!! 28-JAN-81 ! ************************************************************** ! * * ! * PERKIN-ELMER 32-BIT SERIES IMP COMPILER * ! * INTERMEDIATE CODE ASSEMBLER * ! * * ! * (GENERAL SERVICE VERSION) * ! * * ! * C.H. WHITFIELD * ! * 19, REDFORD TERRACE * ! * COLINTON, * ! * EDINBURGH EH13-0BT * ! * * ! * COPYRIGHT (c) MAY 1ST. 1980 * ! * ALL RIGHTS RESERVED * ! * * ! ************************************************************** ! Pass 3 for 7/32 Imp ! =========== ! N.B. All loader-visible addresses generated by pass2 are in units ! of halfwords. ! =========== ! ****Compatibility header: to disappear with old-format EXE files constinteger h8 = 8 ! begin include "Sysinc:Com.inc" constinteger direct=1, object=2 constinteger report=0 ! N.B. <0 for diagnostic tracing, >0 for extra details of dumped code constinteger diagnostic = 0 constinteger register template = x'7DEF'; ! wsp, code, gla, link constinteger max tag=2050 constinteger max ref=2900 constinteger max proc=255 constinteger bmax = 8; ! no. of DA buffers available to phase 2 constinteger safe pc rel = 6500; ! 'SAFE' limit in stretch routines q.v. ! Parameters related to diagnostic table generation constinteger indirect = x'4000' constinteger line diag limit = 31 constinteger proc header=1, diag entry=0, linkage name=-1; ! 'descriptions' constinteger none = 0, partial = 1, full = 2 owninteger diags = full, hide = 0 constinteger main prog = x'4000'; ! main program marker in event chain conststring (3) main ep = "%GO"; ! must match pass 2 conststring (6) trace ep = "$TRACE"; ! likewise constinteger init lit = 4; ! halfwords: must not exceed pass 2 value !******** constshortinteger max prim = 52 constshortintegerarray prim(1:1018) = c x'026F',x'0215',x'0224',x'0035',x'0064',x'0087',x'00D7',x'015A',x'00C1', x'0232',x'029A',x'0160',x'02B3',x'02C7',x'02E7',x'030A',x'01C5',x'01F5', x'01AB',x'0335',x'02AA',x'0294',x'028E',x'0278',x'0288',x'0315',x'0188', x'0194',x'02A2',x'0051',x'0251',x'0265',x'0244',x'019E',x'03AF',x'03CD', x'03DC',x'03EC',x'0000',x'0000',x'0000',x'0000',x'0000',x'0000',x'0000', x'0000',x'0000',x'0000',x'039C',x'03A3',x'0338',x'033F',x'001B',x'480F', x'0000',x'2133',x'3402',x'9400',x'9300',x'D331',x'0000',x'C530',x'0080', x'2138',x'D431',x'0001',x'2135',x'2408',x'2411',x'8883',x'0034',x'0503', x'2385',x'2401',x'2417',x'8883',x'0034',x'26F2',x'8888',x'001E',x'0012', x'0512',x'033F',x'D331',x'0000',x'9433',x'3443',x'F830',x'FF00',x'0001', x'D301',x'4400',x'0000',x'D202',x'4400',x'0000',x'0A43',x'2087',x'030F', x'0022',x'480F',x'0000',x'2133',x'3402',x'9400',x'9300',x'D331',x'0000', x'C530',x'0080',x'2138',x'D431',x'0001',x'2135',x'2408',x'2411',x'8883', x'0034',x'2440',x'0503',x'2383',x'0830',x'2304',x'D301',x'4400',x'0000', x'D202',x'4400',x'0000',x'2641',x'2731',x'2218',x'430F',x'0002',x'0039', x'480F',x'0000',x'2133',x'3402',x'9400',x'9300',x'D331',x'0000',x'C530', x'0080',x'2138',x'D431',x'0001',x'2135',x'2408',x'2411',x'8883',x'0034', x'D342',x'0000',x'C540',x'0080',x'2134',x'D442',x'0001',x'223B',x'0A43', x'C540',x'0100',x'2185',x'2401',x'2413',x'8883',x'0034',x'0B04',x'2315', x'2401',x'2417',x'8883',x'0034',x'D242',x'0000',x'0B43',x'0A42',x'2450', x'2308',x'D301',x'4500',x'0001',x'D204',x'4500',x'0001',x'2651',x'2731', x'2218',x'430F',x'0002',x'0015',x'2441',x'D331',x'0000',x'D302',x'0000', x'0B30',x'231B',x'0A03',x'2309',x'D351',x'4400',x'0000',x'D452',x'4400', x'0000',x'023F',x'2641',x'2701',x'2219',x'0833',x'030F',x'0082',x'735F', x'0000',x'9465',x'1058',x'2133',x'3452',x'9455',x'9355',x'1068',x'2133', x'3464',x'9466',x'9366',x'D0B7',x'0000',x'D3B3',x'0000',x'C5B0',x'0080', x'2134',x'D4B3',x'0001',x'2339',x'D301',x'0000',x'C500',x'0080',x'2138', x'D401',x'0001',x'2135',x'2408',x'2411',x'8883',x'0034',x'0BB0',x'4210', x'80A8',x'24C0',x'0800',x'4330',x'8038',x'D301',x'0001',x'D403',x'4C00', x'0001',x'2339',x'26C1',x'05BC',x'2286',x'4300',x'808A',x'D301',x'0001', x'2207',x'08E3',x'0AEC',x'D3D1',x'0000',x'27D1',x'D30E',x'4D00',x'0001', x'D401',x'4D00',x'0001',x'203E',x'27D1',x'2028',x'0822',x'2334',x'055C', x'4280',x'8062',x'08DC',x'0844',x'233A',x'D301',x'0000',x'0AC0',x'D3E3', x'0000',x'0BEC',x'056E',x'4280',x'804A',x'0822',x'233C',x'D2D2',x'0000', x'2307',x'D303',x'4D00',x'0001',x'D202',x'4D00',x'0001',x'27D1',x'2217', x'0844',x'4330',x'801C',x'D2E4',x'0000',x'0AC3',x'24D0',x'2308',x'D30C', x'4D00',x'0001',x'D204',x'4D00',x'0001',x'26D1',x'27E1',x'2218',x'2501', x'D1B7',x'0000',x'430F',x'0002',x'2400',x'2205',x'D1B7',x'0000',x'2401', x'2417',x'8883',x'0034',x'0005',x'023F',x'2407',x'2410',x'8883',x'0034', x'0027',x'D301',x'0000',x'C500',x'0080',x'2138',x'D401',x'0001',x'2135', x'2408',x'2411',x'8883',x'0034',x'0822',x'2326',x'0503',x'2184',x'CB32', x'FFFF',x'2316',x'0843',x'2405',x'2414',x'8883',x'0034',x'0A21',x'C817', x'0000',x'D231',x'0000',x'2307',x'D302',x'4300',x'0000',x'D201',x'4300', x'0001',x'2731',x'2217',x'030F',x'000B',x'1132',x'2307',x'5801',x'4300', x'0000',x'5002',x'4300',x'0000',x'2734',x'2217',x'030F',x'0009',x'1132', x'2400',x'2304',x'5002',x'4300',x'0000',x'2734',x'2214',x'030F',x'000C', x'0B44',x'D301',x'4400',x'0000',x'D402',x'4400',x'0000',x'023F',x'2641', x'0543',x'2039',x'030F',x'0019',x'0831',x'4932',x'0002',x'212C',x'4B32', x'0000',x'2119',x'0A33',x'7333',x'4200',x'0004',x'2339',x'0A33',x'0A3E', x'0303',x'0821',x'2406',x'2413',x'8883',x'0034',x'0821',x'2408',x'2412', x'8883',x'0034',x'002F',x'D097',x'0000',x'2431',x'2410',x'489F',x'0000', x'08B4',x'48AF',x'0002',x'58CB',x'0008',x'5BCB',x'0004',x'26C1',x'4210', x'8030',x'50CB',x'0000',x'1C0C',x'5B1B',x'0004',x'1C2C',x'26BC',x'2791', x'203F',x'50AB',x'0000',x'1C0A',x'1C2A',x'2633',x'C430',x'FFFC',x'48CF', x'0000',x'50C4',x'0000',x'D197',x'0000',x'430F',x'0004',x'084B',x'D197', x'0000',x'2405',x'2413',x'8883',x'0034',x'001F',x'0807',x'0A03',x'590D', x'0000',x'2325',x'2402',x'2411',x'8883',x'0034',x'0A71',x'5072',x'0000', x'5042',x'0004',x'2628',x'0870',x'580E',x'000C',x'F500',x'8080',x'8080', x'023F',x'2450',x'0B53',x'033F',x'5007',x'4500',x'0000',x'2654',x'2034', x'030F',x'000E',x'0822',x'2315',x'2405',x'2412',x'8883',x'0034',x'2401', x'2411',x'2302',x'1C03',x'2721',x'2212',x'8888',x'0015',x'000D',x'2401', x'2F00',x'0801',x'2316',x'2D02',x'2820',x'2400',x'CB01',x'0001',x'033F', x'2C02',x'2701',x'2203',x'8010',x'2802',x'2114',x'6A00',x'8010',x'2305', x'6B00',x'800A',x'6A20',x'800A',x'2800',x'2B20',x'030F',x'4600',x'0000', x'4110',x'0000',x'0000',x'800C',x'2822',x'2114',x'6A20',x'800C',x'2303', x'6B20',x'8006',x'2E12',x'030F',x'0000',x'4080',x'0000',x'0013',x'480F', x'0000',x'2133',x'3401',x'9400',x'9300',x'0822',x'2328',x'0502',x'2186', x'E611',x'4200',x'0000',x'430F',x'0002',x'2406',x'2415',x'8883',x'0034', x'0009',x'581D',x'0000',x'CB17',x'0200',x'031F',x'2402',x'2411',x'8883', x'0034',x'0008',x'023F',x'2408',x'2411',x'8883',x'0034',x'0000',x'8080', x'8080',x'000F',x'0822',x'233A',x'0B10',x'0801',x'EE00',x'001F',x'1D02', x'0811',x'2113',x'0800',x'033F',x'2405',x'2411',x'8883',x'0034',x'0005', x'033F',x'2404',x'2412',x'8883',x'0034',x'0005',x'033F',x'2401',x'2415', x'8883',x'0034',x'0005',x'034F',x'2401',x'2415',x'8883',x'0034',x'0007', x'D401',x'0000',x'038F',x'2401',x'2417',x'8883',x'0034',x'0007',x'C320', x'FFE0',x'033F',x'2405',x'2416',x'8883',x'0034',x'0008',x'0800',x'033F', x'2601',x'033F',x'2401',x'2411',x'8883',x'0034',x'0013',x'5823',x'0004', x'5912',x'0004',x'2119',x'5912',x'0008',x'2126',x'5C02',x'000C',x'5A13', x'0000',x'030F',x'0842',x'0821',x'2406',x'2412',x'8883',x'0034',x'001F', x'5843',x'0004',x'5914',x'0004',x'4210',x'8028',x'5914',x'0008',x'4220', x'8020',x'5C04',x'000C',x'5924',x'0010',x'211A',x'5924',x'0014',x'2127', x'0A12',x'5C04',x'0018',x'5A13',x'0000',x'030F',x'0812',x'264C',x'0821', x'2406',x'2412',x'8883',x'0034',x'0022',x'5853',x'0004',x'5845',x'0000', x'2741',x'1142',x'0A42',x'0801',x'2410',x'2744',x'5905',x'0004',x'4210', x'801C',x'5905',x'0008',x'212C',x'0A10',x'5C05',x'000C',x'265C',x'5804', x'0000',x'0542',x'228F',x'5A13',x'0000',x'030F',x'0845',x'0820',x'2406', x'2412',x'8883',x'0034',x'000A',x'5843',x'0004',x'5C04',x'000C',x'0A12', x'5C04',x'0018',x'5A13',x'0000',x'030F',x'001F',x'0847',x'484F',x'0000', x'732F',x'0002',x'1122',x'0B42',x'0A27',x'583D',x'0000',x'C532',x'0200', x'2385',x'2402',x'2411',x'8883',x'0034',x'26F4',x'0872',x'F830',x'8080', x'8080',x'553E',x'000C',x'023F',x'5037',x'4400',x'0000',x'2644',x'2224', x'030F',x'0002',x'8883',x'0034',x'0006',x'D007',x'002C',x'0867',x'CA70', x'006C',x'8102',x'005C',x'D007',x'002C',x'584D',x'0008',x'2337',x'5004', x'0000',x'5014',x'0004',x'5024',x'0008',x'C8A7',x'0040',x'0810',x'2441', x'ED41',x'0000',x'0813',x'4120',x'805C',x'0855',x'2315',x'083F',x'0813', x'4120',x'8050',x'4826',x'0002',x'9352',x'1152',x'585A',x'45FF',x'FFEC', x'0822',x'4210',x'8022',x'7316',x'0008',x'0A11',x'0A1E',x'0931',x'232C', x'4816',x'0004',x'0414',x'2338',x'D17A',x'0008',x'7316',x'0006',x'0A11', x'0A1E',x'0301',x'C320',x'4000',x'2138',x'5835',x'0028',x'58E5',x'0024', x'08A5',x'4300',x'FFB0',x'D107',x'002C',x'8101',x'736E',x'40FF',x'FFFE', x'0A66',x'0B1E',x'7306',x'4E00',x'0000',x'0A00',x'0856',x'0B50',x'0916', x'2123',x'0915',x'2128',x'0865',x'221B',x'D107',x'002C',x'2400',x'241F', x'8101',x'0855',x'0212',x'0A6E',x'0302',x'0006',x'583D',x'0004',x'08C8', x'0183',x'088C',x'030F',x'000B',x'486F',x'0000',x'26F2',x'085F',x'D057', x'0000',x'D1DD',x'8887',x'082F',x'08F5',x'0302',x'001D',x'2400',x'C830', x'001C',x'5841',x'4300',x'0000',x'5852',x'4300',x'0000',x'0865',x'0464', x'0964',x'2333',x'C600',x'0001',x'0965',x'2333',x'C600',x'0002',x'2734', x'4310',x'FFDA',x'2460',x'450F',x'0000',x'2132',x'2461',x'430F',x'0002', x'000E',x'C830',x'001C',x'5801',x'4300',x'0000',x'5602',x'4300',x'0000', x'5001',x'4300',x'0000',x'2734',x'221A',x'030F',x'000F',x'C830',x'001C', x'2501',x'5702',x'4300',x'0000',x'5401',x'4300',x'0000',x'5001',x'4300', x'0000',x'2734',x'221B',x'030F',x'000E',x'C830',x'001C',x'5801',x'4300', x'0000',x'5402',x'4300',x'0000',x'5001',x'4300',x'0000',x'2734',x'221A', x'030F' !******** ! ==== control codes ==== constinteger tag defn = 1 constinteger r ref = 2 constinteger p ref = 3 constinteger sw ref = 4 constinteger j ref = 5 constinteger c ref = 6 constinteger code item = 7 constinteger gla item = 8 constinteger line diag = 9 constinteger line reset = 10 constinteger var diag = 11 constinteger code area = 12 constinteger lit area = 13 constinteger lit org = 14 constinteger frame patch = 15 constinteger proc head = 16 constinteger proc end = 17 constinteger prog end = 18 constinteger code rel = 19 constinteger gla rel = 20 constinteger extern = 21 ! external reference sub-types constinteger data spec = 4, data defn = 5 constinteger ep spec = 6, ep defn = 7 ! ======== constants associated with code generation ======== constinteger align=3; ! single word alignment (literal area) constinteger emark = x'8880', tmark = x'8887' constinteger backwards = X'0100'; ! short jump modifier constinteger code base = 14; ! code base register constinteger BZ = X'433E', BZS = X'2330' constinteger BNZ = X'423E', BNZS = X'2130' constinteger BM = X'421E', BMS = X'2110' constinteger BP = X'422E', BPS = X'2120' constinteger BNP = X'432E', BNPS = X'2320' constinteger BNM = X'431E', BNMS = X'2310' constinteger JMP = X'430E', JMPS = X'2300' constinteger BAL = X'410E' constshortintegerarray short jump(0:12) = BZS, BNZS, BMS, BPS, BNPS, BNMS, BNZS, BZS, BPS, BMS, BNMS, BNPS, JMPS constshortintegerarray long jump(0:12) = BZ, BNZ, BM, BP, BNP, BNM, BNZ, BZ, BP, BM, BNM, BNP, JMP ! == flag bits used in 'REF' table == constinteger short=1 constinteger long=2 constinteger pc rel=4 constinteger very=8 constinteger invert=16 constinteger remove=32 constinteger rcall=64 constinteger safe=128 constinteger conditional=256 ! == values used in code generation phase ( reftype(k)=0 -> 'REMOVE' ) == constinteger sf=1 constinteger rx1=2 constinteger rx2=3 constinteger rx3=4 constinteger sign bit = x'80000000' constinteger halfword sign = x'FFFF8000' ! ** Purely for accumulating jump instruction statistics owninteger sfjump=0, rx1jump=0, rx2jump=0, rx13jump=0 ! ** For accumulating counts in various bits of program owninteger localtot=0,localnonsafe=0, globaltot=0,globalnonsafe=0 owninteger buff miss1=0, buff miss2=0, buff miss3=0 ! ** for recording timings integer t0,t1,t2; ! phase 1, phase 2 timing integer t10, t11, t12; ! local, global stretch timing (inside phase 1) recordformat reffm(shortinteger tag, link, flags, ca) recordformat deffm(record (deffm)name link, shortinteger proc,ca) recordformat procfm(record (procfm)name link, record (reffm)name ref list, record (deffm)name def list, shortinteger base, ca, static frame, event mask, display reg, event start, event finish, ld base, ld size, vd base, vd size, Me) record (procfm)array proc(1:max proc) record (deffm)array tagdef(1:max tag) byteintegerarray reftype(1:max ref) owninteger refs = 0 constrecord (*)name null == (0) record (procfm)name proc1, last proc; ! ** N.B. proc1 ultimately is prim ** shortintegerarray prim entry(1:max prim) integer header size, gla size, code size, literal size integer var diags, line diags owninteger defns = 0, specs = 0, relocations = 0 integer current line, line incr, ca incr integer j,k,l tagdef(j) = 0 for j = 1,1,max tag prim entry(j) = -1 for j = 1,1,max prim proc1 == proc(1); proc1 = 0 last proc == proc1 routine phex(shortinteger n) integer j,k for j = 12,-4,0 cycle k = (n>>j)&15 if k < 10 then k = k+'0' else k = k-10+'A' print symbol(k) repeat end routine error(integer n,p) select output(report) print string("*ERROR"); write(n,1) print symbol(':'); write(p,4) newline signal 15,15 end routine get(integername n) integer j,k read symbol(j); read symbol(K) n = j<<8 ! k end routine phase one; ! Input directives and expand jumps record (reffm)array ref(1:max ref) record (procfm)name pp, qq integer procs; procs = 0 integer ca total; ca total = 0 integer extra, n integer j routine input directives owninteger depth = 0 owninteger code = 0, n = 0, ca = 0 record (reffm)name r record (deffm)name d, dd record (procfm)name p integer last ref, this proc, last line switch dir(1:extern) depth = depth+1 procs = procs+1 this proc = procs; p == proc(procs); p = 0 P_Me = This proc p_ld size = diags; ! FRIG: 0 = none, 1 = partial, 2 full ! 0 + ( ( line org + ( link )? )? p_vd size = 0 if diags > none start ; ! p_vd size set = zero above p_vd size = 4; ! procedure identifier p_vd size = 5 if diags = full; ! link required as well finish last line = current line; ! ??????? last ref = 0; r == null cycle read symbol(code) -> dir(code) if 0 < code <= extern !!dir(*): error(0,code) dir(proc head): ! <proc index> read symbol(n); error(1,n) unless n = procs input directives continue dir(proc end): ! <code size> <no. var diags> <static frame size> ! <local display register> <event mask> <event start> <event finish> get(ca) get(n) p_vd size = p_vd size + n if diags = full; ! header+local idents get(n); p_static frame <- n p_display reg = next symbol; skip symbol; ! avoid any limited 'read symbol' get(n); p_event mask <- n get(n); p_event start = n; ! tag no get(n); p_event finish = n; ! tag no depth = depth-1; return if depth = 0 p_ca = ca+2; ! size + basic event header p_ca = p_ca+3 if p_event mask # 0; ! full form required ca total = ca total + ca ! *** reverse reference list - should grow it forwards *** if not r == null start n = last ref; last ref = 0 while n # 0 cycle r == ref(n) k = r_link; r_link = last ref last ref = n n = k repeat finish p_ref list == r last proc_link == p; last proc == p return dir(tag defn): ! <tag no> <ca> *N.B. switch defns. have x'8000' bit set* get(j); get(ca) n = j&x'7FFF'; ! mask out 'switch' bit error(3,n) unless 0 < n <= max tag d == tag def(n) if not d_link == null start ; ! already defined error(4,n) if j&x'8000' = 0; ! not a switch tag so it's an error ! remove existing entry so it can be redefined if not p_def list == d start dd == p_def list dd == dd_link while not dd_link == d dd_link == d_link else p_def list == d_link finish finish d_proc = this proc; d_ca = ca d_link == p_def list p_def list == d continue dir(r ref): ! <n> <ca> code = r call + long; -> ref ref dir(j ref): code = short; -> ref ref dir(c ref): code = short + conditional ref ref: get(n); get(ca) error(5,n) unless 0 < n <= max tag error(6,n) if refs = max ref refs = refs+1 r == ref(refs) r_link = last ref; last ref = refs r_tag = n r_ca = ca r_flags = code continue dir(sw ref): ! <n> <ca> * * * IGNORED * * * get(n); get(ca) continue dir(p ref): ! <n> <ca> get(n); get(ca) prim entry(n) = -2 continue dir(line reset): get(n); current line = n-1 dir(line diag): current line = current line+1 if diags = full start p_ld size = p_ld size + 1 p_ld size = p_ld size + 1 unless c 0 <= current line-last line <= line diag limit finish last line = current line continue repeat end ; ! input directives routine set prim(integer n) integer a,j,k,base,to error(9,n) unless 0 < n <= max prim return if prim entry(n) >= 0 base = proc1_ca; ! current size of prim package j = prim(n); ! entry to pointer table k = prim(j); ! size of this prim routine if k&x'8000' # 0 start ; ! routine to be full-word aligned base = (base+1)&(¬1) finish k = k & x'7FFF'; ! strip 'align' bit prim entry(n) = base proc1_ca = base + k*(2//2); ! halfwords to = j+k; ! N.B. j+1:to inclusive while j # to cycle j = j+1; a = prim(j)&x'FFFF' if a&x'FFF0' = emark and a # tmark start j = j+1; a = prim(j) set prim(a) if prim entry(a) < 0 finish repeat end ; ! set prim routine local stretch(record (procfm)name p) record (deffm)name d,dd record (reffm)name r integer j,n,mod return if p_ref list == null; ! no references !! cycle n = 0; mod = 0 r == p_ref list cycle local tot = local tot+1; ! *** monitoring only *** r_ca = r_ca + mod if r_flags&(long!rcall!safe) = 0 start local nonsafe = local nonsafe+1; ! *** monitoring only *** d == tagdef(r_tag) j = r_ca unless j-30//2 <= d_ca <= j+30//2 start n = 1; mod = mod + (2//2) p_ca = p_ca + (2//2) r_flags = r_flags ! long if j+2-16384//2 <= d_ca <= j+2+16384//2-1 start r_flags = r_flags ! pc rel r_flags = r_flags ! safe if |(j-d_ca)| <= safe pc rel finish dd == p_def list cycle exit if dd == null or dd_ca <= r_ca dd_ca = dd_ca+(2//2) dd == dd_link repeat finish finish exit if r_link = 0 r == ref(r_link) repeat exit if n = 0 repeat end ; ! local stretch routine global stretch(record (procfm)name p, integername extra) record (procfm)name pp record (deffm)name d,dd record (reffm)name r integer j,k,x,n,mod,me extra = 0 and return if p_ref list == null x = 0 cycle n = 0; mod = 0 r == p_ref list; Me = P_Me cycle global tot = global tot+1; ! *** monitoring only *** r_ca = r_ca + mod if r_flags&(safe!very) = 0 start global nonsafe = global nonsafe+1; ! *** monitoring only *** d == tagdef(r_tag) j = p_base + r_ca ! ****** This wants cleaning up ****** if D_Proc # Me or R_Flags&rcall # 0 start k = proc(d_proc)_base + d_ca if j+2-16384//2 <= k <= j+2+16384//2-1 start r_flags = r_flags ! pc rel r_flags = r_flags ! safe if |(j-k)| <= safe pc rel -> NEXT if R_Flags&Long # 0 finish else k = p_base + d_ca finish -> NEXT if j-30//2 <= k <= j+30//2; ! short form adequate if r_flags&long = 0 start r_flags = r_flags ! long if j+2-16384//2 <= k <= j+2+16384//2-1 start r_flags = r_flags ! pc rel r_flags = r_flags ! safe if |(j-k)| <= safe pc rel finish else if (r_flags & pc rel = 0 and not 0 <= k <= 16383//2) c or (r_flags & pc rel # 0 c and not j+2-16384//2 <= k <= j+2+16384//2-1) if 0 <= k <= 16383//2 start r_flags = r_flags & (¬pc rel) -> NEXT finish r_flags = r_flags ! very else -> NEXT finish !************************************ n = 1; x = x+(2//2); mod = mod+(2//2) p_ca = p_ca + (2//2) dd == p_def list cycle exit if dd_ca <= r_ca dd_ca = dd_ca + (2//2) dd == dd_link repeat pp == p cycle pp == pp_link; exit if pp == null pp_base = pp_base+(2//2) repeat finish NEXT: exit if r_link = 0 r == ref(r_link) repeat exit if n = 0 repeat extra = x end ; ! global stretch routine condense constbyteintegerarray m(0:15) = SF, SF, ! 0 1 RX1, RX1, ! 2 3 RX2, RX2, RX2, RX2, ! 4 5 6 7 RX3, RX3, RX3, RX3, RX3, RX3, RX3, RX3 ! 8 9 10 11 12 13 14 15 integer j,f for j = 1,1,refs cycle f = ref(j)_flags if f&remove # 0 start reftype(j) = 0 else reftype(j) = m(f&15) ! ( f & (invert+rcall) ) finish repeat if diagnostic < 0 start for j = 1,1,refs cycle if (j-1)&15 = 0 start newline; write(j,-4); print string(": ") finish write(reftype(j),2) repeat newlines(2) finish end ; ! condense ! === for diagnostics only === routine dump tags integer k integerfn tagno(record (deffm)name d) integer k for k = 1,1,max tag cycle result = k if tagdef(k) == d repeat signal 15,15 end routine dump proc(integer n) record (procfm)name p record (deffm)Name d integer k; k = 0 p == proc(n) print string(" base"); write(p_base,1) print string(" size"); write(p_ca,1) newline d == p_deflist while not d == null cycle write(tagno(d),3); print symbol(':') write(d_ca,0) k = k+1 newline if k&7 = 0 d == d_link repeat newline if k&7 # 0 end for k = 1,1,procs cycle newline; print string("proc"); write(k,1) dump proc(k) repeat end ; ! dump tags select input(direct) current line = 0 input directives last proc_link == null readsymbol(j) error(-1, j) unless j = prog end ! read next six halfwords defining various sizes for last block: ! <code size> <literal size> <gla size> <defns> <specs> <relocations> !===== size in halfwords get(code size); get(literal size); get(gla size) !===== no. of items get(defns); get(specs); get(relocations) error(8,ca total) if code size # ca total for j = 1,1,max prim cycle set prim(j) if prim entry(j) = -2 repeat proc1_ca = proc1_ca+2; !event marker+link dump tags if diagnostic < 0 t10 = cpu time; ! *** monitoring only *** ! Initial stretching and block allocation ! no diags in perm == proc1 !!! proc1_ld size = 0 !!! proc1_vd size = 0 pp == proc1 cycle qq == pp_link; exit if qq == null local stretch(qq) qq_base = qq_base + pp_base + pp_ca qq_ld base = pp_ld base + pp_ld size qq_vd base = pp_vd base + pp_vd size pp == qq repeat dump tags if diagnostic < 0 t11 = cpu time; ! *** monitoring only *** ! Routine calls and final stretch cycle n = 0 pp == proc1 cycle pp == pp_link; exit if pp == null global stretch(pp,extra) if extra # 0 start n = n+1 pp_ca = pp_ca + extra qq == pp cycle qq == qq_link; exit if qq == null qq_base = qq_base + extra repeat finish repeat exit if n = 0 repeat dump tags if diagnostic < 0 t12 = cputime; ! *** monitoring only *** condense; ! from ref(k)_flags -> reftype(k) line diags = last proc_ld base + last proc_ld size var diags = last proc_vd base + last proc_vd size code size = last proc_base + last proc_ca end ; ! phase one routine phase two ! generate final object file using 'tag defn' and 'ref type' tables recordformat bfm(record (bfm)name link, integer block, c shortintegerarray b(0:255)) recordformat sfm(integer zero addr, lower, upper, ca) record (sfm) code, gla, ldiag, vdiag, reloc, defn, spec constinteger bmax = 8; ! no. of da buffers (at least 2 !!) record (bfm)array buffpool(1:bmax) record (bfm)name buff list, bp recordformat hdfm(shortinteger p1,p2) recordformat headerfm(shortinteger pure size,gla size, code disp, c lit disp, registers, main ep, c record (hdfm) reloc, defn, spec, ldiag, vdiag) record (headerfm) header; constinteger basic header=18; ! ** halfwords ** ! formats associated with external linkage recordformat namefm(shortinteger n1a,n1b,n2a,n2b) recordformat xdeffm(record (namefm) n, integer ep) recordformat specfm(integer code, gla, link) recordformat descriptionfm(integer base,disp,type,size,form,otype, c data size, shortinteger ident len, string (12) sym) record (descriptionfm) xd integer this proc; this proc = 0 integer total blocks integer op, cond, tag, extra integer ref; ref = 0 integer event link, ldiag link, vdiag link, defn link, spec link, asynch link integer trace patch = 0; ! point in perm to patch in jump to $TRACE integer j,k,l ! =================== SYSTEM DEPENDENT ===================== recordformat parmfm(shortinteger dsno,dact,ssno,sact, c integer p1,p2,p3,p4,p5,p6) owninteger da key = 0 constinteger da read = 9, da write = 10 routine open da(string (31)name fd, integer blocks) record (parmfm) p,q string(addr(p_sact)) = fd; svc(17,p); ! pack if p_p2 < 0 start print string(fd."?"); newline stop finish q = p p_dact = 14; svc(20,p); ! delete p = q; p_p5 = blocks p_dact = 2; svc(20,p); ! create if p_p6 >= 0 start p = q p_p5 = 1; !permit write p_dact = 6; svc(20,p); ! open da da key = p_p5 and return if p_p6 >= 0 finish print string("open da: ".string(addr(p_p1))); newline stop end routine close da record (parmfm) p p_p5 = da key p_dact = 11; svc(20,p) da key = 0 return if p_p6 >= 0 print string("close da: ".string(addr(p_p1))); newline stop end routine block io(record (bfm)name block, integer iofn) record (parmfm) p p_p4 = addr(block_b(0)) p_p5 = da key p_p6 = block_block; ! block number req'd p_dact = iofn; svc(20,p) return if p_p6 >= 0 print string("block io: ".string(addr(p_p1))); write(block_block,1) newline signal 15,15 end ! ========================================================== ! Initialise buffer pool buff list == null for j = 1,1,bmax cycle bp == buff list buff list == buffpool(j) buff list_block = -1; buff list_link == bp repeat ! Initialise control records routine set section(record (sfm)name sect, integer sect size, c record (hdfm)name hd) sect_zero addr = header size; header size = header size + sect size sect_lower = 0 sect_upper = sect size sect_ca = 0 hd_p1 = sect_zero addr; hd_p2 = 0 end ; ! set section header size = basic header defns = defns*(3*2); ! 3 fullwords each specs = specs*(2*2); ! 2 fullwords each relocations = relocations*((2//2)); ! 1 halfword each literal size = (literal size + 3)&(¬3); ! double word align code size = code size + proc1_ca; ! allow for prim ! N.B. == defn and spec are fullword aligned in output file == set section(defn,defns,header_defn) set section(spec,specs,header_spec) set section(reloc,relocations,header_reloc) set section(ldiag,line diags,header_ldiag) set section(vdiag,var diags,header_vdiag) header size = (header size+3)&(¬3); ! align literals + code code_zero addr = header size + literal size code_lower = -literal size code_upper = code size code_ca = 0 gla_zero addr = (code_zero addr + code size + h8 + 255)&(¬255); ! block align gla_lower = 0 gla_upper = gla size gla_ca = 0 header_registers = register template header_main ep = -1; ! default: reset if a main program header_code disp = code_zero addr; ! within-file disp. header_lit disp = header size; ! within-file disp. header_pure size = code_zero addr + code size header_gla size = gla size total blocks = (gla_zero addr + gla size + 255) >> 8 header_reloc_p2 = relocations; ! no. of halfwords header_defn_p2 = defns record (bfm)map buff(integer addr) record (bfm)name this,last integer block block = addr>>8; ! ** N.B. halfword addressing units, 512 byte block ** result == buff list if block = buff list_block buff miss1 = buff miss1+1; ! *** monitoring only *** if diagnostic < 0 start printstring("block"); write(block,1); newline finish last == buff list cycle buff miss3 = buff miss3+1; ! *** monitoring only *** this == last_link -> promote if this_block = block exit if this_link == null last == this repeat if this_block < 0 start ; ! buffer still free this_block = block else block io(this,da write) this_block = block block io(this,da read) buff miss2 = buff miss2+1; ! *** monitoring only *** finish promote: last_link == this_link this_link == buff list buff list == this result == buff list end ; ! of 'buff' routine flush buffers record (bfm)name this integer k this == buff(0) if h8 # 0 start this_b(0) = (header_pure size + h8 + 255)//256 this_b(1) = (header_gla size + 255)//256 this_b(2) = x'4321'; ! new format identifier this_b(3) = 0; this_b(4) = 0; this_b(5) = 0 this_b(6) = 0; ! flags this_b(7) = 0; ! stack finish for k = 0,1,basic header-1 cycle this_b(k+h8) = short integer(addr(header)+k*2) repeat this == buff list cycle block io(this,da write) if this_block >= 0 this == this_link exit if this == null repeat end ; ! flush buffers routine origin(record (sfm)name section, integer org) if diagnostic < 0 start if diagnostic <= -2 start print string("ORG:"); write(org,1) write(section_lower,6); write(section_upper,1) newline finish finish section_ca = org and return if section_lower <= org <= section_upper error(25,org) end routine put(record (sfm)name section, shortinteger item) record (bfm)name bp integer addr owninteger last = -1 addr = section_zero addr + section_ca addr = addr + h8 unless section == gla if diagnostic < 0 start if diagnostic < -2 start ; ! two-stage test for speed newline if addr # last+1 last = addr write(addr,4); print string(": "); phex(item) newline finish finish bp == buff(addr) bp_b(addr&255) = item section_ca = section_ca + 1 end ; ! of 'put' routine put name(record (sfm)name sect) integer j; shortinteger half integerfn ch(integer sym) result = sym-'A'+1 if 'A' <= sym <= 'Z' result = sym-'a'+1 if 'a' <= sym <= 'z'; ! ** lower case alphabet ** result = sym-'0'+27 if '0' <= sym <= '9' result = sym-'#'+37 if '#' <= sym <= '%'; ! 37='#', 38='$', 39='%' result = 0 if sym = ' ' result = -1 end ; ! ch routine pack3(integer k, shortintegername n) integer p,q,r p = charno(xd_sym,k); q = charno(xd_sym,k+1); r = charno(xd_sym,k+2) n <- ( (ch(p)*40 + ch(q))*40 + ch(r) ); ! ugh!!! end ; ! pack3 charno(xd_sym,j) = ' ' for j = length(xd_sym)+1,1,xd_ident len for j = 1,3,xd_identlen-2 cycle pack3(j,half); put(sect,half) repeat end ; ! put name routine set description(integer desc type) integer sym,j,k,l, char read symbol(k) l = k; l = 12 if l > 12 length(xd_sym) = l for j = 1,1,l cycle readsymbol(char) char = char - 'a' + 'A' if c 'a' <= char <= 'z' charno(xd_sym,j) = char repeat k = k-l skip symbol and k = k-1 while k > 0 xd_ident len = 12; ! assume full 12-character ident. return if desc type = proc header; ! only ident. present xd_identlen = 6 if l <= 6 and desc type = diag entry read symbol(xd_otype) read symbol(k) xd_type = k>>4; xd_form = k&15 read symbol(j); get(k) xd_base = j>>4 xd_disp = (j&15)<<16 + (k&x'FFFF') if diagnostic < 0 start print string(xd_sym.": "); write(xd_identlen,1) write(xd_base,1); write(xd_disp,4) write(xd_type,3); write(xd_form,1); write(xd_otype,1) newline finish end ; ! set description routine insert prims integer j,k,l,m,to for j = 1,1,max prim cycle k = prim entry(j) if k >= 0 start if diagnostic < 0 start print string("prim"); write(j,1); print symbol(' '); phex(k) newline finish origin(code,proc1_base + prim entry(j)) k = prim(j) to = k + prim(k) & x'7FFF'; ! strip 'align' bit while k # to cycle k = k+1; m = prim(k)&x'FFFF' if m&x'FFF0' # emark start put(code,m) else if m = tmark; ! trace routine external call trace patch = code_ca put(code,m) else if m&15 = 8 start put(code, jmp) else put(code, bal + (m&15)<<4) finish k = k+1; m = prim(k) l = prim entry(m); ! pointer to referenced routine error(15,j) if l < 0 put(code,(proc1_base+l)*2); ! byte displacement finish repeat finish repeat asynch link = prim entry(max prim); ! *** must be last entry in perms *** end ; ! 'insert prims' routine plant code ref integer j,k,l,t,there record (deffm)name d switch format(SF:RX3) ref = ref+1; t = reftype(ref) d == tagdef(tag) there = proc(d_proc)_base + d_ca + extra cond = cond+6 if t&invert # 0 op = long jump(cond) if t&rcall = 0 -> format(t&7) format(SF): ! short format sfjump = sfjump+1 l = 0; k = there-code_ca; ! halfword disp. req'd here if k < 0 start l = backwards; k = -k finish error(200,code_ca) if k > 15; ! error in reference table put(code,(short jump(cond) !! l) + k) return format(RX1): rx1jump = rx1jump+1 format(RX3): rx13jump = rx13jump+1 k = (there - proc1_base)*2; ! byte disp. from code base put(code, op) if t&7 = RX3 start put(code, x'4000'!((k>>16)&15)) else error(201,code_ca) unless 0 <= k <= 16383 finish put(code,k&x'FFFF') return format(RX2): rx2jump = rx2jump+1 k = (there - (code_ca+4//2))*2 error(202,code_ca) unless -16384 <= k <= 16383 put(code, op&(¬15)) put(code,halfword sign ! k) end ; ! 'plant code ref' routine dump code owninteger depth = 0 integer last line, last ca integer code reset owninteger lit reset; ! no recursion!! - literals are not exbedded owninteger last spec = 0, gla skip = 0 record (procfm)name p integer cca, lca, vca integer k,c,half switch dir(1:extern) depth = depth+1 this proc = this proc+1 p == proc(this proc) origin(code,p_base); origin(ldiag,p_ldbase); origin(vdiag,p_vdbase) last ca = code_ca; last line = 0 if this proc # 1 start ; ! its a recursive call ! DIAGS: dump procedure line origin and identifier get(last line); set description(proc header) if diags # none start k = last line k = 0 if hide # 0 put(ldiag,k); put name(vdiag) finish else ; ! initial (non-recursive) call if diags # none start xd_sym = "PERM"; xd_identlen = 12 put(ldiag,0); put name(vdiag) finish insert prims origin(code,proc1_base+proc1_ca-2) put(code,code_ca - event link); ! link round perm event link = code_ca - 1 put(code,x'8000'); ! dummy event mask finish cycle read symbol(c) -> dir(c) if 0 < c <= extern !!dir(*): error(12,c) dir(proc head): read symbol(k); error(13,k) unless k = this proc cca = code_ca; lca = ldiag_ca; vca = vdiag_ca dump code origin(code,cca); origin(ldiag,lca); origin(vdiag,vca) continue dir(proc end): depth = depth-1 if depth # 0 start ; !not in perm ! dump event chain put(code,code_ca-event link); ! here relative link to preceding block event link = code_ca-1 if p_event mask = 0 start put(code,p_display reg ! halfword sign) else put(code,p_display reg) put(code,p_event mask) put(code,tagdef(p_event start)_ca + p_base) put(code,tagdef(p_event finish)_ca + p_base) finish finish ! dump line diag. table link !!!!!!!!!! last line = -line diag limit-1 if diagnostic < 0 start write(ldiag_ca,1) write(p_ldbase,1); write(p_ldsize,1); newline finish if diags = full start if depth = 0 start ; !special for perm put(ldiag, proc1_ldsize) put(vdiag, proc1_vdsize) else put(ldiag, ldiag_ca-ldiag link); ! relative to here ldiag link = ldiag_ca - 1 put(vdiag, vdiag_ca-vdiag link); ! ... ditto ... vdiag link = vdiag_ca - 1 finish k = p_ld base + p_ld size; put(ldiag,0) while ldiag_ca # k; ! zero finish return dir(code area): lit reset = code_ca code_ca = code reset continue dir(lit area): code reset = code_ca code_ca = lit reset continue dir(lit org): get(half) lit reset = -half continue dir(code item): get(half) put(code,half) continue dir(gla item): get(half) gla skip = gla skip-1 and continue if gla skip # 0 put(gla,half) continue dir(gla rel): ! Assumed to immediately follow the dumping of the GLA full-word to ! which it refers. put(reloc,gla_ca-2); ! N.B. -2 halfwords = -4 bytes continue dir(code rel): ! As for GLA REL but modifies a word in gla according to the value of ! code base at load time put(reloc,(gla_ca-2)+1); ! N.B ** odd-numbered halfword => code seg ** continue dir(frame patch): origin(code,code_ca-1) put(code,p_static frame); ! bytes if TRUSTED else fullwords continue dir(c ref): dir(j ref): ! jumps skip symbol; ! 'code item' get(half) cond = half&15; tag = half>>4 extra = 0; ! to match r ref path!! plant code ref continue dir(r ref): ! procedure calls (including %begin-%end blocks) get(tag) skip symbol; ! 'code item' get(op) skip symbol; ! 'code item' get(extra) cond = 0 plant code ref continue dir(p ref): ! prim call skip symbol; ! 'code item' get(op) skip symbol; ! 'code item' get(k) error(15,k) unless 0 < k <= max prim put(code,op) put(code,prim entry(k)*2 ); ! byte disp. continue dir(sw ref): skip symbol; ! 'code item' get(tag) k = tag def(tag)_ca; k = k + p_base if k # 0 put(code,k); ! N.B. halfwords relative to code base continue dir(line reset): get(half) current line = half-1; ! * see below * dir(line diag): current line = current line + 1 if diagnostic < 0 start print string("line"); write(current line,1); write(code_ca,1) newline finish ca incr = code_ca - last ca continue if ca incr = 0 line incr = current line - last line unless 0 <= line incr <= line diag limit start put(ldiag, (current line-1) ! halfword sign ) if diags = full line incr = 1 finish put(ldiag, ca incr*(line diag limit+1) + line incr) if diags = full last line = current line last ca = code_ca continue dir(var diag): set description(diag entry) if diags = full start k = ((xd_type&7)<<4 + xd_base&15)<<4 + (xd_disp>>16) k = k!halfword sign if xd_identlen # 12; ! ...%if a short ident k = k!indirect if xd_form = 2; ! %name variable k = k!x'2000' if xd_type&8 # 0 put(vdiag,k); put(vdiag,xd_disp&x'FFFF') put name(vdiag) finish continue dir(extern): ! <=== word 1 =====> <======== word 2 ======> <== word 3 => ! ------------------ ------------ ----------- ------------- ! Proc spec: | link to previous | identifier : self-link | x'00000000' | ! ------------------ ------------ ----------- ------------- ! ------------------ ------------ ----------- ------------- ! Data spec | link to previous | identifier : ????????? | x'80000000' | ! ------------------ ------------ ----------- ------------- read symbol(c); ! type of cross reference get(xd_data size) set description(linkage name) gla skip = 0 if c = ep defn or c = data defn start k = xd_disp if c = ep defn start k = code_ca if xd_sym = main ep start p_display reg = p_display reg ! main prog header_main ep = k finish finish put(defn, defn link); defn link = header_defn_p1 + defn_ca-1; ! file relative put(defn, k) put name(defn) else if c = ep spec or c = data spec if trace patch # 0 and xd_sym = trace ep start c = code_ca origin(code,trace patch) put(code,gla_ca*2); !halfwords note. origin(code,c) finish k = header_spec_p1 + spec_ca; ! file relative put name(spec) put(gla,spec link>>16); put(gla,spec link); ! gla relative back link spec link = gla_ca - 2 put(gla,k) put(gla,gla_ca-3); ! halfword disp. of this block into GLA if c = data spec start put(gla, -1); put(gla, -1) else put(gla, 0); put(gla, 0) finish gla skip = 6; ! half words else error(170,c) finish continue repeat end ; ! of 'dump code' select input(object) open da(IMPCOM_file,total blocks) !!!! read symbol(j); put(gla,x'7FFF') %for j = 1,1,j; ! init gla ! Dual standard meantime for first words in gla read symbol(j); put(gla,x'7FFF') for j = 1,1,j-2 put(gla,0); put(gla,0) read symbol(j); error(17,j) if j < init lit; ! pass2 INIT LIT value current line = 0 event link = -1 ldiag link = proc1_ldsize-1 vdiag link = proc1_vdsize-1 defn link = 0 spec link = 0 dump code readsymbol(j) error(-2,j) unless j = prog end origin(code,-init lit); ! = -4: must always dump the exact number put(code,0); ! *** padding *** put(code,asynch link); ! signal relative to code base put(code,header_code disp); ! code base addr - file start addr put(code,event link) if diags # full start ; ! no links embedded in tables!!! if diags = partial start header_ldiag_p1 = header_ldiag_p1 ! halfword sign ldiag link = this proc*(2//2); ! halfword size: for use below vdiag link = this proc*8//2; ! ditto else ; ! 'none' header_ldiag_p1 = 0; ! no diag tables present finish finish header_ldiag_p2 = ldiag link; ! ldiag_p1+ldiag_p2 => start of chain header_vdiag_p2 = vdiag link header_spec_p2 = spec link; ! GLA relative header_defn_p2 = defn link; ! N.B. FILE relative flush buffers close da end ; ! phase two !======================================================================== diags = (IMPCOM_flags >> 8)&7; ! * * * * SYSTEM DEPENDENT * * * * hide = IMPCOM_flags&x'0800' !======================================================================== select output(report) t0 = cpu time; ! *** monitoring only *** diags = full if diags > full phase one t1 = cpu time; ! *** monitoring only *** phase two t2 = cpu time; ! *** monitoring only *** IMPCOM_code = (code size+literal size-proc1_ca)*2 IMPCOM_perm = proc1_ca*2 IMPCOM_gla = gla size*2 IMPCOM_diags = (line diags+var diags)*2 ! print string("Jumps:") ! write(sfjump,1); print string(" SF +") ! write(rx1jump,1); print string(" RX1 +") ! write(rx2jump,1); print string(" RX2 +") ! write(rx13jump-rx1jump,1); print string(" RX3 =") ! write(sfjump+rx2jump+rx13jump,1) ! newline; print string("Diagnostic Tables (bytes):") ! print string(" line"); write(line diags*2,1) ! print string(", ident"); write(var diags*2,1) ! newlines(2) ! print string("Millisec s: phase1 "); write(t1-t0,1) ! print string(" phase2"); write(t2-t1,1) ! newline ! %if local tot # 0 %and global tot # 0 %start ! print string("Stretching - safe/total (%) local:") ! write( (local tot-local nonsafe)*100//local tot, 4) ! print string(" global:") ! write( (global tot-global nonsafe)*100//global tot,4) ! newline ! %finish ! spaces(15) ! print string("millisecs:"); write(t11-t10,14); write(t12-t11,13) ! newline ! print string("Total output (halfwords):") ! write(code size+literal size+gla size+var diags+line diags, 1) ! newline ! print string("Disc buffer: searches"); write(buff miss1,1) ! print string(" cache misses"); write(buff miss2,1) ! newline ! print string("Mean search length="); print(buff miss3/buff miss1,1,2) ! newline endofprogram