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

  1. ;
  2. ;                   FINDBAD.ASM Ver. 3.8
  3. ;            revised 12/08/80
  4. ;
  5. ;FINDBAD WILL FIND ALL BAD BLOCKS ON A DISK AND BUILD A FILE
  6. ;NAMED [UNUSED].BAD TO ALLOCATE THEM, THUS "LOCKING OUT" THE
  7. ;BAD BLOCKS SO CP/M WILL NOT USE THEM.
  8. ;
  9. ;Originally written by Gene Cotton,  published in "Interface
  10. ;Age", September 1980 issue, page 80.
  11. ;
  12. ;THIS PROGRAM NOW SUPPORTS THE FOLLOWING DISK DRIVES:
  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. ;
  21. ;AS PRESENTLY SET UP, THIS PROGRAM WILL PERFORM PROPERLY ON AN
  22. ;8" SINGLE DENSITY SOFT SECTORED DISK RECORDED IN STANDARD IBM
  23. ;FORMAT (I.E., 77 TRACKS, 26 SECTORS/TRACK, 243 BLOCKS/DISK, 8
  24. ;SECTORS/BLOCK, 128 BYTES/SECTOR).  IF YOUR DISK IS NOT AN IBM
  25. ;8" STANDARD, THEN YOU MUST SET THE CONDITIONAL ASSEMBLY 
  26. ;SWITCHES TO ONE OF THE DEFINED DISK SYSTEMS OR MODIFY THE 
  27. ;EXISTING DISK PARAMETER DEFINITIONS ACCORDING TO THE 
  28. ;GUIDELINES ESTABLISHED IN THIS DOCUMENTATION.  SEE NOTES BELOW
  29. ;CONCERNING 'TEST' CONDITIONAL ASSEMBLY OPTION.
  30. ;
  31. ;NOTE: If you add conditional assembly for other disk systems,
  32. ;or otherwise update this program, please modem a copy of the
  33. ;new file to "TECHNICAL CBBS" in Dearborn, Michigan - phone
  34. ;313-846-6127 (110, 300, 450 or 600 baud).  Use the filename
  35. ;FINDBAD.NEW.   (KBP)
  36. ;
  37. ;08/06/80 ADDED COMMENTS AND CRUNCHED SOME CODE.
  38. ;      KELLY SMITH.  805-527-9321 (Modem, 300 Baud)
  39. ;            805-527-0518 (Verbal)
  40. ;
  41. ;08/26/80 MODIFIED BY KEITH PETERSEN, W8SDZ, TO:
  42. ;    (1) ADD CONDITIONAL ASSEMBLY FOR 1k/2k GROUPS
  43. ;    (2) ADD CONDITIONAL ASSEMBLY FOR STANDARD DRIVES AND
  44. ;        MICROPOLIS MOD II
  45. ;    (3) MAKE COMPATIBLE WITH CP/M-2.x
  46. ;    (4) REMOVE UNNEEDED CODE TO CHECK FOR DRIVE NAME
  47. ;        (CP/M does it for you and returns it in the FCB)
  48. ;    (5) CHANGED TO OPEN ADDITIONAL EXTENTS AS NEEDED FOR
  49. ;        OVERFLOW, INSTEAD OF ADDITIONAL FILES
  50. ;    (6) ADD CONDITIONAL ASSEMBLY FOR SYSTEM TRACKS CHECK
  51. ;        (some double-density disks have single-density
  52. ;        system tracks which cannot be read by this program)
  53. ;    (7) INCREASED STACK AREA (some systems use more than
  54. ;        others).
  55. ;
  56. ;08/27/80 FIX MISSING CONDITIONAL ASSEMBLY IN FINDB ROUTINE.
  57. ;      PUT VERSION NUMBER IN SIGN-ON MESSAGE. (KBP)
  58. ;
  59. ;08/30/80 ADDED CONDITIONAL ASSEMBLY FOR MICROMATION
  60. ;      DOUBLE DENSITY FORMAT. (CHARLES H. STROM)
  61. ;
  62. ;08/31/80 CORRECT MAXB EQUATE - MAXB MUST INCLUDE THE DIRECTORY
  63. ;      BLOCKS AS WELL AS THE DATA BLOCKS.  FIX TO MAKE SURE
  64. ;      ANY [UNUSED].BAD FILE ERASED BEFORE DATA AREA IS
  65. ;      CHECKED. (KBP)
  66. ;
  67. ;08/31/80 ADD CONDITIONAL ASSEMBLY FOR DIGITAL MICROSYSTEMS FDC3
  68. ;      CONTROLLER BOARD IN DOUBLE DENSITY FORMAT AND FIX TO
  69. ;      DO 256 BLOCKS IN ONE REGISTER. (THOMAS V. CHURBUCK)
  70. ;
  71. ;09/01/80 CHANGED EQUATES SO THAT PARAMETERS ARE AUTOMATICALLY
  72. ;      SET FOR EACH DISK SYSTEM CONDITIONAL ASSEMBLY (KBP)
  73. ;
  74. ;09/02/80 ADDED IMDOS DOUBLE-DENSITY EQUATES & MODIFIED FOR 
  75. ;      MORE THAN 256 BLOCKS PER DISK. (AL JEWER)
  76. ;
  77. ;09/08/80 FIXED SEVERAL ERRORS IN AL JEWER'S MODS.  CHANGED
  78. ;      RETURN TO CP/M TO WARM BOOT SO BITMAP IN MEMORY WILL
  79. ;      WILL BE PROPERLY UPDATED. ADDED CONDITIONAL ASSEMBLY
  80. ;      FOR TESTING PROGRAM. (KBP)
  81. ;
  82. ;09/14/80 CORRECTED DGROUP EQUATE FOR MMDBL. ADDED NEW ROUTINE
  83. ;      TO CORRECT FOR IMDOS GROUP ALLOCATION.  CORRECTED
  84. ;      ERROR IN INSTRUCTIONS FOR USING TEST ROUTINE.
  85. ;      (CHS) (AJ) (KBP) - (a group effort)
  86. ;
  87. ;09/22/80 ADDED EQUATES FOR MORROW DISK JOCKEY 2D/SS, 256,
  88. ;      512 AND 1024-BYTE SECTOR OPTIONS.  FIX 'S2' UPDATE
  89. ;      FLAG FOR LARGER MAX NUMBER OF EXTENTS. CLEANED UP
  90. ;      FILE. (BEN BRONSON and KBP)
  91. ;
  92. ;12/08/80 ADDED EQUATES FOR NATIONAL MULTIPLEX D3S/D4S
  93. ;         DOUBLE DENSITY BOARD IN VARIOUS FORMATS.
  94. ;         (DAVID FIEDLER)
  95. ;
  96. ;            Using the Program
  97. ;
  98. ; Before  using this program to "reclaim" a diskette,  it  is
  99. ;recommended that the diskette be reformatted. If this is not
  100. ;possible,  at least assure yourself that any existing  files
  101. ;on the diskette  do not contain unreadable  sectors.  If you
  102. ;have changed disks since the last warm-boot, you  must warm-
  103. ;boot again before running this program.
  104. ;
  105. ; To  use the program,  insert  both the disk containing  the
  106. ;program  FINDBAD.COM and the diskette to be checked into the
  107. ;disk drives. It is possible that the diskette containing the
  108. ;program is the one to be checked. Assume that the program is
  109. ;on drive "A" and the suspected bad disk is on drive "B".  In
  110. ;response to the CP/M prompt "A>",  type in FINDBAD B:.  This
  111. ;will  load the file FINDBAD.COM from drive "A" and test  the
  112. ;diskette  on  drive "B" for  unreadable  sectors.  The  only
  113. ;allowable  parameter  after  the  program name  is  a  drive
  114. ;specification  (of the form " N:") for up to four (A  to  D)
  115. ;disk drives.  If no drive is specified, the currently logged
  116. ;in drive is assumed to contain the diskette to check.
  117. ;
  118. ; The  program first checks the CP/M System tracks (0 and 1),
  119. ;and  any  errors here prohibit the disk from being  used  on
  120. ;drive  "A",  since all "warm boot's" occur using the  system
  121. ;tracks from the "A" drive.
  122. ;
  123. ; The  program next checks the first two data blocks  (groups
  124. ;to some of us) containing the directory of the diskette.  If
  125. ;errors  occur  here,  the  program  terminates  and  control
  126. ;returns  to  CP/M  (no other data blocks are  checked  since
  127. ;errors in the directory render the disk useless).
  128. ;
  129. ; Finally,  all  the remaining data blocks are  checked.  Any
  130. ;sectors  which  are  unreadable cause the data  block  which
  131. ;contains them to be stored temporarily as a "bad block".  At
  132. ;the end of this phase,  the message "XX bad blocks found" is
  133. ;displayed (where XX is replaced by the number of bad blocks,
  134. ;or "No" if no read errors occur).  If bad blocks occur,  the
  135. ;filname [UNUSED].BAD is created, the list of "bad blocks" is
  136. ;placed  in  the allocation map of the  directory  entry  for
  137. ;[UNUSED].BAD,  and the file is closed.  Note,  that when the
  138. ;number of "bad blocks" exceeds 16,  the  program  will  open
  139. ;additional  extents  as  required  to  hold the overflow.  I
  140. ;suggest that if the diskette has more than  32 "bad blocks",
  141. ;perhaps it should be sent to the "big disk drive in the sky"
  142. ;for the rest it deserves.
  143. ;
  144. ; The  nifty part of all this is that if any "bad blocks"  do
  145. ;occur, they are allocated to [UNUSED].BAD and no longer will
  146. ;be available to CP/M for future allocation...bad sectors are
  147. ;logically locked out on the diskette!
  148. ;
  149. ;
  150. ;              Using the TEST conditional assembly
  151. ;
  152. ;A  conditional  assembly has been added to allow  testing  this 
  153. ;program  to  make sure it is reading all sectors on  your  disk 
  154. ;that  are accessible to CP/M.  The program reads the disk on  a 
  155. ;block by block basis, so it is necessary to first determine the 
  156. ;number of blocks present.  To start, we must know the number of 
  157. ;sectors/block (8 sectors/block for standard IBM single  density 
  158. ;format).  If  this  value  is  not  known,  it  can  easily  be 
  159. ;determined  by saving one page in a test file and interrogating 
  160. ;using the STAT command:
  161. ;
  162. ;    A>SAVE 1 TEST.SIZ
  163. ;    A>STAT TEST.SIZ
  164. ;
  165. ;For standard single-density STAT will report this file as being
  166. ;1k.  The file size reported (in bytes) is the size of a  block. 
  167. ;This  value  divided  by 128 bytes/sector  (the  standard  CP/M 
  168. ;sector  size)  will  give sectors/block.  For  our  IBM  single 
  169. ;density example, we have:
  170. ;
  171. ;  (1024 bytes/block) / (128 bytes/sector) = 8 sectors/block.
  172. ;
  173. ;We  can now calculate blocks/track (assuming we know the number 
  174. ;of sectors/track). In our example:
  175. ;
  176. ;  (26 sectors/track) / (8 sectors/block) = 3.25 blocks/track
  177. ;
  178. ;Now  armed with the total number of data tracks (75 in our  IBM 
  179. ;single density example), we get toatal blocks accessible: 
  180. ;
  181. ;  75 (tracks/disk) x (3.25 blocks/track) = 243.75 blocks/disk 
  182. ;
  183. ;CP/M cannot access a fractional block, so we round down (to 243 
  184. ;blocks  in  our  example).  Now  multiplying  total  blocks  by 
  185. ;sectors/block  results in total sectors as should  be  reported 
  186. ;when TEST is set TRUE and a good disk is read. For our example, 
  187. ;this value is 1944 sectors. 
  188. ;
  189. ;Finally,  note that if SYSTEM is set TRUE,  the sectors present 
  190. ;on  the  first  two tracks must be added in  as  well.  In  the 
  191. ;previous  example,  this  results in  1944 + 52 = 1996  sectors 
  192. ;reported by the TEST conditional.
  193. ;
  194. ;Run the program on a KNOWN-GOOD disk.  It should report that it
  195. ;has read  the  correct number of sectors.  The test conditional
  196. ;assembly should then be set FALSE and the program re-assembled.
  197. ;The test routines  cannot be left in  because this program does
  198. ;not read all the sectors in a block that is found to be bad and
  199. ;thus will report an inaccurate number of sectors read.
  200. ;
  201. ;
  202. ;DEFINE TRUE AND FALSE
  203. ;
  204. FALSE    EQU    0
  205. TRUE    EQU    NOT FALSE
  206. ;
  207. ;******************************************************************
  208. ;CONDITIONAL ASSEMBLY SWITCHES (only one should be true)
  209. ;
  210. STDDRV    EQU    TRUE      ;TRUE IF STANDARD 8" SINGLE DENSITY DRIVE
  211. MICROP    EQU    FALSE    ;TRUE IF MICROPOLIS MOD II
  212. MMDBL    EQU    FALSE    ;TRUE IF MICROMATION DOUBLE DENSITY
  213. DIGDBL    EQU    FALSE    ;TRUE IF DIGITAL MICROSYSTEMS FDC3 DBL DENS
  214. IMDOS    EQU    FALSE     ;TRUE IF IMSAI DOUBLE DENSITY
  215. DJ256S    EQU    FALSE    ;TRUE IF MORROW 2D/SS  (256-BYTE SECTOR)
  216. DJ512S    EQU    FALSE    ;TRUE IF MORROW 2D/SS  (512-BYTE SECTOR)
  217. DJ1024    EQU    FALSE    ;TRUE IF MORROW 2D/SS (1024-BYTE SECTOR)
  218. NM256    EQU    FALSE    ;TRUE IF NATMUX 2D     (256-BYTE SECTOR)
  219. NM512    EQU    FALSE    ;TRUE IF NATMUX 2D     (512-BYTE SECTOR)
  220. ;******************************************************************
  221. ;
  222. ;CONDITIONAL ASSEMBLY SWITCH FOR DOUBLE SIDED DRIVES
  223. ;presently supported for National Multiplex only
  224. ;
  225. SIDES2    EQU    FALSE    ;TRUE for NatMux D3S/D4S double sided only
  226. ;
  227. ;******************************************************************
  228. ;
  229. ;CONDITIONAL ASSEMBLY SWITCH FOR TESTING THIS PROGRAM
  230. ;(for initial testing phase only - see remarks above)
  231. ;
  232. TEST    EQU    FALSE    ;TRUE FOR TESTING ONLY
  233. ;******************************************************************
  234. ;
  235. ;SYSTEM EQUATES
  236. ;
  237. BASE    EQU    0    ;STANDARD CP/M BASE ADDRESS
  238. BDOS    EQU    BASE+5    ;CP/M WARM BOOT ENTRY
  239. FCB    EQU    BASE+5CH;CP/M DEFAULT FCB LOCATION
  240. ;
  241. ;DEFINE DISK SYSTEM PARAMETERS
  242. ;
  243.     IF    STDDRV
  244. SYSTEM    EQU    TRUE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  245. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  246. SECTS    EQU    26    ;TOTAL NUMBER OF SECTORS/TRACK
  247. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  248. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  249. MAXB    EQU    243    ;MAX NUMBER OF BLOCKS (including directory)
  250. BLOCK    EQU    8    ;NUMBER OF SECTORS/BLOCK
  251. DGROUP    EQU    FALSE    ;TRUE IF 2k GROUP SIZE
  252.     ENDIF        ;STDDRV
  253. ;
  254.     IF    MICROP
  255. SYSTEM    EQU    TRUE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  256. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  257. SECTS    EQU    32    ;TOTAL NUMBER OF SECTORS/TRACK
  258. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  259. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  260. MAXB    EQU    150    ;MAX NUMBER OF BLOCKS (including directory)
  261. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  262. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  263.     ENDIF        ;MICROP
  264. ;
  265.     IF MMDBL
  266. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  267. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  268. SECTS    EQU    52    ;TOTAL NUMBER OF SECTORS/TRACK
  269. DBASE    EQU    2    ;DATA AREA STARTING TRACK NUMBER
  270. BBASE    EQU    2    ;FIRST BLOCK FOR DATA
  271. MAXB    EQU    243    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  272. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  273. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  274.     ENDIF        ;MMDBL
  275. ;
  276.     IF    DIGDBL
  277. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  278. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  279. SECTS    EQU    58    ;TOTAL NUMBER OF SECTORS/TRACK
  280. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  281. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  282. MAXB    EQU    256    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  283. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  284. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  285.     ENDIF        ;DIGDBL
  286. ;
  287.     IF    IMDOS
  288. SYSTEM    EQU    FALSE    ;TRUE IF CHECK SYSTEM TRACKS WANTED
  289. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  290. SECTS    EQU    58    ;TOTAL NUMBER OF SECTORS/TRACK
  291. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  292. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  293. MAXB    EQU    271    ;MAX NUMBER OF BLOCKS (including directory)
  294. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  295. DGROUP    EQU    TRUE     ;TRUE IF 2k GROUP SIZE
  296.     ENDIF        ;IMDOS
  297. ;
  298.     IF    DJ256S OR NM256 AND NOT SIDES2
  299. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  300. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  301. SECTS    EQU    52    ;TOTAL NUMBER OF SECTORS/TRACK
  302. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  303. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  304. MAXB    EQU    243    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  305. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  306. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  307.     ENDIF        ;MORROW DJ256S OR NM256
  308. ;
  309.     IF    DJ512S OR NM512 AND NOT SIDES2
  310. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  311. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  312. SECTS    EQU    60    ;TOTAL NUMBER OF SECTORS/TRACK
  313. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  314. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  315. MAXB    EQU    281    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  316. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  317. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  318.     ENDIF        ;MORROW DJ512S OR NM512
  319. ;
  320.     IF    DJ1024
  321. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  322. TRACKS    EQU    77    ;TOTAL NUMBER OF TRACKS/DISK
  323. SECTS    EQU    64    ;TOTAL NUMBER OF SECTORS/TRACK
  324. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  325. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  326. MAXB    EQU    300    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  327. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  328. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  329.     ENDIF        ;MORROW DJ1024
  330. ;
  331.     IF    NM256 AND SIDES2
  332. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  333. TRACKS    EQU    77 * 2    ;TOTAL NUMBER OF TRACKS/DISK
  334. SECTS    EQU    52    ;TOTAL NUMBER OF SECTORS/TRACK
  335. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  336. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  337. MAXB    EQU    487    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  338. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  339. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  340.     ENDIF        ;MORROW DJ256S OR NM256
  341. ;
  342.     IF    NM512 AND SIDES2
  343. SYSTEM    EQU    FALSE    ;FALSE IF CHECK SYSTEM TRACKS NOT WANTED
  344. TRACKS    EQU    77 * 2    ;TOTAL NUMBER OF TRACKS/DISK
  345. SECTS    EQU    60    ;TOTAL NUMBER OF SECTORS/TRACK
  346. DBASE    EQU    2    ;DIRECTORY & DATA AREA STARTING TRACK NUMBER
  347. BBASE    EQU    2    ;FIRST BLOCK NUMBER FOR DATA
  348. MAXB    EQU    281 * 2    ;MAXIMUM NUMBER OF BLOCKS (including directory)
  349. BLOCK    EQU    16    ;NUMBER OF SECTORS/BLOCK
  350. DGROUP    EQU    TRUE    ;TRUE IF 2k GROUP SIZE
  351.     ENDIF        ;MORROW DJ512S OR NM512
  352. ;
  353. ;
  354. ;DEFINE ASCII CHARACTERS USED
  355. ;
  356. CR    EQU    0DH    ;ASCII CARRIAGE RETURN CHARACTER
  357. LF    EQU    0AH    ;ASCII LINE FEED CHARACTER
  358. TAB    EQU    09H    ;ASCII TAB CHARACTER
  359. ;
  360. ;
  361.     ORG    BASE+100H
  362. ;
  363. START:    LXI    SP,NEWSTK ;MAKE NEW STACK
  364. ;
  365.     IF    IMDOS
  366.     XRA    A
  367.     OUT    0FFH    ;CLEAR FRONT PANEL
  368.     ENDIF        ;IMDOS
  369. ;
  370.     LXI    D,IDMSG    ;IDENT MESSAGE
  371.     CALL    START2    ;GO PRINT IT
  372. ;
  373. IDMSG:    DB    CR,LF,'FINDBAD - ver 3.8'
  374.     DB    CR,LF,'Bad sector lockout '
  375.     DB    'program',CR,LF
  376. ;
  377.     IF    STDDRV
  378.     DB    'For single-density 8" only'
  379.     ENDIF
  380. ;
  381.     IF    MICROP
  382.     DB    'For Micropolis Mod II only'
  383.     ENDIF
  384. ;
  385.     IF    MMDBL
  386.     DB    'For Micromation double-density only'
  387.     ENDIF
  388. ;
  389.     IF    DIGDBL
  390.     DB    'For Digital Microsystems',CR,LF
  391.     DB    'FDC3 cntlr dbl dens only'
  392.     ENDIF
  393. ;
  394.     IF    IMDOS
  395.     DB    'For IMSAI IMDOS double-density ONLY'
  396.     ENDIF
  397. ;
  398.     IF    DJ256S
  399.     DB    'For Discus 2-dens./1-side/256-byte sectors only'
  400.     ENDIF
  401. ;
  402.     IF    DJ512S
  403.     DB    'For Discus 2-dens./1-side/512-byte sectors only'
  404.     ENDIF
  405. ;
  406.     IF    DJ1024
  407.     DB    'For Discus 2-dens./1-side/1024-byte sectors only'
  408.     ENDIF
  409. ;
  410.     IF    NM256 OR NM512
  411.     DB    'For National Multiplex double density'
  412.     ENDIF
  413. ;
  414.     IF    SIDES2 AND (NM256 OR NM512)
  415.     DB    ' double'
  416.     ENDIF
  417. ;
  418.     IF    NOT SIDES2 AND (NM256 OR NM512)
  419.     DB    ' single'
  420.     ENDIF
  421. ;    
  422.     IF    NM256
  423.     DB    ' sided 256-byte sectors only'
  424.     ENDIF
  425. ;
  426.     IF    NM512
  427.     DB    ' sided 512-byte sectors only'
  428.     ENDIF
  429. ;
  430.     DB    CR,LF,'$'
  431. ;
  432. START2    POP    D    ;GET MSG ADRS
  433.     MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  434.     CALL    BDOS    ;PRINT SIGN-ON MSG
  435.     CALL    IBIOS    ;SET BIOS ENTRY, AND CHECK DRIVE
  436.     CALL    FINDB    ;ESTABLISH ALL BAD BLOCKS
  437.     JZ    NOBAD    ;SAY NO BAD BLOCKS, IF SO
  438.     CALL    OPENB    ;OPEN [UNUSED].BAD ALLOCATION
  439.     CALL    SETDM    ;FIX DM BYTES IN FCB
  440.     CALL    CLOSEB    ;CLOSE [UNUSED].BAD
  441.     CALL    SETNUM    ;PUT NUMBER OF BAD BLOCKS IN MESSAGE
  442. ;
  443. NOBAD:    LXI    D,ENDMSG;SAY HOW MANY BAD BLOCKS
  444. ;
  445. PMSG:    MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  446.     CALL    BDOS
  447. ;
  448.     IF    TEST
  449.     MVI    A,TAB    ;GET A TAB
  450.     CALL    TYPE    ;PRINT IT
  451.     LHLD    SECCNT    ;GET NUMBER OF SECTORS READ
  452.     CALL    DECOUT    ;PRINT IT
  453.     LXI    D,SECMSG ;POINT TO MESSAGE
  454.     MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  455.     CALL    BDOS    ;PRINT IT
  456.     ENDIF        ;TEST
  457. ;
  458.     IF    IMDOS
  459.     XRA    A
  460.     OUT    0FFH    ;CLEAR FRONT PANEL
  461.     ENDIF        ;IMDOS
  462. ;
  463.     JMP    BASE    ;EXIT TO CP/M WARM BOOT
  464. ;
  465. ;GET ACTUAL ADDRESS OF BIOS ROUTINES
  466. ;
  467. IBIOS:    LHLD    BASE+1    ;GET BASE ADDRESS OF BIOS VECTORS
  468. ;
  469. ;WARNING...PROGRAM MODIFICATION TAKES PLACE HERE...DO NOT CHANGE!
  470. ;
  471.     LXI    D,27    ;OFFSET TO "SETTRK"
  472.     DAD    D
  473.     SHLD    SETTRK+1;FIX OUR CALL ADDRESS
  474.     LXI    D,3    ;OFFSET TO "SETSEC"
  475.     DAD    D
  476.     SHLD    SETSEC+1;FIX OUR CALL ADDRESS
  477.     LXI    D,6    ;OFFSET TO "DREAD"
  478.     DAD    D
  479.     SHLD    DREAD+1    ;FIX OUR CALL ADDRESS
  480. ;
  481. ;CHECK FOR DRIVE SPECIFICATION
  482. ;
  483.     LDA    FCB    ;GET DRIVE NAME
  484.     ORA    A    ;ZERO?
  485.     RZ        ;YES, NO DRIVE CHANGE REQUIRED
  486.     CPI    4+1    ;CHECK FOR HIGHEST DRIVE NUMBER
  487.     JNC    ERROR4
  488.     DCR    A    ;BACK OFF FOR CP/M
  489.     MOV    E,A    ;MAKE DISK NUMBER
  490.     MVI    C,14    ;BDOS SELECT DISK FUNCTION
  491.     CALL    BDOS
  492.     RET        ;RETURN FROM "IBIOS"
  493. ;
  494. ;LOOK FOR BAD BLOCKS
  495. ;
  496. FINDB:    EQU    $
  497. ;
  498.     IF    SYSTEM
  499.     CALL    CHKSYS    ;CHECK FOR BAD BLOCKS ON TRACK 0 AND 1
  500.     ENDIF        ;SYSTEM
  501. ;
  502.     CALL    CHKDIR    ;CHECK FOR BAD BLOCKS IN DIRECTORY
  503.     CALL    ERAB    ;ERASE ANY [UNUSED].BAD FILE
  504.     LXI    B,BBASE    ;START AT FIRST DATA BLOCK
  505. ;
  506. FINDBA:    CALL    READB    ;READ THE BLOCK
  507.     CNZ    SETBD    ;IF BAD, ADD BLOCK TO LIST
  508.     INX    B    ;BUMP TO NEXT BLOCK
  509.     MOV    A,C    ;SEE IF MORE TO CHECK
  510.     CPI    MAXB AND 0FFH
  511.     JNZ    FINDBA
  512.     MOV    A,B    ;THEN CHECK HI BYTE
  513.     CPI    MAXB SHR 8
  514.     JNZ    FINDBA    ;LOOP TILL DONE    
  515.     LHLD    DMCNT    ;GET NUMBER OF BAD SECTORS
  516.     MOV    A,H
  517.     ORA    L    ;SET ZERO FLAG, IF NO BAD BLOCKS
  518.     RET        ;RETURN FROM "FINDB"
  519. ;
  520.     IF    SYSTEM
  521. ;
  522. ;CHECK SYSTEM TRACKS, NOTIFY USER IF BAD...BUT CONTINUE
  523. ;
  524. CHKSYS:    LXI    H,1    ;SET TRACK 0, SECTOR 1
  525. ;
  526. CHKSY1:    CALL    READS    ;READ A SECTOR
  527.     JNZ    SYSERR    ;NOTIFY, IF BAD BLOCKS HERE
  528.     MOV    A,H    ;BOTH SYSTEM TRACKS DONE?
  529.     CPI    2
  530.     JC    CHKSY1
  531.     RET        ;RETURN FROM "CHKSYS"
  532. ;
  533. SYSERR:    LXI    D,ERMSG5;SAY NO GO, AND BAIL OUT
  534.     MVI    C,9    ;BDOS PRINT BUFFER FUNCTION
  535.     CALL    BDOS
  536.     RET        ;RETURN FROM "SYSERR"
  537. ;
  538.     ENDIF        ;SYSTEM
  539. ;
  540. ;CHECK FOR BAD BLOCKS IN DIRECTORY AREA
  541. ;
  542. CHKDIR:    LXI    B,0    ;START AT BLOCK 0
  543. ;
  544. CHKDI1:    CALL    READB    ;READ A BLOCK
  545.     JNZ    ERROR6    ;IF BAD, INDICATE ERROR IN DIRECTORY AREA
  546.     INX    B    ;BUMP FOR NEXT BLOCK
  547.     MOV    A,C    ;GET BLOCK NUMBER
  548.     CPI    BBASE    ;ALL DONE CHECKING DIRECTORY AREA?
  549.     JC    CHKDI1    ;PRESS ON, IF NOT
  550.     RET        ;RETURN FROM "CHKDIR"
  551. ;
  552. ;READ ALL SECTORS IN BLOCK, AND RETURN ZERO FLAG SET IF NONE BAD
  553. ;
  554. READB:    CALL    CNVRTB    ;CONVERT TO TRACK/SECTOR IN H&L REGS.
  555.     MVI    D,BLOCK    ;NUMBER OF SECTORS/BLOCK
  556. ;
  557. READBA:    PUSH    D
  558.     CALL    READS    ;READ SKEWED SECTOR
  559.     POP    D
  560.     RNZ        ;ERROR IF NOT ZERO...
  561.     DCR    D    ;DEBUMP SECTOR/BLOCK
  562.     JNZ    READBA    ;DO NEXT, IF NOT FINISHED
  563.     RET        ;RETURN FROM "READBA"
  564. ;
  565. ;CONVERT BLOCK NUMBER TO TRACK AND SKEWED SECTOR NUMBER
  566. ;
  567. CNVRTB:    PUSH    B    ;SAVE BLOCK NUMBER
  568.     MOV    L,C    ;BLOCK NUMBER TO H&L REGS.
  569.     MOV    H,B
  570.     DAD    H    ;*2
  571.     DAD    H    ;*4
  572.     DAD    H    ;*8
  573. ;
  574.     IF    DGROUP
  575.     DAD    H    ;*16 FOR 2k GROUP SIZE
  576.     ENDIF        ;DGROUP
  577. ;
  578.     LXI    D,DBASE*256    ;MAKE BASE TRACK NUMBER
  579.     LXI    B,-SECTS    ;DIVIDE BY SECTORS/TRACK
  580. ;
  581. CNVRTC:    MOV    A,H    ;OVER SECTORS...
  582.     ORA    A
  583.     JNZ    CNVRTT    ;...BYE GROUPS?
  584.     MOV    A,L    ;OVER SECTORS...
  585.     CPI    SECTS
  586.     JC    CNVRTS    ;...AND DOWN TO TRACKS?
  587. ;
  588. CNVRTT:    DAD    B    ;TAKE AWAY SECTORS
  589.     INR    D    ;+1 TO TRACK NUMBER
  590.     JMP    CNVRTC    ;...AND GO BACK FOR MORE
  591. ;
  592. CNVRTS:    MOV    E,L    ;RESIDUAL = SKEWED SECTOR-1
  593.     INR    E    ;BUMP FOR SECTORS 1 TO 32
  594.     XCHG        ;TRACK/SECTOR IN H&L REGS.
  595.     POP    B    ;RECOVER BLOCK NUMBER
  596.     RET        ;RETURN FROM "CNVRTB"
  597. ;
  598. ;READS A LOGICAL SECTOR (IF IT CAN), AND RETURNS ZERO FLAG SET IF NO ERROR
  599. ;
  600. READS:    PUSH    B    ;EXILE BLOCK
  601.     PUSH    H    ;...AND TRACK/SECTOR
  602.     CALL    LTOP    ;CONVERT LOGICAL TO PHYSICAL SECTOR
  603.     PUSH    H    ;SAVE SECTOR NUMBER
  604.     MOV    C,H    ;TRACK NUMBER IN H REG...
  605. ;
  606. SETTRK:    CALL    $-$    ;BIOS SET TRACK (MODIFIED BY IBIOS)
  607.     POP    B    ;PUT SECTOR IN C
  608. ;
  609. SETSEC:    CALL    $-$    ;BIOS SET SECTOR (MODIFIED BY IBIOS)
  610. ;
  611. DREAD:    CALL    $-$    ;BIOS READ SECTOR (MODIFIED BY IBIOS)
  612.     ORA    A    ;SET FLAGS FOR POSSIBLE BAD SECTOR
  613. ;
  614.     IF    TEST
  615.     LHLD    SECCNT    ;GET NUMBER OF SECTORS READ
  616.     INX    H    ;INCREMENT
  617.     SHLD    SECCNT    ;SAVE NEW NUMBER
  618.     ENDIF        ;TEST
  619. ;
  620.     POP    H
  621.     POP    B    ;BACK FROM EXILE...
  622.     PUSH    PSW    ;SAVE FLAGS
  623.     INR    L    ;BUMP FOR NEXT SECTOR
  624.     MOV    A,L
  625.     CPI    SECTS+1    ;TRACK OVERFLOW?
  626.     JC    READSR
  627.     MVI    L,1    ;YUP, RESET SECTOR NUMBER TO 1...
  628.     INR    H    ;...AND BUMP TRACK NUMBER
  629. ;
  630. READSR:    POP    PSW    ;GET FLAGS, TO CHECK IF ERROR ON RETURN
  631.     RET        ;RETURN FROM "READS"
  632. ;
  633. ;CONVERT LOGICAL TO PHYSICAL SECTOR
  634. ;
  635. LTOP:    XCHG
  636.     LXI    B,LPMAP-1 ;GET BASE OF LOGICAL TO PHYSICAL MAPPING
  637.     MOV    L,E
  638.     MVI    H,0    ;LOGICAL SECTOR OFFSET
  639.     DAD    B    ;+ BIAS
  640.     MOV    E,M    ;GET PHYSICAL SECTOR
  641.     XCHG        ;PUT H&L REGS. BACK...
  642.     RET        ;RETURN FROM "LTOP"
  643. ;
  644. ;LOGICAL TO PHYSICAL MAPPING VECTORS (SECTOR SKEW TABLE)
  645. ;
  646.     IF    STDDRV
  647. LPMAP:    DB    01,07,13,19,25,05,11,17,23,03,09,15,21
  648.     DB    02,08,14,20,26,06,12,18,24,04,10,16,22
  649.     ENDIF        ;STDDRV
  650. ;
  651.     IF    MICROP
  652. LPMAP:    DB    01,02,11,12,21,22,31,32,09,10,19,20,29,30,07,08
  653.     DB    17,18,27,28,05,06,15,16,25,26,03,04,13,14,23,24
  654.     ENDIF        ;MICROP
  655. ;
  656.     IF    MMDBL
  657. LPMAP:    DB    01,14,27,40,10,23,36,49,06,19,32,45,02,15,28,41
  658.     DB    11,24,37,50,07,20,33,46,03,16,29,42,12,25,38,51
  659.     DB    08,21,34,47,04,17,30,43,13,26,39,52,09,22,35,48
  660.     DB    05,18,31,44
  661.     ENDIF        ;MMDBL
  662. ;
  663.     IF    DIGDBL
  664. LPMAP:    DB    01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16
  665.     DB    17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32
  666.     DB    33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48
  667.     DB    49,50,51,52,53,54,55,56,57,58
  668.     ENDIF        ;DIGDBL
  669. ;
  670.     IF    IMDOS
  671. LPMAP:    DB    1,8,15,22,29,36,43,50,57,6,13,20,27,34,41,48,55
  672.     DB    4,11,18,25,32,39,46,53,2,9,16,23,30,37,44,51,58
  673.     DB    7,14,21,28,35,42,49,56,5,12,19,26,33,40,47,54
  674.     DB    3,10,17,24,31,38,45,52
  675.     ENDIF        ;IMDOS
  676. ;
  677.     IF    DJ256S
  678. LPMAP:    DB    01,02,19,20,37,38,03,04,21,22,39,40,05,06,23,24
  679.     DB    41,42,07,08,25,26,43,44,09,10,27,28,45,46,11,12
  680.     DB    29,30,47,48,13,14,31,32,49,50,15,16,33,34,51,52
  681.     DB    17,18,35,36
  682.     ENDIF        ;DJ256S
  683. ;
  684.     IF    NM256
  685. LPMAP:    DB    01,02,23,24,45,46,15,16,37,38,07,08,29,30,51,52
  686.     DB    21,22,43,44,13,14,35,36,05,06,27,28,49,50,19,20
  687.     DB    41,42,11,12,33,34,03,04,25,26,47,48,17,18,39,40
  688.     DB    09,10,31,32
  689.     ENDIF        ;NM256
  690. ;
  691.     IF    DJ512S OR NM512
  692. LPMAP:    DB    01,02,03,04,17,18,19,20,33,34,35,36,49,50,51,52
  693.     DB    05,06,07,08,21,22,23,24,37,38,39,40,53,54,55,56
  694.     DB    09,10,11,12,25,26,27,28,41,42,43,44,57,58,59,60
  695.     DB    13,14,15,16,29,30,31,32,45,46,47,48
  696.     ENDIF        ;DJ512S or NM512
  697. ;
  698.     IF    DJ1024
  699. LPMAP:    DB    01,02,03,04,05,06,07,08,25,26,27,28,29,30,31,32
  700.     DB    49,50,51,52,53,54,55,56,09,10,11,12,13,14,15,16
  701.     DB    33,34,35,36,37,38,39,40,57,58,59,60,61,62,63,64
  702.     DB    17,18,19,20,21,22,23,24,41,42,43,44,45,46,47,48
  703.     ENDIF        ;DJ1024
  704. ;
  705. ;PUT BAD BLOCK IN BAD BLOCK LIST
  706. ;
  707. SETBD:    LHLD    DMCNT    ;GET NUMBER OF SECTORS
  708.     LXI    D,BLOCK
  709.     DAD    D    ;BUMP BY NUMBER IN THIS BLOCK
  710.     SHLD    DMCNT    ;UPDATE NUMBER OF SECTORS
  711.     LHLD    DMPTR    ;GET POINTER INTO DM
  712.     MOV    M,C    ;...AND PUT BAD BLOCK NUMBER
  713.     INX    H    ;BUMP TO NEXT AVAILABLE EXTENT
  714. ;
  715.     IF    IMDOS OR DJ512S OR DJ1024 OR NM256 OR NM512
  716.     MOV    M,B    ;PUT IN 2ND BYTE FOR IMDOS OR DJ512/1024
  717.     INX    H    ;POINT TO NEXT AVAILABLE EXTENT
  718.     ENDIF        ;IMDOS OR DJ512S OR DJ1024 OR NM256 OR NM512
  719. ;
  720.     SHLD    DMPTR    ;SAVE DM POINTER, FOR NEXT TIME THROUGH HERE
  721.     RET        ;RETURN FROM "SETBD"
  722. ;
  723. ;ELIMINATE ANY PREVIOUS [UNUSED].BAD ENTRIES
  724. ;
  725. ERAB:    LXI    D,BFCB    ;POINT TO BAD FCB
  726.     MVI    C,19    ;BDOS DELETE FILE FUNCTION
  727.     CALL    BDOS
  728.     RET
  729. ;
  730. ;CREATE [UNUSED].BAD FILE ENTRY
  731. ;
  732. OPENB:    LXI    D,BFCB    ;POINT TO BAD FCB
  733.     PUSH    D    ;SAVE IT...
  734.     MVI    C,22    ;BDOS MAKE FILE FUNCTION
  735.     CALL    BDOS
  736.     POP    D    ;RECOVER BAD FCB POINTER
  737.     MVI    C,15    ;BDOS OPEN FILE FUNCTION
  738.     CALL    BDOS
  739.     CPI    0FFH    ;CHECK FOR OPEN ERROR
  740.     RNZ        ;RETURN FROM "OPENB", IF NO ERROR
  741.     JMP    ERROR7    ;BAIL OUT...CAN'T CREATE [UNUSED].BAD
  742. ;
  743. ;MOVE BAD AREA DM TO BFCB
  744. ;
  745. SETDM:    LXI    H,DM    ;GET DM
  746.     SHLD    DMPTR    ;SAVE AS NEW POINTER
  747.     LHLD    DMCNT    ;GET THE COUNT
  748. ;
  749. SETDM0:    MOV    A,H
  750.     ORA    A
  751.     JNZ    GOBIG
  752.     MOV    A,L
  753.     CPI    129    ;ALL BYTES MOVED?
  754.     JC    SETDME
  755. ;
  756. GOBIG:    LXI    D,-128
  757.     DAD    D
  758.     PUSH    H
  759.     MVI    A,128
  760.     CALL    SETDME
  761.     XCHG
  762.     SHLD    DMPTR
  763.     CALL    CLOSEB    ;CLOSE OLD EXTENT
  764.     LDA    EXTNUM    ;GET OLD EXTENT NUMBER
  765.     INR    A    ;INCREMENT IT
  766.     STA    EXTNUM    ;SAVE NEW EXTENT NUMBER
  767.     STA    BFCB+12    ;PUT NEW EXTENT NUMBER INTO OUR FCB
  768.     CALL    OPENB    ;OPEN NEW EXTENT
  769.     POP    H
  770.     JMP    SETDM0
  771. ;
  772. SETDME:    STA    BFCB+15    ;PUT RC IN PLACE
  773. ;
  774.     IF    NOT DGROUP
  775.     MVI    B,16    ;NUMBER OF BYTES TO MOVE
  776.     ENDIF        ;NOT DGROUP
  777. ;
  778.     IF    DGROUP
  779.     MVI    B,8    ;NUMBER OF BYTES TO MOVE
  780.     ENDIF        ;DGROUP
  781. ;
  782.     LHLD    DMPTR    ;GET BAD DMAP POINTER
  783.     XCHG        ;TO DE
  784.     LXI    H,BFCB+16 ;POINT AT OUR FCB
  785. ;
  786. SETDML:    EQU    $
  787. ;
  788.     IF    NOT IMDOS
  789.     LDAX    D    ;GET BYTE FROM DMAP
  790.     MOV    M,A    ;MOVE TO OUR FCB
  791.     INX    D    ;INCREMENT DMAP POINTER
  792.     INX    H    ;INCREMENT OUR FCB POINTER
  793.     ENDIF        ;NOT IMDOS (1 BYTE GROUP #)
  794. ;
  795.     IF    DJ512S OR DJ1024 OR NM256 OR NM512
  796.     LDAX    D    ;GET SECOND BYTE FROM DMAP
  797.     MOV    M,A    ;MOVE TO OUR FCB
  798.     INX    D    ;INCREMENT DMAP POINTER
  799.     INX    H    ;INCREMENT OUR FCB POINTER
  800.     ENDIF        ;DJ512S OR DJ1024 OR NMXXXDS (2 BYTE GROUP #)
  801. ;
  802.     IF    IMDOS
  803.     LDAX    D    ;GET FIRST (LO ORDER) BYTE FROM DMAP
  804.     MOV    C,A    ;SAVE IT IN C
  805.     INX    D    ;INCREMENT DMAP POINTER
  806.     LDAX     D    ;THEN GET SECOND (HI ORDER) BYTE
  807.     MOV    M,A    ;STORE HI BYTE FIRST
  808.     INX    H    ;INCREMENT FCB POINTER
  809.     MOV    M,C    ;THEN LO BYTE FOR 16-BIT POINTER
  810.     INX    H    ;INCREMENT OUR FCB POINTER
  811.     ENDIF        ;IMDOS (2 BYTE GROUP #)
  812. ;
  813.     DCR    B    ;ONE LESS BYTE TO MOVE
  814.     JNZ    SETDML    ;NOT DONE, GO MOVE MORE
  815.     RET        ;ELSE RETURN FROM "SETDM"
  816.  
  817. ;
  818. CLOSEB:    XRA    A
  819.     LDA    BFCB+14    ;GET CP/M 2.x 'S2' BYTE
  820.     ANI    1FH    ;ZERO UPDATE FLAGS
  821.     STA    BFCB+14    ;RESTORE IT TO OUR FCB (WON'T HURT 1.4)
  822.     LXI    D,BFCB    ;FCB FOR [UNUSED].BAD
  823.     MVI    C,16    ;BDOS CLOSE FILE FUNCTION
  824.     CALL    BDOS
  825.     RET        ;RETURN FROM "CLOSEB"
  826. ;
  827. ;CONVERT NUMBER OF BLOCKS TO DECIMAL ASCII, FOR PRINTING
  828. ;
  829. SETNUM:    LHLD    DMCNT    ;GET NUMBER OF SECTORS
  830.     DAD    H    ;*2
  831.     DAD    H    ;*4
  832.     DAD    H    ;*8
  833.     DAD    H    ;*16
  834. ;
  835.     IF    NOT DGROUP
  836.     DAD    H    ;*32 FOR 1k GROUP SIZE
  837.     ENDIF
  838. ;
  839. ;H REG NOW EQUALS NUMBER OF BLOCKS
  840.     LXI    D,255
  841.     DAD    D    ;ROUND UP
  842.     MOV    L,H
  843.     MVI    H,0    ;NOW H&L REGS. EQUAL NUMBER OF BLOCKS
  844.     LXI    D,NUMBAD
  845.     CALL    DCNV
  846.     RET        ;RETURN FROM "SETNUM"
  847. ;
  848. DCNV:    MVI    B,' '    ;SET FOR PLUS
  849.     MOV    A,H
  850.     ORA    A
  851.     JP    H3
  852.     MVI    B,'-'
  853.     MOV    A,L
  854.     CMA
  855.     INR    A
  856.     MOV    L,A
  857.     MOV    A,H
  858.     CMA
  859.     JNZ    H2
  860.     INR    A
  861. ;
  862. H2:    MOV    H,A
  863. ;
  864. H3:    SHLD    DCNVHL
  865.     MVI    A,' '
  866.     STAX    D
  867.     MOV    A,B
  868.     STA    DCNVPM
  869.     XCHG
  870.     SHLD    DCNVAD
  871.     XRA    A
  872.     STA    DCNVFL
  873.     LXI    B,-10000
  874.     CALL    DFL8
  875.     CALL    DSTC
  876.     LXI    B,-1000
  877.     CALL    DFL8
  878.     CALL    DSTC
  879.     LXI    B,-100
  880.     CALL    DFL8
  881.     CALL    DSTC
  882.     LXI    B,-10
  883.     CALL    DFL8
  884.     CALL    DSTC
  885.     LDA    DCNVHL
  886.     ORI    '0'
  887.     MOV    E,A
  888. ;
  889. DSTC:    LHLD    DCNVAD
  890.     LDA    DCNVFL
  891.     ORA    A
  892.     JNZ    DSTC3
  893. ;
  894. DSTC1:    ADD    E
  895.     STA    DCNVFL
  896.     JNZ    DSTC2
  897.     MVI    A,' '
  898.     JMP    DSTC4
  899. ;
  900. DSTC2:    LDA    DCNVPM
  901.     MOV    M,A
  902. ;
  903. DSTC3:    MVI    A,'0'
  904.     ORA    E
  905. ;
  906. DSTC4:    INX    H
  907.     MOV    M,A
  908.     SHLD    DCNVAD
  909.     RET        ;RETURN FROM "SETDM"
  910. ;
  911. DCNVFL:    DB    0
  912. DCNVHL:    DW    0
  913. DCNVAD:    DW    0
  914. DCNVPM:    DB    0
  915. ;
  916. DFL8:    LHLD    DCNVHL
  917.     MVI    E,0
  918. ;
  919. DF1:    DAD    B
  920.     MOV    A,H
  921.     ORA    A
  922.     RM
  923.     INR    E
  924.     SHLD    DCNVHL
  925.     JMP    DF1
  926. ;
  927. BFCB:    DB    0,'[UNUSED]BAD',0,0,0,0
  928.     DS    17
  929. ;
  930. ENDMSG:    DB    CR,LF,'    '
  931. ;
  932. NUMBAD:    DB    '    No'
  933.     DB    ' bad blocks found',CR,LF,'$'
  934. ;
  935. EXTNUM:    DB    0    ;USED IF MORE THAN 16 BAD BLOCKS
  936. DMCNT:    DW    0    ;NUMBER OF BAD SECTORS
  937. DMPTR:    DW    DM    ;POINTER TO NEXT BLOCK ID
  938. ;
  939. ;ALLOCATION MAP FOR BAD BLOCKS
  940. ;
  941. DM:    DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  942.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  943.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  944.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  945.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  946.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  947.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  948.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  949.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  950.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  951.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  952.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  953.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  954.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  955.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  956.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  957. ;
  958. ;ERROR MESSAGES
  959. ;
  960. ERROR4:    LXI    D,ERMSG4 ;SAY NO GO, AND BAIL OUT
  961.     JMP    PMSG
  962. ;
  963. ERMSG4:    DB    CR,LF,'Only drives A to D allowed$'
  964. ;
  965.     IF    SYSTEM
  966. ERMSG5:    DB    CR,LF,'Warning...System tracks bad$'
  967.     ENDIF        ;SYSTEM
  968. ;
  969. ERROR6:    LXI    D,ERMSG6 ;OOPS...CLOBBERED DIRECTORY
  970.     JMP    PMSG
  971. ;
  972. ERMSG6:    DB    CR,LF,'Bad directory area, try reformatting$'
  973. ;
  974. ERROR7:    LXI    D,ERMSG7 ;SAY NO GO, AND BAIL OUT
  975.     JMP    PMSG
  976. ;
  977. ERMSG7:    DB    CR,LF,'Can''t create [UNUSED].BAD$'
  978. ;
  979.     IF    TEST
  980. ;
  981. ;DECIMAL OUTPUT ROUTINE
  982. ;
  983. DECOUT:    PUSH    B
  984.     PUSH    D
  985.     PUSH    H
  986.     LXI    B,-10
  987.     LXI    D,-1
  988. ;
  989. DECOU2:    DAD    B
  990.     INX    D
  991.     JC    DECOU2
  992.     LXI    B,10
  993.     DAD    B
  994.     XCHG
  995.     MOV    A,H
  996.     ORA    L
  997.     CNZ    DECOUT
  998.     MOV    A,E
  999.     ADI    '0'
  1000.     CALL    TYPE
  1001.     POP    H
  1002.     POP    D
  1003.     POP    B
  1004.     RET
  1005. ;
  1006. TYPE:    PUSH    B
  1007.     PUSH    D
  1008.     PUSH    H
  1009.     MOV    E,A    ;CHARACTER TO E FOR CP/M
  1010.     MVI    C,2    ;PRINT CONSOLE FUNCTION
  1011.     CALL    BDOS    ;PRINT CHARACTER
  1012.     POP    H
  1013.     POP    D
  1014.     POP    B
  1015.     RET
  1016. ;
  1017. SECMSG:    DB    ' total sectors read',CR,LF,'$'
  1018. ;
  1019. SECCNT:    DW    0    ;NUMBER OF SECTORS READ
  1020. ;
  1021.     ENDIF        ;TEST
  1022. ;
  1023.     DS    60    ;ROOM FOR 30 LEVEL STACK
  1024. NEWSTK    EQU    $    ;OUR STACK
  1025. ;
  1026.     END
  1027.