tcl text processing - rearrange values in rows and columns based on user defined value

后端 未结 3 765
予麋鹿
予麋鹿 2020-12-17 08:27

I am new to tcl and would like to use it in text processing of a simple case. The following format is in Liberty (.lib file) which is used in chip design. I would be truly i

相关标签:
3条回答
  • 2020-12-17 08:35

    The first step is to know how to represent the data in tcl in its final form. This is just one possible solution.

    dict set risedata constraints { 
      constraint {
        0.084 { 0 { 0 1.1 1  6.1 2 11.1 3 16.1 4 21.1 }
                1 { 0 2.1 1  7.1 2 12.1 3 17.1 4 22.1 }
                2 { 0 3.1 1  8.1 2 13.1 3 18.1 4 23.1 }
                3 { 0 4.1 1  9.1 2 14.1 3 19.1 4 24.1 }
                4 { 0 5.1 1 10.1 2 15.1 3 20.1 4 25.1 }
        }
      }
      indexes { 1 { 0.01 0.05 0.12 0.2 0.4 }
                2 { 0.005 0.025 0.06 0.1 0.3 }
                3 { 0.084 0.84 3.36 8.4 13.44 } }
    }
    
    set c 0.084
    puts "$c 2 3: [dict get $risedata constraints constraint $c 2 3]"
    puts "idx1 3: [lindex [dict get $risedata constraints indexes 1] 3]"
    puts "idx2 3: [lindex [dict get $risedata constraints indexes 2] 3]"
    

    Then knowing where you need to be, loading the .lib is just a straightforward parsing problem:

    set fh [open z.lib r]
    set inval false
    while { [gets $fh line] >= 0 } {
      if { [regexp {\);} $line] } {
        set inval false
      }
      if { [regexp {index_(\d+)} $line all idx] } {
        regsub {^[^"]*"} $line {} d
        regsub {".*} $d {} d
        regsub -all {,} $d {} d
        dict set risedata constraints indexes $idx $d
      }
      if { $inval } {
        regsub {^[^"]*"} $line {} d
        regsub {".*} $d {} d
        regsub -all {[ ,]+} $d { } d
        set row [expr {$rcount % 5}]
        set column [expr {$rcount / 5}]
        set i 0
        foreach {v} [split $d { }] {
          set c [lindex [dict get $risedata constraints indexes 3] $i]
          dict set risedata constraints constraint $c $row $column $v
          incr i
        }
        incr rcount
      }
      if { [regexp {values} $line] } {
        set inval true
        set row 0
        set rcount 0
      }
    }
    close $fh
    
    puts $risedata
    set c 0.084
    puts "$c 2 3: [dict get $risedata constraints constraint $c 2 3]"
    puts "idx1 3: [lindex [dict get $risedata constraints indexes 1] 3]"
    puts "idx2 3: [lindex [dict get $risedata constraints indexes 2] 3]"
    
    0 讨论(0)
  • 2020-12-17 08:39

    This is STF (Synopsys Technology File) or simple known as [dot]lib liberty

    I did work on these files on TCL platform but by use of some Parsers.

    although many parser are available here is one for you.

    I suggest to use parsers for handling [dot]lib as many times the file formate gets corrupt and is unable to read by primetime or other lib tool.

    liberty_parser

    there is another one available in C language too .. google vlsicad ucsd edu + liberty parser

    0 讨论(0)
  • 2020-12-17 08:55

    I finally got really interested in this, and against my better judgement coded up a complete answer. I'm not going to document it in any way. Read it, read the docs for commands you don't understand, then come and ask questions.

    Looking at your liberty file, I see it's very close to native Tcl syntax. So you can create a few procedures named "timing", "rise_constraint", etc, and you can basically run it as a script.

    package require struct::list
    
    ######################################################################
    proc main {libfile} {
        global lines idx3 vals
        set lines [list]
        set idx3 [list]
        set vals [list]
    
        evaluate_liberty $libfile
    
        set idx [get_choice "select an index_3 value: " $idx3]
        set column [struct::list mapfor elem $vals {lindex $elem $idx}]
    
        set newvalues [list]
        for {set i 0} {$i < 5} {incr i} {
            lappend newvalues [lrange $column [expr {5*$i}] [expr {5*($i+1)-1}]]
        }
    
        print_liberty $newvalues
    }
    
    ######################################################################
    proc evaluate_liberty {libfile} {
        set fh [open $libfile r]
        # handle known syntax error in liberty file
        set contents [string map {\", \"} [read -nonewline $fh]]
        regsub -all -line {\s+$} $contents {} contents
        close $fh
    
        uplevel #0 $contents
    }
    
    proc get_choice {prompt values} {
        while {1} {
            for {set i 0} {$i < [llength $values]} {incr i} {
                puts stderr [format "%2d. %s" $i [lindex $values $i]]
            }
            puts -nonewline stderr $prompt
            gets stdin answer
            if {[string is integer -strict $answer]} {
                if {0 <= $answer && $answer < [llength $values]} {
                    return $answer
                }
            }
        }
    }
    
    proc print_liberty {newvalues} {
        global lines close_braces
        puts [join $lines \n]
    
        puts "values ( \\"
        foreach elem $newvalues {
            puts [format "\"%s\", \\" [join $elem {, }]]
        }
        puts ");"
    
        for {set i 1} {$i <= $close_braces} {incr i} {
            puts [format %c 125]
        }
    }
    
    ######################################################################
    # define DSL
    proc timing {label script} {
        lappend ::lines [format "timing %s %c" $label 123]
        incr ::close_braces
        uplevel 1 $script
    }
    
    proc rise_constraint {label script} {
        lappend ::lines [format "rise_constraint %s %c" $label 123]
        incr ::close_braces
        uplevel 1 $script
    }
    
    proc index_3 {args} {
        global idx3
        foreach item $args {
            lappend idx3 [string map {( "" \" "" , "" ) ""} $item]
        }
    }
    
    proc values {args} {
        global vals
        foreach set [lrange $args 1 end-1] {
            lappend vals [split [regsub -all {\s*,\s*} $set { }]]
        }
    }
    
    rename unknown system_unknown
    
    proc unknown args {
        lappend ::lines "[join $args];"
    }
    
    ######################################################################
    if {$argc == 0} {
        puts "usage: $argv0 filename.lib"
        exit
    }
    
    set libfile [lindex $argv 0]
    if {![file exists $libfile]} {
        error "no such file: $libfile"
    }
    
    main $libfile
    

    Running it:

    $ tclsh liberty.tcl test.lib  > newlib.lib
     0. 0.084
     1. 0.84
     2. 3.36
     3. 8.4
     4. 13.44
    select an index_3 value: 0
    
    $ cat newlib.lib 
    timing () {
    related_pin : clk;
    timing_type : setup_rising;
    rise_constraint (constraint_template_5X5) {
    index_1 ("0.01, 0.05, 0.12, 0.2, 0.4");
    index_2 ("0.005, 0.025, 0.06, 0.1, 0.3");
    values ( \
    "1.1, 2.1, 3.1, 4.1, 5.1", \
    "6.1, 7.1, 8.1, 9.1, 10.1", \
    "11.1, 12.1, 13.1, 14.1, 15.1", \
    "16.1, 17.1, 18.1, 19.1, 20.1", \
    "21.1, 22.1, 23.1, 24.1, 25.1", \
    );
    }
    }
    

    You do lose all your nice indentation, but you get the values you want.

    0 讨论(0)
提交回复
热议问题