#!/usr/local/bin/perl
# 
# modedit - automaticly make the edits we need to HP-BSIM2 mosfet models
#
# This version converts HP-BSIM2 models to HSPICE format
#
# $Log: modedit_hspice,v $
# Revision 1.5  1995/06/27 14:02:01  tell
# Inserted jp's revised nwell-resistor models: changed dw, added dlr
#
# Revision 1.4  1995/06/27  13:50:42  tell
# copied back from /usr/msl/vlsi/bin because revs 1.4, 1.5, and 1.6 lost
# in disk crash.
# # Revision 1.6  1995/05/18  19:22:44  tell
# # in nwell resistor stuff, changed dw=.33 - per edge, not total
# #
# # Revision 1.5  1995/05/18  18:53:44  tell
# # fixed - nwellres option not required
# #
# # Revision 1.4  1995/05/18  18:51:15  tell
# # changed to omit models besides nfet/pfet and subcircuits
# # added code to insert n well resistor models
#
# Revision 1.6  1995/05/18  19:22:44  tell
# in nwell resistor stuff, changed dw=.33 - per edge, not total
#
# Revision 1.5  1995/05/18  18:53:44  tell
# fixed - nwellres option not required
#
# Revision 1.4  1995/05/18  18:51:15  tell
# changed to omit models besides nfet/pfet and subcircuits
# added code to insert n well resistor models
#
# Revision 1.3  1995/05/03  14:52:34  tell
# changed to delete .param statements
#
# Revision 1.2  1995/05/03  14:49:21  tell
# now passes non-mosfet models through unchanged
# passes .PARAM statements through unchaged
# passes subcircuits through unchanged
#
# Revision 1.1  1994/11/23  18:30:28  tell
# Initial revision
#
#

$RSDWdiv=1.0e-6;  # what to divide RSDW by to get RS and RD
$LD=0.0;
$CGBO=0.0;

$no_resistors = 0;	# set to 1 to defeat parasitic resistors
$no_overlapcap = 0;	# set to 1 to zero-out overlap capacitances
$no_diodecap = 0;	# set to 1 to zero out parasitic diode capacitance
$no_namemap = 0;	# default: change model names to nfet/pfet. 1 leaves.
$process = 'hpcmos14';

# these parameters will be deleted.
@param_omit=('TCR', 'RSDW', 'LEVEL',
	'DLAC', 'DWAC',
	'TCVI',  'LTCVI', 'WTCVI',
	'UTEXP', 'LUTEXP', 'WUTEXP',
	'ETEXP', 'LETEXP', 'WETEXP',
	'CGSO',  'CGDO', 'CGBO',
	'CJ', 'CJSW',
	);

while($ARGV[0] =~ /^-/) {
	$option = shift(@ARGV);
	
	if($option eq '-nores') {
		$no_resistors = 1;
	} elsif($option eq '-novcap') {
		$no_overlapcap = 1;
	} elsif($option eq '-nodiodecap') {
		$no_diodecap = 1;
	} elsif($option eq '-noacdelta') {
		# accepted but ignored for modedit compatibility
	} elsif($option eq '-nonamemap') {
		$no_namemap = 1;
	} elsif($option eq '-process') {
		$process = shift(@ARGV);
	} elsif($option eq '-nwellres') {
		$nwellres = shift(@ARGV);
	} else {
		print STDERR "Unknown option: $option\n";
	}
}

if($process ne 'hpcmos14' && $process ne 'hpcmos26') {
	print STDERR "-process: must be either hpcmos14 or hpcmos26\n";
	exit 1;
}

if($#ARGV != 1) {
	print STDERR "usage: modedit slow|nom|fast file\n";
	exit 1;
}

$case = $ARGV[0];
if($case ne 'slow' && $case ne 'fast' && $case ne 'nom') {
	print STDERR "case must be one of slow, nom, or fast\n";
	exit 1;
}

if(defined($nwellres) && $nwellres ne 'best' && $nwellres ne 'worst' && $nwellres ne 'nominal') {
	print STDERR "N-well resistor model must be one of best, worst, or nominal.\n";
	exit 1;
}

$infile = $ARGV[1];

