

; File BUSCMNDS.S contains the routines for the standard
; Atari serial bus commands, GET SECTOR, PUT SECTOR,
; GET STATUS, FORMAT plus new bus commands made up just
; for SIO2PC and associated with the REMOTE and FILE2PC
; functions.  Extended commands GET and PUT CONFIGURATION
; are also included.
; Rev. 3.20 will add routines for the 1050-2-PC interface
; which allows the program to communicate with an Atari
; disk drive.

; Contains these routines:

;       STATUS;  PUTSEC;  GETSEC;  FORMAT;  PHYS_FMT
;       POINT2SEC;  Z_SECBUF;  SEC_ADR;  ATTOPC
;       RMT_READ;  FILE2PC;  SEND_CONFG;  GET_CONFG
;       WRT_FSEC;  RD_FSEC;  CX_SIZE; SPEED_UP;  CAN_CFB
;	T_RI_SENSE D_GETS




;                   SEC_ADR

; A subroutine to point ES:DI to the base address for the sector
; identified in the word CFAUX1, CFAUX2.
; - RESULTS IN ES,DI
; NOTE: The program copies [STARS+BP] into DVSEG before calling
; this function ...


SEC_ADR: PUSH DX,AX,BX
;        MOV AL, 'E'
;        CALL PUT_LOC
        MOV BX,DVSEG ; Point BX to base segment
        MOV AL,CFAUX1; Sector number
        MOV AH,CFAUX2
        MOV SECTOR, AX; Save sector for reference - rev 3.00
;        CMP AX, 0; REV 4.04 - correct bug which would accept sec #0
;        JE > B1 DID 4.04 FIX IN PUTSEC AND GETSEC ONLY ...
        CMP [MAX_SEX+BP],AX
        JAE >L1
        STC; Set error return, invalid sector #.
        JMP AAG


L1:     MOV CX,0; Left shift counter
        MOV DX,CX; DX is high word of 32 bit left shift

        DEC AX; Make sector # start with 0

        CMP WORD PTR [SEC_SIZE+BP], 128; WORD: 11/27/89
        JE >L1; Skip down for small sectors

        CMP AX,3
        JB >L1; Sectors 0,1,2 always 128 bytes
        ADD BX,24; Adjust segment base for 3 128 byte sectors
        SUB AX,3; Make sector #3 = 0
        MOV CX,1; One more left shift for big sectors

; Following will multiply sec # (in AX) by 128 or 256,
; depending on sector size. Overflow goes into DX, which will
; contain # of 64K blocks. AX will hold offset, or remainder
; less than 64K. DX will then be multiplied by 01000h (12 left
; shifts) to put into appropriate position in SEGMENT register.

L1:     ADD CX,7; 7 or 8 left shifts required

L1:     SHL DX,1; Shift high word first,
        SHL AX,1; then low word,
        ADC DX,0; then low carry to high word
        LOOP L1

        MOV DI, AX; Offset returned in DI

; WARNING ***** DON'T TRY SHL reg, count ON 8086, NOT VALID *****

        MOV CL,12
        SHL DX,CL; * 01000h
        ADD BX,DX; Final segment adjustment
        MOV ES,BX; Seg returned in ES
        CLC; No error return

AAG:    POP BX,AX,DX
        RET

; A routine to set CX to the # of bytes in the sector:

CX_SIZE:
        MOV CX,128; assume small sectors
        CMP W[SEC_SIZE+BP],128; If all sectors are small, just RET
        JNE >L1
        RET
L1:     PUSH AX
        MOV AL,CFAUX1
        MOV AH,CFAUX2
        DEC AX  ; Make sector # start at 0
        CMP AX,3; If 0,1, or 2, return with 128
        JB >L1
        MOV CX,256
L1:     POP AX
        RET



; A routine to fill the sector buffer with 0's

Z_SECBUF:
        FILL 0, SECBUF, 256
        RET

;
; A routine to move the file pointer to the current sector
; number for the disk pointed to by BP. If there is a DOS
; error, the carry will be set on return.
;

POINT2SEC:

        MOV AX, SECTOR; Get desired sector number
;       CMP AX, 0 ; REV 4.04 - sector 0 not allowed
;       JE > B2
        CMP AX, SEC_PTR[BP]; See if pointer already correct
        JNE >L1
        CLC     ; clear carry is good sector return
        RET
L1:     DEC AX          ; make sector # in AX 0 based
        CMP AX, 2       ; first 3 sectors always single dens
        JA ACM
        MOV CX, 128     ; single density sector size
        MUL CX          ; result is in DX:AX
        ADD AX, 16      ; get past header
        JMP >L1

; below for sector #s greater than 3

ACM:    MOV CX, SEC_SIZE[BP]; multiply by actual sector size
        SUB AX, 3           ; for sectors > 3
        MUL CX
        ADD AX, 0190h   ; Offset past 10h header & 180h 3 SD
        ADC DX, 0       ; Carry high bit to DX

; Now, point the file pointer to the calculated offset:

L1:     PUSH DX         ; move MSD of offset from DX to CX
        POP CX
        MOV DX,AX       ; LSB of offset into file
        MOV BX, HANDLE[BP]
        MOV AH, 042h    ; Set file pointer
        MOV AL, 00      ; Method: offset from start of file
        INT 021h
        JNC >L1
        PSTATUS ESFP, ATTR10    ; Error setting file ptr
        MOV AH,0; AX contains error code
        ADD AL,'0'; Convert to ASCII digit
        CALL PRINT1
        TICKS 18
        STC             ; bad status return
        RET

