Ví dụ về Quartus® II Tcl: Báo cáo thời gian đường dẫn tùy chỉnh

author-image

Bởi

Các lệnh list_path report_timing Tcl rất mạnh mẽ, nhưng chúng có một số hạn chế. Điểm cuối đường dẫn phải là đồng hồ, chân hoặc thanh ghim. Ngoài ra, các lệnh đó không báo cáo mọi đường dẫn kết hợp giữa các điểm cuối. Ví dụ lệnh nâng cao này hỗ trợ thời gian báo cáo trên các đường dẫn tùy ý trong thiết kế của bạn (bao gồm cả điểm cuối kết hợp) và báo cáo tất cả các đường dẫn kết hợp giữa các điểm cuối. Kịch bản sử dụng thuật toán tìm kiếm định kỳ để tìm đường dẫn. Thuật toán dừng lại ở các chân và thanh ghi để ngăn chặn thời gian chạy quá mức.

Bạn có thể chỉ định tên nút, ký tự đại diện hoặc tên nhóm thời gian cho nguồn và đích. Lệnh này không hỗ trợ các trình loại trừ nhóm thời gian; một cảnh báo sẽ được hiển thị nếu bạn chỉ định một nhóm thời gian chứa các tính năng loại trừ cho điểm cuối và các trình loại trừ sẽ bị bỏ qua.

Bạn có thể định hướng đầu ra của lệnh sang tệp Giá trị phân tách dấu phẩy (.csv). Tên tệp mặc định là p2p_timing.csv. Ngoài ra, bạn có thể chuyển đầu ra của lệnh sang một bảng trong báo cáo thời gian của dự án. Tên bảng mặc định là Thời gian điểm-điểm.

quartus_tan -t p2p_timing.tcl -project < tên dự án> -từ tên <node|wildcard|timegroup tên> -đến tên <node| |wildcard|timegroup tên> [-write_file] [-file <output file name>] [-write_panel] [-panel < tên bảng điều khiển>]

Nếu bạn muốn chuyển đầu ra sang một tệp khác với tên tệp mặc định, bạn phải xác định cả tên tệp -write_file và -file <tộ tin > tin. Nếu bạn muốn chuyển đầu ra đến bảng báo cáo khác với tên bảng báo cáo mặc định, bạn phải xác định cả tên bảng điều khiển -write_panel và bảng điều khiển <điểm báo cáo> tùy chọn.

Sao chép các lệnh Tcl sau vào một tệp và đặt tên nó p2p_timing.tcl.

gói yêu cầu cmdline 
load_package advanced_timing 
load_package báo cáo 

quartus toàn cầu 
biến::argv0 $::quartus(args) 

tùy chọn bộ { \ 
   { "from.arg" "" "" "Tên nút nguồn" } \ 
   { "to.arg" "" "" "Tên nút Điểm đến" } \ 
   { "project.arg" "" "Tên dự án" } \ 
   { "file.arg" "p2p_timing.csv" "Tên tệp csv đầu ra" } \ 
   { "write_file" "" "Viết đầu ra vào tệp" } \ 
   { "panel.arg" "Thời gian điểm-điểm" "Tên bảng báo cáo" } \ 
   { "write_panel" "" "Viết đầu ra vào bảng báo cáo" } \ 
} 

