
HP-IPL/OS Basics
----------------

By default HP-IPL/OS is configured for a console interface in slot 11,
a papertape reader (PTR) interface in slot 12, and a papertape punch (PTP)
interface in slot 13. If this is not the case, certain memory locations must
be changed after loading and before running. Location 355 determines the
console slot, location 357 determines the PTR slot, and location 356
determines the PTP slot.

To run HP-IPL/OS, load it into memory and run from location 2.
Any word with a name that begins with ! automatically runs on startup.
To suppress autostart words, set switch register bit 15.

To load an IPL file, attach it to PTR (papertape reader) and enter: <PTR
If MS hasn't been redirected, for the same thing enter: <MS
The MS input and output vectors are assignable to other drivers.
Once an IPL file has been loaded whatever words it defined remain
in the dictionary unless removed.

The kernel provides very little in the way of operating the system,
just WORDS to display a list of currently defined words. Load an "extra"
package for helpful words like FORGET WORDNAME to remove words,
RENAME WORDNAME NEWNAME to rename a word, and EXPLAIN WORDNAME to
list word code.

A word can be manually removed by entering: "WORDNAME" $DEFADR 4 SUB 0 PUT

The dictionary is a linked list so removing a word removes all words
after it - FORGET or the manual version truncate the dictionary. Since
words are compiled to addresses as they are defined, a single word in
between other words cannot be removed. Renaming a word does not affect
other words already in the dictionary that call it, but will cause
any newly loaded package that uses the renamed word to fail.

Only the 1st 4 characters and the length of a word name are significant,
the remaining characters are listed as "xxxx" in WORDS and EXPLAIN listings.
This may seem very crude, and it is, but it increases speed and reduces
memory requirements, important when the max address space is 32KW and
very important when doing fancy stuff like disk operating systems in
the confines of an 8KW machine. In practice I've never had any issue
with running out of name space, and long descriptive names can be used
in source code so long as they meet the uniqueness standard. Just avoid
names like TEMP1 TEMP2 etc, use 1TEMP 2TEMP TMP1 TMP2 etc. 

The rest of this is a (very) trimmed version of summary.txt...


Summary of kernel words from HP-IPL/OS 1.60 (6/20/10)
-----------------------------------------------------

EXECUTE - pops stack and executes from address contained there
RUN - pops stack and runs machine code there
WBOOT - restarts hpiplos without running autostart words
AND - pops stack twice, does bit-wise AND and pushes result
OR - pops stack twice, does OR and pushes result
XOR - pops stack twice, does XOR and pushes result
ADD - pops stack twice, adds the two and pushes result
SUB - subtracts 1st pop from 2nd pop and pushes res. (3 2 SUB pushes 1)
MUL - pops two items from stack, multiplies and pushes results
DIV - divides 2nd pop by 1st pop and pushes res. (6 2 DIV pushes 3)
INC - pops stack, adds one and pushes results
DEC - pops stack, subtracts one and pushes results
ROL - pops stack, rotates left, pushes results
ROR - pops stack, rotates right, pushes results
ASL - pops stack, shifts left (lsb 0), pushes results
ASR - pops stack, shifts right (msb 0), pushes results
NOT - pops stack, reverses 1's and 0's and pushes results
2CPL - pops stack, does 2's compliment and pushes results
DUP - pops stack and pushes twice, duplicating the top entry
DROP - pops stack to nothing
OVER - duplicates stack over current (1 2 OVER yields 1 2 1 on stack)
ROT - swaps two items over current (1 2 3 ROT yields 2 1 3)
SWAP - swaps the top two stack items
GET - pops stack, gets memory there and pushes data
PUT - a b PUT writes b to location a
DO - pushes address of next instruction on return stack - starts a loop
UNTIL - pops stack, if zero continues DO loop
WHILE - pops stack, if not zero continues DO loop
PNUM - pops stack and prints as a number
CRLF - prints a new-line to the console
DECIMAL - sets number-radix to 10 with leading zeros suppressed
OCTAL - sets radix to 8, displays numbers as 6 digits
BINARY - sets radix to 2, displays numbers as 16 digits
SP>S - pushes stack pointer to stack (pushes 1st unused pos. BEFORE the push)
SB>S - pushes stack base to stack
XP>S, XB>S, YP>S, YB>S, ZP>S, ZB>S - pointer/base for X/Y/Z stacks
>STEP - pops stack and sets +DO increment used by next +LOOP
 (do not use within nested loops unless outer loop inc is 1)
