home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol096 / findbad.a86 < prev    next >
Encoding:
Text File  |  1984-04-29  |  31.3 KB  |  1,153 lines

  1.     TITLE    'FINDBAD Ver 1.0 - Universal Version for CP/M-86'
  2. ;
  3. ;            FINDBAD.A86 Ver. 1.0
  4. ;
  5. ;    Modified for CP/M-86 from FINDBAD52.ASM of 02/16/82
  6. ;
  7. ;FINDBAD will find all bad blocks on a disk and build a file
  8. ;named [UNUSED].BAD to allocate them, thus "locking out" the
  9. ;bad blocks so CP/M-86 will not use them.
  10. ;
  11. ;Originally written by Gene Cotton,  published in "Interface
  12. ;Age", September 1980 issue, page 80.
  13. ;
  14. ;               SYSTST and BADUSR options:
  15. ;
  16. ;  Many double-density disk systems have single-density system 
  17. ;tracks.  If this is true with your system, you can change the 
  18. ;program to skip the system tracks,  without re-assembling it.  
  19. ;To do this, set the byte at 103H to a 0 if you don't want the 
  20. ;system  tracks tested,  otherwise leave it 0.   This is  also 
  21. ;necessary if you have a "blocked" disk system;  that is, when 
  22. ;the same physical disk is seperated into logical disks by use 
  23. ;of the SYSTRK word in the disk parameter block.
  24. ;
  25. ;   If  you  are a CP/M-86 1.x user,  you may assign the  user 
  26. ;number  where  [UNUSED.BAD] will be created by  changing  the  
  27. ;byte  at 104H  to  the  desired user number.   If you want it  
  28. ;in  the default user,  then leave it 0FFH.
  29. ;
  30. ;
  31. ;-------------------------------------------------------------
  32. ;NOTE: If you want to  update this program, make sure you have 
  33. ;the latest version first.   After adding your changes, please 
  34. ;modem  a  copy of the new file to CP/M-NET  in  Simi  Valley, 
  35. ;California - phone (805) 527-9321 (50,  110,  300, 450 or 600 
  36. ;baud). Use the filename FNDBDA86.NEW. (K. Smith)
  37. ;
  38. ;Modifications/updates:
  39. ;
  40. ;02/03/82  Changed to CP/M-86 compatibility with the help  of 
  41. ;          DR's XLT86 utility, made changes for goofs made by 
  42. ;           XLT86,  removed ANYTHING to do with CP/M-80  Ver. 
  43. ;          1.4. (K. Smith, CP/M-Net 'SYSOP')
  44. ;         Note: You must assemble with ASM86.CMD as follows:
  45. ;
  46. ;               ASM86 FINDBAD<cr>
  47. ;
  48. ;               Then create a '.CMD' as,
  49. ;
  50. ;               GENCMD FINDBAD 8080<cr>
  51. ;
  52. ;04/10/81 Changed extent DB from -1 to 0FFH so program can be
  53. ;      assembled by ASM.  Added BADUSR info to instructions
  54. ;      for altering with DDT.  (KBP)
  55. ;
  56. ;04/09/81 Changed sign-on message, added control-c abort test,
  57. ;      added '*' to console once each track    (RGF)
  58. ;
  59. ;04/07/81 Re-wrote to add the following features:
  60. ;        1) "universal" operation
  61. ;        2) DDT-changeable "SYSTRK" boolean (see above)
  62. ;        3) Report to console when bad blocks are detected
  63. ;        4) Changed the method of printing the number of
  64. ;           bad blocks found (at end of run)...the old
  65. ;           method used too much code, and was too cum-
  66. ;           bersome.
  67. ;        5) Made several cosmetic changes
  68. ;
  69. ;            Ron Fowler
  70. ;            Westland, Mich
  71. ;
  72. ;03/23/81 Set equates to standard drive and not double-sided. (KBP)
  73. ;
  74. ;03/01/81 Corrected error for a Horizon with double sided drive.
  75. ;      This uses 32k extents, which code did not take into account.
  76. ;      (Bob Clyne)
  77. ;
  78. ;02/05/81 Merged 2/2/81 and 1/24/81 changes, which were done
  79. ;      independently by Clyne and Mack.  (KBP)
  80. ;
  81. ;02/02/81 Added equates for North Star Horizon - 5.25" drives,
  82. ;      double density, single and double sided. (Bob Clyne)
  83. ;
  84. ;01/24/81 Added equates for Jade DD disk controller
  85. ;      (Pete H. Mack)
  86. ;
  87. ;01/19/81 Added equates for Icom Microfloppy 5.25" drives.
  88. ;      (Eddie Currie)
  89. ;
  90. ;01/05/81 Added equates for Heath H-17 5.25" drives.
  91. ;      (Ben Goldfarb)
  92. ;
  93. ;12/08/80 Added equates for National Multiplex D3S/D4S
  94. ;      double-density board in various formats.
  95. ;      (David Fiedler)
  96. ;
  97. ;09/22/80 Added equates for Morrow Disk Jockey 2D/SS, 256,
  98. ;      512 and 1024-byte sector options.  Fix 'S2' update
  99. ;      flag for larger max number of extents. Cleaned up
  100. ;      file. (Ben Bronson and KBP)
  101. ;
  102. ;09/14/80 Corrected DGROUP equate for MMDBL. Added new routine
  103. ;      to correct for IMDOS group allocation.  Corrected
  104. ;      error in instructions for using TEST routine.
  105. ;      (CHS) (AJ) (KBP) - (a group effort)
  106. ;
  107. ;09/08/80 Fixed several errors in Al Jewer's mods.  Changed
  108. ;      return to CP/M to warm boot so bitmap in memory will
  109. ;      be properly updated. Added conditional assembly for
  110. ;      testing program. (KBP)
  111. ;
  112. ;09/02/80 Added IMDOS double-density equates & modified for 
  113. ;      more then 256 blocks per disk. (Al Jewer)
  114. ;
  115. ;09/01/80 Changed equates so that parameters are automatically
  116. ;      set for each disk system conditional assembly (KBP)
  117. ;
  118. ;08/31/80 Add conditional assembly for Digital Microsystems FDC3
  119. ;      controller board in double-density format and fix to
  120. ;      do 256 blocks in one register. (Thomas V. Churbuck)
  121. ;
  122. ;08/31/80 Correct MAXB equate - MAXB must include the directory
  123. ;      blocks as well as the data blocks.  Fix to make sure
  124. ;      any [UNUSED].BAD file is erased before data area is
  125. ;      checked. (KBP)
  126. ;
  127. ;08/30/80 Added conditional assembly for Micromation
  128. ;      double-density format. (Charles H. Strom)
  129. ;
  130. ;08/27/80 Fix missing conditional assembly in FINDB routine.
  131. ;      Put version number in sign-on message. (KBP)
  132. ;
  133. ;08/26/80 Modified by Keith Petersen, W8SDZ, to:
  134. ;      (1) Add conditional assembly for 1k/2k groups
  135. ;      (2) Add conditional assembly for standard drives
  136. ;          and Micropolis MOD II
  137. ;      (3) Make compatible with CP/M-2.x
  138. ;      (4) Remove unneeded code to check for drive name
  139. ;          (CP/M does it for you and returns it in the FCB)
  140. ;      (5) Changed to open additional extents as needed for
  141. ;          overflow, instead of additional files
  142. ;      (6) Add conditional assembly for system tracks check
  143. ;          (some double-density disks have single-density
  144. ;          system tracks which cannot be read by this program)
  145. ;      (7) Increased stack area (some systems use more than
  146. ;          others).
  147. ;
  148. ;08/06/80 Added comments and crunched some code.
  149. ;      KELLY SMITH.    805-527-9321 (Modem, 300 Baud)
  150. ;            805-527-0518 (Verbal)
  151. ;
  152. ;
  153. ;            Using the Program
  154. ;
  155. ; Before  using this program to "reclaim" a diskette,  it  is
  156. ;recommended that the diskette be reformatted. If this is not
  157. ;possible,  at least assure yourself that any existing    files
  158. ;on the diskette  do not contain unreadable  sectors.  If you
  159. ;have changed disks since the last warm-boot, you  must warm-
  160. ;boot again before running this program.
  161. ;
  162. ; To  use the program,    insert    both the disk containing  the
  163. ;program  FINDBAD.CMD and the diskette to be checked into the
  164. ;disk drives. It is possible that the diskette containing the
  165. ;program is the one to be checked. Assume that the program is
  166. ;on drive "A" and the suspected bad disk is on drive "B".  In
  167. ;response to the CP/M prompt "A>",  type in FINDBAD B:.  This
  168. ;will  load the file FINDBAD.CMD from drive "A" and test  the
  169. ;diskette  on  drive "B" for  unreadable  sectors.  The  only
  170. ;allowable  parameter  after  the  program name  is  a    drive
  171. ;specification    (of the form " N:") for up to four (A  to  D)
  172. ;disk drives.  If no drive is specified, the currently logged
  173. ;in drive is assumed to contain the diskette to check.
  174. ;
  175. ; The  program first checks the CP/M System tracks (0 and 1),
  176. ;and  any  errors here prohibit the disk from being  used  on
  177. ;drive    "A",  since all "warm  boots" occur using the  system
  178. ;tracks from the "A" drive.
  179. ;
  180. ; The  program next checks the first two data blocks  (groups
  181. ;to some of us) containing the directory of the diskette.  If
  182. ;errors  occur    here,  the  program  terminates  and  control
  183. ;returns  to  CP/M  (no other data blocks are  checked    since
  184. ;errors in the directory render the disk useless).
  185. ;
  186. ; Finally,  all  the remaining data blocks are    checked.  Any
  187. ;sectors  which  are  unreadable cause the data  block    which
  188. ;contains them to be stored temporarily as a "bad block".  At
  189. ;the end of this phase,  the message "XX bad blocks found" is
  190. ;displayed (where XX is replaced by the number of bad blocks,
  191. ;or "No" if no read errors occur).  If bad blocks occur,  the
  192. ;filname [UNUSED].BAD is created, the list of "bad blocks" is
  193. ;placed  in  the allocation map of the    directory  entry  for
  194. ;[UNUSED].BAD,    and the file is closed.  Note,    that when the
  195. ;number of "bad blocks" exceeds 16,  the  program  will  open
  196. ;additional  extents  as  required  to    hold the overflow.  I
  197. ;suggest that if the diskette has more than  32 "bad blocks",
  198. ;perhaps it should be sent to the "big disk drive in the sky"
  199. ;for the rest it deserves.
  200. ;
  201. ; The  nifty part of all this is that if any "bad blocks"  do
  202. ;occur, they are allocated to [UNUSED].BAD and no longer will
  203. ;be available to CP/M-86 for future allocation... bad sectors
  204. ;are logically locked out on the diskette
  205. ;
  206. ;
  207. ;           Using the TEST conditional assembly
  208. ;
  209. ;A  conditional  assembly has been added to allow  testing  this 
  210. ;program  to  make sure it is reading all sectors on  your  disk 
  211. ;that  are accessible to CP/M.    The program reads the disk on  a 
  212. ;block by block basis, so it is necessary to first determine the 
  213. ;number of blocks present.  To start, we must know the number of 
  214. ;sectors/block (8 sectors/block for standard IBM single  density 
  215. ;format).  If  this  value  is    not  known,  it  can  easily  be 
  216. ;determined  by saving one page in a test file and interrogating 
  217. ;using the STAT command:
  218. ;
  219. ;For standard single-density STAT will report this file as being
  220. ;1k.  The file size reported (in bytes) is the size of a  block. 
  221. ;This  value  divided  by 128 bytes/sector  (the  standard  CP/M 
  222. ;sector  size)    will  give sectors/block.  For    our  IBM  single 
  223. ;density example, we have:
  224. ;
  225. ;  (1024 bytes/block) / (128 bytes/sector) = 8 sectors/block.
  226. ;
  227. ;We  can now calculate blocks/track (assuming we know the number 
  228. ;sectors/track). In our example:
  229. ;
  230. ;  (26 sectors/track) / (8 sectors/block) = 3.25 blocks/track
  231. ;
  232. ;Now  armed with the total number of data tracks (75 in our  IBM 
  233. ;single density example), we get total blocks accessible: 
  234. ;
  235. ;  75 (tracks/disk) x (3.25 blocks/track) = 243.75 blocks/disk 
  236. ;
  237. ;CP/M cannot access a fractional block, so we round down (to 243 
  238. ;blocks  in  our  example).  Now  multiplying  total  blocks  by 
  239. ;sectors/block    results in total sectors as should  be    reported 
  240. ;when TEST is set TRUE and a good disk is read. For our example, 
  241. ;this value is 1944 sectors. 
  242. ;
  243. ;Finally,  note that if SYSTEM is set TRUE,  the sectors present 
  244. ;on  the  first  two tracks must be added in  as  well.  In  the 
  245. ;previous  example,  this  results in  1944 + 52 = 1996  sectors 
  246. ;reported by the TEST conditional.
  247. ;
  248. ;Run the program on a KNOWN-GOOD disk.    It should report that it
  249. ;has read  the    correct number of sectors.  The test conditional
  250. ;assembly should then be set FALSE and the program re-assembled.
  251. ;The test routines  cannot be left in  because this program does
  252. ;not read all the sectors in a block that is found to be bad and
  253. ;thus will report an inaccurate number of sectors read.
  254. ;
  255. ;
  256. ;Define TRUE and FALSE
  257. ;
  258. FALSE    EQU    0
  259. TRUE    EQU    NOT FALSE
  260. ;
  261. ;******************************************************************
  262. ;
  263. ;Conditional assembly switch for testing this program
  264. ;(for initial testing phase only - see remarks above)
  265. ;
  266. TEST    EQU    FALSE            ;TRUE FOR TESTING ONLY
  267. ;
  268. ;******************************************************************
  269. ;
  270. ;System equates
  271. ;
  272. BASE    EQU    0            ;STANDARD CP/M BASE ADDRESS
  273. FCB    EQU    BASE+5CH        ;CP/M DEFAULT FCB LOCATION
  274. ;
  275. ;Define ASCII characters used
  276. ;
  277. CR    EQU    0DH            ;CARRIAGE RETURN CHARACTER
  278. LF    EQU    0AH            ;LINE FEED CHARACTER
  279. TAB    EQU    09H            ;TAB CHARACTER
  280. BEL    EQU    07H            ;BELL CHARACTER
  281. ;
  282. M    EQU    Byte Ptr    0[BX]
  283. ;
  284.     cseg
  285.     ORG    BASE+100H
  286. ;
  287.     JMPS    START            ;JMP AROUND OPTION BYTES
  288. ;
  289. ;If you want the system tracks tested, then put a 1 here, otherwise 0.
  290. ;
  291. SYSTST    DB    1            ;0 IF NO SYS TRACKS, OTHERWISE 1
  292. ;
  293. ;   Change this byte to the user number you want [UNUSED].BAD 
  294. ;to reside in.  If you want it in the default user, then leave 
  295. ;it 0FFH.
  296. ;
  297. BADUSR    DB    0FFH            ;USER # WHERE [UNUSED.BAD] GOES
  298. ;0FFH = DEFAULT USER
  299. ;
  300. START:    CALL    START2            ;GO PRINT SIGNON
  301. ;
  302.     DB    CR,LF,'FINDBAD - Ver 1.0, Bad Sector Lockout Utility'
  303.     DB    CR,LF
  304.     DB    '------- Universal Version for CP/M-86 -------'
  305.     DB    CR,LF,CR,LF,'Type CTL-C to abort',CR,LF,'$'
  306. ;
  307. START2:    POP    DX            ;GET MSG ADRS
  308.     MOV    CL,9            ;bdos PRINT BUFFER function
  309.     INT    224            ;bdos PRINT SIGN-ON MSG
  310.     CALL    SETUP            ;SET BIOS ENTRY, AND CHECK DRIVE
  311.     CALL    FINDB            ;ESTABLISH ALL BAD BLOCKS
  312.     JZ    NOBAD            ;SAY NO BAD BLOCKS, IF SO
  313.     CALL    SETDM            ;FIX DM BYTES IN FCB
  314. ;
  315. NOBAD:    CALL    CRLF
  316.     MOV    AL,TAB
  317.     CALL    DISPLAY
  318.     MOV    DX,(Offset NOMSG)    ;POINT FIRST TO 'NO'
  319.     MOV    BX,Word Ptr BADBKS    ;PICK UP # BAD BLOCKS
  320.     MOV    AL,BH            ;CHECK FOR ZERO
  321.     OR    AL,BL
  322.     JZ    PMSG1            ;JUMP IF NONE
  323.     CALL    DECOUT            ;OOPS..HAD SOME BAD ONES, REPORT
  324.     JMPS    PMSG2
  325. ;
  326. PMSG1:    MOV    CL,9            ;bdos PRINT BUFFER function
  327.     INT    224
  328. ;
  329. PMSG2:    MOV    DX,(Offset ENDMSG)    ;REST OF EXIT MESSAGE
  330. ;
  331. PMSG:    MOV    CL,9
  332.     INT    224
  333. ;
  334.     MOV    CL,0            ;EXIT TO CP/M WARM BOOT
  335.     MOV    DL,0
  336.     INT    224
  337. ;
  338. ;Get actual address of BIOS routines
  339. ;
  340. SETUP    EQU    $    ;Check for drive specification
  341. ;
  342. GDRIV:    MOV    AL,Byte Ptr .FCB    ;GET DRIVE NAME
  343.     MOV    CL,AL
  344.     OR    AL,AL            ;ZERO?
  345.     JNZ    GD2            ;IF NOT,THEN GO SPECIFY DRIVE
  346.     MOV    CL,25            ;GET LOGGED-IN DRIVE
  347.     INT    224
  348.     INC    AL            ;MAKE 1-RELATIVE
  349.     MOV    CL,AL
  350. ;
  351. GD2:    CMP    AL,15+1            ;CHECK FOR HIGHEST DRIVE NUMBER
  352.     JNAE    GD3    
  353.     JMP    SELERR            ;SELECT ERROR
  354. ;
  355. GD3:    DEC    CL            ;BACK OFF FOR CP/M
  356.     PUSH    CX            ;SAVE DISK SELECTION
  357.     MOV    DL,CL            ;ALIGN FOR BDOS
  358.     MOV    CL,14            ;SELECT DISK function
  359.     INT    224
  360.     POP    CX            ;GET BACK DISK NUMBER
  361. ;
  362. SETDSK:    MOV    Byte Ptr FUNC,9        ;bios select disk function
  363.     MOV    Word Ptr BIOS_DESC,CX    ;pass disk number to bios descriptor
  364.     MOV    Word Ptr BIOS_DESC+2,0    ;fill remaining descriptor (DX) zero
  365.     MOV    DX,(Offset FUNC)    ;point to function parameter block
  366.     MOV    CL,50            ;direct bios call
  367.     INT    224            ;do it, to it...
  368. ;
  369.     MOV    DL,ES: M        ;GET SECTOR TABLE PNTR
  370.     LAHF
  371.     INC    BX
  372.     SAHF
  373.     MOV    DH,ES: M
  374.     LAHF
  375.     INC    BX
  376.     SAHF
  377.     XCHG    BX,DX
  378.     MOV    Word Ptr SECTBL,BX    ;STORE IT AWAY
  379.     MOV    BX,8            ;OFFSET TO DPB POINTER
  380.     LAHF
  381.     ADD    BX,DX
  382.     RCR    SI,1
  383.     SAHF
  384.     RCL    SI,1
  385.     MOV    AL,ES: M            ;PICK UP DPB POINTER
  386.     LAHF                ;  TO USE
  387.     INC    BX
  388.     SAHF
  389.     MOV    BH,ES: M            ;  AS PARAMETER
  390.     MOV    BL,AL            ;  TO LOGIT
  391. ;
  392. DOLOG:    CALL    LOGIT            ;LOG IN DRIVE, GET DISK PARMS
  393.     CALL    GETDIR            ;CALCULATE DIRECTORY INFORMATION
  394. ;
  395. ;
  396. HOMDSK:    MOV    Byte Ptr FUNC,8        ;bios HOME DISK function
  397.     MOV    Word Ptr BIOS_DESC,0    ;pass 'nothing' number to bios descriptor
  398.     MOV    Word Ptr BIOS_DESC+2,0    ;fill remaining descriptor (DX) zero
  399.     MOV    DX,(Offset FUNC)    ;point to function parameter block
  400.     MOV    CL,50            ;direct bios call
  401.     INT    224            ;do it, to it...
  402. ;
  403. ;Now set the required user number
  404. ;
  405.     MOV    AL,Byte Ptr BADUSR    ;GET THE USER NUMBER
  406.     CMP    AL,0FFH            ;IF IT IS 0FFH, THEN RETURN
  407.     JNZ    L_6
  408.     RET
  409. L_6:
  410.     MOV    CL,32            ;GET/SET USER CODE
  411.     INT    224
  412.     RET
  413. ;
  414. ;Look for bad blocks
  415. ;
  416. FINDB:    MOV    AL,Byte Ptr SYSTST
  417.     OR    AL,AL
  418.     JZ    DODIR            ;JUMP IF NO SYS TRACKS TO BE TESTED
  419.     CALL    CHKSYS            ;CHECK FOR BAD BLOCKS ON TRACK 0 AND 1
  420. ;
  421. DODIR:    CALL    CHKDIR            ;CHECK FOR BAD BLOCKS IN DIRECTORY
  422.     CALL    TELL1
  423. ;
  424.     DB    CR,LF,'Testing data area...',CR,LF,'$'
  425. ;
  426. TELL1:    POP    DX
  427.     MOV    CL,9            ;bdos PRINT STRING function
  428.     INT    224
  429.     CALL    ERAB            ;ERASE ANY [UNUSED].BAD FILE
  430.     MOV    BX,Word Ptr DIRBKS    ;START AT FIRST DATA BLOCK
  431.     MOV    CX,BX            ;PUT INTO [CX]
  432. ;
  433. FINDBA:    CALL    READB            ;READ THE BLOCK
  434.     JZ    L_7    
  435.     CALL    SETBD            ;IF BAD, ADD BLOCK TO LIST
  436. L_7:
  437.     LAHF                ;BUMP TO NEXT BLOCK
  438.     INC    CX
  439.     SAHF
  440.     MOV    BX,Word Ptr DSM
  441.     MOV    DX,CX            ;SET UP FOR (MAXGRP - CURGRP)
  442.     SBB    BX,DX            ;DO SUBTRACT: (MAXGRP - CURGRP)
  443.     JNB    FINDBA            ;UNTIL CURGRP>MAXGRP
  444.     CALL    CRLF
  445.     MOV    BX,Word Ptr DMCNT    ;GET NUMBER OF BAD SECTORS
  446.     MOV    AL,BH
  447.     OR    AL,BL            ;SET ZERO FLAG, IF NO BAD BLOCKS
  448.     RET                ;RETURN FROM "FINDB"
  449. ;
  450. ;Check system tracks, notify user if bad, but continue
  451. ;
  452. CHKSYS:    CALL    CHSY1            ;bdos PRINT MESSAGE
  453. ;
  454.     DB    CR,LF,'Testing system tracks...',CR,LF,'$'
  455. ;
  456. CHSY1:    POP    DX
  457.     MOV    CL,9            ;bdos PRINT STRING function
  458.     INT    224
  459.     MOV    BX,0            ;SET TRACK 0, SECTOR 1
  460.     MOV    Word Ptr TRACK,BX
  461.     LAHF
  462.     INC    BX
  463.     SAHF
  464.     MOV    Word Ptr SECTOR,BX
  465. ;
  466. CHKSY1:    CALL    READS            ;READ A SECTOR
  467.     JNZ    SYSERR            ;NOTIFY, IF BAD BLOCKS HERE
  468.     MOV    BX,Word Ptr SYSTRK    ;SET UP (TRACK-SYSTRK)
  469.     XCHG    BX,DX
  470.     MOV    BX,Word Ptr TRACK
  471.     SBB    BX,DX            ;DO THE SUBTRACT
  472.     JB    CHKSY1            ;LOOP WHILE TRACK < SYSTRK
  473.     RET                ;RETURN FROM "CHKSYS"
  474. ;
  475. SYSERR:    MOV    DX,(Offset ERMSG5)    ;SAY NO GO, AND BAIL OUT
  476.     MOV    CL,9            ;bdos PRINT BUFFER function
  477.     INT    224
  478.     RET                ;RETURN FROM "SYSERR"
  479. ;
  480. ;Check for bad blocks in directory area
  481. ;
  482. CHKDIR:    CALL    CHKD1
  483. ;
  484.     DB    CR,LF,'Testing directory area...',CR,LF,'$'
  485. ;
  486. CHKD1:    POP    DX
  487.     MOV    CL,9            ;bdos PRINT STRING function
  488.     INT    224
  489.     MOV    CX,0            ;START AT BLOCK 0
  490. ;
  491. CHKDI1:    CALL    READB            ;READ A BLOCK
  492.     JZ    L_8    
  493.     JMP    ERROR6            ;IF BAD, INDICATE ERROR IN DIRECTORY AREA
  494. L_8:
  495.     LAHF                ;BUMP FOR NEXT BLOCK
  496.     INC    CX
  497.     SAHF
  498.     MOV    BX,Word Ptr DIRBKS    ;SET UP (CURGRP - DIRBKS)
  499.     LAHF                ;MAKE 0-RELATIVE
  500.     DEC    BX
  501.     SAHF
  502.     MOV    DX,CX
  503.     SBB    BX,DX            ;DO THE SUBTRACT
  504.     JNB    CHKDI1            ;LOOP UNTIL CURGRP > DIRGRP
  505.     RET                ;RETURN FROM "CHKDIR"
  506. ;
  507. ;Read all sectors in block, and return zero flag set if none bad
  508. ;
  509. READB:    CALL    CNVRTB            ;CONVERT TO TRACK/SECTOR IN H&L REGS.
  510.     MOV    AL,Byte Ptr BLM
  511.     INC    AL            ;NUMBER OF SECTORS/BLOCK
  512.     MOV    DH,AL            ;  IN D REG
  513. ;
  514. READBA:    PUSH    DX
  515.     CALL    READS            ;READ SKEWED SECTOR
  516.     POP    DX
  517.     JZ    L_9    
  518.     RET                ;ERROR IF NOT ZERO...
  519. L_9:
  520.     DEC    DH            ;DEBUMP SECTOR/BLOCK
  521.     JNZ    READBA            ;DO NEXT, IF NOT FINISHED
  522.     RET                ;RETURN FROM "READBA"
  523. ;
  524. ;Convert block number to track and skewed sector number
  525. ;
  526. CNVRTB:    PUSH    CX            ;SAVE CURRENT GROUP
  527.     MOV    BX,CX            ;NEED IT IN [BX], FOR EASY SHIFTING
  528.     MOV    AL,Byte Ptr BSH        ;DPB VALUE THAT TELLS HOW TO
  529. ;
  530. SHIFT:    SHL    BX,1            ;  SHIFT GROUP NUMBER TO GET
  531.     DEC    AL            ;  DISK-DATA-AREA RELATIVE
  532.     JNZ    SHIFT            ;  SECTOR NUMBER
  533.     XCHG    BX,DX            ;REL SECTOR # INTO DE
  534.     MOV    BX,Word Ptr SPT        ;SECTORS PER TRACK FROM DPB
  535.     NOT    BX            ;1ST 1'S COMPLEMENT...
  536.     INC    BX            ;...THEN 2'S COMPLEMENT
  537.     XCHG    BX,DX
  538.     MOV    CX,0            ;INITIALIZE QUOTIENT
  539. ;
  540. ;Divide by number of sectors
  541. ;    quotient = track
  542. ;         mod = sector
  543. ;
  544. DIVLP:    LAHF                ;DIRTY DIVISION
  545.     INC    CX
  546.     SAHF
  547.     LAHF
  548.     ADD    BX,DX
  549.     RCR    SI,1
  550.     SAHF
  551.     RCL    SI,1
  552.     JB    DIVLP
  553.     LAHF                ;FIXUP LAST
  554.     DEC    CX
  555.     SAHF
  556.     XCHG    BX,DX
  557.     MOV    BX,Word Ptr SPT
  558.     LAHF
  559.     ADD    BX,DX
  560.     SAHF
  561.     LAHF
  562.     INC    BX
  563.     SAHF
  564.     MOV    Word Ptr SECTOR,BX    ;NOW HAVE LOGICAL SECTOR
  565.     MOV    BX,Word Ptr SYSTRK    ;BUT BEFORE WE HAVE TRACK #,
  566.     LAHF                ;  WE HAVE TO ADD SYS TRACK OFFSET
  567.     ADD    BX,CX
  568.     RCR    SI,1
  569.     SAHF
  570.     RCL    SI,1
  571.     MOV    Word Ptr TRACK,BX
  572.     POP    CX            ;THIS WAS OUR GROUP NUMBER
  573.     RET
  574. ;
  575. ;READS reads a logical sector (if it can)
  576. ;and returns zero flag set if no error.
  577. ;
  578. READS:    PUSH    CX            ;SAVE THE GROUP NUMBER
  579. ;
  580.     CALL    LTOP            ;CONVERT LOGICAL TO PHYSICAL
  581.     MOV    BX,Word Ptr PHYSEC    ;GET PHYSICAL SECTOR
  582.     MOV    CX,BX            ;INTO [CX]
  583. ;
  584. SETSEC:    MOV    BYTE PTR FUNC,11    ;bios SET SECTOR function
  585.     MOV    WORD PTR BIOS_DESC,CX    ;pass sector number to bios descriptor
  586.     MOV    WORD PTR BIOS_DESC+2,0    ;fill remaining descriptor (DX) zero
  587.     MOV    DX,(Offset FUNC)    ;point to function parameter block
  588.     MOV    CL,50            ;direct bios call
  589.     INT    224            ;do it, to it...
  590. ;
  591.     MOV    BX,Word Ptr TRACK    ;NOW SET THE TRACK
  592.     MOV    CX,BX            ;CP/M WANTS IT IN [CX]
  593. ;
  594. SETTRK:    MOV    BYTE PTR FUNC,10    ;bios SELECT TRACK function
  595.     MOV    WORD PTR BIOS_DESC,CX    ;pass track number to bios descriptor
  596.     MOV    WORD PTR BIOS_DESC+2,0    ;fill remaining descriptor (DX) zero
  597.     MOV    DX,(Offset FUNC)    ;point to function parameter block
  598.     MOV    CL,50            ;direct bios call
  599.     INT    224            ;do it, to it...
  600. ;
  601. ;Now do the sector read
  602. ;
  603. DREAD:    MOV    BYTE PTR FUNC,13    ;bios READ SECTOR function
  604.     MOV    WORD PTR BIOS_DESC,0    ;pass 'nothing' number to bios descriptor
  605.     MOV    WORD PTR BIOS_DESC+2,0    ;fill remaining descriptor (DX) zero
  606.     MOV    DX,(Offset FUNC)    ;point to function parameter block
  607.     MOV    CL,50            ;direct bios call
  608.     INT    224            ;do it, to it...
  609. ;
  610.     OR    AL,AL            ;SET FLAGS
  611.     LAHF                ;SAVE ERROR FLAG
  612.     XCHG    AL,AH
  613.     PUSH    AX
  614.     MOV    BX,Word Ptr SECTOR    ;GET LOGICAL SECTOR #
  615.     LAHF                ;WE WANT TO INCREMENT TO NEXT
  616.     INC    BX
  617.     SAHF
  618.     XCHG    BX,DX            ;BUT FIRST...CHECK OVERFLOW
  619.     MOV    BX,Word Ptr SPT        ;  BY DOING (SECPERTRK-SECTOR)
  620.     SBB    BX,DX            ;DO THE SUBTRACTION
  621.     XCHG    BX,DX
  622.     JNB    NOOVF            ;JUMP IF NOT SECTOR>SECPERTRK
  623. ;
  624. ;Sector overflow...bump track number, reset sector
  625. ;
  626.     MOV    BX,Word Ptr TRACK
  627.     LAHF
  628.     INC    BX
  629.     SAHF
  630.     MOV    Word Ptr TRACK,BX
  631.     MOV    AL,'*'            ;TELL CONSOLE ANOTHER TRACK DONE
  632.     CALL    DISPLAY
  633.     CALL    STOP            ;SEE IF CONSOLE WANTS TO QUIT
  634.     MOV    BX,1            ;NEW SECTOR NUMBER ON NEXT TRACK
  635. ;
  636. NOOVF:    MOV    Word Ptr SECTOR,BX    ;PUT SECTOR AWAY
  637.     POP    AX            ;GET BACK ERROR FLAGS
  638.     XCHG    AL,AH
  639.     SAHF
  640.     POP    CX            ;RESTORE GROUP NUMBER
  641.     RET
  642. ;
  643. ;Convert logical sector # to physical
  644. ;
  645. LTOP:    MOV    BX,Word Ptr SECTBL    ;SET UP PARAMETERS
  646.     XCHG    BX,DX            ;  FOR CALL TO SECTRAN
  647.     MOV    BX,Word Ptr SECTOR
  648.     MOV    CX,BX
  649.     DEC    CX            ;ALWAYS CALL SECTRAN W/ZERO-REL SEC #
  650. ;
  651. SECT1:    CALL    SECTRN            ;DO THE SECTOR TRANSLATION
  652.     MOV    AL,Byte Ptr SPT+1    ;CHECK IF BIG TRACKS
  653.     OR    AL,AL            ;SET FLAGS (TRACKS > 256 SECTORS)
  654.     JNZ    LTOP1            ;NO SO SKIP
  655.     MOV    BH,AL            ;ZERO OUT UPPER 8 BITS
  656. ;
  657. LTOP1:    MOV    Word Ptr PHYSEC,BX    ;PUT AWAY PHYSICAL SECTOR
  658.     RET
  659. ;
  660. ;Sector translation vector
  661. ;
  662. SECTRN:    MOV    BYTE PTR FUNC,16    ;bios SECTOR TRANSLATE function
  663.     MOV    WORD PTR BIOS_DESC,CX    ;pass sector to bios descriptor
  664.     MOV    WORD PTR BIOS_DESC+2,DX    ;translate table offset
  665.     MOV    DX,(Offset FUNC)    ;point to function parameter block
  666.     MOV    CL,50            ;direct bios call
  667.     INT    224            ;do it, to it...
  668.     ret                ;return from 'sectrn'
  669. ;
  670. ;Put bad block in bad block list
  671. ;
  672. SETBD:    PUSH    CX
  673.     CALL    SETBD1
  674.     DB    CR,LF,BEL,'Bad block: $'
  675. ;
  676. SETBD1:    POP    DX            ;RETRIEVE ARG
  677.     MOV    CL,9            ;bdos PRINT STRING
  678.     INT    224
  679.     POP    CX            ;GET BACK BLOCK NUMBER
  680.     MOV    AL,CH
  681.     CALL    HEXO            ;bdos PRINT IN HEX
  682.     MOV    AL,CL
  683.     CALL    HEXO
  684.     CALL    CRLF
  685.     MOV    BX,Word Ptr DMCNT    ;GET NUMBER OF SECTORS
  686.     MOV    AL,Byte Ptr BLM        ;GET BLOCK SHIFT VALUE
  687.     INC    AL            ;MAKES SECTOR/GROUP VALUE
  688.     MOV    DL,AL            ;WE WANT 16 BITS
  689.     MOV    DH,0
  690.     ADD    BX,DX            ;BUMP BY NUMBER IN THIS BLOCK
  691.     MOV    Word Ptr DMCNT,BX    ;UPDATE NUMBER OF SECTORS
  692.     MOV    BX,Word Ptr BADBKS    ;INCREMENT NUMBER OF BAD BLOCKS
  693.     INC    BX
  694.     MOV    Word Ptr BADBKS,BX
  695.     MOV    BX,Word Ptr DMPTR    ;GET POINTER INTO DM
  696.     MOV    M,CL            ;...AND PUT BAD BLOCK NUMBER
  697.     INC    BX            ;BUMP TO NEXT AVAILABLE EXTENT
  698.     MOV    AL,Byte Ptr DSM+1    ;CHECK IF 8 OR 16 BIT BLOCK SIZE
  699.     OR    AL,AL
  700.     JZ    SMGRP            ;JUMP IF 8 BIT BLOCKS
  701.     MOV    M,CH            ;ELSE STORE HI BYTE OF BLOCK #
  702.     LAHF                ;AND BUMP POINTER
  703.     INC    BX
  704.     SAHF
  705. ;
  706. SMGRP:    MOV    Word Ptr DMPTR,BX    ;SAVE DM POINTER, FOR NEXT TIME THROUGH HERE
  707.     RET                ;RETURN FROM "SETBD"
  708. ;
  709. ;Eliminate any previous [UNUSED].BAD entries
  710. ;
  711. ERAB:    MOV    DX,(Offset BFCB)    ;POINT TO BAD FCB
  712.     MOV    CL,19            ;bdos DELETE FILE function
  713.     INT    224
  714.     RET
  715. ;
  716. ;Create [UNUSED].BAD file entry
  717. ;
  718. OPENB:    MOV    DX,(Offset BFCB)    ;POINT TO BAD FCB
  719.     MOV    CL,22            ;bdos MAKE FILE function
  720.     INT    224
  721.     CMP    AL,0FFH            ;CHECK FOR OPEN ERROR
  722.     JZ    L_10    
  723.     RET                ;RETURN FROM "OPENB", IF NO ERROR
  724. L_10:
  725.     JMP    ERROR7            ;BAIL OUT...CAN'T CREATE [UNUSED].BAD
  726. ;
  727. CLOSEB:    XOR    AL,AL
  728.     MOV    AL,Byte Ptr BFCB+14    ;GET CP/M 'S2' BYTE
  729.     AND    AL,1FH            ;ZERO UPDATE FLAGS
  730.     MOV    Byte Ptr BFCB+14,AL    ;RESTORE IT TO OUR FCB
  731.     MOV    DX,(Offset BFCB)    ;FCB FOR [UNUSED].BAD
  732.     MOV    CL,16            ;bdos CLOSE FILE function
  733.     INT    224
  734.     RET                ;RETURN FROM "CLOSEB"
  735. ;
  736. ;Move bad area DM to BFCB
  737. ;
  738. SETDM:    MOV    BX,(Offset DM)        ;GET DM
  739.     MOV    Word Ptr DMPTR,BX    ;SAVE AS NEW POINTER
  740.     MOV    AL,Byte Ptr EXM        ;GET THE EXTENT SHIFT FACTOR
  741.     MOV    CL,0            ;INIT BIT COUNT
  742.     CALL    COLECT            ;GET SHIFT VALUE
  743.     MOV    BX,128            ;STARTING EXTENT SIZE
  744.     MOV    AL,CL            ;FIRST SEE IF ANY SHIFTS TO DO
  745.     OR    AL,AL
  746.     JZ    NOSHFT            ;JUMP IF NONE
  747. ;
  748. ESHFT:    SHL    BX,1            ;SHIFT
  749.     DEC    AL            ;BUMP
  750.     JNZ    ESHFT            ;LOOP
  751. ;
  752. NOSHFT:    PUSH    BX            ;SAVE THIS, IT IS RECORDS PER EXTENT
  753.     MOV    AL,Byte Ptr BSH        ;GET BLOCK SHIFT
  754.     MOV    CH,AL
  755. ;
  756. BSHFT:    CLC                ;CLEAR CARRY FLAG
  757.     RCR    BX,1            ;SHIFT RIGHT
  758.     DEC    CH
  759.     JNZ    BSHFT            ;TO GET BLOCKS PER EXTENT
  760.     MOV    AL,BL            ;IT'S IN [BL] (CAN'T BE >16)
  761.     MOV    Byte Ptr BLKEXT,AL    ;SET BLOCK EXTENT, WILL NEED THIS LATER
  762.     POP    BX            ;GET BACK REC/EXT
  763. ;
  764. SET1:    XCHG    BX,DX            ;NOW HAVE REC/EXTENT IN [DX]
  765.     MOV    BX,Word Ptr DMCNT    ;COUNT OF BAD SECTORS
  766. ;
  767. SETDMO:    PUSH    BX            ;SET FLAGS ON (DMCNT-BADCNT)
  768.     SBB    BX,DX            ;HAVE TO SUBTRACT FIRST
  769.     MOV    CX,BX            ;SAVE RESULT IN [CX]
  770.     POP    BX            ;THIS POP MAKES IT COMPARE ONLY
  771.     JB    SETDME            ;JUMP IF LESS THAN 1 EXTENT WORTH
  772.     MOV    AL,CH
  773.     OR    AL,CL            ;TEST IF SUBTRACT WAS 0
  774.     JZ    EVENEX            ;EXTENT IS EXACTLY FILLED (SPL CASE)
  775.     MOV    BX,CX            ;RESTORE RESULT TO [BX]
  776.     PUSH    BX            ;SAVE TOTAL
  777.     PUSH    DX            ;AND SECTORS/EXTENT
  778.     XCHG    BX,DX
  779.     CALL    SETDME            ;PUT AWAY ONE EXTENT
  780.     XCHG    BX,DX
  781.     MOV    Word Ptr DMPTR,BX    ;PUT BACK NEW DM POINTER
  782.     POP    DX            ;GET BACK SECTORS/EXTENT
  783.     POP    BX            ;AND COUNT OF BAD SECTORS
  784.     JMPS    SETDMO            ;AND LOOP
  785. ;
  786. ;Handle the special case of a file that ends on an extent
  787. ;boundary.  CP/M requires that such a file have a succeeding
  788. ;empty extent in order for the BDOS to properly access the file.
  789. ;
  790. EVENEX:    XCHG    BX,DX            ;FIRST SET EXTENT W/BAD BLOCKS
  791.     CALL    SETDME
  792.     XCHG    BX,DX
  793.     MOV    Word Ptr DMPTR,BX
  794.     MOV    BX,0            ;NOW SET ONE WITH NO DATA BLOCKS
  795. ;
  796. ;Fill in an extent's worth of bad sectors/block numbers.
  797. ;Also fill in the extent number in the FCB.
  798. ;
  799. SETDME:    PUSH    BX            ;SAVE RECORD COUNT
  800.     MOV    AL,Byte Ptr EXTNUM    ;UPDATE EXTENT BYTE
  801.     INC    AL
  802.     MOV    Byte Ptr EXTNUM,AL    ;SAVE FOR LATER
  803.     MOV    Byte Ptr BFCB+12,AL    ; AND PUT IN FCB
  804.     CALL    OPENB            ;OPEN THIS EXTENT
  805.     POP    BX            ;RETRIEVE REC COUNT
  806. ;
  807. ;Divide record count by 128 to get the number
  808. ;of logical extents to put in the EX field
  809. ;
  810.     MOV    CH,0            ;INIT QUOTIENT
  811.     MOV    DX,-128            ;-DIVISOR
  812.     MOV    AL,BH            ;TEST FOR SPL CASE
  813.     OR    AL,BL            ;  OF NO RECORDS
  814.     JZ    SKIP
  815. ;
  816. DIVLOP:    ADD    BX,DX            ;SUBTRACT
  817.     INC    CH            ;BUMP QUOTIENT
  818.     JB    DIVLOP
  819.     MOV    DX,128            ;FIX UP OVERSHOOT
  820.     ADD    BX,DX
  821.     DEC    CH
  822.     MOV    AL,BH            ;TEST FOR WRAPAROUND
  823.     OR    AL,BL
  824.     JNZ    SKIP
  825.     MOV    BL,80H            ;RECORD LENGTH
  826.     DEC    CH
  827. ;
  828. SKIP:    MOV    AL,Byte Ptr EXTNUM    ;NOW FIX UP EXTENT NUM
  829.     ADD    AL,CH
  830.     MOV    Byte Ptr EXTNUM,AL
  831.     MOV    Byte Ptr BFCB+12,AL
  832.     MOV    AL,BL            ;MOD IS RECORD COUNT
  833.     MOV    Byte Ptr BFCB+15,AL    ;THAT GOES IN RC BYTE
  834. ;
  835. MOVDM:    MOV    AL,Byte Ptr BLKEXT    ;GET BLOCKS PER EXTENT
  836.     MOV    CH,AL            ;INTO B
  837. ;
  838. SETD1:    MOV    BX,Word Ptr DMPTR    ;POINT TO BAD ALLOCATION MAP
  839.     XCHG    BX,DX
  840.     MOV    BX,(Offset BFCB)+16    ;DISK ALLOC MAP IN FCB
  841. ;
  842. SETDML:    MOV    SI,DX
  843.     MOV    AL,[SI]
  844.     MOV    M,AL
  845.     INC    BX
  846.     INC    DX
  847. ;
  848. ;Now see if 16 bit groups...if so,
  849. ;we have to move another byte
  850. ;
  851.     MOV    AL,Byte Ptr DSM+1    ;THIS TELLS US
  852.     OR    AL,AL
  853.     JZ    BUMP1            ;IF ZERO, THEN NOT
  854.     MOV    SI,DX            ;IS 16 BITS, SO DO ANOTHER
  855.     MOV    AL,[SI]
  856.     MOV    M,AL
  857.     LAHF
  858.     INC    BX
  859.     SAHF
  860.     LAHF
  861.     INC    DX
  862.     SAHF
  863. ;
  864. BUMP1:    DEC    CH            ;COUNT DOWN
  865.     JNZ    SETDML
  866.     PUSH    DX
  867.     CALL    CLOSEB            ;CLOSE THIS EXTENT
  868.     POP    DX
  869.     RET
  870. ;
  871. ;Error messages
  872. ;
  873. SELERR:    MOV    DX,(Offset SELEMS)    ;SAY NO GO, AND BAIL OUT
  874.     JMP    PMSG
  875. ;
  876. SELEMS    DB    CR,LF,'Drive specifier out of range$'
  877. ;
  878. ERMSG5    DB    CR,LF,BEL,'+++ Warning...System tracks'
  879.     DB    ' bad +++',CR,LF,CR,LF,'$'
  880. ;
  881. ERROR6:    MOV    DX,(Offset ERMSG6)    ;OOPS...CLOBBERED DIRECTORY
  882.     JMP    PMSG
  883. ;
  884. ERMSG6    DB    CR,LF,BEL,'Bad directory area, try reformatting$'
  885. ;
  886. ERROR7:    MOV    DX,(Offset ERMSG7)    ;SAY NO GO, AND BAIL OUT
  887.     JMP    PMSG
  888. ;
  889. ERMSG7    DB    CR,LF,'Can''t create [UNUSED].BAD$'
  890. ;
  891. ;
  892. ;==== SUBROUTINES ====
  893. ;
  894. ;Decimal output routine
  895. ;
  896. DECOUT:    PUSH    CX
  897.     PUSH    DX
  898.     PUSH    BX
  899.     MOV    CX,-10
  900.     MOV    DX,-1
  901. ;
  902. DECOU2:    ADD    BX,CX
  903.     INC    DX
  904.     JB    DECOU2
  905.     MOV    CX,10
  906.     ADD    BX,CX
  907.     XCHG    BX,DX
  908.     MOV    AL,BH
  909.     OR    AL,BL
  910.     JZ    L_17    
  911.     CALL    DECOUT
  912. L_17:
  913.     MOV    AL,DL
  914.     ADD    AL,'0'
  915.     CALL    DISPLAY
  916.     POP    BX
  917.     POP    DX
  918.     POP    CX
  919.     RET
  920. ;
  921. ;Carriage-return/line-feed to console
  922. ;
  923. CRLF:    MOV    AL,CR
  924.     CALL    DISPLAY
  925.     MOV    AL,LF            ;FALL INTO 'DISPLAY'
  926. ;
  927. DISPLAY:PUSH    CX
  928.     PUSH    DX
  929.     PUSH    BX
  930.     MOV    DL,AL            ;CHARACTER TO [DX] FOR CP/M
  931.     MOV    CL,2            ;bdos PRINT CONSOLE function
  932.     INT    224            ;bdos PRINT CHARACTER
  933.     POP    BX
  934.     POP    DX
  935.     POP    CX
  936.     RET
  937. ;
  938. ;Subroutine to test console for control-c abort
  939. ;
  940. STOP:    MOV    BYTE PTR FUNC,2        ;BIOS CONSOLE STATUS FUNCTION
  941.     MOV    WORD PTR BIOS_DESC,0    ;PASS 'NOTHING' NUMBER TO BIOS DESCRIPTOR
  942.     MOV    WORD PTR BIOS_DESC+2,0    ;FILL REMAINING DESCRIPTOR (DX) ZERO
  943.     MOV    DX,(OFFSET FUNC)    ;POINT TO FUNCTION PARAMETER BLOCK
  944.     MOV    CL,50            ;direct bios call
  945.     INT    224            ;do it, to it...
  946. ;
  947.     OR    AL,AL            ;TEST FLAGS ON ZERO
  948.     JNZ    L_18    
  949.     RET                ;RETURN IF NO CHAR
  950. L_18:    MOV    BYTE PTR FUNC,3        ;BIOS READ CONSOLE CHARACTER FUNCTION
  951.     MOV    WORD PTR BIOS_DESC,0    ;PASS 'NOTHING' NUMBER TO BIOS DESCRIPTOR
  952.     MOV    WORD PTR BIOS_DESC+2,0    ;FILL REMAINING DESCRIPTOR (DX) ZERO
  953.     MOV    DX,(OFFSET FUNC)    ;POINT TO FUNCTION PARAMETER BLOCK
  954.     MOV    CL,50            ;direct bios call
  955.     INT    224            ;do it, to it...
  956. ;
  957.     CMP    AL,'C'-40H        ;IS IT CONTROL-C?
  958.     JZ    L_19    
  959.     RET                ;RETURN IF NOT
  960. L_19:
  961.     MOV    DX,(Offset ABORTM)    ;EXIT WITH MESSAGE
  962.     JMP    PMSG
  963. ;
  964. ABORTM    DB    CR,LF
  965.     DB    'Test aborted by control-C'
  966.     DB    CR,LF,'$'
  967. ;
  968. ;Move from [BX] to [DX], Count in [CX]
  969. ;
  970. MOVE:    MOV    AL,ES: M
  971.     MOV    SI,DX
  972.     MOV    [SI],AL
  973.     LAHF
  974.     INC    BX
  975.     SAHF
  976.     LAHF
  977.     INC    DX
  978.     SAHF
  979.     DEC    CH
  980.     JNZ    MOVE
  981.     RET
  982. ;
  983. ;Print byte in accumulator in hex
  984. ;
  985. HEXO:    LAHF                ;SAVE FOR SECOND HALF
  986.     XCHG    AL,AH
  987.     PUSH    AX
  988.     XCHG    AL,AH
  989.     ROR    AL,1            ;MOVE INTO POSITION
  990.     ROR    AL,1
  991.     ROR    AL,1
  992.     ROR    AL,1
  993.     CALL    NYBBLE            ;bdos PRINT MS NYBBLE
  994.     POP    AX
  995.     XCHG    AL,AH
  996. ;
  997. NYBBLE:    AND    AL,0FH            ;LO NYBBLE ONLY
  998.     ADD    AL,90H
  999.     DAA
  1000.     ADC    AL,40H
  1001.     DAA
  1002.     JMP    DISPLAY            ;bdos PRINT IN HEX
  1003. ;
  1004. ;Subroutine to determine the number
  1005. ;of groups reserved for the directory
  1006. ;
  1007. GETDIR:    MOV    CL,0            ;INIT BIT COUNT
  1008.     MOV    AL,Byte Ptr AL0        ;READ DIR GRP BITS
  1009.     CALL    COLECT            ;COLLECT COUNT OF DIR GRPS..
  1010.     MOV    AL,Byte Ptr AL1        ;..IN REGISTER [CL]
  1011.     CALL    COLECT
  1012.     MOV    BL,CL
  1013.     MOV    BH,0            ;[CX] NOW HAS A DEFAULT START GRP #
  1014.     MOV    Word Ptr DIRBKS,BX    ;SAVE FOR LATER
  1015.     RET
  1016. ;
  1017. ;Collect the number of '1' bits in A as a count in [CL]
  1018. ;
  1019. COLECT:    MOV    CH,8
  1020. ;
  1021. COLOP:    RCL    AL,1
  1022.     JNB    COSKIP
  1023.     INC    CL
  1024. ;
  1025. COSKIP:    DEC    CH
  1026.     JNZ    COLOP
  1027.     RET
  1028. ;
  1029. ;Routine to fill in disk parameters
  1030. ;
  1031. LOGIT:    MOV    DX,(Offset DPB)        ;   THEN MOVE TO LOCAL
  1032.     MOV    CH,(Offset DPBLEN)    ;  WORKSPACE
  1033.     CALL    MOVE
  1034.     RET
  1035. ;
  1036. L_22    EQU    $
  1037.     dseg    $
  1038.     ORG    Offset L_22
  1039. ;
  1040. ;--------------------------------------------------
  1041. ;The disk parameter block is moved here from CP/M-86
  1042. ;
  1043. DPB    EQU    (Offset $)        ;DISK PARAMETER BLOCK (COPY)
  1044. ;
  1045. SPT    RS    2            ;SECTORS PER TRACK
  1046. BSH    RS    1            ;BLOCK SHIFT
  1047. BLM    RS    1            ;BLOCK MASK
  1048. EXM    RS    1            ;EXTENT MASK
  1049. DSM    RS    2            ;MAXIMUM BLOCK NUMBER
  1050. DRM    RS    2            ;MAXIMUM DIRECTORY BLOCK NUMBER
  1051. AL0    RS    1            ;DIRECTORY ALLOCATION VECTOR
  1052. AL1    RS    1            ;DIRECTORY ALLOCATION VECTOR
  1053. CKS    RS    2            ;CHECKED DIRECTORY ENTRIES
  1054. SYSTRK    RS    2            ;SYSTEM TRACKS
  1055. ;
  1056. ;End of disk parameter block
  1057. ;
  1058. DPBLEN    EQU    (Offset $)-(Offset DPB)    ;LENGTH OF DISK PARM BLOCK
  1059. ;
  1060. ;--------------------------------------------------
  1061. BLKEXT    DB    0            ;BLOCKS PER EXTENT
  1062. DIRBKS    DW    0            ;CALCULATED # OF DIR BLOCKS
  1063. ;
  1064. BFCB    DB    0,'[UNUSED]BAD',0,0,0,0
  1065. FCBDM    RS    17
  1066. ;
  1067. NOMSG    DB    'No$'
  1068. ENDMSG    DB    ' bad blocks found',CR,LF,'$'
  1069. ;
  1070. BADBKS    DW    0            ;COUNT OF BAD BLOCKS
  1071. SECTOR    DW    0            ;CURRENT SECTOR NUMBER
  1072. TRACK    DW    0            ;CURRENT TRACK NUMBER
  1073. PHYSEC    DW    0            ;CURRENT PHYSICAL SECTOR NUMBER
  1074. SECTBL    DW    0            ;SECTOR SKEW TABLE POINTER
  1075. ;
  1076. EXTNUM    DB    0FFH            ;USED FOR UPDATING EXTENT NUMBER
  1077. DMCNT    DW    0            ;NUMBER OF BAD SECTORS
  1078. DMPTR    DW    (Offset DM)        ;POINTER TO NEXT BLOCK ID
  1079. ;
  1080. ;storage for 5 byte BIOS function descriptor
  1081. ;
  1082. FUNC        RS    1        ;bios function code goes here
  1083. BIOS_DESC    RS    2        ;[CX] data goes here
  1084.         RS    2        ;[DX] data goes here
  1085. ;
  1086. DM    EQU    (Offset $)        ;BAD BLOCK ALLOCATION MAP
  1087. ;
  1088.     DW    0            ;RESERVE 2 BYTES
  1089.     DW    0            ;RESERVE 2 BYTES
  1090.     DW    0            ;RESERVE 2 BYTES
  1091.     DW    0            ;RESERVE 2 BYTES
  1092.     DW    0            ;RESERVE 2 BYTES
  1093.     DW    0            ;RESERVE 2 BYTES
  1094.     DW    0            ;RESERVE 2 BYTES
  1095.     DW    0            ;RESERVE 2 BYTES
  1096.     DW    0            ;RESERVE 2 BYTES
  1097.     DW    0            ;RESERVE 2 BYTES
  1098.     DW    0            ;RESERVE 2 BYTES
  1099.     DW    0            ;RESERVE 2 BYTES
  1100.     DW    0            ;RESERVE 2 BYTES
  1101.     DW    0            ;RESERVE 2 BYTES
  1102.     DW    0            ;RESERVE 2 BYTES
  1103.     DW    0            ;RESERVE 2 BYTES
  1104.     DW    0            ;RESERVE 2 BYTES
  1105.     DW    0            ;RESERVE 2 BYTES
  1106.     DW    0            ;RESERVE 2 BYTES
  1107.     DW    0            ;RESERVE 2 BYTES
  1108.     DW    0            ;RESERVE 2 BYTES
  1109.     DW    0            ;RESERVE 2 BYTES
  1110.     DW    0            ;RESERVE 2 BYTES
  1111.     DW    0            ;RESERVE 2 BYTES
  1112.     DW    0            ;RESERVE 2 BYTES
  1113.     DW    0            ;RESERVE 2 BYTES
  1114.     DW    0            ;RESERVE 2 BYTES
  1115.     DW    0            ;RESERVE 2 BYTES
  1116.     DW    0            ;RESERVE 2 BYTES
  1117.     DW    0            ;RESERVE 2 BYTES
  1118.     DW    0            ;RESERVE 2 BYTES
  1119.     DW    0            ;RESERVE 2 BYTES
  1120.     DW    0            ;RESERVE 2 BYTES
  1121.     DW    0            ;RESERVE 2 BYTES
  1122.     DW    0            ;RESERVE 2 BYTES
  1123.     DW    0            ;RESERVE 2 BYTES
  1124.     DW    0            ;RESERVE 2 BYTES
  1125.     DW    0            ;RESERVE 2 BYTES
  1126.     DW    0            ;RESERVE 2 BYTES
  1127.     DW    0            ;RESERVE 2 BYTES
  1128.     DW    0            ;RESERVE 2 BYTES
  1129.     DW    0            ;RESERVE 2 BYTES
  1130.     DW    0            ;RESERVE 2 BYTES
  1131.     DW    0            ;RESERVE 2 BYTES
  1132.     DW    0            ;RESERVE 2 BYTES
  1133.     DW    0            ;RESERVE 2 BYTES
  1134.     DW    0            ;RESERVE 2 BYTES
  1135.     DW    0            ;RESERVE 2 BYTES
  1136.     DW    0            ;RESERVE 2 BYTES
  1137.     DW    0            ;RESERVE 2 BYTES
  1138.     DW    0            ;RESERVE 2 BYTES
  1139.     DW    0            ;RESERVE 2 BYTES
  1140.     DW    0            ;RESERVE 2 BYTES
  1141.     DW    0            ;RESERVE 2 BYTES
  1142.     DW    0            ;RESERVE 2 BYTES
  1143.     DW    0            ;RESERVE 2 BYTES
  1144.     DW    0            ;RESERVE 2 BYTES
  1145.     DW    0            ;RESERVE 2 BYTES
  1146.     DW    0            ;RESERVE 2 BYTES
  1147.     DW    0            ;RESERVE 2 BYTES
  1148.     DW    0            ;RESERVE 2 BYTES
  1149.     DW    0            ;RESERVE 2 BYTES
  1150. ;
  1151.     END
  1152.