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 the Linker /B switch). In addition to the by RSTS, a job running under RT11 contains a core image as described in pages 2-6 ff of the words in this region are: 1000 (or as specified in normal context save areas used remarkably complete RT11 low APG. Some of the important 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 a Job start address, program is run. 42,43 set i.e., where RT11 transfers control when Set by Linker /T switch or Macro .END psuedo. Initial job stack pointer. Normally equal to 1000 or the value by /B Linker switch. 44,45 RT11 JSW. Various bits enables lowercase input when was CHAINed to. Other bits the emulator are bits 6, 9, 50,51 the are important. set and BIT 8 stored is BIT 14 set if the program described in APG which are relevant to 12, and 13. Gives the program high memory address. value Notably, The difference between 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 abort RT11 error byte which is set when certain programmed requests because of an error. PAGE 3 54,55 For For "real" RT11 this is the address of the resident monitor. the emulator it points at the first word of the impure area. 56,57 /K This word differs totally from RT11. It is set by switch size and determines the memory the Linker 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 V7.0 have a 34 loaded here (28K) which as distributed with RSTS 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 5060 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 (.e.g., If non-zero, used as PPN for file oriented calls .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 etc. PROTEC If non-zero, the protection code to use For .READ and with opens, .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 (V7.0 -- MSB is high order byte of file size (large files) only) 000014 LOGTBL logical Start of 44 byte assignment table area which is copy of RSTS (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 CTRL/C's. This word is used by the emulator for inhibiting 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. 000202 per CHNMAP (offset 104 for V6C) 20 word block of pointers to the channel blocks. RT11 channel. A One zero value means that the corresponding channel is not open. The word at offset CHNMAP+<2*X> points the to the channel block for RT11 channel X. Only low order 4 bits of an RT11 channel number are used. See note on channel mapping following the description of RT11 programmed requests. 000242 CCLTAG program. (offset 220 for V6C). This BYTE flags a CCL (i.e., CHAIN) entry to Byte is zero for RUN command; the equals 377 for CCL entry. (offset 260 for V6C) 001072 CHANNL containing 17 blocks (1 per RSTS channel) of 20 bytes each, 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 currently open. bits emulator. The information in these if the channel is Other are used internally by the 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 DECtape. A nice 510. word area unused unless you are using 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. B/E/D for The commands B, E, and D provide a simple ODT-like capability examining locations in (same as Basic) memory. "B <addr>" sets the base from which offsets in E and D commands are computed. Initially the base is 0. "E <addr>" prints the contents of location <addr> relative to the current base offset. "D <addr> <value>" deposits <value> into location <addr> 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. as Basic) CLEAN Clean a disk pack. COntinue CO Continue a program after a CTRL/C interrupt. may not always (same as Basic) Note: CCO work, in which case the error "?Can't continue" will be issued. (same (same as Basic) and PAGE 7 CLose each Close all open channels. open channel This performs a RSTS .CLOSE EMT on and correctly updates channel blocks in the impure area. DAte Prints the current date on the terminal. DEAssign Deassigns a logical name or device. DISMount Dismounts a disk pack. ERror last Prints the RSTS encountered (same as Basic) error error. (same as Basic) message This is associated with the 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 execute Loads an executable (.SAV) file into memory but does not 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 address subsequent STart command will begin execution at the loaded in location 40 by the linker. STart <addr> 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 <addr> 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 searched The command "LIB [p,pn]" sets [p,pn] as for an "R" command. The default the is directory [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. MOnitor value Exits to the user's default runtime system. if an RT11 (same as Basic) program Primarily of "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 The command "PPN [p,pn]" sets the emulator attempts to "search ppn". Whenever 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 is Runs a program from the library account. the same That is, "R LINK" 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 is Loads a program from the user's current directory (if no specified) with and begins execution. ppn Program may be associated 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 RSTS This is NOT an emulator KMON command. and has the same effect whether It is or processed by not RT11 is the current default runtime system. SIze RT11, Set the size available for running a program. the size is set at 2K words. On entry to Typing SI <number> sets the current size to <number>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 with Used to start a program after it has been loaded into memory 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. VErsion this Prints the current emulator version number. (same as Basic) Information in 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; addition, though, RSTS file specifications are also handled. 3. real The request is handled without detectable difference in from 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 is Any channel number specified is ignored, so that possible with this request. .ENTER request error (One-shot) Real RT11 creates a temporary file as a result of this which the no is made permanent when the file is closed. For V6C 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 request. If a .PURGE or .HRESET is issued the .ENTER temporary file is killed. More importantly, since the rename is never done, any file by the same program may name will still be intact. Serious aborts 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. .PURGE No change. .RENAME Channel number is ignored. .REOPEN the Operation basically as documented in 5-word (One-shot) blocks setup by (One-shot) the .SAVESTATUS APG. have However, 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 without (Also .READC and .READW). change, except that These control work is as never documented 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 by This apparently translating works RT11 as documented for codes to RSTS equivalent. RT11 magtape For other devices it appears to operate as does RSTS .SPEC. Completion routines are supported. .TTYIN applies (also .TTINR) completely. Most of However, the discussion treatment in the APG 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 implies (also TTOUTR) No change, except that the two operate identically. preferred synchronous I/O .PRINT should always be 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 bit Always produces error (returns to user program with set). carry 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 second When chaining from one RT11 program to another, and the 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. .CSIGEN However, See example below. Works as documented, even for RSTS type indirect supported command files are not (One-shot) filespecs. by this command. Since under the emulator device handlers are always loaded, the area for "devspc" is not required. .CSISPC the This also works treatment of as RSTS documented filespecs in the involves APG. a However, 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 information EMT's are provided for restoring the RSTS 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 to Exits to user's default run-time system. It is not possible pass information to RT11 KMON through core common as documented in the APG. .FETCH this Since all handlers are always resident under the emulator, request does nothing but check that the device specified is valid. .GTIM No change. Note: Format returned is RT11, not RSTS. .GTJB returned Only the current high limit is returned. Other words as zero. .GTLIN not Works as documented, except that indirect command files are supported under the emulator. PAGE 12 .GVAL the Returns the contents of impure area. "offse" from the beginning The instructions "MOV @#54,R0 of ADD #OFFSE,R0" produce the same effect more efficiently. .HERR Ignored. .HRESET channel Does a RSTS reset of all open channels, blocks in the impure updating the area, and deleting any temporary files (i.e, those created with .ENTER which have not yet been closed). .INTEN totally This is not an EMT; any attempt to use it will have unpredictable results. .LOCK Ignored. .MFPS (see .INTEN) .MRKT Ignored. .MTPS (see .INTEN) .QSET Ignored. .RCTRLO No change. .RELEAS Ignored. .SCCA has This request operates VERY differently from real RT11. absolutely no effect on the typing of a CTRL/C. It 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 space This command simply returns to the user between the the amount of 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 while No change. Note, however, running Fortran program could cause serious problems, a that use of this request 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 be entered for both FPU and FIS exceptions. .SRESET Identical to .HRESET .SYNCH (See .INTEN) request will PAGE 13 .TRPSET to No change, except that the emulator will not pass control the specified routine if certain critical locations in low core or the impure area have been destroyed. .TWAIT The Does a RSTS sleep for the number emulator always assume of seconds 60 ticks per second. requested. (Note: this is the only FB/XM request that the emulator supports). .UNLOCK Ignored. .WAIT V6C, Program simply checks to see if the channel is open. the EMT returns For 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. numbers The emulator "maps" RT11 channel numbers to RSTS in such channel 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. care Mixing native RSTS I/O and RT11 I/O could produce problems if 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 for the first input file in the string #CMD. MOV EMT found #OUT+<3*5*2>,R0 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 nonzero 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 TIME$() format. DATE$() or 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. CR/LF is appended to the error message. No 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 information. 6.1 above 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 c program to play with ctrl/c trapping from fortran. 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 10 FORMAT(/1X) I=0 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 900 910 ; ; ; ; if(answer.eq.'Y' .or. answer.eq.'y') call clrcc format(/' a CTRL/C has been typed.... Clear CTRL/C? ',$) 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:: mov mov clr emt rts tst (r5)+ ;skip number of arguments @r5,name ;save address of routine to call if ctrl/c #cchit,r0 ;trap to cchit if ctrl/c. ccflag ;set to zero just in case 362 ; 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 mov mov mov mov stack,sp (sp)+,r5 (sp)+,r4 (sp)+,r3 (sp)+,r2 ;reset stack (who knows what fortran did to it) mov (sp)+,r1 mov (sp)+,r0 clr ccflag ;all done processing ctrl/c. rti twocc: .print #cctext PAGE 18 .exit stack: name: .word ccflag: cctext: .end .word 0 retcc .word 0 .asciz '?Second CTRL/C typed - program halts.' Ready RUN CC 1000.000 1000000. 1 111.1100 2000.000 4000000. 2 1684.210 3000.000 9000000. 3 8379.311 4000.000 1.6000000E+07 4 26256.41 5000.000 2.5000000E+07 5 63775.51 6000.000 3.6000000E+07 6 1^C ?Err 26 in routine "CCTRAP" line 3 from routine ".MAIN." line 11 1.0000000E+09 31.62278 1.000000 8.0000000E+09 44.72136 1.000000 2.7000001E+10 54.77225 1.000000 6.4000000E+10 63.24556 1.000000 1.2500000E+11 70.71068 1.000000 2.1600000E+11 77.45967 1.000000 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 111.1100 1.0000000E+09 31.62278 1.000000 2000.000 4000000. 2 1684.210 3000.000 9000000. 8.0000000E+09 44.72136 1.000000 a CTRL/C has been typed.... Clear CTRL/C? 7000.000 4.9000000E+07 3.4299999E+11 83.66601 1.000000 ^C PAGE 19 7 243579.7 8000.000 6.4000000E+07 8 414784.8 9000.000 8.1000000E+07 9 663472.0 10000.00 1.0000000E+08 10 1010101. 11000.00 1.2100000E+08 11 1477532. 12000.00 1.4400000E+08 12 2091026. 13000.00 1.6900000E+08 13 2878241. 14000.00 1.9600000E+0^C 5.1200000E+11 89.44272 1.000000 7.2899999E+11 94.86833 1.000000 1.0000000E+12 100.0000 1.000000 1.3310000E+12 104.8809 1.000000 1.7280000E+12 109.5445 1.000000 2.1970000E+12 114.0175 1.000000 122.4745 1.000000 126.4911 1.000000 130.3840 1.000000 134.1641 1.000000 137.8405 1.000000 141.4214 1.000000 144.9138 1.000000 148.3240 1.000000 a CTRL/C has been typed.... Clear CTRL/C? Y 15000.00 2.2500000E+08 3.3749999E+12 15 5096477. 16000.00 2.5600000E+08 4.0960000E+12 16 6594818. 17000.00 2.8900000E+08 4.9130001E+12 17 8401521. 18000.00 3.2400000E+08 5.8319999E+12 18 1.0556246E+07 19000.00 3.6100000E+08 6.8589999E+12 19 1.3101053E+07 20000.00 4.0000000E+08 8.0000000E+12 20 1.6080402E+07 21000.00 4.4100000E+08 9.2610002E+12 21 1.9541152E+07 22000.00 4.8400000E+08 1.0648000E+13 6.2 Chaining between programs under different runtime systems. The following examples show various combinations between Fortran and Basic. Several points are worth noting. 1. which of chaining Passing of core common depends upon the runtime system from we are leaving and to which we are going. 2. expand Chaining between two RT11 programs does not automatically 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. be For programs which are not RT11, .DORUN rather than .CHAIN must PAGE 20 used for chaining. C C PROGRAM TO CHAIN TO BASIC OR RT11 PROGRAM USING BCHAIN.MAC 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 910 810 100 900 110 120 130 C 901 902 903 C 200 TYPE 910 ACCEPT 810, NC,CORCOM FORMAT(' ENTER CORE COMMON STRING'/' >',$) FORMAT(Q,127A1) TYPE 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 TYPE 901 GOTO 100 TYPE 902 GOTO 100 TYPE 903 GOTO 100 FORMAT(' ?Illegal command line') FORMAT(' ?Illegal device') FORMAT(' ?Illegal switch - only /K:# allowed') 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 .DORUN .PERR = .GETCOR FIRQB = FQPPN = = EMT+360 = EMT+363 EMT+364 = EMT+366 402 6 PROG = CORCOM NCHAR = CORSIZ SPACES 2 = 6 = = 4 10 40+<400*40> ;TWO ASCII SPACES BCHAIN:: TST BLT BEQ @CORSIZ(R5) ;WHAT KIND OF CHAIN? DORUN ;<0 MEANS WE MUST "RUN" NOT "CHAIN" 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 RETURN #NOCORE NOCORE: .END '?CORE REQUEST TOO LARGE' .ASCIZ 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 C C C TRT11 - TARGET PROGRAM FOR CHAINS FROM RT11. TARGET PROGRAM FOR CHAIN DEMOS. THIS VERSION SHOWS HOW CORE COMMON IS PASSED WHEN CHAIN IS FROM RT11. 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 910 920 FORMAT(' WE WERE CHAINED TO. CORE COMMON WAS:'/) FORMAT(' WE WERE RUN - CORE COMMON SHOULD BE EMPTY'/) 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 NBYTES JSW = CBIT = COMMON = = 44 400 = 4 6 GETCC:: BIT BEQ COM 10$: MOV MOV MOV 20$: MOVB SOB CLR @IFLAG(R5) ;ASSUME A RUN ENTRY #CBIT,@#JSW ;IS THE CHAIN BIT SET? 10$ ;NO, THEN LEAVE FLAG = 0 @IFLAG(R5) ;IFLAG=-1 FOR CHAIN ENTRY @NBYTES(R5),R0 ;NUMBER OF BYTES TO MOVE. #COMMON,R1 ;RT11 CORE COMMON AREA. CORCOM(R5),R2 ;WHERE FORTRAN PROGRAM WANTS IT (R1)+,(R2)+ ;AND COPY IT OVER R0,20$ 510 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 73 82 0 0 0 0 0 0 0 0 72 84 75 0 0 0 0 0 0 0 0 73 32 0 0 0 0 0 0 0 0 0 83 87 0 0 0 0 0 0 0 0 0 32 73 0 0 0 0 0 0 0 0 0 84 76 0 0 0 0 0 0 0 0 0 73 76 0 0 0 0 0 0 0 0 0 77 32 0 0 0 0 0 0 0 0 0 69 87 0 0 0 0 0 0 0 0 0 32 79 0 0 0 0 0 0 0 0 0 0 0 STOP -- 0 0 Ready RUN TRT11 0 54 0 46 0 4 0 0 0 18 0 0 0 PAGE 24 WE WERE RUN - CORE COMMON SHOULD BE EMPTY 0 0 0 0 0 0 0 0 0 0 0 0 0 STOP -- 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 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 20 8192 10000 10010 32767 PRINT 'ENTERED AT THE BEGINING' GOTO 10000 PRINT 'ENTERED AT 8192' PRINT 'CORE COMMON IS:' PRINT SYS(CHR$(7)) 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 C C TARGET PROGRAM FOR CHAIN DEMOS. THIS VERSION SHOWS HOW CORE COMMON IS PASSED WHEN CHAIN IS FROM BASIC. BYTE CORCOM(127) REAL X(2000) C ACCEPT 800, LEN,CORCOM !DUMMY ARRAY TO MAKE US BIG. PAGE 25 TYPE 900,(CORCOM(I),I=1,LEN) TYPE 910,LEN,(CORCOM(I),I=1,LEN) C C C 100 C 800 900 910 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 RT11 HAS ADDED <CR><LF><^Z> TO END OF CORE COMMON. NEXT LINE SHOULD THEREFORE TRAP EOF ON READ. READ(5,800,END=100) LEN STOP 'NO CTRL/Z' STOP 'CTRL/Z READ' FORMAT(Q,127A1) FORMAT(1X,40A1) FORMAT(' LENGTH=',I5/(1X,10I5)) END !FBASIC - CHAINS TO FORTRAN PROGRAM WITH CORE COMMON. DIM X(95) PRINT 'CORE COMMON <CR> FOR ALL ASCII CODES' INPUT LINE X$ \ X$=CVT$$(X$,4%) GOTO 100 IF LEN(X$)>0 X(I)=31+I FOR I=1 TO 95 X(0)=95 CHANGE X TO X$ ! PRINT 'TARGET PROGRAM'; INPUT LINE F$ \ F$=CVT$$(F$,4%) I$=SYS(CHR$(8)+X$) PRINT 'CHAINING...' CHAIN F$ 8192 !8192 SET CHAIN ENTRY FLAG FOR RT11. STOP END Ready RUN FBASIC 02:50 PM 15-Apr-79 CORE COMMON <CR> FOR ALL ASCII CODES ? TARGET PROGRAM? TBASIC.SAV CHAINING... !"#$%&'()*+,-./0123456789:;<=>[email protected] IJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOP QRSTUVWXYZ{|}~ LENGTH= 94 33 34 35 36 37 38 39 40 43 44 45 46 47 48 49 50 53 54 55 56 57 58 59 60 63 64 65 66 67 68 69 70 73 74 75 76 77 78 79 80 41 51 61 71 81 42 52 62 72 82 83 93 71 81 123 84 94 72 82 124 85 95 73 83 125 86 96 74 84 126 STOP -- CTRL/Z READ 87 65 75 85 88 66 76 86 89 67 77 87 90 68 78 88 91 69 79 89 92 70 80 90 PAGE 26 Ready
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
advertisement