#
# These parameters have to do with the resistance of diffusion interconnect
# when contacts are not placed right next to transistors.
# They are not found in the model files, but in the HP fab documents.
# XW is width correction factor, listed as Wc in some of the documents.
#
#
# For HPCMOS14, they come from the "CMOS14TA Design Reference Manual,"
# chapter 3, "Interconnect characteristics,", page 57-59.
# RSH, N/P-island sheet resistance, comes from table 3-1 and 3-3
# XW, N/P-island width correction factor, comes from table 3-2 and 3-4
# TCR, temperature coeficient of resistance for RSH, comes from the text of
# sections 3.1.1.1 and 3.1.1.2.    The parameters are the same for N and P
# transistors; this code will have to be changed if that is not true for some
# process.

if($process eq 'hpcmos14') {
	$TCR=0.0042;
	if($case eq "slow") {
		$XW=-0.15e-6;
		$RSH=5.0;
	} elsif($case eq "nom") {
		$XW=0.07e-6;
		$RSH=2.5;
	} elsif($case eq "fast") {
		$XW=0.15e-6;
		$RSH=1.0;
	} else {
		print STDERR "no case $case\n";
		exit(1);
	}
#
# For HPCMOS26, these come from "CMOS26 Design Rules, Rev C, Page 75"
#

} elsif($process eq 'hpcmos26') {
	$TCR=0.0042;
	if($case eq "slow") {
		$XW=-0.34e-6;
		$RSH=5.0;
	} elsif($case eq "nom") {
		$XW=-0.20e-6;
		$RSH=3.0;
	} elsif($case eq "fast") {
		$XW=-0.06e-6;
		$RSH=2.0;
	} else {
		print STDERR "no case $case\n";
		exit(1);
	}
} else {
	print STDERR "no process\n";
	exit(1);
}



foreach $par (@param_omit) {
	$param_omit{$par} = 1;
}

open($infile, $infile) || die "can't open $infile\n";

print "* processed by modedit $case\n";

if($no_resistors == 1) {
	printf STDERR "Models will have source and drain resistors forced to 0\n";
	print "*** Devices have source and drain resistors forced to 0\n";
	$LDIF=0;
	$HDIF=0;
} else {
	$LDIF=1.0e-6;
	$HDIF=1.0e-6;
}
if($no_overlapcap == 1) {
	print STDERR "Models will have overlap capacitances forced to 0\n";
	print "*** Devices have overlap capacitances forced to 0\n";
}
if($no_diodecap == 1) {
	print STDERR "Models will have parasitic diode capacitances forced to 0\n";
	print "*** Devices have parasitic diode capacitances forced to 0\n";
}


