# ==============================================================================
# Script: analyze_clock_path_final.tcl
# Description: Analyzes launch clock path, calculates insertion delay per module,
# sorts by path order, and reports cumulative delay.
# Supports command line argument for input filename.
# Usage: tclsh analyze_clock_path_final.tcl <input_file>
# Date: 2026-10-22
# ==============================================================================
proc parse_clock_path {filename} {
if {![file exists $filename]} {
error "File $filename not found."
}
set fid [open $filename r]
set content [read $fid]
close $fid
set lines [split $content "\n"]
set all_points {}
# Regex to match timing points
set point_pattern {^\s+([\w/.]+)\s+\(.*\)}
foreach line $lines {
# Stop at data arrival time or end of launch path
if {[string match "*data arrival time*" $line]} {
break
}
if {![regexp $point_pattern $line match full_path]} {
continue
}
# Extract numbers (Incr and Path Delay)
set nums [regexp -all -inline -- {[0-9]+\.[0-9]+} $line]
if {[llength $nums] >= 2} {
set incr [lindex $nums end-1]
set path_delay [lindex $nums end]
lappend all_points [list $full_path $incr $path_delay]
}
}
return $all_points
}
proc is_clock_pin {pin_name} {
set clock_pins {"CK" "CKN" "CLK" "CLKN" "C" "CN"}
foreach cp $clock_pins {
if {[string equal $pin_name $cp]} {
return 1
}
}
return 0
}
proc analyze_and_sort_modules {points} {
set module_delays {}
set module_cumulative {} ;# Dict to store the cumulative path_delay at the END of the module
foreach point $points {
set full_path [lindex $point 0]
set incr [lindex $point 1]
set path_delay [lindex $point 2]
set parts [split $full_path "/"]
set pin_name [lindex $parts end]
# Determine root module
if {[llength $parts] > 0} {
set root_module [lindex $parts 0]
} else {
continue
}
# Initialize if new module encountered
if {![dict exists $module_delays $root_module]} {
dict set module_delays $root_module 0.0
}
# Accumulate delay for the current module
set current_sum [dict get $module_delays $root_module]
dict set module_delays $root_module [expr {$current_sum + $incr}]
# Update the cumulative delay for this module to the current point's path_delay
dict set module_cumulative $root_module $path_delay
# Stop if we hit the register clock pin (End of Clock Path)
if {[is_clock_pin $pin_name]} {
break
}
}
# Prepare list for sorting: {{module_name module_delay cumulative_delay}}
set sort_list {}
dict for {mod del} $module_delays {
set cum [dict get $module_cumulative $mod]
lappend sort_list [list $mod $del $cum]
}
# Sort by 'cumulative_delay' (index 2) in increasing order (Source -> Sink)
set sorted_list [lsort -increasing -real -index 2 $sort_list]
return $sorted_list
}
proc generate_html_report {sorted_list output_file} {
set fid [open $output_file w]
puts $fid "<!DOCTYPE html>"
puts $fid "<html>"
puts $fid "<head>"
puts $fid "<title>Clock Path Module Analysis</title>"
puts $fid "<style>"
puts $fid "body { font-family: Arial, sans-serif; margin: 20px; background-color: #f4f4f9; }"
puts $fid "h1 { color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; }"
puts $fid "table { border-collapse: collapse; width: 100%; margin-top: 20px; background-color: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }"
puts $fid "th, td { border: 1px solid #ddd; padding: 12px 15px; text-align: left; }"
puts $fid "th { background-color: #007bff; color: white; }"
puts $fid "tr:nth-child(even) { background-color: #f9f9f9; }"
puts $fid ".note { font-size: 0.9em; color: #666; margin-top: 10px; }"
puts $fid "</style>"
puts $fid "</head>"
puts $fid "<body>"
puts $fid "<h1>Launch Clock Path: Module Insertion & Cumulative Delay</h1>"
puts $fid "<p class='note'>Modules are sorted by signal flow order (Clock Source → Sink).</p>"
puts $fid "<table>"
puts $fid "<tr><th>Order</th><th>Module Name</th><th>Module Insertion Delay (ns)</th><th>Cumulative Launch Delay (ns)</th></tr>"
set counter 1
foreach item $sorted_list {
set module [lindex $item 0]
set delay [lindex $item 1]
set cumulative [lindex $item 2]
puts $fid "<tr><td>$counter</td><td>$module</td><td>[format "%.4f" $delay]</td><td>[format "%.4f" $cumulative]</td></tr>"
incr counter
}
puts $fid "</table>"
puts $fid "</body>"
puts $fid "</html>"
close $fid
}
# Main execution
# Check for command line arguments
if {[llength $argv] < 1} {
puts "Usage: tclsh analyze_clock_path_final.tcl <input_file>"
exit 1
}
set input_file [lindex $argv 0]
set output_html "clock_analysis_report.html"
puts "Reading $input_file..."
set points [parse_clock_path $input_file]
if {[llength $points] == 0} {
puts "No points found."
exit 1
}
puts "Analyzing and sorting modules by path order..."
set sorted_list [analyze_and_sort_modules $points]
puts "Generating HTML report..."
generate_html_report $sorted_list $output_html
puts "Report generated: $output_html"
# Print summary to console
puts "\n--- Summary of Clock Insertion Delays (Ordered by Path Flow) ---"
puts [format "%-6s %-40s %15s %15s" "Order" "Module Name" "Mod. Insertion (ns)" "Cumulative (ns)"]
puts [string repeat "-" 80]
set counter 1
foreach item $sorted_list {
set module [lindex $item 0]
set delay [lindex $item 1]
set cumulative [lindex $item 2]
puts [format "%-6d %-40s %15.4f %15.4f" $counter $module $delay $cumulative]
incr counter
}