MS-DOS v1.25 Release
authorRich Turner <richturn@microsoft.com>
Thu, 4 Mar 1982 00:51:26 +0000 (16:51 -0800)
committerRich Turner <richturn@microsoft.com>
Sat, 22 Sep 2018 00:51:26 +0000 (17:51 -0700)
35 files changed:
v1.25/Tim_Paterson_16Dec2013_email.txt [new file with mode: 0644]
v1.25/bin/ART.BAS [new file with mode: 0644]
v1.25/bin/BALL.BAS [new file with mode: 0644]
v1.25/bin/BASIC.COM [new file with mode: 0644]
v1.25/bin/BASICA.COM [new file with mode: 0644]
v1.25/bin/CALENDAR.BAS [new file with mode: 0644]
v1.25/bin/CHKDSK.COM [new file with mode: 0644]
v1.25/bin/CIRCLE.BAS [new file with mode: 0644]
v1.25/bin/COLORBAR.BAS [new file with mode: 0644]
v1.25/bin/COMM.BAS [new file with mode: 0644]
v1.25/bin/COMMAND.COM [new file with mode: 0644]
v1.25/bin/COMP.COM [new file with mode: 0644]
v1.25/bin/DEBUG.COM [new file with mode: 0644]
v1.25/bin/DISKCOMP.COM [new file with mode: 0644]
v1.25/bin/DISKCOPY.COM [new file with mode: 0644]
v1.25/bin/DONKEY.BAS [new file with mode: 0644]
v1.25/bin/EDLIN.COM [new file with mode: 0644]
v1.25/bin/EXE2BIN.EXE [new file with mode: 0644]
v1.25/bin/FORMAT.COM [new file with mode: 0644]
v1.25/bin/LINK.EXE [new file with mode: 0644]
v1.25/bin/MODE.COM [new file with mode: 0644]
v1.25/bin/MORTGAGE.BAS [new file with mode: 0644]
v1.25/bin/MUSIC.BAS [new file with mode: 0644]
v1.25/bin/PIECHART.BAS [new file with mode: 0644]
v1.25/bin/SAMPLES.BAS [new file with mode: 0644]
v1.25/bin/SETCLOCK.COM [new file with mode: 0644]
v1.25/bin/SPACE.BAS [new file with mode: 0644]
v1.25/bin/SYS.COM [new file with mode: 0644]
v1.25/source/ASM.ASM [new file with mode: 0644]
v1.25/source/COMMAND.ASM [new file with mode: 0644]
v1.25/source/HEX2BIN.ASM [new file with mode: 0644]
v1.25/source/IO.ASM [new file with mode: 0644]
v1.25/source/MSDOS.ASM [new file with mode: 0644]
v1.25/source/STDDOS.ASM [new file with mode: 0644]
v1.25/source/TRANS.ASM [new file with mode: 0644]