+DO - pops startval and endval and sets up a loop
INDEX - pushes current DO index
+LOOP - adds one to index and if <> endval repeats loop
DMPS - dumps the stack
DEFINE name - starts a new word definition
END - terminates a definition
PCHR - pops stack and prints as a single character
PWRD - pops stack and prints as a double-character
$PRINT - prints string on the X stack
IFNZ - pops stack, if not 0 continues else jumps to corresponding ELSE/ENDIF
IFZ - pops stack, if zero continues else jumps to ELSE or ENDIF
IF<0 - pops stack, if less than zero continues else jumps to ELSE or ENDIF
ELSE - when run jumps to corresponding ENDIF
ENDIF - terminates an IFZ/IFNZ/IF<0/ELSE block
CASE - pops stack and searches for matching condition
= < > <= >= <>  - condition markers, must be followed by number, const or var
DEFAULT - optional default condition marker for when no matches
ENDCASE - terminates a case structure
S>X - pops (system) stack and pushes to X stack
X>S - pops X stack and pushes to system stack
S>Y, S>Z, Y>S and Z>S provide same for Y and Z stacks
X>>Y, X>>Z, Y>>X, Z>>X - string moves
S>SR - pops stack and writes to Switch Register
SR>S - reads Switch Register and pushes to stack
$CPY - string copy from X to Y (leaving on X)
$DUP - duplicates string on X
$SWAP - swaps 2 strings on X
$DROP - removes string from X
$IN - inputs string up to CR and pushes (without CR) to the X stack
$GET - n $GET gets byte# n from string on X and pushes to system stack
$PUT - n b $PUT puts b into byte# n of string on X
$LEN - pushes true character length of string on X to S
$CREATE - n b $CREATE creates a string on X containing n bytes of b
$ADR - pushes address of first element of string on X
$XTEST - prints error message and restarts if value on stack is below XB
$STR - pops stack and converts to a string on X
CHRIN - inputs one character and pushes to stack
RND - pushes random number to S
$APPEND - pops stack and appends character to string on X
$HEAD - removes 1st char from string on X and pushes to stack
$TAIL - removes last char from string on X and pushes to stack
$IN - inputs string up to but not including return to string on X
$VAL - pops string on X and pushes value to stack (0 if not a number)
$CAT - combines two strings on X into one string
<>CON - resets I/O to console
CONSOLE - like <>CON but also sets MS to papertape
>PTP - redirects output to papertape punch
<PTR - redirects input from papertape reader
MSBIN - reads byte from mass-storage and pushes to stack
MSWIN - reads word from mass-storage and pushes to stack
MSBOUT - pops stack and writes byte from mass-storage
MSWOUT - pops stack and writes word to mass-storage
MS$OUT - pops and writes string from X to mass storage
MS$IN - inputs string from mass storage using redirected $IN
MSCRLF - sends a CRLF sequence to mass storage output
MSPAPER - sets mass storage vectors to paper-tape
MS_SAVE - saves current MS byte vectors
MS_RESTORE - restores previously saved MS byte vectors
INBLOCK - pops and sets mass storage input to specified block
OUTBLOCK - pops and sets mass storage output to specified block
BPUT - block word put - word offset block BPUT
BGET - block word get - offset block BGET (word on stack)
ZEROBLOCK - pops stack and writes 1K word zeros to that block
 (note.. redirects MS output, MS_SAVE/MS_RESTORE if important)
GETIP - pushes value of input byte pointer
SETIP - pops and sets input byte pointer
GETOP - pushes value of output byte pointer
SETOP - pops and sets output byte pointer
>MS - directs regular text output to mass storage
<MS - directs regular text and console input from mass storage
EOD - pushes current end-of-dictionary
RADIX - pushes current radix number
VARIABLE - defines a variable, usage: VARIABLE Name [size]
CONSTANT - defines a constant, usage: CONSTANT Name Value
TOKEN - if another token in buffer returns in @TL,@TB1,@TB2
        and pushes 0, otherwise pushes non-zero
SDIC - searches dictionary for token in @TL,@TB1,@TB2 and
       pushes address twice if found, else pushes 0
HEADER$ - pops stack and pushes string containing header name + " "
WORDS - lists defined words, prints EOD and free space
ALLOCATE - pops and allocates specified number of blocks
$DEFADR - pops string and pushes word address of definition
+IRQ - turns on interrupts (note usually renamed to !IRQ)
-IRQ - turns off interrupts
+AUTO - turns on autostart of words beginning with !
-AUTO - turns off autostart (or put 177777 in switch reg)

Used by defining words... (variable constant create etc)

