File LINKMP.PS

Directory of image this file is from
This file as a plain text file

{$X+ accept non-standard stuff}
Program linkmp(input:'.mp', output:'IO:.ls');
{$T-,L-}
{  Annotates link map for greater readability }
{  JTE	SSRFC	1979/06/12 }
{
    To run, do:

	.R PARTS
	>LINKMP,SOURCE,RESULT

 }
{  overlays described a little better	79/07/21 }
{  overlay fwa, lwa scanned		79/07/30 }
{  variables level, overlay made locals 80/01/28 }

{ The various map parts expected are laid out as follows.


123456789.123456789.123456789.123456789.123456789.123456789.123456789.12
.........1.........2.........3.........4.........5.........6.........7..

 OS/8	LINKER V 2AG  LOAD MAP	    13-JUN-79

UNDEFINED SYMBOLS:
ELNRT	 00000	  EOFRT    00000    GTCRT    00000

GLOBAL-ABSOLUTE SYMBOLS:
ADRERR	  4427	  A0	    0071    A1	      0072

SECTION  ADDR	 SIZE  ENTRY	ADDR	ENTRY	 ADDR
TTIV1	 00600	 0177  CCABT	00701	IOTD4	 00770

OVERLAY LEVEL 0001  OVERLAY 0000

PROGRAM ENTRY:	 00200
JOB STATUS WORD: 0200

123456789.123456789.123456789.123456789.123456789.123456789.123456789.12
.........1.........2.........3.........4.........5.........6.........7..

 }




const
  blank =	' ';
  blocklen =	0400b	{ OS/8 physical block length };
  divlen =	54	{ divider lines length };
  fielddiv =	'=====================';
  fieldlen =	10000b	{ length of one memory field };
{levdiv = '======================================================';}
  linelength =	80	{ maximum input line length };
  maxaddr =	3777777b { highest valid address };
  maxlevel =	7	{ number of levels in overlay design };
  maxoverlays = 17b	{ number of overlays in each level above zero };
  niladdr =	4000000b { value of non-existant address };
{ovldiv = '------------------------------------------------------';}
  pagediv =	'	  ------------';
  pagelen =	0200b	{ length of one memory page };
  sectionheader = 'section..addr....size..entry....addr....entry....addr.';
  unused =	'(unused= ';


type
  address =	0..niladdr;
  alllevels =	0..maxlevel;
  alloverlays = 0..maxoverlays;
  charinteger = 0..177b { range of character values };
  charset =	set of char;
  fieldsize =	0..fieldlen;
  levelcounter = array[alllevels] of integer;
  linebuff =	array[1..linelength] of char;
  ovlcounter =	array[alllevels] of array[alloverlays] of integer;


