It is currently Sun May 26, 2019 1:54 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: JSR and RTS
PostPosted: Wed Dec 12, 2018 4:48 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 81
Location: Finland
According to few sites JSR subtracts 1 from the program counter before pushing it to the stack (should now point to the lower byte of the subroutine's address). Why? Additionally one site says that RTS subtracts 1 from the value taken from the stack (pointing the JSR instruction) and one says it adds 1 (pointing the upper byte of the subroutine's address). Which one of these is correct? If the addition is correct do I increment the program counter before reading the next instruction?


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 4:53 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7711
Location: Chexbres, VD, Switzerland
SusiKette wrote:
According to few sites JSR subtracts 1 from the program counter before pushing it to the stack (should now point to the lower byte of the subroutine's address). Why?

This is wrong, it pushes the PC of the JSR instruction + 2; or in other words the 3rd byte of the JSR instruction; or in other words the PC of the next instruction - 1. It does not substract anything - rather than that it justs push the PC as it is when fetching the 3rd byte of the JSR instruction.

Practical example: Let's say we are at adress $b000 and that the instruction is JSR $ABCD. The memory is as follows:
Code:
B000 : $20
B001 : $CD
B002 : $AD
B003 : .... (next instruction is here)

In this case, $B002 will be pushed on the stack.

Quote:
Additionally one site says that RTS subtracts 1 from the value taken from the stack (pointing the JSR instruction) and one says it adds 1 (pointing the upper byte of the subroutine's address). Which one of these is correct?

The second site is correct, the first is wrong (*). RTS pull an adress from the stack, add one and continues execution from there.

Taking back our exaple, the adress $B002 will be retrived from the stack and incremented, and the 6502 will fetch the next instruction at adress $B003.

(*) Either that or your understanding of what they said is wrong.


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 5:05 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 81
Location: Finland
Bregalad wrote:
(*) Either that or your understanding of what they said is wrong.


The reference said "...It pulls the program counter (minus one) from the stack.". I don't think there is any other way you can understand that.

Either way, the way you explained the JSR and RTS function makes more sense.

Bregalad wrote:
...or in other words the PC of the next instruction - 1.


Maybe this is what the reference intended, but the explanation was kinda weird and somewhat confusing when you threw RTS to it as well.


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 5:21 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 2510
Location: DIGDUG
Unless you're writing an emulator, you shouldn't have to worry about how JSR and RTS affect the stack.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 5:35 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 81
Location: Finland
I'm not making a full emulator at least for now. I might try it later, so it's a good idea to understand how things work. It'll make things easier when I do.

EDIT: Would pulling the return address from the stack be really any different than reading a word from the position of the stack pointer and then increment the stack pointer by two? JSR seems to push the upper byte first probably so that they are in correct order for RTS. I already have a code that can read a word as two individual bytes and combine the bytes to a word in correct order so I don't have to make a separate code for pulling the return address. If FCEUX is correct pulling bytes from stack leaves the original value there rather than clearing it, so in that sense it should work


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 5:58 am 
Offline
User avatar

Joined: Thu Sep 15, 2016 6:29 am
Posts: 896
Location: Denmark (PAL)
I don't think it makes sense to think of it as additions or subtractions. Like Bregalad said, the CPU just keeps incrementing the program counter by one as it executes the program, and after executing one instruction it will be at the last byte of that instruction. Then it increments it again to move on to the next instruction. At least that's how I understand it :)

The RTS instruction simply "cheats" the program counter by putting it back at the end of the JSR instruction, ready to execute what comes next.

dougeff wrote:
Unless you're writing an emulator, you shouldn't have to worry about how JSR and RTS affect the stack.


It's important to know because you can use RTS to jump to an address dynamically, such as using a jump table or an address otherwise stored somewhere (like a pointer to a routine that can be switched out).

That's why a jump table will usually be typed out something like this:
Code:
JumpTable:
.word RoutineAddress-1
.word SomeOtherRoutine-1


EDIT: It's also kinda important to know whenever you're actually using the stack, since you can't push something to the stack and then RTS afterwards unless you're intentionally doing what I described above.


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 6:31 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21401
Location: NE Indiana, USA (NTSC)
Sumez wrote:
you can use RTS to jump to an address dynamically, such as using a jump table or an address otherwise stored somewhere (like a pointer to a routine that can be switched out).

That's why a jump table will usually be typed out something like this:
Code:
JumpTable:
.word RoutineAddress-1
.word SomeOtherRoutine-1

The concept of RTS-based jump table handling is critical to understand any of my code that's a state machine or object-oriented.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 6:43 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 81
Location: Finland
Somewhat off topic, but does the NES CPU fetch the address correctly for Indirect JMP if the first byte is on $xxFF or does it wrap around to the beginning of the page? I read that it happened incorrectly for the original 6502 processor, but since the NES CPU is not exactly same as the original 6502, I guess I should make sure before implementing it.


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 7:02 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21401
Location: NE Indiana, USA (NTSC)
The NES CPU behaves as the MOS 6502 in this case and in all known others that do not involve use of the D flag.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 8:08 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 81
Location: Finland
tepples wrote:
The NES CPU behaves as the MOS 6502 in this case and in all known others that do not involve use of the D flag.


I see. Although since I'm not making a full emulator I don't think I need to emulate this feature anyway. I doubt there are cases where the Indirect JMP vector is intentionally placed on page boundary.

I guess we could talk about branches as well since we are already off topic anyway. Is the offset added from branch from the offset byte (branch instruction +1)?


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 8:42 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21401
Location: NE Indiana, USA (NTSC)
Branch offsets on 6502 are from the end of the branch instruction, which is 2 bytes after the start of the branch instruction. For example:
Code:
  ; Wait for an interrupt handler to change the value in $18
  lda $18
loop:
  cmp $18
  beq loop

This gets assembled to C5 18 F0 FC, where FC is the two's complement representation of -4, because there is a 4 byte difference in the PC when the branch is taken compared to the PC when it is not taken.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 9:42 am 
Offline
User avatar

Joined: Fri Mar 16, 2018 1:52 pm
Posts: 81
Location: Finland
So the program counter is already at the next opcode when it decides whether it should branch or not?


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 10:12 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21401
Location: NE Indiana, USA (NTSC)
SusiKette wrote:
So the program counter is already at the next opcode when it decides whether it should branch or not?

Correct.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 10:59 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7711
Location: Chexbres, VD, Switzerland
SusiKette wrote:
Bregalad wrote:
(*) Either that or your understanding of what they said is wrong.


The reference said "...It pulls the program counter (minus one) from the stack.". I don't think there is any other way you can understand that.

Then it is exactly your understanding, and not the statement, which is false. This statement is correct. The RTS instruction pulls data from the stack. That data represents the return adress minus one. Nowhere it says it substracts 1 from the adress pulled from the stack. On the other hand, it increment the adress by one to compensate the face it's the adress minus one.


Top
 Profile  
 
 Post subject: Re: JSR and RTS
PostPosted: Wed Dec 12, 2018 1:55 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 7467
Location: Canada
SusiKette wrote:
Although since I'm not making a full emulator I don't think I need to emulate this feature anyway. I doubt there are cases where the Indirect JMP vector is intentionally placed on page boundary.

What reason would you have not to implement this feature of JMP if you are aware of it? It's literally only a couple of extra characters on the line of code that would otherwise implement the address fetch.

Yes, it's true that an NES programmer is unlikely to do it intentionally except as a test (thankfully in ca65 it generates an error), but mistakes happen all the time, and lots of games rely on their bugs. Leaving this out just makes room for the situation of "this thing works on X emulator but not Y", which as an emulator author is a rather annoying report to get, but unfortunately a lot of users don't have an NES / flash cart to test hardware to know which behaviour is true.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 9 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