home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol016 / findbd42.asm < prev    next >
Assembly Source File  |  1984-04-29  |  33KB  |  1,148 lines

  1. ;                   FINDBAD.ASM ver. 4.2
  2. ;             (revised 02/05/81)
  3. ;
  4. ;FINDBAD will find all bad blocks on a disk and build a file
  5. ;named [UNUSED].BAD to allocate them, thus "locking out" the
  6. ;bad blocks so CP/M will not use them.
  7. ;
  8. ;Originally written by Gene Cotton,  published in "Interface
  9. ;Age", September 1980 issue, page 80.
  10. ;
  11. ;This program now supports the following disk drives:
  12. ;
  13. ;    - STANDARD 8" SINGLE DENSITY
  14. ;    - MICROPOLIS MOD II
  15. ;    - MICROMATION DOUBLE DENSITY
  16. ;    - DIGITAL MICROSYSTEMS FDC3 DBL DENS
  17. ;    - IMSAI DOUBLE DENSITY (IMDOS)
  18. ;    - DISCUS 2D (SINGLE SIDED) 256/512/1024 BYTE SECTORS
  19. ;    - NATIONAL MULTIPLEX DD 1/2 SIDED 256/512 BYTE SECTORS
  20. ;    - HEATH H-17 5.25" SINGLE SIDED SINGLE DENSITY
  21. ;       - ICOM MICROFLOPPY 5.25" SINGLE SIDED, SINGLE DENSITY  
  22. ;       - JADE DOUBLE DENSITY/SINGLE SIDED
  23. ;    - NORTH STAR HORIZON DOUBLE DENSITY, SINGLE OR DOUBLE SIDED
  24. ;
  25. ;As presently set up, this program will perform properly on an
  26. ;8" single-density soft-sectored disk recorded in standard IBM
  27. ;format (i.e., 77 tracks, 26 sectors/track, 243 blocks/disk, 8
  28. ;sectors/block, 128 bytes/sector).  If your disk is not an IBM
  29. ;8" standard, then you must set the conditional assembly 
  30. ;switches to one of the defined disk systems or modify the 
  31. ;existing disk parameter definitions according to the 
  32. ;guidelines established in this documentation.  See notes
  33. ;below concerning 'TEST' conditional assembly option.
  34. ;
  35. ;NOTE: If you want to add conditional assembly for other disk
  36. ;systems, or otherwise update this program, make sure you have
  37. ;the latest version first.  After adding your changes, please
  38. ;modem a copy of the new file to "TECHNICAL CBBS" in Dearborn,
  39. ;Michigan - phone 313-846-6127 (110, 300, 450 or 600 baud).
  40. ;Use the filename FINDBAD.NEW.   (KBP)
  41. ;
  42. ;Revisions/modifications: (listed in reverse order
  43. ;to minimize reading time)
  44. ;
  45. ;02/05/81 Merged 2/2/81 and 1/24/81 changes, which were done
  46. ;      independently by Clyne and Mack.  (KBP)
  47. ;
  48. ;02/02/81 Added equates for North Star Horizon - 5.25" drives,
  49. ;      double density, single and double sided. (Bob Clyne)
  50. ;
  51. ;01/24/81 Added equates for Jade DD disk controller
  52. ;         (Pete H. Mack)
  53. ;
  54. ;01/19/81 Added equates for Icom Microfloppy 5.25" drives.
  55. ;         (Eddie Currie)
  56. ;
  57. ;01/05/81 Added equates for Heath H-17 5.25" drives.
  58. ;      (Ben Goldfarb)
  59. ;
  60. ;12/08/80 Added equates for National Multiplex D3S/D4S
  61. ;         double-density board in various formats.
  62. ;         (David Fiedler)
  63. ;
  64. ;09/22/80 Added equates for Morrow Disk Jockey 2D/SS, 256,
  65. ;      512 and 1024-byte sector options.  Fix 'S2' update
  66. ;      flag for larger max number of extents. Cleaned up
  67. ;      file. (Ben Bronson and KBP)
  68. ;
  69. ;09/14/80 Corrected DGROUP equate for MMDBL. Added new routine
  70. ;      to correct for IMDOS group allocation.  Corrected
  71. ;      error in instructions for using TEST routine.
  72. ;      (CHS) (AJ) (KBP) - (a group effort)
  73. ;
  74. ;09/08/80 Fixed several errors in Al Jewer's mods.  Changed
  75. ;      return to CP/M to warm boot so bitmap in memory will
  76. ;      be properly updated. Added conditional assembly for
  77. ;      testing program. (KBP)
  78. ;
  79. ;09/02/80 Added IMDOS double-density equates & modified for 
  80. ;      more then 256 blocks per disk. (Al Jewer)
  81. ;
  82. ;09/01/80 Changed equates so that parameters are automatically
  83. ;      set for each disk system conditional assembly (KBP)
  84. ;
  85. ;08/31/80 Add conditional assembly for Digital Microsystems FDC3
  86. ;      controller board in double-density format and fix to
  87. ;      do 256 blocks in one register. (Thomas V. Churbuck)
  88. ;
  89. ;08/31/80 Correct MAXB equate - MAXB must include the directory
  90. ;      blocks as well as the data blocks.  Fix to make sure
  91. ;      any [UNUSED].BAD file is erased before data area is
  92. ;      checked. (KBP)
  93. ;
  94. ;08/30/80 Added conditional assembly for Micromation
  95. ;      double-density format. (Charles H. Strom)
  96. ;
  97. ;08/27/80 Fix missing conditional assembly in FINDB routine.
  98. ;      Put version number in sign-on message. (KBP)
  99. ;
  100. ;08/26/80 Modified by Keith Petersen, W8SDZ, to:
  101. ;      (1) Add conditional assembly for 1k/2k groups
  102. ;      (2) Add conditional assembly for standard drives
  103. ;          and Micropolis MOD II
  104. ;      (3) Make compatible with CP/M-2.x
  105. ;      (4) Remove unneeded code to check for drive name
  106. ;          (CP/M does it for you and returns it in the FCB)
  107. ;      (5) Changed to open additional extents as needed for
  108. ;          overflow, instead of additional files
  109. ;      (6) Add conditional assembly for system tracks check
  110. ;          (some double-density disks have single-density
  111. ;          system tracks which cannot be read by this program)
  112. ;      (7) Increased stack area (some systems use more than
  113. ;          others).
  114. ;
  115. ;08/06/80 Added comments and crunched some code.
  116. ;      KELLY SMITH.  805-527-9321 (Modem, 300 Baud)
  117. ;            805-527-0518 (Verbal)
  118. ;
  119. ;
  120. ;            Using the Program
  121. ;
  122. ; Before  using this program to "reclaim" a diskette,  it  is
  123. ;recommended that the diskette be reformatted. If this is not
  124. ;possible,  at least assure yourself that any existing  files
  125. ;on the diskette  do not contain unreadable  sectors.  If you
  126. ;have changed disks since the last warm-boot, you  must warm-
  127. ;boot again before running this program.
  128. ;
  129. ; To  use the program,  insert  both the disk containing  the
  130. ;program  FINDBAD.COM and the diskette to be checked into the
  131. ;disk drives. It is possible that the diskette containing the
  132. ;program is the one to be checked. Assume that the program is
  133. ;on drive "A" and the suspected bad disk is on drive "B".  In
  134. ;response to the CP/M prompt "A>",  type in FINDBAD B:.  This
  135. ;will  load the file FINDBAD.COM from drive "A" and test  the
  136. ;diskette  on  drive "B" for  unreadable  sectors.  The  only
  137. ;allowable  parameter  after  the  program name  is  a  drive
  138. ;specification  (of the form " N:") for up to four (A  to  D)
  139. ;disk drives.  If no drive is specified, the currently logged
  140. ;in drive is assumed to contain the diskette to check.
  141. ;
  142. ; The  program first checks the CP/M System tracks (0 and 1),
  143. ;and  any  errors here prohibit the disk from being  used  on
  144. ;drive  "A",  since all "warm  boots" occur using the  system
  145. ;tracks from the "A" drive.
  146. ;
  147. ; The  program next checks the first two data blocks  (groups
  148. ;to some of us) containing the directory of the diskette.  If
  149. ;errors  occur  here,  the  program  terminates  and  control
  150. ;returns  to  CP/M  (no other data blocks are  checked  since
  151. ;errors in the directory render the disk useless).
  152. ;
  153. ; Finally,  all  the remaining data blocks are  checked.  Any
  154. ;sectors  which  are  unreadable cause the data  block  which
  155. ;contains them to be stored temporarily as a "bad block".  At
  156. ;the end of this phase,  the message "XX bad blocks found" is
  157. ;displayed (where XX is replaced by the number of bad blocks,
  158. ;or "No" if no read errors occur).  If bad blocks occur,  the
  159. ;filname [UNUSED].BAD is created, the list of "bad blocks" is
  160. ;placed  in  the allocation map of the  directory  entry  for
  161. ;[UNUSED].BAD,  and the file is closed.  Note,  that when the
  162. ;number of "bad blocks" exceeds 16,  the  program  will  open
  163. ;additional  extents  as  required  to  hold the overflow.  I
  164. ;suggest that if the diskette has more than  32 "bad blocks",
  165. ;perhaps it should be sent to the "big disk drive in the sky"
  166. ;for the rest it deserves.
  167. ;
  168. ; The  nifty part of all this is that if any "bad blocks"  do
  169. ;occur, they are allocated to [UNUSED].BAD and no longer will
  170. ;be available to CP/M for future allocation...bad sectors are
  171. ;logically locked out on the diskette!
  172. ;
  173. ;
  174. ;              Using the TEST conditional assembly
  175. ;
  176. ;A  conditional  assembly has been added to allow  testing  this 
  177. ;program  to  make sure it is reading all sectors on  your  disk 
  178. ;that  are accessible to CP/M.  The program reads the disk on  a 
  179. ;block by block basis, so it is necessary to first determine the 
  180. ;number of blocks present.  To start, we must know the number of 
  181. ;sectors/block (8 sectors/block for standard IBM single  density 
  182. ;format).  If  this  value  is  not  known,  it  can  easily  be 
  183. ;determined  by saving one page in a test file and interrogating 
  184. ;using the STAT command:
  185. ;
  186. ;    A>SAVE 1 TEST.SIZ
  187. ;    A>STAT TEST.SIZ
  188. ;
  189. ;For standard single-density STAT will report this file as being
  190. ;1k.  The file size reported (in bytes) is the size of a  block. 
  191. ;This  value  divided  by 128 bytes/sector  (the  standard  CP/M 
  192. ;sector  size)  will  give sectors/block.  For  our  IBM  single 
  193. ;density example, we have:
  194. ;
  195. ;  (1024 bytes/block) / (128 bytes/sector) = 8 sectors/block.
  196. ;
  197. ;We  can now calculate blocks/track (assuming we know the number 
  198. ;of sectors/track). In our example:
  199. ;
  200. ;  (26 sectors/track) / (8 sectors/block) = 3.25 blocks/track
  201. ;
  202. ;Now  armed with the total number of data tracks (75 in our  IBM 
  203. ;single density example), we get toatal blocks accessible: 
  204. ;
  205. ;  75 (tracks/disk) x (3.25 blocks/track) = 243.75 blocks/disk 
  206. ;
  207. ;CP/M cannot access a fractional block, so we round down (to 243 
  208. ;blocks  in  our  example).  Now  multiplying  total  blocks  by 
  209. ;sectors/block  results in total sectors as should  be  reported 
  210. ;when TEST is set TRUE and a good disk is read. For our example, 
  211. ;this value is 1944 sectors. 
  212. ;
  213. ;Finally,  note that if SYSTEM is set TRUE,  the sectors present 
  214. ;on  the  first  two tracks must be added in  as  well.  In  the 
  215. ;previous  example,  this  results in  1944 + 52 = 1996  sectors 
  216. ;reported by the TEST conditional.
  217. ;
  218. ;Run the program on a KNOWN-GOOD disk.  It should report that it
  219. ;has read  the  correct number of sectors.  The test conditional
  220. ;assembly should then be set FALSE and the program re-assembled.
  221. ;The test routines  cannot be left in  because this program does
  222. ;not read all the sectors in a block that is found to be bad and
  223. ;thus will report an inaccurate number of sectors read.
  224. ;
  225. ;
  226. ;Define TRUE and FALSE
  227. ;
  228. FALSE    EQU    0
  229. TRUE    EQU    NOT FALSE
  230. ;
  231. ;******************************************************************
  232. ;Conditional assembly switches (only one should be true)
  233. STDDRV    EQU    TRUE     ;TRUE IF STANDARD 8" SINGLE DENSITY DRIVE
  234. MICROP    EQU    FALSE    ;TRUE IF MICROPOLIS MOD II
  235. MMDBL    EQU    FALSE    ;TRUE IF MICROMATION DOUBLE DENSITY
  236. DIGDBL    EQU    FALSE    ;TRUE IF DIGITAL MICROSYSTEMS FDC3 DBL DENS
  237. IMDOS    EQU    FALSE     ;TRUE IF IMSAI DOUBLE DENSITY
  238. DJ256S    EQU    FALSE    ;TRUE IF MORROW 2D/SS  (256-BYTE SECTOR)
  239. DJ512S    EQU    FALSE    ;TRUE IF MORROW 2D/SS  (512-BYTE SECTOR)
  240. DJ1024    EQU    FALSE    ;TRUE IF MORROW 2D/SS (1024-BYTE SECTOR)
  241. NM256    EQU    FALSE    ;TRUE IF NATMUX 2D     (256-BYTE SECTOR)
  242. NM512    EQU    FALSE    ;TRUE IF NATMUX 2D     (512-BYTE SECTOR)
  243. H17    EQU    FALSE    ;TRUE IF HEATH H-17 5.25" SGL. DENS.
  244. ICOM    EQU    FALSE    ;TRUE IF ICOM MICROFLOPPY
  245. JADEDD    EQU    FALSE    ;TRUE IF JADE DD DISK CONTROLLER
  246. HORIZON    EQU    FALSE    ;TRUE IF NORTH STAR HORIZON
  247. ;******************************************************************
  248. ;
  249. ;Conditional assembly switch for double-sided drives
  250. ;(presently supported for National Multiplex and Horizon only)
  251. ;
  252. SIDES2    EQU    FALSE    ;TRUE FOR NATMUX D3S/D4S OR HORIZON DOUBLE SIDED ONLY
  253. ;
  254. ;******************************************************************
  255. ;
  256. ;Conditional assembly switch for testing this program
  257. ;(for initial testing phase only - see remarks above)
  258. ;
  259. TEST    EQU    FALSE    ;TRUE FOR TESTING ONLY
  260. ;******************************************************************
  261. ;
  262. ;System equates
  263. ;
  264. BASE    EQU    0    ;STANDARD CP/M BASE ADDRESS (4200H FOR ALTCPM)
  265. BDOS    EQU    BASE+5    ;CP/M WARM BOOT ENTRY
  266. FCB    EQU    BASE+5CH;CP/M DEFAULT FCB LOCATION
  267. ;
  268. ;Define disk system parameters
  269. ;
  270.     IF    STDDRV
  271. SYSTEM    EQU    TRUE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  272. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  273. SECTS    EQU    26    ;TOTAL NUMBER OF SECTORS/TRACK
  274. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  275. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  276. MAXB    EQU    243    ;MAX NUMBER OF BLOCKS (including directory)
  277. BLOCK    EQU    8    ;NUMBER OF SECTORS/BLOCK
  278. DGROUP    EQU    FALSE    ;TRUE IF 2k GROUP SIZE
  279.     ENDIF        ;STDDRV
  280. ;
  281.     IF    MICROP
  282. SYSTEM    EQU    TRUE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  283. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  284. SECTS    EQU    32    ;TOTAL NUMBER OF SECTORS/TRACK
  285. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  286. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  287. MAXB    EQU    150    ;MAX NUMBER OF BLOCKS (including directory)
  288. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  289. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  290.     ENDIF        ;MICROP
  291. ;
  292.     IF    MMDBL
  293. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  294. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  295. SECTS    EQU    52    ;TOTAL NUMBER OF SECTORS/TRACK
  296. DBASE    EQU    2    ;DATA AREA STARTING TRACK NUMBER
  297. BBASE    EQU    2    ;FIRST BLOCK FOR DATA
  298. MAXB    EQU    243    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  299. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  300. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  301.     ENDIF        ;MMDBL
  302. ;
  303.     IF    DIGDBL
  304. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  305. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  306. SECTS    EQU    58    ;TOTAL NUMBER OF SECTORS/TRACK
  307. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  308. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  309. MAXB    EQU    256    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  310. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  311. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  312.     ENDIF        ;DIGDBL
  313. ;
  314.     IF    IMDOS
  315. SYSTEM    EQU    FALSE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  316. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  317. SECTS    EQU    58    ;TOTAL NUMBER OF SECTORS/TRACK
  318. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  319. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  320. MAXB    EQU    271    ;MAX NUMBER OF BLOCKS (including directory)
  321. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  322. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  323.     ENDIF        ;IMDOS
  324. ;
  325.     IF    DJ256S OR NM256 AND NOT SIDES2
  326. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  327. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  328. SECTS    EQU    52    ;TOTAL NUMBER OF SECTORS/TRACK
  329. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  330. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  331. MAXB    EQU    243    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  332. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  333. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  334.     ENDIF        ;MORROW DJ256S OR NM256
  335. ;
  336.     IF    DJ512S OR NM512 AND NOT SIDES2
  337. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  338. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  339. SECTS    EQU    60    ;TOTAL NUMBER OF SECTORS/TRACK
  340. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  341. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  342. MAXB    EQU    281    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  343. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  344. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  345.     ENDIF        ;MORROW DJ512S OR NM512
  346. ;
  347.     IF    DJ1024
  348. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  349. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  350. SECTS    EQU    64    ;TOTAL NUMBER OF SECTORS/TRACK
  351. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  352. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  353. MAXB    EQU    300    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  354. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  355. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  356.     ENDIF        ;MORROW DJ1024
  357. ;
  358.     IF    NM256 AND SIDES2
  359. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  360. TRACKS    EQU    77 * 2    ;TOTAL NUMBER OF TRACKS/DISK
  361. SECTS    EQU    52    ;TOTAL NUMBER OF SECTORS/TRACK
  362. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  363. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  364. MAXB    EQU    487    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  365. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  366. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  367.     ENDIF        ;MORROW DJ256S OR NM256
  368. ;
  369.     IF    NM512 AND SIDES2
  370. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  371. TRACKS    EQU    77 * 2    ;TOTAL NUMBER OF TRACKS/DISK
  372. SECTS    EQU    60    ;TOTAL NUMBER OF SECTORS/TRACK
  373. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  374. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  375. MAXB    EQU    281 * 2    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  376. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  377. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  378.     ENDIF        ;MORROW DJ512S OR NM512
  379. ;
  380.     IF    H17
  381. SYSTEM    EQU    TRUE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  382. TRACKS    EQU    40    ;NUMBER OF TRACKS/DISK
  383. SECTS    EQU    20    ;NUMBER OF SECTS/TRACK
  384. DBASE    EQU    3    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  385. BBASE    EQU    1    ;FIRST BLOCK NUMBER FOR DATA
  386. MAXB    EQU    92    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  387. BLOCK    EQU    8    ;NUMBER OF SECTORS/BLOCK
  388. DGROUP    EQU    FALSE    ;TRUE IF 2k GROUP SIZE
  389.     ENDIF        ;H17
  390. ;
  391.     IF    ICOM
  392. SYSTEM    EQU    TRUE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  393. TRACKS    EQU    35    ;NUMBER OF TRACKS/DISK
  394. SECTS    EQU    18    ;NUMBER OF SECTS/TRACK
  395. DBASE    EQU    3    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  396. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA  
  397. MAXB    EQU    72    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  398. BLOCK    EQU    8    ;NUMBER OF SECTORS/BLOCK
  399. DGROUP    EQU    FALSE    ;TRUE IF 2k GROUP SIZE
  400.     ENDIF        ;ICOM
  401. ;
  402.     IF    JADEDD
  403. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  404. TRACKS    EQU    77    ;NUMBER OF TRACKS/DISK
  405. SECTS    EQU    50    ;NUMBER OF SECTORS/TRACK
  406. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  407. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  408. MAXB    EQU    233    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  409. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  410. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  411.     ENDIF        ;JADEDD
  412. ;
  413.     IF    HORIZON AND NOT SIDES2
  414. SYSTEM    EQU    TRUE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  415. TRACKS    EQU    35    ;TOTAL NUMBER OF TRACKS/DISK
  416. SECTS    EQU    40    ;TOTAL NUMBER OF SECTORS/TRACK
  417. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  418. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  419. MAXB    EQU    165    ;MAX NUMBER OF BLOCKS (including directory)
  420. BLOCK    EQU    8    ;NUMBER OF SECTORS/BLOCK
  421. DGROUP    EQU    FALSE    ;TRUE IF 2k GROUP SIZE
  422.     ENDIF        ;HORIZON
  423. ;
  424.     IF    HORIZON AND SIDES2
  425. SYSTEM    EQU    TRUE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  426. TRACKS    EQU    70    ;TOTAL NUMBER OF TRACKS/DISK
  427. SECTS    EQU    40    ;TOTAL NUMBER OF SECTORS/TRACK
  428. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  429. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  430. MAXB    EQU    170    ;MAX NUMBER OF BLOCKS (including directory)
  431. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  432. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  433.     ENDIF        ;HORIZON
  434. ;
  435. ;Define ASCII characters used
  436. ;
  437. CR    EQU    0DH    ;CARRIAGE RETURN CHARACTER
  438. LF    EQU    0AH    ;LINE FEED CHARACTER
  439. TAB    EQU    09H    ;TAB CHARACTER
  440. ;
  441. ;
  442.     ORG    BASE+100H
  443. ;
  444. START:    LXI    SP,NEWSTK ;MAKE NEW STACK
  445. ;
  446.     IF    IMDOS
  447.     XRA    A
  448.     OUT    0FFH    ;CLEAR FRONT PANEL
  449.     ENDIF        ;IMDOS
  450. ;
  451.     LXI    D,IDMSG    ;IDENT MESSAGE
  452.     CALL    START2    ;GO PRINT IT
  453. ;
  454. IDMSG:    DB    CR,LF,'FINDBAD - ver 4.2'
  455.     DB    CR,LF,'Bad sector lockout '
  456.     DB    'program',CR,LF
  457. ;
  458.     IF    STDDRV
  459.     DB    'For single-density 8"'
  460.     ENDIF
  461. ;
  462.     IF    MICROP
  463.     DB    'For Micropolis Mod II'
  464.     ENDIF
  465. ;
  466.     IF    MMDBL
  467.     DB    'For Micromation double-density'
  468.     ENDIF
  469. ;
  470.     IF    DIGDBL
  471.     DB    'For Digital Microsystems',CR,LF
  472.     DB    'FDC3 cntlr dbl dens'
  473.     ENDIF
  474. ;
  475.     IF    IMDOS
  476.     DB    'For IMSAI IMDOS double-density'
  477.     ENDIF
  478. ;
  479.     IF    DJ256S
  480.     DB    'For Discus 2-dens./1-side/256-byte sectors'
  481.     ENDIF
  482. ;
  483.     IF    DJ512S
  484.     DB    'For Discus 2-dens./1-side/512-byte sectors'
  485.     ENDIF
  486. ;
  487.     IF    DJ1024
  488.     DB    'For Discus 2-dens./1-side/1024-byte sectors'
  489.     ENDIF
  490. ;
  491.     IF    NM256 OR NM512
  492.     DB    'For National Multiplex double density'
  493.     ENDIF
  494. ;
  495.     IF    HORIZON
  496.     DB    'For North Star Horizon - 5.25" drives, double density,'
  497.     ENDIF
  498. ;
  499.     IF    SIDES2 AND (NM256 OR NM512 OR HORIZON)
  500.     DB    ' double sided'
  501.     ENDIF
  502. ;
  503.     IF    NOT SIDES2 AND (NM256 OR NM512 OR HORIZON)
  504.     DB    ' single sided'
  505.     ENDIF
  506. ;    
  507.     IF    NM256
  508.     DB    ' 256-byte sectors'
  509.     ENDIF
  510. ;
  511.     IF    NM512
  512.     DB    ' 512-byte sectors'
  513.     ENDIF
  514. ;
  515.     IF    H17
  516.     DB    'For Heath H-17 5.25" drives'
  517.     ENDIF
  518. ;
  519.     IF    ICOM
  520.     DB    'For ICOM Microfloppy'
  521.     ENDIF
  522. ;
  523.     IF    JADEDD
  524.     DB    'For Jade Double Density/Single Sided'
  525.     ENDIF
  526. ;
  527.     DB    ' only.',CR,LF,'$'
  528. ;
  529. START2    POP    D    ;GET MSG ADRS
  530.     MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  531.     CALL    BDOS    ;PRINT SIGN-ON MSG
  532.     CALL    IBIOS    ;SET BIOS ENTRY, AND CHECK DRIVE
  533.     CALL    FINDB    ;ESTABLISH ALL BAD BLOCKS
  534.     JZ    NOBAD    ;SAY NO BAD BLOCKS, IF SO
  535.     CALL    OPENB    ;OPEN [UNUSED].BAD ALLOCATION
  536.     CALL    SETDM    ;FIX DM BYTES IN FCB
  537.     CALL    CLOSEB    ;CLOSE [UNUSED].BAD
  538.     CALL    SETNUM    ;PUT NUMBER OF BAD BLOCKS IN MESSAGE
  539. ;
  540. NOBAD:    LXI    D,ENDMSG ;SAY HOW MANY BAD BLOCKS
  541. ;
  542. PMSG:    MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  543.     CALL    BDOS
  544. ;
  545.     IF    TEST
  546.     MVI    A,TAB    ;GET A TAB
  547.     CALL    TYPE    ;PRINT IT
  548.     LHLD    SECCNT    ;GET NUMBER OF SECTORS READ
  549.     CALL    DECOUT    ;PRINT IT
  550.     LXI    D,SECMSG ;POINT TO MESSAGE
  551.     MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  552.     CALL    BDOS    ;PRINT IT
  553.     ENDIF        ;TEST
  554. ;
  555.     IF    IMDOS
  556.     XRA    A
  557.     OUT    0FFH    ;CLEAR FRONT PANEL
  558.     ENDIF        ;IMDOS
  559. ;
  560.     JMP    BASE    ;EXIT TO CP/M WARM BOOT
  561. ;
  562. ;Get actual address of BIOS routines
  563. ;
  564. IBIOS:    LHLD    BASE+1    ;GET BASE ADDRESS OF BIOS VECTORS
  565. ;
  566. ;WARNING...Program modification takes place here...do not change.
  567. ;
  568.     LXI    D,27     ;OFFSET TO "SETTRK"
  569.     DAD    D
  570.     SHLD    SETTRK+1 ;FIX OUR CALL ADDRESS
  571.     LXI    D,3     ;OFFSET TO "SETSEC"
  572.     DAD    D
  573.     SHLD    SETSEC+1 ;FIX OUR CALL ADDRESS
  574.     LXI    D,6     ;OFFSET TO "DREAD"
  575.     DAD    D
  576.     SHLD    DREAD+1     ;FIX OUR CALL ADDRESS
  577. ;
  578. ;Check for drive specification
  579. ;
  580.     LDA    FCB    ;GET DRIVE NAME
  581.     ORA    A    ;ZERO?
  582.     RZ        ;YES, NO DRIVE CHANGE REQUIRED
  583.     CPI    4+1    ;CHECK FOR HIGHEST DRIVE NUMBER
  584.     JNC    ERROR4
  585.     DCR    A    ;BACK OFF FOR CP/M
  586.     MOV    E,A    ;MAKE DISK NUMBER
  587.     MVI    C,14    ;BDOS SELECT DISK FUNCTION
  588.     CALL    BDOS
  589.     RET        ;RETURN FROM "IBIOS"
  590. ;
  591. ;Look for bad blocks
  592. ;
  593. FINDB:    EQU    $
  594. ;
  595.     IF    SYSTEM
  596.     CALL    CHKSYS    ;CHECK FOR BAD BLOCKS ON TRACK 0 AND 1
  597.     ENDIF        ;SYSTEM
  598. ;
  599.     CALL    CHKDIR    ;CHECK FOR BAD BLOCKS IN DIRECTORY
  600.     CALL    ERAB    ;ERASE ANY [UNUSED].BAD FILE
  601.     LXI    B,BBASE    ;START AT FIRST DATA BLOCK
  602. ;
  603. FINDBA:    CALL    READB    ;READ THE BLOCK
  604.     CNZ    SETBD    ;IF BAD, ADD BLOCK TO LIST
  605.     INX    B    ;BUMP TO NEXT BLOCK
  606.     MOV    A,C    ;SEE IF MORE TO CHECK
  607.     CPI    MAXB AND 0FFH
  608.     JNZ    FINDBA
  609.     MOV    A,B    ;THEN CHECK HI BYTE
  610.     CPI    MAXB SHR 8
  611.     JNZ    FINDBA    ;LOOP TILL DONE    
  612.     LHLD    DMCNT    ;GET NUMBER OF BAD SECTORS
  613.     MOV    A,H
  614.     ORA    L    ;SET ZERO FLAG, IF NO BAD BLOCKS
  615.     RET        ;RETURN FROM "FINDB"
  616. ;
  617.     IF    SYSTEM
  618. ;
  619. ;Check system tracks, notify user if bad, but continue
  620. ;
  621. CHKSYS:    LXI    H,1    ;SET TRACK 0, SECTOR 1
  622. ;
  623. CHKSY1:    CALL    READS    ;READ A SECTOR
  624.     JNZ    SYSERR    ;NOTIFY, IF BAD BLOCKS HERE
  625.     MOV    A,H    ;BOTH SYSTEM TRACKS DONE?
  626.     CPI    DBASE
  627.     JC    CHKSY1
  628.     RET        ;RETURN FROM "CHKSYS"
  629. ;
  630. SYSERR:    LXI    D,ERMSG5 ;SAY NO GO, AND BAIL OUT
  631.     MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  632.     CALL    BDOS
  633.     RET        ;RETURN FROM "SYSERR"
  634. ;
  635.     ENDIF        ;SYSTEM
  636. ;
  637. ;Check for bad blocks in directory area
  638. ;
  639. CHKDIR:    LXI    B,0    ;START AT BLOCK 0
  640. ;
  641. CHKDI1:    CALL    READB    ;READ A BLOCK
  642.     JNZ    ERROR6    ;IF BAD, INDICATE ERROR IN DIRECTORY AREA
  643.     INX    B    ;BUMP FOR NEXT BLOCK
  644.     MOV    A,C    ;GET BLOCK NUMBER
  645.     CPI    BBASE    ;ALL DONE CHECKING DIRECTORY AREA?
  646.     JC    CHKDI1    ;PRESS ON, IF NOT
  647.     RET        ;RETURN FROM "CHKDIR"
  648. ;
  649. ;Read all sectors in block, and return zero flag set if none bad
  650. ;
  651. READB:    CALL    CNVRTB    ;CONVERT TO TRACK/SECTOR IN H&L REGS.
  652.     MVI    D,BLOCK    ;NUMBER OF SECTORS/BLOCK
  653. ;
  654. READBA:    PUSH    D
  655.     CALL    READS    ;READ SKEWED SECTOR
  656.     POP    D
  657.     RNZ        ;ERROR IF NOT ZERO...
  658.     DCR    D    ;DEBUMP SECTOR/BLOCK
  659.     JNZ    READBA    ;DO NEXT, IF NOT FINISHED
  660.     RET        ;RETURN FROM "READBA"
  661. ;
  662. ;Convert block number to track and skewed sector number
  663. ;
  664. CNVRTB:    PUSH    B    ;SAVE BLOCK NUMBER
  665.     MOV    L,C    ;BLOCK NUMBER TO H&L REGS.
  666.     MOV    H,B
  667.     DAD    H    ;*2
  668.     DAD    H    ;*4
  669.     DAD    H    ;*8
  670. ;
  671.     IF    DGROUP
  672.     DAD    H    ;*16 FOR 2k GROUP SIZE
  673.     ENDIF        ;DGROUP
  674. ;
  675.     LXI    D,DBASE*256    ;MAKE BASE TRACK NUMBER
  676.     LXI    B,-SECTS    ;DIVIDE BY SECTORS/TRACK
  677. ;
  678. CNVRTC:    MOV    A,H    ;OVER SECTORS...
  679.     ORA    A
  680.     JNZ    CNVRTT    ;...BYE GROUPS?
  681.     MOV    A,L    ;OVER SECTORS...
  682.     CPI    SECTS
  683.     JC    CNVRTS    ;...AND DOWN TO TRACKS?
  684. ;
  685. CNVRTT:    DAD    B    ;TAKE AWAY SECTORS
  686.     INR    D    ;+1 TO TRACK NUMBER
  687.     JMP    CNVRTC    ;...AND GO BACK FOR MORE
  688. ;
  689. CNVRTS:    MOV    E,L    ;RESIDUAL = SKEWED SECTOR-1
  690.     INR    E    ;BUMP FOR SECTORS 1 TO 32
  691.     XCHG        ;TRACK/SECTOR IN H&L REGS.
  692.     POP    B    ;RECOVER BLOCK NUMBER
  693.     RET        ;RETURN FROM "CNVRTB"
  694. ;
  695. ;Reads a logical sector (if it can), and returns zero flag set if no error
  696. ;
  697. READS:    PUSH    B    ;EXILE BLOCK
  698.     PUSH    H    ;...AND TRACK/SECTOR
  699.     CALL    LTOP    ;CONVERT LOGICAL TO PHYSICAL SECTOR
  700.     PUSH    H    ;SAVE SECTOR NUMBER
  701.     MOV    C,H    ;TRACK NUMBER IN H REG...
  702. ;
  703. SETTRK:    CALL    $-$    ;BIOS SET TRACK (MODIFIED BY IBIOS)
  704.     POP    B    ;PUT SECTOR IN C
  705. ;
  706. SETSEC:    CALL    $-$    ;BIOS SET SECTOR (MODIFIED BY IBIOS)
  707. ;
  708. DREAD:    CALL    $-$    ;BIOS READ SECTOR (MODIFIED BY IBIOS)
  709.     ORA    A    ;SET FLAGS FOR POSSIBLE BAD SECTOR
  710. ;
  711.     IF    TEST
  712.     LHLD    SECCNT    ;GET NUMBER OF SECTORS READ
  713.     INX    H    ;INCREMENT
  714.     SHLD    SECCNT    ;SAVE NEW NUMBER
  715.     ENDIF        ;TEST
  716. ;
  717.     POP    H
  718.     POP    B    ;BACK FROM EXILE...
  719.     PUSH    PSW    ;SAVE FLAGS
  720.     INR    L    ;BUMP FOR NEXT SECTOR
  721.     MOV    A,L
  722.     CPI    SECTS+1    ;TRACK OVERFLOW?
  723.     JC    READSR
  724.     MVI    L,1    ;YUP, RESET SECTOR NUMBER TO 1...
  725.     INR    H    ;...AND BUMP TRACK NUMBER
  726. ;
  727. READSR:    POP    PSW    ;GET FLAGS, TO CHECK IF ERROR ON RETURN
  728.     RET        ;RETURN FROM "READS"
  729. ;
  730. ;Convert logical to physical sector
  731. ;
  732. LTOP:    XCHG
  733.     LXI    B,LPMAP-1 ;GET BASE OF LOGICAL TO PHYSICAL MAPPING
  734.     MOV    L,E
  735.     MVI    H,0    ;LOGICAL SECTOR OFFSET
  736.     DAD    B    ;+ BIAS
  737.     MOV    E,M    ;GET PHYSICAL SECTOR
  738.     XCHG        ;PUT H&L REGS. BACK...
  739.     RET        ;RETURN FROM "LTOP"
  740. ;
  741. ;Logical to physical mapping vectors (sector skew table)
  742. ;
  743.     IF    STDDRV
  744. LPMAP:    DB    01,07,13,19,25,05,11,17,23,03,09,15,21
  745.     DB    02,08,14,20,26,06,12,18,24,04,10,16,22
  746.     ENDIF        ;STDDRV
  747. ;
  748.     IF    MICROP
  749. LPMAP:    DB    01,02,11,12,21,22,31,32,09,10,19,20,29,30,07,08
  750.     DB    17,18,27,28,05,06,15,16,25,26,03,04,13,14,23,24
  751.     ENDIF        ;MICROP
  752. ;
  753.     IF    MMDBL
  754. LPMAP:    DB    01,14,27,40,10,23,36,49,06,19,32,45,02,15,28,41
  755.     DB    11,24,37,50,07,20,33,46,03,16,29,42,12,25,38,51
  756.     DB    08,21,34,47,04,17,30,43,13,26,39,52,09,22,35,48
  757.     DB    05,18,31,44
  758.     ENDIF        ;MMDBL
  759. ;
  760.     IF    DIGDBL
  761. LPMAP:    DB    01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16
  762.     DB    17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
  763.     DB    33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48
  764.     DB    49,50,51,52,53,54,55,56,57,58
  765.     ENDIF        ;DIGDBL
  766. ;
  767.     IF    IMDOS
  768. LPMAP:    DB    1,8,15,22,29,36,43,50,57,6,13,20,27,34,41,48,55
  769.     DB    4,11,18,25,32,39,46,53,2,9,16,23,30,37,44,51,58
  770.     DB    7,14,21,28,35,42,49,56,5,12,19,26,33,40,47,54
  771.     DB    3,10,17,24,31,38,45,52
  772.     ENDIF        ;IMDOS
  773. ;
  774.     IF    DJ256S
  775. LPMAP:    DB    01,02,19,20,37,38,03,04,21,22,39,40,05,06,23,24
  776.     DB    41,42,07,08,25,26,43,44,09,10,27,28,45,46,11,12
  777.     DB    29,30,47,48,13,14,31,32,49,50,15,16,33,34,51,52
  778.     DB    17,18,35,36
  779.     ENDIF        ;DJ256S
  780. ;
  781.     IF    NM256
  782. LPMAP:    DB    01,02,23,24,45,46,15,16,37,38,07,08,29,30,51,52
  783.     DB    21,22,43,44,13,14,35,36,05,06,27,28,49,50,19,20
  784.     DB    41,42,11,12,33,34,03,04,25,26,47,48,17,18,39,40
  785.     DB    09,10,31,32
  786.     ENDIF        ;NM256
  787. ;
  788.     IF    DJ512S OR NM512
  789. LPMAP:    DB    01,02,03,04,17,18,19,20,33,34,35,36,49,50,51,52
  790.     DB    05,06,07,08,21,22,23,24,37,38,39,40,53,54,55,56
  791.     DB    09,10,11,12,25,26,27,28,41,42,43,44,57,58,59,60
  792.     DB    13,14,15,16,29,30,31,32,45,46,47,48
  793.     ENDIF        ;DJ512S or NM512
  794. ;
  795.     IF    DJ1024
  796. LPMAP:    DB    01,02,03,04,05,06,07,08,25,26,27,28,29,30,31,32
  797.     DB    49,50,51,52,53,54,55,56,09,10,11,12,13,14,15,16
  798.     DB    33,34,35,36,37,38,39,40,57,58,59,60,61,62,63,64
  799.     DB    17,18,19,20,21,22,23,24,41,42,43,44,45,46,47,48
  800.     ENDIF        ;DJ1024
  801. ;
  802.     IF    H17
  803. LPMAP:    DB    01,02,09,10,17,18,05,06,13,14,03,04,11,12,19,20
  804.     DB    07,08,15,16
  805.     ENDIF        ;H17
  806. ;
  807.     IF    ICOM
  808. LPMAP:    DB    01,05,09,13,17,04,08,12,16,03,07,11,15,02,06,10
  809.     DB    14,18
  810.     ENDIF        ;ICOM
  811. ;
  812.     IF    JADEDD
  813. LPMAP:    DB    01,11,21,31,41,02,12,22,32,42,03,13,23,33,43
  814.     DB    04,14,24,34,44,05,15,25,35,45,06,16,26,36,46
  815.     DB    07,17,27,37,47,08,18,28,38,48,09,19,29,39,49
  816.     DB    10,20,30,40,50
  817.     ENDIF        ;JADEDD
  818. ;
  819.     IF    HORIZON
  820. LPMAP:    DB    01,02,03,04,21,22,23,24
  821.     DB    05,06,07,08,25,26,27,28
  822.     DB    09,10,11,12,29,30,31,32
  823.     DB    13,14,15,16,33,34,35,36
  824.     DB    17,18,19,20,37,38,39,40
  825.     ENDIF        ;HORIZON    
  826. ;
  827. ;Put bad block in bad block list
  828. ;
  829. SETBD:    LHLD    DMCNT    ;GET NUMBER OF SECTORS
  830.     LXI    D,BLOCK
  831.     DAD    D    ;BUMP BY NUMBER IN THIS BLOCK
  832.     SHLD    DMCNT    ;UPDATE NUMBER OF SECTORS
  833.     LHLD    DMPTR    ;GET POINTER INTO DM
  834.     MOV    M,C    ;...AND PUT BAD BLOCK NUMBER
  835.     INX    H    ;BUMP TO NEXT AVAILABLE EXTENT
  836. ;
  837.     IF    IMDOS OR DJ512S OR DJ1024 OR NM256 OR NM512
  838.     MOV    M,B    ;PUT IN 2ND BYTE FOR IMDOS OR DJ512/1024
  839.     INX    H    ;POINT TO NEXT AVAILABLE EXTENT
  840.     ENDIF        ;IMDOS OR DJ512S OR DJ1024 OR NM256 OR NM512
  841. ;
  842.     SHLD    DMPTR    ;SAVE DM POINTER, FOR NEXT TIME THROUGH HERE
  843.     RET        ;RETURN FROM "SETBD"
  844. ;
  845. ;Eliminate any previous [UNUSED].BAD entries
  846. ;
  847. ERAB:    LXI    D,BFCB    ;POINT TO BAD FCB
  848.     MVI    C,19    ;BDOS DELETE FILE FUNCTION
  849.     CALL    BDOS
  850.     RET
  851. ;
  852. ;Create [UNUSED].BAD file entry
  853. ;
  854. OPENB:    LXI    D,BFCB    ;POINT TO BAD FCB
  855.     PUSH    D    ;SAVE IT...
  856.     MVI    C,22    ;BDOS MAKE FILE FUNCTION
  857.     CALL    BDOS
  858.     POP    D    ;RECOVER BAD FCB POINTER
  859.     MVI    C,15    ;BDOS OPEN FILE FUNCTION
  860.     CALL    BDOS
  861.     CPI    0FFH    ;CHECK FOR OPEN ERROR
  862.     RNZ        ;RETURN FROM "OPENB", IF NO ERROR
  863.     JMP    ERROR7    ;BAIL OUT...CAN'T CREATE [UNUSED].BAD
  864. ;
  865. ;Move bad area DM to BFCB
  866. ;
  867. SETDM:    LXI    H,DM    ;GET DM
  868.     SHLD    DMPTR    ;SAVE AS NEW POINTER
  869.     LHLD    DMCNT    ;GET THE COUNT
  870. ;
  871. SETDM0:    MOV    A,H
  872.     ORA    A
  873.     JNZ    GOBIG
  874.     MOV    A,L
  875.     CPI    129    ;ALL BYTES MOVED?
  876.     JC    SETDME
  877. ;
  878. GOBIG:    LXI    D,-128
  879.     DAD    D
  880.     PUSH    H
  881.     MVI    A,128
  882.     CALL    SETDME
  883.     XCHG
  884.     SHLD    DMPTR
  885.     CALL    CLOSEB    ;CLOSE OLD EXTENT
  886.     LDA    EXTNUM    ;GET OLD EXTENT NUMBER
  887.     INR    A    ;INCREMENT IT
  888.     STA    EXTNUM    ;SAVE NEW EXTENT NUMBER
  889.     STA    BFCB+12    ;PUT NEW EXTENT NUMBER INTO OUR FCB
  890.     CALL    OPENB    ;OPEN NEW EXTENT
  891.     POP    H
  892.     JMP    SETDM0
  893. ;
  894. SETDME:    STA    BFCB+15    ;PUT RC IN PLACE
  895.     IF    NOT DGROUP
  896.     MVI    B,16    ;NUMBER OF BYTES TO MOVE
  897.     ENDIF        ;NOT DGROUP
  898. ;
  899.     IF    DGROUP
  900.     MVI    B,8    ;NUMBER OF BYTES TO MOVE
  901.     ENDIF        ;DGROUP
  902. ;
  903.     LHLD    DMPTR    ;GET BAD DMAP POINTER
  904.     XCHG        ;TO DE
  905.     LXI    H,BFCB+16 ;POINT AT OUR FCB
  906. ;
  907. SETDML:    EQU    $
  908. ;
  909.     IF    NOT IMDOS
  910.     LDAX    D    ;GET BYTE FROM DMAP
  911.     MOV    M,A    ;MOVE TO OUR FCB
  912.     INX    D    ;INCREMENT DMAP POINTER
  913.     INX    H    ;INCREMENT OUR FCB POINTER
  914.     ENDIF        ;NOT IMDOS (1 BYTE GROUP #)
  915. ;
  916.     IF    DJ512S OR DJ1024 OR NM256 OR NM512
  917.     LDAX    D    ;GET SECOND BYTE FROM DMAP
  918.     MOV    M,A    ;MOVE TO OUR FCB
  919.     INX    D    ;INCREMENT DMAP POINTER
  920.     INX    H    ;INCREMENT OUR FCB POINTER
  921.     ENDIF        ;DJ512S OR DJ1024 OR NMXXXDS (2 BYTE GROUP #)
  922. ;
  923.     IF    IMDOS
  924.     LDAX    D    ;GET FIRST (LO ORDER) BYTE FROM DMAP
  925.     MOV    C,A    ;SAVE IT IN C
  926.     INX    D    ;INCREMENT DMAP POINTER
  927.     LDAX     D    ;THEN GET SECOND (HI ORDER) BYTE
  928.     MOV    M,A    ;STORE HI BYTE FIRST
  929.     INX    H    ;INCREMENT FCB POINTER
  930.     MOV    M,C    ;THEN LO BYTE FOR 16-BIT POINTER
  931.     INX    H    ;INCREMENT OUR FCB POINTER
  932.     ENDIF        ;IMDOS (2 BYTE GROUP #)
  933. ;
  934.     DCR    B    ;ONE LESS BYTE TO MOVE
  935.     JNZ    SETDML    ;NOT DONE, GO MOVE MORE
  936.     RET        ;ELSE RETURN FROM "SETDM"
  937.  
  938. ;
  939. CLOSEB:    XRA    A
  940.     LDA    BFCB+14    ;GET CP/M 2.x 'S2' BYTE
  941.     ANI    1FH    ;ZERO UPDATE FLAGS
  942.     STA    BFCB+14    ;RESTORE IT TO OUR FCB (WON'T HURT 1.4)
  943.     LXI    D,BFCB    ;FCB FOR [UNUSED].BAD
  944.     MVI    C,16    ;BDOS CLOSE FILE FUNCTION
  945.     CALL    BDOS
  946.     RET        ;RETURN FROM "CLOSEB"
  947. ;
  948. ;Convert number of blocks to decimal ASCII, for printing
  949. ;
  950. SETNUM:    LHLD    DMCNT    ;GET NUMBER OF SECTORS
  951.     DAD    H    ;*2
  952.     DAD    H    ;*4
  953.     DAD    H    ;*8
  954.     DAD    H    ;*16
  955. ;
  956.     IF    NOT DGROUP
  957.     DAD    H    ;*32 FOR 1k GROUP SIZE
  958.     ENDIF
  959. ;
  960. ;H reg now equals number of blocks
  961.     LXI    D,255
  962.     DAD    D    ;ROUND UP
  963.     MOV    L,H
  964.     MVI    H,0    ;NOW HL=NUMBER OF BLOCKS
  965.     LXI    D,NUMBAD
  966.     CALL    DCNV
  967.     RET        ;RETURN FROM "SETNUM"
  968. ;
  969. DCNV:    MVI    B,' '    ;SET FOR PLUS
  970.     MOV    A,H
  971.     ORA    A
  972.     JP    H3
  973.     MVI    B,'-'
  974.     MOV    A,L
  975.     CMA
  976.     INR    A
  977.     MOV    L,A
  978.     MOV    A,H
  979.     CMA
  980.     JNZ    H2
  981.     INR    A
  982. ;
  983. H2:    MOV    H,A
  984. ;
  985. H3:    SHLD    DCNVHL
  986.     MVI    A,' '
  987.     STAX    D
  988.     MOV    A,B
  989.     STA    DCNVPM
  990.     XCHG
  991.     SHLD    DCNVAD
  992.     XRA    A
  993.     STA    DCNVFL
  994.     LXI    B,-10000
  995.     CALL    DFL8
  996.     CALL    DSTC
  997.     LXI    B,-1000
  998.     CALL    DFL8
  999.     CALL    DSTC
  1000.     LXI    B,-100
  1001.     CALL    DFL8
  1002.     CALL    DSTC
  1003.     LXI    B,-10
  1004.     CALL    DFL8
  1005.     CALL    DSTC
  1006.     LDA    DCNVHL
  1007.     ORI    '0'
  1008.     MOV    E,A
  1009. ;
  1010. DSTC:    LHLD    DCNVAD
  1011.     LDA    DCNVFL
  1012.     ORA    A
  1013.     JNZ    DSTC3
  1014. ;
  1015. DSTC1:    ADD    E
  1016.     STA    DCNVFL
  1017.     JNZ    DSTC2
  1018.     MVI    A,' '
  1019.     JMP    DSTC4
  1020. ;
  1021. DSTC2:    LDA    DCNVPM
  1022.     MOV    M,A
  1023. ;
  1024. DSTC3:    MVI    A,'0'
  1025.     ORA    E
  1026. ;
  1027. DSTC4:    INX    H
  1028.     MOV    M,A
  1029.     SHLD    DCNVAD
  1030.     RET        ;RETURN FROM "SETDM"
  1031. ;
  1032. DCNVFL:    DB    0
  1033. DCNVHL:    DW    0
  1034. DCNVAD:    DW    0
  1035. DCNVPM:    DB    0
  1036. ;
  1037. DFL8:    LHLD    DCNVHL
  1038.     MVI    E,0
  1039. ;
  1040. DF1:    DAD    B
  1041.     MOV    A,H
  1042.     ORA    A
  1043.     RM
  1044.     INR    E
  1045.     SHLD    DCNVHL
  1046.     JMP    DF1
  1047. ;
  1048. BFCB:    DB    0,'[UNUSED]BAD',0,0,0,0
  1049.     DS    17
  1050. ;
  1051. ENDMSG:    DB    CR,LF,'    '
  1052. ;
  1053. NUMBAD:    DB    '    No'
  1054.     DB    ' bad blocks found',CR,LF,'$'
  1055. ;
  1056. EXTNUM:    DB    0    ;USED IF MORE THAN 16 BAD BLOCKS
  1057. DMCNT:    DW    0    ;NUMBER OF BAD SECTORS
  1058. DMPTR:    DW    DM    ;POINTER TO NEXT BLOCK ID
  1059. ;
  1060. ;Allocation map for bad blocks
  1061. ;
  1062. DM:    DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1063.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1064.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1065.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1066.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1067.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1068.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1069.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1070.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1071.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1072.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1073.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1074.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1075.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1076.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1077.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  1078. ;
  1079. ;Error messages
  1080. ;
  1081. ERROR4:    LXI    D,ERMSG4 ;SAY NO GO, AND BAIL OUT
  1082.     JMP    PMSG
  1083. ;
  1084. ERMSG4:    DB    CR,LF,'Only drives A to D allowed$'
  1085. ;
  1086.     IF    SYSTEM
  1087. ERMSG5:    DB    CR,LF,'Warning...System tracks bad$'
  1088.     ENDIF        ;SYSTEM
  1089. ;
  1090. ERROR6:    LXI    D,ERMSG6 ;OOPS...CLOBBERED DIRECTORY
  1091.     JMP    PMSG
  1092. ;
  1093. ERMSG6:    DB    CR,LF,'Bad directory area, try reformatting$'
  1094. ;
  1095. ERROR7:    LXI    D,ERMSG7 ;SAY NO GO, AND BAIL OUT
  1096.     JMP    PMSG
  1097. ;
  1098. ERMSG7:    DB    CR,LF,'Can''t create [UNUSED].BAD$'
  1099. ;
  1100.     IF    TEST
  1101. ;
  1102. ;Decimal output routine
  1103. ;
  1104. DECOUT:    PUSH    B
  1105.     PUSH    D
  1106.     PUSH    H
  1107.     LXI    B,-10
  1108.     LXI    D,-1
  1109. ;
  1110. DECOU2:    DAD    B
  1111.     INX    D
  1112.     JC    DECOU2
  1113.     LXI    B,10
  1114.     DAD    B
  1115.     XCHG
  1116.     MOV    A,H
  1117.     ORA    L
  1118.     CNZ    DECOUT
  1119.     MOV    A,E
  1120.     ADI    '0'
  1121.     CALL    TYPE
  1122.     POP    H
  1123.     POP    D
  1124.     POP    B
  1125.     RET
  1126. ;
  1127. TYPE:    PUSH    B
  1128.     PUSH    D
  1129.     PUSH    H
  1130.     MOV    E,A    ;CHARACTER TO E FOR CP/M
  1131.     MVI    C,2    ;PRINT CONSOLE FUNCTION
  1132.     CALL    BDOS    ;PRINT CHARACTER
  1133.     POP    H
  1134.     POP    D
  1135.     POP    B
  1136.     RET
  1137. ;
  1138. SECMSG:    DB    ' total sectors read',CR,LF,'$'
  1139. ;
  1140. SECCNT:    DW    0    ;NUMBER OF SECTORS READ
  1141. ;
  1142.     ENDIF        ;TEST
  1143. ;
  1144.     DS    64    ;ROOM FOR 32 LEVEL STACK
  1145. NEWSTK    EQU    $    ;OUR STACK
  1146. ;
  1147.     END
  1148.