คําสั่ง list_path และ report_timing Tcl นั้นทรงพลังมาก แต่มีข้อจํากัดบางประการ ปลายทางพาธต้องเป็นนาฬิกา พิน หรือการลงทะเบียน นอกจากนี้ คําสั่งเหล่านี้ไม่ได้รายงานทุกพาธรวมกันระหว่างปลายทาง ตัวอย่างสคริปต์ขั้นสูงนี้รองรับการรายงานเวลาบนเส้นทางโดยพลการในการออกแบบของคุณ (รวมถึงจุดสิ้นสุดแบบรวม) และรายงานพาธรวมทั้งหมดระหว่างปลายทาง สคริปต์ใช้อัลกอริธึมการค้นหาซ้ําเพื่อค้นหาเส้นทาง อัลกอริทึมจะหยุดที่พินและรีจิสเตอร์เพื่อป้องกันเวลาทํางานที่มากเกินไป
คุณสามารถระบุชื่อโหนด สัญลักษณ์ตัวแทน หรือชื่อกลุ่มเวลาสําหรับแหล่งข้อมูลและปลายทาง การยกเว้นกลุ่มเวลาไม่รองรับโดยสคริปต์นี้ คําเตือนจะปรากฏขึ้นหากคุณระบุกลุ่มเวลาที่มีการยกเว้นสําหรับปลายทาง และละเว้นการยกเว้น
คุณสามารถส่งเอาต์พุตของสคริปต์ไปยังไฟล์ Comma Separated Value (.csv) ชื่อไฟล์เริ่มต้นคือp2p_timing.csv นอกจากนี้ คุณสามารถส่งเอาต์พุตสคริปต์ไปยังแผงในรายงานเวลาของโครงการของคุณ ชื่อแผงเริ่มต้นคือการกําหนดเวลาแบบจุดต่อจุด
quartus_tan -t p2p_timing.tcl -project <project name> -จากชื่อ <node|wildcard|timegroup> -to <node name| >ชื่อwildcard|timegroup> [-write_file] [-file <output file name>] [-write_panel] [-panel <report panel name>]
หากคุณต้องการส่งเอาต์พุตไปยังไฟล์ที่แตกต่างจากชื่อไฟล์เริ่มต้น คุณต้องระบุตัวเลือก -write_file และ -file <output file> หากคุณต้องการส่งเอาต์พุตไปยังแผงรายงานที่แตกต่างจากชื่อแผงรายงานเริ่มต้น คุณต้องระบุตัวเลือก -write_panel และ -panel <report panel>
คัดลอกคําสั่ง Tcl ต่อไปนี้ไปยังไฟล์และตั้งชื่อไฟล์p2p_timing.tcl
แพคเกจต้องมี cmdline load_package advanced_timing รายงานload_package Quartus ระดับโลก ผันแปร ::argv0 $::quartus(args) ตั้งค่าตัวเลือก { \ { "from.arg" "" "ชื่อโหนดต้นทาง" } \ { "to.arg" "" "ชื่อโหนดปลายทาง" } \ { "project.arg" "" "ชื่อโครงการ" } \ { "file.arg" "p2p_timing.csv" "Output csv file name" } \ { "write_file" "" "เขียนผลลัพธ์ไปยังไฟล์" } \ { "panel.arg" "การกําหนดเวลาแบบจุดต่อจุด" "ชื่อแผงรายงาน" } \ { "write_panel" "" "เขียนผลลัพธ์ไปยังแผงรายงาน" } \ } array set opts [::cmdline::getoptions ::argv0 $options "ตัวเลือกไม่ถูกต้อง"] ############################################################## # # ส่งกลับรายชื่อของชื่อโหนดและรหัสโหนดที่เกี่ยวข้อง # สําหรับชื่อการออกแบบที่ตรงกับรูปแบบที่มีลวดลายอยู่ # รูปแบบใดๆ ที่ไม่ตรงกับชื่อในการออกแบบมี จํานวนรายการว่างเปล่าที่ส่งคืน # ตัวอย่าง: ส่งผ่านใน "รีเซ็ต" และรับ { รีเซ็ต 3 } กลับคืน # ############################################################## proc get_node_ids { pattern } { ชุดอาร์เรย์name_to_node [list] ถ้า { [string เท่ากับ "" $pattern] } { ส่งคืน [รายการ] } # จริงๆ แล้วรูปแบบคือชื่อของกลุ่มเวลาหรือไม่ # หากเป็นเช่นนั้น สคริปต์จะได้รับสมาชิกของ # กลุ่มเวลา ตั้งค่าสมาชิก [get_all_global_assignments -name TIMEGROUP_MEMBER -section_id $pattern] # หากมีสมาชิกในคอลเลกชันนี้ # รูปแบบคือ Timegroup หาก { 0 < [get_collection_size $members]} { # เตือนหากมีข้อยกเว้น เนื่องจากสคริปต์ # ข้ามข้อยกเว้น หาก {0 < [get_collection_size [get_all_global_assignments -name TIMEGROUP_EXCLUSION -section_id $pattern]] } คําเตือน post_message -type "ข้ามการยกเว้นใน$patternกลุ่มเวลา" } # ดูแต่ละรายการในกลุ่มเวลา $membersการมอบหมายforeach_in_collection { # แต่ละรายการในคอลเลกชันเป็นรายการดังนี้: จํานวน {$pattern} {TIMEGROUP_MEMBER} {node/real pattern} ชุดอาร์เรย์sub_collection_names [get_node_ids [lindex $assignment 2]] foreach node_name [array names sub_collection_names] { ตั้งค่า name_to_node($node_name) $sub_collection_name($node_name) } } } อื่นๆ { # ไม่ใช่กลุ่มเวลา # คํานวณใหม่ผ่านโหนดเวลาทั้งหมดในการออกแบบ # ตรวจสอบว่าชื่อตรงกับรูปแบบที่ระบุหรือไม่ foreach_in_collection node_id [get_timing_nodes -พิมพ์ทั้งหมด] { ตั้งค่าnode_name [get_timing_node_info -ชื่อข้อมูล $node_id] หาก { [string match [escape_brackets $pattern] $node_name] } { ตั้งค่า name_to_node($node_name) $node_id } } } ส่งคืน [array get name_to_node] } ############################################################## # # กระบวนการนี้ค้นหาพาธผสมระหว่างแหล่งข้อมูล # โหนดและรายการโหนดปลายทาง โดยจะส่งคืนรายชื่อ # พาธระหว่างโหนด แต่ละพาธประกอบด้วยทริปเล็ต จํานวน ID โหนด และการเชื่อมต่อระหว่างกันและความล่าช้าของเซลล์จาก # โหนดก่อนหน้า # ขั้นตอนหยุดข้าม Netlist ที่การลงทะเบียน # หรือพิน จึงไม่พบพาธที่ลงทะเบียน # ############################################################## proc find_combinational_paths_between {queue dest_nodes} { ตั้งค่า num_iterations 0 ตั้งค่าพาธ [list] ในขณะที่ {0 < [llength $queue]} { # รายงานความคืบหน้าของลูปทุกพันครั้ง # การnum_iterationsแบบบูรณาการ ถ้า { 1000 == $num_iterations } { ตั้งค่า num_iterations 0 post_message "กําลังเลือกพาธ [llength $queue] } # ป็อปพาธแรกจากคิว # เป็นครั้งแรกที่เรียกว่าขั้นตอน คิว # เป็นเพียงตัวเลขเดียว โหนดต้นทาง ตั้งค่าพาธ [lindex $queue 0] ตั้งคิว [lrange $queue 1 end] # รับโหนดสุดท้ายในเส้นทาง แล้วในลูป foreach # รับ fanout จากโหนดนั้น ตั้งค่าlast_triplet_in_path [lindex $path End] ตั้งค่าlast_node_in_path [lindex $last_triplet_in_path 0] # ดึงข้อมูลเฉพาะ ID โหนดในพาธปัจจุบัน # ซึ่งจะถูกใช้ในภายหลังเพื่อให้แน่ใจว่าจะไม่มีการเคลื่อนที่ของลูป ตั้งค่าnodes_in_path [collapse_triplets_to_node_list $path] # รับแฟนๆ ทั้งหมดของโหนดสุดท้ายในเส้นทางนี้และทําให้ # เส้นทางใหม่กับพวกเขาเพื่อกดดันคิว foreach n [get_timing_node_fanout $last_node_in_path] { foreach { node_id ic_delay cell_delay } $n { แบ่ง } ถ้า { -1 != [lsearch $dest_nodes $node_id] } { # ถ้าโหนดนี้ในพาธอยู่ในรายการ # โหนดปลายทาง มีพาธ # เพิ่มลงในรายการพาธระหว่างโหนด ตั้งค่าnew_path $pathยืม new_path $n พาธ lappend $new_path } ถ้า { -1 == [lsearch $nodes_in_path $node_id] } # หากโหนดนี้ในเส้นทางไม่อยู่ในเส้นทาง # แล้ว นี่ไม่ใช่ลูป ดันไปที่ # Queue ถ้าเป็นโหนดผสมหรือโหนดนาฬิกา # เส้นทางจะไม่ถูกผลักดันถ้าโหนดนี้เป็น # ลงทะเบียนหรือพิน # ผลักดันเส้นทางใหม่บนคิวเช่นนี้ # แม้ว่าโหนดนี้ในเส้นทางอาจตรงกัน # โหนดปลายทาง ช่วยให้มั่นใจได้ว่าจะนานที่สุด พบพาธต่างๆ ตั้งค่าnode_type [get_timing_node_info -ชนิดข้อมูล $node_id] สวิตช์ -- $node_type { หวี - clk { ตั้งค่าnext_path $path next_path $nยืม lappend queue $next_path } { เริ่มต้น } } } } } $pathsส่งคืน } ############################################################## # # บวกตัวเลขหน่วงเวลาสองตัวและคืนค่าผลลัพธ์ # หมายเลขหน่วงเวลาอยู่ในฟอร์ม "หน่วยมูลค่า" ที่หน่วยต่างๆ # อาจเป็นนาโนวินาที (ns) หรือ picoseconds (ps) และอาจมีค่า # เป็น x{1,3} หากหน่วยเป็น picoseconds หรือ x+.y{1,3} หาก # หน่วยคือนาโนวินาที ขั้นตอนนี้จะทําให้ความล่าช้าเป็นปกติ # นาโนวินาทีและเพิ่มค่า # ตัวอย่าง: add_delays "1.234 ns" "56 ps" # ############################################################## add_delays proc { a b } { หาก { ![ regexp {^([\d\] +)\s+([np]s)$} $a match a_value a_unit] } { ข้อผิดพลาด post_message -type "ความซับซ้อนไม่ได้ระบุส่วนของเวลา: $a" } หาก { ![ regexp {^([\d\] +)\s+([np]s)$} การจับคู่$b b_value b_unit] } { ข้อผิดพลาด post_message -type "ที่ยอมรับได้ไม่กําหนดส่วนของเวลา: $b" } # แปลงทุกอย่างเป็นระดับนาโนวินาทีหากจําเป็น หาก { [string equal -nocase ps $a_unit] } { ตั้งค่า a_value_ps [format "%.3f" $a_value] ตั้งค่าa_value [format "%.3f" [expr { $a_value_ps / 1000 }]] } หาก { [string equal -nocase ps $b_unit] } { ตั้งค่า b_value_ps [format "%.3f" $b_value] ตั้งค่าb_value [format "%.3f" [expr { $b_value_ps / 1000 }]] } # ตอนนี้หน่วยมีค่าเท่ากันและระดับนาโนวินาที # เพียงเพิ่มตัวเลขเข้าด้วยกัน ตั้งค่า sum_value [format "%.3f" [expr { $a_value + $b_value }]] ส่งคืน "$sum_value ns" } ############################################################## # # รูปแบบและพิมพ์ชื่อโหนดในเส้นทางที่มี # ความล่าช้าระหว่างโหนด # ############################################################## proc print_path_delays { พาธ {iteration ก่อน}} { ตั้งค่าsource_triplet [lindex $path 0] ตั้งค่าsource_node [lindex $source_triplet 0] ตั้งค่าsource_node_name [get_timing_node_info -ชื่อข้อมูล $source_node] ตั้งค่าsource_node_loc [get_timing_node_info -ตําแหน่งข้อมูล $source_node] # พิมพ์ความล่าช้าก่อน ถ้า { [string เท่ากับ "แรก" $iteration] } { accumulate_data [รายการ "IC(0.000 ns)" "CELL(0.000 ns)"] } อื่นๆ { ตั้งค่าic_delay [lindex $source_triplet 1] ตั้งค่าcell_delay [lindex $source_triplet 2] accumulate_data [list "IC($ic_delay)" "CELL($cell_delay)"] } accumulate_data [list $source_node_loc $source_node_name] print_accumulated_data # เกิดขึ้นอีกครั้งบนเส้นทางที่เหลือ ถ้า { 1 < [llength $path] } { print_path_delays [lrange $path 1 End] อื่นๆ } } ############################################################## # # รวมความล่าช้าของ IC และเซลล์บนพาธที่ระบุ และ # ส่งกลับรายการที่มีความล่าช้าในการเชื่อมต่อระหว่างกันทั้งหมดและเซลล์ทั้งหมด # หน่วงเวลา # ############################################################## proc end_to_end_delay { พาธ } { ตั้งค่า ic_total "0.000 ns" ตั้งค่า cell_total "0.000 ns" # การดําเนินการนี้จะผ่านโหนด 1 เพื่อสิ้นสุดในเส้นทางเนื่องจาก # โหนดแรกในพาธคือแหล่งที่มาและแต่ละโหนดใน # พาธมีความล่าช้าจากโหนดก่อนหน้า # Source ไม่มีโหนดก่อนหน้า จึงไม่มีความล่าช้า foreach n [lrange $path 1 end] { foreach { node_id ic_delay cell_delay } $n { แบ่ง } ตั้งค่าic_total [add_delays $ic_total $ic_delay] ตั้งค่าcell_total [add_delays $cell_total $cell_delay] } การส่งคืน [list $ic_total $cell_total] } ############################################################## # # ตรวจสอบให้แน่ใจว่าต้นทางและปลายทางที่ระบุมีอยู่ใน # การออกแบบ ค้นหาเส้นทางผสมระหว่างพวกเขาและ # พิมพ์เส้นทาง # ############################################################## proc find_paths_and_display { Source Dest } { แหล่งข้อมูลชุดอาร์เรย์ [get_node_ids $source] dests ชุดอาร์เรย์ [get_node_ids $dest] ตั้งค่า nodes_exist 1 # ตรวจสอบว่ามีโหนดที่มีชื่ออยู่ ถ้า { 0 == [llength [array get sources]] } { ตั้งค่า nodes_exist 0 post_message -type error "ไม่พบโหนดที่ตรงกับ$sourceในการออกแบบของคุณ" } ถ้า { 0 == [llength [array get dests]] } { ตั้งค่า nodes_exist 0 post_message -type error "ไม่พบโหนดที่ตรงกับ$destในการออกแบบของคุณ" } # หากเป็นเช่นนั้น ให้หาเส้นทาง หาก { $nodes_exist } { # รับรายการ ID โหนดปลายทาง ตั้งค่าdest_node_ids [list] foreach D [array names dests] { dest_node_ids $destsให้ยืม ($d) } # ดูทั้งหมดจากโหนด foreach s [แหล่งข้อมูลชื่ออาร์เรย์] { ตั้งค่าพาธ [find_combinational_paths_between $sources($s) $dest_node_ids] ถ้า { 0 == [llength $paths] } { post_message "ไม่มีพาธแบบผสมจาก$sไปยัง$dest" } อื่นๆ { เส้นทางการก้าว$paths { # พิมพ์เส้นทาง print_path_delays $path # Sum ความล่าช้าของเซลล์และการเชื่อมต่อระหว่างกัน และ # พิมพ์ออกทางใต้เส้นทาง foreach {total_ic_delay total_cell_delay } [end_to_end_delay $path] { แบ่ง } accumulate_data [list $total_ic_delay $total_cell_delay] accumulate_data [รายการ [add_delays $total_ic_delay $total_cell_delay]] # มีสองสายให้print_accumulated_data # ตรงนี้ หนึ่งภาพเพื่อพิมพ์ยอดรวมของการเชื่อมต่อระหว่างกัน # และเซลล์เกิดความล่าช้า และอีกเซลล์หนึ่งเพื่อสร้างเซลล์ว่าง # บรรทัดในเอาต์พุต print_accumulated_data print_accumulated_data } } } } } ############################################################## # # พาธประกอบด้วยข้อมูลเป็นสามเท่า - รหัสโหนด # ความล่าช้าการเชื่อมต่อระหว่างกัน และความล่าช้าของเซลล์ ขั้นตอนนี้จะแยกออก # ID โหนดจากแต่ละ Triplet ในการสั่งซื้อและส่งคืนรายการ # ID โหนด # ############################################################## collapse_triplets_to_node_list proc { l } { ตั้งค่าto_return [list] foreach triplet $l { to_returnยืม [lindex $triplet 0] } return $to_return } ############################################################## # # รวมข้อมูลเข้ากับตัวแปรระดับโลกในการเตรียมการ # สําหรับงานที่กําลังพิมพ์ออกมา # ############################################################## proc accumulate_data { ข้อมูล } { คํากล่าวหาระดับโลก [concat $accum $data] } ############################################################## # # พิมพ์ข้อมูลที่สะสมออกมา # ไฟล์จะถูกพิมพ์ออกเป็นมาตรฐาน และอาจเลือกเป็นไฟล์ใน # รูปแบบ CSV หากไฟล์จัดการอยู่ และอาจเลือกเป็น แผงรายงาน # หากมีแผงรายงานอยู่ (ไม่ใช่ค่า -1) # ############################################################## print_accumulated_data proc {} { panel_id accum fh ระดับโลก ใส่ [เข้าร่วม$accum ","] # เขียนลงในไฟล์? หาก { [info มี fh] } } ใส่$fh [เข้าร่วม$accum "," ] } # เพิ่มลงในแผงรายงานหรือไม่ ถ้า { -1 != $panel_id } { # หากแถวแผงรายงานไม่มี 4 รายการ # ในเครื่อง ให้กดเป็น 4 ในขณะที่ { 4 > [llength $accum] } { lappend accum [list] } add_row_to_table -id $panel_id $accum } # ล้างข้อมูลในตัวแปรส่วนกลาง ตั้ง accum [list] } ############################################################## ############################################################## # # สิ้นสุดขั้นตอน การเริ่มต้นสคริปต์ # ############################################################## ############################################################## # # ตัวแปร Global เพื่อเก็บข้อมูลเพื่อจัดแสดง และแผง # ID สําหรับแผงรายงานเพิ่มเติม ตั้ง accum [list] ตั้งค่าpanel_id -1 ถ้า { [string equal "" $opts(project)] } } # ตัวเลือกการใช้การพิมพ์หากมีการเรียกสคริปต์โดยไม่มี จํานวนข้อโต้แยะ puts [::cmdline::การใช้งาน$options] } elseif { [string equal "" $opts(project)] } { post_message -type error "ระบุโครงการที่มีตัวเลือก -project" } อื่นๆ { ! [project_exists $opts(Project)] } { ข้อผิดพลาด post_message -type "ไม่มี project $opts(project) อยู่ในไดเรกทอรีนี้" } elseif { [string equal "" $opts(จาก)] } { post_message -type error "ระบุชื่อหรือรูปแบบสัญลักษณ์ตัวแทนด้วยตัวเลือก -from" } elseif { [string equal "" $opts(to)] } { post_message -type error "ระบุชื่อหรือรูปแบบสัญลักษณ์ตัวแทนด้วยตัวเลือก -to" } อื่นๆ { ตั้งค่าcur_revision [get_current_revision $opts(โครงการ)] project_open $opts (โครงการ) -การปรับปรุงแก้ไข $cur_การปรับปรุงแก้ไข # พยายามสร้าง Netlist กําหนดเวลา คําสั่งนี้จะล้มเหลว # หากยังไม่ได้รันquartus_fit ถ้า { [จริงใจ { create_timing_netlist } msg ] } { $msgข้อผิดพลาด post_message -type } อื่นๆ { # เตรียมเขียนเอาต์พุตไปยังไฟล์หากจําเป็น ถ้า { 1 == $opts(write_file) } { ถ้า { [ดูข้อมูล {open $opts(ไฟล์) w} fh] } { ข้อผิดพลาด post_message -type "การไม่เปิด$opts(write_file): $fh" ไม่ตั้งค่า fh } อื่นๆ { post_message "การเขียนเอาต์พุตไปยัง$opts (ไฟล์)" # เพิ่มข้อมูลระดับเริ่มต้นให้กับไฟล์เอาต์พุต ใส่$fh "รายงานพาธจาก $opts(จาก) ไปยัง $opts(to)" ใส่$fh "สร้างขึ้นบน [รูปแบบนาฬิกา [วินาทีนาฬิกา]" ใส่ $fh "" ทําให้$fh "IC ล่าช้า,ความล่าช้าของเซลล์,ตําแหน่งโหนด,ชื่อโหนด" } } # เตรียมเขียนเอาต์พุตไปยังแผงรายงานหากจําเป็น ถ้า { 1 == $opts(write_panel) } { # โหลดรายงาน ลบแผงหากมีอยู่แล้ว # สร้างแผงใหม่และเพิ่มแถวหัวเรื่อง load_report ตั้งค่าpanel_id [get_report_panel_id "ตัววิเคราะห์เวลา|| $opts (แผง)"] ถ้า { -1 != $panel_id } { delete_report_panel -id $panel_id } ตั้งค่าpanel_id [create_report_panel -table "ตัววิเคราะห์เวลา|| $opts (แผง)"] add_row_to_table -id $panel_id [list "IC delay" "ความล่าช้าของเซลล์" "ตําแหน่งโหนด" "ชื่อโหนด"] } find_paths_and_display $opts(จาก) $opts(ไปยัง) # ปิดไฟล์เอาต์พุตหากจําเป็น หาก { [info มี fh] } { close $fh } # บันทึกแผงรายงานหากจําเป็น ถ้า { -1 != $panel_id } { save_report_database unload_report } } project_close }