L1:     MOV AX, SECTOR
        MOV SEC_PTR[BP], AX ; Update sector pointer
        CLC     ; good status return
        RET


; a routine to read in a "sector" from a physical file.  It also
; points ES:DI to SECBUF for the GETSEX routine


RD_FSEC:
        CALL POINT2SEC  ; Make file pointer = SECTOR
;       JCS > B3 ; 4.04 added recognize error stat from POINT2SEC
        CALL CX_SIZE    ; get sector size into CX
        MOV DX, OFFSET SECBUF
        MOV BX, HANDLE[BP]
        MOV AH, 03Fh    ; read a file
        INT 021h
        JNC >L1
        PSTATUS ERRRF, ATTR10
        TICKS 15
        STC     ; error return
        RET

L1:     INC W[SEC_PTR+BP] ; we are now pointed to the next sector
        MOV DI, OFFSET SECBUF
        CALL CLICK
        PUSH CS
        POP ES
        CLC
        RET

; a routine to write a "sector" to a physical disk file

WRT_FSEC:
         CALL POINT2SEC ; Make file ptr = SECTOR
;        JCS > B4 ; rev 4.04 added recognize error from POINT2SEC
         CALL CX_SIZE
         MOV AH, 040h   ; Write file
         MOV BX, [HANDLE+BP]
         MOV DX, OFFSET SECBUF
         INT 021h
         JNC >L1
         PSTATUS EWTF, ATTR10
        MOV AH,0; AX contains error code
        ADD AL,'0'; Convert to ASCII digit
        CALL PRINT1
        TICKS 12
        STC             ; bad status return
        RET

L1:     INC W[SEC_PTR+BP]; Now pointing to next sector
        CALL CLICK1
        CLC
        RET



;               ATTOPC

; This subroutine is similar to PUTSEC, it gets a sector's worth
; of data, but it doesn't send it to the ramdisk area, or check
; the validity of the sector number. This function is used with
; the REMOTE control feature.

ATTOPC:
        MOV BX,T1
        CALL TIMER_0
        MOV AL,'A'
        CALL PUT1
        MOV CX,080h; Set up to get 128 bytes
        MOV SI,0
        MOV AH,0        ; AH will be checksum
ABD:    CALL GET1       ; read a byte from port

; 3.19 jmp to Z1 did go to ABP--BX was not initialized!!

	JC >Z1		; carry set = timed out


	CLC
        ADC AH,AL       ; compute checksum      
        ADC AH,0
        MOV [SECBUF+SI],AL ; store data
        INC SI
        LOOP ABD
        
; Now, get one more byte (checksum)

        CALL GET1
        CMP AH,AL
        JE >L1
Z1:	MOV BX,1100
ABP:	JMP SNAK	; Send NAK byte and return to IDLE


L1:     MOV B[STATS+2+BP],0FFh; Good controller status

; Now delay about 900 more u Sec or so...

        MOV BX,T2
        CALL TIMER_0

; Send ACK

        MOV AL,'A'
        CALL PUT1

; Delay another 250 u Sec

        MOV BX,T3
        CALL TIMER_0

; Now send complete:

        MOV AL,'C'
        CALL PUT1
        CALL CLICK

; Check the string for length and update the counter
;
        CLD; UP direction
        MOV CX,120; Max size of string
        MOV AL,09Bh; Search for atari EOL char
        PUSH DS
        POP ES
        MOV BYTE PTR DS:[80h],119
        MOV DI,OFFSET SECBUF
        REPNE SCASB
        MOV BYTE PTR [DI-1],' '; Replace EOL with space

        SUB DS:[80h], CL; CL holds 120 - # of bytes -1

; Move the string to command tail

        MOV CL, DS:[80h]
        INC CL; because I'm adding a space to end of string
        MOV TAIL_CNT, CL
        MOV DI,081h
        MOV SI,OFFSET SECBUF
        REP MOVSB
        MOV WORD PTR [DI],000Dh; append 0D,00

        MOV TAIL_PT, 081h
        MOV REMOTE, -1; Set 'remote in process' flag

W1:     RET

;
;
; This routine is entered when DEVID = 039h and command = 'R'
;
; It means the REMOTE.OBJ program on the Atari is requesting
; information about SIO2PC

RMT_READ:

; Check CFAUX1 for value 1 to 4

        MOV AL,CFAUX1
        SUB AL,1
        CMP AL,4
        JB >L1
        MOV BX,250
        JMP SNAK; Currently no function for DAUX not 0 - 3.

L1:     MOV AH, 0
        MOV BX, BLOCK_SIZE
        MUL BX  ; Puts disk record # (0 - 3) * block size in DX:AX
        MOV BP, AX      ; BP now points to structure record

L1:     MOV BX,50; delay about 50 uS before ACK
        CALL TIMER_0

L1:     MOV AL,'A'
        CALL PUT1

        MOV BX,270
        CALL TIMER_0      ; kill about >=250 uS
        MOV AL,'C'
        CALL PUT1       ; send "COMPLETE"

        CMP B[WRITTN+BP], ' '; see if disk exists
        JNE >L1
        CALL MOVE_NONE      ; put "NONE" string into SECBUF
        JMP ADH

; REV 3.00; S_DISK below was ADSKSZ

