Exemple de Quartus® II Tcl : création de rapports arbitraires sur le timing des chemins

author-image

Par

Les commandes list_path et report_timing Tcl sont très puissantes, mais elles ont des limites. Les points d’extrémité du chemin d’accès doivent être des horloges, des broches ou des registres. De plus, ces commandes ne signalent pas chaque chemin combiné entre les points d’extrémité. Cet exemple de script avancé prend en charge la synchronisation des rapports sur les chemins arbitraires de votre conception (y compris les terminaux combinés) et signale toutes les voies combinées entre les points d’extrémité. Le script utilise un algorithme de recherche itérative pour trouver des chemins. L’algorithme s’arrête aux broches et aux registres pour éviter les temps d’exécution excessifs.

Vous pouvez spécifier les noms de nœud, les wildcards ou les noms du timegroupe pour la source et la destination. Les exclusions de Timegroup ne sont pas prises en charge par ce script ; un avertissement s’affiche si vous spécifiez un timegroup contenant des exclusions pour les points d’extrémité, et les exclusions sont ignorées.

Vous pouvez diriger la sortie du script vers un fichier.csv(Virgule séparée). Le nom du fichier par défaut est p2p_timing.csv. De plus, vous pouvez diriger la sortie du script vers un panneau dans le rapport de synchronisation de votre projet. Le nom par défaut du panneau est « Synchronisation point à point ».

quartus_tan -t p2p_timing.tcl -project <project name> du nom <node|wildcard|timegroup> au nom <node quartus_tan nom |wildcard|timegroup> [-write_file] [nom du fichier <output>] [-write_panel] [nom du panneau <reporter>].

Si vous souhaitez diriger la sortie vers un fichier différent du nom de fichier par défaut, vous devez spécifier à la fois le nom du fichier write_file et le nom du fichier <outputé> options. Si vous souhaitez diriger la sortie vers un panneau de rapport différent du nom par défaut du panneau de rapport, vous devez spécifier les options -write_panel et -panel <reporter> options.

Copiez les commandes Tcl suivantes dans un fichier et nommez-le p2p_timing.tcl.

package nécessitent une ligne cmdline 
load_package advanced_timing 
rapport load_package 

quartus mondial 
variable ::argv0 $::quartus(args) 

options { \ 
   { « from.arg » « » « Nom de nœud source » } \ 
   { « to.arg » « » « nom de nœud de destination » } \ 
   { « project.arg » « » « Nom du projet » } \ 
   { « file.arg » « p2p_timing.csv » « Nom du fichier output csv » } \ 
   { « write_file », « Écrire la sortie sur un fichier » } \ 
   { « panel.arg » « Timing point à point », « Nom du panneau de rapport » } \ 
   { « write_panel », « Écrivez la sortie dans un panneau de rapport » } \ 
} 

