To download the source code, you can go straight to the downloads section.
In early January 2024, just a couple of days after 86-DOS 0.11 and 0.34 were dumped and shared by f15sim, I started a project to reconstruct the source code of 86-DOS 0.11. To help me with my project, I reached out to a few folks, and started a group called the "DOS Disassembly Group", dedicated to the disassembly of 86-DOS 0.11.
Whenever I got stuck on something, a core group member and friend of mine, Rich Cini, would jump in to help. One day in March 2024, I got stuck deciphering pass 2 of the SCP 8086 assembler, because it had been completely rewritten between 86-DOS 0.11 and MS-DOS 1.25, and I was using the sources from the 1.25 release as a reference. Something popped into my head - Tim Paterson told Len Shustek in his email regarding the MS-DOS 1.25 source code that:
I also have a 6" stack of printouts of assembly listings for some of these and probably other related programs.
I wondered whether there were earlier versions of the assembler in those listings to help me with my disassembly. I asked that question in the chat, and Rich immediately shot Tim an email, asking if he still had them, and got a response back!
You must be using disassembly to recreate the source code, so you should be able to disassemble ASM and get the translated source. I don't have pre-translation source for it (written in Z80 assembly language).
My stack of listings (on 15"-wide green/white fanfold) is about 5" high. I looked at some of the ones near the top and you might find them interesting. For example, one is 86DOS.A86 v1.00 4/28/81, which means it used SCP ASM mnemonics instead of MASM that you see in the v1.25 source. There are also listings for ASM (post translation) dated late 1981 and early 1982. I wouldn't scan these listing myself; how would you make it happen?
I was shocked. Wow, 86-DOS 1.00 source code? It is the general consensus that the earliest surviving DOS source code is 1.25, as mentioned by Tim himself several times. Now, this was news. Tim's response sounded like he wanted to help! But stuff happened and life went on, and we put this aside for more than a year. Bill Gates' release of Altair BASIC source listing scans put a thought in my head - what if we released the 86-DOS 1.00 source code on DOS' 45th birthday? With that thought in mind, I shot Tim an email on 2025/04/24, and he replied:
The listing stack is actually only 3.5" (I found a bunch of blank paper at the bottom). Here is the inventory:
- DOS 1.25
- DOS snapshot 7/8/81
- DOS snapshot 6/16/81
- DOS diff: 5/5/81 vs. 6/16/81
- EDLIN diff: 5/5/81 vs. 7/1/81
- CHKDSK snapshot 7/28/81
- CHKDSK snapshot 6/16/81
- SCP Assembler 2.40
- SCP Assembler 2.43
- MS BASIC compiler runtime library 11/13/81
The last item was my area of responsibility at MS at the time, and takes up half the stack. Most of the listings are from an MS line printer, and print quality is not great.
Getting around to packing and shipping is the hard part.
Tim Paterson
Ok, wow, there's a lot of stuff here, including multiple snapshots of DOS! Now, we had to jump through a few hoops to actually get the listings. Like Tim said, indeed, shipping was hard. Clearly, getting them shipped to me was out of the question, because Tim's in the US while I'm in Australia. So, getting them shipped to and scanned by Rich is the way to go, but then Tim lives on the West Coast and Rich lives on the East Coast. In the end, Rich's friend, Frank, who lives 10 minutes away from Tim, volunteered to visit Tim in person to grab the listings... but then that was delayed when other matters arose.
Finally, Frank visited Tim on 2025/09/26 and picked up the listings from him.
They were then shipped to Rich, and arrived 6 days later.
The listings came in 10 bundles of connected greenbar paper, in the following order:
MSDOS.LST)86DOS.A86)EDLIN source vs 86-DOS
1.00 EDLIN (EDLIN.DIF)CHKDSK source
(CHKDSK.A86)86DOS.ASMASM.PRN)ASM.PRN)CHKDSK source
(CHKDSK.A86)86DOS.DIF)LIBLST.LOG)BASLIB.PRT)PAINT graphics runtime routine
(PAINT.ASM)CIRCLE graphics runtime routine
(CIRCLE.ASM)Realising that transcribing them would be a non-trivial amount of work, we came up with a plan for how we were going to transcribe the listings and created a GitHub organisation dedicated to the transcription, on the same day the listings arrived. Our approach mirrored that of the UNIX V1 kernel transcription project - doing it page by page and merging the pages together once all pages were done. Rich has a great writeup with some OCR correction tricks as well as info about printers.
Due to the amount of effort required to transcribe the listings, we limited the scope of the project to just the first 8 bundles. While the BASIC-86 Compiler runtime library stuff would be nice to have, we just don't have the bandwidth to transcribe almost 480 pages. After the scope of the project was defined, two things quickly appeared on our radar:
While we were searching for solutions, Rich worked on scanning the listings and I worked on organising and processing the raw scans, as well as transcribing bundle 2 to test the waters. At the same time, I roped Joshua Scarsbrook, a friend of mine and a research officer at my university, into the project, to work on a segmenter and OCR program for greenbar printer listings. While the OCR program didn't end up being used for this project, it provided some good research into the segmentation of printer listings, to be used in future projects!
After all the scanning was done, Rich and I worked together to transcribe all of bundles 1-8. (Actually... I cheated for bundle 1 - it's identical to the MS-DOS 1.25 source code released by Microsoft, so I just used the 1.25 kernel listing for it.) Once that was done, our focus shifted to solving mysteries around the listings.
So, let's take a deep dive into what's in Tim's printouts.
This is the first bundle, at the very top. It is an assembler listing of the MS-DOS 1.25 kernel. There's nothing special here, it's the exact output you get if you assemble the released MS-DOS 1.25 kernel source code. The listing was generated on 1983/01/26, well after Tim had left Microsoft in March 1982.
This bundle is a lot more interesting - it contains
86DOS.A86 dated 1981/07/07, printed by user
BASLIB-86 using the TOPS-10 spooler on the next day. It is
a snapshot of the PC-DOS 1.00 kernel from July, making it a pre-release
or "beta" of PC-DOS 1.00. The code is largely identical to that of the
final PC-DOS 1.00, with the exception of the INT 13H hook
being missing.
The front page has "DATE/TIME FUNCTIONS ADDED FOR IBM CLOCK" written in pencil, and there are several other annotations throughout the listing.
This bundle contains 2 files, EDLIN.DIF and
CHKDSK.A86, both printed by user ROS BASIC on
1981/07/28, using the TOPS-10 spooler.
EDLIN.DIF is a diff of the PC-DOS EDLIN
source code from 1981/06/01 against the 86-DOS 1.00 EDLIN
source code, generated by the TOPS-10 FILCOM utility on the
same day it was printed.
CHKDSK.A86 is a snapshot of the PC-DOS
CHKDSK source code from 1981/07/15.
Bundle 4 contains 86DOS.ASM, the vanilla 86-DOS 1.00
kernel source code. It was printed on 1981/06/16, by user
ROS BASIC using the TOPS-10 spooler, with the file itself
created a day prior. This is the true original 86-DOS 1.00 kernel, which
contains the bug in STORE that Pat Opalka found - a typo
when dealing with file sizes greater than 64K. All existing copies of
"86-DOS 1.00" are in fact functionally equivalent to 86-DOS 1.01, as
they have this bug fixed through patching the kernel.
The front page has "PC-DOS 1.0 NO DATE/TIME FUNCTIONS" written in pencil. While labelled as "PC-DOS 1.0", it's 86-DOS with no modifications for the IBM PC. The terms "QDOS", "86-DOS", "PC-DOS" and "MS-DOS" were all used interchangeably in 1981.
At the end of this bundle, there is a header page for
COMAND.DIF, created and printed on the same day as
86DOS.ASM. It's presumably a diff of the PC-DOS 1.00
command interpreter at that point of development, against the 86-DOS
1.00 command interpreter, but nobody knows for sure. Note that it's
COMAND.DIF with only one "M", this is due to the TOPS-10
6.3 filename limit.
Bundle 5 is the assembly listing of a work-in-progress version of the SCP 8086 assembler, version 2.40, printed from 86-DOS with a daisy-wheel printer. It identifies itself as version 2.31, however it has an incomplete 2.40 entry in the changelog - "Add 8087 mnemonics", dated 1981/08/23. The 8087 support is incomplete - several entries in the 8086 mnemonic table are placeholders.
The assembler itself also has some serious bugs, one severe enough to render it completely unusable - with a fix for it written on page 21 in pencil. There are a few other minor annotations distributed throughout the pages.
Bundle 6 is the assembly listing of SCP 8086 assembler version 2.43, printed from MS-DOS with a dot-matrix printer. The changelog says it's from 1983/01/05, with 1983 mistyped as 1982 (fixed in the next version).
This bundle contains another copy of CHKDSK.A86, dated
1981/06/15 and printed the next day, by user ROS BASIC
using the TOPS-10 spooler. Like the CHKDSK.A86 from bundle
3, this is also the source code for the PC-DOS CHKDSK
utility, but a month older.
This bundle has 86DOS.DIF, a diff generated by
FILCOM dated 1981/06/16 and printed the same day, by user
ROS BASIC using the TOPS-10 spooler. The diff is between a
snapshot of the PC-DOS 1.00 kernel from 1981/06/16 and the 86-DOS 1.00
kernel, and can be applied to the 86-DOS 1.00 kernel from bundle 4 to
restore the 1981/06/16 kernel source code.
This bundle has the build logs and listings of the Microsoft BASIC-86
Compiler runtime library, LIBLST.LOG and
BASLIB.PRT. They were both created on 1981/11/13 and
printed the same day by user BASLIB-86. As Tim said, this
BASIC library was his area of responsibility at Microsoft during that
time. The runtime was written in pure 8086 assembly, and assembled using
MACRO-86 running under TOPS-10.
This bundle has 2 files, PAINT.ASM and
CIRCLE.ASM, dated 1982/01/06 and 1982/02/04 respectively.
Both were printed on 1982/02/06 by user MULTI-PLAN. Not
sure what they're for, an educated guess would be that they're part of
the BASIC-86 Compiler's runtime, perhaps the graphics package. Of
course, they could've also been for Microsoft Multiplan, given the user
who printed them.
Special thanks to Tim Paterson for providing the listings and to Scott Hanselman for obtaining approval to release these sources.
Based on the 86-DOS and PC-DOS kernel sources from these listings, I have reconstructed the source code of several other kernels from 1981:
The original kernel sources from the listings are provided here for reference:
You can compare these sources to figure out exactly what changed between different 86-DOS and PC-DOS versions, as well as the difference between 86-DOS and PC-DOS in general.
Most of the sources here target SCP' ASM assembler, so you will need
a copy. It can be obtained from any release of 86-DOS or MS-DOS by SCP.
You will also need the HEX2BIN utility from SCP to convert
Intel HEX objects produced by the assembler into binaries.
The simplest way to assemble a source file is to run
ASM <FILENAME-NO-EXTENSION>, followed by
HEX2BIN <FILENAME-NO-EXTENSION>. For example, to
assemble 86DOS.ASM into the binary 86DOS.COM,
run:
A:ASM 86DOS
Seattle Computer Products 8086 Assembler Version 2.24
Copyright 1979,80,81 by Seattle Computer Products, Inc.
Error Count = 0
A:HEX2BIN 86DOS
A:
These listings give us some insight into how PC-DOS 1.00 was
developed. The first thing they show is that 86-DOS and PC-DOS were
developed separately, unlike later versions where you build MS-DOS or
PC-DOS from the same source files using switches. There's no
MSVER or IBMVER, nor the hypothetical
SCPVER.
Next, we see that all DOS source files were stored on Microsoft's
DECSYSTEM-20 running TOPS-10, on the DSKC volume. PC-DOS
sources used the extension .A86, while 86-DOS sources used
the extension .ASM - presumably to allow them to coexist in
the same place for easy diffing.
One thing you may have found odd is that all the DOS source files printed by the TOPS-10 spooler have a 5-digit line number at the beginning of each line. Sometimes the numbers increment linearly, sometimes not.
Because some increments are non-linear, these line numbers must've
been in the source files themselves rather than being added by the
spooler. So, wouldn't these line numbers induce syntax errors? Well, no,
because these line numbers are special - they are called
SOS line numbers, produced by the SOS editor
Microsoft used on TOPS-10.
ASCII on 8-/16-/32-/64-bit systems is quite straightforward - each 8-bit byte holds a 7-bit ASCII character, starting from bit 0 which is the LSB (least-significant bit). The remaining bit, bit 7 - the MSB (most-significant bit) is unused and set to 0.
MSB LSB
7 6 5 4 3 2 1 0
0 \___________/
|
7-bit char
TOPS-10 on the other hand is a 36-bit operating system, which ran on the 36-bit PDP-10 family of computers (including the DECSYSTEM-20 that Microsoft used). ASCII on the 36-bit PDP-10 is a bit more complicated - these systems address things in terms of 36-bit words, and each 36-bit word stores five 7-bit ASCII characters. This scheme gives one unused bit per 5 characters, which has been exploited by programs to store metadata.
MSB LSB
00 ....... 06 07 ....... 13 14 ....... 20 21 ....... 27 28 ....... 34 35
\___________/ \___________/ \___________/ \___________/ \___________/ |
| | | | | |____ unused
char 1 char 2 char 3 char 4 char 5
(Yes, bit 0 is the MSB which is the left-most bit on the PDP-10. Crazy, isn't it?)
The SOS editor inserts a word at the beginning of each
line, which I call the "line number word", holding a 5-digit line
number. These "line number words" have the unused bit set to 1, to
separate them from regular text words which have the unused bit set to
0. This way, while the line numbers are stored within the text file,
they are not a part of the actual text, and hence can easily be ignored
or stripped.
For example, a text file with content
Hello,\r\nWorld!\r\n and SOS line numbers may
look like this when printed:
02670 Hello,
02680 World!
And it's stored in memory and on disk as the following array of 36-bit words:
| |
MSB LSB | MSB LSB | MSB LSB
0 <-----------> 35 | 0 <-----------> 35 | 0 <--------------> 35
'0' '2' '6' '7' '0' 1 | '\t' 'H' 'e' 'l' 'l' 0 | 'o' ',' '\r' '\n' '\0' 0
| |
----------------------+-----------------------+--------------------------
| |
MSB LSB | MSB LSB | MSB LSB
0 <-----------> 35 | 0 <------------> 35 | 0 <--------------> 35
'0' '2' '6' '8' '0' 1 | '\t' 'W' 'o' 'r' 'l' 0 | 'd' '!' '\r' '\n' '\0' 0
| |
As you can see, the line numbers must be 5 characters each, so they cannot exceed 99999 and are 0-padded on the left if they do not have 5 digits. Technically any valid ASCII character may appear in a line number, but in practice only numerical digits are used.
From the spooler headers and trailers, we can gather that Microsoft had the following accounts on their DECSYSTEM-20:
ROS BASIC [500,500]BASLIB-86 [20,67]MS-DOS [500,100]MULTI-PLAN [104,103]The tuple enclosed in square brackets is the PPN (Project-Programmer Number). The first value is the project ID, and the second value is the programmer ID. You can sort of think of them as group ID and user ID in Unix-based systems.
From the account names, we can gather some insight into what was developed or stored on the DECSYSTEM-20. "ROS BASIC" most likely referred to the IBM PC ROM BASIC, which Microsoft developed for IBM to use in the IBM PC 5150. "BASLIB-86" was what Tim worked on during that time - BASIC-86 Compiler runtime library. "MS-DOS" is self-explanatory, and "MULTI-PLAN" was Microsoft Multiplan, either the CP/M version or the DOS version.
If you examine DSKC:86DOS.ASM - the 86-DOS 1.00 kernel
source code listed in bundle 4 and diff'd against in the bundle 8 diff,
you'll see some weird things.
For example:
00930 ; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number
00940 ; zero is used as an end-of-file trap in the OS and as a flag for directory
00950 ; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The
00960 ; first available allocation unit is assigned entry number two, and for Drive Parameter Block
00970
00980 ORG 0
00990 DRVNUM: DS 1 ;Drive number
Line 00960 is quite a bit longer than the other lines, and the ending doesn't make much sense. Comparing against the same comment in the MS-DOS 1.25 kernel source, we can see that the last part of the FAT comment is truncated, and the second half of the block comment for DPB fields is merged with the truncated FAT comment. The original should've been:
00930 ; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number
00940 ; zero is used as an end-of-file trap in the OS and as a flag for directory
00950 ; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The
00960 ; first available allocation unit is assigned entry number two, and even
+++++ ; though it is the first, is called cluster 2. Entries greater than 0FF8H are
+++++ ; end of file marks; entries of zero are unallocated. Otherwise, the contents
+++++ ; of a FAT entry is the number of the next cluster in the file.
+++++
+++++
+++++ ; Field definition for Drive Parameter Block
00970
00980 ORG 0
00990 DRVNUM: DS 1 ;Drive number
The next spot is much more obvious - lines 02790 and 02810 are simply not syntactically correct:
02760 SEG CS
02770 MOV AX,[NSP]
02780 SEG CS
02790 MOV [SPSA ENDIF
02800
02810 PBX
02820 POP CX
02830 POP DX
02840 POP SI
The original code is in bundle 2, as well as in the bundle 8 diff:
02760 SEG CS
02770 MOV AX,[NSP]
02780 SEG CS
02790 MOV [SPSAVE],AX
+++++ SEG CS
+++++ MOV AX,[NSS]
+++++ SEG CS
+++++ MOV [SSSAVE],AX
+++++ ENDIF
02800
02810 POP AX
+++++ POP BX
02820 POP CX
02830 POP DX
02840 POP SI
The final spot manifests itself as a syntax error on line 30270:
30240 CALL GETLET
30250 SUB AL,"@" ;Convert drive letter to binary drive number
30260 JZ NODRV ;Valid drive numbers are 1-15
30270 INCcifier--back up pointer
30280 DEFAULT:
30290 XOR AL,AL
30300 HAVDRV:
Again, characters went missing. This time the code actually changed between 86-DOS 1.00 and later versions of DOS, so the later sources aren't of any help for restoring these missing characters. I've figured out the missing instructions using the 1.00 kernel binary, but no guarantees that it's a perfect character-for-character match with the original source code.
30240 CALL GETLET
30250 SUB AL,"@" ;Convert drive letter to binary drive number
30260 JZ NODRV ;Valid drive numbers are 1-15
30270 INC SI
+++++ CMP AL,15
+++++ JBE HAVDRV
+++++ DEC SI
+++++ NODRV:
+++++ DEC SI ;Invalid drive specifier--back up pointer
30280 DEFAULT:
30290 XOR AL,AL
30300 HAVDRV:
So how did these characters go missing? There are a few possible theories, but let's take a look at the facts first.
Given that the PC-DOS 1.00 source code does not have the FAT comment at all, yet MS-DOS 1.25 source code has it, the corruption must've come from outside of SCP. This is because MS-DOS 1.25 is based on 86-DOS 1.13 or 1.14 from SCP, and if the comment in MS-DOS 1.25 is intact, it must've been intact at SCP.
Also worth noting is PC-DOS 1.00 source code does not have the FAT comment, yet has the 86-DOS 1.00 header comment as well as some of the instructions that are missing. This combined with the fact that development of PC-DOS started before 86-DOS 1.00 suggests that:
Clearly, the FAT comment was added after 86-DOS 0.34, because it mentions directory sizes - 0.34 used only 16-byte directory entries. Microsoft started working on porting 86-DOS to the IBM PC in late 1980 (possibly December), and first boot happened on or shortly before 1981/01/25. Whichever version they worked on, it's either 0.34 or earlier, hence could not have had that FAT comment. So, if they were to rebase their changes onto the corrupted 86-DOS 1.00 source code, they would've used their older sources to repair the missing instructions, but since their older sources didn't have the FAT comment, that was not repairable and hence taking it out would make sense. This would result in the PC-DOS 1.00 source code being based off of 86-DOS 1.00, have the missing instructions but missing that FAT comment - like what we see in bundles 2 and 8.
Ok, cool, so where exactly did the corruption happen? I'd say during the transfer from 8" 86-DOS-formatted floppies to the DECSYSTEM-20. Bob O'Rear, who led the PC-DOS project in 1981 wrote in his notes:
Seattle Computers delivers source of QDOS and utilities on 8" QDOS formatted diskette & an absolute assembler.
This was from early 1981, when the project had just started and source files were mostly stored on 8" DOS disks, while the DECSYSTEM-20 was used only for assembling the DOS BIOS. As they progressed, they moved the files to be stored on their DECSYSTEM-20, but I don't think how SCP delivered the source code changed. I imagine they would've used an SCP Gazelle to read the 8" floppies, then transfer source code to the DECSYSTEM-20 via some serial communication protocol like RS-232.
My suspicion is something happened during the serial transfer of the source file to the DECSYSTEM-20 and caused bytes to be dropped silently. A quick example would be a loose wire or bad contact when the receiving end uses RS-232 with pull-down resistors - if the connection is broken, the receiver would simply see no data and no errors, for the duration of the disconnection. It may not be what actually happened, but things like this would explain why missing bytes are all clustered together in chunks rather than spread out throughout the file.
Could it have been disk corruption - like bad sectors? Highly unlikely, because:
The only other plausible explanation for the corruptions would be someone messed up editing the file and accidentally deleted a bunch of characters. This is also unlikely because you have to try quite hard to mess up 3 different sections of the file by purely deleting characters, and have it go unnoticed until after you save the file.
Perhaps the most mind-blowing fact we learned from this is that all known copies of 86-DOS 1.00 are functionally 86-DOS 1.01. If you read the MS-DOS 1.25 change log, you'll see this entry:
1.01 05/12/81 Fix bug in `STORE'
It bugged me for quite a while what that bug was. I had to inspect the "1.00" kernel binary in order to fix the corruptions mentioned, and after the fix, the binary from assembling 1.00 source did not match the original "1.00" binary.
A quick diff revealed two differences:
*** 86DOS.ASM
--- 86DOS_101.ASM
***************
*** 1526,1532 ****
MOV BL,[SECCLUSPOS]
CALL FIGREC
OR AL,AL
! JNZ SETBUF
CMP DX,[BUFSECNO]
JNZ GETSEC
MOV AL,[BUFDRVNO]
--- 1526,1533 ----
MOV BL,[SECCLUSPOS]
CALL FIGREC
OR AL,AL
! NOP
! NOP
CMP DX,[BUFSECNO]
JNZ GETSEC
MOV AL,[BUFDRVNO]
***************
*** 1920,1926 ****
SEG ES
MOV AX,[DI+FILSIZ]
SEG ES
! MOV DX,[DI+FILSIZ]
DIV AX,[BP+SECSIZ]
OR DX,DX
JZ NORNDUP
--- 1921,1927 ----
SEG ES
MOV AX,[DI+FILSIZ]
SEG ES
! MOV DX,[DI+FILSIZ+2]
DIV AX,[BP+SECSIZ]
OR DX,DX
JZ NORNDUPBUFSEC is disabled,
so that it always does a pre-read before doing a write. I haven't looked
into exactly what this fixes.STORE, where DX:AX is
set to the 32-bit FILSIZ field. Original 1.00 stores the
lower 16 bits of FILSIZ to both AX and
DX, which is clearly wrong. 1.01 fixed it to store the
lower 16 bits to AX, and the upper 16 bits to
DX.We can tell it was a binary patch, because of the
NOPping out of the conditional jump rather than deleting it
as well as the instruction above which sets the condition. Patching of
the binary suggests that these were very last minute changes, otherwise
they would've just modified the source code and re-assembled the kernel
instead of patching.
Given the released "1.00" kernel has the STORE bug
fixed, it's functionally 1.01. Apparently this bug was found by Pat
Opalka and fixed upon a customer's request, and then the change was sent
to Microsoft as Tim Paterson had already left SCP.
Given that a bunch of the files were originally stored on TOPS-10, can we reconstruct them and put them back on TOPS-10? Absolutely, but it's not that easy.
The first thing to do is to convert the printed
files in plaintext to PDP-10 core dump format. Given that 36-bit
words don't divide cleanly into 8-bit bytes, storing them on a modern
byte-oriented computer is a challenge. Core dump format is the native
format that PDP-10 uses for storing 36-bit words using 8-bit bytes on
9-track tapes. One can convert a plain ASCII text file to core dump
format using my txt2core
utility - it can also turn line numbers in the plaintext into SOS line
number words with the -l option.
Once you have the plaintext files converted to core dump format, they
can then be added to a backup tape using my fork of Johnny
Eriksson's back10 program.
For example, if I want to create a TOPS-10 backup tape with the
86DOS.A86 from bundle 2, I would run:
$ txt2core -l plaintext/86DOS.A86 86DOS.A86
$ back10 -U MT:500,500 -S 86DOS -C -f 86dos.tap -c 86DOS.A86
This would create a TOPS-10 backup tape 86dos.tap in
SIMH format, with the file 86DOS.A86<055> owned by
[500,500]. You can now use this with the SIMH simulator or write it to a
real 9-track tape.
To use it to import 86DOS.A86, at the user console,
run:
.MOUNT TAPE: /REELID:86DOS /NOWAIT
Then at the operator console, attach the tape. In SIMH, to attach the tape, run:
OPR>^E
sim> att tu0 86dos.tap
sim> set tu0 lock
sim> c
If prompted about label error, run
RESPOND <number> PROCEED at OPR>
prompt.
OPR>SHOW QUEUE
OPR>IDENTIFY MTA0: REQUEST-ID <number>
Now that the tape is attached and mounted, at user console, run:
.R BACKUP
/TAPE MT:
/REWIND
/RESTORE DSK:86DOS.A86=MT:86DOS.A86[*,*]
/EXIT
Now 86DOS.A86 is restored from the backup tape - with
the same owner and file mode as what Microsoft had.
To unmount the tape, run .DISMOUNT MT: at user console
and then OPR>DISMOUNT TAPE-DRIVE MTA0: at operator
console.
As I mentioned earlier - there is a fatal bug in the assembler from
bundle 5 that made it completely unusable. What the code wants is to
shift bits 6 and 7 of the register CH into bits 0 and 1 of
the global variable [RELOC], such that:
[RELOC] = ABCDEFGHCH = IJKLMNOP[RELOC] = CDEFGHIJThe buggy code is:
MOV CL,[RELOC]
ROL CX
ROL CX
MOV [RELOC],CL
Do you see what's wrong :)? Let's trace it line by line:
MOV CL,[RELOC] -> CH:CL = IJKLMNOP:ABCDEFGH, CARRY = ?
ROL CX -> CH:CL = JKLMNOPA:BCDEFGH0, CARRY = I
ROL CX -> CH:CL = KLMNOPAB:CDEFGH0I, CARRY = J
MOV [RELOC],CL -> [RELOC] = CDEFGH0I
As you can see, [RELOC] becomes CDEFGH0I in
the end. Clearly, this is not the CDEFGHIJ that the program
wants.
So, here's the code written on the listing in pencil:
MOV AL,[RELOC]
RCL CH
RCL AL
RCL CH
RCL AL
MOV [RELOC],AL
Does it fix the bug? Let's trace through it and see!
MOV AL,[RELOC] -> AL = ABCDEFGH, CH = IJKLMNOP, CARRY = ?
RCL CH -> AL = ABCDEFGH, CH = JKLMNOP?, CARRY = I
RCL AL -> AL = BCDEFGHI, CH = JKLMNOP?, CARRY = A
RCL CH -> AL = BCDEFGHI, CH = KLMNOP?A, CARRY = J
RCL AL -> AL = CDEFGHIJ, CH = KLMNOP?A, CARRY = B
MOV [RELOC],CL -> [RELOC] = CDEFGHIJ
Yup, this indeed puts the desired CDEFGHIJ into
[RELOC]. A bit of poking around revealed that all versions
of the assembler both before and after this snapshot use the "fixed"
code, which means Tim likely accidentally introduced this bug while
trying to optimise the assembler, and quickly realised the optimisation
was incorrect and undid it.
There are other bugs in the assembler as well, all can be fixed by applying this patch:
*** ASM.ASM
--- ASM_FIXED.ASM
***************
*** 1350,1359 ****
;Save byte of code in AL, given intermediate code bits in bits 7&8 of CH.
CALL PUTINC ;Save it and bump code pointer
GEN1:
! MOV CL,[RELOC]
! ROL CX
! ROL CX
! MOV [RELOC],CL
MOV BX,BCOUNT
DEC B,[BX]
JNZ RET
--- 1350,1361 ----
;Save byte of code in AL, given intermediate code bits in bits 7&8 of CH.
CALL PUTINC ;Save it and bump code pointer
GEN1:
! MOV AL,[RELOC]
! RCL CH
! RCL AL
! RCL CH
! RCL AL
! MOV [RELOC],AL
MOV BX,BCOUNT
DEC B,[BX]
JNZ RET
***************
*** 2489,2494 ****
--- 2491,2497 ----
JZ EXIT
MOV AL,1AH
CALL WRTBUF ;Write end-of-file mark
+ MOV DI,[LSTPNT]
CALL FLUSHBUF
MOV AX,[FCB+20] ;Get date of source file
MOV [LSTFCB+20],AX
***************
*** 2699,2705 ****
RET
FLUSHBUF:
! MOV CX,[LSTPNT]
MOV DX,LSTBUF
MOV DI,DX
SUB CX,DX
--- 2702,2708 ----
RET
FLUSHBUF:
! MOV CX,DI
MOV DX,LSTBUF
MOV DI,DX
SUB CX,DXPage written by Yufeng Gao. Last updated: 2026/04/12.