;                            SIO2PC

;
; A communications program for linking an 8 bit Atari computer
; to a PC Compatible computer via the Atari's SIO connector
; and the PC's serial port.

;                CONVERTING TO QUICK-ASSEMBLER VERSION

;                       February 18, 1990

;            (first version begun on A86 assembler)
;
; last session 01/03/92
; again trying A86: 01/19/92
;
; NOTICE: WHEN USING A86, JUMPS TO LOCALS WITHOUT THE ">" SYMBOL
; FOR "FORWARD" ARE SUPPOSED TO GO BACKWARDS.  I HAVE NOTED THAT
; IF THE SAME LABEL IMMEDIATELY FOLLOWS A BACKWARD JUMP, IT WILL GO
; FORWARD ANYWAY.  USE A DIFFERENT (UNIQUE TO THE AREA) LOCAL NAME
; IN THIS CASE:

COMMENT\

EXAMPLE:

L1:     NOP     ; START LOCAL PROC
        NOP
        NOP
        CMP AL, STUFF
        JE L1   ; This will foul up and go forward
L1:     NOP     ; because this adjacent label confuses A86
                ; so, make the first  L1 be L2 instead and save
                ; much debugging!!!!!
ENDOFCOMMENT\

;
; this section of the code contains the "main loop," plus
; a few routines which didn't really fit the description of
; the other files; some Interrupt 023 and 024 routines and
; the QUIT routine, plus the stack and end of program label.
;
; The files necessary to assemble the complete SIO2PC other than
; this one are:
;
;  TEXT.S; PORTS.S; NUMBERS.S; DISKS.S; PRINTER.S; DIR_SUBS.S
;  BUSCMNDS.S; SCREEN.S; TIME.S; MACROS.S
;
; I assemble SIO2PC with the following batch file:
;

; A86 MACROS.S SIOTEXT.S PORTS.S NUMBERS.S TIME.S SCREEN.S PRINTER.S
; BUSCMNDS.S DIR_SUBS.S DISKS.S SIO2PC.S TO SIO2PC.COM
;
;
; *****************************************************************
; * NOTICE to persons in possession of this source code:          *
; *                                                               *
; * All commercial rights are reserved by the Author.             *
; *                                                               *
; * If you make changes or improvements, please contact me so I   *
; * can consider updating the original.  If you make changes and  *
; * distribute the program to others: Leave my sign off message,  *
; * add a revision # or note to the effect that the program has   *
; * been modified, put your own name and address after mine in    *
; * the sign off message.                                         *
; *                                                               *
; * Thanks,  Nick Kennedy, 300 South Vancouver, Russellville, AR  *
; * 72801, 501-967-3843                                           *
; *****************************************************************

; NOTE: See QA guide pg 79 for instructions for creating a COM file
; Program execution begins at label "INIT:"


; VERSION 1.01 USES DEFAULT PORT ADDRESSES IF NECESSARY
; VERSION 1.02 CURED SEVERAL BUGS, INCLUDING NO FORMAT IN 2.5 MODE
; VERSION 1.03 CHANGED STD TIME DLY ROUTINE TO TIMER_0
; VERSION 1.04 WILL ALLOW ENTRY OF PORT ADDRESSES MANUALLY
; VERSION 1.05 CHANGES THE SIO INTERFACE PROTOCOL, ADDS MYVEC8
;       timer 0 redirection to replace JIFFY. Also now programs
;       UART directly, not using BIOS. Added loopback test and LCR
;       read diagnostic. Added programming of timer 0. Made routine
;       getting filespec pad out RFSPEC with 0's. Removed bad write
;       to wrong segment in REG_INIT. Shipped 4/24/90.

; VERSION 1.06 STARTED USING NOTES WINDOW. Worked on loopback test.
;       Added option "R" to allow restoring screen. Added file
;       transfer, Atari to PC, routine FILE2PC. Changed enable/disable
;       on RTS line to be when SIO2PC addressed/not addressed.
;
; VERSION 1.07 MADE SOME CHANGES TO WRITE_DISK. I had function 03 but
;       should have been 03Eh to close file. Added the get directory
;       function to Options. Changed program end to DOS function 4Ch.
;       The program now asks if you really want to quit when a ramdisk
;       has been written to but not saved. The PRINTHRU function has
;       been started, but is not yet functioning.
; VERSION 1.08 PRINT_THRU MODE is working.
;
; VERSION 1.09 Added strip hi bit capability to PRINT_THRU
;
; VERSION 2.00 Allows deletion of ramdisks, making ram re-useable
;
; VERSION 2.1 Adds function to remote control program to send
;       ramdisk information to REMOTE.OBJ on Atari. Routine added
;       is called RMT_READ
;
; VERSION 2.2 will disable the data out line immediately after
; receiving DEVID if not an SIO2PC device. This is in hopes of curing
; the interference problem encountered by Joe Woyak and Rolf Beyer.

; VERSION 2.3 gets rid of the CTS line check completely. It also adds
; the lock RTS switch. It gets rid of the OPTIONS menu and puts all
; menu items on the same screen. Therefore, some menu choices are
; now addressed by different letters. Also, this revision adds another
; option for PRINT_THRU, allowing the printer data to be sent to
; a file.

; VERSION 2.4 Changed directory to show 4 files per line instead of
; 2, now max of 100 per page. Also change method of printing from
; PRINTL macro to DOS function 40 because file name could contain
; $. Added print functions for original 40 col Atari printer. Sends
; 29 or 20 chars to printer instead of 40. Also, printer STATUS
; routine now gets actual status from printer and sends 'E' to
; Atari if bad.
; This version also redirected the vectors for INT 024h AND INT 023h
; CRITICAL ERROR and BREAK vectors to prevent exit of program
; without ending timer interrupt routine. Added "SHAREWARE" message
; at end of program.

; Rev 2.5: Adding user command "A" to adjust timing values. Allows
; user to set critical time delays used in the bus data transfers,
; to try to iron out differences between different systems. This
; addition is menu choice "A" and adds the TIMING menu.
;
; Rev. 2.6: Rewrote PRINTER routine to more closely emulate 850
; interface. Moved timer values to front of program and added
; ASCII flags so user can use DEBUG to change program. 12/30/90
;
; Rev. 2.7: Changing PRINT_THRU routine so it will check for a
; disk full error and notify user, and terminate PRINT_THRU
; process.

