%include "inc:level1.imp-nolist"
%include "inc:util.imp-nolist"

! MPLACE: Manual Placement Program for ESDL suite
! RWT September 1985

%begin

%include "edwin:specs.inc-nolist"
%include "edwin:consts.inc-nolist"

!ESDL -> ^S [0:eic,1:fic,2:cic,3:bic] UNIT*
!UNIT -> ^U [1:spec,2:unit,3:chip,4:board,5:pack] HEAD UNIT*
!        ^J nsubs HEAD* {^N{^A netname nfans {subno tno}*}+}*
!        ^E
!HEAD -> ^H0 nin nout nio nt label name
!        {^T tno<<2+[0:dup,1:out,2:in,3:inout] coords/pinname signalname}*
!        {^P [1:at,2:on,3:pack,4:subpack,5:delay,6:value,7:size,8:place] parm}*
!        ^G

%recordformatspec pinf
%recordformatspec netf

%recordformat chipf(%record(chipf)%name next,%record(pinf)%name pins,
                    %integer name,type,pack,on,at,
                           ni,no,nio,nt,wide,high,x,y)
%recordformat pinf(%record(pinf)%name nextinchip,nextinnet,
                   %record(chipf)%name chip,%record(netf)%name net,
                   %integer number,flags,pin,signal,index,x,y)
%recordformat netf(%record(netf)%name nextnet,nextsubnet,net,
                   %record(pinf)%name pins, %integer signal,index)

%constinteger pat=1,pon=2,psize=7,pplace=8

%integer sym;          !Current I-code symbol
%string(255)s;         !Current I-code string
%integer si;           !Signal name index, normally -1, but for
                       !a signal A<17>, si would be 17 and s A

%constinteger hashmask=63
%recordformat hashf(%record(hashf)%name next,%string(255)s)
%record(hashf)%namearray hashtab(0:hashmask)

%record(netf)%name nets;   !List of nets in main circuit
%record(chipf)%name packs; !List of packages in library (if needed)
%record(chipf)%name board; !Selected board from library (if needed)
%record(chipf)%name chips; !List of chips in main circuit, of which
                           !the first is the main circuit itself.

%string(255)mainfile="",packlib="pack.lib",boardlib="board.lib",outfile=""
%integer grid=10,bools=0
%constinteger showhash=1<<31
%integer fileunit,halfgrid

%routine pl(%string(255)s)
  printstring(s); newline
%end

%integerfn codestring
! Returns a code value which uniquely identifies
! global string S, which is entered in a dictionary.
! This consists of a primary hash table with simple
! unsorted linked lists hanging off each entry.
! The actual number returned is the address of the string.
%record(hashf)%name h
%integer value=0,i
  %result = 0 %if length(s)=0
  %for i = 1,1,length(s) %cycle
    value = value<<1+(charno(s,i)!32)
  %repeat
  value = value&hashmask
  h == hashtab(value)
  %cycle
    %if h==nil %start; !Tag new entry onto (end of) list
      h == record(heapget(5+length(s)))
      h_s = s; h_next == hashtab(value)
      hashtab(value) == h
      %result = addr(h_s)
    %finish
    %result = addr(h_s) %if h_s=s
    h == h_next
  %repeat
%end

%string(255)%fn hashstring(%integer tag)
! Re-constitutes a hash-coded string
  %result = "" %if tag=0
  %result = string(tag)
%end

%routine hash statistics
%integerarray x(0:hashmask)
%integer i,j,k=0,l=0
%record(hashf)%name h
  %for i = 0,1,hashmask %cycle
    h == hashtab(i); j = 0
    %while h##nil %cycle
      l = l+length(h_s); k = k+1; j = j+1
      h == h_next
    %repeat
    x(i) = j
  %repeat
  write(k,0); printstring(" strings")
  write(l,1); printstring(" characters")
  %for i = 0,1,hashmask %cycle
    newline %if i&7=0
    write(i,4); write(x(i),3)
  %repeat
  newline
%end

%string(255)%fn indexstring(%integer i)
! Re-constitutes index part of a signal name
%string(255)s
  %result = "" %if i<0
  s = itos(i,0)
  %result = "<".s.">"
%end

