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

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)