The Museum of HP Calculators

HP Articles Forum

[Return to the Index ]
[ Previous | Next ]


Effective Computer-aided Calculator Programming - Part 1 - Voyager

Posted by Egan Ford on 2 Apr 2008, 12:47 a.m.

Abstract

Keystroke programming for small quick&dirty programs it is very efficient, but what about for long or very long programs? Debugging a 100+ instruction program can be a challenge, especially when only one instruction is visible. Many of us can write RPN code in text editors, and then run the program in our heads before keying the sequence. While this may work for some, there are more effective ways.

The purpose for this series of articles is to describe the options available to aid in the rapid development and testing of RPN code by leveraging the use of text editors, compilers, and accelerated simulators and emulators.

Part 1 of this series supports the follow models: 11C, 12C, 15C, and the 16C.

Audience

Windows, Linux, and OS/X users that want to save time debugging and testing RPN programs; especially long complex competition and challenge code.

Prerequisites

Perl

The Voyager compiler used in this article requires a Perl interpreter. For Linux and OS/X nothing is required, however for Windows, Perl must be installed. There are a number of freely available Perl implementations for Windows; one of the most popular is the freely available ActivePerl (http://www.activestate.com/store/activeperl/download/).

To verify that Perl is working open up a command prompt and type:

perl -e "print \"hello world\n\""

Nonpareil

Nonpareil 15C Windows Snap Shot

Nonpareil is multiplatform (Windows, Linux, OS/X, and UNIX) multicalculator emulator that supports many classic models including all the Voyagers (sans the 10C). Since the emulator uses the original Voyager ROMs the numeric results will be exactly the same.

NOTE: The Voyager compiler in this article only supports Nonpareil.

To install Nonpareil for Windows visit http://nonpareil.brouhaha.com/download and download and install GTK first, then download and extract the Nonpareil Windows zip file into any directory. To launch Nonpareil, change to the nonpareil-0.77-win32 directory and type:

nonpareil calculator
e.g.
nonpareil 15c
Alternatively you can give no argument and then be greeted by a GUI calculator selector.

To install Nonpareil for Linux/Unix first verify that GTK is installed, and then download the source from http://nonpareil.brouhaha.com/download, extract, and type as root:

cd nonpareil-0.78/scons-local
tar -xzf scons-local-0.96.90.tar.gz
cd ..
scons-local/scons.py install
This will place nonpareil in /usr/local/bin. If you wish to install in a different directory read the INSTALL file for more details.

OS/X users can get Nonpareil from http://homepage.mac.com/mba/nonpareil/. This version unfortunately does not save or read Nonpareil state files making the compiler only good for syntax checking, macros, virtual labels (12C), numeric expansion, and publication of code (pretty print). OS/X users may opt for VMware Fusion, Parallels, or Wine with the Windows or Linux version of Nonpareil.

Voyager Compiler

vcomp.pl is a Nonpareil Voyager program compiler and lister. vcomp.pl achieves this by reading and writing Nonpareil state files, i.e. the files that contain the RAM contents of each emulated calculator.

vcomp.pl has a number of advanced features to make Voyager development and testing more efficient:

  1. Syntax checking with support for user definable statements.
  2. Numeric expansion. Multiple digit constant numbers can use a single line of code.
  3. Duplicate label checking. Although legal, warnings are issued when duplicate labels are encountered.
  4. GTO checking. No point in going nowhere.
  5. Macro expansion. Macros can be defined on a per calculator basis.
  6. Virtual 12C labels. LBL can be use with 12C programs. All LBL and GTO statements will be properly converted to line numbers when compiled.
  7. Pretty print listings than can contain line numbers, statements, and/or keystroke sequences. Listings can be displayed using multiple columns to minimize space usage when publishing your code.
  8. An internal dictionary of statements and keystrokes that can be listed and used as a reference guide.


Windows Install

The Windows version can be obtained from here: http://www.hpmuseum.org/guest/eganford/vcomp.zip, to install just copy into any directory in your path.

Linux, OS/X, Cygwin, Unix, etc… Install

The non-Windows version can be obtain from here: http://www.hpmuseum.org/guest/eganford/vcomp.gz, to install just copy into any directory in your path and type:

gunzip <vcomp.gz >vcomp.pl
chmod 755 vcomp.pl

Using vcomp.pl

vcomp.pl without any options will produce the following helpful output:

vcomp.pl dict [-help] [-c|-cc n] <model>
         list [-help] [-c|-cc n] [-code|-linecode] <file>
         comp [-help] [-strip n] [-phase 1|2] [-c|-cc n] [-new <model>] -nst <file> <code>
<model>  Must be 11C, 12C, 15C, or 16C.
<file>   Is an existing or new Nonpareil State file.
<code>   Is your text source code.
vcomp.pl has three modes of operation: dictionary, list, and compile. Although all the examples use the first four letters, the lazy (or efficient) can opt to use just the first letter when specifying the mode of operation. Each mode has options specific to that mode. However there are few universal options.

The universal option –help can be used with any vcomp.pl command/mode to display usage and examples. E.g.:

vcomp.pl dict –help
will output:
vcomp.pl dict [-c|-cc n] <model>
-c n       Print output in n columns.
-cc n      Print output using x columns that can fit in n characters.
<model>    Must be 11C, 12C, 15C, or 16C.
E.g.  11C dictionary in 2 columns:
vcomp.pl dict -c 2 11C
E.g.  15C dictionary in x columns that can fix in 80 characters:
vcomp.pl dict -cc 80 15C
-c and –cc are two other universal options that can be used to columnize any output. –c n will display the output in n columns whereas –cc n will determine based on the length of the longest line how many columns can fit within an n character line, e.g. –cc 80 will columnize the output into m columns such that the maximum character count for any output line will <= 80.

Dictionary

The dictionary is used to convert statements to byte code (compiling) and byte code to statements (listing). The vomp.pl dict command can be used to list the contents of the dictionary, e.g.:

vcomp.pl dict -c 2 15C
Output:
%                      43 14      RCL/ (i)          - 45,10,24      
+                         40      RCL/ .0           - 45,10,.0      
-                         30      RCL/ .1           - 45,10,.1      
->DEG                  43  3      RCL/ .2           - 45,10,.2      
->H                    43  2      RCL/ .3           - 45,10,.3      
.
.
.
RCL- B            - 45,30,12      x^2                    43 11      
RCL- C            - 45,30,13      y^,r                   42 48      
RCL- D            - 45,30,14        y hat,r                         
RCL- E            - 45,30,15        LIN EST                         
RCL- I            - 45,30,25      y^x                       14      
The listing is sorted alphabetically. Nested statements (e.g. y hat,r, LIN EST above) are aliases. That is LIN EST could be used in your source instead of or in addition to y^,r when compiling, however when listing only the primary statement (e.g. y^,r) will be used. The dictionary and its contents are user definable.

Editing the Dictionary

To edit the dictionary for any model use your favorite text editor and search for "model Opcode Start", e.g. "11C Opcode Start", then scroll down until you find the statements you wish to edit or rearrange. E.g.:

   ee | L.R.               |    42 49 |
   ef | y^,r               |    42 48 |
   ef | y hat, r           |    42 48 |
   ef | LIN EST            |    42 48 |
   f0 | 0                  |        0 |
Notice how y^,r, y hat, r and LIN EST all have the same byte code. The first one listed will be the primary and the others will be aliases. Feel free to edit this to suit your taste, but make a backup first, just in case.

List

vcomp.pl list
will list the contents of any existing or newly created Nonpareil state file, e.g.:
vcomp.pl list -c 2 "c:\Documents and Settings\Egan\nonpareil\12C.nst"
Output:
01 -        0  0           24 -        1  1
02 -    44  2  STO 2       25 -       40  +
03 -        1  1           26 -        1  1
04 -    44  1  STO 1       27 -        4  4
05 -    44  0  STO 0       28 -        8  8
06 -        1  1           29 -        6  6
07 -       16  CHS         30 -        3  3
08 - 44 20  1  STOx 1      31 -        5  5
09 -        2  2           32 -        6  6
10 - 44 40  0  STO+ 0      33 -        4  4
11 -    45  0  RCL 0       34 -        8  8
12 -        1  1           35 -       20  x
13 -        1  1           36 -        5  5
14 -       21  y^x         37 -        0  0
15 -       22  1/x         38 -        5  5
16 -    45  1  RCL 1       39 -       48  .
17 -       20  x           40 -        2  2
18 - 44 40  2  STO+ 2      41 -        1  1
19 -    42 14  RND         42 -       10  /
20 -    43 35  x=0         43 -        1  1
21 - 43,33 23  GTO 23      44 -        1  1
22 - 43,33 06  GTO 06      45 -       22  1/x
23 -    45  2  RCL 2       46 -       21  y^x
The –code and –linecode options can be used to limit the amount of information, e.g.:
vcomp.pl list -c 5 -code 12C.nst
0           RCL 0       GTO 23      5           1           
STO 2       1           GTO 06      6           /           
1           1           RCL 2       4           1           
STO 1       y^x         1           8           1           
STO 0       1/x         +           x           1/x         
1           RCL 1       1           5           y^x         
CHS         x           4           0           
STOx 1      STO+ 2      8           5           
2           RND         6           .           
STO+ 0      x=0         3           2           
vcomp.pl list -c 3 -linecode 12C.nst
01  0           17  x           33  4           
02  STO 2       18  STO+ 2      34  8           
03  1           19  RND         35  x           
04  STO 1       20  x=0         36  5           
05  STO 0       21  GTO 23      37  0           
06  1           22  GTO 06      38  5           
07  CHS         23  RCL 2       39  .           
08  STOx 1      24  1           40  2           
09  2           25  +           41  1           
10  STO+ 0      26  1           42  /           
11  RCL 0       27  4           43  1           
12  1           28  8           44  1           
13  1           29  6           45  1/x         
14  y^x         30  3           46  y^x         
15  1/x         31  5           
16  RCL 1       32  6           

Compile
vcomp.pl comp
will compile plain text statements into Voyager byte code in the form of a Nonpareil state file.

When compiling you have the option of creating a new out-of-the-box state file or inserting your code into an existing state file preserving the contents of the stack and storage registers.

NOTE: Inserting into an existing state file is experimental. Backup your data first.
NOTE: New state files are not exactly "out-of-the-box", the 11C, 12C, and 15C are out-of-the-box + FIX 9.

Source Code Anatomy


Compiler Example

To compile the source file area.12c and insert into an existing 12C.nst state file:

vcomp.pl comp -nst 12C.nst area.12c
To compile the source file area.12c and create a new 12C.nst state file:
vcomp.pl comp -new 12C -nst 12C.nst area.12c
The output for any successful compile should look like this:
Phase 1: Preprocessor
Phase 2: Check GTOs
Phase 3: Compile
Done!
The only difference between the two is the use of the –new option. This is required to instruct the compiler as to what model you are compiling for. Without –new the compiler can autodetect the model from the provided state file.

Because of the advanced preprocessing features of this compiler the post compiled listing may not match your source code, e.g.

Input file area.12:

ENTER
ENTER
*
3.141592654
*
Listing:
vcomp.pl list -linecode 12c.nst
01  ENTER      
02  ENTER      
03  x          
04  3          
05  .          
06  1          
07  4          
08  1          
09  5          
10  9          
11  2          
12  6          
13  5          
14  4          
15  x          

The –strip option can be used to remove leading characters from source. E.g. if someone sent you the above as area.txt and you tried to compile it you would get the following error:
ERROR: illegal instruction: 01  ENTER, line: 1
However if you strip off the first 4 characters all is well:
vcomp.pl comp -strip 4 -new 12c -nst 12c.nst area.txt
Phase 1: Preprocessor
Phase 2: Check GTOs
Phase 3: Compile
Done!

Macros

Macros are defined in vcomp.pl. To add or edit use your favorite text editor and search for "model Macro Start", e.g. "12C Macro Start". This is an example of two 12C macros:

12C Macro Start
&SMOD
LBL START
-
LSTx
x<=y
GTO START
Rv
&MOD
x<>y
ENTER
Rv
x<>y
/
LSTx
x<>y
INTG
*
x<>y
-
CHS
12C Macro End
Macro definitions start with &NAME and end when the next macro starts and may contain any number of legitimate statements and virtual labels (12C only). E.g. the &SMOD (slow or subtract mod) leverages the use of 12C virtual labels to setup a loop.

In this example two 15C macros are defined. One for calling the other as a subroutine:

&CALL_MOD
GSB .8
&MOD
LBL .8
x<>y
ENTER
Rv
x<>y
/
LSTx
x<>y
INT
*
R^
-
CHS
RTN
An example of how to use this macro:
LBL A
...
&CALL_MOD
...
&CALL_MOD
...
RTN            ;End of program
&MOD
NOTE: Macros cannot call macros.
NOTE: Macros do not support numeric expansion.

Compiler Preprocessor

Phase 1 of the compiler checks for syntax, expands macros, checks for duplicate labels, processes virtual labels, and expands multiple digit numbers. If there is an error the compiler will halt and display a useful message. E.g. the following 12C program has an invalid statement on line 3:

11
&SMOD
SIN
The compiler will report:
ERROR: illegal instruction: SIN, line: 3
Errors in macros will be reported as:
ERROR: illegal instruction: SIN, in macro: &TAN, line: 2.1
The 2.1 indicates the 2nd line of your code and the 1st line of the macro.

Phase 2 of the compiler checks for valid GTO statements and completes the processing of the virtual label GTOs. If a GTO has nowhere to go an error message will be produced and the compiler will halt. E.g., the following 12C program has an invalid GTO:

11
&SMOD
GTO A
The compiler will report:
ERROR: Virtual GTO A goes nowhere, post processed line: 8
Line 8? The source only has 3 lines. Finding the source of this error may be difficult with larger programs. This can be addressed with the –phase option. –phase 1 will halt the compile and dump out intermediate results, e.g.
vcomp.pl comp -phase 1 -new 12c -nst 12c.nst foo.txt
Phase 1: Preprocessor
001   1f 1             
002   1f 1             
003   b2 -             
004   d5 LSTx          
005   c5 x<=y          
006 ---- gtostart      
007   dc Rv            
008 ---- gtoa          
The first column is the line number. Column 2 is the byte code. The gtoa on line 8 is the offending statement. The ---- statements require the next compiler phase, to see the byte code and the final GTO statements use –phase 2 after replacing GTO A with RTN, e.g.:
vcomp.pl comp -phase 2 -new 12c -nst 12c.nst foo.txt
Phase 1: Preprocessor
Phase 2: Check GTOs
001   1f 1           
002   1f 1           
003   b2 -           
004   d5 LSTx        
005   c5 x<=y        
006   03 GTO 03      
007   dc Rv          
008   00 GTO 00      
For long programs the –c and –cc options can be used with –phase to columnize the output.

Authors

vcomp.pl was written by Thomas Klemm and Egan Ford.

Test with Nonpareil

To test your program with Nonpareil:

  1. Shutdown Nonpareil. Important! Nonpareil on exit writes out its state.
  2. Compile your program as a new state file.
  3. Replace the Nonpareil state file with your new state file.
  4. Startup Nonpareil.
This process can be simplified if you compile to an existing Nonpareil state file. After closing Nonpareil Windows users would type:
vcomp.pl comp –nst "c:\Documents and Settings\Egan\nonpareil\15C.nst" code.ext
Linux/UNIX users:
vcomp.pl comp –nst ~/.nonpareil/15C.nst code.txt
I prefer this method because all my register and stack variables are still intact.

Accelerate your Nonpareil

Nonpareil will execute your programs at authentic Voyager speeds. It can be very frustrating to have a competition or challenge code take 9 hours just to return the wrong answer. If you have the ability to build your own version of Nonpareil you can speed up program execution by about 200 times.

First edit src/model.c and change the following lines from:

    { "11C",  PLATFORM_VOYAGER,   ARCH_NUT,        40, 215000 },
    { "12C",  PLATFORM_VOYAGER,   ARCH_NUT,        40, 215000 },
    { "15C",  PLATFORM_VOYAGER,   ARCH_NUT,        80, 215000 },
    { "16C",  PLATFORM_VOYAGER,   ARCH_NUT,        40, 215000 },
to:
    { "11C",  PLATFORM_VOYAGER,   ARCH_NUT,        40, 2147483647 },
    { "12C",  PLATFORM_VOYAGER,   ARCH_NUT,        40, 2147483647 },
    { "15C",  PLATFORM_VOYAGER,   ARCH_NUT,        80, 2147483647 },
    { "16C",  PLATFORM_VOYAGER,   ARCH_NUT,        40, 2147483647 },
This will increase the emulated frequency to as fast as possible. Don’t get too excited, you are still limited by the speed of your computer.

Next edit src/voyager_lcd.c, and change:

#define VOYAGER_DISPLAY_BLINK_DIVISOR 150
to:
#define VOYAGER_DISPLAY_BLINK_DIVISOR 0
This will disable the blinking "running". This will not increase the speed of the emulation, but will reduce the OS overhead measurably when running accelerated. This is important for the next step to get the most out of your pimped-out Voyager.

Lastly edit src/proc.c and fiddle with:

#define MAX_INST_BURST 5000
If you make this number too big you will be unable to use the virtual keyboard. This number will vary from system to system. Increase this value by increments of 5000 until Nonpareil becomes unstable (keyboard does not work) or CPU utilization reaches 100% when running your program. For my 2.4 GHz P4 system I have MAX_INST_BURST set to 30000. My CPU utilization is 98%. A program that took 9:37 hours with Nonpareil and a real 15C now runs in 3:05 minutes.

     

It is probably not a good idea to replace your normal Nonpareil. To avoid overwriting when compiling with scons.py do not specify the install option.

Linux example:

To build/test:

cd nonpareil-0.78
scons-local/scons.py
build/posix/nonpareil 15c
When you have a satisfactory supercharged Nonpareil binary, just copy it to /usr/local/bin as nonpareil.fast, e.g.:
cp ./build/posix/nonpareil /usr/local/bin/nonpareil.fast

Test the Real Thing

Unfortunately there is no way to electronically transfer your programs from the virtual to the physical world. But you can use the listing features of the compiler to provide the necessary keystrokes to save time and increase accuracy.

Errata

Reported bug in vcomp 15C listings has been fixed.

Edited: 30 Oct 2012, 9:19 a.m.

Password:

[ Return to the Message Index ]

Go back to the main exhibit hall