%record(*)%map reverse(%record(*)%name list)
! Reverses an arbitrary singly linked list, provided
! the first field in the record is used for linking.
%recordformat f(%record(f)%name next)
%record(f)%name head,tail,temp
  head == list; tail == nil; %result == nil %if list==nil
  %cycle
    temp==head; head==temp_next; temp_next==tail; tail==temp
  %repeatuntil head==nil
  %result==tail
%end

!  ESDL I-code input procedures

%routine readsym
! Read significant character and store in global SYM.
! NB newlines are not significant but spaces are.
  readsymbol(sym) %until sym#nl
  %returnunless sym='^'
  readsymbol(sym); sym=sym+'^'<<8
%end

%routine verify(%integer want)
! Ensure global SYM corresponds to WANT
  %routine p(%integer x)
    printsymbol(x>>8) %unless x>>8=0
    printsymbol(x)
  %end
  %returnif sym=want
  printstring("Got "); p(sym)
  printstring(" when expecting "); p(want)
  newline; %stop
%end

%routine readstring
! Read string and store in global S and SI (if of form signal<num>)
%integer indexed=0
%integer len,i
  si = -1
  read(len); readsym; verify(':')
  length(s) = len
  %for i=1,1,len %cycle
    readsym
    indexed = i %if indexed=0 %and sym='<'
    charno(s,i) = sym
  %repeat
  %if indexed#0 %start
    length(s) = indexed-1
    si = 0
    %cycle
      indexed = indexed+1; i = charno(s,indexed)-'0'
      %exitunless 0<=i<=9
      si = si*10+i
    %repeat
  %finish
%end

%integerfn getnum
! Extract a possibly signed decimal number off the front of global
! string S, which is shortened by the number plus its terminator.
%integer n=0,sign=0,pos=1
  %while pos<=length(s) %cycle
    sym = charno(s,pos); pos = pos+1
    %if sym='-' %start
      sign = 1
    %finishelseif '0'<=sym<='9' %start
      n = n*10-'0'+sym
    %finishelseexit
  %repeat
  s = substring(s,pos,length(s))
  %result = n %if sign=0
  %result=-n
%end

%predicate contains(%string(*)%name s,%integer k)
! Does strng S contain character K?
%integer i
  %for i = 1,1,length(s) %cycle
    %trueif charno(s,i)=k
  %repeat
  %false
%end

