Omnimaga

Calculator Community => TI Calculators => ASM => Topic started by: Jerros on October 10, 2010, 07:55:06 am

Title: Executing "ret" twice?
Post by: Jerros on October 10, 2010, 07:55:06 am
I've stumbled across another problem - how would I do a "double" ret command?
Let me explain:
Code: [Select]
Label1:
   call   label2
   ret                ; Let's call this one "ret%" This will go to where I want!

Label2
   ret                ; I want this "ret" to go to the same 'place' as "ret%".
Or, to make things more general:
Code: [Select]
Label1:
Call Label2
(......)        ;[1]

Label2:
Call Label3
ret             ;[2] Will take it back to [1].

Label3:
Call Label4
ret             ;[3] Will take it back to [2].


Label4:
Call Label5
ret             ;[4] Will take it back to [3].


Label5:
ret             ;[5] Will take it back to [4].
In the latter example, I want the ret from [5] not to go back to [4], but, lets say, to [1].
Is it possible to set things up in such way that a "ret" command will do that?
I don't know the specifics, but the addres from which you use "Call" from gets stored in a  stack, right?
So would it be possible to "Pop" that stack, so that a "ret" will take it back more than one 'step'?
From what I've  read, "POP   PC" would do that. :P Though I've  tried that and then my assembles gives an error, so I guess things aren't that simple.
Thank you!
Title: Re: Executing "ret" twice?
Post by: jnesselr on October 10, 2010, 08:19:46 am
Yeah, iirc, the last address is stored on the stack.  Try a pop into hl and then go to that address.
Title: Re: Executing "ret" twice?
Post by: Jerros on October 10, 2010, 08:40:41 am
Yeah, iirc, the last address is stored on the stack.  Try a pop into hl and then go to that address.
Ehrm, as in:
Code: [Select]
Label1:
   Call   Label2
   (...)

Label2:
   Call   Label3
   ret                  ; <-- isn't neccarery, since it will nver get executed, right?

Label3:
   POP   HL
   ret                     ;<-- will go to label 1?
^That?

EDIT:
Doesn't work.
I'm more braindead than you can imagine - could you elaborate what you meant with:
Try a pop into hl and then go to that address.



Thanks for the reply!
Title: Re: Executing "ret" twice?
Post by: jnesselr on October 10, 2010, 09:55:25 am
Yeah, not quite.  See, when you do a call, and I can't remember the exact addresses, but I think it stores the byte right after it, so that it would be on the ret or something. I'm not real sure, some other asm programmer could help you a little better.  I've always just used ret.  If you have a debugger, try following where the call is going, and if you can, what is on the stack.  I believe the TI-83 SDK has one.

Also, btw, if it went to the byte to label1, it would be the call for label2, which would call it, and then that would be an infinite loop.

Try this as a completely new program:
Code: [Select]
Label1:
push Label2
ret

Label2:
ret
This should exit the program because you are pushing the location of Label2 onto the stack, and then returning to it. Not sure, though. If that doesn't work, just push two zeros onto the stack, and run it with a ret. That should reset your calc, so beware.
Title: Re: Executing "ret" twice?
Post by: SirCmpwn on October 10, 2010, 10:03:07 am
That looks like it will work at first glance, but I don't konw why it isn't.  This is how calls work:
Code: [Select]
9D95h:   Label1:
9D95h:   call Label2   // 1. Pushes 9D97 to the stack, loads 9D98 into PC
9D97h:   ret  // 5. This executes.
9D98h:   Label2:
9D98h:   call Label3  // 2. This loads 9D9B onto the stack (the stack at this point: 9D9B, 9D97) and loads 9D9C into PC
9D9Bh:   ret
9D9Ch:   Label3:
9D9Dh:   pop hl  // 3. This removes the last stack entry (the stack at this point: 9D97)
9D9Eh:   ret  // 4. This does the equivalent of POP PC (PC now equals 9D97)
Title: Re: Executing "ret" twice?
Post by: Jerros on October 10, 2010, 10:27:05 am
That looks like it will work at first glance, but I don't konw why it isn't.  This is how calls work:
I don't know why it isn't either, haha.
Try this as a completely new program:

