📄 spiceprm
字号:
#! /usr/bin/perl# spiceprm# Pass parameters to spice subcircuits.# Usage: spiceprm infile [outfile]# infile and outfile must be different.# Output written to STDOUT if outfile not given.$BANNER = "Spiceprm version 0.11, Copyright (C) 1996 Andrew J. Borsa";# NOTES:# 1. Units not recognized inside .subckt {} expressions.# 2. Perl exponent operator: "**", Spice exp op: "^".# 3. "-" as part of subckt name doesn't work but "_" does.# Netlist convention# Xname n1 n2 n3 ... ni subname {p1 = val1 ... pj = valj}# p1 thru pj are the parameters to be passed to the subcircuit.# val is any valid spice value.## .subckt name n1 n2 ... ni {p1 p2 ... pj}# parameter expressions must be enclosed in {}.# After substitution -# Xname n1 n2 n3 ... ni subname#k# *{p1 = val1 ... pj = valj}# .subckt subname#k n1 n2 n3 ... ni# ... listing with parameters substituted# .ends# %subckt: key = subname# value = startline, endline, listing(.subckt ... .ends)# Only for .subckts with parameters.# %subprm: key = subname# value = parameter name list# %subcall: key = Xname[#subname0#subname1...]# value = subname#k# NOTE: IF Xname is called from within a .subckt, it will have calling# .subckt names appended, delimited by #'s.# %sub: key = subname#k# value = p1 val1 ... pj valj, where val is a pure# numeric with no units.$MAXLEN = 70; # Max output file line length.$DMAXLEN = 10; # Amount to increment if necessary.$linenum = 0;%units = ('f','1e-15','p','1e-12','n','1e-9','u','1e-6','mil','25.4e-6', 'm','1e-3','k','1e3','meg','1e6','g','1e9','t','1e12');$* = 1; # Pattern match with multi-line strings.($infile, $outfile) = @ARGV;print "\n$BANNER\ninfile: $infile\noutfile: $outfile\n\n";$#ARGV && ($infile eq $outfile) && die "Input and Output filenames must be different\n";open(INFILE, $infile) || die "Can't open source file: $infile\n";$hasprm = $depth = 0;&prm_scan;close(INFILE);open(INFILE, $infile) || die "Can't open source file: $infile\n";unlink $outfile if $#ARGV;open(OUTFILE, $#ARGV ? ">$outfile" : ">-") || die "Can't open output file: $outfile\n";$depth = 0;&prm_wr;close(INFILE);close(OUTFILE);# Get a line from the input file, combining any continuation lines into# one long line. Skip comment and blank lines.sub prm_getline { local($line); chop($line = defined($nxtline) ? $nxtline : <INFILE>); $linenum = $.; while ($nxtline = <INFILE>) { if ($line =~ /^\*|^\s/) { $line = ''; } if ($line eq '' || $nxtline =~ s/^(\+)/ /) { chop($nxtline); $line .= $nxtline; } else { last; } } $line;}# Scan the input file looking for subcircuit calls with parameter list and# any subcircuits with defined parameters.sub prm_scan { local(@w, @tmp, @list); local($xnm, $subnm, $i, $max, $m, $s, $n, $tmp, $start); local($sublist) = ''; PRM_SCAN: while ($_ = &prm_getline) { # skip .control - .endc blocks if (/^\.control/i) { while ($_ = &prm_getline) { next PRM_SCAN if (/^\.endc/i); } } tr/A-Z/a-z/; PRM_TST: { if (/^x/ && s/(\{([^\}]+)\})//) { @w = split(' '); @tmp = @w[0 .. $#w-1]; $xnm = $w[0] . $sublist; $subnm = $w[$#w]; $_ = $2; $i = 0; while (/(\w+)\s*\=\s*([+-]?\d*(\.\d*)?([Ee][+-]?\d+)?)([a-z]\w*)?/) { # 1 2 3 4 5 $prmval{$1} = $2*($5 ? &unit2mult($5) : 1); $_ = $'; $i += 2; } $max = -1; $m = ''; CHKDUP: foreach $s (keys %sub) { $s =~ /(\w+)\#(\d+)/; if ($subnm eq $1) { if ($max < $2) { $max = $2; } $n = (@w = split(' ', $sub{$s})); if ($n == $i) { for ($i = 0; $i < $n; $i += 2) { last if $w[$i+1] ne $prmval{$w[$i]}; } if ($i >= $n) { $m = 1; $subcall{$xnm} = $s; last CHKDUP; } } } } if ($m eq '') { foreach $n (keys %prmval) { $m = join(' ', $m, $n, $prmval{$n}); } $sub{($s = join('', $subnm, '#', $max+1))} = $m; $subcall{$xnm} = $s; } push(@list, join(' ', @tmp, $subcall{$xnm})) if $depth; undef %prmval; last PRM_TST; } if (/^\.subckt\s+(\w+)/) { $depth++; $tmp = $1; $sublist .= '#' . $1; if (s/(\{([^\}]+)\})//) { if ($hasprm) { print "Line $linenum: ", "Nested parameterized subckt definitions not permitted\n\n"; } else { $hasprm = 1; $start = $.; $subprm{$psubnm = $tmp} = $2; } } push(@list, $_); # With {} parameter defs removed. last PRM_TST; } if (/^\.ends/) { $sublist =~ s/(\#\w+)$//; if (--$depth == 0) { if ($hasprm) { $subckt{$psubnm} = join("\n",join(' ',$start,$.),@list,$_); } $hasprm = 0; undef @list; $sublist = ''; last PRM_TST; }# MW. 'last PRM_TST' should be inside 'if' loop to allow nestle subckts. } if ($depth) { push(@list, $_); last PRM_TST; } } }}# Write the output file.sub prm_wr { local(@w, @pnms, @list, @line); local($xnm, $subnm, $n, $m, $i, $s); local($sublist) = ''; PRMWR_SCAN: while ($_ = &prm_getline) { # write .control - .endc blocks if (/^\.control/i) { print OUTFILE "$_\n"; while ($_ = &prm_getline) { prm_wrline($_); next PRMWR_SCAN if (/^\.endc/i); } } tr/A-Z/a-z/; if (/^x/ && s/(\{([^\}]+)\})//) { @w = split(' '); $subnm = pop(@w); $xnm = $w[0] . $sublist; prm_wrline(join(' ', @w, $subcall{$xnm})); print OUTFILE "* $1\n"; if (!defined($subprm{$subnm})) { print "Line $linenum: Subckt \"$subnm\" has no defined parameters\n\n"; next PRMWR_SCAN; } $n = @pnms = sort(split(' ', $subprm{$subnm})); $m = (@w = split(' ', $sub{$subcall{$xnm}})); if ($n == $m/2) { for ($i = 0, undef(@list); $i < $m; $i += 2) { push(@list, $w[$i]); } for ($i = 0, @w = sort(@list); $i < $n; ++$i) { if ($pnms[$i] ne $w[$i]) { print "Line $linenum: ", "Undefined parameter \"$w[$i]\"", "in subckt \"$subnm\" call\n\n"; next PRMWR_SCAN; } } } else { print "Line $linenum: ", "Incorrect number of parameters in subckt \"$subnm\" call\n\n"; } next PRMWR_SCAN; } if (/^\.subckt\s+(\w+)/) { if ($s = $subckt{$1}) { $s =~ /\d+\s+(\d+)/; $n = $1; &prm_getline until $. == $n; } else { $depth++; $sublist .= '#' . $1; prm_wrline($_); } next PRMWR_SCAN; } if (/^\.end\b/) { foreach $s (keys %sub) { ($subnm = $s) =~ s/\#\d+//; @line = split(/\n/, $subckt{$subnm}); shift(@line); $line[0] =~ s/$subnm/$s/; %prmval = split(' ', $sub{$s}); foreach (@line) { s/\{([^\}]+)\}/&prm_eval($1, %prmval)/eg; prm_wrline($_); } } print OUTFILE ".end\n"; last PRMWR_SCAN; } if (/^\.ends/) { if (--$depth == 0) { $sublist = ''; } else { $sublist =~ s/(\#\w+)$//; } } prm_wrline($_); }}# Translate a possible unit into a multiplier factor.# Parameter is the unit letter string assumed lower case.sub unit2mult { local($u) = shift; $u = ($u =~ /^(mil|meg)/ ? $1 : substr($u, 0, 1)); $u = defined($units{$u}) ? $units{$u} : 1;}# Evaluate a parameter expression.# Arguments: expression, parameter & value assoc. array.sub prm_eval { local($x,%prm) = @_; foreach $key (keys %prm) { $x =~ s/\b$key\b/$prm{$key}/eg; } eval($x . ';');}# Write an output file line with a max length. The line is split on# whitespace or '=' at a point less than or equal to the max length# and output as a spice continuation line.# If a splitting delimiter is not found within $MAXLEN, then allowable# length is increased, potentially up to the actual line length.# NOTE: outputs '\n'.# $MAXLEN sets the max value, $DMAXLEN the increment.# File handle = OUTFILE.sub prm_wrline { local($line) = shift; local($max, $s, $m); $max = $MAXLEN; until ($line eq '') { if (length($line) > $max) { $m = substr($line, 0, $max); if ($m =~ /((\s|\=)[^(\s|\=)]*)$/) { $s = $` . $2; $line = '+' . substr($line, length($s)); } else { $max += $DMAXLEN; next; } } else { $s = $line; $line = ''; } print OUTFILE "$s\n"; $max = $MAXLEN; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -