;
;                   TOHARD.ASM ver 1.2
;                by Keith Petersen, W8SDZ
;                    (revised 9/26/80)
;
;This program will transfer files from CP/M on floppy disks
;to CP/M on hard disk. (It can also be used for transfers
;from 5-1/4" minifloppy to 8" floppy.)
;
;To do this you must bring up the floppy CP/M as a small
;system (say 24k).  The system location isn't important so
;long as it does not overwrite the larger system in use by
;the hard disk. It is assumed that the user's system allows
;both disk controller boards to be used without conflict.
;
;
;               USING THIS PROGRAM
;
; 1 - Bring up the hard disk CP/M as a large system (eg. 56k).
; 2 - Log into the drive you will be transferring files to.
; 3 - Cold boot the floppy CP/M, then run this program on it.
;
;COMMANDS:
;       TOHARD filename.type    ;gets file from default drive
;       TOHARD B:filename.type  ;gets file from B:
;       TOHARD *.*              ;gets all files
;       TOHARD B:*.*            ;gets all files from B:
;
;All normal ambiguous file names are allowed. Files written to
;the hard disk will go to the default drive.
;
FALSE   EQU     0
TRUE    EQU     NOT FALSE
;
;CONDITIONAL ASSEMBLY SWITCHES FOR CPn to
;the hard disk will go to the default drive.
;
FALSE   EQU     0
TRUE    EQU     NOT FALSE
;
;CONDITIONAL ASSEMBLY SWITCHES FOR CP/M VERSION
;       (only one should be true)
;
CPM14   EQU     FALSE   ;CP/M VERSION 1.4
CPM2    EQU     TRUE    ;CP/M VERSION 2.x
;
;OTHER CONDIT/M VERSION
;       (only one should be true)
;
CPM14   EQU     FALSE   ;CP/M VERSION 1.4
CPM2    EQU     TRUE    ;CP/M VERSION 2.x
;
;OTHER CONDITIONAL ASSEMBLY SWITCHES
;
DJ2D    EQU     FALSE   ;TRUE IF BIG SYSTEM IS DISCUS 2D FLOPPY
REPORT  EQU     FALSE   ;TRUE TO REPORT READS AND WRITES
                       ;(nice, but slows down transfers)
;
;EQUATES
;
MSIZE   EQU     56      ;PUT BIG SYSTEM MEMORY SIZE HERE
;
       IF      CPM14
BIAS    EQU     (MSIZE-16)*1024
CCP     EQU     BIAS+2900H      ;BASE OF CCP
       ENDIF                   ;CP/M 1.4
;
       IF      CPM2 AND (NOT DJ2D)
BIAS    EQU     (MSIZE-20)*1024
CCP     EQU     BIAS+3400H      ;BASE OF CCP
       ENDIF                   ;STANDARD CP/M 2.x
;
       IF      CPM2 AND DJ2D
BIAS    EQU     (MSIZE-20)*1024
CCP     EQU     BIAS+2D00H      ;BASE DISCUS 2D CCP
       ENDIF                   ;CP/M 2.x ON DISCUS 2D
;
DEST$BDOS EQU   CCP+806H   ;RECEIVING BDOS VECTOR
;
BELL    EQU     7       ;BELL CHARACTER
TAB     EQU     9       ;TAB CHARACTER
CR      EQU     0DH     ;CARRIAGE RETURN
LF      EQU     0AH     ;LINE FEED
;
;BDOS/CBIOS EQUATES
;
WBOOT   EQU     0       ;WARM BOOT ENTRY ADRS
WRCON   EQU     2       ;WRITE CHARACTER TO CONSOLE
BDOS    EQU     0005H   ;THE SENDING BDOS VECTOR
PRINT   EQU     9       ;PRINT STRING (DE) UNTIL '$'
OPEN    EQU     15      ;OPEN FILE
CLOSE   EQU     16      ;CLOSE FILE
SRCHF   EQU     17      ;SEARCH DIR FOR FIRST OCCUR.
SRCHN   EQU     18      ;SEARCH DIR FOR NEXT OCCUR.
DELETE  EQU     19      ;ERASE FILE
READ    EQU     20      ;READ RECORD
WRITE   EQU     21      ;WRITE RECORD
MAKE    EQU     22      ;MAKE FILE
STDMA   EQU     26      ;SET DMA ADRS
FCB     EQU     5CH     ;DEFAULT FILE CONTROL BLOCK
FCBEXT  EQU     FCB+12  ;EXTENT BYTE IN FCB
FCBRNO  EQU     FCB+32  ;RECORD NUMBER IN FCB
;
NOERR   EQU     0       ;NO ERROR
EOF     EQU     1       ;END OF FILE
NTFND   EQU     255     ;NOT FOUND
NOMAKE  EQU     255     ;CAN'T MAKE FILE
BDCLOS  EQU     255     ;BAD FILE CLOSE
;
;       THIS IS THE START OF THE PROGRAM.
;
       ORG     100H
