OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [soc/] [rtl/] [altera_ddr_ctrl/] [altera_ddr_phy_ddr_pins.tcl] - Blame information for rev 12

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 12 xianfeng
# This is a library of useful functions to include at the top of an SDC file.
2
 
3
proc walk_to_pin {type mainnode {depth 100}} {
4
        if { $type == "fanout" } {
5
                set edgename "-fanout_edges"
6
                set srcdst "-dst"
7
        } elseif { $type == "clock" } {
8
                set edgename "-clock_edges"
9
                set srcdst "-src"
10
        } elseif { $type == "fanin" } {
11
                set edgename "-synch_edges"
12
                set srcdst "-src"
13
        }
14
        set fanout [get_node_info $edgename $mainnode]
15
        foreach edge $fanout {
16
                set node [get_edge_info $srcdst $edge]
17
                if { [get_node_info -type $node] == "port" } {
18
                        return $node
19
                }
20
                set node_type [get_node_info -type $node]
21
                if {$depth > 0 && ($node_type == "comb" || $node_type == "pin")} {
22
                        #puts "walking down [get_node_info -name $node] [get_node_info -type $node]..."
23
                        set res [walk_to_pin $type $node [expr {$depth - 1}]]
24
                        if { $res != "" } {
25
                                return $res
26
                        }
27
                } else {
28
                        #puts "ignoring node [get_node_info -name $node] of type [get_node_info -type $node]"
29
                }
30
        }
31
        return ""
32
}
33
 
34
# Like walk_to_pin, but searches out in a tree if the 
35
# pin drives multiple ports
36
proc walk_to_all_pins {type collection {depth 100}} {
37
        if { $type == "fanout" } {
38
                set edgename "-fanout_edges"
39
                set srcdst "-dst"
40
        } elseif { $type == "clock" } {
41
                set edgename "-clock_edges"
42
                set srcdst "-src"
43
        } elseif { $type == "fanin" } {
44
                set edgename "-synch_edges"
45
                set srcdst "-src"
46
        }
47
        set res [list]
48
        foreach_in_collection mainnode $collection {
49
                set fanout [get_node_info $edgename $mainnode]
50
                foreach edge $fanout {
51
                        set node [get_edge_info $srcdst $edge]
52
                        if { [get_node_info -type $node] == "port" } {
53
                                lappend res $node
54
                        }
55
                        set node_type [get_node_info -type $node]
56
                        if {$depth > 0 && ($node_type == "comb" || $node_type == "pin")} {
57
                                #puts "walking down [get_node_info -name $node] [get_node_info -type $node]..."
58
                                set r [walk_to_pin $type $node [expr {$depth - 1}]]
59
                                set res [concat $res $r]
60
                        } else {
61
                                #puts "ignoring node [get_node_info -name $node] of type [get_node_info -type $node]"
62
                        }
63
                }
64
        }
65
        return $res
66
}
67
 
68
 
69
# (map walk_to_pin)
70
proc walk_to_pins { type collection {depth 100} } {
71
        set res [list]
72
        foreach_in_collection c $collection {
73
                set i [walk_to_pin $type $c $depth]
74
                if { $i == "" } {
75
                        #puts "Node [get_node_info -name $c] was a dead end"
76
                } else {
77
                        #puts "Got port for node [get_node_info -name $c]"
78
                        lappend res $i
79
                }
80
        }
81
        #puts "walk_to_pins returning: $res"
82
        return $res
83
}
84
 
85
# (map get_node_info -name)
86
proc map_get_node_name {nodes} {
87
        set res [list]
88
        foreach n $nodes {
89
                lappend res [get_node_info -name $n]
90
        }
91
        return $res
92
}
93
 
94
proc get_all_dqs_pins { dqsgroups} {
95
        set res [list]
96
        foreach dqsgroup $dqsgroups {
97
                lappend res [lindex $dqsgroup 0]
98
        }
99
        return $res
100
}
101
 
102
proc get_all_dq_pins { dqsgroups} {
103
        set res [list]
104
        foreach dqsgroup $dqsgroups {
105
                set res [concat $res [lindex $dqsgroup 2]]
106
        }
107
        return $res
108
}
109
 
110
proc get_all_dm_pins { dqsgroups} {
111
        set res [list]
112
        foreach dqsgroup $dqsgroups {
113
                set res [concat $res [lindex $dqsgroup 1]]
114
        }
115
        return $res
116
}
117
 
118
 
119
proc list_collection { col } {
120
        set res "("
121
        foreach_in_collection c $col {
122
                append res "[get_node_info -name $c]\n"
123
        }
124
        append res ")"
125
        return $res
126
}
127
 
128
proc sett_collection { vlist col } {
129
        set i 0
130
        set len [llength $vlist]
131
        foreach_in_collection c $col {
132
                if { $i < $len } {
133
                        upvar 1 [lindex $vlist $i] x
134
                        set x $c
135
                        incr i
136
                } else {
137
                        error "Too many items in collection ([expr {$i+1}]) for list $vlist"
138
                }
139
        }
140
        if { $i != $len } {
141
                error "Too Few items in collection ($i) for list $vlist"
142
        }
143
}
144
 
