1 |
12 |
xianfeng |
##
|
2 |
|
|
##Legal Notice: (C)2007 Altera Corporation. All rights reserved. Your
|
3 |
|
|
##use of Altera Corporation's design tools, logic functions and other
|
4 |
|
|
##software and tools, and its AMPP partner logic functions, and any
|
5 |
|
|
##output files any of the foregoing (including device programming or
|
6 |
|
|
##simulation files), and any associated documentation or information are
|
7 |
|
|
##expressly subject to the terms and conditions of the Altera Program
|
8 |
|
|
##License Subscription Agreement or other applicable license agreement,
|
9 |
|
|
##including, without limitation, that your use is for the sole purpose
|
10 |
|
|
##of programming logic devices manufactured by Altera and sold by Altera
|
11 |
|
|
##or its authorized distributors. Please refer to the applicable
|
12 |
|
|
##agreement for further details.
|
13 |
|
|
|
14 |
|
|
if { ![info exists quartus(nameofexecutable)] || $quartus(nameofexecutable) != "quartus_sta" } {
|
15 |
|
|
puts "Restarting in quartus_sta..."
|
16 |
|
|
|
17 |
|
|
set cmd quartus_sta
|
18 |
|
|
if { [info exists quartus(binpath)] } {
|
19 |
|
|
set cmd [file join $quartus(binpath) $cmd]
|
20 |
|
|
}
|
21 |
|
|
|
22 |
|
|
set res [catch { exec $cmd -t [info script] batch } output]
|
23 |
|
|
|
24 |
|
|
# This procedure is 'clever' in that it will write a message using
|
25 |
|
|
# post_message if available and refert to puts otherwise.
|
26 |
|
|
# if post_message fails, this procedure changes itself into one that
|
27 |
|
|
# uses a simple 'puts' and continues.
|
28 |
|
|
proc out { msg } {
|
29 |
|
|
set type info
|
30 |
|
|
regexp {^\W*(Info|Extra Info|Warning|Critical Warning|Error): (.*)$} $msg x type msg
|
31 |
|
|
regsub " " $type _ type
|
32 |
|
|
if { [catch { post_message -type $type $msg } res] } {
|
33 |
|
|
proc out { msg } {puts $msg}
|
34 |
|
|
out $msg
|
35 |
|
|
}
|
36 |
|
|
}
|
37 |
|
|
|
38 |
|
|
foreach line [split $output \n] {
|
39 |
|
|
out $line
|
40 |
|
|
}
|
41 |
|
|
return 0
|
42 |
|
|
}
|
43 |
|
|
|
44 |
|
|
set scriptname [info script]
|
45 |
|
|
if { ! [regexp (.*)_report_timing.tcl $scriptname _ corename] } {
|
46 |
|
|
error "Couldn't determine corename from $scriptname"
|
47 |
|
|
}
|
48 |
|
|
|
49 |
|
|
if {[namespace which -variable ::argv] != "" && [lindex $::argv 0] == "batch" } {
|
50 |
|
|
post_message -type info "Running in batch mode"
|
51 |
|
|
|
52 |
|
|
set proj_name [glob *.qpf]
|
53 |
|
|
project_open -revision [get_current_revision $proj_name] $proj_name
|
54 |
|
|
|
55 |
|
|
catch {delete_timing_netlist }
|
56 |
|
|
create_timing_netlist
|
57 |
|
|
read_sdc
|
58 |
|
|
|
59 |
|
|
set opcs [list]
|
60 |
|
|
foreach_in_collection op [get_available_operating_conditions] {
|
61 |
|
|
lappend opcs $op
|
62 |
|
|
}
|
63 |
|
|
|
64 |
|
|
update_timing_netlist
|
65 |
|
|
} else {
|
66 |
|
|
set opcs [list ""]
|
67 |
|
|
}
|
68 |
|
|
|
69 |
|
|
set fpga_tREAD_CAPTURE_SETUP_ERROR 0
|
70 |
|
|
set fpga_tREAD_CAPTURE_HOLD_ERROR 0
|
71 |
|
|
set fpga_RESYNC_SETUP_ERROR 0
|
72 |
|
|
set fpga_RESYNC_HOLD_ERROR 0
|
73 |
|
|
set fpga_PA_DQS_SETUP_ERROR 0
|
74 |
|
|
set fpga_PA_DQS_HOLD_ERROR 0
|
75 |
|
|
set WR_DQS_DQ_SETUP_ERROR 0
|
76 |
|
|
set WR_DQS_DQ_HOLD_ERROR 0
|
77 |
|
|
set fpga_tCK_ADDR_CTRL_SETUP_ERROR 0
|
78 |
|
|
set fpga_tCK_ADDR_CTRL_HOLD_ERROR 0
|
79 |
|
|
set fpga_tDQSS_SETUP_ERROR 0
|
80 |
|
|
set fpga_tDQSS_HOLD_ERROR 0
|
81 |
|
|
set fpga_tDSSH_SETUP_ERROR 0
|
82 |
|
|
set fpga_tDSSH_HOLD_ERROR 0
|
83 |
|
|
set write_deskew_mode "none"
|
84 |
|
|
set read_deskew_mode "none"
|
85 |
|
|
set write_deskew_t10 0
|
86 |
|
|
set write_deskew_t9i 0
|
87 |
|
|
set write_deskew_t9ni 0
|
88 |
|
|
set write_deskew_range 0
|
89 |
|
|
|
90 |
|
|
set period 6.666
|
91 |
|
|
|
92 |
|
|
load_package atoms
|
93 |
|
|
read_atom_netlist
|
94 |
|
|
|
95 |
|
|
proc traverse_atom_path {atom_id atom_oport_id path} {
|
96 |
|
|
# Return list of {atom oterm_id} pairs by tracing the atom netlist starting from the given atom_id through the given path
|
97 |
|
|
# Path consists of list of {atom_type fanin|fanout|end <port_type> <-optional>}
|
98 |
|
|
set result [list]
|
99 |
|
|
if {[llength $path] > 0} {
|
100 |
|
|
set path_point [lindex $path 0]
|
101 |
|
|
set atom_type [lindex $path_point 0]
|
102 |
|
|
set next_direction [lindex $path_point 1]
|
103 |
|
|
set port_type [lindex $path_point 2]
|
104 |
|
|
set atom_optional [lindex $path_point 3]
|
105 |
|
|
if {[get_atom_node_info -key type -node $atom_id] == $atom_type} {
|
106 |
|
|
if {$next_direction == "end"} {
|
107 |
|
|
if {[get_atom_port_info -key type -node $atom_id -port_id $atom_oport_id -type oport] == $port_type} {
|
108 |
|
|
lappend result [list $atom_id $atom_oport_id]
|
109 |
|
|
}
|
110 |
|
|
} elseif {$next_direction == "fanin"} {
|
111 |
|
|
set atom_iport [get_atom_iport_by_type -node $atom_id -type $port_type]
|
112 |
|
|
if {$atom_iport != -1} {
|
113 |
|
|
set iport_fanin [get_atom_port_info -key fanin -node $atom_id -port_id $atom_iport -type iport]
|
114 |
|
|
set source_atom [lindex $iport_fanin 0]
|
115 |
|
|
set source_oterm [lindex $iport_fanin 1]
|
116 |
|
|
set result [traverse_atom_path $source_atom $source_oterm [lrange $path 1 end]]
|
117 |
|
|
}
|
118 |
|
|
} elseif {$next_direction == "fanout"} {
|
119 |
|
|
set atom_oport [get_atom_oport_by_type -node $atom_id -type $port_type]
|
120 |
|
|
if {$atom_oport != -1} {
|
121 |
|
|
set oport_fanout [get_atom_port_info -key fanout -node $atom_id -port_id $atom_oport -type oport]
|
122 |
|
|
foreach dest $oport_fanout {
|
123 |
|
|
set dest_atom [lindex $dest 0]
|
124 |
|
|
set dest_iterm [lindex $dest 1]
|
125 |
|
|
set fanout_result_list [traverse_atom_path $dest_atom -1 [lrange $path 1 end]]
|
126 |
|
|
foreach fanout_result $fanout_result_list {
|
127 |
|
|
if {[lsearch $result $fanout_result] == -1} {
|
128 |
|
|
lappend result $fanout_result
|
129 |
|
|
}
|
130 |
|
|
}
|
131 |
|
|
}
|
132 |
|
|
}
|
133 |
|
|
} else {
|
134 |
|
|
error "Unexpected path"
|
135 |
|
|
}
|
136 |
|
|
} elseif {$atom_optional == "-optional"} {
|
137 |
|
|
set result [traverse_atom_path $atom_id $atom_oport_id [lrange $path 1 end]]
|
138 |
|
|
}
|
139 |
|
|
}
|
140 |
|
|
return $result
|
141 |
|
|
}
|
142 |
|
|
|
143 |
|
|
# Get the fitter name of the PLL output driving the given pin
|
144 |
|
|
proc traverse_to_ddio_out_pll_clock {pin msg_list_name} {
|
145 |
|
|
upvar 1 $msg_list_name msg_list
|
146 |
|
|
set result ""
|
147 |
|
|
if {$pin != ""} {
|
148 |
|
|
set pin_id [get_atom_node_by_name -name $pin]
|
149 |
|
|
set pin_to_pll_path [list {IO_PAD fanin PADIN} {IO_OBUF fanin I} {PSEUDO_DIFF_OUT fanin I -optional} {DDIO_OUT fanin CLKHI -optional} {CLKBUF fanin INCLK -optional} {PLL end CLK}]
|
150 |
|
|
set pll_id_list [traverse_atom_path $pin_id -1 $pin_to_pll_path]
|
151 |
|
|
if {[llength $pll_id_list] == 1} {
|
152 |
|
|
set atom_oterm_pair [lindex $pll_id_list 0]
|
153 |
|
|
set result [get_atom_port_info -key name -node [lindex $atom_oterm_pair 0] -port_id [lindex $atom_oterm_pair 1] -type oport]
|
154 |
|
|
} else {
|
155 |
|
|
lappend msg_list "Error: PLL clock not found for $pin"
|
156 |
|
|
}
|
157 |
|
|
}
|
158 |
|
|
return $result
|
159 |
|
|
}
|
160 |
|
|
|
161 |
|
|
proc verify_high_performance_timing_assumptions {instname pin_array_name write_deskew_t10} {
|
162 |
|
|
upvar 1 $pin_array_name pins
|
163 |
|
|
set num_errors 0
|
164 |
|
|
load_package verify_ddr
|
165 |
|
|
set ck_pins [lsort $pins(ck_p)]
|
166 |
|
|
set ckn_pins [lsort $pins(ck_n)]
|
167 |
|
|
set ck_ckn_pairs [list]
|
168 |
|
|
set failed_assumptions [list]
|
169 |
|
|
|
170 |
|
|
if {[llength $ck_pins] > 0 && [llength $ck_pins] == [llength $ckn_pins]} {
|
171 |
|
|
for {set ck_index 0} {$ck_index != [llength $ck_pins]} {incr ck_index} {
|
172 |
|
|
lappend ck_ckn_pairs [list [lindex $ck_pins $ck_index] [lindex $ckn_pins $ck_index]]
|
173 |
|
|
}
|
174 |
|
|
} else {
|
175 |
|
|
incr num_errors
|
176 |
|
|
lappend failed_assumptions "Error: Could not locate same number of CK pins as CK# pins"
|
177 |
|
|
}
|
178 |
|
|
|
179 |
|
|
set read_pins_list [list]
|
180 |
|
|
set write_pins_list [list]
|
181 |
|
|
foreach dqsgroup $pins(dqsgroup) {
|
182 |
|
|
set dqs [lindex $dqsgroup 0]
|
183 |
|
|
set dq_list [lindex $dqsgroup 2]
|
184 |
|
|
lappend read_pins_list [list $dqs $dq_list]
|
185 |
|
|
set dm_list [lindex $dqsgroup 1]
|
186 |
|
|
lappend write_pins_list [list $dqs [concat $dq_list $dm_list]]
|
187 |
|
|
}
|
188 |
|
|
set all_write_dqs_list [get_all_dqs_pins $pins(dqsgroup)]
|
189 |
|
|
set all_d_list [get_all_dq_pins $pins(dqsgroup)]
|
190 |
|
|
if {[llength $pins(dqsgroup)] == 0} {
|
191 |
|
|
incr num_errors
|
192 |
|
|
lappend failed_assumptions "Error: Could not locate DQS pins"
|
193 |
|
|
}
|
194 |
|
|
|
195 |
|
|
if {$num_errors == 0} {
|
196 |
|
|
set msg_list [list]
|
197 |
|
|
set clk_to_write_d [traverse_to_ddio_out_pll_clock [lindex $all_d_list 0] msg_list]
|
198 |
|
|
set clk_to_write_clock [traverse_to_ddio_out_pll_clock [lindex $all_write_dqs_list 0] msg_list]
|
199 |
|
|
set clk_to_ck_ckn [traverse_to_ddio_out_pll_clock [lindex $ck_pins 0] msg_list]
|
200 |
|
|
|
201 |
|
|
foreach msg $msg_list {
|
202 |
|
|
set verify_assumptions_exception 1
|
203 |
|
|
incr num_errors
|
204 |
|
|
lappend failed_assumptions $msg
|
205 |
|
|
}
|
206 |
|
|
|
207 |
|
|
if {$num_errors == 0} {
|
208 |
|
|
#puts "calling verify_assumptions -memory_type ddr -read_pins_list $read_pins_list -write_pins_list $write_pins_list -ck_ckn_pairs $ck_ckn_pairs -clk_to_write_d $clk_to_write_d -clk_to_write_clock $clk_to_write_clock -clk_to_ck_ckn $clk_to_ck_ckn -mimic_pin [lindex $ck_pins 0] "
|
209 |
|
|
set verify_assumptions_exception 0
|
210 |
|
|
set verify_assumptions_result {0}
|
211 |
|
|
set verify_assumptions_exception [catch {verify_assumptions -memory_type ddr -read_pins_list $read_pins_list -write_pins_list $write_pins_list -ck_ckn_pairs $ck_ckn_pairs -clk_to_write_d $clk_to_write_d -clk_to_write_clock $clk_to_write_clock -clk_to_ck_ckn $clk_to_ck_ckn -mimic_pin [lindex $ck_pins 0] } verify_assumptions_result]
|
212 |
|
|
if {$verify_assumptions_exception == 0} {
|
213 |
|
|
incr num_errors [lindex $verify_assumptions_result 0]
|
214 |
|
|
set failed_assumptions [concat $failed_assumptions [lrange $verify_assumptions_result 1 end]]
|
215 |
|
|
}
|
216 |
|
|
}
|
217 |
|
|
if {$verify_assumptions_exception != 0} {
|
218 |
|
|
lappend failed_assumptions "Error: Macro timing assumptions could not be verified"
|
219 |
|
|
incr num_errors
|
220 |
|
|
}
|
221 |
|
|
}
|
222 |
|
|
|
223 |
|
|
if {$num_errors != 0} {
|
224 |
|
|
for {set i 0} {$i != [llength $failed_assumptions]} {incr i} {
|
225 |
|
|
set raw_msg [lindex $failed_assumptions $i]
|
226 |
|
|
if {[regexp {^\W*(Info|Extra Info|Warning|Critical Warning|Error): (.*)$} $raw_msg -- msg_type msg]} {
|
227 |
|
|
regsub " " $msg_type _ msg_type
|
228 |
|
|
if {$msg_type == "Error"} {
|
229 |
|
|
set msg_type "critical_warning"
|
230 |
|
|
}
|
231 |
|
|
post_message -type $msg_type $msg
|
232 |
|
|
} else {
|
233 |
|
|
post_message -type info $raw_msg
|
234 |
|
|
}
|
235 |
|
|
}
|
236 |
|
|
post_message -type critical_warning "Read Capture and Write timing analyses may not be valid due to violated timing model assumptions"
|
237 |
|
|
}
|
238 |
|
|
return [expr $num_errors == 0]
|
239 |
|
|
}
|
240 |
|
|
|
241 |
|
|
proc ddr_pin {n pin pin_array_name} {
|
242 |
|
|
upvar 1 $pin_array_name pins
|
243 |
|
|
lappend pins($n) $pin
|
244 |
|
|
}
|
245 |
|
|
|
246 |
|
|
load_package report
|
247 |
|
|
load_report
|
248 |
|
|
|
249 |
|
|
if { ! [timing_netlist_exist] } {
|
250 |
|
|
post_message -type error "Timing Netlist has not been created. Run the 'Update Timing Netlist' task first."
|
251 |
|
|
return
|
252 |
|
|
}
|
253 |
|
|
|
254 |
|
|
source "${corename}_ddr_pins.tcl"
|
255 |
|
|
|
256 |
|
|
set corename [file tail $corename]
|
257 |
|
|
set instance_names [get_core_full_instance_list $corename]
|
258 |
|
|
|
259 |
|
|
for {set inst_index 0} {$inst_index != [llength $instance_names]} {incr inst_index} {
|
260 |
|
|
set full_instance_name [lindex $instance_names $inst_index]
|
261 |
|
|
set instance_name [get_timequest_name $full_instance_name]
|
262 |
|
|
set instname "${instance_name}|${corename}"
|
263 |
|
|
|
264 |
|
|
global TimeQuestInfo
|
265 |
|
|
set family $TimeQuestInfo(family)
|
266 |
|
|
|
267 |
|
|
set pins(ck_p) [list]
|
268 |
|
|
set pins(ck_n) [list]
|
269 |
|
|
set pins(addrcmd) [list]
|
270 |
|
|
set pins(addrcmd_2t) [list]
|
271 |
|
|
set pins(dqsgroup) [list]
|
272 |
|
|
set pins(dgroup) [list]
|
273 |
|
|
get_ddr_pins $instname pins
|
274 |
|
|
# Find all the DQ pins
|
275 |
|
|
set alldqpins [list]
|
276 |
|
|
set alldqdmpins [list]
|
277 |
|
|
set alldqspins [list]
|
278 |
|
|
foreach dqsgroup $pins(dqsgroup) {
|
279 |
|
|
set alldqpins [concat $alldqpins [lindex $dqsgroup 2]]
|
280 |
|
|
set alldqdmpins [concat $alldqdmpins [lindex $dqsgroup 2] [lindex $dqsgroup 1]]
|
281 |
|
|
lappend alldqspins [lindex $dqsgroup 0]
|
282 |
|
|
}
|
283 |
|
|
|
284 |
|
|
set summary [list]
|
285 |
|
|
foreach opc $opcs {
|
286 |
|
|
if {$opc != "" } {
|
287 |
|
|
set_operating_conditions $opc
|
288 |
|
|
update_timing_netlist
|
289 |
|
|
}
|
290 |
|
|
|
291 |
|
|
set opcname [get_operating_conditions_info [get_operating_conditions] -display_name]
|
292 |
|
|
set opcname [string trim $opcname]
|
293 |
|
|
|
294 |
|
|
if {$altera_ddr_phy_use_high_performance_timing && $family != "HardCopy III" && $family != "HardCopy IV"} {
|
295 |
|
|
set assumptions_valid [verify_high_performance_timing_assumptions $instname pins $write_deskew_t10]
|
296 |
|
|
}
|
297 |
|
|
# endif altera_ddr_phy_use_high_performance_timing
|
298 |
|
|
|
299 |
|
|
if {!$altera_ddr_phy_use_high_performance_timing} {
|
300 |
|
|
# Write
|
301 |
|
|
set res_0 [report_timing -detail full_path -to [get_ports $alldqdmpins] -npaths 100 -panel_name "$instname Write \u0028setup\u0029" -setup]
|
302 |
|
|
set res_1 [report_timing -detail full_path -to [get_ports $alldqdmpins] -npaths 100 -panel_name "$instname Write \u0028hold\u0029" -hold]
|
303 |
|
|
lappend summary [list $opcname 0 "Write ($opcname)" [lindex $res_0 1] [lindex $res_1 1]]
|
304 |
|
|
|
305 |
|
|
}
|
306 |
|
|
# endif !altera_ddr_phy_use_high_performance_timing
|
307 |
|
|
|
308 |
|
|
# Address Command
|
309 |
|
|
set res_0 [report_timing -detail full_path -to $pins(addrcmd) -npaths 100 -panel_name "$instname Address Command \u0028setup\u0029" -setup]
|
310 |
|
|
set res_1 [report_timing -detail full_path -to $pins(addrcmd) -npaths 100 -panel_name "$instname Address Command \u0028hold\u0029" -hold]
|
311 |
|
|
lappend summary [list $opcname 0 "Address Command ($opcname)" [lindex $res_0 1] [lindex $res_1 1]]
|
312 |
|
|
|
313 |
|
|
# DQS vs CK
|
314 |
|
|
set res_0 [report_timing -detail full_path -to [get_ports $alldqspins] -npaths 100 -panel_name "$instname DQS vs CK \u0028setup\u0029" -setup]
|
315 |
|
|
set res_1 [report_timing -detail full_path -to [get_ports $alldqspins] -npaths 100 -panel_name "$instname DQS vs CK \u0028hold\u0029" -hold]
|
316 |
|
|
lappend summary [list $opcname 0 "DQS vs CK ($opcname)" [lindex $res_0 1] [lindex $res_1 1]]
|
317 |
|
|
|
318 |
|
|
if {!$altera_ddr_phy_use_high_performance_timing} {
|
319 |
|
|
# Read Capture
|
320 |
|
|
set res_0 [report_timing -detail full_path -from [get_ports $alldqpins] -to [all_registers] -npaths 100 -panel_name "$instname Read Capture \u0028setup\u0029" -setup]
|
321 |
|
|
set res_1 [report_timing -detail full_path -from [get_ports $alldqpins] -to [all_registers] -npaths 100 -panel_name "$instname Read Capture \u0028hold\u0029" -hold]
|
322 |
|
|
lappend summary [list $opcname 0 "Read Capture ($opcname)" [lindex $res_0 1] [lindex $res_1 1]]
|
323 |
|
|
|
324 |
|
|
}
|
325 |
|
|
# endif !altera_ddr_phy_use_high_performance_timing
|
326 |
|
|
|
327 |
|
|
# Phy
|
328 |
|
|
set res_0 [report_timing -detail full_path -to [get_registers "$full_instance_name|*" ] -npaths 100 -panel_name "$instname Phy \u0028setup\u0029" -setup]
|
329 |
|
|
set res_1 [report_timing -detail full_path -to [get_registers "$full_instance_name|*" ] -npaths 100 -panel_name "$instname Phy \u0028hold\u0029" -hold]
|
330 |
|
|
lappend summary [list $opcname 0 "Phy ($opcname)" [lindex $res_0 1] [lindex $res_1 1]]
|
331 |
|
|
|
332 |
|
|
# Phy Reset
|
333 |
|
|
set res_0 [report_timing -detail full_path -to [get_registers "$full_instance_name|*" ] -npaths 100 -panel_name "$instname Phy Reset \u0028recovery\u0029" -recovery]
|
334 |
|
|
set res_1 [report_timing -detail full_path -to [get_registers "$full_instance_name|*" ] -npaths 100 -panel_name "$instname Phy Reset \u0028removal\u0029" -removal]
|
335 |
|
|
lappend summary [list $opcname 0 "Phy Reset ($opcname)" [lindex $res_0 1] [lindex $res_1 1]]
|
336 |
|
|
|
337 |
|
|
# Mimic
|
338 |
|
|
set res_1 [list xxx ""]
|
339 |
|
|
set res_0 [report_timing -detail full_path -from $pins(ck_p) -to * -npaths 100 -panel_name "$instname Mimic \u0028setup\u0029" -setup]
|
340 |
|
|
lappend summary [list $opcname 0 "Mimic ($opcname)" [lindex $res_0 1] [lindex $res_1 1]]
|
341 |
|
|
|
342 |
|
|
}
|
343 |
|
|
set opcname "All Conditions"
|
344 |
|
|
set tDCD_total 0.250
|
345 |
|
|
|
346 |
|
|
if {$altera_ddr_phy_use_high_performance_timing} {
|
347 |
|
|
set board_skew 0.020
|
348 |
|
|
set tmin_additional_dqs_variation 0.000
|
349 |
|
|
set tmax_additional_dqs_variation 0.000
|
350 |
|
|
set tDS 0.400
|
351 |
|
|
set tDH 0.400
|
352 |
|
|
set tDQSQ 0.400
|
353 |
|
|
set tQHS 0.500
|
354 |
|
|
set tAC 0.700
|
355 |
|
|
set all_read_dqs_list [get_all_dqs_pins $pins(dqsgroup)]
|
356 |
|
|
set all_write_dqs_list $all_read_dqs_list
|
357 |
|
|
set all_d_list [get_all_dq_pins $pins(dqsgroup)]
|
358 |
|
|
set mem_if_memtype "DDR SDRAM"
|
359 |
|
|
set dqs_phase 60.000
|
360 |
|
|
# Write capture
|
361 |
|
|
set msg_list [list]
|
362 |
|
|
set dqs_pll_output_id [get_output_clock_id $all_write_dqs_list "DQS output" msg_list]
|
363 |
|
|
set dqs_pll_clock ""
|
364 |
|
|
sett_collection dqs_pll_clock_id [get_clocks [get_pin_info -name $dqs_pll_output_id]]
|
365 |
|
|
set dqs_output_phase [get_clock_info -phase $dqs_pll_clock_id]
|
366 |
|
|
set dq_pll_output_id [get_output_clock_id $all_d_list "DQ output" msg_list]
|
367 |
|
|
set dq_pll_clock ""
|
368 |
|
|
sett_collection dq_pll_clock_id [get_clocks [get_pin_info -name $dq_pll_output_id]]
|
369 |
|
|
set dq_output_phase [get_clock_info -phase $dq_pll_clock_id]
|
370 |
|
|
set dq2dqs_output_phase_offset [expr $dqs_output_phase - $dq_output_phase]
|
371 |
|
|
if {$dq2dqs_output_phase_offset < 0} {
|
372 |
|
|
set dq2dqs_output_phase_offset [expr $dq2dqs_output_phase_offset + 360.0]
|
373 |
|
|
}
|
374 |
|
|
set tccs [get_tccs $mem_if_memtype $all_write_dqs_list $period]
|
375 |
|
|
set write_board_skew $board_skew
|
376 |
|
|
set su [round_3dp [expr {$period*$dq2dqs_output_phase_offset/360.0 - $write_board_skew - [lindex $tccs 0]/1000.0 - $tDS}]]
|
377 |
|
|
set hold [round_3dp [expr {$period*(0.5 - $dq2dqs_output_phase_offset/360.0) - $tDCD_total - $write_board_skew - [lindex $tccs 1]/1000.0 - $tDH}]]
|
378 |
|
|
lappend summary [list $opcname 0 "Write ($opcname)" $su $hold]
|
379 |
|
|
# Read capture
|
380 |
|
|
set tsw [get_tsw $mem_if_memtype $all_read_dqs_list $period]
|
381 |
|
|
|
382 |
|
|
################################################################################
|
383 |
|
|
# Cyclone III uses a Macro Timing Methodology for the write and capture paths.
|
384 |
|
|
# The read data is captured using a PLL phase which is calibrated and tracked
|
385 |
|
|
# with the sequencer. The PHY will automatically calibrate the phase of a
|
386 |
|
|
# dedicated PLL read clock to center it within the read data valid window
|
387 |
|
|
# presented to all DQ capture registers. The DQS read strobes are ignored, so
|
388 |
|
|
# postamble is not an issue. The phase of the read clock is adjusted to account
|
389 |
|
|
# for VT variations seen in the mimic path. Also, the exact length of the DQ
|
390 |
|
|
# and CK traces don't affect the timing analysis. Note that the read data
|
391 |
|
|
# resync to the PHY system clock domain is done through a dual-clock FIFO, so
|
392 |
|
|
# no resync timing analysis is needed for that transfer.
|
393 |
|
|
################################################################################
|
394 |
|
|
set su [round_3dp [expr {0.25*$period - 0.5*$tDCD_total - $tAC - [lindex $tsw 0]/1000.0 - 0.5 * $board_skew}]]
|
395 |
|
|
set hold [round_3dp [expr {0.25*$period - 0.5*$tDCD_total - $tAC - [lindex $tsw 1]/1000.0 - 0.5 * $board_skew}]]
|
396 |
|
|
lappend summary [list $opcname 0 "Read Capture ($opcname)" $su $hold]
|
397 |
|
|
|
398 |
|
|
}
|
399 |
|
|
# endif altera_ddr_phy_use_high_performance_timing
|
400 |
|
|
proc sort_proc {a b} {
|
401 |
|
|
set idxs [list 1 2 0]
|
402 |
|
|
foreach i $idxs {
|
403 |
|
|
set ai [lindex $a $i]
|
404 |
|
|
set bi [lindex $b $i]
|
405 |
|
|
if {$ai > $bi} {
|
406 |
|
|
return 1
|
407 |
|
|
} elseif { $ai < $bi } {
|
408 |
|
|
return -1
|
409 |
|
|
}
|
410 |
|
|
}
|
411 |
|
|
return 0
|
412 |
|
|
}
|
413 |
|
|
|
414 |
|
|
set summary [lsort -command sort_proc $summary]
|
415 |
|
|
if {[llength $instance_names] <= 1} {
|
416 |
|
|
set f [open "${corename}_summary.csv" w]
|
417 |
|
|
} else {
|
418 |
|
|
set f [open "${corename}${inst_index}_summary.csv" w]
|
419 |
|
|
}
|
420 |
|
|
puts $f "#Path, Setup Margin, Hold Margin"
|
421 |
|
|
post_message -type info " setup hold"
|
422 |
|
|
set panel_name "$instname"
|
423 |
|
|
set root_folder_name [get_current_timequest_report_folder]
|
424 |
|
|
if { ! [string match "${root_folder_name}*" $panel_name] } {
|
425 |
|
|
set panel_name "${root_folder_name}||$panel_name"
|
426 |
|
|
}
|
427 |
|
|
# Create the root if it doesn't yet exist
|
428 |
|
|
if {[get_report_panel_id $root_folder_name] == -1} {
|
429 |
|
|
set panel_id [create_report_panel -folder $root_folder_name]
|
430 |
|
|
}
|
431 |
|
|
|
432 |
|
|
# Delete any pre-existing summary panel
|
433 |
|
|
set panel_id [get_report_panel_id $panel_name]
|
434 |
|
|
if {$panel_id != -1} {
|
435 |
|
|
delete_report_panel -id $panel_id
|
436 |
|
|
}
|
437 |
|
|
|
438 |
|
|
# Create summary panel
|
439 |
|
|
set panel_id [create_report_panel -table $panel_name]
|
440 |
|
|
add_row_to_table -id $panel_id [list "Path" "Operating Condition" "Setup Slack" "Hold Slack"]
|
441 |
|
|
foreach summary_line $summary {
|
442 |
|
|
foreach {corner order path su hold} $summary_line { }
|
443 |
|
|
if { $su < 0 || ($hold!="" && $hold < 0) } {
|
444 |
|
|
set type warning
|
445 |
|
|
set offset 50
|
446 |
|
|
} else {
|
447 |
|
|
set type info
|
448 |
|
|
set offset 53
|
449 |
|
|
}
|
450 |
|
|
set su [format %.3f $su]
|
451 |
|
|
if {$hold != ""} {
|
452 |
|
|
set hold [format %.3f $hold]
|
453 |
|
|
}
|
454 |
|
|
post_message -type $type [format "%-${offset}s | %6s %6s" $path $su $hold]
|
455 |
|
|
puts $f [format "\"%s\",%s,%s" $path $su $hold]
|
456 |
|
|
set fg_colours [list black black]
|
457 |
|
|
if { $su < 0 } {
|
458 |
|
|
lappend fg_colours red
|
459 |
|
|
} else {
|
460 |
|
|
lappend fg_colours black
|
461 |
|
|
}
|
462 |
|
|
if { $hold != "" && $hold < 0 } {
|
463 |
|
|
lappend fg_colours red
|
464 |
|
|
} else {
|
465 |
|
|
lappend fg_colours black
|
466 |
|
|
}
|
467 |
|
|
add_row_to_table -id $panel_id -fcolors $fg_colours [list $path $corner $su $hold]
|
468 |
|
|
}
|
469 |
|
|
close $f
|
470 |
|
|
}
|
471 |
|
|
write_timing_report
|