1
votes

I am trying to search for a string in a large text file and return an exit code accordingly. For context, the text file is a ModelSim log file and I need to pass an exit code of 1 (bad) or 0 (good) to the Windows batch script that is calling the following TCL script (snippet):

  set sim_pass {# ** Failure: NONE. End of Test: PASS}
  set sim_fail {# ** Failure: ERRORS. End of Test: FAIL}
#  set each_line "# ** Failure: ERRORS. End of Test: FAIL\r";
  set failed_sim 0

  # Set top-level paths and testbench.
  global app_sim_path reg_tb_path parent_path log_directory msim_ini
  set TOP_LEVEL_NAME project_io_tb

  cd $app_sim_path

  # Create logfile.
  set sim_log_file ${parent_path}/${log_directory}/${TOP_LEVEL_NAME}_sim.log
  if {[file exists $sim_log_file]} {
    file delete -force $sim_log_file
  }
  set fs [open $sim_log_file {RDWR CREAT EXCL}]
  close $fs

  # Initialize ModelSim.
  puts "\[INFO\] Now testing ... $TOP_LEVEL_NAME"
  vsim -modelsimini $msim_ini -c -quiet -l $sim_log_file

  # Compile all files required for testbench.
  source compile.tcl
  # Log all signals for debug.
  log -r /*
  # Run simulation.
  run -all
  quit -sim

  # Read log file.
  set fptr [open ${sim_log_file} r]
  set log_data [read $fptr]
  close $fptr
  # Split file contents on new line.
  set line_data [split $log_data "\n"];
  # Parse each line.
  foreach each_line $line_data {
    # Check if simulation test failed.
    if {[string match $sim_fail [string trim $each_line]]} {
      set failed_sim 1
      break
    }
  }

  # Return correct exit code.
  if {$failed_sim} {
    puts "Simulation Failed, returning $failed_sim"
  } else {
      puts "Simulation Passed, returning $failed_sim"
  }
  exit -code $failed_sim
  quit -f

At least 2 things go wrong when I execute the above script:

  1. The log file is echoed to my Windows command shell w/o line breaks. This does not occur if I comment out everything after "# Read log file".
  2. The exit code is 0 even when the string appears in the log file.

What am I doing wrong?

[EDIT]: Thanks all for the responses. Unfortunately, I still can't get my TCL script to work. It may have to do with the fact that my log file contains the following text string that I'm searching for:

# ** Failure: ERRORS. End of Test: FAIL

I cannot change the first part of the text, "# ** Failure: ", as this is the syntax ModelSim uses for the log file. So the "**" may screw up the string match since I don't know how to escape it.

What I really want to do is search for the substring "ERRORS. End of Test: FAIL", which is the text I can change.

Note that I am using the string commands in a foreach loop.

I'm still getting the crazy long echo of the entire log file to my Windows command window, which is also written to the log file w/o line breaks. I'm afraid I'm not opening/closing the log file properly, so have added more to my original code snippet.

4

4 Answers

1
votes

Well, the problem with these patterns:

set sim_ok {# ** Failure: NONE. End of Test: PASS};
set sim_fail {# ** Failure: ERRORS. End of Test: FAIL};

is that for a glob pattern such as supported by string match, you've got to match the whole string, and even after splitting into lines there can be unexpected characters in there. There might be other things in there which you don't expect (e.g., colour codes) yet those end up as characters that still need matching. Also, you might have whitespace at the end of the line and ** in a glob pattern is the same as * and matches any number of any character.

Diagnosis tip

You can spot such problems by doing:

puts [exec od -c << $the_line_contents]

but you'll want to be careful about doing that, since it greatly increases the amount of output. It's a diagnostic tool that will let you see exactly what you're matching against and look for unusual characters easily as od -c converts anything not printable ASCII into an escape sequence and separates everything out, but it is not something you'd (usually) leave in production use.

Try these patterns instead:

# BTW, you don't need semicolons at the end of the line
set sim_ok {# * Failure: NONE. End of Test: PASS}
set sim_fail {# * Failure: ERRORS. End of Test: FAIL}

and do the pattern matching with:

if {[string match $sim_fail [string trim $each_line]]} {
   ...

The easiest way of dealing with coloured output (if that is a problem) is to change the TERM environment variable to something that doesn't support colour, such as vt100 or plain, before running the program that generates the output.


The exit command doesn't take a -code option. Just use a straight exit 1 to do a this-program-failed exit.

0
votes

The first problem is caused by -nonewline. Remove it.

set log_data [read $fptr]

If you leave it in, the log_data will contain no newlines and therefore split $log_data "\n" will be a list of length 1.

The is probably the -code option to the exit command. The documentation that I find indicates that it's not a supported option (no options are for exit). You may have had a return statement in there before, which does support a -code attribute. Try

exit $failed_sim
0
votes

For matching exact substrings (not regular expressions or glob patterns), [string first] is a good tool:

set sim_fail {# ** Failure: ERRORS. End of Test: FAIL};
set each_line "# ** Failure: ERRORS. End of Test: FAIL\r"   ;# trailing whitespace

if {[string match $sim_fail $each_line]} {puts matched} else {puts "not matched"}
# => not matched

if {[string first $sim_fail $each_line] != -1} {puts matched} else {puts "not matched"}
# => matched
0
votes

After some more debugging of my TCL script, I got it to work. The solutions were:

  1. Adding "quietly" in front of my file read:

    quietly set line_data [split [read -nonewline $fptr] "\n"]
    

This turns off transcript echoing from ModelSim, which is the TCL interpreter I was using.

  1. Fixing indentation and misplacement of the "break" command to the following:

    foreach each_line $line_data {
        if {[string match $sim_fail $each_line]} {
          set failed_sim 1
          break
        }
    }
    

Thanks for the help!