array set opts [::cmdline::getoptions ::argv0 $options « Bad option"] 
############################################################## 
# 
# Retourne une liste de noms de nœuds et d’ID de nœud correspondants 
Nb. de noms de conception qui correspondent à l’argument du schéma. 
# Tout schéma qui ne correspond pas aux noms dans la conception a un 
Nb. liste vide retournée 
# Exemple : Passez dans « reset » et obtenez { reset 3 } retour 
# 
############################################################## 
proc get_node_ids { schéma } { 
   array set name_to_node [liste] 

si {[chaîne égale « » $pattern] } { 
      retourner [liste] 
   }

# Le schéma est-il en fait le nom d’un timegroup ? 
   Nb. S’il l’est, alors le script obtient de façon récursive les membres de 
   # le timegroup. 
   définissez les membres [get_all_global_assignments-nom TIMEGROUP_MEMBER -section_id $pattern] 

Nb. S’il y a des membres de la collection, 
   # le schéma est un timegroup 
   si {0 < [get_collection_size $members]} { 
      # L’exclusion s’il y a des exclusions, car le script 
      Nb. d’exclusions de poste 
      si {0 < [get_collection_size [get_all_global_assignments -name TIMEGROUP_EXCLUSION -section_id $pattern]] } { 
         Avertissement de type post_message « Exclusions de l’hélisement dans le $pattern timegroup » 
      } 

Nb. Consultez chaque élément du groupe de temps. 
      foreach_in_collection affectation $members { 
         Nb. Chaque article de la collection est une liste comme celle-ci : 
         # {$pattern} {TIMEGROUP_MEMBER} {node/real pattern} 
         array set sub_collection_names [get_node_ids [$assignment $assignment get_node_ids] 

node_name [noms de batterie sub_collection_names] { 
            définissez name_to_node($node_name) $sub_collection_names($node_name) 
         } 
      } 
   } d’autre {. 
      Nb. Il ne s’agit pas d’un timegroup 
      # Itération à travers tous les nœuds de synchronisation de la conception, 
      Nb. vérifier si le nom correspond au schéma spécifié 
      foreach_in_collection node_id [get_timing_nodes-type tout] { 
         définissez node_name [nom get_timing_node_info -info $node_id] 
         si {[string match [escape_brackets $pattern] $node_name] } { 
            définissez name_to_node($node_name) $node_id 
         } 
      } 
   } 
   retour [array get name_to_node]
} 

############################################################## 
# 
# Cette procédure trouve des chemins combinaux entre une source 
Nb. de nœud et liste de nœuds de destination. Il renvoie une liste des 
Nb. de chemins entre les nœuds. Chaque chemin est constitué d’un triplet 
Nb. d’ID de nœud, et retard d’interconnexion et de cellule à partir du 
Nb. de nœud précédent. 
# La procédure ne passe plus sur la netliste à l’intérieur d’un registre 
Nb. ou broche, de sorte qu’il ne trouve pas de chemins qui passent par les registres. 
#
############################################################## 
proc find_combinational_paths_between {file d’attente dest_nodes} { 
   définir num_iterations 0 
   définir des chemins [liste] 
   
tandis que {0 < [llength $queue]} { 
      Nb. Rapport sur la progression de la boucle tous les mille 
      # itérations incr num_iterations 
      si { 1000 == $num_iterations } { 
         définir num_iterations 0 
         post_message « Vérification des chemins [llength $queue] ». 
      } 
      
# Ouvrez le premier chemin depuis la file d’attente. 
      # La première fois que la procédure est appelée, la file d’attente 
      Le nº est qu’un seul chiffre, le nœud source. 
      définir la voie [$queue $queue] 
      définir la file d’attente [lrange $queue 1 extrémité] 
      
# Obtenez le dernier nœud sur le chemin, puis dans le circuit de foreach 
      # Obtenir le ventilateur de ce nœud 
      définir last_triplet_in_path [fin de l$path hexex] 
      définir last_node_in_path [$last_triplet_in_path 0] 
 
# Extraire uniquement les ID de nœud dans le chemin actuel. 
      Nb. Ceci est utilisé ultérieurement pour s’assurer que les boucles ne sont pas traversées. 
      définir nodes_in_path [collapse_triplets_to_node_list $path] 

# Obtenez tous les ventilateurs du dernier nœud dans ce chemin et faites 
      # de nouveaux chemins avec eux pour pousser dans la file d’attente. 
      foreach n [get_timing_node_fanout $last_node_in_path] { 
         foreach { node_id ic_delay cell_delay } $n { 
            Pause 
         }
 
si {-1 != [lsearch $dest_nodes $node_id] } { 
            Nb. Si ce nœud se trouve sur le chemin d’accès dans la liste des 
            Nb. de nœuds de destination, il y a un chemin. 
            # Ajoutez-le à la liste des chemins entre les nœuds 
            définir new_path $path lalsynd 
            new_path $n 
            chemins laïnds $new_path 
         } 

si {-1 == [lsearch $nodes_in_path $node_id] } { 
            # Si ce nœud sur le chemin n’est pas sur le chemin 
            Nb. Déjà, il ne s’agit pas d’une boucle. Poussez-le sur le 
            Nb. de file d’attente s’il s’agit d’un nœud combiné ou d’horloge. 
            # Le chemin n’est pas poussé sur si ce nœud est un 
            Nb. registre ou broche. 
            # Pousser un nouveau chemin dans la file d’attente comme celui-ci, 
            Nb. même si ce nœud sur le chemin peut correspondre 
            # un nœud de fin, garantit le plus long possible 
            Nb. de chemins trouvés. 
            définissez node_type [type get_timing_node_info -info $node_id] 
            commutateur -exact - $node_type { 
               comb - 
               clk { 
                  définir next_path $path 
                  next_path $n laïnd 
                  file d’attente laïnd $next_path 
               } 
               par défaut { 
               } 
            } 
         } 
      }
   }
   $paths de retour 
} 

############################################################## 
# 
# Ajoute deux numéros de retard et renvoie le résultat. 
Nb. Le numéro de retard se trouve dans le formulaire « unités de valeur » où les unités 
Nº peut être nanoseconds (ns) ou picoseconds (ps), et la valeur peut 
# être x{1,3} si les unités sont des picoseconds, ou x+.y{1,3} si le 
Les unités nb. sont des nanoseconds. Cette procédure normalise les retards sur 
# nanosecond et ajoute les valeurs. 
Exemple : add_delays « 1.234 ns » « 56 ps » 
############################################################## 
proc add_delays { a b } { 
   si { ![ regexp {^([\d\.] +)\s+([np]s)$} $a match a_value a_unit] } { 
      Erreur de type post_message « Impossible de déterminer les moments : $a » 
   } 

si { ![ regexp {^([\d\.] +)\s+([np]s)$} $b match b_value b_unit] } { 
      erreur de type post_message « Impossible de déterminer les moments : $b » 
   } 
  
Nb. Convertir tout en nanoseconds, le cas échéant 
   si {[chaîne égale -nocase ps $a_unit] } { 
      définir a_value_ps [format « %.3f » $a_value] 
      définir a_value [format « %.3f » [expr { $a_value_ps / 1000 }]]. 
   } 

si {[chaîne égale -nocase ps $b_unit] } { 
      définir b_value_ps [format « %.3f » $b_value] 
      définir b_value [format « %.3f » [expr { $b_value_ps / 1000 }]]. 
   } 

# Maintenant, les unités sont égales, et les nanoseconds. 
   # Ajoutez les chiffres. 
   définir sum_value [format « %.3f » [expr { $a_value + $b_value }]]. 
  
retourner « $sum_value ns » 
} 

############################################################## 
# 
Nb. Formats et s’affranchissant des noms de nœuds sur le chemin avec le  
Nb. de retards entre les nœuds. 
# 
############################################################## 
proc print_path_delays { chemin {itération first}} { 
   définir source_triplet [l'$path $path 0] 
   définir source_node [$source_triplet 0] 
   définissez source_node_name [get_timing_node_info -info name $source_node] 
   définir source_node_loc [emplacement get_timing_node_info -info $source_node] 
   
# Imprimez d’abord les retards 
   si {[chaîne égale « premier » $iteration] } { 
      accumulate_data [liste « IC(0.000 ns) » « CELL(0.000 ns) » ]. 
   } d’autre {. 
      définir ic_delay [$source_triplet 1] 
      définir cell_delay [$source_triplet 2] 
      accumulate_data [liste « IC($ic_delay) », « CELL ($cell_delay)] 
   } 
   accumulate_data [liste $source_node_loc $source_node_name] 
   print_accumulated_data 

# Récursez sur le reste du chemin 
   si {1 < [llength $path] } { 
      print_path_delays [lrange $path 1 extrémité] autre 
   } 
} 

############################################################## 
# 
# résume les retards de l’IC et des cellules sur la voie spécifiée et 
# renvoie une liste avec le retard total d’interconnexion et la cellule totale 
Nb. de retard. 
# 
############################################################## 
proc end_to_end_delay { chemin } { 
   définir ic_total « 0,000 ns » 
   définir cell_total « 0,000 ns » 
   
Nb. Cela passe par les nœuds 1 pour se terminer sur le chemin, car le 
   Le premier nœud sur le chemin est la source et chaque nœud dans le 
   # path contient les retards du nœud précédent. Lla 
   Nb. source n’a pas de nœud précédent, il n’a donc pas de retard. 
   foreach n [lrange $path 1 fin] { 
      foreach { node_id ic_delay cell_delay } $n { 
         Pause 
      } 
      définir ic_total [add_delays $ic_total $ic_delay] 
      définir cell_total [add_delays $cell_total $cell_delay] 
   } 

retourner [liste $ic_total $cell_total] 
} 

##############################################################
# 
# Garantit l’existence de la source et des destinations spécifiées dans le 
# conception, trouve les chemins combinés entre eux, et 
Nb. de s’enserrez les chemins. 
# 
############################################################## 
proc find_paths_and_display { source dest } { 
   sources définies par batterie [get_node_ids $source] 
   array set dests [get_node_ids $dest] 

définir nodes_exist 1 

# Assurez-vous que les nœuds nommés existent 
   si {0 == [llength [array get sources]] } { 
      définir nodes_exist 0 
      erreur de type post_message « Nœuds correspondant $source ont été trouvés dans votre conception ». 
   } 
   si {0 == [llength [array get dests]] } { 
      définir nodes_exist 0 
      erreur de type post_message « Nœuds correspondant $dest ont été trouvés dans votre conception ». 
   } 

# S’ils le font, trouvez des chemins.   si { $nodes_exist } { 
      # Obtenez la liste des ID de nœud de destination 
      définir dest_node_ids [liste] 
      avant-première d [noms de batterie dests] { 
         dest_node_ids $dests laïnd ($d) 
      } 

Nb. Parcourez tous les nœuds 
      foreach s [sources de noms de réseau] { 
         définir des chemins [find_combinational_paths_between $sources($s) $dest_node_ids] 
         si {0 == [llength $paths] } {  
            post_message « Aucune voie combinée n’existe entre les $s et les $dest » 
         } d’autre {. 
            chemin d’avant-recherche $paths { 
               # Imprimez le chemin 
               print_path_delays $path 

# Récaptez l’interconnexion et les retards des cellules et 
               # imprimez-les sous le chemin. 
               foreach {total_ic_delay total_cell_delay} [end_to_end_delay $path] { 
                  Pause 
               } 
               accumulate_data [liste $total_ic_delay $total_cell_delay] 
               accumulate_data [liste [add_delays $total_ic_delay $total_cell_delay]] 

Nb. Il y a deux appels à print_accumulated_data 
               # ici, un pour imprimer les sommes de l’interconnexion 
               Nb. et les retards des cellules, et un pour générer un vide 
               Nb. de ligne dans la sortie. 
               print_accumulated_data print_accumulated_data 
            } 
         } 
      }
   } 
} 

############################################################## 
# 
# Un chemin est constitué de triplets d’informations - id de nœud, 
# Le retard d’interconnexion et le retard des cellules. Cette procédure extrait 
# l’ID de nœud de chaque triplet dans l’ordre et renvoie une liste 
Nb. d’ID de nœud 
# 
############################################################## 
proc collapse_triplets_to_node_list { l } { 
   définir to_return [liste] 
   $l de triplet foreach { 
      laïnd to_return [$triplet laïcsex 0] 
   } 
   retour $to_retour 
} 

############################################################## 
# 
# Concatenates des informations à une variable globale en préparation 
Nb. pour l’impression. 
# 
############################################################## 
proc accumulate_data { données } { 
   accum global accum [concat $accum $data] 
}
 
############################################################## 
# 
# Imprimez les données accumulées. 
Nb. Il est imprimé de manière standard et en option sur un fichier 
Nb. format CSV si la poignée de fichiers existe et, en option, sur un 
Nb. panneau de rapport s’il existe un panneau de rapport (pas une valeur de -1) 
# 
############################################################## 
proc print_accumulated_data {} { 
   accum mondial panel_id 
   met [rejoindre $accum « »,] 

# Écrivez-le dans un fichier ? 
   si {[info existe fh] } { 
      met $fh [rejoindre $accum « », 
   } 

# Ajoutez-le au panneau de rapport ? 
   si {-1 != $panel_id } { 
      Nb. Si la ligne du panneau de rapport ne possède pas 4 éléments 
      Nb. dedans, connectez-le à 4. 
      {4 > [llength $accum] } { 
         laïnd accum [liste] 
      } 
      add_row_to_table -id $panel_id $accum 
   } 
   # Effacez les informations dans la variable globale. 
   définir accum [liste] 
}

############################################################## 
############################################################## 
# 
# Fin des procédures, début du script 
# 
############################################################## 
##############################################################
# 
Nb. Variables mondiales permettant de conserver les données pour l’impression et le panneau 
# ID pour un panneau de rapport facultatif 

définir accum [liste] 
définir panel_id -1 

si {[chaîne égale « » $opts(project)] } { 
   # Imprimer les options d’utilisation si le script est appelé sans 
   Nb. d’arguments 
   met [::cmdline:::utilisation $options] 
} elseif { [chaîne égale « » $opts(projet)] } { 
   erreur de type post_message « Spécifiez un projet avec l’option - projet ». 
} elseif { ! [project_exists $opts(projet)] } { 
   post_message type d’erreur « Le projet $opts(projet) n’existe pas dans ce répertoire ». 
} elseif { [chaîne égale « » $opts(de)] } { 
   erreur de type post_message « Spécifiez un nom ou un schéma wildcard avec l’option - de l’option ». 
} elseif { [chaîne égale « » $opts(pour)] } { 
   erreur de type post_message « Spécifiez un nom ou un schéma wildcard avec l’option de -à ». 
} d’autre {. 
   définir cur_revision [get_current_revision $opts(projet)] 
   project_open $opts (projet) -révision $cur_revision 

# Essayez de créer la netlist de synchronisation. Cette commande tomberait en panne 
   Nb. si quartus_fit n’a pas encore été exécuté, par exemple. 
   si {[capture { create_timing_netlist} } msg ] } { 
      erreur de type post_message $msg 
   } d’autre {. 

# Préparez-vous à écrire le résultat dans un fichier, le cas échéant 
      si { 1 == $opts (write_file) } { 
         si {capture {open $opts(file) w} fh] } {open $opts(fichier) w} fh] } 
            erreur de type post_message « Impossible d’ouvrir $opts (write_file) : $fh » non jeu fh 
         } d’autre {. 
            post_message « Écriture de la sortie sur $opts (fichier) » 
            # Ajoutez quelques informations d’introduction au fichier de sortie 
            met $fh « Rapport de chemins de $opts (de) à $opts (vers) » 
            met $fh « généré sur [format d’horloge [secondes d’horloge] » 
            met $fh « » met $fh « retard IC, délai de cellule, emplacement du nœud, nom de nœud » 
         } 
      } 

Nb. Préparer la sortie dans un panneau de rapport, le cas échéant 
      si { 1 == $opts (write_panel) } { 
         # Chargez le rapport, supprimez le panneau s’il existe déjà, 
         # créez un nouveau panneau, puis ajoutez la ligne de tête. 
         load_report 
         définissez panel_id [get_report_panel_id « Analyseur de synchronisation|| $opts(panneau)]] 
         si {-1 != $panel_id } { 
            delete_report_panel -id $panel_id 
         } 
        définissez panel_id [create_report_panel tableau « Analyseur de synchronisation|| $opts(panneau)]] 
        add_row_to_table -id $panel_id [liste « retard IC », « délai de cellule », « emplacement du nœud », « nom de nœud » ]. 
      } 
      find_paths_and_display $opts(de) $opts(à) 

Nb. fermez le fichier de sortie si nécessaire 
      si {[info existe fh] } { fermez $fh } 

# Enregistrez le panneau de rapport si nécessaire 
      si {-1 != $panel_id } { 
         save_report_database 
         unload_report 
      } 
   } 
   project_close 
}    

Le contenu de cette page est une combinaison de traduction humaine et informatique du contenu original en anglais. Ce contenu vous est fourni pour votre commodité et à titre informatif seulement et ne saurait être totalement exact ou complet. En cas de contradiction entre la version anglaise de cette page et la traduction, c'est la version anglaise qui prévaut. Afficher la version anglaise de cette page.