; Rev 2.8: Fixed a bug in PRINT_THRU introduced by 2.7 in which
; converting EOL's  would lock up the PC if the EOL were found to
; be byte # 40. Also changed so consequtive EOL's no longer put
; spaces between CR/LF's after conversion. Also fixed so ESCAPE
; key also restores the menu.
;
; Rev 2.9: Added "disk full" error trapping for routines which
; write to disk, especially PRINT_THRU and FILE2PC. (Write ramdisk
; already had error trapping.)
;
; Rev. 2.10: Added location and error codes to PRINTER routine
; for better error trapping. Also added a timing value to the
; timings menu for output to the printer.
;
; Rev. 2.11: Added a byte count to sign off message to help users
; discover virus infection.
;
; Rev. 2.12: Adding routine to allow extracting directory info
; from Atari disk image files. This was completed for Atari DOS and
; compatibles only.  I also put in the start of the required
; recursive routines to dig out MYDOS subdirectories, but did not
; complete it in revision 2.12
;
; Rev. 3.0:  This revision will allow reading directly from a
; physical disk file, without using a ramdisk intermediary. The intent
; is to allow disk image files of unlimited size. Begun 11/10/91
; This rev. will move MACROS to a file MACRO.ASM and INCLUDE them.
;
; Rev. 3.01: Fixed PUT_SECNO so it doesn't unless cmnd is P, W, or R.
; Added JMP RED1 after CALL GET_CONFIG.  Previously, it went to U13
; which updated the status line, taking too much time.  In READ_DSK,
; added the line to change DSK_FLAGS when the LOAD_OPT is /N.
; Now the "don't format physical disk" option does work.  On
; the QUICKA version, I changed the IF NOT ONECHIP to IFE ONECHIP
; after I realized that NOT does an EOR, so a non zero number still
; ends up non zero unless it were all 1's to start with.  This had
; been causing major problems with the ONECHIP version.  Changed the
; CUSTOM message to say 65535 sectors max instead of 16535.  Fixed the
; number of characters to be input for disk size from 5 to 6 because
; the CR counts as one.  Previously, one could only go with 4 digits
; maximum.  Corrected the math which converted the number of sectors
; to the size in paragraphs.  There was an error for LARGE disks
; because I was failing to left shift the high word for each "times 2"
; operation.  Fixed the PUT_DEVID routine, because it wouldn't - in
; some cases.

; Rev. 3.02: Found data out line wasn't always getting disabled.  Put
; a CALL DISABLE at front of RED1 in hopes of curing this.  It seems to
; have worked.
;
; Rev. 3.03: Added CRC check and file size check for virus protection.
; Added routines V_CHECK, GET_CRC, DO_CRC, INC_CRC
; Changed FILE2PC so it would write the whole file (forgot to save
; X before using LDA ICBLL,X to load remaining bytes)
;
; REV 3.04: changed directory logic so separator is '.' for normal
; file and '*' for subdirectory, per original intent.  I also added
; SPARTADOS compatibility for the directory extraction function.
; Disk image files ending in 'S' are now treated as SPARTADOS images
; and the directory is expanded, including sub-directories! I moved
; the directory functions to the SIOSUBS file.
;
; REV 3.05: did some tweaks on the main loop and think I got rid of
; at least one bug there.  Added a group of size choices for
; SPARTADOS to the CREATE disk option.  Moved the density selection
; to a sub function of CREATE.  Added the "simulated disk" option
; Menu choice "I" to allow direct access to a PC file.
;
; REV 3.06: did away with the ONECHIP flag.  Now there are variables
; REV_FLAG and TX1A. TX1A is copied from REV_FLAG at startup. If TX1A
; is 'i', the system will respond as necessary for the ONECHIP design.
; It does this by toggling the zero flag after comparisons involving
; the RI bit of the MSR.  REV_FLAG can be found easily by DEBUG near
; the program's start.  Also, a new option under the "A" submenu
; allows changing it during program execution.
; Changed the way the system responds to framing errors on the serial
; bus when High Speed has been in use.  Now, it toggles from hi to lo
; or lo to hi whenever a framing error is read during a command frame
; providing a '?' get high speed index has been read as indicated by
; a 'Y' in the EVER_HI variable.
;
; REV 3.07: Print-thru now offers the option of converting ATASCII
; tabs (07Fh) to standard ascii tabs (09h).

; REV 3.08: First correction makes the FIX OLD DISK command accept
; upper or lower case 'Y'; Main improvement adds the DOS SHELL "H"
; command. Also added the capability of the program to fix its internal
; CRC if the user chooses.
;
; REV 3.09
; Fixed the TO_UPPER sub to it only converts lowercase letters, I found
; that installing a PC which had numbers in its filename file as a disk
; caused the numbers to change to graphics symbols.

; REV 3.10
; Made some changes to the SIMULATED disk:
; Now, if the Atari tries to write this the SIM disk, an error isn't
; returned (just an 'S' to the ERR column of the status line).  Instead
; the system "pretends" to write the sector.  Also, the SIMULATED disk's
; status is no longer "locked" or "in use" as shown by the status
; byte in the directory sector.  The sim. disk now reports data sectors
; as 401 thru 700, then repeats, instead of just using sector #100 for
; all sectors.  Also, no error is returned for requesting the wrong
; sector number.  I also added the /B (boot disk) option to the Install
; PC disk feature, but haven't tested it.
;
; REV 3.11: BOOT disk option for SIM disk tested, added message to
; notify user how to install
; NOTE: I had a 3.12, but that was just Carl M's remote interface
; I've decided to withdraw back to 3.11 ...

; 3.12: I had something wrong with the extract directory function for
; SPARTADOS, which is fixed.  Something to do with local labels.  Also
; added an ESC bailout to the directory function.

; 3.13: doubled some printer timeout numbers due to a user complaint.  I'm
; not sure yet if it helped ...

; 3.14: I found that simulated disk access had slowed down.  It turned out
; that I had used "T1" as a local code label in two places, causing the
; addresses to supersede the word value T1 had as a bus timing variable!!
; Fixed by changing T1 code labels to L1s.
; 3.15: Added screen blank via B key.  Not shown on menu.

; 3.16: Trying to fix a bug which causes an INT 024 hardware error on
; startup.  It seems to be caused by the drive # stored at CUR_DRIVE, see
; subs. GET_DRIVE and GET_DIR.	Note that DOS sometimes uses A = 0, and
; other times uses different method of drive designation.

; 4.00: Added the 1050-2-PC routines for direct connection to a disk drive
; using different hardware.  4.01 was a minor enhancement

; 4.02: Worked on the 1050-2-PC routines in preparation for shipping first
; two units. Added retry on error to the disk copy routine; and bail-out
; via ESCAPE to a couple of routines. Worked with SIM DISK routines some
; seems to be some minor problems.  May need more work.

