%EXTERNALROUTINE LINK11(%STRING(63) PARAM) %STRING(63) MAP %OWNINTEGER BRIANS FIDDLE = 255 %CONSTINTEGER LIMIT = 128 %OWNINTEGER CODE BASE = 2<<13, GLA BASE = 0, SPBASE = 7<<13 %OWNINTEGER ALONE = 0, MAIN EP = -1, ENTRY = 0 %OWNSTRING(31) TASK ID = "" %OWNSTRING(31) FIX FILE = "" %OWNINTEGER STREAMS = 2 %OWNSTRING(31) PERM FILE = ".PERM11#REL", %C LIB FILE = ".LIB11#REL", %C OBJECT = "" %OWNINTEGER STACK = 8*1024 %CONSTINTEGER PLUG BIT = 64 %EXTERNALINTEGERFNSPEC EXIST(%STRING(255) S) %EXTERNALROUTINESPEC DEFINE(%STRING(63) S) %EXTERNALSTRING(6) %FNSPEC IMP11HOST %EXTERNALROUTINESPEC PROMPT(%STRING(15) S) %RECORDFORMAT TABFM(%INTEGER ADDR, INDEX, %C %BYTEINTEGER TYPE, %STRING(63) TEXT) %CONSTINTEGER MAX TABLE = 400 %CONSTINTEGER MAX FILES = 50 %RECORDARRAY TABLE(0:MAX TABLE)(TABFM) %STRING(63)%ARRAY FILE(1:MAX FILES) %INTEGERARRAY FILECODE, FILEGLA, SPECS, SPECLIST(0:MAX FILES) %BYTEINTEGERARRAY USED(1:MAX FILES) %INTEGER ERRORS %INTEGER STREAM %INTEGER REFS, DEFS, MODULE COUNT %INTEGER LAST CODE %INTEGER CA, GA %INTEGER FILE NO, FILE LIMIT %OWNINTEGER PERM = 0, PERM EP = 0 %STRING(63) FILE NAME %INTEGER J %RECORDNAME T(TABFM) %INTEGER CP, GP, TOTAL CA, SP, DS %INTEGERARRAY CBUF, GBUF(0:LIMIT) !Predefined externals %CONSTINTEGER XTOP = MAX TABLE %CONSTINTEGER XEVENT = MAX TABLE-1 %CONSTINTEGER XDS = MAX TABLE-2 %CONSTINTEGER XSP = MAX TABLE-3 %CONSTINTEGER XGO = MAX TABLE-4 ! TABLE(XTOP)_TEXT = "$TOP"; TABLE(XTOP)_TYPE =0; TABLE(XTOP)_INDEX =0 TABLE(XEVENT)_TEXT = "$EVENT"; TABLE(XEVENT)_TYPE=0; TABLE(XEVENT)_INDEX=0 TABLE(XDS)_TEXT = "$DS"; TABLE(XDS)_TYPE =0; TABLE(XDS)_INDEX =0 TABLE(XSP)_TEXT = "$SP"; TABLE(XSP)_TYPE =0; TABLE(XSP)_INDEX =0 TABLE(XGO)_TEXT = "$$$"; TABLE(XGO)_TYPE =0; TABLE(XGO)_INDEX =0 ! PERM FILE=IMP11HOST.PERM FILE LIB FILE = IMP11HOST.LIB FILE ! %ROUTINE OCTAL(%INTEGER N) %INTEGER J %CYCLE J = 15, -3, 0 PRINTSYMBOL(N>>J&7+'0') %REPEAT %END %ROUTINE SELECT(%INTEGER ST) STREAM = ST SELECTOUTPUT(STREAM) %END %ROUTINE GET(%INTEGERNAME N) %INTEGER S1, S2 READCH(S1); READCH(S2) N = S1+S2<<8 %END %ROUTINE READ WORD(%STRINGNAME S) %INTEGER SYM S = "" SKIPSYMBOL %WHILE NEXTSYMBOL = ' ' %OR NEXTSYMBOL = NL %CYCLE SYM = NEXTSYMBOL %RETURN %IF SYM = ' ' %OR SYM = NL %OR SYM = '=' SYM = SYM-32 %IF 'a' <= SYM <= 'z' S = S.TOSTRING(SYM) SKIPSYMBOL %REPEAT %END %ROUTINE ERROR(%STRING(100) TEXT) SELECTOUTPUT(0) PRINTSTRING("* ") PRINTSTRING(TEXT); NEWLINE ERRORS = ERRORS+1 SELECTOUTPUT(STREAM) %END %ROUTINE GET RECORD(%RECORDNAME R, %INTEGER SPEC) %RECORDSPEC R(TABFM) %INTEGER J,N,S %IF SPEC # 0 %THEN R_ADDR = 0 %ELSE GET(R_ADDR) R_INDEX = FILE NO READCH(R_TYPE) READCH(N) R_TEXT = "" %CYCLE J = 1, 1, N READCH(S) R_TEXT = R_TEXT.TOSTRING(S) %REPEAT %END %ROUTINE GET SPEC %INTEGER J %RECORD R(TABFM) %RECORDNAME T(TABFM) GET RECORD(R, 1) R_INDEX = 0 REFS = REFS+1; TABLE(REFS) = R %CYCLE J = 1, 1, REFS %EXIT %IF TABLE(J)_TEXT = R_TEXT %REPEAT T == TABLE(J) %IF R_TYPE # 0 %AND T_TYPE # R_TYPE %START ERROR("inconsistent use of ".R_TEXT) DEFS = DEFS-1; TABLE(DEFS) = R %RETURN %FINISH %END %ROUTINE GET DEF %INTEGER J %RECORD R(TABFM) GET RECORD(R, 0) R_INDEX = FILE NO PERM EP = FILE NO %IF R_TEXT = "$GO$" DEFS = DEFS-1; TABLE(DEFS) = R %CYCLE J = MAX TABLE, -1, DEFS %EXIT %IF TABLE(J)_TEXT = R_TEXT %REPEAT %RETURN %IF J = DEFS DEFS = DEFS+1 ERROR("duplicate ".R_TEXT) %IF PERM = 0 %END %ROUTINE SATISFY(%RECORDNAME R) %RECORDSPEC R(TABFM) %RECORDNAME T(TABFM) %INTEGER J %CYCLE J = MAX TABLE, -1, DEFS T == TABLE(J) %IF T_TEXT = R_TEXT %START R_ADDR = T_ADDR; R_TYPE = T_TYPE T_TYPE = T_TYPE!32; !SHOW USED %RETURN %FINISH %REPEAT ERROR("unsatisfied reference ".R_TEXT." in file ".FILE NAME) %END %ROUTINE PREPARE SPECS(%INTEGER INSERT, %INTEGERNAME FLAG) %RECORD R(TABFM) %INTEGER N FLAG = ERRORS GET(N) %WHILE N > 0 %CYCLE GET RECORD(R, 0) N = N-1 %REPEAT GET(N) %WHILE N > 0 %CYCLE N = N-1 GET RECORD(R, 1) %CONTINUE %IF INSERT = 0 SATISFY(R) REFS = REFS+1; TABLE(REFS) = R %REPEAT FLAG = ERRORS-FLAG GET(N); !CODE SIZE GET(N); !GLA SIZE %END %ROUTINE SKIP MODULE %INTEGER S %CYCLE READCH(S) %UNTIL S = X'E0' READCH(S) %IF S = X'E0' %START READCH(S) %RETURN %IF S = X'E0' %FINISH %REPEAT %END %ROUTINE FLUSH(%INTEGERARRAYNAME B, %INTEGERNAME P, %INTEGER NEW) %INTEGER J, CHECK %ROUTINE PUT(%INTEGER N) PRINTCH(N&255); PRINTCH(N>>8) CHECK = CHECK+N+N>>8 %END %CYCLE J = 1, 1, 10 PRINTCH(0) %REPEAT CHECK = 0 PUT(1) PUT(P*2+6) %CYCLE J = 0, 1, P PUT(B(J)) %REPEAT PRINTCH( (-CHECK)&255 !BRIANS FIDDLE ) BRIANS FIDDLE = 0 P = 0 B(0) = NEW %END %ROUTINE CPUT(%INTEGER N) LAST CODE = N CP = CP+1; CBUF(CP) = N CA = CA+2 FLUSH(CBUF, CP, CA) %IF CP = LIMIT %END %ROUTINE GPUT(%INTEGER N) GP = GP+1; GBUF(GP) = N GA = GA+2 FLUSH(GBUF, GP, GA) %IF GP = LIMIT %END %ROUTINE PLUG GLA(%INTEGER WHAT, WHERE) FLUSH(GBUF, GP, WHERE) %IF GP # 0 GBUF(0) = WHERE GBUF(1) = WHAT GP = 1 FLUSH(GBUF, GP, GA) %END %ROUTINE LOCATE(%INTEGER AT) FLUSH(CBUF, CP, AT) %IF CP # 0 CBUF(0) = AT CA = AT %END %ROUTINE PLUG CODE(%INTEGER WHAT) %IF CP # 0 %START CBUF(CP) = WHAT %FINISH %ELSE %START LOCATE(CA-2) CPUT(WHAT) %FINISH %END %ROUTINE LOAD MODULE(%INTEGER BASE) %INTEGER CB, GB, KEY, N, INDEX, LINE, MOD %RECORDNAME T(TABFM) %SWITCH S(1:12) CB = CA; GB = GA; MOD = 0 %CYCLE READCH(KEY) ->S(KEY) S(1): GET(N); CPUT(N+MOD); MOD = 0; %CONTINUE S(2): GET(N); GPUT(N+MOD); MOD = 0; %CONTINUE S(7): GET(INDEX) T == TABLE(INDEX+BASE) %IF T_TYPE&PLUG BIT # 0 %START %IF LAST CODE # K'004737' %START; !JSR_PC,#??? ERROR("Cannot fixup ".T_TEXT) T_TYPE = 0 %FINISH PLUG CODE(K'004777'); !JSR_PC,@#??? MOD = MOD-CA-2 %FINISH MOD = MOD+T_ADDR %CONTINUE S(4): GET(N); GET(INDEX) PLUG GLA(N+CB, INDEX+GB) %CONTINUE S(5): GET(N); LOCATE(N+CB); %CONTINUE S(9): MOD = MOD+CB; %CONTINUE S(10): MOD = MOD+GB; %CONTINUE S(11): MOD = MOD-CA-2; %CONTINUE S(6): GET(LINE) %REPEAT S(8): GET(N); N = N+CB; !EVENT CHAIN? READCH(N); READCH(N); READCH(N) %END %ROUTINE HEADER %INTEGER TOTAL CA, J, G %ROUTINE STRIP(%INTEGER SEG) %ROUTINE ADD(%INTEGERNAME N) N = N-8*1024 %IF N >= 0 %THEN CPUT(8*1024) %ELSE CPUT(N+8*1024) %END %IF TOTAL CA > 0 %START CPUT(5); ADD(TOTAL CA) %FINISH %ELSE %START %IF GA > 0 %AND SEG >= G %START CPUT(6); ADD(GA) %FINISH %ELSE %START CPUT(4); CPUT(0) %FINISH %FINISH %END TOTAL CA = CA-CODEBASE GA = SP-GLABASE G = GLABASE>>13 LOCATE(0) ! TASK ID = TASK ID." " CPUT(CHARNO(TASK ID, 1)+CHARNO(TASK ID, 2)<<8) CPUT(CHARNO(TASK ID, 3)+CHARNO(TASK ID, 4)<<8) CPUT(SP); !INITIAL SP CPUT(4); CPUT(0); !SEG 0 CPUT(7); CPUT(0); !SEG 1 STRIP(2); !SEG 2 STRIP(3); !SEG 3 STRIP(4); !SEG 4 STRIP(5); !SEG 5 STRIP(6); !SEG 6 CPUT(6); CPUT(STREAMS*X'280'+X'140'); !SEG 7 LOCATE(CODE BASE) %CYCLE J = 1, 1, 8 CPUT(0) %REPEAT %END %ROUTINE RESET(%INTEGER C, G) FLUSH(CBUF, CP, CA) %UNLESS CP = 0 FLUSH(GBUF, GP, GA) %UNLESS GP = 0 CBUF(0) = C; CA = C GBUF(0) = G; GA = G %END %ROUTINE LOAD(%INTEGER MODULES) %INTEGER FLAG, BASE, NO, USE NO = FILE NO USE = USED(NO) BASE = REFS PREPARE SPECS(USE, FLAG) FILE NO = FILE NO+1 %AND LOAD(MODULES-1) %IF MODULES > 1 RESET(FILECODE(NO), FILEGLA(NO)) %IF FLAG # 0 %OR USE = 0 %START SKIP MODULE %FINISH %ELSE %START LOAD MODULE(BASE) %FINISH %END %ROUTINE GET MODULE(%INTEGERNAME CODESIZE, GLASIZE) %INTEGER N GET(N); !NO OF DEFINITIONS %WHILE N > 0 %CYCLE N = N-1 GET DEF %REPEAT GET(N); !NO OF REFERENCES SPECLIST(FILE NO) = REFS SPECS(FILE NO) = N %WHILE N > 0 %CYCLE N = N-1 GET SPEC %REPEAT GET(CODE SIZE) GET(GLA SIZE) %END %ROUTINE EXAMINE(%INTEGER MODULES) %CYCLE FILE NO = FILE NO+1 FILE(FILE NO) = FILE NAME; FILE NAME = "" GET MODULE(FILE CODE(FILE NO), FILE GLA(FILE NO)) MODULES = MODULES-1 %RETURN %IF MODULES = 0 %REPEAT %END %ROUTINE FILL REFS %RECORDNAME R(TABFM) %INTEGER REF, DEF %RETURN %IF REFS = 0 %OR DEFS = 0 %CYCLE REF = 1, 1, REFS R == TABLE(REF) %CYCLE DEF = MAX TABLE, -1, DEFS %IF TABLE(DEF)_TEXT = R_TEXT %START R_INDEX = TABLE(DEF)_INDEX %EXIT %FINISH %REPEAT %REPEAT %END %ROUTINE MARK(%INTEGER MODULE INDEX) %INTEGER P, N, C, G %RETURN %IF MODULE INDEX = 0 %OR USED(MODULE INDEX) # 0 USED(MODULE INDEX) = 1 C = CA CA = CA+FILE CODE(MODULE INDEX) FILE CODE(MODULE INDEX) = C G = GA GA = GA+FILE GLA(MODULE INDEX) FILE GLA(MODULE INDEX) = G P = SPEC LIST(MODULE INDEX) N = SPECS(MODULE INDEX) %WHILE N > 0 %CYCLE N = N-1 P = P+1 MARK(TABLE(P)_INDEX) %REPEAT %END %ROUTINE FIX ADDRESSES %INTEGER J, B %RECORDNAME T(TABFM) %RETURN %IF DEFS > MAX TABLE %CYCLE J = DEFS, 1, MAX TABLE T == TABLE(J) %IF T_TYPE&1 # 0 %THEN B = FILE GLA(T_INDEX) %C %ELSE B = FILE CODE(T_INDEX) T_ADDR = T_ADDR+B %REPEAT %END %ROUTINE HANDLE FIXUPS(%STRING(63) FIX FILE) %STRING(63) FIXUP %INTEGER SYM, J, AT, N %RECORDNAME T(TABFM) %ROUTINE READSYM READSYMBOL(SYM) %UNTIL SYM # ' ' SYM = SYM-32 %IF 'a' <= SYM <= 'z' %END %ROUTINE READ OCTAL(%INTEGERNAME N) %INTEGER J %IF SYM = '@' %THEN AT = PLUG BIT %AND READSYM %C %ELSE AT = 0 N = 0 %CYCLE J = 1, 1, 6 %EXIT %UNLESS '0' <= SYM <= '7' N = N<<3+(SYM-'0') READSYM %RETURN %IF SYM = NL %REPEAT ERROR("Bad address for fixup ".FIXUP) %END ! %RETURN %IF FIX FILE = "" %IF EXIST(FIXFILE) = 0 %START PRINTSTRING(FIXFILE." does not exist"); NEWLINE %RETURN %FINISH DEFINE("ST2,".FIXFILE); SELECTINPUT(2) %CYCLE READ WORD(FIXUP); %EXIT %IF FIXUP = ".END" READSYM %IF SYM # '=' %START ERROR("No = in fixup for ".FIXUP) %FINISH %ELSE %START READSYM; READ OCTAL(N) DEFS = DEFS-1; T == TABLE(DEFS) T_TEXT = FIXUP; T_INDEX = 0; T_ADDR = N; T_TYPE = 128!AT %CYCLE J = MAX TABLE, -1, DEFS %EXIT %IF TABLE(J)_TEXT = FIXUP %REPEAT DEFS = DEFS+1 %IF J # DEFS %FINISH READSYM %WHILE SYM # NL %REPEAT SELECTINPUT(1); CLOSE STREAM(2) %END %ROUTINE GET OCTAL(%INTEGERNAME N) %INTEGER S N = 0 READSYMBOL(S) %UNTIL '0' <= S <= '7' %CYCLE N = N<<3!(S-'0') READSYMBOL(S) %RETURN %UNLESS '0' <= S <= '7' %REPEAT %END %ROUTINE PROCESS(%STRING(63) FILE) FILE NAME = FILE %RETURN %IF FILE = "" %IF EXIST(FILE NAME) = 0 %START FILE NAME = FILE NAME."#REL" %IF EXIST(FILE NAME) = 0 %START PRINTSTRING(FILE." does not exist"); NEWLINE %RETURN %FINISH %FINISH DEFINE("ST2,".FILE NAME) SELECT INPUT(2) GET(MODULE COUNT) EXAMINE(MODULE COUNT) SELECT INPUT(1) CLOSE STREAM(2) %END ! MAP = ".OUT" %UNLESS PARAM -> PARAM.("/").MAP %C %OR PARAM -> PARAM.(",").MAP PARAM = ".IN" %IF PARAM = "" DEFINE("ST1,".PARAM) %CYCLE J = 1, 1, MAX FILES USED(J) = 0 %REPEAT TABLE(0) = 0; FILECODE(0) = 0; FILEGLA(0) = 0 CA = CODE BASE+16; GA = 16; !LEAVE SPACE FOR ENTRY INSTRUCTIONS ERRORS = 0 FILE NO = 0 REFS = 0; DEFS = MAX TABLE-4 ! SELECT(0) SELECTINPUT(1) %CYCLE PROMPT("Link: ") READ WORD(FILE NAME) %IF CHARNO(FILE NAME, 1) = '.' %START %EXIT %IF FILE NAME = ".END" %IF FILE NAME = ".STACK" %START GET OCTAL(STACK); %CONTINUE %FINISH %IF FILE NAME = ".NAME" %START PROMPT("Task name:") READ WORD(FILE NAME) LENGTH(FILE NAME) = 4 %IF LENGTH(FILE NAME) > 4 TASK ID = FILE NAME %CONTINUE %FINISH %IF FILE NAME = ".FIXUP" %START READ WORD(FIX FILE) HANDLE FIXUPS(FIX FILE) %CONTINUE %FINISH %IF FILE NAME = ".ENTRY" %START PROMPT("Entry point: "); GET OCTAL(MAIN EP) ENTRY = 1 FILE NAME = ".ALONE" %FINISH %IF FILE NAME = ".ALONE" %START PROMPT("Start of store:"); GET OCTAL(CODE BASE) PROMPT(" End of store:"); GET OCTAL( SP BASE) CA = CODE BASE; GA = 0 ALONE = 1 BRIANS FIDDLE = 0 %CONTINUE %FINISH %IF FILE NAME = ".STREAMS" %START GET OCTAL(STREAMS); %CONTINUE %FINISH %IF FILE NAME = ".NOLIB" %START LIB FILE = "" %CONTINUE %FINISH %IF FILE NAME = ".NOPERM" %START PERM FILE = ""; %CONTINUE %FINISH PRINTSTRING("Unknown keyword ".FILE NAME) NEWLINE %CONTINUE %FINISH PROCESS(FILE NAME) %REPEAT PERM = 1 PROCESS(LIB FILE) PROCESS(PERM FILE) %RETURN %IF ERRORS # 0 CP = 0; GP = 0; GBUF(0) = GA TABLE(XTOP)_ADDR = CA+2; !CODE TOP !!!HANDLE FIXUPS(FIX FILE) FILL REFS CA = CODE BASE %IF ENTRY # 0 %START MARK(1); !LOAD THE MAIN PROGRAM %FINISH %ELSE %START CA = CODE BASE+16 %IF ALONE = 0 MAIN EP = CA ERROR("No main entry point!") %IF PERM EP = 0 MARK(PERM EP); !LOAD $GO$ %FINISH TABLE(XGO)_ADDR = 0 SP = SPBASE&(\1) GLABASE = CA GLABASE = (7<<13-GA-STACK)&K'160000' %IF ALONE = 0 DS = (GLABASE+GA+7)&(\7) SP = (DS+STACK)&(\1) %IF ALONE = 0 TABLE(XSP)_ADDR = SP ERROR("No space for stack") %IF SP > SPBASE %OR DS >= SP %CYCLE J = 0, 1, FILE NO FILE GLA(J) = FILE GLA(J)+GLA BASE %REPEAT TABLE(XDS)_ADDR = DS TABLE(XEVENT)_ADDR = CA-2 FIX ADDRESSES PROMPT("Object: ") READ WORD(OBJECT) DEFINE("ST3,".OBJECT) TASK ID = OBJECT %IF TASK ID = "" SELECT(3) HEADER %IF ALONE = 0 FILE LIMIT = FILE NO FILE NO = 0 %WHILE FILE NO < FILE LIMIT %CYCLE FILE NO = FILE NO+1 FILE NAME = FILE(FILE NO) %IF FILE NAME = "" %START ERROR("Linker phase error!!!"); %RETURN %FINISH DEFINE("ST2,".FILE NAME) SELECT INPUT(2) GET(MODULE COUNT) REFS = 0 LOAD(MODULE COUNT) SELECT INPUT(1) CLOSE STREAM(2) %REPEAT FLUSH(GBUF, GP, GA) %IF GP # 0 LOCATE(MAIN EP) FLUSH(CBUF, CP, CA) %RETURN %IF ERRORS # 0 SELECT OUTPUT(0) PRINTSTRING("Linking complete"); NEWLINE DEFINE("ST2,".MAP); SELECT OUTPUT(2) !MAP NEWLINE CA = 0; GA = 0 %CYCLE J = MAX TABLE, -1, DEFS T == TABLE(J) %IF T_TYPE&32 # 0 %START %IF CA&3 = 0 %THEN NEWLINE %ELSE SPACES(GA) CA = CA+1 OCTAL(T_ADDR) SPACE PRINTSTRING(T_TEXT) GA = 12-LENGTH(T_TEXT) %FINISH %REPEAT NEWLINE NEWLINE %CYCLE J = 1, 1, FILE NO %CONTINUE %IF USED(J) = 0 %OR FILE(J) = "" OCTAL(FILE CODE(J)); SPACE OCTAL(FILE GLA(J)); SPACE PRINTSTRING(FILE(J)) NEWLINE %REPEAT NEWLINE PRINTSTRING("SP = "); OCTAL(SP); NEWLINE PRINTSTRING("DS = "); OCTAL(DS); NEWLINE %END %ENDOFFILE