;
START   LDA     FCB+1
       CPI     ' '     ;SEE IF FILENAME THERE
       JNZ     SIGNON
       CALL    ILPRT   ;PRINT:
       DB      CR,LF,'++NO FILE NAME SPECIFIED++',0
       RET             ;EXIT TO CP/M
;
SIGNON: LXI     SP,STACK  ;SET STACK POINTER
       CALL    ILPRT   ;PRINT:
       DB      CR,LF,'FLOPPY to HARD DISK',CR,LF
       DB      'multiple file transfer program',CR,LF,0

MORE:   CALL    MFNAME  ;SEE IF FILE IS IN DIRECTORY
       JNC     MOVNAM  ;ANOTHER FILE FOUND, GET IT
       LDA     MFFLG1  ;NOTHING FOUND, CHECK...
       ORA     A       ;... FIRST TIME FLAG
       JZ      DONE    ;AT LEAST ONE WAS FOUND
       CALL    EXIT
       DB      '++FILE NOT FOUND++$'
;
DONE:   CALL    EXIT
       DB      CR,LF,'DONE$'
;
;MOVE FILENAME FROM FCB TO FNAME AND PRINT IT
;
MOVNAM: LXI     H,FCB+1
       LXI     D,FNAME
       MVI     B,8     ;8 CHARS IN FILE NAME
       CALL    MOVER
       LXI     H,FCB+9
       LXI     D,FNAME+9
       MVI     B,3     ;3 CHARS IN FILE TYPE
       CALL    MOVER
       CALL    ILPRT   ;PRINT:
       DB      CR,LF,'--> FILE: '
FNAME:  DB      'XXXXXXXX.XXX'
       DB      CR,LF,0
;
;SAVE FIRST FCB FOR USE LATER AS DESTINATION FILE NAME
       MVI     B,11       ;NUMBER OF CHARACTERS TO MOVE
       LXI     H,FCB+1    ;...FROM FIRST FCB
       LXI     D,NEWFCB+1 ;...TO NEWFCB (USE DEFAULT DRIVE)
       CALL    MOVER
;
;OPEN THE SOURCE FILE
       LXI     D,FCB
       MVI     C,OPEN
       CALL    BDOS
       CPI     NTFND   ;NOT FOUND?
       JNZ     OPENOK
       CALL    EXIT
       DB      BELL
       DB      '++CAN''T OPEN FILE ON SOURCE DISK++$'
;
;OPEN THE DESTINATION FILE
;
OPENOK: CALL    ILPRT   ;PRINT:
       DB      'Opening file on destination disk',0
       LXI     D,NEWFCB
       MVI     C,DELETE        ;ERASE ANY OLD FILE
       CALL    DEST$BDOS
       LXI     D,NEWFCB
       MVI     C,MAKE          ;MAKE THE NEW ONE
       CALL    DEST$BDOS
       CPI     NOMAKE
       JNZ     RDLOOP
       CALL    EXIT
       DB      BELL
       DB      '++CANNOT CREATE FILE ON DESTINATION DISK++$'
;
;READ A SECTOR FROM SMALL DISK
;
RDLOOP: EQU     $
;
       IF      REPORT
       CALL    ILPRT   ;PRINT:
       DB      TAB,'Reading sector from source disk',0
       ENDIF           ;REPORT
;
       LXI     D,80H
       MVI     C,STDMA ;SET DMA TO 80H
       CALL    BDOS
       LXI     D,FCB
       MVI     C,READ  ;READ A RECORD
       CALL    BDOS
       CPI     NOERR
       JZ      WRLOOP  ;NO ERROR, GO WRITE SECTOR
       CPI     EOF
       JZ      TDONE   ;END OF FILE, GO CLOSE IT
       CALL    EXIT
       DB      BELL
       DB      '++READ ERROR ON SOURCE DISK++$'
;
;WRITE A SECTOR TO BIG DISK
;
WRLOOP: EQU     $
;
       IF      REPORT
       CALL    ILPRT   ;PRINT:
       DB      TAB,'Writing sector to destination disk',0
       ENDIF           ;REPORT
;
       LXI     D,80H
       MVI     C,STDMA         ;SET DMA TO 80H
       CALL    DEST$BDOS
       LXI     D,NEWFCB
       MVI     C,WRITE         ;WRITE A RECORD
       CALL    DEST$BDOS
       CPI     NOERR
       JZ      RDLOOP
       CALL    EXIT
       DB      BELL
       DB      '++WRITE ERROR ON DESTINATION DISK++$'