var
  addr :	address { current section address };
  continuation : boolean { section entry/global continuation lines };
  endofile :	boolean { eof(input)  };
  field :	char	{ current root section field };
  fwa : 	address { first actual address of section };
  holdlc :	integer { hold line count while scanning overlays };
  i :		integer { main prog index var };
  lastaddr :	address { previous section address };
  lastfield :	char	{ previous root section field };
  lastlength :	fieldsize { previous section length };
  lastlevel :	alllevels { previous level number };
  lastsize :	fieldsize { previous section length ?? };
  length :	fieldsize { current section length };
  levdiv :	packed array[1..divlen] of char;
  levellength : levelcounter { length of each level };
  leveloccupied : array[alllevels] of boolean;
  levfirstactual : levelcounter { level's lowest overlay fwa };
  levhigh :	address { working copy of levhighbound };
  levhighbound : levelcounter { highest address, rounded up to page ? };
  levlastactual : levelcounter { highest overlay lwa in given level };
  levlow :	address { working copy of levlowbound };
  levlowbound : levelcounter { lowest address, rounded down to block bound };
  line :	linebuff { source lines read into line buffer };
  linecount :	integer { count of source lines read };
  lwa : 	address { lwa of current level or overlay };
  newlev :	boolean { change in overlay level spotted };
  newovl :	boolean { change in overlay number spotted };
  nextaddr :	address { current sect addr plus current sect length };
  nextpage :	address { nestaddr rounded up to page bound };
  octaldigits : charset { for converting character string to octal number };
  ordzero :	charinteger { for converting to a number };
  ovldiv :	packed array[1..divlen] of char;
  ovlfirstactual : ovlcounter { raw first word addresses };
  ovllastactual : ovlcounter { raw last word addresses };
  ovunused :	integer { amount unused at end of overlay};
  size :	fieldsize { current section size ? };
  title :	linebuff { keep copy of title, but don't use it yet };




procedure initialize  { init program variables };

var
  i : integer;

begin
  linecount := 0;
  lastlevel := 0;
  ordzero := ord('0');
  octaldigits := ['0', '1', '2', '3', '4', '5', '6', '7'];
  lastlength := linelength;
  for i := 1 to divlen do
    begin
      ovldiv[i] := '-';
      levdiv[i] := '='
    end
end   { initialize };




procedure readline { read next line from source map file };
{ skips blank lines altogether }

var
  i, j : integer;

begin
  repeat { read until a non-blank line }
    if not eof(input) then
      begin
	i := 0;
	while not eoln(input) do
	  begin
	    if i < linelength then
	      begin
		i := i + 1;
		line[i] := input^
	      end;
	    get(input)
	  end;
     { for j := i+1 to lastlength do line[j] := blank;
	lastlength := i; }
	if i > 0 then
	  begin
	    while (i > 1) and (line[i] = blank) do i := i - 1;
	    if (i = 1) and (line[i] = blank) then i := i - 1
	  end;
	length := i;
	readln(input);
	linecount := linecount + 1
      end
  until eof(input) or (length > 0)
end  { readline };




procedure writeline { writes out current line buffer,
		       image of a line read };

var
  i : integer;

begin
  for i := 1 to length do write(output, line[i]);
  writeln(output)
end  { writeline};




procedure copysymbollines { undefined or absolute-global };

begin
  repeat
    readline;
    if line[12] in octaldigits then writeline
  until (not (line[12] in octaldigits)) or eof(input)
end { copysymbollines };




function octal4(start : integer) : integer
    { decode 4 octal digits to integer };

var
  n, i : integer;

begin
  n := 0;
  for i := start to start+3 do
    n := (n * 8) + (ord(line[i]) - ordzero);
  octal4 := n
end  { octal4 };




function octal5(start : integer) : integer
    { decode 5 octal digits to integer };

var
  n, i : integer;

begin
  n := 0;
  for i := start to start+4 do
    n := (n * 8) + (ord(line[i]) - ordzero);
  octal5 := n
end  { octal5 };




procedure rootmap { produces annotated map of root sections };

begin
  readline;
  lastfield := line[10];
  lastaddr  := 0;
  lastsize  := 0;
  while (line[1] = blank) or (line[12] in octaldigits) do
    begin { process all sections in root or overlay }
      if line[1] = blank then writeline { continuation }
      else
	begin { process new section line }
	  addr := octal4(11);
	  size := octal4(18);
	  field := line[10] { a character };
	  nextaddr := lastaddr + lastsize;
	  if field <> lastfield
	    then
	      begin
		if (nextaddr > 0) and (nextaddr < fieldlen) then
		  begin
		    if nextaddr mod pagelen = 0 then
		      writeln(output, pagediv);
		    writeln(output, unused, lastfield,
		      nextaddr : 4 oct, '   ', (fieldlen-nextaddr) : 4 oct,
		      ')')
		  end;
		writeln(output, fielddiv);
		if addr > 0 then
		  begin
		    writeln(output, unused, field, '0000   ',
		      addr : 4 oct, ')');
		    if addr mod pagelen = 0 then
		      writeln(output, pagediv)
		  end;
		writeline
	      end
	    else { within field }
	      begin
		if nextaddr = 0 then nextpage := 0 else
		nextpage := (nextaddr  div pagelen) * pagelen;
		if (nextaddr = nextpage) and (nextaddr > 0) then
		  writeln(output, pagediv);
		if nextaddr <> addr then
		  begin
		    writeln(output, unused, field, nextaddr : 4 oct, '	 ',
		      (addr - nextaddr) : 4 oct, ')');
		    if addr mod pagelen = 0 then
		      writeln(output, pagediv)
		  end;
		writeline
	      end;
	  lastaddr := addr;
	  lastsize := size;
	  lastfield := field
	end   { process new section line };
      readline
    end   { process all sections in root or overlay };
  { finish up map }
  nextaddr := lastaddr + lastsize;
  if nextaddr < fieldlen then { note balance of field }
    begin
      writeln(output, unused, lastfield,
	nextaddr : 4 oct, '   ', (fieldlen - nextaddr) : 4 oct, ')')
    end;
  writeln(output, fielddiv)
end { rootmap };




procedure scanoverlays { for fwa, lwa, lengths };

var
  gotfwa	: boolean;
  min, max	: address;
  level :	alllevels { the current level number };
  overlay :	alloverlays { the current overlay number };

begin
  for level := 0 to maxlevel do { zero counters }
    begin
      for overlay := 0 to maxoverlays do
	begin
	  ovlfirstactual[level, overlay] := 0;
	  ovllastactual[level, overlay] := 0
	end
    end;

  repeat { for each level/overlay }
    level := octal4(15);
    overlay := octal4(29);
    readline { set first section line in overlay };
    gotfwa := false;
    repeat  { for each section in an overlay }
      addr := octal5(10);
      if not gotfwa then
	begin
	  ovlfirstactual[level, overlay] := addr;
	  gotfwa := true
	end;
      ovllastactual[level, overlay] := addr + octal4(18) - 1;
      repeat { bypass continuations }
	readline
      until line[1] <> blank
    until not (line[12] in octaldigits) { new overlay }
  until line[1] <> 'O' { escape on a misc. line };

  for level := 1 to maxlevel do { deduce min, max level addresses }
    begin
      leveloccupied[level] := false;
      min := niladdr;
      max := 0;
      for overlay := 0 to maxoverlays do
	if ovlfirstactual[level, overlay] <> 0 then
	  begin
	    leveloccupied[level] := true;
	    fwa := ovlfirstactual[level, overlay];
	    if fwa < min then
	      begin
		min := fwa;
		levfirstactual[level] := fwa;
		levlowbound[level] := fwa div blocklen * blocklen
	      end;
	    lwa := ovllastactual[level, overlay];
	    if lwa >= max then
	      begin
		max := lwa;
		levlastactual[level] := lwa;
		levhighbound[level] := lwa div pagelen * pagelen
					+ pagelen - 1
	      end
	  end;
      levellength[level] := levhighbound[level] - levlowbound[level] + 1
    end;

  writeln(output);
  writeln(output);
  writeln(output,'Program overlay information.');
  writeln(output);
  for level := 1 to maxlevel do
    if leveloccupied[level] then
      begin
	writeln(output, 'Level	', level : 1,
	  '  low ', levlowbound[level] : 5 oct,
	  '  fwa ', levfirstactual[level] : 5 oct,
	  '  lwa ', levlastactual[level] : 5 oct,
	  '  high ', levhighbound[level] : 5 oct,
	  '  len ', levellength[level] : 4 oct);
	for overlay := 0 to maxoverlays do
	  if ovlfirstactual[level, overlay] <> 0 then
	    writeln(output, '  overlay	', overlay : 2 oct,
	      '  fwa: ', ovlfirstactual[level, overlay] : 5 oct,
	      '  lwa: ', ovllastactual[level, overlay] : 5 oct);
	writeln(output)
      end;
      writeln(output)
end  { scanoverlays };




procedure ovlmap { produce annotated map of overlays };

var
  level :	alllevels { the current level number };
  overlay :	alloverlays { the current overlay number };

begin
  lastlevel := 0;
  repeat { for each level/overlay }
    level := octal4(15);
    overlay := octal4(29);
    if level <> lastlevel then
      begin
	newlev := true;
	levlow := levlowbound[level];
	levhigh := levhighbound[level];
	writeln(output);
	writeln(output, levdiv);
	writeln(output,  'Level    ', level : 1 oct,
	  '  low ', levlow : 5 oct,
	      '  hi ', levhigh : 5 oct,
	  '  len ', levellength[level] : 4 oct,
	  '  unused ', (levhigh - levlastactual[level]) : 4 oct);
	writeln(output);
	lastlevel := level
      end;
    readline { set first sect of overlay };
    newovl := true;
    addr := levfirstactual[level];
    size := 0;
    fwa := ovlfirstactual[level, overlay];
    lwa := ovllastactual[level, overlay];
    if not newlev then
      begin
	writeln(output);
	writeln(output, ovldiv)
      end;
    ovunused := levhigh - lwa;
    writeln(output, 'Overlay ', overlay : 2 oct,
      '  fwa ', fwa : 5 oct,
      ' lwa ', lwa : 5 oct,
      '  len ', (lwa - levlow + 1) : 4 oct,
      '  unused ', ovunused : 4 oct);
    writeln(output);
    if newlev then
      begin
	writeln(output, sectionheader);
	writeln(output);
	newlev := false
      end;
    repeat { for each section in an overlay }
      nextaddr := addr + size;
      addr := octal4(11);
      size := octal4(18);
      field := line[10]  { a character };
      if newovl
	then
	  begin
	    newovl := false;
	    nextaddr := (addr div pagelen) * pagelen
	  end
	else
	  begin
	    if nextaddr = 0
	      then nextpage := 0
	      else nextpage := (nextaddr div pagelen) * pagelen;
	    if (nextaddr = nextpage) and (nextaddr > 0) and
	       (nextaddr <> addr) then writeln(output, pagediv)
	  end;
      if nextaddr <> addr then
	begin
	  writeln(output, unused, field, nextaddr : 4 oct, '   ',
		  (addr - nextaddr) : 4 oct,')');
	  if addr mod pagelen = 0 then
	    writeln(output, pagediv)
	end
      else if addr mod pagelen = 0 then
	     writeln(output, pagediv);
      writeline;
      repeat { swim through continuations }
	readline;
	continuation := line[1] = blank;
	if continuation then writeline
      until not continuation
    until not (line[12] in octaldigits) { new map part };
    if ovunused <> 0 then
      begin
	nextaddr := addr + size;
	if nextaddr mod pagelen = 0 then
	  writeln(output, pagediv);
	writeln(output, unused, field, nextaddr : 4 oct,
		'   ', ovunused : 4 oct, ')')
      end
  until line[1] <> 'O' { escape on a non-level/overlay line };
  writeln(output, ovldiv)
end   { ovlmap };


begin { linkmp }
  { reset(input); -- automatic }
  endofile := eof(input);
  if endofile then halt('no data on input');
  page(output);
  initialize;
  readline;
  while not endofile do
    begin
      endofile := eof(input);
      if line[12] in octaldigits then
	begin
	  writeln(output, '****** error ******');
	  writeline;
	  readline
	end
      else if line[4] = '/' then
	begin { title line }
	  for i := 1 to length do
	    begin
	      title[i] := line[i];
	      write(output, line[i])
	    end;
	  writeln(output);
	  readline
	end
      else if line[1] = 'U' then
	begin { undefined }
	  writeln(output);
	  writeline;
	  copysymbollines
	end
      else if line[1] = 'G' then
	begin { globals }
	  writeln(output);
	  writeline;
	  copysymbollines
	end
      else if line[1] = 'P' then
	begin { program entry }
	  writeln(output);
	  writeline;
	  readline
	end
      else if line[1] = 'J' then
	begin { job status word }
	  writeln(output);
	  writeline;
	  readline
	end
      else if line[1] = 'S' then
	begin { root sections }
	  writeln(output);
	  writeln(output);
	  writeline;
	  writeln(output);
	  rootmap
	end
      else if line[1] = 'O' then
	begin { overlay }
	  holdlc := linecount;
	  scanoverlays { find fwa, lwa, lengths };
	  reset(input); { oh boy }
	  linecount := 0;
	  while linecount < holdlc-1 do { skip-1 down to original position }
	    begin
	      readln(input);
	      linecount := linecount + 1
	    end;
	  readline { reinstate line buffer };
	  ovlmap;
	end
      else { unknown map part }
	begin
	  writeln(output);
	  write(output,'(??) ');
	  writeline;
	  readline
	end
    end  { while not endofile };
  writeln(output)
end { linkmp }.



Feel free to contact me, David Gesswein djg@pdp8online.com with any questions, comments on the web site, or if you have related equipment, documentation, software etc. you are willing to part with.  I am interested in anything PDP-8 related, computers, peripherals used with them, DEC or third party, or documentation. 

PDP-8 Home Page   PDP-8 Site Map   PDP-8 Site Search