startup.tcl 9.47 KB
Newer Older
1
2
3
4
5
6
7
#
# Defines basic Tcl procs that must be there for
# OpenOCD to work.
#
# Embedded into OpenOCD executable
#

oharboe's avatar
oharboe committed
8
9
10
11
12
13
14
15
16
17
18

# Help text list. A list of command + help text pairs.
#
# Commands can be more than one word and they are stored
# as "flash banks" "help text x x x"

proc add_help_text {cmd cmd_help} {
	global ocd_helptext
	lappend ocd_helptext [list $cmd $cmd_help]
}

oharboe's avatar
oharboe committed
19
20
21
22
23
proc get_help_text {} {
	global ocd_helptext
	return $ocd_helptext
}

24
25
26

# Show flash in human readable form
# This is an example of a human readable form of a low level fn
27
28
proc flash_banks {} {
	set i 0
29
	set result ""
30
	foreach {a} [ocd_flash_banks] {
31
32
33
		if {$i > 0} {
			set result "$result\n"
		}
34
		set result [format "$result#%d: %s at 0x%08x, size 0x%08x, buswidth %d, chipwidth %d" $i $a(name) $a(base) $a(size) $a(bus_width) $a(chip_width)]
35
36
		set i [expr $i+1]
	}
37
38
39
40
41
42
	return $result
}

# We need to explicitly redirect this to the OpenOCD command
# as Tcl defines the exit proc
proc exit {} {
43
	ocd_throw exit
44
45
}

oharboe's avatar
oharboe committed
46
47
#Print help text for a command. Word wrap
#help text that is too wide inside column.
48
proc help {args} {
oharboe's avatar
oharboe committed
49
50
51
	global ocd_helptext
	set cmd $args
	foreach a [lsort $ocd_helptext] {
oharboe's avatar
oharboe committed
52
		if {[string length $cmd]==0||[string first $cmd $a]!=-1||[string first $cmd [lindex $a 1]]!=-1} {
53
			set w 50
oharboe's avatar
oharboe committed
54
55
56
57
58
			set cmdname [lindex $a 0]
			set h [lindex $a 1]
			set n 0
			while 1 {
				if {$n > [string length $h]} {break}
59

oharboe's avatar
oharboe committed
60
61
62
63
64
65
66
67
68
69
				set next_a [expr $n+$w]
				if {[string length $h]>$n+$w} {
					set xxxx [string range $h $n [expr $n+$w]]
					for {set lastpos [expr [string length $xxxx]-1]} {$lastpos>=0&&[string compare [string range $xxxx $lastpos $lastpos] " "]!=0} {set lastpos [expr $lastpos-1]} {
					}
					#set next_a -1
					if {$lastpos!=-1} {
						set next_a [expr $lastpos+$n+1]
					}
				}
70
71


oharboe's avatar
oharboe committed
72
73
74
75
				puts [format "%-25s %s" $cmdname [string range $h $n [expr $next_a-1]] ]
				set cmdname ""
				set n [expr $next_a]
			}
oharboe's avatar
oharboe committed
76
77
78
79
		}
	}
}

80
add_help_text help "Tcl implementation of help command"
oharboe's avatar
oharboe committed
81
82


83
# If a fn is unknown to Tcl, we try to execute it as an OpenOCD command
84
85
86
#
# We also support two level commands. "flash banks" is translated to
# flash_banks
87
proc unknown {args} {
88
89
90
	# do the name mangling from "flash banks" to "flash_banks"
	if {[llength $args]>=2} {
		set cmd_name "[lindex $args 0]_[lindex $args 1]"
91
92
93
94
		if {[catch {info body $cmd_name}]==0} {
		    # the command exists, try it...
			return [eval "$cmd_name [lrange $args 2 end]"]
		}
95
	}
96
	# This really is an unknown command.
oharboe's avatar
oharboe committed
97
	return -code error "Unknown command: $args"
98
}
99

100
proc new_target_name { } {
101
	return [target number [expr [target count] - 1 ]]
102
103
}