;
TDONE:  CALL    ILPRT   ;PRINT:
       DB      'Closing file on destination disk now',0
       LXI     D,NEWFCB
       MVI     C,CLOSE         ;CLOSE DESTINATION FILE
       CALL    DEST$BDOS
       CPI     BDCLOS
       JNZ     MORE            ;ANOTHER FILE?
       CALL    EXIT
       DB      BELL
       DB      '++BAD CLOSE ON DESTINATION DISK++$'
;
;PRINT MESSAGE THEN EXIT TO CP/M WARM BOOT
;
EXIT:   POP     D
       MVI     C,PRINT
       CALL    BDOS
       JMP     WBOOT
;
;INLINE PRINT ROUTINE
;
ILPRT   XTHL            ;SAVE HL, GET MSG
;
ILPLP   MOV     A,M     ;GET CHAR
       CALL    TYPE    ;OUTPUT IT
       INX     H       ;POINT TO NEXT
       MOV     A,M     ;TEST
       ORA     A       ;..FOR END
       JNZ     ILPLP
       MVI     A,CR    ;CARRIAGE RETURN
       CALL    TYPE
       MVI     A,LF    ;LINE FEED
       CALL    TYPE
       XTHL            ;RESTORE HL, RET ADDR
       RET             ;RET PAST MSG
;
TYPE    PUSH    B
       PUSH    D
       PUSH    H
       MOV     E,A     ;CHAR TO E FOR CP/M
       MVI     C,WRCON ;WRITE TO CONSOLE
       CALL    BDOS
       POP     H
       POP     D
       POP     B
       RET
;
;MULTI-FILE ACCESS SUBROUTINE.  ALLOWS PROCESSING
;OF MULTIPLE FILES (I.E. *.ASM) FROM DISK.  THIS
;ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH
;TIME IT IS CALLED. CARRY IS SET IF NO MORE NAMES
;CAN BE FOUND. THE ROUTINE IS COMMENTED IN PSEUDO
;CODE, EACH PSEUDO CODE STATEMENT IS IN <<...>>
;
MFNAME: ;<<INIT DMA ADDR, FCB>>
       MVI     C,STDMA
       LXI     D,80H
       CALL    BDOS
       XRA     A
       STA     FCBEXT
       STA     FCBRNO
;<<IF FIRST TIME>>
       LDA     MFFLG1
       ORA     A
       JZ      MFN01
;<<SAVE THE REQUESTED NAME>>
;SAVE ORIG REQ
       LXI     H,FCB
       LXI     D,MFREQ
       MVI     B,12
       CALL    MOVER
       LDA     FCB
       STA     MFCUR   ;SAVE DISK IN CURR FCB
;<<SRCHF REQ NAME>>
       LXI     H,MFREQ
       LXI     D,FCB
       MVI     B,12
       CALL    MOVER
       MVI     C,SRCHF
       LXI     D,FCB
       CALL    BDOS
;<<ELSE>>
       JMP     MFN02
;
MFN01:  ;<<SRCHF CURR NAME>>
       LXI     H,MFCUR
       LXI     D,FCB
       MVI     B,12
       CALL    MOVER
       MVI     C,SRCHF
       LXI     D,FCB
       CALL    BDOS
;<<SRCHN REQ NAME>>
       LXI     H,MFREQ
       LXI     D,FCB
       MVI     B,12
       CALL    MOVER
       MVI     C,SRCHN
       LXI     D,FCB
       CALL    BDOS
;<<ENDIF>>
MFN02:  ;<<RETURN CARRY IF NOT FOUND>>
       INR     A
       STC
       RZ
;<<MOVE NAME FOUND TO CURR>>
       DCR     A
       ANI     3
       ADD     A
       ADD     A
       ADD     A
       ADD     A
       ADD     A
       ADI     81H
       MOV     L,A
       MVI     H,0
       PUSH    H       ;SAVE NAME POINTER
       LXI     D,MFCUR+1
       MVI     B,11
       CALL    MOVER
;<<MOVE NAME FOUND TO FCB>>
       POP     H
       LXI     D,FCB+1
       MVI     B,11
       CALL    MOVER
;<<SETUP FCB>>
       XRA     A
       STA     FCBEXT
       STA     FCBRNO
       STA     NEWFCB
       STA     NEWFCB+12
       STA     NEWFCB+32
       STA     MFFLG1  ;TURN OFF 1ST TIME SW
;<<RETURN>>
       RET
;------------------------------------------------
;
;MOVE SUBROUTINE  MOVE (B) BYTES FROM (HL) TO (DE)
;
MOVER   MOV     A,M
       ANI     7FH     ;STRIP CP/M 2.x ATTRIBUTES
       STAX    D
       INX     H
       INX     D
       DCR     B
       JNZ     MOVER
       RET
;
;MULTI-FILE ACCESS WORK AREA
;
MFFLG1  DB      1       ;1ST TIME SW
MFREQ   DS      12      ;REQ NAME
MFCUR   DS      12      ;CURR NAME
;
NEWFCB  DS      33
STACK   EQU     $+100
;
       END