home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol004
/
findbd37.asm
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
27KB
|
965 lines
;
; FINDBAD.ASM Ver. 3.7
; revised 9/22/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
;
;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)
;
;
; 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)
;******************************************************************
;
;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
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
;
IF DJ512S
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
;
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
;
;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.7'
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
;
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 DJ512S
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
;
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
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
;
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
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 (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