home *** CD-ROM | disk | FTP | other *** search
- Title 'SDF : Speedy Disk Formatter'
-
- ; **************************************************************************
- ; * THIS PROGRAM IS PUBLIC DOMAIN. You Are Free To Use It And Redistribute *
- ; * It, As Long As No Profit Is Made Out Of It. Redistribution Costs May *
- ; * Not Exceed $5. This Notice May Not Be Removed Or Altered In Any Way. *
- ; * Use At Your Own Risk. Author Will Not Be Held Responsible For Any Dama-*
- ; * ge That Might Result Of Use Or Misuse. Enjoy. *
- ; **************************************************************************
-
- ; This program is inspired from QDR by Vernon D. Buerg, which unfortunately
- ; has a bug in handling 3.5" floppies.
-
- ; Better late than never, I dedicate this program to Ward Christensen, who
- ; showed us the way in the good old CP/M days ...
-
- ; Jacques Pierson, Belgrade (Belgium), November 1987.
- ; CIS 76446,1516
-
- ; Modification history:
- ; September 1990: fixed bug with DMA boundary errors, and added code to turn
- ; off the drive motor quickly.
- ; October 1990: fixed bug in above bug fix.
-
- M24 = 0 ;set to one at work, for an Olivetti M24 (ATT 6300)
-
- bell equ 7
- bs equ 8
- lf equ 0Ah
- cr equ 0Dh
- escape equ 1Bh
- ulc equ 0C9h ;graphic char - Upper Left Corner
- llc equ 0C8h ;Lower Left Corner
- urc equ 0BBh ;Upper Right Corner
- lrc equ 0BCh ;Lower Right Corner
- vb equ 0BAh ;Vertical Border
- hb equ 0CDh ;Horizontal Border
- ;
- hsr equ 0EFh ;Head Step Rate : 4 ms
- hst equ 0 ;Head Settle Time : 0 ms
- ;
-
-
- SDF segment
- assume ds:SDF, ss:SDF ,cs:SDF ,es:SDF
-
- org 0100h ;make this a COM file
-
-
- start: jmp GetCmdLine
-
- ; First describe our Disk Base Parms. We will make INT 1Eh to point here
- ; while formatting. Put at head of program so people without an assembler
- ; can easily patch this area w/ DEBUG.
-
- OurDBP equ $
-
- db hsr ;high nibble : heads step rate
- ;low nibble, head unload time
- db 2 ;DMA mode
- db 255 ;clock ticks before stopping drive motor
- db 2 ;sector size - 2 => 512 bytes
- db 9 ;How many sectors per track
- db 42 ;Gap length between sectors for R/W ops
- db -1 ;data length - Not used
- db 80 ;Gap length when formatting
- db 0F6h ;Formatting char. Dos likes F6's
- db hst ;Head settle time in ms.
- db 1 ;Motor speed up time in 1/4 sec.
-
- Welcome db cr,lf,'Speedy Disk Formatter, V1.0, '
- db '(c) Jacques Pierson, Nov 1987$'
-
- UsageMessage equ $
- db cr,lf,lf,'Usage: SDF drv: [switches]',cr,lf
- db 'drv: mandatory and is either A: or B:,',cr,lf
- db 'No switch => format standard 360K diskette, no verify',cr,lf
- db '/Q => format Quad density (3',0abh,'" 720K disk)',cr,lf
- db '/V => force Verify after format',cr,lf
- db 'Multiple switches may be combined, e.g. SDF b:/q/v.'
- db cr,lf,lf,'$'
-
- DriveMissing db cr,lf,lf,'Invalid or missing Drive Spec !$'
-
- WrongSwitch db cr,lf,lf,'Unknown /switch in command line !$'
-
- InsertDisk db cr,lf,lf,'Insert diskette in drive '
- Drive db 'A, and press ENTER when ready ...$'
-
- Again db cr,lf,lf,'Format complete,'
- Clusters db ' K available to user.'
- db cr,lf,'Press ENTER to format another diskette, '
- db 'or ESCape to quit...$'
-
- Formatting db cr,lf,lf,'Formatting '
- DiskType db 'DSDD, Without$'
- Verify db ' Verify.',cr,lf,'$'
-
- Track db cr,'Track: '
- TrackNr db ' Side: '
- SideNr db ' $'
-
- ShowRetry db bs,'R$'
-
- WritingBoot db ' - writing BOOT$'
- WritingFAT db ', FATs$'
- WritingDIR db ', DIR.$'
-
- ErrorTbl db 1,'Invalid command '
- db 2,'Address mark not found. '
- db 4,'Requested sector not found. '
- db 8,'DMA overrun on operation. '
- db 10h,'Bad CRC on diskette read/write.'
- db 20h,'Controller failure. '
- db 40h,'SEEK operation failed. '
- EndOfErrTbl equ $
-
- FatalErr db bell,cr,lf,lf,'Door Open, Write-protected disk,'
- db ' or Drive Fails to respond.'
- db cr,lf,'Please fix problem and hit Enter to continue,'
- db 'or ESCape to abort...$'
-
- BadClusters db cr,lf,lf,'Bad sectors :'
- BadClNr db ' Cluster(s) disabled.',cr,lf,lf,'$'
- ;
- ErrBadSec db bs,bs,', Sec: '
- ErrSec db ' , Error '
- ErrCode db ' hex : '
- ErrMsg db 'Unknown error. ',cr,lf,'$'
- ;
- ;
- ; Flags, set according to switches
- ;
- OptionsFlag db 0 ;default is No Verify, Normal Disk
- CtrlBreak db 0 ;Ctrl-Break flag on entry
- ;
- ; Disk characteristics, other parms are found in BootSector
- ;
- DirSecs dw 7 ;DIRectory size in sectors
- DskTrks db 40 ;Cyls/disk
- CurTrk db -1 ;Current track
- CurDrv db 0 ;Current drive, binary, BIOS way (A:=0,..)
- NeedSetup db 1 ;nonzero if default parms are in effect
-
- even ;Align for those w/8086 processors
-
- RetryCount dw 0 ;Count of retries
- MaxTries dw 2 ;Maximum retries attempted
- BadSecCnt dw 0 ;Count of Bad Sectors
- NextSec dw 0 ;Temp storage for next sector #
- INT1Eoff dw 0 ;INT 1Eh offset
- INT1Eseg dw 0 ;INT 1Eh segment
- INT24off dw 0 ;Critical error handler offset
- INT24seg dw 0 ;Critical error segment
- ;
- HexTbl db '0123456789abcdef'
- ;
- ID_tbl dw Side0 ;addr of table of ID's for track 0, side 0
-
- Side0 db 0,0,1,2
- db 0,0,2,2
- db 0,0,3,2
- db 0,0,4,2
- db 0,0,5,2
- db 0,0,6,2
- db 0,0,7,2
- db 0,0,8,2
- db 0,0,9,2 ;end of side 0
-
- db 0,1,1,2 ;side 1 now
- db 0,1,2,2
- db 0,1,3,2
- db 0,1,4,2
- db 0,1,5,2
- db 0,1,6,2
- db 0,1,7,2
- db 0,1,8,2
- db 0,1,9,2 ;end of track, side 1
-
- SideLen equ 36
- ;
- ;
- ; Anatomy of our Boot sector
- ;
- BootSector equ $
-
- jmp BootMsg
-
- db 'SDF v01' ;OEM name, 8 chars
- dw 512 ;Sector size
- db 2 ;Cluster size in sectors
- dw 1 ;Reserved sectors
- db 2 ;Number of FATs
- DirSize dw 112 ;Directory entries
- TotSecs dw 720 ;Total sectors
- MediaDes db 0FDh ;Media descriptor
- FatSize dw 2 ;FAT size in sectors
- dw 9 ;Sectors per Track
- dw 2 ;Number of heads
- dw 0 ;Number of hidden sectors
- db 0 ;filler
- db 0 ;head
- db 10 ;length of BIOS file
- db hsr ;The DPB, remember ?
- db 2
- db 25h
- db 2
- db 9
- db 42
- db -1
- db 80
- db 0F6h
- db hst
- db 1
-
- NoBootMsg equ $
-
- db cr,lf,lf
- db ulc,50 DUP (hb),urc,cr,lf
- db vb,' This diskette has been formatted by SDF and ',vb,cr,lf
- db vb,' contains no system to boot from. Either ',vb,cr,lf
- db vb,' remove it and hit a key to boot from hard disk ',vb,cr,lf
- db vb,' if any, or replace it with another disk with a ',vb,cr,lf
- db vb,' system to boot from and hit a key when ready. ',vb,cr,lf
- db llc,50 DUP (hb),lrc,cr,lf,lf,0
-
-
- BootMsg:
- cli ;no interrupts
- cld ;forward direction
- mov AX,07C0h ;Boot runtime address
- mov DS,AX ;to DS
- mov ES,AX
- mov SS,AX
- mov SP,0 ;temp stack at top of segment
- mov SI,(OFFSET NoBootMsg - OFFSET BootSector) ;Msg ptr
- BNextChar:
- lodsb ;Get byte fm msg
- or AL,AL ;a null ?
- je ReBoot ;yes, print msg done
- mov AH,0Eh ;print char, no bells and whistles
- int 10h ;Bios output char INT
- jmp SHORT BNextchar ;loop for all string
- ;
- ReBoot: xor AH,AH ;wait for key hit
- int 16h
-
- int 19h ;and try booting again
-
-
- BEndOfStuff equ $
-
- db (510 - (BEndOfStuff - BootSector)) DUP (0) ;filler
-
- db 55h,0AAh ;DOS disk signature
- ;
- ; End of boot sector
- ;
- ;
- ; First sector of File Allocation Table
- ;
- FatSec1 equ $
- db 0FDh ;FAT - Media descriptor
- db 0FFh
- db 0FFh
- db 509 DUP (0) ;to get a full sector
-
- FatSec2 db 512 DUP (0) ;FAT, second sector
- db 512 DUP (0) ;FAT, third sector
- ;
- DirSec1 equ $
- DskLbl db 'SDF--------' ;Dir entry for disk label, 11 char
- db 28h ;Attributes : Label + Archive
- db 10 DUP (0)
- TimeLo db 0
- TimeHi db 0
- Date dw 0
- db 486 DUP (0) ;full sector
- ;
- DirSec2 db 512 DUP (0) ;2nd and other sectors
- ;
- ;
- ; Control-Break handler : DO NOT give user a chance to exit w/^C or Break
- ; without resetting the environement...
- ;
- ControlBreak:
-
- iret ;trap ^C and simply return
- ;
- ;
- ; Critical Error handler: Same as above. Note that, contrary to documentation
- ; (under DOS 2.1 at least), selecting 'a' under Abort/Retry/Fail does not put
- ; you into INT 23.
- ;
- CritError:
- push AX
- push DX
- push DS
- push CS
- pop DS
- call Restore
- pop DS
- pop DX
- pop AX
- jmp far cs:[INT24off] ;go to the previous handler
- ;
- ; Let's go to it now
- ;
- GetCmdLine:
-
- mov DX,offset Welcome ;print welcome msg
- call PrintString
- mov SI,80H ;Peek at input bfr char count
- lodsb ;get byte
- cbw ;make word
- or AX,AX ;any option ?
- jne GCL1 ;yes
- Usage: mov DX,offset UsageMessage
- call PrintString ;Print and fall thru ErrorExit
- ;
- ; Error Exit, w/ return code 1, Normal Exit, w/ return code 0
- ;
- ErrorExit:
- mov AL,1
- jmp SHORT DoExit
- ;
- Abort: call Restore ;Restore INT 1E, INT 35
- ;
- Exit: mov AL,0 ;normal exit, no error
- DoExit: mov AH,4Ch ;Program Exit
- int 21h
- ;
- ;
- ; Carry on parsing command line
- ;
- GCL1: mov CX,AX ;got something in cmd line, count to CX
- call ParseSwitches ;Parse cmd line "/" switches
- mov SI,81h ;Get drive spec
- GCL2: lodsb
- cmp AL,' ' ;skip spaces
- loopz GCL2
- jcxz Usage ;Nuts, give Usage Msg
- cmp AL,cr
- jz Usage
- and AL,5fh ;Make drive letter uppercase
- mov Drive,AL ;Put drive letter in msg
- sub AL,'A' ;make binary, BIOS way
- mov CurDrv,AL ;Store in current drive
- cmp AL,1 ;Drive MUST be 0 or 1
- jg BadDrive
- lodsb
- cmp AL,':' ;Make sure this WAS a drive spec
- jne BadDrive ;no, it was not
- jmp Setup ;Yes, indeed
- BadDrive:
- mov DX,OFFSET DriveMissing
- call PrintString
- jmp Usage
- ;
- ;
- A$Ret: ret
- ;
- ; Parse command line switches
- ;
- ParseSwitches:
- mov DI,81h ;peek at cmd line
- PS1: mov AL,'/'
- repne scasb ;search for "/", length in CX
- jne A$Ret
- jcxz A$Ret ;none, or no more
- mov BYTE PTR [DI-1],cr ;Got a "/", put a CR for later use
- cmp BYTE PTR [DI-2],' ' ;Previous char was space ?
- jne PS2 ;no
- mov BYTE PTR [DI-2],cr ;yes, force to CR
- PS2: mov SI,DI
- lodsb ;get switch
- and AL,5Fh ;Force uppercase
- PS3: cmp AL,'V' ;/Verify ?
- jne PS4 ;no
- mov OptionsFlag,1 ;yes, remember that
- mov WORD PTR DskLbl+6,'V+' ;put in disk label
- mov BYTE PTR DiskType+10,'$' ;truncate "Without" msg
- jmp PS1 ;parse next
- PS4: cmp AL,'Q' ;/Quad density ?
- jne PS5 ;no, unknown switch
- mov BYTE PTR DiskType+2,'Q' ;Flag, and Description
- mov DskTrks,80 ;80 tracks
- mov FatSize,3 ;FAT is 3 sectors long
- mov TotSecs,1440 ;1440 sectors
- mov MediaDes,0F9h ;to Boot Sector
- mov WORD PTR DskLbl+8,'Q+' ;put in disk label
- jmp PS1 ;parse next switch
- PS5: mov DX,OFFSET WrongSwitch
- call PrintString
- jmp Usage
-
- ;
- ; Restore : Restore the world as it was on entry
- ;
- Restore:cmp NeedSetup,0 ;see if we need to do this
- jnz Res1 ;if not
- mov NeedSetup,1
-
- lds DX,DWORD PTR INT1Eoff ;previous INT 1Eh vector
- mov AX,251Eh ;restore it
- int 21h
- push CS ;restore DS
- pop DS
-
- mov AH,0 ;Reset Disk System
- int 13h
-
- mov AX,3301h ;set Ctrl-Break flag
- mov DL,CtrlBreak ;restore as was on entry
- int 21h
-
- Res1: ret
- ;
- ;
- ; Setup : Set up the world
- ;
- Setup: mov AH,AL ;colon to AH
- mov AL,CurDrv
- add AL,'A'
- mov WORD PTR DskLbl+4,AX ;put DriveSpec in disk label
-
- mov AX,3300h ;Get CtrlBreak flag
- int 21h
- mov CtrlBreak,DL ;save flag
-
- mov DX,OFFSET ControlBreak ;our handler
- mov AX,2523h ;Set Interrupt Vector 23h
- int 21h
-
- mov AX,3524h ;get Interrupt Vector 24h
- int 21h
- mov INT24off,BX
- mov INT24seg,ES
- mov DX,OFFSET CritError ;our handler
- mov AX,2524h ;Set Interrupt Vector 24h
- int 21h
-
- mov AX,351Eh ;get Interrupt Vector 1Eh
- int 21h
- mov INT1Eoff,BX
- mov INT1Eseg,ES
-
- push CS
- pop ES
- ;fall thru format loop
- ;
- Do_It: mov DX,OFFSET InsertDisk ;say "Insert diskette in drive.."
- call PrintString
- ;
- GetChar:mov AH,0 ;get char function
- int 16h
- cmp AL,escape
- jne GC1
- jmp Abort
- GC1: cmp AL,cr
- jne GetChar ;Escape or CR only !
-
- cmp NeedSetup,0 ;see if we need to do this
- je GC2 ;if not
- mov NeedSetup,0
-
- mov DX,OFFSET OurDBP ;our DBP
- mov AX,251Eh ;Set Interrupt Vector 1Eh
- int 21h
-
- mov AH,0 ;Reset Disk System
- int 13h ;our DBP is now in effect
-
- mov AX,3301h ;set flag
- xor DL,DL ;set checking OFF
- int 21h
-
- GC2: mov DX,OFFSET Formatting ;"Formatting..."
- call PrintString
- mov DX,OFFSET Verify
- call PrintString
- mov BadSecCnt,0 ;no bad sector so far
- call PrepareFat
- ;
- ; Format all disk now
- ;
- call DoFormat ;Here we go
- mov AX,BadSecCnt ;any bad sector ?
- or AX,AX
- je NoBadSec ;no
- mov SI,OFFSET BadClNr ;Pointer to decimal places
- call AX2dec ;convert to decimal
- mov DX,OFFSET BadClusters ;Bad Clusters msg
- call PrintString
- ;
- ; Write Boot, FAT, DIR
- ;
- NoBadSec:call WriteBFD ;write Boot, Fat, Dir
- ;
- ; Show available space
- ;
- mov AH,0Dh ;reset disk system
- int 21h
- mov AH,36h ;get free space
- mov DL,CurDrv ;for our drive
- inc DL ;DOS way
- int 21h
- mov AX,BX ;clusters to AX
- mov SI,OFFSET Clusters
- call AX2dec ;convert and fall thru print
- ;
- ; Done - prompt for another disk to format
- ;
- mov DX,OFFSET Again ;"Hit enter to format another..."
- call PrintString
- call MotorOff ;Turn motor off
- call Whistle ;Wake him up
- jmp GetChar ;get char
-
-
- ;
- ; Prepare first FAT sector - This stuff required for multiple formatting
- ;
- PrepareFat:
- sub AX,AX ;clear FAT to all zeros
- mov DX,FatSize ;How many sectors ?
- mov DI,OFFSET FatSec1
- PF1: mov CX,512/2 ;sector size, in words
- repz stosw ;for speed
- dec DX ;next FAT
- jnz PF1
- mov AL,MediaDes ;get Media Descriptor from Boot Sec
- mov BYTE PTR FatSec1,AL ;move in place
- mov WORD PTR FatSec1+1,0FFFFh
- ret
-
- ;
- ; Here to REALLY format a disk
- ;
- DoFormat:
- mov CurTrk,-1 ;Initialize track nr
- NextTrk: ;Prepare table for Track/sect. ID's
- inc CurTrk ;Next track
- mov CH,CurTrk ;to CH
- cmp CH,DskTrks ;All done ?
- jb NT1 ;not yet
- ret ;yes, return
- NT1: mov DI,ID_tbl ;Point to table
- mov AL,18 ;18 sectors per Cyl
- NT2: mov [DI],CH ;move Track # in table
- add DI,4 ;point to next entry
- dec AL ;all done ?
- jnz NT2 ;No, loop
- mov AH,1 ;Give user a chance to abort
- int 16h ;Keyboard hit ?
- jz NT3 ;no
- cmp AL,escape ;yes, Escape to abort ?
- jne NT3
- jmp Abort
- ;
- NT3: mov AX,0509h ;Format Track, 9 sectors/trk
- mov BX,ID_tbl ;track id table address, side 0
- mov DL,CurDrv ;current drive
- mov DH,0 ;Side 0
- mov CL,1 ;First sec is #1
- call PrintProgress ;Print progress (Track#, Side #)
- int 13h ;Format track, side 0
- jnc NT3V ;No Carry, no error
- call Retry ;Carry set, Shall we retry ?
- jnc NT3 ;yes, if we come here w/Carry clear
- ;else, give up
- NT3V: test OptionsFlag,1 ;Should we verify ?
- jz NT4 ;No, next side
- ;
- NT3R: mov AX,0409h ;Verify, 9 sectors per track
- int 13h
- jnc NT4 ;No carry, no error
- call Retry ;Carry set, retry ?
- jnc NT3R ;Yes, if Carry clear, else give up
- NT4: mov DH,1 ;Side 1
- mov AX,0509h ;Format Track, 9 sectors/trk
- mov BX,ID_tbl ;track id table address, side 1
- add BX,SideLen
- mov DL,CurDrv ;current drive
- mov CL,1 ;First sec is #1
- call PrintProgress ;Print progress (Track#, Side #)
- int 13h ;Format track, side 1
- jnc NT4V ;no error
- call Retry ;Carry set, error
- jnc NT4 ;Retry if Carry clear, else give up
- NT4V: test OptionsFlag,1 ;Should we verify ?
- jz NextTrk ;no, next track
- ;
- NT4R: mov AX,0409h ;Verify, 9 sectors per track
- int 13h
- jc NT5 ;error !
- jmp NextTrk ;no error, next track
- NT5: call Retry ;Carry set, retry ?
- jnc NT4R ;yes
- jmp NextTrk ;no, next track
- ;
- Retry: cmp AH,3 ;Door open/Write protected ?
- je R1 ;yes
- cmp AH,80h ;Attachment failed to respond ?
- jne R2 ;no, other error
- R1: mov DX,OFFSET FatalErr ;tell him he'd better close the door
- call PrintString ;..or remove the write-protect tab
- pop AX ;clean up stack, we won't return
- pop AX ;two calls to clean up
- jmp GetChar ;OK, we may restart now
- R2: cmp AH,9 ;DMA boundary error?
- jne R4 ;no, other error
- push CX ;save registers
- push SI
- mov DI,ES ;compute offset of next DMA page
- neg DI
- mov CL,4
- shl DI,CL
- cmp DI,EndCode
- ja R3 ;if it's not in the code segment
- mov DI,EndCode ;don't clobber code
- R3: mov SI,ID_tbl ;move the table pointer
- mov ID_tbl,DI
- mov CX,SideLen ;move the table itself
- rep movsw
- cmp SI,DI
- pop SI ;restore registers
- pop CX
- je R4 ;if this should already be fixed
- clc
- ret
- R4: push DX
- mov DX,OFFSET ShowRetry ;Show 'R' to indicate a retry
- call PrintString
- pop DX
- inc RetryCount
- mov DI,MaxTries ;limit exceeded ?
- cmp RetryCount,DI
- ja SecIsBad ;Yes, this one is really bad
- mov AH,0 ;No, Reset Disk System
- int 13h
- clc ;clear carry
- ret ;and return to try again
- ;
- ; If we come here, we really have to deal with a bad sector
- ;
- SecIsBad: call ShowBadSec
- inc BadSecCnt ;count it
- call MarkBad ;Mark whole cluster
- mov RetryCount,0 ;Reset retry count
- stc ;Set Carry to indicate "give up"
- ret ;go process next side or track
- ;
- ;
- ; Mark a bad sector (cluster) in FAT
- ;
- MarkBad:push AX
- push BX
- push CX
- push DX
- push DI
- push SI
- push DS ;We have to fetch..
- mov AX,40h ;.. the faulty sector
- mov DS,AX ;.. in the BIOS area
- mov BX,47h
- mov CL,BYTE PTR [BX] ;Get sector number
- pop DS
- mov AL,CH ;Track # to AL; AH is already 0
- xor CH,CH
- cmp DH,0 ;Side 0 ?
- je MB1
- add CL,9 ;Side 1, add 9 sects for side 0
- MB1: shl AX,1 ;* 2 heads
- mov BX,9 ;* 9 sectors per track
- mul BX ;compute absolute sector #
- add AX,CX
- sub AX,FatSize ;minus 1st FAT size
- sub AX,FatSize ;minus 2nd FAT size
- sub AX,DirSecs ;minus Directory size
- mov BL,2 ;disk heads
- div BX
- add AX,1
- mov CX,3
- mul CX
- shr AX,1 ; / 2
- mov DI,AX
- lea SI,[DI+FatSec1] ;pointer into FAT
- mov DI,SI
- lodsw ;get cluster entry
- mov DX,0FF70h ;12 bits, left aligned
- jb MB2 ;if even
- mov DX,0FF7h ;if odd
- MB2: or AX,DX ;merge w/ word to mark bad
- stosw ;store back in FAT
- pop SI
- pop DI
- pop DX
- pop CX
- pop BX
- pop AX
- ret
- ;
- ; Write Boot sector, then FATs, then DIR.
- ;
- WriteBFD:
- mov DX,OFFSET WritingBoot
- call PrintString
- mov AL,CurDrv
- lea BX,BootSector ;boot sector
- mov CX,1 ;1 sector to write
- mov DX,0 ;absolute sector 0
- call AbsSecWrite
- ;
- ; Write FAT(s)
- ;
- push DX ;Preserve Sector Nr
- mov DX,OFFSET WritingFAT ;"FATs"
- call PrintString
- pop DX
- mov AL,CurDrv ;current drive
- lea BX,FatSec1 ;point to FAT 1st sector
- mov CX,1 ;1 sector write
- inc DX ;DX knows which
- call AbsSecWrite
- mov CX,FatSize ;sectors/FAT
- dec CX ;One written already
- lea BX,FatSec2 ;get FAT 2nd sector
- mov AL,CurDrv ;current drive
- inc DX ;next sector(s)
- call AbsSecWrite
- add DX,CX ;count sectors written this time
- ;
- ; Write second FAT
- ;
- mov AL,CurDrv ;current drive
- mov BX,OFFSET FatSec1 ;FAT
- mov CX,1 ;1 sector, DX knows which
- call AbsSecWrite
- mov CX,FatSize ;How many remaining ?
- dec CX ;One already written
- mov BX,OFFSET FatSec2 ;point to FAT 2nd sector
- mov AL,CurDrv ;current drive
- inc DX ;next FAT sector(s)
- call AbsSecWrite
- add DX,CX
- mov NextSec,DX ;remember next sector to write
- ;
- ; Write Directory
- ;
- mov DX,OFFSET WritingDIR ;"DIRectory"
- call PrintString
- ;
- ; Update Disk Label Date and Time
- ;
- mov AH,2Ch ;Get Time
- int 21h
- mov BX,CX ;Minutes, Seconds
- mov AX,CX
- mov CL,3
- shl CH,CL ;Shift to move hour in place
- shr BL,CL ;Shift to keep high 3 bits of min
- add CH,BL ;merge
- mov TimeHi,CH ;move in place
- and AL,7 ;keep min. lower 3 bits
- shl AL,1 ;shift
- mov CL,5
- shr DX,CL ;Shift seconds
- add DH,AL ;merge
- mov TimeLo,DH ;move in place
- mov AH,2Ah ;Get Date
- int 21h
- sub CX,1980 ;From 1980 on
- shl CL,1
- mov BX,DX
- mov AH,CL
- mov CL,3
- shr DH,CL
- add AH,DH
- mov CL,5
- shl BH,CL
- add BH,DL
- mov AL,BH
- mov Date,AX ;Move date in place
- mov AL,CurDrv ;current drive
- mov BX,OFFSET DirSec1 ;First sector of DIR
- mov DX,NextSec ;current sector
- mov CX,1 ;1 sector to write
- call AbsSecWrite
- mov AL,CurDrv
- mov BX,OFFSET DirSec2
- mov CX,DirSecs ;How many sectors
- dec CX ;One already written
- WD1: push CX
- mov CX,1 ;1 sector write
- inc DX ;next one
- call AbsSecWrite
- pop CX ;how many remaining ?
- loop WD1
- ret ;Done, next disk please.
- ;
- ; Print progress : Track nn Side n - inline decimal conversion
- ;
- PrintProgress:
- push AX
- push DX
- mov AL,DH ;Side #
- add AL,'0' ;Brute force ascify
- mov SideNr,al ;Put side # in msg
- mov AL,CH ;get track #
- aam ;THE trick
- xchg AL,AH ;swap
- add AX,'00' ;Ascify
- mov WORD PTR TrackNr,AX ;Put track # in msg
- mov DX,OFFSET Track ;say "Track..., Side..."
- call PrintString
- pop DX
- pop AX
- ret
- ;
- ; Here to show that we have a bad sector
- ;
- ShowBadSec:
- push AX
- push BX
- push CX
- push DX
- push DI
- push SI
- mov DX,AX ;Save AX for further hex printing
- sub BX,BX
- mov BL,AH ;remember error code
- mov DI,OFFSET ErrorTbl ;Table for INT 13 error codes & msgs
- mov AL,AH ;Error code to AL
- MOV CX,OFFSET EndOfErrTbl
- sub CX,DI ;compute table length
- repnz scasb ;search for error code
- jnz SBS1 ;Not found, "Unknown Error"
- mov SI,DI ;Got it, Ptr to SI
- mov CX,31 ;err msg length
- mov DI,OFFSET ErrMsg ;Point to destination
- repz movsb ;Move Err Msg in place
- SBS1: mov AL,DH ;Get AH : error code
- call AL2hex ;Convert
- mov WORD PTR ErrCode,AX ;move AH (hex) in msg
- push DS
- mov AX,40h ;Point to BIOS data area
- mov DS,AX
- mov BX,47h ;the right place in BIOS area
- mov AL,BYTE PTR [BX] ;BIOS knows which sector causes problem
- pop DS
- add AL,'0' ;ascify
- mov ErrSec,AL ;move sec # in msg
- mov DX,OFFSET ErrBadSec ;give error msg
- call PrintString
- pop SI
- pop DI
- pop DX
- pop CX
- pop BX
- pop AX
- ret
- ;
- ;
- ; AL2hex : binary AL to 2 hex digits in AX conversion
- ;
- AL2hex: push BX
- push CX
- push DX
- push SI
- mov BL,AL ;will use BX as offset to tbl
- mov CL,4 ;bits to shift
- sub BH,BH
- shr BL,CL
- and AL,0Fh ;mask off bits
- sub AH,AH
- mov SI,OFFSET HexTbl ;point to hex tbl
- add SI,BX
- mov DL,[BX+HexTbl]
- mov BX,AX
- mov DH,[BX+HexTbl]
- mov AX,DX
- pop SI
- pop DX
- pop CX
- pop BX
- ret
- ;
- ;
- ; AX2dec : routine to convert AX to decimal string at DS:SI
- ;
- AX2dec: push AX
- push CX
- push SI
- xor CL,CL ;clear 10000 counter
- s10000: inc CL
- sub AX,10000
- jnc s10000
- add AX,10000 ;one SUB too much
- add CL,'0'-1 ;adjust and ascify
- mov [SI],CL ;store in string
- inc SI
- xor CL,CL ;clear 1000 counter
- s1000: inc CL
- sub AX,1000
- jnc s1000
- add AX,1000 ;one SUB too much
- add CL,'0'-1 ;adjust and ascify
- mov [SI],CL ;store in string
- inc SI
- xor CL,CL ;clear 100 counter
- s100: inc CL
- sub AX,100
- jnc s100
- add AX,100 ;one SUB too much
- add CL,'0'-1 ;adjust and ascify
- mov [SI],CL ;store in string
- inc SI
- aam ;Convert value <100
- xchg AL,AH ;swap
- add AX,'00' ;Ascify
- mov [SI],AX
- pop SI ;restore string ptr
- mov CX,5 ; 5 bytes to search
- AX2D1: cmp BYTE PTR [SI],'0' ;leading Zero ?
- jne AX2D2 ;no or no more
- mov BYTE PTR [SI],' ' ;yes, make leading space
- inc SI
- loop AX2D1 ;loop for all
- AX2D2: pop CX
- pop AX
- ret
- ;
- ;
- ; PrintString : print string pointed by DX, terminated by '$'
- ;
- PrintString:
-
- push ax
- mov ah,9
- int 21h
- pop ax
- ret
- ;
- ; Absolute sector Write
- ;
- AbsSecWrite:
-
- push AX
- push BX
- push CX
- push DX
- int 26h ;absolute sector write
- jnb ASW1 ;no carry, no error
- xchg CX,DX
- mov DH,DL
- call ShowBadSec
- ASW1: popf
- pop DX
- pop CX
- pop BX
- pop AX
- ret
- ;
- ; MotorOff - Turn drive motor off
- ;
- motor_count equ 440h
- ;
- MotorOff:
- push ds
- xor ax,ax
- mov ds,ax
- mov byte [motor_count],1 ;turn off drive motor next timer tick
- pop ds
- ret
- ;
- ; Whistle - Wolf's whistle
- ;
- i8253 equ 40h ;Timer chip base address
- i8255 equ 60h ;PPI chip base address
- ;
- Whistle:
- push AX
- mov AL,0B6h ;Counter 2, 2 bytes count, mode 3
- out (i8253+3),AL ;Write Mode Word
- mov AX,1000 ;Divisor
- push AX
- out (i8253+2),AL ;load lo byte
- xchg AH,AL
- out (i8253+2),AL ;load hi byte
- in AL,(i8255+1) ;8255, port B
- or AL,3 ;turn on bottom two bits, spkr on
- out (i8255+1),AL
- pop AX
- W1: call SwLoop ;soft timing loop
- dec AX
- out (i8253+2),AL ;load lo byte
- xchg AH,AL
- out (i8253+2),AL ;load hi byte
- xchg AH,AL
- jne W1 ;loop
- in AL,(i8255+1) ;8255, port B
- and AL,NOT 3 ;turn off bottom two bits, spkr off
- out (i8255+1),AL
- pop AX
- ret
- ;
- ; Soft loop for Whistle
- ;
- SwLoop: push CX
- mov CX,100
- SWL: loop SWL
- pop CX
- ret
- ;
- ; End of code
- ;
- EndCode:
- ;
- SDF ends
- ;
- end start
-