Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.sys.apple2.programmer > #2522 > unrolled thread

How Do JSR and RTS work?

Started byalxmist@aol.com
First post2016-03-17 10:02 -0700
Last post2016-03-18 13:09 -0700
Articles 19 — 7 participants

Back to article view | Back to comp.sys.apple2.programmer


Contents

  How Do JSR and RTS work? alxmist@aol.com - 2016-03-17 10:02 -0700
    Re: How Do JSR and RTS work? David Schmidt <schmidtd@my-deja.com> - 2016-03-17 13:19 -0400
      Re: How Do JSR and RTS work? Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-03-17 16:38 -0700
        Re: How Do JSR and RTS work? David Schmidt <schmidtd@my-deja.com> - 2016-03-17 20:34 -0400
    Re: How Do JSR and RTS work? Michael J. Mahon <mjmahon@aol.com> - 2016-03-17 12:29 -0500
    Re: How Do JSR and RTS work? wssimms@gmail.com - 2016-03-17 10:29 -0700
      Re: How Do JSR and RTS work? wssimms@gmail.com - 2016-03-17 10:32 -0700
    Re: How Do JSR and RTS work? Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-03-17 15:37 -0700
      Re: How Do JSR and RTS work? Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-03-17 16:16 -0700
    Re: How Do JSR and RTS work? markpmlim@yahoo.com.sg - 2016-03-17 18:41 -0700
      Re: How Do JSR and RTS work? wssimms@gmail.com - 2016-03-17 20:22 -0700
        Re: How Do JSR and RTS work? Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-03-18 08:10 -0700
          Re: How Do JSR and RTS work? wssimms@gmail.com - 2016-03-18 08:47 -0700
            Re: How Do JSR and RTS work? alxmist@aol.com - 2016-03-18 09:22 -0700
              Re: How Do JSR and RTS work? David Schmidt <schmidtd@my-deja.com> - 2016-03-18 12:31 -0400
                Re: How Do JSR and RTS work? alxmist@aol.com - 2016-03-18 09:36 -0700
                  Re: How Do JSR and RTS work? David Schmidt <schmidtd@my-deja.com> - 2016-03-18 12:39 -0400
                    Re: How Do JSR and RTS work? Michael Pohoreski <michael.pohoreski@gmail.com> - 2016-03-18 12:25 -0700
              Re: How Do JSR and RTS work? gids.rs@sasktel.net - 2016-03-18 13:09 -0700

#2522 — How Do JSR and RTS work?

Fromalxmist@aol.com
Date2016-03-17 10:02 -0700
SubjectHow Do JSR and RTS work?
Message-ID<8da280fb-19bf-4299-9536-c6ef3be1d560@googlegroups.com>
I am up to using CMP and BNE/BEQ commands in my book, but JSR and RTS still aren't sticking with me. Can anyone explain exactly how they work, and what the requirements are for using them? It seems that every time a JSR is used an RTS should be required, but none of the instructional programs I study are setup like that.

[toc] | [next] | [standalone]


#2523

FromDavid Schmidt <schmidtd@my-deja.com>
Date2016-03-17 13:19 -0400
Message-ID<nceopu$r3n$1@dont-email.me>
In reply to#2522
On 3/17/2016 1:02 PM, alxmist@aol.com wrote:
> I am up to using CMP and BNE/BEQ commands in my book, but JSR and RTS
> still aren't sticking with me. Can anyone explain exactly how they
> work, and what the requirements are for using them?

http://www.6502.org/tutorials/6502opcodes.html#JSR

JSR pushes the program counter (minus 1) onto the stack, then jumps to 
the location specified.

http://www.6502.org/tutorials/6502opcodes.html#RTS

RTS pulls the top two bytes off the stack, puts them into the program 
counter, which then auto-increments as the next instruction is 
fetched... following the location that JSR pushed!  Voila, jump to a 
subroutine, and return from whence it came.

> It seems that every time a JSR is used an RTS should be required,

It is - or else your stack will burst.  (Unless you do some other 
unnatural chicanery to clean up the stack.)

> but none of the
> instructional programs I study are setup like that.

That would be... unusual.  Of course it's possible to manually pop the 
pushed addresses off the stack yourself and clean up a missing RTS, and 
some very tricky code does things like that - but it would be cruel and 
unusual for "instructional programs" to teach that, at least at first. 
Are you _sure_ they don't do normal JSR-RTS things?  It's just like 
GOSUB and RETURN in BASIC.  If you GOSUB too much without returning, 
eventually you crash.

