;
;               MOVE.ASM
;                 V2.1
;          (revised 6/12/80)
;
;USED TO TRANSFER FILES FROM ONE DISK TO ANOTHER
;ON A 1 DISK SYSTEM, BY READING THE FILE INTO MEMORY.
;ISSUES ERROR MSG IF FILE WON'T FIT. ALSO USEFUL FOR
;TRANSFERRING ONE FILE TO MULTIPLE DISKS. WORKS WITH
;ANY DRIVE - A, B, C, OR D.
;
;***************************************************
;* NOTE: CHECK COMMENTS AT LABEL 'EXIT:' REGARDING *
;*       REBOOT WHEN EXITING THIS PROGRAM.         *
;***************************************************
;
;07/23/78 ORIGINALLY WRITTEN BY WARD CHRISTENSEN
;10/20/78 MODIFY TO WRITE MULTIPLE TIMES
;       (FOR EXAMPLE TO MOVE STAT.COM TO 5 NEW DISKS)
;02/24/79 MODIFY TO STORE TO EITHER A: OR B:, AS
;       MOVE IS MUCH QUICKER THAN PIP FOR PEOPLE
;       WITH 2 DRIVE SYSTEMS.
;05/27/79 MODIFY TO CHECK FOR NO FILE NAME AND TO
;       ZERO OUT DISK NAME SO IT WON'T OVERULE THIS
;       PROGRAM.  BY KEITH PETERSEN, W8SDZ.
;08/19/79 REMOVE MACROS TO ALLOW ASSEMBLY WITH
;       ASM.COM. ADD CONDITIONAL ASSEMBLY FOR CP/M
;       ON H8 OR TRS-80.  (KBP)
;08/20/79 FIX TEST TO PROTECT BDOS (WAS WRONG WHEN
;       ALTCPM OPTION CHOSEN).  (KBP).
;11/27/79 FIX DMA PROBLEM FOR MULTIPLE WRITES.
;       ELIMINATE EXTRA PUSH-POPS. (KBP).
;12/04/79 FIX ERROR IN RESETTING DMA TO NORMAL
;       (Thanks to Ward Christensen) (KBP)
;04/20/80 MODIFIED TO WORK WITH EITHER CP/M 1.4 OR CP/M-2.
;       EARLIER VERSION COPIED FILE ATTRIBUTES WHICH PREVENTED
;       MOVING R/O FILES AND MADE CP/M-2 FILES INACCESSABLE
;       UNDER 1.4. (KBP)
;06/12/80 MODIFIED TO REMOVE ATTRIBUTES ON ALL 11 CHARACTERS
;       OF FCB NAME. (KBP)
;
STDCPM  EQU     1       ;TRUE FOR STANDARD CP/M
ALTCPM  EQU     0       ;TRUE FOR H8 OR TRS-80
;
BASE    SET     0
;
       IF      ALTCPM  ;H8 OR TRS-80
BASE    SET     4200H
       ENDIF           ;ALTCPM
;
CR      EQU     0DH     ;CARRIAGE RETURN
LF      EQU     0AH     ;LINE FEED
;
       ORG     BASE+100H
;
START   LDA     FCB+1   ;SEE IF FILE NAME THERE
       CPI     ' '     ;NONE?
       RZ              ;IF NONE, RETURN TO CP/M
       LXI     SP,STACK
       XRA     A       ;ZERO DISK NAME SO IT WON'T
       STA     FCB     ;OVERULE COMMANDS IN THIS PGM.
       CALL    ILPRT
       DB      'MOVE.COM V2.1, 6/12/80'
       DB      CR,LF,0
;
SRCMSG  CALL    ILPRT
       DB      'MOUNT SOURCE DISK, TYPE: A, B, C, OR D ',0
       CALL    GETDISK ;GET DISK NAME
       JC      SRCMSG  ;INVALID ANSWER, ASK AGAIN
;
;GOT DISK, OPEN THE INPUT FILE
;
       LXI     D,FCB
       MVI     C,OPEN
       CALL    BDOS
       INR     A       ;WAS THE OPEN OK?
       JNZ     OPENOK  ;YES
;
;OPEN WAS BAD, EXIT WITH ERROR MESSAGE.
;
       CALL    ERXIT
       DB      '++NO SUCH FILE++',CR,LF,'$'
;
OPENOK  LXI     D,BUFF  ;POINT TO BUFFER
READLP  PUSH    D       ;SAVE BUFFER ADDRESS
       MVI     C,STDMA
       CALL    BDOS
