1. Introduction
I got another HP 50g calculator. I heard it has an assembler install on the calculator, and it is much fun to program with Reverse Polish Lisp.
Indeed it is fun to play with RPL, but it is a burden to plan ahead the program, with the familiarity of HP 50g's library and the aid of pen and paper it might be easier. To help some new comers who already have plenty of programming experience in Forth and Assembly this article try to provide some quick-start example.
2. User RPL
2.1. Overview of User RPL
Traditionally Forth uses a separated data stack to handle local
variables, while RPL only has one stack. Thus RPL has added the
arrow (→
) notation to declare local variables. In fact
the notion is similar to the lambda notation in functional
programming languages. The language itself is a bit slow compared
to the System RPL that will be introduced later, however it is
still a powerful language mixing concepts from Forth Lisp,
BASIC.
2.2. Higher order non-homogeneous differential equation
The original program was from TI BASIC. To be honest (or biased), the CAS of 50g is a bit inferior than Voyage 200.
The idea of algorithm is well known from any differential equation textbook.
This function produces the Wronskian from an input vector of independent terms from a homogeneous solution.
|« DUP SIZE 1 GET → a s
|« a 1 s 1 -
|START a DERVX DUP 'a' STO AUGMENT
|NEXT
5 |»
|»
You can check the matrix determinant of the Wronskian for a test of existence of solutions.
Then, with the Wronskian as coefficient of the system and the right hand side of the homogeneous equation as inputs, this function produces the coefficient for the particular solution.
|« 0 → f S
|« DUP SIZE 1 GET 'S' STO S 1 - 1 SWAP
|START 0 NEXT
|NEXT f S →ARRY
5 |SWAP / SIMPLIFY INTVX SIMPLIFY
|»
|»
The builtin LDEC
can be used for
solve non-homogeneous LDEs but the result is complicated because of
the method it uses.
2.3. Use inverse Laplace to solve initial value problem
The program below generates equation for the left hand side a linear differential equation of numeric coefficients, taking the list of coefficients from higher power to lower and initial values of the form .
|« → c s
|« 'F' 1 s SIZE
|FOR i
|'X^n' 'n' i 0 1 NEG SEQ
5 |{ 'F' } s 0 i SUB NEG + * ΣLIST
|NEXT
|c SIZE →LIST REVLIST c * ΣLIST
|»
|»
The second part solves the equation by applying inverse Laplace.
|« SOLVE EQ→ SWAP DROP ILAP»
3. Saturn assembly language
3.1. Overview of Saturn assembly
At the first glance Saturn does not even look like assembly languages we would typically see today. It is more like so called "structured programming language". Well, there are examples from structured low level programming languages like PL/360. And although feels like 16bit computers, the registers are actually 64bits with BCD arithmetic support!
The HP50g ROM is running on the Saturn processor emulated on top of the ARM chip, so even the assembler supports embedding ARM assembly, interfacing the calculator stack is still done via Saturn machine language.1
3.2. Control the buzzer
It is surprising that HP50g is with a speaker that is capable of
producing complex sound. The BEEP
command accept the
first integer as the frequency in Hz and second float number as
time in second.
In this section we will use the source file from qmc program on hpcalc.org as an example to demonstrate how to control the buzzer from Saturn Assembly.
Entering the above program into a string, push to the stack, and
call ASM
from library 256
. Store the result to a variable then you may
recall the program from soft menu.
Unfortunately, the buzzer cannot be emulated by the ARM based calculators like 50g.
4. System RPL
4.1. Overview of SysRPL
Actually there is no fundamental difference between User System RPL as every User RPL is tokenized to a subset of System RPL after editing2. It is just that System RPL can access more internal features and does lesser safety checking, so it is not available to user by default to avoid causing damage to data.
As I have mentioned, System RPL is still running on top of the Saturn emulation layer for ARM based HP49 calculators, and a System RPL program is directly assembled to series of Saturn instructions.
4.2. More buzzer
This simple program makes 4 beeps of different pitches.
|::
|1200 440 1300 550 1000 470 1300 750
|4 #1+_ONE_DO setbeep LOOP
|;
4.3. Programming using PC
There is a set of tool chain that allows user to create System RPL/Saturn Assembly program and libraries on desktop computers. Unfortunately, ARM Assembly is not supported by this method.
This time we will create a bit more complex buzzer program with HPTools.
|muse ( $ -> )
This program will convert each character in a string to a pitch and play it.
|* Synth some music ( $ --> )
|ASSEMBLE
|NIBASC /HPHP49-C/
|RPL
5 |::
|CK1NOLASTWD
|CK&DISPATCH0 str
|::
|DUPLEN$ #1+_ONE_DO (DO)
10 |DUP INDEX@ SUB$1# 48 #-
|* n^(2/12)
|UNCOERCE %2 SWAP %^ %12 %1/ %^
|130E0 %* COERCE
|500 SWAP setbeep
15 |LOOP
|DROP
|;
|;
The string HPHP49-C
specify the ROM
version of the target. In fact the final output produced by
sload
is a bare binary, that is a file
only contains the machine code without any linking/loading
format.
To compile this file to a standalone program, this example Makefile can be used:
|all: muse
|%.a: %.s
|rplcomp $< $@
|%.o: %.a
5 |sasm $<
|muse: muse.o
|sload -H muse.m
Where the content of loader instruction muse.m
is:
|TITLE Muse
|OUTPUT muse
|LLIST muse.lr
|SUPPRESS XREF
5 |SEARCH SUPROM49.o
|REL muse.o
|END
The SUPROM49.o
is the entry table
list created by running sasm
assembler
on the corresponding SUPROM49.a
.
4.3.1. Calling CAS functions
To handling ZINT objects, the functions provided by CAS in the
form of flashpointers and their names are prefixed by
^
, for example ^#>Z
. On MASD the
syntax for calling flashpointers is FPTR2 ^label
,
while RPLComp from HPTools uses a different syntax FLASHPTR
label
(note the ^
is omitted).
Do not call flashpointers directly, the assembler would not produce error message on such case but running such program would crash your calculator.
5. Miscellaneous
5.1. Step function in Laplace
It is common to have Laplace transform on step-wised functions.
Although it is not explicitly mentioned in the manual, and the
corresponding section from user manual is vague on that,
'Heaviside(X-1)*(X-1)' LAP
for example works well.