; 4.04: Fixed SEC_ADR in BUSCMNDS.S so sector #0 will no longer be
; accepted.  DOS's and user programs shouldn't ask for the invalid
; sector 0, but if they did, on a write, SIO2PC would overwrite program
; space and crash.

COMMENT^  REV. 3.17  2/10/94

Bug fixes and enhancements suggested by Terry Chamberlain's letter.

Increased the time on several bus timing constants.

Changed the editor so the user can backspace normally, but most non-
printing characters are outlawed.  Changed the routine which gets the
number of sectors desired under Create Disk option 5 to use this
editor instead of DOS input.

Fixed the load option so the /P doesn't seal in - clears it before
each subsequent choice.

Worked on the direct access disk feature a bit.  I had a complete
lockup before I changed a few things.  Seems to work OK now.

Fixed the SPARTADOS extract directory.	It had degraded to the point
that it didn't show all files and never extracted subdirectories.

Changed the DOS SHELL routine so it gets the COMSPEC path name from
the environment string instead of assuming C:\COMMAND.COM.

Made many changes to the 6/More  sub-option under Create Disk.	Mostly
I got rid of the 28 sector/track choices and added 26 sector/track.  I
also change Create option 3 from 143K to 133K because 1050 enhanced is
actually 1040 sectors, not 1120 as I had thought.

REV 3.18:

Changed the TIMER_0 routine.  It formerly tried to keep track of
counts in the timer chip's timer 0 "on the fly."  I've come to believe
that the rollover from 0 to 65535 has never been adequately addressed,
so now my routine programs the counter to a known initial count
(0 or effectively, 2 to 16th), and watches for it to decrement to the desired
count.	Also, I discovered that timer_0 normally runs in mode 3, not
mode 2 as I had thought.  More importantly, I found that in mode 3
the counter counts down by TWOS!  This explains why the timing seemed to
be twice as fast as I calculated.  Each count actually represents
420 nanoseconds, not 840 as I had thought!

REV 3.19:

Good Grief!! The improvement I made in TIMER_0 above causes WRITE and
PUT actions to sputter along and stop at random.  I couldn't figure out
why, so I put TIMER_0 back the way it was.
OK, at 3.19 and 1/2, I finally figured out that a JA branch opcode
should have been a JB!	So I'm back to the new improved version, which
is working OK, tested for read, write, format, and FILE2PC.

REV 4.0:

I added the 1050-2-PC functions and decided to go up to the next
integer revision numbers. Currently, read 720 sectors, read 1040 sectors
and read user defined block of sectors is working.

REV 4.05:

Added a bunch of new features to 1050-2-PC.  Format, emulate bad sectors
debug style screen of sector data, etc.

REV 4.06:

Took out the DO_TIME crude timing routine.  It finally caught up with me
on fast PENTIUM PC's.  Replaced with the timer_0 interrupt routine
counting down.  It was only used in the PUT1 and PUT1A routines
anyway.

REV 4.07:

Took a couple of bugs out of how 1050-2-PC sends bad sector status.
Added MT-550 to empty a 16550 buffer and called it once per init of
COM port and once per pass thru the main loop (no command frame in
progress).  Changed VID_INIT so it puts the screen in mode 3 instead
of mode 2.  Mode two caused weirdness such as a 43 line screen on
following programs.  Also in CON_COM, put the 16550 in the character
(not the FIFO) mode.  Haven't tested this on a real 16550, but it
didn't mess up anything on my 486 or 286.

REV 4.09:

Added diagnostic routines.  Added the A, G menu on SIO2PC and DIAGS.OBJ
for the Atari.  12/3/95

Rev 4.10:  I discovered that adding some time to T7 (time between UART
accesses) completely cured the halting behavior I see on my '486.  I
started with 000A (4.5 us) but went to 0005 and it worked too.  Settled
on 0008.  12/4/95
Also, fixed a bug where the MCR wasn't being initialized.  This isn't
usually a problem, but some computers apparently come up with LOOPBACK
turned ON!!
Changed TIMER_0 routine so it actually uses timer #2.  This is because a
routine using VARBL was repeatedly calling TIMER_0, and therefore, it
couldn't timer out and decrement VARBL.
I changed the programming of the BAUD rate from a 16 bit out to two
8 bit outs with delay between, because I'm not sure I trust that 16 bit out.
Added a "hidden" menu function M, which is temporary to allow setting the
MCR's lower 4 bits.

4.11 - Remove menu function M; DELETE function wasn't checking for
SIM DISK and closing file if so.  Fixed.  Fixed some other file handle
open/close problems.  Removed CALL RESETDTA from DOS dir function - it
messed up drop down dir which expected my DTA to be in force

4.12 - Fixed problem with multiple disk loads from command line, added some
more delays between IN's and OUT's, fixed double backslash in path when in
root directory.  After DOS directory or DOS Shell, file selector box
didn't work - fixed that.  Some other problems with file selector box -
error in page down function fixed and error caused by bad path couldn't be
corrected - fixed it.

4.13 - Fixed an error causing lockup when at the bottom of the file selector
list and pressing a key not resulting in a matching file.  Also, fixed the
feature that puts the simulated directory sector name in the simulated
directory.  Made the space bar work the same as [TYPE SPEC] in the file
selector box.

4.14 - In 1050-2-PC, fixed "press any Key" prompt so it doesn't happen if
there are still chars in the command tail.  Also made a change so extended
characters in the drop down dir box don't do a bogus search!!

4.15 - Fixed formatting error in 1050-2-PC: CMND was being change by
STATUS call after having been set up with format command code. Also
added the BEEP functions and beeps now occur when errors are
encountered in 1050-2-PC sector I/O.  9/96

4.16 - Added low click for read sector and high click for write sector

4.17 - 1/20/97 - fixed ALF routine in 6SCREEN.S so it doesn't fail on 'Z'

4.17 - 8/26/98 - fixed the fact that for large numbers of files in a dir,
the selector box would load the wrong file.  This was due to an 8 bit
multiply MUL BL instead of 16 bit MUL BX in TAKE_IT in DIR_SUBS.S

4.18, 4.19 - 10/5/98  Fixed some stuff I don't even remember well--Oh!
; I moved the sending of the C (complete) to the end of the routine in
; either PUTSEC or GETSEC.  Also made the Timings menu show that T7 =
; 8 as it has been since rev. 4.10

ENDOFCOMMENT^
COMMENT"


This program is intended to allow the PC to interface with an 8 bit
Atari computer, via the PC's RS232 port and the Atari's serial interface.
In this implementation, the PC will emulate an Atari disk drive. The
Atari will not require any special software whatsoever, and can
actually boot from the PC.
"