L1:     PUSH CS
        POP ES
        MOV DI,OFFSET S_DISK ; Start of string
        ADD DI,BP; Address specific disk
        CLD; "UP" direction

        MOV CX, OFFSET DOLL - OFFSET S_DISK; Move entire string
        MOV DI, OFFSET SECBUF; Gonna move string to SECBUF
        MOV SI, OFFSET S_DISK; base of source string to move
        ADD SI,BP; Address specific disk
        PUSH CS
        POP DS
        REP MOVSB

; Now, find first 0 in SECBUF and replace it with EOL

        MOV DI, OFFSET SECBUF
        MOV AL,0; 0 marks end of filespec
        MOV CX,OFFSET DOLL - OFFSET ADSKSZ; Max # of bytes to check
        REPNE SCASB; Find 0 in string
        DEC DI; Point DI to first 0 in string
        MOV BYTE PTR [DI],09Bh; Put atari EOL at end of string

; Now, send the whole wretched mess to the Atari:

ADH:    MOV BL,0        ; checksum
        MOV CX,128; Sector size
        MOV DI, OFFSET SECBUF

L1:     MOV AL, [DI]  ; Get the data byte
        CLC
        ADC BL,AL
        ADC BL,0
        CALL PUT1A      ; Send it
        INC DI
        LOOP L1
        MOV AL,BL
        CALL PUT1       ; send checksum
        RET

;       MOVE_NONE
;
; This is a sub of the routine RMT_READ. When it finds that
; a disk isn't set up, it puts the "NONE" string to the sector
; buffer to be sent to the Atari

MOVE_NONE:
        SMOVE S_NONE, SECBUF, 5
        RET


; ******************************************************************
;
;                       FILE2PC
;
; A routine to transfer a file from the Atari to a PC file
;
; Entered when DEVID = 03Ah
;
; *****************************************************************


FILE2PC:
;        MOV AL,'J'
;        CALL PUT_LOC
        MOV AL, CMND
        CMP AL,'S'; AL still contains command. STATUS?
        JNE >L1
        JMP ST2PC; Finish in routine that sends status

L1:     CMP AL,'W'; Only status and write are valid
        JE >L1
GO2BAD: CALL BAD_F2PC
        MOV BX,200
        JMP SNAK

L1:     CMP CFAUX1,2; Means error over there
        JNE >L1
        JMP GO2BAD; Return from there
L1:     CMP FTSTATS,1; 1 means ESC pressed, abort process
        JNE >L1; Don't accept any writes until Atari has gotten bad
        MOV BX,200; Status report and starts over.
        JMP SNAK

L1:     MOV AL,'A'
        CALL PUT1

; Now, get a sector full...

F2R1:   MOV CX, 128; Set up to get 128 bytes
        MOV SI,0
        MOV AH,0        ; AH will be checksum
F2ABE:  CALL GET1       ; read a byte from port
        JNC >L1         ; carry set = timed out
        CALL BAD_F2PC
        RET

L1:     CLC
        ADC AH,AL       ; compute checksum
        ADC AH,0
        MOV [SECBUF+SI],AL ; store data
        INC SI
        LOOP F2ABE

; Now, get one more byte (checksum)

        CALL GET1
        CMP AH,AL
        JE >L1
        MOV BX,1100
        JMP SNAK        ; Send NAK byte and return to IDLE

; Now delay about 900 more u Sec or so...

L1:     MOV BX,1000
        CALL TIMER_0

; Send ACK

        MOV AL,'A'
        CALL PUT1
; REV 3.05: don't send 'C' until PC's disk operation is
; complete

; Now, was this the first sector? If so, it has pathname

        CMP FTSTATS,0
        JE >L1
        JMP PUT2FILE
L1:     PSTATUS F2PCIP, ATTR9
        MOV FTSTATS,02h; Not first time next time...

; Use macro to search buffer for EOL char, then change it to 0
; because DOS requires ASCIIZ string for pathname.

        FIND_BYTE SECBUF, 09Bh, 128
        DEC DI; DI points 1 past found byte
        MOV BYTE PTR [DI],0

; Now, attempt to create the file requested by the Atari

        MOV CX,0; Normal file attribute
        MOV AH,03Ch; Create file
        MOV DX, OFFSET SECBUF; (DS assumed = CS)
        INT 021h
        MOV F2PC_HND,AX; Save handle
        JNC >L1; If no error

        PSTATUS ECF, ATTR10
        MOV AH,0
        ADD AL,'0'; Convert to ASCII digit
        CALL PRINT1
        TICKS 54
        JMP BAD_F2PC; Return from there

; Now, go back and await data sectors from the Atari...

L1:     MOV AL, 'C'; 3.05
        CALL PUT1
        RET

; Continue here for W commands and not first time... (get data)
; At this point, we have a sector's worth of data to process...

PUT2FILE:
        MOV BX,F2PC_HND; Load in file handle
        MOV DX,OFFSET SECBUF; DS:DX points to data...
        MOV AH,040h; Write to file function
        MOV CX,128; Assume full sector
        CMP CFAUX1,0; CFAUX1 = 0 means full sector
        JE >L1
        MOV CL,CFAUX2; Else, CFAUX2 holds # of bytes
        MOV CH,0
L1:     INT 021h
        JNC >L1; Return if no error
        PSTATUS EWF1, ATTR10
        TICKS 72
        CALL BAD_F2PC
        RET