opts bộ mảng [::cmdline::getoptions ::argv0 $options "Tùy chọn hỏng hở"] 
############################################################## 
# 
# Trả về danh sách các tên nút và ID nút tương ứng 
# cho các tên thiết kế phù hợp với tham số mẫu. 
# Bất kỳ mẫu nào không khớp với tên trong thiết kế đều có một 
# danh sách trống được trả lại 
# Ví dụ: Chuyển vào "đặt lại" và nhận { đặt lại 3 } trở lại 
# 
############################################################## 
proc get_node_ids { pattern } { 
   tập hợp mảng name_to_node [danh sách] 

nếu { [chuỗi bằng "" $pattern] } { 
      trả lại [danh sách] 
   }

# Mẫu có thực sự là tên của một nhóm thời gian không? 
   # Nếu có, kịch bản sẽ được lập trình định kỳ cho các thành viên của 
   # nhóm thời gian. 
   đặt thành viên [get_all_global_assignments -name TIMEGROUP_MEMBER -section_id $pattern] 

# Nếu có bất kỳ thành viên nào trong bộ sưu tập, 
   # pattern là một nhóm thời gian 
   nếu { 0 < [get_collection_size $members]} { 
      # Cảnh báo nếu có sự loại trừ, vì kịch bản 
      # bỏ qua trình loại trừ 
      nếu {0 < [get_collection_size [get_all_global_assignments -name TIMEGROUP_EXCLUSION -section_id $pattern]] } { 
         post_message báo kiểu -type "Bỏ qua các trình điều khiển không thể loại bỏ trong trình điều khiển $pattern" 
      } 

# Đi qua từng mục trong nhóm thời gian. 
      foreach_in_collection tập $members { 
         # Mỗi hạng mục trong bộ sưu tập là một danh sách như sau: 
         # {$pattern} {TIMEGROUP_MEMBER} {node/real pattern} 
         tập hợp mảng sub_collection_names [get_node_ids [lindex $assignment 2]] 

quản lý node_name [tên mảng sub_collection_names] { 
            đặt name_to_node($node_name) $sub_collection_names($node_name) 
         } 
      } 
   } khác { 
      # Nó không phải là một nhóm thời gian 
      # Sao lưu qua tất cả các nút thời gian trong thiết kế, 
      # kiểm tra xem tên có khớp với kiểu hình được chỉ định hay không 
      foreach_in_collection node_id [get_timing_nodes -gõ tất cả] { 
         đặt node_name [get_timing_node_info -info name $node_id] 
         nếu { [khớp chuỗi [escape_brackets $pattern] $node_name] } { 
            đặt name_to_node($node_name) $node_id 
         } 
      } 
   } 
   trở lại [array get name_to_node]
} 

############################################################## 
# 
# Quy trình này tìm ra đường dẫn kết hợp giữa một nguồn 
Nút # và danh sách các nút đích. Nó trả về danh sách các 
# đường dẫn giữa các nút. Mỗi đường dẫn được tạo thành một ba lần 
Số ID nút, độ trễ liên kết và độ trễ ô từ 
# nút trước đó. 
# Quy trình ngừng đi qua danh sách mạng tại một thanh ghi 
# hoặc chân, vì vậy nó không tìm thấy đường dẫn đi qua thanh ghi. 
#
############################################################## 
proc find_combinational_paths_between {queue dest_nodes} { 
   thiết lập num_iterations 0 
   đường dẫn thiết lập [danh sách] 
   
trong khi {0 < [llength $queue]} { 
      # Báo cáo tiến độ của vòng lặp hàng ngàn lần 
      # inerations incr num_iterations 
      nếu { 1000 == $num_iterations } { 
         thiết lập num_iterations 0 
         post_message "Kiểm tra đường dẫn [llength $queue]." 
      } 
      
# Mở đường dẫn đầu tiên từ hàng đợi. 
      # Lần đầu tiên quy trình được gọi là, hàng đợi 
      # chỉ là một số, nút nguồn. 
      đường dẫn thiết lập [lindex $queue 0] 
      thiết lập hàng đợi [lrange $queue 1 đầu] 
      
# Nhận nút cuối cùng trong đường dẫn, sau đó trong vòng lặp foreach 
      # nhận fanout từ nút đó 
      đặt last_triplet_in_path [lindex $path cuối] 
      đặt last_node_in_path [lindex $last_triplet_in_path 0] 
 
# Trích xuất chỉ id nút trong đường dẫn hiện tại. 
      # Mục này được sử dụng sau này để đảm bảo các vòng lặp không bị lỗi thời. 
      đặt nodes_in_path [collapse_triplets_to_node_list $path] 

# Nhận tất cả các fanouts của nút cuối cùng trong đường dẫn này và thực hiện 
      # các đường dẫn mới với họ để đẩy hàng đợi. 
      foreach n [get_timing_node_fanout $last_node_in_path] { 
         đi trước { node_id ic_delay cell_delay } $n { 
            Phá vỡ 
         }
 
nếu { -1 != [lsearch $dest_nodes $node_id] } { 
            # Nếu nút này trong đường dẫn có trong danh sách 
            # các nút đích, có một đường dẫn. 
            # Thêm nó vào danh sách các đường dẫn giữa các nút 
            đặt new_path $path lappend 
            new_path $n 
            đường dẫn lappend $new_path 
         } 

nếu { -1 == [$nodes_in_path $node_id] } { 
            # Nếu nút này trong đường dẫn không ở trong đường dẫn 
            # đã rồi, đây không phải là một vòng lặp. Đẩy nó lên 
            # queue if it is a combinational or clock node. Hàng đợi nếu nó là một nút kết hợp hoặc đồng hồ. 
            # Đường dẫn không được bật nếu nút này là một 
            # đăng ký hoặc chân. 
            # Đẩy một con đường mới trên hàng đợi như thế này, 
            # mặc dù nút này trong đường dẫn có thể phù hợp 
            # một nút cuối, đảm bảo thời gian dài nhất có thể 
            # paths được tìm thấy. 
            đặt node_type [get_timing_node_info -info type $node_id] 
            switch -exact -- $node_type { 
               lược - 
               clk { 
                  đặt next_path $path 
                  Gửi next_path $n 
                  lappend queue $next_path 
               } 
               mặc định { 
               } 
            } 
         } 
      }
   }
   trả lại $paths 
} 

