home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol074 / copy21.asm < prev    next >
Encoding:
Assembly Source File  |  1984-04-29  |  18.0 KB  |  741 lines

  1. ;********************************************************
  2. ;*                            *
  3. ;*     HARDWARE DEPENDANT DISK COPY PROGRAM        *
  4. ;*     FOR MORROW DESIGNS DJ2D AND CP/M 2.X        *
  5. ;*                            *
  6. ;********************************************************
  7. ;
  8. ;    By:    Bill Bolton
  9. ;        Software Tools
  10. ;        P.O. Box 63
  11. ;        Newport Beach
  12. ;        NSW, 2106
  13. ;        AUSTRALIA
  14. ;
  15. ;    COPYRIGHT (C) 1980,1981 SOFTWARE TOOLS
  16. ;
  17. ;    ALL COMMERCIAL RIGHTS RETAINED BY AUTHOR
  18. ;
  19. ;    History:
  20. ;            All versions prior to release 2 were
  21. ;            for North Star disk systems and
  22. ;            I'd rather forget all about them
  23. ;            so dont ask !
  24. ;
  25. ;    July 16, 1980    Version 2.0 developed as a universal
  26. ;            disk copy program for CP/M 2.X, but
  27. ;            it was too slow.
  28. ;
  29. ;    July 22,1980    Version 2.10 developed as much faster
  30. ;            faster hardware dependant version
  31. ;            for DJ2D & CP/M 2.2
  32. ;
  33. ;    July 25,1980    Version 2.11 error message bugs fixed
  34. ;            and conditional assembly for system
  35. ;            density added.
  36. ;
  37. ;    August 17,1980    Version 2.12 doublesided disk routines
  38. ;            bugs fixed
  39. ;
  40. ;    Feb 10, 1981    Version 2.13 pause before error reboot added
  41. ;
  42. ;    Mar 26, 1981    Version 2.14 correctly detects two sided disks
  43. ;            with Model A Disk Jockeys
  44. ;
  45. ;    May 22, 1981    Version 2.15 clobbers incorrect format determination
  46. ;            in some circumstances due to some "undocumented
  47. ;            feature" of the DJ2D or 1791, still don't know why it
  48. ;            happens in the first place but I found a way to 
  49. ;            stop it . Also ^C abort is now correctly detected
  50. ;            immediately. FDOS$SIZE values corrected.
  51. ;
  52.     TITLE    'DJ2D Disk Copier Ver 2.15'
  53. ;
  54. TRUE    EQU    0FFFFH
  55. FALSE    EQU    NOT TRUE
  56. SINGLE    EQU    FALSE        ;Single density CP/M system with DJ2D 
  57. MODELB    EQU    FALSE        ;Model B DJ2D controller (for debugging)
  58. ;                 In practice this equate should be FALSE
  59. ;                 even for Model B DJ2Ds
  60. HARD    EQU    FALSE        ;Hard disk/floppy disk system, floppys must
  61. ;                 be drives A,B,C,D for this to work, otherwise
  62. ;                 you'll have to hack the code yourself
  63. ;
  64. DJORG    EQU    0F800H        ;DJ2D BASE ADDRESS
  65. ;
  66.     IF    SINGLE OR MODELB
  67. BASE    EQU    DJORG        ;USE ROM FIRMWARE
  68.     ELSE
  69. BASE    EQU    DJORG+400H    ;USE RAM IMAGE OF DJ FIRMWARE
  70.     ENDIF
  71. ;
  72. DJTRKSET EQU    BASE+0CH
  73. DJSETSEC EQU    BASE+0FH
  74. DJSETDMA EQU    BASE+12H
  75. DJREAD    EQU    BASE+15H
  76. DJWRITE    EQU    BASE+18H
  77. DJSELDRV EQU    BASE+1BH
  78. DJDMAST    EQU    BASE+24H
  79. DJSTATUS EQU    BASE+27H
  80. DJSETSID EQU    BASE+30H
  81. WBOOT    EQU    00000H
  82. BDOS    EQU    00005H
  83. CNTRL$C    EQU    003H        ;ASCII ETX (^C)
  84. ACR    EQU    00DH        ;ASCII CARRIAGE RETURN
  85. VERSION    EQU    12        ;BDOS VERSION NO. FUNCTION    
  86. ;
  87.     IF    SINGLE AND NOT HARD
  88. FDOS$SIZE EQU    01100H        ;SIZE OF BDOS+BIOS
  89.     ENDIF
  90.     IF    NOT SINGLE AND NOT HARD
  91. FDOS$SIZE EQU    01400H        ;SIZE OF BDOS+BIOS
  92.     ENDIF
  93.     IF    HARD AND NOT SINGLE
  94. FDOS$SIZE EQU    01700H        ;SIZE OF BDOS+BIOS
  95.     ENDIF
  96. ;
  97.     ORG    0100H
  98. ;
  99.     MACLIB    MACRO3        ;SOFTWARE TOOLS SPECIAL MACROS
  100. ;
  101. BEGIN:
  102.     MVI    C,VERSION
  103.     CALL    BDOS        ;GET CP/M VERSION NO.
  104.     MOV    A,L
  105.     SUI    022H        ;VERSION 2.2 OR LATER?
  106.     JM    WRONG$VERSION    ;NO
  107.     LXI    H,BASE        ;POINT TO ADDRESS OF FIRMWARE
  108.     MOV    A,M        ;GET FIRST BYTE OF FIRMWARE
  109.     CPI    0C3H        ;IS IT A 'JMP' INSTRUCTION
  110.     JNZ    WRONG$VERSION    ;NO
  111.     LXI    SP,STACK$TOP    ;YES, SET UP STACK
  112.     IF    SINGLE
  113.     PRINT    <CR,LF,'COPY - Ver 2.15 (1D)',CR,LF>
  114.     ELSE
  115.     PRINT    <CR,LF,'COPY - Ver 2.15 (2D)',CR,LF>
  116.     ENDIF
  117.     PRINT    <'Copyright (C) 1980/81 - Bill Bolton, Software Tools',CR,LF>
  118.     PRINT    <'For Morrow Designs Disk Jockey 2D and CP/M 2.2',CR,LF,LF>
  119.     PRINT    'BOTH Source and Destination MUST be the same format'
  120. ;
  121. MENU:
  122.     PRINT    <CR,LF,LF,'  *****  O P T I O N S  *****'>
  123.     PRINT    <CR,LF,LF>
  124.     PRINT    '  "A" = Copy ALL '
  125.     DECOUT    TRACKS
  126.     PRINT    <' tracks',CR,LF>
  127.     PRINT    '  "M" = Copy all tracks UNTIL '
  128.     PRINT    <'0E5H track',CR,LF>
  129.     PRINT    <'  "O" = Copy ONLY CP/M system tracks',CR,LF>
  130.     PRINT    <'  "F" = Copy FILES to end of disk',CR,LF>
  131.     PRINT    <'  "N" = Copy files UNTIL 0E5H track',CR,LF>
  132.     PRINT    '  "E" = EXIT to CP/M (FIRST insert system disk)'
  133.     PRINT    <CR,LF,LF,'Enter your selection - '>
  134. ;
  135.     CALL    GET$CONSOLE        ;GET CONSOLE INPUT
  136.     STA    COMMAND            ;SAVE FOR LATER
  137.     LXI    H,TRACKS        ;GET NUMBER OF TRACKS
  138.     MOV    H,M            ;H <--- MAX NO. TRACKS
  139.     MVI    L,0            ;L <--- TRACK 0 TO START
  140.     CPI    'A'
  141.     JZ    SELECT$DRIVES
  142.     CPI    'M'
  143.     JZ    SELECT$DRIVES
  144.     LXI    H,0200H            ;H <--- TRACK 2
  145.     CPI    'O'            ;L <--- TRACK 0 TO START
  146.     JZ    SELECT$DRIVES
  147.     LXI    H,TRACKS
  148.     MOV    H,M            ;H <--- MAX NO. TRACKS
  149.     MVI    L,2            ;L <--- TRACK 2 TO START
  150.     CPI    'F'
  151.     JZ    SELECT$DRIVES
  152.     CPI    'N'
  153.     JZ    SELECT$DRIVES
  154.     CPI    'E'
  155.     JZ    WBOOT
  156.     PRINT    <CR,LF,BEL,'Illegal selection - try again.'>
  157.     JMP    MENU
  158. ;
  159. SELECT$DRIVES:
  160.     SHLD    START$TRACK    ;L= TRACK TO START
  161.                 ;H= LAST TRACK TO COPY
  162. SOURCE$DRIVE:
  163.     PRINT    <CR,LF,'Enter SOURCE drive (A, B, C or D)'>
  164.     PRINT    <CR,LF,'    ( CR copies from A to B ) - '>
  165. ;
  166.     CALL    GET$CONSOLE    ;GET CONSOLE INPUT
  167.     CPI    ACR
  168.     JZ    DEFAULT
  169.     ANI    05FH        ;MAKE INTO UPPER CASE
  170.     STA    SOURCE
  171.     SUI    'A'        ;SUBTRACT ASCII OFFSET
  172.     CPI    4        ;GREATER THAN 4?
  173.     JNC    SOURCE$DRIVE    ;YES, TRY AGAIN
  174. DEST$DRIVE:
  175.     PRINT    <CR,LF,'Enter DESTINATION drive (A, B, C or D) - '>
  176.     CALL    GET$CONSOLE    ;GET CONSOLE INPUT
  177.     STA    DEST
  178.     SUI    'A'        ;REMOVE ASCII OFFSET
  179.     CPI    4
  180.     JNC    DEST$DRIVE
  181. COMMENCE:
  182.     LXI    SP,STACK$TOP    ;RESET STACK
  183.     PRINT    <CR,LF,'Insert SOURCE in '>
  184.     CHAROUT    SOURCE
  185.     PRINT    <', DEST in '>
  186.     CHAROUT DEST
  187.     PRINT    <' and press RETURN to copy.',CR,LF>
  188.     PRINT    <'   (Press any other key to reset options) - '>
  189.     CALL    GET$CONSOLE    ;GET CONSOLE INPUT
  190.     CPI    ACR        ;IS IT A 'RETURN'
  191.     JNZ    MENU        ;NO, DISPLAY THE MENU
  192.     LDA    START$TRACK
  193.     STA    CURRENT$TRACK
  194.     DISKIO    INITIAL        ;RESET THE DISK SYSTEM
  195.     LDA    SOURCE        ;GET SOURCE DRIVE NO.
  196.     SUI    'A'        ;SUBTRACT ASCII OFFSET
  197.     MVI    B,0
  198.     MOV    C,A        ;BC  <--- DRIVE NO.
  199.     CALL    DJSELDRV
  200.     MVI    C,1
  201.     CALL    DJTRKSET
  202.     MVI    C,1        ;SET UP SECTOR FOR READ
  203.     CALL    DJSETSEC
  204.     LXI    B,STACK$TOP+1    ;GET FIRST FREE MEMORY LOC.
  205.     CALL    DJSETDMA
  206.     CALL    DJREAD        ;FIRST TIME CLEARS ?????? ON DJ2D
  207.     CALL    DJSTATUS    ;DITTO    
  208.     CALL    DJREAD        ;THIS TIME ITS FOR REAL
  209. STATUS1:
  210.     CALL    DJSTATUS    ;GET DISK DATA
  211.     ANI    0FCH        ;DISCARD DRIVE NO. BITS
  212.     MOV    C,A        ;C <--- STATUS
  213.     LDA    DJORG+3FAH    ;GET DJ2D 1791 STATUS
  214.     ANI    8        ;MASK OUT SIDE BIT
  215.     XRI    8        ;COMPLEMENT IT
  216.     RLC            ;INTO BIT 4
  217.     RLC            ;INTO BIT 5
  218.     ORA    C        ;MERGE WITH PREVIOUS STATUS
  219.     PUSH    PSW        ;TEMP SAVE SOURCE DISK DATA (TO BE POPPED AS B)
  220.     LDA    DEST        ;GET DESTINATION DRIVE NO.
  221.     SUI    'A'        ;REMOVE ASCII OFFSET    
  222.     MOV    C,A
  223.     CALL DJSELDRV
  224.     MVI    C,1        ;SET UP TRACK FOR READ
  225.     CALL    DJTRKSET
  226.     MVI    C,1        ;SET UP SECTOR FOR READ
  227.     CALL    DJSETSEC
  228.     CALL    DJREAD        ;FIRST TIME CLEARS ?????? ON DJ2D
  229.     CALL    DJSTATUS    ;DITTO    
  230.     CALL    DJREAD        ;THIS TIME ITS FOR REAL
  231. STATUS2:
  232.     CALL    DJSTATUS    ;GET DISK DATA
  233.     ANI    0FCH        ;DISCARD DRIVE NO. BITS
  234.     MOV    C,A        ;C <--- STATUS
  235.     LDA    DJORG+3FAH    ;GET DJ2D 1791 STATUS
  236.     ANI    8        ;MASK OUT SIDE BIT
  237.     XRI    8        ;COMPLEMENT IT
  238.     RLC            ;INTO BIT 4
  239.     RLC            ;INTO BIT 5
  240.     ORA    C        ;MERGE WITH PREVIOUS STATUS
  241.     POP    B        ;RESTORE SOURCE DISK DATA (PUSHED AS PSW)
  242. STATUS$CHECK:
  243.     CMP    B        ;DISK DATA SAME FOR BOTH DRIVES?
  244.     JNZ    FORMAT$ERROR    ;NO, ERROR
  245.     ANI    00CH        ;MASK OUT SECTOR SIZE BITS
  246.     STA    SEC$BITS
  247.     MOV    A,B        ;A <--- DISK DATA
  248.     ANI    020H        ;MASK OUT SIDE BIT
  249.     CNZ    MERGE        ;MERGE SIDE BITS WITH SECTOR BITS
  250.     LDA    SEC$BITS
  251.     LXI    H,SECTOR$LENGTH$TB
  252.     MVI    D,0        ;FORM OFFSET
  253.     MOV    E,A
  254.     DAD    D        ;ADD OFFSET
  255.     MOV    E,M        ;GET LOW BYTE OF SEC$LENGTH
  256.     INX    H
  257.     MOV    D,M        ;GET HIGH BYTE OF SEC$LENGTH
  258.     INX    H
  259.     MOV    A,M        ;GET LOW BYTE OF SPT
  260.     INX    H
  261.     MOV    H,M        ;GET HIGH BYTE OF SPT
  262.     MOV    L,A        ;FORM VALUE
  263.     SHLD    SPT        ;SAVE SECTORS/TRACK
  264.     SDED    SEC$LENGTH    ;SAVE SECTOR LENGTH
  265.     LXI    H,0
  266. SIZE$LOOP:
  267.     DAD    D        ;ADD 1 SECTOR LENGTH
  268.     DCR    A        ;ADJUST SECTOR COUNT
  269.     JNZ    SIZE$LOOP
  270.     SHLD    BUFFER$SIZE
  271.     XCHG            ;DE <--- BUFFER SIZE
  272.     LXI    H,STACK$TOP+1    ;GET FIRST FREE MEMORY LOC.
  273.     SHLD    TRACK$BUFFER
  274.     DAD    D        ;FORM ADDRESS OF VERIFY BUFFER
  275.     SHLD    VERIFY$BUFFER    
  276.     DAD    D        ;FORM ADDRESS OF TOP OF BUFFER
  277.     SHLD    BUFFER$TOP
  278.     XCHG            ;DE <--- BUFFER TOP
  279.     LHLD    BDOS+1        ;GET BDOS BASE ADDRESS
  280.     DSUB            ;ENOUGH MEMORY FOR BUFFERS?
  281.     JC    OUT$OF$MEMORY    ;NO, ERROR
  282.     LDA    SEC$BITS    ;YES, GET DISK DATA
  283.     ANI    010H        ;MASK OUT DOUBLE SIDED BIT
  284.     JZ    SIDE$FLAG
  285.     LDA    SPT        ;GET SECTORS/TRACK
  286.     RRC            ;DIVIDE BY 2
  287.     PUSH    PSW
  288.     ORI    080H        ;SET SIDE 1 BIT
  289.     STA    SPT        ;SAVE NEW LAST SECTOR NO.
  290.     POP    PSW
  291.     INR    A
  292.  
  293. SIDE$FLAG:
  294.     STA    SIDE$ONE    ;SIDE CHANGE SECTOR NO.
  295.     PRINT    <CR,LF,LF,'Copy in progress - '>
  296.     PRINT    <'Control C to abort',CR,LF>
  297.     CALL    COPY        ;DO THE COPY
  298.     PRINT    <CR,LF,'Copy complete - '>
  299.     LDA    ERRORS        ;CHECK FOR ERRORS
  300.     ORA    A
  301.     JNZ    ERROR$MESSG
  302.     PRINT    <'NO errors were detected.'>
  303.     JMP    COPY$AGAIN
  304. ;
  305. MERGE:
  306.     RRC            ;ROTATE SIDE BIT INTO POSITION
  307.     MOV    B,A        ;B <--- SIDE BIT
  308.     LDA    SEC$BITS    ;GET SECTOR BITS
  309.     ORA    B        ;MERGE THEM
  310.     STA    SEC$BITS    ;KEEP STACK RIGHT
  311.     RET
  312. ;
  313. ERROR$MESSG:
  314.     PRINT    <'Errors detected. *** ERRORS ***',BEL>
  315. ;
  316. COPY$AGAIN:
  317.     PRINT    <CR,LF,LF,'Press RETURN to copy again or'>
  318.     PRINT    <CR,LF,'any other key to reset options. - '>
  319.     CALL    GET$CONSOLE    ;GET CONSOLE INPUT
  320.     CPI    ACR
  321.     JZ    COMMENCE
  322.     JMP    MENU
  323. ;
  324. FORMAT$ERROR:
  325.     PRINT    <CR,LF,LF,BEL>
  326.     PRINT    'Destination disk is NOT the same'
  327.     PRINT    <' format as Source disk.',CR,LF>
  328.     PRINT    'BOTH disks MUST be the same format.'
  329.     PRINT    <CR,LF,LF,'Press any key to reset options. - '>
  330.     CALL    GET$CONSOLE
  331.     JMP    MENU
  332. ;
  333. DEFAULT:
  334.     MVI    A,'A'        ;DEFAULT TO A DRIVE
  335.     STA    SOURCE
  336.     INR    A        ;  AND B DRIVE
  337.     STA    DEST
  338.     JMP    COMMENCE
  339. ;
  340. COPY:
  341.     XRA    A        ;RESET ERROR FLAG
  342.     STA    ERRORS
  343.     CALL    FIRST$TIME    ;INITIALISE TRACK PARAMETERS
  344. COPY$LOOP:
  345.     CALL    ABORT$CHECK    ;WANT TO QUIT?
  346.     LDA    SOURCE        ;GET SOURCE DRIVE NO.
  347.     SUI    'A'        ;REMOVE ASCII OFFSET
  348.     CALL    SETUP$TRACK    ;SET UP INITIAL PARAMETERS
  349.     LHLD    TRACK$BUFFER
  350.     CALL    READ$A$TRACK
  351.     CALL    CHECK$EMPTY    ;CHECK IF E5 TRACK
  352.     RC            ;CARRY SET IF E5 TRACK
  353.     CALL    ABORT$CHECK    ;CHECK FOR QUIT BEFORE BDOS SWALLOWS ANY
  354.                 ; WAITING CHARACTER DURING CONSOLE OUTPUT
  355.     PRINT    '*'        ;DISPLAY TRACK DONE MARKER
  356.     MVI    A,5        ;NUMBER OF RETRIES
  357.     STA    RETRIES
  358. TRY$WRITE:
  359.     LXI    H,RETRIES    ;GET REMAINING RETRIES
  360.     DCR    M        ;ADJUST IT
  361.     JM    LAST$TRY
  362.     LDA    DEST        ;GET DESTINATION DRIVE NO.
  363.     SUI    'A'        ;REMOVE ASCII OFFSET
  364.     CALL    SETUP$TRACK
  365.     LHLD    TRACK$BUFFER
  366.     CALL    WRITE$A$TRACK
  367.     LDA    DEST        ;GET DESTINATION DRIVE IDENT
  368.     SUI    'A'        ;REMOVE ASCII OFFSET
  369.     CALL    SETUP$TRACK
  370.     LHLD    VERIFY$BUFFER
  371.     CALL    READ$A$TRACK
  372.     CALL    VERIFY
  373.     JC    TRY$WRITE    ;CARRY SET MEANS RETRY
  374. LAST$TRY:
  375.     LXI    H,CURRENT$TRACK
  376.     INR    M        ;ADJUST IT
  377.     LDA    LAST$TRACK
  378.     CMP    M        ;LAST TRACK?
  379.     JNZ    COPY$LOOP    ;NO, COPY ANOTHER
  380.     RET
  381. ;
  382. READ$A$TRACK:
  383.     LXI    B,1        ;SET START SECTOR NO.
  384. READ$TRACK:
  385.     PUSH    B        ;SAVE START SECTOR NO.
  386.     PUSH    H        ;SAVE CURRENT DMA ADDRESS
  387.     MVI    A,1FH
  388.     ANA    C        ;MASK OF HIGH BITS
  389.     MOV    C,A        ;C <--- MASKED SECTOR
  390.     CALL    DJSETSEC    ;SET THE SECTOR
  391.     POP    B        ;BC <--- DMA ADDRESS
  392.     PUSH    B        ;SAVE IT AGAIN
  393.     CALL    DJSETDMA
  394.     MVI    B,5        ;RETRY COUNT
  395. READ$RETRY:
  396.     DCR    B
  397.     JM    READ$PARAM    ;FINISHED RETRIES?
  398.     PUSH    B        ;NO, SAVE COUNT
  399.     CALL    DJREAD        ;READ A SECTOR
  400.     POP    B        ;RESTORE RETRY COUNT
  401.     JC    READ$RETRY    ;READ ERROR, TRY AGAIN
  402. READ$PARAM:
  403.     POP    H        ;GET CURENT DMA ADDRESS
  404.     LDED    SEC$SIZE    ;GET SECTOR LENGTH
  405.     DAD    D        ;FORM NEW DMA ADDRESS
  406.     POP    B        ;GET SECTOR NO. 
  407.     CNZ    READ$ERROR    ;READ ERROR MESSAGE
  408.     INX    B        ;ADJUST SECTOR NO.
  409.     LDA    SECTORS        ;GET MAX NO SECTORS
  410.     INR    A
  411.     CMP    C        ;DONE LAST SECTOR
  412.     RZ            ;YES
  413.     LDA    OTHER$SIDE
  414.     CMP    C        ;TIME TO CHANGE SIDES?
  415.     JNZ    READ$TRACK    ;NO, DO ANOTHER SECTOR
  416.     MVI    C,1
  417.     CALL    DJSETSID    ;SELECT SIDE 1
  418.     LXI    B,081H        ;SET SECTOR 1 ON SIDE 1
  419.     JMP    READ$TRACK
  420. ;
  421. CHECK$EMPTY:
  422.     LDA    COMMAND        ;GET CURRENT COMMAND
  423.     CPI    'N'        ;FILES UNTIL E5 TRACK?
  424.     JZ    SETUP$E5    ;YES, TEST FOR EMPTY TRACK
  425.     CPI    'M'        ;ALL UNTIL E5 TRACK?
  426.     JNZ    RESET$CARRY    ;NO,FORCE COPY TILL END
  427. SETUP$E5:
  428.     LDA    CURRENT$TRACK    ;TRACK NUMBER
  429.     CPI    2        ;DON'T TEST TRACKS 0 & 1
  430.     JC    RESET$CARRY    ;RESET CARRY FLAG
  431.     LHLD    BUFFER$SIZE
  432.     PUSH    H
  433.     POP    B        ;BC <--- NO BYTES TO CHECK
  434.     LHLD    TRACK$BUFFER
  435. TEST$E5:
  436.     MOV    A,M        ;GET A BYTE FROM TRACK BUFFER
  437.     CPI    0E5H        ;DATA FILLER?
  438.     JNZ    RESET$CARRY    ;RESET FLAG
  439.     INX    H        ;POINT TO NEXT BYTE
  440.     DCX    B        ;ADJUST CONTROL COUNTER
  441.     MOV    A,B        ;FINISHED LOOP YET?
  442.     ORA    C
  443.     JNZ    TEST$E5        ;NO, DO IT AGAIN
  444.     STC            ;SET CARRY AS A FLAG
  445.     RET
  446. ;
  447. RESET$CARRY:
  448.     STC            ;DEFINE CARRY STATUS
  449.     CMC            ;COMPLEMENT IT
  450.     RET
  451. ;
  452. WRITE$A$TRACK:
  453.     LXI    B,1        ;SET UP SECTOR NO.
  454. WRITE$TRACK:
  455.     PUSH    B        ;SAVE SECTOR NO.
  456.     PUSH    H        ;SAVE DMA ADDRESS
  457.     MVI    A,1FH        ;1AH IS MAX NO. SECTORS ON ANY FORMAT
  458.     ANA    C        ;MASK OF HIGH BITS
  459.     MOV    C,A        ;C <--- MASKED SECTOR
  460.     CALL    DJSETSEC    ;NEXT SECTOR TO WRITE
  461.     POP    B        ;BC <--- DMA ADDRESS
  462.     PUSH    B        ;SAVE IT AGAIN
  463.     CALL    DJSETDMA    ;NEXT ADDRESS TO WRITE FROM
  464.     MVI    B,5        ;RETRY COUNTER
  465. WRITE$RETRY:
  466.     DCR    B        ;ADJUST RETRY COUNT
  467.     JM    WRITE$PARAM    ;FINISHED RETRIES?
  468.     PUSH    B        ;SAVE RETRY COUNT
  469.     CALL    DJWRITE        ;WRITE THE SECTOR
  470.     POP    B        ;RESTORE RETRY COUNT
  471.     JC    WRITE$RETRY    ;YES, TRY AGAIN
  472. WRITE$PARAM:
  473.     POP    H        ;GET CURRENT DMA ADDRESS
  474.     LDED    SEC$SIZE    ;GET SECTOR LENGTH
  475.     DAD    D        ;FORM NEW DMA ADDRESS
  476.     POP    B        ;GET LAST SECTOR DONE NO.
  477.     CNZ    WRITE$ERROR    ;MESSAGE IF WRITE ERROR
  478.     INX    B        ;ADJUST SECTOR NO.
  479.     LDA    SECTORS        ;GET MAX NO. SECTORS
  480.     INR    A
  481.     CMP    C        ;DONE LAST SECTOR?
  482.     RZ            ;YES
  483.     LDA    OTHER$SIDE
  484.     CMP    C        ;TIME TO CHANGE SIDES?
  485.     JNZ    WRITE$TRACK    ;NO, DO ANOTHER SECTOR
  486.     MVI    C,1
  487.     CALL    DJSETSID    ;SELECT SIDE 1
  488.     LXI    B,081H        ;SET SECTOR 1 ON SIDE 1
  489.     JMP    WRITE$TRACK
  490. ;
  491. SETUP$TRACK:
  492.     STA    DRIVE$NO    ;SAVE DRIVE NO.
  493.     MOV    C,A
  494.     CALL    DJSELDRV    ;SELECT THE DRIVE
  495.     LDA    CURRENT$TRACK
  496.     MOV    C,A
  497.     CALL    DJTRKSET    ;SET THE TRACK
  498.     LXI    B,0
  499.     CALL    DJSETSID    ;SET THE SIDE
  500.     LDA    CURRENT$TRACK
  501.     ORA    A        ;TRACK 0?
  502.     JZ    TRACK$0
  503.     CPI    1        ;TRACK 1?
  504.     RNZ            ;NO
  505.                 ;YES, RESET PARAMETERS
  506. FIRST$TIME:
  507.     LHLD    SPT        ;SECTORS/TRACK
  508.     SHLD    SECTORS
  509.     LHLD    SEC$LENGTH    ;BYTES/SECTOR
  510.     SHLD    SEC$SIZE
  511.     LDA    SIDE$ONE    ;SECTOR NO. TO CHANGE SIDES
  512.     STA    OTHER$SIDE
  513.     RET
  514. ;
  515. TRACK$0:
  516.     LXI    H,26        ;26 SECTORS/TRACK
  517.     SHLD    SECTORS
  518.     LXI    H,128        ;128 BYTES/SECTOR
  519.     SHLD    SEC$SIZE
  520.     MVI    A,0        ;FORCE SINGLE SIDED
  521.     STA    OTHER$SIDE
  522.     RET
  523. ;
  524. VERIFY:
  525.     XRA    A
  526.     STA    ESECTOR        ;RESET ERROR SECTOR
  527.     LHLD    TRACK$BUFFER    ;POINT TO BASE OF DATA WRITTEN
  528.     LDED    VERIFY$BUFFER    ;POINT TO BASE OF DATA READ
  529.     LDA    CURRENT$TRACK
  530.     ORA    A        ;TRACK 0?
  531.     LXI    B,26*128    ;TRACK 0 PARAMETERS ARE FIXED
  532.     JZ    SINGLE2        ;YES
  533.     PUSH    H
  534.     LHLD    BUFFER$SIZE
  535.     PUSH    H
  536.     POP    B        ;BC <--- NO. OF BYTES TO CHECK:
  537.     POP    H
  538. SINGLE2:
  539.     LDAX    D        ;GET A WRITTEN BYTE 
  540.     CMP    M        ;GET A READ BYTE
  541.     JZ    NEXT$COMPARE    ;IF THE SAME GET NEXT PAIR
  542.     LDA    RETRIES        ;GET NO RETRIES LEFT
  543.     ORA    A        ;ANY LEFT?
  544.     STC            ;SET CARRY AS RETRY FLAG
  545.     RNZ            ;YES, RETRY TRACK
  546.     CALL    COMPARE$ERROR    ;NO, HARD ERROR
  547. NEXT$COMPARE:
  548.     INX    H        ;POINT TO NEXT WRITTEN BYTE
  549.     INX    D        ;POINT TO NEXT READ BYTE
  550.     DCX    B        ;ADJUST NUMBER DONE COUNT
  551.     MOV    A,C        ;FINISHED?
  552.     ORA    B
  553.     JNZ    SINGLE2        ;NO, COMPARE BYTES
  554.     RET
  555. ;
  556. COMPARE$ERROR:
  557.     PUSH    H        ;SAVE WRITTEN DATA LOC.
  558.     PUSH    D        ;SAVE READ DATA LOC.
  559.     MVI    A,0
  560.     STA    SECTOR$COUNT
  561. SECTOR$LOOP:
  562.     LDED    SEC$SIZE    ;NO. BYTES IN A SECTOR
  563.     DSUB            ;SUBTRACT SECTOR FROM ERROR LOC.
  564.     LDA    SECTOR$COUNT
  565.     INR    A        ;ADJUST SECTOR COUNT
  566.     STA    SECTOR$COUNT
  567.     LDED    TRACK$BUFFER
  568.     CPHL            ;COMPARE TO BASE OF BUFFER
  569.     JNC    SECTOR$LOOP    ;FINISHED WHEN GONE MINUS
  570.     LDA    SECTOR$COUNT
  571.     MOV    C,A        ;BC <--- SECTOR NO.
  572.     MVI    B,0
  573.     PUSH    B        ;SAVE ERROR SECTOR
  574.     PRINT    <CR,LF,'Compare'>
  575.     JMP    ERROR$END
  576. ;
  577. READ$ERROR:
  578.     SAVE    H,D,B
  579.     PRINT    <CR,LF,'Read'>
  580.     JMP    ERROR$END
  581. ;
  582. WRITE$ERROR:
  583.     SAVE    H,D,B
  584.     PRINT    <CR,LF,'Write'>
  585. ;
  586. ERROR$END:
  587.     PRINT    ' error at Track '
  588.     DECOUT    CURRENT$TRACK
  589.     PRINT    ', Physical Sector '
  590.     POP    H        ;HL <--- SECTOR NO.
  591.     PUSH    H        ;SAVE IT AGAIN
  592.     MOV    A,L        ;A <--- SECTOR NO.
  593.     ANI    080H        ;MASK OUT DOUBLE SIDED BIT
  594.     JZ    ONE$SIDE
  595.     LDA    SIDE$ONE    ;GET SECTORS ON (SIDE 0) + 1
  596.     DCR    A        ;NO. SECTORS ON SIDE ZERO
  597.     ADD    L        ;A <--- NO. OF BAD SECTOR
  598.     ANI    07FH        ;MASK OFF BIT 7
  599.     MOV    L,A        ;HL <--- NO BAD SECTOR
  600. ONE$SIDE:
  601.     DECOUT
  602.     PRINT    ', on Drive '
  603.     LDA    DRIVE$NO
  604.     ADI    'A'
  605.     CHAROUT
  606.     PRINT    <BEL,' '>
  607.     MVI    A,0FFH        ;SET ERROR FLAG
  608.     STA    ERRORS
  609.     CALL    ABORT$CHECK
  610. NO$ERROR:
  611.     RESTORE    B,D,H
  612.     RET
  613. ;
  614. GET$CONSOLE:
  615.     CHARIN            ;GET A CHARACTER
  616.     CPI    'B'        ;MAKE INTO UPPER CASE
  617.     RC
  618.     CPI    '{'
  619.     RNC
  620.     ANI    '_'
  621.     RET
  622. ;
  623. ABORT$CHECK:
  624.     CALLBIOS DSTAT        ;CHECK IF KEY PRESSED
  625.     ORA    A
  626.     RZ
  627.     CALLBIOS DCONIN
  628.     CPI    CNTRL$C
  629.     RNZ
  630.     PRINT    <CR,LF,BEL,'^C ABORT'>
  631.     CHARSTAT        ;SEE IF ^C GOT INTO BDOS
  632.     JZ    MENU        ;NO
  633.     CHARIN            ;YES, DISCARD IT
  634.     JMP    MENU
  635. ;
  636.     
  637. OUT$OF$MEMORY:
  638.     PRINT    <BEL,CR,LF,LF,'               TRACK BUFFER OVERFLOW',CR,LF,LF>
  639.     PRINT    <'Your present CP/M system does not have enough memory'>
  640.     PRINT    <CR,LF,'in the Transient Program Area for copying disks'>
  641.     PRINT    <CR,LF,'in the format you are trying to copy.'>
  642.     PRINT    <BEL,CR,LF,LF,'You need at least a '>
  643.     LHLD    BUFFER$TOP    ;GET SIZE OF BUFFERS
  644.     LXI    D,FDOS$SIZE    ;GET SIZE OF BDOS+BIOS
  645.     DAD    D        ;MINIMUM SYSTEM SIZE IN BYTES
  646.     MOV    A,H        ;GET PAGE NO.
  647.     RRC            ;DIVIDE BY 4 TO GET KBYTES
  648.     RRC
  649.     ANI    03FH
  650.     INR    A        ;ADD AN EXTRA KBYTE
  651.     MVI    H,0
  652.     MOV    L,A
  653.     DECOUT            ;DISPLAY THE SYSTEM SIZE
  654.     PRINT    <'K system to copy this disk.'>
  655.     PRINT    <CR,LF,LF,'Insert a disk which has DJ2D CP/M system on it'>
  656.     PRINT    <CR,LF,'into the A: drive, then press any key to exit to CP/M'>
  657. WAITLP:
  658.     DIRIN            ;SET UP FOR DIRECT CONSOLE READ
  659.     ORA    A        ;ANY KEY PRESSED?
  660.     JZ    WAITLP        ;NO, WAIT UNTIL ONE IS PRESSED    
  661.     PRINT    <CR,LF,LF,'Warm booting CP/M'>
  662.     JMP    WBOOT
  663. ;
  664. WRONG$VERSION:
  665.     PRINT    <'Sorry, you need CP/M Version 2.2 or later',CR,LF>
  666.     PRINT    <'and a Morrow Designs Disk Jockey 2D Controller'>
  667.     PRINT    <CR,LF,'to run this disk copy utility.'>
  668.     RET            ;BACK TO CP/M
  669. ;
  670. SECTOR$LENGTH$TB:
  671.     DW    128        ;1S/1D/128
  672.     DW    26
  673.     DW    256        ;1S/2D/256
  674.     DW    26
  675.     DW    512        ;1S/2D/512
  676.     DW    15
  677.     DW    1024        ;1S/2D/1024
  678.     DW    8
  679.     DW    128        ;2S/1D/128
  680.     DW    52
  681.     DW    256        ;2S/2D/256
  682.     DW    52
  683.     DW    512        ;2S/2D/512
  684.     DW    30
  685.     DW    1024        ;2S/2D/1024
  686.     DW    16
  687. ;
  688. CURRENT$TRACK:
  689.     DW    0
  690. START$TRACK:
  691.     DB    0
  692. LAST$TRACK:
  693.     DB    0
  694. ESECTOR:
  695.     DB    0
  696. SECTOR$COUNT:
  697.     DB    0
  698. ERRORS:    DB    0
  699. RETRIES:
  700.     DB    0
  701. DRIVE$NO:
  702.     DB    0
  703. COMMAND:
  704.     DB    0
  705. SIDE$ONE:
  706.     DB    0        ;1ST SECTOR ON SIDE ONE + 1
  707. OTHER$SIDE:
  708.     DB    0        ;SECTOR NO. TO CHANGE SIDES
  709. SEC$BITS:
  710.     DB    0        ;SECTOR SIZE BITS
  711. SEC$LENGTH:
  712.     DW    00        ;FORMATED BYTES/SECTOR
  713. SEC$SIZE:
  714.     DW    00        ;SEC$LENGTH
  715. TRACKS:    DW    77        ;NO TRACKS PER DISK
  716. SOURCE:    DW    00
  717. DEST:    DW    00
  718. BADSEC:    DW    00
  719. SPT:    DW    00        ;FORMATTED SECTORS/TRACK
  720. SECTORS:
  721.     DW    00        ;SECTORS/TRACK
  722. BUFFER$SIZE:
  723.     DW    00
  724. TRACK$BUFFER:
  725.     DW    00        ;LOCATION OF TRACK BUFFER
  726. VERIFY$BUFFER:
  727.     DW    00        ;LOCATION OF VERIFY BUFFER
  728. BUFFER$TOP:
  729.     DW    00        ;LOCATION OF TOP OF BUFFERS
  730. ;
  731. ; AN INITIALISED STACK MAKES DEBUGGING EASIER
  732. ;
  733.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  734.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  735.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  736.     DB    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 
  737. ;
  738. STACK$TOP    EQU    $
  739. ;
  740.     END    BEGIN
  741.