home *** CD-ROM | disk | FTP | other *** search
- TITLE 'LRUN Library Run--a utility for .LBR files'
- VERSION EQU 2$0 ;82-11-19 Added equates for user
- ; area to search for command.lbr.
- ;
- ; 1$0 ;82-08-06 Initial source release
- PAGE 60
- ;
- ; Requires MAC for assembly. Due to the complexity of
- ; the relocation macros, this program may take a while
- ; to assemble. Be prepared for periods of no disk activity
- ; on both passes before pressing panic button. G.P.N.
- ;
-
- ;--------------------------NOTICE------------------------------
- ;
- ; (c) Copyright 1982 Gary P. Novosielski
- ; All rights reserved.
- ;
- ; The following features courtesy of Ron Fowler:
- ; 1) command line reparsing and repacking (this allows
- ; the former load-only program to become a load & run
- ; utility).
- ; 2) code necessary to actually execute the loaded file
- ; 3) the HELP facility (LRUN with no arguments)
- ; 4) modified error routines to avoid warm-boot delay
- ; (return to CCP directly instead)
- ;
- ; Permission to distribute this program in source or
- ; object form without prior written aproval is granted
- ; only under the following conditions.
- ;
- ; 1. No charge is imposed for the program.
- ; 2. Charges for incidental costs including
- ; but not limited to media, postage, tele-
- ; communications, and data storage do not
- ; exceed those costs actually incurred.
- ; 3. This Notice and any copright notices in
- ; the object code remain intact
- ;
- ; (signed) Gary P. Novosielski
- ;
- ;--------------------------------------------------------------
- ;
- ; LRUN is intended to be used in conjunction with libraries
- ; created with LU.COM, a library utility based upon the
- ; groundwork laid by Michael Rubenstein, with some additional
- ; inspiration from Leor Zolman's CLIB librarian for .CRL files.
- ;
- ; The user can place the less frequently used command (.COM)
- ; files in a library to save space, and still be able to run
- ; them when required, by typing:
- ; LRUN <normal command line>.
- ; The name of the library can be specified, but the greatest
- ; utility will be achieved by placing all commands in one
- ; library called COMMAND.LBR, or some locally defined name,
- ; and always letting LRUN use that name as the default.
- ;
-
- ;Syntax:
- ; LRUN [-<lbrname>] <command> [<parameters>]
- ;
- ;where:
- ;<lbrname> is the optional library name. In the
- ; distrubution version, this defaults to
- ; COMMAND.LBR. If the user wishes to use a
- ; different name for the default, the 8-byte
- ; literal at DFLTNAM below may be changed to
- ; suit local requirements. The current drive
- ; is searched for the .LBR file, and if not
- ; found there, the A: drive is searched.
- ; **Note that the leading minus sign (not a part
- ; of the name) is required to indicate an
- ; override library name is being entered.
- ;
- ;<command> is the name of the .COM file in the library
- ;
- ;<line> is the (possibly empty) set of parameters
- ; which are to be passed to <command>, as in
- ; normal CP/M syntax. Notice that if the
- ; library name is defaulted, the syntax is
- ; simply:
- ; LRUN <command line>
- ; which is just the normal command line with
- ; LRUN prefixed to it.
- ;
- ;--------------------------------------------------------------
- ; USER MODIFIABLE EQUATES
- ;
- ; Define a secondary search drive and user if .LBR is
- ; not found after initial search of current area:
- ;
- SSDRV: EQU 'A' ;Valid values are 'A' through 'P'.
- SSUSR: EQU 0 ;Valid values are 0 through 31.
- ;
- ;Default library may also be modified. See label DFLTNAM.
- ;--------------------------------------------------------------
- ;
- QUERY SET -1
- @SYS SET 0
- @KEY SET 1
- @CON SET 2
- @RDR SET 3
- @PUN SET 4
- @LST SET 5
- @DIO SET 6
- @RIO SET 7
- @SIO SET 8
- @MSG SET 9
- @INP SET 10
- @RDY SET 11
- @VER SET 12
- @LOG SET 13
- @DSK SET 14
- @OPN SET 15
- @CLS SET 16
- @DIR SET 17
- @NXT SET 18
- @DEL SET 19
- @FRD SET 20
- @FWR SET 21
- @MAK SET 22
- @REN SET 23
- @CUR SET 25
- @DMA SET 26
- @CHG SET 30
- @USR SET 32
- @RRD SET 33
- @RWR SET 34
- @SIZ SET 35
- @REC SET 36
- @LOGV SET 37 ;2.2 only
- @RWR0 SET 40 ;2.2 only
- ;
- CPMBASE EQU 0
- BOOT SET CPMBASE
- BDOS SET BOOT+5
- TFCB EQU BOOT+5CH
- TFCB1 EQU TFCB
- TFCB2 EQU TFCB+16
- TBUFF EQU BOOT+80H
- TPA EQU BOOT+100H
- CTRL EQU ' '-1 ;Ctrl char mask
- CR SET CTRL AND 'M'
- LF SET CTRL AND 'J'
- TAB SET CTRL AND 'I'
- FF SET CTRL AND 'L'
- BS SET CTRL AND 'H'
- FALSE SET 0
- TRUE SET NOT FALSE
- ;
- CPM MACRO FUNC,OPERAND,CONDTN
- LOCAL PAST
- IF NOT NUL CONDTN
- DB ( J&CONDTN ) XOR 8
- DW PAST
- ENDIF ;;of not nul condtn
- IF NOT NUL OPERAND
- LXI D,OPERAND
- ENDIF ;;of not nul operand
- IF NOT NUL FUNC
- MVI C,@&FUNC
- ENDIF
- CALL BDOS
- PAST:
- ENDM
- ;
- BLKMOV MACRO DEST,SRCE,LEN,COND
- LOCAL PAST
- JMP PAST
- @BMVSBR:
- MOV A,B
- ORA C
- RZ
- DCX B
- MOV A,M
- INX H
- STAX D
- INX D
- JMP @BMVSBR
- BLKMOV MACRO DST,SRC,LN,CC
- LOCAL PST
- IF NOT NUL CC
- DB ( J&CC ) XOR 8
- DW PST
- ENDIF
- IF NOT NUL DST
- LXI D,DST
- ENDIF
- IF NOT NUL SRC
- LXI H,SRC
- ENDIF
- IF NOT NUL LN
- LXI B,LN
- ENDIF
- CALL @BMVSBR
- IF NOT NUL CC
- PST:
- ENDIF
- ENDM
- PAST: BLKMOV DEST,SRCE,LEN,COND
- ENDM
-
- ;
- OVERLAY SET 0
- ; Macro Definitions
- ;
- RTAG MACRO LBL
- ??R&LBL EQU $+2-@BASE
- ENDM
- ;
- RGRND MACRO LBL
- ??R&LBL EQU 0FFFFH
- ENDM
- ;
- R MACRO INST
- @RLBL SET @RLBL+1
- RTAG %@RLBL
- INST-@BASE
- ENDM
- ;
- NXTRLD MACRO NN
- @RLD SET ??R&NN
- @NXTRLD SET @NXTRLD + 1
- ENDM
- ;
- ;
- ; Enter here from Console Command Processor (CCP)
- ;
- CCPIN ORG TPA
- JMP INTRO ;Jump around signon
- ;
- SIGNON:
- DB 'LRUN Ver ' ;Signon message
- DB VERSION/10+'0'
- DB '.'
- DB VERSION MOD 10+'0'
- DB CR,LF
- DB ' Copyright (c) 1982 Gary P. Novosielski '
- DB '$',CTRL AND 'Z'
- ;
- INTRO:
- LXI H,0 ;get the CCP entry stackpointer
- DAD SP ;(used only if HELP request
- SHLD SPSAVE ; is encountered)
- CPM MSG,SIGNON; ;Display signon
- CALL SETUP ;initialize.
- LHLD BDOS+1 ;find top of memory
- MOV A,H ;page address
- ;Form destination...
- SUI PAGES ;...address in
- MOV D,A ;DE pair.
- MVI E,0
- PUSH D ;save on stack
- ;
- BLKMOV ,@BASE,SEGLEN ;Move the active segment.
- ;
- ;The segment is now moved to high memory, but not
- ;properly relocated. The bit table which specifies
- ;which addresses need to be adjusted is located
- ;just after the last byte of the source segment,
- ;so (HL) is now pointing at it.
- POP D ;beginning of newly moved code.
- LXI B,SEGLEN;length of segment
- PUSH H ;save pointer to reloc info
- MOV H,D ;offset page address
- ;
- FIXLOOP:
- ;Scan through the newly moved code, and adjust any
- ;page addresses by adding (H) to them. The word on
- ;top of the stack points to the next byte of the
- ;relocation bit table. Each bit in the table
- ;corresponds to one byte in the destination code.
- ;A value of 1 indicates the byte is to be adjusted.
- ;A value of 0 indicates the byte is to be unchanged.
- ;
- ;Thus one byte of relocation information serves to
- ;mark 8 bytes of object code. The bits which have
- ;not been used yet are saved in L until all 8
- ;are used.
- ;
- MOV A,B
- ORA C ;test if finished
- JZ FIXDONE
- DCX B ;count down
- MOV A,E
- ANI 07H ;on 8-byte boundry?
- JNZ NEXTBIT
- ;
- NEXTBYT:
- ;Get another byte of relocation bits
- XTHL
- MOV A,M
- INX H
- XTHL
- MOV L,A ;save in register L
- ;
- NEXTBIT MOV A,L ;remaining bits from L
- RAL ;next bit to CARRY
- MOV L,A ;save the rest
- JNC NEXTADR
- ;
- ;CARRY was = 1. Fix this byte.
- LDAX D
- ADD H ;(H) is the page offset
- STAX D
- ;
- NEXTADR INX D
- JMP FIXLOOP
- ;
- FIXDONE:
- ;Finished. Jump to the first address in the new
- ;segment in high memory.
- ;
- ;First adjust the stack. One garbage word was
- ;left by fixloop.
- INX SP
- INX SP
- ;
- ;(HL) still has the page address
- MOV L,A ;move zero to l
- PCHL ;Stack is valid
- SETUP:
- ;Any one-shot initialization code goes here.
- ;
- LXI H,NOLOAD
- SHLD CCPIN+1 ;Prevent reentry
- ;
- ;
- CPM VER ;Test version of CP/M in use
- CPI 20H ;2.0 or better?
- JC BADVER ;No, bitch and quit.
- ;
- CPM USR,QUERY ;What's the current user area?
- STA ENTUSR ;Save for later.
- ;
- CALL REPARS ;Re-parse command line
- ;
- LXI D,MEMBER+9 ;Check member filetype
- LDAX D
- CPI ' ' ;If blank,
- BLKMOV ,COMLIT,3,Z ; default to COM.
- ;
- LXI D,LBRFIL+9 ;Check library filetype
- LDAX D
- CPI ' ' ;If blank,
- BLKMOV ,LBRLIT,3,Z ; default to LBR
- ;
- LXI D,LBRFIL+1 ;Check name
- LDAX D
- CPI ' ' ;If blank,
- BLKMOV ,DFLTNAM,8,Z ; use default name.
- ;
- ;
- DIROPN: CPM OPN,LBRFIL ;Open for directory read.
- INR A ;Was it found?
- JNZ DIROK ;yes, ok
- LXI H,LBRFIL ;No, test drive spec
- MOV A,M ; to see if it's
- ORA A ; explicit
- JNZ NODIR ;It is explicit. Out of luck
- MVI M,SSDRV-'@' ;Look on secondary drive,
- CPM USR,SSUSR ; in secondary user.
- JMP DIROPN ; before giving up.
- ;
- DIROK:
- CPM DMA,TBUFF
- FINDMBR:
- CPM FRD,LBRFIL ;Read the directory
- ORA A
- JNZ FISHY ;Empty file, Give up.
- LXI H,TBUFF
- MOV A,M
- ORA A
- JNZ FISHY ;Directory not active??
- MVI B,8+3 ;Check for blanks
- MVI A,' '
- VALIDLOOP:
- INX H
- CMP M
- JNZ FISHY
- DCR B
- JNZ VALIDLOOP
- ;
- LHLD TBUFF+1+8+3 ;Index must be 0000
- MOV A,H
- ORA L
- JNZ FISHY
- ;
- LHLD TBUFF+1+8+3+2 ;Get directory size
- DCX H ;We already read one.
- PUSH H ;Save on stack
- JMP FINDMBRN ;Jump into loop
- FINDMBRL:
- POP H ;Read sector count from TOS
- MOV A,H
- ORA L ;0 ?
- JZ NOMEMB ;Member not found in library
- DCX H ;Count down
- PUSH H ;and put it back.
- CPM FRD,LBRFIL ;Get next directory sector
- ORA A
- JNZ FISHY
-
-
- FINDMBRN:
- LXI H,TBUFF ;Point to buffer.
- MVI C,128/32 ;Number of directory entries
- ;
- FINDMBR1:
- CALL COMPARE ;Check if found yet.
- JZ GETLOC ;Found member in .DIR
- DCR C
- JZ FINDMBRL
- ;
- LXI D,32 ;No match, point to next one.
- DAD D
- JMP FINDMBR1
- ;
- GETLOC: ;The name was found now get index and length
- POP B ;Clear stack garbage
- XCHG ;Pointer to sector address.
- MOV E,M ;Get First
- INX H
- MOV D,M
- XCHG
- SHLD INDEX ;Save it
- XCHG
- INX H ;Get Size to DE
- MOV E,M
- INX H
- MOV D,M
- XCHG ; Size to HL
- SHLD LENX
- CALL PACKUP ;Repack command line arguments
- CPM CON,CR ;do <cr> only (look like CCP)
- RET
- ; End of setup.
- ;
- ; Utility subroutines
- NEGDE: ;DE = -DE
- MOV A,D
- CMA
- MOV D,A
- ;
- MOV A,E
- CMA
- MOV E,A
- INX D
- RET
- ;
- ; REPARSE re-parses the fcbs from the command line,
- ; to allow the "-" character to prefix the library name
- ;
- REPARS: LXI D,MEMBER ;first reinitialize both fcbs
- CALL NITF
- LXI D,LBRFIL
- CALL NITF
- LXI H,TBUFF ;store a null at the end of
- MOV E,M ; the command line (this is
- MVI D,0 ; done by CP/M usually, except
- XCHG ; in the case of a full com-
- DAD D ; mand line
- INX H
- MVI M,0
- XCHG ;tbuff pointer back in hl
- SCANBK: INX H ;bump to next char position
- MOV A,M ;fetch next char
- ORA A ;reached a null? (no arguments)
- JZ HELP ;interpret as a call for help
- CPI ' ' ;not null, skip blanks
- JZ SCANBK
- CPI '-' ;library name specifier?
- JNZ NOTLBR ;skip if not
- INX H ;it is, skip over flag character
- LXI D,LBRFIL ;parse library name into FCB
- CALL GETFN
- NOTLBR: LXI D,MEMBER ;now parse the command name
- CALL GETFN
- LXI D,HOLD+1 ;pnt to temp storage for rest of cmd line
- MVI B,-1 ;init a counter
- CLSAVE: INR B ;bump up counter
- MOV A,M ;fetch a char
- STAX D ;move it to hold area
- INX H ;bump pointers
- INX D
- ORA A ;test whether char was a terminator
- JNZ CLSAVE ;continue moving line if not
- MOV A,B ;it was, get count
- STA HOLD ;save it in hold area
- RET
- ;
- ; PACKUP retrieves the command line stored at
- ; HOLD and moves it back to tbuff, then reparses
- ; the default file control blocks so the command
- ; will never know it was run from a library
- ;
- PACKUP: LXI H,HOLD ;point to length byte of HOLD
- MOV C,M ;get length in BC
- MVI B,0
- INX B ;bump up to because length byte doesn't
- INX B ; include itself or null terminator
- BLKMOV TBUFF ;moving everybody to Tbuff
- LXI H,TBUFF+1 ;point to the command tail
- LXI D,TFCB1 ;first parse out tfcb1
- CALL GETFN
- LXI D,TFCB2 ;then tfcb2
- CALL GETFN
- RET
- ;
- ; Here when HELP is requested (indicated
- ; by LRUN with no arguments)
- ;
- HELP: CPM MSG,HLPMSG ;print the HELP message
- EXIT: LHLD SPSAVE ;find CCP re-entry adrs
- SPHL ;fix & return
- RET
- ;
- ; the HELP message
- ;
- HLPMSG: DB CR,LF,'Correct syntax is:'
- DB CR,LF
- DB LF,TAB,'LRUN [-<lbrname>] <command line>'
- DB CR,LF
- DB LF,'Where <lbrname> is the optional library name'
- DB CR,LF,'(Note the preceding "-". ) If omitted,'
- DB CR,LF,'the default command library is used.'
- DB LF
- DB CR,LF,'<command line> is the name and parameters'
- DB CR,LF,'of the command being run from the library,'
- DB CR,LF,'just as if a separate .COM file were being run.'
- DB CR,LF,'$'
- ;
- ;
- COMPARE: ;Test status, name and type of
- PUSH H ;a directory entry.
- MVI B,1+8+3
- XCHG ;with the one we're
- LXI H,MEMBER ;looking for.
- COMPAR1:
- LDAX D
- CMP M
- JNZ COMPEXIT
- INX D
- INX H
- DCR B
- JNZ COMPAR1
- COMPEXIT: ;Return with DE pointing to
- POP H ;last match + 1, and HL still
- RET ;pointing to beginning.
- ;
- ;
- ; File name parsing subroutines
- ;
- ; getfn gets a file name from text pointed to by reg hl into
- ; an fcb pointed to by reg de. leading delimeters are
- ; ignored.
- ; entry hl first character to be scanned
- ; de first byte of fcb
- ; exit hl character following file name
- ;
- ;
- ;
- GETFN: CALL NITF ;init 1st half of fcb
- CALL GSTART ;scan to first character of name
- RZ ;end of line was found - leave fcb blank
- CALL GETDRV ;get drive spec. if present
- CALL GETPS ;get primary and secondary name
- RET
-
-
- ;
- ; nitf fills the fcb with dflt info - 0 in drive field
- ; all-blank in name field, and 0 in ex,s1,s2 and rc flds
- ;
- NITF: PUSH D ;save fcb loc
- XCHG ;move it to hl
- MVI M,0 ;zap dr field
- INX H ;bump to name field
- MVI B,11 ;zap all of name fld
- NITLP1: MVI M,' '
- INX H
- DCR B
- JNZ NITLP1
- MVI B,4 ;zero others
- NITLP2: MVI M,0
- INX H
- DCR B
- JNZ NITLP2
- XCHG ;restore hl
- POP D ;restore fcb pointer
- RET
- ;
- ; gstart advances the text pointer (reg hl) to the first
- ; non delimiter character (i.e. ignores blanks). returns a
- ; flag if end of line (00h or ';') is found while scaning.
- ; exit hl pointing to first non delimiter
- ; a clobbered
- ; zero set if end of line was found
- ;
- GSTART: CALL GETCH ;see if pointing to delim?
- RNZ ;nope - return
- CPI ';' ;end of line?
- RZ ;yup - return w/flag
- ORA A
- RZ ;yup - return w/flag
- INX H ;nope - move over it
- JMP GSTART ;and try next char
- ;
- ; getdrv checks for the presence of a drive spec at the text
- ; pointer, and if present formats it into the fcb and
- ; advances the text pointer over it.
- ; entry hl text pointer
- ; de pointer to first byte of fcb
- ; exit hl possibly updated text pointer
- ; de pointer to second (primary name) byte of fcb
- ;
- GETDRV: INX D ;point to name if spec not found
- INX H ;look ahead to see if ':' present
- MOV A,M
- DCX H ;put back in case not present
- CPI ':' ;is a drive spec present?
- RNZ ;nope - return
- MOV A,M ;yup - get the ascii drive name
- SUI 'A'-1 ;convert to fcb drive spec
- DCX D ;point back to drive spec byte
- STAX D ;store spec into fcb
- INX D ;point back to name
- INX H ;skip over drive name
- INX H ;and over ':'
- RET
- ;
- ; getps gets the primary and secondary names into the fcb.
- ; entry hl text pointer
- ; exit hl character following secondary name (if present)
- ;
- GETPS: MVI C,8 ;max length of primary name
- CALL GETNAM ;pack primary name into fcb
- MOV A,M ;see if terminated by a period
- CPI '.'
- RNZ ;nope - secondary name not given
- ;return default (blanks)
- INX H ;yup - move text pointer over period
- FTPOINT:MOV A,C ;yup - update fcb pointer to secondary
- ORA A
- JZ GETFT
- INX D
- DCR C
- JMP FTPOINT
- GETFT: MVI C,3 ;max length of secondary name
- CALL GETNAM ;pack secondary name into fcb
- RET
- ;
- ; getnam copies a name from the text pointer into the fcb for
- ; a given maximum length or until a delimiter is found, which
- ; ever occurs first. if more than the maximum number of
- ; characters is present, characters are ignored until a
- ; a delimiter is found.
- ; entry hl first character of name to be scaned
- ; de pointer into fcb name field
- ; c maximum length
- ; exit hl pointing to terminating delimiter
- ; de next empty byte in fcb name field
- ; c max length - number of characters transfered
- ;
- GETNAM: CALL GETCH ;are we pointing to a delimiter yet?
- RZ ;if so, name is transfered
- INX H ;if not, move over character
- CPI '*' ;ambigious file reference?
- JZ AMBIG ;if so, fill the rest of field with '?'
- STAX D ;if not, just copy into name field
- INX D ;increment name field pointer
- DCR C ;if name field full?
- JNZ GETNAM ;nope - keep filling
- JMP GETDEL ;yup - ignore until delimiter
- AMBIG: MVI A,'?' ;fill character for wild card match
- QFILL: STAX D ;fill until field is full
- INX D
- DCR C
- JNZ QFILL ;fall thru to ingore rest of name
- GETDEL: CALL GETCH ;pointing to a delimiter?
- RZ ;yup - all done
- INX H ;nope - ignore another one
- JMP GETDEL
- ;
- ; getch gets the character pointed to by the text pointer
- ; and sets the zero flag if it is a delimiter.
- ; entry hl text pointer
- ; exit hl preserved
- ; a character at text pointer
- ; z set if a delimiter
- ;
- GETCH:
- MOV A,M ;get the character
- CPI '.'
- RZ
- CPI ','
- RZ
- CPI ';'
- RZ
- CPI ' '
- RZ
- CPI ':'
- RZ
- CPI '='
- RZ
- CPI '<'
- RZ
- CPI '>'
- RZ
- ORA A ;Set zero flag on end of text
- RET
- ;
- ;
- ; Error routines:
- ;
- BADVER:
- CALL ABEND
- DB 'Can''t run under CP/M 1.4'
- DB '$'
- NODIR:
- CALL ABEND
- DB 'Library not found'
- DB '$'
- FISHY:
- CALL ABEND
- DB 'Name after "-" isn''t a library'
- DB '$'
- NOMEMB:
- CALL ABEND
- DB 'Command not in directory'
- DB '$'
- NOLOAD:
- CALL ABEND
- DB 'No program in memory'
- DB '$'
- NOFIT:
- CALL ABEND
- DB 'Program too large to load'
- DB '$'
- ;
- COMLIT: DB 'COM'
- ;
- DFLTNAM:DB 'COMMAND ' ; <---change this if you like---
- LBRLIT: DB 'LBR'
- ;
- ABEND:
- LDA ENTUSR
- MOV E,A
- CPM USR ;Reset to entry user.
- CPM MSG,NEWLIN
- POP D
- CPM MSG
- CPM DEL,SUBFILE
- CPM MSG,ABTMSG
- JMP EXIT
- ABTMSG: DB '...ABORTED.$'
- NEWLIN: DB CR,LF,'$'
- SPSAVE: DS 2 ;stack pointer save
- ;
- PAGE
- ;Adjust location counter to next 256-byte boundry
- @BASE ORG ($ + 0FFH) AND 0FF00H
- @RLBL SET 0
- ;
- ; The segment to be relocated goes here.
- ; Any position dependent (3-byte) instructions
- ; are handled by the "R" macro.
- ;*************************************************
- R <LHLD LENX> ;Get length of .COM member to load.
- MVI A,TPA/128
- ADD L ;Calculate highest address
- MOV L,A ;To see if it will fit in
- ADC H ;available memory
- SUB L
- MOV H,A
- REPT 7
- DAD H
- ENDM
- XCHG
- CALL NEGDE ;IT'S STILL IN LOW MEMORY
- R <LXI H,PROTECT>
- DAD D
- JNC NOFIT ;Haven't overwritten it yet.
- LBROPN:
- ; The library file is still open. The open FCB has been
- ; moved up here into high memory with the loader code.
- ;
- R <LHLD INDEX> ;Set up for random reads
- R <SHLD RANDOM>
- XRA A
- R <STA RANDOM+2>
- ;
- LXI H,TPA
- R <SHLD LOADDR>
-
- ; This high memory address and above, including CCP, must be
- ; protected from being overlaid by loaded program
- PROTECT:
- ;
- LOADLOOP: ;Load that sucker.
- R <LHLD LENX> ;See if done yet.
- MOV A,L
- ORA H
- R <JZ LOADED>
- DCX H
- R <SHLD LENX>
- ;
- R <LHLD LOADDR> ;Increment for next time
- MOV D,H
- MOV E,L
- LXI B,80H
- DAD B
- R <SHLD LOADDR>
- CPM DMA ;but use old value (DE)
- ;
- R <LXI D,LBRFIL>
- CPM RRD ;Read the sector
- ORA A ;Ok?
- R <JNZ ERR> ;No, bail out.
- ;
- R <LHLD RANDOM> ;Increment random record field
- INX H
- R <SHLD RANDOM>
- ;
- R <JMP LOADLOOP> ;Until done.
- ;
- ERR:
- MVI A,( JMP ) ;Prevent execution of bad code
- STA TPA
- R <LXI H,ERRX>
- SHLD TPA+1
- R <JMP LOADED> ;Execute dummy program instead
- ERRX:
- LXI H,BOOT ;One more time, but this time
- SHLD TPA+1 ;Jump to BOOT
- ;
- R <LXI D,LDMSG>
- CPM MSG
- R <LXI D,SUBFILE> ;Abort SUBMIT if in progress
- CPM DEL
- LOADED:
- R <LDA ENTUSR>
- MOV E,A
- CPM USR ;Restore USR number from setup.
- CPM DMA,TBUFF ;Restore DMA adrs for user pgm
- CPM CON,LF ;Turn up a new line on console
- JMP TPA
- ;
- LDMSG:
- DB 'BAD LOAD$'
- INDEX DW 0
- LENX DW 0
- ENTUSR DB 0
- SUBFILE:
- DB 1,'$$$ SUB',0,0,0,0
- ;If used, this FCB will clobber the following one.
- ;but it's only used on a fatal error, anyway.
- LBRFIL:
- DS 32 ;Name placed here at setup
- DB 0 ;Normal FCB plus...
- OVERLAY SET $ ;(Nothing past here but DS's)
- RANDOM DS 3 ;...Random access bytes
- MAXMEM DS 2
- LOADDR DS 2
- ;*************************************************
- ;End of segment to be relocated.
- IF OVERLAY EQ 0
- OVERLAY SET $
- ENDIF
- ;
- PAGES EQU ($-@BASE+0FFH)/256+8
- ;
- SEGLEN EQU OVERLAY-@BASE
- ORG @BASE+SEGLEN
- PAGE
- ; Build the relocation information into a
- ; bit table immediately following.
- ;
- @X SET 0
- @BITCNT SET 0
- @RLD SET ??R1
- @NXTRLD SET 2
- RGRND %@RLBL+1 ;define one more label
- ;
- REPT SEGLEN+8
- IF @BITCNT>@RLD
- NXTRLD %@NXTRLD ;next value
- ENDIF
- IF @BITCNT=@RLD
- @X SET @X OR 1 ;mark a bit
- ENDIF
- @BITCNT SET @BITCNT + 1
- IF @BITCNT MOD 8 = 0
- DB @X
- @X SET 0 ;clear hold variable for more
- ELSE
- @X SET @X SHL 1 ;not 8 yet. move over.
- ENDIF
- ENDM
- ;
- DB 0
- HOLD: DB 0,0 ;0 length, null terminator
- DS 128-2 ;rest of HOLD area
- MEMBER:
- DS 16
- ;
- END CCPIN
-