diff --git a/doc/_info_/char.sail b/doc/_info_/char.sail
new file mode 100755
index 00000000..75607177
--- /dev/null
+++ b/doc/_info_/char.sail
@@ -0,0 +1,45 @@
+Stanford character set.
+These are the exceptions to standard ASCII.
+5.10.72 z = 749
+
+
+^A downarrow
+^B alpha
+^C beta
+^D carat (logical and)
+^E not
+^F epsilon
+^G pi
+^H lambda
+^I tab
+^J line feed
+^K vertical tab
+^L form feed
+^M return
+^N infinity (two dots)
+^O del
+^P subset of
+^Q contains
+^R intersect
+^S union
+^T for all
+^U there exists
+^V exclusive or (plus with a circle around it)
+^W equivalence (two way arrow)
+^X underbar (note that backarrow is like old ascii and =/ ^X)
+^Y forward arrow
+^Z end of file
+^[ not equal (=/)
+^\ less than or equal
+^] greater than or equal
+^^ equivalence (three bars)
+^_ down-carat (logical or)
+
+
+^ is up-arrow, not carat
+_ is backarrow, not underbar
+
+
+} is altmode, not right brace
+~ is right brace, not 'not'
+
\ No newline at end of file
diff --git a/doc/_info_/pcode.info b/doc/_info_/pcode.info
new file mode 100755
index 00000000..bdda0396
--- /dev/null
+++ b/doc/_info_/pcode.info
@@ -0,0 +1,88 @@
+
+ 3. DISPLAY-MODE CHANNELS. ^P-CODES.
+
+It would be impossible to output a display command using a channel
+which simply printed any character sent out on it. If it is desired
+to make use of display commands, a channel may be opened in display
+mode. That causes the character "^P" to be an escape character when
+output on that channel. When a "^P" is output on a display-mode
+channel, it has no effect except for setting bits causing the next
+character output on that channel to be interpreted as a display code.
+The display codes are:
+
+A Advance to a fresh line. If at beginning of line do nothing,
+ else act like a CRLF.
+B move Backward. Decrements the horizontal position.
+ If the horizontal position is 0, it is set to the horizontal
+ screen size minus two, and the vertical position is decreased
+ by one. Thus, it moves back over one character position even
+ if there was a line continuation in the way.
+C Clear screen. The cursor goes to the upper left corner and
+ the whole screen is cleared. On a printing tty (%TOMVU is 0)
+ a CRLF is output, since "clearing the screen" is undefined.
+ If "^PC" is output to the echo area, only the echo area is
+ cleared, and only the echo area cursor is moved.
+D move Down. The vertical position is incremented. If it becomes
+ equal to the vertical screen size, it is set to 0.
+E clear to Eof. The remainder of the current line, and all lower
+ lines, are erased. The cursor doesn't move.
+F move Forward. The horizontal position is incremented. At the
+ end of the line it wraps around to the beginning of the
+ same line.
+H set Horizontal position. Takes one argument: the following
+ character should be the desired horizontal position setting
+ plus 8. The vertical position is not changed. An attempt to
+ set the position beyond a margin will position it at the
+ margin.
+K Kill (erase) the character the cursor points at. The cursor
+ does not move. The position erased is the one that would be
+ written in next by ordinary output.
+L clear Line. The current line, starting with the position that
+ the cursor points at, is erased. The cursor does not move.
+M (More) hang up until a character is read in. See F.3.
+N (No home-up) similar, but don't home up after the character is
+ read.
+P output "^P". Useful if it is desired to output "^P" in image
+ mode with a display-mode channel, or if the terminal handles
+ the SAIL character set.
+Q output "^C". Similar to "^PP". This is needed only for block
+ mode IOT's. With SIOT, it is not needed since "^C" isn't special.
+R Restore cursor position. The cursor is set to the most
+ recently saved value.
+S Save cursor position. Remembers the current cursor position
+ for use with "^PR". There is no stack for saved cursor
+ positions; only the most recent saved position is remembered.
+T go to Top of screen (home up). The cursor is positioned at the
+ upper left corner of the screen.
+U move Up. The vertical position is decremented. If it was 0,
+ it becomes equal to the vertical size minus one.
+V set Vertical position. Takes the following character as an
+ argument - it should be 8 plus the desired vertical position.
+ An attempt to set the cursor beyond the top or bottom margin
+ will position it as far as allowed in the desired direction.
+ Similarly, "^PV" will not move the echo area cursor outside
+ the echo area. Note that vertical positions in the echo area
+ are to be specified relative to the top of the echo area.
+X backspace and erase one character ("^PB" followed by "^PK").
+ If done at column zero, it clears the last TWO characters on
+ the previous line (assuming that one of them was the
+ character you intended to erase, and the other was an "!"
+ indicating a continuation).
+Z home down. The cursor is positioned at the lower left corner.
+[ insert line. The current line and all lines below it are
+ pushed down one slot. A blank line appears at the current
+ position. The cursor does not move. Works only on terminals
+ which have %TOLID set (^P\ also).
+\ delete line. The current line disappears, and all teh lines
+ below it move up by one position. The bottom line becomes
+ blank. The cursor does not move.
+] obsolete - same as "^PL".
+^ insert character. All the characters after the cursor move
+ right one position. The last one moves off the right margin
+ and disappears. A space appears at the cursor, which does not
+ move. Works only on terminals which have %TOCID set.
+_ delete character. The character at the cursor disappears, and
+ all the rest of the characters on the line move left one
+ position. A space appears at the end of the line. The cursor
+ does not move.
+
\ No newline at end of file
diff --git a/doc/info/lib.28 b/doc/info/lib.28
new file mode 100755
index 00000000..ef7838e6
--- /dev/null
+++ b/doc/info/lib.28
@@ -0,0 +1,998 @@
+-*-Text-*- Documentation of MIDAS .INSRT libraries.
+
+File: LIB Node: Top Up: (DIR)
+
+.INSRT'able Subroutine Libraries for MIDAS Programs
+
+ITS now has several libraries of commonly useful subroutines
+for MIDAS programs. This file tells how to use them and
+what the existing libraries do.
+
+* Menu:
+
+* General:: What libraries expect from their callers
+
+These libraries exist now
+
+* RFN:: Reading and printing filenames
+* DATIME:: Reading, printing and converting dates and times
+* NETWRK:: Accessing the ARPANET
+* LSRTNS:: Accessing the INQUIR data base
+* FORMAT: (SYSENG;FORMAT) Output made easy. Like Lisp's FORMAT function.
+* MSGS: (SYSENG;MSGS) Accessing the :MSGS date data base
+* BYELIB: (SYSENG;BYELIB) Obtaining epigrams a la BYE
+
+File: LIB, Node: General, Up: Top, Previous: Top, Next: RFN
+
+The Calling Conventions of the .INSRT'able Libraries
+
+ MIDAS libraries are designed to be requested with a .INSRT, because
+of the fact that MIDAS programs are usually absolute assemblies.
+A library named FOO resides (unless otherwise stated) in the file
+SYSENG;FOO > on all ITS machines, and can be requested with
+.INSRT SYSENG;FOO
+
+ Every library clothes itself in a MIDAS symbol block named after the
+library. Almost all of the symbols of the library live within this
+block, and thus cannot interfere with the calling program. Some
+libraries define their normal entry points in the outer block, while
+others define NO symbols except in their own block. Routines in
+libraries of the latter sort must be referred to in MIDAS with an
+explicit block name, as in RFN"PFN for the PFN routine in the library
+RFN.
+
+ Because libraries are included in the assembly with .INSRT,
+they inherit (unless you specify otherwise) the symbol definitions
+of the program that is calling them. Subroutines use specific
+accumulator names for their arguments, rather than specific
+accumulator numbers, and they expect to be called with a PUSHJ P,
+where P is whatever the .INSRT'ing program defines it to be.
+
+ Most libraries require a block of four or five accumulators, named
+A, B, C, and D, and perhaps E. Usually, the code assumes that those
+accumulators are consecutive, and the caller should assume that this
+is required. Some libraries require another pair of consecutive
+accumulators named T and TT. Of course, every library requires a
+stack named P. Each library will say exactly which accumulators it
+requires and which must be consecutive.
+
+ If your existing program does not provide suitably named
+accumulators, you can still use the library if you define the required
+names within the library's symbol block. For example, if your program
+defines the accumulator names A=1, B=2, C=3, T=4, D=5,, while the
+library FOO insists on A through D consecutively, you can do
+
+ FOO"D=4
+
+causing the name D within FOO to refer to the program's accumulator T.
+Within FOO, A through D are now consecutive, but D outside of FOO
+continues to have its old value of 5. The only disadvantage of this
+is that arguments to FOO's routines cannot be set up in D=5, but must
+be placed in T or FOO"D, which are names for 4.
+
+ Library subroutines are almost always intended to be called
+with a "PUSHJ P,". Each subroutine's documentation will specify
+whether it can skip return, what arguments are expected in which
+accumulators, which values are to be counted on in which accumulators,
+and which accumulators are randomly clobbered. Accumulators in the
+set used by the library which are not mentioned in the documentation
+may be used temporarily if they are saved and restored. Accumulators
+not among those "used by the library" are not touched even for an
+instant.
+
+ Some libraries assume that the symbols CPOPJ and POPJ1 have been
+defined by the caller in the standard manner:
+
+ POPJ1: AOS (P)
+ CPOPJ: POPJ P,
+
+They may also expect the user to define specifically named routines to
+serve as subroutines for the library to call. This is to allow the
+user to customize the behavior of the library. Each library says
+which such symbols are required by which routines. Of course, all
+libraries assume that the predefined symbols of MIDAS are available.
+If you redefine them carefully, you may succeed in faking the
+libraries into doing something interesting. If you redefine them
+carelessly, you will lose.
+
+ Because many callers will not need all the routines in a library,
+the caller can specify which parts of the library should be assembled
+by defining some control parameters before .INSRT'ing the library.
+Such parameters have names starting with "$$". Each library has its
+own set of control parameters, which it documents; those not defined
+will usually be taken to be zero, and the associated features NOT
+assembled. Thus, the caller must set to one the control parameters
+associated with the routines he wishes to use (some libraries may use
+the opposite default, assembling all routines except those whose
+control parameters are set to zero by the caller). Since it cannot be
+assumed that no two libraries will have control paramaters with the
+same name, it is good practise to make the control paramaters local to
+the library's symbol block, as in:
+
+ RFN"$$RFN==1 ;Assemble the RFN routine.
+ RFN"$$PFN==1 ;Assemble the PFN routine.
+
+ Libraries know which parts depend on other parts as subroutines, and
+automatically assemble the subroutines of any part that is explicitly
+requested.
+
+ All code assembled by libraries at the point where they are
+.INSRT'ed is pure code. Most libraries create impure static storage
+using .SCALAR and .VECTOR. A library that never uses them and has no
+static variables will say so; others should be assumed to use them.
+
+ Routines that use or return a text string generally expect to find a
+byte pointer to the beginning of it in D. They then advance D as they
+read or write the text, returning with D pointing at the last
+character read or written. Some routines that write text will store a
+null character after the last real character of output, to make the
+string ASCIZ; D will not be advanced past the null.
+
+File: LIB Node: RFN, Up: Top, Previous: General, Next: Datime
+
+The RFN library contains filename reading and printing routines.
+
+ACS: This file requires acs A, B, C, D, and E, which NEED NOT be
+ consecutive, and P.
+
+VARS: This file defines no static variables. It is entirely pure.
+
+EXITS: Required exits can include SWITCH, RSIXTP, PSIXTP, MNAME,
+ and MSNAME, depending on the routines assembled.
+
+ENTRIES:
+ The entries defined are RFN, PFN, PFNMCH, and PFNBRF, and
+ RMNAME. They are defined only in the symbol block RFN.
+ None of them skips.
+
+The control parameters all default to zero:
+ $$RFN enables the filename reading routines.
+ Requires the RSIXTP be defined.
+ $$SWITCH enables the portion that handles switches.
+ Requires that SWITCH be defined.
+ $$RUC inhibits the definition of the RUC subroutine, used
+ for reading input, so that the user can define it.
+ Requires that RUC be defined.
+ $$PFN enables the PFN filename printing routine.
+ Requires that PSIXTP be defined.
+ $$PFNBRF as well enables the PFNBRF printing routine.
+ Requires that MSNAME be defined.
+ $$MNAME enables the PFNMCH printing routine.
+ It also enables the RMNAME routine that sets up MNAME.
+ Requires that MNAME be defined.
+
+A Filename Block is a four-word block which holds the four names of a
+ file in the order DEVICE, FN1, FN2 and SNAME, each as a word
+ of SIXBIT. These words are in the same order as the arguments
+ to a symbolic OPEN call.
+
+
+Filename Reading: $$RFN==1 to enable.
+
+ The routine RFN"RFN parses a file specification. It expects in D a
+byte pointer to the text, and in B the address of a filename block in
+which to store the parsed names. On return, B and C are unchanged,
+while D is updated to point at the terminating character, which is
+left in A. E contains flags indicating which of the four names were
+specified by the filespec. The other words of the filename block are
+not changed. The flags are bits 3.1, 3.2, 3.3 and 3.4 set to indicate
+that the device, fn1, fn2 and sname, respectively, were specified.
+These flags are best written as 1_RFN"DEV, 1_RFN"FN1, 1_RFN"FN2,
+and 1_RFN"SNM.
+
+ Filenames as parsed by RFN"RFN recognize the special characters
+Space, Colon for the device name, Semicolon for the sname, ^X for
+referring to the default fn1, ^Y for referring to the default fn2, and
+^Q for quoting a special character to include it in a filename.
+All control characters other than ^Q, ^X and ^Y terminate the
+filespec.
+
+ Additional filespec terminating characters are specified by the
+caller by defining the routine RSIXTP, which should skip if the
+character in A is one which should terminate the filespec.
+
+ Default filenames can be supplied by storing them in the filename
+block before calling RFN. For more control, you can examine the flags
+returned in E to find which names were specified, and default the
+others. However, ^X and ^Y will always take their defaults from the
+contents of the second and third words of the filename block.
+
+ RFN reads characters from the input string using the subroutine
+RFN"RUC. The caller may set $$RUC==1 and define RUC himself, to cause
+RFN to get its input from another source. RUC should return the next
+input character in A, converted to upper case, and not skip.
+
+
+Filename Reading with Switches: $$SWITCH==1 to enable
+
+ Setting $$SWITCH causes RFN"RFN to call a routine SWITCH, which the
+caller must define, whenever a switch is encountered. A slash is
+followed by a single switch, while a "(" is followed by several
+switches, terminated by a ")".
+
+ The caller's SWITCH routine is called once for each slash, and
+several times as appropriate for each "(". It should read and process
+one switch, assuming that the first character of the switch is in A.
+If it returns without skipping, RFN assumes that the last character
+read was part of the switch. If SWITCH skips, RFN assumes that the
+last character read, which must be left in A, was a terminator that
+was not part of the switch. This terminator is reprocessed.
+SWITCH must not clobber C or E.
+
+ Note that slash and "(" are not recognized by RFN unless RSIXTP
+skips for them. This gives the caller run-time control over whether
+to accept switches.
+
+
+Filename Printing: $$PFN==1 to enable.
+
+ The routine RFN"PFN takes a filename block address in B and prints
+the filenames, depositing the text down the byte pointer in D, which
+is updated. No accumulator other than D is changed.
+
+ PFN knows how to put ^Q in front of characters that need it.
+It requires that the user define a routine PSIXTP that takes a
+character in A and skips if that character requires a ^Q. However,
+the characters Space, Colon and Semicolon get ^Q's and are not passed
+to PSIXTP. Thus, PSIXTP can be the same routine as RSIXTP.
+
+ The routine RFN"PFNBRF is similar to PFN except that it suppresses
+mention of the device name if it is DSK, or the sname if it is the
+default one. The user must set $$PFNBRF==1 to enable this, and must
+define MSNAME to contain the default sname.
+
+
+Filename Printing using AI: instead of DSK: $$MNAME to enable.
+
+ The routine RFN"PFNMCH prints filenames just like PFN except that a
+device name of DSK is printed as the running machine's name.
+The user must define a location MNAME and store the machine's name
+there. A routine RFN"RMNAME is provided which initializes MNAME
+correctly.
+
+File: LIB, Node: DATIME, Up: Top, Previous: RFN, Next: NETWRK
+
+The DATIME library contains routines for handling dates and times.
+
+ACS: A, B, C, D and E, which must be consecutive, as well as P.
+
+VARS: ENGDTP and TMSYST are internal static variables.
+
+EXITS: None.
+
+The control parameters all default to zero:
+ $$OUT enables output as mm/dd/yy hh:mm:ss
+ $$OUTF enables output as, eg, 3 Mar 1975 1020
+ $$OUTZ as well enables routines for outputting time zone
+ (EST vs EDT).
+ $$IN enables input of the form mm/dd/yy hh:mm:ss
+ $$INF enables flexible input allowing named months
+ $$ABS enables routines to convert dates in y-m-d format
+ to number of days since 1900, routines to add and subtract
+ dates, etc.
+ $$SVNG enables routines to determine whether daylight
+ savings time was in effect at a given time.
+ $$UPTM enables conversion of time into how long ITS had
+ been up at that time.
+
+Data Formats:
+ A date and time are usually expressed in the form of a time
+ word. A time word is a single word containing the time in
+ units of half a second, and one century worth of date. It is
+ also known as the "ITS disk-format date/time".
+ It has these fields:
+
+ ; Mask Field Bits Range Units Actual Range
+
+ TM%SEC== 777776 ; 2.9-1.2 0-131K seconds 0-86399.
+ TM%DAY== 37,,0 ; 3.5-3.1 0-31 days 1-31
+ TM%MON== 740,,0 ; 3.9-3.6 0-15 months 1-12
+ TM%YR== 177000,,0 ; 4.7-4.1 0-127 years 0-127
+ relative to 1900 (1900-2027)
+
+ Those four symbols, and byte pointer left halves named
+ TM$YR, TM$MON, TM$DAY and TM$SEC, are defined in DATIME.
+ So you can do LDB B,[DATIME"TM$YR,,A] to extract the year
+ from A into B, for example.
+
+
+ One routine which is always assembled is TIMGET, which returns the
+current time as a time word in A. -1 is returned if ITS doesn't know
+what the time is.
+
+
+Output of date/time:
+
+ $$OUT==1 enables the routines DATASC, TIMASC and TWDASC which output
+a date and time from a time word in A in the format mm/dd/yy hh:mm:ss,
+stuffing the text down the byte pointer in D. A null character is
+deposited at the end of the string, but the byte pointer in D is not
+advanced over it. B and C are untouched.
+
+ DATASC outputs just the date, TIMASC outputs just the time,
+and TWDASC outputs the date and time with a space between.
+All three place a null character after the text they output.
+
+ $$OUTF==1 enables the routine TIMENG which, called like TWDASC,
+outputs the date and time in the format "7 AUG 1976 0831".
+There is also DATENG, called the same way, which outputs only the
+date, in the form "7 AUG 1976".
+
+ $$OUTZ==1 enables routines TIMSTD and TIMEXP which know about the
+difference between standard time and daylight saving time.
+They are both called just like TIMENG. But whereas TIMENG simply
+outputs the hour it is told, without worrying about the time zone,
+TIMSTD assumes that the time was specified in EST, and converts it to
+EDT if EDT was in effect at that time, and then prints the time with
+EDT or EST as appropriate.
+TIMEXP, on the other hand, assumes that the time was specified in
+whichever time, EST or EDT, was in effect at that time. It prints the
+time like TIMENG, followed by EST or EDT as appropriate.
+
+ $$OUTT==1 enables the tables DOWTAB and DOWLNG of names of days of
+the week. Each is seven words long. DOWTAB's words contain an ASCIZ
+string each, such as ASCIZ/SUN/ in the first word. DOWLNG's words
+contain pointers to ASCIZ strings of the full names of the days.
+DOWTAB and DOWLNG should be used in conjunction with TIMDOW, which is
+assembled when $$ABS==1. Another table, MONTAB, contains pointers to
+the ASCIZ full names of the months, indexed by month number (Jan = 1).
+
+
+Input of date/time:
+
+ $$IN==1 enables the routine ASCTWD which is the inverse of TWDASC.
+It accepts in D a pointer to an ASCIZ string, and returns a time word
+in A, advancing D past the text that was used.
+
+ $$INF==1 enables the "flexible format" input routines which accept
+such input formats as "march 5, 1971" and "3mar71" for the date, and
+"0800", "08:00" "0800:00" and "08:00:00" for the time. They take a
+byte pointer in D pointing to the string, and advance it past the text
+that they use. The routines are ENGTWD, ENGTIM and ENGDAT.
+ENGTWD reads a date and a time, whereas ENGDAT reads just a date and
+ENGTIM reads just a time.
+
+
+Addition and Subtraction of Times: $$ABS==1 to enable.
+
+ The time word format, while convenient for I/O and for comparison of
+times, is not suitable for computation of the number of days or
+seconds between two instants. The routines enabled by $$ABS allow you
+do to that sort of thing.
+
+ TIMADY converts the date in the time word in A to the number of days
+past Jan 1 1900, which is returned in A. TIMSEC converts the date and
+time in the time word in A to the number of seconds since Jan 1, 1900,
+returned in A.
+
+ ADYTIM and SECTIM perform the inverse transformations, of an
+absolute number of days or seconds since 1900 into a time word. The
+argument and value are again in A.
+
+ Slightly higher level routines are TIMADD and TIMSUB. TIMADD adds
+the number of seconds in B to the time word in A, returning the new
+time as a time word in A. TIMSUB returns in A the number of seconds
+from the time in B to the time in A, both arguments being in the form
+of time words.
+
+ TIMDOW takes a time word in A and returns in B the day-of-the-week
+index (Sunday = 0) of that date.
+
+ TIMNET takes a time word in A and returns in A the same time in
+32-bit Arpanet standard format.
+
+ The routines UPTIME and UPINI can convert a time word into the
+system up-time in 30'ths of a second. They are assembled if
+$$UPTM==1. UPTIME takes a time word in A, and returns the
+corresponding system up-time. This works only for times since the
+system came up, of course. Before using UPTIME, UPINI must be called
+to initialize the variable TMSYST.
+
+
+Daylight Savings Time: $$SVNG==1 to enable.
+
+ The routines ODAYL and IDAYL know at which times daylight savings
+time is in effect.
+
+ ODAYL takes a time word in A, assumed to be standard time, and skips
+if standard time was really in effect at that time. Thus, it can be
+used to decide whether the time ought to be converted to daylight time
+before being printed.
+
+ Such conditional conversion can be done this way:
+
+ MOVEI B,3600.
+ PUSHJ P,DATIME"ODAYL ;If daylight time now in effect,
+ PUSHJ P,DATIME"TIMADD ;convert to daylight time before printing.
+
+ IDAYL takes a time word in A, which might be either standard or
+daylight time, whichever was in effect at that time. Thus, it is the
+sort of quantity that you get if you simply ask for the current time
+or a file's creation time and do not convert the zone. IDAYL skips if
+the argument supplied is presumably standard time.
+
+ This is useful for converting such an unspecified-zone quantity
+specifically into standard time, which can be done this wat:
+
+ MOVNI B,3600.
+ PUSHJ P,DATIME"IDAYL ;If at a time when daylight time is in use,
+ PUSHJ P,DATIME"TIMADD ;convert daylight to standard.
+
+File: LIB, Node: NETWRK, Previous: DATIME, Up: Top, Next: LSRTNS
+
+SYSENG;NETWRK > Contains ARPANET-Handling Routines
+
+NETWRK is the oldest library, and makes more demands on the caller
+than the others do. *Note NCP: (.INFO.;ITS NCP)*, for other
+information that you will need for writing programs that use the
+ARPANET.
+
+ACS: A, B, C, D, and E, which need not be consecutive, and
+ T and TT, which must be consecutive, and P.
+ All main entry points clobber T and TT.
+
+VARS: SKTBAS and HSTADR are internal static variables.
+
+EXITS: CPOPJ and POPJ1 must have the standard definitions.
+ GETCHR, PUTCHR, SPCHAN and DEBUG may be required.
+
+ PUTCHR is used by several routines to "print" a character.
+ It should expect the character in T, and not skip.
+
+Entries:
+ HSTMAP accesses the host name table file.
+ HSTLOOK converts a host name string to a host number.
+ HOSTNM reads a host name from the terminal with completion.
+ ICP connects to a foreign server.
+ SERVE in a server listens for and connects to a user.
+ ANALYZ prints an error message
+ CONNECT makes a single connection.
+ CONFIN completes a connection made asynchronously.
+ HSTSRC converts a host number to a host name.
+ HSTSIX converts a host number to a concise abbreviation
+ for its name.
+
+Other conventions:
+ The major entry points of NETWRK all skip if succesful. They
+ are all defined in the containing symbol block, not just in
+ the block named NETWRK. They all clobber T and TT.
+
+ A rigid correspondance between socket numbers and I/O channels
+ is assumed. See under the CONNECT routine for how and why.
+
+Control parameters default to zero:
+ $$HSTMAP enables mapping in the host names and characteristics
+ data base, and the conversion of a host number to a host
+ name.
+ $$HOSTNM enables the routines to convert host names to host
+ numbers. The following switches select one or both of
+ them.
+ $$SYMLOOK enables the non-interactive host name lookup.
+ $$SYMGET enables the interactive one.
+ $$HSTSIX enables the routine to generate a six-character
+ abbreviation for a specified host name such abbreviations
+ are used by servers to put in the LOGIN to be printed on
+ the system console.
+ $$CONNECT enables the routine to open a connection.
+ $$ICP enables the routine for a network user program's ICP.
+ $$SERVE enables the routine for a server's ICP.
+ $$SYSDBG tells the server ICP routine NOT to refuse
+ most connections when SYSDBG is on.
+ $$ERRHAN enables an automatic error message printout when
+ making a connection fails.
+ $$ANAYLZE enables the routine for printing an error message
+ when an error occurs using the net.
+
+Host Name Lookup:
+
+ Programs that use the Arpanet often accept the name of a host as
+input and contact that host. NETWRK provides routines for converting
+a host name to the host's number.
+
+ The first requirement for parsing a host name is to access the ITS
+host name table, the file SYSBIN;HOSTS1 >. All programs should use
+this table rather than have their own, because it is kept up-to-date.
+The routine NETWRK"HSTMAP maps this file into core starting at the
+page whose number is specified in A, making temporary use of an I/O
+channel specified in B. HSTMAP skips if it is successful (it will
+fail only if the file is clobbered), returning in rh(A) the number of
+the first page not used. NETWRK"HSTADR will retain the address of the
+beginning of the file, so NETWRK can access it.
+
+ HSTMAP is assembled if $$HSTMAP==1. This should always be so.
+
+ The basic operation of looking a name up in the table is performed
+by the HSTLOOK routine, which takes in A the address of an ASCIZ string
+containing the host name (or a host number in octal, or decimal
+followed by a point). HSTLOOK skips if the name is valid and
+unambiguous, returning the host number in A. If HSTLOOK does not skip, the name
+was meaningless if B contains 0, or ambiguous if B is not 0. E, T and
+TT are clobbered. To get HSTLOOK assembled, set $$HOSTNM and
+$$SYMLOOK.
+
+ If you wish simply to read a host name from the terminal, you can
+call HOSTNM, which provides completion and help facilities. HOSTNM
+requires no arguments when called, but it expects the user to define
+the subroutines GETCHR, PUTCHR and SPCHAN which it calls. GETCHR is
+used to read input (from the terminal, presumably); PUTCHR, to echo
+the input and print error messages and completions; SPCHAN, to handle
+control characters, etc. returned by GETCHR. HOSTNM skips if it
+succeeds, returning the host number in A. To get HOSTNM assembled,
+set $$HOSTNM and $$SYMGET.
+
+ The user-provided subroutines of HOSTNM must have these calling
+conventions:
+ PUTCHR should expect the character in T, and not skip.
+ GETCHR should return an input character in T,
+ skipping unless there is "no more input available".
+ SPCHAN is used by the interactive host-name lookup routine to
+ handle "special" input characters, not recognized.
+ The special character is passed in T, and the number of
+ characters read so far in TT. If SPCHAN skips, the
+ character is then ignored. If SPCHAN does not skip, the
+ read-in process is restarted, ignoring all input so far.
+ Of course, SPCHAN can collude with GETCHR to feed the
+ previous input or part of it to HOSTNM again.
+
+ HOSTNM and HSTLOOK accept abbreviations as long as they are
+unambiguous. The precise criterion is that, if the specified name
+abbreviates more than one known host name, then one of those host
+names must abbreviate all the rest. Thus, "Rut" is a valid
+abbreviation for "Rutgers" even though "Rugters-10" and "Rutgers-Tip"
+both exist and are different machines, because "Rutgers" abbreviates
+both of the other two possibilities. If "Rutabaga" also existed, then
+none of the four possible completions of "Rut" would abbreviate all
+the others, and "Rut" would be invalid. This is an extension of the
+normal rule that an exact match is valid even if it is also an
+abbreviation for something else.
+
+ In addition, HOSTNM and HSTLOOK accept an octal number, or a decimal
+number terminated by a decimal point.
+
+ HOSTNM, the interactive reader, types a bell whenever an invalid
+name is entered, and ignores the invalid character. At any time, the
+user can type "?" or Altmode to see a list of all the hosts whose
+names are abbreviated by what he has typed so far. "?" or Altmode at
+the beginning of a host name will type a list of all known hosts.
+
+
+Routines for Servers:
+
+ Arpanet server programs need to listen for and then establish
+connections, and often need to be able to translate a host number into
+the host's official name. Also, standard practise is for the server
+to log in after accepting a connection, and supply as the "terminal
+name" argument of the LOGIN symbolic system call a six-character
+abbreviation of the host name, which will be printed on the log
+console. NETWRK provides subroutines SERVE, HSTSRC and HSTSIX for
+these functions.
+
+ SERVE, assembled if $$SERVE==1, is the routine which listens for and
+establishes a connection. It takes several arguments:
+A contains the number of the first of three consecutive I/O channels.
+ The first is the ICP listen channel,
+ the second is the input channel for the TELNET connection,
+ and the third is the output channel for it.
+B contains the local socket number to listen on.
+C contains ,, where the modes are those to
+ be used in the OPENs for the two halves of the TELNET connection.
+DEBUG must be defined by the user, and contain a flag which, if
+ nonzero, disables SERVE's time-out and causes it to .VALUE if
+ anything strange happens. Deposit -1 in DEBUG when you test the
+ server undeer DDT.
+SERVE skips if successful; it can fail due to a time-out, or because
+the setting of SYSDBG specifies that connections from the ICP'ing host
+are to be rejected. When SERVE succeeds, it returns the foreign host
+number in B, and clobbers A, D, T and TT. The channel whose number
+was passed in A is now closed, and the next two channels are open.
+
+ Normally, SERVE itself refuses connections from hosts locked out by
+SYSDBG. However, if you set $$SYSDBG==1, SERVE will accept them, and
+skip, returning in C a flag which will be nonzero if the connection is
+not really wanted. In that case, the caller should break the
+connection himself; but he has the opportunity first to send an error
+message.
+
+ To convert a host number into a host name, HSTSRC can be used. It
+also makes it possible to find out what sort of machine the host is,
+and what operating system it runs, if this information is known in the
+ITS host name table.
+
+ HSTSRC takes a host number in B, and returns host name as an ASCIZ
+string whose address is in A. The sign of A is set if the host is a
+TIP. In addition, D points at the entry for the host in the NUMBERS
+table of the HOSTS1 file; see KSC;HOSTS1 > for the format of this
+table. HSTMAP must be called before HSTSRC can be used. HSTSRC is
+assembled is $$HSTMAP==1.
+
+ To get instead a six-character abbreviation for the host name, call
+HSTSIX. It takes a host number in A, and returns the abbreviation in
+A as a word of SIXBIT, suitable for passing to a LOGIN system call.
+If the host is not known, a name is made from its number. HSTSIX
+always skips. HSTMAP must be called before using it. HSTSIX is
+assembled if $$HSTSIX==1.
+
+
+Routines for User Programs
+
+ "User" ends of network protocols need to at least to establish a
+TELNET connection to a server. If any problems arise, they should
+decode the status information provided by ITS to print an error
+message. The routines ICP and ANALYZ are provided for these purposes.
+User ends will often also need the host-name conversion routines
+described above.
+
+ The routine ICP creates a two-way TELNET connection to a server.
+It takes these arguments:
+A contains , the number of the first of a block of four I/O
+ channels to be used. itself is used only during the ICP.
+ The input side of the TELNET connection is established on channel
+ +2, since its socket number must be two greater than the one
+ used on channel to begin the ICP. The output side takes the
+ next channel number, +3, since it takes the next socket
+ number. Channel +1 is not actually by the ICP process, and it
+ cannot be used for any network connection. It can be in use in any
+ other way, even while the ICP is happening.
+B contains the number of the foreign host.
+C contains the foreign socket number to ICP to (1 for TELNET, etc.)
+D contains ,,, describing the modes to be
+ used in the OPENs that establish the two halves of the TELNET
+ connection.
+ICP clobbers all the known ACs, A through E and T and TT, and returns
+no values. It skips if the TELNET connection is successfully
+established. Otherwise, a caller running under the control of a
+terminal should print an error message by calling ANALYZ. Setting the
+flag $$ERRHAN==1 will cause ICP to call ANALYZ itself before returning
+in the case of failure.
+
+ The ICP routine is synchronous: it waits until the connection
+succeeds or fails. An ICP can be done asynchronously also, with the
+ICPASN routine. ICPASN takes the same arguments as ICP, and in
+addition should be given zero in E when it is called for the first
+time. On successful return, the first channel (the ICP socket) will
+have been opened. At any later time, calling ICPASN again will wait
+for that first connection to complete and then request the two halves
+of the TELNET connection. Calling ICPASN a third time will wait for
+those two halves to complete. The ACs A through E returned by one
+call to ICPASN must be saved and given to ICPASN again the next time.
+If ICPASN ever fails to skip, the entire ICP has failed and you should
+not attempt to complete it.
+
+ The routine ANALYZ prints an error message after an attempt to open
+a network connection fails. It needs no arguments, as it knows how to
+track down all relevant information from ITS's debugging variables.
+The error message is output by calling the user-supplied subroutine
+PUTCHR with a character to be output in T. PUTCHR should output the
+character as appropriate and return without skipping.
+ANALYZ always skip-returns.
+
+
+Establishing Subsidiary Connections (FTP data connection, etc):
+
+ The CONNECT routine can be used to establish a unidirectional
+network connection in either a server or user program. Its arguments
+are these:
+A contains the I/O channel number on which to open the connection.
+ This also specifies the socket number, via the channel-socket
+ correspondance. If a new connection must use a socket number 2
+ greater than an existing connection's, then the new connection must
+ be made on the channel 2 greater than the existing connection's
+ channel.
+B contains the foreign host number.
+C contains the foreign socket number to connect to.
+D contains in its rh the mode to use in the OPEN.
+ Its sign is set to request asynchronous mode.
+Normally, CONNECT waits until the connection is completed, skipping if
+it is successful. Failure can be due to a down host, a refusal, or to
+a time out which CONNECT checks. When CONNECT fails to skip, you may
+call ANALYZ (see above) to print an error message; or, if you set
+$$ERRHAN==1, CONNECT will call ANALYZ itself. In any case, ACs T and
+TT are clobbered; the others are preserved.
+
+ Set the sign bit of D when calling CONNECT to create the connection
+asynchronously. CONNECT will initiate the connection and return
+skipping if there has been no problem yet. At a later time, call
+CONFIN to wait for the connection to complete. CONFIN will skip if
+the connection has been accepted.
+
+ CONNECT, and ICP and SERVE which call it, uses the ITS feature that
+assigns a set of eight consecutive network socket numbers to a job
+which requests them. CONNECT assumes that these eight sockets
+correspond directly to eight consecutive I/O channels; each socket
+can be used only from the corresponding I/O channel.
+
+ The socket-channel correspondance is set up the first time CONNECT
+is called. At this time, connect realizes that it has no socket
+numbers assigned and asks the system to assign some. The first socket
+number of that block is used for the first connection, made on the I/O
+channel specified in the first call to CONNECT. The following seven
+socket numbers, also assigned to this job, correspond to the following
+I/O channels. The first CONNECT stores the offset from the I/O
+channel number to the corresponding socket number in NETWRK"SKTBAS,
+so that later CONNECTs can convert a channel number to a socket
+number. As you can see, the lowest-numbered socket of a set must be
+CONNECTed first.
+
+ If you close all network connections at any time, ITS deallocates
+the block of socket numbers, so you should store zero in SKTBAS to
+cause the next CONNECT to allocate a new set.
+
+File: LIB, Node: LSRTNS, Previous: NETWRK, Up: Top
+
+The LSRTNS library contains routines for accessing the INQUIR data
+ base. *Note LSR1: LSR1 Format, for the details of the format
+ of that data base.
+
+ACS: A, B, C, D, and E, which must be consecutive, and P.
+
+VARS: LSRTNS has these static internal variables:
+
+ LSRADR ;Core address where first part of file is mapped in
+ DATFPG ;Page number in file of first data page
+ SCMPRT ;String compare routine to use LSRLNM and LSRLNP
+
+ If overlaying of pages is being done (the default),
+ these additional variables exist.
+
+ DATADR ;Core address of two pages for mapping in data pages of file
+ DATPAG ;DATADR/2000
+ PAGEIN ;Page number in file of page currently mapped in at DATPAG
+ ;The page after that maps the next sequential file page.
+ ;This is negative if no page is currently mapped in.
+
+
+ If the HSNAME routines are included, (not by default) these variables
+ are exist as well.
+
+ HSNADR ; Address in core of HSNAME table base.
+ HSNPTR ; AOBJN ptr to HSNAME table entries.
+ HSNLN1 ; Length-1 of an entry in HSNAME table.
+ LMCHNM ; Local machine name, as returned by SSTATU.
+ HRETRY ; Switch for re-trying with HX$NRM if HX$TUR (or other) fails.
+ LSRCHN ; Holds # of temp channel to use.
+ MNAME ; "Canonical" machname of site specified.
+ MNAME1 ; "MIT-**" version of machname.
+
+
+Exits: None.
+
+Entries: (All skip if successful).
+ LSRMAP opens the data base.
+ LSRUNM searches for a UNAME's entry.
+ LSRITM extracts a specifically numbered item from an entry.
+ LSRLNM searches for the entries for a given last name.
+ LSRLNP is similar but allows abbreviation.
+ LSRNAM permutes a name in Lastname, Firstname, Suffix order
+ (as stored in the data base) into First Last Suffix.
+ LSRGET converts a file address into a core address,
+ overlaying if necessary.
+ LSRHSN looks up the HSNAME for a user, given his XUNAME
+ LSRTUR skips if an entry is that of a Tourist (T or nonexistant group)
+
+Control parameters default to One, except for $$HSNM.
+Everything is normally assembled except what you say you don't need.
+
+ $$ULNM==0 to omit the routine to search for a last name.
+ $$ULNP==0 to omit the routine to search for an abbreviated
+ last name.
+ $$UNAM==0 to omit the routine to permute a fullname into
+ "humanized" Firstname Lastname Suffix order.
+ $$OVLY==0 to omit the overlay routines, and map the whole
+ data base into core at once. This is good for a
+ program which wants to scan the whole data base
+ instead of looking up a few entries.
+ $$HSNM==1 to include the HSNAME lookup routines.
+
+Routines in LSRTNS:
+
+ LSRMAP takes in A a channel number, and in B an AOBJN pointer to a
+range of free pages, and maps in the data base. If successful, it
+returns in B an updated pointer indicating which pages were not
+needed, and leaves the file STILL OPEN on the given channel.
+Pages which might be needed later for mapping in an entry are
+remembered internally and marked off as "used". No skip can
+either be due to trouble opening or mapping the file, or due
+to a clobbered file, or due to needing more pages than are offered.
+If you set LSRTNS"$$OVLY to zero at assembly time, the whole
+file will be mapped in instead of just a few pages at a time.
+In that case, the channel will not be left open.
+
+ LSRUNM takes in A a channel number, on which the LSR1 file is
+assumed to be open, and in B a UNAME as a word of SIXBIT,
+and returns in B the address, in core, of the entry for that UNAME.
+Such entries are mapped in by LSRUNM and will not
+necessarily remain in core if another LSRUNM or LSRLNM is done.
+No skip implies there is no entry for that UNAME.
+
+ LSRLNM is like LSRUNM but expects in B the address of
+an all-caps last name, as an ASCIZ string, instead
+of a UNAME, and returns in B an aobjn pointer to the
+LASTNAME table words whose Lastname match the argument.
+
+ LSRLNP is like LSRLNM except that the specified last name
+need only be an initial segment of a user's last name for the
+user to be matched and included in the range of the lastname
+table returned.
+
+ LSRGET takes in A a channel number and in B the file address of an
+entry. It maps in the appropriate pages and returns in B the core
+address. Fails to skip if the map fails or if the given address does
+not point at the header of an entry, Use this after calling LSRLNM,
+etc. LSRUNM calls LSRGET itself. If $$OVLY is 0, then this routine
+just converts a file address into a core address.
+
+ LSRITM takes in A an item number and in B the address in core
+of a LSR entry, and returns in A a b.p. to the specified item.
+No skip => this entry lacks that item. A nonexistent item is legal
+and should be treated just like a null string. The item number should
+usually be specified with one of the I$... item names defined by
+LSRTNS in the LSRTNS block:
+
+ I$==,-1 ;Bit typeout mode prefix.
+ I$UNAM==0 ;UNAME
+ I$NAME==1 ;FULL NAME
+ I$NICK==2 ;NICKNAME
+ I$SSN==3 ;SOC SEC #.
+ I$MITA==4 ;MIT ADDRESS
+ I$MITT==5 ;MIT TELEPHONE NUMBER
+ I$HOMA==6 ;HOME ADDRESS
+ I$HOMT==7 ;HOME TELEPHONE NUMBER
+ I$SUPR==10 ;SUPERVISOR(S)
+ I$PROJ==11 ;PROJECT
+ I$DIR==12 ;FILE DIR NAMES
+ I$AUTH==13 ;AUTHORIZATION
+ I$GRP==14 ;GROUP AFFILIATION
+ I$REL==15 ;RELATION TO GROUP
+ I$BRTH==16 ;BIRTHDAY
+ I$REM==17 ;REMARKS
+ I$NETA==20 ;NETWORK ADDRESS
+ I$ALTR==21 ;USER &TIME OF LAST ALTERATION
+ I$MACH==22 ;I.T.S.'S TO BE KNOWN ON.
+
+ LSRNAM takes in A a b.p. to a Name item, and in B a b.p. to
+storage, and IDPBs down B the name, canonically permuted into
+Firstname Lastname Suffix order.
+
+
+LSRHSN find HSNAME for entry, given
+ A/ UNAME of entry
+ B/ or 0 if none.
+ C/ - as per SSTATU call, or host #, or 0 for local site.
+ D/ to use for disk opens (if -1, don't use any.)
+It skips if successful, with
+ D/ HSNAME
+It uses the following algorithm:
+ If no entry address given,
+ If directory for that UNAME exists, return that as HSNAME
+ Else assume tourist and use hasher/tables.
+ Else if "Fildir" entry exists, and a valid dir is specified for
+ local site, return that as HSNAME.
+ Else if directory for that UNAME exists, return that as HSNAME
+ Else determine HSNAME using hash or tables, plus touristness (see
+ LSRTUR)
+LSRHSN is the routine that DDT uses to deterimine what a person's Home
+directory is (HSNAME) on logging in. It is also used by the mailer to
+determine where a person's mail goes.
+
+LSRTUR Test an entry for touristness. It takes a LSR entry address and
+skips if tourist ("Group" field T or non-existent)
+
+
+
+File: LIB, Node: LSR1 Format, Up: LSRTNS
+
+This is the format of the user data base (INQUIR data base),
+which lives in the file INQUIR;LSR1 > on each machine:
+
+HDRSID==0 ; wd 0 SIXBIT /LSR1!!/ for detection of clobberage.
+HDRDAT==1 ; wd 1 Date of compilation as sixbit YYMMDD.
+HDRTIM==2 ; wd 2 Time of compilation as sixbit HHMMSS.
+HDRUNM==3 ; wd 3 Address in file of UNAME table.
+HDRLNM==4 ; wd 4 Address in file LASTNAME table.
+HDRDTA==5 ; wd 5 Address in file of start of data area.
+ ; The data area must start on a page boundary,
+ ; and it must be the last thing in the file.
+HDRHSN==6 ; wd 6 Address in file of HSNAME table.
+ ;.... other data; the tables just mentioned
+ ; and strings which they point to.
+
+;UNAME table:
+; wd 0 Number of entries in this table,
+;followed by entries, one per page of data area,
+;each containing the UNAME of the first data area entry which begins on that page.
+
+;LASTNAME table:
+; wd 0 Number of entries in this table,
+; followed by entries, in order by last name
+; Each entry looks like this:
+; rh addr in file of entry
+; lh addr in file of Last-name string
+
+;The lastname strings are word-aligned upper-case ASCIZ strings,
+; and they follow the LASTNAME table.
+
+;HSNAME table:
+; Currently this table is simply snarfed from the file INQUIR;DIRS BIN,
+; which is assembled from INQUIR;DMUNCH >. It's format is as follows:
+
+ 0: -<# entries>,,# wds/entry
+ 1-n: MACH entries
+
+=================================================================
+Sub-tables
+
+ mach wd 0: ; 6bit returned by SSTATU
+ mach wd 1: ; Arpanet site #.
+ mach wd 2: ; Addr is rel to start of HSNAME-table.
+ mach wd 3:
+
+Each sub-table is simply:
+ 0: -<# entries>,,# wds per entry ; RH is currently 2.
+ 1-n: NAME entries
+
+ entry wd 0: UNAME ; For all unames => this but < next entry,
+ entry wd 1: HSNAME ; this is the HSNAME.
+
+|
+
+ ; HSNAME table indices
+hx$mnm==:0 ; wd 0 of mach-table entry is mach name, as per SSTATU call.
+hx$hst==:1 ; wd 1 is arpanet host #.
+hx$nrm==:2 ; wd 2 is sub-table ptr for normal unames.
+hx$tur==:3 ; wd 3 is sub-table ptr for tourists.
+hx$len==:4 ; # wds per mach-table entry
+
+ ; Sub-table indices
+hs$unm==:0 ; wd 0 of sub-table entry is UNAME
+hs$hsn==:1 ; wd 1 is HSNAME for range.
+hs$len==:2 ; # wds per sub-table entry
+
+;The data area:
+; It starts on a page boundary. It is made up of consecutive entries,
+; in order by UNAME, each looking like this:
+LDACNT==0 ; entry wd 0 lh
+ ; the number of words in the entry,
+ ; including this one.
+ ; entry wd 0 rh -1
+
+; followed by unaligned ASCIZ strings, one per item, separated
+; only by the single ^@ that ends the ASCIZ. The strings are associated
+; with their meanings according to their numerical position in the entry.
+; The entire entry is then padded to a word boundary with nulls.
+; Note that the low bit is set in the count-words of entries
+; and not in any other words of the data area.
+
+; Symbols for all the item numbers are defined in LSRTNS as follows:
+
+ I$==,-1 ;Bit typeout mode prefix.
+ I$UNAM==0 ;UNAME
+ I$NAME==1 ;FULL NAME
+ I$NICK==2 ;NICKNAME
+ I$SSN==3 ;SOC SEC #.
+ I$MITA==4 ;MIT ADDRESS
+ I$MITT==5 ;MIT TELEPHONE NUMBER
+ I$HOMA==6 ;HOME ADDRESS
+ I$HOMT==7 ;HOME TELEPHONE NUMBER
+ I$SUPR==10 ;SUPERVISOR(S)
+ I$PROJ==11 ;PROJECT
+ I$DIR==12 ;FILE DIR NAMES
+ I$AUTH==13 ;AUTHORIZATION
+ I$GRP==14 ;GROUP AFFILIATION
+ I$REL==15 ;RELATION TO GROUP
+ I$BRTH==16 ;BIRTHDAY
+ I$REM==17 ;REMARKS
+ I$NETA==20 ;NETWORK ADDRESS
+ I$ALTR==21 ;USER &TIME OF LAST ALTERATION
+ I$MACH==22 ;I.T.S.'S TO BE KNOWN ON.
+
+; The entries are sorted in ascii order, which is NOT the same
+; as the order obtained by arithmetically sorting the SIXBIT unames.
+
+; The end of the data area is marked by ,,-1, which
+; is tantamount to an entry 0 words long.
+; That word is also the last word of the file.
+
+
+Local Modes
+Auto Fill Mode:1
+end:
diff --git a/doc/info/pdp-10.15 b/doc/info/pdp-10.15
new file mode 100755
index 00000000..01975acd
--- /dev/null
+++ b/doc/info/pdp-10.15
@@ -0,0 +1,2772 @@
+-*-Text-*-
+
+PDP-10 Node: Top, Up: (DIR), Next: Intro
+
+PDP-10 Machine Language.
+
+This file attempts to teach the machine language of the PDP-10 computer. It
+describes what instructions are available and what they do. The conventions
+of the assembler in which PDP-10 machine programs are usually written are
+another subject; see *Note MIDAS: (MIDAS).
+
+The machine language itself:
+
+* Menu:
+
+* Intro:: Introduction
+* Memory:: Addressing memory. Formats of memory words.
+* IFormat:: General instruction formats.
+* Terms:: Terminology.
+* Addr-Comp:: Effective address computation.
+* Full-Word:: Full word data transfer instructions
+* Stack:: Stack instructions.
+* Half-Word:: Half word data transfer instructions.
+* Arith Tests:: Conditional jumps on signs and comparisons.
+* Fixed Point:: Fixed point arithmetic operations.
+* KL-Only:: KL-10 double precision fixed point.
+* Floating Point:: Floating point arithmetic operations.
+* Shifting:: Shift and rotate instructions.
+* Byte:: Byte extraction instructions.
+* Logical Tests:: Conditional skip on bit test instructions.
+* Boolean:: Bitwise logical operations.
+* PC Format:: Format of PC saved by subroutine calls.
+* Jumps:: Jumps other than arithmetic conditionals.
+* Obsolete:: Obsolete subroutine call instructions.
+
+Program examples:
+
+* Program:: Complete simple program.
+* TTY Output:: Simple terminal output.
+* Reverse:: Simple terminal input and output.
+* Even-Odd:: Read a line, separate even- and odd-numbered chars.
+* Even-Odd-Vowels:: Separates vowels from consonants too.
+* Even-Odd-Vowels 2:: Another way of writing the previous example.
+* Calculator:: Reads arithmetic expressions, prints results.
+* FileIO:: Reading and writing files.
+* Parsing:: Converting input to SIXBIT, or to filenames.
+* BufInput:: Buffered input from files.
+* BufPadding:: Buffered input, discarding padding at end of file.
+
+I haven't got the time to test these examples. That means they may have bugs.
+Sorry. But it's a useful exercise to test one and, if it doesn't work, fix it
+and tell BUG-INFO.
+
+* Debugging:: Using DDT to debug programs or try out instructions.
+
+
+PDP-10 Node: Intro, Up: Top, Previous: Top, Next: Memory
+
+Introduction to PDP-10 Assembly Language Programming
+
+The PDP-10 is a general purpose stored program computer. There are four
+different processors (computers) in the PDP-10 family (the PDP-6, the KA10,
+the KI10 and the KL10). This file discusses primarily the KA-10 version,
+which is what most of the ITS systems are.
+
+There are three principal aspects of assembly language programming:
+the machine instructions, the assembler, and the operating system.
+
+The machine instructions are the primitive operations with which we
+write programs. Learning the instruction set means learning what
+operations are performed by each instruction. Programming is the art
+or science of combining these operations to accomplish some
+particular task.
+
+The machine instructions, like everything else in a computer, are in
+binary. The assembler is a program that translates the mnemonic
+names by which we refer to instructons into the binary form that the
+computer recognizes. The assembler also does a variety of other
+chores that are essentially bookkeeping. There are several assemblers
+for the PDP-10, which differ in various ways; what they all have in
+common is the PDP-10 machine instructions, which are described in this
+file. Everything else about how to use a particular assembler is
+documented under that assembler. The assembler used most on ITS is
+called MIDAS; *Note MIDAS: (MIDAS).
+
+The operating system is a special program that handles all input and
+output and which schedules among user programs. For its own
+protection and the protection of other users the operating system
+places various restrictions on user programs. User mode programs are
+restricted to memory assigned to them by the operating system; they
+may not perform any machine input-output instructions, nor can they
+perform several other restricted operations (e.g., HALT instruction).
+To facilitate user input-output and core allocation the operating
+system provides various system calls (UUO or JSYS operations) by
+which a user program can communicate its wishes to the system.
+Essentially all programs except the operating system itself are run
+as user mode programs. Editors, assemblers, compilers, utilities,
+and programs that you write yourself are all user mode programs.
+
+PDP-10 Node: Memory, Previous: Intro, Up: Top, Next: IFormat
+
+Memory
+
+In programming the PDP-10 it is convenient to imagine that your
+program occupies contiguous virtual memory locations from 0 to some
+maximum address. All memory locations are equivalent for most
+purposes (but some operating systems reserve some of your space for
+their own purposes).
+
+Accumulators
+
+Sixteen memory locations (addresses 0 to 17 - note that addresses
+will appear in octal) are distinguished by their use as general
+purpose registers (also called accumulators or index registers).
+Most PDP-10 instructions address one memory operand and one
+accumulator (so-called "one and a half address" architecture). This
+means that nearly all instructions affect some accumulator. These
+registers are actually implemented in high speed solid state memory
+rather than in slower core. For any purpose where it is convenient
+to do so, a user may reference an accumulator as memory.
+
+
+PDP-10 Node: IFormat, Previous: Memory, Up: Top, Next: Terms
+
+Instruction Formats
+
+The PDP-10 is a word oriented machine. Words contain 36 data bits,
+numbered (left to right) 0 to 35. Every machine instruction is one
+word. The program counter or PC is a register which contains the
+address of the next word to be used as an instruction; after a normal
+instruction, the PC is incremented by one so that successive
+instructions come from successive words.
+
+There are two formats for machine instructions. Most
+instructions have the format:
+
+ 000000000 0111 1 1111 112222222222333333
+ 012345678 9012 3 4567 890123456789012345
+ ________________________________________
+| | | | | |
+| OP | AC |I| X | Y |
+|_________|____|_|____|__________________|
+
+
+
+Input-output instructions (which are illegal in user mode) have the
+format: (These instructions are not discussed any farther by this
+file).
+
+ 000 0000000 111 1 1111 112222222222333333
+ 012 3456789 012 3 4567 890123456789012345
+ _________________________________________
+| | | | | | |
+|111| DEV |IOP|I| X | Y |
+|___|_______|___|_|____|__________________|
+
+In the diagrams above the field names are
+ OP = operation code
+ AC = accumulator field
+ I = indirect bit
+ X = index field
+ Y = address field
+ DEV = device code
+ IOP = input-output operation code
+
+Some example intructions are:
+
+ MOVE 1,@100 ;MOVE is the OP. AC is 1.
+ ;@ sets the I bit.
+ ;X is zero, Y is 100.
+
+ HRRZ 17,1(3) ;HRRZ is the OP. AC is 17,
+ ;Y = 1, X = 3, I = 0
+
+ SOS FOO ;SOS is OP, FOO is symbolic
+ ;for the Y field. AC, X, I are 0.
+
+The address field, the index field, and the indirect bit are all used
+in effective addrss computation. *Note Addr: Addr-comp.
+
+PDP-10 Node: Terms, Previous: IFormat, Up: Top, Next: Addr-Comp
+
+Terminology
+
+Symbols particular to this file:
+
+# means "not equal".
+<= means "less than or equal".
+>= means "greater than or equal".
+<- means "is assigned the new value".
+
+AC means the contents of the AC field of the current instruction;
+ this is a number from 0 to 17.
+E means the value of the effective address of the current instruction.
+ *Note Addr: Addr-Comp, for how this is computed.
+PC means the address from which the next instruction will be fetched.
+C(...) surrounding an expression refers to the contents of the memory
+ location whose address is the value of the expression.
+ Thus, C(AC) is the contents of the accumulator which the
+ instruction refers to, and C(E) is the contents of the memory
+ location which the instruction refers to.
+CR(...) means the right half, only, of the contents.
+CS(...) means the contents, with the two halves swapped.
+CL(...) means the left half, only, of the contents.
+
+Symbols which are taken from assembler language:
+
+x,,y means a word whose left half contains x, and whose right half
+ contains y. This is similar to x*1000000+y, except that x,,y
+ truncates y, using only the low 18 bits of it.
+
+<...> surrounding an expression serves the same purpose
+ as parentheses in algebra. Thus, 5*<1,,1> equals 5,,5.
+
+[...] surrounding an expression means the address of a word
+ in memory which contains the specified expression.
+ Thus, [2] means the address of a word containing 2.
+ This is called a literal. The address could turn out to
+ be anything at all, but the proper ways to use literals are
+ such that only the contents matter.
+
+(...) surrounding an expression exchanges the halves of that
+ expression. Thus, (3,,4) equals 4,,3.
+
+PDP-10 Node: Addr-Comp, Previous: Terms, Up: Top, Next: Full-Word
+
+Effective Address Calculation
+
+All instructions without exception calculate an "effective address".
+The effective address gets its name because it is usually used as the
+address of an operand in memory. Depending on the instruction, that
+operand might be read, written or both. For some instructions, called
+"immediate" instructions, the effective address is not used to address
+memory; it is used directly, as a number, in the operation. For
+example, the ADD instruction uses the effective address as the
+address of a location in memory, and uses the contents of that
+location in the addition. The ADDI instruction (Add Immediate) uses
+the effective address itself as the number to add.
+
+The effective address computation uses three fields of the instruction
+word: the 18-bit address field (Y), the index field (X), and the
+indirect bit (I). The result is an 18-bit effective address.
+
+If the X field and I bit are zero, the effective address is simply the
+contents of the address field (Y).
+
+If the index field X is nonzero, then it is the number of an
+accumulator to use as an index register. Any accumulator except
+accumulator 0 can be so used. The right half of the contents of the
+index register is added to the address field (Y) from the instruction
+to get the effective address.
+
+The I bit specifies indirect addressing. If it is 1, then the result
+of the previous steps (Address field, or address field plus index
+quantity) is used as the address of an "indirect word". From the
+contents of this indirect word, a new address field Y, index field X
+and indirect bit I are obtained. Then the process starts from the
+beginning. If the I bit in the indirect word is 1, a second indirect
+word is eventually fetched. Indirection can happen any number of
+times, and only stops when an indirect word has 0 in its I bit.
+
+The result of the effective address calculation may be thought of as
+an instruction word where bits 0:12 are copied from the original
+instruction, bits 13:17 are zero, and 18:35 contain the effective
+address.
+
+The effective address computation is described by the following
+program. MA means memory address. PC means program counter. C(MA)
+means contents of the word addressed by MA.
+
+IFETCH: MA <- PC
+ OP <- Bits 0:8 of C(MA);
+ AC <- Bits 9:12 of C(MA);
+EACOMP: I <- Bit 13 of C(MA);
+ X <- Bits 14:17 of C(MA);
+ Y <- Bits 18:35 of C(MA);
+ E <- Y;
+ IF NOT(X=0) then E <- E+C(X);
+ IF I=0 then go to done;
+ MA <- E;
+ GO TO EACOMP;
+DONE:
+
+
+
+PDP-10 Node: Full-Word, Previous: Addr-Comp, Up: Top, Next: Stack
+
+Full word instructions. MOVE, BLT, EXCH, PUSH, POP
+
+These are the instructions whose basic purpose is to move one or more
+full words of data from one location to another, usually from an
+accumulator to a memory location or vice versa. In some cases, minor
+arithmetic operations are performed, such as taking the magnitude or
+negative of a word.
+
+The MOVE class of instructions perform full word data transmission
+between an accumulator and a memory location. There are sixteen
+instructions in the MOVE class. All mnemonics begin with MOV. The
+first modifier specifies a data transformation operation; the second
+modifier specifies the source of data and the destination of the
+result.
+
+
+ |E no modification | from memory to AC
+MOV |N negate source |I Immediate. Move the address to AC.
+ |M magnitude |M from AC to memory
+ |S swap source |S to self. If AC#0, move to AC also
+
+"Magnitude" means that the absolute value of the input quantity is
+what is stored in the output.
+"Swap Source" means that the right and left halves of the input
+quantity are interchanged before storing into the output.
+
+In a "to self" instruction, the input value (negated, swapped, or the
+magnitude, if appropriate) is stored back into the memory location; if
+the AC field is nonzero, the value is stored in the AC as well.
+
+MOVE C(AC) <- C(E)
+MOVEI C(AC) <- 0,,E
+MOVEM C(E) <- C(AC)
+MOVES C(E) <- C(E); if AC#0 then C(AC) <- C(E)
+
+MOVN C(AC) <- -C(E)
+MOVNI C(AC) <- -E
+MOVNM C(E) <- -C(AC)
+MOVNS C(E) <- -C(E); if AC#0 then C(AC) <- -C(E)
+
+MOVM C(AC) <- |C(E)|
+MOVMI C(AC) <- 0,,E
+MOVMM C(E) <- |C(AC)|
+MOVMS C(E) <- |C(E)|; if AC#0 then C(AC) <- |C(E)|
+
+MOVS C(AC) <- CS(E)
+MOVSI C(AC) <- E,,0
+MOVSM C(E) <- CS(AC)
+MOVSS C(E) <- CS(E); if AC#0 then C(AC) <- CS(E)
+
+
+
+
+
+EXCH exchanges the contents of the selected ac with the contents of
+the effective address.
+
+EXCH C(AC)>; C(CR(AC))<-C(E)
+
+The specified accumulator is incremented by adding 1 to each half (in
+the KI10 and KL10 carry out of the right half is suppressed). If, as
+result of the addition, the left half of the AC becomes positive, a
+pushdown overflow condition results (but the instruction procedes to
+completion). The word addressed by the effective address is fetched
+and stored on the top of the stack which is addressed by the right
+half of the (incremented) accumulator.
+
+POP C(E)<-C(CR(AC)); C(AC)<-C(AC)-<1,,1>
+
+POP undoes PUSH as follows: the word at the top of the stack
+(addressed by the right half of the selected AC) is fetched and
+stored at the effective address. Then the AC is decremented by
+subtracting 1 from both halves (in the KI10 and KL10 carry out of bit
+18 is suppressed). If the AC becomes negative as a result of the
+subtraction a pushdown overflow results.
+
+Often the accumulator used as the pushdown pointer is given the
+symbolic name P. To initialize a pushdown pointer (e.g., for N words
+starting at PDL), one might do the following:
+ MOVE P,[-N,,PDL-1]
+
+Elsewhere in the program should appear:
+
+PDL: BLOCK N
+
+which defines the symbolic label PDL and reserves N words
+following it.
+
+PDP-10 Node: Half-Word, Previous: Stack, Up: Top, Next: Arith Tests
+
+Halfword instructions
+
+The halfword class of instructions perform data transmission between
+one half of an accumulator and one half of a memory location. There
+are sixty-four halfword instructions. Each mnemonic begins with H
+and has four modifiers. The first modifier specifies which half of
+the source word; the second specifies which half of the destination.
+The third modifier specifies what to do to the other half of the
+destination. The fourth modifier specifies the source of data and
+the destination of the result.
+
+H halfword from |R right of source to
+ |L left
+
+ |R right of destination
+ |L left
+
+ | no modification of other half
+ |Z zero other half
+ |O set other half to ones
+ |E sign extend source to other half
+
+ | from memory to AC
+ |I Immediate
+ |M from AC to memory
+ |S to self. If AC#0, then move to AC also.
+
+C18 means bit 18 of the contents (the high bit of the low half);
+C0 means bit 0 of the contents (the high bit of the high half);
+E18 means the high bit of the effective address.
+777777*X evaluates to 0 if X is 0, or 777777 (all ones) if X is one.
+Such expressions represent sign extension.
+
+HRR CR(AC) <- CR(E)
+HRRI CR(AC) <- E
+HRRM CR(E) <- CR(AC)
+HRRS CR(E) <- CR(E); if AC#0 then CR(AC) <- CR(E)
+
+HRRZ C(AC) <- 0,,CR(E)
+HRRZI C(AC) <- 0,,E
+HRRZM C(E) <- 0,,CR(AC)
+HRRZS C(E) <- 0,,CR(E); if AC#0 then C(AC) <- 0,,CR(E)
+
+HRRO C(AC) <- 777777,,CR(E)
+HRROI C(AC) <- 777777,,E
+HRROM C(E) <- 777777,,CR(AC)
+HRROS C(E) <- 777777,,CR(E); if AC#0 then C(AC) <- 777777,,CR(E)
+
+HRRE C(AC) <- 777777*C18(E),,CR(E);
+HRREI C(AC) <- 777777*E18,,E
+HRREM C(E) <- 777777*C18(AC),,CR(AC)
+HRRES C(E) <- 777777*C18(E),,CR(E);
+ if AC#0 then C(AC) <- 777777*C18(E),,CR(E)
+
+HRL CL(AC) <- CR(E)
+HRLI CL(AC) <- E
+HRLM CL(E) <- CR(AC)
+HRLS CL(E) <- CR(E); if AC#0 then CL(AC) <- CR(E)
+
+HRLZ C(AC) <- CR(E),,0
+HRLZI C(AC) <- E,,0
+HRLZM C(E) <- CR(AC),,0
+HRLZS C(E) <- CR(E),,0; if AC#0 then C(AC) <- CR(E),,0
+
+HRLO C(AC) <- CR(E),,777777
+HRLOI C(AC) <- E,,777777
+HRLOM C(E) <- CR(E),,777777
+HRLOS C(E) <- CR(E),,777777; if AC#0 then C(AC) <- CR(E),,777777
+
+HRLE C(AC) <- CR(E),,777777*C18(E)
+HRLEI C(AC) <- E,,777777*E18
+HRLEM C(E) <- CR(AC),,777777*C18(AC)
+HRLES C(E) <- CR(E),,777777*C18(E);
+ if AC#0 then C(AC) <- CR(E),,777777*C18(E)
+
+HLR CR(AC) <- CL(E)
+HLRI CR(AC) <- 0
+HLRM CR(E) <- CL(AC)
+HLRS CR(E) <- CL(E); if AC#0 then CR(AC) <- CL(E)
+
+HLRZ C(AC) <- 0,,CL(E)
+HLRZI C(AC) <- 0
+HLRZM C(E) <- 0,,CL(AC)
+HLRZS C(E) <- 0,,CL(E); if AC#0 then C(AC) <- 0,,CL(E)
+
+HLRO C(AC) <- 777777,,CL(E)
+HLROI C(AC) <- 777777,,0
+HLROM C(E) <- 777777,,CL(AC)
+HLROS C(E) <- 777777,,CL(E); if AC#0 then C(AC) <- 777777,,CL(E)
+
+HLRE C(AC) <- 777777*C0(E),,CL(E);
+HLREI C(AC) <- 0
+HRREM C(E) <- 777777*C0(AC),,CL(AC)
+HRRES C(E) <- 777777*C0(E),,CL(E);
+ if AC#0 then C(AC) <- 777777*C0(E),,CR(E)
+
+HLL CL(AC) <- CL(E)
+HLLI CL(AC) <- 0
+HLLM CL(E) <- CL(AC)
+HLLS CL(E) <- CL(E); if AC#0 then CL(AC) <- CL(E)
+
+HLLZ C(AC) <- CL(E),,0
+HLLZI C(AC) <- 0
+HLLZM C(E) <- CL(AC),,0
+HLLZS C(E) <- CL(E),,0; if AC#0 then C(AC) <- CL(E),,0
+
+HLLO C(AC) <- CL(E),,777777
+HLLOI C(AC) <- 0,,777777
+HLLOM C(E) <- CL(E),,777777
+HLLOS C(E) <- CL(E),,777777; if AC#0 then C(AC) <- CL(E),,777777
+
+HLLE C(AC) <- CL(E),,777777*C0(E)
+HLLEI C(AC) <- 0
+HLLEM C(E) <- CL(AC),,777777*C0(AC)
+HLLES C(E) <- CL(E),,777777*C0(E);
+ if AC#0 then C(AC) <- CL(E),,777777*C0(E)
+
+PDP-10 Node: Arith Tests, Previous: Half-word, Up: Top, Next: Fixed Point
+
+Arithmetic testing. AOBJP, AOBJN, JUMP, SKIP, CAM, CAI, AOS, SOS, SOJ, AOJ
+
+The AOBJ (Add One to Both halves of AC and Jump) instructions allow
+forward indexing through an array while maintaining a control count
+in the left half of an accumulator. Use of AOBJN and AOBJP can
+reduce loop control to one instruction.
+
+AOBJN C(AC)<-C(AC)+<1,,1>; If C(AC)<0 then PC<-E;
+AOBJP C(AC)<-C(AC)+<1,,1>; If C(AC)>=0 then PC<-E;
+
+Example. Add 3 to N words starting at location TAB:
+ MOVSI 1,-N ;Initialize register 1 to -N,,0
+ MOVEI 2,3 ;register 2 gets the constant 3.
+ ADDM 2,TAB(1) ;add 3 to one array element.
+ AOBJN 1,.-1 ;increment both the index and the control.
+ ;Loop until the ADDM has been done N times.
+
+By the way, for the sake of consistency, AOBJN should have been called
+AOBJL and AOBJP should have been called AOBJGE. However, they weren't.
+
+
+The JUMP instructions compare the selected accumulator to zero and
+jump (to the effective address of the instruction) if the specified
+relation is true.
+
+JUMP Jump never. This instruction is a no-op.
+JUMPL If C(AC) < 0 then PC<-E;
+JUMPLE If C(AC) <= 0 then PC<-E;
+JUMPE If C(AC) = 0 then PC<-E;
+JUMPN If C(AC) # 0 then PC<-E;
+JUMPGE If C(AC) >= 0 then PC<-E;
+JUMPG If C(AC) > 0 then PC<-E;
+JUMPA PC<-E. This is an unconditional branch.
+
+Example:
+ JUMPLE 5,FOO ;Jump to FOO if AC 5 is negative or zero.
+
+
+The SKIP instructions compare the contents of the effective address
+to zero and skip the next instruction if the specified relation is
+true. If a non-zero AC field appears, the selected AC is loaded from
+memory.
+
+SKIP If AC#0 then C(AC)<-C(E);
+SKIPL If AC#0 then C(AC)<-C(E); If C(E) < 0 then skip
+SKIPLE If AC#0 then C(AC)<-C(E); If C(E) <= 0 then skip;
+SKIPE If AC#0 then C(AC)<-C(E); If C(E) = 0 then skip;
+SKIPN If AC#0 then C(AC)<-C(E); If C(E) # 0 then skip;
+SKIPGE If AC#0 then C(AC)<-C(E); If C(E) >= 0 then skip;
+SKIPG If AC#0 then C(AC)<-C(E); If C(E) > 0 then skip;
+SKIPA If AC#0 then C(AC)<-C(E); skip;
+
+Example:
+ SKIPL FOO ;Unless FOO's contents are negative,
+ MOVE 1,BAR ;load BAR's contents into accumulator 1.
+ ;By convention, instructions which can be
+ ;are written indented an extra space.
+
+ SKIPN 2,FOO ;Load FOO's contents into accumulator 2
+ ;and if they are nonzero, skip the next
+ ;instruction.
+
+
+The AOS (Add One to memory and Skip) instructions increment a memory
+location, compare the result to zero to determine the skip condition,
+If a non-zero AC field appears then the AC selected will be loaded
+(with the incremented data).
+
+AOS Add One to Storage (don't skip).
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+
+AOSL Add One and Skip if Less than zero.
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+ If C(E) < 0 then skip;
+
+AOSLE Add One and Skip if Less than or Equal to zero.
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+ If C(E) <= 0 then skip;
+
+AOSE Add One and Skip if Equal to zero.
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+ If C(E) = 0 then skip;
+
+AOSN Add One and Skip if Not zero.
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+ If C(E) # 0 then skip;
+
+AOSGE Add One and Skip if Greater than or Equal to zero.
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+ If C(E) >= 0 then skip;
+
+AOSG Add One and Skip if Greater than zero.
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+ If C(E) > 0 then skip;
+
+AOSA Add One and Skip Always
+ C(E) <- C(E)+1; If AC#0 then C(AC)<-C(E);
+ skip;
+
+Example:
+;This is the way, in parallel processing,
+;we wait for a lock to be free and then lock it.
+;If the lock is unlocked, it contains -1, so incrementing it yields zero.
+ AOSE FOO ;Increment FOO's contents, skip if zero.
+ JUMPA .-1 ;If they aren't zero, do it again.
+
+
+The SOS (Subtract One from memory and Skip) instructions decrement a
+memory location, then compare the result to zero to decide whether to
+skip. If a non-zero AC field appears then the AC selected will
+be loaded (with the decremented data).
+
+The SOS instructions are just like the AOS instrucrtions except that
+they subtract one instead of adding one.
+
+SOS Subtract One from Storage (don't skip).
+ C(E) <- C(E)-1; If AC#0 then C(AC)<-C(E);
+
+SOSL Subtract One and Skip if Less than zero.
+ Perform SOS instruction:
+ C(E) <- C(E)-1; If AC#0 then C(AC)<-C(E);
+ Then, if C(E) < 0 then skip;
+
+The other SOS instructions differ from SOSL only in when they skip.
+
+SOSLE Subtract One and Skip if Less than or Equal to zero.
+SOSE Subtract One and Skip if Equal to zero.
+SOSN Subtract One and Skip if Not zero.
+SOSGE Subtract One and Skip if Greater than or Equal to zero.
+SOSG Subtract One and Skip if Greater than zero.
+SOSA Subtract One and Skip Always
+
+
+The AOJ (Add One to AC and Jump) instructions increment the contents
+of the selected accumulator. If the result bears the indicated
+relation to zero then the instruction will jump to the effective
+address.
+
+AOJ Add One (don't jump).
+ C(AC) <- C(AC)+1;
+
+AOJL Add One and Jump if Less than zero.
+ C(AC) <- C(AC)+1; If C(AC) < 0 then PC <- E;
+
+The other AOJ instructions differ from AOJL only in how they decide
+whether to jump.
+
+AOJLE Add One and Jump if Less than or Equal to zero.
+AOJE Add One and Jump if Equal to zero.
+AOJN Add One and Jump if Not zero.
+AOJGE Add One and Jump if Greater than or Equal to zero.
+AOJG Add One and Jump if Greater than zero.
+AOJA Add One and Jump Always
+
+
+The SOJ (Subtract One from AC and Jump) instructions decrement the
+contents of the selected accumulator. If the result bears the
+indicated relation to zero then the instruction will jump to the
+effective address.
+
+SOJ Subtract One (don't jump).
+ C(AC) <- C(AC)-1;
+
+SOJL Subtract One and Jump if Less than zero.
+ C(AC) <- C(AC)-1; If C(AC) < 0 then PC <- E;
+
+The other SOJ instructions differ from SOJL only in how they decide
+whether to jump.
+
+SOJLE Subtract One and Jump if Less than or Equall to zero.
+SOJE Subtract One and Jump if Equal to zero.
+SOJN Subtract One and Jump if Not zero.
+SOJGE Subtract One and Jump if Greater than or Equal to zero.
+SOJG Subtract One and Jump if Greater than zero.
+SOJA Subtract One and Jump Always
+
+
+The CAM (Compare Accumulator to Memory) class compare the contents of
+the selected accumulator to the contents of the effective address.
+If the indicated condition is true, the instruction will skip. The
+CAM instruction is suitable for arithmetic comparision of either
+fixed point quantities or normalized floating point quantities.
+Needless to say, for the comparison to be meaningful both C(AC) and
+C(E) should be in the same format (i.e., either both fixed or both
+floating).
+
+CAM no op (references memory)
+CAML If C(AC) < C(E) then skip;
+CAMLE If C(AC) <= C(E) then skip;
+CAME If C(AC) = C(E) then skip;
+CAMN If C(AC) # C(E) then skip;
+CAMGE If C(AC) >= C(E) then skip;
+CAMG If C(AC) > C(E) then skip;
+CAMA skip;
+
+The CAI (Compare Accumulator Immediate) class compare the contents of
+the selected accumulator to the value of the effective address. If
+the indicated condition is true, the instruction will skip.
+An effective address is an 18 bit quantity that is always considered
+to be positive.
+
+CAI no op
+CAIL If C(AC) < E then skip;
+CAILE If C(AC) <= E then skip;
+CAIE If C(AC) = E then skip;
+CAIN If C(AC) # E then skip;
+CAIGE If C(AC) >= E then skip;
+CAIG If C(AC) > E then skip;
+CAIA skip;
+
+PDP-10 Node: Fixed Point, Previous: Arith Tests, Up: Top, Next: KL-Only
+
+Fixed point arithmetic ADD, SUB, IMUL, IDIV, MUL, DIV
+
+In positive numbers bit 0 is zero. Bits 1 is most significant; bit
+35 is least significant. Negative numbers are the twos complement of
+postive numbers. Results (of ADD, SUB or IMUL) outside the range
+-2^|35 to 2^|35-1 will set overflow (PC bit 0).
+
+Each arithmetic instruction has four forms, with modifier characters
+(nothing), M, B and I.
+
+The ordinary form operates on an accumulator and memory,
+ putting the result in the accumulator.
+The Memory form puts the result in the memory location instead.
+ The accumulator is not changed.
+The Both form stores the result in both the accumulator and the memory
+ location.
+The Immediate form uses an accumulator and the effective address,
+ putting the result in the accumulator.
+
+ADD C(AC) <- C(AC) + C(E);
+ADDI C(AC) <- C(AC) + E;
+ADDM C(E) <- C(AC) + C(E);
+ADDB C(AC) <- C(AC) + C(E); C(E) <- C(AC);
+
+SUB C(AC) <- C(AC) - C(E);
+SUBI C(AC) <- C(AC) - E;
+SUBM C(E) <- C(AC) - C(E);
+SUBB C(AC) <- C(AC) - C(E); C(E) <- C(AC);
+
+The IMUL instructions are for multiplying numbers where the product
+is expected to be representable as one word.
+
+IMUL C(AC) <- C(AC) * C(E);
+IMULI C(AC) <- C(AC) * E;
+IMULM C(E) <- C(AC) * C(E);
+IMULB C(AC) <- C(AC) * C(E); C(E) <- C(AC);
+
+The IDIV instructions are for divisions in which the dividend is a one
+word quantity. Two consecutive accumulators are used for the results;
+these are AC for the quotient, and AC+1 for the remainder (Actually,
+AC+1 is calculated mod 20, so if AC=17, the remainder is stored in
+accumulator 0.) If the divisor is zero set overflow and no divide;
+don't change AC or memory operands. The remainder will have the same
+sign as the dividend.
+
+IDIV C(AC) <- C(AC) / C(E); C(AC+1) <- remainder
+IDIVI C(AC) <- C(AC) / E; C(AC+1) <- remainder;
+IDIVM C(E) <- C(AC) / C(E);
+IDIVB C(AC) <- C(AC) / C(E); C(AC+1) <- remainder; C(E) <- C(AC);
+
+
+The MUL instructions produce a double word product. A double word
+integer has 70 bits of significance. Bit 0 of the high order word is
+the sign bit. In data, Bit 0 of the low order word is ignored by the
+hardware. In results, bit 0 of the low word is the same as bit 0 in
+the high word. MUL will set overflow if both operands are -2^|35.
+
+MUL C(AC AC+1) <- C(AC) * C(E);
+MULI C(AC AC+1) <- C(AC) * E;
+MULM C(E) <- high word of product of C(AC) * C(E);
+MULB C(AC AC+1) <- C(AC) * C(E); C(E) <- C(AC);
+
+The DIV instructions are for divisions in which the dividend is a two
+word quantity (such as produced by MUL). If C(AC) is greater than the
+memory operand then set overflow and no divide.
+
+
+DIV C(AC) <- C(AC AC+1) / C(E); C(AC+1) <- remainder;
+DIVI C(AC) <- C(AC AC+1) / E; C(AC+1) <- remainder;
+DIVM C(E) <- C(AC AC+1) / C(E);
+DIVB C(AC) <- C(AC AC+1) / C(E); C(AC+1) <- remainder;
+ C(E) <- C(AC);
+
+PDP-10 Node: KL-Only, Previous: Fixed Point, Up: Top, Next: Floating Point
+
+This node describes some instructions that only KL-10's have. This
+means that the only ITS machine which has them is MC. You should
+probably not use them even if you expect to run on MC, so that your
+program can be moved.
+
+Double word Move instructions (KI10 and KL10)
+
+There are four double word move instructions. These are suitable for
+manipulating KI10 and KL10 double precision floating point numbers,
+and for KL10 double precision integers.
+
+DMOVE C(AC AC+1) <- C(E E+1)
+DMOVEM C(E E+1) <- C(AC AC+1)
+DMOVN C(AC AC+1) <- -C(E E+1)
+DMOVNM C(E E+1) <- -C(AC AC+1)
+
+Note that the DMOVN and DMOVNM are NOT to be used for KA10 double
+precision floating point numbers!
+
+If a program is written that may be have to be run on a KA10, the use
+of all double word instructions should be avoided.
+
+Double Precision Integer Arithmetic (KL10 only)
+
+There are four instructions for double precision integer arithmetic.
+None of these instructions have any modifier: they all operate on
+double (or quadruple) accumulators and double words in memory with
+results to double (or quadruple) accumulators.
+
+The format for a double word integer is the same as that produced by
+MUL, i.e., a 70 bit integer in twos complement, with bit 0 of the
+most significant word is the sign; in operands, bit 0 of the low
+order word is ignored. A quadruple word has 140 bits; bit 0 of the
+most significant word is the sign; in operands, bit 0 in all other
+words is ignored. In double (and quadruple) arithmetic results bit 0
+of the low order word(s) is stored with the same value as bit 0 of
+the high order word.
+
+DADD C(AC AC+1) <- C(AC AC+1) + C(E E+1);
+DSUB C(AC AC+1) <- C(AC AC+1) - C(E E+1);
+DMUL C(AC AC+1 AC+2 AC+3) <- C(AC AC+1) * C(E E+1);
+DDIV C(AC AC+1) <- C(AC AC+1 AC+2 AC+3) / C(E E+1);
+ C(AC+2 AC+3) <- remainder;
+
+PDP-10 Node: Floating Point, Previous: KL-Only, Up: Top, Next: Shifting
+
+Floating Point Arithmetic
+
+Single precision floating point numbers are represented in one 36 bit
+word as follows:
+
+ 0 00000000 011111111112222222222333333
+ 0 12345678 901234567890123456789012345
+ ______________________________________
+| | | |
+|S| EXP | Fraction |
+|_|_______|____________________________|
+
+
+If S is zero, the sign is positive. If S is one the sign is negative
+and the word is in twos complement format. The fraction is
+interpreted as having a binary point between bits 8 and 9. The
+exponent is an exponent of 2 represented in excess 200 (octal)
+notation. In a normalized floating point number bit 9 is different
+from bit 0, except in a negative number bits 0 and 9 may both be one
+if bits 10:35 are all zero. A floating point zero is represented by
+a word with 36 bits of zero. Floating point numbers can represent
+numbers with magnitude within the range 0.5*2^|-128 to
+(1-2^|-27)*2^|127, and zero.
+
+A number that in which bit 0 is one and bits 9-35 are zero can
+produce an incorrect result in any floating point operation. Any
+word with a zero fraction and non-zero exponent can produce extreme
+loss of precision if used as an operand in a floating point addition
+or subtraction.
+
+In KI10 (and KL10) double precision floating point, a second word is
+included which contains in bits 1:35 an additional 35 fraction bits.
+The additional fraction bits do not significantly affect the range of
+representable numbers, rather they extend the precision.
+
+The KA10 lacks double precision floating point hardware, however
+there are several instructions by which software may implement double
+precision. These instructions are DFN, UFA, FADL, FSBL, FMPL, and
+FDVL. Users of the KL10 are strongly advised to avoid using these
+intructions.
+
+In the PDP-6 floating pointing is somewhat different. Consult a wizard.
+
+
+ |AD add | result to AC
+F floating |SB subtract |R rounded |I Immediate. result to AC
+ |MP multiply | |M result to memory
+ |DV divide | |B result to memory and AC
+ |
+ |
+ | no rounding | result to AC
+ |L Long mode
+ |M result to memory
+ |B result to memory and AC
+
+
+ |AD add
+DF double floating |SB subtract
+ |MP multiply
+ |DV divide
+
+
+Note: In immediate mode, the memory operand is . In long mode
+(except FDVL) the result appears in AC and AC+1. In FDVL the AC
+operand is in AC and AC+1 and the quotient is stored in AC with the
+remainder in AC+1.
+
+Other floating point instructions:
+
+FSC (Floating SCale) will add E to the exponent of the number in AC
+and normalize the result. One use of FSC is to convert an integer in
+AC to floating point (but FLTR, available in the KI and KL is better)
+To use FSC to float an integer, set E to 233 (excess 200 and shift
+the binary point 27 bits). The integer being floated must not have
+more than 27 significant bits. FSC will set AROV and FOV if the
+resulting exponent exceeds 127. FXU (and AROV and FOV) will be set
+if the exponent becomes smaller than -128.
+
+DFN (Double Floating Negate) is used only to negate KA10 software
+format double precision floating point numbers. DFN treats AC and E
+as a KA10 double floating point number which it negates and stores
+back. AC is the high order word. Usually the low order word is in
+AC+1, so the instruction most often appears as DFN AC,AC+1.
+
+UFA (Unnormalized Floating Add) is used in KA10 to assist in software
+format double precision arithmetic. UFA will add C(AC) to C(E) and
+place the result in AC+1. The result of UFA will not be postnormalized
+unless in original operands the exponents and signs were the same and
+a fraction with magnitude greater than or equal to 1 was produced. Only
+in this case will a one step normalization (right shift) occur.
+UFA will overflow in the same circumstances as FAD. Underflow is not
+possible.
+
+FIX will convert a floating point number to an integer. If the
+exponent of the floating point number in C(E) is greater than
+(decimal) 35 (which is octal 243) then this instruction will set AROV
+and not affect C(AC). Otherwise, convert C(E) to fixed point by the
+following procedure: Move C(E) to AC, copying bit 0 of C(E) to bits
+1:8 of AC (sign extend). Then ASH AC by X-27 bits (where X is the
+exonent from bits 1:9 of C(E) less 200 octal).
+FIX will truncate towards zero, i.e., 1.9 is fixed to 1
+and -1.9 is fixed to -1.
+
+FIXR (Fix and round) will convert a floating point number to an
+integer by rounding. If the exponent of the floating point number in
+C(E) is greater than (decimal) 35 (which is octal 243) then this
+instruction will set AROV and not affect C(AC). Otherwise, convert
+C(E) to fixed point by the following procedure: Move C(E) to AC,
+copying bit 0 of C(E) to bits 1:8 of AC (sign extend). Then ASH AC
+by X-27 bits (where X is the exponent from bits 1:9 of C(E) less 200
+octal). If X-27 is negative (i.e., right shift) then the rounding
+process will consider the bits shifted off the right end of AC. If
+AC is positive and the discarded bits are >=1/2 then 1 is added to AC.
+If AC is negative and the discarded bits are >1/2 then 1 is added to
+AC. Rounding is always in the positive direction: 1.4 becomes 1, 1.5
+becomes 2, -1.5 becomes -1, and -1.6 becomes -2.
+
+FLTR (FLoaT and Round) will convert C(E), an integer, to floating
+point and place the result in AC. The data from C(E) is copied to AC
+where its is arithmetic shifted right 8 places (keeping the bits that
+fall off the end) and the exponent 243 is inserted in bits 1:8. The
+resulting number is normalized until bit 9 is significant
+(normalization may result in some or all of the bits that were right
+shifted being brought back into AC). Finally, if any of the bits
+that were right shifted still remain outside the AC the result is
+rounded by looking at the bit to the right of the AC.
+
+PDP-10 Node: Shifting, Previous: Floating Point, Up: Top, Next: Byte
+
+Shift instructions
+
+The following instructions shift or rotate the AC or the double word
+formed by AC and AC+1.
+
+Shift instructions are all immediate instructions. The effective
+address is not used as the address of a memory operand. Instead, it is
+used as the number of places to shift. A positive number means a left
+shift; a negative number (bit 18 = 1) means a right shift.
+
+Aside from the sign bit of the effective address, only the lowest
+eight bits are used. The other nine bits are ignored.
+
+
+LSH Logical Shift. C(AC) is shifted as specified by E. Zero
+ bits are shifted into the AC.
+
+LSHC Logical Shift Combined. C(AC AC+1) is shifted as a 72 bit
+ quantity. Zero bits are shifted in.
+
+ASH Arithmetic Shift. Bit 0 is not changed. In a left
+ shift zero bits are shifted into the right end of AC.
+ In a left shift, if any bit of significance is shifted
+ out of bit 1, AROV (overflow) is set. In a right shift,
+ bit 0 is shifted into bit 1.
+
+ASHC Arithmetic Shift Combined. AC bit 0 is not changed. If
+ E is non zero, AC bit 0 is copied to AC+1 bit 0.
+ C(AC AC+1) is shifted as a 70 bit quantity. In a left
+ shift zero bits are shifted into the right end of AC+1.
+ In a left shift, if any bit of significance is shifted
+ out of AC bit 1 then AROV is set. In a right shift AC
+ bit 0 is shifted into AC bit 1.
+
+ROT Rotate. The 36 bit C(AC) is rotated. In a left rotate bits
+ shifted out of bit 0 are shifted into bit 35. In a right
+ rotate, bit 35 is shifted into bit 0.
+
+ROTC Rotate Combined. AC and AC+1 are rotated as a 72 bit
+ quantity. In a left rotate AC bit 0 shifts into AC+1
+ bit 35 and AC+1 bit 0 shifts into AC bit 35. In a right
+ rotate, AC+1 bit 35 shifts into AC bit 0, etc.
+
+JFFO Jump if Find First One. This is not actually a shift
+ instruction, but it is a related sort of thing. It counts the
+ number of leading zeros in the contents of AC, and stores this
+ number in AC+1. (If AC contains zero, the number stored in
+ AC+1 is zero, not 36). The instruction also jumps to its
+ effective address if C(AC) # 0 (in other words, if it
+ succeeded in finding the first one bit).
+
+Example:
+
+;Suppose that each bit in accumlator 1 is a flag
+;telling us that some sort of processing needs to be done.
+;We would like to find out which flags are set
+;and, for each one, do the processing. But we don't want to
+;waste a lot of time checking flags which are not set.
+
+LOOP: JFFO 1,[JRST @TABLE(2)]
+ ... ;Here all flags are zero.
+
+TABLE: FOO ;FOO handles flag bit 0
+ BAR ;BAR handles flag bit 1.
+ ... ;Other addresses for the remaining flags.
+
+FOO: ... ;Do the work.
+ TLZ 1,400000 ;Clear flag bit 0
+ JRST LOOP ;Find the next flag which is set.
+
+PDP-10 Node: Byte, Previous: Shifting, Up: Top, Next: Logical Tests
+
+Byte instructions
+
+In the PDP-10 a "byte" is some number of contiguous bits within one
+word. A byte pointer is a quantity (which occupies a whole word)
+which describes the location of a byte. There are three parts to the
+description of a byte: the word (i.e., address) in which the byte
+occurs, the position of the byte within the word, and the length of
+the byte.
+
+A byte pointer has the following format:
+
+ 000000 000011 1 1 1111 112222222222333333
+ 012345 678901 2 3 4567 890123456789012345
+ _________________________________________
+| | | | | | |
+| POS | SIZE |U|I| X | Y |
+|______|______|_|_|____|__________________|
+
+POS is the byte position: the number of bits from the right end of
+the byte to the right end of the word.
+
+SIZE is the byte size in bits.
+
+The U field is ignored by the byte instructions.
+
+The I, X and Y fields are used, just as in an instruction, to compute
+an effective address which specifies the location of the word
+containing the byte.
+
+Here are the byte instructions.
+
+LDB - Load byte. The contents of the effective address of the LDB
+instruction is interpreted as a byte pointer. The byte described
+there is loaded, right adjusted, into the AC. The rest of the AC is
+cleared.
+
+DPB - Deposit byte. The contents of the effective address of the DPB
+instruction is interpreted as a byte pointer. The byte described
+there is deposited from the byte of the same size at the right end of
+the AC. AC and the remainder of the word into which the byte is
+deposited are left unchanged.
+
+IBP - Increment byte pointer. The purpose of this instruction is to
+advance a byte pointer to point at the next consecutive byte. The AC
+field must be zero. The contents of the effective address are
+fetched. The POS field is changed by subtracting the size field from
+it. If the result of the subtraction is greater than or equal to
+zero, store the difference in the POS field. If the difference is
+negative, add 1 to the Y field (in the KA10 and PDP-6 if Y contains
+777777 then this will carry into the X field; in the KI10 and KL10 the
+carry out is suppressed) and set POS field to 44-SIZE (44 is octal).
+The effect of this is to modify the byte pointer to address the next
+byte (of the same size) that follows the byte addressed by the
+original pointer.
+
+ILDB - Increment and Load Byte. Increment the byte pointer contained
+at the effective address. Then perform a LDB function using
+the updated byte pointer.
+
+IDPB - Increment and Deposit Byte. Increment the byte pointer contained
+at the effective address. Then perform a DPB function using
+the updated byte pointer.
+
+Text strings are typically stored using seven-bit bytes, five per
+word. ILDB and IDPB can then be used to step through a string. The
+byte pointer should be initialized to 440700,,.
+Then the first ILDB will increment it to point at the first character
+of the string.
+
+Byte pointers can be decremented by special use of the IBP
+instruction. However, since this instruction is not available on all
+cpu's, use of the following midas macro is recommended instead.
+
+DEFINE DBP7 AC
+ ADD AC,[070000,,0]
+ TLNE AC,400000
+ SUB AC,[430000,,1]
+TERMIN
+
+Note that this only works for 7 bit bytes and only if the byte pointer
+is in an accumulator.
+
+PDP-10 Node: Logical Tests, Previous: Byte, Up: Top, Next: Boolean
+
+Logical Testing and Modification.
+
+The Test instructions are for testing and modifying bits in an
+accumulator. There are 64 test instructions. Each one's name is
+T followed by three modifiers.
+
+
+ |R right half immediate
+Test accumulator |L left half immediate
+ |D direct mask
+ |S swapped mask
+
+ |N no modification
+ |Z zero selected bits
+ |O set selected bits to One
+ |C complement selected bits
+
+ | never skip
+ |N skip unless all selected bits are zero
+ |E skip if all selected bits are zero
+ |A skip always
+
+The test operation considers two 36 bit quantities. One of these is
+the contents of the selected AC. The other quantity, called the
+mask, depends on the first modifier letter. For R the mask is
+<0,,E>; for L it is . For D the mask is C(E), and for S the
+mask is CS(E), the swapped contents of E.
+
+If the skip condition N is specified, then the test instruction will
+skip if the AND of the mask and the AC operand is Not equal to zero.
+
+If the skip condition E is specified, then the test instruction will
+skip if the AND of the mask and the AC operand is Equal to zero.
+
+If the modification code Z appears then bits that are one in mask are
+made zero in the AC.
+
+If the modification code O appears then bits that are one in mask are
+made one in the AC.
+
+If the modification code C appears then bits that are one in mask are
+complemented in the AC.
+
+Note that the skip condition is determined on the basis of the
+contents of the AC before it is modified.
+
+The principle use for the Test instructions is in testing and
+modifying single bit flags that are kept in an accumulator.
+
+
+Example:
+
+ TRON 5,FOOFLG ;Where FOOFLG has the value 200
+
+This turns on the 200 bit in the right half of accumulator 5,
+and skips if the bit was already on.
+
+PDP-10 Node: Boolean, Previous: Logical Tests, Up: Top, Next: PC Format
+
+Boolean Logic
+
+There are 16 possible boolean functions of 2 variables. The PDP-10
+has 16 instruction classes (each with 4 modifiers) that perform these
+operations. Each boolean function operates on the 36 bits of AC and
+memory as individual bits.
+
+C(AC) 0 0 1 1
+C(E) 0 1 0 1
+
+SETZ 0 0 0 0 SET to Zero
+AND 0 0 0 1 AND
+ANDCM 0 0 1 0 AND with Complement of Memory
+SETA 0 0 1 1 SET to AC
+ANDCA 0 1 0 0 AND with Complement of AC
+SETM 0 1 0 1 SET to Memory
+XOR 0 1 1 0 eXclusive OR
+IOR 0 1 1 1 Inclusive OR
+ANDCB 1 0 0 0 AND with Complements of Both
+EQV 1 0 0 1 EQuiValence
+SETCM 1 0 1 0 SET to Complement of Memory
+ORCM 1 0 1 1 OR with Complement of Memory
+SETCA 1 1 0 0 SET to Complement of AC
+ORCA 1 1 0 1 OR with Complement of AC
+ORCB 1 1 1 0 OR with Complements of Both
+SETO 1 1 1 1 SET to One
+
+
+Each of the 16 instructions above have four modifiers that specify
+where to store the result. No modifier means result to AC. Modifier
+I means Immediate: the memory data is <0,,E> and the result goes to
+AC. M as a modifier means result should be stored in memory. B
+means store the results in both memory and AC.
+
+PDP-10 Node: PC Format, Previous: Boolean, Up: Top, Next: Jumps
+
+PC format.
+
+A subroutine call instruction is one which changes the PC (jumps) but
+stores the old value of the PC so that the subroutine can "return"
+(jump back) when it is done. There are several subroutine call
+instructions on the PDP-10, but they all store the PC in the same
+format:
+
+ 0 0 0 0 0 0 0 0 0 0 1 1 1 11111 112222222222333333
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 34567 890123456789012345
+ __________________________________________________
+|A|C|C|F|F|U|I|P|A|T|T|F|D| | |
+|R|R|R|O|P|S|O|U|F|R|R|X|C|00000| PC |
+|O|Y|Y|V|D|E|T|B|I|A|A|U|K| | |
+|V|0|1| | |R| |L| |P|P| | | | |
+| | | | | | | | | |2|1| | | | |
+|_|_|_|_|_|_|_|_|_|_|_|_|_|_____|__________________|
+
+
+The right half is the PC proper -- the address of the next instruction
+to be executed (the one which follows the subroutine call
+instruction). The other individual bits are the status flags. They
+are stored in case the subroutine wants to restore them when it
+returns.
+
+AROV, ARithmetic OVerflow, is set by any of the following:
+ A single instruction has set one of CRY0 or CRY1 without
+ setting them both.
+ An ASH or ASHC has left shifted a significant bit out of
+ AC bit 1.
+ A MULx instruction has multiplied -2^|35 by itself.
+ A DMUL instruction has multiplied -2^|70 by itself.
+ An IMULx instruction has produced a product less than
+ -2^|35 or greater than 2^|35-1.
+ A FIX or FIXR has fetched an operand with exponent
+ greater than 35.
+ FOV (Floating Overflow) has been set.
+ DCK (Divide ChecK) has been set.
+
+CRY0, short for Carry 0, means that there was a carry out of bit 0 in
+an addition. Note that a carry out of bit 0, with no accompanying
+carry out of bit 1 (into bit 0), causes AROV to be set.
+The precise conditions which can set CRY0 and not CRY1 are:
+ An ADDx has added two negative numbers with sum less
+ than -2^|35.
+ A SUBx has subtracted a positive number from a negative
+ number and produced a result less than -2^|35.
+ A SOSx or SOJx has decremented -2^|35.
+
+CRY1, short for Carry 1, means that there was a carry out of bit 1 in
+an addition. Note that a carry out of bit 1, with no accompanying
+carry out of bit 0, causes AROV to be set.
+The precise conditions which can set CRY1 and not CRY0 are:
+ An ADDx has added two positive number with a sum greater
+ than 2^|35-1.
+ A SUBx has subtracted a negative number from a positive
+ number to form a difference greater than 2^|35-1.
+ An AOSx or AOJx instruction has incremented 2^|35-1.
+ A MOVNx or MOVMx has negated -2^|35.
+ A DMOVNx has negated -2^|70
+
+In addition, the following non-overflow conditions set both CRY0 and
+CRY1:
+ In ADDx both summands were negative, or their signs differed
+ and the postive one was greater than or equal to the
+ magnitude of the negative summand.
+ In SUBx the sign of both operands was the same and the AC
+ operand was greater than or equal to the memory
+ operand, or the AC operand was negative and the
+ memory operand was postive.
+ An AOJx or AOSx has incremented -1.
+ A SOJx or SOS has decremented a non zero number other
+ than -2^|35.
+ A MOVNx has negated zero.
+
+FOV, Floating point OVerflow, is set by any of:
+ In a floating point instruction other than FLTR, DMOVNx,
+ or DFN the exponent of the result exceeds 127.
+ FXU (Floating eXponent Underflow) has been set.
+ DCK (Divide ChecK) has been set by FDVx, FDVRx, or DFDV.
+
+FPD, First Part Done, is set when the processor responds to a
+priority interrupt, after having completed the first part of a two
+part instruction (e.g., ILDB). This flag is not usually of interest
+to the programmer.
+
+USER is set while the processor is in user mode. In user mode,
+various instruction and addressing restrictions are in effect.
+
+IOT, User IN-Out mode, (also called IOT User), is a special mode in
+which some of the user mode instruction (but not addressing)
+restrictions are removed. In this mode a user program may perform
+the hardware I/O instructions.
+
+[PUBL, Public mode, signifies that the processor is in user public
+mode or in exec supervisor mode. This bit exists only on standard
+KL-10 systems; it is not on ANY ITS system.]
+
+AFI, Address Failure Inhibit, if this flag is set, address break is
+inhibited for during the execution of the next instruction [KI10,
+KL10 only].
+
+TRAP2 - if bit 10 is not also set, pushdown overflow has occurred.
+If traps are enabled, setting this flag immediately causes a trap.
+At present no hardware condition sets both TRAP1 and TRAP2
+simultaneously. [KI10 KL10 only]
+
+TRAP1 - if bit 9 is not also set, arithemetic overflow has occurred.
+If traps are enabled, setting this flag immediately causes a trap.
+At present no hardware condition sets both TRAP1 and TRAP2
+simultaneously. [KI10 KL10 only]
+
+FXU, Floating eXponent Underflow, is set to signify that in a
+floating instruction other than DMOVNx, FLTR, or DFN, the exponent of
+the result was less than -128 and AROV and FOV have been set.
+
+DCK, Divide ChecK, signifies that one of the following conditions has
+set AROV:
+ In a DIVx the high order word of the dividend was greater than
+ or equal to the divisor.
+ In an IDIVx the divisor was zero.
+ In an FDVx, FDVRx, or DFDV, the divisor was zero, or the
+ magnitude of the dividend fraction was greater than
+ or equal to twice the magnitude of the divisor fraction.
+ In either case, FOV is also set.
+
+Bits 13 through 17 of the PC word are always zero to facilitate the
+use of indirect addressing to return from a subroutine.
+
+Bits 18 through 35 store an address that is one greater than the
+address of the instruction that stores the PC. Thus, the PC word
+points at the instruction immediately following the subroutine call.
+
+PDP-10 Node: Jumps, Previous: PC Format, Up: Top, Next: Obsolete
+
+Recommended jump instructions: PUSHJ, POPJ, JRST, JFCL, XCT.
+
+PUSHJ C(AC)<-C(AC)+<1,,1>; C(CR(AC))<-; PC<-E;
+
+PUSHJ (PUSH return address and Jump) is like PUSH except the data
+that is pushed onto the top of the stack is the PC and flags word.
+The PC that is stored is the PC of the instruction that follows the
+PUSHJ. Then the PC is set to the effective address of the
+instruction. Pushdown overflow results if the AC becomes positive
+when it is incremented.
+
+------
+
+POPJ PC<-CR(CR(AC)); C(AC)<-C(AC)-<1,,1>
+
+POPJ (POP return address and Jump) undoes PUSHJ. The right half of
+the word at the top of the stack is loaded into the PC (the flags are
+unchanged). Then the stack pointer is decremented as in POP. The
+effective address of POPJ is ignored. Pushdown overflow obtains if
+the AC becomes negative as a result of the subtraction.
+
+Programming hints:
+
+If a subroutine called by PUSHJ AC, wants to skip over the
+instruction following the PUSHJ, the following sequence accomplishes
+that result:
+ AOS (AC) ;AC better be non zero.
+ POPJ AC,
+
+If you must restore the flags that PUSHJ saved, the following
+sequence should be used instead of POPJ:
+ POP AC,(AC) ;Adjust the stack
+ JRST 2,@1(AC) ;Restore flags and PC from old stack top.
+However, this sequence has a timing error in that the word is released
+from the stack while its contents are still needed. This can cause a
+bug if you have any interrupt processing in your program.
+
+------
+
+JRST, Jump and ReSTore, is an unconditional jump instruction. In
+JRST, the AC field does not address an accumulator. Instead, the AC
+is decoded to signify various things.
+
+JRST PC<-E;
+JRST 2, PC<-E; flags are restored (see text);
+JRST 10, PC<-E; Dismiss current priority interrupt;
+JRST 12, PC<-E; restore flags and dismiss priority interrupt;
+
+If the AC field is zero, only a jump occurs. JRST is everyone's
+favorite unconditional jump instruction (the only other one is JUMPA
+which is more typing, also, on the KA-10 JUMPA is slower than
+JRST).
+
+JRST 2, (i.e., JRST with AC field set to 2) signifies jump and
+restore flags. (The assembler also recognizes the mnemonic JRSTF for
+JRST 2,). If indirection is used in JRSTF, then the flags are
+restored from the last word fetched in the address calculation. If
+indexing is used with no indirection, the flags are restored from the
+left half of the specified index register. If neither indexing nor
+indirection is used in the address calculation the flags are restored
+from the left half of the JRSTF itself! In a user mode program JRSTF
+cannot clear USER nor can it set IOT User (it can however, clear IOT
+User).
+
+The following are all illegal in user mode and are trapped as UUOs.
+
+JRST 4, (alternate mnemonic HALT) sets the PC from E and stops the
+processor.
+
+JRST 10, is used to dismiss the current priority interrupt. Usually
+JRST 12, is used for this purpose since JRST 10, fails to restore
+flags.
+
+JRST 12, (an alternate mnemonic is JEN, jump and enable priority
+interrupts) combines the functions of JRST 10, and JRST 2,.
+
+------
+
+The JFCL (Jump on Flag and CLear) instruction is another case in
+which the AC field is decoded to modify the instruction. The AC
+field selects the four flags in PC bits 0 through 3. PC bits 0 to 3
+correspond to bits 9 to 12 in the JFCL instruction. JFCL will jump
+if any flag selected by the AC field is a 1. All flags selected by
+the AC field are set to zero.
+
+JFCL 0, since it selects no PC bits, is a no-op.
+
+JFCL 17, will clear all flags, and will jump if any of AROV, CRY0,
+CRY1, or FOV are set.
+
+JFCL 1, (JFOV) jumps if FOV is set and clears FOV.
+
+JFCL 10, (JOV) jumps if AROV is set and clears AROV.
+
+------
+
+XCT, the execute instruction, fetches the word addressed by the
+effective address and executes that word as an instruction. In the
+case of XCTing an instruction that stores a PC, the PC that is stored
+is the address of the instruction that follows the XCT. If the
+executed instruction skips, then that skip is relative to the XCT.
+The AC field of the XCT should be zero. [In exec mode a non zero AC
+field in an XCT is significant.]
+
+PDP-10 Node: Obsolete, Previous: Jumps, Up: Top, Next: Program
+
+Obsolete and not-recommended jump instructions: JSR, JSP, JSA and JRA
+
+The JSR and JSP instructions are two non-stack subroutine calls which
+are typical of most non-stack machines. JSP stores the old PC in an
+accumulator, and JSR stores it in a word at the beginning of the
+subroutine. JSP is useful once in a while, such as, for a subroutine
+whose job is to push or pop several words on the stack. JSR is useful
+only for UUO-handlers. *Note JSR: UUO Handlers. PUSHJ and POPJ
+should be used for all ordinary subroutines.
+
+JSA and JRA are a peculiar subroutine call and matching return which
+were invented for PDP-6 Fortran. In most programs they are not used
+at all.
+
+JSR C(E)<-; PC<-E+1;
+
+JSR, Jump to SubRoutine, stores the PC in the word addressed by the
+effective address and jumps to the word following the word where the
+PC is stored. This is the only PDP-10 instruction that stores the PC
+and flags without modifying any ACs; however, it is non-reentrant, so
+PUSHJ is favored in most cases. The usual return from a subroutine
+called by a JSR is via JRST (or JRST 2,) indirect through the PC
+word. (See JRST)
+
+------
+
+JSP C(AC)<-; PC<-E;
+
+JSP, Jump and Save PC, stores the PC and flags in the selected
+accumulator and jumps.
+
+------
+
+JSA C(E)<-C(AC); C(AC)<-; PC<-E+1;
+
+JSA, Jump and Save AC, stores the AC in word addressed by the
+effective address. Then the left half of the AC is set to the
+effective address and the right half of AC is set to the return PC.
+Then the PC is set to one greater than the effective address. The
+JRA instruction unwinds this call. The advantage of this call is
+that a routine may have multiple entry points (which is difficult to
+do with JSR) and it's easy to find (and later to skip over) arguments
+that follow the calling instruction (which is possible to do with
+PUSHJ, but not quite so convenient). Among the disadvantages of this
+call is that it is non reentrant, and it doesn't save flags.
+
+------
+
+JRA C(AC)<-C(CL(AC)); PC<-E;
+
+JRA, Jump and Restore AC, is the return from JSA. If, e.g., a
+subrountine is called with JSA AC, then the return is made by:
+ JRA AC,(AC).
+
+PDP-10 Node: MIT Machines, Previous: Obsolete, Up: Top, Next: Program
+
+The MIT PDP-10's running ITS (AI, ML, DM, MC) have been modified in several
+ways, primarily to implement paging. AI, ML, and DM are KA-10 processors
+and are therefore modified by the addition of an additional piece of
+hardware called a paging box and some rewiring of the CPU; MC is an early
+KL-10 (hardware does not support extended addressing) modified by changing
+microcode.
+
+The paging modifications affect only the operating system (instructions XCTR
+(execute relocated), LPM (load/store page map), etc.) although it is through
+the mechanism of the paging box that the MAR-break facility is implemented,
+which ITS makes available through .mara (in DDT, $I), as well as the JPC
+(the last jump address), available in DDT as .JPC.
+
+Three user-level facilities were added to the AI 10: the Circ instruction,
+the PC Index mode, and one-proceed mode. Circ AC,Efad (instruction 247)
+rotates AC and AC+1 like Rotc except that (for positive Efad) bits leaving
+the top of AC enter the TOP of AC+1 and bits leaving the bottom of AC+1
+enter the BOTTOM of AC. Thus Circ AC,36. reverses the bitstring AC|AC+1.
+Caution: Circ is a No-op and not an Illegal-op on machines on which it is
+not implemented. PC index mode (bit %PCX17=200 in LH of PC) uses the PC as
+index when index 17 is specified. This was intended to be used for
+position-independent code; as far as I know, no programs use it.
+One-proceed mode (%PC1PR=400) interrupts the program after one instruction
+is executed. It is used by DDT's ^N and ^^ commands.
+
+Of these user facilities, only one-proceed is available on ML and DM.
+
+The MC KL-10 has had its microcode modified to implement Circ and
+one-proceed. The Extend instructions available on standard-microcode
+KL's are not available on MC. Jfcl, Jrst, and Blt are compatible with
+Dec's KL versions.
+
+This node added by S. Macrakis (Macrakis@MC).
+
+PDP-10 Node: Program, Previous: MIT Machines, Up: Top, Next: TTY Output
+
+A Trivial Complete MIDAS Program.
+
+This program stores, in each word of TABLE, the index of that word.
+Thus, the 0th word gets 0, the next gets 1, etc.
+
+ TITLE COUNT
+
+A=1 ;Define a name for an accumulator.
+
+START: MOVSI A,-100 ;initialize loop counter.
+ ;A contains -100,,0
+LOOP: HRRZM A,TABLE(A) ;Use right half of A to index.
+ AOBJN A,LOOP ;Add 1 to both halves (-77,,1 -76,,2 etc.)
+ ;Jump if still negative.
+ .VALUE ;Halt program.
+
+TABLE: BLOCK 100 ;Assemble space to fill up.
+
+END START ;End the assembly.
+
+NOTES:
+
+*) TITLE: Every MIDAS program should begin with a TITLE statement
+which contains the program's name.
+
+*) A: It is best to give names to the accumulators you use.
+Single character names are good except for an AC which is used
+generally for the same thing throughout the program. Define a
+symbolic name for an AC with the assembler operator =.
+
+*) Comments: Everything after a semicolon is a comment, until the end
+of the line. Actually, this is only true if the semicolon is not
+inside of a text string of some sort.
+
+*) START: This is a label, which marks a location in the program. The
+label START is used to name the instruction at which the program
+should start running. The name START itself is nothing special.
+MIDAS knows to use the value of START as the starting address because
+START is the operand of the END statement.
+
+*) .VALUE: This is a system call instruction. It halts the program,
+and makes DDT print out the program counter. All system calls have
+names starting with a period.
+
+*) BLOCK: The BLOCK n statement reserves n words of storage, which are
+not initialized.
+
+*) END: The end statement tells MIDAS that the assembly input is
+finished, and its argument says what address to start the program at.
+In this case the argument is the value of the label START.
+
+PDP-10 Node: TTY Output, Previous: Program, Up: Top, Next: Reverse
+
+Print the string FOO on the terminal.
+
+ TITLE PRINT
+A=1 ;Symbolic AC names are defined
+
+CHTTYO==1 ;Channel for output
+ ;== means don't use this symbol
+ ;for symbolic typeout in DDT.
+
+START: ;Open TTY channel.
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAO,,CHTTYO] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+ .IOT CHTTYO,["F] ;Print F.
+ .IOT CHTTYO,["O] ;Print O.
+ .IOT CHTTYO,["O] ;Print O.
+ .VALUE ;Halt program.
+
+END START ;Tell MIDAS this is the end of the text
+ ;and specify the address to start execution.
+
+NOTES:
+
+*) CHTTYO: All I/O is done by means of I/O channels, of which
+there are sixteen, numbered 0 through 17. It is best to make symbolic
+names for the channels you use and start them all with CH. Define
+these names with the MIDAS operator ==, which is like = except that
+symbols defined with == are not used for symbolic typeout by the DDT
+debugger. We call this "half killing". In this example, CHTTYO and A
+both have the value 1, but CHTTYO is half killed, so 1 will always be
+output symbolically as A. This is the desired result, because
+references to address or AC 1 are more likely to mean A than CHTTYO.
+
+*) .CALL: This is an ITS symbolic system call. Its format is, in
+general,
+
+ .CALL [SETZ ? SIXBIT/callname/ ? arguments ((SETZ))]
+
+(Note that the value of SETZ is a word with just the sign bit set).
+The [ ... ] construct is a literal, and "?" is equivalent to a line
+separator. Thus, the .CALL instruction is assembled with an address
+field that points at a block of words containing a SETZ, a
+SIXBIT/OPEN/, and finally the arguments. ((SETZ)) is a magic
+assembler incantation which sets the sign bit of the last argument
+word.
+
+The arguments are simply addresses of words containing data for the
+system call. There are other kinds of arguments, but we won't get
+into that. See .INFO.;.CALLS > for more information on symbolic
+system calls.
+
+A symbolic system call skips if it is successful.
+
+*) OPEN: This is the name of the symbolic system call used in the
+example. The OPEN call is used to open an I/O channel so it can be
+used for I/O. It requires two arguments: the first one containing the
+channel number and the I/O mode, and the second one containing the
+device name in SIXBIT. In this example, the channel is CHTTYO, the
+mode is .UAO (unit ascii output), and the device name is TTY, for the
+terminal.
+
+Most OPENs will also specify two filenames and a directory name as
+additional arguments, but for device TTY they are not necessary.
+
+*) .LOSE %LSFIL: This is a system call which prints an error message
+and halts. It is designed to be used as the instruction following an
+OPEN or other symbolic system call which deals with an I/O channel.
+Sophisticated programs can recover from failing system calls, and
+sometimes the failure should simply be ignored, but often it is
+easiest just to use .LOSE %LSFIL. This instruction is indented
+because it can be skipped over.
+
+*) .IOT: This is the system call for doing actual I/O. It is an
+instruction whose AC field should be the I/O channel and whose address
+points to a word containing a character to be output. "F in MIDAS
+represents the code for the character F.
+
+PDP-10 Node: Reverse, Previous: TTY Output, Up: Top, Next: Even-Odd
+
+The following program accepts a line of input (terminated by Carriage
+Return) from the terminal and outputs that line with the characters
+reversed.
+
+ TITLE REVERSE
+A=1 ;Symbolic AC names are defined
+P=17
+
+CHTTYO==1 ;Channel for output
+CHTTYI==2 ;Channel for input
+
+PDLLEN==100 ;Length of push down stack
+PDL: BLOCK PDLLEN ;Storage for push down stack
+
+BEG: MOVE P,[-PDLLEN,,PDL-1] ;Initialize stack pointer.
+ ;Open TTY channels.
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAI,,CHTTYI] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAO,,CHTTYO] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+LOOP: .IOT CHTTYO,["*] ;Prompt for input.
+ PUSHJ P,REVERS ;do the work, once.
+ .IOT CHTTYO,[^M] ;Output CRLF to go to new line.
+ .IOT CHTTYO,[^J]
+ JRST LOOP ;Jump back to repeat.
+
+REVERS: .IOT CHTTYI,A ;Read a character.
+ CAIN A,^M ;If it is a Carriage Return, the line is ended,
+ POPJ P, ;so return.
+ PUSH P,A ;Else save this character on the stack,
+ PUSHJ P,REVERS ;call REVERS recursively,
+ POP P,A ;get our character back
+ .IOT CHTTYO,A ;and print it.
+ POPJ P, ;Return.
+
+END BEG
+
+NOTES:
+
+*) OPEN: Two tty channels are used, one for input and one for output.
+The input channel is opened in mode .UAI (unit ascii input) and the
+output channel in mode .UAO (unit ascii output). The mode is how the
+system knows whether to make an input channel or an output channel.
+
+*) .IOT: It works on input channels as well as on output channels.
+On an input channel, it stores the input character (or word) in the
+addressed memory location. The ITS system does not do any sort of
+input editing or "rubout processing". There is a library for that:
+SYSENG;RUBOUT >.
+
+*) To output "go to a new line", output a ^M followed by a ^J. ^M is
+the MIDAS syntax for the code for Control-M, which is Carriage Return.
+When the user types Carriage Return, which echoes as going to a new
+line, it is read by the program as only one character, a ^M.
+
+*) The subroutine REVERS is recursive. The first call to REVERS reads
+the first character, calls REVERS (to read the rest of the line and
+print it in reverse), and lastly prints the first character. Over the
+recursive call to REVERS, the first character is saved on the stack.
+
+*) P is the conventional name for the AC used as the stack pointer.
+The MOVE instruction is there to set it up with a pointer to the
+allocated area. Initializing a stack is one of the first things any
+real program should do.
+
+From then on, calling is done with PUSHJ and returning with POPJ.
+PUSH is used to save data on the stack, and POP to get it back.
+
+*) The POPJ P, which is skipped over by the CAIN is indented one extra
+column. If there is a sequence of skipping instructions, each
+instruction is indented one more than the previous one.
+
+It is reasonable to omit the address field of an instruction if it is
+unused (as it is in a POPJ). An omitted field assembles as zero, but
+you should never omit a field which is supposed to contain a zero
+which actually stands for something. For example, instructions which
+refer to AC zero should always have a zero (or better, a symbolic
+name) where the AC is referred to.
+
+PDP-10 Node: Even-Odd, Previous: Reverse, Up: Top, Next: Even-Odd-Vowels
+
+Separate Even-Numbered and Odd-Numbered Characters. Rubout Processing.
+
+The following program accepts a line of input (terminated by carriage return)
+from the terminal and outputs the even (i.e., every second) letters followed
+by the odd letters. Also, we exhibit a subroutine for reading a line from the
+terminal with rubout processing.
+
+
+ TITLE EVEN ODD
+A=1 ;Symbolic AC names are defined.
+B=2
+P=17
+
+CHTTYO==1 ;Channel for output
+CHTTYI==2 ;Channel for input
+
+PDLLEN==100 ;Length of push down stack
+PDL: BLOCK PDLLEN ;Storage for push down stack
+
+BUF: BLOCK 30 ;Storage for 79 characters at 5 per word.
+LINBUF: BLOCK 30
+LINBFE::
+
+START: MOVE P,[-PDLLEN,,PDL-1]
+ ;Open TTY channels.
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAI,,CHTTYI] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAO,,CHTTYO] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+L: PUSHJ P,GETLIN ;Read in an entire line.
+ MOVE C,[440700,,LINBUF] ;Initialize byte pointer to fetch from the line.
+ MOVE B,[440700,,BUF] ;Initialize byte pointer to store into BUF.
+;Get odd-numbered character.
+L1: ILDB A,C ;Get next odd-numbered char of the line.
+ JUMPE A,L2 ;Zero byte => end of line.
+ IDPB A,B ;Store char in BUF. Advance pointer first.
+;Get even-numbered character.
+ ILDB A,C ;Get next even-numbered char of the line.
+ JUMPE A,L2 ;Zero byte => end of line.
+ .IOT CHTTYO,A ;Output this character right away.
+ JRST L1 ;Keep going till we get a terminator.
+
+L2: MOVEI A,0 ;Store a terminating character (code zero)
+ IDPB A,B ;at the end of the string in BUF.
+ ;Now it is an ASCIZ string.
+ MOVEI A,BUF
+ PUSHJ P,OUTSTR ;Call OUTSTR to output ASCIZ string
+ ;starting at address in A.
+ MOVEI A,[ASCIZ /
+/]
+ PUSHJ P,OUTSTR ;Output a CRLF.
+ JRST L
+
+;Subroutine to read in a line and store it in LINBUF,
+;checking to avoid running past the end of LINBUF.
+;Discards the line terminator and leaves a null (zero) character
+;in the buffer at the end of the string.
+;Rubout cancels one character.
+;Clobbers A and B.
+GETLIN: .IOT CHTTYO,["*] ;Prompt for input.
+ MOVE B,[440700,,LINBUF]
+GETLI1: .IOT CHTTYI,A ;Read the character
+ CAIN A,177 ;Rubout means cancel one character.
+ JRST GETLRB
+ CAIN A,^M ;Carriage Return ends the line.
+ JRST GETLCR
+ CAME B,[100700,,LINBFE-1] ;Don't store if buffer almost full.
+ ;(Leaves room for one more char:
+ ; the zero at the end)
+ IDPB A,B ;Any other character is stored in the buffer.
+ JRST GETLI1
+
+;Come here after reading the carriage return.
+GETLCR: SETZ A, ;Store a zero to mark end of string - and make it ASCIZ.
+ IDPB A,B
+ POPJ P,
+
+;Come here after reading a rubout.
+GETLRB: CAMN B,[440700,,LINBUF] ;Is there anything to rub out?
+ JRST GETLNL
+ LDB A,B ;Yes => get back the char we are cancelling
+ .IOT CHTTYO,A ;and print it out so user can see it.
+ ADD B,[070000,,] ;To discard char, decrement the byte pointer.
+ ;First increase position by one byte (7).
+ SKIPGE B ;If byte pointer negative, position is 44,
+ SUB B,[430000,,1] ;so change it to position 01 in previous word.
+ JRST GETLI1
+
+;Come here after reading a rubout with nothing to rub out.
+GETLNL: MOVEI A,[ASCIZ /
+/]
+ PUSHJ P,OUTSTR ;Just output a blank line.
+ JRST GETLIN ;Prompt again.
+
+;Subroutine to output the ASCIZ string which starts
+;in the word whose address is inA. Clobbers A.
+OUTSTR: HRLI A,440700 ;Make A into a byte pointer to fetch string.
+OUTST1: ILDB B,A ;Fetch next character of string into B.
+ JUMPE B,CPOPJ ;If it is the terminator, return.
+ .IOT CHTTYO,B ;Else output it
+ JRST OUTST1 ;and loop back.
+
+CPOPJ: POPJ P, ;Return.
+
+ END START
+
+NOTES:
+
+*) "LINBFE::" defines the label LINBFE and half kills it. This is because
+LINBFE and START are actually the same location; we would prefer to
+have DDT print out START, so we tell it not to print out LINBFE.
+
+*) 440700: The correct left half for a byte pointer for 7-bit bytes
+which points to the nonexistent character to the left of a word. The
+first increment will make it point to the first actual character in
+the word. This is the right way to start off the pointer because the
+ILDB and IDPB instructions increment first.
+
+*) Decrementing a byte pointer: This is done in GETLRB. It is the
+inverse of incrementing the byte pointer, as done by IBP, ILDB and IDPB.
+The particular three-instruction sequence used above assumes that the
+byte size is 7. It is not hard to adapt it to other byte sizes, but sizes
+other than 7 are infrequent.
+
+*) GETLIN: This subroutine does "rubout processing". It gives the
+user the ability to type in a line and make corrections within it.
+This is a very simple rubout processor; the only editing character
+it provides is Rubout, and it does not handle display terminals.
+SYSENG;RUBOUT > is a rubout processor that you can use in practice.
+
+*) OUTSTR: A subroutine to print out an ASCIZ (ASCII, terminated by
+a Zero) string. Most programs contain this subroutine under some name
+or other.
+
+*) CPOPJ: Note that it is possible to conditionaly jump to a POPJ
+instruction to do a conditional return from a subroutine. Every
+subroutine in the program can use the same POPJ instruction for this,
+and the traditional name for it is CPOPJ. You can assume when you see
+the label CPOPJ used that it is the address of a POPJ P, instruction.
+
+PDP-10 Node: Even-Odd-Vowels, Previous: Even-Odd, Up: Top, Next: Even-Odd-Vowels 2
+
+Separate Even Characters, Odd Vowels, and Odd Consonants.
+
+The following program accepts a line of input (terminated by carriage
+return) from the terminal and outputs the even (i.e., every second)
+letters followed by those odd letters that are not vowels, followed by
+those odd letters that are vowels.
+
+In the program of example 4, take the code
+
+L2: MOVEI A,0 ;Store a terminating character (code zero)
+ IDPB A,B ;at the end of the string in BUF.
+ ;Now it is an ASCIZ string.
+ MOVEI A,BUF
+ PUSHJ P,OUTSTR ;Call OUTSTR to output ASCIZ string
+ ;starting at address in A.
+ MOVEI A,[ASCIZ /
+/]
+ PUSHJ P,OUTSTR ;Output a CRLF.
+ JRST L
+
+and replace it with
+
+L2: MOVEI A,0 ;Deposit code zero to terminate string
+ IDPB A,B ;of odd letters (i.e., make it ASCIZ).
+ MOVE B,[440700,,BUF] ;Take pointer for odd letters
+ MOVE C,B ;Put pointer for vowels
+L3: ILDB A,B ;Get one odd letter.
+ JUMPE A,L4 ;Stop scanning when we reach the zero.
+ PUSHJ P,ISVOW ;Is this a vowel?
+ JRST L3A ;No.
+ IDPB A,C ;Yes. Store for later.
+ JRST L3
+
+L3A: .IOT CHTTYO,A ;Not a vowel, so output now.
+ JRST L3
+
+L4: IDPB A,C ;Store code zero to end string of vowels.
+ MOVEI A,BUF
+ PUSHJ P,OUTSTR ;Output that string.
+ MOVEI A,[ASCIZ /
+/]
+ PUSHJ P,OUTSTR ;Output a CRLF.
+ JRST L
+
+;Subroutine to skip if the character in A is a vowel.
+ISVOW: CAIE A,"A ;If character is upper case A
+ CAIN A,"a ;or if it is lower case A,
+ JRST POPJ1 ;jump to a skip return.
+ CAIE A,"E ;Same for E, etc.
+ CAIN A,"e
+ JRST POPJ1
+ CAIE A,"I
+ CAIN A,"i
+ JRST POPJ1
+ CAIE A,"O
+ CAIN A,"o
+ JRST POPJ1
+ CAIE A,"U
+ CAIN A,"u
+ JRST POPJ1
+ CAIE A,"Y
+ CAIN A,"y
+ JRST POPJ1
+ POPJ P, ;Not a vowel, so return with no skip.
+
+;Standard address of single skip return.
+POPJ1: AOS (P)
+ POPJ P,
+
+NOTES:
+
+*) Skip return: A subroutine is said to skip return when it skips
+the instruction which follows the call. The subroutine call instruction
+therefore acts as a conditional skip instruction. Subroutines called
+with a PUSHJ skip return by incrementing the return address where
+it lives on the stack. Subroutines called in other ways implement
+skip returning in other ways.
+
+*) POPJ1: This is the standard name for a place to jump to for a skip
+return. Since the procedure for a skip return is independent of the
+address of the subroutine, every subroutine can use the same POPJ1.
+If you see the label POPJ1 used, you can assume it is a skip return of
+the sort shown above.
+
+*) Consecutive skip instructions appear in ISVOW. When this happens,
+each instruction that can be skipped is indented one more than the
+previous one.
+
+If, on the other hand, you had a subroutine that could skip twice, and
+followed it by two non-skipping instructions, each of those
+instructions would be indented only once.
+
+*) Re-using the string: as we scan the string of odd characters for
+vowels, we print out the consonants and store the vowels in a string
+again, reusing the same space. The reason why it works to be reading
+out one string and writing another string in the same memory space is
+that we write at most one character for each character we read. So we
+can never clobber a character that has not been read. Even if every
+character is a vowel, the characters are stored into the bytes they
+have just been read out of, so nothing is lost.
+
+*) Lower case letters make a difference in a character constant (such
+as "a).
+
+PDP-10 Node: Even-Odd-Vowels 2, Previous: Even-Odd-Vowels, Up: Top, Next: Calculator
+
+Alternative Implementation of Previous Example.
+
+The following program performs the same function as the program written for
+example 5. Some different ideas are shown here.
+
+ TITLE EVEN ODD #2
+A=1 ;SYMBOLIC AC NAMES ARE DEFINED
+B=2
+C=3
+D=4
+P=17
+
+CHTTYO==1 ;Channel for output
+CHTTYI==2 ;Channel for input
+
+PDLLEN==100 ;Length of push down stack
+PDL: BLOCK PDLLEN ;Storage for push down stack
+
+BUF: BLOCK 30 ;Storage for 79 characters at 5 per word.
+LINBUF: BLOCK 30 ;Read a line into here.
+LINBFE::
+
+START: MOVE P,[-PDLLEN,,PDL-1]
+ ;Open TTY channels.
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAI,,CHTTYI] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAO,,CHTTYO] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+L: PUSHJ P,GETLIN ;Read in the line.
+ MOVE C,[440700,,LINBUF] ;Initialize byte pointer to fetch from the line.
+ MOVE B,[440700,,BUF] ;Initialize byte pointer to store into BUF.
+ SETZ D,0 ;Low bit of D is even-oddness of character.
+L1: ILDB A,C ;Get next character. Jump if end of line.
+ JUMPE A,L2
+ XORI D,1 ;Complement low bit -- count mod 2.
+ ;D is 1, then 0, then 1, then 0.
+ XCT XTBL(D) ;Execute an instruction to dispose of char.
+ JRST L1
+
+XTBL: .IOT CHTTYO,A ;Even character non-vowel
+ IDPB A,B ;Odd character vowel
+
+
+L2: MOVEI A,0 ;Deposit a null byte to make string
+ IDPB A,B ; of odd letters ASCIZ.
+ MOVE C,[440700,,BUF] ;Fetch the string.
+ MOVE B,C ;Store back only the vowels.
+L3: ILDB A,C ;Get one odd letter.
+ JUMPE A,L4 ;Check for end of string.
+ PUSHJ P,ISVOW ;Test character, skip if vowel.
+ TDZA D,D ;Not a vowel, set D=0.
+ MOVEI D,1 ;Vowel. D=-1
+ XCT XTBL(D) ;Dispose of char depending.
+ JRST L3
+
+L4: IDPB A,B ;Store null to make string of odd vowels ASCIZ.
+ MOVEI A,BUF
+ PUSHJ P,OUTSTR ;Type out that string.
+ MOVEI A,[ASCIZ /
+/]
+ PUSHJ P,OUTSTR
+ JRST L
+
+ISVOW:
+IRPC ZZ,,[AEIOUY]
+ CAIE A,"ZZ
+ CAIN A,"ZZ+40
+ JRST POPJ1
+TERMIN
+ POPJ P,
+
+;Copy the GETLIN and OUTSTR subroutines from above into here.
+
+ END START
+
+NOTES:
+
+*) IRPC is an assembler macro operation which generates repetitive code
+with small variations. In this case, the three instructions CAIE,
+CAIN and JRST are repeated once for each vowel. The first time, ZZ is
+replaced by A. The second, ZZ is replaced by Z. The sixth time, ZZ
+is replaced by Y. As a result, the subroutine ISVOW in this example
+is actually identical to the ISVOW in the previous example, though it
+takes much fewer lines of source code.
+
+PDP-10 Node: Calculator, Previous: Even-Odd-Vowels 2, Up: Top, Next: FileIO
+
+Arithmetic Calculator Program.
+
+This program will read an arithmetic expression composed of numbers and the
+operators +, -, * and /, compute the value and type the result. It shows how
+to read and print numbers. It does not know about operator precedence; it
+does operations from left to right always.
+
+ TITLE NUM
+FL=0
+A=1
+B=2
+C=3
+D=4
+P=17
+
+CHTTYI==1
+CHTTYO==2
+
+;FLAG NAMES
+NEGF==1
+DIGF==2
+
+PDLLEN==100
+PDL: BLOCK PDLLEN
+OP1: 0
+X1: 0
+
+LINBUF: BLOCK 30
+LINBFE::
+
+LINPTR: 0
+
+START: MOVE P,[-PDLLEN,,PDL-1]
+ ;Open TTY channels.
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAI,,CHTTYI] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+ .CALL [SETZ ? SIXBIT/OPEN/
+ [.UAO,,CHTTYO] ? [SIXBIT/TTY/] ((SETZ))]
+ .LOSE %LSFIL
+START1: PUSHJ P,GETLIN ;Read in a line of input.
+ MOVE A,[440700,,LINBUF]
+ MOVEM A,LINPTR ;Set up to fetch chars from the line.
+ PUSHJ P,EVAL ;Parse and evaluate expression.
+ PUSHJ P,DECOUT ;Print the answer.
+ MOVEI A,[ASCIZ/
+/]
+ PUSHJ P,OUTSTR
+ JRST START1
+
+;Read and evaluate an expression. Value returned in A.
+;Clobbers B.
+EVAL: PUSHJ P,DECIN ;Read one number.
+ MOVEM B,OP1 ;Save the number.
+EVAL1: MOVEI B,0
+ CAIN A,"+ ;Consider the operation character:
+ MOVE B,[ADD B,OP1] ;B gets an instruction to do that operation.
+ CAIN A,"-
+ MOVE B,[SUB B,OP1]
+ CAIN A,"*
+ MOVE B,[IMUL B,OP1]
+ CAIN A,"/
+ MOVE B,[IDIV B,OP1]
+ JUMPE B,EVALX ;If B is still 0, the terminator
+ ;was not an arith op, so it ends
+ ;the expression or is illegal.
+ MOVEM B,X1 ;It is an arith op, so save the instruction.
+ PUSHJ P,DECIN ;Read the second operand.
+ EXCH B,OP1 ;B gets first op, OP1 gets second operand.
+ XCT X1 ;Compute result of operation, in B.
+ MOVEM B,OP1 ;Save it as first operand of next operation.
+ JRST EVAL1 ;A has terminator of second operand,
+ ;which is the next operation.
+
+;Come here on number terminated by char not an arith op.
+EVALX: JUMPN A,ERR ;Should be end of line, or it's an error.
+ MOVE A,OP1 ;Otherwise, last saved value is value of exp.
+ POPJ P,
+
+;Print an error message if we see something we don't recognize.
+ERR: MOVEI A,[ASCIZ/Unrecognized character in expression: /]
+ PUSHJ P,OUTSTR
+ LDB A,LINPTR ;Print the offending character
+ .IOT CHTTYO,A ;as part of the error message.
+ MOVEI A,[ASCIZ /
+/]
+ PUSHJ P,OUTSTR
+ JRST START1
+
+;Read a signed decimal number out of the line, returning number in B
+;and terminating character in A.
+DECIN: TRZ FL,NEGF!DIGF ;No minus, no digit seen yet.
+ MOVEI B,0
+DECIN1: ILDB A,LINPTR ;Fetch next character of line.
+ CAIL A,"0
+ CAILE A,"9
+ JRST DECIN2 ;Jump if character not a digit.
+ IMULI B,10. ;Else accumulate this digit into the number.
+ ADDI B,-"0(A) ;Note that we convert the digit into its value.
+ ;("0 into the value 0, "1 into 1).
+ TRO FL,DIGF ;Set flag saying non-null number seen.
+ JRST DECIN1
+
+DECIN2: CAIN A,"-
+ JRST DECIN3 ;Jump on minus sign.
+ TRNN FL,DIGF ;Anything else: if we saw a number,
+ POPJ P, ;negate it if it began with a minus sign.
+DECIN4: TRZE FL,NEGF
+ MOVN B,B
+ POPJ P,
+
+;Come here after reading a minus sign.
+DECIN3: TRNE FL,DIGF ;Does it follow a number?
+ JRST DECIN4 ;Yes. This must be a binary minus.
+ TRC FL,NEGF ;This must be unary minus.
+ ;Complement flag that number is negative.
+ JRST DECIN1 ;(So that two minus signs cancel out).
+
+;Print number in A, positive or negative, in decimal.
+;Clobbers A and B.
+DECOUT: JUMPGE A,DECOT1
+ .IOT CHTTYO,["-] ;If number is negative, print sign.
+ CAMN A,[400000,,] ;Smallest negative number is a pain:
+ JRST DECOT2 ;its absolute value cannot fit in one word!
+ MOVM A,A ;Else get abs val of negative number and print.
+DECOT1: IDIVI A,10.
+ HRLM B,(P) ;Save remainder in LH of stack word
+ ;whose RH contains our return address.
+ SKIPE A ;If quotient is nonzero,
+ PUSHJ P,DECOT1 ;print higher-order digits of number.
+ HLRZ A,(P) ;Get back this remainder (this digit).
+ ADDI A,"0
+ .IOT CHTTYO,A
+ POPJ P,
+
+;Print the abs value of the largest negative number.
+DECOT2: MOVEI A,[ASCIZ /34359738368/]
+ JRST OUTSTR
+
+;Copy the GETLIN and OUTSTR subroutines here.
+
+ END START
+
+NOTES
+
+*) 10.: This is a decimal number. You can tell, because it ends
+with a decimal point.
+
+*) LINPTR: this location holds the byte pointer used for fetching
+characters out of the line. It is usually not worth while to keep
+this pointer in an accumulator if the parsing is being done over
+more than a very small piece of code.
+
+*) XCT: Note how EVAL chooses an arithmetic instruction based on
+the arithmetic operator character, then reads the following argument,
+and then executes the instruction chosen earlier, performing the
+operation. This is also the first use you have seen of literals
+containing instructions.
+
+*) ERR: this is an example of printing an error message. Error messages
+should always show the offending data, not just say "something was wrong".
+
+*) DECIN: Note how flags in accumulator 0 (FL) are used to keep
+track of whether any digits have been seen, and whether a minus
+sign came before them. Accumulator 0 is most often used for such flags
+because it is the least useful accumulator for anything else
+(since it cannot be used as an index register).
+
+*) DECOUT: This is a very famous program for printing a number.
+It works recursively because the first digits extracted as the remainders
+in successive divisions by the radix are the last digits to be printed.
+So the digits are produced and saved on the way down the recursion,
+and printed on the way up.
+
+*) HRLM: We could save the remainder with PUSH P,B and restore it
+with POP P,A, but since the left half of each word saved by a PUSHJ
+is not really going to be used, we can save stack space by using those
+left halves to store the remainder. It is also faster.
+
+PDP-10 Node: FileIO, Previous: Calculator, Up: Top, Next: Parsing
+
+Reading and Writing Files.
+
+As a preface to this example, several things need to be explained.
+In the foregoing examples, only terminal I/O has been discussed.
+Here we introduce disk file input. One important thing to emphasize
+is the concept of device independence: most of the system calls for
+disk i/o are the same as those for say, magtape i/o. Naturally,
+different devices have different phyical characteristics; therefore,
+some differences between devices will be apparent. Despite these
+differences, a programmer really needs to learn only one set of basic
+concepts for i/o.
+
+When doing i/o it is necessary to specify a physical device, a mode
+(input vs. output, character vs. word), and possibly a file name to
+select among "files" on a particular physical device.
+
+Each job can has sixteen i/o channels available, each of which can be
+opened individually to do i/o. The same OPEN system call used to open
+a tty channel is also used to open i/o channels for other devices.
+OPEN also specifies the mode and filenames.
+
+You have already seen the use of modes .UAI (unit ascii input) and
+.UAO (unit ascii output). Modes .UII and .UIO are "image" i/o instead
+of ascii i/o. They transfer whole words instead of characters, and
+are used for binary files.
+
+There are two filenames, and also a directory name. These are
+specified as words of SIXBIT just like the device name.
+
+Once the channel is open, the .IOT UUO is used to transfer the
+characters in or out, just as it is with the terminal. In fact, the
+above examples could be adapted to read and write input using disk
+files only by changing the two OPEN system calls. Alternatively,
+filename translations could be used to translate device TTY: to a disk
+file.
+
+Writing output to a file does require one thing that writing output to
+the terminal does not need: you must "close" the channel when you are
+finished to make the file appear properly on disk. Closing a terminal
+i/o channel is also allowed but nobody bothers since it is not
+necessary. Closing is done with the .CLOSE UUO, which takes the
+channel number in its AC field just like .IOT.
+
+Here is an example which copies the file SYS;SYSTEM MAIL (the announcements
+printed when DDT or PWORD starts up) to the file FOO BAR on your own directory.
+
+ TITLE FILE COPY
+A=1
+
+CHDSKI==1
+CHDSKO==2
+
+FCOPY: .CALL [ SETZ ? SIXBIT/OPEN/
+ [.UAI,,CHDSKI] ? [SIXBIT/DSK/] ;Mode, channel and device name
+ [SIXBIT /SYSTEM/] ? [SIXBIT/MAIL/] ;Two filenames.
+ 400000,,[SIXBIT /SYS/]] ;Directory name.
+ .LOSE %LSFIL
+ .CALL [ SETZ ? SIXBIT/OPEN/
+ [.UAO,,CHDSKO] ? [SIXBIT/DSK/]
+ [SIXBIT /FOO/] ? 400000,,[SIXBIT/BAR/]] ;Note no directory name!
+ ;The default (your working directory) is used.
+ .LOSE %LSFIL
+LOOP: .IOT CHDSKI,A ;Read next input character.
+ JUMPL A,EOF ;Negative => there is none, it's eof.
+ .IOT CHDSKO,A ;Else write char to output file.
+ JRST LOOP
+
+EOF: .CLOSE CHDSKO, ;Make output file appear.
+ .CLOSE CHDSKI, ;Release input file (to be clean).
+ .LOGOUT 1,
+
+ END FCOPY
+
+NOTES:
+
+*) This example is so simple that no stack is needed, and no tty channels.
+
+*) When reading from a file instead of the terminal, it is possible to reach the
+end of the file. In ascii mode (.UAI), this is signalled by a negative value
+returned by the .IOT. The right halfword of that value contains the character
+^C, which is the standard end-of-file padding character on ITS. That is, ^C is
+used to fill out the last word of a file of characters if that last word is not
+entirely used up. In image mode, .IOT causes an error interrupt at end of file.
+Usually binary files are read many words at a time using SIOT (which will be
+explained soon) or block-mode .IOT; these do provide a way to detect end of file
+without getting an error.
+
+*) .LOGOUT 1, is a convenient way to exit a program and kill the job. It kills
+the job if it is running under DDT (the usual condition) and also kills the job
+if it is disowned. When a program running under DDT does a .LOGOUT 1, DDT just
+prints an asterisk.
+
+PDP-10 Node: Parsing, Previous: FileIO, Up: Top, Next: BufInput
+
+Parsing SIXBIT Words, and Filenames.
+
+Here is a sample routine which accumulates a word of sixbit, returning
+it in B. Non-alphanumeric characters are terminators; the terminator
+encountered is returned in A.
+
+We assume that GETCHR is a subroutine we can call
+which reads a character of input and returns it in A.
+
+GETSIX: MOVEI B,0
+ MOVE C,[440600,,B] ;Byte pointer for storing into B.
+GETSX1: PUSHJ P,GETCHR ;Read next character into A.
+ CAIN A,40
+ JRST [ JUMPE B,GETSX1 ;Flush leading blanks
+ POPJ P,] ;but trailing blanks are terminators.
+ CAIL A,"A+40
+ CAILE A,"Z+40
+ JRST .+2 ;Not lower case
+ TRZ A,40 ;Make lower case into upper case
+ CAIL A,"A
+ CAILE A,"Z
+ JRST .+2
+ JRST GETSX2 ;Letters are ok in sixbit
+ CAIN A,^Q ;^Q means "quote": use the next char
+ JRST [ PUSHJ P,GETCHR ;even if it is usually a delimiter.
+ JRST GETSX2]
+ CAIL A,"0
+ CAILE A,"9
+ POPJ P, ;Not a letter, not a digit. This is delim.
+GETSX2: SUBI A,40 ;Convert to sixbit
+ TLNE C,770000 ;Skip if already got 6 characters.
+ IDPB A,C ;Otherwise we would clobber C here.
+ JRST GETSX1
+
+You don't need to write a filename parsing routine, because you can
+use the library SYSENG;RFN >. However, RFN is a good example to read.
+
+PDP-10 Node: BufInput, Previous: Parsing, Up: Top, Next: BufPadding
+
+Sample Routine to do Buffered Input.
+
+So far, the i/o in the examples has always transferred a single character at a
+time. When a large file is to be read or written, it is worth while to go to
+the extra trouble of transferring many words or characters at a time. There are
+two ways of doing this. The old way is to open the i/o channel in "block" mode
+instead of "unit" mode: use mode .BAI, .BAO, .BII or .BIO instead of .UAI, .UAO,
+.UII or .UIO. Then the .IOT UUO itself transfers a block of consecutive words
+instead of a single word or character. The newer way is to open the channel in
+unit mode as usual, and use the system call SIOT to transfer any number of
+consecutive bytes. SIOT can be interspersed with individual .IOTs.
+
+We assume that INCHAN has a file open in mode .UAI, unit ascii input.
+We use the SIOT system call to read many characters at a time into a
+buffer, and then get them out of the buffer one by one.
+
+SIOT expects three arguments: a channel number, a byte pointer and a number of
+characters. The byte pointer argument should not be a literal, because the
+SIOT increments it past the characters that are transferred. The count is
+also modified; it is decremented for all the characters transferred
+(decremented down to zero if the transfer is completed). On input, if end of
+file is encountered before the requested number of characters is obtained,
+then the byte pointer and count indicate the characters actually transferred.
+
+INBFR: BLOCK INBFL ;This is the buffer. 40 to 200 is
+ ;good for INBFL (160. to 640. characters).
+
+INCNT: 0 ;Number of characters left in buffer
+ ;not fetched yet.
+INPTR: 0 ;Byte pointer used for fetching characters
+
+;Read another input character into A.
+;Skip if successful. No skip if EOF.
+GETCHR: SOSL INCNT ;Anything left in the buffer?
+ JRST GETCH1
+ PUSH P,A ;No - must read another load.
+ PUSH P,B
+ MOVE A,[440700,,INBFR]
+ MOVEM A,INPTR
+ MOVEI B,INBFL*5
+ ;; Do the input. A says where to put it and B says how many chars.
+ .CALL [ SETZ ? SIXBIT /SIOT/ ? %CLIMM,,INCHAN
+ A ? 400000,,B]
+ ;Note "immediate" argument:
+ ;%CLIMM,,INCHAN is the same as [INCHAN].
+ .LOSE %LSFIL
+ MOVNS B ;B is left with number of characters
+ ADDI B,INBFL*5 ;We wanted but didn't get.
+ MOVEM B,INCNT ;Compute how many chars we did get.
+ POP P,B
+ POP P,A
+ SOSG INCNT ;If we got none, it's eof.
+ POPJ P,
+GETCH1: ILDB A,INPTR
+ AOS (P)
+ POPJ P,
+
+Note that this GETCHR routine is completely equivalent to
+
+GETCHR: .IOT INCHAN,A
+ SKIPGE A
+ AOS (P)
+ POPJ P,
+
+but the buffered one is much faster because it does not have to do a
+system call for each character. If your program is supposed to
+process characters quickly, use buffered input. If characters will be
+read only infrequently and a few at a time, use simple input.
+
+PDP-10 Node: BufPadding, Previous: BufInput, Up: Top, Next: Debugging
+
+Buffered Input, Ignoring Padding.
+
+Sometimes it is desirable to ignore padding (^@ and ^C characters) at
+the end of a file, but to consider ^@ and ^C characters within the
+file to be significant. The convention usually used is that ^@ and
+^C characters are only padding if they occur as the last few
+characters in the last word of the file. A ^L character in the last
+word followed only by ^C's or ^@'s is also to be ignored. Here is a
+routine which claims to have hit end of file when it reaches the
+padding.
+
+This routine works by saving the last word of each buffer load to be
+processed at the front of the next buffer load. That is so that, when
+we discover end of it is guaranteed that we have not yet processed the
+last word of the file. So once we KNOW it is the last word, we can
+look through it for padding and discard what we find.
+
+It is necessary to call the subroutine GETINI before reading the first
+character of input.
+
+INBFR: BLOCK INBFL ;This is the buffer. 40 to 200 is
+ ;good for INBFL (160. to 640. characters).
+
+INCNT: 0 ;Number of characters left in buffer
+ ;not fetched yet.
+INPTR: 0 ;Byte pointer used for fetching characters
+
+INAHED: 0 ;Look-ahead word.
+ ;The last word of previous bufferful
+ ;saved for the next bufferful.
+INEOF: 0 ;-1 if this bufferful is the last.
+
+;Read another input character into A.
+;Skip if successful. No skip if EOF.
+GETCHR: SOSL INCNT ;Anything left in the buffer?
+ JRST GETCH1 ;Yes => just get it.
+ SKIPE INEOF ;If we discovered last time that there
+ POPJ P, ;is no more, it's eof now.
+ PUSHJ P,GETBUF ;Fill up the buffer again.
+ JRST GETCHR
+
+GETCH1: ILDB A,INPTR
+ AOS (P)
+ POPJ P,
+
+;Call this to initialize the buffer, before reading the first character.
+;This is to ignore the look-ahead word,
+;which is garbage the first time around.
+GETINI: SETZM INEOF
+ SETZM INCNT
+ PUSHJ P,GETCHR ;So just read and throw away
+ PUSHJ P,GETCHR ;the supposed look-ahead chars.
+ PUSHJ P,GETCHR
+ PUSHJ P,GETCHR
+ PUSHJ P,GETCHR
+ POPJ P,
+
+GETBUF: PUSH P,A
+ PUSH P,B
+ MOVE A,INAHED ;Our previous look ahead word is now
+ MOVEM A,INBFR ;our first word of input.
+ MOVE A,[440700,,INBFR] ;That's where we should start fetching.
+ MOVEM A,INPTR
+ HRLI A,010700 ;The SIOT should start AFTER that word.
+;Note that it is essential that we set up A with
+;010700,,INBFR rather than 440700,,INBFR+1
+;because of how GETCH4 decrements the byte pointer.
+;We are being compatible with SIOT, which also returns
+;a byte pointer of the form 010700 rather than 440700.
+ MOVEI B,INBFL*5-5 ;from the file, but not that word.
+ ;; Do the input. A says where to put it and B says how many chars.
+ .CALL [ SETZ ? SIXBIT /SIOT/ ? %CLIMM,,INCHAN
+ A ? 400000,,B]
+ .LOSE %LSFIL
+ JUMPE B,GETCH2 ;Didn't get all we asked for =>
+ SETOM INEOF ; this is the last we will get.
+ MOVNS B ;B is left with number of characters
+ ADDI B,INBFL*5 ;we wanted but didn't get.
+ MOVEM B,INCNT ;Compute how many chars we did get.
+;We are now certainly at eof, and the last word of the file
+;is now in the buffer.
+GETCH4: ADD A,[070000,,] ;Back up to last character.
+ JUMPL A,GETCH3 ;When we get to left edge of word,
+ ;we have examined the entire last word,
+ ;so there is no more padding.
+ LDB B,A
+ CAIE B,^C ;Any number of ^@ and ^C chars is padding.
+ CAIN B,^@
+ JRST [ SOS INCNT ;So officially say it is not there.
+ JRST GETCH4]
+ CAIN B,^L ;A ^L followed by padding is padding
+ SOS INCNT ;but nothing before it is padding.
+ JRST GETCH3
+
+;If we did fill the buffer, we must save one word as look-ahead
+;for next time.
+GETCH2: MOVE A,INBFR+INBFL-1 ;Save the last word we got.
+ MOVEM A,INAHED
+ MOVEI A,INBFL*5-5 ;Don't include those 5 chars
+ MOVEM A,INCNT ;in the count of how many are in the bfr.
+GETCH3: POP P,B
+ POP P,A
+ POPJ P,
+
+Both of these examples are suited to reading input from a disk file.
+If you are reading input from the terminal, you probably want to do
+rubout processing for the user's sake. There is a library you can use
+for this; read the file SYSENG;RUBOUT >.
+
+PDP-10 Node: Debugging, Previous: BufPadding, Up: Top
+
+Debugging Programs with DDT
+
+When you try your program for the first time, it won't work.
+
+To find out why, you use the debugging features of DDT. DDT is
+completely documented (*Note DDT: (DDT).) but this is a summary of
+what sorts of things you can do with it.
+
+DDT allows you to set a "breakpoint". Setting a breakpoint at an
+instruction means that when the program gets to that instruction it
+will stop (return to DDT). At this time you can examine any location
+in the program to see if everything is working right so far.
+If it is still working right, you can set another breakpoint, later
+on, and continue the program.
+
+When you see that a variable contains a "wrong" value, DDT allows you
+to correct the value and continue, from the breakpoint or from
+someplace else. You can also change instructions in the program with
+DDT so that you can keep running the program and the problem will not
+happen again (but don't forget to make the correction in the source
+file as well!) DDT allows can print instructions and addresses using
+the symbols you define in the program, and it understands those
+symbols in your input as well.
+
+You can also ask DDT to run your program one instruction at a time.
+This is often easier than setting breakpoints.
+
+You don't have to do anything special to be able to use DDT on your
+program, because DDT is always available on ITS. It is the program
+which processed your command to run INFO. You probably don't want to
+set any breakpoints in INFO, but if you type C-Z now you could do just
+that.
+
+Homework # 1 answer
+
+ TITLE IGPAY ATINLAY
+A=1 ;SYMBOLIC AC NAMES ARE DEFINED
+B=2
+C=3
+D=4
+P=17
+PDLEN==100 ;LENGTH OF PUSH DOWN LIST
+PDLIST: BLOCK PDLEN ;STORAGE FOR PUSH DOWN LIST
+BUFR: BLOCK 30 ;STORAGE FOR 79 CHARACTERS
+
+
+START: RESET
+ MOVE P,[IOWD PDLEN,PDLIST]
+L: OUTCHR ["*"] ;PROMPT FOR INPUT
+ MOVE B,[POINT 7,BUFR]
+L1: PUSHJ P,DOWORD
+ CAIE A,12 ;DELIMITER SEEN?
+ JRST L1
+ OUTSTR [BYTE(7)15,12]
+ JRST L
+
+DOWORD: MOVE B,[POINT 7,BUFR]
+ SETZM BUFR
+ PUSHJ P,GETLTR
+ JRST EPOPJ ;NON LETTER
+DOWRD1: PUSHJ P,ISVOW ;IS IT A VOWEL?
+ JRST .+2
+ JRST DOWRD3 ;YES.
+ IDPB A,B ;CONSONANT AT FRONT OF WORD
+ PUSHJ P,GETLTR
+ TDZA C,C ;"WORD" HAS ALL CONSONANTS
+ JRST DOWRD1
+ IDPB C,B ;STORE ZERO TO MAKE ASCIZ
+ OUTSTR BUFR
+EPOPJ: CAIE A,12
+ OUTCHR A ;TYPE NON LETTER
+ POPJ P,
+
+DOWRD2: OUTCHR A ;HERE FOR A WORD THAT BEGINS W/VOWEL
+ PUSHJ P,GETLTR
+ JRST EPOPJ
+ JRST DOWRD2
+
+DOWRD3: LDB C,[POINT 7,BUFR,6] ;GET FIRST CONSONANT IF ANY.
+ JUMPE C,DOWRD2 ;JUMP IF NO FIRST CONSONANT.
+ MOVE D,A ;COPY CASE OF FIRST VOWEL
+ TRNN C,40 ;SKIP IF FIRST LETTER IS LOWER CASE
+ TRZ A,40 ;MAKE FIRST VOWEL UPPER CASE.
+DOWRD4: OUTCHR A ;OUTPUT FIRST V IN SAME CASE AS FIRST CONS.
+ PUSHJ P,GETLTR
+ JRST .+2 ;END OF WORD
+ JRST DOWRD4
+ MOVEI C,"A"
+ IDPB C,B
+ MOVEI C,"Y"
+ IDPB C,B
+ MOVEI C,0
+ IDPB C,B
+ TRNN D,40 ;WAS FIRST VOWEL IN LOWER CASE?
+ SKIPA C,[JFCL]
+ MOVE C,[IORI D,40] ;YES. FORCE REMAINDER TO LOWERCASE.
+ MOVE B,[POINT 7,BUFR]
+DOWRD5: ILDB D,B
+ JUMPE D,EPOPJ
+ XCT C
+ OUTCHR D
+ JRST DOWRD5
+
+GETLTR: .IOT CHTTYI,A ;Read input character into A.
+ CAIN A,^M
+ JRST GETLTR
+ CAIL A,"A
+ CAILE A,"Z
+ JRST .+2
+ JRST CPOPJ1
+ CAIL A,"A+40
+ CAILE A,"Z+40
+ POPJ P,
+CPOPJ1: AOS (P) ;SKIP RETURN, UNLESS LF.
+ POPJ P,
+
+ISVOW:
+IRPC ZZ,,[AEIOUY]
+ CAIE A,"ZZ
+ CAIN A,"ZZ+40
+ JRST CPOPJ1
+TERMIN
+ POPJ P,
+
+ END START
+
\ No newline at end of file