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 / SIMTEL / CPMUG / CPMUG052.ARK / CPYFST35.ASM < prev    next >
Assembly Source File  |  1984-04-29  |  26KB  |  1,151 lines

  1. ;              COPYFAST.ASM Version 3.5
  2. ;        (See the DOC file for change history)
  3. ;
  4.     ORG    0100H
  5. ;
  6. ;
  7. ;    Equates
  8. ;
  9. FALSE    EQU    0    ; define false
  10. TRUE    EQU    NOT FALSE;  define true
  11. ;
  12. EXITCP    EQU    0    ; warm start return to CP/M
  13. FCB    EQU    5CH    ; default FCB address
  14. ;
  15. CR    EQU    0DH    ; ASCII Carriage return
  16. LF    EQU    0AH    ; ASCII line feed
  17. CTRLC    EQU    3    ; ASCII control-C
  18. ;
  19. ;    User-modifiable switches
  20. ;
  21. SINGLE    EQU    FALSE    ; TRUE for single drive copy program
  22. RSKEW    EQU    FALSE    ; TRUE if read interleaving needed
  23. ;            ; Note: change READTAB if TRUE
  24. DOCOMP    EQU    TRUE    ; TRUE if byte-by-byte comparison
  25. ;            ; desired on read-after-write check
  26. TRSKW    EQU    TRUE     ; TRUE if track skewing is wanted
  27. ;            ; on non-interleaved reads
  28. ;            ; (RSKEW MUST be false)
  29. WRSWCH    EQU    FALSE    ; TRUE if CP/M 2.2 block/deblock
  30. ;            ; routines need various values in
  31. ;            ; reg. C during writes. See WRTAB
  32. ;
  33. NUMERR    EQU    4    ; number of error retries done
  34. ;
  35. BUFFNU  EQU    0    ; the number of full track buffers
  36. ;    that will fit in your system. This figure includes
  37. ;    the space used by the read-back buffers, if used
  38. ;    (minimum 2). If zero, the number of buffers will
  39. ;    be automatically computed at execution.
  40. ;
  41. TSKEW    EQU    6    ; Amount of track-to-track skew
  42. ;            ; (if TRSKW is TRUE and RSKEW is FALSE)
  43. ;            ; Should be less than SDLAST
  44. ;
  45. ;    The next two values specify the copy range, and the program
  46. ;    can be run in other ways by the parameter (first character
  47. ;    of the first filename) given when COPYFAST is first invoked:
  48. ;
  49. ;    All    0-(Lastrk-1)        Entire disk
  50. ;    Data    Firstrk-(Lastrk-1)    CP/M data area
  51. ;    First    Firstrk            CP/M directory track 
  52. ;    Last    (Lastrk-1)        Last track on disk
  53. ;    One    1            Track one, UCSD directory
  54. ;    Pascal    1-(Lastrk-1)        UCSD Pascal data area
  55. ;    System    0-(Firstrk-1)        CP/M bootstrap
  56. ;    Zero    0            Track zero, UCSD bootstrap
  57. ;            (Note: only complete tracks are copied)
  58. ;    The default range, currently Firstrk to Lastrk-1, is given
  59. ;    in the two values at TRKSRT.
  60. ;
  61. FIRSTRK EQU    2        ; the first data track copied.
  62. ;                ; The bootstrap is assumed to be
  63. ;                ; on tracks 0 to Firstrk-1
  64. LASTRK    EQU    77        ; the last track copied plus one
  65. ;
  66. DIFFTRK    EQU    0        ; difference between first source
  67. ;                ; track and the first object track.
  68. ;                ; (applies only when default range
  69. ;                ; is used)
  70. ;
  71. SDLAST  EQU    26        ; the number of sectors per track
  72. ;                ; Also determines the lengths of
  73. ;                ; WRTAB, READTAB, and WRITAB
  74. ;
  75. SECSIZ    EQU    128        ; number of bytes per sector.
  76. ;
  77. WRCODE    EQU    2        ; value passed to sector write rtn
  78. ;                ; in reg. C if WRSWCH is FALSE
  79.     IF    TRSKW AND RSKEW
  80. TRSKW    SET    FALSE        ; option is wrong
  81.     ENDIF
  82. ;
  83. ;    A set of dummy branch points to the CBIOS that are
  84. ;    filled in by the VECTOR routine.
  85. ;
  86. START:
  87.     JMP    VECTOR        ; go initialize the branches
  88. WBOOT:
  89.     JMP    $-$        ; not used
  90. CONST:
  91.     JMP    $-$
  92. CONIN:
  93.     JMP    $-$
  94. CONOUT:
  95.     JMP    $-$
  96. LIST:
  97.     JMP    $-$        ; not used
  98. PUNCH:
  99.     JMP    $-$        ; not used
  100. READER:
  101.     JMP    $-$        ; not used
  102. HOME:
  103.     JMP    $-$
  104. SELDIS:
  105.     JMP    $-$
  106. SETRAK:
  107.     JMP    $-$
  108. SETSCT:
  109.     JMP    $-$
  110. SETDMA:
  111.     JMP    $-$
  112. READ:
  113.     JMP    $-$
  114. WRITE:
  115.     JMP    $-$
  116. ;
  117. ;    Useful constants placed here for finding easily
  118. ;    These can be changed using DDT to alter some of
  119. ;    the characteristics of the program to suit your
  120. ;    taste.
  121. ;
  122. TRKSRT:                ; default first and last+1 track numbers
  123. ;                ; Can be changed at run time
  124.     DB    FIRSTRK
  125.     DB    LASTRK
  126. BUFFNMB:            ; max. number of buffers
  127.     DB    BUFFNU
  128. SRCTRAK:            ; source track - object track
  129.     DB    DIFFTRK
  130. ;
  131. ;    This  is the point where the program returns to repeat  the
  132. ;    copy. Everything is re-initialized.
  133. ;
  134. REPEAT:
  135.     LXI    SP,STKTOP    ; re-initialize stack
  136.     LXI    D,SOURCE
  137.     CALL    PRINT        ; ask for source drive
  138. SRCELU:
  139.     CALL    CONIN        ; read response (upper case)
  140.     CPI    CTRLC
  141.     JZ    EXIT        ; CTRL-C means abort
  142.     ANI    5FH
  143.     CPI    'A'    ;41H
  144.     JC    SRCELU        ; bad value - less than A
  145.     CPI    'F'    ;46H
  146.     JZ    SETSOU
  147.     JC    SETSOU
  148.     JMP    SRCELU        ; bad value - greater than F
  149. SETSOU:
  150.     STA    SRCEME        ; save the source drive
  151.     IF    SINGLE
  152.     STA    OBJMES
  153.     ENDIF
  154.     SUI    'A'    ;41H
  155.     STA    SRCEDR        ; convert value to CP/M number
  156.     LDA    SRCEME
  157.     CALL    CONOUT        ; echo value to console
  158.     IF    NOT SINGLE
  159.     LXI    D,OBJECT    ; prompt for destination disk
  160.     CALL    PRINT
  161. OBJLUP:                ; read response
  162.     CALL    CONIN
  163.     CPI    CTRLC        ; CTRL-C means abort
  164.     JZ    EXIT
  165.     ANI    5FH        ; convert to upper case
  166.     CPI    'A'    ;41H
  167.     JC    OBJLUP        ; bad value - less than A
  168.     CPI    'F'    ;46H
  169.     JZ    SETOBJ
  170.     JC    SETOBJ
  171.     JMP    OBJLUP        ; bad value - greater than F
  172. SETOBJ:
  173.     LXI    H,SRCEME    ; Cannot have a one drive copy
  174.     CMP    M
  175.     JZ    OBJLUP
  176.     STA    OBJMES        ; save the destination drive
  177.     SUI    'A'    ;41H
  178.     STA    OBJDRI        ; convert value to CP/M number
  179.     LDA    OBJMES
  180.     CALL    CONOUT        ; echo object drive
  181.     LXI    D,SIGNON
  182.     CALL    PRINT        ; now give chance to change disks
  183. ;                ; or give up
  184. AGIN:
  185.     CALL    CONIN        ; read response from keyboard
  186.     CPI    CTRLC
  187.     JZ    EXIT        ; ctrl-C means quit
  188.     CPI    CR
  189.     JNZ    AGIN         ; CR means go. Ignore anything else
  190.     ENDIF
  191. ;
  192. ;    now go do it !
  193. ;
  194.     LXI    D,CRLF
  195.     CALL    PRINT        ; now start actual copy
  196.     CALL    COPY
  197.     LXI    D,DONMSG
  198.     CALL    PRINT        ; copy is now done, say so
  199. ;
  200. ;    end of this copy
  201. ;
  202. EXIT:
  203.     LXI    SP,STKTOP    ; re-initialize stack
  204.     LDA    SRCEDR        ; first, select source drive
  205.     MOV    C,A
  206.     CALL    SELDSK
  207.     CALL    HOME        ; home the disk in case
  208.     IF    NOT SINGLE
  209.     LDA    OBJDRI
  210.     MOV    C,A        ; now, select destination drive
  211.     CALL    SELDSK
  212.     CALL    HOME        ; and home that disk, in case
  213.     ENDIF
  214.     LXI    D,REPMES    ; ask if another copy is desired
  215.     CALL    PRINT
  216.     CALL    CONIN        ; read response, upper case
  217.     ANI    5FH
  218.     CPI    'R'        ; R means repeat
  219.     JZ    REPEAT
  220.     CPI    CR        ; carriage return means back to CP/M
  221.     JNZ    EXIT
  222.     MVI    C,0        ; set default disk back to A
  223.     CALL    SELDSK
  224.     JMP    EXITCP        ; and warmstart back to CP/M
  225. ;
  226. ;    convert value in A reg. to ASCII hex and print it
  227. ;
  228. PRTHEX:
  229.     PUSH    PSW        ; save for LSN
  230.     RAR
  231.     RAR            ; shift MSN nibble to LSN
  232.     RAR
  233.     RAR
  234.     CALL    PRTNBL        ; now print it
  235.     POP    PSW        ; and then do LSN
  236. PRTNBL:
  237.     ANI    0FH
  238.     ADI    '0'        ;convert to ASCII value
  239.     CPI    '0'+10        ; over 9 ?
  240.     JC    SML
  241.     ADI    7        ; convert 10 to A, etc.
  242. SML:
  243.     MOV    C,A        ; move to C for BDOS call
  244.     CALL    CONOUT
  245.     RET
  246. ;
  247. ;
  248. ;    this is the main copy routine
  249. ;
  250. COPY:
  251.     LDA    SRCEDR        ; first, select source drive
  252.     MOV    C,A
  253.     CALL    SELDSK
  254.     CALL    HOME        ; home the disk first, in case
  255. ;                ; the controller requires it.
  256. ;                ; (this might be the first time
  257. ;                ; the drive has been used)
  258.     LDA    TRKSRT
  259.     CALL    SETTRK        ; now start with first track
  260.     IF    NOT SINGLE
  261.     LDA    OBJDRI
  262.     MOV    C,A        ; now, select destination drive
  263.     CALL    SELDSK
  264.     CALL    HOME        ; and home that disk, in case
  265.     ENDIF
  266. ;
  267. ;    return here to continue copy
  268. ;
  269. RDLOOP:
  270.     LDA    TRK        ; note current track
  271.     STA    TRKSAV
  272.     XRA    A        ; reset error counter
  273.     STA    CMPERR
  274.     LXI    D,TRKM        ; print the current starting track
  275.     CALL    PRINT        ; being copied
  276.     LDA    TRKSAV
  277.     CALL    PRTHEX
  278. TRYRDA:
  279.     IF    SINGLE
  280.     LXI    D,SIGNON    ; now give operator chance to change disk
  281.     ENDIF
  282.     LDA    SRCEDR        ; select source drive
  283. ;
  284. ;    read  loop
  285. ;
  286.     CALL    STARTL        ; start the copy loop (reading source)
  287. LOOP1:
  288.     CALL    READT        ; read one track
  289.     JZ    LOOP4        ; if all tracks read, go check errors
  290.     LDA    ERR1
  291.     ORA    A        ; not all done, but see if error already
  292.     JNZ    LOOP1        ; and go try another track
  293. ;
  294. ;    now see if any errors in the previous operations
  295. ;
  296. LOOP4:
  297.     LDA    ERR1        ; now check if any errors
  298.     ORA    A
  299.     JNZ    RDSKIP        ; jump if no errors at all
  300.     MVI    A,10H
  301.     STA    ERR1        ; reset error flag
  302. ;
  303. ;    allow NUMERR errors before giving up
  304. ;
  305.     LDA    CMPERR        ; check the retry counter
  306.     INR    A
  307.     STA    CMPERR
  308.     CPI    NUMERR        ; normally ten retries max
  309.     JNZ    LOOP1    ; WAS TRYRDA
  310.     LXI    D,MESGC        ; if maximum error count,
  311.     CALL    PRINT        ;   print message
  312.     XRA    A
  313.     STA    CMPERR        ; full track error, reset error counter
  314.     CALL    ENDLUP
  315.     JNZ    LOOP1        ; now bump up track and see if done
  316. ;
  317. ;    write loop
  318. ;
  319. RDSKIP:
  320.     XRA    A        ; reset error counter
  321.     STA    CMPERR
  322. TRYAGA:
  323.     IF    SINGLE
  324.     LXI    D,OBJMSG    ; give chance to put in object disk
  325.     ENDIF
  326.     LDA    OBJDRI        ; now select destination disk
  327.     CALL    STARTL        ; start the write loop
  328. LOOP2:
  329.     CALL    WRITET        ; write one track (and readback check)
  330.     JZ    LOOP3        ; if all tracks written, go check errors
  331.     LDA    ERR1
  332.     ORA    A        ; not all done, but see if error already
  333.     JNZ    LOOP2
  334. ;
  335. ;    now see if any errors in the previous operations
  336. ;
  337. LOOP3:
  338.     LDA    ERR1        ; now check if any errors
  339.     ORA    A
  340.     JNZ    SKIP        ; jump if no errors at all
  341. ;
  342. ;    allow NUMERR errors before giving up
  343. ;
  344.     LDA    CMPERR        ; check the retry counter
  345.     INR    A
  346.     STA    CMPERR
  347.     CPI    NUMERR        ; normally ten retries max
  348.     JNZ    TRYAGA
  349.     LXI    D,MESGC        ; if maximum error count,
  350.     CALL    PRINT        ;   print message
  351.     LDA    BUFFNMB
  352.     MOV    H,A
  353.     LDA    TRK        ;   and set next track
  354.     INR    A        ;   past track in error
  355.     SUB    H
  356.     STA    TRKSAV
  357. ;
  358. ;    copied all tracks correctly (or NUMERR errors)
  359. ;
  360. SKIP:
  361.     LDA    BUFFNMB        ; get number of buffers
  362.     MOV    H,A
  363.     LDA    TRKSAV        ; bump up track counter
  364.     ADD    H
  365.     STA    TRK
  366.     LXI    H,TRKSRT+1    ; see if copy operation is done
  367.     CMP    M
  368.     RNC
  369.     JNZ    RDLOOP        ; go back and do more
  370.     RET
  371. ;
  372. ;    This routine selects the disk,  and initializes the  buffer
  373. ;    address,  buffer counter, and track counter,and seeks to the
  374. ;    right track.
  375. ;
  376. STARTL:
  377.     IF    SINGLE
  378.     CALL    HOME        ; Home the disk for a deblocking CBIOS
  379. ;                ; to get a chance to flush the buffer
  380.     CALL    PRINT        ; now give chance to change disks
  381. ;                ; or give up
  382. AGIN:
  383.     CALL    CONIN        ; read response from keyboard
  384.     CPI    CTRLC
  385.     JZ    EXIT        ; CTRL-C means quit
  386.     CPI    CR
  387.     JNZ    AGIN         ; CR means go. Ignore anything else
  388.     ENDIF
  389.     IF    NOT SINGLE
  390.     MOV    C,A        ; select the disk first
  391.     CALL    SELDSK
  392.     ENDIF
  393.     IF    TRSKW
  394.     XRA    A        ; zero out track sector skew
  395.     STA    TSECT
  396.     STA    TBUFF        ; zero out coresponding buffer addr
  397.     STA    TBUFF+1
  398.     ENDIF
  399.     LXI    H,BUF0        ; load address of first buffer
  400.     SHLD    BUF0SA
  401.     MVI    A,10H        ; reset error flag
  402.     STA    ERR1
  403.     LDA    BUFFNMB        ; load number of buffers
  404.     STA    BUFFCO
  405.     LDA    TRKSAV        ; load first track copied
  406. ;
  407. ;    set the track to be used, and add offset if source
  408. ;    drive. Save track number for error routine.
  409. ;
  410. SETTRK:
  411.     STA    TRK        ; save current track
  412.     IF    (NOT SINGLE)
  413.     LDA    CURRDI        ; check drive
  414.     MOV    C,A
  415.     LDA    SRCEDR        ; is it source
  416.     CMP    C
  417.     LDA    TRK        ; if object, skip
  418.     JNZ    SETTR0
  419.     MOV    C,A        ; now get difference
  420.     LDA    SRCTRAK
  421.     ADD    C        ; and do correction
  422. SETTR0:
  423.     ENDIF
  424.     MOV    C,A        ; now go set track
  425.     JMP    SETRAK
  426. ;
  427. ;    set the DMA address (in HL)
  428. ;
  429. DMASET:
  430.     MOV    C,L        ; move HL to BC
  431.     MOV    B,H
  432.     PUSH    B        ; save result and call CBIOS
  433.     CALL    SETDMA
  434.     POP    B
  435.     RET
  436. ;
  437. ;    these are the disk error handling routines
  438. ;
  439. FAILR:
  440.     LXI    D,MESGD        ; read error message
  441.     JMP    DIE
  442. FAILW:
  443.     LXI    D,MESGE        ; write error message
  444. DIE:
  445.     CALL    PRINT        ; print the main error message
  446.     LXI    D,ERM
  447.     CALL    PRINT
  448.     LDA    TRK          ; print the track number
  449.     CALL    PRTHEX
  450.     LXI    D,MESGB        ; print sector message
  451.     CALL    PRINT
  452.     LDA    SECTOR        ; and print sector
  453.     CALL    PRTHEX
  454.     LXI    D,DRIVE        ; print drive message
  455.     CALL    PRINT
  456.     LDA    CURRDI
  457.     ADI    'A'        ; convert drive number to ASCII
  458.     MOV    C,A
  459.     CALL    CONOUT        ; and finally print drive
  460.     XRA    A
  461.     STA    ERR1         ; note the error so this track is retried
  462.     CALL    CONST
  463.     ORA    A        ; see if any console input present
  464.     JZ    ENDLUP
  465.     CALL    CONIN        ; yes, see if aborting
  466.     CPI    CTRLC
  467.     JZ    EXIT        ; die if CTRL-C was hit
  468.     JMP    ENDLUP
  469. ;
  470. ;    read the full track now, no interleaving
  471. ;
  472. READT:
  473.     CALL    CONST
  474.     ORA    A        ; see if any console input present
  475.     JZ    READT0
  476.     CALL    CONIN        ; yes, see if aborting
  477.     CPI    CTRLC
  478.     JZ    EXIT        ; die if CTRL-C was hit
  479. READT0:
  480.     IF    (NOT RSKEW) AND (NOT TRSKW)
  481.     LHLD    BUF0SA        ; first, get beginning of buffer
  482.     SHLD    DMAAD
  483.     ENDIF
  484.     IF    TRSKW
  485.     LHLD    BUF0SA        ; first, get beginning of buffer
  486.     XCHG
  487.     LHLD    TBUFF        ; and correct for skew
  488.     DAD    D
  489.     SHLD    DMAAD
  490.     LDA    TSECT        ; initialize first sector
  491.     MOV    C,A
  492.     ENDIF
  493.     IF    (NOT TRSKW)
  494.     MVI    C,0        ; initialize first sector
  495.     ENDIF
  496.     MVI    B,SDLAST    ; initialize sector count
  497. RT3:
  498.     IF    TRSKW
  499.     MOV    A,C        ; check for skew too big
  500.     CPI    SDLAST
  501.     JC    RT4        ; jump if sector within range
  502.     XRA    A
  503.     MOV    C,A        ; out of range, back to sector 1
  504.     LHLD    BUF0SA
  505.     SHLD    DMAAD
  506. RT4:
  507.     ENDIF
  508.     IF    RSKEW
  509.     INR    C        ; increment sector counter
  510.     PUSH    B
  511.     LXI    H,READTAB-1    ; find the interleaved sector number
  512.     MVI    B,0
  513.     DAD    B        ; using the READTAB
  514.     MOV    C,M
  515.     CALL    SETSEC        ; and set the sector
  516.     MVI    H,0
  517.     DCR    C        ; now compute the buffer location
  518.     MOV    L,C
  519. ;
  520.     DAD    H        ; corresponding to that sector
  521.     DAD    H
  522.     DAD    H        ; by multiplying by 128
  523.     DAD    H
  524.     DAD    H        ; The number of DAD H instructions
  525.     DAD    H        ; MUST correspond to the buffer size
  526.     DAD    H        ; i.e. 7 DADs means 128 byte (2^7)
  527. ;
  528.     XCHG
  529.     LHLD    BUF0SA        ; and then adding to the buffer start
  530.     DAD    D
  531.     CALL    DMASET        ; set the DMA and do the read
  532.     ENDIF
  533.     IF    (NOT RSKEW)
  534.     INR    C        ; increment sector counter
  535.     PUSH    B
  536.     CALL    SETSEC        ; set the sector
  537.     LHLD    DMAAD
  538.     CALL    DMASET        ; set the DMA
  539.     LXI    H,SECSIZ
  540.     DAD    B        ; bump up the DMA for next time
  541.     SHLD    DMAAD
  542.     ENDIF
  543.     CALL    READ        ; now read one sector
  544.     RAR
  545.     CC    FAILR        ; if returned 01, read error
  546.     POP    B
  547.     DCR    B        ; see if all sectors read
  548.     JNZ    RT3
  549.     IF    TRSKW
  550.     LHLD    TBUFF        ; bump up skewed buffer
  551.     LXI    D,SECSIZ*TSKEW
  552.     DAD    D        ; add the skew
  553.     SHLD    TBUFF
  554.     LDA    TSECT        ; now bump starting sector
  555.     ADI    TSKEW
  556.     STA    TSECT        ; and put it back
  557.     SBI    SDLAST
  558.     JC    ENDLUP        ; jump if sector within range
  559.     STA    TSECT
  560.     LHLD    TBUFF
  561.     LXI    D,-SDLAST*SECSIZ; correct sector start and
  562.     DAD    D
  563.     SHLD    TBUFF        ;  buffer skew address
  564.     ENDIF
  565.     JMP    ENDLUP        ; return with complete track read
  566. ;
  567. ;    Write the full track,  with interleaving,  and then check it
  568. ;    by reading it all back in.
  569. ;
  570. WRITET:
  571.     CALL    CONST
  572.     ORA    A        ; see if any console input present
  573.     JZ    WRITE0
  574.     CALL    CONIN        ; yes, see if aborting
  575.     CPI    CTRLC
  576.     JZ    EXIT        ; die if CTRL-C was hit
  577. WRITE0:
  578.     LHLD    BUF0SA        ; first, get the beginning of buffer
  579.     SHLD    DMAAD
  580.     MVI    C,0
  581.     MVI    B,SDLAST    ; initialize sector counter
  582. WT3:
  583.     PUSH    B
  584.     LXI    H,WRITAB    ; find the interleaved sector number
  585.     MVI    B,0
  586.     DAD    B        ; using the WRITAB
  587.     MOV    C,M
  588.     CALL    SETSEC        ; and set the sector
  589.     MVI    H,0
  590.     DCR    C        ; now compute the buffer location
  591.     MOV    L,C
  592. ;
  593.     DAD    H        ; corresponding to that sector
  594.     DAD    H
  595.     DAD    H        ; by multiplying by 128
  596.     DAD    H
  597.     DAD    H        ; NOTE: see comments in RT3 for
  598.     DAD    H        ; changing this code for other
  599.     DAD    H        ; than 128 byte sectors
  600. ;
  601.     XCHG
  602.     LHLD    DMAAD        ; and then adding to the buffer start
  603.     DAD    D
  604.     CALL    DMASET        ; set the DMA and do the write
  605.     IF    NOT WRSWCH
  606.     MVI    C,WRCODE    ; value for CP/M 2.2 routine
  607.     ENDIF
  608.     IF    WRSWCH
  609.     POP    B        ; get sector number
  610.     PUSH    B
  611.     LXI    H,WRTAB-1    ; find the C reg. value for this
  612.     MVI    B,0
  613.     DAD    B        ; sector using the WRTAB
  614.     MOV    C,M
  615.     ENDIF
  616.     CALL    WRITE
  617.     RAR            ; if 01 returned, write error
  618.     CC    FAILW
  619.     POP    B
  620.     INR    C        ; increment sector count
  621.     DCR    B
  622.     JNZ    WT3        ; and loop back if not done
  623.     IF    DOCOMP AND (NOT RSKEW)
  624.     LXI    H,BUF1        ; first, get beginning of buffer
  625.     SHLD    DMAAD
  626.     ENDIF
  627.     MVI    C,0
  628.     MVI    B,SDLAST    ; reinitialize sector counts for read
  629. WT4:
  630.     INR    C        ; bump up sector counter
  631.     PUSH    B
  632.     IF    RSKEW
  633.     LXI    H,READTAB-1    ; find the interleaved sector number
  634.     MVI    B,0
  635.     DAD    B        ; using the READTAB
  636.     MOV    C,M
  637.     CALL    SETSEC        ; and set the sector
  638.     ENDIF
  639.     IF    RSKEW AND DOCOMP
  640.     MVI    H,0
  641.     DCR    C        ; now compute the buffer location
  642.     MOV    L,C
  643.     DAD    H        ; corresponding to that sector
  644.     DAD    H
  645.     DAD    H        ; by multiplying by 128
  646.     DAD    H
  647.     DAD    H        ; (2 ^ 7 = 128)
  648.     DAD    H
  649.     DAD    H
  650.     XCHG
  651.     LXI    H,BUF1        ; and then adding to the buffer start
  652.     DAD    D
  653.     CALL    DMASET        ; now set the read buffer
  654.     ENDIF
  655.     IF    (NOT RSKEW) AND DOCOMP
  656.     CALL    SETSEC        ; set the sector
  657.     LHLD    DMAAD
  658.     CALL    DMASET        ; set the DMA
  659.     LXI    H,SECSIZ
  660.     DAD    B        ; bump up the DMA for next time
  661.     SHLD    DMAAD
  662.     ENDIF
  663.     IF    RSKEW AND (NOT DOCOMP)
  664.     LXI    H,BUF1        ; load the buffer address
  665.     CALL    DMASET        ; and set the read buffer
  666.     ENDIF
  667.     IF    (NOT RSKEW) AND (NOT DOCOMP)
  668.     CALL    SETSEC        ; now set the sector
  669.     LXI    H,BUF1
  670.     CALL    DMASET        ; and set the read buffer
  671.     ENDIF
  672.     CALL    READ
  673.     RAR            ; was bit 0 set by disk error?
  674.     CC    FAILR
  675.     POP    B        ; no error, see if all sectors read
  676.     DCR    B
  677.     JNZ    WT4        ; if not all done, go back
  678.     IF    DOCOMP
  679.     LXI    B,SECSIZ*SDLAST    ; now, compare the track read in
  680.     LHLD    BUF0SA
  681.     LXI    D,BUF1
  682. CMPLP:    LDAX    D        ; get read data
  683.     CMP    M
  684.     JNZ    CERR        ; and if not what was written, error
  685.     INX    H
  686.     INX    D        ; bump counters
  687.     DCX    B
  688.     MOV    A,C        ; and count BC down to zero
  689.     ORA    B
  690.     JNZ    CMPLP        ; if all done, return
  691.     JMP    ENDLUP
  692. ;
  693. ;    print read verify compare error
  694. ;
  695. CERR:    PUSH    H        ; save the goodies
  696.     PUSH    D
  697.     PUSH    B
  698.     LXI    D,MESGA        ; start the error message
  699.     CALL    PRINT
  700.     LDA    TRK        ; print the track number
  701.     CALL    PRTHEX
  702.     LXI    D,MESGB        ; print more
  703.     CALL    PRINT
  704.     POP    H        ; pop the down counter
  705.     DCX    H
  706.     DAD    H        ; multiply by 2 to get sectors left
  707.     MVI    A,SDLAST
  708.     SUB    H        ; subtract from total number of sectors
  709.     CALL    PRTHEX        ; to get sector number, and print it
  710.     LXI    D,MEM
  711.     CALL    PRINT        ; print second line
  712.     POP    H
  713.     MOV    A,M        ; get byte read
  714.     STA    DATA1        ; and save it
  715.     PUSH    H
  716.     MOV    A,H        ; print high order byte of address
  717.     CALL    PRTHEX
  718.     POP    H
  719.     MOV    A,L        ; print low order byte of address
  720.     CALL    PRTHEX
  721.     MVI    C,','
  722.     CALL    CONOUT        ; comma
  723.     POP    H
  724.     MOV    A,M        ; get byte written
  725.     STA    DATA2        ; and save it
  726.     PUSH    H
  727.     MOV    A,H        ; print high order byte of address
  728.     CALL    PRTHEX
  729.     POP    H
  730.     MOV    A,L        ; print low order byte of address
  731.     CALL    PRTHEX
  732.     LXI    D,DATAM        ; print data header
  733.     CALL    PRINT
  734.     LDA    DATA1        ; print byte read
  735.     CALL    PRTHEX
  736.     MVI    C,','        ; comma
  737.     CALL    CONOUT
  738.     LDA    DATA2        ; print byte written
  739.     CALL    PRTHEX
  740.     XRA    A
  741.     STA    ERR1        ; note the error so this track is retried
  742.     ENDIF
  743. ;
  744. ;    This  routine  is  used to check if another track is  to  be
  745. ;    read/written:   it   increments  buffer  address  and  track
  746. ;    counter,   and  decrements  the  buffer  counter.  Then,  it
  747. ;    terminates  the  loop if all buffers are full  or  the  last
  748. ;    track has been processed (Z flag set).
  749. ;
  750. ENDLUP:
  751.     LDA    ERR1        ; now check if any errors
  752.     ORA    A        ; and return if so
  753.     RZ
  754.     LDA    TRK        ; increment track
  755.     INR    A
  756.     LXI    H,TRKSRT+1    ; check if last track
  757.     CMP    M
  758.     RZ            ; return if last track
  759.     CALL    SETTRK
  760.     LXI    H,BUFFCO    ; decrement buffer counter
  761.     DCR    M
  762.     RZ            ; return if all buffers full/empty
  763.     LXI    D,SECSIZ*SDLAST
  764.     LHLD    BUF0SA        ; increment buffer address
  765.     DAD    D
  766.     SHLD    BUF0SA
  767.     ORI    255        ; non-zero to indicate more
  768.     RET    
  769. ;
  770. ;    this  routine  writes  messages  to  the  console.  Message
  771. ;    address  is in DE,  and terminates on a $.  The BDOS call is
  772. ;    not  used  here because BDOS may be destroyed by  the  track
  773. ;    buffers
  774. ;
  775. PRINT:
  776.     LDAX    D        ; get the character
  777.     CPI    '$'    ;24H
  778.     RZ            ; quit if $
  779.     PUSH    D
  780.     MOV    C,A        ; send it to the console
  781.     CALL    CONOUT
  782.     POP    D        ; go check next character
  783.     INX    D
  784.     JMP    PRINT
  785. ;
  786. ;    set the next sector to be used, and save that
  787. ;    number for the error routine, in case
  788. ;
  789. SETSEC:
  790.     MOV    A,C        ; save the sector number
  791.     STA    SECTOR
  792.     PUSH    B        ; save regs, in case
  793.     CALL    SETSCT        ; now go set the sector
  794.     POP    B
  795.     RET
  796. ;
  797. ;    set the disk to be used, and save that
  798. ;    for the error routine, in case
  799. ;
  800. SELDSK:
  801.     MOV    A,C        ; save the disk number
  802.     STA    CURRDI
  803.     JMP    SELDIS        ; now select the disk
  804. ;
  805. ;    all messages here for convenience in disassembling
  806. ;
  807. DONMSG:
  808.     DB    CR,LF,'*** COPY COMPLETE ***$'
  809. DRIVE:
  810.     DB    ', DRIVE $'
  811. ERM:
  812.     DB    CR,LF,'+ ERROR ON TRACK (HEX)$'
  813. MESGB:
  814.     DB    ' SECTOR (HEX)$'
  815. MESGC:
  816.     DB    CR,LF,'++PERMANENT $'
  817. MESGD:
  818.     DB    CR,LF,'+ READ ERROR $'
  819. MESGE:
  820.     DB    CR,LF,'+ WRITE ERROR $'
  821. SIGNON:
  822.     DB    CR,LF,'SOURCE ON '
  823. SRCEME:
  824.     DB    0            ; will be filled in later
  825.     IF    NOT SINGLE
  826.     DB    ': OBJECT ON '
  827. OBJMES:
  828.     DB    0            ; will be filled in later
  829.     DB    ':'
  830.     ENDIF
  831. SINOFF:
  832.     DB    CR,LF,'TYPE <RET> TO CONTINUE, OR CONTROL-C TO EXIT: $'
  833.     IF    SINGLE
  834. OBJMSG:
  835.     DB    CR,LF,'OBJECT ON '
  836. OBJMES:
  837.     DB    0            ; will be filled in later
  838.     DB    ':'
  839.     DB    CR,LF,'TYPE <RET> TO CONTINUE, OR CONTROL-C TO EXIT: $'
  840.     ENDIF
  841. REPMES:
  842.     DB    CR,LF,'TYPE <RET> OR "R", TO REPEAT COPY: $'
  843. CRLF:
  844.     DB    CR,LF,'$'
  845. SOURCE:
  846.     DB    CR,LF,'SOURCE DRIVE (A THRU F): $'
  847.     IF    NOT SINGLE
  848. OBJECT:
  849.     DB    CR,LF,'OBJECT DRIVE (A THRU F): $'
  850.     ENDIF
  851. TRKM:
  852.     DB    CR,LF,'COPYING TRACK $'
  853. ;
  854.     IF    DOCOMP
  855. MESGA:
  856.     DB    CR,LF,'+ MEMORY COMPARE ERROR ON TRACK (HEX)$'
  857. MEM:
  858.     DB    CR,LF,'+ MEMORY ADDRESS $'
  859. DATAM:
  860.     DB    ' (OBJ,SRC)   DATA  $'
  861.     ENDIF
  862. ;
  863. ;     This  is  the  sector interleave table.  If  you  want  the
  864. ;    program to work,  all sector numbers must be here somewhere.
  865. ;
  866. WRITAB:
  867. ;
  868. ;    Interleave table for very fast controllers
  869. ;
  870.     DB    25,26,1,2,3,4,5,6,7,8,9,10,11,12
  871.     DB    13,14,15,16,17,18,19,20,21,22,23,24
  872. ;
  873. ;
  874.     IF    WRSWCH
  875. ;
  876. ;    This is the write switch table. The values in this table
  877. ;    are passed to the sector write routine of CP/M 2.2 in
  878. ;    reg. C when each write occurs. This table is modified if
  879. ;    and only if some particular pattern is needed for your
  880. ;    blocking routine to work as fast or as well as possible.
  881. ;    Refer to the CP/M 2.2 Alteration Guide for more details.
  882. ;
  883. WRTAB:
  884.     DB    2,2,2,2,2,2,2,2,2,2,2,2,2
  885.     DB    2,2,2,2,2,2,2,2,2,2,2,2,2
  886.     ENDIF
  887. ;
  888.     IF    RSKEW
  889. ;
  890. ;     This  is the read skew table,  if needed.  The same general
  891. ;    considerations as the write skew table apply here also,  but
  892. ;    the table should start with sector 1.  Both the read and the
  893. ;    read-after write use this table.  As you can see,  the write
  894. ;    and read interleaving doesn't have to be the same.
  895. ;
  896. READTAB:
  897.     DB    1,3,5,7,9,11,13,15,17,19,21,23,25
  898.     DB    2,4,6,8,10,12,14,16,18,20,22,24,26
  899.     ENDIF
  900. ;
  901. ;    This is the initialization code, and occupies the lowest area
  902. ;    of the stack, and may be clobbered by the stack during operation,
  903. ;    but it is used only once. (The stack is about 32 bytes long)
  904. ;
  905. VECTOR:
  906.     LHLD    1        ; get bottom of CBIOS
  907.     MOV    B,H
  908.     LXI    D,SECSIZ*SDLAST    ; get size of buffers
  909.     LXI    H,BUF0        ; start checking where buffer starts
  910. VECT0:
  911.     DAD    D        ; add buffer size to buffer addr
  912.     MOV    A,H
  913.     CMP    B        ; check hi order byte if high
  914.     JZ    VECT1        ; or equal
  915.     JNC    VECT1
  916.     LDA    BUFTMP        ; buffer fits, add one to count
  917.     INR    A
  918.     STA    BUFTMP        ; and store
  919.     JMP    VECT0
  920. ;
  921. ;    the stack
  922. ;
  923.     DS    8
  924. STKTOP:
  925.     DB    0
  926. ;
  927. ;    variables
  928. ;
  929. BUF0SA:                ; buffer address
  930.     DB    0,0
  931. TRKSAV:                ; track save area during read and write
  932.     DB    0
  933. BUFFCO:                ; buffer counter
  934.     DB    0
  935. CMPERR:                ; number of disk errors
  936.     DB    0
  937. TRK:                ; current track
  938.     DB    0
  939. SRCEDR:                ; source drive
  940.     IF    NOT SINGLE
  941.     DB    0
  942.     ENDIF
  943. OBJDRI:                ; destination drive
  944.     DB    0
  945. CURRDI:                ; drive for current operation
  946.     DB    0
  947. DMAAD:                ; DMA address for current operation
  948.     DB    0,0
  949. ERR1:                ; error flag (0 = error)
  950.     DB    0
  951. SECTOR:                ; sector number for current operation
  952.     DB    0
  953. ;
  954.     IF    TRSKW
  955. TSECT:
  956.     DB    0        ; skewed sector start for track
  957. TBUFF:
  958.     DB    0,0        ; skewed buffer address
  959.     ENDIF
  960. ;
  961. ;    the track buffers. BUFEND must not overlay the BIOS !
  962. ;
  963. ;    BUF1 is where the read-after-write is performed
  964. ;
  965.     IF    DOCOMP
  966. DATA1:
  967.     DS    1        ; used in compare
  968. DATA2:
  969.     DS    1
  970. BUF1:
  971.     DS    SECSIZ*SDLAST    ; space for a full track read
  972.     ENDIF
  973. ;
  974.     IF    NOT DOCOMP
  975. BUF1:
  976.     DS    SECSIZ        ; just one sector for CRC only
  977.     ENDIF
  978. ;
  979. ;    BUF0 is where all input tracks are read
  980. ;    Tho space for only one track is allocated here,
  981. ;    the program will use BUFFNU track buffers, or
  982. ;    up to the CBIOS, whichever is smaller
  983. ;
  984. BUF0:    DS    SECSIZ*SDLAST
  985. ;
  986.     ORG    BUF1
  987. ;
  988. ;    This is one-time code to initialize the branch table to
  989. ;    the CBIOS vectors. Only those vectors used are initialized.
  990. ;    Placed here so that it wont get clobbered by the stack
  991. ;
  992. VECT1:
  993.     LHLD    1        ; get warm boot address
  994.     SPHL            ; and save it in SP for DAD
  995.     LXI    H,3
  996.     DAD    SP
  997.     SHLD    CONST+1
  998. ;
  999.     LXI    H,6
  1000.     DAD    SP
  1001.     SHLD    CONIN+1
  1002. ;
  1003.     LXI    H,9
  1004.     DAD    SP
  1005.     SHLD    CONOUT+1
  1006. ;
  1007.     LXI    H,15H
  1008.     DAD    SP
  1009.     SHLD    HOME+1
  1010. ;
  1011.     LXI    H,18H
  1012.     DAD    SP
  1013.     SHLD    SELDIS+1
  1014. ;
  1015.     LXI    H,1BH
  1016.     DAD    SP
  1017.     SHLD    SETRAK+1
  1018. ;
  1019.     LXI    H,1EH
  1020.     DAD    SP
  1021.     SHLD    SETSCT+1
  1022. ;
  1023.     LXI    H,21H
  1024.     DAD    SP
  1025.     SHLD    SETDMA+1
  1026. ;
  1027.     LXI    H,24H
  1028.     DAD    SP
  1029.     SHLD    READ+1
  1030. ;
  1031.     LXI    H,27H
  1032.     DAD    SP
  1033.     SHLD    WRITE+1
  1034. ;
  1035. ;    Now check what kind of copy is wanted
  1036. ;
  1037.     LXI    SP,STKTOP    ; initial stack
  1038.     LXI    D,INIT
  1039.     CALL    PRINT        ; start program
  1040.     LHLD    TRKSRT
  1041.     LDA    FCB+1        ; get character of parameter
  1042.     ANI    5FH
  1043.     CPI    0        ; check for default
  1044.     JZ    COPYDEF
  1045.     MOV    B,A
  1046.     XRA    A        ; no track shift
  1047.     STA    SRCTRAK
  1048.     MOV    A,B
  1049.     CPI    'A'        ; check for All
  1050.     JZ    COPYALL
  1051.     CPI    'D'        ; check for Data
  1052.     JZ    COPYDAT
  1053.     CPI    'F'        ; check for First
  1054.     JZ    COPYFIR
  1055.     CPI    'L'        ; check for Last
  1056.     JZ    COPYLAS
  1057.     CPI    'O'        ; check for One
  1058.     JZ    COPYONE
  1059.     CPI    'P'        ; check for Pascal
  1060.     JZ    COPYPAS
  1061.     CPI    'S'        ; check for System
  1062.     JZ    COPYSYS
  1063.     CPI    'Z'        ; check for Zero
  1064.     JZ    COPYZER
  1065.     LXI    D,CALLERR    ; got a bad value
  1066.     CALL    PRINT
  1067.     JMP    EXITCP
  1068. COPYALL:
  1069.     MVI    H,LASTRK    ; All
  1070.     MVI    L,0
  1071.     JMP    COPYDEF
  1072. COPYDAT:
  1073.     MVI    H,LASTRK    ; Data
  1074.     MVI    L,FIRSTRK
  1075.     JMP    COPYDEF
  1076. COPYFIR:
  1077.     MVI    H,FIRSTRK+1    ; First
  1078.     MVI    L,FIRSTRK
  1079.     JMP    COPYDEF
  1080. COPYLAS:
  1081.     MVI    H,LASTRK    ; Last
  1082.     MVI    L,LASTRK-1
  1083.     JMP    COPYDEF
  1084. COPYONE:
  1085.     MVI    H,2        ; One
  1086.     MVI    L,1
  1087.     JMP    COPYDEF
  1088. COPYPAS:
  1089.     MVI    H,LASTRK    ; Pascal
  1090.     MVI    L,1
  1091.     JMP    COPYDEF
  1092. COPYSYS:
  1093.     MVI    H,FIRSTRK    ; System
  1094.     MVI    L,0
  1095.     JMP    COPYDEF
  1096. COPYZER:
  1097.     MVI    H,1        ; Zero
  1098.     MVI    L,0
  1099. ;
  1100. ;    The one time finish - up routine
  1101. ;
  1102. COPYDEF:
  1103.     SHLD    TRKSRT
  1104.     LXI    D,BGMES1    ; Now print message giving copy range
  1105.     CALL    PRINT
  1106.     LDA    TRKSRT
  1107.     CALL    PRTHEX        ; print first track
  1108.     LXI    D,BGMES2
  1109.     CALL    PRINT
  1110.     LDA    TRKSRT+1    ; print last track
  1111.     DCR    A
  1112.     CALL    PRTHEX
  1113.     LDA    BUFFNMB        ; load desired buffer number
  1114.     ORA    A
  1115.     JZ    VECT3        ; if no autosize, put in
  1116.     IF    DOCOMP
  1117.     DCR    A        ; subtract one for compare buffer
  1118.     STA    BUFFNMB
  1119.     ENDIF
  1120.     LXI    H,BUFTMP
  1121.     CMP    M        ; compare against number found
  1122.     JZ    VECT2
  1123.     JC    VECT2        ; branch if smaller
  1124.     LXI    D,BUFERR
  1125.     CALL    PRINT        ; print out error msg
  1126.     LDA    BUFTMP
  1127.     CALL    PRTHEX        ; print out buffer number
  1128. VECT3:
  1129.     LDA    BUFTMP
  1130.     STA    BUFFNMB        ; put in smaller buffer number
  1131. VECT2:
  1132.     LXI    H,REPEAT    ; go to mainline code now
  1133.     SHLD    START+1
  1134.     PCHL
  1135. ;
  1136. BUFTMP:    DB    0        ; temporary storage for buffer counter
  1137. INIT:
  1138.     DB    CR,LF,'FAST DISKETTE COPY PROGRAM, VER. 3.5$'
  1139. BUFERR:
  1140.     DB    CR,LF,'CP/M IS TOO SMALL - BUFFER SPACE REDUCED: $'
  1141. CALLERR:
  1142.     DB    CR,LF,'INVALID PARAMETER .. VALID COPYFAST PARAMETERS ARE'
  1143.     DB    CR,LF,'ALL, DATA, FIRST, LAST, ONE, PASCAL, SYSTEM, ZERO$'
  1144. BGMES1:
  1145.     DB    CR,LF,'COPYING FROM TRACK $'
  1146. BGMES2:
  1147.     DB    ' TO TRACK $'
  1148. ;
  1149. ;
  1150.     END
  1151.