;READ A SECTOR
       LXI     D,FCB
       MVI     C,READ
       CALL    BDOS
       POP     D       ;GET DMA ADDR
       ORA     A       ;OK?
       JNZ     EOF     ;NOT OK, MUST BE EOF
       LHLD    FCT     ;LOAD SECTOR COUNT FOR FILE
       INX     H       ;BUMP IT
       SHLD    FCT     ;SAVE IT BACK
       LXI     H,80H   ;LENGTH OF 1 SECT.
       DAD     D       ;CALC NEXT BUFF ADDR
       XCHG            ;PUT IT BACK IN DE
;OUT OF MEMORY?
       LDA     BASE+7  ;GET BDOS PAGE POINTER
       SUI     2       ;MAKE SURE
       CMP     D       ;ABOUT TO HIT BDOS?
       JNC     READLP  ;NO, LOOP
;
;FILE IS TOO BIG - EXIT PRINTING ERROR MSG.
;
       CALL    ERXIT
       DB      '++FILE WON''T FIT IN MEMORY++$'
;
;GOT RETURN CODE ON READ, SEE IF ERROR OR EOF
;
EOF     LHLD    FCT     ;GET SECTOR COUNT
       SHLD    SAVEFCT ;SAVE IT FOR MULTIPLE WRITES
;A HAS RETURN CODE FROM READ
       DCR     A       ;EOF?
       JZ      DESTMSG ;YES, ASK FOR DEST. DISK
;
;READ ERROR - EXIT WITH MSG
;
       CALL    ERXIT
       DB      '++READ ERROR++$'
;
;FILE READ INTO MEMORY.  ASK FOR DEST. DISK
;
DESTMSG LXI     D,BASE+80H ;RESET DMA TO NORMAL
       MVI     C,STDMA
       CALL    BDOS
       CALL    ILPRT
       DB      'C/R TO END, ',CR,LF
       DB      'MOUNT DEST.  DISK, TYPE: A, B, C, OR D ',0
       CALL    GETDISK ;GET A OR B
       JC      DESTMSG ;NEITHER, ASK AGAIN
       LHLD    SAVEFCT ;GET SAVED COUNT
       SHLD    FCT     ;SAVE FOR DECREMENT
;
;INIT FOR WRITING THE FILE
;
       XRA     A
       STA     FCBEXT  ;ZERO EXTENT #
       STA     FCBSNO  ;ZERO SECTOR #
;
;REMOVE ALL FILE ATTRIBUTES
       LXI     H,FCB+1 ;POINT TO FILE NAME.TYPE
       MVI     B,11    ;NUMBER OF CHARACTERS
;
ZFCBLP  MOV     A,M     ;GET CHAR
       ANI     7FH     ;ZERO OUT ATTRIBUTE
       MOV     M,A     ;RESTORE CHAR TO FCB
       INX     H
       DCR     B       ;ONE LESS CHARACTER
       JNZ     ZFCBLP
;
;ERASE ANY FILE BY SAME NAME
       LXI     D,FCB
       MVI     C,ERASE
       CALL    BDOS
;
;MAKE THE FILE
       LXI     D,FCB
       MVI     C,MAKE
       CALL    BDOS
       INR     A
       JZ      BADMAKE ;MAYBE DIRECTORY IS FULL?
;
;WRITE THE FILE TO DISK
;
       LXI     H,BUFF  ;POINT TO BUFFER
       SHLD    BUFPTR
WRLP    LHLD    BUFPTR
       LXI     D,BASE+80H
       CALL    MOVE128
       SHLD    BUFPTR  ;SAVE THE NEW BUF ADDR
;WRITE THE SECTOR
       LXI     D,FCB
       MVI     C,WRITE
       CALL    BDOS
       ORA     A       ;WAS THE WRITE SUCCESSFUL?
       JNZ     WRERR   ;NO, EXIT W/ERROR MSG
       LHLD    FCT     ;GET FILE'S SECTOR COUNT
       DCX     H       ;DECREMENT IT
       SHLD    FCT     ;SAVE IT BACK
       MOV     A,H
       ORA     L       ;ZERO?
       JNZ     WRLP    ;NO, LOOP
;CLOSE THE FILE
       LXI     D,FCB
       MVI     C,CLOSE
       CALL    BDOS
       CALL    ILPRT   ;PRINT THE FOLLOWING:
       DB      '++DONE++',CR,LF,0
       JMP     DESTMSG
;
;GOT A WRITE ERROR - EXIT W/ERROR MSG.
;
WRERR   CALL    ERXIT
       DB      '++WRITE ERROR$'
;
;COULDN'T MAKE THE FILE, EXIT W/ERROR MSG.
;
BADMAKE CALL    ERXIT
       DB      '++CAN''T MAKE OUTPUT FILE$'
