# ****************************************************************************************
# PROC: Return distance to the closest welltie
# ****************************************************************************************
proc calc_d {wells space row x y} {
   upvar $wells my_wells
   set dist_sr [expr 2 * $space]

   # Calculate SAME Row
   if {[info exists my_wells($y.x)]} { 
      foreach wx $my_wells($y.x) {
         if {[expr abs($wx - $x)] < $dist_sr} {
            set dist_sr [expr abs($wx - $x)]
         }
      }
   }

   
   # if the welltie on the same row is too far ...
   if {$dist_sr > $space} {

      # Calculate UP Row
      set dist_up $dist_sr
      set yu [expr $y + $row]
      if {[info exists my_wells($yu.x)]} { 
         foreach wx $my_wells($yu.x) {
            if {[expr abs($wx - $x)] < $dist_up} {
               set dist_up [expr abs($wx - $x)]
            }
         }
      }

      # Calculate DOWN Row
      set dist_dn $dist_sr
      set yd [expr $y - $row]
      if {[info exists my_wells($yd.x)]} { 
         foreach wx $my_wells($yd.x) {
            if {[expr abs($wx - $x)] < $dist_dn} {
               set dist_dn [expr abs($wx - $x)]
            }
         }
      }

      # Report MAX
      if {$dist_up > $dist_dn} {
         return $dist_up
      } else {
         return $dist_dn
      }
   } else {
      return $dist_sr
   }
}

# ****************************************************************************************
# MAIN PROC: Report and highlight cells too far from a welltie
# ****************************************************************************************
proc check_welltie {} {

# Max distance
set space 20000
# Welltie width
set wt 1600
# Row heigth
set row 6400

set failed 0
   
deselectall

puts stdout "\n\n+----------------------------------------------------------------------------------+-----------+"
puts stdout "| Component Name                                                                   |  Spacing  |"
puts stdout "+==================================================================================+===========+"
   
   # Parse and store each welltie
   dbForEachCellInst [dbgTopCell] instPtr {
      if {[dbInstCellName $instPtr] == "subwelltie_a"} {
         set coord [split [dbInstLoc $instPtr]]
         set x [expr [lindex $coord 0] + $wt]
         set y [lindex $coord 1]
         
         if {[info exists wells($y.x)]} { 
            lappend wells($y.x) $x
         } else {
            lappend wells(y) $y
            lappend wells($y.x) $x
         }
      }
   }

   # Parse each components
   dbForEachCellInst [dbgTopCell] instPtr {
      if {[dbInstCellName $instPtr] != "subwelltie_a"} {
      if {[dbInstCellName $instPtr] != "fillemp1_a"} {
      if {[dbInstCellName $instPtr] != "fillemp2_a"} {
      if {[dbInstCellName $instPtr] != "fillemp4_a"} {
      if {[dbInstCellName $instPtr] != "fillemp8_a"} {
      if {[dbInstCellName $instPtr] != "fillemp16_a"} {
      if {[dbInstCellName $instPtr] != "fillemp32_a"} {
         set name [dbInstName $instPtr]
         set xmin [get_property [get_cells [dbInstName $instPtr]] x_coordinate_min]
         set xmax [get_property [get_cells [dbInstName $instPtr]] x_coordinate_max]
         set y    [get_property [get_cells [dbInstName $instPtr]] y_coordinate_min]
         set x [expr ($xmin + $xmax) * 1000 / 2]
         set y [expr $y * 1000]
         set xmin [expr $xmin * 1000]
         set xmax [expr $xmax * 1000]
         set tmp [split $x .]
         set x [lindex $tmp 0]
         set tmp [split $y .]
         set y [lindex $tmp 0]
         set tmp [split $xmin .]
         set xmin [lindex $tmp 0]
         set tmp [split $xmax .]
         set xmax [lindex $tmp 0]

         set dx [calc_d wells $space $row $x $y]
         set dl [calc_d wells $space $row $xmin $y]
         set dr [calc_d wells $space $row $xmax $y]
         
         set d [list $dx $dl $dr]
         set d [lsort $d]
         set d [lindex $d 2]
         
         if {$d > $space} {
            set p [format "| %-80s | %9d |" $name $d]
            puts $p
            incr failed
            selectInst $name
         }
         
      }
      }
      }
      }
      }
      }
      }
   }
   
# Highlight each components with violations
dehiliteall 
highlight -index 1
deselectall

if {$failed != 0} {
   puts stdout "+----------------------------------------------------------------------------------+-----------+"
}
set p [format "| Number of cells with violations                                                  | %9d |" $failed]
puts $p
puts stdout "+----------------------------------------------------------------------------------+-----------+"

}
