; 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