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 |
|
|
################################################################################
|
15 |
|
|
# This file constrains the ALTMEMPHY memory interface PHY. The parameters at
|
16 |
|
|
# the top of thie file may be edited, but be warned that it it overwritten when
|
17 |
|
|
# regenerating the ALTMEMPHY Megacore Function.
|
18 |
|
|
################################################################################
|
19 |
|
|
# Generated by:9.0
|
20 |
|
|
# variation name : altera_ddr_phy
|
21 |
|
|
# family : Cyclone III
|
22 |
|
|
# speed_grade : 6
|
23 |
|
|
# local_if_drate : Full
|
24 |
|
|
# pll_ref_clk_mhz : 50.0
|
25 |
|
|
# mem_if_clk_mhz : 150.0
|
26 |
|
|
# mem_if_preset : PSC A2S56D40CTP-G5
|
27 |
|
|
# chip_or_dimm : Discrete Device
|
28 |
|
|
# mem_if_dq_per_dqs : 8
|
29 |
|
|
# ac_phase : 90
|
30 |
|
|
# ac_clk_select : 90
|
31 |
|
|
|
32 |
|
|
# The clock period of your memory interface. Don't modify this
|
33 |
|
|
set t(period) 6.666
|
34 |
|
|
|
35 |
|
|
# The worst case skew between any pair of traces which are nominally matched
|
36 |
|
|
set t(board_skew) 0.020
|
37 |
|
|
set t(min_additional_dqs_variation) 0.000
|
38 |
|
|
set t(max_additional_dqs_variation) 0.000
|
39 |
|
|
|
40 |
|
|
# Memory timing parameters. See Section 6 of the JEDEC spec.
|
41 |
|
|
# ----------------------------------
|
42 |
|
|
# tDS/tDH: write timing
|
43 |
|
|
set t(DS) 0.400
|
44 |
|
|
set t(DH) 0.400
|
45 |
|
|
|
46 |
|
|
# Data output timing for non-DQS capture
|
47 |
|
|
set t(AC) 0.700
|
48 |
|
|
|
49 |
|
|
# Address and command input timing
|
50 |
|
|
set t(IS) 0.600
|
51 |
|
|
set t(IH) 0.600
|
52 |
|
|
|
53 |
|
|
# DQS to CK input timing
|
54 |
|
|
set t(DSS) 0.2
|
55 |
|
|
set t(DSH) 0.2
|
56 |
|
|
set t(DQSS) 0.28
|
57 |
|
|
|
58 |
|
|
# DQ to DQS timing on read
|
59 |
|
|
set t(DQSQ) 0.400
|
60 |
|
|
set t(QHS) 0.500
|
61 |
|
|
|
62 |
|
|
# DQS to CK timing on reads
|
63 |
|
|
set t(DQSCK) 0.550
|
64 |
|
|
set t(capture_shift) 2.2
|
65 |
|
|
set t(HP) 3.000
|
66 |
|
|
|
67 |
|
|
# The maximum allowed length of the mimic path depends on the device family
|
68 |
|
|
if {$::TimeQuestInfo(family) == "Arria GX"} {
|
69 |
|
|
set t(mimic_shift) 2.200
|
70 |
|
|
} elseif {$::TimeQuestInfo(family) == "HardCopy II"} {
|
71 |
|
|
set t(mimic_shift) 2.000
|
72 |
|
|
} elseif {$::TimeQuestInfo(family) == "Cyclone III" || $::TimeQuestInfo(family) == "Cyclone III LS"} {
|
73 |
|
|
set t(mimic_shift) 2.500
|
74 |
|
|
} else {
|
75 |
|
|
set t(mimic_shift) 1.600
|
76 |
|
|
}
|
77 |
|
|
|
78 |
|
|
# The characterised margin loss on capture due to measurement error in the
|
79 |
|
|
# sequencer auto calibration.
|
80 |
|
|
set t(calibration_error) 1.144
|
81 |
|
|
|
82 |
|
|
|
83 |
|
|
# If the address and command paths are longer than the CK paths, put the
|
84 |
|
|
# difference in here
|
85 |
|
|
set t(additional_addresscmd_tpd) 0.000
|
86 |
|
|
|
87 |
|
|
# The variation name of this ALTMEMPHY
|
88 |
|
|
set corename "altera_ddr_phy"
|
89 |
|
|
|
90 |
|
|
# The clock period of the PLL reference clock
|
91 |
|
|
set t(inclk_period) 20.000
|
92 |
|
|
|
93 |
|
|
# Duty cycle distortion from the device data sheet
|
94 |
|
|
set t(DCD_total) 0.250
|
95 |
|
|
|
96 |
|
|
# PLL phase shift error
|
97 |
|
|
set t(PLL_PSERR) 0.000
|
98 |
|
|
|
99 |
|
|
|
100 |
|
|
################################################################################
|
101 |
|
|
# A callback to collect the results of the top level pin detection
|
102 |
|
|
################################################################################
|
103 |
|
|
proc ddr_pin {n pin pins_array_name} {
|
104 |
|
|
upvar 1 $pins_array_name pins
|
105 |
|
|
global pins
|
106 |
|
|
if {![info exists pins($n)] } {
|
107 |
|
|
post_message -type critical_warning "ddr_pin $n $pin $pins_array_name didn't recognise '$n' as a pin type"
|
108 |
|
|
} else {
|
109 |
|
|
lappend pins($n) $pin
|
110 |
|
|
}
|
111 |
|
|
}
|
112 |
|
|
|
113 |
|
|
################################################################################
|
114 |
|
|
# Locate the top level pins that are connected to this ALTMEMPHY instance
|
115 |
|
|
################################################################################
|
116 |
|
|
set pin_file_name "altera_ddr_phy_ddr_pins.tcl"
|
117 |
|
|
set dirname [file dirname [info script]]
|
118 |
|
|
set fn [file join $dirname $pin_file_name]
|
119 |
|
|
source $fn
|
120 |
|
|
|
121 |
|
|
################################################################################
|
122 |
|
|
# Add the SDC constraints for a single instantiation of this ALTMEMPHY
|
123 |
|
|
# variation. This is called multiple times if the variation has multiple
|
124 |
|
|
# instantiations.
|
125 |
|
|
################################################################################
|
126 |
|
|
proc add_requirements_for_instance {corename instance_name t_name altera_ddr_phy_use_high_performance_timing} {
|
127 |
|
|
upvar 1 $t_name t
|
128 |
|
|
set instname "${instance_name}|${corename}"
|
129 |
|
|
|
130 |
|
|
global ck_output_clocks
|
131 |
|
|
array unset ck_output_clocks
|
132 |
|
|
|
133 |
|
|
global pins
|
134 |
|
|
array unset pins
|
135 |
|
|
|
136 |
|
|
set pins(ck_p) [list]
|
137 |
|
|
set pins(ck_n) [list]
|
138 |
|
|
set pins(addrcmd) [list]
|
139 |
|
|
set pins(addrcmd_2t) [list]
|
140 |
|
|
set pins(dqsgroup) [list]
|
141 |
|
|
set pins(dgroup) [list]
|
142 |
|
|
|
143 |
|
|
################################################################################
|
144 |
|
|
# Cache the result of the automatic top level pin detection to reduce fit times
|
145 |
|
|
global pins_cache
|
146 |
|
|
if { [array exists pins_cache] && [info exists pins_cache($corename-$instance_name)] } {
|
147 |
|
|
# post_message -type critical_warning "cache hit"
|
148 |
|
|
array set pins $pins_cache($corename-$instance_name)
|
149 |
|
|
} else {
|
150 |
|
|
# post_message -type critical_warning "cache miss"
|
151 |
|
|
get_ddr_pins $instname pins
|
152 |
|
|
set pins_cache($corename-$instance_name) [array get pins]
|
153 |
|
|
}
|
154 |
|
|
|
155 |
|
|
################################################################################
|
156 |
|
|
# Create the PLL input clock and derive clocks on the PLL outputs
|
157 |
|
|
set msg_list [list]
|
158 |
|
|
|
159 |
|
|
set ck_pll_clock_id [get_output_clock_id $pins(ck_p) "CK output" msg_list]
|
160 |
|
|
if {$ck_pll_clock_id == -1} {
|
161 |
|
|
foreach {msg_type msg} $msg_list {
|
162 |
|
|
post_message -type $msg_type "altera_ddr_phy_ddr_timing.sdc: $msg"
|
163 |
|
|
}
|
164 |
|
|
post_message -type warning "altera_ddr_phy_ddr_timing.sdc: Failed to find PLL clock for pins [join $pins(ck_p)]"
|
165 |
|
|
} else {
|
166 |
|
|
set ck_pll_clock [get_node_info -name $ck_pll_clock_id]
|
167 |
|
|
set pll_ref_clk_id [get_input_clk_id $ck_pll_clock_id]
|
168 |
|
|
if {$pll_ref_clk_id != -1} {
|
169 |
|
|
set pll_ref_clk [get_node_info -name $pll_ref_clk_id]
|
170 |
|
|
if {[get_collection_size [get_clocks -nowarn $pll_ref_clk]] == 0} {
|
171 |
|
|
create_clock -period $t(inclk_period) $pll_ref_clk
|
172 |
|
|
}
|
173 |
|
|
|
174 |
|
|
if {[get_collection_size [get_clocks -nowarn $ck_pll_clock]] > 0} {
|
175 |
|
|
# PLL clocks already derived
|
176 |
|
|
} else {
|
177 |
|
|
derive_pll_clocks
|
178 |
|
|
}
|
179 |
|
|
} else {
|
180 |
|
|
post_message -type info "altera_ddr_phy_ddr_timing.sdc: Could not find PLL clocks for $ck_pll_clock. Creating PLL base clocks"
|
181 |
|
|
# Attempt to recover
|
182 |
|
|
derive_pll_clocks -create_base_clocks
|
183 |
|
|
}
|
184 |
|
|
derive_clock_uncertainty
|
185 |
|
|
}
|
186 |
|
|
|
187 |
|
|
################################################################################
|
188 |
|
|
|
189 |
|
|
# Find the TimeQuest name for the resync clock. If it is not found, create one.
|
190 |
|
|
set resync_clock_pattern ${instname}_alt_mem_phy_inst|clk|*|altpll_component|auto_generated|pll1|clk\[3\]
|
191 |
|
|
set resync_clock_id ""
|
192 |
|
|
sett_collection resync_clock_id [get_pins -compatibility_mode $resync_clock_pattern]
|
193 |
|
|
set resync_clock [get_node_info -name $resync_clock_id]
|
194 |
|
|
set resync_pll_ref_clk_id [get_input_clk_id $resync_clock_id]
|
195 |
|
|
|
196 |
|
|
if {$resync_pll_ref_clk_id != -1} {
|
197 |
|
|
set resync_pll_ref_clk [get_node_info -name $resync_pll_ref_clk_id]
|
198 |
|
|
if {[get_collection_size [get_clocks -nowarn $resync_pll_ref_clk]] == 0} {
|
199 |
|
|
create_clock -period $t(inclk_period) $resync_pll_ref_clk
|
200 |
|
|
}
|
201 |
|
|
} else {
|
202 |
|
|
post_message -type warning "altera_ddr_phy_ddr_timing.sdc: Failed to find PLL input clock pin driving $resync_clock"
|
203 |
|
|
}
|
204 |
|
|
|
205 |
|
|
################################################################################
|
206 |
|
|
|
207 |
|
|
# Find the TimeQuest name for the mimic clock. If it is not found, create one.
|
208 |
|
|
set mimic_clock_pattern ${instname}_alt_mem_phy_inst|clk|*|altpll_component|auto_generated|pll1|clk\[4\]
|
209 |
|
|
set mimic_clock_pins [get_pins -nowarn -compatibility_mode $mimic_clock_pattern]
|
210 |
|
|
|
211 |
|
|
if {[get_collection_size $mimic_clock_pins] == 1} {
|
212 |
|
|
set mimic_clock_id ""
|
213 |
|
|
sett_collection mimic_clock_id $mimic_clock_pins
|
214 |
|
|
set mimic_clock [get_node_info -name $mimic_clock_id]
|
215 |
|
|
} else {
|
216 |
|
|
post_message -type error "Couldn't find mimic clock from pattern $mimic_clock_pattern"
|
217 |
|
|
set mimic_clock ""
|
218 |
|
|
}
|
219 |
|
|
|
220 |
|
|
################################################################################
|
221 |
|
|
|
222 |
|
|
# Find the TimeQuest name for the system clock. If it is not found, create one.
|
223 |
|
|
set system_clock_pattern ${instname}_alt_mem_phy_inst|clk|*|altpll_component|auto_generated|pll1|clk\[1\]
|
224 |
|
|
set system_clock_pins [get_pins -nowarn -compatibility_mode $system_clock_pattern]
|
225 |
|
|
|
226 |
|
|
if {[get_collection_size $system_clock_pins] == 1} {
|
227 |
|
|
set system_clock_id ""
|
228 |
|
|
sett_collection system_clock_id $system_clock_pins
|
229 |
|
|
set system_clock [get_node_info -name $system_clock_id]
|
230 |
|
|
if {[info exists pll_ref_clk]} {
|
231 |
|
|
set_false_path -from $pll_ref_clk -to $system_clock
|
232 |
|
|
set_false_path -to $pll_ref_clk -from $system_clock
|
233 |
|
|
#Cut the path from the system clock to the mimic clock :
|
234 |
|
|
set_false_path -from $system_clock -to [get_clocks $mimic_clock]
|
235 |
|
|
}
|
236 |
|
|
} else {
|
237 |
|
|
set system_clock ""
|
238 |
|
|
}
|
239 |
|
|
|
240 |
|
|
|
241 |
|
|
################################################################################
|
242 |
|
|
# When the ALTMEMPHY is targeted for the HardCopy device family, additional
|
243 |
|
|
# clock uncertainties need to be added. These uncertainties will be provided by
|
244 |
|
|
# the HardCopy Design Centre in a file called _cu.tcl. They are
|
245 |
|
|
# not needed for the FPGA device families, and are set to zero in that case.
|
246 |
|
|
################################################################################
|
247 |
|
|
set fpga_tREAD_CAPTURE_SETUP_ERROR 0
|
248 |
|
|
set fpga_tREAD_CAPTURE_HOLD_ERROR 0
|
249 |
|
|
set fpga_RESYNC_SETUP_ERROR 0
|
250 |
|
|
set fpga_RESYNC_HOLD_ERROR 0
|
251 |
|
|
set fpga_PA_DQS_SETUP_ERROR 0
|
252 |
|
|
set fpga_PA_DQS_HOLD_ERROR 0
|
253 |
|
|
set WR_DQS_DQ_SETUP_ERROR 0
|
254 |
|
|
set WR_DQS_DQ_HOLD_ERROR 0
|
255 |
|
|
set fpga_tCK_ADDR_CTRL_SETUP_ERROR 0
|
256 |
|
|
set fpga_tCK_ADDR_CTRL_HOLD_ERROR 0
|
257 |
|
|
set fpga_tDQSS_SETUP_ERROR 0
|
258 |
|
|
set fpga_tDQSS_HOLD_ERROR 0
|
259 |
|
|
set fpga_tDSSH_SETUP_ERROR 0
|
260 |
|
|
set fpga_tDSSH_HOLD_ERROR 0
|
261 |
|
|
################################################################################
|
262 |
|
|
# post_message -type info "Creating CK output clocks"
|
263 |
|
|
set ck_clock_types_list [list tDSS tDQSS ac_rise ac_fall]
|
264 |
|
|
set source $ck_pll_clock
|
265 |
|
|
|
266 |
|
|
foreach ckpin [concat $pins(ck_p) $pins(ck_n)] {
|
267 |
|
|
if { [lsearch -exact $pins(ck_p) $ckpin] != -1 } {
|
268 |
|
|
set invert 0
|
269 |
|
|
set ckpn p
|
270 |
|
|
} elseif { [lsearch -exact $pins(ck_n) $ckpin] != -1 } {
|
271 |
|
|
set invert 1
|
272 |
|
|
set ckpn n
|
273 |
|
|
} else {
|
274 |
|
|
error "Can't find pin $ckpin in $pins(ck_p) or $pins(ck_n)"
|
275 |
|
|
}
|
276 |
|
|
|
277 |
|
|
# We don't care about the tco of the memory clocks
|
278 |
|
|
set_false_path -from * -to [get_ports $ckpin]
|
279 |
|
|
set clocknamestub "${instname}_ck_${ckpn}_${ckpin}"
|
280 |
|
|
|
281 |
|
|
foreach ck_clock_type $ck_clock_types_list {
|
282 |
|
|
set clockname "${clocknamestub}_${ck_clock_type}"
|
283 |
|
|
if { $invert } {
|
284 |
|
|
create_generated_clock -add -multiply_by 1 -source $source -master_clock $source -invert -name $clockname $ckpin
|
285 |
|
|
} else {
|
286 |
|
|
create_generated_clock -add -multiply_by 1 -source $source -master_clock $source -name $clockname $ckpin
|
287 |
|
|
}
|
288 |
|
|
add_output_clock $ck_clock_type $ckpn $clockname
|
289 |
|
|
}
|
290 |
|
|
}
|
291 |
|
|
|
292 |
|
|
# calibrated capture clock
|
293 |
|
|
set capture_clockname "${instname}_ddr_capture"
|
294 |
|
|
set capture_pattern ${instname}_alt_mem_phy_inst|dpio|dqs_group\[*\].dq\[*\].dqi|auto_generated|input_cell_*\[0\]|clk
|
295 |
|
|
create_clock -period $t(period) -name $capture_clockname [get_pins -compatibility_mode $capture_pattern] -add
|
296 |
|
|
set count 0
|
297 |
|
|
foreach_in_collection reg [get_pins -compatibility_mode $capture_pattern] {
|
298 |
|
|
set clockname "${instname}_dq_[incr count]"
|
299 |
|
|
create_generated_clock -name $clockname -source [get_pins -compatibility_mode $resync_clock] [get_pin_info -name $reg] -add
|
300 |
|
|
set_false_path -from [get_ports *] -to [get_clocks $clockname]
|
301 |
|
|
}
|
302 |
|
|
set_false_path -from [get_clocks $capture_clockname] -to [get_clocks $resync_clock]
|
303 |
|
|
# measure clock
|
304 |
|
|
set measure_clockname ${instname}_ddr_mimic
|
305 |
|
|
set measure_pattern ${instname}_alt_mem_phy_inst|clk|DDR_CLK_OUT\[0\].ddr_clk_out_p|auto_generated|input_cell_h\[0\]|clk
|
306 |
|
|
sett_collection c [get_pins -compatibility_mode $measure_pattern]
|
307 |
|
|
set source [get_node_info -name $c]
|
308 |
|
|
create_clock -period $t(period) -name $measure_clockname $source -add
|
309 |
|
|
set_false_path -from [get_clocks $mimic_clock] -to $measure_clockname
|
310 |
|
|
set_false_path -to [get_clocks $mimic_clock] -from $measure_clockname
|
311 |
|
|
foreach ck_clock_type_pn [array names ck_output_clocks] {
|
312 |
|
|
set_false_path -from [get_clocks $ck_output_clocks($ck_clock_type_pn)] -to [get_clocks $measure_clockname]
|
313 |
|
|
}
|
314 |
|
|
|
315 |
|
|
################################################################################
|
316 |
|
|
# The scan clock provides a slow-speed clock domain to drive the PLL phase
|
317 |
|
|
# stepping interface. It is created by dividing down a PLL output phase. All
|
318 |
|
|
# transfers to and from the scan clock domain have asynchronous clock domain
|
319 |
|
|
# crossings, so the only constraint on these paths is that they have a skew
|
320 |
|
|
# less than 2 whole cycles of the scan clock. The fastest that the scan clock
|
321 |
|
|
# can run is 100MHz, so we set a +/- 9ns skew constraint across the clock
|
322 |
|
|
# domain crossing.
|
323 |
|
|
################################################################################
|
324 |
|
|
set scan_clock_patterns [list ${instname}_alt_mem_phy_inst|clk|scan_clk|q 2]
|
325 |
|
|
foreach {pattern divide_by} $scan_clock_patterns {
|
326 |
|
|
foreach_in_collection c [get_pins -compatibility_mode $pattern] {
|
327 |
|
|
set source [get_node_info -name $c]
|
328 |
|
|
set sys_pll_clock [get_pll_clock [list $c] "System" "" 16]
|
329 |
|
|
if {$sys_pll_clock != ""} {
|
330 |
|
|
post_sdc_message info "Creating scan clock ${source}_clock driven by $sys_pll_clock divided by $divide_by"
|
331 |
|
|
create_generated_clock -multiply_by 1 -divide_by $divide_by -source $sys_pll_clock -master_clock $sys_pll_clock $source -name ${source}_clock
|
332 |
|
|
set_max_delay -to [get_clocks $sys_pll_clock] -from [get_clocks ${source}_clock] 9.0
|
333 |
|
|
set_max_delay -from [get_clocks $sys_pll_clock] -to [get_clocks ${source}_clock] 9.0
|
334 |
|
|
set_min_delay -to [get_clocks $sys_pll_clock] -from [get_clocks ${source}_clock] -9.0
|
335 |
|
|
set_min_delay -from [get_clocks $sys_pll_clock] -to [get_clocks ${source}_clock] -9.0
|
336 |
|
|
} else {
|
337 |
|
|
post_message -type warning "Cannot find source clock of $source"
|
338 |
|
|
}
|
339 |
|
|
}
|
340 |
|
|
}
|
341 |
|
|
|
342 |
|
|
set msg_list [list]
|
343 |
|
|
################################################################################
|
344 |
|
|
# Locate the clocks that drive the DQ and DQS pins when writing
|
345 |
|
|
################################################################################
|
346 |
|
|
set dqs_pll_clock_id [get_output_clock_id [get_all_dqs_pins $pins(dqsgroup)] "DQS output" msg_list]
|
347 |
|
|
set dq_pll_clock_id [get_output_clock_id [get_all_dq_pins $pins(dqsgroup)] "DQ output" msg_list]
|
348 |
|
|
|
349 |
|
|
if {$dqs_pll_clock_id == -1 || $dq_pll_clock_id == -1} {
|
350 |
|
|
foreach {msg_type msg} $msg_list {
|
351 |
|
|
post_message -type $msg_type "altera_ddr_phy_ddr_timing.sdc: $msg"
|
352 |
|
|
}
|
353 |
|
|
post_message -type warning "altera_ddr_phy_ddr_timing.sdc: Failed to find PLL clock for pins [join [get_all_dqs_pins $pins(dqsgroup)]]"
|
354 |
|
|
} else {
|
355 |
|
|
set dqsclksource [get_node_info -name $dqs_pll_clock_id]
|
356 |
|
|
set dqclksource [get_node_info -name $dq_pll_clock_id]
|
357 |
|
|
}
|
358 |
|
|
|
359 |
|
|
################################################################################
|
360 |
|
|
foreach dqsgroup $pins(dqsgroup) {
|
361 |
|
|
set dqspin [lindex $dqsgroup 0]
|
362 |
|
|
|
363 |
|
|
# If this design uses macro timing parameters, SDC constraints are not needed
|
364 |
|
|
if {!$altera_ddr_phy_use_high_performance_timing} {
|
365 |
|
|
# DQS output clock
|
366 |
|
|
set dqs_out_clockname "${instname}_ddr_dqsout_${dqspin}"
|
367 |
|
|
create_generated_clock -multiply_by 1 -source $dqsclksource -master_clock $dqsclksource $dqspin -name $dqs_out_clockname -add
|
368 |
|
|
}
|
369 |
|
|
# endif !altera_ddr_phy_use_high_performance_timing
|
370 |
|
|
if {!$altera_ddr_phy_use_high_performance_timing} {
|
371 |
|
|
|
372 |
|
|
################################################################################
|
373 |
|
|
# The write timing constrains the DQ write data with respect to the DQS strobe.
|
374 |
|
|
# An output clock is created on the DQS strobe, and we create a pair of
|
375 |
|
|
# set_output_delay assignments: one for the DQ data vs the rising edge of the
|
376 |
|
|
# DQS and the other against the falling edge.
|
377 |
|
|
# For the two max delay (setup) constraints:
|
378 |
|
|
#
|
379 |
|
|
# $t(board_skew)
|
380 |
|
|
# The worst case difference in propagation delay between the DQS strobe and any
|
381 |
|
|
# DQ pin within the same group.
|
382 |
|
|
#
|
383 |
|
|
# $t(DS)
|
384 |
|
|
# The setup requirement at the memory
|
385 |
|
|
#
|
386 |
|
|
# $WR_DQS_DQ_SETUP_ERROR
|
387 |
|
|
# An uncertainty term for HardCopy II designs, contact the HardCopy Design
|
388 |
|
|
# Centre for more information.
|
389 |
|
|
#
|
390 |
|
|
# For the two min delay (hold) constraints:
|
391 |
|
|
# - $t(board_skew)
|
392 |
|
|
# The worst case difference in propagation delay between the DQS strobe and any
|
393 |
|
|
# DQ pin within the same group.
|
394 |
|
|
#
|
395 |
|
|
# -$t(DH)
|
396 |
|
|
# The hold requirement at the memory
|
397 |
|
|
#
|
398 |
|
|
# - $t(DCD_total)
|
399 |
|
|
# Duty cycle distortion, since the launch and latch edges will be on the
|
400 |
|
|
# opposite edges
|
401 |
|
|
#
|
402 |
|
|
# - $WR_DQS_DQ_HOLD_ERROR
|
403 |
|
|
# An uncertainty term for HardCopy II designs, contact the HardCopy Design
|
404 |
|
|
# Centre for more information.
|
405 |
|
|
################################################################################
|
406 |
|
|
set_output_delay -add_delay -clock $dqs_out_clockname -max [round_3dp [expr {$t(board_skew) + $t(DS) + $WR_DQS_DQ_SETUP_ERROR}]] [concat [lindex $dqsgroup 1] [lindex $dqsgroup 2]]
|
407 |
|
|
set_output_delay -add_delay -clock $dqs_out_clockname -min [round_3dp [expr {-$t(DH) - $t(board_skew) - $WR_DQS_DQ_HOLD_ERROR}]] [concat [lindex $dqsgroup 1] [lindex $dqsgroup 2]]
|
408 |
|
|
set_output_delay -add_delay -clock_fall -clock $dqs_out_clockname -max [round_3dp [expr {$t(board_skew) + $t(DS) + $WR_DQS_DQ_SETUP_ERROR}]] [concat [lindex $dqsgroup 1] [lindex $dqsgroup 2]]
|
409 |
|
|
set_output_delay -add_delay -clock_fall -clock $dqs_out_clockname -min [round_3dp [expr {-$t(DH) - $t(board_skew) - $WR_DQS_DQ_HOLD_ERROR}]] [concat [lindex $dqsgroup 1] [lindex $dqsgroup 2]]
|
410 |
|
|
}
|
411 |
|
|
# endif !altera_ddr_phy_use_high_performance_timing
|
412 |
|
|
|
413 |
|
|
|
414 |
|
|
################################################################################
|
415 |
|
|
# The memory requires that the DQS strobes and CK clocks arrive edge aligned.
|
416 |
|
|
# For designs that generate CK/CK# from normal I/O (not recommended for
|
417 |
|
|
# HardCopy) this is just a problem for the board layout, since the DQS and CK
|
418 |
|
|
# signals are generated using the same structures from the same clocks.
|
419 |
|
|
# However, for designs that generate CK and CK# from dedicated PLL clock
|
420 |
|
|
# outputs (required for HardCopy), the CK and CK# outputs must use a different
|
421 |
|
|
# PLL clock than the slower DQS outputs to align themselves at the memory.
|
422 |
|
|
# There are two timing constraints: tDQSS says that the rising edge of DQS must
|
423 |
|
|
# align to the rising edge of ck to within 25% of a clock cycle, and tDSS/tDSH
|
424 |
|
|
# that requires the falling edge of DQS to be more than 20% of a clock cycle
|
425 |
|
|
# away from the rising edge of CK. This is automatically met if the minimum
|
426 |
|
|
# pulse width of CK is 45% (note that DDR3 has a 47/53 DCD requirement plus a
|
427 |
|
|
# separate jitter requirement).
|
428 |
|
|
# Since we need to correctly account for DCD, we must turn both of these
|
429 |
|
|
# parameters into timing constraints.
|
430 |
|
|
################################################################################
|
431 |
|
|
# DQS vs CK
|
432 |
|
|
################################################################################
|
433 |
|
|
# These offsets are only needed for designs that use a dedicated PLL output for
|
434 |
|
|
# the mem_ck pins. This design uses DDIO structures instead, so the required
|
435 |
|
|
# offset is zero.
|
436 |
|
|
################################################################################
|
437 |
|
|
set off_tDQSS 0
|
438 |
|
|
set off_tDSS 0
|
439 |
|
|
foreach ckclock [get_output_clocks tDQSS p] {
|
440 |
|
|
set_output_delay -add_delay -clock $ckclock -max [round_3dp [expr {($off_tDQSS+1-$t(DQSS)) * $t(period) + $t(board_skew) + $fpga_tDQSS_SETUP_ERROR}]] $dqspin
|
441 |
|
|
set_output_delay -add_delay -clock $ckclock -min [round_3dp [expr {($off_tDQSS+$t(DQSS)) * $t(period) - $t(board_skew) - $fpga_tDQSS_HOLD_ERROR}]] $dqspin
|
442 |
|
|
}
|
443 |
|
|
foreach ckclock [get_output_clocks tDQSS n] {
|
444 |
|
|
set_output_delay -add_delay -clock_fall -clock $ckclock -max [round_3dp [expr {($off_tDQSS+1-$t(DQSS)) * $t(period) + $t(board_skew) + $fpga_tDQSS_SETUP_ERROR}]] $dqspin
|
445 |
|
|
set_output_delay -add_delay -clock_fall -clock $ckclock -min [round_3dp [expr {($off_tDQSS+$t(DQSS)) * $t(period) - $t(board_skew) - $fpga_tDQSS_HOLD_ERROR}]] $dqspin
|
446 |
|
|
}
|
447 |
|
|
foreach ckclock [concat [get_output_clocks tDQSS p] [get_output_clocks tDQSS n]] {
|
448 |
|
|
set_false_path -to [get_clocks $ckclock] -fall_from [get_clocks $dqsclksource]
|
449 |
|
|
}
|
450 |
|
|
foreach ckclock [get_output_clocks tDSS p] {
|
451 |
|
|
set_output_delay -add_delay -clock $ckclock -max [round_3dp [expr {($off_tDSS+$t(DSS)) * $t(period) + $t(board_skew) + $fpga_tDSSH_SETUP_ERROR}]] $dqspin
|
452 |
|
|
set_output_delay -add_delay -clock $ckclock -min [round_3dp [expr {($off_tDSS-$t(DSH)) * $t(period) - $t(board_skew) - $fpga_tDSSH_HOLD_ERROR}]] $dqspin
|
453 |
|
|
}
|
454 |
|
|
foreach cknclock [get_output_clocks tDSS n] {
|
455 |
|
|
set_output_delay -add_delay -clock_fall -clock $cknclock -max [round_3dp [expr {($off_tDSS+$t(DSS)) * $t(period) + $t(board_skew) + $fpga_tDSSH_SETUP_ERROR}]] $dqspin
|
456 |
|
|
set_output_delay -add_delay -clock_fall -clock $cknclock -min [round_3dp [expr {($off_tDSS-$t(DSH)) * $t(period) - $t(board_skew) - $fpga_tDSSH_HOLD_ERROR}]] $dqspin
|
457 |
|
|
}
|
458 |
|
|
foreach ckclock [concat [get_output_clocks tDSS p] [get_output_clocks tDSS n]] {
|
459 |
|
|
# DSS and DSH are only for falling edge of DQS
|
460 |
|
|
set_false_path -to [get_clocks $ckclock] -rise_from [get_clocks $dqsclksource]
|
461 |
|
|
}
|
462 |
|
|
|
463 |
|
|
|
464 |
|
|
################################################################################
|
465 |
|
|
# There are three potential timing paths through a DDIO to the output pin. Two
|
466 |
|
|
# of these are from the output registers, and the third is the combinatorial
|
467 |
|
|
# path
|
468 |
|
|
# The only timing path through a DDIO that actually affects the output is the
|
469 |
|
|
# one that goes through the MUX. The timing delays through the other paths are
|
470 |
|
|
# chosen to ensure this.
|
471 |
|
|
################################################################################
|
472 |
|
|
set_false_path -from [all_registers] -to [get_ports $dqspin]
|
473 |
|
|
|
474 |
|
|
}
|
475 |
|
|
|
476 |
|
|
set x [expr {$t(HP) - 2*$t(AC) - $t(calibration_error)}]
|
477 |
|
|
set_max_delay -from [get_all_dq_pins $pins(dqsgroup)] -to [all_registers] [round_3dp [expr {$t(capture_shift) + 0.5*$x}]]
|
478 |
|
|
set_min_delay -from [get_all_dq_pins $pins(dqsgroup)] -to [all_registers] [round_3dp [expr {$t(capture_shift) - 0.5*$x}]]
|
479 |
|
|
set capture_clock $resync_clock
|
480 |
|
|
set_false_path -from [get_all_dq_pins $pins(dqsgroup)] -to [get_clocks $capture_clock]
|
481 |
|
|
set_false_path -to [get_pins -compatibility_mode ${instname}_alt_mem_phy_inst|dpio|dqs_group\[*\].dq\[*\].dqi|auto_generated|input_*_*\[0\]|clrn]
|
482 |
|
|
|
483 |
|
|
|
484 |
|
|
if {$altera_ddr_phy_use_high_performance_timing} {
|
485 |
|
|
|
486 |
|
|
# Cut paths to read capture registers, since they are subject to macro timing
|
487 |
|
|
# analysis
|
488 |
|
|
set dq_list [get_all_dq_pins $pins(dqsgroup)]
|
489 |
|
|
if {[llength $dq_list] > 0} {
|
490 |
|
|
set_false_path -from [concat $dq_list] -to [all_registers]
|
491 |
|
|
}
|
492 |
|
|
# Cut paths from write registers and PLL clocks-as-data
|
493 |
|
|
set d_dm_list [concat $dq_list [get_all_dm_pins $pins(dqsgroup)]]
|
494 |
|
|
if {[llength $d_dm_list] > 0} {
|
495 |
|
|
set_false_path -from * -to $d_dm_list
|
496 |
|
|
}
|
497 |
|
|
}
|
498 |
|
|
# endif altera_ddr_phy_use_high_performance_timing
|
499 |
|
|
|
500 |
|
|
#False path the read and write latency values from the sequencer, as these will be static when being used :
|
501 |
|
|
set rd_wr_latency_ops [get_pins -compatibility_mode ${instname}_alt_mem_phy_inst|*seq_wrapper|*seq_inst|*dgrb|?d_lat*|clk]
|
502 |
|
|
set_false_path -from $rd_wr_latency_ops
|
503 |
|
|
#False path the sequencer memory clock disable signal from the sequencer, as this will be static when being used :
|
504 |
|
|
set_false_path -from [get_pins -compatibility_mode ${instname}_alt_mem_phy_inst|*seq_wrapper|*seq_inst|seq_mem_clk_disable*]
|
505 |
|
|
|
506 |
|
|
################################################################################
|
507 |
|
|
# The mimic path consists of a register on a dedicated PLL clock phase that is
|
508 |
|
|
# set up to capture an echo of the outgoing CK clocks.
|
509 |
|
|
# The sequencer measures the arrival time of the echo of the CK clock by
|
510 |
|
|
# sweeping the dedicated PLL phase that is used to clock the mimic path
|
511 |
|
|
# register. By taking a reference measurement of this phase during calibration
|
512 |
|
|
# and comparing that with a similar measurement during operation, variations in
|
513 |
|
|
# timing due to voltage and temperature can be tracked.
|
514 |
|
|
# The mimic path register needs to be placed close to the IOE in order that the
|
515 |
|
|
# changes in the length of the routing from the IOE to the mimic path register
|
516 |
|
|
# doesn't distort the measurements.
|
517 |
|
|
################################################################################
|
518 |
|
|
foreach ck $pins(ck_p) {
|
519 |
|
|
create_clock -period $t(period) $ck -name ${instname}_${ck}_mimic_launch_clock -add
|
520 |
|
|
}
|
521 |
|
|
set_max_delay -from [get_clocks ${instname}_${ck}_mimic_launch_clock] -to [get_clocks *ddr_mimic] $t(mimic_shift)
|
522 |
|
|
|
523 |
|
|
# Cut asynchronous reset paths for clock domain crossing in the clocking and
|
524 |
|
|
# reset block
|
525 |
|
|
|
526 |
|
|
# - clk|global_pre_clear|clrn: The master reset flop, driven by the PLL locked
|
527 |
|
|
# output and the soft_reset_n and global_reset_n signals
|
528 |
|
|
|
529 |
|
|
# - clk|reset_master_ams|clrn: Synchronises the PLL locked reset to the
|
530 |
|
|
# global_pre_clear reset
|
531 |
|
|
|
532 |
|
|
# - clk|mem_pipe|ams_pipe\[*\]|clrn: Transfers the master reset to the mem
|
533 |
|
|
# clock domain
|
534 |
|
|
|
535 |
|
|
# - clk|mem_clk_pipe|ams_pipe\[*\]|clrn: Transfers the master reset to the mem
|
536 |
|
|
# clock domain
|
537 |
|
|
|
538 |
|
|
# - clk|write_clk_pipe|ams_pipe\[*\]|clrn: Transfers the master reset to the
|
539 |
|
|
# write clock domain
|
540 |
|
|
|
541 |
|
|
# - clk|measure_clk_pipe|ams_pipe\[*\]|clrn: Transfers the master reset to the
|
542 |
|
|
# measure clock domain
|
543 |
|
|
|
544 |
|
|
# - clk|resync_clk_pipe|ams_pipe\[*\]|clrn: Transfers the master reset to the
|
545 |
|
|
# resync clock domain
|
546 |
|
|
# - clk|clk_div_reset_ams_n_r|clrn: Master reset clock domain crossing
|
547 |
|
|
# - clk|clk_div_reset_ams_n|clrn: Master reset clock domain crossing
|
548 |
|
|
|
549 |
|
|
# - clk|pll_reconfig_reset_ams_n_r|clrn: Master reset clock domain crossing to
|
550 |
|
|
# the PLL reconfig block
|
551 |
|
|
|
552 |
|
|
# - clk|pll_reconfig_reset_ams_n|clrn: Master reset clock domain crossing to
|
553 |
|
|
# the PLL reconfig block
|
554 |
|
|
set clear_list [list \
|
555 |
|
|
${instname}_alt_mem_phy_inst|clk|*pll|altpll_component|auto_generated|pll_lock_sync|clrn \
|
556 |
|
|
${instname}_alt_mem_phy_inst|clk|global_pre_clear|clrn \
|
557 |
|
|
${instname}_alt_mem_phy_inst|clk|reset_master_ams|clrn \
|
558 |
|
|
${instname}_alt_mem_phy_inst|clk|mem_pipe|ams_pipe\[*\]|clrn \
|
559 |
|
|
${instname}_alt_mem_phy_inst|clk|mem_clk_pipe|ams_pipe\[*\]|clrn \
|
560 |
|
|
${instname}_alt_mem_phy_inst|clk|write_clk_pipe|ams_pipe\[*\]|clrn \
|
561 |
|
|
${instname}_alt_mem_phy_inst|clk|measure_clk_pipe|ams_pipe\[*\]|clrn \
|
562 |
|
|
${instname}_alt_mem_phy_inst|clk|resync_clk_pipe|ams_pipe\[*\]|clrn \
|
563 |
|
|
${instname}_alt_mem_phy_inst|clk|clk_div_reset_ams_n_r|clrn \
|
564 |
|
|
${instname}_alt_mem_phy_inst|clk|clk_div_reset_ams_n|clrn \
|
565 |
|
|
${instname}_alt_mem_phy_inst|clk|pll_reconfig_reset_ams_n_r|clrn \
|
566 |
|
|
${instname}_alt_mem_phy_inst|clk|pll_reconfig_reset_ams_n|clrn \
|
567 |
|
|
]
|
568 |
|
|
|
569 |
|
|
foreach clear $clear_list {
|
570 |
|
|
set clear_pins [get_pins -nowarn -compatibility_mode $clear]
|
571 |
|
|
if {[get_collection_size $clear_pins] > 0} {
|
572 |
|
|
set_false_path -thru $clear_pins -to *
|
573 |
|
|
}
|
574 |
|
|
}
|
575 |
|
|
|
576 |
|
|
|
577 |
|
|
################################################################################
|
578 |
|
|
# Timing constrain the Address/command outputs. Note that ALTMEMPHY uses a DDIO
|
579 |
|
|
# structure to generate the output, even though the output is single data rate
|
580 |
|
|
# (or half data rate for the non-chip-select pins, when in half rate mode). It
|
581 |
|
|
# does this by controlling the input to the DDIO such that the same data is
|
582 |
|
|
# driven out on the rising and falling edges, or on the falling edge and the
|
583 |
|
|
# subsequent rising edge. This is used to provide a 180 degree phase shift to
|
584 |
|
|
# the output when the address/command phase in the wizard is set to 90 degree
|
585 |
|
|
# or 180 degrees, which are inverted versions of the 270 degree write clock or
|
586 |
|
|
# 0 degree DQS clock.
|
587 |
|
|
#
|
588 |
|
|
# The transitions on the select signal driving the DDIO output MUX control the
|
589 |
|
|
# timing, so we have to cut the paths coming from the registers to the IO pin
|
590 |
|
|
# with a set_false_path -from [all_registers] assignment.
|
591 |
|
|
#
|
592 |
|
|
# We also have to tell TimeQuest that only the rising (or falling) edge of the
|
593 |
|
|
# address/command clock generates a transition on the output. This is done with
|
594 |
|
|
# a set_false_path -rise_from (or -fall_from) assignment.
|
595 |
|
|
#
|
596 |
|
|
# When the core is in half-rate mode, which is the default and needed to
|
597 |
|
|
# achieve the maximum possible frequency, all the address/command pins except
|
598 |
|
|
# the chip select (cs) pin are driven out a whole cycle early. This improves
|
599 |
|
|
# timing when the address bus has a greater load than the Chip Select signal.
|
600 |
|
|
# It is simply a set_multicycle_path assignment to all the 2t address/command
|
601 |
|
|
# pins.
|
602 |
|
|
################################################################################
|
603 |
|
|
################################################################################
|
604 |
|
|
# Address/Command
|
605 |
|
|
################################################################################
|
606 |
|
|
set msg_list [list]
|
607 |
|
|
set ac_pll_clock_id [get_output_clock_id $pins(addrcmd) "Address/Command output" msg_list]
|
608 |
|
|
if {$ac_pll_clock_id == -1} {
|
609 |
|
|
foreach {msg_type msg} $msg_list {
|
610 |
|
|
post_message -type $msg_type "altera_ddr_phy_ddr_timing.sdc: $msg"
|
611 |
|
|
}
|
612 |
|
|
post_message -type warning "altera_ddr_phy_ddr_timing.sdc: Failed to find PLL clock for pins [join $pins(addrcmd)]"
|
613 |
|
|
} else {
|
614 |
|
|
set ac_pll_clock [get_node_info -name $ac_pll_clock_id]
|
615 |
|
|
|
616 |
|
|
################################################################################
|
617 |
|
|
# These offset parameters are needed for designs that have the 'Use Dedicated
|
618 |
|
|
# PLL clock outputs' set. They are not needed in this case, and are set to
|
619 |
|
|
# zero.
|
620 |
|
|
################################################################################
|
621 |
|
|
set ded_off_rise 0
|
622 |
|
|
set ded_off_fall 0
|
623 |
|
|
set off $ded_off_fall
|
624 |
|
|
# Only analyze the DDIO mux select
|
625 |
|
|
set_false_path -from [all_registers] -to [concat $pins(addrcmd) $pins(addrcmd_2t)]
|
626 |
|
|
foreach ckclock [get_output_clocks ac_fall p] {
|
627 |
|
|
set_output_delay -add_delay -clock $ckclock -max [round_3dp [expr {$off*$t(period) + $t(IS) + $t(board_skew) + $fpga_tCK_ADDR_CTRL_SETUP_ERROR + $t(additional_addresscmd_tpd)}]] [concat $pins(addrcmd) $pins(addrcmd_2t)]
|
628 |
|
|
set_output_delay -add_delay -clock $ckclock -min [round_3dp [expr {$off*$t(period) - $t(IH) - $t(board_skew) - $fpga_tCK_ADDR_CTRL_HOLD_ERROR + $t(additional_addresscmd_tpd)}]] [concat $pins(addrcmd) $pins(addrcmd_2t)]
|
629 |
|
|
}
|
630 |
|
|
foreach ckclock [get_output_clocks ac_fall n] {
|
631 |
|
|
set_output_delay -add_delay -clock_fall -clock $ckclock -max [round_3dp [expr {$off*$t(period) + $t(IS) + $t(board_skew) + $fpga_tCK_ADDR_CTRL_SETUP_ERROR + $t(additional_addresscmd_tpd)}]] [concat $pins(addrcmd) $pins(addrcmd_2t)]
|
632 |
|
|
set_output_delay -add_delay -clock_fall -clock $ckclock -min [round_3dp [expr {$off*$t(period) - $t(IH) - $t(board_skew) - $fpga_tCK_ADDR_CTRL_HOLD_ERROR + $t(additional_addresscmd_tpd)}]] [concat $pins(addrcmd) $pins(addrcmd_2t)]
|
633 |
|
|
}
|
634 |
|
|
if {$ac_pll_clock_id != -1} {
|
635 |
|
|
foreach ckclock [concat [get_output_clocks ac_fall p] [get_output_clocks ac_fall n]] {
|
636 |
|
|
set_false_path -rise_from [get_clocks $ac_pll_clock] -to $ckclock
|
637 |
|
|
}
|
638 |
|
|
}
|
639 |
|
|
}
|
640 |
|
|
if { [llength $pins(addrcmd_2t)] > 0 } {
|
641 |
|
|
# post_message -type info "Address/Command (half rate)"
|
642 |
|
|
set_multicycle_path -setup -to $pins(addrcmd_2t) 2
|
643 |
|
|
set_multicycle_path -hold -to $pins(addrcmd_2t) 1
|
644 |
|
|
}
|
645 |
|
|
|
646 |
|
|
}
|
647 |
|
|
|
648 |
|
|
################################################################################
|
649 |
|
|
|
650 |
|
|
|
651 |
|
|
# Apply the timing constraints to every instantiation of this ALTMEMPHY
|
652 |
|
|
# variation within the design.
|
653 |
|
|
set instance_list [get_core_instance_list $corename]
|
654 |
|
|
foreach inst $instance_list {
|
655 |
|
|
post_sdc_message info "Adding SDC requirements for $corename instance $inst"
|
656 |
|
|
add_requirements_for_instance $corename $inst t $altera_ddr_phy_use_high_performance_timing
|
657 |
|
|
add_ddr_report_command "source [list [file join [file dirname [info script]] ${corename}_report_timing.tcl]]"
|
658 |
|
|
}
|