OS/8 FORTRAN IV SOFTWARE SUPPORT MANUAL DISCLAIMER This document file was created by scanning the original document and then editing the scanned text. As much as possible, the original text format was restored. Some format changes were made to insure this document would print on current laser printers using 60 lines per page, which changed the page numbering. The original spelling and grammar have been preserved. 1-NOV-1997 DEC-S8-LFSSA-A-D AA-4532A-TA 056573 OS/8 FORTRAN IV SOFTWARE SUPPORT MANUAL ---------------------------------------------------------- | For additional copies, order No. DEC-S8-LFSSA-A-D | | from Software Distribution Center, Digital Equipment | | Corporation, Maynard, Mass. | ---------------------------------------------------------- digital equipment corporation - maynard, massachusetts First Printing June, 1973 Copyright (c) 1973 by Digital Equipment Corporation The following are trademarks of Digital Equipment Corporation, Maynard, Massachusetts: CDP DIGITAL KA10 PS/8 COMPUTER LAB DNC LAB-8 QUICKPOINT COMTEX EDGRIN LAB-8/e RAD-8 COMSYST EDUSYSTEM LAB-K RSTS DDT FLIP CHIP OMNIBUS RSX DEC FOCAL OS/8 RTM DECCOMM GLC-8 PDP SABR DECTAPE IDAC PHA TYPESET 8 DIBOL IDACS UNIBUS INDAC ii CONTENTS CHAPTER 1 THE F4 COMPILER 1-1 CHAPTER 2 THE RALF ASSEMBLER 2-1 CHAPTER 3 THE FORTRAN IV LOADER 3-1 CHAPTER 4 THE FORTRAN IV RUN-TIME SYSTEM 4-1 CHAPTER 5 LIBRA AND FORLIB 5-1 APPENDIX A RALF Assembler Permanent Symbol Table A-1 APPENDIX B Assembly Instructions B-1 iii CHAPTER 1 THE F4 COMPILER The OS/8 F4 compiler runs in 8K on either a PDP-8 or a PDP-12. It operates in three passes to transform FORTRAN IV source programs into RALF assembly language. The function of each of the three passes is: 1. Analyze statements, check syntax and convert to a polish notation. 2. Convert output of PASS1 to RALF assembly language making extensive use of code skeleton tables. 3. Produce a listing of the FORTRAN source program and/or chain to the assembler. The following is a more complete description of each of the three passes. PASS1 OPERATION After opening the source language input file(s) and an intermediate output file, PASS1 processes statements in the following fashion: 1. Assemble a statement into the statement buffer by reading characters from the OS/8 input file. This section eliminates comments and handles continuations so that the statement buffer contains the entire statement as if it had been written on one long line. 2. The statement is first assumed to be an arithmetic assignment and an attempt is made to compile it as such. This is done with a special switch (NOCODE) set so that in the event the statement is not arithmetic, no erroneous output is produced. Thus, with this switch set, the expression analyzer subroutine is used merely as a syntax checker. 3. If the statement is indeed an arithmetic assignment statement (or arithmetic statement function) the switch is set off and the statement is then recompiled, this time producing output. 4. If not an arithmetic assignment, the statement might be one of the keyword defined statements. The compiler now checks the first symbol on the line to see of it is a legal keyword (REAL, GOTO, etc.) and jumps to the appropriate subroutine if so. Any statement that is not now classified is considered to be in error. 5. The compilation of each statement takes place. Some state- ments produce only symbol table entries (e.g., DIMENSION) 1-1 which will be processed by PASS2. Others use the arithmetic expression analyzer (EXPR) and also output special purpose operators which will tell PASS2 what to do with the value represented by the arithmetic expression (e.g., IF, DO). 6. After the statement has been processed, control passes to the end-of-statement routine which handles DO-loop terminations and then outputs the end-of-statement code. 7. Statements containing some kind of error cause a special error code to be output. 8. The entire process is now repeated for the next statement. 9. When the END statement is encountered, PASS1 chains to PASS2. PASS1 SYMBOL TABLE A significant portion of the PASS1 processing involves the production of symbol table entries. These entries contain all storage related information, i.e., variable name, type, dimensions, etc. The symbol table is organized as a set of linked lists. The first 26 such lists are for variables, with the first letter of the variable name corresponding to the ordinal number of the list. There are also separate lists for statement numbers and literals (integer, real, complex, double, and Hollerith). In addition to list elements, there are special entries for holding DIMENSION and EQUIVALENCE information. A detailed description of each type of entry follows. (NOTE: All symbol table entries are in Field 1.) 1. VARIABLE - The first word of each entry is a pointer to the next entry, with a zero pointer signaling end of list. The second word contains type information. The third word points to the dimension and/or equivalence information blocks. The next one to three words contain the remainder of the name (the first character is implied by which list the entry is in) in stripped six-bit ASCII terminated by a zero character. Thus, shorter variables take less symbol table space. The entries are (as for all lists in the symbol table) arranged in order of increasing magnitude, or alphabetically. 1-2 --------------- POINTER | ------> | |-------------| TYPE | | | | | | | | |-------------| DIMENSION/EQUIVALENCE | ------> | |-------------| NAME 2-3 | N | A | |-------------| NAME 4-5 | M | E | |-------------| NAME 6 | X | 0 | --------------- TYPE WORD FORMAT 0 1 2 3 4 5 6 7 8 9 10 11 ---------------------------------------------------------------------- | C | D | E | A | E | E || L | A | T || Y | P | E | | O | I | X | S | Q | X || I | R | || | | | | M | M | T | F | U | P || T | G | || | | | | | | | | I | L || | | || | | | | | | | | V | I || | | || | | | | | | | | | C || | | || | | | ---------------------------------------------------------------------- BIT 0 - Variable is in common. 1 - Variable is dimensioned. 2 - External symbol or subroutine/function name. 3 - Symbol is the name of an arithmetic statement function. 4 - Variable is an equivalence slave. 5 - Variable is explicitly typed. 6 - Entry is a literal. 7 - Variable is a formal parameter. - 1 integer | 2 real | 3 complex 8-11 < 4 double Type | 5 logical | 8 statement number - 9 common section name 2. STATEMENT NUMBER - The first two words are the standard pointer/type. The next three words are the statement number, with leading zeros deleted, in stripped six-bit ASCII, filled to the right with blanks. 1-3 --------------- POINTER | ------> | |-------------| TYPE | | | | | | | | |-------------| NUMBER 1-2 | N | U | |-------------| NUMBER 3-4 | M | B | |-------------| NUMBER 5 | R | | --------------- 3. INTEGER OR REAL LITERALS - The first two words are the pointer and type. The next three words are the value in standard floating-point format (12-bit exponent, 24-bit signed 2's complement mantissa). Since the type of the literal must be preserved, there are two lists; hence use of 1 and 1.0 in the same program will cause one entry in each of the integer and real literal lists. --------------- POINTER | ------> | |-------------| TYPE | | | | | | | | |-------------| EXPONENT | V | |----A--------| MANTISSA 0-11 | L | |--------U----| MANTISSA 12-23 | E | --------------- 4. COMPLEX LITERALS - The first two words are standard. The next three are the real part in standard floating-point format. The next three are the imaginary part. --------------- POINTER | ------> | |-------------| TYPE | | | | | | | | |-------------| REAL EXPONENT | R | |----E--------| REAL MANTISSA 0-11 | A | |------L------| REAL MANTISSA 12-23 | | |-------------| IMAGINARY EXPONENT | IM | |----A--------| IMAGINARY MANTISSA 0-11 | GIN | |--------A----| IMAGINARY MANTISSA 12-23 | RY | --------------- 1-4 5. DOUBLE PRECISION LITERALS - The first two words are standard. The next six are the literal in FPP extended format (12-bit exponent, 60-bit mantissa). --------------- POINTER | ------> | |-------------| TYPE | | | | | | | | |-------------| EXPONENT | | |-------------| MANTISSA 0-11 | | |-------------| MANTISSA 12-23 | | |-------------| MANTISSA 24-35 | | |-------------| MANTISSA 36-47 | | |-------------| MANTISSA 48-59 | | --------------- 6. HOLLERITH (quoted) LITERALS - The first two words are stan- dard. The next N words are the characters of the literal in stripped six-bit ASCII, ending in a zero character. --------------- POINTER | ------> | |-------------| TYPE | | | | | | | | |-------------| CHARACTERS 1-2 | | --------------- etc. ............. 7. DIMENSION INFORMATION BLOCK - If a variable is DIMENSIONed, the third word of its symbol table entry will point to its dimension information block (may be indirectly, see section 8 below). The first word of this block is the number of dimensions. The second word is the total size of the array in elements; thus the size in PDP-8 words may be 3 or 6 times this number. The third word contains the "magic number" which is computed as follows: n-1 i MN= - 1+ SUM of d(j) i=1 j=1 where d(j) is the jth dimension and n is the number of dimensions. 1-5 For a 3-dimensional variable this number becomes: MN+ 1+d(1)+d(1)d(2) The magic number must be subtracted from any computed index, since indexing starts at one and not zero. The fourth word will (in PASS2) contain the displacement from #LIT of a literal which will contain either the magic number in un-normalized form (for dimensioned variables which are subroutine arguments) or the address of the variable minus the magic number (for local or COMMON dimensioned variables). This literal is necessary for calling subroutines where a subscripted variable is an argument. The next N words are the dimensions of the variable. If the variable is a formal parameter of the subroutine, it may have one or more dimen- sions which are also formal parameters. In this case, the magic number is zero, and the dimension(s) is a pointer to the symbol table entry for the variable(s) used as a dimen- sion. ---------- NUMBER OF DIMENSIONS | # | |--------| TOTAL NUMBER OF ELEMENTS | SIZE | |--------| MAGIC NUMBER | MN | |--------| RESERVED | | |--------| DIMENSION 1 | D1 | |--------| DIMENSION 2 | D2 | ---------- ........ ---------- DIMENSION n | Dn | ---------- 8. EQUIVALENCE INFORMATION BLOCK - If a variable is an EQUIVALENCE slave variable, the third word of its symbol table entry points to the equivalence information block. The first word of this block points to the dimension infor- mation (if any) of the variable. The second word points to the symbol table entry of the EQUIVALENCE master variable. The third word is the linearized subscript of the master variable from the EQUIVALENCE statement. The fourth word is the linearized subscript of the slave variable. 1-6 --------------- POINTER TO DIMENSIONS | ------> | |-------------| POINTER TO MASTER | ------> | |-------------| MASTER SUBSCRIPT | SSM | |-------------| SLAVE SUBSCRIPT | SSM | --------------- 9. COMMON INFORMATION BLOCK - If a symbol is defined as the name of a COMMON section, the third word of its symbol table entry points to a list of common information blocks. The first word of each such block points to the next block. The second word is the number of entries in the list that follows. The rest of the block is a set of pointers to the symbol table entries of the variables in the COMMON section. --------------- POINTER TO NEXT CIB | ------> | |-------------| NUMBER OF ENTRIES | # | |-------------| - | ------> | | |-------------| POINTER TO VARIABLES < | ------> | IN THIS COMMON | |-------------| - | ------> | --------------- PASS1 OUTPUT The output of PASS1 is a stream of polish with many special operators. Whenever an operand is to be output, the address of its symbol table entry is used. The following is a list of the output codes (in their mnemonic form, obtain numeric values from listing of PASS1) and the operation they are conveying to PASS2: PUSH The next word in the output file is an operand (symbol table pointer) to be put onto the stack. ADD Add the operands represented by the top two stack entries (actually this causes PASS2 to generate the RALF coding which will do the desired add). SUB Subtract top from next-to-top. MUL Multiply top two. DIV Divide top into next-to-top. EXP Raise next-to-top to power of top. 1-7 NOT Logical .NOT. of top of stack. NEG Negate top of stack. GE Compare top two for greater than or equal to, this has TRUE value if the next-to-top is .GE. the top. GT Compare for greater than. LE Compare for less than or equal. LT Compare for less than. AND Logical AND of top two entries. OR Logical inclusive OR of top two. EQ Compare top two for equality. NE Compare top two for inequality. XOR Exclusive OR of top two. EQV EQUIVALENCE of top two. PAUSOP Use top of stack as PAUSE number. DPUSH The next two words are a symbol table pointer and a displacement; put them onto the stack (used for DATA statements). BINRD1 Take the top of stack as the unit number and com- pile an unformatted READ-open. FMTRD1 The top two stack elements are the unit and format, take them and compile a formatted READ- open. RCLOSE Compile a READ-close. DARD1 Take the top two stack elements as a unit number and a block number and compile a direct access unformatted READ-open. BINWR1 - FMTWRI |> Same as for the corresponding READ case, except WCLOSE | substitute the word "WRITE". DAWR1 - DEFFIL Take the top four stack entries as the unit, number of records, record size, and index variable and compile a DEFINE FILE call. ASFDEF Set the PASS2 switch which says that the following statement is an arithmetic statement function. 1-8 ARGSOP The next word is a count, call it n; take the previous n stack entries as subscripts (or arguments) and the N+1st entry from the top as the array (or function) name; now compile this as an array reference (or function/subroutine call). EOLCOD The current statement is completed, reset stacks and do other housekeeping. ERRCOD The following word contains an error code, write it on the TTY together with the current line number, and put the error code and line number into the error list for possible PASS3. RETOPR Compile a subroutine RETURN. REWOPR Take the top of stack as a unit and compile a rewind. STOROP Compile a store of the top of stack into the next-to-top. ENDOPR Compile a RETURN if a function or subroutine or a CALL EXIT if a main program. DEFLBL The following word is a symbol table pointer to a statement number, compile this as the tag for the current RALF line. DOFINI The following word is a symbol table pointer for the DO-loop index, compile the corresponding DO-ending code. ARTHIF The following one, two, or three words are symbol table pointers to statement numbers for the less than zero, zero, and greater than zero conditions with the comparison to be made on the top of stack. LIFBGN The top of stack is taken as a logical expression PASS 2 should compile a jump-around-on-false; this implies that some statement is to follow. DOBEGN The top two stack entries represent the final value and increment of the DO-loop, process them in hopes of finding a matching DOFINI. ENDFOP The top of stack is a unit, compile an END FILE. STOPOP Compile a CALL EXIT. 1-9 ASNOPR The next word is the address of the symbol table entry for a statement number; compile an ASSIGN of this statement number to the variable represented by the top of stack. BAKOPR Take the top of stack as the unit and compile a BACKSPACE. FMTOPR The following word is a count N; the next N words after that are the image of the FORMAT statement. GO2OPR The following word is the symbol table entry for the statement number which is to be executed next. CGO2OP The following word is a count N; the next N words are symbol table pointers for the statement numbers of a computed GO TO list; use the value represented by the top of stack to compile a computed GO TO into this list. AGO2OP Compile an assigned GO TO with the top of stack. IOLMNT Take the top of stack as a list element for an I/O statement and compile read or write; PASS2 knows if it is a READ or WRITE by remembering previous FMTRD1, FMTWR1, etc. DATELM The next word is a count N; the next N words are a data element. DREPTC The next word is a repetition count for the set of DATELMs up until the next ENDELM. ENDELM Signals the end of a data element group. PRGSTK Tells PASS2 to purge the top stack entry. DOSTOR Performs the same function as STOROP after checking the top two stack elements for legal DO-parameter type (integer or real). PASS 1 SUBROUTINES The following is a brief description of the function of each of the major PASS1 subroutines: RDWR Compiles everything in a READ or WRITE statement starting at the first left parenthesis. RESTCP Restore character pointer and count for the statement buffer from the stack. 1-10 OUTWRD Output a word (the AC on entering) to the PASS1 output file. COMARP Test for comma or right parenthesis, skip one instruction if a comma, two if a right parenthesis, and none if neither. BACK1 Backup the statement buffer character pointer. GETSS Scans a variable reference, or subscripted variable reference with numeric subscripts and returns the linearized subscript. MUL12 Perform a 12-bit unsigned integer multiply. DOSTUF Handles compilation of DO-loop setup. TYPLST Process a type declaration, DIMENSION, or COMMON statement; sets up type bits and/or dimension information. LOOKUP Perform a symbol table search for variables and Hollerith literals. LUKUP2 Perform a symbol table search for integer, real, complex, and double precision literals or statement numbers. EXPR Analyze and process an arithmetic expression. LETTER Get next character from the statement buffer and skip if it is a letter, otherwise put the character back and don't skip. CHECKC The first word after the JMS is the negative of the ASCII character to test for; if this is the next character, skip. GETCWB Get the next character from the statement buffer preserving blanks. SAVECP Save the character pointer and count on the stack. GETC Get the next character ignoring blanks. ERMSG Output an error code to PASS1 output file. POP Pop the stack into the AC. PUSH Push the AC onto the stack. LEXPR Analyze and process an arithmetic expression, legal to the left of the equal sign in an assignment statement. 1-11 GET2C Get the next two character into one word. STMNUM Scan off a statement number and do the symbol table search. DIGIT Same as letter, except checks for a digit. NUMBER Scans off an integer, real, or double precision literal. GETNAM Scan off a variable name. ICHAR Get the next character from the input file. PASS2 OPERATION The first part of PASS2 generates the storage for variables, arguments, arrays, literals and temporaries by processing the symbol table built by PASS1, which is kept in core. The next step is to generate the code for subroutine entry and exit including argument pickup and restore. After all such prolog code is generated, PASS2O is loaded into core, overlaying most of the prolog-generating functions. The main loop of the compiler is now entered. This consists simply of reading a PASS1 output code from the intermediate file and using this number as an index into a jump table. The sections of code entered in this way then perform the correct generation of RALF code. Example: The statement: A=B+C*D would produce the following PASS1 output: (assuming A,B,C,D are REAL) 1) PUSH ->A (symbol table address of A) 2) PUSH ->B 3) PUSH ->C 4) PUSH ->D 5) MUL 6) ADD 7) STOROP 8) EOLCOD 1-12 The corresponding operations performed by PASS2 are: 1) Make a 3-word entry on the stack corresponding to the variable A consisting of a pointer to the symbol table entry, a word containing the type, and one reserved word. 2) Repeat above for B. 3) Repeat above for C. 4) Repeat above for D. 5) The multiply operator is handled like any of the binary operators by the subroutine CODE. This routine is called with the address of the multiply skeleton table. The top two stack entries are taken as the operands, with their types used to index into the skeleton tables. (See description of binary operator skeleton tables below.) The correct skeleton for this combination is chosen based on the where-abouts of each of the operands (AC or memory) at the corresponding point in the code which is being compiled. There are three possible cases: Memory,AC; Memory,Memory; AC,Memory. In this example, both operands are in memory so the code generated would be: FLDA C FMUL D The CODE subroutine then makes a new stack entry to replace the entries for C and D. This entry has a 0 in place of the symbol table pointer, signifying that the operand is in the AC. Other special case operand codes are: 0 - AC ( Already mentioned) 1 - 51 Temporaries 52 - 60 Array reference, the subscript of which is in an index register (1-7). 61 - A variable, the address of which is in base location 0. 62 - A variable, the address of which is in base location 3. 63-6777 - Symbol table entry (can be variable or literal). 7000 - Special temporary 1-13 6) The add operator is handled in the same way as for multiply, except that in this case the add skeleton table is used. When the correct row is found, the memory,AC case is chosen since the result of C*D is now in the AC. This skeleton simply generates: FADD B The new top of stack entry is a 0, since the result is in the AC. 7) The store operation works in a similar manner using a special skeleton table to determine whether the value to be stored is already in the AC and whether it must be converted from one type to another. In this case, no conversion need be performed and the code generated is: FSTA A 8) The end of statement has been reached and any necessary bookkeeping is performed. PASS2 SYMBOL TABLE PASS2 modifies the symbol table entries corresponding to variables by replacing the first word of the entry with the first character of the name, this character being derived from the list in which the name is located. PASS2 ERROR LIST PASS2 creates a list (in field 1) of error codes and line numbers corresponding to the errors printed on the Teletype during PASS2. This list works downward starting just below the skeleton table area, working towards the symbol table area. PASS3 uses this list to write out extended error messages on the listing. PASS2 SKELETON TABLES All binary operators have associated with them a skeleton table having 24 entries arranged in 8 rows and 3 columns. The rows correspond to the following eight possibilities: 1) Both operands integer or real. 2) Both operands complex. 3) Both operands double precision. 4) First operand integer or real, second complex. 5) First operand integer or real, second double precision. 1-14 6) First operand complex, second integer or real. 7) First operand double precision, second integer or real. 8) Both operands logical. The columns correspond to the following three possibilities: 1) First operand in memory, second in AC. 2) Both operands in memory. 3) First operand in the AC, second in memory. Each entry of the skeleton tables is either zero (illegal operator- type combination) or points to a code skeleton (minus one). Code skeletons are composed of combinations of the following types of elements: 1) OPCODES - If an element has a non-negative value, it is taken as the address of a text string for the desired opcode. This works since all such text strings are stored below location 4000 (in field 0). In this case, the next word of the skeleton is taken as a designator for the address field, the possibilities are: a. A non-negative values means the address field is a literal text string, with the value being the address of the string. (Same restriction as for opcode text strings.) b. A zero indicates that this instruction should have no address field. c. A minus one indicates that the address field is the operand defined by the three variables ARG1, TYPE1, and BASE1. d. A minus two indicates that the address field is the operand defined by the three variables ARG2, TYPE2, and BASE2. 2) MODE CHANGE - An element value of minus one means generate a STARTF if currently in extended mode. A value of minus two means generate a STARTE if currently in single mode. 3) MACRO - Any other negative value is taken as the address (minus 3) of a sub-skeleton. This sub-skeleton may contain anything except another sub-skeleton reference. When the end of the sub-skeleton is encountered, the main skeleton is re-entered. 4) END-OF-SKELETON - A zero indicates the end of the skeleton. 1-15 PASS2 SUBROUTINES The following is a list of the major PASS 2 subroutines together with a brief functional description. ERMSG Output a 2-character error code together with the line number on the Teletypes; also put the code and line number into the error list for PASS3. UCODE Generate the code for unary operators, given the skeleton table address. CODE Generate code for binary operators, given the skeleton table address. INWORD Read a word from the PASS1 output file. FATAL Output a fatal error message and exit to OS/8. ONUMBER Output the AC as a 4-digit octal number. SAVEAC Generate an FSTA #TMP+XXXX if necessary. GENCOD Generate the code specified by the given code skeleton. OPCOD Output a TAB followed by the specified opcode field. OPCODE Same as OPCOD, except output a second TAB after the opcode field. OADDR Generate the address field specified by the argument. GENSTF Generate STARTF if in E mode. GENSTE Generate STARTE if in F mode. OSNUM Output a statement number preceded by a "#". CRLF Output a carriage return/line feed. OTAB Output a TAB. OUTSYM Output a text string. GARG Pop the top entry of the stack into ARG1, TYPE1, and BASE1. GARGS Pop the top two stack entries into ARG1, TYPE1, BASE1 and ARG2, TYPE2, BASE2. OUTNAM Output a variable name. 1-16 OLABEL Output a generated label. GETSS Find the address of the dimension information block given the symbol table address. SKPIRL Skip if integer, real, or logical. GENCAL Generate the code for a subroutine call from the information contained on the stack. MUL12 Do a 12-bit unsigned multiply. OINS Output a literal opcode and address field. OCHAR Output a character NUMBRO Output a 5-digit octal number. PASS3 OPERATION PASS3 first initializes the listing header line with the version number, date, and page number. It then processes lines, much like PASS1, handling continuations and comments and outputs their image to the listing file together with the line number. A constant check is made on the error message list for line numbers that correspond to the current line number, When such a correspondence occurs, the error code is used to find the associated detailed error message, which is then printed out. 1-17 CHAPTER 2 THE RALF ASSEMBLER RALF and FLAP are essentially the same program, with differences con- trolled by the conditional assembly parameter RALF, which must be nonzero to assemble RALF, or zero to assemble FLAP. The source may be assembled by either PAL8 or FLAP; although FLAP flags one error (a US on a FIELD statement), this may safely be ignored. The remainder of this chapter applies to RALF only. The following definitions are pre- requisite to discussion of the operation of this assembler. MODULE The relocatable binary output of an assembly. A module is physically an OS/8 file or sub-file in a library, and is made up of an external symbol dictionary and related text. Logically, it consists of one or more program sections and COMMON sections. LIBRARY An OS/8 file on a directory device containing a catalog and one or more modules as sub-files. Used solely by the loader, as a source of modules with which to satisfy unresolved symbols in a program being loaded. CATALOG A list of entry points defined in modules contained in a library, with an indication of the locations of the modules which define them. EXTERNAL A list of the global symbols defined in and/or used by SYMBOL a module. Usually called ESD table. DICTIONARY TEXT That part of the assembler's binary output which contains the binary data to be loaded into memory, along with sufficient information for the loader to associate the output with specific memory locations through references to the ESD table. SECTION A unit of binary data output by the assembler as part of a module to be loaded into a contiguous area of memory. COMMON sections are a special case in that they may be defined with the same name in each of many modules. In this case, all the definitions are combined to create a single section in memory whose size is that of the largest COMMON section with the given name. Program sections, the only other type of section, must have unique names. Sections are listed in the ESD table by name, type and size. ENTRY POINT An address within a section which is named and defined to be global, so that it may be used for the resolution of external references in other sections. Entry points are listed in the ESD table by name, type and address within the section in which they occur. 2-1 EXTERNAL A symbol which is specified at assembly time to be SYMBOL defined in another module as an entry point. External symbols are listed in the ESD table by name and type. A complete program must include entry point names equivalent to every external symbol defined in every module in the program. There need not, however, be an external symbol for every entry point, nor is there any limit on the number of modules which may contain external symbols referencing one entry point. From a functional viewpoint, entry points correspond to tags within a program and external symbols correspond to references to those tags. Every section is considered to have an entry point at location zero of the section. The name of this entry point is the section name. When RALF is called from the monitor, execution begins at the tag BEGIN. Unless entry is via CHAIN, the OS/8 command decoder is called to obtain input and output file designations. If entry is by way of CHAIN, it is assumed that the command decoder area has already been set up by the caller. In either case, it is always assumed that the USR is already in core. A check is made to determine that the first output file is a directory device file and, if no first output file was specified, the default file SYS:FORTRN.RL is set up. Default output file extensions are defined if none were specified to the command decoder, using .RL for the first output file and .LS for the second output file. The first output file is then opened, and the handler for the first input file is FETCHed. If /L or /G was specified, the loader is looked up on SYS so that chaining will be possible. The symbol table, which is loaded above 12000 in order to preserve the USR, is now moved down to 10000. Finally, the system date word is converted to character form and stored in the title buffer. This completes the initialization procedure, and control is passed to NEWLIN to collect the first line in the buffer. At NEXTST, teats are made to determine whether the line just assembled needs to be listed, and whether there are any remaining significant characters in the line which have not been assembled. If a semicolon terminated the statement, the character pointers are bumped to skip over it, and control passes to ASMBL to process the next statement on the line. If the assembler is currently in a REPEAT line and the count is not exhausted, the current line is re-assembled. Otherwise, a new line is obtained in the line buffer by collecting input characters until a carriage return is found. If the line is longer than 128 characters, all characters after the 128th are ignored and the LT message is printed. The line length is calculated and saved. At ASMBL, ASMOF is tested to determine whether the assembly is currently inside a conditional. If so, the line is scanned for angle brackets but not assembled. If not, and the first character is not a slash, leading blanks are thrown away and control passes to LUNAME. If there is a name, it is collected. If it is followed by a comma, the symbol is looked up in the user symbol table. If the symbol is undefined, it is defined as a label. If it was already defined, the 2-2 current location counter is compared with it to check for a possible MD error. Control then returns to ASMBL. If the symbol found by LUNAME was followed by an equal sign, it is looked up and defined according to the expression to the right of the equal sign. If it was followed by a space, either of the characters ' or #, or the character % and then a space, it is looked up in the op-code table. If it is found, control passes to the appropriate op-code handler. Otherwise, control is dispatched to GETEXP which restores the character pointers saved by LUNAME, processes the rest of the line as a single-word expression, and returns to NEXTST for the next statement. Expressions are processed on a strict left-to-right basis by the routine EXPR. A symbol is looked up, and its value is stored in WORD1 and WORD2. It is then combined with the accumulated expressions in EXPVAL according to the operator in LASTOP. A new operator (if any) is then located, and the loop begins again. When no operator is found after some symbol, the expression is considered complete and control returns to the calling routine. Undefined symbols appearing in an expression cause output of a US message, and the value zero is used in their place. COMMON and section names in the symbol table have special values (namely their lengths), but they always refer to the starting location of the sections they define, and their values are taken to be zero of the section so named. If GETNAM is not able to find a symbol in the expression, three possibilities are checked before flagging the expression as invalid: 1. It may be a number, rather than a symbol. 2. It may be one of the characters period (representing the current value of the location counter) or double quote (representing the binary value of the next ASCII character). 3. The last operator may have been a plus sign in an indexed FPP instruction. At the end of expression evaluation, the console keyboard flag is checked to ensure that the user has not typed CTRL/C to stop the assembly. There are six expression operator routines, one each for the operations add, subtract, AND, OR, multiply and divide. Except for add and subtract, these routines must operate on absolute addresses because the loader does not have facilities for non-additive resolution of address constants. The symbol table is the sole occupant of field 1, except for the OS/8 field 1 resident. The symbol table is loaded at location 12000 to prevent an unnecessary swap of the USR, but moved down, to start at location 10000, during initialization. Subsequent calls to the USR do require a swap. The symbol table is a set of linked lists, or, more properly, two sets; one for user-defined symbols and one for op-codes and pseudo-ops. Each set contains a list corresponding to every 2-3 letter of the alphabet, and each list consists of the symbols which start with that same letter. Every time a symbol is encountered in the source, the list corresponding to its first letter is searched until a match is found, or until the end of the list or a symbol of higher alphabetical order is found. In the latter cases, the new symbol is inserted into the user symbol table by changing the list pointers so that the new symbol appears in the list in correct alphabetical order. The pre-defined symbol table is never changed, because the user is not permitted to define op-codes or pseudo-ops. A RALF output file of relocatable binary data consists of two parts; the ESD table and the text. The ESD table contains all information required by LIBRA or the loader, and is generated between the first and second passes of assembly. It serves as a partial symbol table for the loader (the full symbol table is built up from the ESD tables of all the modules in a program) and provides the name, attributes, and value of every global symbol used by any module, as well as an ESD code by which the symbol may be referred to within the text. Every entry in the ESD table is six words long. The first three words are the symbol itself, packed in stripped ASCII, with two characters per word. The next word contains type information in the following format: A VALUE OF INDICATES 0 Last entry in the ESD table. 1 The symbol is defined as external to this module. The value of the symbol must be resolved by a symbol of the same name appearing in the ESD table of another module. The ESD code which follows the type code is the code by which references to this symbol will be identified in the text. 2 The symbol is defined as an entry point in this module. It is therefore suitable for the resolution of external references in other modules. The ESD code which follows the type word identifies the program section in which this entry point appears, and the value of the symbol is relative to that section. 3 The symbol is defined as a COMMON section whose size is at least as large as specified by the value of the symbol. If several modules contain ESD entries referring to COMMON sections with the same name, a single COMMON block having the size of the largest symbol is allocated for all of them. A name consisting of blanks is treated in the same manner as any other name. 4 The symbol is defined as a section of location independent (that is, fully word-relocatable) code of a size equal to the value of the symbol. The ESD code for this section allows text from the module to be included in this section, and relocated with respect to it. 2-4 5-17 Undefined The text portion of a relocatable binary file consists of the binary data to be loaded into memory, along with information directing the loader on how to modify that data to correct the addresses for program relocation. The first word of text is a control word, which is made up of a 4-bit type code and an 8-bit indicator. Following the control word, and depending on the type code, are a number of data words to be loaded as directed by the type code and the indicator. The control word type codes are: CODE FUNCTION 0 End of text, if the indicator is zero, or no operation otherwise. 1 Copy the number of words given by the indicator from text directly into memory without modification. 2 Re-origin to the section identified by the indicator, with a relative location defined by bits 9-23 of the following doubleword. Thus, the next two words define a new origin for the following text, in the program section identified by the indicator. 3 Relocate the following doubleword bits 9-23 by the value of the symbol whose ESD code is identified by the indicator. The following doubleword is usually a two- word FPP instruction, the low-order 15 bits of which are to be relocated by the value of the symbol identified by the indicator. WRITING PDP-8 CODE UNDER OS/8 FORTRAN IV RALF contains the normal set of PDP-8 instructions (TAD, DCA, CDF, KSF, etc.), however RALF does not allow literals, the PAGE pseudo-op, or the use of I to specify indirect addressing. PDP-8 code generated by RALF is not relocatable; therefore, operations such as the following are illegal: EXTERN SWAP /Illegal TAD (SWAP /Under CDF SWAP /RALF The character % appended to the end of a memory reference instruction indicates indirect addressing, and the character Z indicates a page 0 reference: 2-5 CURRENT PAGE PAGE ZERO DIRECT INDIRECT DIRECT INDIRECT TAD A TAD% A TADZ A TADZ% A DCA B DCA% B DCAZ B DCAZ% B Spaces are not allowed between memory reference instructions and either the Z or the % characters. The Z must precede the % when both are used. I.e., do not write "DCA%Z". Three pseudo-ops have been added to RALF: SECT8, COMMZ, and FIELD1. All three define sections of code and are handled in the same manner as SECT; however, these new sections have special meaning for the loader. The address pseudo-op (ADDR) which generates a two word re- locatable 15 bit address (i.e., JA TAG without use of JA) might prove useful in 8-mode routines. The following example demonstrates a way in which an 8-mode routine in one RALF module calls an 8-mode routine in another module: EXTERN SUB . . RIF /Set DF to current TAD ACDF /IF for return DCA .+1 0 /CDF X TAD KSUB /Make a CIF from RTL CLL /Field bits RAL TAD ACIF DCA .+1 0 /CIF to field /Containing SUB JMS% KSUB+1 KSUB, ADDR SUB /Psuedo-op to /Generate 15 bit /ADDR of subroutine /SUB ACDF, CDF ACIF, CIF In general the address pseudo-op can be used to supply an 8-mode section with an argument or pointer external to the section. FPP and 8-mode code may be intermixed in any RALF section. PDP-8 mode routines must be called in FPP mode by either: TRAP3 SUB or TRAP4 SUB A TRAP3 SUB causes FRTS to generate a JMP SUB with interrupts on and the FPP hardware (if any) halted. TRAP4 generates a JMS SUB under the 2-6 same conditions. The return from TRAP4 is: CDF CIF 0 JMP% SUB The return from TRAP3 is: CDF CIF 0 JMP% RETURN+1 EXTERN #RETRN RETURN, ADDR #RETRN Communication between FPP and 8-mode routines is best done at the FPP level because of greater flexibility in both addressing and relocation in FPP mode. The following routine demonstrates how to pass an argu- ment to, and retrieve an argument from, an 8-mode routine: EXTERN SUB EXTERN SUBIN EXTERN SUBOUT . . . FLDA X /Arg for SUB FSTA SUBIN TRAP4 SUB /Call SUB FLDA SUBOUT /Get result FSTA Y If the 8-mode routine SUB were in the same module as the FPP routine, the externs would not be necessary. In practice it is common for FPP and 8-mode routines that communicate with one another to be in the same section. A number of techniques can be used to pass arguments. For example, an FPP routine could move the index registers to an 8-mode section and pass single precision arguments via ATX. Because 8-mode routines are commonly used in conjunction with FPP code (generated by the compiler), the 8-mode programmer should be familiar with OS/8 FORTRAN IV subroutine calling conventions. The general code for a subroutine call is a JSR, followed by a JA around a list of arguments, followed by a list of pointers to the arguments. The FPP code for the statement: CALL SUB (X,Y,Z) would be EXTERN SUB JSR SUB JA BYARG JA X JA Y JA Z 2-7 BYARG, . . . . The general format of every subroutine obeys the following scheme: SECT SUB JA #ST /Jump to start of /Routine TEXT +SUB+ /Needed for /Trace back RTN, SETX XSUB /Reset SUB's index SETB BSUB /And base page BSUB, FNOP /Start of base page JA . . . ORG BSUB+30 /Restart for SUB FNOP:JA RTN GOBAK, FNOP:JA . /Return to /Calling program Location 00000 of the calling routine's base page points to the list of arguments, if any, and may be used by the called subroutine provided that it is not modified. Location 0003 of the calling routine's base page is free for use by the called subroutine. Location 0030 of the calling routine's base page contains the address where execution is to continue upon exit from the subroutine, so that a subroutine should not return from a JSR call via location 0 of the calling routine: CORRECT INCORRECT FLDA 30 FLDA 0 JAC JAC The "non-standard" return allows the calling routine to reset its own index registers and base page before continuing in-line execution. General initialization code for a subroutine would be: SECT SUB JA #ST . . . BASE 0 #ST, STARTD /So only 2 words /Will be picked up FLDA 30 /Get return JA FSTA GOBAK /Save it FLDA 0 /Get pointer to list 2-8 SETX XSUB /Set SUB's XR SETB BSUB /Set SUB's Base BASE BSUB INDEX XSUB FSTA BSUBX /Store pointer /Somewhere on Base . . . STARTF /Set F mode before JA GOBAK /Return The above code can be optimized for routines that do not require full generality. The JA #ST around the base page code is a convenience which may be omitted. The three words of text are necessary only for error traceback and may also be omitted. If the subroutine is not going to call any general subroutines, the SETX and SETB instructions at location RTN and the JA RTN at location 0030 are not necessary. If the subroutine does not require a base page, the SETB instruction is not necessary in subroutine initialization; similar remarks apply to index registers. If neither base page nor index registers are modified by the subroutine, the return sequence: FLDA 0 JAC is also legal. In a subroutine call, the JA around the list of argu- ments is unnecessary when there are no arguments. A RALF listing of a FORTRAN source will provide a good reference of general FPP coding conventions. In order to generate good 8-mode code, one must be aware of the manner in which the loader links and relocates RALF code. The loader handles three 8-mode section types: COMMZ, FIELD1, and SECT8. All three types of section are forced to begin and end on page boundaries and to be a part of level MAIN; 8-mode sections never reside in overlays. COMMZ and FIELD1 sections are forced to reside in field 1; SECT sections may be in any field. The first COMMZ section encountered is forced to begin at location 10000, thus enabling a page 0 in field 1. COMMZ sections of the same name are handled like COMMON sections of the same name (i.e., they are combined into one common section). This feature allows 8-mode code in different modules to share page 0, pro- vided that the modules do not destroy each other's page 0 allocations. Suppose two modules were to share page 0, with the first using location 0-17 and the second using locations 20-37: /Module A COMMZ SHARE P1, 1 P2, 2 KSUBA1, SUBA1 KSUBA2, SUBA2 . . 2-9 . /Should not go over LASTA, -1 /20 locations FIELD1 A TADZ P1 JMSZ% KSUBA1 . . . /Module B COMMZ SHARE ORG .+20 /ORG past module A's /Page 0 P3, 3 P4, 4 KSUBB, SUBB . . . LASTB -2 FIELD1 B TADZ P3 . . . The two COMMZ sections will be put on top of one another, however, because of the ORG .+20 in module B, they will effectively reside back to back. When the image is loaded, the COMMZ sections will look as follows: LOC CONTENTS 1 0000 1 0001 2 2 SUBA1 3 SUBA2 . . . 1 0017 -1 /LASTA 1 0020 3 21 4 22 SUBB . . . 37 -2 /LASTB If module A is to reference module B's page 0, the procedure is: P3=20 TADZ P3 2-10 Alternately, a duplicate of the source code for COMMZ SHARE may be included in module B. Modules that are using the same COMMZ section must be aware of how it is divided up. Although COMMZ SHARE takes only 40 locations, the loader allocates a full 200 locations to it. All 8-mode section core allocations are always rounded up so that they terminate on a page boundary. If COMMZ sections of different names exist, they are accepted by the loader and inserted into field 1, but only one COMMZ is the real page 0. In general, it is unwise to have more than 1 COMMZ section name. FIELD1 sections are identical to COMMZ sections in most respects. Memory allocation for FIELD1 sections is assigned after COMMZ sections, however, and FIELD1 sections are combined with FORTRAN COMMON sections of the same name as well as other FIELD1 sections of the same name. The first difference ensures that COMMZ will be allocated page 0 storage even in the presence of FIELD1 sections. The second allows PDP-8 code to be loaded into COMMON, making it possible to load initialization code into data buffers. Two FIELD1 sections with the same name may be combined in the same manner as two COMMZ, sections. The primary purpose of COMMZ is to provide a PDP-8 page 0; the primary purpose of FIELD1 is to ensure that 8-mode code will be loaded into field 1 and that generating CIF CDF instructions in-line is not neces- sary. SECT8 sections may not be combined in the manner of a COMMON and are not ensured of being placed into field 1. An 8-mode section does not have to be less than a page in length; however, the programmer should be aware that a SECT8 section which exceeds one page may be loaded across a field boundary and could thereby produce disastrous results at execution time. For this reason, it is generally unwise to cross pages in SECT8 code. This situation will never occur on an 8K configuration. If the total amount of COMMZ and FIELD1 code exceeds 4K, the loader generates an OVER CORE message. The loader generates an MS error for any of the following: 1. A COMMZ section name is identical to some entry point or some non-COMMZ section name. 2. A FIELD1 section name is identical to some entry point or a SECT, SECT8 or COMMZ section name. 3. A SECT8 section name is identical to an entry point or some other section name. COMMZ sections, like FORTRAN COMMONS, are never entered in the library catalog. For users who intend to write 8-mode code that will execute in conjunction with certain 8-mode library routines, the layout of PDP-8 FIELD1 #PAGE 0 is: 2-11 LOCATION USE 0-1 Temps for any non-interrupt time routine. 2-13 User locations. 14-157 System locations. 160-177 User locations. 1. Do not define any COMMZ sections other than the system COMMZ which is #PAGE0. 2. If the system page 0 is desired, it will be pulled in from the library if EXTERN #DISP appears in the code. 3. Do not use any part of page 0 reserved for the system. Special purpose PDP-8 mode subroutines may be written to perform idle jobs (refreshing a scope, checking sense lines) or to handle specific interrupts not serviced by FRTS. The run-time system enters idle loops while waiting for the FPP to complete a task or for an I/O job to complete. It is possible to effect a JMS to a user routine during the idle loop. RTS contains a set of instructions such as: #IDLE, JMP .+4 0 CDF CIF JMS I .-2 This sequence of instructions must be revised if an IDLE routine is to be called. The location #IDLE must be changed to a SKP (7410). #IDLE+1 must be set to the address of the routine to be called. #IDLE+2 must be set to a CDF CIF to the field of the routine. This setup can be done in a routine that is called at the beginning of MAIN. For example: CALL SETIDL where SETIDL is a routine such as: SECT8 SETIDL /Must be an 8-mode section JA #RET TEXT +SETIDL+ /Traceback information SXR, SETX XR SETB BP BP, 0.0 XR, 0.0 . . . 2-12 ORG 10*3+BP FNOP /For trace back JA SXR . 0 RET, JA . /Return address . . . #RET, STARTD /Set up FLDA 10*3 /Return address FSTA RET SETB BP /Just for traceback TRAP4 SET8 /Go to the 8 mode /Routine set 8 STARTF JA RET /Return to main SET8, 0 TAD IDLAD /Field of idle CLL RTL RAL /Move to /Bits 6-8 TAD SCDF /CDF to #IDLE DCA .+3 TAD IDLAD+1 /Address of #IDLE DCA IDPTR 0 /CDF goes here TAD S7410 /SKP DCA% IDPTR /Store at #IDLE TAD JOB+1 /Address of IDLE top routine ISZ IDPTR DCA IDPTR /Store a #IDLE+1 TAD JOB /Field of routine CLL RTL RAL /Position TAD SFIELD ISZ IDPTR DCA% IDPTR /Store at #IDLE+2 CDF CIF /Set to field 0 JMP% SET8 /Return to instruction /Following "TRAP4 SET8" EXTERN #IDLE IDLAD, ADDR #IDLE /15 bit address of IDLE JOB, ADDR DOIT /15 bit address of IDLE /Routine "DOIT" SCDF, 6201 /CDF SFIEL, 6203 /CDF CIF IDPTR, 0 S7410, 7410 /Skip /The following routine performs the /IDLE task /Executed during IDLE loops 2-13 DOIT, 0 . . . /Perform task . CDF CIF 0 /Back to field 0 JMP% DOIT /And back If the subroutine is checking for an illegal argument, an argument error message with traceback can be included in the subroutine by adding two lines somewhere on the base pages EXTERN #ARGER EXAMER, TRAP4 #ARGER When the error is detected in the program, effect a jump to the TRAP4 instruction. For example, FLDA% EXTMP1 JEQ EXAMER /A value of 0 is illegal or FLDA EXTMP1 FNEG FADD EXTMP2 JLT EXAMER /The value in EXTMP1 must be /greater than that in EXTMP2 Some points to note in the above example 1. Using a # as the first character in the name of the start of the program assumes that the name is not called from the FORTRAN level. This is because # is an illegal FORTRAN keyboard character. 2. If index registers 3-5 are not used by the subroutine, the space from XR3 to the ORG statement can be used for temporary storage, if needed. 3. The arguments passed from the FORTRAN level do not have to be picked up all at once at the start of the calculation (3-word) portion of the program. They can be picked up as required during the program, can be saved in temporary space, or accessed indirectly each time required, as best suits the subroutine. If a call to this routine such as Z=EXAMPL(A,B,C,D) were encountered by the compiler, it would generate the following call to the routine: JSR EXAMPL /go to the routine JA .+10 /jump around arguments JA A /pointer to lst argument JA B /pointer to 2nd argument JA C /pointer to 3rd argument JA D /pointer to 4th argument 2-14 The AMOD routine is listed below to illustrate an application of the formal calling sequence. It also includes an error condition check and picks up two arguments. When called from FORTRAN, the code is AMOD(X,Y). / / / / A M O D / - - - - / /SUBROUTINE AMOD(X,Y) SECT AMOD /SECTION NAME(REAL NUMBERS) ENTRY MOD /ENTRY POINT NAME(INTEGERS) JA #AMOD /JUMP TO START OF ROUTINE TEXT +AMOD + /FOR ERROR TRACE BACK AMODXR, SETX XRAMOD /SET INDEX REGISTERS SETB BPAMOD /ASSIGN BASE PAGE BPAMOD, F 0.0 /BASE PAGE XRAMOD, F 0.0 /INDEX REGS. AMODX, F 0.0 /TEMP STORAGE ORG 10*3+BPAMOD /RETURN SEQUENCE FNOP JA AMODXR 0 AMDRTN, JA . /EXIT EXTERN #ARGER AMODER, TRAP4 #ARGER /PRINT AN ERROR MESSAGE FCLA /EXIT WITH FAC=0 JA AMDRTN BASE 0 /STAY ON CALLER'S BASE PG /LONG ENOUGH TO GET RETURN ADDRESS MOD, /START OF INTEGER ROUTINE SAME AS #AMOD, STARTD /START OF REAL NUM. ROUTINE FLDA 10*3 /GET RETURN JUMP FSTA AMDRTN /SAVE IN THIS PROGRAM FLDA 0 /GET POINTER TO PASSED ARG SETX XRAMOD /ASSIGN MOD'S INDEX REGS SETB BPAMOD /AND ITS BASE PAGE BASE BPAMOD LDX 1,1 FSTA BPAMOD FLDA% BPAMOD,1 /ADDR OF X FSTA AMODX FLDA% BPAMOD,1+ /ADDR OF Y FSTA BPAMOD STARTF FLDA% BPAMOD /GET Y JEQ AMODER /Y=0 IS ERROR JGT .+3 FNEG /ABS VALUE FSTA BPAMOD FLDA% AMODX /GET X JGT .+5 2-15 FNEG /ABS VALUE LDX 0,1 /NOTE SIGN FSTA AMODX /SAVE IN A TEMPORARY FDIV BPAMOD /DIVIDE BY Y JAL AMODER /TOO BIG. ALN 0 /FIX IT UP NOW. FNORM FMUL BPAMOD /MULTIPLY IT. FNEG /NEGATE IT. FADD AMODX /AND ADD IN X. JXN AM,1 /CHECK SIGN FNEG AM. JA AMDRTN /DONE RTS has its own interrupt skip chain in which all on-line device flags are checked and serviced. This chain may be extended to handle special interrupts. The external tag #INT marks the first of three locations on RTS which have to be modified to effect a JMS to the user's special interrupt handler. The three locations must be set up in exactly the same manner as that used to set up #IDLE, #IDLE1, #IDLE2 as described above. All the same conventions hold. Refer also to the library subroutines ONQI and ONQB. Three pseudo-ops have been added to RALF to help the loader determine core allocation. Each is a more definitive case of the SECT pseudo-op and defines a chunk of code, thereby providing more control for the user. They are: SECT8 - section starts at a page boundary FIELD1 - section starts at a page boundary and is in field 1 COMMZ - section starts at page 0 of field 1 If there is more than one SECT8 section in a module, those sections are not necessarily loaded in contiguous core. The loader considers core to be in two chunks - one block in field 0, and all of field 1 and above. If there is more than one COMMZ pseudo-op in a module, they are stacked one behind the other, but there is no way of specifying which one starts at absolute location 0 of field 1. COMMZ sections are allocated by the loader before FIELD1 sections. Modules can share a COMMZ section in the same way that FORTRAN COMMON sections can be shared. FIELD1 sections can also be shared by using the same FIELD1 section name in each module. The first occurrence of a section name defines that section. For example, SECT8 PARTA . . . SECT8 PARTB 2-16 . . . SECT8 PARTA The second mention of PARTA in the same module continues the source where the first mention of PARTA ended at execution time. (There is a location counter for each section.) To save core, a RALF FIELD1 section and FORTRAN COMMON section of the same name are mapped on top of each other, being allocated the length of the longer and the same absolute address by the loader. This feature is useful for initialization (once-only) code, which can later be overlayed by a data area. Thus, the occurrence of FIELD1 AREA1 in the RALF module and COMMON AREA1 in the FORTRAN program causes AREA1 to start the same location (in field 1) and have a length of at least 200 locations (depending on the length of the RALF FIELD1 section or of the COMMON section in the FORTRAN). If the subroutine is longer than one page and values are to be passed across page boundaries, the address pseudo-op, ADDR, is required. The format is: AVAR1, ADDR VAR1 This generates a two-word reference to the proper location on another page, here VAR1. For example, to pass a value to VAR1, possible code is: 00124 1244 TAD VAR2 /Value on this page 00125 3757 DCA% AVAR1+1 /Pass through 12-bit . /location 00156 0000 AVAR1,ADDR VAR1 /Field and 00157 0322 /location of VAR1 Any reference to an absolute address can be effected by the ADDR pseudo-op. If it is doubtful that the effective address is in the current data field, it is necessary to create a CDF instruction to the proper field. In the above example, suitable code to add to specify the data field is: TAD AVAR1 /Get field bits RTL /Rotate to bits 6-8 RAL TAD (6201 /Add a CDF DCA .+1 /Deposit in line 0 /Execute CDFn If the subroutine includes an off-page reference to another RALF module (e.g., in FORLIB), it can be addressed by using an EXTERN with an ADDR pseudo-op. For example, in the display program, a ref- erence to the non-interrupt task subroutine ONQB is coded as 2-17 EXTERN ONQB ONQBX, ADDR ONQB and is called by JMS% ONQBX+1 The next instruction in the program is ADDR DISPLY so that DISPLY will be added to the background list. Execution from ONQB returns after the ADDR pseudo-op. It may be desirable to salvage the first (field) word allocated by ADDR pseudo-ops. If the address requires only twelve bite for proper execution, code such as TMP, TMP,ADDR X ARG,ADDR X or ARG= .-1 permits TMP to be used for temporary storage because ARG+1 in the left hand example or just ARG in the right hand example defines the 12-bit address. RALF does not recognize LINC instruction or PDP-8 laboratory device instructions. Such instructions can be included in the subroutine by defining them by equate statements in the program. For example, adding the statements: PDP = 2 LINC = 6141 DIS = 140 takes care of all instructions for coding the PDP-12 display subroutine. When writing a routine that is going to be longer than a page, it can be useful to have a non-fixed origin in order not to waste core and to facilitate modification of the code. A statement such as IFPOS .-SECNAM&177-K will start a new page only if the value [current location less section name] is greater than some K (start of section has a relative value of 0) where K<=177 and is the relative location on the current page before which a new page should be started. The ORG statement includes an AND mask of 7600 to preserve the current page. When added to 200 for the next page and the section name, the new origin is set. When calculating directly in a module, the following rules apply to relative and absolute values. 2-18 relative - relative = absolute absolute + relative = relative OR (!), AND (&) and ADD (+) of relative symbols generate the RALF error message RE. When passing arguments (single precision) from FPP code to PDP code, using the index registers is very efficient. For example, . . . FLDA% ARG1 /Get argument in FPP mode SETX MODE8 /Change index registers so XR0 is /At MODE8 ATX MODE8 /Save argument . . . TRAP4 SUB8 /Go to PDP-8 routine . . . SUB8, 0 /PDP-8 routine . . . TAD MODE8 /Get argument . . . MODE8, 0 /Index registers set here . . . 2-19 CHAPTER 3 THE FORTRAN IV LOADER The FORTRAN IV loader accepts a set of (up to 128) RALF modules as input, and links the modules, along with any necessary library components, to form a loader image file that may be read into memory and executed by the run-time system. The main task accomplished by the loader is program relocation, achieved by replacing the relative starting address of every section with an absolute core address. Absolute addresses are also assigned to all entry points, all relocatable binary text, and the externs. The loader executes in three passes. Pass 0 begins by determining how much memory is available on the running hardware configuration, and then constructs tables from the OS/8 command decoder input for use by pass 1 and pass 2. Pass 1 reads the relocatable binary input and creates the loader symbol table. The length of each input module is computed and stored, along with the relative values of entry points defined within the input modules. When an undefined symbol is encountered, pass 1 searches the catalog of the FORTRAN IV library specified to pass 0, or FORLIB.RL if no other library was explicitly specified, and loads the library routine corresponding to the undefined symbol. Pass 1 also allocates absolute core addresses to all modules and, through them, to all symbols. Pass 1 execution concludes by computing the lengths of all overlay levels defined for the current FORTRAN IV job. Trap vectors are also set up at this time, and the tables required for pass 2 loading are initialized. Pass 2 concludes loader execution by creating a loader image file from the relocated binary input and symbol values processed by pass 1. Pass 2 also produces the loader symbol map, if requested, and chains to the run-time system if /G was specified. Pass 0 contains very few subroutines. The routine CORDSW checks for the presence of /U, /C or /O option specifications, as supplied to the command decoder, and processes these options if necessary. A routine called UPDMOD is called when input to each overlay has been concluded, to update the module counts in the module count table. CORMOV is a general core-moving subroutine, called by the instruction sequence: JMS CORMOV CDF FROMFIELD FROMADDR - 1 CDF TOFIELD TOADDR - 1 - COUNT 3-1 LOADER PASS 0 (FILE COLLECTION) ------------------------------ 00000 | OS/8 Command Decoder | FIELD 0 | | | | |----------------------------| 02000 | Loader Pass 1 and | | Pass 2 | | | |----------------------------| 04600 | Core measuring routine | | and scratch area to | | save 00000-02000 | | during CD calls | |----------------------------| 06600 | | | Unused | | | |----------------------------| 07600 | OS/8 Field 0 resident | |----------------------------| 10000 | OS/8 User Service Routine | FIELD 1 | | | | |----------------------------| 12000 | Symbol table, loader map | | titles | 12400 | | |----------------------------| 13200 | Pass 0 code | |----------------------------| 14000 | Pass 1 initialization | | | | | |----------------------------| 16000 | Module count and | | module tables | |----------------------------| 17000 | Library catalog header | | read into this block | |----------------------------| 17600 | OS/8 Field 1 resident | ------------------------------ while ERROR is the local error processing routine, called with a pointer to the appropriate error message in the accumulator. The major pass 1 and pass 2 subroutines, described below, operate on the loader internal tables, whose format is presented later in this chapter. The subroutines are presented in approximately the order that they occur in the source listing. 3-2 LOADER PASS 1 (SYMBOL RESOLUTION) ------------------------------ 00000 | Pass 1 and Pass 2 | FIELD 0 | utility routines | |----------------------------| 01400 | Symbol map printer | |----------------------------| 02000 | Pass 2 | |----------------------------| 03200 | Pass 1 symbol collection | |----------------------------| 04000 | Inter-pass code allocates | | storage, builds and writes | | Loader Image Header Block. | |----------------------------| 04600 | Library catalog loads | | here in 8K. Unused in | | 12K or more. | |----------------------------| 07200 | Input device handlers | |----------------------------| 07600 | OS/8 Field 0 resident | |----------------------------| 10000 | ESD table | FIELD 1 | | 11400 | | |----------------------------| 12000 | Symbol table | |----------------------------| 15400 | Overlay length table | |----------------------------| 16000 | Module count and module | | tables (MCTTBL, MODTBL) | |----------------------------| 17200 | Loader header | |----------------------------| 17400 | ESD reference page | |----------------------------| 17600 | OS/8 Field 1 resident | |----------------------------| 20000 | Library catalog loads here | FIELD 2 | in 12K or more. | |----------------------------| 25000 | OS/8 BATCH processor if | | 12K or more and BATCH | | is running | ------------------------------ 3-3 LOADER PASS 2 (LOADER IMAGE BUILDER) ----------------------------------- 00000 | Utility routines: Symbol table | FIELD 0 | look-up, TTY message handler, | | OS/8 block I/O, MCTTBL | | processor. | |---------------------------------| 01400 | Routine to print symbol map. | |---------------------------------| 02000 | Pass 2 | |---------------------------------| 03200 | Binary buffer #1 | | | |---------------------------------| 05200 | Binary buffer #2 | | | |---------------------------------| 07200 | I/O device handlers | |---------------------------------| 07600 | OS/8 Field 0 resident | |---------------------------------| 10000 | RALF module text loads | FIELD 1 | here if 8K. | |---------------------------------| 12000 | Symbol table | | | |---------------------------------| 15400 | Overlay length table | |---------------------------------| 16000 | MCTTBL and MODTBL | - |---------------------------------| | 17200 | Binary section table and | > symbol map | binary buffer (LDBUFS) table | | output buffer |---------------------------------| | 17400 | ESD reference page | - |---------------------------------| 17600 | OS/8 Field 1 resident | |---------------------------------| 20000 | Binary buffer #3, if >8K | FIELD 2 |---------------------------------| 22000 | Binary buffer #4, if >8K | |---------------------------------| 24000 | Binary buffer #5, if >12K | |---------------------------------| 26000 | Unused | |---------------------------------| 30000 | RALF module text loads | FIELD 3 | here if >12K | ----------------------------------- 3-4 SETBPT Sets words BPTR and BPT2 to contain AC and AC+1, respectively. TTYHAN Subroutine to unpack and print a TEXT message on the console terminal. TTYHAN is called by: CDF CURRENT CIF 0 JMS TTYHAN CDF MSGFIELD MSG RTNOS8 Prints a fatal error message and then returns to the OS/8 monitor. A pointer to the message must follow the JMS RTNOS8. IOHAN Used to execute all I/O under OS/8. The calling sequence is: TAD (ACARG /Optional CDF CURRENT CIF 0 JMS IOHAN ADDR ARG1 ARG2 ARG3 where ARG1, ARG2 and ARG3 are standard OS/8 device handler arguments and ADDR points to a three-word block in field 1 which contains the OS/8 unit number in word 1, the file length in word 2, and the starting block number in word 3. If ACARG is zero, the indicated I/O operation is executed after the handler has been FETCHed, if necessary. If ACARG=n (greater than zero), the handler for OS/8 unit n is FETCHed, no I/O is done, and the four arguments that conclude the calling sequence are not needed. ADVOVR Called to initialize the loader to accept a new input module. ADVOVR determines whether a new overlay or level is being started by accessing the module count table. If so, it sets various pointers and internal counters accordingly, rounds the previous overlay to terminate on a 200 word boundary, and updates the length of the previous level, if necessary, as the maximum of its constituent overlay lengths. NXTOVR Called by ADVOVR when the next input module will be the first module in a new overlay. 3-5 SETCNT Initializes the pointers and counters used by ADVOVR. SETCNT is called once at the beginning of each pass. LOOK Executes a symbol look-up in the loader symbol table. LOOK is called by: TAD (Pointer to symbol name in RALF ESD format JMS LOOK RETURN here if not found RETURN here if found GPTR points to word following entry name If the symbol is not found, it is inserted into the loader symbol table and GPTR is set to point to the word following the symbol name. SYMMAP Produces the symbol map. PUTSYM Enters an ESD symbol in the loader symbol table. PUTSYM calls LOOK to determine whether the symbol is already present in the symbol table and, if so, verifies that the symbol is not multiply defined. Otherwise, it copies the ESD data words into the symbol table entry, updates the length of the current overlay by the length associated with the symbol, and links the symbol to its parent symbol, if any. FIT Fits a section into core by subtracting its length from the amount of core still available and substituting its load address for its length in the symbol table. DO8S, FIT8S Fits an 8-mode section into core by calling FIT and then checking for field 1 overflow. SETREF Extracts data from the ESD table of the current module and initializes the ESD reference page at 17400. BLDTV Builds the transfer vector. A transfer vector entry is created for each subroutine in an overlay. This entry provides the information that the run-time system will require in order to load the overlay containing the referenced subroutine. NEWORG Called whenever an origin is found in an input module, to map the location referenced by the origin into a block of the loader image file and an address within that block. NEWBB Called whenever a new binary buffer is needed during loader image file construction. NEWBB scans a list of available buffers and dumps the content of the least recently accessed buffer to free up space for new data. 3-6 MERGE Relocates an input word pair and outputs it to the loader image file. GETCTL Gets a control byte from the input module and incre- ments its return address by the content of the control byte. PUTBIN Inserts words, sequentially, into the current binary buffer. When the buffer is full, PUTBIN calls NEWBB to execute output to the loader image file and supply a new buffer. TXTSCN Called once for each input module. TXTSCN reads and relocates an entire input module, executing calls to MERGE, PUTBIN and NEWORG as needed. SYMBOL TABLE The loader symbol table begins at location 12000 and contains room for 26 (decimal) permanent system symbol entries and 218 (decimal) user entries. Each entry is 7 words long, and provides the name and definition of a symbol. The table is organized in buckets according to the first character of the symbol, which must be A to Z, #, or blank (for blank COMMON). The table of bucket pointers begins at location 12000 with the pointer to bucket A, and consists of one word per bucket. This word contains a value of zero, if there are no symbols in the corresponding bucket, or else the address of the first symbol in the bucket. Symbols within a bucket are arranged in alphabetical order, with each symbol entry pointing to the following entry, and the last entry pointing to zero. Thus, the symbol table appears as a set of threaded lists in core. The format of a symbol table entry is: 3-7 ------------------------------ | Pointer to next symbol in | | bucket (zero if none). | WORD 1 |----------------------------| | S | Y | WORD 2 |----------------------------| | M | B | WORD 3 |----------------------------| | O | L | |----------------------------| | | 3-bit | 4-bit | | | * | level | overlay | ** | | | # | # | | |----------------------------| | 9-bit pointer to | | | parent symbol | | | during pass 1 | | | (zero if none). | Field | | Trap vector | bits | | displacement | | | during pass 2. | | |----------------------------| | ADDRESS | | (Length during pass 1) | ------------------------------ * 1-bit trap vector flag during pass 1. Error flag during pass 2. ** 4-bit type code 0- undefined 1- entry point 2- extern 3- common sect 4- program sect 5- multiple entry point 6- multiple sect 7- SECT8 sect 10- COMMZ 11- FIELD1 12 to 17- undefined Several special symbols are created by the loader. The symbol #YLVLn, where n is an octal digit, describes overlay level n. This symbol table entry contains the length of level n during pass 1 and the starting address of level n during pass 2. The symbol #YTRAP describes the trap vector, a method by which the run-time system controls automatic overlaying of user subroutines. Four words are allocated in the trap vector for each entry point in every overlay except overlay #MAIN. The symbol table entry for #YTRAP contains the accumulated length of the trap vector during pass 1 and the trap vector starting address during pass 2. 3-8 ESD CORRESPONDENCE TABLE (ESDPG) The ESD correspondence table begins at location 17400 and contains 128 (decimal) 1-word entries. This table establishes the correspondence between the local ESD reference numbers used to reference a symbol inside a RALF module, and the address of that symbol in the loader symbol table. The nth entry in the ESD correspondence table points to the address of ESD symbol n. BINARY BUFFER TABLE (LDBUFS) The binary buffer table begins at location 17247 and contains from two to ten entries, depending upon the amount of memory available. Each entry is 4 words in length. The binary buffers function as windows into the loader image file, through which the loaded program is written onto mass storage. Each binary buffer is 8 pages (4 OS/8 blocks) in length. The loader tries to minimize the amount of "window turning" necessary to buffer the binary data by keeping a record of the last time each buffer was referenced. In this way, when the content of a binary buffer must be dumped to make room for new data, the loader empties that buffer which was least recently used. In addition, program loading is overlay oriented such that only one overlay is loaded at a time and while any specific overlay is being loaded, only origins inside that overlay are legal. The format of a binary buffer table entry is: ------------------------------------ | Pointer to the binary buffer of | | "next earliest reference", i.e., | | the youngest buffer older than | WORD 1 | this buffer. Contains zero if | | this buffer is oldest. | |----------------------------------| | Loader image block #. Contains | | zero if buffer has not been used.| WORD 2 |----------------------------------| | Blocks left in current overlay | | If <4, only part of buffer will | WORD 3 | be dumped. | |----------------------------------| | Page address | Buffer | | | of buffer. | field | Unused | WORD 4 | | bits | | ------------------------------------ 3-9 The number of binary buffers used varies with the amount of memory available as follows: ------------------------------------------- MEMORY | NO. OF AVAIL | BUFFERS -------------------|----------------------- 8K | 2 12K | 4 16K | 5 20K | 7 24K | 10 (decimal) 28K | 10 (decimal) 32K | 10 (decimal) ------------------------------------------- BINARY SECTION TABLE The binary section table overlays the loader image header block (described under FRTS) after the latter has been written into the loader image file at the beginning of pass 2. Thus, the binary section table begins at location 17200 and contains eight 4-word entries. Each entry relates the core origin of one of the eight overlay levels to that level's position in the loader image file. The format of a binary section table entry is: ----------------------------------- | | Field | | Unused | of | WORD 1 | | level | |---------------------------------| | Address of level | WORD 2 |---------------------------------| | Relative block # | WORD 3 |---------------------------------| | Length (in blocks) | WORD 4 ----------------------------------- OVERLAY TABLE (OVLTBL) The overlay table begins at location 15435 and contains room for 113 (decimal) 2-word entries. There is one entry for each overlay defined, including overlay MAIN, with each entry designating the length in words, of the corresponding overlay. The format of an overlay table entry is: 3-10 OVLTBL ----------------------- | LEVEL MAIN | |---------------------| Negated to indicate | LEVEL 1 OVERLAY 1 | last table entry |--------/\/----------| / . - / . | ------------------- / . | | HIGH-order bits |/ |--------/\/----------| | | of length | WORD 1 | LEVEL m OVERLAY n-1 |>----< |-----------------| |---------------------| | | LOW-order bits | | LEVEL m OVERLAY n | | | of length | WORD 2 |---------------------| | ------------------- | OVLTBL format | - individual entry (2 words) ----------------------- MODULE DESCRIPTOR TABLE (MODTBL) The module descriptor table begins at location 16172 and contains room for 172 (decimal) 3-word entries. Each entry provides the information needed to locate an input module. The first MODTBL entry corresponds to the library file to be used in building the current loader image. Successive entries correspond to input modules and appear in the order that the modules were specified by the user, (i.e., in ascending order by level, and ascending by overlay within any given level.) At the end of pass 1, entries corresponding to individual library modules are appended to the end of the table, even though the library modules load into level MAIN. The table format is: MODTBL -------------------------------- | FORLIB.RL or user- | | specified library | - |------------------------------| | -------------------------- | Level MAIN module #1 | | | OS/8 I/O unit # | |------------------------------| | |------------------------| | Level MAIN module #2 | < | File length (positive) | |------------------------------| | |------------------------| | Level MAIN module #3 | | | Starting block # | |----/\/----------------\/\----| | -------------------------- - |----/\/----------------\/\----| | Level MAIN module n | MODTBL format of |------------------------------| individual entry (3 words) | Level 1 Overlay 1 module #1 | |------------------------------| | Level 1 Overlay 1 module #2 | |----/\/----------------\/\----| 3-11 |----/\/----------------\/\----| | Level 1 Overlay 1 module #n | |------------------------------| | Level 1 Overlay 2 module #1 | |----/\/----------------\/\----| . . . |----/\/----------------\/\----| | Level m Overlay n module #p | |------------------------------| | Library module #1 | |------------------------------| | Library module #2 | |----/\/----------------\/\----| MODTBL format MODULE COUNT TABLE (MCTTBL) The module count table begins at location 16000 and contains room for 122 (decimal) 1-word entries that give the (two's complement) module count for each overlay level. The table format is: MCTTBL ------------------------- | LEVEL MAIN | 1-word ENTRIES |-----------------------| | 0 | |-----------------------| | LEVEL 1 OVERLAY 1 | |-----------------------| | LEVEL 1 OVERLAY 2 | |-----------------------| | LEVEL 1 OVERLAY 3 | |----/\/---------\/\----| |----/\/---------\/\----| | LEVEL 1 OVERLAY n | |-----------------------| | 0 | |-----------------------| | LEVEL 2 OVERLAY 1 | |-----------------------| | LEVEL 2 OVERLAY 2 | |----/\/---------\/\----| 3-12 |----/\/---------\/\----| | LEVEL 2 OVERLAY n | |-----------------------| | 0 | |-----------------------| | LEVEL 3 OVERLAY 1 | |----/\/---------\/\----| . . . |----/\/---------\/\----| | LEVEL m OVERLAY n | |-----------------------| | 0 | |-----------------------| | 0 | ------------------------- If an overlay or level is not defined for a specific program, there is no module count table entry corresponding to that overlay or level. The loader image file, produced by the loader and read as input by the run-time system, consists of a header block followed by a binary image of each level defined in the FORTRAN IV job. ----------------------------------- ----------- | HEADER | LEVEL | LEVEL / / LEVEL | | BLOCK | MAIN | 1 \ \ n | | | | / / | ---------------------------------- ------------ The loader image file header block contains information in the following format: LOCATION CONTENTS 0 2 -- Identifies the file as a loader image file. 1-2 Initial SWAP arguments to load level MAIN. 3-4 Highest address used by core load, including overlays but not including OS/8 device handlers. 5 Loader version number. 6 Double-precision flag. 7-46 User overlay information table containing one 4-word entry per overlay level (the level MAIN entry is ignored) in the following format: 3-13 --------------------------------------- | Unused until SWAP time. Must | WORD 1 | be positive or zero. | |-------------------------------------| Load | Page | Bits 4-5 | Field | Bits 9-11 | WORD 2 address ---> | bits | unused | bits | unused | |-------------------------------------| | Block number of this level, | WORD 3 | relative to header block. | |-------------------------------------| | Length of overlays in this level, | WORD 4 | in blocks. | --------------------------------------- 3-14 CHAPTER 4 THE FORTRAN IV RUN-TIME SYSTEM The FORTRAN IV run-time system supervises execution of a FORTRAN job and provides an I/O interface between the running program and the OS/8 operating system. FRTS includes its own loader, which should not be confused with LOAD, the system loader. It executes with only one overlay, used to restore the resident monitor and effect program termination. The run-time system was designed to permit convenient modification or enhancement, and it is well documented in the assembly language source, available from the Software Distribution Center, which includes extensive comments. One of the most valuable modifications to FRTS provides for the inclusion of background (or idle) jobs. When FORTRAN is waiting for I/O operations or the FPP to complete execution, the PDP-8 or PDP-12 processor is sitting in an idle loop. An idle job may be executed by the PDP-8 or PDP-12 CPU during this time, perhaps for the purpose of refreshing a CRT display, for example, or monitoring a controlled process. To indicate such a job, the idle wait loop must be modified to include a reference to the user's PDP-8 routine. The routine #IDLE in FRTS must be changed as part of the user's subroutine from #IDLE, JMP .+4 to #IDLE, SKP 0 ADDUSR CDF CIF FLDUSR JMS I .-2 JMS I .-2 Devices issuing interrupts may be added to the interrupt skip chain so that FORTRAN checks the user's device as well as system devices. The original code is: #INT, JMP .+4 0 CDF CIF JMS I .-2 and must be changed, as above, to: #INT, SKP ADDUSR FLDUSR JMS I .-2 In both cases, ADDUSR should be the address of the user's routine, and FLDUSR should be the memory field of the user's routine. The idle job is initiated by the subroutine HANG in the run-time system. Hang should only be called when the FORTRAN program must wait for an I/O device flag. The calling sequence is: 4-1 EXTERN #HANG IOF /Important. CDF n /Where n is current field. CIF 0 JMS% HANG+1 ADDRSS /Return here with interrupts OFF /When device flag is raised. HANG, ADDR #HANG The word ADDRSS must point to a location in page 400 of the run-time system which must normally contain a JMP DISMIS. Three such locations have been provided for the user at #DISMS, #DISMS+1, and #DISMS+2. The selected location must be the location via which the interrupt caused by the desired flag is dismissed. No two flag routines should use the same dismiss location. The following program example illustrates these calling conventions. This routine may be used to drive a Teletype terminal via the PT08 option. EXTERN #ONQI EXTERN #DISMS FIELD1 GETCH /JMS GETCH GETS A CHAR 0 /GETCH RUNS IN FIELD I ONLY ISZ FIRST JMP NOTFST JMS% ONQI+1 KSF1 ADDR KSFSUB TAD DISMIS+1 /SET UP TO CALL HANG DCA HNGLOC NOTFST, IOF TAD INCHR SZA CLA JMP GOT1 CIF 0 JMS% HANG+1 /NO CHAR READY: HANG HNGLOC, 0 /HANG RETURNS W/ IOF GOT1, TAD INCHR DCA FIRST DCA INCHR TAD FIRST ION JMP% GETCH /INTERRUPT ROUTINE - KSFSUB, 0 /CALLED AS SUBROUTINE KRB1 DCA INCHR CDF CIF 0 JMP% DISMIS+1 /RETURN TO SYSTEM LOCATION /CONTAINING "JMP DISMIS" INCHR, 0 ONQI, ADDR #ONQI 4-2 HANG, ADDR #HANG DISMIS, ADDR #DISMS FIRST, -1 In most cases, it is easier to include references to the FORLIB module ONQI for adding a handler to the interrupt skip chain and ONQB for adding a job to the idle chain, instead of trying to modify #IDLE and #INT. ONQB provides slots for up to 9 idle jobs to be executed round-robin, and ONQI provides for up to 9 user flags to be tested on program interrupts. FRTS entry points are listed, along with the core map, on the following pages. The FRTS calling sequence must be observed in any user subroutine. The formal calling sequence is illustrated below. In general, it can be used exactly as illustrated, changing only the section, entry, base page, index register and return location names. FRTS CALLING SEQUENCE SECT EXAMPL /Section name. Your module may /require another section pseudo-op /such as FIELD1 or SECT8. JA #EXSRT /Jump to start of subroutine /Use # for first character TEXT +EXAMPL+ /6 character section name for /error traceback (optional) EXAMXR, SETX XREXAM /Set up index registers /for this subroutine SETB BPEXAM /and its base page. BPEXAM, F 0.0 /Base page XREXAM, F 0.0 /Index registers 0-2 F 0.0 /Index registers 3-5 (optional) EXTMP1, F 0.0 /Space between index registers EXTMP2, F 0.0 /and the ORG for temporary EXTMP3, F 0.0 /storage (optional) ORG 10*3+BPEXAM /Location 30 of base page FNOP /Force a two-word instruction JA EXAMXR /Jump to base page for /return to calling program 0 /Force a two-word instruction EXMRTN, JA . /Will be replaced by return jump BASE 0 /Caller's base page #EXSRT, STARTD /Start of subroutine FLDA 10*3 /Get return jump from caller's /base page FSTA EXMRTN /Save in return location for /this routine FLDA 0 /Location 0 of caller's routine /is a pointer to the argument list SETX XREXAM /Change to EXAMPL's index registers 4-3 SETB BPEXAM /Change to EXAMPL's base page BASE BPEXAM FSTA BPEXAM /Save the pointer LDX 1,1 /Set up index register 1 FLDA% BPEXAM, 1 /Get address of argument list FSTA EXTMP1 /Save the addresses FLDA% BPEXAM, 1+ /of all passed arguments FSTA EXTMP2 FLDA% BPEXAM, 1+ FSTA EXTMP3 /Continue for all arguments . /to be picked up . . STARTF /Start three-word instructions FLDA% EXTMP1 . . . FLDA% EXTMP2 . . . /Continue to get arguments . /as required in routine JA EXMRTN /Exit when done RTS ENTRY POINT USEAGE AND COMMENTS #UE TRAP3 #UE /Produces USER ERROR error message. #ARGER or TRAP4 #ARGER /Produces BAD ARG error message. #ARGERR #READO TRAP3 #READO /Initializes JA UNITNO /formatted JA FORMAT /read operation. #WRITO TRAP3 #WRITO /Initializes JA UNITNO /formatted JA FORMAT /write operation. #RUO TRAP3 #RUO /Initializes unformatted JA UNITNO /read operation. #WUO TRAP3 #WUO /Initializes unformatted JA UNITNO /write operation. #RDAO TRAP3 #RDAO /Initializes JA UNITNO /direct access JA RECNO /read operation. 4-4 #WDAO TRAP3 #WDAO /Initializes JA UNITNO /direct access JA RECNO /write operation. #RFSV TRAP3 #RFSV /Passes a variable to or from the read/ /write processors via the floating AC. #RENDO TRAP3 #RENDO /Terminates a read/write operation. #ENDF FLDA UNITNO /Executes an TRAP3 #ENDF /end file, #REW or TRAP3 #REW /rewind, #BAK or TRAP3 #BAK /backspace (depending upon the entry used) /on the referenced I/O unit. #DEF TRAP3 #DEF /Opens a file JA UNITNO /for direct access I/O. JA RECORDS JA FPNPR /(FPP numbers per record) JA VARIABLE /Refer to DEFINE FILE statement #EXIT JSR #EXIT /Terminates current FORTRAN IV job. #SWAP TRAP3 #SWAP /Reads overlay OVLY into level LVL and ADDR /jumps to ADR. ADDR is given by: /ADDR=4000000*OVLY+100000*LVL+ADR #8OR12 /=00000001 if the CPU is a PDP-12. #IDLE Address of background job, used by ONQB. Contains: JMP I (NULJOB /Replace by SKP 0 /Replace by addr of background job CDF CIF 0 /Replace by field of background job JMS I .-2 JMP .-4 CORE LAYOUT OF FRTS NON-FPP FPP (Same as non-FPP unless indicated) ----------------------------------- 0000 | Page zero (0120-0134 free) | |---------------------------------| 0200 | Most entry points, character | | I/O handlers, interrupt | | service, and HANG routine | |---------------------------------| 0600 | Format decoder; A, H, and ' | | format processors, and EXIT | |------\/\---------------/\/------| 4-5 |------\/\---------------/\/------| 1400 | REWIND, ENDFILE, BACKSPACE and | | general unit initialization | | DATABL table (3wds/unit) | |---------------------------------| 2000 | I, E, F and G output | |---------------------------------| 2400 | I, E, F and G input | |---------------------------------| 2600 | X, L and T formats and | | GETHND routine | |---------------------------------| 3000 | Char in and char out routines | | including OS/8 packing, editing | | and forms control | |---------------------------------| 3400 | Binary and D. A. I/O, and | | DEFINE FILE processor | |---------------------------------| 3600 | Overlay loader | |---------------------------------| 4000 | Input line buffer, overlay | | and DSRN tables, FORMAT | | parenth pushdown list, /P | | processor and init flag clear | |---------------------------------| 4400 | Floating-point utilities (shift,| | add, etc.) used even w/FPP | |---------------------------------| 4600 | Error routine and messages | |---------------------------------| 5200 | OS/8 handler area and part of | | FRTS loader initialization | |---------------------------------|----------------------------- 5600 | FPP simulator | FPP start-up and trap | | | routines | | |----------------------------| 6000 | | B and D format I/O | |---------------------------------|----------------------------| 6600 | Floating-point package and | Floating-point package | | part of LPT ring buffer | (never used) and part of | | | LPT ring buffer | |---------------------------------|----------------------------- 7400 | Most of LPT ring buffer | |---------------------------------| 7600 | OS/8 handler and field | | 0 resident | |---------------------------------| 10000 | OS/8 User Service Routine | |---------------------------------| 12000 | FRTS loader tables, IONTBL | Locations 12000 to 17400 are | | overlayed at execution time |------\/\---------------/\/------| 4-6 |------\/\---------------/\/------| 12200 | FRTS loader: main flow | |---------------------------------| 12400 | program start-up (1) | |---------------------------------| 12600 | initialize and | | configure system | |---------------------------------| 13000 | Load OS/8 handlers and assign | | unit numbers to OS/8 files | |---------------------------------| 13400 | Utility and error routines, | | error messages | 14000 | | |---------------------------------| 15600 | FPP start-up and trap routines | Locations 14000 to 16777 are |---------------------------------| used to save lower field 0 16000 | B and D format I/O | during loading of device |---------------------------------| handlers and file 16600 | EAE Floating-point package | specifications |---------------------------------| 17400 | Termination routine | Locations 17400 to 17777 are |---------------------------------| written on SYS block 37 17600 | OS/8 field 1 resident | before program load and |---------------------------------| restored on termination #INT /Address of user interrupt location, used by ONQI: JMP .+4 /Replace with SKP 0 /Replace with address of interrupt processor CDF CIF 0 /Replace with field of interrupt processor JMS I .-2 #DISMS /Addresses first of three JMP DISMIS instructions for use by specialized I/O routines. #HANG /Addresses I/O dismiss routine. #RETRN /Provides return from TRAP3. ------------------------ (1) Program start-up moves OS/8 handler to top of core, writes field 1 resident onto SYS, and termination routine goes to FRTS to load program. 4-7 DSRN TABLE The DSRN table controls files and I/O devices used under OS/8 FORTRAN IV ASCII, binary and direct access I/O operations, including BACKSPACE, REWIND, and END FILE operations. The exact meaning of the initials DSRN is one of the great, unanswered questions of FORTRAN IV development and, as such, has considerable historical interest. The DSRN table provides room for 9 entries; each entry is 9 words in length, and contains the following data: WORD 1: (HAND) Handler entry point. If this value is positive, the I/O device handler is a FORTRAN internal (character-oriented) handler, and the remainder of the DSRN table entry is ignored. If the value is negative, the handler is an OS/8 device handler whose entry point is the two's complement of the value. Entry points always fall in the range [7607, 7777] for resident handlers or [5200, 5377] for non-resident handlers. Space for non-resident handlers is allocated downward from the top of memory, and the handlers are moved into locations 5200 to 5577 before being called. WORD 2: (HCODEW) Handler code word. Bits 0-4 of this word specify the page into which the device handler was loaded, while bits 6-8 specify the memory field. If all of bits 0-8 are zero, the handler is permanently resident. When any of these bits are non-zero, the data is used to determine which handler, if any, currently occupies locations 5200-5577. This eliminates unnecessarily moving the content of memory. Bit 10 is set if forms control has been inhibited on the I/O unit. Bit 11 is set if the device handler can execute with the interrupt system enabled. The data in bits 10 and 11 is obtained from the IOWTBL table in the FRTS loader. WORD 3: (BADFLD) Buffer address and field. Bits 0-4 address the memory page at which the I/O buffer for this unit begins, while bits 6-8 specify the memory field. Unlike the FORTRAN internal I/O unit buffers, OS/8 device handler buffers always occupy two full pages of memory. Buffer space is allocated upward from the top of the FORTRAN program. WORD 4: (CHRPTR) Character pointer. WORD 5: (CHRCTR) Character counter. Words 4 and 5 of each DSRN table entry define the current character/position in the I/O buffer as follows: 4-8 Value of Character Next value Next value Special CHRCTR position of CHRCTR of CHRPTR Conditions ---------------------------------------------------------------------- | Bits 4-11 of word | | | Refresh buffer if -3 | addressed by | -2 | CHRPTR + 1 | input operation and | CHRPTR | | | CHRPTR mod 256=0 | | | | -2 | " | -1 | " | none | | | | -1 | Bits 0-3 of words | | | | addressed by | | | Dump buffer if | CHRPTR-2 and | -3 | CHRPTR | output operation | CHRPTR-1 | | | and CHRPTR mod | | | | 256=0 | | | | ---------------------------------------------------------------------- WORD 6: (STBLK) Starting block of file. WORD 7: (RELBLIC) Current relative block of file. That is, block to be accessed next. WORD 8: (TOTBLK) Length of file in blocks. WORD 9: (FFLAGS) Status flags: Bit 0 - Has been written flag. Set to 1 if unit has received output since last REWIND. Bit 1 - Formatted I/O flag. Set to 1 if an ASCII I/O operation has occurred since last REWIND. Bit 2 - Unformatted I/O flag. Set to 1 if a binary or direct access I/O operation has occurred since last REWIND. Bits 1 and 2 are never set simultaneously. Bit 11- END FILEd flag. Set to 1 if unit has been END FILEd. Bit 11 is not cleared by a REWIND. When any active unit is selected for an I/O operation, the DSRN table entry for that unit is moved into 9 words on page 0. These 9 words are tagged with the labels cited above. Upon completion of the I/O operation, the 9 words are moved from page 0 back into the DSRN table. 4-9 /FORTRAN 4 RUNTIME SYSTEM - R.L PAL8-V8 PAGE 3 /PAGE ZERO FOR FORTRAN IV RTS 0000 *0 /INTERRUPT STUFF 00000 0000 0 00001 5402 JMP I .+1 00002 0400 INTRPT 00003 5165 LPGET, LPBUFR /LINE PRINTER RING BUFFER FETCH 00004 0000 TOCHR, 0 /TELETYPE STATUS WORD 00005 0000 KBDCHR, 0 /KEYBOARD INPUT CHARACTER 00006 0000 POCHR, 0 /P.T. PUNCH COMPLETION FLAG 00007 0000 RDRCHR, 0 /P.T. READER STATUS 00010 0000 FMTPXR, 0 /XR USED TO INDEX FORMAT PARENTH 00011 3777 INXR, INBUFR-1 /XR USED TO GET CHARS FROM INPUT 00012 0000 XR, 0 00013 0000 XR1, 0 0016 *16 00016 0000 VEOFSW, 0 /USED BY "EOFCHK" TO STORE VARIABLE ADDRESS 00017 0000 0 /*K* MUST BE IN AUTO - XR 00020 0000 T, 0 /TEMPORARY 00021 0000 DFLG, 0 /0 = F.P., 1 = D.P. 00022 0000 INST, 0 /CURRENT INSTRUCTION WORD /IOH PAGE ZERO LOCATIONS 00023 0000 RWFLAG, 0 /READ/WRITE FLAG 00024 0000 FMTTYP, 0 /TYPE OF CONVERSION BEING DONE 00025 0000 EOLSW, 0 /EOL SW ON INPUT - CHAR POS ON OUT 00026 0000 N, 0 /REPEAT FACTOR 00027 0000 W, 0 /FIELD WIDTH 00030 0000 D, 0 /NUMBER OF PLACES AFTER DECIMAL 00031 0300 DATCDF, 0 /SUBROUTINE TO CHANGE DATA FIELD 00032 0000 DATAF, 0 /CONTAINS VARIOUS CDF'S 00033 5431 JMP I DATCDF /RETURN 00034 5013 ERR, ERROR /POINTER TO ERROR ROUTINE 00035 0000 FATAL, 0 /FATAL ERROR FLAG - 0=FATAL 00036 5000 MCDF, MAKCDF /FPP PARAMETER TABLE LOCATIONS: 00037 0000 APT, 0 /VARIOUS FIELD BITS FOR FPP 00040 5313 PC, DPTEST /FPP PROGRAM COUNTER 00041 0000 XRBASE, 0 /FPP INDEX REGISTER ARRAY ADDRESS 00042 0000 BASADR, 0 /FPP BASE PAGE ADDRESS 00043 0000 ADR, 0 /ADDRESS TEMPORARY 00044 0000 ACX, 0 00045 0000 ACH, 0 /*** FLOATING ACCUMULATOR *** 00046 0000 ACL, 0 00047 0000 EAC1, 0 00050 0000 EAC2, 0 /** FOR EXTENDED PRECISION OPTION ** 00051 0003 EAC3, 0 4-10 /FORTRAN 4 RUNTIME SYSTEM - R.L PAL8-V8 PAGE 4 /FLOATING POINT PACKAGE LOCATIONS 00052 0000 AC0, 0 00053 0000 AC1, 0 /FLOATING AC OVERFLOW WORD 00054 0000 AC2, 0 /OPERAND OVFLOW WORD 00055 0000 OPX, 0 00056 0000 OPH, 0 /*** FLOATING OPERAND REGISTER *** 00057 0000 OPL, 0 /RTS I/O SYSTEM LOCATIONS 00060 0000 FMTBYT, 0 /FORMAT BYTE POINTER 00061 0000 IFLG, 0 /I FORMAT FLAG 00062 0000 GFLG, 0 /G FORMAT FLAG 00063 0000 EFLG, 0 /E FORMAT FLAG - SOMETIMES ON FOR 00064 0000 OD, 0 00065 0000 SCALE, 0 00066 0000 PFACT, 0 /P-SCALE FACTOR 00067 0000 PFACTX, 0 /TEMP FOR PFACT 00070 0000 INESW, 0 /EXPONENT SWITCH 00071 0000 CHCH, 0 00072 0000 FMTNUM, 0 /CONTAINS ACCUMULATED NUMERIC VALUE 00073 0000 CTCINH, 0 /^C INHIBIT FLAG 00074 0320 PTTY, TTY /POINTER TO TTY HANDLER - USED BY 00075 0000 0 / SO FORMS CONTROL WILL WORK ON 00076 6001 FPNXT, ICYCLE /USED AS INTERPRETER ADDRESS IF /DSRN IMAGE 00077 0000 HAND, 0 /HANDLER ENTRY POINT 00100 0000 HCODEW, 0 /HANDLER LOAD ADDR & FIELD + IOFFL 00101 0000 BADFLD, 0 /BUFFER ADDRESS AND FIELD 00102 0000 CHRPTR, 0 /ACTUALLY A WORD POINTER 00103 0000 CHRCTR, 0 /COUNTER - RANGES FROM -3 TO -1 00104 0000 STBLK, 0 /STARTING BLOCK OF FILE 00105 0000 RELBLK, 0 /CURRENT RELATIVE BLOCK NUMBER 00106 0000 TOTBLK, 0 /LENGTH OF FILE 00107 0000 FFLAGS, 0 /FILE FLAGS: /BIT 0 - "HAS BEEN WRITTEN" FLAG /BITS 1-2 - FORMATTED/UNFORMATTED /BIT 11 - "END-FILED" FLAG 00110 0000 BUFFLD, 0 /ROUTINE TO SET DF TO BUFFER FIELD 00111 7402 BUFCDF, HLT 00112 5510 JMP I BUFFLD 00113 0000 FGPBF, 0 /THESE THREE WORDS ARE USED 00114 0000 BIOPTR, 0 /TO FETCH AND STORE FLOATING POINT 00115 0000 FEXIT /FROM RANDOM MEMORY 0200 PAGE 4-11 /FORTRAN 4 RUNTIME SYSTEM - R.L PAL8-V8 PAGE 5 /STARTUP CODE 00200 2203 FTEMP2, ISZ .+3 /ALSO USED AS I/O F.P. TEMPORARY 00201 6213 CDF CIF 10 00202 5603 JMP I .+1 00203 2200 VDATE, RTSLDR /USED TO STORE OS/8 DATE /RTS ENTRY POINTS - "VERSION INDEPENDENT" 00204 5777 VUERR, JMP I (USRERR /USER ERROR /** LOADER MUST DEFINE #ARGER AS 00205 4434 VARGER, JMS I ERR /LIBRARY ARGUMENT ERROR 00206 2023 VRENDO, ISZ RWFLAG /END OF I/O LIST 00207 5634 VRFSV, JMP I GETLMN /I/O LIST ARG ENTRY - COROUTINE 00210 5776 VBAK, JMP I (BKSPC /"BACKSPACE" ROUTINE 00211 5775 VENDF, JMP I (ENDFL /"END FILE" ROUTINE 00212 5774 VREW, JMP I (RWIND /"REWIND" ROUTINE 00213 5773 VDEF, JMP I (DFINE /"DEFINE FILE" ROUTINE 00214 7330 VWUO, AC4000 /UNFORMATTED WRITE 00215 5772 VRUO, JMP I (RWUNF /UNFORMATTED READ 00216 7330 VWDAO, AC4000 /DIRECT ACCESS WRITE 00217 5771 VRDAO, JMP I (RWDACC /DIRECT ACCESS READ 00220 7330 VWRITO, AC4000 /FORMATTED (ASCII) WRITE 00221 5770 VREADO, JMP I (RWASCI /FORMATTED (ASCII) READ 00222 5767 VSWAP, JMP I (SWAP /OVERLAY PROCESSOR 00223 3000 VEXIT, TRAP3; CALXIT /"STOP" ROUTINE - ENTERED IN FPP 00224 1317 00225 0000 V8OR12, 0;0 /0;1 IF CPU IS A PDP-12 00226 0000 00227 5766 VBACKG, JMP I (NULLJB /BACKGROUND JOB DISPATCHER 00230 0000 0 00231 6203 CDF CIF 0 /USED BY ROUTINE "ONQB" IN LIBRARY 00232 4630 JMS I .-2 00233 5227 JMP VBACKG /IOH GET VARIABLE ROUTINE. /THIS ROUTINE MAKES THE FORMATTED I/O PROCESSOR AND THE /PROGRAM CO-ROUTINES (DEF(COROUTINE): 2 ROUTINES EACH / IS A SUBROUTINE). ON ENTRY FAC=INPUT NUMBER /IF I/O IS A READ, ON RETURN FAC=OUTPUT NUMBER IF I/O 00234 0000 GETLMN, 0 00235 5577 VRETRN, JMP I [RETURN 4-12 All FORTRAN IV mass storage I/O is performed in terms of OS/8 blocks, including direct access I/O. Hence, all FORTRAN IV files conform to OS/8 standard ASCII file format. When a formatted READ or WRITE is requested, the data is converted to or from 8-bit binary representa- tion according to the FORMAT statement associated with the READ or WRITE. Standard OS/8 file format packs three 8-bit characters into two 12-bit words as follows: MASS STORAGE CORE ----------------------------- ------------------ | WORD 3 | | | WORD 1 | | bits 0-3 | WORD 1 | |----------------| |---------------------------- | WORD 2 | | WORD 3 | | |----------------| | bits 4-7 | WORD 2 | | WORD 3 | ----------------------------- ------------------ Unformatted (i.e. direct access) READ and WRITE operations also operate on standard OS/8 format files, with each statement causing one FORTRAN IV record to be read or written. A FORTRAN IV record must contain at least one OS/8 block, and always contains an integral number of blocks. The number of variables contained in a 1-block record depends upon the content and format of the I/O list, as follows: Number of 12-bit Number of Format type Words/Variable Variables/Block ___________ ________________ _______________ Integer 3 85 Real 3 85 Double precision 6 42 1/2 Complex 6 42 1/2 It is possible to mix any types of data in an I/O list; however, no more than 85 variables may be stored in one OS/8 block. The number of blocks required for a FORTRAN IV record depends, therefore, upon the number of variables in the I/O list, and may be minimized by supplying every direct access WRITE with sufficient data to nearly fill an integral number of blocks without overflowing the last block. The last word in every file block contains a block count sequence number and is not available for data storage. FRTS assigns block count numbers sequentially, beginning with 1, whenever a file is written. Block count numbers must be maintained by the user when FORTRAN IV files are created outside of an OS/8 FORTRAN IV environment. While reading a binary file, FRTS checks the block count sequence numbers on input blocks and ignores any block whose sequence number is larger than expected. Sequence number checking is disabled during direct access READ operations. When FRTS is loaded and started, the initialization routines deter- mine what optional hardware, such as FPP-12 Floating Point Processor or KE8E Extended Arithmetic Element, is present in the running hardware configuration. The initialization routines then modify FRTS 4-13 to use the optional hardware, if available. When an FPP is present in the system and it becomes desirable to disable the FPP under FRTS, this may be accomplished by changing the content of location 12621 from 6555 to 7200. The extended arithmetic element may be disabled in the same manner by changing the content of FRTS location 12623 from 7413 to 7200. These changes must be made before FRTS is started. The OS/8 monitor GET and ODT commands provide an excellent mechanism for changes of this type. The FRTS internal line printer handler uses a linked ring buffer for maximum I/O buffering efficiency. The buffer consists of several contiguous sections of memory, linked together by pointers. All of these buffer segments are located above 04000, so that the pointers are readily distinguishable from buffered characters. The entire 07400 page is included in the line printer ring buffer. If it becomes desirable to modify FRTS by patching or reassembly, most of the 07400 page may be reclaimed from the buffer by changing the content of location 07402 from 7577 to 5164. This frees up locations 07403 to 07577 for new code and still leaves about eighty character positions in the LPT ring buffer. Because FRTS executes with the processor interrupt system enabled, it may hang up on hardware configurations that include equipment capable of generating spurious program interrupts. In addition, any OS/8 I/O device handler that exits without clearing all device flags may cause troublesome interrupts when it is assigned as a FORTRAN I/O unit under FRTS. To counteract these potential problems, FRTS provides certain areas that are reserved for inclusion of user-generated code designed to clear device flags and/or inhibit spurious interrupts. A string of NOP instructions beginning at location 04020 is executed during FRTS initialization, just before the interrupt system is enabled. When the /H option is specified to FRTS, the system halts after these NOPs have been executed and the interrupt system has been enabled. Another string of NOPs occupying the eight locations from 03746 to 03755 is executed after every call to an OS/8 device handler. Any of these NOP instructions may be replaced by flag-handling or interrupt-servicing code. If additional memory locations are required, they may be obtained by replacing some of the code from locations 04007 to 04017 with flag-handling code. Locations 04007-17 are used to clear flags associated with LAB-8/E peripheral devices. Due to memory limitations, it is not possible to add internal I/O device handlers to the four internal handlers supplied with the system. However, FORTRAN I/O unit 0, which is not defined by the ANSI standard, may be specified for terminal I/O via the internal console terminal handler. I/O unit 0 is not re-assignable. The FRTS /P option provides a mechanism whereby the core image gener- ated from a FORTRAN program may be punched onto paper tape in binary loader format. This permits the loader image to be executed on a hardware configuration that does not include mass-storage devices. To use the /P option, specify /P to FRTS and assign a device or file as FORTRAN I/O unit 9. Assigning the paper tape punch as unit 9 causes 4-14 /FORTRAN 4 RUNTIME SYSTEM - R.L PAL8-V8 PAGE 6 /INTERRUPT DRIVEN I/O HANDLERS 00236 0000 LPT, 0 /RING-BUFFERED - LP08 OR LS8E 00237 0176 AND [377 /JUST IN CASE 00240 7450 LPTSNA, SNA 00241 5765 JMP I (IOERR /CANNOT BE USED FOR INPUT 00242 6002 IOF 00243 3667 DCA I LPPUT 00244 1003 TAD LPGET 00245 7041 CIA 00246 1267 TAD LPPUT 00247 7640 SZA CLA /IS LPT QUIET? 00250 5253 JMP .+3 /NO 00251 1667 TAD I LPPUT 00252 6666 LLS /YES - START 'ER UP 00253 7201 CLA IAC 00254 6665 LIE /ENABLE LPT INTERRUPTS 00255 1267 TAD LPPUT /1 IN AC, REMEMBER? 00256 3267 DCA LPPUT 00257 1667 TAD I LPPUT 00260 7510 SPA 00261 5256 JMP .-3 /NEGATIVE NUMBERS ARE BUFFER LINKS 00262 7640 SZA CLA /ANY ROOM LEFT IN BUFFER? 00263 4764 JMS I (HANG 00264 0436 LPUHNG /WAIT FOR LINE PRINTER 00265 6001 ION /TURN INTERRUPTS BACK ON 00266 5636 JMP I LPT /RETURN 00267 5165 LPPUT, LPBUFR 00270 0000 PTP, 0 /PAPER TAPE PUNCH HANDLER 00271 7450 SNA 00272 5765 JMP I (IOERR /INPUT IS ERROR 00273 3236 DCA LPT /SAVE CHAR 00274 6002 IOF 00275 1006 TAD POCHR /IF PUNCH IS NOT IDLE, 00276 7640 SZA CLA /WE DISMISS JOB 00277 4764 JMS I (HANG 00300 0502 PPUHNG /WAIT FOR PUNCH INTERRUPT 00301 1236 TAD LPT 00302 6026 PLS /OUTPUT CHAR 00303 3006 DCA POCHR /SET FLAG NON-ZERO 00304 6001 ION 00305 5670 JMP I PTP /*K* THE FOLLOWING ADDRESSES GET FALLEN INTO & MUST BE SMALL IFNZRO PPUHNG&7000 <--ERROR--> IFNZRO TTUHNG&7000 <--ERROR--> IFNZRO KBUHNG&7000 <--ERROR--> IFNZRO RDUHNG&7000 <--ERROR--> IFNZRO LPUHNG&7000 <--ERROR--> 4-15 /FORTRAN 4 RUNTIME SYSTEM - R.L PAL8-V8 PAGE 7 /INTERRUPT-DRIVEN PTR AND TELETYPE HANDLER 00306 0000 PTR, 0 /CRUDE READER HANDLER 00307 7640 SZA CLA 00310 5765 JMP I (IOERR /OUTPUT ILLEGAL TO PTR 00311 6002 IOF 00312 6014 RFC /START READER 00313 4764 JMS I (HANG 00314 0510 RDUHNG /HANG UNTIL COMPLETE 00315 1007 TAD RDRCHR /GET CHARACTER 00316 6001 ION 00317 5706 JMP I PTR /RETURN 00320 0000 TTY, 0 /BUFFERS 2 CHARS ON OUTPUT, 1 ON 00321 6002 IOF /DELICATE CODE AHEAD 00322 7450 SNA /INPUT OR OUTPUT? 00323 5342 JMP KBD /INPUT 00324 3236 DCA LPT /OUTPUT - SAVE CHAR 00325 1004 TAD TOCHR /GET TTY STATUS 00326 7740 SMA SZA CLA /G.T. 0 MEANS A CHAR IS BACKED UP 00327 4764 JMS I (HANG 00330 0451 TTUHNG /WAIT FOR LOG JAM TO CLEAR 00331 1004 TAD TOCHR /NO CHAR BACKED UP - SEE IF TTY 00332 7104 CLL RAL /"BUSY" FLAG IN LINK - INTERRUPTS 00333 7230 CLA CML RAR /COMPLEMENT OF BUSY IN SIGN 00334 1236 TAD LPT /GET CHAR 00335 7510 SPA /IF TTY NOT BUSY, 00336 6046 TLS /OUTPUT CHAR 00337 3004 DCA TOCHR /STORE POS OR NEG, BACKED UP 00340 6001 TTYRET, ION /TURN INTERRUPTS BACK ON 00341 5720 JMP I TTY /AND LEAVE /FORTRAN 4 RUNTIME SYSTEM - R.L PAL8-V8 PAGE 8 00342 1005 KBD, TAD KBDCHR /HAS A CHARACTER BEEN INPUT? 00343 7650 SNA CLA 00344 4764 JMS I (HANG 00345 0465 KBUHNG /NO - RUN BACKGROUND UNTIL ONE IS 00346 1005