145
# For static deskew, get the frequency range of the given configuration
146
# Return triplet {mode min_freq max_freq}
147
proc get_deskew_freq_range {timing_params period} {
148
        set mode [list]
149
        # freq_range list should be sorted from low to high
150
        if {[lindex $timing_params 2] == "STATIC_DESKEW_8" || [lindex $timing_params 2] == "STATIC_DESKEW_10"}  {
151
                # These modes have more than 2 freq ranges
152
                set range_list [list LOW HIGH]
153
        } else {
154
                # Just 1 freq range
155
                set range_list [list [list]]
156
        }
157
        set freq_mode [list]
158
        foreach freq_range $range_list {
159
                if {[catch {get_micro_node_delay -micro MIN -parameters [concat $timing_params $freq_range]} min_freq] != 0 || $min_freq == "" ||
160
                        [catch {get_micro_node_delay -micro MAX -parameters [concat $timing_params $freq_range]} max_freq] != 0 || $max_freq == ""} {
161
                        # Invalid mode
162
                } else {
163
                        set max_freq_period [expr 1000.0 / $min_freq]
164
                        set min_freq_period [expr 1000.0 / $max_freq]
165
                        lappend freq_mode [list $freq_range $min_freq $max_freq]
166
                        if {$period >= $min_freq_period && $period <= $max_freq_period} {
167
                                set mode [lindex $freq_mode end]
168
                                break
169
                        }
170
                }
171
        }
172
        if {$mode == [list] && $freq_mode != [list]} {
173
                if {$period < $min_freq_period} {
174
                        # Fastest mode
175
                        set mode [lindex $freq_mode end]
176
                } else {
177
                        # Slowest mode
178
                        set mode [lindex $freq_mode 0]
179
                }
180
        }
181
        return $mode
182
}
183
# Return a tuple of the tCCS value for a given device
184
proc get_tccs { mem_if_memtype dqs_list period args} {
185
        global TimeQuestInfo
186
        array set options [list "-write_deskew" "none" "-dll_length" 0 "-config_period" 0 "-ddr3_discrete" 0]
187
        foreach {option value} $args {
188
                if {[array names options -exact "$option"] != ""} {
189
                        set options($option) $value
190
                } else {
191
                        error "ERROR: Unknown get_tccs option $option (with value $value; args are $args)"
192
                }
193
        }
194
 
195
        set interface_type [get_io_interface_type $dqs_list]
196
        # The tCCS for a HYBRID interface is the same as a HPAD interface
197
        if {$interface_type == "VHPAD"} {
198
                set interface_type "HPAD"
199
        }
200
        set io_std [get_io_standard [lindex $dqs_list 0]]
201
        set result [list 0 0]
202
        if {$interface_type != "" && $interface_type != "UNKNOWN" && $io_std != "" && $io_std != "UNKNOWN"} {
203
                package require ::quartus::ddr_timing_model
204
 
205
                set tccs_params [list IO $interface_type]
206
 
207
                if {$options(-ddr3_discrete) == 1} {
208
                        lappend tccs_params NONLEVELED
209
 
210
                } elseif {$options(-write_deskew) == "static"} {
211
 
212
                        if {$options(-dll_length) != 0} {
213
                                lappend tccs_params STATIC_DESKEW_$options(-dll_length)
214
                        } else {
215
                                # No DLL length dependency
216
                                lappend tccs_params STATIC_DESKEW
217
                        }
218
                } elseif {$options(-write_deskew) == "dynamic"} {
219
                        lappend tccs_params DYNAMIC_DESKEW
220
                }
221
                if {$options(-ddr3_discrete) == 0 && $options(-write_deskew) != "none"} {
222
                        set mode [get_deskew_freq_range $tccs_params $period]
223
                        set expected_mode [get_deskew_freq_range $tccs_params $options(-config_period)]
224
                        if {$mode == [list]} {
225
                                post_message -type critical_warning "Memory interface with period $period and write $options(-write_deskew) deskew does not fall in a supported frequency range"
226
                        } elseif {$expected_mode != $mode || $period < [expr 1000.0/[lindex $mode 2]] || $period > [expr 1000.0/[lindex $mode 1]]} {
227
                                post_message -type critical_warning "Memory interface with clock frequency [expr 1000.0/$period] MHz is operating outside the frequency range of the megafunction configuration (expected frequency range is from [lindex $expected_mode 1] MHz to [lindex $expected_mode 2] MHz).  The timing analysis will not be accurate."
228
                        } elseif {[lindex $mode 0] != [list]} {
229
                                lappend tccs_params [lindex $mode 0]
230
                        }
231
                }
232
                if {[catch {get_io_standard_node_delay -dst TCCS_LEAD -io_standard $io_std -parameters $tccs_params} tccs_lead] != 0 || $tccs_lead == "" || $tccs_lead == 0 || \
233
                                [catch {get_io_standard_node_delay -dst TCCS_LAG -io_standard $io_std -parameters $tccs_params} tccs_lag] != 0 || $tccs_lag == "" || $tccs_lag == 0 } {
234
                        set family $TimeQuestInfo(family)
235
                        error "Missing $family timing model for tCCS of $io_std $tccs_params"
236
                } else {
237
                        return [list $tccs_lead $tccs_lag]
238
                }
239
        }
240
}
241
 
