ISX - An ISIS-II emulator

Browsing through the CP/M unofficial pages I found an interesting piece of software: an ISIS-II emulator for the CP/M operating system. In case you are too young to know it (or too old to remember it), ISIS-II was an early operating system released by Intel for the MDS series of development machines. Much of the CP/M was actually developed using ISIS, many of the utilities were written in PL/M, and compiled under ISIS.

I wanted to get this historical curiosity running on the P112.

Exact file sizes

In constrast with CP/M 2.2, ISIS-II supports file sizes with byte resolution, and so does the ISX emulator. How it was done? A disassembly of the emulator shows that the disk subsystem is based on the vanilla CP/M 2.2 BDOS; minor changes were done so the BDOS size could stay the same. The exact file size support is similar in principle to what both CP/M 3.0 and DOS+ 2.5 do, but there are differences:

The CP/M 3.0 and DOS+ 2.5 way:

When a file is opened, if the CR byte at FCB offset 32 is set to 0FFh, the count of unused bytes in the last record will be returned there. The count may be set with function 30 (Set File Attributes) by setting the F6 (interface attribute) bit and placing the count in CR. The count is normally 0 and can range up to 7Fh (127).

Note: The DOS+ 2.5 documentation explicitely states that the last record byte count is the number of unused bytes. Apparently, the CP/M 3.0 documentation does not mention how the S1 byte should be interpreted, and that leaves two possibilities: the number of used bytes or the number of unused bytes. The ISIS emulator follows the first interpretation (see below), but a couple of other popular utilities follow the second one: Tilmann Reh's MSDOS, PIP under DOS Plus, and John Elliot's MSODBALL.

The ISX way:

The number of unused bytes is saved in the S1 byte (offset 13) of the directory entry corresponding to the last extent of the file. The count can be retrieved by using the Search First and Search Next functions (the extent field must contain a '?' character), or by the File Open function. The count may be set by opening the file, writing the appropriate value into the S1 byte (offset 13) and calling the BDOS Close File function. The count can range from 0 up to 7Fh.

There is a SETEOF utility included with the emulator, which is used to adjust the size of CP/M text files before they can be used by ISIS utilities. Here is what it does:

  • opens the file
  • seeks to the last record
  • computes the unused byte count by searching backwards for the first non-^Z character and saves the resulting value into FCB's S1
  • clears the high bit of S2 (apparently to simulate that the file was modified)
  • closes the file

You will probably notice that this is not the best way to determine where a text file ends: the method might fail for text files that have been SAVEd, since there are chances that an extra record is appended (the SAVE command has a 2-record resolution). Also, some text editors might not fill the remainder of the record with ^Z characters, as SETEOF expects. A better way would be to scan the text file from the very beginning until the first ^Z is encountered. However, the SETEOF method is faster and will work for files that have been EDited.

Text files created by ISIS programs will have the size field setup correctly; SETEOF does not need to be called for such files unless you edit them under CP/M.

SETEOF requires a CP/M system using the same modified BDOS that the ISX emulator susbsystem uses. Therefore, it will not work under the standard CP/M or a Z-system.

Emulator commands

The ISX command line processor is based on the standard CP/M CCP. There are the familiar DIR, ERA, TYPE and REN commands, but USER is missing: it was replaced by a DBUG command, which can be used to trace the execution of ISIS system calls. The new command apparently was intended for debugging the ISX emulator itself, according to the amount and type of information it provides, but it can be useful when debugging ISIS programs or just to see what they are doing.

