TRS-80 DOS - MicroDOS / OS-80
Page Index
Background
MicroDOS holds a unique position in TRS-80 history as the only disk operating system for the platform that made no attempt whatsoever at compatibility with Radio Shack's TRSDOS. Where every other alternative DOS of the era — NEWDOS, LDOS, DOSPLUS, MULTIDOS — worked within the TRSDOS framework or emulated its command structure, MicroDOS took a philosophically independent path. It extended Level II BASIC directly, bypassed any notion of a file system, and gave the programmer raw direct access to the disk at the sector level.
Jim Stutsman came to the TRS-80 world via the Motorola 6800 hobbyist scene. In 1978, having built his own 6800-based computer from a kit, he attended a 6800 User Group meeting where he encountered Harold Mauch, founder of Percom Data Company in Garland, Texas. Mauch — a former Texas Instruments engineer who had started Percom making high-speed tape interfaces for S-100 bus machines — convinced Stutsman to leave his regular job and write software professionally.
Percom had already developed a simple direct-sector disk access system for its 6800 platform, one that worked through BASIC extensions rather than a command shell. When Tandy began offering floppy drives for the TRS-80, Stutsman ported that approach to the Z80. Rather than reverse-engineering TRSDOS (which would have been a major undertaking), he adapted what Percom already had. The result was MicroDOS Version 1.00, with a manual dated January 1979. Version 1.10 followed on June 4, 1979. Percom renamed the product OS-80 by 1980, and continued selling it well into 1982.
Pictures






