#
#  File: hspice_backannotate.tcl
#
#  This file is part of XSCHEM,
#  a schematic capture and Spice/Vhdl/Verilog netlisting tool for circuit
#  simulation.
#  Copyright (C) 1998-2024 Stefan Frederik Schippers
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA


proc read_hspice_log {f} {
  global current_probe voltage
  set fd [open $f]
  while {[gets $fd line] >= 0} {
    regsub -all {\r} $line {} line
    regsub {^ *\+} $line { + } line
    if [regexp {\*\*\*\*\*\*.*operating point information} $line] {
      set vnodes 1
    }
    if [regexp {\*\*\*\*.*voltage sources} $line] {
      set vnodes 0
      set vsources 1
    }
    if [regexp {total voltage source power} $line] {
      set vsources 0
    }
    if { [lindex $line 0] == {element}  && $vsources } {
      set  vsource_name $line
    }
    if { [lindex $line 0] == {current}  && $vsources } {
      for {set i 1} {$i < [llength $line]} { incr i } {
        set vsource [lindex $vsource_name $i]
        set current [lindex $line $i]
        if {[regexp {^0:} $vsource]} {
          if {[regsub {^.*:} $vsource {} vsource]} {
            set current_probe($vsource) $current
            puts "$vsource --> $current"
          }
        }
      }
    }
    if { [lindex $line 0] == {+} && $vnodes} {
      regsub -all {=} $line { = } line
      for { set i 1} {$i < [llength $line]} { set i [expr $i+3]} {
        set node [lindex $line $i]
        set volt [lindex $line [expr $i+2]]
        if {[regsub {^0:} $node {} node]} {
          set voltage($node) $volt
          puts "$node --> $volt"
        }
      }
    }
  }
  close $fd
}

proc get_voltage { n } {
  global voltage
  if { abs($voltage([string tolower $n])) < 1e-3 } {
    return [format %.4e $voltage([string tolower $n])]
  } else {
    return [format %.4g $voltage([string tolower $n])]
  }
  # return DELETE
}

proc get_diff_voltage { p m } {
  global voltage
  return [format %.4e [expr $voltage([string tolower $p]) - $voltage([string tolower $m]) ] ]
  # return DELETE
}

proc get_current { n } {
  global current_probe
  if {abs($current_probe([string tolower $n])) <1e-3} {
    return [format %.4e $current_probe([string tolower $n])]
  } else {
    return [format %.4g $current_probe([string tolower $n])]
  }
  # return DELETE
}


proc annotate {} {
  ### disable screen redraw and undo when looping to speed up performance
  ### but save state on undo stack before doing backannotations.
  xschem push_undo
  xschem set no_undo 1
  xschem set no_draw 1

  read_hspice_log $::netlist_dir/hspice.out
  set lastinst [xschem get instances]
  for { set i 0 } { $i < $lastinst } {incr i } {
    set name [xschem getprop instance $i name]
    set type [xschem getprop instance $i cell::type]
    if { $type == "probe"} {
      set net [xschem instance_net $i p]
      if {[catch {xschem setprop -fast instance $i voltage [get_voltage $net]} err]} {
        puts "1 error : $err net: $net"
      }
    }
    if { $type == "current_probe"} {
      if {[catch {xschem setprop -fast instance $i current [get_current $name]} err]} {
        puts "2 error : $err"
      }
    }
    if { $type == "differential_probe"} {
      set netp [xschem instance_net $i p]
      set netm [xschem instance_net $i m]
      if {[catch {xschem setprop -fast instance $i voltage [get_diff_voltage $netp $netm]} err]} {
        puts "3 error : $err"
      }
    }
    # puts "$i $name $type"
  }

  # re-enable undo and draw
  xschem set no_undo 0
  xschem set no_draw 0
  xschem redraw

  ### xschem setprop instructions have not altered circuit topology so
  ### in this case a connectivity rebuild is not needed.
  # xschem rebuild_connectivity
  #
  #
}