C_INFO1 EQU 1200h ; cursor position for info line1
C_INFO2 EQU 1300h
C_INFO3 EQU 1400h

; THE PROGRAM BEGINS EXECUTION HERE:

;               USER INTERFACE:

; This section of the program puts up a menu screen and gets
; configuration information from the user or from the command
; tail.

INIT:
        CLI
        MOV AX, OFFSET MY_STACK; Lower the stack pointer
        ADD AX,0FFh
        MOV SP,AX
        STI
        CALL VID_INIT
        CALL GET_SCRN   ; Get the screen segment into SCR_SEG
                        ; and set COLOR flag
        CMP COLOR, 0
        JNE >L1
        CALL DO_MONO    ; set all attributes to 07 for mono
L1:     CALL INEXTS     ; init next sector pointer.
        CALL ZSTARS     ; Zero STARS to show no Rdisks yet
        CALL PUT_SIZE   ; fill in ASCII size for sign off msg
        MOV AL,DS:[80h]   ; Get command tail length
        MOV TAIL_CNT, AL; and init counter with it.
        MOV AL,081h      ; Init tail pointer for GET_TAIL
        MOV TAIL_PT, AL
        MOV LOCK_RTS,0  ; RTS not locked on.
        CALL PRG_T0
        MOV CRITIC,0    ; Flag no critical error
        CALL SET_NEW24  ; Set new INT 024 handler
        CALL SET_NEW23  ; Set new INT 023 handler
        CALL SETUPV8    ; Redirect INT 08 for my routine MYVEC8
        CALL V_CHECK    ; Check CRC and file length for virus 3.03
; Init for directory and path functions:


; 4.10 - since I'm going use to timer #2, I need to turn off sound:


	MOV DX,061h     ; TTL control port
	IN AL,DX
;        CALL ACC_DLY ; 4.12
        CALL ONE_TIK
        OR AL, 1 ; must gate ON for counter 2 to receive input
        AND AL, 0FFh - 8 ; turn bit 3 off to kill sound
	OUT DX,AL
        CALL ACC_DLY ; 4.12

; REV 3.16: CHANGE ORDER OF NEXT TWO CALLS, BECAUSE GET_DIR USES
; THE CUR_DRIVE # GOTTEN BY GET_DRIVE ...
; 3.16 also changed GET_DIR: see DIR_SUBS.S

        CALL GET_DRIVE; Store drive # @ CUR_DRIVE
        MOV AL,B[CUR_DRIVE]
        ADD AL,'A'; Change drive # to drive letter, 0 = A.
        MOV [OLDRIVE],AL
        MOV [NEWDRIVE], AL

        CALL GET_DIR; Store path at OLDPATH

        SMOVE OLDPATH, NEWPATH, 64 ;; 4.11 initializes New = Old path
        FIND_BYTE NEWPATH, 0, 64 ;; find end of string and add \
        CMP B[DI-2], '\' ; already got \ ?  4.11c
        JE > C1
        MOV B[DI-1], '\' ; as preface to adding search spec
C1:     CALL CONCPATH ; add default *.* to search spec
        CALL GETDTA; Save address of current DTA set by DOS.
        CALL SETDTA ; added here by 4.11

; Initialize parallel port addresses for Carl M.'s interface:
        #IF CARLM
PP_INI:
        MOV AX, 0040h; BIOS DATA AREA
        PUSH AX
        POP ES
        MOV AX, ES:[08] ; parallel port LPT1 address
	CMP AX, 0	; if no address, use default
	JE > L1
        MOV PP_OUT1, AX
        INC AX
        MOV PP_IN, AX
        INC AX
        MOV PP_OUT2, AX
L1:	PUSH CS
        POP ES
        #ENDIF

; Initialize DOS SHELL data (rev 3.08)


        PUSH CS
        POP AX
        MOV PBS1, AX
        MOV PBS2, AX
        MOV CTS, AX


; NOTE: THE QUICKASSEMBLER VERSION CALLS PUT_SIZE HERE; I THINK
; A86 VERSION DOESN'T NEED IT?? (FOR VIRUS MESSAGE)

        MOV B[ACOMN],'?'   ; Rev. 2.7 - if program is restarted,
        MOV AX,'xx'     ; get these fields and flag back to
        MOV WORD PTR CMTXT,AX   ; default values
        MOV WORD PTR [CMTXT+2],AX
        MOV CONFIGD,0

        CALL CLR_SCRN
        CALL DO_MENU
        CALL PUT_RAM; REV 3.04
        CALL WS240      ; Set up status line

	CMP B[REV_FLAG], 'i' ; REV 3.20
	JNE > L1
	CALL RTS_UP ; command line high for 1050-2-PC
L1:     PSTATUS PRMT_COM, ATTR9
        CALL COM_SET
        JNC SETUP; No carry = no error
        CMP CONFIGD, 0; If already configured, disregard error
        JE L1; Else, demand a port #!

        MOV AL,' '; Start with "no input"


;               SETUP

; A routine which gets characters from the command tail
; or from the user (kybd) and sets up the program as 
; directed. It continues to look for input until Run or
; Quit command is received. Returns with Q or R in AL

; 10/30/89: SETUP will now be in-line, not a subroutine.

SETUP:

;        PUSH AX
;        MOV AL, 'H'
;        CALL PUT_LOC
;        POP AX
        AND AL,11011111xB; convert to uppercase
        MOV CCRUD, AL   ; save user's menu choice
        MOV XCRUD, AL

; Now, check for valid command and call routine if good:

        CMP AL,'S'; Set COM port #?
        JNE >L2
        MOV DH, 20; Line #
        CALL C_LINE
        PRINTL CHPN
        PSTATUS PRMT_COM, ATTR9
        CALL COM_SET
        CALL CLR_ALL
        JMP XI1 ; Go get more config info

L2:     CMP AL,'A'      ; Adjust timings, rev. 2.5
        JNE >L1
        CALL CLR_SCRN
        CALL TIMING ; in file TIME.S
        CALL FIX_SCRN
        JMP XI1

L1:     CMP AL,'L'; Load ramdisk from real disk?
        JNE >L3
        CALL READ_DSK
        CALL CLR_ALL    ; clear info and status lines
        CALL SU_DSKHDR
        JMP XI1

; Rev 1.08 moved R from options to main menu

L3:     CMP AL, 'R'; Restore screen/menu
	JNE >L1
	CALL FIX_SCRN
	 JMP XI1