MicroDOS Overview
The philosophy at Percom is stated directly in the manual's opening:
"The philosophy at Percom is that a DOS for a microcomputer should make minimal demands on available resources while providing essential functions in accessing the disk. These functions include program save and load and a simple means of storing and retrieving data. Random access of the disk should be as easy to perform as sequential access. MICRODOS was designed around these principles."
Unlike other Disk Operating Systems, MicroDOS exists in conjunction with Level II BASIC, not apart from it. When the computer is first turned on (or the RESET button is pushed), the Level II ROM loads MicroDOS from the disk on drive 0. After performing some initialization, MicroDOS turns control over to Level II. From that point on all communication with MicroDOS is done through the use of BASIC instructions. There is no separate DOS prompt or command shell.
MicroDOS is recorded on sectors 0 to 19 of any disk it is written on. Once loaded by power-up or reset, it is not necessary to keep the MicroDOS disk mounted. MicroDOS resides entirely in memory and does not need a "system" disk available, as TRSDOS does. Its requirements are small: less than 7K of memory and only 5% of a diskette. This makes a 16K one-disk system quite useful.
Disk files created by MicroDOS are NOT compatible with TRSDOS or other disk operating systems. A utility program exists to read TRSDOS BASIC program files, but programs using disk I/O statements will need to be modified for the MicroDOS BASIC syntax.
MicroDOS was configured for Percom disk drives, which permit operation on 40 tracks with a track-to-track step time of 20 milliseconds. Radio Shack drives are capable of only 35 tracks and will not step faster than 40 milliseconds. Users with Radio Shack drives must apply the following patches:
- To change to 35 tracks: POKE 17554,35 : CMD"M",0
- To change step time to 40ms: POKE 17556,3 : CMD"M",0
Disk Organization
Up to four disk drives may be accessed under MicroDOS. These drives are referenced using numbers from 0 through 3. Data within a track is stored in segments called "sectors". Under MicroDOS the unit of disk storage is one sector, and each sector has the capacity for 255 characters (bytes) of data.
Sectors on a disk are accessed by number. The first sector on the first track is number 0. Accessing a sector requires both a drive number and a sector number, combined in a single 5-digit number of the form DSSSS. The first digit D represents the drive number (0-3); the last four digits SSSS are the desired sector number. Leading zeroes are not required, so sectors on drive 0 may be accessed by sector number alone:
- 10010 accesses sector 10 of drive 1.
- 20349 accesses sector 349 of drive 2.
- 20 or 00020 both access sector 20 of drive 0.
The DSSSS number may be specified as an actual number, a variable, or an arithmetic expression. Some examples:
- DS — a simple variable
- D*10000+S — an expression
- LOC(1) — a function
The DSSSS number must never be negative, the drive number may not exceed 3, and the sector number must not exceed the largest possible value for the disk in use.
MicroDOS System Commands
For some functions it is necessary to issue commands directly to MicroDOS using the CMD statement:
| Command | Description |
|---|---|
| CMD"F",D | Format. Formats the diskette on drive D (0-3). Writes control and timing information on every track, then does a full verification pass. If a read error is found during verification, that track is reformatted. If a sector still cannot be read, it is counted. At conclusion, LOC(3) returns the number of sectors that could not be verified (0 = none). Inherently destructive — will overwrite all data on the disk. |
| CMD"M",D | Write MicroDOS to Disk. Writes the MicroDOS system (currently in memory) to sectors 0-19 of the diskette in drive D. The diskette must already be formatted. Any data on sectors 0-19 will be overwritten. Prudent programmers should not use any sector below 20 on any disk that might contain MicroDOS. |
| CMD"I",D | Initialize Disk. A shortcut: performs CMD"F",D then CMD"M",D in sequence on drive D (0-3). |
| CMD"H",A$ | Set Boot Heading. Stores a message of up to 128 characters in MicroDOS memory to be displayed on screen every time MicroDOS is loaded. Use the down-arrow key for a newline within the string. Affects only the copy of MicroDOS in memory; must always be followed by CMD"M",D to write the change to disk. |
| CMD"K",A$ | Set Auto-Key. Stores up to 128 characters in a buffer that is fed to BASIC as keyboard entries at startup. Down-arrow within the string is converted to Enter at power-up. Used to auto-answer "MEMORY SIZE?" and auto-load programs. Must always be followed by CMD"M",D to make it permanent. Example: CMD"K","47245 [down]LOAD 30,R [down]" |
Program Manipulation Commands
MicroDOS allows BASIC programs to be saved on diskette and loaded into memory. Programs are saved in "memory-image" form, so they cannot be read from disk as data and printed.
| Command | Description |
|---|---|
| LOAD DSSSS LOAD DSSSS,R | Loads the program beginning at the sector specified by the DSSSS expression. If ,R follows, the program is RUN immediately after loading. Performs an internal NEW, so no part of any current program in memory will remain. If the program exceeds available memory, an OUT OF MEMORY error occurs and nothing is loaded. |
| SAVE DSSSS | Saves the program in memory to disk, beginning at the sector specified by DSSSS. No check is made to ensure the sectors are unused — it is the user's responsibility to verify sectors are free. At conclusion, the command displays the last sector used, which should be noted to prevent overwriting the program in future disk access. |
| MERGE DSSSS | Works like LOAD but without the implied NEW. The program in memory is not cleared; lines from the incoming program are merged in, with disk lines replacing any matching in-memory lines. If memory is exhausted before the merge is complete, an OUT OF MEMORY error occurs with as much of the program merged as could fit. |
Disk I/O Statements
Each disk sector holds 255 characters (bytes) of data. To store or retrieve data, it must be in string form. Only two statements are needed for simple data storage and retrieval:
| Statement | Description |
|---|---|
| PUT A$,DSSSS | Writes the contents of string variable A$ to the sector identified by the DSSSS expression. A$ may range in length from 0 to 255 bytes. DSSSS may be a number or a variable. Example: 100 A$="HELLO" : PUT A$,50 Numeric data must first be converted to string form using STR$() or the MKX$ functions. |
| GET A$,DSSSS | Reads data from the sector identified by DSSSS into string variable A$. The prior contents of A$ are lost. The length of A$ after the GET reflects the actual number of characters read. LEN(A$) may be used to determine this. Example: 100 GET A$,50 : PRINT LEN(A$);A$ |
| GET #N,DSSSS | Reads the sector identified by DSSSS into Field Buffer N (1-4). The length of the Field Buffer is set to the length of the data read. Always perform a DEF FIELD after a GET and before a PUT to ensure the proper length will be written. |
| PUT #N,DSSSS | Writes the contents of Field Buffer N to the sector identified by DSSSS. The length written is determined by the total length of fields defined by the longest preceding DEF FIELD statement for that buffer. |
Field Buffers
MicroDOS provides four Field Buffers (numbered 1-4) for more efficient and structured disk I/O. Rather than storing data as a single string, data fields may be defined within a buffer for easier manipulation.
| Statement / Function | Description |
|---|---|
| DEF FIELD #N,N1 AS F1$,...,NI AS FI$ | Defines Field Buffer N as named fields F1$ through FI$, having lengths N1 through NI. Lengths may be a number or a parenthesized expression. Maximum buffer size is 255 characters total. Example: DEF FIELD #1,20 AS NA$,40 AS AD$,7 AS PH$ This defines buffer 1 with three fields: a 20-char name, a 40-char address, and a 7-char phone number — 67 characters total, allowing 3 records per sector. |
| LSET A$=B$ | Moves data from B$ into the Field Buffer location named A$, left-justified with trailing spaces. This is the correct way to place data into a field buffer. Simply assigning A$=B$ moves the name, not the data, and will not populate the buffer. |
| RSET A$=B$ | Moves data from B$ into the Field Buffer location named A$, right-justified with leading spaces. If the source is longer than the defined field length, it is truncated. |
| MKI$(I) | Converts integer I to a 2-byte string in internal format for compact storage in a field buffer. Must be stored in a field of exactly 2 characters. |
| MKS$(S) | Converts single-precision floating point S to a 4-byte internal-format string. Must be stored in a field of exactly 4 characters. |
| MKD$(D) | Converts double-precision D to an 8-byte internal-format string. Must be stored in a field of exactly 8 characters. |
| CVI(I$) | Converts a 2-byte string (created by MKI$) back to an integer value. |
| CVS(S$) | Converts a 4-byte string (created by MKS$) back to a single-precision number. A Function Call error occurs if the string is not exactly 4 characters. |
| CVD(D$) | Converts an 8-byte string (created by MKD$) back to a double-precision number. A Function Call error occurs if the string is not exactly 8 characters. |
| LOF(N) | Returns the total length (0-255) of all fields currently defined in Field Buffer N. Useful for verifying buffer length before a PUT. |
Multi-record sectors: Because a sector holds 255 bytes, it is often possible to pack multiple records into one sector. Using a dummy field with a variable length allows a loop to "step through" records within the same sector without reading multiple sectors:
100 GET #1,20048 110 FOR I=0 TO 2 120 DEF FIELD #1,I*67 AS XX$,20 AS NA$,40 AS AD$,7 AS PH$ 130 PRINT NA$ : PRINT AD$ : PRINT PH$ 140 NEXT I
MicroDOS Functions
| Function | Description |
|---|---|
| LOC(0) | Returns the DSSSS number for the last drive and sector accessed. Useful for tracking where SAVE wrote its last data. |
| LOC(1) | Returns the largest possible sector number that can legally be accessed under the current version of MicroDOS (varies by drive model). |
| LOC(2) | Returns the status (in decimal) of the WD1771 Disk Controller following any disk I/O that resulted in an error. Advanced programmers can analyze this to determine the exact hardware failure condition. |
| LOC(3) | Returns the number of sectors that could not be verified during the most recent CMD"F" or CMD"I" format operation. 0 indicates no failures. |
| &H | Hexadecimal constant prefix. Any constant preceded by &H is interpreted as hexadecimal (1-5 hex digits). Always represents a signed integer. Note: octal constants (&O) are NOT supported by MicroDOS. |
| INSTR(N,S1$,S2$) | String search function. Searches S1$ for the first occurrence of the substring S2$. The optional parameter N specifies the starting position within S1$ (default 1). Returns the position where S2$ was found, or 0 if not found. |
| MID$(S1$,N1,N2)=S2$ | String replacement. MID$ may appear on the left side of an assignment. Replaces N2 characters of S1$ starting at position N1 with the string S2$. N2 is optional; if omitted, LEN(S2$) or LEN(S1$)-N1+1 is used, whichever is shorter. |
| LINE INPUT "prompt";A$ | Enhanced INPUT statement. No question mark is displayed. Accepts commas, quotes, colons, and leading blanks as part of the input string. Only one string variable may be specified per statement. |
| DEF USRn / USRn | Up to ten external user machine-language subroutines (USR0-USR9). The entry point is defined using DEFUSRn=X where X is the entry address as a signed integer (-32768 to +32767). |
| DEF FNx | User-defined functions. Allows the programmer to define implicit functions by name. Parameters are supported. Example: DEF FNAC(R)=3.14159*R*R |
MicroDOS Error Codes
All errors are reported using descriptive error messages. Error code numbers may be derived in ON ERROR routines using the expression ERR/2+1. Error codes 1-23 are standard Level II BASIC errors. MicroDOS-specific errors begin at code 24. Note that MicroDOS errors 24 and above cannot be simulated via the ERROR statement; attempting to do so results in UNPRINTABLE ERROR.
| Code | Message and Description |
|---|---|
| 1 | NEXT WITHOUT FOR |
| 2 | SYNTAX ERROR |
| 3 | RETURN WITHOUT GOSUB |
| 4 | OUT OF DATA |
| 5 | ILLEGAL FUNCTION CALL |
| 6 | OVERFLOW |
| 7 | OUT OF MEMORY |
| 8 | UNDEFINED LINE |
| 9 | SUBSCRIPT OUT OF RANGE |
| 10 | REDIMENSIONED ARRAY |
| 11 | DIVISION BY ZERO |
| 12 | ILLEGAL DIRECT |
| 13 | TYPE MISMATCH |
| 14 | OUT OF STRING SPACE |
| 15 | STRING TOO LONG |
| 16 | STRING FORMULA TOO COMPLEX |
| 17 | CAN'T CONTINUE |
| 18 | NO RESUME |
| 19 | RESUME WITHOUT ERROR |
| 20 | UNPRINTABLE ERROR |
| 21 | MISSING OPERAND |
| 22 | BAD FILE DATA |
| 23 | FEATURE NOT IMPLEMENTED |
| 24 | INVALID DRIVE NUMBER — A drive number was encountered outside the range 0 through 3. |
| 25 | INVALID SECTOR NUMBER — The sector referenced is either negative or beyond the limit of the disk drive for which the current version of MicroDOS was designed. |
| 26 | DISK READ/WRITE ERROR — Despite repeated retries, the disk I/O operation could not be completed. Use LOC(2) to get the exact disk controller status. |
| 27 | DISK WRITE PROTECTED — A write operation was requested but the diskette has a write-protect tab. |
| 28 | DISK OVERFLOW — During a SAVE, the end of the disk was encountered before the last line of the program was written. The program is NOT successfully saved. |
| 29 | DISK MISSING OR DOOR OPEN — A legal drive and sector number were specified, but there is no diskette in the drive, the door is not closed, or the drive motor is not turning. |
| 30 | FIELD OVERFLOW — In a DEF FIELD statement, a single field was defined for more than 255 characters, or the total of all defined fields exceeds 255. |
| 31 | FUNCTION DEFINITION ERROR — A DEF FNx statement was not correctly defined, or an FNx reference was made to a function that was not defined. |
| 32 | INVALID FIELD BUFFER NUMBER — A Field Buffer number was either less than 1 or greater than 4. |
| 33 | DISK DRIVE NOT AVAILABLE — The drive referenced either does not exist or fails to properly select when accessed. |
| 34 | DISK SEEK ERROR — Following a seek operation, the disk controller was unable to verify that the head was on the proper track. |
| 35 | CAN'T FORMAT DISK — Either a write circuitry failure on the drive, or more than 255 sectors could not be verified during format. |
Product Versions
The name MicroDOS was phased out in advertising by 1980 and replaced universally by OS-80. A Percom advertisement in the August 1981 issue of 80 Microcomputing described it as: "OS-80, Percom's fast extendable BASIC-language disk operating system, is included on diskette when you purchase an initial drive kit. Originally called MicroDOS, OS-80 was favorably reviewed in the June 1980 issue of Creative Computing magazine." By 1981, Percom offered three distinct versions:
| Version | Description |
|---|---|
| OS-80 | Original single-density version for the TRS-80 Model I. Bundled with Percom's initial drive kits. Retail price: $29.95. |
| OS-80D | Double-density version for Model I computers equipped with the Percom Doubler or Doubler II. Retail price: $49.95. |
| OS-80/III | Version for the TRS-80 Model III, supporting both single- and double-density operation. Retail price: $49.95. |
Percom also sold OS-80 for the Dick Smith System 80, a TRS-80 clone popular in Australia and New Zealand. It also appeared in the Dick Smith Electronics catalog (New Zealand, 1981). A review of the System 80 version appeared in the Australian magazine Micro-80, Issue 16, March 1981.
Patches and Version History
| Version | Notes |
|---|---|
| 1.00 | Initial release. Manual dated January 1979. |
| 1.10 | Released June 4, 1979 (Addendum PM-TFD-100 dated June 4, 1979). Changed format behavior: instead of aborting on an unreadable sector after 9 tries, format now always completes unless physically unable to write or more than 255 bad sectors are found. Bad sector count accessible via LOC(3). System disk menu auto-loads at power-up; press BREAK to exit to BASIC. |
| 1.11 | Patch Memo PM-TFD-100-001 (July 11, 1979). Fixed: LOAD and MERGE did not check whether the incoming program exceeded available memory, causing unpredictable malfunction if it did. Patch lines applied via the Patch Utility stored on sector 40 of the system diskette. |
| 1.12 | Patch Memo PM-TFD-100-002 (July 11, 1979). Fixed: In rare instances, SAVE reported the last sector used as one less than it should, potentially causing undesired concatenation of programs or appending of garbage data on LOAD. |
| v1.14 | No information beyond the fact that a copy exists. |
| v1.15 | No information beyond the fact that a copy exists. |
| v1.21 | No information beyond the fact that a copy exists. |
| v1.22 | No information beyond the fact that a copy exists. |
| v1.21 | No information beyond the fact that a copy exists. |
| v2.10 | No information beyond the fact that a copy exists. |
| v2.20 | No information beyond the fact that a copy exists. |
Percom built a patching facility into the MicroDOS system diskette. A Patch Utility program (stored on sector 40 of system disks from v1.11 onward) allowed patches to be entered and applied without reassembling the DOS. The utility performs three phases: Phase 1 validates the entered patch DATA lines for typing errors; Phase 2 applies the patches to MicroDOS in memory; Phase 3 rewrites the patched DOS to disk via CMD"M".
Copying Programs from TRSDOS to MicroDOS
The following procedure (from a Percom Data Company document dated November 26, 1979) provides a means to copy any BASIC program from a TRSDOS diskette to a MicroDOS diskette:
- Load MicroDOS (power-on or RESET). Insert a blank diskette in drive 0 and initialize it:
CMD"K","" : CMD"I",0 - Put the TRSDOS diskette in drive 0 and press RESET. Load Disk BASIC normally.
- Load the BASIC program to be copied, then type these commands and record the values printed:
PRINT "A="; PEEK(16548)
PRINT "B="; PEEK(16549)
PRINT "C="; PEEK(16633)
PRINT "D="; PEEK(16634) - Load the MicroDOS diskette in drive 0 and press RESET. When BASIC shows READY, enter the values recorded above:
POKE 16548,(A value) : POKE 16549,(B value)
POKE 16633,(C value) : POKE 16634,(D value) - The program is now in memory and may be verified with LIST, then saved to the MicroDOS diskette using the SAVE command. Press RESET after saving to restore usable memory to the MicroDOS size.
Programs may also be transferred between systems by saving to cassette under one DOS and loading from cassette under the other. Note that TRSDOS Disk BASIC programs using disk I/O statements will require modification to use MicroDOS syntax — primarily removal of OPEN/CLOSE statements and reworking of file record logic into sector read/write calls.
Relationship to the Percom Doubler and DBLDOS
In 1980, Percom introduced the Percom Doubler, the first successful double-density add-on for the TRS-80 Model I, at an initial price of $219.95. The hardware was designed by Wayne Smith and Harold Mauch; the accompanying software was written by Jim Stutsman. The Doubler installed inside the Expansion Interface by replacing the Western Digital 1771 floppy disk controller chip, requiring no soldering or trace cutting.
The Doubler was bundled with DBLDOS, a version of TRSDOS modified by Stutsman to support double-density operation. Percom also sold OS-80D as a companion product that could work with the Doubler.
The critical technical insight behind the Doubler's software grew directly from Stutsman's work on MicroDOS. The Z80's clock speed was theoretically insufficient for double-density disk transfers using TRSDOS's polled I/O approach. Stutsman devised a different loop structure that gained just enough cycles to make double-density reliable. In a 2008 interview he called it "without a doubt" his proudest TRS-80 accomplishment: "I'm sure that anyone could have figured out the critical loop timing, but it was really cool to be first."
With the notable exception of Model I TRSDOS itself, Percom Doubler support was eventually added to virtually all TRS-80 operating systems.
Percom Data Company
Percom Data Company was founded by Harold Mauch and his wife Lucy, incorporated in Texas on 23 January 1978. The company's origins traced to the November 1975 BYTE magazine symposium in Kansas City, Missouri, which produced the "Kansas City Standard" for cassette data storage. The final standard was co-authored by Lee Felsenstein and Harold Mauch; attendees included Bill Gates. Mauch also published a companion technical article, "Digital Data on Cassette Recorders," in the March 1976 issue of BYTE.
Percom had its roots in the S-100 and SS-50 bus hobbyist markets before expanding into the TRS-80 space in 1979 with the Percom Separator, a corrective add-on for the Radio Shack Expansion Interface's floppy disk controller defect. The company's headquarters were at 211 N. Kirby Street, Garland, Texas 75042 (phone: 214-272-3421). In October 1981 the company relocated to a larger 27,000 sq ft facility in Dallas. At its peak, Percom employed approximately 150 people.
Harold Mauch died suddenly in August 1982. In 1984, Esprit Systems purchased Percom. The Percom Data trademark was formally cancelled in 1990.
Jim Stutsman, the author of MicroDOS and DBLDOS, left Percom after the Doubler project and later wrote software for Montezuma Micro, including Monte's Windows. He reflected in 2008: "It was fun to be involved in the early stages of personal computing, and I'm very glad to have had the experience."
MicroDOS System Disk Programs
The MicroDOS system diskette shipped with four BASIC programs in addition to the operating system. A menu program loads automatically at power-up or reset; press BREAK to exit to BASIC. Control returns to the menu from any program using the EXIT command. All programs occupy sectors 20 onward; the menu is loaded with LOAD 30,R.
Program 1 — Disk File Manager

