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

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)