home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / BEEHIVE / UTILITYS / FIRE12.ARC / FIRE12.Z80 < prev    next >
Text File  |  1991-08-11  |  59KB  |  2,332 lines

  1.     TITLE    'FiRe - File Restoral Utility Program'
  2. ;
  3. ;-----------------------------------------------------------------------
  4. ;
  5. ;    FIRE v12    by George F. Reding        08/10/87
  6. ;
  7. ; Utility program to restore disk files to like-new condition, where the
  8. ; file allocations for each file are in a sequential order rather than
  9. ; being scattered all over the disk (such as after a file/program has
  10. ; been modified).
  11. ;
  12. ;      NOTE: This program may possibly be not suitable
  13. ;        for use on a hard disk drive that has been
  14. ;        "partitioned"  into several pseudo-drives.
  15. ;        Use at your own risk especially in such case.
  16. ;
  17. ; DPB offset and table lengths for CP/M 2.2 are different from those for
  18. ; CP/M 3.0.  They are now automatically set by the program, and the BIOS
  19. ; access is performed differently, eliminating the need to copy BIOS
  20. ; vectors into the program.  Much 8080 code is changed to Z80 which con-
  21. ; serves memory space and increases the speed of the program, although
  22. ; it does restrict usage to computers with Z80 microprocessors.  You may
  23. ; use the program even if available (TPA) memory falls short of the cap-
  24. ; ability to handle your system maximum directory entry capacity (BSH,
  25. ; BLM, DRM, and AL0 & AL1 values are all factors).  Either your TPA may
  26. ; be too low, or your system directory capacity (DRM) is too large e.g.,
  27. ; 2048 or more? max entries capacity.  If the situation does arise, a
  28. ; message is given of the  MAXIMUM ACTIVE entries that you may have to
  29. ; be able to continue, and you may abort if you desire not to continue.
  30. ; The user should ensure that there are LESS active directory entries
  31. ; by using DU, after usage of SAP.
  32. ;
  33. ;     >> WARNING <<    To CONTINUE with MORE entries ACTIVE
  34. ;     than the figure shown WILL TRASH both files and di-
  35. ;     rectory.  Because of the memory limitation and dif-
  36. ;     ferences among systems, no warranties are expressed
  37. ;     or implied and a user of this program shall assume
  38. ;     any and all responsibility for results arising from
  39. ;     usage of the program.
  40. ;
  41. ; CP/M 3 test made on a Morrow MD-11 with two 20M hard drives, 22,004k
  42. ; formatted capacity.  Morrow directory entry maximum is 2048 entries
  43. ; for each hard drive.
  44. ;                    George F Reding
  45. ;                    P.O. Box 86386
  46. ;                    North Vancouver, BC
  47. ;                    Canada    V7L 4K6
  48. ;
  49. ;                    CompuServe: 72436,45
  50. ;
  51. ;
  52. ; 08/10/87  Modified CONBUF routine so that if return only is entered
  53. ;   v12     after the summary is given that the program will properly
  54. ;        abort.            - George Reding
  55. ;
  56. ; 07/13/87  The original clobbered the DE register in the XBIOS2 routine
  57. ;   v11     which would cause RECTRAN for CP/M 2.2 to nor work properly.
  58. ;                    - George Reding
  59. ;
  60. ; 06/15/87  Orginal version of FIRE.  Created from RESTORE v 1.2.
  61. ;   v10     Created from RESTORE v 1.2
  62. ;
  63. ;-----------------------------------------------------------------------
  64. ;
  65. ; Created from:  RESTORE v 1.2
  66. ;        by:  Steve Dirickson
  67. ;         21145 Raintree Place NW
  68. ;         Poulsbo, WA  98370-9726
  69. ;
  70. ; Other credit:
  71. ;        CPM22E by Mike Griswold
  72. ;        SYSLIB by Richard Conn
  73. ;
  74. ;-----------------------------------------------------------------------
  75. ;
  76. ;    ASEG            ; M80 needs this
  77. ;
  78. NO    EQU    0
  79. YES    EQU    NOT NO        ; For conditional assembly
  80. ;
  81. DEBUG    EQU    NO        ; Yes for debug display
  82. PROTCT    EQU    NO        ; Yes to disable disk write
  83. ;
  84. VER    EQU    12        ; Version number
  85. VERM    EQU    08        ; Version month
  86. VERD    EQU    10        ; Version day
  87. VERY    EQU    87        ; Version year
  88. ;
  89. ; System equates
  90. ;
  91. BDOS    EQU    0005H        ; BDOS
  92. DPB2OF    EQU    10        ; Offset to CP/M 2.2 DPB
  93. DPB2LN    EQU    15        ; Length of CP/M 2.2 dpb
  94. DPB3OF    EQU    12        ; Offset to CP/M 3.0 dpb
  95. DPB3LN    EQU    17        ; Length of CP/M 3.0 dpb
  96. FCB    EQU    5CH
  97. ;
  98. RCCPM3    EQU    1024        ; Size of CP/M 3.0 record buffer
  99.                 ; Set to your largest record size
  100. ; Bdos function codes
  101. ;
  102. CONINF    EQU    1        ; Console input
  103. CONOUF    EQU    2        ;    "      output
  104. RDCBUF    EQU    10        ; Read console buffer
  105. CONSTF    EQU    11        ; Console status
  106. RETVER    EQU    12        ; Return version #
  107. RESETF    EQU    13        ; Reset disk
  108. GETDSK    EQU    25        ; Get default disk
  109. ;
  110. ; Ascii characters
  111. ;
  112. BEL    EQU    07H        ; Bell
  113. BS    EQU    08H        ; Backspace
  114. CR    EQU    0DH        ; Carriage return
  115. LF    EQU    0AH        ; Linefeed
  116. TAB    EQU    09H        ; Tab
  117. ;
  118. ;-----------------------------------------------------------------------
  119. ;
  120. ; Macros to make things easier
  121. ;
  122. PUSHRG     MACRO
  123.     PUSH    HL
  124.     PUSH    DE
  125.     PUSH    BC
  126.      ENDM
  127. ;
  128. POPRG     MACRO
  129.     POP    BC
  130.     POP    DE
  131.     POP    HL
  132.      ENDM
  133. ;
  134. ;-----------------------------------------------------------------------
  135. ;
  136. ;
  137.     ORG    100H
  138. ;
  139. FIRE:    JP    CPUTST
  140.                 ; May be modified with SID/DDT
  141. DWAIT:    DEFB    0FFH        ; Non-zero for disk change wait
  142. ADDLF:    DEFB    0        ; Zero = no LF, else 0Ah = LF
  143. RECSIZ:    DEFW    RCCPM3        ; Size of CP/M 3.0 record buffer
  144. ;
  145. ; Use Bob Freed's z80 CPU test
  146. ;
  147. CPUTST:    SUB    A        ; Z80 test
  148.     JP    PO,SIGNON    ; If Z80, continue
  149.     CALL    PRINT        ; Else give msg
  150.     DEFB    CR,LF,'Z80 needed',CR,LF,0
  151.     JP    0000H        ; And quit
  152. ;
  153. ; Get version, see if valid, then give program name/version
  154. ;
  155. SIGNON:    LD    C,RETVER    ; Get version
  156.     CALL    BDOS
  157.     LD    A,L        ; Get version to 'A'
  158.     LD    (VERFLG),A    ; Store it
  159.     CP    22H        ; Must be at least 2.2
  160.     JP    C,0000H        ; If less then quit
  161.     LD    A,H
  162.     OR    A        ; Test for 0 for CP/M
  163.     JP    NZ,0000H    ; If not, quit as MP/M untested
  164. ;
  165.     CALL    PRINT
  166.     DEFB    CR,LF,LF,'FiRe v'
  167.     DEFB    VER/10+'0',(VER    MOD    10)+'0',' '
  168.     DEFB    VERM/10+'0',(VERM MOD 10)+'0','/'
  169.     DEFB    VERD/10+'0',(VERD MOD 10)+'0','/'
  170.     DEFB    VERY/10+'0',(VERY MOD 10)+'0',' '
  171.     DEFB    ' GFR',0
  172. ;
  173.     LD    A,(DWAIT)
  174.     OR    A
  175.     JR    Z,CLRDT        ; Skip if no disk change wait
  176.     CALL    PRINT
  177.     DEFB    CR,LF,LF,'Change disk - '
  178.     DEFB    'any key continues ',0
  179.     CALL    CONBUF        ; Wait for input
  180. ;
  181. ; Initialize data and buffer areas to zero
  182. ;
  183. CLRDT:    XOR    A        ; Clear data/stack space to 0
  184.     LD    HL,DATA        ; Point to 1st spot (source)
  185.     LD    (HL),A        ; Fill 1st
  186.     LD    DE,DATA+1    ; Point to 2nd spot (destination)
  187.     LD    BC,DATSIZ    ; Length
  188.     LDIR            ; Zero it all
  189. ;
  190. ; Next is for CP/M plus in debug mode
  191. ;
  192.      IF    DEBUG
  193.     PUSHRG
  194.     CALL    V3CHEK
  195.     JR    C,CLRDT1    ; If not CP/M 3.0 skip this
  196.     PUSH    HL        ; Save HL
  197.     CALL    PRINT
  198.     DEFB    CR,LF,'HSTBUF: ',0
  199.     POP    HL        ; Restore for display
  200.     CALL    PHL4HC
  201. CLRDT1:    POPRG
  202.      ENDIF
  203. ;
  204. ; Only CP/M 3.0 needs the next buffer
  205. ;
  206.     CALL    V3CHEK        ; Cy set if not 3.0
  207.     JR    C,CLRDT2    ; Skip if 2.2
  208.     XOR    A        ; Zero for fill
  209.     LD    (HSTBUF),HL    ; Save address of CP/M 3.0 record buffer
  210.     LD    BC,(RECSIZ)    ; Get size of CP/M 3.0 record buffer
  211.     LDIR
  212. ;
  213. ; Save directory buffer start address, initialize this buffer
  214. ;
  215. CLRDT2:    LD    (DIRECT),HL    ; Save address of directory buffer
  216. ;
  217.      IF    DEBUG
  218.     PUSHRG
  219.     PUSH    HL        ; Save HL
  220.     CALL    PRINT
  221.     DEFB    CR,LF,'DIRECT: ',0
  222.     POP    HL        ; Restore for display
  223.     CALL    PHL4HC
  224.     POPRG
  225.      ENDIF
  226. ;
  227.     XOR    A        ; Zero
  228.     LD    (HL),A        ; The 1st location (source)
  229.     LD    BC,256*32    ; Length to fill
  230.     LDIR
  231. ;
  232. ; Buffers initialized, now set up stack and linefeed char
  233. ;
  234.     LD    SP,STACK    ; Set our own stack
  235.     LD    A,(ADDLF)    ; Get LF character or zero
  236.     LD    (FILELF),A    ; Store it
  237. ;
  238. ; Set up dpb length and dpb offset according to CP/M version
  239. ;
  240. SETDPB:    CALL    V3CHEK        ; Carry set if not 3.0
  241.     JR    C,STDPB2    ; Skip if 2.2
  242.     LD    HL,DPB3OF    ; Offset XLT address to DPB address
  243.     LD    (DPBOF),HL    ; Was defaulted for CP/M 2.2
  244.     LD    HL,DPB3LN    ; Length of CP/M 3.0 DPB table
  245.     LD    (DPBLN),HL    ; Was defaulted for CP/M 2.2
  246. ;
  247. ; The next protect conditional changed to be compatible.
  248. ; Wasn't sure if the original would work under CP/M 3.0.  <gfr>
  249. ;
  250. STDPB2:
  251.      IF    PROTCT
  252.     LD    A,0AFH        ; Store "XOR A" op code
  253.     LD    (WRITE),A    ; At start of write routine
  254.     LD    A,0C9H        ; Store "RET" op code
  255.     LD    (WRITE+1),A    ; Just after it
  256.      ENDIF
  257. ;
  258. ; If no disk specified on command line, get current disk
  259. ;
  260. SETUP:    LD    A,(FCB)        ; Check for any drive
  261.     DEC    A
  262.     JP    P,SETUP1    ; Skip if disk mentioned
  263.     LD    C,GETDSK    ; Get current disk (0=A,1=B,...)
  264.     CALL    BDOS
  265. ;
  266. ; Save disk, give msg, reset disk (CP/M 3.0), and go select it
  267. ;
  268. SETUP1:    LD    (LOGDSK),A    ; Save disk for CP/M 3.0
  269.     PUSH    AF        ; Save it
  270.     CALL    PRINT        ; Give drive message
  271.     DEFB    CR,LF,LF,'Drive: ',0
  272.     POP    AF        ; Restore disk
  273.     PUSH    AF        ; Resave it
  274.     ADD    A,'A'        ; Convert to ASCII
  275.     LD    (ASCDSK),A    ; Save ASCII disk letter
  276.     LD    E,A
  277.     CALL    CONOUT
  278.     LD    C,RESETF    ; Reset disk for CP/M 3.0
  279.     CALL    BDOS
  280.     POP    AF        ; Restore disk
  281.     LD    C,A        ; Disk to 'C'
  282.     CALL    SELECT        ; Select disk and get parameters
  283. ;
  284. ; Check that there is enough memory to read in the directory.
  285. ; Get the max # of dir entries that will fit in available memory.
  286. ;
  287. GTDRMX:    LD    A,(BDOS+2)    ; Fetch BDOS page
  288.     DEC    A        ; Less one
  289.     LD    HL,(DIRECT)    ; Subtract start of directory buffer
  290.     SUB    H        ; To get space available for directory
  291.     LD    H,0
  292.     LD    L,A        ; # of 256-byte pages available
  293.     ADD    HL,HL        ; *2  multiply by 8 to get number of
  294.     ADD    HL,HL        ; *2  32-byte directory entries
  295.     ADD    HL,HL        ; *2  that will fit
  296. ;
  297.      IF    DEBUG
  298.     PUSHRG
  299.     PUSH    HL        ; Save HL
  300.     CALL    PRINT
  301.     DEFB    CR,LF,'MAXDIR: ',0
  302.     POP    HL        ; Restore for display
  303.     CALL    PHLFDC
  304.     POPRG
  305.      ENDIF
  306. ;
  307.     LD    DE,(DRM)    ; Get # of directory entries on disk
  308.     INC    DE        ; Convert from 0-relative to 1-relative
  309.     OR    A
  310.     SBC    HL,DE        ; Subtr from max that will fit
  311.     JP    NC,CKDRBF    ; Ok if enough room
  312. ;
  313. ;-----------------------------------------------------------------------
  314. ;
  315. ; Adjust maximum directory number (DRM) to a smaller/fake value for cases
  316. ; where the directory has a capacity to hold 2048 (or more??) entries, or
  317. ; in cases where the TPA may fall short of of capability to handle all of
  318. ; the directory entries.  Adjust the directory group count (AL0 and AL1)
  319. ; which varies with BLM (block size BLS) so that it matches with the
  320. ; smaller/fake DRM value.  In order to use the program in such cases of
  321. ; too many directory entries and/or of too little TPA space the TOTAL of
  322. ; ACTIVE directory entries will have to be verified by the user with
  323. ; "DU" or some equivilent program (after using "CLEANDIR", "SAP", "SAPP",
  324. ; etc).  A warning message and the maximum number of active entries that
  325. ; the program can handle is given, with opportunity for the user to
  326. ; abort.  Faking of the DRM value is similar to that which "SAPP" (for
  327. ; CP/M 3.0) is capable of (an assembly time option).  The way I have im-
  328. ; plemented it here is an improvement though and "SAPP" will subsequently
  329. ; be updated to implement this means of "auto-faking".    - George Reding
  330. ;
  331.     LD    A,(BSH)
  332.     LD    B,A
  333.     LD    HL,128        ; Calculate BLS
  334. ;
  335. LESSBK:    ADD    HL,HL        ; Shift HL left BSH times
  336.     DJNZ    LESSBK
  337.     ADD    HL,HL        ; *2 for size of 2 buffers
  338.     LD    DE,(DIRECT)    ; Start of directory buffer
  339.     ADD    HL,DE        ; Add to get space used up
  340. ;
  341.     CALL    V3CHEK        ; Carry set if not 3.0
  342.     JR    C,NO3BUF    ; Skip if 2.2
  343.     LD    DE,(RECSIZ)    ; Get size of CP/M 3.0 record buffer
  344.     ADD    HL,DE        ; Add it to the space used up
  345. ;
  346. NO3BUF:    EX    DE,HL        ; Space used up to DE
  347.     LD    HL,(BDOS+1)    ; BDOS page (memory top) to HL
  348.     OR    A        ; Clear for subtract
  349.     SBC    HL,DE        ; Subtract space used from available
  350.     LD    L,H        ; # of 256 byte pages available to L
  351.     LD    H,0
  352.     DEC    L        ; Less one page
  353.     ADD    HL,HL        ; *2  multiply by 8 to get number of
  354.     ADD    HL,HL        ; *2  32-byte directory entries
  355.     ADD    HL,HL        ; *2  that will fit
  356.     LD    (NEWMAX),HL    ; Save memory maximum directory entries
  357. ;
  358. ; Now have faked maximum directory entries.  Now calculate new directory
  359. ; allocation groups
  360. ;
  361.     LD    A,(BLM)        ; Get block size
  362.     INC    A        ; Make 1 relative
  363.     LD    L,A        ; Put into HL
  364.     LD    H,0
  365.     LD    DE,8        ; Divisor 8 - 128 blocks make 1k
  366.     CALL    UDIVID        ; Result HL = block size k's
  367.     LD    (BLMSIZ),HL    ; Save block k size
  368. ;
  369.     EX    DE,HL        ; Move k size to DE (divisor)
  370.     LD    HL,(NEWMAX)    ; Get memory maximum (dividend)
  371.     CALL    UDIVID
  372.     LD    DE,32        ; Divisor 32 entries per k
  373.     CALL    UDIVID
  374.     LD    H,0        ; Zero high
  375.     LD    A,L        ; Result (new groups) into 'A'
  376.     LD    (NEWGRP),A    ; Save new/fake group count
  377. ;
  378. ; Now have new directory groups.  Recalculate matching new fake DRM.
  379. ;
  380.     LD    DE,32        ; Mult by 32 entries
  381.     CALL    MULT
  382.     LD    DE,(BLMSIZ)    ; Mult by k size
  383.     CALL    MULT
  384.     DEC    HL        ; Make 0-relative
  385.     LD    (FAKDRM),HL    ; Save new/fake "DRM"
  386. ;
  387.     CALL    PRINT
  388.     DEFB    CR,LF,LF,BEL
  389.     DEFB    'Insufficient directory room',CR,LF,LF
  390.     DEFB    'Continue ONLY IF LESS than ',0
  391.     LD    HL,(FAKDRM)    ; Get fake maximum entries
  392.     INC    HL
  393.     CALL    PHLFDC
  394.     CALL    PRINT
  395.     DEFB    ' entries are ACTIVE!',CR,LF
  396.     DEFB    'To continue IF MORE WILL DESTROY'
  397.     DEFB    ' directory & files!',CR,LF,LF
  398.     DEFB    'Press ''Y'' to continue,'
  399.     DEFB    ' else aborts: ',0
  400. ;
  401.     CALL    CONBUF        ; Get response
  402.     LD    A,(INBUF+2)
  403.     AND    31        ; "Y", "y", and "^Y" are equiv
  404.     CP    'Y'-40H
  405.     JP    NZ,0000H    ; If not Y, then abort
  406. ;
  407.     LD    HL,(FAKDRM)    ; Get our fake value
  408.     LD    (DRM),HL    ; Store it
  409.     CALL    DOCOLL        ; Get group count and 1st group
  410.                 ;   don't save real group count
  411.     LD    A,(NEWGRP)    ; Get our fake group count
  412.     LD    (DIRGRP),A    ; Save fake # of group instead
  413.     JR    FAKGRP        ; Save real start/search group
  414. ;
  415. ; If enough memory, set up variables (see above about faking)
  416. ;
  417. CKDRBF:    CALL    DOCOLL        ; Get group count and 1st group
  418.     LD    (DIRGRP),A    ; Save # of groups in directory
  419. FAKGRP:    LD    (STRTGP),HL    ; Starting group in case faked
  420.     LD    (SRCHGP),HL    ; Save 1st group after directory
  421. ;
  422. ;-----------------------------------------------------------------------
  423. ;
  424. ; Then read in the directory
  425. ;
  426.     CALL    READDR        ; Read in the directory
  427. ;
  428.     LD    DE,(DRM)    ; Get maximum # of directory entries in DE
  429.     INC    DE        ; Make 1-relative
  430.     LD    (DIRACT),DE    ; Default to all entries active
  431. ;
  432. ; Count active directory entries by finding 1st erased entry if any
  433. ;
  434.     LD    BC,32        ; Size of each entry
  435.     LD    HL,(DIRECT)
  436. FINDER:    LD    A,0E5H        ; Look for first 'E5' in user #
  437.     CP    (HL)
  438.     JR    Z,FOUNDR
  439.     ADD    HL,BC        ; Bump pointer to next entry
  440.     DEC    DE
  441.     LD    A,E
  442.     OR    D        ; See if all entries checked
  443.     JR    NZ,FINDER    ; Loop if some left
  444.     JR    DRNMST        ; If no 'E5' found, already set up
  445. ;
  446. ; Now calculate the number of active entries
  447. ;
  448. FOUNDR:    PUSH    HL        ; Save pointer to 1st erased entry
  449.     LD    HL,(DRM)    ; Calculate # of entries found
  450.     INC    HL
  451.     OR    A
  452.     SBC    HL,DE        ; Subtr # of entries left
  453.     LD    (DIRACT),HL    ; Save # of active dir entries
  454. ;
  455.      IF    DEBUG
  456.     PUSHRG
  457.     PUSH    HL        ; Save HL
  458.     CALL    PRINT
  459.     DEFB    CR,LF,'DIRACT: ',0
  460.     POP    HL        ; Restore for display
  461.     CALL    PHLFDC
  462.     POPRG
  463.      ENDIF
  464. ;
  465. ; Because Morrow had an oddity (possibly others) of setting the RC field
  466. ; to 00H on newly formatted HARD drives, the set of DE (should have been
  467. ; BC) register to the bytes-left value is now remarked out (below) and a
  468. ; value of 13 is used for "remaining bytes to check".  Besides, if  13
  469. ; "sequential bytes" are 0E5h you can probably bet your booties any r-
  470. ; emaining bytes are the same, ensuring the directory was sorted and
  471. ; cleaned with SAP.
  472. ;
  473. ;;;    LD    HL,32        ; Mult entries left by 32
  474. ;;;    CALL    MULT        ; To get # of bytes
  475. ;;;    EX    DE,HL        ; Move count of bytes left to DE
  476.     LD    BC,13        ; Check 13 bytes, see note above
  477.     POP    HL        ; Restore pointer to 1st erased entry
  478. ;
  479. ; Ensure remaining free directory space is erased
  480. ;
  481. CKERLP:    LD    A,0E5H        ; Check that the rest of directory
  482.     CPI            ; Is erased
  483. ;
  484.      IF    DEBUG
  485.     JP    NZ,DRNSRT
  486.      ELSE
  487.     JR    NZ,DRNSRT    ; Error if anything but 'E5' found
  488.      ENDIF
  489.     JP    PE,CKERLP    ; Loop until rest of directory checked
  490. ;
  491. ; Calculate total dir bytes, save 1st buffer address
  492. ;
  493. DRNMST:    LD    HL,(DRM)    ; Max # of directory entries
  494.     INC    HL        ; Make 1-relative
  495.     LD    DE,32        ; Size of each directory entry
  496.     CALL    MULT        ; Hl has # of bytes in directory buffer
  497.     LD    (DIRBYT),HL    ; Save it
  498. ;
  499.      IF    DEBUG
  500.     PUSHRG
  501.     PUSH    HL        ; Save HL
  502.     CALL    PRINT
  503.     DEFB    CR,LF,'DIRBYT: ',0
  504.     POP    HL        ; Restore for display
  505.     CALL    PHL4HC
  506.     POPRG
  507.      ENDIF
  508. ;
  509.     LD    DE,(DIRECT)    ; Size in HL, get directory buffer start
  510.     ADD    HL,DE        ; Add size and directory buffer start
  511.     LD    (GRBUF1),HL    ; Addr of 1st group buffer
  512. ;
  513.      IF    DEBUG
  514.     PUSHRG
  515.     PUSH    HL        ; Save HL
  516.     CALL    PRINT
  517.     DEFB    CR,LF,'GRBUF1: ',0
  518.     POP    HL        ; Restore for display
  519.     CALL    PHL4HC
  520.     POPRG
  521.      ENDIF
  522. ;
  523.     LD    A,(BDOS+2)    ; Fetch BDOS page
  524.     DEC    A        ; Less one
  525.     SUB    H        ; Subtr buffer address
  526.     LD    D,A        ; Move to high, to multiply by 256
  527.     LD    E,0        ; DE = bytes available for buffers
  528. ;
  529. ; Calculate the size of each block on the disk - 1k, 2k, 4k, etc.
  530. ; See if room for two buffers.
  531. ;
  532. CALBLS:    LD    A,(BSH)
  533.     LD    B,A
  534.     LD    HL,128        ; Calculate BSL
  535. ;
  536. CBLSLP:    ADD    HL,HL        ; Shift HL left bsh times
  537.     DJNZ    CBLSLP
  538.     LD    (BLS),HL    ; HL = block size (BLS) bytes, 1024, 2048,..
  539.     ADD    HL,HL        ; Double to get size of 2 buffers
  540.     EX    DE,HL        ; Put available space back in HL
  541.     OR    A
  542.     SBC    HL,DE        ; Subtr buffer size from available space
  543. ;
  544.     JP    NC,CKSORT    ; Ok if no carry
  545.     CALL    PRINT
  546.     DEFB    CR,LF,LF,'Insufficient '
  547.     DEFB    ' buffers room',BEL,0
  548.     JP    0000H
  549. ;
  550. DRNSRT:    CALL    PRINT        ; Directory unsorted error message
  551.     DEFB    CR,LF,LF,'Unsorted - use SAPP or'
  552.     DEFB    ' equivilent first',CR,LF,0
  553.     JP    0000H
  554. ;
  555. ; Calculate and save addr of 2nd buffer
  556. ;
  557. CKSORT:    LD    DE,(BLS)
  558.     LD    HL,(GRBUF1)    ; Calculate address of 2nd group buffer
  559.     ADD    HL,DE
  560.     LD    (GRBUF2),HL
  561. ;
  562.      IF    DEBUG
  563.     PUSHRG
  564.     PUSH    HL        ; Save HL
  565.     CALL    PRINT
  566.     DEFB    CR,LF,'GRBUF2: ',0
  567.     POP    HL        ; Restore for display
  568.     CALL    PHL4HC
  569.     POPRG
  570.      ENDIF
  571. ;
  572.     CALL    PRINT        ; Hard drives may take time
  573.     DEFB    CR,LF,LF,'Calculating...',0
  574. ;
  575.     LD    DE,(DIRECT)    ; Put start of directory in DE
  576.     LD    HL,32
  577.     ADD    HL,DE        ; Point to 2nd directory entry
  578.     EX    DE,HL        ; Now HL = 1st entry, DE = 2nd
  579.     LD    BC,(DIRACT)    ; # of entries to check
  580.     DEC    BC        ; Minus 1
  581. ;
  582. ; Ensure the directory is sorted
  583. ;
  584. CKSTLP:    CALL    CMPDIR        ; Compare the two directory entries
  585.     JP    C,DRNSRT    ; Error if unsorted
  586.     PUSH    BC
  587.     LD    BC,32        ; Size of directory entries
  588.     EX    DE,HL
  589.     ADD    HL,BC        ; Bump pointers
  590.     EX    DE,HL
  591.     ADD    HL,BC
  592.     POP    BC
  593.     DEC    BC
  594.     LD    A,B
  595.     OR    C
  596.     JR    NZ,CKSTLP    ; Loop until done
  597. ;
  598. ; Directory is verified to be sorted
  599. ;
  600.     LD    B,16        ; Assume 8 bit groups
  601.     LD    A,(DSM+1)
  602.     OR    A
  603.     JR    Z,SGRPAL
  604.     LD    B,8
  605. ;
  606. SGRPAL:    LD    A,B
  607.     LD    (GRPALL),A    ; Save # of allocation groups per entry
  608.     XOR    A        ; Clear stats flag
  609.     LD    (STATS),A    ; Zero means stats only
  610. ;
  611. REDO:    LD    A,(STATS)    ; Get stats flag
  612.     OR    A
  613.     CALL    NZ,READDR    ; If after stat pass, reread directory
  614. ;
  615. ; Set initial starting group to be the 1st group after directory
  616. ;
  617.     LD    HL,(STRTGP)    ; Starting group in case faked
  618.     LD    (SRCHGP),HL
  619. ;
  620.     LD    HL,(DIRACT)
  621.     LD    (DIRCTR),HL    ; Initialize directory entry counter
  622.     LD    HL,(DIRECT)    ; Point to 1st entry in directory
  623. ;
  624. ; Main program loop (finally)
  625. ;
  626. ; On entry, HL points to next directory entry to be checked.  (SRCHGP)
  627. ; holds the 1st alloc group we want this file to have.    The allocation
  628. ; group pointer and counter are set up, then the inner loop is entered
  629. ; to process each allocation group assigned to this file.
  630. ;
  631. RECOVR:    LD    (FILPTR),HL    ; Save pointer to next file
  632.     LD    A,(STATS)
  633.     OR    A
  634.     JR    Z,RECOV1
  635. ;
  636. SHOFIL:    CALL    PRINT        ; Show user what we're doing
  637.     DEFB    CR
  638. FILELF:    DEFB    0,0        ; Program sets to 0 or linefeed
  639. ;
  640.     CALL    PRINT
  641.     DEFB    'Relocating:  ',0
  642.     LD    A,(ASCDSK)
  643.     LD    E,A
  644.     CALL    CONOUT
  645.     LD    HL,(FILPTR)    ; Get file pointer
  646.     PUSH    HL
  647.     LD    A,(HL)        ; Get user #
  648.     CALL    PAFDC
  649.     LD    E,':'
  650.     CALL    CONOUT
  651.     POP    DE        ; Get file pointer back to 'DE'
  652.     INC    DE        ; Bump past user #
  653.     CALL    PFN1
  654.     CALL    CTLCS        ; See if abort requested
  655.     JP    Z,ABORT
  656. ;
  657. RECOV1:    LD    HL,(FILPTR)    ; Restore file pointer
  658.     LD    DE,16        ; Offset to allocation map
  659.     ADD    HL,DE
  660.     LD    (ALLPTR),HL    ; Pointer to working allocation group
  661. ;
  662.      IF    DEBUG
  663.     PUSHRG
  664.     PUSH    HL        ; Save HL
  665.     CALL    PRINT
  666.     DEFB    CR,LF,'ALLPTR: ',0
  667.     POP    HL        ; Restore for display
  668.     CALL    PHL4HC
  669.     POPRG
  670.      ENDIF
  671. ;
  672.     LD    A,(GRPALL)    ; Get max # of alloc groups per entry
  673.     LD    (GRPNUM),A    ; Save it as the group counter
  674. ;
  675. ; Inner loop to process each directory entry.  This loop steps through
  676. ; the allocation map for the current directory entry, checking that the
  677. ; next allocation group is the next sequential group.  If it isn't, the
  678. ; group allocated to this file is swapped with the next sequential group
  679. ; if it is also allocated, or simply copied to the next group if unallo-
  680. ; cated.  The directory entries are updated to reflect the group swap.
  681. ; The loop also terminates when a zero allocation group is found, indi-
  682. ; cating that no more groups are allocated to this directory entry.
  683. ;
  684. ; On entry, HL points to the next allocation group in the disk map of
  685. ; the current directory entry.    This should be the next consecutive al-
  686. ; location group.  If not, the group pointed at is swapped with the next
  687. ; sequential group.
  688. ;
  689. ; (SRCHGP) holds the number of the next sequential group
  690. ;
  691. RECLP:    LD    HL,(ALLPTR)    ; Pointer to next map entry to check
  692.     LD    BC,0        ; Check for no more groups allocated
  693.     CALL    GRPCMP        ; For this directory entry
  694.     JP    Z,DONXEN    ; If so, skip to next entry
  695. ;
  696.      IF    DEBUG
  697.     PUSHRG
  698.     CALL    PRINT
  699.     DEFB    CR,LF,'At RECLP, SRCHGP: ',0
  700.     LD    HL,(SRCHGP)
  701.     CALL    PHL4HC
  702.     POPRG
  703.      ENDIF
  704. ;
  705.     LD    HL,(SGPCTR)    ; Increment allocation group counter
  706.     INC    HL
  707.     LD    (SGPCTR),HL
  708. ;
  709.     LD    HL,(ALLPTR)    ; Get back pointer
  710.     LD    BC,(SRCHGP)    ; Next sequential group that should be there
  711. ;
  712.     CALL    GRPCMP        ; See if the next group is already in place
  713.     JP    Z,DONEXT    ; Skip if no swap of group needed
  714. ;
  715. SWAP:    LD    A,0FFH        ; Set flag that directory has changed
  716.     LD    (DIRCHG),A
  717.     LD    HL,(SWPCTR)    ; Increment swap counter
  718.     INC    HL
  719.     LD    (SWPCTR),HL
  720.     CALL    GETGRP        ; If swap needed, see if it's allocated
  721.     LD    (GRPTR),HL    ; Save possible allocation pointer
  722. ;
  723.      IF    DEBUG
  724.     PUSHRG
  725.     PUSH    HL        ; Save HL
  726.     CALL    PRINT
  727.     DEFB    CR,LF,'GRPTR: ',0
  728.     POP    HL        ; Restore for display
  729.     CALL    PHL4HC
  730.     POPRG
  731.      ENDIF
  732. ;
  733.     LD    A,H
  734.     OR    L
  735.     PUSH    AF        ; Save flags
  736.     JR    Z,COPY2        ; If not allocated, don't worry about copy
  737. ;
  738.      IF    DEBUG
  739.     PUSHRG
  740.     CALL    PRINT
  741.     DEFB    CR,LF,'Copying group ',0
  742.     LD    HL,(SRCHGP)
  743.     CALL    PHL4HC
  744.     CALL    PRINT
  745.     DEFB    ' to GRBUF1',0
  746.     POPRG
  747.      ENDIF
  748. ;
  749. COPY1:    LD    A,(STATS)
  750.     OR    A
  751.     JR    Z,COPY1X    ; Skip if stats only
  752.     LD    DE,(SRCHGP)
  753.     CALL    DEGRUP        ; Select track and sector for desired group
  754.     LD    HL,(GRBUF1)    ; Select DMA address
  755.     LD    (DMAADR),HL
  756.     CALL    READGP        ; Read the group into group buffer 1
  757. ;
  758. COPY1X:    LD    HL,(GRDCTR)    ; Increment group read counter
  759.     INC    HL
  760.     LD    (GRDCTR),HL
  761.  
  762. COPY2:    LD    HL,(ALLPTR)    ; Get bad group in current entry
  763.     LD    E,(HL)
  764.     LD    A,(DSM+1)    ; See if 8 or 16-bit groups
  765.     OR    A
  766.     JR    Z,COPY2S    ; Skip if small groups
  767.     INC    HL
  768.     LD    D,(HL)
  769.     JR    COPY2M
  770. ;
  771. COPY2S:    LD    D,0        ; Zero high byte for small groups
  772. ;
  773. COPY2M:    LD    (BADGRP),DE    ; Save # of group being swapped
  774. ;
  775.     LD    A,(STATS)
  776.     OR    A
  777.     JR    Z,COPY2X    ; Skip if stats only
  778. ;
  779.      IF    DEBUG
  780.     PUSHRG
  781.     CALL    PRINT
  782.     DEFB    CR,LF,'Copying group ',0
  783.     LD    HL,(BADGRP)
  784.     CALL    PHL4HC
  785.     CALL    PRINT
  786.     DEFB    ' to GRBUF2',0
  787.     POPRG
  788.      ENDIF
  789. ;
  790. COPY2A:    CALL    DEGRUP        ; Select it
  791.     LD    HL,(GRBUF2)    ; Select DMA addr
  792.     LD    (DMAADR),HL
  793.     CALL    READGP        ; Read it into buffer 2
  794. ;
  795. COPY2X:    LD    HL,(GRDCTR)    ; Increment group read counter
  796.     INC    HL
  797.     LD    (GRDCTR),HL
  798.     POP    AF        ; Get back flags
  799.     PUSH    AF        ; Save again
  800.     JR    Z,COPY4        ; Skip if desired group is not allocated
  801. ;
  802. COPY3:    LD    A,(STATS)
  803.     OR    A
  804.     JR    Z,COPY3X    ; Skip if stats only
  805.     LD    DE,(BADGRP)    ; Get group pointer to swap
  806. ;
  807.      IF    DEBUG
  808.     PUSHRG
  809.     PUSH    DE        ; Save DE
  810.     CALL    PRINT
  811.     DEFB    CR,LF,'Copying from GRBUF1 to grp ',0
  812.     POP    HL        ; Restore for display
  813.     CALL    PHL4HC
  814.     POPRG
  815.      ENDIF
  816. ;
  817. COPY3A:    XOR    A        ; Flag allocated write
  818.     LD    (WRTYP),A
  819.     CALL    DEGRUP
  820.     LD    HL,(GRBUF1)    ; Select DMA address
  821.     LD    (DMAADR),HL
  822.     CALL    WRITGP        ; Write it out
  823. ;
  824. COPY3X:    LD    HL,(GWRCTR)    ; Increment group write counter
  825.     INC    HL
  826.     LD    (GWRCTR),HL
  827. ;
  828. COPY4:    LD    A,(STATS)
  829.     OR    A
  830.     JR    Z,COPY4X    ; Skip if stats only
  831.     LD    DE,(SRCHGP)    ; Write the copy of the desired group
  832. ;
  833.      IF    DEBUG
  834.     PUSHRG
  835.     PUSH    DE        ; Save DE
  836.     CALL    PRINT
  837.     DEFB    CR,LF,'Copying from GRBUF2 to grp ',0
  838.     POP    HL        ; Restore for display
  839.     CALL    PHL4HC
  840.     POPRG
  841.      ENDIF
  842. ;
  843. COPY4A:    XOR    A        ; Flag allocated write
  844.     LD    (WRTYP),A
  845.     CALL    DEGRUP        ; Select the proper group
  846.     LD    HL,(GRBUF2)    ; Select DMA address
  847.     LD    (DMAADR),HL
  848.     CALL    WRITGP
  849. ;
  850. COPY4X:    LD    HL,(GWRCTR)    ; Increment group write counter
  851.     INC    HL
  852.     LD    (GWRCTR),HL
  853.     POP    AF        ; Get back flags
  854.     JR    Z,COPY6
  855. ;
  856. COPY5:    LD    DE,(BADGRP)    ; Get the bad grp number to DE
  857.     LD    HL,(GRPTR)    ; Change the allocation of the group
  858.     LD    (HL),E        ; Save lower byte of group #
  859.     LD    A,(DSM+1)    ; See if 8 or 16-bit groups
  860.     OR    A
  861.     JR    Z,COPY6        ; Skip if small groups
  862.     INC    HL        ; Else save upper byte also
  863.     LD    (HL),D
  864. ;
  865. COPY6:    LD    DE,(SRCHGP)    ; Change the current alloc group
  866.     LD    HL,(ALLPTR)    ; To the updated value
  867.     LD    (HL),E
  868.     LD    A,(DSM+1)    ; See if 8 or 16-bit groups
  869.     OR    A
  870.     JR    Z,DONEXT    ; Skip if small groups
  871.     INC    HL
  872.     LD    (HL),D
  873. ;
  874. DONEXT:    LD    HL,(SRCHGP)    ; Do next alloc group for this file
  875.     INC    HL        ; Incr desired group
  876.     LD    (SRCHGP),HL
  877.     LD    HL,(ALLPTR)    ; Get allocation grp pointer
  878.     INC    HL
  879.     LD    A,(DSM+1)    ; See if 16-bit groups
  880.     OR    A
  881.     JR    Z,DONEX2    ; Don't increment again for small groups
  882.     INC    HL        ; For 16-bit groups, bump pointr again
  883. ;
  884. DONEX2:    LD    (ALLPTR),HL    ; Save new pointer
  885.     LD    A,(GRPNUM)    ; Get group counter
  886.     DEC    A
  887.     LD    (GRPNUM),A
  888.     JP    NZ,RECLP    ; Continue if still in current entry
  889. ;
  890. DONXEN:    LD    A,(DIRCHG)    ; See if directory changed for this entry
  891.     OR    A
  892.     CALL    NZ,WRITDR    ; Rewrite directory if so
  893.     CALL    CTLCS        ; Check for abort request
  894.     JR    Z,ABORT
  895.     XOR    A
  896.     LD    (DIRCHG),A    ; Clear changed flag
  897.     LD    HL,(DIRCTR)    ; See if at end of directory
  898.     DEC    HL
  899.     LD    A,H
  900.     OR    L
  901.     JR    Z,EXIT        ; Exit when done
  902. ;
  903.     LD    (DIRCTR),HL    ; Update counter
  904.     LD    HL,(FILPTR)    ; Get current file pointer
  905.     LD    DE,32        ; Bump to next file
  906.     ADD    HL,DE
  907.     JP    RECOVR        ; Loop back
  908. ;
  909. ABORT:    CALL    PRINT
  910.     DEFB    CR,LF,LF,'Restore aborted, ',0
  911.     LD    HL,(DIRCTR)
  912.     PUSH    HL        ; Save HL
  913.     CALL    PHLFDC
  914.     CALL    PRINT
  915.     DEFB    ' entr',0
  916.     POP    HL        ; Restore it
  917.     LD    A,H        ; Test if 0
  918.     OR    A
  919.     JR    NZ,ABORT1
  920. ;
  921.     LD    A,L
  922.     DEC    A
  923.     JR    NZ,ABORT1
  924.     CALL    PRINT
  925.     DEFB    'y',0
  926.     JR    ABORT2
  927. ;
  928. ABORT1:    CALL    PRINT
  929.     DEFB    'ies',0
  930. ;
  931. ABORT2:    CALL    PRINT
  932.     DEFB    ' left',CR,LF,0
  933.     JP    0000H
  934. ;
  935. EXIT:    LD    A,(STATS)    ; See if doing stats or disk
  936.     OR    A
  937.     JP    NZ,EXIT2    ; Exit if 2nd time through
  938. ;
  939.     CALL    PRINT
  940.     DEFB    CR,LF,LF,'Statistics',LF
  941.     DEFB    CR,LF,TAB,'Active dir entries: ',0
  942.     LD    HL,(DIRACT)
  943.     CALL    PHLFDC
  944.     CALL    PRINT
  945.     DEFB    CR,LF,TAB,'Total groups  allocated: ',0
  946.     LD    HL,(SGPCTR)
  947.     CALL    PHLFDC
  948.     CALL    PRINT
  949.     DEFB    CR,LF,TAB,'Group   swaps    needed: ',0
  950.     LD    HL,(SWPCTR)
  951.     CALL    PHLFDC
  952.     CALL    PRINT
  953.     DEFB    CR,LF,TAB,'Group   reads    needed: ',0
  954.     LD    HL,(GRDCTR)
  955.     CALL    PHLFDC
  956.     CALL    PRINT
  957.     DEFB    CR,LF,TAB,'Group   writes   needed: ',0
  958.     LD    HL,(GWRCTR)
  959.     CALL    PHLFDC
  960.     CALL    PRINT
  961.     DEFB    CR,LF,TAB,'Directory writes needed: ',0
  962.     LD    HL,(DIRWCT)
  963.     CALL    PHLFDC
  964. ;
  965. EXITX:    LD    A,(DWAIT)
  966.     OR    A
  967.     JR    Z,LOOPBK    ; Skip if no waiting
  968.     CALL    PRINT
  969.     DEFB    CR,LF,LF,'Press ''Y'' to continue,'
  970.     DEFB    ' else aborts: ',0
  971.     CALL    CONBUF        ; Get response
  972.     LD    A,(INBUF+2)
  973.     AND    1FH        ; 'y', 'y', and 'ctrl-y' are equivalent
  974.     CP    'Y'-40H
  975.     JP    NZ,0000H
  976. ;
  977. LOOPBK:    INC    A        ; Set non-stats flag
  978.     LD    (STATS),A
  979.     CALL    PRINT
  980.     DEFB    CR,LF,'Press ^C to abort...',CR,LF,0
  981.     JP    REDO
  982. ;
  983. EXIT2:    CALL    PRINT
  984.     DEFB    CR,LF,LF,BEL
  985.     DEFB    'Done',CR,LF,0
  986.     JP    0000H
  987. ;
  988. INBUF:    DEFB    1,0,0        ; Buffer for console buffer read
  989. ;
  990. ;
  991. ; Read or write the directory of the current disk
  992. ;
  993. READDR:
  994.      IF    DEBUG
  995.     PUSHRG
  996.     CALL    PRINT
  997.     DEFB    CR,LF,'Entering READDR',0
  998.     POPRG
  999.      ENDIF
  1000. ;
  1001.     XOR    A        ; Clear write flag
  1002.     JR    RWDIR
  1003. ;
  1004. WRITDR:
  1005.      IF    DEBUG
  1006.     PUSHRG
  1007.     CALL    PRINT
  1008.     DEFB    CR,LF,'Entering WRITDR',0
  1009.     POPRG
  1010.      ENDIF
  1011. ;
  1012.     LD    HL,(DIRWCT)    ; Increment director write counter
  1013.     INC    HL
  1014.     LD    (DIRWCT),HL
  1015.     LD    A,(STATS)
  1016.     OR    A
  1017.     RET    Z        ; Skip if only doing stats
  1018. ;
  1019.     LD    A,1        ; Set write flag
  1020.     LD    (WRTYP),A    ; Flag as directory write also
  1021. ;
  1022. RWDIR:    LD    (WRFLG),A
  1023.     LD    HL,(DIRECT)    ; Select directory buffer for DMA address
  1024.     LD    (DMAADR),HL
  1025.     LD    HL,(SYSTRK)    ; Select 1st directory track
  1026.     LD    (CURTRK),HL
  1027.     LD    HL,1        ; Set record 1
  1028.     LD    (CURREC),HL
  1029.     LD    A,(DIRGRP)    ; # of groups in directory
  1030.     LD    (GRPCTR),A    ; To loop counter
  1031. ;
  1032. RWDRLP:    CALL    RWGRP1        ; Read or write group
  1033.     LD    A,(GRPCTR)
  1034.     DEC    A        ; Decrement counter
  1035.     LD    (GRPCTR),A
  1036.     JR    NZ,RWDRLP    ; Loop until all groups done
  1037.     RET
  1038. ;
  1039. ;
  1040. ; Read or write selected group into or from current dma buffer.
  1041. ;
  1042. ; On entry, the desired group has been selected by a call to DEGROUP
  1043. ; which calculates the proper track and record.  The starting DMA address
  1044. ; for the group is in dMADDR.
  1045. ;
  1046. ; On entry to writgp only, wrtyp must have been set as follows:
  1047. ;        0 = write to allocated block
  1048. ;        1 = write to directory
  1049. ;
  1050. READGP:    XOR    A        ; Clear write flag
  1051.     JR    RWGRP
  1052. ;
  1053. WRITGP:    LD    HL,(DMAADR)    ; Save start of group buffer
  1054.     LD    (CRCBEG),HL    ; For CRC calculation
  1055.     LD    HL,(CURTRK)    ; Likewise the current track
  1056.     LD    (CRCTRK),HL
  1057.     LD    HL,(CURREC)    ; And record values
  1058.     LD    (CRCREC),HL
  1059.     LD    A,2        ; Set write flag
  1060. ;
  1061. RWGRP:    LD    (WRFLG),A    ; Set write flag
  1062.     LD    (CRCFLG),A    ; And CRC-needed flag
  1063. ;
  1064. RWGRP1:    LD    A,(BLM)        ; Get block mask
  1065.     INC    A        ; Increment to get # of 128-byte records
  1066.     LD    (RECCTR),A    ; Per allocation group - set up counter
  1067. ;
  1068.      IF    DEBUG
  1069.     PUSHRG
  1070.     CALL    PRINT
  1071.     DEFB    CR,LF,'Entering RWGRP',0
  1072.     POPRG
  1073.      ENDIF
  1074. ;
  1075. ; Loop to read or write a group
  1076. ;
  1077. RWGPLP:
  1078.      IF    DEBUG
  1079.     PUSHRG
  1080.     CALL    PRINT
  1081.     DEFB    CR,LF,'In RWGPLP, DMA: ',0
  1082.     LD    HL,(DMAADR)
  1083.     CALL    PHL4HC
  1084.     CALL    PRINT
  1085.     DEFB    '  T: ',0
  1086.     LD    HL,(CURTRK)
  1087.     CALL    PHLFDC
  1088.     CALL    PRINT
  1089.     DEFB    '  S: ',0
  1090.     LD    HL,(CURREC)
  1091.     CALL    PHLFDC
  1092.     POPRG
  1093.      ENDIF
  1094. ;
  1095.     LD    BC,(DMAADR)    ; Set DMA addr
  1096.     CALL    SETDMA
  1097.     LD    DE,(CURTRK)    ; Get track
  1098.     CALL    SETTRK
  1099.     LD    DE,(CURREC)    ; Get record
  1100.     CALL    SETREC
  1101. ;
  1102.     LD    A,(WRFLG)    ; See if read or write
  1103.     OR    A
  1104.     JR    NZ,WRGRP
  1105.     CALL    READ        ; Read the record
  1106.     JR    RWNXSC
  1107. ;
  1108. WRGRP:    LD    A,(WRTYP)    ; Get type of write
  1109.     LD    C,A
  1110.     CALL    WRITE        ; Write the record
  1111. ;
  1112. RWNXSC:    LD    DE,(CURREC)    ; Incr current record
  1113.     INC    DE
  1114.     LD    HL,(SPT)    ; See if beyond end of track
  1115.     OR    A
  1116.     SBC    HL,DE        ; Subtract current from SPT
  1117.     JR    NC,NEXTOK    ; If not > SPT then continue
  1118. ;
  1119.     LD    DE,(CURTRK)    ; Is > SPT, bump track counter
  1120.     INC    DE
  1121.     LD    HL,(MAXTRK)    ; See if at end of disk
  1122.     OR    A
  1123.     SBC    HL,DE        ; Subtract new track from maximum
  1124.     JR    NC,NXTTRK    ; If not > maximum track then jump over
  1125. ;
  1126.     LD    DE,0        ; Is > maximum track, wrap to start
  1127. ;
  1128. NXTTRK:    LD    (CURTRK),DE    ; Store new current track
  1129.     LD    DE,1        ; And set record to 1
  1130. ;
  1131. NEXTOK:    LD    (CURREC),DE    ; Store new current record
  1132. ;
  1133.     LD    HL,(DMAADR)
  1134.     LD    DE,80H        ; Advance to next DMA address
  1135.     ADD    HL,DE
  1136.     LD    (DMAADR),HL    ; Store next DMA address
  1137.     LD    A,(RECCTR)    ; Get # of 128 byte records
  1138.     DEC    A        ; Decrement it
  1139.     LD    (RECCTR),A    ; Save new
  1140. ;
  1141.      IF    DEBUG
  1142.     JP    NZ,RWGPLP    ; Normal jump for debug mode
  1143.      ELSE
  1144.     JR    NZ,RWGPLP    ; Loop until all read
  1145.      ENDIF
  1146. ;
  1147. ; CRC verfification
  1148. ;
  1149. CKCRC:    LD    A,(CRCFLG)    ; See if CRC needed
  1150.     OR    A
  1151.     RET    Z        ; Return if not
  1152. ;
  1153.     DEC    A        ; See if 1st or 2nd time through
  1154.     LD    (CRCFLG),A    ; Save updated flag
  1155.     JR    Z,CRCVER    ; If 2nd loop, go verify CRC
  1156. ;
  1157.     CALL    CRCGEN        ; Get the CRC for the grp in the buffer
  1158.     LD    (CRCVAL),HL    ; Save CRC value
  1159.     LD    HL,(CRCBEG)    ; Restore the grp buffer addr
  1160.     LD    (DMAADR),HL
  1161.     LD    HL,(CRCTRK)    ; Likewise the track
  1162.     LD    (CURTRK),HL
  1163.     LD    HL,(CRCREC)    ; And record values
  1164.     LD    (CURREC),HL
  1165.     XOR    A
  1166.     LD    (WRFLG),A    ; Clear write flag
  1167.     JP    RWGRP1        ; Go read the group back in
  1168. ;
  1169. CRCVER:    CALL    CRCGEN        ; Generate the new CRC
  1170.     EX    DE,HL        ; Save 2nd CRC in de
  1171.     LD    HL,(CRCVAL)    ; Get back the original CRC
  1172.     OR    A
  1173.     SBC    HL,DE        ; Compare the two CRCs
  1174.     RET    Z        ; Return if ok
  1175. ;
  1176. CRCERR:    CALL    PRINT
  1177.     DEFB    CR,LF,'CRC error abort',CR,LF,0
  1178.     JP    0000H
  1179. ;
  1180. ; Generate a CRC for the group in the buffer starting at (CRCbeg) with
  1181. ; length (BLS).  CRC value returned in HL.
  1182. ;
  1183. CRCGEN:    CALL    CRCCLR        ; Initialize CRC
  1184. ;
  1185.     LD    DE,(BLS)    ; Length of group in bytes
  1186.     LD    HL,(CRCBEG)    ; Point to start of buffer
  1187. CRCLP:    LD    A,(HL)        ; Get next byte in buffer
  1188.     CALL    CRCUPD        ; Update the CRC
  1189.     INC    HL
  1190.     DEC    DE
  1191.     LD    A,D
  1192.     OR    E
  1193.     JR    NZ,CRCLP    ; Loop until all bytes done
  1194.     JP    CRCDON        ; Finish CRC
  1195. ;
  1196. ; Get directory group count into a and 1st group number after directory
  1197. ; into HL.
  1198. ;
  1199. DOCOLL:    LD    L,0
  1200.     LD    A,(AL0)        ; Read directory group allocation bits
  1201.     CALL    COLECT        ; Collect count of directory groups
  1202.     LD    A,(AL1)
  1203.     CALL    COLECT
  1204.     LD    A,L        ; Group count in register 'A' and
  1205.     LD    H,0        ;   HL = 1st group after directory
  1206.     RET
  1207. ;
  1208. ; Collect the number of '1' bits in a as a count in L
  1209. ;
  1210. COLECT:    LD    B,8        ; Number of bits
  1211. ;
  1212. COLOP:    RLA
  1213.     JR    NC,COSKIP
  1214.     INC    L
  1215. ;
  1216. COSKIP:    DJNZ    COLOP
  1217.     RET
  1218. ;
  1219. ;
  1220. ; Check for CTL-C or CTL-S, returns Z-flag set if CTL-C typed, else NZ
  1221. ;
  1222. CTLCS:    CALL    CONST        ; See if character available
  1223.     OR    A
  1224.     JR    NZ,GETC
  1225.     OR    1        ; Return NZ if not
  1226.     RET
  1227. ;
  1228. GETC:    CALL    CONIN        ; Get the character
  1229.     AND    31
  1230.     CP    'S'-40H        ; Wait for next character if CTL-S or S or s
  1231.     CALL    Z,CONIN
  1232.     CP    'C'-40H        ; Check for CTL-C or C or c
  1233.     RET            ; Z-flag set if CTL-C
  1234. ;
  1235. ; Select the track/record corresponding to the group in DE
  1236. ;
  1237. DEGRUP:    LD    HL,(DSM)    ; Compare group # with maximum
  1238.     OR    A
  1239.     SBC    HL,DE        ; Subtract group number from maximum
  1240.     RET    C        ; Return bad if too large
  1241. ;
  1242.     CALL    GRP2SC        ; Convert group number to track and record
  1243.     CALL    SETTRK        ; Set track
  1244.     EX    DE,HL
  1245.     CALL    SETREC        ; And record
  1246.     RET
  1247. ;
  1248. ;
  1249. ; Convert group in DE to corresponding record (HL) and track (DE)
  1250. ;
  1251. GRP2SC:    LD    H,D
  1252.     LD    L,E
  1253.     LD    A,(BSH)        ; Get block shift (count)
  1254.     LD    B,A        ; To 'B'
  1255.     XOR    A        ; Zero 'A'
  1256. ;
  1257. SHLGRP:    ADD    HL,HL        ; Shift block left 1 place
  1258.     JP    NC,SHLSKI
  1259.     INC    A
  1260. ;
  1261. SHLSKI:    DJNZ    SHLGRP
  1262.     LD    (TEMPC),A
  1263.     EX    DE,HL
  1264.     LD    HL,(SPT)    ; Get SPT
  1265.     CALL    NEG        ; Negate it for division
  1266.     EX    DE,HL        ; Put into DE
  1267.     LD    BC,0        ; Initial quotient
  1268. ;
  1269. GRPDLP:    INC    BC        ; Incr quotient
  1270.     ADD    HL,DE        ; Divide by adding negative SPT
  1271.     JP    C,GRPDLP
  1272.     LD    A,(TEMPC)
  1273.     DEC    A
  1274.     LD    (TEMPC),A
  1275.     JP    P,GRPDLP
  1276. ;
  1277.     DEC    BC        ; Adjust division result
  1278.     LD    DE,(SPT)    ; Position SPT to DE, negative value = HL
  1279.     ADD    HL,DE        ; Add to get remainder
  1280.     PUSH    HL        ; Save records remaining
  1281.     LD    HL,(SYSTRK)    ; Get number of system tracks
  1282.     ADD    HL,BC        ; Add to quotient (tracks)
  1283.     EX    DE,HL        ; Put absolute track into DE
  1284.     POP    HL        ; Get back records remaining
  1285.     INC    HL        ; Make 1-relative
  1286.     RET
  1287. ;
  1288. ; Find which file the group in (BC) belongs to.  On return, HL has the
  1289. ; address of the allocation map entry which matches BC, or 0 if no
  1290. ; matching entry found.
  1291. ;
  1292. GETGRP:    LD    HL,(DIRACT)    ; Max directory entry number
  1293.     INC    HL        ; Make 1-relative
  1294.     LD    (FILECT),HL
  1295.     LD    HL,(DIRECT)    ; Point to directory
  1296.     PUSH    HL        ; Save pointer to name
  1297. ;
  1298. GETGLP:    POP    HL        ; Restore file pointer
  1299.     PUSH    HL
  1300.     LD    A,(HL)        ; Look at user number of next directory entry
  1301.     CP    0E5H        ; Erased? (shouldn't be, but just in case)
  1302.     JR    Z,GETGNF    ; Ignore if so
  1303.     LD    DE,14        ; Now get record count
  1304.     ADD    HL,DE        ; S2 portion ..
  1305.     LD    A,(HL)        ; Is 0 in CP/M 1.4
  1306.     AND    0FH
  1307.     LD    E,A
  1308.     INC    HL
  1309.     LD    A,(HL)
  1310.     OR    E
  1311.     JR    Z,GETGNF    ; Skip if no records allocated (empty file)
  1312.     LD    A,(GRPALL)    ; Initialize loop counter to number of
  1313.     LD    E,A        ; Allocation groups per file
  1314. ;
  1315. GETGL2:    INC    HL        ; Point at next allocation map entry
  1316.     CALL    GRPCMP        ; See if it matches the one in 'BD'
  1317.     JR    Z,GETGEX    ; Exit if match found
  1318.     DEC    E        ; Count down
  1319.     JR    NZ,GETGL2    ; Go test some more
  1320. ;
  1321. GETGNF:    POP    HL        ; Get back entry pointer
  1322.     LD    DE,32
  1323.     ADD    HL,DE        ; Bump to next entry
  1324.     PUSH    HL        ; Save it
  1325.     LD    HL,(FILECT)    ; See if all directory entries checked
  1326.     DEC    HL
  1327.     LD    (FILECT),HL
  1328.     LD    A,H
  1329.     OR    L
  1330.     JR    NZ,GETGLP    ; Continue if more entries left
  1331. ;
  1332. GETGEX:    POP    DE        ; Pop extra directory pointer
  1333.     LD    A,H
  1334.     OR    L
  1335.     RET    Z        ; Exit if HL = 0, indicating no match found
  1336.     LD    A,(DSM+1)    ; Get disk size indicator
  1337.     OR    A
  1338.     JR    Z,GETGX1    ; Skip if 8-bit groups
  1339.     DEC    HL        ; Since GRPCMP increments pointer for big ones
  1340. GETGX1:    INC    A        ; Reset zero flag to show match found
  1341.     RET            ; Return with address of match in HL
  1342. ;
  1343. ; Compare the directory entry pointed to by HL to the one pointed to by
  1344. ; DE.  Set carry flag if the one pointed to by HL (lower in the direc-
  1345. ; tory) is larger, indicating that the directory is not sorted.
  1346. ;
  1347. CMPDIR:    PUSH    HL        ; Save registers
  1348.     PUSH    DE
  1349.     PUSH    BC
  1350. ;
  1351.      IF    DEBUG
  1352.     PUSHRG
  1353.     PUSH    DE        ; Save 2nd file
  1354.     PUSH    HL        ; Save 1st file
  1355.     CALL    PRINT
  1356.     DEFB    CR,LF,'Comparing ',0
  1357.     POP    DE        ; Restore 1st file
  1358.     INC    DE        ; Skip user number
  1359.     CALL    PFN1
  1360.     CALL    PRINT
  1361.     DEFB    ' and ',0
  1362.     POP    DE        ; Restore 2nd file
  1363.     INC    DE        ; Skip user #
  1364.     CALL    PFN1
  1365.     POPRG
  1366.      ENDIF
  1367. ;
  1368. ;
  1369.     LD    B,15        ; Check user, name, type, extent, s2, & rc
  1370. ;
  1371. ; Loop through the user number, file name, type, and extent.  Any time
  1372. ; the character in the lower entry is larger than the corresponding ele-
  1373. ; ment in the upper entry, meaning the directory is not in order, the
  1374. ; routine exits with the carry flag set.  When the first non-match is
  1375. ; found with the upper element larger, indicating that the two entries
  1376. ; are in order, the routine exits with the carry flag cleared.
  1377. ;
  1378. CMPDLP:    LD    A,(HL)        ; Compare corresponding elements
  1379.     AND    7FH        ; Mask off attribute bit
  1380.     LD    C,A        ; Save it
  1381.     LD    A,(DE)
  1382.     AND    7FH
  1383.     CP    C
  1384.     JR    C,CMPDEX    ; Error if lower one is larger
  1385.     JR    NZ,CMPDEX    ; If not the same and no carry,
  1386.                 ; Higher must be larger - exit ok
  1387.     INC    DE        ; If the same continue the check
  1388.     INC    HL        ; Bump pointers
  1389.     DJNZ    CMPDLP        ; Loop until all characters checked
  1390. ;
  1391. ; This point should never be reached, since, if we drop out of the loop,
  1392. ; it indicates that the two entries have the same user number, file name,
  1393. ; type, and extent which is not really legal.  "SAPP", "CLEANDIR", or
  1394. ; whatever was used to sort the directory should have caught this, but
  1395. ; didn't.  Treat this the same as an improperly sorted directory.
  1396. ;
  1397. CMPDER:    SCF            ; Set carry
  1398. ;
  1399. CMPDEX:    POP    BC
  1400.     POP    DE
  1401.     POP    HL
  1402.     RET
  1403. ;
  1404. ;
  1405. ; See if the group # in bc and the one pointed to by hl are the
  1406. ; same.  Set z flag if so, nz if not.  Hl is incremented if the
  1407. ; allocation groups are 16 bits.  Flags are set.
  1408. ;
  1409. GRPCMP:    LD    A,(DSM+1)
  1410.     LD    D,A        ; Set size indicator
  1411.     LD    A,C        ; Get (lower byte of) group number
  1412.     INC    D
  1413.     DEC    D        ; See if one or two bytes in number
  1414.     JR    Z,CMP8        ; Skip if only 1 byte to be checked
  1415.     CP    (HL)        ; Compare lower byte of number
  1416.     INC    HL        ; Bump pointer
  1417.     RET    NZ        ; Return if not equal
  1418.     LD    A,B        ; Otherwise get upper byte
  1419. ;
  1420. CMP8:    CP    (HL)        ; Set flag for compare
  1421.     RET
  1422. ;
  1423. ; 2's complement HL ==> HL
  1424. ;
  1425. NEG:    LD    A,L
  1426.     CPL
  1427.     LD    L,A
  1428.     LD    A,H
  1429.     CPL
  1430.     LD    H,A
  1431.     INC    HL
  1432.     RET
  1433. ;
  1434. ; Unsigned division.  Divide HL by DE.    Destroys register 'A'.    Return
  1435. ; HL = quotient, DE = remainder, carry clear if ok.  Carry set if DE > HL
  1436. ; or if DE = 0 else carry is clear.
  1437.  
  1438. UDIVID:    PUSH    BC        ; Save registers
  1439.     LD    BC,0        ; Initialize quotient
  1440.     PUSH    HL        ; Save HL
  1441.     OR    A        ; Clear carry
  1442.     SBC    HL,DE        ; Test if divisor > dividend
  1443.     POP    HL        ; Restore HL
  1444.     JR    C,DIVBAD    ; If so, it is bad
  1445.     LD    A,E        ; Else test divisor
  1446.     OR    D        ; For 0
  1447.     JR    NZ,DIVLOP    ; If <> 0 continue
  1448. DIVBAD:    POP    BC        ; Restore registers
  1449.     SCF            ; Set carry to show bad
  1450.     RET
  1451. ;
  1452. DIVLOP:    INC    BC        ; Increment quotient
  1453.     OR    A        ; Clear carry for subtract
  1454.     SBC    HL,DE        ; Division by subtract
  1455.     JR    C,DIVOFL    ; If borrow, done dividing
  1456.     JR    NZ,DIVLOP    ; If <> 0 more to do
  1457.     JR    DIVREM        ; Was 0, skip calc of remainder
  1458. ;
  1459. DIVOFL:    ADD    HL,DE        ; HL=negative remainder, DE=divisor
  1460.     DEC    BC        ; The even division was 1 less
  1461. ;
  1462. DIVREM:    EX    DE,HL        ; Positive remainder to DE
  1463.     LD    H,B        ; Put quotient
  1464.     LD    L,C        ; Into HL
  1465.     POP    BC        ; Restore register
  1466.     OR    A        ; Clear carry (valid result)
  1467.     RET
  1468. ;
  1469. ; Multiply HL by DE, return result in HL
  1470. ;
  1471. MULT:    PUSH    BC
  1472.     PUSH    DE
  1473.     EX    DE,HL
  1474.     LD    B,D
  1475.     LD    C,E
  1476.     LD    A,B
  1477.     OR    C
  1478.     JR    NZ,MULCON
  1479.     LD    HL,0        ; Filter special case
  1480.     JR    MLDONE        ; Of multiply by 0
  1481. ;
  1482. MULCON:    DEC    BC
  1483.     LD    D,H
  1484.     LD    E,L
  1485. ;
  1486. MULTLP:    LD    A,B
  1487.     OR    C
  1488.     JR    Z,MLDONE
  1489.     ADD    HL,DE
  1490.     DEC    BC
  1491.     JR    MULTLP
  1492. ;
  1493. MLDONE:    POP    DE
  1494.     POP    BC
  1495.     RET
  1496. ;
  1497. ; Print string following the call. Return to spot after string.
  1498. ;
  1499. PRINT:    EX    (SP),HL        ; Get string pointer
  1500. ;
  1501. PRINLP:    LD    A,(HL)
  1502.     INC    HL
  1503.     OR    A
  1504.     JR    Z,PREX
  1505.     LD    E,A
  1506.     PUSH    HL
  1507.     CALL    CONOUT
  1508.     POP    HL
  1509.     JR    PRINLP
  1510. ;
  1511. PREX:    EX    (SP),HL
  1512.     RET
  1513. ;
  1514. ;-----------------------------------------------------------------------
  1515. ;
  1516. ; Select disk whose number is in C (A=0, B=1, etc)
  1517. ;
  1518. SELECT:    CALL    V3CHEK        ; Carry set if not 3.0
  1519.     JR    C,SELEC2    ; Skip if 2.2
  1520.     LD    DE,1        ; Set 1st time flag for CP/M 3.0
  1521.     LD    (DEREG),DE    ; Into e of DPB
  1522.     LD    (BCREG),BC    ; Into c of DPB
  1523.     LD    A,9        ; BIOS SELDSK function
  1524.     CALL    XBIOS3        ; Do it
  1525.     JR    SELEC3        ; Skip over
  1526.  
  1527. SELEC2:    LD    A,9        ; BIOS SELDSK function
  1528.     CALL    XBIOS2        ; Do it
  1529. ;
  1530. SELEC3:    LD    A,H        ; Get result
  1531.     OR    L
  1532.     JP    Z,0000H
  1533. ;
  1534.     LD    E,(HL)        ; Get the record table pointer
  1535.     INC    HL
  1536.     LD    D,(HL)
  1537.     DEC    HL
  1538.     EX    DE,HL
  1539.     LD    (RECTBL),HL    ; Save the record table pointer
  1540.     LD    HL,DPB2OF    ; Default, CP/M 2.2 offset to DPB
  1541. ;
  1542. DPBOF    EQU    $-2
  1543. ;
  1544.     ADD    HL,DE
  1545.     LD    A,(HL)        ; Get DPB pointer
  1546.     INC    HL
  1547.     LD    H,(HL)
  1548.     LD    L,A        ; Into HL
  1549.     LD    DE,DPB        ; Copy dpb to local area
  1550.     LD    BC,DPB2LN    ; Default, DPB size for CP/M 2.2
  1551. ;
  1552. DPBLN    EQU    $-2
  1553. ;
  1554.     LDIR
  1555.     LD    DE,(DSM)    ; Get number of last group
  1556.     CALL    GRP2SC        ; Find out what track and record it is in
  1557.     LD    (MAXTRK),DE    ; Save the maximum track number
  1558.     LD    HL,(PHYREC)    ; This logic will tell
  1559.     LD    A,H        ; If first record
  1560.     OR    L        ; Is physical 0 or 1
  1561.     LD    (FIRST0),A
  1562.     RET
  1563. ;
  1564. ; Set DMA address in BC
  1565. ;
  1566. SETDMA:    CALL    V3CHEK        ; Carry set if not 3.0
  1567.     JR    C,STDMA2    ; Skip if 2.2
  1568.     LD    (DMAADR),BC    ; Do for CP/M 3
  1569.     RET            ; And return
  1570.  
  1571. STDMA2:    LD    A,12        ; BIOS SETDMA function
  1572.     JP    XBIOS2        ; Do it
  1573. ;
  1574. ; Set track # in DE
  1575. ;
  1576. SETTRK:    PUSH    HL        ; Save HL
  1577.     LD    HL,(MAXTRK)    ; Verify within limits
  1578.     OR    A
  1579.     SBC    HL,DE        ; Error if > maximum track #
  1580.     POP    HL        ; Restore HL in case error
  1581.     JP    C,OUTLIM    ; If too big, abort
  1582. ;
  1583.     LD    (CURTRK),DE    ; Save desired track
  1584.     LD    B,D        ; BC=track number
  1585.     LD    C,E
  1586.     PUSH    HL        ; Resave HL
  1587. ;
  1588. ; Is ok, so set track
  1589. ;
  1590.     CALL    V3CHEK        ; Carry set if not 3.0
  1591.     JR    C,STTRK2    ; Do it 2.2 way
  1592.     LD    (LOGTRK),DE    ; Setup track for CP/M 3
  1593.     JR    STTRK3        ; Skip 2.2 stuff
  1594. ;
  1595. STTRK2:    LD    A,10        ; BIOS SETTRK function
  1596.     CALL    XBIOS2        ; Do it
  1597. ;
  1598. STTRK3:    POP    HL        ; Restore HL
  1599.     RET
  1600. ;
  1601. ;
  1602. ; Set record number in DE
  1603. ;
  1604. SETREC:    PUSH    HL        ; Save HL
  1605.     PUSH    DE        ; Save record #
  1606.     LD    (CURREC),DE    ; Store current record
  1607.     LD    DE,(SYSTRK)    ; Get number of sys trks
  1608.     LD    HL,(CURTRK)    ; Get current track
  1609.     OR    A        ; Clear carry for subtract
  1610.     SBC    HL,DE        ; See if in system tracks
  1611.     POP    BC        ; Restore record number to BD
  1612.     LD    H,B        ; And
  1613.     LD    L,C        ; To HL
  1614.     JR    NC,NOTSYS    ; If no carryy we're not in system tracks
  1615. ;
  1616.     LD    A,(FIRST0)    ; See if first record is 0
  1617.     OR    A
  1618.     JP    NZ,STREC1    ; No, jump away
  1619.     DEC    HL        ; Yes, so decrement requested
  1620.     JP    STREC1        ; Then go
  1621. ;
  1622. NOTSYS:    LD    DE,(RECTBL)    ; Point to XLT table
  1623.     DEC    BC        ; Decr record
  1624.     CALL    V3CHEK        ; Carry set if not 3.0
  1625.     JR    C,NOTSY2    ; Do it 2.2 way
  1626.     CALL    RECTRN        ; Else do CP/M 3 way (see note)
  1627.     JR    NOTSY3        ; Skip 2.2 stuff
  1628. ;
  1629. NOTSY2:    LD    A,16        ; Bios RECTRAN function #
  1630.     CALL    XBIOS2        ; Do it
  1631. ;
  1632. NOTSY3:    LD    A,(SPT+1)    ; If SPT<256 (HI-ord = 0)
  1633.     OR    A        ; Then force 8-bit translation
  1634.     JP    NZ,STREC1    ; Else keep all 16 bits
  1635.     LD    H,A
  1636. ;
  1637. STREC1:    LD    (PHYREC),HL
  1638.     LD    B,H
  1639.     LD    C,L
  1640. ;
  1641.     CALL    V3CHEK        ; Cy set if not 3.0
  1642.     JR    C,STREC2    ; Do it 2.2 way
  1643.     LD    A,L
  1644.     LD    (LOGREC),A    ; Setup track for CP/M 3
  1645.     JR    STREC3        ; Skip 2.2 stuff
  1646. ;
  1647. STREC2:    LD    A,11        ; BIOS SETREC function #
  1648.     CALL    XBIOS2        ; Do it
  1649. ;
  1650. STREC3:    POP    HL        ; Restore HL
  1651.     RET
  1652. ;
  1653. ; Out of disk track limit
  1654. ;
  1655. OUTLIM:    CALL    PRINT
  1656.     DEFB    CR,LF,BEL,'Track Error',0
  1657.     JP    0000H
  1658. ;
  1659. ; Read next block into dma address
  1660. ;
  1661. READ:    CALL    V3CHEK        ; Carry set if not 3.0
  1662.     JR    C,READ2        ; Skip if 2.2
  1663.     CALL    READ3        ; Do CP/M 3.0 way
  1664.     JR    READ4        ; Jump over
  1665. ;
  1666. READ2:    LD    A,13        ; BIOS READ function
  1667.     CALL    XBIOS2        ; Do it
  1668. ;
  1669. READ4:    OR    A        ; Check status
  1670.     RET    Z        ; Return if ok
  1671. ;
  1672.     CALL    PRINT
  1673.     DEFB    CR,LF,BEL,'Read Error',0
  1674.     JP    0000H
  1675.     RET
  1676. ;
  1677. ; Write block in DMA address to disk
  1678. ;
  1679. WRITE:    CALL    V3CHEK        ; Carry set if not 3.0
  1680.     JR    C,WRITE2    ; Skip if 2.2
  1681.     CALL    WRITE3        ; Do CP/M 3.0 way
  1682.     JR    WRITE4        ; Jump over
  1683. ;
  1684. WRITE2:    LD    A,14        ; BIOS WRITE function
  1685.     CALL    XBIOS2        ; Do it
  1686. ;
  1687. WRITE4:    OR    A        ; Check for write error
  1688.     RET    Z
  1689. ;
  1690.     CALL    PRINT
  1691.     DEFB    CR,LF,BEL,'Write Error',0
  1692.     JP    0000H
  1693. ;
  1694. ;-----------------------------------------------------------------------
  1695. ;
  1696. ; Test for CP/M 3.0, used by above routines
  1697. ;
  1698. V3CHEK:    LD    A,(VERFLG)    ; Check for version 3.0
  1699.     CP    30H        ; Carry set if not 3.0
  1700.     RET
  1701. ;
  1702. VERFLG:    DEFB    0        ; Version number of CP/M
  1703. ;
  1704. ;-----------------------------------------------------------------------
  1705. ;
  1706. ; For CP/M 2.2, enter with BIOS function in A, eg.,  LD A,9  (DELDSK)
  1707. ;
  1708. XBIOS2:    PUSH    DE        ; Save registers
  1709.     LD    HL,(0001H)    ; Warmboot address
  1710.     LD    L,A        ; BIOS function number to L
  1711.     LD    E,L        ; And to E
  1712.     LD    D,0        ; Zero Dd
  1713.     ADD    HL,DE        ; Add so that HL
  1714.     ADD    HL,DE        ; Points to BIOS function address
  1715.     POP    DE        ; Restore DE
  1716.     JP    (HL)        ; Do it and return to call address
  1717. ;
  1718. ;-----------------------------------------------------------------------
  1719. ;
  1720. ; BDOS subroutines
  1721. ;
  1722. CONST:    LD    C,CONSTF
  1723.     JP    BDOS
  1724. ;
  1725. CONIN:    LD    C,CONINF
  1726.     JP    BDOS
  1727. ;
  1728. CONOUT:    LD    C,CONOUF
  1729.     JP    BDOS
  1730. ;
  1731. CONBUF:    XOR    A        ; Zero the character buffer
  1732.     LD    (INBUF+2),A
  1733.     LD    C,RDCBUF
  1734.     LD    DE,INBUF
  1735.     JP    BDOS
  1736. ;
  1737. ;-----------------------------------------------------------------------
  1738. ;
  1739. ; Used by some SYSLIB routines.  (Modified - SYSLIB used BIOS.)
  1740. ;
  1741. COUT:    PUSHRG            ; Save registers
  1742.     PUSH    AF
  1743.     LD    E,A
  1744.     CALL    CONOUT
  1745.     POP    AF
  1746.     POPRG            ; Restore registers
  1747.     RET
  1748. ;
  1749. ;-----------------------------------------------------------------------
  1750. ;
  1751. ; Start of SYSLIB routines (by Richard Conn).
  1752. ; NOTE - some of these have been modified to Z80 code.
  1753. ;
  1754. ; Print register 'A' as decimal characters in N-character field floating
  1755. ; print, where 1-3 chars are used
  1756. ;
  1757. PAFDC:    PUSH    BC        ; Save registers
  1758.     PUSH    DE
  1759.     PUSH    AF        ; Save 'A'
  1760.     LD    D,1        ; Turn on leading sapce flag
  1761. ;
  1762. ; Print routine
  1763. ;
  1764.     LD    B,100        ; Print 100's
  1765.     CALL    PAC        ; Print a character
  1766.     LD    B,10        ; Print 10's
  1767.     CALL    PAC
  1768.     ADD    A,'0'        ; Convert to ASCII
  1769.     CALL    COUT        ; Print
  1770.     POP    AF        ; Restore 'A'
  1771.     POP    DE        ; Restore registers
  1772.     POP    BC
  1773.     RET
  1774. ;
  1775. ; Print result of division of 'A' by 'B' with leading space (integer
  1776. ; division)
  1777. ;
  1778. PAC:    LD    C,0        ; Set count
  1779. ;
  1780. PACL:    SUB    B        ; Compute count
  1781.     JR    C,PACD
  1782.     INC    C        ; Increment count
  1783.     JR    PACL
  1784. ;
  1785. PACD:    ADD    A,B        ; Add 'B' back in
  1786.     LD    E,A        ; Save 'A'
  1787.     LD    A,C        ; Get count
  1788.     OR    A        ; Zero?
  1789.     JR    NZ,PACD1
  1790.     OR    D        ; 0 means no leading space
  1791.     JR    Z,PACD1        ; (A=0, A or D = 0 means D=0)
  1792.     LD    A,E        ; Restore 'A'
  1793.     RET
  1794. ;
  1795. PACD1:    LD    D,0        ; D=0 for no leading space
  1796.     LD    A,C        ; Get count
  1797.     ADD    A,'0'        ; Convert to decimal
  1798.     CALL    COUT        ; Print it
  1799.     LD    A,E        ; Restore 'A'
  1800.     RET
  1801. ;
  1802. ; Changed following to utilize some Z80 code
  1803. ;
  1804. ; Print HL as decimal characters in N-character field floating print,
  1805. ; where field size is from 1 to 5 characters
  1806. ;
  1807. PHLFDC:    PUSH    AF        ; Save all registers
  1808.     PUSH    BC
  1809.     PUSH    DE
  1810.     PUSH    HL
  1811.     LD    B,1        ; B=1 for leading <sp>
  1812. ;
  1813. ; Print HL using leading space flag in 'B'
  1814. ;
  1815.     LD    DE,10000    ; Print 10000's
  1816.     CALL    PHDC1
  1817.     LD    DE,1000        ; Print 1000's
  1818.     CALL    PHDC1
  1819.     LD    DE,100        ; Print 100's
  1820.     CALL    PHDC1
  1821.     LD    DE,10        ; Print 10's
  1822.     CALL    PHDC1
  1823.     LD    A,L        ; Print 1's
  1824.     ADD    A,'0'        ; Convert to ASCII
  1825.     CALL    COUT
  1826.     POP    HL        ; Restore all registers
  1827.     POP    DE
  1828.     POP    BC
  1829.     POP    AF
  1830.     RET
  1831. ;
  1832. ; Divide HL by DE and print quotient with leading spaces
  1833. ;
  1834. PHDC1:    LD    C,0        ; Set count
  1835. ;
  1836. PHDC2:    OR    A        ; Clear carry for Z80 way
  1837.     SBC    HL,DE        ; Subtract DE from HL with borrow
  1838.     JR    C,PHDC3        ; Done if carry set (further borrow)
  1839.     INC    C        ; Increment count
  1840.     JR    PHDC2
  1841. ;
  1842. PHDC3:    OR    A        ; Clear carry
  1843.     ADC    HL,DE        ; Add DE to HL with carry Z80 way
  1844.     LD    A,C        ; Get result
  1845.     OR    A        ; Check for zero
  1846.     JR    NZ,PHDC4
  1847.     OR    B        ; 0=no leading space
  1848.     RET    NZ        ; (A=0, A or B = 0 means B = 0)
  1849. ;
  1850. PHDC4:    LD    B,0        ; Turn off leading space
  1851.     LD    A,C        ; Get value
  1852.     ADD    A,'0'        ; Convert to ascii
  1853.     JP    COUT
  1854. ;
  1855. ;
  1856. ; Print FCB file name and type pointed to by DE on console:  Format of
  1857. ; output:  xxxxxxxx.yyy  Modified.  (8 chars and/or spaces, period, 3
  1858. ; characters and/or spaces)
  1859. ;
  1860. PFN1:    PUSH    DE        ; Save registers
  1861.     PUSH    BC
  1862.     PUSH    AF
  1863.     LD    B,8        ; 8 characters first
  1864.     CALL    PRFNX
  1865.     LD    A,'.'        ; Dot
  1866.     CALL    COUT
  1867.     LD    B,3        ; 3 more characters
  1868.     CALL    PRFNX
  1869.     POP    AF        ; Restore registers
  1870.     POP    BC
  1871.     POP    DE
  1872.     RET
  1873. ;
  1874. PRFNX:    LD    A,(DE)        ; Get character
  1875.     AND    7FH        ; Mask out MSB
  1876.     CALL    COUT        ; Print it
  1877.     INC    DE        ; Point to next
  1878.     DJNZ    PRFNX        ; Loop until done
  1879.     RET
  1880. ;
  1881. ; Clear the CRC accumulator
  1882. ;
  1883. CRCCLR:    PUSH    HL
  1884.     LD    HL,0        ; Set CRC to zero
  1885.     LD    (CRCACC),HL
  1886.     POP    HL
  1887.     RET
  1888. ;
  1889. ; Update the CRC accumulator.  This routine must be called once for each
  1890. ; byte in the byte stream for which the CRC is being calculated.
  1891. ;
  1892. ; Input parameters: A = byte to be included in CRC
  1893. ;
  1894. CRCUPD:    PUSH    AF        ; Save all registers
  1895.     PUSH    BC
  1896.     PUSH    HL
  1897.     LD    B,8        ; Rotate 8 bits
  1898.     LD    C,A        ; Byte in C
  1899.     LD    HL,(CRCACC)    ; HL=old CRC value
  1900. ;
  1901. UPDLOP:    LD    A,C        ; Rotate HLC as a 24-bit ACC left 1 bit
  1902.     RLCA
  1903.     LD    C,A
  1904.     LD    A,L
  1905.     RLA
  1906.     LD    L,A
  1907.     LD    A,H
  1908.     RLA
  1909.     LD    H,A
  1910.     JR    NC,SKIPIT
  1911.     LD    A,H        ; The generator is x^16 + x^12 + x^5 + 1
  1912.     XOR    10H        ; As recommended by CCITT.
  1913.     LD    H,A        ; An alternate generator which is often
  1914.     LD    A,L        ; Used in synchronous protocols
  1915.     XOR    21H        ; Is x^16 + x^15 + x^2 + 1. this may be
  1916.     LD    L,A        ; Used by substituting xor 80h for xor 10h
  1917.                 ; And XOR 05h for XOR 21h in the adjacent code.
  1918. SKIPIT:    DEC    B        ; Count down 8 bits
  1919.     JR    NZ,UPDLOP
  1920.     LD    (CRCACC),HL    ; Save new CRC value
  1921.     POP    HL        ; Restore all
  1922.     POP    BC
  1923.     POP    AF
  1924.     RET
  1925. ;
  1926. ; Complete the CRC calculation.  Called after the last byte of the byte
  1927. ; stream has passed through CRCUPD.  It returns the calculated CRC bytes
  1928. ; in HL.
  1929. ;
  1930. ; Output parameters:  HL = calculated CRC bytes
  1931. ;
  1932. CRCDON:    PUSH    AF        ; Save 'A'
  1933.     XOR    A        ; Send out 2 zeroes
  1934.     CALL    CRCUPD
  1935.     CALL    CRCUPD
  1936.     LD    HL,(CRCACC)    ; Return CRC value in HL
  1937.     POP    AF
  1938.     RET
  1939. ;
  1940. ; Print HL as 4 hex characters, no registers are to be affected
  1941. ;
  1942.      IF    DEBUG        ; For dumping hex values
  1943. PHL4HC:    PUSH    AF        ; Save 'A'
  1944.     LD    A,H        ; Print H
  1945.     CALL    PA2HC
  1946.     LD    A,L        ; Print L
  1947.     CALL    PA2HC
  1948.     POP    AF        ; Restore 'A'
  1949.     RET
  1950. ;
  1951. ; Print regiaster A as 2 hex characters on console
  1952. ;
  1953. PA2HC:    PUSH    AF        ; Save 'A'
  1954.     PUSH    AF
  1955.     RRCA            ; Exchange nybbles
  1956.     RRCA
  1957.     RRCA
  1958.     RRCA
  1959.     CALL    PAHC        ; Print low-order nybble as hex
  1960.     POP    AF        ; Get a
  1961.     CALL    PAHC        ; Print low-order nybble as hex
  1962.     POP    AF        ; Restore a
  1963.     RET
  1964. ;
  1965. PAHC:    AND    0FH        ; Mask for low nybble
  1966.     CP    10        ; Letter or digit?
  1967.     JR    C,PADIG        ; Digit if carry
  1968.     ADD    A,'A'-10    ; Convert to 'a'-'f'
  1969.     JP    COUT        ; Print
  1970. ;
  1971. PADIG:    ADD    A,'0'        ; Convert to '0'-'9'
  1972.     JP    COUT        ; Print
  1973.      ENDIF
  1974. ;
  1975. ;-----------------------------------------------------------------------
  1976. ;
  1977. ; Start of the CP/M 3.0 specific subroutines for disk I/O.  Extracted
  1978. ; from CPM22E BIOS program, and slightly modified.  This portion most
  1979. ; probably could be utilized in almost any CP/M 2.2 program which uses
  1980. ; the BIOS for disk I/O.
  1981. ;
  1982. ; Translate records.  Records are not translated yet.  Wait until we
  1983. ; know the physical record number.  This works fine as long as a program
  1984. ; trusts the BIOS to do translation.  For programs that directly access
  1985. ; the XLAT table to do their own translation, this may give wrong idea
  1986. ; about disk skew but it shouldn't cause harm.
  1987. ;
  1988. RECTRN:    LD    L,C        ; Return record in HL
  1989.     LD    H,B
  1990.     RET
  1991. ;
  1992. ; Read the selected CP/M record
  1993. ;
  1994. READ3:    LD    A,1
  1995.     LD    (READOP),A    ; Read operation
  1996.     INC    A        ; A=2 (WRUAL)
  1997.     LD    (WRTYP3),A    ; Treat as unallocated
  1998.     JP    ALLOC        ; Perform read
  1999. ;
  2000. ; Write the selected CP/M record
  2001. ;
  2002. WRITE3:    XOR    A
  2003.     LD    (READOP),A    ; Not a read operation
  2004.     LD    A,C
  2005.     LD    (WRTYP3),A    ; Save write type
  2006.     CP    2        ; Unallocated block?
  2007.     JP    NZ,CHKUNA
  2008. ;
  2009. ; Write to first record of unallocated block
  2010. ;
  2011.     LD    A,(BLM)        ; Get block shift mask
  2012.     INC    A        ; Adjust value
  2013.     LD    (UNACNT),A    ; Unalloc record count
  2014.     LD    A,(LOGDSK)    ; Set up values for
  2015.     LD    (UNADSK),A    ; Writing to an unallocated
  2016.     LD    A,(LOGTRK)    ; Block
  2017.     LD    (UNATRK),A
  2018.     LD    A,(LOGREC)
  2019.     LD    (UNAREC),A
  2020. ;
  2021. CHKUNA:    LD    A,(UNACNT)    ; Any unallocated records
  2022.     OR    A        ; In this block
  2023.     JP    Z,ALLOC        ; Skip if not
  2024.     DEC    A        ; --UNACNT
  2025.     LD    (UNACNT),A
  2026.     LD    A,(LOGDSK)
  2027.     LD    HL,UNADSK
  2028.     CP    (HL)        ; LOGDSK = UNADSK ?
  2029.     JP    NZ,ALLOC    ; Skip if not
  2030.     LD    A,(LOGTRK)
  2031.     CP    (HL)        ; LOGTRK = UNATRK ?
  2032.     JP    NZ,ALLOC    ; Skip if not
  2033.     LD    A,(LOGREC)
  2034.     LD    HL,UNAREC
  2035.     CP    (HL)        ; LOGTRK = UNASEC ?
  2036.     JP    NZ,ALLOC    ; Skip if not
  2037.     INC    (HL)        ; Move to next record
  2038.     LD    A,(HL)
  2039.     LD    HL,SPT        ; Address of SPT
  2040.     CP    (HL)        ; Record > SPT ?
  2041.     JP    C,NOOVF        ; Skip if no overflow
  2042.     LD    HL,(UNATRK)
  2043.     INC    HL
  2044.     LD    (UNATRK),HL    ; Bump track
  2045.     XOR    A
  2046.     LD    (UNAREC),A    ; Reset record count
  2047. ;
  2048. NOOVF:    XOR    A
  2049.     LD    (RSFLAG),A    ; Do not pre-read
  2050.     JP    RWOPER        ; Perform write
  2051. ;
  2052. ALLOC:    XOR    A        ; Requires pre-read
  2053.     LD    (UNACNT),A
  2054.     INC    A
  2055.     LD    (RSFLAG),A    ; Force pre-read
  2056. ;
  2057. RWOPER:    XOR    A
  2058.     LD    (ERFLAG),A    ; No errors yet
  2059.     LD    A,(PSH)        ; Get physical shift factor
  2060.     OR    A        ; Set flags
  2061.     LD    B,A
  2062.     LD    A,(LOGREC)    ; Logical record
  2063.     LD    HL,(HSTBUF)    ; Addr of CP/M 3 record buffer
  2064.     LD    DE,128
  2065.     JP    Z,NOBLK        ; No blocking
  2066.     EX    DE,HL        ; Shuffle registers
  2067. ;
  2068. SHIFT:    EX    DE,HL
  2069.     RRCA
  2070.     JP    NC,SH1
  2071.     ADD    HL,DE        ; Bump buffer address
  2072. ;
  2073. SH1:    EX    DE,HL
  2074.     ADD    HL,HL
  2075.     AND    07FH        ; Zero high bit
  2076.     DJNZ    SHIFT
  2077.     EX    DE,HL        ; HL=buffer address
  2078. ;
  2079. NOBLK:    LD    (RECHST),A
  2080.     LD    (RECBUF),HL
  2081.     LD    HL,HSTACT    ; Buffer active flag
  2082.     LD    A,(HL)
  2083.     LD    (HL),1        ; Set buffer active
  2084.     OR    A        ; Was it already?
  2085.     JP    Z,FILHST    ; Fill buffer if not
  2086.     LD    A,(LOGDSK)
  2087.     LD    HL,HSTDSK    ; Same disk ?
  2088.     CP    (HL)
  2089.     JP    NZ,NMATCH
  2090.     LD    A,(LOGTRK)
  2091.     LD    HL,HSTTRK    ; Same track ?
  2092.     CP    (HL)
  2093.     JP    NZ,NMATCH
  2094.     LD    A,(RECHST)    ; Same buffer ?
  2095.     LD    HL,HSTREC
  2096.     CP    (HL)
  2097.     JP    Z,MATCH
  2098. ;
  2099. NMATCH:    LD    A,(HSTWRT)    ; Buffer changed?
  2100.     OR    A
  2101.     CALL    NZ,WRTHST    ; Clear buffer
  2102. ;
  2103. FILHST:    LD    A,(LOGDSK)
  2104.     LD    (HSTDSK),A
  2105.     LD    HL,(LOGTRK)
  2106.     LD    (HSTTRK),HL
  2107.     LD    A,(RECHST)
  2108.     LD    (HSTREC),A
  2109.     LD    A,(RSFLAG)    ; Need to read ?
  2110.     OR    A
  2111.     CALL    NZ,REDHST    ; Yes
  2112.     XOR    A
  2113.     LD    (HSTWRT),A    ; No pending write
  2114. ;
  2115. MATCH:    LD    DE,(DMAADR)
  2116.     LD    HL,(RECBUF)
  2117.     LD    A,(READOP)    ; Which way to move ?
  2118.     OR    A
  2119.     JP    NZ,RWMOVE    ; Skip if read
  2120.     LD    A,1
  2121.     LD    (HSTWRT),A    ; Mark buffer changed
  2122.     EX    DE,HL        ; Hl=dma  de=buffer
  2123. ;
  2124. RWMOVE:    LD    BC,128        ; Byte count
  2125.     LDIR            ; Block move
  2126.     LD    A,(WRTYP3)    ; Write type
  2127.     CP    1        ; To directory ?
  2128.     JP    NZ,RWEXIT    ; Done
  2129.     LD    A,(ERFLAG)    ; Check for errors
  2130.     OR    A
  2131.     JP    NZ,RWEXIT    ; Do not write dir if so
  2132.     XOR    A
  2133.     LD    (HSTWRT),A    ; Show buffer written
  2134.     CALL    WRTHST        ; Write buffer
  2135. ;
  2136. RWEXIT:    LD    A,(ERFLAG)
  2137.     RET
  2138. ;
  2139. ; Disk read, call bios to fill the buffer with one physical record
  2140. ;
  2141. REDHST:    CALL    RWINIT        ; Initialize CP/M 3.0 BIOS
  2142.     LD    A,13        ; BIOS READ function
  2143.     JP    DORW        ; Go do it
  2144. ;
  2145. ; Disk write, call BIOS to write one physical record from buffer
  2146. ;
  2147. WRTHST:    CALL    RWINIT        ; Initialize CP/M 3.0 BIOS
  2148.     LD    A,14        ; BIOS WRITEW function
  2149. ;
  2150. ; Call BIOS to read (or write) 1 physical record to (or from) buffer.
  2151. ;
  2152. DORW:    CALL    XBIOS3        ; Go do it to the record
  2153.     LD    (ERFLAG),A
  2154.     RET
  2155. ;
  2156. ; Read/write initialization routine does the following:  Translate re-
  2157. ; cord, set track, record, DMA buffer and DMA bank.
  2158. ;
  2159. RWINIT:    LD    HL,(HSTTRK)    ; Get physical track number
  2160.     LD    (BCREG),HL    ; Put track number in BC
  2161.     LD    A,10        ; BIOS SETTRK function
  2162.     CALL    XBIOS3
  2163. ;
  2164.     LD    A,(HSTREC)    ; Get physical record number
  2165.     LD    L,A
  2166.     LD    H,0
  2167.     LD    (BCREG),HL    ; Put record number in BC
  2168.     LD    HL,(RECTBL)    ; Address of XLAT table
  2169.     LD    (DEREG),HL    ; XLAT address in DE
  2170.     LD    A,16        ; BIOS RECTRN function
  2171.     CALL    XBIOS3        ; Get skewed record #
  2172. ;
  2173.     LD    A,L
  2174.     LD    (ACTREC),A    ; Actual record
  2175.     LD    (BCREG),HL    ; Record number in BC
  2176.     LD    A,11        ; BIOS SETREC function
  2177.     CALL    XBIOS3        ; Set CP/M 3.0 record
  2178. ;
  2179.     LD    HL,(HSTBUF)    ; Address of CP/M 3.0 record buffer
  2180.     LD    (BCREG),HL    ; Buffer address in BC
  2181.     LD    A,12        ; SETDMA function
  2182.     CALL    XBIOS3
  2183. ;
  2184.     LD    A,1        ; DMA bank number
  2185.     LD    (AREG),A    ; Put bank number in 'A'
  2186.     LD    A,28        ; BIOS SETBNK function
  2187.     CALL    XBIOS3        ; Set DMA bank
  2188.     RET
  2189. ;
  2190. ;
  2191. ; Under CP/M 3.0, direct bios calls via the bios jump vector are only
  2192. ; supported by the bios console i/o and list functions.  You must use
  2193. ; bdos function 50 to call any other bios function. Store appropriate
  2194. ; registers in the bios parameter block [eg: ld (bcreg),bc] and enter
  2195. ; this routine with the desired bios function number in register a.
  2196. ;
  2197. ; All CP/M 3.0 disk I/O calls are made through here
  2198. ;
  2199. XBIOS3:    LD    (BIOSPB),A    ; Set BIOS function
  2200.     LD    C,50        ; Direct BIOS call function
  2201.     LD    DE,BIOSPB    ; BIOS parameter block
  2202.     JP    BDOS        ; Jump to BDOS
  2203. ;
  2204. ;-----------------------------------------------------------------------
  2205. ;
  2206. ; Temporary storage area for the program
  2207. ;
  2208. DATA    EQU    $
  2209. ;
  2210. STATS:    DEFS    1
  2211. SGPCTR:    DEFS    2
  2212. SWPCTR:    DEFS    2
  2213. GRDCTR:    DEFS    2
  2214. GWRCTR:    DEFS    2
  2215. DIRWCT:    DEFS    2
  2216. ;
  2217. GRBUF1:    DEFS    2
  2218. GRBUF2:    DEFS    2
  2219. BLS:    DEFS    2
  2220. DIRBYT:    DEFS    2
  2221. DIRCTR:    DEFS    2
  2222. DIRACT:    DEFS    2
  2223. DIRGRP:    DEFS    2
  2224. SRCHGP:    DEFS    2
  2225. BADGRP:    DEFS    2
  2226. GRPALL:    DEFS    1
  2227. GRPNUM:    DEFS    1
  2228. FILPTR:    DEFS    2
  2229. ALLPTR:    DEFS    2
  2230. GRPTR:    DEFS    2
  2231. WRTYP:    DEFS    2
  2232. WRFLG:    DEFS    2
  2233. GRPCTR:    DEFS    1
  2234. RECCTR:    DEFS    1
  2235. DIRCHG:    DEFS    1
  2236. ;
  2237. CRCACC:    DEFS    2        ; Accumulator for CRC value (SYSLIB)
  2238. CRCFLG:    DEFS    1
  2239. CRCVAL:    DEFS    2
  2240. CRCBEG:    DEFS    2
  2241. CRCTRK:    DEFS    2
  2242. CRCREC:    DEFS    2
  2243. ;
  2244. TEMPC:    DEFS    1        ; Used in "GRP2SC"
  2245. ;
  2246. ASCDSK:    DEFS    1        ; ASCII drive number
  2247. FIRST0:    DEFS    1        ; Sets 0 if first record number is 0
  2248. FILECT:    DEFS    2        ; File count
  2249. CURTRK:    DEFS    2        ; Current track number
  2250. CURREC:    DEFS    2        ; Current record number
  2251. PHYREC:    DEFS    2        ; Current physical record number
  2252. MAXTRK:    DEFS    2        ; Maximum track number
  2253. ;
  2254. ; Next 5 for low memory or high DRM
  2255. ;
  2256. NEWMAX:    DEFS    2        ; New faked memory directory capacity
  2257. FAKDRM:    DEFS    2        ; New faked DRM value
  2258. BLMSIZ:    DEFS    2        ; K size of blocks
  2259. NEWGRP:    DEFS    1        ; New faked number of directory groups
  2260. STRTGP:    DEFS    2        ; Starting group in case faked
  2261. ;
  2262. DIRECT:    DEFS    2        ; Pointer to directory buffer
  2263. ;
  2264. ;-----------------------------------------------------------------------
  2265. ;
  2266. ; Data area common to program and CP/M 3.0 subroutines
  2267. ;
  2268. RECTBL:    DEFS    2        ; Pointer to record XLT table
  2269. ;
  2270. DPB:                ; DPB for CP/M 2.2 & 3.0
  2271. SPT:    DEFS    2        ; Copy of disk parameter block
  2272. BSH:    DEFS    1
  2273. BLM:    DEFS    1
  2274. EXM:    DEFS    1
  2275. DSM:    DEFS    2
  2276. DRM:    DEFS    2
  2277. AL0:    DEFS    1
  2278. AL1:    DEFS    1
  2279. CKS:    DEFS    2
  2280. SYSTRK:    DEFS    2
  2281. PSH:    DEFS    1        ; Physical shift count (CP/M 3.0)
  2282. PHM:    DEFS    1        ; Physical record mask (CP/M 3.)
  2283. ;
  2284. BIOSPB:    DEFS    1        ; BIOS function
  2285. AREG:    DEFS    1        ; A register
  2286. BCREG:    DEFS    2        ; BC registers
  2287. DEREG:    DEFS    2        ; DE registers
  2288. HLREG:    DEFS    2        ; HL registers
  2289. ;
  2290. DMAADR:    DEFS    2        ; Last DMA address
  2291. LOGDSK:    DEFS    1        ; Logical disk number
  2292. LOGREC:    DEFS    2        ; Logical recort number
  2293. LOGTRK:    DEFS    2        ; Logical track number
  2294. HSTBUF:    DEFS    2        ; Address of CP/M 3.0 record buffer
  2295. ;
  2296. ;-----------------------------------------------------------------------
  2297. ;
  2298. ; Data/variable storage area for CP/M 3.0 subroutines
  2299. ;
  2300. HSTDSK:    DEFS    1        ; Physical disk number
  2301. HSTTRK:    DEFS    2        ; Physical track number
  2302. HSTREC:    DEFS    1        ; Physical record number
  2303. ;
  2304. ACTREC:    DEFS    1        ; Skewed physical record
  2305. RECHST:    DEFS    1        ; Temp phyical racord
  2306. HSTACT:    DEFB    0        ; Buffer active flag, initial 0
  2307. HSTWRT:    DEFB    0        ; Buffer changed flag, initial 0
  2308. ;
  2309. UNACNT:    DEFS    1        ; Unallocated record count
  2310. UNADSK:    DEFS    1        ; Unallocated disk number
  2311. UNATRK:    DEFS    2        ; Unallocated track number
  2312. UNAREC:    DEFS    1        ; Unallocated record number
  2313. RECBUF:    DEFS    2        ; Logical racord address in buffer
  2314. ;
  2315. ERFLAG:    DEFS    1        ; Error reporting
  2316. RSFLAG:    DEFS    1        ; Force record read
  2317. READOP:    DEFS    1        ; 1 if read operation
  2318. WRTYP3:    DEFS    1        ; Write operation type
  2319. ;
  2320. ;-----------------------------------------------------------------------
  2321. ;
  2322. ; Start of stack and buffers
  2323. ;
  2324.     DEFS    40        ; Min stack depth (20 levels)
  2325. EVEN    EQU    ($+255)/256*256    ; Start buffer on even page
  2326.     ORG    EVEN        ; Also increases stack greatly
  2327. STACK    EQU    $-2
  2328. DATSIZ    EQU    $-DATA        ; Size of data area
  2329.                 ; Buffers start here
  2330. ;
  2331.     END
  2332.