242
# Return a tuple of setup,hold time for read capture
243
proc get_tsw { mem_if_memtype dqs_list period args} {
244
        global TimeQuestInfo
245
        array set options [list "-read_deskew" "none" "-dll_length" 0 "-config_period" 0 "-ddr3_discrete" 0]
246
        foreach {option value} $args {
247
                if {[array names options -exact "$option"] != ""} {
248
                        set options($option) $value
249
                } else {
250
                        error "ERROR: Unknown get_tsw option $option (with value $value; args are $args)"
251
                }
252
        }
253
 
254
        set interface_type [get_io_interface_type $dqs_list]
255
        set io_std [get_io_standard [lindex $dqs_list 0]]
256
 
257
        if {$interface_type != "" && $interface_type != "UNKNOWN" && $io_std != "" && $io_std != "UNKNOWN"} {
258
                package require ::quartus::ddr_timing_model
259
                set family $TimeQuestInfo(family)
260
                # The tSW for HYBRID DLL-based interfaces is the worst case of
261
                # VPAD and HPAD interfaces. Non-DLL-based interfaces have their own
262
                # VHPAD spec
263
                if {$interface_type == "VHPAD" && $options(-dll_length) > 0} {
264
                        set interface_type_list [list VPAD HPAD]
265
                } else {
266
                        set interface_type_list [list $interface_type]
267
                }
268
                set max_tsw_setup -999999
269
                set max_tsw_hold -999999
270
                foreach interface_type $interface_type_list {
271
                        set tsw_params [list IO $interface_type]
272
 
273
                        if {$options(-ddr3_discrete) == 1} {
274
                                lappend tsw_params NONLEVELED
275
 
276
                        } elseif {$options(-read_deskew) == "static"} {
277
                                if {$options(-dll_length) != 0} {
278
                                        lappend tsw_params STATIC_DESKEW_$options(-dll_length)
279
                                } else {
280
                                        # No DLL length dependency
281
                                        lappend tsw_params STATIC_DESKEW
282
                                }
283
                        } elseif {$options(-read_deskew) == "dynamic"} {
284
                                lappend tsw_params DYNAMIC_DESKEW
285
                        }
286
                        if {$options(-ddr3_discrete) == 0 && $options(-read_deskew) != "none"} {
287
                                set mode [get_deskew_freq_range $tsw_params $period]
288
                                if {$mode == [list]} {
289
                                        post_message -type critical_warning "Memory interface with period $period and read $options(-read_deskew) deskew does not fall in a supported frequency range"
290
                                } elseif {[lindex $mode 0] != [list]} {
291
                                        lappend tsw_params [lindex $mode 0]
292
                                }
293
                        }
294
 
295
                        if {[catch {get_io_standard_node_delay -dst TSU -io_standard $io_std -parameters $tsw_params} tsw_setup] != 0 || $tsw_setup == "" || $tsw_setup == 0 || \
296
                                        [catch {get_io_standard_node_delay -dst TH -io_standard $io_std -parameters $tsw_params} tsw_hold] != 0 || $tsw_hold == "" || $tsw_hold == 0 } {
297
                                error "Missing $family timing model for tSW of $io_std $tsw_params"
298
                        } else {
299
                                # Derate tSW for DDR2 on VPAD in CIII Q240 parts
300
                                # The tSW for HPADs and for other interface types on C8 devices
301
                                # have a large guardband, so derating for them is not required
302
                                if {[get_part_info -package -pin_count $TimeQuestInfo(part)] == "PQFP 240"} {
303
                                        if {[catch {get_io_standard_node_delay -dst TSU -io_standard $io_std -parameters [list IO $interface_type Q240_DERATING]} tsw_setup_derating] != 0 || $tsw_setup_derating == 0 || \
304
                                                        [catch {get_io_standard_node_delay -dst TH -io_standard $io_std -parameters [list IO $interface_type Q240_DERATING]} tsw_hold_derating] != 0 || $tsw_hold_derating == 0} {
305
                                                set f "$io_std/$interface_type/$family"
306
                                                switch -glob $f {
307
                                                        "SSTL_18*/VPAD/Cyclone III"  {
308
                                                                set tsw_setup_derating 50
309
                                                                set tsw_hold_derating 135
310
                                                        }
311
                                                        default {
312
                                                                set tsw_setup_derating 0
313
                                                                set tsw_hold_derating 0
314
                                                        }
315
                                                }
316
                                        }
317
                                        incr tsw_setup $tsw_setup_derating
318
                                        incr tsw_hold $tsw_hold_derating
319
                                }
320
                                if {$tsw_setup > $max_tsw_setup} {
321
                                        set max_tsw_setup $tsw_setup
322
                                }
323
                                if {$tsw_hold > $max_tsw_hold} {
324
                                        set max_tsw_hold $tsw_hold
325
                                }
326
                        }
327
                        return [list $max_tsw_setup $max_tsw_hold]
328
                }
329
        }
330
}
331
 
332
# Return a pseudo x36 derating tuple of setup,hold time for read capture
333
proc get_qdr_tsw_derating { dqs_list } {
334
        global TimeQuestInfo
335
        set io_std [get_io_standard [lindex $dqs_list 0]]
336
        set interface_type [get_io_interface_type [lindex $dqs_list 0]]
337
 
338
        if {[catch {get_io_standard_node_delay -dst TSU -io_standard $io_std -parameters [list IO $interface_type PSEUDOX36]} tsw_setup] != 0 || $tsw_setup == "" || \
339
                        [catch {get_io_standard_node_delay -dst TH -io_standard $io_std -parameters [list IO $interface_type PSEUDOX36]} tsw_hold] != 0 || $tsw_hold == "" || $tsw_hold == 0 } {
340
                set family $TimeQuestInfo(family)
341
                error "Missing $family timing model for derated tSW of $io_std $interface_type"
342
        } else {
343
                set result [list $tsw_setup $tsw_hold]
344
        }
345
        return $result
346
}
347
 
348
# Return a pseudo x36 derating tuple of setup,hold time for write capture
349
proc get_qdr_tccs_derating { dqs_list } {
350
        set io_std [get_io_standard [lindex $dqs_list 0]]
351
        set interface_type [get_io_interface_type [lindex $dqs_list 0]]
352
 
353
        if {[catch {get_io_standard_node_delay -dst TCCS_LEAD -io_standard $io_std -parameters [list IO $interface_type PSEUDOX36]} tccs_lead] != 0 || $tccs_lead == "" || $tccs_lead == 0 || \
354
                        [catch {get_io_standard_node_delay -dst TCCS_LAG -io_standard $io_std -parameters [list IO $interface_type PSEUDOX36]} tccs_lag] != 0 || $tccs_lag == "" || $tccs_lag == 0 } {
355
                set family $TimeQuestInfo(family)
356
                error "Missing $family timing model for derated tCCS of $io_std $interface_type"
357
        } else {
358
                set result [list $tccs_lead $tccs_lag]
359
        }
360
 
361
        return $result
362
}
363
 
364
proc round_3dp { x } {
365
        return [expr { round($x * 1000) / 1000.0  } ]
366
}
367
 
368
proc min { a b } {
369
        if { $a == "" } {
370
                return $b
371
        } elseif { $a < $b } {
372
                return $a
373
        } else {
374
                return $b
375
        }
376
}
377
 
378
proc max { a b } {
379
        if { $a == "" } {
380
                return $b
381
        } elseif { $a > $b } {
382
                return $a
383
        } else {
384
                return $b
385
        }
386
}
387
 
388
proc wrap_to_period {period t} {
389
        return [expr {fmod(fmod($t,$period) + $period,$period)}]
390
}
391
 
392
proc get_clock_latency {period clockname risefall } {
393
        set countclocks 0
394
        if { $risefall != "rise" && $risefall != "fall" } {
395
                error "Internal error: get_clock_latency risefall was $risefall expected \"rise\" or \"fall\""
396
        }
397
        foreach_in_collection c [get_clocks $clockname] {
398
                set clock $c
399
                incr countclocks
400
        }
401
        if { $countclocks == 1 } {
402
                if { $risefall == "rise" } {
403
                        set edge_index 0
404
                } elseif { $risefall == "fall" } {
405
                        set edge_index 1
406
                } else {
407
                        error "Unreachable in get_clock_latency"
408
                }
409
        } else {
410
                error "Internal error: Found $countclocks matching $clockname. Expected 1 in get_clock_latency"
411
        }
412
        set waveform [get_clock_info -waveform $clock]
413
        if {[llength $waveform] != 2 } {
414
                error "Internal error: Waveform for clock $clockname is \"$waveform\""
415
        }
416
        set latency [lindex $waveform $edge_index]
417
        set res [wrap_to_period $period $latency]
418
        return $res
419
}
420
 
