;Stscopy - Data Technology Corporation CP/M 2.2 Stscopy. ; ; +-----------------------+ ; | | ; | S T S C O P Y | ; | | ; +-----------------------+ ; ; ; Version number: 2.1 ; Version date: April 16, 1981 ; ; Update date: May 26, 1981 ; Clear FCB before OPEN for verify. ; Update date: June 16, 1981 ; Initialize DTCBIOS. ; ; The following code is supplied to customers who ; purchase a hard/floppy disk system from DTC. ; Type STSCOPY HELP cr for instructions on usage. ; VERS: EQU 21 CR: EQU 0Dh ;ASCII carrriage return LF: EQU 0Ah ;ASCII line feed TAB: EQU 9 ;ASCII HORIZONTAL TAB EOS: EQU '$' ;BDOS End of string ERRCD: EQU 0FFh ;BDOS error code ; BDOS function equates. PRTSTR: EQU 09 ;Print String DE = buffer address. RDCB: EQU 10 ;Read console buffer DE = buffer address. INIT: EQU 13 ;Initialize BDOS SELECT: EQU 14 ;Select disk drive, DE = drive number OPEN: EQU 15 ;Open file DE = FCB address. CLOSE: EQU 16 ;Close file, DE = FCB SFIRST: EQU 17 ;Search for first occurrence, DE = FCB SNEXT: EQU 18 ;Search for next occurrence, DE = FCB DELETE: EQU 19 ;Delete file, DE = FCB READS: EQU 20 ;Read sequential file DE = FCB. WRITES: EQU 21 ;Write sequential file, DE = FCB. CREATE: EQU 22 ;Create file, DE = FCB. RENAME: EQU 23 ;Rename file, DE = FCB. IDRIVE: EQU 25 ;Interrogate drive SETDMA: EQU 26 ;Set DMA address DE = DMA address. ; Page zero locations. WBOOT: EQU 0 ;Warm boot jump address. BDOSV: EQU 5 ;BDOS jump address. CPMFCB: EQU 005Ch ;Default FCB address. DBUF: EQU 0080h ;Default DMA buffer. ORG 100h STSCOPY: PUSH PSW PUSH B PUSH D PUSH H LXI H,0 DAD SP SHLD SYSTK ;save system stack LXI SP,STACK MVI C,IDRIVE ;Save original drive number CALL BDOSV STA ODRIVE CALL HELPCK ;Check for user help request. CALL GFILEN ;Get file name CALL SKIPF ;Skip do not care sectors CALL RCPM ;Read CP/M CALL RBIOS ;Read BIOS CALL SYSINI ;Initialize destination system STSCO1: CALL COMMAND ;Do keyboard commands CALL COPY ;Copy files JMP STSCO1 ; Return to system gracefully. SYSRET: LDA ODRIVE ;Restore original drive selection MOV E,A MVI D,0 MVI C,SELECT CALL BDOSV LHLD SYSTK SPHL POP H POP D POP B POP PSW RET ;return to system ; GFILEN - Get file name and open the file. ; ; ENTRY loaction 5C = filename. GFILEN: LXI D,FCB ;Initialize FCB CALL INIFCB LXI H,CPMFCB LXI D,FCB LXI B,12 CALL MOVDTA ;Move file name to FCB LXI D,FCB MVI C,OPEN CALL BDOSV ;Open the file CPI ERRCD RNZ ;If no error LXI D,OPNERR MVI C,PRTSTR CALL BDOSV JMP SYSRET OPNERR: DB CR,LF,'Error on file open.',CR,LF,EOS ; SKIPF - Skip meaningless sectors and boot sector on file. SKIPF: LXI D,DBUF MVI C,SETDMA CALL BDOSV ;Set DMA address to default buffer MVI A,17 ;Skip 17 sectors SKPF1: PUSH PSW LXI D,FCB MVI C,READS CALL BDOSV ;Read a sector CPI ERRCD JZ SKPF2 ;If error on read POP PSW DCR A JNZ SKPF1 ;If 16 sectors not read RET SKPF2: LXI D,SKERR MVI C,PRTSTR CALL BDOSV ;Output error message JMP SYSRET SKERR: DB CR,LF,'File read error sectors 0 thru 15.' DB CR,LF,EOS ; RCPM - Read CPM sectors. RCPM: MVI A,22*2 LXI D,CCP RCPM1: PUSH PSW PUSH D ;Save buffer address MVI C,SETDMA CALL BDOSV ;Set DMA address to default buffer LXI D,FCB MVI C,READS CALL BDOSV ;Read a sector CPI ERRCD JZ RCPM2 ;If error on read POP D LXI H,128 DAD D XCHG POP PSW DCR A JNZ RCPM1 ;If 22*2 sectors not read RET RCPM2: LXI D,RCERR MVI C,PRTSTR CALL BDOSV ;Output error message JMP SYSRET RCERR: DB CR,LF,'File read error in CPM sectors (17 thru 60).' DB CR,LF,EOS RET ; RBIOS - Read BIOS sectors. RBIOS: LXI D,CBIOS RBIOS1: PUSH D ;Save buffer address MVI C,SETDMA CALL BDOSV ;Set DMA address to default buffer LXI D,FCB MVI C,READS CALL BDOSV ;Read a sector POP D LXI H,128 DAD D XCHG ORA A JZ RBIOS1 ;If no errors RET ; COMMAND - keyboard command processor ; COMMAND: LXI D,PROMPT ;show prompt COM1: CALL INFCRT LXI H,INBUFX+1 ;Get count MOV C,M INX H ;Point to first character MOV A,C ORA A JZ SYSRET LXI D,DFCB ;Parse for destination CALL PARSE CPI ERRCD ;Valid descriptor? JZ COM2 MOV A,B ;Yes. Save destination drive STA DDRIVE MOV A,C ;End of command? ORA A JZ COM2 MVI A,'=' ;No. Correct format? CMP M JNZ COM2 INX H ;Yes. Skip separator DCR C JZ COM2 LXI D,SFCB ;Parse for source CALL PARSE CPI ERRCD ;Valid descriptor? JZ COM2 MOV A,B ;Yes. Save source drive STA SDRIVE LXI H,SFCB+1 ;Check for wild cards MVI B,11 MVI A,'?' COM3: CMP M JZ COM4 INX H DCR B JNZ COM3 COM4: MOV A,B ;Set wild card flag STA WILD RET COM2: LXI D,INVMSG JMP COM1 INVMSG: DB CR,LF,'Invalid command.' PROMPT: DB CR,LF,'*',EOS ; COPY - Copy selected source system files to destination system ; COPY: LXI D,COPMSG ;If wild cards, print header. MVI C,PRTSTR LDA WILD ORA A CNZ BDOSV LDA SDRIVE ;Select source drive CPI ERRCD ; if specified. JZ COPY1 MOV E,A MVI D,0 MVI C,SELECT CALL BDOSV CPI ERRCD JNZ COPY1 LXI D,COPYM1 ;Select error COPYER: MVI C,PRTSTR ;Print error message CALL BDOSV MVI A,ERRCD ;Return error code RET COPY1: ;Search for source file XRA A ;Initialize search occurrence STA SRCOCC COPYS: MVI B,0 ;Clear search count LDA SRCOCC MOV C,A INR A ;Increment occurrence count STA SRCOCC PUSH B ;Save counts LXI D,SFCB ;Search for first occurrence MVI C,SFIRST CALL BDOSV POP B ;Restore counts CPI ERRCD JNZ COPYS1 LXI D,COPYM2 ;File not found. JMP COPYER COPYS1: MOV A,B ;This occurrence? CMP C JZ COPYS2 INR B ;No. increment search count PUSH B ;Save counts LXI D,SFCB ;Search for next occurrence MVI C,SNEXT CALL BDOSV POP B ;Restore counts CPI ERRCD MVI A,0 RZ ;Found all occurrences. JMP COPYS1 COPYS2: DAD H ;HL=entry number, DE=end of dir. buffer DAD H ;*32 for entry offset DAD H DAD H DAD H DAD D ;Add directory pointer LXI D,-128 ;relative to beginning of dir. buffer DAD D LXI D,SFFCB LXI B,32 CALL MOVDTA XRA A ;Clear next record number STAX D LDA WILD ;If wild cards, print file name. ORA A JZ COPYS3 LXI H,SFFCB+1 LXI D,FN LXI B,8 CALL MOVDTA INX D ;Skip '.' LXI B,3 CALL MOVDTA LXI D,FNMSG MVI C,PRTSTR CALL BDOSV COPYS3: LXI D,SFFCB ;Open source file MVI C,OPEN CALL BDOSV LXI D,COPYM3 CPI ERRCD JZ COPYER COPYR: XRA A ;clear continuation flag STA CFLAG LXI D,BUFFER ;Set buffer pointer LXI B,0 ;Clear file record count. COPYR1: PUSH B ;Read a record PUSH D MVI C,SETDMA CALL BDOSV LXI D,SFFCB MVI C,READS CALL BDOSV POP D ;Restore buffer pointer POP B ;Restore record count CPI 0 ;Done? JNZ COPYR2 INX B ;No. Increment record count LXI H,128 ;Increment buffer pointer DAD D XCHG LXI H,-BUFEND ;Buffer full? DAD D MOV A,H ORA L JNZ COPYR1 LXI H,CFLAG ;Yes. Set continuation flag. INR M COPYR2: PUSH B ;Save file record count POP H SHLD FCNT MOV A,H ;Empty file? ORA L JZ COPYS CALL SWSD ;No. Switch to destination system. LDA CFLAG ;On a continuation? CPI 2 JNC COPYW LDA DDRIVE ;No. Select destination drive CPI ERRCD ; if specified JZ COPYD MOV E,A MVI D,0 PUSH D ;Save selection MVI C,INIT ;Initialize CP/M CALL BDOSV POP D MVI C,SELECT CALL BDOSV CPI ERRCD LXI D,COPYM4 JZ COPYED COPYD: ;Initialize destination file. LXI D,DFFCB CALL INIFCB LXI D,DFFCB+1 ;Move file name LDA WILD ;If wild cards, use source name ORA A JNZ COPYD0 LXI H,DFCB+1 ;Was file name specified? MVI A,' ' CMP M JNZ COPYD1 COPYD0: LXI H,SFFCB+1 ;No. Use source file name. COPYD1: LXI B,8 CALL MOVDTA LXI H,DOLLAR ;Set file type to $$$. LXI B,3 CALL MOVDTA LXI D,DFFCB ;Delete any temporary file of same name MVI C,DELETE CALL BDOSV LXI D,DFFCB ;Create temporary file MVI C,CREATE CALL BDOSV LXI D,COPYM5 CPI ERRCD JZ COPYED LXI D,DFFCB ;Open destination file MVI C,OPEN CALL BDOSV LXI D,COPYM6 CPI ERRCD JZ COPYED COPYW: ;Write buffer. LXI D,BUFFER LHLD FCNT ;Initialize record count PUSH H ;Save record count COPYW1: PUSH D ;Save buffer pointer MVI C,SETDMA ;Set dma address CALL BDOSV LXI D,DFFCB MVI C,WRITES ;Write a record CALL BDOSV POP D ;Restore buffer pointer POP H ;Restore record count CPI 0 JNZ COPYW2 ;If write error. DCX H ;Decrement record count MOV A,H ORA L JZ COPYW3 PUSH H ;Save record count LXI H,128 ;Increment buffer pointer DAD D XCHG JMP COPYW1 COPYW2: ;Write error LXI D,COPYM7 CPI 1 JZ COPYED LXI D,COPYM8 CPI 2 JZ COPYED LXI D,COPYM5 COPYED: ;Error on destination system PUSH D ;Save message pointer CALL SWDS ;Switch to source system POP D ;Restore message pointer JMP COPYER ;Print error and return COPYW3: ;Close destination and verify. LXI D,DFFCB MVI C,CLOSE CALL BDOSV LXI D,COPYM9 CPI ERRCD JZ COPYED LXI H,DFFCB+12 ;CLEAR FCB MVI B,33-12 XRA A COPYV0: MOV M,A INX H DCR B JNZ COPYV0 LXI D,DFFCB ;Verify MVI C,OPEN CALL BDOSV LXI D,COPYM6 CPI ERRCD JZ COPYED LXI D,VBUFF ;Set dma address MVI C,SETDMA CALL BDOSV LHLD FCNT ;Initialize record count MOV B,H MOV C,L LXI H,BUFFER ;Initialize buffer pointer COPYV: ;Verify record PUSH H ;Save buffer pointer PUSH B ;Save record count LXI D,DFFCB MVI C,READS ;Get record CALL BDOSV POP B ;Restore record count POP H ;Restore buffer pointer LXI D,COPYMA CPI 0 JNZ COPYED PUSH B ;Save record count MVI B,128 ;Set compare count LXI D,VBUFF ;Set compare buffer pointer COPYV1: LDAX D ;Get destination byte CMP M ;Are they equal? JZ COPYV2 POP B ;Remove compare count LXI D,COPYMA JMP COPYED COPYV2: INX H ;Yes. Increment buffer pointers INX D DCR B ;Decrement compare count JNZ COPYV1 POP B ;Restore record count DCX B ;Decrement record count MOV A,B ORA C JNZ COPYV LXI D,DFFCB ;Close destination file MVI C,CLOSE CALL BDOSV LXI D,COPYM9 CPI ERRCD JZ COPYED LXI D,DFFCB+16 ;Setup FCB for rename LXI H,DFFCB LXI B,9 CALL MOVDTA LXI H,DFCB+9 ;Was type specified? MVI A,' ' CMP M JNZ COPYN1 LXI H,SFFCB+9 ;No. Use source type. COPYN1: LXI B,3 CALL MOVDTA LXI D,DFFCB+16 ;Delete any file of same name & type MVI C,DELETE CALL BDOSV LXI D,DFFCB ;Rename the destination file MVI C,RENAME CALL BDOSV LXI D,COPYMB CPI ERRCD JZ COPYED COPYL: CALL SWDS ;Switch to source system LDA CFLAG ;Continuation? ORA A JNZ COPYR ;Yes JMP COPYS ;No. Get next occurrence. DOLLAR: DB '$$$' COPMSG: DB CR,LF,LF,'COPYING -',EOS COPYM1: DB CR,LF,'Source drive not ready.',EOS COPYM2: DB CR,LF,'File not found.',EOS COPYM3: DB CR,LF,'Open error on source file.',EOS COPYM4: DB CR,LF,'Destination drive not ready.',EOS COPYM5: DB CR,LF,'Destination drive directory is full.',EOS COPYM6: DB CR,LF,'Open error on destination file.',EOS COPYM7: DB CR,LF,'Error in extending destination file.',EOS COPYM8: DB CR,LF,'Destination disk is full.',EOS COPYM9: DB CR,LF,'Close error on destination file.',EOS COPYMA: DB CR,LF,'Verify error.',EOS COPYMB: DB CR,LF,'Rename error.',EOS ; INFCRT - Output message and input from console. ; ; ENTRY DE = message address. ; ; EXIT A = First character entered (upper case). INFCRT: MVI C,PRTSTR CALL BDOSV ;Output message LXI D,INBUFX MVI C,RDCB CALL BDOSV LDA INBUFX+1 ANA A MVI A,CR RZ LDA INBUF CPI 'A'+20h RC ;If upper case CPI 'Z'+20h+1 RNC ;If upper case SUI 20h ;Fold to uppercase RET INBUFX: DB 40,0 INBUF: DS 40 ; PARSE - Parse file descriptor ; ; Entry: HL = address of string buffer ; DE = address of FCB ; C = string length ; Exit: A = 0ffh if illegal file descriptor or drive ; B = drive code or 0ffh ; PARSE: CALL INIFCB ;Initialize FCB INX D ;skip entry type MVI B,0FFH ;initialize drive code MOV A,C ;empty string? ORA A JNZ PARSE2 PARSE1: MVI A,0FFh ;yes. return error code RET PARSE2: MVI A,1 ;drive specified? CMP C JNC PARSE3 INX H ;maybe MOV A,M ;Is second character ':'? DCX H CPI ':' JNZ PARSE3 CALL GETFDC ;Yes. Get drive character SUI 'A' ;Legal drive #? JM PARSE1 CPI 16 JNC PARSE1 MOV B,A ;Yes. Save drive code. INX H ;Skip to file name DCR C INX H DCR C JNZ PARSE3 XRA A ;done RET PARSE3: PUSH B ;Save drive code MVI B,8 ;Set maximum length of file name CALL PARSNT ;parse file name XRA A ;done? CMP C JZ PARSE4 MVI A,'.' ;No. file type? CMP M JNZ PARSE4 INX H ;Yes. parse file type DCR C JZ PARSE5 MVI B,3 CALL PARSNT PARSE4: MOV A,C ;Save count POP B ;Restore drive code MOV C,A XRA A RET PARSE5: MOV A,C POP B MOV C,A MVI A,0FFh RET ; PARSNT - Parse file name or type ; PARSNT: MVI A,'*' ;Wild card? CMP M JNZ PARSN3 PARSN1: INX H ;Yes. Skip to terminator. DCR C JZ PARSN2 CALL GETFDC JNZ PARSN1 PARSN2: PUSH B ;Save count MOV C,B ;Fill with '?' MVI B,0 CALL PARSEQ POP B ;Restore count RET PARSN3: CALL GETFDC ;Get character JZ PARSN5 STAX D ;Store char INX D ;Incr. FCB pointer INX H ;Incr. string pointer DCR B ;Out of space? JZ PARSN4 DCR C ;Decr. string count. JNZ PARSN3 RET PARSN4: CALL GETFDC ;Skip to terminator. RZ DCR C JNZ PARSN4 RET PARSN5: MOV A,E ;Adjust FCB pointer to end of field. ADD B MOV E,A RNC INR D RET ; PARSEQ - Fill field with '?' ; PARSEQ: PUSH H ;Save string pointer MOV H,D MOV L,E MVI A,'?' STAX D INX D DCX B CALL MOVDTA POP H RET ; GETFDC - Get file descriptor character ; ; Entry: HL = Address of FD string ; Exit: A = character (upper case) ; Z = 1 iff terminator ; GETFDC: MOV A,M ;Get character CPI 'A'+20h ;Convert to upper case JC GETFC1 CPI 'Z'+20h JNC GETFC1 SUI 20h GETFC1: CPI '.' ;Check for terminator RZ CPI ' ' RZ CPI '=' RZ CPI '*' RET ; INIFCB - Initialize FCB ; ; Entry: DE = Address of FCB ; INIFCB: PUSH H ;Save registers PUSH D POP H ;HL = FCB PUSH H PUSH B XRA A ;clear entry type MOV M,A INX H INX D ;set file name & type to spaces INX D MVI A,' ' MOV M,A LXI B,10 CALL MOVDTA INX H XRA A ;clear rest of FCB MOV M,A INX D LXI B,20 ; and next record number CALL MOVDTA POP B POP D ;restore registers POP H RET ; MOVDTA - Move data utility program. ; ; ENTRY HL = Source field. ; DE = Destination field. ; BC = number of bytes. MOVDTA: MOV A,M STAX D INX H INX D DCX B MOV A,B ORA C JNZ MOVDTA RET ; SYSINI - Initialize destination system ; SYSINI: CALL SWSD ;Switch page 0 LXI H,SYSIN1 ;Set BIOS initialization return PUSH H LHLD WBOOT+1 ;Get warm boot vector address DCX H ;Get cold boot address MOV D,M DCX H MOV E,M LXI H,-3 ;Point to STSINI entry DAD D PCHL ;Initialize BIOS SYSIN1: CPI 0FFh ;Initialization error? JNZ SYSIN2 CALL SWDS ;Yes. Restore source system LXI D,INIMSG MVI C,PRTSTR CALL BDOSV JMP SYSRET SYSIN2: MVI C,INIT ;Initialize BDOS and select A CALL BDOSV CALL SWDS ;Switch page 0 RET INIMSG: DB CR,LF,'BIOS initialization error.', EOS ; SWSD - Switch from source to destination system ; SWSD: LXI H,0 ;Save source page 0 pointers LXI D,SPZERO LXI B,8 CALL MOVDTA LXI H,DPZERO ;Set destination page 0 pointers SWDS1: LXI D,0 LXI B,8 CALL MOVDTA RET ; SWDS - Switch from destination to source system ; SWDS: LXI H,0 ;Save destination page 0 pointers. LXI D,DPZERO LXI B,8 CALL MOVDTA LXI H,SPZERO ;Set source page 0 pointers. JMP SWDS1 ; Destination system page 0 pointers ; DPZERO: JMP CBIOS+3 ;BIOS entry DB 0 ;I/O byte DB 0 ;Current disk JMP BDOS ;BDOS entry ; Source system page 0 pointers ; SPZERO: DS 8 WILD: DS 1 ;Wild card flag FNMSG: DB CR,LF FN: DS 8 DB '.' FT: DS 3 DB EOS SYSTK: DS 2 ;Hold stack ODRIVE: DS 1 ;Original drive DDRIVE: DS 1 ;Destination drive SDRIVE: DS 1 ;Source drive SRCOCC: DS 1 ;Source file occurrence count CFLAG: DS 1 ;Continuation flag FCNT: DS 2 ;File record count DFCB: DS 33 ;destination command file name DFFCB: DS 33 ;destination FCB SFCB: DS 33 ;source command file name SFFCB: DS 33 ;source file FCB FCB: DS 33 ;STSCPM.COM FCB DS 50 STACK: DS 1 ; VBUFF: DS 128 BUFFER: DS (CCP-$) AND 0FF00H BUFSEC: EQU ($-BUFFER)/128 BUFEND: EQU BUFFER+BUFSEC*128 ; ORG VBUFF ; ; Check for HELP request ; HELPCK: LXI H,HELPNM LXI D,CPMFCB+1 MVI B,8 LDAX D ;Was file specified? CPI ' ' JZ HELPC2 ;No HELPC1: CMP M ;Yes RNZ INX D INX H LDAX D DCR B JNZ HELPC1 HELPC2: LXI D,HELP ;Print HELP message MVI C,PRTSTR CALL BDOSV JMP SYSRET HELPNM: DB 'HELP ' HELP: DB CR,LF,LF DB 'STSCOPY - System-to-System file copy',CR,LF,LF DB 'This program provides a means of loading files onto',CR,LF DB 'a hard disk from floppy diskette for Data Technology',CR,LF DB 'Corporation customers receiving controllers that do',CR,LF DB 'not include floppy diskette control. It is assumed',CR,LF DB 'that the customer has an operational CP/M system',CR,LF DB 'running with a non-DTC disk controller.',CR,LF,LF DB 'After FORMATting the hard disk and INSTALLing CP/M',CR,LF DB 'on it, edit the file CONFIG and set MSIZE to a value',CR,LF DB 'just below the CCP of your floppy based CP/M. Then',CR,LF DB 'execute the SUBMIT file STSCOPY.SUB which will',CR,LF DB 'generate customized copies of STSCOPY.COM and',CR,LF DB 'STSCPM.COM. (See STSCOPY.SUB for details.)',CR,LF DB 'To execute STSCOPY.COM, type',CR,LF DB ' STSCOPY STSCPM.COM',CR,LF DB 'The file STSCPM.COM is read into memory and the',CR,LF DB 'keyboard prompt "*" is output to the console.',CR,LF DB 'The form of each command line is',CR,LF,LF DB ' destination=source cr',CR,LF,LF DB 'where "destination" is the file in the STSCPM',CR,LF DB 'system to receive the data and "source" is the',CR,LF DB 'file in the floppy based CP/M system. Disk drive',CR,LF DB 'names may be optionally included in the source',CR,LF DB 'and destination. The destination may be null or',CR,LF DB 'an "unambiguous" (ufn) file reference as defined',CR,LF DB 'in CP/M. The source may be a ufn or an "ambiguous"',CR,LF DB '(afn) file reference. For example',CR,LF,LF DB ' x:=*.COM',CR,LF,LF DB 'transfers all COM files from the currently selected',CR,LF DB 'drive of the floppy based CP/M system to drive x',CR,LF DB 'of the hard disk system. All transfers are verified',CR,LF DB 'by reading them back and comparing.',CR,LF,EOS END