L1: CMP AX,CX   ; This is a revision 2.9 addition:
        JE >L1       ; OK if equal
        PSTATUS PARTW, ATTR10
        TICKS 72
        JMP BAD_F2PC; Give disk full message and close file
L1: CMP CFAUX1,0
        JE >L1; If it was the last sector, close the file and close
        MOV BX,F2PC_HND; up shop
        MOV AH,03Eh; Close file
        INT 021h
        MOV AL, 'C'
        CALL PUT1
ABY:
        MOV FTSTATS,0; Flag file transfer not in process
        MOV F2PC_HND,0; And no file handle established
        PSTATUS FTCPT, ATTR9
        TICKS 54
        PSTATUS RUNNG, ATTR9
        RET
L1:     MOV AL, 'C'; 3.05
        CALL PUT1
        RET

; End up here if an error or partial record (disk full) occurs

BAD_F2PC:
        CMP F2PC_HND,0; Close file, if it exists
        JE >L1
        MOV BX,F2PC_HND; Get file handle
        MOV AH,03Eh; DOS close file function
        INT 021h
        MOV F2PC_HND,0; flag no open file
L1:     MOV B[F2P_STAT+3],0FFh; Make next status request bad
        MOV FTSTATS,0; Flag file transfer not in process
        PSTATUS RUNNG, ATTR9
        RET

;       STATUS sends the status of the disk drive to the Atari. It
;       consists of 4 bytes

ST2PC:
        MOV BX,500
        MOV AL,'A'
        CALL PUT1

        MOV BX,280
        CALL TIMER_0
        MOV AL,'C'
        CALL PUT1


        MOV CX,04       ; 4 bytes
        MOV BL,0
B1:     MOV SI,CX
        MOV AL, [F2P_STAT-1][SI]
        CLC
        ADC BL,AL       ; checksum
        ADC BL,0        ; plus carry
        CALL PUT1A
        LOOP B1
        MOV AL,BL
        CALL PUT1
        MOV B[F2P_STAT+3],010h; Make next status start out "good"
        CMP FTSTATS,1; If escape flag was set
        JNE >L1
        MOV FTSTATS,0; Then clear it
L1:     RET



;               PUTSEC - This subroutine gets a sector's worth of data
;               from the Atari and puts it to the sector #
;               obtained from the command frame.

; First move the data into the buffer, if good, transfer to Ramdisk

PUTSEC:

	MOV AL,CFAUX1; Sector number ; 4.01 moved to start of sub
        MOV AH,CFAUX2
        MOV SECTOR, AX; Save sector for reference - rev 3.00
        CMP AX, 0 ; Added by rev 4.04 - reject sector #0
        JNE > B5
        MOV BYTE PTR [STATS+2+BP],0EFh; invalid sector # error status.
        JE > B4
B5:     MOV AL, [DSK_FLAGS+BP] ; see if write protected
	AND AL, 32 ; bit 5 set means yes [4.01]
	JE >L2 ; 4.03 - was JNE IN 4.02

; Error exit for write protected or sector 0

B4:     MOV BX, T1
	CALL TIMER_0
	MOV AL, 'E'
	CALL PUT1
	JMP NEAR > Y3

; NOT write protected, not sector 0

L2:	CMP B[WRITTN+BP], 'F'     ; physical disk file?
        JE >L1

        CALL SEC_ADR ; point ES:DI to sector of ramdisk
	JNC >L2; Carry set if bad sector number; 4.03 ; WAS JNC > L1
        MOV B[STATS+2+BP],0EFh; Means sector # not valid
        MOV BX,1100

        JMP SNAK

; Physical disk

L1:

; here, we know it's a physical disk, so if it's also copy protected
; we'll have to actually READ a sector to see if the sector is "bad"

	MOV AL, [DSK_FLAGS+BP] ; 4.01
	AND AL, 16; bit 4 for CPTK'd
	JZ > L2 ; branch if not cptk
	CALL RD_FSEC ; puts in SECBUF, DI points to it ... carry if error

; also note that RD_FSEC prints an error message and TICKS 15 ...

	JNC > E1 ; just return if a DOS error
	JMP NEAR > Y3
; now, see if sector should be considered bad?
; If it IS a bad sector, I'll return if not responding if the 1st
; bus response letter is a 'T' and I'll send the response if it's not
; a 'T', but I'm not checking the second letter ...

E1:    CALL BAD_CHECK
       JNC > L2 ; carry clear means good ...

       MOV AL, ES:[DI+8]
       CMP AL, 'T' ; T means TIMEOUT - i.e. don't respond
       JE > Y5 ; return if 'T'
       MOV BX, T1
       CALL TIMER_0
       CALL PUT1

; first, force a delay of TIME_B jiffies for bad sector ... (4.05)

Y5:     XOR AH, AH
        MOV AL, TIME_B[BP]
        CMP AL, 0
        JE > V2 ; no delay requested
        MOV VARBL, AX
V1:     CMP VARBL, 0
        JNE V1
V2:     JMP NEAR > Y3

; NOT physical disk

L2:	MOV BX,T1; REV 2.5
        CALL TIMER_0
        MOV AL,'A'
	CALL PUT1


R1:     CALL CX_SIZE    ; Get # of bytes into CX
        MOV SI,0
        MOV AH,0        ; AH will be checksum
ABE:    CALL GET1       ; read a byte from port
        JNC >L1         ; carry set = timed out
        MOV BX, 1100    ; REV 3.06
        JMP SNAK

