.Z80 ASEG ; ; ; program: zex ; author: richard conn (derived from ex, which was written by someone else) ; version: 3.0 ; date: 8 mar 84 ; previous versions: none ; ;Modified by Bob Logan for assembly by M80 & Z80 codes 25/4/85 ; VERS EQU 30 ZEXADR EQU 0DB00H ;address of zex running module CHANGE THIS to suit ; uour own system (needs to be 400h below ZCPR3) ; ; zcpr3 definitions ; MACLIB Z3BASE.LIB ; ; offsets to zcpr3 environment descriptor elements ; EPOFF EQU 9 ;external path data MCOFF EQU 24 ;command line data ; ; general equates ; BELL EQU 7 CTRLZ EQU 1AH ;^z DELAY EQU 6000H ;delay constant for timer loop BS EQU 'H'-'@' ;backspace CR EQU 0DH LF EQU 0AH ; ; zex monitor command bytes ; PSUP EQU 80H ;^. print suppress flag IMON EQU 81H ;^< immediate mode start IMOFF EQU 82H ;^> immediate mode stop MSUP EQU 83H ;^# zex message suppress flag CRWAIT EQU 84H ;^? zex runtime wait for cr flag REXEC EQU 85H ;^: zex runtime re-execute flag CRBWAIT EQU 86H ;^/ zex runtime ring bell and wait for cr flag RNG EQU 87H ;^* ZEX RUNTIME RING BELL UICH EQU 88H ;^" user input command char sequence IPS EQU 89H ;^& false if print suppress ; ; cp/m constants ; WARM EQU 0 BDISK EQU 4 BDOS EQU 5 DFCB EQU 5CH BUFF EQU 80H ; start of zex initiator code segment ORG 100H ; .PHASE 100H ; external ZCPR3 Environment Descriptor JP start db 'Z3ENV' ;this is a ZCPR3 Utility db 1 ;external Environment Descriptor z3eadr: dw z3env start: LD HL,(z3eadr) ;pt to ZCPR3 environment ; start of Program -- Initialize ZCPR3 Environment call z3init ;initialize the ZCPR3 Env JP START0 ; ; initial command line area ; DB 0FFH ;size of command line DBUFF: DB 0FFH ;size of buffer DS 100H ;space for command line ; ; start of zex ; START0: DB 0 ;replaced with ret to prevent reentry LD A,(DFCB+1) ;check for help request CP '/' ;help? JP Z,HELP LD (CCPSTK),SP ;ccp stack ptr LD SP,CCPSTK ;user stack area LD A,0C9H ; (8080 ret) LD (START),A ;prevent re-entrance by zcpr LD HL,BUFF ;copy input line into dbuff LD DE,DBUFF LD BC,128 ;size of buffer LDIR LD DE,SIGNON ;logo CALL PRINT CALL ZEXACTV ;check for recursion CALL ZRELOC ;relocate zex module CALL ZPARMS ;extract parameters from command line LD A,(DFCB+1) ;check to see if sub file present CP ' ' ;=no PUSH AF ;save flag CALL NZ,OPENSB ;open and load zex file if present or abort POP AF ;get flag CALL Z,INPUTSB ;input commands from user ; ; hl now points to byte after loaded text ; CALL ZMCL ;store rest of multiple command line CALL ZLINES ;copy and process command lines ; ; set up for zex execution and run; hl pts to bottom of data area ; PUSH HL ;save ptr to end of data LD HL,(RELSTRT) ;get ptr to start of zex LD (GOADR),HL ;set address to run to DEC HL ;pt to start of data area LD (Z3MSG+09H),HL ;set address of next char for zex processing LD (Z3MSG+0BH),HL ;set address of first char for zex processing LD A,0FFH ;set zex running flag LD (Z3MSG+08H),A ;zex is now running POP HL ;hl is ptr to end of data LD (HL),A ;set up end of data DEC HL LD A,(BDOS+2) ;set up bdos jump to protect data LD (HL),A DEC HL LD A,(BDOS+1) LD (HL),A DEC HL LD (HL),0C3H ;sim jump LD (BDOS+1),HL ;set new bdos address LD HL,0 ;assume no multiple commands LD A,(MCAVAIL) ;get flag OR A ;0=none JP Z,GOTOZEX ;no multiple commands, so bc=0 LD HL,(MCADR) ;get address of multiple command buffer ; ; zex monitor entry parameters -- ; hl address of multiple command buffer or 0 if none ; GOTOZEX: DB 0C3H GOADR: DW 0 ; ; init zcpr3 environment ; Z3INIT: PUSH HL ;save ptr to environment LD DE,MCOFF ;offset to cl data ADD HL,DE LD E,(HL) ;get cl address INC HL LD D,(HL) INC HL ;get cl size LD A,(HL) OR D ;if all three values are 0, then no command line OR E LD (MCAVAIL),A ;set available flag EX DE,HL ;hl pts to cl LD (MCADR),HL POP HL ;get ptr to environment LD DE,EPOFF ;offset to external path data ADD HL,DE LD E,(HL) ;get external path address INC HL LD D,(HL) LD A,D ;check for any OR E LD (EPAVAIL),A ;set available flag EX DE,HL LD (EPADR),HL ;set address RET ; ; z3init buffers ; INTPATH: ;internal path DB 1,0 ;disk a, user 0 DB 0,0 ;end of path MCAVAIL: ;multiple command line data DB 0 MCADR: DW 0 EPAVAIL: ;external path data DB 0 EPADR: DW 0 ; ; print help message for zex ; HELP: LD DE,SIGNON ;print banner CALL PRINT LD HL,HMSG ;print message CALL HPRINT LD C,1 ;get char CALL BDOS CP 'C'-'@' ;^c? RET Z LD DE,CRLFS CALL PRINT LD DE,SIGNON CALL PRINT LD HL,HMSG0 CALL HPRINT LD C,1 ;get char CALL BDOS CP 'C'-'@' ;^c? RET Z LD DE,CRLFS CALL PRINT LD DE,SIGNON CALL PRINT LD HL,HMSG1 HPRINT: LD A,(HL) ;get char OR A ;done? RET Z INC HL ;pt to next PUSH HL ;save ptr LD E,A ;char in e LD C,2 ;console output CALL BDOS POP HL ;get ptr JR HPRINT HMSG: DB CR,LF,LF DB 'ZEX is an indirect command file processing facility, similar' DB CR,LF,'to the standard CP/M SUBMIT facility and the other ' DB 'ZCPR2' DB CR,LF,'indirect command file processing facility, SUB2.' DB CR,LF,'The major difference between the SUBMIT-like programs' DB CR,LF,'and ZEX is that ZEX is memory-based, storing a command' DB CR,LF,'processor and the interpreted command file itself in' DB CR,LF,'memory, just under ZCPR2.' DB CR,LF,LF DB 'There is a basic tradeoff to be considered when using ZEX' DB CR,LF,'as opposed to SUB2. Since ZEX is memory-based, it ' DB 'offers' DB CR,LF,'the advantage of greatly increased operating speed ' DB 'over' DB CR,LF,'SUB2. Also, ZEX intercepts all input unless user ' DB 'input' DB CR,LF,'is explicitly enabled (the ^" command), in which case' DB ' the user' DB CR,LF,'is allowed to enter text from his console during a ' DB 'ZEX run.' DB CR,LF,'SUB2, on the other hand, inputs from the command file' DB ' only' DB CR,LF,'at the command line prompt unless XSUB is active. ZEX' DB ' acts like' DB CR,LF,'SUB2 and XSUB combined. The only bad feature of ZEX is' DB ' that' DB CR,LF,'ZEX significantly shortens the TPA work area, so ' DB 'programs which' DB CR,LF,'require a lot of memory may have trouble running under' DB ' ZEX.' DB CR,LF,'This is why SUB2 is provided to the ZCPR2 user along ' DB 'with ZEX.' DB CR,LF,LF,'Strike Any Key to Continue, ^C to Abort - ',0 HMSG0: DB CR DB LF,LF,'ZEX is invoked by one of the following command lines --' DB CR,LF DB CR,LF,' ZEX ' DB CR,LF,'or' DB CR,LF,' ZEX' DB CR,LF DB CR,LF,'The first form executes the indicated command file' DB CR,LF,'( may be of type ZEX or SUB, and if a ZEX and' DB ' SUB both' DB CR,LF,'exist, the ZEX file is used), passing to it the ' DB 'indicated ' DB CR,LF,'parameters, similar to the way SUBMIT is used.' DB CR,LF DB CR,LF,'The second form allows the user to enter a series of ' DB 'commands.' DB CR,LF,'ZEX presents the user with a prompt like "n:", where' DB CR,LF,'n is a line number, and the user may enter any command' DB CR,LF,'line. Input is terminated by simply striking the' DB CR,LF,'RETURN key.' DB CR,LF,LF,'ZEX can be aborted by ^C from console.' DB CR,LF,LF,'The following screen displays the ZEX control codes.' DB CR,LF,LF,'Strike Any Key to Continue, ^C to Abort - ',0 HMSG1: DB CR,LF,LF DB ' **** ZEX Embedded Command Processing Facility ****' DB CR,LF,LF DB 'ZEX supports an enhanced command processing facility which ' DB 'includes the' DB CR,LF,'following escaped character commands which may be' DB CR,LF,'embedded in the text of the command file or user' DB CR,LF,'input and will be executed after the command run begins' DB ' --' DB CR,LF DB CR,LF,' Cmd Meaning Cmd Meaning' DB CR,LF,' | insert ^| insert ' DB CR,LF,' ^: rerun command file ^. suppress print of chars' DB CR,LF,' ^# toggle ZEX msgs ^$ define default params' DB CR,LF,' ^? wait for user ^/ ring and wait for ' DB CR,LF,' ^* ring bell ^" allow user input' DB CR,LF,' ^< display chars only ^> stop display' DB CR,LF,' ;; zex comment $n 1<=n<=9 for param' DB CR,LF,' $$ =$ $^ =^' DB CR,LF,' $| =| ^c insert ctrl char c' DB CR,LF,LF,LF,LF,0 ; ; relocate zex module into high memory just below zcpr2 ; ZRELOC: ;***** LD HL,REST LD BC,RELE LD DE,ZEXADR PUSH DE ;save load address LDIR POP HL ;get back load address in hl LD (RELSTRT),HL ;save ptr DEC HL ;relocate program-1 LD (OUTBUF),HL ;save ptr to byte in front of relocated program RET ; ; get parameters from command line ; terminate each parameter with a binary zero, and set pointers ; to each parameter ; ZPARMS: LD DE,DBUFF ;terminate command line with cr LD A,(DE) ;get char count INC DE ;pt to first char PUSH DE LD L,A ;hl = number of chars in line LD H,0 ADD HL,DE ;pt to after last char LD (HL),CR ;store LD HL,PRMDMY ;start at dummy parameter for .sub file spec PUSH HL LD BC,PRMPNL+2 XOR A CALL FILL ;clear ptr area POP HL ;get ptr to pointer for parameter 0 POP DE ;get ptr to first char in line LD A,PRMPNL/2+1 ;number of parameters possible, max LD (PRMMAX),A ;highest parameter # + 1 for .SUB SPEC ; ; parameter extraction routine hl pts to first param ptr, de pts to line ; PARMS: LD B,0 ;clear parameter counter LD (ERRLNE),DE ;save in case of error ; PARMSL: LD A,(DE) ;ignore leading spaces INC DE CP CR JR Z,ENDLNE CP ' ' JR Z,PARMSL DEC DE ;back up to 1st char LD (HL),E ;save address in table INC HL LD (HL),D INC HL INC B ;count+1 LD A,(PRMMAX) CP B JP C,PRMTOO ;too many arguments ; ENDPRM: LD A,(DE) ;go to end of parameter INC DE CP CR JR Z,ENDLNE CP ' ' ;skip until JR NZ,ENDPRM XOR A ;a=0 to terminate param DEC DE ;pt to following param LD (DE),A ;terminate parameter INC DE ;pt to char after JR PARMSL ;ignore spaces between parameters ENDLNE: XOR A ;store zero after last parameter DEC DE ;pt to cr LD (DE),A ;terminate last parameter INC DE ;pt to after last param LD A,CR ;store ending cr LD (DE),A RET ; ; input command lines from user ; INPUTSB: LD HL,0 LD (LINES),HL ;start line counter LD A,0FFH ;set buffer length LD (DBUFF-1),A LD HL,BEGREL ;set up output buffer LD (INBUF),HL GETLIN: CALL CRLF LD HL,(LINES) INC HL LD (LINES),HL CALL DECOUT ;print line # LD E,':' ;get prompt CALL OUTCHR LD E,' ' CALL OUTCHR LD DE,DBUFF-1 LD C,10 ;read console buffer CALL BDOS LD DE,DBUFF LD A,(DE) ;get length LD B,A INC DE LD HL,(INBUF) ;get input pointer OR A ;see if end RET Z ;done with input EX DE,HL CALL MOVE ;move to input buffer EX DE,HL LD (HL),CR INC HL LD (HL),LF INC HL LD (INBUF),HL JR GETLIN ; ; open and load sub file ; OPENSB: CALL PUTUD ;save user/disk ; ; set up to read zex file ; LD DE,DFCB+9 LD HL,ZEXNAM ;move 'sub' to dfcb file type LD BC,3 LDIR XOR A ;zero cr field LD (DFCB+32),A LD DE,BUFF ;set dma address LD C,26 ;set dma CALL BDOS LD DE,DFCB LD HL,INTPATH ;pt to internal path LD A,(EPAVAIL) ;external paths available? OR A ;0=no JR Z,OSB1 ;use internal path LD HL,(EPADR) ;pt to external path OSB1: PUSH HL ;save path ptr CALL FNDFILE ;look for file along path and say if it is found POP HL ;get path ptr JP NZ,READSB ; ; zex file not found -- set up to read sub file ; PUSH HL ;save path ptr CALL GETUD ;restore user/disk LD DE,DFCB+9 ;set type to sub LD HL,SUBNAM LD BC,3 LDIR XOR A ;zero cr field LD (DFCB+32),A POP HL ;pt to path LD DE,DFCB ;pt to fcb CALL FNDFILE ;look for file JP NZ,READSB RSBERR: CALL GETUD ;restore user/disk LD HL,NOSBF2 LD DE,DFCB+1 LD B,8 ;name length CALL MOVEFN ;move file name LD B,3 ;type length LD (HL),'.' INC HL LD DE,DFCB+9 ;file type pointer CALL MOVEFN ;move file type LD (HL),'$' ;end terminater JP NOSUB ;* ;* FNDFILE -- LOOK FOR FILE ALONG ZCPR3 PATH ;* INPUT PARAMETERS: HL = BASE ADDRESS OF PATH, DE = PTR TO FCB OF FILE ;* OUTPUT PARAMETERS: A=0 AND ZERO FLAG SET IF NOT FOUND, NZ IF FOUND ;* FNDFILE: LD (PATH),HL ;save path base address LD C,17 ;search for first CALL BENTRY ;look for file INC A ;set flag JP NZ,FF5 ;found it -- return found flag EX DE,HL ;hl=fcb ptr LD (FCBPTR),HL ;save it LD HL,(PATH) ;pt to path for failure possibility LD C,32 ;get current user LD E,0FFH CALL BENTRY LD (TMPUSR),A ;save it for later ; ; main search loop ; FF1: LD A,(HL) ;get drive AND 7FH ;mask msb OR A ;0=done=command not found JR NZ,FF2 ;no error abort? ; ; file not found error ; XOR A ;zero flag means not found RET ; ; look for command in directory pted to by hl; drive in a ; FF2: LD E,A ;disk in e CP '$' ;current disk? JR NZ,FF3 ;skip default drive selection if so LD A,(BDISK) ;get default user/disk AND 0FH ;mask for default disk INC A ;prep for following dcr a LD E,A ;disk number in e FF3: DEC E ;adjust path 1 to 0 for a, etc LD C,14 ;select disk fct CALL BENTRY ;select drive INC HL ;pt to user number LD A,(HL) ;get user number AND 7FH ;mask out msb INC HL ;pt to next entry in path PUSH HL ;save ptr LD E,A ;save in e CP '$' ;match? JR NZ,FF4 ;do not select current user if so LD A,(TMPUSR) ;get original user number LD E,A ;select user FF4: LD C,32 CALL BENTRY LD HL,(FCBPTR) ;get ptr to fcb EX DE,HL ;... in de LD C,17 ;search for first CALL BENTRY ;look for file POP HL ;get ptr to next path entry INC A ;set flag JR Z,FF1 ;continue path search if search failed ; ; file found -- perform system test and proceed if approved ; FF5: LD A,0FFH ;set ok return OR A RET ; ; bdos routine ; BENTRY: PUSH HL ;save regs PUSH DE PUSH BC CALL BDOS POP BC ;get regs POP DE POP HL RET ;* BUFFERS FCBPTR: DS 2 ;pointer to fcb for file search TMPUSR: DS 1 ;current user number PATH: DS 2 ;base address of path ; ; putud -- save away current user/disk ; getud -- restore current user/disk ; PUTUD: LD E,0FFH ;get current user LD C,32 ;bdos CALL BDOS LD (CUSER),A ;save current user away LD C,25 ;get current disk CALL BDOS LD (CDISK),A RET GETUD: LD A,(CDISK) ;get current disk LD E,A ;... in e LD C,14 ;select disk CALL BDOS LD A,(CUSER) ;get current user LD E,A ;... in e LD C,32 ;select user CALL BDOS RET CDISK: DS 1 ;current disk number CUSER: DS 1 ;current user number ; ; open and read sub file ; READSB: LD C,15 ;open file CALL BDOS ;bdos INC A ;error? JP Z,RSBERR ; ; read in and store sub file ; READTX: LD HL,(INBUF) ;get ptr to next byte EX DE,HL ;set ptr in de LD HL,80H ;get sector offset ADD HL,DE ;hl pts to following block to be read, de pts to LD (INBUF),HL ; block to read; save ptr to following block LD C,26 ;set dma address CALL BDOS LD DE,DFCB LD C,20 ;read sequential CALL BDOS OR A JR Z,READTX ;read complete .sub file CALL GETUD ;restore current user/disk LD HL,(INBUF) ;make sure buffer's terminated LD DE,-100H ;pt to first byte of last block read ADD HL,DE LD B,80H ;look at at most 80h bytes SKIP1A: LD A,(HL) ;get byte CP CTRLZ ;eof? JR Z,SKIP1B INC HL ;pt to next DEC B ;count down JR NZ,SKIP1A ; hl now points to after last valid char in file SKIP1B: LD (INBUF),HL ;set ptr RET ;done with no error ; ; this part of the code stores the rest of the command line as part of the ; command file for zcpr2; on entry, hl pts to next available byte ; ZMCL: EX DE,HL ;buffer pted to by de LD HL,(MCADR) ;get base address of multiple command line LD A,(HL) ;get low INC HL LD H,(HL) ;get high LD L,A ;hl pts to next char in multiple command line EX DE,HL ;de pts to next char in command line, hl pts to buf end LD A,(MCAVAIL) ;multiple commands enabled? OR A ;0=no JR Z,ENDSTR ;terminate file; hl pts to next byte LD A,(DE) ;get first byte LD B,A ;save first byte in b XOR A ;a=0 LD (DE),A ;clear command line INC DE ;pt to next byte LD A,B ;get first byte CP ';' ;separation char? JR NZ,CMCMD1 ;process if not ; ; loop to store rest of multiple command line into loaded file ; CMCMD: LD A,(DE) ;get byte from line CMCMD1: OR A ;eol if zero JR Z,CMEND ;read in file; hl pts to next available byte LD (HL),A ;store byte INC HL ;pt to next INC DE JR CMCMD CMEND: LD (HL),CR ;store INC HL LD (HL),LF INC HL ;pt to next available byte ; ; mark end of buffer and continue ; ENDSTR: LD (HL),1AH ;eof character LD (ENDBUF),HL ;eob address LD A,L SUB LOW BEGREL+1 ;see if buffer's empty LD A,H SBC A,HIGH BEGREL JP C,BUFLOW RET ; ; copy and process command lines, placing final command line form under zex ; return with hl pting to next available byte in memory buffer under zex ; ZLINES: XOR A LD (IMFLG1),A LD (IMFLG2),A LD (PRTFLG),A LD (OUTCNT),A LD HL,1 LD (LINES),HL ;set line count LD HL,(OUTBUF) ;pt to byte just below loaded zex LD (OUTLNE),HL LD (BUFSTR),HL LD DE,BEGREL ;pt to first byte of command buffer ; ; main copy loop to copy buffer at begrel to just under zex with processing ; MOVSTR: LD A,(DE) ;get next command byte INC DE ;pt to following AND 7FH ;make sure no parity CP LF ;new line? JR NZ,MOVST0 ; ; new line -- don't store and increment line count ; MOVSTX: CALL INCR ;increment line count JR MOVSTR ;continue ; ; begin character processing ; a contains char, de pts to byte after char, hl pts to next buffer pos ; MOVST0: CP 1AH ;end of input? RET Z ;done if so CP '|' ;carriage return? JR NZ,MOVST1 ;nope ; ; process carriage return form (|) ; PUSH DE ;save old pointer INC DE ;look for eof after | (pt to lf) INC DE ;pt to possible eof LD A,(DE) ;get present location+2 POP DE ;get old pointer CP 1AH ;end of buffer RET Z ;end, so no following LD A,CR ;make char a CALL INCR ;increment lines for errors JR MOVST4 ;store in a ; ; check for non-cr forms ; at this point, de pts to next char in line and hl pts to next ; byte in buffer (moving down) ; MOVST1: LD C,A ;save char in c LD A,(IMFLG1) CP IMON ;immediate mode on ? LD A,C ;get char back JR Z,MOVST2 ;yes..skip zex comment processing CP ';' ;first ';'? JP Z,EXCOMM ;process possible zex comment MOVST2: CP '^' ;control char? JR Z,MOVST5 ;convert control characters CP '$' ;parameter or control char? CALL Z,GTPARM ;substitute command parameter or control char. MOVST3: LD (LCHR),A ;save last char entered CP CR ;=cr? JR NZ,MOVST4 LD C,A ;save char temporarily LD A,(OUTCNT) ;get char output flag OR A ;any char? LD A,C JR Z,MOVSTR ;no..use input cr only if other non-control ; characters in current line ; place char in buffer ; char in a, hl pts to buffer loc ; MOVST4: CALL CHRSTR ;add to buffer CALL CNTINC ;increment count JR MOVSTR ; ; prefix was an uparrow (^), so process control chars ; MOVST5: CALL GETCMD ;validate control characters CP ':' JR Z,REXC ;re-execute CP '?' JR Z,GCRW ;cr wait CP '/' JR Z,GCRBW ;ring bell and wait for CP '"' JR Z,UISET ;user input CP '*' JR Z,GRNG ;continually ring bell while waiting for CP '|' JR Z,GCRLF ;cr,lf generation CP '$' JR Z,PRMDEF ;default parameters' line CP '.' JP Z,PRTSUP ;print suppress toggle CP '#' JP Z,MSGSUP ;message suppress toggle CP '<' JP Z,IMPRTY ;immediate mode start CP '>' JP Z,IMPRTN ;immediate mode stop CP '&' JR Z,IFPSUP ;print suppress during false if MVST3: JR MOVST3 ;other control codes ; IFPSUP: LD A,IPS ;convert '^&' to if print suppress flag JR MVST3 ; REXC: LD A,REXEC ;convert '^:' to re-execute flag JR MVST3 ; GCRW: LD A,CRWAIT ;convert '^?' to crwait flag JR MVST3 ; GCRBW: LD A,CRBWAIT ;convert '^/' to crbwait flag JR MVST3 ; ; allow user input from now on, but first skip out rest of line ; UISET: LD A,(DE) ;get next char AND 7FH ;mask it CP LF ;done? JR Z,UISET1 CP 1AH ;eof? JR Z,UISET1 INC DE ;pt to next char JR UISET ;continue skipping UISET1: LD A,UICH ;control char JR MVST3 ; GRNG: LD A,RNG ;convert '^*' TO RNG FLAG JR MVST3 ; GCRLF: LD A,CR ;generate cr & lf CALL CHRSTR LD A,LF CALL CHRSTR LD (LCHR),A JP MOVSTR ; PRMDEF: PUSH HL LD HL,PRMDFP PUSH HL LD BC,PRMDFL XOR A CALL FILL ;clear ptr table POP HL LD A,PRMDFL/2 LD (PRMMAX),A ;highest parameter # CALL PARMS ;build default parameters ptrs POP HL INC DE ;skip cr LD A,LF JP MOVSTX ;continue at eol ; ; check to see if previous char was also a ; and flush as zex comment if so ; EXCOMM: PUSH HL LD HL,LCHR ;pt to previous char CP (HL) ; double ;? LD (HL),A ;store current char as previous char POP HL JP NZ,MOVST3 ;no...continue LD C,A ;save char LD A,(PRTFLG) CP PSUP LD A,C JP Z,MOVST3 ;print suppress LD A,(IMFLG1) CP IMON LD A,C JP Z,MOVST3 ;immediate mode INC HL ;yes..ignore previous ; PUSH HL LD HL,LCHR LD A,(OUTCNT) DEC A ;drop 1 char. LD (OUTCNT),A EXCOML: LD A,(DE) ;ignore characters until eof or lf INC DE CP 1AH ;eof JR Z,EXCOMX CP LF ;line feed JR NZ,EXCOML LD (HL),A LD A,(OUTCNT) OR A ;any char. on this line? JR Z,EXCOM2 ;no...skip cr EXCOM1: POP HL ;yes..force cr LD A,CR CALL CHRSTR LD A,LF JP MOVSTX ;continue ; EXCOM2: POP HL LD A,LF JP MOVSTX ;continue ; EXCOMX: POP HL RET ;return to main flow, with hl pting to next byte ; MSGSUP: LD A,MSUP ;convert '^#' to message suppress flag JP MOVST3 ; PRTSUP: LD A,PSUP ;convert '^.' to print suppress flag PUSH HL LD HL,PRTFLG CP (HL) ;already on? JR NZ,PRTSST ;no...set flag XOR A ;yes..clear flag PRTSST: LD (HL),A ;set/reset flag POP HL LD A,PSUP JP MOVST3 ; IMPRTY: LD A,IMON ;convert '^<' to immediate mode start LD (LCHR),A PUSH HL LD HL,IMFLG1 CP (HL) ;already on? POP HL JP Z,MOVSTR ;yes.. LD (IMFLG1),A LD (IMFLG2),A JP MOVST3 ;no... ; IMPRTN: LD A,IMOFF ;convert '^>' to immediate mode stop LD (LCHR),A PUSH HL LD HL,IMFLG2 CP (HL) ;already off? POP HL JP Z,MOVSTR ;yes.. LD (IMFLG2),A LD (IMFLG1),A JP MOVST3 ;no... ; ; place char in buffer; a=char, hl pts to buffer loc ; CHRSTR: PUSH AF ;check for input/zex buffer overlap PUSH DE PUSH HL LD HL,(ENDBUF) EX DE,HL POP HL LD A,L CP E JR NZ,CHRSTX ;lsb<> LD A,H CP D JP Z,OVERL ;msb=, overlap will occur/abort zex ; ; add char to zex's buffer ; CHRSTX: POP DE ;add char. to zex's buffer POP AF LD (HL),A ;store char DEC HL ;pt to next location (moving down) RET ; ; check to see if zex is already active, and abort if so ; ZEXACTV: LD A,(Z3MSG+08H) ;zex running? OR A ;0 if no RET Z LD DE,ZEXACT CALL PRINT ;zex already present ; ; abort and return to zcpr2 ; CCPRET: LD SP,(CCPSTK) ;restore stack RET ;return to ccp ; ; error exits ; GETERR: LD DE,CMDER ;control character invalid CALL PRINT JP LINE ;print line # and line and exit ; NUMERR: LD DE,NONUM ;excessive number CALL PRINT JP LINE ;print line # and line and exit ; PRMERR: LD DE,PMERR CALL PRINT JP LINE ;print line # and line and exit ; PRMTOO: LD DE,TOOARG ;too many parameter arguments CALL PRINT LD HL,(ERRLNE) CALL EPRT ;print parameter line JR CCPRET ; BUFLOW: LD DE,BUFMTY ;text buffer empty CALL PRINT JR CCPRET ; NOSUB: LD DE,NOSBF1 ;.sub file not found CALL PRINT LD DE,NOTHER CALL PRINT JR CCPRET ; OVERL: LD DE,OVERLP ;input/zex buffer overlap CALL PRINT JP LINE ; ; subroutines ; ; control codes 0-1fh ; with support for $ . # < > ; GETCMD: LD A,(DE) ;get next character INC DE ;increment pointer CP '|' RET Z ;cr,lf generation CP 'a'-1 ;lowercase? JR C,GETUPR ;nope CP 'z'+1 ;a-z? JP NC,GETERR ;nope SUB 'a'-'A' ;get to uppercase GETUPR: CP '@' ;0-1fh control code? JR NC,GETCC CP ':' RET Z ;re-execute CP '?' RET Z ;cr wait CP '/' RET Z ;cr wait and ring bell CP '*' RET Z ;ring bell CP '"' RET Z ;user input CP '$' RET Z ;default parameters' line CP '.' RET Z ;print suppress toggle CP '#' RET Z ;message suppress toggle CP '<' RET Z ;immediate mode start CP '>' RET Z ;immediate mode stop CP '&' RET Z ;false if print suppress JP GETERR GETCC: SUB '@' ;get control code RET NC JP GETERR ; ; extract parameter element whose $n specification is pointed to by de ; de pts to char after the $ ; buffer to place resulting parameter is pted to by hl ; GTPARM: LD A,(DE) ;get char after the $ INC DE ;pt to next char CP '$' ;if double $, then store as $ RET Z CP '^' ;up arrow RET Z CP '|' ;carriage return RET Z CP '1' ;check for valid digit (1-9) JP C,PRMERR CP '9'+1 ;range error? JP NC,PRMERR SUB '1' ;get actual # (zero relative) ADD A,A ;double for offset LD (PRMNUM),A PUSH DE ;save ptrs PUSH HL LD HL,PRMPNT ;pt to parameter ptr table CP PRMPNL-1 ;parameter number within range? JP NC,NOPARM ;> highest # LD E,A LD D,0 ADD HL,DE LD E,(HL) ;get parameter pointer INC HL LD D,(HL) POP HL ;restore ptr to next byte in output buffer below zex LD A,E ;any param? OR D JR Z,NOPARM ;no parameter present, try defaults ; ; move parameter pted to by de into buffer below zex, 1st byte pted to by hl ; MOVPRM: LD A,(DE) ;get parameter char INC DE ;pt to next OR A ;done? JP Z,ENDPAR CALL CHRSTR ;store chars JR MOVPRM ; ; parameter placed in memory -- continue ; ENDPAR: POP DE ;get ptr to next char in line POP AF ;clear stack JP MOVSTR ;resume processing ; ; no parameter pted to ; NOPARM: PUSH HL ;save ptr to next byte in buffer below zex LD HL,PRMDFP ;try default parameters LD A,(PRMNUM) CP PRMDFL-1 JP NC,NUMERR ;> highest # LD E,A LD D,0 ADD HL,DE LD E,(HL) ;get parameter pointer INC HL LD D,(HL) POP HL LD A,E OR D JR NZ,MOVPRM ;move parameter into buffer JR ENDPAR ;resume with no parameter ; MOVEFN: LD A,(DE) CP ' ' ;see if space RET Z LD (HL),A INC DE ;increment pointers INC HL DJNZ MOVEFN RET ; ; increment line count, and affect only hl (must not affect a) ; INCR: PUSH HL ;save output pointer LD HL,(LINES) INC HL ;increment line counter LD (LINES),HL LD HL,LCHR ;clear last character LD (HL),0 LD HL,OUTCNT ;clear character count LD (HL),0 LD L,E ;de=hl LD H,D LD (BEGLIN),HL POP HL LD (OUTLNE),HL ;save new output line RET ; CNTINC: CP ' ' ;control character? RET C ;yes.. CP UICH ;user input char? JR Z,CNTIN1 AND 80H ;special control? RET NZ ;yes.. LD A,(PRTFLG) CP PSUP ;print suppress flag? RET Z ;yes.. LD A,(IMFLG1) CP IMON ;immediate mode? RET Z ;yes.. CNTIN1: LD A,(OUTCNT) INC A LD (OUTCNT),A RET ; PRINT: LD C,9 ;print string at (de) JP BDOS ; EPRT: LD A,(HL) ;print parameter line at (hl) CP CR RET Z CP 0 JR NZ,EPRT1 LD A,' ' EPRT1: INC HL PUSH HL LD E,A LD C,2 CALL BDOS POP HL JR EPRT ; CRLF: LD DE,CRLFS ;print cr/lf JP PRINT ; LINE: LD DE,LINEM ;print line # and line in error and exit CALL PRINT LD HL,(LINES) CALL DECOUT ;print line # CALL CRLF LD HL,(BEGLIN) PUSH HL ;save begging pointer FINDCR: LD A,(HL) INC HL CP 1AH ;end of buffer JR Z,FOUND CP CR JR NZ,FINDCR FOUND: LD (HL),0 ;end of string POP HL ;start of string CALL PRNTHL ;print bad line JP CCPRET ;thats all folks ; PRNTHL: LD A,(HL) ;print line at (hl) INC HL OR A RET Z LD E,A PUSH HL ;save pointer CALL OUTCHR POP HL ;get pointer back JR PRNTHL ; OUTCHR: LD C,2 ;print character in e JP BDOS ; DECOUT: PUSH HL ;print decimal line number PUSH DE PUSH BC LD BC,-10 ;radix for conversion LD DE,-1 ;this becomes no divided by radix DX: ADD HL,BC ;subtract 10 INC DE JP C,DX LD BC,10 ADD HL,BC ;add radix back in once EX DE,HL LD A,H OR L ;test for zero CALL NZ,DECOUT ;recursive call LD A,E ADD A,'0' ;convert from bcd to hex LD E,A ;to e for output LD C,2 CALL BDOS POP BC ;restore registers POP DE POP HL RET ; MOVE: LD A,(HL) ;move string at (hl) to (de) for length in b INC HL LD (DE),A INC DE DJNZ MOVE RET ; FILL: PUSH DE ; fill storage at (hl) with character in a LD E,A ; for length in bc LD A,B OR C LD A,E POP DE RET Z DEC BC LD (HL),A INC HL JR FILL ; ; working storage area ; SUBNAM: DB 'SUB' ZEXNAM: DB 'ZEX' LINEM: DB ' Error Line # $' ZEXACT: DB CR,LF,' ZEX Already Present$' BUFMTY: DB CR,LF,'Text Buffer Empty$' OVERLP: DB CR,LF,'Input/ZEX Buffer Overlap$' NONUM: DB CR,LF,'Parameter Number out of range$' NOPRM: DB CR,LF,'No Parameter or Default Parameter$' PMERR: DB CR,LF,'Parameter$' NOSBF1: DB CR,LF,'File ' NOSBF2: DB 'filename.typ$' NOTHER: DB ' not there$' CMDER: DB CR,LF,'Control character$' TOOARG: DB CR,LF,'Too many arguments - $' SIGNON: DB 'ZEX, Version ' DB VERS/10+'0','.',(VERS MOD 10)+'0','$' CRLFS: DB CR,LF,'$' ; DS 80 ;stack space CCPSTK: DW 0 ;ccp stack ptr IMFLG1: DB 0 ;=imon encountered IMFLG2: DB 0 ;=imoff encountered PRTFLG: DB 0 ;=psup on LCHR: DB 0 ;last character read PRMMAX: DB 0 ;highest parameter # PRMNUM: DB 0 ;current $<1-9> number * 2 (ZERO RELATIVE) ERRLNE: DW 0 BITMAP: DB 0 ;present offset bit's COUNT: DB 0FFH ;present offset bit count BEGLIN: DW BEGREL ;beginning of old line pointer LINES: DW 1 INBUF: DW BEGREL ENDBUF: DW 0 ;end of input buffer OUTCNT: DB 0 OUTLNE: DW 0 RELSTRT: DW 0 OUTBUF: DW 0 BUFSTR: DW 0 RELOCL: DW 0 ;length of reloc program (filled in by sid) PRMDFP: ;default parameter ptrs DS 18 PRMDFL EQU $-PRMDFP PRMDMY: DW 0 ;dummy parameter for .sub file spec. PRMPNT: ;command line parameter ptrs DS 18 PRMPNL EQU $-PRMPNT PATCH: ;patch area REPT 32 DB 'p' ENDM DS 60 BEGREL: DS 0 ;reloc program starts here (also used as buffer) ; ; ENDIF ; ; end of zex initiator code segment ; ;*****************ª STARÔ OÆ ZEØ ******************* ; ; start of zex relocated code segment ; hl pts to multiple command buffer ; or hl=0 if no multiple commands ; REST EQU $ ; .DEPHASE .PHASE ZEXADR ;???? ZEX: LD (EXMBASE),HL ;save address of mcl buffer LD HL,(Z3MSG+09H) ;pt to next char LD A,(HL) ;get 1st char CP MSUP ;1st char=message suppress? JR NZ,ZEX1 ;no... DEC HL ;yes..skip character LD (Z3MSG+09H),HL ;set ptr to next char LD (MSUPFL),A ;set initial flag ZEX1: LD SP,MEMTOP LD HL,(BDOS+1) ;get warm jump for standard ccp LD (MEMTOP),HL ;set ptr to top of memory INC HL LD E,(HL) ;de = address of actual bdos INC HL LD D,(HL) EX DE,HL ;hl pts to actual bdos LD A,H ;subtract 8 for ccp entry point SUB 8 LD H,A LD L,3 ;set up for warm ccp jump LD (CCPJMP),HL LD HL,(WARM+1) ;save warm boot address LD (WARMPT),HL LD DE,BSWARM ;save old bios jumps LD BC,12 LDIR ;move bios jumps LD DE,(WARMPT) LD HL,LOCJMP ;store new bios jumps LD BC,12 LDIR ;move new bios jumps to bios area ; ; zex runtime bios intercept routines ; NWARM: LD SP,MEMTOP LD HL,(Z3MSG+09H) ;see if we're at buffers end LD A,(HL) CP 0FFH ;test it JP Z,WARMX ;warm return LD HL,(WARMPT) ;set warm boot address LD (WARM+1),HL LD HL,(MEMTOP) ;set bdos entry address LD (BDOS+1),HL LD DE,BUFF ;dma address LD C,26 ;set dma CALL BDOS LD A,(BDISK) LD C,A LD HL,(CCPJMP) JP (HL) ;goto console processor ; ; jmp table to overlay bios with new zex-based jumps ; LOCJMP: JP NWARM ;warm JP BCONST ;const JP NCONIN ;conin JP NCONOT ;conot ; ; console input intercept routine ; NCONIN: LD HL,Z3MSG+7 ;pt to zex message byte LD A,(HL) ;get zex message CP 2 ;suspend intercept? JP Z,BCONIN ;get input via bios if user input active CP 1 ;prompt just printed? JR NZ,NCONNP LD (HL),0 ;clear zex message LD HL,STARTM ;print message CALL PMSG ; lda pmchr ;print prompt char ; mov c,a ; call bconot NCONNP: LD A,(Z3MSG+08H) ;is zex running? OR A ;0=no JP Z,WARMX ;abort zex if not LD (CONSTK),SP LD SP,MEMTOP ;set user stack NCONNL: CALL BCONST ;get console status OR A JP Z,GETBUF ;get character from buffer CALL BCONIN ;get character CP 'C'-'@' ;see if terminate character JP Z,ZEXABRT CP 'S'-'@' ;13h JR NZ,NCONEX CALL BCONIN ;wait for next character AND 7FH LD HL,(Z3MSG+09H) ;pt to next char INC HL LD (HL),A LD (Z3MSG+09H),HL ;reset ptr LD A,'S'-'@' ;13h NCONEX: LD SP,(CONSTK) ;restore caller's stack RET ; ; return next char from input buffer ; GETBUF: LD A,(IPSUPFL) ;combine psupfl and ipsupfl to set print flag OR A ;0=no suppress JR Z,GBUF0 LD HL,Z3MSG+1 ;pt to if flag LD A,(HL) ;get if flag OR A ;no if? JR Z,GBUF0 INC HL AND (HL) ;set if state JR NZ,GBUF0 ;current if is true LD A,0FFH ;suppress print LD (OUTFLG),A JR GBUF1 GBUF0: LD A,(PSUPFL) ;set print suppress flag for nconot LD (OUTFLG),A GBUF1: CALL GETCHR ;get next character CP UICH ;user input? JP Z,UISTRT ;yes..set user input pending flag CP REXEC ;re-execute? JP Z,REXECR ;yes..reset buffer ptr CP CRWAIT ;cr wait? JP Z,CRWRTN ;yes..wait for cr CP CRBWAIT ;cr wait with ring bell? JP Z,CRBWRTN ;yes..wait for cr and ring bell CP RNG ;ring bell? JP Z,RNGBELL ;yes..just ring the bell CP MSUP ;message suppress flag? JP Z,MSUPCK ;yes..toggle flag CP PSUP ;print suppress ? JP Z,PSUPCK ;yes..toggle flag CP IPS ;false if print suppress? JP Z,IPSUPCK CP IMON ;immediate mode start ? JP Z,IMFLGS ;yes..set flag CP IMOFF ;immediate mode stop? JP Z,IMFLGS ;yes..reset flag CP CR ;cr? JR NZ,GETEXT ;no...exit ; ; cr, so reset print suppression based only on ipsupfl ; LD A,(IPSUPFL) ;combine psupfl and ipsupfl to set print flag OR A ;0=no suppress JR Z,GBUF2 LD HL,Z3MSG+1 ;pt to if flag LD A,(HL) ;get if flag OR A ;no if? JR Z,GBUF2 INC HL AND (HL) ;set if state JR NZ,GBUF2 ;current if is true LD A,0FFH ;suppress print LD (OUTFLG),A LD A,CR JR GETEXT GBUF2: XOR A LD (OUTFLG),A ;yes..reset print suppression LD A,CR GETEXT: LD C,A LD A,(IMFLG) CP IMON ;immediate mode ? LD A,C JP NZ,NCONEX ;no...return to caller with char CALL BCONOT ;yes..immediate echo to console JP NCONNL ;...loop until imoff ; ; ^" command ; UISTRT: LD A,2 ;set message to suspend intercept LD (Z3MSG+7),A LD SP,(CONSTK) ;restore caller's stack JP NCONIN ;get char from user for now ; ; ^: command ; REXECR: LD HL,(Z3MSG+0BH) ;start at top of buffer again LD (Z3MSG+09H),HL XOR A LD (IMFLG),A ;reset all flags LD (PSUPFL),A LD (IPSUPFL),A LD (MSUPFL),A JP NCONNL ;...loop until ^c ; ; ^? command ; CRWRTN: CALL BCONIN ;get input char CP 'C'-'@' JP Z,ZEXABRT ;=^c CP CR JR Z,CRWRTX ;= CP ' ' JR Z,CRWRTX ;= LD C,BELL CALL BCONOT ;<>cr JR CRWRTN ; ; ^/ command ; CRBWRTN: LD HL,DELAY ;set counter CRBWR1: PUSH HL ;save counter CALL BCONST ;check status POP HL ;get counter OR A ;set flags JR NZ,CRBWR2 DEC HL ;count down LD A,H ;done? OR L JR NZ,CRBWR1 LD C,BELL ;ring bell CALL BCONOT JR CRBWRTN CRBWR2: CALL BCONIN ;get char CP 'C'-'@' ;abort? JP Z,ZEXABRT CP CR ;cont if JR NZ,CRBWRTN ; ; ^| command ; CRWRTX: LD C,A ;echo cr/lf CALL NCONOT LD C,LF CALL NCONOT JP GETBUF ; ; ^* COMMAND ; RNGBELL: LD C,BELL ;ring bell CALL NCONOT JP GETBUF ; ; ^. command ; PSUPCK: LD HL,PSUPFL CP (HL) JR NZ,PSUPST ;set flags if not equal XOR A ;else reset flags PSUPST: LD (HL),A ;set/reset saved flag JP GETBUF ;and get next character (sets exec flag) ; ; ^& command ; IPSUPCK: LD HL,IPSUPFL CP (HL) JR NZ,PSUPST ;set flags if not equal XOR A ;else reset flags JR PSUPST ;set/reset flag in a ; ; ^# command ; MSUPCK: LD HL,MSUPFL CP (HL) JR NZ,MSUPST ;set flags if not equal XOR A ;else reset flag MSUPST: LD (HL),A ;set/reset flag JP GETBUF ;and get next character ; ; ^< and ^> commands ; IMFLGS: LD (IMFLG),A ;set/reset immediate mode flag JP GETBUF ;get next character ; ; console output intercept routine ; NCONOT: LD A,(OUTFLG) ;print suppression? OR A RET NZ ;yes...ignore echo LD A,C LD (PMCHR),A ;set last char output JP BCONOT ; ; get next char from buffer and terminate zex if end of buffer ; GETCHR: LD HL,(Z3MSG+09H) ;pt to next char LD A,(HL) ;get it DEC HL ;pt to following LD (Z3MSG+09H),HL ;reset ptr CP 0FFH ;eob? RET NZ ;no...return LD HL,(Z3MSG+09H) ;pt to eob INC HL ;point to eob LD (Z3MSG+09H),HL CALL MOVBAK ;move jumps back CALL BDOSRST ;restore bdos address CALL PRDONEM XOR A ;turn off zex LD (Z3MSG+08H),A LD SP,(CONSTK) ;get old stack LD A,CR ;return carriage return RET ; ; print done message with following prompt char ; PRDONEM: LD HL,DONEM ;print message CALL PMSG LD A,(PMCHR) ;print prompt char LD C,A ;in c for bios JP BCONOT ; ; restore bdos jmp if necessary ; BDOSRST: LD HL,(MEMTOP) ;see if bdos+1=memtop EX DE,HL LD HL,(BDOS+1) LD A,E SUB L LD A,D SBC A,H RET NZ ;don't replace bdos jump INC DE ;pt to bdos jump LD A,(DE) ;get low address LD L,A ;... in l INC DE LD A,(DE) ;get high address LD H,A ;... in h LD (BDOS+1),HL ;reset bdos jump RET ; ; ^c abort exit ; ZEXABRT: LD SP,MEMTOP ;^c aborts zex LD HL,ABORTD ;abort CALL PMSG JR WARMX1 ;don't print done message ; ; abort zex and return to zcpr2 ; WARMX: CALL PRDONEM ;print done message ; ; entry point to abort zex without message ; WARMX1: XOR A ;say that zex is not running LD (Z3MSG+08H),A CALL MOVBAK ;move jumps back CALL BDOSRST ;restore bdos jumps LD HL,(EXMBASE) ;multiple command lines enabled? LD A,H ;any on? OR L JP Z,WARM ;none on if address is zero, so just warm boot ; ; this section of code clears the multiple command line buffer ; LD D,H ;de pts to multiple command buffer also LD E,L PUSH HL ;save ptr LD HL,4 ;pt to first char of line ADD HL,DE LD (HL),0 ;set first char of line to zero for eol EX DE,HL ;de pts to first char of line POP HL ;get ptr LD (HL),E ;store address of empty command (eol) INC HL LD (HL),D JP WARM ; PMSG: PUSH HL LD A,(IPSUPFL) ;combine psupfl and ipsupfl to set print flag OR A ;0=no suppress JR Z,PMSG0 LD HL,Z3MSG+1 ;pt to if flag LD A,(HL) ;get if flag OR A ;no if? JR Z,PMSG0 INC HL AND (HL) ;set if state POP HL ;in case of return RET Z ;skip message if suppressed PUSH HL PMSG0: POP HL LD A,(MSUPFL) ;print message at (hl) CP MSUP ;messages suppressed? RET Z ;yes..exit PMSGL: LD A,(HL) ;get next char OR A ;end of message? RET Z ;yes..exit INC HL ;pt to next char PUSH HL ;save ptr LD C,A ;output char CALL BCONOT POP HL ;restore ptr JR PMSGL ; ; subroutines ; MOVBAK: LD HL,(WARMPT) ;move old jump table back to bios EX DE,HL LD HL,BSWARM LD BC,12 LDIR ; ; replace zex routine jumps with bios jumps ; F121: LD HL,BSWARM ; insure only bios 1.1.2 LD DE,NWARM ; calls from now on 1.1.2 LD BC,3 ; for programs 1.1.2 LDIR ; that may have 1.1.2 LD HL,BCONIN ; copied our 1.1.2 LD DE,NCONIN ; addresses as 1.1.2 LD BC,3 ; if they were 1.1.2 LDIR ; in the bios. 1.1.2 LD HL,BCONOT ; (mbasic does this) 1.1.2 LD DE,NCONOT ; 1.1.2 LD BC,3 ; 1.1.2 LDIR ; 1.1.2 RET ; ; working storage area ; ABORTD: DB CR,LF,'[ZEX Aborted]',CR,LF,0 STARTM: DB ' ZEX: ',0 DONEM: DB 'Done',0 DS 30 ;stack space MEMTOP: DW 0 EXMBASE: DW 0 CCPJMP: DW 0 WARMPT: DW 0 ; ; original bios jmp table ; BSWARM: JP $ BCONST: JP $ BCONIN: JP $ BCONOT: JP $ ; PMCHR: DB 0 PSUPFL: DB 0 IPSUPFL: DB 0 OUTFLG: DB 0 NUICH: DB 0 IMFLG: DB 0 MSUPFL: DB 0 CONSTK: DW 0 ;?PLEN DEFL $ ; IF (?PLEN MOD 8) GT 0 ;?PLEN DEFL (?PLEN AND 0FFF8H)+8 ;get next boundary ; ENDIF ; ;DRVERL EQU ?PLEN ; ;DRVL8 EQU DRVERL/8 ;length of relocation bit map ; ORG DRVERL ; ; ; end of zex relocated code segment ; .DEPHASE REEND EQU $ RELE EQU REEND-REST END