]> wirehaze git hosting - MS-DOS.git/commitdiff

wirehaze git hosting

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
+
+STKPTRS STRUC
+AXSAVE  DW      ?
+BXSAVE  DW      ?
+CXSAVE  DW      ?
+DXSAVE  DW      ?
+SISAVE  DW      ?
+DISAVE  DW      ?
+BPSAVE  DW      ?
+DSSAVE  DW      ?
+ESSAVE  DW      ?
+IPSAVE  DW      ?
+CSSAVE  DW      ?
+FSAVE   DW      ?
+STKPTRS ENDS
+
+; Start of code
+
+CODE    SEGMENT
+ASSUME  CS:DOSGROUP,DS:DOSGROUP,ES:DOSGROUP,SS:DOSGROUP
+
+        ORG     0
+CODSTRT EQU     $
+        JMP     DOSINIT
+
+ESCCHAR DB      ESCCH   ;Lead-in character for escape sequences
+ESCTAB: 
+        IF      NOT IBM
+        DB      "S"     ;Copy one char
+        DB      "V"     ;Skip one char
+        DB      "T"     ;Copy to char
+        DB      "W"     ;Skip to char
+        DB      "U"     ;Copy line
+        DB      "E"     ;Kill line (no change in template)
+        DB      "J"     ;Reedit line (new template)
+        DB      "D"     ;Backspace
+        DB      "P"     ;Enter insert mode
+        DB      "Q"     ;Exit insert mode
+        DB      "R"     ;Escape character
+        DB      "R"     ;End of table
+        ENDIF
+        IF      IBM
+        DB      64      ;Crtl-Z - F6
+        DB      77      ;Copy one char - -->
+        DB      59      ;Copy one char - F1
+        DB      83      ;Skip one char - DEL
+        DB      60      ;Copy to char - F2
+        DB      62      ;Skip to char - F4
+        DB      61      ;Copy line - F3
+        DB      61      ;Kill line (no change to template ) - Not used
+        DB      63      ;Reedit line (new template) - F5
+        DB      75      ;Backspace - <--
+        DB      82      ;Enter insert mode - INS (toggle)
+        DB      65      ;Escape character - F7
+        DB      65      ;End of table
+        ENDIF
+
+ESCTABLEN EQU   $-ESCTAB
+        IF      NOT IBM
+HEADER  DB      13,10,"MS-DOS version 1.25"
+        IF      HIGHMEM
+        DB      "H"
+        ENDIF
+        IF      DSKTEST
+        DB      "D"
+        ENDIF
+
+        DB      13,10
+        DB      "Copyright 1981,82 Microsoft, Inc.",13,10,"$"
+        ENDIF
+
+QUIT:
+        MOV     AH,0
+        JMP     SHORT SAVREGS
+
+COMMAND: ;Interrupt call entry point
+        CMP     AH,MAXCOM
+        JBE     SAVREGS
+BADCALL:
+        MOV     AL,0
+IRET:   IRET
+
+ENTRY:  ;System call entry point and dispatcher
+        POP     AX              ;IP from the long call at 5
+        POP     AX              ;Segment from the long call at 5
+        POP     CS:[TEMP]       ;IP from the CALL 5
+        PUSHF                   ;Start re-ordering the stack
+        CLI
+        PUSH    AX              ;Save segment
+        PUSH    CS:[TEMP]       ;Stack now ordered as if INT had been used
+        CMP     CL,MAXCALL      ;This entry point doesn't get as many calls
+        JA      BADCALL
+        MOV     AH,CL
+SAVREGS:
+        PUSH    ES
+        PUSH    DS
+        PUSH    BP
+        PUSH    DI
+        PUSH    SI
+        PUSH    DX
+        PUSH    CX
+        PUSH    BX
+        PUSH    AX
+
+        IF      DSKTEST
+        MOV     AX,CS:[SPSAVE]
+        MOV     CS:[NSP],AX
+        MOV     AX,CS:[SSSAVE]
+        MOV     CS:[NSS],AX
+        POP     AX
+        PUSH    AX
+        ENDIF
+
+        MOV     CS:[SPSAVE],SP
+        MOV     CS:[SSSAVE],SS
+        MOV     SP,CS
+        MOV     SS,SP
+REDISP:
+        MOV     SP,OFFSET DOSGROUP:IOSTACK
+        STI                     ;Stack OK now
+        MOV     BL,AH
+        MOV     BH,0
+        SHL     BX,1
+        CLD
+        CMP     AH,12
+        JLE     SAMSTK
+        MOV     SP,OFFSET DOSGROUP:DSKSTACK
+SAMSTK:
+        CALL    CS:[BX+DISPATCH]
+LEAVE:
+        CLI
+        MOV     SP,CS:[SPSAVE]
+        MOV     SS,CS:[SSSAVE]
+        MOV     BP,SP
+        MOV     BYTE PTR [BP.AXSAVE],AL
+
+        IF      DSKTEST
+        MOV     AX,CS:[NSP]
+        MOV     CS:[SPSAVE],AX
+        MOV     AX,CS:[NSS]
+        MOV     CS:[SSSAVE],AX
+        ENDIF
+
+        POP     AX
+        POP     BX
+        POP     CX
+        POP     DX
+        POP     SI
+        POP     DI
+        POP     BP
+        POP     DS
+        POP     ES
+        IRET
+; Standard Functions
+DISPATCH DW     ABORT           ;0
+        DW      CONIN
+        DW      CONOUT
+        DW      READER
+        DW      PUNCH
+        DW      LIST            ;5
+        DW      RAWIO
+        DW      RAWINP
+        DW      IN
+        DW      PRTBUF
+        DW      BUFIN           ;10
+        DW      CONSTAT
+        DW      FLUSHKB
+        DW      DSKRESET
+        DW      SELDSK
+        DW      OPEN            ;15
+        DW      CLOSE
+        DW      SRCHFRST
+        DW      SRCHNXT
+        DW      DELETE
+        DW      SEQRD           ;20
+        DW      SEQWRT
+        DW      CREATE
+        DW      RENAME
+        DW      INUSE
+        DW      GETDRV          ;25
+        DW      SETDMA
+        DW      GETFATPT
+        DW      GETFATPTDL
+        DW      GETRDONLY
+        DW      SETATTRIB       ;30
+        DW      GETDSKPT
+        DW      USERCODE
+        DW      RNDRD
+        DW      RNDWRT
+        DW      FILESIZE        ;35
+        DW      SETRNDREC
+; Extended Functions
+        DW      SETVECT
+        DW      NEWBASE
+        DW      BLKRD
+        DW      BLKWRT          ;40
+        DW      MAKEFCB
+        DW      GETDATE
+        DW      SETDATE
+        DW      GETTIME
+        DW      SETTIME         ;45
+        DW      VERIFY
+
+INUSE:
+GETIO:
+SETIO:
+GETRDONLY:
+SETATTRIB:
+USERCODE:
+        MOV     AL,0
+        RET
+
+VERIFY:
+        AND     AL,1
+        MOV     CS:VERFLG,AL
+        RET
+
+FLUSHKB:
+        PUSH    AX
+        CALL    FAR PTR BIOSFLUSH
+        POP     AX
+        MOV     AH,AL
+        CMP     AL,1
+        JZ      REDISPJ
+        CMP     AL,6
+        JZ      REDISPJ
+        CMP     AL,7
+        JZ      REDISPJ
+        CMP     AL,8
+        JZ      REDISPJ
+        CMP     AL,10
+        JZ      REDISPJ
+        MOV     AL,0
+        RET
+
+REDISPJ:JMP     REDISP
+
+READER:
+AUXIN:
+        CALL    STATCHK
+        CALL    FAR PTR BIOSAUXIN 
+        RET
+
+PUNCH:
+        MOV     AL,DL
+AUXOUT:
+        PUSH    AX
+        CALL    STATCHK
+        POP     AX
+        CALL    FAR PTR BIOSAUXOUT 
+        RET
+
+
+UNPACK:
+
+; Inputs:
+;       DS = CS
+;       BX = Cluster number
+;       BP = Base of drive parameters
+;       SI = Pointer to drive FAT
+; Outputs:
+;       DI = Contents of FAT for given cluster
+;       Zero set means DI=0 (free cluster)
+; No other registers affected. Fatal error if cluster too big.
+
+        CMP     BX,[BP.MAXCLUS]
+        JA      HURTFAT
+        LEA     DI,[SI+BX]
+        SHR     BX,1
+        MOV     DI,[DI+BX]
+        JNC     HAVCLUS
+        SHR     DI,1
+        SHR     DI,1
+        SHR     DI,1
+        SHR     DI,1
+        STC
+HAVCLUS:
+        RCL     BX,1
+        AND     DI,0FFFH
+        RET
+HURTFAT:
+        PUSH    AX
+        MOV     AH,80H          ;Signal Bad FAT to INT 24H handler
+        MOV     DI,0FFFH        ;In case INT 24H returns (it shouldn't)
+        CALL    FATAL
+        POP     AX              ;Try to ignore bad FAT
+        RET
+
+
+PACK:
+
+; Inputs:
+;       DS = CS
+;       BX = Cluster number
+;       DX = Data
+;       SI = Pointer to drive FAT
+; Outputs:
+;       The data is stored in the FAT at the given cluster.
+;       BX,DX,DI all destroyed
+;       No other registers affected
+
+        MOV     DI,BX
+        SHR     BX,1
+        ADD     BX,SI
+        ADD     BX,DI
+        SHR     DI,1
+        MOV     DI,[BX]
+        JNC     ALIGNED
+        SHL     DX,1
+        SHL     DX,1
+        SHL     DX,1
+        SHL     DX,1
+        AND     DI,0FH
+        JMP     SHORT PACKIN
+ALIGNED:
+        AND     DI,0F000H
+PACKIN:
+        OR      DI,DX
+        MOV     [BX],DI
+        RET
+
+DEVNAME:
+        MOV     SI,OFFSET DOSGROUP:IONAME       ;List of I/O devices with file names
+        MOV     BH,NUMDEV               ;BH = number of device names
+LOOKIO:
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        MOV     CX,4                    ;All devices are 4 letters
+        REPE    CMPSB                   ;Check for name in list
+        JZ      IOCHK                   ;If first 3 letters OK, check for the rest
+        ADD     SI,CX                   ;Point to next device name
+        DEC     BH
+        JNZ     LOOKIO
+CRET:
+        STC                             ;Not found
+        RET
+
+IOCHK:
+        IF      IBM
+        CMP     BH,NUMDEV       ;Is it the first device?
+        JNZ     NOTCOM1
+        MOV     BH,2            ;Make it the same as AUX
+NOTCOM1:
+        ENDIF
+        NEG     BH
+        MOV     CX,2            ;Check rest of name but not extension
+        MOV     AX,2020H
+        REPE    SCASW           ;Make sure rest of name is blanks
+        JNZ     CRET
+RET1:   RET                     ;Zero set so CREATE works
+
+GETFILE:
+; Same as GETNAME except ES:DI points to FCB on successful return
+        CALL    MOVNAME
+        JC      RET1
+        PUSH    DX
+        PUSH    DS
+        CALL    FINDNAME
+        POP     ES
+        POP     DI
+RET2:   RET
+
+
+GETNAME:
+
+; Inputs:
+;       DS,DX point to FCB
+; Function:
+;       Find file name in disk directory. First byte is
+;       drive number (0=current disk). "?" matches any
+;       character.
+; Outputs:
+;       Carry set if file not found
+;       ELSE
+;       Zero set if attributes match (always except when creating)
+;       BP = Base of drive parameters
+;       DS = CS
+;       ES = CS
+;       BX = Pointer into directory buffer
+;       SI = Pointer to First Cluster field in directory entry
+;       [DIRBUF] has directory record with match
+;       [NAME1] has file name
+; All other registers destroyed.
+
+        CALL    MOVNAME
+        JC      RET2            ;Bad file name?
+FINDNAME:
+        MOV     AX,CS
+        MOV     DS,AX
+        CALL    DEVNAME
+        JNC     RET2
+        CALL    STARTSRCH
+CONTSRCH:
+        CALL    GETENTRY
+        JC      RET2
+SRCH:
+        MOV     AH,BYTE PTR [BX]
+        OR      AH,AH                   ;End of directory?
+        JZ      FREE
+        CMP     AH,[DELALL]             ;Free entry?
+        JZ      FREE
+        MOV     SI,BX
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        MOV     CX,11
+WILDCRD:
+        REPE    CMPSB
+        JZ      FOUND
+        CMP     BYTE PTR [DI-1],"?"
+        JZ      WILDCRD
+NEXTENT:
+        CALL    NEXTENTRY
+        JNC     SRCH
+RET3:   RET
+
+FREE:
+        CMP     [ENTFREE],-1            ;Found a free entry before?
+        JNZ     TSTALL                  ;If so, ignore this one
+        MOV     CX,[LASTENT]
+        MOV     [ENTFREE],CX
+TSTALL:
+        CMP     AH,[DELALL]             ;At end of directory?
+        JZ      NEXTENT                 ;No - continue search
+        STC                             ;Report not found
+        RET
+FOUND:
+;Check if attributes allow finding it
+        MOV     AH,[ATTRIB]             ;Attributes of search
+        NOT     AH
+        AND     AH,[SI]                 ;Compare with attributes of file
+        ADD     SI,15   
+        AND     AH,6                    ;Only look at bits 1 and 2
+        JZ      RET3
+        TEST    BYTE PTR [CREATING],-1  ;Pass back mismatch if creating
+        JZ      NEXTENT                 ;Otherwise continue searching
+        RET
+
+
+GETENTRY:
+
+; Inputs:
+;       [LASTENT] has previously searched directory entry
+; Function:
+;       Locates next sequential directory entry in preparation for search
+; Outputs:
+;       Carry set if none
+;       ELSE
+;       AL = Current directory block
+;       BX = Pointer to next directory entry in [DIRBUF]
+;       DX = Pointer to first byte after end of DIRBUF
+;       [LASTENT] = New directory entry number
+
+        MOV     AX,[LASTENT]
+        INC     AX                      ;Start with next entry
+        CMP     AX,[BP.MAXENT]
+        JAE     NONE
+GETENT:
+        MOV     [LASTENT],AX
+        MOV     CL,4
+        SHL     AX,CL
+        XOR     DX,DX
+        SHL     AX,1
+        RCL     DX,1                    ;Account for overflow in last shift
+        MOV     BX,[BP.SECSIZ]
+        AND     BL,255-31               ;Must be multiple of 32
+        DIV     BX
+        MOV     BX,DX                   ;Position within sector
+        MOV     AH,[BP.DEVNUM]          ;AL=Directory sector no.
+        CMP     AX,[DIRBUFID]
+        JZ      HAVDIRBUF
+        PUSH    BX
+        CALL    DIRREAD
+        POP     BX
+HAVDIRBUF:
+        MOV     DX,OFFSET DOSGROUP:DIRBUF
+        ADD     BX,DX
+        ADD     DX,[BP.SECSIZ]
+        RET
+
+NEXTENTRY:
+
+; Inputs:
+;       Same as outputs of GETENTRY, above
+; Function:
+;       Update AL, BX, and [LASTENT] for next directory entry.
+;       Carry set if no more.
+
+        MOV     DI,[LASTENT]
+        INC     DI
+        CMP     DI,[BP.MAXENT]
+        JAE     NONE
+        MOV     [LASTENT],DI
+        ADD     BX,32
+        CMP     BX,DX
+        JB      HAVIT
+        INC     AL                      ;Next directory sector
+        PUSH    DX                      ;Save limit
+        CALL    DIRREAD
+        POP     DX
+        MOV     BX,OFFSET DOSGROUP:DIRBUF
+HAVIT:
+        CLC
+        RET
+
+NONE:
+        CALL    CHKDIRWRITE
+        STC
+RET4:   RET
+
+
+DELETE: ; System call 19
+        CALL    MOVNAME
+        MOV     AL,-1
+        JC      RET4
+        MOV     AL,CS:[ATTRIB]
+        AND     AL,6                    ;Look only at hidden bits
+        CMP     AL,6                    ;Both must be set
+        JNZ     NOTALL
+        MOV     CX,11
+        MOV     AL,"?"
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        REPE    SCASB                   ;See if name is *.*
+        JNZ     NOTALL
+        MOV     BYTE PTR CS:[DELALL],0  ;DEL *.* - flag deleting all
+NOTALL:
+        CALL    FINDNAME
+        MOV     AL,-1
+        JC      RET4
+        OR      BH,BH           ;Check if device name
+        JS      RET4            ;Can't delete I/O devices
+DELFILE:
+        MOV     BYTE PTR [DIRTYDIR],-1
+        MOV     AH,[DELALL]
+        MOV     BYTE PTR [BX],AH
+        MOV     BX,[SI]
+        MOV     SI,[BP.FAT]
+        OR      BX,BX
+        JZ      DELNXT
+        CMP     BX,[BP.MAXCLUS]
+        JA      DELNXT
+        CALL    RELEASE
+DELNXT:
+        CALL    CONTSRCH
+        JNC     DELFILE
+        CALL    FATWRT
+        CALL    CHKDIRWRITE
+        XOR     AL,AL
+        RET
+
+
+RENAME: ;System call 23
+        CALL    MOVNAME
+        JC      ERRET
+        ADD     SI,5
+        MOV     DI,OFFSET DOSGROUP:NAME2
+        CALL    LODNAME
+        JC      ERRET           ;Report error if second name invalid
+        CALL    FINDNAME
+        JC      ERRET
+        OR      BH,BH           ;Check if I/O device name
+        JS      ERRET           ;If so, can't rename it
+        MOV     SI,OFFSET DOSGROUP:NAME1
+        MOV     DI,OFFSET DOSGROUP:NAME3
+        MOV     CX,6            ;6 words (12 bytes)--include attribute byte
+        REP     MOVSW           ;Copy name to search for
+RENFIL:
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        MOV     SI,OFFSET DOSGROUP:NAME2
+        MOV     CX,11
+NEWNAM:
+        LODSB
+        CMP     AL,"?"
+        JNZ     NOCHG
+        MOV     AL,[BX]
+NOCHG:
+        STOSB
+        INC     BX
+        LOOP    NEWNAM
+        MOV     BYTE PTR [DI],6 ;Stop duplicates with any attributes
+        CALL    DEVNAME         ;Check if giving it a device name
+        JNC     RENERR
+        PUSH    [LASTENT]       ;Save position of match
+        MOV     [LASTENT],-1    ;Search entire directory for duplicate
+        CALL    CONTSRCH        ;See if new name already exists
+        POP     AX
+        JNC     RENERR                  ;Error if found
+        CALL    GETENT                  ;Re-read matching entry
+        MOV     DI,BX
+        MOV     SI,OFFSET DOSGROUP:NAME1
+        MOV     CX,5
+        MOVSB
+        REP     MOVSW                   ;Replace old name with new one
+        MOV     BYTE PTR [DIRTYDIR],-1  ;Flag change in directory
+        MOV     SI,OFFSET DOSGROUP:NAME3
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        MOV     CX,6                    ;Include attribute byte
+        REP     MOVSW                   ;Copy name back into search buffer
+        CALL    CONTSRCH
+        JNC     RENFIL
+        CALL    CHKDIRWRITE
+        XOR     AL,AL
+        RET
+
+RENERR:
+        CALL    CHKDIRWRITE
+ERRET:
+        MOV     AL,-1
+RET5:   RET
+
+
+MOVNAME:
+
+; Inputs:
+;       DS, DX point to FCB or extended FCB
+; Outputs:
+;       DS:DX point to normal FCB
+;       ES = CS
+;       If file name OK:
+;       BP has base of driver parameters
+;       [NAME1] has name in upper case
+; All registers except DX destroyed
+; Carry set if bad file name or drive
+
+        MOV     CS:WORD PTR [CREATING],0E500H   ;Not creating, not DEL *.*
+        MOV     AX,CS
+        MOV     ES,AX
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        MOV     SI,DX
+        LODSB
+        MOV     CS:[EXTFCB],AL  ;Set flag if extended FCB in use
+        MOV     AH,0            ;Set default attributes
+        CMP     AL,-1           ;Is it an extended FCB?
+        JNZ     HAVATTRB
+        ADD     DX,7            ;Adjust to point to normal FCB
+        ADD     SI,6            ;Point to drive select byte
+        MOV     AH,[SI-1]       ;Get attribute byte
+        LODSB           ;Get drive select byte
+HAVATTRB:
+        MOV     CS:[ATTRIB],AH  ;Save attributes
+        CALL    GETTHISDRV
+LODNAME:
+; This entry point copies a file name from DS,SI
+; to ES,DI converting to upper case.
+        CMP     BYTE PTR [SI]," "       ;Don't allow blank as first letter
+        STC                     ;In case of error
+        JZ      RET5
+        MOV     CX,11
+MOVCHK:
+        CALL    GETLET
+        JB      RET5
+        JNZ     STOLET          ;Is it a delimiter?
+        CMP     AL," "          ;This is the only delimiter allowed
+        STC                     ;In case of error
+        JNZ     RET5
+STOLET:
+        STOSB
+        LOOP    MOVCHK
+        CLC                     ;Got through whole name - no error
+RET6:   RET
+
+GETTHISDRV:
+        CMP     CS:[NUMDRV],AL
+        JC      RET6
+        DEC     AL
+        JNS     PHYDRV
+        MOV     AL,CS:[CURDRV]
+PHYDRV:
+        MOV     CS:[THISDRV],AL
+        RET
+        
+
+OPEN:   ;System call 15
+        CALL    GETFILE
+DOOPEN:
+; Enter here to perform OPEN on file already found
+; in directory. DS=CS, BX points to directory
+; entry in DIRBUF, SI points to First Cluster field, and
+; ES:DI point to the FCB to be opened. This entry point
+; is used by CREATE.
+        JC      ERRET
+        OR      BH,BH           ;Check if file is I/O device
+        JS      OPENDEV         ;Special handler if so
+        MOV     AL,[THISDRV]
+        INC     AX
+        STOSB
+        XOR     AX,AX
+        IF      ZEROEXT
+        ADD     DI,11
+        STOSW                   ;Zero low byte of extent field if IBM only
+        ENDIF
+        IF      NOT ZEROEXT
+        ADD     DI,12           ;Point to high half of CURRENT BLOCK field
+        STOSB                   ;Set it to zero (CP/M programs set low byte)
+        ENDIF
+        MOV     AL,128          ;Default record size
+        STOSW                   ;Set record size
+        LODSW                   ;Get starting cluster
+        MOV     DX,AX           ;Save it for the moment
+        MOVSW                   ;Transfer size to FCB
+        MOVSW
+        MOV     AX,[SI-8]       ;Get date
+        STOSW                   ;Save date in FCB
+        MOV     AX,[SI-10]      ;Get time
+        STOSW                   ;Save it in FCB
+        MOV     AL,[BP.DEVNUM]
+        OR      AL,40H
+        STOSB
+        MOV     AX,DX           ;Restore starting cluster
+        STOSW                   ; first cluster
+        STOSW                   ; last cluster accessed
+        XOR     AX,AX
+        STOSW                   ; position of last cluster
+        RET
+
+
+OPENDEV:
+        ADD     DI,13           ;point to 2nd half of extent field
+        XOR     AX,AX
+        STOSB                   ;Set it to zero
+        MOV     AL,128
+        STOSW                   ;Set record size to 128
+        XOR     AX,AX
+        STOSW
+        STOSW                   ;Set current size to zero
+        CALL    DATE16
+        STOSW                   ;Date is todays
+        XCHG    AX,DX
+        STOSW                   ;Use current time
+        MOV     AL,BH           ;Get device number
+        STOSB
+        XOR     AL,AL           ;No error
+        RET
+FATERR:
+        XCHG    AX,DI           ;Put error code in DI
+        MOV     AH,2            ;While trying to read FAT
+        MOV     AL,[THISDRV]    ;Tell which drive
+        CALL    FATAL1
+        JMP     SHORT FATREAD
+STARTSRCH:
+        MOV     AX,-1
+        MOV     [LASTENT],AX
+        MOV     [ENTFREE],AX
+FATREAD:
+
+; Inputs:
+;       DS = CS
+; Function:
+;       If disk may have been changed, FAT is read in and buffers are
+;       flagged invalid. If not, no action is taken.
+; Outputs:
+;       BP = Base of drive parameters
+;       Carry set if invalid drive returned by MAPDEV
+; All other registers destroyed
+
+        MOV     AL,[THISDRV]
+        XOR     AH,AH           ;Set default response to zero & clear carry
+        CALL    FAR PTR BIOSDSKCHG      ;See what BIOS has to say
+        JC      FATERR
+        CALL    GETBP
+        MOV     AL,[THISDRV]    ;Use physical unit number
+        MOV     SI,[BP.FAT]
+        OR      AH,[SI-1]       ;Dirty byte for FAT
+        JS      NEWDSK          ;If either say new disk, then it's so
+        JNZ     MAPDRV
+        MOV     AH,1
+        CMP     AX,WORD PTR [BUFDRVNO]  ;Does buffer have dirty sector of this drive?
+        JZ      MAPDRV
+NEWDSK:
+        CMP     AL,[BUFDRVNO]   ;See if buffer is for this drive
+        JNZ     BUFOK           ;If not, don't touch it
+        MOV     [BUFSECNO],0    ;Flag buffers invalid
+        MOV     WORD PTR [BUFDRVNO],00FFH
+BUFOK:
+        MOV     [DIRBUFID],-1
+        CALL    FIGFAT
+NEXTFAT:
+        PUSH    AX
+        CALL    DSKREAD
+        POP     AX
+        JC      BADFAT
+        SUB     AL,[BP.FATCNT]
+        JZ      NEWFAT
+        CALL    FATWRT
+NEWFAT:
+        MOV     SI,[BP.FAT]
+        MOV     AL,[BP.DEVNUM]
+        MOV     AH,[SI]         ;Get first byte of FAT
+        OR      AH,0F8H         ;Put in range
+        CALL    FAR PTR BIOSMAPDEV
+        MOV     AH,0
+        MOV     [SI-2],AX       ;Set device no. and reset dirty bit
+MAPDRV:
+        MOV     AL,[SI-2]       ;Get device number
+GETBP:
+        MOV     BP,[DRVTAB]     ;Just in case drive isn't valid
+        AND     AL,3FH          ;Mask out dirty bit
+        CMP     AL,[NUMIO]
+        CMC
+        JC      RET7
+        PUSH    AX
+        MOV     AH,DPBSIZ
+        MUL     AH
+        ADD     BP,AX
+        POP     AX
+RET7:   RET
+
+BADFAT:
+        MOV     CX,DI
+        ADD     DX,CX
+        DEC     AL
+        JNZ     NEXTFAT
+        CALL    FIGFAT                          ;Reset registers
+        CALL    DREAD                           ;Try first FAT once more
+        JMP     SHORT NEWFAT
+
+OKRET1:
+        MOV     AL,0
+        RET
+
+CLOSE:  ;System call 16
+        MOV     DI,DX
+        CMP     BYTE PTR [DI],-1                ;Check for extended FCB
+        JNZ     NORMFCB3
+        ADD     DI,7
+NORMFCB3:
+        TEST    BYTE PTR [DI.DEVID],0C0H        ;Allow only dirty files
+        JNZ     OKRET1                          ;can't close if I/O device, or not writen
+        MOV     AL,[DI]                         ;Get physical unit number
+        DEC     AL                              ;Make zero = drive A
+        MOV     AH,1                            ;Look for dirty buffer
+        CMP     AX,CS:WORD PTR [BUFDRVNO]
+        JNZ     FNDDIR
+;Write back dirty buffer if on same drive
+        PUSH    DX
+        PUSH    DS
+        PUSH    CS
+        POP     DS
+        MOV     BYTE PTR [DIRTYBUF],0
+        MOV     BX,[BUFFER]
+        MOV     CX,1
+        MOV     DX,[BUFSECNO]
+        MOV     BP,[BUFDRVBP]
+        CALL    DWRITE
+        POP     DS
+        POP     DX
+FNDDIR:
+        CALL    GETFILE
+BADCLOSEJ:
+        JC      BADCLOSE
+        MOV     CX,ES:[DI.FIRCLUS]
+        MOV     [SI],CX
+        MOV     DX,ES:WORD PTR [DI.FILSIZ]
+        MOV     [SI+2],DX
+        MOV     DX,ES:WORD PTR [DI.FILSIZ+2]
+        MOV     [SI+4],DX
+        MOV     DX,ES:[DI.FDATE]
+        MOV     [SI-2],DX
+        MOV     DX,ES:[DI.FTIME]
+        MOV     [SI-4],DX
+        CALL    DIRWRITE
+
+CHKFATWRT:
+; Do FATWRT only if FAT is dirty and uses same I/O driver
+        MOV     SI,[BP.FAT]
+        MOV     AL,[BP.DEVNUM]
+        MOV     AH,1
+        CMP     [SI-2],AX       ;See if FAT dirty and uses same driver
+        JNZ     OKRET
+
+FATWRT:
+
+; Inputs:
+;       DS = CS
+;       BP = Base of drive parameter table
+; Function:
+;       Write the FAT back to disk and reset FAT
+;       dirty bit.
+; Outputs:
+;       AL = 0
+;       BP unchanged
+; All other registers destroyed
+
+        CALL    FIGFAT
+        MOV     BYTE PTR [BX-1],0
+EACHFAT:
+        PUSH    DX
+        PUSH    CX
+        PUSH    BX
+        PUSH    AX
+        CALL    DWRITE
+        POP     AX
+        POP     BX
+        POP     CX
+        POP     DX
+        ADD     DX,CX
+        DEC     AL
+        JNZ     EACHFAT
+OKRET:
+        MOV     AL,0
+        RET
+
+BADCLOSE:
+        MOV     SI,[BP.FAT]
+        MOV     BYTE PTR [SI-1],0
+        MOV     AL,-1
+        RET
+
+
+FIGFAT:
+; Loads registers with values needed to read or
+; write a FAT.
+        MOV     AL,[BP.FATCNT]
+        MOV     BX,[BP.FAT]
+        MOV     CL,[BP.FATSIZ]  ;No. of records occupied by FAT
+        MOV     CH,0
+        MOV     DX,[BP.FIRFAT]  ;Record number of start of FATs
+        RET
+
+
+DIRCOMP:
+; Prepare registers for directory read or write
+        CBW
+        ADD     AX,[BP.FIRDIR]
+        MOV     DX,AX
+        MOV     BX,OFFSET DOSGROUP:DIRBUF
+        MOV     CX,1
+        RET
+
+
+CREATE: ;System call 22
+        CALL    MOVNAME
+        JC      ERRET3
+        MOV     DI,OFFSET DOSGROUP:NAME1
+        MOV     CX,11
+        MOV     AL,"?"
+        REPNE   SCASB
+        JZ      ERRET3
+        MOV     CS:BYTE PTR [CREATING],-1
+        PUSH    DX
+        PUSH    DS
+        CALL    FINDNAME
+        JNC     EXISTENT
+        MOV     AX,[ENTFREE]    ;First free entry found in FINDNAME
+        CMP     AX,-1
+        JZ      ERRPOP
+        CALL    GETENT          ;Point at that free entry
+        JMP     SHORT FREESPOT
+ERRPOP:
+        POP     DS
+        POP     DX
+ERRET3:
+        MOV     AL,-1
+        RET
+
+EXISTENT:
+        JNZ     ERRPOP          ;Error if attributes don't match
+        OR      BH,BH           ;Check if file is I/O device
+        JS      OPENJMP         ;If so, no action
+        MOV     CX,[SI]         ;Get pointer to clusters
+        JCXZ    FREESPOT
+        CMP     CX,[BP.MAXCLUS]
+        JA      FREESPOT
+        PUSH    BX
+        MOV     BX,CX
+        MOV     SI,[BP.FAT]
+        CALL    RELEASE         ;Free any data already allocated
+        CALL    FATWRT
+        POP     BX
+FREESPOT:
+        MOV     DI,BX
+        MOV     SI,OFFSET DOSGROUP:NAME1
+        MOV     CX,5
+        MOVSB
+        REP     MOVSW
+        MOV     AL,[ATTRIB]
+        STOSB
+        XOR     AX,AX
+        MOV     CL,5
+        REP     STOSW
+        CALL    DATE16
+        XCHG    AX,DX
+        STOSW
+        XCHG    AX,DX
+        STOSW
+        XOR     AX,AX
+        PUSH    DI
+        MOV     CL,6
+SMALLENT:
+        REP     STOSB
+        PUSH    BX
+        CALL    DIRWRITE
+        POP     BX
+        POP     SI
+OPENJMP:
+        CLC                     ;Clear carry so OPEN won't fail
+        POP     ES
+        POP     DI
+        JMP     DOOPEN
+
+
+DIRREAD:
+
+; Inputs:
+;       DS = CS
+;       AL = Directory block number
+;       BP = Base of drive parameters
+; Function:
+;       Read the directory block into DIRBUF.
+; Outputs:
+;       AX,BP unchanged
+; All other registers destroyed.
+
+        PUSH    AX
+        CALL    CHKDIRWRITE
+        POP     AX
+        PUSH    AX
+        MOV     AH,[BP.DEVNUM]
+        MOV     [DIRBUFID],AX
+        CALL    DIRCOMP
+        CALL    DREAD
+        POP     AX
+RET8:   RET
+
+
+DREAD:
+
+; Inputs:
+;       BX,DS = Transfer address
+;       CX = Number of sectors
+;       DX = Absolute record number
+;       BP = Base of drive parameters
+; Function:
+;       Calls BIOS to perform disk read. If BIOS reports
+;       errors, will call HARDERR for further action.
+; BP preserved. All other registers destroyed.
+
+        CALL    DSKREAD
+        JNC     RET8
+        MOV     CS:BYTE PTR [READOP],0
+        CALL    HARDERR
+        CMP     AL,1            ;Check for retry
+        JZ      DREAD
+        RET                     ;Ignore otherwise
+
+
+HARDERR:
+
+;Hard disk error handler. Entry conditions:
+;       DS:BX = Original disk transfer address
+;       DX = Original logical sector number
+;       CX = Number of sectors to go (first one gave the error)
+;       AX = Hardware error code
+;       DI = Original sector transfer count
+;       BP = Base of drive parameters
+;       [READOP] = 0 for read, 1 for write
+
+        XCHG    AX,DI           ;Error code in DI, count in AX
+        SUB     AX,CX           ;Number of sectors successfully transferred
+        ADD     DX,AX           ;First sector number to retry
+        PUSH    DX
+        MUL     [BP.SECSIZ]     ;Number of bytes transferred
+        POP     DX
+        ADD     BX,AX           ;First address for retry
+        MOV     AH,0            ;Flag disk section in error
+        CMP     DX,[BP.FIRFAT]  ;In reserved area?
+        JB      ERRINT
+        INC     AH              ;Flag for FAT
+        CMP     DX,[BP.FIRDIR]  ;In FAT?
+        JB      ERRINT
+        INC     AH
+        CMP     DX,[BP.FIRREC]  ;In directory?
+        JB      ERRINT
+        INC     AH              ;Must be in data area
+ERRINT:
+        SHL     AH,1            ;Make room for read/write bit
+        OR      AH,CS:[READOP]
+FATAL:
+        MOV     AL,[BP.DRVNUM]  ;Get drive number
+FATAL1:
+        PUSH    BP              ;The only thing we preserve
+        MOV     CS:[CONTSTK],SP
+        CLI                     ;Prepare to play with stack
+        MOV     SS,CS:[SSSAVE]
+        MOV     SP,CS:[SPSAVE]  ;User stack pointer restored
+        INT     24H             ;Fatal error interrupt vector
+        MOV     CS:[SPSAVE],SP
+        MOV     CS:[SSSAVE],SS
+        MOV     SP,CS
+        MOV     SS,SP
+        MOV     SP,CS:[CONTSTK]
+        STI
+        POP     BP
+        CMP     AL,2
+        JZ      ERROR
+        RET
+
+DSKREAD:
+        MOV     AL,[BP.DEVNUM]
+        PUSH    BP
+        PUSH    BX
+        PUSH    CX
+        PUSH    DX
+        CALL    FAR PTR BIOSREAD 
+        POP     DX
+        POP     DI
+        POP     BX
+        POP     BP
+RET9:   RET
+
+
+CHKDIRWRITE:
+        TEST    BYTE PTR [DIRTYDIR],-1
+        JZ      RET9
+
+DIRWRITE:
+
+; Inputs:
+;       DS = CS
+;       AL = Directory block number
+;       BP = Base of drive parameters
+; Function:
+;       Write the directory block into DIRBUF.
+; Outputs:
+;       BP unchanged
+; All other registers destroyed.
+
+        MOV     BYTE PTR [DIRTYDIR],0
+        MOV     AL,BYTE PTR [DIRBUFID]
+        CALL    DIRCOMP
+
+
+DWRITE:
+
+; Inputs:
+;       BX,DS = Transfer address
+;       CX = Number of sectors
+;       DX = Absolute record number
+;       BP = Base of drive parameters
+; Function:
+;       Calls BIOS to perform disk write. If BIOS reports
+;       errors, will call HARDERR for further action.
+; BP preserved. All other registers destroyed.
+
+        MOV     AL,[BP.DEVNUM]
+        MOV     AH,CS:VERFLG
+        PUSH    BP
+        PUSH    BX
+        PUSH    CX
+        PUSH    DX
+        CALL    FAR PTR BIOSWRITE 
+        POP     DX
+        POP     DI
+        POP     BX
+        POP     BP
+        JNC     RET9
+        MOV     CS:BYTE PTR [READOP],1
+        CALL    HARDERR
+        CMP     AL,1            ;Check for retry
+        JZ      DWRITE
+        RET
+
+
+ABORT:
+        LDS     SI,CS:DWORD PTR [SPSAVE]
+        MOV     DS,[SI.CSSAVE]
+        XOR     AX,AX
+        MOV     ES,AX
+        MOV     SI,SAVEXIT
+        MOV     DI,EXIT
+        MOVSW
+        MOVSW
+        MOVSW
+        MOVSW
+        MOVSW
+        MOVSW
+ERROR:
+        MOV     AX,CS
+        MOV     DS,AX
+        MOV     ES,AX
+        CALL    WRTFATS
+        XOR     AX,AX
+        CLI
+        MOV     SS,[SSSAVE]
+        MOV     SP,[SPSAVE]
+        MOV     DS,AX
+        MOV     SI,EXIT
+        MOV     DI,OFFSET DOSGROUP:EXITHOLD
+        MOVSW
+        MOVSW
+        POP     AX
+        POP     BX
+        POP     CX
+        POP     DX
+        POP     SI
+        POP     DI
+        POP     BP
+        POP     DS
+        POP     ES
+        STI             ;Stack OK now
+        JMP     CS:DWORD PTR [EXITHOLD]
+
+
+SEQRD:  ;System call 20
+        CALL    GETREC
+        CALL    LOAD
+        JMP     SHORT FINSEQ
+
+SEQWRT: ;System call 21
+        CALL    GETREC
+        CALL    STORE
+FINSEQ:
+        JCXZ    SETNREX
+        ADD     AX,1
+        ADC     DX,0
+        JMP     SHORT SETNREX
+
+RNDRD:  ;System call 33
+        CALL    GETRRPOS1
+        CALL    LOAD
+        JMP     SHORT FINRND
+
+RNDWRT: ;System call 34
+        CALL    GETRRPOS1
+        CALL    STORE
+        JMP     SHORT FINRND
+
+BLKRD:  ;System call 39
+        CALL    GETRRPOS
+        CALL    LOAD
+        JMP     SHORT FINBLK
+
+BLKWRT: ;System call 40
+        CALL    GETRRPOS
+        CALL    STORE
+FINBLK:
+        LDS     SI,DWORD PTR [SPSAVE]
+        MOV     [SI.CXSAVE],CX
+        JCXZ    FINRND
+        ADD     AX,1
+        ADC     DX,0
+FINRND:
+        MOV     ES:WORD PTR [DI.RR],AX
+        MOV     ES:[DI.RR+2],DL
+        OR      DH,DH
+        JZ      SETNREX
+        MOV     ES:[DI.RR+3],DH ;Save 4 byte of RECPOS only if significant
+SETNREX:
+        MOV     CX,AX
+        AND     AL,7FH
+        MOV     ES:[DI.NR],AL
+        AND     CL,80H
+        SHL     CX,1
+        RCL     DX,1
+        MOV     AL,CH
+        MOV     AH,DL
+        MOV     ES:[DI.EXTENT],AX
+        MOV     AL,CS:[DSKERR]
+        RET
+
+GETRRPOS1:
+        MOV     CX,1
+GETRRPOS:
+        MOV     DI,DX
+        CMP     BYTE PTR [DI],-1
+        JNZ     NORMFCB1
+        ADD     DI,7
+NORMFCB1:
+        MOV     AX,WORD PTR [DI.RR]
+        MOV     DX,WORD PTR [DI.RR+2]
+        RET
+
+NOFILERR:
+        XOR     CX,CX
+        MOV     BYTE PTR [DSKERR],4
+        POP     BX
+        RET
+
+SETUP:
+
+; Inputs:
+;       DS:DI point to FCB
+;       DX:AX = Record position in file of disk transfer
+;       CX = Record count
+; Outputs:
+;       DS = CS
+;       ES:DI point to FCB
+;       BL = DEVID from FCB
+;       CX = No. of bytes to transfer
+;       BP = Base of drive parameters
+;       SI = FAT pointer
+;       [RECCNT] = Record count
+;       [RECPOS] = Record position in file
+;       [FCB] = DI
+;       [NEXTADD] = Displacement of disk transfer within segment
+;       [SECPOS] = Position of first sector
+;       [BYTPOS] = Byte position in file
+;       [BYTSECPOS] = Byte position in first sector
+;       [CLUSNUM] = First cluster
+;       [SECCLUSPOS] = Sector within first cluster
+;       [DSKERR] = 0 (no errors yet)
+;       [TRANS] = 0 (No transfers yet)
+;       [THISDRV] = Physical drive unit number
+; If SETUP detects no records will be transfered, it returns 1 level up 
+; with CX = 0.
+
+        PUSH    AX
+        MOV     AL,[DI]
+        DEC     AL
+        MOV     CS:[THISDRV],AL
+        MOV     AL,[DI.DEVID]
+        MOV     SI,[DI.RECSIZ]
+        OR      SI,SI
+        JNZ     HAVRECSIZ
+        MOV     SI,128
+        MOV     [DI.RECSIZ],SI
+HAVRECSIZ:
+        PUSH    DS
+        POP     ES              ;Set ES to DS
+        PUSH    CS
+        POP     DS              ;Set DS to CS
+        OR      AL,AL           ;Is it a device?
+        JNS     NOTDEVICE
+        MOV     AL,0            ;Fake in drive 0 so we can get SP
+NOTDEVICE:
+        CALL    GETBP
+        POP     AX
+        JC      NOFILERR
+        CMP     SI,64           ;Check if highest byte of RECPOS is significant
+        JB      SMALREC
+        MOV     DH,0            ;Ignore MSB if record >= 64 bytes
+SMALREC:
+        MOV     [RECCNT],CX
+        MOV     WORD PTR [RECPOS],AX
+        MOV     WORD PTR [RECPOS+2],DX
+        MOV     [FCB],DI
+        MOV     BX,[DMAADD]
+        MOV     [NEXTADD],BX
+        MOV     BYTE PTR [DSKERR],0
+        MOV     BYTE PTR [TRANS],0
+        MOV     BX,DX
+        MUL     SI
+        MOV     WORD PTR [BYTPOS],AX
+        PUSH    DX
+        MOV     AX,BX
+        MUL     SI
+        POP     BX
+        ADD     AX,BX
+        ADC     DX,0            ;Ripple carry
+        JNZ     EOFERR
+        MOV     WORD PTR [BYTPOS+2],AX
+        MOV     DX,AX
+        MOV     AX,WORD PTR [BYTPOS]
+        MOV     BX,[BP.SECSIZ]
+        CMP     DX,BX           ;See if divide will overflow
+        JNC     EOFERR
+        DIV     BX
+        MOV     [SECPOS],AX
+        MOV     [BYTSECPOS],DX
+        MOV     DX,AX
+        AND     AL,[BP.CLUSMSK]
+        MOV     [SECCLUSPOS],AL
+        MOV     AX,CX           ;Record count
+        MOV     CL,[BP.CLUSSHFT]
+        SHR     DX,CL
+        MOV     [CLUSNUM],DX
+        MUL     SI              ;Multiply by bytes per record
+        MOV     CX,AX
+        ADD     AX,[DMAADD]     ;See if it will fit in one segment
+        ADC     DX,0
+        JZ      OK              ;Must be less than 64K
+        MOV     AX,[DMAADD]
+        NEG     AX              ;Amount of room left in segment
+        JNZ     PARTSEG         ;All 64K available?
+        DEC     AX              ;If so, reduce by one
+PARTSEG:
+        XOR     DX,DX
+        DIV     SI              ;How many records will fit?
+        MOV     [RECCNT],AX
+        MUL     SI              ;Translate that back into bytes
+        MOV     BYTE PTR [DSKERR],2     ;Flag that trimming took place
+        MOV     CX,AX
+        JCXZ    NOROOM
+OK:
+        MOV     BL,ES:[DI.DEVID]
+        MOV     SI,[BP.FAT]
+        RET
+
+EOFERR:
+        MOV     BYTE PTR [DSKERR],1
+        XOR     CX,CX
+NOROOM:
+        POP     BX              ;Kill return address
+        RET
+
+BREAKDOWN:
+
+;Inputs:
+;       DS = CS
+;       CX = Length of disk transfer in bytes
+;       BP = Base of drive parameters
+;       [BYTSECPOS] = Byte position witin first sector
+;Outputs:
+;       [BYTCNT1] = Bytes to transfer in first sector
+;       [SECCNT] = No. of whole sectors to transfer
+;       [BYTCNT2] = Bytes to transfer in last sector
+;AX, BX, DX destroyed. No other registers affected.
+
+        MOV     AX,[BYTSECPOS]
+        MOV     BX,CX
+        OR      AX,AX
+        JZ      SAVFIR          ;Partial first sector?
+        SUB     AX,[BP.SECSIZ]
+        NEG     AX              ;Max number of bytes left in first sector
+        SUB     BX,AX           ;Subtract from total length
+        JAE     SAVFIR
+        ADD     AX,BX           ;Don't use all of the rest of the sector
+        XOR     BX,BX           ;And no bytes are left
+SAVFIR:
+        MOV     [BYTCNT1],AX
+        MOV     AX,BX
+        XOR     DX,DX
+        DIV     [BP.SECSIZ]     ;How many whole sectors?
+        MOV     [SECCNT],AX
+        MOV     [BYTCNT2],DX    ;Bytes remaining for last sector
+RET10:  RET
+
+
+FNDCLUS:
+
+; Inputs:
+;       DS = CS
+;       CX = No. of clusters to skip
+;       BP = Base of drive parameters
+;       SI = FAT pointer
+;       ES:DI point to FCB
+; Outputs:
+;       BX = Last cluster skipped to
+;       CX = No. of clusters remaining (0 unless EOF)
+;       DX = Position of last cluster
+; DI destroyed. No other registers affected.
+
+        MOV     BX,ES:[DI.LSTCLUS]
+        MOV     DX,ES:[DI.CLUSPOS]
+        OR      BX,BX
+        JZ      NOCLUS
+        SUB     CX,DX
+        JNB     FINDIT
+        ADD     CX,DX
+        XOR     DX,DX
+        MOV     BX,ES:[DI.FIRCLUS]
+FINDIT:
+        JCXZ    RET10
+SKPCLP:
+        CALL    UNPACK
+        CMP     DI,0FF8H
+        JAE     RET10
+        XCHG    BX,DI
+        INC     DX
+        LOOP    SKPCLP
+        RET
+NOCLUS:
+        INC     CX
+        DEC     DX
+        RET
+
+
+BUFSEC:
+; Inputs:
+;       AL = 0 if buffer must be read, 1 if no pre-read needed
+;       BP = Base of drive parameters
+;       [CLUSNUM] = Physical cluster number
+;       [SECCLUSPOS] = Sector position of transfer within cluster
+;       [BYTCNT1] = Size of transfer
+; Function:
+;       Insure specified sector is in buffer, flushing buffer before
+;       read if necessary.
+; Outputs:
+;       SI = Pointer to buffer
+;       DI = Pointer to transfer address
+;       CX = Number of bytes
+;       [NEXTADD] updated
+;       [TRANS] set to indicate a transfer will occur
+
+        MOV     DX,[CLUSNUM]
+        MOV     BL,[SECCLUSPOS]
+        CALL    FIGREC
+        MOV     [PREREAD],AL
+        CMP     DX,[BUFSECNO]
+        JNZ     GETSEC
+        MOV     AL,[BUFDRVNO]
+        CMP     AL,[THISDRV]
+        JZ      FINBUF          ;Already have it?
+GETSEC:
+        XOR     AL,AL
+        XCHG    [DIRTYBUF],AL   ;Read dirty flag and reset it
+        OR      AL,AL
+        JZ      RDSEC
+        PUSH    DX
+        PUSH    BP
+        MOV     BP,[BUFDRVBP]
+        MOV     BX,[BUFFER]
+        MOV     CX,1
+        MOV     DX,[BUFSECNO]
+        CALL    DWRITE
+        POP     BP
+        POP     DX
+RDSEC:
+        TEST    BYTE PTR [PREREAD],-1
+        JNZ     SETBUF
+        XOR     AX,AX
+        MOV     [BUFSECNO],AX           ;Set buffer valid in case of disk error
+        DEC     AX
+        MOV     [BUFDRVNO],AL
+        MOV     BX,[BUFFER]
+        MOV     CX,1
+        PUSH    DX
+        CALL    DREAD
+        POP     DX
+SETBUF:
+        MOV     [BUFSECNO],DX
+        MOV     AL,[THISDRV]
+        MOV     [BUFDRVNO],AL
+        MOV     [BUFDRVBP],BP
+FINBUF:
+        MOV     BYTE PTR [TRANS],1      ;A transfer is taking place
+        MOV     DI,[NEXTADD]
+        MOV     SI,DI
+        MOV     CX,[BYTCNT1]
+        ADD     SI,CX
+        MOV     [NEXTADD],SI
+        MOV     SI,[BUFFER]
+        ADD     SI,[BYTSECPOS]
+        RET
+
+BUFRD:
+        XOR     AL,AL           ;Pre-read necessary
+        CALL    BUFSEC
+        PUSH    ES
+        MOV     ES,[DMAADD+2]
+        SHR     CX,1
+        JNC     EVENRD
+        MOVSB
+EVENRD:
+        REP     MOVSW
+        POP     ES
+        RET
+
+BUFWRT:
+        MOV     AX,[SECPOS]
+        INC     AX              ;Set for next sector
+        MOV     [SECPOS],AX
+        CMP     AX,[VALSEC]     ;Has sector been written before?
+        MOV     AL,1
+        JA      NOREAD          ;Skip preread if SECPOS>VALSEC
+        MOV     AL,0
+NOREAD:
+        CALL    BUFSEC
+        XCHG    DI,SI
+        PUSH    DS
+        PUSH    ES
+        PUSH    CS
+        POP     ES
+        MOV     DS,[DMAADD+2]
+        SHR     CX,1
+        JNC     EVENWRT
+        MOVSB
+EVENWRT:
+        REP     MOVSW
+        POP     ES
+        POP     DS
+        MOV     BYTE PTR [DIRTYBUF],1
+        RET
+
+NEXTSEC:
+        TEST    BYTE PTR [TRANS],-1
+        JZ      CLRET
+        MOV     AL,[SECCLUSPOS]
+        INC     AL
+        CMP     AL,[BP.CLUSMSK]
+        JBE     SAVPOS
+        MOV     BX,[CLUSNUM]
+        CMP     BX,0FF8H
+        JAE     NONEXT
+        MOV     SI,[BP.FAT]
+        CALL    UNPACK
+        MOV     [CLUSNUM],DI
+        INC     [LASTPOS]
+        MOV     AL,0
+SAVPOS:
+        MOV     [SECCLUSPOS],AL
+CLRET:
+        CLC
+        RET
+NONEXT:
+        STC
+        RET
+
+TRANBUF:
+        LODSB
+        STOSB
+        CMP     AL,13           ;Check for carriage return
+        JNZ     NORMCH
+        MOV     BYTE PTR [SI],10
+NORMCH:
+        CMP     AL,10
+        LOOPNZ  TRANBUF
+        JNZ     ENDRDCON
+        CALL    OUT             ;Transmit linefeed
+        XOR     SI,SI
+        OR      CX,CX
+        JNZ     GETBUF
+        OR      AL,1            ;Clear zero flag--not end of file
+ENDRDCON:
+        MOV     [CONTPOS],SI
+ENDRDDEV:
+        MOV     [NEXTADD],DI
+        POP     ES
+        JNZ     SETFCBJ         ;Zero set if Ctrl-Z found in input
+        MOV     DI,[FCB]
+        AND     ES:BYTE PTR [DI.DEVID],0FFH-40H ;Mark as no more data available
+SETFCBJ:
+        JMP     SETFCB
+
+READDEV:
+        PUSH    ES
+        LES     DI,DWORD PTR [DMAADD]
+        INC     BL
+        JZ      READCON
+        INC     BL
+        JNZ     ENDRDDEV
+READAUX:
+        CALL    AUXIN
+        STOSB
+        CMP     AL,1AH
+        LOOPNZ  READAUX
+        JMP     SHORT ENDRDDEV
+
+READCON:
+        PUSH    CS
+        POP     DS
+        MOV     SI,[CONTPOS]
+        OR      SI,SI
+        JNZ     TRANBUF
+        CMP     BYTE PTR [CONBUF],128
+        JZ      GETBUF
+        MOV     WORD PTR [CONBUF],0FF80H        ;Set up 128-byte buffer with no template
+GETBUF:
+        PUSH    CX
+        PUSH    ES
+        PUSH    DI
+        MOV     DX,OFFSET DOSGROUP:CONBUF
+        CALL    BUFIN           ;Get input buffer
+        POP     DI
+        POP     ES
+        POP     CX
+        MOV     SI,2 + OFFSET DOSGROUP:CONBUF
+        CMP     BYTE PTR [SI],1AH       ;Check for Ctrl-Z in first character
+        JNZ     TRANBUF
+        MOV     AL,1AH
+        STOSB
+        MOV     AL,10
+        CALL    OUT             ;Send linefeed
+        XOR     SI,SI
+        JMP     SHORT ENDRDCON
+
+RDERR:
+        XOR     CX,CX
+        JMP     WRTERR
+
+RDLASTJ:JMP     RDLAST
+
+LOAD:
+
+; Inputs:
+;       DS:DI point to FCB
+;       DX:AX = Position in file to read
+;       CX = No. of records to read
+; Outputs:
+;       DX:AX = Position of last record read
+;       CX = No. of bytes read
+;       ES:DI point to FCB
+;       LSTCLUS, CLUSPOS fields in FCB set
+
+        CALL    SETUP
+        OR      BL,BL           ;Check for named device I/O
+        JS      READDEV
+        MOV     AX,ES:WORD PTR [DI.FILSIZ]
+        MOV     BX,ES:WORD PTR [DI.FILSIZ+2]
+        SUB     AX,WORD PTR [BYTPOS]
+        SBB     BX,WORD PTR [BYTPOS+2]
+        JB      RDERR
+        JNZ     ENUF
+        OR      AX,AX
+        JZ      RDERR
+        CMP     AX,CX
+        JAE     ENUF
+        MOV     CX,AX
+ENUF:
+        CALL    BREAKDOWN
+        MOV     CX,[CLUSNUM]
+        CALL    FNDCLUS
+        OR      CX,CX
+        JNZ     RDERR
+        MOV     [LASTPOS],DX
+        MOV     [CLUSNUM],BX
+        CMP     [BYTCNT1],0
+        JZ      RDMID
+        CALL    BUFRD
+RDMID:
+        CMP     [SECCNT],0
+        JZ      RDLASTJ
+        CALL    NEXTSEC
+        JC      SETFCB
+        MOV     BYTE PTR [TRANS],1      ;A transfer is taking place
+ONSEC:
+        MOV     DL,[SECCLUSPOS]
+        MOV     CX,[SECCNT]
+        MOV     BX,[CLUSNUM]
+RDLP:
+        CALL    OPTIMIZE
+        PUSH    DI
+        PUSH    AX
+        PUSH    DS
+        MOV     DS,[DMAADD+2]
+        PUSH    DX
+        PUSH    BX
+        PUSHF                   ;Save carry flag
+        CALL DREAD
+        POPF                    ;Restore carry flag
+        POP     DI              ;Initial transfer address
+        POP     AX              ;First sector transfered
+        POP     DS
+        JC      NOTBUFFED       ;Was one of those sectors in the buffer?
+        CMP     BYTE PTR [DIRTYBUF],0   ;Is buffer dirty?
+        JZ      NOTBUFFED       ;If not no problem
+;We have transfered in a sector from disk when a dirty copy of it is in the buffer.
+;We must transfer the sector from the buffer to correct memory address
+        SUB     AX,[BUFSECNO]   ;How many sectors into the transfer?
+        NEG     AX
+        MOV     CX,[BP.SECSIZ]
+        MUL     CX              ;How many bytes into the transfer?
+        ADD     DI,AX
+        MOV     SI,[BUFFER]
+        PUSH    ES
+        MOV     ES,[DMAADD+2]   ;Get disk transfer segment
+        SHR     CX,1
+        REP     MOVSW
+        JNC     EVENMOV
+        MOVSB
+EVENMOV:
+        POP     ES
+NOTBUFFED:
+        POP     CX
+        POP     BX
+        JCXZ    RDLAST
+        CMP     BX,0FF8H
+        JAE     SETFCB
+        MOV     DL,0
+        INC     [LASTPOS]       ;We'll be using next cluster
+        JMP     SHORT RDLP
+
+SETFCB:
+        MOV     SI,[FCB]
+        MOV     AX,[NEXTADD]
+        MOV     DI,AX
+        SUB     AX,[DMAADD]     ;Number of bytes transfered
+        XOR     DX,DX
+        MOV     CX,ES:[SI.RECSIZ]
+        DIV     CX              ;Number of records
+        CMP     AX,[RECCNT]     ;Check if all records transferred
+        JZ      FULLREC
+        MOV     BYTE PTR [DSKERR],1
+        OR      DX,DX
+        JZ      FULLREC         ;If remainder 0, then full record transfered
+        MOV     BYTE PTR [DSKERR],3     ;Flag partial last record
+        SUB     CX,DX           ;Bytes left in last record
+        PUSH    ES
+        MOV     ES,[DMAADD+2]
+        XCHG    AX,BX           ;Save the record count temporarily
+        XOR     AX,AX           ;Fill with zeros
+        SHR     CX,1
+        JNC     EVENFIL
+        STOSB
+EVENFIL:
+        REP     STOSW
+        XCHG    AX,BX           ;Restore record count to AX
+        POP     ES
+        INC     AX              ;Add last (partial) record to total
+FULLREC:
+        MOV     CX,AX
+        MOV     DI,SI           ;ES:DI point to FCB
+SETCLUS:
+        MOV     AX,[CLUSNUM]
+        MOV     ES:[DI.LSTCLUS],AX
+        MOV     AX,[LASTPOS]
+        MOV     ES:[DI.CLUSPOS],AX
+ADDREC:
+        MOV     AX,WORD PTR [RECPOS]
+        MOV     DX,WORD PTR [RECPOS+2]
+        JCXZ    RET28           ;If no records read, don't change position
+        DEC     CX
+        ADD     AX,CX           ;Update current record position
+        ADC     DX,0
+        INC     CX      
+RET28:  RET
+
+RDLAST:
+        MOV     AX,[BYTCNT2]
+        OR      AX,AX
+        JZ      SETFCB
+        MOV     [BYTCNT1],AX
+        CALL    NEXTSEC
+        JC      SETFCB
+        MOV     [BYTSECPOS],0
+        CALL    BUFRD
+        JMP     SHORT SETFCB
+
+WRTDEV:
+        PUSH    DS
+        LDS     SI,DWORD PTR [DMAADD]
+        OR      BL,40H
+        INC     BL
+        JZ      WRTCON
+        INC     BL
+        JZ      WRTAUX
+        INC     BL
+        JZ      ENDWRDEV        ;Done if device is NUL
+WRTLST:
+        LODSB
+        CMP     AL,1AH
+        JZ      ENDWRDEV
+        CALL    LISTOUT
+        LOOP    WRTLST
+        JMP     SHORT ENDWRDEV
+
+WRTAUX:
+        LODSB
+        CALL    AUXOUT
+        CMP     AL,1AH
+        LOOPNZ  WRTAUX
+        JMP     SHORT ENDWRDEV
+
+WRTCON:
+        LODSB
+        CMP     AL,1AH
+        JZ      ENDWRDEV
+        CALL    OUT
+        LOOP    WRTCON
+ENDWRDEV:
+        POP     DS
+        MOV     CX,[RECCNT]
+        MOV     DI,[FCB]
+        JMP     SHORT ADDREC
+
+HAVSTART:
+        MOV     CX,AX
+        CALL    SKPCLP
+        JCXZ    DOWRTJ
+        CALL    ALLOCATE
+        JNC     DOWRTJ
+WRTERR:
+        MOV     BYTE PTR [DSKERR],1
+LVDSK:
+        MOV     AX,WORD PTR [RECPOS]
+        MOV     DX,WORD PTR [RECPOS+2]
+        MOV     DI,[FCB]
+        RET
+
+DOWRTJ: JMP     DOWRT
+
+WRTEOFJ:
+        JMP     WRTEOF
+
+STORE:
+
+; Inputs:
+;       DS:DI point to FCB
+;       DX:AX = Position in file of disk transfer
+;       CX = Record count
+; Outputs:
+;       DX:AX = Position of last record written
+;       CX = No. of records written
+;       ES:DI point to FCB
+;       LSTCLUS, CLUSPOS fields in FCB set
+
+        CALL    SETUP
+        CALL    DATE16
+        MOV     ES:[DI.FDATE],AX
+        MOV     ES:[DI.FTIME],DX
+        OR      BL,BL
+        JS      WRTDEV
+        AND     BL,3FH          ;Mark file as dirty
+        MOV     ES:[DI.DEVID],BL
+        CALL    BREAKDOWN
+        MOV     AX,WORD PTR [BYTPOS]
+        MOV     DX,WORD PTR [BYTPOS+2]
+        JCXZ    WRTEOFJ
+        DEC     CX
+        ADD     AX,CX
+        ADC     DX,0            ;AX:DX=last byte accessed
+        DIV     [BP.SECSIZ]     ;AX=last sector accessed
+        MOV     CL,[BP.CLUSSHFT]
+        SHR     AX,CL           ;Last cluster to be accessed
+        PUSH    AX
+        MOV     AX,ES:WORD PTR [DI.FILSIZ]
+        MOV     DX,ES:WORD PTR [DI.FILSIZ+2]
+        DIV     [BP.SECSIZ]
+        OR      DX,DX
+        JZ      NORNDUP
+        INC     AX              ;Round up if any remainder
+NORNDUP:
+        MOV     [VALSEC],AX     ;Number of sectors that have been written
+        POP     AX
+        MOV     CX,[CLUSNUM]    ;First cluster accessed
+        CALL    FNDCLUS
+        MOV     [CLUSNUM],BX
+        MOV     [LASTPOS],DX
+        SUB     AX,DX           ;Last cluster minus current cluster
+        JZ      DOWRT           ;If we have last clus, we must have first
+        JCXZ    HAVSTART        ;See if no more data
+        PUSH    CX              ;No. of clusters short of first
+        MOV     CX,AX
+        CALL    ALLOCATE
+        POP     AX
+        JC      WRTERR
+        MOV     CX,AX
+        MOV     DX,[LASTPOS]
+        INC     DX
+        DEC     CX
+        JZ      NOSKIP
+        CALL    SKPCLP
+NOSKIP:
+        MOV     [CLUSNUM],BX
+        MOV     [LASTPOS],DX
+DOWRT:
+        CMP     [BYTCNT1],0
+        JZ      WRTMID
+        MOV     BX,[CLUSNUM]
+        CALL    BUFWRT  
+WRTMID:
+        MOV     AX,[SECCNT]
+        OR      AX,AX
+        JZ      WRTLAST
+        ADD     [SECPOS],AX
+        CALL    NEXTSEC
+        MOV     BYTE PTR [TRANS],1      ;A transfer is taking place
+        MOV     DL,[SECCLUSPOS]
+        MOV     BX,[CLUSNUM]
+        MOV     CX,[SECCNT]
+WRTLP:
+        CALL    OPTIMIZE
+        JC      NOTINBUF        ;Is one of the sectors buffered?
+        MOV     [BUFSECNO],0    ;If so, invalidate the buffer since we're
+        MOV     WORD PTR [BUFDRVNO],0FFH        ;       completely rewritting it
+NOTINBUF:
+        PUSH    DI
+        PUSH    AX
+        PUSH    DS
+        MOV     DS,[DMAADD+2]
+        CALL    DWRITE
+        POP     DS
+        POP     CX
+        POP     BX
+        JCXZ    WRTLAST
+        MOV     DL,0
+        INC     [LASTPOS]       ;We'll be using next cluster
+        JMP     SHORT WRTLP
+WRTLAST:
+        MOV     AX,[BYTCNT2]
+        OR      AX,AX
+        JZ      FINWRT
+        MOV     [BYTCNT1],AX
+        CALL    NEXTSEC
+        MOV     [BYTSECPOS],0
+        CALL    BUFWRT
+FINWRT:
+        MOV     AX,[NEXTADD]
+        SUB     AX,[DMAADD]
+        ADD     AX,WORD PTR [BYTPOS]
+        MOV     DX,WORD PTR [BYTPOS+2]
+        ADC     DX,0
+        MOV     CX,DX
+        MOV     DI,[FCB]
+        CMP     AX,ES:WORD PTR [DI.FILSIZ]
+        SBB     CX,ES:WORD PTR [DI.FILSIZ+2]
+        JB      SAMSIZ
+        MOV     ES:WORD PTR [DI.FILSIZ],AX
+        MOV     ES:WORD PTR [DI.FILSIZ+2],DX
+SAMSIZ:
+        MOV     CX,[RECCNT]
+        JMP     SETCLUS
+
+
+WRTERRJ:JMP     WRTERR
+
+WRTEOF:
+        MOV     CX,AX
+        OR      CX,DX
+        JZ      KILLFIL
+        SUB     AX,1
+        SBB     DX,0
+        DIV     [BP.SECSIZ]
+        MOV     CL,[BP.CLUSSHFT]
+        SHR     AX,CL
+        MOV     CX,AX
+        CALL    FNDCLUS
+        JCXZ    RELFILE
+        CALL    ALLOCATE
+        JC      WRTERRJ
+UPDATE:
+        MOV     DI,[FCB]
+        MOV     AX,WORD PTR [BYTPOS]
+        MOV     ES:WORD PTR [DI.FILSIZ],AX
+        MOV     AX,WORD PTR [BYTPOS+2]
+        MOV     ES:WORD PTR [DI.FILSIZ+2],AX
+        XOR     CX,CX
+        JMP     ADDREC
+
+RELFILE:
+        MOV     DX,0FFFH
+        CALL    RELBLKS
+SETDIRT:
+        MOV     BYTE PTR [SI-1],1
+        JMP     SHORT UPDATE
+
+KILLFIL:
+        XOR     BX,BX
+        XCHG    BX,ES:[DI.FIRCLUS]
+        OR      BX,BX
+        JZ      UPDATE
+        CALL    RELEASE
+        JMP     SHORT SETDIRT
+
+
+OPTIMIZE:
+
+; Inputs:
+;       DS = CS
+;       BX = Physical cluster
+;       CX = No. of records
+;       DL = sector within cluster
+;       BP = Base of drives parameters
+;       [NEXTADD] = transfer address
+; Outputs:
+;       AX = No. of records remaining
+;       BX = Transfer address
+;       CX = No. or records to be transferred
+;       DX = Physical sector address
+;       DI = Next cluster
+;       Carry clear if a sector to transfer is in the buffer
+;       Carry set otherwise
+;       [CLUSNUM] = Last cluster accessed
+;       [NEXTADD] updated
+; BP unchanged. Note that segment of transfer not set.
+
+        PUSH    DX
+        PUSH    BX
+        MOV     AL,[BP.CLUSMSK]
+        INC     AL              ;Number of sectors per cluster
+        MOV     AH,AL
+        SUB     AL,DL           ;AL = Number of sectors left in first cluster
+        MOV     DX,CX
+        MOV     SI,[BP.FAT]
+        MOV     CX,0
+OPTCLUS:
+;AL has number of sectors available in current cluster
+;AH has number of sectors available in next cluster
+;BX has current physical cluster
+;CX has number of sequential sectors found so far
+;DX has number of sectors left to transfer
+;SI has FAT pointer
+        CALL    UNPACK
+        ADD     CL,AL
+        ADC     CH,0
+        CMP     CX,DX
+        JAE     BLKDON
+        MOV     AL,AH
+        INC     BX
+        CMP     DI,BX
+        JZ      OPTCLUS
+        DEC     BX
+FINCLUS:
+        MOV     [CLUSNUM],BX    ;Last cluster accessed
+        SUB     DX,CX           ;Number of sectors still needed
+        PUSH    DX
+        MOV     AX,CX
+        MUL     [BP.SECSIZ]     ;Number of sectors times sector size
+        MOV     SI,[NEXTADD]
+        ADD     AX,SI           ;Adjust by size of transfer
+        MOV     [NEXTADD],AX
+        POP     AX              ;Number of sectors still needed
+        POP     DX              ;Starting cluster
+        SUB     BX,DX           ;Number of new clusters accessed
+        ADD     [LASTPOS],BX
+        POP     BX              ;BL = sector postion within cluster
+        CALL    FIGREC
+        MOV     BX,SI
+;Now let's see if any of these sectors are already in the buffer
+        CMP     [BUFSECNO],DX
+        JC      RET100          ;If DX > [BUFSECNO] then not in buffer
+        MOV     SI,DX
+        ADD     SI,CX           ;Last sector + 1
+        CMP     [BUFSECNO],SI
+        CMC
+        JC      RET100          ;If SI <= [BUFSECNO] then not in buffer
+        PUSH    AX
+        MOV     AL,[BP.DEVNUM]
+        CMP     AL,[BUFDRVNO]   ;Is buffer for this drive?
+        POP     AX
+        JZ      RET100          ;If so, then we match 
+        STC                     ;No match
+RET100: RET
+BLKDON:
+        SUB     CX,DX           ;Number of sectors in cluster we don't want
+        SUB     AH,CL           ;Number of sectors in cluster we accepted
+        DEC     AH              ;Adjust to mean position within cluster
+        MOV     [SECCLUSPOS],AH
+        MOV     CX,DX           ;Anyway, make the total equal to the request
+        JMP     SHORT FINCLUS
+
+
+FIGREC:
+
+;Inputs:
+;       DX = Physical cluster number
+;       BL = Sector postion within cluster
+;       BP = Base of drive parameters
+;Outputs:
+;       DX = physical sector number
+;No other registers affected.
+
+        PUSH    CX
+        MOV     CL,[BP.CLUSSHFT]
+        DEC     DX
+        DEC     DX
+        SHL     DX,CL
+        OR      DL,BL
+        ADD     DX,[BP.FIRREC]
+        POP     CX
+        RET
+
+GETREC:
+
+; Inputs:
+;       DS:DX point to FCB
+; Outputs:
+;       CX = 1
+;       DX:AX = Record number determined by EXTENT and NR fields
+;       DS:DI point to FCB
+; No other registers affected.
+
+        MOV     DI,DX
+        CMP     BYTE PTR [DI],-1        ;Check for extended FCB
+        JNZ     NORMFCB2
+        ADD     DI,7
+NORMFCB2:
+        MOV     CX,1
+        MOV     AL,[DI.NR]
+        MOV     DX,[DI.EXTENT]
+        SHL     AL,1
+        SHR     DX,1
+        RCR     AL,1
+        MOV     AH,DL
+        MOV     DL,DH
+        MOV     DH,0
+        RET
+
+
+ALLOCATE:
+
+; Inputs:
+;       DS = CS
+;       ES = Segment of FCB
+;       BX = Last cluster of file (0 if null file)
+;       CX = No. of clusters to allocate
+;       DX = Position of cluster BX
+;       BP = Base of drive parameters
+;       SI = FAT pointer
+;       [FCB] = Displacement of FCB within segment
+; Outputs:
+;       IF insufficient space
+;         THEN
+;       Carry set
+;       CX = max. no. of records that could be added to file
+;         ELSE
+;       Carry clear
+;       BX = First cluster allocated
+;       FAT is fully updated including dirty bit
+;       FIRCLUS field of FCB set if file was null
+; SI,BP unchanged. All other registers destroyed.
+
+        PUSH    [SI]
+        PUSH    DX
+        PUSH    CX
+        PUSH    BX
+        MOV     AX,BX
+ALLOC:
+        MOV     DX,BX
+FINDFRE:
+        INC     BX
+        CMP     BX,[BP.MAXCLUS]
+        JLE     TRYOUT
+        CMP     AX,1
+        JG      TRYIN
+        POP     BX
+        MOV     DX,0FFFH
+        CALL    RELBLKS
+        POP     AX              ;No. of clusters requested
+        SUB     AX,CX           ;AX=No. of clusters allocated
+        POP     DX
+        POP     [SI]
+        INC     DX              ;Position of first cluster allocated
+        ADD     AX,DX           ;AX=max no. of cluster in file
+        MOV     DL,[BP.CLUSMSK]
+        MOV     DH,0
+        INC     DX              ;DX=records/cluster
+        MUL     DX              ;AX=max no. of records in file
+        MOV     CX,AX
+        SUB     CX,WORD PTR [RECPOS]    ;CX=max no. of records that could be written
+        JA      MAXREC
+        XOR     CX,CX           ;If CX was negative, zero it
+MAXREC:
+        STC
+RET11:  RET
+
+TRYOUT:
+        CALL    UNPACK
+        JZ      HAVFRE
+TRYIN:
+        DEC     AX
+        JLE     FINDFRE
+        XCHG    AX,BX
+        CALL    UNPACK
+        JZ      HAVFRE
+        XCHG    AX,BX
+        JMP     SHORT FINDFRE
+HAVFRE:
+        XCHG    BX,DX
+        MOV     AX,DX
+        CALL    PACK
+        MOV     BX,AX
+        LOOP    ALLOC
+        MOV     DX,0FFFH
+        CALL    PACK
+        MOV     BYTE PTR [SI-1],1
+        POP     BX
+        POP     CX              ;Don't need this stuff since we're successful
+        POP     DX
+        CALL    UNPACK
+        POP     [SI]
+        XCHG    BX,DI
+        OR      DI,DI
+        JNZ     RET11
+        MOV     DI,[FCB]
+        MOV     ES:[DI.FIRCLUS],BX
+RET12:  RET
+
+
+RELEASE:
+
+; Inputs:
+;       DS = CS
+;       BX = Cluster in file
+;       SI = FAT pointer
+;       BP = Base of drive parameters
+; Function:
+;       Frees cluster chain starting with [BX]
+; AX,BX,DX,DI all destroyed. Other registers unchanged.
+
+        XOR     DX,DX
+RELBLKS:
+; Enter here with DX=0FFFH to put an end-of-file mark
+; in the first cluster and free the rest in the chain.
+        CALL    UNPACK
+        JZ      RET12
+        MOV     AX,DI
+        CALL    PACK
+        CMP     AX,0FF8H
+        MOV     BX,AX
+        JB      RELEASE
+RET13:  RET
+
+
+GETEOF:
+
+; Inputs:
+;       BX = Cluster in a file
+;       SI = Base of drive FAT
+;       DS = CS
+; Outputs:
+;       BX = Last cluster in the file
+; DI destroyed. No other registers affected.
+
+        CALL    UNPACK
+        CMP     DI,0FF8H
+        JAE     RET13
+        MOV     BX,DI
+        JMP     SHORT GETEOF
+
+
+SRCHFRST: ;System call 17
+        CALL    GETFILE
+SAVPLCE:
+; Search-for-next enters here to save place and report
+; findings.
+        JC      KILLSRCH
+        OR      BH,BH
+        JS      SRCHDEV
+        MOV     AX,[LASTENT]
+        MOV     ES:[DI.FILDIRENT],AX
+        MOV     ES:[DI.DRVBP],BP
+;Information in directory entry must be copied into the first
+; 33 bytes starting at the disk transfer address.
+        MOV     SI,BX
+        LES     DI,DWORD PTR [DMAADD]
+        MOV     AX,00FFH
+        CMP     AL,[EXTFCB]
+        JNZ     NORMFCB
+        STOSW
+        INC     AL
+        STOSW
+        STOSW
+        MOV     AL,[ATTRIB]
+        STOSB
+NORMFCB:
+        MOV     AL,[THISDRV]
+        INC     AL
+        STOSB   ;Set drive number
+        MOV     CX,16
+        REP     MOVSW   ;Copy remaining 10 characters of name
+        XOR     AL,AL
+        RET
+
+KILLSRCH:
+KILLSRCH1       EQU     KILLSRCH+1
+;The purpose of the KILLSRCH1 label is to provide a jump label to the following
+;   instruction which leaves out the segment override.
+        MOV     WORD PTR ES:[DI.FILDIRENT],-1
+        MOV     AL,-1
+        RET
+
+SRCHDEV:
+        MOV     ES:[DI.FILDIRENT],BX
+        LES     DI,DWORD PTR [DMAADD]
+        XOR     AX,AX
+        STOSB           ;Zero drive byte
+        SUB     SI,4            ;Point to device name
+        MOVSW
+        MOVSW
+        MOV     AX,2020H
+        STOSB
+        STOSW
+        STOSW
+        STOSW                   ;Fill with 8 blanks
+        XOR     AX,AX
+        MOV     CX,10
+        REP     STOSW
+        STOSB
+RET14:  RET
+
+SRCHNXT: ;System call 18
+        CALL    MOVNAME
+        MOV     DI,DX
+        JC      NEAR PTR KILLSRCH1
+        MOV     BP,[DI.DRVBP]
+        MOV     AX,[DI.FILDIRENT]
+        OR      AX,AX
+        JS      NEAR PTR KILLSRCH1
+        PUSH    DX
+        PUSH    DS
+        PUSH    CS
+        POP     DS
+        MOV     [LASTENT],AX
+        CALL    CONTSRCH
+        POP     ES
+        POP     DI
+        JMP     SAVPLCE
+
+
+FILESIZE: ;System call 35
+        CALL    GETFILE
+        MOV     AL,-1
+        JC      RET14
+        ADD     DI,33           ;Write size in RR field
+        MOV     CX,ES:[DI.RECSIZ-33]
+        OR      CX,CX
+        JNZ     RECOK
+        MOV     CX,128
+RECOK:
+        XOR     AX,AX
+        XOR     DX,DX           ;Intialize size to zero
+        OR      BH,BH           ;Check for named I/O device
+        JS      DEVSIZ
+        INC     SI
+        INC     SI              ;Point to length field
+        MOV     AX,[SI+2]       ;Get high word of size
+        DIV     CX
+        PUSH    AX              ;Save high part of result
+        LODSW           ;Get low word of size
+        DIV     CX
+        OR      DX,DX           ;Check for zero remainder
+        POP     DX
+        JZ      DEVSIZ
+        INC     AX              ;Round up for partial record
+        JNZ     DEVSIZ          ;Propagate carry?
+        INC     DX
+DEVSIZ:
+        STOSW
+        MOV     AX,DX
+        STOSB
+        MOV     AL,0
+        CMP     CX,64
+        JAE     RET14           ;Only 3-byte field if RECSIZ >= 64
+        MOV     ES:[DI],AH
+        RET
+
+
+SETDMA: ;System call 26
+        MOV     CS:[DMAADD],DX
+        MOV     CS:[DMAADD+2],DS
+        RET
+
+NOSUCHDRV:
+        MOV     AL,-1
+        RET
+
+GETFATPT: ;System call 27
+        MOV     DL,0                    ;Use default drive
+
+GETFATPTDL:     ;System call 28
+        PUSH    CS
+        POP     DS
+        MOV     AL,DL
+        CALL    GETTHISDRV
+        JC      NOSUCHDRV
+        CALL    FATREAD
+        MOV     BX,[BP.FAT]
+        MOV     AL,[BP.CLUSMSK]
+        INC     AL
+        MOV     DX,[BP.MAXCLUS]
+        DEC     DX
+        MOV     CX,[BP.SECSIZ]
+        LDS     SI,DWORD PTR [SPSAVE]
+        MOV     [SI.BXSAVE],BX
+        MOV     [SI.DXSAVE],DX
+        MOV     [SI.CXSAVE],CX
+        MOV     [SI.DSSAVE],CS
+        RET
+
+
+GETDSKPT: ;System call 31
+        PUSH    CS
+        POP     DS
+        MOV     AL,[CURDRV]
+        MOV     [THISDRV],AL
+        CALL    FATREAD
+        LDS     SI,DWORD PTR [SPSAVE]
+        MOV     [SI.BXSAVE],BP
+        MOV     [SI.DSSAVE],CS
+        RET
+
+
+DSKRESET: ;System call 13
+        PUSH    CS
+        POP     DS
+WRTFATS:
+; DS=CS. Writes back all dirty FATs. All registers destroyed.
+        XOR     AL,AL
+        XCHG    AL,[DIRTYBUF]
+        OR      AL,AL
+        JZ      NOBUF
+        MOV     BP,[BUFDRVBP]
+        MOV     DX,[BUFSECNO]
+        MOV     BX,[BUFFER]
+        MOV     CX,1
+        CALL    DWRITE
+NOBUF:
+        MOV     CL,[NUMIO]
+        MOV     CH,0
+        MOV     BP,[DRVTAB]
+WRTFAT:
+        PUSH    CX
+        CALL    CHKFATWRT
+        POP     CX
+        ADD     BP,DPBSIZ
+        LOOP    WRTFAT
+        RET
+
+
+GETDRV: ;System call 25
+        MOV     AL,CS:[CURDRV]
+RET15:  RET
+
+
+SETRNDREC: ;System call 36
+        CALL    GETREC
+        MOV     [DI+33],AX
+        MOV     [DI+35],DL
+        CMP     [DI.RECSIZ],64
+        JAE     RET15
+        MOV     [DI+36],DH      ;Set 4th byte only if record size < 64
+RET16:  RET
+
+
+SELDSK: ;System call 14
+        MOV     AL,CS:[NUMDRV]
+        CMP     DL,AL
+        JNB     RET17
+        MOV     CS:[CURDRV],DL
+RET17:  RET
+
+BUFIN:  ;System call 10
+        MOV     AX,CS
+        MOV     ES,AX
+        MOV     SI,DX
+        MOV     CH,0
+        LODSW
+        OR      AL,AL
+        JZ      RET17
+        MOV     BL,AH
+        MOV     BH,CH
+        CMP     AL,BL
+        JBE     NOEDIT
+        CMP     BYTE PTR [BX+SI],0DH
+        JZ      EDITON
+NOEDIT:
+        MOV     BL,CH
+EDITON:
+        MOV     DL,AL
+        DEC     DX
+NEWLIN:
+        MOV     AL,CS:[CARPOS]
+        MOV     CS:[STARTPOS],AL
+        PUSH    SI
+        MOV     DI,OFFSET DOSGROUP:INBUF
+        MOV     AH,CH
+        MOV     BH,CH
+        MOV     DH,CH
+GETCH:
+        CALL    IN
+        CMP     AL,"F"-"@"      ;Ignore ^F
+        JZ      GETCH
+        CMP     AL,CS:ESCCHAR
+        JZ      ESC
+        CMP     AL,7FH
+        JZ      BACKSP
+        CMP     AL,8
+        JZ      BACKSP
+        CMP     AL,13
+        JZ      ENDLIN
+        CMP     AL,10
+        JZ      PHYCRLF
+        CMP     AL,CANCEL
+        JZ      KILNEW
+SAVCH:
+        CMP     DH,DL
+        JAE     BUFFUL
+        STOSB
+        INC     DH
+        CALL    BUFOUT
+        OR      AH,AH
+        JNZ     GETCH
+        CMP     BH,BL
+        JAE     GETCH
+        INC     SI
+        INC     BH
+        JMP     SHORT GETCH
+
+BUFFUL:
+        MOV     AL,7
+        CALL    OUT
+        JMP     SHORT GETCH
+
+ESC:
+        CALL    IN
+        MOV     CL,ESCTABLEN
+        PUSH    DI
+        MOV     DI,OFFSET DOSGROUP:ESCTAB
+        REPNE   SCASB
+        POP     DI
+        SHL     CX,1
+        MOV     BP,CX
+        JMP     [BP+OFFSET DOSGROUP:ESCFUNC]
+
+ENDLIN:
+        STOSB
+        CALL    OUT
+        POP     DI
+        MOV     [DI-1],DH
+        INC     DH
+COPYNEW:
+        MOV     BP,ES
+        MOV     BX,DS
+        MOV     ES,BX
+        MOV     DS,BP
+        MOV     SI,OFFSET DOSGROUP:INBUF
+        MOV     CL,DH
+        REP     MOVSB
+        RET
+CRLF:
+        MOV     AL,13
+        CALL    OUT
+        MOV     AL,10
+        JMP     OUT
+
+PHYCRLF:
+        CALL    CRLF
+        JMP     SHORT GETCH
+
+KILNEW:
+        MOV     AL,"\"
+        CALL    OUT
+        POP     SI
+PUTNEW:
+        CALL    CRLF
+        MOV     AL,CS:[STARTPOS]
+        CALL    TAB
+        JMP     NEWLIN
+
+BACKSP:
+        OR      DH,DH
+        JZ      OLDBAK
+        CALL    BACKUP
+        MOV     AL,ES:[DI]
+        CMP     AL," "
+        JAE     OLDBAK
+        CMP     AL,9
+        JZ      BAKTAB
+        CALL    BACKMES
+OLDBAK:
+        OR      AH,AH
+        JNZ     GETCH1
+        OR      BH,BH
+        JZ      GETCH1
+        DEC     BH
+        DEC     SI
+GETCH1:
+        JMP     GETCH
+BAKTAB:
+        PUSH    DI
+        DEC     DI
+        STD
+        MOV     CL,DH
+        MOV     AL," "
+        PUSH    BX
+        MOV     BL,7
+        JCXZ    FIGTAB
+FNDPOS:
+        SCASB
+        JNA     CHKCNT
+        CMP     ES:BYTE PTR [DI+1],9
+        JZ      HAVTAB
+        DEC     BL
+CHKCNT:
+        LOOP    FNDPOS
+FIGTAB:
+        SUB     BL,CS:[STARTPOS]
+HAVTAB:
+        SUB     BL,DH
+        ADD     CL,BL
+        AND     CL,7
+        CLD
+        POP     BX
+        POP     DI
+        JZ      OLDBAK
+TABBAK:
+        CALL    BACKMES
+        LOOP    TABBAK
+        JMP     SHORT OLDBAK
+BACKUP:
+        DEC     DH
+        DEC     DI
+BACKMES:
+        MOV     AL,8
+        CALL    OUT
+        MOV     AL," "
+        CALL    OUT
+        MOV     AL,8
+        JMP     OUT
+
+TWOESC:
+        MOV     AL,ESCCH
+        JMP     SAVCH
+
+COPYLIN:
+        MOV     CL,BL
+        SUB     CL,BH
+        JMP     SHORT COPYEACH
+
+COPYSTR:
+        CALL    FINDOLD
+        JMP     SHORT COPYEACH
+
+COPYONE:
+        MOV     CL,1
+COPYEACH:
+        MOV     AH,0
+        CMP     DH,DL
+        JZ      GETCH2
+        CMP     BH,BL
+        JZ      GETCH2
+        LODSB
+        STOSB
+        CALL    BUFOUT
+        INC     BH
+        INC     DH
+        LOOP    COPYEACH
+GETCH2:
+        JMP     GETCH
+
+SKIPONE:
+        CMP     BH,BL
+        JZ      GETCH2
+        INC     BH
+        INC     SI
+        JMP     GETCH
+
+SKIPSTR:
+        CALL    FINDOLD
+        ADD     SI,CX
+        ADD     BH,CL
+        JMP     GETCH
+
+FINDOLD:
+        CALL    IN
+        MOV     CL,BL
+        SUB     CL,BH
+        JZ      NOTFND
+        DEC     CX
+        JZ      NOTFND
+        PUSH    ES
+        PUSH    DS
+        POP     ES
+        PUSH    DI
+        MOV     DI,SI
+        INC     DI
+        REPNE   SCASB
+        POP     DI
+        POP     ES
+        JNZ     NOTFND
+        NOT     CL
+        ADD     CL,BL
+        SUB     CL,BH
+RET30:  RET
+NOTFND:
+        POP     BP
+        JMP     GETCH
+
+REEDIT:
+        MOV     AL,"@"
+        CALL    OUT
+        POP     DI
+        PUSH    DI
+        PUSH    ES
+        PUSH    DS
+        CALL    COPYNEW
+        POP     DS
+        POP     ES
+        POP     SI
+        MOV     BL,DH
+        JMP     PUTNEW
+
+ENTERINS:
+        IF      TOGLINS
+        NOT     AH
+        JMP     GETCH
+        ENDIF
+        IF      NOT TOGLINS
+        MOV     AH,-1
+        JMP     GETCH
+
+EXITINS:
+        MOV     AH,0
+        JMP     GETCH
+        ENDIF
+
+ESCFUNC DW      GETCH
+        DW      TWOESC
+        IF      NOT TOGLINS
+        DW      EXITINS
+        ENDIF
+        DW      ENTERINS
+        DW      BACKSP
+        DW      REEDIT
+        DW      KILNEW
+        DW      COPYLIN
+        DW      SKIPSTR
+        DW      COPYSTR
+        DW      SKIPONE
+        DW      COPYONE
+
+        IF      IBM
+        DW      COPYONE
+        DW      CTRLZ
+CTRLZ:
+        MOV     AL,"Z"-"@"
+        JMP     SAVCH
+        ENDIF
+BUFOUT:
+        CMP     AL," "
+        JAE     OUT
+        CMP     AL,9
+        JZ      OUT
+        PUSH    AX
+        MOV     AL,"^"
+        CALL    OUT
+        POP     AX
+        OR      AL,40H
+        JMP     SHORT OUT
+
+NOSTOP:
+        CMP     AL,"P"-"@"
+        JZ      INCHK
+        IF      NOT TOGLPRN
+        CMP     AL,"N"-"@"
+        JZ      INCHK
+        ENDIF
+        CMP     AL,"C"-"@"
+        JZ      INCHK
+        RET
+
+CONOUT: ;System call 2
+        MOV     AL,DL
+OUT:
+        CMP     AL,20H
+        JB      CTRLOUT
+        CMP     AL,7FH
+        JZ      OUTCH
+        INC     CS:BYTE PTR [CARPOS]
+OUTCH:
+        PUSH    AX
+        CALL    STATCHK
+        POP     AX
+        CALL    FAR PTR BIOSOUT 
+        TEST    CS:BYTE PTR [PFLAG],-1
+        JZ      RET18
+        CALL    FAR PTR BIOSPRINT 
+RET18:  RET
+
+STATCHK:
+        CALL    FAR PTR BIOSSTAT 
+        JZ      RET18
+        CMP     AL,'S'-'@'
+        JNZ     NOSTOP
+        CALL    FAR PTR BIOSIN          ;Eat Cntrl-S
+INCHK:
+        CALL    FAR PTR BIOSIN 
+        CMP     AL,'P'-'@'
+        JZ      PRINTON
+        IF      NOT TOGLPRN
+        CMP     AL,'N'-'@'
+        JZ      PRINTOFF
+        ENDIF
+        CMP     AL,'C'-'@'
+        JNZ     RET18
+; Ctrl-C handler.
+; "^C" and CR/LF is printed. Then the user registers are restored and the
+; user CTRL-C handler is executed. At this point the top of the stack has
+; 1) the interrupt return address should the user CTRL-C handler wish to
+; allow processing to continue; 2) the original interrupt return address
+; to the code that performed the function call in the first place. If the
+; user CTRL-C handler wishes to continue, it must leave all registers
+; unchanged and IRET. The function that was interrupted will simply be
+; repeated.
+        MOV     AL,3            ;Display "^C"
+        CALL    BUFOUT
+        CALL    CRLF
+        CLI                     ;Prepare to play with stack
+        MOV     SS,CS:[SSSAVE]
+        MOV     SP,CS:[SPSAVE]  ;User stack now restored
+        POP     AX
+        POP     BX
+        POP     CX
+        POP     DX
+        POP     SI
+        POP     DI
+        POP     BP
+        POP     DS
+        POP     ES              ;User registers now restored
+        INT     CONTC           ;Execute user Ctrl-C handler
+        JMP     COMMAND         ;Repeat command otherwise
+
+PRINTON:
+        IF      TOGLPRN
+        NOT     CS:BYTE PTR [PFLAG]
+        RET
+        ENDIF
+        IF      NOT TOGLPRN
+        MOV     CS:BYTE PTR [PFLAG],1
+        RET
+
+PRINTOFF:
+        MOV     CS:BYTE PTR [PFLAG],0
+        RET
+        ENDIF
+
+CTRLOUT:
+        CMP     AL,13
+        JZ      ZERPOS
+        CMP     AL,8
+        JZ      BACKPOS
+        CMP     AL,9
+        JNZ     OUTCHJ
+        MOV     AL,CS:[CARPOS]
+        OR      AL,0F8H
+        NEG     AL
+TAB:
+        PUSH    CX
+        MOV     CL,AL
+        MOV     CH,0
+        JCXZ    POPTAB
+TABLP:
+        MOV     AL," "
+        CALL    OUT
+        LOOP    TABLP
+POPTAB:
+        POP     CX
+RET19:  RET
+
+ZERPOS:
+        MOV     CS:BYTE PTR [CARPOS],0
+OUTCHJ: JMP     OUTCH
+
+BACKPOS:
+        DEC     CS:BYTE PTR [CARPOS]
+        JMP     OUTCH
+
+
+CONSTAT: ;System call 11
+        CALL    STATCHK
+        MOV     AL,0 
+        JZ      RET19
+        OR      AL,-1
+        RET
+
+
+CONIN:  ;System call 1
+        CALL    IN
+        PUSH    AX
+        CALL    OUT
+        POP     AX
+        RET
+
+
+IN:     ;System call 8
+        CALL    INCHK
+        JZ      IN
+RET29:  RET
+
+RAWIO:  ;System call 6
+        MOV     AL,DL
+        CMP     AL,-1
+        JNZ     RAWOUT
+        LDS     SI,DWORD PTR CS:[SPSAVE]                ;Get pointer to register save area
+        CALL    FAR PTR BIOSSTAT
+        JNZ     RESFLG
+        OR      BYTE PTR [SI.FSAVE],40H ;Set user's zero flag
+        XOR     AL,AL
+        RET
+
+RESFLG:
+        AND     BYTE PTR [SI.FSAVE],0FFH-40H    ;Reset user's zero flag
+RAWINP: ;System call 7
+        CALL    FAR PTR BIOSIN 
+        RET
+RAWOUT:
+        CALL    FAR PTR BIOSOUT 
+        RET
+
+LIST:   ;System call 5
+        MOV     AL,DL
+LISTOUT:
+        PUSH    AX
+        CALL    STATCHK
+        POP     AX
+        CALL    FAR PTR BIOSPRINT 
+RET20:  RET
+
+PRTBUF: ;System call 9
+        MOV     SI,DX
+OUTSTR:
+        LODSB
+        CMP     AL,"$"
+        JZ      RET20
+        CALL    OUT
+        JMP     SHORT OUTSTR
+
+OUTMES: ;String output for internal messages
+        LODS    CS:BYTE PTR [SI]
+        CMP     AL,"$"
+        JZ      RET20
+        CALL    OUT
+        JMP     SHORT OUTMES
+
+
+MAKEFCB: ;Interrupt call 41
+DRVBIT  EQU     2
+NAMBIT  EQU     4
+EXTBIT  EQU     8
+        MOV     DL,0            ;Flag--not ambiguous file name
+        TEST    AL,DRVBIT       ;Use current drive field if default?
+        JNZ     DEFDRV
+        MOV     BYTE PTR ES:[DI],0      ;No - use default drive
+DEFDRV:
+        INC     DI
+        MOV     CX,8
+        TEST    AL,NAMBIT       ;Use current name fiels as defualt?
+        XCHG    AX,BX           ;Save bits in BX
+        MOV     AL," "
+        JZ      FILLB           ;If not, go fill with blanks
+        ADD     DI,CX
+        XOR     CX,CX           ;Don't fill any
+FILLB:
+        REP     STOSB
+        MOV     CL,3
+        TEST    BL,EXTBIT       ;Use current extension as default
+        JZ      FILLB2
+        ADD     DI,CX
+        XOR     CX,CX
+FILLB2:
+        REP     STOSB
+        XCHG    AX,CX           ;Put zero in AX
+        STOSW
+        STOSW                   ;Initialize two words after to zero
+        SUB     DI,16           ;Point back at start
+        TEST    BL,1            ;Scan off separators if not zero
+        JZ      SKPSPC
+        CALL    SCANB           ;Peel off blanks and tabs
+        CALL    DELIM           ;Is it a one-time-only delimiter?
+        JNZ     NOSCAN
+        INC     SI              ;Skip over the delimiter
+SKPSPC:
+        CALL    SCANB           ;Always kill preceding blanks and tabs
+NOSCAN:
+        CALL    GETLET
+        JBE     NODRV           ;Quit if termination character
+        CMP     BYTE PTR[SI],":"        ;Check for potential drive specifier
+        JNZ     NODRV
+        INC     SI              ;Skip over colon
+        SUB     AL,"@"          ;Convert drive letter to binary drive number
+        JBE     BADDRV          ;Valid drive numbers are 1-15
+        CMP     AL,CS:[NUMDRV]
+        JBE     HAVDRV
+BADDRV:
+        MOV     DL,-1
+HAVDRV:
+        STOSB           ;Put drive specifier in first byte
+        INC     SI
+        DEC     DI      ;Counteract next two instructions
+NODRV:
+        DEC     SI      ;Back up
+        INC     DI      ;Skip drive byte
+        MOV     CX,8
+        CALL    GETWORD         ;Get 8-letter file name
+        CMP     BYTE PTR [SI],"."
+        JNZ     NODOT
+        INC     SI              ;Skip over dot if present
+        MOV     CX,3            ;Get 3-letter extension
+        CALL    MUSTGETWORD
+NODOT:
+        LDS     BX,CS:DWORD PTR [SPSAVE]
+        MOV     [BX.SISAVE],SI
+        MOV     AL,DL
+        RET
+
+NONAM:
+        ADD     DI,CX
+        DEC     SI
+        RET
+
+GETWORD:
+        CALL    GETLET
+        JBE     NONAM           ;Exit if invalid character
+        DEC     SI
+MUSTGETWORD:
+        CALL    GETLET
+        JBE     FILLNAM
+        JCXZ    MUSTGETWORD
+        DEC     CX
+        CMP     AL,"*"          ;Check for ambiguous file specifier
+        JNZ     NOSTAR
+        MOV     AL,"?"
+        REP     STOSB
+NOSTAR:
+        STOSB
+        CMP     AL,"?"
+        JNZ     MUSTGETWORD
+        OR      DL,1            ;Flag ambiguous file name
+        JMP     MUSTGETWORD
+FILLNAM:
+        MOV     AL," "
+        REP     STOSB
+        DEC     SI
+RET21:  RET
+
+SCANB:
+        LODSB
+        CALL    SPCHK
+        JZ      SCANB
+        DEC     SI
+        RET
+
+GETLET:
+;Get a byte from [SI], convert it to upper case, and compare for delimiter.
+;ZF set if a delimiter, CY set if a control character (other than TAB).
+        LODSB
+        AND     AL,7FH
+        CMP     AL,"a"
+        JB      CHK
+        CMP     AL,"z"
+        JA      CHK
+        SUB     AL,20H          ;Convert to upper case
+CHK:
+        CMP     AL,"."
+        JZ      RET21
+        CMP     AL,'"'
+        JZ      RET21
+        CMP     AL,"/"
+        JZ      RET21
+        CMP     AL,"["
+        JZ      RET21
+        CMP     AL,"]"
+        JZ      RET21
+
+        IF      IBM
+DELIM:
+        ENDIF
+        CMP     AL,":"          ;Allow ":" as separator in IBM version
+        JZ      RET21
+        IF      NOT IBM
+DELIM:
+        ENDIF
+
+        CMP     AL,"+"
+        JZ      RET101
+        CMP     AL,"="
+        JZ      RET101
+        CMP     AL,";"
+        JZ      RET101
+        CMP     AL,","
+        JZ      RET101
+SPCHK:
+        CMP     AL,9            ;Filter out tabs too
+        JZ      RET101
+;WARNING! " " MUST be the last compare
+        CMP     AL," "
+RET101: RET
+
+SETVECT: ; Interrupt call 37
+        XOR     BX,BX
+        MOV     ES,BX
+        MOV     BL,AL
+        SHL     BX,1
+        SHL     BX,1
+        MOV     ES:[BX],DX
+        MOV     ES:[BX+2],DS
+        RET
+
+
+NEWBASE: ; Interrupt call 38
+        MOV     ES,DX
+        LDS     SI,CS:DWORD PTR [SPSAVE]
+        MOV     DS,[SI.CSSAVE]
+        XOR     SI,SI
+        MOV     DI,SI
+        MOV     AX,DS:[2]
+        MOV     CX,80H
+        REP     MOVSW
+
+SETMEM:
+
+; Inputs:
+;       AX = Size of memory in paragraphs
+;       DX = Segment
+; Function:
+;       Completely prepares a program base at the 
+;       specified segment.
+; Outputs:
+;       DS = DX
+;       ES = DX
+;       [0] has INT 20H
+;       [2] = First unavailable segment ([ENDMEM])
+;       [5] to [9] form a long call to the entry point
+;       [10] to [13] have exit address (from INT 22H)
+;       [14] to [17] have ctrl-C exit address (from INT 23H)
+;       [18] to [21] have fatal error address (from INT 24H)
+; DX,BP unchanged. All other registers destroyed.
+
+        XOR     CX,CX
+        MOV     DS,CX
+        MOV     ES,DX
+        MOV     SI,EXIT
+        MOV     DI,SAVEXIT
+        MOVSW
+        MOVSW
+        MOVSW
+        MOVSW
+        MOVSW
+        MOVSW
+        MOV     ES:[2],AX
+        SUB     AX,DX
+        CMP     AX,MAXDIF
+        JBE     HAVDIF
+        MOV     AX,MAXDIF
+HAVDIF:
+        MOV     BX,ENTRYPOINTSEG
+        SUB     BX,AX
+        SHL     AX,1
+        SHL     AX,1
+        SHL     AX,1
+        SHL     AX,1
+        MOV     DS,DX
+        MOV     DS:[6],AX
+        MOV     DS:[8],BX
+        MOV     DS:[0],20CDH    ;"INT INTTAB"
+        MOV     DS:(BYTE PTR [5]),LONGCALL
+        RET
+
+DATE16:
+        PUSH    CX
+        CALL    READTIME
+        SHL     CL,1            ;Minutes to left part of byte
+        SHL     CL,1
+        SHL     CX,1            ;Push hours and minutes to left end
+        SHL     CX,1
+        SHL     CX,1
+        SHR     DH,1            ;Count every two seconds
+        OR      CL,DH           ;Combine seconds with hours and minutes
+        MOV     DX,CX
+        POP     CX
+        MOV     AX,WORD PTR [MONTH]     ;Fetch month and year
+        SHL     AL,1                    ;Push month to left to make room for day
+        SHL     AL,1
+        SHL     AL,1
+        SHL     AL,1
+        SHL     AX,1
+        OR      AL,[DAY]
+RET22:  RET
+
+FOURYEARS       EQU     3*365+366
+
+READTIME:
+;Gets time in CX:DX. Figures new date if it has changed.
+;Uses AX, CX, DX.
+        CALL    FAR PTR BIOSGETTIME 
+        CMP     AX,[DAYCNT]     ;See if day count is the same
+        JZ      RET22
+        CMP     AX,FOURYEARS*30 ;Number of days in 120 years
+        JAE     RET22           ;Ignore if too large
+        MOV     [DAYCNT],AX
+        PUSH    SI
+        PUSH    CX
+        PUSH    DX              ;Save time
+        XOR     DX,DX
+        MOV     CX,FOURYEARS    ;Number of days in 4 years
+        DIV     CX              ;Compute number of 4-year units
+        SHL     AX,1
+        SHL     AX,1
+        SHL     AX,1            ;Multiply by 8 (no. of half-years)
+        MOV     CX,AX           ;<240 implies AH=0
+        MOV     SI,OFFSET DOSGROUP:YRTAB        ;Table of days in each year
+        CALL    DSLIDE          ;Find out which of four years we're in
+        SHR     CX,1            ;Convert half-years to whole years
+        JNC     SK              ;Extra half-year?
+        ADD     DX,200
+SK:
+        CALL    SETYEAR
+        MOV     CL,1            ;At least at first month in year
+        MOV     SI,OFFSET DOSGROUP:MONTAB       ;Table of days in each month
+        CALL    DSLIDE          ;Find out which month we're in
+        MOV     [MONTH],CL
+        INC     DX              ;Remainder is day of month (start with one)
+        MOV     [DAY],DL
+        CALL    WKDAY           ;Set day of week
+        POP     DX
+        POP     CX
+        POP     SI
+RET23:  RET
+
+DSLIDE:
+        MOV     AH,0
+DSLIDE1:
+        LODSB           ;Get count of days
+        CMP     DX,AX           ;See if it will fit
+        JB      RET23           ;If not, done
+        SUB     DX,AX
+        INC     CX              ;Count one more month/year
+        JMP     SHORT DSLIDE1
+
+SETYEAR:
+;Set year with value in CX. Adjust length of February for this year.
+        MOV     BYTE PTR [YEAR],CL
+CHKYR:
+        TEST    CL,3            ;Check for leap year
+        MOV     AL,28
+        JNZ     SAVFEB          ;28 days if no leap year
+        INC     AL              ;Add leap day
+SAVFEB:
+        MOV     [MONTAB+1],AL   ;Store for February
+        RET
+
+;Days in year
+YRTAB   DB      200,166         ;Leap year
+        DB      200,165
+        DB      200,165
+        DB      200,165
+
+;Days of each month
+MONTAB  DB      31              ;January
+        DB      28              ;February--reset each time year changes
+        DB      31              ;March
+        DB      30              ;April
+        DB      31              ;May
+        DB      30              ;June
+        DB      31              ;July
+        DB      31              ;August
+        DB      30              ;September
+        DB      31              ;October
+        DB      30              ;November
+        DB      31              ;December
+
+GETDATE: ;Function call 42
+        PUSH    CS
+        POP     DS
+        CALL    READTIME        ;Check for rollover to next day
+        MOV     AX,[YEAR]
+        MOV     BX,WORD PTR [DAY]
+        LDS     SI,DWORD PTR [SPSAVE]   ;Get pointer to user registers
+        MOV     [SI.DXSAVE],BX  ;DH=month, DL=day
+        ADD     AX,1980         ;Put bias back
+        MOV     [SI.CXSAVE],AX  ;CX=year
+        MOV     AL,CS:[WEEKDAY]
+RET24:  RET
+
+SETDATE: ;Function call 43
+        MOV     AL,-1           ;Be ready to flag error
+        SUB     CX,1980         ;Fix bias in year
+        JC      RET24           ;Error if not big enough
+        CMP     CX,119          ;Year must be less than 2100
+        JA      RET24
+        OR      DH,DH
+        JZ      RET24
+        OR      DL,DL
+        JZ      RET24           ;Error if either month or day is 0
+        CMP     DH,12           ;Check against max. month
+        JA      RET24
+        PUSH    CS
+        POP     DS
+        CALL    CHKYR           ;Set Feb. up for new year
+        MOV     AL,DH
+        MOV     BX,OFFSET DOSGROUP:MONTAB-1
+        XLAT                    ;Look up days in month
+        CMP     AL,DL
+        MOV     AL,-1           ;Restore error flag, just in case
+        JB      RET24           ;Error if too many days
+        CALL    SETYEAR
+        MOV     WORD PTR [DAY],DX       ;Set both day and month
+        SHR     CX,1
+        SHR     CX,1
+        MOV     AX,FOURYEARS
+        MOV     BX,DX
+        MUL     CX
+        MOV     CL,BYTE PTR [YEAR]
+        AND     CL,3
+        MOV     SI,OFFSET DOSGROUP:YRTAB
+        MOV     DX,AX
+        SHL     CX,1            ;Two entries per year, so double count
+        CALL    DSUM            ;Add up the days in each year
+        MOV     CL,BH           ;Month of year
+        MOV     SI,OFFSET DOSGROUP:MONTAB
+        DEC     CX              ;Account for months starting with one
+        CALL    DSUM            ;Add up days in each month
+        MOV     CL,BL           ;Day of month
+        DEC     CX              ;Account for days starting with one
+        ADD     DX,CX           ;Add in to day total
+        XCHG    AX,DX           ;Get day count in AX
+        MOV     [DAYCNT],AX
+        CALL    FAR PTR BIOSSETDATE 
+WKDAY:
+        MOV     AX,[DAYCNT]
+        XOR     DX,DX
+        MOV     CX,7
+        INC     AX
+        INC     AX              ;First day was Tuesday
+        DIV     CX              ;Compute day of week
+        MOV     [WEEKDAY],DL
+        XOR     AL,AL           ;Flag OK
+RET25:  RET
+
+DSUM:
+        MOV     AH,0
+        JCXZ    RET25
+DSUM1:
+        LODSB
+        ADD     DX,AX
+        LOOP    DSUM1
+        RET
+
+GETTIME: ;Function call 44
+        PUSH    CS
+        POP     DS
+        CALL    READTIME
+        LDS     SI,DWORD PTR [SPSAVE]   ;Get pointer to user registers
+        MOV     [SI.DXSAVE],DX
+        MOV     [SI.CXSAVE],CX
+        XOR     AL,AL
+RET26:  RET
+
+SETTIME: ;Function call 45
+;Time is in CX:DX in hours, minutes, seconds, 1/100 sec.
+        MOV     AL,-1           ;Flag in case of error
+        CMP     CH,24           ;Check hours
+        JAE     RET26
+        CMP     CL,60           ;Check minutes
+        JAE     RET26
+        CMP     DH,60           ;Check seconds
+        JAE     RET26
+        CMP     DL,100          ;Check 1/100's
+        JAE     RET26
+        CALL    FAR PTR BIOSSETTIME 
+        XOR     AL,AL
+        RET
+
+
+; Default handler for division overflow trap
+DIVOV:
+        PUSH    SI
+        PUSH    AX
+        MOV     SI,OFFSET DOSGROUP:DIVMES
+        CALL    OUTMES
+        POP     AX
+        POP     SI
+        INT     23H             ;Use Ctrl-C abort on divide overflow
+        IRET
+
+CODSIZ  EQU     $-CODSTRT       ;Size of code segment
+CODE    ENDS
+
+
+;***** DATA AREA *****
+CONSTANTS       SEGMENT BYTE
+        ORG     0
+CONSTRT EQU     $               ;Start of constants segment
+
+IONAME:
+        IF      NOT IBM
+        DB      "PRN ","LST ","NUL ","AUX ","CON "
+        ENDIF
+        IF      IBM
+        DB      "COM1","PRN ","LPT1","NUL ","AUX ","CON "
+        ENDIF
+DIVMES  DB      13,10,"Divide overflow",13,10,"$"
+CARPOS  DB      0
+STARTPOS DB     0
+PFLAG   DB      0
+DIRTYDIR DB     0               ;Dirty buffer flag
+NUMDRV  DB      0       ;Number of drives
+NUMIO   DB      ?       ;Number of disk tables
+VERFLG  DB      0       ;Initialize with verify off
+CONTPOS DW      0
+DMAADD  DW      80H             ;User's disk transfer address (disp/seg)
+        DW      ?
+ENDMEM  DW      ?
+MAXSEC  DW      0
+BUFFER  DW      ?
+BUFSECNO DW     0
+BUFDRVNO DB     -1
+DIRTYBUF DB     0
+BUFDRVBP DW     ?
+DIRBUFID DW     -1
+DAY     DB      0
+MONTH   DB      0
+YEAR    DW      0
+DAYCNT  DW      -1
+WEEKDAY DB      0
+CURDRV  DB      0               ;Default to drive A
+DRVTAB  DW      0               ;Address of start of DPBs
+DOSLEN  EQU     CODSIZ+($-CONSTRT)      ;Size of CODE + CONSTANTS segments
+CONSTANTS       ENDS
+
+DATA    SEGMENT WORD
+; Init code overlaps with data area below
+
+        ORG     0
+INBUF   DB      128 DUP (?)
+CONBUF  DB      131 DUP (?)             ;The rest of INBUF and console buffer
+LASTENT DW      ?
+EXITHOLD DB     4 DUP (?)
+FATBASE DW      ?
+NAME1   DB      11 DUP (?)              ;File name buffer
+ATTRIB  DB      ?
+NAME2   DB      11 DUP (?)
+NAME3   DB      12 DUP (?)
+EXTFCB  DB      ?
+;WARNING - the following two items are accessed as a word
+CREATING DB     ?
+DELALL  DB      ?
+TEMP    LABEL   WORD
+SPSAVE  DW      ?
+SSSAVE  DW      ?
+CONTSTK DW      ?
+SECCLUSPOS DB   ?       ;Position of first sector within cluster
+DSKERR  DB      ?
+TRANS   DB      ?
+PREREAD DB      ?       ;0 means preread; 1 means optional
+READOP  DB      ?
+THISDRV DB      ?
+
+        EVEN
+FCB     DW      ?       ;Address of user FCB
+NEXTADD DW      ?
+RECPOS  DB      4 DUP (?)
+RECCNT  DW      ?
+LASTPOS DW      ?
+CLUSNUM DW      ?
+SECPOS  DW      ?       ;Position of first sector accessed
+VALSEC  DW      ?       ;Number of valid (previously written) sectors
+BYTSECPOS DW    ?       ;Position of first byte within sector
+BYTPOS  DB      4 DUP (?)               ;Byte position in file of access
+BYTCNT1 DW      ?       ;No. of bytes in first sector
+BYTCNT2 DW      ?       ;No. of bytes in last sector
+SECCNT  DW      ?       ;No. of whole sectors
+ENTFREE DW      ?
+
+        DB      80H DUP (?)     ;Stack space
+IOSTACK LABEL   BYTE
+        DB      80H DUP (?)
+DSKSTACK LABEL  BYTE 
+
+        IF      DSKTEST
+NSS     DW      ?
+NSP     DW      ?
+        ENDIF
+
+DIRBUF LABEL    WORD
+
+;Init code below overlaps with data area above
+
+        ORG     0
+
+MOVFAT:
+;This section of code is safe from being overwritten by block move
+        REP     MOVS    BYTE PTR [DI],[SI]
+        CLD
+        MOV     ES:[DMAADD+2],DX
+        MOV     SI,[DRVTAB]     ;Address of first DPB
+        MOV     AL,-1
+        MOV     CL,[NUMIO]      ;Number of DPBs
+FLGFAT:
+        MOV     DI,ES:[SI.FAT]  ;get pointer to FAT
+        DEC     DI              ;Point to dirty byte
+        STOSB                   ;Flag as unused
+        ADD     SI,DPBSIZ       ;Point to next DPB
+        LOOP    FLGFAT
+        MOV     AX,[ENDMEM]
+        CALL    SETMEM          ;Set up segment
+
+XXX     PROC FAR
+        RET
+XXX     ENDP
+
+DOSINIT:
+        CLI
+        CLD
+        PUSH    CS
+        POP     ES
+        MOV     ES:[ENDMEM],DX
+        LODSB                   ;Get no. of drives & no. of I/O drivers
+        MOV     ES:[NUMIO],AL
+        MOV     DI,OFFSET DOSGROUP:MEMSTRT
+PERDRV:
+        MOV     BP,DI
+        MOV     AL,ES:[DRVCNT]
+        STOSB           ;DEVNUM
+        LODSB           ;Physical unit no.
+        STOSB           ;DRVNUM
+        CMP     AL,15
+        JA      BADINIT
+        CBW             ;Index into FAT size table
+        SHL     AX,1
+        ADD     AX,OFFSET DOSGROUP:FATSIZTAB
+        XCHG    BX,AX
+        LODSW           ;Pointer to DPT
+        PUSH    SI
+        MOV     SI,AX
+        LODSW
+        STOSW           ;SECSIZ
+        MOV     DX,AX
+        CMP     AX,ES:[MAXSEC]
+        JBE     NOTMAX
+        MOV     ES:[MAXSEC],AX
+NOTMAX:
+        LODSB
+        DEC     AL
+        STOSB           ;CLUSMSK
+        JZ      HAVSHFT
+        CBW
+FIGSHFT:
+        INC     AH
+        SAR     AL,1
+        JNZ     FIGSHFT
+        MOV     AL,AH
+HAVSHFT:
+        STOSB           ;CLUSSHFT
+        MOVSW           ;FIRFAT (= number of reserved sectors)
+        MOVSB           ;FATCNT
+        MOVSW           ;MAXENT
+        MOV     AX,DX           ;SECSIZ again
+        MOV     CL,5
+        SHR     AX,CL
+        MOV     CX,AX           ;Directory entries per sector
+        DEC     AX
+        ADD     AX,ES:[BP.MAXENT]
+        XOR     DX,DX
+        DIV     CX
+        STOSW           ;DIRSEC (temporarily)
+        MOVSW                   ;DSKSIZ (temporarily)
+FNDFATSIZ:
+        MOV     AL,1
+        MOV     DX,1
+GETFATSIZ:
+        PUSH    DX
+        CALL    FIGFATSIZ
+        POP     DX
+        CMP     AL,DL           ;Compare newly computed FAT size with trial
+        JZ      HAVFATSIZ       ;Has sequence converged?
+        CMP     AL,DH           ;Compare with previous trial
+        MOV     DH,DL
+        MOV     DL,AL           ;Shuffle trials
+        JNZ     GETFATSIZ       ;Continue iterations if not oscillating
+        DEC     WORD PTR ES:[BP.DSKSIZ] ;Damp those oscillations
+        JMP     SHORT FNDFATSIZ ;Try again
+
+BADINIT:
+        MOV     SI,OFFSET DOSGROUP:BADMES
+        CALL    OUTMES
+        STI
+        HLT
+
+HAVFATSIZ:
+        STOSB                   ;FATSIZ
+        MUL     ES:BYTE PTR[BP.FATCNT]  ;Space occupied by all FATs
+        ADD     AX,ES:[BP.FIRFAT]
+        STOSW                   ;FIRDIR
+        ADD     AX,ES:[BP.DIRSEC]
+        MOV     ES:[BP.FIRREC],AX       ;Destroys DIRSEC
+        CALL    FIGMAX
+        MOV     ES:[BP.MAXCLUS],CX
+        MOV     AX,BX           ;Pointer into FAT size table
+        STOSW                   ;Allocate space for FAT pointer
+        MOV     AL,ES:[BP.FATSIZ]
+        XOR     AH,AH
+        MUL     ES:[BP.SECSIZ]
+        CMP     AX,ES:[BX]      ;Bigger than already allocated
+        JBE     SMFAT
+        MOV     ES:[BX],AX
+SMFAT:
+        POP     SI              ;Restore pointer to init. table
+        MOV     AL,ES:[DRVCNT]
+        INC     AL
+        MOV     ES:[DRVCNT],AL
+        CMP     AL,ES:[NUMIO]
+        JAE     CONTINIT
+        JMP     PERDRV  
+
+BADINITJ:
+        JMP     BADINIT
+
+CONTINIT:
+        PUSH    CS
+        POP     DS
+;Calculate true address of buffers, FATs, free space
+        MOV     BP,[MAXSEC]
+        MOV     AX,OFFSET DOSGROUP:DIRBUF
+        ADD     AX,BP
+        MOV     [BUFFER],AX     ;Start of buffer
+        ADD     AX,BP
+        MOV     [DRVTAB],AX     ;Start of DPBs
+        SHL     BP,1            ;Two sectors - directory and buffer
+        ADD     BP,DI           ;Allocate buffer space
+        ADD     BP,ADJFAC       ;True address of FATs
+        PUSH    BP
+        MOV     SI,OFFSET DOSGROUP:FATSIZTAB
+        MOV     DI,SI
+        MOV     CX,16
+TOTFATSIZ:
+        INC     BP              ;Add one for Dirty byte
+        INC     BP              ;Add one for I/O device number
+        LODSW                   ;Get size of this FAT
+        XCHG    AX,BP
+        STOSW                   ;Save address of this FAT
+        ADD     BP,AX           ;Compute size of next FAT
+        CMP     AX,BP           ;If size was zero done
+        LOOPNZ  TOTFATSIZ
+        MOV     AL,15
+        SUB     AL,CL           ;Compute number of FATs used
+        MOV     [NUMDRV],AL
+        XOR     AX,AX           ;Set zero flag
+        REPZ    SCASW           ;Make sure all other entries are zero
+        JNZ     BADINITJ
+        ADD     BP,15           ;True start of free space
+        MOV     CL,4
+        SHR     BP,CL           ;First free segment
+        MOV     DX,CS
+        ADD     DX,BP
+        MOV     BX,0FH
+        MOV     CX,[ENDMEM]
+        CMP     CX,1            ;Use memory scan?
+        JNZ     SETEND
+        MOV     CX,DX           ;Start scanning just after DOS
+MEMSCAN:
+        INC     CX
+        JZ      SETEND
+        MOV     DS,CX
+        MOV     AL,[BX]
+        NOT     AL
+        MOV     [BX],AL
+        CMP     AL,[BX]
+        NOT     AL
+        MOV     [BX],AL
+        JZ      MEMSCAN
+SETEND:
+        IF      HIGHMEM
+        SUB     CX,BP
+        MOV     BP,CX           ;Segment of DOS
+        MOV     DX,CS           ;Program segment
+        ENDIF
+        IF      NOT HIGHMEM
+        MOV     BP,CS
+        ENDIF
+; BP has segment of DOS (whether to load high or run in place)
+; DX has program segment (whether after DOS or overlaying DOS)
+; CX has size of memory in paragraphs (reduced by DOS size if HIGHMEM)
+        MOV     CS:[ENDMEM],CX
+        IF      HIGHMEM
+        MOV     ES,BP
+        XOR     SI,SI
+        MOV     DI,SI
+        MOV     CX,(DOSLEN+1)/2
+        PUSH    CS
+        POP     DS
+        REP MOVSW               ;Move DOS to high memory
+        ENDIF
+        XOR     AX,AX
+        MOV     DS,AX
+        MOV     ES,AX
+        MOV     DI,INTBASE
+        MOV     AX,OFFSET DOSGROUP:QUIT
+        STOSW                   ;Set abort address--displacement
+        MOV     AX,BP
+        MOV     BYTE PTR DS:[ENTRYPOINT],LONGJUMP
+        MOV     WORD PTR DS:[ENTRYPOINT+1],OFFSET DOSGROUP:ENTRY
+        MOV     WORD PTR DS:[ENTRYPOINT+3],AX
+        MOV     WORD PTR DS:[0],OFFSET DOSGROUP:DIVOV   ;Set default divide trap address
+        MOV     DS:[2],AX
+        MOV     CX,9
+        REP STOSW               ;Set 5 segments (skip 2 between each)
+        MOV     WORD PTR DS:[INTBASE+4],OFFSET DOSGROUP:COMMAND
+        MOV     WORD PTR DS:[INTBASE+12],OFFSET DOSGROUP:IRET   ;Ctrl-C exit
+        MOV     WORD PTR DS:[INTBASE+16],OFFSET DOSGROUP:IRET   ;Fatal error exit
+        MOV     AX,OFFSET BIOSREAD
+        STOSW
+        MOV     AX,BIOSSEG
+        STOSW
+        STOSW                   ;Add 2 to DI
+        STOSW
+        MOV     WORD PTR DS:[INTBASE+18H],OFFSET BIOSWRITE
+        MOV     WORD PTR DS:[EXIT],100H
+        MOV     WORD PTR DS:[EXIT+2],DX
+        IF      NOT IBM
+        MOV     SI,OFFSET DOSGROUP:HEADER
+        CALL    OUTMES
+        ENDIF
+        PUSH    CS
+        POP     DS
+        PUSH    CS
+        POP     ES
+;Move the FATs into position
+        MOV     AL,[NUMIO]
+        CBW
+        XCHG    AX,CX
+        MOV     DI,OFFSET DOSGROUP:MEMSTRT.FAT
+FATPOINT:
+        MOV     SI,WORD PTR [DI]        ;Get address within FAT address table
+        MOVSW                           ;Set address of this FAT
+        ADD     DI,DPBSIZ-2             ;Point to next DPB
+        LOOP    FATPOINT
+        POP     CX                      ;True address of first FAT
+        MOV     SI,OFFSET DOSGROUP:MEMSTRT      ;Place to move DPBs from
+        MOV     DI,[DRVTAB]             ;Place to move DPBs to
+        SUB     CX,DI                   ;Total length of DPBs
+        CMP     DI,SI
+        JBE     MOVJMP                  ;Are we moving to higher or lower memory?
+        DEC     CX                      ;Move backwards to higher memory
+        ADD     DI,CX
+        ADD     SI,CX
+        INC     CX
+        STD
+MOVJMP:
+        MOV     ES,BP
+        JMP     MOVFAT
+
+FIGFATSIZ:
+        MUL     ES:BYTE PTR[BP.FATCNT]
+        ADD     AX,ES:[BP.FIRFAT]
+        ADD     AX,ES:[BP.DIRSEC]
+FIGMAX:
+;AX has equivalent of FIRREC
+        SUB     AX,ES:[BP.DSKSIZ]
+        NEG     AX
+        MOV     CL,ES:[BP.CLUSSHFT]
+        SHR     AX,CL
+        INC     AX
+        MOV     CX,AX           ;MAXCLUS
+        INC     AX
+        MOV     DX,AX
+        SHR     DX,1
+        ADC     AX,DX           ;Size of FAT in bytes
+        MOV     SI,ES:[BP.SECSIZ]
+        ADD     AX,SI
+        DEC     AX
+        XOR     DX,DX
+        DIV     SI
+        RET
+
+BADMES:
+        DB      13,10,"INIT TABLE BAD",13,10,"$"
+
+FATSIZTAB:
+        DW      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+
+DRVCNT  DB      0
+
+MEMSTRT LABEL   WORD
+ADJFAC  EQU     DIRBUF-MEMSTRT
+DATA    ENDS
+        END
+\1a
\ No newline at end of file
diff --git a/v1.25/source/STDDOS.ASM b/v1.25/source/STDDOS.ASM
new file mode 100644 (file)
index 0000000..1216b4c
--- /dev/null
@@ -0,0 +1,23 @@
+       TITLE   MS-DOS version 1.25 by Tim Paterson     March 3, 1982
+       PAGE    60,132
+; Use the following booleans to set the switches 
+FALSE  EQU     0
+TRUE   EQU     NOT FALSE
+
+; Use the switches below to produce the standard Microsoft version of the IBM
+; version of the operating system
+MSVER  EQU     TRUE
+IBM    EQU     FALSE
+
+; Set this switch to cause DOS to move itself to the end of memory
+HIGHMEM        EQU     FALSE
+
+; Turn on switch below to allow testing disk code with DEBUG. It sets
+; up a different stack for disk I/O (functions > 11) than that used for
+; character I/O which effectively makes the DOS re-entrant.
+
+DSKTEST        EQU     FALSE
+
+       INCLUDE MSDOS.ASM
+
+\1a
\ No newline at end of file
diff --git a/v1.25/source/TRANS.ASM b/v1.25/source/TRANS.ASM
new file mode 100644 (file)
index 0000000..6b06619
--- /dev/null
@@ -0,0 +1,1213 @@
+; Z80 to 8086 Translator  version 2.21
+;  Runs on the 8086 under 86-DOS
+; by Tim Paterson
+;
+       ORG     100H
+EOF:   EQU     1AH     ;End of file
+EOL:   EQU     0DH
+FCB:   EQU     5CH
+SYSTEM:        EQU     5
+OPEN:  EQU     15
+CLOSE: EQU     16
+SETDMA:        EQU     26
+CREATE:        EQU     22
+DELETE:        EQU     19
+READ:  EQU     20
+WRITE: EQU     21
+PRNBUF:        EQU     9
+       MOV     SP,STACK
+       MOV     DX,HEADER
+       MOV     CL,9
+       CALL    SYSTEM
+       MOV     BX,FCB+12
+       XOR     AL,AL
+       MOV     CH,4
+CLRFCB:
+       MOV     [BX],AL
+       INC     BX
+       DEC     CH
+       JNZ     CLRFCB
+       MOV     [FCB+32],AL
+       MOV     BX,FCB
+       MOV     DX,PUTFCB
+       MOV     CX,16
+       UP
+       MOV     SI,BX
+       MOV     DI,DX
+       REP
+       MOVB
+       MOV     DX,DI
+       MOV     BX,SI
+       MOV     [PUTFCB+32],AL
+       MOV     BX,"A"+5300H    ;"AS"
+       MOV     [PUTFCB+9],BX
+       MOV     AL,'M'
+       MOV     [PUTFCB+11],AL
+       MOV     DX,FCB
+       MOV     CL,OPEN
+       CALL    SYSTEM
+       INC     AL
+       MOV     DX,NOFILE
+       JZ      ABORTJ
+       MOV     DX,PUTFCB
+       MOV     CL,DELETE
+       CALL    SYSTEM
+       MOV     DX,PUTFCB
+       MOV     CL,CREATE
+       CALL    SYSTEM
+       INC     AL
+       MOV     DX,NOROOM
+ABORTJ:
+       JZ      ABORT
+       MOV     DX,PUTFCB
+       MOV     CL,OPEN
+       CALL    SYSTEM
+       MOV     BX,PUTBUF
+       MOV     [PUTPT],BX
+       MOV     BX,GETBUF+80H
+       MOV     [GETPT],BX
+TRANLN:
+       XOR     AL,AL
+       MOV     [OP1],AL
+       MOV     [OP2],AL
+       MOV     BX,OPCODE
+       CALL    LOAD
+       MOV     BX,OP1
+       CALL    GETOP
+       MOV     B,[BX],0
+       MOV     BX,OP2
+       CALL    GETOP
+DOLIN:
+       MOV     B,[BX],0
+       CALL    FINDOP
+ENLIN:
+       MOV     SP,STACK
+       MOV     AL,[CHAR]
+       CMP     AL,';'
+       JNZ     NOCOM
+       MOV     AL,9
+       CALL    PUTCH
+       MOV     AL,';'
+NOCOM:
+       CALL    PUTCH
+PUTLIN:
+       CMP     AL,EOF
+       JZ      END
+       CALL    GETCH
+       CALL    PUTCH
+       CMP     AL,10
+       JNZ     PUTLIN
+       JP      TRANLN
+END:
+       MOV     CH,127
+       MOV     AL,1AH
+FILL:
+       CALL    PUTCH
+       DEC     CH
+       JNZ     FILL
+       MOV     DX,PUTFCB
+       MOV     CL,CLOSE
+       CALL    SYSTEM
+       MOV     DX,ENDMES
+ABORT:
+       MOV     CL,PRNBUF
+       CALL    SYSTEM
+       JMP     0
+DELIM:
+       CALL    GETCH
+DELCHK:
+       CMP     AL,EOL
+       JZ      DOLIN
+       CMP     AL,EOF
+       JZ      DOLIN
+       CMP     AL,';'
+       JZ      DOLIN
+       CMP     AL,' '
+       JZ      RET
+       CMP     AL,':'
+       JZ      RET
+       CMP     AL,','
+       JZ      RET
+       CMP     AL,9
+       RET
+HEX:
+       AND     AL,0FH
+       ADD     AL,90H
+       DAA
+       ADC     AL,40H
+       DAA
+PUTCH:
+       PUSH    BX
+       PUSH    DX
+       PUSH    CX
+       LAHF
+       XCHG    AH,AL
+       PUSH    AX
+       XCHG    AH,AL
+       AND     AL,7FH
+       MOV     BX,[PUTPT]
+       MOV     [BX],AL
+       INC     BX
+       MOV     [PUTPT],BX
+       CMP     BX,PUTBUF+80H
+       JNZ     POPRET
+       MOV     DX,PUTBUF
+       MOV     [PUTPT],DX
+       MOV     CL,SETDMA
+       CALL    SYSTEM
+       MOV     DX,PUTFCB
+       MOV     CL,WRITE
+       CALL    SYSTEM
+       OR      AL,AL
+       MOV     DX,WRTERR
+       JNZ     ABORT
+POPRET:
+       POP     AX
+       XCHG    AH,AL
+       SAHF
+NOTAF:
+       POP     CX
+       POP     DX
+       POP     BX
+       RET
+;
+; Get character from source file.
+;
+GETCH:
+       PUSH    BX
+       PUSH    DX
+       PUSH    CX
+       MOV     BX,[GETPT]      ; Get buffer pointer.
+       CMP     BX,GETBUF+80H   ; Past end-of-buffer?
+       JNZ     GETIT           ; Jump if not.
+       MOV     DX,GETBUF       ; Set `DMA address'.
+       MOV     CL,SETDMA
+       CALL    SYSTEM
+       MOV     DX,FCB          ; Read the next record from source file.
+       MOV     CL,READ
+       CALL    SYSTEM
+       CMP     AL,0            ; Entire record read OK?
+       JE      OKRECORD
+       CMP     AL,3            ; Partial record read?
+       JE      OKRECORD
+       MOV     AL,EOF          ; Force end-of-file character in case
+       JP      TESEND          ;  there is nothing in the record.
+OKRECORD:
+       MOV     BX,GETBUF       ; Reset buffer pointer.
+GETIT:
+       MOV     AL,[BX]         ; Get next character from buffer.
+       INC     BX              ; Point to next character.
+       MOV     [GETPT],BX      ; Save new pointer.
+TESEND:
+       MOV     [CHAR],AL
+       JP      NOTAF           ; Pop registers and return.
+LOAD:
+       CALL    DELIM
+       JZ      LOADOP
+EATLAB:
+       CALL    PUTCH
+       CALL    DELIM
+       JNZ     EATLAB
+ENLAB:
+       MOV     AL,':'
+       CALL    PUTCH
+LOADOP:
+       MOV     BX,OPCODE
+EATEM:
+       CALL    DELIM
+       JZ      EATEM
+LOADLP:
+       CALL    IDCHK
+       JNC     $+5
+       JMP     OPERR
+       MOV     [BX],AL
+       INC     BX
+       CALL    DELIM
+       JNZ     LOADLP
+       MOV     B,[BX],0
+       CMP     AL,':'
+       JNZ     RET
+       MOV     BX,OPCODE
+       CALL    TRANS
+       JP      ENLAB
+GETOP:
+       XOR     AL,AL
+       LAHF
+       XCHG    AX,BP
+       SAHF
+GETLP:
+       CALL    DELIM
+       JZ      GETLP
+OPCHAR:
+       CMP     AL,'('
+       JNZ     NOTLEF
+       LAHF
+       XCHG    AX,BP
+       SAHF
+       INC     AL
+       LAHF
+       XCHG    AX,BP
+       SAHF
+       MOV     B,[BX],'['
+       JP      NEXCH
+NOTLEF:
+       CMP     AL,')'
+       JNZ     NOTRIT
+       LAHF
+       XCHG    AX,BP
+       SAHF
+       DEC     AL
+       LAHF
+       XCHG    AX,BP
+       SAHF
+       MOV     B,[BX],']'
+       JP      NEXCH
+NOTRIT:
+       MOV     [BX],AL
+       CMP     AL,''''
+       JZ      EATQUO
+       CALL    IDCHK
+       JNC     GETID
+NEXCH:
+       INC     BX
+       CALL    GETCH
+IDRET:
+       CALL    DELCHK
+       JNZ     OPCHAR
+       CMP     AL,' '
+       JZ      OPCHAR
+       RET
+EATQUO:
+       INC     BX
+       CALL    GETCH
+       MOV     [BX],AL
+       CMP     AL,';'
+       JZ      L0000
+       CALL    DELCHK
+L0000: 
+       CMP     AL,''''
+       JNZ     EATQUO
+       JP      NEXCH
+IDCHK:
+       CMP     AL,'0'
+       JC      RET
+       CMP     AL,'9'+1
+       CMC
+       JNC     RET
+       CMP     AL,40H
+       JC      RET
+       AND     AL,5FH
+       CMP     AL,'A'
+       JC      RET
+       CMP     AL,'Z'+1
+       CMC
+       RET
+GETID:
+       MOV     [BX],AL
+       MOV     CH,1
+LODID:
+       INC     BX
+       CALL    GETCH
+       CALL    IDCHK
+       JC      RWCHK
+       MOV     [BX],AL
+       INC     CH
+       JP      LODID
+RWCHK:
+       LAHF
+       XCHG    AH,AL
+       PUSH    AX
+       XCHG    AH,AL
+       PUSH    BX
+       DEC     BX
+       DEC     CH
+       MOV     DL,CH
+       JZ      LOOKRW
+       MOV     DL,[BX]
+       DEC     BX
+       DEC     CH
+       JNZ     NORW
+LOOKRW:
+       MOV     AL,[BX]
+       MOV     DH,AL
+       PUSH    BX
+       MOV     BX,RWTAB
+       MOV     CX,LENRW
+RWLK:
+       UP
+       MOV     DI,BX
+       REPNZ
+       SCAB
+       MOV     BX,DI
+       JNZ     NOTRW
+       PUSH    BX
+       PUSH    CX
+       MOV     CX,LENRW-1
+       LAHF
+       ADD     BX,CX
+       RCR     SI
+       SAHF
+       RCL     SI
+       MOV     AL,[BX]
+       POP     CX
+       POP     BX
+       CMP     AL,DL
+       JZ      HAVRW
+       MOV     AL,CL
+       OR      AL,AL
+       MOV     AL,DH
+       JNZ     RWLK
+NOTRW:
+       POP     BX
+NORW:
+       POP     BX
+ENDRW:
+       POP     AX
+       XCHG    AH,AL
+       SAHF
+       JMP     IDRET
+HAVRW:
+       POP     BX
+       INC     CL
+       MOV     [BX],CL
+       INC     BX
+       POP     DX
+       PUSH    BX
+       MOV     AL,CL
+       MOV     BX,IXSI
+       CMP     AL,RSI
+       JZ      IXIY
+       MOV     BX,IYDI
+       CMP     AL,RDI
+       JNZ     NORW
+IXIY:
+       LAHF
+       XCHG    AX,BP
+       SAHF
+       JZ      NOTENC
+       LAHF
+       XCHG    AX,BP
+       SAHF
+       CALL    OUTSTR
+       JP      NORW
+NOTENC:
+       LAHF
+       XCHG    AX,BP
+       SAHF
+       POP     BX
+       DEC     BX
+       MOV     B,[BX],'['
+       INC     BX
+       ADD     AL,RIX-1
+       MOV     [BX],AL
+       INC     BX
+       MOV     B,[BX],']'
+       INC     BX
+       JP      ENDRW
+       RET
+FINDOP:
+       MOV     BX,OPCODE
+       MOV     CX,5
+       XOR     AL,AL
+       UP
+       MOV     DI,BX
+       REPNZ
+       SCAB
+       MOV     BX,DI
+       JNZ     OPERR
+       MOV     AL,4
+       SUB     AL,CL
+       JZ      RET
+       DEC     AL
+       JZ      OPERR
+       MOV     CL,AL
+       DEC     BX
+       DEC     BX
+       OR      B,[BX],080H
+       MOV     AL,[OPCODE]
+       SUB     AL,'A'
+       JC      OPERR
+       ADD     AL,AL
+       MOV     DL,AL
+       MOV     DH,0
+       MOV     BX,OPTAB
+       LAHF
+       ADD     BX,DX
+       RCR     SI
+       SAHF
+       RCL     SI
+       MOV     DL,[BX]
+       INC     BX
+       MOV     DH,[BX]
+       XCHG    DX,BX
+       MOV     AL,9
+       CALL    PUTCH
+LOOKOP:
+       MOV     AL,[BX]
+       OR      AL,AL
+       JZ      OPERR
+       MOV     DX,OPCODE+1
+       MOV     CH,CL
+LOOKLP:
+       MOV     SI,DX
+       LODB
+       CMP     AL,[BX]
+       JNZ     NEXOP
+       INC     DX
+       INC     BX
+       DEC     CH
+       JNZ     LOOKLP
+       MOV     DX,[BX]
+       MOV     BX,[BX+2]
+       JMP     DX
+NEXOP:
+       RCR     SI
+       TEST    B,[BX],080H
+       RCL     SI
+       LAHF
+       INC     BX
+       SAHF
+       JZ      NEXOP
+       MOV     DX,4
+       LAHF
+       ADD     BX,DX
+       RCR     SI
+       SAHF
+       RCL     SI
+       JP      LOOKOP
+OPERR:
+       MOV     BX,OPCODE
+       CALL    OUTSTR
+       CALL    TWOOPS
+       MOV     BX,OPCDER
+       CALL    OUTSTR
+       JMP     ENLIN
+LD:
+       CALL    OUTSTR
+       MOV     BX,OP1
+       MOV     DX,OP2+1
+       CALL    LCHECK
+       JNZ     $+5
+       JMP     LDAX
+       XCHG    DX,BX
+       DEC     BX
+       INC     DX
+       CALL    LCHECK
+       JNZ     $+5
+       JMP     STAX
+;If immediate move, check for byte memory reference
+       MOV     AL,[OP2]
+       CMP     AL,20H          ;Could be immediate?
+       MOV     AL,9
+       JC      L0001
+       CALL    BYTCHK          ;Add "B," if memory reference
+L0001: 
+       CALL    TRAN1
+       JP      TRNOP2
+TWOOPS:
+       CALL    TRNOP1
+TRNOP2:
+       MOV     AL,','
+TRAN2:
+       MOV     BX,OP2
+PTRANS:
+       CALL    PUTCH
+TRANS:
+       MOV     AL,[BX]
+       LAHF
+       INC     BX
+       SAHF
+       OR      AL,AL
+       JZ      RET
+       CALL    TRNTOK
+       JP      TRANS
+LCHECK:
+       MOV     AL,[BX]
+       CMP     AL,RAL
+       JNZ     RET
+       MOV     SI,DX
+       LODB
+       CMP     AL,RCX
+       JZ      RET
+       CMP     AL,RDX
+       RET
+
+ONEOP:
+       CALL    OUTSTR
+       MOV     AL,9
+       CALL    BYTCHK          ;If memory reference, add "B," flag
+       JMPS    TRAN1
+
+TRNOP1:
+       MOV     AL,9
+TRAN1:
+       MOV     BX,OP1
+       JP      PTRANS
+IN:
+       MOV     AL,[OP1]
+       CMP     AL,RAL
+       XCHG    DX,BX
+       MOV     BX,OP2
+       JZ      GETPORT
+       MOV     BX,SAVEAX
+       CALL    OUTSTR
+       CALL    OUTSTR
+       MOV     BX,OP2
+       CALL    GETPORT
+       MOV     BX,MOV0
+       CALL    ONEOP
+       MOV     AL,','
+       CALL    PUTCH
+       MOV     AL,RAL
+       CALL    TRNTOK
+IODONE:
+       MOV     BX,RESTAX
+       JMP     OUTSTR
+OUT:
+       MOV     AL,[OP2]
+       XCHG    DX,BX
+       MOV     BX,OP1
+       CMP     AL,RAL
+       JZ      GETOUT
+       MOV     BX,SAVEAX
+       CALL    OUTSTR
+       MOV     BX,MOVAL
+       CALL    OUTSTR
+       CALL    TRNOP2
+       MOV     BX,CRLFTB
+       CALL    OUTSTR
+       MOV     BX,OP1
+       CALL    GETOUT
+       JP      IODONE
+GETPORT:
+       MOV     AL,[BX]
+       CMP     AL,'['
+       JNZ     NOBRAK
+       LAHF
+       INC     BX
+       SAHF
+       PUSH    BX
+       MOV     CX,80
+       MOV     AL,']'
+       UP
+       MOV     DI,BX
+       REPNZ
+       SCAB
+       MOV     BX,DI
+       LAHF
+       DEC     BX
+       SAHF
+       MOV     B,[BX],0
+       POP     BX
+NOBRAK:
+       MOV     AL,[BX]
+       CMP     AL,RGCL
+       JNZ     FIXPOR
+       MOV     BX,IO1
+       CALL    OUTSTR
+       XCHG    DX,BX
+       CALL    OUTSTR
+       MOV     AL,RDX
+       CALL    TRNTOK
+       MOV     BX,IO2
+       JMP     OUTSTR
+GETOUT:
+       CALL    GETPORT
+       JNC     RET
+       MOV     BX,BADIO
+       JMP     OUTSTR
+FIXPOR:
+       XCHG    DX,BX
+       CALL    OUTSTR
+       XCHG    DX,BX
+       JMP     TRANS
+LDAX:
+       MOV     BX,LDAX1
+LSAX:
+       CALL    OUTSTR
+       MOV     SI,DX
+       LODB
+       CALL    TRNTOK
+       JP      OUTSTR
+STAX:
+       MOV     BX,STAX1
+       JP      LSAX
+TRNTOK:
+       CMP     AL,' '
+       JC      $+5
+       JMP     PUTCH
+       PUSH    BX
+       PUSH    CX
+       MOV     CL,AL
+       MOV     CH,0
+       MOV     BX,TOKTAB-2
+       LAHF
+       ADD     BX,CX
+       RCR     SI
+       SAHF
+       RCL     SI
+       LAHF
+       ADD     BX,CX
+       RCR     SI
+       SAHF
+       RCL     SI
+       MOV     AL,[BX]
+       CALL    PUTCH
+       INC     BX
+       MOV     AL,[BX]
+       POP     CX
+       POP     BX
+       OR      AL,AL
+       JZ      RET
+       JMP     PUTCH
+PUSH:
+       MOV     DX,PUSHAF
+       JP      AFCHK
+POP:
+       MOV     DX,POPAF
+AFCHK:
+       MOV     AL,[OP1]
+       CMP     AL,RAX
+       JNZ     ONEOPJ
+       XCHG    DX,BX
+OUTSTR:
+       MOV     AL,[BX]
+       OR      AL,AL
+       JNZ     L0002
+       CALL    NEWOP
+L0002: 
+       CALL    PUTCH
+       INC     BX
+       ADD     AL,AL
+       JNC     OUTSTR
+       RET
+NEWOP:
+       MOV     AL,13
+       CALL    PUTCH
+       MOV     AL,10
+       CALL    PUTCH
+       MOV     AL,9
+       RET
+LDDR:
+       CALL    OUTSTR
+       MOV     BX,BLMOVE
+       JP      OUTSTR
+CPDR:
+       CALL    OUTSTR
+       MOV     BX,CMPREP
+       JP      OUTSTR
+ADD:
+       MOV     AL,[OP1]
+       CMP     AL,RBX
+       JZ      DAD
+ARITH:
+       CALL    OUTSTR
+       MOV     AL,[OP2]
+       OR      AL,AL
+       JZ      $+5
+       JMP     TWOOPS
+       MOV     AL,9
+       CALL    PUTCH
+       MOV     AL,RAL
+       CALL    TRNTOK
+       MOV     AL,','
+       JMP     TRAN1
+ACCUM:
+       CALL    OUTSTR
+       MOV     AL,9
+       CALL    PUTCH
+       MOV     AL,RAL
+       JMP     TRNTOK
+ONEOPJ:        JMP     ONEOP
+DAD:
+       MOV     BX,DAD1
+       CALL    OUTSTR
+       CALL    TWOOPS
+       MOV     BX,DAD2
+       JP      OUTSTR
+
+INCDEC:
+       MOV     AL,[OP1]
+       CMP     AL,RCX+1        ;16-bit?
+       JNC     ONEOPJ
+       MOV     BX,LAHF
+       CALL    OUTSTR
+       XCHG    DX,BX
+       MOV     BX,OPCODE-1
+       CALL    ONEOP
+       XCHG    DX,BX
+OUTSTRJ:
+       JMP     OUTSTR
+JUMP:
+       MOV     AL,[OP1]
+       CMP     AL,'['
+       JNZ     DIRECT
+       MOV     AL,[OP1+1]
+       MOV     [OP1],AL
+       XOR     AL,AL
+       MOV     [OP1+1],AL
+DIRECT:
+       MOV     AL,[OP2]
+       OR      AL,AL
+       JZ      ONEOPJ
+       CALL    FIXCON
+       MOV     BX,OP2
+OUTCON:
+       MOV     CH,AL
+       MOV     AL,'J'
+       CALL    PUTCH
+       MOV     AL,CH
+       CALL    TRNTOK
+       MOV     AL,9
+       CALL    PTRANS
+       MOV     AL,CH
+       CMP     AL,ODDPAR
+       MOV     BX,WARNPA
+       JZ      OUTSTRJ
+       CMP     AL,EVEPAR
+       JZ      OUTSTRJ
+       RET
+FIXCON:
+       MOV     AL,[OP1]
+       CMP     AL,RGCL
+       JNZ     RET
+       MOV     AL,CY
+       RET
+RETURN:
+       MOV     AL,[OP1]
+       OR      AL,AL
+       JZ      OUTSTRJ
+       MOV     BX,'R'+4500H    ;"RE"
+       MOV     [OP2],BX
+       MOV     BX,'T'
+       MOV     [OP2+2],BX
+       JP      DIRECT
+ONEOPJ1:
+       JMP     ONEOP
+DOCALL:
+       MOV     AL,[OP2]
+       OR      AL,AL
+       JZ      ONEOPJ1
+       CALL    FIXCON
+       DEC     AL
+       XOR     AL,1
+       INC     AL
+       MOV     BX,LABEL
+       CALL    OUTCON
+       MOV     BX,OPCODE-1
+       CALL    OUTSTR
+       MOV     AL,[OP2]
+       OR      AL,AL
+       MOV     AL,9
+       MOV     BX,OP2
+       JZ      L0003
+       CALL    PTRANS
+L0003: 
+       MOV     BX,CRLF
+       CALL    OUTSTR
+       CALL    TRANS
+       CALL    OUTSTR
+       MOV     BX,LABEL+4
+NEXLAB:
+       INC     [BX]
+       MOV     AL,[BX]
+       CMP     AL,'9'+1
+       JNZ     RET
+       MOV     B,[BX],'0'
+       LAHF
+       DEC     BX
+       SAHF
+       JP      NEXLAB
+EX:
+       MOV     AL,[OP1]
+       CMP     AL,RAX
+       JZ      OUTSTRJ1
+       MOV     AL,[OP1+1]
+       CMP     AL,STP
+       JZ      XTHL
+       MOV     BX,XCHG
+       CALL    OUTSTR
+       JMP     TWOOPS
+XTHL:
+       MOV     BX,XTHL1
+       CALL    OUTSTR
+       CALL    TRNOP2
+       MOV     BX,XTHL2
+OUTSTRJ1:
+       JMP     OUTSTR
+PSEUDO:
+       CALL    ONEOP
+       MOV     AL,[OP2]
+       OR      AL,AL
+       JZ      RET
+       JMP     TRNOP2
+       RET
+BITSET:
+       MOV     CL,0
+       JP      SETRES
+RES:
+       MOV     CL,-1
+SETRES:
+       CALL    OUTSTR
+       PUSH    BX
+       MOV     AL,[OP2]
+       CMP     AL,'['
+       MOV     AL,9
+       JNZ     L0004
+       CALL    BFLAG
+L0004: 
+       CALL    TRAN2
+       MOV     AL,','
+       CALL    PUTCH
+       CALL    GETBIT
+       MOV     BX,BITERR
+       JNC     L0005
+       CALL    OUTSTR
+L0005: 
+       POP     BX
+       JMP     OUTSTR
+
+BYTCHK:
+;Check if memory reference and add "B," for byte mode
+       CMP     B,[OP1],"["     ;Memory reference?
+       JNZ     RET
+       CMP     B,[OP1+1],RIX   ;Referencing IX as a word?
+       JZ      RET
+       CMP     B,[OP1+1],RIY
+       JZ      RET
+BFLAG:
+       CALL    PUTCH
+       MOV     AL,'B'
+       CALL    PUTCH
+       MOV     AL,','
+       RET
+
+GETBIT:
+       MOV     AL,[OP1+1]
+       OR      AL,AL
+       STC
+       JNZ     RET
+       MOV     AL,[OP1]
+       SUB     AL,'0'
+       JC      RET
+       CMP     AL,8
+       CMC
+       JC      RET
+       MOV     CH,AL
+       INC     CH
+       XOR     AL,AL
+       STC
+SHFT:
+       RCL     AL
+       DEC     CH
+       JNZ     SHFT
+       XOR     AL,CL
+       MOV     CH,AL
+       MOV     AL,'0'
+       CALL    PUTCH
+       MOV     AL,CH
+       RCR     AL
+       RCR     AL
+       RCR     AL
+       RCR     AL
+       CALL    HEX
+       MOV     AL,CH
+       CALL    HEX
+       MOV     AL,'H'
+       JMP     PUTCH
+OPTAB:
+       DW      AOPS,BOPS,COPS,DOPS,EOPS
+       DW      FOPS,GOPS,HOPS,IOPS,JOPS
+       DW      KOPS,LOPS,MOPS,NOPS,OOPS
+       DW      POPS,QOPS,ROPS,SOPS,TOPS
+       DW      UOPS,VOPS,WOPS,XOPS,YOPS
+       DW      ZOPS
+AOPS:
+       DM      'DD'
+       DW      ADD,OPCODE
+       DM      'DC'
+       DW      ARITH,OPCODE
+       DM      'ND'
+       DW      ARITH,OPCODE
+       DB      0
+BOPS:
+       DM      'IT'
+       DW      BITSET,TESBIT
+       DB      0
+COPS:
+       DM      'ALL'
+       DW      DOCALL,OPCODE
+       DM      'P'
+       DW      ARITH,CMP
+       DM      'PL'
+       DW      ACCUM,NOT
+       DM      'PIR'
+       DW      OUTSTR,CPIR
+       DM      'PDR'
+       DW      CPDR,DOWN
+       DM      'CF'
+       DW      OUTSTR,CMC
+       DB      0
+DOPS:
+       DM      'EC'
+       DW      INCDEC,OPCODE
+       DM      'JNZ'
+       DW      ONEOP,DJNZ
+       DM      'AA'
+       DW      OUTSTR,OPCODE
+       DM      'I'
+       DW      OUTSTR,OPCODE
+       DM      'W'
+       DW      PSEUDO,OPCODE
+       DM      'B'
+       DW      PSEUDO,OPCODE
+       DM      'M'
+       DW      PSEUDO,OPCODE
+       DM      'S'
+       DW      ONEOP,OPCODE
+       DB      0
+EOPS:
+       DM      'X'
+       DW      EX,EXAF
+       DM      'I'
+       DW      OUTSTR,OPCODE
+       DM      'XX'
+       DW      OUTSTR,EXX
+       DM      'QU'
+       DW      ONEOP,OPCODE
+       DM      'NDIF'
+       DW      OUTSTR,OPCODE
+       DB      0
+FOPS:
+       DB      0
+GOPS:
+       DB      0
+HOPS:
+       DM      'ALT'
+       DW      OUTSTR,HLT
+       DB      0
+IOPS:
+       DM      'NC'
+       DW      INCDEC,OPCODE
+       DM      'N'
+       DW      IN,INB
+       DM      'F'
+       DW      ONEOP,OPCODE
+       DB      0
+JOPS:
+       DM      'R'
+       DW      JUMP,JR
+       DM      'P'
+       DW      JUMP,JMP
+       DB      0
+KOPS:
+       DB      0
+LOPS:
+       DM      'D'
+       DW      LD,MOV
+       DM      'DIR'
+       DW      OUTSTR,UP
+       DM      'DDR'
+       DW      LDDR,DOWN
+       DB      0
+MOPS:
+       DB      0
+NOPS:
+       DM      'EG'
+       DW      ACCUM,OPCODE
+       DB      0
+OOPS:
+       DM      'R'
+       DW      ARITH,OPCODE
+       DM      'UT'
+       DW      OUT,OUTB
+       DM      'RG'
+       DW      ONEOP,OPCODE
+       DB      0
+POPS:
+       DM      'OP'
+       DW      POP,OPCODE
+       DM      'USH'
+       DW      PUSH,OPCODE
+       DB      0
+QOPS:
+       DB      0
+ROPS:
+       DM      'ET'
+       DW      RETURN,OPCODE
+       DM      'LA'
+       DW      ACCUM,RCL
+       DM      'RA'
+       DW      ACCUM,RCR
+       DM      'LCA'
+       DW      ACCUM,ROL
+       DM      'RCA'
+       DW      ACCUM,ROR
+       DM      'L'
+       DW      ONEOP,RCL
+       DM      'R'
+       DW      ONEOP,RCR
+       DM      'LC'
+       DW      ONEOP,ROL
+       DM      'RC'
+       DW      ONEOP,ROR
+       DM      'ES'
+       DW      RES,RESBIT
+       DM      'ETI'
+       DW      OUTSTR,IRET
+       DM      'ETN'
+       DW      OUTSTR,IRET
+       DM      'ST'
+       DW      ONEOP,CALL
+       DB      0
+SOPS:
+       DM      'UB'
+       DW      ARITH,OPCODE
+       DM      'BC'
+       DW      ARITH,SBB
+       DM      'LA'
+       DW      ONEOP,SAL
+       DM      'RA'
+       DW      ONEOP,SAR
+       DM      'RL'
+       DW      ONEOP,SHR
+       DM      'CF'
+       DW      OUTSTR,STC
+       DM      'ET'
+       DW      BITSET,SETBIT
+       DB      0
+TOPS:
+       DB      0
+UOPS:
+       DB      0
+VOPS:
+       DB      0
+WOPS:
+       DB      0
+XOPS:
+       DM      'OR'
+       DW      ARITH,OPCODE
+       DB      0
+YOPS:
+       DB      0
+ZOPS:
+       DB      0
+LDAX1: DM      9,'SI,'
+       DM      0,'LODB'
+STAX1: DM      9,'DI,'
+       DM      0,'STOB'
+PUSHAF:        DB      'LAHF',0,'XCHG',9,'AH,AL',0,'PUSH',9,'AX',0
+       DM      'XCHG',9,'AH,AL'
+POPAF: DM      'POP',9,'AX',0,'XCHG',9,'AH,AL',0,'SAHF'
+DOWN:  DM      'DOWN'
+UP:    DB      'UP'
+BLMOVE:        DB      0,'MOV',9,'SI,BX',0,'MOV',9,'DI,DX'
+       DB      0,'REP',0,'MOVB',0,'MOV',9,'DX,DI'
+       DM      0,'MOV',9,'BX,SI'
+CPIR:  DB      'UP'
+CMPREP:        DB      0,'MOV',9,'DI,BX',0,'REPNZ',0,'SCAB'
+       DM      0,'MOV',9,'BX,DI'
+DAD1:  DM      'LAHF',0,'ADD'
+DAD2:  DM      0,'RCR',9,'SI',0,'SAHF',0,'RCL',9,'SI'
+LAHF:  DM      'LAHF'
+       DM      0,'SAHF'
+DJNZ:  DB      'DEC',9,'CH',13,10
+       DB      '; *** WARNING: DJNZ does not affect flags - DEC does.',0
+       DM      'JNZ'
+WARNPA:        DM      13,10,'; *** WARNING: Parity flag not always same as Z80.'
+IO1:   DB      'MOV',9,'DI,DX',0,'MOV',9,'DL,CL',0
+       DM      'XOR',9,'DH,DH',13,10,9
+IO2:   DM      0,'MOV',9,'DX,DI'
+BADIO: DM      13,10,'; *** WARNING: Flags not same as Z80.'
+BITERR:        DM      13,10,' *** ERROR: Cannot determine bit number.'
+SETBIT:        DM      'LAHF',0,'OR'
+       DM      0,'SAHF'
+RESBIT:        DM      'LAHF',0,'AND'
+       DM      0,'SAHF'
+TESBIT:        DM      'RCR',9,'AH',0,'TEST'
+       DM      0,'RCL',9,'AH'
+XTHL1: DM      'POP',9,'SI',0,'XCHG',9,'SI'
+XTHL2: DM      0,'PUSH',9,'SI'
+EXX:   DB      'XCHG',9,'BX,[HL]',0,'XCHG',9,'DX,[DE]',0
+       DM      'XCHG',9,'CX,[BC]'
+EXAF:  DM      'LAHF',0,'XCHG',9,'AX,BP',0,'SAHF'
+MOVAL: DM      0,'MOV',9,'AL'
+IXSI:  DM      9,'MOV',9,'SI,[IX]',13,10
+IYDI:  DM      9,'MOV',9,'DI,[IY]',13,10
+RESTAX:        DB      0
+SAVEAX:        DM      'XCHG',9,'AX,SI'
+CRLFTB:        DM      13,10,9
+INB:   DM      'INB',9
+OUTB:  DM      'OUTB',9
+XCHG:  DM      'XCHG'
+JMP:   DM      'JMP'
+JR:    DM      'JMPS'
+RCL:   DM      'RCL'
+RCR:   DM      'RCR'
+ROL:   DM      'ROL'
+ROR:   DM      'ROR'
+SAL:   DM      'SAL'
+SAR:   DM      'SAR'
+SHR:   DM      'SHR'
+STC:   DM      'STC'
+IRET:  DM      'IRET'
+HLT:   DM      'HLT'
+CMC:   DM      'CMC'
+NOT:   DM      'NOT'
+MOV0:  DB      0
+MOV:   DM      'MOV'
+CMP:   DM      'CMP'
+SBB:   DM      'SBB'
+CALL:  DM      'CALL'
+TOKTAB:
+       DB      'SIDI'
+       DB      'PEPOS',0,'NSNZZ',0,'NCC',0
+       DB      'AXSPBXDXCX'
+       DB      'BLBHDLDHCLCHALIXIY'
+RWTAB:
+       DB      'ABCDEHLBDHSACNZNPMPPII'
+LENRW: EQU     $-RWTAB
+       DB      0,0,0,0,0,0,0,'CELPF',0,'C',0,'Z',0,0,'OEYX'
+HEADER:        DB      13,10,'Z80 to 8086 Translator  version 2.21',13,10,'$'
+NOROOM:        DB      13,10,'File creation error',13,10,'$'
+NOFILE:        DB      13,10,'File not found',13,10,'$'
+ENDMES:        DB      13,10,'Translation complete',13,10,'$'
+WRTERR:        DB      13,10,'Out of disk space',13,10,'$'
+OPCDER:        DM      13,10,'*** Opcode Error '
+CRLF:  DM      13,10
+LABEL: DB      'L0000',0
+       DM      ':',9
+PUTPT: DS      2
+GETPT: DS      2
+CHAR:  DS      1
+       DB      0
+OPCODE:        DS      80
+OP1:   DS      80
+OP2:   DS      80
+PUTBUF:        DS      128
+GETBUF:        DS      128
+PUTFCB:        DS      33
+       DS      50
+STACK: EQU     $
+       ORG     1       ;This is really just for equates without EQU
+RSI:   DS      1
+RDI:   DS      1
+ODDPAR:        DS      1
+EVEPAR:        DS      1
+       DS      5       ;MINUS,PLUS,NOT ZERO,ZERO,NOT CARRY
+CY:    DS      1
+RAX:   DS      1
+STP:   DS      1
+RBX:   DS      1
+RDX:   DS      1
+RCX:   DS      1
+RBL:   DS      1
+RBH:   DS      1
+RDL:   DS      1
+RDH:   DS      1
+RGCL:  DS      1
+RCH:   DS      1
+RAL:   DS      1
+RIX:   DS      1
+RIY:   DS      1
+\1a
\ No newline at end of file