home *** CD-ROM | disk | FTP | other *** search
- ;
- ; FINDBAD.ASM Ver. 3.8
- ; revised 12/08/80
- ;
- ;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
- ;
- ;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 add conditional assembly for other disk systems,
- ;or otherwise update this program, 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)
- ;
- ;08/06/80 ADDED COMMENTS AND CRUNCHED SOME CODE.
- ; KELLY SMITH. 805-527-9321 (Modem, 300 Baud)
- ; 805-527-0518 (Verbal)
- ;
- ;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/27/80 FIX MISSING CONDITIONAL ASSEMBLY IN FINDB ROUTINE.
- ; PUT VERSION NUMBER IN SIGN-ON MESSAGE. (KBP)
- ;
- ;08/30/80 ADDED CONDITIONAL ASSEMBLY FOR MICROMATION
- ; DOUBLE DENSITY FORMAT. (CHARLES H. STROM)
- ;
- ;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 ERASED BEFORE DATA AREA IS
- ; CHECKED. (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)
- ;
- ;09/01/80 CHANGED EQUATES SO THAT PARAMETERS ARE AUTOMATICALLY
- ; SET FOR EACH DISK SYSTEM CONDITIONAL ASSEMBLY (KBP)
- ;
- ;09/02/80 ADDED IMDOS DOUBLE-DENSITY EQUATES & MODIFIED FOR
- ; MORE THAN 256 BLOCKS PER DISK. (AL JEWER)
- ;
- ;09/08/80 FIXED SEVERAL ERRORS IN AL JEWER'S MODS. CHANGED
- ; RETURN TO CP/M TO WARM BOOT SO BITMAP IN MEMORY WILL
- ; WILL BE PROPERLY UPDATED. ADDED CONDITIONAL ASSEMBLY
- ; FOR TESTING PROGRAM. (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/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)
- ;
- ;12/08/80 ADDED EQUATES FOR NATIONAL MULTIPLEX D3S/D4S
- ; DOUBLE DENSITY BOARD IN VARIOUS FORMATS.
- ; (DAVID FIEDLER)
- ;
- ; 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 boot's" 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)
- ;******************************************************************
- ;
- ;CONDITIONAL ASSEMBLY SWITCH FOR DOUBLE SIDED DRIVES
- ;presently supported for National Multiplex only
- ;
- SIDES2 EQU FALSE ;TRUE for NatMux D3S/D4S 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
- 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
- ;
- ;
- ;DEFINE ASCII CHARACTERS USED
- ;
- CR EQU 0DH ;ASCII CARRIAGE RETURN CHARACTER
- LF EQU 0AH ;ASCII LINE FEED CHARACTER
- TAB EQU 09H ;ASCII 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 3.8'
- DB CR,LF,'Bad sector lockout '
- DB 'program',CR,LF
- ;
- IF STDDRV
- DB 'For single-density 8" only'
- ENDIF
- ;
- IF MICROP
- DB 'For Micropolis Mod II only'
- ENDIF
- ;
- IF MMDBL
- DB 'For Micromation double-density only'
- ENDIF
- ;
- IF DIGDBL
- DB 'For Digital Microsystems',CR,LF
- DB 'FDC3 cntlr dbl dens only'
- ENDIF
- ;
- IF IMDOS
- DB 'For IMSAI IMDOS double-density ONLY'
- ENDIF
- ;
- IF DJ256S
- DB 'For Discus 2-dens./1-side/256-byte sectors only'
- ENDIF
- ;
- IF DJ512S
- DB 'For Discus 2-dens./1-side/512-byte sectors only'
- ENDIF
- ;
- IF DJ1024
- DB 'For Discus 2-dens./1-side/1024-byte sectors only'
- ENDIF
- ;
- IF NM256 OR NM512
- DB 'For National Multiplex double density'
- ENDIF
- ;
- IF SIDES2 AND (NM256 OR NM512)
- DB ' double'
- ENDIF
- ;
- IF NOT SIDES2 AND (NM256 OR NM512)
- DB ' single'
- ENDIF
- ;
- IF NM256
- DB ' sided 256-byte sectors only'
- ENDIF
- ;
- IF NM512
- DB ' sided 512-byte sectors only'
- ENDIF
- ;
- DB 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 2
- 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
- ;
- ;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 H&L REGS. EQUAL 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 60 ;ROOM FOR 30 LEVEL STACK
- NEWSTK EQU $ ;OUR STACK
- ;
- END
-