L1: CMP AL,27; ESCAPE? REV 2.8: ESCAPE FIXES SCREEN
        JNE >L4
;        CALL CLICK_ME this was just for test
        CALL FIX_SCRN
        JMP XI1

L4:     CMP AL,'C'; Create ramdisk?
        JE >D3
        JMP NEAR DD2

D3:     MOV CCRUD, 'C'; assume single density: 3.06
        PSTATUS D_OR_S, ATTR9 ; REV 3.05; put density choice here
	CALL GET_TORK
	AND AL, 11011111xb

	CMP AL, 'S'
        JE >F1
	CMP AL, 'D'
        JNE L1
	MOV CCRUD, 'Z'; "Z" tells other routines double density

F1:     MOV DH, 20; Info line #1
	CALL C_LINE
	PRINTL CRAMD; Tell what's happening
	PSTATUS PRMT_DSK, ATTR9
	CALL CRUD
	CALL CLR_ALL
        JMP XI1


DD2:     CMP AL, 'I'; 3.06
        JNE >L1
	CALL INST_PC
	CALL CLR_ALL
        JMP XI1

L1:      CMP AL, 'W'
         JNE >L5
         CALL WRITE_DISK
         CALL CLR_ALL
         JMP XI1

L5:     CMP AL,'X'
        JNE U8
        CALL XCHANGE
        CALL CLR_ALL
        JMP XI1

U8:     CMP AL,'T'; Toggle status line usage
        JNE >L1
        CALL TOG_STAT
        JMP XI1

L1:     CMP AL,'Q'
	JNE >N1
        JMP GDOS; Quit if 'Q'

N1:	CMP AL,'U'
        JNE >L1
        PSTATUS PRMT_DSK, ATTR9
        CALL GET_DISKNO
        CMP ERROR,27
	JE N1
        CMP ERROR,'N'
	JE N1; Don't need to delete if it doesn't exist
        CALL DELETE
        JMP XI1


L1:     CMP AL,'E'; Enter port address manually
        JNE >L6
        CALL MAN_PORT
        JMP XI1

L6:     CMP AL,'D'; Print directory
        JNE >L1
        CALL DODIR
        CALL FIX_SCRN
        JMP XI1

L1:     CMP AL,'K'; Lock Data Out Line (RTS) on (toggle)
        JNE >L7
        CALL LOCK_IT
        JMP XI1

L7:     CMP AL,'P'; PRINT_THRU mode
        JNE >L1; CHANGE TO >L1 WHEN OPTION 'A' READY *** 2.2***
        CALL PRINT_THRU
        JMP XI1

L1:     CMP AL, 'J'; Jmp to ultra speed (toggle)
        JNE >S8;         3.08
        CALL TOG_SPEED
        JMP XI1

S8:     CMP AL, 'Z' ; toggle sound ON/OFF (4.16)
        JNE > L8
        CALL SNDONOFF
        JMP XI1

L8:     CMP AL, 'H'     ; 3.08 - exit to DOS SHELL
	JNE > L1
        CALL TO_DOS
	JMP XI1

L1:	CMP AL, 'B'
        JNE > L9
	CALL BLANKIT ; blank the screen
        JMP XI1

L9:
;        CMP AL, 'M' ; change MCR bits - 4.10 - 4.11 removes
;        JNE XI1
;        CALL EXP_MCR ; change bits 0 - 3 of MCR


; Are there any characters in command tail?
; If not, fall thru and run program

XI1:    CALL GET_TAIL
        CMP AL,0
        JE > U13 ; 4.10 added > symbol for forward.  Needed??
        JMP SETUP

; Wait for the Atari COMMAND line to go low. (Connected to RI on port)


U13:	CMP BLANK, 0
	JNE RED1 ; if BLANK non-0, don't print to screen
	PSTATUS RUNNG, ATTR9
        CURSET 01700h

RED1:
;        MOV AL, 'G'
;        CALL PUT_LOC
        CALL DISABLE    ; REV 3.02 - RTS wasn't getting disabled!
        MOV DX, MSR    ; Read modem status register
        IN AL,DX        ; Read to reset TERI
        CALL ACC_DLY    ; 4.10
        CALL CK_LINES   

NCMND:
	#IF CARLM

; joystick support for CARL's interface

	CMP JOY, 0
	JZ > L1
	MOV JOYSTAT, 0 ; initialize
	MOV AH, 084h ; joystick support function
	XOR DX, DX ; read switch settings
	INT 015h
	JC > L1 ; carry set means error
	AND AL, 00110000xB ; b4&3 are stick A button statuses
	JE > L2 ; jump if no button pressed
	MOV JOYSTAT, 16; set bit 4
L2:	MOV AH, 084h
	MOV DX, 1 ; now read stick position
	INT 015h
	JC > L1
	CMP BX, 50 ; < 50 means UP
	JA > L3
	OR JOYSTAT, 1 ; set UP bit
	JMP > L4
L3:	CMP BX, 150 ; > 150 means DOWN
	JB > L4
	OR JOYSTAT, 2
L4:	CMP AX, 50; < 50 means LEFT
	JA > L5
	OR JOYSTAT, 4
	JMP > L6
L5:	CMP AX, 150
	JB > L6
	OR JOYSTAT, 8
L6:	CALL SEND_JOY

	#ENDIF
;        MOV AL, 'N'
;        CALL PUT_LOC


L1:     CALL MT_550     ; 4.07 - keep the 16550 empty when no cmnd going
        MOV AH,1        ; is a key ready for input?
        INT 016h
	JNZ > L9	; 3.14 + ... fix long jmp, was JZ XR1
	JMP XR1 	  ; zero means no key ready
L9:
        #IF CARLM

        CMP CARL, 0     ; in remote keyboard mode?
        JE >L1         ; CARL = 0 means not in remote mode
        CALL CM_LOOP
        JMP XR1         ; see if SIO bus active

        #ENDIF

L1:     MOV AH,0        ; else, input the character
        INT 016h
        CMP AL,27       ; ESCAPE pressed?
        JNE >L1
        CMP FTSTATS,0
        JE >L1           ; If 0, not in File transfer mode
        MOV FTSTATS,1    ; Else, flag that ESC has been pressed
        MOV B[F2P_STAT+3],0FFh; And make next status tell Atari
L1:
        #IF CARLM

        TEST AL, AL      ; check for function key (Carl)
        JNE >L2
        CMP AH, 044h    ; F10 key pressed?
	JNE >L3
        MOV CARL, 0FFh ; turn remote kybd mode on
        CALL CLR_SCRN
	CURSET 0500h
	PRINTLA CM_ON, ATTR9
        TICKS 36
	JMP NCMND
	JMP > L2
