!14/05
!
!
%endoflist
%constinteger blue= 4,
              green=2,
              red=  1
%constbyte  yes= 1,
            no = 0

%include "DECLARATIONS"

%externalintegerarrayspec min width(contact:metal)
%externalintegerspec min extension
%externalbytespec min gate ratio

%externalstring(25)%array PORT NAME(1:20)
%externalintegerarray port pos(1:20,Xdir:Ydir)
%externalinteger portcount= 1
%externalinteger this port= 1
%externalrecord(NODELIST)%array PORT LIST(topp:bottom)= 0(*)

%externalrecord(NODE) left edge= 0, right edge= 0
%externalrecord(NODE) top edge= 0,  bottom edge= 0

%externalrecord(EXT)%array screens(X dir:Y dir)

%externalroutine INIT
screens(X dir)_ptr== left edge
screens(Y dir)_ptr== bottom edge

left edge_x=  left side
left edge_y= -edges
left edge_next y== right edge
right edge_x=  right side
right edge_y= -edges
left edge_type=  edges
left edge_class= device
right edge_type= edges
right edge_class= device

bottom edge_y= bottom side
bottom edge_x= edges
bottom edge_next x== top edge
top edge_y= top side
top edge_x= edges
top edge_type= edges
top edge_class= device
bottom edge_type=  edges
bottom edge_class= device
%end

%externalrecord(NODE) error 

!_______________________________________________________________________
%externalpredicate THRU WIRE(%record(NODE)%name wire,%integer x,y)
  %if (wire_class= horiz wire %and wire_x < x < wire_coord3 %c
                              %and wire_y= y) %or %c
      (wire_class= vert wire %and  wire_y < y < wire_coord3 %c
                             %and  wire_x= x) %then %TRUE
%FALSE
%end
!_______________________________________________________________________

%externalrecord(NODE)%map FIND WIRE(%record(NODE)%name n,%c
                            %integer type)
%record(ARCC)%name con
%record(NODE)%name nn
%integer dir
  %for dir= xdir,1,ydir %cycle
    con== n_cons(dir)
    %while con## nil %cycle
     nn== con_next node
     %if nn_type= type %and (nn_class= vert wire %or nn_class= horiz wire) %c
                       %then %result== nn
     con== con_another arcc
    %repeat
  %repeat
%result== error
%end

!_______________________________________________________________________

%externalroutine CLEAN CONSTRAINT GRAPH(%integer limited)
%record(NODE)%name edge== screens(Xdir)_ptr_nexty 
%record(NODE)%name nodde

   %routine CLEAN(%record(NODE)%name nodde)
   %record(ARCC)%name arc
    %integer dir
    nodde_checked= 0

    %if limited# yes %start
      %for dir= xdir,1,ydir %cycle
         nodde_path length(dir)= 0
         arc== nodde_arccs(dir)
         %while arc## nil %cycle
          arc_lp route= no
         arc== arc_another arcc
         %repeat
         arc== nodde_cons(dir)
         %while arc## nil %cycle
          arc_lp route= no
         arc== arc_another arcc
         %repeat
      %repeat
    %finish
   %end

%while edge## nil %cycle
 nodde== edge_next x
  %while nodde## nil %cycle
    CLEAN(nodde)
    nodde== nodde_next x
  %repeat
 edge== edge_next y
%repeat
CLEAN(left edge)
CLEAN(right edge)
CLEAN(top edge)
CLEAN(bottom edge)
%end

!________________________________________________________________________

%externalroutine SCALE OUT
%conststring(255)%array dirs(xdir:ydir)= " DX ",
                                         " DY "
%conststring(255)%array direction(topp:bottom)= "N",
                                                "E",
                                                "W",
                                                "S"
%conststring(255)%array directions(topp:bottom)= "North",
                                                 "East ",
                                                 "West ",
                                                 "South"
%own%record(NODE)%name edge,
                   ptr,
                   port is,
                   pw
edge== screens(Xdir)_ptr
%record(ARCC)%name arc
%byte wire no= 1,
      offset