ADDCODE - pops stack, writes to mem spec'd by @DIPTR, increments @DIPTR
ADDHEADER - finds end, adds definition header spec'd by @TL/@TB1/@TB2,
  saves fix info (len, initial address) to Z, sets @DIPTR to where
  the ENSEC or *+1 code should go
ADDHEADER$ - pops string containing definition name, sets @TL/@TB1/@TB2
  and runs ADDHEADER
ADDMLVAR - adds definition body containing *+1 and machine code that
  pushes the contents of an internal location, used by VARIABLE/CONSTANT
FIXLINKS - pops initial address and len from Z and completes definition

Constants and addresses...

#0 - pushes a 0
#1 - pushes a 1
@DIC - pushes location w/ start of dictionary
@USR - pushes location w/ start of user dictionary
@BLK - pushes location w/ start of block memory
@END - pushes location w/ end of block memory
@TB, @TL1, @TL2 - addresses of TOKEN/SDIC variables
@ENSEC, @RTSEC - addresses of Enter/Return Secondary
@LITERAL - address of threaded literal push
@STRING - address of threaded string push
@CLH - address of Console Literal handler (SDIC returns for literals)
@ANVAL - address of Ascii Number Value (SDIC sets for literals)
@DIPTR - zero-page variable for use as a code pointer
@LLP - "last load point" var, set to EOD before <PTR or <MS (new for 1.6)

The base 8K version does not auto-enable interrupts, interrupt-using
options in 16K+ builds (extra.ipl loaded) typically RENAME +IRQ !IRQ
to enable interrupts all the time. "+IRQ" $DEFADR 3 SUB 20511 PUT
at the console does the same thing if you want interrupts in 8K.

Configured for TTY Console in slot 11, PTR in slot 12, PTP in slot 13.
Change locations 355, 357, 356 and restart to change configuration.

----------------------------------------------------------------------

Useful locations in octal...

260 - ABFLG, alt boot flag set to 1 if timeout
261 - ABVEC, holds address of alternate boot code (sets ABFLG to 1)
262 - WDENA, non-zero to enable watchdog
263 - WDTMR, increments when +TBG's ISR runs
264 - WDTOV, timout value, JMP ABVEC,I when WDTMR=WDTOV
265 - contains +LOOP increment
266 - address of default input sub, enabled on boot
267 - address of default output sub, enabled on boot
270 - TBG slot - disable IRQ 1st, takes effect when !100MS runs
271 - BACI slot - takes effect when !BACI runs
272 - LPT slot for printer driver in print.ipl
273 - 7900 lower slot or 7906 slot
274 - IDE slot
275 - CS80 slot (not implemented yet)
276 - HPIB slot
277 - available for slot-patching user-written driver
355 - TTY slot             \
356 - PTP (punch) slot      > restart to take effect
357 - PTR (reader) slot    /
300 - buffer pointer for CONIN, TOKEN
301-305 - stack pointers for S,R,X,Y and Z
315 - @TL - token length - length of word found by TOKEN
316 - @TB1 - token buffer 1 - 1st 2 chars of word
317 - @TB2 - token buffer 2 - next 2 chars of word
321 - link to NEXT - JMP 321,I to return to HPIPLOS
323 - link to SPUSH - JSB 323,I to push A to sys stack
324 - link to SPOP - JSB 324,I to pop sys stack to A
325-334 - similar links to push,pop for R,X,Y and Z
337 - link to CHROT(*) - JSB 337,I outputs A to console
340 - link to CRLF - JSB 340,I prints crlf to console
341 - link to CHRIN(*) - JSB 341,I to get char from console to A
(* can be changed to change console to a different device)
342 - link to PTWD - JSB 342,I to print A as 2 characters
343 - link to PBFL - A=w.length, B=addr, JSB 343,I to print "string"
(not a HPIPLOS string, but for printing ML messages)
344 - link to PTRIN - JSB 344,I to get byte from PT to A
345 - link to PTROT - JSB 345,I to write byte in A to PT
346 - ZIN vector - normally points to CHRIN for input
347 - ZOUT vector - normally points to CHROT for output
(all user input/output goes thru ZIN/ZOUT - redirectable to
console or papertape using <>CON, <PTR and >PTP definitions)
350 - ZMINP or MS input vector - default PTR
351 - ZMOUT or MS output vector - default PTP
410 - holds the current number radix for reading, don't write
to since tables and everything needs to be changed to change radix.
435 - holds value for end of input buffer (614)
436 - holds value for start of input buffer (500, note previous
location 477 must contain a space for proper operation)
437 - holds start of system stack (620)
440 - holds end of system stack (777)
441 - holds start of return stack (1000)
442 - holds end of return stack (1177)
443 - holds start of X stack (1200)
444 - holds end of X stack (1377)
445 - holds start of Y stack (1400)
446 - holds end of Y stack (1577)
447 - holds start of Z stack (1600)
450 - holds end of Z stack (1777)
451 - @DIC - holds start of dictionary (4000)
452 - @USR - holds start of user dictionary
453 - @BLK - holds the end of dictionary space+1
454 - @END - holds the end of hpiplos memory
457 - address of warm-boot machine code
460 - prompt copied to 464 on startup (default "? ")
461 - global interrupt enable, set/reset by !IRQ/-IRQ
462 - IENAV - interrupt enable vector, JSB IENAV,I instead of STF 0
463 - contains the address of the sign-on message (starting w/crlf)
464 - current prompt
465 - if non-zero autostarting is enabled
470 - holds address of PIOCS subroutine, A=patchlist, B=new slot#
471 - holds address of CHRIN subroutine
472 - holds address of CHROT subroutine
473 - timer low (tbg option)
474 - timer high (tbg option)
475 - link to interrupt save sub (ISAVE) JSB ISAVE,I to save state
476 - link to interrupt restore sub (IREST) JSB IREST,I to restore


