RT-11 EMULATOR UNDER RSTS 7.0: A Guide to Its Effective Use James Krupp Middlebury College Middlebury,Vermont 1.0 Introduction Since Fortran was first made available under RSTS, many user's have experimented with Assembly Language programming under RSTS. For most of us this required reading between the lines of monitor listings, trading of "secret documents", and careful questioning of software specialists and others. With RSTS V7.0, most of the mystery of Macro programming under RSTS has been removed. A new (and superbly written) manual documents all of the native RSTS system calls, as well as providing thorough documentation on the RSX emulator directives. However, for many the most natural environment for writing Macro code is not under RSX but rather under the RT11 emulator. This is certainly the case for the Fortran programmer. It could even be argued that the RT11 environment is better for straight Macro coding since the RT11 assembler is smaller and faster than its RSX counterpart, and the RT11 Linker can significantly out perform the RSX Taskbuilder. Yet for reasons that are unclear (although one might wish to conjecture) the RT11 emulator for RSTS V7.0 has not been adequately documented. It is the purpose of this brief presentation to provide some necessary information that should allow the interested person to get over the initial hurdles of using Macro under RT11. Many details will of necessity be omitted. However, it is the case that the information presented here together with that in the RT11 Advanced Programmer's Guide (DEC#AA-5280B-TC) should allow very effective programming in Macro under RT11. (This manual will be referred to as "APG" in the following). It is assumed that the reader/listener has benefited from the many illuminating talks at past Decus Symposium on the structure of RSTS job images, runtime systems and the like. For those who are not, rest assured that the new RSTS System Directives Manual will tell you all you've ever wanted to know (and in some cases more). NOTE All values in the following, except when referring to bits, are in octal. Bit numbering is from 0 to 15, least significant to most significant bit, according to standard PDP-11 numbering conventions. PAGE 2 2.0 The Job Image Under RT11 The RT11 Emulator attempts to provide all of the support services of an RT11 V3 SJ Monitor. When selected as the default runtime system, most RT11 KMON commands are supported. A program running under RT11 may issue an RT11 programmed request, and the emulator will translate the request from its RT11 format to the equivalent RSTS format (where appropriate) and perform the desired action. The commands and EMT's supported are discussed further below. As a general rule, if an RT11 KMON command or programmed request "makes sense" in the RSTS environment, it can be assumed to work as it does for RT11. The are some notable exceptions and these shall be pointed out. A first step towards using Macro under RT11 is an understanding of how the emulator utilizes memory. The job's address space may be separated into 4 logically distinct regions: low core, the program, the impure area, and the runtime system. For purposes of the presentation here, the runtime system may be considered a "black box" which performs certain actions and occupies 4K words of address space, leaving 28K for the other three areas. 2.1 Low Core Low core is the region from address 0 to 1000 (or as specified in the Linker /B switch). In addition to the normal context save areas used by RSTS, a job running under RT11 contains a remarkably complete RT11 low core image as described in pages 2-6 ff of the APG. Some of the important words in this region are: 14,16 Two-word trap vector used for BPT traps issued by the user program. ODT.OBJ uses this vector. 20,22 Two-word trap used for IOT traps issued by the user program. 34,36 Two-word trap vector for TRAP traps issued by the user program. 40,41 Job start address, i.e., where RT11 transfers control when a program is run. Set by Linker /T switch or Macro .END psuedo. 42,43 Initial job stack pointer. Normally equal to 1000 or the value set by /B Linker switch. 44,45 RT11 JSW. Various bits are important. Notably, BIT 14 enables lowercase input when set and BIT 8 is set if the program was CHAINed to. Other bits described in APG which are relevant to the emulator are bits 6, 9, 12, and 13. 50,51 Gives the program high memory address. The difference between the value stored here and in word 54,55 (when the program is running) is the amount of free memory currently available to the job. This value is available via the .SETTOP RT11 programmed request. 52 RT11 error byte which is set when certain programmed requests abort because of an error. PAGE 3 54,55 For "real" RT11 this is the address of the resident monitor. For the emulator it points at the first word of the impure area. 56,57 This word differs totally from RT11. It is set by the Linker /K switch and determines the memory size to use when loading the program. A value of 0 (default) causes the emulator to expand memory "enough to fit" the program. However, if many buffers are needed for Fortran I/O, for example, additional space can be requested by loading an additional value here (using $ODT.BAC is the easiest method). Note that LINK.SAV and MACRO.SAV as distributed with RSTS V7.0 have a 34 loaded here (28K) which is excessive for most systems. It is recommended that a 20 (16K words) be used for MACRO, LINK, and FORTRAN and more be used only for those rare applications that require it. See the SIZE command below for details. 250,252 Two-word trap vector used for memory management unit faults. Note that trap vector locations for traps to 4, traps to 10, and FPU/FIS traps are not mentioned. If a user program wishes to intercept these traps, an RT11 programmed request (.TRPSET and .SFPA) is used. The emulator itself intercepts these traps and routes them to the user specified address in the request. Note that not all trap conditions will be re-routed to user specified locations. In particular, multiple odd address traps, errors that clobber certain critical locations in low core or the impure area, etc. will cause the emulator to abort execution and print an error message. NOTE It is recommended that the RT11 runtime system be installed using the /NOLOGERR switch; otherwise benign programming errors will show up in your system error log as T0, T4, KT, etc. type of errors. There are several other special words in low core for RT11. By using ODT and pages 2-14 ff of APG one can satisfy his/her curiosity about these other locations. The exception is the region from 500-776 which contains file specification for chain operations, core common, and the user stack area. Whereas the other low core areas occupy "unused space" as far as RSTS is concerned, the area 500-776 has conflicting usage between RSTS and RT11. This conflict is resolved by some "magic" within the RT11 emulator. Before examining this "magic", it is necessary, however, to look at a job's impure area. 2.2 The Impure Area Since the emulator must be Read Only, a "scratch" area must be set up for each job running under its control. The space for this area is allocated above the user program and occupies almost 1K words of memory. This PAGE 4 accounts for why the maximum high address limit of an RT11 job is 154000 (27K) and why RT11 jobs, especially Fortran, always seem to be much larger than they Linked. In fact, the space addition could be almost 2K words. The emulator takes a program's high address from word 50 (assuming word 56 is 0), rounds up to the next multiple of 4000 (1K) and then inserts the impure area at this point, setting the first address of the impure area into word 54. For the Macro programmer this space may easily be reclaimed as a scratch data area. For Fortran, this space is used for I/O buffers and object-time format decoding. For Version 6C, the impure area is shoved against its low address boundary; for Version 7.0, it has been shoved against its high address limit, giving the programmer an incredible 50-60 extra bytes to play with. Certain offsets into the impure area are of no value to the programmer; they are simply scratch areas for the emulator. Other locations contain critically useful information for performing I/O and other activities. Ideally, a file containing the definition of these various offsets should be provided; however, source listings would also suffice. The following table defines some of these critical offsets. NOTE: THESE OFFSETS ARE FOR V7.0 AS DEDUCED FROM V6C LISTINGS. THERE ARE SIGNIFICANT CHANGES IN THESE DEFINITIONS BETWEEN V6C AND V7.0. TO THE BEST OF MY KNOWLEDGE THESE VALUES ARE CORRECT, BUT THEY MAY BE IN ERROR. Where the V6C offset differs from the V7.0 offsets, the V6C offset appears in parentheses following the description of the offset. 000000 PPN If non-zero, used as PPN for file oriented calls (.e.g., .LOOKUP, .ENTER, .DELETE, .CHAIN, etc.). For devices that accept a modifier word, the value stored here prior to a .WRITE is placed in location XRB+XRMOD prior to issuing a RSTS write EMT. For example, binary output to a terminal is performed by putting a 1 in this word prior to issuing a .WRITE. 000002 PROTEC If non-zero, the protection code to use with opens, etc. For .READ and .WRITE, this word is the low order word of the logical block number, used with offset 000012 for accessing large files. If these words are clear, the block number from the programmed request is used. (Note: This function is for version 7.0 only). 000004 MODE RSTS MODE value for file opens. 000006 CLUSTR File cluster size for opens. 000010 POSITN DCN for file placement (V7.0 only) 000012 -- MSB is high order byte of file size (large files) (V7.0 only) 000014 LOGTBL Start of 44 byte area which is copy of RSTS logical assignment table (normally in 734-776 for normal RSTS job image). (Starts at 10 for V6C). Order is: default ppn, default protection code, and assigned logicals. 000066 NOCTLC This word is used by the emulator for inhibiting CTRL/C's. PAGE 5 A value of 177777 means CTRL/C's will interrupt execution. A zero or positive value inhibits CTRL/C interrupts. The emulator sets this location to zero for certain critical sequences. While it is non-negative, each CTRL/C increments the value by one. When the emulator re-enables CTRL/C, any pending CTRL/C's are processed at that time. After setting this location to zero, it may be examined by the user program to know how many CTRL/C's have been typed. When a pending CTRL/C is processed, control is passed to a user CTRL/C routine, if one has been specified by use of the .SETCC EMT (see below). In the absence of a user CTRL/C routine, the program exits to the user's default runtime system. If it is RT11, a CONT or CCONT command will resume the program. A user program can safely set this value to zero to inhibit CTRL/C's; however, there is no way to inhibit the emulator from clearing the word at the end of various critical sequences. These sequences occur for the following programmed requests: .PURGE, .SRESET, .HRESET, .LOOKUP, .ENTER, .REOPEN, .CLOSE, and .SAVESTATUS. (offset 104 for V6C) 000202 CHNMAP 20 word block of pointers to the channel blocks. One per RT11 channel. A zero value means that the corresponding channel is not open. The word at offset CHNMAP+<2*X> points to the channel block for RT11 channel X. Only the low order 4 bits of an RT11 channel number are used. See note on channel mapping following the description of RT11 programmed requests. (offset 220 for V6C). 000242 CCLTAG This BYTE flags a CCL (i.e., CHAIN) entry to the program. Byte is zero for RUN command; equals 377 for CCL entry. (offset 260 for V6C) 001072 CHANNL 17 blocks (1 per RSTS channel) of 20 bytes each, containing for each open channel: a flag word, device name (RAD50), filename and extension (3 words RAD50), ppn, RSTS channel*2 on which this RT channel is open, and status word from RSTS open. Using the CHNMAP pointers to these blocks, and the contents of each block allows, for example, a way to find an empty channel for I/O from a Macro routine called from a Fortran program which already opened some files. Bits 1-4 of the flag word contain the low order four bits of the specified RT11 channel number, bit 6 is set if the file is open for output, and bit 15 is set if the channel is currently open. Other bits are used internally by the emulator. The information in these areas should not be changed directly by a program. Rather, based upon information read from these areas, appropriate RT11 requests (.ENTER or .LOOKUP) with a free channel can be issued. In this way only the emulator modifies these locations and serious errors are avoided. NOTE: The best procedure for allocating channels is to use the SYSLIB subroutines IGETC() and IFREEC() which use information from the Fortran OTS to find an unused RT11 channel number (see APG for details). (offset 1026 for V6C) PAGE 6 001454? DTBUFF A nice 510. word area unused unless you are using DECtape. This is a lot of space and can be safely used as long as no reference is made to DECtape. For example, we are currently planning to modify Fortran OTS so that object-time decoding routines use this space, rather than the space between the program and the impure area. The address for V7.0 is a guess based upon other offset changes. For V6C, the correct offset is 1410. The first 6 words of the impure area used for setting RSTS specific information for programmed requests involving file operations. These locations are "one-shot" in that they are cleared after each call which uses them. There are several other key locations in this area. However, each of them is more easily (and safely) accessed via an RT11 programmed request. Use of these and other offsets will be given in the examples which follow. 3.0 RT11 KMON Commands The following table lists all of the KMON commands supported by the emulator. They may be used whenever the RT11 "." prompt has been issued. This table is based upon information from V6C listings but appears to be the same for V7.0. Only the letters appearing capitalized need to be typed. "(same as Basic)" appearing after a description means that the command format and operation is identical to the same command when issued when Basic is the default runtime system, or in the case where Basic doesn't have such a command, the action is the same as the function of the same name performed by the $UTILTY program. ASsign Assign Logical name or device. (same as Basic) B/E/D The commands B, E, and D provide a simple ODT-like capability for examining locations in memory. "B " sets the base from which offsets in E and D commands are computed. Initially the base is 0. "E " prints the contents of location relative to the current base offset. "D " deposits into location relative to the current offset. Any address from 0 to 177777 is valid. However, addresses outside of your current job size (as determined by the SIze command) will give an error. It is possible to examine locations with in the impure area or the runtime system itself with these commands; however, it is not possible to modify either the impure area or runtime system with the D command. Use of these commands can help analyze simple errors in Macro programs. CCOntinue Continue a program detached after a CTRL/C interrupt. (same as Basic) CLEAN Clean a disk pack. (same as Basic) COntinue Continue a program after a CTRL/C interrupt. Note: CCO and CO may not always work, in which case the error "?Can't continue" will be issued. (same as Basic) PAGE 7 CLose Close all open channels. This performs a RSTS .CLOSE EMT on each open channel and correctly updates channel blocks in the impure area. DAte Prints the current date on the terminal. DEAssign Deassigns a logical name or device. (same as Basic) DISMount Dismounts a disk pack. (same as Basic) ERror Prints the RSTS error message associated with the last encountered error. This is extremely useful because Fortran, Macro, and Link will sometimes issue RT11 errors which could arise from any of several RSTS error conditions. This command prints the RSTS error message as returned by the FIP call with function code of 9. GEt Loads an executable (.SAV) file into memory but does not execute it. If no ppn is specified, the program is assumed to be in the user's current directory. The loading operation of a GEt differs from that of a RN or R command. In particular, certain low core areas are preserved rather than loaded from block 0 of the .SAV file. Moreover, a bit-map stored in locations 300-376 of block 0 is used for "scatterloading" the file if it comes from a random access device. The only documentation on the meaning of this bit-map that I have found is in the RT11 System Reference Manual for Version 2 RT11. GEt is particularly useful when ODT is compiled into a .SAV file. A subsequent STart command will begin execution at the address loaded in location 40 by the linker. STart will begin execution at the specified address. This means ODT can be linked in (without specifying O.ODT as a transfer address) and if it's needed, ODT can be entered by doing a GEt followed by a STart with equal to the value of O.ODT as shown in the Linker .MAP listing. INitialize Resets all RT11 conditions, excluding logical assignments, to the state they would be in when RT11 is first entered as the default runtime system. LIB The command "LIB [p,pn]" sets [p,pn] as the directory searched for an "R" command. The default is [1,2]. Note that this account is also scanned if a file lookup cannot find the specified file on the current directory. Typing LIB without a ppn disables the file lookup scanning. LOCK Lock a disk pack. (same as Basic) MOnitor Exits to the user's default runtime system. Primarily of value if an RT11 program "really bombs" leaving the user with a "." rather than a nice "Ready". However, the SWITCH CCL provides the same capability. MOUnt Mount a disk pack. (same as Basic) PAGE 8 PPN The command "PPN [p,pn]" sets the "search ppn". Whenever the emulator attempts to open a file for input and no ppn has been explicitly given in the filespec, the emulator first scans the current user directory for the file. If this fails, it searches the directory specified in the most recent PPN command. If this fails it searches the current library directory as set by the LIB command. If no PPN command has been given, or PPN search has been disabled by typing PPN without a number, only the user's directory and the library are searched. If LIB has been typed without a ppn, then only the user's current directory is searched. R Runs a program from the library account. That is, "R LINK" is the same as "RUN $LINK" assuming no LIB command has been typed. The program may be associated with any runtime system. Note: R, RN, RU, and RUN are four distinct commands; they are not simply abbreviations or variants of the same command. REenter Re-enters or restarts a program already in memory whose execution has halted. Bit 13 of the JSW must be set to allow a restart. If it is set, execution begins at the address located in word 40. All channel are reset (.RESET) unless the chain bit (bit 8) of the JSW is set. The emulator issues the message "?No restart" if restart is not possible. RN Loads a program from the user's current directory (if no ppn is specified) and begins execution. Program may be associated with any runtime system. Memory is automatically expanded to size computed by the emulator from the contents of word 54. RN and R commands are identical in operation, except for which directory each uses for searching for the program when no explicit ppn is specified. RU RU is exactly the same as a GEt followed by a STart. RUN This is NOT an emulator KMON command. It is processed by RSTS and has the same effect whether or not RT11 is the current default runtime system. SIze Set the size available for running a program. On entry to RT11, the size is set at 2K words. Typing SI sets the current size to K words; typing SI with no arguments, prints the current size. The job image is automatically expanded for R and RN commands. However, SIze must be used to insure enough memory before typing a GEt or RU command. The current size overrides size requests computed from .SAV files if the space computed is less than the current size. When linking large programs or doing large file copies using PIP.SAV, using SIze to specify a large memory size is very useful. (Note: the CCL switch /SI:, when used with an RT11 program, acts as if a SIze command were issued before the program is actually run.) STart Used to start a program after it has been loaded into memory with a GEt command. See GEt for details. PAGE 9 TIme Prints the current time of day in the system format. UNLOCk Unlock a disk pack. (same as Basic) VErsion Prints the current emulator version number. Information in this document was produced for "RT11 SJ V3-03; RSTS 7.0". Note that there is no BYE command supported by the emulator. This can be remedied by making BYE a CCL for the LOGOUT program running under the system's default runtime system. 4.0 RT11 Programmed Requests All of the programmed requests (monitor calls) described in the APG for "real" RT11 may be issued under the emulator. The action of the emulator to a particular request will fall into one of three categories. 1. The request is ignored because it is meaningless when running on RSTS. All F/B or XM requests fall into this category. Issuing such a request returns control immediately to the user program with nothing having been done and no error being reported. 2. The request is interpreted in a "RSTS-like" manner. Almost all file oriented requests fall into this category. Typically the emulator maintains total compatibility with what real RT11 would expect, but then adds some "magic" to incorporate RSTS specific features. The .CSISPC and .CSIGEN are examples. These requests may be used exactly as documented in the APG; in addition, though, RSTS file specifications are also handled. 3. The request is handled without detectable difference from real RT11. These include most of the non-file related facilities such as sleeping, getting time and date information, printing information on the terminal, etc. The following is a list of all programmed requests from Table 2-1 of the APG which would operate in a real RT11 SJ environment. The comments following them explain their action under RSTS. No attempt is made to reproduce the information in the APG. The comment "No change" means that no difference in operation from that described in the APG is detectable. "Ignored" means the emulator immediately returns control to the user program without any action having been performed. "One-shot" means that the first words of the impure area are used for setting RSTS specific information into the FIRQB for the associated monitor call. This process is as described for the .SETFQB EMT in the next section. .CLOSE No change. .DELETE Any channel number specified is ignored, so that no error is possible with this request. (One-shot) .ENTER Real RT11 creates a temporary file as a result of this request which is made permanent when the file is closed. For V6C the PAGE 10 emulator creates a RSTS file by the name "TMxnnn.TMP" where "x" corresponds to the RT11 channel on which the file is open, and nnn is the job number. When the file is properly closed, the emulator will rename the file to that specified in the .ENTER request. If a .PURGE or .HRESET is issued the temporary file is killed. More importantly, since the rename is never done, any file by the same name will still be intact. Serious program aborts may leave the TMxnnn.TMP file on the user's directory. For V7.0 this process is simplified by using the given filename and doing a "tentative open". The effect is the same as the above mechanism. If the length is supplied which is greater than zero, the file is pre-extended to this size. An argument of 0 or -1 means that the file grows dynamically as it is written. (One-shot) .LOOKUP No change. (One-shot) .PURGE No change. .RENAME Channel number is ignored. (One-shot) .REOPEN Operation basically as documented in the APG. However, the 5-word blocks setup by .SAVESTATUS have any specified ppn stored as well as device, filename, and extension. "One-shot" values may also be specified. .SAVESTATUS 5-Word block saved contains (in order): device, filename, extension (all in standard RT11 RAD50 format), and ppn. .PRINT No change. .READ (Also .READC and .READW). These work as documented without change, except that control is never returned to the user program until the I/O is completed. This is a result of all I/O being synchronous on RSTS. However, .READC will transfer to a completion routine as documented when the I/O is complete. See also the discussion of one-shot offsets into impure area for specifying RSTS specific information. .SPFUN This apparently works as documented for RT11 magtape by translating RT11 codes to RSTS equivalent. For other devices it appears to operate as does RSTS .SPEC. Completion routines are supported. .TTYIN (also .TTINR) Most of the discussion in the APG applies completely. However, treatment of CTRL/C and CTRL/Z differs (see .SETCC and .SCCA below), none of the special RT11 control characters is recognized, and because of synchronous I/O on RSTS, both requests operate identically. Note in particular that single character input (ODT mode) is fully supported as documented in the APG. Bits in the JSW affect the operation of this request. .TTYOUT (also TTOUTR) No change, except that synchronous I/O implies the two operate identically. .PRINT should always be preferred PAGE 11 to this form of output. Even in a tight loop using all available cpu time on an 11/45, this call cannot produce output much faster than 120 cps or so. .WRITE (also .WRITC and .WRITW) See comments under .READ. .CDFN Always produces error (returns to user program with carry bit set). Although RSTS maps all RT11 channels into RSTS channels so that channels other than 1 to 17 are possible, the emulator will not permit more than 17 channels to be defined. .CHAIN When chaining from one RT11 program to another, and the second program is small enough to fit in the current job size, this request operates exactly as documented, including the treatment of core common. However, modification is required when chaining to a larger program or to a program which runs under a different runtime system. See example below. (One-shot) .CSIGEN Works as documented, even for RSTS type filespecs. However, indirect command files are not supported by this command. Since under the emulator device handlers are always loaded, the area for "devspc" is not required. .CSISPC This also works as documented in the APG. However, the treatment of RSTS filespecs involves a little magic. The information returned in the RT11 "outspc" area is exactly as for real RT11. The emulator saves any RSTS specific information about each file in the job's read/write area. Special EMT's are provided for restoring the RSTS information before doing file opens or running programs. These EMT's are described below. Note that no indirect command file capability is supported by the emulator for this or any other programmed request. .DATE No change. Note: format of date is RT11, not RSTS. .DSTATUS Everything meaningful to RSTS is returned as documented. Handler size is always zero; load address is always 160000; device size is always 0. .EXIT Exits to user's default run-time system. It is not possible to pass information to RT11 KMON through core common as documented in the APG. .FETCH Since all handlers are always resident under the emulator, this request does nothing but check that the device specified is valid. .GTIM No change. Note: Format returned is RT11, not RSTS. .GTJB Only the current high limit is returned. Other words returned as zero. .GTLIN Works as documented, except that indirect command files are not supported under the emulator. PAGE 12 .GVAL Returns the contents of "offse" from the beginning of the impure area. The instructions "MOV @#54,R0 ADD #OFFSE,R0" produce the same effect more efficiently. .HERR Ignored. .HRESET Does a RSTS reset of all open channels, updating the channel blocks in the impure area, and deleting any temporary files (i.e, those created with .ENTER which have not yet been closed). .INTEN This is not an EMT; any attempt to use it will have totally unpredictable results. .LOCK Ignored. .MFPS (see .INTEN) .MRKT Ignored. .MTPS (see .INTEN) .QSET Ignored. .RCTRLO No change. .RELEAS Ignored. .SCCA This request operates VERY differently from real RT11. It has absolutely no effect on the typing of a CTRL/C. Rather, when called with any non-zero value for "addr", subsequent CTRL/Z's typed at the terminal are translated to a 003 and passed like any other character to the program (through .TTYIN or .GTLIN). To inhibit CTRL/C's, see the .SETCC EMT below. .SERR Ignored. .SETTOP This command simply returns to the user the amount of space between the current program high limit (as stored in word 50) and the start of the impure area (as stored in word 54). Expansion of a program's size while it is running requires the copying of the impure area to give the program space. The .GETCOR EMT must be used for this. .SFPA No change. Note, however, that use of this request while running a Fortran program could cause serious problems, since Fortran has its own FPU/FIS exception handling routines and expects to always find the FPU status as it has set it. The routine whose address is specified in this request will be entered for both FPU and FIS exceptions. .SRESET Identical to .HRESET .SYNCH (See .INTEN) PAGE 13 .TRPSET No change, except that the emulator will not pass control to the specified routine if certain critical locations in low core or the impure area have been destroyed. .TWAIT Does a RSTS sleep for the number of seconds requested. The emulator always assume 60 ticks per second. (Note: this is the only FB/XM request that the emulator supports). .UNLOCK Ignored. .WAIT Program simply checks to see if the channel is open. For V6C, the EMT returns with the carry bit set if the channel is not currently open. For V7.0, this features has (apparently?) been removed. The above is the complete list of "standard" RT11 programmed requests. supported by the emulator. As mentioned above, requests not in this list are ignored. The following additional notes on this list may be of help. 1. The emulator "maps" RT11 channel numbers to RSTS channel numbers in such a way that only the low order 4 bits of the RT11 channel number are preserved. Thus any RT11 channel number from 0 to 377 may be used, but care must be used since 7, 27, 67, etc all map to the same channel number. The emulator will open a file for each such number, but the channel mapping area of the impure area will be corrupted and only the last channel will be accessable. 2. Magtape, DECtape, and "funny devices" may require some experimentation to completely determine how I/O on them operates. 3. Mixing native RSTS I/O and RT11 I/O could produce problems if care is not taken with the assignment of channels. 4. The above list corresponds to the names of macros defined in RT11 V3 SYSMAC.SML. The corresponding Fortran callable subroutines in RT11 SYSLIB.OBJ function the same. Currently neither of these is distributed with RSTS (hopefully that may change very soon). However, a complete listing of SYSMAC is contained in an appendix in the APG. 5.0 "Magic" EMTs for the Emulator In addition to the above RT11 programmed requests, the emulator supports 7 (8 for V7.0) additional EMTs for performing RSTS specific actions in an RT11 environment. Complete documentation on these EMTs follows. PAGE 14 5.1 .SETFQB - EMT 360 When processing a .CSISPC programmed request, RSTS specific information about each filespec found is stored in the impure area. The .SETFQB is used to retrieve this information. To use .SETFQB, move the address of the file descriptor block of the desired file into R0 and issue the EMT. When control returns to the user program, the user's FIRQB and XRB will be as they were after the selected filespec was scanned by RSTS (using .FSS). The first six (five for V6C) words of the impure area are cleared by this EMT. No errors are possible and registers are unchanged by the call. It is critical that the address in R0 is in the same "outspc" area as passed to .CSIGEN. For example, given the request .CSISPC #OUT,#EXT,#CMD the following would setup the FIRQB and XRB for the information found for the first input file in the string #CMD. MOV #OUT+<3*5*2>,R0 EMT 360 This EMT is used within the emulator itself for processing filename information in the following calls: .LOOKUP, .ENTER, .RENAME, and .DELETE. If the address in R0 does not match any address in the emulator's internal table, then the FIRQB/XRB are set up for the specified devblk using any information that is saved in the "one-shot" area. Note that non-zero values in the first 6 (5 for V6C) words of the impure area override specifications found in the string. 5.2 .DATIM - EMT 361 This call returns a date or time string in Basic-Plus DATE$() or TIME$() format. To use this EMT, put the location to return the string into R0. If a date is needed, load the argument into loaction XRB; if a time is needed, clear XRB and load the time into XRB+2. The date and time must be in RSTS internal format, as returned by the RSTS .DATE EMT. 5.3 .SETCC - EMT 362 This routine is used to define a user CTRL/C handling routine. If CTRL/C's are temporarily disabled (non-negative value in NOCTLC), this routine will be entered when CTRL/C is enabled. The emulator disables CTRL/C trapping before passing control to the user routine. To use this EMT, place the address of the CTRL/C routine into R0 and issue the EMT. When control is passed to this routine, it is the user's responsibility to re-enable CTRL/C trapping and to reset CTRL/O (using PAGE 15 .RCTRLO). Exit from the routine must be by an RTI instruction. An example below shows the operation of this routine from Fortran. This EMT can be safely and effectively used with the method discussed above for totally disabling CTRL/C's by placing a non-negative value into NOCTLC. 5.4 .DORUN - EMT 363 This EMT is used to run a program under another runtime system. It must be used rather than a RSTS .RUN EMT, since the emulator must restore parts of low core before issuing the RSTS .RUN. To use this EMT, pass the address of an RT11-style parameter block in R0. This block contains five words: device, filename (2), extension (all in RAD50), and line number. The first four words are as returned by .CSISPC. If the address passed is that used in a preceding .CSISPC call, all of the RSTS information from the filespec will be loaded into the FIRQB for the RSTS .RUN call. Values in the "one-shot" area take precedence over values found in the string. The line number is loaded into FIRQB+FQNENT. Errors for this call are the same as for the RSTS .RUN EMT. An example showing how to use this call and .CHAIN for "chaining" operations is shown below. 5.5 .PERR - EMT 364 This EMT prints a RSTS error message corresponding to a RSTS error code on the user terminal. To use this EMT, load the error code into R0 and issue the EMT. No CR/LF is appended to the error message. 5.6 .DOFSS - EMT 365 This EMT performs a RSTS .FSS file string scan. It must be used rather than .FSS, since the emulator has moved the location of user logical device names from the top of low core into the impure area. To use this EMT, load the adress of the string to scan (which must be in ASCIZ format) into R0 and issue the EMT. On return, the user's FIRQB and XRB will be set up as per a RSTS .FSS EMT. 5.7 .GETCOR - EMT 366 This EMT is used to dynamically expand the size of a user job image. It must be used rather than a RSTS .CORE EMT, since the emulator must move the impure area as well as expand the job size. To use this EMT, put the new job size (in K words) into R0 and issue the EMT. If the required expansion is not possible, the carry bit will be set PAGE 16 on return from the EMT; otherwise, the size change has been successful and word 54 will now point to the new location for the start of the impure area. This EMT must be issued prior to a .CHAIN to a program which requires more core than the current job size. An example below demonstrates the use of this EMT. 5.8 .DOCCL - EMT 367 (Version 7.0 only) This EMT is used to execute a CCL command. It must be used in place of the RSTS .CCL command in order to allow the emulator to properly restore low core. To use this EMT, load the address of the CCL command string (in ASCIZ format) into R0. Control returns inline, only if the call fails. 6.0 Some examples. The following contain programs showing how to use some of the above above information. 6.1 CTRL/C trapping from Fortran. The following is a listing of a Fortran program that loops until a CTRL/C is typed, at which time control is passed to the subroutine CCTRAP. The Macro routine CTRLC is used to enable/disable the trapping. c program to play with ctrl/c trapping from fortran. c data a,b,c,d,e/1e-10,1e-8,1e-6,1e-4,1e-2/ external cctrap call setcc(cctrap) c TYPE 800 800 FORMAT(/1X) I=0 10 i=i+1 if(mod(i,1000).ne.0) goto 10 x=i type *, x,x*x,x**3,sqrt(x),x**(1/3) z=(((x*a+b)*x+c)*x+d)*x+e type *,i/1000,z if(i.ge.32000) i=0 goto 10 c end subroutine cctrap byte answer type 900 accept 910, answer PAGE 17 if(answer.eq.'Y' .or. answer.eq.'y') call clrcc 900 format(/' a CTRL/C has been typed.... Clear CTRL/C? ',$) 910 format(a1) return end .enabl lc .title ctrlc ; routine to set ctrl/c traps. ; CALL SETCC(NAME) - defines NAME as ctrl/c trap routine. ; CALL CLRCC - disables ctrl/c trapping. ; NAME should be declared EXTERNAL in fortran routine. .mcall .rctrlo,.print,.exit setcc:: tst (r5)+ ;skip number of arguments mov @r5,name ;save address of routine to call if ctrl/c mov #cchit,r0 ;trap to cchit if ctrl/c. clr ccflag ;set to zero just in case emt 362 ; rts pc clrcc:: clr r0 ;clearing location usercc in r/w area emt 362 ;disables ctrl/c trapping. rts pc cchit:: .rctrlo ;reset crtl/o from crtl/c tst ccflag ;cannot process nested ctrl/c's. bne twocc ;ctrl/c typed in ctrl/c routine. inc ccflag ;indicate ctrl/c currently being processed. mov r0,-(sp) ;must save all registers, don't mov r1,-(sp) ;know what we were doing. mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) mov r5,-(sp) mov sp,stack ;finally save stack pointer. mov #cchit,r0 ;re-enable ctrl/c trap emt 362 mov #retcc,-(sp) ;fake stack so return from name returns jmp @name ;to retcc to restore registers and the like. retcc:: mov stack,sp ;reset stack (who knows what fortran did to it) mov (sp)+,r5 mov (sp)+,r4 mov (sp)+,r3 mov (sp)+,r2 mov (sp)+,r1 mov (sp)+,r0 clr ccflag ;all done processing ctrl/c. rti twocc: .print #cctext PAGE 18 .exit stack: .word 0 name: .word retcc ccflag: .word 0 cctext: .asciz '?Second CTRL/C typed - program halts.' .end Ready RUN CC 1000.000 1000000. 1.0000000E+09 31.62278 1.000000 1 111.1100 2000.000 4000000. 8.0000000E+09 44.72136 1.000000 2 1684.210 3000.000 9000000. 2.7000001E+10 54.77225 1.000000 3 8379.311 4000.000 1.6000000E+07 6.4000000E+10 63.24556 1.000000 4 26256.41 5000.000 2.5000000E+07 1.2500000E+11 70.71068 1.000000 5 63775.51 6000.000 3.6000000E+07 2.1600000E+11 77.45967 1.000000 6 1^C ?Err 26 in routine "CCTRAP" line 3 from routine ".MAIN." line 11 Ready This error results from the CTRL/C being typed while Fortran I/O was in progress, causing "recursive I/O" when the TYPE in CCTRAP was executed. The solution to this problem is to have the CTRL/C routine reset critical values within the Fortran OTS, so that Fortran thinks all I/O is complete. Another alternative is to disable CTRL/C during printing parts of the program, and to honor them only when all I/O is complete. Note, however, that even here, the simple approach shown will work frequently. RUN CC 1000.000 1000000. 1.0000000E+09 31.62278 1.000000 1 111.1100 2000.000 4000000. 8.0000000E+09 44.72136 1.000000 2 1684.210 3000.000 9000000. ^C a CTRL/C has been typed.... Clear CTRL/C? 7000.000 4.9000000E+07 3.4299999E+11 83.66601 1.000000 PAGE 19 7 243579.7 8000.000 6.4000000E+07 5.1200000E+11 89.44272 1.000000 8 414784.8 9000.000 8.1000000E+07 7.2899999E+11 94.86833 1.000000 9 663472.0 10000.00 1.0000000E+08 1.0000000E+12 100.0000 1.000000 10 1010101. 11000.00 1.2100000E+08 1.3310000E+12 104.8809 1.000000 11 1477532. 12000.00 1.4400000E+08 1.7280000E+12 109.5445 1.000000 12 2091026. 13000.00 1.6900000E+08 2.1970000E+12 114.0175 1.000000 13 2878241. 14000.00 1.9600000E+0^C a CTRL/C has been typed.... Clear CTRL/C? Y 15000.00 2.2500000E+08 3.3749999E+12 122.4745 1.000000 15 5096477. 16000.00 2.5600000E+08 4.0960000E+12 126.4911 1.000000 16 6594818. 17000.00 2.8900000E+08 4.9130001E+12 130.3840 1.000000 17 8401521. 18000.00 3.2400000E+08 5.8319999E+12 134.1641 1.000000 18 1.0556246E+07 19000.00 3.6100000E+08 6.8589999E+12 137.8405 1.000000 19 1.3101053E+07 20000.00 4.0000000E+08 8.0000000E+12 141.4214 1.000000 20 1.6080402E+07 21000.00 4.4100000E+08 9.2610002E+12 144.9138 1.000000 21 1.9541152E+07 22000.00 4.8400000E+08 1.0648000E+13 148.3240 1.000000 6.2 Chaining between programs under different runtime systems. The following examples show various combinations of chaining between Fortran and Basic. Several points are worth noting. 1. Passing of core common depends upon the runtime system from which we are leaving and to which we are going. 2. Chaining between two RT11 programs does not automatically expand the job image to the size needed for the second program. 3. Chains coming into RT11 from another runtime system do not preserve core common (since the location under RT11 differs from that used by other RSTS runtime systems). However, if offset FQNENT of the FIRQB has bit 13 set on entry, RT11 will copy core common into the job's terminal input buffer area (in the impure area) before passing control to the user job. A subsequent read from the terminal can recover this information. 4. For programs which are not RT11, .DORUN rather than .CHAIN must be PAGE 20 used for chaining. C PROGRAM TO CHAIN TO BASIC OR RT11 PROGRAM USING BCHAIN.MAC C BYTE CORCOM(127) INTEGER*2 ISWIT(4) INTEGER*2 IOUT(39) INTEGER*2 IEXT(4) C DATA IEXT/3RSAV,3*0/ DATA ISWIT/'K ',3*0/ C TYPE 910 ACCEPT 810, NC,CORCOM 910 FORMAT(' ENTER CORE COMMON STRING'/' >',$) 810 FORMAT(Q,127A1) 100 TYPE 900 900 FORMAT(' PROGRAM TO CHAIN TO? ',$) IRET=ICSI(IOUT,IEXT,,ISWIT,1) IF(IRET.EQ.0) GOTO 200 !ALL IS OK TYPE *,IRET GOTO (110,120,130),IRET 110 TYPE 901 GOTO 100 120 TYPE 902 GOTO 100 130 TYPE 903 GOTO 100 C 901 FORMAT(' ?Illegal command line') 902 FORMAT(' ?Illegal device') 903 FORMAT(' ?Illegal switch - only /K:# allowed') C 200 IF(ISWIT(2).EQ.0) ISWIT(4)=0 !NO /K:# FOUND IF(IOUT(19).NE.IEXT(1)) ISWIT(4)=-1 C C CALL BCHAIN(IOUT(16),CORCOM,NC,ISWIT(4)) STOP 'CHAIN FAILED' END The subroutine ICSI() in the above is from RT11 SYSLIB and is described completely in the APG. The first argument is the "outspc" area from a .CSISPC programmed request. By using this call, all necessary RSTS information can be recovered in BCHAIN() by using the .SETFQB EMT. .TITLE BCHAIN ; FORTRAN CALLABLE ROUTINE FOR CHAINING BETWEEN PROGRAMS IN ; SAME OR DIFFERENT RUN-TIME SYSTEMS. ; ; CALL BCHAIN(PROG,CORCOM,NCHAR,CORSIZ) ; PROG - FILE TO RUN IN CSISPC OUTPUT FORMAT. ; CORCOM - BYTE ARRAY TO PASS AS CORE COMMON PAGE 21 ; NCHAR - NUMBER OF CHARACTERS IN CORCOM ; CORSIZ - INTEGER*2 <0 IF PROG NOT RT11 .SAV FILE ; =0 IF CURRENT SIZE OK ; >0 EXPAND TO CORSIZ BEFORE ; DOING RT11 CHAIN. .MCALL .PRINT,.CHAIN .SETFQB = EMT+360 .DORUN = EMT+363 .PERR = EMT+364 .GETCOR = EMT+366 FIRQB = 402 FQPPN = 6 PROG = 2 CORCOM = 4 NCHAR = 6 CORSIZ = 10 SPACES = 40+<400*40> ;TWO ASCII SPACES BCHAIN:: TST @CORSIZ(R5) ;WHAT KIND OF CHAIN? BLT DORUN ;<0 MEANS WE MUST "RUN" NOT "CHAIN" BEQ CHAIN ;=0 MEANS CHAIN WITH CURRENT CORE SIZE. ;MUST NOW EXPAND BEFORE CHAINING. MOV @CORSIZ(R5),R0 ;SIZE REQUESTED FOR EXPAND. .GETCOR ;PREPARE FOR FAILURE IF EMT BOMBS. BCS TOOBIG ;CARRY BIT SET IF ERROR IN EMT CHAIN: MOV #500,R1 ;POINT TO PARAMETER AREA MOV PROG(R5),R0 ;GET ADDRESS OF NAME OF PROG .SETFQB ;RECOVER A PPN, IF ANY IN ORIGINAL MOV @#FIRQB+FQPPN,@54 ;LOAD PPN INTO ONE-SHOT AREA MOV (R0)+,(R1)+ ;MOVE IN NAME OF CHAINEE MOV (R0)+,(R1)+ MOV (R0)+,(R1)+ MOV (R0)+,(R1)+ CALL PUTCC ;NOW INSERT CORCOM ARRAY .CHAIN ; .EXIT ;CHAIN WILL NEVER RETURN, EVEN IF FAILURE. DORUN: MOVB @NCHAR(R5),@#460 ;NUMBER OF CHAR IN CORE COMMON MOV #461,R1 ;BASIC'S CORE COMMON IS AT 460 CALL PUTCC MOV PROG(R5),R0 ;ADDRESS OF RT11 TYPE FILEBLOCK .SETFQB ;RECOVER A PPN, IF ANY IN ORIGINAL MOV @#FIRQB+FQPPN,@54 ;LOAD PPN INTO ONE-SHOT AREA MOV #8192.,4*2(R0) ;LINE NUMBER - VERSION 7.0 PAGE 22 .DORUN ;DO A RSTS .RUN AFTER UNDOING RT11 STUFF MOVB @#FIRQB,R0 ;GET THE RETURNED RSTS ERROR CODE. .PERR ;PRINT THE RSTS ERROR. CLR R0 .PRINT ;ADD THE CR/LF RETURN PUTCC: MOV CORCOM(R5),R2 MOV @NCHAR(R5),R3 1$: MOVB (R2)+,(R1)+ SOB R3,1$ RETURN TOOBIG: .PRINT #NOCORE RETURN NOCORE: .ASCIZ '?CORE REQUEST TOO LARGE' .END The following Fortran program uses a Macro subroutine for retrieving core common information. This approach to reading core common will only work if the program doing the chaining is also running under RT11. C TRT11 - TARGET PROGRAM FOR CHAINS FROM RT11. C TARGET PROGRAM FOR CHAIN DEMOS. THIS VERSION SHOWS C HOW CORE COMMON IS PASSED WHEN CHAIN IS FROM RT11. C BYTE CORCOM(127) REAL X(2000) !DUMMY ARRAY TO MAKE US BIG. C CALL GETCC(ICHAIN,CORCOM,127) C IF(ICHAIN.LT.0) TYPE 900 IF(ICHAIN.EQ.0) TYPE 910 C TYPE 920, (CORCOM(I),I=1,127) STOP C 900 FORMAT(' WE WERE CHAINED TO. CORE COMMON WAS:'/) 910 FORMAT(' WE WERE RUN - CORE COMMON SHOULD BE EMPTY'/) 920 FORMAT(1X,10I5) END .TITLE GETCC ; CALL GETCC(IFLAG,CORCOM,NBYTES) ; - RETURNS IFLAG=-1 IF CHAIN BIT SET; IFLAG=0 IF CLEAR ; - CORCOM GET NBYTES BYTES STARTING AT LOCATION 510 ; SIMILAR TO RT11 SYSLIB PROGRAM "RCHAIN" IFLAG = 2 PAGE 23 CORCOM = 4 NBYTES = 6 JSW = 44 CBIT = 400 COMMON = 510 GETCC:: CLR @IFLAG(R5) ;ASSUME A RUN ENTRY BIT #CBIT,@#JSW ;IS THE CHAIN BIT SET? BEQ 10$ ;NO, THEN LEAVE FLAG = 0 COM @IFLAG(R5) ;IFLAG=-1 FOR CHAIN ENTRY 10$: MOV @NBYTES(R5),R0 ;NUMBER OF BYTES TO MOVE. MOV #COMMON,R1 ;RT11 CORE COMMON AREA. MOV CORCOM(R5),R2 ;WHERE FORTRAN PROGRAM WANTS IT 20$: MOVB (R1)+,(R2)+ ;AND COPY IT OVER SOB R0,20$ RETURN .END RUN CH ENTER CORE COMMON STRING >ABCDEF PROGRAM TO CHAIN TO? *TRT11.SAV ?Maximum memory exceeded Ready The above example shows that RT11 will not automatically expand core on a chain operation. In the following we force a call of .GETCOR before the chain. RUN CH ENTER CORE COMMON STRING >THIS TIME IT WILL WORK PROGRAM TO CHAIN TO? *TRT11.SAV/K:12. WE WERE CHAINED TO. CORE COMMON WAS: 84 72 73 83 32 84 73 77 69 32 73 84 32 87 73 76 76 32 87 79 82 75 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 54 46 4 0 18 STOP -- Ready RUN TRT11 PAGE 24 WE WERE RUN - CORE COMMON SHOULD BE EMPTY 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 STOP -- The following is a Basic program that shows the effect on line numbers when chaining to basic. Note that core common comes through fine. 10 PRINT 'ENTERED AT THE BEGINING' 20 GOTO 10000 8192 PRINT 'ENTERED AT 8192' 10000 PRINT 'CORE COMMON IS:' 10010 PRINT SYS(CHR$(7)) 32767 END RUN CH ENTER CORE COMMON STRING >THIS TIME LET'S GO TO A BASIC PROGRAM PROGRAM TO CHAIN TO? *X.BAC ENTERED AT 8192 CORE COMMON IS: THIS TIME LET'S GO TO A BASIC PROGRAM As a final example of chaining, the following chains to RT11 from BASIC. By inserting 8192. in the line number field, RT11 copies core common into the terminal input buffer, so that simple read statements within the program can access it. If the program doing the chaining is an RT11 program, the chain bit in the JSW will be set. If a non-RT11 program (e.g., BASIC) program chained, the CCLTAG byte in the impure area is set to 377 (the JSW cannot be used in this case). Testing this bit or byte permits the conditional execution of special code for chain or run entry. C TBASIC - TARGET PROGRAM OF CHAIN FROM BASIC. C TARGET PROGRAM FOR CHAIN DEMOS. THIS VERSION SHOWS C HOW CORE COMMON IS PASSED WHEN CHAIN IS FROM BASIC. C BYTE CORCOM(127) REAL X(2000) !DUMMY ARRAY TO MAKE US BIG. C ACCEPT 800, LEN,CORCOM PAGE 25 TYPE 900,(CORCOM(I),I=1,LEN) TYPE 910,LEN,(CORCOM(I),I=1,LEN) C C RT11 HAS ADDED <^Z> TO END OF CORE COMMON. C NEXT LINE SHOULD THEREFORE TRAP EOF ON READ. READ(5,800,END=100) LEN STOP 'NO CTRL/Z' 100 STOP 'CTRL/Z READ' C 800 FORMAT(Q,127A1) 900 FORMAT(1X,40A1) 910 FORMAT(' LENGTH=',I5/(1X,10I5)) END 10 !FBASIC - CHAINS TO FORTRAN PROGRAM WITH CORE COMMON. 20 DIM X(95) 30 PRINT 'CORE COMMON FOR ALL ASCII CODES' 40 INPUT LINE X$ \ X$=CVT$$(X$,4%) 50 GOTO 100 IF LEN(X$)>0 60 X(I)=31+I FOR I=1 TO 95 70 X(0)=95 80 CHANGE X TO X$ 90 ! 100 PRINT 'TARGET PROGRAM'; 110 INPUT LINE F$ \ F$=CVT$$(F$,4%) 120 I$=SYS(CHR$(8)+X$) 130 PRINT 'CHAINING...' 140 CHAIN F$ 8192 !8192 SET CHAIN ENTRY FLAG FOR RT11. 150 STOP 160 END Ready RUN FBASIC 02:50 PM 15-Apr-79 CORE COMMON FOR ALL ASCII CODES ? TARGET PROGRAM? TBASIC.SAV CHAINING... !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGH IJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOP QRSTUVWXYZ{|}~ LENGTH= 94 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 123 124 125 126 STOP -- CTRL/Z READ PAGE 26 Ready