HP Forums

Full Version: Help - Assembly programming on Debug4x (HP50G)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi

This is my first question.

I have started reading about assembly programming and am sort of at the point where I need to start doing some experimental programming to progress further.

I am reasonably good at sysrpl and find using Debug4x no problem, but cannot find a way to do start using assembly programming on Debug4x

From what I have read I think I should be using CODEM & ENDCODE

I have tried the code snippet below which puts BINT1 on the stack and the assembly code (from asmtut) should be DROP. When its run the screen just clears completely and the emulator freezes

Any help on this would be much appreciated

Jeff


ASSEMBLE
CON(1) 8
RPL
xNAME ASMTEST
::

BINT1


CODEM

C=DAT1 A
?C=0 A
GOYES QUIT
D1=D1+ 5
D=D+1 A
*QUIT
GOVLNG =LOOP % =LOOP is 2D564 on the 48 and 05149 on the 49, which returns to RPL

ENDCODE

;
(06-11-2019 07:47 PM)JeffB Wrote: [ -> ]ASSEMBLE
CON(1) 8
RPL
xNAME ASMTEST

Leave out this part - that's only needed for building libraries.
The rest should be ok, I think.

Cheers, Werner
Yes, the following in Debug4x works just fine:
Code:
RPL

::
   BINT1
   CODEM
      C=DAT1 A
      ?C=0 A
      GOYES QUIT
      D1=D1+ 5
      D=D+1 A
      *QUIT
      GOVLNG =LOOP % =LOOP is 2D564 on the 48 and 05149 on the 49, which returns to RPL
   ENDCODE
;

Since you are invoking the MASD compiler (via CODEM), you could also use this alternative form to do the same thing:
Code:
RPL

::
   BINT1
   CODEM
      C=DAT1 A
      ?C#0 A ->{
         D1=D1+ 5
         D=D+1 A
      }
      GOVLNG =LOOP
   ENDCODE
;

In this tiny example, there's not a significant advantage to the latter form. Both versions compile to the same size object and do the same thing. But coding in this manner makes it easier as projects grow, since you don't have to keep up with jumps and labels for simple skips. The MASD preprocessor essentially creates indexed labels as needed so you don't have to worry about them when using this syntax. It can also help by making the code easier to use in other projects without having to worry about label conflicts.
(06-11-2019 07:47 PM)JeffB Wrote: [ -> ]C=DAT1 A
?C=0 A
GOYES QUIT

In addition to what Werner said (which should resolve your freezing issues) and what DavidM suggested (which merely improves readability), your code won't do exactly what you think it will do. The issue is in the lines I quoted: you're reading an object from the stack, then comparing it to 0 and jumping if that's true. However, you're not comparing the number stored in the BINT object, but instead you're comparing its address with 0. If you ever get such an address from the stack, then you've done something wrong (e.g. it can happen when the stack is empty, but dropping a level in that case will mess things up).
What you want is something like this:
Code:
A=DAT1 A
AD0EX
D0+5
C=DAT0 A
D0=A
?C=0 A
GOYES QUIT
That brings the address of the object into A, moves it into D0 while backing up the former D0 (which is the top of the return stack) into A, advances D0 to point just past the 5-nibble prolog of the object (i.e. to the 5-nibble number in a BINT), pulls the number into C, and then it restores D0. Finally, your comparison and conditional jump.
Hope this helps.
(06-12-2019 09:02 AM)3298 Wrote: [ -> ]...you're reading an object from the stack, then comparing it to 0 and jumping if that's true. However, you're not comparing the number stored in the BINT object, but instead you're comparing its address with 0. If you ever get such an address from the stack, then you've done something wrong (e.g. it can happen when the stack is empty, but dropping a level in that case will mess things up).

I believe Jeff was merely copying the sample code for the "Drop" program from "Introduction to Saturn Assembly Language" by Gilbert Fernandes at the bottom of page 141 in that book. In this case, he probably used BINT1 just to place something on the stack which could subsequently be dropped by the code object. The code sample checks to see if the current SL1 pointer is aimed at #00000 in an effort to skip the traditional drop sequence if the stack is empty. While that should usually work OK, the "stack depth" discussion that immediately precedes that example in the book also shows why that method is not 100% foolproof.

Dropping a level when the stack is empty is one of my favorite examples of how easy it is to truly mess up your RPL calculator with SysRPL or Saturn code in just a few easy steps. Smile
Thanks everyone for the reply's, really appreciated.

As DavidM said I only copied the ASM code DROP sample as an example to highlight my problem. I am nowhere near the level to write even this simple piece of ASM code myself yet.

The problem I have is how do I write any ASM code using xNAME or NULLNAME in Debug4x as there is no problem with crashes when I mess up while trying to learn

Your replies have given me some ideas which I will try out.
hello,