%integer i,j,
         x,y,
         this layer,
         dir
  
%string(255) name=""
%string(255)%array wirecode(1:20),
                   turn(1:20),
                   bend(1:20)
wirecode(i)= "" %and bend(i)= "" %and turn(i)= "" %for i= 1,1,20
%integerarray pos(1:20,1:2)

!___________________________________________________________________
%string(255)%fn BRACKETS(%integer x,y,%string(255) dir)
%integer temp= x
%if dir# dirs(ydir) %start
    x= y
    y= temp
            %finish
   %result= "  (".itos(x,0).",".itos(y,0).")  "
%end
!___________________________________________________________________
%string(255)%fn  GATE(%record(NODE)%name dev)
%ownbytearray count(pull down:pass tran)=  0(*)
%string(255) which =""
%integer dir= ydir

%if dev_type= pass tran %start
 which= "pt"
 printstring("
   PassTran pt")
%else
 which= "pd"
 printstring("
   PullDown pd")
%finish

printstring(itos(count(dev_type),0)."   ".%c
             brackets(dev_path length(ydir),dev_path length(xdir),dirs(Ydir)))

%if dev_cons(ydir)_next node_type= diff %then %c
                        dir= ydir %else  %c
%if dev_cons(ydir)_next node_type= poly %then %c
                        dir= xdir

printstring("
            SRC   ".brackets(0,-(min width(poly)+min width(diff))//2,dirs(dir)))

  %if  dev_ratio# min gate ratio %then %c
        printstring("Width ".itos(dev_ratio*min width(diff),0))

printstring(dirs(dir).itos((dev_ratio+1)*min width(diff),0)." DRN,")
printstring("
            GTin  ".brackets(%c
       -(dev_ratio*min width(diff))//2-min extension,0,dirs(dir)))
printstring(dirs(1-dir).itos(%c
       dev_ratio*min width(diff)+ 2*min extension,0)." GTout")
dev_checked= count(dev_type)
count(dev_type)= count(dev_type)+1
newline
%result= which.itos(count(dev_type)-1,0)
%end


!___________________________________________________________________
%string(255)%fn  PU(%record(NODE)%name dev)
%ownbyte count=  0
%integer dir= ydir,
              value= min width(diff)*dev_ratio + (min width(contact)//2)

printstring("
   PullUp   pu".itos(count,0)."   ".%c
             brackets(dev_path length(ydir),dev_path length(xdir),dirs(Ydir)))

%if dev_type= PUN %then dir= ydir %else dir= xdir

printstring("
            SRC   ".brackets(0,-value//2-1,dirs(dir)))
printstring(dirs(dir).itos(value+2,0)." DRN,")
printstring("
            GTin  ".brackets(0,-value//2,dirs(dir)))
printstring("Width ".itos(min width(diff) + 2*min extension,0))
printstring(dirs(dir).itos(value,0)." GTout")
dev_checked= count
count= count+1
newline
%result= "pu".itos(count-1,0)
%end


!_________________________________________________________________________
%string(255)%fn CONTACT(%record(NODE)%name c)
%ownbyte count= 0
%string(255) dir= dirs(Ydir)
printstring("
   CONTACT  c".itos(count,0).%c
        " AT ".brackets(c_path length(Ydir),c_path length(Xdir),dirs(Ydir)))
c_checked= count
count= count+1
%result= "c".itos(count-1,0)
%end

!________________________________________________________________
%string(255)%fn MAKE DEVICE CODE(%record(NODE)%name dev)
%if CPM <=dev_type <= CDM %or CPDE <= dev_type <= CPDS %or  %c
    dev_type= join %then %result= CONTACT(dev)
%if PUE <= dev_type <= PUN %then %c
         %result= PU(dev)
%if dev_type= pull down %or dev_type= pass Tran %c
        %then %result= GATE(dev)
%if dev_type= port %then %result= direction(dev_side).":".port name(dev_idd)
%result= "?"
%end
   
!________________________________________________________
  %string(255)%fn HEADER(%integer type,width)
   %string(255) res =""
   %if type= metal %then res= "Metal     " %else %c
   %if type= diff  %then res= "Diffusion " %else %c
   %if type= poly  %then res= "Poly      "
   %if width# min width(type) %then res= res."(".itos(width,0).") "
   %result= "   ".res."Wire "
  %end

!______________________________________________________
%string(255)%fn dev port(%record(NODE)%name dev,wire,%integer first)
  %if %not(CPM <=dev_type <= CDM) %andnot (CPDE <=dev_type <=CPDS)%c
      %andnot dev_class= notional  %start
    %if wire_type= poly %start
     %if first= yes %then %result= "_GTOut" %else %result= "_GTin"
    %else %if wire_type= diff
     %if first= yes %then %result= "_DRN" %else %result= "_SRC"
    %finish
  %finish
%result= ""
%end
!__________________________________________________________________
%routine CELL START
%string(255) s=""
%record(NODELIST)%name list
%ownstring(255)%array mins(topp:bottom)= ""(*)
%integerarray sum(topp:bottom)
%integer count,i,j,dir,update,started= no

mins(i)= "" %for i= topp,1,bottom
printstring(" Design stick
")
s= "   Leaf Cell "."test"." ["
printstring(s)
offset= length(s)
%for j= topp,1,bottom %cycle
 list== PORT LIST(j)_next
 %if list## nil %start
     mins(j)= directions(j)." Minimum |" 
     spaces(offset) %if j#topp %and started= yes
     printstring(direction(j).":") 
 %finish
 count= 0
 sum(j)= 0
 %if j= topp %or j= bottom %then dir= Ydir %else dir= Xdir
 %while list## nil %cycle
     %if count > 0 %then printsymbol(',')
     printstring(port name(list_rx))
     update= list_node_path length(dir)
     %if count# 0 %then mins(j)= mins(j)." <- "
     mins(j)= mins(j).itos(update-sum(j),0).%c
              " -> ".port name(list_rx)
     sum(j)=  update
     count= count + 1
  list== list_next
 %repeat
 %if J# bottom %start
   %if port list(j+1)_next## nil %c
       %andnot(j=topp %and port list(j)_next== nil) %then %c
    printstring(" |
") %and started= yes
 %else
    printstring("]
")
 %finish
%repeat

newline
%for i= topp,1,bottom %cycle
  printstring(mins(i))
  %if mins(i)# "" %start
   %if i= topp %or i= bottom %then %c
         printstring(" <- ".itos(right edge_path length(Ydir)-sum(i),0)." |
") %else printstring(" <- ".itos(top   edge_path length(Xdir)-sum(i),0)." |
")
  %finish
%repeat
%end


!________________________________________________________________
  %routine MAKE WIRE CODE(%record(NODE)%name wire,
                                             dev,
                          %string(255) dev name,
                          %integer lx,ly,
                          %bytename wireno)
    %bytename   pwc== wire_checked
    %string(255) direct=""
    %integer x= ptr_x,
             y= ptr_y,
             thru
             
            %if pwc= 0 %then pwc= wire no %and wire no= wire no + 1

            %if lx# dev_path length(Ydir) %start
                direct= " DX ".itos(lx-dev_path length(Ydir),0)
            %else %if ly# dev_path length(Xdir)
                direct= " DY ".itos(ly-dev_path length(Xdir),0)
            %finish

            %if direct# "" %start
               %if wire_class= horiz wire %start
                  turn(pwc)= " XThenY "
               %else
                  turn(pwc)= " YThenX "
               %finish
            %finish

            %if wirecode(pwc)= "" %start  
                wirecode(pwc)= header(wire_type,wire_width).%c
                       dev name.dev port(dev,wire,yes)." -> "
                bend(pwc)= direct.turn(pwc) %if direct# ""
            %else
                %if bend(pwc)= "" %then bend(pwc)= turn(pwc)
                wirecode(pwc)= wirecode(pwc).%c
                       dev name.dev port(dev,wire,no).bend(pwc)
                %if thru wire(wire,x,y) %start
                     wirecode(pwc)= wirecode(pwc).",
                  ".devname.dev port(dev,wire,yes)." -> "
                  %if direct# "" %then bend(pwc)= direct.turn(pwc) %else %c
                                       bend(pwc)= ""
                %else
                  bend(pwc)= ""
                %finish
            %finish
%end



CLEAN CONSTRAINT GRAPH(yes)

open output(1,"ills")
select output(1)

CELL START

%while edge## nil  %cycle
  ptr== edge_next x
  %while ptr## nil %cycle
    %if (ptr_class= device %or ptr_class= notional) %and ptr_type# edges %start


      %if %not(PUE <= ptr_type <= PUN) %and %not(CPM <= ptr_type <= CDM) %start
! this also handles notional corners

        %if ptr_class= notional %start
           %for dir= xdir,1,ydir %cycle
            ptr_path length(dir)= ptr_cons(dir)_next node_path length(dir)
           %repeat
        %finish

        name= MAKE DEVICE CODE(ptr)
        %for dir= xdir,1,ydir  %cycle
         arc== ptr_cons(dir)
         %while arc## nil %cycle
          pw== arc_next node
          %if pw_type# edges %start
           y= ptr_path length(Xdir)
           x= ptr_path length(Ydir)
           MAKE WIRE CODE(pw,ptr,name,x,y,wireno)
          %finish
         arc== arc_another arcc
         %repeat
        %repeat

      %else

         name= MAKE DEVICE CODE(ptr)
         %for dir= xdir,1,ydir %cycle
           arc== ptr_cons(dir)
           %while arc## nil %cycle
          
             %if arc## nil %start
                %if dir= xdir %start 
                    y= arc_next node_path length(Xdir)
                    x= ptr_path length(Ydir)
                %else
                    x= arc_next node_path length(Ydir)
                    y= ptr_path length(Xdir)
                %finish
                MAKE WIRE CODE(arc_next node,ptr,name,x,y,wireno)
             %finish
              
            arc== arc_another arcc
           %repeat
         %repeat
      %finish
     
    %finish
   ptr== ptr_next x
  %repeat
 edge== edge_next y
%repeat


! now output wires
   newline
   %for i=wire no-1,-1,1 %cycle
        printstring(wirecode(i))
        newline
   %repeat

printstring("
   Endcell
 
   Cell (test) place
   Put place At (0,0)

 EndDesign
Endfile
")

close output

%end

!________________________________________________________________________

%externalroutine ILAP OUT
%conststring(255)%array lay(poly:metal)= "poly",
                                         "diffusion","",
                                         "metal"
%integer%array current width(poly:metal)
%string(255)%array width(poly:metal)
width(poly)= itos(min width(poly),0)
width(diff)= itos(min width(diff),0)
width(metal)=itos(min width(metal),0)

%conststring(255)%array contacts(cpm:cpds)= "PM(",
                                            "DM(","","",
                                            "PDBE(",
                                            "PDBW(",
                                            "PDBN(",
                                            "PDBS("

%conststring(255)%array gates(horiz wire:vert wire)= "ETPX(",
                                                     "ETPY("

%conststring(255)%array pull ups(PUE:PUN)= "DTDBX(",
                                           "DTDBY("

%own%record(NODE)%name edge,
                   ptr,
                   pw
edge== screens(Xdir)_ptr
%record(ARCC)%name arc
%byte wire no= 1
%integer i,
         x,y,
         this layer,
         dir
  
%string(255)%array wirecode(1:100)
wirecode(i)= "" %for i= 1,1,100
%integerarray pos(1:100,1:2),
              wide(1:100),
              layer(1:100)

  %routine ADJUST gate(%record(NODE)%name dev,%integername x,y)
  %record(NODE)%name polyy== FIND WIRE(dev,poly)
     %if polyy## error %start
       %if polyy_class= vert wire %start
           x= x-(min width(poly)//2)
           y= y-((min width(diff)*ptr_ratio)//2)
       %else
           y= y-(min width(poly)//2)
           x= x-((min width(diff)*ptr_ratio)//2)
       %finish
     %finish
  %end

  %routine ADJUST pu(%record(NODE)%name dev,%integername x,y)
   %if dev_type= PUE %start
              x= x-((ptr_ratio*min width(diff)+(min width(contact)//2))//2)
              y= y-(min width(diff)//2)
   %else
              y= y-((ptr_ratio*min width(diff)+(min width(contact)//2))//2)
              x= x-(min width(diff)//2)
   %finish
   
  %end
   
  %string(255)%fn OPEN(%integer x,y)
   %result= "(".itos(x,0).",".itos(y,0).","
  %end

  %string(255)%fn HEADER(%integer class)
   %if class= horiz wire %then %result= "WIREX"
   %result= "WIREY"
  %end


  %routine MAKE DEVICE CODE(%record(NODE)%name dev)
  %record(NODE)%name polyy== FIND WIRE(dev,poly),
                     wire
  %record(ARCC)%name arc,arc2
  %owninteger gate= 0
  %owninteger pu= 0
  %integer x= dev_path length(Ydir),
           y= dev_path length(Xdir),
           length,
           reverse= not set

        %predicate CORRECT(%record(NODE)%name n1,n2)
          %if (n1_type= PUN %and n2_y > n1_y) %or %c
              (n1_type= PUE %and n2_x > n1_x) %then %TRUE
          %FALSE
        %end

  %if dev_class# notional %start
    %if CPM <= dev_type <= CDM %or CPDE <= dev_type <= CPDS %start
       printstring(contacts(dev_type).itos(x,0).",".itos(y,0).")
")
    %finish %else %if dev_type= pull down %or dev_type= pass tran %start
       adjust gate(dev,x,y)
       printstring(gates(polyy_class)."""".itos(gate,0).""",". %c
         itos(x,0).",".itos(y,0).",".itos(min width(diff)*dev_ratio,0).")
")
      gate= gate + 1
    %finish %else %start
       %if dev_type= PUN %then dir= ydir %else dir= Xdir
       wire== dev_cons(dir)_next node
       arc==  wire_cons(dir)
       %while arc## nil %cycle
        %if cpm <= arc_next node_type <= cdm %start
          %if ((dev_type= PUN %and arc_next node_y < dev_y) %or %c
              (dev_type= PUE %and arc_next node_x < dev_x)) %and %c
               reverse= not set  %then reverse= yes
        %finish
        %if arc_next node_type= pull down %start
          %if correct(dev,arc_next node) %then reverse= yes %else reverse= no
        %finish
        %if arc_next node_type= join %start
            arc2== arc_next node_cons(1-dir)_next node_cons(1-dir)
            %while arc2## nil %cycle
             %if correct(dev,arc2_next node) %then reverse= yes
             arc2== arc2_another arcc
            %repeat
        %finish
       arc== arc_another arcc
       %repeat
       adjust pu(dev,x,y)
       length= min width(diff)*dev_ratio+(min width(contact)//2)
       %if reverse= yes %start
          %if dev_type= PUN %then y= y+length %else x= x+length
          length= -length
       %finish
          printstring(pull ups(dev_type)."""".itos(pu,0).""",". %c
            itos(x,0).",".itos(y,0).",")
          printstring(itos(length,0).")
")
       pu= pu + 1
    %finish
  %finish
  %end



  %routine MAKE WIRE CODE(%record(NODE)%name wire,%c
                          %integer lx,ly,x,y,%c
                                   link device,
                          %bytename wireno)
    %integer coord3,thru
    %bytename   pwc== wire_checked
       %cycle
         thru= no
            %if pwc= 0 %then pwc= wire no %and wire no= wire no + 1

            %if wirecode(pwc)= "" %start  

                x= lx-(wire_width//2)
                y= ly-(wire_width//2)
                pos(pwc,1)= x
                pos(pwc,2)= y
                layer(pwc)= wire_type
                wide(pwc)= wire_width
                wirecode(pwc)= header(wire_class).open(pos(pwc,1),pos(pwc,2))
            %else
!              ptr== wire_cons(dir)
!              %while ptr## nil %cycle
!                nn== ptr_next node
!                %if nn_type= join %and %c
!                   ((wire_class= horiz wire %and nn_x= wire_coord3) %or %c
!                    (wire_class= vert wire %and nn_y= wire_coord3)) %start
!                   inflate= nn_cons(1-dir)_next node_width//2
!                   %exit
!                %finish
!                ptr== ptr_another arcc
!              %repeat
               %if wire_class= horiz wire %then %c
                 coord3= lx-pos(pwc,1)+1 %else coord3= ly-pos(pwc,2)+1
                wirecode(pwc)= wirecode(pwc).itos(coord3,0).")
"
                %if thru wire(wire,x,y) %start
                     %if wire_class= horiz wire %start
                       ly= pos(pwc,2)+wire_width//2
                     %else
                       lx= pos(pwc,1)+wire_width//2
                     %finish
                     pwc= 0  
                     thru= yes 
                %finish
            %finish
       %repeat %until thru= no
%end



CLEAN CONSTRAINT GRAPH(yes)

open output(1,"ill")
select output(1)

printstring("
%begin
%include ""ilap:ilap.inc""
MERGE ON

symbol(""test"")
")

%while edge## nil  %cycle
  ptr== edge_next x
  %while ptr## nil %cycle
    %if (ptr_class= device %or ptr_class= notional) %and ptr_type# edges %start


      %if %not(PUE <= ptr_type <= PUN) %and %not(CPM <= ptr_type <= CDM) %start
! this also handles notional corners

        %if ptr_class= notional %start
           %for dir= xdir,1,ydir %cycle
            ptr_path length(dir)= ptr_cons(dir)_next node_path length(dir)
           %repeat
        %finish

        %for dir= xdir,1,ydir  %cycle
         %if ptr_cons(dir)## nil %start
          pw== ptr_cons(dir)_next node
          %if pw_class# device %start
           y= ptr_path length(Xdir)
           x= ptr_path length(Ydir)
           MAKE WIRE CODE(pw,x,y,ptr_x,ptr_y,ptr_class,wireno)
          %finish
         %finish
        %repeat

      %else

         %for dir= xdir,1,ydir %cycle
           arc== ptr_cons(dir)
           %while arc## nil %cycle
          
             %if arc## nil %start
                %if dir= xdir %start 
                    y= arc_next node_path length(Xdir)
                    x= ptr_path length(Ydir)
                %else
                    x= arc_next node_path length(Ydir)
                    y= ptr_path length(Xdir)
                %finish

             MAKE WIRE CODE(arc_next node,x,y,ptr_x,ptr_y,ptr_class,wireno)
             %finish
              
            arc== arc_another arcc
           %repeat
         %repeat
      %finish
     
      MAKE DEVICE CODE(ptr)
     
    %finish
   ptr== ptr_next x
  %repeat
 edge== edge_next y
%repeat


! now output wires
this layer= Poly
%cycle
 printstring("
layer(".lay(this layer).")
width(".width(this layer).")
")
current width(this layer)= min width(this layer)
   %for i=wire no-1,-1,1 %cycle
    %if layer(i)= this layer %start
       %if current width(this layer)# wide(i) %start
             current width(this layer)= wide(i)
             printstring("width(".itos(wide(i),0).")")
             newline
             printstring(wirecode(i))
       %else
        printstring(wirecode(i))
       %finish
    %finish
   %repeat
   %if this layer= poly %then this layer= diff %else %c
   %if this layer= diff %then this layer= metal %else %exit
%repeat 

printstring("
end symbol

DRAW(""test"",0,0)

FINISH
%endofprogram
")

close output

%end


%list
%endoffile
