TITLE ADVANCED DIGITAL HDC1001 HARD DISK FORMATTER OCT 27 1982 09:30 ;********************************************************* ;** ** ;** ADVANCED DIGITAL HDC1001 HARD DISK CONTROLLER ** ;** ** ;** HARD DISK FORMATTER ** ;** ** ;** This program will format an HDC1001 device. ** ;** It requires a hardware discription vector ** ;** for the selected device. It formats the ** ;** drive in 512 byte sectors for ADVANCED ** ;** DIGITAL SUPER QUAD'S Super Bios. ** ;** ** ;** Written by ** ;** ** ;** Greg Lindberg ** ;** ** ;********************************************************* .z80 PAGE ;*** EQUATES *** ;SYSTEM EQUATES BDOS EQU 5 ;BDOS entry point TFCB EQU 5CH ;Temporary FCB CR EQU 0DH ;Carriage return LF EQU 0AH ;Line feed BS equ 08H ;Back space ; PRTSTR EQU 9 ; Print string CONIN EQU 1 ; Console input CONOUT EQU 2 ; Console output RDBUF EQU 10 ; Read console buffer CONST EQU 11 ; Console status ;Port offsets for the HDC1001 HDBASE EQU 0E0H ; HDC1001 BASE I/O PORT DATA EQU HDBASE+0 ; Data register ERROR EQU HDBASE+1 ; Error register SECNT EQU HDBASE+2 ; Sector count SECNO EQU HDBASE+3 ; Sector number CYLLO EQU HDBASE+4 ; Cylinder low CYLHI EQU HDBASE+5 ; Cylinder high SDH EQU HDBASE+6 ; Size/Drive/Head COMND EQU HDBASE+7 ; Command register STATUS EQU COMND ; Status register ;Some HDC1001 commands CREAD EQU 20H ; Read sector CWRITE EQU 30H ; Write sector CFORM EQU 50H ; Format track PAGE ; ;*** Main program *** ; START: ld DE,signon ;send signon message ld C,prtstr call bdos strt1: ld DE,inbuf ;Get response to disk type ld C,rdbuf call bdos LD A,(NUMCHR) ;How many chars returned cp 0 jr z,bad ;no chars cp 3 ;to many chars jr C,good ;if not skip bad: ld DE,inval ld C,prtstr call bdos ld DE,menu ;ask again ld C,prtstr call bdos jr strt1 good: LD DE,INTTBL ;set up registers LD HL,0 DECLP: PUSH AF ;Save char count LD A,(DE) ;get char INC DE CP '0' JP C,BAD ;Char less than a '0' CP '9'+1 JP NC,BAD ;Char greater than a '9' SUB '0' ;make = 0-9 LD B,H ;mult present value * 10 LD C,L ADD HL,HL ;*2 ADD HL,HL ;*4 ADD HL,BC ;*5 ADD HL,HL ;*10 ADD A,L ;add in new value LD L,A JP NZ,DIGNC INC H DIGNC: pop AF dec A ;done yet JP NZ,DECLP ;if not go back for more add HL,HL ;now make ref into table of drive parameters add HL,HL ;*4 ld DE,dskprms add HL,DE ld DE,secs ;now move parms to use locs ld BC,4 ldir drvin: ld DE,drvmsg ;get which physical drive to format ld C,prtstr call bdos ld C,conin ;get response call bdos sub '0' ;make = 0-3 cp 4 ;valid response jr c,goodr ;yes ld DE,inval ; otherwise bad response ld C,prtstr call bdos jr drvin ;try again goodr: ld (unit),A ;save drive ; ;Make sure the guy out there really wants to do this ; ld DE,q1 ; Ask if really want to do this ld C,prtstr call bdos LD A,(UNIT) CALL OUTCHR ld DE,q2 ld C,prtstr call bdos ld C,conin ; Get response call bdos CP CR ; Carriage return JP Z,DOIT ABORT: ld DE,abtmsg ld C,prtstr call bdos jp resel ;Calculate interleave table ;But first clear the table to all FF's DOIT: ld DE,formsg ; Say formatting ld C,prtstr call bdos LD B,64 ; Make table 64 long LD HL,INTTBL ; Index interleave table SETLP: LD (HL),-1 INC HL DEC B JP NZ,SETLP ;Generate 16 bit interleave LD HL,(INTERB) ; Get interleave byte LD H,0 ; and turn it into a word LD (INTER),HL ;Next, calculate interleave table upper limit LD A,(SECS) ; Get number of sectors LD B,A ; Save for later LD E,A ; Offset off base of int table LD D,0 LD HL,INTTBL ADD HL,DE LD A,L ; Negate (2s complement) CPL LD L,A LD A,H CPL LD H,A ; This is our upper limit INC HL LD (LIMIT),HL ;Now, negative sector count LD A,B ; Get sectors per track (SECS) CPL ; And twos complement LD L,A LD H,-1 INC HL LD (NSECS),HL ;Calculate interleave table LD B,0 ; Clear sector number LD DE,INTTBL ; Index interleave table CHECK: LD HL,(LIMIT) ; Make sure limits not exceeded ADD HL,DE JP NC,WITHIN ; We are within limits LD HL,(NSECS) ; Otherwise subtract SECS ADD HL,DE XCHECK: EX DE,HL JP CHECK ; And check limits again WITHIN: LD A,(DE) ; This place taken? AND A JP M,GOTIT ; If not, we can use it INC DE ; Else, check next one JP CHECK GOTIT: LD A,B ; Store sector number LD (DE),A LD HL,(INTER) ; Increment pointer by ADD HL,DE ; interleave INC B ; Increment sector count LD A,(SECS) ; Have we done enough? CP B JP NZ,XCHECK ;Do a dummy read to insure that the head has beed restored LD A,CREAD OUT (COMND),A RSWAIT: IN A,(status) AND A JP M,RSWAIT ;Figure all the needed format paramters ; SDH mask LD A,20H ; Get 512 mask LD B,A ; Save for a moment jr noecc ;skip for now LD A,80H ; OR in ECC bit OR B LD B,A ; Save for a while NOECC: LD A,(UNIT) ; Get drive number RLCA ; Rotate drive into position RLCA RLCA OR B ; OR in sector size LD (UNIT),A ; Save size/drive mask ;Get cylinder and head and format LD HL,(CYLS) ; Get last cylinder push HL ; Save it HEADLP: call cylprt ;print new cylinder LD A,(HEADS) ; Get last head LD D,A FORLP: push DE push BC ld A,D ; Output head that we are on call outchr ld E,bs ld C,conout call bdos pop BC pop DE LD A,(SECS) ; Get sector count OUT (SECNT),A pop HL push HL LD A,L OUT (CYLLO),A ; Cylinder low LD A,H OUT (CYLHI),A ; Cylinder high LD A,(UNIT) ; Get size/drive mask OR D ; Or in heads OUT (SDH),A LD A,CFORM ; Issue format command OUT (COMND),A LD HL,INTTBL ; Index interleave table LD B,0 ; Get transfer size 0 = 256 ld A,DATA ld C,A XOR A ; Get bad block bits DATALP: OUT (C),A OUTI JR NZ,DATALP ; Continue till sector full FWAIT: IN A,(STATUS) ; Wait for format AND A JP M,FWAIT RRA ; Any errors? JP C,HERROR ; If so, call it quits call xitck ; want to exit DEC D ; Bump head counter JP P,FORLP ; Have we passed head 0? pop HL DEC HL ld A,H ; Have we passed cyl 0? and A push HL JP P,HEADLP pop HL ; ;Now verify that all records that we formatted can be read. ; ld DE,vermsg ; Say verifying ld C,prtstr call bdos LD HL,(CYLS) ; Get last cylinder LD A,(HEADS) ; Get last head LD E,A LD A,(SECS) ; get last sector DEC A LD D,A RHEAD: call cylprt ;print new cylinder LD C,E ; Reload head RSECS: push HL push DE push BC ld A,C ; Output head that we are on call outchr ld E,bs ld C,conout call bdos pop BC pop DE pop HL LD B,D ; Reload sector READIT: ld A,B OUT (SECNO),A ; Get sector LD A,L OUT (CYLLO),A ; Get cylinder low LD A,H OUT (CYLHI),A ; Get cylinder high LÄ A,(UNIT© » Geô Size/Drive OR C ; OR in head OUT (SDH),A LD A,CREAD ; Issue read command OUT (COMND),A RWAIT: IN A,(STATUS) ; Wait for it to be read AND A JP M,RWAIT RRA ; Check for errors JP NC,NOERR ; Jump if no error, ; ;This routine gives the user a detailed error report ; push HL ; Save important registers push DE push BC ld DE,errst ; Send error message ld C,prtstr call bdos IN A,(ERROR) ;error CALL HEXOUT ld DE,errhd ;head ld C,prtstr call bdos IN A,(SDH) AND 7 CALL OUTCHR ; Print single digit ld DE,errcyl ld C,prtstr call bdos IN A,(CYLHI) ; Report CYLHI first CALL HEXOUT IN A,(CYLLO) ; then CYLLO CALL HEXOUT ld DE,errsec ld C,prtstr call bdos IN A,(SECNO) CALL HEXOUT ld DE,vermsg1 ld C,prtstr call bdos call cylprt pop BC ; Restore registers pop DE pop HL ;The read sector routine continues here NOERR: call xitck DEC B ; Bump sector number JP P,READIT DEC C ; Bump head number JP P,RSECS DEC HL ; Bump cylinder number LD A,H ; Make sure it's not minus AND A JP P,RHEAD ld DE,dnemsg ; Say done ld c,prtstr call bdos JP RESEL ; Reselect original drive ;This subroutine checks for premature exit request xitck: push HL ; save regs push DE push BC ld C,const ;get console status call bdos AND A jr z,skp ;skip if no char ld C,conin call bdos cp 3 ; is it a ^C jp z,ABORT ;if so restart sys skp: pop BC pop DE pop HL ret ;This subroutine prints the contents of A in hex HEXOUT: PUSH AF RRCA ; Get upper digit RRCA RRCA RRCA CALL OUTCHR ; Print upper digit POP AF OUTCHR: AND 0FH ; Mask four bits ADD A,90H DAA ADC A,40H DAA LD E,A ld C,conout ; Write it to console call bdos RET cylprt: push DE push BC push HL ; Save regs to print out cyl ld DE,bsmsg ;back up ld C,prtstr call bdos pop HL ;get cyl push HL ld A,H ;print high cyl call hexout pop HL push HL ld A,L ;print low cyl call hexout ld DE,HDmsg ;print head msg ld C,prtstr call bdos pop HL ;restore regs pop BC pop DE ret HERROR: ld DE,urcmsg ld C,prtstr call bdos ;Re-select formerly current drive RESEL: JP 0 ;WARM START ; ; Disk parameters ; dskprms: st503: db 16 ;sectors dw 152 ;cylinders-1 db 1 ;heads-1 st506: db 16 ;sectors dw 152 ;cylinders-1 db 3 ;heads-1 tm601s: db 16 ;sectors dw 152 ;cylinders-1 db 1 ;heads-1 tm602s: db 16 ;sectors dw 152 ;cylinders-1 db 3 ;heads-1 tm603s: db 16 ;sectors dw 152 ;cylinders-1 db 5 ;heads-1 tm603se: db 16 ;sectors dw 229 ;cylinders-1 db 5 ;heads-1 tm501: db 16 ;sectors dw 305 ;cylinders-1 db 1 ;heads-1 tm502: db 16 ;sectors dw 305 ;cylinders-1 db 3 ;heads-1 tm503: db 16 ;sectors dw 305 ;cylinders-1 db 5 ;heads-1 sa602: db 16 ;sectors dw 159 ;cylinders-1 db 1 ;heads-1 sa604: db 16 ;sectors dw 159 ;cylinders-1 db 3 ;heads-1 sa606: db 16 ;sectors dw 159 ;cylinders-1 db 5 ;heads-1 sa1002: db 16 ;sectors dw 255 ;cylinders-1 db 1 ;heads-1 sa1004: db 16 ;sectors dw 255 ;cylinders-1 db 3 ;heads-1 q2010: db 16 ;sectors dw 511 ;cylinders-1 db 1 ;heads-1 q2020: db 16 ;sectors dw 511 ;cylinders-1 db 3 ;heads-1 q2030: db 16 ;sectors dw 511 ;cylinders-1 db 5 ;heads-1 q2040: db 16 ;sectors dw 511 ;cylinders-1 db 7 ;heads-1 m2010: db 16 ;sectors dw 479 ;cylinders-1 db 1 ;heads-1 m2020: db 16 ;sectors dw 479 ;cylinders-1 db 3 ;heads-1 ; ; Messages ; signon: db 'ADVANCED DIGITAL CORPORATION',CR,LF db 'HDC1001 Hard Disk Controller Formatter',CR,LF,LF db 'Select disk type from following menu',CR,LF menu: db '*** Hard Disk selection choices ***',CR,LF db '0 = ST503 ; Seagate Technology ST503',CR,LF db '1 = ST506',CR,LF db '2 = TM601S ; Tandon Magnetics TM601S',CR,LF db '3 = TM602S',CR,LF db '4 = TM603S',CR,LF db '5 = TM603SE',CR,LF db '6 = TM501 ; Tandon Magnetics TM501',CR,LF db '7 = TM502',CR,LF db '8 = TM503',CR,LF db '9 = SA602 ; Shugart Associates SA602',CR,LF db '10 = SA604',CR,LF db '11 = SA606',CR,LF db '12 = SA1002 ; Shugart Associates SA1002',CR,LF db '13 = SA1004',CR,LF db '14 = Q2010 ; Quantum Q2010',CR,LF db '15 = Q2020',CR,LF db '16 = Q2030',CR,LF db '17 = Q2040',CR,LF db '18 = M4010 ; MiniScribe 4010',CR,LF db '19 = M4020',CR,LF db '? $' inval: db CR,LF,'Invalid input try again.',CR,LF,'$' drvmsg: db CR,LF,'Which physical hard disk do you want to format. (0-3)? $' q1: db CR,LF,'This operation will destroy all data on drive $' q2: db '.',CR,LF,'Hit return to continue or ^C to abort.$' formsg: db LF,'Formatting. CYLINDER ' HDMSG: DB ' HEAD $' BSMSG: db bs,bs,bs,bs,bs,bs,bs,bs,bs,bs,'$' vermsg1: db LF vermsg: db CR,'Verifying. CYLINDER HEAD $' errst: db CR,LF,'HDC1001 Error $' errhd: db ' on Head $' errcyl: db ', Cylinder $' errsec: db ', Sector $' dnemsg: db CR,LF,'Format completed.$' urcmsg: db 'Sorry, unrecoverable error during format.$' abtmsg: db CR,LF,'Operation aborted.$' ; ;Variables ; UNIT: DS 1 ; Physical device unit INTERB: DB 8 ; Current interleave SECS: DS 1 ; Sectors per track CYLS: DS 2 ; Cylinders per drive HEADS: DS 1 ; Heads per drive INTER: DS 2 ; 16 bit interleave NSECS: DS 2 ; 16 bit negative SECS LIMIT: DS 2 ; Upper memory limit of table inbuf: db 64 ; Line input buffer numchr: ds 1 ; Number of characters returned INTTBL: DS 64 ; Interleave table END