HP-IPL/OS Files and Related Material
Notes, News and Other Stuff...
A mirror of these pages is here.
The 1.53 version is somewhat outdated and is not maintained, it
works for what it does but doesn't include new features like erasing
the last package loaded (have to forget words manually) and dictionary
overflow protection (crashes if too much is loaded). New features,
fixes and apps are added to the 1.6x "testing" archive, which although
a bit unstable is probably better for normal usage. Or for the
hard-core hacker, get the hpiplos1.asm source, assemble and run it, and
add packages from the file archives or write your own IPL to build it
like you want.
Refer to the HP-IPL/OS
for notes about changes and the latest applications.
Sometimes minor changes to the testing archive don't get mentioned here.
1/1/12 - Updated testing to 1.65, code changes are trivial (ABS2F no
longer stomps user ZP memory), mostly housekeeping/docs stuff.
7/6/11 - Updated the "testing" archive to 1.64A with a few doc
tweaks, updated the asm21tr.pl assembler, added extasmb.sh for
reassembling the SIO/BCS stuff, added OREGONPT.txt to the BASIC apps.
6/14/11 - Updated the "testing" archive to 1.64, now includes source
code for the vintage tools and reassembled binaries, fixes a few bugs
relating to VDOS (UFSIZE in vdosext.ipl
sometimes failed to return file size, also added to the patch for
existing installs) and running vintage apps (new dms.ipl
swapper clears the B register to keep the BCS linker happy, mkbcs.ipl now runs the linker properly, sioutil.ipl can now slot-patch other
versions of the SIO driver, fixes to altutil.ipl
and dm2.ipl to properly patch HPBASIC for
re-entering, previous solution worked but didn't show the READY
prompt). Updated the files section to include
the latest code, was
previously for 1.5x packages but was getting
really outdated, it should now be possible to build and configure an
up-to-date version of HP-IPL/OS using just the linked text files and a
cross assembler such as Asm21.
11/28/10 - Updated the "testing" archive to 1.62, now includes key vintage software including papertape BASIC, the EXTASMB assembler, FORTRAN and ALGOL compilers and the BCS linker, along with a new "development" build and instructions for using the programs to build applications.
11/23/10 - Updated the "testing" archive to 1.61A with a new version
of VDOS, UDOS for 8KW machines, files for the new PIC-based VDRIVE
interface, and a new vintage.ipl
package for VDOS and the new interface that semi-automates compiling
and linking programs using vintage tools. The new interface uses mostly
the same commands as the
8052-based VDRIVE mods to the IDE interface, but is designed to also
function as a papertape emulator with punch capability with switches
for manually selecting read and write files. The new vdos.ipl and vdosext.ipl
files fix a couple bugs encountered while developing the new
adapter, a patch
can be applied to existing builds without rebuilding.
7/15/10 - Added a link to the new 1.6x "testing" archive, contents
are subject to change however it seems stable enough to use. It's
mainly a repackaging of the previous version with a few updated IPL
packages, a new kernel that detects dictionary overflow and records the
position of the last package that was loaded, and more docs, tools and
source code. The updated IPL's include print.ipl,
and hpscreen.ipl. The new package
includes source code for the included MSU BASIC binary in case the
version on the MSU
page changes (the present version outputs rubout characters
that disturb some terminals, at some point I'd like to fix that), and
source and information for connecting a VDRIVE module to the IDE
interface to permit accessing files on a USB thumbdrive (see the IDE USB page
for more info). The matching VDOS packages are fairly generic,
theoretically they can be adapted to a non-disk version of a VDRIVE
interface that supports the same firmware commands. Keeping the older
version 1.53 around for now, other than a few bugs in a few optional
packages it was quite solid... the dictionary overflow issue wasn't
exactly a bug but a documented "feature", didn't really bother me until
I found myself ducking and dodging too much about what to do when the
dictionary got stuffed or a partial load needed to be removed... so
fixed the kernel to reduce those instructions to basically "if a
dictionary overflow or other error occurs enter ERASE to remove the
failed load".. better.
9/1/08 - Version 1.53 posted, with fixed dm2.ipl and a new sfslib.ipl library system (replaces
lib2.ipl, a2l.ipl and ms2l.ipl, removed a few other outdated IPL's),
the library file is now plain text without the inconvenient terminator
byte of previous versions which caused problems if a library add not
complete properly. Fixed a bug in LFORGET (only matched the specified
part of specified string, like having a * wildcard after the name...
not fixed in the older versions in the text archives). Summary.txt now has more SFS and library info,
added a new ipl_notes.txt file describing
the included IPL's, orders and dependencies, and a place to put extra
IPL code. Has updated IDE builds with the new library system, the other
builds didn't change.
8/9/08 - Version 1.52 posted, adding code to SFS
to ensure that
buffer memory actually exists before attempting to buffer a directory
(otherwise the directory can be updated with all zeros... ouch). Added
the MSU BASIC specific menu (dm2.ipl) and
other code (binpatch.ipl, msupatch.ipl, sham.ipl)
archive self-sufficient, assembly source and docs can be obtained from
the MSU BASIC
page. After my files went away after
trying to use SFS with
non-existent memory (fortunately my IDE disk was just a copy of the
7906 sim disk) figured it'd be a good idea to make a file backup
utility for spitting out files via the console (in bkfile.ipl), it's crude and very slow but
better than nothing (I don't have PTP on my machine to use the more
direct "FILE" F2MS).
4/9/08 - Version 1.51 rev J posted, fixing a bug in the editor's
LDFILE word and less wiggle when moving the cursor. Demo build updated
with the improved version although wasn't affected by the bug.
3/29/08 - Version 1.51 rev G posted with an updated editor and
"demo" build. This version was derived from the 1.51G sim version
(hence the G) and has faster screen updates, avoids file growth and
fixes bugs in the utilities package. No changes to the other 1.51
2/14/08 - Version 1.51 posted, using the 1.5 kernel that uses 0's
(NOP) in the interrupt vector table and adds a CLC 0 to the startup
path to make sure every device starts with control bit clear. This
update fixes the CREATE ASC crash bug and a couple of utility bugs. The
includes IPL's for the base version of an editor
I made (included in the "demo" build), more docs for the build/sim
scripts and Windows versions of
batch files for launching ABS files under the SimH HP2100 simulator,
and for using the HPASM and Asm21 cross-assemblers.
12/18/07 - Version 1.4 fixes several mostly minor (and a couple not
so minor) issues and adds a printer driver and a build for 16KW
machines. The IDE builds are back into the main archive, now with the
essential details for building an IDE disk interface. Also rewrote some
of the outdated text on this page, in particular the "Running
11/19/07 - Fixed the IDE builds, added a fast
system, v1.31 now. Working on putting together my own IDE
interface for my machine.
10/14/07 - The recent 1.1 and 1.2 builds did not work on real
hardware, updated to v1.3. Was working on trying to solve long-time
problems with the TBG "PTIME" clock freezing after certain I/O
operations, restricting it to slot 10, while at the same time dealing
with other interrupt-induced issues like some binaries freezing if
loaded when the TBG is active... that one seems to be fixed now by
making a new PRESET word and calling it before doing binary loads.
1/28/06 - HP-IPL/OS now has floating point! Float.ipl implements basic FP functionality by wrapping existing HP instructions. Floatext.ipl implements double-int and string conversions and includes a square-root function written in IPL using an ancient algorithm, eventually this should be converted to machine code or at least optimized so this should be considered a work in progress. Ecal.ipl is a menu-driven electronic calculator program containing many of the calculations I'm always having to figure out manually. Most of these words require the double.ipl package if not already loaded.
It is easy to express complex formulaes as stack operations.. for
example a calculation like 5.1/(4.5+(3.4*7.8)) can be performed in
"5.1" $>FP "4.5" $>FP "3.4" $>FP "7.8" $>FP ;push FP numbersFP numbers are stored as two 16-bit elements on the stack, use DSWAP to swap FP numbers, and use OVER OVER to duplicate. A number can be squared by using OVER OVER FP* to multiply it by itself. Things like ^ (which would greatly simplify FSQR since a square root is n^0.5), sine, cosign, tangent, etc can eventually be implemented, there's lots of stuff like that embedded in various HP Basic asmb sources floating around.
FP* ;calculate 3.4*7.8
FP+ ;add 4.5 to above result
FP/ ;divide 5.1 by above result
FP>$ $PRINT ;print answer .16441, correct to 6 places
8/13/05 - The SFS 0.69 builds contain a bug in the FCOPY and FMOVE utilities, if the destination file exists they produce errors and leave the buffers occupied. Worse, FMOVE deletes the source file even though the copy didn't take place. Both of these bugs are fixed in the new 0.70 sfs.ipl.txt and sfsutils.ipl.txt files [updated in current distro]. Besides fixing the copy/move bugs, the BCOPY word was deemed too essential to be in the utilities package and was moved to the main SFS package, a new word FDUP was added to the utilities for duplicating a file in the current directory, and the utilities were modified to use buffers 1 and 2 leaving buffer 0 alone for the user and the new experimental editor which still needs a lot of work.
7/17/05 - Bits And Pieces...
7906 BE utility in ASMB format
octapus-c.txt · original source and docs, decrypted from the Interex site
This has been an exciting week of playing around with antique software, so exciting had to delete my previous ramblings to stay on topic :) Many thanks to those who rescue tapes, configure and share systems, archive sources and issue licenses so that these historical programs can be preserved.
7/7/05 - Updated the HP photos page with new pictures of Bob's
and peripherals, including one with many lights blazing (I don't know
many were blinking) and a cool vector graphics display.
[old moldy notes removed]
Around the beginning of 2002 I became interested in the HP2100-series of mini-computers. It started when I ran into a program called SIMH by Bob Supnik that simulated a number of vintage computers, including the PDP-8 which facinated me along with a terse multi-user DOS called TSS/8. I knew Bob Shannon owned HP mini-computers, also simulated by SIMH so I proposed writing a DOS for it too, since at the time about all I could do with it was run HPBASIC. Bob fired back with this idea of his called "HP-IPL/OS", which stands for Hewlett Packard Interpretive Programming Language / Operating System. Its philosophy is summarized in this excerpt from a Jan. 31, 2002 email from Bob...
There can be no argument that a Forth system is the fastest, easiest
way to bootstrap a machine with only an assembler to work with. It's
also by far the most code-efficient approach.
But the problem is, Forth is ugly and nasty to my eye. Something much
nicer can be developed using the same structure and methods, and this
will give the HP collector something useful to get whatever configuration
they might have up and running quickly.
Please remember, I don't want to implement Forth itself. I want to build
something that works the same way, but is easier to use.
I've been working on HP-IPL/OS since then, taking rough code and ideas and making them work. Seven months later I still don't have the DOS I originally wanted, but at least I'm closer to being able to implement it. What we do have now is a threaded language/operating system that is programmable both in high-level "IPL" and in HP assembly that can be used to implement a wide range of algorithms and applications for the HP mini-computer.
HP-IPL/OS is set up to use the following default slot assignments...
The TBG board in slot 10
The TTY console board in slot 11
The paper tape reader board in slot 12
The paper tape punch board in slot 13
The 13181 mag-tape boards in slots 14 and 15 (hard-coded)
The dual XY (scope-driver) board in slot 20 (hard-coded)
The HPIB interface board in slot 21
The BACI interface board in slot 22
(hard-coded) - slots are hard-coded in the source code, edit to
Unused slots up to the last installed board should contain jumper-boards.
Before running, if TTY is not on 11 then load location 355 octal
the TTY channel number. If using a 32K build you can use CONFIG
to change the reader and punch channels, for the 8K and 16K builds poke
356 with the punch channel and location 357 with the reader channel
running HP-IPL/OS. If booting builds containing TBG support and TBG
isn't in slot 10, autostarting words must be disabled before running by
putting 177777 in the switch register.
Run from location 2 to start HP-IPL/OS. Some builds permit reconfiguring via the switch register, put the TTY slot in bits 0-5, the BACI slot in bits 6-11, set bit 12 to select a BACI console or set bit 15 to disable autostart words, and run from location 70 (instead of 2).
Booting on real hardware, assuming slot assignments have been resolved...
Get your paper-tape reader emulator ready with the build you wish to
Select S register, make 001200 octal, with the 12 being your PTR slot. Store.
Preset. IBL. Preset. Run - the PTR emulator should start sending the file.
After loading, the bottom 6 bits will remain lit on the front panel if the load was good.
If successful, select P, clear display, set bit 1 (location 2), store, preset, run.
You should get the ? prompt. Load in desired options and
by attaching to the paper-tape reader and entering LOAD at the prompt.
<PTR must be used to load "IPL" files into the 8K kernel, the first
files loaded when making a build from scratch should probably be
extra.ipl (permits selecting the memory configuration and in addition
to LOAD provides words used by most of the other IPL files), and an
oct??.ipl specific to the memory requirements (in addition to Octapus
provides a SYSALL which can be used to save the configured build to the
The create.ipl file (and smallcre.ipl for 16KW machines) permits
loading options which include assembly source, these packages must be
positioned carefully in the load order so that the assembled machine
code does not cross a 1KW binary, using the WORDS command to display
the current end of dictionary (EOD), try to position such loads so that
EOD is right after a page boundary (42000, 44000, etc), depending on
the size of the machine-coded portion. If a page boundary is crossed
generally a "page error" occurs, use FORGET to remove the 1st word
defined by the offending package and load something else before it to
push EOD past the boundary. Arranging packages to avoid errors can be
tedious at first but easy to predict by keeping track of where EOD is
and estimating the size and positioning of assembly code in the IPL
file. Often I simply proceed until there's a problem then FORGET and
try another order.
Dictionary memory is a limited resource, do not overflow it by
loading too many packages at once. There is no protection against
overflowing but the situation is easy to avoid by not loading big stuff
when the amount of free memory reported by WORDS is low. An overflowed
dictionary can be detected after the fact by doing WORDS after the
load, if word names appear as [addresses] instead of word names you're
in the weeds, immediately do 0 ALLOCATE, WORDS, then FORGET the
overflowing words, afterwhich do 2 ALLOCATE to restore the "safety net"
provided by block memory. The DMS build has 4 blocks allocated by
default, if using that as a base do 3 or 2 ALLOCATE to provide more
dictionary space. CREATE and disk applications require at least 2
blocks, some applications require more.
HP-IPL/OS does not waste code protecting a user against things that
simply should not be done, and does not block the execution of commands
that can corrupt the system in memory. To do so would limit its
usefulness, for example PUT can change any memory location which I
often use to "edit" constants in words after they've been loaded and is
used extensively by IPL packages to modify the setup. Using PUT
incorrectly is guaranteed to damage something somewhere. Adding code to
protect against dictionary overflows would unnecessarily increase build
sizes for no real benefit, and trying to implement a means to support
"relocateable" machine code would require so much code it'd be no
longer possible to have a system able to implement programming, a disk
operating system, utilities and applications all in memory at once. If
such abilities are needed consider using tools such as SIO and BCS
which permit constructing large applications from relocateable modules
written in FORTRAN, ALGOL and assembly. HP-IPL/OS can be used as an
operating system on 64KW+ machines for loading arbitrary binary
applications up to 31KW from disk or papertape, and provides a means to
return to HP-IPL/OS and even save programs written in paper-tape BASIC
to disk files or ABS binaries.
System generation using real hardware...
If you're lucky enough to have a 13181/7970 mag-tape setup you can use the MTGEN word to create new boot files. I've captured bootable files using the BACI interface and a Visual Basic program that captures serial data to a file. I was not able to get reliable results by using Hyper-Terminal's capture option, your results may vary. Probably the best way to generate configured builds is use the SYSALL command to punch them to a paper-tape punch (PTP) emulator. These can take the output and store it in an eeprom chip or if so designed transfer the data directly to an ABS binary file on a PC. A couple of eeprom-based PTP emulators exist but I don't have one. Another option is to use CONGEN (in congen.ipl) to dump the build to the console as encoded text which can be captured to a file and converted to an ABS binary using log2abs.ipl running under simulation. 64KW+ MX machines can use the version in conalt.ipl which also provides words for directly loading text-encoded binaries via the console.
Booting and System Generation using the Simulator...
The main HP-IPL/OS archive contains SimH scripts for generating the
various provided builds and running them under simulation, and the Simulating HP-IPL/OS page gives
instructions for building HP-IPL/OS builds by placing the IPL files
onto a simulated magtape. HP-IPL/OS builds can be made from scratch
under simulation by running the SimH HP2100 program and issuing
commands (or running scripts) to set the machine type and slot
configuration, load the kernel and attach files to PTR to load. For
example... (assuming the kernel abs and IPL's are in the current
sim> set cpu 21mx
sim> set cpu 256k
sim> set clk dev=10
sim> set tty dev=11
sim> set ptr dev=12
sim> set ptp dev=13
sim> set tty1 7b
sim> load hpiplos1.abs
sim> run 2
HP-IPL/OS 8K V1.4
? [ctrl-e pressed to halt]
Simulation stopped, P: 02226 (JMP 2225)
sim> attach ptr extra.ipl
[enter pressed to show prompt but not necessary]
1) keep existing setup
2) 16K w/ 2 blocks
3) 16K w/ 2 blocks and 2K hi-mem
4) 32K w/ 4 blocks and 4K hi-mem
Configured to 32K w/himem
Simulation stopped, P: 02225 (SFS 11)
sim> attach ptr oct70.ipl
Loading OE and OE?
Decoding 32K OCTAPUS-E binary (70000-72352)
Simulation stopped, P: 02226 (JMP 2225)
sim> attach ptp base32k.abs
PTP: creating new file
Simulation stopped, P: 02225 (SFS 11)
sim> detach ptp
sim> load base32k.abs
sim> run 2
HP-IPL/OS 32K V1.4
Paper Tape Reader Emulator
To get software into my HP2113 I use a little black box that Bob
constructed for me. I will try to obtain plans and code for it so that
I can get it on-line. The device contains a PIC (microcontroller) that
interfaces between the HP's paper tape reader interface to a serial
on the PC, and uses a very simple handshake method for transfering
when the HP is ready to receive a byte it sends a "!" character
to the PC (byte 33 decimal), waits for the PC to respond then sends the
received byte to the paper tape reader interface. Bob uses a
Visual Basic program called "Virtual Tape" to send program files
to his PTR emulator (which is different than mine, his includes rom
for quick booting), I used to use a home-made
but unfortunately my entry-level VB compiler didn't support the serial
port so I had to use a work-around called XMCOMM. Here are the
binaries for an earlier version of HpLoader for
Windows. Since then I
upgraded to Linux which gave me back my serial port so now I use
DosEmu/FreeDos to run a simple Dos/QBasic program called HPSEND to
Reversed-engineered documentation for the pass-through PTR emulator
is on the HP Mini Projects
page, along with details for constructing an IDE
HP-IPL/OS implements an indirect-threaded interpreter engine with five stacks, the System stack which is used for general storage and passing parameters, a Return stack used to hold return addresses and loop points, the X stack for passing string data, and Y and Z stacks to assist with string manipulation and general data storage. In addition to stacks, HP-IPL/OS programs can use any unused area of memory for data storage, or use "blocks" of memory which can be allocated in 1K-word increments. HP-IPL/OS' "instruction" pointer is called the Word Address, or WA. Word as in a word like NOT or XOR to execute, not to be confused with a 16-bit word. The contents of the location addressed by WA is called the Code Address and points to machine code to execute. After executing the machine code normally exits by jumping to a routine called NEXT, which increments WA and interprets the next instruction. If the CA points to a routine called ENSEC, or Enter Secondary, the next WA in the "thread" is saved on the return stack, and CA is pointed to the location following ENSEC. Execution follows the new thread until the CA for RTSEC, or Return from Secondary, is encountered, then the previous thread's WA is popped and execution resumes at the location following the call to the secondary word.
New words can be defined by combining existing words, in this way a complex language can be devised from primitive low-level words. To express literal data, special CA's that push integers and strings are used, these parse the data and advance WA (or the input buffer pointer in the case of console entry) past the data. This is handled automatically, you just enter the number to push it to the S (system) stack, or a string surrounded by quote marks to push it to the X stack.
Simple examples... (PNUM is a definition that pops the S stack and prints the number, ? is the HP-IPL/OS prompt)
? 2 2 ADD 3 SUB PNUM
? 5 5 MUL PNUM
000031 (default is octal numbers, 31 octal = 25 decimal)
? DEFINE HELLO (prompt will change to >)
> "Hello World!" $PRINT END
? DEFINE HELLOS
> 1 3 +DO HELLO +LOOP END
Hello World!Hello World!Hello World!
Now for a shocker...
DO LOOP +DO INDEx +LOOx IFNZ IFZ IF<0 ENDIx ELSE UNTIx WHILx CASE = < > <=
>= <> DEFAxxx ENDCxxx EXECxxx AND OR XOR ADD SUB INC DEC NOT 2CPL DUP DROP
OVER ROT SWAP GET PUT PNUM CRLF DECIxxx OCTAx BINAxx RADIx SP>S SB>S XP>S
XB>S YP>S YB>S ZP>S ZB>S END DEFIxx DMPS S>SR SR>S PCHR PWRD $PRIxx S>X X>S
S>Y Y>S S>Z Z>S MUL DIV ASL ASR ROL ROR PNExx RUN X>>Y X>>Z Y>>X Z>>X $SWAx
$CPY $DUP $DROx $LEN $ADR $XTExx $PUT $GET $CRExxx CHRIx RND RESTxxx $STR
$HEAx $APPxxx $TAIx $IN $CAT $VAL <>COx >PTP <PTR MSBOxx MSBIx MSWOxx MSWIx
MS$Oxx MS$Ix MSCRxx PTZExx EOD CONFxx MSPAxxx INBLxxx OUTBxxxx GETIx SETIx
GETOx SETOx >MS <MS BACI MSBAxx <BACx >BACx MTRExx MTWRxxx GAP GAPMxxx
MTINxx FS1R BS1R FS1F BS1F RWLP RWOL MTSTxxxx DEBUx TOKEx SDIC #0 #1 @TL
@TB1 @TB2 @ANVxx @ENSxx @CLH @LITxxxx @STRxxx @RTSxx @DIC @USR @BLK @END
@DIPxx HEADxxx PDEF EXPLxxx ADDCxxx ADDHxxxxx ADDHxxxxxx FIXLxxxx ADDMxxxx
VARIxxxx CONSxxxx ABSOxx SYSGxx SYSAxx OCTAxxx ODHExx ODSExxx DUMP MARKxxx
GLOBxx SETCxx FORGxx ERASx ZEROxxxxx CONSxxx FETCx STASx WORDx ALLOxxxx
BPUT BGET HIDExxxx RENAxx DELExx MTWAxx ?MTExxxx EOF RECOxxx FILEx MTSCxx
MTGEx DMS -DMS SDMA UDMA UJUMx SJUMx SPAGx C>ACxxx A>CCxxx USPAxx DMSTxxxx
BACIxxx TTYCxx ABSLxxx MSUSxx MS_Sxxx MS_Rxxxxxx $DEFxxx WHERxxx VERSxxx
UNDExxxx CREAxx !IRQ -IRQ +AUTx -AUTx +ADB -ADB +TBG -TBG >TBG TBGZxxx
!100xx T>>S TIMExxx PTIMx HELLx HELLxx
WORDS displays the machine names of all the words in the "dictionary", or collection of words that can be executed or used to define new words. At the end is the HELLO and HELLOS definitions, or at least what HP-IPL/OS calls them. Only the first four characters and the length of a definition's name are significant, in listings the unknown characters are indicated by the xxx markings. By doing it this way, HP-IPL/OS needs only three 16 bit words to store the name of any definition no matter how long its length is, and dictionary search and manipulation code is greatly simplified. Be careful when choosing names, TEMP1 and TEMP2 are both TEMPx to HP-IPL/OS. This does not mean you can't have long readable names, just avoid names of the same length with the same 1st four characters, and keep your source code.
You can list high-level words (defined using existing words) using the console command EXPLAIN DefName. Word names with lengths greater than 4 will be printed using the same 1ST4xxx encoding used by WORDS. Definitions are not stored in text form, rather they are compiled as entered and decompiled when listed by EXPLAIN. You cannot edit dictionary definitions, that would be like trying to edit Pascal's P-code. Rather you should retain your human-readable source code and edit that, then reload it back into the HP-IPL/OS dictionary to effect changes. Multiple copies of definitions are allowed, when defining new definitions if multiple copies are present, the last one will be used. However any definitions using the previous copy will not be changed, it will still contain a call to the original. To effect a global definition change (like fixing bugs in an existing definition already being used) the definition must be fixed at the HPASM assembly source level. Most of the later high-level definitions were written in high-level form, when making changes to these I use the MKHPASM.IPL application to output HPASM source which I paste over the existing definition (along with any required editing fixes, MKHPASM is a great help but isn't perfect) then reassemble HP-IPL/OS.
Several console commands are available to assist in dictionary maintenence. RENAME DefName NewName does as expected, DELETE DefName renames a definition to " ", not a true delete but avoids confusion when developing. HIDEDUPS DefName performs this function after new definitions with the same name have been entered, all duplicates will be renamed to a single space. With both of these there will still be artifacts (extra spaces) in the WORDS display to let you know the dictionary contains wasted space. If you decide you liked the original better you can UNDELETE to search for and give a name to deleted definitions. You can truly delete definitions from the end of the dictionary using FORGET [DefName]. If no parameter is specified the last definition is removed from the dictionary after confirming. If a name is specified, that and everything after it will be removed. You cannot forget base definitions that exist in the HPASM assembly source, however you can hide them using delete or hidedups. To erase all user-entered definitions (anything not in the HPASM) use the ERASE command.
Any definition (word) whose name begins with the "!" character will auto-execute whenever HP-IPL/OS restarts for any reason. This is a relatively new feature and still subject to change - presently loading 177777 into SR before running HP-IPL/OS will disable auto-start. While running you can turn auto-execution on and off using +AUTO and -AUTO. If you want autostarting to occur only once in a session no matter how many restarts, simply define something like...
... then regenerate the system using SYSALL or whatever method you employ. When the new system boots, all the words beginning with ! will execute including !NOAUTO which turns auto-execution off. Don't forget to do a +AUTO before generating new builds after doing this. The autostart flag is located at 465 octal, make 0 to disable.
Console vs. DEFINE
The console is the ? prompt that you type commands directly to HP-IPL/OS, DEFINE defines a new thread that you can execute. At the console flow-control words like +DO IFZ etc are totally disabled. Even things like $DEFADR or WHEREIS cannot find them since the start of dictionary pointer is moved past them when at the console. When you use DEFINE to define a new definition the start of dictionary pointer is set to the true beginning, allowing flow control words to be used. At the prompt there is no pointer like WA and no return addresses, only a text buffer pointer and a function called TOKEN that gets the next word from the text buffer. While you can't use conditionals and loops at the prompt, you can define definitions that obtain parameters After the command word, in normal fashion rather than the reverse notation normally forced by threaded languages. At the prompt you can have things like RENAME DEFNAME NEWNAME and WHEREIS DEFNAME and FORGET MYDEF.
RENAME, WHEREIS and FORGET are examples of console-only words that obtain parameters from the text buffer. Console-only words should normally not be used in definitions, if you absolutely insist then they will obtain their parms from the input buffer, you cannot define their normal usage. What you can do though, is redirect MS (mass-storage) output to a memory block (0 OUTBLOCK), write your commands to execute (using MS$OUT and MSCRLF), follow with a CONSOLE[crlf], redirect MS input to that same block (0 INBLOCK), then redirect MS into the console (<MS).
"Streams" as applied in the following refer to 8 bit data quantities passed by sending or receiving the A register by calling a machine-coded subroutine vector. You don't have to know that to use streams but that's what's going on behind the scenes. The provided input and output words generally send or receive information from either Standard Input/Output or Mass Storage Input/Output (MS). By poking subroutine addresses into the vectors which are called, the data can be directed to/from any device that a driver can be programmed for. HP-IPL/OS comes with driver code for the TTY 2400 baud interface, paper tape reader and punch (note.... punch code works fine under simulation but Bob tells me it won't work on a real punch board unless modified - I hope those mods don't affect the simulation!) and the BACI serial interface. PTR (reader), PTP (punch), BACI or TTY can be freely assigned to Standard Input, Standard Output, MS Input or MS Output by poking driver sub addresses into those vectors.
Standard Input is read by the console itself and the following...
$IN · accepts user input up to but not including CR and pushes to X. LFs are ignored.
CHRIN · accepts one character from user and pushes to S
and anything using those words to get user input.
Standard Output is written to by the console and...
$PRINT · pops a string from X and prints it
PCHR · pops an ascii code from S and prints it
PWRD · pops a double-character from S and prints it (high byte is the 1st character printed)
CRLF · prints a Carriage Return followed by a Line Feed
PNUM · prints a number in the selected radix (binary, octal or decimal)
...and anything using those words to display user output. Note that the console prompt (CRLF then ?) is not sent to Standard Output but rather to a console vector which typically is set to TTY or BACI.
Mass Storage Input is read by...
MS$IN · inputs a string from MS up to but not including CR and pushes to X. LF's ignored.
MSBIN · inputs one byte from MS and pushes to S
MSWIN · inputs two bytes (or one word) from MS and pushes to S (1st char goes in the high byte)
...and anything using those words to obtain MS input, including ABSLOAD.
Mass Storage Output is written to by...
MS$OUT · pops string from X and outputs to MS
MSCRLF · outputs CRLF pair to MS
MSBOUT · pops byte from S and outputs to MS
MSWOUT · pops word from S and outputs to MS (as two bytes, the high byte 1st)
...and anything using those words, including ABSOUT and things that use it like SYSALL.
The following built-in definitions redirect one way or another...
<>CON · sets standard input and output to the TTY console
CONSOLE · sets standard input/output to TTY and sets MS input/output to PTR/PTP
<PTR · sets standard input to PTR, this is usually the easiest way to load HP-IPL/OS code
>PTR · sets standard output to PTP, useful for directing a program's output to a file under simulation
<BACI · sets standard input to the BACI interface
>BACI · sets standard output to the BACI interface
MSPAPER · sets MS input and output to PTR and PTP
MSBACI · sets MS input and output to the BACI interface
INBLOCK · pops stack and sets MS input to that memory block
OUTBLOCK · pops stack and sets MS output to that memory block
MS_SAVE · saves MS input and output vectors
MS_RESTORE · restores MS vectors saved by MS_SAVE
MSUSER · sets MS input and output to the user memory map using the top of stack as a pointer
Note that < > etc have no significance (not parsed) other than being part of the word's name. < implies directing into (HP-IPL/OS) and > implies directing out of. These symbols are used in some word names to imply flow from one thing to another, such as S>Z to transfer an item from the S stack to the Z stack, or X>>Y to transfer a string on X to Y. Other words like IF<0 and the CASE tags use < and > to indicate less than and greater than.
Presently, HP-IPL/OS only has what I call "raw" MS drivers that always work on byte quantities. Why bytes? Because that is the smallest unit of transfer and the only way to guarantee no state-switching problems when redirecting is if the system also, at the lowest level also transfers one byte at a time. Each raw MS driver subroutine must maintain its own internal state when dealing with 16 bit or blocked data to assure nothing bad happens when going back and forth between things. The user should not have to worry about this at all, and you don't have to unless you're actually writing driver code.
Writing HP-IPL/OS Programs
This is a (rough) collection of syntax and usage notes grouped by function, refer to the summary.txt file for a list of all of the stock words and (terse) descriptions of what they do.
Unless otherwise noted, all numbers are expressed in octal and the
is the system stack. TOS means "top of stack", or the last value pushed.
Manipulating Stacks and Memory...
100 777 PUT writes 777 into memory location 100
100 GET pushes the contents of location 100 to the stack
S>X pops a value from the stack and pushes to the X stack, or transfers from S to X
X>S transfers a value from X to S
S>Y Y>S S>Z and Z>S do similar transfers to and from the Y and Z stacks
X>>Y transfers a string from the X stack to the Y stack (using the Z stack as a buffer)
Y>>X X>>Z and Z>>X work similarly
DUP duplicates the top stack entry by pushing it again, 2 DUP yields 2 2 on the stack
SWAP swaps the two top entries, 2 5 SWAP yields 5 2 on the stack
OVER duplicates the next-to-top stack entry, 2 3 OVER yields 2 3 2 on the stack
ROT rotates the two stack items over the top one, 1 2 3 ROT yields 2 1 3 on the stack
DROP removes a stack entry without doing anything else
10 ALLOCATE allocates 10 (8 decimal) 1K-word memory blocks
0 100 777 BPUT writes 777 to block 0 offset 100
0 100 BGET pushes the contents of block 0 offset 100
@BLK pushes the address of a variable containing the actual start of memory blocks
therefore @BLK GET pushes the actual start of memory blocks
Variables and Constants...
VARIABLE and CONSTANT are console commands, they cannot be used inside a definition. Of course the variables themselves can be used inside definitions or there wouldn't be much of a point in having them. You can hide variables and subroutine definitions between ~ and ~~ markers using MARKCON, GLOBAL and SETCON if you want to clean up the WORDS display and prevent other definitions (besides the one using them) from being able to see the names. Variables push the address of the variable's memory location when run, constants push the actual number.
VARIABLE ABC creates a variable named ABC
VARIABLE ABC 100 creates a variable named ABC with room for 100 entries
ABC 555 PUT puts 555 into the ABC variable
then ABC GET pushes the contents of ABC to the stack
CONSTANT TCON 123 creates a constant named TCON with a value of 123
then TCON pushes 123 to the stack.
2 2 ADD pushes 4 to the stack
5 2 SUB pushes 3 to the stack
2 3 MUL pushes 6 to the stack
6 2 DIV pushes 3 to the stack
INC increments the item at the top of the stack (TOS), DEC decrements it
ASL shifts TOS left by one bit, filling bit 0 with a zero bit
ASR shifts TOS right by one bit, filling bit 15 with a zero bit
ROL and ROR rotate the TOS left or right by one bit
NOT inverts the TOS, 1 bits become 0 and vice-versa
2CPL does a 2's complement on the TOS, inverting the sign
AND pops two stack items, does a bit-wise AND function and pushes the results
OR and XOR do bit-wise OR and XOR functions
The stack makes the parenthesis of algebraic languages unnecessary but with only integers you probably won't be doing much algebra anyway... but to illustrate using an integer example, something like (3+5) * (2+6) can be computed by...
3 5 ADD 2 6 ADD MUL
IFZ, IFNZ and IF<0 pop the stack and branch accordingly.
IFZ code that runs if TOS was 0 ELSE code that runs if TOS wasn't 0
IFNZ code that runs if TOS was not 0 ELSE code that runs if TOS was 0 ENDIF
IF<0 code that runs if bit 15 of TOS is set (negative) ELSE etc ENDIF
IF varients can be nested as deep as you want but there must be a matching ENDIF for every IF. ELSE and the "not-true" code are optional.
CASE pops the stack and branches according to comparisons with
variables or a literal number. The general form is...
optional structures [inside brackets]
number to examine is on the stack, popped by CASE
condition is one of the following: = <> < > <= >=
comparison is a literal number, a variable or a constant
condition comparison code to run
[condition comparison more code to run [...]]
[DEFAULT code that runs if no condition is true]
Example CASE usage...
CONSTANT CN_A 123
CONSTANT CN_B 456
= CN_A "Constant A detected" $PRINT
= CN_B "Constant B detected" $PRINT
= 0 "Zero detected" $PRINT
DEFAULT "No constants detected" $PRINT
Constant A detected
Constant B detected
No constants detected.
If more than one condition is true only the first occurence is acted upon.
"Hello" " World" $CAT yields "Hello World"
on the X stack
"Hello" $DUP yields "Hello" "Hello" on the X stack
"Hello" "World" $SWAP yields, you guessed it, "World" "Hello" on X
"Hello" $HEAD yields 110 (octal) on the system stack (ascii "H") and "ello" on X
"Hello" $TAIL yields 157 on the system stack and "Hell" on X
"Hello" 41 $APPEND yields "Hello!" on X (41 is octal ascii "!")
"Hello" $LEN pushes 5 to the system stack (string is unaffected)
"Hello!" 5 $GET pushes 41 to the system stack (string unaffected, positions begin at 0)
"Hello!" 5 56 $PUT yields "Hello." on X (56 is octal ascii for ".")
"Hello" $ADR pushes the address of the "He" part to the system stack
$XTEST verifies that the address at the TOS lies within the top string, else STRING ERROR
"123" $VAL yields 123 on the system stack, string is removed
DECIMAL "123" $VAL OCTAL yields 173 octal on the system stack and returns default to octal
123 $STR yields "123" on X, number is popped
Input and Output...
See the section above about redirection.
"Hello" $PRINT prints Hello to standard output
123 PNUM prints 123 to standard output
41 PCHR prints ! to standard output
52116 PWRD prints TN to standard output
CRLF sends carriage return / line feed to standard output
"Hello" MS$OUT sends Hello to MS output
123 MSBOUT sends the byte 123 to MS output
123456 MSWOUT sends the word 123456 to MS output
$IN accepts a string from standard input, up to but not including return, and pushes to X
CHRIN accepts one character from standard input and pushes to the system stack
MS$IN works about the same way but gets a line from MS input
MSBIN gets one byte from MS and pushes to the system stack
MSWIN gets one word (2 bytes) from MS and pushes to the system stack
from to ABSOUT encodes memory and sends to MS in ABS format
PTZERO sends 20 zeros to MS for terminating ABS files
SYSALL encodes HP-IPL/OS and Octapus to ABS and sends to MS
OCTAL sets number interpretation and printing (radix) to octal
DECIMAL and BINARY to set radix to decimal or binary notation
RADIX pushes the current radix to the stack
WORDS displays the (encoded) names of all words in the dictionary (except for hidden words)
EXPLAIN DefName displays the contents of high level definition DefName
"DefName" $DEFADR PDEF does the same thing but can be done from inside a definition
"DefName" 0 STASH saves the definition in text form to memory block #0
0 FETCH interprets whatever is in block #0, if a stashed definition it is re-entered
FORGET DefName removes DefName and everything after it from the dictionary
just FORGET removes the last definition
ERASE removes all definitions that have been entered, leaving only the stock dictionary
RENAME DefName NewDefName renames a definition
DELETE DefName doesn't really delete, but effectively hides a definition by renaming to space
UNDELETE scans for deleted definitions and if directed prompts for a name to "undelete" it
HIDEDUPS DefName hides all occurances of DefName except for the last one
CONFIG lets you reassign the PTR, PTP slots
DEFINE defines new high-level definitions, END returns control back to HP-IPL/OS
CREATE creates new machine-coded words
DEBUG turns on the thread debugger
OE runs the Octapus-E utility
OE? displays a help screen then runs Octapus-E
This is an assembler which is used to create low-level words for HP-IPL/OS. It is mostly HPASM compatible but differs in several ways...
Up to 6 characters can be used for labels, which cannot begin with
Multiple OCT numbers are not supported.
No ORG - you're creating a word so origin is always right after the new word's header.
Except for ASC and DEC, all literal numbers in instructions are interpreted as octal. Any trailing-B is ignored.
Compound instructions should be correctly generated, HPASM has trouble with some combinations
Only one bit-modifier such as ,I for indirect can be specified. Z/C determined automatically by context so normally you do not need to specify unless you're writing something really weird.
Partially supports extended instructions, you have to manually specify the extra words using DEF/OCT etc.
Anything beginning in the 1st column is a label, instructions must begin in the 2nd column or later. Same as with HPASM. Although CREATE isn't exactly HPASM-compatible it is relatively easy to convert from one to the other if not a straight cut and paste.
Many HP-IPL/OS locations and subroutine vectors are pre-defined...
JSB ZSPSH,I pushes A to the system stack
JSB ZSPOP,I pops the system stack into A
also available are ZRPSH, ZRPOP, ZXPSH, ZXPOP, ZYPSH, ZYPOP, ZZPSH and ZZPOP.
TMP1 TMP2 TMP3 and TMP4 are available for temps
the stack pointers are SP RP XP YP and ZP
JSB ZCOUT,I sends the low byte of A to standard output
JSB ZPTWD,I sends both bytes in A to standard output
JSB ZCRLF,I sends a CRLF to standard output
JSB ZPBFL,I writes a string of double-characters to standard output, #words in A, address in B
JSB ZCHIN,I returns one byte from standard input in A
JSB ZMOUT,I sends a byte in A to MS
JSB ZMINP,I returns a byte from MS in A
JSB ISAVE,I saves processor state and turns off interrupts
JSB IREST,I restores processor state and turns on interrupts
JMP ZNXT,I returns control back to HP-IPL/OS
END when used as an instruction parameter points to the end of the created word, when it gets to it.
END starting in the first column assembles a JMP ZNXT,I and terminates CREATE.
CREATE takes care of creating the header and the code address (DEF *+1 in HPASM) and all that, you only need to enter the instructions you want to run. For example...
...creates a word called SETO that turns on the overflow flag.
CREATE uses memory blocks 0 and 1 by default for storing symbols and fixup points. Although single-pass in that you only need to feed the source in once, it makes another pass to put addresses and equates into locations that refer to labels. Forward references are not a problem so long as you eventually add the refered label and code. If not you'll get error messages during the fix-up phase. Not much code is devoted to idiot-proofing, this thing had to be small enough to include in the standard build. You'll get an error if you use an opcode it doesn't understand but the parser is very stupid, it only looks for [label] opcode [parameter[,modifier]] and makes no attempt to determine if the opcode actually takes parameters. Rather, parameters are always OR'd into the instruction. NOP label,I dutifully produces the low 10 bits of the address with the current and indirect bits set. Put comments at least 10 characters removed from the opcode to avoid having them interpreted as parameters.
9/21/02 modifications - call by CREATE DefName /KEEP (or /K) to keep and add to the previous create's symbols, very useful for defining common subroutines and data which have to be accessable by other definitions. The two blocks used by create is enough for ~200 symbols, if you think your program contains more then allocate 4 or more blocks and call by CREATE DefName /LARGE (or /L).
Last modified January 1 2012
Terry Newton <firstname.lastname@example.org>