Ejemplo de Tcl de Quartus® II: Informes de sincronización de rutas arbitrarias

author-image

Por

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 
}    

El contenido de esta página es una combinación de la traducción humana y automática del contenido original en inglés. Este contenido se ofrece únicamente para su comodidad como información general y no debe considerarse completa o precisa. Si hay alguna contradicción entre la versión en inglés de esta página y la traducción, prevalecerá la versión en inglés. Consulte la versión en inglés de esta página.