9be4a05e0eee689fc05a8d2df3295f3b80dc3ccd
[openocd.git] / doc / manual / primer / tcl.txt
1 /** @page primertcl OpenOCD TCL Primer
2
3 The @subpage scripting page provides additional TCL Primer material.
4
5 @verbatim
6
7 ****************************************
8 ****************************************
9
10 This is a short introduction to 'un-scare' you about the language
11 known as TCL. It is structured as a guided tour through the files
12 written by me [Duane Ellis] - in early July 2008 for OpenOCD.
13
14 Which uses the "JIM" embedded Tcl clone-ish language.
15
16 Thing described here are *totally* TCL generic... not Jim specific.
17
18 The goal of this document is to encourage you to add your own set of
19 chips to the TCL package - and most importantly you should know where
20 you should put them - so they end up in an organized way.
21
22 --Duane Ellis.
23 duane@duaneellis.com
24
25 ****************************************
26 ****************************************
27
28 Adding "chip" support - Duane Ellis July 5 - 2008.
29
30 The concept is this:
31 In your "openocd.cfg" file add something like this:
32
33 source [find tcl/chip/VENDOR/FAMILY/NAME.tcl]
34
35 For example...
36 source [find tcl/chip/atmel/at91/at91sam7x256.tcl]
37
38 You'll notice that it makes use of:
39
40 tcl/cpu/arm/<NAME>.tcl.
41
42 Yes, that is where you should put "core" specific things.
43 Be careful and learn the difference:
44
45 THE "CORE" - is not the entire chip!
46
47 Definition:
48 That "file" listed above is called a "CHIP FILE".
49
50 It may be standalone, or may need to "source" other "helper" files.
51
52 The reference [7/5/2008] is the at91sam7x256.tcl file.
53
54 ****************************************
55 ****************************************
56 === TCL TOUR ===
57 Open: at91sam7x256.tcl
58 === TCL TOUR ===
59
60 A walk through --- For those who are new to TCL.
61
62 Examine the file: at91sam7x256.tcl
63
64 It starts with:
65 source [find path/filename.tcl]
66
67 In TCL - this is very important.
68
69 Rule #1 Everything is a string.
70 Rule #2 If you think other wise See #1.
71 Reminds you of:
72 Rule #1: The wife is correct.
73 Rule #2: If you think otherwise, See #1
74
75 Any text contained inside of [square-brackets]
76 is just like `back-ticks` in BASH.
77
78 Hence, the [find FILENAME] executes the command find with a single
79 parameter the filename.
80
81 ========================================
82
83 Next you see a series of:
84
85 set NAME VALUE
86
87 It is mostly "obvious" what is going on.
88
89 Exception: The arrays.
90
91 You would *THINK* Tcl supports arrays.
92 In fact, multi-dim arrays. That is false.
93
94 For the index for"FLASH(0,CHIPSELECT)" is actually the string
95 "0,CHIPSELECT". This is problematic. In the normal world, you think
96 of array indexes as integers.
97
98 For example these are different:
99
100 set foo(0x0c) 123
101 set foo(12) 444
102
103 Why? Because 0x0c {lowercase} is a string.
104 Don't forget UPPER CASE.
105
106 You must be careful - always... always... use simple decimal
107 numbers. When in doubt use 'expr' the evaluator. These are all the
108 same.
109
110 set x 0x0c
111 set foo([expr $x]) "twelve"
112
113 set x 12
114 set foo([expr $x]) "twelve"
115
116 set x "2 * 6"
117 set foo([expr $x]) "twelve"
118
119 **************************************************
120 ***************************************************
121 === TCL TOUR ===
122 Open the file: "bitsbytes.tcl"
123
124 There is some tricky things going on.
125 ===============
126
127 First, there is a "for" loop - at level 0
128 {level 0 means: out side of a proc/function}
129
130 This means it is evaluated when the file is parsed.
131
132 == SIDEBAR: About The FOR command ==
133 In TCL, "FOR" is a funny thing, it is not what you think it is.
134
135 Syntactically - FOR is a just a command, it is not language
136 construct like for(;;) in C...
137
138 The "for" command takes 4 parameters.
139 (1) The "initial command" to execute.
140 (2) the test "expression"
141 (3) the "next command"
142 (4) the "body command" of the FOR loop.
143
144 Notice I used the words "command" and "expression" above.
145
146 The FOR command:
147 1) executes the "initial command"
148 2) evaluates the expression if 0 it stops.
149 3) executes the "body command"
150 4) executes the "next command"
151 5) Goto Step 2.
152
153 As show, each of these items are in {curly-braces}. This means they
154 are passed as they are - KEY-POINT: un evaluated to the FOR
155 command. Think of it like escaping the backticks in Bash so that the
156 "under-lying" command can evaluate the contents. In this case, the FOR
157 COMMAND.
158
159 == END: SIDEBAR: About The FOR command ==
160
161 You'll see two lines:
162
163 LINE1:
164 set vn [format "BIT%d" $x]
165
166 Format is like "sprintf". Because of the [brackets], it becomes what
167 you think. But here's how:
168
169 First - the line is parsed - for {braces}. In this case, there are
170 none. The, the parser looks for [brackets] and finds them. The,
171 parser then evaluates the contents of the [brackets], and replaces
172 them. It is alot this bash statement.
173
174 EXPORT vn=`date`
175
176 LINE 2 & 3
177 set $vn [expr (1024 * $x)]
178 global $vn
179
180 In line 1, we dynamically created a variable name. Here, we are
181 assigning it a value. Lastly Line 3 we force the variable to be
182 global, not "local" the the "for command body"
183
184 ===============
185 The PROCS
186
187 proc create_mask { MSB LSB } {
188 ... body ....
189 }
190
191 Like "for" - PROC is really just a command that takes 3 parameters.
192 The (1) NAME of the function, a (2) LIST of parameters, and a (3) BODY
193
194 Again, this is at "level 0" so it is a global function. (Yes, TCL
195 supports local functions, you put them inside of a function}
196
197 You'll see in some cases, I nest [brackets] alot and in others I'm
198 lazy or wanted it to be more clear... it is a matter of choice.
199 ===============
200
201
202 **************************************************
203 ***************************************************
204 === TCL TOUR ===
205 Open the file: "memory.tcl"
206 ===============
207
208 Here is where I setup some 'memory definitions' that various targets can use.
209
210 For example - there is an "unknown" memory region.
211
212 All memory regions must have 2 things:
213
214 (1) N_<name>
215 (2) NAME( array )
216 And the array must have some specific names:
217 ( <idx>, THING )
218 Where: THING is one of:
219 CHIPSELECT
220 BASE
221 LEN
222 HUMAN
223 TYPE
224 RWX - the access ability.
225 WIDTH - the accessible width.
226
227 ie: Some regions of memory are not 'word'
228 accessible.
229
230 The function "address_info" - given an address should
231 tell you about the address.
232
233 [as of this writing: 7/5/2008 I have done
234 only a little bit with this -Duane]
235
236 ===
237 MAJOR FUNCTION:
238 ==
239
240 proc memread32 { ADDR }
241 proc memread16 { ADDR }
242 proc memread8 { ADDR }
243
244 All read memory - and return the contents.
245
246 [ FIXME: 7/5/2008 - I need to create "memwrite" functions]
247
248 **************************************************
249 ***************************************************
250 === TCL TOUR ===
251 Open the file: "mmr_helpers.tcl"
252 ===============
253
254 This file is used to display and work with "memory mapped registers"
255
256 For example - 'show_mmr32_reg' is given the NAME of the register to
257 display. The assumption is - the NAME is a global variable holding the
258 address of that MMR.
259
260 The code does some tricks. The [set [set NAME]] is the TCL way
261 of doing double variable interpolation - like makefiles...
262
263 In a makefile or shell script you may have seen this:
264
265 FOO_linux = "Penguins rule"
266 FOO_winXP = "Broken Glass"
267 FOO_mac = "I like cat names"
268
269 # Pick one
270 BUILD = linux
271 #BUILD = winXP
272 #BUILD = mac
273 FOO = ${FOO_${BUILD}}
274
275 The "double [set] square bracket" thing is the TCL way, nothing more.
276
277 ----
278
279 The IF statement - and "CATCH" .
280
281 Notice this IF COMMAND - (not statement) is like this:
282 [7/5/2008 it is this way]
283
284 if ![catch { command } msg ] {
285 ...something...
286 } else {
287 error [format string...]
288 }
289
290 The "IF" command expects either 2 params, or 4 params.
291
292 === Sidebar: About "commands" ===
293
294 Take a look at the internals of "jim.c"
295 Look for the function: Jim_IfCoreCommand()
296 And all those other "CoreCommands"
297
298 You'll notice - they all have "argc" and "argv"
299
300 Yea, the entire thing is done that way.
301
302 IF is a command. SO is "FOR" and "WHILE" and "DO" and the
303 others. That is why I keep using the phase it is a "command"
304
305 === END: Sidebar: About "commands" ===
306
307 Parameter 1 to the IF command is expected to be an expression.
308
309 As such, I do not need to wrap it in {braces}.
310
311 In this case, the "expression" is the result of the "CATCH" command.
312
313 CATCH - is an error catcher.
314
315 You give CATCH 1 or 2 parameters.
316 The first 1st parameter is the "code to execute"
317 The 2nd (optional) is where to put the error message.
318
319 CATCH returns 0 on success, 1 for failure.
320 The "![catch command]" is self explaintory.
321
322
323 The 3rd parameter to IF must be exactly "else" or "elseif" [I lied
324 above, the IF command can take many parameters they just have to
325 be joined by exactly the words "else" or "elseif".
326
327 The 4th parameter contains:
328
329 "error [format STRING....]"
330
331 This lets me modify the previous lower level error by tacking more
332 text onto the end of it. In this case, i want to add the MMR register
333 name to make my error message look better.
334
335 ---------
336 Back to something inside show_mmr32_reg{}.
337
338 You'll see something 'set fn show_${NAME}_helper' Here I am
339 constructing a 'function name' Then - I look it up to see if it
340 exists. {the function: "proc_exists" does this}
341
342 And - if it does - I call the function.
343
344 In "C" it is alot like using: 'sprintf()' to construct a function name
345 string, then using "dlopen()" and "dlsym()" to look it up - and get a
346 function pointer - and calling the function pointer.
347
348 In this case - I execute a dynamic command. You can do some cool
349 tricks with interpretors.
350
351 ----------
352
353 Function: show_mmr32_bits()
354
355 In this case, we use the special TCL command "upvar" which tcl's way
356 of passing things by reference. In this case, we want to reach up into
357 the callers lexical scope and find the array named "NAMES"
358
359 The rest of the function is pretty straight forward.
360
361 First - we figure out the longest name.
362 Then print 4 rows of 8bits - with names.
363
364
365 **************************************************
366 ***************************************************
367 === TCL TOUR ===
368 Open the file: "chips/atmel/at91/usarts.tcl"
369 ===============
370
371 First - about the AT91SAM series - all of the usarts
372 are basically identical...
373
374 Second - there can be many of them.
375
376 In this case - I do some more TCL tricks to dynamically
377 create functions out of thin air.
378
379 Some assumptions:
380
381 The "CHIP" file has defined some variables in a proper form.
382
383 ie: AT91C_BASE_US0 - for usart0,
384 AT91C_BASE_US1 - for usart1
385 ... And so on ...
386
387 Near the end of the file - look for a large "foreach" loop that
388 looks like this:
389
390 foreach WHO { US0 US1 US2 US3 US4 .... } {
391
392 }
393
394 In this case, I'm trying to figure out what USARTs exist.
395
396 Step 1 - is to determine if the NAME has been defined.
397 ie: Does AT91C_BASE_USx - where X is some number exist?
398
399 The "info exists VARNAME" tells you if the variable exists. Then -
400 inside the IF statement... There is another loop. This loop is the
401 name of various "sub-registers" within the USART.
402
403 Some more trick are played with the [set VAR] backtick evaluation stuff.
404 And we create two variables
405
406 We calculate and create the global variable name for every subregister in the USART.
407 And - declare that variable as GLOBAL so the world can find it.
408
409 Then - we dynamically create a function - based on the register name.
410
411 Look carefully at how that is done. You'll notice the FUNCTION BODY is
412 a string - not something in {braces}. Why? This is because we need TCL
413 to evaluate the contents of that string "*NOW*" - when $vn exists not
414 later, when the function "show_FOO" is invoked.
415
416 Lastly - we build a "str" of commands - and create a single function -
417 with the generated list of commands for the entire USART.
418
419 With that little bit of code - I now have a bunch of functions like:
420
421 show_US0, show_US1, show_US2, .... etc ...
422
423 And show_US0_MR, show_US0_IMR ... etc...
424
425 And - I have this for every USART... without having to create tons of
426 boiler plate yucky code.
427
428 ****************************************
429 ****************************************
430 END of the Tcl Intro and Walk Through
431 ****************************************
432 ****************************************
433
434 FUTURE PLANS
435
436 Some "GPIO" functions...
437
438 @endverbatim
439
440 */

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)