TWIN Operating Systems

Information on operating system versions, and on module files.

The TWIN machine was sold under three brand names, using at least that many operating systems. From the launch around September 1977 to around 1982 there were several updates to each of these operating systems. Although it seems likely that most of these operating shared architecture, operating instructions and source code, I do not fully know where similarities end, nor what the differences are between versions of the same operating system.

Copies of SDOS (for the Signetics TWIN), UDOS (for the Millennium Universal One) and TEKDOS (for the Tektronix 8002) can be found on available disk images. So far I have looked at the disk images from the Stuttgart computer museum, the Tektronix and Millennium directories on, and the disks that came with my ECA system. The collection can be downloaded below. My HM system came with a large collection of disks, but I have not extracted disk images from them yet. It takes about an hour and a half to dump disk contents on a 1200 baud terminal, and several passes are often needed when there are read errors.

To load DOS from a disk, a small boot EEPROM contains code that reads contents from tracks 1 to 4 into master memory starting from address 0000. The EEPROM is only 256 bytes long, and half of that is taken up by jump instructions for interrupt handler routines. Note that the contents of the EEPROM are in reversed order, probably because the address lines on the system bus are inverted. The file at bitsavers contains the EEPROM-contents in their stored order; file boot.bin below contains the contents as seen by the master cpu.

Based on information gleaned from documentation, dates of copyright notices and the identity-strings in modules on disk images I have compiled the following timelime. This is still very much work in progress!

One outlier is TOS version 1.0, which was found on an original Signetics disk with the ECA system. One clue to its origin can be found in the module for the Editor: the editor contains a command to return to the operating system. This command is either SDOS, UDOS, or SUSPEND (for SDOS, UDOS and TEKDOS respectively). For TOS this editor command is “SDOS”. The fact that TOS was found on an original Signetics-labeled disk most likely means that we are dealing with an internal test-version of SDOS.

Not all release dates are known exactly. At first glance it looks like the major and minor versions numbers are synchronised between SDOS, UDOS and TEKDOS.

SDOS 1.0 No known documentation for this version. Its properties are only known in comparison to SDOS 2.0, based on the TWIN Technical Note SW002. The LDIR command does not show disk statistics.

SDOS 2.0 Described in TWIN Technical Note SW002. Command LDIR also prints disk statistics, the VERIFY command requires a drive number. All RAM is initialised on startup, to support the parity checks on the new dynamic RAM card.

SDOS 3.0 The SEARCH command has been removed. The SLAVE command is replaced by the ICE command (which takes different parameters). Adds CMPF and DFIL commands for file management. Adds MOVE, FILL, READ, WRITE, UPR commands to maniplate slave memory.

SDOS 3.1 The minimum version required for the new Real-time Hardware Analyzer card.

I will updated this page when new information is discovered.

Module files

Modules contain executable code that can be loaded into master or slave memory. Almost all DOS commands are provided as modules. DOS’ module files are stored in hidden files: the first character of the filename is Ctrl-O (h'0F'). Note that LDIR can show hidden files on a disk when using “LDIR .” .

Modules consists of a 128-byte (one sector) header, followed by data bytes. Most often the data bytes are consecutively stored at the starting address, but the actual load sequence is dictated by load commands listed in the header. See the table below; offsets are hexadecimal, lengths are decimal.

Load module layout
00..02   3   "MOD"
03       1   01=overlay area 1, 02=overlay area 2, 03=slave memory
04..05   2   Load address (slave's perspective)
06..07   2   End address
08..09   2   Start address (first address of execution)
0a..1f  22   Identity (e.g. module name, version, date), 0d terminated text.
20..7f  var  Load commands (variable length)

From offset 20 onwards there are one or more load commands. Load commands start with a command byte, followed by one or two bytes, depending on the command. In the explanation below the command byte is separated into its eight bits (0 or 1, a letter indicating a special function, or ‘x’ for don’t care).

Set Base: bbxx-x00x
bb is the bank. The two bytes following this command byte indicate the base address from the master’s perspective. This base address is used for the subsequent Read Data command.

Read Data: abcd-e01z
00za bcde is the number of sectors to read, minus 1. The byte following this command byte is the length for each of these read operations. Typically this length is h'80' (128) for one full sector, but when the number of sectors is one (the last sector to be read), the length will often be less than 128.

Load End: xxxx-x10x
Indicates the end of the list of load commands. Some of the bits may have a function, but this I have not figured out yet.

DOS reserves two memory areas for modules: overlay area 1 (address 1500-187f) and overlay area 2 (address 1880-1bff). These areas are small, just under 900 bytes each. Some DOS commands actually consist of two modules. The LDIR command for example, in module file “Ctrl-O L”, is loaded into overlay area 1. LDIR then verifies that overlay area 2 is not in use, and loads module file “Ctrl-O O” into overlay area 2.

The design of modules seems overly complex. Note also that code that is too large for overlay areas 1 and 2 combined has to be loaded into slave memory, and then has to be executed by the slave processor.

I wrote a Perl-script to parse the header contents of modules.

For example, the module for the MACRO command:

Module file   :  [@8]
Is module?    :  probably
Identity      :  [** MACRO VER 2.1 **]
Overlay       :  slave memory
Address range :  0040 - 1a13
Start address :  0e05
Load commands :
  - bank/base  0/4040
  - 1 partial blocks of 64 bytes into 4040 ~ 407f
  - bank/base  0/4080
  - 32 full blocks into 4080 ~ 507f
  - bank/base  0/5080
  - 19 full blocks into 5080 ~ 59ff
  - bank/base  0/5a00
  - 1 partial blocks of 20 bytes into 5a00 ~ 5a13
  - end.

For comparison, the header of the MACRO module looks like this (with the nine load commands highlighted).

00000000: 4d4f 4403 0040 1a13 0e05 2a2a 204d 4143  MOD..@....** MAC
00000010: 524f 2056 4552 2032 2e31 202a 2a0d 3031  RO VER 2.1 **.
00000020: 0040 4002 4000 4080 fa80 0050 8092 8000  .@@.@.@....P....
00000030: 5a00 0214 040d 2020 2020 2020 204c 0044  Z....
00000040: 492c 3320 203e 4d53 000d 2020 2020 2020  
00000050: 2042 0041 2020 2020 2044 4953 004c 2020  
00000060: 2020 2020 2020 0020 2020 2020 4449 5350  
00000070: 0041 5920 4d45 5353 4147 000d 2020 2020 

Note that unused bytes of the header (padding of the Identity string, and bytes from the Load End command onwards) contain random data.