insert_ila_probes.tcl
1 ################################################################################ 2 # insert_ila_probes.tcl 3 # 4 # AERIS-10 Radar FPGA — Post-Synthesis ILA Debug Core Insertion 5 # Target: XC7A200T-2FBG484I 6 # Design: radar_system_top (Build 16 frozen netlist) 7 # 8 # Usage: 9 # vivado -mode batch -source insert_ila_probes.tcl 10 # 11 # This script: 12 # 1. Opens the post-synth DCP from Build 16 13 # 2. Inserts 4 ILA debug cores across 2 clock domains 14 # 3. Runs full implementation with Build 16 directives 15 # 4. Generates bitstream, reports, and .ltx probe file 16 # 17 # ILA 0: ADC Capture — 400 MHz (rx_inst/adc/clk_400m) — up to 9 bits 18 # ILA 1: DDC Output — 100 MHz — up to 37 bits 19 # ILA 2: Matched Filter Ctrl — 100 MHz — 4 signals 20 # ILA 3: Doppler Output — 100 MHz — up to 45 bits 21 # 22 # APPROACH: Uses get_nets with -hierarchical wildcards and get_nets -of 23 # [get_pins ...] to resolve post-synthesis net names. All probe connections 24 # are fault-tolerant — if a net cannot be found it is logged and skipped, 25 # rather than aborting the build. 26 # 27 # Author: auto-generated for Jason Stone 28 # Date: 2026-03-18 29 ################################################################################ 30 31 # ============================================================================== 32 # 0. Configuration — all paths and parameters in one place 33 # ============================================================================== 34 35 set script_dir [file dirname [file normalize [info script]]] 36 set project_root [file normalize [file join $script_dir "../.."]] 37 set project_base [file join $project_root "build"] 38 set synth_dcp "${project_base}/aeris10_radar.runs/synth_1/radar_system_top.dcp" 39 set synth_xdc [file join $project_root "constraints" "xc7a200t_fbg484.xdc"] 40 set output_dir "${project_base}/aeris10_radar.runs/impl_ila" 41 set top_module "radar_system_top" 42 set part "xc7a200tfbg484-2" 43 44 # Timestamp for output file naming 45 set timestamp [clock format [clock seconds] -format {%Y%m%d_%H%M%S}] 46 set run_tag "build16_ila_${timestamp}" 47 48 # ILA parameters 49 set ila_depth 4096 50 set trigger_pos 512 ;# 512 pre-trigger samples 51 52 # Global counter: total probes actually connected (for final summary) 53 set total_probes_connected 0 54 55 # ============================================================================== 56 # 1. Helper procedures — fault-tolerant net resolution 57 # ============================================================================== 58 59 # Try a sequence of strategies to find a single net. Returns the net object 60 # or empty string "" if nothing was found. Never errors out. 61 # 62 # Each element in $strategies is itself a list: 63 # { method arg } 64 # where method is one of: 65 # "net" — try exact path first (get_nets -quiet $arg), then hierarchical 66 # "pin" — call get_nets -quiet -of [get_pins -quiet $arg] 67 # 68 # Example: 69 # find_net { {net rx_inst/adc/adc_valid} {net *adc_valid*} } 70 # 71 proc find_net {strategies} { 72 foreach strategy $strategies { 73 set method [lindex $strategy 0] 74 set arg [lindex $strategy 1] 75 switch $method { 76 "net" { 77 # Try exact path first (works for fully-qualified hierarchical names) 78 set result [get_nets -quiet $arg] 79 # Fall back to hierarchical search (works for leaf names and wildcards) 80 if {[llength $result] == 0} { 81 set result [get_nets -quiet -hierarchical $arg] 82 } 83 } 84 "pin" { 85 set pins [get_pins -quiet $arg] 86 if {[llength $pins] == 0} { 87 # Also try hierarchical pin search 88 set pins [get_pins -quiet -hierarchical $arg] 89 } 90 if {[llength $pins] > 0} { 91 set result [get_nets -quiet -of $pins] 92 } else { 93 set result {} 94 } 95 } 96 default { 97 set result {} 98 } 99 } 100 if {[llength $result] > 0} { 101 # Return the first matching net 102 set chosen [lindex $result 0] 103 puts " INFO: Resolved '$arg' ($method) -> $chosen" 104 return $chosen 105 } 106 } 107 return "" 108 } 109 110 # Try a sequence of strategies to find a bus (vector) of nets. 111 # Returns a Tcl list of net objects. The list may be shorter than requested 112 # if some bits were optimised away. 113 # 114 # Each element in $strategies is { method pattern } where pattern may contain 115 # a literal '*' or a specific glob. The procedure evaluates ALL strategies 116 # as a batch and picks the first one that returns >= 1 net. 117 # 118 proc find_bus {strategies} { 119 foreach strategy $strategies { 120 set method [lindex $strategy 0] 121 set arg [lindex $strategy 1] 122 switch $method { 123 "net" { 124 # Try exact path first (works for fully-qualified hierarchical paths) 125 set result [get_nets -quiet $arg] 126 # Fall back to hierarchical search (leaf names, wildcards) 127 if {[llength $result] == 0} { 128 set result [get_nets -quiet -hierarchical $arg] 129 } 130 } 131 "pin" { 132 set pins [get_pins -quiet $arg] 133 if {[llength $pins] == 0} { 134 # Also try hierarchical pin search 135 set pins [get_pins -quiet -hierarchical $arg] 136 } 137 if {[llength $pins] > 0} { 138 set result [get_nets -quiet -of $pins] 139 } else { 140 set result {} 141 } 142 } 143 default { 144 set result {} 145 } 146 } 147 if {[llength $result] > 0} { 148 puts " INFO: Bus resolved via '$arg' ($method) -> [llength $result] nets" 149 return $result 150 } 151 } 152 return {} 153 } 154 155 # Connect a list of nets to the next available probe port on an ILA core. 156 # If the net list is empty, logs a warning and returns the same probe index 157 # (no probe port is consumed). 158 # 159 # ila_name: e.g. u_ila_0 160 # probe_index: current probe port index (0 for PROBE0, etc.) 161 # net_list: Tcl list of net objects to connect 162 # label: human-readable description for log messages 163 # 164 # Returns the next available probe index. 165 # 166 proc connect_probe {ila_name probe_index net_list label} { 167 global total_probes_connected 168 169 set width [llength $net_list] 170 if {$width == 0} { 171 puts " WARNING: No nets found for '$label' — skipping probe${probe_index} on $ila_name" 172 return $probe_index 173 } 174 175 puts " INFO: Connecting $width nets to ${ila_name}/probe${probe_index} ($label)" 176 177 if {$probe_index > 0} { 178 create_debug_port $ila_name probe 179 } 180 181 set_property port_width $width [get_debug_ports ${ila_name}/probe${probe_index}] 182 connect_debug_port ${ila_name}/probe${probe_index} $net_list 183 184 incr total_probes_connected $width 185 return [expr {$probe_index + 1}] 186 } 187 188 # Deferred ILA creation — create the debug core, set properties, connect clock, 189 # and wire up all resolved probes in one shot. If no probes resolved, the ILA 190 # is NOT created at all (avoids dangling probe0 error). 191 # 192 # ila_name: e.g. u_ila_0 193 # clk_net: clock net object 194 # probe_list: list of {label net_list} pairs (pre-resolved) 195 # depth: ILA sample depth 196 # 197 # Returns the number of probe ports actually connected. 198 # 199 proc create_ila_deferred {ila_name clk_net probe_list depth} { 200 global total_probes_connected 201 202 # Filter to only probes that have at least 1 net 203 set valid_probes {} 204 foreach probe_entry $probe_list { 205 set label [lindex $probe_entry 0] 206 set net_list [lindex $probe_entry 1] 207 if {[llength $net_list] > 0} { 208 lappend valid_probes [list $label $net_list] 209 } else { 210 puts " WARNING: No nets found for '$label' on $ila_name — skipping" 211 } 212 } 213 214 if {[llength $valid_probes] == 0} { 215 puts " WARNING: ALL probes failed for $ila_name — ILA core NOT created (avoiding dangling probe0)" 216 return 0 217 } 218 219 # Now create the debug core — we know we have at least 1 probe 220 puts " INFO: Creating $ila_name with [llength $valid_probes] probe(s)" 221 create_debug_core $ila_name ila 222 set_property ALL_PROBE_SAME_MU true [get_debug_cores $ila_name] 223 set_property ALL_PROBE_SAME_MU_CNT 2 [get_debug_cores $ila_name] 224 set_property C_ADV_TRIGGER false [get_debug_cores $ila_name] 225 set_property C_DATA_DEPTH $depth [get_debug_cores $ila_name] 226 set_property C_EN_STRG_QUAL true [get_debug_cores $ila_name] 227 set_property C_INPUT_PIPE_STAGES 0 [get_debug_cores $ila_name] 228 set_property C_TRIGIN_EN false [get_debug_cores $ila_name] 229 set_property C_TRIGOUT_EN false [get_debug_cores $ila_name] 230 231 # Connect the clock 232 set_property port_width 1 [get_debug_ports ${ila_name}/clk] 233 connect_debug_port ${ila_name}/clk [get_nets $clk_net] 234 235 # Connect each resolved probe 236 set probe_idx 0 237 foreach probe_entry $valid_probes { 238 set label [lindex $probe_entry 0] 239 set net_list [lindex $probe_entry 1] 240 set probe_idx [connect_probe $ila_name $probe_idx $net_list $label] 241 } 242 243 return $probe_idx 244 } 245 246 # ============================================================================== 247 # 2. Open the synthesized checkpoint 248 # ============================================================================== 249 250 puts "======================================================================" 251 puts " AERIS-10 ILA Insertion — Starting at [clock format [clock seconds]]" 252 puts "======================================================================" 253 254 # Create output directory 255 file mkdir $output_dir 256 257 # Open the frozen Build 13 post-synth DCP 258 puts "\nINFO: Opening post-synth DCP: $synth_dcp" 259 open_checkpoint $synth_dcp 260 261 # Verify the part 262 set loaded_part [get_property PART [current_design]] 263 puts "INFO: Design part = $loaded_part" 264 if {$loaded_part ne $part} { 265 puts "WARNING: Expected part '$part', got '$loaded_part'. Continuing anyway." 266 } 267 268 # Read the synthesis-only constraints (pin assignments, clocks, etc.) 269 puts "INFO: Reading XDC: $synth_xdc" 270 read_xdc $synth_xdc 271 272 # ============================================================================== 273 # 3. Resolve clock nets 274 # ============================================================================== 275 276 puts "\n--- Resolving clock nets ---" 277 278 # 400 MHz clock — inside ADC interface (confirmed resolved to rx_inst/clk_400m) 279 set clk_400m_net [find_net { 280 {net rx_inst/clk_400m} 281 {net rx_inst/adc/clk_400m} 282 {net *adc*/clk_400m} 283 {net *clk_400m*} 284 }] 285 if {$clk_400m_net eq ""} { 286 error "FATAL: Cannot find 400 MHz clock net. Cannot insert ILA 0." 287 } 288 puts "INFO: 400 MHz clock net = $clk_400m_net" 289 290 # 100 MHz system clock 291 set clk_100m_net [find_net { 292 {net clk_100m_IBUF_BUFG} 293 {net clk_100m_buf} 294 {net clk_100m_BUFG} 295 {net *clk_100m*} 296 }] 297 if {$clk_100m_net eq ""} { 298 error "FATAL: Cannot find 100 MHz clock net. Cannot insert ILA 1/2/3." 299 } 300 puts "INFO: 100 MHz clock net = $clk_100m_net" 301 302 # ============================================================================== 303 # 4. ILA 0 — ADC Capture (400 MHz domain) 304 # 305 # Monitors raw ADC data at the CMOS interface output. 306 # Probes: ADC data [7:0] + ADC valid = up to 9 bits. 307 # 4096 samples at 400 MHz => ~10.24 us capture window. 308 # 309 # Uses DEFERRED creation: probes are resolved first, ILA is only created 310 # if at least one probe has nets. This avoids dangling probe0 errors. 311 # ============================================================================== 312 313 puts "\n====== ILA 0: ADC Capture (400 MHz) ======" 314 315 # Probe 0: ADC data [7:0] 316 # Post-synth register name is adc_data_400m_reg_reg (double "reg" from synthesis). 317 # Bit 7 is inverted: adc_data_400m_reg_reg[7]_inv. 318 # Use pin-based discovery which catches both normal and _inv variants. 319 set adc_data_nets [find_bus { 320 {pin rx_inst/adc/adc_data_400m_reg_reg[*]/Q} 321 {net rx_inst/adc/adc_data_400m_reg_reg[*]} 322 {pin rx_inst/adc/adc_data_400m_reg[*]/Q} 323 {net rx_inst/adc/A[*]} 324 {pin rx_inst/adc/adc_data_cmos_reg[*]/Q} 325 {net rx_inst/adc/adc_data_400m[*]} 326 {net rx_inst/adc/adc_data_cmos[*]} 327 }] 328 329 # Probe 1: ADC valid 330 # Net confirmed as rx_inst/adc/adc_valid 331 # Pin confirmed as rx_inst/adc/adc_data_valid_400m_reg_reg/Q (double "reg") 332 set adc_valid_net [find_net { 333 {net rx_inst/adc/adc_valid} 334 {pin rx_inst/adc/adc_data_valid_400m_reg_reg/Q} 335 {pin rx_inst/adc/adc_valid_reg/Q} 336 {net *adc/adc_valid*} 337 }] 338 if {$adc_valid_net ne ""} { 339 set adc_valid_list [list $adc_valid_net] 340 } else { 341 set adc_valid_list {} 342 } 343 344 # Deferred creation: only create ILA if at least 1 probe resolves 345 set ila0_probes [list \ 346 [list "ADC data" $adc_data_nets] \ 347 [list "ADC valid" $adc_valid_list] \ 348 ] 349 set ila0_count [create_ila_deferred u_ila_0 $clk_400m_net $ila0_probes $ila_depth] 350 puts "INFO: ILA 0 — $ila0_count probe ports on 400 MHz clock" 351 352 # ============================================================================== 353 # 5. ILA 1 — DDC Output (100 MHz domain) 354 # 355 # Monitors the digital down-converter output after CIC+FIR decimation. 356 # Probes: DDC I [17:1] + DDC Q [17:1] + DDC valid = up to 35 bits. 357 # Bit 0 is optimized away in synthesis. 358 # 359 # Uses DEFERRED creation to avoid dangling probe0 errors. 360 # ============================================================================== 361 362 puts "\n====== ILA 1: DDC Output (100 MHz) ======" 363 364 # Probe 0: ddc_out_i — DDC I-channel baseband output 365 # Nets confirmed as rx_inst/ddc/ddc_out_i[1] through [17] (bit 0 optimized away) 366 # Use exact path WITHOUT -hierarchical, then fall back to pin-based and hierarchical 367 set ddc_i_nets [find_bus { 368 {net rx_inst/ddc/ddc_out_i[*]} 369 {pin rx_inst/ddc/ddc_out_i_reg[*]/Q} 370 {net *ddc/ddc_out_i[*]} 371 }] 372 373 # Probe 1: ddc_out_q — DDC Q-channel baseband output 374 # Nets confirmed as rx_inst/ddc/ddc_out_q[1] through [17] (bit 0 optimized away) 375 set ddc_q_nets [find_bus { 376 {net rx_inst/ddc/ddc_out_q[*]} 377 {pin rx_inst/ddc/ddc_out_q_reg[*]/Q} 378 {net *ddc/ddc_out_q[*]} 379 }] 380 381 # Probe 2: DDC output valid 382 # Confirmed nets: rx_inst/ddc_valid_q, rx_inst/ddc/baseband_valid_q 383 set ddc_valid_net [find_net { 384 {net rx_inst/ddc_valid_q} 385 {net rx_inst/ddc/baseband_valid_q} 386 {net rx_inst/ddc/fir_valid} 387 {pin rx_inst/ddc/baseband_valid_q_reg/Q} 388 {net *ddc*valid*} 389 }] 390 if {$ddc_valid_net ne ""} { 391 set ddc_valid_list [list $ddc_valid_net] 392 } else { 393 set ddc_valid_list {} 394 } 395 396 # Deferred creation: only create ILA if at least 1 probe resolves 397 set ila1_probes [list \ 398 [list "DDC I" $ddc_i_nets] \ 399 [list "DDC Q" $ddc_q_nets] \ 400 [list "DDC valid" $ddc_valid_list] \ 401 ] 402 set ila1_count [create_ila_deferred u_ila_1 $clk_100m_net $ila1_probes $ila_depth] 403 puts "INFO: ILA 1 — $ila1_count probe ports on 100 MHz clock" 404 405 # ============================================================================== 406 # 6. ILA 2 — Matched Filter Control (100 MHz domain) 407 # 408 # Reduced probe set: only control/status signals that are confirmed to exist 409 # in the post-synthesis netlist. Data nets (pc_i_w, pc_q_w) do NOT exist 410 # post-synth due to hierarchy flattening. 411 # 412 # Probes: range_profile_valid + mf_valid_out + segment_request[1:0] = 4 bits. 413 # 414 # Uses DEFERRED creation to avoid dangling probe0 errors. 415 # ============================================================================== 416 417 puts "\n====== ILA 2: Matched Filter Control (100 MHz) ======" 418 419 # Probe 0: range_profile_valid 420 # Confirmed nets: rx_inst/mf_dual/range_profile_valid, 421 # rx_inst/mf_dual/m_f_p_c/range_profile_valid, 422 # rx_inst/range_decim/range_profile_valid 423 set rpv_net [find_net { 424 {net rx_inst/mf_dual/range_profile_valid} 425 {net rx_inst/mf_dual/m_f_p_c/range_profile_valid} 426 {net rx_inst/range_decim/range_profile_valid} 427 {pin rx_inst/mf_dual/range_profile_valid_reg/Q} 428 {net *mf_dual/range_profile_valid*} 429 }] 430 if {$rpv_net ne ""} { 431 set rpv_list [list $rpv_net] 432 } else { 433 set rpv_list {} 434 } 435 436 # Probe 1: mf_valid_out (internal MF output valid) 437 # Confirmed nets: rx_inst/mf_dual/m_f_p_c/mf_inst/mf_valid_out, 438 # rx_inst/mf_dual/m_f_p_c/mf_valid_in 439 set mfv_net [find_net { 440 {net rx_inst/mf_dual/m_f_p_c/mf_inst/mf_valid_out} 441 {net rx_inst/mf_dual/m_f_p_c/mf_valid_in} 442 {pin rx_inst/mf_dual/m_f_p_c/mf_inst/mf_valid_out_reg/Q} 443 {net *mf_inst/mf_valid_out*} 444 }] 445 if {$mfv_net ne ""} { 446 set mfv_list [list $mfv_net] 447 } else { 448 set mfv_list {} 449 } 450 451 # Probe 2: segment_request[1:0] (confirmed in net dump) 452 set seg_nets [find_bus { 453 {pin rx_inst/mf_dual/segment_request_reg[*]/Q} 454 {net rx_inst/mf_dual/segment_request[*]} 455 {net *mf_dual/segment_request[*]} 456 }] 457 458 # Deferred creation: only create ILA if at least 1 probe resolves 459 set ila2_probes [list \ 460 [list "MF range_profile_valid" $rpv_list] \ 461 [list "MF mf_valid_out" $mfv_list] \ 462 [list "MF segment_request" $seg_nets] \ 463 ] 464 set ila2_count [create_ila_deferred u_ila_2 $clk_100m_net $ila2_probes $ila_depth] 465 puts "INFO: ILA 2 — $ila2_count probe ports on 100 MHz clock (control signals only)" 466 467 # ============================================================================== 468 # 7. ILA 3 — Doppler Output (100 MHz domain) 469 # 470 # Monitors the Doppler processor output (post-FFT). 471 # Probes: doppler_data OBUF [31:0] + doppler_valid + doppler_bin [4:0] 472 # + range_bin [5:0] + new_frame_pulse = up to 45 bits. 473 # Uses _OBUF net variants which are guaranteed to exist at top-level I/O. 474 # 475 # Uses DEFERRED creation to avoid dangling probe0 errors. 476 # ============================================================================== 477 478 puts "\n====== ILA 3: Doppler Output (100 MHz) ======" 479 480 # Probe 0: Doppler output data [31:0] 481 # Use _OBUF variants (top-level output buffer nets) which are guaranteed 482 # to exist. Fall back to register Q pins if OBUFs are not present. 483 set dop_data_nets [find_bus { 484 {net dbg_doppler_data_OBUF[*]} 485 {pin rx_inst/doppler_proc/doppler_output_reg[*]/Q} 486 {net *doppler_data_OBUF[*]} 487 {net *doppler_output[*]} 488 }] 489 490 # Probe 1: Doppler valid 491 set dop_valid_net [find_net { 492 {net dbg_doppler_valid_OBUF} 493 {net rx_inst/doppler_proc/dbg_doppler_valid_OBUF} 494 {pin rx_inst/doppler_proc/doppler_valid_reg/Q} 495 {net *doppler_valid*} 496 }] 497 if {$dop_valid_net ne ""} { 498 set dop_valid_list [list $dop_valid_net] 499 } else { 500 set dop_valid_list {} 501 } 502 503 # Probe 2: Doppler bin [4:0] 504 set dop_bin_nets [find_bus { 505 {pin rx_inst/doppler_proc/doppler_bin_reg[*]/Q} 506 {net rx_inst/doppler_bin_reg[*]} 507 {net *doppler_bin_OBUF[*]} 508 {net *doppler_bin[*]} 509 }] 510 511 # Probe 3: Range bin [5:0] 512 set rng_bin_nets [find_bus { 513 {pin rx_inst/doppler_proc/range_bin_reg[*]/Q} 514 {net rx_inst/range_bin_reg[*]} 515 {net *range_bin_OBUF[*]} 516 {net *range_bin[*]} 517 }] 518 519 # Probe 4: new_frame_pulse — frame synchronization 520 set frame_net [find_net { 521 {net rx_inst/new_frame_pulse} 522 {net *new_frame_pulse*} 523 {pin rx_inst/new_frame_pulse_reg/Q} 524 {net *frame_pulse*} 525 }] 526 if {$frame_net ne ""} { 527 set frame_list [list $frame_net] 528 } else { 529 set frame_list {} 530 } 531 532 # Deferred creation: only create ILA if at least 1 probe resolves 533 set ila3_probes [list \ 534 [list "Doppler data" $dop_data_nets] \ 535 [list "Doppler valid" $dop_valid_list] \ 536 [list "Doppler bin" $dop_bin_nets] \ 537 [list "Range bin" $rng_bin_nets] \ 538 [list "Frame sync pulse" $frame_list] \ 539 ] 540 set ila3_count [create_ila_deferred u_ila_3 $clk_100m_net $ila3_probes $ila_depth] 541 puts "INFO: ILA 3 — $ila3_count probe ports on 100 MHz clock" 542 543 # ============================================================================== 544 # 8. Pre-implementation validation 545 # ============================================================================== 546 547 puts "\n--- Pre-implementation ILA summary ---" 548 puts "INFO: Total probe bits connected across all ILAs: $total_probes_connected" 549 550 # Sanity check: make sure we connected SOMETHING 551 if {$total_probes_connected == 0} { 552 error "FATAL: No probe nets were connected to any ILA. Check net names against the post-synth netlist." 553 } 554 555 # List all debug cores for the log 556 set created_cores [get_debug_cores -quiet] 557 if {[llength $created_cores] > 0} { 558 foreach core $created_cores { 559 puts " DEBUG CORE: $core" 560 } 561 } else { 562 puts " WARNING: No debug cores found (this should not happen if total_probes_connected > 0)" 563 } 564 565 # ============================================================================== 566 # 9. Implement the modified design (Build 13 directives) 567 # ============================================================================== 568 569 puts "\n======================================================================" 570 puts " Implementation — matching Build 13 directives" 571 puts "======================================================================" 572 573 # Save the post-ILA-insertion checkpoint for reference 574 set ila_dcp "${output_dir}/${top_module}_ila_inserted.dcp" 575 write_checkpoint -force $ila_dcp 576 puts "INFO: Saved ILA-inserted checkpoint: $ila_dcp" 577 578 # --- opt_design (Explore) --- 579 puts "\n--- opt_design -directive Explore ---" 580 opt_design -directive Explore 581 582 write_checkpoint -force "${output_dir}/${top_module}_opt.dcp" 583 584 # --- place_design (ExtraTimingOpt) --- 585 puts "\n--- place_design -directive ExtraTimingOpt ---" 586 place_design -directive ExtraTimingOpt 587 588 write_checkpoint -force "${output_dir}/${top_module}_placed.dcp" 589 590 # Post-place timing estimate 591 report_timing_summary -file "${output_dir}/timing_post_place.rpt" -max_paths 20 592 593 # --- phys_opt_design (AggressiveExplore) — post-place --- 594 puts "\n--- phys_opt_design -directive AggressiveExplore (post-place) ---" 595 phys_opt_design -directive AggressiveExplore 596 597 write_checkpoint -force "${output_dir}/${top_module}_physopt.dcp" 598 599 # --- route_design (AggressiveExplore) --- 600 puts "\n--- route_design -directive AggressiveExplore ---" 601 route_design -directive AggressiveExplore 602 603 write_checkpoint -force "${output_dir}/${top_module}_routed.dcp" 604 605 # Post-route timing check 606 report_timing_summary -file "${output_dir}/timing_post_route.rpt" -max_paths 50 607 608 # --- post-route phys_opt_design (AggressiveExplore) --- 609 puts "\n--- phys_opt_design -directive AggressiveExplore (post-route) ---" 610 phys_opt_design -directive AggressiveExplore 611 612 # Final routed + physopt checkpoint 613 set final_dcp "${output_dir}/${top_module}_postroute_physopt.dcp" 614 write_checkpoint -force $final_dcp 615 puts "INFO: Final checkpoint: $final_dcp" 616 617 # ============================================================================== 618 # 10. Generate reports for comparison with Build 13 619 # ============================================================================== 620 621 puts "\n======================================================================" 622 puts " Reports" 623 puts "======================================================================" 624 625 # Timing summary (compare WNS/TNS/WHS/THS against Build 13) 626 report_timing_summary \ 627 -file "${output_dir}/timing_summary_final.rpt" \ 628 -max_paths 100 \ 629 -report_unconstrained 630 631 # Per-clock-domain timing (critical for multi-clock radar design) 632 report_timing \ 633 -file "${output_dir}/timing_per_clock.rpt" \ 634 -max_paths 20 \ 635 -sort_by group 636 637 # Utilization (expect ~2-4% increase from ILA cores on XC7A200T) 638 report_utilization \ 639 -file "${output_dir}/utilization.rpt" 640 641 report_utilization \ 642 -file "${output_dir}/utilization_hierarchical.rpt" \ 643 -hierarchical 644 645 # DRC 646 report_drc \ 647 -file "${output_dir}/drc.rpt" 648 649 # Clock interaction / CDC (important with 400 MHz <-> 100 MHz crossing) 650 report_clock_interaction \ 651 -file "${output_dir}/clock_interaction.rpt" \ 652 -delay_type min_max 653 654 # Clock networks (verify BUFG usage) 655 report_clock_networks \ 656 -file "${output_dir}/clock_networks.rpt" 657 658 # Power estimate 659 report_power \ 660 -file "${output_dir}/power.rpt" 661 662 # ILA core summary 663 report_debug_core \ 664 -file "${output_dir}/debug_core_summary.rpt" 665 666 puts "INFO: All reports written to $output_dir" 667 668 # ============================================================================== 669 # 11. Write debug probes file (.ltx) for Vivado Hardware Manager 670 # ============================================================================== 671 672 puts "\n--- Writing debug probes .ltx file ---" 673 674 set ltx_file "${output_dir}/${top_module}.ltx" 675 write_debug_probes -force $ltx_file 676 puts "INFO: Debug probes file: $ltx_file" 677 678 # Also copy the .ltx next to the bitstream for convenience 679 file copy -force $ltx_file "${output_dir}/debug_nets.ltx" 680 681 # ============================================================================== 682 # 12. Generate bitstream 683 # ============================================================================== 684 685 puts "\n======================================================================" 686 puts " Bitstream Generation" 687 puts "======================================================================" 688 689 set bitstream_file "${output_dir}/${top_module}.bit" 690 691 write_bitstream -force $bitstream_file 692 693 puts "INFO: Bitstream written: $bitstream_file" 694 695 # Also generate a .bin file for SPI flash programming if needed 696 write_cfgmem -force \ 697 -format BIN \ 698 -size 32 \ 699 -interface SPIx4 \ 700 -loadbit "up 0x0 $bitstream_file" \ 701 "${output_dir}/${top_module}.bin" 702 703 puts "INFO: SPI flash image: ${output_dir}/${top_module}.bin" 704 705 # ============================================================================== 706 # 13. Final summary 707 # ============================================================================== 708 709 puts "\n======================================================================" 710 puts " AERIS-10 ILA Insertion Complete" 711 puts "======================================================================" 712 puts "" 713 puts " Output directory: $output_dir" 714 puts " Final DCP: $final_dcp" 715 puts " Bitstream: $bitstream_file" 716 puts " Debug probes: $ltx_file" 717 puts " Run tag: $run_tag" 718 puts "" 719 puts " ILA Cores Inserted (only cores with resolved probes):" 720 if {$ila0_count > 0} { 721 puts " u_ila_0 : ADC Capture (400 MHz, depth=$ila_depth, ${ila0_count} probes)" 722 } else { 723 puts " u_ila_0 : ADC Capture — SKIPPED (no probes resolved)" 724 } 725 if {$ila1_count > 0} { 726 puts " u_ila_1 : DDC Output (100 MHz, depth=$ila_depth, ${ila1_count} probes)" 727 } else { 728 puts " u_ila_1 : DDC Output — SKIPPED (no probes resolved)" 729 } 730 if {$ila2_count > 0} { 731 puts " u_ila_2 : MF Control (100 MHz, depth=$ila_depth, ${ila2_count} probes)" 732 } else { 733 puts " u_ila_2 : MF Control — SKIPPED (no probes resolved)" 734 } 735 if {$ila3_count > 0} { 736 puts " u_ila_3 : Doppler Output (100 MHz, depth=$ila_depth, ${ila3_count} probes)" 737 } else { 738 puts " u_ila_3 : Doppler Output — SKIPPED (no probes resolved)" 739 } 740 puts " Total probe bits connected: $total_probes_connected" 741 puts "" 742 puts " Compare these reports against Build 13 baseline:" 743 puts " - timing_summary_final.rpt (WNS/TNS/WHS/THS)" 744 puts " - utilization.rpt (BRAM/LUT/FF overhead)" 745 puts " - clock_interaction.rpt (CDC paths)" 746 puts "" 747 puts " To load in Hardware Manager:" 748 puts " 1. Program bitstream: $bitstream_file" 749 puts " 2. Load probes file: $ltx_file" 750 puts " 3. Set trigger position to $trigger_pos for pre/post capture" 751 puts "" 752 puts " Finished at [clock format [clock seconds]]" 753 puts "======================================================================" 754 755 close_design