104
105
106
# Try flipping / and \ to find file if the filename does not
# match the precise spelling
proc find {filename} {
107
	if {[catch {ocd_find $filename} t]==0} {
108
		return $t
109
	}
110
	if {[catch {ocd_find [string map {\ /} $filename} t]==0} {
111
		return $t
112
	}
113
	if {[catch {ocd_find [string map {/ \\} $filename} t]==0} {
114
		return $t
115
	}
116
	# make sure error message matches original input string
117
	return -code error "Can't find $filename"
118
119
120
121
122
123
124
125
126
127
}
add_help_text find "<file> - print full path to file according to OpenOCD search rules"

# Run script
proc script {filename} {
	source [find $filename]
}

add_help_text script "<filename> - filename of OpenOCD script (tcl) to run"

oharboe's avatar
oharboe committed
128
129
130
# Handle GDB 'R' packet. Can be overriden by configuration script,
# but it's not something one would expect target scripts to do
# normally
131
proc ocd_gdb_restart {target_id} {
oharboe's avatar
oharboe committed
132
133
	# Fix!!! we're resetting all targets here! Really we should reset only
	# one target
134
	reset halt
oharboe's avatar
oharboe committed
135
136
}

137
138
139
140
global in_process_reset
set in_process_reset 0

# Catch reset recursion
141
proc ocd_process_reset { MODE } {
142
143
144
145
146
	global in_process_reset
	if {$in_process_reset} {
		set in_process_reset 0
		return -code error "'reset' can not be invoked recursively"
	}
147

148
	set in_process_reset 1
149
	set success [expr [catch {ocd_process_reset_inner $MODE} result]==0]
150
	set in_process_reset 0
151

152
153
154
155
156
157
158
159
	if {$success} {
		return $result
	} else {
		return -code error $result
	}
}

proc ocd_process_reset_inner { MODE } {
160
	set targets [target names]
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
	# If this target must be halted...
	set halt -1
	if { 0 == [string compare $MODE halt] } {
		set halt 1
	}
	if { 0 == [string compare $MODE init] } {
		set halt 1;
	}
	if { 0 == [string compare $MODE run ] } {
		set halt 0;
	}
	if { $halt < 0 } {
		return -error "Invalid mode: $MODE, must be one of: halt, init, or run";
	}

zwelch's avatar
zwelch committed
177
178
	# Target event handlers *might* change which TAPs are enabled
	# or disabled, so we fire all of them.  But don't issue any
179
	# target "arp_*" commands, which may issue JTAG transactions,
zwelch's avatar
zwelch committed
180
	# unless we know the underlying TAP is active.
181
182
183
	#
	# NOTE:  ARP == "Advanced Reset Process" ... "advanced" is
	# relative to a previous restrictive scheme
zwelch's avatar
zwelch committed
184

185
	foreach t $targets {
186
187
		# New event script.
		$t invoke-event reset-start
188
	}
189

190
191
192
193
194
	# Use TRST or TMS/TCK operations to reset all the tap controllers.
	# TAP reset events get reported; they might enable some taps.
	#
	# REVISIT arp_init-reset pulses SRST (if it can) with TRST active;
	# but SRST events aren't reported (unlike "jtag arp_reset", below)
195
	jtag arp_init-reset
196

zwelch's avatar
zwelch committed
197
	# Examine all targets on enabled taps.
198
	foreach t $targets {
zwelch's avatar
zwelch committed
199
200
201
		if {[jtag tapisenabled [$t cget -chain-position]]} {
			$t arp_examine
		}
202
	}
203

204
	# Assert SRST, and report the pre/post events.
205
	# Note:  no target sees SRST before "pre" or after "post".
206
	foreach t $targets {
207
		$t invoke-event reset-assert-pre
208
209
	}
	foreach t $targets {
210
		# C code needs to know if we expect to 'halt'
zwelch's avatar
zwelch committed
211
212
213
		if {[jtag tapisenabled [$t cget -chain-position]]} {
			$t arp_reset assert $halt
		}
214
215
	}
	foreach t $targets {
216
		$t invoke-event reset-assert-post
217
	}
218

219
	# Now de-assert SRST, and report the pre/post events.
220
	# Note:  no target sees !SRST before "pre" or after "post".
221
	foreach t $targets {
222
		$t invoke-event reset-deassert-pre
223
224
225
	}
	foreach t $targets {
		# Again, de-assert code needs to know if we 'halt'
zwelch's avatar
zwelch committed
226
227
228
		if {[jtag tapisenabled [$t cget -chain-position]]} {
			$t arp_reset deassert $halt
		}
229
230
	}
	foreach t $targets {
231
		$t invoke-event reset-deassert-post
232
	}
233

234
235
236
	# 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.
237
	if { $halt } {
238
		foreach t $targets {
zwelch's avatar
zwelch committed
239
240
241
242
			if {[jtag tapisenabled [$t cget -chain-position]] == 0} {
				continue
			}

243
244
245
246
			# Wait upto 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
247

248
249
			# Catch, but ignore any errors.
			catch { $t arp_waitstate halted 1000 }
250

251
252
			# Did we succeed?
			set s [$t curstate]
253

254
			if { 0 != [string compare $s "halted" ] } {
255
				return -error [format "TARGET: %s - Not halted" $t]
256
			}
257
		}
258
	}
259

260
261
	#Pass 2 - if needed "init"
	if { 0 == [string compare init $MODE] } {
262
		foreach t $targets {
zwelch's avatar
zwelch committed
263
264
265
266
			if {[jtag tapisenabled [$t cget -chain-position]] == 0} {
				continue
			}

267
268
269
			set err [catch "$t arp_waitstate halted 5000"]
			# Did it halt?
			if { $err == 0 } {
270
				$t invoke-event reset-init
271
			}
272
		}
273
	}
274

275
	foreach t $targets {
276
		$t invoke-event reset-end
277
	}
278
}
oharboe's avatar
oharboe committed
279
280
281
282
283

# stubs for targets scripts that do not have production procedure
proc production_info {} {
	return "Imagine an explanation here..."
}
oharboe's avatar
oharboe committed
284
add_help_text production_info "Displays information on production procedure for target script. Implement this procedure in target script."
oharboe's avatar
oharboe committed
285
286
287

proc production {firmwarefile serialnumber} {
	puts "Imagine production procedure running successfully. Programmed $firmwarefile with serial number $serialnumber"
288
}
oharboe's avatar
oharboe committed
289

oharboe's avatar
oharboe committed
290
add_help_text production "<serialnumber> - Runs production procedure. Throws exception if procedure failed. Prints progress messages. Implement this procedure in the target script."
oharboe's avatar
oharboe committed
291
292
293
294

proc production_test {} {
	puts "Imagine nifty test procedure having run to completion here."
}
295
add_help_text production_test "Runs test procedure. Throws exception if procedure failed. Prints progress messages. Implement in target script."
oharboe's avatar
oharboe committed
296

oharboe's avatar
oharboe committed
297
298
299
300
301
add_help_text cpu "<name> - prints out target options and a comment on CPU which matches name"

# A list of names of CPU and options required
set ocd_cpu_list {
	{
302
303
		name IXP42x
		options {xscale -variant IXP42x}
oharboe's avatar
oharboe committed
304
305
306
		comment {IXP42x cpu}
	}
	{
307
308
		name arm7
		options {arm7tdmi -variant arm7tdmi}
oharboe's avatar
oharboe committed
309
310
311
312
313
314
315
316
317
318
319
		comment {vanilla ARM7}
	}
}

# Invoked from Tcl code
proc ocd_cpu {args} {
	set name $args
	set result ""
	global ocd_cpu_list
	foreach a [lsort $ocd_cpu_list] {
		if {[string length $args]==0||[string first [string toupper $name] [string toupper "$a(name)$a(options)$a(comment)"]]!=-1} {
320
			lappend result $a
oharboe's avatar
oharboe committed
321
322
323
324
325
326
327
328
329
330
331
332
333
		}
	}
	return $result
}

proc cpu {args} {
    #     0123456789012345678901234567890123456789012345678901234567890123456789
	puts "CPU                 Options                                 Comment"
	foreach a [lsort [ocd_cpu $args]] {
		puts [format "%-20s%-40s%s" $a(name) $a(options) $a(comment)]
	}
}

334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
proc power_restore {} {
	puts "Sensed power restore."
	reset init
}

add_help_text power_restore "Overridable procedure run when power restore is detected. Runs 'reset init' by default."

proc power_dropout {} {
	puts "Sensed power dropout."
}

proc srst_deasserted {} {
	puts "Sensed nSRST deasserted."
	reset init
}
add_help_text srst_deasserted "Overridable procedure run when srst deassert is detected. Runs 'reset init' by default."

proc srst_asserted {} {
	puts "Sensed nSRST asserted."
}
oharboe's avatar
oharboe committed
354
355
356
357
358
359

# catch any exceptions, capture output and return output
proc capture_catch {a} {
	catch {
		capture {uplevel $a}
	} result
360
	return $result
oharboe's avatar
oharboe committed
361
}
362
363
364
365
366
367
368
369
370
371


# Executed during "init". Can be implemented by target script 
# tar
proc jtag_init {} {
	if {[catch {jtag arp_init} err]!=0} {
		# try resetting additionally
		jtag arp_init-reset
	}
}