421
# Same as get_clock_latency, but returns the clock phase (0<=x<360) normalised instead
422
proc get_clock_phase {period clockname risefall } {
423
        set countclocks 0
424
        if { $risefall != "rise" && $risefall != "fall" } {
425
                error "Internal error: get_clock_phase risefall was $risefall expected \"rise\" or \"fall\""
426
        }
427
        foreach_in_collection c [get_clocks $clockname] {
428
                set clock $c
429
                incr countclocks
430
        }
431
        if { $countclocks == 1 } {
432
                if { $risefall == "rise" } {
433
                        set offset 0
434
                } elseif { $risefall == "fall" } {
435
                        set offset 180
436
                } else {
437
                        error "Unreachable in get_clock_phase"
438
                }
439
        } else {
440
                error "Internal error: Found $countclocks matching $clockname. Expected 1 in get_clock_phase"
441
        }
442
        set phase [get_clock_info -phase $clock]
443
        set res [expr {fmod(($phase+$offset+360),360)}]
444
        return $res
445
}
446
 
447
 
448
proc expr_debug { exp } {
449
        upvar expr_debug_e expr_debug_e
450
        set expr_debug_e $exp
451
        uplevel {
452
        puts "-----------------"
453
        puts "[regsub -all {[\n \t]+} $expr_debug_e " "]"
454
        puts "-----------------"
455
        puts [regsub -all {[\n \t]+} [subst $expr_debug_e] " "]
456
        puts "-----------------"
457
        set expr_debug_temp [expr $expr_debug_e]
458
        puts "=$expr_debug_temp"
459
        puts "-----------------"
460
        return $expr_debug_temp
461
        }
462
}
463
 
464
# Return all the ck output clocks in the current design of a given type and 
465
# inversion
466
# type - either tDSS/tDQSS/ac_rise/ac_fall
467
# pn - either p/n
468
proc get_output_clocks {type pn} {
469
        global ck_output_clocks
470
        return $ck_output_clocks(${type}-${pn})
471
}
472
 
473
proc add_output_clock {type pn clockname} {
474
        global ck_output_clocks
475
        if { ! [info exists ck_output_clocks(${type}-${pn})] } {
476
                set ck_output_clocks(${type}-${pn}) [list]
477
        }
478
        lappend ck_output_clocks(${type}-${pn}) $clockname
479
}
480
 
481
# ----------------------------------------------------------------
482
#
483
proc get_timequest_name {hier_name} {
484
#
485
# Description:  Convert the full hierarchy name into a TimeQuest name
486
#
487
# ----------------------------------------------------------------
488
        set sta_name ""
489
        for {set inst_start [string first ":" $hier_name]} {$inst_start != -1} {} {
490
                incr inst_start
491
                set inst_end [string first "|" $hier_name $inst_start]
492
                if {$inst_end == -1} {
493
                        append sta_name [string range $hier_name $inst_start end]
494
                        set inst_start -1
495
                } else {
496
                        append sta_name [string range $hier_name $inst_start $inst_end]
497
                        set inst_start [string first ":" $hier_name $inst_end]
498
                }
499
        }
500
        return $sta_name
501
}
502
 
503
# ----------------------------------------------------------------
504
#
505
proc get_core_instance_list {corename} {
506
#
507
# Description:  Get a list of all ALTMEMPHY instances in TimeQuest
508
#
509
# ----------------------------------------------------------------
510
        set full_instance_list [get_core_full_instance_list $corename]
511
        set instance_list [list]
512
 
513
        foreach inst $full_instance_list {
514
                set sta_name [get_timequest_name $inst]
515
                if {[lsearch $instance_list [escape_brackets $sta_name]] == -1} {
516
                        lappend instance_list $sta_name
517
                }
518
        }
519
        return $instance_list
520
}
521
 
522
# ----------------------------------------------------------------
523
#
524
proc get_core_full_instance_list {corename} {
525
#
526
# Description:  Get a list of all ALTMEMPHY instances (full hierarchy names)
527
#               in TimeQuest
528
#
529
# ----------------------------------------------------------------
530
        set instance_list [list]
531
 
532
        # Look for a keeper (register) name
533
        # Try mem_clk[0] to determine core instances
534
        set search_list [list "*"]
535
        set found 0
536
        for {set i 0} {$found == 0 && $i != [llength $search_list]} {incr i} {
537
                set pattern [lindex $search_list $i]
538
                set instance_collection [get_keepers -nowarn "*|${corename}:*|$pattern"]
539
                if {[get_collection_size $instance_collection] == 0} {
540
                        set instance_collection [get_keepers "${corename}:*|$pattern"]
541
                }
542
                if {[get_collection_size $instance_collection] > 0} {
543
                        set found 1
544
                }
545
        }
546
        # regexp to extract the full hierarchy path of an instance name
547
        set inst_regexp {(^.*}
548
        append inst_regexp ${corename}
549
        append inst_regexp {:[A-Za-z0-9\.\\_\[\]\-\$():]+)\|}
550
        foreach_in_collection inst $instance_collection {
551
                set name [get_node_info -name $inst]
552
                if {[regexp -- $inst_regexp $name -> hier_name] == 1} {
553
                        if {[lsearch $instance_list [escape_brackets $hier_name]] == -1} {
554
                                lappend instance_list $hier_name
555
                        }
556
                }
557
        }
558
        return $instance_list
559
}
560
 
