;+++++++++++++++++++++++++++++++++++++++++++++++++ ;++ D I S K T E S T ++ ;++ FLOPPY DISK DIAGNOSTIC 12-1-'80 ++ ;++ TARBELL ELECTRONICS - VERSION 1.9 ++ ;+++++++++++++++++++++++++++++++++++++++++++++++++ ;THIS PROGRAM READS ALL DISK SECTORS ;AND PRINTS THE TRACK AND SECTOR NUMBER ;WHERE AN ERROR IS FOUND. ;RETRY COUNT CAN BE SET AT 0 - 9. ;NORMALLY SET RETRY COUNT AT 0. ;SETTING RETRY COUNT TO GREATER THAN ZERO WILL CAUSE THE ;PROGRAM TO TRY TO READ A SECTOR WHERE AN ERROR IS FOUND ;THAT MANY TIMES OVER BEFORE IT WILL PRINT AN ERROR MESSAGE. ;STEP RATE CAN BE SET TO SLOW (20MS.), MEDIUM (10MS.), ;OR FAST (6MS.). ;FULL TRACK SEEK SEEKS INSIDE TRACK BEFORE READING EACH TRACK ;UP TO THE MIDDLE TRACK, AND SEEKS TRACK ZERO BEFORE READING ;EACH TRACK PAST THE MIDDLE TRACK. ;CONTROL C TERMINATES TEST AND DOES A WARM BOOT. ;CONTROL D TERMINATES TEST AND STARTS OVER. ;CONTROL A AS A RESPONSE TO A PROMPT FOR A TEST ;PARAMETER, (SELECT STEP RATE, ETC.), WILL CAUSE ;THE PROGRAM TO START OVER WITH THE FIRST PROMPT. ;THIS PROGRAM INCLUDES DISK I/O ROUTINES AND CALLS CP/M ;ONLY FOR CONSOLE I/O. ;DISK WRITE ROUTINES HAVE BEEN INCLUDED IN THE SOURCE ;ALTHOUGH THEY ARE NOT USED BY THIS VERSION OF THE PROGRAM. ;WRITTEN BY MARC D. FARJEON USING DISK I/O ROUTINES ;FROM THE TARBELL CBIOS. VN EQU 19 FALSE EQU 0 ;DEFINE VALUE OF FALSE. TRUE EQU NOT FALSE ;DEFINE VALUE OF TRUE. STD EQU TRUE ;TRUE IF STANDARD DRIVE. SINGLE EQU TRUE ;true if using single density board. FAST EQU NOT STD ;TRUE IF FAST SEEK. HLAB EQU 8 ;no headload @ beginning of seek = 0. SEEKC EQU 18H ;seek command with head load. DISK EQU 0F8H ;DISK BASE ADDRESS. DCOM EQU DISK ;DISK COMMAND PORT. DSTAT EQU DISK ;DISK STATUS PORT. TRACK EQU DISK+1 ;DISK TRACK PORT. SECTP EQU DISK+2 ;DISK SECTOR PORT. DDATA EQU DISK+3 ;DISK DATA PORT. WAIT EQU DISK+4 ;DISK WAIT PORT. DCONT EQU DISK+4 ;DISK CONTROL PORT. TRACKS EQU 77 ;TRACKS PER DISK. SECTS EQU 26 ;SECTORS PER TRACK. DOS EQU 5 ;BDOS ENTRY POINT. CREAD EQU 1 ;CODE FOR CONSOLE READ. CWRITE EQU 2 ;CODE FOR CONSOLE WRITE. CPB EQU 9 ;CODE FOR PRINT BUFFER. CSTAT EQU 11 ;CODE FOR STATUS CHECK. DRINT EQU 25 ;CODE FOR DRIVE INTERROGATE. ; ORG 100H ;STARTING ADDRESS. ; LXI H,0 ;CLEAR H AND L. DAD SP ;H AND L = SP. SHLD CPMS ;SAVE IT. LXI H,OMSG ;GET MESSAGE ADDRESS. CALL CPRINT ;PRINT MESSAGE. START: LXI SP,STACK ;LOAD STACK POINTER. SELR: LXI H,SELMSG ;DRIVE SELECT MESSAGE. CALL CPRINT ;PRINT MESSAGE. CALL CONIN ;READ DRIVE. ANI 5FH ;CONVERT TO UPPER CASE. CALL BACK ;CHECK TO START OVER. CPI 'Q' ;WANT TO QUIT? JZ EXITT ;YES CPI 'A' ;COMPARE JC SELR ;FOR CPI 'E' ;CORRECT JNC SELR ;DRIVE. STA DRIVE ;SAVE IT. RETR: LXI H,REMSG ;RETRY QUESTION. CALL CPRINT ;PRINT QUESTION. CALL CONIN ;READ RETRY COUNT. CALL BACK ;CHECK. CPI '0' ;COMPARE JC RETR ;FOR CPI ':' ;CORRECT JNC RETR ;NUMBER. ANI 0FH ;MASK OUT UPPER NYBBLE. ADI 1 ;ADD ONE. STA RTCNT ;STASH IT. IF STD ;IF STANDARD DRIVE. STPSET: LXI H,STPMSG ;STEP RATE MESSAGE. CALL CPRINT ;PRINT IT. CALL CONIN ;GET CHARACTER. IF NOT SINGLE CPI '0' ;CHECK LIMITS ENDIF IF SINGLE CPI '1' ENDIF JC STPSET ;TO SMALL CPI '4' JNC STPSET CALL SETSTP ;SET STEP RATE. ENDIF LXI H,LSMSG ;LONG SEEK QUESTION. CALL CPRINT ;PRINT IT. CALL CONIN ;READ RESPONSE. ANI 5FH ;MAKE UPPER CASE. CALL BACK ;CHECK. CPI 'Y' ;IS IT Y? IF SO, LXI H,LST ;SET LOCATION LST TO MVI M,1 ;ONE FOR LONG SEEK. JZ READY ;JUMP. MVI M,0 ;ZERO FOR SEQUENTIAL SEEK. READY: LXI H,RMSG ;GET MESSAGE ADDRESS. CALL CPRINT ;PRINT MESSAGE. CALL CONIN ;READ RETURN. CALL BACK ;CHECK. CPI 13 ;COMPARE FOR RETURN. JNZ READY ;GO BACK IF NOT. LXI H,CRLF ;OUTPUT A RETURN AND CALL CPRINT ;LINEFEED TO CRT. XRA A ;SET A = 0. STA TRK ;TRACK COUNTER = 0. STA BCDTRK ;BCD TRACK COUNTER = 0. STA BCRETO ;BCD READ ERRORS = 0. STA BCRETH ;BCRETH = 0. STA TLONTL ;READ ERROR FLAG = 0. STA OTIT ;OTIT = 0. STA OT ;OT = 0. INR A ;SET A = 1. STA SECT ;SECTOR COUNTER = 1. STA BCDSEC ;BCD SECTOR COUNTER = 1. MVI A,TRACKS ;SET A = TRACKS. STA IT ;IT = TRACKS. CALL SELECT ;SELECT DRIVE. CALL HOME ;RESTORE. JMP READFS ;START READING. INRTRK: CALL CONST ;CHECK CONSOLE INPUT STATUS. LDA LST ;CHECK LOCATION LST DCR A ;FOR LONG SEEK. IF ONE, JZ LSTRK ;DO IT. IF NOT, LDA TRK ;GET PRESENT TRACK NUMBER. INR A ;INCREMENT TRACK NUMBER. CPI TRACKS ;IF LAST TRACK, JZ FINIS ;JUMP TO END ROUTINE. STA TRK ;SAVE NEW TRACK NUMBER. CALL SEEK ;MOVE HEAD TO NEW TRACK. LDA BCDTRK ;GET BCD TRACK NUMBER. ADI 1 ;ADD ONE TO TRACK COUNT. DAA ;DECIMAL ADJUST. STA BCDTRK ;STASH IT. MVI A,1 ;SET A = 1. STA SECT ;SECTOR = 1 FOR NEW TRACK. STA BCDSEC ;BCD SECTOR NUMBER = 1. READFS: CALL READ ;READ FIRST SECTOR. INRSEC: LDA SECT ;GET PRESENT SECTOR NUMBER. INR A ;INCREMENT SECTOR NUMBER. CPI SECTS+1 ;IF LAST SECTOR, JZ INRTRK ;START NEW TRACK. IF NOT, STA SECT ;SAVE NEW SECTOR NUMBER. ORA A ;CLEAR FLAGS. LDA BCDSEC ;GET BCD SECTOR NUMBER. ADI 1 ;ADD ONE TO SECTOR COUNT. DAA ;DECIMAL ADJUST. STA BCDSEC ;STASH IT. LDA TLONTL ;CHECK FOR ERROR IN LAST ORA A ;SECTOR READ. IF ERROR JNZ READL ;READ WITH HEAD LOAD. CALL READN ;READ NEW SECTOR. JMP INRSEC ;READ NEXT SECTOR. READL: CALL READ ;READ SECTOR. JMP INRSEC ;READ NEXT SECTOR. LSTRK: LDA OTIT ;CHECK TO READ OUTER OR INR A ;INNER TRACK. INCREMENT STA OTIT ;OTIT. SAVE IT. ANI 1 ;IF LSB IS HIGH, JNZ ITRK ;READ INNER TRACK. LDA OT ;GET OUTER TRACK NUMBER. INR A ;INCREMENT TRACK. CPI TRACKS ;IF LAST TRACK, JZ FINIS ;DO QUIT ROUTINE. STA OT ;SAVE IT. STA TRK ;PUT IN TRACK COUNTER. CALL SEEK ;MOVE HEAD TO TRACK. LDA BCDTRK ;GET BCD TRACK NUMBER. ADI 1 ;ADD ONE TO TRACK COUNT. DAA ;DECIMAL ADJUST. STA BCDTRK ;SAVE IT. MVI A,1 ;SET A = 1. STA SECT ;SECTOR = 1 FOR NEW TRACK. STA BCDSEC ;BCD SECTOR = 1 FOR NEW TRACK. JMP READFS ;READ NEW TRACK. ITRK: LDA TRK ;GET TRACK NUMBER. CPI TRACKS/2+1 ;IF < HALFWAY IN, JC INMOST ;SEEK INSIDE TRACK. XRA A ;SET A = 0. STA TRK ;PUT IN TRACK COUNTER. CALL SEEK ;MOVE HEAD TO TRACK 0. JMP LSTRK ;READ NEXT TRACK. INMOST: MVI A,TRACKS-1 ;SET A = TRACKS-1. STA TRK ;PUT IN TRACK COUNTER. CALL SEEK ;MOVE HEAD TO TRACK. JMP LSTRK ;READ NEXT TRACK. ETS: LDA BCDTRK ;GET BCD TRACK NUMBER. RRC ;SHIFT RRC ;RIGHT RRC ;FOUR RRC ;BITS. ANI 0FH ;MASK OFF UPPER NYBBLE. ADI '0' ;ADD ASCII FOR ZERO. CPI '0' ;SEE IF MSD IS ZERO. JNZ TLSD ;PRINT IT IF NOT ZERO. MVI A,20H ;DO NOT PRINT IF ZERO. TLSD: STA TRKM ;INSERT IN BUFFER. LDA BCDTRK ;GET BCD TRACK AGAIN. ANI 0FH ;MASK OFF UPPER NYBBLE. ADI '0' ;ADD ASCII FOR ZERO. STA TRKL ;INSERT IN BUFFER. LDA BCDSEC ;GET BCD SECTOR NUMBER. RRC ;SHIFT RRC ;RIGHT RRC ;FOUR RRC ;BITS. ANI 0FH ;MASK OFF UPPER NYBBLE. ADI '0' ;ADD ASCII FOR ZERO. CPI '0' ;CHECK FOR MSD OF ZERO. JNZ SLSD ;PRINT IT IF NOT ZERO. MVI A,20H ;DO NOT PRINT IF ZERO. SLSD: STA SECM ;INSERT IN BUFFER. LDA BCDSEC ;GET BCD SECTOR AGAIN. ANI 0FH ;LOOK AT LOWER NYBBLE. ADI '0' ;ADD 30 HEX. STA SECL ;INSERT IN BUFFER. LXI H,TSMSG ;GET MESSAGE ADDRESS. CALL CPRINT ;PRINT IT. LXI H,TLONTL ;GET TLONTL ADDRESS. MVI M,55H ;SET TO 01010101. CALL CONST ;CHECK CONSOLE STATUS. RET ;RETURN. ECOUNT: LDA BCRETO ;GET BCD READ ERROR COUNT. ADI 1 ;ADD ONE TO READ ERROR COUNT. DAA ;DECIMAL ADJUST. STA BCRETO ;SAVE IT. RNC ;SKIP IF NO CARRY. LDA BCRETH ;GET HUNDREDS COUNT. ADI 1 ;ADD ONE TO COUNT. DAA ;DECIMAL ADJUST. STA BCRETH ;SAVE IT. RET ;RETURN. FINIS: LXI H,REC ;POINT TO REC BUFFER. LDA BCRETH ;GET READ ERROR MSD'S. RRC ;SHIFT RRC ;RIGHT RRC ;FOUR RRC ;BITS. ANI 0FH ;LOOK AT ONE DIGIT. JZ RECK ;SUPPRESS LEADING ZERO. ADI 30H ;ADD ASCII FOR ZERO. RECK: MOV M,A ;INSERT IN BUFFER. LDA BCRETH ;GET MSD'S BACK. ANI 0FH ;MASK. JNZ PECH ;PRINT IF NOT ZERO. CMP M ;CHECK FOR PREVIOUS ZERO. JZ RECH ;YES, SO DON'T PRINT. PECH: ADI 30H ;ADD ASCII. RECH: INX H ;POINT TO NEXT DIGIT. MOV M,A ;INSERT. LDA BCRETO ;GET READ ERROR LSD'S. RRC ;SHIFT RRC ;RIGHT RRC ;FOUR RRC ;BITS. ANI 0FH ;MASK IT OFF. JNZ PECT ;PRINT IF NOT ZERO. LDA BCRETH ;LOOK AT MSD'S. ORA A ;SEE IF ZERO. JZ RECT ;IF SO, DON'T PRINT. XRA A ;CLEAR A. PECT: ADI 30H ;ADD ASCII. RECT: INX H ;INCREMENT POINTER. MOV M,A ;STASH IN BUFFER. LDA BCRETO ;GET BACK LSD'S. ANI 0FH ;MASK. ADI 30H ;ADD ASCII. INX H ;POINT TO LAST DIGIT. MOV M,A ;STASH IT. LXI H,RECMSG ;GET ERROR MESSAGE. CALL CPRINT ;PRINT IT. JMP SELR ;START AGAIN ; EXITT: CALL INTDRN ;INTERROGATE DRIVE NUMBER. LHLD CPMS ;GET OLD SPHL ;STACK BACK. RET ;GO BACK TO CPM. CONST: MVI C,CSTAT ;SET C FOR STATUS CHECK. CALL DOS ;DO IT. ANI 1 ;LOOK AT LSB. RZ ;RETURN IF ZERO. CALL CONIN ;GET CHARACTER. CPI 4 ;CHECK FOR CONTROL D. RNZ ;RETURN IF NOT. LXI H,AMSG ;IF CONTROL D, CALL CPRINT ;PRINT MESSAGE AND JMP FINIS ;DO QUIT ROUTINE. CONIN: MVI C,CREAD ;SET C FOR CONSOLE READ. CALL DOS ;INPUT CHARACTER. CPI 3 ;CHECK FOR CONTROL C. RNZ ;RETURN IF NOT. LXI H,AMSG ;POINT TO MESSAGE. CALL CPRINT ;SEND IT. JMP SELR ;RESTART FROM START. ; CPRINT: PUSH D ;SAVE D AND E. XCHG ;MESSAGE ADDRESS IN D AND E. MVI C,CPB ;SET C FOR PRINT BUFFER. CALL DOS ;PRINT CONSOLE BUFFER. POP D ;RESTORE D AND E. RET ;RETURN FROM CPRINT. ; INTDRN: MVI C,DRINT ;CODE FOR DRIVE QUERY. CALL DOS ;GET LOGED IN DRIVE. MOV A,E ;PUT IN A. CALL SELD ;SELECT IT. RET ;RETURN FROM INTDRN. SELECT: LDA DRIVE ;GET DRIVE FOR TEST. SUI 'A' ;SUBTRACT ASCII FOR A. STA DISKNO ;SAVE IT. SELD: IF SINGLE ;if using single density board. CMA ;INVERT SELECT CODE. ENDIF ADD A ;PUT BITS ADD A ;ONE AND TWO ADD A ;AT FOUR ADD A ;AND FIVE. IF SINGLE ;if using single density board. ORI 2 ;SET BIT ONE TO SET LATCH. ENDIF OUT DCONT ;SELECT DRIVE. STA LATCH ;SAVE CODE. RET ;RETURN FROM SELECT. IF STD ;IF STANDARD DRIVE. SETSTP: LXI H,STP+1 ;POINT TO SEEK BYTE. MVI M,SEEKC ;SET FOR FAST STEP. CALL POKE ;SET SEEK COMMAND. LXI H,RES+1 ;POINT TO RESTORE BYTE. MVI M,HLAB ;SET FOR FAST STEP WITH HEADLOAD. POKE: CPI '0' ;IS IT AN F? RZ ;RETURN. INR M ;SET FOR MEDIUM STEP. CPI '1' ;IS IT AN M? RZ ;GO BACK. INR M ;SET FOR SLOW STEP. CPI '2' ;IS IT AN S? RZ INR M ;MUST WANT SLOWEST RATE RET ;RETURN. ENDIF BACK: CPI 1 ;CHECK FOR 1. RNZ ;RETURN IF NOT. LXI H,CRLF ;SEND RETURN CALL CPRINT ;AND LINEFEED. JMP START ;START OVER. HOME: IF FAST ;IF FAST SEEK. LDA LATCH ;GET SELECT CODE. ANI 0B2H ;SET FOR RESTORE. OUT DCONT ;RESTORE DRIVE. HLOOP: IN DSTAT ;READ STATUS. ANI 4 ;LOOK AT TRACK 0 BIT. JZ HLOOP ;WAIT UNTIL 0. LDA LATCH ;GET CODE. OUT DCONT ;CLEAR RESTORE. ENDIF RES: MVI A,HLAB ;RESTORE COMMAND. OUT DCOM ;SEND IT. IN WAIT ;WAIT FOR HOME. IN DSTAT ;READ STATUS. MOV B,A ;SAVE IT. ANI 4 ;CHECK FOR TRACK 0. JZ RERR ;ERROR IF NOT TRACK 0. MOV A,B ;GET STATUS BACK. ANI 91H ;LOOK AT ERROR BITS. RZ ;RETURN IF NO ERROR. RERR: LXI H,HEMSG ;POINT TO MESSAGE. CALL CPRINT ;PRINT IT. JMP SELR ;DO IT AGAIN. ; ;READ WITHOUT HEAD LOAD. ; READN: LDA RTCNT ;SET RETRY COUNT. STA ERCNT LDA SECT ;GET SECTOR NUMBER LXI H,DIB ;AND STARTING ADDRESS. OUT SECTP ;SET SECTOR NUMBER INTO 1771. MVI A,88H ;GET CODE FOR READ W/O HLD. JMP READE ;READ A SECTOR. ; ; READ THE SECTOR AT SECT, FROM THE PRESENT TRACK. ; USE STARTING ADDRESS AT DIB. ; READ: LDA RTCNT ;GET RETRY COUNT. RRETRY: STA ERCNT ;STORE IN ERROR CTR. LDA SECT ;GET SECTOR NUMBER. LXI H,DIB ;GET STARTING ADR. OUT SECTP ;SET SECTOR INTO 1771. MVI A,8CH ;CODE FOR READ W/O HD LD. READE: OUT DCOM ;SEND COMMAND TO 1771. RLOOP: IN WAIT ;WAIT FOR DRQ OR INTRQ. ORA A ;SET FLAGS. JP RDDONE ;DONE IF INTRQ. IN DDATA ;READ A DATA BYTE FROM DISK. MOV M,A ;PUT BYTE INTO MEMORY. INX H ;INCREMENT MEMORY POINTER. JMP RLOOP ;KEEP READING. RDDONE: LXI H,TLONTL ;GET TLONTL ADDRESS. MVI M,0 ;SET TO ZERO. IN DSTAT ;READ DISK STATUS. ANI 9DH ;LOOK AT ERROR BITS. RZ ;RETURN IF NONE. MOV D,A ;SAVE ERROR BITS. LDA ERCNT ;GET ERROR COUNT. DCR A ;DECREMENT COUNT. JNZ RRETRY ;TRY TO READ AGAIN. CALL ECOUNT ;COUNT AN ERROR. LXI H,RDMSG ;PRINT "READ ". ERMSG: CALL CPRINT ;PRINT ORIGIN MESSAGE. ERMSG1: MOV A,D ;GET ERROR BITS. ANI 80H ;IF BIT 7 HIGH, LXI H,NRMSG ;"NOT READY". CNZ CPRINT MOV A,D ;GET ERROR BITS. ANI 10H ;IF BIT 4 IS HIGH, LXI H,RNMSG ;PRINT "RECORD NOT FOUND" CNZ CPRINT MOV A,D ;GET ERROR BITS. ANI 8 ;IF BIT 3 IS HIGH, LXI H,CRCMSG ;PRINT "CRC ERROR". CNZ CPRINT MOV A,D ;GET ERROR BITS. ANI 4 ;IF BIT 2 IS HIGH, LXI H,LDMSG ;PRINT "LOST DATA". CNZ CPRINT MOV A,D ;GET ERROR BITS. ANI 1 ;IF BIT 1 IS HIGH, LXI H,BSYMSG ;PRINT "BUSY". CNZ CPRINT LXI H,ERRMSG ;PRINT "ERROR." CALL CPRINT JMP ETS ;JUMP TO ERROR PRINT ROUTINE. ; ; ERCHK - CHECK FOR RECORD NOT FOUND ERROR. ; ERCHK: MOV D,A ;SAVE ERROR BITS IN D. ANI 10H ;IF RECORD NOT FOUND, JNZ CHKSK ;DO A CHECK ON SEEK. MOV A,D ;OTHERWISE RESTORE BITS ORA A ;SET FLAGS, RET ;AND RETURN. ;CHECK FOR SEEK TO CORRECT TRACK, ;AND CHANGE IF NECESSARY. CHKSK: MVI A,0C4H ;SEND COMMAND TO 1771 OUT DCOM ;TO READ ADDRESS. IN WAIT ;WAIT FOR DRQ OR INTRQ. IN DDATA ;READ THE TRACK ADDRESS. MOV B,A ;SAVE IN REGISTER B. CHKS2: IN WAIT ;WAIT FOR INTRQ. JM CHKS2 ;NOT IF DRQ. MOV A,B ;UPDATE TRACK REGITER. OUT TRACK LDA TRK ;GET REQUIRED TRACK NO. CALL SEEK ;MOVE THE HEAD TO IT. MOV A,D ;GET ERROR BITS. ORA A ;SET FLAGS. RET ;RETURN FROM ERCHK. ; ; MOVE THE HEAD TO THE TRACK IN REGISTER A. ; SEEK: PUSH B ;SAVE B&C. MOV B,A ;SAVE DESTINATION TRACK. LDA RTCNT ;GET RETRY COUNT. SRETRY: STA SERCNT ;STORE IN ERROR COUNTER. IN TRACK ;READ PRESENT TRACK NO. MOV C,A ;SAVE IN C. MOV A,C ;DELAY. CMP B ;SAME AS NEW TRACK NO.? MOV A,B ;RESTORE A FROM B. JNZ NOTHR ;JUMP IF NOT THERE. THERE: POP B ;RESTORE B&C. ORA A ;RESET FLAGS. RET ;RETURN FROM SEEK. NOTHR: IF STD ;IF NOT FAST SEEK, OUT DDATA ;TRACK TO DATA REGISTER. BUSY: IN DSTAT ;READ DISK STATUS. RRC ;LOOK AT BIT 0. JC BUSY ;WAIT TILL NOT BUSY. STP: MVI A,SEEKC ;SEEK COMMAND. OUT DCOM ;ISSUE SEEK COMMAND. IN WAIT ;WAIT FOR INTRQ. IN DSTAT ;READ STATUS. ANI 91H ;LOOK AT BITS. JZ THERE ;OK IF ZERO. ENDIF IF FAST ;IF FAST SEEK, MVI A,40H ;IF CARRY = 1, JC SDIR ;STEP IN. MVI A,60H ;OTHERWISE, OUT. SDIR: OUT DCOM ;ISSUE STEP DIRECTION. MVI A,20 ;DELAY LOOP COUNT. DLOOP: DCR A ;DECREMENT COUNTER. JNZ DLOOP MOV A,C ;GET PRESENT TRACK. SUB B ;FIGURE TRACKS TO STEP. JP STEP ;IF NEGATIVE, CMA ;FIGURE THE INR A ;TWO'S COMPLEMENT. STEP: MOV C,A ;GET DIFFERENCE. MVI A,1 ;PERSCI STEP COMMAND. STEP1: OUT DCONT ;STEP PERSCI (E-14). DCR C ;COUNT THE STEP. JNZ STEP1 ;STEP UNTIL C = 0. IN WAIT ;CLEAR 1771. IN DSTAT MOV A,B ;GET DEST. TRACK. OUT TRACK ;UPDATE TRACK REG. LDA DISKNO ;GET DISK NUMBER. RLC!RLC!RLC!RLC ;SHIFT LEFT 4 BITS. ANI 30H ;LOOK AT BITS 4 AND 5. CMA ;INVERT. MOV B,A ;SAVE IN B. ANI 72H ;MAKE COMMAND TO OUT DCONT ;SWITCH WAIT FOR IN WAIT ;SEEK COMPLETE. MOV A,B ;RESTORE ORIG. BITS. ANI 0F2H ;SWITCH WAIT BACK. OUT DCONT XRA A ;MAKE GOOD RETURN. POP B ;RESTORE B&C. RET ENDIF IF STD ;IF NOT FAST SEEK, PUSH H ;SAVE H&L. LXI H,SECNT ;GET ADR OF SEEK ERR CTR. INR M ;ONE MORE SEEK ERROR. POP H ;RESTORE H&L. LDA ERCNT ;GET ERROR COUNT. DCR A ;DECREMENT COUNT. JNZ SRETRY ;RETRY SEEK. POP B ;RESTORE B&C. LXI H,SKMSG ;PRINT "SEEK ". IN DSTAT ;READ DISK STATUS. ANI 81H ;LOOK AT ERROR BITS. MOV D,A ;PUT IN REG D. CALL ERMSG ;DO ERROR MESSAGES. RET ;RETURN FROM SEEK. ENDIF ; ; MESSAGES. ; NRMSG: DB 'Not Ready $' RNMSG: DB 'Record Not Found $' CRCMSG: DB 'CRC $' LDMSG: DB 'Lost Data $' BSYMSG: DB 'Busy $' WPMSG: DB 'Protect $' WFMSG: DB 'Fault $' ERRMSG: DB 'ERROR. $' HEMSG: DB 13,10,'Home Error. ',13,10,36 RDMSG: DB 13,10,'Read $' WTMSG: DB 13,10,'Write $' SKMSG: DB 13,10,'Seek $' TSMSG: DB 13,10,'Track ' TRKM: DB 0 TRKL: DB 0 DB ' Sector ' SECM: DB 0 SECL: DB 0 CRLF: DB 13,10,36 OMSG: DB 13,10,'Tarbell Disk Diagnostic ' DB 13,10 IF STD DB 'Standard ' ENDIF IF FAST DB 'Fast Seek ' ENDIF DB 'Version ',VN/10+48,46 DB VN MOD 10+48,13,10 DB TRACKS/10+48,TRACKS MOD 10+48 DB ' Tracks ' DB SECTS/10+48,SECTS MOD 10+48 DB ' Sectors ',13,10 IF SINGLE DB 13,10,'For Tarbell Single Density Board$' ENDIF IF NOT SINGLE DB 13,10,'For Tarbell Double Density Board$' ENDIF ; SELMSG: DB 13,10,10,'Select Drive. (A/B/C/D or Q to quit) $' REMSG: DB 13,10,'How Many Retrys? (0-9) $' STPMSG: DB 13,10,'Select Step Rate.' IF NOT SINGLE DB '(3ms = 0, 6ms = 1, 10ms = 2, 15ms = 3)? $' ENDIF IF SINGLE DB '(6ms = 1, 10ms = 2, 20ms = 3)? $' ENDIF LSMSG: DB 13,10,'Full Track Seek? (Y/N) $' RMSG: DB 13,10,'To Start Test Type Return. $' RECMSG: DB 13,10 REC: DB 0,0,0,0 DB ' Read Errors Detected. ',13,10,36 AMSG: DB 13,10,'Aborting Test. ',13,10,36 GMSG: DB 13,10,10,36 ; WECNT: DB 0 ;WRITE ERROR COUNT. SECNT: DB 0 ;SEEK ERROR COUNT. BCRETH: DB 0 ;MSD'S OF READ ERROR COUNT. BCRETO: DB 0 ;LSD'S OF READ ERROR COUNT. DRIVE: DB 0 ;DRIVE. LATCH: DB 0 ;LATCH CODE. DISKNO: DB 0 ;DISK NUMBER. TRK: DB 0 ;TRACK NUMBER. SECT: DB 0 ;SECTOR NUMBER. BCDTRK: DB 0 ;TRACK NUMBER IN BCD. BCDSEC: DB 0 ;SECTOR NUMBER IN BCD. RTCNT: DB 0 ;RETRY COUNT. ERCNT: DB 0 ;ERROR COUNT FOR RETRIES. SERCNT: DB 0 ;SEEK RETRY COUNTER. TLONTL: DB 0 ;READ ERROR FLAG. LST: DB 0 ;LONG SEEK FLAG. OT: DB 0 ;LST OUTER TRACK. IT: DB 0 ;LST INNER TRACK. OTIT: DB 0 ;OTIT. CPMS: DW 0 ;OLD STACK POINTER. DIB: DS 128 ;DISK INPUT BUFFER. DS 64 ;STACK AREA. STACK: END