HPIPLOS string format...

addr   highbyte  lowbyte
1200      H        E      "HELLO" is first string on X
1201      L        L
1202      O        ?
1203               5      character length = 5
1204               4      word length for easy copying

Memory map... (numbers in octal)

2-3          Jump to 2000
10-37        contain JSB dummy,I links to avoid interrupt errors
40-77        various irq/etc stuff added by some options
100-147      Reserved for the user
150-177      Temp memory used by some IPL utility words
200-237      SFS zero-page variables
240-257      Vectors for disk driver
260-477      Zero page constants, links, variables
500-615      HP-IPL/OS input buffer
620-777      System stack
1000-1177    Return stack
1200-1377    X stack
1400-1577    Y stack
1600-1777    Z stack
2000-3777    Core HP-IPL/OS code
4000-???     Dictionary
@BLK-@END(*) Up to 16 1K-word memory blocks (typically 2-4 used) (**)

(*) the @END location determines last block location, default 67777
@BLK determines 1st block location, set by ALLOCATE
(**) 8KW builds typically use no blocks at all, load the internal.ipl
file to remove block support. Note that @BLK still should be set to
one more than @END for compatibility.

----------------------------------------------------------------------

Thread Details
--------------

HP-IPL/OS uses an indirect-threaded interpreter that implements
a system stack (S), return stack (R) and 3 auxillary stacks
(X Y and Z). Word Address (WA) is the address HP-IPL/OS interprets
to run a word, it contains the Code Address which points to actual
machine code. If pointed to the ENSEC code, the current WA+1 is pushed
to the return stack and the code following it is interpreted until
RTSEC is encountered which pops the return stack, returning execution
to the previous thread which called the "high-level" definition.
Low level definitions generally have the next address in the WA
location (DEF *+1), the machine code executes until an indirect
jump to the NEXT code (JMP ZNXT,I) is executed.

Definition names are encoded to save space, only the first four
characters and the length are significant. Don't use names like
TEMP1 and TEMP2 together, to HP-IPL/OS they are equal.

Low-level definitions are encoded in the dictionary like...

           length   <--- prev. link (or beginning of dictionary)
           first 2 characters of name
           next 2 characters of name
           link to next definition >---.
WA ------> code address >----------.   |
           1st ML instruction <----'   |
           remaining ML instructions   |
           JMP ZNXT,I to return        |
           (optional data)             |
           next length or 0   <--------'

High-level definitions (beginning with ENSEC) are encoded like..
(using the example DEFINE TEST[cr]"HELLO " $PRINT 7 PNUM END)

           4      length   <---- link from prev. definition
           "TE"   first 2 characters
           "ST"   next 2 characters
      .--< link to next definition
WA----|--> address of ENSEC
      |    address of the string push code
      |    4      length in 16-bit words
      |    "HE"
      |    "LL"
      |    "O "
      |    6      character length of the string
      |    address of $PRINT
      |    address of literal push code
      |    7
      |    address of PNUM
      |    address of RTSEC
      `--> next length or 0

----------------------------------------------------------------------

HP-IPL/OS main page: http://www.infionline.net/~wtnewton/oldcomp/hp2100/
Testing and updates page: http://www.infionline.net/~wtnewton/hpiplos.html
Mirror site: http://newton.freehostia.com/net/oldcomp/hp2100/
Terry Newton (wtnewton@infionline.net or wtn90125@yahoo.com)
