HP50g: local LBL and GOTO in user or sysRPL
09-06-2016, 05:24 PM
Post: #1
 wojtek Member Posts: 131 Joined: Dec 2015
HP50g: local LBL and GOTO in user or sysRPL
Have anybody found implementation of LBL and GOTO in hp50g?
09-06-2016, 05:31 PM (This post was last modified: 09-06-2016 05:32 PM by Han.)
Post: #2
 Han Senior Member Posts: 1,834 Joined: Dec 2013
RE: HP50g: local LBL and GOTO in user or sysRPL
Was your question in the context of RPL or SysRPL? It's fairly easy to do in assembly, so I imagine that you probably meant the first two. Off the top of my head, it can be done using a hybrid of RPL and assembly. If you are comfortable with assembly, you can encapsulate your entire code into a code object that changes the runstream to the first RPL word. This would allow you to inject assembly labels and make use of the assembly GOTO (and related) opcodes.

Graph 3D | QPI | SolveSys
09-06-2016, 06:10 PM
Post: #3
 Han Senior Member Posts: 1,834 Joined: Dec 2013
RE: HP50g: local LBL and GOTO in user or sysRPL
(09-06-2016 05:31 PM)Han Wrote:  Was your question in the context of RPL or SysRPL? It's fairly easy to do in assembly, so I imagine that you probably meant the first two. Off the top of my head, it can be done using a hybrid of RPL and assembly. If you are comfortable with assembly, you can encapsulate your entire code into a code object that changes the runstream to the first RPL word. This would allow you to inject assembly labels and make use of the assembly GOTO (and related) opcodes.

Scratch that... given that the jumps are likely all relative, GOTOs would likely not work unless stored in fixed memory (possible, but lots of work). You could, however, use PC=A and use relative jumps that are calculated during compile time (still requires some assembly language, obviously).

Graph 3D | QPI | SolveSys
09-07-2016, 08:21 PM (This post was last modified: 09-07-2016 08:23 PM by 3298.)
Post: #4
 3298 Member Posts: 117 Joined: Oct 2014
RE: HP50g: local LBL and GOTO in user or sysRPL
Why wouldn't relative GOTOs in Saturn ASM work? I thought the whole point of relative jumps was that you could relocate the entire code...

Anyway, I tried the PC=A approach Han mentioned. It uses some ASM of course, and it is obviously not safe for normal UserRPL operation, so I simply used some features of the on-board SysRPL and ASM compiler (MASD).
The starting point was the existing SysRPL goto command. Yes, that's a thing already, and the ROM uses it in a few places, but because it's made for absolute jumps it's not suitable for user code unless you copy it to a fixed location.

