A few M-Code Routines for the HP-41
Overview
1°) Introduction
a) A few M-Code Instructions
b) Relative Jumps
c) Absolute Jumps
d) Useful Subroutines
e) 13-digit routines
2°) Constants
a) MAXR
b) Euler's Constant
3°) Stack Operations
a) Y<>Z
b) Y<>T
c) Z<>T
d) ST<>A
e) DUP
4°) 14 Functions
a) X+1 & X-1
b) X/2
c) Rounding to the nearest
integer
d) FLOOR & FRC2
e) Cube
f) Cube Root
g) Y^X ( producing 0^0=1 )
h) XROOT
i) CNK
j) Degree of a Polynomial
k) X/E3 & X*E3
5°) Random Number Generator ( Time Module required )
6°) 3D-Vectors
a) Norm
b) Dot Product
c) Cross Product
7°) Statistics
a) Linear Regression
b) Recalling the Statistics
Registers
8°) 3 Tests
a) X=1?
b) X=N?
c) X#Y??
9°) Hyperbolic Functions ( Sine, Cosine, Tangent and their Inverses )
10°) 5 Complex Functions
a) Z*Z & Z/Z
b) Z^2
c) 1/Z
d) SQRTZ
11°) Creating Extra-Registers
a) Saving & Recalling X-Register
b) Saving & Recalling all the
Stack
12°) Largest Element of a Block of Registers
Many of the following routines are elementary, but I hope they will be useful for beginners.
If your HP-41 "crashes", press and hold the ENTER^ key and press
the ON key: this will stop infinite loops on "newer" HP-41s.
Otherwise, you'll have to remove the batteries for a while.
1°) Introduction
a) A few M-Code Instructions
-The CPU ( Central Pocessing Unit ) uses several registers.
-For mathematical purposes, the most important ones are C A B M N
( CPU-registers M , N are not the "synthetic" registers M
, N )
-These 5 registers have 56 bits divided in 14 digits as shown below.
13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
MS | -------------------------- Mantissa ------------------------- |---S&X-- |
MS = Mantissa Sign
S&X = Sign of exponent & eXponent: Sign = digit 2
& exponent = digits 1-0
For example,
3.141592654
1071 is coded 0 3 1 4
1 5 9 2 6 5 4 0 7
1 MS = 0 for a positive
number
-3.141592654 1071
is coded 9 3 1 4 1 5 9
2 6 5 4 0 7 1
MS = 9 for a negative number
3.141592654
10 -71 is coded 0 3 1 4
1 5 9 2 6 5 4 9 2
9 S&X = 1000 - | exponent |
for a negative exponent
-3.141592654 10
-71 is coded 9 3 1 4 1
5 9 2 6 5 4 9 2 9
929 = 1000 - 71
-I cannot list all the M-code instructions, but here are a few ones ( see reference [1] for a more complete list )
2DC PT= 13 sets pointer to digit 13
35C PT= 12 sets pointer to digit 12
21C PT= 2 sets pointer to digit 2
010 LD@PT- 0 loads C-register digit at pointer
with 0 and decrements pointer
050 LD@PT- 1 loads C-register digit at pointer
with 1 and decrements pointer
090 LD@PT- 2 loads C-register digit at pointer
with 2 and decrements pointer
0D0 LD@PT- 3 loads C-register digit at pointer with
3 and decrements pointer
110 LD@PT- 4 loads C-register digit at pointer with
4 and decrements pointer
150 LD@PT- 5 loads C-register digit at pointer with
5 and decrements pointer
190 LD@PT- 6 loads C-register digit at pointer with
6 and decrements pointer
1D0 LD@PT- 7 loads C-register digit at pointer with 7
and decrements pointer
210 LD@PT- 8 loads C-register digit at pointer with
8 and decrements pointer
250 LD@PT- 9 loads C-register digit at pointer with
9 and decrements pointer
130 LDI S&X loads the word in the next address into the S&X field of C-register.
-For instance, the 2 words 130 LDI S&X load
the exponent 41 in C
041 041
-If you want to load 12000 in register C:
04E C=0 ALL ( see below )
35C PT=12
050 LD@PT- 1
090 LD@PT- 2
130 LDI S&X
004 004
04E C=0 ALL clears register C
10E A=C ALL copies C-register to A-register
0AE A<>C ALL exchanges A & C registers
06E A<>B ALL ---------- A & B --------
0EE C<>B ALL ---------- C & B --------
198 C=M ALL copies M-register to C-register
158 M=C ALL ------ C----------- M--------
1D8 C<>M ALL exchanges C & M registers
0B0 C=N ALL copies N-register to C-register
070 M=C ALL ------ C----------- N-------
0F0 C<>M ALL exchanges C & N registers
-The most important register is register C: this is the only one that can exchange data with user memory.
028 WRIT 0(T) writes register C into stack
register T if the RAM pointer is in the status register -
this is always the default
068 WRIT 1(Z) writes register C into stack
register Z if .... etc ...
0A8 WRIT 2(Y) ... and so on ...
0E8 WRIT 3(X)
128 WRIT 4(L)
168 WRIT 5(M) here, M = synthetic register M
1A8 WRIT 6(N) here, N = synthetic register N
1E8 WRIT 7(O)
228 WRIT 8(P)
268 WRIT 9(Q)
-Though it's not rigorous, I often write these instructions T=C , Z=C , Y=C ... etc ...
078 READ 1(Z) reads C into Z-register if
the RAM pointer is in the status register - this is always the default
0B8 READ 2(Y) reads C into Y---------- ...
0F8 READ 3(X) ... and so on ...
138 READ 4(L)
178 READ 5(M)
1B8 READ 6(N)
1F8 READ 7(O)
238 READ 8(P)
278 READ 9(Q) (
I often write these instructions C=Z , C=Y ...etc... )
-Note that there is no READ 0(T) instruction. If you want to copy T into C, use the 3 words
046 C=0 S&X
places the RAM pointer
270 RAM SLCT
in the required area.
038 READ DATA
2F0 WRIT DATA
works in the same way ( see reference [1] to access to data
registers R00 , R01 , ..... )
-The CPU uses a special flag - the carry flag - which is set when there
is an overflow or an underflow or when a special instruction sets it.
It is cleared by any instruction that doesn't set it.
-The CPU also uses 14 flags ( numbered 0 to 13 ). All these flags are
different from the user flags.
-Here are a few instructions:
044 CLRF 4 clears flag 4
048 SETF 4 sets flag 4
04C ?FSET 4 sets the carry flag if flag
4 is set
084 CLRF 5 clears flag 5
088 SETF 5 sets flag 5
08C ?FSET 5 sets the carry flag if flag
5 is set
144 CLRF 6 clears flag 6
148 SETF 6 sets flag 6
14C ?FSET 6 sets the carry flag if flag
6 is set
284 CLRF 7 clears flag 7
288 SETF 7 sets flag 7
28C ?FSET 7 sets the carry flag if flag
7 is set
104 CLRF 8 clears flag 8
108 SETF 8 sets flag 8
10C ?FSET 8 sets the carry flag if flag
8 is set
-The CPU can work in 2 different modes: hexadecimal ( this is the default ) and decimal:
260 SETHEX
2A0 SETDEC
-The end of M-code routines - or subroutines - is usually:
3E0 RTN
360 ?C RTN return if carry
3A0 ?NC RTN return if not carry
>>> There is an exception because the CPU return-stack
only has 4 subroutine-levels
and if you have
used these 4 levels, 3E0 RTN must be replaced by
3C1 ?NCGO
002 00F0
Otherwise ( with 3E0 RTN instead ), the
display would freeze.
But it's not really a "crash": the HP-41 still responds to any
keystroke.
-Among many other instructions, the 2 following ones are useful too:
160 ?LOWBAT which set the carry flag when
the batterry is low
3CC ?KEY
----------------------------- a key is pressed
b) Relative Jumps (
X-Functions Module Required )
-There are 4 types of relative jumps:
JNC +nn jumps nn instrunctions forward if carry clear
00 < nn < 64d
JC +nn jumps nn instrunctions forward if
carry set 00 < nn < 64d
JNC -nn jumps nn instructions backwards if carry clear
00 < nn < 65d
JC -nn jumps nn instructions backwards
if carry set 00 < nn < 65d
-"RJUM" returns the code that corresponds to all possible relative jumps.
Formulae:
JNC+nn = 8 n + 3
JNC-nn = 1027 - 8 n
JC+nn = 8 n + 7
JC-nn = 1031 - 8 n
-These results are finally converted to hexadecimal numbers.
-XTOA is used.
Data Registers: /
Flag: F01
CF 01 for jump if not carry
SF 01 for jump if carry
Subroutines: /
-The append character is denoted "~"
01 LBL "RJUM" 02 INT 03 X=0? 04 LN 05 64 06 CHS 07 X<>Y 08 X<Y? 09 SF 99 10 63 11 X<>Y 12 X>Y? 13 SF 99 14 10 15 X<>Y 16 " J" |
17 FC? 01 18 "~N" 19 "~C" 20 X>0? 21 "~+" 22 X<0? 23 "~-" 24 ABS 25 X<Y? 26 "~0" 27 FIX 0 28 CF 29 29 ARCL X 30 "~=" 31 LASTX 32 8 |
33 * 34 3 35 X<>Y 36 X<0? 37 1027 38 + 39 4 40 FC? 01 41 CLX 42 + 43 STO Y 44 16 45 ST/ Z 46 MOD 47 X<>Y 48 INT |
49 RCL X 50 16 51 ST/ Z 52 MOD 53 X<>Y 54 INT 55 ARCL X 56 2 57 R^ 58 R^ 59 LBL 00 60 10 61 X>Y? 62 GTO 00 63 CLX 64 55 |
65 + 66 XTOA 67 GTO 01 68 LBL 00 69 RDN 70 ARCL X 71 LBL 01 72 X<>Y 73 DSE Z 74 GTO 00 75 FIX 4 76 SF 29 77 AVIEW 78 END |
( 131 bytes / SIZE 000 )
STACK | INPUT | OUTPUT |
X | +/-nn | / |
The alpha register is displayed at the end ---Execution time = 3seconds---
Examples:
• CF 01 "JUMP IF NOT CARRY"
4 XEQ "RJUM" >>>>
JNC+04=023
61 R/S
>>>> JNC+61=1EB
63 R/S
>>>> JNC+63=1FB
-4 R/S
>>>> JNC-04=3E3
-61 R/S
>>>> JNC-61=21B
-64 R/S
>>>> JNC-64=203
• SF 01 "JUMP IF CARRY"
4 XEQ "RJUM" >>>>
JC+04=027
61 R/S
>>>> JC+61=1EF
63 R/S
>>>> JC+63=1FF
-4 R/S
>>>> JC-04=3E7
-61 R/S
>>>> JC-61=21F
-64 R/S
>>>> JC-64=207
Notes:
-If you key in 0 XEQ "RJUM" you'll get
"DATA ERROR" ( line 04 )
-If you key in +nn XEQ "RJUM" with n > 63, you'll
get "NONEXISTENT" ( line 13 )
-If you key in -nn XEQ "RJUM" with -n < -64, you'll get
"NONEXISTENT" ( line 09 )
Warning:
-The n-values = the jump distances, must be expressed in decimal
-If - for instance - you want to code JNC+25 hexadecimal, first convert
25h to 2 x 16 + 5 = 37 decimal
and then: CF 01 37 XEQ "RJUM" yields
JNC+37=12B
-Contrariwise, the returned code is always an hexadecimal word.
c) Absolute Jumps
-There are 4 types of absolute jumps:
?NCXQ if not carry execute
?CXQ if carry execute
?NCGO if not carry go to
?CGO if carry go to
-Each absolute jump requires 2 words.
-The following program displays the required words for a given jump.
-This routine is only a slight modification of a program listed in the
"Hepax Module Owner's Manual"
Data Register: R00 : temp
Flags: /
Subroutines: /
-The append character is denoted ~
-To load lines 20-21 key in XEQ "HEPAX" you get
HEPAX _ _ _ and press 003 or C ... etc
...
01 LBL "JUMP" 02 INT 03 4 04 MOD 05 STO 00 06 "?NCXQ" 07 X#0? 08 "?CXQ" 09 DSE X 10 "?NCGO" 11 DSE X |
12 "?CGO" 13 "~ " 14 4 15 HPROMPT 16 4 17 DECODYX 18 "~=" 19 1 20 HEPAX 21 3 22 X<>Y |
23 -2 24 HEPAX 25 11 26 HEPAX 27 9 28 1023 29 HEPAX 30 3 31 X<>Y 32 HEPAX 33 1 |
34 LASTX 35 X<>Y 36 3 37 DECODYX 38 "~ " 39 RDN 40 10 41 HEPAX 42 11 43 -2 44 HEPAX |
45 11 46 RCL 00 47 HEPAX 48 3 49 HEPAX 50 9 51 3 52 DECODYX 53 AVIEW 54 CLST 55 END |
( 115 bytes / SIZE 001 )
STACK | INPUT | OUTPUT |
X | k | 0 |
where
k = 0 for ?NCXQ
k = 1 for ?CXQ
k = 2 for ?NCGO
k = 3 for ?CGO
Example: You have to code ?NCXQ
F123
0 XEQ "JUMP" the HP-41 displays ?NCXQ _ _ _ _ key in F 1 2 3
and a few seconds later, you
read: ?NCXQ F123 = 08D 3C4
so the answer is
08D ?NCXQ
3C4 F123
-Likewise 3 R/S gives ?CGO _ _ _ _ and if you press 0 0 D A you'll get ?CGO 00DA = 369 003 meaning:
369 ?CGO
003 00DA
Notes:
-"HPROMPT" "DECODYX" "HEPAX" are functions of an HEPAX Module.
-If you don't have an Hepax Module, use for instance Warren Furlow's excellent
V41 Emulator.
-There are also "port dependent jumps" but they will be omitted here.
d) Useful Subroutines
Cheks:
361 ?NCXQ
checks register C for alpha data
050 14D8
and sets the CPU in decimal mode
355 ?NCXQ
checks registers A and C for alpha data, executes A<>C
( more exactly it checks C then executes A<>C and checks C )
050 14D5
and executes SETDEC
Stack Operations:
3B5 ?NCXQ
executes a R^
050 14ED
( roll up )
3A5 ?NCXQ
executes a RDN
050 14E9
( roll down )
345 ?NCXQ
executes synthetic
registers
040 10D1
CLA
M N O P are cleared
Mathematics: the
CPU must be in Decimal mode
-Most of the maths subroutines can deal with numbers as great as 10200
01D ?NCXQ
replaces C by
060 1807
A+C
135 ?NCXQ
replaces C by
060 184D
A*C
2F9 ?NCXQ replaces
C by this subroutines cheks
if C<0
060 18BE
sqrt(C)
and displays DATA ERROR in this case
22D ?NCXQ replaces C by
this subroutines cheks if C=0
060 188B
1/C
and displays DATA ERROR in this case
261 ?NCXQ replaces C by
this subroutines cheks if C=0
060 1898
A/C
and displays DATA ERROR in this case
3C4 ST=0
replaces C
045 ?NCXQ
by
provided X = C
06C 1B11
Y^C
3B1 ?NCXQ replaces C
DATA ERROR is displayed if C < 0 or if C is not an integer
060 18EC
by fact(C)
the result can be used if C < 100
Note: the 7 subroutines above do not alter CPU-register
N
044 CLRF 4
029 ?NCXQ replaces C by
068 1A0A
exp(C)
048 SETF 4
029 ?NCXQ replaces C by
( actually the same subroutine )
068 1A0A
exp(C)-1
084 CLRF 5
1CD ?NCXQ replaces C by
06C 1B73
Ln1+C
088 SETF 5
1CD ?NCXQ replaces C by
( actually the same subroutine )
06C 1B73
Log1+C
003 CLRF 3
084 CLRF 5
115 ?NCXQ replaces C by
06C 1B45
Ln(C)
003 CLRF 3
088 SETF 5
115 ?NCXQ replaces C by
( the same subroutine )
06C 1B45
Log(C)
044 CLRF 4 replaces
070 N=C ALL
C
3E1 ?NCXQ
by
06C 1BF8
10^C
084 CLRF 5 replaces
C
0ED ?NCXQ
by
064 193B
frc(C)
088 SETF 5 replaces
C
0ED ?NCXQ
by
( the same subroutine )
064 193B
Int(C)
-Simply use 2BE C=-C-1 MS to change the sign of C
( but this instruction usually sets the carry flag )
and
05E C=0 MS to replace C by
its magnitude
044 CLRF 4
070 N=C ALL replaces C by
171 ?NCXQ
A mod C
( positive arguments )
064 195C
-For negative arguments, however, this will not work properly if
X is different from C
-So, in this case, add 0E8 WRIT 3(X) before ?NCXQ
195C
0E8 WRIT 3(X)
044 CLRF 4
070 N=C ALL replaces C by
171 ?NCXQ
A mod C
( all arguments )
064 195C
231 ?NCXQ replaces
C by
it performs
064 198C
180.C/(pi)
R-D
070 N=C
replaces C
205 ?NCXQ
by
D-R
064 1981
(pi).C/180
070 N=C
replaces C
265 ?NCXQ
by
044 1199
HMS(C)
070 N=C
replaces C
24D ?NCXQ
by
044 1193
HR(C)
-The following lines rounds X ( not C ) to its nearest integer and places
the result in C ( not X )
-However, the CPU is then set in hexadecimal mode.
-So, add 2A0 SETDEC after these lines if you have to
make other calculations...
130 LDI S&X
080 080
0C5 ?NCXQ
028 0A31
-The 6 following subroutines perform trigonometric functions in the current angular mode.
070 N=C
replaces C
221 ?NCXQ
by
048 1288
sin(C)
070 N=C
replaces C
261 ?NCXQ
by
040 1098
asin(C)
070 N=C
replaces C
1F1 ?NCXQ
by
048 127C
cos(C)
070 N=C
replaces C
1F5 ?NCXQ
by
040 107D
acos(C)
070 N=C
replaces C
209 ?NCXQ
by
048 1282
tan(C)
070 N=C
replaces C
2A9 ?NCXQ
by
040 10AA
atan(C)
Statistics:
the CPU must be in Decimal mode
041 ?NCXQ
calculates the sample standard deviation sx in C
moreover, this subroutine checks the statistics registers
074 1D10
and the sample standard deviation sy in N
and checks for alpha data.
3F9 ?NCXQ
calculates the mean µx in C
it also checks the statistics registers
070 1CFE
and the mean µy in N
and checks for alpha data.
084 CLRF 5
replaces
35C PT=12
C by sx
04D ?NCXQ
and
without checking the statistics registers
074 1D13
N by sy
35C PT=12
replaces C by µx
001 ?NCXQ
and
without checking the statistics registers
074 1D00
N by µy
-The 5 following subroutines recall the statistics registers in C, but
the RAM pointer remains in the stat registers area.
-So, if - for instance - you want to copy the result in register X,
add
10E A=C ALL
046 C=0 S&X
these 2 lines set the RAM pointer
270 RAM SLCT
in the status registers area
0AE A<>C
0E8 WRIT 3(X)
after these instructions.
35C PT=12
3BD ?NCXQ places
Sum x in C
070 1CEF
19C PT=11
3BD ?NCXQ places
Sum x^2 in C
070 1CEF
0DC PT=10
3BD ?NCXQ places
Sum y in C
070 1CEF
25C PT= 9
3BD ?NCXQ places
Sum y^2 in C
070 1CEF
11C PT= 8
3BD ?NCXQ places
Sum x.y in C
070 1CEF
29C PT= 7
3BD ?NCXQ places
n ( number of data points ) in C
070 1CEF
Overflow & underflow:
331 ?NCGO
takes an argument in C if there is an underflow,
X is saved in L-register and 0 is placed in X-register
002 00CC
if there is an overflow, it works according to user flag F24
369 ?NCGO
checks for overflow/underflow,
002 00DA
saves X in L-register , copies C in X , Z in Y , T in Z
e) 13-digit Routines
( cf reference [3] )
-In fact, almost all the routines return 10-digit results in CPU register
C and 13-digit results in CPU registers A & B:
-Register A contains the sign & exponent and register B contains the
13-digit mantissa.
-The result in A & B may be used directly to perform several operations,
for example:
001 ?NCXQ calculates
( with the 13-digit result in A & B
060 1800
AB+1
and the 10-digit result in C )
009 ?NCXQ C=
we could also write
060 1802
AB-1
AB=AB-1
239 ?NCXQ C=
060 188E
1/AB
044 CLRF 4 C
035 ?NCXQ =
068 1A0D exp(AB)
048 SETF 4 C
035 ?NCXQ =
068 1A0D exp(AB)-1
003 CLRF 3
084 SETF 5
C
121 ?NCXQ =
06C 1B48
ln(AB)
305 ?NCXQ C=
060 18C1
sqrt(AB)
-Like 2F9 060 ( 10-digit sqrt ), this last routine must be
used with care: it correctly places 0 in C but incorrectly 0000000000001
in B ( like E-12 )
-So if the argument may be equal to zero and if it is not the last operation,
these words should be followed by
2EE ?C#0 ALL
017 JC+02
02E B=0 ALL
-Simply adding 10E A=C ALL is a correct alternative but we would lose the 13-digit precision.
-The following subroutines takes a 13-digit result in A & B and a 10-digit argument in C:
025 ?NCXQ C=
060 1809 AB+C
13D ?NCXQ C=
060 184F AB*C
269 ?NCXQ C=
060 189A AB/C
-Several routines are available to store and recall the 13-digit results:
089 ?NCXQ AB
stores A & B in synthetic register Q
064 1922 STO Q+
and in the scratch part of the "append" register ( denoted + here )
0D1 ?NCXQ RCL
recalls Q+ in CPU registers C ( 13-digit mantissa )
064 1934 Q+
and M ( sign & exponent )
-If data registers are "ramselected", we must first execute 0 RAMSELECT
before storing in or recalling from Q+
-This is done directly by
081 ?NCXQ 0 ramslct
064 1920 AB
STO Q+
0C9 ?NCXQ 0 ramslct
064 1932
RCL Q+
-And exchanging A & B with Q+ is performed by:
0A9 ?NCXQ
064 192A AB<>Q+
-Finally, the following routines perform operations with two 13-digit arguments, the first one in A & B, the second one in C & M
031 ?NCXQ C=
060 180C AB+CM
149 ?NCXQ C=
060 1852 AB*CM
275 ?NCXQ C=
060 189D AB/CM
-See reference [3] for detailed examples.
Note:
-It's sometimes useful to transform the 10-digit number in register C into
a 13-digit number in A & B
-This may be done by the 3 words:
02E B=0 ALL
0FA B<>C M
0AE A<>C ALL
2°) Constants
-Constants may of course be stored into X-register by standard means.
-However, digit entry lines are very slow and they alter synthetic register
Q.
a) MAXR
-This routine executes a ROLL UP - unless the RPN stack lift is disabled
- and places 9.999999999 E99 in register X.
( the functions that disable stack lift are CLX ENTER^
SIGMA+ SIGMA- )
-CPU flag 11 is set when the RPN stack lift is enabled, so R^ is executed
in this case only.
-If you want to execute R^ in all cases, replace
18C ?FSET 11 by
3B5 ?NCXQ
3B5 ?CXQ
050 14ED
051 14ED
-If you want to overwrite the previous content of register X, key in neither
18C 3B5 051 nor 3B5
050
092 "R"
"R" is coded 012h but we must always add 80h for
the last character of a M-code routine.
018 "X"
001 "A"
A function name or a ROM name is always written in reverse order.
00D "M"
18C ?FSET 11
if CPU flag 11 is set,
3B5 ?CXQ
we execute
051 14ED
R^
2A0 SETDEC
04E C=0 ALL
27A C=C-1 M
130 LDI S&X
099 099
0E8 WRIT 3(X)
3E0 RTN
b) Euler's Constant
-"GAMMA" executes a ROLL UP - unless the RPN stack lift is disabled - and
places 0.5772156649 in X-register.
081 "A"
00D "M"
00D "M"
001 "A"
007 "G"
18C ?FSET 11
3B5 ?CXQ
051 14ED
04E C=0 ALL
35C PT=12
150 LD@PT- 5
1D0 LD@PT- 7
1D0 LD@PT- 7
090 LD@PT- 2
050 LD@PT- 1
150 LD@PT- 5
190 LD@PT- 6
190 LD@PT- 6
110 LD@PT- 4
250 LD@PT- 9
2A0 SETDEC
266 C=C-1 S&X
0E8 WRIT 3(X)
3E0 RTN
3°) Stack Operations
a) Y<>Z
-This routine swaps the contents of registers Y and Z
09A "Z"
03E ">"
03C "<"
019 "Y"
0B8 READ 2(Y)
10E A=C ALL
078 READ 1(Z)
0A8 WRIT 2(Y)
0AE A<>C ALL
068 WRIT 1(Z)
3E0 RTN
b) Y<>T
-Likewise, "Y<>T" swaps the contents of registers Y and T
094 "T"
03E ">"
03C "<"
019 "Y"
0B8 READ 2(Y)
10E A=C ALL
046 C=0 S&X
270 RAM SLCT
038 READ DATA
0A8 WRIT 2(Y)
0AE A<>C ALL
028 WRIT 0(T)
3E0 RTN
c) Z<>T
-And similarly, "Z<>T" exchanges the contents of registers Z and
T
094 "T"
03E ">"
03C "<"
01A "Z"
078 READ 1(Z)
10E A=C ALL
046 C=0 S&X
270 RAM SLCT
038 READ DATA
068 WRIT 1(Z)
0AE A<>C ALL
028 WRIT 0(T)
3E0 RTN
-You can create other routines like "L<>Y" , "L<>Z" ,
"L<>T" in the same way.
d) ST<>A
-"ST<>A" swaps the contents of the stack registers X , Y ,
Z with the "synthetic" registers M , N , O respectively.
-This routine may be used to compute the dot product and the cross product
below.
081 "A"
03E ">"
03C "<"
014 "T"
013 "S"
0F8 READ 3(X)
10E A=C ALL
178 READ 5(M)
0E8 WRIT 3(X)
0AE A<>C ALL
168 WRIT 5(M)
0B8 READ 2(Y)
10E A=C ALL
1B8 READ 6(N)
0A8 WRIT 2(Y)
0AE A<>C ALL
1A8 WRIT 6(N)
078 READ 1(Z)
10E A=C ALL
1F8 READ 7(O)
068 WRIT 1(Z)
0AE A<>C ALL
1E8 WRIT 7(O)
3E0 RTN
e) DUP
-This routine copies the content of register X in registers Y , Z , T
( like ENTER^ ENTER^ ENTER^ )
090 "P"
015 "U"
004 "D"
0F8 READ 3(X)
0A8 WRIT 2(Y)
068 WRIT 1(Z)
028 WRIT 0(T)
3E0 RTN
4°) 13 Functions
a) X+1 & X-1
-It is often useful to add ( or subtract ) one to register X
-If X contains an integer, this can be done by ISG X TEXT0
or DSE X TEXT0
-Otherwise, 1 + or 1 - work but the
stack is changed and synthetic register Q is altered
0B1 "1"
02B "+"
018 "X"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace this line ( SETDEC ) by the
2 words 361 ?NCXQ
00E A=0 ALL
A
050 14D8
35C PT=12
=
162 A=A+1 @PT 1
01D ?NCXQ
C=
060 1807
A+C
0E8 WRIT 3(X)
3E0 RTN
0B1 "1"
02D "-"
018 "X"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace this line by the 2 words
361 ?NCXQ
02E B=0 ALL
050 14D8
0FA B<>C M
0AE A<>C ALL
009 C=
060 AB-1
0E8 WRIT 3(X)
3E0 RTN
b) X/2
-You can use ST+ X to double the content of register X without
disturbing the stack or status register Q.
-Likewise, "X/2" divides the content of X-register by 2.
0B2 "2"
02F "/"
018 "X"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace this line by the 2 words
361 ?NCXQ
10E A=C ALL
050 14D8
04E C=0 ALL
C
35C PT=12
=
090 LD@PT- 2
2
261 ?NCXQ
C=
060 1898
A/C
0E8 WRIT 3(X)
3E0 RTN
c) Rounding to the nearest
integer
-"RND0" is equivalent to FIX 0 RND except
that the display setting is unchanged.
0B0 "0"
004 "D"
00E "N"
012 "R"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace this line by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
130 LDI S&X
080 080
0C5 ?NCXQ
028 0A31
0E8 WRIT 3(X)
3E0 RTN
d) FLOOR & FRC2
FLOOR(x) is the greatest integer less than or equal to x.
FLOOR(x) = INT(x) for positive arguments but not always for negative
x
FRC2(x) = x - FLOOR(x) FRC2(x) and
FRC(x) are usually different if x < 0
-These functions are useful for Calendar routines.
-FRC2 is a periodic function and is non-negative.
092 "R"
00F "O"
00F "O"
00C "L"
006 "F"
108 SETF 8
we use a CPU-flag ( here flag 8 ) to avoid calling FRC2 as a subroutine
033 JNC +06
0B2 "2"
003 "C"
012 "R"
006 "F"
104 CLRF 8
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
084 CLRF 5
C
0ED ?NCXQ
=
064 193B
frc(C)
2FE ?C#0 MS
033 JNC +06
00E A=0 ALL
A
35C PT=12
=
162 A=A+1 @PT
1
01D ?NCXQ
C=
060 1807
A+C
0E8 WRIT 3(X)
10C ?FSET 8
3A0 ?NC RTN
2BE C=-C-1 MS
C=-C
10E A=C ALL
138 READ 4(L)
01D ?NCXQ
C=
060 1807
A+C
0E8 WRIT 3(X)
3E0 RTN
-For instance,
-1.4 XEQ "FLOOR" gives
-2
-1.4 XEQ "FRC2"
gives 0.6
e) Cube
"X^3" saves x in L-register and calculates x3 without
disturbing registers Y Z T
It's faster than 3 Y^X
This routine doesn't check for overflow/underflow
0B3 "3"
01E "^"
018 "X"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
0F8 READ 3(X)
13D ?NCXQ
C=
060 184F
AB*C
0E8 WRIT 3(X)
3E0 RTN
f) Cube Root
-"CBRT" computes the cube root of a real number.
-Unlike 3 1/X Y^X , it works
for negative numbers too.
-Moreover, if n is an integer and if n3 doesn't
exceed 1010 , CBRT(n3) gives exactly
n.
012 "R"
002 "B"
003 "C"
0F8 READ 3(X)
2A0 SETDEC if you want to check for alpha data, replace SETDEC by the 2 words 361 ?NCXQ
128 WRIT 4(L) 050 14D8
2EE ?C#0 ALL
3A0 ?NC RTN
05E C=|C|
084 C
115 =
06C ln(C)
04E C
35C =
0D0 3
269 C=
060 AB/C
044 C
035 =
068 exp(AB)
10E A=C ALL
0F8 C=X
11E A=C MS
0AE A<>C ALL
0E8 X=C
3E0 RTN
-For example, -64 XEQ "CBRT" yields exactly
-4
g) Y^X
-The built-in function Y^X produces a DATA ERROR if X = Y = 0
-It's often preferable to get 0^0 = 1, for instance to compute Bessel's
functions.
098 "X"
01E "^"
019 "Y"
0F8 READ3(X)
10E A=C ALL
0B8 READ2(Y)
355 ?NCXQ
this subroutine checks A and C for alphadata
050 14D5
executes A<>C and SETDEC
128 WRIT4(L)
saves X in L-register
2EE ?C#0? ALL
027 JC+ 04
35C PT= 12
C =
050 LD@PT-1
1
023 JNC+04
3C4 ST=0
C
045 ?NCXQ
=
06C 1B11
Y^C
0E8 WRIT3(X)
078 READ1(Z)
0A8 WRIT2(Y)
046 C=0 S&X
270 RAMSLCT
038 READDATA
068 WRIT1(Z)
3E0 RTN
XEQ "Y^X" will work like the built-in function Y^X but it yields 00 = 1
-However, this M-Code routine does not check for overflows and underflows.
h) XROOT
-This function calculates the x-th root of y if y is non-negative.
-Otherwise, it computes sign(y) [abs(y)^(1/x)]
-So, it's not an orthodox XROOT !
-It will return correctly cube root ( -64 ) = -4 exactly
-But it will also give square root ( -9 ) = -3 !!!
-This function is actually a continuation of y^(1/x) by a symmetry with respect to the origine O.
-There is no check for alpha data or under/overflow.
094 "T"
00F "O"
00F "O"
012 "R"
018 "X"
2A0 SETDEC
0B8 C=Y
2EE ?C#0 ALL
05B JNC+11d
05E C=|C|
084 C
115 =
06C LN(C)
0F8 C=X
269 C=
060 AB/C
044 C
035 =
068 exp(AB)
10E A=C ALL
0B8 C=Y
11E A=C MS
0F8 C=X
128 L=C
0AE A<>C ALL
0E8 X=C
078 C=Z
0A8 Y=C
046 C
270 =
038 T
068 Z=C
3E0 RTN
-For instance, 32 CHS ENTER^ 5 XEQ "XROOT" gives -2
-X is saved in L-register.
-If Y= 0 , the final result will be 0 too !
-Of course, you can improve this routine to get DATA ERROR if y < 0
and x mod 1 # 0
i) CNK
-Since the suroutine 3B1 ?NCXQ calculates
fact(C) up to C = 99 , we can use it to calculate the binomial coefficients
Cnk = n!/[k!(n-k)!]
060 18EC
08B "K"
00E "N"
003 "C"
0F8 READ3(X)
10E A=C ALL
0B8 READ2(Y)
355 ?NCXQ
ckecks C and A for alpha data
050 14D5
and executes SETDEC
3B1 ?NCXQ
C=
060 18EC
fact(C)
070 N=C ALL
0F8 READ3(X)
2BE C=-C-1 MS
C=-C
10E A=C ALL
0B8 READ2(Y)
01D ?NCXQ
C=
060 1807
A+C
3B1 ?NCXQ
C=
060 18EC
fact(C)
10E A=C ALL
0B0 C=N ALL
135 ?NCXQ
C=
060 184D
A*C
070 N=C ALL
0B8 READ2(Y)
3B1 ?NCXQ
C=
060 18EC
fact(C)
10E A=C ALL
0B0 C=N ALL
261 ?NCXQ
C =
060 1898
A/C
369 ?NCGO
saves X in L-register, copies C in X
002 00DA
Z in Y , T in Z
-For example, 99 ENTER^
12 XEQ "CNK" yields 9.243705252 E14
-The results will be meaningless if n is a positive integer greater than
99
j) Degree of a Polynomial
-When performing multiplications of polynomials - whose control numbers
are bbb.eee - we often need the degree of these polynomials
( deg f = eee - bbb )
and the address of the next free register ( eee + 1 )
-"DEG F" takes bbb.eee in X-register and returns deg f in
X-register and eee+1 in L-register
086 "F"
020 " "
007 "G"
005 "E"
004 "D"
0F8 READ3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
088 SETF 5
C
050 14D8
0ED ?NCXQ
=
064 193B
int(C)
2BE C=-C-1 MS
C=-C
070 N=C ALL
0F8 READ3(X)
084 CLRF 5
C
0ED ?NCXQ
=
064 193B
frc(C)
226 C=C+1 S&X
C
226 C=C+1 S&X
=
226 C=C+1 S&X
1000 C
10E A=C ALL
0F0 C<>N ALL
01D ?NCXQ
C=
060 1807
A+C
0E8 WRIT3(X)
00E A=0 ALL
A
35C PT=12
=
162 A=A+1 @PT
1
0B0 C=N ALL
01D ?NCXQ
C=
060 1807
A+C
128 WRIT4(L)
3E0 RTN
k) X/E3 & X*E3
-These short routines divide ( respectively multiply ) X-register by 1000
without disturbing registers Y , Z , T , L.
-Unlike E3 / or E3 * , synthetic
register Q is unchanged.
0B3 "3"
005 "E"
02F "/"
018 "X"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace this line ( SETDEC ) by the
2 words 361 ?NCXQ
2EE ?C#0 ALL
050 14D8
3A0 ?NC RTN
266 C=C-1 S&X
266 C=C-1 S&X
266 C=C-1 S&X
0E8 WRIT 3(X)
3E0 RTN
0B3 "3"
005 "E"
02A "*"
018 "X"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace this line ( SETDEC ) by the
2 words 361 ?NCXQ
2EE ?C#0 ALL
050 14D8
3A0 ?NC RTN
226 C=C+1 S&X
226 C=C+1 S&X
226 C=C+1 S&X
0E8 WRIT 3(X)
3E0 RTN
5°) Random Number Generator
-"RAND" uses the timer to produce pseudo-random numbers r between 0 and
1 ( 0 < r < 1 ). I don't know if r = 0 may happen.
-The content of register X is saved in L-register
084 "D"
00E "N"
001 "A"
012 "R"
0F8 READ 3(X)
128 WRIT 4(L)
130 LDI S&X
010 010
The user memory must be deselected by selecting
270 RAM SLCT
a non-existent RAM ( at 010h )
130 LDI S&X
then the Timer
0FB 0FB
is
3F0 PRPH SLCT
selected
3E8 WRIT 15(e)
Set the A/B pointer to A
038 READ DATA
1BC RCR 11
Rotates C-register 11 digits right
046 C=0 S&X
The user memory
270 RAM SLCT
is selected again
05E C=0 MS
130 LDI S&X
041 041
2A0 SETDEC
10E A=C ALL
04E C=0 ALL
35C PT=12
1D0 LD@PT- 7
210 LD@PT- 8
110 LD@PT- 4
050 LD@PT- 1
090 LD@PT- 2
250 LD@PT- 9
190 LD@PT- 6
1D0 LD@PT- 7
210 LD@PT- 8
1D0 LD@PT- 7
044 CLRF 4
C
070 N=C ALL
=
171 ?NCXQ
A
064 195C
mod C
10E A=C ALL
0B0 C=N ALL
261 ?NCXQ
C =
060 1898
A/C
0E8 WRIT 3(X)
3E0 RTN
6°) 3D-Vectors
a) Norm
-"NORM" save X-register in L-register and returns ( x2
+ y2 + z2 ) 1/2 in X-register
-The other stack registers are undisturbed.
08D "M"
012 "R"
00F "O"
00E "N"
2A0 SETDEC
078 READ 1(Z)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
128 WRIT 4(L)
0B8 READ 2(Y)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
138 READ 4(L)
025 ?NCXQ
C=
060 1809
AB+C
070 N=C ALL
0F8 READ 3(X)
128 WRIT 4(L)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
305 ?NCXQ
C=
060 18C1
sqrt(AB)
0E8 WRIT 3(X)
3E0 RTN
-This routine does not check for alpha data.
b) Dot Product
-Here, we assume that X- Y- Z- registers contain the 3 components of a
vector U(x,y,z)
and that the synthetic registers M , N , O contain the 3 components
of another vector V(x',y',z')
"DOT" saves x in L-registers and returns the dot product U.V
= xx' + yy' + zz' in X-register
without disturbing the other stack registers or the "alpha registers".
094 "T"
00F "O"
004 "D"
2A0 SETDEC
0F8 READ 3(X)
128 WRIT 4(L)
10E A=C ALL
178 READ 5(M)
135 ?NCXQ
C=
060 184D
A*C
070 N=C ALL
0B8 READ 2(Y)
10E A=C ALL
1B8 READ 6(N)
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
070 N=C ALL
078 READ 1(Z)
10E A=C ALL
1F8 READ 7(O)
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
0E8 WRIT 3(X)
3E0 RTN
-This routine does not check for alpha data.
-Even if you add 355 ?NCXQ at the proper places,
the HP-41 may not always identify non-numeric data in the synthetic registers!
050 14D8
-So, this routine should be used carefully...
c) Cross Product
-Like "DOT", "CROSS" assumes that X- Y- Z- registers contain the 3 components
of a vector U(x,y,z)
and that the synthetic registers M , N , O contain the 3 components
of another vector V(x',y',z')
"CROSS" saves x in L-registers and returns the cross product
UxV (x",y",z") in registers X , Y , Z respectively
without disturbing the other stack registers or the "alpha registers".
093 "S"
013 "S"
00F "O"
012 "R"
003 "C"
2A0 SETDEC
0B8 READ 2(Y)
10E A=C ALL
178 READ 5(M)
135 ?NCXQ
C=
060 184D
A*C
2BE C=-C-1 MS
C=-C
128 WRIT 4(L)
0F8 READ 3(X)
10E A=C ALL
1B8 READ 6(N)
135 ?NCXQ
C=
060 184D
A*C
138 READ 4(L)
025 ?NCXQ
C=
060 1809
AB+C
128 WRIT 4(L)
here, L-register = z"
078 READ 1(Z)
10E A=C ALL
1B8 READ 6(N)
135 ?NCXQ
C=
060 184D
A*C
2BE C=-C-1 MS
C=-C
070 N=C ALL
0B8 READ 2(Y)
10E A=C ALL
1F8 READ 7(O)
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
070 N=C ALL
here, the CPU register N = x"
0F8 READ 3(X)
10E A=C ALL
1F8 READ 7(O)
135 ?NCXQ
C=
060 184D
A*C
2BE C=-C-1 MS
C=-C
0A8 WRIT 2(Y)
078 READ 1(Z)
10E A=C ALL
178 READ 5(M)
135 ?NCXQ
C=
060 184D
A*C
0B8 READ 2(Y)
025 ?NCXQ
C=
060 1809
AB+C
0A8 WRIT 2(Y)
Y now contains y"
138 READ 4(L)
068 WRIT 1(Z)
0F8 READ 3(X)
128 WRIT 4(L)
0B0 C=N ALL
0E8 WRIT 3(X)
3E0 RTN
-This routine does not check for alpha data.
-Even if you add 355 ?NCXQ at the proper places,
the HP-41 may not always identify non-numeric data in the synthetic registers!
050 14D8
-So, this routine should be used carefully...
-The 3 routines ST<>A CROSS and DOT may be used to calculate
a determinant of order 3.
-For instance, if
a , a' , a" are stored in R01 , R02 , R03
b , b' , b" are stored in R05 , R06 , R07
c , c' , c" are stored in R12 , R13 , R14 respectively,
the short program:
01 LBL "D3" 02 RCL 14 03 RCL 13 04 RCL 12 05 ST<>A 06 RCL 07 07 RCL 06 08 RCL 05 09 CROSS 10 ST<>A 11 RCL 03 12 RCL 02 13 RCL 01 14 DOT 15 CLA 16 END |
will calculate
| a
b c |
D = | a' b' c' |
| a" b" c" |
7°) Statistics
a) Linear Regression
-The following routines ( COV CORR LR LRY )
calculates the sample covariance, the coefficient of correlation,
the least-squares line and the linear estimate.
-All work like built-in functions: saving X in L-register, without disturbing
the stack.
-However, scratch register Q is altered ( like MEAN and SDEV do ) and
there is no check for OVERFLOW or UNDERFLOW
-You'll get ALPHA DATA if one of the statistics registers contains an
alpha string and NON EXISTENT if one of the statistics registers doesn't
exist.
-If the least-squares line is y = a.x + b
"LR" gives a in X-register
and b in Y-register ( the previous content of Y-register
is lost )
-These routines are interconnected but CPU-flags 6 7 8 are used to avoid
subroutine calls.
099 "Y"
012 "R"
00C "L"
288 SETF 7
023 JNC +04
092 "R"
00C "L"
284 CLRF 7
104 CLRF 8
033 JNC +06
092 "R"
012 "R"
00F "O"
003 "C"
108 SETF 8
144 CLRF 6
02B JNC +05
096 "V"
00F "O"
003 "C"
148 SETF 6
3F9 ?NCXQ
070 1CFE
10E A=C ALL
0F8 READ 3(X)
128 WRIT 4(L)
0B0 C=N ALL
135 ?NCXQ
C=
060 184D
A*C
2BE C=-C-1 MS
C=-C
268 WRIT 9(Q)
11C PT=8
C
3BD ?NCXQ
=
070 1CEF
Sum xy
070 N=C ALL
29C PT=7
C
3BD ?NCXQ
=
070 1CEF
n
10E A=C ALL
046 C=0 S&X
270 RAM SLCT
278 READ 9(Q)
0AE A<>C ALL
268 WRIT 9(Q)
135 ?NCXQ
C=
060 184D
A*C
10E A=C ALL
0B0 C=N ALL
01D ?NCXQ
C=
060 1807
A+C
070 N=C ALL
00E A=0 ALL
A
1BE A=A-1 MS
=
35C PT=12
-
162 A=A+1 @PT
1
278 READ 9(Q)
01D ?NCXQ
C=
060 1807
A+C
10E A=C ALL
0B0 C=N ALL
0AE A<>C ALL
261 ?NCXQ
C =
060 1898
A/C
0E8 WRIT 3(X)
14C ?FSET 6
360 ?C RTN
end of "COV"
084 CLRF 5
C
35C PT=12
= sx
04D ?NCXQ
N
074 1D13
= sy
10E A=C ALL
10C ?FSET 8
013 JNC +02
0B0 C=N
135 ?NCXQ
C=
060 184D
A*C
10E A=C ALL
0F8 READ 3(X)
0AE A<>C
261 ?NCXQ
C =
060 1898
A/C
0E8 WRIT 3(X)
10C ?FSET 8
360 ?C RTN
end of "CORR"
35C PT=12
C
001 ?NCXQ
= x bar
074 1D00
N = y bar
10E A=C ALL
0F8 READ 3(X)
135 ?NCXQ
C=
060 184D
A*C
2BE C=-C-1 MS
C=-C
10E A=C ALL
0B0 C=N ALL
01D ?NCXQ
C=
060 1807
A+C
28C ?FSET 7
01F JC +03
0A8 WRIT 2(Y)
3E0 RTN
end of "LR"
268 WRIT 9(Q)
0F8 READ 3(X)
10E A=C ALL
138 READ 4(L)
135 ?NCXQ
C=
060 184D
A*C
10E A=C ALL
278 READ 9(Q)
01D ?NCXQ
C=
060 1807
A+C
0E8 WRIT 3(X)
3E0 RTN
end of "LRY"
b) Recalling the Statistics
Registers
RCL S ( RCL SIGMA ) saves the content of X-register in L-register, cheks that the statistics registers do exist and returns:
Sum x
in X-erister
Sum y
in Y-register
Sum xy in synthetic register M
Sum x2 in Z-register
and n
in synthetic register N
Sum y2 in T-register
0CE "S"
020 " "
( one space )
00C "L"
003 "C"
012 "R"
260 SETHEX
0F8 READ 3(X)
128 WRIT 4(L)
378 READ 13(c)
1BC RCR 11
070 N=C ALL
10E A=C ALL
130 LDI S&X
1FB 507d
this value is correct for an HP-41CV or CX or an HP-41C with a Quad memory
module.
306 ?A<C S&X
381 ?NCGO
00A 02E0
NON EXISTENT is displayed if the statistics registers do not exist
130 LDI S&X
004 004
0EE C<>B ALL
130 LDI S&X
005 005
10E A=C ALL
0B0 C=N ALL
206 C=C+A S&X
270 RAM SLCT
038 READ DATA
158 M=C ALL
0AE A<>C ALL
10E A=C ALL
326 ?A<B S&X
017 JC +02
226 C=C+1 S&X
270 RAM SLCT
198 C=M ALL
2F0 WRIT DATA
1A6 A=A-1 S&X
393 JNC -0E
04E C=0 ALL
270 RAM SLCT
038 READ DATA
10E A=C ALL
0F8 READ 3(X)
028 WRIT 0(T)
0AE A<>C ALL
0E8 WRIT 3(X)
3E0 RTN
8°) 3 Tests
a) X=1?
-In a program, "X=1?" skips the following line if X-register
is different from 1.
-If the next line is an END or "the" .END. this line is not skipped and
the program pointer is unchanged.
-Executed from the keyboard, it has the same effects and the HP-41 does
not display YES or NO.
0BF "?"
031 "1"
03D "="
018 "X"
00E A=0 ALL
A
35C PT=12
=
162 A=A+1 @PT
1
0F8 READ 3(X)
36E ?A#C ALL
3A0 ?NC RTN
141 ?NCXQ
These 6 words ( 141 0A4 3E5 0A8 0BD
08C ) skip one program line.
0A4 2950
Repeat this sequence if you want to skip 2 lines or more.
3E5 ?NCXQ
Be sure that the CPU is set in Hexadecimal mode ( 260 SETHEX ). It's
not necessary here since it's always the default.
0A8 2AF9
0BD ?NCXQ
Here, the last 3 words may be replaced by only 2 words:
0BD ?NCGO
08C 232F
08E 232F
3E0 RTN
b) X=N?
-In a program, "X=N?" skips the following line if X-register
is not an integer.
-It is equivalent to FRC X=0? except that the stack
is unchanged.
0BF "?"
00E "N"
03D "="
018 "X"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace 2A0 SETDEC by
the 2 words 361 ?NCXQ
084 CLRF 5
C
050 14D8
0ED ?NCXQ
=
064 193B
frc(C)
2EE ?C#0 ALL
3A0 ?NC RTN
260 SETHEX
141 ?NCXQ
0A4 2950
3E5 ?NCXQ
0A8 2AF9
0BD ?NCGO
08E 232F
c) X#Y??
-"X#Y??" allows to stop a loop when 2 successive approximations
( in registers X & Y ) are almost equal.
-So, it can replace "X#Y?" to avoid infinite loops when using
Newton's method ... and so on ...
0BF "?"
03F "?"
019 "Y"
04D "#"
018 "X"
0F8 READ 3(X)
10E A=C ALL
0B8 READ 2(Y)
36E ?A#C ALL
0DB JNC +1Bh
if you want to check for alpha data, replace the 2 words 0DB
by the 3 words 0E3 JNC +1Ch
2A0 SETDEC
2A0
355 ?NCXQ
2EE ?C#0 ALL
050 14D5
017 JC +02
0AE A<>C ALL
2BE C=-C-1 MS
C=-C
070 N=C ALL
01D ?NCXQ
C=
060 1807
A+C
10E A=C ALL
0B0 C=N ALL
261 ?NCXQ
C =
060 1898
A/C
05E C=0 MS
C=|C|
10E A=C ALL
04E C=0 ALL
C=
2BE C=-C-1 MS
35C PT=12
090 LD@PT- 2
21C PT=2
250 LD@PT- 9
250 LD@PT- 9
050 LD@PT- 1
-2 E-9
01D ?NCXQ
C=
060 1807
A+C
2FE ?C#0 MS
3A0 ?NC RTN
260 SETHEX
141 ?NCXQ
0A4 2950
3E5 ?NCXQ
0A8 2AF9
0BD ?NCGO
08E 232F
9°) Hyperbolic Functions
-The following routines compute hyperbolic sine, cosine, tangent and their
inverses: SINH COSH TANH ASINH ACOSH
ATANH
-They use the same formulas as the programs listed in "Hyperbolic Functions
for the HP-41"
-As usual, x is saved in L-register and Y Z T are undisturbed.
-However, these M-Code routines do not check for overflow/underflow.
Hyperbolic Sine & Cosine
088 "H"
013 "S"
00F "O"
003 "C"
044 CLRF 4
033 JNC +06
088 "H"
00E "N"
009 "I"
013 "S"
048 SETF 4
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
2BE C=-C-1 MS
029 ?CXQ
C=
069 1A0A
exp(C) or exp(C)-1 according to CPU flag 4
04C ?FSET 4
013 JNC +02
2BE C=-C-1 MS
C=-C
0E8 WRIT 3(X)
138 READ 4(L)
029 ?NCXQ
C=
068 1A0A
exp(C) or exp(C)-1 according to CPU flag 4
0F8 READ 3(X)
025 ?NCXQ
C=
060 1809
AB+C
04E C=0 ALL
C
35C PT=12
=
090 LD@PT- 2
2
269 ?NCXQ
C=
060 189A
AB/C
0E8 WRIT 3(X)
3E0 RTN
Hyperbolic Tangent
088 "H"
00E "N"
001 "A"
014 "T"
048 SETF 4
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
10E A=C ALL
01D ?NCXQ
C=
060 1807
A+C
035 ?NCXQ
C=
068 1A0D
exp(AB)-1
0E8 WRIT 3(X)
001 ?NCXQ
C=
060 1800
AB+1
001 ?NCXQ
C=
060 1800
AB+1
10E A=C ALL
0F8 READ 3(X)
0AE A<>C ALL
261 ?NCXQ
C=
060 1898
A/C
0E8 WRIT 3(X)
3E0 RTN
Inverse Hyperbolic Sine
088 "H"
00E "N"
009 "I"
013 "S"
001 "A"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
0E8 WRIT 3(X)
001 ?NCXQ
C=
060 1800
AB+1
305 ?NCXQ
C=
060 18C1
sqrt(AB)
001 ?NCXQ
C=
060 1800
AB+1
10E A=C ALL
0F8 READ 3(X)
0AE A<>C ALL
261 ?NCXQ
C=
060 1898
A/C
138 READ 4(L)
05E C=0 MS
C= | C |
025 ?NCXQ
C=
060 1809
AB+C
084 CLRF 5
C
1CD ?NCXQ
=
06C 1B73
Ln1+C
10E A=C ALL
138 READ 4(L)
11E A=C MS
0AE A<>C ALL
0E8 WRIT 3(X)
3E0 RTN
Inverse Hyperbolic Cosine
088 "H"
013 "S"
00F "O"
003 "C"
001 "A"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
02E B=0 ALL
0FA B<>C M
0AE A<>C ALL
009 ?NCXQ
C=
060 1802
AB-1
0E8 WRIT 3(X)
04E C=0 ALL
C
35C PT=12
=
090 LD@PT-2
2
025 ?NCXQ
C=
060 1809
AB+C
0F8 READ 3(X)
13D ?NCXQ
C=
060 184F
AB*C
305 ?NCXQ
C=
060 18C1
sqrt(AB)
2EE ?C#0 ALL
017 JC+02
02E B=0 ALL
0F8 READ 3(X)
025 ?NCXQ
C=
060 1809
AB+C
084 CLRF 5
C
1CD ?NCXQ
=
06C 1B73
Ln1+C
0E8 WRIT 3(X)
3E0 RTN
Inverse Hyperbolic Tangent
088 "H"
00E "N"
001 "A"
014 "T"
001 "A"
0F8 READ 3(X)
2A0 SETDEC
if you want to check for alpha data, replace SETDEC by the 2 words
361 ?NCXQ
128 WRIT 4(L)
050 14D8
05E C=0 MS
C= | C |
2BE C=-C-1 MS
C=-C
00E A=0 ALL
A
35C PT=12
=
162 A=A+1 @PT
1
01D ?NCXQ
C=
060 1807
A+C
0E8 WRIT 3(X)
138 READ 4(L)
05E C=0 MS
C= | C |
10E A=C ALL
01D ?NCXQ
C=
060 1807
A+C
0F8 READ 3(X)
269 ?NCXQ
C=
060 189A
AB/C
084 CLRF 5
C
1CD ?NCXQ
=
06C 1B73
Ln1+C
10E A=C ALL
138 READ 4(L)
11E A=C MS
04E C=0 ALL
C
35C PT=12
=
090 LD@PT- 2
2
261 ?NCXQ
C=
060 1898
A/C
0E8 WRIT 3(X)
3E0 RTN
10°) 5 Complex Functions
-These routines compute the product, quotient, square, inverse and square
root of complex numbers.
-One can use R-P and P-R instead, but the following functions are usually
faster and more accurate.
-However, they do not check for alpha data, overflow/underflow.
-Otherwise, they work like built-in functions: x is saved in L-register
and Z & T registers are undisturbed.
-ENTER the imaginary part first ( in Y-register ), then the real part
in X-register.
a) Z*Z & Z/Z
09A "Z"
02A "*"
01A "Z"
104 CLRF 8
02B JNC +05
09A "Z"
02F "/"
01A "Z"
108 SETF 8
2A0 SETDEC
0F8 READ 3(X)
128 WRIT 4(L)
10E A=C ALL
078 READ 1(Z)
135 ?NCXQ
C=
060 184D
A*C
070 N=C ALL
0B8 READ 2(Y)
10E A=C ALL
046 C=0 S&X
C
270 RAM SLCT
=
038 READ DATA
T
135 ?NCXQ
C=
060 184D
A*C
10C ?FSET 8
017 JC +02
2BE C=-C-1 MS C=-C
10E A=C ALL
0B0 C=N ALL
01D ?NCXQ
C=
060 1807
A+C
0E8 WRIT 3(X)
0B8 READ 2(Y)
10E A=C ALL
078 READ 1(Z)
135 ?NCXQ
C=
060 184D
A*C
10C ?FSET 8
013 JNC +02
2BE C=-C-1 MS
C=-C
070 N=C ALL
138 READ 4(L)
10E A=C ALL
046 C=0 S&X
C
270 RAM SLCT
=
038 READ DATA
T
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
10E A=C ALL
0B8 READ 2(Y)
0AE A<>C ALL
0A8 WRIT 2(Y)
10C ?FSET 8
3A0 ?NC RTN
end of "Z*Z"
0AE A<>C ALL
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
070 N=C ALL
138 READ 4(L)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
070 N=C ALL
0F8 READ 3(X)
10E A=C ALL
0B0 C=N ALL
261 ?NCXQ
C=
060 1898
A/C
0E8 WRIT 3(X)
0B8 READ 2(Y)
10E A=C ALL
0B0 C=N ALL
261 ?NCXQ
C=
060 1898
A/C
0A8 WRIT 2(Y)
3E0 RTN
end of "Z/Z"
b) Z^2
0B2 "2"
01E "^"
01A "Z"
2A0 SETDEC
0F8 READ 3(X)
128 WRIT 4(L)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
2BE C=-C-1 MS C=-C
070 N=C ALL
0B8 READ 2(Y)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
2BE C=-C-1 MS C=-C
0E8 WRIT 3(X)
138 READ 4(L)
10E A=C ALL
01D ?NCXQ
C=
060 1807
A+C
0B8 READ 2(Y)
13D ?NCXQ
C=
060 184F
AB*C
0A8 WRIT 2(Y)
3E0 RTN
c) 1/Z
09A "Z"
02F "/"
031 "1"
2A0 SETDEC
0F8 READ 3(X)
128 WRIT 4(L)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
070 N=C ALL
0B8 READ 2(Y)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
070 N=C ALL
0F8 READ 3(X)
10E A=C ALL
0B0 C=N ALL
261 ?NCXQ
C=
060 1898
A/C
0E8 WRIT 3(X)
0B8 READ 2(Y)
2BE C=-C-1 MS C=-C
10E A=C ALL
0B0 C=N ALL
261 ?NCXQ
C=
060 1898
A/C
0A8 WRIT 2(Y)
3E0 RTN
d) SQRTZ
09A "Z"
014 "T"
012 "R"
011 "Q"
013 "S"
2A0 SETDEC
0F8 READ 3(X)
128 WRIT 4(L)
2EE ?C#0 ALL
097 JC +18d=+12h
0B8 READ 2(Y)
05E C=0 MS
C = | C |
10E A=C ALL
04E C=0 ALL
C
35C PT=12
=
090 LD@PT- 2
2
261 ?NCXQ
C=
060 1898
A/C
305 ?NCXQ
C=
060 18C1
sqrt(AB)
0E8 WRIT 3(X)
10E A=C ALL
0B8 READ 2(Y)
11E A=C MS
0AE A<>C ALL
0A8 WRIT 2(Y)
3E0 RTN
end of the routine
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
070 N=C ALL
0B8 READ 2(Y)
10E A=C ALL
135 ?NCXQ
C=
060 184D
A*C
0B0 C=N ALL
025 ?NCXQ
C=
060 1809
AB+C
305 ?NCXQ
C=
060 18C1
sqrt(AB)
2EE ?C#0 ALL
017 JC+02
02E B=0 ALL
0F8 READ 3(X)
05E C=0 MS
C = | C |
025 ?NCXQ
C=
060 1809
AB+C
070 N=C ALL
04E C=0 ALL
C
35C PT=12
=
090 LD@PT- 2
2
269 ?NCXQ
C=
060 189A
AB/C
305 ?NCXQ
C=
060 18C1
sqrt(AB)
0F0 C<>N ALL
10E A=C ALL
01D ?NCXQ
C=
060 1807
A+C
305 ?NCXQ
C=
060 18C1
sqrt(AB)
10E A=C ALL
0B8 READ 2(Y)
0AE A<>C ALL
261 ?NCXQ
C=
060 1898
A/C
0AE A<>C ALL
0F8 READ 3(X)
2FE ?C#0 MS
027 JC +04
0B0 C=N ALL
0E8 WRIT 3(X)
283 JNC -48d=-30h
0AE A<>C ALL
05E C=0 MS
C = | C |
0E8 WRIT 3(X)
0B0 C=N ALL
243 JNC -56d=-38h
11°) Creating Extra-Registers
a) Saving & Recalling
X-Register
-I wrote these routines thanks to fruitful advices given by Dan Grelinger
& Peter Platzer in the MoHPC forum.
-"STO W" saves the content of register X into 7 words at the addresses
FD4A to FD50
-The first of these addresses are written in red below.
-FD4A to FD50 must remain unused by any routine:
-For example, start the following word at FD51
097 "W"
020 " "
( one space )
00F "O"
014 "T"
013 "S"
0F8 READ 3(X)
0EE C<>B ALL
130 LDI S&X
006 006
106 A=C S&X
15C PT=6
3D0 LD@PT- F
change these 4 words according to the addresses you've choosen in you own
ROM.
350 LD@PT- D
110 LD@PT- 4
290 LD@PT- A
0C6 C=B S&X
loop
042 C=0 @PT
040 WRIT S&X only
works if there is a MLDL type module at the address
3AE RSHFB ALL
3AE RSHFB ALL
23A C=C+1 M
1A6 A=A-1 S&X
3CB JNC -07
3E0 RTN
-After storing X-register, we need of course a routine to recall it in
register X.
097 "W"
020 " "
( one space )
00C "L"
003 "C"
012 "R"
130 LDI S&X
006 006
106 A=C S&X
15C PT=6
3D0 LD@PT- F
350 LD@PT- D
110 LD@PT- 4
290 LD@PT- A
31C PT=1
330 FETCH S&X loop
0EA C<>B PT<-
0EE C<>B ALL
23C RCR 2
0EE C<>B ALL
23A C=C+1 M
1A6 A=A-1 S&X
3CB JNC -07
0EE C<>B ALL
0E8 WRIT 3(X)
3E0 RTN
-"RCL W" simply overwrites X-register
-So, it would be better to replace the last 2 words by
028 WRIT 0(T)
3B5 ?NCGO goto
052 14ED roll up
b) Saving & Recalling
all the Stack
-You can create as many extra-registers as you want with routines similar
to "STO W" & "RCL W"
-The following ones save and recall the 4 registers X Y Z T in a space
of 4x7 = 28 words
-In my ROM, the addresses are FDA4 to FD65 ( I've deleted "STO W" &
"RCL W" )
-So these programs may start at FD66 if the code begins just after the
reserved space:
094 "T"
013 "S"
00F "O"
014 "T"
013 "S"
284 CLRF 7
using a flag to distinguish "STOST" & "RCLST" saves several words
03B JNC+07
094 "T"
013 "S"
00C "L"
003 "C"
012 "R"
288 SETF 7
130 LDI S&X
004 004
if you want to save L-register too, replace this line by 005 and reserve
a space of 35 words for the storage.
070 N=C ALL
15C PT=6
3D0 LD@PT- F
change these 4 words according to the addresses you've choosen in you own
ROM.
350 LD@PT- D
110 LD@PT- 4
290 LD@PT- A
0EE C<>B ALL
0B0 C=N ALL
2E6 ?C#0 S&X
3A0 ?NC RTN
both routines stop here
266 C=C-1 S&X
070 N=C ALL
28C ?FSET 7
01F JC+03
270 RAMSLCT
038 READ DATA
0EE C<>B ALL
130 LDI S&X
006 006
106 A=C S&X
28C ?FSET 7
08B JNC+11h=+17d
31C PT=1
330 FETCH S&X
0EA C<>B PT <-
0EE C<>B ALL
23C RCR 2
0EE C<>B ALL
23A C=C+1 M
1A6 A=A-1 S&X
3CB JNC-07
10E A=C ALL
0B0 C=N ALL
270 RAMSLCT
0EE C<>B ALL
2F0 WRIT DATA
06E A<>B ALL
313 JNC-1Eh=-30d
21C PT=2
0C6 C=B S&X
042 C=0 @PT
040 WRIT S&X
3AE RSHFB ALL
3AE RSHFB ALL
23A C=C+1 M
1A6 A=A-1 S&X
3CB JNC-07
2BB JNC-29h=-41d
-"STOST" stores the 4 registers X Y Z T
-"RCLST" recalls X Y Z T ( the previous stack is lost. L-register is unchanged
)
12°) Largest Element of a Block of Registers
-"MAXAD" takes the control number of a block of contiguous registers
and returns the maximum element ( in absolute value ) in X and
the corresponding address in Y.
-The block is defined by a control number of the form bbb.eee
( like with ISG ) or eee.bbb' with bbb' = bbb-1 ( like
with DSE )
-Rbb is the first register, Ree is the last one
>>> The routine does not chek for alpha data.
-Z-register is saved in T and Y-register is saved in Z
084 "D"
001 "A"
018 "X"
001 "A"
00D "M"
3B5 ?NCXQ
roll up
050 14ED
0B8 READ 2(Y)
128 WRIT 4(L)
2A0 SETDEC
088 SETF 5
C
0ED ?NCXQ
=
064 193B
int(C)
070 N=C ALL
138 READ 4(L)
084 CLRF 5
C
0ED ?NCXQ
=
064 193B
frc(C)
226 C=C+1 S&X
226 C=C+1 S&X
226 C=C+1 S&X
088 SETF 5
C
0ED ?NCXQ
=
064 193B
int(C)
260 SETHEX
38D ?NCXQ
008 02E3
226 C=C+1 S&X
0F0 C<>N ALL
38D ?NCXQ
008 02E3
106 A=C S&X
0B0 C=N ALL
306 ?A<C S&X
01F JC+03
0A6 A<>C S&X
226 C=C+1 S&X
1BC RCR 11
11A A=C M
378 READ 13(c)
15A A=A+C M
03C RCR 3
146 A=A+C S&X
0AE A<>C ALL
070 N=C ALL
03C RCR 3
106 A=C S&X
130 LDI S&X
201 201h
this value is correct for an HP-41CV or CX or an HP-41C with a Quad memory
module.
306 ?A<C S&X
381 ?NCGO
00A 02E0
NON EXISTENT is displayed if the last register of the block does not exist
04E C=0 ALL
0E8 WRIT 3(X)
0B0 C=N ALL
0A8 WRIT 2(Y)
070 N=C ALL
106 A=C S&X
03C RCR 3
306 ?A<C S&X
0CB JNC+19h=+25d
0A6 A<>C S&X
270 RAMSLCT
038 READATA
05E C=0 MS
C= | C |
10E A=C ALL
046 C=0 S&X
270 RAMSLCT
2A0 SETDEC
0F8 READ 3(X)
0AE A<>C ALL
268 WRIT 9(Q)
2BE C=-C-1 MS
C=-C
01D ?CXQ
C=
061 1807
A+C
2FE ?C#0 MS
02B JNC+05
278 READ 9(Q)
0E8 WRIT 3(X)
0B0 C=N ALL
0A8 WRIT 2(Y)
260 SETHEX
0B0 C=N ALL
226 C=C+1 S&X
323 JNC-1Ch=-28d
0B8 READ 2(Y)
106 A=C S&X
378 READ 13(c)
03C RCR 3
1C6 A=A-C S&X
The following lines are actually given by Ken Emery in reference [1]
130 LDI S&X
to convert an hexadecimal number in A S&X into a decimal number in
C
010 010h
270 RAMSLCT
2DC PT=13
110 LD@PT- 4
11E A=C MS
3A1 ?NCXQ
014 05E8
0AE A<>C ALL
11C PT=8
04A C=0 PT<-
270 RAMSLCT
39C PT=0
0D0 LD@PT- 3
010 LD@PT- 0
0AE A<>C ALL
342 ?A#0 @PT
027 JC+04
3FA LSHFA M
1A6 A=A-1 S&X
3E3 JNC-04
0AE A<>C ALL
2FA ?C#0 M
017 JC+02
04E C=0 ALL
0A8 WRIT 2(Y)
3E0 RTN
-For example,
if registers R01 R02 R03 R04
R05
contain 1
4 6 -7
2 respectively
1.005 XEQ "MAXAD" ( or 5 XEQ "MAXAD" )
will return 7 in X-register and 4 in Y-register
Notes:
-The control number is saved in L-register.
-Execution time = 2 seconds for a block of 100 registers.
-Synthetic register Q is used.
References:
[1] Ken Emery - "HP-41 M-Code for Beginners" - Synthetix - ISBN
0-9612174-7-2
[2] VASM listings
[3] Ángel Martin - "HP-41 OS 13-Digit Math Routines"