561
# ----------------------------------------------------------------
562
#
563
proc traverse_fanin_up_to_depth { node_id match_command edge_type results_array_name depth} {
564
#
565
# Description: Recurses through the timing netlist starting from the given
566
#              node_id through edges of type edge_type to find nodes
567
#              satisfying match_command.
568
#              Recursion depth is bound to the specified depth.
569
#              Adds the resulting TDB node ids to the results_array.
570
#
571
# ----------------------------------------------------------------
572
        upvar 1 $results_array_name results
573
 
574
        if {$depth < 0} {
575
                error "Internal error: Bad timing netlist search depth"
576
        }
577
        set fanin_edges [get_node_info -${edge_type}_edges $node_id]
578
        set number_of_fanin_edges [llength $fanin_edges]
579
        for {set i 0} {$i != $number_of_fanin_edges} {incr i} {
580
                set fanin_edge [lindex $fanin_edges $i]
581
                set fanin_id [get_edge_info -src $fanin_edge]
582
                if {$match_command == "" || [eval $match_command $fanin_id] != 0} {
583
                        set results($fanin_id) 1
584
                } elseif {$depth == 0} {
585
                        # Max recursion depth
586
                } else {
587
                        traverse_fanin_up_to_depth $fanin_id $match_command $edge_type results [expr "$depth - 1"]
588
                }
589
        }
590
}
591
 
592
# ----------------------------------------------------------------
593
#
594
proc is_node_type_pll_inclk { node_id } {
595
#
596
# Description: Given a node, tells whether or not it is a PLL clk
597
#
598
# ----------------------------------------------------------------
599
        set cell_id [get_node_info -cell $node_id]
600
        set atom_type [get_cell_info -atom_type $cell_id]
601
        if {$atom_type == "PLL"} {
602
                set node_name [get_node_info -name $node_id]
603
                set fanin_edges [get_node_info -clock_edges $node_id]
604
                # The inclk input should have a |inclk or |inclk[0] suffix
605
                if {([string match "*|inclk" $node_name] || [string match "*|inclk\\\[0\\\]" $node_name]) && [llength $fanin_edges] > 0} {
606
                        set result 1
607
                } else {
608
                        set result 0
609
                }
610
        } else {
611
                set result 0
612
        }
613
 
614
        return $result
615
}
616
 
617
# ----------------------------------------------------------------
618
#
619
proc is_node_type_pin { node_id } {
620
#
621
# Description: Given a node, tells whether or not it is a reg
622
#
623
# ----------------------------------------------------------------
624
        set node_type [get_node_info -type $node_id]
625
        if {$node_type == "port"} {
626
                set result 1
627
        } else {
628
                set result 0
629
        }
630
        return $result
631
}
632
 
633
# ----------------------------------------------------------------
634
#
635
proc get_input_clk_id { pll_output_node_id } {
636
#
637
# Description: Given a PLL clock output node, gets the PLL clock input node
638
#
639
# ----------------------------------------------------------------
640
        if {[is_node_type_pll_clk $pll_output_node_id]} {
641
                array set results_array [list]
642
                traverse_fanin_up_to_depth $pll_output_node_id is_node_type_pll_inclk clock results_array 1
643
                if {[array size results_array] == 1} {
644
                        # Found PLL inclk, now find the input pin
645
                        set pll_inclk_id [lindex [array names results_array] 0]
646
                        array unset results_array
647
                        # If fed by a pin, it should be fed by a dedicated input pin,
648
                        # and not a global clock network.  Limit the search depth to
649
                        # prevent finding pins fed by global clock (only allow io_ibuf pins)
650
                        traverse_fanin_up_to_depth $pll_inclk_id is_node_type_pin clock results_array 3
651
                        if {[array size results_array] == 1} {
652
                                # Fed by a dedicated input pin
653
                                set pin_id [lindex [array names results_array] 0]
654
                                set result $pin_id
655
                        } else {
656
                                traverse_fanin_up_to_depth $pll_inclk_id is_node_type_pll_clk clock pll_clk_results_array 1
657
                                if {[array size pll_clk_results_array] == 1} {
658
                                        # Fed by a neighboring PLL via cascade path.
659
                                        # Should be okay as long as that PLL has its input clock
660
                                        # fed by a dedicated input.  If there isn't, TimeQuest will give its own warning about undefined clocks.
661
                                        set source_pll_clk_id [lindex [array names pll_clk_results_array] 0]
662
                                        set source_pll_clk [get_node_info -name $source_pll_clk_id]
663
                                        if {[get_input_clk_id $source_pll_clk_id] != -1} {
664
                                                post_message -type info "Please ensure source clock is defined for PLL with output $source_pll_clk"
665
                                        } else {
666
                                                # Fed from core
667
                                                post_message -type critical_warning "PLL clock $source_pll_clk not driven by a dedicated clock pin.  To ensure minimum jitter on memory interface clock outputs, the PLL clock source should be a dedicated PLL input clock pin."
668
                                        }
669
                                        set result -1
670
                                } else {
671
                                        # Fed from core
672
                                        post_message -type critical_warning "PLL clock [get_node_info -name $pll_output_node_id] not driven by a dedicated clock pin or neighboring PLL source.  To ensure minimum jitter on memory interface clock outputs, the PLL clock source should be a dedicated PLL input clock pin or an output of the neighboring PLL."
673
                                        set result -1
674
                                }
675
                        }
676
                } else {
677
                        post_message -type critical_warning "Could not find PLL clock for [get_node_info -name $pll_output_node_id]"
678
                        set result -1
679
                }
680
        } else {
681
                error "Internal error: get_input_clk_id only works on PLL output clocks"
682
        }
683
        return $result
684
}
685
 
686
# ----------------------------------------------------------------
687
#
688
proc is_node_type_pll_clk { node_id } {
689
#
690
# Description: Given a node, tells whether or not it is a PLL clk
691
#
692
# ----------------------------------------------------------------
693
        set cell_id [get_node_info -cell $node_id]
694
        set atom_type [get_cell_info -atom_type $cell_id]
695
        if {$atom_type == "PLL"} {
696
                set node_name [get_node_info -name $node_id]
697
                if {[string match "*|clk\\\[*\\\]" $node_name]} {
698
                        set result 1
699
                } else {
700
                        set result 0
701
                }
702
        } else {
703
                set result 0
704
        }
705
 
706
        return $result
707
}
708
 
