# SPDX-License-Identifier: GPL-2.0-or-later # Defines basic Tcl procs for OpenOCD target module proc new_target_name { } { return [target number [expr {[target count] - 1}]] } global in_process_reset set in_process_reset 0 # Catch reset recursion proc ocd_process_reset { MODE } { global in_process_reset if {$in_process_reset} { set in_process_reset 0 return -code error "'reset' can not be invoked recursively" } set in_process_reset 1 set success [expr {[catch {ocd_process_reset_inner $MODE} result] == 0}] set in_process_reset 0 if {$success} { return $result } else { return -code error $result } } proc ocd_process_reset_inner { MODE } { set targets [target names] # If this target must be halted... switch $MODE { halt - init { set halt 1 } run { set halt 0 } default { return -code error "Invalid mode: $MODE, must be one of: halt, init, or run"; } } # Target event handlers *might* change which TAPs are enabled # or disabled, so we fire all of them. But don't issue any # target "arp_*" commands, which may issue JTAG transactions, # unless we know the underlying TAP is active. # # NOTE: ARP == "Advanced Reset Process" ... "advanced" is # relative to a previous restrictive scheme foreach t $targets { # New event script. $t invoke-event reset-start } # Use TRST or TMS/TCK operations to reset all the tap controllers. # TAP reset events get reported; they might enable some taps. init_reset $MODE # Examine all targets on enabled taps. foreach t $targets { if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t invoke-event examine-start set err [catch "$t arp_examine allow-defer"] if { $err } { $t invoke-event examine-fail } else { $t invoke-event examine-end } } } # Assert SRST, and report the pre/post events. # Note: no target sees SRST before "pre" or after "post". foreach t $targets { $t invoke-event reset-assert-pre } foreach t $targets { # C code needs to know if we expect to 'halt' if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t arp_reset assert $halt } } foreach t $targets { $t invoke-event reset-assert-post } # Now de-assert SRST, and report the pre/post events. # Note: no target sees !SRST before "pre" or after "post". foreach t $targets { $t invoke-event reset-deassert-pre } foreach t $targets { # Again, de-assert code needs to know if we 'halt' if {![using_jtag] || [jtag tapisenabled [$t cget -chain-position]]} { $t arp_reset deassert $halt } } foreach t $targets { $t invoke-event reset-deassert-post } # Pass 1 - Now wait for any halt (requested as part of reset # assert/deassert) to happen. Ideally it takes effect without # first executing any instructions. if { $halt } { foreach t $targets { if {[using_jtag] && ![jtag tapisenabled [$t cget -chain-position]]} { continue } if { ![$t was_examined] } { # don't wait for targets where examination is deferred # they can not be halted anyway at this point if { [$t examine_deferred] } { continue } # try to re-examine or target state will be unknown $t invoke-event examine-start set err [catch "$t arp_examine allow-defer"] if { $err } { $t invoke-event examine-fail return -code error [format "TARGET: %s - Not examined" $t] } else { $t invoke-event examine-end } } # Wait up to 1 second for target to halt. Why 1sec? Cause # the JTAG tap reset signal might be hooked to a slow # resistor/capacitor circuit - and it might take a while # to charge # Catch, but ignore any errors. catch { $t arp_waitstate halted 1000 } # Did we succeed? set s [$t curstate] if { $s != "halted" } { return -code error [format "TARGET: %s - Not halted" $t] } } } #Pass 2 - if needed "init" if { $MODE == "init" } { foreach t $targets { if {[using_jtag] && ![jtag tapisenabled [$t cget -chain-position]]} { continue } # don't wait for targets where examination is deferred # they can not be halted anyway at this point if { ![$t was_examined] && [$t examine_deferred] } { continue } set err [catch "$t arp_waitstate halted 5000"] # Did it halt? if { $err == 0 } { $t invoke-event reset-init } } } foreach t $targets { $t invoke-event reset-end } } proc using_jtag {} { set _TRANSPORT [ transport select ] expr { [ string first "jtag" $_TRANSPORT ] != -1 } } proc using_swd {} { set _TRANSPORT [ transport select ] expr { [ string first "swd" $_TRANSPORT ] != -1 } } proc using_hla {} { set _TRANSPORT [ transport select ] expr { [ string first "hla" $_TRANSPORT ] != -1 } } ######### # Target/chain configuration scripts can either execute commands directly # or define a procedure which is executed once all configuration # scripts have completed. # # By default(classic) the config scripts will set up the target configuration proc init_targets {} { } proc set_default_target_event {t e s} { if {[$t cget -event $e] == ""} { $t configure -event $e $s } } proc init_target_events {} { set targets [target names] foreach t $targets { set_default_target_event $t gdb-flash-erase-start "reset init" set_default_target_event $t gdb-flash-write-end "reset halt" set_default_target_event $t gdb-attach "halt 1000" } } # Additionally board config scripts can define a procedure init_board that will be executed after init and init_targets proc init_board {} { } lappend _telnet_autocomplete_skip _post_init_target_array_mem proc _post_init_target_array_mem {} { set targets [target names] lappend targets "" foreach t $targets { if {$t != ""} { set t "$t " } eval [format {lappend ::_telnet_autocomplete_skip "%smem2array"} $t] eval [format {proc {%smem2array} {arrayname bitwidth address count {phys ""}} { echo "DEPRECATED! use 'read_memory' not 'mem2array'" upvar $arrayname $arrayname set $arrayname "" set i 0 foreach elem [%sread_memory $address $bitwidth $count {*}$phys] { set ${arrayname}($i) $elem incr i } }} $t $t] eval [format {lappend ::_telnet_autocomplete_skip "%sarray2mem"} $t] eval [format {proc {%sarray2mem} {arrayname bitwidth address count {phys ""}} { echo "DEPRECATED! use 'write_memory' not 'array2mem'" upvar $arrayname $arrayname set data "" for {set i 0} {$i < $count} {incr i} { lappend data [expr $${arrayname}($i)] } %swrite_memory $address $bitwidth $data {*}$phys }} $t $t] } } lappend post_init_commands _post_init_target_array_mem # smp_on/smp_off were already DEPRECATED in v0.11.0 through http://openocd.zylin.com/4615 lappend _telnet_autocomplete_skip "aarch64 smp_on" proc "aarch64 smp_on" {args} { echo "DEPRECATED! use 'aarch64 smp on' not 'aarch64 smp_on'" eval aarch64 smp on $args } lappend _telnet_autocomplete_skip "aarch64 smp_off" proc "aarch64 smp_off" {args} { echo "DEPRECATED! use 'aarch64 smp off' not 'aarch64 smp_off'" eval aarch64 smp off $args } lappend _telnet_autocomplete_skip "cortex_a smp_on" proc "cortex_a smp_on" {args} { echo "DEPRECATED! use 'cortex_a smp on' not 'cortex_a smp_on'" eval cortex_a smp on $args } lappend _telnet_autocomplete_skip "cortex_a smp_off" proc "cortex_a smp_off" {args} { echo "DEPRECATED! use 'cortex_a smp off' not 'cortex_a smp_off'" eval cortex_a smp off $args } lappend _telnet_autocomplete_skip "mips_m4k smp_on" proc "mips_m4k smp_on" {args} { echo "DEPRECATED! use 'mips_m4k smp on' not 'mips_m4k smp_on'" eval mips_m4k smp on $args } lappend _telnet_autocomplete_skip "mips_m4k smp_off" proc "mips_m4k smp_off" {args} { echo "DEPRECATED! use 'mips_m4k smp off' not 'mips_m4k smp_off'" eval mips_m4k smp off $args }