############################################################## 
# 
# Thêm hai số độ trễ và trả về kết quả. 
# Số độ trễ ở dạng "đơn vị giá trị" trong đó các đơn vị 
# có thể là nano giây (ns) hoặc picosecond (ps) và giá trị có thể 
# x{1,3} nếu đơn vị là picosecond, hoặc x+.y{1,3} nếu đơn vị 
# đơn vị là nano giây. Quy trình này chuẩn hóa độ trễ thành 
# nano giây và thêm các giá trị. 
# Ví dụ: add_delays "1.234 ns" "56 ps" # 
############################################################## 
proc add_delays { a b } { 
   nếu { ![ regexp {^([\d\.] +)\s+([np]s)$} $a khớp a_value a_unit] } { 
      post_message lỗi kiểu "Không xác định được các bộ phận của thời gian: $a" 
   } 

nếu { ![ regexp {^([\d\.] +)\s+([np]s)$} $b ứng b_value b_unit] } { 
      post_message lỗi kiểu "Không xác định được các bộ phận của thời gian: $b" 
   } 
  
# Chuyển đổi mọi thứ thành nano giây nếu cần 
   nếu { [chuỗi bằng -nocase ps $a_unit] } { 
      đặt a_value_ps [định dạng "%.3f" $a_value] 
      đặt a_value [định dạng "%.3f" [expr { $a_value_ps / 1000 }]] 
   } 

nếu { [chuỗi bằng -nocase ps $b_unit] } { 
      đặt b_value_ps [định dạng "%.3f" $b_value] 
      đặt b_value [định dạng "%.3f" [expr { $b_value_ps / 1000 }]] 
   } 

# Bây giờ các đơn vị bằng nhau và nano giây. 
   # Chỉ cần thêm các số vào nhau. 
   đặt sum_value [định dạng "%.3f" [expr { $a_value + $b_value }]] 
  
trả lại "$sum_value ns" 
} 

############################################################## 
# 
# Định dạng và in các tên nút trong đường dẫn với  
# Độ trễ giữa các nút. 
# 
############################################################## 
proc print_path_delays { path {iteration first}} { 
   đặt source_triplet [lindex $path 0] 
   đặt source_node [lindex $source_triplet 0] 
   đặt source_node_name [get_timing_node_info -info name $source_node] 
   đặt source_node_loc [get_timing_node_info -info location $source_node] 
   
# In độ trễ trước 
   nếu { [chuỗi bằng "đầu tiên" $iteration] } { 
      accumulate_data [danh sách "IC(0,000 ns)" "CELL(0,000 ns)"] 
   } khác { 
      đặt ic_delay [lindex $source_triplet 1] 
      đặt cell_delay [lindex $source_triplet 2] 
      accumulate_data [danh sách "IC($ic_delay)" "CELL($cell_delay)"] 
   } 
   accumulate_data [list $source_node_loc $source_node_name] 
   print_accumulated_data 

# Định kỳ trên phần còn lại của đường dẫn 
   nếu { 1 < [llength $path] } { 
      print_path_delays [lrange $path 1 đầu] khác 
   } 
} 

############################################################## 
# 
# Tổng độ trễ IC và ô trên đường dẫn được chỉ định và 
# trả về danh sách có tổng độ trễ kết nối và tổng ô 
# Độ trễ. 
# 
############################################################## 
proc end_to_end_delay { đường dẫn } { 
   đặt ic_total "0,000 ns" 
   đặt cell_total "0,000 ns" 
   
# Nó sẽ đi qua các nút 1 để kết thúc trong đường dẫn vì 
   # nút đầu tiên trong đường dẫn là nguồn và từng nút trong đường dẫn 
   # path chứa độ trễ từ nút trước nó. Các 
   # source không có nút nào trước nó, vì vậy nó không có độ trễ. 
   foreach n [lrange $path 1 end] { 
      đi trước { node_id ic_delay cell_delay } $n { 
         Phá vỡ 
      } 
      đặt ic_total [add_delays $ic_total $ic_delay] 
      đặt cell_total [add_delays $cell_total $cell_delay] 
   } 

trả lại [list $ic_total $cell_total] 
} 

