.TITLE COR .SBTTL Intro .IDENT /V2.0/ .ENABL LC .NLIST BEX ; ; ;****************************************************************************** ; ; This software is provided on an "as is" basis only. Caterpillar Tractor Co., ; disclaims all warranties on the program, including without limitation, all ; implied warranties of merchantablity and fitness. ; ; Full permission and consent is hereby given to DECUS and to the DECUS ; special interest groups to reproduce, distribute, and publish and permit ; others to reproduce in whole or in part, in any form and without restriction ; this program and any information relating thereto ; ;****************************************************************************** ; ; ; Author: D. A. DeMott ; ; Change history: ; ; V2.0 J. M. Miller 8/5/82 ; Updated messages and added hole search, task size ; checks, task extension modification, task check- ; pointing, spawning SPC, and spawning of MCR instead ; of directly queuing to MCR. ; ; ; ; ; ; ; Description: ; ; This program has three functions: 1) allocate core, 2) create a ; partition, or 3) return previously allocated core. ; ; When core is to be allocated, the top of the GEN partition is lowered ; to obtain the requested memory. No tasks can be running at the top of ; GEN at this time so if there are tasks present an attempt will be made ; to checkpointed them. If the tasks will not checkpoint, a task ; called ...SPC will be spawned to try and shuffle the tasks down in ; memory. If both attempts fail to free up the required core, COR ; exits with an error. ; ; When a new partition is to be created, the same actions are taken ; as listed above except that once the core is obtained MCR is spawned ; to set up the partition control block. Also before an attempt is made ; to reduce the GEN partition, a search is made above GEN for vacant ; holes that may have been created. The search is made from the top of ; memory down and is a first fit algorithm. ; ; When run without specifying a partition name and length, or just a ; length of core to be allocated, any unused core at the top of GEN is ; returned. ; ; Checks are made when lowering GEN's upper boundary so that it is not ; smaller than the largest installed task, and if GEN goes below 32KW ; and the extend task directive is allowed, then the max extend size is ; set to what ever GEN size is. This is reset to 32KW when GEN is ; increased to 32KW or greater. ; ; Command line: ; ; COR [[:] ] [:] [/switch] ; ; where: ; ; 1 to 6 character alphanumeric partition name ; ; Is an octal number of core requested in 100(octal) ; bytes. ; ; Can be COM, SYS, or TASK. The default is COM. ; ; switch -LI is used to suppress any messages. The ; default is LI. ; .PAGE .SBTTL Macros .MCALL PCBDF$,TCBDF$ .MCALL WSIG$S,QIOW$S,EXST$,GMCR$,DIR$ .MCALL SPWN$,WTSE$S ; ; Define data structure offsets. ; PCBDF$ ;partition control block TCBDF$ ;task control block ; ; Directives ; CMD: GMCR$ SPAWN: SPWN$ MCR...,,,,,1,,EXSTAT EXIT: EXST$ 1 .PAGE .SBTTL Data storage ; ; Data storage. ; LNGTH: .BLKW 1 ;length of core to allocate TOP: .BLKW 1 ;becomes base of core allocated LOW: .BLKW 2 ;work areas used to find a hole HIGH: .BLKW 1 ; " " " " " " " LRGTSK: .BLKW 2 ;name of largest installed task for GEN NMADD: .BLKW 1 ;address of partition name NMLEN: .BLKW 1 ;length of partition name TYPADD: .WORD COM ;type of partition address TYPLEN: .WORD 3 ;length of partition type MVECT: .WORD 0 ;message vector CKPCNT: .WORD 0 ;# times tried to checkpoint tasks cntr GENPCB: .BLKW 1 ;GEN partition PCB address EXSTAT: .BLKW 1 ;exit status COM: .ASCII /COM/ ;default partition type .EVEN SET: .ASCII "SET /MAIN=" ;set command to MCR buffer SETL=.-SET SET1: .BLKB 40. SPCN: .ASCII /SPC/ ;SPC run command to MCR SPCNL=.-SPCN .EVEN PARNAM: .RAD50 / / GEN: .RAD50 /GEN/ ; ; FLAG: ; BIT0 - set indicates need to allocate core ; BIT1 - set indicates need to create a partition ; BIT2 - set indicates used a hole ; BIT3 - set indicates need to checkpoint tasks ; BIT4 - set indicates suppress messages ; FLAG: .BLKW 1 .PAGE .SBTTL Messages ; ; Messages and message vectors. ; MSG1: .ASCII /COR -- Partition created / MSG1L=.-MSG1 MSG1C: MSG2: .ASCII /COR -- GEN partition boundary is reset/ MSG2L=.-MSG2 MSG3: .ASCII /COR -- Core allocated / MSG3L=.-MSG3 MSG3C: ERR1: .ASCII /COR -- Partition GEN is not in system or is not a main / .ASCII /partition/ ERR1L=.-ERR1 ERR2: .ASCII /COR -- Partition GEN is not a system controlled partition/ ERR2L=.-ERR2 ERR3: .ASCII /COR -- Alignment error/ ERR3L=.-ERR3 ERR4: .ASCII /COR -- Core not allocated, partition GEN unable to / .ASCII /contain task / ERR4L=.-ERR4 ERR4C: ERR5: .ASCII /COR -- Syntax error/ ERR5L=.-ERR5 ERR6: .ASCII /COR -- Too many characters in partition name/ ERR6L=.-ERR6 ERR7: .ASCII /COR -- Duplicate partition name/ ERR7L=.-ERR7 ERR8: .ASCII /COR -- Unsuccessful SET command/ ERR8L=.-ERR8 ERR9: .ASCII /COR -- Unable to allocate core because of subpartitions/ ERR9L=.-ERR9 .EVEN M1: .WORD MSG1,MSG1L,1 M2: .WORD MSG2,MSG2L,1 M3: .WORD MSG3,MSG3L,1 E1: .WORD ERR1,ERR1L,103. E2: .WORD ERR2,ERR2L,102. E3: .WORD ERR3,ERR3L,100. E4: .WORD ERR4,ERR4L,104. E5: .WORD ERR5,ERR5L,105. E6: .WORD ERR6,ERR6L,106. E7: .WORD ERR7,ERR7L,101. E8: .WORD ERR8,ERR8L,108. E9: .WORD ERR9,ERR9L,107. .PAGE .SBTTL Mainline program ; ; Get MCR command line and parse it to see if a new partition is ; to be created, core allocated, or if just need to recover ; unused space. ; COR: DIR$ #CMD ;get MCR line MOV $DSW,R3 ;one there? SUB #3,R3 ;adjust for task name BLE RESET ;LE means yes CLR R1 ;don't parse blanks/tabs MOV #FNCKTB,R2 ;adress of function table MOV #CMD+G.MCRB+3,R4 ;add. of chars. to parse MOV #FUNC,R5 ;first function CALL .TPARS ;parse BCC PRESET ;go process BIC #20,FLAG ;unsuppress messages TST MVECT ;error returned? BNE 1$ ;NE means yes MOV #E5,MVECT ;indicate syntax error 1$: JMP USER ;go finish up PRESET: MOV LNGTH,R1 ;get par length BEQ RESET ;branch if only recovering core BIS #1,FLAG ;indicate allocate core TST NMADD ;partition name? BEQ RESET ;EQ means no BIS #2,FLAG ;indicate partition request RESET: CALL $SWSTK,USER ;enter system state ; ; We are now executing at system state. If a new partition is to be ; created, check and make sure that the name does not conflict with ; an existing partition. Then make sure that there is a system ; controlled GEN partition to work with. ; BIT #2,FLAG ;;;create partition? BEQ GENCHK ;;;branch if no MOV $PARHD,R0 ;;;get PCB listhead MOV #PARNAM,R2 ;;;get new par name DUPCHK: CMP P.NAM(R0),(R2) ;;;same partition? BNE NXT ;;;NE means no CMP P.NAM+2(R0),2(R2) ;;;finish the test BNE NXT ;;;NE means no MOV #E7,MVECT ;;;indicate dup par RETURN ;;;return to user state NXT: MOV P.LNK(R0),R0 ;;;get next PCB BNE DUPCHK ;;;NE means go check some more GENCHK: MOV $PARHD,R0 ;;;PCB listhead CHK: CMP P.NAM(R0),GEN ;;;GEN partition? BNE NXT1 ;;;NE means no TST P.NAM+2(R0) ;;;finish the test BEQ CONT1 ;;;EQ is okay NXT1: MOV P.LNK(R0),R0 ;;;next PCB BNE CHK ;;;NE means more to do MOV #E1,MVECT ;;;no GEN partition RETURN ;;;go back to user state CONT1: BIT #PS.SYS,P.STAT(R0) ;;;system partition? BNE CONT2 ;;;NE means yes MOV #E2,MVECT ;;;wrong type RETURN ;;;go back to user state CONT2: MOV P.REL(R0),R2 ;;;par base CALL RECOVR ;;;try to recover any unused core BIT #1,FLAG ;;;allocate core? BNE HOLE ;;;branch if yes RETURN ;;;return to user state ; ; Check and see if there is already a vacant hole that meets the ; required core needed. Use a first fit algorithm and start at the ; top of memory and work down. Do this only if a partition is to ; be created. ; At this point: ; R0 = GEN PCB address ; R1 = length of core requested ; R2 = GEN partition base address ; HOLE: MOV R0,GENPCB ;;;save GEN PCB MOV P.SIZE(R0),R3 ;;;get GEN par size ADD R2,R3 ;;;get top of GEN BIT #2,FLAG ;;;just allocating core? BEQ TSKCHK ;;;branch if yes CMP $SYSIZ,R3 ;;;top of GEN at top of memory? BEQ TSKCHK ;;;branch if yes MOV $SYSIZ,HIGH ;;;get top of memory 1$: MOV R3,LOW ;;;get current top of GEN partition MOV $PARHD,R0 ;;;get PCB listhead 2$: MOV P.REL(R0),R5 ;;;get top boundary for this partition ADD P.SIZE(R0),R5 ;;; " " " " " " CMP R5,HIGH ;;;par boundary < high limit? BLO 3$ ;;;branch if < BHI 4$ ;;;branch if > CMP R0,GENPCB ;;;is this GEN? BEQ 4$ ;;;branch if yes MOV P.REL(R0),HIGH ;;;get new high boundary BR 4$ ;;;continue 3$: CMP R5,LOW ;;;par boundary LE low limit? BLOS 4$ ;;;branch if yes MOV R5,LOW ;;;get new low boundary MOV P.REL(R0),LOW+2 ;;;save partition base addr 4$: MOV P.LNK(R0),R0 ;;;get next PCB BNE 2$ ;;;branch if there is one CMP LOW,HIGH ;;;found a hole? BEQ 6$ ;;;branch if no MOV HIGH,R5 ;;;compute size of hole SUB LOW,R5 ;;; " " " " CMP R1,R5 ;;;hole big enough? BHI 5$ ;;;branch if no SUB R1,HIGH ;;;compute base addr of new par MOV HIGH,TOP ;;;pass base addr of new par BIS #4,FLAG ;;;indicate used a hole RETURN ;;;return to user state 5$: MOV LOW+2,HIGH ;;;get new upper boundary 6$: CMP LOW,R3 ;;;checked all core above GEN? BHI 1$ ;;;no - keep looking for hole MOV GENPCB,R0 ;;;restore GEN PCB ; ; Couldn't find a hole so must try and lower GEN partition's uppper ; boundary, but first must make sure that if the boundary is ; lowered that there will be enough room for the largest task to run. ; ; At this point: ; R0 = GEN PCB address ; R1 = length of core requested ; R2 = GEN partition base address ; R3 = top of GEN par ; TSKCHK: MOV R3,R4 ;;;copy top of GEN SUB R1,R4 ;;;shorten by new par length MOV R4,R1 ;;;make it requested length CMP R1,R2 ;;;alignment ok? BHI 1$ ;;;HI means yes MOV #E3,MVECT ;;;alignment error RETURN ;;;go back to user state 1$: SUB R2,R1 ;;;proposed length of GEN partition CLR R4 ;;;init R4 MOV $TSKHD,R0 ;;;get first task in task directory 2$: BIT #TS.EXE,T.STAT(R0) ;;;task active? BEQ 3$ ;;;branch if task active CMP T.PCB(R0),GENPCB ;;;GEN partition task? BNE 4$ ;;;branch if no CMP T.MXSZ(R0),R4 ;;;largest task found? BLOS 4$ ;;;branch if no MOV T.MXSZ(R0),R4 ;;;get new largest task length BR 5$ ;;;go get task name 3$: MOV T.PCB(R0),R3 ;;;get task PCB address CMP P.NAM(R3),GEN ;;;is task in GEN partition? BNE 4$ ;;;branch if no TST P.NAM+2(R3) ;;;finish test BNE 4$ ;;;branch if not in GEN partition CMP P.SIZE(R3),R4 ;;;largest task found? BLOS 4$ ;;;branch if no MOV P.SIZE(R3),R4 ;;;get new largest task length 5$: MOV T.NAM(R0),LRGTSK ;;;get task name MOV T.NAM+2(R0),LRGTSK+2 ;;; " " " 4$: MOV T.TCBL(R0),R0 ;;;get next TCB BNE 2$ ;;;branch if another TCB CMP R1,R4 ;;;enough room left in GEN? BHIS EXTCHK ;;;branch if yes MOV #E4,MVECT ;;;indicate task(s) larger than GEN RETURN ;;;return to user state EXTCHK: .IF DF E$$XPR CMP R1,#2000 ;;;GEN GE 32KW? BHIS SUBCHK ;;;branch if yes CMP R1,$MXEXT ;;;GEN GE max task extension? BHIS SUBCHK ;;;branch if yes MOV R1,$MXEXT ;;;set max task extension .ENDC ; ; Now need to make sure that no GEN subpar is above the new ; proposed GEN upper boundary, and if not then lower GEN's upper ; boundary. Else set flag to indicate need to try and get task(s) ; out of upper GEN. ; ; At this point: ; R1 = new GEN partition length ; R2 = GEN partition base address ; SUBCHK: MOV GENPCB,R0 ;;;get GEN PCB address MOV P.SUB(R0),R0 ;;;first subpar BEQ OK ;;;OK means par not in use CLR R5 ;;;set up lowest available bound 1$: MOV P.REL(R0),R3 ;;;subpar base ADD P.SIZE(R0),R3 ;;;subpar top CMP R3,R5 ;;;GT current top BLO 2$ ;;;LO means no MOV R3,R5 ;;;new top of subpars 2$: MOV P.SUB(R0),R0 ;;;next subpar BNE 1$ ;;;NE means more to check SUB R2,R5 ;;;min available length CMP R1,R5 ;;;top above minimum? BHIS OK ;;;HIS means yes BIS #10,FLAG ;;;set up for wait RETURN ;;;go back to user state OK: MOV GENPCB,R0 ;;;get GEN PCB address MOV R1,P.SIZE(R0) ;;;set new length ADD R1,R2 ;;;new top MOV R2,TOP ;;;store it RETURN ;;;go back to user state ; ; We are now back in user state. If MVECT is not zero, then there is ; an error message to print so go print it. If MVECT is zero, then ; check FLAG to see what action is to be taken. ; USER: TST MVECT ;error message to output? BEQ 1$ ;branch if no JMP OUT ;go output error message 1$: BIT #10,FLAG ;subpartitions in the way? BNE CKP ;branch if yes BIT #2,FLAG ;create a partition? BNE CREATE ;branch if yes BIT #1,FLAG ;allocate core? BNE ALLOC ;branch if yes MOV #M2,MVECT ;succesful boundary reset JMP OUT ;go output message ; ; Successfully allocated core so tell where and how much. ; ALLOC: MOV #MSG3C,R0 ;get start of output buffer CLR R2 ;suppress leading zeroes MOV TOP,R1 ;start address CALL $CBOMG ;convert to ASCII MOVB #':,(R0)+ ;put in colon CLR R2 ;suppress leading zeroes MOV LNGTH,R1 ;get length CALL $CBOMG ;convert to ASCII SUB #MSG3,R0 ;get number of char to output MOV R0,M3+2 ;pass number of chars MOV #M3,MVECT ;succesful core allocation BR OUT ;go output message ; ; If here need to create a partition so invoke MCR to do the work. ; CREATE: CALL SEND ;invoke routine to spawn MCR command BCS 1$ ;if unsuccessful go try to recover core SUB #SETL,R0 ;compute # of char to transfer MOV R0,R3 ;save # chars to move MOV R0,R2 ;pass # chars to move MOV #SET1,R1 ;R1 has address of source buffer MOV #MSG1C,R0 ;R2 has address of destination buffer CALL MOVE ;move the characters ADD #MSG1L,R3 ;compute the length of new message MOV R3,M1+2 ;store message length in message vector MOV #M1,MVECT ;get address of vector BR OUT ;go output message 1$: BIT #4,FLAG ;used a hole? BEQ CORCHK ;branch if no MOV #E8,MVECT ;indicate a bad set command BR OUT ;output results ; ; If here the set command was unsuccessful and core was allocated ; so check and see if another COR ran and reset the boundary. If yes ; then get more core and try it again, else if boundary not reset then ; recover core and exit. ; CORCHK: MOV GENPCB,R0 ;restore GEN PCB address MOV P.REL(R0),R2 ;get GEN base address ADD P.SIZE(R0),R2 ;get top of GEN CMP R2,TOP ;is top of GEN what we set it to? BNE SP1 ;branch if no (assume another COR ran) MOV P.REL(R0),R2 ;get GEN base address CALL $SWSTK,1$ ;go to system state CALL RECOVR ;;;recover the memory just obtained RETURN ;return to user state 1$: MOV #E8,MVECT ;indicate bad set command BR OUT ;output error message ; ; If here there are tasks in upper GEN that need to be removed. Try ; and checkpoint them. ; CKP: INC CKPCNT ;incr times tried to checkpoint counter CMP CKPCNT,#5 ;over limit? BGT SPC ;branch if yes CALL CKPT ;go try and checkpoint tasks BIC #177754,FLAG ;reset FLAG MOV LNGTH,R1 ;LENGTH TO GET 1$: MOV $LDRPT,R0 ;get task loader's TCB address BIT #T2.STP,T.ST2(R0) ;is task loader stopped? BEQ 2$ ;branch if no JMP RESET ;try again 2$: WSIG$S ;give task loader a chance to finish BR 1$ ;go see if task loader done ; ; Checkpointing of tasks did not work so start SPC up and see if it ; can do the job. ; SPC: CMP CKPCNT,#6 ;already spawned SPC? BGT SP2 ;branch if yes MOV #SPCN,SPAWN+S.PWCA ;pass command line address MOV #SPCNL,SPAWN+S.PWCL ;pass command line length 1$: DIR$ #SPAWN ;spawn MCR to run SPC thus using CCL BCC 2$ ;branch if directive ok CMP #IE.UPN,$DSW ;enough pool space? BNE SP2 ;branch if enough pool space WSIG$S ;wait for some pool BR 1$ ;try again 2$: WTSE$S #1 ;wait for SPC to finish SP1: BIC #177754,FLAG ;reset FLAG MOV LNGTH,R1 ;length to get JMP RESET ;go try and get core again SP2: MOV #E9,MVECT ;indicate couldn't allocate core ; ; If here it is time to output any messages that need to be output ; and then exit. ; OUT: MOV MVECT,R0 ;get address of message vector MOV 4(R0),EXIT+E.XSTS ;set exit status BIT #20,FLAG ;display message? BNE DONE ;branch if no CMP #104.,4(R0) ;was a too large task found? BNE 1$ ;branch if no MOV #ERR4C,R0 ;get addr to store ASCII task name MOV LRGTSK,R1 ;get first byte of task name CALL $C5TA ;convert to ASCII MOV LRGTSK+2,R1 ;get second byte of task name CALL $C5TA ;convert to ASCII SUB #ERR4,R0 ;get length of message MOV R0,R1 ;copy message length MOV MVECT,R0 ;restore addr of message vector BR 2$ ;go finish up 1$: MOV 2(R0),R1 ;length of message 2$: MOV (R0),R0 ;get address of message QIOW$S #IO.WLB,#1,#1,,,, ;write it out DONE: DIR$ #EXIT ;exit with status .PAGE .SBTTL Recovr - Recover unused core routine ; ; This routine tries to recover any unused core directly above GEN. ; ; INPUTS: ; ; R0 GEN PCB ; R2 GEN base addr ; ; OUTPUT: ; ; GEN PCB updated to include all possible core ; RECOVR: MOV R1,-(SP) ;;;save R1 MOV R0,-(SP) ;;;save R0 MOV $SYSIZ,R1 ;;;assume full system MOV $PARHD,R0 ;;;par listhead 1$: CMP P.REL(R0),R2 ;;;higher par? BLOS 2$ ;;;LOS means no CMP P.REL(R0),R1 ;;;conflict w/proposed boundary? BHI 2$ ;;;HI means no MOV P.REL(R0),R1 ;;;take this base as new GEN top 2$: MOV P.LNK(R0),R0 ;;;next PCB BNE 1$ ;;;NE means more to check MOV (SP)+,R0 ;;;recover GEN PCB SUB R2,R1 ;;;new length .IF DF E$$XPR CMP P.SIZE(R0),#2000 ;;;was GEN length GE 32KW? BHIS 3$ ;;;branch if yes CMP R1,#2000 ;;;is GEN length GE 32KW? BLO 3$ ;;;branch if no CMP P.SIZE(R0),$MXEXT ;;;was max extend and GEN same size? BNE 3$ ;;;branch if no MOV #-1,$MXEXT ;;;restore max task extension .ENDC 3$: MOV R1,P.SIZE(R0) ;;;store it MOV (SP)+,R1 ;;;restore R1 RETURN .PAGE .SBTTL Ckpt - Checkpoint tasks in GEN partition routine ; ; This routine tries to checkpoint all tasks in the GEN partition. ; CKPT: CALL $SWSTK,2$ ;switch to system state MOV $ACTHD,R1 ;;;begin with the loader +1 1$: MOV T.ACTL(R1),R1 ;;;get the next active task BEQ 2$ ;;;if EQ no more tasks TST T.STAT(R1) ;;;is task already blocked? BNE 1$ ;;;branch if yes BIT #T2.CHK,T.ST2(R1) ;;;task checkpointable? BNE 1$ ;;;branch if no MOV T.PCB(R1),R2 ;;;get task PCB CMP P.NAM(R2),GEN ;;;in GEN partition? BNE 1$ ;;;branch if no TST P.NAM+2(R2) ;;;finish test BNE 1$ ;;;branch if not in GEN MOV R1,-(SP) ;;;found an eligible task CALL $ICHKP ;;;try to checkpoint task MOV (SP)+,R1 ;;;restore task TCB address BR 1$ ;;;find another one 2$: RETURN ;;;return to user state .PAGE .SBTTL Send - Send set partition command to MCR routine ; ; This routine sets up the buffer and spawns MCR in order ; to establish a partition in the newly obtained core. ; SEND: MOV #SET1,R0 ;address for ASCII name MOV NMADD,R1 ;address of chars. MOV NMLEN,R2 ;# of chars. CALL MOVE ;get them in place MOVB #':,(R0)+ ;colon for syntax MOV TOP,R1 ;start address CLR R2 ;suppress leading zeroes CALL $CBOMG ;ASCII in place MOVB #':,(R0)+ ;colon for syntax MOV LNGTH,R1 ;length CLR R2 ;suppress leading zeroes CALL $CBOMG ;ASCII in place MOVB #':,(R0)+ ;colon for syntax MOV TYPADD,R1 ;address of chars. for type MOV TYPLEN,R2 ;# of chars CALL MOVE ;get them in place SUB #SET,R0 ;# chars. in MCR cmd line 1$: MOV R0,SPAWN+S.PWCL ;pass command line length MOV #SET,SPAWN+S.PWCA ;pass command line address DIR$ #SPAWN ;spawn MCR to set up partition BCC 2$ ;branch if directive OK CMP #IE.UPN,$DSW ;enough pool space? BNE 3$ ;branch if enough pool space WSIG$S ;wait for some pool BR 1$ ;try again 2$: WTSE$S #1 ;wait for MCR to finish CMP #1,EXSTAT ;MCR successful? CLC ;assume succesful completion BEQ 4$ ;branch if successful 3$: SEC ;indicate unsuccesful 4$: RTS PC ;return .PAGE .SBTTL Move - transfer data routine ; ; Routine to transfer data. ; ; INPUT: ; R0 output buffer addr ; R1 input buffer addr ; R2 #bytes to move ; MOVE: TST R2 ;chars. to move? BLE 2$ ;LE means no 1$: MOVB (R1)+,(R0)+ ;move a char. SOB R2,1$ ;loop till done 2$: RTS PC .PAGE .SBTTL Command line parse routines .MCALL ISTAT$,STATE$,TRAN$ ISTAT$ FNCSTB,FNCKTB STATE$ FUNC ;par name/core only TRAN$ $NUMBR,LST,PARLN ;allocate core only TRAN$ $STRNG,CO1,PARNM ;par name TRAN$ !LST,$EXIT STATE$ CO1 ;colon for syntax TRAN$ ': STATE$ ;par length TRAN$ $NUMBR,,PARLN STATE$ ;colon for syntax or def par type TRAN$ ':,PT TRAN$ !LST,$EXIT STATE$ PT ;par type TRAN$ "TASK",LST,PARTYP TRAN$ "COM",LST,PARTYP TRAN$ "SYS",LST,PARTYP STATE$ LST ;check for switch TRAN$ $EOS,$EXIT TRAN$ '/ STATE$ TRAN$ "LI",REST TRAN$ '- STATE$ TRAN$ "LI",,,20,FLAG STATE$ REST TRAN$ $EOS,$EXIT STATE$ PARLN: TST .PNUMH ;in range? BNE LNERR ;NE means no CMP .PNUMB,$SYSIZ ;in range? BHIS LNERR ;HIS means no MOV .PNUMB,LNGTH ;store length RTS PC LNERR: MOV #E3,MVECT ;alignment error ERRCOM: ADD #2,@SP ;reject transition RTS PC PARNM: CMP .PSTCN,#6 ;more than 6 chars.? BGT NMERR ;GT means yes MOV .PSTCN,NMLEN ;store # of chars. MOV R4,NMADD ;and the address SUB .PSTCN,NMADD ;adjust for chars. read MOV NMADD,R0 ;get par name addr CALL $CAT5 ;convert 1st 3 char to RAD50 MOV R1,PARNAM ;store 1st RAD50 word CMP .PSTCN,#3 ;more than 3 char in par name? BLE 1$ ;branch if no CALL $CAT5 ;convert next 3 chars to RAD50 MOV R1,PARNAM+2 ;store 2nd RAD50 word 1$: RTS PC ; NMERR: MOV #E6,MVECT ;too many chars. in par name BR ERRCOM PARTYP: CMP .PSTCN,#4 ;too many chars. for type? BGT ERRCOM ;GT means yes MOV .PSTCN,TYPLEN ;store # of chars. MOV R4,TYPADD ;store the address SUB .PSTCN,TYPADD ;adjust for chars. read RTS PC .END COR