manual:chapter5:asm

This is an old revision of the document!


Sometimes managing a more than three or four values on the stack leads to an excessive use of stack manipulation commands (the so-called stackrobatics) resulting in convolute code.

In these cases a compact subset of instructions, with a different syntax and based on the manipulation of a small number of global registers, may achieve greater clarity; this subset of the language, given its compact format, is called Assembly-like Instruction Set.

The Assembly-like Instruction Set is not meant as a separate programming language neither its feature are intended to be sandboxed in exclusive environments: its statements can be freely intermingled with newRPL commands and to suit anyone's programming style.

The programming paradigm is based on the manipulation of a small number of registers and pseudo-registers which act as top-level global variables, accessible anywhere in the code. It must be stressed that registers and pseudo-registers are totally distinct from any local or global identifier that shares the same name.

  • There are 8 proper registers, named A through H, free for the users to assign any object to them. These registers are global and persistent;
  • also, there are 7 pseudo-registers that correspond to the 7 topmost stack levels, named S1 through S7; these pseudo-registers are not persistent and exist only if the corresponding stack level is occupied by an object. If the stack is empty, read or write operations on e.g. S1 will trigger a Stack index out of bounds error.
  • finally there are 2 additional pseudo-registers: P and R.
    • any value assigned to P is pushed immediately to the stack, thus P can be used only as a destination register, not as an argument.
    • R references to the object immediately following it in the runstream. R cannot be used as a destination.

WARNING: all of these instructions are present in the specification but some of them may not be implemented yet at the time of the writing of this document.

Assembly-like statements must always start with a colon : and must not have any spaces within. Wherever a separator is needed, use the dot ..

Instructions are divided in the following classes:

Assignment operators Math operators Math functions Flow control Data manipulation
= + IP CMP GET
+= - LN SKIP PUT
-= * EXP LOOP PUSH
*= / SQRT FPUSH RPUSH
/= ^ SIN POP
COS RPOP
TAN MIN
ASIN MAX
ACOS RND
ATAN
SINH
COSH
TANH
ASINH
ACOSH
ATANH
FP
ABS
ARG
RE
IM

