.lall ;****************************************************************************** ;* * ;* * ;* AAAMM MM PPPPPPPPPPPPP RRRRRRRRRRRR OOOOOOOOOOOOOO * ;* AAAAAMMM MMM PPPPPPPPPPPPP RRRRRRRRRRRR OOOOOOOOOOOOOO * ;* AAA AAA MMM MMM PPP PPP RRR OOO OOO * ;* AAA AAA MMM MMM PPP PPPPPPPPP RRRRRRRRRRRR OOO OOO * ;* AAA AAA MMM MMM PPP PPPPPPPPP RRRRRRRRRRRR OOO OOO * ;* AAA AAA MMM PPP RRR OOO OOO * ;* AAA AAAAAAAAAA M PPP RRR OOOOOOOOOOOOOO * ;* AAA AAAAAAAAAAAA PPP RRR OOOOOOOOOOOOOO * ;* * ;* * ;* * ;* This code was developed for use with AMPRO hardware only. * ;* All other use is prohibited without prior written consent from * ;* AMPRO Computers, Inc. * ;* * ;****************************************************************************** ;* * ;* Ampro tape/disk transfer/back-up program * ;* * ;* Version 2.01 Major changes, save system tracks 12/09/1987 * ;* fixed a couple of bugs * ;* Version 1.0 Initial release 05/20/1987 * ;* * ;* by: Barry Harding * ;* and Joe Silvia * ;* * ;****************************************************************************** ;* * ;* Time & Date for Ampro * ;* Zilog CTC * ;* Requires BIOS ver 3.3 or higher * ;* * ;* When clock is true, a polled real time clock is available. * ;* The LITTLE BOARD must have CTC ZC/TC2 connected to CLK/TRG3: * ;* On assemblies which have the SCSI option, whether populated * ;* or not, short JMP2 pins 1 and 2, and check that JMP2 pins 2 * ;* and 3 are unshorted. NOTE: some boards have a trace between * ;* JMP2 pins 2 and 3 on the bottom of the board, which must be * ;* cut. - On the original LITTLE BOARD, without the SCSI option, * ;* the trace to the CTC, U6, pin 20 must be cut. Then wire U6 * ;* pin 20 to U6 pin 9. * ;* * ;****************************************************************************** page false equ 00h true equ not false maxdrv equ 16 ; thru drive p totpart equ maxdrv*2 ; system and user partition for each lstdrv equ 'A'+maxdrv ; P last Drive in sys clock equ true ; if CTC hdw clock available telvid equ false ; Televideo terminal h19 equ false ; H19 terminal lfeeds equ true ; clear screen, line feeds toggle equ true ; true rewind upon completion tapid equ 040h ; Teac tape drive, SCSI ID 6 hdisk equ 3 ishard equ 0 wiluse equ 1 iserr equ 2 wasuse equ 3 harder equ 4 syspart equ 7 ; this must be bit 7 to work ie the ; assumption that it is in code yeach blocks equ 60 ; blocks/2 = tape buffer in Kb the ; bigger this number the faster xfer ncrcsd equ 20h ; ncr scsi controller equates ncrodr equ 20h ncricr equ 21h ncrmr equ 22h ncrtcr equ 23h ncrcsb equ 24h ncrser equ 24h ncrbsr equ 25h ncrsds equ 25h ncridr equ 26h ncrsdt equ 26h ncrrpi equ 27h ncrsdi equ 27h ncrdac equ 28h boot equ 0 ; warm boot biosvec equ 1 ; start of bios bdos2 equ 2 ; console output byte bdos5 equ 5 ; bdos entry point bdos9 equ 9 ; console output string bdos10 equ 10 ; console input lf equ 10 ; ^J line feed cr equ 13 ; ^M carriage return esc equ 27 ; ^[ escape ofset equ 31 ; H19 cursor offset symbol equ 119 ; H19 graphic X page ;**************************************************** ; ; Macro stuff ; ;**************************************************** grfon: db esc,'F','$' ; enable graphics string grfoff: db esc,'G','$' ; cursor addressing string msga: db ' Tape/Disk ','$' msgb: db ' CP/M Back-up Transfer ','$' msgc: db ' Program.. ','$' linefd: db lf,lf,lf,lf,lf,lf db lf,lf,lf,lf,lf,lf db lf,lf,lf,lf,lf,lf db lf,lf,lf,lf,lf,lf,'$' cls macro ; clear screen ld c,bdos2 ld e,esc call bdos5 ld c,bdos2 if h19 ld e,'E' ; H19 terminal endif if telvid ld e,'*' ; Televideo terminal endif if lfeeds ld de,linefd ; cls with linefeeds ld c,bdos9 endif call bdos5 endm macro1 macro one ; print string ld c,bdos9 ld de,one call bdos5 endm macro2 macro one,two ; print byte ld c,bdos2 ld e,one call bdos5 ld c,bdos2 ld e,two call bdos5 endm cursor macro one,two ; cursor addressing - line, column ld c,bdos2 ld e,one call bdos5 ld c,bdos2 ld e,two call bdos5 endm sym macro ; print graphics character ld c,bdos2 ld e,symbol call bdos5 endm page ;*************************************************** ;*************************************************** ; ; Main entry point. (this is where it all starts) ; ;*************************************************** ;*************************************************** begin: ld (spsave),sp ; establish local stack ld sp,(06h) if h19 cls ; clear screen macro1 grfon ; enable H19 graphics ld d,60+ofset ; start column rpt1: macro2 esc,'Y' ; enable cursor addressing cursor 32,d ; put cursor sym ; put 'X' dec d ; move cursor ld a,20+ofset ; end column cp d ; do they match jp z,fini1 ; 1 = finished jp rpt1 ; 0 = no go back for more fini1: ld d,2+ofset ; start line rpt2: macro2 esc,'Y' ; enable cursor addressing cursor d,21+ofset ; put cursor ld c,bdos2 ; console output byte ld e,symbol ; graphics character call bdos5 ; do it inc d ; move cursor ld a,9+ofset ; end line cp d ; do they match jp z,fini2 ; 1 = finished jp rpt2 ; 0 = no go back for more fini2: ld d,21+ofset ; start column rpt3: macro2 esc,'Y' ; enable cursor addressing cursor 9+ofset,d ; put cursor ld c,bdos2 ; console output byte ld e,symbol ; graphics character call bdos5 ; do it inc d ; move cursor ld a,61+ofset ; end column cp d ; do they match jp z,fini3 ; 1 = finished jp rpt3 ; 0 = no go back for more fini3: ld d,8+ofset ; start line rpt4: macro2 esc,'Y' ; enable cursor addressing cursor d,60+ofset ; put cursor ld c,bdos2 ; console output byte ld e,symbol ; graphics character call bdos5 ; do it dec d ; move cursor ld a,1+ofset ; end line cp d ; do they match jp z,fini4 ; 1 = finished jp rpt4 ; 0 = no go back for more fini4: macro1 grfoff ; disable graphics macro2 esc,'p' ; enable reverse video macro2 esc,'Y' ; enable cursor addressing macro2 34,67 ; put cursor macro1 msga ; print title line 1 macro2 esc,'Y' ; enable cursor addressing macro2 36,61 ; put cursor macro1 msgb ; print title line 2 macro2 esc,'Y' ; enable cursor addressing macro2 38,67 ; put cursor macro1 msgc ; print title line 3 macro2 esc,'q' ; disable reverse video macro2 esc,'Y' ; enable cursor addressing macro2 54,32 ; put cursor ld bc,0fffh delay1: ld d,7fh dec bc ld a,1 cp b jp z,main delay2: dec d ld a,1 cp d jp nz,delay2 jp delay1 endif ;******************************************* ; copy bios table ; so we can use local labels to call the bios ;******************************************* main: ld hl,(biosvec) ; get start of bios ld de,jmptbl ; dest of ldir ld bc,sizetbl ; size of table ldir ; move the table ;******************************************* ; copy bios ampro extended table ; so we can use local labels to call the bios ;******************************************* call next ; get address of table in hl ld de,swap ; dest add of table ld bc,sz_tbl ; size of table ldir ; move the table ;******************************************** ; Main cmd loop ;******************************************** main1: cls ; clear screen ld de,sign ; print version call print call clrstat ; clear drive status call gethard ; find out which disks are hard disks ;*************************************** ; Main loop: ; print current options ; print select menu ; loop waiting for cmd ;*************************************** call showsys ; show selected systems call showhard ; show user all hard disks call showsel ; show selected drives call showdate ; show date call showcomm ; and comment fields ld de,mree ; print rewind at end option ld c,bdos9 call bdos5 ld a,(lastrew) ; is rewind at end on or a jr nz,reeoff ; no then jmp because opt on ld de,moff ; show rewind option off jr reem reeoff: ld de,moni ; show rewind option reem: ld c,bdos9 call bdos5 ;******************************* ; print menu ;******************************* ld de,help ; print help menu call print mloop: ld de,msg1 ; print prompt msg call print call bell ;****************************** ; get buffered input from user ;****************************** ld c,bdos10 ; get cmd char ld de,inbuf call bdos5 ld a,(insiz) ; jmp if no input or a jp z,main1 ld a,(chin) ;****************************** ; find opt from all legal ones ;****************************** cp 'a' ; tape to disk jp z,tapdis cp 'A' jp z,tapdis cp 'b' ; disk to tape jp z,distap cp 'B' jp z,distap cp 'c' ; tape directory jp z,dodir cp 'C' jp z,dodir cp 'd' ; select disk drives jp z,slect cp 'D' jp z,slect cp 'e' ; toggle rewind jp z,tree cp 'E' jp z,tree if not clock cp 'f' ; enter date jp z,edate cp 'F' jp z,edate endif cp 'g' ; enter comment jp z,ecomm cp 'G' jp z,ecomm cp 'h' ; rewind tape jp z,rewind cp 'H' jp z,rewind cp 'i' ; prewind tape jp z,prewind cp 'I' jp z,prewind cp 'j' ; erase tape jp z,erase cp 'J' jp z,erase cp 'k' ; display tape status jp z,sens cp 'K' jp z,sens cp 'x' ; warm boot jp z,done cp 'X' jp z,done ;************************************ ; unknown option so ask again ;************************************ jp main1 ; return to menu ;******************************************** ;******************************************** ; ; transfer selected disks to tape ; ;******************************************** ;******************************************** distap: call newcas ; was a new tape just put in ld de,tdmsg1 ; print user msg call print ;************************************ ; set up loop as follows: ; reg function ; HL index into select table ; B Max partions to do ; A current drive ; (anerror) set if error accured in loop ;************************************ ld hl,drives ; setup select loop ld b,totpart ; we will do system and data parts xor a distlop: bit wiluse,(hl) ; did user select this drive jp z,distnxt ; no jmp ld (curdpar),hl ; we will do this drive push af push bc push hl ;********************************** ; select drive and get param table ;********************************** ld c,a ; set the drive number in the header add a,'A' ; setup tape header for this drive ld (ddrive),a ld e,1 ; make bios think frst time sel call seldsk ld a,h ; was there a select error or l jr nz,noerr ; no then jmp ;********************************** ; there was a select error ;********************************** ld a,0ffh ld (anerror),a pop hl ; select error so pass this drive pop bc pop af set iserr,(hl) jr distnxt noerr: ld de,0ah ; get and copy the dpb add hl,de ld e,(hl) inc hl ld d,(hl) push de pop hl ld de,sectrk ; do the copy ld bc,000fh ldir ; move it ;*********************************** ; setup values for header and xfer ;*********************************** xor a ; zero out curent sector ld h,a ld l,a ld (cursec),hl ld hl,(dsize) ; convert # grps to # sectors in drive ld a,(bshift) ld b,a gtoslop: add hl,hl ; shift left once djnz gtoslop ld (sleft),hl ; save this in secs remaining ld bc,(offset) ; starting track ld (ctrk),bc ;***************************** ; if this is system then fix offset and size ;***************************** ld hl,(curdpar) bit syspart,(hl) jr z,dtnsys ld hl,(sectrk) ; we will do 2 trks ; this is a kluge that will have to ; change if # of sys trks chng add hl,hl ld (sleft),hl ld hl,ddrive ; mark drive letter as system set syspart,(hl) xor a ld h,a ld l,a ld (ctrk),hl ;*********************************** ; write directory header to tape ;*********************************** dtnsys: ld de,ddrive ; write the header out ld a,1 ; size of transfer call wwrite jr z,noerr2 ;*********************************** ; we got an error ;*********************************** ld a,0ffh ld (anerror),a pop hl pop bc pop af set iserr,(hl) jp w_rterr ;*********************************** ; Write the drive to tape ;*********************************** noerr2: call dtxlop ; do the disk xfer jr nz,w_rterr ;*********************************** ; Tell user that this drive was done ok ;*********************************** ld a,(ddrive) res syspart,a ld (tdmsg2),a call bell ld de,tdmsg2 call print pop hl pop bc pop af ;*********************************** ; Next drive ?? ;*********************************** distnxt: inc hl inc a cp maxdrv jr nz,dnof xor a dnof: dec b jp nz,distlop ;*********************************** ; user select rewind at end ?? ;*********************************** ld a,(lastrew) or a call nz,drewind ;*********************************** ; Tell user of any errors ;*********************************** ld a,(anerror) or a call nz,shwdserr jp main1 ; return to menu curdpar: dw 0 anerror: db 0 ;********************************** ; tape write error routines ;********************************** w_rterr: ld de,unre_wrt ; unrecoverable tape write error call print waitmain: call bell ld c,bdos10 ld de,inbuf call bdos5 jp main1 ; return to menu unre_wrt: db cr,'*** Unrecoverable tape write error' db ' - hit RETURN for menu: $' r_rterr: ld de,unre_rd ; unrecoverable tape read error call print jr waitmain unre_rd: db cr,lf,'Unrecoverable tape read error' db ' - Hit return for menu: $' r_rnodrv: ld de,unre_ndrv ; drive not found error call print jp waitmain unre_ndrv: db cr,'*** Drive not found on Tape' db ' - Hit return for menu: $' ;******************************************** ;******************************************** ; ; transfer selected tape dives to disk ; ;******************************************** ;******************************************** tapdis: call newcas ; was a new tape just put in ld de,tdmsg1 call print ;************************************ ; set up loop as follews: ; reg function ; HL index into select table ; B Max partions to do ; A current drive ; (anerror) set if error accured in loop ;************************************ ld hl,drives ; setup select loop ld b,totpart ; we will do system and data parts xor a taplop: bit wiluse,(hl) ; did user elect to restore this drive jp z,tapnxt ld (curdpar),hl ; we will do this drive push af push bc push hl ;********************************** ; select drive and get param table ;********************************** ld c,a ; set the drive number in the header add a,'A' ld (ddrive),a ld e,1 ; make bios think frst time sel call seldsk ld a,h or l jr nz,n2oerr ;********************************** ; there was a select error ;********************************** ld a,0ffh ld (anerror),a pop hl ; this is select error pass this drive pop bc pop af set iserr,(hl) jr tapnxt n2oerr: ld de,0ah ; get and copy the dpb add hl,de ld e,(hl) inc hl ld d,(hl) push de pop hl ld de,sectrk ; do the copy ld bc,000fh ldir ;*********************************** ; setup values for header and xfer ;*********************************** xor a ; zero out curent sector ld h,a ld l,a ld (cursec),hl ld hl,(dsize) ; convert # grps to # sectors in drive ld a,(bshift) ld b,a gtoslp: add hl,hl ; shift left once djnz gtoslp ld (sleft),hl ; save this in secs remaining ld bc,(offset) ; starting track ld (ctrk),bc ;***************************** ; if this is system then fix offset and size ;***************************** ld hl,(curdpar) bit syspart,(hl) jr z,tdnsys ld hl,(sectrk) ;we will do 2 trks ;this is a kluge that will have to ;change if # of sys trks change add hl,hl ld (sleft),hl ld hl,ddrive ;mark drive letter as system set syspart,(hl) xor a ld h,a ld l,a ld (ctrk),hl ;********************************** ; search for this drive on the tape ;********************************** tdnsys: call search ; search for the selected drive on tape jr z,n3oerr ;********************************** ; search drive not found on tape ;********************************** pop hl ; we got an error pop bc pop af set iserr,(hl) jp r_rnodrv ;********************************** ; do the xfer ;********************************** n3oerr: call ttxlop ; do the disk xfer jp nz,r_rterr ;********************************** ; flush the BIOS buffer ;********************************** ld bc,(offset) call settrk xor a ld b,a ld c,a call setsec call read ;********************************** ; tell the user we did this drive ;********************************** ld a,(ddrive) res syspart,a ;strip it off in case ld (tdmsg2),a call bell ld de,tdmsg2 call print pop hl pop bc pop af tapnxt: inc hl ; check for next drive inc a ; inc drv # cp maxdrv jr nz,tnof xor a tnof: dec b jp nz,taplop ;********************************** ; do we do rewind after oper. ;********************************** ld a,(lastrew) or a call nz,drewind ;********************************** ; show errors if any. ;********************************** ld a,(anerror) or a call nz,shwdserr jp main1 ; return to menu tdmsg1: db cr,lf,'Drives Completed: $' tdmsg2: db ' $' ;************************************ ;************************************ ; ; inc thru drive until data is xfered ; disk to tape copy loop ; ;************************************ ;************************************ dtxlop: call readbuf ; fill the buffer from disk ld a,blocks ; xfer siz ld de,dbuff call wwrite ;write to tape jp nz,taperr ld hl,(sleft) ld a,l or h jr nz,dtxlop ;*********************************** ; Write the file mark to tape ;*********************************** call dfilem jp nz,taperr xor a ret taperr: ld hl,(curdpar) set iserr,(hl) ld a,0ffh ld (anerror),a xor a cpl ret ;************************************ ;************************************ ; ; inc thru drive until data is xfered ; tape to disk copy loop ; ;************************************ ;************************************ ttxlop: ld a,blocks ; xfer siz ld de,dbuff call wread ;read the tape jp nz,taperr call wrtbuf ; write the disk buffer ld hl,(sleft) ld a,l or h jr nz,ttxlop call skipfil ret sleft: dw 0 ; sectors to go on drive cursec: dw 0 ; starting sector ctrk: dw 0 ;******************************************* ;******************************************* ; read one blocks buffer from ; disk or remaining if less ; then blocks. this loops calling ; the bios to fill the buffer ; this routine uses the following ; name use ; sleft # of 128 byte blks left to xfer ; xfersz size of xfer we will actually do in 128b blks ; dbuff place that data is read into ; xferad address of next xfer within bduff ; cursec current sector on disk ; ctrk current track on disk ; sectrk # sectors per cpm track ; curdpar current status byte for drive ;******************************************* ;******************************************* readbuf: ld hl,(sleft) ld de,blocks*512/128 ;cpm sectors scf ccf sbc hl,de ;sleft-(blocks*512/128) jr nc,en_left ;*************************** ; we can only do sleft size ;*************************** ld hl,(sleft) ld (xfersz),hl jr en_don ;*************************** ; we have enough for blocks left ;*************************** en_left: ld hl,blocks*512/128 ld (xfersz),hl en_don: ld bc,dbuff-128 ; setup starting dma ld (xferad),bc ld bc,(ctrk) call settrk ;*************************** ; prime bios with address track and sector ;*************************** read_lop: ld bc,(xferad) ld hl,128 add hl,bc ld (xferad),hl push hl pop bc call setdma ld bc,(cursec) push bc ;will be used in hl call setsec ;**************************** ; inc the track sector value ;**************************** pop de ; was current sector in bc inc de ;**************************** ; are we at end of a track ;**************************** ld hl,(sectrk) inc hl scf ccf sbc hl,de jr nz,secok ;no then jmp ld hl,(ctrk) inc hl ld (ctrk),hl push hl pop bc call settrk ld de,0 secok: ld (cursec),de call read ; do the disk read or a jp z,readok ld hl,(curdpar) ; set the error bit for this drive set harder,(hl) ld a,0ffh ld (anerror),a readok: ld hl,(sleft) ; up-date sleft and xfersz dec hl ld (sleft),hl ld hl,(xfersz) dec hl ld (xfersz),hl ld a,l or h jr nz,read_lop ret ;******************************************* ;******************************************* ; write one blocks buffer from ; disk or remaining if less ; then blocks. this loops calling ; the bios to fill the buffer ; this routine uses the following ; name use ; sleft # of 128 byte blks left to xfer ; xfersz size of xfer we will actually do in 128b blks ; dbuff place that data is read into ; xferad address of next xfer within bduff ; cursec current sector on disk ; ctrk current track on disk ; sectrk # sectors per cpm track ; curdpar current status byte for drive ;******************************************* ;******************************************* wrtbuf: ld hl,(sleft) ld de,blocks*512/128 ;cpm sectors scf ccf sbc hl,de ; sleft-(blocks*512/128) jr nc,en2_left ;*************************** ; we can only do sleft size ;*************************** ld hl,(sleft) ld (xfersz),hl jr en2_don ;*************************** ; we have enough for blocks left ;*************************** en2_left: ld hl,blocks*512/128 ld (xfersz),hl en2_don: ld bc,dbuff-128 ; setup starting dma ld (xferad),bc ld bc,(ctrk) call settrk ;*************************** ; prime the bios with address track and sector ;*************************** read2_lop: ld bc,(xferad) ld hl,128 add hl,bc ld (xferad),hl push hl pop bc call setdma ld bc,(cursec) push bc ; will be used in hl call setsec ;**************************** ; inc the track sector value ;**************************** pop de ; was current sector in bc inc de ; inc the track sector value ld hl,(sectrk) inc hl scf ccf sbc hl,de jr nz,se2cok ;**************************** ; are we at end of a trck ;**************************** ld hl,(ctrk) inc hl ld (ctrk),hl push hl pop bc call settrk ld de,0 se2cok: ld (cursec),de ld c,0 ; do the disk read call write or a jp z,r2eadok ld hl,(curdpar) ; set the error bit for this drive set harder,(hl) ld a,0ffh ld (anerror),a r2eadok: ld hl,(sleft) ; up-date sleft and xfersz dec hl ld (sleft),hl ld hl,(xfersz) dec hl ld (xfersz),hl ld a,l or h jr nz,read2_lop ret xfersz: dw 0000h xferad: dw 0000h ;*********************************************** ;*********************************************** ; ; display tape headers ; ;*********************************************** ;*********************************************** dodir: call newcas ; do the direct call drewind call shwdir ld a,(lastrew) or a call nz,drewind jp mloop shwdir: ;***************************** ; read the headers off tape ;***************************** ld de,d2drive ; show a tape directory ld a,1 call wread ret nz ;end of tapes data ;***************************** ; show headers to user ;***************************** ld a,(d2drive) ; show the drive bit syspart,a jr nz,shwsys ld (tdrv1),a ld de,sdrv1 call print jr shwdon shwsys: res syspart,a ld (tsys1),a ld de,ssys1 call print shwdon: ld de,mdsiz1 ; show dsize call print ld hl,(d2size) call error2 ld de,mscttrk ; show sectors a track call print ld hl,(s2ectrk) call error2 ld de,moff1 ; show trk offset call print ld hl,(o2ffset) call error2 ld de,crlf call print ld de,d2bin ; show the date call print ld de,crlf call print ld de,c2ommin ; show user comment call print call skipfil ; skip to next file mark ret nz call bell jr shwdir sdrv1: db cr,lf,'Disk Drive:' tdrv1: db ' $' ssys1: db cr,lf,'Disk Systm:' tsys1: db ' $' mdsiz1: db ' Total Groups:$' mscttrk: db ' Sectors/Track:$' moff1: db ' System Tracks:$' ;******************************************** ;******************************************** ; ; search for drive on tape sel by user ; if not found or tape err return error ; ;******************************************** ;******************************************** search: ld de,d2drive ld a,1 call wread ret nz ld a,(ddrive) ; is this the right drive ld hl,d2drive cp (hl) jp nz,fskip ld hl,(sectrk) ; check if this is the right drive ld de,(s2ectrk) scf ccf sbc hl,de jp nz,fskip ld a,(bshift) ld hl,b2shift cp (hl) jp nz,fskip ld hl,(dsize) ld de,(d2size) scf ccf sbc hl,de jp nz,fskip ld hl,(offset) ld de,(o2ffset) scf ccf sbc hl,de jp nz,fskip xor a ; we found the drive ret fskip: call skipfil ; skip to next file mark ret nz jr search ;****************************************** ;****************************************** ; ; if a new tape insert do rewind ; this code does some tricky and undocumented ; things since the drive does not act as doc ; when a new casset is first loaded ; ;****************************************** ;****************************************** newcas: call werror ; get tape status jr nz,aftrew ld a,(stasens) cp 0ffh ;this status byte is a bug in drive!! jr z,pos_rew cp 06h ;this means new load jr z,do_rew ret pos_rew: call werror ;we got the strang stat now for real 1 jr nz,aftrew ld a,(stasens) cp 06h ;this means new load ret nz do_rew: call drewind jr nz,dorerr aftrew: ld b,40h ;we must delay for drive to see tape ;another bug from teac (settle time)?? drlop: djnz drlop jr newcas dorerr: ld de,dorwerr ;posible bad tape in drive call print ret dorwerr: db cr,lf,'rewind error on newly insterted tape',cr,lf,'$' edate: ; enter user date if not clock ld de,mdat call print ld de,datebuff ld c,bdos10 call bdos5 endif jp main1 ; return to menu ecomm: ld de,mcom ; enter user comment call print ld de,commbuff ld c,bdos10 call bdos5 jp main1 ; return to menu ;************************************ ;************************************ ; ; select new drives ; ;************************************ ;************************************ slect: ld hl,drives ; clear all selected drives ld b,totpart slclelop: res wiluse,(hl) inc hl djnz slclelop ld de,msel ; select new drives call print ld c,bdos10 ; get selected drives ld de,inbuf call bdos5 ld a,(insiz) ;jmp if no input or a jp z,selsysd ld a,(insiz) ld b,a ld hl,chin ;******************** ; check range of input ;******************** sulop: res 5,(hl) ;make upper case ld a,(hl) cp 'A' jp m,main1 ;bad value bail out cp lstdrv jp p,main1 ;bad value bail out inc hl djnz sulop ld a,(insiz) ; select user drives ld b,a ld de,udrvs ld hl,chin setslelop: ld a,(hl) sub 'A' push hl ld l,a xor a ld h,a add hl,de bit ishard,(hl) jr nz,okh1 pop hl ld de,pause_a call pause1 jp main1 okh1: set wiluse,(hl) pop hl inc hl djnz setslelop ;******************** ; input system backups ;******************** selsysd: ld de,mselsys ; select new drives call print ld c,bdos10 ; get selected systems ld de,inbuf call bdos5 ld a,(insiz) ;jmp if no input or a jp z,main1 ld a,(insiz) ld b,a ld hl,chin ;******************** ; check range of input ;******************** sslop: res 5,(hl) ;make upper case ld a,(hl) cp 'A' jp m,main1 ;bad value bail out cp lstdrv jp p,main1 ;bad value bail out inc hl djnz sslop ld a,(insiz) ; select user drives ld b,a ld de,drives ld hl,chin sstslelop: ld a,(hl) sub 'A' push hl ld l,a xor a ld h,a add hl,de bit ishard,(hl) jr nz,okh2 pop hl ld de,pause_a call pause1 jp main1 okh2: set wiluse,(hl) pop hl inc hl djnz sstslelop jp main1 ; return to menu ;****************************** ;****************************** ; ; toggle rewind on end ; ;****************************** tree: ld a,(lastrew) ; togle rewind at end cpl ld (lastrew),a jp main1 ; return to menu ;****************************** ;****************************** ; ; get hard drives for user ; ;****************************** ;****************************** gethard: ld b,totpart ; number of drive in cpm xor a ; start with a drv (0) ld hl,drives ; base of defalt table setdelop: push af push hl call paget ; call bios paget ld a,(hl) ; get drive type cp hdisk ; is this hard disk pop hl ; restor drv defalt tbl pointer jr nz,nothard ; no jmp set ishard,(hl) ; set bit if a hard disk nothard: pop af ; restor drive # inc hl ; next tbl entry inc a ; next drive cp maxdrv jr nz,nh1 xor a nh1: djnz setdelop ret ;****************************** ;****************************** ; ; show the hard drives to user ; ;****************************** ;****************************** showhard: ld de,hdisks ; print title of line call print ld a,'A' ; start with first DRV A ld hl,udrvs ; base of default tbl showlop: bit ishard,(hl) ; is this a hard drive jr z,not1hard ; no then jmp push hl ; save default tbl push af ; save current drv leter ld e,a ; print drive letter ld c,02h ; print a char call bdos5 pop af ; restor drive letter pop hl ; restor default tbl pointer not1hard: inc hl ; next default tbl entry inc a ; next DRV letter cp lstdrv ; past last drive jr nz,showlop ; no jmp back again ld de,crlf call print ret ;****************************** ;****************************** ; ; show the hard drives to user ; ;****************************** ;****************************** shwdserr: ld de,dserr ; print title of line call print ld a,'A' ; start with first DRV A ld hl,drives ; base of default tbl ld b,totpart s1howlop: bit harder,(hl) ; is this a hard drive jr z,not2hard ; no then jmp push hl ; save default tbl push af ; save current drv leter push bc ; save drv count ld e,a ; print drive letter ld c,02h ; print a char call bdos5 pop bc ;restore drv count pop af ; restor drive letter pop hl ; restor default tbl pointer not2hard: inc hl ; next default tbl entry inc a ; next DRV letter cp maxdrv+'A' jr nz,senof ld a,'A' senof: dec b jr nz,s1howlop ; no jmp back again ld de,rd_dsk_er pause1: push de call bell pop de call print ld c,bdos10 ld de,inbuf call bdos5 ret pause_a: db cr,lf,'Invalid drive selection - hit RETURN for menu $' rd_dsk_er: db cr,lf,' - Hit RETURN for menu: $' dserr: db 'Disk Errors: --> ','$' ;****************************** ;****************************** ; ; show the selected system drives to user ; ;****************************** ;****************************** showsel: ld de,showsys2 ; print header call print ld hl,drives ; loop through default table xor a showsslop: bit wiluse,(hl) ; is it selected jr z,notsys ; not selected jmp ld e,'^' ; print ^ if selected jr nxtsys notsys: ld e,' ' ; print space if not selected nxtsys: push af push hl ld c,02h call bdos5 pop hl pop af inc hl ; inc and jump back for next inc a cp maxdrv jr nz,showsslop ld de,crlf call print ld de,crlf call print ret ;****************************** ;****************************** ; ; show the selected drives to user ; ;****************************** ;****************************** showsys: ld de,showdrvs ; print header call print ld hl,udrvs ; loop through default table xor a showsulop: bit wiluse,(hl) ; is it selected jr z,notsel ; not selected jmp ld e,'v' ; print v if selected jr nxtsel notsel: ld e,' ' ; print space if not selected nxtsel: push af push hl ld c,02h call bdos5 pop hl pop af inc hl ; inc and jump back for next inc a cp maxdrv jr nz,showsulop ld de,crlf call print ret showdrvs: db 'Selected drives for back-up: $' hdisks: db 'Hard disks available for back-up: --> $' showsys2: db 'Selected system for back-up: $' ;*********************************** ;*********************************** ; ; show user the date ; ;*********************************** ;*********************************** showdate: if not clock ld a,(datebuff+1) ; get # of chars input ld hl,dbin ; start of actual buffer ld c,a xor a ld b,a add hl,bc ; set pointer to end of buffer ld (hl),'$' ; put $ in for bdos 9 ld de,datmsg call print ld de,dbin call print ld de,crlf call print endif ;*********************************** ; CTC time date routine ;*********************************** if clock ; get CTC time ld hl,0 call tod ; get clock base address ld de,s_ec ; move time ld bc,6 ldir ; save time ld de,datebuff+1 shdate: push de ; address of output buffer to fill call j2md ; convert julian date to month/day ld a,(tmonth) dec a ; adjust ld e,a add a,a ; times 2 add a,e ; times 3 ld e,a ld d,0 ld hl,amonths ; find month in string add hl,de ld de,mon ld bc,3 ; move 3 bytes ldir ld a,(tday) call binasc ld (day),bc ld a,(y_ear) call binasc ld (yr),bc shtime: ld a,(s_ec) ; get seconds count call binasc ; convert to ascii ld (sc),bc ; save seconds ld a,(m_in) ; get minutes count call binasc ; convert to ascii ld (mn),bc ; save minutes ld a,(hour) ; get hours call binasc ; convert to ascii ld (hr),bc ; save hours pop de ld hl,curdat ;move table for user ld bc,shd_siz+1 ldir ld de,dbin call print endif ret curdat: db shd_siz ;count of chars db 'Date of back-up: ' mon: db ' ' day: db ' , 19' yr: db ' , ' curtim: db 'at ' hr: db ' :' mn: db ' :' sc: db ' ' db cr,lf db '$' shd_siz equ $-(curdat+1) ;************************************** ;************************************** ; ; convert binary to ascii ; in: a - binary value ; out: bc - ascii character (low high) ; ;************************************** ;************************************** binasc: ld c,0 ; init count ld b,10 bin1: sub b jp c,binext inc c jp bin1 binext: add a,b ; a = ones digit c = tens digit add a,'0' ld b,a ld a,c add a,'0' ld c,a ret ; convert julian to month/day j2md: ld de,mths ; int month pointer ld hl,(jday) ; julian day in 'hl' inc hl ; adjust for ordinal 0 xor a ld b,a ; init high byte of sub with 0 inc a ld (tmonth),a ; init month to 1 j2md1: ld a,(de) or a ; clear carry ld c,a ld a,l ; may be day dw 42edh ; sbc hl,bc jp c,j2md2 jp z,j2md2 ld a,(tmonth) inc a ; update month ld (tmonth),a inc de jp j2md1 j2md2: ld (tday),a ; set day ret datmsg: db 'Date of operation: $' mths: db 31,29,31,30,31,30,31,31,30,31,30,31 amonths: db 'JanFebMarAprMayJunJulAugSepOctNovDec' ;************************************ ;************************************ ; ; show user comment ; ;************************************ ;************************************ showcomm: ld a,(commbuff+1) ; get # of chars input ld hl,commin ; start of actual buffer ld c,a xor a ld b,a add hl,bc ; set pointer to end of buffer ld (hl),'$' ; put $ in for bdos 9 ld de,commmsg call print ld de,commin call print ld de,crlf call print ld de,crlf call print ret commmsg: db 'Comment:',cr,lf,'$' sens: ld de,crlf ; sens tape status call print call werror cp 1 jr z,senserr call dispsens jp mloop senserr: ld de,err1 call print jp mloop rewind: call newcas ; rewind tape call drewind jp z,mloop ld de,reerr call print jp mloop erase: call newcas call derase ; erase tape jp z,mloop ld de,eeerr call print jp mloop prewind: call newcas ; prewind tape call dprewind ; do prewind jp z,mloop ld de,preerr call print jp mloop dispsens: cls ; display sens data ld hl,endstat ld a,(hl) push hl call error1 pop hl bit 7,(hl) jr z,noval ld de,msg3 call print noval: ld de,crlf call print inc hl ld a,(hl) push hl call error1 pop hl ld de,crlf call print inc hl ld a,(hl) push hl call error1 pop hl bit 7,(hl) jr z,nofmk ld de,msg4 call print nofmk: bit 6,(hl) jr z,noeom ld de,msg5 call print noeom: ld a,(hl) and 0fh cp 0 jr nz,notsen ld de,msg6 call print notsen: cp 2 jr nz,notcass ld de,msg7 call print notcass: cp 3 jr nz,nomed ld de,msg8 call print nomed: cp 4 jr nz,nohard ld de,msg9 call print nohard: cp 5 jr nz,noill ld de,msg10 call print noill: cp 6 jr nz,noatt ld de,msg11 call print noatt: cp 7 jr nz,noprot ld de,msg12 call print noprot: cp 8 jr nz,nonodat ld de,msg13 call print nonodat: cp cr jr nz,noover ld de,msg14 call print noover: ld de,crlf call print inc hl ld a,(hl) push hl call error1 ; byte 3 pop hl ld de,crlf call print inc hl ld a,(hl) push hl call error1 ; byte 4 pop hl ld de,crlf call print inc hl ld a,(hl) push hl call error1 ; byte 5 pop hl ld de,crlf call print inc hl ld a,(hl) push hl call error1 ; byte 6 pop hl ld de,crlf call print inc hl ld a,(hl) push hl call error1 ; byte 7 pop hl ld de,crlf call print inc hl ld a,(hl) push hl call error1 pop hl bit 2,(hl) jr z,nosta ld de,msg15 call print nosta: bit 1,(hl) jr z,nohol ld de,msg16 call print nohol: bit 0,(hl) jr z,nopar ld de,msg17 call print nopar: ld de,crlf call print ld de,crlf call print inc hl ld a,(hl) push hl call error1 pop hl ld de,crlf call print inc hl ld a,(hl) push hl call error1 pop hl bit 7,(hl) jr z,nocld ld de,msg20 call print nocld: bit 6,(hl) jr z,nowpt ld de,msg21 call print nowpt: bit 5,(hl) jr z,nobom ld de,msg22 call print nobom: bit 4,(hl) jr z,norun ld de,msg23 call print norun: bit 3,(hl) jr z,nostrm ld de,msg24 call print nostrm: ld de,crlf call print ld de,msg25 call print inc hl ld d,(hl) inc hl ld e,(hl) push hl push de pop hl call error2 pop hl ld de,crlf call print ld de,msg26 call print inc hl ld d,(hl) inc hl ld e,(hl) push hl push de pop hl call error2 pop hl ld de,crlf call print ld de,msg27 call print inc hl ld a,(hl) push hl call error1 pop hl ld de,crlf call print ld de,msg28 call print inc hl ld d,(hl) inc hl ld e,(hl) push de pop hl call error2 ld de,crlf call print ret ;************************************** ; ring bell ;************************************** bell: ld c,bdos2 ld e,7 call bdos_5 ret ;*************************************** ; print a string ;*************************************** print: ld c,bdos9 call bdos_5 ret bdos_5: push de push bc push hl push af call bdos5 pop af pop hl pop bc pop de ret ;************************************ ;************************************ ; error ; de = msg to output ; a = number to output ; error1 ; a = number to output ; error2 ; hl = number to output ;************************************ ;************************************ error: push af call print pop af error1: push af rrca rrca rrca rrca call hexot pop af hexot: and 0fh add a,'0' cp '9'+1 jr c,prt add a,07h prt: ld c,02h ld e,a call bdos5 ret error2: ld a,h push hl call error1 pop hl ld a,l call error1 ret ;****************************************** ; clrstatus from prev cmds ;****************************************** clrstat: ld b,totpart ld hl,drives clrslop: res iserr,(hl) djnz clrslop xor a ld (anerror),a ret ;****************************************** ; low level scsi tape cmd's ;****************************************** drewind: ld hl,rwdcmd ; rewind ld de,dbuff ld a,tapid call scsi and 3h ret rwdcmd: db 01h db 00h db 00h db 00h db 00h db 00h skipfil: ld hl,blk_c ; blkspac ld de,dbuff ld a,tapid call scsi and 3h ret blk_c: db 011h db 01h db 00h db 00h blks1: db 01h db 00h derase: ld hl,eracmd ; erase ld de,dbuff ld a,tapid call scsi and 3h ret eracmd: db 02h db 00h db 00h db 00h db 00h db 00h dfilem: ld hl,wfmcmd ; dfilem write 1 file marks ld de,dbuff ld a,tapid call scsi and 3h ret wfmcmd: db 010h db 00h db 00h db 00h db 01h ; this is times 1 db 00h dprewind: ld hl,prwdcmd ; prewind ld de,dbuff ld a,tapid call scsi and 3h ret prwdcmd: db 01bh db 00h db 00h db 00h db 03h db 00h ; wread ; de = address of buffer to read wread: ld (rleng),a ; a = # of blks to move ld hl,wred ld a,tapid call scsi errd: and 03h ; Was there an error ret wred: db 08h db 01h db 0 db 0 rleng: db 0 db 0 ; ************************************ ; werror ; We still seem to have control over the scsi ; port so just return error code ; Get error status from scsi port ; ************************************ werror: ld hl,statcmd ; This is comp of cmd 3 ld de,endstat ld a,tapid call scsi and 03h ret nz ; Get error status from scsi port ld hl,astatcmd ; This is comp of cmd 3 ld de,aendstat ld a,tapid call scsi and 03h jr nz,wferror xor a ret statcmd: db 03h db 00h db 00h db 00h db 9 db 00h astatcmd: db 06h db 00h db 00h db 00h db 9 db 00h endstat: db 0 ; valid db 0 ; fill stasens: db 0 ; sense db 0 ; info msb db 0 ; info db 0 ; info db 0 ; info lsb db 0 ; fill db 0 ; hardware aendstat: db 0 ; valid db 0 ; fill db 0 ; sense db 0 ; info msb db 0 ; info db 0 ; info db 0 ; info lsb db 0 ; fill db 0 ; hardware wferror: xor a inc a ret ; ************************************** ; de = address of buffer to write ; a = # of blks to move ; ************************************** wwrite: ld (wleng),a ld hl,wwrt ld a,tapid call scsi erwrt: and 03h ; Was there an error ret wwrt: db 0ah db 01h db 00h db 00h wleng: db 01 db 00h done: cls ld sp,(spsave) jp boot ;************************************** ;************************************** ; scsi ncr interface ; entry: ; a = target address ; hl = point to scsi cmd ; de = point to data block ; exit: ; a = 0 ok (sets zero) ; a = 0ffh scsi timeout ; a = teac error ;************************************** ;************************************** scsi: ld (target),a ;save scsi device id ; save block pointers cmd/data ld (cmd.ptr),hl ; save cmd ld (dat.ptr),de ; save data ; do the IO call select ;start io ; get exit status ld a,(status) or a ret ;***************************************** ;***************************************** ; start IO here ; This is a state machine which is driven ; by the NCR chip. We could be here for a ; short period or for ever depending on the ; SCSI chip ; clear NCRs idea of the scsi state ;****************************************** ;***************************************** select: xor a out (ncricr),a ; state of buss out (ncrtcr),a ; what buss should be cleararbit: xor a ; clear ncr mode out (ncrmr),a in a,(ncrrpi) ; reset ncr interrupts ld a,(target) ; put address on buss out (ncrodr),a in a,(ncricr) ; turn on data buss or 01h out (ncricr),a ld a,05h ; put select on buss out (ncricr),a ld bc,6000h ; delay until busy stim: in a,(ncrcsb) ; check for busy and 040h ; mask busy jp nz,okselect dec c jp nz,stim dec b jp nz,stim xor a ; buss timeout out (ncrodr),a dec a ld (status),a jp alldone okselect: xor a ; check for timeout error alldone: ld b,a ; save status ld a,01h out (ncricr),a xor a out (ncricr),a ; clear data buss ld a,b or a ret nz dec a ld (status),a ld a,06h ; set dma mode and mointer busy out (ncrmr),a scsirdy: in a,(ncrbsr) ; check ncr status after select and 10h ; check for interrupt jr nz,scsiint in a,(ncrcsb) and 20h ; check for scsi req jr z,scsirdy jp phase ; go to state look up scsiint: xor a ; this is the interrupt code out (ncricr),a ; free data buss in a,(ncrbsr) ; check for interrupt and 0ch jr nz,scsiexit phase: xor a ; this is the start of the code to switch phases out (ncrmr),a in a,(ncrrpi) ; reset ints ld a,06h out (ncrmr),a ; set dma and mointer busy in a,(ncrcsb) ; update phase and 1ch ; mask used bits rra ld e,a rra out (ncrtcr),a ; update expected phase ld d,0 ; look up phase and jump to it ld hl,phasetable add hl,de ld a,(hl) inc hl ld h,(hl) ld l,a ld d,40h jp (hl) phasetable: dw phase0 dw phase1 dw phase2 dw phase3 dw phase4 dw phase5 dw phase6 dw phase7 phase0: ld hl,(dat.ptr) ; data out of phase ld e,1 jp wscsi phase1: ld hl,(dat.ptr) ; data in phase ld e,1 jp rscsi phase2: ld hl,(cmd.ptr) ; command out phase ld e,1 jp wscsi phase3: ld hl,status ; status in phase ld e,1 jp rscsi phase7: ld hl,message ; message phase ld e,1 jp rscsi phase4: ; unused phases phase5: phase6: scsiexit: xor a out (ncrtcr),a out (ncrmr),a in a,(ncrrpi) ret ; general scsi write code wscsi: ld a,01h ; assert data buss out (ncricr),a ld c,ncrdac out (ncrsds),a ; start dma wscsi1: in a,(ncrbsr) ; check for dma req ld b,a and d jr z,wscsi2 ; no dma now ld b,e otir jp wscsi1 wscsi2: ld a,b ; check for interrupt and 10h jp z,wscsi1 jp scsiint rscsi: ld c,ncrdac ; general scsi read out (ncrsdi),a ; start dma read rscsi1: in a,(ncrbsr) ; wait for dma ld b,a and d jr z,rscsi2 ; no dma now ld b,e inir jp rscsi1 rscsi2: ld a,b ; check for interrupt and 10h jp z,rscsi1 ; no ints now jp scsiint target: db 0 status: db 0 message: db 0 cmd.ptr: dw 0 dat.ptr: dw 0 ;********************************** ; end scsi ncr interface ;********************************** ;********************************** ; all thats fit to print ;********************************** msel: db 'Select drives, no spaces : $' mselsys: db cr,lf,'Select system, no spaces : $' mdat: db 'hh:mm:ss mm/dd/yyyy Enter time and date',cr,'$' mcom: db 'Enter comment:----!----!----!----!----!----!----!' db '----!----!----!----!----!----',cr,'$' mree: db ' Rewind on completion: $' moni: db '$' moff: db '$' eeerr: db cr,lf,'erase error',cr,lf,'$' reerr: db cr,lf,'rewind error',cr,lf,'$' preerr: db cr,lf,'prewind error',cr,lf,'$' msg1: db cr,lf,'Cmd --> $' msg3: db ' valid$' msg4: db ' filemark$' msg5: db ' eom$' msg6: db ' no-error$' msg7: db ' no-cassette$' msg8: db ' med-error$' msg9: db ' hardware-error$' msg10: db ' illegal-request$' msg11: db ' unit-attention$' msg12: db ' data-protect$' msg13: db ' no-data$' msg14: db ' volume-overflow$' msg15: db ' stall$' msg16: db ' hole$' msg17: db ' parity$' msg20: db ' cld$' msg21: db ' wpt$' msg22: db ' bom$' msg23: db ' run$' msg24: db ' strm$' msg25: db 'error count $' msg26: db 'repos count $' msg27: db 'track $' msg28: db 'address $' err1: db 'sens error',cr,lf,'$' sign: db cr,'AMPRO HARD DISK BACKUP, TEAC CT500 - 20Mbyte' db cr,lf,'Vers: 2.01 12/07/1987',cr,lf db 'Program by; Barry Harding, Joe Silvia,' db ' for AMPRO COMPUTERS INC.',cr,lf,lf,'$' help: db cr,lf db 'A - Tape to disk G - Enter comment',cr,lf db 'B - Disk to tape H - Rewind',cr,lf db 'C - Directory of tape I - Prewind tape',cr,lf db 'D - Select disk dives J - Erase tape',cr,lf db 'E - Toggle rewind K - Display tape status' db cr,lf if not clock db 'F - Enter Date' endif db cr,lf,lf,'X - Exit to CP/M' crlf: db cr,lf,'$' jmptbl: ; jmp table wboot: jp 0 ; warmboot const: jp 0 ; con status conin: jp 0 ; console in conout: jp 0 ; console out list: jp 0 ; list device punch: jp 0 ; punch reader: jp 0 ; reader home: jp 0 ; home drive seldsk: jp 0 ; select dsk settrk: jp 0 ; set track setsec: jp 0 ; set sector setdma: jp 0 ; set dma address read: jp 0 ; read disk write: jp 0 ; write disk listst: jp 0 ; list status sectran: jp 0 ; sector trans next: jp 0 ; extra data sizetbl equ $-jmptbl ; size of table swap: jp 0 ; swap drive hdinfo: jp 0 ; hard disk info phtbac: jp 0 ; get/set phytab paget: jp 0 ; get phytab entry address tod: ds 3 ; get base address of clock tick sz_tbl equ $-swap s_ec: ds 1 ; time/date counters from bios m_in: ds 1 hour: ds 1 jday: ds 2 ; julian day 0-366 for leap year y_ear: ds 1 tmonth: ds 1 ; temp storage for month tday: ds 1 ; temp storage for day tyear: ds 1 ; temp storage for year ;*********************************** ; defalt param table ; ; bit - meaning ; 0 hard disk ; 1 will be used ; 2 error ; 3 was completed ; 7 system track ;*********************************** drives: db 82h ; a drv system db 80h ; b drv " db 80h ; c drv " db 80h ; d drv " db 80h ; e drv " db 80h ; f drv " db 80h ; g drv " db 80h ; h drv " db 80h ; i drv " db 80h ; j drv " db 80h ; k drv " db 80h ; l drv " db 80h ; m drv " db 80h ; n drv " db 80h ; o drv " db 80h ; p drv " udrvs: db 2 ; a drv db 0 ; b drv db 0 ; c drv db 0 ; d drv db 0 ; e drv db 0 ; f drv db 0 ; g drv db 0 ; h drv db 0 ; i drv db 0 ; j drv db 0 ; k drv db 0 ; l drv db 0 ; m drv db 0 ; n drv db 0 ; o drv db 0 ; p drv wstat: db 00h ; status lastrew: ; run params if toggle db 0ffh ; no rewind on completion else db 0 ; rewind on completion endif filesn: dw 0 ; number of file we past inbuf: db 78 ; bdos buffered key input insiz: db 00 chin: ds 81 ddrive: db 'A' ; disk table sectrk: dw 0 bshift: db 0 bmask: db 0 emask: db 0 dsize: dw 0 ; max grp # dirmax: dw 0 alloc0: db 0 alloc1: db 0 chksiz: dw 0 offset: dw 1 ; trk offset datebuff: db 78 ; date buffer db 00 dbin: ds 81 commbuff: db 78 ; comment buffer db 00 commin: ds 81 d2drive: db 'A' ; tape table s2ectrk: dw 0 b2shift: db 0 b2mask: db 0 e2mask: db 0 d2size: dw 0 ; max grp # d2irmax: dw 0 a2loc0: db 0 a2loc1: db 0 c2hksiz: dw 0 o2ffset: dw 1 ; trk offset d2atebuff: db 78 ; date buffer db 00 d2bin: ds 81 c2ommbuff: db 78 ; comment buffer db 00 c2ommin: ds 81 spsave: dw 100 ; save stack dbuff: db 0 ; ds 512*blocks end begin