.t ZEMU - The Z-Machine Emulator for the PDP-11. .chlo 3,2 .disable numbering chapter .stc .ell .ap .ast .f .fl substitute .ps 64,72,5,0,1 .iif ln03 ; $Elite .stc .fl substitute .stc .iif ln03 ; $Elite .stch 2,1,1,-1,-1 .fg 10 .c text ZEMU - A Z-Machine emulator for PDP-11. Written by Johnny Billquist RT-11 port by Megan Gentry Date: $$DATE .ecn .ch What is ZEMU ZEMU is a Z-Machine emulator. The Z-Machine was/is a virtual machine invented by Infocom Inc. in order to make their text-based interactive fiction games easily portable to many different home computers, which were popular in the 1980s. The Z-Machine defines an abstract instruction set which, when implemented, allows you to play all the Infocom games. Many different Z-Machine interepreters/emulators have been implemented, for a number of computers. Today, one of the more popular are called ZIP. ZEMU was somewhat inspired by ZIP, and ZIP was used as a debugging tool when ZEMU was written. .hl 1 Different game versions Infocom developed a lot of different games for the Z-Machine, and they spanned a decade. During this time Infocom did add some new features and changed some of the behaviour of the Z-Machine in order to cope with new game ideas they had. Thus there are a number of different versions of the Z-Machine. ZEMU can currently handle all version 1 through version 8 games. Version 6 games have graphics, which are a bit difficult on the PDP-11. It would maybe be possible to handle this using a VT340 or similar terminal, but that's a problem for another day. Version 6 games with graphics probably will not work as might be expected in ZEMU because of this, and also because very few version 6 games exist, which can be used as tests of the version 6 code. Version 7 and Version 8 games have more recently started to show up. These versions are not really from Infocom, but instead further developments to the Z-Machine done by the Internet community, which have adopted the Z-Machine for writing their own interactive fiction games. .hl 1 Unsupported things The Z-Machine has a few optional features, which aren't implemented in ZEMU. These are: .list .le SAVE__UNDO .le RESTORE__UNDO .end list The reason for this is that they can require a lot of memory, which ZEMU does not have. The Z-Machine also has the possibility to transcript all the commands to a log file or read those commands back. Neither of these features are currently supported by ZEMU, but they might be in the future. .hl 1 Memory requirements ZEMU itself takes approximately 8 Kword of memory. Different OS libraries and other stuff outside the control of ZEMU might take additional memory, but what is left free after this is used by ZEMU for the game. Three different types of memory are allocated by ZEMU. .list .le The game stack, which is of a fixed size. .le The dynamic game memory. This is the memory used by the game to store variables and other dynamic data, which can change during the play. The actual size of this region varies from game to game. .le The cache buffers. The rest of the memory, once the other two types of memory have been allocated, is used as a cache. If no cache can be allocated, the game cannot run. If very few pages of cache can be allocated, the game can run, but it might be slow on execution, since a lot of page faults resulting in disk I/O will occur. .end list .hl 1 The ZEMU cache system The Z-Machine has an address size for code which is 18 bits, or more. All of this code memory cannot be placed in physcial memory at once in a PDP-11. Instead the code is left on the disk, and a cache system is used. .hl 2 The disk-based cache model The memory is divided into a number of 512 byte .fn The page size can be other values as well .efn pages. When a memory reference in the Z-machine is done to a page, the cache is searched through, and if the page is already in there, the address is relocated to the physical address in the page. If the page isn't in the cache, it is fetched from disk. The page currently in the cache which hasn't been used for the longest time is replaced by the new page, and the address relocation is then done the same way as if the page was already in the cache. Each time a page is referred to, it's placed at the head of the list of referred pages, so that the LRU algorithm for the pages work. .hl 2 Memory based cache (RSX only) The memory based cache model is very similar to the disk based. The primary difference is that at startup, ZEMU attaches to a common region that holds the game data. When a page is fetched, it is instead a remapping of an address window to the correct part of the region. The page size is 8192 bytes (the same as an APR) and all free APRs are used to map to the region. Many users can map to the same region concurrently, if they play the same game, so it is possible to save memory on a system where much gaming is going on, while at the same time have increased speed. .hl 1 Terminals and fonts ZEMU can handle a number of different terminal types. Unknown terminals are regarded as hardcopy devices, and are used in a very straight forward way. However, VT52 and newer Digital terminals are used in a more advanced way. For version 3 games, a status line is shown at the top of the screen at all times, and on a VT100 or newer this line is shown in reverse. For VT100 and newer terminals, ZEMU also handles different text attributes, such as bold, underline and reverse. It also supports screen splitting, which some games use. For VT200 and newer terminals, ZEMU can also handle different fonts. Some games make use of a special font defined by Infocom. ZEMU takes advantage of the software definable font feature of the VT200 and newer to show this font on the terminal. The font is not defined by ZEMU however, but has to be loaded before running ZEMU. The actual look of this font is not defined in this document, but the font name expected is "w". In addition to all this, ZEMU can also take advantage of colors if the terminal supports that. .hl 1 Terminal function keys Some of the more advanced games also allows the player to use special keys for gaming. These have been partially implemented on the VT52 and VT100, and fully implemented on VT200 and newer terminals. The arrow keys work on all of these terminals, and the PFn keys and numeric keyboard always work. PF1-4 equals the F1 to F4 keys in the Z-Machine. On the VT200 and newer, the top row function keys F6-F12 also match the Z-Machine F6 to F12. In addition, a number of the other keys are also bound to different Z-Machine function keys. .hl 1 Where to get games Infocom Inc. was bought by Activision in the early '90s, and so all rights to the Infocom games were transferred to Activision. Activision retains all the rights to all Infocom games, even if they are not sold anymore. This means that they are not publicly available from anywhere. They might be found as products in stores, if you are lucky. The newer games have the game file available on the disk sold, which means you just have to transfer this game file to the PDP-11 in order to play the game under ZEMU. For older games, the game file might be embedded on the disk, and not easily extracted. A few games have been released to the public, as a marketing move to sell newer games. These are the classical ZORK I, II and III. They can be found on different FTP-sites on the internet. .hl 2 How to get the game file to your PDP-11 As this might differ depending on your operating system, it might be hard to answer. In general, you want to transfer the file without any modifications to it. As such, KERMIT or some ftp program (if you have TCP/IP) can be used in binary mode. .ch Building ZEMU ZEMU is distributed with a command file which should work on all operating systems, called ZEMU.CMD. This command file should be run. It will identify which operating system you run on, and ask the appropriate questions in order to build ZEMU. .hl 1 Different game options A number of options are selectable at the build time. Some are specific to certain operating systems, other are common to all versions. .hl 2 Default game directory (RSX only) When ZEMU is installed, it can be started with a game name as the argument on the command line. If no directory is given, the users current directory will be searched for the game file. If it isn't found, ZEMU will then look in the default directory for the game. .hl 2 Default save game name (RSX only) The save and restore file names can be complemented by this file specification. A suggested name in RSX-11M-PLUS is SYS_$LOGIN:.ZSG which means the save/restore file will be located in the home directory of the user, with the extension _.ZSG and the same file name as the game name. .hl 2 Default transcript file name (RSX only) The transcription is done to a file. This is the default file name. If the filename part is excluded, the game name is used. If the file type is excluded, .LOG is used. A suggested name in RSX-11M-PLUS is SYS_$LOGIN:.LOG. .hl 2 Cache size ZEMU will never allocate more cache than what is possible, so this only sets a possible upper limit on the number of pages allocated. If less memory is available it is not considered an error. It is also possible in some versions to override this value at runtime. .hl 2 Stack size ZEMU have a game stack. Normally, the default size is what you want to use. It is possible to change it if required. This should not be done lightly, though. .hl 2 Game id The Infocom Z-Machines have an identifier which can be read by the games which tells what hardware the game is running on. ZEMU normally identifies itself as a DECsystem-20 (1). Other values means some games will behave slightly different. It's probably not sensible to set other values, but it might be interesting. Some other values are: 2 - Apple II. 6 - IBM PC. .hl 2 Debug ZEMU can be built with debug code included. This is mainly usable while development or debugging of ZEMU, and should normally be left off, since it takes memory and extra time when included. .hl 2 Emulate EIS If the hardware on which ZEMU is expected to run don't have EIS this option should be selected. .hl 2 Emulate SOB The SOB instruction can be emulated, if required. .ch Porting ZEMU ZEMU has been written with the intent that it should be portable to other operating systems. A few requirements must be met, though. .list .le The architecture must be a PDP-11 (real or simulated). .le A MACRO-11 compatible compiler must be available. .end list All modules, except for one is shared between all different ports. The OS-specific parts are all located in one module, with a suggested name of Z_.MAC. When a port is started, it is suggested that an existing port is used as a reference. .hl 1 Debugging help Once the code is starting to get together, it is useful to implement ZMSG. Once ZMSG is implemented, you can spray .DBG statements in your code, at all places except in ZMSG (since .DBG itself uses ZMSG). _.DBG has several parameters, but the most important is the first two. Parameter one is a bitmask. Whenever ZEMU is compiled with debugging, every .DBG statement means that this bitmask is tested against an address called DBGFLG, and if the result is non-zero, the second argument (which should be a string) is printed. This string can contain special formatting codes. Any additional parameters to .DBG are placed in the string according to the formatting codes at those places. A number of bitmask bits have been reserved by ZEMU. The high four bits of a 16 bit word is however reserved for OS-dependant use and will never be used for anything else. A simpler function is .MSG, which does an unconditional printing. It's a MACRO that takes one or more arguments. The first argument is a format string, the same was as .DBG (see the RSX _$EDMSG function for information about the format string). Any additional arguments are used as input to the format string. Note that it's unadvisable to use any values relative to the stack pointer, since SP is modified by the macro. .hl 1 A few helping tips on the user interface Apart from getting the game to play from the user, it is often useful to accept a few switches as well. Perhaps the most important is a debug switch, which sets the DBGFLG address to a specific value. This can be used in combination with the .DBG instruction (see above) to conditionally print out certain information at ZEMU execution. .hl 1 Files ZEMU consists of a number of OS independent files, and one or more OS dependent files. All of these are compiled separately, and are linked together to form an executable program. .list " " .le ZEMU.MAC is the main program. .le ZINTER.MAC is the instruction interpreter. .le ZOPTAB.MAC holds the opcode tables. .le ZCTRL.MAC handles control instructions, such as jumps, tests and subroutines. .le ZALU.MAC handles arithmetic instructions. .le ZOBJ.MAC handles instructions that manages objects. .le ZIO.MAC handles I/O-related instructions. .le ZSCREE.MAC handles the screen for ZEMU. .le ZPIC.MAC handles the pictures in version 6 games. .le ZPRINT.MAC handles the printer for scripts. .le ZTEXT.MAC handles encoding/decoding of ZSCII text. .end list .hl 1 Functions There are a number of functions that needs to be implemented in order to get ZEMU running. However, only a subset is required to start playing and testing. Most of these functions are working outside of the ZEMU context, and cannot use any ZEMU functions to do any work. There are a few exceptions. Whenever an abrupt termination of the program is required, ABORT is the label to jump to, not ZEXIT. There are a few things that ZEMU might do, which the OS-dependant code does not know about, but which have to be reset. ABORT will reset these things before jumping to ZEXIT. The SAVE and RESTORE file handling functions might need to print texts (such as error messages). Since ZEMU has an advanced screen handling module, any code that is processed as a part of normal ZEMU operations cannot directly print to the screen, or the screen will be rather messed up. Instead, such code should call SCRTXT with a pointer to the text to print in R0. This text should be NUL-terminated. The full list of functions required are .list "o" .le ZINIT_* .le ZEXIT_* .le ZALLOC_* .le ZBLK_* .le ZMSG .le PUTTXT_* .le GETRND .le INPINI .le CHARNE_* .le INPEND .le SCROPN .le SCRBLK .le SCRCLO .le SAVOPN .le SAVBLK .le SAVCLO .le RESOPN .le RESBLK .le RESCLO .le GETSCL .le GETSLN .le GETSTP .le GETAVO .le GETSOF .le GETCOL .le CHESIZ_* .le CHEALL_* .le CHEUPD_* .end list Functions marked with a "_*" are the ones absolutely required to start testing. All other functions can be stubbed, returning just fixed values and doing nothing. The rest of this chapter will go through each function, describing what the function expects to do, how it is called, and what it should return. .hl 2 ZINIT ZINIT is the first function called, and it should set up all data and structures required by other functions. It should also somehow find out which game should be played and open the game file. Any user interaction in this function is solely the responsibility of ZINIT itself. There are no other functions that can be used from other modules. When ZINIT returns, ZEMU assumes that a game file has been selected, and that all other functions are callable. No values are returned. .hl 2 ZEXIT ZEXIT is the final function called. It is expected to clean up anything that needs to be cleaned. Close the game file, and reset anything that has been set for the user. It should the return to the operating system. It is not expected to return from where it was called. It does not have to care about other files, such as script files. Any files except for the game file is closed by the general code before ZEXIT is called. .hl 2 ZALLOC ZALLOC should allocate memory for the game to use. When called, R0 holds the number of bytes that are requested. On return, R0 should point to the address where the memory block allocated is located, and the carry should be clear. If ZALLOC fails to allocate the memory requested, it should instead return with the carry set. Once ZALLOC has returned a failure it will never be called again, so it might leave it's own internal information state in a mess without any penalty. ZALLOC should also return memory contigous with the previous call. This is because code depend on sequential calls will give a larger contigous memory space. .hl 2 ZBLK ZBLK shall read a block (or several) from the game file into memory. The arguments are passed at specific memory cells. These cells must be defined globally in the OS-dependant file, and are named .list .le BPAGE - the page to start reading from in the game file. Pages are numbered from 1 and up, and each page is 512 bytes. .le BADDR - the address in physical memory where the page is to be placed. .le BCNT - a byte count, telling how many bytes to read. This number is always a multiple of 512. .end list ZBLK should not return any result. .hl 2 ZMSG ZMSG is used to print assorted informational messages to the screen by the interpreter. These are not part of the normal ZEMU operations, and are used for diagnostics and debug purposes. At entry, R1 points to a format string, while an argument list is located at 2(SP). If you're familiar with RSX, the format string and argument list are the same ones as that used by _$EDMSG. The format string is a NUL-terminated ASCII string which shall be processed before printing. Most characters are printed the same way they appear in the format string. However, whenever a percent sign "_%" occurs, the next character is substituted by the next argument in the argument list. Exactly how the substitution is done depends on what character followed the percent sign. Neither the percent sign, nor the follow on character are copied to the resulting string tough. Once the format string have been processed, it is written to the screen, and terminated by a newline. .hl 2 PUTTXT (This is the function that should be used if the interpreter wants to write out text, while not messing up the screen handling.) Print a text on the screen. R0 points at the string to print, while R1 holds the length. The string is terminated by a NUL character, which isn't included in the length. If the text should be terminated with a newline, the CR+LF should be included in the text. No new lines are added by default by this function. .hl 2 GETRND GETRND should return a random number, which is used to seed the random number generator. The value returned can be derived from the clock, or another fairly random number, and would be placed in R0 on return. Any range is possible, but it is suggested that a range of atleast 1000 is returned. .hl 2 INPINI INPINI is the function called before anything is read from the user. On entry, R0 will hold a timeout value. If this value is anything but zero, this is a time interval on which CHARNE should return even if no input data exist. The timeout should be reset every time it expires, but should not be affected by any input data. The implication of this is that between the calls to INPINI and INPEND, CHARNE should return without data at an even interval, no matter what data CHARNE returns in between. The timeout is given in 1/10 second units. .hl 2 CHARNE CHARNE reads one character from the user, without echo. If the timer expires (see INPINI) the function should return with carry set, otherwise carry should be clear and the character code read should be in R0. .hl 2 INPEND INPEND is called when ZEMU don't want to read anything more from the user. It should cancel any outstanding timers. .hl 2 SCROPN SCROPN should open a scripting file, where a transcript of the game will be written. The filename is pointer to by R0, while R1 holds the length of the file name. The file name is terminated by a NUL, which isn't included in the length. If the file cannot be opened, the function should return with the carry set. It might also be meaningful to write an error message telling why the file couldn't be opened. ZEMU will immediately stop scripting again if the open fails. .hl 2 SCRBLK SCRBLK will write a line to the opened transcription file. The line is pointed to by R0, while the length is in R1. The string is terminated by a NUL, which isn't included in the length. Each line written should result in a newline as well, which SCRBLK must insert. In case of any errors, the function should return with the carry set. It might be meaningful to write an error message as well. ZEMU will, on detecting the carry set, close the scripting file, reset any scripting information it has, and write a message that the scripting was aborted. .hl 2 SCRCLO SCRCLO should close the game transcription file. .hl 2 SAVOPN SAVOPN should create a file for saving the current game state. The file name is pointed to by R0, while R1 holds the length. The file name is terminated by a NUL character, which isn't included in the length. If the file cannot be opened, no matter why, SAVOPN should return with the carry set. If it succeeded the carry should be cleared. R2 gives a hint for how the file should be created, which is useful for instance, if the system can have several versions of the same file available. If R2 is zero, SAVOPN should (if possible) open an already existing file to modify, and otherwise create a new file. If R2 is non-zero, a new file should be created. Ie. R2=0 means overwrite existing file, while R2!=0 means that a new file should be created. .hl 2 SAVBLK SAVBLK should write one block (512 bytes) to the save file. Each write is done sequentially through the file. The data to write is pointed at by R0. If an error occurs during a write, the function should return with the carry set. It might also be meaningful to write a message about the error. If the file can be marked for deletion that should be done. ZEMU will close the save file and inform the game that the save failed. .hl 2 SAVCLO Close the save file that has been written. .hl 2 RESOPN RESOPN should open an existing file for restoring the game state. The parameters, and functionality is the same as for SAVOPN. .hl 2 RESBLK RESBLK should read the next block (512 bytes) from the save file, and place the data where R0 points. If an error occurs, the function should return with the carry set. It might be meaningful to write some error telling what kind of error occurred. Upon detecting that the restore failed, ZEMU will close the file, and restart the game from scratch. .hl 2 RESCLO Close the restore file that has been read. .hl 2 GETSCL Read the number of columns that the screen have. Return this number in R0. .hl 2 GETSLN Read the number of lines that the screen have. Return this number in R0. .hl 2 GETSTP Read the terminal type. Return the number in R0. Possible values are: .list .le UNKT - Unknown type. .le VT52 - VT52 .le ANSI - Ansi terminal. .le VT100 - VT100 .le VT102 - VT102 .le VT200 - VT200 series .le VT300 - VT300 series .le VT400 - VT400 series .le VT500 - VT500 series .end list .hl 2 GETAVO This function should return with the carry set if the terminal supports the AVO option, which means it can set different attributes on displayed characters. .hl 2 GETSOF This function should return with the carry set if the terminal supports software defined characters. If true, ZEMU will allow font 3. .hl 2 GETCOL This function should return with the carry set if the terminal supports colors. .hl 2 CHESIZ This function should return the cache page size in R0. .hl 2 CHEALL This function allocates a cache page. It might call .ALLOC (macro) to do the actual memory allocation for the cache page, or it might have some other scheme to keep cache pages. It should return with an identifier, used to uniquely identify this cache page in R0, and the physical address of the page in R1. .hl 2 CHEUPD This function should update the cache. R0 holds the identifier of the cache page to be replaced, while R2,,R3 holds the virtual address requested. On return, R0 should have the offset into the cache page, while R2,,R3 holds the virtual base address of the cache page. R0 is therefore the difference between R2,,R3 passed in, and R2,,R3 returned. .ch ZEMU internals. This chapter discuss some internal information about ZEMU, and is primarily intended for those who like to hack around, modify and extend ZEMU. .hl 1 Register convention There are two registers that must be kept intact at all times, and that is R5, which is the game stack, and R4 which is the frame pointer. When instructions are executed R2 will point at the argument list, while R3 holds the number of arguments passed to the instruction. R0 and R1 are always available for use. R2 and R3 can be used as well, and the initial values in these registers are also available from other places. (R2 actually points to ARGS, while R3 have the contents of ARGC.) .hl 1 Stacks ZEMU itself uses the normal stack of the PDP-11. It does not require a great amount of stack. The game state includes another stack, called the game stack. This stack is pointed at by R5. The game stack is allocated when ZEMU starts, and items are pushed and popped in the normal manner from this stack. R4 holds the frame pointer. The frame pointer points at the local variables available. .list .le 0(R4) The number of local variables available _* 2 .le 2(R4) Local variable _#1 .le 4(R4) Local variable _#2 .end list and so on... After the local variables comes the previous frame pointer, the previous PC, and the continuation function to execute. All addresses on the game stack are relative. That means that the previous frame pointer is expressed as a number of bytes down the stack. The continuation function is a number, that is used as an index into a table. The throw and catch functions of the Z-machine also gives the stack as a relative offset from the top. Nothing should ever put absolute addresses on the stack since the stack is saved and restored as a part of the save/restore game state. The saved game should be restorable on another version of ZEMU, and it should also be possible to restore on ZEMU on another operating system. Addresses can and will move when the code is modified or ported. .hl 1 Instruction decoding The ZEMU instruction decoder is done through a combination of coding and lookup tables. ZINTER holds the main instruction decode routine. It will decode all arguments, place the at ARGS, set ARGC to the number of decoded arguments and set INSTR to the instruction to execute. It loads R2 and R3, and then does a table lookup of the instruction. ZOPTAB holds all instruction tables. Instructions are grouped depending on the number of arguments. Within each instruction type and number of tables exist for different versions of the Z-machine. Pointers to the correct table, depending on version, are initialised as a part of the ZEMU initialisation. ZEMU will call the correct function, which is pointed at by the opcode tables. If the instruction don't give a result or affect the flow it should just return. If the instruction will give a result, the value should be placed in R0, and it should call the RESULT routine, which saves the value in the appropriate variable. If the instruction conditionally changes the flow, it should jump to BTRUE if the condition was true, and BFALSE if the condition was false. Note that this is not the same as saying if the branch will be taken or not. The condition codes can be reversed in the Z-machine branches, so it can branch on false as well as on true. Unconditional jumps are done by storing the new PC in ZPC and ZPC+2. Return from subroutines are done by jumping to DORET with the return value in R0. .ax RSX operations .hl 1 Operating system requirements ZEMU was developed on RSX-11M-PLUS V4.6, but it should be able to run on all versions. It should also run on RSX-11M, RSX-11D and IAS. ZEMU uses the EXTK_$ directive. If that isn't available, ZEMU has to be run with a pretty large increment, since it uses a lot of dynamic memory. ZEMU requires the full duplex terminal driver. ZEMU uses the GIN_$ system call to drop any privileges it might have once the game starts. The reason for this is to be able to have the (perhaps) copyrighted game files protected from public reading while still accessible to ZEMU. ZEMU can also be installed without privileges, but if so, each user must be able to read the games files. ZEMU is written in such a way that it can be build with split I/D space, and also as a multiuser task. If ZEMU is build on an M+ system, it can be linked against FCSFSL, which means the system library will be located in supervisor address space, and will not take any room in the normal address space. If ZEMU is linked against FCSFSL, it will also be linked with split I/D space. If ZEMU is to be built without split I/D space, or linked as a multiuser task, you have to build the task on your own, with the appropriate switches. ZEMU also identifies if it has been built and installed with the FAST MAP option, and will use FAST MAP if possible. .hl 1 Building ZEMU uses a couple of system calls that might not be available on older M+ systems, or other members of the RSX family. More explicitly, the GIN_$ macro, and the CSI_$4 macro might cause problems. If this happens, the GIN_$ macro can be removed (just comment the two lines having this call out), and CSI_$4 can safely be replaced by CSI_$2 for older systems. .hl 1 Installing Once ZEMU has been built, it can be installed. The default task name for ZEMU is ...ZEM, with a priority of 50. It might be built linked to FCSRES (or FCSFSL if you have RSX-11M-PLUS). When installed, it can be invoked as "ZEM _". ZEMU can be installed as a privileged task (/PR:0), if you like ZEMU to bypass file protection when accessing game files. However, if the GIN_$ directive is removed, this opens up a security hole, since save files and script files then also will bypass file protection checks. ZEMU on RSX will try to find games in common regions. If found, ZEMU will use mapping directives to map around the game file instead of accessing the game file. This will significantly speed up the game play. If a game isn't found in a common region, but is determined to be a system game (located in the system game directory), ZEMU will create a region for the game, and copy the game file to that region. The region will be created with protection so that only privileged programs have read access to the region. If several players want to play the same system game, they will share the same common region, which isn't a problem since only read access is allowed. .hl 2 Directories and filenames .hl 3 The game files The games files have a default extension of .DAT. When ZEMU tries to run a game without a directory specification, it will first look in current directory. If not found there, ZEMU also looks in the default location as specified when building the system. If neither of these places have the game file, ZEMU will report an error. If ZEMU is installed with privileges, it can access the game files even if they are protected from access. Once the game starts, ZEMU drops all privileges (by using the GIN_$ directive) so that later scripting and save files are governed by the expected file protection rules. .hl 3 The save file When ZEMU is built, a default save file name is specified. This is expanded with the file name part of the game being played, and the resulting file name and directory is used as the default filename when a save is done. If no default directory have been specified the users current directory is used. Finally, if no default extension have been given, a default extension of .ZSG is used. .hl 3 The transcription file The transcription file created by ZEMU is a normal text file with variable length records having the FD_.CR attribute. This means that the file can be printed, edited, or handled like any other text file. Of special notice is that the output file for transcription can be a spooled device, in which case, the transcription is printed on by the spooler as soon as ZEMU exits. Once the scripting file is opened, it isn't closed again until the game stops. If the game is terminated by some error, the file will not be properly closed, and this will result in a locked file. .hl 1 Terminal information Terminal information in ZEMU on RSX is retrieved from TI:. When ZEMU is run under RSX, it will turn off terminal wrapping and broadcast to the terminal, and enable full duplex. At exit, these parameters will be restored to whatever they were when ZEMU started. ZEMU will also attach to the terminal, so that all input is directed to it. Some behaviour in ZEMU is changed depending on different attributes retrieved from the terminal driver. The AVO attribute controls wether ZEMU supports underline and bold text. The SOFT attribute controls wether ZEMU allows font 3, which is a software defined font with special characters used by Beyond Zork. The /CO switch is used to determine if the terminal supports color. .ax RT-11 operations .ax RSTS/E operations