A loop is a piece of code that gets executed over and over again until some condition is met. Loops are common and powerful tools used in many Tcl scripts so it’s worth spending some time understanding their quirks. Tcl supports three types of loops, whilefor, and foreach.

While Loop

 while loops are typically used when the exact number of iterations to execute the code is unknown. For example, iterating over a piece of code that sequenctially improves timing in your FPGA design until timing conditions are met. Care must be taken to avoid writing infinite loops as some conditions may never be met. Running code iteratively until timing is met may result in an infinite loop if the design is simply too large for the FPGA. The syntax for while loops is 

while testCondition body

Like most things in Tcl, this can be rewritten for better readability as shown.

while {testCondition} {
    body 
}

The testCondition is evaluated using the same rules as the expr command. Note: make sure  to wrap the testCondition within braces, failure to do so will likely result in an infinite loop. Let’s look at the following example.

set x 1

while {$x<4} {
    puts “$x is less than 4”
    incr x; #increments x by 1
}

Because the test condition is wrapped in braces the code executes as expected and produces the following output

1 is less than 4
2 is less than 4
3 is less than 4

The incr command expects an integer variable and by default increments the variable by one. However, it is possible to override this behavior and increment by other values or even decrement the variable by passing a third parameter such as incr x -2 which decrements x by 2.

But what happens if we forget to include the braces around the testCondition or use quotes instead as shown below?


while $x<4 {
    puts “$x is less than 4”
    incr x; #increments x by 1
}

This code produces an infinite loop! It prints

1 is less than 4
2 is less than 4
3 is less than 4
4 is less than 4
…

To understand what is going on we must first remember Tcl substitution rules. Before a command is evaluated Tcl substitutes the variables, in this case $x<4 is now 1<4. Then the while command is executed where a second round of substitution occurs.  However, due to the first round of substitutions made by the Tcl compiler,  the test condition that is evaluated each time the code is executed is 1<4, which is always true! Thus we wrap the testCondition within braces to prevent the first round of substitution.

For Loop

for loops are typically used when the number of iterations to execute a piece of code is known. The for loop syntax is

for start testCondition next body

but is better written as 

for {start} {testCondition} {next} {
    body 
}

Just like the while loop we’ll want to wrap the start, testCondition, and next portions with braces to avoid unwanted substitutions that result in infinite loops. start initializes the variable that is checked within the testCondition. This initialization only occurs once during the first pass of the for loop. The testCondition behaves as it did within the while loop. next manipulates the variable defined in start after the body is executed. It’s time to show some examples.

for {set x 0} {$x < 3} {incr x} {
    puts "$x is less than 3"
}
puts "$x is equal to 3 \n"

for {set x 4} {$x > 1} {set x [expr {$x-1}]} {
    puts "$x is greater than 1"
}
puts "$x is equal to 1 \n"

for {set x 5} {$x>2} {incr x -1} {
    puts "$x > 2" 
    if {$x == 4} {
  	set y 40
    }
}
puts "$x is equal to 2"
puts "\$y = $y"

Running the above code produces

0 is less than 3
1 is less than 3
2 is less than 3
3 is equal to 3 

4 is greater than 1
3 is greater than 1
2 is greater than 1
1 is equal to 1 

5 > 2
4 > 2
3 > 2
2 is equal to 2
$y = 40

Notice that variables defined within the for loop can be used anywhere in the code.

Many times it’s necessary to loop through an array. If the array index starts at one and increments sequentially then all we need to do is use the length of the array in the test condition. This can be done by first finding and storing the length of the array with the code below. In this case, the command within the brackets gets executed first and returned. array is a keyword in Tcl where size is an argument and arrayname is the name of the array you wish to get the size of. Be warned, this example assumes that the indices of the array are all sequential numbers and that the starting index is known. Because arrays in Tcl are associative this is not always the case. If you need to loop through an array I suggest you check out the article found here.

set length [array size arrayname]
set names(0) Ammy
set names(1) Billy
set names(2) Sarah

set lengthNames [array size names]
for {set x 1} {$x<lengthNames} {incr x} {
    puts "names = $names($x)"
}

Foreach

The foreach command in Tcl creates a loop that iterates through all of the elements of a list. Do not get confused, arrays are not lists. Most commonly, lists are one dimensional but it is possible to loop through multi-dimensional lists. The syntax for the foreach command is

foreach variable list body

or more commonly

foreach variable list {
    body
}

Learning how foreach works is best done through examples. The example below shows a one-dimensional foreach loop. x is the loop variable that takes on the value of each element in the list and the list elements can take on any string. The elements in the list are separated by a space.

foreach x {1 2 tom 4 5 6} {
    puts "x = $x"
}

Next are multi-dimensional lists which can take one of two forms. The first is to include a second loop variable as shown in the example below. The first element in the list is assigned to the first loop variable and the second element in the list is assigned to the second loop variable. If the number of elements in the list is not divisible by the number of loop variable then on the last iteration of the loop, the loop variables without matching elements get assigned an empty string.

foreach {x y} {1 2 3 4 5 6 7 8 9} {
	puts "x = $x"
	puts "y = $y"
}

The second method of creating multi-dimensional foreach loops is shown below.  In this case, the loop variables and lists are split into loop variable and list pairs. This is the preferred method as it clarifies the programmer’s intent and is less prone to mistakes. If the two lists are not the same length, the loop variable associated with the shorter list is assigned empty strings for the final iterations.

foreach {x} {1 2 3 4} {y} {5 6 7 8 9} {
	puts "x = $x"
	puts "y = $y"
}

 There are many cases where we want the list to be set by a variable. This is easily shown as follows

set list1 {1 -1 2 -2 3 -3}
foreach {x} $list1 { ;#when using a variable for list don't wrap it in braces as it prevents substitution
	puts "x = $x"
}

Be warned, if the list variable (not to be confused with the loop variable} is wrapped with braces then variable substitution does not occur and you will get undesirable results.

Take a moment to try some of the examples in the widget below. As always, please leave a comment and let us know what you’d like to learn next.

JOIN OUR NEWSLETTER
I agree to receive email updates when new content is posted and receive promotional emails when new courses are available
Enjoying the article? Receive free updates when new content is published and courses are available.
We hate spam. Your email address will not be sold or shared with anyone else.
Christopher Hogstrom
christopher.hogstrom@grittyengineer.com

2 thoughts on “Tcl Loops”

  1. Hello. I have checked your grittyengineer.com and i see you’ve got some duplicate content so probably it is the reason that
    you don’t rank high in google. But you can fix this issue fast.
    There is a tool that generates content like human, just search in google:
    miftolo’s tools

Leave a Reply

Your email address will not be published. Required fields are marked *