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 tblsz equ 26 ;track table 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 sd2bit equ 80h ;side two bit index equ 10h ;Delta index status bit wproct equ 40h ;Write protected status bit dready equ 80h ;Drive ready status bit notrdy equ 82h ;drive not ready eightk equ 2000h ;disk buffer size retries equ 1 ;Disk retries before verify error conin equ 1 ;character in console cout equ 2 ;character out console wrstrn equ 9h ;bdos write string consta equ 0bh ;get console status lf equ 0ah ;line feed cr equ 0dh ;carriage return esc equ 1bh ;escape character wboot equ 0 ;warm boot address bdos equ 5 ;Bdos entry address 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 test ;testem rst 7 drvcks mvi c,8 ;maximum number of drives lxi h,snstat ;get address of sense command shld vector ;store it in vector drvlp mvi a,8 ;# of possible drives sub c ;to find current drive mov b,a ;save drive # in B push b ;save count 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 call login ;record results in table pop b ;recover count dcr c ;drive count-down jnz drvlp ;next drive ret ;else return login cpi good ;zero means active drive jz ckit ;to find out about it cpi notrdy ;appropriate result cnz error ;report to terminal 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 mvi b,0 ;zero B cpi '1' ;single-sided? jz skpdbl ;skip double-sided entry mvi b,80h ;double-sided bit skpdbl 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 test mvi c,8 ;number of drive possibilities lxi h,drvlog ;pickup log address next mov a,m ;load tracks cpi 0 ;active? jnz go ;yes inx h ;else advance pointer inx h ;to next drive dcr c ;decrement drive counter jnz next ;loop till done ret go shld logpnt ;save pointer mvi a,8 ;number of drive possibilities sub c ;current drive number sta wrtkdr ;tell commands sta rdtkdr push h ;save HL push b ;and BC call seekms ;advise terminal call seeks ;do seek tests call rdwrms ;advise terminal call rdwrts ;do data tests endrv pop b ;recover pointers pop h inx h ;advance pointer inx h ;for next drive dcr c ;drive count down jmp next ;and loop seeks lxi h,rdtrak ;read track command address shld vector ;guide controller mvi a,80h ;to abort command call clrtbl ;writes A to command table lhld logpnt ;pickup pointer 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 lhld logpnt ;pickup log pointer 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) ret 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 mov c,a ;save track in C lhld logpnt ;get log pointer inx h ;advance log pointer to sides byte mov a,m ;load byte dcx h ;return 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 mov b,a ;save side byte in B sub a ;zero A sta rtrslt ;clear result byte out start ;start controller call ckabrt ;check for interrupt call wait1 ;wait for it to finish lda rtrslt ;check the results cpi good ;normal completion? rz ;gives normal return cpi notrdy ;drive gone away? jnz error ;if not, report error call error ;if yes, report and pop h ;clear 3 returns off stack and pop h pop h jmp endrv ;go to next drive rdwrts sub a ;zero A call clrtbl ;clears command table call trkszr ;puts size of track at tbytes sub a ;zero A sta pass ;clear pass counter tstdat lxi h,wrtrak ;write track command address shld vector ;to guide controller call wrdrv ;writes all tracks lxi h,rdtrak ;read track command address shld vector ;guide controller call rddrv ;reads and compares all lda pass ;get pass counter inr a ;increment it sta pass ;put it back cpi 4 ;one to many jnz tstdat ;continue data test ret wrdrv lhld logpnt ;pickup log pointer mov b,m ;number of tracks trklp push b ;save track counter push h ;save log pointer mov a,m ;number of tracks sub b ;track counter mov c,a ;save track in C sta wrtktk ;current track to command sta track ;and record call newpat ;get pattern for this track call filbuf ;writes it to disk buffer wttk sub a ;zero A sta wtrslt ;clear result byte out start ;starts controller call ckabrt ;check for interrupt call wait1 ;wait for it to finish lda wrtksd ;get the side byte mov b,a ;save it in B lda wtrslt ;load result byte cpi good ;ordinary completion jz aswas ;gives normal return cpi notrdy ;drive gone away? jz abrtdr ;end this drive call error ;else report and continue jmp aswas ;normal completion abrtdr pop h ;clear 2 pushes & 2 returns off stack pop h pop h pop h jmp endrv ;go to next drive aswas lhld logpnt ;get log pointer inx h ;advance to side byte mov a,m ;load it ani 80h ;check sides bit jz cntdwn ;if single-sided, forget it lda wrtksd ;load command side byte ani 80h ;check side bit jnz reset ;already done mvi a,80h ;else set it sta wrtksd ;store in command jmp wttk reset sub a ;reset side bit for next track sta wrtksd ;store in command cntdwn pop h ;restore pointer pop b ;restore BC dcr b ;count down the tracks jnz trklp ;do another track ret ;pass complete rddrv lhld logpnt ;get log pointer mov b,m ;loads # of tracks to B trklp2 push b ;save track counter push h ;save log pointer mov a,m ;get number of tracks sub b ;track counter mov c,a ;save track in C sta rdtktk ;store in command sta track ;track record rd sub a ;zero A sta rtrslt ;clear result byte out start ;start controller call ckabrt ;check for interrupt call wait1 ;wait for it to finish lda rdtksd ;get side byte mov b,a ;save it in B lda rtrslt ;get result byte cpi good ;compare jz okay ;gives normal return cpi notrdy ;drive gone away? jz abort ;end this drive call error ;else report and continue jmp okay ;normal completion abort pop h ;clear 2 pushes & 2 returns off stack pop h pop h pop h jmp endrv ;go to next drive okay call newpat ;get test pattern call verify ;read and compare data lhld logpnt ;get log pointer inx h ;advance to side byte mov a,m ;load it ani 80h ;check sides bit jz ignor ;if single-sided, forget it lda rdtksd ;load command side byte ani 80h ;check side bit jnz reset2 ;already done mvi a,80h ;else set it sta rdtksd ;store in command jmp rd ;do other side reset2 sub a ;reset side bit for next track sta rdtksd ;store in command ignor pop h ;restore pointer pop b ;recover counter dcr b ;count down tracks jnz trklp2 ;do next track ret ;else finish verify lxi d,0 ;zero DE push d ;save DE lhld tbytes ;load track size xchg ;move to DE lxi h,dskbuf ;set M to disk buffer verlp mov a,m ;pick up memory cmp b ;what it should be jz cntinu ;if correct xthl ;save HL & get error count inx h ;increment error count xthl ;restore & save cntinu inx h ;increment M dcx d ;decrement size counter mov a,e ;check for zero ora d jnz verlp ;continue if not pop h ;get error count mov a,l ;put L in A ora h ;zero? rz push h ;or report lxi d,crlf ;carriage return & line feed call wrterm ;send it pop h ;get error count call putdc ;prints it to terminal lxi d,cmperr ;compare error msg call wrterm ;send it lda rdtktk ;get track number call bcdout ;send it lxi d,sdms ;side msg call wrterm ;send it lda rdtksd ;load side bit ani sd2bit ;get side bit rlc ;put it in lowest bit inr a ;make it 1 or two call bcdout ;send it ret trkszr lhld logpnt ;pickup log pointer mvi b,0 ;zero B mov a,m ;get tracks in A cpi 77 ;8 inch? jnz skp ;do not change mvi b,3 ;to skip 5 inch skp 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 ret newpat push h ;save HL lxi h,patble ;set M to test patterns lda pass ;load pass counter add l ;adjust low byte of address jnc nocary ;cover overflow possibility inr h nocary mov l,a ;brings M to current pattern lda track ;get current track number rar ;check for even or odd mov a,m ;load test pattern jnc even ;skip on alternate tracks cma ;complement test pattern even pop h ;restore HL mov b,a ;save in B ret filbuf 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 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 error push d push h push b ;save register pairs 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 call wrterm ;send to terminal lxi d,tkmsg ;track message call wrterm ;send it pop b ;get BC push b ;and resave mov a,c ;get track number call bcdout ;and send it lxi d,sdms ;side msg call wrterm ;send it pop b mov a,b ;get sides rlc ;move side bit to data 0 inr a ;make it 1 or 2 call bcdout ;send it resume pop h ;recover register pairs pop d ret sd1msg lxi d,sd1ms ;side 1 msg jmp wrterm ;send it sd2msg lxi d,sd2ms ;side 2 msg jmp wrterm ;send it askop push h ;save HL push b ;save BC lxi d,sidesq ;number 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 cr ;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 clrtbl mvi c,tblsz ;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 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? jz panic1 ;report & continue sub a ;zero A sta hlted ;clear result byte pop b ;recover BC pop d ;recover DE ret seekms lxi d,seekng ;address of seek message call wrterm ;send to terminal jmp drtype ;tells track and drive number rdwrms lxi d,readng ;address of read/write message call wrterm ;send to terminal jmp drtype ;track and drive number drtype lhld logpnt ;pick up log pointer mov a,m ;get number of tracks cpi 77 ;see if eight inch lxi d,eighms ;eight inch drive message jz eightr ;for eight inch message lxi d,fivems ;five inch drive message eightr call wrterm ;eight message to terminal lda rdtkdr ;get number of drive jmp hexout ;send to terminal ckabrt mvi c,consta ;asks for console status call bdos dcr a ;0ffh means data ready rnz ;no abort mvi c,conin ;get the character call bdos cpi esc ;escape character jnz 100h ;re-start test rst 7 ;return to DDT 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 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 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 trktbl ds tblsz ;table used by write track command patble db 0 ;test patterns db 0ffh db 0aah db 55h tksiz5 dw 0 ;no equivalent on 5 in 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 ;current track size track db 0 ;current track pass db 0 ;current pass logpnt dw drvlog ;pointer to drvlog drvlog ds 16 ;drive log (trks, sides & sector sizes) pan1ms db ' controller not responding$' seekng db lf,lf,cr,cr db 'Testing seeks on$' readng db lf,cr,cr db 'testing read/writes on$' trkmsg db ' Track $' crlf db lf,cr,cr db '$' cmperr db ' Compare error(s) on Track $' drvmsg db lf,cr,cr db 'physical $' fivems db ' 5 inch physical $' eighms db ' 8 inch physical $' wrprms db ' write protected$' dblmsg db ' double-sided drive$' nodrvs db lf,cr,cr db 'no drives are ready$' sidesq db ': How many sides on this drive? $' zero db lf,cr,cr db 'Improper command code$' one db lf,cr,cr db 'Improper disk drive value$' two db lf,cr,cr db 'Disk drive not ready$' three db lf,cr,cr db 'Improper track value$' four db lf,cr,cr db 'Unreadable media$' five db lf,cr,cr db 'Improper sector header - no sync byte(s)$' six db lf,cr,cr db 'CRC error in sector header scan$' seven db lf,cr,cr db 'Seek error$' eight db lf,cr,cr db 'Compare error in sector header scan$' fourtn db lf,cr,cr db 'CRC error in data field$' fiftn db lf,cr,cr db 'Improper sector value$' sixtn db lf,cr,cr db 'Media write protected$' sevntn db lf,cr,cr db 'Lost data - DMA channel did not respond$' eightn db lf,cr,cr db 'Lost command - Channel did not respond$' tkmsg db ' track $' sdms db ' side $' sd1ms db ' side one$' sd2ms db ' side two$' 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