%owninteger comp no=0 
!14/05
!
!   Constraint Graph Generation 4
!
%endoflist
%constbyte less= 230,  {jogs
           both= 231,
           greater= 232 


%const %integer last= yes
%const %integer not last= no
%const %integer slide= 1000

%const %byte %integer layers check= 3
%const %integer metal layers= 1
%const %integer poly and diff layers= 0


%owninteger %array new side (poly and diff layers:metal layers,topp:bottom)
%owninteger %array valid port(topp:bottom,poly and diff layers:metal layers)
%owninteger error count= 0


%own %record(NODE LIST) top crosser= 0
%own %record(NODE LIST)%name top crosser list
top crosser list== top crosser

%own %record(NODE LIST) compartment 1= 0,
                        compartment2= 0
%own %record(NODE LIST)%name first compartment,special compartment
 first compartment== compartment 1
 special compartment== compartment2

! rule types
%constinteger connectivity= 2,
              seperations=  3


!++++++++++++++++++++
%routine SCAN LP
!%record(NODE)%name edge== screens(Xdir)_ptr_next y,
!                   node
!%while edge## right edge %cycle
!  node== edge_next x
!  %while node## nil %cycle
!    write(node_x,1);write(node_y,1)
!    %if node_class= device %then printstring("DEV*") %else %c
!    %if node_class= horiz wire %then printstring("HW*") %else %c
!    %if node_class= vert wire %then printstring("VW*") %else %c
!    printstring("UNKNOWN")
!    newline
!    printstring("==>");write(node_path length(xdir),1);write(node_path length(Ydir),2)
!    newline
!    node== node_next x
!   %repeat
!  edge== edge_next y
! %repeat
%end



!+++++++++++++++++++++++++++++++++++++++++++
%routine SCAN2
!%record(NODE LIST)%name comp== First compartment_next,
!                        mem
!%while comp## nil %cycle
!newline
!printstring("comp:");write(comp_lx,3);write(comp_rx,3);newline
!printstring("id:");write(comp_id,2)
!mem== comp_list
!%while mem## nil %cycle
!  write(mem_node_x,3);write(mem_node_y,3)
!  %if mem_node_class= horiz wire %then printstring("HW") %else %c
!  %if mem_node_class= vert wire %then printstring("VW") %else %c
!  %if mem_node== left edge %then printstring("LEFT EDGE") %else %C
!  %IF MEM_node== right edge %then printstring("RIGHT EDGE") %else %c
!  %if mem_node== top edge %then printstring("TOP EDGE") %else %c
!  %if mem_node== bottom edge %then printstring("BOTTOM EDGE") %else %c
!  %IF MEM_node_class=device %then printstring("DEV") %else %c
!  printstring("ERRRRRROR")
! mem== mem_list
!%repeat
!comp== comp_next
!%repeat
%end
!!+++++++++++++++++++++
%routine SCAN3(%record(NODE LIST)%name cc,%integer layers)
!%record(NODE LIST)%name scan== cc_list
!enable reg= any colour
!%if layers= metal layers %then set colour(magenta) %else %c
!set colour(yellow)
!%while scan## nil %cycle
!%if scan_node_class= vert wire %then %c
!  at(scan_node_x,scan_node_y+8) %else %c
!%if scan_node_class= device %then %c
!at (scan_node_x, scan_node_y-8) %else %c
!  at(scan_node_x,scan_node_y)
!  showstring(itos(comp no,comp no))
!scan== scan_list
!%repeat
!comp no=comp no+1
%end
!!_____________________________________________
%routine scan4
!%integer test= no
!%Integer dir,tmp
!%record(ARCC)%name all3
!%record(NODE)%name all== screens(Xdir)_ptr,all2
!
!!________________________________
!%routine rubbish
!     %while all3## nil %cycle
!        printsymbol('x'+dir)
!        printstring("->")
!        printstring("dev:")
!        %if all3_next node_class= horiz wire %then printstring("hw") %else %c
!        %if all3_next node_class= vert wire %then printstring("vw") %else %c
!        printstring("D")
!        printstring("type:")
!        tmp=all3_next node_type
!        %if tmp < 5 %and tmp >= 0 %then printstring(wires(tmp)) %else write(tmp,3)
!        printstring("x:")
!        write(all3_next node_x,3)
!        printstring("y:")
!        write(all3_next node_y,3)
!        printstring("len:")
!        print(all3_length,3,3)
!        newline
!     all3== all3_another arcc
!  %repeat
!%end
!
!!++++++++++++++++++++++
!newline
!%while all## nil %cycle
! all2== all_next x
! %while all2## nil %cycle
!newline
!   printstring("device:")
!   %if all2_class= horiz wire %then printstring("hw") %else %c
!      %if all2_class= vert wire %then %c
!   printstring("vw") %else printstring("D")
!   printstring("type  :")
!   %if all2_type<= 4 %then %c
!   printstring(wires(all2_type)) %else write(all2_type,3)
!   printstring("x: ");write(all2_x,2)
!   printstring("y:") ;write(all2_y,2)
!   %for dir= xdir,1,ydir %cycle
!   printstring("iac");write(all2_in arc count(dir),2)
!   %repeat
!   %for dir= xdir,1,ydir %cycle
!     printstring("cc-");write(all2_cc(dir),2)
!   %repeat
!   printstring("id");write(all2_idd,2)
!newline
!printstring("arcs
!")
!   %for dir= xdir,1,ydir %cycle
!printstring(":")
!     all3== all2_arccs(dir)
!        rubbish
!  %repeat
!printstring("cons
!")
!  %for dir= xdir,1,ydir %cycle
!     all3== all2_cons(dir)
!     rubbish
!  %repeat
!   
!all2== all2_next x
! %repeat
!all== all_next y
!%repeat
!
!printstring("
!LEFT ...")
!%for dir= xdir,1,ydir %cycle
!printstring("iac")
!write(left edge_in arc count(dir),0)
!  all3== left edge_arccs(dir)
!  rubbish
!%repeat
!
!printstring("
!BOTTOM ....")
!%for dir= xdir,1,ydir %cycle
!printstring("iac");write(bottom edge_in arc count(dir),0)
!  All3== bottom edge_arccs(dir)
!  rubbish
!%repeat
!
!printstring("
!RIGHT.... ")
!%for dir= xdir,1,ydir %cycle
!printstring("iac:")
!write(right edge_in arc count(dir),0)
!  all3== right edge_arccs(dir)
!  rubbish
!%repeat
!
!printstring("
!TOP..... ")
!%for dir= xdir,1,ydir %cycle
!printstring("iac:")
!write(top edge_in arc count(dir),0)
!  all3== top edge_arccs(dir)
!  rubbish
!%repeat
!printstring("
!DEC ARCS
!")
!%for tmp=1,1,dec count-1 %cycle
!  printstring("dec next node:");write(decarc(tmp,Xdir)_next node_x,3)
!write(decarc(tmp,Xdir)_next node_y,3)
!  spaces(6);write(decarc(tmp,Y dir)_next node_x,3)
!write(decarc(tmp,Ydir)_next node_y,3)
!  newline
!%repeat
%end   

!!____________________________________________________________________________
%routine OUT(%string(255) s)
gotoxy(2,21)
clear line
printstring(s)
%end

!____________________________________________________________________________
%predicate PARALLEL(%record(NODE)%name wire,%integer dir)
  %if dir= xdir %and wire_class= vert wire %then %TRUE
  %if dir= ydir %and wire_class= horiz wire %then %TRUE
%FALSE
%end

!____________________________________________________________________________
%routine FORCE screen(%integer x,y,colour)
%integer flip screen= screen top
origin x= REGULARISE(x-screen x//2)
origin y= REGULARISE(y-screen y//2)
DRAW SCREEN(flip screen)
RESET SCREEN(flip screen)
    zoom= 7
    DRAW CELL(x-40-origin x,y-40-origin y,0,colour,0,0)
    zoom= 1
%end

!____________________________________________________________________________
%routine ERROR OUT(%string(255) error,
                   %record(NODE)%name n1,n2)
%integer a,
         x= n1_x,
         y= n2_y
%if n1## nil %start 
%if n1_checked= no %or n2_checked= no %start
    error count= error count + 1
    OUT("ERROR > ".error)
    n1_checked= yes
    n2_checked= yes
    FORCE SCREEN(x,y,yellow)
    %SIGNALEVENT(10)
%finish
%finish
%end

%string(255)%fnspec GET INPUT(%string(255) prompt)
 
!_________________________________________________________________________

%routine ADD TO(%record(NODE LIST)%name  compartment, %c
                %record(NODE)%name nodde)
%record(NODE LIST)%name new

%if nodde## nil %start
   new== NEW NODE LIST
   new_node== nodde
   new_list== compartment_list
   compartment_list== new
%finish

%end

!_________________________________________________________________________
%routine DISPOSE MEMBERS(%record(NODE LIST)%name  compartment)
%record(NODE LIST)%name member== compartment_list,
                        remove
%while member## nil %cycle
  remove== member
  member== member_list
  DISPOSE NODE LIST(remove)
%repeat
!compartment_rx= ignore
!compartment_lx= ignore
compartment_list== nil
%end

%routinespec UPDATE CROSSERS(%record(NODE)%name edge,%integer layers)

!________________________________________________________________________
%routine CLEAN COMPARTMENTS
%record(NODE LIST)%name cc== first compartment_next,
                        last
firstcompartment_next== nil
%while cc## nil %cycle
  DISPOSE MEMBERS(cc)
  last== cc
  cc== cc_next
  DISPOSE NODE LIST(last)
%repeat
UPDATE CROSSERS(top edge,ignore)
%end
!________________________________________________________________________
%routine DETERMINE CONTACT(%record(NODE)%name wire1,wire2,nodde)
 %record(NODE)%name polyptr== nil,
                    diffptr== nil
 %if wire1_type= poly %then polyptr== wire1 %else %c
 %if wire2_type= poly %then polyptr== wire2
!**** straight throu contact
 %if wire1_type= diff %then diffptr== wire1 %else %c
 %if wire2_type= diff %then diffptr== wire2
 %if wire1_type= metal %or  wire2_type= metal %start
   %if polyptr## nil %then nodde_type= CPM %else nodde_type= CDM
 %else
   %if diffptr_class= horiz wire %start
       %if nodde_x= diffptr_coord3 %then nodde_type= CPDW %else nodde_type= CPDE
   %else
       %if nodde_y= diffptr_coord3 %then nodde_type= CPDS %else nodde_type= CPDN
   %finish
 %finish
%end
!________________________________________________________________________
%predicate CHECK CONNECT(%record(NODE)%name n1,n2,%integer dir)
! do these objects need to be constrained ? -they may be electrically
!                                                        connected
%record(NODE)%name work== n2
%record(ARCC)%name arc,arc2

           %integerfn TEST(%record(NODE)%name n1)
            %if n1_class= horiz wire %or n1_class= vert wire %then %c
                                     %result= n1_type
            %if n1_type= pull down %and %c
                  n1_class= device %and %c
                   n1_ratio# min gate ratio %c
                                   %then %result= diff
            %if n1_type= cpm %then %result= poly
            %if n1_type= cdm %then %result= diff
           %result= ignore
           %end

! n1= device ;n2= wire
%if n2_class= device %start
    n2== n1
    n1== work
%finish

arc== n1_cons(1-dir)
%while arc## nil %cycle
  arc2==arc_next node_cons(1-dir)
  %while arc2## nil %cycle
   %if arc2_next node== n2 %start
    %if test(n1)# ignore %and test(n1)=test(n2) %then %TRUE
   %finish
    %if arc2_next node_type= join %start
        %if arc2_next node_cons(dir)_next node== n2 %start
           %if test(n1)# ignore %and test(n1)=test(n2) %Then %TRUE
        %finish
    %finish
   arc2== arc2_another arcc
  %repeat
arc== arc_another arcc
%repeat
  
%FALSE
%end

!________________________________________________________________________
%real %function TECH TABLE(%record(NODE)%name thing1,thing2,
                           %integer rule type,dir,id,gb)
%real res=0
%record(NODE)%name tempp
%integer index1= thing1_type,
         index2= thing2_type,
         temp

%integerfn FORCE INDEX(%record(NODE)%name thing,
                       %integer index)
      %if thing_class= device %start
        %if PUE <= thing_type <= PUN %then index= pull upp
        %if CPDE <= thing_type <= CPDS %then index= buried
        %if thing_type= Pull down %or thing_type= Pass tran %start
            %if thing_ratio# min gate ratio %then index= fat gate %c
                                            %else index= gate
        %finish
      %finish
%result= index
%end

%realfn DYNAMIC WIDTH(%record(NODE)%name thing,other)
%record(NODE)%name polyy
%if thing_class= device %start
! generate the edge to centre distance in the dir of the pull up

   %if thing_type= PUN %or thing_type= PUE %start

      %if (dir= xdir %and thing_type= PUE) %or %c
          (dir= ydir %and thing_type= PUN) %then %c
           %result= min width(diff)/2+min extension %c
               %else %c
           %result= (thing_ratio*min width(diff)+ min width(contact)/2)/2

     %finishelseif CPDE <= thing_type <= CPDS %start

       %if (other_y > thing_y %and dir= Xdir %and thing_type= CPDN) %or %c
         (  other_y < thing_y %and dir= Xdir %and thing_type= CPDS) %or %c
         (  other_x < thing_x %and dir= Ydir %and thing_type= CPDW) %or %c
         (  other_x > thing_x %and dir= Ydir %And thing_type= CPDE) %c
            %then %result= min buried long
           %result= min buried short

     %finishelseif (thing_type= pull down %or thing_type= pass tran) %start

      polyy= FIND WIRE(thing,poly)
      %if (other_y >= thing_y %and thing_idd= topp) %or %c
          (other_y <= thing_y %and thing_idd= bottom ) %or %c
          (other_x <= thing_x %and thing_idd= left ) %or %c
          (other_x >= thing_x %and thing_idd= right ) %start
           %if PUE <= other_type <= PUN %start
                      %result= min width(poly)/2 + min extension
           %finish
           %if parallel(polyy,dir) %then %c
                     %result= thing_ratio*min width(diff)/2 + min extension
           %if thing_ratio# min gate ratio %then %c
                     %result= min width(poly)/2 + min extension
           %result= min width(poly)/2
      %else
         %if thing_ratio= min gate ratio %then %result= 0
         %if parallel(polyy,dir) %then %c
                     %result= thing_ratio*min width(diff)/2 %else %c
                     %result= min width(poly)/2 + min extension
!        %result= -(other_width-min width(poly))/2
      %finish

     %finishelseif CPM <= thing_type <= CDM %start
           %result= min width(contact)/2
     %finish
%finish
%result= thing_width/2
%end




%if thing1== left edge %or thing1== bottom edge %or %c
    thing2== top edge %or  thing2== right edge %then %c
     %result= max min seperation+%c
        dynamic width(thing1,thing2)+dynamic width(thing2,thing1)


%if rule type= connectivity %start
        %if thing2_class= device  %start
            tempp== thing1
            thing1== thing2
            thing2== tempp
        %finish
! thing1= device
! thing2= wire

        %if id= slide %then %result= 0

        %if thing1_type= cpm %or thing1_type= cdm %start
           %if THRU WIRE(thing2,thing1_x,thing1_y) %then %c
               %result=-(|min width(contact)+thing2_width|)/2
           %result=-(|min width(contact)-thing2_width|)/2
        %finish

        %if thing1_type= PUN %or thing1_type= PUE  %start
         %if thing2_type= poly %start
              %result= -(|(thing1_ratio*min width(diff)+min width(contact)/2- %c
                        thing2_width)/2|)
           %else %if thing2_type= diff 
              %result= -(|min width(diff)-thing2_width|)/2
           %finish
        %finish

        %if thing1_type= pass tran %or thing1_type= pull down %start
           %if thing2_type= poly %start
               %result= 0
           %else 
               %result= -(thing1_ratio*min width(diff)-thing2_width)/2
           %finish
        %finish

        %result= 0
%finish 

index1= FORCE INDEX(thing1,index1)
index2= FORCE INDEX(thing2,index2)


%if index1> index2 %start
    temp= index 1
    index1= index2
    index2= temp
%finish

   %if rule type# connectivity %and %c
      CHECK CONNECT(thing1,thing2,dir) %start
           res= -min extension//2
           %if cpm <= thing1_type <= cdm %or cpm <= thing2_type <= cdm %c
             %then res= -min width(contact)//2
   %else
      res= min seperations(index1,index2)
   %finish
   res= res+ DYNAMIC WIDTH(thing1,thing2)
   %result= res+ DYNAMIC WIDTH(thing2,thing1)
%end


!________________________________________________________________________
%record(NODE)%map CONTACT SEPERATION(%record(NODE)%name nodde, %c
                             %integer dir,forward)
%record(NODE)%name polyy== FIND WIRE(nodde,poly),
                   difff== FIND WIRE(nodde,diff),
                   res== nodde


! not done straight thru yet !
      %if nodde_type= CPDE %or nodde_type= CPDW %start

         %if dir= ydir %start
          %if (nodde_type= CPDW %and forward= no) %or %c
              (nodde_type= CPDE %and forward= yes) %or %c
               THRU WIRE(difff,nodde_x,nodde_y) %c
                %then res== polyy  %c
                %else res== difff
         %else

          %if THRU WIRE(polyy,nodde_x,nodde_y) %or %c
              (nodde_y= polyy_coord3 %and forward= no) %or %c
              (nodde_y= polyy_y %and forward= yes) %c
               %then res== difff %c
                %else res== polyy
          
         %finish

      %finish %else %if nodde_type= CPDN %or nodde_type= CPDS %start
 
         %if dir= xdir %start
          %if (nodde_type= CPDS %and forward= no) %or %c
              (nodde_type= CPDN %and forward= yes) %or %c
               THRU WIRE(difff,nodde_x,nodde_y) %c
                 %then res== polyy %c
                   %else res== difff
         %else

          %if THRU WIRE(polyy,nodde_x,nodde_y) %or %c
              (nodde_x= polyy_coord3 %and forward= no) %or %c
              (nodde_x= polyy_x %and forward= yes) %c
                 %then res== difff %c
                   %else res== polyy
         %finish

      %finish
%result== res
!***  could force the index of the edge 
!
! if there are no thru wires then only the head on projections are of interest
! (and there fore check not arriving from back). The sides of these 
! projections have already been included in the same compartment. where a
! thru wire exists. the remaining projection is included from both the side and
! head on, the thru wire not allowing the side view to have been included in
! the same compartment as the projection. The natural extention is both
! thru wires where neither head on is of interest, all sides have been
! included.
%end

!_________________________________________________________________________
%routine CLEAN DECS
%integer i
dec arc(i,Xdir)== nil %and dec arc(i,Ydir)== nil %for i=1,1, dec count
%end
!_________________________________________________________________________
%routine FIND DECISIONS(%record(NODE)%name where,what, %c
                        %record(ARCC)%name arc)
%record(NODE)%name where join,
   debug1== nil,debug2== nil,
                   what  join

      %record(NODE)%map   FIND JOIN(%record(NODE)%name n,near)
      %record(ARCC)%name arc== n_cons(Ydir)
      %record(NODE)%name res
      %integer x= near_x,
               y= near_y,
x1,x2,y1,y2,
               dir

         %predicate IN LINE(%integer i1,i2,i3,i4)
         %constinteger infinity= not set
         %if i2= i4 %then i3= infinity %else i2= -infinity
           %if %not(i2 <= i1 <= i3) %then %TRUE
         %FALSE
         %end

       %if n_class= vert wire %then dir= Ydir %else dir= Xdir
       arc== n_cons(dir)

       %while arc## nil %cycle
         %if (arc_next node_class= notional %and %c
                                    arc_next node_type=  join) %start

          %if %not THRU WIRE(n,arc_next node_x,arc_next node_y) %start
            res== arc_next node_cons(1-dir)_next node 
            %if %not THRU WIRE(res,arc_next node_x,arc_next node_y) %start
%if n= where %then debug2== arc_next node %else debug1== arc_next node
                 %if IN LINE(x,res_x,res_coord3,arc_next node_x) %and  %c
                     IN LINE(y,n_y,n_coord3,arc_next node_y) %then %result== res
            %finish
          %finish
         %finish
        arc== arc_another arcc
       %repeat
      %result== nil
      %end


           %routine EXAMINE FORMS(%record(NODE)%name n1,
                                  %record(NODE)%name n2)
           %record(ARCC)%name checker== nil
            %if n2## nil %and n1## nil %start
              checker== n1_arccs(Xdir) 
                %while checker## nil %cycle
                   %if checker_next node==  n2 %and %c
                       checker_length#0 %and arc_length# 0 %start
                      dec arc(dec count,Ydir)== arc
                      dec arc(dec count,Xdir)== checker
                      arc_dec= yes
                      checker_dec= yes
                      dec count= dec count + 1
enable reg= any colour
!line(x1,y1,x2,y2)
                      %return
                   %finish
                   checker== checker_another arcc
                %repeat
              %finish
           %end

what join==  FIND JOIN(what,where)
where join== FIND JOIN(where,what)
set colour(cyan)
x1= where_x;y1=where_y;x2=what_x;y2=what_y
EXAMINE FORMS(where,     what)
x1=what_x;y1=what_y;x2=where_x;y2= where_y
EXAMINE FORMS(what,     where)
set colour(white)
x2=debug2_x %and y2= debug2_y %if where join## nil
EXAMINE FORMS(what,where join)
x1= debug1_x %and y1= debug1_y %if what join## nil
EXAMINE FORMS(what join,where join)
x2= where_x;y2= where_y
EXAMINE FORMS(what join,where)
x1= x2;y1= y2;x2= debug1_x %and y2= debug1_y %if what join## nil
EXAMINE FORMS(where,what join)
x1= debug2_x %and y1= debug2_y %if where join## nil 
x2= what_x;y2= what_y
EXAMINE FORMS(where join,what)
x2= what join_x;y2= what join_Y
EXAMINE FORMS(where join,what join)

%end


!_________________________________________________________________________
%routine ADD ARC(%record(NODE)%name where,what,
                 %integer dir,rule type,
                                include,id)
%record(NODE)%name cwhere== where,
                   cwhat==  what
%integer replaced= no,
         gb,
         width,
         temp
%record(ARCC)%name arc,
                   checker== where_arccs(dir)
%predicate GATE BACK(%record(NODE)%name n1,n2)
%if n1_class= device %and (n1_type= pull down %or n1_type= pass tran) %start
  %if (dir= Ydir %and %c
      ((n1_idd= left %and n2_x> n1_x) %or (n1_idd= right %and n2_x< n1_x))) %or  %c
      (dir= Xdir %and %c
      ((n1_idd= topp %and n2_y< n1_y) %or (n1_idd= bottom %And n2_y> n1_y))) %start
      %if %not (n2_class= device %and CPDE <= n2_type <= CPDS) %then %TRUE
  %finish
%finish
%FALSE
%end
 

! if the implant regions of a buried contact are not critical then
! use the wires that make the contact for seperation calculation
 %if rule type# connectivity %and %c
   (what_class# device %or where_class# device %or  %c
      CPM <= what_type <= CDM %or CPM <= where_type <= CDM) %start
            cwhere== CONTACT SEPERATION(where,dir,yes)
            cwhat==  CONTACT SEPERATION(what,dir,no)
 %finish


%if GATE BACK(what,where) %or GATE BACK(where,what) %then gb= yes %c
                                                    %else gb= no
    temp= intpt(TECH TABLE(cwhere,cwhat,rule type,dir,id,gb))

 %if where## nil %and what## nil %start
     
    %if rule type # connectivity %start
     %while checker## nil %and replaced= no %cycle
       %if checker_next node== what %start
          %if  |checker_length| < |temp| %then checker_length= temp
          replaced= yes
       %finish
       checker== checker_another arcc
     %repeat
    %finish
    
! if the type has not been changed from a buried => the other is
    %if replaced= no %start
     arc== NEW ARCC
     arc_length= temp
     arc_include= include
     arc_next node== what
     %if rule type= connectivity %start
!       no. of connectivity arcs leaving this node
        where_cc(dir)= where_cc(dir) + 1  %if include= yes
        arc_another arcc== where_cons(dir)
        where_cons(dir)==  arc
     %else
!       no. of constraint arcs entering this node
        what_in arc count(dir)= what_in arc count(dir) + 1
        arc_another arcc== where_arccs(dir)
        where_Arccs(dir)== arc
       %if dir= ydir %then FIND DECISIONS(where,what,arc) 
     %finish

    %finish

  %finish

%end
!________________________________________________________________________

%routine FIND DEVICE WIRES(%record(NODE)%name nodde)
%record(NODE)%name wire1== nil,
                   wire2== nil,
                   difff,
                   dump,
                   wire
%integer count,dir,
         type= nodde_type,
         to slide= ignore,
         sliding= no,
         poly count= 0,
         diff count= 0
%string(255) s
%record(NODE)%name %array wires(1:4)
wires(count)== nil %for count=1,1,4
count= 1

   %routine WIRE layers
    %if wire1== nil %then wire1== wire %else %c
    %if wire2== nil %and wire_type# wire1_type %then wire2== wire
   %end


! straight thru contact !

%if nodde## nil %and %c
               nodde_cc(xdir)= 0 %and nodde_cc(ydir)= 0 %start
%for dir= xdir,1,ydir %cycle
wire== connect(find edge(nodde_x,nodde_y,dir),dir)
  %while wire## nil %cycle      
   %if wire_class= horiz wire %or wire_class= vert wire %start

       %if dir= ydir %and wire_class= horiz wire %And %c
                       wire_x <= nodde_x <= wire_coord3 %start
         WIRE layers
         wires(count)== wire
         count= count+1
       %finish %else %c
       %if  dir= Xdir %And wire_class= vert wire %and %c
                       wire_y <= nodde_y <= wire_coord3 %start
         WIRE layers
         wires(count)== wire
         count= count+1
       %finish

!       %if nodde_type= pull up %start
!           %for i= 1,1,count %cycle
!              %if wires(i)_class# wire_class %and %c
!                 wire_type= diff %and wires(i)_type= diff %and %c
!                (ON WIRE(wires(i),wire_x,wire_y) %or %c
!                (wire_class= horiz wire %and ON WIRE(wires(i),wire_coord3,wire_y)) %or %c
!                (wire_class= vert wire %and ON WIRE(wires(i),wire_x,wire_coord3))) %c
!                %then sliding= i
!           %repeat
!       %finish

   %finish
   wire== CONNECT(wire,dir)
  %repeat
%repeat

%if type= contact %then  DETERMINE CONTACT(wire1,wire2,nodde)

! must generate connectivity constraints 
   
 count=1 
 %while count<= 4 %and wires(count)## nil %cycle
   %if type= pull up %start
       %if (wires(count)_type= diff %and %c
            wires(count)_class= horiz wire) %or %c
           (wires(count)_type= poly %and %c
            wires(count)_class= vert wire) %then %c
                        nodde_type= PUE %and dir= xdir %else %c
                        nodde_type= PUN %and dir= ydir
        %if wires(count)_type= poly %then dir= 1-dir
   %else
!     opposite dir to usual
     %if wires(count)_class= horiz wire %then dir= Xdir %else dir= Ydir
   %finish

!    %if count= sliding %then to slide= slide %else %c
!      to slide= no %and %c
      ADD ARC(nodde,wires(count),dir,connectivity,yes,ignore)
    ADD ARC(wires(count),nodde,dir,connectivity,yes,to slide)
    %if wires(count)_type= diff %then diffcount= diffcount+1
    %if wires(count)_type= poly %then polycount= polycount+1
    
  count= count+1
 %repeat


%if type= pull down %or type= pass tran %start
  %if diffcount# 1 %or poly count# 1 %start
     %if type= pull down %then s= " PULL DOWN:" %else %c
     %if type= pass tran %then s= " PASS TRANS:"
     ERROR OUT(s." illegal connections",nodde,nodde)
  %else
  %finish
!   %if type= pull down %start
!        difff== FIND WIRE(nodde,diff)
!        difff_width= nodde_ratio* min width(diff)
!  %finish
%finish %else %c
%c
%if PUE <= type <= PUN  %andnot diffcount # 1  %start
    ERROR OUT("INCORRECT # OF DIFF CONNECTIONS TO PULLUP ",nodde,nodde)
%finish %else %c
%c
%if CPDE <= nodde_type <= CPDS %or CPM <= nodde_type <= CDM %start
    %if wire1== nil %or wire2== nil %then %c
        ERROR OUT("CONTACT: too few connections",nodde,nodde)
    %if CPDE <= nodde_type <= CPDS %start
        %if wire1_width# min width(wire1_type) %or %c
            wire2_width# min width(wire2_type) %then %c
        ERROR OUT("INCORRECT WIDTH WIRES ENTERING BURIED CONTACT",nodde,nodde)
    %finish
%finish 
%finish
%end

!________________________________________________________________________
%record(NODE)%map  SPLITTER(%record(NODE)%name start,%integer any)
! nb if used to find a device on a border etc then of correct type
!    as lying on the correct wire
%integer before
 %if start## nil %start
   before= start_y
   start== CONNECT(start,Xdir)
   %while start## nil %and start_y <= before %cycle 
     %if start_class= device %or any= yes %then %result== start
      start== CONNECT(start,Xdir)
   %repeat
 %finish
%result== error
%end

!_________________________________________________________________________
%routine NAME PORTS(%integer limited)
%string(255) s
%record(NODELIST)%name list
%if compiled= no %start
    OUT(" PLease Compile first")
    %return
%finish
OUT("Return to retain old name (if one exists !) ")
%for i= topp,1,bottom %cycle
     list== PORT LIST(i)_next
     %while list## nil %cycle
      %if port name(list_rx)="" %or limited= no %start
         FORCE SCREEN(port pos(list_rx,Xdir),port pos(list_rx,Ydir),cyan)
         s=  GET INPUT("New Port Name")
         port name(list_rx)= s %if s# ""
      %finish
      list== list_next
     %repeat
%repeat
%end
!_________________________________________________________________________
%routine ADD PORT (%integer side,
                   %record(NODE)%name port,
                   %string(255) name)
%constbyte check= 10
%record(NODELIST)%name list== PORT LIST(side)_next,
                       new
! currently not being disposed !
%integer dir
%string(255) s

%while list## nil %cycle
 %if list_node== port %and side+check= list_lx %then %return
 list== list_next
%repeat

%if side= topp %or side= bottom %then dir= Xdir %else dir= Ydir

  %if side= topp %start
    port pos(port count,Ydir)= port_coord3 
    port pos(port count,Xdir)= port_x
  %else %if side= right
    port pos(port count,Ydir)= port_y
    port pos(port count,Xdir)= port_coord3
  %else
    port pos(port count,Ydir)= port_y
    port pos(port count,Xdir)= port_x
  %finish

list== PORT LIST(side)
%while list_next## nil %and ((dir= Xdir %and list_next_node_x < port_x) %or %c
                       (dir= Ydir %and list_next_node_y < port_y)) %cycle
   list== list_next
%repeat
new== NEW NODE LIST
new_next== list_next
list_next== new
new_node== port
new_rx= port count
new_lx= check+side
port name(port count)= name
port count= port count +1
%end

!_________________________________________________________________________
%integerfn  ADD NOTIONAL(%record(NODE)%name node1,node2,
                                %integer type)
! node1 is vw
%record(ARCC)%name arc== node1_cons(ydir)
%record(NODE)%name ptr,
                   temp
%integer res= yes,
         side

  %integerfn find(%record(NODE)%name n)
    %if n== right edge %start
        %result= right
    %else %if n== left edge  
        %result= left
    %else %if n== top edge 
        %result= topp
    %else %if n== bottom edge
        %result= bottom
    %finish
   %result= ignore
  %end

  %integerfn adjust(%record(NODE)%name n,%integer dir)
  %integer f= find(n)
    %if f# ignore %start
        %result= port side(f)
    %else %if dir= Xdir
        %result= n_x
    %finish
   %result= n_y
  %end


     %while arc## nil %cycle
       temp==  arc_next node_cons(Xdir)_next node
       %result= no %if temp== node2
       arc== arc_another arcc
     %repeat


ptr== NEW NODE
ptr_class= notional
ptr_type=  type
ptr_x= adjust(node1,xdir) 
ptr_y= adjust(node2,ydir)
res= INSERT NODE(ptr)

%if res= yes %start
  ADD ARC(ptr,node1,ydir,connectivity,no,ignore)
  ADD ARC(ptr,node2,xdir,connectivity,no,ignore)
  ADD ARC(node1,ptr,ydir,connectivity,no,ignore) %if node1_type# edges
  ADD ARC(node2,ptr,xdir,connectivity,no,ignore) %if node2_type# edges

  %if type= port %start
   side= find(node1)
   %if side# ignore %then ptr_side=  side %else ptr_side= find(node2)
   ptr_idd= port count
  %finish

%else
  DISPOSE NODE(ptr)
%finish

%result= res
%end

!_____________________________________________________________________________
%routine FIND PORTS(%record(NODE)%name n1)
%record(ARCC)%name arc
%integer dump

%predicate NEW(%integer coord,dir)
         arc== n1_cons(dir)
         %while arc## nil %cycle
           %if arc_next node_type= port %start
               %if (dir= Xdir %and coord= arc_next node_x) %or %c
                   (dir= Ydir %and coord= arc_next node_y) %then %FALSE
           %finish
           arc== arc_another arcc
         %repeat
%TRUE
%end

       %if  n1_class= horiz wire %start
         %if n1_coord3= port side(right) %and NEW(n1_coord3,Xdir) %start
             dump= ADD NOTIONAL(right edge,n1,port)
             %if dump= yes %then ADD PORT(right,n1,"")
         %else %if n1_x= portside(left) %and NEW(n1_x,Xdir)
             dump= ADD NOTIONAL(left edge,n1,port)
             %if dump= yes %then ADD PORT(left,n1,"")
         %finish
       %finish %else %if n1_class= vert wire %start
         %if n1_coord3= port side(topp) %and NEW(n1_coord3,Ydir) %start
             dump= ADD NOTIONAL(n1,top edge,port)
             %if dump= yes %then ADD PORT(topp,n1,"")
         %else %if  n1_y= port side(bottom) %and NEW(n1_y,Ydir)
             dump= ADD NOTIONAL(n1,bottom edge,port)
              %if dump= yes %then ADD PORT(bottom,n1,"")
         %finish
       %finish
%end


!_______________________________________________________________________
%routine TEST PAIRS(%record(NODE)%name n1,n2)
%record(NODE)%name dump
%integer valid= no

 %if n1_class= vert wire %or  n1_class= horiz wire %start

         %if (n2_class= vert wire %or n2_class= horiz wire)  %and %c
              n2_class# n1_class %start
                   %if n1_class= horiz wire %start
                    %if n1_x <= n2_x <= n1_coord3 %and %c
                      ( n2_Y= n1_y %or  n2_coord3= n1_Y) %start
                         valid= ADD NOTIONAL(n2,n1,join)
                         %if n2_type# n1_type %and valid= yes %then  %c
                            ERROR OUT("DEVICE or CONTACT MISSING",n2,n1)
                       %finish
                   %else
                       %if n1_y <= n2_y <= n1_coord3 %and %c
                       (n2_x= n1_x %or n2_coord3= n1_x) %start
                         valid= ADD NOTIONAL(n1,n2,join)
                         %if n2_type# n1_type %and valid= yes %then %c
                            ERROR OUT("DEVICE or CONTACT MISSING",n1,n2)
                       %finish
                   %finish

         %finish
 %finish
%end

!______________________________________________________________________
%routine FIND CONNECTIVITY(%record(NODELIST)%name compartment)
%integer dir,
         found source= no
%record(NODELIST)%name this member,
                       other member
%record(ARCC)%name arc
%record(NODE)%name found1,
                   join1,
                   restrict1,
                   restrict2,
                   polyy,
                   ptr,
                   tmn,
                   omn

%record(NODE)%map GATE TEST(%record(NODE)%name n1,n2)
! identifies that a gate has a projection into this compartment
%record(NODE)%name polyy== FIND WIRE(n1,poly)
  %if n1_class= device %and  %c
       (n1_type= pull down %or n1_type= pass tran)  %c
       %and polyy== n2 %then %result== polyy
%result== nil
%end

  this member== compartment_list
  %while this member## nil %cycle
    found source= no
    tmn== this member_node
    FIND PORTS(tmn)
    other member== compartment_list
       %while other member## nil %cycle
          omn== other member_node
          %if omn## tmn %start
             TEST PAIRS(tmn,omn)
             %if GATE TEST(tmn,omn)## nil %then found source= yes
          %finish
        other member== other member_list
       %repeat
       %if found source= no %and tmn_class= device %and %c
           (tmn_type= pass tran %or tmn_type= pull down) %start
            polyy== FIND WIRE(tmn,poly)
            %if polyy_class= horiz wire %start
                %if polyy_x= tmn_x %then tmn_idd= left %else %c
                %if polyy_coord3= tmn_x %then tmn_idd= right %else %c
                                              tmn_idd= 255
            %else 
                %if polyy_y= tmn_y %then tmn_idd= bottom %else %c
                %if polyy_coord3= tmn_y %then tmn_idd= topp %else %c
                                              tmn_idd= 255
            %finish
       %finish
  this member== this member_list
  %repeat


! find jogs

this member== compartment_list
%while this member## nil %cycle
  tmn== this member_node
  dir= not set
  found1== nil

  %if tmn_class= horiz wire %then %c
      dir= Xdir %c
  %else %if tmn_class= vert wire %then %c
      dir= Ydir

  %if dir# not set  %start
      arc== tmn_cons(dir)
      %while arc## nil %cycle
       ptr== arc_next node
       %if  (ptr_class= notional %and ptr_type= join) %or %c
             ptr_class= device  %start
           join1== ptr_cons(1-dir)_next node
           %if %not THRU WIRE(join1,ptr_x,ptr_y) %and %c
                tmn_type//layers check= join1_type//layers check %start

                 %if join1_class= vert wire %and tmn_coord3 > join1_x %start
                       %if join1_Y=  tmn_y %start
                          %if join1_idd= greater %start
                              join1_idd= both
                          %else
                              join1_idd=  less
                          %finish
                       %else
                          %if join1_idd= less %start
                              join1_idd= both
                          %else
                              join1_idd=  greater 
                          %finish
                       %finish
                 %else %if join1_class= horiz wire %and tmn_coord3 > join1_y 
                       %if join1_x= tmn_x %start
                          %if join1_idd= greater %start
                              join1_idd= both 
                          %else
                              join1_idd=  less
                          %finish
                       %else
                          %if join1_idd= less %start
                              join1_idd= both 
                          %else 
                              join1_idd=  greater
                          %finish
                       %finish

                 %finish

          %finish
       %finish
       arc== arc_another arcc
      %repeat
  %finish
  this member== this member_list
%repeat
%end

!__________________________________________________________________________
%routine GENERATE CONSTRAINTS(%record(NODE LIST)%name compartment,
                              %integer layers)
%record(NODE LIST)%name this member,
                        other member
%record(NODE)%name omn,
                   tmn
%integer dir

  %predicate EXTRACT(%record(NODE)%name tmn,%integer direct,dir)
  %record(NODE)%name test== tmn,
                     hold== tmn_cons(dir)_next node
    %if tmn_type= edges %then %TRUE
! *many wires if split for device
    %if tmn_class= device %and ON WIRE(hold,tmn_x,tmn_y) %then test== hold
    %if  test_idd# direct %and test_idd# both %then %TRUE
    %FALSE
  %end

  %predicate SMALL(%integer  dir,%record(NODE)%name tmn,omn)
  %record(NODE)%name test== tmn
  %if tmn_class= device %then test== tmn_cons(dir)_next node
  %if dir= Xdir %start
     %if (omn_class= horiz wire %and omn_coord3<= test_x) %or %c
         (omn_class= device %and omn_x < test_x) %then %FALSE
  %else
    %if (omn_class= vert wire %and omn_coord3 <= test_y) %or %c
        (omn_class= device %and omn_y < test_y) %then %FALSE
  %finish
  %TRUE
  %end

  %predicate GREAT(%integer dir,%record(NODE)%name tmn,omn)
  %record(NODE)%name test== tmn
  %if tmn_class= device %then test== tmn_cons(dir)_next node
    %if dir= Xdir %start
        %if (omn_class= horiz wire %and omn_x>= test_coord3) %or %c
            (omn_class= device %and omn_x > test_coord3) %then %FALSE
    %else
        %if (omn_class= vert wire %and omn_y>= test_coord3) %or %c
            (omn_class= device %and omn_y > test_coord3) %then %FALSE
    %finish
    %TRUE
  %end

FIND CONNECTIVITY(compartment)

%for dir= xdir,1,ydir %cycle
   this member== compartment_list
   %while this member## nil %cycle
 
      tmn== this member_node
!      %if (tmn_class= vert wire %and %c
!          (tmn_cons(Ydir)== nil %or tmn_cons(Ydir)_another arcc== nil))%or  %C
!          (tmn_class= horiz wire %and %c
!          (tmn_cons(xdir)== nil %or tmn_cons(Xdir)_another arcc== nil)) %then %c
! ERROR OUT("WIRE IS NOT JOINED AT END + NOT A PORT !",tmn,tmn)

      %if tmn## right edge %and tmn## top edge %and tmn_class# notional %start
        other member== compartment_list
        %while other member## nil %cycle
            omn== other member_node
            %if omn## left edge %And %c
                omn## bottom  edge %and %c
                omn## tmn %and %c
                omn_class# notional %And %c
             ((dir= ydir %and tmn_class# horiz wire %c
                         %and (extract(tmn,less,dir) %or SMALL(dir,tmn,omn)) %c
                         %and (extract(tmn,greater,dir) %or GREAT(dir,tmn,omn)) %c
                         %and tmn## bottom edge %c
                         %and omn## top edge %and %c
                          omn_class# horiz wire) %or %c
              (dir= xdir %and tmn_class# vert wire %c
                         %and (extract(tmn,less,dir) %or SMALL(dir,tmn,omn)) %c
                         %and (extract(tmn,greater,dir) %or GREAT(dir,tmn,omn)) %c
                         %and tmn## left edge %c
                         %and omn## right edge %and %c
                          omn_class# vert wire)) %start

             %if layers# metal layers %or %c
               %not(CPM <= omn_type <= CDM) %or %not(CPM <= tmn_type <= CDM) %or %c
                    tmn_arccs(dir)== nil %start
!            stops unneccessary contact decisions

               %if  (dir= ydir %And omn_x > tmn_x) %c
                %or (dir= xdir %and omn_y > tmn_y) %c
                %then  ADD ARC(tmn,omn,dir,seperations,yes, %c
                              compartment_id)

             %finish
            %finish
            other member== other member_list
        %repeat
      %finish
     this member== this member_list
   %repeat
%repeat
%end

!_________________________________________________________________________
%record(NODE)%map FIND LAYER(%record(NODE)%name n,%integer layers)
%constinteger hw= horiz wire,
              vw= vert wire
%predicate DEV IN LAYER(%record(NODE)%name n)
%if n_class= device %start
   %if  layers= metal layers %start
      %if  n_type= CPM %or n_type= CDM  %then %TRUE
      %FALSE
   %finish
   %TRUE
%finish
%FALSE
%end
!ignores notionals
 %while n## nil %cycle
    %if ((n_class= hw %or n_class= vw) %and n_type//layers check= layers) %or %c
      DEV IN LAYER(n) %then %exit
    n== n_next y
 %repeat
%result== n
%end

!________________________________________________________________________
! nb that the gate wires associated with a pull down or pass trans will always
! be found before the device: This means that these devices are only included
! in the compartments that contain their short extensions!
%routine ADD MEMBER(%record(NODE LIST)%name compartment, %c
                    %record(NODE)%name new device, %c
                    %integer layers,b1,b2)
%record(NODE LIST)%name member== compartment_list
%integer type= new device_type

%if new device_class# notional %start

    %while member## nil %cycle
      %if member_node== new device %then %exit
      member== member_list
    %repeat
    
    
   %if member== nil %start
      %if (((b1 <= new device_x <=b2) %or %c
          new device_class= horiz wire) %and %c
            new device== FIND LAYER(new device,layers)) %or layers= edges %then %c
                  ADD TO(compartment,new device) 
   %finish
%finish
%end

!_________________________________________________________________________
%routine UPDATE COMPARTMENT(%record(NODE LIST)%name compartment, %c
                           %record(NODE)%name nodde, %c
                           %integer layers)
%if nodde_class= horiz wire %and nodde_type//layers check= layers %start

 %if nodde_coord3>= compartment_rx %and %c
     nodde_x <      compartment_rx %then compartment_rx= nodde_x
 %if nodde_x<=      compartment_lx %and %c
     nodde_coord 3> compartment_lx %then compartment_lx= nodde_coord 3

%finish
%end

!_________________________________________________________________________
%record(NODE LIST)%map NEXT COMPARTMENT(%record(NODE LIST)%name %c
                                         CC)
%if CC## nil %then %c
    CC== CC_next
%while CC## nil %and %c
                   CC_list== nil  %cycle
  CC== CC_next
%repeat
%result== CC
%end

!_________________________________________________________________________
%record(NODE LIST)%map NEXT NEW COMPARTMENT(%record(NODE LIST)%name %c
                                             CC, %c
                                            %integer x)
%ownbyte id= 1
%record(NODE LIST)%name new,%c
                        res== NEXT COMPARTMENT(CC)
%while res## nil %and res_rx<x %cycle
  CC== res
  res== NEXT COMPARTMENT(CC)
%repeat
%if res## nil %and res_lx<= x %start
    %result== res
%else 
    new== NEW NODE LIST
    new_next== CC_next
    CC_next== new
    CC== new
    CC_lx= x
    CC_rx= not set
    CC_list== nil
    CC_id= id
    id= id+1
%finish
%result== CC
%end

!_________________________________________________________________________

%routine MERGE COMPARTMENTS(%record(NODE LIST)%name CC, %c
                                                  next)
 %record(NODE LIST)%name add== CC_list
 %while add_list## nil %cycle
  add== add_list
 %repeat
 add_list== next_list
 CC_rx= next_rx
 next_lx= ignore
 next_rx= ignore
 next_list== nil
%end



!_________________________________________________________________________
%routine UPDATE CROSSERS(%record(NODE)%name edge,%integer layers)
%integer y= edge_y
%record(NODE lIST)%name remove,
                        start== top crosser list

%if edge== top edge %and layers# ignore %then y= new side(layers,topp)

%while start_next## nil %cycle
start== start_next
%repeat


start== top crosser list
%while start_next## nil %cycle

  %if  (edge## top edge %and %c
        start_next_node_coord3 <= y) %or %c
       (edge== top edge %And %c
        start_next_node_coord3 < y)  %start
            remove== start_next
            start_next== remove_next
            DISPOSE NODE LIST(remove)
  %else
     start== start_next
  %finish

%repeat
%end


!_________________________________________________________________________
%routine  ADD TO CROSSERS LIST(%record(NODE)%name node,%integer layers)
%record(NODE LIST)%name cross== top crosser list,
                        new== NEW NODE LIST

%if node_type//layers check= layers %start
      %while cross_next## nil %and %c
             cross_next_node_x < node_x %cycle
        cross== cross_next
      %repeat
      new_node== node
      new_next== cross_next
      cross_next== new
%finish
%end

!________________________________________________________________________

%routine  SEE IF COMPARTMENT CLOSED(%integer layers,
                             %record(NODE LIST)%name CC,
                             %record(NODE)%name nodde) 
         %if CC_rx <= CC_lx %start
               GENERATE CONSTRAINTS(CC,layers)
scan2
scan3(CC,layers)
               DISPOSE MEMBERS(CC)
         %finish
%end


!_________________________________________________________________________

%predicate NO OTHER WIRE AT (%integer x,
                             %record(NODE)%name start)
%record(NODELIST)%name vert crosser== top crosser list_next
 %while vert crosser## nil %And vert crosser_node_x <= x %cycle
    %if vert crosser_node_x = x %then %FALSE
    vert crosser== vert crosser_next
 %repeat
 start== start_next Y
 %while start## nil %cycle
  %if (start_class= horiz wire %or start_class= vert wire) %and %c
       start_x= x %then %FALSE
  start== start_next y
 %repeat
 %TRUE
%end

!_________________________________________________________________________

%routine CHECK SPECIAL FORMS(%record(NODE LIST)%name CC, %c
                             %record(NODE)%name horiz crosser)

%record(NODE LIST)%name nextt== NEXT COMPARTMENT(CC)
%if horiz crosser## nil %start
! situ 1
           %if nextt## nil %and %c
               horiz crosser_coord3= nextt_lx %And %c
                NO OTHER WIRE AT(horiz crosser_coord3,horiz crosser) %then %c
                 MERGE COMPARTMENTS(CC,nextt)
! situ 2
           %if horiz crosser_x= CC_rx %c
               %and NO OTHER WIRE AT(horiz crosser_x,horiz crosser) %c
                %then CC_rx= not set
%finish
%end


!________________________________________________________________________

%routine CLOSE COMPARTMENTS(%record(NODE)%name edge, %c
                            %integer layers)
%integer ccb1,
         ccb2
%record(NODE)%name node== FIND LAYER(edge_next y,layers), 
                   horiz crosser== nil,
                   dev
%record(NODE LIST)%name CC== first compartment_next

!  this rows horizontal wires + devices to compartments and update their limits

  
%while node## nil %and CC## nil %cycle

   ccb2= CC_rx
   ccb1= CC_lx
   %while node## nil %and node_x < ccb2 %cycle

      %if node_class= horiz wire %and node_type//layers check= layers %then %c
           horiz crosser== Node

    %if node_class= device %then ADD MEMBER(CC,node,layers,ccb1,ccb2)

    %if horiz crosser## nil %and %c
                CC_lx < horiz crosser_coord3 %start
       ADD MEMBER (CC,horiz crosser,layers,ccb1,ccb2)
       UPDATE COMPARTMENT(CC,horiz crosser,layers)
    %finish

    node== FIND LAYER(node_next y,layers)
   %repeat

    %if node## nil %and node_class= device %and node_x <= ccb2 %then %c
             ADD MEMBER(CC,node,layers,ccb1,ccb2)
    SEE IF COMPARTMENT CLOSED(layers,CC,node)
    cc== NEXT COMPARTMENT(cc)

%repeat

  %while CC## nil %and horiz crosser## nil %and %C
         CC_lx < horiz crosser_coord3 %cycle
         ADD MEMBER (CC,horiz crosser,layers,cc_lx,cc_rx)
         UPDATE COMPARTMENT(CC,horiz crosser,layers)
         SEE IF COMPARTMENT CLOSED(layers,CC,nil)
         CC== NEXT COMPARTMENT(CC)
  %repeat

%end
!_________________________________________________________________________
%record(NODE)%map  INITIALISE COMPARTMENTS(%integer layers)
%record(NODE)%name node,
                   dev,
                   horiz crosser== nil,
                   edge== screens(Ydir)_ptr_next x
%record(NODE LIST)%name CC

%while edge## top edge %cycle
   node== FIND LAYER(edge_next y,layers)
   %if node## nil %then %exit
   edge== edge_next x
%repeat


%if edge## top edge %start
   %if node## nil %and node_x= new side(layers,left) %and node_class= vert wire %then %c
   CC== %c
        NEXT NEW COMPARTMENT(first compartment,left side) %c
   %else %c
   CC== %c
        NEXT NEW COMPARTMENT(first compartment,new side(layers,left))
   ADD MEMBER (CC, left edge,edges,cc_lx,cc_rx)

     %while node## nil %cycle
       %if node_class# notional %start
         %if  node== FIND LAYER(node,layers)  %start
           ADD MEMBER(CC,node,layers,cc_lx,cc_rx)


           %if node_class= horiz wire %or node_class= device %start
              ADD MEMBER(special compartment,node,layers,left side,right side)
              ADD MEMBER(special compartment,bottom edge,edges,left side,right side)
              GENERATE CONSTRAINTS(special compartment,layers)
              DISPOSE MEMBERS(special compartment)
              horiz crosser== node %if node_class= horiz wire


           %finish %else %c
           %if node_class= vert wire %start

              %if horiz crosser== nil %or horizcrosser_coord3< node_x %start
                 %if node_next y== nil %or node_next y_class# horiz wire %then %c
                   ADD MEMBER (CC,bottom edge,edges,cc_lx,cc_rx)
              %finish

              dev== SPLITTER(node,no)
              %if dev## error %then ADD MEMBER(CC,dev,layers,cc_lx,cc_rx)

              CC_rx= node_x 
              CC== %c
                 NEXT NEW COMPARTMENT(CC,node_x)

              %if horiz crosser## nil %and horiz crosser_coord3> node_x %then %c
                   ADD MEMBER (CC,horiz crosser,layers,cc_lx,cc_rx)  

              ADD MEMBER (CC,node,layers,cc_lx,cc_rx)
              ADD TO CROSSERS LIST(node,layers)
           %finish
         %finish
       %finish
       node== FIND LAYER(node_next y,layers)
     %repeat


   %if CC_lx= new side(layers,right) %then %c
       CC_rx= right side %else %c
       CC_rx= new side(layers,right)
   %if horiz crosser== nil %or %c
         horiz crosser_coord3 < new side(layers,right) %then %c
          ADD MEMBER (CC,bottom edge,edges,cc_lx,cc_rx)
   ADD MEMBER (CC,right edge,edges,cc_lx,cc_rx)

edge== edge_next x
%finish

scan2
%result== edge
%end

!_______________________________________________________________________
%routine EXAMINE CIRCUIT(%integer layers)
%record(NODE LIST)%name vert crosser,
                        CC,
                        nextt,ptr
%record(NODE)%name edge,
                   dev,
                   nodde,
                   horiz crosser== nil

!__________________
%record(NODE LIST)%map COMPARTMENT BORDER(%record(NODE LIST)%name %c
                                          CC, %c
                                          %record(NODE)%name nodde, %c
                                          horiz crosser,
                                          cause)
%record(NODE)%name dev== SPLITTER(cause,no)

       %if dev## error %then ADD MEMBER(CC,dev,layers,cc_lx,cc_rx)
       ADD MEMBER (CC,nodde,layers,cc_lx,cc_rx)
   %if CC_rx= not set %then CC_rx= nodde_x
   CC== %c
        NEXT NEW COMPARTMENT(CC,nodde_x)
   CHECK SPECIAL FORMS(CC,horiz crosser)
   %if horiz crosser## nil %and %c
       horiz crosser_x <= nodde_x %and %c
       horiz crosser_coord3 > nodde_x %then %c
       ADD MEMBER (CC,horiz crosser,layers,cc_lx,cc_rx)
       ADD MEMBER (CC,nodde,layers,cc_lx,cc_rx)
       %if dev## error %then ADD MEMBER(CC,dev,layers,cc_lx,cc_rx)
 %result== CC
%end

!_____________

%routine START ROW

  nodde== FIND LAYER(edge_next y,layers)
  CC== nil
  %if nodde## nil %start
    horiz crosser== nil
    vert crosser== top crosser list_next
    %while vert crosser## nil %and vert crosser_node_x < nodde_x %cycle
           vert crosser== vert crosser_next
    %repeat
  
    %if nodde_x= new side(layers,left) %And %c
                   nodde_class= vert wire  %then %c
     CC== %c
             NEXT NEW COMPARTMENT(first compartment,left side) %c
        %else %c
     CC== %c
             NEXT NEW COMPARTMENT(first compartment,nodde_x)
  
!  if there is a left edge compartment still in existance , it will be
!  picked else a new left edge compartment is generated
  
      %if cc_lx <= new side(layers,left) %then %c
               ADD MEMBER(CC,left edge,edges,cc_lx,cc_rx)
%finish
%end
  
!_____________

%integer %function NEW BORDER FOUND
%record(NODE)%name dev2== nil
  
      %if  vert crosser## nil  %and %c
           ((nodde## nil %and nodde_x >= vert crosser_node_x) %or %c
            (horiz crosser## nil %and %c
           horiz crosser_coord3 >= vert crosser_node_x)) %start

         %if nodde## nil %And nodde_x= vert crosser_node_x %and %c
           nodde_class= device %then %c
             ADD MEMBER(CC,nodde,layers,cc_lx,cc_rx) %and dev2== nodde

         CC== %c
               COMPARTMENT BORDER(CC,vert crosser_node, %c
                                                 horiz crosser,nodde)
        %if dev2## nil %Then ADD MEMBER(CC,dev2,layers,cc_lx,cc_rx)
        vert crosser== vert crosser_next
      %finish %else %C
%c
%c
      %if nodde## nil %And  nodde_class= vert wire %start

         CC== %c
              COMPARTMENT BORDER(CC,nodde,horiz crosser,nodde)

          ADD TO CROSSERS LIST(nodde,layers)
         nodde== FIND LAYER(nodde_next y,layers)
        %finish %else %c
%c
%c
      %if nodde== nil %start
!           Finish off compartment if is new, as it is rightmost
            %if CC## nil %and %c
                CC_rx= not set %start
                %if CC_lx= new side(layers,right) %then %c
                 CC_rx= right side %else %c
                 CC_rx= new side(layers,right)
                ADD MEMBER (CC, right edge,edges,cc_lx,cc_rx)
            %finish
           %result= last
      %finish 

%result= not last
%end

!_____________

%routine FINISH LAST COMPARTMENT ROW

  CC== NEXT COMPARTMENT(first compartment)
! finish final compartments
  %while CC## nil %cycle
    ADD MEMBER (CC,top edge,edges,cc_lx,cc_rx)
    GENERATE CONSTRAINTS( CC,layers)
scan2
scan3(CC,layers)
    DISPOSE MEMBERS(CC)
    CC== NEXT COMPARTMENT(CC)
  %repeat

%end


{start examine circuit}



! initialise compartments
enable reg= any colour
set colour(layers + 1)

edge== INITIALISE COMPARTMENTS(layers)

%while edge## top edge  %cycle

  UPDATE CROSSERS(edge,layers)

  CLOSE COMPARTMENTS(edge,layers)
  
  START ROW

    %cycle 

!     add all devices hws etc between 2 vws to compartment

      %while nodde## nil %cycle
       
        %if nodde_class# notional %start

         %if (nodde_class= vert wire %and nodde_type//layers check= layers) %or  %c
             (vert crosser## nil %and nodde_x >= vert crosser_node_x) %c
              %then %exit

              %if nodde_class= device %c
                     %then ADD MEMBER (CC,nodde,layers,cc_lx,cc_rx) 

               %if nodde_class= horiz wire %and %c
                                 nodde_type//layers check= layers %start
                 horiz crosser== nodde
                 ADD MEMBER (CC,nodde,layers,cc_lx,cc_rx)
                 dev== SPLITTER(nodde,no)
                 %if dev## error %start
                   ADD MEMBER(CC,dev,layers,cc_lx,cc_rx)
                 %finish
               %finish
               CHECK SPECIAL FORMS(CC,horiz crosser)
           %finish
       nodde== FIND LAYER(nodde_next y,layers)
     %repeat
  
      %exit %if NEW BORDER FOUND= last

   %repeat

 edge== edge_next x
%repeat

UPDATE CROSSERS(top edge,layers)

FINISH LAST COMPARTMENT ROW

UPDATE CROSSERS(top edge,ignore)

CLEAN COMPARTMENTS
%end
 

!_________________________________________________________________________
%routine FIND SIDES(%record(NODE)%name w)
%integer layers= w_type//layers check
%routine check valid(%record(NODE)%name w,%integer class,side,new,reverse)
   %if w_class# class %then valid port(side,layers)= no %else %c
    %if (reverse= no  %and new > new side(layers,side)) %or %c
        (reverse= yes %and new < new side(layers,side)) %then %c
                          valid port(side,layers)= yes
       new side(layers,side)= new
%end 

%if w_class= horiz wire %or  w_class= vert wire %start
  %if w_x <= new side(layers,left) %then %c
                check valid(w,horiz wire,left,w_x,yes)
  %if w_class= horiz wire %and %c
     w_coord3 >= new side(layers,right) %then %c
                check valid(w,horiz wire,right,w_coord3,no)
  %if w_y <= new side(layers,bottom) %then %c
                check valid(w,vert wire,bottom,w_y,yes)
  %if w_class= vert wire %and %c
      w_coord3 >= new side(layers,topp) %then %c
                check valid(w,vert wire,topp,w_coord3,no)
  %if w_Y >= new side(layers,topp) %then new side(layers,topp)= w_y %c
                                    %and valid port(topp,layers)= no
  %if w_x >= new side(layers,right) %then new side(layers,right)= w_x %c
                                    %and valid port(right,layers)= no
%finish
%end

!_______________________________________________________________________
           
%routine FIND PORT SIDES
%constinteger pdl= poly and diff layers,
              ml = metal layers
%integer i 
%integerfn test(%integer reverse,side)
%integer res,
         i1= new side(pdl,side),
         i2= new side(ml,side)
%if reverse= no %start
    %if i1 > i2 %start
     res= i1 
     %if valid port(side,pdl)= no %then res= res+ 20
    %else
     res= i2
     %if valid port(side,ml)= no %then res= res + 20
    %finish
%else
    %if i1 < i2 %start
       res= i1
       %if valid port(side,pdl)= no %then res= res-20
    %else
       res= i2
       %if valid port(side,ml)= no %then res= res -20
    %finish
%finish
%result= res
%end

port side(i)= test(no,i ) %for i= topp,1,right
port side(i)= test(yes,i) %for i= left,1,bottom
%end

!_________________________________________________________________________

%routine SPLIT and JOIN(%byte all)
%integer valid
%record(NODE)%name temp,
                   edge,
                   nodde,
                   delete this,
                   last wire,
                   last,
                   use,
                   split,
                   dump
%integer dir,
         i,
         side,
         layers,
         delete x,
         delete y

!   initialise the side coords to their worst values

%for layers= poly and diff layers,1,metal layers %cycle
  new side(layers,right)=  left side+1
  new side(layers,left)=   right side-1
  new side(layers,topp)=   bottom side+1
  new side(layers,bottom)= top side-1
  valid port(i,layers) = yes %for i= topp,1,bottom
%repeat

%for dir= Xdir,1,Ydir %cycle
 
  edge== CONNECT(screens(dir)_ptr,1-dir)
 
 %while edge## top edge %and edge## right edge  %cycle
   nodde== CONNECT(edge,dir)
   last wire== nil
     %while nodde## nil %cycle
     delete this== nil
     use== nil
     split== SPLITTER(nodde,no)
     
  %if last wire## nil %start
! wire splitting
       %if split## error %and split_class= device %And %c
            ON WIRE(last wire,split_x,split_y) %then use== split
       %if nodde_class= device %and  %c
            ON WIRE(last wire,nodde_x,nodde_y) %then use== nodde
       
       %if use## nil %and all= yes %start
              temp== NEW NODE
              temp=  last wire
              temp_cc(1-dir)= 0
              temp_cons(1-dir)== nil
              temp_x= use_x
              temp_y= use_y
                  %if dir= Xdir %then last wire_coord3= use_y %c
                      %else last wire_coord3= use_x
              last wire== temp
              valid= INSERT NODE(temp)
              temp==  nil

         %finish %else %if nodde_class# notional %start
       
  ! check for wire joining
              %if last wire_class= nodde_class %and %c
                  nodde_type= last wire_type %start
              %if  ((dir= xdir %and nodde_y= last wire_coord3) %or %c
                   ( dir= ydir %and nodde_x= last wire_coord3)) %start
                   delete this== nodde
                   last wire_coord3= nodde_coord3
                 %finish
             %finish
         %finish
     
%else
        %if dir= Xdir %and nodde_class= vert wire %then last wire== nodde  
        %if dir= ydir %and nodde_class= horiz wire %then last wire== nodde
%finish
     

        last== nodde
        nodde== CONNECT(nodde,dir)

        %if delete this## nil %start
         dump==DELETE OR SIZE NODE(delete this_x,
                       delete this_y,ignore,delete this,last wire)
           FIND SIDES(last wire)
        %else
           FIND SIDES(last)
           %if dir= ydir %and last_class= device %and all= no %c
              %then FIND DEVICE WIRES(last)
        %finish

   %repeat
  edge== CONNECT(edge,1-dir)
 %repeat
%repeat
FIND PORT SIDES
%end



%list
%endoffile

