How is this possible?

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

How is this possible?

Post by klonoa » Sun Aug 23, 2020 4:29 am

Hi all,

I have this very annoying bug that I can't find the cause of for the life of me.

When the character reaches the right of the screen I disable sprite rendering, delete all sprites except for the character, load the new screen
and put the character on the left of the screen.
This works 85% of the time but once in a bluemoon it puts the character in the topleft corner, so somewhere there's a #$00 being writen to $0200 (where my dma data is residing.)

When I put a breakpoint there I saw it was breaking in my defrag routine.
My defrag routine is nothing special.
It makes a new list of sprites at $0600 skipping over all the gaps at $0200 and then copies the new list back to $0200

This just puzzles me to no end..
Image
How can A be #$00 when just the line before it's supposed to be set at #$94.

A simmilar thing happend a little later down the line here:
Image
Hilighted in green I'd put a breakpoint that would break if x == #$00. and it did break..
How is that possible?

Fiskbit
Posts: 151
Joined: Sat Nov 18, 2017 9:15 pm

Re: How is this possible?

Post by Fiskbit » Sun Aug 23, 2020 4:57 am

Are you saving and restoring registers in your interrupt handlers by pushing them to and pulling them from the stack? If not, then if an interrupt occurs between these instructions, your registers will likely be clobbered.

Edit: If it's not the interrupt handler, you might be able to figure out what happened here using the Trace Logger tool. Another helpful option is the Step Backward feature in Mesen's debugger, though it does have some limitations.
Last edited by Fiskbit on Sun Aug 23, 2020 5:40 am, edited 1 time in total.

User avatar
dougeff
Posts: 2735
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: How is this possible?

Post by dougeff » Sun Aug 23, 2020 5:37 am

Both happened at scanline 101 pixel 207.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
Memblers
Site Admin
Posts: 3877
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: How is this possible?

Post by Memblers » Sun Aug 23, 2020 6:54 am

Fiskbit wrote:
Sun Aug 23, 2020 4:57 am
Are you saving and restoring registers in your interrupt handlers by pushing them to and pulling them from the stack? If not, then if an interrupt occurs between these instructions, your registers will likely be clobbered.
Yeah, I think it's that. And if the NMI is itself being interrupting by another NMI, then not only will the registers be clobbered, but so will any variables being used.

In addition to saving/restoring the registers, you should also check if you're inside a recursive interrupt:

Code: Select all

 pha
 txa
 pha
 tya
 pha
 
 lda nmi_check
 bne exit
 inc nmi_check
 
 ; do stuff
 
 dec nmi_check
 
exit:
 jsr play_music
 
 pla
 tay
 pla
 tax
 pla
 rti
 
I also noticed in that debugger that none of the zeropage variables are using zeropage addressing mode (STA $003A instead of STA $3A). So they're all 1 byte larger and 1 cycle slower, it could be running slower than you expected. If you're using the NESASM assembler, you have to specifically type "STA <variable" instead of "STA variable". Not causing this problem, but could be slowing the code down a little.

klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

Re: How is this possible?

Post by klonoa » Mon Aug 24, 2020 12:36 pm

Found it! :D

You were right, the nmi wasn't done before the next nmi was triggered. (There should be a name for this)
I did store the registers but made the big error to first jsr to a function.
I probably put it there late one evening when I wasn't thinking right. :lol: :oops:

Image

Image

I was tearing my hair out from this one, yet it's such a dumb obvious mistake.. :oops:

Anyway, thanks a lot for the help y'all! :beer:

klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

Re: How is this possible?

Post by klonoa » Mon Aug 24, 2020 12:43 pm

Memblers wrote:
Sun Aug 23, 2020 6:54 am

I also noticed in that debugger that none of the zeropage variables are using zeropage addressing mode (STA $003A instead of STA $3A). So they're all 1 byte larger and 1 cycle slower, it could be running slower than you expected. If you're using the NESASM assembler, you have to specifically type "STA <variable" instead of "STA variable". Not causing this problem, but could be slowing the code down a little.
Yeah I'm aware of that now, when I was writing that function I was an even bigger noob. :P
Don't know if I was unaware about zeropage addressing or that I assumed the compiler would take care of that
but I'm aware about it now.
Still need to change that throughout my project.

User avatar
Bregalad
Posts: 7951
Joined: Fri Nov 12, 2004 2:49 pm
Location: Chexbres, VD, Switzerland

Re: How is this possible?

Post by Bregalad » Mon Aug 24, 2020 1:53 pm

klonoa wrote:
Sun Aug 23, 2020 4:29 am
When the character reaches the right of the screen I disable sprite rendering, delete all sprites except for the character, load the new screen
and put the character on the left of the screen.
I'm not sure if I understand well what you're doing, but you're supposed to set all 64 hardware sprites to some value every frame. Unused sprites usually go in the $f0-$ff range for vertical position. You're not supposed to use the sprite X/Y coordinates from shadow OAM as actual game values.
Of course you could do that but i'd be very bad programming practice and always will end up handicaping you when you want to do a more complex game using metasprites instead of individual sprites, or start to do sprite cycling.
Useless, lumbering half-wits don't scare us.

klonoa
Posts: 72
Joined: Mon Nov 21, 2011 3:53 pm

Re: How is this possible?

Post by klonoa » Mon Aug 24, 2020 4:00 pm

Bregalad wrote:
Mon Aug 24, 2020 1:53 pm
I'm not sure if I understand well what you're doing, but you're supposed to set all 64 hardware sprites to some value every frame. Unused sprites usually go in the $f0-$ff range for vertical position. You're not supposed to use the sprite X/Y coordinates from shadow OAM as actual game values.
Of course you could do that but i'd be very bad programming practice and always will end up handicaping you when you want to do a more complex game using metasprites instead of individual sprites, or start to do sprite cycling.
I am setting all sprites every frame, when I said I delete all sprites I mean setting them all to $00.

I am using the oam data as x/y values and I now know that's bad practice.
I am too far into my project to change it all however, and for what it's worth it works. I'll just take it as a lesson.
I don't see how I can't use metasprites though as I am using them right now
and if you mean sprite cycling as in having a flicker effect for when 8 tiles align I got that too.

Post Reply