xName and NULLNAME are used for library creation only.
I honestly do not remember how the whole library thing works and how to tell debug4x to generate one :-( it is was so long ago!

Anyhow, the MASD syntax also encourages you to use a "." as a separator between an instruction and a field. It does make the code more readable as it visually links the 2 and separates one instruction from the next...
It is also better when programming ON the calc where the . is a single key while the space is shifted...

as in:
A=A+B.A C=C+C.B
from memory, for instructions that are of the form reg=reg_operator_reg, you can even omit the reg= as in A+B.A C+C.B This is especially useful on the calc small screen... (and of course you can put as many instructions as you want on one line)...

For example, this code extracts the square root of A.A (as integers of course, result in C.A)

LC FFFFF { C+2.A A-C.A UPNC } CSRB.A

The syntax makes it nice and compact, the initialization and finalization code is clearly visible before and after the braketed loop zone..
And of course, no labels! which makes it so much easier to compile and copy/paste somewhere else in your code!

If/when you DO have to use labels, use local labels for small stuff.
Local labels are labels that start with a . in their names as in: *.loop for example.
Local labels are local in between 2 global labels.
They also get compiled as soon as they get out of scope, which means that you can reuse their name in various sub routines... example:

*sub_routine_1
some code
*.loop
some more code
GOTO .loop
RTN

*sub_routine_2
some code
*.loop <- here, I can reuse the nane .loop as the previous .loop is now "defunct" as it was 100% processed when the compiler hit the *sub_routine_2 label.
some more code
GOTO .loop
RTN

Enjoy ASM coding!
Cyrille
Jeff,

If your goal is to simply have multiple program objects in the same source code file for experimentation, you don't need to create a library for that with Debug4x. You can use something like this:
Code:
RPL

INCLUDE DirMacro.s

ASSEMBLE
   Dir <test>
RPL
::
   "Hello world!"
   CODEM
      SAVE
%     ...
      LOADRPL
   ENDCODE
;

ASSEMBLE
   Dir <test2>
RPL
::
   "How are you?"
   CODEM
      SAVE
%     ...
      LOADRPL
   ENDCODE
;

This requires you to have the DirMacro.s file in your Debug4x "Include" folder. I can't recall if Debug4x comes with that pre-installed or not; if it isn't, here's the contents of that file on my system:
Code:
RPL 

**************************************************************
*  Directory building macro
*
*  Invoke this way:
*  ASSEMBLE
*    Dir  "name"
*    saturn code     (if any)
*  RPL
*    :: rpl code  ;       (if any)
*
*  All directory entries must be in the same file
*  All source in the file will be part of the same directory.
**************************************************************
ASSEMBLE
Dir  MACRO
  IFNDEF   $dir$st
    CON(5) =DORRP
    CON(3) #7FF        * Number of attached libraries
    REL(5) $dir$st       * Offset to last directory entry
    CON(5) 0        * constant 00000
  ELSE
    CON(5) (*)-$dir$st  * size of the previous entry
  ENDIF
$dir$st = *               * used by next call to macro
    CON(2)  (($dir$nm$0)-2-(*))/2
    NIBASC  "$1"
$dir$nm$0 = *           * must be unique because of fwd reference
    CON(2)  ((*)-2-$dir$st)/2
=$1 EQU     *           * make entry in symbol table
  ENDM
RPL

Note that the order of objects in the compiled directory object this creates is the opposite of the ordering in the source. So in this case, the above source file example creates a directory with two objects in it, test2 and test (in that order).

Hope this helps!
- David
(06-13-2019 05:13 AM)cyrille de brébisson Wrote: [ -> ]Anyhow, the MASD syntax also encourages you to use a "." as a separator between an instruction and a field. It does make the code more readable as it visually links the 2 and separates one instruction from the next...
It is also better when programming ON the calc where the . is a single key while the space is shifted...

MASD definitely rocks !!!!

gj Cyrille, this great and clever syntax is burned into my memory for ever as very great coding experience !
Thank you Cyrille and David for the further information.

As mentioned before I'm a novice ASM programmer but find it very interesting so will try to keep at it.

Jeff
Hello,

Have you read the doc on the build in development library?
Not all of it is applicable to debug4x, but a LOT of it is...

https://www.hpcalc.org/details/2986

Cyrille
Thanks Cyrille, just downloaded the Machine Language Compiler in PDF

Also thanks to the all the help given here I have found a way to compile ASM on debug4x.

On the debug4x Project Data tab I unchecked 'The Project is a Library'

Typing the code below in a source file and press build puts a compiled program on the stack.

I then press EVAL and the object on the stack (a bint just for testing) drops

Not much I know but its a start. At least I can try things out while learning.

Jeff



::

BINT2

CODEM

C=DAT1.A
?C#0.A ->{
D1=D1+5
D=D+1.A
}
GOVLNG =LOOP

ENDCODE

;
(06-17-2019 12:11 PM)JeffB Wrote: [ -> ]On the debug4x Project Data tab I unchecked 'The Project is a Library'

Typing the code below in a source file and press build puts a compiled program on the stack.

I then press EVAL...

You're off to a good start!

Just a hint: putting an object name in the "Path" field shown on the "Project Data" tab will cause the program to be stored in a global variable with the given name. That's usually more convenient than having to manually store the object yourself, and it also enables you to run the program with varying inputs as needed without having to compile it again.

Have fun with Saturn coding! It's challenging, but also very rewarding. That "warm fuzzy" feeling you get when a program works the way you intended is grown by at least an order of magnitude when you get Saturn code working the way it should. Smile
Hi David

I did what you said and yes the object name was put in the HOME dir and ready to simply press on the emulator menu

Much more straightforward. Thanks you for this and your encouraging comments.

Jeff
Reference URL's