L1:     CLC
        ADC AH,AL       ; compute checksum      
        ADC AH,0
        MOV [SECBUF+SI],AL ; store data
        INC SI
        LOOP ABE
        
; Now, get one more byte (checksum)

        CALL GET1
        CMP AH,AL
        JE >L1
        MOV BX,1100
        JMP SNAK        ; Send NAK byte and return to IDLE


; note: 4.01 moved code that put sector # from CFAUX1/2 to SECTOR
; outta this location and to beginning ...

; Now delay about 900 more u Sec or so...

L1:     MOV BX,T2
        CALL TIMER_0

; Send ACK

        MOV AL,'A'
        CALL PUT1

; sector read in ok, now put to ramdisk or real disk?

        CMP B[WRITTN+BP], 'F'
        JE >L2
        CMP B[WRITTN+BP],'S'; SIM disk: (REV. 3.10)
        JE ACP  ; "pretend to write info"
        JNE >L1

L2:     CALL WRT_FSEC
        JC BADWRIT; bad return
        MOV DUN_BLANK, 0; flag that this disk HAS been written
        MOV B[STATS+2+BP],0FFh; Good controller status
        JMP SHORT ACP; else good return

; Now move the sector data from buffer to ramdisk

L1:     MOV B[STATS+2+BP],0FFh; Good controller status
        MOV SI, OFFSET SECBUF
        CALL CX_SIZE     ; # of bytes to move
        CLD             ; increment in UP direction
        REP MOVSB       ; move entire sector

; Delay another 250 u Sec

ACP:   MOV BX,T3
        CALL TIMER_0

; Now send complete:

	MOV AL, [DSK_FLAGS+BP] ; 4.01
	AND AL, 16; bit 4 for CPTK'd
        JZ > V2 ; branch if not cptk

; first, force a delay of TIME_G jiffies for good sector ... (4.05)

        XOR AH, AH
        MOV AL, TIME_G[BP]
        CMP AL, 0
        JE > V2 ; no delay requested
        MOV VARBL, AX
V1:     CMP VARBL, 0
        JNE V1

;V2:     MOV AL,'C' ; - 4.18: moved to end of subroutine
;        CALL PUT1
V2:      CALL CLICK1

