; ; D D D ; ; DYSAN CORPORATION ; C.E. DIVISION ; 1244 REAMWOOD AVENUE ; SUNNYVALE, CAL. 94086 ; 408-734-1624 ; ; VERSION [ 1.0 ] ; TITLE 'Drive Diagnostic Program for CP/M 80 1/15/83' PAGE 75 ; FILE DDD.ASM ; ; DIGITAL RESEARCH'S MAC MACRO ASSEMBLER HAS ; BEEN USED TO COMPILE THIS PROGRAM. ; ; DIGITAL RESEARCH ; P.O. BOX 579 ; 801 LIGHTHOUSE AVENUE ; PACIFIC GROVE, CA 93950 ; (408) 649-3896 ; ; THIS EXAMPLE SKELETON PROGRAM MAY BE USED TO READ ; THE DIGITAL DIAGNOSTIC DISKETTE. MANY FEATURES CAN ; BE ADDED TO MAKE A MORE SUBSTANTIAL PROGRAM. THE ; READ ROUTINES ARE DIRECTED AT THE 8 INCH "DDD," BUT ; CAN BE ALTERED FOR 5 1/4 INCH "DDD" ; ; THE WESTERN DIGITAL 1793 FLOPPY CONTROLLER HAS BEEN ; CHOSEN BECAUSE OF ITS WIDE USE IN MICROCOMPUTERS. ; THIS PROGRAM DOESN'T DEPEND UPON THIS CONTROLLER, BUT ; THE CONTROLLER USED MUST BE ABLE TO READ FM OF MFM ; FORMATS. ; ; WESTERN DIGITAL CORP. ; P.O. BOX 2180 ; 3128 REDHILL AVENUE ; NEWPORT BEACH, CAL 92663 ; (714) 557-3550 ; ; N O T I C E ; THIS DOCUMENT CONTAINS INFORMATION DEVELOPED BY ; DYSAN CORPORATION (DYSAN) AND IS FURNISHED FOR ; INFORMATION ONLY. ; DYSAN MAKES NO WARRANTY OR REPRESENTATION (EXPRESSED ; OR IMPLIED) WITH RESPECT TO THE ACCURACY, COMPLETENESS ; OR USEFULNESS OF THE INFORMATION CONTAINED HEREIN. ; FURTHER, DYSAN ASSUMES NO RESPONSIBILITY FOR LIABILITY ; OR DAMAGE OF ANY KIND WHICH MAY RESULT FROM THE USE ; OF THE INFORMATION CONTAINED HEREIN. PAGE ; THE FOLLOWING FEATURES OF { DDD } ARE UTILIZED: ; ; RADIAL ALIGNMENT CHECK ; AZIMUTH ALIGNMENT CHECK ; CENTERING ; STEPPER HYSTERESIS ; INDEX TIMING ; ; *** CONFIGURATION *** ; Modifications (in upper & lower case) by Jim Petersen in March, 1984: ; A. Televideo TS-802 integral terminal ; B. 8080 ASSEMBLY LANGUAGE ; C. TIMING BASED ON 4 MHZ Z80 PROCESSOR ; D. DIRECT CONSOLE I/O TO CP/M 80 ; E. Disk operation modified for Televideo TS-802 ; 340k (formatted), 5 1/4" floppy drive. ; F. diagnostic disk (508-400) ; *** MACRO CALL BDOS DIRECT *** ; THIS MACRO IS PRESENTLY USED TO LINK CONSOLE I/O ; ONLY, THE DISK I/O ROUTINES ALSO MAY BE LINKED ; TO CP/M 2.2 WITH THIS MACRO. ; ; E.G. GOBIOS 24 ; SELECT DRIVE ; ; ; FUNCTION: ; LOADS WARM BOOT ADDRESS TO BDOS ; AND COMPUTES OFFSET TO ROUTINE. WBOOT EQU 0 ; WARM BOOT ADDRESS GOBIOS MACRO @FUNC LHLD WBOOT+1 ; WARM BOOT ADDRESS LXI D,@FUNC ; OFFSET DAD D ; ADD OFFSET PCHL ; GO TO BDOS ROUTINE ENDM PAGE ; *** CONSOLE FUNCTIONS *** ; THE FOLLOWING ARE DIRECT CONSOLE COMMANDS ; WHICH CAN BE ALTERED FOR MOST CONSOLES. ; NOTE: ; The text print routine must be altered ; if "column" is sent before "row." ; The cursor address bias should also be checked. ; *** MISCELLANEOUS EQUATES *** CR EQU 0DH ; CARRIAGE RETURN LF EQU 0AH ; LINE FEED ESC EQU 1BH ; ESCAPE BS EQU 8 ; BACKSPACE BELL EQU 7 ; AUDIO ALERT lead$in equ esc ; console lead-in ADD$CUR EQU 3DH ; address cursor command (=) CLR$CO EQU 2AH ; clear to foreground spaces (*) END$LN EQU 54H ; clear to end of line (T) ; *** FLOPPY CONTROLLER PORT EQUATES *** ; CHANGE THE FOLLOWING PORT ASSIGNMENTS FOR ; YOUR SYSTEM. ; ; "FDC" ACRONYM FLOPPY DISK CONTROLLER ; ; FDC PORT ASSIGNMENTS: ; FDC EQU 14H ; base port address FDC ; CMD EQU FDC ; COMMAND REG. STAT EQU FDC ; STATUS REG. TRK EQU FDC+1 ; TRACK REG. SEC EQU FDC+2 ; SECTOR REG. DATA EQU FDC+3 ; DATA REG. DMA EQU FDC-4 ; DMA controller ; DSEL EQU FDC+4 ; drive select ; *** FLOPPY CONTROLLER COMMANDS *** CLEAR EQU 0D0H ; clear FDC SDMA EQU 87H ; start DMA transfer RSEC EQU 80H ; read sector RADDR EQU 0C0H ; read address SEEK EQU 18H ; seek track RESTORE EQU 8 ; home head(s) SDELAY EQU 4 ; SEEK DELAY FLAG ; *** FLOPPY CONTROLLER VARIABLES *** RATE EQU 1 ; STEP RATE RETRY EQU 1 ; READ RETRIES FDELAY EQU 11 ; FDC DELAY TTRK EQU 40 ; total number of tracks SECTOR EQU 16 ; sectors per track LNEG EQU SECTOR+2 ; last neg. sector +2 LPOS EQU SECTOR+1 ; last pos. sector +2 TSEC EQU (SECTOR/2)-1 ; centering test REF EQU 798 ; REFERENCE TIME (SINGLE DEN) PAGE ; *** MAIN PROGRAM LOOP *** ORG 100H ; === ==== DI ; don't let BIOS interrupt LXI SP,STACK ; INIT STACK CALL SELECT ; SELECT DRIVE ; MAIN: LXI SP,STACK ; RESET STACK CALL CLS ; CLEAR DISPLAY LXI H,ME1 ; DISPLAY MENU CALL TEXT CALL CI ; SELECTION? CPI 'R' ; RADIAL JZ RADIAL CPI 'A' ; AZIMUTH JZ AZIMUTH CPI 'C' ; CENTERING JZ CENTER CPI 'H' ; HYSTERESIS JZ HYSTER CPI 'S' ; RPM JZ RPM CPI 'I' ; INDEX JZ INDEX cpi 'N' ; select new drive jnz main1 call select jmp main main1: CPI 'E' ; EXIT TO DOS JZ EXIT MVI A,BELL ; NOT VALID CALL CO JMP MAIN ; TRY AGAIN... PAGE ; *** EXIT TO DOS *** EXIT: CALL CLS ; CLEAR DISPLAY EI ; give control back to BIOS JMP WBOOT ; *** CONSOLE STATUS *** ; RETURNS WITH ZERO STATUS FLAG SET. CSTAT: PUSH H ; SAVE ALL REGISTERS PUSH D PUSH B CALL CSTAT1 ; DATA READY? POP B POP D POP H ORA A RET CSTAT1: GOBIOS 3 ; MACRO LHLD WBOOT+1 ; WARM BOOT ADDRESS LXI D,3 ; OFFSET DAD D ; ADD OFFSET PCHL ; GO TO BDOS ROUTINE ; *** CONSOLE INPUT *** ; RETURNS CHARACTER IN A CI: PUSH H ; SAVE ALL REGISTERS PUSH D PUSH B CALL CI1 ; TAKE CHARACTER POP B POP D POP H CPI ESC ; EXIT? JZ MAIN ; YES CPI 'a' ; CONVERT TO UPPER CASE RC ; ONLY... CPI '{' RNC ANI '^'+1 RET CI1: GOBIOS 6 ; MACRO LHLD WBOOT+1 ; WARM BOOT ADDRESS LXI D,6 ; OFFSET DAD D ; ADD OFFSET PCHL ; GO TO BDOS ROUTINE PAGE ; *** CONSOLE OUTPUT *** ; ENTER WITH CHARACTER IN A CO: PUSH H ; SAVE ALL REGISTERS PUSH D PUSH B MOV C,A ; PASS CHAR IN C CALL CO1 POP B POP D POP H RET CO1: GOBIOS 9 LHLD WBOOT+1 ; WARM BOOT ADDRESS LXI D,9 ; OFFSET DAD D ; ADD OFFSET PCHL ; GO TO BDOS ROUTINE ; *** LINE INPUT *** ; USED TO INPUT DATA GREATER THAN ONE ; CHARACTER AND IS TERMINATED BY "CR." GETLN: LXI D,BUFFER ; INPUT BUFFER ; GL1: CALL CI ; WAIT FOR INPUT CPI LF ; LINE FEEDS NOT ALLOWED JZ GL1 CPI '_' ; TREAT AS BACKSPACE JZ BACK CPI BS ; CHECK FOR BACKSPACE JZ BACK CPI 7FH ; DELETE CHAR? JZ BACK CPI CR JZ GL2 CPI ' ' JC GL1 ; CONTROL CHARACTERS NOT ALLOWED ; GL2: STAX D ; STORE CHAR INX D ; NEXT ADDRESS CALL CO ; ECHO CHAR CPI CR ; END OF LINE? RZ ; YES! LXI H,BUFFER+4 ; END OF BUFFER CALL DEHL ; CHECK JNZ GL1 ; NO! PAGE ; BACK: LXI H,BUFFER ; CAN BACKUP? CALL DEHL JZ GL1 ; NO! DCX D ; BACKUP TEXT POINTER MVI A,BS ; BACKUP CURSOR CALL CO MVI A,' ' ; STORE SPACE CALL CO MVI A,BS ; ADJUST CURSOR CALL CO JMP GL1 ; NEW CHAR ; *** BIAS FROM SELECTED TRACK *** ; SETS THE REQUIRED OFFSET FOR HYSTERESIS ; TEST. OFFSET: CALL CLS ; CLEAR DISPLAY LXI H,ME6 ; OFFSET? CALL TEXT CALL GETLN ; INPUT OFFSET CALL GETNUM ; CONVERT TO HEX CPI CR ; AT END OF LINE? JNZ OFFSET1 ; ERROR... MOV A,H ; CHECK LIMITS ORA A JNZ OFFSET1 MOV A,L CPI TTRK+1 ; GREATER THAN LAST TRACK? JNC OFFSET1 STA BIAS ; SAVE OFFSET RET ; OFFSET1: MVI A,BELL ; ALERT OPERATOR CALL CO JMP OFFSET PAGE ; *** INPUT TRACK LOCATIONS *** ; INPUT TRACK LOCATIONS FOR RADIAL ; HYSTERESIS, CENTERING, AND INDEX TESTS. ; B CONTAINS UPPER LIMIT UPON ENTRY. INP$TRK: CALL CLS ; CLEAR DISPLAY CALL TEXT ; output message pointed to by HL ; INP$TRK1: CALL CI ; get char. CMP B ; selection too high? JNC INP$TRK2 ; yes SUI 'A' ; selection too low? JC INP$TRK2 ; yes LHLD TEMP ; start of track table MVI D,0 MOV E,A DAD D ; ADD OFFSET MOV A,M ; get a certain track # from table JMP TRACK ; SEEK TO TRACK ; INP$TRK2: MVI A,BELL ; ALERT CALL CO JMP INP$TRK1 ; TRY AGAIN... ; *** radial and hysteresis track locations *** RH$TBL DB 0 DB 5 DB 16 DB 19 DB 30 DB 39 ; *** index track table *** IX$TBL: DB 0 DB 34 ; *** centering tracks *** CEN$TBL: DB 21 DB 24 DB 27 PAGE ; *** PRINT DECIMAL NUMBERS *** ; ENTER WITH NUMBER TO BE PRINTED IN DE PNUM: PUSH H ; SET UP STACK LXI H,10 ; TERMINATOR... PUSH H PUSH H ; PN1: CALL DIV16 ; DIVIDE NUMBER BY (10) MOV A,D ; CHECK RESULT ORA E ; = 0 JZ PN2 XTHL DCR L PUSH H LXI H,10 JMP PN1 ; DIVIDE AGAIN ; PN2: POP D ; DISPLAY VALUES MOV E,L ; PN3: MOV A,E ; CHECK FOR TERMINATOR (10) CPI 10 POP D ; NEXT DIGIT RZ ADI '0' ; ADD ASCII BIAS CALL CO JMP PN3 ; *** 16 BIT SUBTRACTION *** ; SUBTRACT "DE" FROM "HL" SUBDE: MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A RET PAGE ; *** CONVERT ASCII DECIMAL NUMBER TO BINARY *** ; RETURNS 16 BIT HEX VALUE IN HL GET$NUM: CALL SKSP ; SKIP SPACES AND RETURN CHAR LXI H,0 ; CLEAR COUNTER MOV B,H ; CLEAR B ; GET$NUM1: CPI CR ; END OF LINE? CPI '0' ; LESS THAN RC ; YES ERROR! CPI ':' ; UPPER LIMIT RNC ; RETURNS "CR" MVI A,0F0H ; MASK UPPER NIBBLE ANA H RNZ INR B ; +1 PUSH B ; SAVE COUNT... MOV B,H MOV C,L ; SWAP "HL" WITH "BC" DAD H DAD H DAD B DAD H LDAX D ; LOAD SAME CHAR... INX D ; NEXT CHAR ANI 0FH ; MASK LOWER NIBBLE ADD L MOV L,A ; SAVE RESULT MVI A,0 ; CLEAR A ADC H ; ADD CARRY MOV H,A POP B ; RESTORE COUNTER... LDAX D ; LOAD NEXT CHAR... JMP GETNUM1 ; *** SKIP OVER SPACES IN TEXT BUFFER *** SKSP: LXI D,BUFFER ; POINT TO TEXT BUFFER ; SKSP1: LDAX D ; CHECK FOR SPACE CPI ' ' ; FIRST NON SPACE RETURN RNZ INX D JMP SKSP1 ; *** COMPARE DE TO HL *** DEHL: MOV A,L ; COMPARE E TO L CMP E ; IF NOT ZERO RETURN RNZ MOV A,H CMP D RET PAGE ; *** 16/24 BIT DIVIDE ROUTINE *** ; DIVIDE HL BY DE ; DIV16: XRA A ; OPTIONAL 16 BIT DIVIDE ; DIV24: STA MSB ; NORMAL 24 BIT DIVIDE SHLD MSB1 LXI H,MSB2 MVI M,24+1 LXI B,0 PUSH B DIV25: MOV A,E RAL MOV E,A MOV A,D RAL MOV D,A LDA MSB RAL STA MSB DCR M POP H RZ MVI A,0 ACI 0 DAD H MOV B,H ADD L LHLD MSB1 SUB L MOV C,A MOV A,B SBB H MOV B,A PUSH B JNC DIV26 DAD B XTHL ; DIV26: LXI H,MSB2 CMC JMP DIV25 PAGE ; *** CLEAR CONSOLE DISPLAY *** ; CLEAR CONSOLE TO FOREGROUND SPACES. CLS: MVI A,LEAD$IN ; LEAD-IN CALL CO MVI A,CLR$CO ; CLEAR TO FOREGOUND SPACES JMP CO ; *** CLEAR DISPLAY LINE *** CLINE: MVI A,0 ; cursor to col. 1 so we erase whole line STA COLUMN LXI H,SET$CUR CALL TEXT MVI A,LEAD$IN ; LEAD-IN BYTE CALL CO MVI A,END$LN ; CLEAR TO END OF LINE CALL CO RET ; *** FATAL ERROR MSG *** FATAL: CALL CLINE ; CLEAR LINE MVI A,30 ; COLUMN POSITION STA COLUMN LXI H,SET$CUR ; position cursor to col. 31 CALL TEXT LXI H,ME2 ; FATAL ERROR MSG CALL TEXT RET PAGE ; *** PRINT STRING OF TEXT *** ; ENTER WITH HL POINTING TO TEXT STRING, ; TERMINATE STRING WITH NULL. ; ; DIRECTION CURSOR POSITION IS USED FOR DISPLAYS. ; THE VALUE (-1) AT THE START OF STRING INDICATES ; THAT COLUMN AND ROW POSITION WILL FOLLOW. ; E.G. ; DB -1,50,10,'NOW IS THE TIME' ; ^ ^ ^ ; | | |_ROW POSITION (ADD BIAS IF NEEDED) ; | |_COLUMN POSITION (ADD BIAS IF NEEDED) ; |_FLAG (SEND CONSOLE LEAD-IN SEQUENCE) TEXT: MOV A,M ; LOAD CHAR. ORA A ; END OF STRING? RZ ; YES CPI -1 ; POSITION CURSOR? JZ TEXT1 ; YES INX H ; NEXT CHAR. CALL CO ; OUTPUT JMP TEXT ; TEXT1: INX H ; MOVE PAST COMMAND MVI A,LEAD$IN ; LEAD-IN FOR CONSOLE CALL CO ; ISSUE. mvi a,add$cur ; cursor address command call co ; ship it. inx h ; must issue row pos. first MOV A,M ; row position... adi 31 ; add offset for ADM-3A cursor command dcx h ; go back to col. pos. CALL CO MOV A,M ; column position... adi 31 ; offset again (for col. this time) CALL CO INX H inx h ; skip to text section of msg. JMP TEXT PAGE ; *** CENTERING CHECK *** ; ; CENTERING TEST REQUIRES THE FDC TO READ ; ALL THE SECTORS BEFORE DISKETTE CENTERING ; IS CONSIDERED OK. CENTER: LXI H,CEN$TBL ; TRACK TABLE SHLD TEMP LXI H,ME9 ; track selection message MVI B,'D' ; limit for their entry CALL INP$TRK ; ask for track # CALL CLS ; CLEAR DISPLAY LXI H,ME10 ; CENTERING MSG. CALL TEXT LXI H,ME15 ; frame around msg. CALL TEXT LXI H,ME11 ; "space bar for new track" CALL TEXT ; CENTER1: MVI A,10 ; set row pos. STA ROW CALL RD$TRK ; READ CENTERING TRACK JC CENTER3 ; carry bit says fatal error occured. CALL CLINE ; CLEAR LINE MVI A,30 ; set column pos. STA COLUMN LXI H,SET$CUR CALL TEXT LDA DIFF ; must be 0 for no error ORA A LXI H,ME3 ; "RE-CLAMP DISKETTE" JNZ CENTER2 MOV A,C CPI TSEC ; ALL SEC READ? JNZ CENTER2 LXI H,ME4 ; "CENTERING OK" ; CENTER2: CALL TEXT CALL CSTAT ; ABORT? JZ CENTER1 CALL CI CPI ' ' ; NEW TRACK? JNZ CENTER1 ; NO... JMP CENTER ; YES... ; CENTER3: CALL FATAL ; FATAL ERROR JMP CENTER2 PAGE ; *** AZIMUTH ALIGNMENT CHECK *** AZIMUTH: CALL CLS ; CLEAR DISPLAY... MVI A,34 ; azimuth track CALL TRACK ; seek the track LXI H,ME12 ; TYPE OF TEST MSG CALL TEXT LXI H,ME15 ; frame around msg. CALL TEXT MVI A,10 ; SET DISPLAY ROW STA ROW ; AZIMUTH1: LXI H,AZI$TAB SHLD XPOINT ; store current azimuth angle for printing SHLD YPOINT CALL RD$TRK ; READ AZIMUTH TRACK JC AZIMUTH3 ; FATAL ERROR CALL CLINE ; CLEAR LINE MVI A,20 ; screen position for negative angle STA COLUMN LXI H,SET$CUR CALL TEXT MVI A,'-' ; show that it's negative CALL CO MVI A,' ' ; SPACE CALL CO LHLD YPOINT MOV E,M ; negative translation data MVI D,0 CALL PNUM ; DISPLAY LXI H,ME5 ; "minutes" CALL TEXT MVI A,45 ; screen position for positive angle STA COLUMN LXI H,SET$CUR CALL TEXT MVI A,'+' ; show that it's positive CALL CO MVI A,' ' ; SPACE CALL CO LHLD XPOINT MOV E,M ; positive translation data MVI D,0 CALL PNUM LXI H,ME5 ; "minutes" CALL TEXT ; AZIMUTH2: CALL CSTAT ; did they type something? JZ AZIMUTH1 CALL CI ; test for abort JMP AZIMUTH1 ; no abort ; ; FATAL ERROR HAS OCCURRED ; AZIMUTH3: CALL FATAL ; FATAL READ ERROR JMP AZIMUTH2 PAGE ; *** RADIAL ALIGNMENT CHECK *** RADIAL: LXI H,RH$TBL ; TABLE POINTER SHLD TEMP LXI H,ME7 ; give them the selections MVI B,'G' ; limit for their entry CALL INP$TRK ; ask for track and seek to it CALL CLS LXI H,ME8 ; PRINT SCALE CALL TEXT LXI H,ME11 ; SPACE BAR MSG CALL TEXT ; RADIAL1: MVI A,11 ; SET ROW POSITION STA ROW ; LXI H,RAD$POS ; RADIAL POSITIVE SHLD XPOINT ; CURSOR TABLE ; LXI H,RAD$NEG ; RADIAL NEGATIVE SHLD YPOINT ; CURSOR TABLE ; CALL RD$TRK ; READ RADIAL TRACK JC RADIAL4 ; FATAL ERROR HAS OCCURRED CALL CLINE ; CLEAR LINE (1) LDA ROW PUSH PSW INR A ; CLEAR LINE (2) STA ROW CALL CLINE POP PSW ; RESET LINE POSITION STA ROW LHLD YPOINT ; NEGATIVE MOV A,M STA COLUMN ; POSITION CURSOR MOV B,A LXI H,SET$CUR CALL TEXT MVI A,'^' ; SET POINTER CALL CO LHLD XPOINT MOV A,M ; POSITIVE POSITION STA COLUMN MOV C,A ; SAVE CURSOR POSITION LXI H,SET$CUR ; SET CURSOR CALL TEXT MVI A,'^' CALL CO MOV A,B STA COLUMN ; RESET COLUMN POSITION LDA ROW ; DOWN ONE LINE INR A STA ROW PAGE ; *** SET POINTERS AND DRAW LINE *** ; USED TO DRAW THE GRAPHIC DISPLAY OF THE ; RADIAL ERROR. LXI H,SET$CUR ; POSITION CURSOR CALL TEXT MOV A,C SUB B ; LINE LENGTH DCR A ; LESS (1) MOV B,A MVI A,'|' ; POINTER CALL CO ; RADIAL2: MVI A,'_' ; JOINTING LINE CALL CO DCR B ; LINE LENGTH -1 JNZ RADIAL2 MVI A,'|' CALL CO ; RADIAL3: CALL CSTAT ; CHECK FOR ABORT JZ RADIAL1 ; READ AGAIN CALL CI ; NEW TRACK? CPI ' ' JNZ RADIAL1 ; NO JMP RADIAL ; YES ; *** FATAL RADIAL ERROR *** RADIAL4: CALL CLINE ; CLEAR DISPLAY LDA ROW ; NEXT LINE INR A STA ROW CALL CLINE CALL FATAL ; FATAL READ ERROR JMP RADIAL3 ; ABORT? PAGE ; *** STEPPER HYSTERESIS CHECK *** ; ; THIS ROUTINE USES ONE OF THE PROGRESSIVE OFFSET ; TRACKS TO DETERMINE THE STEPPER MOTOR HYSTERESIS. HYSTER: LXI H,RH$TBL ; TABLE POINTER SHLD TEMP LXI H,ME7 ; TRACK MSG MVI B,'G' ; LIMIT CALL INP$TRK ; SEEK TRACK MVI A,10 ; SET ROW STA ROW CALL OFFSET ; OFFSET FROM CALL CLS ; SELECTED TRACK. LXI H,ME14 ; DISPLAY TEST CALL TEXT LXI H,ME15 ; FRAME CALL TEXT LXI H,ME11 ; NEW TRACK MSG. CALL TEXT ; HYSTER1: LDA BIAS ; OFFSET FROM TRACK MOV B,A LDA CTRK ; SAVE CURRENT TRACK STA SAVTRK ADD B ; ADD BIAS TO CURRENT TRACK CPI TTRK ; WITHIN LIMITS? JC HYSTER2 ; OK! MVI A,TTRK ; SET LAST TRACK ; ; MOVE TO (ID) INSIDE DIAMETER HYSTER2: CALL TRACK ; SEEK TO TRACK LDA SAVTRK ; BACK TO TEST TRACK CALL TRACK ; SEEK CALL RD$TRK ; READ TRACK JC HYSTER8 ; FATAL ERROR!!! LDA DIFF ; DIFFERENCE STA HYERR ; SAVE THE DIFFERENCE ; MOVE TO (OD) OUTSIDE DIAMETER LDA BIAS ; TRACKS TO MOVE MOV B,A LDA CTRK ; CURRENT TRACK SUB B JNC HYSTER4 ; OK TO MOVE XRA A ; SET TO TRACK (0) PAGE ; HYSTER4: CALL TRACK ; SEEK TO TRACK LDA SAVTRK ; BACK TO TEST TRACK CALL TRACK CALL RD$TRK ; READ TRACK JC HYSTER8 ; FATAL ERROR!! LDA HYERR ; LOAD ERROR FIRST MOV C,A ; READ OPERATION LDA DIFF ; LAST READING SUB C JP HYSTER6 CMA INR A ; HYSTER6: CALL HYSTER9 ; HYSTER7: CALL CSTAT ; ABORT? JZ HYSTER1 ; RETEST CALL CI CPI ' ' ; NEW PARAMETERS JZ HYSTER JMP HYSTER1 ; NEW TRACK AND OFFSET ; HYSTER8: CALL FATAL ; FATAL READ ERROR CALL HOME ; RECAL. DRIVE JMP HYSTER7 PAGE ; *** DISPLAY HYSTERESIS ERROR *** ; PRESENTLY SET UP FOR 48 TPI DRIVES ; WITH INCREMENTS IN .5 MILLINCHES. HYSTER9: PUSH PSW ; SAVE ERROR CALL CLINE ; CLEAR DISPLAY MVI A,25 ; SET COLUMN STA COLUMN LXI H,SET$CUR CALL TEXT LXI H,ME16 ; HYSTERESIS ERROR MSG CALL TEXT POP PSW ORA A JNZ HYSTER11 MOV C,A ; COUNT MVI B,5 ; INCREMENTS XRA A ; CLEAR ACC. ; HYSTER10: ADD B DAA DCR C JNZ HYSTER10 ; HYSTER11: PUSH PSW ANI 0F0H ; MASK UPPER NIBBLE RAR!RAR!RAR!RAR ADI '0' ; ADD ASCII BIAS CALL CO MVI A,'.' ; DECIMAL POINT CALL CO POP PSW ANI 0FH ADI '0' CALL CO RET PAGE ; *** INDEX TIMING *** ; ; THIS FUNCTION COMPUTES THE TIME FROM LEADING ; EDGE OF INDEX TO FIRST SECTOR ID MARK ; AND DISPLAYS IT IN 10.0 USEC INCREMENTS ; NOTE: ; DYSAN AAD DISK IS USED FOR REFERENCE. INDEX: MVI A,10 ; SET ROW STA ROW LXI H,IX$TBL ; TRACK TABLE SHLD TEMP LXI H,ME13 ; TRACK LOCATIONS MVI B,'C' CALL INP$TRK ; MOVE TO INDEX TRACK CALL CLS ; CLEAR DISPLAY LXI H,ME17 ; DISPLAY SCALE CALL TEXT LXI H,ME15 CALL TEXT LXI H,ME11 CALL TEXT ; INDEX1: LXI H,0 ; CLEAR COUNTER SHLD TEMP MVI C,5 ; AVERAGE 5 READINGS ; INDEX2: CALL CLPEND ; CLEAR FDC CALL PRG$DMA ; PROGRAM CONTROLLER LXI D,0 ; CLEAR COUNTER ; INDEX3: IN STAT ; WAIT FOR NEXT INDEX ANI 2 JNZ INDEX3 ; COMPUTE TIME FROM INDEX TO ID INDEX4: IN STAT ; LOOP UNTIL NEXT INDEX ANI 2 JZ INDEX4 ; ; READ ADDRESS... ; NOP ; 1.00 MVI A,RADDR ; 1.75 OUT CMD ; 2.75 CALL DELAY ; [ 50 USEC ] MVI A,SDMA ; 1.75 OUT DMA ; 2.75 PAGE ; ; 10 USEC TEST CNT. LOOP INDEX5: INX D ; 1.50 [ COUNTER ] INX H ; 1.50 IN STAT ; 2.75 ANI 1 ; 1.75 JNZ INDEX5 ; 2.50 ; INDEX6: LXI H,6 ; ADJUST OVERHEAD DAD D ; ERROR (60 USEC) XCHG LHLD TEMP DAD D ; ADD CNT SHLD TEMP DCR C ; NEXT READING JNZ INDEX2 XCHG LXI H,5 ; DIVIDE BY 5 CALL DIV16 DAD D ; ADD REMAINDER XCHG LXI H,0 ; COUNTER... LDA SECBUF+2 ; MUST CONTAIN SEC 1 ID CPI 1 JNZ INDEX9 ; OUT OF RANGE MVI A,10 ; LOOP TIME * CNT INDEX7: DAD D DCR A JNZ INDEX7 LXI D,REF ; TIMING REF CALL SUBDE ; TO ID MARK XCHG ; (200 USEC) AAD JNC INDEX8 MOV A,E CMA MOV E,A MOV A,D ; NEGATE "DE" CMA MOV D,A INX D LXI H,200 ; 200 - ERROR CALL SUBDE JNC INDEX9 LXI H,0 ; OUT OF RANGE JMP INDEX9 ; INDEX8: LXI H,200 ; 200 + ERROR DAD D ; INDEX9: XCHG PUSH D CALL CLINE ; CLEAR LINE MVI A,25 STA COLUMN LXI H,SET$CUR ; POSITION CURSOR CALL TEXT LXI H,ME18 ; TIME IN MS. CALL TEXT POP D CALL PNUM ; DISPLAY TIME CALL CSTAT ; ABORT? JZ INDEX1 ; RETEST CALL CI ; ESC? CPI ' ' ; NEW TRACK? JZ INDEX ; YES JMP INDEX1 ; NEW TRACK PAGE ; *** CHECK SPINDLE SPEED *** ; ALL TIMING IS BASED ON 4 MHZ Z80 CPU ; RPM: CALL CLS ; CLEAR DISPLAY LXI H,ME19 ; TEST PERFORMED CALL TEXT LXI H,ME15 ; FRAME... CALL TEXT MVI A,10 ; SET ROW STA ROW ; RPM1: CALL RPM2 ; COMPUTE TIME IN 100 US INCREMENTS SHLD TEMP ; STORE COUNT CALL CLINE ; CLEAR LINE MVI A,19 ; SET CURSOR STA COLUMN LXI H,SET$CUR CALL TEXT LHLD TEMP XCHG ; CONVERT TO MILLISECONDS LXI H,10 CALL DIV16 PUSH H ; SAVE REMAINDER CALL PNUM MVI A,'.' ; DECIMAL POINT CALL CO POP H XCHG CALL PNUM ; FRACTION LXI H,ME20 ; MILLISECONDS MSG CALL TEXT MVI A,50 STA COLUMN LXI H,SET$CUR CALL TEXT LHLD TEMP ; CONVERT TO RPM MVI A,9 ; DIVIDE BY 600,000 LXI D,27C0H CALL DIV24 PUSH H ; REMAINDER CALL PNUM MVI A,'.' ; FRACTION CALL CO POP H XCHG CALL PNUM LXI H,ME21 ; RPM MSG CALL TEXT CALL CSTAT ; ABORT? JZ RPM1 ; NO... CALL CI ; ESC KEY? JMP RPM1 ; NO... PAGE ; *** INDEX TO INDEX TIMING *** ; ; RETURNS TIME IN 100 US INCREMENTS TO CALLER IN HL. RPM2: CALL CLPEND ; CLEAR PENDING COMMANDS LXI H,0 ; CLEAR COUNTER RPM3: IN STAT ; LOOP UNTIL INDEX ANI 2 ; MASK ALL BUT INDEX BIT JNZ RPM3 ; NO INDEX RPM4: IN STAT ; IF INDEX... ANI 2 ; WAIT FOR NO INDEX JZ RPM4 ; IN INDEX HOLE ; ADD INDEX HOLE TO COUNT RPM5: CALL RPM7 ; 4.25 IN STAT ; 2.75 ANI 2 ; 1.75 JNZ RPM5 ; 2.50 ; TOTAL = 11.25 ; COUNT UNTIL NEXT INDEX RPM6: CALL RPM7 ; 4.25 IN STAT ; 2.75 ANI 2 ; 1.75 JZ RPM6 ; 2.50 RET ; TOTAL = 11.25 ; *** RPM TIMING LOOP *** ; THE LOOP TIME MUST BE ADJUSTED FOR 100 US ; INCREMENTS. ; ; NOTE: "RPM5" AND "RPM6" LOOP TIME MUST BE COUNTED. ; RPM7: INX H ; 1.50 MVI A,22 ; 1.75 ; RPM8: DCR A ; 1.00 (22 * 1.00) = 22 USEC JNZ RPM8 ; 2.50 (22 * 2.50) = 55 USEC INX D ; 1.50 INX D ; 1.50 INX D ; 1.50 INX D ; 1.50 RET ; 2.50 ; TOTAL = 88.75 PAGE ; *** READ DDD TRACK *** ; ATT: MAIN READ ROUTINE FOR PROGRAM. ; ============================== ; ; READS THE POSITIVE AND NEGATIVE OFFSET ; SECTORS AND RETURNS POINTERS TO THE ; TRANSLATION TABLES SET BY CALLER. ; RD$TRK: MVI C,LPOS ; LAST SECTOR MVI A,1 ; BEGINNING SECTOR POSITIVE CALL RD$SEC ; READ POSITIVE OFFSETS CPI 1 ; UNABLE TO READ JZ RD$TRK2 ; FIRST SEC? STA DIFF ; STORE LAST SECTOR TESTED MVI C,LNEG MVI A,2 ; BEGINNING SECTOR NEGATIVE CALL RD$SEC ; READ NEGATIVE OFFSETS CPI 2 ; FATAL ERROR? JZ RD$TRK2 ; SET ERROR FLAG ; ; POSITIVE SECTOR TRANSLATION ; LDA DIFF INR A ; ADJUST SECTOR NUMBER SUI 4 RAR ; DIVIDE BY TWO LHLD XPOINT ; TRANSLATE TABLE POINTER MVI D,0 ; SETUP FOR OFFSET MOV E,A DAD D ; ADD OFFSET SHLD XPOINT ; SET POINTER ; ; NEGATIVE SECTOR TRANSLATION IN SEC ; LAST SECTOR SUI 4 RAR ; DIVIDE BY TWO MOV C,A SUB E ; DIFF. FOR HYSTERESIS STA DIFF MOV E,C ; OFFSET LHLD YPOINT ; TRANSLATION TABLE POINTER DAD D ; OFFSET IN TABLE SHLD YPOINT ; SET POINTER ORA A ; CLEAR CARRY RET ; SET FATAL ERROR FLAG, CALLER PROCESSES ; THE ERROR. RD$TRK2: STC ; CARRY = FATAL ERROR RET PAGE ; *** READ SECTORS BY INCREMENTS OF TWO *** ; ; ENTER WITH FIRST SECTOR TO BE READ IN A. ; RETURNS TO CALLER ON ERROR OR LAST SECTOR. ; NOTE: ; Z FLAG SET IF GOOD READ, ELSE NZ RD$SEC: CALL READ ; READ SECTOR IN SEC ; CURRENT SECTOR RNZ ADI 2 OUT SEC CMP C ; LAST SEC? RZ ; YES JMP RD$SEC ; *** THE FOLLOWING ARE HARDWARE DEPENDENT ROUTINES *** ; ; *** DRIVE SELECT *** ; The drive select routine is expanded now, and will ; ask for user's selection of the drive and side to test. select: call cls ; start with a fresh screen lxi h,me22 ; which drive to test? call text sel1: call ci ; get input char. cpi 'B' ; drive B? jnz notb mvi b,22h ; drive B: select, motor on jmp side notb: cpi 'A' ; drive A? jz drivea call badinp jmp sel1 ; ask for drive again drivea: mvi b,12h ; drive A: select, motor on side: call co ; show their valid drive entry lxi h,me23 ; which side to select? call text side1: call ci ; get input char. cpi '1' push psw ; save their input jnz not1 mov a,b ori 04H ; turn on bit 2 for side 1... mov b,a jmp prgdsk ; ...and go program it not1: cpi '0' jz prgdsk ; bit 2 is already off (side 0) pop psw ; get rid of their bad input... call badinp ; ...and tell them about it jmp side1 ; ask for side again prgdsk: pop psw ; recall their input call co ; show their valid side entry mov a,b ; get finished product ready... out dsel ; ...and ship it jmp home ; home drive badinp: mvi a,bell ; not a valid selection call co ret ; *** SEEK HEAD(S) TO TRACK *** ; ; ENTER WITH NEW TRACK LOCATION IN A. TRACK: OUT DATA ; NEW TRACK CALL CLPEND ; CLEAR FDC MVI A,SEEK+RATE ; SEEK COMMAND + STEP RATE ; TRACK1: OUT CMD ; ISSUE... CALL DELAY ; DELAY FOR FDC ; TRACK2: IN STAT ; BUSY? RRC ; TEST JC TRACK2 ; STILL BUSY... MVI A,SDELAY ; SET SEEK DELAY BIT STA DFLAG IN TRK ; SET CURRENT TRACK STA CTRK RET PAGE ; *** RESTORE HEAD(S) TO TRACK ZERO *** HOME: CALL CLPEND ; CLEAR FDC MVI A,RESTORE+RATE ; RESTORE COMMAND + STEP RATE JMP TRACK1 ; ISSUE COMMAND... ; *** READ SECTOR ROUTINE *** ; ENTER THIS ROUTINE WITH THE SECTOR TO ; BE READ IN A. ; ; THIS ROUTINE WILL KEEP TRYING TO READ ; THE SECTOR UNTIL RETRY COUNT EQUALS ZERO. ; ; THE 1793 CONTROLLER HAS A BUILT-IN AUTOMATIC ; FOUR RETRIES TO READ ID, SO THE VALUE SET IN ; THE EQUATE (RETRY) IS EQUAL TO [ 4 * RETRY + 1 ]. READ: OUT SEC ; set sector to read MVI E,RETRY ; READ1: CALL CLPEND ; CLEAR FDC CALL PRG$DMA ; PROGRAM DMA CONTROLLER LDA DFLAG ; possible addition of 15 ms seek delay... ORI RSEC ; ...in with read sector command OUT CMD ; ship it. MVI A,SDMA ; START TRANSFER OUT DMA CALL COMP ; TRANSFER COMPLETED? ; READ2: XRA A ; clear seek delay flag STA DFLAG IN STAT ORA A RZ ; return if good read DCR E ; COUNT OFF RETRIES JNZ READ1 ; TRY AGAIN IN STAT ; still bad; return status ORA A RET PAGE ; *** WAIT FOR END OF DMA TRANSFER *** COMP: CALL DELAY ; wait 50 usec before each check IN STAT ; COMPLETED TRANSFER? RRC ; get busy bit in C flag RNC ; return if completed JMP COMP ; *** PROGRAM DMA CONTROLLER *** PRG$DMA: MVI B,15 ; BYTES COUNT LXI H,CMD$TBL ; COMMAND TABLE ; PRG$DMA1: MOV A,M ; LOAD OUT DMA ; WRITE TO CONTROLLER INX H DCR B ; -1 JNZ PRG$DMA1 RET ; *** COMMAND TABLE DMA CONTROLLER *** ; THIS DATA IS USED TO PROGRAM ZILOG'S ; Z80 DMA CONTROLLER. CMD$TBL: DB 0C3H ; RESET DMA CONTROLLER DB 8BH ; CLEAR BLOCK COUNTER DB 79H ; RECEIVE BLOCK DW SECBUF ; ADDRESS TO STORE BLOCK DW 256 ; BLOCK SIZE DB 14H ; DEFINE PORT (B) ADDRESS DB 28H ; DEFINE PORT (A) ADDRESS DB 85H DB DATA ; DATA REG FDC DB 8AH ; SET DMA CONTROLLER ACTIVE HIGH DB 0CFH DB 3 ; DATA ----> MEMORY DB 0CFH PAGE ; *** CLEAR PENDING COMMANDS FDC *** ; CLEARS THE FLOPPY CONTROLLER OF ANY ; PENDING COMMANDS. CLPEND: MVI A,CLEAR ; CLEAR FDC COMMAND OUT CMD ; *** FDC DELAY TO PROCESS COMMANDS *** ; THIS 50 USEC DELAY LOOP MUST BE ADJUSTED FOR ; DIFFERENT CLOCK SPEEDS. ; ; NOTE: ; IF ALTERED, ADJUST INDEX TIMING ROUTINE. DELAY: ; 4.25 MVI A,FDELAY ; 1.75 DELAY1: DCR A ; 11.00 JNZ DELAY1 ; 27.50 NOP ; 1.00 NOP ; 1.00 NOP ; 1.00 RET ; 2.50 PAGE ; *** RADIAL TRANSLATE TABLE *** ; CURSOR POSITIONING TABLE FOR RADIAL ; ALIGNMENT TEST. RAD$NEG: DB 38 ; 1 MILLINCH DB 36 ; 2 " " DB 34 ; 3 " " DB 32 ; 4 " " DB 30 ; 5 " " DB 28 ; 6 " " DB 26 ; 7 " " DB 24 ; 8 " " DB 22 ; 9 " " DB 20 ; 10 " " DB 17 ; 11 " " DB 14 ; 12 " " DB 11 ; 13 " " RAD$POS: DB 40 ; 1 MILLINCH DB 42 ; 2 " " DB 44 ; 3 " " DB 46 ; 4 " " DB 48 ; 5 " " DB 50 ; 6 " " DB 52 ; 7 " " DB 54 ; 8 " " DB 56 ; 9 " " DB 58 ; 10 " " DB 61 ; 11 " " DB 64 ; 12 " " DB 67 ; 13 " " ; *** azimuth translate table *** azi$tab: DB 21 ; head azimuth angle DB 24 DB 27 DB 30 DB 33 DB 36 DB 39 DB 42 PAGE ; *** PROGRAM MESSAGES *** ME1: DB -1,27,1,'Drive Diagnostic Program' DB -1,31,2,'CP/M 80 Ver 1.0' DB -1,23,4,'( Dysan Corp. Santa Clara, Ca. )' DB -1,18,5,'<*>=======================================<*>' DB -1,18,6,'<*> DIAGNOSTIC COMMAND MENU <*>' DB -1,18,7,'<*>=======================================<*>' DB -1,18,8,'<*> <*>' DB -1,18,9,'<*> R = Radial H = Hysteresis <*>' DB -1,18,10,'<*> <*>' DB -1,18,11,'<*> A = Azimuth I = Index Timing <*>' DB -1,18,12,'<*> <*>' DB -1,18,13,'<*> C = Centering S = Spindle Speed <*>' DB -1,18,14,'<*> <*>' DB -1,18,15,'<*> N = New Drive E = Exit Program <*>' DB -1,18,16,'<*> <*>' DB -1,18,17,'<*><*><*><*><*><*><*><*><*><*><*><*><*><*><*>' DB -1,18,19,'SELECTION? ....',BS,0 ME2: DB 'FATAL READ ERROR',0 ME3: DB 'RE-CLAMP DISKETTE ....',BS,0 ME4: DB 'CENTERING OK ....',BS,0 ME5: DB ' Minutes',0 ME6: DB -1,25,2,'<>==========================<>' DB -1,25,3,'<> TRACK OFFSET <>' DB -1,25,4,'<>==========================<>' DB -1,25,5,'<> <>' db -1,25,6,'<> 0 ---> 39 <>' DB -1,25,7,'<> <>' DB -1,25,8,'<>==========================<>' DB -1,25,9,'<> Cancels Test <>' DB -1,25,10,'<>==========================<>' DB -1,25,12,'OFFSET? ...',BS,0 ME7: DB -1,25,2,'<>==========================<>' DB -1,25,3,'<> TRACK SELECTION <>' DB -1,25,4,'<>==========================<>' DB -1,25,5,'<> <>' db -1,25,6,'<> A = (0) D = (19) <>' DB -1,25,7,'<> <>' db -1,25,8,'<> B = (5) E = (30) <>' DB -1,25,9,'<> <>' db -1,25,10,'<> C = (16) F = (39) <>' DB -1,25,11,'<> <>' DB -1,25,12,'<>==========================<>' DB -1,25,13,'<> Cancels Test <>' DB -1,25,14,'<>==========================<>' DB -1,25,16,'TRACK? ...',BS,0 ME8: DB -1,24,5,'--- RADIAL ALIGNMENT CHECK ---' DB -1,10,9,'Away',-1,36,9,'Spindle',-1,63,9,'Toward' DB -1,10,10,'13 12 11 10 9 8 7 6 5 4 3 2 1' DB '-1 2 3 4 5 6 7 8 9 10 11 12 13',0 PAGE ME9: DB -1,25,2,'<>==========================<>' DB -1,25,3,'<> TRACK SELECTION <>' DB -1,25,4,'<>==========================<>' DB -1,25,5,'<> <>' db -1,25,6,'<> A = (21) B = (24) <>' DB -1,25,7,'<> <>' db -1,25,8,'<> C = (27) <>' DB -1,25,9,'<> <>' DB -1,25,10,'<>==========================<>' DB -1,25,11,'<> Cancels Test <>' DB -1,25,12,'<>==========================<>' DB -1,25,14,'TRACK? ...',BS,0 ME10: DB -1,23,5,'--- DISKETTE CENTERING CHECK ---',0 ME11: DB -1,23,14,'Press For New Track',0 ME12: DB -1,24,5,'--- AZIMUTH ALIGNMENT CHECK ---' DB -1,25,14,' Will Cancel AZIMUTH Check',0 ME13: DB -1,25,2,'<>==========================<>' DB -1,25,3,'<> TRACK SELECTION <>' DB -1,25,4,'<>==========================<>' DB -1,25,5,'<> <>' db -1,25,6,'<> A = (0) B = (34) <>' DB -1,25,7,'<> <>' DB -1,25,8,'<>==========================<>' DB -1,25,9,'<> Cancels Test <>' DB -1,25,10,'<>==========================<>' DB -1,25,12,'TRACK? ...',BS,0 ME14: DB -1,28,5,'--- HYSTERESIS CHECK ---',0 ME15: DB -1,15,8,'#################################################' DB -1,15,12,'#################################################',0 ME16: DB 'Positioner Hysteresis = ',0 ME17: DB -1,25,5,'--- INDEX TO DATA TIME ---',0 ME18: DB 'Index To ID In Usecs = ',0 ME19: DB -1,27,5,'--- SPINDLE SPEED CHECK ---' DB -1,25,14,' Will Cancel RPM Check',0 ME20: DB ' Milliseconds',0 ME21: DB ' RPM',0 me22: db -1,10,9,'Put diagnostic disk in the drive to be tested.' db -1,10,11,'Enter drive to be tested (A or B) ---> ',0 me23: db -1,10,12,'Enter side to be tested (0 or 1) ---> ',0 PAGE ; *** position cursor to a certain column *** set$cur db -1 ; to trip the cursor address routine COLUMN DS 1 ; SET COLUMN ROW DS 1 ; SET ROW DB 0 ; TERMINATOR ; *** PROGRAM VARIABLE STORAGE *** TEMP DS 2 ; TEMP STORAGE DIFF DS 1 ; 1ST - 2ND READ CTRK DS 1 ; CURRENT TRACK SAVTRK DS 1 ; TEMP STORAGE HYSTERESIS TEST DFLAG DS 1 ; SEEK DELAY FLAG POINT DS 2 ; TABLE POINTER XPOINT DS 2 ; TABLE POINTER POSITIVE YPOINT DS 2 ; TABLE POINTER NEGATIVE XOFF DS 1 ; POSITIVE OFFSET YOFF DS 1 ; NEGATIVE OFFSET BIAS DS 1 ; BIAS FROM TEST TRACK (HYSTERESIS) HYERR DS 1 ; HYSTERESIS ERROR ON FIRST READING ; ; STORAGE AREA FOR 16/24 BIT DIVIDE ROUTINE ; MSB DS 1 MSB1 DS 2 MSB2 DS 2 BUFFER DS 4 ; CONSOLE INPUT BUFFER SECBUF DS 256 ; SECTOR BUFFER DS 100 ; STACK SPACE STACK EQU $ PAGE