OpenSTA/spice/WriteSpice.tcl

288 lines
8.7 KiB
Tcl
Raw Normal View History

# OpenSTA, Static Timing Analyzer
# Copyright (c) 2025, Parallax Software, Inc.
#
# 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 3 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, see <https://www.gnu.org/licenses/>.
#
# The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software.
#
# Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
#
# This notice may not be removed or altered from any source distribution.
namespace eval sta {
define_cmd_args "write_path_spice" { -path_args path_args\
-spice_directory spice_directory\
-lib_subckt_file lib_subckts_file\
-model_file model_file\
-power power\
-ground ground\
[-simulator hspice|ngspice|xyce]}
proc write_path_spice { args } {
parse_key_args "write_path_spice" args \
keys {-spice_directory -lib_subckt_file -model_file \
-power -ground -path_args -simulator} \
flags {}
if { [info exists keys(-spice_directory)] } {
set spice_dir [file nativename $keys(-spice_directory)]
if { ![file exists $spice_dir] } {
sta_error 1920 "Directory $spice_dir not found."
}
if { ![file isdirectory $spice_dir] } {
sta_error 1921 "$spice_dir is not a directory."
}
if { ![file writable $spice_dir] } {
sta_error 1922 "Cannot write in $spice_dir."
}
} else {
sta_error 1923 "No -spice_directory specified."
}
if { [info exists keys(-lib_subckt_file)] } {
set lib_subckt_file [file nativename $keys(-lib_subckt_file)]
if { ![file readable $lib_subckt_file] } {
sta_error 1924 "-lib_subckt_file $lib_subckt_file is not readable."
}
} else {
sta_error 1925 "No -lib_subckt_file specified."
}
if { [info exists keys(-model_file)] } {
set model_file [file nativename $keys(-model_file)]
if { ![file readable $model_file] } {
sta_error 1926 "-model_file $model_file is not readable."
}
} else {
sta_error 1927 "No -model_file specified."
}
if { [info exists keys(-power)] } {
set power $keys(-power)
} else {
sta_error 1928 "No -power specified."
}
if { [info exists keys(-ground)] } {
set ground $keys(-ground)
} else {
sta_error 1929 "No -ground specified."
}
set ckt_sim [parse_ckt_sim_key keys]
if { ![info exists keys(-path_args)] } {
sta_error 1930 "No -path_args specified."
}
set path_args $keys(-path_args)
set path_ends [eval [concat find_timing_paths $path_args]]
if { $path_ends == {} } {
sta_error 1931 "No paths found for -path_args $path_args."
} else {
set path_index 1
foreach path_end $path_ends {
set path [$path_end path]
set path_name "path_$path_index"
set spice_file [file join $spice_dir "$path_name.sp"]
set subckt_file [file join $spice_dir "$path_name.subckt"]
write_path_spice_cmd $path $spice_file $subckt_file \
$lib_subckt_file $model_file $power $ground $ckt_sim
incr path_index
}
}
}
set ::ckt_sims {hspice ngspice xyce}
proc parse_ckt_sim_key { keys_var } {
upvar 1 $keys_var keys
global ckt_sims
set ckt_sim "ngspice"
if { [info exists keys(-simulator)] } {
set ckt_sim [file nativename $keys(-simulator)]
if { [lsearch $ckt_sims $ckt_sim] == -1 } {
sta_error 1910 "Unknown circuit simulator"
}
}
return $ckt_sim
}
################################################################
define_cmd_args "write_gate_spice" \
{ -gates {{instance input_port driver_port edge [delay]}...}\
-spice_filename spice_filename\
-lib_subckt_file lib_subckts_file\
-model_file model_file\
-power power\
-ground ground\
[-simulator hspice|ngspice|xyce]\
[-corner corner]\
[-min] [-max]}
proc write_gate_spice { args } {
parse_key_args "write_gate_spice" args \
keys {-gates -spice_filename -lib_subckt_file -model_file \
-power -ground -simulator -corner}\
flags {-measure_stmts -min -max}
if { [info exists keys(-gates)] } {
set gates $keys(-gates)
} else {
sta_error 1932 "Missing -gates argument."
}
if { [info exists keys(-spice_filename)] } {
set spice_file [file nativename $keys(-spice_filename)]
set spice_dir [file dirname $spice_file]
if { ![file writable $spice_dir] } {
sta_error 1903 "Cannot write $spice_dir."
}
} else {
sta_error 1904 "No -spice_filename specified."
}
if { [info exists keys(-lib_subckt_file)] } {
set lib_subckt_file [file nativename $keys(-lib_subckt_file)]
if { ![file readable $lib_subckt_file] } {
sta_error 1905 "-lib_subckt_file $lib_subckt_file is not readable."
}
} else {
sta_error 1906 "No -lib_subckt_file specified."
}
if { [info exists keys(-model_file)] } {
set model_file [file nativename $keys(-model_file)]
if { ![file readable $model_file] } {
sta_error 1907 "-model_file $model_file is not readable."
}
} else {
sta_error 1908 "No -model_file specified."
}
if { [info exists keys(-power)] } {
set power $keys(-power)
} else {
sta_error 1909 "No -power specified."
}
if { [info exists keys(-ground)] } {
set ground $keys(-ground)
} else {
sta_error 1915 "No -ground specified."
}
set ckt_sim [parse_ckt_sim_key keys]
set corner [parse_corner keys]
set min_max [parse_min_max_flags flags]
check_argc_eq0 "write_gate_spice" $args
set spice_dir [file dirname $spice_file]
set spice_root [file rootname [file tail $spice_file]]
set subckt_file [file join $spice_dir "$spice_root.subckt"]
write_gate_spice_cmd $gates $spice_file $subckt_file \
$lib_subckt_file $model_file $power $ground $ckt_sim \
$corner $min_max
}
################################################################
# plot_pins defaults to input_pin, driver_pina and load pins for each driver.
define_cmd_args "write_gate_gnuplot" \
{ -gates {{instance input_port driver_port edge [delay]}...}\
-plot_pins plot_pins\
-plot_basename plot_basename\
[-corner corner] [-min] [-max]}
proc write_gate_gnuplot { args } {
parse_key_args "write_gate_gnuplot" args \
keys {-gates -plot_pins -plot_basename -spice_waveforms -corner} \
flags {-min -max}
if { [info exists keys(-gates)] } {
set gates $keys(-gates)
} else {
sta_error 1933 "Missing -gates argument."
}
if { [info exists keys(-plot_pins)] } {
set plot_pins [get_port_pins_error "-plot_pins" $keys(-plot_pins)]
} else {
set plot_pins {}
set plot_all_loads 0
set gate_idx 0
foreach gate $gates {
set in_pin [parse_gate_in_pin $gate]
set drvr_pin [parse_gate_drvr_pin $gate]
lappend plot_pins $in_pin
lappend plot_pins $drvr_pin
# Only plot driver loads.
if { $plot_all_loads || $gate_idx == 0 } {
set pin_iter [$drvr_pin connected_pin_iterator]
while { [$pin_iter has_next] } {
set pin [$pin_iter next]
if { [$pin is_load] } {
lappend plot_pins $pin
}
}
$pin_iter finish
}
incr gate_idx
}
}
if { [info exists keys(-plot_basename)] } {
set plot_base [file nativename $keys(-plot_basename)]
set plot_dir [file dirname $plot_base]
if { ![file writable $plot_dir] } {
sta_error 1913 "Cannot write $plot_dir."
}
} else {
sta_error 1914 "No -plot_basename specified."
}
set gnuplot_filename "${plot_base}.gnuplot"
set csv_filename "${plot_base}.csv"
set sim_wave_filename ""
if { [info exists keys(-spice_waveforms)] } {
set sim_wave_filename $keys(-spice_waveforms)
}
set corner [parse_corner keys]
set min_max [parse_min_max_flags flags]
write_gate_gnuplot_cmd $gates $plot_pins $sim_wave_filename \
$gnuplot_filename $csv_filename $corner $min_max
}
proc parse_gate_drvr_pin { gate_arg } {
lassign $gate_arg inst_name in_port_name in_rf drvr_port_name drvr_rf
set inst [get_instance_error "instance" $inst_name]
set drvr_pin [$inst find_pin $drvr_port_name]
return $drvr_pin
}
proc parse_gate_in_pin { gate_arg } {
lassign $gate_arg inst_name in_port_name in_rf drvr_port_name drvr_rf
set inst [get_instance_error "instance" $inst_name]
set in_pin [$inst find_pin $in_port_name]
return $in_pin
}
# sta namespace end.
}