Why not read controllers in NMI?
Moderator: Moderators
- mikejmoffitt
- Posts: 1353
- Joined: Sun May 27, 2012 8:43 pm
Re: Why not read controllers in NMI?
Street Fighter II reads inputs at the start of the game's polling loop. This is troublesome for emulator authors who don't update the virtual inputs frequently. If the game has a "turbo" setting on, it means that the number of game ticks that run per visual frame can vary, and with that, the frequency of input polls.
Dwedit - why would reading the gamepad during the NMI produce controller data changes mid-frame?
Dwedit - why would reading the gamepad during the NMI produce controller data changes mid-frame?
Re: Why not read controllers in NMI?
Just assuming you store your byte after you did the 8 joypad reads.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
- rainwarrior
- Posts: 8734
- Joined: Sun Jan 22, 2012 12:03 pm
- Location: Canada
- Contact:
Re: Why not read controllers in NMI?
Race conditions with a vblank interrupt aren't necessarily a big deal. It depends how often you refer to your input, and what you do with it. If you handle your player control early on in a frame and never later on it'd be pretty unlikely to get clobbered even in a lag situation. There are lots of "convenient" reasons one might end up checking again later on in a frame though...
The main disadvantage is just that you've introduced another situation that can go wrong if you're not aware of the threading / timing. Probably most of the time it wouldn't matter at all, but the kind of errors you get when you forget can be pretty insidious.
That's basically why I'd advocate not doing it by default on the NES, but if you've got a reason you need it then sure go for it.
Polling in a vblank interrupt is a valid technique on NES, SNES, or Genesis. Polling on demand is also valid on all three of these platforms.
Should one way or the other be "standard" for any of these platforms? I don't care. I think I already stated what purposes it can be used for. If you've got a good use case for it, use it. If you don't, I'd probably recommend not doing it for simplicity's sake. If you're using a library like SGDK, just roll with however it expects you to do things.
The main disadvantage is just that you've introduced another situation that can go wrong if you're not aware of the threading / timing. Probably most of the time it wouldn't matter at all, but the kind of errors you get when you forget can be pretty insidious.
That's basically why I'd advocate not doing it by default on the NES, but if you've got a reason you need it then sure go for it.
Ask me when you've got a concrete example for SNES, I don't want to get hypothetical. We're comparing a C games library API on Genesis to what's appropriate for NES, or at least, I was.tepples wrote:Would it be likewise "apples to oranges" between the NES and Super NES?
Polling in a vblank interrupt is a valid technique on NES, SNES, or Genesis. Polling on demand is also valid on all three of these platforms.
Should one way or the other be "standard" for any of these platforms? I don't care. I think I already stated what purposes it can be used for. If you've got a good use case for it, use it. If you don't, I'd probably recommend not doing it for simplicity's sake. If you're using a library like SGDK, just roll with however it expects you to do things.
Re: Why not read controllers in NMI?
No, they do not. These are modern tools, with LTO and other such conveniences the ancient platforms can only dream of.tepples wrote:And which get linked into the executable, occupying ROM and RAM, even if unused.
LTO will notice you never call function X. That cascades. If you don't use any SGDK joy functions, they will be optimized out such that only the var update in the vblank func will remain.
Re: Why not read controllers in NMI?
I was going to say the exact same thing. This is really the only significant problem with reading the controller in NMI. I can't think of anything else. If the main code is designed robustly, either by making it's local copies during decision-taking routines, or by making sure the potentially slow code is always executed after the code using the controller-read value and taking decisions, it's fine. But the danger of having main codes behaving weirdly, or, in worst cases, even crashing, if the controller changes states during a lag frame, is there. This could also be a thing to exploit for speedruners.tokumaru wrote:One reason not to read controllers in the NMI handler is the consistency of controller state within the same logic frame. If a lag frame happens, and an NMI fires in the middle of that logic frame, it's possible that different controller states will be readable in that same logic frame.
For similar reasons, it would be bad practice to poll the controller multiple times during the same frame (*) - unless the logic is solid, and for example once only the directional pad are used and the other time only the buttons are used.
(*) I'm not including cases where reading the controller multiple times is part of the read routine
Also I disagree with tepples that games usually don't read controller during NMI. This practice might be not recommended, but commercial games still do it, often. Just check the NMI routine of your favourite games.
The only real advantage of reading the controller in NMI I can think of, is that you don't need to call the controller reading routine at many different places across the game's code. This saves a tiny bit of ROM. Other than that I can't think of any advantages.
Doing it before the VRAM updates would be completely nonsensical, but doign it in NMI after all VRAM updates, I really don't see the problem. Just like playing the music engine, by the way. And reading controllers in constant-cycle-timed routine is not hard to do, so it even doesn't clash with potential further-raster-effects-that-don't rely-on-sprite-zero-hit.tokumaru wrote: I don't know about the Mega Drive, but on the NES, where vblank time is at a premium, wasting part of it on a task that could literally be performed at any other time, would be completely nonsensical.
Re: Why not read controllers in NMI?
Yeah I'm also not sure what Tepples is talking about. It is commonly done in games. I once even thought it was preferable to have input reading in NMI, but Tokumaru taught me about the possible inconsistency it introduces, and I stopped doing it.
Also doesn't the SNES controller auto-reading function read the controllers in vblank or something?
Also doesn't the SNES controller auto-reading function read the controllers in vblank or something?
That could be done in the main loop as well. If you have a jump table for the various modes your game has in the main thread, you can just read the controllers before the jump table and jumping to the active mode's logic. As long as all modes are fine with the same controller reading routine it's enough with just one call.Bregalad wrote:The only real advantage of reading the controller in NMI I can think of, is that you don't need to call the controller reading routine at many different places across the game's code. This saves a tiny bit of ROM. Other than that I can't think of any advantages.
Re: Why not read controllers in NMI?
LTO is only good if there is a means of indicating when a function call needs to be regarded as "opaque", and all functions where that is necessary are thus marked. When C was invented, there was no need for such a directive because all or nearly all extant compilers would extend the language by treating cross-module function calls as opaque(in fact such treatment was so universal it wasn't generally thought of as an "extension", but simply part of how the language worked), and thus very little code that relies upon such treatment that is marked to indicate such reliance.calima wrote:No, they do not. These are modern tools, with LTO and other such conveniences the ancient platforms can only dream of.tepples wrote:And which get linked into the executable, occupying ROM and RAM, even if unused.
LTO will notice you never call function X. That cascades. If you don't use any SGDK joy functions, they will be optimized out such that only the var update in the vblank func will remain.
Without such marking, something like:
Code: Select all
volatile unsigned char data_ready_flag;
void wait_for_frame(void)
{
while(data_ready_flag)
;
}
...
databuff[0] = 123;
wait_for_frame();
databuff[0] = 45;
wait_for_frame();
Re: Why not read controllers in NMI?
If one performs an OAM DMA within the NMI routine, and keeps track of whether an even or odd number of cycles have elapsed between then and the code that will read the controller, one can avoid the possibility of DMC clobbering the controller read. Likewise if one reads the controller at a suitable time within a DMC IRQ. While one needs to be mindful of how controller inputs will behave in the presence of lag, and ensure that such behaviors will always be sensible, I think reading then at a consistent point each frame is for many purposes better than just reading them "whenever".Bregalad wrote:(*) I'm not including cases where reading the controller multiple times is part of the read routine
Re: Why not read controllers in NMI?
I've edited this note in quickly because when I claimed that reading controller twice per frame could be potentially harmful, I was sure someone came up with an annoying remark noticing how this is useful for DMC. Apparently even though I've edited this in, I still didn't avoid people quibble over that.supercat wrote:If one performs an OAM DMA within the NMI routine, and keeps track of whether an even or odd number of cycles have elapsed between then and the code that will read the controller, one can avoid the possibility of DMC clobbering the controller read. Likewise if one reads the controller at a suitable time within a DMC IRQ. While one needs to be mindful of how controller inputs will behave in the presence of lag, and ensure that such behaviors will always be sensible, I think reading then at a consistent point each frame is for many purposes better than just reading them "whenever".
Re: Why not read controllers in NMI?
My point was that if one is using DMC for video frame timing and reads controllers from the main loop, one will have to read them multiple times to make them reliable, but the necessity of reading them twice suggests that the controllers should be read differently.Bregalad wrote:I've edited this note in quickly because when I claimed that reading controller twice per frame could be potentially harmful, I was sure someone came up with an annoying remark noticing how this is useful for DMC. Apparently even though I've edited this in, I still didn't avoid people quibble over that.supercat wrote:If one performs an OAM DMA within the NMI routine, and keeps track of whether an even or odd number of cycles have elapsed between then and the code that will read the controller, one can avoid the possibility of DMC clobbering the controller read. Likewise if one reads the controller at a suitable time within a DMC IRQ. While one needs to be mindful of how controller inputs will behave in the presence of lag, and ensure that such behaviors will always be sensible, I think reading then at a consistent point each frame is for many purposes better than just reading them "whenever".
Re: Why not read controllers in NMI?
I'm not sure I understand what is bein' posited? I think every NES game I've made strobes the controller in NMI, but not necessarily in vblank. Are we talkin' about readin' the actual inputs that the user... inputs? Like testin' if they pushed the 'A' button and all that jazz?
Re: Why not read controllers in NMI?
Yeah, we're talking about reading the state of the controller's buttons. The main argument against doing this in the NMI handler is that the state of the controller will change in the middle of lag frames, which could cause problems depending on how the game uses the input data, while the main argument for reading the controllers in the NMI handler appears to be the possibility of using the OAM DMA to avoid controller data corruption caused by DPCM sample fetches.
Re: Why not read controllers in NMI?
haha What a weird debate. Obviously it will depend on the engine bein' used, because if you KNOW there will be no input lag due to lagging frames, then implement it. Alternatively, if you can implement a DMC bug squash with it, then do it.
The way I tend to program though, I would shy away from anything not PPU related during vblank. But that's because everyone has a different way to implement things hehe No one is right or wrong, if I'm reading this correctly. Just all about implementation?
The way I tend to program though, I would shy away from anything not PPU related during vblank. But that's because everyone has a different way to implement things hehe No one is right or wrong, if I'm reading this correctly. Just all about implementation?
Re: Why not read controllers in NMI?
It's not about being right or wrong. It's about different possibilities and pros and cons, but yeah it heavily depends on what you are trying to do.
Also it is not about input lag, but rather the opposite (logic lags but not the controller). It's about a possible bug if you have slowdown in your game and have the controller reading in NMI instead of the main thread.
If the main thread lags and an NMI interrupts it, having the controller reading in the NMI will update the controller state again before the main thread has finished the logic. So the first part of the logic is processing one controller state and the second part (after PC has returned from NMI) is processing an updated controller state, which would potentially be the cause of a bug, although possibly rarely.
If you can guarantee you have no lag frames there is no problem in having the controller reading in NMI though, since there will be an equal number of main thread logic frames as NMI frames.
Either way NMI isn't strictly for vblank related things. Your sound driver is best updated in the NMI or the music will not have a consistent beat if you have lag frames (some commercial games messes this up too).
The DMC fix is very advanced, and I'm not sure it's fully PAL compatible either.
Also it is not about input lag, but rather the opposite (logic lags but not the controller). It's about a possible bug if you have slowdown in your game and have the controller reading in NMI instead of the main thread.
If the main thread lags and an NMI interrupts it, having the controller reading in the NMI will update the controller state again before the main thread has finished the logic. So the first part of the logic is processing one controller state and the second part (after PC has returned from NMI) is processing an updated controller state, which would potentially be the cause of a bug, although possibly rarely.
If you can guarantee you have no lag frames there is no problem in having the controller reading in NMI though, since there will be an equal number of main thread logic frames as NMI frames.
Either way NMI isn't strictly for vblank related things. Your sound driver is best updated in the NMI or the music will not have a consistent beat if you have lag frames (some commercial games messes this up too).
The DMC fix is very advanced, and I'm not sure it's fully PAL compatible either.
- FrankenGraphics
- Formerly WheelInventor
- Posts: 2064
- Joined: Thu Apr 14, 2016 2:55 am
- Location: Gothenburg, Sweden
- Contact:
Re: Why not read controllers in NMI?
The theory behind is in-depth but the implementation is plug and play, provided there's nothing in your game that makes controller reads right after OAMDMA directly unsuitable.The DMC fix is very advanced, and I'm not sure it's fully PAL compatible either.
the PAL version doesn't have the dmc bug (it was fixed), so it should work either way you do it, rahsennors' cycle alignment fix or not. There might be problems with several emulators, though - the even/odd observation was only highlighted a few years ago and emulators might not have the bug correctly implemented. Then again, you need games that use the dmc fix to create incentive to fix emulation inaccuracies.