!! 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"
{Include file for compiler communication}
recordformat impcomfm(integer statements, flags, code, gla, diags, perm,
                        string(31) file,
                        string(63) Option)
externalrecord(impcomfm)spec IMPCOM
!%endoffile
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("Millisecs: 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