Code:
Label1:
push Label2
ret

Label2:
ret
This should exit the program because you are pushing the location of Label2 onto the stack, and then returning to it. Not sure, though. If that doesn't work, just push two zeros onto the stack, and run it with a ret. That should reset your calc, so beware.
But does label 2 get executed now?
Doesn't look like it...
ret  // 4. This does the equivalent of POP PC (PC now equals 9D97)
So... isn't it possible to do POP PC then?
Because POP HL just pops... HL, not PC right?
It doesn't seem to work though...
Title: Re: Executing "ret" twice?
Post by: SirCmpwn on October 10, 2010, 11:05:20 am
ret IS pop pc.
pop hl pops hl.
Title: Re: Executing "ret" twice?
Post by: Jerros on October 10, 2010, 11:48:41 am
ret IS pop pc.
pop hl pops hl.
But... I want to pop PC twice with one Ret command...
Or at least do 2 pops and THEN peform the next line of code.
I suck at making myself clear. Q_Q
Title: Re: Executing "ret" twice?
Post by: SirCmpwn on October 10, 2010, 11:55:41 am
Err...
ret \ ret would pop pc twice, but the first time you pop pc, the next line will not execute, because PC will be elsewhere.  Pop is not exclusive to variables, they are all on the stack together.  For instance:
Code: [Select]
push hl
push bc
pop hl
pop bc
This will swap the values of hl and bc.  Therefore, if (9D95:) call xxxx pushes PC to the stack and loads xxxx into pc, the stack looks like this:
9D95
Then, if you pop hl, you can no longer return to that location unless you push it back.  Look at this:
Code: [Select]
Label1:
push Label1
jr Label2
This is the equivalent of call Label2, just with more bytes.
Title: Re: Executing "ret" twice?
Post by: mapar007 on October 10, 2010, 12:21:33 pm
POP HL \ ret should work, Jerros. Maybe the fault is elsewhere? Do you mind posting the code fragment involved?
Title: Re: Executing "ret" twice?
Post by: Jerros on October 10, 2010, 12:32:38 pm
POP HL \ ret should work, Jerros. Maybe the fault is elsewhere? Do you mind posting the code fragment involved?
I'll just try again.
The code fragment considered is BIG (over 600 lines + lots of calls and stuff) so I dont want to bother you with that ^_^.
To give more detail of what I'm trying:
Code: [Select]
Label1:
(...)
   CALL   Label2
(...)                            ; <-- must get executed after the RET*

Label2:
(...)
   CALL   label3
(...)                            ; <-- A normal Ret in Label 3 will cause this to be executed. I don't want that :P.
ret
Label3:
    b_call _GetCSC
    CP     skDel
    JP     Z, Quit
    JR     Label3
Quit:
   ret            ; and I want this RET* to go to Label1, NOT 2.
It's obvious that I should use a JP under "Quit" to go to where I want in Label1, though I have my reasons for it to MUST be a "ret"...
Err...
ret \ ret would pop pc twice, but the first time you pop pc, the next line will not execute, because PC will be elsewhere.  Pop is not exclusive to variables, they are all on the stack together.  For instance:
Code: [Select]
push hl
push bc
pop hl
pop bc
This will swap the values of hl and bc.  Therefore, if (9D95:) call xxxx pushes PC to the stack and loads xxxx into pc, the stack looks like this:
9D95
Then, if you pop hl, you can no longer return to that location unless you push it back.  Look at this:
Code: [Select]
Label1:
push Label1
jr Label2
This is the equivalent of call Label2, just with more bytes.
Wow! Thanks, I get it now :P
Though I can't experiment anymore today, I'll post as soon as I know more.
Title: Re: Executing "ret" twice?
Post by: calc84maniac on October 10, 2010, 01:56:36 pm
Actually, a call Label2 equivalent would look like this:
Code: [Select]
Label1:
  ld hl,ReturnLabel
  push hl
  jp Label2