L3:	CMP AH, 043h ; F9 key for joystick monitoring
	JNE > L2
	CALL JOY_ON  ; toggle ON/OFF
	JMP U13

        #ENDIF

L2:     JMP SETUP


; Note: when bit 6 of MSR = 0, this means that the RI input is
; logic 1; or command line is HIGH (TTL 1) or, RS-232 line is at
; -10 volts: all mean the same thing. With the ONECHIP design
; the line status is same at PC as at Atari. With the old design
; the RI line is inverse on PC due to inversion on board.


XR1:
        MOV DX, MSR
        IN AL,DX        ; Make sure it was for real...
        CALL ACC_DLY ; 4.12
        CALL CK_LINES
        AND AL,01000000xB ; This time checking actual RI bit...
        LAHF    ; 3.06 - complement ZF if ONECHIP. AH <- FLAGS
	CMP [REV_FLAG], 'i'
        JNE >L1
        XOR AH, 01000000Xb; complement ZF
L1:     SAHF; FLAGS <- AH
        JE >A1 ; 3.12 cure long jump
        JMP NCMND
A1:
;        MOV AL, 'I'    ; Update debug info
;        CALL PUT_LOC

; Clear the breech by reading a byte from the receive register

; 4.10 removed clearing of DLAB - already clear
        
;        MOV DX, LCR ; Clear DLAB to 0
;        IN AL,DX
;        CALL ACC_DLY
;        AND AL,01111111xB
;        OUT DX,AL
;        CALL ACC_DLY
;
        MOV DX, BAUD ; Read the register
        IN AL,DX;       Throw away this byte...
        CALL ACC_DLY

; First, clear any error bits from LSR: (REV 3.01)

	MOV DX, LSR
	IN AL, DX
        CALL ACC_DLY
;
; Now read characters from the port. Command frame is 5 bytes long.
; First, get 4, computing checksum...

; First, a routine to time out if no data forthcoming in 55 to
; 110 mSec.
;        MOV AL, 'T'
;        CALL PUT_LOC
        MOV VARBL,10; 3.06
L2:     MOV DX, LSR
        IN AL,DX        ; First see if a byte is ready
        CALL ACC_DLY
        CMP EVER_HI, 'Y'
        JNE >N1
        TEST AL, 8      ; Framing error?
        JE >N1
        CALL CAN_CFB    ; Cancel frame
        JMP RED1
N1:     AND AL,1
        JNZ >L1         ; branch if byte waiting...
        CMP VARBL,0
        JE AAZ         ; loop until timed out... REV 3.06
        MOV DX, MSR     ; 3.05
        IN AL, DX
        CALL CK_LINES
        AND AL, 01000000XB
        LAHF
        CMP [REV_FLAG], 'i'
        JNE >L3
        XOR AH, 01000000xB
L3:     SAHF
        JE L2  ; JNE MEANS CMND LINE IS HIGH
        JNE PUT_F  ; JE MEANS CMND LINE IS LOW

AAZ:    CMP EVER_HI, 'Y'
        JNE PUT_F
        CALL CAN_CFB
PUT_F:  MOV ERR_CHAR, 'f'
        CALL PUT_ERCH

        JMP RED1        ; else abort attempt to get cmnd frame

L1:     CALL GET1; Get DEVID
        JC AAZ

        MOV DEVID,AL

; First, see if we are the device being addressed, if not, just
; ignore the command frame received.

        CALL SET_BP     ; sets BP, NC if good device and VALID <> 0
        JNC G3MORE

; I'm still going to get the rest of the frame, cause I want to
; update the STATUS line for the user's info. (Unless bad CKSUM)

; As of REV 3.06: if the speed has been EVER_HI, a framing error
; will cause toggle  of speed and cancel of CFB


G3MORE:
;        MOV AL, '3'
;        CALL PUT_LOC
        MOV CX,3
        MOV BL,DEVID
GET3:
        CMP EVER_HI, 'Y'; REV 3.01 for ultra speed
        JNE >L1
	MOV DX, LSR
	IN AL, DX
        CALL ACC_DLY
	TEST AL, 8      ; Framing error?
        JE >L1          ; No error
	CALL CAN_CFB    ; Cancel frame
        JMP RED1

L1:     CALL GET1
        JC AAZ   ; carry set means timed out in GET1
        MOV SI,CX
        MOV [CFCKSM+SI],AL ; Store the command frame bytes
        CLC     ; do checksum math
        ADC BL,AL
        ADC BL,0

        LOOP GET3

; Now get checksum and store it...

        CALL GET1
        JC AAZ
        MOV CFCKSM, AL
        
        CMP BL, CFCKSM
        JNE AAZ  ; Abort the whole thing if bad CKSUM

; 3.05 moved block below. was after checking cmnd line raised:

        MOV AL, DEVID; Device ID from cmnd frame, 31 - 34
        CALL BYTE2HEX
        CALL PUT_DEVID
        CALL PUT_COM    ; REV 3.00: This call formerly followed
        CALL PUT_SECNO
        CMP VALID,0     ; the JNE >L1 below
        JNE ABA
        JMP RED1

; At this point, we have successfully read a command frame. Now, wait
; for the computer to raise the command line:

ABA:    MOV VARBL, 2; 4.08 - did use BX in a crude counter for timeout
;        MOV AL, 'n'
;        CALL PUT_LOC
B1:     CMP VARBL, 0
        JNE >L1 ; timed out, cmnd line didn't go high
        MOV ERR_CHAR, 'q'
        CALL PUT_ERCH
        JMP RED1
L1:     MOV DX, MSR
        IN AL,DX
        CALL ACC_DLY ; 4.12
        CALL CK_LINES
        AND AL,01000000xB
        LAHF    ; 3.06 - complement ZF if ONECHIP. AH <- FLAGS
	CMP [REV_FLAG], 'i'
        JNE >L4
        XOR AH, 01000000xb; complement ZF
L4:     SAHF; FLAGS <- AH
        JE B1

; Now, disk does exist so put starting segment for this
; disk into the DVSEG variable

;        MOV AL, 'Y'
;        CALL PUT_LOC

        CALL ENABLE
        MOV CX, [STARS+BP]
        MOV DVSEG, CX

;       Device #40h is the printer
        CMP DEVID,040h
        JNE >N2 ; was ADK
        CMP [PRINTHRU],0; 0 Means no PRINT_THRU mode
        JE >L1
        CALL PRINTER
L1:     JMP RED1 ; this shouldn't be possible at this point