diff --git a/v1.25/Tim_Paterson_16Dec2013_email.txt b/v1.25/Tim_Paterson_16Dec2013_email.txt
new file mode 100644 (file)
index 0000000..45c4055
--- /dev/null
@@ -0,0 +1,23 @@
+From: Tim Paterson 
+To: Len Shustek 
+Date: Mon, 16 Dec 2013 10:34:17 -0800
+Subject: RE: Source code to MS-DOS 1.0
+
+
+I have found and attached the source code for MS-DOS 1.25 as shipped by Seattle Computer Products.  Version 1.25 was the first general release to OEM customers other than IBM so was used by all the first clone manufacturers.
+IBM's DOS 1.1 corresponds to MS-DOS 1.24.  There is one minor difference between 1.24 and 1.25, as noted in the revision history at the top of MSDOS.ASM.
+Of the file attached, only STDDOS.ASM/MSDOS.ASM (DOS main code) and COMMAND.ASM (command processor) would have been used by an OEM other than Seattle Computer.  The other files:
+IO.ASM - I/O system unique to SCP (equivalent to ibmbio.sys).
+ASM.ASM & HEX2BIN.ASM - Old 8086 assembler developed by SCP (used to assemble older version of DOS).
+TRANS.ASM - Z80 to 8086 assembly source code translator developed by SCP.
+I also have a 6\94 stack of printouts of assembly listings for some of these and probably other related programs.
+Tim Paterson
+Paterson Technology
+http://www.patersontech.com/
diff --git a/v1.25/bin/ART.BAS b/v1.25/bin/ART.BAS
new file mode 100644 (file)
index 0000000..2de324a
Binary files /dev/null and b/v1.25/bin/ART.BAS differ
diff --git a/v1.25/bin/BALL.BAS b/v1.25/bin/BALL.BAS
new file mode 100644 (file)
index 0000000..132087a
Binary files /dev/null and b/v1.25/bin/BALL.BAS differ
diff --git a/v1.25/bin/BASIC.COM b/v1.25/bin/BASIC.COM
new file mode 100644 (file)
index 0000000..d6b32cf
Binary files /dev/null and b/v1.25/bin/BASIC.COM differ
diff --git a/v1.25/bin/BASICA.COM b/v1.25/bin/BASICA.COM
new file mode 100644 (file)
index 0000000..dc08578
Binary files /dev/null and b/v1.25/bin/BASICA.COM differ
diff --git a/v1.25/bin/CALENDAR.BAS b/v1.25/bin/CALENDAR.BAS
new file mode 100644 (file)
index 0000000..34860ec
Binary files /dev/null and b/v1.25/bin/CALENDAR.BAS differ
diff --git a/v1.25/bin/CHKDSK.COM b/v1.25/bin/CHKDSK.COM
new file mode 100644 (file)
index 0000000..bf88ed2
Binary files /dev/null and b/v1.25/bin/CHKDSK.COM differ
diff --git a/v1.25/bin/CIRCLE.BAS b/v1.25/bin/CIRCLE.BAS
new file mode 100644 (file)
index 0000000..611fc0d
Binary files /dev/null and b/v1.25/bin/CIRCLE.BAS differ
diff --git a/v1.25/bin/COLORBAR.BAS b/v1.25/bin/COLORBAR.BAS
new file mode 100644 (file)
index 0000000..067792c
Binary files /dev/null and b/v1.25/bin/COLORBAR.BAS differ
diff --git a/v1.25/bin/COMM.BAS b/v1.25/bin/COMM.BAS
new file mode 100644 (file)
index 0000000..ef3439a
Binary files /dev/null and b/v1.25/bin/COMM.BAS differ
diff --git a/v1.25/bin/COMMAND.COM b/v1.25/bin/COMMAND.COM
new file mode 100644 (file)
index 0000000..751326f
Binary files /dev/null and b/v1.25/bin/COMMAND.COM differ
diff --git a/v1.25/bin/COMP.COM b/v1.25/bin/COMP.COM
new file mode 100644 (file)
index 0000000..0d16119
Binary files /dev/null and b/v1.25/bin/COMP.COM differ
diff --git a/v1.25/bin/DEBUG.COM b/v1.25/bin/DEBUG.COM
new file mode 100644 (file)
index 0000000..b502552
Binary files /dev/null and b/v1.25/bin/DEBUG.COM differ
diff --git a/v1.25/bin/DISKCOMP.COM b/v1.25/bin/DISKCOMP.COM
new file mode 100644 (file)
index 0000000..08c595b
Binary files /dev/null and b/v1.25/bin/DISKCOMP.COM differ
diff --git a/v1.25/bin/DISKCOPY.COM b/v1.25/bin/DISKCOPY.COM
new file mode 100644 (file)
index 0000000..e2436d1
Binary files /dev/null and b/v1.25/bin/DISKCOPY.COM differ
diff --git a/v1.25/bin/DONKEY.BAS b/v1.25/bin/DONKEY.BAS
new file mode 100644 (file)
index 0000000..8b6ac8a
Binary files /dev/null and b/v1.25/bin/DONKEY.BAS differ
diff --git a/v1.25/bin/EDLIN.COM b/v1.25/bin/EDLIN.COM
new file mode 100644 (file)
index 0000000..5ed5148
Binary files /dev/null and b/v1.25/bin/EDLIN.COM differ
diff --git a/v1.25/bin/EXE2BIN.EXE b/v1.25/bin/EXE2BIN.EXE
new file mode 100644 (file)
index 0000000..d43a3f2
Binary files /dev/null and b/v1.25/bin/EXE2BIN.EXE differ
diff --git a/v1.25/bin/FORMAT.COM b/v1.25/bin/FORMAT.COM
new file mode 100644 (file)
index 0000000..c1cc45e
Binary files /dev/null and b/v1.25/bin/FORMAT.COM differ
diff --git a/v1.25/bin/LINK.EXE b/v1.25/bin/LINK.EXE
new file mode 100644 (file)
index 0000000..499b7b2
Binary files /dev/null and b/v1.25/bin/LINK.EXE differ
diff --git a/v1.25/bin/MODE.COM b/v1.25/bin/MODE.COM
new file mode 100644 (file)
index 0000000..b9f69e3
Binary files /dev/null and b/v1.25/bin/MODE.COM differ
diff --git a/v1.25/bin/MORTGAGE.BAS b/v1.25/bin/MORTGAGE.BAS
new file mode 100644 (file)
index 0000000..80c062e
Binary files /dev/null and b/v1.25/bin/MORTGAGE.BAS differ
diff --git a/v1.25/bin/MUSIC.BAS b/v1.25/bin/MUSIC.BAS
new file mode 100644 (file)
index 0000000..bd0ae0d
Binary files /dev/null and b/v1.25/bin/MUSIC.BAS differ
diff --git a/v1.25/bin/PIECHART.BAS b/v1.25/bin/PIECHART.BAS
new file mode 100644 (file)
index 0000000..943b398
Binary files /dev/null and b/v1.25/bin/PIECHART.BAS differ
diff --git a/v1.25/bin/SAMPLES.BAS b/v1.25/bin/SAMPLES.BAS
new file mode 100644 (file)
index 0000000..2d2b2aa
Binary files /dev/null and b/v1.25/bin/SAMPLES.BAS differ
diff --git a/v1.25/bin/SETCLOCK.COM b/v1.25/bin/SETCLOCK.COM
new file mode 100644 (file)
index 0000000..3bf8501
Binary files /dev/null and b/v1.25/bin/SETCLOCK.COM differ
diff --git a/v1.25/bin/SPACE.BAS b/v1.25/bin/SPACE.BAS
new file mode 100644 (file)
index 0000000..52ba147
Binary files /dev/null and b/v1.25/bin/SPACE.BAS differ
diff --git a/v1.25/bin/SYS.COM b/v1.25/bin/SYS.COM
new file mode 100644 (file)
index 0000000..7f478fa
Binary files /dev/null and b/v1.25/bin/SYS.COM differ
diff --git a/v1.25/source/ASM.ASM b/v1.25/source/ASM.ASM
new file mode 100644 (file)
index 0000000..d870d97
--- /dev/null
@@ -0,0 +1,4006 @@
+; Seattle Computer Products 8086 Assembler  version 2.44
+;   by Tim Paterson
+; Runs on the 8086 under MS-DOS
+
+;* * * * * * REVISION HISTORY * * * * * *
+;
+; 12/29/80  2.01  General release with 86-DOS version 0.34
+; 02/22/81  2.10  Increased buffer size from 128 bytes to 1024 bytes
+; 03/18/81  2.11  General cleanup and more documentation
+; 03/24/81  2.20  Modify ESC handling for full 8087 operation
+; 04/01/81  2.21  Fix date in HEX and PRN files; modify buffer handling
+; 04/03/81  2.22  Fix 2.21 buffer handling
+; 04/13/81  2.23  Re-open source file for listing to allow assembling CON:
+; 04/28/81  2.24  Allow nested IFs
+; 07/30/81  2.25  Add Intel string mnemonics; clean up a little
+; 08/02/81  2.30  Re-write pass 2:
+;                      Always report errors to console
+;                      Exact byte lengths for HEX and PRN files
+; 11/08/81  2.40  Add 8087 mnemonics; print full error messages;
+;                allow expressions with *, /, and ()
+; 07/04/82  2.41  Fix Intel's 8087 "reverse-bit" bug; don't copy date
+; 08/18/82  2.42  Increase stack from 80 to 256 (Damn! Overflowed again!)
+; 01/05/83  2.43  Correct over-zealous optimization in 2.42
+; 05/09/83  2.44  Add memory usage report
+;
+;* * * * * * * * * * * * * * * * * * * * *
+
+SYMWID:        EQU     5       ;5 symbols per line in dump
+FCB:   EQU     5CH
+BUFSIZ:        EQU     1024    ;Source code buffer
+LSTBUFSIZ:EQU  BUFSIZ  ;List file buffer
+HEXBUFSIZ:EQU  70      ;Hex file buffer (26*2 + 5*2 + 3 + EXTRA)
+EOL:   EQU     13      ;ASCII carriage return
+OBJECT:        EQU     100H    ;DEFAULT "PUT" ADDRESS
+
+;System call function codes
+PRINTMES: EQU  9
+OPEN:  EQU     15
+CLOSE: EQU     16
+READ:  EQU     20
+SETDMA:        EQU     26
+MAKE:  EQU     22
+BLKWRT:        EQU     40
+
+;The following equates define some token values returned by GETSYM
+UNDEFID:EQU    0       ;Undefined identifier (including no nearby RET)
+CONST: EQU     1       ;Constant (including $)
+REG:   EQU     2       ;8-bit register
+XREG:  EQU     3       ;16-bit register (except segment registers)
+SREG:  EQU     4       ;Segment register
+FREG:  EQU     6       ;8087 floating point register
+
+;Bits to build 8087 opcode table entries
+ONEREG:        EQU     40H     ;Single ST register OK as operand
+NEEDOP:        EQU     80H     ;Must have an operand
+INTEGER:EQU    20H     ;For integer operations
+REAL:  EQU     28H     ;For real operations
+EXTENDED EQU   10H     ;For Long integers or Temporary real
+MEMORY:        EQU     18H     ;For general memory operations
+STACKOP:EQU    10H     ;Two register arithmetic with pop
+ARITH: EQU     8       ;Non-pop arithmetic operations
+
+       ORG     100H
+       PUT     100H
+
+       JMPS    BEGIN
+
+HEADER:        DB      13,10,'Seattle Computer Products 8086 Assembler Version 2.44'
+       DB      13,10,'Copyright 1979-1983 by Seattle Computer Products, Inc.'
+       DB      13,10,13,10,'$'
+
+BEGIN:
+       MOV     SP,STACK
+       MOV     DX,HEADER
+       MOV     AH,PRINTMES
+       INT     33
+       MOV     AL,[FCB+17]
+       MOV     [SYMFLG],AL     ;Save symbol table request flag
+       MOV     SI,FCB+9        ;Point to file extension
+       LODB                    ;Get source drive letter
+       CALL    CHKDSK          ;Valid drive?
+       OR      AL,AL
+       JZ      DEFAULT         ;If no extension, use existing drive spec
+       MOV     [FCB],AL
+DEFAULT:
+       LODB                    ;Get HEX file drive letter
+       CMP     AL,'Z'          ;Suppress HEX file?
+       JZ      L0000
+       CALL    CHKDSK
+L0000: 
+       MOV     [HEXFCB],AL
+       LODB                    ;Get PRN file drive letter
+       MOV     AH,0            ;Signal no PRN file
+       CMP     AL,'Z'          ;Suppress PRN file?
+       JZ      NOPRN
+       CMP     AL,'Y'          ;Print errors only on console?
+       JZ      NOPRN
+       MOV     AH,2
+       CMP     AL,'X'          ;PRN file to console?
+       JZ      NOPRN
+       MOV     AH,4
+       CMP     AL,'P'          ;PRN file to printer?
+       JZ      NOPRN
+       CALL    CHKDSK
+       MOV     AH,80H
+NOPRN:
+       MOV     [LSTFCB],AL
+       MOV     [LSTDEV],AH     ;Flag device for list ouput
+       MOV     SI,EXTEND
+       MOV     DI,FCB+9
+       MOVW
+       MOVB                    ;Set extension to ASM
+       MOVW                    ;Zero extent field
+       MOV     DX,FCB
+       MOV     AH,OPEN
+       INT     33
+       MOV     BX,NOFILE
+       OR      AL,AL
+       JZ      $+5
+       JMP     PRERR
+       MOV     DX,HEXFCB
+       CALL    MAKFIL
+       MOV     DX,LSTFCB
+       CALL    MAKFIL
+       XOR     AX,AX
+       MOV     [FCB+12],AX     ;Zero CURRENT BLOCK field
+       MOV     [FCB+32],AL     ;Zero Next Record field
+       MOV     [FCB+14],BUFSIZ ;Set record size
+       MOV     [BUFPT],SRCBUF  ;Initialize buffer pointer
+       MOV     [CODE],START+1  ;POINTER TO NEXT BYTE OF INTERMEDIATE CODE
+       MOV     [IY],START      ;POINTER TO CURRENT RELOCATION BYTE
+       XOR     AX,AX
+       MOV     [PC],AX         ;DEFAULT PROGRAM COUNTER
+       MOV     [BASE],AX       ;POINTER TO ROOT OF ID TREE=NIL
+       MOV     [RETPT],AX      ;Pointer to last RET record
+       MOV     [IFFLG],AL      ;NOT WITHIN IF/ENDIF
+       MOV     [CHKLAB],AL     ;LOOKUP ALL LABELS
+       DEC     AX
+       MOV     [LSTRET],AX     ;Location of last RET
+       MOV     AX,[6]          ;HL=END OF MEMORY
+       MOV     [HEAP],AX       ;BACK END OF SYMBOL TABLE SPACE
+       MOV     [BCOUNT],4      ;CODE BYTES PER RELOCATION BYTE
+
+;Assemble each line of code
+
+LOOP:
+       CALL    NEXTCHR         ;Get first character on line
+       CMP     AL,1AH
+       JZ      ENDJ
+       MOV     AL,-1           ;Flag that no tokens have been read yet
+       MOV     [SYM],AL
+       CALL    ASMLIN          ;Assemble the line
+       MOV     AL,[SYM]
+       CMP     AL,-1           ;Any tokens found on line?
+       JNZ     L0002
+       CALL    GETSYM          ;If no tokens read yet, read first one
+L0002: 
+       CMP     AL,';'
+       JZ      ENDLN
+       CMP     AL,EOL
+       JZ      ENDLN
+       MOV     AL,14H          ;Garbage at end of line error
+       JP      ENDLIN
+ENDJ:  JMP     END
+
+ENDLN:
+       XOR     AL,AL           ;Flag no errors on line
+ENDLIN:
+;AL = error code for line. Stack depth unknown
+       MOV     SP,STACK
+       CALL    NEXLIN
+       JP      LOOP
+
+NEXLIN:
+       MOV     CH,0C0H         ;Put end of line marker and error code (AL)
+       CALL    PUTCD
+       CALL    GEN1
+       MOV     AL,[CHR]
+GETEOL:
+       CMP     AL,10
+       JZ      RET
+       CMP     AL,1AH
+       JZ      ENDJ
+       CALL    NEXTCHR         ;Scan over comments for linefeed
+       JP      GETEOL
+
+ABORT:
+       MOV     BX,NOMEM
+PRERR:
+       MOV     DX,BX
+       MOV     AH,PRINTMES
+       INT     33
+       INT     32
+
+MAKFIL:
+       MOV     SI,DX
+       LODB                    ;Get drive select byte
+       CMP     AL,20H          ;If not valid, don't make file
+       JNC     RET
+       MOV     CX,4
+       MOV     DI,SI
+       MOV     SI,FCB+1
+       REP
+       MOVW                    ;Copy source file name
+       MOV     AH,MAKE
+       INT     33
+       MOV     [DI-9+14],1     ;Set record length to 1 byte
+       MOV     BX,NOSPAC
+       OR      AL,AL           ;Success?
+       JNZ     PRERR
+       RET
+
+CHKDSK:
+       SUB     AL,' '          ;If not present, set zero flag
+       JZ      RET
+       SUB     AL,20H
+       JZ      DSKERR          ;Must be in range A-O
+       CMP     AL,'P'-'@'
+       JC      RET
+DSKERR:
+       MOV     BX,BADDSK
+       JP      PRERR
+
+ERROR:
+       MOV     AL,CL
+       JMP     ENDLIN
+
+NEXTCHR:
+       MOV     SI,[BUFPT]
+       CMP     SI,SRCBUF
+       JNZ     GETCH
+;Buffer empty so refill it
+       PUSH    DX
+       PUSH    AX              ;AH must be saved
+       MOV     DX,SI
+       MOV     AH,SETDMA
+       INT     33
+       MOV     DX,FCB
+       MOV     AH,READ
+       INT     33
+       XCHG    AX,DX           ;Put error code in DL
+       POP     AX              ;Restore AH
+       MOV     AL,DL           ;Error code back in AL
+       POP     DX
+       CMP     AL,1
+       MOV     AL,1AH          ;Possibly signal End of File
+       JZ      NOMOD           ;If nothing read
+GETCH:
+       LODB
+       CMP     SI,SRCBUF+BUFSIZ
+       JNZ     NOMOD
+       MOV     SI,SRCBUF
+NOMOD:
+       MOV     [BUFPT],SI
+       MOV     [CHR],AL
+       RET
+
+
+MROPS:
+
+; Get two operands and check for certain types, according to flag byte
+; in CL. OP code in CH. Returns only if immediate operation.
+
+       PUSH    CX              ;Save type flags
+       CALL    GETOP
+       PUSH    DX              ;Save first operand
+       CALL    GETOP2
+       POP     BX              ;First op in BX, second op in DX
+       MOV     AL,SREG         ;Check for a segment register
+       CMP     AL,BH
+       JZ      SEGCHK
+       CMP     AL,DH
+       JZ      SEGCHK
+       MOV     AL,CONST        ;Check if the first operand is immediate
+       MOV     CL,26
+       CMP     AL,BH
+       JZ      ERROR           ;Error if so
+       POP     CX              ;Restore type flags
+       CMP     AL,DH           ;If second operand is immediate, then done
+       JZ      RET
+       MOV     AL,UNDEFID      ;Check for memory reference
+       CMP     AL,BH
+       JZ      STORE           ;Is destination memory?
+       CMP     AL,DH
+       JZ      LOAD            ;Is source memory?
+       TEST    CL,1            ;Check if register-to-register operation OK
+       MOV     CL,27
+       JZ      ERROR
+       MOV     AL,DH
+       CMP     AL,BH           ;Registers must be of same length
+RR:
+       MOV     CL,22
+       JNZ     ERROR
+RR1:
+       AND     AL,1            ;Get register length (1=16 bits)
+       OR      AL,CH           ;Or in to OP code
+       CALL    PUT             ;And write it
+       POP     CX              ;Dump return address
+       MOV     AL,BL
+       ADD     AL,AL           ;Rotate register number into middle position
+       ADD     AL,AL
+       ADD     AL,AL
+       OR      AL,0C0H         ;Set register-to-register mode
+       OR      AL,DL           ;Combine with other register number
+       JMP     PUT
+
+SEGCHK:
+;Come here if at least one operand is a segment register
+       POP     CX              ;Restore flags
+       TEST    CL,8            ;Check if segment register OK
+       MOV     CL,22
+       JZ      ERR1
+       MOV     CX,8E03H        ;Segment register move OP code
+       MOV     AL,UNDEFID
+       CMP     AL,DH           ;Check if source is memory
+       JZ      LOAD
+       CMP     AL,BH           ;Check if destination is memory
+       JZ      STORE
+       MOV     AL,XREG
+       SUB     AL,DH           ;Check if source is 16-bit register
+       JZ      RR              ;If so, AL must be zero
+       MOV     CH,8CH          ;Change direction
+       XCHG    DX,BX           ;Flip which operand is first and second
+       MOV     AL,XREG
+       SUB     AL,DH           ;Let RR perform finish the test
+       JP      RR
+
+STORE:
+       TEST    CL,004H         ;Check if storing is OK
+       JNZ     STERR
+       XCHG    DX,BX           ;If so, flip operands
+       AND     CH,0FDH         ;   and zero direction bit
+LOAD:
+       MOV     DH,25
+       CMP     AL,BH           ;Check if memory-to-memory
+       JZ      MRERR
+       MOV     AL,BH
+       CMP     AL,REG          ;Check if 8-bit operation
+       JNZ     XRG
+       MOV     DH,22
+       TEST    CL,1            ;See if 8-bit operation is OK
+       JZ      MRERR
+XRG:
+       MOV     AL,DL
+       SUB     AL,6            ;Check for R/M mode 6 and register 0
+       OR      AL,BL           ;   meaning direct load/store of accumulator
+       JNZ     NOTAC
+       TEST    CL,8            ;See if direct load/store of accumulator
+       JZ      NOTAC           ;   means anything in this case
+; Process direct load/store of accumulator
+       MOV     AL,CH
+       AND     AL,2            ;Preserve direction bit only
+       XOR     AL,2            ;   but flip it
+       OR      AL,0A0H         ;Combine with OP code
+       MOV     CH,AL
+       MOV     AL,BH           ;Check byte/word operation
+       AND     AL,1
+       OR      AL,CH
+       POP     CX              ;Dump return address
+       JMP     PUTADD          ;Write the address
+
+NOTAC:
+       MOV     AL,BH
+       AND     AL,1            ;Get byte/word bit
+       AND     AL,CL           ;But don't use it in word-only operations
+       OR      AL,CH           ;Combine with OP code
+       CALL    PUT
+       MOV     AL,BL
+       ADD     AL,AL           ;Rotate to middle position
+       ADD     AL,AL
+       ADD     AL,AL
+       OR      AL,DL           ;Combine register field
+       POP     CX              ;Dump return address
+       JMP     PUTADD          ;Write the address
+
+STERR:
+       MOV     DH,29
+MRERR:
+       MOV     CL,DH
+
+ERR1:  JMP     ERROR
+
+GETOP2:
+;Get the second operand: look for a comma and drop into GETOP
+       MOV     AL,[SYM]
+       CMP     AL,','
+       MOV     CL,21
+       JNZ     ERR1
+
+
+GETOP:
+
+; Get one operand. Operand may be a memory reference in brackets, a register,
+; or a constant. If a flag (such as "B" for byte operation) is encountered,
+; it is noted and processing continues to find the operand.
+;
+; On exit, AL (=DH) has the type of operand. Other information depends
+; on the actual operand:
+;
+; AL=DH=0  Memory Reference.  DL has the address mode properly prepared in
+; the 8086 R/M format (middle bits zero). The constant part of the address
+; is in ADDR. If an undefined label needs to be added to this, a pointer to
+; its information fields is in ALABEL, otherwise ALABEL is zero.
+;
+; AL=DH=1  Value. The constant part is in DATA. If an undefined label needs
+; to be added to this, a pointer to its information fields is in DLABEL,
+; otherwise DLABEL is zero. "$" and "RET" are in this class.
+;
+; AL=DH=2  8-bit Register. DL has the register number.
+;
+; AL=DH=3  16-bit Register. DL has the register number.
+;
+; AL=DH=4  Segment Register. DL has the register number.
+
+       CALL    GETSYM
+GETOP1:
+;Enter here if we don't need a GETSYM first
+       CMP     AL,'['          ;Memory reference?
+       JZ      MEM
+       CMP     AL,5            ;Flag ("B", "W", etc.)?
+       JZ      FLG
+       CMP     AL,REG          ;8-Bit register?
+       JZ      NREG
+       CMP     AL,XREG         ;16-Bit register?
+       JZ      NREG
+       CMP     AL,SREG         ;Segment register?
+       JZ      NREG
+VAL:                           ;Must be immediate
+       XOR     AL,AL           ;No addressing modes allowed
+VAL1:
+       CALL    GETVAL
+       MOV     AX,[CON]        ;Defined part
+       MOV     [DATA],AX
+       MOV     AX,[UNDEF]      ;Undefined part
+       MOV     [DLABEL],AX
+       MOV     DL,CH
+       MOV     DH,CONST
+       MOV     AL,DH
+       RET
+NREG:
+       PUSH    DX
+       CALL    GETSYM
+       POP     DX
+       MOV     AL,DH
+       RET
+MEM:
+       CALL    GETSYM
+       MOV     AL,1
+       CALL    GETVAL
+       MOV     AL,[SYM]
+       CMP     AL,']'
+       MOV     CL,24
+       JNZ     ERR1
+       CALL    GETSYM
+       MOV     BX,[CON]
+       MOV     [ADDR],BX
+       MOV     BX,[UNDEF]
+       MOV     [ALABEL],BX
+       MOV     DL,CH
+       MOV     DH,UNDEFID
+       MOV     AL,DH
+       RET
+FLG:
+       CMP     DL,[MAXFLG]     ;Invalid flag for this operation?
+       MOV     CL,27H
+       JG      ERR1
+       CALL    GETSYM
+       CMP     AL,','
+       JZ      GETOP
+       JP      GETOP1
+
+
+GETVAL:
+
+; Expression analyzer. On entry, if AL=0 then do not allow base or index
+; registers. If AL=1, we are analyzing a memory reference, so allow base
+; and index registers, and compute addressing mode when done. The constant
+; part of the expression will be found in CON. If an undefined label is to
+; be added to this, a pointer to its information fields will be found in
+; UNDEF.
+
+       MOV     AH,AL           ;Flag is kept in AH
+       MOV     [UNDEF],0
+       MOV     AL,[SYM]
+       CALL    EXPRESSION
+       MOV     [CON],DX
+       MOV     AL,AH
+       MOV     CH,0            ;Initial mode
+       TEST    AL,10H          ;Test INDEX bit
+       RCL     AL              ;BASE bit (zero flag not affected)
+       JZ      NOIND           ;Jump if not indexed, with BASE bit in carry
+       CMC
+       RCL     CH              ;Rotate in BASE bit
+       RCL     AL              ;BP bit
+       RCL     CH
+       RCL     AL              ;DI bit
+       RCL     CH              ;The low 3 bits now have indexing mode
+MODE:
+       OR      CH,080H         ;If undefined label, force 16-bit displacement
+       TEST    [UNDEF],-1
+       JNZ     RET
+       MOV     BX,[CON]
+       MOV     AL,BL
+       CBW                     ;Extend sign
+       CMP     AX,BX           ;Is it a signed 8-bit number?
+       JNZ     RET             ;If not, use 16-bit displacement
+       AND     CH,07FH         ;Reset 16-bit displacement
+       OR      CH,040H         ;Set 8-bit displacement
+       OR      BX,BX
+       JNZ     RET             ;Use it if not zero displacement
+       AND     CH,7            ;Specify no displacement
+       CMP     CH,6            ;Check for BP+0 addressing mode
+       JNZ     RET
+       OR      CH,040H         ;If BP+0, use 8-bit displacement
+       RET
+
+NOIND:
+       MOV     CH,6            ;Try direct address mode
+       JNC     RET             ;If no base register, that's right
+       RCL     AL              ;Check BP bit
+       JC      MODE
+       INC     CH              ;If not, must be BX
+       JP      MODE
+
+EXPRESSION:
+;Analyze arbitrary expression. Flag byte in AH.
+;On exit, AL has type byte: 0=register or undefined label
+       MOV     CH,-1           ;Initial type
+       MOV     DI,DX
+       XOR     DX,DX           ;Initial value
+       CMP     AL,'+'
+       JZ      PLSMNS
+       CMP     AL,'-'
+       JZ      PLSMNS
+       MOV     CL,'+'
+       PUSH    DX
+       PUSH    CX
+       MOV     DX,DI
+       JP      OPERATE
+PLSMNS:
+       MOV     CL,AL
+       PUSH    DX
+       PUSH    CX
+       OR      AH,4            ;Flag that a sign was found
+       CALL    GETSYM
+OPERATE:
+       CALL    TERM
+       POP     CX              ;Recover operator
+       POP     BX              ;Recover current value
+       XCHG    DX,BX
+       AND     CH,AL
+       OR      AL,AL           ;Is it register or undefined label?
+       JZ      NOCON           ;If so, then no constant part
+       CMP     CL,"-"          ;Subtract it?
+       JNZ     ADD
+       NEG     BX
+ADD:
+       ADD     DX,BX
+NEXTERM:
+       MOV     AL,[SYM]
+       CMP     AL,'+'
+       JZ      PLSMNS
+       CMP     AL,'-'
+       JZ      PLSMNS
+       MOV     AL,CH
+       RET
+NOCON:
+       CMP     CL,"-"
+       JNZ     NEXTERM
+BADOP:
+       MOV     CL,5
+       JMP     ERROR
+
+TERM:
+       CALL    FACTOR
+MULOP:
+       PUSH    DX              ;Save value
+       PUSH    AX              ;Save type
+       CALL    GETSYM
+       POP     CX
+       CMP     AL,"*"
+       JZ      GETFACT
+       CMP     AL,"/"
+       JNZ     ENDTERM
+GETFACT:
+       OR      CL,CL           ;Can we operate on this type?
+       JZ      BADOP
+       PUSH    AX              ;Save operator
+       CALL    GETSYM          ;Get past operator
+       CALL    FACTOR
+       OR      AL,AL
+       JZ      BADOP
+       POP     CX              ;Recover operator
+       POP     BP              ;And current value
+       XCHG    AX,BP           ;Save AH in BP
+       CMP     CL,"/"          ;Do we divide?
+       JNZ     DOMUL
+       OR      DX,DX           ;Dividing by zero?
+       MOV     CL,29H
+       JZ      ERR2
+       MOV     BX,DX
+       XOR     DX,DX           ;Make 32-bit dividend
+       DIV     AX,BX
+       JMPS    NEXFACT
+DOMUL:
+       MUL     AX,DX
+NEXFACT:
+       MOV     DX,AX           ;Result in DX
+       XCHG    AX,BP           ;Restore flags to AH
+       MOV     AL,-1           ;Indicate a number
+       JMPS    MULOP
+ENDTERM:
+       POP     DX
+       MOV     AL,CL
+       RET
+
+FACTOR:
+       MOV     AL,[SYM]
+       CMP     AL,CONST
+       JZ      RET
+       CMP     AL,UNDEFID
+       JZ      UVAL
+       CMP     AL,"("
+       JZ      PAREN
+       CMP     AL,'"'
+       JZ      STRING
+       CMP     AL,"'"
+       JZ      STRING
+       CMP     AL,XREG         ;Only 16-bit register may index
+       MOV     CL,20
+       JNZ     ERR2
+       TEST    AH,1            ;Check to see if indexing is OK
+       MOV     CL,1
+       JZ      ERR2
+       MOV     AL,DL
+       MOV     CL,3
+       SUB     AL,3            ;Check for BX
+       JZ      BXJ
+       SUB     AL,2            ;Check for BP
+       JZ      BPJ
+       DEC     AL              ;Check for SI
+       MOV     CL,4
+       JZ      SIJ
+       DEC     AL              ;Check for DI
+       JZ      DIJ
+       MOV     CL,2            ;Invalid base/index register
+ERR2:  JMP     ERROR
+
+DIJ:
+       OR      AH,20H          ;Flag seeing index register DI
+SIJ:
+       TEST    AH,10H          ;Check if already seen index register
+       JNZ     ERR2
+       OR      AH,10H          ;Flag seeing index register
+       RET
+
+BPJ:
+       OR      AH,40H          ;Flag seeing base register BP
+BXJ:
+       TEST    AH,80H          ;Check if already seen base register
+       JNZ     ERR2
+       OR      AH,80H          ;Flag seeing base register
+       RET
+
+PAREN:
+       CALL    GETSYM          ;Eat the "("
+       CALL    EXPRESSION
+       CMP     B,[SYM],")"     ;Better have closing paren
+       MOV     CL,20
+       JNZ     ERR30
+       RET
+
+UVAL:
+       MOV     CL,6
+       TEST    AH,8            ;Check if undefined label has been seen
+       JNZ     ERR30
+       OR      AH,8            ;Flag seeing undefined label
+       MOV     [UNDEF],BX
+       RET
+
+ERR30: JMP     ERROR
+
+STRING:
+       MOV     CH,AL
+       MOV     AL,[CHR]
+       CMP     AL,CH
+       MOV     CL,35
+       MOV     DL,AL
+       MOV     DH,0
+       JNZ     L0003
+       CALL    ZERLEN
+L0003:
+       CALL    GETCHR
+       MOV     CL,37
+       TEST    AH,2
+       JZ      ERR30
+       TEST    AH,4
+       MOV     CL,38
+       JNZ     ERR30
+STRGDAT:
+       MOV     AL,DL
+       CMP     AL,EOL
+       MOV     CL,39
+       JZ      ERR30
+       CALL    PUT
+       MOV     AL,[DATSIZ]
+       OR      AL,AL
+       JNZ     BYTSIZ
+       MOV     AL,DH
+       CALL    PUT
+BYTSIZ:
+       MOV     AL,[CHR]
+       MOV     DL,AL
+       CALL    GETCHR
+       JP      STRGDAT
+
+ZERLEN:
+       CALL    NEXTCHR
+       CMP     AL,CH
+       JNZ     ERR30
+       RET
+
+GETCHR:
+       CALL    NEXTCHR
+       CMP     AL,CH
+       JNZ     RET
+       CALL    NEXTCHR
+       CMP     AL,CH
+       JZ      RET
+       POP     BX              ;Kill return address to STRGDAT loop
+       MOV     AL,-1           ;Flag type as constant
+       RET
+
+
+GETSYM:
+
+; The lexical scanner. Used only in the operand field. Returns with the token
+; in SYM and AL, sometimes with additional info in BX or DX.
+;
+; AL=SYM=0  Undefined label. BX has pointer to information fields.
+;
+; AL=SYM=1  Constant (or defined label). DX has value.
+;
+; AL=SYM=2,3,4  8-bit register, 16-bit register, or segment register,
+; respectively. DL has register number.
+;
+; AL=SYM=5  A mode flag (such as "B" for byte operation). Type of flag in DL
+; and also stored in FLAG: -1=no flags, 0=B, 1=W, 2=S, 3=L, 4=T.
+;
+; AL=SYM=6  8087 floating point register, ST(n) or ST. DL has register number.
+;
+; All other values are the ASCII code of the character. Note that this may
+; never be a letter or number.
+
+       PUSH    AX              ;Save AH
+       CALL    GETSY
+       POP     AX
+       MOV     AL,[SYM]
+       RET
+
+SCANB:
+       MOV     AL,[CHR]
+SCANT:
+       CMP     AL,' '
+       JZ      NEXB
+       CMP     AL,9
+       JNZ     RET
+NEXB:
+       CALL    NEXTCHR
+       JP      SCANT
+
+DOLLAR:
+       MOV     DX,[OLDPC]
+       MOV     AL,CONST
+       MOV     [SYM],AL
+NEXTCHJ:
+       JMP     NEXTCHR
+
+GETSY:
+       CALL    SCANB
+       CMP     AL,'$'
+       JZ      DOLLAR
+       MOV     [SYM],AL
+       OR      AL,20H
+       CMP     AL,'z'+1
+       JNC     NEXTCHJ
+       CMP     AL,'a'
+       JC      $+5
+       JMP     LETTER
+       CMP     AL,'9'+1
+       JNC     NEXTCHJ
+       CMP     AL,'0'
+       JC      NEXTCHJ
+       MOV     BX,SYM
+       MOV     B,[BX],CONST
+       CALL    READID
+       DEC     BX
+       MOV     AL,[BX]
+       MOV     CL,7
+       MOV     BX,0
+       CMP     AL,'h'
+       JNZ     $+5
+       JMP     HEX
+       INC     CL
+       MOV     [IX],ID
+DEC:
+       MOV     SI,[IX]
+       MOV     AL,[SI]
+       INC     [IX]
+       CMP     AL,'9'+1
+       JC      $+5
+       JMP     ERROR
+       SUB     AL,'0'
+       MOV     DX,BX
+       SHL     BX
+       SHL     BX
+       ADD     BX,DX
+       SHL     BX
+       MOV     DL,AL
+       MOV     DH,0
+       ADD     BX,DX
+       DEC     CH
+       JNZ     DEC
+       XCHG    DX,BX
+       RET
+
+HEX:
+       MOV     DX,ID
+       DEC     CH
+HEX1:
+       MOV     SI,DX
+       LODB
+       INC     DX
+       SUB     AL,'0'
+       CMP     AL,10
+       JC      GOTIT
+       CMP     AL,'g'-'0'
+       JNC     ERR4
+       SUB     AL,'a'-10-'0'
+GOTIT:
+       SHL     BX
+       SHL     BX
+       SHL     BX
+       SHL     BX
+       ADD     BL,AL
+       DEC     CH
+       JNZ     HEX1
+       XCHG    DX,BX
+       RET
+
+ERR4:  JMP     ERROR
+
+GETLET:
+       CALL    SCANB
+       CMP     AL,EOL
+       STC
+       JZ      RET
+       CMP     AL,';'
+       STC
+       JZ      RET
+       MOV     CL,10
+       OR      AL,20H
+       CMP     AL,'a'
+       JC      ERR4
+       CMP     AL,'z'+1
+       JNC     ERR4
+READID:
+       MOV     BX,ID
+       MOV     CH,0
+MOREID:
+       MOV     [BX],AL
+       INC     CH
+       INC     BX
+       CALL    NEXTCHR
+       CMP     AL,'0'
+       JC      NOMORE
+       OR      AL,20H
+       CMP     AL,'z'+1
+       JNC     NOMORE
+       CMP     AL,'9'+1
+       JC      MOREID
+       CMP     AL,'a'
+       JNC     MOREID
+NOMORE:
+       MOV     CL,AL
+       MOV     AL,CH
+       MOV     [LENID],AL
+       OR      AL,AL
+       MOV     AL,CL
+       RET
+
+LETTER:
+       CALL    READID
+       MOV     AL,CH
+       DEC     AL
+       JNZ     NOFLG
+       MOV     AL,[ID]
+       MOV     CX,5
+       MOV     DI,FLGTAB
+       UP
+       REPNE
+       SCAB                    ;See if one of B,W,S,L,T
+       JZ      SAVFLG          ;Go save flag
+       XOR     AL,AL
+       MOV     CH,[LENID]
+NOFLG:
+       DEC     AL
+       PUSH    BX
+       JNZ     L0004
+       CALL    REGCHK
+L0004: 
+       POP     BX
+       MOV     AL,DH
+       JZ      SYMSAV
+       CALL    LOOKRET
+SYMSAV:
+       MOV     [SYM],AL
+       RET
+
+SAVFLG:
+       MOV     DL,CL           ;Need flag type in DL
+       XCHG    [FLAG],CL
+       CMP     CL,-1
+       MOV     CL,32
+       MOV     AL,5
+       JZ      SYMSAV
+ERRJ3: JMP     ERROR
+
+FLGTAB:        DB      "tlswb"
+
+FPREG:
+;Have detected "ST" for 8087 floating point stack register
+       MOV     DL,0            ;Default is ST(0)
+       CALL    SCANB           ;Get next character
+       CMP     AL,"("          ;Specifying register number?
+       JNZ     HAVREG
+;Get register number
+       CALL    NEXTCHR         ;Skip over the "("
+       CALL    GETOP           ;A little recursion never hurt anybody
+       CMP     AL,CONST        ;Better have found a constant
+       MOV     CL,20           ;Operand error if not
+       JNZ     ERRJ3
+       CMP     [DLABEL],0      ;Constant must be defined
+       MOV     CL,30
+       JNZ     ERRJ3
+       MOV     DX,[DATA]       ;Get constant
+       CMP     DX,7            ;Constant must be in range 0-7
+       MOV     CL,31
+       JA      ERRJ3
+       MOV     AL,[SYM]
+       CMP     AL,")"
+       MOV     CL,24
+       JNZ     ERRJ3
+HAVREG:
+       MOV     DH,FREG
+       XOR     AL,AL           ;Zero set means register found
+       RET
+
+REGCHK:
+       MOV     BX,ID
+       CMP     [BX],"s"+7400H  ;"st"
+       JZ      FPREG
+       MOV     CL,[BX]
+       INC     BX
+       MOV     AL,[BX]
+       MOV     BX,REGTAB
+       MOV     DH,XREG
+       MOV     DL,0
+       CMP     AL,'x'
+       JZ      SCANREG
+       MOV     DH,REG
+       CMP     AL,'l'
+       JZ      SCANREG
+       MOV     DL,4
+       CMP     AL,'h'
+       JZ      SCANREG
+       MOV     DH,SREG
+       MOV     DL,0
+       MOV     BX,SEGTAB
+       CMP     AL,'s'
+       JZ      SCANREG
+       MOV     DH,XREG
+       CMP     AL,'p'
+       JZ      PREG
+       CMP     AL,'i'
+       JNZ     RET
+       MOV     DL,6
+       MOV     AL,CL
+       CMP     AL,'s'
+       JZ      RET
+       INC     DL
+       CMP     AL,'d'
+       RET
+PREG:
+       MOV     DL,4
+       MOV     AL,CL
+       CMP     AL,'s'
+       JZ      RET
+       INC     DL
+       CMP     AL,'b'
+       RET
+SCANREG:
+       MOV     AL,CL
+       MOV     CX,4
+       UP
+       MOV     DI,BX
+       REPNZ
+       SCAB
+       MOV     BX,DI
+       JNZ     RET
+       MOV     AL,CL
+       ADD     AL,DL
+       MOV     DL,AL
+       XOR     AL,AL
+       RET
+
+REGTAB:        DB      'bdca'
+
+SEGTAB:        DB      'dsce'
+
+LOOK:
+       MOV     CH,[BX]
+       INC     BX
+       MOV     DX,ID
+       CALL    CPSLP
+       JZ      RET
+       XOR     AL,80H
+       ROL     AL              ;Make end-of-symbol bit least significant
+       MOV     CL,AL
+       DEC     BX
+       MOV     AL,[BX]
+       XOR     AL,80H
+       ROL     AL
+       CMP     AL,CL
+       JNC     SMALL
+       INC     CH
+       INC     CH
+SMALL:
+       MOV     DL,CH
+       MOV     DH,0
+       ADD     BX,DX
+       MOV     DX,[BX]
+       INC     BX
+       MOV     AL,DL
+       OR      AL,DH
+       STC
+       JZ      RET
+       XCHG    DX,BX
+       JP      LOOK
+
+LOOKRET:
+       MOV     AL,CH
+       CMP     AL,3    ;RET has 3 letters
+       JNZ     LOOKUP
+       DEC     BX
+       OR      B,[BX],080H
+       MOV     DX,RETSTR+2
+CHKRET:
+       MOV     SI,DX
+       LODB
+       CMP     AL,[BX]
+       JNZ     LOOKIT
+       DEC     BX
+       DEC     DX
+       DEC     CH
+       JNZ     CHKRET
+       MOV     DX,[LSTRET]
+       MOV     AL,DL
+       AND     AL,DH
+       INC     AL
+       JZ      ALLRET
+       MOV     BX,[PC]
+       SUB     BX,DX
+       MOV     AL,BL
+       CBW
+       CMP     AX,BX           ;Signed 8-bit number?
+       MOV     AL,1
+       JZ      RET
+ALLRET:
+       MOV     BX,[RETPT]
+       MOV     AL,BH
+       OR      AL,BL
+       MOV     AL,0
+       JNZ     RET
+       MOV     BX,[HEAP]
+       DEC     BX
+       DEC     BX
+       DEC     BX
+       MOV     [HEAP],BX
+       XOR     AL,AL
+       MOV     [BX],AL
+       MOV     [RETPT],BX
+       RET
+
+LOOKUP:
+       DEC     BX
+       OR      B,[BX],080H
+LOOKIT:
+       MOV     BX,[BASE]
+       MOV     AL,BH
+       OR      AL,BL
+       JZ      EMPTY
+       CALL    LOOK
+       JC      ENTER
+       MOV     DX,4
+       ADD     BX,DX
+       MOV     AL,[BX]
+       OR      AL,AL
+       JZ      RET
+       INC     BX
+       MOV     DX,[BX]
+       INC     BX
+       RET
+
+ENTER:
+       PUSH    BX              ;Save pointer to link field
+       CALL    CREATE          ;Add the node
+       POP     SI
+       MOV     [SI-1],DX       ;Link new node
+       RET                     ;Zero was set by CREATE
+
+EMPTY:
+       CALL    CREATE
+       MOV     [BASE],DX
+       RET
+
+
+CREATE:
+
+; Add a new node to the identifier tree. The identifier is at ID with
+; bit 7 of the last character set to one. The length of the identifier is
+; in LENID, which is ID-1.
+;
+; Node format:
+;      1. Length of identifier (1 byte)
+;      2. Identifier (1-80 bytes)
+;      3. Left link (2-byte pointer to alphabetically smaller identifiers)
+;      4. Right link (0 if none larger)
+;      5. Data field:
+;         a. Defined flag (0=undefined, 1=defined)
+;         b. Value (2 bytes)
+;
+; This routine returns with AL=zero and zero flag set (which indicates
+; on return from LOOKUP that it has not yet been defined), DX points
+; to start of new node, and BX points to data field of new node.
+
+       MOV     AL,[LENID]
+       ADD     AL,8            ;Storage needed for the node
+       MOV     BX,[HEAP]
+       MOV     DL,AL
+       MOV     DH,0
+       SUB     BX,DX           ;Heap grows downward
+       MOV     [HEAP],BX
+       XCHG    DX,BX
+       MOV     BX,[CODE]       ;Check to make sure there's enough
+       CMP     BX,DX
+       JB      $+5
+       JMP     ABORT
+       PUSH    DX
+       MOV     BX,LENID
+       MOV     CL,[BX]
+       INC     CL
+       MOV     CH,0
+       UP
+       MOV     SI,BX
+       MOV     DI,DX
+       REP
+       MOVB                    ;Move identifier and length into node
+       MOV     DX,DI
+       MOV     BX,SI
+       MOV     CH,4
+       XCHG    DX,BX
+NILIFY:
+       MOV     [BX],CL         ;Zero left and right links
+       INC     BX
+       DEC     CH
+       JNZ     NILIFY
+       XOR     AL,AL           ;Set zero flag
+       MOV     [BX],AL         ;Zero defined flag
+       POP     DX              ;Restore pointer to node
+       RET
+
+CPSLP:
+       MOV     SI,DX
+       LODB
+       CMP     AL,[BX]
+       LAHF
+       INC     DX
+       INC     BX
+       SAHF
+       JNZ     RET
+       DEC     CH
+       JNZ     CPSLP
+       RET
+
+GETLAB:
+       MOV     BX,0
+       MOV     [LABPT],BX
+       MOV     B,[FLAG],-1
+       MOV     DH,0
+       MOV     AL,[CHR]
+       CMP     AL,' '+1
+       JC      NOT1
+       OR      DH,001H
+NOT1:
+       CALL    GETLET
+       JC      RET
+       CMP     AL,':'
+       JNZ     LABCHK
+       CALL    NEXTCHR
+       JP      LABEL
+LABCHK:
+       OR      AL,AL
+       TEST    DH,001H
+       JZ      RET
+LABEL:
+       MOV     AL,[CHKLAB]
+       OR      AL,AL
+       JZ      $+5
+       JMP     GETLET
+       CALL    LOOKUP
+       MOV     CL,11
+       JNZ     ERR5
+       MOV     DX,[PC]
+       MOV     B,[BX],1
+       INC     BX
+       MOV     [BX],DX
+       MOV     [LABPT],BX
+       JMP     GETLET
+
+ERR5:  JMP     ERROR
+
+ASMLIN:
+       MOV     B,[MAXFLG],1    ;Allow only B and W flags normally
+       MOV     BX,[PC]
+       MOV     [OLDPC],BX
+       CALL    GETLAB
+       JNC     $+5
+       JMP     ENDLN
+       MOV     BX,LENID
+       MOV     AL,[BX]
+       MOV     CL,12
+       SUB     AL,2
+       MOV     CH,AL
+       JC      ERR5
+       INC     BX
+       CMP     B,[BX],"f"      ;See if an 8087 mnemonic
+       JZ      NDPOP
+       CMP     AL,5
+       JNC     ERR5
+       MOV     AL,[BX]
+       SUB     AL,'a'
+       MOV     CL,AL
+       ADD     AL,AL
+       ADD     AL,AL
+       ADD     AL,CL
+       ADD     AL,CH
+       ADD     AL,AL
+       MOV     BX,OPTAB
+       MOV     DL,AL
+       MOV     DH,0
+       ADD     BX,DX
+       MOV     BX,[BX]
+       INC     CH
+       MOV     CL,CH
+       MOV     AH,[BX]
+       INC     BX
+       OR      AH,AH
+       JZ      OPERR
+FINDOP:
+       MOV     CH,CL
+       MOV     DX,ID+1
+       XCHG    AX,BP           ;Save count of opcodes in BP
+       CALL    CPSLP
+       JZ      HAVOP
+       XCHG    AX,BP
+       MOV     DH,0
+       MOV     DL,CH
+       INC     DX
+       INC     DX
+       ADD     BX,DX
+       DEC     AH
+       JNZ     FINDOP
+OPERR:
+       MOV     CL,12
+       JMP     ERROR
+
+HAVOP:
+       MOV     AL,[BX+2]       ;Get opcode
+       JMP     [BX]
+
+NDPOP: ;First letter is "F" so must be 8087 opcode ("Numeric Data Processor")
+       MOV     B,[MAXFLG],4    ;Allow all type flags
+       INC     BX
+       CMP     B,[BX],"n"      ;"No-wait" form?
+       MOV     AH,0
+       JNZ     SAVNFLG
+       MOV     AH,1
+       DEC     AL
+       INC     BX              ;Skip over the "N"
+SAVNFLG:
+       MOV     [NOWAIT],AH     ;0 for wait, 1 for no wait
+       CMP     AL,1
+       JB      OPERR           ;Not enough char left for valid opcode?
+       CMP     AL,5
+       JA      OPERR           ;Too many?
+       CBW
+       XCHG    AX,DX           ;Save length in DX
+       MOV     SI,DX
+       OR      B,[SI+BX],80H   ;Set high bit of last character
+       MOV     AL,[BX]         ;Get first char of opcode
+       INC     BX
+       SUB     AL,"a"
+       JB      TRY2XM1         ;Go see if opcode starts with "2"
+       CMP     AL,"z"-"a"
+       JA      OPERR
+       CBW
+       SHL     AX              ;Double to index into address table
+       XCHG    AX,SI           ;Put in index register
+       MOV     DI,[SI+NDPTAB]  ;Get start of opcode table for this letter
+LOOKNDP:
+       MOV     AH,[DI]         ;Number of opcodes starting with this letter
+       OR      AH,AH
+       JZ      OPERR           ;Any start with this letter?
+FNDNDP:
+       INC     DI
+       MOV     SI,BX           ;Pointer to start of opcode
+       MOV     CX,DX           ;Get length of opcode
+       REPE
+       CMPB                    ;Compare opcode to table entry
+       JZ      HAVNDP
+       DEC     DI              ;Back up in case that was last letter
+       MOV     AL,80H          ;Look for char with high bit set
+ENDOP:
+       SCASB
+       JA      ENDOP
+       INC     DI              ;Skip over info about opcode
+       DEC     AH
+       JNZ     FNDNDP
+OPERRJ:        JP      OPERR
+
+TRY2XM1:
+       CMP     AL,"2"-"a"
+       JNZ     OPERR
+       MOV     DI,XM1
+       JP      LOOKNDP
+
+SPECIALOP:
+       AND     AL,7            ;Mask to special op number
+       JZ      FWAIT           ;If zero, go handle FWAIT
+;Handle FNOP
+       CMP     B,[NOWAIT],0    ;Was "N" present (If not opcode was "FOP")
+       JZ      OPERR
+       MOV     AL,9BH          ;Need Wait opcode after all
+       CALL    PUT
+       MOV     AL,0D9H
+       CALL    PUT
+       MOV     AL,0D0H
+       JMP     PUT
+
+FWAIT:
+       CMP     B,[NOWAIT],0    ;"FNWAIT" not legal
+       JNZ     OPERRJ
+       RET                     ;Nothing to do - "WAIT" already sent
+
+HAVNDP:
+       MOV     SI,DI
+       CMP     B,[NOWAIT],0
+       JNZ     NWAIT
+       MOV     AL,9BH          ;Wait opcode
+       CALL    PUT
+NWAIT:
+       LODW                    ;Get opcode info
+       TEST    AL,0F8H         ;Any operand bits set?
+       JZ      NOOPS           ;If no operands, output code
+       TEST    AL,78H          ;Special case?
+       JZ      SPECIALOP
+       PUSH    AX
+       CALL    GETSYM          ;See if any operands
+       POP     CX
+       CMP     AL,";"
+       JZ      NOOPCHK
+       CMP     AL,EOL
+       JZ      NOOPCHK
+       CMP     AL,FREG         ;Is it 8087 register?
+       JNZ     MEMOP
+       XCHG    AX,CX
+       TEST    AL,ONEREG       ;One register OK as operand?
+       JNZ     PUTREG          ;Yes - save it
+       TEST    AL,20H          ;Memory-only operation?
+       MOV     CL,20
+       JNZ     ERRJ4
+       TEST    AL,18H          ;Two-register operation?
+       JPE     ERRJ4           ;Must be exactly one bit set
+       PUSH    DX              ;Save register number
+       PUSH    AX              ;Save opcode
+       CALL    GETSYM
+       CMP     AL,","
+       MOV     CL,15H
+       JNZ     ERRJ4
+       CALL    GETSYM
+       MOV     CL,20
+       CMP     AL,FREG
+       JNZ     ERRJ4
+       POP     AX
+       POP     BX
+       XOR     AL,2            ;Flip "POP" bit
+       AND     AL,0FBH         ;Reset direction bit to ST(0)
+       OR      BL,BL           ;Is first register ST(0)?
+       JZ      ST0DEST
+       XCHG    DX,BX
+       OR      BL,BL           ;One of these must be ST(0)
+       JNZ     ERRJ4
+       XOR     AL,4            ;Flip direction
+       JMPS    PUTREG
+ST0DEST:
+       TEST    AL,2            ;Is POP bit set?
+       JNZ     ERRJ4           ;Don't allow destination ST(0) then pop
+PUTREG:
+       AND     AH,0F8H         ;Zero out register field
+       OR      AH,DL
+       OR      AH,0C0H
+       PUSH    AX
+       CALL    GETSYM          ;Get to next symbol
+       POP     AX
+       JMPS    NOOPS
+
+NOOPCHK:
+       XCHG    AX,CX
+       TEST    AL,80H          ;Is no operands OK?
+       MOV     CL,20
+       JNZ     ERRJ4
+NOOPS:
+;First test for FDIV or FSUB and reverse "R" bit if "D" bit is set
+       PUSH    AX
+       AND     AX,0E005H
+       CMP     AX,0E004H
+       POP     AX
+       JNZ     NOREV
+       XOR     AH,8            ;Reverse "R" bit
+NOREV:
+       AND     AL,7
+       OR      AL,0D8H         ;ESC hook
+       CALL    PUT
+       MOV     AL,AH
+       JMP     PUT
+
+BADFLAG:
+       MOV     CL,20H
+ERRJ4: JMP     ERROR
+
+MEMOP:
+       PUSH    CX              ;Save opcode
+       CALL    GETOP1          ;Get memory operand
+       CMP     AL,UNDEFID      ;Is it?
+       MOV     CL,20
+       JNZ     ERRJ4
+       POP     AX
+       TEST    AL,20H          ;Does it have memory format field?
+       JNZ     GETFORMAT
+       TEST    AL,8            ;Check if any memory operand legal
+       JZ      ERRJ4
+       TEST    AL,10H          ;Check for 2-op arithmetic
+       JNZ     PUTMEM          ;If not, just use as plain memory op
+GETFORMAT:
+       AND     AL,0F9H         ;Zero memory format bits
+       MOV     CL,[FLAG]
+       DEC     CL              ;Must now be in range 0-3
+       JL      BADFLAG
+       MOV     CH,AL           ;Save opcode byte
+       SHR     AL              ;Put format bits in bits 2 & 3
+       AND     AL,0CH
+       OR      AL,CL           ;Combine format bits with flag
+       MOV     BX,FORMATTAB
+       XLAT
+       OR      AL,AL           ;Valid combination?
+       JS      BADFLAG
+       OR      AH,AL           ;Possibly set new bits in second byte
+       OR      AL,CH           ;Set memory format bits
+PUTMEM:
+       AND     AL,7
+       OR      AL,0D8H
+       CALL    PUT
+       MOV     AL,AH
+       AND     AL,38H
+       OR      AL,DL           ;Combine addressing mode
+       JMP     PUTADD
+
+FORMATTAB:
+;There are 16 entries in this table. The 4-bit index is built like this:
+;      Bit 3           0 for normal memory ops, 1 if extended is OK
+;      Bit 2           0 for integer, 1 for real
+;      Bit 0 & 1       Flag: 00=W, 01=S, 10=L, 11=T
+;
+;The entries in the table are used as two 3-bit fields. Bits 0-2 are ORed
+;into the first byte of the opcode for the Memory Format field. Bits 3-6
+;are ORed into the second byte to modify the opcode for extended operands.
+;If bit 7 is set, then that combination is illegal.
+
+       DB      6,2,80H,80H     ;Normal integers
+       DB      80H,0,4,80H     ;Normal reals
+       DB      6,2,2EH,80H     ;Extended integers
+       DB      80H,0,4,2BH     ;Extended reals
+
+GRP1:
+       MOV     CX,8A09H
+       CALL    MROPS
+       MOV     CX,0C6H
+       MOV     AL,BH
+       CMP     AL,UNDEFID
+       JNZ     L0006
+       CALL    STIMM
+L0006: 
+       AND     AL,1
+       JZ      BYTIMM
+       MOV     AL,0B8H
+       OR      AL,BL
+       CALL    PUT
+       JMP     PUTWOR
+
+BYTIMM:
+       MOV     AL,0B0H
+       OR      AL,BL
+       CALL    PUT
+PUTBJ: JMP     PUTBYT
+
+IMMED:
+       MOV     AL,BH
+       CMP     AL,UNDEFID
+       JZ      STIMM
+       MOV     AL,BL
+       OR      AL,AL
+       JZ      RET
+       MOV     AL,BH
+       CALL    IMM
+       OR      AL,0C0H
+       CALL    PUT
+FINIMM:
+       MOV     AL,CL
+       POP     CX
+       TEST    AL,1
+       JZ      PUTBJ
+       CMP     AL,83H
+       JZ      PUTBJ
+       JMP     PUTWOR
+
+STIMM:
+       MOV     AL,[FLAG]
+       CALL    IMM
+       CALL    PUTADD
+       JP      FINIMM
+
+IMM:
+       AND     AL,1
+       OR      AL,CL
+       MOV     CL,AL
+       CALL    PUT
+       MOV     AL,CH
+       AND     AL,38H
+       OR      AL,BL
+       RET
+
+PUT:
+;Save byte in AL as pure code, with intermediate code bits 00. AL and
+;DI destroyed, no other registers affected.
+       PUSH    BX
+       PUSH    CX
+       MOV     CH,0            ;Flag as pure code
+       CALL    GEN
+       POP     CX
+       POP     BX
+       RET
+
+GEN:
+;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
+       MOV     B,[BX],4
+       MOV     BX,RELOC
+       MOV     AL,[BX]
+       MOV     B,[BX],0
+       MOV     DI,[IY]
+       MOV     [DI],AL
+       MOV     BX,[CODE]
+       MOV     [IY],BX
+       INC     BX
+       MOV     [CODE],BX
+       RET
+
+PUTINC:
+       INC     [PC]
+PUTCD:
+       MOV     DI,[CODE]
+       STOB
+       MOV     [CODE],DI
+       RET
+
+PUTWOR:
+;Save the word value described by [DLABEL] and [DATA] as code. If defined,
+;two bytes of pure code will be produced. Otherwise, appropriate intermediate
+;code will be generated.
+       PUSH    CX
+       MOV     CH,80H
+       PUSH    DX
+       PUSH    BX
+       JP      PUTBW
+
+PUTBYT:
+;Same as PUTWOR, above, but for byte value.
+       PUSH    CX
+       MOV     CH,40H
+       PUSH    DX
+       PUSH    BX
+       MOV     BX,[DLABEL]
+       MOV     AL,BH
+       OR      AL,BL
+       JNZ     PUTBW
+       MOV     BX,[DATA]
+       OR      AL,BH
+       JZ      PUTBW
+       INC     BH
+       JZ      PUTBW
+       MOV     CL,31
+       JMP     ERROR
+PUTBW:
+       MOV     DX,[DLABEL]
+       MOV     BX,[DATA]
+PUTCHK:
+       OR      DX,DX
+       JZ      NOUNDEF
+       MOV     AL,DL
+       CALL    PUTCD
+       MOV     AL,DH
+       CALL    PUTCD
+       MOV     AL,BL
+       CALL    PUTINC
+       MOV     AL,BH
+       TEST    CH,080H
+       JZ      SMPUT
+       CALL    GEN
+       JP      PRET
+SMPUT:
+       CALL    PUTCD
+       CALL    GEN1
+PRET:
+       POP     BX
+       POP     DX
+       POP     CX
+       RET
+
+NOUNDEF:
+       MOV     AL,BL
+       MOV     CL,BH
+       PUSH    CX
+       MOV     CH,0
+       CALL    GEN
+       POP     CX
+       MOV     AL,CL
+       TEST    CH,080H
+       MOV     CH,0
+       JZ      PRET
+       CALL    GEN
+       JP      PRET
+
+PUTADD:
+;Save complete addressing mode. Addressing mode is in AL; if this is a register
+;operation (>=C0), then the one byte will be saved as pure code. Otherwise,
+;the details of the addressing mode will be investigated and the optional one-
+;or two-byte displacement will be added, as described by [ADDR] and [ALABEL].
+       PUSH    CX
+       PUSH    DX
+       PUSH    BX
+       MOV     CH,0
+       MOV     CL,AL
+       CALL    GEN             ;Save the addressing mode as pure code
+       MOV     AL,CL
+       MOV     CH,80H
+       AND     AL,0C7H
+       CMP     AL,6
+       JZ      TWOBT           ;Direct address?
+       AND     AL,0C0H
+       JZ      PRET            ;Indirect through reg, no displacement?
+       CMP     AL,0C0H
+       JZ      PRET            ;Register to register operation?
+       MOV     CH,AL           ;Save whether one- or two-byte displacement
+TWOBT:
+       MOV     BX,[ADDR]
+       MOV     DX,[ALABEL]
+       JP      PUTCHK
+
+GRP2:
+       CALL    GETOP
+       MOV     CX,0FF30H
+       CMP     AL,UNDEFID
+       JZ      PMEM
+       MOV     CH,50H
+       CMP     AL,XREG
+       JZ      PXREG
+       MOV     CH,6
+       CMP     AL,SREG
+       JNZ     $+5
+       JMP     PACKREG
+       MOV     CL,20
+       JMP     ERROR
+
+PMEM:
+       MOV     AL,CH
+       CALL    PUT
+       MOV     AL,CL
+       OR      AL,DL
+       JMP     PUTADD
+
+PXREG:
+       MOV     AL,CH
+       OR      AL,DL
+       JMP     PUT
+
+GRP3:
+       CALL    GETOP
+       PUSH    DX
+       CALL    GETOP2
+       POP     BX
+       MOV     CX,8614H
+       MOV     AL,SREG
+       CMP     AL,BH
+       JZ      ERR6
+       CMP     AL,DH
+       JZ      ERR6
+       MOV     AL,CONST
+       CMP     AL,BH
+       JZ      ERR6
+       CMP     AL,DH
+       JZ      ERR6
+       MOV     AL,UNDEFID
+       CMP     AL,BH
+       JZ      EXMEM
+       CMP     AL,DH
+       JZ      EXMEM1
+       MOV     AL,BH
+       CMP     AL,DH
+       MOV     CL,22
+       JNZ     ERR6
+       CMP     AL,XREG
+       JZ      L0008
+       CALL    RR1
+L0008:                 ;RR1 never returns
+       MOV     AL,BL
+       OR      AL,AL
+       JZ      EXACC
+       XCHG    DX,BX
+       MOV     AL,BL
+       OR      AL,AL
+       MOV     AL,BH
+       JZ      EXACC
+       CALL    RR1
+EXACC:
+       MOV     AL,90H
+       OR      AL,DL
+       JMP     PUT
+
+EXMEM:
+       XCHG    DX,BX
+EXMEM1:
+       CMP     AL,BH
+       JZ      ERR6
+       MOV     CL,1    ;Flag word as OK
+       CALL    NOTAC   ;NOTAC never returns
+ERR6:  JMP     ERROR
+
+GRP4:
+       PUSH    AX
+       CALL    GETOP
+       POP     CX
+       XCHG    CL,CH
+       CMP     AL,CONST
+       JZ      FIXED
+       SUB     AL,XREG
+       DEC     DL
+       DEC     DL
+       OR      AL,DL
+       MOV     CL,20
+       JNZ     ERR6
+       MOV     AL,CH
+       OR      AL,8
+       JMP     PUT
+FIXED:
+       MOV     AL,CH
+       CALL    PUT
+       JMP     PUTBYT
+
+GRP5:
+       PUSH    AX
+       CALL    GETOP
+       MOV     CL,20
+       CMP     AL,CONST
+       JNZ     ERR6
+       MOV     BX,[DLABEL]
+       MOV     AL,BH
+       OR      AL,BL
+       MOV     CL,30
+       JNZ     ERR6
+       MOV     BX,[DATA]
+       POP     AX
+       OR      AL,AL
+       JZ      ORG
+       DEC     AL
+       JZ      DSJ
+       DEC     AL
+       JZ      EQU
+       DEC     AL
+       JZ      $+5
+       JMP     IF
+PUTOP:
+       MOV     AL,-3
+       JP      NEWLOC
+ALIGN:
+       MOV     AL,[PC]
+       AND     AL,1
+       JZ      RET
+       MOV     BX,1
+DSJ:
+       XCHG    DX,BX
+       MOV     BX,[PC]
+       ADD     BX,DX
+       MOV     [PC],BX
+       XCHG    DX,BX
+       MOV     AL,-4
+       JP      NEWLOC
+EQU:
+       XCHG    DX,BX
+       MOV     BX,[LABPT]
+       MOV     AL,BH
+       OR      AL,BL
+       MOV     CL,34
+       JZ      ERR7
+       MOV     [BX],DL
+       INC     BX
+       MOV     [BX],DH
+       RET
+ORG:
+       MOV     [PC],BX
+       MOV     AL,-2
+NEWLOC:
+       CALL    PUTCD
+       MOV     AL,BL
+       CALL    PUTCD
+       MOV     AL,BH
+       CALL    PUTCD
+       MOV     CH,0C0H
+       JMP     GEN1
+GRP6:
+       MOV     CH,AL
+       MOV     CL,4
+       CALL    MROPS
+       MOV     CL,23
+ERR7:  JMP     ERROR
+GRP7:
+       MOV     CH,AL
+       MOV     CL,1
+       CALL    MROPS
+       MOV     CL,80H
+       MOV     DX,[DLABEL]
+       MOV     AL,DH
+       OR      AL,DL
+       JNZ     ACCJ
+       XCHG    DX,BX
+       MOV     BX,[DATA]
+       MOV     AL,BL
+       CBW
+       CMP     AX,BX
+       XCHG    DX,BX
+       JNZ     ACCJ
+       OR      CL,002H
+ACCJ:  JMP     ACCIMM
+GRP8:
+       MOV     CL,AL
+       MOV     CH,0FEH
+       JP      ONEOP
+GRP9:
+       MOV     CL,AL
+       MOV     CH,0F6H
+ONEOP:
+       PUSH    CX
+       CALL    GETOP
+ONE:
+       MOV     CL,26
+       CMP     AL,CONST
+       JZ      ERR7
+       CMP     AL,SREG
+       MOV     CL,22
+       JZ      ERR7
+       POP     CX
+       CMP     AL,UNDEFID
+       JZ      MOP
+       AND     AL,1
+       JZ      ROP
+       TEST    CL,001H
+       JZ      ROP
+       MOV     AL,CL
+       AND     AL,0F8H
+       OR      AL,DL
+       JMP     PUT
+MOP:
+       MOV     AL,[FLAG]
+       AND     AL,1
+       OR      AL,CH
+       CALL    PUT
+       MOV     AL,CL
+       AND     AL,38H
+       OR      AL,DL
+       JMP     PUTADD
+ROP:
+       OR      AL,CH
+       CALL    PUT
+       MOV     AL,CL
+       AND     AL,38H
+       OR      AL,0C0H
+       OR      AL,DL
+       JMP     PUT
+GRP10:
+       MOV     CL,AL
+       MOV     CH,0F6H
+       PUSH    CX
+       CALL    GETOP
+       MOV     CL,20
+       MOV     AL,DL
+       OR      AL,AL
+       JNZ     ERRJ1
+       MOV     AL,DH
+       CMP     AL,XREG
+       JZ      G10
+       CMP     AL,REG
+ERRJ1: JNZ     ERR8
+G10:
+       PUSH    AX
+       CALL    GETOP
+       POP     AX
+       AND     AL,1
+       MOV     [FLAG],AL
+       MOV     AL,DH
+ONEJ:  JP      ONE
+GRP11:
+       CALL    PUT
+       MOV     AL,0AH
+       JMP     PUT
+GRP12:
+       MOV     CL,AL
+       MOV     CH,0D0H
+       PUSH    CX
+       CALL    GETOP
+       MOV     AL,[SYM]
+       CMP     AL,','
+       MOV     AL,DH
+       JNZ     ONEJ
+       PUSH    DX
+       CALL    GETOP
+       SUB     AL,REG
+       MOV     CL,20
+       DEC     DL
+       OR      AL,DL
+       JNZ     ERR8
+       POP     DX
+       MOV     AL,DH
+       POP     CX
+       OR      CH,002H
+       PUSH    CX
+       JMP     ONE
+GRP13:
+       MOV     CH,AL
+       MOV     CL,1
+       CALL    MROPS
+       MOV     CL,80H
+ACCIMM:
+       CALL    IMMED
+       OR      CH,004H
+       AND     CH,0FDH
+AIMM:
+       MOV     AL,BH
+       AND     AL,1
+       LAHF
+       PUSH    AX
+       OR      AL,CH
+       CALL    PUT
+       POP     AX
+       SAHF
+       JNZ     $+5
+       JMP     PUTBYT
+       JMP     PUTWOR
+
+ERR8:  JMP     ERROR
+
+GRP14:
+;JMP and CALL mnemonics
+       LAHF
+       XCHG    AH,AL
+       PUSH    AX
+       XCHG    AH,AL
+       MOV     B,[MAXFLG],3    ;Allow "L" flag
+       CALL    GETOP
+       CMP     AL,CONST
+       JZ      DIRECT
+       MOV     CL,20
+       CMP     AL,REG
+       JZ      ERR8
+       CMP     AL,SREG
+       JZ      ERR8
+       CMP     AL,XREG
+       JNZ     NOTRG
+       OR      DL,0C0H
+NOTRG:
+;Indirect jump. DL has addressing mode.
+       MOV     AL,0FFH
+       CALL    PUT
+       POP     AX
+       XCHG    AH,AL
+       SAHF
+       AND     AL,38H
+       OR      AL,DL
+       MOV     CH,[FLAG]
+       CMP     CH,3            ;Flag "L" present?
+       JZ      PUTADDJ         ;If so, do inter-segment
+       MOV     CL,27H
+       CMP     CH,-1           ;Better not be a flag
+       JNZ     ERR8
+       AND     AL,0F7H         ;Convert to intra-segment
+PUTADDJ:
+       JMP     PUTADD
+DIRECT:
+       MOV     AL,[SYM]
+       CMP     AL,','
+       JZ      LONGJ
+       POP     AX
+       XCHG    AH,AL
+       SAHF
+       DEC     AL
+       CMP     AL,0E9H
+       JZ      GOTOP
+       MOV     AL,0E8H
+GOTOP:
+       CALL    PUT
+       MOV     DX,[PC]
+       INC     DX
+       INC     DX
+       SUB     [DATA],DX
+       JMP     PUTWOR
+LONGJ:
+       POP     AX
+       XCHG    AH,AL
+       SAHF
+       CALL    PUT
+       CALL    PUTWOR
+       CALL    GETOP
+       MOV     CL,20
+       CMP     AL,CONST
+       JNZ     ERR8
+       JMP     PUTWOR
+
+GRP16:
+;RET mnemonic
+       LAHF
+       XCHG    AH,AL
+       PUSH    AX
+       XCHG    AH,AL
+       CALL    GETSYM
+       CMP     AL,5
+       JZ      LONGR
+       CMP     AL,EOL
+       JZ      NODEC
+       CMP     AL,';'
+       JZ      NODEC
+GETSP:
+       CALL    GETOP1
+       POP     CX
+       CMP     AL,CONST
+       MOV     CL,20
+       JNZ     ERR9
+       MOV     AL,CH
+       AND     AL,0FEH
+       CALL    PUT
+       JMP     PUTWOR
+LONGR:
+       CMP     DL,3            ;Is flag "L"?
+       MOV     CL,27H
+       JNZ     ERR10           ;If not, bad flag
+       POP     AX
+       XCHG    AH,AL
+       SAHF
+       OR      AL,8
+       LAHF
+       XCHG    AH,AL
+       PUSH    AX
+       XCHG    AH,AL
+NOTLON:
+       CALL    GETSYM
+       CMP     AL,EOL
+       JZ      DORET
+       CMP     AL,';'
+       JZ      DORET
+       CMP     AL,','
+       JNZ     L0011
+       CALL    GETSYM
+L0011: 
+       JP      GETSP
+NODEC:
+;Return is intra-segment (short) without add to SP. 
+;Record position for RET symbol.
+       MOV     BX,[PC]
+       MOV     [LSTRET],BX
+       XCHG    DX,BX
+       MOV     BX,[RETPT]
+       MOV     AL,BH
+       OR      AL,BL
+       JZ      DORET
+       MOV     B,[BX],1
+       INC     BX
+       MOV     [BX],DX
+       MOV     BX,0
+       MOV     [RETPT],BX
+DORET:
+       POP     AX
+       XCHG    AH,AL
+       SAHF
+       JMP     PUT
+
+GRP17:
+       CALL    PUT
+       CALL    GETOP
+       CMP     AL,CONST
+       MOV     CL,20
+ERR9:  JNZ     ERR10
+       MOV     BX,[DATA]
+       MOV     DX,[PC]
+       INC     DX
+       SUB     BX,DX
+       MOV     [DATA],BX
+       CALL    PUTBYT
+       MOV     BX,[DLABEL]
+       MOV     AL,BH
+       OR      AL,BL
+       JNZ     RET
+       MOV     BX,[DATA]
+       MOV     AL,BL
+       CBW
+       CMP     AX,BX           ;Signed 8-bit number?
+       JZ      RET
+       MOV     CL,31
+ERR10: JMP     ERROR
+       RET
+GRP18:
+       CALL    GETOP
+       CMP     AL,CONST
+       MOV     CL,20
+       JNZ     ERR10
+       MOV     BX,[DLABEL]
+       MOV     AL,BH
+       OR      AL,BL
+       JNZ     GENINT
+       MOV     BX,[DATA]
+       MOV     DX,3
+       SBB     BX,DX
+       JNZ     GENINT
+       MOV     AL,0CCH
+       JMP     PUT
+GENINT:
+       MOV     AL,0CDH
+       CALL    PUT
+       JMP     PUTBYT
+
+GRP19: ;ESC opcode
+       CALL    GETOP
+       MOV     CL,20
+       CMP     AL,CONST
+       JNZ     ERRJ            ;First operand must be immediate
+       MOV     CL,1EH
+       TEST    [DLABEL],-1     ;See if all labels have been defined
+       JNZ     ERRJ
+       MOV     AX,[DATA]
+       CMP     AX,64           ;Must only be 6 bits
+       MOV     CL,1FH
+       JNB     ERRJ
+       MOV     BL,AL           ;Save for second byte
+       SHR     AL
+       SHR     AL
+       SHR     AL
+       OR      AL,0D8H         ;ESC opcode
+       CALL    PUT
+       PUSH    BX
+       CALL    GETOP2
+       POP     BX
+       AND     BL,7            ;Low 3 bits of first operand
+       SHL     BL
+       SHL     BL
+       SHL     BL
+       CMP     AL,UNDEFID      ;Check for memory operand
+       JZ      ESCMEM
+       CMP     AL,CONST        ;Check for another immediate
+       JZ      ESCIMM
+       MOV     CL,20
+ERRJ:  JMP     ERROR
+
+ESCMEM:
+       OR      BL,DL           ;Combine mode with first operand
+       MOV     AL,BL
+       JMP     PUTADD
+
+ESCIMM:
+       MOV     CL,1EH
+       TEST    [DLABEL],-1     ;See if second operand is fully defined
+       JNZ     ERRJ
+       MOV     AX,[DATA]
+       MOV     CL,1FH
+       CMP     AX,8            ;Must only be 3 bit value
+       JNB     ERRJ
+       OR      AL,BL           ;Combine first and second operands
+       OR      AL,0C0H         ;Force "register" mode
+       JMP     PUT
+
+GRP20:
+       MOV     CH,AL
+       MOV     CL,1
+       CALL    MROPS
+       MOV     CL,0F6H
+       CALL    IMMED
+       MOV     CH,0A8H
+       JMP     AIMM
+GRP21:
+       CALL    GETOP
+       CMP     AL,SREG
+       MOV     CL,28
+       JNZ     ERRJ
+       MOV     CH,26H
+PACKREG:
+       MOV     AL,DL
+       ADD     AL,AL
+       ADD     AL,AL
+       ADD     AL,AL
+       OR      AL,CH
+       JMP     PUT
+GRP22:
+       CALL    GETOP
+       MOV     CX,8F00H
+       CMP     AL,UNDEFID
+       JNZ     $+5
+       JMP     PMEM
+       MOV     CH,58H
+       CMP     AL,XREG
+       JNZ     $+5
+       JMP     PXREG
+       MOV     CH,7
+       CMP     AL,SREG
+       JZ      PACKREG
+       MOV     CL,20
+ERR11: JMP     ERROR
+GRP23:
+       MOV     [DATSIZ],AL
+GETDAT:
+       CALL    GETSYM
+       MOV     AL,2
+       CALL    VAL1
+       MOV     AL,[SYM]
+       CMP     AL,','
+       MOV     AL,[DATSIZ]
+       JNZ     ENDDAT
+       CALL    SAVDAT
+       JP      GETDAT
+ENDDAT:
+       CMP     AL,2
+       JNZ     SAVDAT
+       MOV     BX,[DATA]
+       LAHF
+       OR      BL,080H
+       SAHF
+       MOV     [DATA],BX
+SAVDAT:
+       OR      AL,AL
+       JZ      $+5
+       JMP     PUTBYT
+       JMP     PUTWOR
+IF:
+       OR      BX,BX
+       JZ      SKIPCD
+       INC     B,[IFFLG]
+       RET
+
+SKIPCD:
+       INC     B,[CHKLAB]
+SKIPLP:
+       XOR     AL,AL
+       CALL    NEXLIN
+       CALL    NEXTCHR
+       CMP     AL,1AH
+       JZ      END
+       CALL    GETLAB
+       JC      SKIPLP
+       MOV     DI,LENID
+       MOV     SI,IFEND
+       MOV     CH,0
+       MOV     CL,[DI]
+       INC     CL
+       REPE
+       CMPB
+       JZ      ENDCOND
+       MOV     DI,LENID
+       MOV     SI,IFNEST
+       MOV     CL,[DI]
+       INC     CL
+       REPE
+       CMPB
+       JNZ     SKIPLP
+       INC     B,[CHKLAB]
+       JP      SKIPLP
+
+ENDCOND:
+       DEC     B,[CHKLAB]
+       JNZ     SKIPLP
+       RET
+
+ENDIF:
+       MOV     AL,[IFFLG]
+       MOV     CL,36
+       DEC     AL
+       JS      ERRJMP
+       MOV     [IFFLG],AL
+       RET
+
+ERRJMP:        JMP     ERROR
+
+;*********************************************************************
+;
+;      PASS 2
+;
+;*********************************************************************
+
+END:
+       MOV     DL,4
+WREND:
+       MOV     CH,0FFH
+       MOV     AL,CH
+       CALL    GEN
+       DEC     DL
+       JNZ     WREND
+       MOV     [BUFPT],SRCBUF
+       MOV     B,[HEXCNT],-5   ;FLAG HEX BUFFER AS EMPTY
+       MOV     [LSTPNT],LSTBUF
+       MOV     [HEXPNT],HEXBUF
+       XOR     AX,AX
+       MOV     [ERRCNT],AX
+       MOV     [PC],AX
+       MOV     [LINE],AX       ;Current line number
+       MOV     [HEXADD],OBJECT
+       MOV     DX,FCB
+       MOV     AH,OPEN
+       INT     33              ;Re-open source file
+       XOR     AX,AX
+       MOV     [FCB+12],AX     ;Set CURRENT BLOCK to zero
+       MOV     [FCB+20H],AL    ;Set NEXT RECORD field to zero
+       MOV     [FCB+14],BUFSIZ
+       MOV     [COUNT],AL
+       MOV     CH,1
+       MOV     SI,START
+FIXLINE:
+       MOV     DI,START        ;Store code over used up intermediate code
+       XOR     AL,AL
+       MOV     [SPC],AL        ;No "special" yet (ORG, PUT, DS)
+       MOV     [ERR],AL        ;No second pass errors yet
+NEXBT:
+       SHL     CL              ;Shift out last bit of previous code
+       DEC     CH              ;Still have codes left?
+       JNZ     TESTTYP
+       LODB                    ;Get next flag byte
+       MOV     CL,AL
+       MOV     CH,4
+TESTTYP:
+       SHL     CL              ;Set flags based on two bits
+       JO      FIXUP
+       LODB
+       JC      EMARK
+OBJBT:
+       STOB
+       JP      NEXBT
+
+FIXUP:
+;Either a word or byte fixup is needed from a forward reference
+       LODW                    ;Get pointer to symbol
+       XCHG    AX,BX
+       LODW                    ;Get constant part
+       ADD     AX,[BX+1]       ;Add symbol value to constant part
+       CMP     B,[BX],0        ;See if symbol got defined
+       JNZ     HAVDEF
+       MOV     B,[ERR],100     ;Undefined - flag error
+       XOR     AX,AX
+HAVDEF:
+       OR      CL,CL           ;See if word or byte fixup
+       JS      DEFBYT
+       STOW
+       JP      NEXBT
+
+DEFBYT:
+       MOV     DX,AX
+       CBW                     ;Extend sign
+       CMP     AX,DX           ;See if in range +127 to -128
+       JZ      OBJBT           ;If so, it's always OK
+       NOT     AH              ;Check for range +255 to -256
+       CMP     AH,DH
+       JNZ     RNGERR          ;Must always be in this range
+;Check for short jump. If so, we're out of range; otherwise we're OK
+       CMP     DI,START+1      ;Only one other byte on line?
+       JNZ     OBJBT           ;Can't be short jump if not
+       MOV     AL,[START]      ;Get the first byte of this line
+       CMP     AL,0EBH         ;Direct short jump?
+       JZ      RNGERR
+       AND     AL,0FCH
+       CMP     AL,0E0H         ;LOOP or JCXZ instruction?
+       JZ      RNGERR
+       AND     AL,0F0H
+       CMP     AL,70H          ;Conditional jump?
+       MOV     AL,DL           ;Get code byte in AL
+       JNZ     OBJBT           ;If not, we're OK
+RNGERR:
+       MOV     B,[ERR],101     ;Value out of range
+       JP      OBJBT
+
+FINIJ: JMP     FINI
+
+EMARK:
+       CMP     AL,-1           ;End of file?
+       JZ      FINIJ
+       CMP     AL,-10          ;Special item?
+       JA      SPEND
+       PUSH    CX
+       PUSH    SI
+       PUSH    AX              ;Save error code
+       MOV     AH,[LSTDEV]
+       AND     AH,0FEH         ;Reset error indicator
+       OR      AL,[ERR]        ;See if any errors on this line
+       JZ      NOERR
+       OR      AH,1            ;Send line to console if error occured
+NOERR:
+       MOV     [LSTDEV],AH
+       MOV     CX,DI
+       CALL    STRTLIN         ;Print address of line
+       MOV     SI,START
+       SUB     CX,SI           ;Get count of bytes of code
+       JZ      SHOLIN
+CODLP:
+       LODB
+       CALL    SAVCD           ;Ouput code to HEX and PRN files
+       LOOP    CODLP
+SHOLIN:
+       MOV     AL,0
+       XCHG    AL,[COUNT]
+       MOV     CX,7            ;Allow 7 bytes of code per line
+       SUB     CL,AL
+       MOV     AL,' '
+       JZ      NOFIL
+BLNK:                          ;Put in 3 blanks for each byte not present
+       CALL    LIST
+       CALL    LIST
+       CALL    LIST
+       LOOP    BLNK
+NOFIL:
+       CALL    OUTLIN
+       POP     AX              ;Restore error code
+       CALL    REPERR
+       MOV     AL,[ERR]
+       CALL    REPERR
+       POP     SI
+       POP     CX
+       MOV     AL,[SPC]        ;Any special funtion?
+       OR      AL,AL
+       JNZ     SPCFUN
+       JMP     FIXLINE
+
+SPEND:
+       MOV     [SPC],AL        ;Record special function
+       LODW                    ;Get it's data
+       MOV     [DATA],AX
+       JMP     NEXBT
+
+SPCFUN:
+       MOV     DX,[DATA]
+       CMP     AL,-2
+       JZ      DORG
+       CMP     AL,-3
+       JZ      DPUT
+DDS:
+;Handle DS pseudo-op
+       ADD     [PC],DX
+       ADD     [HEXADD],DX
+       JMP     FIXLINE
+
+DORG:
+;Handle ORG pseudo-op
+       MOV     [PC],DX
+       JMP     FIXLINE
+
+DPUT:
+;Handle PUT pseudo-op
+       MOV     [HEXADD],DX
+       JMP     FIXLINE
+
+OUTLIN:
+;Copy the source line to the ouput device. Line will be preceded by
+;assembler-generated line number. This routine may be called several times
+;on one line (once for each line of object code bytes), so it sets a flag
+;so the line will only be output on the first call.
+       MOV     AL,-1
+       XCHG    AL,[LINFLG]
+       OR      AL,AL
+       JNZ     CRLF            ;Output line only if first time
+       MOV     AX,[LINE]
+       INC     AX
+       MOV     [LINE],AX
+       MOV     BH,0            ;No leading zero suppression
+       CALL    OUT10
+       MOV     AL," "
+       CALL    LIST
+       MOV     AL,[LSTFCB]
+       CMP     AL,'Z'
+       JZ      CRLF            ;Don't call NEXTCHR if listing suppressed
+       PUSH    SI              ;Save the only register destroyed by NEXTCHR
+OUTLN:
+       CALL    NEXTCHR
+       CALL    LIST
+       CMP     AL,10           ;Output until linefeed found
+       JNZ     OUTLN
+       POP     SI
+       RET
+
+PRTCNT:
+       MOV     AX,[ERRCNT]
+       MOV     BX,ERCNTM
+PRNT10:
+       PUSH    AX
+       CALL    PRINT
+       POP     AX
+       MOV     BH,"0"-" "      ;Enable leading zero suppression
+       CALL    OUT10
+CRLF:
+       MOV     AL,13
+       CALL    LIST
+       MOV     AL,10
+       JP      LIST
+
+OUT10:
+       XOR     DX,DX
+       MOV     DI,10000
+       DIV     AX,DI
+       OR      AL,AL           ;>10,000?
+       JNZ     LEAD
+       SUB     AL,"0"-" "      ;Convert leading zero to blank
+LEAD:
+       ADD     AL,"0"
+       CALL    LIST
+       XCHG    AX,DX
+       MOV     BL,100
+       DIV     AL,BL
+       MOV     BL,AH
+       CALL    HIDIG           ;Convert to decimal and print 1000s digit
+       CALL    DIGIT           ;Print 100s digit
+       MOV     AL,BL
+       CALL    HIDIG           ;Convert to decimal and print 10s digit
+       MOV     BH,0            ;Ensure leading zero suppression is off
+       JP      DIGIT
+
+HIDIG:
+       AAM                     ;Convert binary to unpacked BCD
+       OR      AX,3030H        ;Add "0" bias
+DIGIT:
+       XCHG    AL,AH
+       CMP     AL,"0"
+       JZ      SUPZ
+       MOV     BH,0            ;Turn off zero suppression if not zero
+SUPZ:
+       SUB     AL,BH           ;Convert leading zeros to blanks
+       JP      LIST
+
+STRTLIN:
+       MOV     B,[LINFLG],0
+       MOV     BX,[PC]
+       MOV     AL,BH
+       CALL    PHEX
+       MOV     AL,BL
+PHEXB:
+       CALL    PHEX
+       MOV     AL,' '
+LIST:
+       PUSH    AX
+       PUSH    DX
+       AND     AL,7FH
+       MOV     DL,AL
+       TEST    B,[LSTDEV],3    ;See if output goes to console
+       JZ      PRNCHK
+       MOV     AH,2
+       INT     33              ;Output to console
+PRNCHK:
+       TEST    B,[LSTDEV],4    ;See if output goes to printer
+       JZ      FILCHK
+       MOV     AH,5
+       INT     33              ;Output to printer
+FILCHK:
+       MOV     AL,DL
+       POP     DX
+       TEST    B,[LSTDEV],80H  ;See if output goes to a file
+       JZ      LISTRET
+       CALL    WRTBUF
+LISTRET:
+       POP     AX
+       RET
+
+WRTBUF:
+       PUSH    DI
+       MOV     DI,[LSTPNT]
+       STOB
+       CMP     DI,LSTBUF+LSTBUFSIZ
+       JNZ     SAVPT
+       PUSH    AX
+       PUSH    CX
+       PUSH    DX
+       CALL    FLUSHBUF
+       POP     DX
+       POP     CX
+       POP     AX
+SAVPT:
+       MOV     [LSTPNT],DI
+       POP     DI
+       RET
+
+PHEX:
+       PUSH    AX
+       CALL    UHALF
+       CALL    LIST
+       POP     AX
+       CALL    LHALF
+       JP      LIST
+
+FINI:
+       OR      B,[LSTDEV],1
+       CALL    PRTCNT
+       MOV     BX,SYMSIZE
+       MOV     AX,[6]
+       SUB     AX,[HEAP]               ;Size of symbol table
+       CALL    PRNT10
+       MOV     BX,FRESIZE
+       MOV     AX,[HEAP]
+       SUB     AX,[CODE]               ;Free space remaining
+       CALL    PRNT10
+       AND     B,[LSTDEV],0FEH
+       MOV     AL,[HEXFCB]
+       CMP     AL,'Z'
+       JZ      SYMDMP
+       MOV     AL,[HEXCNT]
+       CMP     AL,-5
+       JZ      L0012
+       CALL    ENHEXL
+L0012: 
+       MOV     AL,':'
+       CALL    PUTCHR
+       MOV     CH,10
+HEXEND:
+       PUSH    CX
+       MOV     AL,'0'
+       CALL    PUTCHR
+       POP     CX
+       DEC     CH
+       JNZ     HEXEND
+       MOV     AL,13
+       CALL    PUTCHR
+       MOV     AL,10
+       CALL    PUTCHR
+       MOV     AL,1AH
+       CALL    PUTCHR
+       CALL    WRTHEX          ;Flush HEX file buffer
+       MOV     DX,HEXFCB
+       MOV     AH,CLOSE
+       INT     33
+SYMDMP:
+       MOV     AL,[SYMFLG]
+       CMP     AL,'S'
+       JNZ     ENDSYM
+       MOV     AL,[LSTDEV]
+       OR      AL,AL           ;Any output device for symbol table dump?
+       JNZ     DOSYMTAB
+       OR      AL,1            ;If not, send it to console
+       MOV     [LSTDEV],AL
+DOSYMTAB:
+       MOV     BX,SYMMES
+       CALL    PRINT
+       MOV     DX,[BASE]
+       MOV     AL,DH
+       OR      AL,DL
+       JZ      ENDSYM
+       MOV     B,[SYMLIN],SYMWID  ;No symbols on this line yet
+       MOV     BX,[HEAP]
+       MOV     SP,BX           ;Need maximum stack for recursive tree walk
+       CALL    NODE
+ENDSYM:
+       TEST    B,[LSTDEV],80H  ;Print listing to file?
+       JZ      EXIT
+       MOV     AL,1AH
+       CALL    WRTBUF          ;Write end-of-file mark
+       MOV     DI,[LSTPNT]
+       CALL    FLUSHBUF
+       MOV     AH,CLOSE
+       INT     33
+EXIT:  JMP     0
+
+NODE:
+       XCHG    DX,BX
+       PUSH    BX
+       MOV     DL,[BX]
+       MOV     DH,0
+       INC     BX
+       ADD     BX,DX
+       MOV     DX,[BX]
+       OR      DX,DX
+       JZ      L0014
+       CALL    NODE
+L0014: 
+       POP     BX
+       MOV     AL,[BX]
+       INC     BX
+       MOV     CH,AL
+       ADD     AL,24
+       SHR     AL
+       SHR     AL
+       SHR     AL
+       MOV     CL,AL
+       INC     CL              ;Invert last bit
+       AND     CL,1            ;Number of extra tabs needed (0 or 1)
+       SHR     AL              ;Number of positions wide this symbol needs
+       SUB     [SYMLIN],AL
+       JNC     WRTSYM          ;Will it fit?
+       SUB     AL,SYMWID
+       NEG     AL
+       MOV     [SYMLIN],AL
+       CALL    CRLF            ;Start new line if not
+WRTSYM:
+       MOV     AL,[BX]
+       INC     BX
+       CALL    LIST
+       DEC     CH
+       JNZ     WRTSYM
+       INC     CL
+TABVAL:
+       MOV     AL,9
+       CALL    LIST
+       LOOP    TABVAL
+       INC     BX
+       INC     BX
+       PUSH    BX
+       MOV     AL,[BX+4]
+       CALL    PHEX
+       MOV     AL,[BX+3]
+       CALL    PHEX
+       CMP     B,[SYMLIN],0    ;Will any more fit on line?
+       JZ      NEXSYMLIN
+       MOV     AL,9
+       CALL    LIST
+       JP      RIGHTSON
+NEXSYMLIN:
+       CALL    CRLF
+       MOV     B,[SYMLIN],SYMWID
+RIGHTSON:
+       POP     BX
+       MOV     DX,[BX]
+       OR      DX,DX
+       JNZ     NODE
+       RET
+
+SAVCD:
+       MOV     [PREV],AL
+       PUSH    BX
+       PUSH    CX
+       PUSH    AX
+       PUSH    DX
+       CALL    CODBYT
+       POP     DX
+       MOV     BX,COUNT
+       INC     B,[BX]
+       MOV     AL,[BX]
+       CMP     AL,8
+       JNZ     NOEXT
+       MOV     B,[BX],1
+       CALL    OUTLIN
+       MOV     AL,' '
+       MOV     CH,5
+TAB:
+       CALL    LIST
+       DEC     CH
+       JNZ     TAB
+NOEXT:
+       POP     AX
+       CALL    PHEXB
+       POP     CX
+       INC     [PC]
+       INC     [HEXADD]
+       POP     BX
+       RET
+
+REPERR:
+       OR      AL,AL           ;Did an error occur?
+       JZ      RET
+       INC     [ERRCNT]
+       PUSH    AX
+       MOV     BX,ERRMES       ;Print "ERROR"
+       CALL    PRINT
+       POP     AX
+;We have error number in AL. See if there's an error message for it
+       MOV     DI,ERRTAB
+       MOV     BL,80H
+ERRLOOK:
+       SCASB                   ;Do we have the error message
+       JBE     HAVMES          ;Quit looking if we have it or passed it
+       XCHG    AX,BX           ;Put 80H in AL to look for end of this message
+NEXTMES:
+       SCASB                   ;Look for high bit set in message
+       JA      NEXTMES         ;   which means we've reached the end
+       XCHG    AX,BX           ;Restore error number to AL
+       JMPS    ERRLOOK         ;Keep looking
+
+HAVMES:
+       MOV     BX,DI           ;Put address of message in BX
+       JZ      PRNERR          ;Do we have a message for this error?
+       CALL    PHEX            ;If not, just print error number
+       JMP     CRLF
+
+PRNERR:
+       CALL    PRINT
+       JMP     CRLF
+
+PRINT:
+       MOV     AL,[BX]
+       CALL    LIST
+       OR      AL,AL
+       JS      RET
+       INC     BX
+       JP      PRINT
+
+OUTA:
+       MOV     DL,AL
+OUT:
+       AND     DL,7FH
+       MOV     CL,2
+SYSTEM:
+       CALL    5
+       RET
+
+CODBYT:
+       CMP     B,[HEXFCB],"Z"
+       JZ      RET
+       PUSH    AX
+       MOV     DX,[LASTAD]
+       MOV     BX,[HEXADD]
+       MOV     [LASTAD],BX
+       INC     DX
+       MOV     AL,[HEXCNT]
+       CMP     AL,-5
+       JZ      NEWLIN
+       CMP     BX,DX
+       JZ      AFHEX
+       CALL    ENHEXL
+NEWLIN:
+       MOV     AL,':'
+       CALL    PUTCHR
+       MOV     AL,-4
+       MOV     [HEXCNT],AL
+       XOR     AL,AL
+       MOV     [CHKSUM],AL
+       MOV     BX,[HEXPNT]
+       MOV     [HEXLEN],BX
+       CALL    HEXBYT
+       MOV     AL,[HEXADD+1]
+       CALL    HEXBYT
+       MOV     AL,[HEXADD]
+       CALL    HEXBYT
+       XOR     AL,AL
+       CALL    HEXBYT
+AFHEX:
+       POP     AX
+HEXBYT:
+       MOV     CH,AL
+       MOV     BX,CHKSUM
+       ADD     AL,[BX]
+       MOV     [BX],AL
+       MOV     AL,CH
+       CALL    UHALF
+       CALL    PUTCHR
+       MOV     AL,CH
+       CALL    LHALF
+       CALL    PUTCHR
+       MOV     BX,HEXCNT
+       INC     B,[BX]
+       MOV     AL,[BX]
+       CMP     AL,26
+       JNZ     RET
+ENHEXL:
+       MOV     DI,[HEXLEN]
+       MOV     CH,AL
+       CALL    UHALF
+       STOB
+       MOV     AL,CH
+       CALL    LHALF
+       STOB
+       MOV     AL,-6
+       MOV     [HEXCNT],AL
+       MOV     AL,[CHKSUM]
+       ADD     AL,CH
+       NEG     AL
+       CALL    HEXBYT
+       MOV     AL,13
+       CALL    PUTCHR
+       MOV     AL,10
+       CALL    PUTCHR
+WRTHEX:
+;Write out the line
+       MOV     DX,HEXBUF
+       MOV     [HEXPNT],DX
+       MOV     AH,SETDMA
+       INT     33
+       SUB     DI,DX           ;Length of buffer
+       MOV     CX,DI
+       MOV     DX,HEXFCB
+       MOV     AH,BLKWRT
+       INT     33
+       OR      AL,AL
+       JNZ     DSKFUL
+       RET
+
+PUTCHR:
+       MOV     DI,[HEXPNT]
+       STOB
+       MOV     [HEXPNT],DI
+       RET
+
+FLUSHBUF:
+       MOV     CX,DI
+       MOV     DX,LSTBUF
+       MOV     DI,DX
+       SUB     CX,DX
+       JZ      RET             ;Buffer empty?
+       MOV     AH,SETDMA
+       INT     33
+       MOV     DX,LSTFCB
+       MOV     AH,BLKWRT
+       INT     33
+       OR      AL,AL
+       JZ      RET
+DSKFUL:
+       MOV     BX,WRTERR
+       JMP     PRERR
+
+UHALF:
+       RCR     AL
+       RCR     AL
+       RCR     AL
+       RCR     AL
+LHALF:
+       AND     AL,0FH
+       OR      AL,30H
+       CMP     AL,'9'+1
+       JC      RET
+       ADD     AL,7
+       RET
+
+NONE:  DB      0
+
+; 8086 MNEMONIC TABLE
+
+; This table is actually a sequence of subtables, each starting with a label.
+; The label signifies which mnemonics the subtable applies to--A3, for example,
+; means all 3-letter mnemonics beginning with A.
+
+A3:
+       DB      7
+       DB      'dd'
+       DW      GRP7
+       DB      2
+       DB      'nd'
+       DW      GRP13
+       DB      22H
+       DB      'dc'
+       DW      GRP7
+       DB      12H
+       DB      'aa'
+       DW      PUT
+       DB      37H
+       DB      'as'
+       DW      PUT
+       DB      3FH
+       DB      'am'
+       DW      GRP11
+       DB      0D4H
+       DB      'ad'
+       DW      GRP11
+       DB      0D5H
+A5:
+       DB      1
+       DB      'lign'
+       DW      ALIGN
+       DB      0
+C3:
+       DB      7
+       DB      'mp'
+       DW      GRP7
+       DB      3AH
+       DB      'lc'
+       DW      PUT
+       DB      0F8H
+       DB      'ld'
+       DW      PUT
+       DB      0FCH
+       DB      'li'
+       DW      PUT
+       DB      0FAH
+       DB      'mc'
+       DW      PUT
+       DB      0F5H
+       DB      'bw'
+       DW      PUT
+       DB      98H
+       DB      'wd'
+       DW      PUT
+       DB      99H
+C4:
+       DB      3
+       DB      'all'
+       DW      GRP14
+       DB      9AH
+       DB      'mpb'
+       DW      PUT
+       DB      0A6H
+       DB      'mpw'
+       DW      PUT
+       DB      0A7H
+C5:
+       DB      2
+       DB      'mpsb'
+       DW      PUT
+       DB      0A6H
+       DB      'mpsw'
+       DW      PUT
+       DB      0A7H
+D2:
+       DB      5
+       DB      'b'
+       DW      GRP23
+       DB      1
+       DB      'w'
+       DW      GRP23
+       DB      0
+       DB      'm'
+       DW      GRP23
+       DB      2
+       DB      's'
+       DW      GRP5
+       DB      1
+       DB      'i'
+       DW      PUT
+       DB      0FAH
+D3:
+       DB      4
+       DB      'ec'
+       DW      GRP8
+       DB      49H
+       DB      'iv'
+       DW      GRP10
+       DB      30H
+       DB      'aa'
+       DW      PUT
+       DB      27H
+       DB      'as'
+       DW      PUT
+       DB      2FH
+D4:
+       DB      1
+       DB      'own'
+       DW      PUT
+       DB      0FDH
+E2:
+       DB      1
+       DB      'i'
+       DW      PUT
+       DB      0FBH
+E3:
+       DB      3
+       DB      'qu'
+       DW      GRP5
+       DB      2
+       DB      'sc'
+       DW      GRP19
+       DB      0D8H
+       DB      'nd'
+       DW      END
+       DB      0
+E5:
+       DB      1
+       DB      'ndif'
+       DW      ENDIF
+       DB      0
+H3:
+       DB      1
+       DB      'lt'
+       DW      PUT
+       DB      0F4H
+H4:
+       DB      1
+       DB      'alt'
+       DW      PUT
+       DB      0F4H
+I2:
+       DB      2
+       DB      'n'
+       DW      GRP4
+       DB      0E4H
+       DB      'f'
+       DW      GRP5
+       DB      4
+I3:
+       DB      4
+       DB      'nc'
+       DW      GRP8
+       DB      41H
+       DB      'nb'
+       DW      GRP4
+       DB      0E4H
+       DB      'nw'
+       DW      GRP4
+       DB      0E5H
+       DB      'nt'
+       DW      GRP18
+       DB      0CCH
+I4:
+       DB      4
+       DB      'mul'
+       DW      GRP10
+       DB      28H
+       DB      'div'
+       DW      GRP10
+       DB      38H
+       DB      'ret'
+       DW      PUT
+       DB      0CFH
+       DB      'nto'
+       DW      PUT
+       DB      0CEH
+J2:
+       DB      10
+       DB      'p'
+       DW      GRP17
+       DB      0EBH
+       DB      'z'
+       DW      GRP17
+       DB      74H
+       DB      'e'
+       DW      GRP17
+       DB      74H
+       DB      'l'
+       DW      GRP17
+       DB      7CH
+       DB      'b'
+       DW      GRP17
+       DB      72H
+       DB      'a'
+       DW      GRP17
+       DB      77H
+       DB      'g'
+       DW      GRP17
+       DB      7FH
+       DB      'o'
+       DW      GRP17
+       DB      70H
+       DB      's'
+       DW      GRP17
+       DB      78H
+       DB      'c'
+       DW      GRP17
+       DB      72H
+J3:
+       DB      17
+       DB      'mp'
+       DW      GRP14
+       DB      0EAH
+       DB      'nz'
+       DW      GRP17
+       DB      75H
+       DB      'ne'
+       DW      GRP17
+       DB      75H
+       DB      'nl'
+       DW      GRP17
+       DB      7DH
+       DB      'ge'
+       DW      GRP17
+       DB      7DH
+       DB      'nb'
+       DW      GRP17
+       DB      73H
+       DB      'ae'
+       DW      GRP17
+       DB      73H
+       DB      'nc'
+       DW      GRP17
+       DB      73H
+       DB      'ng'
+       DW      GRP17
+       DB      7EH
+       DB      'le'
+       DW      GRP17
+       DB      7EH
+       DB      'na'
+       DW      GRP17
+       DB      76H
+       DB      'be'
+       DW      GRP17
+       DB      76H
+       DB      'pe'
+       DW      GRP17
+       DB      7AH
+       DB      'np'
+       DW      GRP17
+       DB      7BH
+       DB      'po'
+       DW      GRP17
+       DB      7BH
+       DB      'no'
+       DW      GRP17
+       DB      71H
+       DB      'ns'
+       DW      GRP17
+       DB      79H
+J4:
+       DB      6
+       DB      'mps'
+       DW      GRP17
+       DB      0EBH
+       DB      'cxz'
+       DW      GRP17
+       DB      0E3H
+       DB      'nge'
+       DW      GRP17
+       DB      7CH
+       DB      'nae'
+       DW      GRP17
+       DB      72H
+       DB      'nbe'
+       DW      GRP17
+       DB      77H
+       DB      'nle'
+       DW      GRP17
+       DB      7FH
+L3:
+       DB      3
+       DB      'ea'
+       DW      GRP6
+       DB      8DH
+       DB      'ds'
+       DW      GRP6
+       DB      0C5H
+       DB      'es'
+       DW      GRP6
+       DB      0C4H
+L4:
+       DB      5
+       DB      'oop'
+       DW      GRP17
+       DB      0E2H
+       DB      'odb'
+       DW      PUT
+       DB      0ACH
+       DB      'odw'
+       DW      PUT
+       DB      0ADH
+       DB      'ahf'
+       DW      PUT
+       DB      9FH
+       DB      'ock'
+       DW      PUT
+       DB      0F0H
+L5:
+       DB      4
+       DB      'oope'
+       DW      GRP17
+       DB      0E1H
+       DB      'oopz'
+       DW      GRP17
+       DB      0E1H
+       DB      'odsb'
+       DW      PUT
+       DB      0ACH
+       DB      'odsw'
+       DW      PUT
+       DB      0ADH
+L6:
+       DB      2
+       DB      'oopne'
+       DW      GRP17
+       DB      0E0H
+       DB      'oopnz'
+       DW      GRP17
+       DB      0E0H
+M3:
+       DB      2
+       DB      'ov'
+       DW      GRP1
+       DB      88H
+       DB      'ul'
+       DW      GRP10
+       DB      20H
+M4:
+       DB      2
+       DB      'ovb'
+       DW      PUT
+       DB      0A4H
+       DB      'ovw'
+       DW      PUT
+       DB      0A5H
+M5:
+       DB      2
+       DB      'ovsb'
+       DW      PUT
+       DB      0A4H
+       DB      'ovsw'
+       DW      PUT
+       DB      0A5H
+N3:
+       DB      3
+       DB      'ot'
+       DW      GRP9
+       DB      10H
+       DB      'eg'
+       DW      GRP9
+       DB      18H
+       DB      'op'
+       DW      PUT
+       DB      90H
+O2:
+       DB      1
+       DB      'r'
+       DW      GRP13
+       DB      0AH
+O3:
+       DB      2
+       DB      'ut'
+       DW      GRP4
+       DB      0E6H
+       DB      'rg'
+       DW      GRP5
+       DB      0
+O4:
+       DB      2
+       DB      'utb'
+       DW      GRP4
+       DB      0E6H
+       DB      'utw'
+       DW      GRP4
+       DB      0E7H
+P3:
+       DB      2
+       DB      'op'
+       DW      GRP22
+       DB      8FH
+       DB      'ut'
+       DW      GRP5
+       DB      3
+P4:
+       DB      2
+       DB      'ush'
+       DW      GRP2
+       DB      0FFH
+       DB      'opf'
+       DW      PUT
+       DB      9DH
+P5:
+       DB      1
+       DB      'ushf'
+       DW      PUT
+       DB      9CH
+R3:
+       DB      6
+       DB      'et'
+       DW      GRP16
+       DB      0C3H
+       DB      'ep'
+       DW      PUT
+       DB      0F3H
+       DB      'ol'
+       DW      GRP12
+       DB      0
+       DB      'or'
+       DW      GRP12
+       DB      8
+       DB      'cl'
+       DW      GRP12
+       DB      10H
+       DB      'cr'
+       DW      GRP12
+       DB      18H
+R4:
+       DB      2
+       DB      'epz'
+       DW      PUT
+       DB      0F3H
+       DB      'epe'
+       DW      PUT
+       DB      0F3H
+R5:
+       DB      2
+       DB      'epnz'
+       DW      PUT
+       DB      0F2H
+       DB      'epne'
+       DW      PUT
+       DB      0F2H
+S3:
+       DB      11
+       DB      'ub'
+       DW      GRP7
+       DB      2AH
+       DB      'bb'
+       DW      GRP7
+       DB      1AH
+       DB      'bc'
+       DW      GRP7
+       DB      1AH
+       DB      'tc'
+       DW      PUT
+       DB      0F9H
+       DB      'td'
+       DW      PUT
+       DB      0FDH
+       DB      'ti'
+       DW      PUT
+       DB      0FBH
+       DB      'hl'
+       DW      GRP12
+       DB      20H
+       DB      'hr'
+       DW      GRP12
+       DB      28H
+       DB      'al'
+       DW      GRP12
+       DB      20H
+       DB      'ar'
+       DW      GRP12
+       DB      38H
+       DB      'eg'
+       DW      GRP21
+       DB      26H
+S4:
+       DB      5
+       DB      'cab'
+       DW      PUT
+       DB      0AEH
+       DB      'caw'
+       DW      PUT
+       DB      0AFH
+       DB      'tob'
+       DW      PUT
+       DB      0AAH
+       DB      'tow'
+       DW      PUT
+       DB      0ABH
+       DB      'ahf'
+       DW      PUT
+       DB      9EH
+S5:
+       DB      4
+       DB      'casb'
+       DW      PUT
+       DB      0AEH
+       DB      'casw'
+       DW      PUT
+       DB      0AFH
+       DB      'tosb'
+       DW      PUT
+       DB      0AAH
+       DB      'tosw'
+       DW      PUT
+       DB      0ABH
+T4:
+       DB      1
+       DB      'est'
+       DW      GRP20
+       DB      84H
+U2:
+       DB      1
+       DB      'p'
+       DW      PUT
+       DB      0FCH
+W4:
+       DB      1
+       DB      'ait'
+       DW      PUT
+       DB      9BH
+X3:
+       DB      1
+       DB      'or'
+       DW      GRP13
+       DB      32H
+X4:
+       DB      2
+       DB      'chg'
+       DW      GRP3
+       DB      86H
+       DB      'lat'
+       DW      PUT
+       DB      0D7H
+
+
+; 8087 MNEMONIC TABLE
+; Similar to 8086 table above, except NOT distinguished by opcode length
+
+XM1:   ;F2XM1
+       DB      1               ;One opcode
+       DM      "xm1"
+       DB      1,0F0H
+
+NDPA:
+       DB      3
+       DM      "dd"
+       DB      6+ARITH,0C1H
+       DM      "ddp"
+       DB      NEEDOP+STACKOP,0
+       DM      "bs"
+       DB      1,0E1H
+
+NDPB:
+       DB      2
+       DM      "ld"
+       DB      7+NEEDOP+MEMORY,20H
+       DM      "stp"
+       DB      7+NEEDOP+MEMORY,30H
+
+NDPC:
+       DB      5
+       DM      "om"
+       DB      0+ONEREG+REAL,0D1H
+       DM      "omp"
+       DB      0+ONEREG+REAL,0D9H
+       DM      "hs"
+       DB      1,0E0H
+       DM      "ompp"
+       DB      6,0D9H
+       DM      "lex"
+       DB      3,0E2H
+
+NDPD:
+       DB      6
+       DM      "iv"
+       DB      6+ARITH,0F1H
+       DM      "ivp"
+       DB      NEEDOP+STACKOP,30H
+       DM      "ivr"
+       DB      6+ARITH,0F9H
+       DM      "ivrp"
+       DB      NEEDOP+STACKOP,38H
+       DM      "ecstp"
+       DB      1,0F6H
+       DM      "isi"
+       DB      3,0E1H
+
+NDPE:
+       DB      1
+       DM      "ni"
+       DB      3,0E0H
+
+NDPF:
+       DB      1
+       DM      "ree"
+       DB      5+NEEDOP+ONEREG,0
+
+NDPI:
+       DB      13
+       DM      "add"
+       DB      2+NEEDOP+INTEGER,0
+       DM      "ld"
+       DB      3+NEEDOP+INTEGER+EXTENDED,0
+       DM      "sub"
+       DB      2+NEEDOP+INTEGER,20H
+       DM      "stp"
+       DB      3+NEEDOP+INTEGER+EXTENDED,18H
+       DM      "st"
+       DB      3+NEEDOP+INTEGER,10H
+       DM      "mul"
+       DB      2+NEEDOP+INTEGER,8
+       DM      "div"
+       DB      2+NEEDOP+INTEGER,30H
+       DM      "subr"
+       DB      2+NEEDOP+INTEGER,28H
+       DM      "divr"
+       DB      2+NEEDOP+INTEGER,38H
+       DM      "com"
+       DB      2+NEEDOP+INTEGER,10H
+       DM      "comp"
+       DB      2+NEEDOP+INTEGER,18H
+       DM      "ncstp"
+       DB      1,0F7H
+       DM      "nit"
+       DB      3,0E3H
+
+NDPL:
+       DB      10
+       DM      "d"
+       DB      1+NEEDOP+ONEREG+REAL+EXTENDED,0
+       DM      "dz"
+       DB      1,0EEH
+       DM      "d1"
+       DB      1,0E8H
+       DM      "dpi"
+       DB      1,0EBH
+       DM      "dl2t"
+       DB      1,0E9H
+       DM      "dl2e"
+       DB      1,0EAH
+       DM      "dlg2"
+       DB      1,0ECH
+       DM      "dln2"
+       DB      1,0EDH
+       DM      "dcw"
+       DB      1+NEEDOP+MEMORY,28H
+       DM      "denv"
+       DB      1+NEEDOP+MEMORY,20H
+
+NDPM:
+       DB      2
+       DM      "ul"
+       DB      6+ARITH,0C9H
+       DM      "ulp"
+       DB      NEEDOP+STACKOP,8
+
+NDPO:
+       DB      1
+       DM      "p"
+       DB      NEEDOP+1,0      ;Flag special handling
+
+NDPN:
+       DB      1
+       DM      "op"
+       DB      1,0D0H
+
+NDPP:
+       DB      3
+       DM      "rem"
+       DB      1,0F8H
+       DM      "tan"
+       DB      1,0F2H
+       DM      "atan"
+       DB      1,0F3H
+
+NDPR:
+       DB      2
+       DM      "ndint"
+       DB      1,0FCH
+       DM      "stor"
+       DB      5+NEEDOP+MEMORY,20H
+
+NDPS:
+       DB      12
+       DM      "t"
+       DB      5+NEEDOP+ONEREG+REAL,0D0H
+       DM      "tp"
+       DB      7+NEEDOP+ONEREG+REAL+EXTENDED,0D8H
+       DM      "ub"
+       DB      6+ARITH,0E1H
+       DM      "ubp"
+       DB      NEEDOP+STACKOP,0E0H
+       DM      "ubr"
+       DB      6+ARITH,0E9H
+       DM      "ubrp"
+       DB      NEEDOP+STACKOP,0E8H
+       DM      "qrt"
+       DB      1,0FAH
+       DM      "cale"
+       DB      1,0FDH
+       DM      "ave"
+       DB      5+NEEDOP+MEMORY,30H
+       DM      "tcw"
+       DB      1+NEEDOP+MEMORY,38H
+       DM      "tenv"
+       DB      1+NEEDOP+MEMORY,30H
+       DM      "tsw"
+       DB      5+NEEDOP+MEMORY,38H
+
+NDPT:
+       DB      1
+       DM      "st"
+       DB      1,0E4H
+
+NDPW:
+       DB      1
+       DM      "ait"
+       DB      NEEDOP,0        ;Flag special handling
+
+NDPX:
+       DB      3
+       DM      "ch"
+       DB      1+ONEREG,0C9H
+       DM      "am"
+       DB      1,0E5H
+       DM      "tract"
+       DB      1,0F4H
+
+NDPY:
+       DB      2
+       DM      "l2x"
+       DB      1,0F1H
+       DM      "l2xp1"
+       DB      1,0F9H
+
+
+OPTAB:
+; Table of pointers  to mnemonics. For each letter of the alphabet (the
+; starting letter of the mnemonic), there are 5 entries. Each entry
+; corresponds to a mnemonic whose length is 2, 3, 4, 5, and 6 characters
+; long, respectively. If there are no mnemonics for a given combination
+; of first letter and length (such as A-2), then the corresponding entry
+; points to NONE. Otherwise, it points to a place in the mnemonic table
+; for that type.
+
+; This table only needs to be modified if a mnemonic is added to a group
+; previously marked NONE. Change the NONE to a label made up of the first
+; letter of the mnemonic and its length, then add a new subsection to
+; the mnemonic table in alphabetical order.
+
+       DW      NONE
+       DW      A3
+       DW      NONE
+       DW      A5
+       DW      NONE
+       DW      NONE    ;B
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;C
+       DW      C3
+       DW      C4
+       DW      C5
+       DW      NONE
+       DW      D2      ;D
+       DW      D3
+       DW      D4
+       DW      NONE
+       DW      NONE
+       DW      E2      ;E
+       DW      E3
+       DW      NONE
+       DW      E5
+       DW      NONE
+       DW      NONE    ;F
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;G
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;H
+       DW      H3
+       DW      H4
+       DW      NONE
+       DW      NONE
+       DW      I2      ;I
+       DW      I3
+       DW      I4
+       DW      NONE
+       DW      NONE
+       DW      J2      ;J
+       DW      J3
+       DW      J4
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;K
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;L
+       DW      L3
+       DW      L4
+       DW      L5
+       DW      L6
+       DW      NONE    ;M
+       DW      M3
+       DW      M4
+       DW      M5
+       DW      NONE
+       DW      NONE    ;N
+       DW      N3
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      O2      ;O
+       DW      O3
+       DW      O4
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;P
+       DW      P3
+       DW      P4
+       DW      P5
+       DW      NONE
+       DW      NONE    ;Q
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;R
+       DW      R3
+       DW      R4
+       DW      R5
+       DW      NONE
+       DW      NONE    ;S
+       DW      S3
+       DW      S4
+       DW      S5
+       DW      NONE
+       DW      NONE    ;T
+       DW      NONE
+       DW      T4
+       DW      NONE
+       DW      NONE
+       DW      U2      ;U
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;V
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;W
+       DW      NONE
+       DW      W4
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;X
+       DW      X3
+       DW      X4
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;Y
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE    ;Z
+       DW      NONE
+       DW      NONE
+       DW      NONE
+       DW      NONE
+
+NDPTAB:
+;Lookup table for 8087 mnemonics. There is one entry for each letter of the
+;alphabet
+       DW      NDPA
+       DW      NDPB
+       DW      NDPC
+       DW      NDPD
+       DW      NDPE
+       DW      NDPF
+       DW      NONE    ;G
+       DW      NONE    ;H
+       DW      NDPI
+       DW      NONE    ;J
+       DW      NONE    ;K
+       DW      NDPL
+       DW      NDPM
+       DW      NDPN
+       DW      NDPO
+       DW      NDPP
+       DW      NONE    ;Q
+       DW      NDPR
+       DW      NDPS
+       DW      NDPT
+       DW      NONE    ;U
+       DW      NONE    ;V
+       DW      NDPW
+       DW      NDPX
+       DW      NDPY
+       DW      NONE    ;Z
+
+;Error message table
+
+ERRTAB:
+       DM      1,"Register not allowed in immediate value"
+       DM      2,"Index or base register must be BP, BX, SI, or DI"
+       DM      3,"Only one base register (BX, BP) allowed"
+       DM      4,"Only one index register (SI or DI) allowed"
+       DM      5,"Only addition allowed on register or undefined label"
+       DM      6,"Only one undefined label per expression allowed"
+       DM      7,"Illegal digit in hexadecimal number"
+       DM      8,"Illegal digit in decimal number"
+       DM      10,"Illegal character in label or opcode"
+       DM      11,"Label defined twice"
+       DM      12,"Opcode not recognized"
+       DM      20,"Invalid operand"
+       DM      21,'"," and second operand expected'
+       DM      22,"Register mismatch"
+       DM      23,"Immediate operand not allowed"
+       DM      24,'"]" expected'
+       DM      25,"Two memory operands not allowed"
+       DM      26,"Destination must not be immediate value"
+       DM      27,"Both operands must not be registers"
+       DM      28,"Operand must be segment register"
+       DM      29,"First operand must be register"
+       DM      30,"Undefined label not allowed"
+       DM      31,"Value out of range"
+       DM      32,"Missing or illegal operand size flag"
+       DM      33,"Must have label on same line"
+       DM      35,"Zero-length string illegal"
+       DM      36,"ENDIF without IF"
+       DM      37,"One-character strings only"
+       DM      38,"Illegal expression"
+       DM      39,"End of string not found"
+       DM      100,"Undefined label"
+       DM      101,"Value out of range (forward)"
+       DB      255
+
+ERRMES:        DM      '***** ERROR:  '
+NOSPAC:        DB      13,10,'File creation error',13,10,"$"
+NOMEM: DB      13,10,'Insufficient memory',13,10,'$'
+NOFILE:        DB      13,10,'File not found',13,10,'$'
+WRTERR:        DB      13,10,'Disk full',13,10,'$'
+BADDSK:        DB      13,10,'Bad disk specifier',13,10,'$'
+ERCNTM:        DM      13,10,13,10,'Error Count ='
+SYMSIZE        DM      13,10,'Symbol Table size = '
+FRESIZE        DM            'Free space =        '
+SYMMES:        DM      13,10,'Symbol Table',13,10,13,10
+EXTEND:        DB      'ASM',0,0
+IFEND: DB      5,'endif'
+IFNEST:        DB      2,'if'
+RETSTR:        DM      'ret'
+HEXFCB:        DB      0,'        HEX',0,0,0,0
+       DS      16
+       DB      0,0,0,0,0
+LSTFCB:        DB      0,'        PRN',0,0,0,0
+       DS      16
+       DB      0,0,0,0,0
+PC:    DS      2
+OLDPC: DS      2
+LABPT: DS      2
+FLAG:  DS      1
+MAXFLG:        DS      1
+ADDR:  DS      2
+ALABEL:        DS      2
+DATA:  DS      2
+DLABEL:        DS      2
+CON:   DS      2
+UNDEF: DS      2
+LENID: DS      1
+ID:    DS      80
+CHR:   DS      1
+SYM:   DS      1
+BASE:  DS      2
+HEAP:  DS      2
+SYMFLG:        DS      1
+SYMLIN:        DS      1
+CODE:  DS      2
+DATSIZ:        DS      1
+RELOC: DS      1
+BCOUNT:        DS      1
+COUNT: DS      1
+ERR:   DS      1
+LINE:  DS      2
+HEXLEN:        DS      2
+HEXADD:        DS      2
+LASTAD:        DS      2
+HEXCNT:        DS      1
+CHKSUM:        DS      1
+LINFLG:        DS      1
+PREV:  DS      1
+IFFLG: DS      1
+CHKLAB:        DS      1
+ERRCNT:        DS      2
+LSTRET:        DS      2
+RETPT: DS      2
+LSTDEV:        DS      2
+SPC:   DS      1
+NOWAIT:        DS      1
+IX:    DS      2
+IY:    DS      2
+HEXPNT:        DS      2
+LSTPNT:        DS      2
+HEXBUF:        DS      HEXBUFSIZ
+LSTBUF:        DS      LSTBUFSIZ
+BUFPT: DS      2
+SRCBUF:        DS      BUFSIZ
+       DS      100H
+       ALIGN
+STACK: EQU     $
+START: EQU     $
+\1a
\ No newline at end of file
diff --git a/v1.25/source/COMMAND.ASM b/v1.25/source/COMMAND.ASM
new file mode 100644 (file)
index 0000000..830bf73
--- /dev/null
@@ -0,0 +1,2166 @@
+; COMMAND version 1.17
+;
+; This version of COMMAND is divided into three distinct parts. First
+; is the resident portion, which includes handlers for interrupts
+; 22H (terminate), 23H (Cntrl-C), 24H (fatal error), and 27H (stay
+; resident); it also has code to test and, if necessary, reload the
+; transient portion. Following the resident is the init code, which is
+; overwritten after use. Then comes the transient portion, which
+; includes all command processing (whether internal or external).
+; The transient portion loads at the end of physical memory, and it may
+; be overlayed by programs that need as much memory as possible. When
+; the resident portion of command regains control from a user program,
+; a checksum is performed on the transient portion to see if it must be
+; reloaded. Thus programs which do not need maximum memory will save
+; the time required to reload COMMAND when they terminate.
+
+;Use the following booleans to set assembly flags
+FALSE   EQU     0
+TRUE    EQU     NOT FALSE
+
+IBMVER  EQU     FALSE   ;Switch to build IBM version of Command
+MSVER   EQU     TRUE    ;Switch to build MS-DOS version of Command
+
+HIGHMEM EQU     TRUE    ;Run resident part above transient (high memory)
+
+LINPERPAG       EQU     23
+NORMPERLIN      EQU     1
+WIDEPERLIN      EQU     5
+
+        IF      IBMVER
+SYM     EQU     ">"
+COMDRV  EQU     1
+        ENDIF
+
+        IF      MSVER
+SYM     EQU     ":"
+COMDRV  EQU     0
+        ENDIF
+
+FCB     EQU     5CH
+DSKRESET EQU    13
+SETBASE EQU     38
+SRCHFRST EQU    17
+SRCHNXT EQU     18
+RENAM   EQU     23
+INCHAR  EQU     1
+GETFAT  EQU     27
+OPEN    EQU     15
+CLOSE   EQU     16
+MAKE    EQU     22
+DELETE  EQU     19
+RDBLK   EQU     39
+WRBLK   EQU     40
+SETDMA  EQU     26
+SELDRV  EQU     14
+GETDRV  EQU     25
+PRINTBUF EQU    9
+OUTCH   EQU     2
+INBUF   EQU     10
+GETDATE EQU     2AH
+SETDATE EQU     2BH
+GETTIME EQU     2CH
+SETTIME EQU     2DH
+RR      EQU     33
+RECLEN  EQU     14
+FILLEN  EQU     16
+OFFDATE EQU     20
+
+
+;The following are all of the segments used in the load order
+
+CODERES SEGMENT
+CODERES ENDS
+
+DATARES SEGMENT BYTE
+DATARES ENDS
+
+INIT    SEGMENT BYTE
+INIT    ENDS
+
+TAIL    SEGMENT PARA
+TAIL    ENDS
+
+TRANCODE        SEGMENT PARA
+TRANCODE        ENDS
+
+TRANDATA        SEGMENT BYTE
+TRANDATA        ENDS
+
+TRANSPACE       SEGMENT BYTE
+TRANSPACE       ENDS
+
+RESGROUP        GROUP   CODERES,DATARES,INIT,TAIL
+TRANGROUP       GROUP   TRANCODE,TRANDATA,TRANSPACE
+
+;Data for resident portion
+
+DATARES SEGMENT BYTE
+        ORG     0
+ZERO    =       $
+MESBAS  DW      OFFSET RESGROUP:ERR0
+        DW      OFFSET RESGROUP:ERR2
+        DW      OFFSET RESGROUP:ERR4
+        DW      OFFSET RESGROUP:ERR6
+        DW      OFFSET RESGROUP:ERR8
+        DW      OFFSET RESGROUP:ERR10
+        DW      OFFSET RESGROUP:ERR12
+ERR0    DB      "Write protect$"
+ERR2    DB      "Not ready$"
+ERR4    DB      "Data$"
+ERR6    DB      "Seek$"
+ERR8    DB      "Sector not found$"
+ERR10   DB      "Write fault$"
+ERR12   DB      "Disk$"
+READ    DB      "read$"
+WRITE   DB      "writ$"
+ERRMES  DB      " error "
+IOTYP   DB      "writing"
+DRVNUM  DB      " drive "
+DRVLET  DB      "A"
+NEWLIN  DB      13,10,"$"
+REQUEST DB      "Abort, Retry, Ignore? $"
+BADFAT  DB      13,10,"File allocation table bad,$"
+COMBAD  DB      13,10,"Invalid COMMAND.COM"
+NEEDCOM DB      13,10,"Insert DOS disk in "
+        IF      IBMVER
+        DB      "drive A"
+        ELSE
+        DB      "default drive"
+        ENDIF
+PROMPT  DB      13,10,"and strike any key when ready",13,10,"$"
+NEEDBAT DB      13,10,"Insert disk with batch file$"
+ENDBATMES DB    13,10,"Terminate batch job (Y/N)? $"
+LOADING DB      0
+BATFCB  DB      1,"AUTOEXECBAT"
+        DB      21 DUP(?)
+        DW      0
+        DW      0               ;Initialize RR field to zero
+PARMTAB DW      10 DUP(-1)      ;No parameters initially
+BATCH   DB      1               ;Assume batch mode initially
+COMFCB  DB      COMDRV,"COMMAND COM"
+        DB      25 DUP(?)
+TRANS   DW      OFFSET TRANGROUP:COMMAND
+TRNSEG  DW      ?
+BATBYT  DB      ?
+MEMSIZ  DW      ?
+SUM     DW      ?
+INITADD DB      4 DUP(?)
+RESDATASIZE     EQU     $-ZERO
+DATARES ENDS
+
+;Data for transient portion
+
+TRANDATA        SEGMENT BYTE
+        ORG     0
+ZERO    EQU     $
+BADNAM  DB      "Bad command or file name",13,10,"$"
+MISNAM  DB      "Missing file name$"
+RENERR  DB      "Duplicate file name or "
+NOTFND  DB      "File not found$"
+EXEBAD  DB      "Error in EXE file$"
+NOSPACE DB      "Insufficient disk space",13,10,"$"
+FULDIR  DB      "File creation error",13,10,"$"
+OVERWR  DB      "File cannot be copied onto itself",13,10,"$"
+LOSTERR DB      "Content of destination lost before copy",13,10,"$"
+COPIED  DB      " File(s) copied$"
+DIRMES  DB      " File(s)$"
+TOOBIG  DB      "Program too big to fit in memory$"
+BADDRV  DB      "Invalid drive specification$"
+PAUSMES DB      "Strike a key when ready . . . $"
+BADSWT  DB      "Illegal switch",13,10,"$"
+WEEKTAB DB      "SunMonTueWedThuFriSat"
+BADDAT  DB      13,10,"Invalid date$"
+CURDAT  DB      "Current date is $"
+NEWDAT  DB      13,10,"Enter new date: $"
+BADTIM  DB      13,10,"Invalid time$"
+CURTIM  DB      "Current time is $"
+NEWTIM  DB      13,10,"Enter new time: $"
+SUREMES DB      "Are you sure (Y/N)? $"
+
+COMTAB  DB      4,"DIR",1
+        DW      OFFSET TRANGROUP:CATALOG
+        DB      7,"RENAME",1
+        DW      OFFSET TRANGROUP:RENAME
+        DB      4,"REN",1
+        DW      OFFSET TRANGROUP:RENAME
+        DB      6,"ERASE",1
+        DW      OFFSET TRANGROUP:ERASE
+        DB      4,"DEL",1
+        DW      OFFSET TRANGROUP:ERASE
+        DB      5,"TYPE",1
+        DW      OFFSET TRANGROUP:TYPEFIL
+        DB      4,"REM",1
+        DW      OFFSET TRANGROUP:COMMAND
+        DB      5,"COPY",1
+        DW      OFFSET TRANGROUP:COPY
+        DB      6,"PAUSE",1
+        DW      OFFSET TRANGROUP:PAUSE
+        DB      5,"DATE",0
+        DW      OFFSET TRANGROUP:DATE
+        DB      5,"TIME",0
+        DW      OFFSET TRANGROUP:TIME
+        DB      0               ;Terminate command table
+
+COMBUF  DB      128,1,13
+
+TRANDATASIZE    EQU     $-ZERO
+TRANDATA        ENDS
+
+;Uninitialized transient data
+TRANSPACE       SEGMENT BYTE
+        ORG     0
+ZERO    =       $
+        DB      128 DUP(?)
+TPA     DW      1 DUP(?)
+RESSEG  DW      1 DUP(?)
+CHKDRV  DB      1 DUP(?)
+FILTYP  DB      1 DUP(?)
+CURDRV  DB      1 DUP(?)
+PARM1   DB      1 DUP(?)
+PARM2   DB      1 DUP(?)
+COMSW   DW      1 DUP(?)
+ARG1S   DW      1 DUP(?)
+ARG2S   DW      1 DUP(?)
+FLAGER  DB      1 DUP(?)
+CFLAG   DB      1 DUP(?)
+SPECDRV DB      1 DUP(?)
+BYTCNT  DW      1 DUP(?)
+NXTADD  DW      1 DUP(?)
+LINCNT  DB      1 DUP(?)
+LINLEN  DB      1 DUP(?)
+FILECNT DW      1 DUP(?)
+EXEFCB  LABEL WORD
+IDLEN   DB      1 DUP(?)
+ID      DB      8 DUP(?)
+COM     DB      3 DUP(?)
+DEST    DB      37 DUP(?)
+DESTNAME DB     11 DUP(?)
+DIRBUF  DB      37 DUP(?)
+BITS    DW      1 DUP(?)
+FULLSCR DW      1 DUP(?)
+EXEEND  DW      1 DUP(?)
+;Header variables for EXE file load
+;These are overlapped with COPY variables, below
+RUNVAR  LABEL WORD
+RELPT   DW      1 DUP(?)
+RELSEG  DW      1 DUP(?)
+PSIZE   LABEL   WORD
+PAGES   DW      1 DUP(?)
+RELCNT  DW      1 DUP(?)
+HEADSIZ DW      1 DUP(?)
+        DW      1 DUP(?)
+LOADLOW DW      1 DUP(?)
+INITSS  DW      1 DUP(?)
+INITSP  DW      1 DUP(?)
+        DW      1 DUP(?)
+INITIP  DW      1 DUP(?)
+INITCS  DW      1 DUP(?)
+RELTAB  DW      1 DUP(?)
+RUNVARSIZ       EQU     $-RUNVAR
+
+        DB      80H DUP(?)
+STACK   LABEL   WORD
+
+PRETRLEN        EQU     $-ZERO          ;Used later to compute TRNLEN
+
+        ORG     RUNVAR-ZERO                     ;Overlaps EXE variables
+
+SRCPT   DW      1 DUP(?)
+INEXACT DB      1 DUP(?)
+APPEND  DB      1 DUP(?)
+NOWRITE DB      1 DUP(?)
+ASCII   DB      1 DUP(?)
+PLUS    DB      1 DUP(?)
+SOURCE  DB      11 DUP(?)
+TRANSPACESIZE   EQU     $-ZERO
+TRANSPACE       ENDS
+
+
+;START OF RESIDENT PORTION
+
+CODERES SEGMENT
+ASSUME  CS:RESGROUP,DS:RESGROUP,ES:RESGROUP,SS:RESGROUP
+        ORG     0
+ZERO    =       $
+PARMBUF LABEL   WORD
+
+        ORG     100H
+
+RSTACK  LABEL   WORD
+
+PROGSTART:
+        JMP     CONPROC
+
+LTPA    DW      0               ;WILL STORE TPA SEGMENT HERE
+MYSEG   DW      0               ;Put our own segment here
+
+CONTC:
+        MOV     AX,CS
+        MOV     DS,AX
+        MOV     SS,AX
+        MOV     SP,OFFSET RESGROUP:RSTACK
+        STI
+        CALL    SETVECT
+        MOV     AH,DSKRESET
+        INT     33              ;Reset disks in case files were open
+        TEST    [BATCH],-1
+        JZ      LODCOM
+ASKEND:
+        MOV     DX,OFFSET RESGROUP:ENDBATMES
+        MOV     AH,PRINTBUF
+        INT     33
+        MOV     AX,0C00H+INCHAR
+        INT     33
+        AND     AL,5FH
+        CMP     AL,"N"
+        JZ      LODCOM
+        CMP     AL,"Y"
+        JNZ     ASKEND
+        MOV     [BATCH],0
+LODCOM:
+        MOV     AX,CS
+        MOV     SS,AX
+        MOV     SP,OFFSET RESGROUP:RSTACK
+        MOV     DS,AX
+        CALL    SETVECT
+        CALL    CHKSUM
+        CMP     DX,[SUM]
+        JZ      HAVCOM
+        MOV     [LOADING],1
+        CALL    LOADCOM
+CHKSAME:
+        CALL    CHKSUM
+        CMP     DX,[SUM]
+        JZ      HAVCOM
+        CALL    WRONGCOM
+        JMP     SHORT CHKSAME
+HAVCOM:
+        MOV     [LOADING],0
+        MOV     SI,OFFSET RESGROUP:LTPA
+        MOV     DI,OFFSET TRANGROUP:TPA
+        MOV     ES,[TRNSEG]
+        CLD
+        MOVSW           ;Move TPA segment to transient storage
+        MOVSW           ;Move resident segment too
+        MOV     AX,[MEMSIZ]
+        MOV     WORD PTR ES:[2],AX
+        JMP     DWORD PTR [TRANS]
+
+RESIDENT:
+        ADD     DX,15
+        MOV     CL,4
+        SHR     DX,CL           ;Number of paragraphs of new addition
+        ADD     CS:[LTPA],DX
+        XOR     AX,AX
+        MOV     DS,AX
+        JMP     DWORD PTR DS:[80H]              ;Pretend user executed INT 20H
+
+DSKERR:
+        ;******************************************************
+        ;       THIS IS THE DEFAULT DISK ERROR HANDLING CODE 
+        ;       AVAILABLE TO ALL USERS IF THEY DO NOT TRY TO 
+        ;       INTERCEPT INTERRUPT 24H.
+        ;******************************************************
+        STI
+        PUSH    DS
+        PUSH    CS
+        POP     DS              ;Set up local data segment
+        PUSH    DX
+        CALL    CRLF
+        POP     DX
+        ADD     AL,"A"          ;Compute drive letter
+        MOV     [DRVLET],AL
+        TEST    AH,80H          ;Check if hard disk error
+        JNZ     FATERR
+        MOV     SI,OFFSET RESGROUP:READ
+        TEST    AH,1
+        JZ      SAVMES
+        MOV     SI,OFFSET RESGROUP:WRITE
+SAVMES:
+        LODSW
+        MOV     WORD PTR [IOTYP],AX
+        LODSW
+        MOV     WORD PTR [IOTYP+2],AX
+        AND     DI,0FFH
+        CMP     DI,12
+        JBE     HAVCOD
+        MOV     DI,12
+HAVCOD:
+        MOV     DI,WORD PTR [DI+MESBAS] ;Get pointer to error message
+        XCHG    DI,DX           ;May need DX later
+        MOV     AH,PRINTBUF
+        INT     33              ;Print error type
+        MOV     DX,OFFSET RESGROUP:ERRMES
+        INT     33
+        CMP     [LOADING],0
+        JNZ     GETCOMDSK
+ASK:
+        MOV     DX,OFFSET RESGROUP:REQUEST
+        MOV     AH,PRINTBUF
+        INT     33
+        MOV     AX,0C00H+INCHAR
+        INT     33              ;Get response
+        CALL    CRLF
+        OR      AL,20H          ;Convert to lower case
+        MOV     AH,0            ;Return code for ignore
+        CMP     AL,"i"          ;Ignore?
+        JZ      EXIT
+        INC     AH
+        CMP     AL,"r"          ;Retry?
+        JZ      EXIT
+        INC     AH
+        CMP     AL,"a"          ;Abort?
+        JNZ     ASK
+EXIT:
+        MOV     AL,AH
+        MOV     DX,DI
+        POP     DS
+        IRET
+
+FATERR:
+        MOV     DX,OFFSET RESGROUP:BADFAT
+        MOV     AH,PRINTBUF
+        INT     33
+        MOV     DX,OFFSET RESGROUP:DRVNUM
+        INT     33
+        MOV     AL,2            ;Abort
+        POP     DS
+        IRET
+
+GETCOMDSK:
+        MOV     DX,OFFSET RESGROUP:NEEDCOM
+        MOV     AH,PRINTBUF
+        INT     33
+        MOV     AX,0C07H        ;Get char without testing or echo
+        INT     33
+        JMP     LODCOM
+
+CRLF:
+        MOV     DX,OFFSET RESGROUP:NEWLIN
+        PUSH    AX
+        MOV     AH,PRINTBUF
+        INT     33
+        POP     AX
+RET10:  RET
+
+LOADCOM:
+        PUSH    DS
+        MOV     DS,[TRNSEG]
+        MOV     DX,100H
+        MOV     AH,SETDMA
+        INT     33
+        POP     DS
+        MOV     DX,OFFSET RESGROUP:COMFCB
+        MOV     AH,OPEN
+        INT     33              ;Open COMMAND.COM
+        OR      AL,AL
+        JZ      READCOM
+        MOV     DX,OFFSET RESGROUP:NEEDCOM
+PROMPTCOM:
+        MOV     AH,PRINTBUF
+        INT     33
+        MOV     AX,0C07H        ;Get char without testing or echo
+        INT     33
+        JMP     SHORT LOADCOM
+READCOM:
+        MOV     WORD PTR[COMFCB+RR],OFFSET RESGROUP:TRANSTART
+        XOR     AX,AX
+        MOV     WORD PTR[COMFCB+RR+2],AX
+        MOV     [COMFCB],AL             ;Use default drive
+        INC     AX
+        MOV     WORD PTR[COMFCB+RECLEN],AX
+        MOV     CX,COMLEN
+        MOV     DX,OFFSET RESGROUP:COMFCB
+        MOV     AH,RDBLK
+        INT     33
+        OR      AL,AL
+        JZ      RET10
+WRONGCOM:
+        MOV     DX,OFFSET RESGROUP:COMBAD
+        JMP     SHORT PROMPTCOM
+
+CHKSUM:
+        CLD
+        PUSH    DS
+        MOV     DS,[TRNSEG]
+        MOV     SI,100H
+        MOV     CX,COMLEN
+        SHR     CX,1
+        XOR     DX,DX
+CHK:
+        LODSW
+        ADD     DX,AX
+        LOOP    CHK
+        POP     DS
+        RET
+
+SETVECT:
+        MOV     DX,OFFSET RESGROUP:LODCOM
+        MOV     AX,2522H        ;Set Terminate address
+        INT     21H
+        MOV     DX,OFFSET RESGROUP:CONTC
+        MOV     AX,2523H        ;Set Ctrl-C address
+        INT     21H
+        MOV     DX,OFFSET RESGROUP:DSKERR
+        MOV     AX,2524H        ;Set Hard Disk Error address
+        INT     33
+        MOV     DX,OFFSET RESGROUP:RESIDENT
+        MOV     AX,2527H        ;Set Terminate and Stay Resident address
+        INT     33
+        RET
+RESCODESIZE     EQU     $-ZERO
+CODERES ENDS
+
+;*******************************************************************
+;START OF INIT PORTION
+;This code is overlayed the first time the TPA is used.
+
+INIT    SEGMENT BYTE
+
+        ORG     0
+ZERO    =       $
+CONPROC:
+        MOV     SP,OFFSET RESGROUP:RSTACK
+
+        IF      HIGHMEM
+        MOV     AX,WORD PTR DS:[2]
+        SUB     AX,((RESCODESIZE+RESDATASIZE)+15)/16            ;Subtract size of resident
+        MOV     WORD PTR DS:[2],AX
+        MOV     ES,AX
+        MOV     SI,100H
+        MOV     DI,SI
+        MOV     CX,((RESCODESIZE+RESDATASIZE)-100H+1)/2 ;Length of resident in words
+        REP     MOVSW                   ;Move to end of memory
+        MOV     DS,AX
+        MOV     [LTPA],CS
+        ENDIF
+
+        IF      NOT HIGHMEM
+        MOV     AX,CS
+        ADD     AX,((RESCODESIZE+RESDATASIZE)+15)/16            ;Compute segment of TPA
+        MOV     [LTPA],AX
+        MOV     AX,WORD PTR DS:[2]
+        ENDIF
+
+        MOV     [MYSEG],DS
+        MOV     [MEMSIZ],AX
+        SUB     AX,TRNLEN               ;Subtract size of transient
+        MOV     [TRNSEG],AX
+        CALL    SETVECT
+        CALL    LOADCOM
+        CALL    CHKSUM
+        MOV     [SUM],DX
+
+        IF MSVER
+        IF      HIGHMEM
+        PUSH    DS
+        PUSH    CS
+        POP     DS
+        ENDIF
+        MOV     DX,OFFSET RESGROUP:HEADER
+        MOV     AH,PRINTBUF
+        INT     33
+        IF      HIGHMEM
+        POP     DS
+        ENDIF
+        ENDIF
+
+        MOV     DX,OFFSET RESGROUP:BATFCB
+        MOV     AH,OPEN
+        INT     33                      ;See if AUTOEXEC.BAT exists
+        MOV     WORD PTR[BATFCB+RECLEN],1       ;Set record length to 1
+        OR      AL,AL                   ;Zero means file found
+        JZ      DRV0
+        MOV     [BATCH],0               ;Not found--turn off batch job
+        MOV     AX,OFFSET TRANGROUP:DATINIT
+        MOV     WORD PTR[INITADD],AX
+        MOV     AX,[TRNSEG]
+        MOV     WORD PTR[INITADD+2],AX
+        CALL    DWORD PTR DS:[INITADD]
+
+        IF IBMVER
+        MOV     DX,OFFSET RESGROUP:HEADER
+        MOV     AH,PRINTBUF
+        INT     33
+        ENDIF
+
+DRV0:
+        JMP     HAVCOM
+
+
+        IF MSVER
+HEADER  DB      13,10,"Command v. 1.17"
+        IF      HIGHMEM
+        DB      "H"
+        ENDIF
+        DB      13,10,"$"
+        ENDIF
+
+        IF IBMVER
+HEADER  DB      13,10,13,10,"The IBM Personal Computer DOS",13,10
+        DB      "Version 1.10 (C)Copyright IBM Corp 1981, 1982",13,10,"$"
+        DB      "Licensed Material - Program Property of IBM"
+        ENDIF
+
+INITSIZE        EQU     $-ZERO
+INIT    ENDS
+
+;This TAIL segment is used to produce a PARA aligned label in the resident
+; group which is the location where the transient segments will be loaded
+; initialy.
+
+TAIL    SEGMENT PARA
+        ORG     0
+TRANSTART       LABEL   WORD
+TAIL    ENDS
+
+;********************************************************************
+;START OF TRANSIENT PORTION
+;This code is loaded at the end of memory and may be overwritten by
+;memory-intensive user programs.
+
+TRANCODE        SEGMENT PARA
+ASSUME  CS:TRANGROUP,DS:TRANGROUP,ES:TRANGROUP,SS:TRANGROUP
+
+WSWITCH EQU     1               ;Wide display during DIR
+PSWITCH EQU     2               ;Pause (or Page) mode during DIR
+VSWITCH EQU     4               ;Verify during COPY
+ASWITCH EQU     8               ;ASCII mode during COPY
+BSWITCH EQU     10H             ;Binary mode during COPY
+
+        ORG     0
+ZERO    =       $
+
+        ORG     100H            ;Allow for 100H parameter area
+
+SETDRV:
+        MOV     AH,SELDRV
+        INT     21H
+COMMAND:
+        CLD
+        MOV     AX,CS
+        MOV     SS,AX
+        MOV     SP,OFFSET TRANGROUP:STACK
+        MOV     ES,AX
+        MOV     DS,AX
+        STI
+        MOV     AX,46*100H
+        MOV     DL,0
+        INT     33              ;Turn off verify after write
+        MOV     AX,CS           ;Get segment we're in
+        SUB     AX,[TPA]        ;AX=size ot TPA in paragraphs
+        MOV     DX,16
+        MUL     DX              ;DX:AX=size of TPA in bytes
+        OR      DX,DX           ;See if over 64K
+        JZ      SAVSIZ          ;OK if not
+        MOV     AX,-1           ;If so, limit to 65535 bytes
+SAVSIZ:
+        MOV     [BYTCNT],AX     ;Max no. of bytes that can be buffered
+        CALL    CRLF2
+GETCOM:
+        MOV     AH,GETDRV
+        INT     21H
+        MOV     [CURDRV],AL
+        ADD     AL,"A"
+        CALL    OUT             ;Print letter for default drive
+        MOV     AL,SYM
+        CALL    OUT
+        MOV     DS,[RESSEG]     ;All batch work must use resident seg.
+ASSUME  DS:RESGROUP
+        TEST    [BATCH],-1
+        JNZ     READBAT
+        PUSH    CS
+        POP     DS              ;Need local segment to point to buffer
+ASSUME  DS:TRANGROUP
+        MOV     DX,OFFSET TRANGROUP:COMBUF
+        MOV     AH,INBUF
+        INT     21H             ;Get a command
+        JMP     DOCOM
+
+;All batch proccessing has DS set to segment of resident portion
+ASSUME  DS:RESGROUP
+NEEDPARM:
+        CALL    GETBATBYT
+        CMP     AL,"%"          ;Check for two consecutive %
+        JZ      SAVBATBYT
+        CMP     AL,13           ;Check for end-of-line
+        JZ      SAVBATBYT
+        SUB     AL,"0"
+        JB      RDBAT           ;Ignore parameter reference if invalid
+        CMP     AL,9
+        JA      RDBAT
+        CBW
+        MOV     SI,AX
+        SHL     SI,1            ;Two bytes per entry
+        MOV     SI,[SI+OFFSET RESGROUP:PARMTAB] ;Get pointer to corresponding parameter
+        CMP     SI,-1           ;Check if parameter exists
+        JZ      RDBAT           ;Ignore if it doesn't
+        MOV     AH,OUTCH
+RDPARM:
+        LODSB           ;From resident segment
+        CMP     AL,0DH          ;Check for end of parameter
+        JZ      RDBAT
+        STOSB           ;To transient segment
+        MOV     DL,AL
+        INT     33              ;Display paramters too
+        JMP     SHORT RDPARM
+
+PROMPTBAT:
+        MOV     AH,PRINTBUF
+        MOV     DX,OFFSET RESGROUP:NEEDBAT
+        INT     33              ;Prompt for batch file
+        MOV     AH,PRINTBUF
+        MOV     DX,OFFSET RESGROUP:PROMPT
+        INT     33
+        MOV     AX,0C00H+INCHAR
+        INT     33
+        JMP     COMMAND
+
+BADCOMJ1:JMP    BADCOM
+
+READBAT:
+        MOV     DX,OFFSET RESGROUP:BATFCB
+        MOV     AH,OPEN
+        INT     33              ;Make sure batch file still exists
+        OR      AL,AL
+        JNZ     PROMPTBAT       ;If OPEN fails, prompt for disk
+        MOV     WORD PTR [BATFCB+RECLEN],1
+        MOV     DX,OFFSET RESGROUP:BATBYT
+        MOV     AH,SETDMA
+        INT     33
+        MOV     DI,OFFSET TRANGROUP:COMBUF+2
+RDBAT:
+        CALL    GETBATBYT
+        CMP     AL,"%"          ;Check for parameter
+        JZ      NEEDPARM
+SAVBATBYT:
+        STOSB
+        CALL    OUT             ;Display batched command line
+        CMP     AL,0DH
+        JNZ     RDBAT
+        SUB     DI,OFFSET TRANGROUP:COMBUF+3
+        MOV     AX,DI
+        MOV     ES:[COMBUF+1],AL        ;Set length of line
+        CALL    GETBATBYT       ;Eat linefeed
+        PUSH    CS
+        POP     DS              ;Go back to local segment
+ASSUME DS:TRANGROUP
+DOCOM:
+;All segments are local for command line processing
+        MOV     AL,10
+        CALL    OUT
+        MOV     SI,OFFSET TRANGROUP:COMBUF+2
+        MOV     DI,OFFSET TRANGROUP:IDLEN
+        MOV     AX,2901H        ;Make FCB with blank scan-off
+        INT     21H
+        CMP     AL,1            ;Check for ambiguous command name
+        JZ      BADCOMJ1        ;Ambiguous commands not allowed
+        CMP     AL,-1
+        JNZ     DRVGD
+        JMP     DRVBAD
+DRVGD:
+        MOV     AL,[DI]
+        MOV     [SPECDRV],AL
+        MOV     AL," "
+        MOV     CX,9
+        INC     DI
+        REPNE   SCASB           ;Count no. of letters in command name
+        MOV     AL,9
+        SUB     AL,CL
+        MOV     [IDLEN],AL
+        MOV     DI,81H
+        MOV     CX,0
+        PUSH    SI
+COMTAIL:
+        LODSB
+        STOSB           ;Move command tail to 80H
+        CMP     AL,13
+        LOOPNZ  COMTAIL
+        NOT     CL
+        MOV     BYTE PTR DS:[80H],CL
+        POP     SI
+;If the command has 0 parameters must check here for
+;any switches that might be present.
+;SI -> first character after the command.
+        MOV     [FLAGER],0      ;Set error flag before any calls to switch 
+        CALL    SWITCH          ;Is the next character a "/"
+        MOV     [COMSW],AX
+        MOV     DI,FCB
+        MOV     AX,2901H
+        INT     21H
+        MOV     [PARM1],AL      ;Save result of parse
+        CALL    SWITCH
+        MOV     [ARG1S],AX
+        MOV     DI,FCB+10H
+        MOV     AX,2901H
+        INT     21H             ;Parse file name
+        MOV     [PARM2],AL      ;Save result
+        CALL    SWITCH
+        MOV     [ARG2S],AX
+        MOV     AL,[IDLEN]
+        MOV     DL,[SPECDRV]
+        OR      DL,DL           ;Check if drive was specified
+        JZ      OK
+        JMP     DRVCHK
+OK:     DEC     AL              ;Check for null command
+        JNZ     FNDCOM
+        JMP     GETCOM
+
+RETSW:
+        XCHG    AX,BX           ;Put switches in AX
+        RET
+
+SWITCH:
+        XOR     BX,BX           ;Initialize - no switches set
+SWLOOP:
+        CALL    SCANOFF         ;Skip any delimiters
+        CMP     AL,"/"          ;Is it a switch specifier?
+        JNZ     RETSW           ;No -- we're finished
+        INC     SI              ;Skip over "/"
+        CALL    SCANOFF
+        INC     SI
+;Convert lower case input to upper case
+        CMP     AL,"a"
+        JB      SAVCHR
+        CMP     AL,"z"
+        JA      SAVCHR
+        SUB     AL,20H          ;Lower-case changed to upper-case
+SAVCHR:
+        MOV     DI,OFFSET TRANGROUP:SWLIST
+        MOV     CX,SWCOUNT
+        REPNE   SCASB                   ;Look for matching switch
+        JNZ     BADSW
+        MOV     AX,1
+        SHL     AX,CL           ;Set a bit for the switch
+        OR      BX,AX
+        JMP     SHORT SWLOOP
+
+BADSW:
+        MOV     [FLAGER],1      ;Record error in switch
+        JMP     SHORT SWLOOP
+
+SWLIST  DB      "BAVPW"
+SWCOUNT EQU     $-SWLIST
+
+DRVBAD:
+        MOV     DX,OFFSET TRANGROUP:BADDRV
+        JMP     ERROR
+
+FNDCOM:
+        MOV     SI,OFFSET TRANGROUP:COMTAB      ;Prepare to search command table
+        MOV     CH,0
+FINDCOM:
+        MOV     DI,OFFSET TRANGROUP:IDLEN
+        MOV     CL,[SI]
+        JCXZ    EXTERNAL
+        REPE    CMPSB
+        LAHF
+        ADD     SI,CX           ;Bump to next position without affecting flags
+        SAHF
+        LODSB           ;Get flag for drive check
+        MOV     [CHKDRV],AL
+        LODSW           ;Get address of command
+        JNZ     FINDCOM
+        MOV     DX,AX
+        CMP     [CHKDRV],0
+        JZ      NOCHECK
+        MOV     AL,[PARM1]
+        OR      AL,[PARM2]      ;Check if either parm. had invalid drive
+        CMP     AL,-1
+        JZ      DRVBAD
+NOCHECK:CALL    DX
+COMJMP: JMP     COMMAND
+
+BADCOMJ:JMP     BADCOM
+
+SETDRV1:
+        JMP     SETDRV
+
+DRVCHK:
+        DEC     DL              ;Adjust for correct drive number
+        DEC     AL              ;Check if anything else is on line
+        JZ      SETDRV1
+EXTERNAL:
+        MOV     AL,[SPECDRV]
+        MOV     [IDLEN],AL
+        MOV     WORD PTR[COM],4F00H+"C" ;"CO"
+        MOV     BYTE PTR[COM+2],"M"
+        MOV     DX,OFFSET TRANGROUP:IDLEN
+        MOV     AH,OPEN
+        INT     33              ;Check if command to be executed
+        MOV     [FILTYP],AL     ;0 for COM files, -1 for EXE files
+        OR      AL,AL
+        JZ      EXECUTE
+        MOV     WORD PTR[COM],5800H+"E" ;"EX"
+        MOV     BYTE PTR[COM+2],"E"
+        INT     33              ;Check for EXE file
+        OR      AL,AL
+        JZ      EXECUTE
+        MOV     WORD PTR[COM],4100H+"B" ;"BA"
+        MOV     BYTE PTR[COM+2],"T"
+        INT     33              ;Check if batch file to be executed
+        OR      AL,AL
+        JNZ     BADCOMJ
+BATCOM:
+;Batch parameters are read with ES set to segment of resident part
+        MOV     ES,[RESSEG]
+ASSUME  ES:RESGROUP
+        MOV     DI,OFFSET RESGROUP:PARMTAB
+        MOV     AX,-1
+        MOV     CX,10
+        REP     STOSW           ;Zero parameter pointer table
+        MOV     SI,OFFSET TRANGROUP:COMBUF+2
+        MOV     DI,OFFSET RESGROUP:PARMBUF
+        MOV     BX,OFFSET RESGROUP:PARMTAB
+EACHPARM:
+        CALL    SCANOFF
+        CMP     AL,0DH
+        JZ      HAVPARM
+        MOV     ES:[BX],DI              ;Set pointer table to point to actual parameter
+        INC     BX
+        INC     BX
+MOVPARM:
+        LODSB
+        CALL    DELIM
+        JZ      ENDPARM         ;Check for end of parameter
+        STOSB
+        CMP     AL,0DH
+        JZ      HAVPARM
+        JMP     SHORT MOVPARM
+ENDPARM:
+        MOV     AL,0DH
+        STOSB           ;End-of-parameter marker
+        CMP     BX,OFFSET RESGROUP:PARMTAB+20   ;Maximum number of parameters?
+        JB      EACHPARM
+HAVPARM:
+        MOV     SI,OFFSET TRANGROUP:IDLEN
+        MOV     DI,OFFSET RESGROUP:BATFCB
+        MOV     CX,16
+        REP     MOVSW           ;Move into private batch FCB
+        XOR     AX,AX
+        PUSH    ES
+        POP     DS                      ;Simply batch FCB setup
+ASSUME  DS:RESGROUP
+        MOV     WORD PTR[BATFCB+RR],AX
+        MOV     WORD PTR[BATFCB+RR+2],AX        ;Zero RR field
+        INC     AX
+        MOV     WORD PTR[BATFCB+RECLEN],AX      ;Set record length to 1 byte
+        MOV     [BATCH],AL              ;Flag batch job in progress
+        JMP     COMMAND
+ASSUME  DS:TRANGROUP,ES:TRANGROUP
+
+EXECUTE:
+        MOV     AX,WORD PTR[IDLEN+16]
+        OR      AX,WORD PTR[IDLEN+18]           ;See if zero length
+        JZ      BADCOM                  ;If so, error
+        XOR     AX,AX
+        MOV     WORD PTR[IDLEN+RR],AX
+        MOV     WORD PTR[IDLEN+RR+2],AX         ;Set RR field to zero
+        INC     AX
+        MOV     WORD PTR[IDLEN+RECLEN],AX       ;Set record length field to 1
+        MOV     DX,[TPA]
+        MOV     BX,DX
+        MOV     AH,SETBASE
+        INT     21H
+        TEST    [FILTYP],-1             ;Check if file is COM or EXE
+        JZ      COMLOAD
+        JMP     EXELOAD
+COMLOAD:PUSH    DS
+        MOV     DS,DX
+        MOV     DX,100H
+        MOV     AH,SETDMA
+        INT     21H
+        POP     DS
+        MOV     CX,[BYTCNT]
+        SUB     CX,100H
+        MOV     DX,OFFSET TRANGROUP:IDLEN
+        MOV     AH,RDBLK
+        INT     21H
+        DEC     AL
+        MOV     DX,OFFSET TRANGROUP:TOOBIG
+        JNZ     ERROR
+;Set up exit conditions
+        MOV     CX,[BYTCNT]
+        MOV     DS,BX
+        MOV     ES,BX
+        CLI
+        MOV     SS,BX
+        MOV     SP,CX
+        STI
+        SUB     CX,100H         ;Allow some stack space
+        XOR     AX,AX
+        PUSH    AX
+        MOV     AX,100H
+        PUSH    BX
+        PUSH    AX
+        CALL    SETUP
+XXX     PROC    FAR
+        RET
+XXX     ENDP
+BADCOM:
+        MOV     DX,OFFSET TRANGROUP:BADNAM
+ERROR:
+        MOV     AH,PRINTBUF
+        INT     21H
+        JMP     COMMAND
+
+CHKCNT:
+        TEST    [FILECNT],-1
+        JNZ     ENDDIR
+        MOV     DX,OFFSET TRANGROUP:NOTFND
+        JMP     ERROR
+
+ENDDIR:
+;Make sure last line ends with CR/LF
+        MOV     AL,[LINLEN]
+        CMP     AL,[LINCNT]     ;Will be equal if just had CR/LF
+        JZ      MESSAGE
+        CALL    CRLF2
+MESSAGE:                
+        MOV     SI,[FILECNT]
+        XOR     DI,DI
+        CALL    DISP32BITS
+        MOV     DX,OFFSET TRANGROUP:DIRMES
+        MOV     AH,PRINTBUF
+        INT     21H
+        RET
+
+CATALOG:
+        MOV     AL,"?"                  ;*.* is default file spec.
+        MOV     DI,5DH
+        MOV     CX,11
+        REP     STOSB
+        MOV     SI,81H
+        CALL    SWITCH
+        MOV     DI,5CH
+        MOV     AX,41*100H+0DH          ;Parse with default name and extension
+        INT     33
+
+;Begin by processing any switches that may have been specified.
+;BITS will contain any information about switches that was
+;found when the command line was parsed.
+
+SETSWT:
+        MOV     AX,[COMSW]              ;Get switches from command
+        OR      AX,[ARG1S]              ;OR in switches from first parameter
+        MOV     [BITS],AX
+        MOV     BYTE PTR[FULLSCR],LINPERPAG
+        TEST    AL,1                    ;Look for /W
+        MOV     AL,NORMPERLIN
+        JZ      DIR
+        MOV     AL,WIDEPERLIN
+DIR:
+        MOV     [LINLEN],AL             ;Set number of entries per line
+        MOV     [LINCNT],AL
+        MOV     [FILECNT],0     ;Keep track of how many files found
+        MOV     DX,OFFSET TRANGROUP:DIRBUF      ;Set Disk transfer address
+        MOV     AH,SETDMA
+        INT     21H             
+        MOV     AH,SRCHFRST
+SHOWDIR:
+        MOV     DX,5CH          ;DX -> Unopened FCB
+        INT     21H             ;Search for a file to match FCB
+        INC     AL              ;FF = file not found
+        JNZ     AGAIN           ;Either an error or we are finished
+        JMP     CHKCNT
+AGAIN:
+        INC     [FILECNT]       ;Keep track of how many we find
+        MOV     SI,OFFSET TRANGROUP:DIRBUF+1    ;SI -> information returned by sys call
+        CALL    SHONAME
+        TEST    BYTE PTR[BITS],1        ;/W set?
+        JNZ     NEXENT          ;If so, no size, date, or time
+        CALL    DISPSIZE        ;Print size of file
+        CALL    TWOSPC
+        MOV     AX,WORD PTR[DIRBUF+25]  ;Get date
+        OR      AX,AX
+        JZ      NEXENT          ;Skip if no date
+        MOV     DX,AX
+        MOV     CL,5
+        SHR     AX,CL           ;Align month
+        AND     AL,0FH
+        MOV     BH,"0"-" "      ;Enable zero suppression
+        CALL    OUT2
+        MOV     AL,"-"
+        CALL    OUT
+        MOV     AL,DL
+        AND     AL,1FH          ;Mask to day
+        CALL    OUT2
+        MOV     AL,"-"
+        CALL    OUT
+        MOV     AL,DH
+        SHR     AL,1            ;Align year
+        ADD     AX,80           ;Relative 1980
+        CMP     AL,100
+        JB      MILLENIUM
+        SUB     AL,100
+MILLENIUM:
+        CALL    OUT2
+        MOV     BX,WORD PTR[DIRBUF+23]  ;Get time
+        OR      BX,BX           ;Time field present?
+        JZ      NEXENT
+        CALL    TWOSPC  
+        SHR     BX,1
+        SHR     BX,1
+        SHR     BX,1
+        SHR     BL,1
+        SHR     BL,1            ;Hours in BH, minutes in BL
+        MOV     AL,BH
+        MOV     DH,"a"          ;Assume A.M.
+        CMP     AL,12           ;In the afternoon?
+        JB      MORN
+        MOV     DH,"p"
+        JE      MORN
+        SUB     AL,12           ;Keep it to 12 hours or less
+MORN:
+        OR      AL,AL           ;Before 1 am?
+        JNZ     SHOHOURS
+        MOV     AL,12
+SHOHOURS:
+        MOV     BH,"0"-" "      ;Enable zero suppression
+        CALL    OUT2
+        MOV     AL,":"
+        CALL    OUT
+        MOV     AL,BL           ;Output minutes
+        CALL    OUT2
+        MOV     AL,DH           ;Get "a" or "p"
+        CALL    OUT
+NEXENT:
+        DEC     [LINCNT]
+        JNZ     SAMLIN
+NEXLIN:
+        MOV     AL,[LINLEN]
+        MOV     [LINCNT],AL
+        CALL    CRLF2
+        TEST    BYTE PTR[BITS],2        ;/P switch present?
+        JZ      SCROLL          ;If not, just continue
+        DEC     BYTE PTR[FULLSCR]
+        JNZ     SCROLL
+        MOV     BYTE PTR[FULLSCR],LINPERPAG
+        MOV     AH,PRINTBUF
+        MOV     DX,OFFSET TRANGROUP:PAUSMES
+        INT     33
+        MOV     AX,0C08H        ;Wait for any character to be typed
+        INT     21H
+        CALL    CRLF2
+SCROLL:
+        MOV     AH,SRCHNXT
+        JMP     SHOWDIR
+
+SAMLIN:
+        MOV     AL,9            ;Output a tab
+        CALL    OUT
+        JMP     SHORT SCROLL
+
+SHONAME:
+        MOV     CX,8
+        CALL    OUTCNT
+        CALL    ONESPC
+        MOV     CX,3
+OUTCNT:
+        LODSB
+        CALL    OUT
+        LOOP    OUTCNT
+        RET
+
+TWOSPC:
+        CALL    ONESPC
+ONESPC:
+        MOV     AL," "
+        JMP     OUT
+
+CRLF2:
+        MOV     AL,13
+        CALL    OUT
+        MOV     AL,10
+        JMP     OUT
+
+DISPSIZE:
+        MOV     SI,WORD PTR[DIRBUF+29]
+        MOV     DI,WORD PTR[DIRBUF+31]
+DISP32BITS:
+;Prints the 32-bit number DI:SI on the console in decimal. Uses a total
+;of 9 digit positions with leading blanks.
+        XOR     AX,AX
+        MOV     BX,AX
+        MOV     BP,AX
+        MOV     CX,32
+CONVLP:
+        SHL     SI,1
+        RCL     DI,1
+        XCHG    AX,BP
+        CALL    CONVWRD
+        XCHG    AX,BP
+        XCHG    AX,BX
+        CALL    CONVWRD
+        XCHG    AX,BX
+        ADC     AL,0
+        LOOP    CONVLP
+; Conversion complete. Print 9-digit number.
+        MOV     CX,1810H        ;Allow leading zero blanking for 8 digits
+        XCHG    DX,AX
+        CALL    DIGIT
+        XCHG    AX,BX
+        CALL    OUTWORD
+        XCHG    AX,BP
+OUTWORD:
+        PUSH    AX
+        MOV     DL,AH
+        CALL    OUTBYTE
+        POP     DX
+OUTBYTE:
+        MOV     DH,DL
+        SHR     DL,1
+        SHR     DL,1
+        SHR     DL,1
+        SHR     DL,1
+        CALL    DIGIT
+        MOV     DL,DH
+DIGIT:
+        AND     DL,0FH
+        JZ      BLANKZER
+        MOV     CL,0
+BLANKZER:
+        DEC     CH
+        AND     CL,CH
+        OR      DL,30H
+        SUB     DL,CL
+        MOV     AH,OUTCH
+        INT     21H
+        RET
+
+CONVWRD:
+        ADC     AL,AL
+        DAA
+        XCHG    AL,AH
+        ADC     AL,AL
+        DAA
+        XCHG    AL,AH
+RET20:  RET
+
+ERASE:
+        MOV     CX,11
+        MOV     SI,FCB+1
+AMBSPEC:        
+        LODSB
+        CMP     AL,"?"
+        JNZ     ALLFIL
+        LOOP    AMBSPEC
+ALLFIL: 
+        CMP     CX,0
+        JNZ     NOPRMPT
+ASKAGN:         
+        MOV     DX,OFFSET TRANGROUP:SUREMES     ;"Are you sure (Y/N)?"
+        MOV     AH,PRINTBUF
+        INT     21H
+        MOV     AX,0C00H+INCHAR
+        INT     21H
+        AND     AL,5FH
+        CMP     AL,"N"
+        JZ      RET20
+        CMP     AL,"Y"
+        CALL    CRLF2
+        JZ      NOPRMPT
+        JMP     SHORT ASKAGN
+NOPRMPT:
+        MOV     AH,DELETE
+        MOV     BX,OFFSET TRANGROUP:NOTFND
+        CMP     BYTE PTR DS:[FCB+1]," " ;Check if parameter exists
+        JMP     SHORT OPFILE
+RENAME:
+        MOV     AH,RENAM
+        MOV     BX,OFFSET TRANGROUP:RENERR
+        CMP     BYTE PTR DS:[FCB+16+1]," "  ;Check if parameter exists
+OPFILE:
+        MOV     DX,OFFSET TRANGROUP:MISNAM
+        JZ      ERRJ            ;Error if missing parameter
+        MOV     DX,FCB
+        INT     21H
+        INC     AL
+        JNZ     RET20
+        MOV     DX,BX
+ERRJ:   JMP     ERROR
+
+TYPEFIL:
+        MOV     DS,[TPA]
+        XOR     DX,DX
+        MOV     AH,SETDMA
+        INT     21H
+        PUSH    CS
+        POP     DS
+        MOV     DX,FCB
+        MOV     AH,OPEN
+        INT     21H
+        OR      AL,AL
+        MOV     DX,OFFSET TRANGROUP:NOTFND
+        JNZ     ERRJ
+        XOR     AX,AX
+        MOV     WORD PTR DS:[FCB+RR],AX ;Set RR field
+        MOV     WORD PTR DS:[FCB+RR+2],AX
+        INC     AX
+        MOV     WORD PTR DS:[FCB+RECLEN],AX     ;Set record length
+        MOV     ES,[TPA]
+TYPELP:
+        MOV     DX,FCB
+        MOV     CX,[BYTCNT]
+        MOV     AH,RDBLK
+        INT     21H
+        JCXZ    RET30
+        XOR     SI,SI           ;Start at 0 in TPA
+OUTLP:
+        LODS    BYTE PTR ES:[SI]                ;In TPA segment
+        CMP     AL,1AH
+        JZ      RET30
+        MOV     AH,OUTCH
+        MOV     DL,AL
+        INT     21H
+        LOOP    OUTLP
+        JMP     SHORT TYPELP
+
+RET30:  RET                             ;Need a nearby RET
+
+COPY:
+        XOR     AX,AX
+        MOV     [PLUS],AL               ;Will keep track of "+"s
+        MOV     [FILECNT],AX
+        MOV     SI,81H                  ;Point to input line
+        CALL    SWITCH                  ;Skip over switches on command
+        MOV     BP,AX
+        MOV     DI,FCB
+        CALL    PARSNAM                 ;Scan first source
+        MOV     [PARM1],DL              ;Save ambiguous flag
+        MOV     [SRCPT],SI              ;Save pointer to command line
+;Parse each name to find destination and check for /V switch
+SCANNAM:
+        CALL    PARSE
+        JNZ     SCANNAM
+GETDEST:
+        MOV     DI,OFFSET TRANGROUP:DEST
+        MOV     BX,BP                   ;Remeber switches so far
+        XOR     BP,BP                   ;Must have dest. swtiches alone
+        CALL    PARSNAM
+        MOV     [ARG2S],BP              ;Remember switches on destination
+        JNZ     HAVDESTNAM              ;File name present?
+        INC     DI                      ;Point to file name spot
+        MOV     AL,"?"                  ;Substitute *.*
+        MOV     CX,11
+        REP     STOSB
+HAVDESTNAM:
+        OR      BX,BP                   ;BX = all switches combined
+        AND     BL,VSWITCH              ;Verify requested?
+        JZ      NOVER
+        MOV     AX,46*100H+1            ;Set verify
+        MOV     DL,0
+        INT     33
+NOVER:
+        MOV     DI,OFFSET TRANGROUP:DESTNAME
+        MOV     SI,OFFSET TRANGROUP:DEST+1
+        MOV     BX,FCB+1
+        CALL    BUILDNAME               ;See if we can make it unambiguous
+        MOV     DI,OFFSET TRANGROUP:DESTNAME
+        MOV     AL,"?"
+        MOV     CX,11
+        REPNE   SCASB                   ;Scan for "?" to see if ambiguous
+        MOV     AL,1                    ;Flag if ambig.
+        JZ      AMBIG
+        DEC     AX                      ;AL=0 if unambig.
+AMBIG:
+        MOV     DL,AL
+        MOV     AH,[PLUS]               ;1=found "+"
+        XOR     AL,1                    ;0=ambig, 1=unambig destination
+        AND     AL,[PARM1]              ;Source ambig. AND dest unambig.
+        OR      AL,AH                   ;OR found "+" means concatenation
+        MOV     [ASCII],AL              ;Concatenation implies ASCII mode
+        MOV     [INEXACT],AL            ;ASCII implies inexact copy
+        SHL     AL,1
+        OR      AL,DL                   ;Combine multiple and concat flags
+        MOV     [PARM2],AL
+        MOV     AL,BYTE PTR[COMSW]
+        CALL    SETASC                  ;Check /A,/B on command
+        MOV     AL,BYTE PTR[ARG1S]
+        CALL    SETASC                  ;Check for ASCII on first filename
+        MOV     BYTE PTR[COMSW],AL              ;Save starting switch values
+        MOV     AH,SRCHFRST
+        CALL    SEARCH                  ;Search for first source name
+MULTDEST:
+        JZ      FIRSTSRC                ;Find a first source name?
+        TEST    [PARM2],1               ;If multiple, we're done
+        JNZ     ENDCOPY
+        XOR     AX,AX
+        MOV     [NXTADD],AX
+        MOV     [CFLAG],AL              ;Flag nothing read yet
+NEXTSNG:
+        MOV     DI,FCB
+        MOV     SI,[SRCPT]
+        CALL    PARSESRC                ;Parse next file name into FCB
+        MOV     [PARM1],DL              ;Remember if it's ambiguous
+        MOV     [SRCPT],SI
+        JZ      SNGCLOS
+        MOV     AH,SRCHFRST
+        CALL    SEARCH                  ;Search for new file name
+        JNZ     NEXTSNG                 ;If none, skip it and move to next name
+READSNG:
+        CALL    CHECKREAD
+SNGLOOP:
+        CALL    SEARCHNEXT              ;See if any more of this name
+        JZ      READSNG
+        JMP     SHORT NEXTSNG
+
+SNGCLOS:
+        CALL    CLOSEFIL
+ENDCOPY:
+        MOV     SI,[FILECNT]
+        XOR     DI,DI
+        CALL    DISP32BITS
+        MOV     DX,OFFSET TRANGROUP:COPIED
+        MOV     AH,PRINTBUF
+        INT     21H
+        JMP     COMMAND                 ;Stack could be messed up
+
+FIRSTSRC:
+        MOV     SI,OFFSET TRANGROUP:DIRBUF+1
+        MOV     DI,OFFSET TRANGROUP:SOURCE
+        MOV     CX,11
+        REP     MOVSB                   ;Copy first source name to SOURCE
+        MOV     SI,OFFSET TRANGROUP:DESTNAME
+        MOV     DI,OFFSET TRANGROUP:DEST+1
+        MOV     BX,OFFSET TRANGROUP:SOURCE
+        CALL    BUILDNAME               ;Build destination name
+        XOR     AX,AX
+        MOV     [NXTADD],AX
+        MOV     [CFLAG],AL
+        MOV     [APPEND],AL
+        MOV     [NOWRITE],AL
+        TEST    [PARM2],1               ;Multiple destinations?
+        JZ      NOPRT
+        MOV     SI,OFFSET TRANGROUP:DIRBUF+1
+        CALL    SHONAME                 ;If so, show first source
+        CALL    CRLF2
+NOPRT:
+        CALL    COMPNAME                ;Source and dest. the same?
+        JNZ     DOREAD                  ;If not, read source in
+        TEST    [PARM2],2               ;Concatenation?
+        MOV     DX,OFFSET TRANGROUP:OVERWR
+        JZ      COPERRJ                 ;If not, overwrite error
+        MOV     [APPEND],1              ;Set physical append
+        MOV     AH,OPEN
+        MOV     DX,OFFSET TRANGROUP:DEST
+        INT     33                      ;Open (existing) destination
+        CMP     [ASCII],0               ;ASCII flag set?
+        JZ      BINARYAPP
+;ASCII append. Must find logical EOF, then seek there with dest. FCB
+        MOV     [NOWRITE],1
+        CALL    READIN                  ;Find EOF
+        CALL    FLSHFIL                 ;Seek there
+        MOV     [NOWRITE],0
+        CALL    FLSHFIL                 ;Truncate file
+        JMP     SHORT SNGLCHK
+
+SNGLOOPJ:JMP    SNGLOOP
+
+COPERRJ:JMP     COPERR
+
+BINARYAPP:
+        MOV     WORD PTR[DEST+RECLEN],1         ;Set record length to 1
+        MOV     SI,OFFSET TRANGROUP:DEST+16             ;Point to file size
+        MOV     DI,OFFSET TRANGROUP:DEST+RR
+        MOVSW
+        MOVSW                           ;Seek to end of file
+        MOV     [CFLAG],1
+        JMP     SHORT SNGLCHK
+DOREAD:
+        CALL    READIN
+SNGLCHK:
+        TEST    [PARM2],1               ;Single or multiple destinations?
+        JZ      SNGLOOPJ
+        MOV     SI,[SRCPT]
+MULTAPP:
+        CALL    PARSE
+        JZ      MULTCLOS
+        PUSH    SI
+        MOV     SI,OFFSET TRANGROUP:DIRBUF+1
+        MOV     DI,SI
+        MOV     BX,OFFSET TRANGROUP:SOURCE
+        CALL    BUILDNAME
+        CALL    CHECKREAD
+        POP     SI
+        JMP     SHORT MULTAPP
+MULTCLOS:
+        CALL    CLOSEFIL
+        MOV     AL,BYTE PTR[COMSW]
+        MOV     [ASCII],AL              ;Restore ASCII flag
+        CALL    SEARCHNEXT
+        JMP     MULTDEST
+
+PARSE:
+        MOV     DI,OFFSET TRANGROUP:DIRBUF
+PARSESRC:
+        CALL    SCANOFF
+        CMP     AL,"+"
+        JNZ     RETZF
+        MOV     [PLUS],1                ;Keep track of "+" signs
+        INC     SI                      ;Skip over it
+PARSNAM:
+        MOV     AX,2901H
+        INT     33                      ;Parse file name
+        CMP     AL,-1                   ;Illegal?
+        MOV     DX,OFFSET TRANGROUP:BADDRV
+        JZ      COPERRJ
+        XCHG    AX,DX                   ;Save parse flag in DL
+        MOV     AL,BYTE PTR[DI]         ;Get drive number
+        OR      AL,AL                   ;Is it default?
+        JNZ     PARSW
+        MOV     AL,[CURDRV]             ;Substitute actual drive
+        INC     AX
+        MOV     BYTE PTR[DI],AL
+PARSW:
+        PUSH    BX
+        PUSH    DI
+        CALL    SWITCH                  ;Process switches
+        OR      BP,AX                   ;Combine all switches
+        CALL    SETASC                  ;Check for /A or /B
+        POP     DI
+        POP     BX
+        CMP     BYTE PTR[DI+1]," "              ;Did we even get a file name?
+        RET
+
+RETZF:
+        XOR     AX,AX
+RET35:  RET
+
+SEARCHNEXT:
+        MOV     AL,[PARM1]              ;Is name ambiguous?
+        DEC     AL
+        JNZ     RET35                   ;Don't perform search if not
+        MOV     AH,SRCHNXT
+SEARCH:
+        PUSH    AX
+        MOV     AH,SETDMA
+        MOV     DX,OFFSET TRANGROUP:DIRBUF
+        INT     33                      ;Put result of search in DIRBUF
+        POP     AX                      ;Restore search first/next command
+        MOV     DX,FCB
+        INT     33                      ;Do the search
+        OR      AL,AL
+        RET
+
+SETASC:
+;Given switch vector in AX, 
+;       Set ASCII switch if /A is set
+;       Clear ASCII switch if /B is set
+;       Leave ASCII unchanged if neither or both are set
+; Also sets INEXACT if ASCII is ever set. AL = ASCII on exit, flags set
+        AND     AL,ASWITCH+BSWITCH
+        JPE     LOADSW                  ;PE means both or neither are set
+        AND     AL,ASWITCH
+        MOV     [ASCII],AL
+        OR      [INEXACT],AL
+LOADSW:
+        MOV     AL,[ASCII]
+        OR      AL,AL
+        RET
+
+BUILDNAME:
+; [SI] = Ambiguous input file name
+; [BX] = Source of replacement characters
+; [DI] = Destination
+; File name is copied from [SI] to [DI]. If "?"s are encountered,
+; they are replaced with the character in the same position at [BX].
+        MOV     CX,11
+BUILDNAM:
+        LODSB
+        CMP     AL,"?"
+        JNZ     NOTAMBIG
+        MOV     AL,BYTE PTR[BX]
+NOTAMBIG:
+        STOSB
+        INC     BX
+        LOOP    BUILDNAM
+        RET
+
+COMPNAME:
+        MOV     SI,OFFSET TRANGROUP:DEST
+        MOV     DI,OFFSET TRANGROUP:DIRBUF
+        MOV     CX,6
+        REPE    CMPSW
+        RET
+
+CHECKREAD:
+;Read file in (with READIN) if not identical to destination
+        CALL    COMPNAME                ;See if source and destination the same
+        JNZ     READIN
+        CMP     [APPEND],0              ;If physical append, it's OK
+        JNZ     RET40
+        MOV     DX,OFFSET TRANGROUP:LOSTERR             ;Tell him he's not going to get it
+        MOV     AH,PRINTBUF
+        INT     33
+RET40:  RET
+
+READIN:
+;Open source file and read it in. If memory fills up, flush it out to
+;destination and keep reading. If /A switch set, chop file at first ^Z.
+; Inputs/Outputs:
+;       [NXTADD] has current pointer in buffer
+;       [CFLAG] <>0 if destination has been created
+
+        MOV     DX,OFFSET TRANGROUP:DIRBUF
+        MOV     AH,OPEN
+        INT     21H
+        OR      AL,AL                   ;Successful open?
+        JNZ     RET40                   ;If not, just ignore it
+        XOR     AX,AX
+        MOV     WORD PTR[DIRBUF+RR],AX
+        MOV     WORD PTR[DIRBUF+RR+2],AX
+        INC     AX
+        MOV     WORD PTR[DIRBUF+RECLEN],AX
+COPYLP:
+        MOV     DX,[NXTADD]
+        MOV     AH,SETDMA
+        PUSH    DS
+        MOV     DS,[TPA]
+        INT     33
+        POP     DS
+        MOV     CX,[BYTCNT]
+        SUB     CX,DX                   ;Compute available space
+        MOV     DX,OFFSET TRANGROUP:DIRBUF
+        MOV     AH,RDBLK                ;Read in source file
+        INT     21H
+        JCXZ    RET40
+        CMP     [ASCII],0
+        JZ      BINREAD
+        MOV     DX,CX
+        MOV     DI,[NXTADD]
+        MOV     AL,1AH
+        PUSH    ES
+        MOV     ES,[TPA]
+        REPNE   SCASB                   ;Scan for EOF
+        POP     ES
+        JNZ     USEALL
+        INC     CX
+USEALL:
+        SUB     DX,CX
+        MOV     CX,DX
+BINREAD:
+        ADD     CX,[NXTADD]
+        MOV     [NXTADD],CX
+        CMP     CX,[BYTCNT]             ;Is buffer full?
+        JB      RET40                   ;If not, we must have found EOF
+        CALL    FLSHFIL
+        JMP     SHORT COPYLP
+
+CLOSEFIL:
+        MOV     AX,[NXTADD]
+        MOV     BX,AX
+        OR      AL,AH                   ;See if any data is loaded
+        OR      AL,[CFLAG]              ;   or file was created
+        JZ      RET50                   ;Don't close or count if not created
+        MOV     AL,BYTE PTR[ARG2S]
+        CALL    SETASC                  ;Check for /B or /A on destination
+        JZ      BINCLOS
+        CMP     BX,[BYTCNT]             ;Is memory full?
+        JNZ     PUTZ
+        CALL    FLSHFIL                 ;Empty it to make room for 1 lousy byte
+        XOR     BX,BX
+PUTZ:
+        PUSH    DS
+        MOV     DS,[TPA]
+        MOV     WORD PTR[BX],1AH                ;Add End-of-file mark (Ctrl-Z)
+        POP     DS
+        INC     [NXTADD]
+BINCLOS:
+        CALL    FLSHFIL
+        CMP     [INEXACT],0             ;Copy not exact?
+        JNZ     NODATE                  ;If so, don't copy date & time
+        MOV     SI,OFFSET TRANGROUP:DIRBUF+OFFDATE
+        MOV     DI,OFFSET TRANGROUP:DEST+OFFDATE        ;Make date & time same as original
+        MOVSW                           ;Copy date
+        MOVSW                           ;Copy time
+NODATE:
+        MOV     DX,OFFSET TRANGROUP:DEST
+        MOV     AH,CLOSE
+        INT     21H
+        INC     [FILECNT]
+RET50:  RET
+
+FLSHFIL:
+;Write out any data remaining in memory.
+; Inputs:
+;       [NXTADD] = No. of bytes to write
+;       [CFLAG] <>0 if file has been created
+; Outputs:
+;       [NXTADD] = 0
+
+        MOV     AL,1
+        XCHG    [CFLAG],AL
+        OR      AL,AL
+        JNZ     EXISTS
+        CMP     [NOWRITE],0
+        JNZ     SKPMAK                  ;Don't actually create if NOWRITE set
+        MOV     DX,OFFSET TRANGROUP:DEST
+        MOV     AH,MAKE
+        INT     21H
+        MOV     DX,OFFSET TRANGROUP:FULDIR
+        OR      AL,AL
+        JNZ     COPERR
+SKPMAK:
+        XOR     AX,AX
+        MOV     WORD PTR[DEST+RR],AX
+        MOV     WORD PTR[DEST+RR+2],AX
+        INC     AX
+        MOV     WORD PTR[DEST+RECLEN],AX
+EXISTS:
+        XOR     CX,CX
+        XCHG    CX,[NXTADD]
+        CMP     [NOWRITE],0             ;If NOWRITE set, just seek CX bytes
+        JNZ     SEEKEND
+        XOR     DX,DX
+        PUSH    DS
+        MOV     DS,[TPA]
+        MOV     AH,SETDMA
+        INT     33
+        POP     DS
+        MOV     DX,OFFSET TRANGROUP:DEST
+        MOV     AH,WRBLK
+        INT     21H
+        OR      AL,AL
+        JZ      RET60
+        MOV     DX,OFFSET TRANGROUP:DEST
+        MOV     AH,CLOSE
+        INT     21H
+        MOV     AH,DELETE
+        INT     33
+        MOV     DX,OFFSET TRANGROUP:NOSPACE
+COPERR:
+        MOV     AH,9
+        INT     21H
+        JMP     ENDCOPY
+
+SEEKEND:
+        ADD     WORD PTR[DEST+RR],CX
+        ADC     WORD PTR[DEST+RR+2],0           ;Propagate carry
+RET60:  RET
+
+GETBATBYT:
+;Get one byte from the batch file and return it in AL. End-of-file
+;returns <CR> and ends batch mode. DS must be set to resident segment.
+;AH, CX, DX destroyed.
+ASSUME  DS:RESGROUP
+        MOV     DX,OFFSET RESGROUP:BATFCB
+        MOV     AH,RDBLK
+        MOV     CX,1
+        INT     33              ;Get one more byte from batch file
+        JCXZ    BATEOF
+        MOV     AL,[BATBYT]
+        CMP     AL,1AH
+        JNZ     RET70
+BATEOF:
+        MOV     AL,0DH          ;If end-of-file, then end of line
+        MOV     [BATCH],0       ;And turn off batch mode
+RET70:  RET
+ASSUME  DS:TRANGROUP
+
+SCANOFF:
+        LODSB
+        CALL    DELIM
+        JZ      SCANOFF
+        DEC     SI              ;Point to first non-delimiter
+        RET
+
+DELIM:
+        CMP     AL," "
+        JZ      RET80
+        CMP     AL,"="
+        JZ      RET80
+        CMP     AL,","
+        JZ      RET80
+        CMP     AL,9            ;Check for TAB character
+RET80:  RET
+
+PAUSE:
+        MOV     DX,OFFSET TRANGROUP:PAUSMES
+        MOV     AH,PRINTBUF
+        INT     33
+        MOV     AX,0C00H+INCHAR ;Get character with KB buffer flush
+        INT     33
+RET90:  RET
+
+;Date and time are set during initialization and use
+;this routines since they need to do a long return
+
+DATINIT:
+        PUSH    ES
+        PUSH    DS              ;Going to use the previous stack
+        MOV     AX,CS           ;Set up the appropriate segment registers
+        MOV     ES,AX
+        MOV     DS,AX
+        MOV     WORD PTR DS:[81H],13    ;Want to prompt for date during initialization
+        CALL    DATE
+        CALL    TIME
+        POP     DS
+        POP     ES
+YYY     PROC    FAR
+        RET
+YYY     ENDP
+
+; DATE - Gets and sets the time
+
+DATE:
+        MOV     SI,81H          ;Accepting argument for date inline
+        CALL    SCANOFF
+        CMP     AL,13
+        JZ      PRMTDAT
+        MOV     BX,2F00H+"-"    ;"/-"
+        CALL    INLINE
+        JMP     COMDAT
+
+PRMTDAT:
+        MOV     DX,OFFSET TRANGROUP:CURDAT
+        MOV     AH,PRINTBUF
+        INT     33              ;Print "Current date is "
+        MOV     AH,GETDATE
+        INT     33              ;Get date in CX:DX
+        CBW
+        MOV     SI,AX
+        SHL     SI,1
+        ADD     SI,AX           ;SI=AX*3
+        ADD     SI,OFFSET TRANGROUP:WEEKTAB
+        MOV     BX,CX
+        MOV     CX,3
+        CALL    OUTCNT
+        MOV     AL," "
+        CALL    OUT
+        MOV     AX,BX
+        MOV     CX,DX
+        MOV     DL,100
+        DIV     DL
+        XCHG    AL,AH
+        XCHG    AX,DX
+        MOV     BL,"-"
+        CALL    SHOW
+GETDAT:
+        MOV     DX,OFFSET TRANGROUP:NEWDAT
+        MOV     BX,2F00H+"-"    ;"/-" in BX
+        CALL    GETBUF
+COMDAT: JZ      RET90
+        JC      DATERR
+        LODSB   
+        CMP     AL,BL
+        JZ      SEPGD
+        CMP     AL,BH
+        JNZ     DATERR
+SEPGD:  CALL    GETNUM
+        JC      DATERR
+        MOV     CX,1900
+        CMP     BYTE PTR[SI],13
+        JZ      BIAS
+        MOV     AL,100
+        MUL     AH
+        MOV     CX,AX
+        CALL    GETNUM
+        JC      DATERR
+BIAS:
+        MOV     AL,AH
+        MOV     AH,0
+        ADD     CX,AX
+        LODSB
+        CMP     AL,13
+        JNZ     DATERR
+        MOV     AH,SETDATE
+        INT     33
+        OR      AL,AL
+        JNZ     DATERR
+        JMP     RET90
+DATERR:
+        MOV     DX,OFFSET TRANGROUP:BADDAT
+        MOV     AH,PRINTBUF
+        INT     33
+        JMP     GETDAT
+
+; TIME gets and sets the time
+
+TIME:
+        MOV     SI,81H                  ;Accepting argument for time inline
+        CALL    SCANOFF
+        CMP     AL,13
+        JZ      PRMTTIM
+        MOV     BX,3A00H+":"
+        CALL    INLINE
+        JMP     COMTIM
+
+PRMTTIM:
+        MOV     DX,OFFSET TRANGROUP:CURTIM
+        MOV     AH,PRINTBUF
+        INT     33              ;Print "Current time is "
+        MOV     AH,GETTIME
+        INT     33              ;Get time in CX:DX
+        MOV     BL,":"
+        CALL    SHOW
+GETTIM:
+        XOR     CX,CX           ;Initialize hours and minutes to zero
+        MOV     DX,OFFSET TRANGROUP:NEWTIM
+        MOV     BX,3A00H+":"
+        CALL    GETBUF
+COMTIM: JZ      RET100          ;If no time present, don't change it
+        JC      TIMERR
+        MOV     CX,DX
+        XOR     DX,DX
+        LODSB
+        CMP     AL,13
+        JZ      SAVTIM
+        CMP     AL,BL
+        JNZ     TIMERR
+        MOV     BL,"."
+        CALL    GETNUM
+        JC      TIMERR
+        MOV     DH,AH           ;Position seconds
+        LODSB
+        CMP     AL,13
+        JZ      SAVTIM
+        CMP     AL,BL
+        JNZ     TIMERR  
+        CALL    GETNUM
+        JC      TIMERR
+        MOV     DL,AH
+        LODSB
+        CMP     AL,13
+        JNZ     TIMERR
+SAVTIM:
+        MOV     AH,SETTIME
+        INT     33
+        OR      AL,AL
+        JZ      RET100          ;Error in time?
+TIMERR:
+        MOV     DX,OFFSET TRANGROUP:BADTIM
+        MOV     AH,PRINTBUF
+        INT     33              ;Print error message
+        JMP     GETTIM          ;Try again
+
+GETBUF:
+        MOV     AH,PRINTBUF
+        INT     33              ;Print "Enter new date: "
+        MOV     AH,INBUF
+        MOV     DX,OFFSET TRANGROUP:COMBUF
+        INT     33              ;Get input line
+        CALL    CRLF2
+        MOV     SI,OFFSET TRANGROUP:COMBUF+2
+        CMP     BYTE PTR[SI],13 ;Check if new date entered
+        JZ      RET100
+INLINE:
+        CALL    GETNUM          ;Get one or two digit number
+        JC      RET100
+        MOV     DH,AH           ;Put in position
+        LODSB
+        CMP     AL,BL
+        JZ      NEXT
+        CMP     BL,":"          ;Is it a date seperator?
+        JNZ     DATESEP
+        DEC     SI
+        MOV     DL,0
+RET100: RET                     ;Time may have only an hour specified
+DATESEP:
+        CMP     AL,BH
+        STC
+        JNZ     RET100
+NEXT:   CALL    GETNUM
+        MOV     DL,AH           ;Put in position
+        RET
+
+GETNUM:
+        CALL    INDIG
+        JC      RET100
+        MOV     AH,AL           ;Save first digit
+        CALL    INDIG           ;Another digit?
+        JC      OKRET
+        AAD                     ;Convert unpacked BCD to decimal
+        MOV     AH,AL
+OKRET:
+        OR      AL,1
+RET110: RET
+
+INDIG:
+        MOV     AL,BYTE PTR[SI]
+        SUB     AL,"0"
+        JC      RET110
+        CMP     AL,10
+        CMC
+        JC      RET110
+        INC     SI
+        RET
+
+SHOW:
+        MOV     AL,CH
+        MOV     BH,"0"-" "      ;Enable leading zero suppression
+        CALL    OUT2
+        MOV     AL,BL
+        CALL    OUT
+        MOV     AL,CL
+        CALL    OUT2
+        MOV     AL,BL
+        CALL    OUT
+        MOV     AL,DH
+        CALL    OUT2
+        CMP     BL,":"          ;Are we outputting time?
+        JNZ     SKIPIT
+        MOV     AL,"."
+        CALL    OUT
+SKIPIT: MOV     AL,DL
+OUT2:   ;Output binary number as two ASCII digits
+        AAM                     ;Convert binary to unpacked BCD
+        XCHG    AL,AH
+        OR      AX,3030H        ;Add "0" bias to both digits
+        CMP     AL,"0"          ;Is MSD zero?
+        JNZ     NOSUP
+        SUB     AL,BH           ;Suppress leading zero if enabled
+NOSUP:
+        MOV     BH,0            ;Disable zero suppression
+        CALL    OUT
+        MOV     AL,AH
+OUT:
+;Print char in AL without affecting registers
+        XCHG    AX,DX
+        PUSH    AX
+        MOV     AH,OUTCH
+        INT     33
+        POP     AX
+        XCHG    AX,DX
+        RET
+
+EXELOAD:
+        MOV     AX,CS
+        ADD     AX,LOADSEG
+        MOV     [EXEEND],AX     ;Store in EXEEND
+        MOV     DX,OFFSET TRANGROUP:RUNVAR      ;Read header in here
+        MOV     AH,SETDMA
+        INT     33
+        MOV     CX,RUNVARSIZ    ;Amount of header info we need
+        MOV     DX,OFFSET TRANGROUP:EXEFCB
+        MOV     AH,RDBLK
+        INT     33              ;Read in header
+        OR      AL,AL
+        JNZ     BADEXE          ;Must not reach EOF
+        MOV     AX,[HEADSIZ]    ;Size of header in paragraphs
+;Convert header size to 512-byte pages by multiplying by 32 & rounding up
+        ADD     AX,31           ;Round up first
+        MOV     CL,5
+        SHR     AX,CL           ;Multiply by 32
+        MOV     [EXEFCB+RR],AX  ;Position in file of program
+        MOV     WORD PTR[EXEFCB+RECLEN],512 ;Set record size
+        ADD     BX,10H          ;First paragraph above parameter area
+        MOV     DX,[PAGES]      ;Total size of file in 512-byte pages
+        SUB     DX,AX           ;Size of program in pages
+        MOV     [PSIZE],DX
+        SHL     DX,CL           ;Convert pages back to paragraphs
+        MOV     AX,DX
+        ADD     DX,BX           ;Size + start = minimum memory (paragr.)
+        MOV     CX,[EXEEND]     ;Get memory size in paragraphs
+        CMP     DX,CX           ;Enough memory?
+        JA      SHRTERR
+        MOV     DX,[INITSP]
+        ADD     DX,15
+        SHR     DX,1
+        SHR     DX,1
+        SHR     DX,1
+        SHR     DX,1
+        ADD     DX,[INITSS]
+        ADD     DX,BX           ;Adjusted value of SP
+        CMP     DX,CX           ;Is it valid?
+        JA      SHRTERR
+        CMP     [LOADLOW],-1    ;Load low or high?
+        JZ      LOAD            ;If low, load at segment BX
+        SUB     CX,AX           ;Memory size - program size = load addr.
+        MOV     BX,CX
+LOAD:
+        MOV     BP,BX           ;Save load segment
+LOAD1:
+LOADSEG EQU     (LOAD1-ZERO)/16
+        PUSH    DS
+        MOV     DS,BX
+        XOR     DX,DX           ;Address 0 in segment
+        MOV     AH,SETDMA
+        INT     33              ;Set load address
+        POP     DS
+        MOV     CX,[PSIZE]      ;Number of records to read
+        MOV     DX,OFFSET TRANGROUP:EXEFCB
+        MOV     AH,RDBLK
+        INT     33              ;Read in up to 64K
+        SUB     [PSIZE],CX      ;Decrement count by amount read
+        JZ      HAVEXE          ;Did we get it all?
+        TEST    AL,1            ;Check return code if not
+        JNZ     BADEXE          ;Must be zero if more to come
+        ADD     BX,1000H-20H    ;Bump data segment 64K minus one record
+        JMP     SHORT LOAD1             ;Get next 64K block
+
+BADEXE:
+        MOV     DX,OFFSET TRANGROUP:EXEBAD
+        JMP     ERROR
+
+SHRTERR:
+        MOV     DX,OFFSET TRANGROUP:TOOBIG
+        JMP     ERROR
+
+HAVEXE:
+        MOV     AX,[RELTAB]     ;Get position of table
+        MOV     [EXEFCB+RR],AX  ;Set in random record field
+        MOV     WORD PTR[EXEFCB+RECLEN],1  ;Set one-byte record
+        MOV     DX,OFFSET TRANGROUP:RELPT       ;4-byte buffer for relocation address
+        MOV     AH,SETDMA
+        INT     33
+        CMP     [RELCNT],0
+        JZ      NOREL
+RELOC:
+        MOV     AH,RDBLK
+        MOV     DX,OFFSET TRANGROUP:EXEFCB
+        MOV     CX,4
+        INT     33              ;Read in one relocation pointer
+        OR      AL,AL           ;Check return code
+        JNZ     BADEXE
+        MOV     DI,[RELPT]      ;Get offset of relocation pointer
+        MOV     AX,[RELSEG]     ;Get segment
+        ADD     AX,BP           ;Bias segment with actual load segment
+        MOV     ES,AX
+        ADD     WORD PTR ES:[DI],BP             ;Relocate
+        DEC     [RELCNT]        ;Count off
+        JNZ     RELOC
+;Set up exit conditions
+NOREL:
+        MOV     AX,[INITSS]
+        ADD     AX,BP
+        CLI
+        MOV     SS,AX           ;Initialize SS
+        MOV     SP,[INITSP]
+        STI
+        ADD     [INITCS],BP
+        MOV     AX,[TPA]        ;Get pointer to parameter area
+        MOV     CX,[BYTCNT]     ;Size of TPA segment
+        MOV     ES,AX
+        MOV     DS,AX           ;Set segment registers to point to it
+        CALL    SETUP
+        JMP     DWORD PTR CS:[INITIP]   ;Long jump to program
+
+SETUP:
+        AND     CL,0F0H         ;Adjust to even paragraph boundary
+        MOV     AX,WORD PTR DS:[6]              ;Get current memory size
+        SUB     AX,CX           ;Find out how much we're changing it
+        MOV     WORD PTR DS:[6],CX
+        MOV     CL,4
+        SAR     AX,CL           ;Convert to a segment address
+        ADD     WORD PTR DS:[8],AX              ;Adjust long jump to go to same place
+        MOV     DX,80H
+        MOV     AH,SETDMA
+        INT     33              ;Set default disk transfer address
+        MOV     AX,WORD PTR CS:[PARM1]  ;Pass on info about FCBs
+        XOR     CX,CX
+        MOV     DX,CX           ;Assume no batch file
+ASSUME  CS:RESGROUP
+        TEST    CS:[BATCH],-1   ;Batch file in progress?
+ASSUME  CS:TRANGROUP
+        JZ      RET120          ;If not, all set up
+        MOV     CX,CS:[RESSEG]
+        MOV     DX,OFFSET RESGROUP:BATFCB       ;CX:DX points to batch FCB
+RET120: RET
+TRANCODESIZE    EQU     $-ZERO
+TRANCODE        ENDS
+COMLEN  EQU     TRANDATASIZE+TRANCODESIZE-102H          ;End of COMMAND load. ZERO Needed to make COMLEN absolute
+TRNLEN  EQU     (PRETRLEN+TRANCODESIZE+TRANDATASIZE+15)/16              ;Length of transient in paragraphs
+        END     PROGSTART
+\1a
\ No newline at end of file
diff --git a/v1.25/source/HEX2BIN.ASM b/v1.25/source/HEX2BIN.ASM
new file mode 100644 (file)
index 0000000..d7ba742
--- /dev/null
@@ -0,0 +1,214 @@
+; HEX2BIN  version 1.02
+; Converts Intel hex format files to straight binary
+
+FCB:   EQU     5CH
+READ:  EQU     20
+SETDMA:        EQU     26
+OPEN:  EQU     15
+CLOSE: EQU     16
+CREATE:        EQU     22
+DELETE:        EQU     19
+BLKWRT:        EQU     40
+GETSEG:        EQU     38
+BUFSIZ:        EQU     1024
+
+       ORG     100H
+       PUT     100H
+
+HEX2BIN:
+       MOV     DI,FCB+9
+       CMP     B,[DI]," "
+       JNZ     HAVEXT
+       MOV     SI,HEX
+       MOVB
+       MOVW
+HAVEXT:
+;Get load offset (default is -100H)
+       MOV     CL,4            ;Needed for shifts
+       MOV     [OFFSET],-100H
+       MOV     SI,FCB+11H      ;Scan second FCB for offset
+       LODB
+       CMP     AL," "          ;Check if offset present
+       JZ      HAVOFF
+       MOV     B,[SIGN],0      ;Assume positive sign for now
+       CMP     AL,"+"
+       JZ      GETOFF          ;Get a positive offset
+       CMP     AL,"-"
+       JNZ     GETOFF1         ;If not + or -, then not signed
+       MOV     B,[SIGN],1      ;Flag as negative offset
+GETOFF:
+       LODB                    ;Eat sign
+GETOFF1:
+       CALL    HEXCHK          ;Check for valid hex character
+       JC      HAVOFF          ;No offset if not valid
+       XOR     BX,BX           ;Intialize offset sum to 0
+CONVOFF:
+       SHL     BX,CL           ;Multiply current sum by 16
+       OR      BL,AL           ;Add in current hex digit
+       LODB                    ;Get next digit
+       CALL    HEXCHK          ;And convert it to binary
+       JNC     CONVOFF         ;Loop until all hex digits read
+       TEST    B,[SIGN],-1     ;Check if offset was to be negative
+       JZ      SAVOFF
+       NEG     BX
+SAVOFF:
+       MOV     [OFFSET],BX
+HAVOFF:
+       MOV     DX,STARTSEG
+       MOV     AX,DS
+       ADD     DX,AX           ;Compute load segment
+       MOV     AH,GETSEG
+       INT     33
+       MOV     ES,DX
+       SEG     ES
+       MOV     CX,[6]          ;Get size of segment
+       MOV     [SEGSIZ],CX
+       XOR     AX,AX
+       MOV     DI,AX
+       MOV     BP,AX
+       SHR     CX
+       REP
+       STOW                    ;Fill entire segment with zeros
+       MOV     AH,OPEN
+       MOV     DX,FCB
+       INT     21H
+       OR      AL,AL
+       JNZ     NOFIL
+       MOV     B,[FCB+32],0
+       MOV     [FCB+14],BUFSIZ ;Set record size to buffer size
+       MOV     DX,BUFFER
+       MOV     AH,SETDMA
+       INT     33
+       MOV     AH,READ
+       MOV     DX,FCB          ;All set up for sequential reads
+       MOV     SI,BUFFER+BUFSIZ ;Flag input buffer as empty
+READHEX:
+       CALL    GETCH
+       CMP     AL,":"          ;Search for : to start line
+       JNZ     READHEX
+       CALL    GETBYT          ;Get byte count
+       MOV     CL,AL
+       MOV     CH,0
+       JCXZ    DONE
+       CALL    GETBYT          ;Get high byte of load address
+       MOV     BH,AL
+       CALL    GETBYT          ;Get low byte of load address
+       MOV     BL,AL
+       ADD     BX,[OFFSET]     ;Add in offset
+       MOV     DI,BX
+       CALL    GETBYT          ;Throw away type byte
+READLN:
+       CMP     DI,[SEGSIZ]
+       JAE     ADERR
+       CALL    GETBYT          ;Get data byte
+       STOB
+       CMP     DI,BP           ;Check if this is the largest address so far
+       JBE     HAVBIG
+       MOV     BP,DI           ;Save new largest
+HAVBIG:
+       LOOP    READLN
+       JP      READHEX
+
+NOFIL:
+       MOV     DX,NOFILE
+QUIT:
+       MOV     AH,9
+       INT     21H
+       INT     20H
+
+ADERR:
+       MOV     DX,ADDR
+       JMP     SHOWERR
+
+GETCH:
+       CMP     SI,BUFFER+BUFSIZ
+       JNZ     NOREAD
+       INT     21H
+       CMP     AL,1
+       JZ      ERROR
+       MOV     SI,BUFFER
+NOREAD:
+       LODB
+       CMP     AL,1AH
+       JZ      DONE
+       RET
+
+GETBYT:
+       CALL    HEXDIG
+       MOV     BL,AL
+       CALL    HEXDIG
+       SHL     BL
+       SHL     BL
+       SHL     BL
+       SHL     BL
+       OR      AL,BL
+       RET
+
+HEXCHK:
+       SUB     AL,"0"
+       JC      RET
+       CMP     AL,10
+       JC      CMCRET
+       SUB     AL,"A"-"0"-10
+       JC      RET
+       CMP     AL,16
+CMCRET:
+       CMC
+       RET
+
+HEXDIG:
+       CALL    GETCH
+       CALL    HEXCHK
+       JNC     RET
+ERROR:
+       MOV     DX,ERRMES
+SHOWERR:
+       MOV     AH,9
+       INT     21H
+DONE:
+       MOV     [FCB+9],4F00H+"C"       ;"CO"
+       MOV     B,[FCB+11],"M"
+       MOV     DX,FCB
+       MOV     AH,CREATE
+       INT     21H
+       OR      AL,AL
+       JNZ     NOROOM
+       XOR     AX,AX
+       MOV     [FCB+33],AX
+       MOV     [FCB+35],AX     ;Set RR field
+       INC     AX
+       MOV     [FCB+14],AX     ;Set record size
+       XOR     DX,DX
+       PUSH    DS
+       PUSH    ES
+       POP     DS              ;Get load segment
+       MOV     AH,SETDMA
+       INT     21H
+       POP     DS
+       MOV     CX,BP
+       MOV     AH,BLKWRT
+       MOV     DX,FCB
+       INT     21H
+       MOV     AH,CLOSE
+       INT     21H
+EXIT:
+       INT     20H
+
+NOROOM:
+       MOV     DX,DIRFUL
+       JMP     QUIT
+
+HEX:   DB      "HEX"
+ERRMES:        DB      "Error in HEX file--conversion aborted$"
+NOFILE:        DB      "File not found$"
+ADDR:  DB      "Address out of range--conversion aborted$"
+DIRFUL:        DB      "Disk directory full$"
+
+OFFSET:        DS      2
+SEGSIZ:        DS      2
+SIGN:  DS      1
+BUFFER:        DS      BUFSIZ
+
+START:
+STARTSEG EQU   (START+15)/16
+\1a
\ No newline at end of file
diff --git a/v1.25/source/IO.ASM b/v1.25/source/IO.ASM
new file mode 100644 (file)
index 0000000..3b9f181
--- /dev/null
@@ -0,0 +1,1934 @@
+; I/O System for 86-DOS version 1.20 and later. Revised 8-02-82.
+;
+; Assumes a CPU Support card at F0 hex for character I/O,
+; with disk drivers for SCP, Tarbell, or Cromemco controllers.
+;
+; Select whether console input is interrupt-driven or polled.
+INTINP:                EQU     1
+;
+; Select whether the auxiliary port is the Support Card parallel port
+; or on channel 1 of a Multiport Serial card addressed at 10H.
+PARALLELAUX:   EQU     1
+SERIALAUX:     EQU     0
+;
+; Select whether the printer is connected to the Support card parallel
+; output port (standard) or channel 0 of a Multiport Serial card
+; addressed at 10H.
+PARALLELPRN:   EQU     1
+SERIALPRN:     EQU     0
+;
+; If the Multiport Serial was chosen for either the auxiliary or the
+; printer, select the baud rate here. Refer to Multiport Serial manual
+; page 11 to pick the correct value for a given baud rate.
+PRNBAUD:EQU    7               ; 1200 baud
+AUXBAUD:EQU    0FH             ; 19200 baud
+;
+; Select disk controller here.
+SCP:           EQU     1
+TARBELLSD:     EQU     0
+TARBELLDD:     EQU     0
+CROMEMCO4FDC:  EQU     0
+CROMEMCO16FDC: EQU     0
+;
+; Select if you want a special conversion version which can read/write
+; both the new Microsoft format and the old SCP format.
+; For a two drive system, drives A and B are the new Microsoft format,
+; and drives C and D are the old SCP format (where C is the same physical
+; drive as A, and D is the same drive as B).  CONVERT has no effect
+; on 5.25-inch drives.
+CONVERT:EQU    1
+;
+; Select disk configuration:
+LARGE: EQU     1               ; Large drives.
+COMBIN:        EQU     0               ; Two 8-inch and one 5.25-inch.
+SMALL: EQU     0               ; Three 5.25-inch drives.
+CUSTOM:        EQU     0               ; User defined.
+;
+; If 8-inch drives are PerSci, select FASTSEEK here:
+; (Fastseek with Tarbell controllers doesn't work yet).
+FASTSEEK:      EQU     1
+;
+; For double-density controllers, select double-sided operation of
+; 8-inch disks in double-density mode.
+LARGEDS:       EQU     0
+;
+; For double-density controllers, select double-sided operation of
+; 5.25-inch disks in double-density mode.
+SMALLDS:       EQU     0
+;
+; Use table below to select head step speed. Step times for 5" drives
+; are double that shown in the table. Times for Fast Seek mode (using
+; PerSci drives) is very small - 200-400 microseconds.
+;
+; Step value   1771    1793
+;
+;     0                 6ms     3ms
+;     1                 6ms     6ms
+;     2                10ms    10ms
+;     3                20ms    15ms
+;
+STPSPD:        EQU     0
+;
+; ****** End of selections ********************************************
+;
+BIOSSEG:EQU    40H             ; I/O system segment.
+BIOSLEN:EQU    2048            ; Maximum length of I/O system.
+DOSLEN:        EQU     8192            ; Maximum length of MS-DOS.
+QSIZE: EQU     80              ; Input queue size.
+PBUFSIZ:EQU    128             ; Size of print buffer
+BASE:  EQU     0F0H            ; CPU Support card base port number.
+SIOBASE:EQU    10H             ; Base port number of Multiport Serial card.
+STAT:  EQU     BASE+7          ; Serial I/O status port.
+DATA:  EQU     BASE+6          ; Serial I/O data port.
+DAV:   EQU     2               ; Data available bit.
+TBMT:  EQU     1               ; Transmitter buffer empty bit.
+SERIAL:        EQU     SERIALPRN+SERIALAUX
+STCDATA:EQU    BASE+4          ; Ports for 9513 Timer chip.
+STCCOM:        EQU     BASE+5
+
+       IF      SERIALAUX
+AUXSTAT:EQU    SIOBASE+3
+AUXDATA:EQU    SIOBASE+2
+       ENDIF
+
+       IF      PARALLELAUX
+AUXSTAT:EQU    BASE+13
+AUXDATA:EQU    BASE+12
+       ENDIF
+
+       IF      SERIALPRN
+PRNSTAT:EQU    SIOBASE+1
+PRNDATA:EQU    SIOBASE+0
+       ENDIF
+
+       IF      PARALLELPRN
+PRNSTAT:EQU    BASE+13
+PRNDATA:EQU    BASE+12
+       ENDIF
+
+       ORG     0
+       PUT     100H
+
+       JMP     INIT
+       JMP     STATUS
+       JMP     INP
+       JMP     OUTP
+       JMP     PRINT
+       JMP     AUXIN
+       JMP     AUXOUT
+       JMP     READ
+       JMP     WRITE
+       JMP     DSKCHG
+       JMP     SETDATE
+       JMP     SETTIME
+       JMP     GETTIME
+       JMP     FLUSH
+       JMP     MAPDEV
+MAPDEV:
+       RET     L
+
+INIT:
+       XOR     BP,BP           ; Set up stack just below I/O system.
+       MOV     SS,BP
+       MOV     SP,BIOSSEG*16
+
+       IF      INTINP-1
+       MOV     AL,0FFH         ; Mask all interrupts.
+       OUTB    BASE+3
+       ENDIF
+
+       IF      INTINP
+       DI                      ; Set up keyboard interrupt vector.
+       MOV     [BP+64H],KBINT
+       MOV     [BP+66H],CS
+       EI
+       ENDIF
+
+       MOV     [BP+4*38H],PRNFCB
+       MOV     [BP+4*38H+2],CS
+       PUSH    CS
+       POP     DS
+;
+; Initialize time-of-day clock.
+;
+       MOV     SI,STCTAB
+       MOV     CX,4            ;Initialize 4 registers
+       UP
+INITSTC:
+       LODB
+       OUT     STCCOM          ;Select register to initialize
+       LODB
+       OUT     STCDATA
+       LODB
+       OUT     STCDATA
+       LOOP    INITSTC
+
+       IF      SERIAL
+       MOV     CX,4
+SERINIT:
+       LODB
+       OUT     SIOBASE+1
+       OUT     SIOBASE+3
+       LOOP    SERINIT
+       LODB                    ;Baud rate for channel 0
+       OUT     SIOBASE+8
+       LODB                    ;Baud rate for channel 1
+       OUT     SIOBASE+9
+       ENDIF
+;
+; Move MS-DOS down to the first segment just above the I/O system.
+;
+       MOV     SI,BIOSLEN      ; Source points to where MS-DOS currently is.
+       MOV     AX,DOSSEG       ; Destination is beginning of DOSSEG.
+       MOV     ES,AX
+       SUB     DI,DI
+       MOV     CX,DOSLEN/2     ; CX is number of words to move.
+       REP
+       MOVSW
+
+       MOV     SI,INITTAB
+       MOV     DX,1            ; Do auto memory scan.
+       CALL    0,DOSSEG
+;
+; Change disk read and write vectors (INT 37 and INT 38) to go to
+; DIRECTREAD and DIRECTWRITE rather than READ and WRITE.
+;
+       SUB     BP,BP
+       MOV     W,[BP+37*4],DIRECTREAD
+       MOV     W,[BP+38*4],DIRECTWRITE
+
+       MOV     DX,100H
+       MOV     AH,26           ;Set DMA address
+       INT     33
+       MOV     CX,[6]          ;Get size of segment
+       MOV     BX,DS           ;Save segment for later
+;
+; DS must be set to CS so we can point to the FCB.
+;
+       MOV     AX,CS
+       MOV     DS,AX
+       MOV     DX,FCB          ;File Control Block for COMMAND.COM
+       MOV     AH,15
+       INT     33              ;Open COMMAND.COM
+       OR      AL,AL
+       JNZ     COMERR          ;Error if file not found
+       XOR     AX,AX
+       MOV     [FCB+33],AX     ; Set 4-byte Random Record field to
+       MOV     [FCB+35],AX     ;  beginning of file.
+       INC     AX
+       MOV     [FCB+14],AX     ;Set record length field
+       MOV     AH,39           ;Block read (CX already set)
+       INT     33
+       JCXZ    COMERR          ;Error if no records read
+       TEST    AL,1
+       JZ      COMERR          ;Error if not end-of-file
+;
+; Make all segment registers the same.
+;
+       MOV     DS,BX
+       MOV     ES,BX
+       MOV     SS,BX
+       MOV     SP,5CH          ;Set stack to standard value
+       XOR     AX,AX
+       PUSH    AX              ;Put zero on top of stack for return
+       MOV     DX,80H
+       MOV     AH,26
+       INT     33              ;Set default transfer address (DS:0080)
+       PUSH    BX              ;Put segment on stack
+       MOV     AX,100H
+       PUSH    AX              ;Put address to execute within segment on stack
+       RET     L               ;Jump to COMMAND
+
+COMERR:
+       MOV     DX,BADCOM
+       MOV     AH,9            ;Print string
+       INT     33
+       EI
+STALL: JP      STALL
+
+STCTAB:        DB      17H             ;Select master mode register
+       DW      84F3H           ;Enable time-of-day
+       DB      1               ;Counter 1 mode register
+       DW      0138H
+       DB      2
+       DW      0038H
+       DB      3
+       DW      0008H           ;Set counter 3 to count days
+
+       IF      SERIAL
+       DB      0B7H, 77H, 4EH, 37H, PRNBAUD, AUXBAUD
+       ENDIF
+
+BADCOM:        DB      13,10,"Error in loading Command Interpreter",13,10,"$"
+FCB:   DB      1,"COMMAND COM"
+       DS      25
+;
+; ************ Time and Date ************
+;
+GETTIME:
+       MOV     AL,0A7H         ;Save counters 1,2,3
+       OUT     STCCOM
+       MOV     AL,0E0H         ;Enable data pointer sequencing
+       OUT     STCCOM
+       MOV     AL,19H          ;Select hold 1 / hold cycle
+       OUT     STCCOM
+       CALL    STCTIME         ;Get seconds & 1/100's
+       XCHG    AX,DX
+       CALL    STCTIME         ;Get hours & minutes
+       XCHG    AX,CX
+       IN      STCDATA
+       MOV     AH,AL
+       IN      STCDATA
+       XCHG    AL,AH           ;Count of days
+       JP      POINTSTAT
+
+STCTIME:
+       CALL    STCBYTE
+       MOV     CL,AH
+STCBYTE:
+       IN      STCDATA
+       MOV     AH,AL
+       SHR     AH
+       SHR     AH
+       SHR     AH
+       SHR     AH
+       AND     AL,0FH          ;Unpack BCD digits
+       AAD                     ;Convert to binary
+       MOV     AH,AL
+       MOV     AL,CL
+       RET
+
+SETTIME:
+       PUSH    CX
+       PUSH    DX
+       CALL    LOAD0           ;Put 0 into load registers to condition timer
+       MOV     AL,43H          ;Load counters 1 & 2
+       OUT     STCCOM
+       POP     DX
+       POP     CX
+       CALL    LOAD
+       MOV     AL,43H
+       OUT     STCCOM          ;Load counters 1&2
+       CALL    LOAD0
+       MOV     AL,27H          ;Arm counters 1,2,3
+       OUT     STCCOM
+       JP      POINTSTAT
+
+LOAD0:
+       XOR     CX,CX
+       MOV     DX,CX
+LOAD:
+       MOV     AL,09           ;Counter 1 load register
+       CALL    OUTDX
+       MOV     AL,0AH          ;Counter 2 load register
+       MOV     DX,CX
+OUTDX:
+       OUT     STCCOM          ;Select a load register
+       MOV     AL,DL
+       CALL    OUTBCD
+       MOV     AL,DH
+OUTBCD:
+       AAM                     ;Convert binary to unpacked BCD
+       SHL     AH
+       SHL     AH
+       SHL     AH
+       SHL     AH
+       OR      AL,AH           ;Packed BCD
+       OUT     STCDATA
+       RET
+
+SETDATE:
+       XCHG    AX,DX           ;Put date in DX
+       MOV     AL,0BH          ;Select Counter 3 load register
+       OUT     STCCOM
+       XCHG    AX,DX
+       OUT     STCDATA
+       MOV     AL,AH
+       OUT     STCDATA
+       MOV     AL,44H          ;Load counter 3
+       OUT     STCCOM
+POINTSTAT:
+       PUSH    AX
+       MOV     AL,1FH          ;Point to status register
+       OUT     STCCOM          ;   so power-off glitches won't hurt
+       POP     AX
+       RET     L
+;
+; ************ CONSOLE INPUT ************
+;
+
+       IF      INTINP-1        ; Non-interrupt driven input.
+STATUS:
+       IN      STAT
+       AND     AL,DAV
+       JZ      NOTHING         ; Jump if nothing there.
+       PUSHF                   ; Save Z flag.
+       INB     DATA
+       AND     AL,7FH
+       SEG     CS
+       MOV     [QUEUE],AL      ; Put new character in buffer.
+       POPF                    ; Return with Z flag clear.
+       RET     L
+NOTHING:
+       SEG     CS
+       MOV     AL,[QUEUE]      ; See if there's anything in the buffer.
+       NOT     AL              ; Set up the Z flag.
+       TEST    AL,80H
+       PUSHF
+       NOT     AL
+       POPF
+       RET     L
+
+INP:
+       MOV     AL,-1
+       SEG     CS
+       XCHG    AL,[QUEUE]      ; Remove the character from the buffer.
+       AND     AL,AL
+       JNS     INRET           ; Return if we have a character.
+INLOOP:
+       IN      STAT            ; Wait till a character is available.
+       AND     AL,DAV
+       JZ      INLOOP
+       IN      DATA
+       AND     AL,7FH
+INRET:
+FLUSH:
+       RET     L
+
+QUEUE: DB      -1              ; For storing characters from STATUS to INP.
+       ENDIF
+
+       IF      INTINP          ; Interrupt-driven input.
+;
+; Console keyboard interrupt handler.
+;
+KBINT:
+       PUSH    AX
+       PUSH    SI
+       MOV     AL,20H          ;End of Interrupt command
+       OUT     BASE+2          ;Send to slave
+       IN      DATA            ;Get the character
+       AND     AL,7FH
+       CMP     AL,"C"-"@"
+       JZ      FLSH
+       CMP     AL,"S"-"@"
+       JZ      FLSH
+       CMP     AL,"F"-"@"
+       JNZ     SAVKY
+FLSH:
+       CALL    13*3,BIOSSEG    ; Call I/O system keyboard buffer flush.
+SAVKY:
+       SEG     CS
+       MOV     SI,[REAR]       ;Pointer to rear of queue
+       CALL    INCQ
+       SEG     CS
+       CMP     SI,[FRONT]      ;Any room in queue?
+       JZ      QFULL
+       SEG     CS
+       MOV     [SI],AL         ;Put character in queue
+       SEG     CS
+       MOV     [REAR],SI       ;Save pointer
+LEAVINT:
+       POP     SI
+       POP     AX
+       IRET
+QFULL:
+       MOV     AL,7            ; BELL character.
+       CALL    3*3,BIOSSEG     ; Call I/O system console output function.
+       JMPS    LEAVINT
+
+STATUS:
+       PUSH    SI
+;See if printer ready
+       IN      PRNSTAT
+       AND     AL,TBMT
+       JZ      NOPRN
+       SEG     CS
+       MOV     SI,[PFRONT]
+       SEG     CS
+       CMP     SI,[PREAR]      ;Anything in print queue?
+       JNZ     SENDPRN
+       SEG     CS
+       CMP     B,[PRNFCB],-1   ;Print spooling in progress?
+       JZ      NOPRN           ;If not, nothing to print
+;Print spooling in progress. Get next buffer
+       PUSH    DS
+       PUSH    CS
+       POP     DS
+       PUSH    AX
+       PUSH    CX
+       PUSH    DX
+       PUSH    [STKSAV]
+       PUSH    [STKSAV+2]
+       PUSH    [DMAADD]
+       PUSH    [DMAADD+2]
+       MOV     DX,PQUEUE
+       MOV     AH,26           ;Set DMA address
+       INT     33
+       MOV     DX,PRNFCB
+       MOV     CX,PBUFSIZ
+       MOV     AH,39           ;Read buffer
+       INT     33
+       OR      AL,AL
+       JZ      NOTEOF
+       MOV     B,[PRNFCB],-1   ;Turn off print spooling at EOF
+NOTEOF:
+       POP     [DMAADD+2]
+       POP     [DMAADD]
+       POP     [STKSAV+2]
+       POP     [STKSAV]
+       MOV     SI,CX
+       POP     DX
+       POP     CX
+       POP     AX
+       POP     DS
+       OR      SI,SI
+       JZ      NOPRN
+       ADD     SI,PQUEUE-1
+       SEG     CS
+       MOV     [PREAR],SI
+       MOV     SI,ENDPQ-1
+SENDPRN:
+       CALL    INCPQ
+       SEG     CS
+       MOV     [PFRONT],SI
+       SEG     CS
+       LODSB                   ;Get character to print
+       OUT     PRNDATA
+NOPRN:
+       DI                      ; Disable interrupts while checking queue.
+       SEG     CS
+       MOV     SI,[FRONT]
+       SEG     CS
+       CMP     SI,[REAR]       ; Anything in queue?
+       JZ      NOCHR           ; Jump if nothing in queue.
+       CALL    INCQ
+       SEG     CS
+       LODSB                   ;Get character (if there is one)
+       OR      SI,SI           ;Reset zero flag
+NOCHR:
+       EI
+       POP     SI
+       RET     L               ;Zero clear if we have a character
+
+INP:
+       CALL    STATUS,BIOSSEG  ; Get I/O system console input status.
+       JZ      INP
+       PUSH    SI
+       DI                      ; Disable interrupts while changing queue pointers.
+       SEG     CS
+       MOV     SI,[FRONT]
+       CALL    INCQ            ; Permanently remove char from queue
+       SEG     CS
+       MOV     [FRONT],SI
+       EI
+       POP     SI
+       RET     L
+
+FLUSH:
+       DI
+       SEG     CS
+       MOV     [REAR],QUEUE
+       SEG     CS
+       MOV     [FRONT],QUEUE
+       EI
+       RET     L
+
+INCQ:
+       INC     SI
+       CMP     SI,ENDQ         ;Exceeded length of queue?
+       JB      RET
+       MOV     SI,QUEUE
+       RET
+
+INCPQ:
+       INC     SI
+       CMP     SI,ENDPQ        ;Exceeded length of queue?
+       JB      RET
+       MOV     SI,PQUEUE
+       RET
+
+FRONT: DW      QUEUE
+REAR:  DW      QUEUE
+QUEUE: DS      QSIZE
+ENDQ:  EQU     $
+PFRONT:        DW      PQUEUE
+PREAR: DW      PQUEUE
+PQUEUE:        DS      PBUFSIZ
+ENDPQ: EQU     $
+PRNFCB:        DB      -1
+       DS      36
+       ENDIF
+
+;
+; ************ Console and Printer Output ************
+;
+OUTP:
+       PUSH    AX
+OUTLP:
+       IN      STAT
+       AND     AL,TBMT
+       JZ      OUTLP
+       POP     AX
+       OUT     DATA
+       RET     L
+
+PRINT:
+       PUSH    SI
+       SEG     CS
+       MOV     SI,[PREAR]
+       CALL    INCPQ
+PRINLP:
+       SEG     CS
+       CMP     SI,[PFRONT]
+       JNZ     PRNCHR
+;Print queue is full
+       PUSH    AX
+       CALL    STATUS,BIOSSEG  ;Poll and maybe print something
+       POP     AX
+       JMPS    PRINLP
+PRNCHR:
+       SEG     CS
+       MOV     [PREAR],SI
+       SEG     CS
+       MOV     [SI],AL
+       POP     SI
+       RET     L
+;
+; ************ Auxiliary I/O ************
+;
+AUXIN:
+       IN      AUXSTAT
+       AND     AL,DAV
+       JZ      AUXIN
+       IN      AUXDATA
+       RET     L
+
+AUXOUT:
+       PUSH    AX
+AUXLP:
+       IN      AUXSTAT
+       AND     AL,TBMT
+       JZ      AUXLP
+       POP     AX
+       OUT     AUXDATA
+       RET     L
+;
+; ************ 1771/1793-type controller disk I/O ************
+;
+TARBELL:EQU    TARBELLSD+TARBELLDD
+CROMEMCO:EQU   CROMEMCO4FDC+CROMEMCO16FDC
+
+WD1791:        EQU     SCP+TARBELLDD+CROMEMCO16FDC
+WD1771:        EQU     TARBELLSD+CROMEMCO4FDC
+
+       IF      WD1791
+READCOM:EQU    80H
+WRITECOM:EQU   0A0H
+       ENDIF
+
+       IF      WD1771
+READCOM:EQU    88H
+WRITECOM:EQU   0A8H
+       ENDIF
+
+       IF      SCP
+SMALLBIT:EQU   10H
+BACKBIT:EQU    04H
+DDENBIT:EQU    08H
+DONEBIT:EQU    01H
+DISK:  EQU     0E0H
+       ENDIF
+
+       IF      TARBELL
+BACKBIT:EQU    40H
+DDENBIT:EQU    08H
+DONEBIT:EQU    80H
+DISK:  EQU     78H
+       ENDIF
+
+       IF      CROMEMCO
+SMALLBIT:EQU   10H
+BACKBIT:EQU    0FDH            ; Send this to port 4 to select back.
+DDENBIT:EQU    40H
+DONEBIT:EQU    01H
+DISK:  EQU     30H
+       ENDIF
+
+       IF      SMALLDS-1
+SMALLDDSECT:   EQU     8
+       ENDIF
+
+       IF      SMALLDS
+SMALLDDSECT:   EQU     16
+       ENDIF
+
+       IF      LARGEDS-1
+LARGEDDSECT:   EQU     8
+       ENDIF
+
+       IF      LARGEDS
+LARGEDDSECT:   EQU     16
+       ENDIF
+;
+; Disk change function.
+; On entry:
+;      AL = disk drive number.
+; On exit:
+;      AH = -1 (FF hex) if disk is changed.
+;      AH = 0 if don't know.
+;      AH = 1 if not changed.
+;
+;      CF clear if no disk error.
+;      AL = disk I/O driver number.
+;
+;      CF set if disk error.
+;      AL = disk error code (see disk read below).
+;
+       IF      WD1771
+DSKCHG:
+       MOV     AH,0            ; AH = 0 in case we don't know.
+       SEG     CS
+       CMP     AL,[CURDRV]
+       JNZ     RETL
+       PUSH    AX              ; Save drive number.
+
+       IF      CROMEMCO
+       INB     DISK+4
+       ENDIF
+
+       IF      TARBELL
+       INB     DISK
+       ENDIF
+
+       AND     AL,20H          ; Look at head load bit
+       POP     AX
+       JZ      RETL
+       MOV     AH,1            ; AH = 1, disk not changed.
+RETL:
+       CLC                     ; No disk error.
+       RET     L
+       ENDIF                   ; End of 1771 DSKCHG.
+
+       IF      WD1791
+DSKCHG:
+       MOV     AH,0            ; AH = 0 in case we don't know.
+       SEG     CS
+       CMP     AL,[CURDRV]
+       JNZ     DENSCHK         ; Check density if not same drive.
+       PUSH    AX
+
+       IF      SCP+CROMEMCO
+       INB     DISK+4
+       ENDIF
+
+       IF      TARBELL
+       INB     DISK
+       ENDIF
+
+       AND     AL,20H          ; Look at head load bit
+       POP     AX
+       JZ      DENSCHK         ; Check density if head not loaded.
+       MOV     AH,1            ; AH = 1, disk not changed.
+       MOV     BX,PREVDENS
+       SEG     CS
+       XLAT                    ; Get previous density
+       CLC                     ; No disk error.
+       RET     L
+DENSCHK:
+       CALL    CHKNEW          ; Unload head if selecting new drive.
+       CBW
+       XCHG    AX,SI
+       ADD     SI,PREVDENS
+       MOV     CX,4            ; Try each density twice
+       MOV     AH,0            ; Disk may not have been changed.
+CHKDENS:
+       SEG     CS
+       MOV     AL,[SI]         ; Get previous disk I/O driver number.
+       MOV     BX,DRVTAB
+       SEG     CS
+       XLAT                    ; Get drive select byte for previous density
+
+       IF      CROMEMCO16FDC
+       CALL    MOTOR           ; Wait for motor to come up to speed.
+       ENDIF
+
+       OUT     DISK+4          ; Select disk
+       MOV     AL,0C4H         ; READ ADDRESS command
+       CALL    DCOM
+       AND     AL,98H
+       IN      DISK+3          ; Eat last byte to reset DRQ
+       JZ      HAVDENS         ; Jump if no error in reading address.
+       NOT     AH              ; AH = -1 (disk changed) if new density works.
+       SEG     CS
+       XOR     B,[SI],1        ; Try other density
+       LOOP    CHKDENS
+       MOV     AX,2            ; Couldn't read disk at all, AH = 0 for don't 
+       STC                     ;  know if disk changed, AL = error code 2 -
+       RET     L               ;  disk not ready, carry set to indicate error.
+
+HAVDENS:
+       SEG     CS
+       LODSB                   ; AL = disk I/O driver number.
+       CLC                     ; No disk error.
+       RET     L
+
+PREVDENS:DB    1,3,5,7,9,11,13 ; Table of previous disk I/O driver numbers.
+       ENDIF                   ; End of 1793 DSKCHG function.
+
+CHKNEW:
+       MOV     AH,AL           ; Save disk drive number in AH.
+       SEG     CS              ; AL = previous disk drive number,
+       XCHG    AL,[CURDRV]     ;  make new drive current.
+       CMP     AL,AH           ; Changing drives?
+       JZ      RET
+;
+; If changing drives, unload head so the head load delay one-shot will
+; fire again. Do it by seeking to the same track with the H bit reset.
+;
+       IN      DISK+1          ; Get current track number
+       OUT     DISK+3          ; Make it the track to seek to
+       MOV     AL,10H          ; Seek and unload head
+       CALL    DCOM
+       MOV     AL,AH           ; Restore current drive number
+       RET
+
+       IF      CROMEMCO16FDC
+MOTOR:
+       PUSH    AX
+       MOV     AH,AL
+       IN      DISK+4          ; See if the motor is on.
+       TEST    AL,08H
+       MOV     AL,AH
+       OUTB    DISK+4          ; Select drive & start motor.
+       JNZ     MOTORSON        ; No delay if motors already on.
+       PUSH    CX
+       MOV     CX,43716        ; Loop count for 1 second.
+MOTORDELAY:                    ;  (8 MHz, 16-bit memory).
+       AAM                     ; 83 clocks.
+       AAM                     ; 83 clocks.
+       LOOP    MOTORDELAY      ; 17 clocks.
+       POP     CX
+MOTORSON:
+       POP     AX
+       RET
+       ENDIF
+;
+; Disk read function.
+;
+; On entry:
+;      AL = Disk I/O driver number
+;      BX = Disk transfer address in DS
+;      CX = Number of sectors to transfer
+;      DX = Logical record number of transfer
+; On exit:
+;      CF clear if transfer complete
+;
+;      CF set if hard disk error.
+;      CX = number of sectors left to transfer.
+;      AL = disk error code
+;              0 = write protect error
+;              2 = not ready error
+;              4 = "data" (CRC) error
+;              6 = seek error
+;              8 = sector not found
+;             10 = write fault
+;             12 = "disk" (none of the above) error
+;
+READ:
+       CALL    SEEK            ;Position head
+       JC      ERROR
+       PUSH    ES              ; Make ES same as DS.
+       MOV     BX,DS
+       MOV     ES,BX
+RDLP:
+       CALL    READSECT        ;Perform sector read
+       JC      POPESERROR
+       INC     DH              ;Next sector number
+       LOOP    RDLP            ;Read each sector requested
+       CLC                     ; No errors.
+       POP     ES              ; Restore ES register.
+       RET     L
+;
+; Disk write function.
+; Registers same on entry and exit as read above.
+;
+WRITE:
+       CALL    SEEK            ;Position head
+       JC      ERROR
+WRTLP:
+       CALL    WRITESECT       ;Perform sector write
+       JC      ERROR
+       INC     DH              ;Bump sector counter
+       LOOP    WRTLP           ;Write CX sectors
+       CLC                     ; No errors.
+WRITERET:
+       RET     L
+
+POPESERROR:
+       POP     ES              ; Restore ES register.
+ERROR:
+       MOV     BL,-1
+       SEG     CS
+       MOV     [DI],BL         ; Indicate we don't know where head is.
+       MOV     SI,ERRTAB
+GETCOD:
+       INC     BL              ; Increment to next error code.
+       SEG     CS
+       LODB
+       TEST    AH,AL           ; See if error code matches disk status.
+       JZ      GETCOD          ; Try another if not.
+       MOV     AL,BL           ; Now we've got the code.
+       SHL     AL              ; Multiply by two.
+       STC
+       RET     L
+
+ERRTAB:
+       DB      40H             ;Write protect error
+       DB      80H             ;Not ready error
+       DB      8               ;CRC error
+       DB      2               ;Seek error
+       DB      10H             ;Sector not found
+       DB      20H             ;Write fault
+       DB      7               ;"Disk" error
+;
+; Direct disk read and write from INT 37 and INT 38.  Subroutine GETIODRIVER
+; calls DSKCHG to convert disk drive number to I/O driver number.
+;
+; Setting CURDRV to -1 before calling DSKCHG forces DSKCHG to check the disk's
+; density before returning the I/O driver number.  This is necessary because
+; programs such as FORMAT could change the density of a disk and leave the
+; head loaded.  If the head is loaded DSKCHG assumes the disk hasn't been
+; changed and returns the old I/O driver number which could be wrong.
+;
+; CURDRV is set to -1 before returning so when DSKCHG is called by the
+; operating system, it will tell the operating system the disk may have
+; been changed (because it may have been).
+;
+DIRECTREAD:
+
+       IF      WD1791
+       CALL    GETIODRIVER     ; Convert drive number to I/O driver number.
+       JC      DIRECTRET       ; Return if DSKCHG returned error.
+       ENDIF
+
+       CALL    7*3,BIOSSEG     ; Call READ.
+       JMPS    DIRECTRET
+
+DIRECTWRITE:
+
+       IF      WD1791
+       CALL    GETIODRIVER     ; Convert drive number to I/O driver number.
+       JC      DIRECTRET       ; Return if DSKCHG returned error.
+       ENDIF
+
+       CALL    8*3,BIOSSEG     ; Call WRITE.
+DIRECTRET:
+       SEG     CS
+       MOV     B,[CURDRV],-1   ; Force DSKCHG to do density check.
+       RET     L
+
+       IF      WD1791
+GETIODRIVER:
+       SEG     CS
+       MOV     B,[CURDRV],-1   ; Force DSKCHG to do density check.
+       PUSH    BX
+       PUSH    CX
+       CALL    9*3,BIOSSEG     ; Call DSKCHG.
+       POP     CX
+       POP     BX
+       RET
+       ENDIF
+;
+; Function:
+;      Seeks to proper track.
+; On entry:
+;      Same as for disk read or write above.
+; On exit:
+;      AH = Drive select byte
+;      DL = Track number
+;      DH = Sector number
+;      SI = Disk transfer address in DS
+;      DI = pointer to drive's track counter in CS
+;      CX unchanged (number of sectors)
+;
+SEEK:
+       MOV     SI,BX           ; Save transfer address
+       CBW
+       MOV     BX,AX           ; Prepare to index on drive number
+
+       IF      WD1791          ; If two disk formats per drive.
+       SHR     AL              ; Convert to physical disk drive number.
+       ENDIF
+
+       CALL    CHKNEW          ; Unload head if changing drives.
+       SEG     CS
+       MOV     AL,[BX+DRVTAB]  ; Get drive-select byte.
+
+       IF      CROMEMCO16FDC
+       CALL    MOTOR           ; Wait for the motors to come up to speed.
+       ENDIF
+
+       OUTB    DISK+4          ; Select drive.
+
+       IF      CROMEMCO
+       OR      AL,80H          ; Set auto-wait bit.
+       ENDIF
+
+       MOV     AH,AL           ; Save drive-select byte in AH.
+       XCHG    AX,DX           ; AX = logical sector number.
+       MOV     DL,26           ; 26 sectors/track unless changed below
+
+       IF      SCP
+       TEST    DH,SMALLBIT     ; Check if small disk.
+       JZ      BIGONE          ; Jump if big disk.
+       MOV     DL,18           ; Assume 18 sectors on small track.
+       TEST    DH,DDENBIT      ; Check if double-density.
+       JZ      HAVSECT         ; Jump if not.
+       MOV     DL,SMALLDDSECT  ; Number of sectors on small DD track.
+       JP      HAVSECT
+BIGONE:
+       TEST    DH,DDENBIT      ; Check if double-density.
+       JZ      HAVSECT         ; Jump if not.
+       MOV     DL,LARGEDDSECT  ; Number of sectors on big DD track.
+       ENDIF
+
+       IF      TARBELLDD       ; Tarbell DD controller.
+       TEST    DH,DDENBIT      ; Check for double-density.
+       JZ      HAVSECT
+       MOV     DL,LARGEDDSECT  ; Number of sectors on DD track.
+       ENDIF
+
+       IF      CROMEMCO4FDC
+       TEST    DH,SMALLBIT     ; Check if small disk.
+       JNZ     HAVSECT         ; Jump if not.
+       MOV     DL,18           ; 18 sectors on small disk track.
+       ENDIF
+
+       IF      CROMEMCO16FDC
+       TEST    DH,SMALLBIT     ; Check if small disk.
+       JNZ     BIGONE          ; Jump if big disk.
+       MOV     DL,18           ; Assume 18 sectors on small track.
+       TEST    DH,DDENBIT      ; Check if double-density.
+       JZ      HAVSECT         ; Jump if not.
+       MOV     DL,SMALLDDSECT  ; Number of sectors on small DD track.
+       JP      HAVSECT
+BIGONE:
+       TEST    DH,DDENBIT      ; Check if double-density.
+       JZ      HAVSECT         ; Jump if not.
+       MOV     DL,LARGEDDSECT  ; Number of sectors on big DD track.
+       ENDIF
+
+HAVSECT:
+       DIV     AL,DL           ; AL = track, AH = sector.
+       XCHG    AX,DX           ; AH has drive-select byte, DX = track & sector.
+       INC     DH              ; Sectors start at one, not zero.
+       SEG     CS
+       MOV     BL,[BX+TRKPT]   ; Get this drive's displacement into track table.
+       ADD     BX,TRKTAB       ; BX now points to track counter for this drive.
+       MOV     DI,BX
+       MOV     AL,DL           ; Move new track number into AL.
+       SEG     CS
+       XCHG    AL,[DI]         ; Xchange current track with desired track
+       OUT     DISK+1          ; Inform controller chip of current track
+       CMP     AL,DL           ; See if we're at the right track.
+       JZ      RET
+       MOV     BH,2            ; Seek retry count
+       CMP     AL,-1           ; Head position known?
+       JNZ     NOHOME          ; If not, home head
+TRYSK:
+       CALL    HOME
+       JC      SEEKERR
+NOHOME:
+       MOV     AL,DL           ; AL = new track number.
+       OUT     DISK+3
+       MOV     AL,1CH+STPSPD   ; Seek command.
+       CALL    MOVHEAD
+       AND     AL,98H          ; Accept not ready, seek, & CRC error bits.
+       JZ      RET
+       JS      SEEKERR         ; No retries if not ready
+       DEC     BH
+       JNZ     TRYSK
+SEEKERR:
+       MOV     AH,AL           ; Put status in AH.
+       TEST    AL,80H          ; See if it was a Not Ready error.
+       STC
+       JNZ     RET             ; Status is OK for Not Ready error.
+       MOV     AH,2            ; Everything else is seek error.
+       RET
+
+SETUP:
+       MOV     BL,DH           ; Move sector number to BL to play with
+
+       IF      SCP+CROMEMCO16FDC
+       TEST    AH,DDENBIT      ; Check for double density.
+       JZ      CHECKSMALL      ; Not DD, check size for SD.
+       ENDIF
+
+       IF      TARBELLDD
+       TEST    AH,DDENBIT      ; Check for double density.
+       JZ      CHECK26         ; Not DD.
+       ENDIF
+
+       IF      WD1791
+
+       IF      (SCP+TARBELL)*LARGEDS+SCP*SMALLDS
+       MOV     AL,AH           ; Select front side of disk.
+       OUT     DISK+4
+       ENDIF
+
+       IF      CROMEMCO*(LARGEDS+SMALLDS)
+       MOV     AL,0FFH         ; Select front side of disk.
+       OUT     04H
+       ENDIF
+
+       CMP     BL,8            ; See if legal DD sector number.
+       JBE     PUTSEC          ; Jump if ok.
+
+       IF      (LARGEDS-1)*((SMALLDS*(SCP+CROMEMCO))-1)
+       JP      STEP            ; If only SS drives, we gotta step.
+       ENDIF
+
+       IF      SCP*LARGEDS*(SMALLDS-1)
+       TEST    AH,SMALLBIT     ; Check for 5.25 inch disk.
+       JNZ     STEP            ; Jump if small because SMALLDS is off.
+       ENDIF
+
+       IF      SCP*SMALLDS*(LARGEDS-1)
+       TEST    AH,SMALLBIT     ; Check for 8 inch disk.
+       JZ      STEP            ; Jump if large because LARGEDS is off.
+       ENDIF
+
+       IF      CROMEMCO16FDC*LARGEDS*(SMALLDS-1)
+       TEST    AH,SMALLBIT     ; Check for 5.25 inch disk.
+       JZ      STEP            ; Jump if small because SMALLDS is off.
+       ENDIF
+
+       IF      CROMEMCO16FDC*SMALLDS*(LARGEDS-1)
+       TEST    AH,SMALLBIT     ; Check for 8 inch disk.
+       JNZ     STEP            ; Jump if large because LARGEDS is off.
+       ENDIF
+
+       IF      LARGEDS+SMALLDS*(SCP+CROMEMCO)
+       SUB     BL,8            ; Find true sector for back side.
+       CMP     BL,8            ; See if ok now.
+       JA      STEP            ; Have to step if still too big.
+
+       IF      SCP+TARBELLDD
+       MOV     AL,AH           ; Move drive select byte into AL.
+       OR      AL,BACKBIT      ; Select back side.
+       OUT     DISK+4
+       ENDIF
+
+       IF      CROMEMCO16FDC
+       MOV     AL,BACKBIT      ; Select back side.
+       OUT     04H
+       ENDIF
+
+       JP      PUTSEC
+       ENDIF
+
+       ENDIF
+
+       IF      SCP
+CHECKSMALL:
+       TEST    AH,SMALLBIT     ; See if big disk.
+       JZ      CHECK26         ; Jump if big.
+       ENDIF
+
+       IF      CROMEMCO
+CHECKSMALL:
+       TEST    AH,SMALLBIT     ; See if big disk.
+       JNZ     CHECK26         ; Jump if big.
+       ENDIF
+
+       IF      SCP+CROMEMCO
+       CMP     BL,18           ; See if legal small SD/SS sector.
+       JA      STEP            ; Jump if not.
+       ENDIF
+
+CHECK26:
+       CMP     BL,26           ; See if legal large SD/SS sector.
+       JBE     PUTSEC          ; Jump if ok.
+STEP:
+       INC     DL              ; Increment track number.
+       MOV     AL,58H          ; Step in with update.
+       CALL    DCOM
+       SEG     CS
+       INC     B,[DI]          ; Increment the track pointer.
+       MOV     DH,1            ; After step, do first sector.
+       MOV     BL,DH           ; Fix temporary sector number also.
+PUTSEC:
+       MOV     AL,BL           ; Output sector number to controller.
+       OUT     DISK+2
+       DI                      ; Interrupts not allowed until I/O done
+
+       IF      SCP+CROMEMCO
+       INB     DISK+4          ; Get head-load bit.
+       ENDIF
+
+       IF      TARBELL
+       INB     DISK
+       ENDIF
+
+       NOT     AL
+       AND     AL,20H          ; Check head load status
+       JZ      RET
+       MOV     AL,4
+       RET
+
+READSECT:
+       CALL    SETUP
+       MOV     BL,10           ; Retry count for hard error.
+       XCHG    DI,SI           ; Transfer address to DI.
+       PUSH    DX              ; Save track & sector number.
+       MOV     DL,DISK+3       ; Disk controller data port.
+RDAGN:
+       OR      AL,READCOM
+       OUT     DISK
+
+       IF      CROMEMCO
+       MOV     AL,AH           ; Turn on auto-wait.
+       OUT     DISK+4
+       ENDIF
+
+       MOV     BP,DI           ; Save address for retry.
+       JMPS    RLOOPENTRY
+RLOOP:
+       STOB                    ; Write into memory.
+RLOOPENTRY:
+
+       IF      SCP
+       IN      DISK+5          ; Wait for DRQ or INTRQ.
+       ENDIF
+
+       IF      TARBELL+CROMEMCO
+       IN      DISK+4
+       ENDIF
+
+       IF      TARBELL
+       SHL     AL
+       INB     DX              ; Read data from disk controller chip.
+       JC      RLOOP
+       ENDIF
+
+       IF      SCP+CROMEMCO
+       SHR     AL
+       INB     DX              ; Read data from disk controller chip.
+       JNC     RLOOP
+       ENDIF
+
+       EI                      ; Interrupts OK now
+       CALL    GETSTAT
+       AND     AL,9CH
+       JZ      RDPOP
+       MOV     DI,BP           ; Get origainal address back for retry.
+       MOV     BH,AL           ; Save error status for report
+       MOV     AL,0
+       DEC     BL
+       JNZ     RDAGN
+       MOV     AH,BH           ; Put error status in AH.
+       STC
+RDPOP:
+       POP     DX              ; Get back track & sector number.
+       XCHG    SI,DI           ; Address back to SI.
+
+       IF      TARBELL
+FORCINT:
+       MOV     AL,0D0H         ; Tarbell controllers need this Force Interrupt
+       OUT     DISK            ;  so that Type I status is always available
+       MOV     AL,10           ;  at the 1771/1793 status port so we can find
+INTDLY:                                ;  out if the head is loaded.  SCP and Cromemco
+       DEC     AL              ;  controllers have head-load status available
+       JNZ     INTDLY          ;  at the DISK+4 status port.
+       ENDIF
+
+       RET
+
+WRITESECT:
+       CALL    SETUP
+       MOV     BL,10
+       PUSH    DX              ; Save track & sector number.
+       MOV     DL,DISK+3       ; Disk controller data port.
+WRTAGN:
+       OR      AL,WRITECOM
+       OUT     DISK
+
+       IF      CROMEMCO
+       MOV     AL,AH           ; Turn on auto-wait.
+       OUT     DISK+4
+       ENDIF
+
+       MOV     BP,SI
+WRLOOP:
+
+       IF      SCP
+       INB     DISK+5
+       ENDIF
+
+       IF      TARBELL+CROMEMCO
+       INB     DISK+4
+       ENDIF
+
+       IF      SCP+CROMEMCO
+       SHR     AL
+       LODB                    ; Get data from memory.
+       OUTB    DX              ; Write to disk.
+       JNC     WRLOOP
+       ENDIF
+
+       IF      TARBELL
+       SHL     AL
+       LODB                    ; Get data from memory.
+       OUTB    DX              ; Write to disk.
+       JC      WRLOOP
+       ENDIF
+
+       EI                      ; Interrupts OK now.
+       DEC     SI
+       CALL    GETSTAT
+       AND     AL,0FCH
+       JZ      WRPOP
+       MOV     SI,BP
+       MOV     BH,AL
+       MOV     AL,0
+       DEC     BL
+       JNZ     WRTAGN
+       MOV     AH,BH           ; Error status to AH.
+       STC
+WRPOP:
+       POP     DX              ; Get back track & sector number.
+
+       IF      TARBELL
+       JMPS    FORCINT
+       ENDIF
+
+       IF      SCP+CROMEMCO
+       RET
+       ENDIF
+;
+; Subroutine to restore the read/write head to track 0.
+;
+       IF      SCP+CROMEMCO+TARBELL*(FASTSEEK-1)
+HOME:
+       ENDIF
+
+       IF      FASTSEEK*CROMEMCO
+       TEST    AH,SMALLBIT     ; Check for large disk.
+       JNZ     RESTORE         ; Big disks are fast seek PerSci.
+       ENDIF
+
+       MOV     BL,3
+TRYHOM:
+
+       IF      SCP*FASTSEEK
+       MOV     AL,AH           ; Turn on Restore to PerSci.
+       OR      AL,80H
+       OUTB    DISK+4
+       ENDIF
+
+       MOV     AL,0CH+STPSPD   ; Restore with verify command.
+       CALL    DCOM
+       AND     AL,98H
+
+       IF      SCP*FASTSEEK
+       MOV     AL,AH           ; Restore off.
+       OUTB    DISK+4
+       ENDIF
+
+       JZ      RET
+       JS      HOMERR          ; No retries if not ready
+       MOV     AL,58H+STPSPD   ; Step in with update
+       CALL    DCOM
+       DEC     BL
+       JNZ     TRYHOM
+HOMERR:
+       STC
+       RET
+;
+; RESTORE for PerSci drives.
+; Doesn't exist yet for Tarbell controllers.
+;
+       IF      FASTSEEK*TARBELL
+HOME:
+RESTORE:
+       RET
+       ENDIF
+
+       IF      FASTSEEK*CROMEMCO4FDC
+RESTORE:
+       MOV     AL,0C4H         ;READ ADDRESS command to keep head loaded
+       OUT     DISK
+       MOV     AL,77H
+       OUT     4
+CHKRES:
+       IN      4
+       AND     AL,40H
+       JZ      RESDONE
+       IN      DISK+4
+       TEST    AL,DONEBIT
+       JZ      CHKRES
+       IN      DISK
+       JP      RESTORE         ;Reload head
+RESDONE:
+       MOV     AL,7FH
+       OUT     4
+       CALL    GETSTAT
+       MOV     AL,0
+       OUT     DISK+1          ;Tell 1771 we're now on track 0
+       RET
+       ENDIF
+
+       IF      FASTSEEK*CROMEMCO16FDC
+RESTORE:
+       MOV     AL,0D7H         ; Turn on Drive-Select and Restore.
+       OUTB    4
+       PUSH    AX
+       AAM                     ; 10 uS delay.
+       POP     AX
+RESWAIT:
+       INB     4               ; Wait till Seek Complete is active.
+       TEST    AL,40H
+       JNZ     RESWAIT
+       MOV     AL,0FFH         ; Turn off Drive-Select and Restore.
+       OUTB    4
+       SUB     AL,AL           ; Tell 1793 we're on track 0.
+       OUTB    DISK+1
+       RET
+       ENDIF
+;
+; Subroutine to move the read/write head to the desired track.
+; Usually falls through to DCOM unless special handling for
+; PerSci drives is required in which case go to FASTSK.
+;
+       IF      SCP+CROMEMCO+TARBELL*(FASTSEEK-1)
+MOVHEAD:
+       ENDIF
+
+       IF      CROMEMCO*FASTSEEK
+       TEST    AH,SMALLBIT     ; Check for PerSci.
+       JNZ     FASTSK
+       ENDIF
+
+DCOM:
+       OUT     DISK
+       PUSH    AX
+       AAM                     ;Delay 10 microseconds
+       POP     AX
+GETSTAT:
+       IN      DISK+4
+       TEST    AL,DONEBIT
+
+       IF      TARBELL
+       JNZ     GETSTAT
+       ENDIF
+
+       IF      SCP+CROMEMCO
+       JZ      GETSTAT
+       ENDIF
+
+       IN      DISK
+       RET
+;
+; Fast seek code for PerSci drives.
+; Tarbell not installed yet.
+;
+       IF      FASTSEEK*TARBELL
+MOVHEAD:
+FASTSK:
+       RET
+       ENDIF
+
+       IF      FASTSEEK*CROMEMCO
+FASTSK:
+       MOV     AL,6FH
+       OUT     4
+       MOV     AL,18H
+       CALL    DCOM
+SKWAIT:
+       IN      4
+       TEST    AL,40H
+       JNZ     SKWAIT
+       MOV     AL,7FH
+       OUT     4
+       MOV     AL,0
+       RET
+       ENDIF
+
+CURDRV:        DB      -1
+;
+; Explanation of tables below.
+;
+; DRVTAB is a table of bytes which are sent to the disk controller as drive-
+; select bytes to choose which physical drive is selected for each disk I/O
+; driver.  It also selects whether the disk is 5.25-inch or 8-inch, single-
+; density or double-density.  Always select side 0 in the drive-select byte if
+; a side-select bit is available.  There should be one entry in the DRVTAB
+; table for each disk I/O driver.  Exactly which bits in the drive-select byte
+; do what depends on which disk controller is used.
+;
+; TRKTAB is a table of bytes used to store which track the read/write
+; head of each drive is on.  Each physical drive should have its own
+; entry in TRKTAB.
+;
+; TRKPT is a table of bytes which indicates which TRKTAB entry each
+; disk I/O driver should use.  Since each physical drive may be used for
+; more than one disk I/O driver, more than one entry in TRKPT may point
+; to the same entry in TRKTAB.  Drives such as PerSci 277s which use
+; the same head positioner for more than one drive should share entrys
+; in TRKTAB.
+;
+; INITTAB is the initialization table for 86-DOS as described in the
+; 86-DOS Programer's Manual under "Customizing the I/O System."
+;
+       IF      SCP*COMBIN*FASTSEEK
+;
+; A PerSci 277 or 299 and one 5.25-inch drive.
+;
+DRVTAB:        DB      00H,08H,01H,09H,10H,18H,00H,08H,01H,09H
+TRKPT: DB      0,0,0,0,1,1,0,0,0,0
+TRKTAB:        DB      -1,-1
+INITTAB:
+       IF      CONVERT-1
+       DB      6               ; Number of disk I/O drivers.
+       ENDIF
+
+       IF      CONVERT
+       DB      10
+       ENDIF
+
+       DB      0               ; Disk I/O driver 0 uses disk drive 0.
+       DW      LSDRIVE         ; Disk I/O driver 0 is 8-inch single-density.
+       DB      0               ; Disk I/O driver 1 uses disk drive 0.
+       DW      LDDRIVE         ; Disk I/O driver 1 is 8-inch double-density.
+       DB      1               ; Etc.
+       DW      LSDRIVE
+       DB      1
+       DW      LDDRIVE
+       DB      2
+       DW      SSDRIVE
+       DB      2
+       DW      SDDRIVE
+
+       IF      CONVERT
+       DB      3
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLDDRIVE
+       DB      4
+       DW      OLDLSDRIVE
+       DB      4
+       DW      OLDLDDRIVE
+       ENDIF
+       ENDIF
+
+       IF      SCP*LARGE*FASTSEEK
+;
+; PerSci 277 or 299.
+;
+DRVTAB:        DB      00H,08H,01H,09H,00H,08H,01H,09H
+TRKPT: DB      0,0,0,0,0,0,0,0
+TRKTAB:        DB      -1
+INITTAB:
+       IF      CONVERT-1
+       DB      4
+       ENDIF
+
+       IF      CONVERT
+       DB      8
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      0
+       DW      LDDRIVE
+       DB      1
+       DW      LSDRIVE
+       DB      1
+       DW      LDDRIVE
+
+       IF      CONVERT
+       DB      2
+       DW      OLDLSDRIVE
+       DB      2
+       DW      OLDLDDRIVE
+       DB      3
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLDDRIVE
+       ENDIF
+       ENDIF
+
+       IF      TARBELLDD
+;
+; Two 8-inch Shugart-type drives.
+;
+DRVTAB:        DB      0,8,10H,18H,0,8,10H,18H
+TRKPT: DB      0,0,1,1,0,0,1,1
+TRKTAB:        DB      -1,-1
+INITTAB:
+
+       IF      CONVERT-1
+       DB      4
+       ENDIF
+
+       IF      CONVERT
+       DB      8
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      0
+       DW      LDDRIVE
+       DB      1
+       DW      LSDRIVE
+       DB      1
+       DW      LDDRIVE
+
+       IF      CONVERT
+       DB      2
+       DW      OLDLSDRIVE
+       DB      2
+       DW      OLDLDDRIVE
+       DB      3
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLDDRIVE
+       ENDIF
+       ENDIF
+
+       IF      TARBELLSD
+;
+; Four 8-inch Shugart-type drives.
+;
+DRVTAB:        DB      0F2H,0E2H,0F2H,0E2H
+TRKPT: DB      0,1,0,1
+TRKTAB:        DB      -1,-1
+INITTAB:
+
+       IF      CONVERT-1
+       DB      2
+       ENDIF
+
+       IF      CONVERT
+       DB      4
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      1
+       DW      LSDRIVE
+
+       IF      CONVERT
+       DB      2
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLSDRIVE
+       ENDIF
+       ENDIF
+;
+; Cromemco drive select byte is derived as follows:
+;      Bit 7 = 0
+;      Bit 6 = 1 if double density (if 16FDC)
+;      Bit 5 = 1 (motor on)
+;      Bit 4 = 0 for 5", 1 for 8" drives
+;      Bit 3 = 1 for drive 3
+;      Bit 2 = 1 for drive 2
+;      Bit 1 = 1 for drive 1
+;      Bit 0 = 1 for drive 0
+;
+       IF      CROMEMCO4FDC*LARGE
+;
+; PerSci 277 drive.
+;
+DRVTAB:        DB      31H,32H,31H,32H
+TRKPT: DB      0,0,0,0
+TRKTAB:        DB      -1
+INITTAB:
+
+       IF      CONVERT-1
+       DB      2
+       ENDIF
+
+       IF      CONVERT
+       DB      4
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      1
+       DW      LSDRIVE
+
+       IF      CONVERT
+       DB      2
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLSDRIVE
+       ENDIF
+       ENDIF
+
+       IF      CROMEMCO4FDC*COMBIN
+;
+; A PerSci 277 and one 5.25-inch drive.
+;
+DRVTAB:        DB      31H,32H,24H,31H,32H
+TRKPT: DB      0,0,1,0,0
+TRKTAB:        DB      -1,-1
+INITTAB:
+
+       IF      CONVERT-1
+       DB      3
+       ENDIF
+
+       IF      CONVERT
+       DB      5
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      1
+       DW      LSDRIVE
+       DB      2
+       DW      SSDRIVE
+
+       IF      CONVERT
+       DB      3
+       DW      OLDLSDRIVE
+       DB      4
+       DW      OLDLSDRIVE
+       ENDIF
+       ENDIF
+
+       IF      CROMEMCO4FDC*SMALL
+;
+; Three 5.25-inch drives.
+;
+DRVTAB:        DB      21H,22H,24H
+TRKPT: DB      0,1,2
+TRKTAB:        DB      -1,-1,-1
+INITTAB:DB     3
+       DB      0
+       DW      SSDRIVE
+       DB      1
+       DW      SSDRIVE
+       DB      2
+       DW      SSDRIVE
+       ENDIF
+
+       IF      CUSTOM
+;
+; Cromemco 4FDC with two 8-inch Shugart-type drives.
+;
+DRVTAB:        DB      31H,32H,31H,32H
+TRKPT: DB      0,1,0,1
+TRKTAB:        DB      -1,-1
+INITTAB:
+       IF      CONVERT-1
+       DB      2
+       ENDIF
+
+       IF      CONVERT
+       DB      4
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      1
+       DW      LSDRIVE
+
+       IF      CONVERT
+       DB      2
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLSDRIVE
+       ENDIF
+       ENDIF
+
+       IF      CROMEMCO16FDC*SMALL
+;
+; Three 5.25-inch drives.
+;
+DRVTAB:        DB      21H,61H,22H,62H,24H,64H
+TRKPT: DB      0,0,1,1,2,2
+TRKTAB:        DB      -1,-1,-1
+INITTAB:DB     6
+       DB      0
+       DW      SSDRIVE
+       DB      0
+       DW      SDDRIVE
+       DB      1
+       DW      SSDRIVE
+       DB      1
+       DW      SDDRIVE
+       DB      2
+       DW      SSDRIVE
+       DB      2
+       DW      SDDRIVE
+       ENDIF
+
+       IF      CROMEMCO16FDC*COMBIN
+;
+; A PerSci 277 or 299 and one 5.25-inch drive.
+;
+DRVTAB:        DB      31H,71H,32H,72H,24H,64H,31H,71H,32H,72H
+TRKPT: DB      0,0,0,0,1,1,0,0,0,0
+TRKTAB:        DB      -1,-1
+INITTAB:
+       IF      CONVERT-1
+       DB      6
+       ENDIF
+
+       IF      CONVERT
+       DB      10
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      0
+       DW      LDDRIVE
+       DB      1
+       DW      LSDRIVE
+       DB      1
+       DW      LDDRIVE
+       DB      2
+       DW      SSDRIVE
+       DB      2
+       DW      SDDRIVE
+
+       IF      CONVERT
+       DB      3
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLDDRIVE
+       DB      4
+       DW      OLDLSDRIVE
+       DB      4
+       DW      OLDLDDRIVE
+       ENDIF
+       ENDIF
+
+       IF      CROMEMCO16FDC*LARGE
+;
+; A PerSci 277 or 299.
+;
+DRVTAB:        DB      31H,71H,32H,72H,31H,71H,32H,72H
+TRKPT: DB      0,0,0,0,0,0,0,0
+TRKTAB:        DB      -1
+INITTAB:
+       IF      CONVERT-1
+       DB      4
+       ENDIF
+
+       IF      CONVERT
+       DB      8
+       ENDIF
+
+       DB      0
+       DW      LSDRIVE
+       DB      0
+       DW      LDDRIVE
+       DB      1
+       DW      LSDRIVE
+       DB      1
+       DW      LDDRIVE
+
+       IF      CONVERT
+       DB      2
+       DW      OLDLSDRIVE
+       DB      2
+       DW      OLDLDDRIVE
+       DB      3
+       DW      OLDLSDRIVE
+       DB      3
+       DW      OLDLDDRIVE
+       ENDIF
+       ENDIF
+
+       IF      SMALL+COMBIN
+SSDRIVE:
+       DW      128             ; Sector size in bytes.
+       DB      2               ; Sector per allocation unit.
+       DW      54              ; Reserved sectors.
+       DB      2               ; Number of allocation tables.
+       DW      64              ; Number of directory entrys.
+       DW      720             ; Number of sectors on the disk.
+
+       IF      SMALLDS-1
+SDDRIVE:                       ; This is the IBM Personal Computer
+       DW      512             ; disk format.
+       DB      1
+       DW      1
+       DB      2
+       DW      64
+       DW      320
+       ENDIF
+
+       IF      SMALLDS
+SDDRIVE:
+       DW      512
+       DB      2
+       DW      1
+       DB      2
+       DW      112
+       DW      640
+       ENDIF
+       ENDIF                   ; End of small drive DPTs.
+
+       IF      COMBIN+LARGE
+LSDRIVE:
+       DW      128             ; Size of sector in bytes.
+       DB      4               ; Sectors per allocation unit.
+       DW      1               ; Number of reserved sectors.
+       DB      2               ; Number of File Allocation Tables.
+       DW      68              ; Number of directory entrys.
+       DW      77*26           ; Number of sectors on the disk.
+
+       IF      CONVERT
+OLDLSDRIVE:
+       DW      128
+       DB      4
+       DW      52              ; Old format had two tracks reserved.
+       DB      2
+       DW      64              ; 64 directory entrys.
+       DW      77*26
+       ENDIF
+
+       IF      LARGEDS-1
+OLDLDDRIVE:
+LDDRIVE:
+       DW      1024
+       DB      1
+       DW      1
+       DB      2
+       DW      96
+       DW      77*8
+       ENDIF
+
+       IF      LARGEDS
+LDDRIVE:
+       DW      1024
+       DB      1
+       DW      1
+       DB      2
+       DW      192             ; 192 directory entrys in new 8-inch DD/DS format.
+       DW      77*8*2
+
+       IF      CONVERT
+OLDLDDRIVE:
+       DW      1024
+       DB      1
+       DW      1
+       DB      2
+       DW      128             ; 128 directory entrys in old 8-inch DD/DS format.
+       DW      77*8*2
+       ENDIF
+       ENDIF
+
+       ENDIF                   ; End of large drive DPTs.
+
+DOSSEG:        EQU     ($+15)/16+BIOSSEG       ; Compute segment to use for 86-DOS.
+DOSDIF:        EQU     16*(DOSSEG-BIOSSEG)
+STKSAV:        EQU     1701H+DOSDIF
+DMAADD:        EQU     15B4H+DOSDIF
+       END
+\1a
\ No newline at end of file
diff --git a/v1.25/source/MSDOS.ASM b/v1.25/source/MSDOS.ASM
new file mode 100644 (file)
index 0000000..8538b76
--- /dev/null
@@ -0,0 +1,4031 @@
+; 86-DOS  High-performance operating system for the 8086  version 1.25
+;       by Tim Paterson
+
+
+; ****************** Revision History *************************
+;          >> EVERY change must noted below!! <<
+;
+; 0.34 12/29/80 General release, updating all past customers
+; 0.42 02/25/81 32-byte directory entries added
+; 0.56 03/23/81 Variable record and sector sizes
+; 0.60 03/27/81 Ctrl-C exit changes, including register save on user stack
+; 0.74 04/15/81 Recognize I/O devices with file names
+; 0.75 04/17/81 Improve and correct buffer handling
+; 0.76 04/23/81 Correct directory size when not 2^N entries
+; 0.80 04/27/81 Add console input without echo, Functions 7 & 8
+; 1.00 04/28/81 Renumber for general release
+; 1.01 05/12/81 Fix bug in `STORE'
+; 1.10 07/21/81 Fatal error trapping, NUL device, hidden files, date & time,
+;               RENAME fix, general cleanup
+; 1.11 09/03/81 Don't set CURRENT BLOCK to 0 on open; fix SET FILE SIZE
+; 1.12 10/09/81 Zero high half of CURRENT BLOCK after all (CP/M programs don't)
+; 1.13 10/29/81 Fix classic "no write-through" error in buffer handling
+; 1.20 12/31/81 Add time to FCB; separate FAT from DPT; Kill SMALLDIR;
+;               Add FLUSH and MAPDEV calls; allow disk mapping in DSKCHG;
+;               Lots of smaller improvements
+; 1.21 01/06/82 HIGHMEM switch to run DOS in high memory
+; 1.22 01/12/82 Add VERIFY system call to enable/disable verify after write
+; 1.23 02/11/82 Add defaulting to parser; use variable escape character
+;               Don't zero extent field in IBM version (back to 1.01!)
+; 1.24 03/01/82 Restore fcn. 27 to 1.0 level; add fcn. 28
+; 1.25 03/03/82 Put marker (00) at end of directory to speed searches
+;
+; *************************************************************
+
+
+; Interrupt Entry Points:
+
+; INTBASE:      ABORT
+; INTBASE+4:    COMMAND
+; INTBASE+8:    BASE EXIT ADDRESS
+; INTBASE+C:    CONTROL-C ABORT
+; INTBASE+10H:  FATAL ERROR ABORT
+; INTBASE+14H:  BIOS DISK READ
+; INTBASE+18H:  BIOS DISK WRITE
+; INTBASE+40H:  Long jump to CALL entry point
+
+        IF      IBM
+ESCCH   EQU     0
+CANCEL  EQU     1BH             ;Cancel with ESC
+TOGLINS EQU     TRUE            ;One key toggles insert mode
+TOGLPRN EQU     TRUE            ;One key toggles printer echo
+NUMDEV  EQU     6               ;Include "COM1" as I/O device name
+ZEROEXT EQU     TRUE
+        ELSE
+ESCCH   EQU     1BH
+CANCEL  EQU     "X"-"@"         ;Cancel with Ctrl-X
+TOGLINS EQU     FALSE           ;Separate keys for insert mode on and off
+TOGLPRN EQU     FALSE           ;Separate keys for printer echo on and off
+NUMDEV  EQU     5               ;Number of I/O device names
+ZEROEXT EQU     FALSE
+        ENDIF
+
+MAXCALL EQU     36
+MAXCOM  EQU     46
+INTBASE EQU     80H
+INTTAB  EQU     20H
+ENTRYPOINTSEG   EQU     0CH
+ENTRYPOINT      EQU     INTBASE+40H
+CONTC   EQU     INTTAB+3
+EXIT    EQU     INTBASE+8
+LONGJUMP EQU    0EAH
+LONGCALL EQU    9AH
+MAXDIF  EQU     0FFFH
+SAVEXIT EQU     10
+
+; Field definition for FCBs
+
+FCBLOCK STRUC
+        DB      12 DUP (?)              ;Drive code and name
+EXTENT  DW      ?
+RECSIZ  DW      ?       ;Size of record (user settable)
+FILSIZ  DW      ?       ;Size of file in bytes
+DRVBP   DW      ?       ;BP for SEARCH FIRST and SEARCH NEXT
+FDATE   DW      ?       ;Date of last writing
+FTIME   DW      ?       ;Time of last writing
+DEVID   DB      ?       ;Device ID number, bits 0-5
+                        ;bit 7=0 for file, bit 7=1 for I/O device
+                        ;If file, bit 6=0 if dirty
+                        ;If I/O device, bit 6=0 if EOF (input)
+FIRCLUS DW      ?       ;First cluster of file
+LSTCLUS DW      ?       ;Last cluster accessed
+CLUSPOS DW      ?       ;Position of last cluster accessed
+        DB      ?       ;Forces NR to offset 32
+NR      DB      ?       ;Next record
+RR      DB      3 DUP (?)               ;Random record
+FCBLOCK ENDS
+FILDIRENT       = FILSIZ                ;Used only by SEARCH FIRST and SEARCH NEXT
+
+; Description of 32-byte directory entry (same as returned by SEARCH FIRST
+; and SEARCH NEXT, functions 17 and 18).
+;
+; Location      bytes   Description
+;
+;    0          11      File name and extension ( 0E5H if empty)
+;   11           1      Attributes. Bits 1 or 2 make file hidden
+;   12          10      Zero field (for expansion)
+;   22           2      Time. Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
+;   24           2      Date. Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
+;   26           2      First allocation unit ( < 4080 )
+;   28           4      File size, in bytes (LSB first, 30 bits max.)
+;
+; The File Allocation Table uses a 12-bit entry for each allocation unit on
+; the disk. These entries are packed, two for every three bytes. The contents
+; of entry number N is found by 1) multiplying N by 1.5; 2) adding the result
+; to the base address of the Allocation Table; 3) fetching the 16-bit word at
+; this address; 4) If N was odd (so that N*1.5 was not an integer), shift the
+; word right four bits; 5) mask to 12 bits (AND with 0FFF hex). Entry number
+; zero is used as an end-of-file trap in the OS and as a flag for directory
+; entry size (if SMALLDIR selected). Entry 1 is reserved for future use. The
+; 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
+
+DPBLOCK STRUC
+DEVNUM  DB      ?       ;I/O driver number
+DRVNUM  DB      ?       ;Physical Unit number
+SECSIZ  DW      ?       ;Size of physical sector in bytes
+CLUSMSK DB      ?       ;Sectors/cluster - 1
+CLUSSHFT DB     ?       ;Log2 of sectors/cluster
+FIRFAT  DW      ?       ;Starting record of FATs
+FATCNT  DB      ?       ;Number of FATs for this drive
+MAXENT  DW      ?       ;Number of directory entries
+FIRREC  DW      ?       ;First sector of first cluster
+MAXCLUS DW      ?       ;Number of clusters on drive + 1
+FATSIZ  DB      ?       ;Number of records occupied by FAT
+FIRDIR  DW      ?       ;Starting record of directory
+FAT     DW      ?       ;Pointer to start of FAT
+DPBLOCK ENDS
+
+DPBSIZ  EQU     20      ;Size of the structure in bytes
+DIRSEC  =       FIRREC  ;Number of dir. sectors (init temporary)
+DSKSIZ  =       MAXCLUS ;Size of disk (temp used during init only)
+
+;The following are all of the segments used
+;They are declared in the order that they should be placed in the executable
+
+CODE    SEGMENT
+CODE    ENDS
+
+CONSTANTS       SEGMENT BYTE
+CONSTANTS       ENDS
+
+DATA    SEGMENT WORD
+DATA    ENDS
+
+DOSGROUP        GROUP   CODE,CONSTANTS,DATA
+
+SEGBIOS SEGMENT
+SEGBIOS ENDS
+
+
+; BOIS entry point definitions
+
+        IF      IBM
+BIOSSEG EQU     60H
+        ENDIF
+        IF      NOT IBM
+BIOSSEG EQU     40H
+        ENDIF
+
+SEGBIOS         SEGMENT AT BIOSSEG
+                ORG     0
+                DB      3 DUP (?)       ;Reserve room for jump to init code
+BIOSSTAT        DB      3 DUP (?)       ;Console input status check
+BIOSIN          DB      3 DUP (?)       ;Get console character
+BIOSOUT         DB      3 DUP (?)       ;Output console character
+BIOSPRINT       DB      3 DUP (?)       ;Output to printer
+BIOSAUXIN       DB      3 DUP (?)       ;Get byte from auxilliary
+BIOSAUXOUT      DB      3 DUP (?)       ;Output byte to auxilliary
+BIOSREAD        DB      3 DUP (?)       ;Disk read
+BIOSWRITE       DB      3 DUP (?)       ;Disk write
+BIOSDSKCHG      DB      3 DUP (?)       ;Dsik-change status
+BIOSSETDATE     DB      3 DUP (?)       ;Set date
+BIOSSETTIME     DB      3 DUP (?)       ;Set time
+BIOSGETTIME     DB      3 DUP (?)       ;Get time and date
+BIOSFLUSH       DB      3 DUP (?)       ;Clear console input buffer
+BIOSMAPDEV      DB      3 DUP (?)       ;Dynamic disk table mapper
+
+SEGBIOS ENDS
+; Location of user registers relative user stack pointer
+