Literals are integer constants from 0 to 15. They can optionally prefixed with a hash (#) or expressed in hexadecimal (#0H-#FH). In the latter case the leading # and trailing H are compulsory.

Statements are divided in two categories:

  • Assignments, which may have
    • an optional destination register (A-H, S1-S7 or P);
    • an optional assignment operator (=, +=, -=, *= or /=);
    • a math operator, a math function or a data manipulation command: operators are infix, functions and commands are prefix;
    • 1 or 2 arguments to the operator or function. Arguments can be either a (pseudo-)register (A-H, S1-S7), a reference (R) or a literal. The context makes clear if the arguments are to be interpreted as direct (e.g. register A) or indirect (e.g. the stack level referenced by register A).
  • Commands, which may be
    • a comparison command, followed by the two arguments to be compared;
    • a flow control command, followed by the condition to be tested;
    • a data manipulation command, followied by two arguments defining the extent of the manipulation;
    • arguments can be either a register (A-H, S1-S7), a reference (R) or a literal. The context makes clear if the arguments are to be interpreted as direct (e.g. register A) or indirect (e.g. the stack level referenced by register A).
:A=B+#1 Add 1 to the value of register B and assign the result to register A
:E=R { 1 2 3 } Assign the list { 1 2 3 } to register E
:P=A Push the value of register A to the stack
:A=S2 :S2=S1 :S1=A Swap stack level 1 with level 2 using register A as temporary storage. An error is raised if the stack contains less than 2 levels
:C+=B^#2 Square the value register B and adds the result to register C
:A+=ABS.S1 Add the absolute value of stack level 1 to the value of register A
:C*=SIN.A Compute the sine of register A and multiplies it with the content of register C
:D=ATANH.R 'e^2' Assign the hyperbolic arctangent of 'e^2' to register D
:CMP.A.#1 Compare register A and literal 1, setting internal flags accordingly

The CMP command is equivalent to the newRPL CMP operator and accepts the same type of arguments, but instead of returning a value representing the result of the comparison it merely sets two system flags: flag -58 if the two arguments are equal and flag -59 if the first argument is less than the second.

The following commands accept one argument expressing a test condition. the argument expresses mnemonically the state of flags -58 and -59, according to the following table.

Mnemonic Test condition Flag -58 (Zero) Flag -59 (Negative)
AL Always
LT Less Than Set
EQ Equals Set
LTE Less Than or Equals Set
Set
NA Never
GTE Greater Than or Equals Clear
NE Not Equals Clear
GT Greater Than Clear Clear

:SKIP.EQ Skip next instruction if the result of last comparison was Equals
:LOOP.LTE Must be followed by a program « … » or a secondary :: … ;. Repeat the object that follows while the result of the last comparison is Less Than or Equals. Notice the program or secondary that follows must update the internal flags with a :CMP.[Y].[Z] statement or it will loop indefintely
:FPUSH.GT Push True (1) to the stack if the result of the last comparison is Greater Than, otherwise push False (0)

The FPUSH command is useful to combine assembly-like statements into newRPL flow control structures. For example

« IF 
    :CMP.A.#0
    :FPUSH.EQ
  THEN
    ...
  END
»

These instructions allow manipulation of composite objects (lists, vectors and matrices) as well data retrieval or storage from and to the stack, therefore some of them are assignments and others are commands.

:A=GET.S2.#5 Retrieve the 5th element of the composite stored at stack level 2 and store it in register A
:C=PUT.#3.R 9 Store the object on the ninth level of stack at third position of the composite stored in register C. In other words C(3)=S9
:A=POP.S1.#3 Remove values from the stack (pop) from the given stack levels and store the values on registers A, B, C… starting with A, and as many values as needed. The example given will assign :A=S1, :B=S2 and :C=S3, while also removing the values from the stack.
:A=RPOP.S1.#3 Similar to :POP but the assignment is done in reverse order. In this example will do :A=S3, :B=S2, and :C=S1
:PUSH.A.#3 Reverse of :POP. In this example will do :P=C, :P=B and :P=A
:RPUSH.A.#3 Reverse of :RPOP. In this example will do :P=A, :P=B, and :P=C

The following programs show the Assembly-like Instruction Set features in action: they are meant to be didactic rather than clever.


  • Q2 is an almost line-per-line translation of the program presented in chapter 2 of the HP-42S Programming Examples and Techniques manual.
« @@ Q2: Solve aX^2+bX+c=0 where a≠0, c≠0
  -103 SF             @ Complex results
  :A=RPOP.S1.#3       @ Store coefficients in registers
  :CMP.A.#0 :FPUSH.EQ @ a=0? Push test on the stack
  :CMP.C.#0 :FPUSH.EQ @ c=0? Push test on the stack
  OR                  @ Are either zero?
  :CMP.S1.#1 DROP     @ Turn newRPL boolean into flags and discard it
  :SKIP.NE            @ Skip next seco if false
  :: "Zero Input Invalid"
     DOERR            @ Abort with error
  ;
  :P=#0-B             @ Push -B on stack
  DUP SQ              @ -B, B^2
  4 :S1*=A :S1*=C     @ -B, B^2, 4*A*C
  - √                 @ -B, √(B^2-4*A*C)
  :P=B SIGN * -       @ -B-SIGN(B)*√(B^2-4*A*C)
  2 / :S1/=A          @ (-B-SIGN(B)*√(B^2-4*A*C))/2/A is R1, the largest root in absolute value
  :P=C :S1/=A         @ R1, C/A
  :S1/=S2             @ C/(R1*A) is R2, the other root
»

  • STRAIGHT computes the equation of the straight line passing through the points p1=(x1,y1) and p2=(x2,y2).
« @@ STRAIGHT: compute aX+bY+c passing through p1 and p2
  → p1 p2         @ Get the two points
  « p1 C→R        @ Split the first
    p2 C→R        @ Split the second
    :C=RPOP.S1.#4 @ Store x1, y1, x2 and y2 in C, D, E and F registers
    :A=R 'X'      @ Registers can store anything
    :B=R 'Y'      @ if 'R' pseudo-register is used
    :B-=D         @ B='Y-y1'
    :A-=C         @ A='X-x1'
    :F-=D         @ F=y2-y1
    :E-=C         @ E=x2-x1
    :B*=E         @ B='(Y-y1)*(x2-x1)'
    :F*=A         @ F='(y2-y1)*(X-x1)'
    :B-=F         @ B='(Y-y1)*(x2-x1)-(y2-y1)*(X-x1)'
    :PUSH.B.#1    @ Push result on the stack
  »
»
  • manual/chapter5/asm.1574900977.txt.gz
  • Last modified: 2019/11/27 16:29
  • by jojo1973