Firstly, the compiler supplies a handy label mechanism which is practically designed for this. Syntax is "LABEL foo" according to the MASD docs.
Next: supplying the jump offset to the goto command. The easiest solution I found is to switch to ASM mode, use the apparently ASM-only G5 macro to obtain the offset, and switch back to SysRPL mode. In code this looks like: "!ASM G5 foo !RPL".
Last is the command itself. It is an ordinary code object, so you could inline it or make it a separate program, whatever you want. This is the code:
Code:
CODE   C=DAT0.A   AD0EX   A+C.A   AD0EX   GOVLNG Loop ENDCODE
You need to place this or a call to it directly before the offset calculation snippet.
If you know Saturn ASM you can probably see that it simply adds the next address in the runstream to the runstream pointer. There is no adjustment for the size of that taken address because the G5 macro handles that part for us (if the label is right behind the goto's offset, the G5 macro will output 5, which is the size of an address, so the address will be skipped like it should).
I did a simple test with this and it seems to work. MASD didn't like my attempts to craft a macro from this, though. Maybe someone who knows MASD better could help with that, but I'd just do it manually or add my own preprocessing step to the compilation process.

You probably know from other programming languages that it's a bad idea to jump from one code block to a different one. In RPL this can be used with care if you know how the return stack works, but I don't recommend it. It's as messy as trying to break out of a BEGIN...AGAIN, BEGIN...UNTIL, or BEGIN...WHILE...REPEAT loop early.
09-07-2016, 08:32 PM
Post: #5
 Han Senior Member Posts: 1,834 Joined: Dec 2013
RE: HP50g: local LBL and GOTO in user or sysRPL
(09-07-2016 08:21 PM)3298 Wrote:  Why wouldn't relative GOTOs in Saturn ASM work? I thought the whole point of relative jumps was that you could relocate the entire code...

It would work if it was pure assembly (which you can trick the calculator to think your object is pure assembly by encapsulating it inside a code object). That said, the reason I was backtracking on my earlier statement was because I imagined that original post was likely using (Sys)RPL and therefore the labels might not be stable. Most (SysRPL) projects span across several secondaries (I don't know of many RPL programs that exist as a single secondary object; most are either libraries or have subroutines that are placed into temporary memory).

Graph 3D | QPI | SolveSys
09-07-2016, 10:15 PM
Post: #6
 DavidM Senior Member Posts: 780 Joined: Dec 2013
RE: HP50g: local LBL and GOTO in user or sysRPL
(09-07-2016 08:21 PM)3298 Wrote:  Why wouldn't relative GOTOs in Saturn ASM work? I thought the whole point of relative jumps was that you could relocate the entire code...

Anyway, I tried the PC=A approach Han mentioned...

I was also playing around with this concept, but using Debug4x/Emu48 instead of the onboard compiler. I was successful making the jump, but realized pretty quickly that the interpreter pointer (D0) needed to be updated to keep it from acting more like a GOSUB.

That's where things started getting messy. Updating D0 to point to the new next object seems straightforward enough, but "fixing" the RPL return stack has so far eluded me. Here's what I have so far as a test:
Code:
::    "begin"    CODEM       A=PC       *.Jmp1       LC(5) (Lbl1-.Jmp1)       A+C.A       D0=A       PC=(A)    ENDCODE    "skip this"    "and this"    TRUE ?SEMI    LABEL Lbl1    "Lbl1 1"    "Lbl1 2" ;

The output of the above code is:
Code:
"begin" "Lbl1 1" "Lbl1 1" "Lbl1 2"
...so clearly the RPL return stack needs to be adjusted. But my attempts so far have not been fruitful.

Having said all this, I still agree with 3298 and Han that this is probably not a very robust solution. I can imagine that a common place you might want to use a GOTO would be embedded in some kind of loop structure (or worse yet, multiple layers deep). Those are exactly the type of situations that would cause problems with this approach, since the RPL return stack would require manipulation that would depend on the exact status of the loop(s) you were trying to exit from. Keeping track of all that would quickly negate any GOTO advantage over simply using normal coding structures from the start.
09-07-2016, 10:37 PM (This post was last modified: 09-07-2016 10:41 PM by Vtile.)
Post: #7
 Vtile Senior Member Posts: 385 Joined: Oct 2015
RE: HP50g: local LBL and GOTO in user or sysRPL
I think that loop quit gotos could be emulated with the IFERR DOERR THEN END structures, not too efficient, but this way you can jump out from loops.

Also {<<program1>> <<program2>><<programNth>>} N GET EVAL structure could be used as GOSUB somehow, but again this is just a braindump without testing nor further evaluating of though.
09-08-2016, 06:25 AM
Post: #8
 cyrille de brébisson Senior Member Posts: 1,009 Joined: Dec 2013
RE: HP50g: local LBL and GOTO in user or sysRPL
Hello,

As stated above, ASM goto are not a problem.
(SYS)RPL goto do exist natively, but require fix address which does not work here...
Relative GOTO can be implemented in ASM in a (SYS)RPL program using arithmetics on the D0 pointer.

CODE
RPL
*endcode
ENDCODE

(sys)rpn here!!!

LABEL dest

Note that if you know that the distance between the 2 items is not long, you can use directly D0+(dest-endcode) (if my memory serves me well) but since arithmetic on pointers is limited to +/- 16, if the distance is large, it can be problematic.

Note that this type of GOTO can NOT exit (sys)RPL loops and program structures!!!! so be careful!!!

Cyrille

Although I work for the HP calculator group, the views and opinions I post here are my own. I do not speak for HP.
09-08-2016, 07:47 AM
Post: #9
 wojtek Member Posts: 131 Joined: Dec 2015
RE: HP50g: local LBL and GOTO in user or sysRPL
Thank you friends, I've read all posts very carefully. I'm interested in jumps inside a single block of code only. Although I'm an experienced assembler programmer I have not tried that of hp50g yet and know little about its architecture
Thanks very much again
09-09-2016, 02:34 AM (This post was last modified: 09-12-2016 04:24 PM by DavidM.)
Post: #10
 DavidM Senior Member Posts: 780 Joined: Dec 2013
RE: HP50g: local LBL and GOTO in user or sysRPL
My curiosity got the better of me and I spent a little more time on this trying a few things. Cyrille's post provided a big clue that took me a while to understand due to the multiple interpretations of the "RPL" statement in his sample code. While I initially thought that it was a compiler directive indicating to switch compilation modes (which didn't make sense to me), I ultimately realized it was the shortcut for the standard "LOOP" phrase that triggers the next RPL object execution:
Code:
   A=DAT0 A    D0=D0+ 5    PC=(A)

At that point things fell into place nicely and it became clear how to proceed. Reminder: everything below is source code applicable to Debug4x; if you use the on-board compiler, the syntax would be different (though similar).

To make things slightly more readable, I cooked up this macro to assist with the GOTO step:
Code:
ASSEMBLE MyGOTO MACRO    CON(5) =DOCODE    REL(5) LBL_END_$0 A=PC jmp$0    LC(5) ($1)-(jmp$0)    A+C A    D0=A    GOVLNG =Loop LBL_END_\$0 MyGOTO ENDM RPL

This removes some of the clutter in the final code segment. The macro call still has to be bracketed by "ASSEMBLE" and "RPL" tokens, and unfortunately they need to be on separate lines. Hence the 3-line invocation for each GOTO.

With that, I present (in all its spaghetti-code glory) a working example of a code segment that jumps around to arbitrary labels:
Code:
::    ASSEMBLE       MyGOTO lbl_A    RPL LABEL lbl_EXIT    "all done!" [;] LABEL lbl_B    "second line"    ASSEMBLE       MyGOTO lbl_C    RPL    "skip this" LABEL lbl_C    "third line"    ASSEMBLE       MyGOTO lbl_EXIT    RPL LABEL lbl_A    "first line"    ASSEMBLE       MyGOTO lbl_B    RPL    "skip this, too!" ;

The above code object leaves this on the stack at exit:
Code:
"first line" "second line" "third line" "all done!"

Hope this helps.

EDIT: changed the "exit" SEMI to "[;]", which is a better way to generate the appropriate code without RPLCOMP ditching the rest of the program due to its tracking of code blocks. Also shortened the Saturn code by jumping to Loop instead of executing directly.
09-09-2016, 10:35 AM
Post: #11
 3298 Member Posts: 117 Joined: Oct 2014
RE: HP50g: local LBL and GOTO in user or sysRPL
I guess I should showcase my version in a program as well...

The major differences to the other solutions are:
- I'm using the on-board compiler
- the offset is not embedded inside the code object but placed behind it, so the code object can be re-used.

Here I'm using one of my favorite tricks, storing a subroutine (the goto code) in a local variable:
Code:
::   ' CODE     C=DAT0.A     AD0EX     A+C.A     AD0EX     GOVLNG Loop   ENDCODE   ' LAM goto BINT1 DOBIND (store goto code in LAM goto)   %0   LAM goto !ASM G5 label1 !RPL   %10 %+ (skip this)   LABEL label1   %5 %+   LAM goto !ASM G5 label2 !RPL   %1+ (skip this too)   LABEL label2   %.5 %+   ABND (get rid of the local variable with the goto code) ;
This program will output 5.5, the lines adding 10 and 1 will be skipped.
I used a named LAM here to improve readability; unnamed LAMs would be faster and smaller, but unfortunately NULLLAM and 2GETEVAL are the only commands fetching and evaluating an unnamed LAM in one go, others need a separate EVAL.

But I'll have to ask: what usecases for goto does SysRPL have? In C I sometimes use goto, but only for errors (either jumping to an error handling section at the end of a function, or jumping to the start from inside nested code blocks when an error prompts a retry). With RPL's error handling functions (ERRSET...ERRTRAP and ERRJMP) these usecases vanish. The former should be obvious, the latter can be handled by letting the error cascade up the return stack to the "code block" (i.e. secondary) that should be repeated, and constructing a BEGIN...UNTIL loop there.
So what do you need this for? (Or are you just curious how it could be implemented?)
09-09-2016, 01:24 PM (This post was last modified: 09-09-2016 01:27 PM by wojtek.)
Post: #12
 wojtek Member Posts: 131 Joined: Dec 2015
RE: HP50g: local LBL and GOTO in user or sysRPL
(09-09-2016 10:35 AM)3298 Wrote:  So what do you need this for? (Or are you just curious how it could be implemented?)
Out of curiosity as well but mainly because I am biased former assembly and C programmer. I almost think in assembly. Always felt comfortable in 41c programming because of very good solution of LBL and GTO. In some cases GTO in 50g would simplify the code and I was curious if implementing it would be possible.
09-09-2016, 02:49 PM
Post: #13
 DavidM Senior Member Posts: 780 Joined: Dec 2013
RE: HP50g: local LBL and GOTO in user or sysRPL
(09-09-2016 10:35 AM)3298 Wrote:  I guess I should showcase my version in a program as well...

Nicely done. Putting some of the preliminary steps in a reusable code object adds efficiency.

(09-09-2016 10:35 AM)3298 Wrote:  But I'll have to ask: what usecases for goto does SysRPL have?

I agree with you on this. Not only agree, but I must confess that I still feel that the risks outweigh any advantage to using this type of construct. In a real program, it would be far too easy to overlook a critical issue (traversing secondaries, skipping ABND, "breaking" error traps, etc.). Troubleshooting could be problematic because some of the resulting problems would be memory leaks that might not show up for a while. Just seems like more trouble than it's worth to go this route.

A similar technique might have limited use for a GOSUB construct, though, at least in certain scenarios. Like you, I usually place SysRPL subroutines in LAMs when not building a library. But there could be times when you don't want to alter the temporary environment structure that this could come into play. Might be worth investigating, and it seems like a GOSUB wouldn't carry the same risks as a GOTO.
 « Next Oldest | Next Newest »

User(s) browsing this thread: 1 Guest(s)