[toc] | [prev] | [next] | [standalone]


#2529

FromMichael Pohoreski <michael.pohoreski@gmail.com>
Date2016-03-17 16:38 -0700
Message-ID<d35ebd29-2a68-4e3c-a794-5ae3bffbc569@googlegroups.com>
In reply to#2523
On Thursday, March 17, 2016 at 10:19:55 AM UTC-7, schmidtd wrote:
> > It seems that every time a JSR is used an RTS should be required,
> 
> It is - or else your stack will burst.  (Unless you do some other 
> unnatural chicanery to clean up the stack.)

Look ma, no RTS :-)

300:20 06 03 4C ED FD
306:7A FA C8 D0 01 E8
30C:8C 15 03 8E 16 03 A9 41 4C FF
300G

Self-modifying code is not "unnatural chicanery" -- it "natural optimizations" :-)

300: 20 06 03 JSR $306
303: 4C ED FD JMP $FDED
306: 7A       PLY ; lo
307: FA       PLX ; hi
308: C8       INY
309: D0 01    BNE $30C
30B: E8       INX
30C: 8C 15 03 STY $315
30F: 8E 16 03 STX $316
312: A9 65    LDA #$41
314: 4C FF FF JMP $FFFF

Also, using an RTS to "fake" an JMP is an natural 6502 optimization "trick" once you understand how RTS works.


[toc] | [prev] | [next] | [standalone]


#2530

FromDavid Schmidt <schmidtd@my-deja.com>
Date2016-03-17 20:34 -0400
Message-ID<ncfi8d$2h5$1@dont-email.me>
In reply to#2529
On 3/17/2016 7:38 PM, Michael Pohoreski wrote:
> On Thursday, March 17, 2016 at 10:19:55 AM UTC-7, schmidtd wrote:
>>> It seems that every time a JSR is used an RTS should be required,
>>
>> It is - or else your stack will burst.  (Unless you do some other
>> unnatural chicanery to clean up the stack.)
>
> Look ma, no RTS :-)
>
> 300:20 06 03 4C ED FD
> 306:7A FA C8 D0 01 E8
> 30C:8C 15 03 8E 16 03 A9 41 4C FF
> 300G
>
> Self-modifying code is not "unnatural chicanery" -- it "natural optimizations" :-)
>
> [...]
>
> Also, using an RTS to "fake" an JMP is an natural 6502 optimization "trick" once you understand how RTS works.

"...once you understand how RTS works."

Ummm, exactly what we're trying to do here.  _Before_ we get into 
self-modifying code and other optimization chicanery. ;-)

[toc] | [prev] | [next] | [standalone]


#2524

FromMichael J. Mahon <mjmahon@aol.com>
Date2016-03-17 12:29 -0500
Message-ID<BZmdnSaY14X9dHfLnZ2dnUU7-bfNnZ2d@giganews.com>
In reply to#2522
<alxmist@aol.com> wrote:
> I am up to using CMP and BNE/BEQ commands in my book, but JSR and RTS
> still aren't sticking with me. Can anyone explain exactly how they work,
> and what the requirements are for using them? It seems that every time a
> JSR is used an RTS should be required, but none of the instructional
> programs I study are setup like that.
> 

In general, you are correct--JSR and RTS are complementary halves of a
subroutine linkage mechanism. 

JSR first pushes the "return address" on the stack, then jumps to the entry
point of the subroutine. Upon completion of the subroutine, it executed an
RTS, which pops the return address off the stack and jumps to it,
"returning" to the instruction following the "calling" JSR. 

This provides a simple method for calling a commonly used piece of code
from multiple places in a program. 

The details are a bit more subtle, but are unimportant for straightforward
JSR/RTS subroutine linkage. 

Now for the subtlety:  the actual address pushed onto the stack is the
address of the third byte of the JSR, not the address of the first byte of
the following instruction, so the RTS increments the address it pops off
the stack by one before jumping to it. This is only important when using
the address on the stack for other purposes, or when explicitly placing an
address on the stack to be used by a subsequent RTS. 

As in all other uses of the stack, it's important that "pushes" and "pops"
be balanced, so that the stack neither grows nor shrinks overall during
program execution. 
-- 
-michael - NadaNet 3.1 and AppleCrate II:  http://michaeljmahon.com

[toc] | [prev] | [next] | [standalone]


#2525