N2:     CMP DEVID,03Ah; File transfer to PC file? label was ADK
	JNE >L2
        CALL FILE2PC
        JMP RED1
L2:	CMP B[WRITTN+BP], 'S'; simulated disk (PC file)?
	JNE >N1
        CALL SIM_IO
        JMP RED1

N1:	MOV AL,[CMND]
        CMP AL,'R'      ; read
        JNE >N3
        CMP DEVID, 039h
	JE >O1
        CALL GETSEC
        JMP RED1
O1:	CALL RMT_READ
        JMP RED1
N3:   CMP AL,'P'      ; put
	JNE >P1
        CALL PUTSEC
        JMP RED1
P1:	CMP AL,'W'      ; write
        JNE >N4
        CMP DEVID, 039h
	JE >Q1
        CALL PUTSEC
        JMP RED1
Q1:    CALL ATTOPC
        JMP XI1         ; process command
N4:     CMP AL,'S'      ; status
	JNE >R1
        CALL STATUS
        JMP RED1
R1:	CMP AL,'!'      ; format
	JNE >S1
        CALL FORMAT
        JMP RED1
S1:	CMP AL,022h	 ; format in 1055 1.5 density (h = REV 1.02)
	JNE >L1
        CALL FORMAT
        JMP RED1
L1:	TEST B[DSK_FLAGS+BP],2; bit 1 set means don't respond to N or O
        JNE AEA
	CMP AL, 'N'     ; send config. information to Atari
	JNE >U1
        CALL SEND_CONFG
        JMP RED1
U1:	CMP AL, 'O'     ; receive config. info
        JNE AEA
        CALL GET_CONFG
        JMP RED1
AEA:    CMP AL, '?'; HI SPEED: 3.01
	JNE >V1
        CALL SPEED_UP
        JMP RED1
        JMP U13         ; U13 restores the status line; 3.07 TOOK OUT

; following for invalid command:

V1:	MOV AL,'N'      ; send NAK byte:
	CALL PUT1
	MOV ERR_CHAR, 'e'; Update status line
	CALL PUT_ERCH
        JMP RED1


GDOS:

; The following lines are REV 1.07 change to check if Ramdisks
; have been changed and ask the user if he is sure he wants to
; quit without saving them:

        MOV CX,4; Check 4 ramdisks for written or not?
        MOV BP,0
L1:     CMP B[WRITTN+BP],'W'
        JE WARNW
        ADD BP,BLOCK_SIZE
        LOOP L1
        JMP >L1
WARNW:  PSTATUS QUITW?, ATTR10
        CALL GET_TORK
        AND AL,11011111xB ; Uppercase
        CMP AL,'Q'
        JE >L1
        JMP XI1; Return to main loop without quiting.

; now close any physical disk files: REV 3.00

L1:     MOV CX,4
        MOV BP,0
Q1:     CMP B[WRITTN+BP], 'F'
        JNE >L1
        PUSH CX
        CALL REL_DEL    ; close the disk files
        POP CX
L1:     ADD BP, BLOCK_SIZE
        LOOP Q1


L1:     CALL DO_TITLE
        CALL DISABLE; get SIO2PC off line when program isn't on.
        CALL CLOSPFIL; Close printer file, if any

; **** WARNING: DON'T USE THE "TICKS" FUNCTION AFTER THE FIXV8 CALL***


        CALL FIXV8; Put INT 08 vector back like it was

; REV 4.11 - return to original drive and path

        CALL RES_DRIVE
        CALL RES_PATH


; REV 1.07: USE INT 021h/4Ch instead of INT 020h to terminate

        MOV AL,0; Return code
        MOV AH,4Ch; DOS terminate function
        INT 021h


; A routine to redirect INT 024h to my handler:

SET_NEW24:
        MOV AL,024h; Int number
        MOV AH,025h; Set INT vector function
        MOV DX,OFFSET NEWV24; DS:DX points to new handler
        INT 021h
        RET


; Interrupt routine for INT 024h, critical error routine

NEWV24:

; Note, don't save AX, it carries msg

        PUSH DS,ES,BX,CX,DX
        PUSH CS
        POP DS
        STI; Allow interrupts to happen

        MOV AX,DI
        CALL BYTE2HEX; Convert error code to ASCII digits in BX
        MOV CRIT_STAT,BX
        CALL CLR_ALL
        CALL CLR_24
        PSTATUS SCRITIC, ATTR10
RECRITIC:
        PRINTL SCRITIC2

; Get a character from keyboard:

        MOV AH,0
        INT 016h; Returns char in AL
        AND AL,11011111xB; Convert to uppercase
        CMP AL,'I'; Ignore critical error and proceed...
        JNE >L1
        MOV CRITIC,0FFh; Critic means critical error ignored
        CALL FIX_SCRN
        ADD SP,16; First get rid of my 5 plus INT 24 ret. adr.
        POP AX,BX,CX,DX,SI; Then restore others, see Prog. Ref.
        POP DI,BP,DS,ES;    page 74

; Also, I want to return with carry set:
        PUSH BX
        MOV BX,SP
        OR WORD PTR [BX+6],1; Carry flag is at bit 0
        POP BX
        IRET
L1:     CMP AL,'R'
        JNE >L1
        CALL FIX_SCRN
        MOV AL,1; tells DOS to retry
        JMP CRIRET
L1:     CMP AL,'E'
        JNE RECRITIC; if choice not in range...

; If decision is to exit program, the interrupt vector for INT 08
; must be fixed because the handler's memory area is not protected

        CALL CLOSEV8; Fixes without calling DOS
        MOV AL,2; Tell DOS to end program

CRIRET:
        POP DX,CX,BX,ES,DS
        IRET

; A routine to handle the BREAK and CTRL-C interrupts:

NEWV23:
        PUSH DS ; My routine just sets a flag to tell
        PUSH CS ; main program that ctrl-C has been pressed
        POP DS
        MOV CTRL_C,0FFh
        POP DS
        IRET

; A routine to redirect the BREAK interrupt (INT 023h) to
; my NEWV23 handler...

SET_NEW23:
        MOV AH,025h
        MOV AL,023h
        MOV DX,OFFSET NEWV23
        INT 021h
        RET


;**************** INTERRUPT ROUTINES *******************************

; A routine to get and save the interrupt vectors for IRQ 3 & 4

INT_SAVE:

        PUSH ES,BX,AX
        MOV AL,0Bh;     INT for COM2&4, IRQ #3
        MOV AH,035h;    Get int function
        INT 021h;       Call DOS
        MOV INT_B,BX;   Interrupt vector returned in ES:BX
        MOV BX,ES
        MOV [INT_B+2],BX

