; Patching CP/M-80's PIP for Multiple Disk File Transfers ; ; By: Kelly Smith ; ; ; "We shall not cease from exploration, and the end of all our ; exploring will be to arrive where we started and know the place ; for the first time." - T.S. Eliot, Little Gidding ; ; Digital Researchs's PIP (Peripheral Interchange Program) is the ; CP/M transient command used to move a single file or multiple ; files from one disk to another, or to other peripheral devices. ; Unfortunately PIP will not allow the transfer of files to ; multiple disks...you must always exit PIP and re-log any new ; disks or warm boot (by entering your keyboard Control-C) the CP/M ; system, then invoke PIP again to proceed...agonizing, if you want ; to do multiple disk copies of specific files. ; ; How would you like to be able to transfer files to multiple ; disks without exiting PIP, as well as have it repeat the last ; operation that you entered at PIP's command level with ONE ; keystroke? Its EASY Edit and assemble the following 'patch', ; then merge it into your existing CP/M-80 (Version 2.2) 'PIP.COM' ; utility as follows: ; ; A>ddt pip.com <-- invoke DDT to load memory with 'PIP.COM' ; DDT VERS 2.2 <-- DDT telling us that... ; NEXT PC ; 1E00 0100 <-- 'PIP.COM' uses 29 pages of memory ; -ipatch.hex <-- Input the 'patch' file ; -r <-- Read it in to memory (overlaying parts of PIP) ; NEXT PC ; 1E00 0000 ; -^C <-- Control-C to exit DDT ; ; A>save 29 rpip.com <-- save 29 pages of memory as 'RPIP.COM' ; ; So, for a little "demo" of what you can do and expect from adding ; this 'patch', lets give it a whirl: ; ; A>rpip <-- invoke our new 'Repeating PIP'... ; ; PIP 1.5 with (R)eset Disks and (Q)uick Repeat ; *r <-- lets try 'R' for R)eset of the disk system ; Resetting all disks to R/W <-- keeping user informed... ; *b:=a:*.lib <-- change any (or all) disks here if you like, ; and start PIP'n to your hearts content... ; COPYING - ; MACRO.LIB ; COPYRGHT.LIB ; *q <-- change disks, and then a little "quickie" ; with Q)uick Repeat... ; ; Repeating: b:=a:*.lib <-- PIP remembers us...amazing ; ; COPYING - ; MACRO.LIB ; COPYRGHT.LIB ; *q <-- change disks again for two "quickies" ; in a row (and no Vitamin-E required) ; Repeating: b:=a:*.lib ; ; COPYING - ; MACRO.LIB ; COPYRGHT.LIB ; * <-- PIP waiting patiently for something else to do... ; ; Alright, now that I have whetted your appetite to incorporate ; this into your PIP,...here's the code to do it ; ; ; ; PIP Patch to add '(R)eset Disks' and '(Q)uick Repeat' function ; bdos equ 05h ; bdos entry address fcb equ 5ch ; default file control block address ; pmessg equ 9 ; print message function rdcbuf equ 10 ; read console buffer function rsetdsk equ 13 ; reset disk system function ; start$pip equ 04ceh ; normal start of pip con$buff equ 1ecbh ; pip's internal console buffer pip$cr$lf equ 082eh ; pip's internal cr/lf output routine pip$prompt equ 053ch ; pip's command parser entry address pip$patch equ 096fh ; pip gets patched at this address ; lf equ 0ah ; line feed character cr equ 0dh ; carriage return character ; org 100h ; jmp begin ; jump over INP:/OUT: vectors and EOF ; org 10ah ; begin: lda fcb+1 ; filename specified? cpi ' ' ; if space character, no file jnz start$pip ; let pip do it's thing if file specified lxi d,msg1 ; and sign in please... call prnt$messg ; print message jmp start$pip ; and off to pip ; added: lxi h,con$buff ; point to pip's console buffer mvi m,128 ; set-up for 128 character command string xchg ; pointer swapped to [DE] for CP/M mvi c,rdcbuf ; read console buffer function call bdos ; let CP/M do the work lda con$buff+1 ; check how many characters typed cpi 1 ; just one? jnz save$char$cnt ; if not, save character count and return lda con$buff+2 ; get single character command ani 05fh ; force to uppercase character cpi 'Q' ; repeat pip function last specified? jnz reset$dsk$sys ; if not, check for reset disk system lhld char$cnt ; get character count shld con$buff+1 ; stuff back to console buffer lxi d,msg3 ; tell'em repeating last process call prnt$messg ; print message lxi h,con$buff+1 ; point to last command entry in console buffer mov c,m ; get command length to calculate offset mvi b,0 ; clean high byte bias inx h ; bump to start of command string address dad b ; add bias to locate end of string mvi m,'$' ; tag end of command string for message lxi d,con$buff+2 ; point to command string for message output call prnt$messg ; print message mvi c,rsetdsk ; reset disk system function call bdos ; let CP/M do the work ret ; "Vulcan Princes...How I love You..." ; - Stanley Clark, 'Return to Forever' ; reset$dsk$sys: ; cpi 'R' ; reset disk system? jnz save$char$cnt ; if not, restore character count and return lxi d,msg2 ; tell'em all disk set R/W call prnt$messg ; print message mvi c,rsetdsk ; reset disk system function call bdos ; let CP/M do the work call pip$cr$lf ; do carriage return/line feed pop h ; clean the stack for pip restart jmp pip$prompt ; do pip '*' prompt and wait for command ; save$char$cnt: ; lhld con$buff+1 ; get character count + character shld char$cnt ; save character count ret ; "Welcome Back My Friends, ; To The Show That NEVER Ends..." ; - Emerson, Lake & Palmer, Brain Salad Surgery ; prnt$messg: ; mvi c,pmessg ; print message function call bdos ; let CP/M do the work ret ; "We May Never Pass This Way Again..." ; - Seals and Crofts, Diamond Girl - ; msg1: db cr,lf,'PIP 1.5 with (R)eset Disks and (Q)uick Repeat',cr,lf,'$' ; msg2: db cr,lf,'Resetting all disks to R/W$' ; msg3: db cr,lf,'Repeating: $' ; char$cnt dw 0 ; console buffer character count ; org pip$patch ; patch to get to added code goes here ; jmp added ; check for reset or repeat command ; ; ; end