It is currently Wed Dec 12, 2018 2:52 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 14 posts ] 
Author Message
PostPosted: Thu Dec 06, 2018 8:34 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 56
Location: Finland
I was looking through Akumajou Densetsu's code and the reset code has a subroutine with sound initialization (most likely) at the end of it. What is weird about it is that after each register write it jumps to a subroutine that consists of nothing but NOP. Does anyone have some sort of explanation for this and does it have any functional purpose?

Code:
...
 LDA #$30
 STA P1_VOLUME
 JSR NoOperation

 STA P2_VOLUME
 JSR NoOperation

 STA NOI_VOLUME
 JSR NoOperation

 LDA #$7F
 STA P1_SWEEP
 JSR NoOperation

 STA P2_SWEEP
 JSR NoOperation

 LDA #$00
 STA VRC6_P1_VOLUME
 JSR NoOperation

 STA VRC6_P2_VOLUME
 JSR NoOperation

 STA VRC6_SAW_VOLUME
 JSR NoOperation

 LDA #$0F
 STA APU_STATUS
 JSR NoOperation
 RTS

NoOperation:
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 NOP
 RTS


EDIT:
This is somewhat off topic from the original question, but I'm going to add this here anyway.

After the reset routine the game seems to go to the following loop:

Code:
Loop:
 INC $0020
 CLC
 LDA $0020
 ADC $001B
 STA $0020
 JMP Loop


As far as I can tell, there is no "break condition" meaning it'll be stuck doing that. NMI of course is a temporary break, but it'll return there after NMI is done. Is this game doing all game logic in NMI and using the non NMI time to wait for new NMI to happen? Or is there some other purpose to this? I haven't seen the game do anything else outside NMI so far.


Top
 Profile  
 
PostPosted: Thu Dec 06, 2018 9:25 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7602
Location: Chexbres, VD, Switzerland
I can't answer the first part of your question, except pointing out that it's weird they use so many NOPs when they could have instead used a DEX/BNE loop or something like that and waste less ROM. Anyway, it's very clear that for some reason they thought they should waste time between various writes to memory-mapper-registers.

For the second part of your question, pretty much all Konami games does that. They run the entirety of game logic within NMI, espousing an "all-in-NMI" strategy. The loop you're seeing just generate pseudo-random numbers. You can replace it with a simple "here: JMP here" kind of loop and the game will work the same, except luck-based elements which will be altered.


Top
 Profile  
 
PostPosted: Thu Dec 06, 2018 10:10 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 56
Location: Finland
Bregalad wrote:
For the second part of your question, pretty much all Konami games does that. They run the entirety of game logic within NMI, espousing an "all-in-NMI" strategy. The loop you're seeing just generate pseudo-random numbers. You can replace it with a simple "here: JMP here" kind of loop and the game will work the same, except luck-based elements which will be altered.


Does this strathegy have adventages or disadventages over handling game logic outside NMI?


Top
 Profile  
 
PostPosted: Thu Dec 06, 2018 11:59 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7011
Location: Canada
Previous thread where I asked a very similar question:
https://forums.nesdev.com/viewtopic.php?f=9&t=15989

The VRC7 does need a delay between writes to its audio registers, which is normal for the Yamaha FM chips. My theory is that they initially thought VRC6 was going to require a similar delay, but by the time it was finished it didn't need it, and this delay code is vestigial. (The later two VRC6 games don't delay between writes like this.)


Top
 Profile  
 
PostPosted: Thu Dec 06, 2018 12:27 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11011
Location: Rio de Janeiro - Brazil
SusiKette wrote:
Does this strathegy have adventages or disadventages over handling game logic outside NMI?

If the "all in NMI" implementation in question doesn't allow reentrant NMIs (i.e. handling an NMI even if the previous handler didn't finish yet), the game will miss vblanks when lag frames occur, causing the music to slow down and raster effects (e.g. status bars) to glitch. If it does allow reentrant NMIs, it can detect lag frames and still perform crucial tasks like audio playback and raster effects.

So yeah, depending on how you implement it, "all in NMI" can be as versatile as "main + NMI". I personally prefer to do "main + NMI", keeping the two threads clearly separated.


Top
 Profile  
 
PostPosted: Thu Dec 06, 2018 5:42 pm 
Offline
Site Admin
User avatar

Joined: Mon Sep 20, 2004 6:04 am
Posts: 3596
Location: Indianapolis
SusiKette wrote:
As far as I can tell, there is no "break condition" meaning it'll be stuck doing that. NMI of course is a temporary break, but it'll return there after NMI is done. Is this game doing all game logic in NMI and using the non NMI time to wait for new NMI to happen? Or is there some other purpose to this? I haven't seen the game do anything else outside NMI so far.


That is odd, I have no idea why they would do that. NMI or IRQ has to be the escape from the loop, the return address is stored on the stack, and you can use the TSX instruction to index it. It's also OK (but.. weird) if you just never return from the interrupt, the interrupt source will never notice.


Top
 Profile  
 
PostPosted: Fri Dec 07, 2018 12:28 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7602
Location: Chexbres, VD, Switzerland
tokumaru wrote:
If the "all in NMI" implementation in question doesn't allow reentrant NMIs (i.e. handling an NMI even if the previous handler didn't finish yet), the game will miss vblanks when lag frames occur, causing the music to slow down and raster effects (e.g. status bars) to glitch. If it does allow reentrant NMIs, it can detect lag frames and still perform crucial tasks like audio playback and raster effects.