709
# ----------------------------------------------------------------
710
#
711
proc get_pll_clock { dest_id_list node_type clock_id_name search_depth} {
712
#
713
# Description: Look for the PLL output clocking the given nodes
714
#
715
# ----------------------------------------------------------------
716
        if {$clock_id_name != ""} {
717
                upvar 1 $clock_id_name clock_id
718
        }
719
        set clock_id -1
720
 
721
        array set clk_array [list]
722
        foreach node_id $dest_id_list {
723
                traverse_fanin_up_to_depth $node_id is_node_type_pll_clk clock clk_array $search_depth
724
        }
725
        if {[array size clk_array] == 1} {
726
                set clock_id [lindex [array names clk_array] 0]
727
                set clk [get_node_info -name $clock_id]
728
        } elseif {[array size clk_array] > 1} {
729
                puts "Found more than 1 clock driving the $node_type"
730
                set clk ""
731
        } else {
732
                set clk ""
733
                #puts "Could not find $node_type clock"
734
        }
735
 
736
        return $clk
737
}
738
 
739
# ----------------------------------------------------------------
740
#
741
proc get_output_clock_id { ddio_output_pin_list pin_type msg_list_name {max_search_depth 13} } {
742
#
743
# Description: Look for the PLL output clocks of the given pins
744
#
745
# ----------------------------------------------------------------
746
        upvar 1 $msg_list_name msg_list
747
        set output_clock_id -1
748
 
749
        set output_id_list [list]
750
        set pin_collection [get_keepers $ddio_output_pin_list]
751
        if {[get_collection_size $pin_collection] == [llength $ddio_output_pin_list]} {
752
                foreach_in_collection id $pin_collection {
753
                        lappend output_id_list $id
754
                }
755
        } elseif {[get_collection_size $pin_collection] == 0} {
756
                lappend msg_list "warning" "Could not find any $pin_type pins"
757
        } else {
758
                lappend msg_list "warning" "Could not find all $pin_type pins"
759
        }
760
        get_pll_clock $output_id_list $pin_type output_clock_id $max_search_depth
761
        return $output_clock_id
762
}
763
 
764
# ----------------------------------------------------------------
765
#
766
proc is_node_type_io_clock_divider_clkout { node_id } {
767
#
768
# Description: Given a node, tells whether or not it is a I/O clock divider clk
769
#
770
# ----------------------------------------------------------------
771
        set cell_id [get_node_info -cell $node_id]
772
        set atom_type [get_cell_info -atom_type $cell_id]
773
        if {$atom_type == "IO_CLOCK_DIVIDER"} {
774
                set node_name [get_node_info -name $node_id]
775
                set fanout_edges [get_node_info -fanout_edges $node_id]
776
                if {[string match "*|clkout" $node_name] && [llength $fanout_edges] > 0} {
777
                        set result 1
778
                } else {
779
                        set result 0
780
                }
781
        } else {
782
                set result 0
783
        }
784
 
785
        return $result
786
}
787
 
788
# ----------------------------------------------------------------
789
#
790
proc post_sdc_message {msg_type msg} {
791
#
792
# Description: Posts a message in TimeQuest, but not in Fitter
793
#              The SDC is read mutliple times during compilation, so we'll wait
794
#              until final TimeQuest timing analysis to display messages
795
#
796
# ----------------------------------------------------------------
797
        if { $::TimeQuestInfo(nameofexecutable) != "quartus_fit"} {
798
                post_message -type $msg_type $msg
799
        }
800
}
801
 
802
# ----------------------------------------------------------------
803
#
804
proc get_report_column { report_id str} {
805
#
806
# Description: Gets the report column index with the given header string
807
#
808
# ----------------------------------------------------------------
809
        set target_col [get_report_panel_column_index -id $report_id $str]
810
        if {$target_col == -1} {
811
                error "Cannot find $str column"
812
        }
813
        return $target_col
814
}
815
 
816
# ----------------------------------------------------------------
817
#
818
proc get_fitter_report_pin_info_from_report {target_pin info_type pin_report_id} {
819
#
820
# Description: Gets the report field for the given pin in the given report
821
#
822
# ----------------------------------------------------------------
823
        set pin_name_column [get_report_column $pin_report_id "Name"]
824
        set info_column [get_report_column $pin_report_id $info_type]
825
        set result ""
826
 
827
        if {$pin_name_column == 0 && 0} {
828
                set row_index [get_report_panel_row_index -id $pin_report_id $target_pin]
829
                if {$row_index != -1} {
830
                        set row [get_report_panel_row -id $pin_report_id -row $row_index]
831
                        set result [lindex $row $info_column]
832
                }
833
        } else {
834
                set report_rows [get_number_of_rows -id $pin_report_id]
835
                for {set row_index 1} {$row_index < $report_rows && $result == ""} {incr row_index} {
836
                        set row [get_report_panel_row -id $pin_report_id -row $row_index]
837
                        set pin [lindex $row $pin_name_column]
838
                        if {$pin == $target_pin} {
839
                                set result [lindex $row $info_column]
840
                        }
841
                }
842
        }
843
        return $result
844
}
845
 