ReturnLabel:

It won't be returning to Label1, it will return to the point after the call.
Title: Re: Executing "ret" twice?
Post by: SirCmpwn on October 10, 2010, 01:57:47 pm
Thanks calc84maniac.
Title: Re: Executing "ret" twice?
Post by: Jerros on October 11, 2010, 06:58:03 am
Actually, a call Label2 equivalent would look like this:
Code: [Select]
Label1:
  ld hl,ReturnLabel
  push hl
  jp Label2
ReturnLabel:

It won't be returning to Label1, it will return to the point after the call.
Thanks thanks thanks! :P
I'll try this as soon as possible. ^_^
Title: Re: Executing "ret" twice?
Post by: Jerros on October 12, 2010, 03:41:29 am
Figured it out ~
All I needed to do was pop HL enough times to return to where I wanted it to:
Code: [Select]
RetMoar:
POP HL
POP HL
ret
I just didn't knew how calls and stacks worked, but by putting all your advices together, I've got a pretty clear idea now, and managed to fix my own problem (albeit a noob problem).
Thank you all!

EDIT:
Or so I thought...
It seems that the number of POPs required varies the whole time, which is odd...
Do more lines get executed after the GetCSC if you press a button?
Like:
Code: [Select]
    b_call _GetCSC
    CP     skDel
    JP     Z, Quit
    (...)                            ; Can this get executed, even though you press the Del button?
                                      ; If that's true, things just've gotten much more complicated :c

Quit:
POP HL
POP HL
ret
Title: Re: Executing "ret" twice?
Post by: DJ Omnimaga on October 12, 2010, 03:48:13 am
On an off-topic note, I fixed your forum signature because it was not showing up properly
Title: Re: Executing "ret" twice?
Post by: Quigibo on October 12, 2010, 03:56:07 am
You know, you can save your stack pointer first and then return out of an arbitrary number of nested calls at once without memory leaks.

Code: [Select]
;Say this is on the base level before you start calling everything
  ld (save_sp),sp

;Now start calling away...
  call L1
L1:
  call L2
L2:
  call L3
L3:
  ...
LN:

;Now you decide you want to return to the base level again,
;but you don't know how many nested subs you actually used.
;So you just load the base address directly into sp again.

  ld sp,(save_sp)

;You are now back at the base level again.
;So in essence, you have returned out of all the subroutines
;and can do as you please at the base level.
Title: Re: Executing "ret" twice?
Post by: mapar007 on October 12, 2010, 04:44:36 am
You know, you can save your stack pointer first and then return out of an arbitrary number of nested calls at once without memory leaks.
<code block not quoted>

Ooh, I failed to think of that.
Title: Re: Executing "ret" twice?
Post by: SirCmpwn on October 12, 2010, 08:45:17 am
(...) Should never get executed if the del button is held down...
Try it with direct input and see again.
Title: Re: Executing "ret" twice?
Post by: Jerros on October 14, 2010, 03:15:23 am
On an off-topic note, I fixed your forum signature because it was not showing up properly
Haha! That was a mindf**k to me.;) One moment my sign wasn't showing correctly and I was like "Meh, will fix that later", then I log in, and it was showing correctly... >.< Thanks though.
You know, you can save your stack pointer first and then return out of an arbitrary number of nested calls at once without memory leaks.
I'll try that, though my problem is still that it HAS to return to the base level by a RET command (for noob reasons).
But I guess that with your code that can be done easely.
Thanks Quigibo, you've saved my day once again.

EDIT:
Ah, figured out why/how Quigibo's script works.
Works PERFECTLY now, so problem solved. n_n
Title: Re: Executing "ret" twice?
Post by: DJ Omnimaga on October 18, 2010, 12:54:19 am
I'm glad to hear it works fine :D