So yeah, depending on how you implement it, "all in NMI" can be as versatile as "main + NMI". I personally prefer to do "main + NMI", keeping the two threads clearly separated.

Konami games does "all in NMI" and handle lagging and re-entrant NMIs properly - by software (rather than disable further NMIs by $2000.7, it probably sets some flag or something so that further NMIs only do music and minimal work before returning to unfinished game logic buisness).


Top
 Profile  
 
PostPosted: Fri Dec 07, 2018 7:32 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11011
Location: Rio de Janeiro - Brazil
That's definitely the good way to do it. I believe that they're are games that disable NMIs though, and those have poor handling of lag frames.


Top
 Profile  
 
PostPosted: Tue Dec 11, 2018 5:57 am 
Offline

Joined: Tue Oct 16, 2018 5:46 am
Posts: 25
Bregalad wrote:
Konami games does "all in NMI" and handle lagging and re-entrant NMIs properly - by software (rather than disable further NMIs by $2000.7, it probably sets some flag or something so that further NMIs only do music and minimal work before returning to unfinished game logic buisness).


tokumaru wrote:
That's definitely the good way to do it. I believe that they're are games that disable NMIs though, and those have poor handling of lag frames.


What would one typically do to handle lag frames? Detect lag, flag it and avoid doing non critical stuff?


Top
 Profile  
 
PostPosted: Tue Dec 11, 2018 6:09 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 56
Location: Finland
pwnskar wrote:
What would one typically do to handle lag frames? Detect lag, flag it and avoid doing non critical stuff?


I would simply have a variable that tells that the last frame was completed. It's set at the end of NMI and tested at the beginning of NMI. After the test it's cleared and things go on normally. If a new NMI starts before the flag gets set again the code should return to where it left off (maybe with RTI). You can of course update some stuff before it if you want. VRAM updates are something that has to be skipped, but not sure about the rest.
I have never used the all in NMI style so someone has to confirm if this is correct or not.

(Since we are talking about the all in NMI style, when I say NMI it also includes the main loop of the game)


Top
 Profile  
 
PostPosted: Tue Dec 11, 2018 7:00 am 
Offline

Joined: Tue Oct 16, 2018 5:46 am
Posts: 25
SusiKette wrote:
pwnskar wrote:
What would one typically do to handle lag frames? Detect lag, flag it and avoid doing non critical stuff?


I would simply have a variable that tells that the last frame was completed. It's set at the end of NMI and tested at the beginning of NMI. After the test it's cleared and things go on normally. If a new NMI starts before the flag gets set again the code should return to where it left off (maybe with RTI). You can of course update some stuff before it if you want. VRAM updates are something that has to be skipped, but not sure about the rest.
I have never used the all in NMI style so someone has to confirm if this is correct or not.

(Since we are talking about the all in NMI style, when I say NMI it also includes the main loop of the game)


So it's basically just avoid doing your NMI stuff before all of your last NMI stuff has been finished?

About the all-in-NMI stuff though. Having your game logic at the end of your NMI, how is that different from having a regular main loop outside of it? Most of the time you only let your game logic run once after each NMI anyway so you would end up with the same behavior as an all-in-NMI approach either way?


Top
 Profile  
 
PostPosted: Tue Dec 11, 2018 7:19 am 
Offline
User avatar

Joined: Thu Sep 15, 2016 6:29 am
Posts: 827
Location: Denmark (PAL)
Well, by keeping your main logic outside of NMI you at least don't have to worry too much about lag frames.

Personally, I think it also makes my code a lot more manageable and modular (for example I can have multiple different main loops that all rely on the same the same NMI for timing and PPU updates)


Top
 Profile  
 
PostPosted: Tue Dec 11, 2018 7:22 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 56
Location: Finland
pwnskar wrote:
About the all-in-NMI stuff though. Having your game logic at the end of your NMI, how is that different from having a regular main loop outside of it? Most of the time you only let your game logic run once after each NMI anyway so you would end up with the same behavior as an all-in-NMI approach either way?


It's simply preference. I'm pretty sure most people here keep NMI and main loop separate just for clarity. I think lag frames are easier to manage if they are separate anyway. You can just jump at the end of your NMI if lag frame occurs and maybe run only sound engine or something and then return with RTI. You could do return immediately though if you don't mind music slowing down during lag.


Top
 Profile  
 
PostPosted: Tue Dec 11, 2018 1:59 pm 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7602
Location: Chexbres, VD, Switzerland
pwnskar wrote:
Having your game logic at the end of your NMI, how is that different from having a regular main loop outside of it? Most of the time you only let your game logic run once after each NMI anyway so you would end up with the same behavior as an all-in-NMI approach either way?

It's just a different style, but in the end it doesn't change things much. Doing it all-in-NMI, the start of the NMI is as usual, but then at some points it tests if the previous frame is finished, and if it's not it exits. In normal cases, it probably restores the state of the last frame by means of complex state machines and possibly pointers. This is a bit harder to manage than simply calling routines in a given order within code, but in the end it's exact same thing.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 14 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group