; Change this disk's status info to show that it has
; been written (unless it's a physical file...):
        CMP B[WRITTN+BP], 'F'
	JE >Y3

; Has this disk already been written? If not, update...

        CMP BYTE PTR [WRITTN+BP],'N'
	JNE >Y3  ;  change to 'W' only if it's now 'N'
        MOV BYTE PTR [WRITTN+BP],'W'
        CALL SU_DSKHDR
Y3:     MOV AL, 'C'; 4.19 moved this stuff here ...
        CALL PUT1
        RET

; Error exit:


SNAK:
        ; HAVE BX SET UP FOR TIME ON ENTRY
        CALL TIMER_0
        MOV AL,'N'
        CALL PUT1
        RET


BADWRIT:

; error exit for bad physical disk write:

; delay about 900 more u Sec or so...

        MOV B[STATS+2+BP],00h; bad controller status

        MOV BX,T2
        CALL TIMER_0

; Send ACK

        MOV AL,'A'
        CALL PUT1

; Delay another 250 u Sec

BWRT1:  MOV BX,T3       ; entry point for when ACK already sent
        CALL TIMER_0    ; called from PHYS_FMT

; Now send error:

        MOV AL,'E'
        CALL PUT1

        RET


 
;       GETSEC reads a sector from the ramdisk and sends it to the
;       Atari


GETSEC:
        MOV AL,CFAUX1; Sector number
        MOV AH,CFAUX2
        MOV SECTOR, AX; Save sector for reference - rev 3.00
        CMP AX, 0 ; rev 4.04 - reject sector #0
        JE ACN
        CMP B[WRITTN+BP], 'F'; physical disk file?
        JNE >L1

; 4.01 delays ACK for physical file till we see file data ...

;        MOV BX,T1       ; Send the ACK for physical file
;       CALL TIMER_0
;        MOV AL,'A'
;        CALL PUT1

        CALL RD_FSEC; read physical file "sector" ES:DI -> SECBUF
        JC ACN
        JNC ACO ; pre 4.01 - DEST WAS GETSEX

; Here, not a physical disk file

L1:     CALL SEC_ADR ; Points ES:DI to sector data
        JNC ACO
ACN:    MOV BYTE PTR [STATS+2+BP],0EFh; invalid sector # error status.
        MOV BX,250 ; T2
        JMP SNAK

ACO:    MOV BX,T1
        CALL TIMER_0

        MOV AL, [DSK_FLAGS+BP]
        AND AL, 16 ; bit 4 set? eg - copy protected?
        JZ > F1

; BAD_CHECK IS IN FILE 1050.S

        CALL BAD_CHECK ; see if bad sector, transfer data if so
        JNC > F1 ; no carry = good sector

; first, force a delay of TIME_B jiffies for bad sector ... (4.05)

        XOR AH, AH
        MOV AL, TIME_B[BP]
        CMP AL, 0
        JE > V2 ; no delay requested
        MOV VARBL, AX
V1:     CMP VARBL, 0
        JNE V1

V2:     MOV AL, ES:[DI+8]
        CMP AL, 'T' ; T means TIMEOUT - i.e. don't respond
        JNE > U2
; return if 'T'
	JMP NEAR > C3
U2:     CMP AL, 'N'
        JNE > F1
        CALL PUT1 ; send NAK
        JMP NEAR > C3 ; and get outta here
F1:     MOV AL,'A'
F2:     CALL PUT1

;       NOTE: GETSEX is the entry point from FORMAT
;       ES, DI, CFAUX1/2, will be set up

GETSEX: 
        MOV BYTE PTR [STATS+2+BP],0FFh
        MOV BX,T4
        CALL TIMER_0      ; kill about >=250 uS
        CMP [B_STAT+BP], 0 ; 4.01
        JE > F4
        MOV AL, ES:[DI+9]
        CMP AL, 'T'
	JNE > F5 ; return if intent is to "TIME OUT"
F6:	JMP NEAR > C3
F4:     MOV AL,'C'
F5:     CALL PUT1       ; send "COMPLETE"

        CMP [B_STAT+BP], 0 ; 4.01
        JNE  > C3 ; don't send any data for bad sector

; NOTE: may want to put some time delay in here

        MOV BX,T5; *** REV 2.5 - WASN'T ANY DELAY HERE BEFORE ***
        CALL TIMER_0

        MOV BL,0        ; checksum
        CALL CX_SIZE     ; init for sector size
L1:     MOV AL, ES:[DI]  ; Get the data byte
        CLC
        ADC BL,AL
        ADC BL,0
        CALL PUT1A      ; Send it
        INC DI
        LOOP L1
        MOV AL,BL
        CALL PUT1       ; send checksum
        CALL CLICK
C3:	RET

; *************************** DPUTSEC **********************************

; DPUTSEC is PUTSEC rewritten for the diagnostics menu, stripped of
; features such as copy protection, write protect, physical disks, etc.
; It gets a sector's worth of data from the Atari into BUFFER, but
; doesn't do anything with it.  It puts an error character into DS_FLD+5
; and returns with carry set if an error occurs.

DPUTSEC:
	MOV AL,CFAUX1; Sector number ; 4.01 moved to start of sub
        MOV AH,CFAUX2
        MOV SECTOR, AX; Save sector for reference - rev 3.00
        MOV BX,T1; REV 2.5
        CALL TIMER_0
        MOV AL,'A'
	CALL PUT1
        MOV CX, DS_SIZE ; sector size for diagnostic routines
        MOV SI,0        ; pointer into sector buffer
        MOV AH,0        ; AH will be checksum
D1:     CALL GET1       ; read a byte from port
        JNC >L1         ; carry set = timed out
D2:     MOV BX, 1100    ; REV 3.06
        MOV B[DS_FLD+5], 'T'; timed out in GET1, put to second * in string
        JMP DNAK

L1:     CLC
        ADC AH,AL       ; compute checksum      
        ADC AH,0
        MOV [SECBUF+SI], AL ; store data
        INC SI
        LOOP D1
        
; Now, get one more byte (checksum)

        CALL GET1
        JC D2
        CMP AH,AL
        JE >L1
        MOV BX,1100
        MOV B[DS_FLD+5], 'K' ; indicate bad checksum in second *
        JMP DNAK        ; Send NAK byte and return to IDLE

; Now delay about 900 more u Sec or so...

L1:     MOV BX,T2
        CALL TIMER_0

; Send ACK

        MOV AL,'A'
        CALL PUT1

; Delay another 250 u Sec

       MOV BX,T3
       CALL TIMER_0

; Now send complete:

        MOV AL,'C'
        CALL PUT1
        CALL CLICK1
        CLC ; signal success
        RET

; ERROR EXIT ->

DNAK:
        ; HAVE BX SET UP FOR TIME ON ENTRY
        CALL TIMER_0
        MOV AL,'N'
        CALL PUT1
        STC ; signal bad status
        RET

;********************** DGETSEC ************************************

; Send sectors to the Atari, for the diagnostics menu ...
; Here's the sequence:
; Delay T1 time ... Send ACK
; Delay T4 time ... Send CPT
; Delay T5 time ... Send sector's worth of data bytes
; Return

DGETSEC:
        MOV AL,CFAUX1; Sector number
        MOV AH,CFAUX2
        MOV SECTOR, AX; Save sector for reference - rev 3.00
        MOV BX, T1
        CALL TIMER_0
        MOV AL, 'A'
        CALL PUT1
        MOV BX, T4
        CALL TIMER_0
        MOV AL, 'C'
        CALL PUT1
        MOV BX, T5
        CALL TIMER_0
        MOV BL, 0 ; for checksum
        MOV CX, DS_SIZE ; # of bytes to send
        MOV DI, 0 ; pointer to byte
L2:     MOV AL, [S_DATA+DI] ; get data byte
        CLC
        ADD BL, AL
        ADC BL, 0       ; computing checksum
        CALL PUT1A      ; send data byte
        INC DI
        CMP DI, 16      ; 16 data bytes, sent 8 times for 128 byte sector
        JNE > L1
        MOV DI, 0       ; reset counter to 1st byte
L1:     LOOP L2
        MOV AL, BL      ; send checksum
        CALL PUT1
        CALL CLICK
        CLC             ; good status
        RET

; ***************************** SEND_CONFG ***************************

;       SEND_CONFG sends the 12 byte configuration information to
;       the Atari when the command 04Eh ('N') is received:

SEND_CONFG:

        MOV BX,T1
        CALL TIMER_0
        MOV AL,'A'
        CALL PUT1

        MOV BX,T4
        CALL TIMER_0
        MOV AL,'C'
        CALL PUT1

        MOV BX,T5
        CALL TIMER_0

; first, move the 12 bytes from the specific disk record to
; the staging area:

        MOV CX, 12
        MOV SI,0
L1:     MOV AL, [TRACKS_SIDE+BP+SI]
        MOV [CFG0+SI], AL
        INC SI
        LOOP L1

; then flip the two words which are to be sent high byte first:

        MOV AX, [MAX_SEX+BP]
        XCHG AL,AH
        MOV WORD PTR CFG2, AX
        MOV AX, [SEC_SIZE+BP]
        XCHG AL,AH
        MOV WORD PTR CFG6, AX

; Now, I'm ready to send the 12 bytes

        MOV SI,0
        MOV CX,12       ; 12 bytes
        MOV BL,0
L1:     MOV AL, [CFG0+SI+BP]
        CLC
        ADC BL,AL       ; checksum
        ADC BL,0        ; plus carry
        CALL PUT1A
        INC SI
        LOOP L1
        MOV AL,BL
        CALL PUT1
        RET

; RETURNING THE SPARTA DOS HI SPEED INDEX QUERY:

SPEED_UP:
	MOV BX,T1
	CALL TIMER_0
	MOV AL,'A'
	CALL PUT1

	MOV BX,T4
	CALL TIMER_0
	MOV AL,'C'
	CALL PUT1

	MOV BX,T5
	CALL TIMER_0

; Now, send the new divisor (index):

	MOV AL, INDEX ; 16 for 38.5KB
	CALL PUT1A
	MOV AL, INDEX ; CHECKSUM: NEEDED???
	CALL PUT1
	MOV AX, PCDIV
	MOV T9, AX   ; 3 For 38.4K; 4 for 28.8K; 6 for 19.2K
	CALL RE_BAUD; do the speedup
        MOV EVER_HI, 'Y'
	RET

; Cancel getting the CFB when there is a framing error:
; waits for command line to raise

; AS OF REV 3.06, THIS ROUTINE TOGGLES THE SPEED BETWEEN HIGH
; AND LOW

CAN_CFB:
       MOV AL, 'C'
       CALL PUT_LOC
        MOV VARBL, 60
        CALL TOG_SPEED
L1:     CMP VARBL, 0
        JE >L4 ; 4.10 - was JNE > L2, followed by RET
L2:    MOV DX, MSR
	IN AL,DX
        CALL ACC_DLY ; 4.10 added
	CALL CK_LINES
        AND AL,01000000XB
	LAHF    ; 3.06 - complement ZF if ONECHIP. AH <- FLAGS
	CMP [REV_FLAG], 'i'
        JNE >L3
        XOR AH, 01000000xb; complement ZF
L3:     SAHF; FLAGS <- AH
        JE L1
L4:     RET


;       GET_CONFG reads in configuration from the Atari when an 'O'
;       command is received. Currently, it doesn't do anything
;       with the information, it just accepts it.

GET_CONFG:
        MOV BX,T1
        CALL TIMER_0
        MOV AL,'A'
        CALL PUT1

        MOV CX, 12      ; read 12 bytes
        MOV SI,0
        MOV AH,0        ; AH will be checksum
ADL:    CALL GET1       ; read a byte from port
        JNC >L1          ; carry set = timed out
        RET

L1:     CLC
        ADC AH,AL       ; compute checksum
        ADC AH,0
        MOV [CFG0+SI],AL ; store data
        INC SI
        LOOP ADL

; Now, get one more byte (checksum)

        CALL GET1
        CMP AH,AL
        JE >L1
        MOV BX,1100
        JMP SNAK        ; Send NAK byte and return to IDLE


; Now delay about 900 more u Sec or so...

L1:     MOV BX,T2
        CALL TIMER_0

; Send ACK

        MOV AL,'A'
        CALL PUT1

        MOV BX,T3
        CALL TIMER_0

; Now send complete:

        MOV AL,'C'
        CALL PUT1

; Now check to see that configuration written matches actual
; configuration of disk, and warn if not:

        MOV AH, CFG2
        MOV AL, CFG3
        CMP [MAX_SEX+BP], AX
        JMP >L1; 3.01A MADE UNCONDITIONAL JUMP

        MOV AX, [MAX_SEX+BP]
        MOV DI, OFFSET WSX_PTR
        CALL INT2DEC; Put actual size at end of WRONG_SX string
        PSTATUS WRONG_SX, ATTR10
        TICKS 54

; Note: I'm going to bypass this check because MYDOS seems to
; always try to set double density when the "O' choice is used,
; even though it then continues to correctly view the disk as SD.
; Recall that choice "O" doesn't include density in its list of
; questions. Choice "P" does correctly send the low density info,
; but even after it is used, "O" continues to send 0100H as the
; sector size.

L1:     JMP >L1
        MOV AX, WORD PTR CFG6   ; Now, check the density
        XCHG AL, AH
        CMP [SEC_SIZE+BP], AX
        JE >L1

        PSTATUS WRONG_DNS, ATTR10
        TICKS 54

L1:     RET


;       STATUS sends the status of the disk drive to the Atari. It 
;       consists of 4 bytes

STATUS:

        MOV BX,T1
        CALL TIMER_0
        MOV AL,'A'
        CALL PUT1

        MOV BX,T4
        CALL TIMER_0
        MOV AL,'C'
        CALL PUT1

        MOV BX,T5; **** NEW TO REV 2.5
        CALL TIMER_0

; 4.01 - now, let's see if this is a copy protected disk image, and
; if so, did the last request result in a bad sector status?

	TEST B[DSK_FLAGS+BP], 16 ; copy protected?; 4.03 - WAS CMP NOT TEST
        JZ > V5 ; V5 is code for non-copy protected disk [4.05]
	CMP [B_STAT+BP], 0 ; last access bad?
        JZ > B1 ; B1 is code for non-bad sector

	MOV CX, 4
	MOV BL, 0
B2:     MOV SI, CX
        MOV AL, [B_STATUS-1+SI+BP] ; 4.07 revised
	CLC
	ADC BL, AL
	ADC BL, 0
	CALL PUT1A
	LOOP B2
	JMP > B3 ; finish (checksum) down there

; rev 4.07 - found that my loop address counter (SI) wasn't even being used
; so I added in the SI to the B2 and V4 loops same as is in the V5 loop -
; assume bytes get sent out in reverse order...

B1:     MOV CX, 4
        MOV BL, 0
V4:     MOV SI, CX
        MOV AL, [G_STATUS-1][SI][BP] ; 4.07 revised
        CLC
        ADC BL, AL
        ADC BL, 0
        CALL PUT1A
        LOOP V4
        JMP  > B3

V5:     MOV CX,04       ; 4 bytes
        MOV BL,0
L1:     MOV SI,CX
        MOV AL, [STATS-1][SI][BP]
        CLC
        ADC BL,AL       ; checksum
        ADC BL,0        ; plus carry
        CALL PUT1A
        LOOP L1
B3:	MOV AL,BL
        CALL PUT1
        RET     


FORMAT:
        MOV BX,T1
        CALL TIMER_0
        MOV AL,'A'
        CALL PUT1
        CMP B[WRITTN+BP], 'F'    ; physical file?
        JNE >L1
        JMP PHYS_FMT            ; finish up there if so

; As of REV 3.00: format will clear all RAMDISK ram to 0's
; this is so compression schemes can work effectivly on saved
; disk images:

L1:
        CALL Z_SECBUF   ; fill sector buffer with 0's
        MOV CX, [MAX_SEX+BP]
L1:     PUSH CX
        MOV CFAUX1, CL
        MOV CFAUX2, CH
        CALL SEC_ADR; point ES:DI to sector address

; Now move the sector data from buffer to ramdisk

        MOV SI, OFFSET SECBUF
        CALL CX_SIZE     ; # of bytes to move
        CLD             ; increment in UP direction
        REP MOVSB       ; move entire sector
        POP CX
        LOOP L1

        PUSH CS
        POP ES
        MOV DI, OFFSET SECBUF
        MOV W ES:[DI],0FFFFh ; start with FF means no bad sectors
        MOV CFAUX1,200; Make sure CX_SIZE sends proper size sector
        MOV CFAUX2,0;   by making sector # higher than 3. (use 200)
        CALL GETSEX     ; let GETSEC routine handle sending data
        
; Now, if there was a PATHNAME associated with this ramdrive, 
; erase it!

        MOV CX,55; Length of pathname field
F1:     MOV DI,CX
        MOV BYTE PTR [F_SPEC-1][DI][BP],0                              
        LOOP F1
        RET

; A routine to handle formatting of physical files:
; REV 3.01: don't clear image if /N option was used. /N is indicated
; by b0 of DSK_FLAGS set

PHYS_FMT:
        MOV AL, 00000001xB
        AND AL, [DSK_FLAGS+BP]
        JZ >L1
        JMP ACZ

L1:     CMP DUN_BLANK,0 ; this disk ever been written?
        JE >L1   ; if 0, disk has been written & needs clearing
        JMP ACZ
L1:     CMP RAM, 0100h; is 4K available?
        JB ADV  ; use one sector at a time method
        CALL USE_4K
        JNC >L1
        JMP BWRT1
L1:     MOV AX, [MAX_SEX+BP]
        INC AX; since we're @ EOF, it's MAX_SEX + 1
        MOV [SEC_PTR+BP], AX
        JMP ACZ ; send the info to Atari and return

ADV:    MOV SECTOR, 1

L1:     CALL Z_SECBUF   ; fill sector buffer with 0s
        MOV CX, [MAX_SEX+BP]

L1:     PUSH CX
        CALL WRT_FSEC
        JNC ACV
        POP CX
        JMP BWRT1       ; Note: WRT_FSEC prints an error message

ACV:    INC SECTOR
        POP CX
        LOOP L1

ACZ:    PUSH CS
        POP ES
        MOV DI, OFFSET SECBUF
        MOV W ES:[DI],0FFFFh ; start with FF means no bad sectors
        MOV CFAUX1,4  ; Make sure CX_SIZE sends proper size sector
        MOV CFAUX2,0;   by making sector # higher than 3. (use 4)
        CALL GETSEX     ; let GETSEC routine handle sending data

        RET

; REV 3.06: T_RI_SENSE changes flags to cause the sensing of
; the command line (RI) to be inverted.

T_RI_SENSE:
	CMP TX1A, 'i'
        JE >L1
	MOV TX1A, 'i'
	MOV REV_FLAG, 'i'
	RET
L1:     MOV TX1A, ' '
	MOV REV_FLAG, ' '
        RET