846
# ----------------------------------------------------------------
847
#
848
proc get_fitter_report_pin_info {target_pin info_type preferred_report_id {found_report_id_name ""}} {
849
#
850
# Description: Gets the report field for the given pin by searching through the
851
#              input, output and bidir pin reports
852
#
853
# ----------------------------------------------------------------
854
        if {$found_report_id_name != ""} {
855
                upvar 1 $found_report_id_name found_report_id
856
        }
857
        set found_report_id -1
858
        set result ""
859
        if {$preferred_report_id == -1} {
860
                set pin_report_list [list "Fitter||Resource Section||Bidir Pins" "Fitter||Resource Section||Input Pins" "Fitter||Resource Section||Output Pins"]
861
                for {set pin_report_index 0} {$pin_report_index != [llength $pin_report_list] && $result == ""} {incr pin_report_index} {
862
                        set pin_report_id [get_report_panel_id [lindex $pin_report_list $pin_report_index]]
863
                        if {$pin_report_id != -1} {
864
                                set result [get_fitter_report_pin_info_from_report $target_pin $info_type $pin_report_id]
865
                                if {$result != ""} {
866
                                        set found_report_id $pin_report_id
867
                                }
868
                        }
869
                }
870
        } else {
871
                set result [get_fitter_report_pin_info_from_report $target_pin $info_type $preferred_report_id]
872
                if {$result != ""} {
873
                        set found_report_id $preferred_report_id
874
                }
875
        }
876
        return $result
877
}
878
# ----------------------------------------------------------------
879
#
880
proc get_io_interface_type {pin_list} {
881
#
882
# Description: Gets the type of pin that the given pins are placed on
883
#              either (HPAD, VPAD, VHPAD, "", or UNKNOWN).
884
#              "" is returned if pin_list is empty
885
#              UNKNOWN is returned if an error was encountered
886
#              This function assumes the fitter has already completed and the
887
#              compiler report has been loaded.
888
#
889
# ----------------------------------------------------------------
890
        set preferred_report_id -1
891
        set interface_type ""
892
        foreach target_pin $pin_list {
893
                set io_bank [get_fitter_report_pin_info $target_pin "I/O Bank" $preferred_report_id preferred_report_id]
894
                if {[regexp -- {^([0-9]+)[A-Z]*} $io_bank -> io_bank_number]} {
895
                        if {$io_bank_number == 1 || $io_bank_number == 2 || $io_bank_number == 5 || $io_bank_number == 6} {
896
                                # Row I/O
897
                                if {$interface_type == ""} {
898
                                        set interface_type "HPAD"
899
                                } elseif {$interface_type == "VPAD"} {
900
                                        set interface_type "VHPAD"
901
                                }
902
                        } elseif {$io_bank_number == 3 || $io_bank_number == 4 || $io_bank_number == 7 || $io_bank_number == 8} {
903
                                if {$interface_type == ""} {
904
                                        set interface_type "VPAD"
905
                                } elseif {$interface_type == "HPAD"} {
906
                                        set interface_type "VHPAD"
907
                                }
908
                        } else {
909
                                post_message -type critical_warning "Unknown I/O bank $io_bank for pin $target_pin"
910
                                # Asuume worst case performance (mixed HIO/VIO interface)
911
                                set interface_type "VHPAD"
912
                        }
913
                }
914
        }
915
        return $interface_type
916
}
917
 
918
# ----------------------------------------------------------------
919
#
920
proc get_io_standard {target_pin} {
921
#
922
# Description: Gets the I/O standard of the given memory interface pin
923
#              This function assumes the fitter has already completed and the
924
#              compiler report has been loaded.
925
#
926
# ----------------------------------------------------------------
927
        # Look through the pin report
928
        set io_std [get_fitter_report_pin_info $target_pin "I/O Standard" -1]
929
        if {$io_std == ""} {
930
                return "UNKNOWN"
931
        }
932
        set result ""
933
        switch  -exact -- $io_std {
934
        "SSTL-2 Class I" {set result "SSTL_2_I"}
935
                "Differential 2.5-V SSTL Class I" {set result "DIFF_SSTL_2_I"}
936
        "SSTL-2 Class II" {set result "SSTL_2_II"}
937
                "Differential 2.5-V SSTL Class II" {set result "DIFF_SSTL_2_II"}
938
        "SSTL-18 Class I" {set result "SSTL_18_I"}
939
                "Differential 1.8-V SSTL Class I" {set result "DIFF_SSTL_18_I"}
940
        "SSTL-18 Class II" {set result "SSTL_18_II"}
941
                "Differential 1.8-V SSTL Class II" {set result "DIFF_SSTL_18_II"}
942
        "SSTL-15 Class I" {set result "SSTL_15_I"}
943
                "Differential 1.5-V SSTL Class I" {set result "DIFF_SSTL_15_I"}
944
        "SSTL-15 Class II" {set result "SSTL_15_II"}
945
                "Differential 1.5-V SSTL Class II" {set result "DIFF_SSTL_15_II"}
946
        "1.8-V HSTL Class I" {set result "HSTL_18_I"}
947
                "Differential 1.8-V HSTL Class I" {set result "DIFF_HSTL_18_I"}
948
        "1.8-V HSTL Class II" {set result "HSTL_18_II"}
949
                "Differential 1.8-V HSTL Class II" {set result "DIFF_HSTL_18_II"}
950
        "1.5-V HSTL Class I" {set result "HSTL_I"}
951
                "Differential 1.5-V HSTL Class I" {set result "DIFF_HSTL"}
952
        "1.5-V HSTL Class II" {set result "HSTL_II"}
953
                "Differential 1.5-V HSTL Class II" {set result "DIFF_HSTL_II"}
954
                default {
955
                        post_message -type error "Found unsupported Memory I/O standard $io_std on pin $target_pin"
956
                        set result "UNKNOWN"
957
                }
958
        }
959
        return $result
960
}
961
 
962
# ----------------------------------------------------------------
963
#
964
proc get_input_oct_termination {target_pin} {
965
#
966
# Description: Tells whether or not the given memory interface pin uses OCT
967
#              This function assumes the fitter has already completed and the
968
#              compiler report has been loaded.
969
#
970
# ----------------------------------------------------------------
971
        # Look through the pin reports
972
        set pin_report_id [get_report_panel_id "Fitter||Resource Section||Bidir Pins"]
973
        # Look through the output and bidir pin reports
974
        if {$pin_report_id == -1} {
975
                set termination ""
976
        } else {
977
                set termination [get_fitter_report_pin_info $target_pin "Input Termination" $pin_report_id]
978
        }
979
        if {$termination == ""} {
980
                set pin_report_id [get_report_panel_id "Fitter||Resource Section||Input Pins"]
981
                set termination [get_fitter_report_pin_info $target_pin "Termination" $pin_report_id]
982
                if {$termination == ""} {
983
                        return "UNKNOWN"
984
                }
985
        }
986
        set result "OCT_OFF"
987
        switch -exact -glob -- $termination {
988
                "Off" {set result "OCT_OFF"}
989
                "OCT*" {set result "OCT_ON"}
990
                "Parallel *" {set result "OCT_ON"}
991
                default {
992
                        post_message -type critical_warning "Found unsupported memory pin input termination $termination on pin $target_pin"
993
                        set result "UNKNOWN"
994
                }
995
        }
996
        return $result
997
}
998
 
