PT report_qor Script

#
# Procedure to emulate DC's report_qor in PT
#
# Version 1.10 6/1/09 pjarvis
#
# Revision history
# 1.0 (pfj) 9/3/03 - Initial release
# 1.1 (pfj) 9/4/03 - Added hold-time reporting
# 1.2 (pfj) 9/4/03 - Rewrote report_constraint parser and added all other DRCs
# 1.3 (pfj) 9/4/03 - Added missing DRCs and fixed a bunch of related problems
# 1.4 (pfj) 9/5/03 - Rewrote DRC parser to eliminate dependency on list of DRCs
# 1.5 (pfj) 9/30/03 - Fixed bug with unconstrained path slacks
# 1.6 (pfj) 5/14/04 - Changed report_constraint to use 5 digits for consistency with its DRC summary values
# 1.7 (pfj) 4/27/07 - Added DMSA support; switched to redirect -variable instead of using temp file;
#                     fixed bug with recovery/removal sum/count not being reported in async_default group;
#                     added -significant_digits switch and dummy -physical switch (compatibility with DC/ICC)
# 1.8 (pfj) 11/5/07 - Added code to stop script from running in 2007.06-* PrimeTime DMSA mode prior to 2007.06-SP3
#                     to avoid merged-reporting bug from STAR 9000188708
# 1.9 (pfj) 11/13/07 - Changed get_pins -of [get_cells $nonhier_cells] to the more-memory-efficient
#                      get_pins -hier * -filter "is_hierarchical==false" approach; reduces overall memory usage
# 1.10 (pfj) 6/1/09  - Fixed bug in DMSA mode where zero TNS and path count is reported with nonzero WNS;
#                      alphabetized display of path groups to avoid nondeterministic get_timing_paths group ordering
 