##############################################################
# 
# Đảm bảo nguồn và điểm đến được chỉ định tồn tại trong 
# thiết kế, tìm ra những đường dẫn kết hợp giữa chúng và 
# in các đường dẫn. 
# 
############################################################## 
proc find_paths_and_display { dest nguồn } { 
   nguồn bộ mảng [get_node_ids $source] 
   dests bộ mảng [get_node_ids $dest] 

đặt nodes_exist 1 

# Đảm bảo các nút có tên tồn tại 
   nếu { 0 == [llength [array get sources]] } { 
      đặt nodes_exist 0 
      post_message lỗi kiểu "Không tìm thấy nút khớp với $source trong thiết kế của bạn". 
   } 
   nếu { 0 == [llength [array get dests]] } { 
      đặt nodes_exist 0 
      post_message lỗi kiểu "Không tìm thấy nút khớp với $dest trong thiết kế của bạn". 
   } 

# Nếu họ muốn, hãy tìm đường dẫn.   nếu { $nodes_exist } { 
      # Nhận danh sách id nút điểm đến 
      đặt dest_node_ids [danh sách] 
      foreach d [tên mảng dests] { 
         Lappend dest_node_ids $dests($d) 
      } 

# Xem qua tất cả các nút 
      foreach s [nguồn tên mảng] { 
         thiết lập đường dẫn [find_combinational_paths_between $sources($s) $dest_node_ids] 
         nếu { 0 == [llength $paths] } {  
            post_message "Không có đường dẫn kết hợp nào tồn tại từ $s đến $dest" 
         } khác { 
            đường dẫn trước $paths { 
               # In đường dẫn 
               print_path_delays $path 

# Tổng hợp độ trễ liên kết và ô và 
               # in chúng ra dưới đường dẫn. 
               foreach {total_ic_delay total_cell_delay } [end_to_end_delay $path] { 
                  Phá vỡ 
               } 
               accumulate_data [list $total_ic_delay $total_cell_delay] 
               accumulate_data [danh sách [add_delays $total_ic_delay $total_cell_delay]] 

# Có hai cuộc gọi đến print_accumulated_data 
               # here, one to print the sums of the interconnect 
               # và độ trễ ô, và một ô để tạo ra một khoảng trống 
               # line in the output. 
               print_accumulated_data print_accumulated_data 
            } 
         } 
      }
   } 
} 

############################################################## 
# 
# Một đường dẫn được tạo thành từ gấp ba lần thông tin - id nút, 
# độ trễ kết nối và độ trễ ô. Trích xuất quy trình này 
# id nút từ mỗi bộ ba theo thứ tự và trả về danh sách 
Số id nút 
# 
############################################################## 
proc collapse_triplets_to_node_list { l } { 
   đặt to_return [danh sách] 
   máy tính ba $l { 
      Lappend to_return [lindex $triplet 0] 
   } 
   trả $to_return 
} 

############################################################## 
# 
# Kết hợp thông tin với một biến toàn cầu để chuẩn bị 
# cho nó đang được in ra. 
# 
############################################################## 
proc accumulate_data { dữ liệu } { 
   tích lũy toàn cầu [concat $accum $data] 
}
 
############################################################## 
# 
# In các dữ liệu đã được truy xuất. 
# Nó được in thành tiêu chuẩn ra và tùy chọn vào một tập tin trong 
# Định dạng CSV nếu tệp tồn tại và tùy chọn 
# bảng báo cáo nếu bảng báo cáo tồn tại (không phải là giá trị -1) 
# 
############################################################## 
proc print_accumulated_data {} { 
   tích lũy toàn cầu fh panel_id 
   đặt [tham gia $accum ","] 

# Ghi vào một tập tin? 
   nếu { [thông tin tồn tại fh] } { 
      đặt $fh [tham gia $accum ","] 
   } 

# Thêm nó vào bảng báo cáo? 
   nếu { -1 != $panel_id } { 
      # Nếu hàng bảng báo cáo không có 4 mục 
      # trong đó, đệm nó lên 4. 
      trong khi { 4 > [llength $accum] } { 
         phụ lục tích lũy [danh sách] 
      } 
      add_row_to_table -id $panel_id $accum 
   } 
   # Xóa thông tin trong biến toàn cầu. 
   bộ tích lũy [danh sách] 
}