999
# ----------------------------------------------------------------
1000
#
1001
proc get_output_oct_termination {target_pin} {
1002
#
1003
# Description: Tells whether or not the given memory interface pin uses OCT
1004
#              This function assumes the fitter has already completed and the
1005
#              compiler report has been loaded.
1006
#
1007
# ----------------------------------------------------------------
1008
        set pin_report_id [get_report_panel_id "Fitter||Resource Section||Bidir Pins"]
1009
        # Look through the output and bidir pin reports
1010
        if {$pin_report_id == -1} {
1011
                set termination ""
1012
        } else {
1013
                set termination [get_fitter_report_pin_info $target_pin "Output Termination" $pin_report_id]
1014
        }
1015
        if {$termination == ""} {
1016
                set pin_report_id [get_report_panel_id "Fitter||Resource Section||Output Pins"]
1017
                set termination [get_fitter_report_pin_info $target_pin "Termination" $pin_report_id]
1018
                if {$termination == ""} {
1019
                        return "UNKNOWN"
1020
                }
1021
        }
1022
        set result "OCT_OFF"
1023
        switch -exact -glob -- $termination {
1024
                "Off" {set result "OCT_OFF"}
1025
                "OCT*" {set result "OCT_ON"}
1026
                "Series *" {set result "OCT_ON"}
1027
                default {
1028
                        post_message -type critical_warning "Found unsupported memory pin output termination $termination on pin $target_pin"
1029
                        set result "UNKNOWN"
1030
                }
1031
        }
1032
        return $result
1033
}
1034
 
1035
 
1036
# ----------------------------------------------------------------
1037
proc get_ddr_pins {instname pins_array_name} {
1038
#
1039
# ----------------------------------------------------------------
1040
        upvar 1 $pins_array_name pins
1041
        set corename "altera_ddr_phy"
1042
        array unset pins_t
1043
 
1044
        set dqsgroups 2
1045
        for {set i 0} {$i < $dqsgroups} {incr i} {
1046
                set dqs ${instname}_alt_mem_phy_inst|dpio|dqs\[$i\].dqs_ddio_out|dataout
1047
                set dq  ${instname}_alt_mem_phy_inst|dpio|dqs_group\[$i\].dq\[*\].dq_ddio_out|dataout
1048
                set dm  ${instname}_alt_mem_phy_inst|dpio|dm\[$i\].dm_ddio_out|dataout
1049
 
1050
                set dqs_p [map_get_node_name [walk_to_pins fanout [get_pins -compatibility_mode $dqs]]]
1051
                if { [llength $dqs_p] != 1} { post_sdc_message critical_warning "Could not find DQS pin number $i" }
1052
 
1053
                set dqsn_p [list]
1054
 
1055
                set dm_p  [map_get_node_name [walk_to_pins fanout [get_pins -compatibility_mode $dm]]]
1056
                if { [llength $dm_p] != 1} { post_sdc_message critical_warning "Could not find DM pin for DQS pin number $i" }
1057
 
1058
                set dq_p  [map_get_node_name [walk_to_pins fanout [get_pins -compatibility_mode $dq]]]
1059
                if { [llength $dq_p] != 8} { post_sdc_message critical_warning "Could not find correct number of DQ pins for DQS pin $i. Found [llength $dq_p] pins. Expecting 8." }
1060
 
1061
                set dqsgroup [list [lindex $dqs_p 0] $dm_p [lsort $dq_p] [lindex $dqsn_p 0]]
1062
                lappend pins_t(dqsgroup) $dqsgroup
1063
        }
1064
 
1065
        set patterns [list]
1066
lappend patterns addrcmd ${instname}_alt_mem_phy_inst|*adc*|addr\[*\].addr_struct|full_rate.addr_pin|auto_generated|ddio_outa\[*\]|dataout
1067
lappend patterns addrcmd ${instname}_alt_mem_phy_inst|*adc*|ba\[*\].ba_struct|full_rate.addr_pin|auto_generated|ddio_outa\[*\]|dataout
1068
lappend patterns addrcmd ${instname}_alt_mem_phy_inst|*adc*|cas_n_struct|full_rate.addr_pin|auto_generated|ddio_outa\[*\]|dataout
1069
lappend patterns addrcmd ${instname}_alt_mem_phy_inst|*adc*|ras_n_struct|full_rate.addr_pin|auto_generated|ddio_outa\[*\]|dataout
1070
lappend patterns addrcmd ${instname}_alt_mem_phy_inst|*adc*|we_n_struct|full_rate.addr_pin|auto_generated|ddio_outa\[*\]|dataout
1071
lappend patterns addrcmd    ${instname}_alt_mem_phy_inst|*adc*|cke\[*\].cke_struct|full_rate.addr_pin|auto_generated|ddio_outa\[0\]|dataout
1072
lappend patterns addrcmd    ${instname}_alt_mem_phy_inst|*adc*|cs_n\[*\].cs_n_struct|full_rate.addr_pin|auto_generated|ddio_outa\[0\]|dataout
1073
lappend patterns ck_p ${instname}_alt_mem_phy_inst|clk|DDR_CLK_OUT\[*\].ddr_clk_out_p|auto_generated|ddio_outa\[*\]|dataout
1074
lappend patterns ck_n ${instname}_alt_mem_phy_inst|clk|DDR_CLK_OUT\[*\].ddr_clk_out_n|auto_generated|ddio_outa\[*\]|dataout
1075
 
1076
        foreach {pin_type pattern} $patterns {
1077
                set ports [map_get_node_name [walk_to_pins fanout [get_pins -compatibility_mode $pattern]]]
1078
                if {[llength $ports] == 0} {
1079
                        post_message -type critical_warning "Could not find pin of type $pin_type from pattern $pattern"
1080
                } else {
1081
                        foreach port [lsort -unique $ports] {
1082
                                lappend pins_t($pin_type) $port
1083
                        }
1084
                }
1085
        }
1086
 
1087
        set outputFileName "altera_ddr_phy_autodetectedpins.tcl"
1088
        set f [open $outputFileName w]
1089
 
1090
        foreach {k v} [array get pins_t] {
1091
                foreach vi $v {
1092
                        ddr_pin $k  $vi pins
1093
                        puts $f "ddr_pin [list $k] [list $vi] pins"
1094
                }
1095
        }
1096
        close $f
1097
}
1098
 
1099
set altera_ddr_phy_use_high_performance_timing 1
1100
if {[namespace which -variable ::override_altera_ddr_phy_use_high_performance_timing] != ""} {
1101
        set altera_ddr_phy_use_high_performance_timing $::override_altera_ddr_phy_use_high_performance_timing
1102
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.