%const %string (31) VERSION = "Imp LAP Version 4.7A 9-Jul-85"

   {*************************************************************************}
   {*************************************************************************}
   {***                                                                   ***}
   {***                   This is ILAP  or  Imp LAP                       ***}
   {***                                                                   ***}
   {*************************************************************************}
   {*************************************************************************}
 
   {#########################################################################}
   {#                                                                       #}
   {#      This program is part of the ILAP library, and was written in     #}
   {#   The Department of Computer Science at the University of Edinburgh   #}
   {#       (James Clerk Maxwell Building, Kings Buildings, Edinburgh)      #}
   {#                                                                       #}
   {#   This software is available free to other educational establisments  #}
   {#   but the University of Edinburgh, retains all commercial rights.     #}
   {#   It is a condition of having this software is that the sources are   #}
   {#   not passed on to any other site, and that Edinburgh University is   #}
   {#   given credit in any re-implementations of any of the algorithms     #}
   {#   used, or articles published which refer to the software.            #}
   {#                                                                       #}
   {#   There is no formal support for this software, but any bugs should   #}
   {#   be reported to Gordon Hughes or David Rees at the above address,    #}
   {#   are likely to be fixed in a future release.                         #}
   {#                                                                       #}
   {#########################################################################}
! 
! INTRODUCTION:
! 
!    ILAP  is  a  series  of  external  Imp  procedures  which  allow  the
! creation  of  syntactically correct CIF2.0 representations of integrated
! circuit layouts.   By embedding a graphics capability into a high  level
! language,  the  use  of  control structures and parameterised symbols is
! made available to the designer.
! 
! 
! DESCRIPTION:
! 
!    ILAP contains procedures to draw shapes on different mask layers  and
! define  symbols  made of such shapes.   The actual individual procedures
! are described below.  However, it is important to note here that ILAP is
! very close to CIF 2.0, and that almost all procedure calls translate
! directly into  CIF 2.0.  Consequently,  where  the  results  of  certain
! constructions are not described the reader is referred to the definition
! of  CIF2.0  given  in  Mead  and Conway's "Introduction to VLSI Systems"
! (chapter 4, section 4.5).
! 
! 
! DIFFERENCES FROM CIF2.0:
! 
!    The major differences and restrictions of ILAP from CIF2.0 are summarised below.
!
!        All primitive shapes and symbol calls should be in symbols.
!        Boxes cannot be specified other than parallel to the axes.
!        Symbols can only be rotated parallel to the axes.
!        Symbol calls which specify rotation or mirroring are rotated or 
!                mirrored before translation.
!        No symbol definition delete statement.
! 
! 
! ACCURACY:
! 
!    All units (i.e. widths,  heights,  lengths  and  displacements),  are
! specified  in  terms  of  lambda.   Lambda  is  the  distance by which a
! geometrical feature on one layer  may  stray  from  another  geometrical
! feature  on  the  same  layer  or  on  another layer with all processing
! factors considered and an appropriate safety factor added.   The  design
! rules  given in Mead and Conway are given in terms of lambda.   Accuracy
! of all units is preserved to one tenth lambda.
! 
! 
! The next 20 lines are operating system dependent possibly
!%external %integer %fn %spec REM (%integer A, B)
 %const %string (4) output extension = ".CIF"
!%const %string (1) snl = "
!"
 %own %integer cif stream = 3
 %own %integer error stream = 0
!%external %integer %fn %spec out stream
!%external %routine %spec open output (%integer s, %string (127) file)
!%external %routine %spec close output
!%external %routine %spec prompt (%string (63) s)
!%external %routine %spec set default (%string (5) s)
 %external %string (63) %fn %spec itos (%integer n, s)
 %external %string (15) %fn %spec date
 %external %string (15) %fn %spec time
 %external %routine %spec check %alias "ILAP__CHECK" (%string (31) s, %byte %array (2) %name data,
    %short %array (2) %name tran ids, %integer xmax, ymax, xorigin, yorigin)
 %external %string (127) %fn %spec out file name
!%system %routine %spec exit (%integer code)

%const %integer true = 1, false = 0
%const %integer smallest = -16_7FFF           { maximum bounding box size in lambda
%const %integer largest  =  16_7FFF           { ditto
%const %integer max symbols = 127             { Must be a power of 2 minus 1 for 'lookup' to work
%const %integer Polygon Type = 1,   Line Type = 2
%const %integer ETPX type = 3,      ETPY type = 4
%const %integer ETDX type = 5,      ETDY type = 6
%const %integer DTPX type = 7,      DTPY type = 8
%const %integer DTDX type = 9,      DTDY type = 10
%const %integer DTDBX type = 11,   DTDBY type = 12
%const %integer Wire type = 13
%const %integer Max type = 13
%const %integer up = 0, down = 1, left = 2, right = 3, none = 4
%const %integer Tr bit = 128                  { Indicates that the layer number is part of a transistor
%const %integer Tr layer = 7
%const %integer no tr bit = \ Tr bit
%const %integer violations = 64
%const %integer max layer = 15
%own %integer last layer = 9
%own %integer last merged layer = 7
%const %integer diff layer = 0
%const %integer poly layer = 1
%const %string (4) %array NMOS codes (0:max layer) =
 "ND", "NP", "NM", "NI", "NB", "NC", "NV", "NT", "NG", "?" (*)
%const %string (4) %array CMOS codes (0:max layer) =
 "CD", "CP", "CM", "CWP", "CWN", "CC", "CV", "CT", "CG", "CS", "CW", "CA", "?"(*)
%own %string (4) %array %name layer codes(0:max layer)
%own %string (15) %array NMOS names (0:max layer) =
 "diffusion", "polysilicon", "metal", "implant", "buried", "contact",
 "violations", "transistors", "glass", "undefined" (*)
%own %string (15) %array CMOS names (0:max layer) =
 "diffusion", "polysilicon", "metal", "P-well", "N-well", "contact",
 "violations", "transistors", "glass", "substrate", "well", "active", "undefined" (*)
%own %string (15) %array %name layer names(0:max layer)
%own %integer %array NMOS widths (0:max layer) =
 2, 2, 3, 6, 4, 2, 0, 2, 40, 0 (*)
%own %integer %array CMOS widths (0:max layer) =
 2, 2, 3, 4, 4, 2, 0, 2, 40, 4, 4, 2, 0 (*)
%own %integer %array %name default widths(0:max layer)
%own %integer %array widths (0:max layer) = 0 (*)
%const %string (35) after init = " must be called before INITIALISE"

%record %format symdef(%string(31) name, %integer number, geometry, calls, xl, yl, xu, yu, trans);! Symbol Table Entry format
%own %record (symdef) %array symbol table(-1:max symbols) = 0(*) { Symbol Table
%own %byte symbols speced = false

%own   %record (symdef) %name current symbol    { current symbol
%own   %record (symdef) %name call symbol       { symbol currently being called

%record %format boxf (%short lx, ly, ux, uy, %byte layer, %record (boxf) %name next)
%own %record (boxf) %name first box, next box  { set to NIL in INILIALISE }

%own %string(31) current transistor name = ""    { name of transistor
%own %string (3) layer before transistor="" { restored after each transistor
%own %byte technology = 'N'                 { Type of MOS.
%own %integer current point                 { index for path
%own %integer current type                  { path type
%own %integer current width                 { for Wires
%own %integer init = false                  { Set TRUE after initialise called
%own %integer statements                    { CIF statement count
%own %integer warnings                      { Error report counter
%own %integer current stream                { Holds current stream selected by caller
%own %integer initial symbol = 100          { Set to first CIF symbol number required can be set by users
%own %integer seqno                         { Number of current symbol

%own %integer wlx, wly, wux, wuy, wdir      { Wire box bounds  (also used for transistor gates)}
%own %integer olx, oly, oux, ouy            { Transistor overlap boxes }
%own %integer ppx, ppy                      { Position in Path }
%own %string (3) gate layer, overlap layer
%own %byte depletion transistor = false     { type of tran being defined }
%own %byte first transistor box = false

%const %integer NMOS Lambda = 300,   CMOS Lambda = 250,   Default Lambda = 250
%own %integer lambda = Default Lambda           { Number of 100s of microns in each unit distance
%own %integer cifscale = 2 - (Default Lambda&1) { All values are multiplied by this
! If lambda is EVEN => CIFSCALE = 2 => DS n lambda//2 1;
! If lambda is ODD  => CIFSCALE = 1 => DS n lambda 1; and polygons used if box is odd sized.

%routine %spec dump comment (%string (255) s)
%routine %spec dump statement (%string (255) s)
%routine %spec end symbol
%integer %fn %spec c width

%include "ILAPUTIL"
! Which defines MONITOR, NODE NAME, and DUMP LAMBDA

%external %integer %fn ILAP warnings %alias "ILAP_WARNINGS"
   %result = WARNINGS
%end

%own %integer control = 0
%external %integer %map ILAP control %alias "ILAP_CONTROL"
   %result == control
%end
%const %integer no warnings = 1             { Suppress warning messages
%const %integer monitor endsym = 2          { Gives a message on ENDSYM
%const %integer give times = 4              { Monitor CPU use 
%const %integer merge = 8                   { Produce merged CIF
%const %integer design rule check = 16      { Turns on DRC
%const %integer circuit analysis = 32       { Let Natalie loose on the design!
%const %integer give node list = 64         { Ask for a list of nodes
%const %integer give tran list = 128        { Ask for a list of transistors
%const %integer give node plot = 256        { Ask for a plot of the extracted circuit.

%own %integer current layer = -1, previous layer = -1
! The significance of the layer integer is -
! <0               => no layer defined
! 0<= layer&noTRbit <=max layer  => a known layer (from array)

%string(63)%fn layer name(%integer cif name)
   cif name = cif name & no tr bit
   %result = layer names(cif name) %if  0<=cif name<=max layer
   %result = "undefined"
%end

%external %routine warn %alias "ILAP_WARNING" (%string(255) s)
   !Outputs a warning message plus some additional information on an error
   !Also keeps a count of number of warnings
   %integer i

   %return %if control & no warnings # 0
   i = out stream
   select output (error stream)
   print string ("Warning: ")
   print string (s)
   print string (" on layer ".layer name(current layer)) %if current layer>=0
   print string (" in symbol ".current symbol_name) %if current symbol##nil
   newline
   select output (i)
   warnings = warnings + 1
%end

%external %routine die %alias "ILAP_DISASTER" (%string (255) s)
   ! Abort the program, after a disasterous error.
   select output (error stream)
   print string ("Disaster: ")
   print string (s)
   print string (" in symbol ".current symbol_name) %if current symbol##nil
   newline
%signal 0, 42
!   exit (16_10000000 + 42)
%end

%string (63)  %fn W P or Tran (%integer current type)
   ! Returns a string with 'Transistor Polygon or Wire'
   ! Current point<1 is none or all
   %const %string (7) %array type(1:max type) =
   "Polygon", "Line", "ETPX", "ETPY", "ETDX", "ETDY", "DTPX", "DTPY", "DTDX", "DTDY", "DTDBX", "DTDBY", "Wire"
   %result = "Transistor, Polygon, or Wire" %if current type<1
   %result = type(current type)
%end

%string (31) %fn at point (%integer x, y)
   %result = " at (X=".itos(x,0)." Y=".itos(y,0).")"
%end

%routine track error (%string (3) which)
   ! Check that we are doing a polygon, wire, line, or transistor
   warn (which." called with no Polygon, Wire, or Transistor being started")
%end

%routine layer check
   ! check that user has specified a layer to output on
   warn ("Layer not defined") %if current layer<0
%end

%routine warn outside symbol (%string (255) s, %integer x, y)
   ! warn a user that geometry of a call is outside a symbol
   warn (s." outside a symbol".at point(x,y))
%end

%routine out num (%integer n)
   ! Outputs a number in the minimum digits
   space;   write (n, 0)
%end

%routine initialise (%string (255) ofile)
   %integer i, char

   %return %if init=true;                          !already initialised
   current stream = out stream
   select output (error stream)
   %if ofile="" %start
       print string (version);   newline
       prompt ("CIF output file name: ")
       read symbol (char) %until char > ' '
       %cycle
          ofile = ofile.tostring(char) %if char#' '
          read symbol (char)
       %repeat %until char < ' '
   %finish
!   set default (output extension)
ofile = ofile.".CIF" %unless ofile -> (".") %or charno(ofile,1)=':'
   open output (cif stream, ofile)
   %if technology = 'N' %start
       Lambda = nmos lambda
       layer codes == nmos codes
       layer names == nmos names
       default widths == nmos widths
       last layer = 9
   %finish %else %if technology = 'C' %start
       Lambda = cmos lambda
       layer codes == cmos codes
       layer names == cmos names
       default widths == cmos widths
       last layer = 11
   %finish
   init = true
   cifscale = 2 - (lambda&1)
   first box == nil;   next box == nil
   symbol table (i) = 0 %for i = -1, 1, max symbols
   current point = -1
   current symbol == nil
   statements = 0
   warnings = 0
   %if initial symbol<0 %start
       warn("Initial symbol ".itos(initial symbol,0)." invalid")
       initial symbol = 100
   %finish
   seqno = initial symbol - 1
   widths(i) = default widths(i) %for i = 0, 1, max layer
   current layer = -1
   select output (cif stream)
   dump comment ("CIF 2.0")
   dump comment ("File ".outfilename)
   dump comment ("Produced by ".version." on ".date." at ".time)
   dump lambda (lambda)
   select output (current stream)
%end

%routine new layer (%string (4) colour)
   %integer new layer, i, current stream
   warn outside symbol("Set layer",0,0) %if current symbol==nil
   colour = to string (technology).colour %if length(colour) = 1
   current layer = -1 %and %return %if colour = ""; ! Forget current layer
   new layer = -1
   %for I = 0, 1, last layer %cycle
        new layer = i %if layer codes(i)=colour
   %repeat
   %if new layer = -1 %start
       ! Try to add it :
       DIE ("Too many layers used") %if last layer = max layer
       last layer = last layer + 1
       layer codes (last layer ) = colour
       layer names (last layer) = colour
       widths (last layer) = 2 { as a default }
       new layer = last layer
   %finish
   new layer = new layer ! Tr bit %if new layer >=0 %and current transistor name # ""
   %return %if current layer=new layer
   current layer=new layer
   %if control < merge %or new layer & no tr bit > last merged layer %start
       current stream = out stream
       select output (cif stream)
       print symbol ('L');  space;  print string (colour);  print symbol (';')
       newline
       select output (current stream)
       statements = statements + 1
   %finish
%end

%string (4) %fn CUR LAYER
   ! returns the current layer
   %integer layer
   layer = current layer & no tr bit
   %result = layer codes (layer) %if 0<=layer<=last layer
   %result = ""
%end

%external %routine fix mbb %alias "ILAP_FIX_MBB" (%integer xl, yl, xu, yu)
   ! Fixes the size of the symbols bounding box  (used by the annotation procedures)
   warn ("FIX MBB used when no symbol was defined") %and %return %if current symbol==nil
   current symbol_xl = xl;   current symbol_yl = yl
   current symbol_xu = xu;   current symbol_yu = yu
%end

%external %routine update mbb %alias "ILAP_UPDATE_MBB" (%integer xl, yl, xu, yu)
   ! Updates if necessary the minimum bounding box of the current symbol
   %return %if current symbol==nil
   current symbol_xl=xl %if xl<current symbol_xl
   current symbol_yl=yl %if yl<current symbol_yl
   current symbol_xu=xu %if xu>current symbol_xu
   current symbol_yu=yu %if yu>current symbol_yu
%end

%integerfn lookup(%string(31)name)
   !Finds the specified name in the Symbol Table or allocates a new entry
   !Names are converted to a canonical form (see fn CANONICAL below)
   !Returns entry -1 if the Symbol Table is full
   %integer val, i
    
    %string(31) %fn canonical(%string(31) name)
       !Returns parameter in a canonical form i.e. only upper case and spaces removed
       %string(31) canon name
       %integer i,char
       canon name = ""
       %for i = 1,1,length(name) %cycle
         char = charno(name,i)
         char = char-('a'-'A') %if 'a'<=char<'z';            !Lower case to Upper case
         canon name = canon name.tostring(char) %if char#' ';!Remove spaces
       %repeat
       %result = canon name
    %end

   name = canonical(name)
   val = 0
   val = val+charno(name,i)<<(i-1) %for i=1,1,length(name)
   i = val&max symbols
   i = (i+1)&max symbols %until canonical(symbol table(i)_name)=name %orc
                         symbol table(i)_number=0 %or i=val&max symbols
   %result = i %unless i=val&max symbols
   %result = -1
%end

%const %integer choose sx = 0, choose sy = 1, choose lx = 2, choose ly = 3

%integer %fn get mbb (%string (31) cell, %integer which)
   %const %string (2) %array proc (0:3) = "SX", "SY", "LX", "LY"
   %record (symdef) %name entry
   %switch sw (0:3)
   initialise ("") %if init=false
   entry  == symbol table (lookup(cell))
   %if entry_number#0 %start
       %if entry_xu<=entry_xl %or entry_yu<=entry_yl %start
           warn (proc(which)." is undefined")
           %result = 0
       %finish
       warn (proc(which)." is of the current symbol") %if entry==current symbol
       -> sw(which)

       sw (choose sx): %result = entry_xu - entry_xl
       sw (choose sy): %result = entry_yu - entry_yl
       sw (choose lx): %result = entry_xl
       sw (choose ly): %result = entry_yl
   %finish
   warn ("Symbol """.cell.""" not defined for ".proc(which))
   %result = 0
%end

%routine dump statement (%string (255) s)
   %integer current stream
   current stream = out stream
   select output (cif stream)
   print string (s);   print symbol (';');   newline
   statements = statements + 1
   select output (current stream)
%end

%routine dump comment (%string (255) s)
   dump statement ("(".s.")")
   warn ("Cif Comment contains brackets") %if s -> ("(")
   warn ("Cif Comment extends across a line") %if s -> (snl)
%end

%routine dump (%string (15) start, %integer x, y)
   ! Start dumping the code for either a polygon or a line
   current stream = out stream
   select output (cif stream)
   print string (start)
   wlx = x;   wly = y
   olx = wlx;   oly = wly
   out num (x*cifscale)
   out num (y*cifscale)
   current point = 1
   select output (current stream)
%end

%routine dump point (%integer x, y)
   current stream = out stream
   select output (cif stream)
   out num (x*cifscale)
   out num (y*cifscale)
   wlx = x;   wly = y
   update mbb (olx, oly, wlx, wly)
   current point = current point + 1
   newline %if rem (current point, 5) = 0
   select output (current stream)
%end

%routine dump box (%integer xl, yl, xu, yu)
   current stream = out stream
   select output (cif stream)
   %if cifscale=2 %start
       print symbol ('B')
       outnum ((xu-xl)*2)
       outnum ((yu-yl)*2)
       outnum (xu+xl)
       outnum (yu+yl)
   %finish %else %if (xu+xl)&1=0 %and (yu+yl)&1=0 %start
       print symbol ('B')
       outnum (xu-xl)
       outnum (yu-yl)
       outnum ((xu+xl)//2)
       outnum ((yu+yl)//2)
   %else
       print symbol ('P')
       outnum (xl);   outnum (yl);   outnum (xu);   outnum (yl)
       outnum (xu);   outnum (yu);   outnum (xl);   outnum (yu)
       outnum (xl);   outnum (yl)
   %finish
   print symbol (';')
   newline
   statements = statements+1
   select output (current stream)
%end

%routine output box(%integer xl, yl, xu, yu)
   ! Saves a box given any diagonally opposite corners
   ! or outputs it if the layer is not to be saved.
   %record(boxf)%name box
   %integer i, l

   %if xu<xl %start
     i=xu; xu=xl; xl=i
   %finish
   %if yu<yl %start
     i=yu; yu=yl; yl=i
   %finish
   update mbb(xl, yl, xu, yu)
   l = current layer & no trbit
   %if control >= merge %and 0<=l<=last merged layer %start
       box == nil
       box == new (box)
       box_next == nil
       %if first box == nil %start
           first box == box
           next box == box
           box == first box
       %finish %else %start
           next box_next == box
           next box == next box_next
       %finish
       box_ly <- yl;   box_lx <- xl;   box_uy <- yu;   box_ux <- xu;   box_layer<-current layer
   %finish %else dump box (xl, yl, xu, yu)
%end

%routine do transistor implant
   %if first transistor box = true %start
       ! Extend the Implant
       %if wdir=up %start
           oly = oly - 2
       %finish %else %if wdir=down %start
           ouy = ouy + 2
       %finish %else %if wdir=right %start
           olx = olx - 2
       %finish %else %if wdir=left %start
           oux = oux + 2
       %finish
       first transistor box = false
   %finish
   new layer ("NI")
   output box (olx, oly, oux, ouy)
%end

%routine bit map to boxes (%byte %array (2) %name bit map, %integer xlim, ylim, originx, originy, layers)
   %integer  p,i,j,x,y,xx,yy,xxlim,mask
   %byte %name  pixel
   %routine put box (%integer xl, yl, xu, yu,la)
      !* Outputs a CIF2.0 box
      %integer st
      %own %integer l = -1
      l = la %and %return %if la<0
      st = out stream
      %if l#la %start
          l = la
          select output (cif stream)
          print symbol ('L')
          space
          print string (layer codes(l))
          print symbol (';')
          newline
          statements = statements+1
      %finish
      dump box (xl, yl, xu, yu)
      select output (st)
   %end

   put box (0, 0, 0, 0, -1)
   ! The above makes the put box routine forget the layer last used in the
   ! last cell, as layers are only local to a symbol call.
   %for p=0,1,last merged layer-1 %cycle
      mask=1<<p
      %continue %if mask&layers = 0
      %for y=0,1,ylim %cycle    ;! find lower left
         %for x=0,1,xlim %cycle
            %if bit map(x,y)&mask#0 %start
               xxlim=xlim
               %for xx=x,1,xlim %cycle    ;! find lower right
                    xxlim=xx-1 %and %exit %if bit map (xx,y)&mask=0
               %repeat
               %for yy=y+1,1,ylim %cycle
                  yy = yy - 1 %and %exit %if bit map(x,yy)&mask=0
                  %for xx=x+1,1,xxlim %cycle
                     %if bit map(xx,yy)&mask=0 %start
                        %if xx-x>=yy-y %start
                           xxlim=xx-1
                           %exit
                        %finish %else %start
                           yy=yy-1
                           ->boxout
                        %finish
                     %finish
                  %repeat
               %repeat
   boxout:     put box(x+originx,y+originy,xxlim+originx+1,yy+originy+1,p)
               %for j=y,1,yy %cycle
                  %for i=x,1,xxlim %cycle
                     pixel == bit map(i, j)
                     pixel = pixel&(\mask)
                  %repeat
               %repeat
            %finish
         %repeat
      %repeat
   %repeat
%end

%routine Transistor Polygon or Wire check
   ! Checks if a path of points is being produced if so outputs a set of boxes
   ! Minimum points for a line is 2
   ! Minimum points for a polygon is 3
   %switch type (1:max type)
   %integer i

   initialise("") %if init=false;     !User has not called initialise do it for him
   %return %if current point<0;       !Nothing happening
   %if current type=Polygon Type %and current point>2 %and (olx#wlx %or oly#wly) %start
       warn("Polygon not closed".at point(wlx, wly))
   %finish
   i = current point
   current point = -1
   %if (current type=Line type %and i=1) %or (current type=Polygon type %and i=2) %start
       warn("Incomplete ".W P or Tran(current type).at point(wlx, wly))
       %return
   %finish
   -> type (current type)

type (polygon type):
type (line type):
     current stream = out stream
     select output (cif stream)
     Print symbol (';');   newline
     select output (current stream)
     statements = statements + 1
     %return

type (wire type):
     output box (wlx, wly, wux, wuy)
     %return

type (ETPX type): type (ETPY type):
type (ETDX type): type (ETDY type):
type (DTPX type): type (DTPY type):
type (DTDX type): type (DTDY type):
type (DTDBX type): type (DTDBY type):
     new layer (overlap layer)
     output box (olx, oly, oux, ouy)
     ! Extend the gate in the direction that we last went in.
     %if wdir=up %start
         wuy = wuy + 2;   ouy = ouy + 2
     %finish %else %if wdir=down %start
         wly = wly - 2;   oly = oly - 2
     %finish %else %if wdir=right %start
         wux = wux + 2;   oux = oux + 2
     %finish %else %start { left }
         wlx = wlx - 2;   olx = olx - 2
     %finish
     do transistor implant %if depletion transistor = true
     new layer (gate layer)
     output box (wlx, wly, wux, wuy)
     current transistor name = ""
     depletion transistor = false
     new layer (layer before transistor)
%end

%integer %fn draw first (%string (31) name, %integer x, y)
   ! Checks if a symbol is defined if it is output first part of call
   ! Used in conjunction with drawlast
   %record (symdef)%name entry
   %own %byte called out side symbol = false

   Transistor Polygon or Wire check

   entry == symbol table (lookup (name))

   %if entry_number = 0 %start
       warn ("Call on undefined symbol ".name.at point(x,y))
       %result = false
   %finish %else %start
      %if entry==current symbol %start
          warn ("Recursive call on symbol ".name.at point(x,y))
          %result = false
      %finish %else %start
          %if current symbol##nil %start
              current symbol_calls = current symbol_calls + 1
              current symbol_trans = current symbol_trans + entry_trans
          %finish %else %start
              ! ILAP allows 1 call outside a symbol, but warns if more occur.
              warn outside symbol ("Call of ".name, x, y) %if called out side symbol = true
              called out side symbol = true
          %finish
          current stream = out stream
          select output(cif stream)
          print symbol ('C')
          outnum (|entry_number|)
          call symbol == entry
          %result = true
      %finish
   %finish
%end

%string (7) %fn rotation (%integer %name ROT)
   ! return the rotation component and also normalise ROT to the range 0 to 3
   %const %string (4) %array rotations (0:3) = "1 0", "0 1", "-1 0", "0 -1"
   rot = rem(rem(rot,4)+4,4);          !normalise rotation
   %result = " R ".rotations(rot)
%end

%routine draw last (%string (15) transform, %integer x, y)
   ! Outputs final part of symbol call.
   ! first the transformation information, and then the translation to new x,y
   print string (transform)
   print string (" T")
   outnum (x*cifscale);   outnum (y*cifscale);   print symbol (';');   newline
   statements = statements + 1
   select output (current stream)
%end

%routine shape check (%string (15) shape, %integer X, Y)
   Transistor Polygon or Wire check
   layer check
   %if current symbol##nil %start
       current symbol_geometry = current symbol_geometry+1
   %finish %else warn outside symbol (shape, x, y)
%end

%routine check current symbol
   %integer  cxl, cxu, cyl, cyu, cxd, cyd
   cxl = current symbol_xl
   cyl = current symbol_yl
   cxu = current symbol_xu
   cyu = current symbol_yu
   cxd = cxu-cxl-1
   cxd = 3 %if cxd<3; ! 0:3 is minimum size that can be DRCed
   cyd = cyu-cyl-1
   cyd = 3 %if cyd<3
   %begin
      %integer i,j,x,y,bit,checks, yl, yu
      %record(boxf) %name  box
      %byte %array  bit map (0 : cxd, 0 : cyd)
      %short %array tran names (0 : cxd, 0 : cyd)
      %byte %name  pixel
!! For EMAS only
!      %integer %fn extend (%half I)
!         I = I ! 16_FFFF0000 %if I&16_8000#0
!         %result = I
!      %end
!! End of EMAS only section, (+ delete following set of {} )
      %for i = 0, 1, cxd %cycle
         bit map(i,j) = 0 %for j = 0, 1, cyd
      %repeat
      checks = 0
      box == first box
      %while box ## nil %cycle
         bit = 1<<(box_layer&notrbit) ! (box_layer&trbit)
         checks = checks ! bit
         yl = {extend} (box_ly) - cyl                { <<< Change on EMAS }
         yu = {extend} (box_uy) - cyl - 1            { <<< Change on EMAS }
         %for x = {extend} (box_lx)-cxl, 1, {extend} (box_ux)-cxl-1 %cycle
            %for y = yl, 1, yu %cycle
               pixel == bit map(x,y)
               pixel = pixel ! bit
            %repeat
         %repeat
         first box == box
         box == box_next
         dispose (first box)
      %repeat
      first box == nil;   next box == nil
      %if control >= design rule check %start
          monitor ("Starting DRC") %if control & give times # 0
          check (current symbol_name, bit map, tran names, cxd, cyd, cxl, cyl)
      %finish
      checks = checks ! violations; ! To ensure that they are drawn.
      monitor ("Start of Bit map to boxes") %if control & give times #0
      bit map to boxes (bit map, cxd, cyd, cxl, cyl, checks)
      monitor ("End of Bit map to boxes ") %if control & give times # 0
   %end
%end

!***
!***
!***         Everything before this point is internal to ILAP
!***         Everything after this point is available externally
!***
!***

%external %routine symbol %alias "ILAP_SYMBOL" (%string (31) name)
   %record (symdef) %name entry
   Transistor Polygon or Wire check
   %if current symbol##nil %start
       warn("Nested symbol definition ".name)
       endsymbol
   %finish
   entry == symbol table(lookup(name))
   %if entry##symbol table (-1) %start
       %if entry_number>0 %then warn ("Multiply defined symbol ".name)
       seqno = seqno+1 %if entry_number = 0   { if it has not been spec'd }
       previous layer = current layer
       current layer = -1
       current symbol == entry
       %if current symbol_number=0 %start
           ! Note that all fields have value 0 if not assigned.
           current symbol_number = seqno
           current symbol_name = name
           current symbol_xl = largest;     current symbol_yl = largest
           current symbol_xu = smallest;    current symbol_yu = smallest
       %finish %else current symbol_number = |current symbol_number|
       current stream = out stream
       select output (cif stream)
       newline;   print string ("DS")
       outnum (current symbol_number)
       %if cifscale=1 %then outnum(lambda) %else outnum(lambda//2)
       print string (" 1;")
       select output (current stream)
       statements = statements + 1
       warn ("Symbol name contains a ';', (trumcated before it)") %if name->name.(";")
       dump statement ("9 ".name)
   %finish %else die ("Symbol Table Full adding ".name)
   monitor ("Start of symbol """.name."""") %if control & give times # 0
%end

%external %routine external symbol %alias "ILAP_EXTERNAL_SYMBOL" (%string (31) name, %integer number)
   %record (symdef) %name entry
   Transistor Polygon or Wire check
   %if current symbol##nil %start
       warn("Nested symbol definition ".name)
       endsymbol
   %finish
   entry == symbol table(lookup(name))
   %if entry##symbol table (-1) %start
       %if entry_number>0 %then warn ("Multiply defined symbol ".name)
       previous layer = current layer
       current layer = -1
       current symbol == entry
       %if current symbol_number=0 %start
           ! Note that all fields have value 0 if not assigned.
           current symbol_number = number   { NB. This should be checked of validity ! }
           current symbol_name = name
           current symbol_xl = largest;     current symbol_yl = largest
           current symbol_xu = smallest;    current symbol_yu = smallest
       %finish %else current symbol_number = |current symbol_number|
       current stream = out stream
       select output (cif stream)
       newline;   print string ("DS")
       outnum (current symbol_number)
       %if cifscale=1 %then outnum(lambda) %else outnum(lambda//2)
       print string (" 1;")
       statements = statements + 1
       select output (current stream)
       warn ("Symbol name contains a ';', (trumcated before it)") %if name->name.(";")
       dump statement ("9 ".name)
   %finish %else die ("Symbol Table Full adding ".name)
   monitor ("Start of symbol """.name."""") %if control & give times # 0
%end

%external %routine symbol spec %alias "ILAP_SYMBOL_SPEC" %c
   (%string (31) name, %integer xl, yl, xu, yu)
   %record (symdef) %name entry
   Transistor Polygon or Wire check
   entry == symbol table(lookup(name))
   %if entry##symbol table (-1) %start
       %if entry_number#0 %then warn ("Symbol ".name." conflicts with previous definition")
       seqno = seqno+1
       previous layer = current layer
       current layer = - 1
       entry_number = - seqno
       entry_name =  name
       entry_xl = xl;    entry_yl = yl
       entry_xu = xu;    entry_yu = yu
   %finish %else die ("Symbol Table Full adding ".name)
   symbols speced = true
%end

%external %routine external symbol spec %alias "ILAP_EXTERNAL_SYMBOL_SPEC" %c
   (%string (31) name, %integer num, xl, yl, xu, yu)
   %string (255) line
   %record (symdef) %name entry
   Transistor Polygon or Wire check
   %if 0<=num<initial symbol %or num>initial symbol+max symbols %start
       entry==symbol table(lookup(name))
       %if entry##symbol table(-1) %start
           %if entry_number#0 %then warn ("External symbol ".name." conflicts with internal definition")
           entry_number=-num;   entry_name=name
           entry_xl=xl;   entry_yl=yl
           entry_xu=xu;   entry_yu=yu
           warn ("Invalid MBB for external symbol ".name) %if xl>xu %or yl>yu
           line = name
           line = itos (yu * lambda,0).",".line
           line = itos (xu * lambda,0).",".line
           line = itos (yl * lambda,0).",".line
           line = itos (xl * lambda,0).",".line
           line = itos (num, 0).",".line
           dump statement ("8 ".line)
       %finish %else die ("Symbol Table Full adding external symbol ".name)
   %finish %else warn ("External symbol ".name." number ".itos(num,0)." conflicts with internal numbers")
%end

%external %routine end symbol %alias "ILAP_END_SYMBOL"
   %integer i
   %string (255) diags
   Transistor Polygon or Wire check
   %if current symbol##nil %start
       %if control # 0 %start
           diags = "End of symbol """.current symbol_name.""""
           %if control & monitor end sym # 0 %start
               diags = diags.itos(current symbol_xl,1).itos(current symbol_yl,1)
               diags = diags.itos(current symbol_xu,1).itos(current symbol_yu,1)
           %finish
           monitor (diags) %if control & (monitor end sym ! give times) # 0
       %finish
       current layer = previous layer
       widths(i) = default widths(i) %for i=0,1,max layer
       %if current symbol_geometry>0 %start
           check current symbol %if control >= merge
       %finish %else %start
           %if control >= design rule check %start
               current stream = out stream
               select output (0)
               newline
               print string ("No check of symbol ".current symbol_name)
               newline
               select output (current stream)
           %finish
       %finish
       dump statement ("DF")
       %if current symbol_xl=largest %and current symbol_yl=largest %and %c
           current symbol_xu=smallest %and current symbol_yu=smallest %start
         warn ("No geometry")
         current symbol_xl=0;   current symbol_yl=0
         current symbol_xu=0;   current symbol_yu=0
       %finish
       current symbol == nil
   %finish %else warn ("Unmatched endsymbol")
%end

%external %routine dx %alias "ILAP_DX" (%integer u)
   track error ("DX") %and %return %if current point < 0
   %if polygon type # current type # line type %start
       %if u#0 %start
           ppx = ppx + u
           %if current type # wire type %start
               ! Transistor
               %if wdir=up %start
                   ouy = ouy + 2
               %finish %else %if wdir=down %start
                   oly = oly - 2
               %finish
               new layer (overlap layer)
               output box (olx, oly, oux, ouy)
               do transistor implant %if depletion transistor = true
               new layer (gate layer)
           %finish
           output box (wlx, wly, wux, wuy)
           %if left#wdir#right %start
               %if wdir=up %then wly=wuy-current width %else wuy=wly+current width
           %finish
           %if u>0 %start
               wlx = wux;   wux = wux + u;   wdir = right
           %finish %else %start
               wux = wlx;   wlx = wlx + u;   wdir = left
           %finish
           olx = wlx;   oux = wux;   oly = wly - 2;   ouy = wuy + 2
       %finish %else warn ("DX of ".W P or Tran (current type)." is zero".at point (ppx,ppy))
   %finish %else dump point (wlx+u, wly)
%end

%external %routine dy %alias "ILAP_DY" (%integer v)
   track error ("DY") %and %return %if current point < 0
   %if polygon type # current type # line type %start
       %if v#0 %start
           PPY = PPY + v
           %if current type # wire type %start
               ! Transistor
               %if wdir=right %start
                   oux = oux + 2
               %finish %else %if wdir=left %start
                   olx = olx - 2
               %finish
               new layer (overlap layer)
               output box (olx, oly, oux, ouy)
               do transistor implant %if depletion transistor = true
               new layer (gate layer)
           %finish
           output box (wlx, wly, wux, wuy)
           %if up#wdir#down %start
               %if wdir=right %then wlx=wux-current width %else wux=wlx+current width
           %finish
           %if v>0 %start
               wly = wuy;   wuy = wuy + v;   wdir = up
           %finish %else %start
               wuy = wly;   wly = wly + v;   wdir = down
           %finish
           olx = wlx - 2;   oux = wux + 2;   oly = wly;   ouy = wuy
       %finish %else warn ("DY of ".W P or Tran (current type)." is zero".at point (ppx,ppy))
   %finish %else dump point (wlx, wly+v)
%end

%external %routine dxy %alias "ILAP_DXY" (%integer dx, dy)
   track error ("DXY") %and %return %if current point < 0
   %unless polygon type # current type # line type %start
       dump point (wlx+dx, wly+dy)
   %finish %else warn ("Only polygons and lines may use the DXY construct")
%end

%external %routine ax %alias "ILAP_AX" (%integer u)
   track error ("AX") %and %return %if current point < 0
   %if polygon type # current type # line type %start
       %if u<wlx %then dx (u-wlx) %else %if u>wux %then dx (u-wux) %else %start
           %if wlx#u#wuy %start
               warn ("AX of ".ITOS(u,0)." is inside the ". %c
                      W P or Tran(current type).at point (ppx, ppy))
           %finish
       %finish
    %else
       ppx = u
       dump point (u, wly)
    %finish
%end

%external %routine ay %alias "ILAP_AY" (%integer v)
   track error ("AY") %and %return %if current point < 0
   %if polygon type # current type # line type %start
       %if v<wly %then dy (v-wly) %else %if v>wuy %then dy (v-wuy) %else %start
           %if wly#v#wuy %start
               warn ("AY of ".ITOS(v,0)." is inside the ". %c
                      W P or Tran(current type).at point (ppx, ppy))
           %finish
       %finish
   %else
       ppy = v
       dump point (wlx, v)
   %finish
%end

%external %routine axy %alias "ILAP_AXY" (%integer x, y)
   track error ("AXY") %and %return %if current point < 0
   %unless polygon type # current type # Line type %start
       dump point (x, y)
   %finish %else warn ("Only polygons and lines may use the AXY construct")
%end

%external %routine wirex %alias "ILAP_WIREX" (%integer x, y, l)
   shape check ("Wirex", x, y)
   %return %if CWIDTH<=0
   current type = wire type
   current width = cwidth
   current point = 0
   ppx = x;   ppy = y   { Position in path for diagnostics }
   %if l < 0 %start
       wlx = x + l;   wux = x;   wdir = left
   %finish %else %if l > 0 %start
       wlx = x;   wux = x + l;   wdir = right
   %finish %else %start
       warn ("Zero length Wirex".at point (x, y))
   %finish
   wly = y;   wuy = y + current width
   { Note the box is buffered and is output when a new one is to be buffered }
%end

%external %routine wirey %alias "ILAP_WIREY" (%integer x, y, l)
   shape check ("Wirey", x, y)
   %return %if CWIDTH<=0
   current type = wire type
   current width = cwidth
   current point = 0
   ppx = x;   ppy = y   { Position in path for diagnostics }
   %if l < 0 %start
       wly = y + l;   wuy = y;   wdir = down
   %finish %else %if l > 0 %start
       wly = y;   wuy = y + l;   wdir = up
   %finish %else %start
       warn ("Zero length Wirey".at point(x,y))
   %finish
   wlx = x;   wux = x + current width
   { Note the box is buffered and is output when a new one is to be buffered }
%end

%external %routine gndwirex %alias "ILAP_GNDWIREX" (%integer x, y, l)
   shape check ("GNDwirex", x, y)
   %return %if CWIDTH<=0
   warn ("GND wire X not on metal layer") %if layer names (current layer)#"metal"
   current type = wire type
   current width = cwidth
   current point = 0
   ppx = x;   ppy = y   { Position in path for diagnostics }
   %if l < 0 %start
       wlx = x + l;   wux = x;   wdir = left
   %finish %else %if l > 0 %start
       wlx = x;   wux = x + l;   wdir = right
   %finish %else %start
       warn ("Zero length Wirex".at point (x, y))
   %finish
   wly = y;   wuy = y + current width
   { Note the box is buffered and is output when a new one is to be buffered }
%end

%external %routine gndwirey %alias "ILAP_GNDWIREY" (%integer x, y, l)
   shape check ("GNDwirey", x, y)
   %return %if CWIDTH<=0
   warn ("GND wire Y not on metal layer") %if layer names (current layer)#"metal"
   current type = wire type
   current width = cwidth
   current point = 0
   ppx = x;   ppy = y   { Position in path for diagnostics }
   %if l < 0 %start
       wly = y + l;   wuy = y;   wdir = down
   %finish %else %if l > 0 %start
       wly = y;   wuy = y + l;   wdir = up
   %finish %else %start
       warn ("Zero length Wirey".at point(x,y))
   %finish
   wlx = x;   wux = x + current width
   { Note the box is buffered and is output when a new one is to be buffered }
%end

%external %routine vddwirex %alias "ILAP_VDDWIREX" (%integer x, y, l)
   shape check ("VDDwirex", x, y)
   %return %if CWIDTH<=0
   warn ("VDD wire X not on metal layer") %if layer names (current layer)#"metal"
   current type = wire type
   current width = cwidth
   current point = 0
   ppx = x;   ppy = y   { Position in path for diagnostics }
   %if l < 0 %start
       wlx = x + l;   wux = x;   wdir = left
   %finish %else %if l > 0 %start
       wlx = x;   wux = x + l;   wdir = right
   %finish %else %start
       warn ("Zero length Wirex".at point (x, y))
   %finish
   wly = y;   wuy = y + current width
   { Note the box is buffered and is output when a new one is to be buffered }
%end

%external %routine vddwirey %alias "ILAP_VDDWIREY" (%integer x, y, l)
   shape check ("VDDwirey", x, y)
   %return %if CWIDTH<=0
   warn ("VDD wire Y not on metal layer") %if layer names (current layer)#"metal"
   current type = wire type
   current width = cwidth
   current point = 0
   ppx = x;   ppy = y   { Position in path for diagnostics }
   %if l < 0 %start
       wly = y + l;   wuy = y;   wdir = down
   %finish %else %if l > 0 %start
       wly = y;   wuy = y + l;   wdir = up
   %finish %else %start
       warn ("Zero length Wirey".at point(x,y))
   %finish
   wlx = x;   wux = x + current width
   { Note the box is buffered and is output when a new one is to be buffered }
%end

%external %routine box %alias "ILAP_BOX" (%integer xl, yl, xu, yu)
   shape check ("Box", xl, yl)
   %if xl<xu %and yl<yu %start
       output box (xl, yl, xu, yu)
   %finish %else warn ("Zero area box".at point(xl,yl))
%end

%external %routine polygon %alias "ILAP_POLYGON" (%integer x, y)
   shape check ("Polygon", x, y)
   current type = Polygon type
   dump ("P", x, y)
%end

%external %routine line %alias "ILAP_LINE" (%integer x, y)
   shape check ("Line", x, y)
   current type = Line type
   dump ("W 0", x, y)
%end

%routine start tran (%string (31) name, %integer x, y, l, w, dir, type, %string (3) gate, overlap)
   Transistor Polygon or Wire check
   %if current symbol##nil %start
       current symbol_geometry = current symbol_geometry+1
   %finish %else warn outside symbol (W P or Tran (type), x, y)
   %if w>=2 %start
       %if l#0 %start
           layer before transistor = cur layer
           current transistor name = name
           current type = Type
           current width = w
           current point = 0
           ppx = x;   ppy = y   { Path position, for error messages }
           gate layer = gate
           overlap layer = overlap
           depletion transistor = true %if DTPX type <= type <= DTDBY type
           first transistor box = true
           %if dir='X' %start
               %if l>0 %start
                   wlx = x;   wux = x + l;   wdir = right
               %finish %else %start
                   wlx = x + l;   wux = x;   wdir = left
               %finish
               wly = y;   wuy = y + w
               olx = wlx;   oux = wux;   oly = wly - 2;   ouy = wuy + 2
               %if l>0 %then wlx=wlx-2 %else wux=wux+2
           %finish %else %start
               %if l>0 %start
                   wly = y;   wuy = y + l;   wdir = up
               %finish %else %start
                   wly = y + l;   wuy = y;   wdir = down
               %finish
               wlx = x;   wux = x + w
               olx = wlx - 2;   oux = wux + 2;   oly = wly;   ouy = wuy
               %if l>0 %then wly=wly-2 %else wuy=wuy+2
           %finish
           %if current symbol ## nil %then current symbol_trans = current symbol_trans + 1
       %finish %else warn ("Zero length ".W P or Tran(type).at point(x,y))
   %finish %else warn("Invalid ".W P or Tran(type)." width <2".at point(x,y))
%end

%external %routine ETPX %alias "ILAP_ETPX" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(poly layer), 'X', ETPX type, "P", "D")
%end

%external %routine ETPY %alias "ILAP_ETPY" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(poly layer), 'Y', ETPY type, "P", "D")
%end

%external %routine ETDX %alias "ILAP_ETDX" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(diff layer), 'X', ETDX type, "D", "P")
%end

%external %routine ETDY %alias "ILAP_ETDY" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(diff layer), 'Y', ETDY type, "D", "P")
%end

%external %routine DTPX %alias "ILAP_DTPX" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(poly layer), 'X', DTPX type, "P", "D")
%end

%external %routine DTPY %alias "ILAP_DTPY" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(poly layer), 'Y', DTPY type, "P", "D")
%end

%external %routine DTDX %alias "ILAP_DTDX" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(diff layer), 'X', DTDX type, "D", "P")
%end

%external %routine DTDY %alias "ILAP_DTDY" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(diff layer), 'Y', DTDY type, "D", "P")
%end

%external %routine DTDBX %alias "ILAP_DTDBX" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(diff layer), 'X', DTDBX type, "D", "P")
   new layer ("NB");   output box (x-2, y-1, x+2, y+widths(diff layer)+1)
%end

%external %routine DTDBY %alias "ILAP_DTDBY" (%string (31) name, %integer x, y, l)
   start tran (name, x, y, l, widths(diff layer), 'Y', DTDBY type, "D", "P")
   new layer ("NB");   output box (x-1, y-2, x+widths(diff layer)+1, y+2)
%end

%external %routine layer %alias "ILAP_LAYER" (%string (4) colour)
   Transistor Polygon or Wire check
   new layer (colour)
%end

%external %string (4) %fn clayer %alias "ILAP_CLAYER"
   ! returns the current layer
   Transistor Polygon or Wire check
   %result = CUR LAYER
%end

%external %routine width %alias "ILAP_WIDTH" (%integer W)
   ! sets the width of Wires and transistors in the current layer
   Transistor Polygon or Wire check
   %if w > 0 %start
       %if current layer >= 0 %start
           widths (current layer&(trbit-1)) = W
       %finish %else warn ("No layer is set")
   %finish %else warn ("Invalid setting for WIDTH (".itos(W,0).")")
%end

%external %integer %fn cwidth %alias "ILAP_CWIDTH"
   ! returns the current width
   %integer layer
   Transistor Polygon or Wire check
   layer = current layer & no tr bit
   %result = widths (layer) %if 0 <= layer <= last layer
   %result = 2
%end

%external %routine draw %alias "ILAP_DRAW" (%string (31) name, %integer x, y)
   %if drawfirst(name,x,y)=true %start
       draw last ("", x, y)
       update mbb (call symbol_xl+x, call symbol_yl+y, call symbol_xu+x, call symbol_yu+y)
   %finish
%end

%external %routine draw mx %alias "ILAP_DRAW_MX" (%string (31) name, %integer x, y)
   %if drawfirst(name,x,y)=true %start
       draw last (" MX", x, y)
       update mbb (-call symbol_xu+x, call symbol_yl+y, -call symbol_xl+x, call symbol_yu+y)
   %finish
%end

%external %routine draw my %alias "ILAP_DRAW_MY" (%string (31) name, %integer x, y)
   %if drawfirst(name,x,y)=true %start
       draw last (" MY", x, y)
       update mbb (call symbol_xl+x, -call symbol_yu+y, call symbol_xu+x, -call symbol_yl+y)
   %finish
%end

%external %routine draw rot %alias "ILAP_DRAW_ROT" (%string (31) name, %integer x, y, rot)
   %if drawfirst(name,x,y)=true %start
       draw last (rotation (rot), x, y)
       %if rot=0 %start;                                   ! In first quadrant
           update mbb(call symbol_xl+x, call symbol_yl+y, call symbol_xu+x, call symbol_yu+y)
       %finish %else %if rot=2 %start;                     ! In third quadrant
           update mbb(-call symbol_xu+x,-call symbol_yu+y, -call symbol_xl+x,-call symbol_yl+y)
       %finish %else %if rot=1 %start;                     ! In Second quadrant
           update mbb(-call symbol_yu+x, call symbol_xl+y, -call symbol_yl+x, call symbol_xu+y)
       %finish %else %start;                               ! In Fourth quadrant
           update mbb(call symbol_yl+x,-call symbol_xu+y, call symbol_yu+x,-call symbol_xl+y)
       %finish
   %finish
%end

%external %routine draw mx rot %alias "ILAP_DRAW_MX_ROT" (%string (31) name, %integer x, y, rot)
   %if drawfirst(name,x,y)=true %start
       draw last (" MX".rotation (rot), x, y)
       %if rot=0 %start
           update mbb(call symbol_xu+x, call symbol_yl+y, call symbol_xl+x, call symbol_yu+y)
       %finish %else %if rot=2 %start
           update mbb(-call symbol_yu+x,-call symbol_xu+y, -call symbol_yl+x,-call symbol_xl+y)
       %finish %else %if rot=1 %start
           update mbb(call symbol_xl+x, -call symbol_yl+y, call symbol_xu+x, -call symbol_yu+y)
       %finish %else %start
           update mbb(call symbol_yl+x,call symbol_xl+y, call symbol_yu+x,call symbol_xu+y)
       %finish
   %finish
%end

%external %routine draw my rot %alias "ILAP_DRAW_MY_ROT" (%string (31) name, %integer x, y, rot)
   %if drawfirst(name,x,y)=true %start
       draw last (" MY".rotation (rot), x, y)
       %if rot=0 %start
           update mbb(call symbol_xl+x, -call symbol_yu+y, call symbol_xu+x, -call symbol_yl+y)
       %finish %else %if rot=2 %start
           update mbb (-call symbol_xu+x, call symbol_yl+y, -call symbol_xl+x, call symbol_yu+y)
       %finish %else %if rot=1 %start
           update mbb(call symbol_yl+x,call symbol_xl+y, call symbol_yu+x,call symbol_xu+y)
       %finish %else %start
           update mbb(-call symbol_yu+x, -call symbol_xu+y, -call symbol_yl+x, -call symbol_xl+y)
       %finish
   %finish
%end

%external %routine cif comment %alias "ILAP_CIF_COMMENT" (%string (255) s)
   Transistor Polygon or Wire check
   dump comment (s)
%end

%external %routine cif statement %alias "ILAP_CIF_STATEMENT" (%string (255) s)
   Transistor Polygon or Wire check
   warn ("CIF statement contains a ';', (trumcated before it)") %if s->s.(";")
   dump statement (s)
%end

%external %routine user extension %alias "ILAP_USER_EXTENSION" (%integer no, %string (255) s)
   warn ("User extension contains a ';', (trumcated before it)") %if s->s.(";")
   Cif statement (Itos(no,0)." ".s)
%end

%external %integer %fn sx %alias "ILAP_SX" (%string (31) cell)
   %result = get mbb (cell, choose sx)
%end

%external %integer %fn sy %alias "ILAP_SY" (%string (31) cell)
   %result = get mbb (cell, choose sy)
%end

%external %integer %fn lx %alias "ILAP_LX" (%string (31) cell)
   %result = get mbb (cell, choose lx)
%end

%external %integer %fn ly %alias "ILAP_LY" (%string (31) cell)
   %result = get mbb (cell, choose ly)
%end

%external %integer %fn symbol exists %alias "ILAP_SYMBOL_EXISTS" (%string (31) name)
   %record (symdef) %name entry
   initialise ("") %if init=false
   entry == symbol table (lookup(name))
   %if entry_number=0 %then %result=false %else %result=true
%end

%external %routine set lambda %alias "ILAP_SET_LAMBDA" (%integer L)
   warn ("Set Lambda called inside a symbol call") %if current symbol ## nil
   lambda = l
   dump lambda (l)
   cifscale = 2 - (L&1)
%end

%external %routine get lambda %alias "ILAP_GET_LAMBDA" (%integer %name L)
   l = lambda
%end

%external %routine first cell number %alias "ILAP_FIRST_CELL_NUMBER" (%integer I)
   warn ("First cell number must be positive") %and %return %if i<0
   %if init=true %start
       %if i<= seqno %then warn ("Call to FIRST CELL NUMBER had number less than the current number") %c
                     %else seqno = i-1
   %finish
   initial symbol = i { Slightly unsafe, but CIFSYS will sort it out if faulty }
%end

%external %routine MERGE ON %alias "ILAP_MERGE_ON"
   control = control ! merge
%end

%external %routine MERGE OFF %alias "ILAP_MERGE_OFF"
   Warn ("Call to MERGE OFF while within a symbol") %if first box ## nil
   control = control & (\merge)
%end

%external %routine DRC ON %alias "ILAP_DRC_ON"
   control = control ! design rule check
%end

%external %routine DRC OFF %alias "ILAP_DRC_OFF"
   CONTROL = control & (\ design rule check)
%end

%external %routine SET ERROR STREAM %alias "ILAP_SET_ERROR_STREAM" (%integer I)
   warn ("Set error stream".after init) %if init=true
   ERROR stream = I
%end

%external %routine SET CIF STREAM %alias "ILAP_SET_CIF_STREAM" (%integer I)
   warn ("Set CIF stream".after init) %if init=true
   CIF stream = I
%end

%external %routine INITIALISE NMOS %alias "ILAP_INIT_NMOS" (%string (255) ofile)
   technology = 'N'
   %if lambda#nmos lambda %start
       Warn ("LAMBDA being re-set by a call to INITIALISE") %if lambda#default lambda
       lambda = nmos lambda
   %finish
   initialise (ofile)
%end

%external %routine INITIALISE CMOS %alias "ILAP_INIT_CMOS" (%string (255) ofile)
   technology = 'C'
   %if lambda#cmos lambda %start
       Warn ("LAMBDA being re-set by a call to INITIALISE") %if lambda#default lambda
       lambda = cmos lambda
   %finish
   initialise (ofile)
%end

%external %routine finish %alias "ILAP_FINISH"
   %record (symdef) %name entry
   %integer i
   Transistor Polygon or Wire check
   end symbol %and warn ("Endsymbol missing at FINISH") %if current symbol##nil
   ! Check for any un-satisfied symbol specs
   %if symbols speced = true %start
       %for i = 0, 1, max symbols %cycle
            entry == symbol table (i)
            warn ("Body of symbol """.entry_name.""" missing at FINISH") %if entry_number < 0
       %repeat
   %finish
   current stream = out stream
   select output (cif stream)
   print symbol ('E');   newline
   close output
   select output (error stream)
   statements = statements+1
   %if warnings>0 %start
       write (warnings, 0);   print string (" Warning")
       print symbol ('s') %if warnings#1 
       print string (" issued.");   newline
   %finish
   write(statements, 0);   printstring(" CIF statements output");   newline
   init = false
   select output (current stream)
%end

%external %routine give statistics %alias "ILAP_GIVE_STATISTICS"
   %record (sym def) %name symbol
   %integer i
   print string ("                              Symbol Statistics");   newline
   newline
   print string ("      ".version."   run at ".time." on ".date); newline
   newline
   print string ("      Type                    Name symbol    LLX    LLY    URX    URY   TR Count");   newline
   %for i=0,1,max symbols %cycle
        symbol == symbol table(i)
        %if symbol_number#0 %start
            %if symbol_geometry=0 %and symbol_calls=0 %start
                %if symbol_xu>symbol_xl %start
                    print string ("   External")
                %finish %else %start
                    print string ("      Empty")
                %finish
            %finish %else %if symbol_geometry=0 %and symbol_calls#0 %start
                print string ("Composition")
            %finish %else %if symbol_geometry#0 %and symbol_calls=0 %start
                print string ("  Leaf Cell")
            %finish %else %if symbol_geometry#0 %and symbol_calls#0 %start
                print string (" Mixed Cell")
            %finish
            spaces (31-8-length (symbol_name))
            print string (symbol_name)
            write (|symbol_number|, 6)
            write (symbol_xl, 6)
            write (symbol_yl, 6)
            write (symbol_xu, 6)
            write (symbol_yu, 6)
            write (symbol_trans, 7)
            newline
        %finish
   %repeat
%end

%end %of %file
