aseg ;cp/m 2.2 version dependent ;assemble under rmac ; ;backup floppy for md-11 ;discipline: copy contents of floppy to file on h.d. then to new floppy ; ;ask for source disk ;logon disk ;if disk is not foreign ; if disk is single sided, track 40 else track=80 endif ; if not exist file "a:backup.dsk" ; makefile "a:backup.dsk" ; for x=0 to tracks-1 ; readtrack x ; writefile tracklen ; next x ; closefile ; "finished reading source disk, please remove from drive" ; endif ;*rewind ; "insert formatted destination disk in drive" ; "press any key when ready, or control-c to abort" ; if (getkey)=control-c exit endif ; if disk is foreign, complain and exit ; if disk is single sided track = 40 else track = 80 endif ; compute filesize "a:backup.dsk", convert to track ; if filesize <> track complain and goto rewind ; openfile "a:backup.dsk" ; for x=0 to track-1 ; readfile trackize ; writetrack x ; next x ; closefile ; "care to make another?" ; if (getkey) = "y" goto insert ; else erasefile "a:backup.dsk" ; endif ;else "unable to backup foreign format disks" ;endif ;exit ; ; ;define bios: ; mtabptr equ 44h-3 ;offset to mtab pointer from bios mtabln equ 16 revptr equ 3fh-3 ;revision number ; ;define lomemory bdos equ 5 fcb1 equ 5ch fcb2 equ 6ch tib equ 80h ; ;define bdos functions getkey equ 1 putkey equ 2 print equ 9 getlin equ 10 getvers equ 12 reset equ 13 seldsk equ 14 open equ 15 close equ 16 delete equ 19 read equ 20 write equ 21 make equ 22 setdma equ 26 getdpb equ 31 getusr equ 32 compute equ 35 flush equ 48 direct$bios equ 50 ; ;define direct bios functions bios$func equ 0 read$mtabs equ 3 bios$seldsk equ 9 bios$settrk equ 10 bios$setsec equ 11 bios$setdma equ 12 bios$read equ 13 bios$write equ 14 bios$sectran equ 16 bios$setbnk equ 28 ;define constants seclen equ 1024 maxsec equ 5 reclen equ 128 maxrec equ 5*8 ; ;define bios masks virtual equ 80h foreign equ 40h sides equ 4 harddsk equ 2 ; ;define characters ctlc equ 3 bell equ 7 lf equ 10 cr equ 13 cls equ 1ah esc equ 1bh brt equ '(' dim equ ')' ; org 100h begin: mvi c,getvers call bdos mov a,l cpi 31h jz begin1 call outsti db bell,'requires CP/M Plus',0 ret begin1: call backup rst 0 ;warm boot backup: call outsti db cls,esc,brt db 'MD-11 BACKUP rev 3.0' db 0 lhld 1 mvi l,1 mov a,m inx h mov h,m mov l,a mov a,m cpi 22h ;shld instruction is first in func: jz setup call outsti db cr,lf,bell,'System is not Morrow Micro-Decision with Banked CP/M Plus' rst 0 setup: mvi c,getusr mvi e,-1 call bdos mov a,e sta user mvi c,getusr mvi e,0 ;set user 0 call bdos mvi c,reset call bdos mvi a,harddsk call getmtab ;get [e]=logical drive of harddisk mov a,e inr a ;in fcb format lxi h,bkfcb ;save in fcb mov m,a xchg ;for bdos lxi h,dv1 dcr a add m mov m,a sta dv2 mvi c,open call bdos ;attempt to open file "backup.dsk" inr a ;if file does not exist { jnz exists call outsti db cr,lf,lf,'Insert SOURCE diskette in drive and press any key to backup,' db cr,lf,'or control-C to abort.' db 0 mvi c,getkey call bdos cpi ctlc rz ;exit mvi a,virtual ;find first virtual drive call getmtab ;find the floppy mov a,m ;test foreign ani foreign jz setup1 fgnerr: call outsti ;error, disk is foreign db cr,lf,lf,bell,'Sorry, BACKUP does not support foreign formats.' db cr,lf,'use program FOREIGN to restore drive to Morrow format' db 0 jmp exit setup1: mov a,e ;logical drive sta drive mvi c,seldsk push h call bdos ;login drive pop h mvi c,80 ;80 track mov a,m ani sides jnz setup2 mvi c,40 ;single sided, 40 track setup2: mov a,c sta tracks ;set number of tracks ;file not there, so make one wind: lxi d,bkfcb mvi c,make call bdos inr a jnz wind1 call outsti db cr,lf,lf,bell,'System error, out of directory space on hard disk...' db cr,lf,'(I don''t believe it either, hit RESET and try again,' db cr,lf,' try erasing .BAK files: "ERA *.BAK".)' db 0 jmp exit ;reboot wind1: call outsti db cr,lf,lf,'Reading source disk to file "' dv1: db 'A:BACKUP.DSK"' db 0 mvi a,0 sta ctrk sta currec lxi h,bios$read shld dcmd mvi a,write sta bcmd wind2: ;main readtrack loop lda drive call getxlt shld xlate call rwtrk ;read track into buffer lda bkfcb dcr a call getxlt ;logon hd again (maintain phase with bdos) call rwfile ;write track to file lxi h,ctrk ;current track lda tracks inr m cmp m jnz wind2 ;do until maxtrack mvi c,close lxi d,bkfcb call bdos ;close file inr a ;check for error jnz compl call outsti db cr,lf,lf,bell,'Fatal error, unable to close "BACKUP.DSK"' db 0 jmp kill compl: call outsti db cr,lf,lf,'Completed reading source disk. Please remove from drive.' db 0 jmp rewind exists: call outsti db cr,lf,lf,bell,'WARNING: Previous BACKUP.DSK file already exists.' db cr,lf,'Prepared to create destination diskette.' db cr,lf,lf,'If you do not wish to make another copy of the saved image,' db cr,lf,'you must exit from this program with CONTROL-C, and then use' db cr,lf,'the command ERA BACKUP.DSK before a new diskette may be copied.' db bell,0 rewind: call outsti db cr,lf,lf,'Insert FORMATTED destination disk in drive.' db cr,lf,'Press any key when ready, or CONTROL-C to ABORT' db 0 mvi c,getkey call bdos cpi ctlc jz exit ;exit ;prepare to rewind ;reset drives, and select floppy mvi c,reset call bdos lxi h,bkfcb+12 lxi b,36-12 call clear mvi a,virtual call getmtab mov a,m ani foreign jnz fgnerr mov a,e ;drive sta drive mvi c,seldsk call bdos ;now make sure it is the same format as the original lxi d,bkfcb mvi c,compute call bdos lxi h,currec mvi m,0 inx h ;r0 byte mov e,m mvi m,0 ;clear inx h mov d,m mvi m,0 ;clear inx h mvi m,0 xchg lxi d,-1600 ;1600 records for single sided ora a ;clear carry dad d ;test if equal mov a,h ora l mvi a,40 jz rewind1 mvi a,80 ;80 tracks rewind1: push psw ;save ;now check mtab of destination drive for match mvi a,virtual call getmtab mov a,m ;get mtab byte ani sides mvi c,40 jz rewind4 mvi c,80 rewind4: pop psw cmp c ;compare file size and disk size jz rewind5 mvi a,40 cmp c jnz dsided call outsti db cr,lf,lf,bell,'Your BACKUP.DSK file is for a double sided disk,' db cr,lf,'while the destination diskette is single sided.' db cr,lf,'Change diskettes and run BACKUP again (BACKUP.DSK is preserved.)' db 0 jmp exit dsided: call outsti db cr,lf,lf,bell,'Your BACKUP.DSK file is for a single sided disk,' db cr,lf,'while the destination diskette is double sided.' db cr,lf,'Change diskettes and run BACKUP again (BACKUP.DSK is preserved.)' db 0 jmp exit rewind5: sta tracks ;save number of tracks lxi d,bkfcb mvi c,open call bdos ;we are sure file is there call outsti db cr,lf,lf,'Writing destination diskette from file "' dv2: db 'A:BACKUP.DSK"' db 0 mvi a,0 sta ctrk ;start at track 0 sta currec ;and record zero lxi h,bios$write ;set for track writes shld dcmd mvi a,read ;set for file reads sta bcmd rewind6: lda bkfcb dcr a call getxlt ;logon source drive call rwfile ;do file read lda drive call getxlt shld xlate call rwtrk ;do track write lxi h,ctrk lda tracks inr m ;track++ cmp m jnz rewind6 ;continue until done mvi c,flush mvi e,-1 call bdos ;flush and purge buffers mvi c,close lxi d,bkfcb call bdos ;close the file call outsti db cr,lf,lf,'Completed destination diskette.' db cr,lf,lf,'Do you wish to make another copy from BACKUP.DSK?' db cr,lf,'(note, answering anything but "Y" erases BACKUP.DSK)' db 0 mvi c,getkey call bdos cpi 'Y' jz rewind cpi 'y' jz rewind kill: call outsti db cr,lf,lf,'erasing BACKUP.DSK' db 0 lda bkfcb ;get boot drive dcr a call getxlt ;select it lxi d,bkfcb mvi c,delete call bdos exit: lda bkfcb dcr a ;see if hd is boot disk ora a jz 0 ;exit quietly call outsti db cr,lf,lf,'Insert system diskette, and hit any key to reboot' db 0 mvi c,getkey call bdos xra a ;drive 0 call getxlt ;select boot drive rst 0 ;exit ;subroutines rwtrk: ;read a track into buffer ;disk is selected, xlate is setup lxi h,bufadr shld buffer lxi h,0 ;sector 0 shld tsector call bios db bios$settrk db 0 ctrk: dw 0,0,0 readt1: call bios db bios$sectran db 0 tsector: dw 0 xlate: dw 0,0 shld sector lhld tsector mvi a,maxsec cmp l rz ;done if max sectors inx h shld tsector call bios db bios$setsec db 0 sector: dw 0,0,0 call bios db bios$setbnk db 1 ;tpa dw 0,0,0 call bios db bios$setdma db 0 buffer: dw 0,0,0 lhld buffer lxi d,seclen dad d shld buffer ;advance dma for next sector call bios dcmd: db 0 ;do read or write db 0 dw 0,0,0 ora a ;test for error jz readt1 ;loop til done lda dcmd ;get command cpi bios$read jnz erdwrite call outsti db cr,lf,lf,lf,bell,'Fatal direct track READ error. File BACKUP.DSK incomplete.' db cr,lf,'Error could be in unused sector, use PIP to read files' db cr,lf,'individually to an empty USER area on hard disk.' db 0 jmp kill ;abort, file not complete erdwrite: call outsti db cr,lf,lf,lf,bell,'Fatal direct track WRITE error.' db cr,lf,lf,'REMOVE destination diskette, and replace with another,' db cr,lf,'Then run BACKUP again. (file BACKUP.DSK is preserved)' db 0 jmp exit rwfile: ;enter with data in buffer, drive selected lxi h,bufadr shld buffer lxi h,0 shld sector ;record count writef: lxi h,sector mvi a,maxrec cmp m rz ;exit when done inr m ;record count++ lhld buffer mov e,l mov d,h lxi b,reclen dad b shld buffer mvi c,setdma call bdos lxi d,bkfcb lda bcmd mov c,a call bdos ora a jz writef ;loop until all written lda bcmd cpi write jnz frderr call outsti db cr,lf,lf,lf,bell,'Fatal write error, file BACKUP.DSK incomplete.' db 0 jmp kill ;abort frderr: call outsti db cr,lf,lf,lf,bell,'Fatal read error, or file incomplete',0 jmp exit ;dbios: ;direct bios call push d xchg lhld bios+1 dad d pop d pchl getxlt: ;enter with a=drive to select, exit hl=xlate ;also used as select disk sta sdrv call bios db bios$seldsk db 0 sdrv: dw 0 ;drive to select dw 1 ;secondary select dw 0 mov a,m ;read xlate inx h mov h,m mov l,a ret getmtab: ;find first mtab with single attribute in [a] ;on entry: a=pattern to search for ;on exit, e=locical number of drive, ; hl=mtab of this drive sta mtabmsk call bios db bios$func ;extended function db read$mtabs dw 0 dw mtab$buffer dw 0 lxi h,mtab$buffer lxi b,mtabln lxi d,500h ;5 drives mtablp: mov a,m ;read flags ani 0 ;see if conditions met mtabmsk equ $-1 ;self modifying rnz ;return when met inr e ;drive++ dad b ;ptr++ dcr d ;count-- jnz mtablp call outsti ;issue error, abort db cr,lf,lf,bell,'Unable to find drive address, abort...',0 jmp exit ;abort outsti: pop h mov a,m inx h push h ora a rz mov e,a mvi c,putkey call bdos jmp outsti clear: ;enter with hl-> first byte to clear, bc=length mvi m,0 inx h dcx b mov a,b ora c jnz clear ret bios: pop d ;[de] -> biospb lxi h,8 ;length of biospb dad d ;[hl] = new return address push h mvi c,direct$bios jmp bdos ;storage user ds 1 drive ds 1 tracks ds 2 bcmd ds 1 bkfcb db 1 db 'BACKUP DSK' db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 currec db 0,0,0,0 mtab$buffer equ $ bufadr equ $ end