;
;INLINE PRINT ROUTINE - CALL ILPRT FOLLOWED
;       BY MESSAGE (ENDING IN 0)
;
ILPRT   MVI     A,CR    ;CR..
       CALL    TYPE
       MVI     A,LF    ;LF FIRST.
       CALL    TYPE
       XTHL            ;SAVE HL, GET MSG ADDR
;
ILPLP   MOV     A,M     ;GET CHAR OF MSG
       CALL    TYPE    ;TYPE IT
       INX     H       ;POINT TO NEXT CHAR
       MOV     A,M     ;GET IT
       ORA     A       ;IS IT END OF MSG?
       JNZ     ILPLP   ;NO, LOOP
       INX     H       ;SKIP THE 0
       XTHL            ;RESTORE HL, STACK RET ADDR
       RET             ;..AND RETURN
;
;TYPE CHAR IN A
;
TYPE    PUSH    B
       PUSH    D
       PUSH    H
       MOV     E,A     ;FOR TYPE
       MVI     C,WRCON
       CALL    BDOS
       POP     H
       POP     D
       POP     B
       RET
;
;EXIT WITH ERROR MESSAGE
;
ERXIT   MVI     A,CR
       CALL    TYPE
       MVI     A,LF
       CALL    TYPE
       POP     D       ;GET MSG ADDR
       MVI     C,PRINT
       CALL    BDOS
;
;EXIT: ASSUMES DISK IN A: MAY NOW BE DIFFERENT
;SYSTEM SIZE, SO WARM BOOT WOULD NOT WORK.
;JUMPS TO COLD BOOT EPROM ENTRY POINT.
;IF SUCH AN ENTRY POINT IS NOT AVAILABLE,
;CHANGE TO JMP 0000.  THIS WILL WORK IF YOU
;ARE WARM-BOOTING THE SAME SIZED SYSTEM AS
;BEFORE.
;
EXIT    CALL    ILPRT
       DB      CR,LF,'RE-BOOTING '
       DB      'VIA "JMP FC00", '      ;<------
       DB      'PRESS RETURN',0
       MVI     C,RDCON
       CALL    BDOS    ;GET CHAR.
       CPI     CR      ;C/R?
       JNZ     EXIT
       JMP     0FC00H  ;COLD BOOT ROM ADDRESS <------
;
;MOVE 128 CHARACTERS
;
MOVE128 MVI     B,128   ;SET MOVE COUNT
;
;MOVE FROM (HL) TO (DE) LENGTH IN (B)
;
MOVE    MOV     A,M     ;GET A CHAR
       STAX    D       ;STORE IT
       INX     H       ;TO NEXT "FROM"
       INX     D       ;TO NEXT "TO"
       DCR     B       ;MORE?
       JNZ     MOVE    ;..YES, LOOP
       RET             ;..NO, RETURN
;
;ROUTINE TO GET DISK NUMBER (A, B, C, D) THEN
;RESET THE DISK AND LOG IN THAT DISK.
;
GETDISK MVI     C,RDCON
       CALL    BDOS    ;GET CHAR.
       CPI     CR      ;JUST RETURN?
       JZ      EXIT    ;YES, ALL DONE
       PUSH    PSW     ;SAVE CHAR
;RESET DISK, KILLING R/O STATUS
       MVI     C,RESETDK
       CALL    BDOS
       POP     PSW     ;GET DISK
       ANI     5FH     ;MAKE UPPER CASE
       SUI     'A'     ;CALC DISK
       MOV     E,A     ;SETUP FOR SELECT
       CPI     4       ;A-D?
       CMC             ;CY ON = BAD
       RC              ;ERROR RETURN
;LOG IN THE APPROPRIATE DISK
SELDISK MVI     C,SELDK
       CALL    BDOS
       ORA     A       ;SHOW NO ERROR
       RET
;
FCT     DW      0       ;FILE COUNT
SAVEFCT DW      0       ;SAVED FILE COUNT
BUFPTR  DS      2       ;BUFFER POINTER FOR WRITE
;
       DS      64      ;STACK AREA
STACK   EQU     $
BUFF    EQU     $
;
;BDOS/CBIOS EQUATES
;
RDCON   EQU     1
WRCON   EQU     2
PRINT   EQU     9
RESETDK EQU     13
SELDK   EQU     14
OPEN    EQU     15
CLOSE   EQU     16
ERASE   EQU     19
READ    EQU     20
WRITE   EQU     21
MAKE    EQU     22
STDMA   EQU     26
BDOS    EQU     BASE+5
FCB     EQU     BASE+5CH
FCBEXT  EQU     FCB+12
FCBSNO  EQU     FCB+32
;
       END