Fromwssimms@gmail.com
Date2016-03-17 10:29 -0700
Message-ID<c50a3162-c56c-4ce8-84da-1d1356610907@googlegroups.com>
In reply to#2522
On Friday, March 18, 2016 at 2:02:56 AM UTC+9, alx...@aol.com wrote:
> I am up to using CMP and BNE/BEQ commands in my book, but JSR and RTS still aren't sticking with me. Can anyone explain exactly how they work, and what the requirements are for using them? It seems that every time a JSR is used an RTS should be required, but none of the instructional programs I study are setup like that.

JSR is like a gosub in BASIC or a procedure call in Pascal. It causes the current PC to be pushed onto the stack and then the PC is loaded with the operand of the JSR instruction -- that is, it is loaded with the target address.

When RTS is encountered, the two top bytes on the stack are popped off the stack and loaded into the PC. This is supposed to set the PC to the address immediately after the original JSR -- thus flow of control returns to the original routine that used JSR to call a subroutine.

As for your instructional programs, if they are attempting to teach the use of JSR, then I suspect they are set up correctly, but perhaps your intuition about what how JSR and RTS are used is wrong. Here is a short example:

Suppose I have a subroutine that is supposed to divide the value in A by 8. It might look like this:

mul8
        asl
        asl
        asl
        rts

This works because a right shift is the same as a division by two. The rts at the end of the routine allows me to use this as a subroutine to be called from some other code. I might have some other code that needs to divide by 8 for some reason. It would look like this:

        ...
        jsr    mul8
        sta    var
        ...

When the instruction "jsr mul8" is executed, the PC is loaded with the address of the mul8 subroutine, and execution continues with that routine. The three asl instructions are executed. Then the rts is executed, which causes the PC to be loaded with the address of the "sta var" instruction, which follows the jsr instruction, and execution continues with that instruction.

FYI, there are some subtleties regarding exactly what is pushed on the stack by JSR and then later popped off by RTS that I have glossed over, but my description is sufficiently accurate for your current needs.

[toc] | [prev] | [next] | [standalone]


#2526

Fromwssimms@gmail.com
Date2016-03-17 10:32 -0700
Message-ID<78785224-f6a7-47c7-a88a-bafbea0edbc1@googlegroups.com>
In reply to#2525
> Suppose I have a subroutine that is supposed to divide the value in A by 8. It might look like this:
> 
> mul8
>         asl
>         asl
>         asl
>         rts
> 
> This works because a right shift is the same as a division by two. The rts at the end of the routine allows me to use this as a subroutine to be called from some other code. I might have some other code that needs to divide by 8 for some reason. It would look like this:

Oops I made a mistake here. I wrote about right shifting and dividing, but the code uses ASL, which is a left shift. Mea Culpa. The ASLs should be LSRs.

[toc] | [prev] | [next] | [standalone]


#2527

FromMichael Pohoreski <michael.pohoreski@gmail.com>
Date2016-03-17 15:37 -0700
Message-ID<6845b641-fac8-4bee-a1fa-fb9175ac6cf9@googlegroups.com>
In reply to#2522
On Thursday, March 17, 2016 at 10:02:56 AM UTC-7, alx...@aol.com wrote:
> I am up to using CMP and BNE/BEQ commands in my book, but JSR and RTS still aren't sticking with me. Can anyone explain exactly how they work, and what the requirements are for using them? It seems that every time a JSR is used an RTS should be required, but none of the instructional programs I study are setup like that.

JSR = Jump to Sub Routine
RTS = Return Sub routine

Enter in this small demo:

CALL-151
300:20 06 03
303:4C ED FD
306:AD 00 C0
308:10 FB
30B:8D 10 C0
30E:60
300G


You'll notice the address $0306 is stored as bytes in reverse order: 06 03 because the 6502 is little endian.


Here's the Disassembly:

  300: JSR $0306
  303: JMP $FDED
  306: LDA $C000
  309: BPL $0306
  30B: STA $C010
  30E: RTS

The equivalent C pseudo code would be:

  int main() // @ $0300
  {
      char a = getkey();
      putchar( a );
  }

  char getkey() // @ $0306
  {
    _306: 
      a = getchar();
      if( a < 0x80 )
          goto _306;
      return a;   
  }

Think of JSR being the function call operator '();'
And RTS being the "return".

Requirements are that you have enough stack space.

So what happens when the 6502 encounters a JSR ?

It save the address of the next instruction -1 (which is $0302) on the hardware stack.  The hardware stack resides at $0100 .. $01FF
It then GOTO's the address
it continues executing instructions.