############################################################## 
############################################################## 
# 
# Kết thúc quy trình, bắt đầu tập lệnh 
# 
############################################################## 
##############################################################
# 
# Các biến toàn cầu để lưu giữ dữ liệu để in ấn và bảng điều khiển 
ID số cho bảng báo cáo tùy chọn 

bộ tích lũy [danh sách] 
đặt panel_id -1 

nếu { [chuỗi bằng "" $opts(dự án)] } { 
   # Tùy chọn sử dụng bản in nếu lệnh được gọi là không có 
   # đối số 
   puts [::cmdline::usage $options] 
} elseif { [chuỗi bằng "" $opts(project)] } { 
   post_message -type lỗi "Xác định dự án có tùy chọn -project." 
} elseif { ! [project_exists $opts(dự án)] } { 
   post_message -type lỗi "Project $opts(project) không tồn tại trong thư mục này." 
} elseif { [chuỗi bằng "" $opts(từ)] } { 
   post_message -type lỗi "Xác định tên hoặc mẫu ký tự đại diện với tùy chọn -from." 
} elseif { [chuỗi bằng "" $opts(sang)] } { 
   post_message -type lỗi "Xác định một tên hoặc mẫu ký tự đại diện với tùy chọn -to." 
} khác { 
   đặt cur_revision [get_current_revision $opts(dự án)] 
   project_open $opts(project) -revision $cur_revision 

# Cố gắng tạo danh sách thời gian. Lệnh này sẽ bị lỗi 
   # nếu quartus_fit chưa được chạy, ví dụ. 
   nếu { [nắm bắt { create_timing_netlist } msg ] } { 
      post_message lỗi kiểu $msg 
   } khác { 

# Chuẩn bị để ghi đầu ra vào một tập tin nếu cần 
      nếu { 1 == $opts(write_file) } { 
         nếu { [nắm bắt {mở $opts(tệp) w} fh] } { 
            post_message lỗi kiểu "Không thể mở $opts(write_file): $fh" unset fh 
         } khác { 
            post_message "Ghi đầu ra $opts(tập tin)" 
            # Thêm một số thông tin giới thiệu vào tệp đầu ra 
            đặt "$fh Report of paths from $opts(from) to $opts(to)" (Báo cáo đường dẫn) $opts(đến)" 
            đặt $fh "Được tạo trên [định dạng đồng hồ [số giây đồng hồ]]" 
            đặt $fh "" đặt $fh "độ trễ IC, độ trễ ô, vị trí nút, tên nút" 
         } 
      } 

# Chuẩn bị để ghi đầu ra vào một bảng báo cáo nếu cần 
      nếu { 1 == $opts(write_panel) } { 
         # Tải báo cáo, xóa bảng điều khiển nếu nó đã tồn tại, 
         # tạo một bảng điều khiển mới và thêm hàng tiêu đề. 
         load_report 
         đặt panel_id [get_report_panel_id "Phân tích Thời gian|| $opts(bảng điều khiển)"] 
         nếu { -1 != $panel_id } { 
            delete_report_panel -id $panel_id 
         } 
        đặt panel_id [create_report_panel -table "Bộ phân tích thời gian|| $opts(bảng điều khiển)"] 
        add_row_to_table -id $panel_id [danh sách "độ trễ IC" "Độ trễ ô" "Vị trí nút" "Tên nút"] 
      } 
      find_paths_and_display $opts(từ) $opts(đến) 

# đóng tập tin đầu ra nếu cần 
      nếu { [thông tin tồn tại fh] } { đóng $fh } 

# Lưu bảng báo cáo nếu cần 
      nếu { -1 != $panel_id } { 
         save_report_database 
         unload_report 
      } 
   } 
   project_close 
}    

Nội dung gốc bằng tiếng Anh trên trang này vừa do con người vừa do máy dịch. Nội dung này chỉ để cung cấp thông tin chung và giúp quý vị thuận tiện. Quý vị không nên tin đây là thông tin hoàn chỉnh hoặc chính xác. Nếu có bất kỳ mâu thuẫn nào giữa bản tiếng Anh và bản dịch của trang này, thì bản tiếng Anh sẽ chi phối và kiểm soát. Xem phiên bản tiếng Anh của trang này.