; FINDBAD.ASM VER. 5.4 ; (REVISED 05/21/81) ; ; NON-DESTRUCTIVE DISK TEST PROGRAM ; ;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. ; ;SEE NOTES BELOW CONCERNING 'TEST' CONDITIONAL ASSEMBLY OPTION, ;SYSTST AND BADUSR DIRECTIVES. ; ;******************************************************** ;* * ;* NOTE * ;* * ;* THIS PROGRAM HAS BEEN RE-WRITTEN TO ALLOW IT TO * ;* WORK WITH (HOPEFULLY) ALL CP/M 2.X SYSTEMS, AND * ;* MOST 1.4 CP/M SYSTEMS. IT HAS BEEN TESTED ON SEV- * ;* ERAL DIFFERENT DISK SYSTEMS, INCLUDING NORTHSTAR, * ;* MICROPOLIS, DJ2D, AND KEITH PETERSEN'S 10 MBYTE * ;* HARD DISK SYSTEM. I HAVE TESTED IT PERSONALLY ON * ;* MY "MODIFIED" NORTHSTAR, UNDER SEVERAL DIFFERENT * ;* FORMATS (INCLUDING >16K PER EXTENT), AND HAVE OB- * ;* NO DIFFICULTIES. * ;* IF YOU HAVE HAVE DIFFICULTIES GETTING THIS PRO- * ;* GRAM TO RUN, AND IF YOU ARE USING CP/M 2.X, AND * ;* IF YOU KNOW YOUR CBIOS TO BE BUG-FREE, LEAVE * ;* ME A MESSAGE ON THE CBBS MENTIONED BELOW ... I AM * ;* INTERESTED IN MAKING THIS PROGRAM AS "UNIVERSAL" * ;* AS POSSIBLE. * ;* I CAN'T HELP WITH ANY VERSION OF CP/M 1.4, OTHER * ;* THAN "STANDARD" VERSIONS (WHATEVER THAT MEANS), * ;* BECAUSE THERE ARE JUST TOO MANY HEAVILY MODIFIED * ;* VERSIONS AVAILABLE. * ;* ONE POSSIBLE PROBLEM YOU MAY FIND IS WITH THE * ;* SYSTEM TRACKS OF YOUR DISKETTES...IF THEY ARE OF * ;* A DIFFERENT DENSITY THAN THE DATA TRACKS, THEN * ;* SEE THE NOTE REGARDING THE "SYSTST" EQUATE. * ;* * ;* RON FOWLER * ;* WESTLAND, MICH * ;* 7 APRIL, 1981 * ;* * ;******************************************************** ; ;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 1. 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 SYSTRKWWORD IN THE DISK PARAMETER BLOCK. ; IF YOU ARE A CP/M 2.X USER, YOU MAY ASSIGN THE USER NUMBER ;WHERE [UNUSED.BAD] WILL BE CREATED BY CHANGING THE BYTE AT ;104H TO THE DESIRED USER NUMBER. IF YOU WANT IT IN THE ;DEFAULT USER, THEN LEAVE IT 0FFH. CP/M 1.4 USERS CAN IGNORE ;THIS BYTE ALTOGETHER. ; ;NOTE THAT THESE CHANGES CAN BE DONE WITH DDT AS FOLLOWS: ; ; A>DDT FINDBAD.COM ; -S103 ; 103 01 0 ;DON'T TEST SYSTEM TRACKS ; 104 FF F ;PUT [UNUSED.BAD] IN USER 15 ; 105 31 . ;DONE WITH CHANGES ; -^C ; A>SAVE XX FINDBAD.COM ; ;---------------------------------------------------------------- ;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 "TECHNICAL CBBS" IN DEARBORN, ;MICHIGAN - PHONE 313-846-6127 (110, 300, 450 OR 600 BAUD). ;USE THE FILENAME FINDBAD.NEW. (KBP) ; ;MODIFICATIONS/UPDATES: (IN REVERSE ORDER TO MINIMIZE READING TIME) ; ;05/21/81 CORRECTED ERROR IN DESCRIPTION OF HOW TO SET SYSTST ; BYTE AT 103H. ADDED CRLF TO BLOCK ERROR MESSAGE. (KBP) ; ;05/19/81 CORRECTED OMISSION IN DOLOG ROUTINE SO THAT BADUSR ; WILL WORK CORRECTLY. THANKS TO ART LARKY. (CHS) ; ;04/10/81 CHANGED EXTENT DB FROM -1TTO 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 MULTYPLEX 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 CONTAONING 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 ;WECTORS/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. FFOR 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 SECTRS/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 SYSTST IS SET TO 0, 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 PROWRAM 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 ; 0000 = FALSE EQU 0 FFFF = TRUE EQU NOT FALSE ; ;****************************************************************** ; ;CONDITIONAL ASSEMBLY SWITCH FOR TESTING THIS PROGRAM ;(FOR INITIAL TESTING PHASE ONLY - SEE REMARKS ABOVE) ; 0000 = TEST EQU FALSE ;TRUE FOR TESTING ONLY ; ;****************************************************************** ; ;SYSTEM EQUATES ; 0000 = BASE EQU 0 ;STANDARD CP/M BASE ADDRESS (4200H FOR ALTCPM) 0005 = BDOS EQU BASE+5 ;CP/M WARM BOOT ENTRY 005C = FCB EQU BASE+5CH;CP/M DEFAULT FCB LOCATION ; ;DEFINE ASCII CHARACTERS USED ; 000D = CR EQU 0DH ;CARRIAGE RETURN CHARACTER 000A = LF EQU 0AH ;LINE FEED CHARACTER 0009 = TAB EQU 09H ;TAB CHARACTER ; 003A = DPBOFF EQU 3AH ;CP/M 1.4 OFFSET TO DPB WITHIN BDOS 000F = TRNOFF EQU 15 ;CP/M 1.4 OFFSET TO SECTOR XLATE ROUTINE ; ; 0100 ORG BASE+100H ; 0100 C30501 JMP START ;JMP AROUND OPTION BYTES ; ;IF YOU WANT THE SYSTEM TRACKS TESTED, THEN ;PUT A 1 HERE, OTHERWISE 0. ; 0103 01 SYSTST: DB 1 ;0 IF NO SYS TRACKS, OTHERWISE 1 ; ;IF YOU ARE A CP/M 2.X USER, 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. CP/M 1.4 USERS ;CAN IGNORE THIS BYTE ALTOGETHER. ; 0104 FF BADUSR: DB 0FFH ;USER # WHERE [UNUSED.BAD] GOES ;0FFH = DEFAULT USER ; 0105 315707 START: LXI SP,NEWSTK ;MAKE NEW STACK 0108 CD6101 CALL START2 ;GO PRINT SIGNON 010B 0D0A46494E DB CR,LF,'FINDBAD - ver 5.4' 011E 0D0A426164 DB CR,LF,'Bad sector lockout ' E0133 000000 DB/'program',CR,LF 0136 556E697665 DB 'Universal version',CR,LF 0149 0D0A547970 DB CR,LF,'Type CTL-C to abort',CR,LF,'$' ; 0161 D1 START2: POP D ;GET MSG ADRS 0162 0E09 MVI C,9 ;BDOS PRINT BUFFER FUNCTION 0164 CD0500 CALL BDOS ;PRINT SIGN-ON MSG 0167 CD9F01 CALL SETUP ;SET BIOS ENTRY, AND CHECK DRIVE 016A CDF305 CALL ZMEM ;ZERO ALL AVAILABLE MEMORY 016D CD3A02 CALL FINDB ;ESTABLISH ALL BAD BLOCKS 0170 CA7601 JZ NOBAD ;SAY NO BAD BLOCKS, IF SO 0173 CD2804 CALL SETDM ;FIX DM BYTES IN FCB ; 0176 CDA005 NOBAD: CALL CRLF 0179 3E09 MVI A,TAB 017B CDA705 CALL TYPE 017E 11D906 LXI D,NOMSG ;POINT FIRST TO 'NO' 0181 2AF006 LHLD BADBKS ;PICK UP # BAD BLOCKS 0184 7C MOV A,H ;CHECK FOR ZERO 0185 B5 ORA L 0186 CA8F01 JZ PMSG1 ;JUMP IF NONE 0189 CD7E05 CALL DECOUT ;OOPS..HAD SOME BAD ONES, REPORT 018C C39401 JMP PMSG2 ; 018F 0E09 PMSG1: MVI C,9 ;BDOS PRINT BUFFER FUNCTION 0191 CD0500 CALL BDOS ; 0194 11DC06 PMSG2: LXI D,ENDMSG ;REST OF EXIT MESSAGE ; 0197 0E09 PMSG: MVI C,9 0199 CD0500 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 ; 019C C30000 JMP BASE ;EXIT TO CP/M WARM BOOT ; ;GET ACTUAL ADDRESS OF BIOS ROUTINES ; 019F 2A0100 SETUP: LHLD BASE+1 ;GET BASE ADDRESS OF BIOS VECTORS ; ;WARNING...PROGRAM MODIFICATION TAKES PLACE HERE...DO NOT CHANGE. ; 01A2 111800 LXI D,24 ;OFFSET TO "SETDSK" 01A5 19 DAD D 01A6 220402 SHLD SETDSK+1 ;FIX OUR CALL ADDRESS 01A9 110300 LXI D,3 ;OFFSET TO "SETTRK" 01AC 19 DAD D 01AD 226B03 SHLD SETTRK+1 ;FIX OUR CALL ADDRESS 01B0 110300 LXI D,3 ;OFFSET TO "SETSEC" 01B3 19 DAD D 01B4 226303 SHLD SETSEC+1 ;FIX OUR CALL ADDRESS 01B7 110600 LXI D,6 ;OFFSET TO "DREAD" 01BA 19 DAD D 01BB 226E03 SHLD DREAD+1 ;FIX OUR CALL ADDRESS 01BE 110900 LXI D,9 ;OFFSET TO CP/M 2.X SECTRAN 01C1 19 DAD D 01C2 22B203 SHLD SECTRN+1 ;FIX OUR CALL ADDRESS 01C5 0E0C MVI C,12 ;GET VERSION FUNCTION 01C7 CD0500 CALL BDOS 01CA 7C MOV A,H ;SAVE AS FLAG 01CB B5 ORA L 01CC 32B706 STA VER2FL 01CF C2DE01 JNZ GDRIV ;SKIP 1.4 STUFF IF IS 2.X 01D2 110F00 LXI D,TRNOFF ;CP/M 1.4 OFFSET TO SECTRAN 01D5 2A0600 LHLD BDOS+1 ;SET UP JUMP TO 1.4 SECTRAN 01D8 2E00 MVI L,0 01DA 19 DAD D 01DB 22B203 SHLD SECTRN+1 ; ;CHECK FOR DRIVE SPECIFICATION ; 01DE 3A5C00 GDRIV: LDA FCB ;GET DRIVE NAME 01E1 4F MOV C,A 01E2 B7 ORA A ;ZERO? 01E3 C2ED01 JNZ GD2 ;IF NOT,THEN GO SPECIFY DRIVE 01E6 0E19 MVI C,25 ;GET LOGGED-IN DRIVE 01E8 CD0500 CALL BDOS 01EB 3C INR A ;MAKE 1-RELATIVE 01EC 4F MOV C,A ; 01ED 3AB706 GD2: LDA VER2FL ;IF CP/M VERSION 2.X 01F0 B7 ORA A 01F1 C2FA01 JNZ GD3 ; SELDSK WILL RETURN SEL ERR ; ;IS CP/M 1.4, WHICH DOESN'T RETURN A SELECT ;ERROR, SO WE HAVE TO DO IT HERE ; 01F4 79 MOV A,C 01F5 FE05 CPI 4+1 ;CHECK FOR HIGHEST DRIVE NUMBER 01F7 D2E004 JNC SELERR ;SELECT ERROR ; 01FA 0D GD3: DCR C ;BACK OFF FOR CP/M 01FB C5 PUSH B ;SAVE DISK SELECTION 01FC 59 MOV E,C ;ALIGN FOR BDOS 01FD 0E0E MVI C,14 ;SELECT DISK FUNCTION 01FF CD0500 CALL BDOS 0202 C1 POP B ;GET BACK DISK NUMBER ; ;EXPLANATION: WHY WE DO THE SAME THING TWICE ; ; YOU MIGHT NOTICE THAT WE ARE ; DOING THE DISK SELECTION TWICE, ; ONCE BY A BDOS CALL AND ONCE BY ; DIRECT BIOS CALL. THE REASON FOR THIS: ; ; THE BIOS CALL IS NECESSARY IN ORDER TO ; GET THE NECESSARY POINTER BACK FROM CP/M ; (2.X) TO FIND THE SECTOR TRANSLATE TABLE. ; THE BDOS CALL IS NECESSARY TO KEEP CP/M ; IN STEP WITH THE BIOS...WE MAY LATER ; HAVE TO CREATE A [UNUSED].BAD FILE, AND ; CP/M MUST KNOW WHICH DRIVE WE ARE USING. ; (RGF) ; 0203 CD0000 SETDSK: CALL $-$ ;DIRECT BIOS VEC FILLED IN AT INIT 0206 3AB706 LDA VER2FL 0209 B7 ORA A 020A CA2202 JZ DOLOG ;JUMP IF CP/M 1.4 020D 7C MOV A,H 020E B5 ORA L ;CHECK FOR 2.X 020F CAE004 JZ SELERR ;JUMP IF SELECT ERROR 0212 5E MOV E,M ;GET SECTOR TABLE PNTR 0213 23 INX H 0214 56 MOV D,M 0215 23 INX H 0216 EB XCHG 0217 22F806 SHLD SECTBL ;STORE IT AWAY 021A 210800 LXI H,8 ;OFFSET TO DPB POINTER 021D 19 DAD D 021E 7E MOV A,M ;PICK UP DPB POINTER 021F 23 INX H ; TO USE 0220 66 MOV H,M ; AS PARAMETER 0221 6F MOV L,A ; TO LOGIT ; 0222 CD5E06 DOLOG: CALL LOGIT ;LOG IN DRIVE, GET DISK PARMS 0225 CD3506 CALL GETDIR ;CALCULATE DIRECTORY INFORMATION ; ;NOW SET THE REQUIRED USER NUMBER ; 0228 3AB706 LDA VER2FL 022B B7 ORA A 022C C8 RZ ;NO USERS IN CP/M 1.4 022D 3A0401 LDA BADUSR ;GET THE USER NUMBER 0230 FEFF CPI 0FFH ;IF IT IS 0FFH, THEN RETURN 0232 C8 RZ 0233 5F MOV E,A ;BDOS CALL NEEDS USER # IN E 0234 0E20 MVI C,32 ;GET/SET USER CODE 0236 CD0500 CALL BDOS 0239 C9 RET ; ;LOOK FOR BAD BLOCKS ; 023A 3A0301 FINDB: LDA SYSTST 023D B7 ORA A 023E CA4402 JZ DODIR ;JUMP IF NO SYS TRACKS TO BE TESTED 0241 CD8C02 CALL CHKSYS ;CHECK FOR BAD BLOCKS ON TRACK 0 AND 1 ; 0244 CDD602 DODIR: CALL CHKDIR ;CHECK FOR BAD BLOCKS IN DIRECTORY 0247 CD6302 CALL TELL1 024A 0D0A546573 DB CR,LF,'Testing data area...',CR,LF,'$' ; 0263 D1 TELL1: POP D 0264 0E09 MVI C,9 ;BDOS PRINT STRING FUNCTION 0266 CD0500 CALL BDOS 0269 CDFF03 CALL ERAB ;ERASE ANY [UNUSED].BAD FILE 026C 2AB506 LHLD DIRBKS ;START AT FIRST DATA BLOCK 026F 44 MOV B,H ;PUT INTO BC 0270 4D MOV C,L ; 0271 CD1103 FINDBA: CALL READB ;READ THE BLOCK 0274 C4B403 CNZ SETBD ;IF BAD, ADD BLOCK TO LIST 0277 03 INX B ;BUMP TO NEXT BLOCK 0278 2AAA06 LHLD DSM 027B 50 MOV D,B ;SET UP FOR (MAXGRP - CURGRP) 027C 59 MOV E,C 027D CD0906 CALL SUBDE ;DO SUBTRACT: (MAXGRP - CURGRP) 0280 D27102 JNC FINDBA ;UNTIL CURGRP>MAXGRP 0283 CDA005 CALL CRLF 0286 2AFB06 LHLD DMCNT ;GET NUMBER OF BAD SECTORS 0289 7C MOV A,H 028A B5 ORA L ;SET ZERO FLAG, IF NO BAD BLOCKS 028B C9 RET ;RETURN FROM "FINDB" ; ;CHECK SYSTEM TRACKS, NOTIFY USER IF BAD, BUT CONTINUE ; 028C CDAC02 CHKSYS: CALL CHSY1 ;PRINT MESSAGE 028F 0D0A546573 DB CR,LF,'Testing system tracks...',CR,LF,'$' ; 02AC D1 CHSY1: POP D 02AD 0E09 MVI C,9 ;PRINT STRING FUNCTION 02AF CD0500 CALL BDOS 02B2 210000 LXI H,0 ;SET TRACK 0, SECTOR 1 02B5 22F406 SHLD TRACK 02B8 23 INX H 02B9 22F206 SHLD SECTOR ; CHKSY;: CALL READS ;READ A SECTOR 02BC C2CD02 JNZ SYSERR ;NOTIFY, IF BAD BLOCKS HERE 02BF 2AB206 LHLD SYSTRK ;SET UP (TRACK-SYSTRK) 02C2 EB XCHG 02C3 2AF406 LHLD TRACK 02C6 CD0906 CALL SUBDE ;DO THE SUBTRACT U02C9 DA0000 JC CHKSY1 ;LOOP WHILE TRACK < SYSTRK 02CC C9 RET ;RETURN FROM "CHKSYS" ; 02CD 110505 SYSERR: LXI D,ERMSG5 ;SAY NO GO, AND BAIL OUT 02D0 0E09 MVI C,9 ;BDOS PRINT BUFFER FUNCTION 02D2 CD0500 CALL BDOS 02D5 C9 RET ;RETURN FROM "SYSERR" ; ;CHECK FOR BAD BLOCKS IN DIRECTORY AREA ; 02D6 CDF702 CHKDIR: CALL CHKD1 02D9 0D0A546573 DB CR,LF,'Testing directory area...',CR,LF,'$' ; 02F7 D1 CHKD1: POP D 02F8 0E09 MVI C,9 ;BDOS PRINT STRING FUNCTION 02FA CD0500 CALL BDOS 02FD 010000 LXI B,0 ;START AT BLOCK 0 ; 0300 CD1103 CHKDI1: CALL READB ;READ A BLOCK 0303 C22F05 JNZ ERROR6 ;IF BAD, INDICATE ERROR IN DIRECTORY AREA 0306 03 INX B ;BUMP FOR NEXT BLOCK 0307 2AB506 LHLD DIRBKS ;SET UP (CURGRP - DIRBKS) 030A 2B DCX H ;MAKE 0-RELATIVE 030B 50 MOV D,B U MOV EOC E030C 40 CALL SUBDE ;DO THE SUBTRACT 030D D20003 JNC CHKDI1 ;LOOP UNTIL CURGRP > DIRGRP 0310 C9 RET ;RETURN FROM "CHKDIR" ; ;READ ALL SECTORS IN BLOCK, AND RETURN ZERO FLAG SET IF NONE BAD ; 0311 CD2403 READB: CALL CNVRTB ;CONVERT TO TRACK/SECTOR IN H&L REGS. 0314 3AA806 LDA BLM 0317 3C INR A ;NUMBER OF SECTORS/BLOCK 0318 57 MOV D,A ; IN D REG ; 0319 D5 READBA: PUSH D 031A CD5203 CALL READS ;READ SKEWED SECTOR 031D D1 POP D 031E C0 RNZ ;ERROR IF NOT ZERO... 031F 15 DCR D ;DEBUMP SECTOR/BLOCK 0320 C21903 JNZ READBA ;DO NEXT, IF NOT FINISHED 0323 C9 RET ;RETURN FROM "READBA" ; ;CONVERT BLOCK NUMBER TO TRACK AND SKEWED SECTOR NUMBER ; 0324 C5 CNVRTB: PUSH B ;SAVE CURRENT GROUP 0325 60 MOV H,B ;NEED IT IN HL 0326 69 MOV L,C ; FOR EASY SHIFTING 0327 3AA706 LDA BSH ;DPB VALUE THAT TELLS HOW TO ; 032A 29 SHIFT: DAD H ; SHIFT GROUP NUMBER TO GET 032B 3D DCR A ; DISK-DATA-AREA RELATIVE 032C C22A03 JNZ SHIFT ; SECTOR NUMBER 032F EB XCHG ;REL SECTOR # INTO DE 0330 2AA506 LHLD SPT ;SECTORS PER TRACK FROM DPB 0333 CD1006 CALL NEG ;FASTER TO DAD THAN CALL SUBDE 0336 EB XCHG 0337 010000 LXI B,0 ;INITIALIZE QUOTIENT ; ;DIVIDE BY NUMBER OF SECTORS ; QUOTIENT = TRACK ; MOD = SECTOR ; 033A 03 DIVLP: INX B ;DIRTY DIVISION 033B 19 DAD D 033C DA3A03 JC DIVLP 033F 0B DCX B ;FIXUP LAST 0340 EB XCHG 0341 2AA506 LHLD SPT 0344 19 DAD D 0345 23 INX H 0346 22F206 SHLD SECTOR ;NOW HAVE LOGICAL SECTOR 0349 2AB206 LHLD SYSTRK ;BUT BEFORE WE HAVE TRACK #, 034C 09 DAD B ; WE HAVE TO ADD SYS TRACK OFFSET 034D 22F406 SHLD TRACK 0350 C1 POP B ;THIS WAS OUR GROUP NUMBER 0351 C9 RET ; ;READS READS A LOGICAL SECTOR (IF IT CAN) ;AND RETURNS ZERO FLAG SET IF NO ERROR. ; 0352 C5 READS: PUSH B ;SAVE THE GROUP NUMBER 0353 CD9903 CALL LTOP ;CONVERT LOGICAL TO PHYSICAL 0356 3AB706 LDA VER2FL ;NOW CHECK VERSION 0359 B7 ORA A 035A CA6503 JZ NOTCP2 ;SKIP THIS STUFF IF CP/M 1.4 035D 2AF606 LHLD PHYSEC ;GET PHYSICAL SECTOR 0360 44 MOV B,H ;INTO BC 0361 4D MOV C,L ; 0362 CD0000 SETSEC: CALL $-$ ;ADDRS FILLED IN AT INIT ; ;QUICK NOTE OF EXPLANATION: THIS CODE APPEARS ;AS IF WE SKIPPED THE SETSEC ROUTINE FOR 1.4 ;CP/M USERS. THAT'S NOT TRUE; IN CP/M 1.4, THE ;CALL WITHIN THE LTOP ROUTINE TO SECTRAN AC- ;TUALLY DOES THE SET SECTOR, SO NO NEED TO DO ;IT TWICE. (RGF) ; 0365 2AF406 NOTCP2: LHLD TRACK ;NOW SET THE TRACK 0368 44 MOV B,H ;CP/M WANTS IT IN BC 0369 4D MOV C,L ; 036A CD0000 SETTRK: CALL $-$ ;ADDRS FILLED IN AT INIT ; ;NOW DO THE SECTOR READ ; 036D CD0000 DREAD: CALL $-$ ;ADDRS FILLED IN AT INIT 0370 B7 ORA A ;SET FLAGS 0371 F5 PUSH PSW ;SAVE ERROR FLAG ; IF TEST LHLD SECCNT ;GET SECTOR COUNT INX H ;ADD ONE SHLD SECCNT ;SAVE NEW COUNT ENDIF ;TEST ; 0372 2AF206 LHLD SECTOR ;GET LOGICAL SECTOR # 0375 23 INX H ;WE WANT TO INCREMENT TO NEXT 0376 EB XCHG ;BUT FIRST...CHECK OVERFLOW 0377 2AA506 LHLD SPT ; BY DOING (SECPERTRK-SECTOR) 037A CD0906 CALL SUBDE ;DO THE SUBTRACTION 037D EB XCHG 037E D29303 JNC NOOVF ;JUMP IF NOT SECTOR>SECPERTRK ; ;SECTOR OVERFLOW...BUMP TRACK NUMBER, RESET SECTOR ; 0381 2AF406 LHLD TRACK 0384 23 INX H 0385 22F406 SHLD TRACK 0388 3E2A MVI A,'*' ;TELL CONSOLE ANOTHER TRACK DONE 038A CDA705 CALL TYPE 038D CDB405 CALL STOP ;SEE IF CONSOLE WANTS TO QUIT 0390 210100 LXI H,1 ;NEW SECTOR NUMBER ON NEXT TRACK ; 0393 22F206 NOOVF: SHLD SECTOR ;PUT SECTOR AWAY 0396 F1 POP PSW ;GET BACK ERROR FLAGS 0397 C1 POP B ;RESTORE GROUP NUMBER 0398 C9 RET ; ;CONVERT LOGICAL SECTOR # TO PHYSICAL ; 0399 2AF806 LTOP: LHLD SECTBL ;SET UP PARAMETERS 039C EB XCHG ; FOR CALL TO SECTRAN 039D 2AF206 LHLD SECTOR 03A0 44 MOV B,H 03A1 4D MOV C,L 03A2 0B DCX B ;ALWAYS CALL SECTRAN W/ZERO-REL SEC # ; 03A3 CDB103 SECT1: CALL SECTRN ;DO THE SECTOR TRANSLATION 03A6 3AA606 LDA SPT+1 ;CHECK IF BIG TRACKS 03A9 B7 ORA A ;SET FLAGS (TRACKS > 256 SECTORS) 03AA C2AD03 JNZ LTOP1 ;NO SO SKIP S MOVIH,A ;ZERO OUT UPPER 8 BITS ; 03AD 22F606 LTOP1: SHLD PHYSEC ;PUT AWAY PHYSICAL SECTOR 03B0 C9 RET ; ;SECTOR TRANSLATION VECTOR ; 03B1 C30000 SECTRN: JMP $-$ ;FILLED IN AT INIT ; ;PUT BAD BLOCK IN BAD BLOCK LIST ; 03B4 C5 SETBD: PUSH B 03B5 CDC603 CALL SETBD1 03B8 0D0A426164 DB CR,LF,'Bad block: $' ; 03C6 D1 SETBD1: POP D ;RETRIEVE ARG 03C7 0E09 MVI C,9 ;PRINT STRING 03C9 CD0500 CALL BDOS 03CC C1 POP B ;GET BACK BLOCK NUMBER 03CD 78 MOV A,B 03CE CD2106 CALL HEXO ;PRINT IN HEX 03D1 79 MOV A,C 03D2 CD2106 CALL HEXO 03D5 CDA005 CALL CRLF 03D8 2AFB06 LHLD DMCNT ;GET NUMBER OF SECTORS 03DB 3AA806 LDA BLM ;GET BLOCK SHIFT VALUE 03DE 3C INR A ;MAKES SECTOR/GROUP VALUE 03DF 5F MOV E,A ;WE WANT 16 BITS 03E0 1600 MVI D,0 03E2 19 DAD D ;BUMP BY NUMBER IN THIS BLOCK 03E3 22FB06 SHLD DMCNT ;UPDATE NUMBER OF SECTORS 03E6 2AF006 LHLD BADBKS ;INCREMENT NUMBER OF BAD BLOCKS 03E9 23 INX H 03EA 22F006 SHLD BADBKS 03ED 2AFD06 LHLD DMPTR ;GET POINTER INTO DM 03F0 71 MOV M,C ;...AND PUT BAD BLOCK NUMBER 03F1 23 INX H ;BUMP TO NEXT AVAILABLE EXTENT 03F2 3AAB06 LDA DSM+1 ;CHECK IF 8 OR 16 BIT BLOCK SIZE 03F5 B7 ORA A 03F6 CAFB03 JZ SMGRP ;JUMP IF 8 BIT BLOCKS 03F9 70 MOV M,B ;ELSE STORE HI BYTE OF BLOCK # 03FA 23 INX H ;AND BUMP POINTER ; 03FB 22FD06 SMGRP: SHLD DMPTR ;SAVE DM POINTER, FOR NEXT TIME THROUGH HERE 03FE C9 RET ;RETURN FROM "SETBD" ; ;ELIMINATE ANY PREVIOUS [UNUSED].BAD ENTRIES ; 03FF 11B806 ERAB: LXI D,BFCB ;POINT TO BAD FCB 0402 0E13 MVI C,19 ;BDOS DELETE FILE FUNCTION 0404 CD0500 CALL BDOS 0407 C9 RET ; ;CREATE [UNUSED].BAD FILE ENTRY ; 0408 11B806 OPENB: LXI D,BFCB ;POINT TO BAD FCB 040B 0E16 MVI C,22 ;BDOS MAKE FILE FUNCTION 040D CD0500 CALL BDOS 0410 FEFF CPI 0FFH ;CHECK FOR OPEN ERROR 0412 C0 RNZ ;RETURN FROM "OPENB", IF NO ERROR 0413 C35C05 JMP ERROR7 ;BAIL OUT...CAN'T CREATE [UNUSED].BAD ; 0416 AF CLOSEB: XRA A 0417 3AC606 LDA BFCB+14 ;GET CP/M 2.X 'S2' BYTE 041A E61F ANI 1FH ;ZERO UPDATE FLAGS 041C 32C606 STA BFCB+14 ;RESTORE IT TO OUR FCB (WON'T HURT 1.4) 041F 11B806 LXI D,BFCB ;FCB FOR [UNUSED].BAD 0422 0E10 MVI C,16 ;BDOS CLOSE FILE FUNCTION 0424 CD0500 CALL BDOS 0427 C9 RET ;RETURN FROM "CLOSEB" ; ;MOVE BAD AREA DM TO BFCB ; 0428 215707 SETDM: LXI H,DM ;GET DM 042B 22FD06 SHLD DMPTR ;SAVE AS NEW POINTER 042E 3AA906 LDA EXM ;GET THE EXTENT SHIFT FACTOR 0431 0E00 MVI C,0 ;INIT BIT COUNT 0433 CD4A06 CALL COLECT ;GET SHIFT VALUE 0436 218000 LXI H,128 ;STARTING EXTENT SIZE 0439 79 MOV A,C ;FIRST SEE IF ANY SHIFTS TO DO 043A B7 ORA A 043B CA4304 JZ NOSHFT ;JUMP IF NONE ; 043E 29 ESHFT: DAD H ;SHIFT 043F 3D DCR A ;BUMP 0440 C23E04 JNZ ESHFT ;LOOP ; 0443 E5 NOSHFT: PUSH H ;SAVE THIS, IT IS RECORDS PER EXTENT 0444 3AA706 LDA BSH ;GET BLOCK SHIFT 0447 47 MOV B,A ; 0448 CD5606 BSHFT: CALL ROTRHL ;SHIFT RIGHT 044B 05 DCR B 044C C24804 JNZ BSHFT ;TO GET BLOCKS PER EXTENT 044F 7D MOV A,L ;IT'S IN L (CAN'T BE >16) 0450 32B406 STA BLKEXT ;SETDME WILL NEED THIS LATER 0453 E1 POP H ;GET BACK REC/EXT ; 0454 EB SET1: XCHG ;NOW HAVE REC/EXTENT IN DE 0455 2AFB06 LHLD DMCNT ;COUNT OF BAD SECTORS ; 0458 E5 SETDMO: PUSH H ;SET FLAGS ON (DMCNT-BADCNT) 0459 CD0906 CALL SUBDE ;HAVE TO SUBTRACT FIRST 045C 44 MOV B,H ;SAVE RESULT IN BC 045D 4D MOV C,L 045E E1 POP H ;THIS POP MAKES IT COMPARE ONLY 045F DA8304 JC SETDME ;JUMP IF LESS THAN 1 EXTENT WORTH 0462 78 MOV A,B 0463 B1 ORA C ;TEST IF SUBTRACT WAS 0 0464 CA7804 JZ EVENEX ;EXTENT IS EXACTLY FILLED (SPL CASE) 0467 60 MOV H,B ;RESTORE RESULT TO HL 0468 69 MOV L,C 0469 E5 PUSH H ;SAVE TOTAL 046A D5 PUSH D ;AND SECTORS/EXTENT 046B EB XCHG 046C CD8304 CALL SETDME ;PUT AWAY ONE EXTENT 046F EB XCHG 0470 22FD06 SHLD DMPTR ;PUT BACK NEW DM POINTER 0473 D1 POP D ;GET BACK SECTORS/EXTENT 0474 E1 POP H ;AND COUNT OF BAD SECTORS 0475 C35804 JMP 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. ; 0478 EB EVENEX: XCHG ;FIRST SET EXTENT W/BAD BLOCKS 0479 CD8304 CALL SETDME 047C EB XCHG 047D 22FD06 SHLD DMPTR 0480 210000 LXI H,0 ;NOW SET ONE WITH NO DATA BLOCKS ; ;FILL IN AN EXTENT'S ORTH OF BAD SECTORS/BLOCK NUMBERS. ;ALSO FILL IN THE EXTENT NUMBER IN THE FCB. ; 0483 E5 SETDME: PUSH H ;SAVE RECORD COUNT 0484 3AFA06 LDA EXTNUM ;UPDATE EXTENT BYTE 0487 3C INR A 0488 32FA06 STA EXTNUM ;SAVE FOR LATER 048B 32C406 STA BFCB+12 ; AND PUT IN FCB 048E CD0804 CALL OPENB ;OPEN THIS EXTENT 0491 E1 POP H ;RETRIEVE REC COUNT ; ;DIVIDE RECORD COUNT BY 128 TO GET THE NUMBER ;OF LOGICAL EXTENTS TO PUT IN THE EX FIELD ; 0492 0600 MVI B,0 ;INIT QUOTIENT 0494 1180FF LXI D,-128 ;-DIVISOR 0497 7C MOV A,H ;TEST FOR SPL CASE 0498 B5 ORA L ; OF NO RECORDS 0499 CAAE04 JZ SKIP ; 049C 19 DIVLOP: DAD D ;SUBTRACT 049D 04 INR B ;BUMP QUOTIENT 049E DA9C04 JC DIVLOP 04A1 118000 LXI D,128 ;FIX UP OVERSHOOT 04A4 19 DAD D 04A5 05 DCR B 04A6 7C MOV A,H ;TEST FOR WRAPAROUND 04A7 B5 ORA L 04A8 C2AE04 JNZ SKIP 04AB 2E80 MVI L,80H ;RECORD LENGTH 04AD 05 DCR B ; 04AE 3AFA06 SKIP: LDA EXTNUM ;NOW FIX UP EXTENT NUM 04B1 80 ADD B 04B2 32FA06 STA EXTNUM 04B5 32C406 STA BFCB+12 04B8 7D MOV A,L ;MOD IS RECORD COUNT 04B9 32C706 STA BFCB+15 ;THAT GOES IN RC BYTE ; 04BC 3AB406 MOVDM: LDA BLKEXT ;GET BLOCKS PER EXTENT 04BF 47 MOV B,A ;INTO B ; 04C0 2AFD06 SETD1: LHLD DMPTR ;POINT TO BAD ALLOCATION MAP 04C3 EB XCHG 04C4 21C806 LXI H,BFCB+16 ;DISK ALLOC MAP IN FCB ; 04C7 1A SETDML: LDAX D 04C8 77 MOV M,A 04C9 23 INX H 04CA 13 INX D ; ;NOW SEE IF 16 BIT GROUPS...IF SO, ;WE HAVE TO MOVE ANOTHER BYTE ; 04CB 3AAB06 LDA DSM+1 ;THIS TELLS US 04CE B7 ORA A 04CF CAD604 JZ BUMP1 ;IF ZERO, THEN NOT 04D2 1A LDAX D ;IS 16 BITS, SO DO ANOTHER 04D3 77 MOV M,A 04D4 23 INX H 04D5 13 INX D ; 04D6 05 BUMP1: DCR B ;COUNT DOWN 04D7 C2C704 JNZ SETDML 04DA D5 PUSH D 04DB CD1604 CALL CLOSEB ;CLOSE THIS EXTENT 04DE D1 POP D 04DF C9 RET ; ;ERROR MESSAGES ; 04E0 11E604 SELERR: LXI D,SELEMS ;SAY NO GO, AND BAIL OUT 04E3 C39701 JMP PMSG ; 04E6 0D0A447269SELEMS: DB CR,LF,'Drive specifier out of range$' ; 0505 0D0A2B2B2BERMSG5: DB CR,LF,'+++ Warning...System tracks' 0522 2062616420 DB ' bad +++',CR,LF,CR,LF,'$' ; 052F 113505 ERROR6: LXI D,ERMSG6 ;OOPS...CLOBBERED DIRECTORY 0532 C39701 JMP PMSG ; 0535 0D0A426164ERMSG6: DB CR,LF,'Bad directory area, try reformatting$' ; 055C 116205 ERROR7: LXI D,ERMSG7 ;SAY NO GO, AND BAIL OUT 055F C39701 JMP PMSG ; 0562 0D0A43616EERMSG7: DB CR,LF,'Can''t create [UNUSED].BAD$' ; ; ;==== SUBROUTINES ==== ; ;DECIMAL OUTPUT ROUTINE ; 057E C5 DECOUT: PUSH B 057F D5 PUSH D 0580 E5 PUSH H 0581 01F6FF LXI B,-10 0584 11FFFF LXI D,-1 ; 0587 09 DECOU2: DAD B 0588 13 INX D 0589 DA8705 JC DECOU2 058C 010A00 LXI B,10 058F 09 DAD B 0590 EB XCHG 0591 7C MOV A,H 0592 B5 ORA L 0593 C47E05 CNZ DECOUT 0596 7B MOV A,E 0597 C630 ADI '0' 0599 CDA705 CALL TYPE 059C E1 POP H 059D D1 POP D 059E C1 POP B 059F C9 RET ; ;CARRIAGE-RETURN/LINE-FEED TO CONSOLE ; 05A0 3E0D CRLF: MVI A,CR 05A2 CDA705 CALL TYPE 05A5 3E0A MVI A,LF ;FALL INTO 'TYPE' ; 05A7 C5 TYPE: PUSH B 05A8 D5 PUSH D 05A9 E5 PUSH H 05AA 5F MOV E,A ;CHARACTER TO E FOR CP/M 05AB 0E02 MVI C,2 ;PRINT CONSOLE FUNCTION 05AD CD0500 CALL BDOS ;PRINT CHARACTER 05B0 E1 POP H 05B1 D1 POP D 05B2 C1 POP B 05B3 C9 RET ; ;SUBROUTINE TO TEST CONSOLE FOR CONTROL-C ABORT ; 05B4 2A0100 STOP: LHLD BASE+1 ;FIND BIOS IN MEMORY 05B7 2E06 MVI L,6 ;OFFSET TO CONSOLE STATUS 05B9 CDF205 CALL GOHL ;THANKS TO BRUCE RATOFF FOR THIS TRICK 05BC B7 ORA A ;TEST FLAGS ON ZERO 05BD C8 RZ ;RETURN IF NO CHAR 05BE 2A0100 LHLD BASE+1 ;NOW FIND CONSOLE INPUT 05C1 2E09 MVI L,9 ;OFFSET FOR CONIN 05C3 CDF205 CALL GOHL 05C6 FE03 CPI 'C'-40H ;IS IT CONTROL-C? 05C8 C0 RNZ ;RETURN IF NOT 05C9 11D405 LXI D,ABORTM ;EXIT WITH MESSAGE 05CC 0E09 MVI C,9 ;PRINT MESSAGE FUNCTION 05CE CD0500 CALL BDOS ;SAY GOODBYE 05D1 C30000 JMP BASE+0 ;THEN LEAVE ; 05D4 0D0A ABORTM: DB CR,LF 05D6 5465737420 DB 'Test aborted by control-C' 05EF 0D0A24 DB CR,LF,'$' ; ;A THING TO ALLOW A CALL TO @HL ; 05F2 E9 GOHL: PCHL ; ;ZERO ALL OF MEMORY TO HOLD DM VALUES ; 05F3 2A0600 ZMEM: LHLD BDOS+1 ;GET TOP-OF-MEM POINTER 05F6 115707 LXI D,DM ;STARTING POINT 05F9 CD0906 CALL SUBDE ;GET NUMBER OF BYTES 05FC 44 MOV B,H 05FD 4D MOV C,L 05FE EB XCHG ;BEGIN IN HL, COUNT IN BC ; 05FF 3600 ZLOOP: MVI M,0 ;ZERO A BYTE 0601 23 INX H ;POINT PAST 0602 0B DCX B ;COUNT DOWN 0603 78 MOV A,B 0604 B1 ORA C 0605 C2FF05 JNZ ZLOOP 0608 C9 RET ; ;SUBTRACT DE FROM HL ; 0609 7D SUBDE: MOV A,L 060A 93 SUB E 060B 6F MOV L,A 060C 7C MOV A,H 060D 9A SBB D 060E 67 MOV H,A 060F C9 RET ; ;NEGATE HL ; 0610 7D NEG: MOV A,L 0611 2F CMA 0612 6F MOV L,A 0613 7C MOV A,H 0614 2F CMA 0615 67 MOV H,A 0616 23 INX H 0617 C9 RET ; ;MOVE FROM (HL) TO (DE) ;COUNT IN BC ; 0618 7E MOVE: MOV A,M 0619 12 STAX D 061A 23 INX H 061B 13 INX D 061C 05 DCR B 061D C21806 JNZ MOVE 0620 C9 RET ; ;PRINT BYTE IN ACCUMULATOR IN HEX ; 0621 F5 HEXO: PUSH PSW ;SAVE FOR SECOND HALF 0622 0F RRC ;MOVE INTO POSITION 0623 0F RRC 0624 0F RRC 0625 0F RRC 0626 CD2A06 CALL NYBBLE ;PRINT MS NYBBLE 0629 F1 POP PSW ; 062A E60F NYBBLE: ANI 0FH ;LO NYBBLE ONLY 062C C690 ADI 90H 062E 27 DAA 062F CE40 ACI 40H 0631 27 DAA 0632 C3A705 JMP TYPE ;PRINT IN HEX ; ;SUBROUTINE TO DETERMINE THE NUMBER ;OF GOUPS RESERVED FOR THE DIRECTORY ; 0635 0E00 GETDIR: MVI C,0 ;INIT BIT COUNT 0637 3AAE06 LDA AL0 ;READ DIR GRP BITS 063A CD4A06 CALL COLECT ;COLLECT COUNT OF DIR GRPS.. 063D 3AAF06 LDA AL1 ;..IN REGISTER C 0640 CD4A06 CALL COLECT 0643 69 MOV L,C 0644 2600 MVI H,0 ;BC NOW HAS A DEFAULT START GRP # 0646 22B506 SHLD DIRBKS ;SAVE FOR LATER 0649 C9 RET ; ;COLLECT THE NUMBER OF '1' BITS IN A AS A COUNT IN C ; 064A 0608 COLECT: MVI B,8 ; 064C 17 COLOP: RAL 064D D25106 JNC COSKIP 0650 0C INR C ; 0651 05 COSKIP: DCR B 0652 C24C06 JNZ COLOP 0655 C9 RET ; ;SHIFT HL RIGHT ONE PLACE ; 0656 B7 ROTRHL: ORA A ;CLEAR CARRY 0657 7C MOV A,H ;GET HI BYTE 0658 1F RAR ;SHIFT RIGHT 0659 67 MOV H,A ;PUT BACK 065A 7D MOV A,L ;GET LO 065B 1F RAR ;SHIFT WITH CARRY 065C 6F MOV L,A ;PUT BACK 065D C9 RET ; ;ROUTINE TO FILL IN DISK PARAMETERS ; 065E 3AB706 LOGIT: LDA VER2FL 0661 B7 ORA A ;IF NOT CP/M 2.X THEN 0662 CA6E06 JZ LOG14 ; DO IT AS 1.4 0665 11A506 LXI D,DPB ; THEN MOVE TO LOCAL 0668 060F MVI B,DPBLEN ; WORKSPACE 066A CD1806 CALL MOVE 066D C9 RET ; 066E 2A0600 LOG14: LHLD BDOS+1 ;FIRST FIND 1.4 BDOS 0671 2E00 MVI L,0 0673 113A00 LXI D,DPBOFF ;THEN OFFSET TO 1.4'S DPB 0676 19 DAD D 0677 1600 MVI D,0 ;SO 8 BIT PARMS WILL BE 16 0679 5E MOV E,M ;NOW MOVE PARMS 067A 23 INX H ; DOWN FROM BDOS DISK PARM BLOCK 067B EB XCHG ; TO OURS 067C 22A506 SHLD SPT 067F EB XCHG 0680 5E MOV E,M 0681 23 INX H 0682 EB XCHG 0683 22AC06 SHLD DRM 0686 EB XCHG 0687 7E MOV A,M 0688 23 INX H 0689 32A706 STA BSH 068C 7E MOV A,M 068D 23 INX H 068E 32A806 STA BLM 0691 5E MOV E,M 0692 23 INX H 0693 EB XCHG 0694 22AA06 SHLD DSM 0697 EB XCHG 0698 5E MOV E,M 0699 23 INX H 069A EB XCHG 069B 22AE06 SHLD AL0 069E EB XCHG 069F 5E MOV E,M 06A0 EB XCHG 06A1 22B206 SHLD SYSTRK 06A4 C9 RET ; ;-------------------------------------------------- ;THE DISK PARAMETER BLOCK ;IS MOVED HERE FROM CP/M ; 06A5 = DPB EQU $ ;DISK PARAMETER BLOCK (COPY) ; 06A5 SPT: DS 2 ;SECTORS PER TRACK 06A7 BSH: DS 1 ;BLOCK SHIFT 06A8 BLM: DS 1 ;BLOCK MASK 06A9 EXM: DS 1 ;EXTENT MASK 06AA DSM: DS 2 ;MAXIMUM BLOCK NUMBER 06AC DRM: DS 2 ;MAXIMUM DIRECTORY BLOCK NUMBER 06AE AL0: DS 1 ;DIRECTORY ALLOCATION VECTOR 06AF AL1: DS 1 ;DIRECTORY ALLOCATION VECTOR 06B0 CKS: DS 2 ;CHECKED DIRECTORY ENTRIES 06B2 SYSTRK: DS 2 ;SYSTEM TRACKS ; ;END OF DISK PARAMETER BLOCK ; 000F = DPBLEN EQU $-DPB ;LENGTH OF DISK PARM BLOCK ; ;-------------------------------------------------- 06B4 00 BLKEXT: DB 0 ;BLOCKS PER EXTENT 06B5 0000 DIRBKS: DW 0 ;CALCULATED # OF DIR BLOCKS 06B7 00 VER2FL: DB 0 ;VERSION 2.X FLAG ; 06B8 005B554E55BFCB: DB 0,'[UNUSED]BAD',0,0,0,0 06C8 FCBDM: DS 17 ; 06D9 4E6F24 NOMSG: DB 'No$' 06DC 2062616420ENDMSG: DB ' bad blocks found',CR,LF,'$' ; 06F0 0000 BADBKS: DW 0 ;COUNT OF BAD BLOCKS 06F2 0000 SECTOR: DW 0 ;CURRENT SECTOR NUMBER 06F4 0000 TRACK: DW 0 ;CURRENT TRACK NUMBER 06F6 0000 PHYSEC: DW 0 ;CURRENT PHYSICAL SECTOR NUMBER 06F8 0000 SECTBL: DW 0 ;SECTOR SKEW TABLE POINTER ; 06FA FF EXTNUM: DB 0FFH ;USED FOR UPDATING EXTENT NUMBER 06FB 0000 DMCNT: DW 0 ;NUMBER OF BAD SECTORS 06FD 5707 DMPTR: DW DM ;POINTER TO NEXT BLOCK ID ; 06FF 20746F7461SECMSG: DB ' total sectors read',CR,LF,'$' ; 0715 0000 SECCNT: DW 0 ;NUMBER OF SECTORS READ ; 0717 DS 64 ;ROOM FOR 32 LEVEL STACK 0757 = NEWSTK EQU $ ;OUR STACK 0757 = DM EQU $ ;BAD BLOCK ALLOCATION MAP ; 0757 END