When the 6502 executes a RTS it pulls off 2 bytes from the stack.
It increments the address
It GOTO's _that_ address.

Here's a little demo program to that shows how JSR works:

310:20 13 03
313:68 
314:20 DA FD
317:68
318:4C DA FD
310G



[toc] | [prev] | [next] | [standalone]


#2528

FromMichael Pohoreski <michael.pohoreski@gmail.com>
Date2016-03-17 16:16 -0700
Message-ID<134b387b-c1c6-4a81-8263-69edf2da7fbc@googlegroups.com>
In reply to#2527
On Thursday, March 17, 2016 at 3:37:16 PM UTC-7, Michael Pohoreski wrote:

> Here's a little demo program to that shows how JSR works:

Or to make it a little more user friendly and use the same JSR address as the first program:

300:20 06 03
306:68
307:AA
308:68
309:20 DA FD
30C:8A
30D:4C DA FD
300G

Which will print the address 0302

[toc] | [prev] | [next] | [standalone]


#2531

Frommarkpmlim@yahoo.com.sg
Date2016-03-17 18:41 -0700
Message-ID<6c24a42b-765a-41c0-ab56-c65c2f3b743e@googlegroups.com>
In reply to#2522
On Friday, March 18, 2016 at 1:02:56 AM UTC+8, alx...@aol.com wrote:
> I am up to using CMP and BNE/BEQ commands in my book, but JSR and RTS still aren't sticking with me. Can anyone explain exactly how they work, and what the requirements are for using them? It seems that every time a JSR is used an RTS should be required, but none of the instructional programs I study are setup like that.

My two cents worth: If you have the time, learn how to use BUGBYTER.

Mark

[toc] | [prev] | [next] | [standalone]


#2532

Fromwssimms@gmail.com
Date2016-03-17 20:22 -0700
Message-ID<1cbfed59-7b2e-4e57-9680-d0e6b371c46d@googlegroups.com>
In reply to#2531
On Friday, March 18, 2016 at 10:41:38 AM UTC+9, mark...@yahoo.com.sg wrote:
> On Friday, March 18, 2016 at 1:02:56 AM UTC+8, alx...@aol.com wrote:
> > I am up to using CMP and BNE/BEQ commands in my book, but JSR and RTS still aren't sticking with me. Can anyone explain exactly how they work, and what the requirements are for using them? It seems that every time a JSR is used an RTS should be required, but none of the instructional programs I study are setup like that.
> 
> My two cents worth: If you have the time, learn how to use BUGBYTER.

Also, learn to use the Virtual II inspector (debugger).

[toc] | [prev] | [next] | [standalone]


#2533

FromMichael Pohoreski <michael.pohoreski@gmail.com>
Date2016-03-18 08:10 -0700
Message-ID<5154e50a-2087-41c9-97cf-5a521910cc5b@googlegroups.com>
In reply to#2532
On Thursday, March 17, 2016 at 8:22:26 PM UTC-7, wss...@gmail.com wrote:
> On Friday, March 18, 2016 at 10:41:38 AM UTC+9, mark...@yahoo.com.sg wrote:
> > My two cents worth: If you have the time, learn how to use BUGBYTER.
> Also, learn to use the Virtual II inspector (debugger).

Or *cough* AppleWin's debugger.


CALL-151
F7
300:20
303:4C ED FD
306:A9 41
308:60
BP 300
G
F7
300G
<SPACE>
<SPACE>
<SPACE>
G
F7

[toc] | [prev] | [next] | [standalone]


#2534

Fromwssimms@gmail.com
Date2016-03-18 08:47 -0700
Message-ID<9b3871a5-0823-4e2d-9a95-0090e41fbee2@googlegroups.com>
In reply to#2533
Sure but he already said he's using Virtual II.
I find the Virtual II debugger to be fairly weak but it's a lot better than nothing at all.

[toc] | [prev] | [next] | [standalone]


#2536

Fromalxmist@aol.com
Date2016-03-18 09:22 -0700
Message-ID<5434f9c6-60c3-40ca-863a-ffbedf472361@googlegroups.com>
In reply to#2534
The instructional program I'm on now is all about using a built-in routine for COUT. The only RTS in this listing seems to be the one for JSR HOME. Wouldn't the program need an RTS for each time I use COUT?

CTR EQU $06
HOME EQU $FC58
COUT EQU $FDED
START JSR HOME
 LDA #$FF
 STA CTR
