home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol016
/
findbd42.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
33KB
|
1,148 lines
; FINDBAD.ASM ver. 4.2
; (revised 02/05/81)
;
;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 will not use them.
;
;Originally written by Gene Cotton, published in "Interface
;Age", September 1980 issue, page 80.
;
;This program now supports the following disk drives:
;
; - STANDARD 8" SINGLE DENSITY
; - MICROPOLIS MOD II
; - MICROMATION DOUBLE DENSITY
; - DIGITAL MICROSYSTEMS FDC3 DBL DENS
; - IMSAI DOUBLE DENSITY (IMDOS)
; - DISCUS 2D (SINGLE SIDED) 256/512/1024 BYTE SECTORS
; - NATIONAL MULTIPLEX DD 1/2 SIDED 256/512 BYTE SECTORS
; - HEATH H-17 5.25" SINGLE SIDED SINGLE DENSITY
; - ICOM MICROFLOPPY 5.25" SINGLE SIDED, SINGLE DENSITY
; - JADE DOUBLE DENSITY/SINGLE SIDED
; - NORTH STAR HORIZON DOUBLE DENSITY, SINGLE OR DOUBLE SIDED
;
;As presently set up, this program will perform properly on an
;8" single-density soft-sectored disk recorded in standard IBM
;format (i.e., 77 tracks, 26 sectors/track, 243 blocks/disk, 8
;sectors/block, 128 bytes/sector). If your disk is not an IBM
;8" standard, then you must set the conditional assembly
;switches to one of the defined disk systems or modify the
;existing disk parameter definitions according to the
;guidelines established in this documentation. See notes
;below concerning 'TEST' conditional assembly option.
;
;NOTE: If you want to add conditional assembly for other disk
;systems, or otherwise update this program, make sure you have
;the latest version first. After adding your changes, please
;modem a copy of the new file to "TECHNICAL CBBS" in Dearborn,
;Michigan - phone 313-846-6127 (110, 300, 450 or 600 baud).
;Use the filename FINDBAD.NEW. (KBP)
;
;Revisions/modifications: (listed in reverse order
;to minimize reading time)
;
;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
; system tracks which cannot be read by this program)
; (7) Increased stack area (some systems use more than
; others).
;
;08/06/80 Added comments and crunched some code.
; KELLY SMITH. 805-527-9321 (Modem, 300 Baud)
; 805-527-0518 (Verbal)
;
;
; 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.COM 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.COM 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
;displayed (where XX is replaced by the number of bad blocks,
;or "No" if no read errors occur). If bad blocks occur, the
;filname [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 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:
;
; A>SAVE 1 TEST.SIZ
; A>STAT TEST.SIZ
;
;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
;of 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 toatal 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 switches (only one should be true)
STDDRV EQU TRUE ;TRUE IF STANDARD 8" SINGLE DENSITY DRIVE
MICROP EQU FALSE ;TRUE IF MICROPOLIS MOD II
MMDBL EQU FALSE ;TRUE IF MICROMATION DOUBLE DENSITY
DIGDBL EQU FALSE ;TRUE IF DIGITAL MICROSYSTEMS FDC3 DBL DENS
IMDOS EQU FALSE ;TRUE IF IMSAI DOUBLE DENSITY
DJ256S EQU FALSE ;TRUE IF MORROW 2D/SS (256-BYTE SECTOR)
DJ512S EQU FALSE ;TRUE IF MORROW 2D/SS (512-BYTE SECTOR)
DJ1024 EQU FALSE ;TRUE IF MORROW 2D/SS (1024-BYTE SECTOR)
NM256 EQU FALSE ;TRUE IF NATMUX 2D (256-BYTE SECTOR)
NM512 EQU FALSE ;TRUE IF NATMUX 2D (512-BYTE SECTOR)
H17 EQU FALSE ;TRUE IF HEATH H-17 5.25" SGL. DENS.
ICOM EQU FALSE ;TRUE IF ICOM MICROFLOPPY
JADEDD EQU FALSE ;TRUE IF JADE DD DISK CONTROLLER
HORIZON EQU FALSE ;TRUE IF NORTH STAR HORIZON
;******************************************************************
;
;Conditional assembly switch for double-sided drives
;(presently supported for National Multiplex and Horizon only)
;
SIDES2 EQU FALSE ;TRUE FOR NATMUX D3S/D4S OR HORIZON DOUBLE SIDED ONLY
;
;******************************************************************
;
;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 (4200H FOR ALTCPM)
BDOS EQU BASE+5 ;CP/M WARM BOOT ENTRY
FCB EQU BASE+5CH;CP/M DEFAULT FCB LOCATION
;
;Define disk system parameters
;
IF STDDRV
SYSTEM EQU TRUE ;TRUE IF CHECK SYSTEM TRACKS WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 26 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 243 ;MAX NUMBER OF BLOCKS (including directory)
BLOCK EQU 8 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU FALSE ;TRUE IF 2k GROUP SIZE
ENDIF ;STDDRV
;
IF MICROP
SYSTEM EQU TRUE ;TRUE IF CHECK SYSTEM TRACKS WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 32 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 150 ;MAX NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;MICROP
;
IF MMDBL
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 52 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK FOR DATA
MAXB EQU 243 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;MMDBL
;
IF DIGDBL
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 58 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 256 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;DIGDBL
;
IF IMDOS
SYSTEM EQU FALSE ;TRUE IF CHECK SYSTEM TRACKS WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 58 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 271 ;MAX NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;IMDOS
;
IF DJ256S OR NM256 AND NOT SIDES2
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 52 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 243 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;MORROW DJ256S OR NM256
;
IF DJ512S OR NM512 AND NOT SIDES2
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 60 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 281 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;MORROW DJ512S OR NM512
;
IF DJ1024
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 64 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 300 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;MORROW DJ1024
;
IF NM256 AND SIDES2
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 * 2 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 52 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 487 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;MORROW DJ256S OR NM256
;
IF NM512 AND SIDES2
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 * 2 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 60 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 281 * 2 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;MORROW DJ512S OR NM512
;
IF H17
SYSTEM EQU TRUE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 40 ;NUMBER OF TRACKS/DISK
SECTS EQU 20 ;NUMBER OF SECTS/TRACK
DBASE EQU 3 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 1 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 92 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 8 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU FALSE ;TRUE IF 2k GROUP SIZE
ENDIF ;H17
;
IF ICOM
SYSTEM EQU TRUE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 35 ;NUMBER OF TRACKS/DISK
SECTS EQU 18 ;NUMBER OF SECTS/TRACK
DBASE EQU 3 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 72 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 8 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU FALSE ;TRUE IF 2k GROUP SIZE
ENDIF ;ICOM
;
IF JADEDD
SYSTEM EQU FALSE ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
TRACKS EQU 77 ;NUMBER OF TRACKS/DISK
SECTS EQU 50 ;NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 233 ;MAXIMUM NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;JADEDD
;
IF HORIZON AND NOT SIDES2
SYSTEM EQU TRUE ;TRUE IF CHECK SYSTEM TRACKS WANTED
TRACKS EQU 35 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 40 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 165 ;MAX NUMBER OF BLOCKS (including directory)
BLOCK EQU 8 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU FALSE ;TRUE IF 2k GROUP SIZE
ENDIF ;HORIZON
;
IF HORIZON AND SIDES2
SYSTEM EQU TRUE ;TRUE IF CHECK SYSTEM TRACKS WANTED
TRACKS EQU 70 ;TOTAL NUMBER OF TRACKS/DISK
SECTS EQU 40 ;TOTAL NUMBER OF SECTORS/TRACK
DBASE EQU 2 ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
BBASE EQU 2 ;FIRST BLOCK NUMBER FOR DATA
MAXB EQU 170 ;MAX NUMBER OF BLOCKS (including directory)
BLOCK EQU 16 ;NUMBER OF SECTORS/BLOCK
DGROUP EQU TRUE ;TRUE IF 2k GROUP SIZE
ENDIF ;HORIZON
;
;Define ASCII characters used
;
CR EQU 0DH ;CARRIAGE RETURN CHARACTER
LF EQU 0AH ;LINE FEED CHARACTER
TAB EQU 09H ;TAB CHARACTER
;
;
ORG BASE+100H
;
START: LXI SP,NEWSTK ;MAKE NEW STACK
;
IF IMDOS
XRA A
OUT 0FFH ;CLEAR FRONT PANEL
ENDIF ;IMDOS
;
LXI D,IDMSG ;IDENT MESSAGE
CALL START2 ;GO PRINT IT
;
IDMSG: DB CR,LF,'FINDBAD - ver 4.2'
DB CR,LF,'Bad sector lockout '
DB 'program',CR,LF
;
IF STDDRV
DB 'For single-density 8"'
ENDIF
;
IF MICROP
DB 'For Micropolis Mod II'
ENDIF
;
IF MMDBL
DB 'For Micromation double-density'
ENDIF
;
IF DIGDBL
DB 'For Digital Microsystems',CR,LF
DB 'FDC3 cntlr dbl dens'
ENDIF
;
IF IMDOS
DB 'For IMSAI IMDOS double-density'
ENDIF
;
IF DJ256S
DB 'For Discus 2-dens./1-side/256-byte sectors'
ENDIF
;
IF DJ512S
DB 'For Discus 2-dens./1-side/512-byte sectors'
ENDIF
;
IF DJ1024
DB 'For Discus 2-dens./1-side/1024-byte sectors'
ENDIF
;
IF NM256 OR NM512
DB 'For National Multiplex double density'
ENDIF
;
IF HORIZON
DB 'For North Star Horizon - 5.25" drives, double density,'
ENDIF
;
IF SIDES2 AND (NM256 OR NM512 OR HORIZON)
DB ' double sided'
ENDIF
;
IF NOT SIDES2 AND (NM256 OR NM512 OR HORIZON)
DB ' single sided'
ENDIF
;
IF NM256
DB ' 256-byte sectors'
ENDIF
;
IF NM512
DB ' 512-byte sectors'
ENDIF
;
IF H17
DB 'For Heath H-17 5.25" drives'
ENDIF
;
IF ICOM
DB 'For ICOM Microfloppy'
ENDIF
;
IF JADEDD
DB 'For Jade Double Density/Single Sided'
ENDIF
;
DB ' only.',CR,LF,'$'
;
START2 POP D ;GET MSG ADRS
MVI C,9 ;BDOS PRINT BUFFER FUNCTION
CALL BDOS ;PRINT SIGN-ON MSG
CALL IBIOS ;SET BIOS ENTRY, AND CHECK DRIVE
CALL FINDB ;ESTABLISH ALL BAD BLOCKS
JZ NOBAD ;SAY NO BAD BLOCKS, IF SO
CALL OPENB ;OPEN [UNUSED].BAD ALLOCATION
CALL SETDM ;FIX DM BYTES IN FCB
CALL CLOSEB ;CLOSE [UNUSED].BAD
CALL SETNUM ;PUT NUMBER OF BAD BLOCKS IN MESSAGE
;
NOBAD: LXI D,ENDMSG ;SAY HOW MANY BAD BLOCKS
;
PMSG: MVI C,9 ;BDOS PRINT BUFFER FUNCTION
CALL BDOS
;
IF TEST
MVI A,TAB ;GET A TAB
CALL TYPE ;PRINT IT
LHLD SECCNT ;GET NUMBER OF SECTORS READ
CALL DECOUT ;PRINT IT
LXI D,SECMSG ;POINT TO MESSAGE
MVI C,9 ;BDOS PRINT BUFFER FUNCTION
CALL BDOS ;PRINT IT
ENDIF ;TEST
;
IF IMDOS
XRA A
OUT 0FFH ;CLEAR FRONT PANEL
ENDIF ;IMDOS
;
JMP BASE ;EXIT TO CP/M WARM BOOT
;
;Get actual address of BIOS routines
;
IBIOS: LHLD BASE+1 ;GET BASE ADDRESS OF BIOS VECTORS
;
;WARNING...Program modification takes place here...do not change.
;
LXI D,27 ;OFFSET TO "SETTRK"
DAD D
SHLD SETTRK+1 ;FIX OUR CALL ADDRESS
LXI D,3 ;OFFSET TO "SETSEC"
DAD D
SHLD SETSEC+1 ;FIX OUR CALL ADDRESS
LXI D,6 ;OFFSET TO "DREAD"
DAD D
SHLD DREAD+1 ;FIX OUR CALL ADDRESS
;
;Check for drive specification
;
LDA FCB ;GET DRIVE NAME
ORA A ;ZERO?
RZ ;YES, NO DRIVE CHANGE REQUIRED
CPI 4+1 ;CHECK FOR HIGHEST DRIVE NUMBER
JNC ERROR4
DCR A ;BACK OFF FOR CP/M
MOV E,A ;MAKE DISK NUMBER
MVI C,14 ;BDOS SELECT DISK FUNCTION
CALL BDOS
RET ;RETURN FROM "IBIOS"
;
;Look for bad blocks
;
FINDB: EQU $
;
IF SYSTEM
CALL CHKSYS ;CHECK FOR BAD BLOCKS ON TRACK 0 AND 1
ENDIF ;SYSTEM
;
CALL CHKDIR ;CHECK FOR BAD BLOCKS IN DIRECTORY
CALL ERAB ;ERASE ANY [UNUSED].BAD FILE
LXI B,BBASE ;START AT FIRST DATA BLOCK
;
FINDBA: CALL READB ;READ THE BLOCK
CNZ SETBD ;IF BAD, ADD BLOCK TO LIST
INX B ;BUMP TO NEXT BLOCK
MOV A,C ;SEE IF MORE TO CHECK
CPI MAXB AND 0FFH
JNZ FINDBA
MOV A,B ;THEN CHECK HI BYTE
CPI MAXB SHR 8
JNZ FINDBA ;LOOP TILL DONE
LHLD DMCNT ;GET NUMBER OF BAD SECTORS
MOV A,H
ORA L ;SET ZERO FLAG, IF NO BAD BLOCKS
RET ;RETURN FROM "FINDB"
;
IF SYSTEM
;
;Check system tracks, notify user if bad, but continue
;
CHKSYS: LXI H,1 ;SET TRACK 0, SECTOR 1
;
CHKSY1: CALL READS ;READ A SECTOR
JNZ SYSERR ;NOTIFY, IF BAD BLOCKS HERE
MOV A,H ;BOTH SYSTEM TRACKS DONE?
CPI DBASE
JC CHKSY1
RET ;RETURN FROM "CHKSYS"
;
SYSERR: LXI D,ERMSG5 ;SAY NO GO, AND BAIL OUT
MVI C,9 ;BDOS PRINT BUFFER FUNCTION
CALL BDOS
RET ;RETURN FROM "SYSERR"
;
ENDIF ;SYSTEM
;
;Check for bad blocks in directory area
;
CHKDIR: LXI B,0 ;START AT BLOCK 0
;
CHKDI1: CALL READB ;READ A BLOCK
JNZ ERROR6 ;IF BAD, INDICATE ERROR IN DIRECTORY AREA
INX B ;BUMP FOR NEXT BLOCK
MOV A,C ;GET BLOCK NUMBER
CPI BBASE ;ALL DONE CHECKING DIRECTORY AREA?
JC CHKDI1 ;PRESS ON, IF NOT
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.
MVI D,BLOCK ;NUMBER OF SECTORS/BLOCK
;
READBA: PUSH D
CALL READS ;READ SKEWED SECTOR
POP D
RNZ ;ERROR IF NOT ZERO...
DCR D ;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 B ;SAVE BLOCK NUMBER
MOV L,C ;BLOCK NUMBER TO H&L REGS.
MOV H,B
DAD H ;*2
DAD H ;*4
DAD H ;*8
;
IF DGROUP
DAD H ;*16 FOR 2k GROUP SIZE
ENDIF ;DGROUP
;
LXI D,DBASE*256 ;MAKE BASE TRACK NUMBER
LXI B,-SECTS ;DIVIDE BY SECTORS/TRACK
;
CNVRTC: MOV A,H ;OVER SECTORS...
ORA A
JNZ CNVRTT ;...BYE GROUPS?
MOV A,L ;OVER SECTORS...
CPI SECTS
JC CNVRTS ;...AND DOWN TO TRACKS?
;
CNVRTT: DAD B ;TAKE AWAY SECTORS
INR D ;+1 TO TRACK NUMBER
JMP CNVRTC ;...AND GO BACK FOR MORE
;
CNVRTS: MOV E,L ;RESIDUAL = SKEWED SECTOR-1
INR E ;BUMP FOR SECTORS 1 TO 32
XCHG ;TRACK/SECTOR IN H&L REGS.
POP B ;RECOVER BLOCK NUMBER
RET ;RETURN FROM "CNVRTB"
;
;Reads a logical sector (if it can), and returns zero flag set if no error
;
READS: PUSH B ;EXILE BLOCK
PUSH H ;...AND TRACK/SECTOR
CALL LTOP ;CONVERT LOGICAL TO PHYSICAL SECTOR
PUSH H ;SAVE SECTOR NUMBER
MOV C,H ;TRACK NUMBER IN H REG...
;
SETTRK: CALL $-$ ;BIOS SET TRACK (MODIFIED BY IBIOS)
POP B ;PUT SECTOR IN C
;
SETSEC: CALL $-$ ;BIOS SET SECTOR (MODIFIED BY IBIOS)
;
DREAD: CALL $-$ ;BIOS READ SECTOR (MODIFIED BY IBIOS)
ORA A ;SET FLAGS FOR POSSIBLE BAD SECTOR
;
IF TEST
LHLD SECCNT ;GET NUMBER OF SECTORS READ
INX H ;INCREMENT
SHLD SECCNT ;SAVE NEW NUMBER
ENDIF ;TEST
;
POP H
POP B ;BACK FROM EXILE...
PUSH PSW ;SAVE FLAGS
INR L ;BUMP FOR NEXT SECTOR
MOV A,L
CPI SECTS+1 ;TRACK OVERFLOW?
JC READSR
MVI L,1 ;YUP, RESET SECTOR NUMBER TO 1...
INR H ;...AND BUMP TRACK NUMBER
;
READSR: POP PSW ;GET FLAGS, TO CHECK IF ERROR ON RETURN
RET ;RETURN FROM "READS"
;
;Convert logical to physical sector
;
LTOP: XCHG
LXI B,LPMAP-1 ;GET BASE OF LOGICAL TO PHYSICAL MAPPING
MOV L,E
MVI H,0 ;LOGICAL SECTOR OFFSET
DAD B ;+ BIAS
MOV E,M ;GET PHYSICAL SECTOR
XCHG ;PUT H&L REGS. BACK...
RET ;RETURN FROM "LTOP"
;
;Logical to physical mapping vectors (sector skew table)
;
IF STDDRV
LPMAP: DB 01,07,13,19,25,05,11,17,23,03,09,15,21
DB 02,08,14,20,26,06,12,18,24,04,10,16,22
ENDIF ;STDDRV
;
IF MICROP
LPMAP: DB 01,02,11,12,21,22,31,32,09,10,19,20,29,30,07,08
DB 17,18,27,28,05,06,15,16,25,26,03,04,13,14,23,24
ENDIF ;MICROP
;
IF MMDBL
LPMAP: DB 01,14,27,40,10,23,36,49,06,19,32,45,02,15,28,41
DB 11,24,37,50,07,20,33,46,03,16,29,42,12,25,38,51
DB 08,21,34,47,04,17,30,43,13,26,39,52,09,22,35,48
DB 05,18,31,44
ENDIF ;MMDBL
;
IF DIGDBL
LPMAP: DB 01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16
DB 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
DB 33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48
DB 49,50,51,52,53,54,55,56,57,58
ENDIF ;DIGDBL
;
IF IMDOS
LPMAP: DB 1,8,15,22,29,36,43,50,57,6,13,20,27,34,41,48,55
DB 4,11,18,25,32,39,46,53,2,9,16,23,30,37,44,51,58
DB 7,14,21,28,35,42,49,56,5,12,19,26,33,40,47,54
DB 3,10,17,24,31,38,45,52
ENDIF ;IMDOS
;
IF DJ256S
LPMAP: DB 01,02,19,20,37,38,03,04,21,22,39,40,05,06,23,24
DB 41,42,07,08,25,26,43,44,09,10,27,28,45,46,11,12
DB 29,30,47,48,13,14,31,32,49,50,15,16,33,34,51,52
DB 17,18,35,36
ENDIF ;DJ256S
;
IF NM256
LPMAP: DB 01,02,23,24,45,46,15,16,37,38,07,08,29,30,51,52
DB 21,22,43,44,13,14,35,36,05,06,27,28,49,50,19,20
DB 41,42,11,12,33,34,03,04,25,26,47,48,17,18,39,40
DB 09,10,31,32
ENDIF ;NM256
;
IF DJ512S OR NM512
LPMAP: DB 01,02,03,04,17,18,19,20,33,34,35,36,49,50,51,52
DB 05,06,07,08,21,22,23,24,37,38,39,40,53,54,55,56
DB 09,10,11,12,25,26,27,28,41,42,43,44,57,58,59,60
DB 13,14,15,16,29,30,31,32,45,46,47,48
ENDIF ;DJ512S or NM512
;
IF DJ1024
LPMAP: DB 01,02,03,04,05,06,07,08,25,26,27,28,29,30,31,32
DB 49,50,51,52,53,54,55,56,09,10,11,12,13,14,15,16
DB 33,34,35,36,37,38,39,40,57,58,59,60,61,62,63,64
DB 17,18,19,20,21,22,23,24,41,42,43,44,45,46,47,48
ENDIF ;DJ1024
;
IF H17
LPMAP: DB 01,02,09,10,17,18,05,06,13,14,03,04,11,12,19,20
DB 07,08,15,16
ENDIF ;H17
;
IF ICOM
LPMAP: DB 01,05,09,13,17,04,08,12,16,03,07,11,15,02,06,10
DB 14,18
ENDIF ;ICOM
;
IF JADEDD
LPMAP: DB 01,11,21,31,41,02,12,22,32,42,03,13,23,33,43
DB 04,14,24,34,44,05,15,25,35,45,06,16,26,36,46
DB 07,17,27,37,47,08,18,28,38,48,09,19,29,39,49
DB 10,20,30,40,50
ENDIF ;JADEDD
;
IF HORIZON
LPMAP: DB 01,02,03,04,21,22,23,24
DB 05,06,07,08,25,26,27,28
DB 09,10,11,12,29,30,31,32
DB 13,14,15,16,33,34,35,36
DB 17,18,19,20,37,38,39,40
ENDIF ;HORIZON
;
;Put bad block in bad block list
;
SETBD: LHLD DMCNT ;GET NUMBER OF SECTORS
LXI D,BLOCK
DAD D ;BUMP BY NUMBER IN THIS BLOCK
SHLD DMCNT ;UPDATE NUMBER OF SECTORS
LHLD DMPTR ;GET POINTER INTO DM
MOV M,C ;...AND PUT BAD BLOCK NUMBER
INX H ;BUMP TO NEXT AVAILABLE EXTENT
;
IF IMDOS OR DJ512S OR DJ1024 OR NM256 OR NM512
MOV M,B ;PUT IN 2ND BYTE FOR IMDOS OR DJ512/1024
INX H ;POINT TO NEXT AVAILABLE EXTENT
ENDIF ;IMDOS OR DJ512S OR DJ1024 OR NM256 OR NM512
;
SHLD DMPTR ;SAVE DM POINTER, FOR NEXT TIME THROUGH HERE
RET ;RETURN FROM "SETBD"
;
;Eliminate any previous [UNUSED].BAD entries
;
ERAB: LXI D,BFCB ;POINT TO BAD FCB
MVI C,19 ;BDOS DELETE FILE FUNCTION
CALL BDOS
RET
;
;Create [UNUSED].BAD file entry
;
OPENB: LXI D,BFCB ;POINT TO BAD FCB
PUSH D ;SAVE IT...
MVI C,22 ;BDOS MAKE FILE FUNCTION
CALL BDOS
POP D ;RECOVER BAD FCB POINTER
MVI C,15 ;BDOS OPEN FILE FUNCTION
CALL BDOS
CPI 0FFH ;CHECK FOR OPEN ERROR
RNZ ;RETURN FROM "OPENB", IF NO ERROR
JMP ERROR7 ;BAIL OUT...CAN'T CREATE [UNUSED].BAD
;
;Move bad area DM to BFCB
;
SETDM: LXI H,DM ;GET DM
SHLD DMPTR ;SAVE AS NEW POINTER
LHLD DMCNT ;GET THE COUNT
;
SETDM0: MOV A,H
ORA A
JNZ GOBIG
MOV A,L
CPI 129 ;ALL BYTES MOVED?
JC SETDME
;
GOBIG: LXI D,-128
DAD D
PUSH H
MVI A,128
CALL SETDME
XCHG
SHLD DMPTR
CALL CLOSEB ;CLOSE OLD EXTENT
LDA EXTNUM ;GET OLD EXTENT NUMBER
INR A ;INCREMENT IT
STA EXTNUM ;SAVE NEW EXTENT NUMBER
STA BFCB+12 ;PUT NEW EXTENT NUMBER INTO OUR FCB
CALL OPENB ;OPEN NEW EXTENT
POP H
JMP SETDM0
;
SETDME: STA BFCB+15 ;PUT RC IN PLACE
IF NOT DGROUP
MVI B,16 ;NUMBER OF BYTES TO MOVE
ENDIF ;NOT DGROUP
;
IF DGROUP
MVI B,8 ;NUMBER OF BYTES TO MOVE
ENDIF ;DGROUP
;
LHLD DMPTR ;GET BAD DMAP POINTER
XCHG ;TO DE
LXI H,BFCB+16 ;POINT AT OUR FCB
;
SETDML: EQU $
;
IF NOT IMDOS
LDAX D ;GET BYTE FROM DMAP
MOV M,A ;MOVE TO OUR FCB
INX D ;INCREMENT DMAP POINTER
INX H ;INCREMENT OUR FCB POINTER
ENDIF ;NOT IMDOS (1 BYTE GROUP #)
;
IF DJ512S OR DJ1024 OR NM256 OR NM512
LDAX D ;GET SECOND BYTE FROM DMAP
MOV M,A ;MOVE TO OUR FCB
INX D ;INCREMENT DMAP POINTER
INX H ;INCREMENT OUR FCB POINTER
ENDIF ;DJ512S OR DJ1024 OR NMXXXDS (2 BYTE GROUP #)
;
IF IMDOS
LDAX D ;GET FIRST (LO ORDER) BYTE FROM DMAP
MOV C,A ;SAVE IT IN C
INX D ;INCREMENT DMAP POINTER
LDAX D ;THEN GET SECOND (HI ORDER) BYTE
MOV M,A ;STORE HI BYTE FIRST
INX H ;INCREMENT FCB POINTER
MOV M,C ;THEN LO BYTE FOR 16-BIT POINTER
INX H ;INCREMENT OUR FCB POINTER
ENDIF ;IMDOS (2 BYTE GROUP #)
;
DCR B ;ONE LESS BYTE TO MOVE
JNZ SETDML ;NOT DONE, GO MOVE MORE
RET ;ELSE RETURN FROM "SETDM"
;
CLOSEB: XRA A
LDA BFCB+14 ;GET CP/M 2.x 'S2' BYTE
ANI 1FH ;ZERO UPDATE FLAGS
STA BFCB+14 ;RESTORE IT TO OUR FCB (WON'T HURT 1.4)
LXI D,BFCB ;FCB FOR [UNUSED].BAD
MVI C,16 ;BDOS CLOSE FILE FUNCTION
CALL BDOS
RET ;RETURN FROM "CLOSEB"
;
;Convert number of blocks to decimal ASCII, for printing
;
SETNUM: LHLD DMCNT ;GET NUMBER OF SECTORS
DAD H ;*2
DAD H ;*4
DAD H ;*8
DAD H ;*16
;
IF NOT DGROUP
DAD H ;*32 FOR 1k GROUP SIZE
ENDIF
;
;H reg now equals number of blocks
LXI D,255
DAD D ;ROUND UP
MOV L,H
MVI H,0 ;NOW HL=NUMBER OF BLOCKS
LXI D,NUMBAD
CALL DCNV
RET ;RETURN FROM "SETNUM"
;
DCNV: MVI B,' ' ;SET FOR PLUS
MOV A,H
ORA A
JP H3
MVI B,'-'
MOV A,L
CMA
INR A
MOV L,A
MOV A,H
CMA
JNZ H2
INR A
;
H2: MOV H,A
;
H3: SHLD DCNVHL
MVI A,' '
STAX D
MOV A,B
STA DCNVPM
XCHG
SHLD DCNVAD
XRA A
STA DCNVFL
LXI B,-10000
CALL DFL8
CALL DSTC
LXI B,-1000
CALL DFL8
CALL DSTC
LXI B,-100
CALL DFL8
CALL DSTC
LXI B,-10
CALL DFL8
CALL DSTC
LDA DCNVHL
ORI '0'
MOV E,A
;
DSTC: LHLD DCNVAD
LDA DCNVFL
ORA A
JNZ DSTC3
;
DSTC1: ADD E
STA DCNVFL
JNZ DSTC2
MVI A,' '
JMP DSTC4
;
DSTC2: LDA DCNVPM
MOV M,A
;
DSTC3: MVI A,'0'
ORA E
;
DSTC4: INX H
MOV M,A
SHLD DCNVAD
RET ;RETURN FROM "SETDM"
;
DCNVFL: DB 0
DCNVHL: DW 0
DCNVAD: DW 0
DCNVPM: DB 0
;
DFL8: LHLD DCNVHL
MVI E,0
;
DF1: DAD B
MOV A,H
ORA A
RM
INR E
SHLD DCNVHL
JMP DF1
;
BFCB: DB 0,'[UNUSED]BAD',0,0,0,0
DS 17
;
ENDMSG: DB CR,LF,' '
;
NUMBAD: DB ' No'
DB ' bad blocks found',CR,LF,'$'
;
EXTNUM: DB 0 ;USED IF MORE THAN 16 BAD BLOCKS
DMCNT: DW 0 ;NUMBER OF BAD SECTORS
DMPTR: DW DM ;POINTER TO NEXT BLOCK ID
;
;Allocation map for bad blocks
;
DM: DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
;Error messages
;
ERROR4: LXI D,ERMSG4 ;SAY NO GO, AND BAIL OUT
JMP PMSG
;
ERMSG4: DB CR,LF,'Only drives A to D allowed$'
;
IF SYSTEM
ERMSG5: DB CR,LF,'Warning...System tracks bad$'
ENDIF ;SYSTEM
;
ERROR6: LXI D,ERMSG6 ;OOPS...CLOBBERED DIRECTORY
JMP PMSG
;
ERMSG6: DB CR,LF,'Bad directory area, try reformatting$'
;
ERROR7: LXI D,ERMSG7 ;SAY NO GO, AND BAIL OUT
JMP PMSG
;
ERMSG7: DB CR,LF,'Can''t create [UNUSED].BAD$'
;
IF TEST
;
;Decimal output routine
;
DECOUT: PUSH B
PUSH D
PUSH H
LXI B,-10
LXI D,-1
;
DECOU2: DAD B
INX D
JC DECOU2
LXI B,10
DAD B
XCHG
MOV A,H
ORA L
CNZ DECOUT
MOV A,E
ADI '0'
CALL TYPE
POP H
POP D
POP B
RET
;
TYPE: PUSH B
PUSH D
PUSH H
MOV E,A ;CHARACTER TO E FOR CP/M
MVI C,2 ;PRINT CONSOLE FUNCTION
CALL BDOS ;PRINT CHARACTER
POP H
POP D
POP B
RET
;
SECMSG: DB ' total sectors read',CR,LF,'$'
;
SECCNT: DW 0 ;NUMBER OF SECTORS READ
;
ENDIF ;TEST
;
DS 64 ;ROOM FOR 32 LEVEL STACK
NEWSTK EQU $ ;OUR STACK
;
END