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 }