%integerfn align(%integer x)
! Turn X into a multiple of the grid size
  %result = ((x+halfgrid)//grid)*grid
%end

%record(chipf)%map readchips
! Read {^H0 ... ^G}*
%integer i
%record(chipf)%name chead,ctail
%record(pinf)%name phead,ptail

  ctail == nil
  readsym
  %while sym='^H' %cycle
    readsym; verify('0')
    chead == new(chead); chead = 0
    chead_next == ctail; ctail == chead
    read(chead_ni); read(chead_no)
    read(chead_nio); read(chead_nt)
    readstring; chead_name = codestring
    readstring; chead_type = codestring
    ptail == nil; readsym
    %while sym='^T' %cycle
      read(i)
      %if i&3#0 %start; !In,Out,or InOut
        phead == new(phead); phead = 0; phead_chip == chead
        phead_nextinchip == ptail; ptail == phead
        phead_number = i>>2; phead_flags = i&3
        readstring
        %if contains(s,':') %start
          phead_x = {align(}getnum{)}; verify(':'); phead_y = {align(}getnum{)}
        %finish
        phead_pin = codestring
        readstring; phead_signal = codestring; phead_index = si
      %else; !Dummy pin
        readstring; readstring
      %finish
      readsym
    %repeat
    chead_pins == reverse(phead)
    %while sym='^P' %cycle
      read(i); readstring
      %if i=pon %start
        chead_on = codestring
      %finishelseif i=pat %start
        chead_at = codestring
      %finishelseif i=psize %start
        chead_wide = getnum; verify(':')
        chead_high = getnum
      %finishelseif i=pplace %start
        chead_x = align(getnum); verify(':')
        chead_y = align(getnum)
      %finish
      readsym
    %repeat
    verify('^G')
    readsym
  %repeat
  %result == chead
%end

%record(netf)%map readnets
! Read {^N {subnet}*}*
%record(netf)%name head,tail

  %record(netf)%map readsubnets
  ! Read {^A subnetname pairs {chip pin}*}*
  %record(netf)%name head,tail
  %record(pinf)%name p,term
  %record(chipf)%name sub
  %integer nfans,subno,tno
    tail == nil
    %while sym='^A' %cycle
      head == new(head); head = 0
      head_nextsubnet == tail; tail == head
      readstring; head_signal = codestring; head_index = si
      read(nfans); p == nil
      %while nfans>0 %cycle
        nfans = nfans-1; read(subno); read(tno)
        sub == chips
! Scan component list (by position)
        sub == sub_next %and subno = subno-1 %while subno>0
        term == sub_pins
! Scan component's pin list (by pin number value)
        term == term_nextinchip %while term_number#tno
        %if term_flags&4=0 %start; !All is well: not been here before
          term_flags = term_flags!4; term_net == head
          term_nextinnet == p; p == term
        %finishelseunless term_net==head %start; !Confusion
          printstring("Terminal"); write(term_number,1)
          printstring(", pin ".hashstring(term_pin))
          space; printstring(hashstring(term_signal))
          printstring(" of ".hashstring(term_chip_name)); space
          printstring(hashstring(term_chip_type)." at ")
          printstring(hashstring(term_chip_at)); newline
          printstring("is already connected to ")
          printstring(hashstring(term_net_signal))
          printstring(indexstring(term_net_index))
          printstring(", cannot also connect to ".s)
          printstring(indexstring(si)); newline
        %finish
      %repeat
      head_pins == p
      readsym
    %repeat
    head == tail
    %cycle
      tail_net == head; tail == tail_nextsubnet
    %repeatuntil tail==nil
    %result == head
  %end

  tail == nil
  %while sym='^N' %cycle
    readsym; head == readsubnets
    head_nextnet == tail; tail == head
  %repeat
  %result == head
%end

%routine readpacks
! Read contents of package library
%record(chipf)%name t
  %onevent 9 %start
    %return
  %finish
  readsym; verify('^S'); readsym; verify('0')
  readsym; verify('^U'); readsym; verify('2')
  packs == readchips
  t == packs
  %cycle
    verify('^J'); readsym; verify('0')
    readsym %until sym='^E'
    readsym; verify('^U'); readsym; verify('2')
    t_next == readchips
    t == t_next
  %repeat
%end

%routine readboard
! Read boards from board library until desired one found
  %onevent 9 %start
    %return
  %finish
  readsym; verify('^S'); readsym; verify('0')
  %cycle
    readsym; verify('^U'); readsym; verify('4')
    board == readchips
    verify('^J')
    readsym %until sym='^E'
  %repeatuntil board_type=chips_on
%end

%predicate placed(%record(chipf)%name c)
  %trueif c_x#0 %or c_y#0
  %false
%end

%routine do pre placement
! Incorporate coordinate information from package and board
! libraries into the main circuit. (.CIC -> .BIC).
%record(chipf)%name c,p
%record(pinf)%name ct,pt
%integer errors=0
  %unless board==nil %start
! Get board name
    chips_name = chips_type; chips_type = chips_on; chips_on = 0
! Get board size
    chips_wide = board_wide; chips_high = board_high
! Get edge connector pin coordinates
    ct == chips_pins
    %while ct##nil %cycle
      pt == board_pins
      %cycle
        %if pt==nil %start
          printstring("Pin ".hashstring(ct_pin))
          printstring(" not on ".hashstring(board_type))
          newline; %exit
        %finish
        %if ct_pin=pt_signal %start
          ct_x = pt_x; ct_y = pt_y
          %exit
        %finish
        pt == pt_nextinchip
      %repeat
      ct == ct_nextinchip
    %repeat
  %finish
  c == chips_next
  %while c##nil %cycle;       !For each chip
    %unless placed(c) %start; !which has not yet been placed
      p == packs
      %cycle;                 !Find its package in library
        %if p==nil %start
          errors = errors+1
          printstring("Package ".hashstring(c_on)." not found"); newline
          %exit
        %finish
        %exitif p_type=c_on
        p == p_next
      %repeat
! Convert 'at' to 'place'
      %if c_at#0 %start
        s = hashstring(c_at)
        %if contains(s,':') %start
          c_at = 0
          c_x = getnum; verify(':'); c_y = getnum
        %finish
      %finish
! Get chip package size
      c_wide = p_wide; c_high = p_high
      ct == c_pins
      %while ct##nil %cycle; !For each pin on chip
        pt == p_pins
        %cycle;              !Search pack lib for pin name
          %if pt==nil %start
            printstring("Pin ".hashstring(ct_pin)." not on ".hashstring(p_type))
            newline; errors = errors+1
            %exit
          %finish
          %if ct_pin=pt_signal %start
            ct_x = {align(}pt_x+c_x{)}; ct_y = {align(}pt_y+c_y{)}
            %exit
          %finish
          pt == pt_next in chip
        %repeat
        ct == ct_next in chip
      %repeat
    %finish
    c == c_next
  %repeat
  %unless errors=0 %start
    printstring("Placement abandoned"); newline; %stop
  %finish
%end

%routine do manual placement
%integer one,b,x,y
%record(pinf)%name p
%record(chipf)%name picked==nil

  %routine alignxy
    x = align(x); y = align(y)
  %end

  %routine adjust chip(%record(chipf)%name c)
! Move chip C to coordinates (X,Y), adjusting all pin offsets.
  %record(pinf)%name p
  %integer dx,dy
    dx = x-c_x; dy = y-c_y
    c_x = c_x+dx; c_y = c_y+dy
    p == c_pins
    %while p##nil %cycle
      p_x = p_x+dx; p_y = p_y+dy
      p == p_next in chip
    %repeat
  %end

  %routine rotate chip(%record(chipf)%name c)
! Rotate chip C 90 degrees anticlockwise about its origin,
! the re-position its origin so that it is at the same
! (e.g. SouthWest) corner of it as before.
  %record(pinf)%name p
  %integer ox,oy,w,h

    %routine rotate point(%integername x,y)
    %integer t
      t = oy+ox+h-y; y = oy-ox+x; x = t
    %end

    ox = c_x; oy = c_y
    w = c_wide; h = c_high
    p == c_pins
    %while p##nil %cycle
      rotate point(p_x,p_y)
      p == p_nextinchip
    %repeat
    c_high = w; c_wide = h
  %end

  %routine drawchip(%record(chipf)%name c,%integer cc,pc,wires)
! Draw chip C at position X,Y, as an outline box in colour CC,
! with dots for all its pins is colour PC, and, unless WIRES=0,
! draw lines corresponding to all nets involved in this chip.
  %integer x
  %record(pinf)%name p,t

    %predicate dotted(%integer signal)
    %string(255)s
      %falseif signal=0
      s = hashstring(signal)
      %falseunless charno(s,1)='.'
!!    %falseunless contains(s,'.')
{}    printstring(s." not drawn"); newline
      %true
    %end

    %returnif c==nil
    moveabs(c_x,c_y); set colour(cc)
    linerel(c_wide,0); linerel(0,c_high)
    linerel(-c_wide,0); linerel(0,-c_high)
    p == c_pins
    %while p##nil %cycle
      set colour(pc)
      %if p_pin=one %then markerabs(triangle marker,p_x,p_y) %c
                    %else markerabs(point marker,p_x,p_y)
      %if wires#0 %and p_net##nil %c
     %andnot (dotted(p_signal) %or dotted(p_net_signal)) %start
        set colour(blue)
        t == p_net_pins
        %while t##nil %cycle
          moveabs(p_x,p_y) %and lineabs(t_x,t_y) %if placed(t_chip)
          t == t_next in net
        %repeat
      %finish
      p == p_next in chip
    %repeat
  %end

  %routine place(%record(chipf)%name c)
! Interactively move chip C about until told to drop it somewhere.
  %integer ox,oy,ob,i
    printsymbol(7) %andreturnif c==nil %or c==chips
    picked == c
    printstring(hashstring(c_name).":".hashstring(c_type))
    printstring(" on ".hashstring(c_on))
    printstring(" at ".hashstring(c_at)) %unless c_at=0; newline
    %cycle
      adjust chip(c)
{*   enable(4)
      drawchip(c,blue,blue,0)
{*   enable(15)
      ox = x; oy = y
      sample input(b,x,y) %until x#ox %or y#oy %or b#0
      i = 0
      %cycle
        ob = b
        sample input(b,x,y); i = 0 %if b#ob
        i = i+1
      %repeatuntil i=50
      alignxy {*; write(x,5); write(y,5); newline
{*}   enable(4); colour(0); fill(0,0,687,511); enable(15)
{*}   set colour(red); set colour(yellow)
      %if b=mouseleft %start; !Drop it here
        alignxy; adjust chip(c)
        drawchip(c,green,red,0)
        %exit
      %finish
      %if b=mousemiddle %start; !Draw wires
{*     enable(4)
        drawchip(c,blue,blue,1)
{*     enable(15)
        sampleinput(b,x,y) %until b#mousemiddle
      %finish
      %if b=mouseright %start; !Rotate chip
        rotatechip(c)
        sampleinput(b,x,y) %until b#mouseright
      %finish
    %repeat
  %end

  %record(chipf)%map most connected unplaced chip
  %record(chipf)%name c,most==nil
  %record(pinf)%name p,t
  %integer con,conmax=-1
    c == chips
    %cycle
      c == c_next
      %exitif c==nil
      %continueif placed(c)
      con = 0
      p == c_pins
      %while p##nil %cycle
        %unless p_net==nil %start
          t == p_net_pins
          %while t##nil %cycle
            con = con+1 %if placed(t_chip)
            t == t_next in net
          %repeat
        %finish
        p == p_next in chip
      %repeat
      %if con>conmax %start
        conmax = con; most == c
      %finish
    %repeat
    %result == most
  %end

  %record(chipf)%map any other unplaced chip
! Un-place previously placed chip, undraw it, and pick another
  %record(chipf)%name c
  %integer ox,oy
    picked == chips_next %if picked==nil
    c == picked
    %if c##nil %and placed(c) %start
      drawchip(c,blank,blank,0)
      ox = x; oy = y; x = 0; y = 0; adjustchip(c); x = ox; y = oy
    %finish
    %cycle
      c == c_next
      c == chips_next %if c==nil
      %result == nil %if c==picked;   !none left
      %result == c %unless placed(c); !got one
    %repeat
  %end

  %record(chipf)%map nearest placed chip
  %record(chipf)%name c,near==nil
  %constinteger maxint=(-1)>>1
  %integer d,min=maxint
    c == chips
    %cycle
      c == c_next
      %exitif c==nil
      %continueunless placed(c)
      d = |c_x-x|+|c_y-y|
      min = d %and near == c %if d<min
    %repeat
    drawchip(near,blank,blank,0)
    %result == near
  %end

  %routine redraw the lot
  %record(chipf)%name c
    newframe
    window(0,chips_wide,0,chips_high)
    chips_x = 0; chips_y = 0;   !Set correct position
    drawchip(chips,green,red,0);!Draw board outline and edge pins
    chips_x = 1; chips_y = 1;   !Make it look placed
    c == chips
    %cycle
      c == c_next
      %exitif c==nil
      drawchip(c,green,red,0) %if placed(c)
    %repeat
  %end

  s = "1"; one = codestring
  initialise for (default device)
  redraw the lot
  sample input(b,x,y) %until b=0
  x = chips_wide>>1; y = chips_high>>1
  moveabs(x,y)
  %cycle
    request input(b,x,y)
    %exitif b=mouseleft+mousemiddle+mouseright
    %if b=mouseleft %start
      place(nearest placed chip)
    %elseif b=mousemiddle
      place(most connected unplaced chip)
    %elseif b=mouseright
      place(any other unplaced chip)
    %elseunless b=0
      redraw the lot
    %finish
  %repeat
  terminate edwin
%end

%routine output file

  %routine putsym(%integer x)
    %if x>>8=0 %then printsymbol(x) %elsestart
      newline
      %cycle
        printsymbol(x>>24) %if x>>24#0
        x = x<<8
      %repeatuntil x=0
    %finish
  %end

  %routine putstring(%string(255)s)
    write(length(s),1); printsymbol(':'); printstring(s)
  %end

  %routine puttag(%integer a,i)
    putstring(hashstring(a).indexstring(i))
  %end

  %routine parameter(%integer num,%string(255)val)
    %returnif val=""
    putsym('^P'); write(num,0); putstring(val)
  %end

  %routine putheader(%record(chipf)%name c)
  %record(pinf)%name p
    putsym('^H0')
    write(c_ni,1); write(c_no,1); write(c_nio,1); write(c_nt,1)
    puttag(c_name,-1); puttag(c_type,-1)
    p == c_pins
    %while p##nil %cycle
      putsym('^T'); write(p_number<<2+p_flags&3,0)
      putstring(itos(p_x,0).":".itos(p_y,0)."/".hashstring(p_pin))
      puttag(p_signal,p_index)
      p == p_nextinchip
    %repeat
  %end

  %routine putnet(%record(netf)%name n)
  %record(pinf)%name p
  %integer i

    %integerfn subno
    %integer i=0
    %record(chipf)%name c
      c == chips
      %cycle
        %result = i %if p_chip==c
        i = i+1
        c == c_next
        %result = -1 %if c==nil
      %repeat
    %end

    putsym('^N')
    %cycle
      putsym('^A'); puttag(n_signal,n_index)
      p == n_pins; i = 0
      i = i+1 %and p == p_nextinnet %while p##nil
      write(i,1)
      p == n_pins; i = 0
      %while p##nil %cycle
        newline %if i&7=0; i = i+1
        write(subno,1); write(p_number,1)
        p == p_nextinnet
      %repeat
      n == n_nextsubnet
    %repeatuntil n==nil
  %end

%integer i
%record(chipf)%name c
%record(netf)%name n

  putsym('^S3'); putsym('^U4')
  putheader(chips); c == chips
  parameter(psize,itos(c_wide,0).":".itos(c_high,0))
  putsym('^G')
  i = 0
  i = i+1 %and c == c_next %while c_next##nil
  putsym('^J'); write(i,0)
  c == chips_next
  %while c##nil %cycle
    putheader(c)
    parameter(pat,hashstring(c_name))
    parameter(pon,hashstring(c_on))
    parameter(psize,itos(c_wide,0).":".itos(c_high,0))
    parameter(pplace,itos(c_x,0).":".itos(c_y,0))
    putsym('^G')
    c == c_next
  %repeat
  n == nets
  %while n##nil %cycle
    putnet(n); n == n_nextnet
  %repeat
  putsym('^E'); newline
%end

  define param("Main circuit file",mainfile,pamnodefault)
  define param("Package library",  packlib,0)
  define param("Board library",   boardlib,0)
  define param("Updated main file",  outfile,pamnewgroup)
  define int param("Grid resolution",grid,pamnewgroup)
  define boolean params("Hash",bools,0)
  processparameters(cliparam)
  halfgrid = grid//2

  mainfile = mainfile.".bic" %unless contains(mainfile,'.')
  packlib = packlib.".lib" %unless packlib="" %or contains(packlib,'.')
  boardlib = boardlib.".lib" %unless boardlib="" %or contains(boardlib,'.')
  %if outfile="" %start
    outfile = mainfile; toupper(outfile)
    %if length(outfile)>4 %start
      %if substring(outfile,length(outfile)-3,length(outfile))=".CIC" %start
        outfile = substring(outfile,1,length(outfile)-4).".BIC"
      %finish
    %finish
  %finish

  hashtab(sym) == nil %for sym = 0,1,hashmask

  setterminalmode(nopage)
  selectoutput(0); printstring("Reading main file"); newline
  openinput(1,mainfile); selectinput(1)
  readsym; verify('^S'); readsym; fileunit = sym<<8
  readsym; verify('^U'); readsym; fileunit = fileunit+sym
  chips == readchips
  verify('^J'); read(sym)
  chips_next == reverse(readchips)
  nets == readnets
  verify('^E')
  packs == nil
  board == nil
  %if fileunit#'34' %start   {not .BIC}
    %if fileunit#'22' %start {not .CIC}
      printstring("Wrong kind of I-code file: ")
      printsymbol(fileunit>>8); printsymbol(fileunit&255); newline; %stop
    %finish
    printstring("Reading package library"); newline
    openinput(1,packlib); selectinput(1); readpacks
    printstring("Reading board library"); newline
    openinput(1,boardlib); selectinput(1); readboard
    do pre placement
  %finish
  hash statistics %unless bools&showhash=0
pl("          +----------+-----------------+-----------+--------+-------+")
pl("Button:   | Left     |  Middle         | Right     | Any 2  | All 3 |")
pl("          +----------+-----------------+-----------+--------+-------+")
pl("Choosing: | Nearest  |  Most connected | Any Other | Redraw | Stop  |")
pl("Placing:  | Put here |  Show wires     | Rotate    | --     | --    |")
pl("          +----------+-----------------+-----------+--------+-------+")
  do manual placement
  printstring("Writing output file"); newline
  openoutput(1,outfile); selectoutput(1)
  output file
%endofprogram
