home *** CD-ROM | disk | FTP | other *** search
Text File | 1984-04-29 | 31.3 KB | 1,156 lines |
- TITLE 'FINDBAD Ver 1.0 - Universal Version for CP/M-86'
- ;
- ; FINDBAD.A86 Ver. 1.0
- ;
- ; Modified for CP/M-86 from FINDBAD52.ASM of 02/16/82
- ;
- ;FINDBAD will find all bad blocks on a disk and build a file
- ;named [UNUSED].BAD to allocate them, thus "locking out" the
- ;bad blocks so CP/M-86 will not use them.
- ;
- ;Originally written by Gene Cotton, published in "Interface
- ;Age", September 1980 issue, page 80.
- ;
- ; SYSTST and BADUSR options:
- ;
- ; Many double-density disk systems have single-density system
- ;tracks. If this is true with your system, you can change the
- ;program to skip the system tracks, without re-assembling it.
- ;To do this, set the byte at 103H to a 0 if you don't want the
- ;system tracks tested, otherwise leave it 0. This is also
- ;necessary if you have a "blocked" disk system; that is, when
- ;the same physical disk is seperated into logical disks by use
- ;of the SYSTRK word in the disk parameter block.
- ;
- ; If you are a CP/M-86 1.x user, you may assign the user
- ;number where [UNUSED.BAD] will be created by changing the
- ;byte at 104H to the desired useru may assign the user
- ;number where [UNUSED.BAD] will be created by changing the
- ;byte at 104H to the desired user--------------
- ;NOTE: If you want to update this program, make sure you have
- ;the latest version first. After adding your changes, please
- ;modem a copy of the new file to CP/M-NET in Simi Valley,
- ;California - phone (805) 527-9321 (50, 110, 300, 450 or 600
- ;baud). Use the filename FNDBDA86.NEW. (K. Smith)
- ;
- ;Modifications/updates:
- ;
- ;02/03/82 Changed to CP/M-86 compatibility with the help of
- ; DR's XLT86 utility, made changes for goofs made by
- ; XLT86, removed ANYTHING to do with CP/M-80 Ver.
- ; 1.4. (K. Smith, CP/M-Net 'SYSOP')
- ;
- ; Note: You must assemble with ASM86.CMD as follows:
- ;
- ; ASM86 FINDBAD<cr>
- ;
- ; Then create a '.CMD' as,
- ;
- ; GENCMD FINDBAD 8080<cr>
- ;
- ;04/10/81 Changed extent DB from -1 to 0FFH so program can be
- ; assembled by ASM. Added BADUSR info to instructions
- ; for altering with DDT. (KBP)
- ;
- ;04/09/81 Changed sign-on message, added control-c abort test,
- ; added '*' to console once each track (RGF)
- ;
- ;04/07/81 Re-wrote to add the following features:
- ; 1) "universal" operation
- ; 2) DDT-changeable "SYSTRK" boolean (see above)
- ; 3) Report to console when bad blocks are detected
- ; 4) Changed the method of printing the number of
- ; bad blocks found (at end of run)...the old
- ; method used too much code, and was too cum-
- ; bersome.
- ; 5) Made several cosmetic changes
- ;
- ; Ron Fowler
- ; Westland, Mich
- ;
- ;03/23/81 Set equates to standard drive and not double-sided. (KBP)
- ;
- ;03/01/81 Corrected error for a Horizon with double sided drive.
- ; This uses 32k extents, which code did not take into account.
- ; (Bob Clyne)
- ;
- ;02/05/81 Merged 2/2/81 and 1/24/81 changes, which were done
- ; independently by Clyne and Mack. (KBP)
- ;
- ;02/02/81 Added equates for North Star Horizon - 5.25" drives,
- ; double density, single and double sided. (Bob Clyne)
- ;
- ;01/24/81 Added equates for Jade DD disk controller
- ; (Pete H. Mack)
- ;
- ;01/19/81 Added equates for Icom Microfloppy 5.25" drives.
- ; (Eddie Currie)
- ;
- ;01/05/81 Added equates for Heath H-17 5.25" drives.
- ; (Ben Goldfarb)
- ;
- ;12/08/80 Added equates for National Multiplex D3S/D4S
- ; double-density board in various formats.
- ; (David Fiedler)
- ;
- ;09/22/80 Added equates for Morrow Disk Jockey 2D/SS, 256,
- ; 512 and 1024-byte sector options. Fix 'S2' update
- ; flag for larger max number of extents. Cleaned up
- ; file. (Ben Bronson and KBP)
- ;
- ;09/14/80 Corrected DGROUP equate for MMDBL. Added new routine
- ; to correct for IMDOS group allocation. Corrected
- ; error in instructions for using TEST routine.
- ; (CHS) (AJ) (KBP) - (a group effort)
- ;
- ;09/08/80 Fixed several errors in Al Jewer's mods. Changed
- ; return to CP/M to warm boot so bitmap in memory will
- ; be properly updated. Added conditional assembly for
- ; testing program. (KBP)
- ;
- ;09/02/80 Added IMDOS double-density equates & modified for
- ; more then 256 blocks per disk. (Al Jewer)
- ;
- ;09/01/80 Changed equates so that parameters are automatically
- ; set for each disk system conditional assembly (KBP)
- ;
- ;08/31/80 Add conditional assembly for Digital Microsystems FDC3
- ; controller board in double-density format and fix to
- ; do 256 blocks in one register. (Thomas V. Churbuck)
- ;
- ;08/31/80 Correct MAXB equate - MAXB must include the directory
- ; blocks as well as the data blocks. Fix to make sure
- ; any [UNUSED].BAD file is erased before data area is
- ; checked. (KBP)
- ;
- ;08/30/80 Added conditional assembly for Micromation
- ; double-density format. (Charles H. Strom)
- ;
- ;08/27/80 Fix missing conditional assembly in FINDB routine.
- ; Put version number in sign-on message. (KBP)
- ;
- ;08/26/80 Modified by Keith Petersen, W8SDZ, to:
- ; (1) Add conditional assembly for 1k/2k groups
- ; (2) Add conditional assembly for standard drives
- ; and Micropolis MOD II
- ; (3) Make compatible with CP/M-2.x
- ; (4) Remove unneeded code to check for drive name
- ; (CP/M does it for you and returns it in the FCB)
- ; (5) Changed to open additional extents as needed for
- ; overflow, instead of additional files
- ; (6) Add conditional assembly for system tracks check
- ; (some double-density disks have single-density
- ; .
- ;
- ;08/06/80 Added comments and crunched some code.
- ; KELLY SMITH. 805-527-9321 (Modem, 300 Baud)
- ; 805-527-0518 (Verba files
- ; (6) Add conditional assembly for system tracks check
- ; (some double-density disks have single-density
- ; l)
- ;
- ;
- ; Using the Program
- ;
- ; Before using this program to "reclaim" a diskette, it is
- ;recommended that the diskette be reformatted. If this is not
- ;possible, at least assure yourself that any existing files
- ;on the diskette do not contain unreadable sectors. If you
- ;have changed disks since the last warm-boot, you must warm-
- ;boot again before running this program.
- ;
- ; To use the program, insert both the disk containing the
- ;program FINDBAD.CMD and the diskette to be checked into the
- ;disk drives. It is possible that the diskette containing the
- ;program is the one to be checked. Assume that the program is
- ;on drive "A" and the suspected bad disk is on drive "B". In
- ;response to the CP/M prompt "A>", type in FINDBAD B:. This
- ;will load the file FINDBAD.CMD from drive "A" and test the
- ;diskette on drive "B" for unreadable sectors. The only
- ;allowable parameter after the program name is a drive
- ;specification (of the form " N:") for up to four (A to D)
- ;disk drives. If no drive is specified, the currently logged
- ;in drive is assumed to contain the diskette to check.
- ;
- ; The program first checks the CP/M System tracks (0 and 1),
- ;and any errors here prohibit the disk from being used on
- ;drive "A", since all "warm boots" occur using the system
- ;tracks from the "A" drive.
- ;
- ; The program next checks the first two data blocks (groups
- ;to some of us) containing the directory of the diskette. If
- ;errors occur here, the program terminates and control
- ;returns to CP/M (no other data blocks are checked since
- ;errors in the directory render the disk useless).
- ;
- ; Finally, all the remaining data blocks are checked. Any
- ;sectors which are unreadable cause the data block which
- ;contains them to be stored temporarily as a "bad block". At
- ;the end of this phase, the message "XX bad blocks found" is
- ;d;contains them to be stored temporarily as a "bad block". At
- ;the end of this phase, the message "XX bad blocks found" is
- ;dname [UNUSED].BAD is created, the list of "bad blocks" is
- ;placed in the allocation map of the directory entry for
- ;[UNUSED].BAD, and the file is closed. Note, that when the
- ;number of "bad blocks" exceeds 16, the program will open
- ;additional extents as required to hold the overflow. I
- ;suggest that if the diskette has more than 32 "bad blocks",
- ;perhaps it should be sent to the "big disk drive in the sky"
- ;for the rest it deserves.
- ;
- ; The nifty part of all this is that if any "bad blocks" do
- ;occur, they are allocated to [UNUSED].BAD and no longer will
- ;be available to CP/M-86 for future allocation... bad sectors
- ;are logically locked out on the diskette
- ;
- ;
- ; Using the TEST conditional assembly
- ;
- ;A conditional assembly has been added to allow testing this
- ;program to make sure it is reading all sectors on your disk
- ;that are accessible to CP/M. The program reads the disk on a
- ;block by block basis, so it is necessary to first determine the
- ;number of blocks present. To start, we must know the number of
- ;sectors/block (8 sectors/block for standard IBM single density
- ;format). If this value is not known, it can easily be
- ;determined by saving one page in a test file and interrogating
- ;using the STAT command:
- ;
- ;For standard single-density STAT will report this file as being
- ;1k. The file size reported (in bytes) is the size of a block.
- ;This value divided by 128 bytes/sector (the standard CP/M
- ;sector size) will give sectors/block. For our IBM single
- ;density example, we have:
- ;
- ; (1024 bytes/block) / (128 bytes/sector) = 8 sectors/block.
- ;
- ;We can now calculate blocks/track (assuming we know the number
- ;sectors/track). In our example:
- ;
- ; (26 sectors/track) / (8 sectors/block) = 3.25 blocks/track
- ;
- ;Now armed with the total number of data tracks (75 in our IBM
- ;single density example), we get total blocks accessible:
- ;
- ; 75 (tracks/disk) x (3.25 blocks/track) = 243.75 blocks/disk
- ;
- ;CP/M cannot access a fractional block, so we round down (to 243
- ;blocks in our example). Now multiplying total blocks by
- ;sectors/block results in total sectors as should be reported
- ;when TEST is set TRUE and a good disk is read. For our example,
- ;this value is 1944 sectors.
- ;
- ;Finally, note that if SYSTEM is set TRUE, the sectors present
- ;on the first two tracks must be added in as well. In the
- ;previous example, this results in 1944 + 52 = 1996 sectors
- ;reported by the TEST conditional.
- ;
- ;Run the program on a KNOWN-GOOD disk. It should report that it
- ;has read the correct number of sectors. The test conditional
- ;assembly should then be set FALSE and the program re-assembled.
- ;The test routines cannot be left in because this program does
- ;not read all the sectors in a block that is found to be bad and
- ;thus will report an inaccurate number of sectors read.
- ;
- ;
- ;Define TRUE and FALSE
- ;
- FALSE EQU 0
- TRUE EQU NOT FALSE
- ;
- ;******************************************************************
- ;
- ;Conditional assembly switch for testing this program
- ;(for initial testing phase only - see remarks above)
- ;
- TEST EQU FALSE ;TRUE FOR TESTING ONLY
- ;
- ;******************************************************************
- ;
- ;System equates
- ;
- BASE EQU 0 ;STANDARD CP/M BASE ADDRESS
- FCB EQU BASE+5CH ;CP/M DEFAULT FCB LOCATION
- ;
- ;Define ASCII characters used
- ;
- CR EQU 0DH ;CARRIAGE RETURN CHARACTER
- LF EQU 0AH ;LINE FEED CHARACTER
- TAB EQU 09H ;TAB CHARACTER
- BEL EQU 07H ;BELL CHARACTER
- ;
- M EQU Byte Ptr 0[BX]
- ;
- cseg
- ORG BASE+100H
- ;
- JMPS START ;JMP AROUND OPTION BYTES
- ;
- ;If you want the system tracks tested, then put a 1 here, otherwise 0.
- ;
- SYSTST DB 0 ;0 IF NO SYS TRACKS, OTHERWISE 1
- ;
- ; Change this byte to the user number you want [UNUSED].BAD
- ;to reside in. If you want it in the default user, then leave
- ;it 0FFH.
- ;
- BADUSR DB 0FFH ;USER # WHERE [UNUSED.BAD] GOES
- ;0FFH = DEFAULT USER
- ;
- START: CALL START2 ;GO PRINT SIGNON
- ;
- DB CR,LF,'FINDBAD - Ver 1.0, Bad Sector Lockout Utility'
- DB CR,LF
- DB '------- Universal Version for CP/M-86 -------'
- DB CR,LF,CR,LF,'Type CTL-C to abort',CR,LF,'$'
- ;
- START2: POP DX ;GET MSG ADRS
- MOV CL,9 ;bdos PRINT BUFFER function
- NOBAD ;SAY NO BAD BLOCKS, IF SO
- CALL SETDM ;FIX DM BYTES IN FCB
- ;
- NOBAD: CALL CRLF
- MOV AL,TAB
- CALL DISPLAY
- MOV DX'
- DB CR,LF,CR,LF,'Type CTL-C to abort',CR,LF,'$'
- ;
- START2: POP DX ;GET MSG ADRS
- MOV CL,9 ;bdos PRINT BUFFER function
- ,(Offset NOMSG) ;POINT FIRST TO 'NO'
- MOV BX,Word Ptr BADBKS ;PICK UP # BAD BLOCKS
- MOV AL,BH ;CHECK FOR ZERO
- OR AL,BL
- JZ PMSG1 ;JUMP IF NONE
- CALL DECOUT ;OOPS..HAD SOME BAD ONES, REPORT
- JMPS PMSG2
- ;
- PMSG1: MOV CL,9 ;bdos PRINT BUFFER function
- INT 224
- ;
- PMSG2: MOV DX,(Offset ENDMSG) ;REST OF EXIT MESSAGE
- ;
- PMSG: MOV CL,9
- INT 224
- ;
- MOV CL,0 ;EXIT TO CP/M WARM BOOT
- MOV DL,0
- INT 224
- ;
- ;Get actual address of BIOS routines
- ;
- SETUP EQU $ ;Check for drive specification
- ;
- GDRIV: MOV AL,Byte Ptr .FCB ;GET DRIVE NAME
- MOV CL,AL
- OR AL,AL ;ZERO?
- JNZ GD2 ;IF NOT,THEN GO SPECIFY DRIVE
- MOV CL,25 ;GET LOGGED-IN DRIVE
- INT 224
- INC AL ;MAKE 1-RELATIVE
- MOV CL,AL
- ;
- GD2: CMP AL,15+1 ;CHECK FOR HIGHEST DRIVE NUMBER
- JNAE GD3
- JMP SELERR ;SELECT ERROR
- ;
- GD3: DEC CL ;BACK OFF FOR CP/M
- PUSH CX ;SAVE DISK SELECTION
- MOV DL,CL ;ALIGN FOR BDOS
- MOV CL,14 ;SELECT DISK function
- INT 224
- POP CX ;GET BACK DISK NUMBER
- ;
- SETDSK: MOV Byte Ptr FUNC,9 ;bios select disk function
- MOV Word Ptr BIOS_DESC,CX ;pass disk number to bios descriptor
- MOV Word Ptr BIOS_DESC+2,0 ;fill remaining descriptor (DX) zero
- MOV DX,(Offset FUNC) ;point to function parameter block
- MOV CL,50 ;direct bios call
- INT 224 ;do it, to it...
- ;
- MOV DL,ES: M ;GET SECTOR TABLE PNTR
- LAHF
- INC BX
- SAHF
- MOV DH,ES: M
- LAHF
- INC BX
- SAHF
- XCHG BX,DX
- MOV Word Ptr SECTBL,BX ;STORE IT AWAY
- MOV BX,8 ;OFFSET TO DPB POINTER
- LAHF
- ADD BX,DX
- RCR SI,1
- SAHF
- RCL SI,1
- MOV AL,ES: M ;PICK UP DPB POINTER
- LAHF ; TO USE
- INC BX
- SAHF
- MOV BH,ES: M ; AS PARAMETER
- MOV BL,AL ; TO LOGIT
- ;
- DOLOG: CALL LOGIT ;LOG IN DRIVE, GET DISK PARMS
- CALL GETDIR ;CALCULATE DIRECTORY INFORMATION
- ;
- ;
- HOMDSK: MOV Byte Ptr FUNC,8 ;bios HOME DISK function
- MOV Word Ptr BIOS_DESC,0 ;pass 'nothing' number to bios descriptor
- MOV Word PtrOV Byte Ptr FUNC,8 ;bios HOME DISK function
- MOV Word Ptr BIOS_DESC,0 ;pass 'nothing' number to bios descriptor
- MOV Word Ptrect bios call
- INT 224 ;do it, to it...
- ;
- ;Now set the required user number
- ;
- MOV AL,Byte Ptr BADUSR ;GET THE USER NUMBER
- CMP AL,0FFH ;IF IT IS 0FFH, THEN RETURN
- JNZ L_6
- RET
- L_6:
- MOV CL,32 ;GET/SET USER CODE
- INT 224
- RET
- ;
- ;Look for bad blocks
- ;
- FINDB: MOV AL,Byte Ptr SYSTST
- OR AL,AL
- JZ DODIR ;JUMP IF NO SYS TRACKS TO BE TESTED
- CALL CHKSYS ;CHECK FOR BAD BLOCKS ON TRACK 0 AND 1
- ;
- DODIR: CALL CHKDIR ;CHECK FOR BAD BLOCKS IN DIRECTORY
- CALL TELL1
- ;
- DB CR,LF,'Testing data area...',CR,LF,'$'
- ;
- TELL1: POP DX
- MOV CL,9 ;bdos PRINT STRING function
- INT 224
- CALL ERAB ;ERASE ANY [UNUSED].BAD FILE
- MOV BX,Word Ptr DIRBKS ;START AT FIRST DATA BLOCK
- MOV CX,BX ;PUT INTO [CX]
- ;
- FINDBA: CALL READB ;READ THE BLOCK
- JZ L_7
- CALL SETBD ;IF BAD, ADD BLOCK TO LIST
- L_7:
- LAHF ;BUMP TO NEXT BLOCK
- INC CX
- SAHF
- MOV BX,Word Ptr DSM
- MOV DX,CX ;SET UP FOR (MAXGRP - CURGRP)
- SBB BX,DX ;DO SUBTRACT: (MAXGRP - CURGRP)
- JNB FINDBA ;UNTIL CURGRP>MAXGRP
- CALL CRLF
- MOV BX,Word Ptr DMCNT ;GET NUMBER OF BAD SECTORS
- MOV AL,BH
- OR AL,BL ;SET ZERO FLAG, IF NO BAD BLOCKS
- RET ;RETURN FROM "FINDB"
- ;
- ;Check system tracks, notify user if bad, but continue
- ;
- CHKSYS: CALL CHSY1 ;bdos PRINT MESSAGE
- ;
- DB CR,LF,'Testing system tracks...',CR,LF,'$'
- ;
- CHSY1: POP DX
- MOV CL,9 ;bdos PRINT STRING function
- INT 224
- MOV BX,0 ;SET TRACK 0, SECTOR 1
- MOV Word Ptr TRACK,BX
- LAHF
- INC BX
- SAHF
- MOV Word Ptr SECTOR,BX
- ;
- CHKSY1: CALL READS ;READ A SECTOR
- JNZ SYSERR ;NOTIFY, IF BAD BLOCKS HERE
- MOV BX,Word Ptr SYSTRK ;SET UP (TRACK-SYSTRK)
- XCHG BX,DX
- MOV BX,Word Ptr TRACK
- SBB BX,DX ;DO THE SUBTRACT
- JB CHKSY1 ;LOOP WHILE TRACK < SYSTRK
- RET ;RETURN FROM "CHKSYS"
- ;
- SYSERR: MOV DX,(Offset ERMSG5) ;SAY NO GO, AND BAIL OUT
- MOV CL,9 ;bdos PRINT BUFFER function
- INT 224
- RET ;RETURN FROM "SYSERR"
- ;
- ;Check for bad blocks in directory area
- ;
- CHKDIR: CALL CHKD1
- ;
- DB CR,LF,'Testing directory area...',CR,LF,'$'
- ;
- CHKD1: POP DX
- MOV CL,9 ;bdos PRINT STRING function
- INT 224
- MOV CX,0 ;START AT BLOCK 0
- ;
- CHKDI1: CALL READB ;READ A BLOCK
- JZ L_8
- JMP ERROR6 ;IF BAD, INDICATE ERROR IN DIRECTORY AREA
- L_8:
- LAHF ;BUMP FOR NEXT BLOCK
- INC CX
- SAHF
- MOV BX,Word Ptr DIRBKS ;SET UP (CURGRP - DIRBKS)
- LAHF ;MAKE 0-RELATIVE
- DEC BX
- SAHF
- MOV DX,CX
- SBB BX,DX ;DO THE SUBTRACT
- JNB CHKDI1 ;LOOP UNTIL CURGRP > DIRGRP
- RET ;RETURN FROM "CHKDIR"
- ;
- ;Read all sectors in block, and return zero flag set if none bad
- ;
- READB: CALL CNVRTB ;CONVERT TO TRACK/SECTOR IN H&L REGS.
- MOV AL,Byte Ptr BLM
- INC AL ;NUMBER OF SECTORS/BLOCK
- MOV DH,AL ; IN D REG
- ;
- READBA: PUSH DX
- CALL READS ;READ SKEWED SECTOR
- POP DX
- JZ L_9
- RET ;ERROR IF NOT ZERO...
- L_9:
- DEC DH ;DEBUMP SECTOR/BLOCK
- JNZ READBA ;DO NEXT, IF NOT FINISHED
- RET ;RETURN FROM "READBA"
- ;
- ;Convert block number to track and skewed sector number
- ;
- CNVRTB: PUSH CX ;SAVE CURRENT GROUP
- MOV BX,CX ;NEED IT IN [BX], FOR EASY SHIFTING
- MOV AL,Byte Ptr BSH ;DPB VALUE THAT TELLS HOW TO
- ;
- SHIFT: SHL BX,1 ; SHIFT GROUP NUMBER TO GET
- DEC AL ; DISK-DATA-AREA RELATIVE
- JNZ SHIFT ; SECTOR NUMBER
- XCHG BX,DX ;REL SECTOR # INTO DE
- MOV BX,Word Ptr SPT ;SECTORS PER TRACK FROM DPB
- NOT BX ;1ST 1'S COMPLEMENT...
- INC BX ;...THEN 2'S COMPLEMENT
- XCHG BX,DX
- MOV CX,0 ;INITIALIZE QUOTIENT
- ;
- ;Divide by number of sectors
- ; quotient = track
- ; mod = sector
- ;
- DIVLP: LAHF ;DIRTY DIVISION
- INC CX
- SAHF
- LAHF
- ADD BX,DX
- RCR SI,1
- SAHF
- RCL SI,1
- JB DIVLP
- LAHF ;FIXUP LAST
- DEC CX
- SAHF
- XCHG BX,DX
- MOV BX,Word Ptr SPT
- LAHF
- ADD BX,DX
- SAHF
- LAHF
- INC BX
- SAHF
- MOV Word Ptr SECTOR,BX ;NOW HAVE LOGICAL SECTOR
- MOV BX,Word Ptr SYSTRK ;BUT BEFORE WE HAVE TRACK #,
- LAHF ; WE HAVE TO ADD SYS TRACK OFFSET
- ADD BX,CX
- RCR SI,1
- SAHF
- RCL SI,1
- MOV Word Ptr TRACK,BX
- POP CX ;THIS WAS OUR GROUP NUMBER
- RET
- ;
- ;READS reads a logical sector (if it can)
- ;and returns zero flag set if no error.
- ;
- READS: PUSH CX ;SAVE THE GROUP NUMBER
- ;
- CALL LTOP ;CONVERT LOGICAL TO PHYSICAL
- MOV BX,Word Ptr PHYSEC ;GET PHYSICAL SECTOR
- MOV CX,BX ;INTO [CX]
- ;
- SETSEC: MOV BYTE PTR FUNC,11 ;bios SET SECTOR function
- MOV WORD PX,(Offset FUNC) ;point to function parameter block
- MOV CL,50 ;direct bios call
- INT 224 ;do it, to it...
- ;
- MOV BX,WordPtr PHYSEC ;GET PHYSICAL SECTOR
- MOV CX,BX ;INTO [CX]
- ;
- SETSEC: MOV BYTE PTR FUNC,11 ;bios SET SECTOR function
- MOV WORD P Ptr TRACK ;NOW SET THE TRACK
- MOV CX,BX ;CP/M WANTS IT IN [CX]
- ;
- SETTRK: MOV BYTE PTR FUNC,10 ;bios SELECT TRACK function
- MOV WORD PTR BIOS_DESC,CX ;pass track number to bios descriptor
- MOV WORD PTR BIOS_DESC+2,0 ;fill remaining descriptor (DX) zero
- MOV DX,(Offset FUNC) ;point to function parameter block
- MOV CL,50 ;direct bios call
- INT 224 ;do it, to it...
- ;
- ;Now do the sector read
- ;
- DREAD: MOV BYTE PTR FUNC,13 ;bios READ SECTOR function
- MOV WORD PTR BIOS_DESC,0 ;pass 'nothing' number to bios descriptor
- MOV WORD PTR BIOS_DESC+2,0 ;fill remaining descriptor (DX) zero
- MOV DX,(Offset FUNC) ;point to function parameter block
- MOV CL,50 ;direct bios call
- INT 224 ;do it, to it...
- ;
- OR AL,AL ;SET FLAGS
- LAHF ;SAVE ERROR FLAG
- XCHG AL,AH
- PUSH AX
- MOV BX,Word Ptr SECTOR ;GET LOGICAL SECTOR #
- LAHF ;WE WANT TO INCREMENT TO NEXT
- INC BX
- SAHF
- XCHG BX,DX ;BUT FIRST...CHECK OVERFLOW
- MOV BX,Word Ptr SPT ; BY DOING (SECPERTRK-SECTOR)
- SBB BX,DX ;DO THE SUBTRACTION
- XCHG BX,DX
- JNB NOOVF ;JUMP IF NOT SECTOR>SECPERTRK
- ;
- ;Sector overflow...bump track number, reset sector
- ;
- MOV BX,Word Ptr TRACK
- LAHF
- INC BX
- SAHF
- MOV Word Ptr TRACK,BX
- MOV AL,'*' ;TELL CONSOLE ANOTHER TRACK DONE
- CALL DISPLAY
- CALL STOP ;SEE IF CONSOLE WANTS TO QUIT
- MOV BX,1 ;NEW SECTOR NUMBER ON NEXT TRACK
- ;
- NOOVF: MOV Word Ptr SECTOR,BX ;PUT SECTOR AWAY
- POP AX ;GET BACK ERROR FLAGS
- XCHG AL,AH
- SAHF
- POP CX ;RESTORE GROUP NUMBER
- RET
- ;
- ;Convert logical sector # to physical
- ;
- LTOP: MOV BX,Word Ptr SECTBL ;SET UP PARAMETERS
- XCHG BX,DX ; FOR CALL TO SECTRAN
- MOV BX,Word Ptr SECTOR
- MOV CX,BX
- DEC CX ;ALWAYS CALL SECTRAN W/ZERO-REL SEC #
- ;
- SECT1: CALL SECTRN ;DO THE SECTOR TRANSLATION
- MOV AL,Byte Ptr SPT+1 ;CHECK IF BIG TRACKS
- OR AL,AL ;SET FLAGS (TRACKS > 256 SECTORS)
- JNZ LTOP1 ;NO SO SKIP
- MOV BH,AL ;ZEROByte Ptr SPT+1 ;CHECK IF BIG TRACKS
- OR AL,AL ;SET FLAGS (TRACKS > 256 SECTORS)
- JNZ LTOP1 ;NO SO SKIP
- MOV BH,AL ;ZEROOV BYTE PTR FUNC,16 ;bios SECTOR TRANSLATE function
- MOV WORD PTR BIOS_DESC,CX ;pass sector to bios descriptor
- MOV WORD PTR BIOS_DESC+2,DX ;translate table offset
- MOV DX,(Offset FUNC) ;point to function parameter block
- MOV CL,50 ;direct bios call
- INT 224 ;do it, to it...
- ret ;return from 'sectrn'
- ;
- ;Put bad block in bad block list
- ;
- SETBD: PUSH CX
- CALL SETBD1
- DB CR,LF,BEL,'Bad block: $'
- ;
- SETBD1: POP DX ;RETRIEVE ARG
- MOV CL,9 ;bdos PRINT STRING
- INT 224
- POP CX ;GET BACK BLOCK NUMBER
- MOV AL,CH
- CALL HEXO ;bdos PRINT IN HEX
- MOV AL,CL
- CALL HEXO
- CALL CRLF
- MOV BX,Word Ptr DMCNT ;GET NUMBER OF SECTORS
- MOV AL,Byte Ptr BLM ;GET BLOCK SHIFT VALUE
- INC AL ;MAKES SECTOR/GROUP VALUE
- MOV DL,AL ;WE WANT 16 BITS
- MOV DH,0
- ADD BX,DX ;BUMP BY NUMBER IN THIS BLOCK
- MOV Word Ptr DMCNT,BX ;UPDATE NUMBER OF SECTORS
- MOV BX,Word Ptr BADBKS ;INCREMENT NUMBER OF BAD BLOCKS
- INC BX
- MOV Word Ptr BADBKS,BX
- MOV BX,Word Ptr DMPTR ;GET POINTER INTO DM
- MOV M,CL ;...AND PUT BAD BLOCK NUMBER
- INC BX ;BUMP TO NEXT AVAILABLE EXTENT
- MOV AL,Byte Ptr DSM+1 ;CHECK IF 8 OR 16 BIT BLOCK SIZE
- OR AL,AL
- JZ SMGRP ;JUMP IF 8 BIT BLOCKS
- MOV M,CH ;ELSE STORE HI BYTE OF BLOCK #
- LAHF ;AND BUMP POINTER
- INC BX
- SAHF
- ;
- SMGRP: MOV Word Ptr DMPTR,BX ;SAVE DM POINTER, FOR NEXT TIME THROUGH HERE
- RET ;RETURN FROM "SETBD"
- ;
- ;Eliminate any previous [UNUSED].BAD entries
- ;
- ERAB: MOV DX,(Offset BFCB) ;POINT TO BAD FCB
- MOV CL,19 ;bdos DELETE FILE function
- INT 224
- RET
- ;
- ;Create [UNUSED].BAD file entry
- ;
- OPENB: MOV DX,(Offset BFCB) ;POINT TO BAD FCB
- MOV CL,22 ;bdos MAKE FILE function
- INT 224
- CMP AL,0FFH ;CHECK FOR OPEN ERROR
- JZ L_10
- RET ;RETURN FROM "OPENB", IF NO ERROR
- L_10:
- JMP ERROR7 ;BAIL OUT...CAN'T CREATE [UNUSED].BAD
- ;
- CLOSEB: XOR AL,AL
- MOV AL,Byte Ptr BFCB+14 ;GET CP/M 'S2' BYTE
- AND AL,1FH ;ZERO UPDATE FLAGS
- MOV Byte Ptr BFCB+14,AL ;RESTORE IT TO OUR FCB
- MOV DX,(Offset BFCB) ;FCB FOR [UNUSED].BAD
- MOV CL,16 ;bdos CLOSE FILE function
- INT 224
- RET ;RETURN FROM "CLOSEB"
- ;
- ;Move bad area DM to BFCB
- ;
- SETDM: MOV BX,(Offset DM) ;GET DM
- MOV Word Ptr DMPTR,BX ;SAVE AS NEW POINTER
- MOV AL,Byte Ptr EXM ;GET THE EXTENT SHIFT FACTOR
- MOV CL,0 ;INIT BIT COUNT
- CALL COLECT ;GET SHIFT VALUE
- MOV BX,128 ;STARTING EXTENT SIZE
- MOV AL,CL ;FIRST SEE IF ANY SHIFTS TO DO
- OR AL,AL
- JZ NOSHFT ;JUMP IF NONE
- ;
- ESHFT: SHL BX,1 ;SHIFT
- DEC AL ;BUMP
- JNZ ESHFT ;LOOP
- ;
- NOSHFT: PUSH BX ;SAVE THIS, IT IS RECORDS PER EXTENT
- MOV AL,Byte Ptr BSH ;GET BLOCK SHIFT
- MOV CH,AL
- ;
- BSHFT: CLC ;CLEAR CARRY FLAG
- RCR BX,1 ;SHIFT RIGHT
- DEC CH
- JNZ BSHFT ;TO GET BLOCKS PER EXTENT
- MOV AL,BL ;IT'S IN [BL] (CAN'T BE >16)
- MOV Byte Ptr BLKEXT,AL ;SET BLOCK EXTENT, WILL NEED THIS LATER
- POP BX ;GET BACK REC/EXT
- ;
- SET1: XCHG BX,DX ;NOW HAVE REC/EXTENT IN [DX]
- MOV BX,Word Ptr DMCNT ;COUNT OF BAD SECTORS
- ;
- SETDMO: PUSH BX ;SET FLAGS ON (DMCNT-BADCNT)
- SBB BX,DX ;HAVE TO SUBTRACT FIRST
- MOV CX,BX ;SAVE RESULT IN [CX]
- POP BX ;THIS POP MAKES IT COMPARE ONLY
- JB SETDME ;JUMP IF LESS THAN 1 EXTENT WORTH
- MOV AL,CH
- OR AL,CL ;TEST IF SUBTRACT WAS 0
- JZ EVENEX ;EXTENT IS EXACTLY FILLED (SPL CASE)
- MOV BX,CX ;RESTORE RESULT TO [BX]
- PUSH BX ;SAVE TOTAL
- PUSH DX ;AND SECTORS/EXTENT
- XCHG BX,DX
- CALL SETDME ;PUT AWAY ONE EXTENT
- XCHG BX,DX
- MOV Word Ptr DMPTR,BX ;PUT BACK NEW DM POINTER
- POP DX ;GET BACK SECTORS/EXTENT
- POP BX ;AND COUNT OF BAD SECTORS
- JMPS SETDMO ;AND LOOP
- ;
- ;Handle the special case of a file that ends on an extent
- ;boundary. CP/M requires that such a file have a succeeding
- ;empty extent in order for the BDOS to properly access the file.
- ;
- EVENEX: XCHG BX,DX ;FIRST SET EXTENT W/BAD BLOCKS
- CALL SETDME
- XCHG BX,DX
- MOV Word Ptr DMPTR,BX
- MOV BX,0 ;NOW SET ONE WITH NO DATA BLOCKS
- ;
- ;Fill in an extent's worth of bad sectors/block numbers.
- ;Also fill in the extent number in the FCB.
- ;
- SETDME: PUSH BX ;SAVE RECORD COUNT
- MOV AL,Byte Ptr EXTNUM ;UPDATE EXTENT BYTE
- INC AL
- MOV Byte Ptr EXTNUM,AL ;SAVE FOR LATER
- MOV Byte Ptr BFCB+12,AL ; AND PUT IN FCB
- CALL OPENB ;OPEN THIS EXTENT
- POP BX ;RETRIEVE REC COUNT
- ;
- ;Divide record count by 128 to get the number
- ;of l
- OR AL,BL ; OF NO RECORDS
- JZ SKIP
- ;
- DIVLOP: ADD BX,DX ;SUBTRACT
- INC CH ;BUMP QUOTIENT
- JB DIVLOP
- MOV DX,128 ; IN FCB
- CALL OPENB ;OPEN THIS EXTENT
- POP BX ;RETRIEVE REC COUNT
- ;
- ;Divide record count by 128 to get the number
- ;of lFIX UP OVERSHOOT
- ADD BX,DX
- DEC CH
- MOV AL,BH ;TEST FOR WRAPAROUND
- OR AL,BL
- JNZ SKIP
- MOV BL,80H ;RECORD LENGTH
- DEC CH
- ;
- SKIP: MOV AL,Byte Ptr EXTNUM ;NOW FIX UP EXTENT NUM
- ADD AL,CH
- MOV Byte Ptr EXTNUM,AL
- MOV Byte Ptr BFCB+12,AL
- MOV AL,BL ;MOD IS RECORD COUNT
- MOV Byte Ptr BFCB+15,AL ;THAT GOES IN RC BYTE
- ;
- MOVDM: MOV AL,Byte Ptr BLKEXT ;GET BLOCKS PER EXTENT
- MOV CH,AL ;INTO B
- ;
- SETD1: MOV BX,Word Ptr DMPTR ;POINT TO BAD ALLOCATION MAP
- XCHG BX,DX
- MOV BX,(Offset BFCB)+16 ;DISK ALLOC MAP IN FCB
- ;
- SETDML: MOV SI,DX
- MOV AL,[SI]
- MOV M,AL
- INC BX
- INC DX
- ;
- ;Now see if 16 bit groups...if so,
- ;we have to move another byte
- ;
- MOV AL,Byte Ptr DSM+1 ;THIS TELLS US
- OR AL,AL
- JZ BUMP1 ;IF ZERO, THEN NOT
- MOV SI,DX ;IS 16 BITS, SO DO ANOTHER
- MOV AL,[SI]
- MOV M,AL
- LAHF
- INC BX
- SAHF
- LAHF
- INC DX
- SAHF
- ;
- BUMP1: DEC CH ;COUNT DOWN
- JNZ SETDML
- PUSH DX
- CALL CLOSEB ;CLOSE THIS EXTENT
- POP DX
- RET
- ;
- ;Error messages
- ;
- SELERR: MOV DX,(Offset SELEMS) ;SAY NO GO, AND BAIL OUT
- JMP PMSG
- ;
- SELEMS DB CR,LF,'Drive specifier out of range$'
- ;
- ERMSG5 DB CR,LF,BEL,'+++ Warning...System tracks'
- DB ' bad +++',CR,LF,CR,LF,'$'
- ;
- ERROR6: MOV DX,(Offset ERMSG6) ;OOPS...CLOBBERED DIRECTORY
- JMP PMSG
- ;
- ERMSG6 DB CR,LF,BEL,'Bad directory area, try reformatting$'
- ;
- ERROR7: MOV DX,(Offset ERMSG7) ;SAY NO GO, AND BAIL OUT
- JMP PMSG
- ;
- ERMSG7 DB CR,LF,'Can''t create [UNUSED].BAD$'
- ;
- ;
- ;==== SUBROUTINES ====
- ;
- ;Decimal output routine
- ;
- DECOUT: PUSH CX
- PUSH DX
- PUSH BX
- MOV CX,-10
- MOV DX,-1
- ;
- DECOU2: ADD BX,CX
- INC DX
- JB DECOU2
- MOV CX,10
- ADD BX,CX
- XCHG BX,DX
- MOV AL,BH
- OR AL,BL
- JZ L_17
- CALL DECOUT
- L_17:
- MOV AL,DL
- ADD AL,'0'
- CALL DISPLAY
- POP BX
- POP DX
- POP CX
- RET
- ;
- ;Carriage-return/line-feed to console
- ;
- CRLF: MOV AL,CR
- CALL DISPLAY
- MOV AL,LF ;FALL INTO 'DISPLAY'
- ;
- DISPLAY:PET
- ;
- ;Carriage-return/line-feed to console
- ;
- CRLF: MOV AL,CR
- CALL DISPLAY
- MOV AL,LF ;FALL INTO 'DISPLAY'
- ;
- DISPLAY:P PRINT CHARACTER
- POP BX
- POP DX
- POP CX
- RET
- ;
- ;Subroutine to test console for control-c abort
- ;
- STOP: MOV BYTE PTR FUNC,2 ;BIOS CONSOLE STATUS FUNCTION
- MOV WORD PTR BIOS_DESC,0 ;PASS 'NOTHING' NUMBER TO BIOS DESCRIPTOR
- MOV WORD PTR BIOS_DESC+2,0 ;FILL REMAINING DESCRIPTOR (DX) ZERO
- MOV DX,(OFFSET FUNC) ;POINT TO FUNCTION PARAMETER BLOCK
- MOV CL,50 ;direct bios call
- INT 224 ;do it, to it...
- ;
- OR AL,AL ;TEST FLAGS ON ZERO
- JNZ L_18
- RET ;RETURN IF NO CHAR
- L_18: MOV BYTE PTR FUNC,3 ;BIOS READ CONSOLE CHARACTER FUNCTION
- MOV WORD PTR BIOS_DESC,0 ;PASS 'NOTHING' NUMBER TO BIOS DESCRIPTOR
- MOV WORD PTR BIOS_DESC+2,0 ;FILL REMAINING DESCRIPTOR (DX) ZERO
- MOV DX,(OFFSET FUNC) ;POINT TO FUNCTION PARAMETER BLOCK
- MOV CL,50 ;direct bios call
- INT 224 ;do it, to it...
- ;
- CMP AL,'C'-40H ;IS IT CONTROL-C?
- JZ L_19
- RET ;RETURN IF NOT
- L_19:
- MOV DX,(Offset ABORTM) ;EXIT WITH MESSAGE
- JMP PMSG
- ;
- ABORTM DB CR,LF
- DB 'Test aborted by control-C'
- DB CR,LF,'$'
- ;
- ;Move from [BX] to [DX], Count in [CX]
- ;
- MOVE: MOV AL,ES: M
- MOV SI,DX
- MOV [SI],AL
- LAHF
- INC BX
- SAHF
- LAHF
- INC DX
- SAHF
- DEC CH
- JNZ MOVE
- RET
- ;
- ;Print byte in accumulator in hex
- ;
- HEXO: LAHF ;SAVE FOR SECOND HALF
- XCHG AL,AH
- PUSH AX
- XCHG AL,AH
- ROR AL,1 ;MOVE INTO POSITION
- ROR AL,1
- ROR AL,1
- ROR AL,1
- CALL NYBBLE ;bdos PRINT MS NYBBLE
- POP AX
- XCHG AL,AH
- ;
- NYBBLE: AND AL,0FH ;LO NYBBLE ONLY
- ADD AL,90H
- DAA
- ADC AL,40H
- DAA
- JMP DISPLAY ;bdos PRINT IN HEX
- ;
- ;Subroutine to determine the number
- ;of groups reserved for the directory
- ;
- GETDIR: MOV CL,0 ;INIT BIT COUNT
- MOV AL,Byte Ptr AL0 ;READ DIR GRP BITS
- CALL COLECT ;COLLECT COUNT OF DIR GRPS..
- MOV AL,Byte Ptr AL1 ;..IN REGISTER [CL]
- CALL COLECT
- MOV BL,CL
- MOV BH,0 ;[CX] NOW HAS A DEFAULT START GRP #
- MOV Word Ptr DIRBKS,BX ;SAVE FOR LATER
- RET
- ;
- ;Collect the number of '1' bits in A as a count in [CL]
- ;
- COLECT: MOV CH,8
- ;
- COLOP: RCL AL,1
- JNB COSKIP
- INC CL
- ;
- COSKIP: DEC CH
- JNZ COLOP
- RET
- ;
- ;Routine to fill in disk parameters
- ;
- LOGIT: MOV DX,(Offset DPB) ; THEN MOVE TO LOCAL
- MOV CH,(Offset DPBLEN) ; WORKSPACE
- CALL MOVE
- RET
- ;
- L_22 EQU $
- dseg $
- ORG Offset L_22
- ;
- ;--------------------------------------------------
- ;The disk parameter block is moved here from CP/M-86
- ;
- DPB EQU (Offset $) ;DISK PARAMETER BLOCK (COPY)
- ;
- SPT RS 2 ;SECTORS PER TRACK
- BSH RS 1 ;BLOCK SHIFT
- BLM RS 1 ;BLOCK MASK
- EXM RS 1 ;EXTENT MASK
- DSM RS 2 ;MAXIMUM BLOCK NUMBER
- DRM RS 2 ;MAXIMUM DIRECTORY BLOCK NUMBER
- AL0 RS 1 ;DIRECTORY ALLOCATION VECTOR
- AL1 RS 1 ;DIRECTORY ALLOCATION VECTOR
- CKS RS 2 ;CHECKED DIRECTORY ENTRIES
- SYSTRK RS 2 ;SYSTEM TRACKS
- ;
- ;End of disk parameter block
- ;
- DPBLEN EQU (Offset $)-(Offset DPB) ;LENGTH OF DISK PARM BLOCK
- ;
- ;--------------------------------------------------
- BLKEXT DB 0 ;BLOCKS PER EXTENT
- DIRBKS DW 0 ;CALCULATED # OF DIR BLOCKS
- ;
- BFCB DB 0,'[UNUSED]BAD',0,0,0,0
- FCBDM RS 17
- ;
- NOMSG DB 'No$'
- ENDMSG DB ' bad blocks found',CR,LF,'$'
- ;
- BADBKS DW 0 ;COUNT OF BAD BLOCKS
- SECTOR DW 0 ;CURRENT SECTOR NUMBER
- TRACK DW 0 ;CURRENT TRACK NUMBER
- PHYSEC DW 0 ;CURRENT PHYSICAL SECTOR NUMBER
- SECTBL DW 0 ;SECTOR SKEW TABLE POINTER
- ;
- EXTNUM DB 0FFH ;USED FOR UPDATING EXTENT NUMBER
- DMCNT DW 0 ;NUMBER OF BAD SECTORS
- DMPTR DW (Offset DM) ;POINTER TO NEXT BLOCK ID
- ;
- ;storage for 5 byte BIOS function descriptor
- ;
- FUNC RS 1 ;bios function code goes here
- BIOS_DESC RS 2 ;[CX] data goes here
- RS 2 ;[DX] data goes here
- ;
- DM EQU (Offset $) ;BAD BLOCK ALLOCATION MAP
- ;
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 E 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- DW 0 ;RESERVE 2 BYTES
- ;
- END
-