OS1BOOT ASMOS2CCP ASM OS2CCP ASMHOS3BDOS ASM !"#$%&'()*+,- mon80 equ 0f800h ;intel monitor base rmon80 equ 0ff0fh ;restart location for mon80 base equ 078h ;'base' used by controller STAT LIN)OS3BDOS ASMOS2CCP $$$t testing bias equ 0000h endif cpmb equ bias ;base of dos load bdos equ 806h+bias ;entry to dos for calls bdose equ 1880hOS3BDOS ASM./0123456789:;<=OS3BDOS ASM>?@ABCDEFGHIJKLMOS3BDOS ASMNOPQRSTUVWXYZ[\OS4BIOS ASM`]^_`abcdefghrtype equ base+1 ;result type rbyte equ base+3 ;result byte reset equ base+7 ;reset controller ; dstat equ base ;disk status+bias ;end of dos load boot equ 1600h+bias ;cold start entry point rboot equ boot+3 ;warm start entry point ; org 03000h ;OS5TRINTSRCiXSUB0 ASMjklXSUB1 ASMmnopPIP PLMqrstuvwxyz{|}~ port ilow equ base+1 ;low iopb address ihigh equ base+2 ;high iopb address bsw equ 0ffh ;boot switch recal equ 3h ;recalibrloaded down from hardware boot at 3000h ; bdosl equ bdose-cpmb ntrks equ 2 ;number of tracks to read bdoss equ bdosl/128 ;nuPIP PLMPIP PLMPIP PLM PIP LINP title 'mds cold start loader at 3000h' ; ; MDS-800 Cold Start Loader for CP/M 2.0 ; ; Version 2.0 August, 1979 ; false eqate selected drive readf equ 4h ;disk read function stack equ 100h ;use end of boot for stack ; rstart: lxi sp,stack;in camber of sectors in dos bdos0 equ 25 ;number of bdos sectors on track 0 bdos1 equ bdoss-bdos0 ;number of sectors on track 1 ; SUBMIT PLMESUBMIT LIN STAT PLMSTAT PLMdu 0 true equ not false testing equ false ;if true, then go to mon80 on errors ; if testing bias equ 03400h endif if nose of call to mon80 ; clear disk status in rtype in rbyte ; check if boot switch is off coldstart: in bsw ani 02h ;swtrack 0 db 2 ;start with sector 2 on track 0 dw cpmb ;start at base of bdos iopbl equ $-iopb0 ; iopb1: db 80h db readf ll * ; * command with comlen = 00). An initializing program * ; * can be automatically loaded by storing the command * ; ral cc rmon80 ;not ready bit set rar ;restore ani 11110b ;overrun/addr err/seek/crc/xxxx ; if testing cnz rmon80 ;g ; ; ******************************************************** ; * Base of CCP contains the following code/data * ; * ccp: jitch on? jnz coldstart ; clear the controller out reset ;logic cleared ; ; mvi b,ntrks ;number of tracks to read lxi title 'console command processor (CCP), ver 2.0' ; assembly language version of the CP/M console command processor ; ; versi db bdos1 ;sectors to read on track 1 db 1 ;track 1 db 1 ;sector 1 dw cpmb+bdos0*128 ;base of second read ; end  * at ccp+8, with the command length at ccp+7. In this * ; * case, the ccp executes the command before prompting * ; * the co to monitor endif if not testing jnz rstart ;retry the load endif ; ; lxi d,iopbl ;length of iopb dad d ;addressimp ccpstart (start with command) * ; * jmp ccpclear (start, clear command) * ; * ccp+6 127 (max command length) * ; h,iopb0 ; start: ; ; read first/next track into cpmb mov a,l out ilow mov a,h out ihigh wait0: in dstat ani 4 jon 2.2 February, 1980 ; ; Copyright (c) 1976, 1977, 1978, 1979, 1980 ; Digital Research ; Box 579, Pacific Grove, ; Califoronsole for input. Note that the command is exe-* ; * cuted on both warm and cold starts. When the command* ; * line is initing next iopb dcr b ;count down tracks jnz start ; ; ; jmp to boot to print initial message, and set up jmps jmp boot ;* ccp+7 comlen (command length = 00) * ; * ccp+8 ' ... ' (16 blanks) * ; *******************************************z wait0 ; ; check disk status in rtype ani 11b cpi 2 ; if testing cnc rmon80 ;go to monitor if 11 or 10 endif inia, 93950 ; false equ 0000h true equ not false testing equ false ;true if debugging ; ; if testing org 3400h bdosl ealized, a jump to "jmp ccpclear" dis- * ; * ables the automatic command execution. * ; *********************** ; parameter blocks iopb0: db 80h ;iocw, no update db readf ;read function db bdos0 ;# sectors to read on track 0 db 0 ;************* ; * Normal entry is at ccp, where the command line given * ; * at ccp+8 is executed automatically (normally a nuf not testing jnc rstart ;retry the load endif ; in rbyte ;i/o complete, check status ; if not ready, then go to mon80 qu $+800h ;bdos location else org 000h bdosl equ $+800h ;bdos location endif tran equ 100h tranm equ $ ccploc equ $ ********************************* ; jmp ccpstart ;start ccp with possible initial command jmp ccpclear ;clear the command beturn lf equ 10 ;line feed la equ 5fh ;left arrow eofile equ 1ah ;end of file ; ; utility procedures printchar: mov e,a!nction searnf equ 18 ;search for next file function delf equ 19 ;delete file function dreadf equ 20 ;disk read function dwriom: ;search for comfcb file lxi d,comfcb! jmp search ; delete: ;delete the file given by d,e mvi c,delf! jmp bdos ; bdary bdos entry point buff equ 0080h ;default buffer fcb equ 005ch ;default file control block ; rcharf equ 1 ;read characteros ; select: mov e,a! mvi c,self! jmp bdos ; bdos$inr: call bdos! sta dcnt! inr a! ret ; open: ;open the file given byuffer maxlen: db 127 ;max buffer length comlen: db 0 ;command length (filled in by dos) ; (command executed initially if coml mvi c,pcharf! jmp bdos ; printbc: ;print character, but save b,c registers push b! call printchar! pop b! ret ; crlf: tf equ 21 ;disk write function makef equ 22 ;file make function renf equ 23 ;rename file function logf equ 24 ;return login vos$cond: call bdos! ora a! ret ; diskread: ;read the next record from the file given by d,e mvi c,dreadf! jmp bdos$cond function pcharf equ 2 ;print character function pbuff equ 9 ;print buffer function rbuff equ 10 ;read buffer function break d,e mvi c,openf! jmp bdos$inr ; openc: ;open comfcb xra a! sta comrec ;clear next record to read lxi d,comfcb! jmp openen non zero) combuf: db ' ' ;8 character fill db ' ' ;8 character fill db 'COPYRIGHT (C) 1979, DIGITAL RESE mvi a,cr! call printbc mvi a,lf! jmp printbc ; blank: mvi a,' '! jmp printbc ; print: ;print string starting at b,c unector cself equ 25 ;return currently selected drive number dmaf equ 26 ;set dma address userf equ 32 ;set user number ; ; s ; diskreadc: ;read the comfcb file lxi d,comfcb! jmp diskread ; diskwrite: ;write the next record to the file given byf equ 11 ;break key function liftf equ 12 ;lift head function (no operation) initf equ 13 ;initialize bdos function self equ ; close: ;close the file given by d,e mvi c,closef! jmp bdos$inr ; search: ;search for the file given by d,e mvi c,searARCH '; 38 ds 128-($-combuf) ; total buffer length is 128 characters comaddr:dw combuf ;address of next to char to scan sttil next 00 entry push b! call crlf! pop h ;now print the string prin0: mov a,m! ora a! rz ;stop on 00 inx h! push h ;readpecial fcb flags rofile equ 9 ;read only file sysfile equ 10 ;system file flag ; ; special characters cr equ 13 ;carriage r d,e mvi c,dwritf! jmp bdos$cond ; make: ;create the file given by d,e mvi c,makef! jmp bdos$inr ; renam: ;rename the fi14 ;select disk function openf equ 15 ;open file function closef equ 16 ;close file function searf equ 17 ;search for file fuf! jmp bdos$inr ; searchn: ;search for the next occurrence of the file given by d,e mvi c,searnf! jmp bdos$inr ; searchcaddr: ds 2 ;starting address of current fillfcb request ; diska equ 0004h ;disk address for current disk bdos equ 0005h ;primy for next call printchar! pop h ;character printed jmp prin0 ;for another character ; initialize: mvi c,initf! jmp bdle given by d,e mvi c,renf! jmp bdos ; getuser: ;return current user code in a mvi e,0ffh ;drop through to setuser ; sall del$sub ;translate to upper case, store zero at end call saveuser ;user # save in case control c mvi c,rbuff! lxi d,ma ;disk read is ok, transfer to combuf lxi d,comlen! lxi h,buff! mvi b,128! call move0 ;line is transferred, close theet to false xra a! call select ;on drive a to erase file lxi d,subfcb! call delete lda cdisk! jmp select ;back to originald to upper case ; readcom: ;read the next command into the command buffer ;check for submit file lda submit! ora a! jz na character ready at the console mvi c,breakf! call bdos ora a! rz mvi c,rcharf! call bdos ;character cleared ora a! retetuser: mvi c,userf! jmp bdos ;sets user number ; saveuser: ;save user#/disk# before possible ^c or transient calxlen! call bdos call setdiska ;no control c, so restore diska noread: ;enter here from submit file ;set the last character file with a ;deleted record lxi h,submod! mvi m,0 ;clear fwflag inx h! dcr m ;one less record lxi d,subfcb! cal drive ; serialize: ;check serialization lxi d,serial! lxi h,bdosl! mvi b,6 ;check six bytes ser0: ldax d! cmp m! jnz baosub ;scanning a submit file ;change drives to open and read the file lda cdisk! ora a! mvi a,0! cnz select ;have to ; cselect: ;get the currently selected drive number to reg-A mvi c,cself! jmp bdos ; setdmabuff: ;set default buffer l getuser ;code to a add a! add a! add a! add a ;rot left lxi h,cdisk! ora m ;4b=user, 4b=disk sta diska ;stored away in m to zero for later scans lxi h,comlen! mov b,m ;length is in b readcom0: inx h! mov a,b! ora a ;end of scan? jz readcom1!l close! jz nosub ;close went ok, return to original drive lda cdisk! ora a! cnz select ;print to the 00 lxi h,cdserial inx d! inx h! dcr b! jnz ser0 ret ;serial number is ok ; comerr: ;error in command string starting at position open again in case xsub present lxi d,subfcb! call open! jz nosub ;skip if no sub lda subrc! dcr a ;read ladma address lxi d,buff ;(drop through) ; setdma: ;set dma address to d,e mvi c,dmaf! jmp bdos ; del$sub: ;delete theemory for later ret ; setdiska: lda cdisk! sta diska ;user/disk ret ; translate: ;translate character in register A mov a,m ;get character and translate call translate! mov m,a! dcr b! jmp readcom0 ; readcom1: ;end of scan, h,l addressombuf! call prin0 call break$key! jz noread call del$sub! jmp ccp ;break key depressed ; nosub: ;no submit file! c ;'staddr' and ending with first delimiter call crlf ;space to next line lhld staddr ;h,l address first to print comerr0st record(s) first sta subcr ;current record to read lxi d,subfcb! call diskread ;end of file if last record jnz nosub submit file, and set submit flag to false lxi h,submit! mov a,m! ora a! rz ;return if no sub file mvi m,0 ;submit flag is sto upper case cpi 61h! rc ;return if below lower case a cpi 7bh! rnc ;return if above lower case z ani 5fh! ret ;translate end of command mov m,a ;store a zero lxi h,combuf! shld comaddr ;ready to scan to zero ret ; break$key: ;check for : ;print characters until blank or zero mov a,m! cpi ' '! jz comerr1; not blank ora a! jz comerr1; not zero, so print it ;set disk to name in register b mov a,b! sta sdisk ;mark as disk selected mov m,b! inx d ;past the : ; setname: ;set tcommand address in d,e call deblank ;to first non-blank character xchg! shld staddr ;in case of errors xchg! pop h ;d,e hatype field with blanks inx h! mvi m,' '! dcr b! jnz padty ; efill: ;end of the filename/filetype fill, save command addrz ;left arrow cpi '.'! rz cpi ':'! rz cpi ';'! rz cpi '<'! rz cpi '>'! rz ret ;delimiter not found ; debla b,3! cpi '.'! jnz padty ;skip the type field if no . inx d ;past the ., to the file type field setty0: ;set the field fro push h! call printchar! pop h! inx h jmp comerr0; for another character comerr1: ;print question mark,and delete sub filehe file name field mvi b,8 ;file name length (max) setnam0: call delim! jz padname ;not a delimiter inx h! cpi '*'! jns command, h,l has fcb address ;look for preceding file name A: B: ... ldax d! ora a! jz setcur0 ;use current disk if empty ress ;fill the remaining fields for the fcb mvi b,3 efill0: inx h! mvi m,0! dcr b! jnz efill0 xchg! shld comaddr ;senk: ;deblank the input line ldax d! ora a! rz ;treat end of line as blank cpi ' '! rnz! inx d! jmp deblank ; addh: ;addm the command buffer call delim! jz padty! inx h! cpi '*'! jnz setty1 mvi m,'?' ;since * specified! jmp setty2 ; mvi a,'?'! call printchar call crlf! call del$sub jmp ccp ;restart with next command ; ; fcb scan and fill subroutinz setnam1 ;must be ?'s mvi m,'?'! jmp setnam2 ;to dec count ; setnam1: mov m,a ;store character to fcb! inx d setnacommand sbi 'A'-1! mov b,a ;disk name held in b if : follows inx d! ldax d! cpi ':'! jz setdsk ;set disk name if : ; sett new starting point ; ;recover the start address of the fcb and count ?'s pop h! lxi b,11 ;b=0, c=8+3 scnq: inx h! a to h,l add l! mov l,a! rnc inr h! ret ; fillfcb0: ;equivalent to fillfcb(0) mvi a,0 ; fillfcb: lxi h,comfcbsetty1: ;not a *, so copy to type field mov m,a! inx d setty2: ;decrement count and go again dcr b! jnz setty0 ; e (entry is at fillfcb below) ;fill the comfcb, indexed by A (0 or 16) ;subroutines delim: ;look for a delimiter ldax dm2: dcr b ;count down length! jnz setnam0 ; ;end of name, truncate remainder trname: call delim! jz setty ;set type fieldcur: ;set current disk dcx d ;back to first character of command setcur0: lda cdisk! mov m,a! jmp setname ; setdsk: mov a,m! cpi '?'! jnz scnq0 ;? found, count it in b! inr b scnq0: dcr c! jnz scnq ; ;number of ?'s in c, move to a a! call addh! push h! push h ;fcb rescanned at end xra a! sta sdisk ;clear selected disk (in case A:...) lhld comaddr! xchg ; ;end of type field, truncate trtyp: ;truncate type field call delim! jz efill! inx d! jmp trtyp ; padty: ;pad the ! ora a! rz ;not the last element cpi ' '! jc comerr ;non graphic rz ;treat blank as delimiter cpi '='! rz cpi la! if delimiter inx d! jmp trname ; padname: inx h! mvi m,' '! dcr b! jnz padname ; setty: ;set the type field mvind return with flags set mov a,b! ora a! ret ; intvec: ;intrinsic function names (all are four characters) db 'DIR ' ;proper disk is selected, now check sub files ;check for initial command lda comlen! ora a! jnz ccp0 ;assume typed already loader lxi sp,stack! push b ;save initial disk number ;(high order 4bits=user code, low 4bits=disk#) mov a,c! rar! xi h,di or (hlt shl 8) shld ccploc! lxi h,ccploc! pchl ; ; ;utility subroutines for intrinsic handlers readerr: dcr b jnz intrin1 ;loop while matching ; ;complete match on name, check for blank in fcb ldax d! cpi ' '! jnz intrice lda sdisk! ora a! jnz userfunc ;check for an intrinsic function call intrinsic lxi h,jmptab ;index is in the accumdb 'ERA ' db 'TYPE' db 'SAVE' db 'REN ' db 'USER' intlen equ ($-intvec)/4 ;intrinsic function length ser ; ccp: ;enter here on each command or error condition lxi sp,stack call crlf ;print d> prompt, where d is disk name carar! rar! rar! ani 0fh ;user code mov e,a! call setuser ;user code selected ;initialize for this user, get $ flag c;print the read error message lxi b,rdmsg! jmp print rdmsg: db 'READ ERROR',0 ; nofile: ;print no file message ln3 ;otherwise matched mov a,c! ret ;with intrinsic number in a ; intrin2: ;mismatch, move to end of intrinsic inx hulator mov e,a! mvi d,0! dad d! dad d ;index in d,e mov a,m! inx h! mov h,m! mov l,a! pchl ;pc changes to the proper inial: db 0,0,0,0,0,0 ; ; intrinsic: ;look for intrinsic functions (comfcb has been filled) lxi h,intvec! mvi c,0 ;c countsll cselect ;get current disk number adi 'A'! call printchar mvi a,'>'! call printchar call readcom ;command buffer filled all initialize ;0ffh in accum if $ file present sta submit ;submit flag set if $ file present pop b ;recall usxi b,nofmsg! jmp print nofmsg: db 'NO FILE',0 ; getnumber: ;read a number from the command line call fillfcb0 ;should ! dcr b! jnz intrin2 ; intrin3: ;try next intrinsic inr c ;to next intrinsic number jmp intrin0 ;for another roundtrinsic or user function jmptab: dw direct ;directory search dw erase ;file erase dw type ;type file dw save intrinsics as scanned intrin0: mov a,c! cpi intlen ;done with scan?! rnc ;no, more to scan lxi d,comfcb+1 ;beginning of ccp0: ;(enter here from initialization with command full) lxi d,buff! call setdma ;default dma address at buff call cselecter code and disk number mov a,c! ani 0fh ;disk number in accumulator sta cdisk ;clears user code nibble call selectbe number lda sdisk! ora a! jnz comerr ;cannot be prefixed ;convert the byte value in comfcb to binary lxi h,comfcb+1! ; ccpclear: ;clear the command buffer xra a sta comlen ;drop through to start ccp ccpstart: ;enter here from boot ;save memory image dw rename ;file rename dw user ;user number dw userfunc;user-defined function badserial: l name mvi b,4 ;length of match is in b intrin1: ldax d! cmp m ;match? jnz intrin2 ;skip if no match inx d! inx h! ! sta cdisk ;current disk number saved call fillfcb0 ;command fcb filled cnz comerr ;the name cannot be an ambiguous referenlxi b,11 ;(b=0, c=11) ;value accumulated in b, c counts name length to zero conv0: mov a,m! cpi ' '! jz conv1 ;more tolank request, must be in comfcb dir1: mvi e,0! push d ;E counts directory entries call searchcom ;first one has been found mand lda sdisk! ora a! rz ;no action if not selected dcr a! lxi h,cdisk! cmp m! rz ;same disk lda cdisk! jmp select ; ;may be 3rd item cpi 3! jnz dirb ;place blank at end if not mvi a,9! call addhcf ;first char of type ani 7fh! cpi ' ame: ;move 3 characters from h,l to d,e addresses mvi b,3 move0: mov a,m! stax d! inx h! inx d dcr b! jnz move0 call crlf push b! call cselect! pop b ;current disk in A adi 'A'! call printbc mvi a,':'! call printbc scan, convert char to binary and add inx h! sui '0'! cpi 10! jnc comerr ;valid? mov d,a ;save value! mov a,b ;mult by 1 cz nofile ;not found message dir2: jz endir ;found, but may be system file lda dcnt ;get the location of the element ;individual intrinsics follow direct: ;directory search call fillfcb0 ;comfcb gets file name call setdisk ;change disk '! jz dir5 ;not a blank in the file type field dirb: mvi a,' ' ;restore trailing filename chr dir4: call printbc ;ret ; addhcf: ;buff + a + c to h,l followed by fetch lxi h,buff! add c! call addh! mov a,m! ret ; setdisk: ;changejmp dirhdr1 ;skip current line hdr dirhdr0:call blank ;after last one mvi a,':'! call printbc dirhdr1: call blank 0 ani 1110$0000b! jnz comerr mov a,b ;recover value rlc! rlc! rlc ;*8 add b! jc comerr add b! jc comerr ;*8+ rrc! rrc! rrc! ani 110$0000b! mov c,a ;c contains base index into buff for dir entry mvi a,sysfile! call addhcf ;value drives if requested lxi h,comfcb+1! mov a,m ;may be empty request cpi ' '! jnz dir1 ;skip fill of ??? if not blank ;set cchar printed inr b! mov a,b! cpi 12! jnc dir5 ;check for break between names cpi 9! jnz dir3 ;for another char ; disks for this command, if requested xra a! sta comfcb ;clear disk name from fcb lda sdisk! ora a! rz ;no action if not s ;compute position of name in buffer mvi b,1 ;start with first character of name dir3: mov a,b! call addhcf ;buff+a+c fe*2 = *10 add d! jc comerr ;+digit mov b,a! dcr c! jnz conv0 ;for another digit ret conv1: ;end of digits, check fto A ral! jc dir6 ;skip if system file ;c holds index into buffer ;another fcb found, new line? pop d! mov a,e! inr omfcb to all ??? for current disk mvi b,11 ;length of fill ????????.??? dir0: mvi m,'?'! inx h! dcr b! jnz dir0 ;not a bprint a blank between names call blank! jmp dir3 ; dir5: ;end of current entry pop psw ;discard the directory countepecified dcr a! lxi h,cdisk! cmp m! rz ;already selected jmp select ; resetdisk: ;return to original disk after comtched ani 7fh ;mask flags ;may delete trailing blanks cpi ' '! jnz dir4 ;check for blank type pop psw! push psw or all blanks mov a,m! cpi ' '! jnz comerr ;blanks? inx h! dcr c! jnz conv1 mov a,b ;recover value! ret ; movene! push d ;e=0,1,2,3,...new line if mod 4 = 0 ani 11b! push psw ;and save the test jnz dirhdr0 ;header on current liner (mod 4) dir6: call break$key ;check for interrupt at keyboard jnz endir ;abort directory search call searchn! jmp dir2er ; ;should be followed by a file to save the memory image call fillfcb0 jnz comerr ;cannot be ambiguous call senz typeof ;hard end of file xra a! mov m,a ;bptr = 0 type1: ;read character at bptr and print inr m ;bptr = bptr + 1 jmp retcom fullmsg: db 'NO SPACE',0 ; ; rename: ;rename a file on a specific disk call fillfcb0! jnz comerr ;must be nofile ;no file message if so jmp retcom ; ermsg: db 'ALL (Y/N)?',0 ; type: call fillfcb0! jnz comerr ;don't allow ?'e around lxi h,128! dad d! push h ;next dma address saved call setdma ;current dma address set lxi d,comfcb! call diskw ;for another entry endir: ;end of directory scan pop d ;discard directory counter jmp retcom ; ; erase: call fillftdisk ;may be a disk change lxi d,comfcb! push d! call delete ;existing file removed pop d! call make ;create a new file o lxi h,buff! call addh ;h,l addresses char mov a,m! cpi eofile! jz retcom call printchar call break$key! jnz retc unambiguous lda sdisk! push psw ;save for later compare call setdisk ;disk selected call searchcom ;is new name already ts in file name call setdisk! call openc ;open the file jz typerr ;zero flag indicates not found ;file opened, read 'til erite pop d! pop h ;dma address, sector count jnz saverr ;may be disk full case jmp save0 ;for another sector ; savcb0 ;cannot be all ???'s cpi 11 jnz erasefile ;erasing all of the disk lxi b,ermsg! call print! call readcom lxin disk jz saverr ;no directory space xra a! sta comrec; clear next record field pop psw ;#pages to write is in a, changom ;abort if break jmp type0 ;for another character ; typeof: ;end of file, check for errors dcr a! jz retcom here? jnz renerr3 ;file doesn't exist, move to second half of fcb lxi h,comfcb! lxi d,comfcb+16! mvi b,16! call move0 of call crlf! lxi h,bptr! mvi m,255 ;read first buffer type0: ;loop on bptr lxi h,bptr! mov a,m! cpi 128 ;end buffer e1: ;end of dump, close the file lxi d,comfcb! call close inr a; 255 becomes 00 if error jnz retsave ;for another comma h,comlen! dcr m! jnz ccp ;bad input inx h! mov a,m! cpi 'Y'! jnz ccp ;ok, erase the entire diskette inx h! shld comadde to #sectors mov l,a! mvi h,0! dad h! lxi d,tran ;h,l is sector count, d,e is load address save0: ;check for sector cocall readerr typerr: call resetdisk! jmp comerr ; save: call getnumber; value to register a push psw ;save it for lat ;check for = or left arrow lhld comaddr! xchg! call deblank cpi '='! jz ren1 ;ok if = cpi la! jnz renerr2 ren1: xchg jc type1! push h ;carry if 0,1,...,127 ;read another buffer full call diskreadc! pop h ;recover address of bptr jnd saverr: ;must be full or read only disk lxi b,fullmsg! call print retsave: ;reset dma buffer call setdmabuff r ;otherwise error at retcom erasefile: call setdisk lxi d,comfcb! call delete inr a ;255 returned if not found czunt zero mov a,h! ora l! jz save1 ;may be completed dcx h ;sector count = sector count - 1 push h ;save it for next tim! inx h! shld comaddr ;past delimiter ;proper delimiter found call fillfcb0! jnz renerr2 ;check for drive conflict nz load1 ;sector loaded, set new dma address and compare pop h! lxi d,128! dad d lxi d,tranm ;has the load overfloweh lda sdisk! ora a! jz endcom ;no disk name if 0 dcr a! sta cdisk! call setdiska ;set user/disk call select! jmp endcomaded program lxi sp,stack ;may come back here call setdiska! call select jmp ccp ; userer: ;arrive here on com; file already exists lxi b,renmsg! call print! jmp retcom renmsg: db 'FILE EXISTS',0 ; user: ;set user number call ov a,m! ora a! jz bmove1! cpi ' '! jz bmove1 inx h! jmp bmove0 ;for another scan ;first blank position found bmove1: pop psw! mov b,a ;previous drive number lxi h,sdisk! mov a,m! ora a! jz ren2 ;drive name was specified. same one? cd? mov a,l! sub e! mov a,h! sbb d! jnc loaderr jmp load0 ;for another sector ; load1: pop h! dcr a! jnz loaderr ; user0: ;file name is present lxi d,comfcb+9! ldax d! cpi ' '! jnz comerr ;type ' ' push d! call setdisk! pop d! lxi h,cmand error call resetdisk! jmp comerr ; loaderr:;cannot load the program lxi b,loadmsg! call print jmp retcomgetnumber; leaves the value in the accumulator cpi 16! jnc comerr; must be between 0 and 15 mov e,a ;save for setuser call mvi b,0! lxi d,buff+1! ;ready for the move bmove2: mov a,m! stax d! ora a! jz bmove3 ;more to move inr b! inx h! inx mp b! mov m,b! jnz renerr2 ren2: mov m,b ;store the name in case drives switched xra a! sta comfcb! call searchcom ;is old end file is 1 call resetdisk ;back to original disk call fillfcb0! lxi h,sdisk! push h mov a,m! sta comfcb ;drive nuomtype ;.com call movename ;file type is set to .com call openc! jz userer ;file opened properly, read it into memory loadmsg: db 'BAD LOAD',0 comtype: db 'COM' ;for com files ; ; retcom: ;reset disk before end of command check call lda comfcb+1! cpi ' '! jz comerr call setuser ;new user number set jmp endcom ; userfunc: call serialize ;check serialid! jmp bmove2 bmove3: ;b has character count mov a,b! sta buff call crlf ;now go to the loaded program call sfile there? jz renerr1 ; ;everything is ok, rename the file lxi d,comfcb! call renam jmp retcom ; renerr1:; mber set mvi a,16! call fillfcb ;move entire fcb to memory pop h! mov a,m! sta comfcb+16 xra a! sta comrec ;record n lxi h,tran ;transient program base load0: push h ;save dma address xchg! call setdma lxi d,comfcb! call diskread! jresetdisk ; endcom: ;end of intrinsic command call fillfcb0 ;to check for garbage at end of line lda comfcb+1! sui ' '! lxzation ;load user function and set up for execution lda comfcb+1! cpi ' '! jnz user0 ;no file name, but may be disk switcetdmabuff ;default dma call saveuser ;user code saved ;low memory diska contains user code call tran ;gone to the lono file on disk call nofile! jmp retcom renerr2:; ambigous reference/name conflict call resetdisk! jmp comerr renerr3:umber set to zero lxi d,fcb! lxi h,comfcb! mvi b,33! call move0 ;move command line to buff lxi h,combuf bmove0: mi h,sdisk! ora m ;0 in accumulator if no disk selected, and blank fcb jnz comerr jmp ccp ; ; ; ; data areas ds 16 ;8stack ; ; low memory locations reboot equ 0000h ;reboot system ioloc equ 0003h ;i/o byte location bdosa equ 0006h ;addre ** ;** ** ;************************************************18h ;=ctl-u ctlz equ 1ah ;end of file rubout equ 7fh ;char delete tab equ 09h ;tab char cr equ 0dh ;carriage return lf equ 1 ;selected disk for current operation ;none=0, a=1, b=2 ... bptr: ds 1 ;buffer pointer end ccploc rack function setsecf set bios+3*11 ;set sector function setdmaf set bios+3*12 ;set dma function readf set bios+3*13 ;read di level stack stack: ; ; 'submit' file control block submit: db 0 ;00 if no submit file, ff if submitting subfcb: db 0,'$$$ ss field of jmp BDOS ; ; bios access constants bootf set bios+3*0 ;cold boot function wbootf set bios+3*1 ;warm boot functio***************** ;***************************************************************** ; ; Copyright (c) 1978, 1979, 1980 ; Di0ah ;line feed ctl equ 5eh ;up arrow ; db 0,0,0,0,0,0 ; ; enter here from the user's program with function number in c, ; title 'Bdos Interface, Bdos, Version 2.2 Feb, 1980' ;***************************************************************** ;*****sk function writef set bios+3*14 ;write disk function liststf set bios+3*15 ;list status function sectran set bios+3*16 ;sect ' ;file name is $$$ db 'SUB',0,0 ;file type is sub submod: db 0 ;module number subrc: ds 1 ;record count filed ds 16 ;n constf set bios+3*2 ;console status function coninf set bios+3*3 ;console input function conoutf set bios+3*4 ;console outpgital Research ; Box 579, Pacific Grove ; California ; ; ; 20 january 1980 ; ; on equ 0ffffh off equ 00000h test and information address in d,e jmp bdose ;past parameter block ; ; ************************************************ ; *** ************************************************************ ;** **or translate ; ; equates for non graphic characters ctlc equ 03h ;control c ctle equ 05h ;physical eol ctlh equ 08h ;backspdisk map subcr: ds 1 ;current record to read ; ; command file control block comfcb: ds 32 ;fields filled in later comrec: dut function listf set bios+3*5 ;list output function punchf set bios+3*6 ;punch output function readerf set bios+3*7 ;reader equ off ; if test org 0dc00h else org 0800h endif ; bios value defined at end of module ; ssize equ 24 ;24 level relative locations 0009 - 000e *** ; ************************************************ pererr: dw persub ;permanent e ;** B a s i c D i s k O p e r a t i n g S y s t e m ** ;** I n t e r f a c e M o d u l e ace ctlp equ 10h ;prnt toggle ctlr equ 12h ;repeat line ctls equ 13h ;stop/start screen ctlu equ 15h ;line delete ctlx equ s 1 ;current record to read/write dcnt: ds 1 ;disk directory count (used for error codes) cdisk: ds 1 ;current disk sdisk: dsinput function homef set bios+3*8 ;disk home function seldskf set bios+3*9 ;select disk function settrkf set bios+3*10 ;set trror subroutine selerr: dw selsub ;select error subroutine roderr: dw rodsub ;ro disk error subroutine roferr: dw rofsub ;ro jmp wait$err ;wait console ; rofsub: ;report read/only file lxi h,rofmsg ;drop through to wait for console ; wait$err: ;dw func24,func25,func26,func27 dw func28,func29,func30,func31 dw func32,func33,func34,func35 dw func36,func37,func38,func3kspace cpi cr! rz ;carriage return? cpi lf! rz ;line feed? cpi tab! rz ;tab? cpi ctlh! rz ;backspace? cpi ' '! ret ;canvalid # mov c,e ;possible output character to C lxi h,functab! mov e,a! mvi d,0 ;DE=func, HL=.ciotab dad d! dad d! mov e,ut character ;(drop through to conin) ;ret ; ; ; console handlers conin: ;read console character to A lxi h,kbchafile error subroutine ; ; bdose: ;arrive here from user programs xchg! shld info! xchg ;info=DE, DE=info mov a,e! sta linwait for response before boot call errflg! jmp reboot ; ; error messages dskmsg: db 'Bdos Err On ' dskerr: db ' : $' ;fill9 ; dw func40 ; nfuncs equ ($-functab)/2 ; ; ; error subroutines persub: ;report permanent error lxi h,permsg! calrry set if not graphic ; conbrk: ;check for character ready lda kbchar! ora a! jnz conb1 ;skip if active kbchar ;no activm! inx h! mov d,m ;DE=functab(func) lhld info ;info in DE for later xchg xchg! pchl ;dispatched ; ; dispatch table for fr! mov a,m! mvi m,0! ora a! rnz ;no previous keyboard character ready jmp coninf ;get character externally ;ret ; conechfo ;linfo = low(info) - don't equ lxi h,0! shld aret ;return value defaults to 0000 ;save user's stack pointer, set to localed in by errflg permsg: db 'Bad Sector$' selmsg: db 'Select$' rofmsg: db 'File ' rodmsg: db 'R/O$' ; ; errflg: ;report l errflg ;to report the error cpi ctlc! jz reboot ;reboot if response is ctlc ret ;and ignore the error ; selsub: ;report e kbchar, check external break call constf! ani 1! rz ;return if no char ready ;character ready, read it call coninf ;tunctions functab: dw wbootf, func1, func2, func3 dw punchf, listf, func6, func7 dw func8, func9, func10,func11 diskf equ: ;read character with echo call conin! call echoc! rc ;echo character? ;character must be echoed before return p stack dad sp! shld entsp ;entsp = stackptr lxi sp,lstack ;local stack setup xra a! sta fcbdsk! sta resel ;fcbdsk,resel=faerror to console, message address in HL push h! call crlf ;stack mssg address, new line lda curdsk! adi 'A'! sta dskerr ;curselect error lxi h,selmsg! jmp wait$err ;wait console before boot ; rodsub: ;report write to read/only disk lxi h,rodmsg! o A cpi ctls! jnz conb0 ;check stop screen function ;found ctls, read next character call coninf ;to A cpi ctlc! jz ($-functab)/2 ;disk funcs dw func12,func13,func14,func15 dw func16,func17,func18,func19 dw func20,func21,func22,func23 ush psw! mov c,a! call tabout! pop psw ret ;with character in A ; echoc: ;echo character if graphic ;cr, lf, tab, or baclse lxi h,goback ;return here after all functions push h ;jmp goback equivalent to ret mov a,c! cpi nfuncs! rnc ;skip if irent disk name lxi b,dskmsg! call print ;the error message pop b! call print ;error mssage tail ;jmp conin ;to get the inpreboot ;ctlc implies re-boot ;not a reboot, act as if nothing has happened xra a! ret ;with zero in accumulator conb0: pop psw! ori 40h ;becomes graphic letter mov c,a ;ready to print ;(drop through to tabout) ; tabout: ;expand tabs toov a,c ;character back to A cpi ctlh! jnz notbacksp ;backspace character dcr m ;column = column - 1 ret notbacll tabout ;another character printed pop b! jmp print ; read: ;read to info address (max length, current length, buffer) acter ;may be copying to the list device lda listcp! ora a! cnz listf ;to printer, if so pop b ;recall the character unctions ;then move to strtcol (starting column) mvi c,'#'! call conout call crlf ;column = 0, move to position strtcol ;character in accum, save it sta kbchar conb1: ;return with true set in accumulator mvi a,1! ret ; conout: ;com console mov a,c! cpi tab! jnz conout ;direct to conout if not ;tab encountered, move to next tab position tab0: mvi cksp: ;not a backspace character, eol? cpi lf! rnz ;return if not ;end of line, column = 0 mvi m,0 ;column = 0 lda column! sta strtcol ;save start for ctl-x, ctl-h lhld info mov c,m! inx h! push h! mvi b,0 ;B = current buffer length,compout: mov a,c ;recall the character ;and compute column position lxi h,column ;A = char, HL = .column cpi rubout! crlfp0: lda column! lxi h,strtcol cmp m! rnc ;stop when column reaches strtcol mvi c,' '! call conout ;print blank pute character position/write console char from C ;compcol = true if computing column position lda compcol! ora a! jnz compo,' '! call conout ;another blank lda column! ani 111b ;column mod 8 = 0 ? jnz tab0 ;back for another if not ret ; ; b ret ; ctlout: ;send C character with possible preceding up-arrow mov a,c! call echoc ;cy if not graphic (or special case) ;C = maximum buffer length, ;HL= next to fill - 1 readnx: ;read next character, BC, HL active push b! push h ;blen, rz ;no column change if nulls inr m ;column = column + 1 cpi ' '! rnc ;return if graphic ;not graphic, reset column po jmp crlfp0 ;; ; crlf: ;carriage return line feed sequence mvi c,cr! call conout! mvi c,lf! jmp conout ;ret ; print: ut ;write the character, then compute the column ;write console character from C push b! call conbrk ;check for screen ackup: ;back-up one screen position call pctlh! mvi c,' '! call conoutf ; (drop through to pctlh) ; pctlh: ;send ctlh jnc tabout ;skip if graphic, tab, cr, lf, or ctlh ;send preceding up arrow push psw! mvi c,ctl! call conout ;up arrow cmax, HL saved readn0: call conin ;next char in A ani 7fh ;mask parity bit pop h! pop b ;reactivate counters sition dcr m ;column = column - 1 mov a,m! ora a! rz ;return if at zero ;not at zero, may be backspace or end line m ;print message until M(BC) = '$' ldax b! cpi '$'! rz ;stop on $ ;more to print inx b! push b! mov c,a ;char to C castop function pop b! push b ;recall/save character call conoutf ;externally, to console pop b! push b ;recall/save char to console without affecting column count mvi c,ctlh! jmp conoutf ;ret ; crlfp: ;print #, cr, lf for ctlx, ctlu, ctlr f cpi cr! jz readen ;end of line? cpi lf! jz readen ;also end of line cpi ctlh! jnz noth ;backspace? ;do we have any ;delete line (ctlu) call crlfp ;physical eol pop h ;discard starting position jmp read ;to start all over notu:.listcp flag mvi a,1! sub m ;True-listcp mov m,a ;listcp = not listcp pop h! jmp readnx ;for another char notp: fer rdecho: inx h! mov m,a ;character filled to mem inr b ;blen = blen + 1 rdech1: ;look for a random control en=blen-1, next to fill - 1 decremented jmp rdech1 ;act like this is an echo ; notrub: ;not a rubout character, chec ;end of repeat, recall lengths ;original BC still remains pushed push h ;save next to fill lda compcol! ora a ;>0 icharacters to back over? mov a,b! ora a! jz readnx ;characters remain in buffer, backup one dcr b ;remove one charac ;not line delete, repeat line? cpi ctlr! jnz notr linelen: ;repeat line, or compute line len (ctlh) ;if comp ;not a ctlp, line delete? cpi ctlx! jnz notx pop h ;discard start position ;loop while column > strtcol backxcharacter push b! push h ;active values saved mov c,a ;ready to print call ctlout ;may be up-arrow C pop h! pop k end line cpi ctle! jnz note ;physical end line? ;yes, save active counters and force eol push b! push h! call crlff computing length jz readn0 ;for another char if so ;column position computed for ctlh lxi h,column! sub m ;diff > ter lda column! sta compcol ;col > 0 ;compcol > 0 marks repeat as length compute jmp linelen ;uses same code as repecol > 0 push b! call crlfp ;save line length pop b! pop h! push h! push b ;bcur, cmax active, beginning buff at HL : lda strtcol! lxi h,column cmp m! jnc read ;start again dcr m ;column = column - 1 call backup ;one positiob! mov a,m ;recall char cpi ctlc ;set flags for reboot test mov a,b ;move length to A jnz notc ;skip if not a contro xra a! sta strtcol ;start position = 00 jmp readn0 ;for another character note: ;not end of line, list toggle? 0 sta compcol ;count down below ;move back compcol-column spaces backsp: ;move back one more space call backuat noth: ;not a backspace cpi rubout! jnz notrub ;rubout char? ;rubout encountered, rubout if possible mov a, rep0: mov a,b! ora a! jz rep1 ;count len to 00 inx h! mov c,m ;next to print dcr b! push b! push h ;count length dn jmp backx notx: ;not a control x, control u? ;not control-X, control-U? cpi ctlu! jnz notu ;skip if not l c cpi 1 ;control C, must be length 1 jz reboot ;reboot if blen = 1 ;length not one, so skip reboot notc: ;n cpi ctlp! jnz notp ;skip if not ctlp ;list toggle - change parity push h ;save next to fill - 1 lxi h,listcp ;HL=p ;one space lxi h,compcol! dcr m jnz backsp jmp readn0 ;for next character notr: ;not a ctlr, place into bufb! ora a! jz readnx ;skip if len=0 ;buffer has characters, resend last char mov a,m! dcr b! dcx h ;A = last char ;blown call ctlout ;character echoed pop h! pop b ;recall remaining count jmp rep0 ;for the next character rep1: ot reboot, are we at end of buffer? cmp c! jc readnx ;go for another if not readen: ;end of read operation, store ble toggle kbchar: db 0 ;initial key char = 00 entsp: ds 2 ;entry stack pointer ds ssize*2 ;stack size lstack: ; end of Basict ;out to console ; func10: equ read ;read a buffered console line ; func11: ;check console status call conbrk ;(dre equ 1 ;number of bytes for "byte" type word equ 2 ;number of bytes for "word" type ; ; fixed addresses in low memory tfcb fh => 00h, means input mode inr a! jz constf ;0feH in C for status ;direct output function jmp conoutf ; dirinp: ** ;** B a s i c D i s k O p e r a t i n g S y s t e m *n pop h! mov m,b ;M(current len) = B mvi c,cr! jmp conout ;return carriage ;ret func1: ;return console character I/O System ; ;***************************************************************** ;*******************************************op through to sta$ret) sta$ret: ;store the A register to aret sta aret func$ret: ; ret ;jmp goback (pop stack for nequ 005ch ;default fcb location tbuff equ 0080h ;default buffer location ; ; fixed addresses referenced in bios module are ; call constf ;status check ora a! jz retmon ;skip, return 00 if not ready ;character is ready, get it call coninf ;to A* ;** ** ;********************************************************with echo call conech jmp sta$ret ; func2: equ tabout ;write console character with tab expansion ; func3: ;return r********************** ; ; common values shared between bdosi and bdos usrcode:db 0 ;current user number curdsk: db 0 ;curreon cp/m functions) ; setlret1: ;set lret = 1 mvi a,1! jmp sta$ret ; ; ; ; ; data areas ; compcol:db 0 ;true if co pererr (0009), selerr (000c), roderr (000f) ; ; error message handlers ; ;per$error: ;report permanent error to user jmp sta$ret ; func7: ;return io byte lda ioloc jmp sta$ret ; func8: ;set i/o byte lxi h,ioloc mov m,c ret ********* ;***************************************************************** ; dvers equ 22h ;version 2.2 ; module addresseseader character call readerf jmp sta$ret ; ;func4: equated to punchf ;write punch character ; ;func5: equated to listfnt disk number info: ds 2 ;information address aret: ds 2 ;address value to return lret equ aret ;low(aret) ; ;************mputing column position strtcol:db 0 ;starting column position after read column: db 0 ;column position listcp: db 0 ;listing; lxi h,pererr jmp goerr ; ;rod$error: ; ;report read/only disk error ; lxi h,roderr jmp goerr ; ; ;rof$error;jmp goback ; func9: ;write line until $ encountered xchg ;was lhld info mov c,l! mov b,h ;BC=string address jmp prin ; ; literal constants true equ 0ffh ;constant true false equ 000h ;constant false enddir equ 0ffffh ;end of directory byt ;write list character ;write to list device ; func6: ;direct console i/o - read if 0ffh mov a,c! inr a! jz dirinp ;0f***************************************************** ;***************************************************************** ;** : ; ;report read/only file error ; ; lxi h,roferr ;jmp goerr ; sel$error: ;report select error lxi h,selerr lect: mvi a,true! ora a! ret ;select disk function ok ; home: ;move to home position, then offset to start of dir call hchg! shld tranv ;.tran vector lxi h,buffa ;DE= source for move, HL=dest mvi c,addlist! call move ;addlist filled ;now fe track given by arecord (actual record) ;local equates for registers arech equ b! arecl equ c ;arecord = BC crech equ alloca, then fill ;the values of the disk parameter block lda curdsk! mov c,a ;current disk# to c ;lsb of e = 0 if not yeype (wrtype) is in register C ;wrtype = 0 => normal write operation ;wrtype = 1 => directory write operation ;wrtype = 2 = ; ; ; goerr: ;HL = .errorhandler, call subroutine mov e,m! inx h! mov d,m ;address of routine in DE xchg! pchl ;to subomef ;move to track 00, sector 00 reference ;lxi h,offset ;mov c,m ;inx h ;mov b,m ;call settrkf ; ;first directory positionill the disk parameter block lhld dpbaddr! xchg ;DE is source lxi h,sectpt ;HL is destination mvi c,dpblist! call move d! crecl equ e ;currec = DE ctrkh equ h! ctrkl equ l ;curtrk = HL tcrech equ h! tcrecl equ l ;tcurrec = HL ;load the t logged - in call seldskf ;HL filled by call ;HL = 0000 if error, otherwise disk headers mov a,h! ora l! rz ;return with > start of new block call writef ;current drive, track, sector, dma diocomp: ;check for disk errors ora a! rz ; lxi h,proutine ; ; ; ; local subroutines for bios interface ; move: ;move data length of length C from source DE to ;destinat selected xra a ;constant zero to accumulator lhld curtrka! mov m,a! inx h! mov m,a ;curtrk=0000 lhld curreca! mov m,a! in;data filled ;now set single/double map mode lhld maxall ;largest allocation number mov a,h ;00 indicates < 255 lxi registers from memory lxi h,arecord! mov arecl,m! inx h! mov arech,m lhld curreca ! mov crecl,m! inx h! mov crech,m lhld c0000 in HL and z flag ;disk header block address in hl mov e,m! inx h! mov d,m! inx h ;DE=.tran shld cdrmaxa! inx h! inererr ; jmp goerr ; seekdir: ;seek the record containing the current dir entry lhld dcnt ;directory counter to HL mvion given by HL inr c ;in case it is zero move0: dcr c! rz ;more to move ldax d! mov m,a ;one byte moved inx d! inxx h! mov m,a ;currec=0000 ;curtrk, currec both set to 0000 ret ; rdbuff: ;read buffer and check condition call readf ;h,single! mvi m,true ;assume a=00 ora a! jz retselect ;high order of maxall not zero, use double dm mvi m,false retseurtrka ! mov a,m! inx h! mov ctrkh,m! mov ctrkl,a ;loop while arecord < currec seek0: mov a,arecl! sub crecl! mov a,arechx h ;.cdrmax shld curtrka! inx h! inx h ;HL=.currec shld curreca! inx h! inx h ;HL=.buffa ;DE still contains .tran xi c,dskshf! call hlrotr ;value to HL shld arecord! shld drec ;ready for seek ; jmp seek ; ;ret ; ; seek: ;seek th h ;to next byte jmp move0 ; selectdisk: ;select the disk drive given by curdsk, and fill ;the base addresses curtrka -current drive, track, sector, dma jmp diocomp ;check for i/o errors ; wrbuff: ;write buffer and check condition ;write t! sbb crech jnc seek1 ;skip if arecord >= currec ;currec = currec - sectpt push ctrkh! lhld sectpt mov a,crecl! sdskmsk equ dirrec-1 fcbshf equ 5 ;log2(fcblen) ; extnum equ 12 ;extent number field maxext equ 31 ;largest extent number ubcord, DE=currec mov a,arecl! sub crecl! mov arecl,a mov a,arech! sbb crech! mov arech,a lhld tranv! xchg ;BC=sector#, DE=. ora a! ral! jmp dmpos1 dmpos2: ;arrive here with A = shl(ext and extmsk,7-blkshf) add b ;add the previous shr(vrecord,bl updated values in each register push arech! push crech! push ctrkh ;to stack for later ;stack contains (lowest) BC=arecord,or file access ; dm$position: ;compute disk map position for vrecord to HL lxi h,blkshf! mov c,m ;shift count to C lda vub l! mov crecl,a mov a,crech! sbb h! mov crech,a pop ctrkh ;curtrk = curtrk - 1 dcx ctrkh jmp seek0 ;for anoytes equ 13 ;unfilled bytes field modnum equ 14 ;data module number maxmod equ 15 ;largest module number fwfmsk equ 80h ;filetran call sectran ;HL = tran(sector) mov c,l! mov b,h ;BC = tran(sector) jmp setsecf ;sector selected ;ret ; ; file cokshf) value ;A is one of the following values, depending upon alloc ;bks blkshf ;1k 3 v/8 + extval * 16 ;2k 4 DE=currec, HL=curtrk xchg! lhld offset! dad d ;HL = curtrk+offset mov b,h! mov c,l! call settrkf ;track set up ;note thatrecord ;current virtual record to A dmpos0: ora a! rar! dcr c! jnz dmpos0 ;A = shr(vrecord,blkshf) = vrecord/2**(sect/blother try seek1: ;look while arecord >= (t:=currec + sectpt) push ctrkh lhld sectpt! dad crech ;HL = currec+sectpt write flag is high order modnum namlen equ 15 ;name length reccnt equ 15 ;record count field dskmap equ 16 ;disk map field ntrol block (fcb) constants empty equ 0e5h ;empty directory entry lstrec equ 127 ;last record# in extent recsiz equ 128 ;reco v/16+ extval * 8 ;4k 5 v/32+ extval * 4 ;8k 6 v/64+ extval * 2 ;16k 7 v/128+extval * 1 ret ;with dm$p BC - curtrk is difference to move in bios pop d ;recall curtrk lhld curtrka! mov m,e! inx h! mov m,d ;curtrk updated ;nowck) mov b,a ;save it for later addition mvi a,8! sub m ;8-blkshf to accumulator mov c,a ;extent shift count in register c jc seek2 ;can be > FFFFH mov a,arecl! sub tcrecl! mov a,arech! sbb tcrech jc seek2 ;skip if t > arecord ;currec = tlstfcb equ fcblen-1 nxtrec equ fcblen ranrec equ nxtrec+1;random record field (2 bytes) ; ; reserved file indicators rofilerd size fcblen equ 32 ;file control block size dirrec equ recsiz/fcblen ;directory elts / record dskshf equ 2 ;log2(dirrec) osition in A ; getdm: ;return disk map value from position given by BC lhld info ;base address of file control block lxi compute sector as arecord-currec pop crech ;recall currec lhld curreca! mov m,crecl! inx h! mov m,crech pop arech ;BC=are lda extval ;extent value ani extmsk dmpos1: ;blkshf = 3,4,5,6,7, C=5,4,3,2,1 ;shift is 4,3,2,1,0 dcr c! jz dmpos2 xchg ;curtrk = curtrk + 1 pop ctrkh! inx ctrkh jmp seek1 ;for another try seek2: pop ctrkh ;arrive here with equ 9 ;high order of first type char invis equ 10 ;invisible file in dir command ; equ 11 ;reserved ; ; utility functions f d,dskmap! dad d ;HL =.diskmap dad b ;index by a single byte value lda single ;single byte/map entry? ora a! jz getdmd ;geranfill setfcb1: mov c,a ;=1 if sequential i/o lda vrecord! add c! mov m,a ;fcb(nxtrec)=vrecord+seqio xchg! lda rcount!! xchg ;DE=.fcb(reccnt) lxi h,(nxtrec-reccnt)! dad d ;HL=.fcb(nxtrec) ret ; getfcb: ;set variables from currently addreslhld rodsk! lda curdsk! mov c,a! call hlrotr mov a,l! ani 1b! ret ;non zero if nowrite ; set$ro: ;set current disk to readkshf ;shift count to reg A lhld arecord atran0: dad h! dcr a! jnz atran0 ;shl(arecord,blkshf) shld arecord1 ;save shi ; hlrotl: ;rotate the mask in HL by amount in C inr c ;may be zero hlrotl0: dcr c! rz ;return if zero dad h! jmp hlrt disk map single byte mov l,m! mvi h,0! ret ;with HL=00bb getdmd: dad b ;HL=.fcb(dm+i*2) ;double precision value ret mov m,a ;fcb(reccnt)=rcount ret ; hlrotr: ;hl rotate right by amount C inr c ;in case zero hlrotr0: dcr c! rz ;returnsed fcb call getfcba ;addresses in DE, HL mov a,m! sta vrecord ;vrecord=fcb(nxtrec) xchg! mov a,m! sta rcount ;rcount=fcb( only lxi h,rodsk! mov c,m! inx h! mov b,m call set$cdisk ;sets bit to 1 shld rodsk ;high water mark in directory goes tfted block # lda blkmsk! mov c,a ;mask value to C lda vrecord! ana c ;masked value in A ora l! mov l,a ;to HL shld areotl0 ; set$cdisk: ;set a "1" value in curdsk position of BC push b ;save input parameter lda curdsk! mov c,a ;ready paraurned mov e,m! inx h! mov d,m! xchg! ret ; index: ;compute disk block number from current fcb call dm$position ;0...15 when zero mov a,h! ora a! rar! mov h,a ;high byte mov a,l! rar! mov l,a ;low byte jmp hlrotr0 ; ; compute$cs: ;coreccnt) call getexta ;HL=.fcb(extnum) lda extmsk ;extent mask to a ana m ;fcb(extnum) and extmsk sta extval ret ; seo max lhld dirmax! inx h! xchg ;DE = directory max lhld cdrmaxa ;HL = .cdrmax mov m,e! inx h! mov m,d ;cdrmax = dirmax cord ;arecord=HL or (vrecord and blkmsk) ret ; getexta: ;get current extent field address to A lhld info! lxi d,extnum! meter for shift lxi h,1 ;number to shift call hlrotl ;HL = mask to integrate pop b ;original mask mov a,c! ora l! mov l,in register A mov c,a! mvi b,0! call getdm ;value to HL shld arecord! ret ; allocated: ;called following index to see ifmpute checksum for current directory buffer mvi c,recsiz ;size of directory buffer lhld buffa ;current directory buffer xrtfcb: ;place values back into current fcb call getfcba ;addresses to DE, HL lda seqio cpi 02! jnz setfcb1! xra a ;check ret ; check$rodir: ;check current directory element for read/only status call getdptra ;address of element ; checkdad d ;HL=.fcb(extnum) ret ; getfcba: ;compute reccnt and nxtrec addresses for get/setfcb lhld info! lxi d,reccnt! dad da mov a,b! ora h! mov h,a ;HL = mask or rol(1,curdsk) ret ; nowrite: ;return true if dir checksum difference occurred block allocated lhld arecord! mov a,l! ora h! ret ; atran: ;compute actual record address, assuming index called lda bla a ;clear checksum value computecs0: add m! inx h! dcr c ;cs=cs+buff(recsiz-C) jnz computecs0 ret ;with checksum in A$rofile: ;check current buff(dptr) or fcb(0) for r/o status lxi d,rofile! dad d ;offset to ro bit mov a,m! ral! rnc ;retur,a ret ; newchecksum: mvi c,true ;drop through to compute new checksum checksum: ;compute current checksum record and u > dcnt lhld dcnt! xchg ;DE = directory counter lhld cdrmaxa ;HL=.cdrmax mov a,e! sub m ;low(dcnt) - low(cdrmax) inx h ;ta dma address ;ret ; rd$dir: ;read a directory entry into the directory buffer call setdir ;directory dma call rdbuff ;bring module number to accumulator ;(high order bit is fwf (file write flag) lhld info! lxi d,modnum! dad d ;HL=.fcb(mode cmp m ;compute$cs=check(drec)? rz ;no message if ok ;checksum error, are we beyond ;the end of the disk? cn if not set lxi h,roferr! jmp goerr ; ; jmp rof$error ;exit to read only disk message ; ; check$write: ;check for wripdate the ;directory element if C=true, or check for = if not ;drec < chksiz? lhld drec! xchg! lhld chksiz! call subdh ;DEHL = .cdrmax+1 mov a,d! sbb m ;hig(dcnt) - hig(cdrmax) ;condition dcnt - cdrmax produces cy if cdrmax>dcnt ret ; setcdr ;directory record loaded ; jmp setdata to data dma address ;ret ; setdata: ;set data dma address lxi h,dmanum) mov a,m! ret ;A=fcb(modnum) ; clrmodnum: ;clear the module number field for user open/make call getmodnum! mvi m,0 all compcdr rnc ;no message if so call set$ro ;read/only disk set ret initial$cs: ;initializing the checksum te protected disk call nowrite! rz ;ok to write if not rodsk lxi h,roderr! jmp goerr ; jmp rod$error ;read only disk error -HL rnc ;skip checksum if past checksum vector size ;drec < chksiz, so continue push b ;save init flag call compute$c: ;if not (cdrmax > dcnt) then cdrmax = dcnt+1 call compcdr rc ;return if cdrmax > dcnt ;otherwise, HL = .cdrmax+1, DE =ad! jmp setdma ;to complete the call ; setdir: ;set directory dma address lxi h,buffa ;jmp setdma to complete call ;fcb(modnum)=0 ret ; setfwf: call getmodnum ;HL=.fcb(modnum), A=fcb(modnum) ;set fwf (file write flag) to "1" ori fwfm mov m,a! ret ; ; wrdir: ;write the current directory entry, set checksum call newchecksum ;initialize entry call se ; getdptra: ;compute the address of a directory element at ;positon dptr in the buffer lhld buffa! lda dptr ; addh: s ;check sum value to A lhld checka ;address of check sum vector xchg lhld drec ;value of drec dad d ;HL = .check(dr dcnt inx d! mov m,d! dcx h! mov m,e ret ; subdh: ;compute HL = DE - HL mov a,e! sub l! mov l,a! mov a,d! sbb h! mov h; setdma: ;HL=.dma address to set (i.e., buffa or dmaad) mov c,m! inx h! mov b,m ;parameter ready jmp setdmaf ; ; dir$sk! mov m,a ;fcb(modnum)=fcb(modnum) or 80h ;also returns non zero in accumulator ret ; ; compcdr: ;return cy if cdrmaxtdir ;directory dma mvi c,1 ;indicates a write directory operation call wrbuff ;write the buffer jmp setdata ;to da ;HL = HL + A add l! mov l,a! rnc ;overflow to H inr h! ret ; ; getmodnum: ;compute the address of the module number ec) pop b ;recall true=0ffh or false=00 to C inr c ;0ffh produces zero flag jz initial$cs ;not initializing, comparto$user: ;copy the directory entry to the user buffer ;after call to search or searchn by user code lhld buffa! xchg ;sourin the low order accumulator position. HL is ;the address of the byte for possible replacement in ;memory upon return, and dir1: add a! dcr b! jnz read$dir1 ;A = (low(dcnt) and dskmsk) shl fcbshf sta dptr ;ready for next dir operation orasition), and ;target ALLOC position in registers HL, rotate and replace rrc! dcr d! jnz rotr ;back into position mov m,a ; read$dir: ;read next directory entry, with C=true if initializing lhld dirmax! xchg ;in preparation for subtract lhld dcmove the bit to the low order position of A rotl: rlc! dcr e! jnz rotl! ret ; ; setallocbit: ;BC is the bit position of Ace is directory buffer lhld dmaad ;destination is user dma address mvi c,recsiz ;copy entire record jmp move ;ret ; enD contains the number of shifts ;required to place the returned value back into position mov a,c! ani 111b! inr a! mov e,a! a! rnz ;return if not a new record push b ;save initialization flag C call seek$dir ;seek proper record call rd$dir ;rback to ALLOC ret ; scandm: ;scan the disk map addressed by dptr for non-zero ;entries, the allocation vector entry corrnt! inx h! shld dcnt ;dcnt=dcnt+1 ;continue while dirmax >= dcnt (dirmax-dcnt no cy) call subdh ;DE-HL jnc read$dir0 ;yLLOC to set or reset. The ;value of the bit is in register E. push d! call getallocbit ;shifted val A, count in D ani 111d$of$dir: ;return zero flag if at end of directory, non zero ;if not at end (end of dir if dcnt = 0ffffh) lxi h,dcnt! mov mov d,a ;d and e both contain the number of bit positions to shift mov a,c! rrc! rrc! rrc! ani 11111b! mov c,a ;C shr 3 to Cead the directory record pop b ;recall initialization flag jmp checksum ;checksum the directory elt ;ret ; ; getalloesponding ;to a non-zero entry is set to the value of C (0,1) call getdptra ;HL = buffa + dptr ;HL addresses the beginninges, set dcnt to end of directory jmp set$end$dir ; ; ret ; read$dir0: ;not at end of directory, seek next element1$1110b ;mask low bit to zero (may be set) pop b! ora c ;low bit of C is masked into A ; jmp rotr ;to rotate back into propera,m ;may be 0ffh inx h! cmp m ;low(dcnt) = high(dcnt)? rnz ;non zero returned if different ;high and low the same, = 0ffh? mov a,b! add a! add a! add a! add a! add a ;B shl 5 ora c! mov c,a ;bbbccccc to C mov a,b! rrc! rrc! rrc! ani 11111b! movcbit: ;given allocation vector position BC, return with byte ;containing BC shifted so that the least significant ;bit is of the directory entry lxi d,dskmap! dad d ;hl now addresses the disk map push b ;save the 0/1 bit to set mvi c,fcblen-ds ;initialization flag is in C lda dcnt! ani dskmsk ;low(dcnt) and dskmsk mvi b,fcbshf ;to multiply by fcb size read$ position ;ret rotr: ;byte value from ALLOC is in register A, with shift count ;in register C (to place bit back into po inr a ;0ffh becomes 00 if so ret ; set$end$dir: ;set dcnt to the end of the directory lxi h,enddir! shld dcnt! ret ; b,a ;BC shr 3 to BC lhld alloca ;base address of allocation vector dad b! mov a,m ;byte to A, hl = .alloc(BC shr 3) ;now kmap+1 ;size of single byte disk map + 1 scandm0: ;loop once for each disk map entry pop d ;recall bit parity dcr c! ) lhld cdrmaxa! mvi m,3! inx h! mvi m,0 ;cdrmax = 0000 call set$end$dir ;dcnt = enddir ;read directory entries and check! inx h ;HL = maxall/8+1 mov b,h! mov c,l ;count down BC til zero lhld alloca ;base of allocation vector ;fill the allocatb! mov c,a ;low bits removed from C pop psw! ana b ;low bits removed from A sub c! ani maxext ;set flags pop b ;restore orjz scanm3 lhld maxall ;check invalid index mov a,l! sub c! mov a,h! sbb b ;maxall - block# cnc set$alloc$bit ; : ;now scan the disk map for allocated blocks mvi c,1 ;set to allocated call scandm call setcdr ;set cdrmax to dcnt rz ;all done scanning? ;no, get next entry for scan push d ;replace bit parity lda single! ora a! jz scandm1 ;singl for allocated storage initial2: mvi c,true! call read$dir call end$of$dir! rz ;return if end of directory ;not end oion vector with zeros initial0: mvi m,0! inx h ;alloc(i)=0 dcx b ;count length down mov a,b! ora c! jnz initial0 ;siginal values ret ; search: ;search for directory element of length C at info mvi a,0ffh! sta dirloc ;changed if actuall ;bit set to 0/1 scanm3: ; pop h! inx h ;to next bit position pop b ;recall counter jmp scandm0 ;for anothe jmp initial2 ;for another entry ; copy$dirloc: ;copy directory location to lret following ;delete, rename, ... ops lde byte scan operation push b ;save counter push h ;save map address mov c,m! mvi b,0 ;BC=block# jmp scandm2 sf directory, valid entry? call getdptra ;HL = buffa + dptr mvi a,empty! cmp m jz initial2 ;go get another item ;not et the reserved space for the directory lhld dirblk! xchg lhld alloca ;HL=.alloc() mov m,e! inx h! mov m,d ;sets reserved y found lxi h,searchl! mov m,c ;searchl = C lhld info! shld searcha ;searcha = info call set$end$dir ;dcnt = enddir callr item ; initialize: ;initialize the current disk ;lret = false ;set to true if $ file exists ;compute the length of thea dirloc! jmp sta$ret ; ; ret ; ; compext: ;compare extent# in A with that in C, return nonzero ;if they do not mcandm1: ;double byte scan operation dcr c ;count for double byte push b ;save counter mov c,m! inx h! mov b,m ;Bempty, user code the same? lda usrcode cmp m! jnz pdollar ;same user code, check for '$' submit inx h! mov a,m ;firsdirectory blks ;allocation vector initialized, home disk call home ;cdrmax = 3 (scans at least one directory record home ;to start at the beginning ;(drop through to searchn) ; ; searchn: ;search for the next directory element, assumin allocation vector - 2 lhld maxall! mvi c,3 ;perform maxall/8 ;number of bytes in alloc vector is (maxall/8)+1 call hlrotratch push b ;save C's original value push psw! lda extmsk! cma! mov b,a ;B has negated form of extent mask mov a,c! ana C=block# push h ;save map address scandm2: ;arrive here with BC=block#, E=0/1 mov a,c! ora b ;skip if = 0000 t character sui '$' ;dollar file? jnz pdollar ;dollar file found, mark in lret dcr a! sta lret ;lret = 255 pdollarg ;a previous call on search which sets searcha and ;searchl mvi c,false! call read$dir ;read next dir element call end$et search$fin: ;end of directory, or empty name call set$end$dir ;may be artifical end mvi a,255! jmp sta$ret ; h push b ;save counters mov c,m ;directory character to c call compext ;compare user/dir char pop b ;recall coun ;left,right pushed call getallocbit rar! jnc retblock ;return block number if zero ;bit is one, so try the right po down searchloop: mov a,c! ora a! jz endsearch ldax d! cpi '?'! jz searchok ;? matches all ;scan next character i element jmp delete0 ;for another record ; get$block: ;given allocation vector position BC, find the zero bit ;closest of$dir! jz search$fin ;skip to end if so ;not end of directory, scan for match lhld searcha! xchg ;DE=beginning of user fc ; ; delete: ;delete the currently addressed file call check$write ;write protected? mvi c,extnum! call search ;search tters jnz searchn ;skip if no match searchok: ;current character matches inx d! inx h! inr b! dcr c jmp searchp b! pop d ;left, right restored righttst: lhld maxall ;value of maximum allocation# mov a,e! sub l! mov a,d! sbb h ;rigf not ubytes mov a,b! cpi ubytes! jz searchok ;not the ubytes field, extent field? cpi extnum ;may be extent field to this position by searching left and right. ;if found, set the bit to one and return the bit position ;in hl. if not founb ldax d ;first character cpi empty ;keep scanning if empty jz searchnext ;not empty, may be end of logical directorhrough file type delete0: ;loop while directory matches call end$of$dir! rz ;stop if end ;set each non zero disk map loop endsearch: ;entire name matches, return dir position lda dcnt! ani dskmsk! sta lret ;lret = low(dcnt) and 11ht=maxall? jnc retblock0 ;return block 0000 if so inx d! push b! push d ;left, right pushed mov b,d! mov c,e ;ready rig ldax d ;fcb character jz searchext ;skip to search extent sub m! ani 7fh ;mask-out flags/extent modulus jnz searcd (i.e., we pass 0 on the left, or ;maxall on the right), return 0000 in hl mov d,b! mov e,c ;copy of starting position to dy push d ;save search address call compcdr ;past logical end? pop d ;recall address jnc search$fin ;artificial stop entry to 0 ;in the allocation vector ;may be r/o file call check$rodir ;ro disk error if found call getdptra ;HL=.bub lxi h,dirloc! mov a,m! ral! rnc ;dirloc=0ffh? ;yes, change it to 0 to mark as found xra a! mov m,a ;dirloc=0 rht for call call getallocbit rar! jnc retblock ;return block number if zero pop d! pop b ;restore left and right pointehn ;skip if not matched jmp searchok ;matched character searchext: ;A has fcb character ;attempt an extent # matce lefttst: mov a,c! ora b! jz righttst ;skip if left=0000 ;left not at position zero, bit zero? dcx b! push d! push b searchnext: call getdptra ;HL = buffa+dptr lda searchl! mov c,a ;length of search to c mvi b,0 ;b counts up, c countsff(dptr) mvi m,empty mvi c,0! call scandm ;alloc elts set to 0 call wrdir ;write the directory call searchn ;to nextrs jmp lefttst ;for another attempt retblock: ral! inr a ;bit back into position and set to 1 ;d contains the number ir! rz ;stop at end of dir ;not end of directory, rename next element call check$rodir ;may be read-only file mvi c,dsk. the ;new name is contained in the last half of the ;currently addressed file conrol block. the file ;name and type are r lxi h,reccnt! dad d ;HL=.buff(dptr+reccnt) mov b,m ;B holds directory record count pop h! pop psw! mov m,a ;restore exte push d ;save length for later mvi b,0 ;double index to BC lhld info ;HL = source for data dad b! xchg ;DE=.fcb(C), sour end ;not end of directory, copy fcb information open$copy: ;(referenced below to copy fcb info) call getexta! mov a,m! pof shifts required to reposition call rotr ;move bit back to position and store pop h! pop d ;HL returned value, DE discarmap! mvi e,extnum! call copy$dir ;element renamed, move to next call searchn jmp rename0 ; indicators: ;set file inchanged, but the reel number ;is ignored. the user number is identical call check$write ;may be write protected ;search unt number ;HL = .user extent#, B = dir rec cnt, C = dir extent# ;if user ext < dir ext then user := 128 records ;if user ece for copy call getdptra ;HL=.buff(dptr), destination pop b ;DE=source, HL=dest, C=length call move ;data moved seek$copush psw! push h ;save extent# call getdptra! xchg ;DE = .buff(dptr) lhld info ;HL=.fcb(0) mvi c,nxtrec ;length of move opeded ret retblock0: ;cannot find an available bit, return 0000 mov a,c ; ora b! jnz lefttst ;also at beginning dicators for current fcb mvi c,extnum! call search ;through file type indic0: call end$of$dir! rz ;stop at end of dir p to the extent field mvi c,extnum! call search ;copy position 0 lhld info! mov a,m ;HL=.fcb(0), A=fcb(0) lxi d,dskmap! xt = dir ext then user := dir records ;if user ext > dir ext then user := 0 records mov a,c! cmp m! mov a,b ;ready dir reccy: ;enter from close to seek and copy current element call seek$dir ;to the directory element jmp wrdir ;write the directoration push d ;save .buff(dptr) call move ;from .buff(dptr) to .fcb(0) ;note that entire fcb is copied, including indicato lxi h,0000h! ret ; copy$fcb: ;copy the entire file control block mvi c,0! mvi e,fcblen ;start at 0, to fcblen-1 ; ;not end of directory, continue to change mvi c,0! mvi e,extnum ;copy name call copy$dir call searchn jmp indic0 ; dad d;HL=.fcb(dskmap) mov m,a ;fcb(dskmap)=fcb(0) ;assume the same disk drive for new named file rename0: call end$of$dnt jz open$rcnt ;if same, user gets dir reccnt mvi a,0! jc open$rcnt ;user is larger mvi a,128 ;directory is larger ory element ;ret ; ; rename: ;rename the file described by the first half of ;the currently addressed file control blockrs call setfwf ;sets file write flag pop d! lxi h,extnum! dad d ;HL=.buff(dptr+extnum) mov c,m ;C = directory extent numbejmp copy$dir ; ; copy$dir: ;copy fcb information starting at C for E bytes ;into the currently addressed directory entry open: ;search for the directory entry, copy to fcb mvi c,namlen! call search call end$of$dir! rz ;return with lret=255 ifpen$rcnt: ;A has record count to fill lhld info! lxi d,reccnt! dad d! mov m,a ret ; mergezero: ;HL = .fcb1(i), DE = .fcbgerr ;high same? ;merge operation ok for this pair dcr c ;extra count for double byte dmset: inx d! inx h ;to next bybnzero ;fcb(i) = 0 mov m,a ;fcb(i) = buff(i) fcbnzero: ora a! jnz buffnzero ;buff(i) = 0 mov a,m! stax d ;hld info ;info = .empty mvi c,1! call search ;length 1 match on empty entry call end$of$dir ;zero flag set if no space popcate file call end$of$dir! rz ;return if not found ;merge the disk map at info with that at buff(dptr) lxi b,dskmap! call xchg! dad b ;DE=.buff(reccnt), HL=.fcb(reccnt) mov a,m! stax d ;buff(reccnt)=fcb(reccnt) endmerge: mvi a,true! sta f2(i), ;if fcb1(i) = 0 then fcb1(i) := fcb2(i) mov a,m! inx h! ora m! dcx h! rnz ;return if = 0000 ldax d! mov m,a! inx d! te position dcr c! jnz merge0 ;for more ;end of disk map merge, check record count ;DE = .buff(dptr)+32, HL = .fcb(32) buff(i)=fcb(i) buffnzero: cmp m! jnz mergerr ;fcb(i) = buff(i)? jmp dmset ;if merge ok merged: ;this is a double b h ;recall info address shld info ;in case we return here rz ;return with error condition 255 if not found xchg ;DE = infogetdptra dad b! xchg ;DE is .buff(dptr+16) lhld info! dad b ;DE=.buff(dptr+16), HL=.fcb(16) mvi c,(fcblen-dskmap) ;length cb$copied ;mark as copied jmp seek$copy ;ok to "wrdir" here - 1.4 compat ; ret ; mergerr: ;elements did not merge inx h ;low byte copied ldax d! mov m,a! dcx d! dcx h ;back to input form ret ; close: ;locate the directory element and lxi b,-(fcblen-extnum)! dad b! xchg! dad b ;DE = .fcb(extnum), HL = .buff(dptr+extnum) ldax d ;current user extent numbyte merge operation call mergezero ;buff = fcb if buff 0000 xchg! call mergezero! xchg ;fcb = buff if fcb 0000 ;they sh address ;clear the remainder of the fcb lxi h,namlen! dad d ;HL=.fcb(namlen) mvi c,fcblen-namlen ;number of bytes to fillof single byte dm merge0: lda single! ora a! jz merged ;skip to double ;this is a single byte map ;if fcb(i) = 0 thencorrectly lxi h,lret! dcr m ;=255 non zero flag set ret ; make: ;create a new file by creating a directory entry ;there-write it xra a! sta lret! sta dcnt! sta dcnt+1 ; call nowrite! rnz ;skip close if r/o disk ;check file write flag - 0 ier ;if fcb(ext) >= buff(fcb) then ;buff(ext) := fcb(ext), buff(rec) := fcb(rec) cmp m! jc endmerge ;fcb extent numbeould be identical at this point ldax d! cmp m! jnz mergerr ;low same? inx d! inx h ;to high byte ldax d! cmp m! jnz mer xra a ;clear accumulator to 00 for fill make0: mov m,a! inx h! dcr c! jnz make0 lxi h,ubytes! dad d ;HL = .fcb(ubytes) fcb(i) = buff(i) ;if buff(i) = 0 then buff(i) = fcb(i) ;if fcb(i) <> buff(i) then error mov a,m! ora a! ldax d! jnz fcn opening the file call check$write ;may be write protected lhld info! push h ;save fcb address, look for e5 lxi h,efcb! sndicates written call getmodnum ;fcb(modnum) in A ani fwfmsk! rnz ;return if bit remains set mvi c,namlen! call search ;lor >= dir extent number mov m,a ;buff(ext) = fcb(ext) ;update directory record count field lxi b,(reccnt-extnum)! dad b! mov m,a ;fcb(ubytes) = 0 call setcdr ;may have extended the directory ;now copy entry to the directory call copy$fcb ;with lret = 1 jmp open$reel2 open$reel1: ;not end of file, open call open$copy open$reel2: call getfcb ;)=++1 ;module number incremented, check for overflow mov a,m! ani maxmod ;mask high order bits jz open$r$err ;cannot ovmpatible with 1.4) call allocated ;arecord=0000? jz diskeof ;record has been allocated, read it call atran ;arecord module if zero ;may be in the same extent group mov b,a! lda extmsk! ana b ;if result is zero, then not in the same groupvrecord! lxi h,rcount! cmp m ;vrecord-rcount ;skip if rcount > vrecord jc recordok ;not enough records in the extent ;;and set the file write flag to "1" jmp setfwf ;ret ; open$reel: ;close the current extent, and open the next one ;if set parameters xra a! jmp sta$ret ;lret = 0 ; ; ret ;with lret = 0 open$r$err: ;cannot move to next extent of this ferflow to zero ;otherwise, ok to continue with new module open$reel0: mvi c,namlen! call search ;next extent found? cnow a disk address call seek ;to proper track,sector call rdbuff ;to dma address jmp setfcb ;replace parameter ; ret lxi h,fcb$copied ;true if the fcb was copied to directory ana m ;produces a 00 in accumulator if not written jz open$reelrecord count must be 128 to continue cpi 128 ;vrecord = 128? jnz diskeof ;skip if vrecord<>128 call open$reel ;go to nepossible. RMF is true if in read mode xra a! sta fcb$copied ;set true if actually copied call close ;close current extentile call setlret1 ;lret = 1 jmp setfwf ;ensure that it will not be closed ;ret ; seqdiskread: ;sequential disk readall end$of$dir! jnz open$reel1 ;end of file encountered lda rmf! inr a ;0ffh becomes 00 if read jz open$r$err ;sets ; diskeof: jmp setlret1 ;lret = 1 ;ret ; seqdiskwrite: ;sequential disk write mvi a,1! sta seqio ;drop thro0 ;go to next physical extent ;result is non zero, so we must be in same logical ext jmp open$reel1 ;to copy fcb informationxt extent if so xra a! sta vrecord ;vrecord=00 ;now check for open ok lda lret! ora a! jnz diskeof ;stop at eof recor ;lret remains at enddir if we cannot open the next ext call end$of$dir! rz ;return if end ;increment extent number lh operation mvi a,1! sta seqio ;drop through to diskread ; diskread: ;(may enter from seqdiskread) mvi a,true! sta rmf ;rlret = 1 ;try to extend the current file call make ;cannot be end of directory call end$of$dir jz open$r$errugh to diskwrite ; diskwrite: ;(may enter here from seqdiskwrite above) mvi a,false! sta rmf ;read mode flag ;write record open$mod: ;extent number overflow, go to next module lxi b,(modnum-extnum)! dad b ;HL=.fcb(modnum) inr m ;fcb(modnumdok: ;arrive with fcb addressing a record to read call index ;error 2 if reading unwritten data ;(returns 1 to be cold info! lxi b,extnum! dad b ;HL=.fcb(extnum) mov a,m! inr a! ani maxext! mov m,a ;fcb(extnum)=++1 jz open$mod ;move to nextead mode flag = true (open$reel) ;read the next record from the current fcb call getfcb ;sets parameters for the read lda to currently selected file call check$write ;in case write protected lhld info ;HL = .fcb(0) call check$rofile ;may be a m,e! inx h! mov m,d ;double wd diskwru: ;disk write to previously unallocated block mvi c,2 ;marked as unallocated wri mvi a,2! jmp sta$ret ;lret=2 blockok: ;allocated block number is in HL shld arecord xchg ;block number to DE ;increment record count if rcount<=vrecord lda vrecord! lxi h,rcount! cmp m ;vrecord-rcount jc diskwr2 ;rcount <= vrecvalue 0 if no space has been allocated call dm$position sta dminx ;save for later lxi b,0000h ;may use block zero or; mvi c,2 ; fill1: shld arecord! push b! call seek! pop b ; call wrbuff ;write fill record ; lhld arecord! ;resread-only file call getfcb ;to set local parameters lda vrecord! cpi lstrec+1 ;vrecord-128 ;skip if vrecord > lstrec ;vte diskwr1: ;continue the write operation of no allocation error ;C = 0 if normal write, 2 if to prev unalloc block lda lhld info! lxi b,dskmap! dad b ;HL=.fcb(dskmap) lda single! ora a ;set flags for single byte dm lda dminx ;recall dm indexord mov m,a! inr m ;rcount = vrecord+1 mvi c,2 ;mark as record count incremented diskwr2: ;A has vrecord, C=2 if new ba a! jz nopblock ;skip if no previous block ;previous block exists at A mov c,a! dcx b ;previous block # in BC call tore last record mvi c,0 ;change allocate flag lda blkmsk! mov b,a! ana l! cmp b!inx h ; jnz fill1 ;cont untirecord = 128, cannot open next extent jnc setlret1 ;lret=1 ; diskwr0: ;can write the next record, so continue call inlret! ora a! rnz ;stop if non zero returned value push b ;save write flag call atran ;arecord set lda seqio! dcr a! dcr a jz allocwd ;skip if allocating word ;allocating a byte value call addh! mov m,e ;single byte alloc jmp diskwru ;lock or new record# dcr c! dcr c! jnz noupdate push psw ;save vrecord value call getmodnum ;HL=.fcb(modnum), A=fcb(modnugetdm ;previous block # to HL mov b,h! mov c,l ;BC=prev block# nopblock: ;BC = 0000, or previous block # call getl cluster is zeroed pop h! shld arecord! call setdata diskwr11: ; call seek ;to proper file position pop b! push b dex call allocated mvi c,0 ;marked as normal write operation for wrbuff jnz diskwr1 ;not allocated ;the argument to ! jnz diskwr11 ; pop b! push b! mov a,c! dcr a! dcr a ; jnz diskwr11 ;old allocation push h ;arecord in hl ret frto continue allocwd: ;allocate a word value mov c,a! mvi b,0 ;double(dminx) dad b! dad b ;HL=.fcb(dminx*2) movm) ;reset the file write flag to mark as written fcb ani (not fwfmsk) and 0ffh ;bit reset mov m,a ;fcb(modnum) = fcb(mo$block ;block # to HL ;arrive here with block# or zero mov a,l! ora h! jnz blockok ;cannot find a block to allocate ;restore/save write flag (C=2 if new block) call wrbuff ;written to disk pop b ;C = 2 if a new block was allocated, 0 if notgetblock is the starting ;position for the disk search, and should be ;the last allocated block for this file, or ;the om atran lhld buffa! mov d,a ;zero buffa & fill fill0: mov m,a! inx h! inr d! jp fill0 ; call setdir! lhld arecord1 dnum) and 7fh pop psw ;restore vrecord noupdate: ;check for end of extent, if found attempt to open ;next extent in pred d ;HL = .fcb(nxtrec) mov m,a ;sought rec# stored away ;arrive here with B=mod#, C=ext#, DE=.fcb, rec stored ;the r/w flmov a,m! ral ;cy=lsb of extent# inx h! mov a,m! ral! ani 11111b ;A=ext# mov c,a ;C holds extent number, record stacked l,5 ;cannot create new extent #5 lda lret! inr a! jz badseek ;no dir space ;file make operation successful seekok: pot time nospace: mvi m,0 ;lret = 00 for returned value diskwr3: jmp setfcb ;replace parameters ;ret ; rseek: ;ranet! inr a! jz badseek lxi h,extnum! dad d! mov m,c ;fcb(extnum)=ext# lxi h,modnum! dad d! mov m,b ;fcb(modnum)=mod# calparation for next write cpi lstrec ;vrecord=lstrec? jnz diskwr3 ;skip if not ;may be random access write, if so we are donag is still stacked. compare fcb values lxi h,extnum! dad d! mov a,c ;A=seek ext# sub m! jnz ranclose ;tests for = extentmov a,m! rar! rar! rar! rar! ani 1111b ;mod# mov b,a ;B holds module#, C holds ext# pop psw ;recall sought record # ;chp b ;discard r/w flag xra a! jmp sta$ret ;with zero set badseek: ;fcb no longer contains a valid fcb, mark ;with 11dom access seek operation, C=0ffh if read mode ;fcb is assumed to address an active file control block ;(modnum has been setl open ;is the file present? lda lret! inr a! jnz seekok ;open successful? ;cannot open the file, read mode? pop b ;r/we ;change next lda seqio! cpi 1! jnz diskwr3 ;skip next extent open op ;update current fcb before going to next s ;extents match, check mod# lxi h,modnum! dad d! mov a,b ;B=seek mod# ;could be overflow at eof, producing module# eck to insure that high byte of ran rec = 00 inx h! mov l,m ;l=high byte (must be 00) inr l! dcr l! mvi l,6 ;zero flag, l=00$000b in modnum field so that it ;appears as overflow with file write flag set push h ;save error flag call getmodnum to 1100$0000b if previous bad seek) xra a! sta seqio ;marked as random access operation rseek1: push b ;save r/w flag lh flag to c (=0ffh if read) push b ;everyone expects this item stacked mvi l,4 ;seek to unwritten extent #4 inr c ;becomextent call setfcb call open$reel ;rmf=false ;vrecord remains at lstrec causing eof if ;no more directory space is a;of 90H or 10H, so compare all but fwf sub m! ani 7fh! jz seekok ;same? ranclose: push b! push d ;save seek mod#,ext#, .6 ;produce error 6, seek past physical eod jnz seekerr ;otherwise, high byte = 0, A = sought record lxi h,nxtrec! da ;HL = .modnum mvi m,1100$0000b pop h ;and drop through seekerr: pop b ;discard r/w flag mov a,l! sta lret ;lret=#ld info! xchg ;DE will hold base of fcb lxi h,ranrec! dad d ;HL=.fcb(ranrec) mov a,m! ani 7fh! push psw ;record number es 00 if read operation jz badseek ;skip to error if read operation ;write operation, make new extent call make mvi vailable lxi h,lret! mov a,m! ora a! jnz nospace ;space available, set vrecord=255 dcr a! sta vrecord ;goes to 00 nexfcb call close ;current extent closed pop d! pop b ;recall parameters and fill mvi l,3 ;cannot close error #3 lda lr, nonzero ;setfwf returns non-zero accumulator for err jmp setfwf ;flag set, so subsequent close ok ;ret ; randiskrea ;ls byte mov a,b! sbb m! inx h ;middle byte mov a,e! sbb m ;carry if .fcb(ranrec) > directory jc getnextsize ;for anote size for current fcb mvi c,extnum call search ;zero the receiving ranrec field lhld info! lxi d,ranrec! dad d! push h o=curdsk mov m,a ;curdsk=info jmp select ;ret ; reselect: ;check current fcb to see if reselection necessary mvi a,t0 add c! mov c,a! mvi a,0! adc b! mov b,a ;BC = 0000 000? errrr rrrr mov a,m! rrc! ani 0fh! add b! mov b,a ;BC = 000? eeubsequent input or output ops lhld dlog! lda curdsk! mov c,a! call hlrotr push h! xchg ;save it for test below, send to seldd: ;random disk read operation mvi c,true ;marked as read operation call rseek cz diskread ;if seek successful ret ; her try ;fcb is less or equal, fill from directory mov m,e! dcx h! mov m,b! dcx h! mov m,c getnextsize: call searchn ;save position mov m,d! inx h! mov m,d! inx h! mov m,d;=00 00 00 getsize: call end$of$dir jz setsize ;current fcb arue! sta resel ;mark possible reselect lhld info! mov a,m ;drive select code ani 1$1111b ;non zero is auto drive select dcee errrr rrrr lxi h,modnum! dad d! mov a,m ;A=XXX? mmmm add a! add a! add a! add a ;cy=? A=mmmm 0000 push psw! add b! mov sk call selectdisk! pop h ;recall dlog vector cz sel$error ;returns true if select ok ;is the disk logged in? mov a,l! r randiskwrite: ;random disk write operation mvi c,false ;marked as write operation call rseek cz diskwrite ;if seek succ jmp getsize setsize: pop h ;discard .fcb(ranrec) ret ; setrandom: ;set random record from the current file control ddressed by dptr call getdptra! lxi d,reccnt ;ready for compute size call compute$rr ;A=0000 000? BC = mmmm eeee errr rr a ;drive code normalized to 0..30, or 255 sta linfo ;save drive code cpi 30! jnc noselect ;auto select function, save cb,a ;cy=?, BC = mmmm eeee errr rrrr push psw ;possible second carry pop h ;cy = lsb of L mov a,l ;cy = lsb of A pop h ar! rc ;return if bit is set ;disk not logged in, set bit and initialize lhld dlog! mov c,l! mov b,h ;call ready call set$essful ret ; compute$rr: ;compute random record position for getfilesize/setrandom xchg! dad d ;DE=.buf(dptr) or .fcb(block lhld info! lxi d,nxtrec ;ready params for computesize call compute$rr ;DE=info, A=cy, BC=mmmm eeee errr rrrr lxi h,rrrr ;compare with memory, larger? pop h! push h ;recall, replace .fcb(ranrec) mov e,a ;save cy mov a,c! sub m! inx hurdsk lda curdsk! sta olddsk ;olddsk=curdsk mov a,m! sta fcbdsk ;save drive code ani 1110$0000b! mov m,a ;preserve hi b;cy = lsb of L ora l ;cy/cy = lsb of A ani 1 ;A = 0000 000? possible carry-out ret ; getfilesize: ;compute logical filcdisk! shld dlog ;dlog=set$cdisk(dlog) jmp initialize ;ret ; curselect: lda linfo! lxi h,curdsk! cmp m! rz ;skip if linf0), HL = .f(nxtrec/reccnt) mov c,m! mvi b,0 ;BC = 0000 0000 ?rrr rrrr lxi h,extnum! dad d! mov a,m! rrc! ani 80h ;A=e000 000anrec! dad d ;HL = .fcb(ranrec) mov m,c! inx h! mov m,b! inx h! mov m,a ;to ranrec ret ; select: ;select disk info for sits call curselect noselect: ;set user code lda usrcode ;0...31 lhld info! ora m! mov m,a ret ; ; individual eselect jmp make ;ret ;jmp goback ; func23: ;rename a file call reselect call rename jmp copy$dirloc ;ret ;jmp gr ;ret ;jmp goback ; func18: ;search for next occurrence of a file name lhld searcha! shld info call reselect! call se ani 1fh! sta usrcode ret ;jmp goback ; func33: ;random disk read operation call reselect jmp randiskread ;to perfole number call reselect jmp open ;ret ;jmp goback ; func16: ;close file call reselect jmp close ;ret ;jmp gobackt ;jmp goback ; func29: ;return r/o bit vector lhld rodsk! jmp sthl$ret ; ; ret ;jmp goback ; func30: ;set file indifunction handlers func12: ;return version number mvi a,dvers! jmp sta$ret ;lret = dvers (high = 00) ; ret ;jmp goback ; oback ; func24: ;return the login vector lhld dlog! jmp sthl$ret ; ; ret ;jmp goback ; func25: ;return selected disarchn jmp dir$to$user ;copy directory entry to user ;ret ;jmp goback ; func19: ;delete a file call reselect call delrm the disk read ;ret ;jmp goback ; func34: ;random disk write operation call reselect jmp randiskwrite ;to perform th ; func17: ;search for first occurrence of a file mvi c,0 ;length assuming '?' true xchg ;was lhld info mov a,m! cpcators call reselect call indicators jmp copy$dirloc ;lret=dirloc ;ret ;jmp goback ; func31: ;return address of diskfunc13: ;reset disk system - initialize to disk 0 lxi h,0! shld rodsk! shld dlog xra a! sta curdsk ;note that usrcode remak number lda curdsk! jmp sta$ret ; ; ret ;jmp goback ; func26: ;set the subsequent dma address to info xchg ;was lhlete jmp copy$dirloc ;ret ;jmp goback ; func20: ;read a file call reselect jmp seqdiskread ; ;jmp goback ; fue disk write ;ret ;jmp goback ; func35: ;return file size (0-65536) call reselect jmp getfilesize ;ret ;jmp goback i '?' ;no reselect if ? jz qselect ;skip reselect if so ;normal search call getexta! mov a,m! cpi '?' ; cnz clrmodnu parameter block lhld dpbaddr sthl$ret: shld aret ret ;jmp goback func32: ;set user code lda linfo! cpi 0ffhins unchanged lxi h,tbuff! shld dmaad ;dmaad = tbuff call setdata ;to data dma address jmp select ;ret ;jmp gobacd info shld dmaad ;dmaad = info jmp setdata ;to data dma address ;ret ;jmp goback ; func27: ;return the login nc21: ;write a file call reselect jmp seqdiskwrite ; ;jmp goback ; func22: ;make a file call clrmodnum call r; func36: equ setrandom ; ;set random record ;ret ;jmp goback func37: ; lhld info mov a,l! cma! mov e,a! mov a,h! cm ;module number zeroed call reselect mvi c,namlen qselect: call search jmp dir$to$user ;copy directory entry to use! jnz setusrcode ;interrogate user code instead lda usrcode! jmp sta$ret ;lret=usrcode ; ret ;jmp goback setusrcode: k ; func14: equ curselect ; ;select disk info ;ret ;jmp goback ; func15: ;open file call clrmodnum ;clear the moduvector address lhld alloca! jmp sthl$ret ; ; ret ;jmp goback ; func28: equ set$ro ; ;write protect current disk ;rema lhld dlog! ana h! mov d,a! mov a,l! ana e mov e,a! lhld rodsk! xchg! shld dlog mov a,l! ana e! mov l,a mov a,h! ana ds byte ;block shift factor blkmsk: ds byte ;block mask extmsk: ds byte ;extent mask maxall: ds word ;maximum allocation number to cur dir max value curtrka:ds word ;current track address curreca:ds word ;current record address buffa: ds word ;pointer ;address of last logged disk on warm start buff equ 0080h ;default buffer address retry equ 10 ;max retries on disk i/o beforndom disk write with zero fill of unallocated block call reselect mvi a,2! sta seqio mvi c,false call rseek1 cz diskwre of "true" false equ not true ;"false" test equ false ;true if test bios ; if test bias equ 03400h ;base of CCP in test s! mov h,a shld rodsk! ret ; ; goback: ;arrive here at end of processing to return to user lda resel! ora a! jz retmon r dirmax: ds word ;largest directory number dirblk: ds word ;reserved allocation bits for directory chksiz: ds word ;size of to directory dma address dpbaddr:ds word ;current disk parameter block address checka: ds word ;current checksum vector addree error ; ; perform following functions ; boot cold start ; wboot warm start (save i/o byte) ; (boot and wboot are the sameite ;if seek successful ret ; ; ; data areas ; ; initialized data efcb: db empty ;0e5=available dir entry rodsk: dw 0 ;ystem endif if not test bias equ 0000h ;generate relocatable cp/m system endif ; patch equ 1600h ; org patch cpmb e ;reselection may have taken place lhld info! mvi m,0 ;fcb(0)=0 lda fcbdsk! ora a! jz retmon ;restore disk number mchecksum vector offset: ds word ;offset tracks at beginning dpblist equ $-sectpt ;size of area ; ; local variables tranv: dss alloca: ds word ;current allocation vector address addlist equ $-buffa ;address list size ; ; sectpt - offset obtained fr for mds) ; const console status ; reg-a = 00 if no character ready ; reg-a = ff if character ready ; conin console characread only disk vector dlog: dw 0 ;logged-in disks dmaad: dw tbuff ;initial dma address ; ; curtrka - alloca are set upon disqu $-patch ;base of cpm console processor bdos equ 806h+cpmb ;basic dos (resident portion) cpml equ $-cpmb ;length (in bytes) ov m,a ;fcb(0)=fcbdsk lda olddsk! sta linfo! call curselect ; ; return from the disk monitor retmon: lhld entsp! sphl ;u; MDS-800 I/O Drivers for CP/M 2.2 ; (four drive single density version) ; ; Version 2.2 February, 1980 ; vers equ 22 ;versom disk parm block at dpbaddr ; (data must be adjacent, do not insert variables) sectpt: ds word ;sectors per track blkshf: dter in (result in reg-a) ; conout console character out (char in reg-c) ; list list out (char in reg-c) ; punch punch out (chk select ; (data must be adjacent, do not insert variables) ; (address of translate vector, not used) cdrmaxa:ds word ;pointeof cpm system nsects equ cpml/128 ;number of sectors to load offset equ 2 ;number of disk tracks used by cp/m cdisk equ 0004hser stack restored lhld aret! mov a,l! mov b,h ;BA = HL = aret ret func38: equ func$ret func39 equ func$ret func40: ;raion 2.2 ; ; Copyright (c) 1980 ; Digital Research ; Box 579, Pacific Grove ; California, 93950 ; ; true equ 0ffffh ;valuar in reg-c) ; reader paper tape reader in (result to reg-a) ; home move to track 00 ; ; (the following calls set-up the io equ 0f800h ;mds monitor rmon80 equ 0ff0fh ;restart mon80 (boot error) ci equ 0f803h ;console character to reg-a ri equ 0f806 ; are tailored to the particular operating environment, and must ; be altered for any system which differs from the intel mds.sp,buff+80h lxi h,signon call prmsg ;print message xra a ;clear accumulator sta cdisk ;set initially to disk a jmp gocindiviual routines jmp boot wboote: jmp wboot jmp const jmp conin jmp conout jmp list jmp punch jmp reader jmp equ 4h ;read function writf equ 6h ;write function recal equ 3h ;recalibrate drive iordy equ 4h ;i/o finished mask cr equ 0dparameter block for the ; mds, which is used to perform subsequent reads and writes) ; seldsk select disk given by reg-c (0,1,h ;reader in to reg-a co equ 0f809h ;console char from c to console out po equ 0f80ch ;punch char from c to punch device lo e ; ; the following code assumes the mds monitor exists at 0f800h ; and uses the i/o subroutines within the monitor ; ; we apm ;go to cp/m ; ; wboot:; loader on track 0, sector 1, which will be skipped for warm ; read cp/m from disk - assuming thehome jmp seldsk jmp settrk jmp setsec jmp setdma jmp read jmp write jmp listst ;list status jmp sectran ; mach ;carriage return lf equ 0ah ;line feed ; signon: ;signon message: xxk cp/m vers y.y db cr,lf,lf if test db '32' ;32k 2...) ; settrk set track address (0,...76) for subsequent read/write ; setsec set sector address (1,...,26) for subsequent reaqu 0f80fh ;list from c to list device csts equ 0f812h ;console status 00/ff to register a ; ; disk ports and commands base elso assume the mds system has four disk drives revrt equ 0fdh ;interrupt revert port intc equ 0fch ;interrupt mask port icon re is a 128 byte cold start ; start. ; lxi sp,buff ;using dma - thus 80 thru ff available for stack ; mvi c,retry ;max relib diskdef ;load the disk definition library disks 4 ;four disks diskdef 0,1,26,6,1024,243,64,64,offset diskdef 1,0 disexample bios endif if not test db '00' ;memory size filled by relocator endif db 'k CP/M vers ' db vers/10+'0','.',vd/write ; setdma set subsequent dma address (initially 80h) ; ; (read and write assume previous calls to set up the io paramequ 78h ;base of disk command io ports dstat equ base ;disk status (input) rtype equ base+1 ;result type (input) rbyte equ basequ 0f3h ;interrupt control port inte equ 0111$1110b ;enable rst 0(warm boot), rst 7 (monitor) ; ; mds monitor equates mon80tries push b wboot0: ;enter here on error retries lxi b,cpmb ;set dma address to start of disk system call setdma mvi ckdef 2,0 diskdef 3,0 ; endef occurs at end of assembly ; ; end of controller - independent code, the remaining subroutines ers mod 10+'0' db cr,lf,0 ; boot: ;print signon message and go to ccp ; (note: mds boot initialized iobyte at 0003h) lxi ters) ; read read track/sector to preset dma address ; write write track/sector from preset dma address ; ; jump vector for e+3 ;result byte (input) ; ilow equ base+1 ;iopb low address (output) ihigh equ base+2 ;iopb high address (output) ; readf ,0 ;boot from drive 0 call seldsk mvi c,0 call settrk ;start with track 0 mvi c,2 ;start reading sector 2 call setsec terr: pop b ;recall counts dcr c jz booter0 ; try again push b jmp wboot0 ; booter0: ; otherwise too many retries lxi b,buff call setdma ; ; reset monitor entry points mvi a,jmp sta 0 lxi h,wboote shld 1 ;jmp wboot at location 00 rive mvi a,00110000b ;selects drive 1 in bank setdrive: mov b,a ;save the function lxi h,iof ;io function mov a,m ani,a ;ready for call call settrk xra a ;clear sector number rd1: inr a ;to next sector mov c,a ;ready for call call setsemds call) jmp po ; reader: ;reader character in to reg-a ; (exactly the same as mds call) jmp ri ; home: ;move to home ; ; read sectors, count nsects to zero pop b ;10-error count mvi b,nsects rdsec: ;read next sector push b ;save sector lxi h,bootmsg call prmsg jmp rmon80 ;mds hardware monitor ; bootmsg: db '?boot',0 ; ; const: ;console status to reg sta 5 lxi h,bdos shld 6 ;jmp bdos at location 5 if not test sta 7*8 ;jmp to mon80 (may have been changed by ddt) lxi 11001111b ;mask out disk number ora b ;mask in new disk number mov m,a ;save it in iopb mov l,c mvi h,0 ;HL=disk numberc pop b ;recall sector count dcr b ;done? jnz rdsec ; ; done with the load, reset default buffer address gocpm: ;(enterposition ; treat as track 00 seek mvi c,0 jmp settrk ; seldsk: ;select disk given by register c lxi h,0000h ;return 000count call read jnz booterr ;retry if errors occur lhld iod ;increment dma address lxi d,128 ;sector size dad d ;incre-a ; (exactly the same as mds call) jmp csts ; conin: ;console character to reg-a call ci ani 7fh ;remove parity bit h,mon80 shld 7*8+1 endif ; leave iobyte set ; previously selected disk was b, send parameter to cpm lda cdisk ;last log dad h ;*2 dad h ;*4 dad h ;*8 dad h ;*16 lxi d,dpbase dad d ;HL=disk header table address ret ; ; settrk: ;set here from cold start boot) ; enable rst0 and rst7 di mvi a,12h ;initialize command out revrt xra a out intc ;cleared0 if error mov a,c cpi ndisks ;too large? rnc ;leave HL = 0000 ; ani 10b ;00 00 for drive 0,1 and 10 10 for drive 2,3 mented dma address in hl mov b,h mov c,l ;ready for call to set dma call setdma lda ios ;sector number just read cpi 2ret ; conout: ;console character from c to console out jmp co ; list: ;list device out ; (exactly the same as mds call) ged disk number mov c,a ;send to ccp to log it in ei jmp cpmb ; ; error condition occurred, print message and retry boo track address given by c lxi h,iot mov m,c ret ; setsec: ;set sector number given by c lxi h,ios mov m,c ret sec mvi a,inte ;rst0 and rst7 bits on out intc xra a out icon ;interrupt control ; ; set default buffer address to 80h sta dbank ;to select drive bank mov a,c ;00, 01, 10, 11 ani 1b ;mds has 0,1 at 78, 2,3 at 88 ora a ;result 00? jz setd6 ;read last sector? jc rd1 ; must be sector 26, zero and go to next track lda iot ;get track to register a inr a mov c jmp lo ; listst: ;return list status xra a ret ;always not ready ; punch: ;punch device out ; (exactly the same as tran: ;translate sector bc using table at de mvi b,0 ;double precision sector number in BC xchg ;translate table addresshigh address for iopb jnz iodr1 ;drive bank 1? out ilow ;low address to controller mov a,b out ihigh ;high address jm from the current i/o function ani 00100000b ;mask the disk select bit lxi h,ios ;address the sector select byte ora m ;accepted as ok above) ; 1 - crc error ; 2 - seek error ; 3 - address error (hardware malfunction) ; 4 - data over/under flowret ;may have error set ; ; ; utility subroutines prmsg: ;print message at h,l to 0 mov a,m ora a ;zero? rz ; more t retry ; ; check i/o error bits call inbyte ral jc wready ;unit not ready rar ani 11111110b ;any other errors? (de to HL dad b ;translate(sector) address mov a,m ;translated sector number to A sta ios mov l,a ;return sector number in p wait0 ;to wait for complete ; iodr1: ;drive bank 1 out ilow+10h ;88 for drive bank 10 mov a,b out ihigh+10h ; wait0select proper disk bank mov m,a ;set disk select bit on/off ret ; waitio: mvi c,retry ;max retries before perm error r (hardware malfunction) ; 5 - write protect (treated as not ready) ; 6 - write error (hardware malfunction) ; 7 - not ready o print push h mov c,a call conout pop h inx h jmp prmsg ; setfunc: ; set function for next i/o (command in reg-cleted data ok) jnz werror ; ; read or write is ok, accumulator contains zero ret ; wready: ;not ready, treat as error foL ret ; setdma: ;set dma address given by regs b,c mov l,c mov h,b shld iod ret ; read: ;read next disk record (as: call instat ;wait for completion ani iordy ;ready? jz wait0 ; ; check io completion ok call intype ;must be io compewait: ; start the i/o function and wait for completion call intype ;in rtype call inbyte ;clears the controller ; lda d; (accumulator bits are numbered 7 6 5 4 3 2 1 0) ; ; it may be useful to filter out the various conditions, ; but we will ge) lxi h,iof ;io function address mov a,m ;get it to accumulator for masking ani 11111000b ;remove previous command ora cr now call inbyte ;clear result byte jmp trycount ; werror: ;return hardware malfunction (crc, track, seek, etc.) ; the suming disk/trk/sec/dma set) mvi c,readf ;set to read function call setfunc call waitio ;perform read function ret ;maylete (00) unlinked ; 00 unlinked i/o complete, 01 linked i/o complete (not used) ; 10 disk status changed 11 (not usebank ;set bank flags ora a ;zero if drive 0,1 and nz if 2,3 mvi a,iopb and 0ffh ;low address for iopb mvi b,iopb shr 8 ;t a permanent error message if it is not ; recoverable. in any case, the not ready condition is ; treated as a separate condi ;set to new command mov m,a ;replaced in iopb ; the mds-800 controller requires disk bank bit in sector byte ; mask the bitmds controller has returned a bit in each position ; of the accumulator, corresponding to the conditions: ; 0 - deleted data ( have error set in reg-a ; ; write: ;disk write function mvi c,writf call setfunc ;set to write function call waitio d) cpi 10b ;ready status change? jz wready ; ; must be 00 in the accumulator ora a jnz werror ;some other condition,tion for later improvement trycount: ; register c contains retry count, decrement 'til zero dcr c jnz rewait ;for another BOOT EQU 0000H ;WARM START IOBYTE EQU 0003H ;IO BYTE BDISK EQU 0004H ;BOOT DISK # BDOS EQU 0005H ;BDOS ENTRY MON1 EQU 0005da bdos+1 ;xsub already present? cpi 06h ;low address must be 06h jnz loaderr lhld bdos+1 inx h inx h inx h lxi d,if drive 2,3 iopb: ;io parameter block db 80h ;normal i/o operation iof: db readf ;io function, initial read ion: db 1 ;num93950 ; org 100h db (lxi or (b shl 3)) ;lxi b,module size org $+2 ;skip address field jmp start db ' Extended Submitry ; ; cannot recover from error mvi a,1 ;error code ret ; ; intype, inbyte, instat read drive bank 00 or 10 intype: lH ;BDOS ENTRY MON2 EQU 0005H ;BDOS ENTRY MON3 EQU 0005H ;BDOS ENTRY MAXB EQU 0006H ;MAX MEM BASE FCB EQU 005CH ;DEFAULT FCB xsubcon mvi c,4 present: ldax d cmp m jnz continue inx h inx d dcr c jz loaderr jmp present ; loaderr: ber of sectors to read iot: db offset ;track number ios: db 1 ;sector number iod: dw buff ;io address ; ; ; define ram aret Vers ' db version/16+'0','.',version mod 16+'0' nogo: db 'Xsub Already Present$' badver: db 'Requires CP/M Version 2.0 or da dbank ora a jnz intyp1 ;skip to bank 10 in rtype ret intyp1: in rtype+10h ;78 for 0,1 88 for 2,3 ret ; inbyte: BUFF EQU 0080H ;DEFAULT BUFFER END  ; bdos or xsub not lowest module in memory, return to ccp mvi c,print lxi d,nogo ;already present message call bdos ;to pas for bdos operation endef end later$' ; bdos equ 0005h ;bdos entry point print equ 9 ;bdos print function vers equ 12 ;get version number ccplen equ 0800lda dbank ora a jnz inbyt1 in rbyte ret inbyt1: in rbyte+10h ret ; instat: lda dbank ora a jnz insta1 in dsta; xsub relocator version 2.2 version equ 20h ; xsub relocator program, included with the module ; to perform the mrint the message pop b ;recall length ret ;to the ccp ; continue: mvi c,vers call bdos ;version number? cpi version; PIP INTERFACE TO BDOS (CAN BE USED FOR OTHER TRANSIENTS) PUBLIC BOOT,IOBYTE,BDISK,BDOS,MON1,MON2,MON3 PUBLIC MAXB,FCB,BUFFh ;size of ccp module equ 200h ;module address ; start: ; ccp's stack used throughout push b ;save the module's length lt ret insta1: in dstat+10h ret ; ; ; ; data areas (must be in ram) dbank: db 0 ;disk bank 00 if drive 0,1 ; 10 ove from 200h to the destination address ; ; copyright (c) 1979, 1980 ; digital research ; box 579 ; pacific grove, ca. ; ;2.0 or greater jnc versok ; ; wrong version mvi c,print lxi d,badver call bdos pop b ret ;to ccp ; versok: ion pop d ;clear stacked address ; h has the high order 8-bits of relocated module address mvi l,0 pchl ;go to relocatedyte jnz rel1 ; fetch bit map from stacked address xthl mov a,m ;next 8 bits of map inx h xthl ;base address goes bacoot saved and restored at end ;of submit file ; wstart: lxi sp,stack mvi c,pbuff ;print message lxi d,actmsg call solute location stax d ;place it into the reloc area inx d inx h jmp move ; reloc: ;storage moved, ready for relocatio 19 ;delete file dreadf equ 20 ;disk read dmaf equ 26 ;set dma function ; ; org 0000h+bias ; initialize jmps to include xlxi h,bdos+2;address field of jump to bdos (top memory) mov a,m ;a has high order address of memory top dcr a ;page directly; xsub 'Extended Submit Facility' version 2.2 ; ; ; ; xsub loads below ccp, and feeds command lines to ; programs whk to stack mov l,a ;l holds the map as we process 8 locations rel1: mov a,l ral ;cy set to 1 if relocation necessary movrbdos lxi h,dbuff ;restore default buffer shld udma call rsetdma lxi h,trapjmp shld bdosl ;fixup low jump address lhn ; hl addresses beginning of the bit map for relocation pop d ;recall base of relocation area pop b ;recall module length sub module jmp start ds 3 trapjmp: jmp trap db 'xsub' start: lhld wboot+1 shld savboot lxi h,wstart shld wboot below bdos sui (ccplen shr 8) ;-ccp pages pop b ;recall length of module push b ;and save it again sub b ;a has high orich read buffered input ; bias equ 0000h ;bias for relocation base equ 0ffffh ;no intercepts below here wboot equ 0000h bdo l,a ;back to l for next time around jnc rel2 ;skip relocation if cy=0 ; ; current address requires relocation ldax d adld ccpret ;back to ccp pchl actmsg: db cr,lf,'(xsub active)$' ; trap: ;arrive here at each bdos call pop h ;return addres push h ;save bit map base in stack mov h,d ;relocation bias is in d ; rel0: mov a,b ;bc=0? ora c jz endrel ; ; not e+1 lhld bdosl shld rbdos+1 ;real bdos entry lxi h,trapjmp ;address to fill shld bdosl ;jmp @0005 leads to trap pop h ;der address of reloc area mov d,a mvi e,0 ;d,e addresses base of reloc area push d ;save for relocation below ; lxi h,ms equ 0005h bdosl equ bdos+1 dbuff equ 0080h ; cr equ 0dh ;carriage return lf equ 0ah ;line feed modnum equ 14 ;module numd h ;apply bias in h stax d rel2: inx d ;to next address jmp rel0 ;for another byte to relocate ; endrel: ;end of relocats push h ;back to stack mov a,h ;high address cpi base shr 8 jnc rbdos ;skip calls on bdos above here mov a,c ;functiond of the relocation, may be into next byte of bit map dcx b ;count length down mov a,e ani 111b ;0 causes fetch of next bccp return address shld ccpret pchl ;back to ccp ; rbdos: jmp 0000h ;filled in at initialization savboot: ds 2 ;warm bodule;ready for the move move: mov a,b ;bc=0? ora c jz reloc dcx b ;count module size down to zero mov a,m ;get next abber position pbuff equ 9 ;print buffer rbuff equ 10 ;read buffer openf equ 15 ;open file closef equ 16 ;close file delf equn number cpi rbuff jz rnbuff ;read next buffer cpi dmaf ;set dma address? jnz rbdos ;skip if not xchg ;dma to hl sh restor: lhld savboot shld wboot+1 jmp rbdos ; subfcb: db 1 ;a: db '$$$ ' db 'SUB' db 0,0,0 subrc: ds 1 jc movlin mov a,m ;max length stax d ;truncate length movlin: mov c,a ;length to c inr c ;+1 inx h ;to length of lTERALLY '0020H'; /* REQUIRED FOR OPERATION */ DECLARE IOBYTE BYTE EXTERNAL, /* IOBYTE AT 0003H */ MAXB ADDRE ;no sub file ; push d lda subrc ;length of file ora a ;zero? jz rbdos ;skip if so dcr a ;length - 1 sta subcr ;neld udma ;save it xchg jmp rbdos ; setdma: mvi c,dmaf lxi d,combuf call rbdos ret ; rsetdma: mvi c,dmaf lhld ds 16 ;map subcr: ds 1 ; combuf: ds 131 udma: dw dbuff ccpret: ds 2 ;ccp return address ds 32 ;16 level stack stack: ine rdloop: ldax d ;next char mov m,a inx h inx d dcr c jnz rdloop ;loop til copied mvi c,closef lxi d,subfcb SS EXTERNAL, /* ADDR FIELD OF JMP BDOS */ FCB (33) BYTE EXTERNAL, /* DEFAULT FILE CONTROL BLOCK */ BUFF(128)BYxt to read mvi c,dreadf lxi d,subfcb call fbdos ;read record ; now print the buffer with cr,lf lxi h,combuf mov e,m ;udma xchg call rbdos ret ; fbdos: push b push d call setdma pop d pop b call rbdos push psw call rsetdmaend  lxi h,modnum dad d ;hl=fcb(modnum) mvi m,0 ;=0 so acts as if written lda subcr ;length of file dcr a ;incremented by reTE EXTERNAL; /* DEFAULT BUFFER */ DECLARE ENDFILE LITERALLY '1AH', /* END OF FILE MARK */ JMP LITERALLY '0length mvi d,0 ;high order 00 dad d ;to last character position inx h mvi m,cr inx h mvi m,lf inx h mvi m,'$' PIPMOD: DO; /* P E R I P H E R A L I N T E R C H A N G E P R O G R A M COPYRIGHT (C) 1976, 1977, 1978, 1979, 198 pop psw ret ; cksub: ;check for sub file present mvi c,openf lxi d,subfcb call fbdos ;submit file present? inr a ad op sta subrc ;decrease file length ora a ;at zero? jnz fileop mvi c,delf ;delete if at end fileop: call fbdos ret C3H', /* 8080 JUMP INSTRUCTION */ RET LITERALLY '0C9H'; /* 8080 RETURN */ /* THE FIRST PORTION OF THE PIP PROGmvi c,pbuff lxi d,combuf+1 call rbdos ;to print it pop h ;.max length lxi d,combuf ldax d ;how long? cmp m ;cy if ok0 DIGITAL RESEARCH BOX 579 PACIFIC GROVE, CA 93950 */ DECLARE CPMVERSION LI;00 if not present ret ; rnbuff: push d ;command address call cksub ;sub file present? pop d mvi c,rbuff jz restorRAM 'FAKES' THE PAGE ONE (100H - 1FFH) SECTION OF PIP WHICH CONTAINS A JUMP TO PIPENTRY, AND SPACE FOR CUSTOM I/O DRIVERS (WHIREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY); DECLARE COPYRIGHT(*) BYTE 03H AND 106H BY JMP'S ; TO THE PROPER LOCATIONS WITHIN THE RESERVED AREA. ; ALSO, RETURN DATA FROM INP: ENTRY POINT A /* CONSOLE */ NULP LIT '19', /* NUL: BEFORE INCREMENT */ EOFP LIT '20', /* EOF: NS THE FOLLOWING 100H: JMP PIPENTRY ;TO START THE PIP PROGRAM 103H: RET ;INP: DEFAULTS TO EMPTY INPUT; /* LITERAL DECLARATIONS */ DECLARE LIT LITERALLY 'LITERALLY', LPP LIT '60', /* LINES PER PAGE */ TACH CAN BE 'PATCHED' USING DDT) IN THE REMAINING PAGE ONE AREA. THE PIP PROGRAM ACTUALLY STARTS AT 200H */ DECLARE JUMP BYTEDATA ( ' COPYRIGHT (C) 1979, DIGITAL RESEARCH, PIP VERS 1.5'); DECLARE INPLOC ADDRESS DATA (.INPSUB); /* ADDRESST 109H. ; THESE DRIVERS ARE MOST EASILY INSERTED WITH THE DDT PROGRAM ; UNDER CP/M */ DECLARE /* 16 BYTE MESSABEFORE INCREMENT */ HSRDR LIT 'RDR', /* READER DEVICES */ PRNT LIT '10', /* PRINTER */ (DATA 1AH AT 109H) 104H: NOP 105H: NOP 106H: RET ;OUT: DEFAULTS TO EMPTY OUTPUT 107H: NOP B LIT '09H', /* HORIZONTAL TAB */ FF LIT '0CH', /* FORM FEED */ LA LIT '05FH', /* LEFT ARROW */ LB LIT DATA(JMP); /* JMP INSTRUCTION TO */ /* JMP .PIPENTRY-3 WHERE THE LXI SP,STACK ACTUALLY OCCURS */ DECLARE JADR ADDRESS DATA(.P OF INP: DEVICE */ DECLARE OUTLOC ADDRESS DATA (.OUTSUB); /* ADDRESS OF OUT: DEVICE */ OUT: PROCEDURE(B); DECLARE GE */ FREEMEMORY LITERALLY '''(INP:/OUT:SPACE)''', /* 256 BYTE AREA FOR INP: OUT: PATCHING */ RESERVED(*) BYTE DA FSIZE LIT '33', FRSIZE LIT '36', /* SIZE OF RANDOM FCB */ NSIZE LIT '8', FNSIZE LIT '11', MDISK LIT ' 108H: NOP 109H: 1AH=ENDFILE ;DATA FROM INP: FUNCTION IS STORED HERE ON ;RETURN FROM T '05BH', /* LEFT BRACKET */ RB LIT '05DH', /* RIGHT BRACKET */ XOFF LIT '13H', /* TRANSMIT BUFFER FUNCTION */ IPENTRY-3); /* START OF PIP */ DECLARE INPSUB(3) BYTE DATA(RET,0,0); /* INP: RET NOP NOP */ DECLARE OUTSUB(3) BYTE DATA(REB BYTE; /* SEND B TO OUT: DEVICE */ CALL OUTLOC; END OUT; INP: PROCEDURE BYTE; CALL INPLOC; RETURN ITA(0,0,0,0,0,0, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, FREEMEMORY, F1', FNAM LIT '8', FEXT LIT '9', FEXTL LIT '3', ROFILE LITERALLY '9', /* READ ONLY FILE FIELD */ SYSFIHE INP: ENTRY POINT 10AH: - 1FFH ;SPACE RESERVED FOR SPECIAL PURPOSE ; DRIVERS - IF INCLUDED, THEN REPLACE 1 RDR LIT '5', LST LIT '10', PUNP LIT '15', /* POSITION OF 'PUN' + 1 */ CONP LIT '19', T,0,0); /* OUT: RET NOP NOP */ DECLARE INPDATA BYTE DATA(ENDFILE); /* RETURNED DATA */ /* NOTE: PAGE 1 AT 100H CONTAINPDATA; END INP; TIMEOUT: PROCEDURE; /* WAIT FOR 50 MSEC */ CALL TIME(250); CALL TIME(250); END TIMEOUTLE LITERALLY '10', /* SYSTEM FILE FIELD */ FREEL LIT '12', /* REEL NUMBER FIELD OF FCB */ HBUFS LIT '80', /* DEST IS 'HEX' FILE IF TRUE */ SOURCE (FSIZE) BYTE, /* SOURCE FCB */ SFUB BYTE AT(.SOURCE(13)), /* U DBLEN ADDRESS, /* DEST BUFFER LENGTH */ SBASE ADDRESS, /* SOURCE BUFFER BASE */ /* THESET WHEN READY FOR NEXT LINE NUM */ CONCNT BYTE, /* COUNTER FOR CONSOLE READY CHECK */ CHAR BYTE, NG */ MATCHLEN BYTE, /* USED IN MATCHING STRINGS */ QUITLEN BYTE, /* USED TO TERMINATE */ HARDEOF ADDRESS, /* SET TO NSOURCE ON REAL EOF */ NDEST ADDRESS; /* NEXT DESTINATION CH /* "HEX" BUFFER SIZE */ ERR LIT '0', SPECL LIT '1', FILE LIT '2', PERIPH LIT '3', DISKNAME LIT 'NFILLED BYTES FIELD */ DEST (FRSIZE) BYTE, /* DESTINATION FCB */ DESTR ADDRESS AT(.DEST(33)), /* RANDOM REC VECTORS DBUFF AND SBUFF ARE DECLARED WITH DIMENSION 1024, BUT ACTUALLY VARY WITH THE FREE MEMORY SIZE */ DBUFF(1024) /* LAST CHARACTER SCANNED */ TYPE BYTE, /* TYPE OF CHARACTER SCANNED */ FLEN BYTE;QUIT COMMAND */ NBUF BYTE, /* NUM BUFFERS-1 IN SBUFF AND DBUFF */ CDISK BYTE, /* ARACTER */ DECLARE /* SUBMIT FILE CONTROL BLOCK FOR ERROR DELETE */ SUBFCB (*) BYTE DATA (0,'$$$ SUB',0,0,0); 4'; DECLARE COLUMN BYTE, /* COLUMN COUNT FOR PRINTER TABS */ LINENO BYTE, /* LINE WITHIN PAGE */ AMBIGORD POSITION */ DESTO BYTE AT(.DEST(35)), /* RANDOM OVERFLOW BYTE */ DFUB BYTE AT (.DEST(13)), /* UNFILLED BYTBYTE AT (.MEMORY), /* DESTINATION BUFFER */ SBUFF BASED SBASE (1024) BYTE, /* SOURCE BUFFER */ SDISK BYTE, /* FILE NAME LENGTH */ MON1: PROCEDURE(F,A) EXTERNAL; DECLARE F BYTE, A ADDRESS; END MON1;CURRENT DISK */ BUFFER LITERALLY 'BUFF', /* DEFAULT BUFFER */ SEARFCB LITERALLY 'FCB', /* SEARCH FCB IN MULT DECLARE PDEST BYTE, /* DESTINATION DEVICE */ PSOURCE BYTE; /* CURRENT SOURCE DEV BYTE, /* SET FOR AMBIGUOUS FILE REFS */ PARSET BYTE, /* TRUE IF PARAMETERS PRESENT */ ES FIELD */ DDISK BYTE, /* DESTINATION DISK */ HBUFF(HBUFS) BYTE, /* HEX FILE BUFFER */ /* SOURCE DISK */ (SCOM, DHEX) BYTE, /* SOURCE IS 'COM' FILE IF TRUE */ MON2: PROCEDURE(F,A) BYTE EXTERNAL; DECLARE F BYTE, A ADDRESS; END MON2; MON3: PROCEDURE(F,A) ADDRESS EXTEI COPY */ MEMSIZE LITERALLY 'MAXB', /* MEMORY SIZE */ SBLEN ADDRESS, /* SOURCE BUFFER LENGTH */ ICE */ DECLARE MULTCOM BYTE, /* FALSE IF PROCESSING ONE LINE */ PUTNUM BYTE, /* FEEDBASE BYTE, /* USED TO FEED SEARCH CHARACTERS */ FEEDLEN BYTE, /* LENGTH OF FEED STRI HSOURCE BYTE, /* NEXT HEX SOURCE CHARACTER */ NSOURCE ADDRESS, /* NEXT SOURCE CHARACTER RNAL; DECLARE F BYTE, A ADDRESS; END MON3; BOOT: PROCEDURE EXTERNAL; /* SYSTEM REBOOT */ END BOOT; ADDRESS; RETURN MON2(20,FCB); END DISKREAD; DISKWRITE: PROCEDURE(FCB) BYTE; DECLARE FCB ADDRESS; RETURN M); END SELECT; OPEN: PROCEDURE(FCB); DECLARE FCB ADDRESS; DCNT = MON2(15,FCB); END OPEN; CLOSE: PROCED RANDOM RECORD POSITION */ CALL MON1(36,FCB); END SET$RANDOM; DECLARE CBUFF(130) BYTE, /* COMMAND BUFFER */ CALL PRINTCHAR(CR); CALL PRINTCHAR(LF); END CRLF; PRINT: PROCEDURE(A); DECLARE A ADDRESS; /* PRINT THOCEDURE(USER); DECLARE USER BYTE; CALL MON1(32,USER); END SETUSER; SETCUSER: PROCEDURE; CALL SETUSER(CUSE READRDR: PROCEDURE BYTE; /* READ CURRENT READER DEVICE */ RETURN MON2(3,0); END READRDR; READCHAR: PROCEDUREON2(21,FCB); END DISKWRITE; MAKE: PROCEDURE(FCB); DECLARE FCB ADDRESS; DCNT = MON2(22,FCB); END MAKE; URE(FCB); DECLARE FCB ADDRESS; DCNT = MON2(16,FCB); END CLOSE; SEARCH: PROCEDURE(FCB); DECLARE FCB ADDRESMAXLEN BYTE AT (.CBUFF(0)), /* MAX BUFFER LENGTH */ COMLEN BYTE AT (.CBUFF(1)), /* CURRENT LENGTH */ COMBUFF (128) BE STRING STARTING AT ADDRESS A UNTIL THE NEXT DOLLAR SIGN IS ENCOUNTERED */ CALL CRLF; CALL MON1(9,A); END PR); END SETCUSER; SETSUSER: PROCEDURE; CALL SETUSER(SUSER); END SETSUSER; READ$RANDOM: PROCEDURE(FCB) BYTE; BYTE; /* READ CONSOLE CHARACTER */ RETURN MON2(1,0); END READCHAR; DECLARE TRUE LITERALLY '1', FALSRENAME: PROCEDURE(FCB); DECLARE FCB ADDRESS; CALL MON1(23,FCB); END RENAME; DECLARE CUSER BYTE, /* CURRENS; DCNT = MON2(17,FCB); END SEARCH; SEARCHN: PROCEDURE; DCNT = MON2(18,0); END SEARCHN; DELETE: PROCEDYTE AT (.CBUFF(2)); /* COMMAND BUFFER CONTENTS */ DECLARE (TCBP,CBP) BYTE; /* TEMP CBP, COMMAND BUFFER POINTER */ READCOM:RINT; DECLARE DCNT BYTE; VERSION: PROCEDURE ADDRESS; RETURN MON3(12,0); /* VERSION NUMBER */ END VERSION; INI DECLARE FCB ADDRESS; RETURN MON2(33,FCB); END READ$RANDOM; WRITE$RANDOM: PROCEDURE(FCB) BYTE; DECLARE FCE LITERALLY '0', FOREVER LITERALLY 'WHILE TRUE', CR LITERALLY '13', LF LITERALLY '10', WHAT LITERALLY '63'; T USER NUMBER */ SUSER BYTE; /* SOURCE USER NUMBER ('G' PARAMETER) */ SETIND: PROCEDURE(FCB); DECLARE FCB ADDRESS; URE(FCB); DECLARE FCB ADDRESS; CALL MON1(19,FCB); END DELETE; DISKREAD: PROCEDURE(FCB) BYTE; DECLARE FCB PROCEDURE; /* READ INTO COMMAND BUFFER */ MAXLEN = 128; CALL MON1(10,.MAXLEN); END READCOM; DECLARE MCBPTIALIZE: PROCEDURE; CALL MON1(13,0); END INITIALIZE; SELECT: PROCEDURE(D); DECLARE D BYTE; CALL MON1(14,DB ADDRESS; RETURN MON2(34,FCB); END WRITE$RANDOM; SET$RANDOM: PROCEDURE(FCB); DECLARE FCB ADDRESS; /* SET PRINTCHAR: PROCEDURE(CHAR); DECLARE CHAR BYTE; CALL MON1(2,CHAR AND 7FH); END PRINTCHAR; CRLF: PROCEDURE; CALL MON1(30,FCB); END SETIND; GETUSER: PROCEDURE BYTE; RETURN MON2(32,0FFH); END GETUSER; SETUSER: PR BYTE; CONBRK: PROCEDURE BYTE; /* CHECK CONSOLE CHARACTER READY */ RETURN MON2(11,0); END CONBRK; DECLARE //ICOM READER INPUT */ INTIN: PROCEDURE BYTE; /* READ THE INTEL / ICOM READER */ DECLARE PTRI LITERALLY '3', /* DAT(17)), /* READ SYSTEM FILES */ STARTS BYTE AT(.CONT(18)), /* START COPY */ TABS BYTE AT(.CONT(19)), /* TA.SUBFCB); CALL CRLF; GO TO RETRY; END ERROR; MOVE: PROCEDURE(S,D,N); DECLARE (S,D) ADDRESS, N BYTE; / GETU BYTE AT(.CONT(6)), /* GET FILE, USER # */ HEXT BYTE AT(.CONT(7)), /* HEX FILE TRANSFER */ IGINTER */ ERROR: PROCEDURE(A); DECLARE A ADDRESS, I BYTE; CALL SETCUSER; CALL PRINT(A); CALL PRINTCHAR(':');* CONTROL TOGGLE VECTOR */ CONT(26) BYTE, /* ONE FOR EACH ALPHABETIC */ /* 00 01 02 03 04 05 06 07 08 09 10 11 12 13A */ PTRS LITERALLY '1', /* STATUS */ PTRC LITERALLY '1', /* COMMAND */ PTRG LITERALLY B SET */ UPPER BYTE AT(.CONT(20)), /* UPPER CASE TRANSLATE */ VERIF BYTE AT(.CONT(21)), /* VERIFY EQUAL FILE DECLARE A BASED S BYTE, B BASED D BYTE; DO WHILE (N:=N-1) <> 255; B = A; S = S+1; D = D+1; END; NOR BYTE AT(.CONT(8)), /* IGNORE :00 RECORD ON FILE */ LOWER BYTE AT(.CONT(11)), /* TRANSLATE TO LOWER CASE */ CALL PRINTCHAR(' '); DO I = TCBP TO CBP; IF I < COMLEN THEN CALL PRINTCHAR(COMBUFF(I)); END; /* A B C D E F G H I J K L M N 14 15 16 17 18 19 20 21 22 23 24 25 O P Q R S T U V '0CH', /* GO */ PTRN LITERALLY '08H'; /* STOP */ /* STROBE THE READER */ OUTPUT(PTRC) = PTRG; OUTPS ONLY */ WRROF BYTE AT(.CONT(22)), /* WRITE TO R/O FILE */ ZEROP BYTE AT(.CONT(25)); /* ZERO PARITY ON INPU END MOVE; FILLSOURCE: PROCEDURE; /* FILL THE SOURCE BUFFERS */ DECLARE (I,J) BYTE; NSOURCE = 0; CAL NUMB BYTE AT(.CONT(13)), /* NUMBER OUTPUT LINES */ OBJ BYTE AT(.CONT(14)), /* OBJECT FILE TRANSFER */ ZERO THE COMLEN IN CASE THIS IS A SINGLE COMMAND */ COMLEN = 0; /* DELETE ANY $$$.SUB FILES IN CASE BATCH PROCESSING W X Y Z */ BLOCK BYTE AT(.CONT(1)), /* BLOCK MODE TRANSFER */ DELET BYTE AT(.CONT(3)), /* DELETE CHARUT(PTRC) = PTRN; DO WHILE NOT ROL(INPUT(PTRS),3); /* NOT READY */ END; /* DATA READY */ RETURN INPUTT */ SETDMA: PROCEDURE(A); DECLARE A ADDRESS; CALL MON1(26,A); END SETDMA; /* INTELLEC 8 INTELL SELECT(SDISK); CALL SETSUSER; /* SOURCE USER NUMBER SET */ DO I = 0 TO NBUF; /* SET DMA ADDRESS TO NEXT PAGCNT BYTE AT(.CONT(15)), /* PAGE LENGTH */ QUITS BYTE AT(.CONT(16)), /* QUIT COPY */ RSYS BYTE AT(.CONT*/ /* DELETE SUB FILE ONLY IF PRESENT (MAY BE R/O DISK) */ CALL SEARCH(.SUBFCB); IF DCNT <> 255 THEN CALL DELETE(ACTERS */ ECHO BYTE AT(.CONT(4)), /* ECHO CONSOLE CHARACTERS */ FORMF BYTE AT(.CONT(5)), /* FORM FILTER *(PTRI) AND 7FH; END INTIN; DECLARE ZEROSUP BYTE, /* ZERO SUPPRESSION */ (C3,C2,C1) BYTE; /* LINE COUNT ON PR BUFFER POSIITION */ CALL SETDMA(.SBUFF(NSOURCE)); IF (J := DISKREAD(.SOURCE)) <> 0 THEN DO; IF J DATAOK THEN CALL ERROR(.('VERIFY ERROR$')); END; DATAOK = DISKWRITE(.DEST); /* ERIF THEN /* VERIFY DATA WRITTEN OK */ DO; NDEST = 0; CALL SETDMA(.BUFF); /* FOR COMPARE */ NOTDEST: CALL ERROR(.('NOT A CHARACTER SINK$')); /* CASE 7 IS OUT */ CALL OUT(B); */ DECLARE (I, J, N) BYTE; DECLARE DMA ADDRESS; DECLARE DATAOK BYTE; IF (N := LOW(SHR(NDEST,7)) - 1) = 255 TION FILE */ DO; IF NDEST >= DBLEN THEN CALL WRITEDEST; DBUFF(NDEST) = B; ND <> 1 THEN CALL ERROR(.('DISK READ ERROR$')); /* END - OF - FILE */ HARDEOF = NSOURCENOW READY TO CONTINUE THE WRITE OPERATION */ END; NDEST = 0; END WRITEDEST; PUTDCHAR: PROCEDURE(B); DO I = 0 TO N; DATAOK = READRANDOM(.DEST) = 0; DESTR = DESTR + 1; /* NEXT RANDOM READ */ /* CASE 8 IS LPT */ DO; IOBYTE = 1000$0000B; GO TO LSTL; END; /* CASE 9 IS UL1 */ THEN RETURN ; NDEST = 0; CALL SELECT(DDISK); CALL SETRANDOM(.DEST); /* SET BASE RECORD FOR VERIFY */ DO EST = NDEST+1; END; /* CASE 1 IS ARD (ADDMASTER) */ GO TO NOTDEST; /* CASE 2 IS IRD (; /* SET HARD END-OF-FILE */ SBUFF(NSOURCE) = ENDFILE; I = NBUF; END; ELSE NSOURCE = NSOURCE DECLARE (B,IOB) BYTE; /* WRITE BYTE B TO THE DESTINATION DEVICE GIVEN BY PDEST */ IF B >= ' ' THEN DO; COLUM J = 0; /* PERFORM COMPARISON */ DO WHILE DATAOK AND J < 80H; DATAOK = BUF DO; IOBYTE = 1100$0000B; GO TO LSTL; END; /* CASE 10 IS PRN (TABS EXPANDED, LINES LISTI = 0 TO N; /* SET DMA ADDRESS TO NEXT BUFFER */ DMA = .DBUFF(NDEST); CALL SETDMA(DMA); IF DINTEL/ICOM) */ GO TO NOTDEST; /* CASE 3 IS PTR */ GO TO NOTDEST; /* CASE 4 IS UR1 */+ 128; END; NSOURCE = 0; CALL SETCUSER; /* BACK TO CURRENT USER NUMBER */ END FILLSOURCE; WRITEDEN = COLUMN + 1; IF DELET > 0 THEN /* MAY BE PAST RIGHT SIDE */ DO; IF COLUMN > DELET THEN RETURN; FER(J) = DBUFF(NDEST+J); J = J + 1; END; NDEST = NDEST + 128; IF NOTED, CHANGED TO LST) */ DO; IOBYTE = 1000$0000B; GO TO LSTL; END; /* CASE 11 IS LST */ISKWRITE(.DEST) <> 0 THEN CALL ERROR(.('DISK WRITE ERROR$')); NDEST = NDEST + 128; END; IF V GO TO NOTDEST; /* CASE 5 IS UR2 */ GO TO NOTDEST; /* CASE 6 IS RDR */ ST: PROCEDURE; /* WRITE OUTPUT BUFFERS UP TO BUT NOT INCLUDING POSITION NDEST - THE LOW ORDER 7 BITS OF NDEST ARE ZERO END; END; IOB = IOBYTE; /* IN CASE IT IS ALTERED */ DO CASE PDEST; /* CASE 0 IS THE DESTINA LSTL: CALL MON1(5,B); /* CASE 12 IS PTP */ DO; IOBYTE = 0001$0000B; GO TO PINTDIG; NEWLINE: PROCEDURE; DECLARE ONE BYTE; ONE = 1; ZEROSUP = NUMB = 1; C1 = DEC(C1+ONE); C2 = DEC(C2 I = I - TABS; END; I = TABS - I; DO WHILE I > 0; I = I - 1; IF (I:=PAGCNT) <> 0 THEN /* PAGE EJECT */ DO; IF I=1 THEN I=LPP; IF (LINENO := L IS UC1 */ DO; IOBYTE = 11B; GO TO CONL; END; /* CASE 19 IS CON */ CONL:WRITTEN */ CALL WRITEDEST; /* CLEARS BUFFERS */ CALL MOVE(.DBUFF(NA),.DBUFF,I); /* DATA MOVED TO BEGINNIUNL; END; /* CASE 13 IS UP1 */ DO; IOBYTE = 0010$0000B; GO TO PUNL; END; PLUS 0); C3 = DEC(C3 PLUS 0); CALL PRINTDIG(C3); CALL PRINTDIG(C2); CALL PRINTDIG(C1); IF NUMB = 1 THEN /* USUALLY PRI CALL PUTDCHAR(' '); END; END; IF B = CR THEN COLUMN = 0; END PUTDESTC; PRINT1: PROCEDUREINENO + 1) >= I THEN DO; LINENO = 0; /* NEW PAGE */ CALL PUTDESTC(FF); CALL MON1(2,B); END; IOBYTE = IOB; END PUTDCHAR; PUTDESTC: PROCEDURE(B); DECLARNG OF BUFFER */ NDEST = I; END CLEARBUFF; PUTDEST: PROCEDURE(B); DECLARE (I,B) BYTE; /* WRITE DESTINATION /* CASE 14 IS UP2 */ DO; IOBYTE = 0011$0000B; GO TO PUNL; END; /* CASE 15 IS PUN */ NTER OUTPUT */ DO; CALL PUTDESTC(':'); CALL PUTDESTC(' '); END; ELSE CALL PUTDESTC(TAB); END NEW(B); DECLARE B BYTE; IF (ZEROSUP := ZEROSUP AND B = 0) THEN CALL PUTDESTC(' '); ELSE CALL PUTDESTC('0'+B); END; END; IF NUMB > 0 THEN CALL NEWLINE; PUTNUM = FALSE; E (B,I) BYTE; /* WRITE DESTINATION CHARACTER, TAB EXPANSION */ IF B <> TAB THEN CALL PUTDCHAR(B); ELSE IF TABS = CHARACTER, CHECK TABS AND LINES */ IF FORMF THEN /* SKIP FORM FEEDS */ DO; IF B = FF THEN RETURN; END; PUNL: CALL MON1(4,B); /* CASE 16 IS TTY */ DO; IOBYTE = 0; GO TO CONL; LINE; CLEARBUFF: PROCEDURE; /* CLEAR OUTPUT BUFFER IN BLOCK MODE TRANSMISION */ DECLARE NA ADDRESS; DECLARE I END PRINT1; PRINTDIG: PROCEDURE(D); DECLARE D BYTE; CALL PRINT1(SHR(D,4)); CALL PRINT1(D AND 1111B); END PR END; END; IF BLOCK THEN /* BLOCK MODE TRANSFER */ DO; IF B = XOFF AND PDEST = 0 THEN 0 THEN CALL PUTDCHAR(B); ELSE /* B IS TAB CHAR, TABS > 0 */ DO; I = COLUMN; DO WHILE I >= TABS; IF PUTNUM THEN /* END OF LINE OR START OF FILE */ DO; IF B <> FF THEN /* NOT FORM FEED */ DO; END; /* CASE 17 IS CRT */ DO; IOBYTE = 1; GO TO CONL; END; /* CASE 18BYTE; I = LOW(NDEST) AND 7FH; /* REMAINING PARTIAL BUFFER LENGTH */ NA = NDEST AND 0FF80H; /* START OF SEGMENT NOT DO; CALL CLEARBUFF; /* BUFFERS WRITTEN */ RETURN; /* DON'T PASS THE X-OFF */ END; EB; GO TO RDRL; END; /* CASE 5 IS UR2 */ DO; IOBYTE = 0000$1100B; GO TO RDRL; T IS ALTERED */ DO CASE PSOURCE; /* CASE 0 IS SOURCE FILE */ DO; IF NSOURCE >= SBLEN THEN CALL FISE 19 IS CON */ CONL: DO; CONCHK = FALSE; /* DON'T CHECK CONSOLE STATUS */ B = MO RETURN B; END LTRAN; GETSOURCEC: PROCEDURE BYTE; /* READ NEXT SOURCE CHARACTER */ DECLARE (IOB,B,CONCHK) BYCE; /* CASE 14 IS UP2 */ GO TO NOTSOURCE; /* CASE 15 IS PUN */ NOTSOURCE: ND; IF B = FF THEN LINENO = 0; CALL PUTDESTC(B); IF B = LF THEN PUTNUM = TRUE; END PUTDEST; UTRAN: PROC END; /* CASE 6 IS RDR */ RDRL: B = MON2(3,0) AND 7FH; /* CASE 7 IS OUT */ LLSOURCE; B = SBUFF(NSOURCE); NSOURCE = NSOURCE + 1; END; /* CASE 1 IS INP */ N2(1,0); END; END; /* OF CASES */ IOBYTE = IOB; /* RESTORE IOBYTE */ IF ECHO THEN /* COPY TOTE; IF PSOURCE - 1 <= RDR THEN /* 1 ... RDR+1 */ DO; IF (BLOCK OR HEXT) AND CONBRK THEN DO; DO; CALL ERROR(.('NOT A CHARACTER SOURCE$')); END; /* CASE 16 IS TTY */ DO; IOEDURE(B) BYTE; DECLARE B BYTE; /* TRANSLATE ALPHA TO UPPER CASE */ IF B >= 110$0001B AND B <= 111$1010B THEN /* L GO TO NOTSOURCE; /* CASE 8 IS LPT */ GO TO NOTSOURCE; /* CASE 9 IS UL1 */ B = INP; /* CASE 2 IS IRD (INTEL/ICOM) */ B = INTIN; /* CASE 3 IS PTR */ CONSOLE DEVICE */ DO; IOB = PDEST; PDEST = CONP; CALL PUTDEST(B); PDEST = IOB; END; IF CONCHK T IF READCHAR = ENDFILE THEN RETURN ENDFILE; CALL PRINT(.('READER STOPPING',CR,LF,'$')); RETURN XOBYTE = 0; GO TO CONL; END; /* CASE 17 IS CRT */ DO; IOBYTE = 01B; GO TO CONL; OWER CASE */ B = B AND 101$1111B; /* TO UPPER CASE */ RETURN B; END UTRAN; LTRAN: PROCEDURE(B) BYTE; GO TO NOTSOURCE; /* CASE 10 IS PRN */ GO TO NOTSOURCE; /* CASE 11 IS LST */ GO TO DO; IOBYTE = 0000$0100B; GO TO RDRL; END; /* CASE 4 IS UR1 */ DO; IOBYTE = 0000$1000HEN /* TEST FOR CONSOLE CHAR READY */ DO; IF SCOM THEN /* SOURCE IS A COM FILE */ CONCHK = (CONCNFF; END; END; CONCHK = TRUE; /* CONSOLE STATUS CHECK BELOW */ IOB = IOBYTE; /* SAVE IT IN CASE I END; /* CASE 18 IS UC1 */ DO; IOBYTE = 11B; GO TO CONL; END; /* CADECLARE B BYTE; /* TRANSLATE TO LOWER CASE ALPHA */ IF B >= 'A' AND B <= 'Z' THEN B = B OR 10$0000B; /* TO LOWER */ NOTSOURCE; /* CASE 12 IS PTP */ GO TO NOTSOURCE; /* CASE 13 IS UP1 */ GO TO NOTSOURT := CONCNT + 1) = 0; ELSE /* ASCII */ CONCHK = B = LF; IF CONCHK THEN DO; IF CONBRK THEN ND; ELSE IF QUITS > 0 THEN /* PASS CHARACTERS TIL MATCH */ DO; IF MATCH(QUITS) THEN DO; QUITS = 0; QU FOR START */ IF FEEDLEN > 0 THEN /* GET SEARCH CHARACTERS */ DO; FEEDLEN = FEEDLEN - 1; CHAR = COMBUFF(FN TRUE; END; RETURN FALSE; END DELIMITER; PUTCHAR: PROCEDURE; FCB(FLEN:=FLEN+1) = IF (C:=COMBUFF(B:=(B+MATCHLEN))) = ENDFILE THEN /* END MATCH */ DO; COMBUFF(B) = CHAR; /* SAVE CURRENT CHCBA); DECLARE FCBA ADDRESS, /* ADDRESS OF FCB TO FILL */ FCB BASED FCBA (FSIZE) BYTE; /* FCB TEMPLATE */ DO; IF READCHAR = ENDFILE THEN RETURN ENDFILE; CALL ERROR(.('ABORTED$')); ITLEN = 2; /* SUBSEQUENTLY RETURN CR, LF, ENDFILE */ RETURN CR; END; RETURN CHAREEDBASE); FEEDBASE = FEEDBASE + 1; RETURN CHAR; END; IF (CHAR := GETSOURCEC) = ENDFILE THEN RETU CHAR; IF CHAR = WHAT THEN AMBIG = TRUE; /* CONTAINS AMBIGUOUS REF */ END PUTCHAR; FILLQ: PROCEDURE(LENARACTER */ RETURN TRUE; END; IF C = CHAR THEN MATCHLEN = MATCHLEN + 1; ELSE MATC DECLARE (I,J,K) BYTE; /* TEMP COUNTERS */ /* SCAN LOOKS FOR THE NEXT DELIMITER, DEVICE NAME, OR FILE NAME. THE VALUE END; END; END; IF ZEROP THEN B = B AND 7FH; IF UPPER THEN RETURN UTRAN(B); IF LO; END; ELSE RETURN CHAR; END; /* OF DO FOREVER */ END GETSOURCE; DECLARE DISK BYTE; /* SELRN ENDFILE; IF STARTS > 0 THEN /* LOOKING FOR START STRING */ DO; IF MATCH(STARTS) THEN DO; FEEDBASE ); /* FILL CURRENT NAME OR TYPE WITH QUESTION MARKS */ DECLARE LEN BYTE; CHAR = WHAT; /* QUESTION MARHLEN = 0; /* NO MATCH */ RETURN FALSE; END MATCH; IF QUITLEN > 0 THEN DO; IF (QUITLEN := QUITLEN OF CBP MUST BE 255 UPON ENTRY THE FIRST TIME */ DELIMITER: PROCEDURE(C) BYTE; DECLARE (I,C) BYTE; DECLWER THEN RETURN LTRAN(B); RETURN B; END GETSOURCEC; GETSOURCE: PROCEDURE BYTE; /* GET NEXT SOURCE CHARACTER */ECTED DISK */ GNC: PROCEDURE BYTE; IF (CBP := CBP + 1) >= COMLEN THEN RETURN CR; RETURN UTRAN(COMBUFF(CBP)); = STARTS; STARTS = 0; FEEDLEN = MATCHLEN + 1; END; /* OTHERWISE NO MATCH, SKIP CHARACTER */ EK */ DO WHILE FLEN < LEN; CALL PUTCHAR; END; END FILLQ; GETFCB: PROCEDUR - 1) = 1 THEN RETURN LF; RETURN ENDFILE; /* TERMINATED WITH CR,LF,ENDFILE */ END; DO FOREVER; /* LOOKINGARE DEL(*) BYTE DATA (' =.:,<>',CR,LA,LB,RB); DO I = 0 TO LAST(DEL); IF C = DEL(I) THEN RETUR DECLARE CHAR BYTE; MATCH: PROCEDURE(B) BYTE; /* MATCH START AND QUIT STRINGS */ DECLARE (B,C) BYTE; END GNC; DEBLANK: PROCEDURE; DO WHILE (CHAR := GNC) = ' '; END; END DEBLANK; SCAN: PROCEDURE(FE(I) BYTE; DECLARE I BYTE; RETURN FCB(I); END GETFCB; SCANPAR: PROCEDURE; DECLARE (I,' '; FLEN = 0; DO WHILE FLEN < FSIZE-1; IF FLEN = FNSIZE THEN CHAR = 0; CALL PUTCHAR; END; CONT(I) = J; IF I = 6 THEN /* SET SOURCE USER */ DO; IF J > 31 THE IF (DISK := GETFCB(1) - 'A' + 1) > 26 THEN /* ERROR, INVALID DISK NAME */ RETURN; C' THEN DO; /* START OR QUIT COMMAND */ J = CBP + 1; /* START OF STRING */ FLEN = 0; DO WHILE NOT DELIMITER(CHAR); IF FLEN >= NSIZE THEN /* ERROR, FILE NAME TOO LONG */ J) BYTE; /* SCAN OPTIONAL PARAMETERS */ PARSET = TRUE; SUSER = CUSER; /* SOURCE USER := CURRENT USER /* DEBLANK COMMAND BUFFER */ CALL DEBLANK; /* SAVE STARTING POSITION OF SCAN FOR DIAGNOSTICS */ TCBP N CALL ERROR(.('INVALID USER NUMBER$')); SUSER = J; END; ALL DEBLANK; /* MAY BE DISK NAME ONLY */ IF DELIMITER(CHAR) THEN DO; IF CHAR = LB THEN DO WHILE NOT ((CHAR := GNC) = ENDFILE OR CHAR = CR); END; CHAR=GNC; RETURN; IF CHAR = '*' THEN CALL FILLQ(NSIZE); ELSE CALL PUTCHAR; CHAR = GNC; */ CHAR = GNC; /* SCAN PAST BRACKET */ DO WHILE NOT(CHAR = CR OR CHAR = RB); IF (I := CHAR - = CBP; /* MAY BE A SEPARATOR */ IF DELIMITER(CHAR) THEN DO; CALL CHKSET; TYPE = SPECL; RETURN; END; END; CHAR = GNC; END SCANPAR; CHKSET: PROCEDURE; IF CHAR = LA T CALL SCANPAR; CBP = CBP - 1; TYPE = DISKNAME; END; ELSE IF (J := (CHAR := GNC) - '0') > 9 THEN J = 1; ELSE END; /* CHECK FOR DISK NAME OR DEVICE NAME */ IF CHAR = ':' THEN DO; IF DISK <> 0 THEN RET'A') > 25 THEN /* NOT ALPHA */ DO; IF CHAR = ' ' THEN CHAR = GNC; ELSE CALL ERROR(.('BAD PARAM END; /* CHECK PERIPHERALS AND DISK FILES */ DISK = 0; /* CLEAR PARAMETERS */ DO I = 0 TO 25; CONHEN CHAR = '='; END CHKSET; /* INITIALIZE FILE CONTROL BLOCK TO EMPTY */ AMBIG = FALSE; TYPE = ERR; CHAR = RETURN; END; END; ELSE /* MAY BE A THREE CHARACTER DEVICE NAME */ DO WHILE (K := (CHAR := GNC) - '0') <= 9; J = J * 10 + K; END; URN; /* ALREADY SET */ IF FLEN = 1 THEN /* MAY BE DISK NAME A ... Z */ DO; ETER$')); END; ELSE DO; /* SCAN PARAMETER VALUE */ IF CHAR = 'S' OR CHAR = 'QT(I) = 0; END; PARSET = FALSE; FEEDLEN,MATCHLEN,QUITLEN = 0; /* SCAN NEXT NAME */ DO FOREVER; IF FLEN <> 3 THEN /* ERROR, CANNOT BE DEVICE NAME */ RETURN; ELSE /* LOOK FOR DEVICE NAM; IF CHAR = '.' THEN /* SCAN FILE TYPE */ DO WHILE NOT DELIMITER(CHAR := GNC); RETURN; END; /* OTHERWISE TRY NEXT DEVICE */ J = J + 3; EXT),FEXTL); END MOVEXT; EQUAL: PROCEDURE(A,B) BYTE; /* COMPARE THE STRINGS AT A AND B UNTIL EITHER A MISMATCH OR ESE DEVICES IN THE LIST */ J = 255; DO K = 0 TO M; I = 0; CB(32) = 0; RETURN; END; END; END SCAN; NULLS: PROCEDURE; /* SEND 40 NULLS TO NAME */ DO; DECLARE (I,J,K) BYTE, M LITERALLY '20', IO(*) BYTE DATA ('INPIRDP IF FLEN >= FNSIZE THEN /* ERROR, TYPE FIELD TOO LONG */ RETURN; IF CHAR = '*' THEN CALL FILLQ END; /* ERROR, NO DEVICE NAME MATCH */ RETURN; END; IF CHAR = LB THEN / A '$' IS ENCOUNTERED IN STRING B */ DECLARE (A,B) ADDRESS, (SA BASED A, SB BASED B) BYTE; DO WHILE SB <> DO WHILE ((I:=I+1) <= 3) AND IO(J+I) = GETFCB(I); END; OUTPUT DEVICE */ DECLARE I BYTE; DO I = 0 TO 39; CALL PUTDEST(0); END; END NULLS; DECLARE FEXTRUR1UR2RDROUTLPTUL1PRNLST', 'PTPUP1UP2PUNTTYCRTUC1CONNULEOF',0); /* NOTE THAT ALL READER-LIK(FNSIZE); ELSE CALL PUTCHAR; END; IF CHAR = LB THEN CALL S* PARAMETERS FOLLOW */ CALL SCANPAR; END; ELSE /* CHAR IS NOT ':', SO FILE NAME IS SET.'$'; IF (SB AND 7FH) <> (SA AND 7FH) THEN RETURN FALSE; A = A + 1; B = B + 1; END; RETURN TRUE; IF I = 4 THEN /* COMPLETE MATCH */ DO; TYPE = PERIPH; /* SCAN PARATH(FEXTL) BYTE, /* HOLDS DESTINATION FILE TYPE */ COPYING BYTE; /* TRUE WHILE COPYING TO DEST FILE */ E DEVICES MUST BE PLACED BEFORE 'RDR', AND ALL LISTING-LIKE DEVICES MUST APPEAR BELOW LST, BUTCANPAR; /* RESCAN DELIMITER NEXT TIME AROUND */ CBP = CBP - 1; TYPE = FILE; SCAN REMAINDER */ DO; IF FLEN = 0 THEN /* ERROR, NO PRIMARY NAME */ RETURN; FLEN = F END EQUAL; READ$EOF: PROCEDURE BYTE; /* RETURN TRUE IF END OF FILE */ CHAR = GETSOURCE; IF SCOM THEN RETURMETERS */ IF GNC = LB THEN CALL SCANPAR; CBP = CBP - 1; CHAR = K; MOVEXT: PROCEDURE(A); DECLARE A ADDRESS; /* MOVE THREE CHARACTER EXTENT INTO DEST FCB */ CALL MOVE(A,.DEST(F ABOVE RDR. THE LITERAL DECLARATIONS FOR RDR, LST, AND PUNP MUST INDICATE THE POSITIONS OF TH/* DISK IS THE SELECTED DISK (1 2 3 ... ) */ IF DISK = 0 THEN DISK = CDISK + 1; /* DEFAULT */ FCB(0),FN HARDEOF < NSOURCE; RETURN CHAR = ENDFILE; END READ$EOF; HEXRECORD: PROCEDURE BYTE; /* READ ONE RECORD INTO /* READ TWO HEX DIGITS */ RETURN SHL(READHEX,4) OR READHEX; END READBYTE; READCS: PROCEDURE BRINTERR(.('RECORD TOO LONG$')); RETURN I; END; RETURN ENDFILE; /* ON ERROR FLAG */ E /* RECORD LENGTH IS NOT ZERO */ LDA = READADDR; /* LOAD ADDRESS */ /* READ WORDS UNTIL RECORD LENGTH EXH CHECKXOFF: PROCEDURE; IF XOFFSET THEN DO; XOFFSET = FALSE; CALL CLEARBUFF; DO; CALL PRINT(.('END OF FILE, CTL-Z',WHAT,'$')); IF READCHAR = ENDFILE THEN RETURN 1; SBUFF AND CHECK FOR PROPER FORM RETURNS 0 IF RECORD OK RETURNS 1 IF END OF TAPE (:00000) RETURNS 2 IYTE; /* READ BYTE WITH CHECKSUM */ RETURN CS := CS + READBYTE; END READCS; READADDR: PROCEDUREND SAVECHAR; DECLARE (M, RL, CS, RT) BYTE, LDA ADDRESS; /* LOAD ADDRESS WHICH FOLLOWS : */ READHEX: PROCEAUSTED */ RT = READCS; /* RECORD TYPE */ DO WHILE RL <> 0 AND NOERRS; RL = RL - 1; M = READCS; END; END CHECKXOFF; SAVECHAR: PROCEDURE BYTE; /* READ CHARACTER AND SAVE IN BUFFER */ DECLARE ELSE HSOURCE = 0; END; CALL CHECKXOFF; END; /* ':' FOUND */ F ERROR IN RECORD */ DECLARE XOFFSET BYTE; /* TRUE IF XOFF RECVD */ DECLARE NOERRS BYTE; /* TRUE IF NO ERROR ADDRESS; /* READ DOUBLE BYTE WITH CHECKSUM */ RETURN SHL(DOUBLE(READCS),8) OR READCS; END READADDR; DURE BYTE; DECLARE H BYTE; IF (H := SAVECHAR) - '0' <= 9 THEN RETURN H-'0'; IF H - 'A' > 5 THEN /* INCREMENT LA HERE FOR EXACT ADDRESS */ END; /* CHECK SUM */ IF CS + READBYTE <> 0 THEN I BYTE; IF NOERRS THEN DO; DO WHILE (I := GETSOURCE) = XOFF; XOFFSET = TRUE; CS = 0; IF (RL := READCS) = 0 THEN /* END OF TAPE */ DO; DO WHILE (RL := SAVECHAR) <> ENDFILE; S IN THIS RECORD */ PRINTERR: PROCEDURE(A); /* PRINT ERROR MESSAGE IF NOERRS TRUE */ DECLARE A ADDRESS; NOERRS = TRUE; /* NO ERRORS DETECTED IN THIS RECORD */ /* READ NEXT RECORD */ /* SCAN FOR THE ':' */ CALL PRINTERR(.('INVALID DIGIT$')); RETURN H - 'A' + 10; END READHEX; READBYTE: PROCEDURE BYTE; CALL PRINTERR(.('CHECKSUM ERROR$')); CALL CHECKXOFF; IF NOERRS THEN RETURN 0; RETURN 2; END END; HBUFF(HSOURCE) = I; IF (HSOURCE := HSOURCE + 1) >= LAST(HBUFF) THEN CALL P CALL CHECKXOFF; END; IF NOERRS THEN RETURN 1; RETURN 2; END; IF NOERRS THEN DO; NOERRS = FALSE; CALL PRINT(A); END; END PRINTERR; HSOURCE = 0; DO WHILE (CS := SAVECHAR) <> ':'; HSOURCE = 0; IF CS = ENDFILE THEN HEXRECORD; READTAPE: PROCEDURE; /* READ HEX FILE FROM HIGH SPEED READER TO 'HEX' FILE, CHECK EACH RECORD FOR VALID E IMMEDIATE READ */ SCOM = EQUAL(.SOURCE(FEXT),.('COM$')); NSOURCE = SBLEN; END SETUPSOURCE; CHECK$STRINGS: PRE OLD $$$ FILE */ CALL MAKE(.DEST); /* CREATE A NEW ONE */ IF DCNT = 255 THEN CALL ERROR(.('NO DIRECTORY SPACE$')); IF UTRAN(READCHAR) <> 'Y' THEN DO; CALL PRINT(.('**NOT DELETED**$')); ORRECT ERROR, TYPE RETURN OR CTL-Z$')); CALL CRLF; IF READCHAR = ENDFILE THEN RETURN; END; END RLL CHECK$STRINGS; CALL WRITEDEST; CALL SELECT(DDISK); CALL CLOSE(.DEST); IF DCNT = 255 THEN CALL ERDIGITS, AND PROPER CHECKSUM */ DECLARE (I,A) BYTE; DO FOREVER; DO WHILE (I := HEXRECORD) <= 1; OCEDURE; IF STARTS > 0 THEN CALL ERROR(.('START NOT FOUND$')); IF QUITS > 0 THEN CALL ERROR(.('QUIT DEST(32),NDEST = 0; END SETUPDEST; SETUPSOURCE: PROCEDURE; HARDEOF = 0FFFFH; CALL SETSUSER; /* SOURCE USER CALL CRLF; CALL MOVEXT(.('$$$')); CALL DELETE(.DEST); RETURN; EADTAPE; FORMERR: PROCEDURE; CALL ERROR(.('INVALID FORMAT$')); END FORMERR; SETUPDEST: PROCEDURE; CALL SELEROR(.('CANNOT CLOSE DESTINATION FILE$')); CALL MOVEXT(.FEXTH); /* RECALL ORIGINAL TYPTE */ DEST(12) = 0; CALL OPEN( IF NOT (I = 1 AND IGNOR) THEN DO A = 1 TO HSOURCE; CALL PUTDEST(HBUFF(A-1)); NOT FOUND$')); END CHECK$STRINGS; CLOSEDEST: PROCEDURE(DIRECT); DECLARE DIRECT BYTE; /* DIRECT IS TRUE IF SEC*/ CALL SELECT(SDISK); CALL OPEN(.SOURCE); CALL SETCUSER; /* BACK TO CURRENT USER */ IF (NOT RSYS) AND ROL(S END; CALL CRLF; END; DEST(ROFILE) = DEST(ROFILE) AND 7FH; CT(DDISK); DHEX = EQUAL(.DEST(FEXT),.('HEX$')); CALL MOVE(.DEST(FEXT),.FEXTH,FEXTL); /* SAVE TYPE */ DEST(ROFILE).DEST); IF DCNT <> 255 THEN /* FILE EXISTS */ DO; IF ROL(DEST(ROFILE),1) THEN /* READ ONLY */ END; CALL PUTDEST(CR); CALL PUTDEST(LF); IF I = 1 THEN /* END OF TAPE ENCOUNTERED */ TOR-BY-SECTOR COPY */ IF DIRECT THEN /* GET UNFILLED BYTES FROM SOURCE BUFFER */ DFUB = SFUB; ELSE DFUB =OURCE(SYSFILE),1) THEN DCNT = 255; IF DCNT = 255 THEN CALL ERROR(.('NO FILE$')); SOURCE(32) = 0; /* CAUS CALL SETIND(.DEST); END; CALL DELETE(.DEST); END; CALL MOVE(.DEST,.DEST(16),16); / = DEST(ROFILE) AND 7FH; DEST(SYSFILE)= DEST(SYSFILE)AND 7FH; CALL MOVEXT(.('$$$')); CALL DELETE(.DEST); /* REMOV DO; IF NOT WRROF THEN DO; CALL PRINT (.('DESTINATION IS R/O, DELETE (Y/N)?$')); RETURN; END; CALL CRLF; HBUFF(HSOURCE) = '$'; CALL PRINT(.HBUFF); CALL PRINT(.('C 0; DO WHILE (LOW(NDEST) AND 7FH) <> 0; DFUB = DFUB + 1; CALL PUTDEST(ENDFILE); END; CA* READY FOR RENAME */ CALL MOVEXT(.('$$$')); CALL RENAME(.DEST); END CLOSEDEST; SIZE$NBUF: PROCEDURE; /* ERS */ DO I = 0 TO 25; IF CONT(I) <> 0 THEN DO; IF NOT(I=6 OR I=14 OR I=17 OR I=21 O NOT READ$EOF; CALL PUTDEST(CHAR); END; IF RESIZED THEN DO; CALL CLEARBUFF; CALL SIZE$M /* FIND A MATCHING ENTRY */ CALL SETSUSER; /* SOURCE USER */ CALL SELECT(SDISK); CALL SETDMINATION BUFFERS */ SBASE = .MEMORY + SHR(MEMSIZE - .MEMORY,1); SBLEN, DBLEN = SHR((MEMSIZE - .MEMORY) AND 0FF00H,1); CLOSEDEST(FASTCOPY); END SIMPLECOPY; MULTCOPY: PROCEDURE; DECLARE (NEXTDIR, NDCNT, NCOPIED) ADDRESS; PRNAME: PCOMPUTE NUMBER OF BUFFERS - 1 FROM DBLEN */ NBUF = (SHR(DBLEN,7) AND 0FFH) - 1; /* COMPUTED AS DBLEN/128-1, WHERE DBLER I=22) THEN /* NOT OBJ OR VERIFY */ FASTCOPY = FALSE; END; END; IF FASTCOPEMORY; END; END COPYCHAR; SIMPLECOPY: PROCEDURE; DECLARE (FASTCOPY,I) BYTE; REAL$EOF: PROCEDURE BYTE;A(.BUFFER); CALL SEARCH(.SEARFCB); NDCNT = 0; DO WHILE (DCNT <> 255) AND NDCNT < NEXTDIR; CALL SIZE$NBUF; END SIZE$MEMORY; COPYCHAR: PROCEDURE; /* PERFORM THE ACTUAL COPY FUNCTION */ DECLARE RESIZROCEDURE; /* PRINT CURRENT FILE NAME */ DECLARE (I,C) BYTE; CALL CRLF; DO I = 1 TO FNSIZN <= 32K (AND THUS NBUF RESULTS IN A VALUE <= 2**15/2**7-1 = 2**8-1 = 255) */ END SIZE$NBUF; SET$DBLEN: PROCEDURE; Y THEN /* COPY DIRECTLY TO DBUFF */ DO; CALL SET$DBLEN; /* EXTEND DBUFF */ DO WHILE NOT REAL$EOF; RETURN HARDEOF <> 0FFFFH; END REALEOF; CALL SIZE$MEMORY; TCBP = MCBP; /* FOR ERROR TRACING */ NDCNT = NDCNT + 1; CALL SEARCHN; END; CALL SETCUSER; /* FILE CONTROL BLOCK IN ED BYTE; /* TRUE IF SBUFF AND DBUFF COMBINED */ IF (RESIZED := (BLOCK AND PSOURCE <> 0)) THEN /* BLOCK MODE */ CALE; IF (C := DEST(I)) <> ' ' THEN DO; IF I = FEXT THEN CALL PRINTCHAR('.'); CA /* ABSORB THE SOURCE BUFFER INTO THE DEST BUFFER */ SBASE = .MEMORY; IF DBLEN >= 4000H THEN DBLEN = 7F80H; ELSE CALL FILLSOURCE; IF REAL$EOF THEN NDEST = HARDEOF; ELSE NDEST = DBLEN; CALL WRITCALL SETUPDEST; CALL SETUPSOURCE; /* FILES READY FOR DIRECT COPY */ FASTCOPY = TRUE; /* LOOK FOR PARAMETBUFFER */ IF DCNT = 255 THEN DO; IF NCOPIED = 0 THEN CALL ERROR(.('NOT FOUND$')); CALL CRLF; L SET$DBLEN; /* ABSORB SOURCE BUFFER */ IF HEXT OR IGNOR THEN /* HEX FILE */ CALL READTAPE; ELSE DO WHILELL PRINTCHAR(C); END; END; END PRNAME; NEXTDIR,NCOPIED = 0; DO FOREVER; DBLEN = DBLEN + SBLEN; CALL SIZE$NBUF; END SET$DBLEN; SIZE$MEMORY: PROCEDURE; /* SET UP SOURCE AND DESTEDEST; END; CALL SIZE$MEMORY; /* RESET TO TWO BUFFERS */ END; ELSE CALL COPYCHAR; CALL RETURN; END; NEXTDIR = NDCNT + 1; /* GET THE FILE CONTROL BLOCK NAME TO DEST */ VERSION < CPMVERSION THEN DO; CALL PRINT(.('REQUIRES CP/M 2.0 OR NEWER FOR OPERATION.$')); CALL BOOT; ENLL SET$SDISK; CALL CHECK$EOL; CALL MOVE(.SOURCE,COPYFCB,33); CALL CHECK$DISK; END SCANDEST; SCANEQL: PROCURCE); /* MAY BE MULTI COPY */ IF TYPE <> FILE THEN CALL FORMERR; IF AMBIG THEN DO; CALL END SET$SDISK; SET$DDISK: PROCEDURE; IF PARSET THEN /* PARAMETERS PRESENT */ CALL FORMERR; IF DISK > 0 THEN DNSOLE IF NOT A ONELINER */ IF MULTCOM THEN DO; CALL PRINTCHAR('*'); CALL READCOM; CALL CRLF; END CALL MOVE(.BUFFER+SHL(DCNT AND 11B,5),.DEST,16); DEST(0) = 0; DEST(12) = 0; CALL MOVE(.DEST,.SOURCE,16); /* FID; /* GET CURRENT USER */ CUSER = GETUSER; /* GET CURRENT DISK */ CDISK = MON2(25,0); RETRY: /* ENTER HERE OEDURE; CALL SCAN(.SOURCE); IF NOT (TYPE = SPECL AND CHAR = '=') THEN CALL FORMERR; MCBP = CBP; /* FOR ERROR PRINT SCANDEST(.SEARFCB); CALL MULTCOPY; END; ELSE DO; CALL SCANDEST(.DEST); /* FDISK = DISK - 1; ELSE DDISK = CDISK; END SET$DDISK; CHECK$DISK: PROCEDURE; IF SUSER <> CUSER THEN /* DIFFERENT DISK; CBP = 255; IF COMLEN = 0 THEN /* SINGLE CARRIAGE RETURN */ DO; CALL SELECT(CDISK); CALL BOOT; LL BOTH FCB'S */ IF RSYS OR NOT ROL(DEST(SYSFILE),1) THEN /* OK TO READ */ DO; IF (NCOPIED :=N ERROR EXIT FROM THE PROCEDURE 'ERROR' */ CALL SIZE$MEMORY; /* MAIN PROCESSING LOOP. PROCESS UNTIL CR ONLY */ DING */ END SCANEQL; PIPENTRY: /* BUFFER AT 80H CONTAINS REMAINDER OF LINE TYPED FOLLOWING THE COMMAND 'PIP' - IFORM IS A:=B:UFN */ CALL SIMPLECOPY; END; GO TO ENDCOM; END; IF TYPE <> FILE OS */ RETURN; IF DDISK = SDISK THEN CALL FORMERR; END CHECK$DISK; CHECK$EOL: PROCEDURE; CALL DEBLANK; END; /* LOOK FOR SPECIAL CASES FIRST */ DDISK,SDISK,PSOURCE,PDEST = 0; CALL SCAN(.DEST); IF TYPE = PERIPH NCOPIED + 1) = 1 THEN CALL PRINT(.('COPYING -$')); CALL PRNAME; CALL SIMPLECOPY; O FOREVER; SUSER = CUSER; C1, C2, C3 = 0; /* LINE COUNT = 000000 */ PUTNUM = TRUE; /* ACTS LIKE LF OCCURRED ON AS ZERO THEN PROMPT TIL CR */ CALL MOVE(.BUFF,.COMLEN,80H); MULTCOM = COMLEN = 0; /* GET CURRENT CP/M VERSION */ IF R AMBIG THEN CALL FORMERR; CALL SET$DDISK; CALL SCANEQL; CALL SCAN(.SOURCE); IF TYPE = DISKNAME THEN IF CHAR <> CR THEN CALL FORMERR; END CHECK$EOL; SCANDEST: PROCEDURE(COPYFCB); DECLARE COPYFCB ADDRESS; CA THEN GO TO SIMPLECOM; IF TYPE = DISKNAME THEN DO; DDISK = DISK - 1; CALL SCANEQL; CALL SCAN(.SO END; END; END MULTCOPY; SET$SDISK: PROCEDURE; IF DISK > 0 THEN SDISK = DISK - 1; ELSE SDISK = CDISK;CII FILE */ CONCNT,COLUMN = 0; /* PRINTER TABS */ LINENO = 254; /* INCREMENTED TO 255 > PAGCNT */ /* READ FROM CO DO; CALL SET$SDISK; CALL CHECK$DISK; CALL MOVE(.DEST,.SOURCE,33); CALL CHECK$EOL; CALL SIM ERROR(.('CANNOT READ$')); SCOM = SCOM OR OBJ; /* MAY BE ABSOLUTE COPY */ PSOURCE = CHAR + 1; IF CHAR =OR(.('INVALID PIP FORMAT$')); /* OTHERWISE SCAN AND COPY UNTIL CR */ COPYING = TRUE; DO WHILE COPYING; COMLEN = MULTCOM; END; /* DO FOREVER */ END; ALL ERROR(.('UNRECOGNIZED DESTINATION$')); DHEX = FALSE; IF TYPE = FILE THEN DO; /* DESTINATION IS A FILE, T SOURCE */ CALL SCAN(.SOURCE); IF TYPE <> SPECL OR (CHAR <> ',' AND CHAR <> CR) THEN CALL ERROR(PLECOPY; GO TO ENDCOM; END; /* MAY BE POSSIBLE TO DO A FAST DISK COPY */ IF TYPE = FILE THEN /* FILE NULP THEN CALL NULLS; ELSE IF CHAR = EOFP THEN CALL PUTDEST(ENDFILE); ELSE DO; /* DISK COPY */ IF SUSER = CUSER; CALL SCAN(.SOURCE); /* SUSER MAY HAVE BEEN RESET */ SCOM = FALSE; IF TYPSAVE EXTENT NAME */ CALL SET$DDISK; CALL SETUPDEST; CHAR = 255; END; ELSE /* PERIPHERAL.('INVALID SEPARATOR$')); COPYING = CHAR <> CR; END; /* IF NECESSARY, CLOSE FILE OR PUNCH TRAILER */ TO FILE */ DO; CALL DEBLANK; IF CHAR <> CR THEN GO TO SIMPLECOM; /* FILE TO FILE */ CALL SET$SDISK; (CHAR < HSRDR AND DHEX) THEN HEXT = 1; /* HEX FILE SET IF SOURCE IS RDR AND DEST IS HEX FILE */ IF PDEST =E = FILE AND NOT AMBIG THEN /* A SOURCE FILE */ DO; CALL SET$SDISK; CALL SETUPSOURCE; NAME */ IF CHAR >= NULP OR CHAR <= RDR THEN CALL ERROR(.('CANNOT WRITE$')); IF (PDEST := CHAR + 1) = PUNP THEN CALL IF PDEST = PUNP THEN DO; CALL PUTDEST(ENDFILE); CALL NULLS; END; IF PDEST = 0 THEN /* FILE HAS TO BE CALL SIMPLECOPY; GO TO ENDCOM; END; SIMPLECOM: CBP = 255; /* READY FOR RESCAN */ /* OT PRNT THEN DO; NUMB = 1; IF TABS = 0 THEN TABS = 8; IF PAGCNT = 0 THEN PAGCNT = 1; CHAR = 255; END; ELSE IF TYPE <> PERIPH OR (CHAR <= LST AND CHAR > RDR) THEN CALL NULLS; /* NOW SCAN THE DELIMITER */ CALL SCAN(.SOURCE); IF TYPE <> SPECL OR CHAR <> '=' THEN CALL ERR CLOSED AND RENAMED */ CALL CLOSEDEST(FALSE); /* COMLEN SET TO 0 IF NOT PROCESSING MULTIPLE COMMANDS */ ENDCOM:HERWISE PROCESS SIMPLE REQUEST */ CALL SCAN(.DEST); IF (TYPE < FILE) OR AMBIG THEN /* DELIMITER OR ERROR */ C END; CALL COPYCHAR; END; CALL CHECK$STRINGS; /* READ ENDFILE, GO TO NEX3 0A3D 184 0A44 185 0A4B 186 0A4E 187 0A4F 188 0A4F 190 0A55 191 0A5C 192 0A5F 193 0A6E 194 0A7B 195 0A89 197 0A91 198 0A97 1916 114 091F 115 091F 116 0923 118 092E 119 092F 120 092F 121 0936 122 0937 123 0937 124 093E 125 093F 126 0945 128 094F 129 0D3A 320 0D44 321 0D4E 322 0D51 323 0D59 324 0D62 325 0D66 326 0D6B 327 0D6E 328 0D6E 329 0D76 330 0D7B 331 0D7C 332 0D80 334 42 080A 43 0813 44 0813 45 0813 46 081C 47 081C 49 0820 51 082D 52 082E 53 082E 54 0833 55 0838 56 0839 57 083F 5B 262 0C2E 263 0C31 264 0C34 265 0C37 266 0C3A 267 0C3D 268 0C46 269 0C50 270 0C50 271 0C55 272 0C58 273 0C5B 274 0C5B 275 0C99 0A9D 200 0AA4 201 0AAA 202 0AAD 203 0AB7 204 0ABE 205 0AC4 206 0AC7 207 0AC8 208 0AC8 212 0ADA 213 0ADB 214 0AE1 215 0AE8 094F 130 0955 132 095F 133 095F 134 0965 136 096E 137 096F 140 096F 141 0974 142 097C 143 097D 145 097D 146 0986 147 0986 149 0D91 335 0D99 336 0DA2 337 0DA3 338 0DA7 340 0DB4 341 0DBD 342 0DBE 343 0DBE 345 0DC3 346 0DCE 347 0DD6 348 0DDF 349 0DE8 359 0842 60 084B 61 084C 63 084C 64 0855 65 0855 66 0855 67 085D 68 085E 69 0862 71 086D 72 086E 73 0874 75 0880 76 60 276 0C63 277 0C66 278 0C66 279 0C6B 280 0C6E 281 0C71 282 0C7F 283 0C7F 284 0C84 285 0C87 286 0C8A 287 0C8A 288 0C8F 289 0216 0AEE 217 0AFD 218 0B07 219 0B0F 220 0B1A 221 0B20 222 0B2A 223 0B31 224 0B38 226 0B3E 227 0B44 228 0B53 229 0B61 230 0B68 098C 151 0995 152 0996 153 0996 155 099A 156 099E 157 09A7 158 09AA 159 09AF 160 09AF 162 09B5 164 09B8 165 09C0 166 09C5 1670 0DEF 351 0DF6 352 0DFD 353 0E05 355 0E0A 356 0E0F 357 0E12 358 0E17 359 0E18 360 0E18 363 0E21 364 0E2A 365 0E2D 366 0E3C 3 0881 77 0887 79 0893 80 0894 81 089A 83 08A6 84 08A7 85 08A7 86 08B2 87 08B3 88 08B9 90 08C2 91 08C3 92 08C9 94 0C92 290 0C95 291 0C95 292 0C9A 293 0C9D 294 0CA0 295 0CAE 296 0CAE 297 0CB3 298 0CB6 299 0CB9 300 0CB9 301 0CBE 302 0CC1 303 231 0B6D 232 0B7B 233 0B9B 234 0B9F 235 0BA2 236 0BAC 237 0BB3 238 0BB9 239 0BC0 240 0BC9 241 0BC9 242 0BCF 243 0BD0 244 0BD4 09CA 168 09DA 169 09E4 170 09F1 171 09F8 172 09FD 173 0A03 174 0A0B 175 0A11 176 0A14 177 0A17 178 0A18 179 0A27 182 0A33 1867 0E44 368 0E45 369 0E49 371 0E50 373 0E58 374 0E59 375 0E59 376 0E60 378 0E68 380 0E73 382 0E7B 383 0E80 384 0E8E 386 0E93 38D3 95 08D3 96 08D9 98 08E3 99 08E3 100 08E9 102 08F5 103 08F6 104 08FC 106 0905 107 0906 109 090C 111 0915 112 0916 113 00CC4 304 0CC4 305 0CC9 306 0CCC 307 0CCF 308 0CDD 309 0D05 310 0D0B 311 0D0C 312 0D10 314 0D18 315 0D22 316 0D2A 317 0D34 319 0000 PIP# 0000 PIPMOD# 07E6 14 07EA 16 07F2 17 07F3 18 07F3 19 07FB 20 07FF 21 07FF 22 07FF 23 0804 24 0809 25 080A 246 0BDC 248 0BE0 249 0BE9 251 0BF3 252 0BF4 253 0BF4 254 0BF4 255 0BFA 256 0C0A 257 0C0A 258 0C16 259 0C19 260 0C24 261 0C287 0E98 388 0E98 389 0E98 390 0EA1 391 0EA4 392 0EA9 393 0EA9 394 0EA9 395 0EB0 397 0EC8 399 0ECB 400 0ECC 401 0ECC 402 0ECC 593 1486 594 1487 595 148B 597 1490 598 149A 599 149D 600 14A0 601 14A1 602 14A5 604 14B1 605 14B1 606 14B1 608 14B6 609 14BC 11EA 527 11EF 528 11F2 529 110D 530 1116 532 1122 533 1125 534 1128 535 1128 536 1128 537 1131 539 1135 540 1141 541 1145 5433 1402 734 140A 735 140D 736 1411 737 1416 738 141E 739 1425 740 1433 741 1434 742 1434 743 1437 744 15CF 745 15CF 747 15DD 705 464 1008 465 1008 466 100E 467 1011 468 1011 469 1016 470 1019 471 101C 472 101C 473 1021 474 1024 475 1027 476 1027 477 112AA 671 12B5 672 12BD 673 12BE 674 12C6 675 12CE 676 12D1 677 12D7 678 12DA 679 12E2 681 12EA 682 12EB 683 12F3 685 1305 686 403 0ED4 404 0ED9 405 0EE0 406 0EE8 407 0EED 408 0EEE 409 0EF2 411 0F09 412 0F11 413 0F15 414 0F15 415 0F19 417 0F30 418 0F38 610 14C2 611 14DA 612 14E9 614 14F1 615 14FA 616 1500 617 1503 619 151B 621 1522 622 153D 623 1540 624 1546 625 1549 626 1552 1146 543 1146 544 1151 545 1154 546 115D 548 1168 550 116E 551 1173 552 117A 553 117A 554 117D 555 1186 557 1191 559 1196 548 15E2 749 15E9 750 15EA 752 15F0 754 15FC 755 15FD 756 1607 758 1610 759 1623 760 1626 761 162D 762 1634 763 1637 764 163A 02C 478 102F 479 1032 480 1032 481 1037 482 1042 483 1045 484 106D 485 1073 486 107A 488 1080 489 1085 490 108C 491 1092 492 1306 687 1309 688 1314 690 131C 691 131F 692 1323 693 1328 694 1329 695 1329 696 132C 697 1334 698 1335 701 133A 702 1346 703 419 0F3C 420 0F3C 421 0F3C 423 0F47 425 0F59 427 0F61 428 0F64 429 0F6A 430 0F6D 431 0F6D 432 0F6D 433 0F72 434 0F78 435 0F8B 627 1563 628 1575 629 158A 630 158D 631 159A 632 15A2 634 15AB 635 15B1 636 15B7 637 15B7 638 15B7 639 15BA 640 15C0 641 1560 119B 561 119E 562 119E 563 11A2 564 11A5 565 11A9 566 11AC 567 11F2 569 11F2 570 1200 571 1203 572 1211 573 1211 574 1211 765 163A 766 163A 767 1640 768 1647 769 1652 770 165B 771 165B 772 1712 775 1718 777 171F 779 1724 780 172C 781 172C 782 172D1092 493 1099 495 10A0 496 10B2 497 10BD 498 10C4 500 10CB 502 10D3 503 10D6 504 10DC 505 10DC 506 10DC 507 10DC 508 10E3 509 134B 704 137B 705 137E 706 1386 708 138B 709 1393 710 1396 711 139A 712 13A0 713 13A1 714 13A1 715 13A9 716 13B0 717 13B1 718 436 0F88 437 0F94 438 0F97 439 0FA3 440 0FAA 441 0FAD 442 0FB6 443 0FBF 444 0FBF 445 0FC4 446 0FC7 447 0FCA 448 0FCA 449 0FC1 642 15C1 643 15C9 644 15CE 645 1226 646 122B 647 1230 648 1233 649 1238 650 1240 651 1248 652 124D 653 1250 654 1253 655 1575 121C 576 121F 577 1220 578 1438 581 143C 584 144A 585 145A 586 145D 587 1464 588 1467 589 1467 590 1467 591 1479 592 1481 783 172D 784 1734 786 1739 787 173C 788 173C 789 173D 790 173D 792 1744 794 174F 795 1754 796 1757 797 1764 798 1770 799 177 10EB 510 10F2 511 10FA 512 1101 513 1109 514 110D 515 110D 516 11AD 518 11B1 520 11C9 522 11D6 523 11D9 524 11D9 525 11E3 5268 13B1 719 13B9 720 13BC 721 13BF 723 13C7 724 13C8 725 13CD 726 13D5 727 13E3 728 13EB 729 13EC 730 13F4 731 13FC 732 13FF 7CF 450 0FD2 451 0FD5 452 0FD5 453 0FDA 454 0FDD 455 0FE0 456 0FF0 457 0FF3 458 0FF6 459 0FF9 460 0FFC 461 0FFF 462 1002 463 10256 656 125C 657 1267 659 126A 660 126F 661 1270 662 1270 663 1275 664 1283 665 128E 666 1295 667 129A 668 12A5 669 12A5 670 6 800 177A 801 177A 802 177D 803 177D 805 177D 807 178C 808 1792 809 179E 810 17A4 811 17AC 812 17AC 813 17AC 814 17BB 815 1778 994 1AB2 995 1AB5 996 1ABB 997 1ABE 998 1AC1 999 1AC6 1000 1AD2 1001 1AE1 1003 1B1D 1004 1B22 1005 1B22 1006 1B29 1007 1B3931 1988 932 198D 933 1993 934 199B 936 19A3 938 19AA 940 19B0 941 19BC 943 19C2 944 19C5 945 19CB 946 19D1 947 19D2 948 19D216 051A 1117 0525 1118 052A 1119 0532 1120 0535 1121 053C 1123 0541 1124 0544 1125 0547 1126 0547 1127 054C 1128 0554 1130 055 184C 875 184F 876 1857 877 1858 878 185B 879 185C 880 185C 881 1862 882 1863 883 1863 884 186A 885 1876 886 1882 887 188A 8881064 1C42 1065 1C45 1066 1C45 1067 1C48 1068 1C88 1069 1C88 1070 1C91 1071 1C9B 1072 1CA1 1073 1CA2 1074 1CA2 1075 1CA9 1076 1BB 816 17BB 817 17C4 818 17C4 819 17C4 820 17DA 821 165B 822 1660 823 1665 824 1670 825 1675 826 167D 828 1683 829 168B 830 160 1009 1B33 1010 1B3A 1011 1B3D 1012 1B44 1013 1B4D 1014 1B53 1015 1B56 1016 1B59 1017 1B5C 1018 1B5F 1019 1B62 1020 1B69 1021 949 19D5 950 19D5 951 19DD 952 19E3 953 19E3 954 19E9 955 19E9 956 19F5 957 19FB 958 1A01 959 1A02 960 1A02 961 1A15 962 1A16B 1131 055E 1132 055E 1133 0570 1134 0576 1135 057E 1136 0581 1137 0589 1139 0590 1140 0593 1141 0599 1142 05A1 1143 05A4 114 1892 889 1898 890 189E 891 18A4 892 18AC 893 18B2 894 18BD 895 18BE 896 18BE 897 18C4 898 18C7 899 18CE 900 18D4 901 18D7 90CAC 1077 1CB5 1078 1CBF 1079 1CC5 1080 1CC6 1081 1CC6 1082 1CD0 1083 1CD1 1084 1CDB 1085 1CDE 1086 1CDF 1087 1CDF 1088 1CE2 18E 831 1693 832 1693 833 1696 834 1699 835 169E 836 16A9 838 16B4 839 16B7 840 16BA 841 16C1 842 16C4 843 16C7 844 16C7 845 1 1B78 1022 1C49 1024 1C49 1026 1C4C 1027 1C5A 1028 1C6C 1030 1C74 1031 1C79 1032 1C80 1033 1C80 1034 1C87 1035 1B78 1036 1B81 963 1A16 964 1A1C 965 1A28 966 1A31 967 1A3C 968 1A3F 969 1A40 970 1A40 971 1A56 972 1A68 973 1A6B 974 1A6C 975 1A6C 977 1A74 05AB 1146 05B1 1147 05B4 1148 05B7 1150 05BD 1151 05C0 1152 05C0 1153 05C3 1154 05C3 1155 05D3 1156 05D6 1157 05D9 1158 05DC2 18E7 903 18EC 904 18F4 905 18FA 906 18FF 907 190B 908 1911 909 1912 910 1912 911 191B 912 1921 913 192A 914 1930 915 1931 9089 1CEA 1090 1CED 1091 1CEE 1092 1CF4 1094 1CF7 1095 1CFA 1096 1D08 1097 1D0B 1098 1D0C 1099 1D0C 1100 1D12 1101 1D2A 1102 1D6CD 846 16D3 847 16E3 848 16E7 849 16ED 850 16F0 851 16FC 852 1702 853 1705 854 170C 855 170F 856 1712 857 17DA 858 17DA 860 1037 1B81 1038 1B84 1039 1B8B 1040 1B91 1041 1B97 1042 1B9D 1043 1BB7 1044 1BBE 1045 1BC1 1046 1BC4 1047 1BC7 1048 1BCF 1050 F 978 1A82 979 1A8D 980 1A93 981 1A9A 982 1AA1 983 1AA4 984 1AAB 986 1AAE 987 1AB1 988 1AB1 989 1AB2 990 1B6A 992 1B6A 993 1B 1159 05E2 1160 05EA 1162 05ED 1163 05F0 1164 05FC 1165 05FF 1166 0602 1167 0605 1168 0605 1169 060D 1171 0610 1172 0618 117316 1935 918 193C 919 1945 920 194A 921 1955 922 1959 923 195E 924 1961 925 1964 926 1967 927 196E 928 1974 929 197C 930 1982 2D 1103 1D33 1104 04CE 1105 04DD 1106 04E8 1107 04F4 1109 04FA 1110 04FD 1111 04FD 1112 0503 1113 050E 1114 0514 1115 0514 1117DA 861 17E7 862 17F7 863 1806 864 1815 865 181C 866 1821 867 1826 868 182E 869 182F 870 1832 871 1835 872 1840 873 1846 8741BDB 1051 1BE1 1052 1BE4 1053 1BE5 1054 1BE5 1055 1BEC 1056 1C06 1057 1C0B 1058 1C10 1059 1C1C 1060 1C29 1062 1C39 1063 1C3F 061B 1174 061E 1175 0621 1176 0624 1177 0624 1178 0629 1179 062F 1180 063D 1181 0643 1182 0648 1183 0650 1185 0653 1186 0656 5) byte initial('001 $'), ln1 byte at(.ln(0)), ln2 byte at(.ln(1)), ln3 byte at(.ln(2)), dfcb(33) byte initia(.submit); /* jmp to submit is placed at the beginning of the module */ boot: procedure external; /* system reboot */ end print; declare dcnt byte; open: procedure(fcb); declare fcb address; dcnt = mon2(15,fcb); end open;41 07E1 1242 07E4 1243 ss', ctll lit '0ch', lca lit '110$0001b', /* lower case a */ lcz lit '111$1010b', /* lower case z */ end1187 065B 1188 065E 1189 0675 1190 067B 1191 0687 1192 068A 1193 0690 1194 06A8 1195 06AE 1196 06B3 1197 06BA 1198 06C0 1199 al(0,'$$$ SUB',0,0,0), drec byte at(.dfcb(32)), /* current record */ buff(128) byte at(dbuff), /* default buffe end boot; mon1: procedure(f,a) external; declare f byte, a address; /* bdos interface, no returned value */ close: procedure(fcb); declare fcb address; dcnt = mon2(16,fcb); end close; delete: procedure(fcb); dsub: do; /* modified 7/26/79 to work with cpm 2.0, module number not zero */ declare wboot literally '0000h', /* warm sfile lit '1ah'; /* cp/m end of file */ declare true literally '1', false literally '0', forever literally '06C6 1200 06CB 1201 06DF 1203 06E2 1204 06E5 1205 06EA 1206 06ED 1207 070D 1208 0713 1209 071B 1210 0722 1211 072A 1212 0730 1r */ sfcb(33) byte at(dfcba); /* default fcb */ submit: procedure; /* t h e c p / m 's u b m i t' f u end mon1; mon2: procedure(f,a) byte external; declare f byte, a address; /* bdos interface, return byte value */eclare fcb address; call mon1(19,fcb); end delete; diskread: procedure(fcb) byte; declare fcb address; retart entry point */ bdos literally '0005h', /* jmp bdos */ dfcba literally '005ch', /* default fcb address */ while true', cr literally '13', lf literally '10', what literally '63'; print: procedure(a); declare a ad213 0738 1214 0740 1216 074E 1217 0753 1218 075B 1220 0760 1221 0768 1222 076D 1223 0775 1224 077A 1225 077A 1226 077D 1227 0 n c t i o n copyright (c) 1976, 1977, 1978 digital research box 579 pacific grove, ca. end mon2; declare copyright(*) byte data (' copyright(c) 1977, digital research '); declare ln(turn mon2(20,fcb); end diskread; diskwrite: procedure(fcb) byte; declare fcb address; return mon2(21,fcb); dbuff literally '0080h'; /* default buffer address */ declare jump byte data(0c3h); /* c3 = jmp */ declare jadr address datdress; /* print the string starting at address a until the next dollar sign is encountered */ call mon1(9,a); 77D 1228 0780 1229 0786 1230 07AA 1231 07B0 1232 07BB 1233 07BE 1234 07C6 1236 07CB 1237 07CE 1238 07CE 1239 07D6 1240 07DB 12 93950 */ declare lit literally 'literally', dcl lit 'declare', proc lit 'procedure', addr lit 'addre end diskwrite; make: procedure(fcb); declare fcb address; dcnt = mon2(22,fcb); end make; move: procedure( end; end; end; /* translate to upper case */ if (b-61h) < 26 then /* lower case alpha */ end setup; getsource: procedure byte; /* read the next source character */ declare b byte; if sbp > 1; end; end deblankparm; putrbuff: procedure(b); declare b byte; if (rbp := rbp +te, /* substitute string */ sbp byte; /* source buffer pointer (0-128) */ setup: procedure; /* move botend: procedure byte; /* look at next character in sstring, return true if not at the end of the string - chas,d,n); declare (s,d) address, n byte; declare a based s byte, b based d byte; do while (n := n - 1) <> 255; b = b and 5fh; /* change to upper case */ return b; end getsource; writebuff: procedure; /* write the co127 then do; if diskread(.sfcb(0)) <> 0 then return endfile; sbp = 0; end; if (b := 1) > last(rbuff) then call error(.('Command Buffer Overflow$')); rbuff(rbp) = b; /* len: c1 ... uffer to substitute string */ call move(.buff(1),.sstring(0),127); sstring(buff(0))=0; /* mark end of string */ cr passed back in 's' */ if not ((s := sstring(ssbp)) = ' ' or s = 0) then do; ssbp = b = a; s = s + 1; d = d + 1; end; end move; declare oldsp address; /* calling program's stack pointentents of the buffer to disk */ if diskwrite(.dfcb) <> 0 then /* error */ call error(.('Disk Write Error$')); buff((sbp:=sbp+1)-1)) = cr then do; /* increment line */ if (ln3 := ln3 + 1) > '9' then do; ln3 c125 :00:$ = 128 chars */ if (rlen := rlen + 1) > 125 then call error(.('Command Too Long$')); enall move(.('SUB'),.sfcb(9),3); /* set file type to sub */ call open(.sfcb(0)); if dcnt = 255 then call error( ssbp + 1; return true; end; return false; end notend; deblankparm: procedurer */ error: procedure(a); declare a address; call print(.(cr,lf,'$')); call print(.('Error On Line $')); end writebuff; declare rbuff(2048) byte, /* jcl buffer */ rbp address, /* jcl buffer pointer */ rlen byte; = '0'; if (ln2 := ln2 + 1) > '9' then do; ln2 = '0'; ln1 = ln1 + 1; d putrbuff; declare (reading,b) byte; /* fill the jcl buffer */ rbuff(0),rbp = 0; reading = true; .('No ''SUB'' File Present$')); /* otherwise file is open - read subsequent data */ sbp = 128; /* causes read below */; /* clear to next non blank substitute string */ do while sstring(ssbp) = ' '; ssbp = ssbp +call print(.ln1); call print(a); stackptr = oldsp; /* return to ccp */ end error; declare sstring(128) by /* length of current command */ fillrbuff: procedure; declare (s,ssbp) byte; /* sub string buffer pointer */ n do while reading; rlen = 0; /* reset command length */ do while (b:=getsource) <> endfile and b <> cr; reading = b = cr; call putrbuff(rlen); /* store length */ end; /* entire file has been read and processe end; else /* not a '$' */ if b = '^' then /* control character */ do; /* must be ^all fillrbuff; call makefile; call boot; /* reboot causes commands to be executed */ end submit; end;  do while b <> 0; b = b - 1; /* clear next parameter */ do buff(0) = i; buff(i+1) = 00; buff(i+2) = '$'; do while i > 0; buff(i) = getrbuff; i=i-1; if b <> lf then do; if b = '$' then /* copy substitute string */ do; if (b:=getsd */ end fillrbuff; makefile: procedure; /* write resulting command file */ declare i byte; getrbuff: pro ... ^z */ if (b:=getsource - 'a') > 25 then call error(.('Invalid Control Charact while notend; end; call deblankparm; end; /* buffer filled to $ */ call writebuff; end; call close(.dfcb); if dcnt = 255 ource) = '$' then /* $$ replaced by $ */ call putrbuff(b); else cedure byte; return rbuff(rbp := rbp - 1); end getrbuff; call delete(.dfcb); drec = 0; /* zero theer$')); else call putrbuff(b+1); end; else /* not $ or ^ */ end; /* ready to copy substitute string from position ssbp */ do while notthen call error(.('Cannot Close, Read/Only?$')); end makefile; /* enter here from the ccp with the fcb set */ declare if (b := b - '0') > 9 then call error(.('Parameter Error$')); else do; /* fi next record to write */ call make(.dfcb); if dcnt = 255 then call error(.('Directory Full$')); do while (i : call putrbuff(b); end; end; /* of line or input file - compute length */ end; call putrbuff(s); end; end; stack(10) address; /* working stack */ oldsp = stackptr; stackptr = .stack(length(stack)); call setup; cand string 'b' in sstring */ ssbp = 0; call deblankparm; /* ready to scan sstring */ = getrbuff) <> 0; /* copy i characters to buffer */ /* 00 $ at end of line gives 1.3 & 1.4 compatibility */ 0000 SUBMIT# 0000 SUB# 01DF 15 01F7 18 01FD 20 0206 21 0207 23 020D 25 0219 26 021A 27 0220 29 022C 30 022D 31 023304FE 168 057A 170 057A 171 0587 172 04FE 173 0504 174 0509 175 050F 176 0517 177 051D 178 0528 179 052E 180 0537 181 0542 182tatus */ /* status status status status status status */ /* status status status status status sA 104 0481 106 0481 107 04A3 109 04A7 110 04AA 111 04AA 112 04AD 113 04AD 114 04AD 115 04BC 116 04C0 117 04C3 118 04C4 119 04tatus */ /* status status status status status status */ /* status status status status status s 33 023C 34 023D 35 0243 37 024D 38 024D 39 0253 41 025D 42 025D 43 0263 45 026F 46 0270 47 027F 50 028B 51 0295 5 054B 183 0558 184 055C 185 055F 186 0562 187 0565 188 056B 189 0573 190 0579 191 01DF 193 01E6 194 01EA 195 01ED 196 01F0 19tatus */ /* status status status status status status */ /* status status status status status sC8 121 04D8 122 04DE 123 04E9 124 04F7 125 04FD 126 038A 128 0395 129 039A 130 03A1 131 03A6 132 03C1 133 03C9 135 03D1 137 0tatus */ /* status status status status status status */ /* status status status status status s2 029C 53 02A3 54 02A6 55 02A7 57 02AD 59 02B3 60 02B9 61 02BF 62 02C7 63 02CB 64 02CC 66 02CC 67 02D8 68 02E3 69 7 01F3 198 01F6 199 0000 MODULE# tatus */ /* status status status status status status */ /* status status status status status s3DC 138 03E6 139 03F5 140 03FE 142 0403 143 0406 144 040E 145 0412 146 0419 147 041C 148 041F 149 0422 150 0429 151 0430 152 tatus */ /* status status status status status status */ /* status status status status status s 02EF 70 02F5 71 02FD 72 0303 73 0308 74 0309 75 0309 77 0312 79 031D 80 0320 81 0325 82 0325 83 033D 85 034B 87 0stat: do; declare cpmversion literally '20h'; /* requires 2.0 cp/m */ /* c p / m s t a t u s c o m m a n d (s t atatus */ /* status status status status status status */ /* status status status status status s0433 153 0433 154 0436 155 043E 157 044D 158 0456 159 045E 160 0461 161 0468 162 0468 163 046B 164 0476 165 047D 166 0480 167 tatus */ /* status status status status status status */ /* status status status status status s350 88 035B 90 0360 91 0362 92 0362 93 0362 94 0362 95 036C 96 0374 97 0378 98 0378 99 0378 100 0383 101 0389 102 038 t) */ /* status status status status status status */ /* status status status status status status */ /* status status status status status status */ /* status status status status status s, /* parameter, if sent */ rreca literally '007dh', /* random record 7d,7e,7f */ rreco literally '007fh', (2 by) size of directory-1 dirblk (2 by) reservation bits for directory chksiz (2 by) size of procedure external; /* reboot */ end boot; mon1: procedure(f,a) external; declare f byte, a address; ende under cp/m 2.0 */ declare jump byte data(0c3h), jadr address data (.status); /* jump to status */ /* function ss, /* disk parameter block address */ dpb based dpba structure (spt address, bls byte, bms byte, exm btatus */ /* status status status status status status */ /* status status status status status s/* high byte of random overflow */ ioba literally '0003h', /* iobyte address */ sectorlen literally '128', /* schecksum vector offset (2 by) offset for operating system */ declare /* fixed locations for cp/m */ mon1; mon2: procedure(f,a) byte external; declare f byte, a address; end mon2; mon3: procedure(f,a) address extcall 32 returns the address of the disk parameter block for the currently selected disk, which consists of: scptrk yte, mxa address, dmx address, dbl address, cks address, ofs address), scptrk literally 'dpb.spt', blkshf literatatus */ /* status status status status status status */ /* copyright(c) 1975, 1976, 1977, 1978,ector length */ memsize address at(bdosa), /* end of memory */ rrec address at(rreca), /* random record addressbdosa literally '0006h', /* bdos base */ buffa literally '0080h', /* default buffer */ fcba literally '005ch'ernal; declare f byte, a address; end mon3; status: procedure; declare copyright(*) byte data ( ' Cop (2 by) number of sectors per track blkshf (1 by) log2 of blocksize (2**blkshf=blksize) blkmsk (1 blly 'dpb.bls', blkmsk literally 'dpb.bms', extmsk literally 'dpb.exm', maxall literally 'dpb.mxa', dirmax li 1979 digital research box 579 pacific grove, ca 93950 */ /* modified */ rovf byte at(rreco), /* overflow on getfile */ doll byte at(dolla), /* dollar parameter */ pa, /* default file control block */ dolla literally '006dh', /* dollar sign position */ parma literally '006eh'yright (c) 1979, Digital Research'); /* dummy outer procedure 'status' will start at 100h */ /* determine status of cuy) 2**blkshf-1 extmsk (1 by) logical/physical extents maxall (2 by) max alloc number dirmaxterally 'dpb.dmx', dirblk literally 'dpb.dbl', chksiz literally 'dpb.cks', offset literally 'dpb.ofs'; boot:10/30/78 to fix the space computation */ /* modified 01/28/79 to remove despool dependencies */ /* modified 07/26/79 to operatrm byte at(parma), /* parameter */ sizeset byte, /* true if displaying size field */ dpba addrerrently selected disk */ declare alloca address, /* alloca is the address of the disk allocation vector */ alloc badma); declare dma address; call mon1(26,dma); end setdma; getalloca: procedure address; /* get base addre*/ return mon2(12,0); end version; select: procedure(d); declare d byte; call mon1(14,d); end selecthis program's stack */ declare fcbmax literally '512', /* max fcb count */ fcbs literally 'memory',/* remainder of are a address; declare s based a byte; do while s <> 0; call printchar(s); a = a + 1; e set$dpb: procedure; /* set disk parameter block values */ dpba = mon3(31,0); /* base of dpb */ end set$dpb; sed alloca (1024) byte; /* allocation vector */ declare true literally '1', false literally '0', forever litess of alloc vector */ return mon3(27,0); end getalloca; getlogin: procedure address; /* get the login vector *; open: procedure(fcb); declare fcb address; dcnt = mon2(15,fcb); end open; search: procedure(fcb); dememory */ fcb(33) byte at (fcba), /* default file control block */ buff(128) byte at (buffa), /* default buffnd; end printx; print: procedure(a); declare a address; /* print the string starting at address a until the getuser: procedure byte; /* return current user number */ return mon2(32,0ffh); end getuser; setuser: procedurrally 'while true', cr literally '13', lf literally '10'; printchar: procedure(char); declare char byte; / return mon3(24,0); end getlogin; writeprot: procedure; /* write protect the current disk */ call mon1(2clare fcb address; dcnt = mon2(17,fcb); end search; searchn: procedure; dcnt = mon2(18,0); end searchn; er */ ioval byte at (ioba); /* io byte */ declare bpb address; /* bytes per block */ set$bpb: procedure next 0 is encountered */ call crlf; call printx(a); end print; break: procedure byte; return mon2(11,0e(user); declare user byte; call mon1(32,user); end setuser; getfilesize: procedure(fcb); declare fcb addcall mon1(2,char); end printchar; crlf: procedure; call printchar(cr); call printchar(lf); end crlf; p8,0); end writeprot; getrodisk: procedure address; /* get the read-only disk vector */ return mon3(29,0); cselect: procedure byte; /* return current disk number */ return mon2(25,0); end cselect; setdma: procedure(; call set$dpb; /* disk parameters set */ bpb = shl(double(1),blkshf) * sectorlen; end set$bpb; select$disk: p); /* console ready */ end break; declare dcnt byte; version: procedure byte; /* returns current cp/m version # ress; call mon1(35,fcb); end getfilesize; declare oldsp address, /* sp on entry */ stack(16) address; /* trintb: procedure; /* print blank character */ call printchar(' '); end printb; printx: procedure(a); decl end getrodisk; setind: procedure; /* set file indicators for current fcb */ call mon1(30,fcba); end setind; rocedure(d); declare d byte; /* select disk and set bpb */ call select(d); call set$bpb; /* bytes per block */ zerosup byte, /* zero suppression flag */ d byte; /* current decimal digit */ zerosup = true; setacc(b); else /* blank fill */ call setacc(' '); if b <= 1 or b = ',' or b = ':' or b = '*' */ bit byte; /* always 1 if mode = false */ ka, ba = 0; bit = 0; do i = 0 to maxall; if if s(i) <> accum(i) then return false; end; return true; end compare; scan: procedure; /* fill acc kilobyte accum */ declare baccum based ab address; /* byte accum */ baccum = baccum + bpb; do while baccum >*/ end select$disk; getalloc: procedure(i) byte; /* return the ith bit of the alloc vector */ declare i addres do while prec <> 0; d = v / prec ; /* get next digit */ v = v mod prec;/* get remainder back to v */ or b = '.' or b = '>' or b = '<' or b = '=' then buff(ibp) = 1; else ibp = ibp + 1; en mode then bit = getalloc(i); if not bit then call add$block(.ka,.ba); end; return ka; end count; um with next input value */ declare (i,b) byte; setacc: procedure(b); declare b byte; accum(i) = b; = 1024; baccum = baccum - 1024; kaccum = kaccum + 1; end; end add$block; count: procedure(mods; return rol(alloc(shr(i,3)), (i and 111b) + 1); end getalloc; declare accum(4) byte, /* accumulator prec = prec / 10; /* ready for next digit */ if prec <> 0 and zerosup and d = 0 then call printb; else d; ibp = ibp + 1; end scan; pdecimal: procedure(v,prec); /* print value v with precision prec (10,100,1000) abortmsg: procedure; call print(.('** Aborted **',0)); end abortmsg; userstatus: procedure; /* display activei = i + 1; end setacc; /* deblank input */ do while buff(ibp) = ' '; ibp=ibp+1; end; /* inie) address; declare mode byte; /* true if counting 0's */ /* count kb remaining, kaccum set upon exit */ declare */ ibp byte; /* input buffer pointer */ compare: procedure(a) byte; /* compare accumulator with four bytes do; zerosup = false; call printchar('0'+d); end; end; end pdecimal; add$block: procedure(ak,a with leading zero suppression */ declare v address, /* value to print */ prec address, /* precision user numbers */ declare i byte; declare user(32) byte; declare ufcb(*) byte data ('????????????',0,0,0); catialize accum length */ i = 0; do while i < 4; if (b := buff(ibp)) > 1 then /* valid */ call ka address, /* kb accumulator */ ba address, /* byte accumulator */ i address, /* local index addressed by a */ declare a address; declare (s based a) (4) byte; declare i byte; do i = 0 to 3; b); declare (ak, ab) address; /* add one block to the kilobyte accumulator */ declare kaccum based ak address; /*ll print(.('Active User :',0)); call pdecimal(getuser,10); call print(.('Active Files:',0)); do i = 0 to last0)); call pv(offset); call printx(.('Reserved Tracks',0)); call crlf; end drivestatus; diskstatus: pr); call printx(.('128 Byte Record Capacity',0)); call pv(count(false)); call printx(.('Kilobyte Drive Ca declare devr(*) byte data (/* console */ 'TTY:CRT:BAT:UC1:', /* reader */ 'TTY:PTR:UR1:UR2:', call crlf; call pdecimal(v,10000); call printchar(':'); call printb; end pv; /* vl byte; declare (i,j,match,sync) byte; j,sync = 0; do sync = 1 to vl; match = true; (user); user(i) = false; end; call setdma(.fcbs); call search(.ufcb); do while dcnt <> 255;ocedure; /* display disk status */ declare login address, d byte; login = getlogin; /* login vector set */ dpacity',0)); call pv(dirmax+1); call printx(.('32 Byte Directory Entries',0)); call pv(shl(chksiz,2)); /* punch */ 'TTY:PTP:UP1:UP2:', /* listing */ 'TTY:CRT:LPT:UL1:'); declare (i,j,iobyte,iteprint the characteristics of the currently selected drive */ call print(.(' ',0)); call printchar(cselect+'A'); do i = 0 to 3; if v(j) <> accum(i) then match=false; j = j + 1; end; if match th if (i := fcbs(shl(dcnt and 11b,5))) <> 0e5h then user(i and 1fh) = true; call searchn; = 0; do while login <> 0; if low(login) then do; call select$disk(d); call drivesta call printx(.('Checked Directory Entries',0)); call pv((extmsk+1) * 128); call printx(.('Records/ Extent',0))ms) byte; prname: procedure(a); declare a address, x based a byte; /* print device name call printchar(':'); call printx(.(' Drive Characteristics',0)); rpb = shl(double(1),blkshf); /* records/block=2**blen return sync; end; return 0; /* no match */ end match; declare devl(*) byte data ('CON:RDR:PUN:LST:end; do i = 0 to last(user); if user(i) then call pdecimal(i,10); end; end userstatus; drivestus; end; login = shr(login,1); d = d + 1; end; end diskstatus; match: procedure; call pv(rpb); call printx(.('Records/ Block',0)); call pv(scptrk); call printx(.('Sectors/ Track',at a */ do while x <> ':'; call printchar(x); a=a+1; end; call printchar(':'); kshf */ if (rpd := (maxall+1) * rpb) = 0 and (rpb <> 0) then call print(.('65536: ',0)); else call pv(rpdDEV:VAL:USR:DSK:'); devreq: procedure byte; /* process device request, return true if found */ /* device tables */ tatus: procedure; declare rpb address, rpd address; pv: procedure(v); declare v address; (va,vl) byte; /* return index+1 to vector at va if match */ declare va address, v based va (16) byte, end prname; items = 0; do forever; call scan; if (i:=match(.devl,8)) = 0 then return ice table */ do; /* find base of destination */ j = shl(i:=i-1,4); call scan; (i,2))); call printx(.(' =',0)); do j = 0 to 12 by 4; call printchar((v/k); v = v mod k; k = k / 10; if zero or k = 0 or d <> 0 then do; zero = true; call printchar(en /* list possible assignment */ do; call print(.('Temp R/O Disk: d:=R/O',0)); call prin ioval = (ioval and iobyte) or j; end; /* end of current item, look for more */ call tems<>0; items = items+1; /* found first/next item */ if i = 5 then /* device status request */ d if accum(0) <> '=' then do; call print(.('Bad Delimiter',0)); return true; e' '); call prname(.devr(shl(i,4)+j)); end; end; end; els'0'+d); end; end; call printchar('k'); call crlf; end pvalue; comp$alloc: procedure; t(.('Set Indicator: d:filename.typ ', '$R/O $R/W $SYS $DIR',0)); call print(.('Disk Statscan; if accum(0) = ' ' then return true; if accum(0) <> ',' then do; call print(.('Bad Delimitero; iobyte = ioval; j = 0; do i = 0 to 3; call prname(.devl(shl(i,2))); nd; call scan; if (j:=match(.devr(j),4)-1) = 255 then do; call print(.('Invalid Assige if i = 7 then /* list user status values */ do; call userstatus; return true; alloca = getalloca; call printchar(cselect+'A'); call printx(.(': ',0)); end comp$alloc; prcount: procedureus : DSK: d:DSK:',0)); call print(.('User Status : USR:',0)); call print(.('Iobyte Assign:',0)); ',0)); return true; end; end; /* of do forever */ end devreq; pvalue: procedure(v); call printx(.(' is ',0)); call prname(.devr(shl(iobyte and 11b,2)+j)); j = j + 16; iobynment',0)); return true; end; iobyte = 1111$1100b; /* construct mask */ end; else if i = 8 then /* show the disk device status */ call diskstatus; else /* scan item i-1 in devi; /* print the actual byte count */ call pvalue(count(true)); end prcount; pralloc: procedure; /* print a do i = 0 to 3; /* each line shows one device */ call crlf; call prname(.devl(shl declare (d,zero) byte, (k,v) address; k = 10000; zero = false; do while k <> 0; d = lowte = shr(iobyte,2); call crlf; end; end; else /* not dev: */ if i = 6 th do while (i:=i-1) <> 255; iobyte = rol(iobyte,2); j = shl(j,2); end; llocation for current disk */ call print (.('Bytes Remaining On ',0)); call comp$alloc; call prcount; end pr fcbr(fcbmax) address, /* record count */ bfcba address, /* index into directory buffer */ fcbsa addr literally '15', fdm literally '16', fdl literally '31', ftyp literally '9', rofile literally '9a('R/O R/W SYS DIR '); if doll = ' ' then return false; call move(4,.parm,.accum); /* $???? */ if acc printchar('W'); call printx(.(', Space: ',0)); call prcount; end; login = shr(l (b,f) byte, /* counters */ matched byte; /* used during fcbs search */ multi16: procedure; /* utalloc; prstatus: procedure; /* print the status of the disk system */ declare (login, rodisk) address; declareess, /* index into fcbs */ bfcb based bfcba (32) byte, /* template over directory */ fcbv based fcbsa (16', /* read/only file */ infile literally '10'; /* invisible file */ declare fcbn address, /* number ofum(0) = 'S' and accum(1) = ' ' then return not (sizeset := true); /* must be a parameter */ if (sogin,1); rodisk = shr(rodisk,1); d = d + 1; end; call crlf; end prstatus; setdisk: procedure; ility to compute fcbs address from i */ fcbsa = shl(i,4) + .fcbs; end multi16; declare scase b d byte; login = getlogin; /* login vector set */ rodisk = getrodisk; /* read only disk vector set */ d = 0; ) byte; /* template over fcbs entry */ declare i address, /* fcb counter during collection and display */ fcb's collected so far */ finx(fcbmax) address, /* index vector used during sort */ fcbe(fcbmax) address, /* case := match(.fstat,4)) = 0 then call print(.('Invalid File Indicator',0)); return true; end set if fcb(0) <> 0 then call select$disk(fcb(0)-1); end setdisk; getfile: procedure; /* process file request */ yte; /* status case # */ declare fstatlist(*) byte data('R/O',0,'R/W',0,'SYS',0,'DIR',0); setfilestatus: do while login <> 0; if low(login) then do; call select$disk(d); call comp$alloc; l address, /* used during sort and display */ k address, /* " */ m address, /* " */ extent counts */ fcbb(fcbmax) address, /* byte count (mod kb) */ fcbk(fcbmax) address, /* kilobyte count */ filestatus; printfn: procedure; declare (k, lb) byte; /* print file name */ do k = 1 to fn declare fnam literally '11', fext literally '12', fmod literally '14', frc literally '15', flnprocedure byte; /* eventually, scase set r/o=0,r/w=1,dat=2,sys=3 */ declare fstat(*) byte dat call printx(.('R/',0)); if low(rodisk) then call printchar('O'); else call kb byte, /* byte counter */ lb byte, /* byte counter */ mb byte, /* byte counter */ am; if (lb := fcbv(k) and 7fh) <> ' ' then do; if k = ftyp then call printchar('.'); ll print(.('** Too Many Files **',0)); i = 0; fcbn = 1; call multi16; end; bv(kb) then kb = fnam; else /* complete match if at end */ matched = kb = fnam; */ display: /* label for debug */ /* now display the collected data */ if fcbn = 0 then call print(.('File Not fmod) = '?'; /* question mark matches all */ call search(fcba); /* fill directory buffer */ collect: /* label for debu countbytes: /* label for debug */ lb = 1; if maxall > 255 then lb = 2; /* double precision inx */ call printchar(lb); end; end; end printfn; call set$bpb; /* in case default di /* save index to element for later sort */ finx(i) = i; do kb = 0 to fnam; end; i = i + 1; end; checkmatched: /* label for debug */ if matched then i = i - Found',0)); else if scase = 255 then /* display collected data */ do; /* sort the file names in ascendingg */ do while dcnt <> 255; /* another item found, compare it for common entry */ bfcba = shl(dcnt and do kb = fdm to fdl by lb; mb = bfcb(kb); if lb = 2 then /* double precision inx */ sk */ call setdisk; sizeset = false; scase = 255; if setfilestatus then do; if scase = 0 then retur fcbv(kb) = bfcb(kb); end; fcbe(i),fcbb(i),fcbk(i),fcbr(i) = 0; end; /* 1; else do; /* copy to new position in fcbs */ fcbn = (i := fcbn) + 1; call multi16; order */ if fcbn > 1 then /* requires at least two to sort */ do; l = 1; do while l > 0; 11b,5)+buffa; /* dcnt mod 4 * 32 */ matched = false; i = 0; do while not matched and i < fcbn; mb = mb or bfcb(kb+1); if mb <> 0 then /* allocated */ call add$block(.fcbk(in; scase = scase - 1; end; else if fcb(1) = ' ' then /* no file named */ do; call pralloc; entry is at, or was placed at location i in fcbs */ fcbe(i) = fcbe(i) + 1; /* extent incremented */ /* record /* fcbsa set to next to fill */ if (fcbn > fcbmax) or (fcbsa + 16) >= memsize then do; ca /* bubble sort */ l = 0; do m = 0 to fcbn - 2; i = finx(m+1); call m /* compare current entry */ call multi16; do kb = 1 to fnam; if bfcb(kb) <> fc),.fcbb(i)); end; call searchn; /* to next entry in directory */ end; /* of do while dcnt <> 255 return; end; /* read the directory, collect all common file names */ fcbn,fcb(0) = 0; fcb(fext),fcb(count */ fcbr(i) = fcbr(i) + bfcb(frc) + (bfcb(fext) and extmsk) * 128; /* count kilobytes */ulti16; bfcba = fcbsa; i = finx(m); call multi16; /* sets fcbsa, basing fcbv */ doelse call printchar('W'); call printb; call printchar('A'+cselect); call printchar(': call pdecimal(rrec,10000); call printb; end; call pdecimal(fcbr(i),10000)default fcb location */ call move(16,fcbsa,fcba); fcb(0) = 0; /* in case matched user# > 0 */ nt(.(' Size ',0)); else call crlf; call printx(.(' Recs Bytes Ext Acc',0)); l = 0; call multi16; call crlf; call printfn; do case scase; /* kb = 1 to fnam; /* compare for less or equal */ if (b:=bfcb(kb)) < (f:=fcbv(kb)) then /* switch */ '); /* print filename.typ */ if (mb:=rol(fcbv(infile),1)) then call printchar('('); call ; /* rrrrr */ call printb; /* blank */ call pdecimal(fcbk(i),10000); /* bbbbbk */ call p call setind; /* indicators set */ call printx(.(' set to ',0)); call printx(.fstatlist(shl(scase, do while l < fcbn; i = finx(l); /* i is the index to next in order */ call multi16; call crlf; set to r/o */ fcbv(rofile) = fcbv(rofile) or 80h; /* set to r/w */ fcbv(rofil do; k = finx(m); finx(m) = finx(m + 1); finx(m + 1) = k; l = l + 1; kb = printfn; if mb then call printchar(')'); l = l + 1; end; call pralloc; rintchar('k'); call printb; call pdecimal(fcbe(i),1000); /* eeee */ call printb; call p2))); l = l + 1; end; end; end getfile; setdrivestatus: procedure; /* handle pos /* print the file length */ call move(16,.fcbv(0),fcba); fcb(0) = 0; if sizeset the) = fcbv(rofile) and 7fh; /* set to sys */ fcbv(infile) = fcbv(infile) or 80h; fnam; end; else if b > f then kb = fnam; /* stop compare */ end; else setfileatt: /* label for debug */ /* set file attributes */ do; l = 0; do whirintchar('R'); call printchar('/'); if rol(fcbv(rofile),1) then call printchar('O'); sible drive status assignment */ call scan; /* remove drive name */ call scan; /* check for = */ if accum(0) = '=en do; call getfilesize(fcba); if rovf <> 0 then call printx(.('65536',0)); else /* set to dir */ fcbv(infile) = fcbv(infile) and 7fh; end; /* place name into end; end; end; end; if sizeset then call prile l < fcbn; if break then do; call abortmsg; return; end; i = l; ' then do; call scan; /* get assignment */ if compare(.('R/O ')) then do; call setdisk; /* a: ...ore exit */ stackptr = oldsp; end status; end; 0B 152 0710 153 071C 154 072A 155 0734 156 0740 157 075B 158 0761 160 0766 161 076F 162 076F 163 0772 164 0773 165 077D 169 07',0)); else do; /* size display if $S set in command */ ibp = 1; /* initialize buffer pointer */6C 82 056C 83 0575 84 0575 85 0575 86 057D 87 057E 88 057E 89 0589 90 058A 91 058A 92 0593 93 0593 94 0597 96 05A2 */ call writeprot; end; else call print(.('Invalid Disk Assignment',0)); end; 0000 STAT# 0000 STAT# 0433 16 0490 20 0494 22 049F 23 04A0 24 04A0 25 04A5 26 04AA 27 04AB 28 04AB 29 04B0 30 04B1 8C 170 0799 171 07A8 172 07B3 173 07B6 174 07B7 175 07BB 178 07C4 179 07C8 180 07DF 181 07E6 182 07F1 183 07F8 184 0801 185 0 if fcb(0) = 0 and fcb(1) = ' ' then /* stat only */ call prstatus; else do; if 97 05A3 98 05A9 100 05B2 101 05B3 105 05B3 106 05B6 107 05CB 108 05CC 109 05D0 111 05D7 112 05DA 113 05DB 114 05E1 116 05FEelse /* not a disk assignment */ do; call setdisk; if match(.devl,8) = 8 then call drive$status; else 31 04B7 34 04C0 35 04C7 36 04CE 37 04D1 38 04D2 39 04D8 41 04DB 42 04E3 43 04E4 44 04E4 45 04ED 46 04ED 48 04ED 4980E 186 0812 187 0812 188 0812 189 0818 190 0819 191 0819 195 081F 196 082B 197 0831 198 083F 199 084A 200 0851 201 0857 202 fcb(0) <> 0 then call setdrivestatus; else do; if not devreq then /* must be 117 05FE 119 0604 123 0612 124 062C 125 062F 126 0636 127 0639 128 0639 129 06EB 131 06EF 133 06FC 134 0700 135 0639 136 064 call getfile; end; end setdrivestatus; /* save stack pointer and reset */ oldsp = stackptr; stackptr = 04F6 50 04F6 51 04FA 53 0505 54 0506 55 050C 57 0518 58 0519 59 051F 61 052B 62 052C 63 052C 64 0537 65 0538 66 085D 203 0865 204 087F 205 088D 206 0890 207 0893 208 08A1 209 08AF 210 08BB 211 08C2 212 08C3 213 09C0 215 09C6 217 09C9 218file name */ call getfile; end; end; end; /* restore old stack bef8 137 064C 138 064F 139 0654 140 065C 141 0670 142 067A 143 067F 144 06D1 145 06DF 146 06E3 147 06E6 148 06EA 149 0701 150 07.stack(length(stack)); /* process request */ if version < cpmversion then call print(.('Wrong CP/M Version (Requires 2.0)0538 67 0541 68 0541 69 0547 71 0550 72 0551 73 0551 74 055A 75 055A 76 055A 77 0563 78 0563 79 0563 80 056B 81 05 09D4 219 09D9 220 09DC 221 08C3 222 08C9 223 08D2 224 08D7 225 08DD 226 08EC 227 091C 228 0925 229 092D 230 0933 231 093D 2329 0DB9 420 0DBA 421 135D 425 135D 426 136B 427 136C 430 136C 432 1374 433 1377 434 1387 435 139F 436 13A7 437 13B7 438 13BD 4C62 359 0C65 360 0C65 361 0C68 362 0C8F 363 0C95 365 0C9B 366 0CA0 367 0CAC 368 0CBA 369 0CC4 370 0CD0 371 0CEB 373 0CF0 374 11DB 561 11E6 562 11E9 563 11E9 564 11FA 565 11FD 566 120E 567 1213 568 1216 569 1227 570 122A 571 122F 572 1234 573 1241 574 297 0ABA 298 0ABF 299 0ACB 300 0ADC 301 0AE2 302 0AF9 303 0B01 304 0B0B 305 0B0E 306 0B15 307 0B18 308 0B20 310 0B26 311 0B2C0 501 0F79 502 0FB9 503 0FBE 504 0FCD 505 0FD2 506 0FF1 507 0FFF 508 1007 509 101C 510 1024 511 103A 512 103D 513 1040 514 10 0943 233 0951 234 0957 235 0969 236 096F 237 0986 238 098C 239 0994 240 099A 241 09A3 242 09A9 243 09B6 244 09BC 245 09BF 2439 13C0 440 13C0 441 13C0 443 13CE 444 13E3 446 13EB 447 13F0 448 13F7 449 13F7 450 1401 451 0DBA 452 0DBD 453 0DC0 454 0DC5 40CF9 375 0CF9 376 0CFC 377 0D01 378 0D04 379 0D05 380 0D05 381 0D0B 382 0D14 383 0D1A 384 0D1B 385 0D1B 386 0D25 387 0D26 388 1249 575 124E 576 1251 577 125A 578 125F 579 126F 580 1274 581 1277 582 127E 583 1283 584 128A 585 128D 586 1290 587 1293 588 312 0B32 313 0B38 314 0B3E 315 0B4C 316 0B4F 317 0B60 318 0B66 319 0B85 320 0B8A 321 0BA1 322 0BA4 323 0BAB 324 0BAE 325 0BB43 515 104F 516 1058 517 1060 519 106B 521 1071 522 107C 523 1082 524 1097 525 10A6 526 10A9 527 10AF 528 10BE 529 10C1 530 106 09DD 247 09DD 249 09E3 250 09E8 251 09F4 252 09FC 254 0A03 255 0A06 256 0A06 257 0A13 258 0A15 259 0A18 260 0A19 261 0A21 255 0DCA 456 0DD1 458 0DD9 459 0DDA 460 0DE1 461 0DE4 462 0DEC 464 0DEF 465 0DF0 466 0DF0 467 0DFA 468 0E04 469 0E0A 470 0E12 0D26 389 0D2C 390 0D2F 391 0D32 392 0D33 393 0D33 396 0D39 397 0D3F 398 0D44 399 0D50 400 0D58 402 0D5F 403 0D62 404 0D68 405 1293 589 1299 590 12A5 591 12AC 593 12AF 594 12B0 595 12B0 596 12B6 597 12B9 598 12BC 599 12BF 600 12CF 601 12E1 602 12F3 606 327 0BB9 328 0BBC 329 0BBF 330 0BC7 331 0BCD 333 0BDB 334 0BDE 335 0BE6 337 0BEC 338 0BEF 339 0BEF 340 0BF2 341 0C0B 343 0CCF 531 10F3 533 1102 534 111B 535 112C 536 1133 537 1138 538 113B 539 1145 540 114A 541 1154 542 1161 543 1164 544 1164 545 164 0A2B 265 0A37 266 0A3C 267 0A4A 268 0A64 269 0A69 270 0A6D 271 0A72 272 0A79 273 0A7D 274 0A84 275 0A87 276 0A87 278 0C69 471 0E24 472 0E29 473 0E2F 474 0E45 475 0E48 476 0E56 477 0E71 478 0E79 479 0E84 480 0E8E 481 0E95 482 0E98 483 0E9F 484 0EA9 0D70 406 0D78 407 0D7D 408 0D83 409 0D86 410 0D86 411 0D93 412 0DA0 413 0DA2 414 0DA5 415 0DA8 416 0DA9 417 0DA9 418 0DB1 413 1305 604 1317 605 131F 606 1333 607 1338 608 133B 609 1341 610 1352 611 1359 612 135C 613 135C 614 1402 615 1402 616 1405 611 344 0C14 345 0C14 346 0C19 347 0C25 348 0C2D 349 0C35 350 0C38 351 0C46 352 0C46 353 0C49 354 0C51 355 0C54 356 0C5C 358 016B 546 1174 547 1177 548 117D 549 1183 550 118F 551 119E 552 11A1 553 11A4 554 11B8 555 11BD 556 11C4 558 11CA 559 11D2 560 281 0C6F 283 0C78 284 0C7F 285 0C86 286 0C89 287 0C8E 288 0A87 289 0A8C 290 0A8C 291 0A8F 292 0A9F 293 0AA8 294 0AAC 295 0AB4 486 0EB3 487 0EB6 488 0ED8 490 0EDE 491 0EE4 492 0EEA 493 0EED 494 0EED 495 0EFE 496 0F0C 497 0F24 498 0F2E 499 0F60 500 0F617 1408 618 1410 620 1413 621 141D 623 1420 624 1423 625 1426 626 142C 627 142F 629 1432 630 143F 631 1445 632 1448 633 1448 ke" single: ds byte ;set true if single byte allocation map resel: ds byte ;reselection flag olddsk: ds byte ;disk on entry t********************************* ; jmp ccpstart ;start ccp with possible initial command jmp ccpclear ;clear the command b program xsubcon: db 'xsub' end 634 0433 635 043A 636 043E 637 0446 638 044F 640 0454 641 046C 642 0472 644 047A 645 0480 647 0488 648 048B 649 048B 650 048Bo bdos fcbdsk: ds byte ;disk named in fcb rcount: ds byte ;record count in current fcb extval: ds byte ;extent number and exts word ;address of translate vector fcb$copied: ds byte ;set true if copy$fcb called rmf: ds byte ;read mode flag for open$ruffer maxlen: db 127 ;max buffer length comlen: db 0 ;command length (filled in by dos) ; (command executed initially if coml * at ccp+8, with the command length at ccp+7. In this * ; * case, the ccp executes the command before prompting * ; * the c 651 048B 652 048F 653 0000 MODULE# msk vrecord:ds word ;current virtual record arecord:ds word ;current actual record arecord1: ds word ;current actual block# *eel dirloc: ds byte ;directory flag in rename, etc. seqio: ds byte ;1 if sequential i/o linfo: ds byte ;low(info) dminx: ds en non zero) combuf: db ' ' ;8 character fill db ' ' ;8 character fill db 'COPYRIGHT (C) 1979, DIGITAL RESEonsole for input. Note that the command is exe-* ; * cuted on both warm and cold starts. When the command* ; * line is initi blkmsk ; ; local variables for directory access dptr: ds byte ;directory pointer 0,1,2,3 dcnt: ds word ;directory counter 0byte ;local for diskwrite searchl:ds byte ;search length searcha:ds word ;search address tinfo: ds word ;temp for info in "maARCH '; 38 ds 128-($-combuf) ; total buffer length is 128 characters comaddr:dw combuf ;address of next to char to scan stalized, a jump to "jmp ccpclear" dis- * ; * ables the automatic command execution. * ; ***********************,1,...,dirmax drec: ds word ;directory record 0,1,...,dirmax/4 ; bios equ ($ and 0ff00h)+100h ;next module end addr: ds 2 ;starting address of current fillfcb request ; diska equ 0004h ;disk address for current disk bdos equ 0005h ;primy for next call printchar! pop h ;character printed jmp prin0 ;for another character ; initialize: mvi c,initf! jmp bdeturn lf equ 10 ;line feed la equ 5fh ;left arrow eofile equ 1ah ;end of file ; ; utility procedures printchar: mov e,a!le given by d,e mvi c,renf! jmp bdos ; getuser: ;return current user code in a mvi e,0ffh ;drop through to setuser ; snction searnf equ 18 ;search for next file function delf equ 19 ;delete file function dreadf equ 20 ;disk read function dwriom: ;search for comfcb file lxi d,comfcb! jmp search ; delete: ;delete the file given by d,e mvi c,delf! jmp bdos ; bdary bdos entry point buff equ 0080h ;default buffer fcb equ 005ch ;default file control block ; rcharf equ 1 ;read characteros ; select: mov e,a! mvi c,self! jmp bdos ; bdos$inr: call bdos! sta dcnt! inr a! ret ; open: ;open the file given by mvi c,pcharf! jmp bdos ; printbc: ;print character, but save b,c registers push b! call printchar! pop b! ret ; crlf: etuser: mvi c,userf! jmp bdos ;sets user number ; saveuser: ;save user#/disk# before possible ^c or transient caltf equ 21 ;disk write function makef equ 22 ;file make function renf equ 23 ;rename file function logf equ 24 ;return login vos$cond: call bdos! ora a! ret ; diskread: ;read the next record from the file given by d,e mvi c,dreadf! jmp bdos$cond function pcharf equ 2 ;print character function pbuff equ 9 ;print buffer function rbuff equ 10 ;read buffer function break d,e mvi c,openf! jmp bdos$inr ; openc: ;open comfcb xra a! sta comrec ;clear next record to read lxi d,comfcb! jmp open mvi a,cr! call printbc mvi a,lf! jmp printbc ; blank: mvi a,' '! jmp printbc ; print: ;print string starting at b,c unl getuser ;code to a add a! add a! add a! add a ;rot left lxi h,cdisk! ora m ;4b=user, 4b=disk sta diska ;stored away in mector cself equ 25 ;return currently selected drive number dmaf equ 26 ;set dma address userf equ 32 ;set user number ; ; s ; diskreadc: ;read the comfcb file lxi d,comfcb! jmp diskread ; diskwrite: ;write the next record to the file given byf equ 11 ;break key function liftf equ 12 ;lift head function (no operation) initf equ 13 ;initialize bdos function self equ ; close: ;close the file given by d,e mvi c,closef! jmp bdos$inr ; search: ;search for the file given by d,e mvi c,seartil next 00 entry push b! call crlf! pop h ;now print the string prin0: mov a,m! ora a! rz ;stop on 00 inx h! push h ;reademory for later ret ; setdiska: lda cdisk! sta diska ;user/disk ret ; translate: ;translate character in register A pecial fcb flags rofile equ 9 ;read only file sysfile equ 10 ;system file flag ; ; special characters cr equ 13 ;carriage r d,e mvi c,dwritf! jmp bdos$cond ; make: ;create the file given by d,e mvi c,makef! jmp bdos$inr ; renam: ;rename the fi14 ;select disk function openf equ 15 ;open file function closef equ 16 ;close file function searf equ 17 ;search for file fuf! jmp bdos$inr ; searchn: ;search for the next occurrence of the file given by d,e mvi c,searnf! jmp bdos$inr ; searchcto upper case cpi 61h! rc ;return if below lower case a cpi 7bh! rnc ;return if above lower case z ani 5fh! ret ;translate end of command mov m,a ;store a zero lxi h,combuf! shld comaddr ;ready to scan to zero ret ; break$key: ;check for all del$sub ;translate to upper case, store zero at end call saveuser ;user # save in case control c mvi c,rbuff! lxi d,ma: ;print characters until blank or zero mov a,m! cpi ' '! jz comerr1; not blank ora a! jz comerr1; not zero, so print it ;disk read is ok, transfer to combuf lxi d,comlen! lxi h,buff! mvi b,128! call move0 ;line is transferred, close theet to false xra a! call select ;on drive a to erase file lxi d,subfcb! call delete lda cdisk! jmp select ;back to originald to upper case ; readcom: ;read the next command into the command buffer ;check for submit file lda submit! ora a! jz na character ready at the console mvi c,breakf! call bdos ora a! rz mvi c,rcharf! call bdos ;character cleared ora a! retxlen! call bdos call setdiska ;no control c, so restore diska noread: ;enter here from submit file ;set the last character push h! call printchar! pop h! inx h jmp comerr0; for another character comerr1: ;print question mark,and delete sub file file with a ;deleted record lxi h,submod! mvi m,0 ;clear fwflag inx h! dcr m ;one less record lxi d,subfcb! cal drive ; serialize: ;check serialization lxi d,serial! lxi h,bdosl! mvi b,6 ;check six bytes ser0: ldax d! cmp m! jnz baosub ;scanning a submit file ;change drives to open and read the file lda cdisk! ora a! mvi a,0! cnz select ;have to ; cselect: ;get the currently selected drive number to reg-A mvi c,cself! jmp bdos ; setdmabuff: ;set default buffer to zero for later scans lxi h,comlen! mov b,m ;length is in b readcom0: inx h! mov a,b! ora a ;end of scan? jz readcom1! mvi a,'?'! call printchar call crlf! call del$sub jmp ccp ;restart with next command ; ; fcb scan and fill subroutinl close! jz nosub ;close went ok, return to original drive lda cdisk! ora a! cnz select ;print to the 00 lxi h,cdserial inx d! inx h! dcr b! jnz ser0 ret ;serial number is ok ; comerr: ;error in command string starting at position open again in case xsub present lxi d,subfcb! call open! jz nosub ;skip if no sub lda subrc! dcr a ;read ladma address lxi d,buff ;(drop through) ; setdma: ;set dma address to d,e mvi c,dmaf! jmp bdos ; del$sub: ;delete the mov a,m ;get character and translate call translate! mov m,a! dcr b! jmp readcom0 ; readcom1: ;end of scan, h,l addresse (entry is at fillfcb below) ;fill the comfcb, indexed by A (0 or 16) ;subroutines delim: ;look for a delimiter ldax dombuf! call prin0 call break$key! jz noread call del$sub! jmp ccp ;break key depressed ; nosub: ;no submit file! c ;'staddr' and ending with first delimiter call crlf ;space to next line lhld staddr ;h,l address first to print comerr0st record(s) first sta subcr ;current record to read lxi d,subfcb! call diskread ;end of file if last record jnz nosub submit file, and set submit flag to false lxi h,submit! mov a,m! ora a! rz ;return if no sub file mvi m,0 ;submit flag is s! ora a! rz ;not the last element cpi ' '! jc comerr ;non graphic rz ;treat blank as delimiter cpi '='! rz cpi la! if delimiter inx d! jmp trname ; padname: inx h! mvi m,' '! dcr b! jnz padname ; setty: ;set the type field mvi;set disk to name in register b mov a,b! sta sdisk ;mark as disk selected mov m,b! inx d ;past the : ; setname: ;set tnd return with flags set mov a,b! ora a! ret ; intvec: ;intrinsic function names (all are four characters) db 'DIR ' command address in d,e call deblank ;to first non-blank character xchg! shld staddr ;in case of errors xchg! pop h ;d,e hatype field with blanks inx h! mvi m,' '! dcr b! jnz padty ; efill: ;end of the filename/filetype fill, save command addrz ;left arrow cpi '.'! rz cpi ':'! rz cpi ';'! rz cpi '<'! rz cpi '>'! rz ret ;delimiter not found ; debla b,3! cpi '.'! jnz padty ;skip the type field if no . inx d ;past the ., to the file type field setty0: ;set the field frohe file name field mvi b,8 ;file name length (max) setnam0: call delim! jz padname ;not a delimiter inx h! cpi '*'! jndb 'ERA ' db 'TYPE' db 'SAVE' db 'REN ' db 'USER' intlen equ ($-intvec)/4 ;intrinsic function length sers command, h,l has fcb address ;look for preceding file name A: B: ... ldax d! ora a! jz setcur0 ;use current disk if empty ress ;fill the remaining fields for the fcb mvi b,3 efill0: inx h! mvi m,0! dcr b! jnz efill0 xchg! shld comaddr ;senk: ;deblank the input line ldax d! ora a! rz ;treat end of line as blank cpi ' '! rnz! inx d! jmp deblank ; addh: ;addm the command buffer call delim! jz padty! inx h! cpi '*'! jnz setty1 mvi m,'?' ;since * specified! jmp setty2 ; z setnam1 ;must be ?'s mvi m,'?'! jmp setnam2 ;to dec count ; setnam1: mov m,a ;store character to fcb! inx d setnaial: db 0,0,0,0,0,0 ; ; intrinsic: ;look for intrinsic functions (comfcb has been filled) lxi h,intvec! mvi c,0 ;c countscommand sbi 'A'-1! mov b,a ;disk name held in b if : follows inx d! ldax d! cpi ':'! jz setdsk ;set disk name if : ; sett new starting point ; ;recover the start address of the fcb and count ?'s pop h! lxi b,11 ;b=0, c=8+3 scnq: inx h! a to h,l add l! mov l,a! rnc inr h! ret ; fillfcb0: ;equivalent to fillfcb(0) mvi a,0 ; fillfcb: lxi h,comfcbsetty1: ;not a *, so copy to type field mov m,a! inx d setty2: ;decrement count and go again dcr b! jnz setty0 ; m2: dcr b ;count down length! jnz setnam0 ; ;end of name, truncate remainder trname: call delim! jz setty ;set type field intrinsics as scanned intrin0: mov a,c! cpi intlen ;done with scan?! rnc ;no, more to scan lxi d,comfcb+1 ;beginning ofcur: ;set current disk dcx d ;back to first character of command setcur0: lda cdisk! mov m,a! jmp setname ; setdsk: mov a,m! cpi '?'! jnz scnq0 ;? found, count it in b! inr b scnq0: dcr c! jnz scnq ; ;number of ?'s in c, move to a a! call addh! push h! push h ;fcb rescanned at end xra a! sta sdisk ;clear selected disk (in case A:...) lhld comaddr! xchg ; ;end of type field, truncate trtyp: ;truncate type field call delim! jz efill! inx d! jmp trtyp ; padty: ;pad the name mvi b,4 ;length of match is in b intrin1: ldax d! cmp m ;match? jnz intrin2 ;skip if no match inx d! inx h! ! sta cdisk ;current disk number saved call fillfcb0 ;command fcb filled cnz comerr ;the name cannot be an ambiguous referen ;proper disk is selected, now check sub files ;check for initial command lda comlen! ora a! jnz ccp0 ;assume typed already lxi b,11 ;(b=0, c=11) ;value accumulated in b, c counts name length to zero conv0: mov a,m! cpi ' '! jz conv1 ;more toloader lxi sp,stack! push b ;save initial disk number ;(high order 4bits=user code, low 4bits=disk#) mov a,c! rar! xi h,di or (hlt shl 8) shld ccploc! lxi h,ccploc! pchl ; ; ;utility subroutines for intrinsic handlers readerr: dcr b jnz intrin1 ;loop while matching ; ;complete match on name, check for blank in fcb ldax d! cpi ' '! jnz intrice lda sdisk! ora a! jnz userfunc ;check for an intrinsic function call intrinsic lxi h,jmptab ;index is in the accum ; ccp: ;enter here on each command or error condition lxi sp,stack call crlf ;print d> prompt, where d is disk name ca scan, convert char to binary and add inx h! sui '0'! cpi 10! jnc comerr ;valid? mov d,a ;save value! mov a,b ;mult by 1rar! rar! rar! ani 0fh ;user code mov e,a! call setuser ;user code selected ;initialize for this user, get $ flag c;print the read error message lxi b,rdmsg! jmp print rdmsg: db 'READ ERROR',0 ; nofile: ;print no file message ln3 ;otherwise matched mov a,c! ret ;with intrinsic number in a ; intrin2: ;mismatch, move to end of intrinsic inx hulator mov e,a! mvi d,0! dad d! dad d ;index in d,e mov a,m! inx h! mov h,m! mov l,a! pchl ;pc changes to the proper inll cselect ;get current disk number adi 'A'! call printchar mvi a,'>'! call printchar call readcom ;command buffer filled 0 ani 1110$0000b! jnz comerr mov a,b ;recover value rlc! rlc! rlc ;*8 add b! jc comerr add b! jc comerr ;*8+all initialize ;0ffh in accum if $ file present sta submit ;submit flag set if $ file present pop b ;recall usxi b,nofmsg! jmp print nofmsg: db 'NO FILE',0 ; getnumber: ;read a number from the command line call fillfcb0 ;should ! dcr b! jnz intrin2 ; intrin3: ;try next intrinsic inr c ;to next intrinsic number jmp intrin0 ;for another roundtrinsic or user function jmptab: dw direct ;directory search dw erase ;file erase dw type ;type file dw save ccp0: ;(enter here from initialization with command full) lxi d,buff! call setdma ;default dma address at buff call cselect*2 = *10 add d! jc comerr ;+digit mov b,a! dcr c! jnz conv0 ;for another digit ret conv1: ;end of digits, check fer code and disk number mov a,c! ani 0fh ;disk number in accumulator sta cdisk ;clears user code nibble call selectbe number lda sdisk! ora a! jnz comerr ;cannot be prefixed ;convert the byte value in comfcb to binary lxi h,comfcb+1! ; ccpclear: ;clear the command buffer xra a sta comlen ;drop through to start ccp ccpstart: ;enter here from boot ;save memory image dw rename ;file rename dw user ;user number dw userfunc;user-defined function badserial: lor all blanks mov a,m! cpi ' '! jnz comerr ;blanks? inx h! dcr c! jnz conv1 mov a,b ;recover value! ret ; movene! push d ;e=0,1,2,3,...new line if mod 4 = 0 ani 11b! push psw ;and save the test jnz dirhdr0 ;header on current linelank request, must be in comfcb dir1: mvi e,0! push d ;E counts directory entries call searchcom ;first one has been found r (mod 4) dir6: call break$key ;check for interrupt at keyboard jnz endir ;abort directory search call searchn! jmp dir2mand lda sdisk! ora a! rz ;no action if not selected dcr a! lxi h,cdisk! cmp m! rz ;same disk lda cdisk! jmp select ; ;may be 3rd item cpi 3! jnz dirb ;place blank at end if not mvi a,9! call addhcf ;first char of type ani 7fh! cpi ' ame: ;move 3 characters from h,l to d,e addresses mvi b,3 move0: mov a,m! stax d! inx h! inx d dcr b! jnz move0 call crlf push b! call cselect! pop b ;current disk in A adi 'A'! call printbc mvi a,':'! call printbc cz nofile ;not found message dir2: jz endir ;found, but may be system file lda dcnt ;get the location of the element ;for another entry endir: ;end of directory scan pop d ;discard directory counter jmp retcom ; ; erase: call fillf ;individual intrinsics follow direct: ;directory search call fillfcb0 ;comfcb gets file name call setdisk ;change disk '! jz dir5 ;not a blank in the file type field dirb: mvi a,' ' ;restore trailing filename chr dir4: call printbc ;ret ; addhcf: ;buff + a + c to h,l followed by fetch lxi h,buff! add c! call addh! mov a,m! ret ; setdisk: ;changejmp dirhdr1 ;skip current line hdr dirhdr0:call blank ;after last one mvi a,':'! call printbc dirhdr1: call blank rrc! rrc! rrc! ani 110$0000b! mov c,a ;c contains base index into buff for dir entry mvi a,sysfile! call addhcf ;value cb0 ;cannot be all ???'s cpi 11 jnz erasefile ;erasing all of the disk lxi b,ermsg! call print! call readcom lxidrives if requested lxi h,comfcb+1! mov a,m ;may be empty request cpi ' '! jnz dir1 ;skip fill of ??? if not blank ;set cchar printed inr b! mov a,b! cpi 12! jnc dir5 ;check for break between names cpi 9! jnz dir3 ;for another char ; disks for this command, if requested xra a! sta comfcb ;clear disk name from fcb lda sdisk! ora a! rz ;no action if not s ;compute position of name in buffer mvi b,1 ;start with first character of name dir3: mov a,b! call addhcf ;buff+a+c feto A ral! jc dir6 ;skip if system file ;c holds index into buffer ;another fcb found, new line? pop d! mov a,e! inr h,comlen! dcr m! jnz ccp ;bad input inx h! mov a,m! cpi 'Y'! jnz ccp ;ok, erase the entire diskette inx h! shld comaddomfcb to all ??? for current disk mvi b,11 ;length of fill ????????.??? dir0: mvi m,'?'! inx h! dcr b! jnz dir0 ;not a bprint a blank between names call blank! jmp dir3 ; dir5: ;end of current entry pop psw ;discard the directory countepecified dcr a! lxi h,cdisk! cmp m! rz ;already selected jmp select ; resetdisk: ;return to original disk after comtched ani 7fh ;mask flags ;may delete trailing blanks cpi ' '! jnz dir4 ;check for blank type pop psw! push psw r ;otherwise error at retcom erasefile: call setdisk lxi d,comfcb! call delete inr a ;255 returned if not found czunt zero mov a,h! ora l! jz save1 ;may be completed dcx h ;sector count = sector count - 1 push h ;save it for next timer ; ;should be followed by a file to save the memory image call fillfcb0 jnz comerr ;cannot be ambiguous call se! inx h! shld comaddr ;past delimiter ;proper delimiter found call fillfcb0! jnz renerr2 ;check for drive conflict nz typeof ;hard end of file xra a! mov m,a ;bptr = 0 type1: ;read character at bptr and print inr m ;bptr = bptr + 1 jmp retcom fullmsg: db 'NO SPACE',0 ; ; rename: ;rename a file on a specific disk call fillfcb0! jnz comerr ;must be nofile ;no file message if so jmp retcom ; ermsg: db 'ALL (Y/N)?',0 ; type: call fillfcb0! jnz comerr ;don't allow ?'e around lxi h,128! dad d! push h ;next dma address saved call setdma ;current dma address set lxi d,comfcb! call diskwtdisk ;may be a disk change lxi d,comfcb! push d! call delete ;existing file removed pop d! call make ;create a new file opop psw! mov b,a ;previous drive number lxi h,sdisk! mov a,m! ora a! jz ren2 ;drive name was specified. same one? c lxi h,buff! call addh ;h,l addresses char mov a,m! cpi eofile! jz retcom call printchar call break$key! jnz retc unambiguous lda sdisk! push psw ;save for later compare call setdisk ;disk selected call searchcom ;is new name already ts in file name call setdisk! call openc ;open the file jz typerr ;zero flag indicates not found ;file opened, read 'til erite pop d! pop h ;dma address, sector count jnz saverr ;may be disk full case jmp save0 ;for another sector ; savn disk jz saverr ;no directory space xra a! sta comrec; clear next record field pop psw ;#pages to write is in a, changmp b! mov m,b! jnz renerr2 ren2: mov m,b ;store the name in case drives switched xra a! sta comfcb! call searchcom ;is old om ;abort if break jmp type0 ;for another character ; typeof: ;end of file, check for errors dcr a! jz retcom here? jnz renerr3 ;file doesn't exist, move to second half of fcb lxi h,comfcb! lxi d,comfcb+16! mvi b,16! call move0 of call crlf! lxi h,bptr! mvi m,255 ;read first buffer type0: ;loop on bptr lxi h,bptr! mov a,m! cpi 128 ;end buffer e1: ;end of dump, close the file lxi d,comfcb! call close inr a; 255 becomes 00 if error jnz retsave ;for another commae to #sectors mov l,a! mvi h,0! dad h! lxi d,tran ;h,l is sector count, d,e is load address save0: ;check for sector cofile there? jz renerr1 ; ;everything is ok, rename the file lxi d,comfcb! call renam jmp retcom ; renerr1:; call readerr typerr: call resetdisk! jmp comerr ; save: call getnumber; value to register a push psw ;save it for lat ;check for = or left arrow lhld comaddr! xchg! call deblank cpi '='! jz ren1 ;ok if = cpi la! jnz renerr2 ren1: xchg jc type1! push h ;carry if 0,1,...,127 ;read another buffer full call diskreadc! pop h ;recover address of bptr jnd saverr: ;must be full or read only disk lxi b,fullmsg! call print retsave: ;reset dma buffer call setdmabuff no file on disk call nofile! jmp retcom renerr2:; ambigous reference/name conflict call resetdisk! jmp comerr renerr3:umber set to zero lxi d,fcb! lxi h,comfcb! mvi b,33! call move0 ;move command line to buff lxi h,combuf bmove0: mnz load1 ;sector loaded, set new dma address and compare pop h! lxi d,128! dad d lxi d,tranm ;has the load overfloweh lda sdisk! ora a! jz endcom ;no disk name if 0 dcr a! sta cdisk! call setdiska ;set user/disk call select! jmp endcomaded program lxi sp,stack ;may come back here call setdiska! call select jmp ccp ; userer: ;arrive here on com; file already exists lxi b,renmsg! call print! jmp retcom renmsg: db 'FILE EXISTS',0 ; user: ;set user number call ov a,m! ora a! jz bmove1! cpi ' '! jz bmove1 inx h! jmp bmove0 ;for another scan ;first blank position found bmove1: d? mov a,l! sub e! mov a,h! sbb d! jnc loaderr jmp load0 ;for another sector ; load1: pop h! dcr a! jnz loaderr ; user0: ;file name is present lxi d,comfcb+9! ldax d! cpi ' '! jnz comerr ;type ' ' push d! call setdisk! pop d! lxi h,cmand error call resetdisk! jmp comerr ; loaderr:;cannot load the program lxi b,loadmsg! call print jmp retcomgetnumber; leaves the value in the accumulator cpi 16! jnc comerr; must be between 0 and 15 mov e,a ;save for setuser call mvi b,0! lxi d,buff+1! ;ready for the move bmove2: mov a,m! stax d! ora a! jz bmove3 ;more to move inr b! inx h! inx end file is 1 call resetdisk ;back to original disk call fillfcb0! lxi h,sdisk! push h mov a,m! sta comfcb ;drive nuomtype ;.com call movename ;file type is set to .com call openc! jz userer ;file opened properly, read it into memory lda comfcb+1! cpi ' '! jz comerr call setuser ;new user number set jmp endcom ; userfunc: call serialize ;check serialid! jmp bmove2 bmove3: ;b has character count mov a,b! sta buff call crlf ;now go to the loaded program call smber set mvi a,16! call fillfcb ;move entire fcb to memory pop h! mov a,m! sta comfcb+16 xra a! sta comrec ;record n lxi h,tran ;transient program base load0: push h ;save dma address xchg! call setdma lxi d,comfcb! call diskread! jzation ;load user function and set up for execution lda comfcb+1! cpi ' '! jnz user0 ;no file name, but may be disk switcetdmabuff ;default dma call saveuser ;user code saved ;low memory diska contains user code call tran ;gone to the lo