title floppy drive test 3/15/82 channl equ 50h ;Start channel address vector equ channl+1 ;branch address start equ 0efh ;port address to start the controller setma equ 23h ;Command to set DMA address rdsec equ 20h ;Command to read a sector wrsec equ 21h ;Command to write a sector snsta equ 22h ;Command to sense drive status strtry equ 28h ;Command to set error retry count stlgcl equ 2eh ;Command to set logical drive sttime equ 2fh ;Command to set head unload/ ; drive deselect timeout rdtrk equ 29h ;Command to read a track wrtrk equ 2ah ;Command to write a track conhlt equ 25h ;Command to halt controller brnch equ 26h ;Command to branch in channel setchn equ 27h ;Command to set channel address sttksz equ 2dh ;Command to set track size good equ 40h ;normal command completion fiver equ 4h ;five inch drive flag wrprot equ 40h ;write protect flag dblsid equ 4 ;double sided drive & media flag index equ 10h ;Delta index status bit wproct equ 40h ;Write protected status bit dready equ 80h ;Drive ready status bit eightk equ 2000h ;disk buffer size retries equ 1 ;Disk retries before verify error conin equ 1 crlfs equ 0d0ah ;Carraige return / line feed sequence acr equ 0dh ;a carriage return wboot equ 0 ;warm boot address bdos equ 5 ;Bdos entry address wrstrn equ 9h ;bdos write string cout equ 2 ;character out console org 100h lxi sp,stack lxi h,drvlog ;load log address shld logpnt ;initialize pointer mvi a,brnch ;branch command sta channl ;controller starts here lxi h,setdma ;set dma address command shld vector ;guide controller sub a ;zero A sta vector+2 ;extended address byte out start ;start controller call wait1 ;wait for it to finish lxi h,retrys ;address of set tries cmnd shld vector ;to guide controller out start ;start controller call wait1 ;wait for it to finish call drvcks ;look for drives call sktsts ;various seek patterns rst 7 drvcks mvi c,8 ;maximum number of drives drvlp lxi h,snstat ;get address of sense command shld vector ;store it in vector mvi a,8 ;# of possible drives sub c ;to find current drive mov b,a ;save drive # in B sta snsdrv ;tell sense command sub a ;zero A sta snsrlt ;clear result byte of sense command out start ;start controller call wait1 ;wait for it to finish cksns lda snsrlt ;sense command result status push b ;save count call login ;record results in table pop b ;recover count dcr c ;drive count-down jnz drvlp ;next drive ret ;else return login ani good ;non-zero means active drive jnz ckit ;to find out about it lda snsrlt ;T E M P O R A R Y call hexout ;T E M P O R A R Y lhld logpnt ;get pointer mvi m,0 ;indicates inactive drive inx h ;update pointer mvi m,0 ;indicates inactive drive inx h ;for next drive shld logpnt ;store pointer ret ckit push b ;save BC pair lxi d,drvmsg ;for operator call wrterm ;send it pop b ;recover BC mov a,b ;put drive # in A call hexout ;send to terminal lda dstat1 ;to find whether 5 or 8 inch ani 4h ;on means 5 inch jz eighin ;else its an 8 inch lhld logpnt ;get log pointer mvi m,40 ;number of tracks inx h ;to next entry (sngl or dble sided) call askop ;ask operator # of sides mov b,a ;save answer in B lda dstat2 ;sector size add b ;combine with B mov m,a ;store result in drive log inx h ;to next drive shld logpnt ;store the updated pointer ret eighin lhld logpnt ;load log pointer mvi m,77 ;number of tracks inx h ;next log entry lda dstat2 ;sector size mov b,a ;save in B lda dstat3 ;3 bit tells sides ani 4h ;on means dbl sided jz sngl ;single sided mvi a,80h ;dble sided bit sngl add b ;combine with sector size mov m,a ;record it inx h ;increment pointer for next drive shld logpnt ;save it ret sktsts lxi h,rdtrak ;address of read track cmnd shld vector ;to guide controller mvi a,80h ;to abort track read call clrtbl ;writes A to track table mvi c,8 ;drive counter lxi h,drvlog ;pick up log address drlp shld logpnt ;initialize pointer mov a,m ;load number of tracks cpi 0 ;see if drive is active jz nxtdrv ;skip if its not mvi a,8 ;number of drives sub c ;leaves current drive # in A sta rdtkdr ;tells controller call seekms ;advise terminal sub a ;zero A call seek ;take drive to track 0 mov d,m ;put # of tracks in D dcr d ;to get highest track number mvi e,0 ;Zero E call pat1 ;short-long-short mov d,m ;number of tracks to D dcr d ;to get highest track number call pat2 ;long-short-long mvi d,0 ;start at 0 call pat3 ;butterfly (+2-1 out, then -2+1 back) nxtdrv dcr c ;drive count down rz ;all drives finished lhld logpnt ;pick up pointer inx h ;advance it to next drive inx h jmp drlp ;check the next slot pat1 mov a,d ;D starts at highest track number call seek ;seeks to track in A mov a,e ;E starts at track 0 call seek dcr d ;count down jm reverse ;no tracks left inr e ;count up cmp m ;number of tracks jnz pat1 reverse inr d ;count up mov a,d cmp m ;M has number of tracks rz call seek ;else seek dcr e rm ;no tracks left mov a,e call seek jmp reverse pat2 mov a,d ;D starts at highest track number rar ;divide by 2 mov d,a ;reset D mov e,a ;set E=D at start pat2lp mov a,d ;start at middle track call seek ;seeks to track in A dcr e ;count E down, D up jm phase2 ;reverse direction mov a,e ;else read it call seek inr d ;count up in first phase cmp m ;number of tracks jnz pat2lp phase2 inr e ;count up mov a,e call seek dcr d ;count down mov a,d ;to check cmp e ;looking for crossing point rm ;finished call seek ;else continue jmp phase2 ;loop pat3 mov a,d ;D starts at 0 call seek ;takes drive back one in loop mov a,d adi 2 ;jump ahead two cmp m ;number of tracks jz phaze2 ;reverse pattern call seek inr d ;and back one jmp pat3 ;repeat phaze2 dcr a ;for first shot only phlp call seek mov a,d sbi 2 ;in two rm call seek dcr d ;and back one mov a,d jmp phlp seek sta rdtktk ;start at track indicated by A inx h ;advance log pointer to sides byte mov a,m ;load byte dcx h ;restore pointer ani 80h ;see if dblesided bit is on jz onesid ;if not, forget it lda rdtksd ;else load side byte xri 80h ;toggle it onesid sta rdtksd ;replace it sub a ;zero A sta rtrslt ;clear result byte out start ;start controller call wait1 ;wait for it to finish lda rtrslt ;check the results cpi good ;normal completion? cnz error ;else record error ret error push b ;save register pairs push d push h ani 1fh ;mask off error value lxi h,errtbl ;pickup address of msg table call adjust ;adjust pointer by double A mov e,m ;load low address inx h ;increment pointer mov d,m ;load high address mvi c,wrstrn ;load bdos write string code call bdos ;send it to terminal pop h ;recover register pairs pop d pop b ret clrtbl mvi c,15 ;size of table lxi h,trktbl ;command result table tblp mov m,a ;fill it with A inx h ;increment memory pointer dcr c jnz tblp ret trkszr push b ;save BC push h ;save HL mvi b,0 ;zero B mov a,m ;get tracks in A cpi 77 ;8 inch? jnz skp5 ;do not change mvi b,2 ;to skip 5 inch skp5 inx h ;advance pointer to 2nd log entry mov a,m ;load sector size & sides ani 7 ;mask size only add b ;covers 5 or 8 inch drives lxi h,tksiz5 ;initialize pointer to sizes call adjust ;adjust M by double A mov e,m ;load low byte inx h ;advance pointer mov d,m ;load high byte xchg ;put result in HL shld tbytes ;store result pop h ;recover register pairs pop b ret adjust mov b,a ;save A in B mov a,l ;pickup pointer low byte add b ;adjust to B jnc skpnc ;if no overflow inr h ;else adjust H skpnc add b ;for high byte jnc skpnc2 ;if no overflow inr h ;else adjust H skpnc2 mov l,a ;put in L ret ;pointer is adjusted by A wrtrds lxi h,drvlog ;pick up log addess mvi c,8 ;maximum number of drives ckone mov a,m ;load tracks cpi 0 ;see if active jnz wrdrlp ;test it inx h ;else advance to next drive inx h dcr c rz ;done jmp ckone ;try another wrdrlp shld logpnt ;save log pointer mov b,m ;save number of tracks in B call trkszr ;puts track size at tbytes mvi a,8 ;maximum # of drives sub c ;to find current drive sta wrtkdr ;set drive in command sub a ;zero A sta pass ;clear pass counter writer call wrtrks ;writes alternate patterns to all call rdtrks ;verifies results lda pass ;pass record inr a ;update cpi 4 ;one over jnz writer ;next pass inx h ;advance log pointer inx h dcr c ;drive counter jnz ckone ;next drive ret ;all done wrtrks lxi h,wrtrak ;address of write track command shld vector ;guide controller trklp sub a ;zero A sta wtrslt ;clear command result byte call clrtbl ;clear results table call newpat ;write test pattern to disk buffer lhld logpnt ;get drive log pointer mov a,m ;get number of tracks sub b ;track counter sta wrtktk ;store track in command out start ;start controller call wait1 ;wait for it to finish call rsltck ;check the results dcr b ;count down the tracks jnz trklp ;do another track ret ;pass complete newpat push h ;save HL lhld tbytes ;track size xchg ;puts size in DE lxi h,dskbuf ;points M at disk buffer buflp mov m,b ;stores B in buffer inx h ;steps M dcx d ;decrement counter mov a,e ;to check for zero ora d jnz buflp ;loop till done pop h ;restore HL ret lhld logpnt ;pickup pointer to place in drvlog mov b,m ;number of tracks trklp mov a,m ;number of tracks sub b ;number of passes sta wrtktk ;store at track address in cmnd sub a ;zero a sta wtrslt ;clear result byte in cmnd call clrtbl ;clear result table call write ;write the track dcr b ;decrement track counter jnz trklp ;next track lda pass ;pass record inr a ;update it cpi 4 ;one over rz ;done call newpat ;writes pattern to buffer bfinit lxi d,eightk ; lxi h,dskbuf ;pointer to disk buffer write rst 7 ckrslt lxi h,secsiz ;pointer to size mov e,m ;load low byte inx h ;advance pointer mov d,m ;load high byte lxi h,trktbl ;load track table address mov c,a ;initialize counter tbloop mov a,m ;load result cpi good ;check result cnz error ;call error message inx h ;increment pointer dcx d ;decrement counter mov a,e ;check for zero ora d ; jnz tbloop ;loop sub a ;zero a jmp clrtbl ;clear table newpat rst 7 prufrd rst 7 askop push h ;save HL push b ;save BC lxi d,sidesq ;address of sides question call wrterm ;send to terminal mvi c,conin ;bdos character-in code call bdos pop b ;recover BC pop h ;recover HL cpi acr ;is it a null answer? jz 100h ;if so, restart program cpi '1' ;or 1 rz ;good answer jm askop ;bad answer, ask again cpi '2' ;good answer jnz askop ;else ask again mvi a,80h ;dble-sided bit ret bcdout mov l,a mvi h,0 ***************************************************************** * * * Putdc prints the ascii decimal equivalent of the number in HL * * * ***************************************************************** putdc lxi b,-10 phl push d mov d,b mov e,b phllp dad b inx d jc phllp xthl xchg mov a,h ora l cnz phl pop h mvi a,'0' add l sub c pchar push h push b push d push psw mov e,a mvi c,2 call bdos pop psw pop d pop b pop h ret panic1 pop b ;get C mov a,c call hexout lxi d,pan1ms call wrterm jmp 0 wrterm mvi c,wrstrn jmp bdos wait1 push d ;save DE push b ;save BC lxi d,0 ;load as timer-counter mvi b,0 ;for auxilliary counter wtloop dcx d ;start countdown mov a,d ora e ;check it for 0 jnz skip ;skip auxilliary counter dcr b ;auxilliary countdown jz panic1 ;report to terminal & wboot skip lda hlted ;universal halt result cpi 0 ;done yet? jz wtloop ;wait for it ani good ;normal completion? cz error ;report & continue sub a ;zero A sta hlted ;clear result byte pop b ;recover BC pop d ;recover DE ret hexout push psw rrc rrc rrc rrc call pnib pop psw call pnib mvi a,' ' jmp pchr pnib ani 0fh cpi 10 jnc p10 adi '0' jmp prn p10 adi 'a'-10 prn call pchr ret pchr mvi c,cout mov e,a call bdos ret snstat db snsta ;sense status command snsdrv db 0 ;physical drive number dstat1 db 0 ;dstat 1 dstat2 db 0 ;dstat 2 dstat3 db 0 ;dstat 3 snsrlt db 0 ;command result branch db brnch ;branch command dw comhlt db 0 ;extended address setdma db setma ;set dma for seeks dw dskbuf ;all purpose buffer (eightk-8192 bytes) db 0 ;extended address byte db brnch ;branch command dw comhlt db 0 ;extended address rdsect db rdsec ;command to read a sector rdsctk db 40 ;default to ck size of 5" drives sidsec db 1 ;side 0 sector 1 rdscdr db 0 ;physical drive number rdscrs db 0 ;result status db brnch ;branch command dw comhlt db 0 ;extended address trktbl ds 15 ;table used by write track command patble db 0 ;test patterns db 0ffh db 0aah db 55h wrtrak db wrtrk ;write track command wrtktk db 0 ; wrtksd db 0 ; wrtkdr db 0 ; wrtabl dw trktbl ; db 0 wtrslt db 0 db brnch ;branch command dw comhlt db 0 ;extended address rdtrak db rdtrk ;read track command rdtktk db 0 ; rdtksd db 0 ; rdtkdr db 0 ; rdsctb dw trktbl ; db 0 rtrslt db 0 db brnch ;branch command dw comhlt db 0 ;extended address retrys db strtry ;command to set # of retries db retries ;number of retries db brnch ;branch command dw comhlt ;standard halt db 0 comhlt db conhlt ;universal halt command hlted db 0 ;result byte tksiz5 dw 2560 ;5 inch single density dw 5120 ;5 inch double density tksiz8 dw 3328 ;8 inch single density dw 6656 ;8 inch 256 byte sectors dw 7680 ;ditto 512 dw 8192 ;ditto 1024 tbytes dw 0 ;storage location logpnt dw drvlog ;pointer to drvlog drvlog ds 16 ;drive log (trks & sides & sector sizes) pan1ms db ' controller not responding$' drvmsg dw crlfs db 'physical $' fivems db ' is a 5 inch $' eighms db ' is an 8 inch $' wrprms db ' write protected$' dblmsg db ' double-sided drive$' nodrvs dw crlfs db 'no drives are ready$' sidesq db ': How many sides on this drive? $' zero dw crlfs db 'Improper command code$' one dw crlfs db 'Improper disk drive value$' two dw crlfs db 'Disk drive not ready$' three dw crlfs db 'Improper track value$' four dw crlfs db 'Unreadable media$' five dw crlfs db 'Improper sector header - no sync byte(s)$' six dw crlfs db 'CRC error in sector header scan$' seven dw crlfs db 'Seek error$' eight dw crlfs db 'Compare error in sector header scan$' fourtn dw crlfs db 'CRC error in data field$' fiftn dw crlfs db 'Improper sector value$' sixtn dw crlfs db 'Media write protected$' sevntn dw crlfs db 'Lost data - DMA channel did not respond$' eightn dw crlfs db 'Lost command - Channel did not respond$' errtbl dw zero,one,two,three,four,five,six,seven,eight dw eight,eight,eight,eight,eight,fourtn dw fiftn,sixtn,sevntn,eightn ds 30 stack equ $ dskbuf ds 8192 ;8K disk buffer