A BASIC-language file management system demonstrating how directory management can be built using MicroDOS. Maintains a directory of up to 50 files, each with a name (up to 10 characters), starting and ending sector numbers, file type (P for program, D for data), and a 30-character remark field. Commands: INT (initialize directory), DIR (display directory), NEW (add entry), DEL (delete entry), CHG (modify entry). A drive number and slash may precede any command (e.g., 1/DIR). Entering a filename directly will load and run it if it is a Program type file.
Program 2 — Disk Utilities

Classical disk utilities written entirely in BASIC, serving as examples of MicroDOS-based utility programming. Includes:
- FORMAT — Writes control and timing information on a new diskette.
- BACKUP — Copies an entire diskette to another. Uses all available memory for buffers to minimize copy time. Works with a single drive (prompts for disk swaps).
- COPY — Copies a specified range of sectors from one disk to another, or from one part of a disk to another part of the same disk. Uses all available memory for buffers.
- FREE — Searches a diskette for empty sectors (data length of zero) and displays their sector numbers.
- VERIFY — Reads every sector on a diskette and displays those that cannot be read, plus a summary of bad sectors and their percentage of the disk.
- ERASE — Writes empty sectors over a specified range, releasing that space for FREE to detect.
- DUMP — Reads specified sectors and displays their contents as printable ASCII characters. Non-printable characters are replaced with a graphic block character.
Program 3 — The Percom 5¼ Inch Notebook

A sample application functioning like a paper notebook. Data is organized as "pages" of up to 15 lines, numbered for access. A Table of Contents on page 0 maps keywords to page numbers. Commands: READ n (display page n, with left/right arrow to navigate), WRITE n (enter up to 15 lines of up to 62 characters each), NEW (generate a blank notebook), HELP (display command descriptions). The notebook comes pre-loaded with information about each MicroDOS Disk BASIC statement. Uses sectors 200-399 of drive 0 by default.
Program 4 — Disk Diagnostic Test

A three-phase disk drive diagnostic. Phase 1: formats the entire diskette under test (destructive — destroys all data). Phase 2: writes a special data pattern to 100 random sectors. Phase 3: reads those sectors back and checks against the pattern, reporting any failures. A summary gives the total error count. Do not run on the MicroDOS system diskette.
Program 5 — Exit to BASIC
Performs a NEW, clears the screen, and displays READY for user programming. Return to the System Diskette menu at any time by pressing RESET or typing LOAD 30,R.