LOOP LDA CTR
 JSR COUT
 DEC CTR
 BEQ END
 JMP LOOP
END RTS

[toc] | [prev] | [next] | [standalone]


#2537

FromDavid Schmidt <schmidtd@my-deja.com>
Date2016-03-18 12:31 -0400
Message-ID<nchab7$ff3$1@dont-email.me>
In reply to#2536
On 3/18/2016 12:22 PM, alxmist@aol.com wrote:
> The instructional program I'm on now is all about using a built-in
> routine for COUT. The only RTS in this listing seems to be the one
> for JSR HOME. Wouldn't the program need an RTS for each time I use
> COUT?
>
> CTR EQU $06
> HOME EQU $FC58
> COUT EQU $FDED
> START JSR HOME
>   LDA #$FF
>   STA CTR
> LOOP LDA CTR
>   JSR COUT
>   DEC CTR
>   BEQ END
>   JMP LOOP
> END RTS

Oh, certainly - the RTS is part of the COUT and HOME routines, which 
lives off in ROM somewhere separate from your program.  So you're 
calling a subroutine that does the returning to you as part of its work. 
  So that HOME routine is doing something like this, elsewhere in memory 
($FC58, to be exact):

HOME (do some work)
   (do some more work)
   (just about done)
   RTS

[toc] | [prev] | [next] | [standalone]


#2538

Fromalxmist@aol.com
Date2016-03-18 09:36 -0700
Message-ID<dbde08e9-4ec2-42fc-905a-c6b16a4c6377@googlegroups.com>
In reply to#2537
Hmmmm, I wish the book had mentioned that.
But if RTS is built in to these routines, what is my RTS command actually doing?

[toc] | [prev] | [next] | [standalone]


#2540

FromDavid Schmidt <schmidtd@my-deja.com>
Date2016-03-18 12:39 -0400
Message-ID<nchapr$h1g$2@dont-email.me>
In reply to#2538
On 3/18/2016 12:36 PM, alxmist@aol.com wrote:
> Hmmmm, I wish the book had mentioned that.
> But if RTS is built in to these routines, what is my RTS command actually doing?

_Your_ RTS is returning to the "system," whatever that is - the monitor 
if you start from the monitor, or BASIC if you're CALLing it from there.

[toc] | [prev] | [next] | [standalone]


#2546

FromMichael Pohoreski <michael.pohoreski@gmail.com>
Date2016-03-18 12:25 -0700
Message-ID<bf05e3be-1c50-4003-bf24-e6ed59e05539@googlegroups.com>
In reply to#2540
On Friday, March 18, 2016 at 9:39:20 AM UTC-7, schmidtd wrote:
> On 3/18/2016 12:36 PM, alxmist
> > Hmmmm, I wish the book had mentioned that.
> > But if RTS is built in to these routines, what is my RTS command actually doing?
> 
> _Your_ RTS is returning to the "system," whatever that is - the monitor 
> if you start from the monitor, or BASIC if you're CALLing it from there.

Exactly. You can probe the return address *non-destructively* via the TSX instruction:

PRHEX EQU $FDDA

START TSX
  LDA $102,X
  JSR PHDEX
  LDA $101,X
END JMP PRHEX

which assembles to:

300:BA BD 02 01 20 DA FD BD 01 01 4C DA FD
Ctrl-C
CALL 768

It will print FF84, which is -1; the real next address is FF85.


[toc] | [prev] | [next] | [standalone]


#2547

Fromgids.rs@sasktel.net
Date2016-03-18 13:09 -0700
Message-ID<fd6cb944-ad8e-4d34-8a59-335b1ef53cf0@googlegroups.com>
In reply to#2536
On Friday, March 18, 2016 at 10:22:38 AM UTC-6, alx...@aol.com wrote:
> The instructional program I'm on now is all about using a built-in routine for COUT. The only RTS in this listing seems to be the one for JSR HOME. Wouldn't the program need an RTS for each time I use COUT?
> 
> CTR EQU $06
> HOME EQU $FC58
> COUT EQU $FDED
> START JSR HOME
>  LDA #$FF
>  STA CTR
> LOOP LDA CTR
>  JSR COUT
>  DEC CTR
>  BEQ END
>  JMP LOOP
> END RTS



You would only have to worry about ReTurnS from the subroutines you create within your own program.  All of ROM's major supported entry points automatically return to your calling program.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.sys.apple2.programmer


csiph-web