; Now do the same for interrupt OCh

        MOV AL,0Ch;     INT for COM1&3, IRQ #4
        MOV AH,035h
        INT 021h
        MOV INT_C,BX
        MOV BX,ES
        MOV [INT_C+2],BX
        POP AX,BX,ES
        RET

; Add subroutines for DOS SHELL function (rev 3.08)

; TO_DOS is the function called from the menu, which manages the
; DOS SHELL entry & exit


TO_DOS:
	CALL GET_SPEC	; 3.17 - get comspec from env. string ...
        MOV AX, DS      ; Get current segment
        DEC AX          ; point to memory control block
        MOV ES, AX
        MOV BL, ES:[00]
        CMP BL, 05Ah    ; Means last block in chain
        JE >L1
        PSTATUS NOT_LAST, ATTR11
        TICKS 48
        RET
L1:     CALL CLR_SCRN
        PRINTL TYPE_EXIT
        CALL FREE_MEM
        CMP FLAG_BM, 0
        JNE >L2         ; skip DOSSHELL if error in releasing memory
        CALL DOSSHELL


; rebuild memory block to show last block (offset 0 = 5Ah) and memory
; owned equals that amount saved before freeing memory:

L2:     MOV AX, DS
        DEC AX
        MOV ES, AX
        MOV AL, 05Ah
        MOV ES:[00], AL
        MOV AX, MEM_ALLOC
        MOV  ES:[03], AX
        PUSH CS
        POP ES

L3:
        CALL FIX_SCRN
        RET



; A function to release all but required memory to DOS:
;
COMMENT\

Please note that there were difficulties freeing and getting back
memory.  A .COM file has all memory assigned to it.  Before I exit to
DOS, I use function 4Ah to change the allocation for SIO2PC to just
that used by the program plus the amount used by ramdisks.  The problem
is that this causes DOS to create new memory control blocks ABOVE my
memory.  Then, when I go back to SIO2PC, I may overwrite these control
blocks.  Even if I tell DOS I want all the original memory back, it
leaves the control blocks back up there.  The solution is to trick DOS
by restoring the control block ahead of SIO2PC to what was originally
shown when I return.  It's especially critical that the initial code
show that this is the last block in the chain, so DOS doesn't go
hunting for more blocks higher up in memory.

Control blocks look like this:

FLAG    DB 04D  ; if not last block  -  05A if last block
PCID    DW xxxx ; PSP segment address (process ID)
SIZE    DW xxxx ; # of paragraphs allocated
SPARES  DB (11 unused bytes)

Note that this control block is in the paragraph just ahead of
the process controlled.  So, for SIO2PC, just take the value of CS and
subtract 1, then the control block is at offset 0 of the resulting
segment.

You can follow UP the chain like this (first you need a MEM type utility
to find the lowest control block, I don't know how to do it.):

If you have the segment address of a control block, add SIZE + 1 to it
and that is the segment address of the new block. The location of SIZE is
defined above.  When you look at the new segment address (offset 0000) you
will see a 4Dh ('M') if the chain continues, or a 5Ah ('Z') if this is the
last block.

ENDOFCOMMENT\

FREE_MEM:

; First, store SIO2PC memory block information:

        MOV AX, CS
        DEC AX  ; point to segment of memory block
        MOV ES, AX
        MOV AX, ES:[03] ; # of paragraphs allocated
        MOV MEM_ALLOC, AX
        PUSH CS
        POP ES

        MOV FLAG_BM, 0  ; assume no error
        PUSH CS
        POP ES
        MOV BX, NEXTS   ; top of memory in use, in paragraphs
        MOV AX, ES      ; ES = CS = bottom of memory in use
        SUB BX, AX      ; yields total memory needed by SIO2PC
        MOV AH, 04Ah    ; modify memory allocation
        INT 021h
        JNC >L1
L1_2:   PSTATUS BAD_MEMAL, ATTR9
        ADD AL, '0'
        CALL PRINT1
        CALL WAIT4KEY
        MOV FLAG_BM, 0FFh       ; Flag memory error
L1:     RET


; A subroutine which executes COMMAND.COM (DOS SHELL):
; NOTE: ALL REGISTERS DESTROYED EXCEPT SEGMENT REGS

DOSSHELL:
        CALL FIXV8      ; turn off my timer interrupt
        MOV AH, 04Bh
        MOV AL, 00; execute program (for load overlay; AL = 3)
        PUSH CS
        POP ES
        MOV DS, ES
        MOV DX, SHELLSPEC
        MOV BX, PAR_BLOCK
        MOV DI, SS
        MOV STORE_SS, DI
        MOV STORE_SP, SP
        INT 021h

        CLI     ; inhibit interrupts

        MOV SS, CS:[STORE_SS]
        MOV SP, CS:[STORE_SP]

        PUSH CS
        POP DI
        MOV DS, DI
        MOV ES, DI
        STI

        JNC >L1 ; branch if no error

L1_1:   PSTATUS BAD_SHELL, ATTR9
        CALL WAIT4KEY
L1:     CALL SETUPV8    ; put timer interrupt back
        CALL SETDTA ; 4.11d adds this ...
        RET

; Function to search the environment string for COMSPEC=
; and copy the COMSPEC pathname if found ...

GET_SPEC:
	 MOV ES, W[02C]; W[02C] is the segment of env. string
	 MOV SI, -1 ; pointer into env. string
L1:	 MOV CX, 8 ; length of CSTRING
	 MOV BX, -1 ;
L2:	 INC BX
	 INC SI
	 MOV AL, ES:B[SI]
	 CMP AL, 0 ; word 0 is end of env. string
	 JE >L3
L4:	 CMP AL, B[CSTRING+BX]
	 JNE L1 ; reset to start of CSTRING, count = 8
	 LOOPE L2

; at this point, all 8 have been found, ES[SI] points to "="
	 MOV BX, 0
	 MOV CX, 60; allow up to 60 char pathname
L6:	 MOV AL, ES:B[SI+1]
	 MOV B[SHELLSPEC+BX], AL
	 CMP AL, 0
	 JE >L5
	 INC BX
	 INC SI
	 LOOP L6


L3:	 CMP ES:B[SI+1], 0 ; double 0 is end of string
	 JNE L4 ; if no find by 0000, drop thru to return ...

L5:	 RET

; Make room for my stack:
MY_STACK: DB 32 DUP ('STACK   ')


XEND_PROG:       ; LABEL END OF PROGRAM CODE
NEXT_SEG:       ; ramdisk area can begin here

FINI:   NOP
