Los comandos list_path y report_timing Tcl son muy potentes, pero tienen algunas limitaciones. Los puntos de conexión de la ruta deben ser relojes, pines o registros. Además, esos comandos no informan cada ruta de combinación entre los puntos de conexión. Este ejemplo de script avanzado admite la temporización de informes en rutas arbitrarias en su diseño (incluidas las terminales de combinación) e informa todas las rutas de combinación entre puntos de conexión. El script utiliza un algoritmo de búsqueda iterativa para encontrar rutas. El algoritmo se detiene en pines y registros para evitar tiempos de ejecución excesivos.
Puede especificar los nombres de nodo, las nomenclaturas o los nombres de grupos de tiempo para la fuente y el destino. Este script no admite exclusiones de grupos de tiempo; se muestra una advertencia si se especifica un grupo de tiempo que contiene exclusiones para las terminales y las exclusiones son poco apropiadas.
Puede dirigir el resultado del script a un archivo de valor separado por coma (.csv). El nombre de archivo predeterminado es p2p_timing.csv. Además, puede dirigir el resultado del script a un panel en el informe de sincronización de su proyecto. El nombre predeterminado del panel es Sincronización de punto a punto.
quartus_tan -t p2p_timing.tcl -project <project name>-from <node name|wildcard|timegroup name> -to <node name|wildcard|timegroup name> [-write_file] [-file <output file name>] [-write_panel] [-panel <report name>]
Si desea dirigir el resultado a un archivo diferente al nombre de archivo predeterminado, debe especificar las opciones -write_file y -file <output file name>. Si desea dirigir el resultado a un panel de informe diferente al nombre del panel de informe predeterminado, debe especificar las opciones -write_panel y -panel <report name>.
Copie los siguientes comandos de Tcl en un archivo y nombreelo p2p_timing.tcl.
paquete require cmdline load_package advanced_timing informe load_package quartus global variable::00 usd::quartus(vd.) establecer opciones { \ { "from.exclam" "" "Nombre del nodo de origen" } \ { "to...." "" "" "Nombre del nodo de destino" } \ { "project...."" "" "Nombre del proyecto" } \ { "file.exclam" "p2p_timing.csv" "Output csv file name" } \ { "write_file" "" "" "Escriba el resultado en un archivo" } \ { "panel.preconfigurado" "Sincronización de punto a punto" "Nombre del panel de informe" } \ { "write_panel" "" "" "Escriba el resultado en un panel de informes" } \ } conjunto de matrices opts [::cmdline::get corrientes::vd. 00 $options "Opción mala"] ############################################################## # # Devuelve una lista de nombres de nodos y los identificadores de nodo correspondientes Cantidad de nombres de diseño que coinciden con el argumento de patrón. # Cualquier patrón que no coincida con los nombres en el diseño tiene un # lista vacía devuelta # Ejemplo: Vuelva a pasar el "reset" y obtenga { reset 3 } # ############################################################## proc get_node_ids { patrón } { conjunto de matrices name_to_node [list] if { [cadena igual a "" $pattern] } { devolver [lista] } # ¿Es el patrón en realidad el nombre de un grupo de tiempo? # Si lo es, entonces el script se lleva a los miembros de No. el grupo de tiempo. establecer miembros [get_all_global_assignments -name TIMEGROUP_MEMBER -section_id $pattern] # Si hay algún miembro de la colección, # el patrón es un grupo de tiempo if { 0 < [get_collection_size $members]} { # Desatado si hay exclusiones, porque el script # omite exclusiones if {0 < [get_collection_size [get_all_global_assignments -name TIMEGROUP_EXCLUSION -section_id $pattern]] } { post_message advertencia de tipo "Exclusiones de riesgo en el $pattern de grupos de tiempo" } # Pase por cada elemento del grupo de tiempo. $members de asignación de foreach_in_collection { # Cada elemento de la colección es una lista como esta: # {$pattern} {TIMEGROUP_MEMBER} {nodo/patrón real} conjunto de matrices sub_collection_names [get_node_ids [lindex $assignment 2]] foreconferencia node_name [nombres de matriz sub_collection_names] { establecer name_to_node($node_name) $sub_collection_names($node_name) } } } else { # No es un grupo de tiempo # Iteración a través de todos los nodos de temporización en el diseño, # comprobando si el nombre coincide con el patrón especificado foreach_in_collection node_id [get_timing_nodes -type all] { establezca node_name [get_timing_node_info -info name $node_id] if { [cadena de coincidencia [escape_brackets $pattern] $node_name] } { establezca name_to_node($node_name) $node_id } } } return [array get name_to_node] } ############################################################## # # Este procedimiento encuentra rutas de combinación entre una fuente N.° nodo y una lista de nodos de destino. Devuelve una lista de Cantidad de rutas entre los nodos. Cada ruta se compone de un triplete Cantidad de ID del nodo, demora de interconexión y demora de celda desde el N.° nodo anterior. # El procedimiento deja de recorrer la lista de redes en un registro No. o pin, de modo que no encuentre rutas que pasen por los registros. # ############################################################## proc find_combinational_paths_between {queue dest_nodes} { configure num_iterations 0 establecer rutas [list] mientras {0 < [$queue]} { Nº de informes sobre el progreso del bucle cada mil Cantidad de iteraciones num_iterations incr if { 1000 == $num_iteraciones } { configure num_iterations 0 post_message "Comprobar las rutas [$queue]". } # Pop la primera ruta de la cola. # La primera vez que se llama al procedimiento, la cola El número es solo un número, el nodo fuente. establecer ruta [lindex $queue 0] establecer cola [lrange $queue 1 end] # Obtenga el último nodo en la ruta de acceso, a continuación, en el bucle foreconferenci # obtenga ventilador de ese nodo establecer last_triplet_in_path [final de $path de lindex] establecer last_node_in_path [lindex $last_triplet_in_path 0] # Extraiga solo los identificadores de nodo en la ruta actual. # Esto se utiliza más tarde para garantizar que los bucles no se acelerán. establecer nodes_in_path [collapse_triplets_to_node_list $path] # Obtenga todos los ventiladores del último nodo en esta ruta y haga N.° nuevas rutas con ellas para empujar la cola. forecontinu n [get_timing_node_fanout $last_node_in_path] { fore,{node_id ic_delay cell_delay } $n { Romper } if { -1 != [lsearch $dest_nodes $node_id] } { # Si este nodo de la ruta está en la lista de Cantidad de nodos de destino, hay una ruta de acceso. # Agréguelo a la lista de rutas entre los nodos configure new_path $path lappend new_path $n rutas lappend $new_path } if { -1 == [lsearch $nodes_in_path $node_id] } { # Si este nodo de la ruta no está en la ruta de acceso # ya, esto no es un bucle. Empuje sobre el Cantidad de cola si es un nodo combinado o de reloj. # La ruta no se inserta si este nodo es un N.° de registro o pin. # Empujando una nueva ruta en la cola como esta, # aunque este nodo de la ruta podría coincidir # un nodo final, garantiza el mayor tiempo posible Se encuentran el número de rutas. establezca node_type [tipo de get_timing_node_info -info $node_id] switch -exact -- $node_type { comb - clk { configure next_path $path lappend next_path $n lappend queue $next_path } predeterminado { } } } } } devolución $paths } ############################################################## # # Agrega dos números de demora y devuelve el resultado. # Los números de demora se encuentran en la forma "unidades de valor" donde las unidades El número puede ser nanosegundos (ns) o picosegundos (ps), y el valor puede no sea x{1,3} si las unidades son picosegundo, o x+.y{1,3} si el Cantidad de unidades son nanosegundos. Este procedimiento normaliza las demoras Cantidad de nanosegundos y agrega los valores. # Ejemplo: add_delays N.° de "1.234 ns" "56 ps" ############################################################## proc add_delays { a b } { if { ![ regexp {^([\d\.] +)\s+([ctrl]s)$} $a coincidencia a_value a_unit] } { post_message error de tipo "No se pudo determinar partes del tiempo: $a" } if { ![ regexp {^([\d\.] +)\s+([ctrl]s)$} $b coincidencia b_value b_unit] } { post_message error de tipo "No se pudo determinar partes del tiempo: $b" } # Convierta todo a nanosegundos si es necesario if { [cadena igual a -nocase ps $a_unit] } { establecer a_value_ps [formatear "%.3f" $a_value] establezca a_value [formatear "%.3f" [expr { $a_value_ps / 1000 }]] } if { [cadena igual a -nocase ps $b_unit] } { establecer b_value_ps [formatear "%.3f" $b_value] establezca b_value [formatear "%.3f" [expr { $b_value_ps / 1000 }]] } # Ahora las unidades son iguales y nanosegundos. # Simplemente agregue los números juntos. establezca sum_value [formatear "%.3f" [expr { $a_value + $b_value }]] devolver "$sum_value ns" } ############################################################## # # Formatea e imprima los nombres de nodos en la ruta con el Cantidad de demoras entre los nodos. # ############################################################## proc print_path_delays { ruta {iteración first}} { establecer source_triplet [lindex $path 0] establecer source_node [lindex $source_triplet 0] establezca source_node_name [get_timing_node_info -info name $source_node] establezca source_node_loc [get_timing_node_info -info location $source_node] # Imprima primero las demoras if { [cadena igual a "first" $iteration] } { accumulate_data [enumerar "IC(0.000 ns)" "CELL(0.000 ns)"] } else { establecer ic_delay [lindex $source_triplet 1] establecer cell_delay [lindex $source_triplet 2] accumulate_data [enumerar "IC($ic_delay)" "CELL($cell_delay)"] } accumulate_data [list $source_node_loc $source_node_name] print_accumulated_data Cantidad de recurse en el resto de la ruta if { 1 < [$path] } { print_path_delays [lrange $path 1 extremo] otro } } ############################################################## # Cantidad de demoras de IC y celda en la ruta especificada y # devuelve una lista con demora total de interconexión y celda total Cantidad de demora. # ############################################################## proc end_to_end_delay { path } { configure ic_total "0.000 ns" configure cell_total "0.000 ns" # Esto pasa por los nodos 1 para finalizar en la ruta porque el El primer nodo de la ruta es la fuente y cada nodo en el La ruta # contiene las demoras del nodo anterior. El La fuente no tiene ningún nodo que lo preceda, por lo que no tiene demoras. fore\n [lrange $path 1 end] { fore,{node_id ic_delay cell_delay } $n { Romper } establecer ic_total [add_delays $ic_total $ic_delay] establecer cell_total [add_delays $cell_total $cell_delay] } devolver [list $ic_total $cell_total] } ############################################################## # # Garantiza que la fuente y los destinos especificados existan en el # diseño, encuentra las rutas de combinación entre ellos, y Cantidad de impresiones de las rutas. # ############################################################## proc find_paths_and_display { source dest } { array establecer fuentes [get_node_ids $source] dests del conjunto de matrices [get_node_ids $dest] configure nodes_exist 1 # Asegúrese de que existan los nodos con nombre if { 0 == [llength [array get sources]] } { configure nodes_exist 0 post_message error de tipo "No se encontró ningún nodo que coincida con $source en su diseño". } if { 0 == [llength [array get dests]] } { configure nodes_exist 0 post_message error de tipo "No se encontró ningún nodo que coincida con $dest en su diseño". } # Si lo hacen, encuentre vías. if { $nodes_exist } { # Obtenga la lista de identificadores de nodo de destino establecer dest_node_ids [list] foreconferencia d [dests de name array] { lappend dest_node_ids $dests($d) } # Pase por todos los nodos forecad s [array names sources] { establecer rutas [find_combinational_paths_between $sources($s) $dest_node_ids] if { 0 == [$paths de desconexión] } { post_message "No existe ninguna ruta combinada de $s a $dest" } else { $paths de ruta foredhes { # Imprima el recorrido print_path_delays $path Cantidad de demoras en interconexión y celdas y No. impríbalos por debajo del camino. foreconferencia {total_ic_delay total_cell_delay } [end_to_end_delay $path] { Romper } accumulate_data [list $total_ic_delay $total_cell_delay] accumulate_data [list [add_delays $total_ic_delay $total_cell_delay]] # Hay dos llamadas a print_accumulated_data # aquí, uno para imprimir las sumas de la interconexión Cantidad y demoras en celdas, y uno para generar un número en blanco N.° línea en el resultado. print_accumulated_data print_accumulated_data } } } } } ############################################################## # # Una ruta se compone de triples de información - id de nodo, Cantidad de demora de interconexión y demora de celda. Este procedimiento se extrae # el id de nodo de cada triplete en orden y devuelve una lista Cantidad de identificadores de nodo # ############################################################## proc collapse_triplets_to_node_list { l } { establecer to_return [list] $l triplete fore,{ lappend to_return [lindex $triplet 0] } return $to_return } ############################################################## # Cantidad de información de Bytes a una variable global en preparación No. para que se imprima. # ############################################################## proc accumulate_data { datos } { política global de política global [concat $accum $data] } ############################################################## # # Imprima los datos acumulados. # Está impreso en la salida estándar y opcionalmente en un archivo en Cantidad de formato CSV si existe el identificador de archivo y, opcionalmente, en un Cantidad de panel de informe si existe el panel de informe (no es un valor de -1) # ############################################################## proc print_accumulated_data {} { global fh panel_id pone [unirse a $accum ","] # Escriba en un archivo? if { [info existe fh] } { pone $fh [unirse a $accum ","] } # ¿Agregarlo al panel de informes? if { -1 != $panel_id } { # Si la fila del panel de informes no tiene 4 elementos # en él, ajádalo a 4. while { 4 > [$accum de desconexión] } { lappend ensaíchate [lista] } add_row_to_table -id $panel_id $accum } # Borre la información de la variable global. set se resonó [lista] } ############################################################## ############################################################## # # Fin de los procedimientos, comienzo del script # ############################################################## ############################################################## # # Variables globales que sostienen los datos para el panel # ID de un panel de informe opcional set se resonó [lista] configure panel_id -1 if { [cadena igual a "" $opts(proyecto)] } { # Opciones de uso de impresión si se llama al script sin Cantidad de argumentos pone [::cmdline::$options de uso] } elseif { [cadena igual a "" $opts(proyecto)] } { post_message error de tipo -"Especificar un proyecto con la opción -project". } elseif { ! [project_exists $opts(proyecto)] } { post_message error de tipo "El proyecto $opts(proyecto) no existe en este directorio". } elseif { [cadena igual a "" $opts(from)] } { post_message error -type "Especificar un patrón de nombre o de patrón de consignación con la opción -from". } elseif { [cadena igual a "" $opts(to)] } { post_message error de tipo -type "Especificar un patrón de nombre o patrón de consignación con la opción -to". } else { establecer cur_revision [get_current_revision $opts(proyecto)] project_open $opts(proyecto) -revision $cur_revision # Intente crear la lista de redes de temporización. Este comando fallaría # si todavía no se ha ejecutar quartus_fit, por ejemplo. if { [catch { create_timing_netlist } nombre de archivo ] } { $msg de error tipo post_message } else { # Prepárese para escribir el resultado en un archivo, si es necesario if { 1 == $opts(write_file) } { if { [catch {open $opts(file) w} fh] } { post_message error "No se pudo abrir $opts(write_file): $fh" no se pudo abrir fh } else { post_message "Salida de escritura a $opts(archivo)" # Agregue información introductoria al archivo de resultados pone $fh "Informe de rutas de $opts(de) a $opts(a)" pone $fh "Generado en [formato de reloj [segundos de reloj]]" pone $fh "" pone $fh "retraso de IC, demora de celda, ubicación del nodo, nombre del nodo" } } # Prepárese para escribir el resultado en un panel de informes, si es necesario if { 1 == $opts(write_panel) } { # Cargue el informe, elimine el panel si ya existe, # cree un panel nuevo y añada la fila de encabezado. load_report establezca panel_id [get_report_panel_id "Timing Analyzer|| $opts(panel)"] if { -1 != $panel_id } { delete_report_panel -id $panel_id } establezca panel_id [create_report_panel -table "Timing Analyzer|| $opts(panel)"] add_row_to_table -id $panel_id [list "IC delay" "Cell delay" "Node location" "Node name"] } find_paths_and_display $opts(from) $opts(a) # cierre el archivo de salida si es necesario if { [info existe fh] } { cerrar $fh } # Guarde el panel del informe si es necesario if { -1 != $panel_id } { save_report_database unload_report } } project_close }