Shop OBEX P1 Docs P2 Docs Learn Events
Reading the stack — Parallax Forums

Reading the stack

Armored CarsArmored Cars Posts: 172
edited 2005-11-01 19:34 in General Discussion
Is there a way to read the top of the stack so a subroutine can know where it was called from?· I would prefer this over setting some bits in my mishmash variable (slower, makes uglier code).
Thanks

Comments

  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-11-01 14:25
    Unfortunately no.

    Inside the isr it is possible using the secret instruction popPC.

    For normal calls, you could pass the return address to the

    subroutine, then use pushPC and reti to jump back to

    that address.

    regards peter
  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-11-01 14:31
    Peter, pushPC is only used for calling the ISR correct? If you disable interrupts, pushPC, call sub, (in sub) popPC, enable interrupts, could you not mimic this ability? The last two steps would need to be done immeadiately in the subroutine because it wouldn't work for more than one level of subroutine.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·1+1=10
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-11-01 14:41
    pushPC is also used by debug, so if you use that you can not

    use the debugger. The shadow stack is only 2 levels deep.

    (isr and debug, or isr and your use)

    regards peter
  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-11-01 15:05
    I neglected to incorporate debug, because I generally assume debug won't be used when using the secret instructions. But that brings up another question, if you take care on not stepping through (or "break"ing in) the critical section (between disabling and reenabling interrupts), could you use the debugger for the program?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·1+1=10
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-11-01 15:26
  • Armored CarsArmored Cars Posts: 172
    edited 2005-11-01 15:43
    From the aforementioned thread;

    MOV·W,JMPLOC·;Load W with "Next" Addr on this 1/2 Page2

    If I am reading this correctly this will load w with the next address.· If "next address" means the top of the stack or where the next ret will return to, that code·will do exacly what I need.
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-11-01 16:04
    Here's another thread

    http://forums.parallax.com/showthread.php?p=520630

    regards peter
  • Armored CarsArmored Cars Posts: 172
    edited 2005-11-01 16:29
    From reading that I think this is getting way to complex and it probably would be best to stick with my origional code.
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-11-01 17:11
    You could do this

    from location 1
    mov m,#($+4)>>8
    mov w,#adr1
    call @mySub
    adr1:·· ;ret adr for this call

    from location 2
    mov m,#($+4)>>8
    mov w,#adr2
    call @mySub
    adr2:·· ;ret adr for this call

    mySub:
    ;save m and w for reference or store to private stack or whatever
    ;do some code
    retp· ;return to adr1 or adr2, specified by m and w

    regards peter
    ·
  • pjvpjv Posts: 1,903
    edited 2005-11-01 17:42
    Hi All;

    I'd like to pipe in here as I have some experience at this.

    The 8 level CALL STACK is totally independent of the 2 level SHADOW STACKS, and the CALL STACK is not accessible under program control in any manner that I have been able to determine.

    As Peter V indicates, the desired action could be simulated by saving a return address prior to jumping to (calling) the subroutine, and then returning from the subroutine via pushing the saved return address on the M:W registers and forcing the return jump via the RETI instruction.

    There is caution to be used here as there are also hidden STATUS bits that get effected on executing a RETI.

    Paul;
    Your description is not correct; pushPC loads M:W into the PCshadow, and popPC does the reverse. It takes a RETI to trigger the jump, but of course all other shadows are then also popped, thereby changing the whole state of the processor.

    As an answer to Armored Cars' original post, my recommendation for the casual programmer is to just use the standard call/return instructions if at all possible. The other approaches, while possible as in the RTOS I have written, are quite involved.

    Cheers,

    Peter (pjv)
  • pjvpjv Posts: 1,903
    edited 2005-11-01 18:08
    Peter Verkaik said...
    You could do this

    from location 1
    mov m,#($+4)>>8
    mov w,#adr1
    call @mySub
    adr1:·· ;ret adr for this call

    from location 2
    mov m,#($+4)>>8
    mov w,#adr2
    call @mySub
    adr2:·· ;ret adr for this call

    mySub:
    ;save m and w for reference or store to private stack or whatever
    ;do some code
    retp· ;return to adr1 or adr2, specified by m and w

    regards peter
    Hi Peter;
    While your suggestion is technically correct, I believe that your last line (retp ;return to adr1 or adr2, specified by m and w) may lead the reader to believe that the return is directed by the contents of M and W, rather than the entry at the top of the call stack.
    The contents of M and W are totally irrelevant to the return; you had simply chosen them as a convenient location to save the return address so that the subroutine code could use it if so required.
    Also, would loading M and W also not be written somewhat more simply as:

    Location1· ·· ·code···························· ;arbitrary code
    · ··············· ·code···························· ;arbitrary code
    ············· ···· mov··· m,#Return1>>8··· ;get the upper 4 return address bits into m (must go through w for SX48/52)
    ·· ········· ····· mov··· w,#Return1········· ;get the lower 8 return address bits into w
    ················· ·call·····Subroutine··········· ;go to the routine
    Return1······· ·code···························· ;arbitrary code
    ·················· code···························· ;arbitrary code

    Subroutine·····code···························· ;arbitrary code
    ···················code···························· ;arbitrary code
    ·················· retp

    Cheers,
    Peter (pjv)

    Post Edited (pjv) : 11/1/2005 6:11:41 PM GMT
  • Peter VerkaikPeter Verkaik Posts: 3,956
    edited 2005-11-01 18:40
    pjv,

    Yes, that would rule out possible errors due to counting storage words.

    And yes, the example only shows how to pass the value that is on top of

    stack (after call Subroutine), to be used in the subroutine, without changing the

    call/return scheme.

    regards peter
  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-11-01 18:52
    I think there was a little misunderstanding about my suggestion (no biggie), I wasn't suggesting forcing the system as you do in your MTOS Peter (pjv), but using pushPC and popPC as a temporary store to pass the address onto the subroutine, though now looking more at it, there would be a built in offset error since the PC pushed onto the shadow PC stack would not be the address of the call instruction.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·1+1=10
  • pjvpjv Posts: 1,903
    edited 2005-11-01 19:08
    Hi Paul;

    Sorry to keep harping on this, but I understood your suggestion (pushPC) to literally mean that you expected the PC itself to be pushed onto the shadow stack, and this of course is not how it works; pushPC pushes M:W onto the PCshadow.

    And the converse, popPC pops the PCshadow into M:W.

    It is the RETI instruction that pops the PCshadow into the PC; and, as previously noted, all other shadows (W, FSR,STATUS), into their respective registers.

    Cheers,

    Peter (pjv)
  • Paul BakerPaul Baker Posts: 6,351
    edited 2005-11-01 19:34
    *smacks himself* Ok nevermind, It'd work if you setup M:W like for IREAD, but thats just making the situation more complicated than it needs to be, just use two variables instead.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    ·1+1=10
Sign In or Register to comment.