home *** CD-ROM | disk | FTP | other *** search
-
- ;
- ; CCC.ASM (C.CCC) v1.45 11/22/81
- ;
- ; NOTE: If you are running under MP/M II, be sure to set the MPM2
- ; equate to 1.
- ;
- ; This is the BDS C run-time package. Normally, it resides at
- ; the start of the TPA (at address BASE+100h, where BASE is either
- ; 0000h or 4200h depending on CP/M implementation.) The code
- ; generated by the compiler ALWAYS sits immediately after the end of
- ; this run-time package code.
- ;
- ; Equate statements in CAPITAL letters may be customized by the
- ; user in order to change a) the origin of the run-time package,
- ; and b) the origin of the run-time RAM area. If you will be
- ; generating code to run in a non-CP/M environment, set the CPM
- ; equate to zero and make sure to set the ORIGIN, RAM and
- ; EXITAD equates to fit your custom run-time configuration.
- ;
- ; The "lxi sp,0" instruction at the start is replaced by the sequence:
- ;
- ; lhld base+6
- ; sphl
- ;
- ; by CLINK at link time, unless the -t option is used with CLINK,
- ; in which case the "lxi sp" remains there and the value used to
- ; initialize the SP is the argument given to the "-t" option.
- ;
-
- page 76
- title 'BDS C Run-Time Module (c.ccc) v1.45 11/22/81'
-
-
- CPM: EQU 1 ;True if to be run under CP/M or MP/M
-
- MPM2: EQU 0 ;True ONLY if running under MP/M II
-
- DMAVIO: EQU 1 ;True if using DMA video library routines and
- ;need parameters initialized
- IF CPM
- base: equ 0 ;start of ram in system (either 0 or 4200h for CP/M)
- bdos: equ base+5 ;rest of these used by CP/M-based configurations.
- tpa: equ base+100h
- nfcbs: equ 8 ;maximum # of files open at one time
- tbuff: equ base+80h
- origin: equ tpa
- exitad: equ base ;warm boot location
- ENDIF
-
- IF NOT CPM ;fill in the appropriate values...
- ORIGIN: EQU NEWBASE ;Address at which programs are to run
- RAM: EQU WHATEVER ;Read-write memory area for non-CP/M configurations
- ; (defaults to immediately after C.CCC under CP/M)
- EXITAD: EQU WHENDONE ;where to go when done executing
- ENDIF
-
- ;
- ; The location of the jump vectors and utility routines must remain
- ; constant relative to the beginning of this run-time module.
- ;
- ; Do NOT change ANYTHING between here and the start of the
- ; "init" routine!!!!!!!!
- ;
-
- org origin
- lxi sp,0 ;this is changed by CLINK to lhld base+5h
- nop ;this first is usually turned into sphl by CLINK
-
- nop! nop ;Simple initialization or patches may be
- nop! nop! nop ;inserted here, but better to do all that
- nop! nop! nop ;in the "init" routine
-
- call init ;do ARGC & ARGV processing, plus misc. initializations
- call main ;go crunch!!!!
- jmp vexit ;close open files and reboot
-
- extrns: ds 2 ;set by CLINK to external data base address
- cccsiz: dw main-origin ;size of this code (for use by CLINK)
- codend: ds 2 ;set by CLINK to (last addr of code + 1)
- freram: ds 2 ;set by CLINK to (last addr of externals + 1)
-
- ;
- ; Jump vectors to some file i/o utility routines:
- ;
-
- error: jmp verror ;loads -1 into HL and returns
- exit: jmp vexit ;close all open files and reboot
-
- IF CPM
- close: jmp vclose ;close a file
- setfcb: jmp vsetfcb ;set up fcb at HL given filename at DE
- fgfd: jmp vfgfd ;return C set if file fd in A not open
- fgfcb: jmp vfgfcb ;compute address of internal fcb for fd in A
- ENDIF
-
- IF NOT CPM ;if not under CP/M, file I/O routines
- close: jmp verror ;are not used.
- setfcb: jmp verror
- fgfd: jmp verror
- fgfcb: jmp verror
- ENDIF
-
- ds 16 ;reserved
-
- IF CPM
- setfcb3: mov m,a ;this is a patch from the "vsetfcb" routine,
- inx h ;which causes the random record bytes of the
- mov m,a ;fcb being initialized to be zeroed. (Former
- inx h ;versions had a "ds 30" above, so this keeps
- mov m,a ;all the addresses consistent between this
- pop d ;and earlier 1.4's)
- pop b
- ret
-
- patchnm: call setnm ;another patch from "vsetfcb"
- jmp setnm3
- ENDIF
-
- IF NOT CPM
- ds 14 ;keep addresses the same for non-CP/M implementations
- ENDIF
-
- ;
- ; The following routines fetch a variable value from either
- ; the local stack frame or the external area, given the relative
- ; offset of the datum required immediately following the call;
- ; for the "long displacement" routines, the offset must be 16 bits,
- ; for the "short displacement" routines, the offset must be 8 bits.
- ;
-
- ;
- ; long-displacement, double-byte external indirection:
- ;
- ; format: call ldei ; get 16-bit value in HL
- ; dw offset_from_extrns ; >= 256
- ;
-
- ldei: pop h ;get address of offset
- mov e,m ;put offset in DE
- inx h
- mov d,m
- inx h
- push h ;save return address
- lhld extrns ;add offset to external area base
- dad d
- mov a,m ;and get the value into HL
- inx h
- mov h,m
- mov l,a
- ret
-
- ;
- ; short-displacement, double-byte external indirection:
- ;
- ; format: call sdei ; get 16-bit value in L
- ; db offset_from_extrns ; < 256
- ;
-
- sdei: pop h
- mov e,m
- inx h
- push h
- mvi d,0
- lhld extrns
- dad d
- mov a,m
- inx h
- mov h,m
- mov l,a
- ret
-
- ;
- ; long-displacement, single-byte external indirection:
- ;
- ; format: call lsei ; get 8-bit value in L
- ; dw offset_from_extrns ; >= 256
- ;
-
- lsei: pop h
- mov e,m
- inx h
- mov d,m
- inx h
- push h
- lhld extrns
- dad d
- mov l,m
- ret
-
- ;
- ; short-displacement, single-byte external indirection:
- ;
- ; format: call ssei ; get 8-bit value in L
- ; db offset_from_externs ; < 256
- ;
-
- ssei: pop h
- mov e,m
- inx h
- push h
- mvi d,0
- lhld extrns
- dad d
- mov l,m
- ret
-
- ;
- ; long-displacement, double-byte local indirection:
- ;
- ; format: call ldli ; get 16-bit value in HL
- ; dw offset_from_BC ; >= 256
- ;
-
- ldli: pop h
- mov e,m
- inx h
- mov d,m
- inx h
- push h
- xchg
- dad b
- mov a,m
- inx h
- mov h,m
- mov l,a
- ret
-
- ;
- ; short-displacement, double-byte local indirection:
- ;
- ; format: call sdli ; get 16-bit value in HL
- ; db offset_from_BC ; < 256
- ;
-
- sdli: pop h
- mov e,m
- inx h
- push h
- xchg
- mvi h,0
- dad b
- mov a,m
- inx h
- mov h,m
- mov l,a
- ret
-
- ;
- ; Flag conversion routines:
- ;
-
- pzinh: lxi h,1 ;return HL = true if Z set
- rz
- dcx h
- ret
-
- pnzinh: lxi h,0 ;return HL = false if Z set
- rz
- inx h
- ret
-
- pcinh: lxi h,1 ;return HL = true if C set
- rc
- dcx h
- ret
-
- pncinh: lxi h,0 ;return HL = false if C set
- rc
- inx h
- ret
-
- ppinh: lxi h,1 ;return HL = true if P (plus) flag set
- rp
- dcx h
- ret
-
- pminh: lxi h,1 ;return HL = true if M (minus) flag set
- rm
- dcx h
- ret
-
- pzind: lxi d,1 ;return DE = true if Z set
- rz
- dcx d
- ret
-
- pnzind: lxi d,0 ;return DE = false if Z set
- rz
- inx d
- ret
-
- pcind: lxi d,1 ;return DE = true if C set
- rc
- dcx d
- ret
-
- pncind: lxi d,0 ;return DE = false if C set
- rc
- inx d
- ret
-
- ppind: lxi d,1 ;return DE = true if P (plus) flag set
- rp
- dcx d
- ret
-
- pmind: lxi d,1 ;return DE = true if M (minus) flag set
- rm
- dcx d
- ret
-
-
- ;
- ; Relational operator routines: take args in DE and HL,
- ; and return a flag bit either set or reset.
- ;
- ; ==, >, < :
- ;
-
- eqwel: mov a,l ;return Z if HL == DE, else NZ
- cmp e
- rnz ;if L <> E, then HL <> DE
- mov a,h ;else HL == DE only if H == D
- cmp d
- ret
-
- blau: xchg ;return C if HL < DE, unsigned
- albu: mov a,d ;return C if DE < HL, unsigned
- cmp h
- rnz ;if D <> H, C is set correctly
- mov a,e ;else compare E with L
- cmp l
- ret
-
- bgau: xchg ;return C if HL > DE, unsigned
- agbu: mov a,h ;return C if DE > HL, unsigned
- cmp d
- rnz ;if H <> D, C is set correctly
- mov a,l ;else compare L with E
- cmp e
- ret
-
- blas: xchg ;return C if HL < DE, signed
- albs: mov a,h ;return C if DE < HL, signed
- xra d
- jp albu ;if same sign, do unsigned compare
- mov a,d
- ora a
- rp ;else return NC if DE is positive and HL is negative
- stc ;else set carry, since DE is negative and HL is pos.
- ret
-
- bgas: xchg ;return C if HL > DE, signed
- agbs: mov a,h ;return C if DE > HL, signed
- xra d
- jp agbu ;if same sign, go do unsigned compare
- mov a,h
- ora a
- rp ;else return NC is HL is positive and DE is negative
- stc
- ret ;else return C, since HL is neg and DE is pos
-
-
- ;
- ; Multiplicative operators: *, /, and %:
- ;
-
- smod: mov a,d ;signed MOD routine: return (DE % HL) in HL
- push psw ;save high bit of DE as sign of result
- call tstn ;get absolute value of args
- xchg
- call tstn
- xchg
- call usmod ;do unsigned mod
- pop psw ;was DE negative?
- ora a ;if not,
- rp ; all done
- mov a,h ;else make result negative
- cma
- mov h,a
- mov a,l
- cma
- mov l,a
- inx h
- ret
-
- nop ;maintain address compatibility with some
- nop ; pre-release v1.4's.
-
- usmod: mov a,h ;unsigned MOD: return (DE % HL) in HL
- ora l
- rz
- push d
- push h
- call usdiv
- pop d
- call usmul
- mov a,h
- cma
- mov h,a
- mov a,l
- cma
- mov l,a
- inx h
- pop d
- dad d
- ret
-
- smul: xra a ;signed multiply: return (DE * HL) in HL
- sta tmp
- call tstn
- xchg
- call tstn
- call usmul
- smul2: lda tmp
- rar
- rnc
- mov a,h
- cma
- mov h,a
- mov a,l
- cma
- mov l,a
- inx h
- ret
-
- tstn: mov a,h
- ora a
- rp
- cma
- mov h,a
- mov a,l
- cma
- mov l,a
- inx h
- lda tmp
- inr a
- sta tmp
- ret
-
- usmul: push b ;unsigned multiply: return (DE * HL) in HL
- call usm2
- pop b
- ret
-
- usm2: mov b,h
- mov c,l
- lxi h,0
- usm3: mov a,b
- ora c
- rz
- mov a,b
- rar
- mov b,a
- mov a,c
- rar
- mov c,a
- jnc usm4
- dad d
- usm4: xchg
- dad h
- xchg
- jmp usm3
-
- usdiv: mov a,h ;unsigned divide: return (DE / HL) in HL
- ora l ;return 0 if HL is 0
- rz
- push b
- call usd1
- mov h,b
- mov l,c
- pop b
- ret
-
-
- usd1: mvi b,1
- usd2: mov a,h
- ora a
- jm usd3
- dad h
- inr b
- jmp usd2
-
- usd3: xchg
-
- usd4: mov a,b
- lxi b,0
- usd5: push psw
- usd6: call cmphd
- jc usd7
- inx b
- push d
- mov a,d
- cma
- mov d,a
- mov a,e
- cma
- mov e,a
- inx d
- dad d
- pop d
- usd7: xra a
- mov a,d
- rar
- mov d,a
- mov a,e
- rar
- mov e,a
- pop psw
- dcr a
- rz
- push psw
- mov a,c
- ral
- mov c,a
- mov a,b
- ral
- mov b,a
- jmp usd6
-
- sdiv: xra a ;signed divide: return (DE / HL) in HL
- sta tmp
- call tstn
- xchg
- call tstn
- xchg
- call usdiv
- jmp smul2
-
- cmphd: mov a,h ;this returns C if HL < DE
- cmp d ; (unsigned compare only used
- rc ; within C.CCC, not from C)
- rnz
- mov a,l
- cmp e
- ret
-
- ;
- ; Shift operators << and >>:
- ;
-
- sderbl: xchg ;shift DE right by L bits
- shlrbe: inr e ;shift HL right by E bits
- shrbe2: dcr e
- rz
- xra a
- mov a,h
- rar
- mov h,a
- mov a,l
- rar
- mov l,a
- jmp shrbe2
-
- sdelbl: xchg ;shift DE left by L bits
- shllbe: inr e ;shift HL left by E bits
- shlbe2: dcr e
- rz
- dad h
- jmp shlbe2
-
-
- ;
- ; Routines to 2's complement HL and DE:
- ;
-
- cmh: mov a,h
- cma
- mov h,a
- mov a,l
- cma
- mov l,a
- inx h
- ret
-
- cmd: mov a,d
- cma
- mov d,a
- mov a,e
- cma
- mov e,a
- inx d
- ret
-
-
- ;
- ; The following routines yank a formal parameter value off the stack
- ; and place it in both HL and A (low byte), assuming the caller
- ; hasn't done anything to its stack pointer since IT was called.
- ;
- ; The mnemonics are "Move Arg #n To HL",
- ; where arg #1 is the third thing on the stack (where the first
- ; and second things are, respectively, the return address of the
- ; routine making the call to here, and the previous return
- ; address to the routine which actually pushed the args on the
- ; stack.) Thus, a call to "ma1toh" would return with the first
- ; passed parameter in HL and A; "ma2toh" would return the second,
- ; etc. Note that if the caller has pushed [n] items on the stack
- ; before calling "ma [x] toh", then the [x-n]th formal parameter
- ; value will be returned, not the [x]th.
- ;
-
- ma1toh: lxi h,4 ;get first arg
- ma0toh: dad sp
- mov a,m
- inx h
- mov h,m
- mov l,a
- ret
-
- ma2toh: lxi h,6 ;get 2nd arg
- jmp ma0toh
-
- ma3toh: lxi h,8 ;get 3rd arg
- jmp ma0toh
-
- ma4toh: lxi h,10 ;get 4th arg
- jmp ma0toh
-
- ma5toh: lxi h,12 ;get 5th arg
- jmp ma0toh
-
- ma6toh: lxi h,14 ;get 6th arg
- jmp ma0toh
-
- ma7toh: lxi h,16 ;get 7th arg
- jmp ma0toh
-
- ;
- ; This routine takes the first 7 args on the stack
- ; and places them contiguously at the "args" ram area.
- ; This allows a library routine to make one call to arghak
- ; and henceforth have all it's args available directly
- ; through lhld's instead of having to hack the stack as it
- ; grows and shrinks. Note that arghak should be called as the
- ; VERY FIRST THING a function does, before even pushing BC.
- ;
-
- arghak: lxi d,args ;destination for block move in DE
- lxi h,4 ;pass over two return address
- dad sp ;source for block move in HL
- push b ;save BC
- mvi b,14 ;countdown in B
- arghk2: mov a,m ;copy loop
- stax d
- inx h
- inx d
- dcr b
- jnz arghk2
- pop b ;restore BC
- ret
-
- ;
- ; UP TO THIS POINT, ABSOLUTELY NO CHANGES SHOULD EVER BE MADE
- ; TO THIS SOURCE FILE (except for customizing the EQU statements
- ; at the beginning of the file).
- ;
-
-
- ;
- ; This routine is called first to do argc & argv processing (if
- ; running under CP/M) and some odds and ends initializations:
- ;
-
- init: pop h ;store return address
- shld tmp2 ; somewhere safe for the time being
-
- IF CPM
- lxi h,arglst-2 ;set the "argv" that the C main program
- ENDIF
-
- IF NOT CPM
- lxi h,0
- ENDIF
-
- push h ; will get.
-
- ;Initialize storage allocation pointers:
- lhld freram ;get address after end of externals
- shld allocp ;store at allocation pointer (for "sbrk.")
- lxi h,1000 ;default safety space between stack and
- shld alocmx ; highest allocatable address in memory
- ; (for use by "sbrk".).
-
- ;Initialize random seed:
- lxi h,59dch ;let's stick something wierd into the
- shld rseed ;first 16 bits of the random-number seed
-
- ;Initialize I/O hack locations:
- mvi a,0dbh ;"in" op, for "in xx; ret" subroutine
- sta iohack
- mvi a,0d3h ;"out" op for "out xx; ret" subroutine
- sta iohack+3
- mvi a,0c9h ;"ret" for above sobroutines
- sta iohack+2 ;the port number is filled in by the
- sta iohack+5 ;"inp" and "outp" library routines.
-
- ;Initialize DMA video parameters:
- IF DMAVIO ;if we're using DMA video routines,
- lxi h,0cc00h ;set up default values (may be changed
- shld pbase ;to whatever suits). Video board address,
- lxi h,16
- shld xsize ;# of lines,
- lxi h,64
- shld ysize ;# of columns,
- lxi h,1024
- shld psize ;and total # of characters on screen
- ENDIF
-
- IF CPM ;under CP/M: clear console, process ARGC & ARGV:
- mvi c,11 ;interrogate console status to see if there
- call bdos ; happens to be a stray character there...
-
- ora a ;(used to be `ani 1'...they tell me this works
- nop ; better for certain bizarre CP/M-"like" systems)
-
- jz initzz
- mvi c,1 ;if input present, clear it
- call bdos
-
- initzz: lxi h,tbuff ;if arguments given, process them.
- lxi d,comlin ;get ready to copy command line
- mov b,m ;first get length of it from loc. base+80h
- inx h
- mov a,b
- ora a ;if no arguments, don't parse for argv
- jnz initl
- lxi d,1 ;set argc to 1 in such a case.
- jmp i5
-
- initl: mov a,m ;ok, there are arguments. parse...
- stax d ;first copy command line to comlin
- inx h
- inx d
- dcr b
- jnz initl
- xra a ;place zero following line
- stax d
-
- lxi h,comlin ;now compute pointers to each arg
- lxi d,1 ;arg count
- lxi b,arglst ;where pointers will all go
- xra a ;clear "in a string" flag
- sta tmp1
- i2: mov a,m ;between args...
- inx h
- cpi ' '
- jz i2
- ora a
- jz i5 ;if null byte, done with list
- cpi '"'
- jnz i2a ;quote?
- sta tmp1 ;yes. set "in a string" flag
- jmp i2b
-
- i2a: dcx h
- i2b: mov a,l ;ok, HL is a pointer to the start
- stax b ;of an arg string. store it.
- inx b
- mov a,h
- stax b
- inx b
- inx d ;bump arg count
- i3: mov a,m
- inx h ;pass over text of this arg
- ora a ;if at end, all done
- jz i5
- push b ;if tmp1 set, in a string
- mov b,a ; (so we have to ignore spaces)
- lda tmp1
- ora a
- mov a,b
- pop b
- jz i3a
- cpi '"' ;we are in a string.
- jnz i3 ;check for terminating quote
- xra a ;if found, reset "in string" flag
- sta tmp1
- dcx h
- mov m,a ;and stick a zero byte after the string
- inx h ;and go on to next arg
- i3a: cpi ' ' ;now find the space between args
- jnz i3
- dcx h ;found it. stick in a zero byte
- mvi m,0
- inx h
- jmp i2 ;and go on to next arg
-
- i5: push d ;all done finding args. Set argc.
-
- mvi b,nfcbs ;now initialize all the file info
- lxi h,fdt ;(just zero the fd table)
- i6: mvi m,0
- inx h
- dcr b
- jnz i6
- ENDIF
-
- IF NOT CPM ;if not under CP/M, force ARGC value
- lxi h,1 ; of one.
- push h
- ENDIF
-
- xra a
- sta ungetl ;clear the push-back byte
- sta lastc ;and last character byte
-
- lhld tmp2
- pchl ;all done initializing.
-
- ;
- ; General purpose error value return routine:
- ;
-
- verror: lxi h,-1 ;general error handler...just
- ret ;returns -1 in HL
-
- ;
- ; Here are file I/O handling routines, only needed under CP/M:
- ;
-
- ;
- ; Close any open files and reboot:
- ;
-
- vexit:
- IF CPM ;if under CP/M, close all open files
- mvi a,7+nfcbs ;start with largest possible fd
- exit1: push psw ;and scan all fd's for open files
- call vfgfd ;is file whose fd is in A open?
- jc exit2 ;if not, go on to next fd
- mov l,a ;else close the associated file
- mvi h,0
- push h
- call vclose
- pop h
- exit2: pop psw
- dcr a ;and go on to next one
- cpi 7
- jnz exit1
- ENDIF
-
- jmp exitad ;done closing; now reboot CP/M or whatever.
-
- ;
- ; Close the file whose fd is 1st arg:
- ;
-
- IF CPM ;here comes a lot of CP/M stuff...
- vclose: call setdma ;library function just jumps here.
- call ma1toh ;get fd in A
- call vfgfd ;see if it is open
- jc verror ;if not, complain
- mov a,m
- ani 4
-
- IF NOT MPM2 ;if not MP/M, and
- jz close2 ;the file isn't open for write, don't bother to close
- ENDIF
-
- IF MPM2 ;always close all files under MP/M
- nop
- nop
- nop
- ENDIF
-
- push h ;save fd table entry addr
- call ma2toh ;move arg1 to A
- push b
- call vfgfcb ;get the appropriate fcb address
- xchg ;put it in DE
- mvi c,16 ;get BDOS function # for close
- call bdos ;and do it!
- pop b
- pop h
- close2: mvi m,0 ;close logically
- cpi 255 ;if 255 comes back, we got problems
- lxi h,0
- rnz ;return 0 if OK
- dcx h ;return -1 on error
- ret
-
- ;
- ; Determine status of file whose fd is in A...if the file
- ; is not open, return C flag set, else clear C flag:
-
- vfgfd: call setdma
- mov d,a
- sui 8
- rc ;if fd < 8, error
- cpi nfcbs
- cmc ;don't allow too big an fd either
- rc
- push d
- mov e,a ;OK, we have a value in range. Now
- mvi d,0 ; see if the file is open or not
- lxi h,fdt
- dad d
- mov a,m
- ani 1 ;bit 0 is high if file is open
- stc
- pop d
- mov a,d
- rz ;return C set if not open
- cmc
- ret ;else reset C and return
-
- ;
- ; Set up a CP/M file control block at HL with the file whose
- ; simple null-terminated name is pointed to by DE:
- ; Format for filename must be: "[white space][d:]filename.ext"
- ;
-
- vsetfcb: call setdma ;set up an fcb at HL for filename at DE
- push b
- call igwsp ;ignore blanks and tabs
- mvi b,8
- push h
- inx d
- ldax d
- dcx d
- cpi ':' ;default disk byte value is 0
- mvi a,0 ; (for currently logged disk)
- jnz setf1
- ldax d ;oh oh...we have a disk designator
- call mapuc ;make it upper case
- sui '@' ;and fudge it a bit
- inx d
- inx d
- setf1: mov m,a
- inx h
- call patchnm ;now set filename and pad with blanks
- ldax d
- cpi '.' ;and if an extension is given,
- jnz setfcb2
- inx d
- setfcb2 mvi b,3 ;set the extension and pad with blanks
- call setnm
- xra a ;and zero the appropriate fields of the fcb
- mov m,a
- lxi d,20
- dad d
- mov m,a
- inx h
- jmp setfcb3 ;finish up elsewhere to keep addresses consistent
- ;with prior releases
-
-
- ;
- ; This routine copes up to B characters from memory at DE to
- ; memory at HL and pads with blanks on the right:
- ;
-
-
- setnm: push b
- setnm1: ldax d
- cpi '*' ;wild card?
- mvi a,'?' ;if so, pad with ? characters
- jz pad2
-
- setnm2: ldax d
- call legfc ;next char legal filename char?
- jc pad ;if not, go pad for total of B characters
- mov m,a ;else store
- inx h
- inx d
- dcr b
- jnz setnm1 ;and go for more if B not yet zero
- pop b
- setnm3: ldax d ;skip rest of filename if B chars already found
- call legfc
- rc
- inx d
- jmp setnm3
-
- pad: mvi a,' ' ;pad with B blanks
- pad2: mov m,a ;pad with B instances of char in A
- inx h
- dcr b
- jnz pad2
- pop b
- ret
-
- ;
- ; Test if char in A is legal character to be in a filename:
- ;
-
- legfc: call mapuc
- cpi '.' ; '.' is illegal in a filename or extension
- stc
- rz
- cpi ':' ;so is ':'
- stc
- rz
- cpi 7fh ;delete is no good
- stc
- rz
- cpi '!' ;if less than exclamation pt, not legal char
- ret ;else good enough
-
- ;
- ; Map character in A to upper case if it is lower case:
- ;
-
- mapuc: cpi 'a'
- rc
- cpi 'z'+1
- rnc
- sui 32 ;if lower case, map to upper
- ret
-
- ;
- ; Ignore blanks and tabs at text pointed to by DE:
- ;
-
- igwsp: dcx d
- igwsp1: inx d
- ldax d
- cpi ' '
- jz igwsp1
- cpi 9
- jz igwsp1
- ret
-
-
- ;
- ; This routine does one of two things, depending
- ; on the value passed in A.
- ;
- ; If A is zero, then it finds a free file slot
- ; (if possible), else returns C set.
- ;
- ; If A is non-zero, then it returns the address
- ; of the fcb corresponding to an open file whose
- ; fd happens to be the value in A, or C set if there
- ; is no file associated with fd.
- ;
-
- vfgfcb: push b
- call setdma
- ora a ;look for free slot?
- mov c,a
- jnz fgfc2 ;if not, go away
- mvi b,nfcbs ;yes. do it...
- lxi d,fdt
- lxi h,fcbt
- mvi c,8
- fgfc1: ldax d
- ani 1
- mov a,c
- jnz fgfc1a ;found free slot?
- pop b ;yes. all done.
- ret
-
- fgfc1a: push d
- lxi d,36 ;fcb length to accommodate random I/O
- dad d
- pop d
- inx d
- inr c
- dcr b
- jnz fgfc1
- fgfc1b: stc
- pop b
- ret ;return C if no more free slots
-
- fgfc2: call vfgfd ;compute fcb address for fd in A:
- jc fgfc1b ;return C if file isn't open
-
- sui 8
- mov l,a ;put (fd-8) in HL
- mvi h,0
- dad h ;double it
- dad h ;4*a
- mov d,h ;save 4*a in DE
- mov e,l
- dad h ;8*a
- dad h ;16*a
- dad h ;32*a
- dad d ;36*a
- xchg ;put 36*a in DE
- lxi h,fcbt ;add to base of table
- dad d ;result in HL
- mov a,c ;and return original fd in A
- pop b
- ret
-
- setdma: push d ;just a preventative measure,
- push b ;since the default I/O buffer
- push psw ;tends to magically change
- push h ;around by itself when left
- mvi c,26 ;in CP/M's hands !!
- lxi d,tbuff
- call bdos
- pop h
- pop psw
- pop b
- pop d
- ret
-
- ENDIF ;end of CP/M-related file I/O routines
-
-
- IF NOT CPM
- main: equ $ ;where main program resides when not under CP/M
- ;(under CP/M, the data area comes first)
- ENDIF
-
-
- ;
- ; Ram area:
- ;
-
- IF NOT CPM ;if not under CP/M, use custom ram area address
- org ram
- ENDIF
-
- room: ds 30 ;room for random stuff
-
- pbase: ds 2 ;screen-DMA address
- ysize: ds 2 ;screen width
- xsize: ds 2 ;screen height
- psize: ds 2 ;screen length
-
- rseed: ds 8 ;the random generator seed
-
- args: ds 14 ;"arghak" puts args passed on stack here.
-
- iohack: ds 6 ;room for I/O subroutines for use by "inp"
- ;and "outp" library routines
-
- allocp: ds 2 ;pointer to free storage for use by "sbrk" func
- alocmx: ds 2 ;highest location to be made available to the
- ;storage allocator
-
- tmp: equ room ;this is misc. garbage space
- tmp1: equ room+1
- tmp2: equ room+2
- tmp2a: equ room+4
- ungetl: equ room+6 ;where characters are "ungotten"
- lastc: equ room+7 ;last char typed
-
- ;
- ;--------------------------------------------------------------------------
- ; The following data areas are needed only if running under CP/M:
- ;
- IF CPM
- ;
- ; The fcb table (fcbt): 36 bytes per file control block
- ;
-
- fcbt: ds 36*nfcbs ;reserve room for fcb's (extra byte for IMDOS)
-
- ;
- ; The fd table: one byte per file specifying r/w/open as follows:
- ; bit 0 is high if open, low if closed
- ; bit 1 is high if open for read
- ; bit 2 is high if open for write
- ; (both b1 and b2 may be high)
- ;
-
- fdt: ds nfcbs ;one byte per fcb tells if it is active, r/w, etc.
-
- ;
- ; The command line is copied here by init:
- ;
-
- comlin: ds 131 ;copy of the command line pointed to by entries
- ;in arglst
-
- ;
- ; This is where "init" places the array of argument pointers:
- ;
-
- arglst: ds 60 ;the "argv" paramater points here (well,
- ;actually to 2 bytes before arglst). Thus,
- ;up to 30 parameters may be passed to "main"
- ENDIF ;(enough for you, Andy?)
-
- ;
- ; End of CP/M-only data area
- ;---------------------------------------------------------------------------
-
- IF CPM
- main: equ $ ;where "main" program will be loaded under CP/M
-
- ENDIF
-
- end
-