In response to the DBUG command, the emulator asks for a "trace level". As response it will only accept a string of ones (111...) terminated by a CR, or a single hash (#). Anything else will cause the prompt to be displayed again. The more ones you enter, the more detailed trace dump you will get (think of the 1's as some sort of bit mask), but only the first 5 ones entered are meaningful. To disable tracing, just hit Enter (CR) when prompted for the trace level. The hash character is used when debugging ISX under DDT, SID or a similar program; it forces the emulator to break into the debugger via RST 7. Don't use it without a debugger, or your system will hang.

The trace dump format is easier to understand with an example. The following is the output for the ISIS READ function:

003: 261E READ     464B (44A3)
   000:0002 81  X0100. E00 U00 R03 C00 L80 @3600 B0003 ,00
   465D=1902   4518=0180   45B4=0000

The first line shows, from left to right:

 003:  - ISIS function code (contents of C register)
 261E  - address of the handling routine in the DOS subsystem
 READ  - ISIS function name
 464B  - address of function argument block (contents of DE register)
(44A3) - where this routine was called from
         (address of CALL instruction in the user program)

Then, the function arguments will follow, one per line, in the form:

 000:  - argument number, count starts at 0
 0002  - argument value, followed by a -> if the argument is a pointer.
         In this example, the first argument to the READ system call is a
         file descriptor, and the dump of the corresponding ISX structure
         is output next:
          81     - file descriptor flags; bits are in the form ufffffwr,
                     u     = 'in use' bit (1 = fd used, 0 = fd is free)
                     fffff = associated internal FCB number
                     w     = 'write' mode bit
                     r     = 'read' mode bit
                   note that both r and w bits can be set at the same time
          X0100. - file name and extension
          E00    - FCB extent value
          U00    - FCB s1 value (unused bytes count)
          R03    - FCB rc value
          C00    - FCB cr value
          L80    - FCB r0 value
          @3600  - I/O buffer address
          B0003  - number of records
          ,00    - last record byte count

Additionally, the contents of one or more I/O buffers may be displayed, depending on the current trace level. Finally, the word value referenced by every pointer in the function call is shown in the form addr=value:

 465D=1902   4518=0180   45B4=0000

The ISIS operating system defines 15 functions, they are:

Number Name Arguments (* means is a pointer)
0 OPEN WORD *fd, BYTE *path, WORD access, WORD echo, WORD *status
1 CLOSE WORD fd, WORD *status
2 DELETE BYTE *path, WORD *status
3 READ WORD fd, BYTE *buff, WORD count, WORD *actual, WORD *status
4 WRITE WORD fd, BYTE *buff, WORD count, WORD *status
5 SEEK WORD fd, WORD mode, WORD *block, WORD *byte, WORD *status
6 LOAD BYTE *path, WORD offset, WORD switch, WORD *entry_pt, WORD *status
7 RENAME BYTE *old, BYTE *new, WORD *status
8 CONSOLE WORD *ci, WORD *co, WORD *status
9 EXIT (none)
10 ATTRIB BYTE *path, WORD attrib, WORD on_off, WORD *status
11 RESCAN WORD fd, WORD *status
12 ERROR WORD errnum
13 WHOCON WORD fd, BYTE *buff
14 SPATH BYTE *path, BYTE *info, WORD *status

Device names

Under the emulator you can use either the ISIS-II or CP/M notation when specifying disks and device names in the command line. Thus, :F0: and A: are the same thing, CON: and :CO: are equivalent, etc. (see table below). That is valid at least for CP/M-style commands like DIR, ERA and REN. ISIS-II utilities will typically allow only ISIS-style names.

The device handling routines expect IOBYTE support in the BIOS. For some devices, the ISX emulator changes the IOBYTE assignment before calling the BDOS handling routine, and restores it afterwards:

Input Devices
CON: :CI: Not changed 1
RDR: :RD: Not changed 3
UC1: :I1: CON:=UC1: 1
UR1: :R1: RDR:=UR1: 3
UR2: :R2: RDR:=UR2: 3
EMP: :BB: Not changed None (empty device, returns ^Z)
Output Devices
CON: :CO: Not changed 2
LST: :LS: Not changed 5
PUN: :PN: Not changed 4
UC1: :O1: CON:=UC1: 2
UL1: :L1: LST:=UL1: 5
UP1: :P1: PUN:=UP1: 4
UP2: :P2: PUN:=UP2: 4
EMP: :BB: Not changed None (empty device)

Memory map

Address Range Description
0040...0042 Jump vector to ISIS DOS.
0180...0FFF BDOS subsystem. Replaces the CP/M BDOS, which can be overlayed by ISIS application programs. This is a slightly modified CP/M 2.2 BDOS, the modification just adds support for exact file lengths, feature needed by ISIS programs.
1000...30FF ISIS DOS emulation subsystem. Emulates ISIS system calls and interprets user commands. The command line processor is based on CP/M CCP.
4000...MEMTOP Transient area for ISIS programs.
MEMTOP...FFFF BIOS subsystem (standard CP/M BIOS). The MEMTOP address is set by the ISX emulator to the start of the BIOS or to F700h, whichever is lower.
F800...F87F MDS-800 BIOS jump table.

Running the emulator

Necessary system modifications:

  • A 128-byte area (F800h...F87Fh) must be reserved in the BIOS for the emulated MDS-800 monitor jump table. The BIOS does not have to initilialize the jump vectors itself, ISX will take care of that.
  • Since ISIS-II applications might overlay the CP/M BDOS, your BIOS should reload CCP and BDOS on warm boot.
  • For proper work of the SETEOF utility, you must replace your CP/M BDOS module with the same modified version the ISX emulator uses.

The disassembled ISX 1.4 can be found in the downloads area. There you'll find also a bootable 3.5" floppy disk image with a working copy of ISX. The system uses a 60K CP/M with a modified BIOS whose data area is located above F900h.

There are several SUBMIT files included with the emulator to aid with compilation (ISIS-II command lines can get really long):

IC.SUB - ISIS Compile (PL/M-80 source to ISIS executable)
CC.SUB - CP/M Compile (PL/M-80 source to CP/M executable)
PRL.SUB - PRL Compile (PL/M-80 source to MP/M PRL)

Note that by default the PL/M compiler stores intermediate files in :F1: (disk B: in the CP/M world), so your P112 should have a second drive connected, and a disk with enough free space on it.

Last updated: 10-Feb-2007