proc report_qor {args} {
 
global sh_product_version
global sh_dev_null
global report_default_significant_digits
global synopsys_program_name
global pt_shell_mode
 
set results(-help) "no help"
set results(-significant_digits) "none"
 
parse_proc_arguments -args $args results
 
if {$results(-help)==""} {
  help -verbose report_qor
  return 1
}
 
if {$results(-significant_digits)=="none"} {
  set significant_digits $report_default_significant_digits
} else {
  if {$results(-significant_digits) < 0 || $results(-significant_digits) > 13} {
    echo "Error: value '$results(-signiificant_digits)' not in range (0 to 13). (CMD-019)"
    return 0
  } else {
    set significant_digits $results(-significant_digits)
  }
}
 
proc count_levels {path} {
  set levels 0
  set endpoint [get_object_name [get_attribute -quiet $path endpoint]]
  foreach_in_collection point [get_attribute -quiet $path points] {
    set object [get_attribute -quiet $point object]
    if {[get_attribute -quiet $object object_class] == "pin"} {
      if {[get_attribute -quiet $object pin_direction] == "in"} {
        if {[get_attribute -quiet $object is_port] == "false"} {
          if {[get_attribute -quiet $object full_name] != $endpoint} {
            incr levels
          }
        }
      }
    }
  }    
  return $levels
}
 
proc display_path_group {levels arrival slack cost count significant_digits scenario} {
  echo "  ---------------------------------------------"
  echo [format "  Levels of Logic:%29d$scenario" $levels]
  echo [format "  Critical Path Length:%24.${significant_digits}f$scenario" $arrival]
  if {[regexp {[^a-zA-Z]} $slack full]} { 
    echo [format "  Critical Path Slack:%25.${significant_digits}f$scenario" $slack]
  } else {
    echo [format "  Critical Path Slack:            unconstrained$scenario"]
  }
  echo [format "  Total Negative Slack:%24.${significant_digits}f" $cost]
  echo [format "  No. of Violating Paths:%22d" $count]
  echo "  ---------------------------------------------"
}
 
proc display_cell_count_and_drcs {hier_cells_count nonhier_cells_count area hier_pins_count nonhier_pins_count cost count drc_list significant_digits scenario} {
upvar $cost cost_local
upvar $count count_local
  echo "\n\n  Cell Count"
  echo "  ---------------------------------------------"
  echo [format "  Hierarchical Cell Count:%21d$scenario" $hier_cells_count]
  echo [format "  Hierarchical Port Count:%21d$scenario" $hier_pins_count]
  echo [format "  Leaf Cell Count:%29d$scenario" $nonhier_cells_count]
  echo "  ---------------------------------------------"
  echo "\n\n  Area"
  echo "  ---------------------------------------------"
  echo [format "  Design Area:%33.6f$scenario" $area]
  if {[info exists cost_local(max_area)]} {
    echo [format "  Area Cost:%35.6f" $cost_local(max_area)]
  }
  echo "  ---------------------------------------------"
  echo "\n\n  Design Rule Violations"
  echo "  ---------------------------------------------"
  echo [format "  Total No. of Pins in Design:%17d$scenario" $nonhier_pins_count]
  foreach i $drc_list {
    if {$count_local($i) != 0} {
      set len [expr 38 - [string length $i]]
      echo [format "  $i Count:%${len}d" $count_local($i)]
    }
  }
  set total_cost 0
  foreach i $drc_list {
    if {$cost_local($i) != 0} {
      set len [expr 39 - [string length $i]]
      set total_cost [expr $total_cost + $cost_local($i)]
      echo [format "  $i Cost:%${len}.${significant_digits}f" $cost_local($i)]
    }
  }
  echo [format "  Total DRC Cost:%30.${significant_digits}f" $total_cost]
  echo "  ---------------------------------------------\n"
}
 
if {$synopsys_program_name != "pt_shell"} {
  echo "Error: This script only functions properly in PrimeTime."
  return 0
}
 
set constraint_text ""
set drc_list ""
set group_list ""
 
if {$pt_shell_mode == "primetime" || $pt_shell_mode == "primetime_slave"} {
 
  set cost(unconstrained) 0
  set count(unconstrained) 0
 
  redirect $sh_dev_null {catch {set design [current_design]}}
 
  if { $design == "" } {
    echo "Error: Current design is not defined. (DES-001)"
    return 0
  }
 
  echo "\n****************************************"
  echo "Report : qor"
  echo "Design : [get_object_name $design]"
  echo "Version: $sh_product_version"
  echo "Date   : [date]"
  echo "****************************************\n"
 
  redirect -variable constraint_text {report_constraint -all_violators -nosplit -significant_digits 5}
 
  foreach line [split $constraint_text "\n"] {
    switch -regexp $line {
      {^.* +([-\.0-9]+) +\(VIOLATED} {
        regexp {^.* +([-\.0-9]+) +\(VIOLATED} $line full slack
        set cost($group) [expr $cost($group) + $slack]
        incr count($group)
        continue
      }
      { *max_delay/setup.*'(.*)'} {
        regexp { *max_delay/setup.*'(.*)'} $line full group
        set cost($group) 0
        set count($group) 0
        continue
      }
      { *min_delay/hold.*'(.*)'} {
        regexp { *min_delay/hold.*'(.*)'} $line full group
        set group ${group}_min
        set cost($group) 0
        set count($group) 0
        continue
      }
      {^ *([a-zA-Z_]+) *$} {
        regexp {^ *([a-zA-Z_]+) *$} $line full group
        if {$group == "recovery" } {
          set group async_default
        }
        if {$group == "removal"} {
          set group async_default_min
        }
        if ![info exists cost($group)] {
          set cost($group) 0
          set count($group) 0
          if {$group != "max_area" && $group != "async_default" && $group != "async_default_min"} {
            lappend drc_list $group
          }
        }
        continue
      }
    }
  }
 
  foreach_in_collection path [sort_collection [get_timing_paths] path_group] {
    set path_group [get_attribute -quiet [get_attribute -quiet $path path_group] full_name]
    if {$path_group == ""} {
      set path_group unconstrained
    }
    if {[regexp {\*\*[a-z_]*\*\*} $path_group full]} {
      set path_group [string map {\* ""} $path_group]
    }
    if {![info exists cost($path_group)]} {
      set cost($path_group) 0
      set count($path_group) 0
    }
 
    set levels [count_levels $path]
 
    set slack [get_attribute -quiet $path slack]
 
    echo "\n  Timing Path Group '$path_group' (max_delay/setup)"
    display_path_group $levels [get_attribute -quiet $path arrival] $slack $cost($path_group) $count($path_group) $significant_digits ""
  }
 
  echo ""
 
  foreach_in_collection path [sort_collection [get_timing_paths -delay min] path_group] {
    redirect $sh_dev_null {set path_group [get_attribute -quiet [get_attribute -quiet $path path_group] full_name]}
    if {$path_group == ""} {
      set path_group unconstrained
    }
    if {[regexp {\*\*[a-z_]*\*\*} $path_group full]} {
      set path_group [string map {\* ""} $path_group]
    }
    if {![info exists cost(${path_group}_min)]} {
      set cost(${path_group}_min) 0
      set count(${path_group}_min) 0
    }
 
    set levels [count_levels $path]
 
    set slack [get_attribute -quiet $path slack]
 
    echo "\n  Timing Path Group '$path_group' (min_delay/hold)"
    display_path_group $levels [get_attribute -quiet $path arrival] $slack $cost(${path_group}_min) $count(${path_group}_min) $significant_digits ""
  }
 
 
  set hier_cells [get_cells -quiet -hier * -filter "is_hierarchical == true"]
  set nonhier_cells [get_cells -quiet -hier * -filter "is_hierarchical == false"]
 
  display_cell_count_and_drcs [sizeof_collection $hier_cells] \
    [sizeof_collection $nonhier_cells] \
    [get_attribute -quiet $design area] \
    [sizeof_collection [get_pins -quiet -of $hier_cells]] \
    [sizeof_collection [get_pins -quiet -hier * -filter "is_hierarchical==false"]] \
    cost \
    count \
    $drc_list \
    $significant_digits \
    ""
 
} elseif {$pt_shell_mode == "primetime_master"} {
 
  global multi_scenario_message_verbosity_level
 
  set old_verbosity_level $multi_scenario_message_verbosity_level
  set multi_scenario_message_verbosity_level low
 
  if [info exists constraint_text] {
   unset constraint_text
  }
 
  if {$sh_product_version=="Z-2007.06"||$sh_product_version=="Z-2007.06-SP1"||$sh_product_version=="Z-2007.06-SP2"||$sh_product_version=="Z-2007.06-SP2-1"} {
    echo "Error: Aborting script execution! Due to a DMSA bug in Z-2007.06 versions prior to Z-2007.06-SP3 (STAR 9000188708),"
    echo "       this script will produce inconsistent and incorrect results. The bug is fixed in Z-2007.06-SP3 PrimeTime." 
    echo "       To use this script in DMSA mode, please use Z-2007.06-SP3 or later PrimeTime instead."
    return 0
  }
 
  echo "\n****************************************"
  echo "Report : qor"
  echo "Design : multi-scenario design"
  echo "Version: $sh_product_version"
  echo "Date   : [date]"
  echo "****************************************\n"
 
  get_distributed_variables -pre_commands \
    {redirect -variable constraint_text {report_constraint -all_violators -nosplit -significant_digits 5}} \
    constraint_text
 
  set max_paths [get_timing_paths -attributes "full_name slack path_group points arrival object object_class pin_direction is_port endpoint"]
  set min_paths [get_timing_paths -delay min -attributes "full_name slack path_group points arrival object object_class pin_direction is_port endpoint"]
 
  set old_scenario_list [current_scenario]
 
  foreach_in scenario $old_scenario_list {
    set first_scenario_name [get_object_name $scenario]
    break
  }
 
  current_scenario $first_scenario_name
 
  get_distributed_variables -pre_commands \
    {set hier_cells [get_cells -quiet -hier * -filter "is_hierarchical == true"]; \
     set nonhier_cells [get_cells -quiet -hier * -filter "is_hierarchical == false"]; \
     set hier_cells_count [sizeof_collection $hier_cells]; \
     set hier_pins_count [sizeof_collection [get_pins -quiet -of $hier_cells]]; \
     set nonhier_cells_count [sizeof_collection $nonhier_cells]; \
     set nonhier_pins_count [sizeof_collection [get_pins -quiet -hier * -filter "is_hierarchical==false"]]; \
     set area [get_attribute -quiet [current_design] area]; \
     } "hier_cells_count nonhier_cells_count hier_pins_count nonhier_pins_count area"
 
  current_scenario $old_scenario_list
 
  set multi_scenario_message_verbosity_level $old_verbosity_level
  set group ""
  foreach scenario [array names constraint_text] {
    foreach line [split $constraint_text($scenario) "\n"] {
      switch -regexp $line {
        {^ +(\S+ ?[\(\)a-zA-Z]*).* ([-\.0-9]+) +\(VIOLATED} {
          regexp {^ +(\S+ ?[\(\)a-zA-Z]*).* ([-\.0-9]+) +\(VIOLATED} $line full object slack
          set object [string trimright $object]
          if ![info exists slack_${group}($object)] {
            set slack_${group}($object) $slack
          } else {
            if [expr $slack < [set slack_${group}($object)]] {
              set slack_${group}($object) $slack
            }
            continue
          }
        }
        { *max_delay/setup.*'(.*)'} {
          regexp { *max_delay/setup.*'(.*)'} $line full group
          if ![info exists slack_$group] {
            array set slack_$group ""
            array set slack_$group ""
            set cost($group) 0
            set count($group) 0
            lappend group_list $group
          }
          continue
        }
        { *min_delay/hold.*'(.*)'} {
          regexp { *min_delay/hold.*'(.*)'} $line full group
          set group ${group}_min
          if ![info exists slack_$group] {
            array set slack_$group ""
            array set slack_$group ""
            set cost($group) 0
            set count($group) 0
            lappend group_list $group
          }
          continue
        }
        {^ *([a-zA-Z_]+) *$} {
          regexp {^ *([a-zA-Z_]+) *$} $line full group
          if {$group == "recovery"} {
            set group async_default
            if ![info exists slack_async_default] {
              lappend group_list async_default
	    }
          }
          if {$group == "removal"} {
            set group async_default_min
            if ![info exists slack_async_default_min] {
              lappend group_list async_default_min
            }
          }
          if ![info exists slack_$group] {
            if {$group != "max_area" && $group != "async_default" && $group != "async_default_min"} {
              lappend drc_list $group
            }
            array set slack_$group ""
            array set slack_$group ""
            set cost($group) 0
            set count($group) 0
          }
          continue
        }
      }
    }
  }
 
  foreach group "$group_list $drc_list" {
    foreach object [array names slack_$group] {
      set cost($group) [expr $cost($group) + [set slack_${group}($object)]]
      incr count($group)
    }
  }
 
  foreach_in_collection path [sort_collection $max_paths path_group] {
    set path_group [get_attribute -quiet [get_attribute -quiet $path path_group] full_name]
    if {$path_group == ""} {
      set path_group unconstrained
    }
    if {[regexp {\*\*[a-z_]*\*\*} $path_group full]} {
      set path_group [string map {\* ""} $path_group]
    }
    if {![info exists cost($path_group)]} {
      set cost($path_group) 0
      set count($path_group) 0
    }
 
    set levels [count_levels $path]
 
    set slack [get_attribute -quiet $path slack]
    set scenario_name [get_attribute $path scenario_name]
 
    echo "\n  Timing Path Group '$path_group' (max_delay/setup)"
    display_path_group $levels [get_attribute -quiet $path arrival] $slack $cost($path_group) $count($path_group) $significant_digits " ($scenario_name)"
  }
 
  echo ""
 
  foreach_in_collection path [sort_collection $min_paths path_group] {
    redirect $sh_dev_null {set path_group [get_attribute -quiet [get_attribute -quiet $path path_group] full_name]}
    if {$path_group == ""} {
      set path_group unconstrained
    }
    if {[regexp {\*\*[a-z_]*\*\*} $path_group full]} {
      set path_group [string map {\* ""} $path_group]
    }
    if {![info exists cost(${path_group}_min)]} {
      set cost(${path_group}_min) 0
      set count(${path_group}_min) 0
    }
 
    set levels [count_levels $path]
 
    set slack [get_attribute -quiet $path slack]
    set scenario_name [get_attribute $path scenario_name]
 
    echo "\n  Timing Path Group '$path_group' (min_delay/hold)"
    display_path_group $levels [get_attribute -quiet $path arrival] $slack $cost(${path_group}_min) $count(${path_group}_min) $significant_digits " ($scenario_name)"
  }
 
  display_cell_count_and_drcs $hier_cells_count($first_scenario_name) \
    $nonhier_cells_count($first_scenario_name) \
    $area($first_scenario_name) \
    $hier_pins_count($first_scenario_name) \
    $nonhier_pins_count($first_scenario_name) \
    cost \
    count \
    $drc_list \
    $significant_digits \
    " ($first_scenario_name)"
}
 
}
 
define_proc_attributes report_qor \
 -info "Report QoR" \
 -define_args {\
  {-physical "For compatibility with DC/ICC report_qor; ignored in PrimeTime" "" boolean optional}
  {-significant_digits "Precision level of report (range from 0 to 13)" "<digits>" int optional}
 }