.MCALL .MODULE .MODULE LINK,VERSION=45,COMMENT= IDENT=NO,MODNAME=LINK8,GLOBAL=.LINK8 ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. .SBTTL GLOBAL SYMBOL CREF OUTPUT .ENABL GBL ; DBB .IIF NDF EIS$ EIS$= 0 ;SAY NO EIS AVAILABLE ; EDIT HISTORY .SBTTL - MISCELLANEOUS MACRO DEFINITIONS .MACRO ERROR$ ERNB,SEV,ETYP,REG .IF NB REG .IIF DIF , MOV REG,R0 .IFF .IIF IDN , CLR R0 .ENDC JSR R5,ERROOT .BYTE ERNB, SEV*100!ETYP .ENDM .IF Z EIS$ .MACRO SOB R,L DEC R BNE L .ENDM .ENDC ;+ ; SUBROUTINE CALL AND RETURN TO MAIN PROGRAM, EQUIVILENT TO: ; CALL SUBR ; RETURN ;- .MACRO CALLR SUBR JMP SUBR .ENDM .MACRO SYMADR R ASL R MOV R,-(SP) ASL R ASL R ADD (SP)+,R ADD SYEN0,R .ENDM .PSECT DATA,D .WORD 16 ;ERROR HANDLER INDEX (1ST PHYSICAL LOC IN OVLY) .PSECT CODE .SBTTL MISCELLANEOUS EQUATES .ENABL LC ; RT-11 MACROS TO BE USED .MCALL .QSET,.SETTOP,.CLOSE,.PURGE,.READW,.WRITE,.WRITW,.WAIT ; CHARACTERS LF = 12 FF = 14 CR = 15 SPACE = 40 ; DEFINITIONS ENTSIZ = 16. ;LENGTH (BYTES) OF A SORT ITEM FDFLT = 7. ;DEFAULT NUMBER OF OUTPUT FIELDS FWIDE = 14. ;# OF OUTPUT FIELDS FOR WIDE LISTING .IF EQ 1 GLOBAL CREF ACCEPTS AS INPUT A FILE WHICH CONSISTS OF 16. BYTE ENTRIES, ONE FOR EACH REFERENCE TO A SYMBOL. THE FORMAT OF AN ENTRY IS: OFFSET VALUE ------ ----- 0-5 ASCII NAME OF SYMBOL 6-11. ASCII NAME OF MODULE 12. BIT 7 IS REF/DEF INDICATOR (0=REF, 1=DEF) BIT 0 IS LIB/NON-LIB INDICATOR (0=NON-LIB, 1=LIB) .ENDC .SBTTL GBLCRF:: GENERATE CREF LISTING, AND CLOSE FILES GBLCRF::TST CBPTR ;CREF DESIRED? BNE 10$ JMP FILCLS ;NO CREF IF EQ 10$: INC MBLK INC CBLK ;WERE THERE ANY SYMBOLS? BNE 20$ ;BRANCH IF SO JMP EXIT ;ELSE QUIT NOW 20$: CMP #-1,RMON ;ARE WE RUNNING UNDER VBGEXE? BNE 30$ ;BRANCH IF NOT MOV #-2,R1 ;NO USR UNDER VBGEXE - TELL .SETTOP BR 40$ ;MERGE BELOW 30$: MOV @#RMON,R1 ;FIND LOW ADRS OF MONITOR MOV U$SRLC(R1),R1 ;ADDR WHERE USR WILL LOAD TST -(R1) 40$: .SETTOP R1 ;AND FORCE USR NOSWAPPING .QSET #QAREA,#1 ;ADD A QUEUE ELEMENT FOR LISTING I/O MOV FILPT1,R2 ;R2 -> LOW ADDRESS AVAILABLE FOR ; CREF BUFFERS 50$: .SETTOP #-2 ;GET ALL AVAILABLE SPACE MOV R0,R1 ;GET ALLOCATED HIGH LIMIT IN R1 MOV MBLK,OUTBLK ;SET OUTPUT FILE INITIAL BLOCK # MOV #FDFLT,WIDTH ;SET # OF OUTPUT FIELDS TO DEFAULT MOV #FDFLT,NUMFLD TST LSTFMT ;132-COLUMN MODE? BEQ ALLOC ;NO MOV #FWIDE,WIDTH ;SET # OF OUTPUT FILES FOR WIDE OUTPUT MOV #FWIDE,NUMFLD .SBTTL STORAGE ALLOCATION & EXEC ALLOC: MOV R2,SRTBUF ;INITIALIZE BUFFER ADDRESSES MOV R2,F1BUF MOV R2,F2BUF MOV R2,F3BUF SUB R2,R1 ;COMPUTE AVAILABLE SPACE ; COMPUTE # OF 3-BLOCK SECTIONS AVAILABLE (=SECT) CLR R4 ;SECT=0 MOV R1,R0 ;COPY AVAILABLE SPACE 10$: SUB #3*512.,R0 BLO 20$ ;R4 = R0/(3*512.) INC R4 BR 10$ ; COMPUTE # OF 3-BLOCK SECTIONS SORTED PER PASS 20$: SUB #2,R4 ;R4 = SECT - 2 ; GET LENGTH OF INPUT FILE (=N) IN BLOCKS MOV CBLK,R5 ;GET SIZE AS PASSED DEC R5 ; COMPUTE NUMBER OF SORT PASSES MOV R4,-(SP) ;R4 = # OF BLOCKS PER SORT LOAD ASL R4 ADD (SP)+,R4 MOV R4,SECT3 ;COPY INTO SECT CLR R0 ;SORT PASSES = 0 30$: INC R0 ;SORT PASSES + 1 SUB R4,R5 ;R0 = N/(3*SECT) BPL 30$ CLR INCORE ;ASSUME CREF FILE WON'T FIT IN CORE CMP R0,#1 ;OPTIMIZE FOR ONE-PASS CASE BGT 40$ COM INCORE ;SET FLAG IF CREF FILE FITS IN CORE 40$: MOV R0,SRTPAS ;SAVE FOR POSTERITY MOV R0,MRGPAS CLR R5 ;COMPUTE START BLOCK # FOR FIRST 50$: DEC R0 ; MERGE PASS BEQ 60$ ADD R4,R5 BR 50$ 60$: MOV R5,F1BLK ; SORT EXEC SWAB R4 ;TO 256.*(3*SECT) MOV R4,SRTWC ;SET WORD COUNT EXEC: MOV #SRTCMD,R5 ;READ IN A CORE LOAD CALL READ MOV R0,ENDF1 ;SET END-OF-BUFFER ADRS FOR LISTING CLR -(SP) ;QUICKSORT STOP FLAG MOV R0,-(SP) ;SET NEW STOP ADDR MOV SRTBUF,-(SP) ;SET START ADDR MOV #ENTSIZ,R0 ;SET UP PARAMETER JMP QUICKS ;GO SORT THE CORE LOAD DONSRT: TST INCORE ;DOES ENTIRE FILE FIT IN CORE? BMI 10$ ;IF YES, THEN GO LIST MOV #SRTCMD,R5 ;WRITE THE CORE LOAD BACK OUT CALL WRITE DEC SRTPAS ;ANY MORE SORT PASSES NEEDED? BEQ 10$ ;NOPE - GO CHECK MERGE ADD SECT3,SRTBLK ;ELSE UPDATE BLOCK NUMBER BR EXEC ;AND GO SORT NEXT CORE LOAD ; MERGE EXEC 10$: MOV SECT3,R5 ;GET # OF BLKS MERGED PER PASS SWAB R5 ;CHANGE TO WORD COUNT MOV R5,F1WC ;AND STORE IT ASL R5 ;GET BYTE COUNT ADD R5,F2BUF ;SET F2 BUFFER ADDRESS ADD R5,F3BUF ;AND F3 BUFFER ADDRESS ADD #3*512.,F3BUF MOV F3BUF,ENDF3 ;AND END-OF-F3-BUFFER ADDRESS ADD #3*512.,ENDF3 20$: DEC MRGPAS ;ANY MERGE PASSES REMAIN? BEQ 30$ ;NOPE - GO FORMAT LISTING MOV #3*256.,F2WC ;### A.C. FIX TO CREF MOV #F1BLK,R5 ;GET INPUT BLOCK ADDR SUB SECT3,@R5 ;GET NEXT SECTION TO MERGE MOV @R5,R4 ;PICK UP F1 BLOCK # MOV R4,F3BLK ;SET OUTPUT START BLOCK ADD SECT3,R4 ;GET F2 START BLOCK MOV R4,F2BLK TST -(R5) ;POINT AT THE COMMAND WORD CALL READ ;READ F1 CALL READ ;AND F2 ADD #ENTSIZ,R0 ;BUMP END F2 ADDR MOV R0,ENDF2 ;AND SET F2 END MOV #3*256.,F3WC ;RESET OUTPUT WORD COUNT CALL MERGE ;DO THE MERGE PASS BR 20$ ;AND CONTINUE 30$: JMP FORMAT ;GO FORMAT LISTING .SBTTL IMPURE AREA SRTCMD: .WORD 0 ;SORT COMMAND & CHANNEL SRTBLK: .WORD 0 ;SORT BLOCK NUMBER SRTBUF: .WORD 0 ;SORT BUFFER ADDRESS SRTWC: .WORD 0 ;SORT WORD COUNT SRTMOD: .WORD 0 ;SORT MODE (WAIT MODE) F1CMD: .WORD 0 ;MERGE INPUT #1 COMMAND & CHANNEL F1BLK: .WORD 0 ;MERGE INPUT #1 BLOCK NUMBER F1BUF: .WORD 0 ;MERGE INPUT #1 BUFFER ADDRESS F1WC: .WORD 0 ;MERGE INPUT #1 WORD COUNT .WORD 0 ;MERGE INPUT #1 MODE (WAIT MODE) F2CMD: .WORD 0 ;MERGE INPUT #2 COMMAND & CHANNEL F2BLK: .WORD 0 ;MERGE INPUT #2 BLOCK NUMBER F2BUF: .WORD 0 ;MERGE INPUT #2 BUFFER ADDRESS F2WC: .WORD 3*256. ;MERGE INPUT #2 WORD COUNT .WORD 0 ;MERGE INPUT #2 MODE (WAIT MODE) F3CMD: .WORD 0 ;MERGE OUTPUT COMMAND & CHANNEL F3BLK: .WORD 0 ;MERGE OUTPUT BLOCK NUMBER F3BUF: .WORD 0 ;MERGE OUTPUT BUFFER ADDRESS F3WC: .WORD 3*256. ;MERGE OUTPUT WORD COUNT .WORD 0 ;MERGE OUTPUT MODE (WAIT MODE) SRTPAS: .WORD 0 ;# OF SORT PASSES REQUIRED MRGPAS: .WORD 0 ;# OF MERGE PASSES REQUIRED SECT3: .BLKW ;# OF BLOCKS SORTED PER PASS INCORE: .BLKW ;IF MINUS, ALL OF INPUT FITS IN CORE LSTCHN=1 ;LISTING (OUTPUT) CHANNEL CRFCHN=11 ;CREF (INPUT) CHANNEL .ENABL LC TITLE: .ASCII /RT-11 / .NLCSI TYPE=I,PART=NAME .ASCII / / .NLCSI TYPE=I,PART=RLSVER .ASCIZ / Global Symbol Cross Reference Table/ PAGEST: .ASCIZ / Page / ;PAGE NUMBER HEADER TTLBUF: .BLKB 134. ;HEADER LINE BUFFER .EVEN INTFLG: .BLKW ;QUICKSORT FLAG SRTFLG: .BLKW ;BUBBLE SORT FLAG NUMFLD: .BLKW ;NUMBER OF OUTPUT FIELDS WIDTH: .BLKW ;AND MEMORY OF ABOVE CURNAM: .BLKB 6 ;CURRENT SYMBOL NAME MODNAM: .BLKB 6 ;PREVIOUS MODULE NAME PAGNUM: .BLKW ;OUTPUT PAGE NUMBER LSTSPC: .BLKW ;LISTING OUTPUT COMMAND & CHANNEL OUTBLK: .BLKW ;LISTING OUTPUT BLOCK NUMBER CURBUF: .BLKW ;LISTING OUTPUT BUFFER POINTER .WORD 256. ;LISTING OUTPUT WORD COUNT .BLKW ;ASYNCHRONOUS WRITE NXTBUF: .BLKW ;ADDRESS OF NEXT OUTPUT BUFFER OUTCNT: .BLKW ;# OF CHARS REMAINING IN CURRENT BUF OUTPTR: .BLKW ;CURRENT LISTING BUFFER POINTER .WORD 0 ;DIVISION TABLE FOR CVTASC .WORD 1 .WORD 10. DIG3: .WORD 100. ENDF1: .BLKW ;END OF MERGE INPUT #1 BUFFER ENDF2: .BLKW ;END OF MERGE INPUT #2 BUFFER ENDF3: .BLKW ;END OF MERGE OUTPUT BUFFER .SBTTL EXIT PROCESSING EXIT: .PURGE #CRFCHN ;PURGE THE TEMP FILE FILCLS: MOV #ODBLK,R1 ;POINT AT FILE NAME IN CASE ERROR .CLOSE #0 ;CLOSE LOAD FILE IF ANY BCC 10$ ;C= 0 -> NO ERROR CMPB #PROTCT,@#ERRBYT ;PROTECTION VIOLATION? BNE 10$ ;NE _> NO ERROR$ ERR66,E$W,E$FIL,R1 ;PROTECTION VIOLATION ON CLOSE 10$: ADD #10.,R1 ;GET NEXT OUTPUT FILE NAME .CLOSE #1 ;CLOSE MAP FILE IF ANY BCC 20$ ;C= 0 -> NO ERROR CMPB #PROTCT,@#ERRBYT ;PROTECTION VIOLATION? BNE 20$ ;NE _> NO ERROR$ ERR66,E$W,E$FIL,R1 ;PROTECTION VIOLATION ON CLOSE 20$: ADD #10.,R1 ;GET LAST OUTPUT FILE NAME .CLOSE #2 ;CLOSE STB FILE IF ANY BCC 30$ ;C= 0 -> NO ERROR CMPB #PROTCT,@#ERRBYT ;PROTECTION VIOLATION? BNE 30$ ;NE _> NO ERROR$ ERR66,E$W,E$FIL,R1 ;PROTECTION VIOLATION ON CLOSE 30$: BISB #SUCCS$,@#USERRB ;SET SUCCESS BIT IN USER ERROR BYTE JMP RESTRT ;BEGIN AGAIN .SBTTL READ/WRITE ROUTINES (INPUT FILE) BLKNO= 2 ;INDEX TO BLOCK NUMBER OF REQUEST BUFAD= 4 ;INDEX TO BUFFER ADDRESS WDCNT= 6 ;INDEX TO WORD COUNT READ: CMP BLKNO(R5),CBLK ;END-OF-FILE? BHIS 50$ ;YES MOVB WDCNT+1(R5),R0 ;GET WORD COUNT AS BLOCKS ADD BLKNO(R5),R0 ;AND ADD IN THE START BLOCK CMP CBLK,R0 ;BEYOND END-OF-FILE? BHIS 10$ ;NOPE SUB CBLK,R0 ;ELSE CORRECT SWAB R0 SUB R0,WDCNT(R5) ;AND MODIFY WORD COUNT 10$: .READW R5,#CRFCHN ;INITIATE READ BCS RDERR ; WHOOPS - ERROR MOV WDCNT(R5),-(SP) ;FIND LAST THREE-BLOCK SEGMENT CLR R0 20$: ADD #3*400,R0 ;INCREASE BY 3 BLOCKS CMP @SP,R0 ;HAVE WE OVERRUN ACTUAL WORD COUNT? BHI 20$ ;NOPE SUB #3*400,R0 ;ELSE BACK OFF BY 3 BLOCKS ASL R0 ;MAKE BYTE COUNT ASL @SP ;DITTO FOR STACK ADD BUFAD(R5),R0 ;R0->BEGINNING OF LAST 3-BLOCK BUF ADD BUFAD(R5),@SP ;AND SET END-OF-BUFFER ADRS 30$: TSTB @R0 ;IS THIS THE LAST ENTRY? BEQ 40$ ;YES ADD #ENTSIZ,R0 ;ELSE MOVE FORWARD BY ONE CMP @SP,R0 ;END OF BUFFER? BHI 30$ ;NOPE 40$: TST (SP)+ ;DISCARD END POINTER SUB #ENTSIZ,R0 ;BACK OFF TO LAST VALID ENTRY ADD #12,R5 ;POINT TO NEXT SET OF BLOCKS RETURN ;AND RETURN TO CALLER 50$: ADD #12,R5 ;ADVANCE TO NEXT SET OF BLOCKS SEZ ;INDICATE END-OF-FILE RTN: RETURN ;AND RETURN TO CALLER WRITE: .WRITW R5,#CRFCHN ;INITIATE WRITE BCC RTN ;BRANCH IF NO ERRORS TSTB @#ERRBYT ;WAS IT WRITE PAST EOF? BNE WRERR ;NOPE - GIVE MESSAGE SUB #256.,6(R5) ;ALTER WORD COUNT BR WRITE ;AND TRY AGAIN RDERR: ERROR$ ERR74,E$F,E$PRT ;CROSS REFERENCE READ ERROR WRERR: ERROR$ ERR76,E$F,E$PRT ;CROSS REFERENCE WRITE ERROR .SBTTL QUICKSORT ROUTINE ;+ ; ; THIS ROUTINE SORTS A CORELOAD OF CREF DATA ; AT ENTRY, THE ROUTINE EXPECTS THE FOLLOWING PARMS: ; ; R0 = ENTSIZ (THE NUMBER OF BYTES IN A SORT ENTRY) ; @SP = ADDRESS OF FIRST ITEM TO BE SORTED ; 2(SP) = ADDRESS OF LAST ITEM TO BE SORTED ; 4(SP) = 0 (USED AS END-OF-STACK FLAG) ; ; CALLING SEQUENCE: JMP QUICKS ; ;- QUICKS: MOV @SP,R1 ;LEFT POINTER BEQ 100$ ;IF ZERO, THEN WE'RE DONE MOV 2(SP),R2 ;RIGHT POINTER CLR INTFLG ;RESET WHICH-PTR-TO-MOVE FLAG MOV R2,R3 ;CHECK NUMBER OF ITEMS SUB R1,R3 ;GET # OF ITEMS - 1 (*ENTSIZ) BEQ QPOP2 ;ONLY ONE - IT'S SORTED ALREADY CMP #ENTSIZ*10.,R3 ;11 OR FEWER ITEMS? BLO 10$ ;NOPE - CONTINUE QUICKSORT MOV R1,R4 ;ELSE SET UP FOR TWO-BUBBLE MOV R1,R5 ; SORT ADD R0,R5 BR SORT ;AND DO IT 10$: MOV R0,R3 ;SET LOOP COUNT MOV R1,R4 ;COPY LEFT PTR MOV R2,R5 ;AND RIGHT PTR 20$: CMPB (R4)+,(R5)+ ;COMPARE PAIR OF ENTRIES BHI 80$ ;IF HIGH, MUST INTERCHANGE BLO 30$ ;IF LOW, OKAY DEC R3 ;LOOP UNTIL DONE WITH ENTRY BNE 20$ 30$: TST INTFLG ;SHOULD WE MOVE LEFT OR RIGHT PTR? BNE 50$ ;INC LEFT POINTER 40$: SUB R0,R2 ;DEC RIGHT POINTER BR 60$ ;GO SEE IF DONE WITH THIS PASS 50$: ADD R0,R1 ;BUMP LEFT PTR BY ONE ENTRY 60$: CMP R1,R2 ;DONE WITH THIS PASS? BLO 10$ ;NOPE - CONTINUE MOV 2(SP),R3 ;PICK UP FORMER RIGHT PTR MOV @SP,R2 ; AND FORMER LEFT POINTER MOV R1,R4 ;COPY THE ADDRESS WE STOPPED AT MOV R3,R5 ;AND THE FORMER RIGHT POINTER SUB R2,R4 ;SIZE OF LEFT PARTITION SUB R1,R5 ;SIZE OF RIGHT PARTION + ENTSIZ CMP R4,R5 ;WHICH PARTITION IS LARGER? BHI 70$ ;THE LEFT ONE IS . . . ; ELSE THE RIGHT PARTITION IS THE LARGER. WE WISH TO STACK ; THE LARGER TO MINIMIZE STACK SIZE AT RUNTIME. MOV R1,@SP ;STORE NEW LEFT PTR ADD R0,@SP ;AND ADD IN ENTSIZ TST R4 ;IS THE LEFT PART NULL? BEQ QUICKS ;YUP - JUST DO THE RIGHT SUB R0,R1 ;GET NEW STOP ADDR MOV R1,-(SP) ;AND STACK IT MOV R2,-(SP) ;ALSO STACK LEFT PTR BR QUICKS ;START SORTING LEFT PARTITION 70$: MOV R1,R2 ;GET STOP ADDRESS SUB R0,R2 ;BACK UP AN ENTRY MOV R2,2(SP) ;AND SET RIGHT PTR ON STACK TST R5 ;IS RIGHT PART NULL? BEQ QUICKS ;YUP - JUST DO THE LEFT MOV R3,-(SP) ;PUT NEW RIGHT PTR ON STACK ADD R0,R1 ;AND NEW LEFT POINTER MOV R1,-(SP) ;STACK IT BR QUICKS ;GO SORT ; EXCHANGE TWO ENTRIES JUST COMPARED. 80$: CMPB -(R4),-(R5) ;RESET POINTERS FOR EXCHANGE 90$: MOVB @R4,R0 ;EXCHANGE ONE BYTE OF EACH MOVB @R5,(R4)+ MOVB R0,(R5)+ DEC R3 ;LOOP UNTIL ALL BYTES SWITCHED BNE 90$ MOV #ENTSIZ,R0 ;RESET R0 VALUE COM INTFLG ;SWITCH POINTER MOVEMENT BEQ 40$ ; AND UPDATE POINTERS BR 50$ 100$: TST (SP)+ ;POP QUICKSORT STOP FLAG (ZERO) JMP DONSRT ;RETURN TO CALLER QPOP2: CMP (SP)+,(SP)+ ;POP POINTERS BR QUICKS ;AND CONTINUE .SBTTL LOWER-LEVEL SORT ROUTINE ;+ ; ; ROUTINE IS CALLED FROM QUICKSORT TO HANDLE PARTITIONS ; OF A SMALL NUMBER OF ITEMS (TO MINIMIZE SIZE OF STACK) ; ; AT ENTRY, THE REGISTER ALLOCATION IS: ; R0 = ENTSIZ ; R1 = ADDRESS OF FIRST ITEM TO BE SORTED ; R2 = ADDRESS OF LAST ITEM TO BE SORTED ; R4 = ADDRESS OF FIRST ITEM (=R1) ; R5 = ADDRESS OF SECOND ITEM ; ;- SORT: CLR SRTFLG ;CLEAR BACKUP FLAG 10$: CMP R4,R2 ;DONE YET? BHIS QPOP2 ;YUP - RETURN TO QUICKSORT MOV R0,R3 ;ELSE SET LOOP COUNT 20$: CMPB (R4)+,(R5)+ ;COMPARE NEXT TWO ENTRIES BNE 30$ DEC R3 BNE 20$ BR 40$ ;IF THEY WERE EQUAL, BRANCH 30$: CMPB -(R4),-(R5) ;BACKUP POINTERS BHI 50$ ;BRANCH IF WE MUST EXCHANGE ADD R3,R4 ;ELSE UPDATE TO NEXT ITEM ADD R3,R5 40$: TST SRTFLG ;WERE WE GOING BACKWARDS? BEQ 10$ ;NOPE - JUST CONTINUE MOV SRTFLG,R4 ;ELSE PICK UP START ADDR MOV R4,R5 ;SET UP SECOND POINTER ADD R0,R5 ;PUSH UP ONE ITEM BR SORT ;AND CONTINUE 50$: MOVB @R4,R0 ;EXCHANGE DISORDERED ITEMS MOVB @R5,(R4)+ MOVB R0,(R5)+ DEC R3 BNE 50$ TST SRTFLG ;BACKING UP ALREADY? BNE 60$ ;YUP - SKIP POINTER SETUP MOV R4,SRTFLG ;ELSE NOTE WHERE TO RESTART 60$: MOV #ENTSIZ*2,R0 ;PREPARE TO BACK UP ONE ENTRY SUB R0,R4 SUB R0,R5 ASR R0 ;R0 = ENTSIZ CMP R5,R1 ;BACK TO THE BEGINNING? BHI 10$ ;NOPE - KEEP BACKING UP BR 40$ ;YES - RESET BACKUP AND CONTINUE .SBTTL LISTING OUTPUT FORMAT ROUTINE ;+ ; ; READ A SORTED CORE LOAD (IN DEFERENCE TO DECTAPE-ONLY ; SYSTEMS) AND WRITE THE LISTING OUTPUT. ; ;- FORMAT: MOV F3BUF,R5 ;GET A CONVENIENT PLACE FOR LINE BUFF MOV R5,R2 ;SET BUFFER POINTER MOV #140.,R1 ;SET LOOP COUNT 10$: MOVB #SPACE,(R2)+ ;BLANK OUT LINE BUFFER DEC R1 BNE 10$ MOV R5,R2 ;RESTORE POINTER MOV F2BUF,R5 ;PLACE FOR FIRST OUTPUT BUFFER MOV R5,CURBUF ;INDICATE SUCH MOV R5,OUTPTR ;AND INITIALIZE OUTPUT POINTER ADD #512.,R5 ;POINT AT SECOND OUTPUT BUFFER MOV R5,NXTBUF ;AND STORE ITS ADDRESS MOV #513.,OUTCNT ;INITIALIZE BYTES REMAINING COUNT CLR CURNAM ;INITIALIZE CURRENT SYMBOL TO NULL CLR PAGNUM ;PAGE # GETS INCREMENTED FIRST CALL ENDPAG ;PRINT THE HEADER AND SUCH TST INCORE ;IS FILE IN CORE ALREADY? BMI NEXT1 ;YES - DON'T READ NEXT: TST INCORE ;IF ENTIRE FILE FITS, BMI ALLDON ;THEN WE MUST BE DONE ALREADY MOV #F1CMD,R5 ;POINT AT INPUT FILE DATA CALL READ ;READ A CORELOAD BEQ ALLDON ;EOF - ALL DONE MOV R0,ENDF1 NEXT1: MOV F1BUF,R1 ;INIT INPUT POINTER ADD SECT3,F1BLK ;UPDATE INPUT BLOCK NUMBER NEWITM: CMP ENDF1,R1 ;END OF BUFFER? BLO NEXT ;YES - GET A NEW ONE TSTB @R1 ;THE VERY END (OF THE FILE)? BEQ ALLDON ;YES - GO CLOSE UP SHOP 10$: MOV #6,R0 ;SET LOOP COUNTER MOV #CURNAM,R5 ;POINT AT CURRENT SYMBOL NAME 20$: CMPB (R1)+,(R5)+ ;CHECK FOR A NEW SYMBOL NAME BNE 110$ ;FOUND A DIFFERENCE - JUMP DEC R0 ;ELSE CHECK NEXT BYTE BNE 20$ ;IF THERE IS ONE 30$: DEC NUMFLD ;SEE IF ANY SPACE LEFT ON LINE BNE 40$ ;YES - GO INSERT NEXT REFERENCE CALL ENDLIN ;ELSE END THIS LINE ADD #6,R2 ;NO SYMBOL NAME 40$: MOV R2,-(SP) ;SAVE CURRENT LINE POINTER MOV R1,-(SP) ;SAVE POINTER TO CURRENT MODULE NAME MOV #MODNAM,R2 ;POINT TO PREVIOUS MODULE NAME MOV #6,R0 ;SET LOOP COUNTER 50$: CMPB (R1)+,(R2)+ ;CHECK FOR A NEW MODULE NAME BNE 60$ ;BRANCH IF THERE IS A DIFFERENCE DEC R0 ;ELSE CHECK NEXT BYTE BNE 50$ ;IF THERE IS ONE MOV (SP)+,R1 ;RESTORE POINTER TO CURRENT MODULE NAME ADD #10.,R1 ;SKIP DUPLICATE MODULE NAME, FLAGS, FILL INC NUMFLD ;WE HAVEN'T USED ANY SPACE, SO RESET COUNTER MOV (SP)+,R2 ;RESTORE CURRENT LINE POINTER BR NEWITM ;PROCESS NEXT RECORD 60$: CMPB -(R1),-(R2) ;RESET POINTERS FOR MOVE 70$: MOVB (R1)+,(R2)+ ;MOVE CURRENT MODULE NAME INTO PREVIOUS DEC R0 ;DONE? BNE 70$ ;BRANCH IF NOT MOV (SP)+,R1 ;RESTORE POINTER TO CURRENT MODULE NAME MOV @SP,R2 ;RESTORE CURRENT LINE POINTER INC R2 ;LEAVE ONE BLANK ; ; INSTALL MODULE NAME AND FLAGS ; MOVB (R1)+,(R2)+ ;COPY MODULE NAME TO LINE BUFFER MOVB (R1)+,(R2)+ MOVB (R1)+,(R2)+ MOVB (R1)+,(R2)+ MOVB (R1)+,(R2)+ MOVB (R1)+,(R2)+ 80$: CMPB #SPACE,-(R2) ;TAKE OUT INTERVENING SPACES TO FLAGS BEQ 80$ INC R2 MOVB (R1)+,R0 ;GET FLAGS BYTE IN R0 BPL 90$ ;IF PL THEN NOT A DEFINITION MOVB #'#,(R2)+ ;DEFINITION IS FLAGGED WITH "#" 90$: ROR R0 ;GET LIB/NON-LIB MODULE FLAG TO C-BIT BCC 100$ ;IF C=0 THEN NON-LIB MODULE MOVB #'+,(R2)+ ;LIB MODULES ARE FLAGGED BY "+" 100$: ADD #3,R1 ;BUMP PTR PAST FILL MOV (SP)+,R2 ;RESTORE LINE POINTER ADD #9.,R2 ;AND ADVANCE TO NEXT FIELD BR NEWITM ;AND GO RECORD NEXT 110$: CMPB -(R1),-(R5) ;RESET POINTERS FOR MOVE MOVB @R5,-(SP) ;SAVE FIRST CHAR OF OLD SYMBOL 120$: MOVB (R1)+,(R5)+ ;MOVE NEW NAME INTO CURRENT NAME DEC R0 ;DONE MOVING NAME? BNE 120$ ;NO - CONTINUE MOVING TSTB (SP)+ ;DID WE HAVE A PREVIOUS SYMBOL? BEQ 130$ ;IF EQ NO CALL ENDLIN ;GET A NEW LINE 130$: MOV #CURNAM,R3 ;ADDR OF STORED SYMBOL NAME MOV (R3)+,(R2)+ ;MOVE NAME TO OUTPUT LINE MOV (R3)+,(R2)+ MOV (R3)+,(R2)+ CLR MODNAM ;INIT PREVIOUS MODULE NAME TO NULL BR 40$ ;HANDLE FIRST REF TO NEW NAME ALLDON: CALL ENDLIN ;DUMP LINE BUFFER MOV OUTPTR,R2 ;GET CURRENT OUTPUT BUFFER POINTER BR 20$ ;WE MUST DECREMENT BYTE COUNT FIRST 10$: CLRB (R2)+ ;AND CLEAR REMAINDER 20$: DEC OUTCNT ; FOR LP HANDLER BNE 10$ CALL WRITBF ;DUMP THE LAST BUFFER .WAIT #LSTCHN ;WAIT FOR WRITE TO LIST FILE TO END BCS MAPERR ;PRINT MESSAGE JMP EXIT ;AND EXIT MAPERR: ERROR$ ERR5,E$F,E$PRT ;MAP WRITE ERROR .SBTTL END-OF-LINE ROUTINE ;+ ; ; THE FOLLOWING ROUTINE IS USED TO FLUSH THE CURRENT CONTENTS ; OF THE LINE BUFFER TO THE OUTPUT. A CARRIAGE RETURN/LINE FEED ; IS APPENDED TO THE LINE, AND THE LINE BUFFER IS BLANK-FILLED ; BEFORE RETURNING. R2 IS UPDATED TO POINT TO THE BEGINNING OF ; THE LINE BUFFER. ; ;- ENDLIN: MOVB #CR,(R2)+ ;MOVE IN CARRIAGE RETURN - MOVB #LF,(R2)+ ; AND LINE FEED MOV R2,-(SP) ;SAVE R2 DEC LINLFT ;ASSURE ENOUGH ROOM ON PAGE BPL 10$ ;YES - THERE IS CALL ENDPAG ;ELSE GET A NEW PAGE DEC LINLFT ;DECREMENT # OF LINES LEFT 10$: MOV OUTPTR,R2 ;GET CURRENT POSITION IN BUFFER MOV F3BUF,R0 ;AND A POINTER TO THE LINE BUFFER MOV WIDTH,NUMFLD ;RESET NUMBER OF OUTPUT FLDS 20$: DEC OUTCNT ;IS BUFFER FULL YET? BEQ 30$ ;YES - GO GET A NEW ONE MOVB @R0,(R2)+ ;MOVE LINE BUFFER TO OUTPUT BUFFER MOVB #SPACE,(R0)+ ;AND CLEAR LINE BUFFER CMP @SP,R0 ;MOVED ALL OF LINE YET? BNE 20$ ;NO - KEEP GOING MOV R2,OUTPTR ;UPDATE BUFFER POINTER MOV F3BUF,R2 ;RESET LINE POINTER TST (SP)+ ;CLEAN UP STACK RETURN ;AND RETURN 30$: MOV R0,-(SP) ;SAVE LINE POINTER CALL WRITBF ;GET A NEW BUFFER MOV (SP)+,R0 ;RESTORE POINTER BR 20$ ;AND CONTINUE WHERE WE LEFT OFF .SBTTL END-OF-PAGE ROUTINE ;+ ; ; THIS ROUTINE TERMINATES THE CURRENT PAGE AND STARTS A NEW ; PAGE, WITH THE APPROPRIATE HEADER LINE. ; ;- ENDPAG: MOV LINPPG,LINLFT ;RESET # LINES LEFT THIS PAGE MOV F3BUF,-(SP) ;SAVE LINE BUFFER ADRS MOV #TTLBUF,R2 ;GET HEADER LINE BUFFER ADRS MOV R2,F3BUF ;AND USE IT TEMPORARILY MOV #TITLE,R0 ;GET ADDR OF HEADER FOR LISTING 10$: MOVB (R0)+,(R2)+ ;MOVE HEADER TO LINE BUF BNE 10$ DEC R2 ;CLOBBER NULL MOV #PAGEST,R0 ;GET PAGE NUMBER STRING 20$: MOVB (R0)+,(R2)+ ;AND MOVE IT INTO THE LINE BUFFER BNE 20$ DEC R2 ;CLOBBER THE NULL INC PAGNUM ;ADD ONE FOR NEW PAGE MOV PAGNUM,R0 ;GET CURRENT PAGE NUMBER TO CONVERT JSR R1,CVTASC ;AND MAKE IT DECIMAL .WORD DIG3,0 CALL ENDLIN ;PRINT THE LINE CALL ENDLIN ;AND 2 BLANKS CALL ENDLIN 30$: MOV (SP)+,R2 ;RESTORE LINE BUFFER ADDRESS MOV R2,F3BUF ;AND BUFFER POINTER RETURN ;AND RETURN .SBTTL LISTING WRITE, CONVERT-TO-ASCII ROUTINES WRITBF: .WAIT #LSTCHN ;WAIT FOR THE PREVIOUS WRITE TO END BCS 10$ ;ERROR .WRITE #LSTSPC,#LSTCHN ;AND START THE NEXT BCS 10$ ;ERROR INC OUTBLK ;SET NEW BLOCK NUMBER FOR NEXT MOV #513.,OUTCNT ;RESET BYTES REMAINING IN BUFFER MOV NXTBUF,R2 ;GET THE NEXT BUFFER ADDR MOV CURBUF,NXTBUF ;SET NEXT BUFFER ADDR MOV R2,CURBUF ;AND SET CURRENT BUFFER RETURN ;RETURN TO CALLER 10$: ERROR$ ERR5,E$F,E$PRT ;MAP WRITE ERROR ;+ ; ; CONVERT THE UNSIGNED NUMBER IN R0 TO ASCII AT (R2)+. ; CALLING SEQUENCE: ; JSR R1,CVTASC ; .WORD ; .WORD <0 IF LEFT-JUSTIFY, 1 IF BLANK PAD> ; ;- CVTASC: MOV (R1)+,R5 ;GET DIVISION TABLE POINTER CLR R3 ;CLEAR LEADING ZEROES FLAG 10$: MOV #-1,R4 ;INITIALIZE DIGIT ACCUMULATOR MOVB #SPACE,@R2 ;BLANK FILL 20$: INC R4 ;DIVIDE BY POWER OF TEN SUB @R5,R0 BCC 20$ ADD @R5,R0 ;CORRECT NUMBER TST -(R5) ;DONE? BEQ 30$ ;YES - GO PUT OUT LAST DIGIT ADD @R1,R2 ;INC IF BLANK FILL, ELSE NOP ADD R4,R3 ;LEADING ZERO? BEQ 10$ ;YES SUB @R1,R2 ;REMOVE AFFECT OF ABOVE ADD #'0,R4 ;MAKE ASCII MOVB R4,(R2)+ ;AND INSTALL IT BR 10$ ;CONTINUE WITH NEXT DIGIT 30$: ADD #'0,R4 ;MAKE LAST DIGIT ASCII MOVB R4,(R2)+ ;AND PUT IT IN BUFFER TST (R1)+ ;SKIP FLAG RTS R1 ;AND RETURN TO CALLER .SBTTL MERGE ROUTINE MERGE: MOV #ENTSIZ,R4 ;SET LOOP COUNT MOV F1BUF,R1 ;GET F1 BUFFER ADDR MOV F2BUF,R2 ;GET F2 BUFFER ADDR MOV F3BUF,R3 ;GET F3 BUFFER ADDR MOV #3*256.,F2WC ;ASSURE F2 READS 3 BLOCKS 10$: MOV R4,R0 ;SET LOOP COUNT 20$: MOVB @R1,(R3)+ ;MOVE A WORD TO OUTPUT BUFFER CMPB (R1)+,(R2)+ ;DID WE MOVE THE CORRECT ENTRY? BLO 30$ BHI 60$ DEC R0 ;EQUAL SO FAR, SO GO BACK BNE 20$ ;IF ANY WORDS LEFT SUB R4,R2 ;MOVE F2 POINTER BACK ONE ENTRY BR 50$ ;AND CHECK FOR END OF F1 30$: SUB R4,R2 ;BACK OFF F2 BY AN ENTRY DEC R0 ;AND INDICATE BYTE USED BEQ 50$ ;IT WAS THE LAST OF THE RECORD 40$: MOVB (R1)+,(R3)+ ;MOVE F1 TO F3 INC R2 ;ADVANCE F2 POINTER DEC R0 ;MOVE ONE ENTRY BNE 40$ 50$: CMP F2BUF,R1 ;END OF CURRENT F1 BUFFER? BNE 80$ ;NOPE - CONTINUE BR 90$ ;YES - GO COPY F2 TO OUTPUT 60$: CMPB -(R2),-(R3) ;LAST BYTE MOVED WAS INCORRECT SUB R4,R1 ;MOVE F1 POINTER BACK ONE ENTRY 70$: MOVB (R2)+,(R3)+ ;MOVE F2 TO F3 INC R1 ;ADVANCE F1 POINTER DEC R0 ;FOR AS MANY WORDS AS LEFT BNE 70$ DEC R1 ;OFF BY A BYTE CMP ENDF2,R2 ;END OF F2 BUFFER? BNE 80$ ;NOPE CALL 140$ ;ELSE CHECK E-O-F BEQ 110$ ;YES - GO COPY F1 80$: CALL CHECK3 ;CHECK OUTPUT BUFFER BR 10$ ;AND CONTINUE MERGE 90$: CALL CHECK3 ;CHECK ON OUTPUT BUFFER MOV R4,R0 ;SET LOOP COUNTER ASR R0 ;GET WORD COUNT 100$: MOV (R2)+,(R3)+ ;DONE WITH F1 - MOVE F2 TO OUTPUT DEC R0 ;MOVE ONE ENTRY AT A TIME BNE 100$ CMP ENDF2,R2 ;END OF F2 BUFFER? BNE 90$ ;NOPE CALL 140$ ;ELSE CHECK E-O-F BEQ 130$ ;YES - WE'RE DONE BR 90$ ;AND CONTINUE 110$: CALL CHECK3 ;CHECK FOR END OF OUTPUT BUFFER MOV R4,R0 ;SET LOOP COUNT ASR R0 ;GET WORD COUNT 120$: MOV (R1)+,(R3)+ ;MOVE F1 TO OUTPUT DEC R0 ;A WORD AT A TIME BNE 120$ CMP F2BUF,R1 ;END OF F1 BUFFER BNE 110$ ;AND CONTINUE 130$: CLR @R3 ;NOW, WE ARE DONE BR WRITE3 ;WRITE LAST AND RETURN TO CALLER 140$: MOV #F2BLK,R5 ;SET UP FOR READ ADD #3,@R5 TST -(R5) CALL READ ;TRY A READ BEQ 150$ ;BRANCH ON E-O-F MOV F2BUF,R2 ;ELSE RESET BUFFER POINTER ADD #ENTSIZ,R0 ;POINT BEYOND LAST ENTRY MOV R0,ENDF2 ;RESET F2 END ADDR 150$: RETURN ;RETURN TO CALLER CHECK3: CMP ENDF3,R3 ;END OF F3 BUFFER? BNE W3END ;NO - DON'T WRITE WRITE3: MOV #F3CMD,R5 ;WRITE OUTPUT FILE CALL WRITE ADD #3,F3BLK ;UPDATE BLOCK NUMBER MOV F3BUF,R3 ;RESET BUFFER POINTER W3END: RETURN ;RETURN TO CALLER OV8DUM::RTS R5 .PSECT PATCH .BLKW 64. ;PSECT FOR PATCHES .END