$lineno = 0;
$nmod = 0;
$nomod = 0;
$nsubckt = 0;
$nparam = 0;
line: while($_ = <$infile> ) {

top:

	$lineno++;
	if($_ =~ /^\*/) {
		print $_;
	} elsif($_ =~ /^\s*$/) {
		print $_;
	} elsif($_ =~ /^\.model\s+[A-Za-z0-9\.]+\s+(n|p)mos/) {
		($dotmod, $modname, $type) = split(/[ \t\n]+/, $_);
		$nmod++;
		$nparline=0;
		if($no_namemap == 0) {
			$modname =~ s/^N\.(\S)/nfet.$1/;
			$modname =~ s/^P\.(\S)/pfet.$1/;
			$modname =~ s/^NENH\.(\S)/nfet.$1/;
			$modname =~ s/^PENH\.(\S)/pfet.$1/;
		}

		print ".model $modname $type\n";
		print "+ LEVEL=39\n";
		print "+ CAPOP=39\n";
		print "+ SPICE3=1\n";
		print "+ ACM=2\n";

		cont: while($_ = <$infile> ) {
			# this counts on the fact that the line after
			# the last continuation line is a comment-line in
			# the model files
			if($_ !~ /^\+/) {
				last cont;
			}
			#print $_;
			$nparline++;

			$_ =~ s/^\+\s*//;
			@params = split(/[ \t\n]+/, $_);
			@outpars=();
			foreach $par (@params) {
				($parname, $parval) = split(/[=]/, $par);
				if($parname eq 'WMAX' && $parval > 10e-3) {
					$parval = 1e3;
				}
				if($parname eq 'LMAX' && $parval > 10e-3) {
					$parval = 1e3;
				}
				$params{$parname} = $parval;
				if($param_omit{$parname} != 1) {
					push(@outpars, "$parname=$parval");
				}
			}
			if($#outpars >= 0) {
				print "+ ", join("\t", @outpars), "\n";
			}
		}
		# we now have all of the parameters for this model.
		# they've already been printed out, but we can insert
		# new ones here, and add on constant ones
		if($no_diodecap) {
			print "+ CJ=0.0\n";
			print "+ CJSW=0.0\n";
		} else {
			printf "+ CJ=%g\n", $params{'CJ'};
			printf "+ CJSW=%g\n", $params{'CJSW'};
		}
		if($no_overlapcap) {
			print "+ CGSO=0.0\n";
			print "+ CGDO=0.0\n";
		} else {
			printf "+ CGSO=%g\n", $params{'CGSO'};
			printf "+ CGDO=%g\n", $params{'CGDO'};
		}
		printf "+ CGBO=%g\n", $CGBO;
		printf "+ TCV=%g\n", $params{'TCVI'};
		printf "+ FEX=%g\tLFEX=%g\tWFEX=%g\n",
			$params{'ETEXP'}, $params{'LETEXP'}, $params{'WETEXP'};
		printf "+ BEX=%g\tLBEX=%g\tWBEX=%g\n",
			$params{'UTEXP'}, $params{'LUTEXP'}, $params{'WUTEXP'};
		
		printf "+ LDIF=%g\tLD=%g\n", $LDIF, $LD;
		printf "+ HDIF=%g\n", $HDIF;
		printf "+ XW=%g\tRSH=%g\n", $XW, $RSH;
		$rs = $params{'RSDW'}/$RSDWdiv;
		printf "+ RS=%g\tRD=%g\n", $rs, $rs;

		print "*\n";
	
	} elsif($_ =~ /^\.model/) {
		# models besides nmos and pmos:
		# delete because they're probably not compatible
		$nomod++;
		chop($_);
		#print "$_\n";
		#print "* ($_ omitted)\n";
		cont: while($_ = <$infile> ) {
			if($_ !~ /^\+/) {
				if($_ !~ /^\*/) {  # if not comment, handle it
					goto top;
				}
				print $_;
				last cont;
			}
			#print $_;
			$nparline++;
		}

	} elsif($_ =~ /^\.subckt/) { # subcircuits - delete
		$nsubckt++;
		chop($_);
		#print "$_\n";
		#print "* ($_ omitted)\n";
		cont: while($_ = <$infile> ) {
			#print $_;	
			last cont if($_ =~ /^\.ends/);
			$nparline++;
		}
	} elsif($_ =~ /^\.PARAM/) {
		$nparam++;
		# .param statement: skip over them
		# may have continuation lines
		$nparam++;
		#print $_;
		cont: while($_ = <$infile> ) {
			# this counts on the fact that the line after
			# the last continuation line is a comment-line in
			# the model files
			if($_ !~ /^\+/) {
				if($_ !~ /^\*/) {  # if not comment
					goto top;
				}
				print $_;
				last cont;
			}
			$nparline++;
			#print $_;
		}
	} else {
		print STDERR "Unknown line at $lineno: $_";
		exit 1;
	}
}

if($nwellres eq 'worst') {
	print STDERR "Adding worst-case nwell model\n";
	print <<EOF;

************************************
* Worst-case nwell model for hspice by JP
* initial resistance = 950 ohms/sq
* width correction = 0.66u
* resistance width correction = 1.2u - 0.66u = 0.54u
* resistance length correction = -0.2u
* temperature coefficient = 0.80 %/C
************************************

.model nwellmodel R bulk=GND cox=2.18e-4 dw=-0.27u dlr=0.1u rsh=950 tc1r=0.008

EOF
} elsif($nwellres eq 'best') {
	print STDERR "Adding best-case nwell model\n";
	print <<EOF;

************************************
* Best-case nwell model for hspice by JP
* initial resistance = 511 ohms/sq
* width correction = 0.66u
* temperature coefficient = 0.80 %/C
************************************

.model nwellmodel R bulk=GND cox=1.87e-4 dw=-0.27u dlr=0.1u rsh=511 tc1r=0.008
EOF
} elsif($nwellres eq 'nominal') {
	print STDERR "Adding nominal-case nwell model\n";
	print <<EOF;

************************************
* Nominal-case nwell model for hspice by JP
* initial resistance = 750 ohms/sq
* width correction = 0.66u
* temperature coefficient = 0.80 %/C
************************************

.model nwellmodel R bulk=GND cox=2.08e-4 dw=-0.27u dlr=0.1u rsh=750 tc1r=0.008
EOF
}

print STDERR "$nmod MOS models processed.\n";
print STDERR "$nomod other models and $nsubckt subcircuits deleted.\n";
print STDERR "$nparam .PARAM statements deleted.\n";
exit 0;
######################################################################
