Search code examples
syntaxglobal-variablestcl

Tcl passing value of a variable


I have a procedure which reads a register from a specified address: "rd_addr $jtag_master 0x00"

I'd like to remove the "$jtag_master" input, and instead use a global variable declared at the beginning of the script, which I can then use in other procedures. The initial declaration is currently implemented through use of another procedure, "set_dev".

global device_path

# Establish the device_path as specified by "device"
proc set_dev {device} {
  set jtag_master [lindex [get_service_paths master] $device];
  set device_path $jtag_master
}

proc rd_addr {address {size 1}} {                   
  set read_data [master_read_32 $device_path $address $size];
  puts "$read_data"
}

# Init
set_dev 0
puts "jtag:         $jtag_master"; # Returns proper path
puts "device_path:  $device_path"; # Returns proper path
rd_addr 0x00

My current implementation of rd_addr returns:

error: can't read "device_path": no such variable

I've also tried implementing defaults, attempting defaults, which result in their own errors:

proc rd_addr {address {size 1} {device_path $device_path}} {
  -> error: master_read_32: Error: The given path is not valid - $device_path

proc rd_addr { {device_path $device_path} address {size 1} } { 
  -> error: wrong # args: should be "rd_addr ?device_path? address ?size?"

Thanks in advance!


Solution

  • From the global documentation:

    This command has no effect unless executed in the context of a proc body. If the global command is executed in the context of a proc body, it creates local variables linked to the corresponding global variables

    Basically, global variable_name needs to be used inside each proc that wants to refer to the global variable of that name.

    proc set_dev {device} {
      global device_path
      set jtag_master [lindex [get_service_paths master] $device];
      set device_path $jtag_master
    }
    
    proc rd_addr {address {size 1}} {
      global device_path                   
      set read_data [master_read_32 $device_path $address $size];
      puts "$read_data"
    }
    

    Without it, set_dev sets a variable local to the proc with that name, and as you've seen rd_addr can't find any variable with that name. Global variables in tcl are not visible at proc scope without this or a few other approaches (A fully qualified $::device_path for example)