Trouble animating sprite

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

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

Re: Trouble animating sprite

Post by Fiskbit »

Re: Emulators, there is no way to verify that someone is actually using the emulator (or even the ROM) that a community requires. One can hack an emulator's binary or modify an open source emulator's source code to add features for cheating, or modify a ROM to cheat in subtle ways that are undetectable even to skilled moderators. There are ways to make the situation better than it is today, but every hurdle you add makes the experience worse for legitimate participants and makes the hobby harder to get into. By requiring MesenRTA, they are gaining only the appearance of security at the cost of useful features and of meaningful accuracy improvements added since the very old version of Mesen it is based on. This isn't much more than security theater: it's a price people pay to make them feel better without actually making them safer.


Re: ROM, it sounds like you don't have a solid grasp on the difference between RTS and RTI. RTI is exclusively for returning from an interrupt handler. When an interrupt occurs, the CPU pushes the return address and current processor flags onto the stack (3 bytes total) and jumps to the address pointed to by the interrupt vector. Normally, software will start the handler by pushing the A, X, and Y registers to the stack, to preserve the context of the code that was interrupted. When finished, software will restore Y, X, and A, and then will RTI. RTI restores the processor flags and program counter from the stack.

The key differences between RTI and RTS are in the handling of processor flags and the format of the return address. RTI pulls 3 bytes from the stack (P and the return address), while RTS pulls just 2 (the return address; it leaves P alone). The RTI return address is also the exact address to return to, while RTS points 1 byte earlier than the actual target address. These instructions are tailored to the specific contexts in which they should be used: RTI is for returning from functions called by the CPU's automatic interrupt process, while RTS is for returning from functions called with a JSR instruction. Thus, RTI is used very rarely in software (in most games, just at the end of the NMI handler, because IRQ handlers are not usually used).
Pokun
Posts: 2651
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: Trouble animating sprite

Post by Pokun »

asm6hackr wrote: Tue Feb 06, 2024 6:52 pm @Pokun I was using FCEUX on Windows. I just tested it and it works fine. What emulator were you using?
I used Mesen2 and I have quite a few of those random-default-states options enabled, including randomizing RAM and various hardware registers. Those are good for catching initialization bugs among other problems.

MesenRTN sounds like something built for speedruns and contests to prevent cheating. Even if you disregard the fact that it is an outdated emulator, I don't see a reason to use it for development. The debugging tools in FCEux and Mesen are made for us homebrew developers to make it easier to figure out bugs in our code, so taking them out of the emulator isn't exactly useful for us.


BTW as Fiskbit said there is no point in replacing RTS with RTI or vice versa as they are used for different things.

Your code should look something like this example:

Code: Select all

RESET: ;reset handler start
  ;Initialization code here.
forever:
  jmp forever ;the RESET handler ends in an endless loop
  
NMI: ;NMI handler start
  ;This is where Nerdy Nights examples run their main code.
  rti ;the NMI handler must end with an RTI
  
IRQ: ;IRQ handler start
  rti ;the IRQ handler must end with an RTI
  
Subroutines: ;any subroutines should be outside the interrupt handlers

subroutine1:
  ;The subroutine's code here.
  rts
  
subroutine2:
  ;The subroutine's code here.
  rts

;Interrupt vector table:
  .org $FFFA
  .dw NMI
  .dw RESET
  .dw IRQ
As you can see here there is only one RTS per subroutine and only one RTI per interrupt handler. Only the RESET handler (which isn't usually considered an interrupt) ends with an endless loop. You can call subroutine1 and subroutine2 from anywhere in the code (after RAM has been initialized) using "JSR subroutine1"/"JSR subroutine2" but you should never jump into them from outside any other way (like using the JMP instruction). The JSR takes care of the subroutine call correctly (by pushing relevant things to stack) and the RTS takes care of returning from the subroutine correctly (by pulling the relevant things from stack).
Likewise never jump into any of the interrupt handlers from outside, they are entered automatically when an interrupt happens and the RTI instruction takes care of returning from them to wherever the PC where when the interrupt happened (which in your case will always be inside the forever loop).

The IRQ is not used by Nerdy Nights and just inserts zeroes instead of a label in the IRQ vector, but if you are paranoid you can leave an empty IRQ handler with just an RTI like in the above example. I don't know which is best but I prefer to include even unused interrupts for my own sanity's sake. Sorry if I'm confusing you.
Post Reply