commit 978f1c32a28c21f80a82ad9474aa90b77d936543 Author: pnenzi Date: Thu Apr 27 20:03:57 2000 +0000 Initial revision diff --git a/ANALYSES b/ANALYSES new file mode 100644 index 000000000..3abec19fd --- /dev/null +++ b/ANALYSES @@ -0,0 +1 @@ +This file will contain a list of implemented analyses. diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..de7f02b21 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,39 @@ +SPICE was originally written at The University of Berkeley (USA). + + +Contributors: +------------- + +Giles C. Billingsley +Mansun Chan +Wayne A. Christopher +Noah Friedman +David A. Gates +JianHui Huang +Jeffrey M. Hsu +S. Hwang +Gordon M. Jacobs +Min-Chie Jeng +Kenneth H. Keller +Mathew Lew +Weidong Liu +Gary W. Ng +Hong June Park +Thomas L. Quarles +Jaijeet S. Roychowdhury +Takayasu Sakurai +Kanwar Jit Singh +Andrew Tuckey + +NGSPICE is now actively hacked by: + + * Glao S. Dezai + * Daniele Foci + * Chris Inbody + * Paolo Nenzi + * Arno Peters + * Serban-Mihai Popescu + * Emmanuel Rouat + * Michael Widlok + +(and many others...) diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..958be0ded --- /dev/null +++ b/COPYING @@ -0,0 +1,31 @@ + +(The original copyright for Spice3f5.) + + +Copyright (C) 1996 The Regents of the University of California. +All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research and non-profit purposes, +without fee, and without a written agreement is hereby granted, +provided that the above copyright notice, this paragraph and the +following three paragraphs appear in all copies. + +This software program and documentation are copyrighted by The Regents +of the University of California. The software program and +documentation are supplied "as is", without any accompanying services +from The Regents. The Regents does not warrant that the operation of +the program will be uninterrupted or error-free. The end-user +understands that the program was developed for research purposes and +is advised not to rely exclusively on the program for any reason. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND +ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF +CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..95cc12a0b --- /dev/null +++ b/ChangeLog @@ -0,0 +1,107 @@ +1999-12-07 Arno Peters + + * source tree: Added MAINTAINERCLEANFILES to Makefile.am to + eliminate automatically generated cruft from patches. To create a + minimal patch between two trees, just do `make maintainer-clean' + on both trees and run `diff -ruN tree1 tree2'. + +1999-10-15 Emmanuel Rouat + + * source tree: entirely modified by Arno Peters (after discussion + on the mailing list) + +1999-09-06 Emmanuel Rouat + + * AUTHORS: added list provided by Arno Peters + + * Applied patch supplied by Arno + +1999-09-01 Emmanuel Rouat + + * AUTHORS: some additions + + * FAQ: a few minor corrections + +1999-08-31 Emmanuel Rouat + + * configure.in: config.h now in top directory + + * All Makefile.am's: removed useless 'DEFS' line + +1999-08-30 Emmanuel Rouat + + * FAQ: added the FAQ to the distribution + +1999-08-28 Emmanuel Rouat + + * Removed mfb from build - nutmeg doesn't use it on Unix. + +1999-08-23 Emmanuel Rouat + + * configure.in: added tests ('make check') + + * ng-spice.patch: added cleanup patch by Arno Peters + +1999-08-08 Emmanuel Rouat + + * configure.in: added some features + +1999-08-03 Emmanuel Rouat + + * configure.in: added a whole bunch of tests! + +1999-08-02 Emmanuel Rouat + + * configure.in: added --with-checkergcc option (experimental!) + added some maths checks + +1999-07-31 Emmanuel Rouat + + * configure.in: made X11 tests more efficient + + +ng-spice-0.0: +------------- + * changed HAX_X11 define to XMISSING_DISPLAY supplied in config.h + + * added 'Changelog' files in all subdirectories + + * added '--enable-ansi' option to configure + + * put src/lib/dev/devsup.c into src/lib/dev/devsup/ + + * added header files into Makefile.am's + +Chianti: +-------- + (27/07/99) + + * added some tests to configure.in (ncurses/termcap, xaw....) + + * cleaned up some directories (examples, patches..) + + * removed all .orig files + +Pizza: +------ + (25/07/99) + + * added installation of man pages + + * emptied 'COPYING' file until we know what to put in it + + * fixed missing install of help and init files (created tune.c.in + to support this) + + * added missing -DWANT_X11 and -DWANT_MFB in several compiles + (fixed some headers in: src/lib/fte/x11.c + src/lib/fte/x11disp.c ) + + +Spaghetti: +---------- + (25/07/99) + + - first attempt at autoconf/automake support + + - based on spice3f5-chili, hardly anything touched on it. diff --git a/DEVICES b/DEVICES new file mode 100644 index 000000000..b2f85b3b8 --- /dev/null +++ b/DEVICES @@ -0,0 +1,167 @@ +DEVICES +------------------------------------------------------------------------------- + +This file contains the status of devices available in ng-spice. This file will +be updated every time the device cospecific code is altered/changed. + + + ************************************** + ********** Linear devices ********** + ************************************** + +CAP - Capacitor + Initial Release + +IND - Inductor + Initial Release + +RES - Resistor + This is a modified version of the spice3 resistance model. This model + supports different ac and dc values (ac=...). This changes are + introduced by Serban Popescu. This device needs more testing. + TO BE TESTED AND IMPROVED. + + + ************************************** + ******** Distributed elements ******** + ************************************** + +TRA - Transmission line + Initial release + +LTRA - Lossy Transmission line + Initial release + +URC - Uniform distributed RC line + Initial release + + + ************************************** + ********** V/I Sources ********** + ************************************** + + ASRC - Arbitrary Source + Initial Release + + CCCS - Current Controlled Current Source + Initial Release + + CCVS - Current Controlled Voltage Source + Initial Release + + ISRC - Independent Current Source + Initial Release + + VCCS - Voltage Controlled Current Source + Initial Release + + VCVS - Voltage Controlled Voltage Source + Initial Release + + VSRC - Indipendent Voltage Source + Initial Release + + + ************************************** + ********* Switches ********** + ************************************** + +CSW - Current controlled switch + Initial release + +SW - Voltage controlled switch + Initial release + + + ************************************** + ********** Diodes ********** + ************************************** + + DIO - Junction Diode + Initial Release + + + ************************************** + *********** Bipolar Devices ********** + ************************************** + + BJT - Bipolar Junction Transistor + Initial Relelase + + + ************************************** + ********** FET Devices ********** + ************************************** + + JFET - Junction Field Effect transistor + Initial Release + + JFET2 - Jfet PS model + Initial release. TO BE TESTED + + + ************************************** + ********* MES devices ********* + ************************************** + +MES - MESfet model + Initial release + + + ************************************** + ********* MOS devices ********* + ************************************** + + MOS1 - Level 1 MOS model + Initial Release + + MOS2 - Level 2 MOS model + Initial Release + + MOS3 - Level 3 MOS model + Initial Release + + MOS6 - Level 6 MOS model + Initial Release + + BSIM1 - BSIM model level 1 + Initial Release + + BSIM2 - BSIM model level 2 + Initial Release + + BSIM3 - BSIM model level 3 + This is the BSIM3v3.2.2 model from Berkeley device group. + You can find some test netlists with results for this model + at http://www-device.eecs.berkeley.edu/~bsim3. + + + BSIM3v1 - BSIM model level 3 + This is the BSIM3v3.1 model modified by Serban Popescu. This + is level 49 model. It is an implementation that supports + HDIF and M parameters. Test netlists are available at the URL + above. + TO BE TESTED AND IMPROVED. + + BSIM3v2 - BSIM model level 3 + This is the BSIM3v3.2 model. It is proved only for compatibility + with existing netlists and parameters files. As always, tests are + availabe on the Berkeley's device group site (at the above URL). + + BSIM4 - BSIM model level 4 (0.18 um) + Initial Release. TO BE TESTED. + + + ************************************** + ********** SOI Devices ********* + ************************************** + + +BSIM3SOI_DD - SOI model (dynamic depletion) + NOT YET IMPLEMENTED. + +BSIM3SOI_FD - SOI model (fully depleted devices) + NOT YET IMPLEMENTED. + +BSIM3SOI_PD - SOI model (partially depleted devices) + NOT YET IMPLEMENTED. diff --git a/FAQ b/FAQ new file mode 100644 index 000000000..ae7a008f0 --- /dev/null +++ b/FAQ @@ -0,0 +1,299 @@ + + + NG-Spice F.A.Q. + Frequently Asked Questions + (and Answers) + + Maintened by Daniele Foci + Last update: 29/08/1999 + + +CONTENTS + +1. INTRODUCTION AND GENERAL INFORMATION + 1.1 What is NG-Spice? + 1.2 Why resurrecting Berkeley's Spice? + 1.3 What is the project's goal? + 1.4 What you are going to do ? + 1.5 Legal issues + 1.6 What mailing lists exist for NG-Spice? + 1.7 Are the mailing lists archived anywhere? + 1.8 What newsgroups exist for NG-Spice? + 1.9 Where can I get a copy of NG-Spice? + 1.10 Where should I look on the World Wide Web for NG-Spice stuff? +2. DEVELOPMENT + 2.1 What is the current version? + 2.2 What are the latest features in the current release? + 2.3 What does it look like ? + 2.4 Who are the authors of ng-spice ? + 2.5 How can I report a bug/request for a feature? + 2.6 How can I join the development? +3. SOLUTIONS TO COMMON MISCELLANEOUS PROBLEMS + 3.1 What systems are supported? + 3.2 I get errors when I try to compile the source code, why? + 3.3 This document didn't answer my question. Where else can I look for + an answer? +4. ADMINISTRATIVE INFORMATION AND ACKNOWLEDGEMENTS + 4.1 Feedback + 4.2 Formats in which this FAQ is available + 4.3 Authorship and acknowledgements + 4.4 Disclaimer and Copyright + +------------------------------------------------------------------------------- + +1. INTRODUCTION AND GENERAL INFORMATION + +1.1 What is NG-Spice? + + NG-spice is the name of a project and of a program in the project. Spice is + the famous circuit simulator developed by the CAD Group of the University + of California at Berkeley (UCB). The NG prefix has a lot of meanings: Next + Generation, New Good, etc. Choose or invent the one you prefer. The NG-spice + project aims to improve the capabilities of the Spice3 circuit simulator. + The heart of the project is the ng-spice program, a circuit simulator + derived from spice3f5. + +1.2 Why resurrecting Berkeley's Spice? + + Berkeley's Spice can be considered the father of most circuit simulators + available today. It is an old but still good piece of software, it may not + be the fastest or the most reliable but it's free, it's available in + source code and most of the electrical simulators inherited it's syntax. + On the more technical side, spice3 uses good numerical algorithms + ( most commercial implementations have only strengthened them), implements + most of the models for MOSFET submicron designs and has a powerful set of + analyses. On the more "social" side, spice3 it's well introduced in the + academic environment. + +1.3 What is the project's goal? + + The final goal of NG-spice project is to develop a reliable, fast and + friendly circuit simulator for mixed signal/mixed level simulation. + Easy isn't it ;-). + +1.4 What you are going to do? + + The NG-spice project is divided in two main overlapping phases. The first + phase is strictly pertinent to the spice3f5 code: during this phase the + original spice3f5 code will be "cleaned" and corrected and small improvements + made to it. In phase one the Autoconf interface will replace the Berkeley's + one and this will lead to a different structure of the sources. + The second phase is the development of improvements in the ngspice code + (the old spice3f5 code cleaned and corrected) and of some programs that will + interface with it, like a schematic editor and a waveform viewer. A list of + proposed improvements follows: + + 1) The framework (or Graphic User Interface): + Spice is (and should continue to be) a command line or a text tool, but + this makes very difficult to design large circuits. To overcome this + difficulty, a schematic entry tool and a waveform viewer tools are needed. + Nevertheless, there are other tools that can be useful: a parts database, + an editor which higlights the syntax, a symbol editor, etc. + Most of these program already exists in the open source world, so they + need only to be integrated in a common EDA environment. + + 2) Documentation: + Commercial simulators have very good manuals with tutorials, models + equations explained, example of use, suggestions, etc. This line of + development has the task of providing the final spice user with an ordered + and comprehensive set of information on the program and its features. + The documentation should be useful for the student as well as for the + circuit professional. + + 3) Improvements to the Spice code: + This is the hard part. The target of this direction is to make ngspice a + commercial grade simulator. This means improving it's speed, its + numerical strenght, include the latest models available and some other + important features: + + * Numerical Algorithms: + - More stable algorithms for integration (as Runge-Kutta Methods). + - Better convergence in Operating Point Calculation replacing the + Newton-Raphson algorithm, a modified version of Fixed-Point + Homotopy. + + * Devices: + - Behavioral device: enhance the B device of spice3 to accepts IF THEN + ELSE conditions, and digital keywords like DELAY, + HIGHV, LOWV, etc. to simulate simple digital + device. + - Dynamically Loadable Devices: reduce the memory occupied by the + simulator by using shared object code + for devices. Each device is a .so + library that is inserted only if the + circuit contains an element modeled by + the device. If we are simulating CMOS, + we do not need BJT or SOI (in most of + the situations). + - Code Level Modeling: let users write their devices in C and use + them in the simulator. + - Improving device: include additional parameters to some devices as + HDIF, LDIF, etc. + + * New types of analysis, oriented to circuits syntesis and optimization: + - Network analysis: given four nodes, extract z,y,s and the other + double bipole paramters. + - Monte Carlo analysis: statistical simulation based on device + tolerances. + - Worst Case analysis: find the worst case of operation of a given + circuit based on device tolerances. + - Parametric analysis: repeat an analysis when one or more parameters + assumes different values. + + * Faster handling of sparse matrices. + + * Possibility to mesure circuit pameters, like the delay between two + nodes, etc. + + * ... whatever else can be judged useful. + + +1.5 Legal issues + + [not written yet: GPL vs. Berkeley] + +1.6 What mailing lists exist for NG-Spice? + + Only one. Send an empty message to to + have information on subscription. + +1.7 Is the mailing lists archived anywhere? + + Yes, the list is archived. Send an empty message to + to have information on how to retrieve + old messages. + +1.8 What newsgroups exist for NG-Spice? + + None. Sorry. + +1.9 Where can I get a copy of NG-Spice? + + You can download NG-Spice from: + ftp://ieee.ing.uniroma1.it/pub/ng-spice/distribution/ + +1.10 Where should I look on the World Wide Web for NG-Spice stuff? + + There is a WWW page for NG-Spice. The URL is: + http://geda.seul.org under the tools section. + + +2. DEVELOPMENT + +2.1 What is the current version? + + 0.3 (released on 30/08/1999) + +2.2 What are the latest features in the current release? + + * New features: + - Autoconf interface. + - BSIM 3.2.2 Model. + - PS jfet Model (jfet level 2). + - Temperature and resistance sweeps. + - "spec" command for spectrum analysis. + + * Bug fixes: + - Altermod command connected to the parser. + - Some memory leaks closed. + - Spice3f5 fixes available on the net. + +2.3 What does it look like ? + + This is a command line utility, no screenshots! + +2.4 Who are the authors of ng-spice ? + + The development is open to anyone who wish to contribute. + People who contributed are: + + * Daniele Foci + * Paolo Nenzi + * Arno Peters + * Serban-Mihai Popescu + * Emmanuel Rouat + * Michael Widlok + + This list is surely incomplete (due to open development group), there are + many people who contributed with improvements, pieces of code, bux fixes, + etc. If you have contributed and do not appear, write to: + ng-spice@ieee.ing.uniroma1.it + and ask to be included. + +2.5 How can I report a bug/request for a feature? + + Write in the mailing list. + +2.6 How can I join the development? + + To join the development just code the feature you want to add and send your + patch in the mailing list. Before you start coding check the latest + development release of NG-Spice from our CVS. It might be that your feature + has already been implemented. + To access the anonymous CVS do the following: + + 1) Install cvs on your machine (version 1.9.x - 1.10.x are just fine). + 2) Set one of the following environment variables: + For bash: + export CVSROOT=:pserver:anonymous@ieee.ing.uniroma1.it:/var/services/cvsroot + For csh/tcsh: + setenv CVSROOT :pserver:anonymous@ieee.ing.uniroma1.it:/var/services/cvsroot + 3) Login to the cvs server by running: + $> cvs login + The password is 'guest' (without the quotes of course). You will only + have to do this once. + 4) Checkout the appropriate files executing the following commands: + $> mkdir somedirectory + $> cd somedirectory + $> cvs co ng-spice + 5) Wait for the cvs logout. + + +3. SOLUTIONS TO COMMON MISCELLANEOUS PROBLEMS + +3.1 What systems are supported? + + This is the updated list: + + Hardware O.S. Compiler Functional? + ---------------- ------------------ -------------- ----------- + i386 Linux (RedHat) gcc yes + i386 Linux (Debian) gcc yes + i386 Linux (SuSE) gcc yes + IBM Risc 6000 AiX lcc no + SUN Solaris 7 gcc yes + SUN Solaris 7 SUN Workshop ? + +3.2 I get errors when I try to compile the source code, why? + + [not written yet] + +3.3 This document didn't answer my question. Where else can I look for + an answer? + + Read old messages from the mailing list archive, search the web site or read + the docs. Upgrade to the latest version of NG-Spice, many problems are fixed + in the new versions. If you still can't find an answer, post your question + to the mailing list. + + +4. ADMINISTRATIVE INFORMATION AND ACKNOWLEDGEMENTS + +4.1 Feedback + + Send your comments about this F.A.Q. to . + Send your comments about NG-Spice to . + +4.2 Formats in which this FAQ is available + + This document is available only in ASCII format in the NG-Spice source + package. + +4.3 Authorship and acknowledgements + + Parts of the questions and answers are originate from Paolo Nenzi. + +4.4 Disclaimer and Copyright + + This document is provided as is. The information in it is not warranted to + be correct: you use it at your own risk. diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..9e8a41cc5 --- /dev/null +++ b/INSTALL @@ -0,0 +1,153 @@ +Basic Installation +================== + + +The autoconf support is still very crude and needs work, but basically +you should be able to do: +./configure +make +make install +(default install dir is /usr/local/bin) + +You can use some extra options to 'configure' + +--disable-debug : this option will remove the '-g' option passed to the +compiler (speeds up compilation a *lot*) + +--enable-ansi : configure will try to find an option for your compiler so +that it expects ansi-C + +Do a './configure --help' to get all available options. + + + + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..92d9ea14e --- /dev/null +++ b/Makefile.am @@ -0,0 +1,15 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = doc src man tests + +EXTRA_DIST = FAQ acconfig.h autogen.sh notes contrib + +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ + config.h.in config.sub configure install-sh \ + missing mkinstalldirs stamp-h.in ltconfig \ + ltmain.sh + +mrproper: maintainer-clean + rm -f `find . -type f -name "*~" -print` + rm -f `find . -type f -name "*.orig" -print` + rm -f `find . -type f -name "*.rej" -print` diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..4ae42e4c9 --- /dev/null +++ b/NEWS @@ -0,0 +1,108 @@ +Ng-spice-rework-10 +============ + +Added BSIM4 model and closed a couple of serious bugs. Added DEVICES file +to distribution. This file contains the status of device models in this +simulator. Read it, this file can save you a lot of time. + +Ng-spice-rework-9 +============ + +Thanks to Arno Peters now all device models are dynamically loaed on demand. +Thay are linked as shared libraries. The next step is the dlopen() one which +will make possible to link devices without any recompilation. + + + +Ng-spice-rework-8 +============ + +Applied Arno's patch. + +From his mail message: + +Hi Paolo, + +I have prepared a source cleaning patch. + +Features: + + + patches don't get polluted with differences between automatically + generated Makefile.am files. Usually these make up the biggest part + of the patches. This allows me to read the patch on the mailing + list instead of sifting through 90% redundant and irrelevant changes. + + + the shell script autogen.sh automatically regenerates the required + files if the user has automake, autoconf and libtool installed. + + + this feature is only valuable to developers, not to end users. + + +Usage of this patch, once incorporated: + + # create a working tree to work from + cp -a ng-spice-rework-x ng-spice + + [ Changes made to ng-spice ] + + # clean up all the automatically generated files + cd ng-spice; make maintainer-clean + + # extract the differences + diff -ruN ng-spice-rework-x ng-spice > my.patch + + [ Patch sent to ng-spice mailing list or you ] + + # incorporate changes into the tree + cd ng-spice-rework-x; patch -p1 < my.patch + + # update the automatically generated files + cd ng-spice-rework-x; sh autogen.sh + + + + +Ng-spice-rework-7 (22 Mar 2000) +============ + +Bug fix release + + + +Ng-spice-rework-6 (29 Jan 2000) +============ + +This porting includes: + +1) BSIM3V3.1 model as level 49. This is the version modified by Serban Popescu + which understands the M parameter and implements HDIF. + +2) BSIM3V3.2 model al Level 50. This is the standard Berkeley version. + +3) Now the resistor model can accepts two differents values for DC and AC + resistance. + + + +Ng-spice-rework-5 and 5_2 (Jan 2000) +============ + +Internal development release, buggy and not working. + +Ng-spice-rework-4 (22/12/99) +============ + +This porting includes a new feature: + +1) dynamically loading of some device code as an experimental feature for + the future GPL simulator. Thanks to Arno Peters and Manu Rouat. + +2) Patched the following bug (thanks to Andrew Tuckey for having supplied the + patch). + + * Wsw (current controlled switch) in subckt, parsing bug. + * scale factor in arbitrary source. + * bug in noise analisys. + * save segmentation faults. + + diff --git a/README b/README new file mode 100644 index 000000000..88cf887d5 --- /dev/null +++ b/README @@ -0,0 +1,162 @@ +README for NGSPICE +------------------ + +This long message describes what NG-SPICE may become in the (near ?) +future. I used a question mark because, as you will read, most of the +features of ng-spice are found on Hi-quality commercial products and +(which is the true reason) I have no idea on how can be implemented. + +** Why resurrecting Berkeley's Spice ? + +Berkeley's spice can be considered the father of most circuit simulator +available today. It is an old but still good piece of software. It may not +be the fastest or the most reliable, but it's free, it is available in +source code, and most of the electrical simulators inherited it's syntax. +On the more technical side, spice3f4(5) uses good numerical algorithms +(commercial implementations have only strengthened them), implements most +of the models for MOSFET submicron designs and has a powerful set of +analyses. On the more "social" side: it's weel introduced in the +academic environment. + + +** What does NG-SPICE mean ? + +It stands for Next Generation Spice but that's not the official name of +the projest. This projects still lacks a name. NG-SPICE is a temporary +name. + + +** What will NG-SPICE be ? + +Berkeley's Spice lacks in three directions: + + a) Graphical user interface (I prefer to say "the framework"). + b) Documentation. + c) Features in the code. + + * The framework: + Spice is (and should continue to be) acommand line or a text tool, but + this makes very difficult to design large circuits. To overcome this + difficulty, a schematic entry tool and a waveform viewer tool are + needed. Nevertheless, there are other tools that can be useful: + a parts database, an editor which higlights the syntax, a symbol + editor, etc. Most of these program already exists in the open source + world, so they need ony to be integrated in a common EDA environment. + This is the first direction of development. + + * Documentation: Commercial simulators (hi-end) have very good manuals + with tutorials, models equation explained, example of use, suggestions, + etc. This line of development has the task of provinding the final + spice user with an orderd and comprehensive set of information on the + program and it's features. The documentation should be useful for the + student as well as for the circuit professional. + + * Improvements to the spice code: This is the hard part. Th target of + this direction is to make ng-spice a commercial grade simulator. This + means improving it's speed, it's numerical robustness, include the + latest models available and some other important features. I will + describe some of them briefly: + + - Analyses - + Network analisys: given four nodes, extract z,y,s and the other + double bipole paramters. + + Monte Carlo analisys: statistical simulation based on device + tolerances. + + Worst Case analisys: find the worst case of operation of a given + circuit based on device tolerances. + + Parametric analisys: repeat an analysis when one or more parameters + assumes different values. + + - Devices - + Behavioral device: enhance the B device of spice3 to accepts IF THEN + ELSE conditions, and digital keywords like DELAY, HIGHV. LOWV, etc to + simulate simple digital device. + + Dynamically loading of device: reduce the memory occupied by the + simulator by using shared object code for devices. Each device + is a .so library that is inserted only if the circuit contains + an element modeled by the device. If we are simulating CMOS, + we do not need BJT or SOI (in most of the situations). + + Code Level Modeling: Let users write their devices in C and use + them in the simulator. I have discovered a couple of standars + for doing this at the Sematech ftp site. + + Improving device: Include additional parameters to some devices: + HDIF, LDIF, etc. (Serban, can you explain better). + + - Numerical Algs - + Integration: include (if necessary) more stable algorithms for + integration. Runge-Kutta Methods ? + + Linearization: + Are there better algorithms for nonlinear equations the the Newton + raphson ? + + - Sparse Matrix - + Faster handling of sparse matrices. + + + - Options - + Possibility to mesure circuit pameters, like the delay between two + nodes, etc. + + +... and others that will emerge during the project. + + +Paolo Nenzi (pnenzi@ieee.ing.uniroma.it) + + + + +NOTES: +------ + +This version builds correctly on redhat linux 6.0, and most probably +on any glibc2-based linux distribution. The executables have hardly been +tested, all I know is that they build. The main goal of this release is +to get autoconf to work. + +The goal is to put all possible configurations flags into the autoconf support. + +It should build on most other unices (especially POSIX ones), please report to me +if it does, or if you know how to fix it if it doesn't. + +As the -Wall flag is turned on during compilation, you will notice a HUGE +amount of warnings - our first job should be to work on those to 'sanitize' +the existing code. + + +MAILING LISTS: +------------- + +There are three mailing lists dedicated to the development of ngspice. + +ng-spice@ieee.ing.uniroma1.it: This list is the list for the users of the + ng-spice simulator. + +ng-spice-devel@ieee.ing.uniroma1.it: ng-spice development issues. + +ng-spice-frontends@ieee.ing.uniroma1.it: issues related to development of + frontends for ng-spice. + +To subscribe the list(s), send a message to: + + + + + +WEB SITE: +-------- + +This project is hosted on the IEEE Central & South Italy Section Server. +The home page is http://ieee.ing.uniroma1.it/ngspice + +Manu (emmanuel.rouat@wanadoo.fr) +Paolo (p.nenzi@ieee.org) + + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 000000000..48a739cf5 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,24 @@ + +/* Define the location of NGSPICEDATADIR */ +#define NGSPICEDATADIR none + +/* Define the location of NGSPICEBINDIR */ +#define NGSPICEBINDIR none + +/* Define the build date */ +#define NGSPICEBUILDDATE none + +/* Define if we have termcap */ +#undef HAVE_TERMCAP + +/* Define if we want NOBYPASS */ +#undef NOBYPASS + +/* Define if we want predictor algorithm */ +#undef PREDICTOR + +/* Define if we want spice2 sensitivity analysis */ +#undef WANT_SENSE2 + +/* Define if we want some experimental code */ +#undef EXPERIMENTAL_CODE diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000..a816809d6 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,73 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +PROJECT=ng-spice +TEST_TYPE=-d +FILE=src/circuit + +DIE=0 + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $PROJECT." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have libtool installed to compile $PROJECT." + echo "Get ftp://alpha.gnu.org/gnu/libtool-1.0h.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have automake installed to compile $PROJECT." + echo "Get ftp://ftp.cygnus.com/pub/home/tromey/automake-1.2d.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + +test $TEST_TYPE $FILE || { + echo "You must run this script in the top-level $PROJECT directory" + exit 1 +} + +if test -z "$*"; then + echo "I am going to run ./configure with no arguments - if you wish " + echo "to pass any to it, please specify them on the $0 command line." +fi + +case $CC in +*lcc | *lcc\ *) am_opt=--include-deps;; +esac + +#echo "Running gettextize... Ignore non-fatal messages." +# Hmm, we specify --force here, since otherwise things don't +# get added reliably, but we don't want to overwrite intl +# while making dist. +#echo "no" | gettextize --copy --force + +echo "Running libtoolize" +libtoolize --copy --force + +aclocal $ACLOCAL_FLAGS + +# optionally feature autoheader +(autoheader --version) < /dev/null > /dev/null 2>&1 && autoheader + +automake -c -a $am_opt +autoconf + +./configure "$@" + +echo +echo "Now type 'make' to compile $PROJECT." + diff --git a/configure.in b/configure.in new file mode 100644 index 000000000..409b083c5 --- /dev/null +++ b/configure.in @@ -0,0 +1,245 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(src/main.c) +dnl Create a configuration header +AM_CONFIG_HEADER(config.h) + +dnl --enable-ansi : try to force --ansi option to the compiler +AC_ARG_ENABLE(ansi, + [ --enable-ansi Force --ansi option for compilation]) + +dnl --disable-debug : remove -g and -Wall option to the compiler +AC_ARG_ENABLE(debug, + [ --enable-debug Add -g option for compilation (default)]) + +dnl --enable-checker : add --with-checker-debug option to the compiler +AC_ARG_ENABLE(checker, + [ --enable-checkergcc Option for compilation with checkergcc]) + +dnl --enable-bypass : define BYPASS for the code +AC_ARG_ENABLE(nobypass, + [ --enable-nobypass Don't bypass recalculations of slowly changing variables]) + +dnl --enable-predictor : define PREDICTOR for the code +AC_ARG_ENABLE(predictor, + [ --enable-predictor Enables a predictor method for convergence]) + +dnl --enable-sense2 : define HAVE_SENSE2 for the code +AC_ARG_ENABLE(sense2, + [ --enable-sense2 Use spice2 sensitivity analysis]) + +dnl --enable-experimental : define EXPERIMENTAL_CODE for the code +AC_ARG_ENABLE(experimental, + [ --enable-experimental Enables some experimental code]) + + +dnl Initialize automake stuff +AM_INIT_AUTOMAKE(ng-spice-rework,10) + +dnl Enable maintainer commands only if requested +AM_MAINTAINER_MODE + +dnl Work on compiler options according to system: +dnl Set default CFLAG - only use -Wall if we have gcc + +AC_PROG_CC + +if test "x$GCC" = "xyes"; then + CFLAGS="$CFLAGS -Wall " +fi + +if test "$enable_debug" = "no"; then + AC_MSG_WARN(Removing debugging option!) + CFLAGS=" " +fi + +dnl Not sure that this will work.... +if test "$with_checkergcc" = "yes"; then + CC="checkergcc" +fi + + +dnl Checks for ANSI-C header files. +AC_HEADER_STDC + +if test "$enable_ansi" = "yes"; then + AM_PROG_CC_STDC + if test ! "$am_cv_prog_cc_stdc"="yes"; then + AC_MSG_WARN(Failed to find Ansi flag!) + fi +fi + + + + +dnl Chech system we're on , and tune accordingly +AC_CANONICAL_HOST + +case "$host" in + +*bsd* ) CFLAGS="$CFLAGS";; +*linux*) CFLAGS="$CFLAGS";; +*rs6000* ) CFLAGS="$CFLAGS";; +*sgi* ) CFLAGS="$CFLAGS";; +*sun* ) CFLAGS="$CFLAGS";; +*ultrix* ) CFLAGS="$CFLAGS";; + +esac + + + +dnl Checks for programs + +AC_LIBTOOL_DLOPEN +AM_PROG_LIBTOOL + + +dnl Checks for X11 header files and libraries - X11 support can be disabled +dnl by passing the '--without-x' option to configure: + +AC_PATH_X +AC_PATH_XTRA + + + +dnl Checks for X libraries - if X11 wasn't found then don't make following +dnl tests and compile without X11 support - otherwise, check if the following +dnl libraries are present (error if they are not) + + +if test ! "$no_x" = "yes" ; then + X_LIBS="$X_LIBS -lX11 -lXt" + AC_CHECK_LIB(Xext, XShmAttach,X_LIBS="$X_LIBS -lXext",AC_MSG_ERROR(Couldn't find Xext librairies), $X_LIBS $X_EXTRA_LIBS) + AC_CHECK_LIB(Xaw,main,X_LIBS="$X_LIBS -lXaw",AC_MSG_ERROR(Couldn't find Xaw librairies),$X_LIBS $X_EXTRA_LIBS) + AC_CHECK_LIB(Xmu,main,X_LIBS="$X_LIBS -lXmu",AC_MSG_ERROR(Couldn't find Xmu librairies), $X_LIBS $X_EXTRA_LIBS) + +fi + +dnl Check for a few typdefs: +AC_TYPE_PID_T +AC_TYPE_SIGNAL + +dnl Check for a few libraries and headers: + +dnl Look for ncurses first, then termcap +AC_SEARCH_LIBS(tputs,ncurses termcap,AC_DEFINE(HAVE_TERMCAP), + AC_MSG_ERROR(Found neither ncurses or termcap)) + + +AC_HEADER_DIRENT +AC_CHECK_HEADERS(ctype.h unistd.h pwd.h fcntl.h) +AC_HEADER_SYS_WAIT +AC_HEADER_STAT + +dnl Check time and ressources headers and functions: +AC_HEADER_TIME +AC_STRUCT_TM +AC_STRUCT_TIMEZONE +AC_CHECK_FUNCS(localtime) +AC_CHECK_FUNCS(gettimeofday time ftime , break) +AC_CHECK_FUNCS(getrusage utimes, break) +AC_CHECK_FUNCS(getrlimit ulimit, break) + +dnl Look for termios first (posix) +AC_CHECK_HEADERS(termios.h termio.h sgtty.h , break) +AC_CHECK_FUNCS(isatty) + +dnl Check for a few functions: +AC_FUNC_VFORK +AC_CHECK_FUNCS(access bcopy qsort dup2 popen) +AC_CHECK_FUNCS(strchr index , break) +AC_CHECK_FUNCS(getcwd getwd , break) + + +AC_MSG_RESULT(Checking mathematical features of the system:) +dnl Look for math library: +AC_CHECK_LIB(m,sqrt) +AC_CHECK_HEADERS(float.h limits.h values.h) + +dnl Check for a few mathematical functions: +AC_CHECK_FUNCS(erfc logb scalb scalbn asinh acosh atanh) + + +# Expand the prefix variable (this is really annoying!) +if eval "test x$prefix = xNONE"; then + dprefix=$ac_default_prefix +else + dprefix=$prefix +fi + +AC_DEFINE_UNQUOTED(NGSPICEBINDIR, "`echo $dprefix/bin`" ) +AC_DEFINE_UNQUOTED(NGSPICEDATADIR, "`echo $dprefix/share/ng-spice`" ) +AC_DEFINE_UNQUOTED(NGSPICEBUILDDATE, "`date`" ) + + +# Recapitulate settings: +AC_MSG_RESULT(Settings which were chosen:) +if test "$enable_sense2" = "yes"; then + AC_DEFINE(WANT_SENSE2) + AC_MSG_RESULT(Spice2 sensitivity analysis enabled) +fi +if test "$enable_nobypass" = "yes"; then + AC_DEFINE(NOBYPASS) + AC_MSG_RESULT(NOBYPASS option enabled) +fi +if test "$enable_predictor" = "yes"; then + AC_DEFINE(PREDICTOR) + AC_MSG_RESULT(PREDICTOR algorithm enabled) +fi +if test "$enable_experimental" = "yes"; then + AC_DEFINE(EXPERIMENTAL_CODE) + AC_MSG_RESULT(EXPERIMENTAL_CODE enabled) +fi + + +AC_OUTPUT( \ +Makefile \ +doc/Makefile \ +man/Makefile \ +man/man1/Makefile \ +src/Makefile \ +src/analysis/Makefile \ +src/circuit/Makefile \ +src/devices/Makefile \ +src/devices/asrc/Makefile \ +src/devices/bjt/Makefile \ +src/devices/bsim1/Makefile \ +src/devices/bsim2/Makefile \ +src/devices/bsim3v1/Makefile \ +src/devices/bsim3/Makefile \ +src/devices/bsim4/Makefile \ +src/devices/bsim3v2/Makefile \ +src/devices/cap/Makefile \ +src/devices/cccs/Makefile \ +src/devices/ccvs/Makefile \ +src/devices/csw/Makefile \ +src/devices/devsup/Makefile \ +src/devices/dio/Makefile \ +src/devices/disto/Makefile \ +src/devices/ind/Makefile \ +src/devices/isrc/Makefile \ +src/devices/jfet/Makefile \ +src/devices/jfet2/Makefile \ +src/devices/ltra/Makefile \ +src/devices/mes/Makefile \ +src/devices/mos1/Makefile \ +src/devices/mos2/Makefile \ +src/devices/mos3/Makefile \ +src/devices/mos6/Makefile \ +src/devices/res/Makefile \ +src/devices/sw/Makefile \ +src/devices/tra/Makefile \ +src/devices/urc/Makefile \ +src/devices/vccs/Makefile \ +src/devices/vcvs/Makefile \ +src/devices/vsrc/Makefile \ +src/frontend/Makefile \ +src/hlp/Makefile \ +src/include/Makefile \ +src/maths/Makefile \ +src/maths/cmaths/Makefile \ +src/maths/ni/Makefile \ +src/maths/sparse/Makefile \ +src/misc/Makefile \ +src/parser/Makefile \ +tests/Makefile \ +) diff --git a/contrib/ChangeLog b/contrib/ChangeLog new file mode 100644 index 000000000..9ebcd5e43 --- /dev/null +++ b/contrib/ChangeLog @@ -0,0 +1,11 @@ +2000-03-22 Paolo Nenzi + + * mslib: Major update. M. Widlok sent the new version of it's programs. + + * spiceprm: Major update. See above line. + +1999-09-14 Arno + + * mslib: Added. + + * spiceprm: Added. diff --git a/contrib/mslib/COPYING b/contrib/mslib/COPYING new file mode 100644 index 000000000..d4dcbaccf --- /dev/null +++ b/contrib/mslib/COPYING @@ -0,0 +1,5 @@ +Mslib is free for everyone who think that it might by useful for +him. If someone makes it better please e-mail me. + +Michael Widlok +widlok@uci.agh.edu.pl \ No newline at end of file diff --git a/contrib/mslib/datadef.h b/contrib/mslib/datadef.h new file mode 100644 index 000000000..c5bdd3e1f --- /dev/null +++ b/contrib/mslib/datadef.h @@ -0,0 +1,87 @@ +/* + * MW. Include for spice + */ + +#ifndef DATADEF_INC +#define DATADEF_INC + + /* + * Program defaults + * + * *Directory for input file and input libraries + */ +#define DECKPATH "./" +#define LIBPATH "/usr/local/lib/" + + /* + * Name for output library file + */ +#define TMPLIBNAME ".lib" /* + * * * * actual name is "deck.TMPLIBNAME" + */ + + /* + * Command for libraries, subckts and models declaration + */ +#define LIBINVL "*LIB" +#define SUBINVL "*SUB" +#define MODINVL "*MOD" + + /* + * Keywords for subckt start, end and model + */ +#define SUBLINE ".SUBCKT" +#define SUBEND ".ENDS" +#define MODLINE ".MODEL" +#define MODEND + +#define LIBMESSAGE "* MW Library include for Spice" + +#define BSIZE 255 +#define MODDLINE 1 +#define SUBDLINE 4 +#define LIBDLINE 8 +#define SUBLLINE 16 +#define MODLLINE 32 +#define ENDSLLINE 64 +#define CONTLLINE 128 +#define NORMLINE 0 +#define WRITESUB 0xffff +#define WRITEMOD 0x1111 +#define NOWRITE 0x0 +#define FAILED 0xffffff +#define SUCCESS 0 + +#define IS_LIB 0x1 +#define LIB_OPEN 0x2 + +#define IS_MOD 0x10 +#define IS_SUB 0x100 +#define FINDED 0x400 +#define DUPLICATE 0x800 + +#define DECK_OPEN 0x20000 +#define TLIB_OPEN 0x100000 + +#define NAMEVALID 0xfff +#define NAMENOTV 0x0 + +struct LSData + { + char name[BSIZE]; + FILE *filedes; + int flag; + struct LSData *prevLS; + struct LSData *nextLS; + }; + +struct LSData *LSinsert(struct LSData *LS, struct LSData *where); +struct LSData *LSclear(struct LSData *LS); +struct LSData *Backfree(struct LSData *LS); +int readdeck(FILE * tdeck, struct LSData *lib, \ + struct LSData *sub, struct LSData *mod); +int readlib(struct LSData *lib, FILE * tlib, \ + struct LSData *firstSUB, struct LSData *firstMOD); +int checkname(struct LSData *smp, char *name); + +#endif diff --git a/contrib/mslib/inc_LSD.c b/contrib/mslib/inc_LSD.c new file mode 100644 index 000000000..6e62dd2d6 --- /dev/null +++ b/contrib/mslib/inc_LSD.c @@ -0,0 +1,93 @@ +/* + * MW. Include for spice - LSData functions + */ + +#include +#include +#include +#include + +#include "datadef.h" + +char *Message = "Michael Widlok, all rights reserved \n" +"mslib - MW include for Spice models/subckts\n"; + +/* + * Add or cretate new LS structure just after where pointer + */ +struct LSData * +LSinsert(struct LSData *LS, struct LSData *where) +{ + + if (!(LS)) + { + LS = (struct LSData *) malloc(sizeof(struct LSData)); + + if (!(LS)) + { + fprintf(stderr, "LSinsert: Can't allocate LSData srtucture.\n"); + exit(FAILED); + } + LS->filedes = NULL; + } +/* + * If where is given we must set nextLS and prevLS correctly + */ + if (where) + { + LS->prevLS = where; + if (LS->nextLS = where->nextLS) + where->nextLS->prevLS = LS; + where->nextLS = LS; + } else + LS->nextLS = LS->prevLS = NULL; + return LS; +} + +/* + * Clear all LS list from end. This also closes opened files + */ +struct LSData * +LSclear(struct LSData *LS) +{ + while (LS->nextLS) + LS = LS->nextLS; + return Backfree(LS); +} + +/* + * Used by LSclear + */ +struct LSData * +Backfree(struct LSData *LS) +{ + if (LS->filedes) + fclose(LS->filedes); + return (LS->prevLS) ? Backfree(LS->prevLS) : free(LS), LS; +} + +/* + * Check if sub/mod name should by included + */ +int +checkname(struct LSData *smp, char *name) +{ + do + { + if (!(strcmp(smp->name, name))) + { + if (smp->flag != FINDED) + { + smp->flag = FINDED; + return NAMEVALID; + } else + { + smp->flag = DUPLICATE; + return NAMEVALID; + } + } + smp = smp->nextLS; + } + while (smp); + return NAMENOTV; +} diff --git a/contrib/mslib/inc_inp.c b/contrib/mslib/inc_inp.c new file mode 100644 index 000000000..c8436a075 --- /dev/null +++ b/contrib/mslib/inc_inp.c @@ -0,0 +1,199 @@ +/* + * MW. Include for spice + */ +#include +#include +#include +#include + +#include "datadef.h" + +static int whatdline(char *tbuf, char *firstname); +static int whatlline(char *tbuf, char *name); + +extern int bsizer; +extern char buf[BSIZE]; + +/* + * Read deck and search for *MOD, *LIB, *SUB commands + */ +int +readdeck(FILE * tdeck, struct LSData *lib, \ + struct LSData *sub, struct LSData *mod) +{ + char firstname[BSIZE]; + char *names, *smlp; + struct LSData *which; + + while (fgets(buf, bsizer, tdeck)) + { + + smlp = buf; + /* + * Ignore control chars at the end of line + */ + do + { + smlp++; + } + while ((!(iscntrl(*smlp))) && (*smlp != '\0')); + *smlp = '\0'; + + switch (whatdline(buf, firstname)) + { + + case LIBDLINE: + lib->flag = IS_LIB; + which = lib; + break; + + case SUBDLINE: + sub->flag = IS_SUB; + which = sub; + break; + + case MODDLINE: + mod->flag = IS_MOD; + which = mod; + break; + + default: + which = NULL; + } + +/* + * If we finded something + */ + if (which) + { + names = buf; + strsep(&names, " "); + + while (smlp = strsep(&names, " ")) + { + if (*smlp) + { + which = LSinsert(NULL, which); + strcpy(which->name, smlp); + } + } + } + } + return ((lib->flag != IS_LIB) && (mod->flag != IS_MOD) \ + &&(sub->flag != IS_SUB)) ? FAILED : SUCCESS; +} + +/* + * Read library and write specififed models/subckts to tmplib + */ +int +readlib(struct LSData *lib, FILE * tlib, \ + struct LSData *sub, struct LSData *mod) +{ + + char name[BSIZE]; + int numi, wflag; + + numi = 0; + wflag = NOWRITE; + + while (fgets(buf, bsizer, lib->filedes)) + { +/* + * Now we must check what line is it and if it should be written to tmplib + */ + switch (whatlline(buf, name)) + { + + case (MODLLINE): + if (wflag == WRITESUB) + fputs(buf, tlib); + else + { + + if (mod) + { + if (checkname(mod, name)) + { + wflag = WRITEMOD; + numi++; + fprintf(tlib, "* Model: %s, from: %s.\n", \ + name, lib->name); + fputs(buf, tlib); + } + } + } + break; + + case (SUBLLINE): + if (sub) + { + if (checkname(sub, name)) + { + wflag = WRITESUB; + numi++; + fprintf(tlib, "* Subckt: %s, from: %s.\n", \ + name, lib->name); + fputs(buf, tlib); + } + } + break; + + case (NORMLINE): + if (wflag == WRITEMOD) + { + wflag = NOWRITE; + fputs("\n* End Model.\n\n", tlib); + } + if (wflag == WRITESUB) + fputs(buf, tlib); + break; + + case (ENDSLLINE): + if (wflag == WRITESUB) + { + fprintf(tlib, "%s\n* End Subckt\n\n", buf); + } + wflag = NOWRITE; + break; + + case (CONTLLINE): + if (wflag != NOWRITE) + fputs(buf, tlib); + } + + } + return numi; +} + +/* + * Check what line in deck it is + */ +int +whatdline(char *tbuf, char *firstname) +{ + if (sscanf(tbuf, "*LIB %s", firstname) == 1) + return LIBDLINE; + if (sscanf(tbuf, "*SUB %s", firstname) == 1) + return SUBDLINE; + if (sscanf(tbuf, "*MOD %s", firstname) == 1) + return MODDLINE; + return NORMLINE; +} + +/* + * Check what line it is. If we have model or subckt line we also read its name + */ +int +whatlline(char *tbuf, char *name) +{ + if (sscanf(tbuf, ".SUBCKT %s %*s", name) == 1) + return SUBLLINE; + if (sscanf(tbuf, ".MODEL %s %*s", name) == 1) + return MODLLINE; + if (sscanf(tbuf, ".ENDS%c", name) == 1) + return ENDSLLINE; + if (sscanf(tbuf, "+%s", name) == 1) + return CONTLLINE; + return NORMLINE; +} diff --git a/contrib/mslib/inc_main.c b/contrib/mslib/inc_main.c new file mode 100644 index 000000000..5f2f18ba7 --- /dev/null +++ b/contrib/mslib/inc_main.c @@ -0,0 +1,208 @@ +/* + * MW. Include - main functions + */ + +#include +#include +#include +#include + +#include "datadef.h" + +struct LSData *firstLIB; +struct LSData *firstSUB; +struct LSData *firstMOD; +struct LSData *deck; +struct LSData *tmplib; +int bsize, bsizer; +char buf[BSIZE]; + +int +main(int argc, char *argv[]) +{ + +/* + * Initialize everything + */ + struct LSData *subp, *libp, *modp; + char tch[BSIZE]; + int mswritten; + + tmplib = LSinsert(NULL, NULL); + deck = LSinsert(NULL, NULL); + *tch = '\0'; + mswritten = 0; + + switch (argc) + { + + case 3: + strcpy(tmplib->name, argv[--argc]); + strcpy(tch, tmplib->name); + + case 2: + strcpy(deck->name, argv[--argc]); + if (!(*tch)) + { + sprintf(tmplib->name, "%s%s", deck->name, TMPLIBNAME); + strcpy(tch, tmplib->name); + } + break; + + case 1: + fprintf(stdout, "Usage: mslib deck [tmplib]\n"); + return FAILED; + + default: + fprintf(stderr, "mslib: Incorrect parameters count.\n"); + return FAILED; + } + +/* + * Open deck + */ + if (!(deck->filedes = fopen(deck->name, "r"))) + { + sprintf(deck->name, "%s%s", DECKPATH, argv[1]); + sprintf(tmplib->name, "%s%s", DECKPATH, tch); + + if (!(deck->filedes = fopen(deck->name, "r"))) + { + fprintf(stderr, "mslib: Can't open deck %s.\n", deck->name); + LSclear(deck); + LSclear(tmplib); + return FAILED; + } + } + bsizer = BSIZE; + bsize = bsizer--; + + deck->flag = DECK_OPEN; + +/* + * Create tmplib and write first line to it + */ + if (!(tmplib->filedes = fopen(tmplib->name, "w"))) + { + fprintf(stderr, "mslib: Can't creat tmplib %s.\n", tmplib->name); + LSclear(tmplib); + LSclear(deck); + return FAILED; + } + tmplib->flag = TLIB_OPEN; + fprintf(tmplib->filedes, "%s\n* Tmp library: %s,\n* For deck: %s.\n\n", \ + LIBMESSAGE, tmplib->name, deck->name); + + firstLIB = LSinsert(NULL, NULL); + firstSUB = LSinsert(NULL, NULL); + firstMOD = LSinsert(NULL, NULL); + +/* + * Find commands in deck + */ + readdeck(deck->filedes, firstLIB, firstSUB, firstMOD); + + if (firstLIB->flag = IS_LIB) + { + + libp = firstLIB->nextLS; + do + { + if (!(libp->filedes = fopen(libp->name, "r"))) + { + strcpy(tch, libp->name); + sprintf(libp->name, "%s%s", LIBPATH, tch); + + if (!(libp->filedes = fopen(libp->name, "r"))) + { + libp->flag = FAILED; + } + } +/* + * Read libraries if everything is OK + */ + if (libp->flag != FAILED) + { + libp->flag = LIB_OPEN; + + modp = (firstMOD->flag == IS_MOD) ? firstMOD->nextLS : NULL; + subp = (firstSUB->flag == IS_SUB) ? firstSUB->nextLS : NULL; + + mswritten += readlib(libp, tmplib->filedes, subp, modp); + } + libp = libp->nextLS; + } + while (libp); + } + fprintf(stdout, "mslib: Written %d items to tmplib %s.\n", \ + mswritten, tmplib->name); + + if (libp = firstLIB->nextLS) + { + do + { + if (libp->flag != LIB_OPEN) + fprintf(stderr, " Can't open lib %s.\n", libp->name); + libp = libp->nextLS; + } + while (libp); + } +/* + * Check is models or subckts were find and + * * are not duplicated + */ + if (modp = firstMOD->nextLS) + { + do + { + switch (modp->flag) + { + case DUPLICATE: + fprintf(stderr, " Model duplicated %s.\n", \ + modp->name); + break; + default: + fprintf(stderr, " Can't find model %s.\n", \ + modp->name); + break; + + case FINDED: + } + + modp = modp->nextLS; + } + while (modp); + } + if (subp = firstSUB->nextLS) + { + do + { + switch (subp->flag) + { + case DUPLICATE: + fprintf(stderr, " Subckt duplicated %s.\n", \ + subp->name); + break; + default: + fprintf(stderr, " Can't find subckt %s.\n", \ + subp->name); + break; + + case FINDED: + } + subp = subp->nextLS; + } + while (subp); + } +/* + * Clear all data and close files + */ + + LSclear(tmplib); + LSclear(deck); + LSclear(firstLIB); + LSclear(firstSUB); + + return SUCCESS; + +} diff --git a/contrib/mslib/makefile b/contrib/mslib/makefile new file mode 100644 index 000000000..186038480 --- /dev/null +++ b/contrib/mslib/makefile @@ -0,0 +1,12 @@ +# MW. Include libs for Spice +CFLAGS= -O2 -s +LDFLAGS= -s + +OBJS= inc_main.o inc_inp.o inc_LSD.o +HDRS= datadef.h +SRCC= inc_main.c inc_inp.c inc_LSD.c + +mslib: $(OBJS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) + +$(OBJS): $(HDRS) \ No newline at end of file diff --git a/contrib/mslib/mslib_readme b/contrib/mslib/mslib_readme new file mode 100644 index 000000000..acebbe4ea --- /dev/null +++ b/contrib/mslib/mslib_readme @@ -0,0 +1,35 @@ +Mslib can create a small tmp library which can be .include to spice deck or +used as tmp file with libprm. +You invoke it like this: mslib deck_name [tmp_lib_name]. If second argument +is not given mslib uses deck_name.lib. Mslib then reads deck and looks for +special commands in it. This commands are: + +*SUB name1 name2 ... - what subckts are used +*MOD name1 name2 ... - what models are used +*LIB name1 name2 ... - what libraries should be searched + +You can give full path for libraries or just the name. Mslib tries to +find them in current directory and then in directory specified in datadef.h +file. There are also some other default options defined there. Check them +After all a tmp. library for the deck is created. It consist only the models +and subckts that were specified in *MOD and *SUB commands. + + + +This is all. +Mslib is _NOT_ a good program. It should automatically recognize what models +or subckts were used and it should be written with flex or bison. Now it +just indicates what is my level of programming in C. +There are some options that You can set for mslib in datadef.h. I tried to +document all of them there, so when want to know more look to the sources. + +And one more thing. There is a perl program "spiceprm" that lets You use +parameters in subckts. Many Intusoft's libraries use this feature. To use +parameters I have written a small shell script "libprm". This program +automatic runs spiceprm and mslib on Your's deck to give a working spice +input file. To see how this all works please read "libprm_readme" and +spiceprm readme. + + + + \ No newline at end of file diff --git a/contrib/scripts/COPYING b/contrib/scripts/COPYING new file mode 100644 index 000000000..5c573038e --- /dev/null +++ b/contrib/scripts/COPYING @@ -0,0 +1,5 @@ +These scripts are free for everyone who think that they might by useful for +him. If someone makes them better please e-mail me. + +Michael Widlok +widlok@uci.agh.edu.pl \ No newline at end of file diff --git a/contrib/scripts/liblook b/contrib/scripts/liblook new file mode 100755 index 000000000..5d56e3e26 --- /dev/null +++ b/contrib/scripts/liblook @@ -0,0 +1,77 @@ +#!/bin/sh +#set -x -v + +# MW. Lib search / show program + +# usage liblook libname [text_to_find] [l_before] [l_after] + +LIBPATH=/usr/local/lib + +function trapper() + { + echo User break! + echo Exiting . . . + unset LIBPATH + exit 1 + } + +trap trapper SIGINT SIGQUIT + +function operror() + { + echo Incorrect parameters: $*, $# + echo Usage: liblook libname [text_to_find] [l_before] [l_after] + unset LIBPATH + exit 2 + } + +function showlib() + { + if test -f $LIBPATH/$1; then + less $LIBPATH/$1; exit 0; fi + + if test -f [C./$1; then + less ./$1; exit 0; fi + + echo Searching $1 in ~/ . . . + less $(find ~/ -name $1) + } + +function searchlib() + { + if test -f $LIBPATH/$1; then + echo File: $LIBNMAE; echo; + grep -B"$3" -A"$4" --ignore-case -e "$2" $LIBPATH/$LIBNAME1; + echo; exit 0; fi + + if test -f ./$1; then + echo File: $1; echo; + grep -B"$3" -A"$4" --ignore-case -e "$2" ./$1; + echo; exit 0; fi + +#if *.lib or sth like this + + echo Searching $1 in ~/ . . .;echo; + if (grep -B"$3" -A"$4" --ignore-case -e "$2" $(find ~/ -name $1)); then + echo; exit 0; fi + + echo Searching $1 in $LIBPATH;echo; + if (grep -B"$3" -A"$4" --ignore-case -e "$2" $(find $LIBPATH -name $1)); then + echo; exit 0; fi + + } + + +# Main body +if test $# -lt 1 -o $# -gt 4; then operror $*; fi + +case $# in +1) showlib $*;; +2) searchlib $1 $2 2 2;; +3) searchlib $1 $2 $3 2;; +4) searchlib $1 $2 $3 $4;; +esac + +unset LIBPATH +exit 0 + diff --git a/contrib/scripts/liblook_readme b/contrib/scripts/liblook_readme new file mode 100644 index 000000000..44f284fed --- /dev/null +++ b/contrib/scripts/liblook_readme @@ -0,0 +1,9 @@ +Liblook is a script that can show specified model or sub-circuit entry in +spice library. Common use look like this: + +liblook lib_name [text_to_find] [lines_before] [lines_after] + +lines_before and lines_after are used when you want to specify how many lines +you want to see before or after given text. Look to he source for more +details. + diff --git a/contrib/scripts/libprm b/contrib/scripts/libprm new file mode 100755 index 000000000..1a4660668 --- /dev/null +++ b/contrib/scripts/libprm @@ -0,0 +1,58 @@ +#!/bin/sh +#set -x -v + +# MW. Lip / Param parsing program for spice + +# -n normal, -f full (keep everything), -r replace original file + +export TMPLP=/tmp/LibPrm.$$- + +function trapper() + { + echo User break! + echo Exiting . . . + rm -f -v ${TMPLP}* + unset TMPLP + exit 1 + } + +trap trapper SIGINT SIGQUIT + +function operror() + { + echo Incorrect parameters: $*, $# + unset TMPLP + exit 2 + } + +function repnormpl() + { + mslib $1 ${TMPLP}1 + sed -n -e 'p' -e "1r ${TMPLP}1" $1 >${TMPLP}2 + spiceprm ${TMPLP}2 $2 + } + +function keepall() + { + mslib $1 + sed -n -e 'p' -e "1r $1.lib" $1 >${TMPLP}2 + spiceprm ${TMPLP}2 $2 + } + + +# Main body +if test $# -lt 2 -o $# -gt 3; then operror $*; fi + +case $1$# in +-r3) operror $*;; +-n2) repnormpl $2 ${2%.cir}.ckt;; +-n3) repnormpl $2 $3;; +-r2) repnormpl $2 $2;; +-f2) keepall $2 ${2%.cir}.ckt;; +-f3) keepall $2 $3;; +esac + +rm -f ${TMPLP}* +unset TMPLP +exit 0 + diff --git a/contrib/scripts/libprm_readme b/contrib/scripts/libprm_readme new file mode 100644 index 000000000..f11b8478c --- /dev/null +++ b/contrib/scripts/libprm_readme @@ -0,0 +1,14 @@ +So, this is my idea of using parametrized subckts with spice. + + First I create an input file like foo.cir and I include commands for +mslib (*MOD, *SUB, *LIB) in it. Then I run "libprm -n foo.cir". Libprm then +runs mslib first to get all models and subckts form given libraries and then +runs spiceprm to evaluate all used parameters. + This works quite right for me, and I hope that You will find my idea +useful. Spiceprm is not my program (I get it from Internet), but I think +that it will better to enclose all used programs in this packet. Spiceprm +has it's own directory with very good readme and examples. If You want to +find out more about libprm or mslib look for the source code. These are rather +short and easy programs - they are all that I could write in quite short +time. + \ No newline at end of file diff --git a/contrib/spiceprm/CHANGES b/contrib/spiceprm/CHANGES new file mode 100644 index 000000000..9988a99b6 --- /dev/null +++ b/contrib/spiceprm/CHANGES @@ -0,0 +1,18 @@ +---------------------------------------------------------------------- + Version 0.11 January 2, 1996 +---------------------------------------------------------------------- +No new features. + +Bug Fixes - +----------- + +1. Duplicate name clash problem with parameterized subckt calls from +within a .subckt....ends block. + +2. Writing continuation lines to the output file occaisionally choked. + + +---------------------------------------------------------------------- + Version 0.10 October 10, 1996 +---------------------------------------------------------------------- +Original release. diff --git a/contrib/spiceprm/COPYING b/contrib/spiceprm/COPYING new file mode 100644 index 000000000..e77696ae8 --- /dev/null +++ b/contrib/spiceprm/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/spiceprm/EXAMPLES b/contrib/spiceprm/EXAMPLES new file mode 100644 index 000000000..ea588adab --- /dev/null +++ b/contrib/spiceprm/EXAMPLES @@ -0,0 +1,176 @@ +**************************************************************** +* Pi attenuator pad. +* Parameters: R0 = impedance +* DB = attenuation in dB (positive) +.SUBCKT PIPAD 1 2 { R0 DB } +R1 1 0 {R0*(1+2/(10**(DB/20)-1))} +R2 1 2 {(R0/2)*(10**(DB/20)-10**(DB/-20))} +R3 2 0 {R0*(1+2/(10**(DB/20)-1))} +.ENDS +**************************************************************** +* PCB Via inductance + extra L. +* H = substrate height in inches +* D = via diameter in inches +* L = extra inductance in henries. +.SUBCKT VIA 1 2 { H D L } +LV 1 2 {L+ ++ 5.08E-9*H*(log((2+sqrt(4+D*D/(H*H)))*H/D)+ ++ .75*(D/H-sqrt(4+D*D/(H*H))))} +.ENDS +**************************************************************** +* Voltage-controlled oscillator. +* Parameters: F = frequency @ Vc = 0 in Hz +* KV = tuning sensitivity in Hz/volt +* A = peak output amplitude +* RO = output port resistance +* Connections: Vc Out +.SUBCKT VCO 20 2 { F KV A RO } +RIN1 20 0 1E12 +VSW 30 0 DC 0 PULSE 0 1 +RSW 30 0 1E12 +BIN 3 0 V=(V(20)+{F/KV})*V(30) +R3 3 0 1E6 +GSIN 2 0 22 0 {1/RO} +RSIN 2 0 {RO} +B1 1 0 I=-(V(22)*V(3)) +B2 22 0 I=V(1)*V(3) +R2 1 0 1E9 +I1 0 1 PULSE {1E-9*A} 0 +C2 1 0 {.159154943/KV} +C1 22 0 {.159154943/KV} +R1 22 0 1E9 +.ENDS +**************************************************************** +* Ideal Frequency converter. +* Parameters: F = Oscillator frequency +* RI = input port resistance +* RO = output port resistance +* Connections: In Out +.SUBCKT FCNVT 1 2 { F RI RO } +RIN 1 0 {RI} +VLO 3 0 DC 0 SIN 0 1 {F} +RLO 3 0 1E12 +BMIX 0 2 I=(V(1)*V(3))/{RO} +RO 2 0 {RO} +.ENDS +**************************************************************** +* Sine wave RF power source. +* Parameters: F = Frequency +* R = Output resistance +* P = Power in dBm +* V = DC (EMF) +.SUBCKT RFGEN 1 2 { F R P V } +* + - +Is 2 1 DC {V/R} SIN {V/R} {sqrt((10**(P/10))/(125*R))} {F} +Ro 1 2 {R} +.ENDS +**************************************************************** +* Sine wave 2-tone RF power source. +* Parameters: F1 = 1st tone frequency +* F2 = 2nd tone frequency +* R = output resistance +* P = power per tone in dBm +* V = DC (EMF) +.SUBCKT 2TGEN 1 2 { F1 F2 R P V } +* + - +I1 2 1 DC {V/R} SIN {V/R} {sqrt((10**(P/10))/(125*R))} {F1} +I2 2 1 DC 0 SIN 0 {sqrt((10**(P/10))/(125*R))} {F2} +Ro 1 2 {R} +.ENDS +**************************************************************** +* Transmission lines +* All ports must have external connections. +* Parameters: Z0 = impedance +* L = length in inches +* VP = velocity-of-propagation rel. to air +* Connections: 1+ 1- 2+ 2- +.SUBCKT TXL 1 2 3 4 { Z0 L VP } +T1 1 2 3 4 Z0={Z0} TD={L/(1.180315E10*VP)} +.ENDS +**************************************************************** +* Lossy transmission line. +* All ports must have external connections. +* Parameters: Z0 = impedance +* L = length in inches +* VP = velocity-of-propagation rel. to air +* A = loss in dB/inch +* Connections: 1+ 1- 2+ 2- +.SUBCKT LTXL 1 2 3 4 { Z0 L VP A } +O1 1 2 3 4 LOSSY +.MODEL LOSSY LTRA LEN={L} ++ R={5.848492e-3*A*Z0} ++ L={Z0/(1.180315E10*VP)} ++ C={1/(1.180315E10*VP*Z0)} +.ENDS +**************************************************************** +* 2 coupled transmission lines +* All ports must have external connections. +* Parameters: Z0E = even-mode impedance +* Z0O = odd-mode impedance +* L = length in inches +* VP = velocity-of-propagation rel. to air +* Connections: 1+ 1- 2+ 2- { Z0E Z0O L VP } +.SUBCKT CPL2 1 2 3 4 +T1 1 0 3 0 Z0={Z0E} TD={L/(1.180315E10*VP)} +T2 1 2 3 4 Z0={2*Z0E*Z0O/(Z0E-Z0O)} TD={L/(1.180315E10*VP)} +T3 2 0 4 0 Z0={Z0E} TD={L/(1.180315E10*VP)} +.ENDS +**************************************************************** +* Generic Bipolar OpAmp - linear model +* Parameters: G = open-loop gain in dB +* FT = unity gain frequency in Hz +* IOS = input offset current in amps +* VOS = input offset voltage +* IB = input bias current in amps +.SUBCKT BIPOPA 2 3 6 7 4 { G FT IOS VOS IB } +* - In + Out Vcc Vee +RP 4 7 10K +RXX 4 0 10MEG +IBP 3 0 {IB-IOS} +RIP 3 0 10MEG +CIP 3 0 1.4PF +IBN 2 0 {IB} +RIN 2 0 10MEG +CIN 2 0 1.4PF +VOFST 2 10 {VOS} +RID 10 3 200K +EA 11 0 10 3 1 +R1 11 12 5K +R2 12 13 50K +C1 12 0 {13E-6/FT} +GA 0 14 0 13 {0.0135*(10**(G/20))} +C2 13 14 {2.7E-6/FT} +RO 14 0 75 +L 14 6 {30/FT} +RL 14 6 1000 +CL 6 0 3PF +.ENDS +**************************************************************** +* Generic FET OpAmp - linear model +* Parameters: G = open-loop gain in dB +* FT = unity gain frequency in Hz +* VOS = input offset voltage +.SUBCKT FETOPA 2 3 6 7 4 { G FT VOS } +* - In + Out Vcc Vee +RP 4 7 6K +RXX 4 0 10MEG +IBP 3 0 33E-12 +RIP 3 0 1E12 +CIP 3 0 3PF +IBN 2 0 30E-12 +RIN 2 0 1E12 +CIN 2 0 3PF +VOFST 2 10 {VOS} +RID 10 3 1E12 +EA 11 0 10 3 1 +R1 11 12 5K +R2 12 13 50K +C1 12 0 {24E-6/FT} +GA 0 14 0 13 {0.0135*(10**(G/20))} +C2 13 14 {2.33E-6/FT} +RO 14 0 75 +L 14 6 {4E-6/FT} +RL 14 6 100 +CL 6 0 3PF +.ENDS +**************************************************************** diff --git a/contrib/spiceprm/README b/contrib/spiceprm/README new file mode 100644 index 000000000..186a2d94a --- /dev/null +++ b/contrib/spiceprm/README @@ -0,0 +1,216 @@ +------------------------------------------------------------------------ +SPICEPRM - A Spice preprocessor for parameterized subcircuits (v 0.11) +Copyright (C) 1996 Andrew J. Borsa +------------------------------------------------------------------------ + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +------------------------------------------------------------------------ + +Spiceprm was written in the course of moving my engineering activities +to the Linux operating system. My previous MSDOS spice package +permitted passing parameters to subcircuits. The raw Berkely Spice +doesn't. Anyone used to this feature knows the frustration of trying +to use a simulator without it. This script is the result of my +desperation. It translates a circuit file containing parameterized +subcircuits with math expressions into another circuit file meeting raw +spice requirements. You then run spice on the translated output file. + +This is an alpha version. It probably has some bugs I haven't caught. +But I have used it in a work environment enough to feel comfortable +about releasing it for comments and improvement suggestions. + + +What's So Great About Subcircuits With Parameters? +-------------------------------------------------- +1. You can generalize a model once and then use it without having to +recalculate values of it's internal elements every time. + +2. Many electronic devices can be modelled by using mathematical +expressions. The independent variables can be passed to the model as +parameters, evaluated in equations, and used to set the behavior of a +particular model instance. + +3. They save mucho time and minimize human calculation error. + + +Installation +------------ +1. Copy the executable script to an accessible directory. I keep mine +in $HOME/bin so it's on my path. + +2. Modify the top line if necessary to reflect the path to your Perl +interpreter. +For ex., #! /usr/bin/perl may have to become #! /usr/local/bin/perl or +wherever the perl binary is located. + + +Usage +----- +spiceprm infile [outfile] + + infile: Circuit file name containing parameterized subcircuits. + outfile: Transformed file meeting raw spice netlist conventions. + Optional. If not given, output is produced on standard + output (stdout). + + My file name convention: infile = *.cir, outfile = *.ckt + + infile == outfile isn't permitted for a coupla good reasons, the + best being you don't want to trash your original source. + +Now source outfile from spice. + +I always check the output from a new infile just to make sure. This +version only checks for a few obvious errors, so scanning outfile for +reasonable looking values and netlist correctness is wise. Note that +comment and blank lines are discarded in outfile and alphabetic +characters are transformed to lower case. + + +Parameterized Subcircuit Netlist Convention +------------------------------------------- +Calling a parameterized subcircuit works similarly to a normal spice call +except for the addition of a {} delimited list of parameter value +assignments - + +Xname n1 n2 n3 ... ni subname {p1 = val1 ... pj = valj} + p1 thru pj are the parameter assignments to be passed to the + subcircuit. + val is any valid spice value. + {} (braces) must enclose the parameter assignment sequence. + +After running the preprocessor on this file, each call in the netlist +will be replaced by the following - + +Xname n1 n2 n3 ... ni subname#k +*{p1 = val1 ... pj = valj} + where k is a digit or digits representing a subcircuit with that + specific set of parameter substitutions. k will be incremented for + each unique set of parameters and matched by a new .subckt listing + named subname#k as follows - + + .subckt subname#k n1 n2 n3 ... ni + ... listing with parameters substituted and equations evaluated + .ends + + +Creating Parameterized Subcircuits +---------------------------------- +Below is a simple example. See the EXAMPLES file for a number of +illustrative and useful models for Spice3. + +This model creates an RF power source specified using the natural +output power units of dBm (dB referenced to 1 milliwatt). Note that +the model parameters must be declared on the ".subckt" definition line +inside curly braces {}. +**************************************************************** +* Sine wave RF power source. +* Parameters: F = Frequency +* R = Output resistance +* P = Power in dBm +* V = DC (EMF) +.SUBCKT RFGEN 1 2 {F R P V} +* + - +Is 2 1 DC {V/R} SIN {V/R} {sqrt((10**(P/10))/(125*R))} {F} +Ro 1 2 {R} +.ENDS +**************************************************************** +Note that independent current source Is has it's literal spice +parameters replaced by equations that calculate the required values +from the passed parameters. Each equation must be enclosed by {} to +inform the preprocessor that a substitution and calculation must be +performed for whatever appears between the braces. + +Equations may span multiple lines by using the spice line continuation +symbol "+" as the first character of the following line. + +.MODEL statements inside subcircuits may also use passed parameters. +In fact, anything between {} inside a subcircuit will be evaluated and +replaced with a result. + +Be careful in situations like the following: + Bx 3 0 v = {v(1)*sgn(v(2))*frick/frack} WRONG!!! + + The Spice3 nonlinear source element "B" also accepts equations + describing it's output dependency on functions of circuit voltages + and currents. If "frick" and "frack" are parameters, you must + separate them from the element's equation as follows - + Bx 3 0 v = v(1)*sgn(v(2))*{frick/frack} + + Just remember that preprocessor equations and spice functions must + never meld. + +The parameter substitution first replaces all parameters between any {} +with their numerical values and then uses Perl's eval() function to +produce a final numerical value. Theoretically at least, you could +execute a Perl program within those braces. I haven't explored this +yet so feel free. Realize though, that whatever's inside the braces +gets a ";" appended at the end to make a valid Perl statement from the +usual equation. Also, Perl's block delimiters are braces, so extra +one's could confuse the current parsing which is simply oriented to +equations. Ah well. + + +Known Bugs, Anomalies, and Perl Gotcha's +---------------------------------------- +1. Minimal error checking! Be forewarned! + +2. Don't use ".ends subckt_name" with parameters. Use ".ends" only. +The preprocessor modifies subckt_name to subckt_name#k. + +3. Spice unit representations like "k", "meg", etc, are not recognized +inside the {} equation sections of .subckt listings. They may, +however, be used in the parameter assignment section of a .subckt call. + +4. "-" as part of .subckt name doesn't work but "_" does. Stick to +alphanumeric names with optional underscore characters. + +5. Equations must use Perl math operators and functions. + The following lists operator differences I'm aware of - + + Exponentiation - Perl : ** + Spice3 : ^ + + Logical AND, OR - Perl : &&, || + Spice3 : &, | + + Equality, Inequality - Perl : ==, != + Spice3 : =, <> + + These operators are the same for Perl and Spice3 - + + - * / % ! < > <= >= + + These operators are unique to Perl - + & | ^ ~ : bitwise AND, OR, exclusive OR, complement + + Perl math functions - + abs(EXPR) : absolute value of EXPR + atan2(Y,X) : arctangent of Y/X in the range of -pi to +pi + cos(EXPR) : cosine of EXPR in radians + exp(EXPR) : e raised to EXPR + int(EXPR) : integer portion of EXPR + log(EXPR) : natural logarithm (base e) of EXPR + rand[(EXPR)]: returns a random fractional number between 0 and the + value of EXPR. If EXPR is omitted, returns a value + between 0 and 1. + sin(EXPR) : sine of EXPR in radians + sqrt(EXPR) : square root of EXPR + + +Finally, if you could make use of a language allowing you to do neat +things like this with minimal pain, give Perl a try. It's naturally +suited for text processing and transformation tasks like pre and post +processors, along with any math manipulation required. diff --git a/contrib/spiceprm/spiceprm b/contrib/spiceprm/spiceprm new file mode 100755 index 000000000..71fc5b93a --- /dev/null +++ b/contrib/spiceprm/spiceprm @@ -0,0 +1,304 @@ +#! /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 : ); + $linenum = $.; + while ($nxtline = ) { + 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; + } + 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; + } +} diff --git a/contrib/spiceprm/spiceprm-0.11.lsm b/contrib/spiceprm/spiceprm-0.11.lsm new file mode 100644 index 000000000..448b11a07 --- /dev/null +++ b/contrib/spiceprm/spiceprm-0.11.lsm @@ -0,0 +1,19 @@ +Begin3 +Title: spiceprm-0.11.tar.gz +Version: 0.11 +Entered-date: 02JAN97 +Description: A Perl script preprocessor adding parameterized + subcircuit capability to the Berkeley Spice circuit + simulator. Should also work with any spice lacking + this feature. +Keywords: spice cad simulation preprocessor perl script +Author: andy@moose.mv.com (Andy Borsa) +Maintained-by: +Primary-site: sunsite.unc.edu /pub/Linux/apps/circuits + 15.6kB spiceprm-0.11.tar.gz +Alternate-site: +Original-site: +Platforms: Linux or most any unix, Perl 4 or greater. + Tested with Linux and Perl 5. +Copying-policy: GNU General Public License. See file COPYING. +End diff --git a/doc/ChangeLog b/doc/ChangeLog new file mode 100644 index 000000000..718e27a8f --- /dev/null +++ b/doc/ChangeLog @@ -0,0 +1,11 @@ +1999-09-06 Arno Peters + + * ngspice.texi: Added TeX equivalents for some formula. + First tables converted to texinfo format. + +1999-08-31 Emmanuel Rouat + + * Makefile.am: added .texi file by Arno Peters - a distribution will now + include a postscript doc. + updated 'clean' rules + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 000000000..88fd2f6a7 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,11 @@ +## Process this file with automake to produce Makefile.in + +EXTRA_DIST = ngspice.ps + +info_TEXINFOS = ngspice.texi + +CLEANFILES = *.fns *.pg *.tp *.aux *.cp *.ky *.vr *.fn *.log *.toc *.vrs + +DISTCLEANFILES = $CLEANFILES *.ps *.dvi *.info* + +MAINTAINERCLEANFILES = $DISTCLEANFILES Makefile.in diff --git a/doc/ngspice.texi b/doc/ngspice.texi new file mode 100644 index 000000000..f309c901e --- /dev/null +++ b/doc/ngspice.texi @@ -0,0 +1,8496 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename ngspice.info +@settitle SPICE User Manual +@setchapternewpage odd +@c %**end of header + +@ifinfo +This file documents SPICE. + +Copyright 1996 The Regents of the University of California. + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research and non-profit purposes, +without fee, and without a written agreement is hereby granted, +provided that the above copyright notice, this paragraph and the +following three paragraphs appear in all copies. + +This software program and documentation are copyrighted by The Regents +of the University of California. The software program and +documentation are supplied "as is", without any accompanying services +from The Regents. The Regents does not warrant that the operation of +the program will be uninterrupted or error-free. The end-user +understands that the program was developed for research purposes and +is advised not to rely exclusively on the program for any reason. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND +ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF +CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +@end ifinfo + +@c This title page illustrates only one of the +@c two methods of forming a title page. + +@titlepage +@title SPICE User Manual +@c @subtitle SUBTITLE-IF-ANY +@c @subtitle SECOND-SUBTITLE +@author + +@c The following two commands +@c start the copyright page. +@page +@vskip 0pt plus 1filll +Copyright 1996 The Regents of the University of California. + +@c Published by ... + +Permission to use, copy, modify, and distribute this software and its +documentation for educational, research and non-profit purposes, +without fee, and without a written agreement is hereby granted, +provided that the above copyright notice, this paragraph and the +following three paragraphs appear in all copies. + +This software program and documentation are copyrighted by The Regents +of the University of California. The software program and +documentation are supplied "as is", without any accompanying services +from The Regents. The Regents does not warrant that the operation of +the program will be uninterrupted or error-free. The end-user +understands that the program was developed for research purposes and +is advised not to rely exclusively on the program for any reason. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND +ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF +CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE +MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +@end titlepage + + +@node Top, Introduction, (dir), (dir) + +@ifinfo +This document describes ... + +This document applies to version ... +of the program named ... +@end ifinfo + +@menu +* Introduction:: +* Circuit Description:: +* Circuit Elements and Models:: +* Analyses and Output Control:: +* Interactive Interpreter:: +* Bibliography:: +* Example Circuits:: +* Model and Device Parameters:: +@end menu + +@c @node First Chapter, Second Chapter, top, top +@c @comment node-name, next, previous, up +@c @chapter First Chapter +@c @cindex Index entry for First Chapter + + +@node Introduction, Circuit Description, Top, Top +@comment node-name, next, previous, up +@chapter Introduction + +SPICE is a general-purpose circuit simulation program for nonlinear +dc, nonlinear transient, and linear ac analyses. Circuits may contain +resistors, capacitors, inductors, mutual inductors, independent +voltage and current sources, four types of dependent sources, lossless +and lossy transmission lines (two separate implementations), switches, +uniform distributed RC lines, and the five most common semiconductor +devices: diodes, BJTs, JFETs, MESFETs, and MOSFETs. + +The SPICE3 version is based directly on SPICE 2G.6. While SPICE3 is +being developed to include new features, it continues to support those +capabilities and models which remain in extensive use in the SPICE2 +program. + +SPICE has built-in models for the semiconductor devices, and the user +need specify only the pertinent model parameter values. The model for +the BJT is based on the integral-charge model of Gummel and Poon; +however, if the Gummel- Poon parameters are not specified, the model +reduces to the simpler Ebers-Moll model. In either case, +chargestorage effects, ohmic resistances, and a current-dependent +output conductance may be included. The diode model can be used for +either junction diodes or Schottky barrier diodes. The JFET model is +based on the FET model of Shichman and Hodges. Six MOSFET models are +implemented: MOS1 is described by a square-law I-V characteristic, +MOS2 [1] is an analytical model, while MOS3 [1] is a semi-empirical +model; MOS6 [2] is a simple analytic model accurate in the +shortchannel region; MOS4 [3, 4] and MOS5 [5] are the BSIM (Berkeley +Short-channel IGFET Model) and BSIM2. MOS2, MOS3, and MOS4 include +second-order effects such as channel-length modulation, subthreshold +conduction, scattering-limited velocity saturation, small-size +effects, and chargecontrolled capacitances. + +@menu +* Types of Analysis:: +* Analysis at Different Temperatures:: +* Convergence:: +@end menu + + +@node Types of Analysis, Analysis at Different Temperatures, Introduction, Introduction +@section Types of Analysis + +@menu +* DC Analysis:: +* AC Small-Signal Analysis:: +* Transient Analysis:: +* Pole-Zero Analysis:: +* Small-Signal Distortion Analysis:: +* Sensitivity Analysis:: +* Noise Analysis:: +@end menu + + +@node DC Analysis, AC Small-Signal Analysis, Types of Analysis, Types of Analysis +@subsection DC Analysis + + +The dc analysis portion of SPICE determines the dc operating point of +the circuit with inductors shorted and capacitors opened. The dc +analysis options are specified on the .DC, .TF, and .OP control lines. +A dc analysis is automatically performed prior to a transient analysis +to determine the transient initial conditions, and prior to an ac +small-signal analysis to determine the linearized, small-signal models +for nonlinear devices. If requested, the dc small-signal value of a +transfer function (ratio of output variable to input source), input +resistance, and output resistance is also computed as a part of the dc +solution. The dc analysis can also be used to generate dc transfer +curves: a specified independent voltage or current source is stepped +over a user-specified range and the dc output variables are stored for +each sequential source value. + + +@node AC Small-Signal Analysis, Transient Analysis, DC Analysis, Types of Analysis +@subsection AC Small-Signal Analysis + + +The ac small-signal portion of SPICE computes the ac output variables +as a function of frequency. The program first computes the dc +operating point of the circuit and determines linearized, small-signal +models for all of the nonlinear devices in the circuit. The resultant +linear circuit is then analyzed over a user-specified range of +frequencies. The desired output of an ac small-signal analysis is +usually a transfer function (voltage gain, transimpedance, etc). If +the circuit has only one ac input, it is convenient to set that input +to unity and zero phase, so that output variables have the same value +as the transfer function of the output variable with respect to the +input. + + +@node Transient Analysis, Pole-Zero Analysis, AC Small-Signal Analysis, Types of Analysis +@subsection Transient Analysis + +The transient analysis portion of SPICE computes the transient output +variables as a function of time over a user-specified time interval. +The initial conditions are automatically determined by a dc analysis. +All sources which are not time dependent (for example, power supplies) +are set to their dc value. The transient time interval is specified +on a .TRAN control line. + + +@node Pole-Zero Analysis, Small-Signal Distortion Analysis, Transient Analysis, Types of Analysis +@subsection Pole-Zero Analysis + + +The pole-zero analysis portion of SPICE computes the poles and/or +zeros in the small-signal ac transfer function. The program first +computes the dc operating point and then determines the linearized, +small-signal models for all the nonlinear devices in the circuit. +This circuit is then used to find the poles and zeros of the transfer +function. + +Two types of transfer functions are allowed: one of the form (output +voltage)/(input voltage) and the other of the form (output +voltage)/(input current). These two types of transfer functions cover +all the cases and one can find the poles/zeros of functions like +input/output impedance and voltage gain. The input and output ports +are specified as two pairs of nodes. + +The pole-zero analysis works with resistors, capacitors, inductors, +linear-controlled sources, independent sources, BJTs, MOSFETs, JFETs +and diodes. Transmission lines are not supported. + +The method used in the analysis is a sub-optimal numerical search. +For large circuits it may take a considerable time or fail to find all +poles and zeros. For some circuits, the method becomes "lost" and +finds an excessive number of poles or zeros. + + +@node Small-Signal Distortion Analysis, Sensitivity Analysis, Pole-Zero Analysis, Types of Analysis +@subsection Small-Signal Distortion Analysis + + +The distortion analysis portion of SPICE computes steady-state +harmonic and intermodulation products for small input signal +magnitudes. If signals of a single frequency are specified as the +input to the circuit, the complex values of the second and third +harmonics are determined at every point in the circuit. If there are +signals of two frequencies input to the circuit, the analysis finds +out the complex values of the circuit variables at the sum and +difference of the input frequencies, and at the difference of the +smaller frequency from the second harmonic of the larger frequency. + +Distortion analysis is supported for the following nonlinear devices: +diodes (DIO), BJT, JFET, MOSFETs (levels 1, 2, 3, 4/BSIM1, 5/BSIM2, +and 6) and MESFETS. All linear devices are automatically supported by +distortion analysis. If there are switches present in the circuit, +the analysis continues to be accurate provided the switches do not +change state under the small excitations used for distortion +calculations. + + +@node Sensitivity Analysis, Noise Analysis, Small-Signal Distortion Analysis, Types of Analysis +@subsection Sensitivity Analysis + + +Spice3 will calculate either the DC operating-point sensitivity or the +AC small-signal sensitivity of an output variable with respect to all +circuit variables, including model parameters. Spice calculates the +difference in an output variable (either a node voltage or a branch +current) by perturbing each parameter of each device independently. +Since the method is a numerical approximation, the results may +demonstrate second order affects in highly sensitive parameters, or +may fail to show very low but non-zero sensitivity. Further, since +each variable is perturb by a small fraction of its value, zero-valued +parameters are not analyized (this has the benefit of reducing what is +usually a very large amount of data). + + +@node Noise Analysis, , Sensitivity Analysis, Types of Analysis +@subsection Noise Analysis + + +The noise analysis portion of SPICE does analysis device-generated +noise for the given circuit. When provided with an input source and +an output port, the analysis calculates the noise contributions of +each device (and each noise generator within the device) to the output +port voltage. It also calculates the input noise to the circuit, +equivalent to the output noise referred to the specified input source. +This is done for every frequency point in a specified range - the +calculated value of the noise corresponds to the spectral density of +the circuit variable viewed as a stationary gaussian stochastic +process. + +After calculating the spectral densities, noise analysis integrates +these values over the specified frequency range to arrive at the total +noise voltage/current (over this frequency range). This calculated +value corresponds to the variance of the circuit variable viewed as a +stationary gaussian process. + +@node Analysis at Different Temperatures, Convergence, Types of Analysis, Introduction +@section Analysis at Different Temperatures + +All input data for SPICE is assumed to have been measured at a nominal +temperature of 27°C, which can be changed by use of the TNOM +parameter on the .OPTION control line. This value can further be +overridden for any device which models temperature effects by +specifying the TNOM parameter on the model itself. The circuit +simulation is performed at a temperature of 27°C, unless +overridden by a TEMP parameter on the .OPTION control line. +Individual instances may further override the circuit temperature +through the specification of a TEMP parameter on the instance. + +Temperature dependent support is provided for resistors, diodes, +JFETs, BJTs, and level 1, 2, and 3 MOSFETs. BSIM (levels 4 and 5) +MOSFETs have an alternate temperature dependency scheme which adjusts +all of the model parameters before input to SPICE. For details of the +BSIM temperature adjustment, see [6] and [7]. + + +Temperature appears explicitly in the exponential terms of the BJT and +diode model equations. In addition, saturation currents have a +built-in temperature dependence. The temperature dependence of the +saturation current in the BJT models is determined by: + +@tex +$$ + I_S(T_1) = I_S(T_0) \left|T_1 \over T_0\right|^{XTI} + \exp \left| E_g q(T_1 T_0) \over k (T_1 - T_0) \right| +$$ +@end tex +@ifnottex +@example + XTI + |T | | E q(T T )| + 1 g 1 0 + I (T ) = I (T ) |--| exp|-----------| + S 1 S 0 + |T | |k (T - T )| + 0 1 0 +@end example +@end ifnottex + +where k is Boltzmann's constant, q is the electronic charge, E is the +energy gap which is a model parameter, G and XTI is the saturation +current temperature exponent (also a model parameter, and usually +equal to 3). + + + +The temperature dependence of forward and reverse beta is according to +the formula: + +@tex +$$ + B(T_1) = B(T_0) \left| T_1 \over T_0 \right|^{XTB} +$$ +@end tex +@ifnottex +@example + XTB + |T | + 1 + B(T ) = B(T ) |--| + 1 0 + |T | + 0 +@end example +@end ifnottex + + +where T and T are in degrees Kelvin, and XTB is a user-supplied model +parameter. Temperature effects on beta are carried out by appropriate +adjustment to the values of B_F , I_SE , B_R , and I_SC (spice model +parameters BF, ISE, BR, and ISC, respectively). + + + +Temperature dependence of the saturation current in the junction diode +model is determined by: + + +@tex +$$ + I_S(T_1) = I_S(T_0) \left| T_1 \over T_0 \right|^{XTI \over N} + \exp \left| E_g q(T_1 T_0) \over N k (T_1 - T_0) \right| +$$ +@end tex +@ifnottex +@example + XTI + --- + N + |T | | E q(T T ) | + 1 g 1 0 + I (T ) = I (T ) |--| exp|-------------| + S 1 S 0 + |T | |N k (T - T )| + 0 1 0 +@end example +@end ifnottex + + +where N is the emission coefficient, which is a model parameter, and the +other symbols have the same meaning as above. Note that for Schottky +barrier diodes, the value of the saturation current temperature +exponent, XTI, is usually 2. + + + +Temperature appears explicitly in the value of junction potential, U +(in spice PHI), for all the device models. The temperature dependence +is determined by: + +@tex +$$ + U(T) = {k T \over q} \log_e \left| N_a N_d \over N_i T^2 \right| +$$ +@end tex +@ifnottex +@example + | N N | + a d + kT |------ | + U(T) = -- log 2 + q e |N (T) | + i +@end example +@end ifnottex + +where k is Boltzmann's constant, q is the electronic charge, N_a is +the acceptor impurity density, N_d is the donor impurity density, N_i +is the intrinsic carrier con centration, and E_g is the energy gap. + + + +Temperature appears explicitly in the value of surface mobility, M_0 +(or UO), for the MOSFET model. The temperature dependence is +determined by: + +@tex +$$ + M_0(T) = {M_0(T_0) \over \left| T \over T_0 \right|^{1.5}} +$$ +@end tex +@ifnottex +@example + M (T ) + 0 0 + M (T) = ------- + 0 1.5 + | T| + |--| + |T | + 0 +@end example +@end ifnottex + +The effects of temperature on resistors is modeled by the formula: + +@tex +$$ + R(T) = R(T_0) \bigl( 1 + TC_1 (T - T_0) + TC_2 (T - T_0)^2 \bigr) +$$ +@end tex +@ifnottex +@example + 2 + R(T) = R(T ) [1 + TC (T - T ) + TC (T - T ) ] + 0 1 0 2 0 +@end example +@end ifnottex + +where T is the circuit temperature, T_0 is the nominal temperature, +and TC_1 and TC_2 are the first- and second order temperature +coefficients. + + + +@node Convergence, , Analysis at Different Temperatures, Introduction +@section Convergence + + +Both dc and transient solutions are obtained by an iterative process +which is terminated when both of the following conditions hold: + +@enumerate + +@item + +The nonlinear branch currents converge to within a tolerance of 0.1% or +1 picoamp (1.0e-12 Amp), whichever is larger. + +@item + +The node voltages converge to within a tolerance of 0.1% or 1 microvolt +(1.0e-6 Volt), whichever is larger. + +@end enumerate + +Although the algorithm used in SPICE has been found to be very +reliable, in some cases it fails to converge to a solution. When this +failure occurs, the program terminates the job. + +Failure to converge in dc analysis is usually due to an error in +specifying circuit connections, element values, or model parameter +values. Regenerative switching circuits or circuits with positive +feedback probably will not converge in the dc analysis unless the OFF +option is used for some of the devices in the feedback path, or the +.NODESET control line is used to force the circuit to converge to the +desired state. + + +@node Circuit Description, Circuit Elements and Models, Introduction, Top +@chapter Circuit Description + +@menu +* General Structure and Conventions:: +* Basics:: +* Device Models:: +* Subcircuits:: +* INCLUDE:: +@end menu + + +@node General Structure and Conventions, Basics, Circuit Description, Circuit Description +@section General Structure and Conventions + +The circuit to be analyzed is described to SPICE by a set of element +lines, which define the circuit topology and element values, and a set +of control lines, which define the model parameters and the run +controls. The first line in the input file must be the title, and the +last line must be ".END". The order of the remaining lines is +arbitrary (except, of course, that continuation lines must immediately +follow the line being continued). + +Each element in the circuit is specified by an element line that +contains the element name, the circuit nodes to which the element is +connected, and the values of the parameters that determine the +electrical characteristics of the element. The first letter of the +element name specifies the element type. The format for the SPICE +element types is given in what follows. The strings XXXXXXX, YYYYYYY, +and ZZZZZZZ denote arbitrary alphanumeric strings. For example, a +resistor name must begin with the letter R and can contain one or more +characters. Hence, R, R1, RSE, ROUT, and R3AC2ZY are valid resistor +names. Details of each type of device are supplied in a following +section. + +Fields on a line are separated by one or more blanks, a comma, an +equal ('=') sign, or a left or right parenthesis; extra spaces are +ignored. A line may be continued by entering a '+' (plus) in column 1 +of the following line; SPICE continues reading beginning with column +2. + +A name field must begin with a letter (A through Z) and cannot contain +any delimiters. + + +A number field may be an integer field (12, -44), a floating point +field (3.14159), either an integer or floating point number followed +by an integer exponent (1e-14, 2.65e3), or either an integer or a +floating point number followed by one of the following scale factors: + +@c TODO: put this in multiple columns. +@ifnottex + @math{@code{T} = 10^12} + @math{@code{G} = 10^9} + @math{@code{Meg} = 10^6} + @math{@code{K} = 10^3} + @math{@code{mil} = 25.4^-6} + @math{@code{m} = 10^-3} + @math{@code{u} = @code{M} = 10^-6} + @math{@code{n} = 10^-9} + @math{@code{p} = 10^-12} + @math{@code{f} = 10^-15} +@end ifnottex +@tex +$$ +\eqalign{\code{T} &= 10^{12} \cr + \code{G} &= 10^9 \cr + \code{Meg} &= 10^6 \cr + \code{K} &= 10^3 \cr + \code{mil} &= 25.4^{-6} \cr + \code{m} &= 10^{-3} \cr + \code{u} = \code{M} &= 10^{-6} \cr + \code{n} &= 10^{-9} \cr + \code{p} &= 10^{-12} \cr + \code{f} &= 10^{-15} \cr} +$$ +@end tex + +Letters immediately following a number that are not scale factors are +ignored, and letters immediately following a scale factor are ignored. +Hence, 10, 10V, 10Volts, and 10Hz all represent the same number, and +M, MA, MSec, and MMhos all represent the same scale factor. Note that +1000, 1000.0, 1000Hz, 1e3, 1.0e3, 1KHz, and 1K all represent the same +number. + +Nodes names may be arbitrary character strings. The datum (ground) +node must be named '0'. Note the difference in SPICE3 where the nodes +are treated as character strings and not evaluated as numbers, thus +'0' and '00' are distinct nodes in SPICE3 but not in SPICE2. The +circuit cannot contain a loop of voltage sources and/or inductors and +cannot contain a cut-set of current sources and/or capacitors. Each +node in the circuit must have a dc path to ground. Every node must +have at least two connections except for transmission line nodes (to +permit unterminated transmission lines) and MOSFET substrate nodes +(which have two internal connections anyway). + + + +@node Basics, Device Models, General Structure and Conventions, Circuit Description +@section Basics: Title Line, Comment Lines and .END Line + + +@menu +* Title Line:: +* END:: +* Comments:: +@end menu + +@node Title Line, END, Basics, Basics +@subsection Title Line + + + Examples: + +@example + POWER AMPLIFIER CIRCUIT + TEST OF CAM CELL +@end example + + +The title line must be the first in the input file. Its contents are +printed verbatim as the heading for each section of output. + + + + +@node END, Comments, Title Line, Basics +@subsection .END Line + + + Examples: + +@example + .END +@end example + + +The "End" line must always be the last in the input + file. Note that the period is an integral part of the + name. + + + + + +@node Comments, , END, Basics +@subsection Comments + + General Form: + +@example + * +@end example + + + Examples: + +@example + * RF=1K Gain should be 100 + * Check open-loop gain and phase margin +@end example + + +The asterisk in the first column indicates that + this line is a comment line. Comment lines may be + placed anywhere in the circuit description. Note that + SPICE3 also considers any line with leading white space + to be a comment. + + + + +@node Device Models, Subcircuits, Basics, Circuit Description +@section Device Models + + General form: + +@example + .MODEL MNAME TYPE(PNAME1=PVAL1 PNAME2=PVAL2 ... ) +@end example + + + Examples: + +@example + .MODEL MOD1 NPN (BF=50 IS=1E-13 VBF=50) +@end example + + + +Most simple circuit elements typically require only a few parameter +values. However, some devices (semiconductor devices in particular) +that are included in SPICE require many parameter values. Often, many +devices in a circuit are defined by the same set of device model +parameters. For these reasons, a set of device model parameters is +defined on a separate .MODEL line and assigned a unique model name. The +device element lines in SPICE then refer to the model name. + +For these more complex device types, each device element line contains +the device name, the nodes to which the device is connected, and the +device model name. In addition, other optional parameters may be +specified for some devices: geometric factors and an initial condition +(see the following section on Transistors and Diodes for more details). + +MNAME in the above is the model name, and type is one of the following +fifteen types: + +@vtable @code + +@item R + +Semiconductor resistor model + +@item C + +Semiconductor capacitor model + +@item SW + +Voltage controlled switch + +@item CSW + +Current controlled switch + +@item URC + +Uniform distributed RC model + +@item LTRA + +Lossy transmission line model + +@item D + +Diode model + +@item NPN + +NPN BJT model + +@item PNP + +PNP BJT model + +@item NJF + +N-channel JFET model + +@item PJF + +P-channel JFET model + +@item NMOS + +N-channel MOSFET model + +@item PMOS + +P-channel MOSFET model + +@item NMF + +N-channel MESFET model + +@item PMF + +P-channel MESFET model +@end vtable + + + +Parameter values are defined by appending the parameter name followed by +an equal sign and the parameter value. Model parameters that are not +given a value are assigned the default values given below for each model +type. Models, model parameters, and default values are listed in the +next section along with the description of device element lines. + + +@node Subcircuits, INCLUDE, Device Models, Circuit Description +@section Subcircuits + + +A subcircuit that consists of SPICE elements can be defined and +referenced in a fashion similar to device models. The subcircuit is +defined in the input file by a grouping of element lines; the program +then automatically inserts the group of elements wherever the subcircuit +is referenced. There is no limit on the size or complexity of +subcircuits, and subcircuits may contain other subcircuits. An example +of subcircuit usage is given in Appendix A. + + + +@menu +* SUBCKT:: +* ENDS:: +* Subcircuit Calls:: +@end menu + +@node SUBCKT, ENDS, Subcircuits, Subcircuits +@subsection .SUBCKT Line + + General form: + +@example + .SUBCKT subnam N1 +@end example + + + Examples: + +@example + .SUBCKT OPAMP 1 2 3 4 +@end example + + + +A circuit definition is begun with a .SUBCKT line. SUBNAM is the +subcircuit name, and N1, N2, ... are the external nodes, which cannot +be zero. The group of element lines which immediately follow the +.SUBCKT line define the subcircuit. The last line in a subcircuit +definition is the .ENDS line (see below). Control lines may not +appear within a subcircuit definition; however, subcircuit definitions +may contain anything else, including other subcircuit definitions, +device models, and subcircuit calls (see below). Note that any device +models or subcircuit definitions included as part of a subcircuit +definition are strictly local (i.e., such models and definitions are +not known outside the subcircuit definition). Also, any element nodes +not included on the .SUBCKT line are strictly local, with the +exception of 0 (ground) which is always global. + + + + +@node ENDS, Subcircuit Calls, SUBCKT, Subcircuits +@subsection ENDS Line + + General form: + +@example + .ENDS +@end example + + + Examples: + +@example + .ENDS OPAMP +@end example + + +The "Ends" line must be the last one for any subcircuit definition. The +subcircuit name, if included, indicates which subcircuit definition is +being terminated; if omitted, all subcircuits being defined are +terminated. The name is needed only when nested subcircuit definitions +are being made. + + + +@node Subcircuit Calls, , ENDS, Subcircuits +@subsection Subcircuit Calls + + General form: + +@example + XYYYYYYY N1 SUBNAM +@end example + + + Examples: + +@example + X1 2 4 17 3 1 MULTI +@end example + + +Subcircuits are used in SPICE by specifying pseudo-elements beginning +with the letter X, followed by the circuit nodes to be used in expanding +the subcircuit. + + + + +@node INCLUDE, , Subcircuits, Circuit Description +@section INCLUDE + + General form: + +@example + .INCLUDE filename +@end example + + + Examples: + +@example + .INCLUDE /users/spice/common/wattmeter.cir +@end example + + +Frequently, portions of circuit descriptions will be reused in several +input files, particularly with common models and subcircuits. In any +spice input file, the ".include" line may be used to copy some other +file as if that second file appeared in place of the ".include" line +in the original file. There is no restriction on the file name +imposed by spice beyond those imposed by the local operating system. + + +@node Circuit Elements and Models, Analyses and Output Control, Circuit Description, Top +@chapter Circuit Elements and Models + + +Data fields that are enclosed in less-than and greater-than signs ('< +>') are optional. All indicated punctuation (parentheses, equal signs, +etc.) is optional but indicate the presence of any delimiter. Further, +future implementations may require the punctuation as stated. A +consistent style adhering to the punctuation shown here makes the input +easier to understand. With respect to branch voltages and currents, +SPICE uniformly uses the associated reference convention (current flows +in the direction of voltage drop). + + +@menu +* Elementary Devices:: +* Voltage and Current Sources:: +* Transmission Lines:: +* Transistors and Diodes:: +@end menu + +@node Elementary Devices, Voltage and Current Sources, Circuit Elements and Models, Circuit Elements and Models +@section Elementary Devices + + +@menu +* Resistors:: +* Semiconductor Resistors:: +* Semiconductor Resistor Model (R):: +* Capacitors:: +* Semiconductor Capacitors:: +* Semiconductor Capacitor Model (C):: +* Inductors:: +* Coupled (Mutual) Inductors:: +* Switches:: +* Switch Model (SW/CSW):: +@end menu + +@node Resistors, Semiconductor Resistors, Elementary Devices, Elementary Devices +@subsection Resistors + + General form: + +@example + RXXXXXXX N1 N2 VALUE +@end example + + + Examples: + +@example + R1 1 2 100 + RC1 12 17 1K +@end example + + +N1 and N2 are the two element nodes. VALUE is the resistance (in ohms) +and may be positive or negative but not zero. + + + + +@node Semiconductor Resistors, Semiconductor Resistor Model (R), Resistors, Elementary Devices +@subsection Semiconductor Resistors + + General form: + +@example + RXXXXXXX N1 N2 +@end example + + + Examples: + +@example + RLOAD 2 10 10K + RMOD 3 7 RMODEL L=10u W=1u +@end example + + + +This is the more general form of the resistor presented in section +6.1, and allows the modeling of temperature effects and for the +calculation of the actual resistance value from strictly geometric +information and the specifications of the process. If VALUE is +specified, it overrides the geometric information and defines the +resistance. If MNAME is specified, then the resistance may be +calculated from the process information in the model MNAME and the +given LENGTH and WIDTH. If VALUE is not specified, then MNAME and +LENGTH must be specified. If WIDTH is not specified, then it is taken +from the default width given in the model. The (optional) TEMP value +is the temperature at which this device is to operate, and overrides +the temperature specification on the .OPTION control line. + + + +@node Semiconductor Resistor Model (R), Capacitors, Semiconductor Resistors, Elementary Devices +@subsection Semiconductor Resistor Model (R) + + +The resistor model consists of process-related device data that allow +the resistance to be calculated from geometric information and to be +corrected for temperature. The parameters available are: + +@multitable @columnfractions .15 .4 .2 .1 .1 +@item name @tab parameter @tab units @tab default @tab example +@item TC1 @tab first order temperature coeff. + @tab Z/°C @tab 0.0 +@item TC2 @tab second order temperature coeff. + @tab Z/°C@math{^2} @tab 0.0 +@item RSH @tab sheet resistance + @tab Z/[] @tab - @tab 50 +@item DEFW @tab default width + @tab meters @tab 1e-6 @tab 2e-6 +@item NARROW @tab narrowing due to side etching + @tab meters @tab 0.0 @tab 1e-7 +@item TNOM @tab parameter measurement temperature + @tab °C @tab 27 @tab 50 +@end multitable + + +The sheet resistance is used with the narrowing parameter and L and W +from the resistor device to determine the nominal resistance by the +formula + +@tex +$$ + R = {\rm RSH} {L - {\rm NARROW} \over W - {\rm NARROW}} +$$ +@end tex +@ifnottex +@example + L - NARROW + R = RSH ---------- + W - NARROW +@end example +@end ifnottex + +DEFW is used to supply a default value for W if one is not specified for +the device. If either RSH or L is not specified, then the standard +default resistance value of 1k Z is used. TNOM is used to override the +circuit-wide value given on the .OPTIONS control line where the +parameters of this model have been measured at a different temperature. +After the nominal resistance is calculated, it is adjusted for +temperature by the formula: + + +@tex +$$ + R(T) = R(T_0) \Bigl( 1 + TC_1 (T - T_0) + TC_2 (T-T_0)^2 \Bigr) +$$ +@end tex +@ifnottex +@example + 2 + R(T) = R(T ) [1 + TC (T - T ) + TC (T - T ) ] + 0 1 0 2 0 +@end example +@end ifnottex + + +@node Capacitors, Semiconductor Capacitors, Semiconductor Resistor Model (R), Elementary Devices +@subsection Capacitors + + General form: + +@example + CXXXXXXX N+ N- VALUE +@end example + + + Examples: + +@example + CBYP 13 0 1UF + COSC 17 23 10U IC=3V +@end example + + +N+ and N- are the positive and negative element nodes, respectively. +VALUE is the capacitance in Farads. + + +The (optional) initial condition is the initial (timezero) value of +capacitor voltage (in Volts). Note that the initial conditions (if any) +apply 'only' if the UIC option is specified on the .TRAN control line. + + + +@node Semiconductor Capacitors, Semiconductor Capacitor Model (C), Capacitors, Elementary Devices +@subsection Semiconductor Capacitors + + General form: + +@example + CXXXXXXX N1 N2 +@end example + + + Examples: + +@example + CLOAD 2 10 10P + CMOD 3 7 CMODEL L=10u W=1u +@end example + + + +This is the more general form of the Capacitor presented in section 6.2, +and allows for the calculation of the actual capacitance value from +strictly geometric information and the specifications of the process. +If VALUE is specified, it defines the capacitance. If MNAME is +specified, then the capacitance is calculated from the process +information in the model MNAME and the given LENGTH and WIDTH. If VALUE +is not specified, then MNAME and LENGTH must be specified. If WIDTH is +not specified, then it is taken from the default width given in the +model. Either VALUE or MNAME, LENGTH, and WIDTH may be specified, but +not both sets. + + + + +@node Semiconductor Capacitor Model (C), Inductors, Semiconductor Capacitors, Elementary Devices +@subsection Semiconductor Capacitor Model (C) + + +The capacitor model contains process information that may be used to +compute the capacitance from strictly geometric information. + +@multitable @columnfractions .15 .4 .2 .1 .1 +@item name @tab parameter @tab units @tab default @tab example +@item CJ @tab junction bottom capacitance + @tab F/meters@math{^2} @tab - @tab 5e-5 +@item CJSW @tab junction sidewall capacitance + @tab F/meters @tab - @tab 2e-11 +@item DEFW @tab default device width + @tab meters @tab 1e-6 @tab 2e-6 +@item NARROW @tab narrowing due to side etching + @tab meters @tab 0.0 @tab 1e-7 +@end multitable + + +The capacitor has a capacitance computed as + +@example +CAP = CJ (LENGTH - NARROW) (WIDTH - NARROW) + + 2 CJSW (LENGTH + WIDTH - 2 NARROW) +@end example + + +@node Inductors, Coupled (Mutual) Inductors, Semiconductor Capacitor Model (C), Elementary Devices +@subsection Inductors + + General form: + +@example + LYYYYYYY N+ N- VALUE +@end example + + + Examples: + +@example + LLINK 42 69 1UH + LSHUNT 23 51 10U IC=15.7MA +@end example + + +N+ and N- are the positive and negative element nodes, respectively. +VALUE is the inductance in Henries. + + +The (optional) initial condition is the initial (timezero) value of +inductor current (in Amps) that flows from N+, through the inductor, to +N-. Note that the initial conditions (if any) apply only if the UIC +option is specified on the .TRAN analysis line. + + + +@node Coupled (Mutual) Inductors, Switches, Inductors, Elementary Devices +@subsection Coupled (Mutual) Inductors + + General form: + +@example + KXXXXXXX LYYYYYYY LZZZZZZZ VALUE +@end example + + + Examples: + +@example + K43 LAA LBB 0.999 + KXFRMR L1 L2 0.87 +@end example + + +LYYYYYYY and LZZZZZZZ are the names of the two coupled inductors, and +VALUE is the coefficient of coupling, K, which must be greater than 0 +and less than or equal to 1. Using the 'dot' convention, place a 'dot' +on the first node of each inductor. + + + + +@node Switches, Switch Model (SW/CSW), Coupled (Mutual) Inductors, Elementary Devices +@subsection Switches + + General form: + +@example + SXXXXXXX N+ N- NC+ NC- MODEL + WYYYYYYY N+ N- VNAM MODEL +@end example + + + Examples: + +@example + s1 1 2 3 4 switch1 ON + s2 5 6 3 0 sm2 off + Switch1 1 2 10 0 smodel1 + w1 1 2 vclock switchmod1 + W2 3 0 vramp sm1 ON + wreset 5 6 vclck lossyswitch OFF +@end example + + +Nodes 1 and 2 are the nodes between which the switch terminals are +connected. The model name is mandatory while the initial conditions are +optional. For the voltage controlled switch, nodes 3 and 4 are the +positive and negative controlling nodes respectively. For the current +controlled switch, the controlling current is that through the specified +voltage source. The direction of positive controlling current flow is +from the positive node, through the source, to the negative node. + + + + +@node Switch Model (SW/CSW), , Switches, Elementary Devices +@subsection Switch Model (SW/CSW) + + +The switch model allows an almost ideal switch to be described in SPICE. +The switch is not quite ideal, in that the resistance can not change +from 0 to infinity, but must always have a finite positive value. By +proper selection of the on and off resistances, they can be effectively +zero and infinity in comparison to other circuit elements. The +parameters available are: + +@multitable @columnfractions .15 .4 .2 .1 .1 +@item name @tab parameter @tab units @tab default @tab switch +@item VT @tab threshold voltage @tab Volts @tab 0.0 @tab S +@item IT @tab threshold current @tab Amps @tab 0.0 @tab W +@item VH @tab hysteresis voltage @tab Volts @tab 0.0 @tab S +@item IH @tab hysteresis current @tab Amps @tab 0.0 @tab W +@item RON @tab on resistance @tab Z @tab 1.0 @tab both +@item ROFF @tab off resistance @tab Z @tab 1/GMIN* @tab both +@end multitable + + + +*(See the .OPTIONS control line for a description of GMIN, its default +value results in an off-resistance of 1.0e+12 ohms.) + + +The use of an ideal element that is highly nonlinear such as a switch +can cause large discontinuities to occur in the circuit node voltages. +A rapid change such as that associated with a switch changing state can +cause numerical roundoff or tolerance problems leading to erroneous +results or timestep difficulties. The user of switches can improve the +situation by taking the following steps: + +First, it is wise to set ideal switch impedances just high or low enough +to be negligible with respect to other circuit elements. Using switch +impedances that are close to "ideal" in all cases aggravates the problem +of discontinuities mentioned above. Of course, when modeling real +devices such as MOSFETS, the on resistance should be adjusted to a +realistic level depending on the size of the device being modeled. + +If a wide range of ON to OFF resistance must be used in the switches +(ROFF/RON >1e+12), then the tolerance on errors allowed during transient +analysis should be decreased by using the .OPTIONS control line and +specifying TRTOL to be less than the default value of 7.0. When +switches are placed around capacitors, then the option CHGTOL should +also be reduced. Suggested values for these two options are 1.0 and +1e-16 respectively. These changes inform SPICE3 to be more careful +around the switch points so that no errors are made due to the rapid +change in the circuit. + + + +@node Voltage and Current Sources, Transmission Lines, Elementary Devices, Circuit Elements and Models +@section Voltage and Current Sources + + +@menu +* Independent Sources:: +* Linear Dependent Sources:: +* Non-linear Dependent Sources:: +@end menu + +@node Independent Sources, Linear Dependent Sources, Voltage and Current Sources, Voltage and Current Sources +@subsection Independent Sources + + General form: + +@example + VXXXXXXX N+ N- < DC/TRAN VALUE> >> + + >> >> + IYYYYYYY N+ N- < DC/TRAN VALUE> >> + + >> >> +@end example + + + Examples: + +@example + VCC 10 0 DC 6 + VIN 13 2 0.001 AC 1 SIN(0 1 1MEG) + ISRC 23 21 AC 0.333 45.0 SFFM(0 1 10K 5 1K) + VMEAS 12 9 + VCARRIER 1 0 DISTOF1 0.1 -90.0 + VMODULATOR 2 0 DISTOF2 0.01 + IIN1 1 5 AC 1 DISTOF1 DISTOF2 0.001 +@end example + + +N+ and N- are the positive and negative nodes, respectively. Note that +voltage sources need not be grounded. Positive current is assumed to +flow from the positive node, through the source, to the negative node. +A current source of positive value forces current to flow out of the N+ +node, through the source, and into the N- node. Voltage sources, in +addition to being used for circuit excitation, are the 'ammeters' for +SPICE, that is, zero valued voltage sources may be inserted into the +circuit for the purpose of measuring current. They of course have no +effect on circuit operation since they represent short-circuits. + + +DC/TRAN is the dc and transient analysis value of the source. If the +source value is zero both for dc and transient analyses, this value may +be omitted. If the source value is time-invariant (e.g., a power +supply), then the value may optionally be preceded by the letters DC. + + +ACMAG is the ac magnitude and ACPHASE is the ac phase. The source is +set to this value in the ac analysis. If ACMAG is omitted following the +keyword AC, a value of unity is assumed. If ACPHASE is omitted, a value +of zero is assumed. If the source is not an ac small-signal input, the +keyword AC and the ac values are omitted. + + +DISTOF1 and DISTOF2 are the keywords that specify that the independent +source has distortion inputs at the frequencies F1 and F2 respectively +(see the description of the .DISTO control line). The keywords may be +followed by an optional magnitude and phase. The default values of the +magnitude and phase are 1.0 and 0.0 respectively. + + +Any independent source can be assigned a time-dependent value for +transient analysis. If a source is assigned a time-dependent value, the +time-zero value is used for dc analysis. There are five independent +source functions: pulse, exponential, sinusoidal, piece-wise linear, and +single-frequency FM. If parameters other than source values are omitted +or set to zero, the default values shown are assumed. (TSTEP is the +printing increment and TSTOP is the final time (see the .TRAN control +line for explanation)). + + +@menu +* Pulse:: +* Sinusoidal:: +* Exponential:: +* Piece-Wise Linear:: +* Single-Frequency FM:: +@end menu + +@node Pulse, Sinusoidal, Independent Sources, Independent Sources +@subsubsection Pulse + + General form: + +@example + PULSE(V1 V2 TD TR TF PW PER) +@end example + + + Examples: + +@example + VIN 3 0 PULSE(-1 1 2NS 2NS 2NS 50NS 100NS) +@end example + + +@multitable @columnfractions .33 .33 .33 +@item parameter @tab default value @tab units +@item V1 (initial value) @tab @tab Volts or Amps +@item V2 (pulsed value) @tab @tab Volts or Amps +@item TD (delay time) @tab 0.0 @tab seconds +@item TR (rise time) @tab TSTEP @tab seconds +@item TF (fall time) @tab TSTEP @tab seconds +@item PW (pulse width) @tab TSTOP @tab seconds +@item PER(period) @tab TSTOP @tab seconds +@end multitable + +A single pulse so specified is described by the following table: + + +@multitable @columnfractions .3 .3 +@item time @tab value +@item 0 @tab V1 +@item TD @tab V1 +@item TD+TR @tab V2 +@item TD+TR+PW @tab V2 +@item TD+TR+PW+TF @tab V1 +@item TSTOP @tab V1 +@end multitable + + +Intermediate points are determined by linear interpolation. + + + + +@node Sinusoidal, Exponential, Pulse, Independent Sources +@subsubsection Sinusoidal + + General form: + +@example + SIN(VO VA FREQ TD THETA) +@end example + + + Examples: + +@example + VIN 3 0 SIN(0 1 100MEG 1NS 1E10) +@end example + + +@multitable @columnfractions .3 .3 .3 +@item parameters @tab default value @tab units +@item VO (offset) @tab @tab Volts or Amps +@item VA (amplitude) @tab @tab Volts or Amps +@item FREQ (frequency) @tab 1/TSTOP @tab Hz +@item TD (delay) @tab 0.0 @tab seconds +@item THETA (damping factor) @tab 0.0 @tab 1/seconds +@end multitable + + +The shape of the waveform is described by the following table: + + +@example +time value +------------------------------------------------------------ +0 to TD VO + -(t - TD)THETA +TD to TSTOP VO + VA e sin(2 J FREQ (t + TD)) +@end example + + + + + + +@node Exponential, Piece-Wise Linear, Sinusoidal, Independent Sources +@subsubsection Exponential + + General Form: + +@example + EXP(V1 V2 TD1 TAU1 TD2 TAU2) +@end example + + + Examples: + +@example + VIN 3 0 EXP(-4 -1 2NS 30NS 60NS 40NS) +@end example + + +@example +parameter default value units +--------------------------------------------------------- +V1 (initial value) Volts or Amps +V2 (pulsed value) Volts or Amps +TD1 (rise delay time) 0.0 seconds +TAU1 (rise time constant) TSTEP seconds +TD2 (fall delay time) TD1+TSTEP seconds +TAU2 (fall time constant) TSTEP seconds +@end example + + +The shape of the waveform is described by the following table: + + +@example +time value +---------------------------------------------------------------------------- +0 to TD1 V1 + | ------------| + TAU1 + | -(t - TD1) | -(t - TD2) +TD1 to TD2 V1 + (V2 - V1) 1 - e + | ----------| | ----------| + | TAU1 | | TAU2 | +TD2 to TSTOP V1 + (V2 - V1) - e + (V1 - V2) 1 - e +@end example + + + +@node Piece-Wise Linear, Single-Frequency FM, Exponential, Independent Sources +@subsubsection Piece-Wise Linear + + General Form: + +@example + PWL(T1 V1 ) +@end example + + + Examples: + +@example + VCLOCK 7 5 PWL(0 -7 10NS -7 11NS -3 17NS -3 18NS -7 50NS -7) +@end example + + + + +Each pair of values (Ti, Vi) specifies that the value of the source is +Vi (in Volts or Amps) at time=Ti. The value of the source at +intermediate values of time is determined by using linear interpolation +on the input values. + + + +@node Single-Frequency FM, , Piece-Wise Linear, Independent Sources +@subsubsection Single-Frequency FM + + General Form: + +@example + SFFM(VO VA FC MDI FS) +@end example + + + Examples: + +@example + V1 12 0 SFFM(0 1M 20K 5 1K) +@end example + + + +@example +parameter default value units +------------------------------------------------------ +VO (offset) Volts or Amps +VA (amplitude) Volts or Amps +FC (carrier frequency) 1/TSTOP Hz +MDI (modulation index) +FS (signal frequency) 1/TSTOP Hz +@end example + + +The shape of the waveform is described by the following equation: + +@tex +$$ + V(t)=V_O + V_A \sin\left| 2 J FC t + MDI \sin(2 J FS t)\right| +$$ +@end tex +@ifnottex +@example + + | | + V(t)=V + V sin 2 J FC t + MDI sin(2 J FS t) + O A | | +@end example +@end ifnottex + + + + + +@node Linear Dependent Sources, Non-linear Dependent Sources, Independent Sources, Voltage and Current Sources +@subsection Linear Dependent Sources + + +SPICE allows circuits to contain linear dependent sources characterized +by any of the four equations + +@tex +$$ + i = g v \qquad v = e v \qquad i = f i \qquad v = h i +$$ +@end tex +@ifnottex +@example + i = g v v = e v i = f i v = h i +@end example +@end ifnottex + +where g, e, f, and h are constants representing transconductance, +voltage gain, current gain, and transresistance, respectively. + + +@menu +* Linear Voltage-Controlled Current Sources:: +* Linear Voltage-Controlled Voltage Sources:: +* Linear Current-Controlled Current Sources:: +* Linear Current-Controlled Voltage Sources:: +@end menu + + + +@node Linear Voltage-Controlled Current Sources, Linear Voltage-Controlled Voltage Sources, Linear Dependent Sources, Linear Dependent Sources +@subsubsection Linear Voltage-Controlled Current Sources + + General form: + +@example + GXXXXXXX N+ N- NC+ NC- VALUE +@end example + + + Examples: + +@example + G1 2 0 5 0 0.1MMHO +@end example + + +N+ and N- are the positive and negative nodes, respectively. Current +flow is from the positive node, through the source, to the negative +node. NC+ and NCare the positive and negative controlling nodes, +respectively. VALUE is the transconductance (in mhos). + + + + + +@node Linear Voltage-Controlled Voltage Sources, Linear Current-Controlled Current Sources, Linear Voltage-Controlled Current Sources, Linear Dependent Sources +@subsubsection Linear Voltage-Controlled Voltage Sources + + General form: + +@example + EXXXXXXX N+ N- NC+ NC- VALUE +@end example + + + Examples: + +@example + E1 2 3 14 1 2.0 +@end example + + +N+ is the positive node, and N- is the negative node. NC+ and NC- are +the positive and negative controlling nodes, respectively. VALUE is the +voltage gain. + + + + + +@node Linear Current-Controlled Current Sources, Linear Current-Controlled Voltage Sources, Linear Voltage-Controlled Voltage Sources, Linear Dependent Sources +@subsubsection Linear Current-Controlled Current Sources + + General form: + +@example + FXXXXXXX N+ N- VNAM VALUE +@end example + + + Examples: + +@example + F1 13 5 VSENS 5 +@end example + + +N+ and N- are the positive and negative nodes, respectively. Current +flow is from the positive node, through the source, to the negative +node. VNAM is the name of a voltage source through which the +controlling current flows. The direction of positive controlling +current flow is from the positive node, through the source, to the +negative node of VNAM. VALUE is the current gain. + + + + + +@node Linear Current-Controlled Voltage Sources, , Linear Current-Controlled Current Sources, Linear Dependent Sources +@subsubsection Linear Current-Controlled Voltage Sources + + General form: + +@example + HXXXXXXX N+ N- VNAM VALUE +@end example + + + Examples: + +@example + HX 5 17 VZ 0.5K +@end example + + +N+ and N- are the positive and negative nodes, respectively. VNAM is +the name of a voltage source through which the controlling current +flows. The direction of positive controlling current flow is from the +positive node, through the source, to the negative node of VNAM. VALUE +is the transresistance (in ohms). + + + + + +@node Non-linear Dependent Sources, , Linear Dependent Sources, Voltage and Current Sources +@subsection Non-linear Dependent Sources + + General form: + +@example + BXXXXXXX N+ N- +@end example + + + Examples: + +@example + B1 0 1 I=cos(v(1))+sin(v(2)) + B1 0 1 V=ln(cos(log(v(1,2)^2)))-v(3)^4+v(2)^v(1) + B1 3 4 I=17 + B1 3 4 V=exp(pi^i(vdd)) +@end example + + + +N+ is the positive node, and N- is the negative node. The values of the +V and I parameters determine the voltages and currents across and +through the device, respectively. If I is given then the device is a +current source, and if V is given the device is a voltage source. One +and only one of these parameters must be given. + +The small-signal AC behavior of the nonlinear source is a linear +dependent source (or sources) with a proportionality constant equal to +the derivative (or derivatives) of the source at the DC operating point. + + +The expressions given for V and I may be any function of voltages and +currents through voltage sources in the system. The following functions +of real variables are defined: + +@multitable @columnfractions .2 .2 .2 .2 +@item abs @tab asinh @tab cosh @tab sin +@item acos @tab atan @tab exp @tab sinh +@item acosh @tab atanh @tab ln @tab sqrt +@item asin @tab cos @tab log @tab tan +@end multitable + +The function "u" is the unit step function, with a value of one for +arguments greater than one and a value of zero for arguments less than +zero. The function "uramp" is the integral of the unit step: for an +input x, the value is zero if x is less than zero, or if x is greater +than zero the value is x. These two functions are useful in sythesizing +piece-wise non-linear functions, though convergence may be adversely +affected. + + +The following standard operators are defined: + +@example ++ - * / @^{@ } unary - +@end example + + +If the argument of log, ln, or sqrt becomes less than zero, the absolute +value of the argument is used. If a divisor becomes zero or the +argument of log or ln becomes zero, an error will result. Other +problems may occur when the argument for a function in a partial +derivative enters a region where that function is undefined. + + +To get time into the expression you can integrate the current from a +constant current source with a capacitor and use the resulting voltage +(don't forget to set the initial voltage across the capacitor). +Non-linear resistors, capacitors, and inductors may be synthesized with +the nonlinear dependent source. Non-linear resistors are obvious. +Nonlinear capacitors and inductors are implemented with their linear +counterparts by a change of variables implemented with the nonlinear +dependent source. The following subcircuit will implement a nonlinear +capacitor: + +@example + .Subckt nlcap pos neg + * Bx: calculate f(input voltage) + Bx 1 0 v = f(v(pos,neg)) + * Cx: linear capacitance + Cx 2 0 1 + * Vx: Ammeter to measure current into the capacitor + Vx 2 1 DC 0Volts + * Drive the current through Cx back into the circuit + Fx pos neg Vx 1 + .ends +@end example + + +Non-linear inductors are similar. + + + + +@node Transmission Lines, Transistors and Diodes, Voltage and Current Sources, Circuit Elements and Models +@section Transmission Lines + + + +@menu +* Lossless Transmission Lines:: +* Lossy Transmission Lines:: +* Lossy Transmission Line Model (LTRA):: +* Uniform Distributed RC Lines (Lossy):: +* Uniform Distributed RC Model (URC):: +@end menu + +@node Lossless Transmission Lines, Lossy Transmission Lines, Transmission Lines, Transmission Lines +@subsection Lossless Transmission Lines + + General form: + +@example + TXXXXXXX N1 N2 N3 N4 Z0=VALUE > + + +@end example + + + Examples: + +@example + T1 1 0 2 0 Z0=50 TD=10NS +@end example + + +N1 and N2 are the nodes at port 1; N3 and N4 are the nodes at port 2. +Z0 is the characteristic impedance. The length of the line may be +expressed in either of two forms. The transmission delay, TD, may be +specified directly (as TD=10ns, for example). Alternatively, a +frequency F may be given, together with NL, the normalized electrical +length of the transmission line with respect to the wavelength in the +line at the frequency F. If a frequency is specified but NL is omitted, +0.25 is assumed (that is, the frequency is assumed to be the +quarter-wave frequency). Note that although both forms for expressing +the line length are indicated as optional, one of the two must be +specified. + +Note that this element models only one propagating mode. If all four +nodes are distinct in the actual circuit, then two modes may be excited. +To simulate such a situation, two transmission-line elements are +required. (see the example in Appendix A for further clarification.) + +The (optional) initial condition specification consists of the voltage +and current at each of the transmission line ports. Note that the +initial conditions (if any) apply 'only' if the UIC option is specified +on the .TRAN control line. + +Note that a lossy transmission line (see below) with zero loss may be +more accurate than than the lossless transmission line due to +implementation details. + + + + +@node Lossy Transmission Lines, Lossy Transmission Line Model (LTRA), Lossless Transmission Lines, Transmission Lines +@subsection Lossy Transmission Lines + + General form: + +@example + OXXXXXXX N1 N2 N3 N4 MNAME +@end example + + + Examples: + +@example + O23 1 0 2 0 LOSSYMOD + OCONNECT 10 5 20 5 INTERCONNECT +@end example + + + +This is a two-port convolution model for singleconductor lossy +transmission lines. N1 and N2 are the nodes at port 1; N3 and N4 are +the nodes at port 2. Note that a lossy transmission line with zero loss +may be more accurate than than the lossless transmission line due to +implementation details. + + + +@node Lossy Transmission Line Model (LTRA), Uniform Distributed RC Lines (Lossy), Lossy Transmission Lines, Transmission Lines +@subsection Lossy Transmission Line Model (LTRA) + + +The uniform RLC/RC/LC/RG transmission line model (referred to as the +LTRA model henceforth) models a uniform constant-parameter distributed +transmission line. The RC and LC cases may also be modeled using the +URC and TRA models; however, the newer LTRA model is usually faster and +more accurate than the others. The operation of the LTRA model is based +on the convolution of the transmission line's impulse responses with its +inputs (see [8]). + +The LTRA model takes a number of parameters, some of which must be given +and some of which are optional. + +@multitable @columnfractions .15 .4 .2 .1 .1 +@item name @tab parameter @tab units/type @tab default @tab example +@item name @tab parameter @tab units/type @tab default @tab example +@item R @tab resistance/length @tab Z/unit @tab 0.0 @tab 0.2 +@item L @tab inductance/length @tab henrys/unit @tab 0.0 @tab 9.13e-9 +@item G @tab conductance/length @tab mhos/unit @tab 0.0 @tab 0.0 +@item C @tab capacitance/length @tab farads/unit @tab 0.0 @tab 3.65e-12 +@item LEN @tab length of line @tab no default @tab 1.0 +@item REL @tab breakpoint control @tab arbitrary unit @tab 1 @tab 0.5 +@item ABS @tab breakpoint control @tab 1 @tab 5 +@item NOSTEPLIMIT @tab don't limit timestep to less than line delay + @tab flag @tab not set @tab set +@item NOCONTROL @tab don't do complex timestep control + @tab flag @tab not set @tab set +@item LININTERP @tab use linear interpolation + @tab flag @tab not set @tab set +@item MIXEDINTERP @tab use linear when quadratic seems bad + @tab not set @tab set +@item COMPACTREL @tab special reltol for history compaction + @tab flag @tab RELTOL @tab 1.0e-3 +@item COMPACTABS @tab special abstol for history compaction + @tab ABSTOL @tab 1.0e-9 +@item TRUNCNR @tab use Newton-Raphson method for timestep control + @tab flag @tab not set @tab set +@item TRUNCDONTCUT @tab don't limit timestep to keep impulse-response +errors low @tab flag @tab not set @tab set +@end multitable + + +The following types of lines have been implemented so far: RLC (uniform +transmission line with series loss only), RC (uniform RC line), LC +(lossless transmission line), and RG (distributed series resistance and +parallel conductance only). Any other combination will yield erroneous +results and should not be tried. The length LEN of the line must be +specified. + +NOSTEPLIMIT is a flag that will remove the default restriction of +limiting time-steps to less than the line delay in the RLC case. +NOCONTROL is a flag that prevents the default limiting of the time-step +based on convolution error criteria in the RLC and RC cases. This +speeds up simulation but may in some cases reduce the accuracy of +results. LININTERP is a flag that, when specified, will use linear +interpolation instead of the default quadratic interpolation for +calculating delayed signals. MIXEDINTERP is a flag that, when +specified, uses a metric for judging whether quadratic interpolation is +not applicable and if so uses linear interpolation; otherwise it uses +the default quadratic interpolation. TRUNCDONTCUT is a flag that +removes the default cutting of the time-step to limit errors in the +actual calculation of impulse-response related quantities. COMPACTREL +and COMPACTABS are quantities that control the compaction of the past +history of values stored for convolution. Larger values of these lower +accuracy but usually increase simulation speed. These are to be used +with the TRYTOCOMPACT option, described in the .OPTIONS section. +TRUNCNR is a flag that turns on the use of Newton-Raphson iterations to +determine an appropriate timestep in the timestep control routines. The +default is a trial and error procedure by cutting the previous timestep +in half. REL and ABS are quantities that control the setting of +breakpoints. + +The option most worth experimenting with for increasing the speed of +simulation is REL. The default value of 1 is usually safe from the +point of view of accuracy but occasionally increases computation time. +A value greater than 2 eliminates all breakpoints and may be worth +trying depending on the nature of the rest of the circuit, keeping in +mind that it might not be safe from the viewpoint of accuracy. +Breakpoints may usually be entirely eliminated if it is expected the +circuit will not display sharp discontinuities. Values between 0 and 1 +are usually not required but may be used for setting many breakpoints. + +COMPACTREL may also be experimented with when the option TRYTOCOMPACT is +specified in a .OPTIONS card. The legal range is between 0 and 1. +Larger values usually decrease the accuracy of the simulation but in +some cases improve speed. If TRYTOCOMPACT is not specified on a +.OPTIONS card, history compaction is not attempted and accuracy is high. +NOCONTROL, TRUNCDONTCUT and NOSTEPLIMIT also tend to increase speed at +the expense of accuracy. + + + +@node Uniform Distributed RC Lines (Lossy), Uniform Distributed RC Model (URC), Lossy Transmission Line Model (LTRA), Transmission Lines +@subsection Uniform Distributed RC Lines (Lossy) + + General form: + +@example + UXXXXXXX N1 N2 N3 MNAME L=LEN +@end example + + + Examples: + +@example + U1 1 2 0 URCMOD L=50U + URC2 1 12 2 UMODL l=1MIL N=6 +@end example + + + +N1 and N2 are the two element nodes the RC line connects, while N3 is +the node to which the capacitances are connected. MNAME is the model +name, LEN is the length of the RC line in meters. LUMPS, if specified, +is the number of lumped segments to use in modeling the RC line (see the +model description for the action taken if this parameter is omitted). + + + +@node Uniform Distributed RC Model (URC), , Uniform Distributed RC Lines (Lossy), Transmission Lines +@subsection Uniform Distributed RC Model (URC) + + +The URC model is derived from a model proposed by L. Gertzberrg in +1974. The model is accomplished by a subcircuit type expansion of the +URC line into a network of lumped RC segments with internally generated +nodes. The RC segments are in a geometric progression, increasing +toward the middle of the URC line, with @math{K} as a proportionality +constant. The number of lumped segments used, if not specified for the +URC line device, is determined by the following formula: + + +@tex +$$ + N = { \log \left| + F_{\rm max} {R\over L}{C \over L} 2 J L^2 + \left| (K - 1) \over K \right|^2 + \right| \over \log K } +$$ +@end tex +@ifnottex +@example + 2 + | R C |(K-1)| | + _ _ 2 + log|F 2 J L |-----| | + max + | L L | K | | + + N = ------------------------------ + log K +@end example +@end ifnottex + + +The URC line is made up strictly of resistor and capacitor segments +unless the ISPERL parameter is given a nonzero value, in which case the +capacitors are replaced with reverse biased diodes with a zero-bias +junction capacitance equivalent to the capacitance replaced, and with a +saturation current of ISPERL amps per meter of transmission line and an +optional series resistance equivalent to RSPERL ohms per meter. + +@multitable @columnfractions .15 .4 .2 .1 .1 +@item name @tab parameter @tab units @tab default @tab example area +@item K @tab Propagation Constant @tab - @tab 2.0 @tab 1.2 +@item FMAX @tab Maximum Frequency of interest @tab Hz @tab 1.0G @tab 6.5Meg +@item RPERL @tab Resistance per unit length @tab Z/m @tab 1000 @tab 10 +@item CPERL @tab Capacitance per unit length @tab F/m @tab 1.0e-15 @tab 1pF +@item ISPERL @tab Saturation Current per unit length @tab A/m @tab 0 +@tab - +@item RSPERL @tab Diode Resistance per unit length @tab Z/m @tab 0 @tab - - +@end multitable + + + +@node Transistors and Diodes, , Transmission Lines, Circuit Elements and Models +@section Transistors and Diodes + + +The area factor used on the diode, BJT, JFET, and MESFET devices +determines the number of equivalent parallel devices of a specified +model. The affected parameters are marked with an asterisk under the +heading 'area' in the model descriptions below. Several geometric +factors associated with the channel and the drain and source diffusions +can be specified on the MOSFET device line. + +Two different forms of initial conditions may be specified for some +devices. The first form is included to improve the dc convergence for +circuits that contain more than one stable state. If a device is +specified OFF, the dc operating point is determined with the terminal +voltages for that device set to zero. After convergence is obtained, +the program continues to iterate to obtain the exact value for the +terminal voltages. If a circuit has more than one dc stable state, the +OFF option can be used to force the solution to correspond to a desired +state. If a device is specified OFF when in reality the device is +conducting, the program still obtains the correct solution (assuming the +solutions converge) but more iterations are required since the program +must independently converge to two separate solutions. The .NODESET +control line serves a similar purpose as the OFF option. The .NODESET +option is easier to apply and is the preferred means to aid convergence. + +The second form of initial conditions are specified for use with the +transient analysis. These are true 'initial conditions' as opposed to +the convergence aids above. See the description of the .IC control line +and the .TRAN control line for a detailed explanation of initial +conditions. + +@menu +* Junction Diodes:: +* Diode Model (D):: +* Bipolar Junction Transistors (BJTs):: +* BJT Models (NPN/PNP):: +* Junction Field-Effect Transistors (JFETs):: +* JFET Models (NJF/PJF):: +* MOSFETs:: +* MOSFET Models (NMOS/PMOS):: +* MESFETs:: +* MESFET Models (NMF/PMF):: +@end menu + + + +@node Junction Diodes, Diode Model (D), Transistors and Diodes, Transistors and Diodes +@subsection Junction Diodes + + General form: + +@example + DXXXXXXX N+ N- MNAME +@end example + + + Examples: + +@example + DBRIDGE 2 10 DIODE1 + DCLMP 3 7 DMOD 3.0 IC=0.2 +@end example + + + +N+ and N- are the positive and negative nodes, respectively. MNAME is +the model name, AREA is the area factor, and OFF indicates an (optional) +starting condition on the device for dc analysis. If the area factor is +omitted, a value of 1.0 is assumed. The (optional) initial condition +specification using IC=VD is intended for use with the UIC option on the +.TRAN control line, when a transient analysis is desired starting from +other than the quiescent operating point. The (optional) TEMP value is +the temperature at which this device is to operate, and overrides the +temperature specification on the .OPTION control line. + + + + +@node Diode Model (D), Bipolar Junction Transistors (BJTs), Junction Diodes, Transistors and Diodes +@subsection Diode Model (D) + + +The dc characteristics of the diode are determined by the parameters IS +and N. An ohmic resistance, RS, is included. Charge storage effects +are modeled by a transit time, TT, and a nonlinear depletion layer +capacitance which is determined by the parameters CJO, VJ, and M. The +temperature dependence of the saturation current is defined by the +parameters EG, the energy and XTI, the saturation current temperature +exponent. The nominal temperature at which these parameters were +measured is TNOM, which defaults to the circuit-wide value specified on +the .OPTIONS control line. Reverse breakdown is modeled by an +exponential increase in the reverse diode current and is determined by +the parameters BV and IBV (both of which are positive numbers). + + +@multitable @columnfractions .1 .4 .2 .1 .1 .1 +@item name @tab parameter @tab units @tab default @tab example @tab area +@item IS @tab saturation current @tab A @tab 1.0e-14 @tab 1.0e-14 @tab * +@item RS @tab ohmic resistance @tab Z @tab 0 @tab 10 @tab * +@item N @tab emission coefficient @tab - @tab 1 @tab 1.0 +@item TT @tab transit-time @tab sec @tab 0 @tab 0.1ns +@item CJO @tab zero-bias junction capacitance + @tab F @tab 0 @tab 2pF @tab * +@item VJ @tab junction potential @tab V @tab 1 @tab 0.6 +@item M @tab grading coefficient @tab - @tab 0.5 @tab 0.5 +@item EG @tab activation energy + @tab eV @tab 1.11 @tab 1.11 Si; 0.69 Sbd; 0.67 Ge +@item XTI @tab saturation-current temp. exp + @tab - @tab 3.0 @tab 3.0 jn; 2.0 Sbd +@item KF @tab flicker noise coefficient @tab - @tab 0 +@item AF @tab flicker noise exponent @tab - @tab 1 +@item FC @tab coefficient for forward-bias + @tab - @tab 0.5 @tab depletion capacitance formula +@item BV @tab reverse breakdown voltage @tab V @tab infinite @tab 40.0 +@item IBV @tab current at breakdown voltage @tab A @tab 1.0e-3 + @tab o +@item TNOM @tab parameter measurement temperature @tab C @tab 27 @tab 50 +@end multitable + + + + + +@node Bipolar Junction Transistors (BJTs), BJT Models (NPN/PNP), Diode Model (D), Transistors and Diodes +@subsection Bipolar Junction Transistors (BJTs) + + General form: + +@example + QXXXXXXX NC NB NE MNAME +@end example + + + Examples: + +@example + Q23 10 24 13 QMOD IC=0.6, 5.0 + Q50A 11 26 4 20 MOD1 +@end example + + + +NC, NB, and NE are the collector, base, and emitter nodes, respectively. +NS is the (optional) substrate node. If unspecified, ground is used. +MNAME is the model name, AREA is the area factor, and OFF indicates an +(optional) initial condition on the device for the dc analysis. If the +area factor is omitted, a value of 1.0 is assumed. The (optional) +initial condition specification using IC=VBE, VCE is intended for use +with the UIC option on the .TRAN control line, when a transient analysis +is desired starting from other than the quiescent operating point. See +the .IC control line description for a better way to set transient +initial conditions. The (optional) TEMP value is the temperature at +which this device is to operate, and overrides the temperature +specification on the .OPTION control line. + + + + +@node BJT Models (NPN/PNP), Junction Field-Effect Transistors (JFETs), Bipolar Junction Transistors (BJTs), Transistors and Diodes +@subsection BJT Models (NPN/PNP) + + +The bipolar junction transistor model in SPICE is an adaptation of the +integral charge control model of Gummel and Poon. This modified +Gummel-Poon model extends the original model to include several effects +at high bias levels. The model automatically simplifies to the simpler +Ebers-Moll model when certain parameters are not specified. The +parameter names used in the modified Gummel-Poon model have been chosen +to be more easily understood by the program user, and to reflect better +both physical and circuit design thinking. + + +The dc model is defined by the parameters IS, BF, NF, ISE, IKF, and NE +which determine the forward current gain characteristics, IS, BR, NR, +ISC, IKR, and NC which determine the reverse current gain +characteristics, and VAF and VAR which determine the output conductance +for forward and reverse regions. Three ohmic resistances RB, RC, and RE +are included, where RB can be high current dependent. Base charge +storage is modeled by forward and reverse transit times, TF and TR, the +forward transit time TF being bias dependent if desired, and nonlinear +depletion layer capacitances which are determined by CJE, VJE, and MJE +for the B-E junction , CJC, VJC, and MJC for the B-C junction and CJS, +VJS, and MJS for the C-S (Collector-Substrate) junction. The +temperature dependence of the saturation current, IS, is determined by +the energy-gap, EG, and the saturation current temperature exponent, +XTI. Additionally base current temperature dependence is modeled by the +beta temperature exponent XTB in the new model. The values specified +are assumed to have been measured at the temperature TNOM, which can be +specified on the .OPTIONS control line or overridden by a specification +on the .MODEL line. + +The BJT parameters used in the modified Gummel-Poon model are listed +below. The parameter names used in earlier versions of SPICE2 are still +accepted. + +Modified Gummel-Poon BJT Parameters. + +@multitable @columnfractions .1 .4 .2 .1 .1 .1 +@item name @tab parameter @tab units @tab default @tab example @tab area +@item IS @tab transport saturation current @tab A @tab 1.0e-16 @tab +1.0e-15 @tab * +@item BF @tab ideal maximum forward beta @tab - @tab 100 @tab 100 +@item NF @tab forward current emission coefficient @tab - @tab 1.0 @tab 1 +@item VAF @tab forward Early voltage @tab V @tab infinite @tab 200 +@item IKF @tab corner for forward beta current roll-off @tab A @tab +infinite @tab 0.01 @tab * +@item ISE @tab B-E leakage saturation current @tab A @tab 0 @tab 1.0e-13 +@tab * +@item NE @tab B-E leakage emission coefficient @tab - @tab 1.5 @tab 2 +@item BR @tab ideal maximum reverse beta @tab - @tab 1 @tab 0.1 +@item NR @tab reverse current emission coefficient @tab - @tab 1 +@tab 1 +@item VAR @tab reverse Early voltage @tab V @tab infinite @tab 200 +@item IKR @tab corner for reverse beta high current roll-off + @tab A @tab infinite @tab 0.01 @tab * +@item ISC @tab B-C leakage saturation current @tab A @tab 0 @tab 1.0e-13 +@tab * +@item NC @tab B-C leakage emission coefficient @tab - @tab 2 @tab 1.5 +@item RB @tab zero bias base resistance @tab Z @tab 0 @tab 100 @tab * +@item IRB @tab current where base resistance falls halfway to its min +value @tab A @tab infinite @tab 0.1 @tab * +@item RBM @tab minimum base resistance at high currents @tab Z @tab RB +10 @tab * +@item RE @tab emitter resistance @tab Z @tab 0 @tab 1 @tab * +@item RC @tab collector resistance @tab Z @tab 0 @tab 10 @tab * +@item CJE @tab B-E zero-bias depletion capacitance @tab F @tab 0 @tab +2pF @tab * +@item VJE @tab B-E built-in potential @tab V @tab 0.75 @tab 0.6 +@item MJE @tab B-E junction exponential factor @tab - @tab 0.33 @tab 0.33 +@item TF @tab ideal forward transit time @tab sec @tab 0 @tab 0.1ns +@item XTF @tab coefficient for bias dependence of TF @tab - @tab 0 +@item VTF @tab voltage describing VBC dependence of TF @tab V @tab infinite +@item ITF @tab high-current parameter for effect on TF @tab A @tab 0 +@tab * +@item PTF @tab excess phase at freq=1.0/(TF*2PI) Hz @tab deg @tab 0 +@item CJC @tab B-C zero-bias depletion capacitance @tab F @tab 0 @tab +2pF @tab * +@item VJC @tab B-C built-in potential @tab V @tab 0.75 @tab 0.5 +@item MJC @tab B-C junction exponential factor @tab - @tab 0.33 @tab 0.5 +@item XCJC @tab fraction of B-C depletion capacitance connected to +internal base node @tab - @tab 1 +@item TR @tab ideal reverse transit time @tab sec @tab 0 @tab 10ns +@item CJS @tab zero-bias collector-substrate capacitance @tab F @tab 0 +@tab 2pF @tab * +@item VJS @tab substrate junction built-in potential @tab V @tab 0.75 +@item MJS @tab substrate junction exponential factor @tab - @tab 0 @tab 0.5 +@item XTB @tab forward and reverse beta temperature exponent @tab - @tab +0 +@item EG @tab energy gap for temperature effect on IS @tab eV @tab 1.11 +@item XTI @tab temperature exponent for effect on IS @tab - @tab 3 +@item KF @tab flicker-noise coefficient @tab - @tab 0 +@item AF @tab flicker-noise exponent @tab - @tab 1 +@item FC @tab coefficient for forward-bias depletion capacitance formula + @tab - @tab 0.5 @tab o +@item TNOM @tab Parameter measurement temperature @tab C @tab 27 @tab 50 +@end multitable + + + +@node Junction Field-Effect Transistors (JFETs), JFET Models (NJF/PJF), BJT Models (NPN/PNP), Transistors and Diodes +@subsection Junction Field-Effect Transistors (JFETs) + + General form: + +@example + JXXXXXXX ND NG NS MNAME +@end example + + + Examples: + +@example + J1 7 2 3 JM1 OFF +@end example + + + +ND, NG, and NS are the drain, gate, and source nodes, respectively. +MNAME is the model name, AREA is the area factor, and OFF indicates an +(optional) initial condition on the device for dc analysis. If the area +factor is omitted, a value of 1.0 is assumed. The (optional) initial +condition specification, using IC=VDS, VGS is intended for use with the +UIC option on the .TRAN control line, when a transient analysis is +desired starting from other than the quiescent operating point. See the +.IC control line for a better way to set initial conditions. The +(optional) TEMP value is the temperature at which this device is to +operate, and overrides the temperature specification on the .OPTION +control line. + + + + +@node JFET Models (NJF/PJF), MOSFETs, Junction Field-Effect Transistors (JFETs), Transistors and Diodes +@subsection JFET Models (NJF/PJF) + + +The JFET model is derived from the FET model of Shichman and Hodges. +The dc characteristics are defined by the parameters VTO and BETA, which +determine the variation of drain current with gate voltage, LAMBDA, +which determines the output conductance, and IS, the saturation current +of the two gate junctions. Two ohmic resistances, RD and RS, are +included. Charge storage is modeled by nonlinear depletion layer +capacitances for both gate junctions which vary as the -1/2 power of +junction voltage and are defined by the parameters CGS, CGD, and PB. + +Note that in Spice3f and later, a fitting parameter B has been added. +For details, see [9]. + +@multitable @columnfractions .1 .4 .1 .1 .1 .1 +@item name @tab parameter @tab units @tab default @tab example @tab area +@item VTO @tab threshold voltage (@math{V_T0}) @tab V @tab -2.0 @tab -2.0 +@item BETA @tab transconductance parameter (B) + @tab A/V@math{^2} @tab 1.0e-4 @tab 1.0e-3 @tab * +@item LAMBDA @tab channel-length modulation parameter (L) + @tab 1/V @tab 0 @tab 1.0e-4 +@item RD @tab drain ohmic resistance @tab Z @tab 0 @tab 100 @tab * +@item RS @tab source ohmic resistance @tab Z @tab 0 @tab 100 @tab * +@item CGS @tab zero-bias G-S junction capacitance (@math{C_gs}) + @tab F @tab 0 @tab 5pF @tab * +@item CGD @tab zero-bias G-D junction capacitance (@math{C_gs}) + @tab F @tab 0 @tab 1pF @tab * +@item PB @tab gate junction potential @tab V @tab 1 @tab 0.6 +@item IS @tab gate junction saturation current (@math{I_S}) + @tab A @tab 1.0e-14 @tab 1.0e-14 @tab * +@item B @tab doping tail parameter @tab - @tab 1 @tab 1.1 +@item KF @tab flicker noise coefficient @tab - @tab 0 +@item AF @tab flicker noise exponent @tab - @tab 1 +@item FC @tab coefficient for forward-bias depletion capacitance formula + @tab - @tab 0.5 +@item TNOM @tab parameter measurement temperature + @tab °C @tab 27 @tab 50 +@end multitable + + + +@node MOSFETs, MOSFET Models (NMOS/PMOS), JFET Models (NJF/PJF), Transistors and Diodes +@subsection MOSFETs + + General form: + +@example + MXXXXXXX ND NG NS NB MNAME + + + + +@end example + + + Examples: + +@example + M1 24 2 0 20 TYPE1 + M31 2 17 6 10 MODM L=5U W=2U + M1 2 9 3 0 MOD1 L=10U W=5U AD=100P AS=100P PD=40U PS=40U +@end example + + +ND, NG, NS, and NB are the drain, gate, source, and bulk (substrate) +nodes, respectively. MNAME is the model name. L and W are the channel +length and width, in meters. AD and AS are the areas of the drain and +source diffusions, in meters@math{^2}. Note that the suffix U specifies +microns (1e-6 m) and P sq-microns (1e-12 m@math{^2}). If any of L, W, +AD, or AS are not specified, default values are used. The use of +defaults simplifies input file preparation, as well as the editing +required if device geometries are to be changed. PD and PS are the +perimeters of the drain and source junctions, in meters. NRD and NRS +designate the equivalent number of squares of the drain and source +diffusions; these values multiply the sheet resistance RSH specified on +the .MODEL control line for an accurate representation of the parasitic +series drain and source resistance of each transistor. PD and PS +default to 0.0 while NRD and NRS to 1.0. OFF indicates an (optional) +initial condition on the device for dc analysis. The (optional) initial +condition specification using IC=VDS, VGS, VBS is intended for use with +the UIC option on the .TRAN control line, when a transient analysis is +desired starting from other than the quiescent operating point. See the +.IC control line for a better and more convenient way to specify +transient initial conditions. The (optional) TEMP value is the +temperature at which this device is to operate, and overrides the +temperature specification on the .OPTION control line. The temperature +specification is ONLY valid for level 1, 2, 3, and 6 MOSFETs, not for +level 4 or 5 (BSIM) devices. + + + + +@node MOSFET Models (NMOS/PMOS), MESFETs, MOSFETs, Transistors and Diodes +@subsection MOSFET Models (NMOS/PMOS) + + +SPICE provides four MOSFET device models, which differ in the +formulation of the I-V characteristic. The variable LEVEL specifies the +model to be used: + +@table @code + +@item LEVEL=1 + +Shichman-Hodges + +@item LEVEL=2 + +MOS2 (as described in [1]) + +@item LEVEL=3 + +MOS3, a semi-empirical model(see [1]) + +@item LEVEL=4 + +BSIM (as described in [3]) + +@item LEVEL=5 + +new BSIM (BSIM2; as described in [5]) + +@item LEVEL=6 + +MOS6 (as described in [2]) + +@end table + +The dc characteristics of the level 1 through level 3 MOSFETs are +defined by the device parameters VTO, KP, LAMBDA, PHI and GAMMA. These +parameters are computed by SPICE if process parameters (NSUB, TOX, ...) +are given, but userspecified values always override. VTO is positive +(negative) for enhancement mode and negative (positive) for depletion +mode N-channel (P-channel) devices. Charge storage is modeled by three +constant capacitors, CGSO, CGDO, and CGBO which represent overlap +capacitances, by the nonlinear thin-oxide capacitance which is +distributed among the gate, source, drain, and bulk regions, and by the +nonlinear depletion-layer capacitances for both substrate junctions +divided into bottom and periphery, which vary as the MJ and MJSW power +of junction voltage respectively, and are determined by the parameters +CBD, CBS, CJ, CJSW, MJ, MJSW and PB. Charge storage effects are modeled +by the piecewise linear voltages-dependent capacitance model proposed by +Meyer. The thin-oxide charge-storage effects are treated slightly +different for the LEVEL=1 model. These voltage-dependent capacitances +are included only if TOX is specified in the input description and they +are represented using Meyer's formulation. + +There is some overlap among the parameters describing the junctions, +e.g. the reverse current can be input either as IS (in A) or as JS (in +A/m@math{^2}). Whereas the first is an absolute value the second is +multiplied by AD and AS to give the reverse current of the drain and +source junctions respectively. This methodology has been chosen since +there is no sense in relating always junction characteristics with AD +and AS entered on the device line; the areas can be defaulted. The same +idea applies also to the zero-bias junction capacitances CBD and CBS (in +F) on one hand, and CJ (in F/m@math{^2}) on the other. The parasitic +drain and source series resistance can be expressed as either RD and RS +(in ohms) or RSH (in ohms/sq.), the latter being multiplied by the +number of squares NRD and NRS input on the device line. + +A discontinuity in the MOS level 3 model with respect to the KAPPA +parameter has been detected (see [10]). The supplied fix has been +implemented in Spice3f2 and later. Since this fix may affect parameter +fitting, the option "BADMOS3" may be set to use the old implementation +(see the section on simulation variables and the ".OPTIONS" line). +SPICE level 1, 2, 3 and 6 parameters: + +@example +name parameter units default example + + 1 LEVEL model index - 1 + 2 VTO zero-bias threshold voltage (V ) V 0.0 1.0 + TO 2 + 3 KP transconductance parameter A/V 2.0e-5 3.1e-5 + 1/2 + 4 GAMMA bulk threshold parameter (\) V 0.0 0.37 + 5 PHI surface potential (U) V 0.6 0.65 + 6 LAMBDA channel-length modulation + (MOS1 and MOS2 only) (L) 1/V 0.0 0.02 + 7 RD drain ohmic resistance Z 0.0 1.0 + 8 RS source ohmic resistance Z 0.0 1.0 + 9 CBD zero-bias B-D junction capacitance F 0.0 20fF + 10 CBS zero-bias B-S junction capacitance F 0.0 20fF + 11 IS bulk junction saturation current (I ) A 1.0e-14 1.0e-15 + S + 12 PB bulk junction potential V 0.8 0.87 + 13 CGSO gate-source overlap capacitance + per meter channel width F/m 0.0 4.0e-11 + 14 CGDO gate-drain overlap capacitance + per meter channel width F/m 0.0 4.0e-11 + 15 CGBO gate-bulk overlap capacitance + per meter channel length F/m 0.0 2.0e-10 + 16 RSH drain and source diffusion + sheet resistance Z/[] 0.0 10.0 + 17 CJ zero-bias bulk junction bottom cap. + 2 + per sq-meter of junction area F/m 0.0 2.0e-4 + 18 MJ bulk junction bottom grading coeff. - 0.5 0.5 + 19 CJSW zero-bias bulk junction sidewall cap. + per meter of junction perimeter F/m 0.0 1.0e-9 + 20 MJSW bulk junction sidewall grading coeff. - 0.50(level1) + 0.33(level2, 3) + 21 JS bulk junction saturation current + 2 + per sq-meter of junction area A/m 1.0e-8 + 22 TOX oxide thickness meter 1.0e-7 1.0e-7 + 3 + 23 NSUB substrate doping 1/cm 0.0 4.0e15 + 2 + 24 NSS surface state density 1/cm 0.0 1.0e10 + 2 + 25 NFS fast surface state density 1/cm 0.0 1.0e10 + + 26 TPG type of gate material: - 1.0 + +1 opp. to substrate + -1 same as substrate + 0 Al gate + 27 XJ metallurgical junction depth meter 0.0 1M + 28 LD lateral diffusion meter 0.0 0.8M + 2 + 29 UO surface mobility cm /Vs 600 700 + 30 UCRIT critical field for mobility + degradation (MOS2 only) V/cm 1.0e4 1.0e4 + 31 UEXP critical field exponent in + mobility degradation (MOS2 only) - 0.0 0.1 + 32 UTRA transverse field coeff. (mobility) + (deleted for MOS2) - 0.0 0.3 + 33 VMAX maximum drift velocity of carriers m/s 0.0 5.0e4 + 34 NEFF total channel-charge (fixed and + mobile) coefficient (MOS2 only) - 1.0 5.0 + 35 KF flicker noise coefficient - 0.0 1.0e-26 + 36 AF flicker noise exponent - 1.0 1.2 + 37 FC coefficient for forward-bias + depletion capacitance formula - 0.5 + 38 DELTA width effect on threshold voltage + (MOS2 and MOS3) - 0.0 1.0 + 39 THETA mobility modulation (MOS3 only) 1/V 0.0 0.1 + 40 ETA static feedback (MOS3 only) - 0.0 1.0 + 41 KAPPA saturation field factor (MOS3 only) - 0.2 0.5 + o + 42 TNOM parameter measurement temperature C 27 50 +@end example + + +The level 4 and level 5 (BSIM1 and BSIM2) parameters are all values +obtained from process characterization, and can be generated +automatically. J. Pierret [4] describes a means of generating a +'process' file, and the program Proc2Mod provided with SPICE3 converts +this file into a sequence of BSIM1 ".MODEL" lines suitable for inclusion +in a SPICE input file. Parameters marked below with an * in the l/w +column also have corresponding parameters with a length and width +dependency. For example, VFB is the basic parameter with units of +Volts, and LVFB and WVFB also exist and have units of Volt-Mmeter The +formula + + +@tex +$$ + P = P_0 + { P_L \over L_{\rm effective} } + { P_W \over W_{\rm effective} } +$$ +@end tex +@ifnottex +@example + P P + L W + P = P + ---------- + ---------- + 0 + L W + effective effective +@end example +@end ifnottex + +is used to evaluate the parameter for the actual device specified with + +@tex +$$ + L_{\rm effective} = L_{\rm input} - DL +$$ +@end tex +@ifnottex +@example + L = L - DL + effective input +@end example +@end ifnottex + + and + +@tex +$$ + W_{\rm effective} = W_{\rm input} - DW +$$ +@end tex +@ifnottex +@example + W = W - DW + effective input +@end example +@end ifnottex + + + +Note that unlike the other models in SPICE, the BSIM model is designed +for use with a process characterization system that provides all the +parameters, thus there are no defaults for the parameters, and leaving +one out is considered an error. For an example set of parameters and +the format of a process file, see the SPICE2 implementation notes[3]. + +For more information on BSIM2, see reference [5]. + + SPICE BSIM (level 4) parameters. + +@example + name parameter units l/w + + VFB flat-band voltage V * + PHI surface inversion potential V * + 1/2 + K1 body effect coefficient V * + K2 drain/source depletion charge-sharing coefficient - * + ETA zero-bias drain-induced barrier-lowering coefficient - * + 2 + MUZ zero-bias mobility cm /V-s + DL shortening of channel Mm + DW narrowing of channel Mm + -1 + U0 zero-bias transverse-field mobility degradation coefficient V * + U1 zero-bias velocity saturation coefficient Mm/V * + 2 2 + X2MZ sens. of mobility to substrate bias at v =0 cm /V -s * + ds -1 + X2E sens. of drain-induced barrier lowering effect to substrate bias V * + -1 + X3E sens. of drain-induced barrier lowering effect to drain bias at V =V V * + ds dd -2 + X2U0 sens. of transverse field mobility degradation effect to substrate bias V * + -2 + X2U1 sens. of velocity saturation effect to substrate bias MmV * + 2 2 + MUS mobility at zero substrate bias and at V =V cm /V -s + ds dd 2 2 + X2MS sens. of mobility to substrate bias at V =V cm /V -s * + ds dd 2 2 + X3MS sens. of mobility to drain bias at V =V cm /V -s * + ds dd -2 + X3U1 sens. of velocity saturation effect on drain bias at V =V MmV * + ds dd + TOX gate oxide thickness Mm + o + TEMP temperature at which parameters were measured C + VDD measurement bias range V + CGDO gate-drain overlap capacitance per meter channel width F/m + CGSO gate-source overlap capacitance per meter channel width F/m + CGBO gate-bulk overlap capacitance per meter channel length F/m + XPART gate-oxide capacitance-charge model flag N0 zero-bias subthreshold slope coefficient - * + NB sens. of subthreshold slope to substrate bias - * + ND sens. of subthreshold slope to drain bias - * + RSH drain and source diffusion sheet resistance Z/[] + 2 + JS source drain junction current density A/m + PB built in potential of source drain junction V + MJ Grading coefficient of source drain junction PBSW built in potential of source, drain junction sidewall V + MJSW grading coefficient of source drain junction sidewall 2 + CJ Source drain junction capacitance per unit area F/m + CJSW source drain junction sidewall capacitance per unit length F/m + WDF source drain junction default width m + DELL Source drain junction length reduction m +@end example + + +XPART = 0 selects a 40/60 drain/source charge partition in saturation, +while XPART=1 selects a 0/100 drain/source charge partition. + + +ND, NG, and NS are the drain, gate, and source nodes, respectively. +MNAME is the model name, AREA is the area factor, and OFF indicates an +(optional) initial condition on the device for dc analysis. If the area +factor is omitted, a value of 1.0 is assumed. The (optional) initial +condition specification, using IC=VDS, VGS is intended for use with the +UIC option on the .TRAN control line, when a transient analysis is +desired starting from other than the quiescent operating point. See the +.IC control line for a better way to set initial conditions. + + + + +@node MESFETs, MESFET Models (NMF/PMF), MOSFET Models (NMOS/PMOS), Transistors and Diodes +@subsection MESFETs + + General form: + +@example + ZXXXXXXX ND NG NS MNAME +@end example + + + Examples: + +@example + Z1 7 2 3 ZM1 OFF +@end example + + + + + + +@node MESFET Models (NMF/PMF), , MESFETs, Transistors and Diodes +@subsection MESFET Models (NMF/PMF) + + +The MESFET model is derived from the GaAs FET model of Statz et al. as +described in [11]. The dc characteristics are defined by the parameters +VTO, B, and BETA, which determine the variation of drain current with +gate voltage, ALPHA, which determines saturation voltage, and LAMBDA, +which determines the output conductance. The formula are given by: + +@tex +$$ +\cases{I_d = {B (V_{gs} - V_T)^2 \over 1 + b(V_{gs} - V_T)} + \left| 1 - \left| 1 - A {V_{ds} \over 3 } \right|^3 \right| + (1 + L V_{ds}) & for $0 < V_{ds} < 3/A$ \cr + I_d = {B (V_{gs} - V_T)^2 \over 1 + b(V_{gs} - V_T)} + (1 + L V_{ds}) & for $V_{ds} > 3/A$ \cr} +$$ +@end tex +@ifnottex +@example + 3 + 2 + B (V -V ) | | V | | 3 + gs T ds _ + I = --------------- |1 - |1-A---| |(1 + L V ) for 0 < V < + d ds ds + 1 + b(V - V ) | | 3 | | A + gs T + 2 + B (V -V ) 3 + gs T _ + I = ---------------(1 + L V ) for V > + d ds ds + 1 + b(V - V ) A + gs T +@end example +@end ifnottex + +Two ohmic resistances, RD and RS, are included. Charge storage is +modeled by total gate charge as a function of gate-drain and gate-source +voltages and is defined by the parameters CGS, CGD, and PB. + + +@example +name parameter units default example area + + 1 VTO pinch-off voltage V -2.0 -2.0 + 2 + 2 BETA transconductance parameter A/V 1.0e-4 1.0e-3 * + 3 B doping tail extending parameter 1/V 0.3 0.3 * + 4 ALPHA saturation voltage parameter 1/V 2 2 * + 5 LAMBDA channel-length modulation + parameter 1/V 0 1.0e-4 + 6 RD drain ohmic resistance Z 0 100 * + 7 RS source ohmic resistance Z 0 100 * + 8 CGS zero-bias G-S junction capacitance F 0 5pF * + 9 CGD zero-bias G-D junction capacitance F 0 1pF * + 10 PB gate junction potential V 1 0.6 + 11 KF flicker noise coefficient - 0 + 12 AF flicker noise exponent - 1 + 13 FC coefficient for forward-bias - 0.5 + depletion capacitance formula +@end example + + + +@node Analyses and Output Control, Interactive Interpreter, Circuit Elements and Models, Top +@chapter Analyses and Output Control + + + +The following command lines are for specifying analyses or plots within +the circuit description file. Parallel commands exist in the +interactive command interpreter (detailed in the following section). +Specifying analyses and plots (or tables) in the input file is useful +for batch runs. Batch mode is entered when either the -b option is +given or when the default input source is redirected from a file. In +batch mode, the analyses specified by the control lines in the input +file (e.g. ".ac", ".tran", etc.) are immediately executed (unless +".control" lines exists; see the section on the interactive command +interpretor). If the -r rawfile option is given then all data generated +is written to a Spice3 rawfile. The rawfile may be read by either the +interactive mode of Spice3 or by nutmeg; see the previous section for +details. In this case, the .SAVE line (see below) may be used to record +the value of internal device variables (see Appendix B). + +If a rawfile is not specified, then output plots (in "line-printer" +form) and tables can be printed according to the .PRINT, .PLOT, and +.FOUR control lines, described next. .PLOT, .PRINT, and .FOUR lines are +meant for compatibility with Spice2. + + +@menu +* Simulator Variables (.OPTIONS):: +* Initial Conditions:: +* Analyses:: +* Batch Output:: +@end menu + + + +@node Simulator Variables (.OPTIONS), Initial Conditions, Analyses and Output Control, Analyses and Output Control +@section Simulator Variables (.OPTIONS) + + +Various parameters of the simulations available in Spice3 can be altered +to control the accuracy, speed, or default values for some devices. +These parameters may be changed via the "set" command (described later +in the section on the interactive front-end) or via the ".OPTIONS" line: + + General form: + +@example + .OPTIONS OPT1 OPT2 ... (or OPT=OPTVAL ...) +@end example + + + Examples: + +@example + .OPTIONS RELTOL=.005 TRTOL=8 +@end example + + +The options line allows the user to reset program control and user +options for specific simulation purposes. Additional options for Nutmeg +may be specified as well and take effect when Nutmeg reads the input +file. Options specified to Nutmeg via the 'set' command are also passed +on to SPICE3 as if specified on a .OPTIONS line. See the following +section on the interactive command interpreter for the parameters which +may be set with a .OPTIONS line and the format of the 'set' command. +Any combination of the following options may be included, in any order. +'x' (below) represents some positive number. + +@vtable @code + +@item ABSTOL=x + +resets the absolute current error tolerance of the program. The default +value is 1 picoamp. + +@item BADMOS3 + +Use the older version of the MOS3 model with the "kappa" discontinuity. + +@item CHGTOL=x + +resets the charge tolerance of the program. The default value is +1.0e-14. + +@item DEFAD=x + +resets the value for MOS drain diffusion area; the default is 0.0. + +@item DEFAS=x + +resets the value for MOS source diffusion area; the default is 0.0. + +@item DEFL=x + +resets the value for MOS channel length; the default is 100.0 +micrometer. + +@item DEFW=x + +resets the value for MOS channel width; the default is 100.0 micrometer. + +@item GMIN=x + +resets the value of GMIN, the minimum conductance allowed by the +program. The default value is 1.0e-12. + +@item ITL1=x + +resets the dc iteration limit. The default is 100. + +@item ITL2=x + +resets the dc transfer curve iteration limit. The default is 50. + +@item ITL3=x + +resets the lower transient analysis iteration limit. the default value +is 4. (Note: not implemented in Spice3). + +@item ITL4=x + +resets the transient analysis timepoint iteration limit. the default is +10. + +@item ITL5=x + +resets the transient analysis total iteration limit. the default is +5000. Set ITL5=0 to omit this test. (Note: not implemented in Spice3). + +@item KEEPOPINFO + +Retain the operating point information when either an AC, Distortion, or +Pole-Zero analysis is run. This is particularly useful if the circuit +is large and you do not want to run a (redundant) ".OP" analysis. + +@item METHOD=name + +sets the numerical integration method used by SPICE. Possible names are +"Gear" or "trapezoidal" (or just "trap"). The default is trapezoidal. + +@item PIVREL=x + +resets the relative ratio between the largest column entry and an +acceptable pivot value. The default value is 1.0e-3. In the numerical +pivoting algorithm the allowed minimum pivot value is determined by +EPSREL=AMAX1(PIVREL*MAXVAL, PIVTOL) where MAXVAL is the maximum element +in the column where a pivot is sought (partial pivoting). + +@item PIVTOL=x + +resets the absolute minimum value for a matrix entry to be accepted as a +pivot. The default value is 1.0e-13. + +@item RELTOL=x + +resets the relative error tolerance of the program. The default value +is 0.001 (0.1%). + +@item TEMP=x + +Resets the operating temperature of the circuit. The default value is +27 deg C (300 deg K). TEMP can be overridden by a temperature +specification on any temperature dependent instance. + +@item TNOM=x + +resets the nominal temperature at which device parameters are measured. +The default value is 27 deg C (300 deg K). TNOM can be overridden by a +specification on any temperature dependent device model. + +@item TRTOL=x + +resets the transient error tolerance. The default value is 7.0. This +parameter is an estimate of the factor by which SPICE overestimates the +actual truncation error. + +@item TRYTOCOMPACT + +Applicable only to the LTRA model. When specified, the simulator tries +to condense LTRA transmission lines' past history of input voltages and +currents. + +@item VNTOL=x + +resets the absolute voltage error tolerance of the program. The default +value is 1 microvolt. + +@end vtable + +In addition, the following options have the listed effect when operating +in spice2 emulation mode: + +@table @code + +@item ACCT + +causes accounting and run time statistics to be printed + +@item LIST + +causes the summary listing of the input data to be printed + +@item NOMOD + +suppresses the printout of the model parameters + +@item NOPAGE + +suppresses page ejects + +@item NODE + +causes the printing of the node table. + +@item OPTS + +causes the option values to be printed. + +@end table + + + +@node Initial Conditions, Analyses, Simulator Variables (.OPTIONS), Analyses and Output Control +@section Initial Conditions + + + +@menu +* Specify Initial Node Voltage Guesses:: +* Set Initial Conditions:: +@end menu + +@node Specify Initial Node Voltage Guesses, Set Initial Conditions, Initial Conditions, Initial Conditions +@subsection .NODESET: Specify Initial Node Voltage Guesses + + General form: + +@example + .NODESET V(NODNUM)=VAL V(NODNUM)=VAL ... +@end example + + + Examples: + +@example + .NODESET V(12)=4.5 V(4)=2.23 +@end example + + + +The Nodeset line helps the program find the dc or initial transient +solution by making a preliminary pass with the specified nodes held to +the given voltages. The restriction is then released and the iteration +continues to the true solution. The .NODESET line may be necessary for +convergence on bistable or a-stable circuits. In general, this line +should not be necessary. + + + + +@node Set Initial Conditions, , Specify Initial Node Voltage Guesses, Initial Conditions +@subsection .IC: Set Initial Conditions + + General form: + +@example + .IC V(NODNUM)=VAL V(NODNUM)=VAL ... +@end example + + + Examples: + +@example + .IC V(11)=5 V(4)=-5 V(2)=2.2 +@end example + + + +The IC line is for setting transient initial conditions. It has two +different interpretations, depending on whether the UIC parameter is +specified on the .TRAN control line. Also, one should not confuse this +line with the .NODESET line. The .NODESET line is only to help dc +convergence, and does not affect final bias solution (except for +multi-stable circuits). The two interpretations of this line are as +follows: + +@enumerate + +@item +When the UIC parameter is specified on the .TRAN line, then the node +voltages specified on the .IC control line are used to compute the +capacitor, diode, BJT, JFET, and MOSFET initial conditions. This is +equivalent to specifying the IC=... parameter on each device line, but +is much more convenient. The IC=... parameter can still be specified +and takes precedence over the .IC values. Since no dc bias (initial +transient) solution is computed before the transient analysis, one +should take care to specify all dc source voltages on the .IC control +line if they are to be used to compute device initial conditions. + +@item +When the UIC parameter is not specified on the .TRAN control line, the +dc bias (initial transient) solution is computed before the transient +analysis. In this case, the node voltages specified on the .IC control +line is forced to the desired initial values during the bias solution. +During transient analysis, the constraint on these node voltages is +removed. This is the preferred method since it allows SPICE to compute +a consistent dc solution. +@end enumerate + + +@node Analyses, Batch Output, Initial Conditions, Analyses and Output Control +@section Analyses + + + + +@menu +* AC Small-Signal AC Analysis:: +* DC Transfer Function:: +* DISTRO Distortion Analysis:: +* NOISE Noise Analysis:: +* OP Operating Point Analysis:: +* PZ Pole-Zero Analysis:: +* SENS; DC or Small-Signal AC Sensitivity Analysis:: +* TF Transfer Function Analysis:: +* TRAN Transient Analysis:: +@end menu + +@node AC Small-Signal AC Analysis, DC Transfer Function, Analyses, Analyses +@subsection .AC: Small-Signal AC Analysis + + General form: + +@example + .AC DEC ND FSTART FSTOP + .AC OCT NO FSTART FSTOP + .AC LIN NP FSTART FSTOP +@end example + + + Examples: + +@example + .AC DEC 10 1 10K + .AC DEC 10 1K 100MEG + .AC LIN 100 1 100HZ +@end example + + + + +DEC stands for decade variation, and ND is the number of points per +decade. OCT stands for octave variation, and NO is the number of points +per octave. LIN stands for linear variation, and NP is the number of +points. FSTART is the starting frequency, and FSTOP is the final +frequency. If this line is included in the input file, SPICE performs +an AC analysis of the circuit over the specified frequency range. Note +that in order for this analysis to be meaningful, at least one +independent source must have been specified with an ac value. + + + + +@node DC Transfer Function, DISTRO Distortion Analysis, AC Small-Signal AC Analysis, Analyses +@subsection .DC: DC Transfer Function + + General form: + +@example + .DC SRCNAM VSTART VSTOP VINCR [SRC2 START2 STOP2 INCR2] +@end example + + + Examples: + +@example + .DC VIN 0.25 5.0 0.25 + .DC VDS 0 10 .5 VGS 0 5 1 + .DC VCE 0 10 .25 IB 0 10U 1U +@end example + + + +The DC line defines the dc transfer curve source and sweep limits (again +with capacitors open and inductors shorted). SRCNAM is the name of an +independent voltage or current source. VSTART, VSTOP, and VINCR are the +starting, final, and incrementing values respectively. The first +example causes the value of the voltage source VIN to be swept from 0.25 +Volts to 5.0 Volts in increments of 0.25 Volts. A second source (SRC2) +may optionally be specified with associated sweep parameters. In this +case, the first source is swept over its range for each value of the +second source. This option can be useful for obtaining semiconductor +device output characteristics. See the second example circuit +description in Appendix A. + + + + +@node DISTRO Distortion Analysis, NOISE Noise Analysis, DC Transfer Function, Analyses +@subsection .DISTO: Distortion Analysis + + General form: + +@example + .DISTO DEC ND FSTART FSTOP + .DISTO OCT NO FSTART FSTOP + .DISTO LIN NP FSTART FSTOP +@end example + + + Examples: + +@example + .DISTO DEC 10 1kHz 100Mhz + .DISTO DEC 10 1kHz 100Mhz 0.9 +@end example + + + + +The Disto line does a small-signal distortion analysis of the circuit. +A multi-dimensional Volterra series analysis is done using +multi-dimensional Taylor series to represent the nonlinearities at the +operating point. Terms of up to third order are used in the series +expansions. + +If the optional parameter F2OVERF1 is not specified, .DISTO does a +harmonic analysis - i.e., it analyses distortion in the circuit using +only a single input frequency @math{F_1}, which is swept as specified by +arguments of the .DISTO command exactly as in the .AC command. Inputs +at this frequency may be present at more than one input source, and +their magnitudes and phases are specified by the arguments of the +DISTOF1 keyword in the input file lines for the input sources (see the +description for independent sources). (The arguments of the DISTOF2 +keyword are not relevant in this case). + +The analysis produces information about the A.C. values of all node +voltages and branch currents at the harmonic frequencies @math{2F_1} and +@math{3F_1}, vs. the input frequency @math{F_1} as it is swept. (A +value of 1 (as a complex distortion output) signifies +@math{\cos(2J(2F_1)t)} at @math{2F_1} and @math{\cos(2J(3F_1)t)} at +@math{3F_1}, using the convention that 1 at the input fundamental +frequency is equivalent to @math{\cos(2JF_1t)}.) The distortion +component desired (@math{2F_1} or @math{3F_1}) can be selected using +commands in nutmeg, and then printed or plotted. (Normally, one is +interested primarily in the magnitude of the harmonic components, so the +magnitude of the AC distortion value is looked at). It should be noted +that these are the A.C. values of the actual harmonic components, and +are not equal to HD2 and HD3. To obtain HD2 and HD3, one must divide by +the corresponding A.C. values at @math{F_1}, obtained from an .AC line. +This division can be done using nutmeg commands. + +If the optional F2OVERF1 parameter is specified, it should be a real +number between (and not equal to) 0.0 and 1.0; in this case, .DISTO does +a spectral analysis. It considers the circuit with sinusoidal inputs at +two different frequencies @math{F_1} and F_2. @math{F_1} is swept +according to the .DISTO control line options exactly as in the .AC +control line. @math{F_2} is kept fixed at a single frequency as @math{F_1} +sweeps - the value at which it is kept fixed is equal to F2OVERF1 times +FSTART. Each independent source in the circuit may potentially have two +(superimposed) sinusoidal inputs for distortion, at the frequencies +@math{F_1} and F_2. The magnitude and phase of the @math{F_1} component +are specified by the arguments of the DISTOF1 keyword in the source's +input line (see the description of independent sources); the magnitude +and phase of the @math{F_2} component are specified by the arguments of the +DISTOF2 keyword. The analysis produces plots of all node +voltages/branch currents at the intermodulation product frequencies +@math{F_1 + F_2}, @math{F_1 - F_2}, and @math{(2 F_1) - F_2}, vs the +swept frequency @math{F_1}. The IM product of interest may be selected +using the setplot command, and displayed with the print and plot +commands. It is to be noted as in the harmonic analysis case, the +results are the actual AC voltages and currents at the intermodulation +frequencies, and need to be normalized with respect to .AC values to +obtain the IM parameters. + +If the DISTOF1 or DISTOF2 keywords are missing from the description of +an independent source, then that source is assumed to have no input at +the corresponding frequency. The default values of the magnitude and +phase are 1.0 and 0.0 respectively. The phase should be specified in +degrees. + +It should be carefully noted that the number F2OVERF1 should ideally be +an irrational number, and that since this is not possible in practice, +efforts should be made to keep the denominator in its fractional +representation as large as possible, certainly above 3, for accurate +results (i.e., if F2OVERF1 is represented as a fraction @math{A/B}, +where @math{A} and @math{B} are integers with no common factors, +@math{B} should be as large as possible; note that @math{A < B} because +F2OVERF1 is constrained to be @math{< 1}). To illustrate why, consider +the cases where F2OVERF1 is 49/100 and 1/2. In a spectral analysis, the +outputs produced are at @math{F_1 + F_2}, @math{F_1 - F_2} and @math{2 +F_1 - F_2}. In the latter case, @math{F_1 - F_2 = F_2}, so the result +at the @math{F_1 - F_2} component is erroneous because there is the +strong fundamental @math{F_2} component at the same frequency. Also, +@math{F_1 + F_2 = 2 F_1 - F_2} in the latter case, and each result is +erroneous individually. This problem is not there in the case where +F2OVERF1 = 49/100, because @math{F_1-F_2 = 51/100} @math{F_1 < > 49/100} +@math{F_1 = F_2}. In this case, there are two very closely spaced +frequency components at @math{F_2} and @math{F_1 - F_2}. One of the +advantages of the Volterra series technique is that it computes +distortions at mix frequencies expressed symbolically (i.e. @math{n F_1 ++ m F_2}), therefore one is able to obtain the strengths of distortion +components accurately even if the separation between them is very small, +as opposed to transient analysis for example. The disadvantage is of +course that if two of the mix frequencies coincide, the results are not +merged together and presented (though this could presumably be done as a +postprocessing step). Currently, the interested user should keep track +of the mix frequencies himself or herself and add the distortions at +coinciding mix frequencies together should it be necessary. + + + + +@node NOISE Noise Analysis, OP Operating Point Analysis, DISTRO Distortion Analysis, Analyses +@subsection .NOISE: Noise Analysis + + General form: + +@example + .NOISE V(OUTPUT <,REF>) SRC ( DEC | LIN | OCT ) PTS FSTART FSTOP + + +@end example + + + Examples: + +@example + .NOISE V(5) VIN DEC 10 1kHZ 100Mhz + .NOISE V(5,3) V1 OCT 8 1.0 1.0e6 1 +@end example + + + +The Noise line does a noise analysis of the circuit. OUTPUT is the node +at which the total output noise is desired; if REF is specified, then +the noise voltage V(OUTPUT) - V(REF) is calculated. By default, REF is +assumed to be ground. SRC is the name of an independent source to which +input noise is referred. PTS, FSTART and FSTOP are .AC type parameters +that specify the frequency range over which plots are desired. +PTS_PER_SUMMARY is an optional integer; if specified, the noise +contributions of each noise generator is produced every PTS_PER_SUMMARY +frequency points. + +The .NOISE control line produces two plots - one for the Noise Spectral +Density curves and one for the total Integrated Noise over the specified +frequency range. All noise voltages/currents are in squared units +(V@math{^2} /Hz and A@math{^2}/Hz for spectral density, V@math{^2} and +A@math{^2} for integrated noise). + + + +@node OP Operating Point Analysis, PZ Pole-Zero Analysis, NOISE Noise Analysis, Analyses +@subsection .OP: Operating Point Analysis + + General form: + +@example + .OP +@end example + + +The inclusion of this line in an input file directs SPICE to determine +the dc operating point of the circuit with inductors shorted and +capacitors opened. Note: a DC analysis is automatically performed prior +to a transient analysis to determine the transient initial conditions, +and prior to an AC small-signal, Noise, and Pole-Zero analysis to +determine the linearized, small-signal models for nonlinear devices (see +the KEEPOPINFO variable above). + + + + +@node PZ Pole-Zero Analysis, SENS; DC or Small-Signal AC Sensitivity Analysis, OP Operating Point Analysis, Analyses +@subsection .PZ: Pole-Zero Analysis + + General form: + +@example + .PZ NODE1 NODE2 NODE3 NODE4 CUR POL + .PZ NODE1 NODE2 NODE3 NODE4 CUR ZER + .PZ NODE1 NODE2 NODE3 NODE4 CUR PZ + .PZ NODE1 NODE2 NODE3 NODE4 VOL POL + .PZ NODE1 NODE2 NODE3 NODE4 VOL ZER + .PZ NODE1 NODE2 NODE3 NODE4 VOL PZ +@end example + + + Examples: + +@example + .PZ 1 0 3 0 CUR POL + .PZ 2 3 5 0 VOL ZER + .PZ 4 1 4 1 CUR PZ +@end example + + +CUR stands for a transfer function of the type (output voltage)/(input +current) while VOL stands for a transfer function of the type (output +voltage)/(input voltage). POL stands for pole analysis only, ZER for +zero analysis only and PZ for both. This feature is provided mainly +because if there is a nonconvergence in finding poles or zeros, then, at +least the other can be found. Finally, NODE1 and NODE2 are the two +input nodes and NODE3 and NODE4 are the two output nodes. Thus, there +is complete freedom regarding the output and input ports and the type of +transfer function. + +In interactive mode, the command syntax is the same except that the +first field is PZ instead of .PZ. To print the results, one should use +the command 'print all'. + + + + +@node SENS; DC or Small-Signal AC Sensitivity Analysis, TF Transfer Function Analysis, PZ Pole-Zero Analysis, Analyses +@subsection .SENS: DC or Small-Signal AC Sensitivity Analysis + + General form: + +@example + .SENS OUTVAR + .SENS OUTVAR AC DEC ND FSTART FSTOP + .SENS OUTVAR AC OCT NO FSTART FSTOP + .SENS OUTVAR AC LIN NP FSTART FSTOP +@end example + + + Examples: + +@example + .SENS V(1,OUT) + .SENS V(OUT) AC DEC 10 100 100k + .SENS I(VTEST) +@end example + + + + +The sensitivity of OUTVAR to all non-zero device parameters is +calculated when the SENS analysis is specified. OUTVAR is a circuit +variable (node voltage or voltage-source branch current). The first +form calculates sensitivity of the DC operating-point value of OUTVAR. +The second form calculates sensitivity of the AC values of OUTVAR. The +parameters listed for AC sensitivity are the same as in an AC analysis +(see ".AC" above). The output values are in dimensions of change in +output per unit change of input (as opposed to percent change in output +or per percent change of input). + + + + +@node TF Transfer Function Analysis, TRAN Transient Analysis, SENS; DC or Small-Signal AC Sensitivity Analysis, Analyses +@subsection .TF: Transfer Function Analysis + + General form: + +@example + .TF OUTVAR INSRC +@end example + + + Examples: + +@example + .TF V(5, 3) VIN + .TF I(VLOAD) VIN +@end example + + + +The TF line defines the small-signal output and input for the dc +small-signal analysis. OUTVAR is the smallsignal output variable and +INSRC is the small-signal input source. If this line is included, SPICE +computes the dc small-signal value of the transfer function +(output/input), input resistance, and output resistance. For the first +example, SPICE would compute the ratio of V(5, 3) to VIN, the +small-signal input resistance at VIN, and the smallsignal output +resistance measured across nodes 5 and 3. + + + + +@node TRAN Transient Analysis, , TF Transfer Function Analysis, Analyses +@subsection .TRAN: Transient Analysis + + General form: + +@example + .TRAN TSTEP TSTOP > +@end example + + + Examples: + +@example + .TRAN 1NS 100NS + .TRAN 1NS 1000NS 500NS + .TRAN 10NS 1US +@end example + + + +TSTEP is the printing or plotting increment for lineprinter output. For +use with the post-processor, TSTEP is the suggested computing increment. +TSTOP is the final time, and TSTART is the initial time. If TSTART is +omitted, it is assumed to be zero. The transient analysis always begins +at time zero. In the interval , the circuit is analyzed +(to reach a steady state), but no outputs are stored. In the interval +, the circuit is analyzed and outputs are stored. TMAX +is the maximum stepsize that SPICE uses; for default, the program +chooses either TSTEP or (TSTOP-TSTART)/50.0, whichever is smaller. TMAX +is useful when one wishes to guarantee a computing interval which is +smaller than the printer increment, TSTEP. + +UIC (use initial conditions) is an optional keyword which indicates that +the user does not want SPICE to solve for the quiescent operating point +before beginning the transient analysis. If this keyword is specified, +SPICE uses the values specified using IC=... on the various elements as +the initial transient condition and proceeds with the analysis. If the +.IC control line has been specified, then the node voltages on the .IC +line are used to compute the initial conditions for the devices. Look +at the description on the .IC control line for its interpretation when +UIC is not specified. + + + +@node Batch Output, , Analyses, Analyses and Output Control +@section Batch Output + +@menu +* SAVE:: +* PRINT:: +* PLOT:: +* FOUR Fourier Analysis of Transient Analysis Output:: +@end menu + +@node SAVE, PRINT, Batch Output, Batch Output +@subsection .SAVE Lines + + General form: + +@example + .SAVE vector vector vector ... +@end example + + + Examples: + +@example + .SAVE i(vin) input output + .SAVE @@m1[id] +@end example + + + +The vectors listed on the .SAVE line are recorded in the rawfile for use +later with spice3 or nutmeg (nutmeg is just the data-analysis half of +spice3, without the ability to simulate). The standard vector names are +accepted. If no .SAVE line is given, then the default set of vectors +are saved (node voltages and voltage source branch currents). If .SAVE +lines are given, only those vectors specified are saved. For more +discussion on internal device data, see Appendix B. See also the +section on the interactive command interpretor for information on how to +use the rawfile. + + + +@node PRINT, PLOT, SAVE, Batch Output +@subsection .PRINT Lines + + General form: + +@example + .PRINT PRTYPE OV1 +@end example + + + Examples: + +@example + .PRINT TRAN V(4) I(VIN) + .PRINT DC V(2) I(VSRC) V(23, 17) + .PRINT AC VM(4, 2) VR(7) VP(8, 3) +@end example + + +The Print line defines the contents of a tabular listing of one to eight +output variables. PRTYPE is the type of the analysis (DC, AC, TRAN, +NOISE, or DISTO) for which the specified outputs are desired. The form +for voltage or current output variables is the same as given in the +previous section for the print command; Spice2 restricts the output +variable to the following forms (though this restriction is not enforced +by Spice3): + + +@table @code + +@item V(N1<,N2>) + +specifies the voltage difference between nodes N1 and N2. If N2 (and +the preceding comma) is omitted, ground (0) is assumed. See the print +command in the previous section for more details. For compatibility +with spice2, the following five additional values can be accessed for +the ac analysis by replacing the "V" in V(N1,N2) with: + +@example + VR - real part + VI - imaginary part + VM - magnitude + VP - phase + VDB - 20 log10(magnitude) +@end example + +@item I(VXXXXXXX) + +specifies the current flowing in the independent voltage source named +VXXXXXXX. Positive current flows from the positive node, through the +source, to the negative node. For the ac analysis, the corresponding +replacements for the letter I may be made in the same way as described +for voltage outputs. + +@end table + +Output variables for the noise and distortion analyses have a different +general form from that of the other analyses. + +There is no limit on the number of .PRINT lines for each type of +analysis. + + + +@node PLOT, FOUR Fourier Analysis of Transient Analysis Output, PRINT, Batch Output +@subsection .PLOT Lines + + General form: + +@example + .PLOT PLTYPE OV1 <(PLO1, PHI1)> ... OV8> +@end example + + + Examples: + +@example + .PLOT DC V(4) V(5) V(1) + .PLOT TRAN V(17, 5) (2, 5) I(VIN) V(17) (1, 9) + .PLOT AC VM(5) VM(31, 24) VDB(5) VP(5) + .PLOT DISTO HD2 HD3(R) SIM2 + .PLOT TRAN V(5, 3) V(4) (0, 5) V(7) (0, 10) +@end example + + +The Plot line defines the contents of one plot of from one to eight +output variables. PLTYPE is the type of analysis (DC, AC, TRAN, NOISE, +or DISTO) for which the specified outputs are desired. The syntax for +the OVI is identical to that for the .PRINT line and for the plot +command in the interactive mode. + + +The overlap of two or more traces on any plot is indicated by the letter +X. + +When more than one output variable appears on the same plot, the first +variable specified is printed as well as plotted. If a printout of all +variables is desired, then a companion .PRINT line should be included. + +There is no limit on the number of .PLOT lines specified for each type of analysis. + + + +@node FOUR Fourier Analysis of Transient Analysis Output, , PLOT, Batch Output +@subsection .FOUR: Fourier Analysis of Transient Analysis Output + + General form: + +@example + .FOUR FREQ OV1 +@end example + + + Examples: + +@example + .FOUR 100K V(5) +@end example + + +The Four (or Fourier) line controls whether SPICE performs a Fourier +analysis as a part of the transient analysis. FREQ is the fundamental +frequency, and OV1, desired. The Fourier analysis is performed over the +interval , where TSTOP is the final time specified +for the transient analysis, and period is one period of the fundamental +frequency. The dc component and the first nine harmonics are +determined. For maximum accuracy, TMAX (see the .TRAN line) should be +set to period/100.0 (or less for very high-Q circuits). + + + +@node Interactive Interpreter, Bibliography, Analyses and Output Control, Top +@chapter Interactive Interpreter + +Spice3 consists of a simulator and a front-end for data analysis and +plotting. The front-end may be run as a separate "stand-alone" program +under the name Nutmeg. + +Nutmeg will read in the "raw" data output file created by spice -r or +with the write command in an interactive Spice3 session. Nutmeg or +interactive Spice3 can plot data from a simulation on a graphics +terminal or a workstation display. Most of the commands available in +the interactive Spice3 front end are available in nutmeg; where this is +not the case, Spice-only commands have been marked with an asterisk +("*"). Note that the raw output file is different from the data that +Spice2 writes to the standard output, which may also be produced by +spice3 with the "-b" command line option. + +Spice and Nutmeg use the X Window System for plotting if they find the +environment variable DISPLAY. Otherwise, a graphics-terminal +independent interface (MFB) is used. If you are using X on a +workstation, the DISPLAY variable should already be set; if you want to +display graphics on a system different from the one you are running +Spice3 or Nutmeg on, DISPLAY should be of the form "machine:0.0". See +the appropriate documentation on the X Window Sytem for more details. + + + Command Synopsis + +@example + spice [ -n ] [ -t term ] [ -r rawfile] [ -b ] [ -i ] [ input file ... ] + + nutmeg [ - ] [ -n ] [ -t term ] [ datafile ... ] +@end example + + + +Options are: + +@table @code + +@item - + +Don't try to load the default data file ("rawspice.raw") if no other +files are given. Nutmeg only. + +@item -n (or -N) + +Don't try to source the file ".spiceinit" upon startup. Normally spice +and nutmeg try to find the file in the current directory, and if it is +not found then in the user's home directory. + +@item -t term (or -T term) + +The program is being run on a terminal with mfb name term. + +@item -b (or -B) + +Run in batch mode. Spice3 reads the default input source (e.g. +keyboard) or reads the given input file and performs the analyses +specified; output is either Spice2-like line-printer plots ("ascii +plots") or a spice rawfile. See the following section for details. +Note that if the input source is not a terminal (e.g. using the IO +redirection notation of "<") Spice3 defaults to batch mode (-i +overrides). This option is valid for Spice3 only. + +@item -s (or -S) + +Run in server mode. This is like batch mode, except that a temporary +rawfile is used and then written to the standard output, preceded by a +line with a single "@@", after the simulation is done. This mode is used +by the spice daemon. This option is valid for Spice3 only. + +@item -i (or -I) + +Run in interactive mode. This is useful if the standard input is not a +terminal but interactive mode is desired. Command completion is not +available unless the standard input is a terminal, however. This option +is valid for Spice3 only. + +@item -r rawfile (or -P rawfile) + +Use rawfile as the default file into which the results of the simulation +are saved. This option is valid for Spice3 only. + +@end table + +Further arguments to spice are taken to be Spice3 input files, which are +read and saved (if running in batch mode then they are run immediately). +Spice3 accepts most Spice2 input file, and output ascii plots, fourier +analyses, and node printouts as specified in .plot, .four, and .print +cards. If an out parameter is given on a .width card, the effect is the +same as set width = .... Since Spice3 ascii plots do not use multiple +ranges, however, if vectors together on a .plot card have different +ranges they are not provide as much information as they would in Spice2. +The output of Spice3 is also much less verbose than Spice2, in that the +only data printed is that requested by the above cards. + +For nutmeg, further arguments are taken to be data files in binary or +ascii format (see sconvert(1)) which are loaded into nutmeg. If the +file is in binary format, it may be only partially completed (useful for +examining Spice2 output before the simulation is finished). One file +may contain any number of data sets from different analyses. + + +@menu +* Expressions:: +* Command Interpretation:: +* Commands:: +* Variables:: +* Bugs:: +@end menu + +@node Expressions, Command Interpretation, Interactive Interpreter, Interactive Interpreter +@section Expressions, Functions, and Constants + +Spice and Nutmeg data is in the form of vectors: time, voltage, etc. +Each vector has a type, and vectors can be operated on and combined +algebraicly in ways consistent with their types. Vectors are normally +created when a data file is read in (see the load command below), and +when the initial datafile is loaded. They can also be created with the +let command. + + +An expression is an algebraic formula involving vectors and scalars (a +scalar is a vector of length 1) and the following operations: + +@example + + - * / ^ % +@end example + +% is the modulo operator, and the comma operator has two meanings: if it +is present in the argument list of a userdefinable function, it serves +to separate the arguments. Otherwise, the term @code{x , y} is +synonymous with @code{x + j(y)}. + + +Also available are the logical operations & (and), | (or), ! (not), and +the relational operations <, >, >=, <=, =, and <> (not equal). If used +in an algebraic expression they work like they would in C, producing +values of 0 or 1. The relational operators have the following synonyms: + +@example + gt > + lt < + ge >= + le <= + ne <> + eq = + and & + or | + not ! +@end example + + +These are useful when < and > might be confused with IO redirection +(which is almost always). + + + +The following functions are available: + +@ftable @code + +@item mag(vector) + +The magnitude of vector + +@item ph(vector) + +The phase of vector + +@item j(vector) + +i (sqrt(-1)) times vector + +@item real(vector) + +The real component of vector + +@item imag(vector) + +The imaginary part of vector + +@item db(vector) + +20 log10(mag(vector)) + +@item log(vector) + +The logarithm (base 10) of vector + +@item ln(vector) + +The natural logarithm (base e) of vector + +@item exp(vector) + +e to the vector power + +@item abs(vector) + +The absolute value of vector. + +@item sqrt(vector) + +The square root of vector. + +@item sin(vector) + +The sine of vector. + +@item cos(vector) + +The cosine of vector. + +@item tan(vector) + +The tangent of vector. + +@item atan(vector) + +The inverse tangent of vector. + +@item norm(vector) + +The vector normalized to 1 (i.e, the largest magnitude of any component +is 1). + +@item rnd(vector) + +A vector with each component a random integer between 0 and the absolute +value of the vectors's corresponding com ponent. + +@item mean(vector) + +The result is a scalar (a length 1 vec tor) that is the mean of the +elements of vector. + +@item vector(number) + +The result is a vector of length number, with elements 0, 1, ... number +- 1. If number is a vector then just the first element is taken, and if +it isn't an in teger then the floor of the magnitude is used. + +@item length(vector) + +The length of vector. + +@item interpolate(plot.vector) + +The result of interpolating the named vector onto the scale of +the current plot. This function uses the variable polydegree to +determine the degree of interpolation. + +@item deriv(vector) + +Calculates the derivative of the given vector. This uses numeric +differentia tion by interpolating a polynomial and may not produce +satisfactory results (particularly with iterated differentiation). The +implementation only caculates the dirivative with respect to the real +componant of that vector's scale. + +@end ftable + +A vector may be either the name of a vector already defined or a +floating-point number (a scalar). A number may be written in any format +acceptable to SPICE, such as 14.6Meg or -1.231e-4. Note that you can +either use scientific notation or one of the abbreviations like MEG or +G, but not both. As with SPICE, a number may have trailing alphabetic +characters after it. + +The notation expr [num] denotes the num'th element of expr. For +multi-dimensional vectors, a vector of one less dimension is returned. +Also for multi-dimensional vectors, the notation expr[m][n] will return +the nth element of the mth subvector. To get a subrange of a vector, +use the form expr[lower, upper]. + +To reference vectors in a plot that is not the current plot (see the +setplot command, below), the notation plotname.vecname can be used. + + +Either a plotname or a vector name may be the wildcard all. If the +plotname is all, matching vectors from all plots are specified, and if +the vector name is all, all vectors in the specified plots are +referenced. Note that you may not use binary operations on expressions +involving wildcards - it is not obvious what all + all should denote, +for instance. Thus some (contrived) examples of expressions are: + +@example + cos(TIME) + db(v(3)) + sin(cos(log([1 2 3 4 5 6 7 8 9 10]))) + TIME * rnd(v(9)) - 15 * cos(vin#branch) ^ [7.9e5 8] + not ((ac3.FREQ[32] & tran1.TIME[10]) gt 3) +@end example + + +Vector names in spice may have a name such as @@name[param], where name +is either the name of a device instance or model. This denotes the +value of the param parameter of the device or model. See Appendix B for +details of what parameters are available. The value is a vector of +length 1. This function is also available with the show command, and is +available with variables for convenience for command scripts. + + +There are a number of pre-defined constants in nutmeg. They are: + +@vtable @code + +@item pi + +J (3.14159...) + +@item e + +The base of natural logarithms (2.71828...) + +@item c + +The speed of light (299,792,500 m/sec) + +@item i + +The square root of -1 + +@item kelvin + +Absolute 0 in Centigrade (-273.15 °C) + +@item echarge + +The charge on an electron (1.6021918e-19 C) + +@item boltz + +Boltzman's constant (1.3806226e-23) + +@item planck + +Planck's constant (h = 6.626200e-34) + +@end vtable + +These are all in MKS units. If you have another variable with a name +that conflicts with one of these then it takes precedence. + + +@menu +* Command Interpretation:: +* Commands:: +* Variables:: +* Bugs:: +@end menu + +@node Command Interpretation, Commands, Expressions, Interactive Interpreter +@section Command Interpretation + +If a word is typed as a command, and there is no built-in command with +that name, the directories in the sourcepath list are searched in order +for the file. If it is found, it is read in as a command file (as if it +were sourced). Before it is read, however, the variables argc and argv +are set to the number of words following the filename on the command +line, and a list of those words respectively. After the file is +finished, these variables are unset. Note that if a command file calls +another, it must save its argv and argc since they are altered. Also, +command files may not be re-entrant since there are no local variables. +(Of course, the procedures may explicitly manipulate a stack...) This +way one can write scripts analogous to shell scripts for nutmeg and +Spice3. + +Note that for the script to work with Spice3, it must begin with a blank +line (or whatever else, since it is thrown away) and then a line with +.control on it. This is an unfortunate result of the source command +being used for both circuit input and command file execution. Note also +that this allows the user to merely type the name of a circuit file as a +command and it is automatically run. The commands are executed +immediately, without running any analyses that may be spicified in the +circuit (to execute the analyses before the script executes, include a +"run" command in the script). + +There are various command scripts installed in +/usr/local/lib/spice/scripts (or whatever the path is on your machine), +and the default sourcepath includes this directory, so you can use these +command files (almost) like builtin commands. + + +@node Commands, Variables, Command Interpretation, Interactive Interpreter +@section Commands + +@menu +* AC:: +* Alias:: +* Alter:: +* Asciiplot:: +* Aspice:: +* Bug:: +* Cd:: +* Destroy:: +* DC:: +* Define:: +* Delete:: +* Diff:: +* Display:: +* Echo:: +* Edit:: +* Fourier:: +* Hardcopy:: +* Help:: +* History:: +* Iplot:: +* Jobs:: +* Let:: +* Linearize:: +* Listing:: +* Load:: +* Op:: +* Plot:: +* Print:: +* Quit:: +* Rehash:: +* Reset:: +* Reshape:: +* Resume:: +* Rspice:: +* Run:: +* Rusage:: +* Save:: +* Sens:: +* Set:: +* Setcirc:: +* Setplot:: +* Settype:: +* Shell:: +* Shift:: +* Show:: +* Showmod:: +* Source:: +* Status:: +* Step:: +* Stop:: +* Tf:: +* Trace:: +* Tran:: +* Transpose:: +* Unalias:: +* Undefine:: +* Unset:: +* Version:: +* Where:: +* Write:: +* Xgraph:: +* While - End:: +* Repeat - End:: +* Dowhile - End:: +* Foreach - End:: +* If - Then - Else:: +* Label:: +* Goto:: +* Continue:: +* Break:: +@end menu + + +@node AC, Alias, Commands, Commands +@subsection Ac*: Perform an AC, small-signal frequency response analysis + + General Form: + +@example + ac ( DEC | OCT | LIN ) N Fstart Fstop +@end example + + +Do an ac analysis. See the previous sections of this manual for more +details. + + + +@node Alias, Alter, AC, Commands +@subsection Alias: Create an alias for a command + + General Form: + +@example + alias [word] [text ...] +@end example + + +Causes word to be aliased to text. History substitutions may be used, +as in C-shell aliases. + + + +@node Alter, Asciiplot, Alias, Commands +@subsection Alter*: Change a device or model parameter + + General Form: + +@example + alter device value + alter device parameter value [ parameter value ] +@end example + + +Alter changes the value for a device or a specified parameter of a +device or model. The first form is used by simple devices which have +one principal value (resistors, capacitors, etc.) where the second form +is for more complex devices (bjt's, etc.). Model parameters can be +changed with the second form if the name contains a "#". + +For specifying vectors as values, start the vector with "[", followed by +the values in the vector, and end with "]". Be sure to place a space +between each of the values and before and after the "[" and "]". + + + +@node Asciiplot, Aspice, Alter, Commands +@subsection Asciiplot: Plot values using old-style character plots + + General Form: + +@example + asciiplot plotargs +@end example + + +Produce a line printer plot of the vectors. The plot is sent to the +standard output, so you can put it into a file with asciiplot args ... > +file. The set options width, height, and nobreak determine the width +and height of the plot, and whether there are page breaks, respectively. +Note that you will have problems if you try to asciiplot something with +an X-scale that isn't monotonic (i.e, something like sin(TIME) ), +because asciiplot uses a simple-minded linear interpolation. + + + +@node Aspice, Bug, Asciiplot, Commands +@subsection Aspice: Asynchronous spice run + + General Form: + +@example + aspice input-file [output-file] +@end example + + +Start a SPICE-3 run, and when it is finished load the resulting data. +The raw data is kept in a temporary file. If output-file is specified +then the diagnostic output is directed into that file, otherwise it is +thrown away. + + + +@node Bug, Cd, Aspice, Commands +@subsection Bug: Mail a bug report + + General Form: + +@example + bug +@end example + + +Send a bug report. Please include a short summary of the problem, the +version number and name of the operating system that you are running, +the version of Spice that you are running, and the relevant spice input +file. (If you have defined BUGADDR, the mail is delivered to there.) + + + +@node Cd, Destroy, Bug, Commands +@subsection Cd: Change directory + + General Form: + +@example + cd [directory] +@end example + + +Change the current working directory to directory, or to the user's home +directory if none is given. + + + +@node Destroy, DC, Cd, Commands +@subsection Destroy: Delete a data set + + General Form: + +@example + destroy [plotnames | all] +@end example + + +Release the memory holding the data for the specified runs. + + + +@node DC, Define, Destroy, Commands +@subsection Dc*: Perform a DC-sweep analysis + + General Form: + +@example + dc Source-Name Vstart Vstop Vincr [ Source2 Vstart2 Vstop2 Vincr2 ] +@end example + + +Do a dc transfer curve analysis. See the previous sections of this +manual for more details. + + + +@node Define, Delete, DC, Commands +@subsection Define: Define a function + + General Form: + +@example + define function(arg1, arg2, ...) expression +@end example + + +Define the user-definable function with the name function and arguments +arg1, arg2, ... to be expression, which may involve the arguments. When +the function is later used, the arguments it is given are substituted +for the formal arguments when it is parsed. If expression is not +present, any definition for function is printed, and if there are no +arguments to define then all currently active definitions are printed. +Note that you may have different functions defined with the same name +but different arities. + + + +Some useful definitions are: + +@example + define max(x,y) (x > y) * x + (x <= y) * y + define min(x,y) (x < y) * x + (x >= y) * y +@end example + + + +@node Delete, Diff, Define, Commands +@subsection Delete*: Remove a trace or breakpoint + + General Form: + +@example + delete [ debug-number ... ] +@end example + + +Delete the specified breakpoints and traces. The debug numbers are +those shown by the status command (unless you do status > file, in which +case the debug numbers are not printed). + + + +@node Diff, Display, Delete, Commands +@subsection Diff: Compare vectors + + General Form: + +@example + diff plot1 plot2 [vec ...] +@end example + + +Compare all the vectors in the specified plots, or only the named +vectors if any are given. There are different vectors in the two plots, +or any values in the vectors differ significantly the difference is +reported. The variable diff_abstol, diff_reltol, and diff_vntol are +used to determine a significant difference. + + + +@node Display, Echo, Diff, Commands +@subsection Display: List known vectors and types + + General Form: + +@example + display [varname ...] +@end example + + +Prints a summary of currently defined vectors, or of the names +specified. The vectors are sorted by name unless the variable nosort is +set. The information given is the name of the vector, the length, the +type of the vector, and whether it is real or complex data. +Additionally, one vector is labeled [scale]. When a command such as +plot is given without a vs argument, this scale is used for the X-axis. +It is always the first vector in a rawfile, or the first vector defined +in a new plot. If you undefine the scale (i.e, let TIME = []), one of +the remaining vectors becomes the new scale (which is undetermined). + + + +@node Echo, Edit, Display, Commands +@subsection Echo: Print text + + General Form: + +@example + echo [text...] +@end example + + +Echos the given text to the screen. + + + +@node Edit, Fourier, Echo, Commands +@subsection Edit*: Edit the current circuit + + General Form: + +@example + edit [ file ] +@end example + + +Print the current Spice3 input file into a file, call up the editor on +that file and allow the user to modify it, and then read it back in, +replacing the original file. If a filename is given, then edit that +file and load it, making the circuit the current one. + + + +@node Fourier, Hardcopy, Edit, Commands +@subsection Fourier: Perform a fourier transform + + General Form: + +@example + fourier fundamental_frequency [value ...] +@end example + + +Does a fourier analysis of each of the given values, using the first 10 +multiples of the fundamental frequency (or the first nfreqs, if that +variable is set - see below). The output is like that of the .four +Spice3 line. The values may be any valid expression. The values are +interpolated onto a fixed-space grid with the number of points given by +the fourgridsize variable, or 200 if it is not set. The interpolation +is of degree polydegree if that variable is set, or 1. If polydegree is +0, then no interpolation is done. This is likely to give erroneous +results if the time scale is not monotonic, though. + + + +@node Hardcopy, Help, Fourier, Commands +@subsection Hardcopy: Save a plot to a file for printing + + General Form: + +@example + hardcopy file plotargs +@end example + + +Just like plot, except creates a file called file containing the plot. +The file is an image in plot(5) format, and can be printed by either the +plot(1) program or lpr with the -g flag. + + + +@node Help, History, Hardcopy, Commands +@subsection Help: Print summaries of Spice3 commands + + General Form: + +@example + help [all] [command ...] +@end example + + +Prints help. If the argument all is given, a short description of +everything you could possibly type is printed. If commands are given, +descriptions of those commands are printed. Otherwise help for only a +few major commands is printed. + + + +@node History, Iplot, Help, Commands +@subsection History: Review previous commands + + General Form: + +@example + history [number] +@end example + + +Print out the history, or the last number commands typed at the +keyboard. Note: in Spice3 version 3a7 and earlier, all commands +(including ones read from files) were saved. + + + +@node Iplot, Jobs, History, Commands +@subsection Iplot*: Incremental plot + + General Form: + +@example + iplot [ node ...] +@end example + + +Incrementally plot the values of the nodes while Spice3 runs. The iplot +command can be used with the where command to find trouble spots in a +transient simulation. + + + +@node Jobs, Let, Iplot, Commands +@subsection Jobs: List active asynchronous spice runs + + General Form: + +@example + jobs +@end example + + +Report on the asynchronous SPICE-3 jobs currently running. Nutmeg +checks to see if the jobs are finished every time you execute a command. +If it is done then the data is loaded and becomes available. + + + +@node Let, Linearize, Jobs, Commands +@subsection Let: Assign a value to a vector + + General Form: + +@example + let name = expr +@end example + + +Creates a new vector called name with the value specified by expr, an +expression as described above. If expr is [] (a zero-length vector) +then the vector becomes undefined. Individual elements of a vector may +be modified by appending a subscript to name (ex. name[0]). If there +are no arguments, let is the same as display. + + + +@node Linearize, Listing, Let, Commands +@subsection Linearize*: Interpolate to a linear scale + + General Form: + +@example + linearize vec ... +@end example + + +Create a new plot with all of the vectors in the current plot, or only +those mentioned if arguments are given. The new vectors are +interpolated onto a linear time scale, which is determined by the values +of tstep, tstart, and tstop in the currently active transient analysis. +The currently loaded input file must include a transient analysis (a +tran command may be run interactively before the last reset, +alternately), and the current plot must be from this transient analysis. +This command is needed because Spice3 doesn't output the results from a +transient analysis in the same manner that Spice2 did. + + + +@node Listing, Load, Linearize, Commands +@subsection Listing*: Print a listing of the current circuit + + General Form: + +@example + listing [logical] [physical] [deck] [expand] +@end example + + +If the logical argument is given, the listing is with all continuation +lines collapsed into one line, and if the physical argument is given the +lines are printed out as they were found in the file. The default is +logical. A deck listing is just like the physical listing, except +without the line numbers it recreates the input file verbatim (except +that it does not preserve case). If the word expand is present, the +circuit is printed with all subcircuits expanded. + + + +@node Load, Op, Listing, Commands +@subsection Load: Load rawfile data + + General Form: + +@example + load [filename] ... +@end example + + +Loads either binary or ascii format rawfile data from the files named. +The default filename is rawspice.raw, or the argument to the -r flag if +there was one. + + + +@node Op, Plot, Load, Commands +@subsection Op*: Perform an operating point analysis + + General Form: + +@example + op +@end example + + +Do an operating point analysis. See the previous sections of this +manual for more details. + + + +@node Plot, Print, Op, Commands +@subsection Plot: Plot values on the display + + General Form: + +@example + plot exprs [ylimit ylo yhi] [xlimit xlo xhi] [xindices xilo xihi] + [xcompress comp] [xdelta xdel] [ydelta ydel] [xlog] [ylog] [loglog] + [vs xname] [xlabel word] [ylabel word] [title word] [samep] + [linear] +@end example + + + +Plot the given exprs on the screen (if you are on a graphics terminal). +The xlimit and ylimit arguments determine the high and low x- and +y-limits of the axes, respectively. The xindices arguments determine +what range of points are to be plotted - everything between the xilo'th +point and the xihi'th point is plotted. The xcompress argument +specifies that only one out of every comp points should be plotted. If +an xdelta or a ydelta parameter is present, it specifies the spacing +between grid lines on the X- and Y-axis. These parameter names may be +abbreviated to xl, yl, xind, xcomp, xdel, and ydel respectively. + +The xname argument is an expression to use as the scale on the +x-axis. If xlog or ylog are present then the X or Y scale, respectively, +is logarithmic (loglog is the same as specifying both). The xlabel and +ylabel arguments cause the specified labels to be used for the X and Y +axes, respectively. + +If samep is given, the values of the other parameters (other than xname) +from the previous plot, hardcopy, or asciiplot command is used unless +re-defined on the command line. + +The title argument is used in the place of the plot name at the bottom +of the graph. + +The linear keyword is used to override a default logscale plot (as in +the output for an AC analysis). + +Finally, the keyword polar to generate a polar plot. To produce a smith +plot, use the keyword smith. Note that the data is transformed, so for +smith plots you will see the data transformed by the function +(x-1)/(x+1). To produce a polar plot with a smith grid but without +performing the smith transform, use the keyword smithgrid. + + +@node Print, Quit, Plot, Commands +@subsection Print: Print values + + General Form: + +@example + print [col] [line] expr ... +@end example + + +Prints the vector described by the expression expr. If the col argument +is present, print the vectors named side by side. If line is given, the +vectors are printed horizontally. col is the default, unless all the +vectors named have a length of one, in which case line is the default. +The options width, length, and nobreak are effective for this command +(see asciiplot). If the expression is all, all of the vectors available +are printed. Thus print col all > file prints everything in the file in +SPICE2 format. The scale vector (time, frequency) is always in the +first column unless the variable noprintscale is true. + + + +@node Quit, Rehash, Print, Commands +@subsection Quit: Leave Spice3 or Nutmeg + + General Form: + +@example + quit +@end example + + +Quit nutmeg or spice. + + + +@node Rehash, Reset, Quit, Commands +@subsection Rehash: Reset internal hash tables + + General Form: + +@example + rehash +@end example + + +Recalculate the internal hash tables used when looking up UNIX commands, +and make all UNIX commands in the user's PATH available for command +completion. This is useless unless you have set unixcom first (see +above). + + + +@node Reset, Reshape, Rehash, Commands +@subsection Reset*: Reset an analysis + + General Form: + +@example + reset +@end example + + +Throw out any intermediate data in the circuit (e.g, after a breakpoint +or after one or more analyses have been done already), and re-parse the +input file. The circuit can then be re-run from it's initial state, +overriding the affect of any set or alter commands. In Spice-3e and +earlier versions this was done automatically by the run command. + + + +@node Reshape, Resume, Reset, Commands +@subsection Reshape: Alter the dimensionality or dimensions of + a vector + + General Form: + +@example + reshape vector vector ... + or + reshape vector vector ... [ dimension, dimension, ... ] + or + reshape vector vector ... [ dimension ][ dimension ] ... +@end example + + +This command changes the dimensions of a vector or a set of vectors. +The final dimension may be left off and it will be filled in +automatically. If no dimensions are specified, then the dimensions of +the first vector are copied to the other vectors. An error message of +the form 'dimensions of x were inconsistent' can be ignored. + + + +@node Resume, Rspice, Reshape, Commands +@subsection Resume*: Continue a simulation after a stop + + General Form: + +@example + resume +@end example + + +Resume a simulation after a stop or interruption (control-C). + + + +@node Rspice, Run, Resume, Commands +@subsection Rspice: Remote spice submission + + General Form: + +@example + rspice input file +@end example + + +Runs a SPICE-3 remotely taking the input file as a SPICE-3 input file, +or the current circuit if no argument is given. Nutmeg or Spice3 waits +for the job to complete, and passes output from the remote job to the +user's standard output. When the job is finished the data is loaded in +as with aspice. If the variable rhost is set, nutmeg connects to this +host instead of the default remote Spice3 server machine. This command +uses the "rsh" command and thereby requires authentication via a +".rhosts" file or other equivalent method. Note that "rsh" refers to +the "remote shell" program, which may be "remsh" on your system; to +override the default name of "rsh", set the variable remote_shell. If +the variable rprogram is set, then rspice uses this as the pathname to +the program to run on the remote system. + +Note: rspice will not acknowledge elements that have been changed via +the "alter" or "altermod" commands. + + + +@node Run, Rusage, Rspice, Commands +@subsection Run*: Run analysis from the input file + + General Form: + +@example + run [rawfile] +@end example + + +Run the simulation as specified in the input file. If there were any of +the control lines .ac, .op, .tran, or .dc, they are executed. The +output is put in rawfile if it was given, in addition to being available +interactively. In Spice-3e and earlier versions, the input file would +be re-read and any affects of the set or alter commands would be +reversed. This is no longer the affect. + + + +@node Rusage, Save, Run, Commands +@subsection Rusage: Resource usage + + General Form: + +@example + rusage [resource ...] +@end example + + +Print resource usage statistics. If any resources are given, just print +the usage of that resource. Most resources require that a circuit be +loaded. Currently valid resources are: + + elapsed The amount of time elapsed since the last rusage + elaped call. + faults Number of page faults and context switches (BSD only). + space Data space used. + time CPU time used so far. + + temp Operating temperature. + tnom Temperature at which device parameters were measured. + equations Circuit Equations + + time Total Analysis Time + totiter Total iterations + accept Accepted timepoints + rejected Rejected timepoints + + loadtime Time spent loading the circuit matrix and RHS. + reordertime Matrix reordering time + lutime L-U decomposition time + solvetime Matrix solve time + + trantime Transient analysis time + tranpoints Transient timepoints + traniter Transient iterations + trancuriters Transient iterations for the last time point* + tranlutime Transient L-U decomposition time + transolvetime Transient matrix solve time + + everything All of the above. + + * listed incorrectly as "Transient iterations per point". + + + +@node Save, Sens, Rusage, Commands +@subsection Save*: Save a set of outputs + + General Form: + +@example + save [all | output ...] + .save [all | output ...] +@end example + + +Save a set of outputs, discarding the rest. If a node has been +mentioned in a save command, it appears in the working plot after a run +has completed, or in the rawfile if spice is run in batch mode. If a +node is traced or plotted (see below) it is also saved. For backward +compatibility, if there are no save commands given, all outputs are +saved. + +When the keyword "all" appears in the save command, all default values +(node voltages and voltage source currents) are saved in addition to any +other values listed. + + + +@node Sens, Set, Save, Commands +@subsection Sens*: Run a sensitivity analysis + + General Form: + +@example + sens output_variable + sens output_variable ac ( DEC | OCT | LIN ) N Fstart Fstop +@end example + + +Perform a Sensitivity analysis. output_variable is either a node +voltage (ex. "v(1)" or "v(A,out)") or a current through a voltage source +(ex. "i(vtest)"). The first form calculates DC sensitivities, the +second form calculates AC sensitivies. The output values are in +dimensions of change in output per unit change of input (as opposed to +percent change in output or per percent change of input). + + + +@node Set, Setcirc, Sens, Commands +@subsection Set: Set the value of a variable + + General Form: + +@example + set [word] + set [word = value] ... +@end example + + +Set the value of word to be value, if it is present. You can set any +word to be any value, numeric or string. If no value is given then the +value is the boolean 'true'. + + +The value of word may be inserted into a command by writing $word. If a +variable is set to a list of values that are enclosed in parentheses +(which must be separated from their values by white space), the value of +the variable is the list. + +The variables used by nutmeg are listed in the following section. + + +@node Setcirc, Setplot, Set, Commands +@subsection Setcirc*: Change the current circuit + + General Form: + +@example + setcirc [circuit name] +@end example + + +The current circuit is the one that is used for the simulation commands +below. When a circuit is loaded with the source command (see below) it +becomes the current circuit. + + + +@node Setplot, Settype, Setcirc, Commands +@subsection Setplot: Switch the current set of vectors + + General Form: + +@example + setplot [plotname] +@end example + + +Set the current plot to the plot with the given name, or if no name is +given, prompt the user with a menu. (Note that the plots are named as +they are loaded, with names like tran1 or op2. These names are shown by +the setplot and display commands and are used by diff, below.) If the +"New plot" item is selected, the current plot becomes one with no +vectors defined. + +Note that here the word "plot" refers to a group of vectors that are the +result of one SPICE run. When more than one file is loaded in, or more +than one plot is present in one file, nutmeg keeps them separate and +only shows you the vectors in the current plot. + + + +@node Settype, Shell, Setplot, Commands +@subsection Settype: Set the type of a vector + + General Form: + +@example + settype type vector ... +@end example + + +Change the type of the named vectors to type. Type names can be found +in the manual page for sconvert. + + + +@node Shell, Shift, Settype, Commands +@subsection Shell: Call the command interpreter + + General Form: + +@example + shell [ command ] +@end example + + +Call the operating system's command interpreter; execute the specified +command or call for interactive use. + + + +@node Shift, Show, Shell, Commands +@subsection Shift: Alter a list variable + + General Form: + +@example + shift [varname] [number] +@end example + + +If varname is the name of a list variable, it is shifted to the left by +number elements (i.e, the number leftmost elements are removed). The +default varname is argv, and the default number is 1. + + + +@node Show, Showmod, Shift, Commands +@subsection Show*: List device state + + General Form: + +@example + show devices [ : parameters ] , ... +@end example + + +The show command prints out tables summarizing the operating condition +of selected devices (much like the spice2 operation point summary). If +device is missing, a default set of devices are listed, if device is a +single letter, devices of that type are listed; if device is a +subcircuit name (beginning and ending in ":") only devices in that +subcircuit are shown (end the name in a double-":" to get devices within +sub-subcircuits recursively). The second and third forms may be +combined ("letter:subcircuit:") or "letter:subcircuit::") to select a +specific type of device from a subcircuit. A device's full name may be +specified to list only that device. Finally, devices may be selected by +model by using the form "#modelname" or ":subcircuit#modelname" or +"letter:subcircuit#modelname". + +If no parameters are specified, the values for a standard set of +parameters are listed. If the list of parameters contains a "+", the +default set of parameters is listed along with any other specified +parameters. + +For both devices and parameters, the word "all" has the obvious meaning. +Note: there must be spaces separating the ":" that divides the device +list from the parameter list. + + + +@node Showmod, Source, Show, Commands +@subsection Showmod*: List model parameter values + + General Form: + +@example + showmod models [ : parameters ] , ... +@end example + + +The showmod command operates like the show command (above) but prints +out model parameter values. The applicable forms for models are a +single letter specifying the device type letter, "letter:subckt:", +"modelname", ":subckt:modelname", or "letter:subcircuit:modelname". + + + +@node Source, Status, Showmod, Commands +@subsection Source: Read a Spice3 input file + + General Form: + +@example + source file +@end example + + +For Spice3: Read the Spice3 input file file. Nutmeg and Spice3 commands +may be included in the file, and must be enclosed between the lines +.control and .endc. These commands are executed immediately after the +circuit is loaded, so a control line of ac ... works the same as the +corresponding .ac card. The first line in any input file is considered +a title line and not parsed but kept as the name of the circuit. The +exception to this rule is the file .spiceinit. Thus, a Spice3 command +script must begin with a blank line and then with a acters *# is +considered a control line. This makes it possible to imbed commands in +Spice3 input files that are ignored by earlier versions of Spice2 + +For Nutmeg: Reads commands from the file filename. Lines beginning with +the character * are considered comments and ignored. + + + +@node Status, Step, Source, Commands +@subsection Status*: Display breakpoint information + + General Form: + +@example + status +@end example + + +Display all of the traces and breakpoints currently in effect. + + + +@node Step, Stop, Status, Commands +@subsection Step*: Run a fixed number of timepoints + + General Form: + +@example + step [number] +@end example + + +Iterate number times, or once, and then stop. + + + +@node Stop, Tf, Step, Commands +@subsection Stop*: Set a breakpoint + + General Form: + +@example + stop [ after n] [ when value cond value ] ... +@end example + + +Set a breakpoint. The argument after n means stop after n iteration +number n, and the argument when value cond value means stop when the +first value is in the given relation with the second value, the possible +relations being + +@example + eq or = equal to + ne or <> not equal to + gt or > greater than + lt or < less than + ge or >= greater than or equal to + le or <= less than or equal to +@end example + +IO redirection is disabled for the stop command, since the relational +operations conflict with it (it doesn't produce any output anyway). The +values above may be node names in the running circuit, or real values. +If more than one condition is given, e.g. stop after 4 when @math{v(1) > 4} +when @math{v(2) < 2}, the conjunction of the conditions is implied. + + + +@node Tf, Trace, Stop, Commands +@subsection Tf*: Run a Transfer Function analysis + + General Form: + +@example + tf output_node input_source +@end example + + +The tf command performs a transfer function analysis, returning the +transfer function (output/input), output resistance, and input +resistance between the given output node and the given input source. +The analysis assumes a small-signal DC (slowly varying) input. + + + +@node Trace, Tran, Tf, Commands +@subsection Trace*: Trace nodes + + General Form: + +@example + trace [ node ...] +@end example + + +For every step of an analysis, the value of the node is printed. +Several traces may be active at once. Tracing is not applicable for all +analyses. To remove a trace, use the delete command. + + + +@node Tran, Transpose, Trace, Commands +@subsection Tran*: Perform a transient analysis + + General Form: + +@example + tran Tstep Tstop [ Tstart [ Tmax ] ] [ UIC ] +@end example + + +Perform a transient analysis. See the previous sections of this manual +for more details. + + + +@node Transpose, Unalias, Tran, Commands +@subsection Transpose: Swap the elements in a multi-dimensional data set + + General Form: + +@example + transpose vector vector ... +@end example + + +This command transposes a multidimensional vector. No analysis in +Spice3 produces multidimensional vectors, although the DC transfer curve +may be run with two varying sources. You must use the "reshape" command +to reform the one-dimensional vectors into two dimensional vectors. In +addition, the default scale is incorrect for plotting. You must plot +versus the vector corresponding to the second source, but you must also +refer only to the first segment of this second source vector. For +example (circuit to produce the tranfer characteristic of a MOS +transistor): + +@example + spice3 > dc vgg 0 5 1 vdd 0 5 1 + spice3 > plot i(vdd) + spice3 > reshape all [6,6] + spice3 > transpose i(vdd) v(drain) + spice3 > plot i(vdd) vs v(drain)[0] +@end example + + +@node Unalias, Undefine, Transpose, Commands +@subsection Unalias: Retract an alias + + General Form: + +@example + unalias [word ...] +@end example + + +Removes any aliases present for the words. + + + +@node Undefine, Unset, Unalias, Commands +@subsection Undefine: Retract a definition + + General Form: + +@example + undefine function +@end example + + +Definitions for the named user-defined functions are deleted. + + + +@node Unset, Version, Undefine, Commands +@subsection Unset: Clear a variable + + General Form: + +@example + unset [word ...] +@end example + + +Clear the value of the specified variable(s) (word). + + + +@node Version, Where, Unset, Commands +@subsection Version: Print the version of Spice + + General Form: + +@example + version [version id] +@end example + + +Print out the version of nutmeg that is running. If there are +arguments, it checks to make sure that the arguments match the current +version of SPICE. (This is mainly used as a Command: line in rawfiles.) + + + +@node Where, Write, Version, Commands +@subsection Where: Identify troublesome node or device + + General Form: + +@example + where +@end example + + +When performing a transient or operating point analysis, the name of the +last node or device to cause non-convergence is saved. The where +command prints out this information so that you can examine the circuit +and either correct the problem or make a bug report. You may do this +either in the middle of a run or after the simulator has given up on the +analysis. For transient simulation, the iplot command can be used to +monitor the progress of the analysis. When the analysis slows down +severly or hangs, interrupt the simulator (with control-C) and issue the +where command. Note that only one node or device is printed; there may +be problems with more than one node. + + + +@node Write, Xgraph, Where, Commands +@subsection Write: Write data to a file + + General Form: + +@example + write [file] [exprs] +@end example + + +Writes out the expressions to file. + +First vectors are grouped together by plots, and written out as such +(i.e, if the expression list contained three vectors from one plot and +two from another, then two plots are written, one with three vectors and +one with two). Additionally, if the scale for a vector isn't present, +it is automatically written out as well. + +The default format is ascii, but this can be changed with the set +filetype command. The default filename is rawspice.raw, or the argument +to the -r flag on the command line, if there was one, and the default +expression list is all. + + + +@node Xgraph, While - End, Write, Commands +@subsection Xgraph: use the xgraph(1) program for plotting. + + General Form: + +@example + xgraph file [exprs] [plot options] +@end example + + +The spice3/nutmeg xgraph command plots data like the plot command but +via xgraph, a popular X11 plotting program. + +If file is either "temp" or "tmp" a temporary file is used to hold the +data while being plotted. For available plot options, see the plot +command. All options except for polar or smith plots are supported. + + + +@section Control Structures + + + +@node While - End, Repeat - End, Xgraph, Commands +@subsection While - End + + General Form: + +@example + while condition + statement + ... + end +@end example + + +While condition, an arbitrary algebraic expression, is true, execute the +statements. + + + +@node Repeat - End, Dowhile - End, While - End, Commands +@subsection Repeat - End + + General Form: + +@example + repeat [number] + statement + ... + end +@end example + + +Execute the statements number times, or forever if no argument is given. + + + +@node Dowhile - End, Foreach - End, Repeat - End, Commands +@subsection Dowhile - End + + General Form: + +@example + dowhile condition + statement + ... + end +@end example + + +The same as while, except that the condition is tested after the +statements are executed. + + + +@node Foreach - End, If - Then - Else, Dowhile - End, Commands +@subsection Foreach - End + + General Form: + +@example + foreach var value ... + statement + ... + end +@end example + + +The statements are executed once for each of the values, each time with +the variable var set to the current one. (var can be accessed by the +$var notation - see below). + + + +@node If - Then - Else, Label, Foreach - End, Commands +@subsection If - Then - Else + + General Form: + +@example + if condition + statement + ... + else + statement + ... + end +@end example + + +If the condition is non-zero then the first set of statements are +executed, otherwise the second set. The else and the second set of +statements may be omitted. + + + +@node Label, Goto, If - Then - Else, Commands +@subsection Label + + General Form: + +@example + label word +@end example + + +If a statement of the form goto word is encountered, control is +transferred to this point, otherwise this is a no-op. + + + +@node Goto, Continue, Label, Commands +@subsection Goto + + General Form: + +@example + goto word +@end example + + +If a statement of the form label word is present in the block or an +enclosing block, control is transferred there. Note that if the label +is at the top level, it must be before the goto statement (i.e, a +forward goto may occur only within a block). + + + +@node Continue, Break, Goto, Commands +@subsection Continue + General Form: + +@example + continue +@end example + + +If there is a while, dowhile, or foreach block enclosing this statement, +control passes to the test, or in the case of foreach, the next value is +taken. Otherwise an error results. + + + +@node Break, , Continue, Commands +@subsection Break + + General Form: + +@example + break +@end example + + +If there is a while, dowhile, or foreach block enclosing this statement, +control passes out of the block. Otherwise an error results. + +Of course, control structures may be nested. When a block is entered +and the input is the terminal, the prompt becomes a number of >'s +corresponding to the number of blocks the user has entered. The current +control structures may be examined with the debugging command cdump. + + +@node Variables, Bugs, Commands, Interactive Interpreter +@section Variables + + +The operation of both Nutmeg and Spice3 may be affected by setting +variables with the "set" command. In addition to the variables +mentioned below, the set command in Spice3 also affect the behaviour of +the simulator via the options previously described under the section on +".OPTIONS". + +The variables meaningful to nutmeg which may be altered by the set +command are: + +@vtable @code +@item diff_abstol + +The absolute tolerance used by the diff command. appendwrite Append to +the file when a write command is is sued, if one already exists. + +@item colorN + +These variables determine the colors used, if X is being run on a color +display. N may be between 0 and 15. Color 0 is the background, color 1 +is the grid and text color, and colors 2 through 15 are used in order +for vectors plot ted. The value of the color variables should be names +of colors, which may be found in the file /usr/lib/rgb.txt. + +@item combplot + +Plot vectors by drawing a vertical line from each point to the X-axis, +as opposed to joining the points. Note that this option is subsumed in +the plottype option, below. + +@item cpdebug + +Print cshpar debugging information (must be com plied with the -DCPDEBUG +flag). Unsupported in the current release. + + +@item debug + +If set then a lot of debugging information is printed (must be compiled +with the -DFTEDEBUG flag). Unsupported in the current release. + +@item device + +The name (@code{/dev/tty??}) of the graphics device. If this variable +isn't set then the user's terminal is used. To do plotting on another +monitor you probably have to set both the device and term variables. +(If device is set to the name of a file, nutmeg dumps the graphics +control codes into this file -- this is useful for saving plots.) + +@item echo + +Print out each command before it is executed. + +@item filetype + +This can be either ascii or binary, and determines what format are. The +default is ascii. + + +@item fourgridsize + +How many points to use for interpolating into when doing fourier +analysis. + +@item gridsize + +If this variable is set to an integer, this number is used as the number +of equally spaced points to use for the Y axis when plotting. Otherwise +the current scale is used (which may not have equally spaced points). +If the current scale isn't strictly monotonic, then this option has no +effect. + +@item hcopydev + +If this is set, when the hardcopy com mand is run the resulting file is +au tomatically printed on the printer named hcopydev with the command +@code{lpr -Phcopydev -g file}. + + +@item hcopyfont + +This variable specifies the font name for hardcopy output plots. The +value is device dependent. + +@item hcopyfontsize + +This is a scaling factor for the font used in hardcopy plots. + +@item hcopydevtype + +This variable specifies the type of the printer output to use in the +hardcopy command. If hcopydevtype is not set, plot (5) format is +assumed. The stan dard distribution currently recognizes postscript as +an alternative output for mat. When used in conjunction with hcopydev, +hcopydevtype should specify a format supported by the printer. + +@item height + +The length of the page for asciiplot and print col. + +@item history + +The number of events to save in the his tory list. + +@item lprplot5 + +This is a printf(3s) style format string used to specify the command to +use for sending plot(5)-style plots to a printer or plotter. The first +parameter sup plied is the printer name, the second parameter supplied +is a file name con taining the plot. Both parameters are strings. It +is trivial to cause Spice3 to abort by supplying a unreasonable format +string. + +@item lprps + +This is a printf(3s) style format string used to specify the command to +use for sending PostScript plots to a printer or plotter. The first +parameter supplied is the printer name, the second parame ter supplied +is a file name containing the plot. Both parameters are strings. It is +trivial to cause Spice3 to abort by supplying a unreasonable format +string. + +@item nfreqs + +The number of frequencies to compute in the fourier command. (Defaults +to 10.) + +@item nobreak + +Don't have asciiplot and print col break between pages. + + + +@item noasciiplotvalue + +Don't print the first vector plotted to the left when doing an +asciiplot. + +@item noclobber + +Don't overwrite existing files when do ing IO redirection. + +@item noglob + +Don't expand the global characters `*', `?', `[', and `]'. This is the +default. + +@item nogrid + +Don't plot a grid when graphing curves (but do label the axes). + +@item nomoremode + +If nomoremode is not set, whenever a large amount of data is being +printed to the screen (e.g, the print or asciiplot commands), the output +is stopped every screenful and continues when a carriage return is +typed. If nomoremode is set then data scrolls off the screen without +check. + +@item nonomatch + +If noglob is unset and a global expres sion cannot be matched, use the +global characters literally instead of com plaining. + +@item nosort + +Don't have display sort the variable names. + +@item noprintscale + +Don't print the scale in the leftmost column when a print col command is +given. + +@item numdgt + +The number of digits to print when printing tables of data (fourier, +print col). The default precision is 6 digits. On the VAX, +approximately 16 decimal digits are avail able using double precision, +so numdgt should not be more than 16. If the number is negative, one +fewer digit is printed to ensure constant widths in tables. + +@item plottype + +This should be one of normal, comb, or point:chars. normal, the +default, causes points to be plotted as parts of connected lines. comb +causes a comb plot to be done (see the description of the combplot vari +able above). point causes each point to be plotted separately - the +chars are a list of characters that are used for each vector plotted. +If they are omitted then a de fault set is used. + +@item polydegree + +The degree of the polynomial that the plot command should fit to the +data. If polyde gree is N, then nutmeg fits a degree N po lynomial to +every set of N points and draw 10 intermediate points in between each +end point. If the points aren't monotonic, then it tries rotating the +curve and reduc ing the degree until a fit is achieved. + +@item polysteps + +The number of points to interpolate between every pair of points +available when doing curve fitting. The default is 10. + +@item program + +The name of the current program (argv[0]). + +@item prompt + +The prompt, with the character `!' replaced by the current event number. + +@item rawfile + +The default name for rawfiles created. + +@item diff_reltol + +The relative tolerance used by the diff command. + +@item remote_shell + +Overrides the name used for generating rspice runs (default is +"rsh"). + +@item rhost + +The machine to use for remote SPICE-3 runs, in stead of the default one +(see the description of the rspice command, below). + +@item rprogram + +The name of the remote program to use in the rspice command. + +@item slowplot + +Stop between each graph plotted and wait for the user to type return +before continuing. + +@item sourcepath + +A list of the directories to search when a source command is given. The +default is the current directory and the standard spice library +(/usr/local/lib/spice, or whatever LIBPATH is #defined to in the Spice3 +source. + +@item spicepath + +The program to use for the aspice command. The default is +/cad/bin/spice. + +@item term + +The mfb name of the current terminal. + +@item units + +If this is degrees, then all the trig functions will use degrees instead +of radians. + +@item unixcom + +If a command isn't defined, try to execute it as a UNIX command. +Setting this option has the ef fect of giving a rehash command, below. +This is useful for people who want to use nutmeg as a login shell. + +@item verbose + +Be verbose. This is midway between echo and de bug / cpdebug. + +@item diff _vntol + +The absolute voltage tolerance used by the diff command. + +@item width + +The width of the page for asciiplot and print col. + +@item x11lineararcs + +Some X11 implementations have poor arc drawing. If you set this option, +Spice3 will plot using an approximation to the curve using straight +lines. + +@item xbrushheight + +The height of the brush to use if X is being run. + +@item xbrushwidth + +The width of the brush to use if X is being run. + +@item xfont + +The name of the X font to use when plot ting data and entering labels. +The plot may not look good if this is a variable-width font. + +@end vtable + +There are several set variables that Spice3 uses but Nutmeg does +not. They are: + +@vtable @code + +@item editor + +The editor to use for the edit command. + +@item modelcard + +The name of the model card (normally + +@item noaskquit + +Do not check to make sure that there are no circuits suspended and no +plots un saved. Normally Spice3 warns the user when he tries to quit if +this is the case. + +@item nobjthack + +Assume that BJTs have 4 nodes. + +@item noparse + +Don't attempt to parse input files when they are read in (useful for +debugging). Of course, they cannot be run if they are not parsed. +nosubckt Don't expand subcircuits. + +@item renumber + +Renumber input lines when an input file has .include's. subend The card +to end subcircuits (normally + +@item subinvoke + +The prefix to invoke subcircuits (nor mally x). substart The card to +begin subcircuits (normally + +@end vtable + + +@section MISCELLANEOUS + +If there are subcircuits in the input file, Spice3 expands instances of +them. A subcircuit is delimited by the cards .subckt and .ends, or +whatever the value of the variables substart and subend is, +respectively. An instance of a subcircuit is created by specifying a +device with type 'x' - the device line is written + +@example + xname node1 node2 ... subcktname +@end example + + +where the nodes are the node names that replace the formal parameters on +the .subckt line. All nodes that are not formal parameters are +prepended with the name given to the instance and a ':', as are the +names of the devices in the subcircuit. If there are several nested +subcircuits, node and device names look like subckt1:subckt2:...:name. +If the variable subinvoke is set, then it is used as the prefix that +specifies instances of subcircuits, instead of 'x'. + +Nutmeg occasionally checks to see if it is getting close to running out +of space, and warns the user if this is the case. (This is more likely +to be useful with the SPICE front end.) + +C-shell type quoting with "" and '', and backquote substitution may be +used. Within single quotes, no further substitution (like history +substitution) is done, and within double quotes, the words are kept +together but further substitution is done. Any text between backquotes +is replaced by the result of executing the text as a command to the +shell. + +Tenex-style ('set filec' in the 4.3 C-shell) command, filename, and +keyword completion is possible: If EOF (control-D) is typed after the +first character on the line, a list of the commands or possible +arguments is printed (If it is alone on the line it exits nutmeg). If +escape is typed, then nutmeg trys to complete what the user has already +typed. To get a list of all commands, the user should type ^D. + +The values of variables may be used in commands by writing $varname +where the value of the variable is to appear. The special variables $$ +and $< refer to the process ID of the program and a line of input which +is read from the terminal when the variable is evaluated, respectively. +If a variable has a name of the form $&word, then word is considered a +vector (see above), and its value is taken to be the value of the +variable. If $foo is a valid variable, and is of type list, then the +expression $foo[low-high] represents a range of elements. Either the +upper index or the lower may be left out, and the reverse of a list may +be obtained with $foo[len-0]. Also, the notation $?foo evaluates to 1 +if the variable foo is defined, 0 otherwise, and $#foo evaluates to the +number of elements in foo if it is a list, 1 if it is a number or +string, and 0 if it is a boolean variable. + +History substitutions, similar to C-shell history substitutions, are +also available - see the C-shell manual page for all of the details. + +The characters ~, @{, and @} have the same effects as they do in the +C-Shell, i.e., home directory and alternative expansion. It is possible +to use the wildcard characters *, ?, [, and ] also, but only if you +unset noglob first. This makes them rather useless for typing algebraic +expressions, so you should set noglob again after you are done with +wildcard expansion. Note that the pattern [^abc] matchs all characters +except a, b, and c. + +IO redirection is available - the symbols >, >>, >&, >>&, and < have the +same effects as in the C-shell. + +You may type multiple commands on one line, separated by semicolons. + +If you want to use a different mfbcap file than the default (usually +~cad/lib/mfbcap), you have to set the environment variable SPICE_MFBCAP +before you start nutmeg or spice. The -m option and the mfbcap variable +no longer work. + +If X is being used, the cursor may be positioned at any point on the +screen when the window is up and characters typed at the keyboard are +added to the window at that point. The window may then be sent to a +printer using the xpr(1) program. + +Nutmeg can be run under VAX/VMS, as well as several other operating +systems. Some features like command completion, expansion of *, ?, and +[], backquote substitution, the shell command, and so forth do not work. + +On some systems you have to respond to the -moreprompt during plot with +a carriage return instead of any key as you can do on UNIX. + + +@node Bugs, , Variables, Interactive Interpreter +@section Bugs + +The label entry facilities are primitive. You must be careful to type +slowly when entering labels -- nutmeg checks for input once every +second, and can get confused if characters arrive faster. + +If you redefine colors after creating a plot window with X, and then +cause the window to be redrawn, it does not redraw in the correct +colors. + + +When defining aliases like + +@example + alias pdb plot db( '!:1' - '!:2' ) +@end example + +you must be careful to quote the argument list substitutions in this +manner. If you quote the whole argument it might not work properly. + + + +In a user-defined function, the arguments cannot be part of a name that +uses the plot.vec syntax. For example: + +@example + define check(v(1)) cos(tran1.v(1)) +@end example + +does not work. + + +If you type plot all all, or otherwise use a wildcard reference for one +plot twice in a command, the effect is unpredictable. + +The asciiplot command doesn't deal with log scales or the delta +keywords. + + +Often the names of terminals recognized by MFB are different from those +in /etc/termcap. Thus you may have to reset your terminal type with the +command + +@example + set term = termname +@end example + +where termname is the name in the mfbcap file. + +The hardcopy command is useless on VMS and other systems without the +plot command, unless the user has a program that understands plot(5) +format. + +Spice3 recognizes all the notations used in SPICE2 .plot cards, and +translates vp(1) into ph(v(1)), and so forth. However, if there are +spaces in these names it won't work. Hence v(1, 2) and (-.5, .5) aren't +recognized. + +BJTs can have either 3 or 4 nodes, which makes it difficult for the +subcircuit expansion routines to decide what to rename. If the fourth +parameter has been declared as a model name, then it is assumed that +there are 3 nodes, otherwise it is considered a node. To disable this, +you can set the variable "nobjthack" which forces BJTs to have 4 nodes +(for the purposes of subcircuit expansion, at least). + +The @@name[param] notation might not work with trace, iplot, etc. yet. + +The first line of a command file (except for the .spiceinit file) should +be a comment, otherwise SPICE may create an empty circuit. + +Files specified on the command line are read before .spiceinit is read. + + +@node Bibliography, Example Circuits, Interactive Interpreter, Top +@chapter Bibliography + + + [1] A. Vladimirescu and S. Liu, The Simulation of MOS Integrated +Circuits Using SPICE2 ERL Memo No. ERL M80/7, Electronics Research +Laboratory University of California, Berkeley, October 1980 + + [2] T. Sakurai and A. R. Newton, A Simple MOSFET Model for Circuit +Analysis and its application to CMOS gate delay analysis and +series-connected MOSFET Structure ERL Memo No. ERL M90/19, Electronics +Research Labora tory, University of California, Berkeley, March 1990 + + [3] B. J. Sheu, D. L. Scharfetter, and P. K. Ko, SPICE2 +Implementation of BSIM ERL Memo No. ERL M85/42, Electronics Research +Labora tory University of California, Berkeley, May 1985 + + [4] J. R. Pierret, A MOS Parameter Extraction Program for the BSIM +Model ERL Memo Nos. ERL M84/99 and M84/100, Electronics Research +Laboratory University of California, Berkeley, November 1984 + + [5] Min-Chie Jeng, Design and Modeling of Deep Submicrometer MOSFETSs +ERL Memo Nos. ERL M90/90, Electronics Research Labora tory University of +California, Berkeley, October 1990 + + [6] Soyeon Park, Analysis and SPICE implementation of High Temperature +Effects on MOSFET, Master's thesis, University of California, Berkeley, +December 1986. + + [7] Clement Szeto, Simulator of Temperature Effects in MOS FETs +(STEIM), Master's thesis, University of California, Berkeley, May 1988. + + [8] J.S. Roychowdhury and D.O. Pederson, Efficient Tran sient +Simulation of Lossy Interconnect, Proc. of the 28th ACM/IEEE Design +Automation Confer ence, June 17-21 1991, San Francisco + + [9] A. E. Parker and D. J. Skellern, An Improved FET Model for Computer +Simulators, IEEE Trans CAD, vol. 9, no. 5, pp. 551-553, May 1990. + + [10] R. Saleh and A. Yang, Editors, Simulation and Modeling, IEEE +Circuits and Devices, vol. 8, no. 3, pp. 7-8 and 49, May 1992 + + [11] H.Statz et al., GaAs FET Device and Circuit Simulation in SPICE, +IEEE Transactions on Electron Devices, V34, Number 2, February, 1987 +pp160-169. + + + +@node Example Circuits, Model and Device Parameters, Bibliography, Top +@chapter Example Circuits + +@menu +* Differential Pair:: +* MOSFET Characterization:: +* RTL Inverter:: +* Four-Bit Binary Adder:: +* Transmission-Line Inverter:: +@end menu + + +@node Differential Pair, MOSFET Characterization, Example Circuits, Example Circuits +@section Differential Pair + + +The following deck determines the dc operating point of a simple +differential pair. In addition, the ac small-signal response is computed +over the frequency range 1Hz to 100MEGHz. + +@example +SIMPLE DIFFERENTIAL PAIR +VCC 7 0 12 +VEE 8 0 -12 +VIN 1 0 AC 1 +RS1 1 2 1K +RS2 6 0 1K +Q1 3 2 4 MOD1 +Q2 5 6 4 MOD1 +RC1 7 3 10K +RC2 7 5 10K +RE 4 8 10K +.MODEL MOD1 NPN BF=50 VAF=50 IS=1.E-12 RB=100 CJC=.5PF TF=.6NS +.TF V(5) VIN +.AC DEC 10 1 100MEG +.END +@end example + + + + +@node MOSFET Characterization, RTL Inverter, Differential Pair, Example Circuits +@section MOSFET Characterization + +The following deck computes the output characteristics of a MOSFET +device over the range 0-10V for VDS and 0-5V for VGS. + + +@example +MOS OUTPUT CHARACTERISTICS +.OPTIONS NODE NOPAGE +VDS 3 0 +VGS 2 0 +M1 1 2 0 0 MOD1 L=4U W=6U AD=10P AS=10P +* VIDS MEASURES ID, WE COULD HAVE USED VDS, BUT ID WOULD BE NEGATIVE +VIDS 3 1 +.MODEL MOD1 NMOS VTO=-2 NSUB=1.0E15 UO=550 +.DC VDS 0 10 .5 VGS 0 5 1 +.END +@end example + + + + +@node RTL Inverter, Four-Bit Binary Adder, MOSFET Characterization, Example Circuits +@section RTL Inverter + + +The following deck determines the dc transfer curve and the transient +pulse response of a simple RTL inverter. The input is a pulse from 0 to +5 Volts with delay, rise, and fall times of 2ns and a pulse width of +30ns. The transient interval is 0 to 100ns, with printing to be done +every nanosecond. + + +@example +SIMPLE RTL INVERTER +VCC 4 0 5 +VIN 1 0 PULSE 0 5 2NS 2NS 2NS 30NS +RB 1 2 10K +Q1 3 2 0 Q1 +RC 3 4 1K +.MODEL Q1 NPN BF 20 RB 100 TF .1NS CJC 2PF +.DC VIN 0 5 0.1 +.TRAN 1NS 100NS +.END +@end example + + + +@node Four-Bit Binary Adder, Transmission-Line Inverter, RTL Inverter, Example Circuits +@section Four-Bit Binary Adder + + +The following deck simulates a four-bit binary adder, using several +subcircuits to describe various pieces of the overall circuit. + + +@example +ADDER - 4 BIT ALL-NAND-GATE BINARY ADDER + +*** SUBCIRCUIT DEFINITIONS +.SUBCKT NAND 1 2 3 4 +* NODES: INPUT(2), OUTPUT, VCC +Q1 9 5 1 QMOD +D1CLAMP 0 1 DMOD +Q2 9 5 2 QMOD +D2CLAMP 0 2 DMOD +RB 4 5 4K +R1 4 6 1.6K +Q3 6 9 8 QMOD +R2 8 0 1K +RC 4 7 130 +Q4 7 6 10 QMOD +DVBEDROP 10 3 DMOD +Q5 3 8 0 QMOD +.ENDS NAND + +.SUBCKT ONEBIT 1 2 3 4 5 6 +* NODES: INPUT(2), CARRY-IN, OUTPUT, CARRY-OUT, VCC +X1 1 2 7 6 NAND +X2 1 7 8 6 NAND +X3 2 7 9 6 NAND +X4 8 9 10 6 NAND +X5 3 10 11 6 NAND +X6 3 11 12 6 NAND +X7 10 11 13 6 NAND +X8 12 13 4 6 NAND +X9 11 7 5 6 NAND +.ENDS ONEBIT + +.SUBCKT TWOBIT 1 2 3 4 5 6 7 8 9 +* NODES: INPUT - BIT0(2) / BIT1(2), OUTPUT - BIT0 / BIT1, +* CARRY-IN, CARRY-OUT, VCC +X1 1 2 7 5 10 9 ONEBIT +X2 3 4 10 6 8 9 ONEBIT +.ENDS TWOBIT + +.SUBCKT FOURBIT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +* NODES: INPUT - BIT0(2) / BIT1(2) / BIT2(2) / BIT3(2), +* OUTPUT - BIT0 / BIT1 / BIT2 / BIT3, CARRY-IN, CARRY-OUT, VCC +X1 1 2 3 4 9 10 13 16 15 TWOBIT +X2 5 6 7 8 11 12 16 14 15 TWOBIT +.ENDS FOURBIT + +*** DEFINE NOMINAL CIRCUIT +.MODEL DMOD D +.MODEL QMOD NPN(BF=75 RB=100 CJE=1PF CJC=3PF) +VCC 99 0 DC 5V +VIN1A 1 0 PULSE(0 3 0 10NS 10NS 10NS 50NS) +VIN1B 2 0 PULSE(0 3 0 10NS 10NS 20NS 100NS) +VIN2A 3 0 PULSE(0 3 0 10NS 10NS 40NS 200NS) +VIN2B 4 0 PULSE(0 3 0 10NS 10NS 80NS 400NS) +VIN3A 5 0 PULSE(0 3 0 10NS 10NS 160NS 800NS) +VIN3B 6 0 PULSE(0 3 0 10NS 10NS 320NS 1600NS) +VIN4A 7 0 PULSE(0 3 0 10NS 10NS 640NS 3200NS) +VIN4B 8 0 PULSE(0 3 0 10NS 10NS 1280NS 6400NS) +X1 1 2 3 4 5 6 7 8 9 10 11 12 0 13 99 FOURBIT +RBIT0 9 0 1K +RBIT1 10 0 1K +RBIT2 11 0 1K +RBIT3 12 0 1K +RCOUT 13 0 1K + +*** (FOR THOSE WITH MONEY (AND MEMORY) TO BURN) +.TRAN 1NS 6400NS +.END +@end example + + + + +@node Transmission-Line Inverter, , Four-Bit Binary Adder, Example Circuits +@section Transmission-Line Inverter + + +The following deck simulates a transmission-line inverter. Two +transmission-line elements are required since two propagation modes are +excited. In the case of a coaxial line, the first line (T1) models the +inner conductor with respect to the shield, and the second line (T2) +models the shield with respect to the outside world. + + +@example +TRANSMISSION-LINE INVERTER +V1 1 0 PULSE(0 1 0 0.1N) +R1 1 2 50 +X1 2 0 0 4 TLINE +R2 4 0 50 + +.SUBCKT TLINE 1 2 3 4 +T1 1 2 3 4 Z0=50 TD=1.5NS +T2 2 0 4 0 Z0=100 TD=1NS +.ENDS TLINE + +.TRAN 0.1NS 20NS +.END +@end example + + + +@node Model and Device Parameters, , Example Circuits, Top +@chapter Model and Device Parameters + +The following tables summarize the parameters available on each of the +devices and models in (note that for some systems with limited memory, +output parameters are not available). There are several tables for each +type of device supported by . Input parameters to instances and models +are parameters that can occur on an instance or model definition line in +the form "keyword=value" where "keyword" is the parameter name as given +in the tables. Default input parameters (such as the resistance of a +resistor or the capacitance of a capacitor) obviously do not need the +keyword specified. + +Output parameters are those additional parameters which are available +for many types of instances for the output of operating point and +debugging information. These parameters are specified as +"@@device[keyword]" and are available for the most recent point computed +or, if specified in a ".save" statement, for an entire simulation as a +normal output vector. Thus, to monitor the gate-to-source capacitance +of a MOSFET, a command + +@example + save @@m1[cgs] +@end example + +given before a transient simulation causes the specified capacitance +value to be saved at each timepoint, and a subsequent command such as + +@example + plot @@m1[cgs] +@end example + +produces the desired plot. (Note that the show command does not use +this format). + +Some variables are listed as both input and output, and their output +simply returns the previously input value, or the default value after +the simulation has been run. Some parameter are input only because the +output system can not handle variables of the given type yet, or the +need for them as output variables has not been apparent. Many such +input variables are available as output variables in a different format, +such as the initial condition vectors that can be retrieved as +individual initial condition values. Finally, internally derived values +are output only and are provided for debugging and operating point +output purposes. + +Please note that these tables do not provide the detailed information +available about the parameters provided in the section on each device +and model, but are provided as a quick reference guide. + + +@menu +* Uniform RC line:: +* Arbitrary Source:: +* Bipolar Junction Transistor:: +* BSIM1 Berkeley Short Channel IGFET Model:: +* BSIM2 Berkeley Short Channel IGFET Model:: +* Fixed capacitor:: +* Current controlled current source:: +* Linear current controlled current source:: +* Current controlled ideal switch:: +* Junction Diode model:: +* Inductor:: +* Mutual inductors:: +* Independent current source:: +* Junction Field effect transistor:: +* Lossy transmission line:: +* GaAs MESFET model:: +* Level 1 MOSfet model:: +* Level 2 MOSfet model:: +* Level 3 MOSfet model:: +* Level 6 MOSfet model:: +* Simple linear resistor:: +* Ideal voltage controlled switch:: +* Lossless transmission line:: +* Voltage controlled current source:: +* Voltage controlled voltage source:: +* Independent voltage source:: +@end menu + + +@node Uniform RC line, Arbitrary Source, Model and Device Parameters, Model and Device Parameters +@section URC: Uniform R.C. line + + ------------------------------------------------------------ +| URC - instance parameters (input-output) | +|-----------------------------------------------------------+ +| l Length of transmission line | +| n Number of lumps | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| URC - instance parameters (output-only) | +|-----------------------------------------------------------+ +| pos_node Positive node of URC | +| neg_node Negative node of URC | +| gnd Ground node of URC | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| URC - model parameters (input-only) | +|-----------------------------------------------------------+ +| urc Uniform R.C. line model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| URC - model parameters (input-output) | +|-----------------------------------------------------------+ +| k Propagation constant | +| fmax Maximum frequency of interest | +| rperl Resistance per unit length | +| cperl Capacitance per unit length | +| isperl Saturation current per length | +| rsperl Diode resistance per length | + ------------------------------------------------------------ + + +@node Arbitrary Source, Bipolar Junction Transistor, Uniform RC line, Model and Device Parameters +@section ASRC: Arbitrary Source + + ------------------------------------------------------------ +| ASRC - instance parameters (input-only) | +|-----------------------------------------------------------+ +| i Current source | +| v Voltage source | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| ASRC - instance parameters (output-only) | +|-----------------------------------------------------------+ +| i Current through source | +| v Voltage across source | +| pos_node Positive Node | +| neg_node Negative Node | + ------------------------------------------------------------ + +@node Bipolar Junction Transistor, BSIM1 Berkeley Short Channel IGFET Model, Arbitrary Source, Model and Device Parameters +@section BJT: Bipolar Junction Transistor + + ------------------------------------------------------------ +| BJT - instance parameters (input-only) | +|-----------------------------------------------------------+ +| ic Initial condition vector | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BJT - instance parameters (input-output) | +|-----------------------------------------------------------+ +| off Device initially off | +| icvbe Initial B-E voltage | +| icvce Initial C-E voltage | +| area Area factor | +| temp instance temperature | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BJT - instance parameters (output-only) | +|-----------------------------------------------------------+ +| colnode Number of collector node | +| basenode Number of base node | +| emitnode Number of emitter node | +| substnode Number of substrate node | + ------------------------------------------------------------ +| colprimenode Internal collector node | +| baseprimenode Internal base node | +| emitprimenode Internal emitter node | +| ic Current at collector node | +|-----------------------------------------------------------+ + ib Current at base node +| ie Emitter current | +| is Substrate current | +| vbe B-E voltage | + ------------------------------------------------------------ +| vbc B-C voltage | +| gm Small signal transconductance | +| gpi Small signal input conductance - pi | +| gmu Small signal conductance - mu | +|-----------------------------------------------------------+ +| gx Conductance from base to internal base | +| go Small signal output conductance | +| geqcb d(Ibe)/d(Vbc) | +| gccs Internal C-S cap. equiv. cond. | + ------------------------------------------------------------ +| geqbx Internal C-B-base cap. equiv. cond. | +| cpi Internal base to emitter capactance | +| cmu Internal base to collector capactiance | +| cbx Base to collector capacitance | +|-----------------------------------------------------------+ +| ccs Collector to substrate capacitance | +| cqbe Cap. due to charge storage in B-E jct. | +| cqbc Cap. due to charge storage in B-C jct. | +| cqcs Cap. due to charge storage in C-S jct. | +| cqbx Cap. due to charge storage in B-X jct. | +| continued | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BJT - instance output-only parameters - continued +|-----------------------------------------------------------+ +| cexbc Total Capacitance in B-X junction | +| qbe Charge storage B-E junction | +| qbc Charge storage B-C junction | +| qcs Charge storage C-S junction | +| qbx Charge storage B-X junction | +| p Power dissipation | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BJT - model parameters (input-output) | +|-----------------------------------------------------------+ +| npn NPN type device | +| pnp PNP type device | +| is Saturation Current | +| bf Ideal forward beta | + ------------------------------------------------------------ +| nf Forward emission coefficient | +| vaf Forward Early voltage | +| va (null) | +| ikf Forward beta roll-off corner current | +|-----------------------------------------------------------+ +| ik (null) | +| ise B-E leakage saturation current | +| ne B-E leakage emission coefficient | +| br Ideal reverse beta | + ------------------------------------------------------------ +| nr Reverse emission coefficient | +| var Reverse Early voltage | +| vb (null) | +| ikr reverse beta roll-off corner current | +|-----------------------------------------------------------+ +| isc B-C leakage saturation current | +| nc B-C leakage emission coefficient | +| rb Zero bias base resistance | +| irb Current for base resistance=(rb+rbm)/2 | + ------------------------------------------------------------ +| rbm Minimum base resistance | +| re Emitter resistance | +| rc Collector resistance | +| cje Zero bias B-E depletion capacitance | +|-----------------------------------------------------------+ +| vje B-E built in potential | +| pe (null) | +| mje B-E junction grading coefficient | +| me (null) | + ------------------------------------------------------------ +| tf Ideal forward transit time | +| xtf Coefficient for bias dependence of TF | +| vtf Voltage giving VBC dependence of TF | +| itf High current dependence of TF | +|-----------------------------------------------------------+ +| ptf Excess phase | +| cjc Zero bias B-C depletion capacitance | +| vjc B-C built in potential | +| continued | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BJT - model input-output parameters - continued +|-----------------------------------------------------------+ +| pc (null) | +| mjc B-C junction grading coefficient | +| mc (null) | +| xcjc Fraction of B-C cap to internal base | + ------------------------------------------------------------ +| tr Ideal reverse transit time | +| cjs Zero bias C-S capacitance | +| ccs Zero bias C-S capacitance | +| vjs Substrate junction built in potential | +|-----------------------------------------------------------+ +| ps (null) | +| mjs Substrate junction grading coefficient | +| ms (null) | +| xtb Forward and reverse beta temp. exp. | + ------------------------------------------------------------ +| eg Energy gap for IS temp. dependency | +| xti Temp. exponent for IS | +| fc Forward bias junction fit parameter | +| tnom Parameter measurement temperature | +| kf Flicker Noise Coefficient | +| af Flicker Noise Exponent | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BJT - model parameters (output-only) | +|-----------------------------------------------------------+ +| type NPN or PNP | +| invearlyvoltf Inverse early voltage:forward | +| invearlyvoltr Inverse early voltage:reverse | +| invrollofff Inverse roll off - forward | + ------------------------------------------------------------ +| invrolloffr Inverse roll off - reverse | +| collectorconduct Collector conductance | +| emitterconduct Emitter conductance | +| transtimevbcfact Transit time VBC factor | +| excessphasefactor Excess phase fact. | + ------------------------------------------------------------ + + +@node BSIM1 Berkeley Short Channel IGFET Model, BSIM2 Berkeley Short Channel IGFET Model, Bipolar Junction Transistor, Model and Device Parameters +@section BSIM1: Berkeley Short Channel IGFET Model + + ------------------------------------------------------------ +| BSIM1 - instance parameters (input-only) | +|-----------------------------------------------------------+ +| ic Vector of DS,GS,BS initial voltages | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BSIM1 - instance parameters (input-output) | +|-----------------------------------------------------------+ +| l Length | +| w Width | +| ad Drain area | +| as Source area | + ------------------------------------------------------------ +| pd Drain perimeter | +| ps Source perimeter | +| nrd Number of squares in drain | +| nrs Number of squares in source | +|-----------------------------------------------------------+ +| off Device is initially off | +| vds Initial D-S voltage | +| vgs Initial G-S voltage | +| vbs Initial B-S voltage | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BSIM1 - model parameters (input-only) | +|-----------------------------------------------------------+ +| nmos Flag to indicate NMOS | +| pmos Flag to indicate PMOS | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BSIM1 - model parameters (input-output) | +|-----------------------------------------------------------+ +| vfb Flat band voltage | + lvfb Length dependence of vfb +| wvfb Width dependence of vfb | +| phi Strong inversion surface potential | + ------------------------------------------------------------ +| lphi Length dependence of phi | +| wphi Width dependence of phi | +| k1 Bulk effect coefficient 1 | +| lk1 Length dependence of k1 | +|-----------------------------------------------------------+ +| wk1 Width dependence of k1 | +| k2 Bulk effect coefficient 2 | +| lk2 Length dependence of k2 | +| wk2 Width dependence of k2 | + ------------------------------------------------------------ +| eta VDS dependence of threshold voltage | +| leta Length dependence of eta | +| weta Width dependence of eta | +| x2e VBS dependence of eta | +| lx2e Length dependence of x2e | +| continued | + ------------------------------------------------------------ + + + --------------------------------------------------------------------- +| BSIM1 - model input-output parameters - continued| +|--------------------------------------------------------------------+ +|wx2e Width dependence of x2e | +|x3e VDS dependence of eta | +|lx3e Length dependence of x3e | +|wx3e Width dependence of x3e | + --------------------------------------------------------------------- +|dl Channel length reduction in um | +|dw Channel width reduction in um | +|muz Zero field mobility at VDS=0 VGS=VTH | +|x2mz VBS dependence of muz | +|--------------------------------------------------------------------+ +|lx2mz Length dependence of x2mz | +|wx2mz Width dependence of x2mz | + mus Mobility at VDS=VDD VGS=VTH, channel length modulation +|lmus Length dependence of mus | + --------------------------------------------------------------------- +|wmus Width dependence of mus | +|x2ms VBS dependence of mus | +|lx2ms Length dependence of x2ms | +|wx2ms Width dependence of x2ms | +|--------------------------------------------------------------------+ +|x3ms VDS dependence of mus | +|lx3ms Length dependence of x3ms | +|wx3ms Width dependence of x3ms | +|u0 VGS dependence of mobility | + --------------------------------------------------------------------- +|lu0 Length dependence of u0 | +|wu0 Width dependence of u0 | +|x2u0 VBS dependence of u0 | +|lx2u0 Length dependence of x2u0 | +|--------------------------------------------------------------------+ +|wx2u0 Width dependence of x2u0 | +|u1 VDS depence of mobility, velocity saturation | +|lu1 Length dependence of u1 | +|wu1 Width dependence of u1 | + --------------------------------------------------------------------- +|x2u1 VBS depence of u1 | +|lx2u1 Length depence of x2u1 | +|wx2u1 Width depence of x2u1 | +|x3u1 VDS depence of u1 | +|--------------------------------------------------------------------+ +|lx3u1 Length dependence of x3u1 | +|wx3u1 Width depence of x3u1 | +|n0 Subthreshold slope | + ln0 Length dependence of n0 + --------------------------------------------------------------------- +|wn0 Width dependence of n0 | +|nb VBS dependence of subthreshold slope | +|lnb Length dependence of nb | +|wnb Width dependence of nb | +|--------------------------------------------------------------------+ +|nd VDS dependence of subthreshold slope | +|lnd Length dependence of nd | +|wnd Width dependence of nd | +| continued | + --------------------------------------------------------------------- + + + --------------------------------------------------------------------------- +| BSIM1 - model input-output parameters - continued | +|--------------------------------------------------------------------------+ +|tox Gate oxide thickness in um | +|temp Temperature in degree Celcius | +|vdd Supply voltage to specify mus | +|cgso Gate source overlap capacitance per unit channel width(m) | + --------------------------------------------------------------------------- +|cgdo Gate drain overlap capacitance per unit channel width(m) | +|cgbo Gate bulk overlap capacitance per unit channel length(m) | +|xpart Flag for channel charge partitioning | +|rsh Source drain diffusion sheet resistance in ohm per square | +|--------------------------------------------------------------------------+ +|js Source drain junction saturation current per unit area | +|pb Source drain junction built in potential | + mj Source drain bottom junction capacitance grading coefficient +|pbsw Source drain side junction capacitance built in potential | + --------------------------------------------------------------------------- +|mjsw Source drain side junction capacitance grading coefficient | +|cj Source drain bottom junction capacitance per unit area | +|cjsw Source drain side junction capacitance per unit area | +|wdf Default width of source drain diffusion in um | +|dell Length reduction of source drain diffusion | + --------------------------------------------------------------------------- + + +@node BSIM2 Berkeley Short Channel IGFET Model, Fixed capacitor, BSIM1 Berkeley Short Channel IGFET Model, Model and Device Parameters +@section BSIM2: Berkeley Short Channel IGFET Model + + ------------------------------------------------------------ +| BSIM2 - instance parameters (input-only) | +|-----------------------------------------------------------+ +| ic Vector of DS,GS,BS initial voltages | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BSIM2 - instance parameters (input-output) | +|-----------------------------------------------------------+ +| l Length | +| w Width | +| ad Drain area | +| as Source area | + ------------------------------------------------------------ +| pd Drain perimeter | +| ps Source perimeter | +| nrd Number of squares in drain | +| nrs Number of squares in source | +|-----------------------------------------------------------+ +| off Device is initially off | +| vds Initial D-S voltage | +| vgs Initial G-S voltage | +| vbs Initial B-S voltage | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BSIM2 - model parameters (input-only) | +|-----------------------------------------------------------+ +| nmos Flag to indicate NMOS | +| pmos Flag to indicate PMOS | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BSIM2 - model parameters (input-output) | +|-----------------------------------------------------------+ +|vfb Flat band voltage | +|lvfb Length dependence of vfb | +|wvfb Width dependence of vfb | +|phi Strong inversion surface potential | + ------------------------------------------------------------ +|lphi Length dependence of phi | +|wphi Width dependence of phi | +|k1 Bulk effect coefficient 1 | +|lk1 Length dependence of k1 | +|-----------------------------------------------------------+ +|wk1 Width dependence of k1 | +|k2 Bulk effect coefficient 2 | +|lk2 Length dependence of k2 | +|wk2 Width dependence of k2 | + ------------------------------------------------------------ +|eta0 VDS dependence of threshold voltage at VDD=0 +|leta0 Length dependence of eta0 | +|weta0 Width dependence of eta0 | +|etab VBS dependence of eta | +|-----------------------------------------------------------+ +|letab Length dependence of etab | +|wetab Width dependence of etab | +|dl Channel length reduction in um | +|dw Channel width reduction in um | + ------------------------------------------------------------ +|mu0 Low-field mobility, at VDS=0 VGS=VTH | +|mu0b VBS dependence of low-field mobility | +|lmu0b Length dependence of mu0b | +|wmu0b Width dependence of mu0b | +|-----------------------------------------------------------+ +|mus0 Mobility at VDS=VDD VGS=VTH | +|lmus0 Length dependence of mus0 | +|wmus0 Width dependence of mus | +|musb VBS dependence of mus | + ------------------------------------------------------------ +|lmusb Length dependence of musb | +|wmusb Width dependence of musb | +|mu20 VDS dependence of mu in tanh term | +|lmu20 Length dependence of mu20 | +|-----------------------------------------------------------+ +|wmu20 Width dependence of mu20 | +|mu2b VBS dependence of mu2 | +|lmu2b Length dependence of mu2b | +|wmu2b Width dependence of mu2b | + ------------------------------------------------------------ +|mu2g VGS dependence of mu2 | +| continued | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| BSIM2 - model input-output parameters - continued +|-----------------------------------------------------------+ +| lmu2g Length dependence of mu2g | +| wmu2g Width dependence of mu2g | +| mu30 VDS dependence of mu in linear term | +| lmu30 Length dependence of mu30 | + ------------------------------------------------------------ +| wmu30 Width dependence of mu30 | +| mu3b VBS dependence of mu3 | +| lmu3b Length dependence of mu3b | +| wmu3b Width dependence of mu3b | +|-----------------------------------------------------------+ +| mu3g VGS dependence of mu3 | +| lmu3g Length dependence of mu3g | +| wmu3g Width dependence of mu3g | +| mu40 VDS dependence of mu in linear term | + ------------------------------------------------------------ +| lmu40 Length dependence of mu40 | +| wmu40 Width dependence of mu40 | +| mu4b VBS dependence of mu4 | +| lmu4b Length dependence of mu4b | +|-----------------------------------------------------------+ +| wmu4b Width dependence of mu4b | +| mu4g VGS dependence of mu4 | +| lmu4g Length dependence of mu4g | +| wmu4g Width dependence of mu4g | + ------------------------------------------------------------ +| ua0 Linear VGS dependence of mobility | +| lua0 Length dependence of ua0 | +| wua0 Width dependence of ua0 | +| uab VBS dependence of ua | +|-----------------------------------------------------------+ +| luab Length dependence of uab | +| wuab Width dependence of uab | +| ub0 Quadratic VGS dependence of mobility | +| lub0 Length dependence of ub0 | + ------------------------------------------------------------ +| wub0 Width dependence of ub0 | +| ubb VBS dependence of ub | +| lubb Length dependence of ubb | +| wubb Width dependence of ubb | +|-----------------------------------------------------------+ +| u10 VDS depence of mobility | +| lu10 Length dependence of u10 | + wu10 Width dependence of u10 +| u1b VBS depence of u1 | + ------------------------------------------------------------ +| lu1b Length depence of u1b | +| wu1b Width depence of u1b | +| u1d VDS depence of u1 | +| lu1d Length depence of u1d | +|-----------------------------------------------------------+ +| wu1d Width depence of u1d | +| n0 Subthreshold slope at VDS=0 VBS=0 | +| ln0 Length dependence of n0 | +| continued | + ------------------------------------------------------------ + + + ------------------------------------------------------------------------ +| BSIM2 - model input-output parameters - continued | +|-----------------------------------------------------------------------+ +|wn0 Width dependence of n0 | +|nb VBS dependence of n | +|lnb Length dependence of nb | +|wnb Width dependence of nb | + ------------------------------------------------------------------------ +|nd VDS dependence of n | +|lnd Length dependence of nd | +|wnd Width dependence of nd | +|vof0 Threshold voltage offset AT VDS=0 VBS=0 | +|-----------------------------------------------------------------------+ +|lvof0 Length dependence of vof0 | +|wvof0 Width dependence of vof0 | +|vofb VBS dependence of vof | +|lvofb Length dependence of vofb | + ------------------------------------------------------------------------ +|wvofb Width dependence of vofb | +|vofd VDS dependence of vof | +|lvofd Length dependence of vofd | +|wvofd Width dependence of vofd | +|-----------------------------------------------------------------------+ +|ai0 Pre-factor of hot-electron effect. | +|lai0 Length dependence of ai0 | +|wai0 Width dependence of ai0 | +|aib VBS dependence of ai | + ------------------------------------------------------------------------ +|laib Length dependence of aib | +|waib Width dependence of aib | +|bi0 Exponential factor of hot-electron effect. | +|lbi0 Length dependence of bi0 | +|-----------------------------------------------------------------------+ +|wbi0 Width dependence of bi0 | +|bib VBS dependence of bi | +|lbib Length dependence of bib | +|wbib Width dependence of bib | + ------------------------------------------------------------------------ +|vghigh Upper bound of the cubic spline function. | +|lvghigh Length dependence of vghigh | +|wvghigh Width dependence of vghigh | +|vglow Lower bound of the cubic spline function. | +|-----------------------------------------------------------------------+ +|lvglow Length dependence of vglow | +|wvglow Width dependence of vglow | +|tox Gate oxide thickness in um | +|temp Temperature in degree Celcius | + ------------------------------------------------------------------------ +|vdd Maximum Vds | +|vgg Maximum Vgs | +|vbb Maximum Vbs | +|cgso Gate source overlap capacitance per unit channel width(m) +|-----------------------------------------------------------------------+ +|cgdo Gate drain overlap capacitance per unit channel width(m)| +|cgbo Gate bulk overlap capacitance per unit channel length(m)| +|xpart Flag for channel charge partitioning | +| continued | + ------------------------------------------------------------------------ + + + --------------------------------------------------------------------------- +| BSIM2 - model input-output parameters - continued | +|--------------------------------------------------------------------------+ +|rsh Source drain diffusion sheet resistance in ohm per square | +|js Source drain junction saturation current per unit area | +|pb Source drain junction built in potential | + mj Source drain bottom junction capacitance grading coefficient +| | + --------------------------------------------------------------------------- +|pbsw Source drain side junction capacitance built in potential | +|mjsw Source drain side junction capacitance grading coefficient | +|cj Source drain bottom junction capacitance per unit area | +|cjsw Source drain side junction capacitance per unit area | +|wdf Default width of source drain diffusion in um | +|dell Length reduction of source drain diffusion | + --------------------------------------------------------------------------- + + +@node Fixed capacitor, Current controlled current source, BSIM2 Berkeley Short Channel IGFET Model, Model and Device Parameters +@section Capacitor: Fixed capacitor + + ------------------------------------------------------------ +| Capacitor - instance parameters (input-output) | +|-----------------------------------------------------------+ +| capacitance Device capacitance | +| ic Initial capacitor voltage | +| w Device width | +| l Device length | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Capacitor - instance parameters (output-only) | +|-----------------------------------------------------------+ +| i Device current | +| p Instantaneous device power | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Capacitor - model parameters (input-only) | +|-----------------------------------------------------------+ +| c Capacitor model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Capacitor - model parameters (input-output) | +|-----------------------------------------------------------+ +| cj Bottom Capacitance per area | +| cjsw Sidewall capacitance per meter | +| defw Default width | +| narrow width correction factor | + ------------------------------------------------------------ + + +@node Current controlled current source, Linear current controlled current source, Fixed capacitor, Model and Device Parameters +@section CCCS: Current controlled current source + + ------------------------------------------------------------ +| CCCS - instance parameters (input-output) | +|-----------------------------------------------------------+ +| gain Gain of source | +| control Name of controlling source | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| CCCS - instance parameters (output-only) | +|-----------------------------------------------------------+ +| neg_node Negative node of source | +| pos_node Positive node of source | +| i CCCS output current | +| v CCCS voltage at output | +| p CCCS power | + ------------------------------------------------------------ + + +@node Linear current controlled current source, Current controlled ideal switch, Current controlled current source, Model and Device Parameters +@section CCVS: Linear current controlled current source + + ------------------------------------------------------------ +| CCVS - instance parameters (input-output) | +|-----------------------------------------------------------+ +| gain Transresistance (gain) | +| control Controlling voltage source | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| CCVS - instance parameters (output-only) | +|-----------------------------------------------------------+ +| pos_node Positive node of source | +| neg_node Negative node of source | +| i CCVS output current | +| v CCVS output voltage | +| p CCVS power | + ------------------------------------------------------------ + + + +@node Current controlled ideal switch, Junction Diode model, Linear current controlled current source, Model and Device Parameters +@section CSwitch: Current controlled ideal switch + + ------------------------------------------------------------ +| CSwitch - instance parameters (input-only) | +|-----------------------------------------------------------+ +| on Initially closed | +| off Initially open | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| CSwitch - instance parameters (input-output) | +|-----------------------------------------------------------+ +| control Name of controlling source | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| CSwitch - instance parameters (output-only) | +|-----------------------------------------------------------+ +| pos_node Positive node of switch | +| neg_node Negative node of switch | +| i Switch current | +| p Instantaneous power | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| CSwitch - model parameters (input-output) | +|-----------------------------------------------------------+ +| csw Current controlled switch model | +| it Threshold current | +| ih Hysterisis current | +| ron Closed resistance | +| roff Open resistance | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| CSwitch - model parameters (output-only) | +|-----------------------------------------------------------+ +| gon Closed conductance | +| goff Open conductance | + ------------------------------------------------------------ + + +@node Junction Diode model, Inductor, Current controlled ideal switch, Model and Device Parameters +@section Diode: Junction Diode model + + ------------------------------------------------------------ +| Diode - instance parameters (input-output) | +|-----------------------------------------------------------+ +| off Initially off | +| temp Instance temperature | +| ic Initial device voltage | +| area Area factor | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Diode - instance parameters (output-only) | +|-----------------------------------------------------------+ +| vd Diode voltage | +| id Diode current | +| c Diode current | +| gd Diode conductance | + ------------------------------------------------------------ +| cd Diode capacitance | +| charge Diode capacitor charge | +| capcur Diode capacitor current | +| p Diode power | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Diode - model parameters (input-only) | +|-----------------------------------------------------------+ +| d Diode model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Diode - model parameters (input-output) | +|-----------------------------------------------------------+ +| is Saturation current | +| tnom Parameter measurement temperature | +| rs Ohmic resistance | +| n Emission Coefficient | + ------------------------------------------------------------ +| tt Transit Time | +| cjo Junction capacitance | +| cj0 (null) | +| vj Junction potential | +|-----------------------------------------------------------+ +| m Grading coefficient | +| eg Activation energy | +| xti Saturation current temperature exp. | +| kf flicker noise coefficient | + ------------------------------------------------------------ +| af flicker noise exponent | +| fc Forward bias junction fit parameter | +| bv Reverse breakdown voltage | +| ibv Current at reverse breakdown voltage | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Diode - model parameters (output-only) | +|-----------------------------------------------------------+ +| cond Ohmic conductance | + ------------------------------------------------------------ + + +@node Inductor, Mutual inductors, Junction Diode model, Model and Device Parameters +@section Inductor: Inductors + + ------------------------------------------------------------ +| Inductor - instance parameters (input-output) | +|-----------------------------------------------------------+ +| inductance Inductance of inductor | +| ic Initial current through inductor | + ------------------------------------------------------------ + + + ------------------------------------------------------------- +| Inductor - instance parameters (output-only) | +|------------------------------------------------------------+ +|flux Flux through inductor | +|v Terminal voltage of inductor | +|volt | +|i Current through the inductor | +|current | + p instantaneous power dissipated by the inductor +| | + ------------------------------------------------------------- + + +@node Mutual inductors, Independent current source, Inductor, Model and Device Parameters +@section mutual: Mutual inductors + + ------------------------------------------------------------ +| mutual - instance parameters (input-output) | +|-----------------------------------------------------------+ +| k Mutual inductance | +| coefficient (null) | +| inductor1 First coupled inductor | +| inductor2 Second coupled inductor | + ------------------------------------------------------------ + + +@node Independent current source, Junction Field effect transistor, Mutual inductors, Model and Device Parameters +@section Isource: Independent current source + + ------------------------------------------------------------ +| Isource - instance parameters (input-only) | +|-----------------------------------------------------------+ +| pulse Pulse description | +| sine Sinusoidal source description | +| sin Sinusoidal source description | +| exp Exponential source description | + ------------------------------------------------------------ +| pwl Piecewise linear description | +| sffm single freq. FM description | +| ac AC magnitude,phase vector | +| c Current through current source | +| distof1 f1 input for distortion | +| distof2 f2 input for distortion | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Isource - instance parameters (input-output) | +|-----------------------------------------------------------+ +| dc DC value of source | +| acmag AC magnitude | +| acphase AC phase | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Isource - instance parameters (output-only) | +|-----------------------------------------------------------+ +| neg_node Negative node of source | +| pos_node Positive node of source | + acreal AC real part +| acimag AC imaginary part | + ------------------------------------------------------------ +| function Function of the source | +| order Order of the source function | +| coeffs Coefficients of the source | +| v Voltage across the supply | +| p Power supplied by the source | + ------------------------------------------------------------ + + +@node Junction Field effect transistor, Lossy transmission line, Independent current source, Model and Device Parameters +@section JFET: Junction Field effect transistor + + ------------------------------------------------------------ +| JFET - instance parameters (input-output) | +|-----------------------------------------------------------+ +| off Device initially off | +| ic Initial VDS,VGS vector | +| area Area factor | +| ic-vds Initial D-S voltage | +| ic-vgs Initial G-S volrage | +| temp Instance temperature | + ------------------------------------------------------------ + + + --------------------------------------------------------------- +| JFET - instance parameters (output-only) | +|--------------------------------------------------------------+ +|drain-node Number of drain node | +|gate-node Number of gate node | +|source-node Number of source node | +|drain-prime-node Internal drain node | + --------------------------------------------------------------- +|source-prime-nodeInternal source node | +|vgs Voltage G-S | +|vgd Voltage G-D | +|ig Current at gate node | +|--------------------------------------------------------------+ +|id Current at drain node | +|is Source current | +|igd Current G-D | +|gm Transconductance | + --------------------------------------------------------------- +|gds Conductance D-S | +|ggs Conductance G-S | +|ggd Conductance G-D | +|qgs Charge storage G-S junction | +|--------------------------------------------------------------+ +|qgd Charge storage G-D junction | + cqgs Capacitance due to charge storage G-S junction +| | + cqgd Capacitance due to charge storage G-D junction +|p Power dissipated by the JFET | + --------------------------------------------------------------- + + + ------------------------------------------------------------ +| JFET - model parameters (input-output) | +|-----------------------------------------------------------+ +| njf N type JFET model | +| pjf P type JFET model | +| vt0 Threshold voltage | +| vto (null) | + ------------------------------------------------------------ +| beta Transconductance parameter | +| lambda Channel length modulation param. | +| rd Drain ohmic resistance | +| rs Source ohmic resistance | +| cgs G-S junction capactance | +| continued | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| JFET - model input-output parameters - continued +|-----------------------------------------------------------+ +| cgd G-D junction cap | +| pb Gate junction potential | +| is Gate junction saturation current | +| fc Forward bias junction fit parm. | + ------------------------------------------------------------ +| b Doping tail parameter | +| tnom parameter measurement temperature | +| kf Flicker Noise Coefficient | +| af Flicker Noise Exponent | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| JFET - model parameters (output-only) | +|-----------------------------------------------------------+ +| type N-type or P-type JFET model | +| gd Drain conductance | +| gs Source conductance | + ------------------------------------------------------------ + + +@node Lossy transmission line, GaAs MESFET model, Junction Field effect transistor, Model and Device Parameters +@section LTRA: Lossy transmission line + + ------------------------------------------------------------ +| LTRA - instance parameters (input-only) | +|-----------------------------------------------------------+ +| ic Initial condition vector:v1,i1,v2,i2 | + ------------------------------------------------------------ + + ------------------------------------------------------------ +| LTRA - instance parameters (input-output) | +|-----------------------------------------------------------+ +| v1 Initial voltage at end 1 | +| v2 Initial voltage at end 2 | +| i1 Initial current at end 1 | +| i2 Initial current at end 2 | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| LTRA - instance parameters (output-only) | +|-----------------------------------------------------------+ +| pos_node1 Positive node of end 1 of t-line | +| neg_node1 Negative node of end 1 of t.line | +| pos_node2 Positive node of end 2 of t-line | +| neg_node2 Negative node of end 2 of t-line | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| LTRA - model parameters (input-output) | +|-----------------------------------------------------------+ +|ltra LTRA model | +|r Resistance per metre | +|l Inductance per metre | +|g (null) | + ------------------------------------------------------------ +|c Capacitance per metre | +|len length of line | +|nocontrol No timestep control | +|steplimit always limit timestep to 0.8*(delay of line) +| continued | + ------------------------------------------------------------ + + ----------------------------------------------------------------------------------- +| LTRA - model input-output parameters - continued | +|----------------------------------------------------------------------------------+ +|nosteplimit don't always limit timestep to 0.8*(delay of line) | +|lininterp use linear interpolation | +|quadinterp use quadratic interpolation | +|mixedinterp use linear interpolation if quadratic results look unacceptable | + ----------------------------------------------------------------------------------- +|truncnr use N-R iterations for step calculation in LTRAtrunc | +|truncdontcut don't limit timestep to keep impulse response calculation errors low +|compactrel special reltol for straight line checking | +|compactabs special abstol for straight line checking | + ----------------------------------------------------------------------------------- + + + ------------------------------------------------------------ +| LTRA - model parameters (output-only) | +|-----------------------------------------------------------+ +| rel Rel. rate of change of deriv. for bkpt | +| abs Abs. rate of change of deriv. for bkpt | + ------------------------------------------------------------ + + +@node GaAs MESFET model, Level 1 MOSfet model, Lossy transmission line, Model and Device Parameters +@section MES: GaAs MESFET model + + ------------------------------------------------------------ +| MES - instance parameters (input-output) | +|-----------------------------------------------------------+ +| area Area factor | +| icvds Initial D-S voltage | +| icvgs Initial G-S voltage | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| MES - instance parameters (output-only) | +|-----------------------------------------------------------+ +|off Device initially off | +|dnode Number of drain node | +|gnode Number of gate node | +|snode Number of source node | + ------------------------------------------------------------ +|dprimenode Number of internal drain node | +|sprimenode Number of internal source node | +|vgs Gate-Source voltage | +|vgd Gate-Drain voltage | +|-----------------------------------------------------------+ +|cg Gate capacitance | +|cd Drain capacitance | +|cgd Gate-Drain capacitance | +|gm Transconductance | + ------------------------------------------------------------ +|gds Drain-Source conductance | +|ggs Gate-Source conductance | +|ggd Gate-Drain conductance | +|cqgs Capacitance due to gate-source charge storage +|-----------------------------------------------------------+ +|cqgd Capacitance due to gate-drain charge storage| +|qgs Gate-Source charge storage | +|qgd Gate-Drain charge storage | +|is Source current | +| continued | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| MES - instance output-only parameters - continued +|-----------------------------------------------------------+ +| p Power dissipated by the mesfet | + ----------------------------------------------------------- + ------------------------------------------------------------ +| MES - model parameters (input-only) | +|-----------------------------------------------------------+ +| nmf N type MESfet model | +| pmf P type MESfet model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| MES - model parameters (input-output) | +|-----------------------------------------------------------+ +| vt0 Pinch-off voltage | +| vto (null) | +| alpha Saturation voltage parameter | +| beta Transconductance parameter | + ------------------------------------------------------------ +| lambda Channel length modulation parm. | +| b Doping tail extending parameter | +| rd Drain ohmic resistance | +| rs Source ohmic resistance | +|-----------------------------------------------------------+ +| cgs G-S junction capacitance | +| cgd G-D junction capacitance | +| pb Gate junction potential | +| is Junction saturation current | + ------------------------------------------------------------ +| fc Forward bias junction fit parm. | +| kf Flicker noise coefficient | +| af Flicker noise exponent | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| MES - model parameters (output-only) | +|-----------------------------------------------------------+ +| type N-type or P-type MESfet model | +| gd Drain conductance | +| gs Source conductance | +| depl_cap Depletion capacitance | +| vcrit Critical voltage | + ------------------------------------------------------------ + + +@node Level 1 MOSfet model, Level 2 MOSfet model, GaAs MESFET model, Model and Device Parameters +@section Mos1: Level 1 MOSfet model with Meyer capacitance model + + ------------------------------------------------------------ +| Mos1 - instance parameters (input-only) | +|-----------------------------------------------------------+ +| off Device initially off | +| ic Vector of D-S, G-S, B-S voltages | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos1 - instance parameters (input-output) | +|-----------------------------------------------------------+ +| l Length | +| w Width | +| ad Drain area | +| as Source area | + ------------------------------------------------------------ +| pd Drain perimeter | +| ps Source perimeter | +| nrd Drain squares | +| nrs Source squares | +|-----------------------------------------------------------+ +| icvds Initial D-S voltage | +| icvgs Initial G-S voltage | +| icvbs Initial B-S voltage | +| temp Instance temperature | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos1 - instance parameters (output-only) | +|-----------------------------------------------------------+ +| id Drain current | +| is Source current | +| ig Gate current | +| ib Bulk current | + ------------------------------------------------------------ +| ibd B-D junction current | +| ibs B-S junction current | +| vgs Gate-Source voltage | +| vds Drain-Source voltage | +|-----------------------------------------------------------+ +| vbs Bulk-Source voltage | +| vbd Bulk-Drain voltage | +| dnode Number of the drain node | +| gnode Number of the gate node | + ------------------------------------------------------------ +| snode Number of the source node | +| bnode Number of the node | +| dnodeprime Number of int. drain node | +| snodeprime Number of int. source node | +|-----------------------------------------------------------+ +| von | +| vdsat Saturation drain voltage | +| sourcevcrit Critical source voltage | +| drainvcrit Critical drain voltage | +| rs Source resistance | +| continued | + ------------------------------------------------------------ + + + -------------------------------------------------------------- +| Mos1 - instance output-only parameters - continued +|-------------------------------------------------------------+ +|sourceconductanceConductance of source | +|rd Drain conductance | +|drainconductance Conductance of drain | +|gm Transconductance | + -------------------------------------------------------------- +|gds Drain-Source conductance | +|gmb Bulk-Source transconductance | +|gmbs | +|gbd Bulk-Drain conductance | +|-------------------------------------------------------------+ +|gbs Bulk-Source conductance | +|cbd Bulk-Drain capacitance | +|cbs Bulk-Source capacitance | +|cgs Gate-Source capacitance | + -------------------------------------------------------------- +|cgd Gate-Drain capacitance | +|cgb Gate-Bulk capacitance | +|cqgs Capacitance due to gate-source charge storage +|cqgd Capacitance due to gate-drain charge storage| +|-------------------------------------------------------------+ +|cqgb Capacitance due to gate-bulk charge storage | +|cqbd Capacitance due to bulk-drain charge storage| + cqbs Capacitance due to bulk-source charge storage +|cbd0 Zero-Bias B-D junction capacitance | + -------------------------------------------------------------- +|cbdsw0 | +|cbs0 Zero-Bias B-S junction capacitance | +|cbssw0 | +|qgs Gate-Source charge storage | +|-------------------------------------------------------------+ +|qgd Gate-Drain charge storage | +|qgb Gate-Bulk charge storage | +|qbd Bulk-Drain charge storage | +|qbs Bulk-Source charge storage | +|p Instaneous power | + -------------------------------------------------------------- + + + ------------------------------------------------------------ +| Mos1 - model parameters (input-only) | +|-----------------------------------------------------------+ +| nmos N type MOSfet model | +| pmos P type MOSfet model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos1 - model parameters (input-output) | +|-----------------------------------------------------------+ +| vto Threshold voltage | +| vt0 (null) | +| kp Transconductance parameter | +| gamma Bulk threshold parameter | + ------------------------------------------------------------ +| phi Surface potential | +| lambda Channel length modulation | +| rd Drain ohmic resistance | +| continued | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos1 - model input-output parameters - continued +|-----------------------------------------------------------+ +| rs Source ohmic resistance | +| cbd B-D junction capacitance | +| cbs B-S junction capacitance | +| is Bulk junction sat. current | + ------------------------------------------------------------ +| pb Bulk junction potential | +| cgso Gate-source overlap cap. | +| cgdo Gate-drain overlap cap. | +| cgbo Gate-bulk overlap cap. | +|-----------------------------------------------------------+ +| rsh Sheet resistance | +| cj Bottom junction cap per area | +| mj Bottom grading coefficient | +| cjsw Side junction cap per area | + ------------------------------------------------------------ +| mjsw Side grading coefficient | +| js Bulk jct. sat. current density | +| tox Oxide thickness | +| ld Lateral diffusion | +|-----------------------------------------------------------+ +| u0 Surface mobility | +| uo (null) | +| fc Forward bias jct. fit parm. | +| nsub Substrate doping | + ------------------------------------------------------------ +| tpg Gate type | +| nss Surface state density | +| tnom Parameter measurement temperature | +| kf Flicker noise coefficient | +| af Flicker noise exponent | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos1 - model parameters (output-only) | +|-----------------------------------------------------------+ +| type N-channel or P-channel MOS | + ------------------------------------------------------------ + + +@node Level 2 MOSfet model, Level 3 MOSfet model, Level 1 MOSfet model, Model and Device Parameters +@section Mos2: Level 2 MOSfet model with Meyer capacitance model + + ------------------------------------------------------------ +| Mos2 - instance parameters (input-only) | +|-----------------------------------------------------------+ +| off Device initially off | +| ic Vector of D-S, G-S, B-S voltages | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos2 - instance parameters (input-output) | +|-----------------------------------------------------------+ +| l Length | +| w Width | +| ad Drain area | +| as Source area | + ------------------------------------------------------------ +| pd Drain perimeter | +| ps Source perimeter | +| nrd Drain squares | +| nrs Source squares | +|-----------------------------------------------------------+ +| icvds Initial D-S voltage | +| icvgs Initial G-S voltage | +| icvbs Initial B-S voltage | +| temp Instance operating temperature | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos2 - instance parameters (output-only) | +|-----------------------------------------------------------+ +| id Drain current | +| cd | +| ibd B-D junction current | +| ibs B-S junction current | + ------------------------------------------------------------ +| is Source current | +| ig Gate current | +| ib Bulk current | +| vgs Gate-Source voltage | +|-----------------------------------------------------------+ +| vds Drain-Source voltage | +| vbs Bulk-Source voltage | +| vbd Bulk-Drain voltage | +| dnode Number of drain node | + ------------------------------------------------------------ +| gnode Number of gate node | +| snode Number of source node | +| bnode Number of bulk node | +| dnodeprime Number of internal drain node | +|-----------------------------------------------------------+ +| snodeprime Number of internal source node | +| von | +| vdsat Saturation drain voltage | +| sourcevcrit Critical source voltage | +| drainvcrit Critical drain voltage | +| continued | + ------------------------------------------------------------ + + + -------------------------------------------------------------- +| Mos2 - instance output-only parameters - continued +|-------------------------------------------------------------+ +|rs Source resistance | +|sourceconductanceSource conductance | +|rd Drain resistance | +|drainconductance Drain conductance | + -------------------------------------------------------------- +|gm Transconductance | +|gds Drain-Source conductance | +|gmb Bulk-Source transconductance | +|gmbs | +|-------------------------------------------------------------+ +|gbd Bulk-Drain conductance | +|gbs Bulk-Source conductance | +|cbd Bulk-Drain capacitance | +|cbs Bulk-Source capacitance | + -------------------------------------------------------------- +|cgs Gate-Source capacitance | +|cgd Gate-Drain capacitance | +|cgb Gate-Bulk capacitance | +|cbd0 Zero-Bias B-D junction capacitance | +|-------------------------------------------------------------+ +|cbdsw0 | +|cbs0 Zero-Bias B-S junction capacitance | +|cbssw0 | + cqgs Capacitance due to gate-source charge storage +| | + -------------------------------------------------------------- +|cqgd Capacitance due to gate-drain charge storage| +|cqgb Capacitance due to gate-bulk charge storage | +|cqbd Capacitance due to bulk-drain charge storage| +|cqbs Capacitance due to bulk-source charge storage +|-------------------------------------------------------------+ +|qgs Gate-Source charge storage | +|qgd Gate-Drain charge storage | +|qgb Gate-Bulk charge storage | +|qbd Bulk-Drain charge storage | +|qbs Bulk-Source charge storage | +|p Instantaneous power | + -------------------------------------------------------------- + + + ------------------------------------------------------------ +| Mos2 - model parameters (input-only) | +|-----------------------------------------------------------+ +| nmos N type MOSfet model | +| pmos P type MOSfet model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos2 - model parameters (input-output) | +|-----------------------------------------------------------+ +| vto Threshold voltage | +| vt0 (null) | +| kp Transconductance parameter | +| gamma Bulk threshold parameter | + ------------------------------------------------------------ +| phi Surface potential | +| lambda Channel length modulation | +| rd Drain ohmic resistance | +| rs Source ohmic resistance | +|-----------------------------------------------------------+ +| cbd B-D junction capacitance | +| cbs B-S junction capacitance | +| is Bulk junction sat. current | +| pb Bulk junction potential | + ------------------------------------------------------------ +| cgso Gate-source overlap cap. | +| cgdo Gate-drain overlap cap. | +| cgbo Gate-bulk overlap cap. | +| rsh Sheet resistance | +|-----------------------------------------------------------+ +| cj Bottom junction cap per area | +| mj Bottom grading coefficient | +| cjsw Side junction cap per area | +| mjsw Side grading coefficient | + ------------------------------------------------------------ +| js Bulk jct. sat. current density | +| tox Oxide thickness | +| ld Lateral diffusion | +| u0 Surface mobility | +|-----------------------------------------------------------+ +| uo (null) | +| fc Forward bias jct. fit parm. | +| nsub Substrate doping | +| tpg Gate type | + ------------------------------------------------------------ +| nss Surface state density | +| delta Width effect on threshold | +| uexp Crit. field exp for mob. deg. | +| ucrit Crit. field for mob. degradation | +|-----------------------------------------------------------+ +| vmax Maximum carrier drift velocity | +| xj Junction depth | +| neff Total channel charge coeff. | +| nfs Fast surface state density | + ------------------------------------------------------------ +| tnom Parameter measurement temperature | +| kf Flicker noise coefficient | +| af Flicker noise exponent | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos2 - model parameters (output-only) | +|-----------------------------------------------------------+ +| type N-channel or P-channel MOS | + ------------------------------------------------------------ + + +@node Level 3 MOSfet model, Level 6 MOSfet model, Level 2 MOSfet model, Model and Device Parameters +@section Mos3: Level 3 MOSfet model with Meyer capacitance model + + + ------------------------------------------------------------ +| Mos3 - instance parameters (input-only) | +|-----------------------------------------------------------+ +| off Device initially off | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos3 - instance parameters (input-output) | +|-----------------------------------------------------------+ +| l Length | +| w Width | +| ad Drain area | +| as Source area | + ------------------------------------------------------------ +| pd Drain perimeter | +| ps Source perimeter | +| nrd Drain squares | +| nrs Source squares | +|-----------------------------------------------------------+ +| icvds Initial D-S voltage | +| icvgs Initial G-S voltage | +| icvbs Initial B-S voltage | +| ic Vector of D-S, G-S, B-S voltages | +| temp Instance operating temperature | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos3 - instance parameters (output-only) | +|-----------------------------------------------------------+ +| id Drain current | +| cd Drain current | +| ibd B-D junction current | +| ibs B-S junction current | + ------------------------------------------------------------ +| is Source current | +| ig Gate current | +| ib Bulk current | +| vgs Gate-Source voltage | +|-----------------------------------------------------------+ +| vds Drain-Source voltage | +| vbs Bulk-Source voltage | +| vbd Bulk-Drain voltage | +| dnode Number of drain node | + ------------------------------------------------------------ +| gnode Number of gate node | +| snode Number of source node | +| bnode Number of bulk node | +| dnodeprime Number of internal drain node | +| snodeprime Number of internal source node | +| continued | + ------------------------------------------------------------ + + + -------------------------------------------------------------- +| Mos3 - instance output-only parameters - continued +|-------------------------------------------------------------+ +|von Turn-on voltage | +|vdsat Saturation drain voltage | +|sourcevcrit Critical source voltage | +|drainvcrit Critical drain voltage | + -------------------------------------------------------------- +|rs Source resistance | +|sourceconductanceSource conductance | +|rd Drain resistance | +|drainconductance Drain conductance | +|-------------------------------------------------------------+ +|gm Transconductance | +|gds Drain-Source conductance | +|gmb Bulk-Source transconductance | +|gmbs Bulk-Source transconductance | + -------------------------------------------------------------- +|gbd Bulk-Drain conductance | +|gbs Bulk-Source conductance | +|cbd Bulk-Drain capacitance | +|cbs Bulk-Source capacitance | +|-------------------------------------------------------------+ +|cgs Gate-Source capacitance | +|cgd Gate-Drain capacitance | +|cgb Gate-Bulk capacitance | + cqgs Capacitance due to gate-source charge storage +| | + -------------------------------------------------------------- +|cqgd Capacitance due to gate-drain charge storage| +|cqgb Capacitance due to gate-bulk charge storage | +|cqbd Capacitance due to bulk-drain charge storage| +|cqbs Capacitance due to bulk-source charge storage +|-------------------------------------------------------------+ +|cbd0 Zero-Bias B-D junction capacitance | +|cbdsw0 Zero-Bias B-D sidewall capacitance | +|cbs0 Zero-Bias B-S junction capacitance | +|cbssw0 Zero-Bias B-S sidewall capacitance | + -------------------------------------------------------------- +|qbs Bulk-Source charge storage | +|qgs Gate-Source charge storage | +|qgd Gate-Drain charge storage | +|qgb Gate-Bulk charge storage | +|qbd Bulk-Drain charge storage | +|p Instantaneous power | + -------------------------------------------------------------- + + + ------------------------------------------------------------ +| Mos3 - model parameters (input-only) | +|-----------------------------------------------------------+ +| nmos N type MOSfet model | +| pmos P type MOSfet model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos3 - model parameters (input-output) | +|-----------------------------------------------------------+ +| vto Threshold voltage | +| vt0 (null) | +| kp Transconductance parameter | +| gamma Bulk threshold parameter | + ------------------------------------------------------------ +| phi Surface potential | +| rd Drain ohmic resistance | +| rs Source ohmic resistance | +| cbd B-D junction capacitance | +|-----------------------------------------------------------+ +| cbs B-S junction capacitance | +| is Bulk junction sat. current | +| pb Bulk junction potential | +| cgso Gate-source overlap cap. | + ------------------------------------------------------------ +| cgdo Gate-drain overlap cap. | +| cgbo Gate-bulk overlap cap. | +| rsh Sheet resistance | +| cj Bottom junction cap per area | +|-----------------------------------------------------------+ +| mj Bottom grading coefficient | +| cjsw Side junction cap per area | +| mjsw Side grading coefficient | +| js Bulk jct. sat. current density | + ------------------------------------------------------------ +| tox Oxide thickness | +| ld Lateral diffusion | +| u0 Surface mobility | +| uo (null) | +|-----------------------------------------------------------+ +| fc Forward bias jct. fit parm. | +| nsub Substrate doping | +| tpg Gate type | +| nss Surface state density | + ------------------------------------------------------------ +| vmax Maximum carrier drift velocity | +| xj Junction depth | +| nfs Fast surface state density | +| xd Depletion layer width | +|-----------------------------------------------------------+ +| alpha Alpha | +| eta Vds dependence of threshold voltage | +| delta Width effect on threshold | +| input_delta (null) | + ------------------------------------------------------------ +| theta Vgs dependence on mobility | +| kappa Kappa | +| tnom Parameter measurement temperature | +| kf Flicker noise coefficient | +| af Flicker noise exponent | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos3 - model parameters (output-only) | +|-----------------------------------------------------------+ +| type N-channel or P-channel MOS | + ------------------------------------------------------------ + + +@node Level 6 MOSfet model, Simple linear resistor, Level 3 MOSfet model, Model and Device Parameters +@section Mos6: Level 6 MOSfet model with Meyer capacitance model + + + ------------------------------------------------------------ +| Mos6 - instance parameters (input-only) | +|-----------------------------------------------------------+ +| off Device initially off | +| ic Vector of D-S, G-S, B-S voltages | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos6 - instance parameters (input-output) | +|-----------------------------------------------------------+ +| l Length | +| w Width | +| ad Drain area | +| as Source area | + ------------------------------------------------------------ +| pd Drain perimeter | +| ps Source perimeter | +| nrd Drain squares | +| nrs Source squares | +|-----------------------------------------------------------+ +| icvds Initial D-S voltage | +| icvgs Initial G-S voltage | +| icvbs Initial B-S voltage | +| temp Instance temperature | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos6 - instance parameters (output-only) | +|-----------------------------------------------------------+ +| id Drain current | +| cd Drain current | +| is Source current | +| ig Gate current | + ------------------------------------------------------------ +| ib Bulk current | +| ibs B-S junction capacitance | +| ibd B-D junction capacitance | +| vgs Gate-Source voltage | +|-----------------------------------------------------------+ +| vds Drain-Source voltage | +| vbs Bulk-Source voltage | +| vbd Bulk-Drain voltage | +| dnode Number of the drain node | + ------------------------------------------------------------ +| gnode Number of the gate node | +| snode Number of the source node | +| bnode Number of the node | +| dnodeprime Number of int. drain node | +| snodeprime Number of int. source node | +| continued | + ------------------------------------------------------------ + + + -------------------------------------------------------------- +| Mos6 - instance output-only parameters - continued +|-------------------------------------------------------------+ +|rs Source resistance | +|sourceconductanceSource conductance | +|rd Drain resistance | +|drainconductance Drain conductance | + -------------------------------------------------------------- +|von Turn-on voltage | +|vdsat Saturation drain voltage | +|sourcevcrit Critical source voltage | +|drainvcrit Critical drain voltage | +|-------------------------------------------------------------+ +|gmbs Bulk-Source transconductance | +|gm Transconductance | +|gds Drain-Source conductance | +|gbd Bulk-Drain conductance | + -------------------------------------------------------------- +|gbs Bulk-Source conductance | +|cgs Gate-Source capacitance | +|cgd Gate-Drain capacitance | +|cgb Gate-Bulk capacitance | +|-------------------------------------------------------------+ +|cbd Bulk-Drain capacitance | +|cbs Bulk-Source capacitance | +|cbd0 Zero-Bias B-D junction capacitance | +|cbdsw0 | + -------------------------------------------------------------- +|cbs0 Zero-Bias B-S junction capacitance | +|cbssw0 | +|cqgs Capacitance due to gate-source charge storage +|cqgd Capacitance due to gate-drain charge storage| +|-------------------------------------------------------------+ +|cqgb Capacitance due to gate-bulk charge storage | +|cqbd Capacitance due to bulk-drain charge storage| + cqbs Capacitance due to bulk-source charge storage +|qgs Gate-Source charge storage | + -------------------------------------------------------------- +|qgd Gate-Drain charge storage | +|qgb Gate-Bulk charge storage | +|qbd Bulk-Drain charge storage | +|qbs Bulk-Source charge storage | +|p Instaneous power | + -------------------------------------------------------------- + + + ------------------------------------------------------------ +| Mos6 - model parameters (input-only) | +|-----------------------------------------------------------+ +| nmos N type MOSfet model | +| pmos P type MOSfet model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos6 - model parameters (input-output) | +|-----------------------------------------------------------+ +| vto Threshold voltage | +| vt0 (null) | +| kv Saturation voltage factor | +| nv Saturation voltage coeff. | + ------------------------------------------------------------ +| kc Saturation current factor | +| nc Saturation current coeff. | +| nvth Threshold voltage coeff. | +| ps Sat. current modification par. | +|-----------------------------------------------------------+ +| gamma Bulk threshold parameter | +| gamma1 Bulk threshold parameter 1 | +| sigma Static feedback effect par. | +| phi Surface potential | + ------------------------------------------------------------ +| lambda Channel length modulation param. | +| lambda0 Channel length modulation param. 0 | +| lambda1 Channel length modulation param. 1 | +| rd Drain ohmic resistance | +|-----------------------------------------------------------+ +| rs Source ohmic resistance | +| cbd B-D junction capacitance | +| cbs B-S junction capacitance | +| is Bulk junction sat. current | + ------------------------------------------------------------ +| pb Bulk junction potential | +| cgso Gate-source overlap cap. | +| cgdo Gate-drain overlap cap. | +| cgbo Gate-bulk overlap cap. | +|-----------------------------------------------------------+ +| rsh Sheet resistance | +| cj Bottom junction cap per area | +| mj Bottom grading coefficient | +| cjsw Side junction cap per area | + ------------------------------------------------------------ +| mjsw Side grading coefficient | +| js Bulk jct. sat. current density | +| ld Lateral diffusion | +| tox Oxide thickness | +|-----------------------------------------------------------+ +| u0 Surface mobility | +| uo (null) | +| fc Forward bias jct. fit parm. | +| tpg Gate type | + ------------------------------------------------------------ +| nsub Substrate doping | +| nss Surface state density | +| tnom Parameter measurement temperature | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Mos6 - model parameters (output-only) | +|-----------------------------------------------------------+ +| type N-channel or P-channel MOS | + ------------------------------------------------------------ + + +@node Simple linear resistor, Ideal voltage controlled switch, Level 6 MOSfet model, Model and Device Parameters +@section Resistor: Simple linear resistor + + ------------------------------------------------------------ +| Resistor - instance parameters (input-output) | +|-----------------------------------------------------------+ +| resistance Resistance | +| temp Instance operating temperature | +| l Length | +| w Width | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Resistor - instance parameters (output-only) | +|-----------------------------------------------------------+ +| i Current | +| p Power | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Resistor - model parameters (input-only) | +|-----------------------------------------------------------+ +| r Device is a resistor model | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Resistor - model parameters (input-output) | +|-----------------------------------------------------------+ +| rsh Sheet resistance | +| narrow Narrowing of resistor | +| tc1 First order temp. coefficient | +| tc2 Second order temp. coefficient | +| defw Default device width | +| tnom Parameter measurement temperature | + ------------------------------------------------------------ + + +@node Ideal voltage controlled switch, Lossless transmission line, Simple linear resistor, Model and Device Parameters +@section Switch: Ideal voltage controlled switch + + ------------------------------------------------------------ +| Switch - instance parameters (input-only) | +|-----------------------------------------------------------+ +| on Switch initially closed | +| off Switch initially open | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Switch - instance parameters (input-output) | +|-----------------------------------------------------------+ +| pos_node Positive node of switch | +| neg_node Negative node of switch | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Switch - instance parameters (output-only) | +|-----------------------------------------------------------+ +| cont_p_node Positive contr. node of switch | +| cont_n_node Positive contr. node of switch | +| i Switch current | +| p Switch power | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Switch - model parameters (input-output) | +|-----------------------------------------------------------+ +| sw Switch model | +| vt Threshold voltage | +| vh Hysteresis voltage | +| ron Resistance when closed | +| roff Resistance when open | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Switch - model parameters (output-only) | +|-----------------------------------------------------------+ +| gon Conductance when closed | +| goff Conductance when open | + ------------------------------------------------------------ + + +@node Lossless transmission line, Voltage controlled current source, Ideal voltage controlled switch, Model and Device Parameters +@section Tranline: Lossless transmission line + + ------------------------------------------------------------ +| Tranline - instance parameters (input-only) | +|-----------------------------------------------------------+ +| ic Initial condition vector:v1,i1,v2,i2 | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Tranline - instance parameters (input-output) | +|-----------------------------------------------------------+ +| z0 Characteristic impedance | +| zo (null) | +| f Frequency | +| td Transmission delay | + ------------------------------------------------------------ +| nl Normalized length at frequency given | +| v1 Initial voltage at end 1 | +| v2 Initial voltage at end 2 | +| i1 Initial current at end 1 | +| i2 Initial current at end 2 | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Tranline - instance parameters (output-only) | +|-----------------------------------------------------------+ +| rel Rel. rate of change of deriv. for bkpt | +| abs Abs. rate of change of deriv. for bkpt | +| pos_node1 Positive node of end 1 of t. line | +| neg_node1 Negative node of end 1 of t. line | + ------------------------------------------------------------ +| pos_node2 Positive node of end 2 of t. line | +| neg_node2 Negative node of end 2 of t. line | +| delays Delayed values of excitation | + ------------------------------------------------------------ + + +@node Voltage controlled current source, Voltage controlled voltage source, Lossless transmission line, Model and Device Parameters +@section VCCS: Voltage controlled current source + + ------------------------------------------------------------ +| VCCS - instance parameters (input-only) | +|-----------------------------------------------------------+ +| ic Initial condition of controlling source | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| VCCS - instance parameters (input-output) | +|-----------------------------------------------------------+ +| gain Transconductance of source (gain) | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| VCCS - instance parameters (output-only) | +|-----------------------------------------------------------+ +| pos_node Positive node of source | +| neg_node Negative node of source | +| cont_p_node Positive node of contr. source | +| cont_n_node Negative node of contr. source | + ------------------------------------------------------------ +| i Output current | +| v Voltage across output | +| p Power | + ------------------------------------------------------------ + + +@node Voltage controlled voltage source, Independent voltage source, Voltage controlled current source, Model and Device Parameters +@section VCVS: Voltage controlled voltage source + + ------------------------------------------------------------ +| VCVS - instance parameters (input-only) | +|-----------------------------------------------------------+ +| ic Initial condition of controlling source | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| VCVS - instance parameters (input-output) | +|-----------------------------------------------------------+ +| gain Voltage gain | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| VCVS - instance parameters (output-only) | +|-----------------------------------------------------------+ +| pos_node Positive node of source | +| neg_node Negative node of source | +| cont_p_node Positive node of contr. source | + cont_n_node Negative node of contr. source + ------------------------------------------------------------ +| i Output current | +| v Output voltage | +| p Power | + ------------------------------------------------------------ + + +@node Independent voltage source, , Voltage controlled voltage source, Model and Device Parameters +@section Vsource: Independent voltage source + + ------------------------------------------------------------ +| Vsource - instance parameters (input-only) | +|-----------------------------------------------------------+ +| pulse Pulse description | +| sine Sinusoidal source description | +| sin Sinusoidal source description | +| exp Exponential source description | + ------------------------------------------------------------ +| pwl Piecewise linear description | +| sffm Single freq. FM descripton | +| ac AC magnitude, phase vector | +| distof1 f1 input for distortion | +| distof2 f2 input for distortion | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Vsource - instance parameters (input-output) | +|-----------------------------------------------------------+ +| dc D.C. source value | +| acmag A.C. Magnitude | +| acphase A.C. Phase | + ------------------------------------------------------------ + + + ------------------------------------------------------------ +| Vsource - instance parameters (output-only) | +|-----------------------------------------------------------+ +| pos_node Positive node of source | +| neg_node Negative node of source | +| function Function of the source | +| order Order of the source function | + ------------------------------------------------------------ +| coeffs Coefficients for the function | +| acreal AC real part | +| acimag AC imaginary part | +| i Voltage source current | +| p Instantaneous power | + ------------------------------------------------------------ + +@bye diff --git a/doc/texinfo.tex b/doc/texinfo.tex new file mode 100644 index 000000000..d375c2c09 --- /dev/null +++ b/doc/texinfo.tex @@ -0,0 +1,5951 @@ +% texinfo.tex -- TeX macros to handle Texinfo files. +% +% Load plain if necessary, i.e., if running under initex. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi +% +\def\texinfoversion{1999-07-19.16}% +% +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99 +% Free Software Foundation, Inc. +% +% This texinfo.tex file 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, or (at +% your option) any later version. +% +% This texinfo.tex file 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 texinfo.tex file; see the file COPYING. If not, write +% to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +% Boston, MA 02111-1307, USA. +% +% In other words, you are welcome to use, share and improve this program. +% You are forbidden to forbid anyone else to use, share and improve +% what you give them. Help stamp out software-hoarding! +% +% Please try the latest version of texinfo.tex before submitting bug +% reports; you can get the latest version from: +% ftp://ftp.gnu.org/pub/gnu/texinfo.tex +% (and all GNU mirrors, see http://www.gnu.org/order/ftp.html) +% ftp://tug.org/tex/texinfo.tex +% ftp://ctan.org/macros/texinfo/texinfo.tex +% (and all CTAN mirrors, finger ctan@ctan.org for a list). +% /home/gd/gnu/doc/texinfo.tex on the GNU machines. +% The texinfo.tex in any given Texinfo distribution could well be out +% of date, so if that's what you're using, please check. +% There is a small home page for Texinfo at http://texinfo.org/. +% +% Send bug reports to bug-texinfo@gnu.org. Please include including a +% complete document in each bug report with which we can reproduce the +% problem. Patches are, of course, greatly appreciated. +% +% To process a Texinfo manual with TeX, it's most reliable to use the +% texi2dvi shell script that comes with the distribution. For a simple +% manual foo.texi, however, you can get away with this: +% tex foo.texi +% texindex foo.?? +% tex foo.texi +% tex foo.texi +% dvips foo.dvi -o # or whatever, to process the dvi file; this makes foo.ps. +% The extra runs of TeX get the cross-reference information correct. +% Sometimes one run after texindex suffices, and sometimes you need more +% than two; texi2dvi does it as many times as necessary. +% +% It is possible to adapt texinfo.tex for other languages. You can get +% the existing language-specific files from ftp://ftp.gnu.org/gnu/texinfo/. + +\message{Loading texinfo [version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}% + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv=\equiv +\let\ptexexclam=\! +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t + +% We never want plain's outer \+ definition in Texinfo. +% For @tex, we can use \tabalign. +\let\+ = \relax + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English if not already set. +\ifx\putwordAppendix\undefined \gdef\putwordAppendix{Appendix}\fi +\ifx\putwordChapter\undefined \gdef\putwordChapter{Chapter}\fi +\ifx\putwordfile\undefined \gdef\putwordfile{file}\fi +\ifx\putwordin\undefined \gdef\putwordin{in}\fi +\ifx\putwordIndexIsEmpty\undefined \gdef\putwordIndexIsEmpty{(Index is empty)}\fi +\ifx\putwordIndexNonexistent\undefined \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi +\ifx\putwordInfo\undefined \gdef\putwordInfo{Info}\fi +\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi +\ifx\putwordMethodon\undefined \gdef\putwordMethodon{Method on}\fi +\ifx\putwordNoTitle\undefined \gdef\putwordNoTitle{No Title}\fi +\ifx\putwordof\undefined \gdef\putwordof{of}\fi +\ifx\putwordon\undefined \gdef\putwordon{on}\fi +\ifx\putwordpage\undefined \gdef\putwordpage{page}\fi +\ifx\putwordsection\undefined \gdef\putwordsection{section}\fi +\ifx\putwordSection\undefined \gdef\putwordSection{Section}\fi +\ifx\putwordsee\undefined \gdef\putwordsee{see}\fi +\ifx\putwordSee\undefined \gdef\putwordSee{See}\fi +\ifx\putwordShortTOC\undefined \gdef\putwordShortTOC{Short Contents}\fi +\ifx\putwordTOC\undefined \gdef\putwordTOC{Table of Contents}\fi +% +\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi +\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi +\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi +\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi +\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi +\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi +\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi +\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi +\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi +\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi +\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi +\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi +% +\ifx\putwordDefmac\undefined \gdef\putwordDefmac{Macro}\fi +\ifx\putwordDefspec\undefined \gdef\putwordDefspec{Special Form}\fi +\ifx\putwordDefvar\undefined \gdef\putwordDefvar{Variable}\fi +\ifx\putwordDefopt\undefined \gdef\putwordDefopt{User Option}\fi +\ifx\putwordDeftypevar\undefined\gdef\putwordDeftypevar{Variable}\fi +\ifx\putwordDeffunc\undefined \gdef\putwordDeffunc{Function}\fi +\ifx\putwordDeftypefun\undefined\gdef\putwordDeftypefun{Function}\fi + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} +\hyphenation{white-space} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\ifx\eTeXversion\undefined +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\else +\def\loggingall{\tracingcommands3 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \tracingscantokens1 \tracingassigns1 \tracingifs1 + \tracinggroups1 \tracingnesting2 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% +\fi + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines +\newdimen\cornerlong \cornerlong=1pc +\newdimen\cornerthick \cornerthick=.3pt +\newdimen\topandbottommargin \topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \vskip-\topandbottommargin + \vtop to0pt{% + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vss}% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifpdfmakepagedest \pdfmkdest{\the\pageno} \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \vbox to0pt{\vss + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + }% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment; press RETURN to continue} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Press RETURN to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt\char64}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt\char123}} +\def\myrbrace {{\tt\char125}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @! is an end-of-sentence bang. +\def\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\def\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\nobreak +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output an ellipsis using the current font. +% We do .5em per period so that it has the same spacing in a typewriter +% font as three actual period characters. +% +\def\dots{% + \leavevmode + \hbox to 1.5em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% +} + +% @enddots{} is an end-of-sentence ellipsis. +% +\def\enddots{% + \leavevmode + \hbox to 2em{% + \hskip 0pt plus 0.25fil minus 0.25fil + .\hss.\hss.\hss.% + \hskip 0pt plus 0.5fil minus 0.5fil + }% + \spacefactor=3000 +} + + +% @page forces the start of a new page +% +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\begingroup \catcode`\^^M=\other% +\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other% +\commentxxx} +{\catcode`\^^M=\other \gdef\commentxxx#1^^M{\endgroup}} + +\let\c=\comment + +% @paragraphindent NCHARS +% We'll use ems for NCHARS, close enough. +% We cannot implement @paragraphindent asis, though. +% +\def\asisword{asis} % no translation, these are keywords +\def\noneword{none} +% +\def\paragraphindent{\parsearg\doparagraphindent} +\def\doparagraphindent#1{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \defaultparindent = 0pt + \else + \defaultparindent = #1em + \fi + \fi + \parindent = \defaultparindent +} + +% @exampleindent NCHARS +% We'll use ems for NCHARS like @paragraphindent. +% It seems @exampleindent asis isn't necessary, but +% I preserve it to make it similar to @paragraphindent. +\def\exampleindent{\parsearg\doexampleindent} +\def\doexampleindent#1{% + \def\temp{#1}% + \ifx\temp\asisword + \else + \ifx\temp\noneword + \lispnarrowing = 0pt + \else + \lispnarrowing = #1em + \fi + \fi +} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +% @refill is a no-op. +\let\refill=\relax + +% If working on a large document in chapters, it is convenient to +% be able to disable indexing, cross-referencing, and contents, for test runs. +% This is done with @novalidate (before @setfilename). +% +\newif\iflinks \linkstrue % by default we want the aux files. +\let\novalidate = \linksfalse + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \iflinks + \readauxfile + \fi % \openindices needs to do some work in any case. + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. +} + +% Called from \setfilename. +% +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + + +\message{pdf,} +% adobe `portable' document format +\newcount\tempnum +\newcount\lnkcount +\newtoks\filename +\newcount\filenamelength +\newcount\pgn +\newtoks\toksA +\newtoks\toksB +\newtoks\toksC +\newtoks\toksD +\newbox\boxA +\newcount\countA +\newif\ifpdf +\newif\ifpdfmakepagedest + +\ifx\pdfoutput\undefined + \pdffalse + \let\pdfmkdest = \gobble + \let\pdfurl = \gobble + \let\endlink = \relax + \let\linkcolor = \relax + \let\pdfmakeoutlines = \relax +\else + \pdftrue + \pdfoutput = 1 + \input pdfcolor + \def\dopdfimage#1#2#3#4{ + \def\imagewidth{#2} + \def\imageheight{#3} + \ifnum\pdftexversion < 14 + \pdfimage + \else + \pdfximage + \fi + \ifx\empty\imagewidth\else width \imagewidth \fi + \ifx\empty\imageheight\else height \imageheight \fi + {#1.pdf} + \ifnum\pdftexversion < 14 \else + \pdfrefxform \pdflastxform + \fi} + \def\pdfmkdest#1{\pdfdest name{#1@} xyz} + \def\pdfmkpgn#1{#1@} +% \let\linkcolor = \RoyalBlue + \let\linkcolor = \Cyan + \def\endlink{\Black\pdfendlink} + % Adding outlines to PDF; macros for calculating structure of outlines + % come from Petr Olsak + \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0% + \else \csname#1\endcsname \fi} + \def\advancenumber#1{\tempnum=\expnumber{#1}\relax + \advance\tempnum by1 + \expandafter\xdef\csname#1\endcsname{\the\tempnum}} + \def\pdfmakeoutlines{{% + \openin 1 \jobname.toc + \ifeof 1\else\bgroup + \closein 1 + \indexnofonts + \def\char{char}% because \expnumber uses the section title in a \csname + \def\chapentry ##1##2##3{} + \def\unnumbchapentry ##1##2{} + \def\secentry ##1##2##3##4{\advancenumber{chap##2}} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{\advancenumber{sec##2.##3}} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{\advancenumber{subsec##2.##3.##4}} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \def\chapentry ##1##2##3{% + \pdfoutline goto name{\pdfmkpgn{##3}}count-\expnumber{chap##2}{##1}} + \def\unnumbchapentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \def\secentry ##1##2##3##4{% + \pdfoutline goto name{\pdfmkpgn{##4}}count-\expnumber{sec##2.##3}{##1}} + \def\unnumbsecentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \def\subsecentry ##1##2##3##4##5{% + \pdfoutline goto name{\pdfmkpgn{##5}}count-\expnumber{subsec##2.##3.##4}{##1}} + \def\unnumbsubsecentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \def\subsubsecentry ##1##2##3##4##5##6{% + \pdfoutline goto name{\pdfmkpgn{##6}}{##1}} + \def\unnumbsubsubsecentry ##1##2{% + \pdfoutline goto name{\pdfmkpgn{##2}}{##1}} + \input \jobname.toc + \egroup\fi + }} + \def\makelinks #1,{% + \def\params{#1}\def\E{END}% + \ifx\params\E + \let\nextmakelinks=\relax + \else + \let\nextmakelinks=\makelinks + \ifnum\lnkcount>0,\fi + \picknum{#1}% + \startlink attr{/Border [0 0 0]} + goto name{\pdfmkpgn{\the\pgn}}% + \linkcolor #1% + \advance\lnkcount by 1% + \endlink + \fi + \nextmakelinks + } + \def\picknum#1{\expandafter\pn#1} + \def\pn#1{% + \def\p{#1}% + \ifx\p\lbrace + \let\nextpn=\ppn + \else + \let\nextpn=\ppnn + \def\first{#1} + \fi + \nextpn + } + \def\ppn#1{\pgn=#1\gobble} + \def\ppnn{\pgn=\first} + \def\pdfmklnk#1{\lnkcount=0\makelinks #1,END,} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\skipspaces#1{\def\PP{#1}\def\D{|}% + \ifx\PP\D\let\nextsp\relax + \else\let\nextsp\skipspaces + \ifx\p\space\else\addtokens{\filename}{\PP}% + \advance\filenamelength by 1 + \fi + \fi + \nextsp} + \def\getfilename#1{\filenamelength=0\expandafter\skipspaces#1|\relax} + \ifnum\pdftexversion < 14 + \let \startlink \pdfannotlink + \else + \let \startlink \pdfstartlink + \fi + \def\pdfurl#1{% + \leavevmode\Red + \begingroup + \normalturnoffactive\def\@{@}% + \startlink + attr{/Border [0 0 0]}% + user{/Subtype /Link /A << /S /URI /URI (#1) >>}% + #1 + \endlink + \endgroup} + \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}} + \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks} + \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks} + \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}} + \def\maketoks{% + \expandafter\poptoks\the\toksA|ENDTOKS| + \ifx\first0\adn0 + \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3 + \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6 + \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9 + \else + \ifnum0=\countA\else\makelink\fi + \ifx\first.\let\next=\done\else + \let\next=\maketoks + \addtokens{\toksB}{\the\toksD} + \ifx\first,\addtokens{\toksB}{\space}\fi + \fi + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \next} + \def\makelink{\addtokens{\toksB}% + {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0} + \def\pdflink#1{% + \startlink attr{/Border [0 0 0]} goto name{\mkpgn{#1}} + \linkcolor #1\endlink} + \def\mkpgn#1{#1@} + \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st} +\fi % \ifx\pdfoutput + + +\message{fonts,} +% Font-change commands. + +% Texinfo sort of supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +% Use Computer Modern fonts at \magstephalf (11pt). +\newcount\mainmagstep +\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\ninettsl\ttslshape{10}{900} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\itshape{9}{1000} +\setfont\indsl\slshape{9}{1000} +\let\indtt=\ninett +\let\indttsl=\ninettsl +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts\rm #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Define these so they can be easily changed for other fonts. +\def\angleleft{$\langle$} +\def\angleright{$\rangle$} + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartslanted#1{{\sl #1}\futurelet\next\smartitalicx} +\def\smartitalic#1{{\it #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartslanted +\let\dfn=\smartslanted +\let\emph=\smartitalic +\let\cite=\smartslanted + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp#1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{\angleright}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +% @file, @option are the same as @samp. +\let\file=\samp +\let\option=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ + \catcode`\-=\active + \catcode`\_=\active + % + \global\def\code{\begingroup + \catcode`\-=\active \let-\codedash + \catcode`\_=\active \let_\codeunder + \codex + } + % + % If we end up with any active - characters when handling the index, + % just treat them as a normal -. + \global\def\indexbreaks{\catcode`\-=\active \let-\realdash} +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\def\kbdinputstyle{\parsearg\kbdinputstylexxx} +\def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is kbdinputdistinct. (Too much of a hassle to call the macro, +% the catcodes are wrong for parsearg to work.) +\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% For @url, @env, @command quotes seem unnecessary, so use \code. +\let\url=\code +\let\env=\code +\let\command=\code + +% @uref (abbreviation for `urlref') takes an optional (comma-separated) +% second argument specifying the text to display and an optional third +% arg as text to display instead of (rather than in addition to) the url +% itself. First (mandatory) arg is the url. Perhaps eventually put in +% a hypertex \special here. +% +\def\uref#1{\douref #1,,,\finish} +\def\douref#1,#2,#3,#4\finish{% + \pdfurl{#1}% + \setbox0 = \hbox{\ignorespaces #3}% + \ifdim\wd0 > 0pt + \unhbox0 % third arg given, show only that + \else + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \ifpdf + \unhbox0 % PDF: 2nd arg given, show only it + \else + \unhbox0\ (\code{#1})% DVI: 2nd arg given, show both it and url + \fi + \else + \code{#1}% only url given, so show it + \fi + \fi + % + \endlink +} + +% rms does not like angle brackets --karl, 17may97. +% So now @email is just like @uref, unless we are pdf. +% +%\def\email#1{\angleleft{\tt #1}\angleright} +\ifpdf + \def\email#1{\doemail#1,,\finish} + \def\doemail#1,#2,#3\finish{% + \pdfurl{mailto:#1}% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi + \endlink + } +\else + \let\email=\uref +\fi + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +% Explicit font changes: @r, @sc, undocumented @ii. +\def\r#1{{\rm #1}} % roman font +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @acronym downcases the argument and prints in smallcaps. +\def\acronym#1{{\smallcaps \lowercase{#1}}} + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +% Do an implicit @contents or @shortcontents after @end titlepage if the +% user says @setcontentsaftertitlepage or @setshortcontentsaftertitlepage. +% +\newif\ifsetcontentsaftertitlepage + \let\setcontentsaftertitlepage = \setcontentsaftertitlepagetrue +\newif\ifsetshortcontentsaftertitlepage + \let\setshortcontentsaftertitlepage = \setshortcontentsaftertitlepagetrue + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + % + % If they want short, they certainly want long too. + \ifsetshortcontentsaftertitlepage + \shortcontents + \contents + \global\let\shortcontents = \relax + \global\let\contents = \relax + \fi + % + \ifsetcontentsaftertitlepage + \contents + \global\let\contents = \relax + \global\let\shortcontents = \relax + \fi + % + \ifpdf \pdfmakepagedesttrue \fi + % + \HEADINGSon +} + +\def\finishtitlepage{% + \message{FINISH TITLE} + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks\evenheadline % headline on even pages +\newtoks\oddheadline % headline on odd pages +\newtoks\evenfootline % footline on even pages +\newtoks\oddfootline % footline on odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{% + \number\day\space + \ifcase\month + \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr + \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug + \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec + \fi + \space\number\year} + +% @settitle line... specifies the title of the document, for headings. +% It generates no output of its own. +\def\thistitle{\putwordNoTitle} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. + \noindent + % Do this with kerns and \unhbox so that if there is a footnote in + % the item text, it can migrate to the main vertical list and + % eventually be printed. + \nobreak\kern-\tableindent + \dimen0 = \itemmax \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0 + \unhbox0 + \nobreak\kern\dimen0 + \endgroup + \itemxneedsnegativevskiptrue + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +% Contains a kludge to get @end[description] to work. +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +% @table, @ftable, @vtable. +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a . + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{In hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. +% +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +% Macros used to set up halign preamble: +% +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +% #1 is the part of the @columnfraction before the decimal point, which +% is presumably either 0 or the empty string (but we don't check, we +% just throw it away). #2 is the decimal part, which we use as the +% percent of \hsize for this column. +\def\pickupwholefraction#1.#2 {% + \global\advance\colcount by 1 + \expandafter\xdef\csname col\the\colcount\endcsname{.#2\hsize}% + \setuptable +} + +\newcount\colcount +\def\setuptable#1{% + \def\firstarg{#1}% + \ifx\firstarg\xendsetuptable + \let\go = \relax + \else + \ifx\firstarg\xcolumnfractions + \global\setpercenttrue + \else + \ifsetpercent + \let\go\pickupwholefraction + \else + \global\advance\colcount by 1 + \setbox0=\hbox{#1\unskip }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi + \fi + \ifx\go\pickupwholefraction + % Put the argument back for the \pickupwholefraction call, so + % we'll always have a period there to be parsed. + \def\go{\pickupwholefraction#1}% + \else + \let\go = \setuptable + \fi% + \fi + \go +} + +% This used to have \hskip1sp. But then the space in a template line is +% not enough. That is bad. So let's go back to just & until we +% encounter the problem it was intended to solve again. +% --karl, nathan@acm.org, 20apr99. +\def\tab{&} + +% @multitable ... @end multitable definitions: +% +\def\multitable{\parsearg\dotable} +\def\dotable#1{\bgroup + \vskip\parskip + \let\item\crcr + \tolerance=9500 + \hbadness=9500 + \setmultitablespacing + \parskip=\multitableparskip + \parindent=\multitableparindent + \overfullrule=0pt + \global\colcount=0 + \def\Emultitable{\global\setpercentfalse\cr\egroup\egroup}% + % + % To parse everything between @multitable and @item: + \setuptable#1 \endsetuptable + % + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. + \everycr{\noalign{% + % + % \filbreak%% keeps underfull box messages off when table breaks over pages. + % Maybe so, but it also creates really weird page breaks when the table + % breaks over pages. Wouldn't \vfil be better? Wait until the problem + % manifests itself, so it can be fixed for real --karl. + \global\colcount=0\relax}}% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. + \halign\bgroup&\global\advance\colcount by 1\relax + \multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % + % If the user has set preamble in terms of percent of \hsize we will + % use that dimension as the width of the column, and the \leftskip + % will keep entries from bumping into each other. Table will start at + % left margin and final column will justify at right margin. + % + % Make sure we don't inherit \rightskip from the outer environment. + \rightskip=0pt + \ifnum\colcount=1 + % The first column will be indented with the surrounding text. + \advance\hsize by\leftskip + \else + \ifsetpercent \else + % If user has not set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace. + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: + \leftskip=\multitablecolspace + \fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{conditionals,} +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% + \let\chapter=\relax + \let\unnumbered=\relax + \let\top=\relax + \let\unnumberedsec=\relax + \let\unnumberedsection=\relax + \let\unnumberedsubsec=\relax + \let\unnumberedsubsection=\relax + \let\unnumberedsubsubsec=\relax + \let\unnumberedsubsubsection=\relax + \let\section=\relax + \let\subsec=\relax + \let\subsubsec=\relax + \let\subsection=\relax + \let\subsubsection=\relax + \let\appendix=\relax + \let\appendixsec=\relax + \let\appendixsection=\relax + \let\appendixsubsec=\relax + \let\appendixsubsection=\relax + \let\appendixsubsubsec=\relax + \let\appendixsubsubsection=\relax + \let\contents=\relax + \let\smallbook=\relax + \let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypeivar = \relax + \let\deftypeop = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifnottex{\doignore{ifnottex}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + % This @ is a catcode 12 token (that is the normal catcode of @ in + % this texinfo.tex file). We change the catcode of @ below to match. + \long\def\doignoretext##1@end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % We must not have @c interpreted as a control sequence. + \catcode`\@ = 12 + % + % Make the letter c a comment character so that the rest of the line + % will be ignored. This way, the document can have (for example) + % @c @end ifinfo + % and the @end ifinfo will be properly ignored. + % (We've just changed @ to catcode 12.) + \catcode`\c = 14 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{WARNING: for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.org/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% + % Do not execute macro definitions. + % `c' is a comment character, so the word `macro' will get cut off. + \def\macro{\doignore{ma}}% +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +{ + \catcode`\_ = \active + % + % We might end up with active _ or - characters in the argument if + % we're called from @code, as @code{@value{foo-bar_}}. So \let any + % such active characters to their normal equivalents. + \gdef\value{\begingroup + \catcode`\-=12 \catcode`\_=12 + \indexbreaks \let_\normalunderscore + \valuexxx} +} +\def\valuexxx#1{\expandablevalue{#1}\endgroup} + +% We have this subroutine so that we can handle at least some @value's +% properly in indexes (we \let\value to this in \indexdummies). Ones +% whose names contain - or _ still won't work, but we can't do anything +% about that. The command has to be fully expandable, since the result +% winds up in the index file. This means that if the variable's value +% contains other Texinfo commands, it's almost certain it will fail +% (although perhaps we could fix that with sufficient work to do a +% one-level expansion on the result, instead of complete). +% +\def\expandablevalue#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {[No value for ``#1'']}% + \else + \csname SET#1\endcsname + \fi +} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text +% following, through the first @end iftex (etc.). Make `@end iftex' +% (etc.) valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\def\ifnothtml{\conditionalsucceed{ifnothtml}} +\def\ifnotinfo{\conditionalsucceed{ifnotinfo}} +\defineunmatchedend{iftex} +\defineunmatchedend{ifnothtml} +\defineunmatchedend{ifnotinfo} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @defininfoenclose. +\let\definfoenclose=\comment + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. +% +\def\newindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 % Open the file + \fi + \expandafter\xdef\csname#1index\endcsname{% % Define @#1index + \noexpand\doindex{#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex#1{% + \iflinks + \expandafter\newwrite \csname#1indfile\endcsname + \openout \csname#1indfile\endcsname \jobname.#1 + \fi + \expandafter\xdef\csname#1index\endcsname{% + \noexpand\docodeindex{#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +% The \closeout helps reduce unnecessary open files; the limit on the +% Acorn RISC OS is a mere 16 files. +\def\synindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\doindex{#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex#1 #2 {% + \expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname + \expandafter\closeout\csname#1indfile\endcsname + \expandafter\let\csname#1indfile\endcsname=\synindexfoo + \expandafter\xdef\csname#1index\endcsname{% define \xxxindex + \noexpand\docodeindex{#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +\def\ { }% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +% Need these in case \tex is in effect and \{ is a \delimiter again. +% But can't use \lbracecmd and \rbracecmd because texindex assumes +% braces and backslashes are used only as delimiters. +\let\{ = \mylbrace +\let\} = \myrbrace +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\result{\realbackslash result}% +\def\equiv{\realbackslash equiv}% +\def\expansion{\realbackslash expansion}% +\def\print{\realbackslash print}% +\def\error{\realbackslash error}% +\def\point{\realbackslash point}% +\def\copyright{\realbackslash copyright}% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\uref##1{\realbackslash uref {##1}}% +\def\url##1{\realbackslash url {##1}}% +\def\env##1{\realbackslash env {##1}}% +\def\command##1{\realbackslash command {##1}}% +\def\option##1{\realbackslash option {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\sc##1{\realbackslash sc {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\def\acronym##1{\realbackslash acronym {##1}}% +% +% Handle some cases of @value -- where the variable name does not +% contain - or _, and the value does not contain any +% (non-fully-expandable) commands. +\let\value = \expandablevalue +% +\unsepspaces +% Turn off macro expansion +\turnoffmacros +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\url=\indexdummyfont +\let\uref=\indexdummyfont +\let\env=\indexdummyfont +\let\command=\indexdummyfont +\let\option=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other + @gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. +\let\SETmarginindex=\relax % put index entries in margin (undocumented)? + +% For \ifx comparisons. +\def\emptymacro{\empty} + +% Most index entries go through here, but \dosubind is the general case. +% +\def\doind#1#2{\dosubind{#1}{#2}\empty} + +% Workhorse for all \fooindexes. +% #1 is name of index, #2 is stuff to put there, #3 is subentry -- +% \empty if called from \doind, as we usually are. The main exception +% is with defuns, which call us directly. +% +\def\dosubind#1#2#3{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio = 0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + \def\thirdarg{#3}% + % + % If third arg is present, precede it with space in sort key. + \ifx\thirdarg\emptymacro + \let\subentry = \empty + \else + \def\subentry{ #3}% + \fi + % + % First process the index entry with all font commands turned + % off to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2\subentry}}% + % + % Now the real index entry with the fonts. + \toks0 = {#2}% + % + % If third (subentry) arg is present, add it to the index + % string. And include a space. + \ifx\thirdarg\emptymacro \else + \toks0 = \expandafter{\the\toks0 \space #3}% + \fi + % + % Set up the complete index entry, with both the sort key + % and the original text, including any font commands. We write + % three arguments to \entry to the .?? file, texindex reduces to + % two when writing the .??s sorted result. + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + % + % If a skip is the last thing on the list now, preserve it + % by backing up by \lastskip, doing the \write, then inserting + % the skip again. Otherwise, the whatsit generated by the + % \write will make \lastskip zero. The result is that sequences + % like this: + % @end defun + % @tindex whatever + % @defun ... + % will have extra space inserted, because the \medbreak in the + % start of the @defun won't see the skip inserted by the @end of + % the previous defun. + % + % But don't do any of this if we're not in vertical mode. We + % don't want to do a \vskip and prematurely end a paragraph. + % + % Avoid page breaks due to these extra skips, too. + % + \iflinks + \ifvmode + \skip0 = \lastskip + \ifdim\lastskip = 0pt \else \nobreak\vskip-\lastskip \fi + \fi + % + \temp % do the write + % + % + \ifvmode \ifdim\skip0 = 0pt \else \nobreak\vskip\skip0 \fi \fi + \fi + }% + }% + \penalty\count255 + }% +} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\def\printindex{\parsearg\doprintindex} +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + % Change catcode of @ here so that if the index file contains + % \initial {@} + % as its first line, TeX doesn't complain about mismatched braces + % (because it thinks @} is a control sequence). + \catcode`\@ = 11 + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + \putwordIndexNonexistent + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + \putwordIndexIsEmpty + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +\def\initial#1{{% + % Some minor font changes for the special characters. + \let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt + % + % Remove any glue we may have, we'll be inserting our own. + \removelastskip + % + % We like breaks before the index initials, so insert a bonus. + \penalty -300 + % + % Typeset the initial. Making this add up to a whole number of + % baselineskips increases the chance of the dots lining up from column + % to column. It still won't often be perfect, because of the stretch + % we need before each entry, but it's better. + % + % No shrink because it confuses \balancecolumns. + \vskip 1.67\baselineskip plus .5\baselineskip + \leftline{\secbf #1}% + \vskip .33\baselineskip plus .1\baselineskip + % + % Do our best not to break after the initial. + \nobreak +}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry#1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent = 2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % A bit of stretch before each entry for the benefit of balancing columns. + \vskip 0pt plus1pt + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ifpdf + \pdfgettoks#2.\ \the\toksA % The page number ends the paragraph. + \else + \ #2% The page number ends the paragraph. + \fi + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case we just ship out what is in \partialpage with the normal + % output routine. Generally, \partialpage will be empty when this + % runs and this will be a no-op. See the indexspread.tex test case. + \ifvoid\partialpage \else + \onepageout{\pagecontents\partialpage}% + \fi + % + \global\setbox\partialpage = \vbox{% + % Unvbox the main output page. + \unvbox\PAGE + \kern-\topskip \kern\baselineskip + }% + }% + \eject % run that output routine to set \partialpage + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \advance\vsize by -\ht\partialpage + \vsize = 2\vsize +} + +% The double-column output routine for all double-column pages except +% the last. +% +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@ = \vsize + \divide\dimen@ by 2 + % + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +\def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split, in box0 and box2. + \unvbox\partialpage + % + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize + \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output = {% + % Split the last of the double-column material. Leave it on the + % current page, no automatic page break. + \balancecolumns + % + % If we end up splitting too much material for the current page, + % though, there will be another page break right after this \output + % invocation ends. Having called \balancecolumns once, we do not + % want to call it again. Therefore, reset \output to its normal + % definition right away. (We hope \balancecolumns will never be + % called on to balance too much material, but if it is, this makes + % the output somewhat more palatable.) + \global\output = {\onepageout{\pagecontents\PAGE}}% + }% + \eject + \endgroup % started in \begindoublecolumns + % + % \pagegoal was set to the doubled \vsize above, since we restarted + % the current page. We're now back to normal single-column + % typesetting, so reset \pagegoal to the normal \vsize (after the + % \endgroup where \vsize got restored). + \pagegoal = \vsize +} +\def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% like \box255 but more efficient, see p.120. + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 % target to split to + %debug\message{final 2-column material height=\the\ht0, target=\the\dimen@.}% + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {% + \vbadness = 10000 + \loop + \global\setbox3 = \copy0 + \global\setbox1 = \vsplit3 to \dimen@ + \ifdim\ht3>\dimen@ + \global\advance\dimen@ by 1pt + \repeat + }% + %debug\message{split to \the\dimen@, column heights: \the\ht1, \the\ht3.}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + % + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Chapters, sections, etc. + +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +% The \the is necessary, despite appearances, because \appendixletter is +% expanded while writing the .toc file. \char\appendixno is not +% expandable, thus it is written literally, thus all appendixes come out +% with the same letter (or @) in the toc without it. +\newcount\appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise. +\def\thischapter{} +\def\thissection{} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + +% @chapter, @appendix, @unnumbered. +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter\space \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\the\chapno}}}% +\temp +\donoderef +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 +\message{\putwordAppendix\space \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}}}% +\temp +\appendixnoderef +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +% @top is like @unnumbered. +\outer\def\top{\parsearg\unnumberedyyy} + +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the to achieve this: TeX expands \the only once, +% simply yielding the contents of . (We also do this for +% the toc entries.) +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbchapentry{\the\toks0}}}% +\temp +\unnumbnoderef +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +} + +% Sections. +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\the\chapno}{\the\secno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash secentry{\the\toks0}% + {\appendixletter}{\the\secno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{% +\plainsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsecentry{\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsections. +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{% +\plainsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% Subsubsections. +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\donoderef +\nobreak +} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}}}% +\temp +\appendixnoderef +\nobreak +} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +\toks0 = {#1}% +\edef\temp{\noexpand\writetocentry{\realbackslash unnumbsubsubsecentry% + {\the\toks0}}}% +\temp +\unnumbnoderef +\nobreak +} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{% +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\nobreak +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\nobreak +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc,} +% Table of contents. +\newwrite\tocfile + +% Write an entry to the toc file, opening it if necessary. +% Called from @chapter, etc. We supply {\folio} at the end of the +% argument, which will end up as the last argument to the \...entry macro. +% +% We open the .toc file here instead of at @setfilename or any other +% given time so that @contents can be put in the document anywhere. +% +\newif\iftocfileopened +\def\writetocentry#1{% + \iftocfileopened\else + \immediate\openout\tocfile = \jobname.toc + \global\tocfileopenedtrue + \fi + \iflinks \write\tocfile{#1{\folio}}\fi +} + +\newskip\contentsrightmargin \contentsrightmargin=1in +\newcount\savepageno +\newcount\lastnegativepageno \lastnegativepageno = -1 + +% Finish up the main text and prepare to read what we've written +% to \tocfile. +% +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund + \contentsalignmacro + \immediate\closeout\tocfile + % + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \savepageno = \pageno + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. + % + % Roman numerals for page numbers. + \ifnum \pageno>0 \pageno = \lastnegativepageno \fi +} + + +% Normal (long) toc. +\def\contents{% + \startcontents{\putwordTOC}% + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \pdfmakeoutlines + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} + +% And just the chapters. +\def\summarycontents{% + \startcontents{\putwordShortTOC}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \openin 1 \jobname.toc + \ifeof 1 \else + \closein 1 + \input \jobname.toc + \fi + \vfill \eject + \contentsalignmacro % in case @setchapternewpage odd is in effect + \endgroup + \lastnegativepageno = \pageno + \pageno = \savepageno +} +\let\shortcontents = \summarycontents + +\ifpdf + \pdfcatalog{/PageMode /UseOutlines}% +\fi + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#3\egroup}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno\bgroup#2\egroup}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno\bgroup#2\egroup}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno\bgroup#2\egroup}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + % Do not use \turnoffactive in these arguments. Since the toc is + % typeset in cmr, so characters such as _ would come out wrong; we + % have to do the usual translation tricks. + \entry{#1}{#2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} +% @foo ... @end foo. + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup + \catcode `\\=0 \catcode `\{=1 \catcode `\}=2 + \catcode `\$=3 \catcode `\&=4 \catcode `\#=6 + \catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie + \catcode `\%=14 + \catcode 43=12 % plus + \catcode`\"=12 + \catcode`\==12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \escapechar=`\\ + % + \let\b=\ptexb + \let\bullet=\ptexbullet + \let\c=\ptexc + \let\,=\ptexcomma + \let\.=\ptexdot + \let\dots=\ptexdots + \let\equiv=\ptexequiv + \let\!=\ptexexclam + \let\i=\ptexi + \let\{=\ptexlbrace + \let\+=\tabalign + \let\}=\ptexrbrace + \let\*=\ptexstar + \let\t=\ptext + % + \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% + \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% + \def\@{@}% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +% @cartouche ... @end cartouche: draw rectangle w/rounded corners around +% environment contents. +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18.4pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char, and rule thickness + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% Define the \E... control sequence only if we are inside the particular +% environment, so the error checking in \end will work. +% +% To end an @example-like environment, we first end the paragraph (via +% \afterenvbreak's vertical glue), and then the group. That way we keep +% the zero \parskip that the environments set -- \parskip glue will be +% inserted at the beginning of the next paragraph in the document, after +% the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup} + +% @lisp: indented, narrowed, typewriter font. +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special. + \gobble % eat return +} + +% @example: Same as @lisp. +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} + +% @small... is usually equivalent to the non-small (@smallbook +% redefines). We must call \example (or whatever) last in the +% definition, since it reads the return following the @example (or +% whatever) command. +% +% This actually allows (for example) @end display inside an +% @smalldisplay. Too bad, but makeinfo will catch the error anyway. +% +\def\smalldisplay{\begingroup\def\Esmalldisplay{\nonfillfinish\endgroup}\display} +\def\smallexample{\begingroup\def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smallformat{\begingroup\def\Esmallformat{\nonfillfinish\endgroup}\format} +\def\smalllisp{\begingroup\def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% Real @smallexample and @smalllisp (when @smallbook): use smaller fonts. +% Originally contributed by Pavel@xerox. +\def\smalllispx{\begingroup + \def\Esmalllisp{\nonfillfinish\endgroup}% + \def\Esmallexample{\nonfillfinish\endgroup}% + \indexfonts + \lisp +} + +% @display: same as @lisp except keep current font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% @smalldisplay (when @smallbook): @display plus smaller fonts. +% +\def\smalldisplayx{\begingroup + \def\Esmalldisplay{\nonfillfinish\endgroup}% + \indexfonts \rm + \display +} + +% @format: same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @smallformat (when @smallbook): @format plus smaller fonts. +% +\def\smallformatx{\begingroup + \def\Esmallformat{\nonfillfinish\endgroup}% + \indexfonts \rm + \format +} + +% @flushleft (same as @format). +% +\def\flushleft{\begingroup \def\Eflushleft{\nonfillfinish\endgroup}\format} + +% @flushright. +% +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble +} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + + +\message{defuns,} +% @defun etc. + +% Allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 +} +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } +\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } +\let\ampnr = \& +\def\lbrb{{\bf\char`\[}} +\def\rbrb{{\bf\char`\]}} + +% Active &'s sneak into the index arguments, so make sure it's defined. +{ + \catcode`& = 13 + \global\let& = \ampnr +} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\noindent +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 +\rlap{\rightline{{\rm #2}\hskip -1.25pc }}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by the space, is the class name. +% +\def\defmethparsebody#1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +% Used for @deftypemethod and @deftypeivar. +% #1 is the \E... control sequence to end the definition (which we define). +% #2 is the \...x control sequence for consecutive fns (which we define). +% #3 is the control sequence to call to resume processing. +% #4, delimited by a space, is the class name. +% #5 is the method's return type. +% +\def\deftypemethparsebody#1#2#3#4 #5 {\begingroup\inENV + \medbreak + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 ##2 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}{##2}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\activeparens\spacesplit{#3{#4}{#5}}} + +% Used for @deftypeop. The change from \deftypemethparsebody is an +% extra argument at the beginning which is the `category', instead of it +% being the hardwired string `Method' or `Instance Variable'. We have +% to account for this both in the \...x definition and in parsing the +% input at hand. Thus also need a control sequence (passed as #5) for +% the \E... definition to assign the category name to. +% +\def\deftypeopparsebody#1#2#3#4#5 #6 {\begingroup\inENV + \medbreak + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 ##2 ##3 {% + \def#4{##1}% + \begingroup\obeylines\activeparens\spacesplit{#3{##2}{##3}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines\activeparens\spacesplit{#3{#5}{#6}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does. +% +\def\removeemptybraces\empty#1\relax{#1} + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs#1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Set the font temporarily and use \font in case \setfont made \tensl a macro. +{\tensl\hyphenchar\font=0}% +#1% +{\tensl\hyphenchar\font=45}% +\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\nobreak\vskip -\parskip\nobreak +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDeffunc}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypefun}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefmac}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{\putwordDefspec}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defop CATEGORY CLASS OPERATION ARG... +% +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} +% +\def\defopheader#1#2#3{% +\dosubind {fn}{\code{#2}}{\putwordon\ #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype\ \putwordon\ #1}% +\defunargs {#3}\endgroup % +} + +% @deftypeop CATEGORY CLASS TYPE OPERATION ARG... +% +\def\deftypeop #1 {\def\deftypeopcategory{#1}% + \deftypeopparsebody\Edeftypeop\deftypeopx\deftypeopheader + \deftypeopcategory} +% +% #1 is the class name, #2 the data type, #3 the operation name, #4 the args. +\def\deftypeopheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3} + {\deftypeopcategory\ \putwordon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup +} + +% @deftypemethod CLASS TYPE METHOD ARG... +% +\def\deftypemethod{% + \deftypemethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} +% +% #1 is the class name, #2 the data type, #3 the method name, #4 the args. +\def\deftypemethodheader#1#2#3#4{% + \dosubind{fn}{\code{#3}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{\defheaderxcond#2\relax$$$#3}{\putwordMethodon\ \code{#1}}% + \deftypefunargs{#4}% + \endgroup +} + +% @deftypeivar CLASS TYPE VARNAME +% +\def\deftypeivar{% + \deftypemethparsebody\Edeftypeivar\deftypeivarx\deftypeivarheader} +% +% #1 is the class name, #2 the data type, #3 the variable name. +\def\deftypeivarheader#1#2#3{% + \dosubind{vr}{\code{#3}}{\putwordof\ \code{#1}}% entry in variable index + \begingroup + \defname{#3}{\putwordInstanceVariableof\ \code{#1}}% + \defvarargs{#3}% + \endgroup +} + +% @defmethod == @defop Method +% +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} +% +% #1 is the class name, #2 the method name, #3 the args. +\def\defmethodheader#1#2#3{% + \dosubind{fn}{\code{#2}}{\putwordon\ \code{#1}}% entry in function index + \begingroup + \defname{#2}{\putwordMethodon\ \code{#1}}% + \defunargs{#3}% + \endgroup +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{\putwordof\ #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype\ \putwordof\ #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar CLASS VARNAME == @defcv {Instance Variable} CLASS VARNAME +% +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} +% +\def\defivarheader#1#2#3{% + \dosubind {vr}{\code{#2}}{\putwordof\ #1}% entry in var index + \begingroup + \defname{#2}{\putwordInstanceVariableof\ #1}% + \defvarargs{#3}% + \endgroup +} + +% @defvar +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefvar}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{\putwordDefopt}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name, perhaps followed by text that +% is actually part of the data type, which should not be put into the index. +\def\deftypevarheader #1#2{% +\dovarind#2 \relax% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{\putwordDeftypevar}% +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} +\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\dovarind#3 \relax% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\nobreak\vskip -\parskip\nobreak +\endgroup} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% These definitions are used if you use @defunx (etc.) +% anywhere other than immediately after a @defun or @defunx. +% +\def\defcvx#1 {\errmessage{@defcvx in invalid context}} +\def\deffnx#1 {\errmessage{@deffnx in invalid context}} +\def\defivarx#1 {\errmessage{@defivarx in invalid context}} +\def\defmacx#1 {\errmessage{@defmacx in invalid context}} +\def\defmethodx#1 {\errmessage{@defmethodx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\defopx#1 {\errmessage{@defopx in invalid context}} +\def\defspecx#1 {\errmessage{@defspecx in invalid context}} +\def\deftpx#1 {\errmessage{@deftpx in invalid context}} +\def\deftypefnx#1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypefunx#1 {\errmessage{@deftypefunx in invalid context}} +\def\deftypeivarx#1 {\errmessage{@deftypeivarx in invalid context}} +\def\deftypemethodx#1 {\errmessage{@deftypemethodx in invalid context}} +\def\deftypeopx#1 {\errmessage{@deftypeopx in invalid context}} +\def\deftypevarx#1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx#1 {\errmessage{@deftypevrx in invalid context}} +\def\defunx#1 {\errmessage{@defunx in invalid context}} +\def\defvarx#1 {\errmessage{@defvarx in invalid context}} +\def\defvrx#1 {\errmessage{@defvrx in invalid context}} + + +\message{macros,} +% @macro. + +% To do this right we need a feature of e-TeX, \scantokens, +% which we arrange to emulate with a temporary file in ordinary TeX. +\ifx\eTeXversion\undefined + \newwrite\macscribble + \def\scanmacro#1{% + \begingroup \newlinechar`\^^M + % Undo catcode changes of \startcontents and \doprintindex + \catcode`\@=0 \catcode`\\=12 \escapechar=`\@ + % Append \endinput to make sure that TeX does not see the ending newline. + \toks0={#1\endinput}% + \immediate\openout\macscribble=\jobname.tmp + \immediate\write\macscribble{\the\toks0}% + \immediate\closeout\macscribble + \let\xeatspaces\eatspaces + \input \jobname.tmp + \endgroup +} +\else +\def\scanmacro#1{% +\begingroup \newlinechar`\^^M +% Undo catcode changes of \startcontents and \doprintindex +\catcode`\@=0 \catcode`\\=12 \escapechar=`\@ +\let\xeatspaces\eatspaces\scantokens{#1\endinput}\endgroup} +\fi + +\newcount\paramno % Count of parameters +\newtoks\macname % Macro name +\newif\ifrecursive % Is it recursive? +\def\macrolist{} % List of all defined macros in the form + % \do\macro1\do\macro2... + +% Utility routines. +% Thisdoes \let #1 = #2, except with \csnames. +\def\cslet#1#2{% +\expandafter\expandafter +\expandafter\let +\expandafter\expandafter +\csname#1\endcsname +\csname#2\endcsname} + +% Trim leading and trailing spaces off a string. +% Concepts from aro-bend problem 15 (see CTAN). +{\catcode`\@=11 +\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }} +\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\gdef\trim@@@ #1 } #2@{#1} +} + +% Trim a single trailing ^^M off a string. +{\catcode`\^^M=12\catcode`\Q=3% +\gdef\eatcr #1{\eatcra #1Q^^MQ}% +\gdef\eatcra#1^^MQ{\eatcrb#1Q}% +\gdef\eatcrb#1Q#2Q{#1}% +} + +% Macro bodies are absorbed as an argument in a context where +% all characters are catcode 10, 11 or 12, except \ which is active +% (as in normal texinfo). It is necessary to change the definition of \. + +% It's necessary to have hard CRs when the macro is executed. This is +% done by making ^^M (\endlinechar) catcode 12 when reading the macro +% body, and then making it the \newlinechar in \scanmacro. + +\def\macrobodyctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\{=12 + \catcode`\}=12 + \catcode`\@=12 + \catcode`\^^M=12 + \usembodybackslash} + +\def\macroargctxt{% + \catcode`\~=12 + \catcode`\^=12 + \catcode`\_=12 + \catcode`\|=12 + \catcode`\<=12 + \catcode`\>=12 + \catcode`\+=12 + \catcode`\@=12 + \catcode`\\=12} + +% \mbodybackslash is the definition of \ in @macro bodies. +% It maps \foo\ => \csname macarg.foo\endcsname => #N +% where N is the macro parameter number. +% We define \csname macarg.\endcsname to be \realbackslash, so +% \\ in macro replacement text gets you a backslash. + +{\catcode`@=0 @catcode`@\=@active + @gdef@usembodybackslash{@let\=@mbodybackslash} + @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname} +} +\expandafter\def\csname macarg.\endcsname{\realbackslash} + +\def\macro{\recursivefalse\parsearg\macroxxx} +\def\rmacro{\recursivetrue\parsearg\macroxxx} + +\def\macroxxx#1{% + \getargs{#1}% now \macname is the macname and \argl the arglist + \ifx\argl\empty % no arguments + \paramno=0% + \else + \expandafter\parsemargdef \argl;% + \fi + \if1\csname ismacro.\the\macname\endcsname + \message{Warning: redefining \the\macname}% + \else + \expandafter\ifx\csname \the\macname\endcsname \relax + \else \errmessage{The name \the\macname\space is reserved}\fi + \global\cslet{macsave.\the\macname}{\the\macname}% + \global\expandafter\let\csname ismacro.\the\macname\endcsname=1% + % Add the macroname to \macrolist + \toks0 = \expandafter{\macrolist\do}% + \xdef\macrolist{\the\toks0 + \expandafter\noexpand\csname\the\macname\endcsname}% + \fi + \begingroup \macrobodyctxt + \ifrecursive \expandafter\parsermacbody + \else \expandafter\parsemacbody + \fi} + +\def\unmacro{\parsearg\unmacroxxx} +\def\unmacroxxx#1{% + \if1\csname ismacro.#1\endcsname + \global\cslet{#1}{macsave.#1}% + \global\expandafter\let \csname ismacro.#1\endcsname=0% + % Remove the macro name from \macrolist + \begingroup + \edef\tempa{\expandafter\noexpand\csname#1\endcsname}% + \def\do##1{% + \def\tempb{##1}% + \ifx\tempa\tempb + % remove this + \else + \toks0 = \expandafter{\newmacrolist\do}% + \edef\newmacrolist{\the\toks0\expandafter\noexpand\tempa}% + \fi}% + \def\newmacrolist{}% + % Execute macro list to define \newmacrolist + \macrolist + \global\let\macrolist\newmacrolist + \endgroup + \else + \errmessage{Macro #1 not defined}% + \fi +} + +% This makes use of the obscure feature that if the last token of a +% is #, then the preceding argument is delimited by +% an opening brace, and that opening brace is not consumed. +\def\getargs#1{\getargsxxx#1{}} +\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs} +\def\getmacname #1 #2\relax{\macname={#1}} +\def\getmacargs#1{\def\argl{#1}} + +% Parse the optional {params} list. Set up \paramno and \paramlist +% so \defmacro knows what to do. Define \macarg.blah for each blah +% in the params list, to be ##N where N is the position in that list. +% That gets used by \mbodybackslash (above). + +% We need to get `macro parameter char #' into several definitions. +% The technique used is stolen from LaTeX: let \hash be something +% unexpandable, insert that wherever you need a #, and then redefine +% it to # just before using the token list produced. +% +% The same technique is used to protect \eatspaces till just before +% the macro is used. + +\def\parsemargdef#1;{\paramno=0\def\paramlist{}% + \let\hash\relax\let\xeatspaces\relax\parsemargdefxxx#1,;,} +\def\parsemargdefxxx#1,{% + \if#1;\let\next=\relax + \else \let\next=\parsemargdefxxx + \advance\paramno by 1% + \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname + {\xeatspaces{\hash\the\paramno}}% + \edef\paramlist{\paramlist\hash\the\paramno,}% + \fi\next} + +% These two commands read recursive and nonrecursive macro bodies. +% (They're different since rec and nonrec macros end differently.) + +\long\def\parsemacbody#1@end macro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% +\long\def\parsermacbody#1@end rmacro% +{\xdef\temp{\eatcr{#1}}\endgroup\defmacro}% + +% This defines the macro itself. There are six cases: recursive and +% nonrecursive macros of zero, one, and many arguments. +% Much magic with \expandafter here. +% \xdef is used so that macro definitions will survive the file +% they're defined in; @include reads the file inside a group. +\def\defmacro{% + \let\hash=##% convert placeholders to macro parameter chars + \ifrecursive + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\scanmacro{\temp}}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup\noexpand\scanmacro{\temp}}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{\egroup\noexpand\scanmacro{\temp}}% + \fi + \else + \ifcase\paramno + % 0 + \expandafter\xdef\csname\the\macname\endcsname{% + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \or % 1 + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \noexpand\braceorline + \expandafter\noexpand\csname\the\macname xxx\endcsname}% + \expandafter\xdef\csname\the\macname xxx\endcsname##1{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \else % many + \expandafter\xdef\csname\the\macname\endcsname{% + \bgroup\noexpand\macroargctxt + \expandafter\noexpand\csname\the\macname xx\endcsname}% + \expandafter\xdef\csname\the\macname xx\endcsname##1{% + \expandafter\noexpand\csname\the\macname xxx\endcsname ##1,}% + \expandafter\expandafter + \expandafter\xdef + \expandafter\expandafter + \csname\the\macname xxx\endcsname + \paramlist{% + \egroup + \noexpand\norecurse{\the\macname}% + \noexpand\scanmacro{\temp}\egroup}% + \fi + \fi} + +\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}} + +% \braceorline decides whether the next nonwhitespace character is a +% {. If so it reads up to the closing }, if not, it reads the whole +% line. Whatever was read is then fed to the next control sequence +% as an argument (by \parsebrace or \parsearg) +\def\braceorline#1{\let\next=#1\futurelet\nchar\braceorlinexxx} +\def\braceorlinexxx{% + \ifx\nchar\bgroup\else + \expandafter\parsearg + \fi \next} + +% We mant to disable all macros during \shipout so that they are not +% expanded by \write. +\def\turnoffmacros{\begingroup \def\do##1{\let\noexpand##1=\relax}% + \edef\next{\macrolist}\expandafter\endgroup\next} + + +% @alias. +\def\alias#1=#2{\gdef#1{#2}} + + +\message{cross references,} +% @xref etc. + +\newwrite\auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is relatively simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% @node's job is to define \lastnode. +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +% The sectioning commands (@chapter, etc.) call these. +\def\donoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Ysectionnumberandtype}% + \global\let\lastnode=\relax + \fi +} +\def\unnumbnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}{Ynothing}% + \global\let\lastnode=\relax + \fi +} +\def\appendixnoderef{% + \ifx\lastnode\relax\else + \expandafter\expandafter\expandafter\setref{\lastnode}% + {Yappendixletterandtype}% + \global\let\lastnode=\relax + \fi +} + + +% @anchor{NAME} -- define xref target at arbitrary point. +% +{ \catcode`\@ = 11 +% From latex.ltx, to make @anchor truely invisible. +\newdimen\@savsk +\newcount\@savsf +\gdef\@bsphack{\relax + \ifhmode \@savsk\lastskip \@savsf\spacefactor \fi +} +\gdef\@esphack{\relax + \ifhmode \spacefactor\@savsf + \ifdim\@savsk>\z@ \ignorespaces \fi + \fi +} +\gdef\anchor#1{\@bsphack \setref{#1}{Ynothing}\@esphack} +} + +% \setref{NAME}{SNT} defines a cross-reference point NAME, namely +% NAME-title, NAME-pg, and NAME-SNT. Called from \foonoderef. We have +% to set \indexdummies so commands such as @code in a section title +% aren't expanded. It would be nicer not to expand the titles in the +% first place, but there's so many layers that that is hard to do. +% +\def\setref#1#2{{% + \indexdummies + \pdfmkdest{#1} + \dosetq{#1-title}{Ytitle}% + \dosetq{#1-pg}{Ypagenumber}% + \dosetq{#1-snt}{#2}% +}} + +% @xref, @pxref, and @ref generate cross-references. For \xrefX, #1 is +% the node name, #2 the name of the Info cross-reference, #3 the printed +% node name, #4 the name of the Info file, #5 the name of the printed +% manual. All but the node name can be omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1 > 0pt + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifpdf + \leavevmode + \getfilename{#4}% + \ifnum\filenamelength>0 + \startlink attr{/Border [0 0 0]}% + goto file{\the\filename.pdf} name{#1@}% + \else + \startlink attr{/Border [0 0 0]}% + goto name{#1@}% + \fi + \linkcolor + \fi + % + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' \putwordin{} \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\normalturnoffactive + % Only output a following space if the -snt ref is nonempty; for + % @unnumbered and @anchor, it won't be. + \setbox2 = \hbox{\ignorespaces \refx{#1-snt}{}}% + \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi + }% + % [mynode], + [\printednodename],\space + % page 3 + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi + \endlink +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \normalturnoffactive so that punctuation chars such as underscore +% and backslash work in node names. (\turnoffactive doesn't do \.) +\def\dosetq#1#2{% + {\let\folio=0% + \normalturnoffactive + \edef\next{\write\auxfile{\internalsetq{#1}{#2}}}% + \iflinks + \next + \fi + }% +} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + \angleleft un\-de\-fined\angleright + \iflinks + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. +% +\def\xrdef#1{\begingroup + % Reenable \ as an escape while reading the second argument. + \catcode`\\ = 0 + \afterassignment\endgroup + \expandafter\gdef\csname X#1\endcsname +} + +% Read the last existing aux file, if any. No error if none exists. +\def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + \catcode`+=\other % avoid \+ for paranoia even though we've turned it off + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset and anything else that uses +% \parseargline fail inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f@t\fi \next} +\def\f@@t{\bgroup\aftergroup\@foot\let\next} +\def\f@t#1{#1\@foot} +\def\@foot{\strut\egroup} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = epsf.tex +\ifeof 1 \else + \closein 1 + % Do not bother showing banner with post-v2.7 epsf.tex (available in + % doc/epsf.tex until it shows up on ctan). + \def\epsfannounce{\toks0 = }% + \input epsf.tex +\fi +% +% We will only complain once about lack of epsf.tex. +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://tug.org/tex/epsf.tex.} +% +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is just the usual extra ignored arg for parsing this stuff. +\def\imagexxx#1,#2,#3,#4\finish{% + \ifpdf + \centerline{\dopdfimage{#1}{#2}{#3}}% + \else + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \begingroup + \catcode`\^^M = 5 % in case we're inside an example + % If the image is by itself, center it. + \ifvmode + \nobreak\bigskip + % Usually we'll have text after the image which will insert + % \parskip glue, so insert it here too to equalize the space + % above and below. + \nobreak\vskip\parskip + \nobreak + \centerline{\epsfbox{#1.eps}}% + \bigbreak + \else + % In the middle of a paragraph, no extra space. + \epsfbox{#1.eps}% + \fi + \endgroup + \fi +} + + +\message{localization,} +% and i18n. + +% @documentlanguage is usually given very early, just after +% @setfilename. If done too late, it may not override everything +% properly. Single argument is the language abbreviation. +% It would be nice if we could set up a hyphenation file here. +% +\def\documentlanguage{\parsearg\dodocumentlanguage} +\def\dodocumentlanguage#1{% + \tex % read txi-??.tex file in plain TeX. + % Read the file if it exists. + \openin 1 txi-#1.tex + \ifeof1 + \errhelp = \nolanghelp + \errmessage{Cannot read language file txi-#1.tex}% + \let\temp = \relax + \else + \def\temp{\input txi-#1.tex }% + \fi + \temp + \endgroup +} +\newhelp\nolanghelp{The given language definition file cannot be found or +is empty. Maybe you need to install it? In the current directory +should work if nowhere else does.} + + +% @documentencoding should change something in TeX eventually, most +% likely, but for now just recognize it. +\let\documentencoding = \comment + + +% Page size parameters. +% +\newdimen\defaultparindent \defaultparindent = 15pt + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness = 10000 + +% Don't be so finicky about underfull hboxes, either. +\hbadness = 2000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. We call this whenever the paper size is set. +% +\def\setemergencystretch{% + \ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% + \else + \emergencystretch = .15\hsize + \fi +} + +% Parameters in order: 1) textheight; 2) textwidth; 3) voffset; +% 4) hoffset; 5) binding offset; 6) topskip. Then whoever calls us can +% set \parskip and call \setleading for \baselineskip. +% +\def\internalpagesizes#1#2#3#4#5#6{% + \voffset = #3\relax + \topskip = #6\relax + \splittopskip = \topskip + % + \vsize = #1\relax + \advance\vsize by \topskip + \outervsize = \vsize + \advance\outervsize by 2\topandbottommargin + \pageheight = \vsize + % + \hsize = #2\relax + \outerhsize = \hsize + \advance\outerhsize by 0.5in + \pagewidth = \hsize + % + \normaloffset = #4\relax + \bindingoffset = #5\relax + % + \parindent = \defaultparindent + \setemergencystretch +} + +% @letterpaper (the default). +\def\letterpaper{{\globaldefs = 1 + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + % If page is nothing but text, make it come out even. + \internalpagesizes{46\baselineskip}{6in}{\voffset}{.25in}{\bindingoffset}{36pt}% +}} + +% Use @smallbook to reset parameters for 7x9.5 (or so) format. +\def\smallbook{{\globaldefs = 1 + \parskip = 2pt plus 1pt + \setleading{12pt}% + % + \internalpagesizes{7.5in}{5.in}{\voffset}{.25in}{\bindingoffset}{16pt}% + % + \lispnarrowing = 0.3in + \tolerance = 700 + \hfuzz = 1pt + \contentsrightmargin = 0pt + \deftypemargin = 0pt + \defbodyindent = .5cm + % + \let\smalldisplay = \smalldisplayx + \let\smallexample = \smalllispx + \let\smallformat = \smallformatx + \let\smalllisp = \smalllispx +}} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{{\globaldefs = 1 + \setleading{12pt}% + \parskip = 3pt plus 2pt minus 1pt + % + \internalpagesizes{53\baselineskip}{160mm}{\voffset}{4mm}{\bindingoffset}{44pt}% + % + \tolerance = 700 + \hfuzz = 1pt +}} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex{{\globaldefs = 1 + \setleading{13.6pt}% + % + \afourpaper + \internalpagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm}% + % + \globaldefs = 0 +}} + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{% + \afourpaper + \internalpagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}% + % + \globaldefs = 0 +} + +% @pagesizes TEXTHEIGHT[,TEXTWIDTH] +% Perhaps we should allow setting the margins, \topskip, \parskip, +% and/or leading, also. Or perhaps we should compute them somehow. +% +\def\pagesizes{\parsearg\pagesizesxxx} +\def\pagesizesxxx#1{\pagesizesyyy #1,,\finish} +\def\pagesizesyyy#1,#2,#3\finish{{% + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi + \globaldefs = 1 + % + \parskip = 3pt plus 2pt minus 1pt + \setleading{13.2pt}% + % + \internalpagesizes{#1}{\hsize}{\voffset}{\normaloffset}{\bindingoffset}{44pt}% +}} + +% Set default to letter. +% +\letterpaper + + +\message{and turning on texinfo input format.} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\catcode`\$=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} +\def\normaldollar{$} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi} + +% Same as above, but check for italic font. Actually this also catches +% non-italic slanted fonts since it is impossible to distinguish them from +% italic fonts. But since this is only used by $ and it uses \sl anyway +% this is not a problem. +\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt\char34}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt\char126}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt\char124}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +\catcode`\$=\active +\def${\ifusingit{{\sl\$}}\normaldollar} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus +@let$=@normaldollar} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus +@let$=@normaldollar} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{% + @ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active + @catcode`@_=@active +} + +% Say @foo, not \foo, in error messages. +@escapechar = `@@ + +% These look ok in all fonts, so just make them not special. +@catcode`@& = @other +@catcode`@# = @other +@catcode`@% = @other + +@c Set initial fonts. +@textfonts +@rm + + +@c Local variables: +@c eval: (add-hook 'write-file-hooks 'time-stamp) +@c page-delimiter: "^\\\\message" +@c time-stamp-start: "def\\\\texinfoversion{" +@c time-stamp-format: "%:y-%02m-%02d.%02H" +@c time-stamp-end: "}" +@c End: diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 000000000..fb2c6e3e2 --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = man1 + +MAINTAINERCLEANFILES = Makefile.in diff --git a/man/man1/Makefile.am b/man/man1/Makefile.am new file mode 100644 index 000000000..1818ad812 --- /dev/null +++ b/man/man1/Makefile.am @@ -0,0 +1,8 @@ +## Process this file with automake to produce Makefile.in + + +man_MANS = spice.1 nutmeg.1 sconvert.1 + +EXTRA_DIST = $(man_MANS) + +MAINTAINERCLEANFILES = Makefile.in diff --git a/man/man1/nutmeg.1 b/man/man1/nutmeg.1 new file mode 100644 index 000000000..3fe2e70ed --- /dev/null +++ b/man/man1/nutmeg.1 @@ -0,0 +1,1051 @@ +.\" RCS Info: $Revision$ on $Date$ +.\" $Source$ +.\" Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +.TH NUTMEG 1 "27 April 1987" +.UC 4 +.SH NAME +nutmeg \- spice post-processor +.SH SYNOPSIS +\fBnutmeg [ - ] [ -n ] [ -t term ] [ datafile ... ]\fR +.SH DESCRIPTION +.B Nutmeg +is a post processor for \s-2SPICE\s+2 \- it takes the raw +output file created +by \fBspice -r\fR +and plots the data on a graphics terminal or a workstation display. +Note that the raw output file is different from the +data that \s-2SPICE\s+2 writes to the standard output. +.PP +Arguments are: +.TP +\fB-\fR +Don't try to load the default data file ("rawspice") if no other files +are given. +.TP +\fB-n\fR (or \fB-N\fR) +Don't try to source the file ".spiceinit" upon startup. Normally \fBnutmeg\fR +tries to find the file in the current directory, and if it is not found then +in the user's home directory. +.TP +\fB-t term\fR (or \fB-T term\fR) +The program is being run on a terminal with \fImfb\fR name \fBterm\fR. +.PP +Further arguments are taken to be data files in binary or ascii format +(see \fBsconvert\fR(1)) which are loaded into nutmeg. If the file +is in binary format, it may be only partially completed (useful for +examining \s-2SPICE\s+2 ouput before the simulation is finished). One +file may contain any number of data sets from different analyses. +.PP +\fBNutmeg\fR +data is in the form of vectors: time, voltage, etc. Each vector has +a type, and vectors can be operated on and combined algebraicly in +ways consistent with their types. Vectors are normally created when +a data file is read in (see the +.B load +command below), and when the initial datafile is loaded. They can +also be created with the +.B let +command. +.PP +An expression +is an algebraic +formula involving vectors and scalars (a scalar is a vector of +length 1), and the following operations: +.IP ++, -, *, %, /, ^, and ,. +.PP +% is the modulo operator, and the comma operator has two meanings: +if it is present in the argument list of a user-definable function, it +serves to seperate the arguments. Otherwise, the term \fBx , y\fR is +synonymous with \fBx + j(y)\fR. +.PP +Also available are the logical operations & (and), | (or), ! (not), +and the relational operations <, >, >=, <=, =, and <> (not equal). +If used in an algebraic expression they work like they would in C, +producing values of 0 or 1. The relational operators have the +following synonyms: +\fB"gt"\fR is >, +\fB"lt"\fR is <, +\fB"ge"\fR is >=, +\fB"le"\fR is <=, +\fB"ne"\fR is <>, +\fB"eq"\fR is =, +\fB"and"\fR is &, +\fB"or"\fR is |, +and +\fB"not"\fR is !. +These are useful when < and > might be confused with IO redirection +(which is almost always). +.PP +The following functions are available: +.IP +\fBmag(vector) \-\fR +The magnitude of vector. +.IP +\fBph(vector) \-\fR +The phase of vector. +.IP +\fBj(vector) \-\fR +\fIi\fR (sqrt(-1)) times vector. +.IP +\fBreal(vector) \-\fR +The real component of vector. +.IP +\fBimag(vector) \-\fR +The imaginary part of vector. +.IP +\fBdb(vector) \-\fR +20 * log10(mag(vector)). +.IP +\fBlog(vector) \-\fR +The logarithm (base 10) of the vector. +.IP +\fBln(vector) \-\fR +The natural logarithm (base e) of vector. +.IP +\fBexp(vector) \-\fR +e to the vector power. +.IP +\fBabs(vector) \-\fR +The absolute value of vector. +.IP +\fBsqrt(vector) \-\fR +The square root of vector. +.IP +\fBsin(vector) \-\fR +The sin of vector. +.IP +\fBcos(vector) \-\fR +The cosine of vector. +.IP +\fBtan(vector) \-\fR +The tangent of vector. +.IP +\fBatan(vector) \-\fR +The inverse tangent of vector. +.IP +\fBnorm(vector) \-\fR +The \fBvector\fR normalized to 1 (i.e, the largest magnitude of any component +will be 1). +.IP +\fBrnd(vector) \-\fR +A vector with each component a random integer between 0 and the absolute +value of the vectors's corresponding component. +.IP +\fBmean(vector) \-\fR +The result is a scalar (a length 1 vector) that is the mean of the elements +of \fBvector\fR. +.IP +\fBvector(number) \-\fR +The result is a vector of length \fBnumber\fR, with elements 0, 1, ... +\fBnumber - 1\fR. If \fBnumber\fR is a vector then just the first element +is taken, and if it isn't an integer then the floor of the magnitude is +used. +.IP +\fBlength(vector) \-\fR +The length of \fBvector\fR. +.IP +\fBinterpolate(plot.vector) \-\fR +The result of interpolating the named vector onto the scale of the current +plot. This function uses the variable \fBpolydegree\fR to determine +the degree of interpolation. +.PP +A vector may be either the name of a vector already defined, a floating- +point number (a scalar), or a list like \fB[elt1 elt2 ... eltn]\fR, which +is a vector of length n. +A number may be written in any format acceptable to \s-2SPICE\s+2, such +as \fB14.6MEG\fR or \fB-1.231E-4\fR. Note that you can either use +scientific notation or one of the abbreviations like \fIMEG\fR or \fIG\fR, +but not both. As with \s-2SPICE\s+2, a number may have trailing +alphabetic characters after it. +.PP +The notation \fBexpr [lower upper]\fR, where \fBlower\fR and \fBupper\fR +are numbers, denotes the range of elements from \fBexpr\fR between +\fBlower\fR and \fBupper\fR. The notation \fBexpr [num]\fR denotes +the \fBnum\fR'th element of \fBexpr\fR. If \fBupper\fR +is lower than \fBlower\fR, the order of the elements in the vector +is reversed. In all other cases, \fB[\fR and \fB]\fR serve to surround +literal vectors as described above. (You may have to use a lot of +parentheses to make sure that you get what you want. For instance, +you have to type \fBprint (foo) ([1 2])\fR to print the two vectors. +Otherwise it will be interpreted as a function call or a vector with an +index.) Note that the expression \fBfoo[10 20][5]\fR will \fInot\fR +yield the 15th element of \fBfoo\fR, but rather the 5th. In general only +the last index suffix on an expression will take effect. +.PP +To reference vectors in a plot that is not the +\fIcurrent plot\fR (see the \fBsetplot\fR command, below), the +notation \fBplotname.vecname\fR can be used. +.PP +Either a plotname or a vector name may be the wildcard \fBall\fR. If the +plotname is \fBall\fR, matching vectors from all plots are specified, and +if the vector name is \fBall\fR, all vectors in the specified plots are +referenced. Note that you may not use binary operations on expressions +involving wildcards \- it is not obvious what \fBall + all\fR should +denote, for instance. +.PP +Thus some (contrived) examples of expressions are: +.IP +\fBcos(TIME) + db(v(3))\fR +.IP +\fBsin(cos(log([1 2 3 4 5 6 7 8 9 10])))\fR +.IP +\fBTIME * rnd(v(9)) - 15 * cos(vin#branch) ^ [7.9e5 8]\fR +.IP +\fBnot ((ac3.FREQ[32] & tran1.TIME[10]) gt 3)\fR +.PP +.B Nutmeg +commands are as follows: +.TP +\fBplot exprs [ylimit ylo yhi] [xlimit xlo xhi] [xindices xilo xihi]\fR +.ce +\fB[xcompress comp] [xdelta xdel] [ydelta ydel] [xlog] [ylog] [vs xname]\fR +.ce +\fB[xlabel word] [ylabel word] [title word] [samep]\fR +Plot the given +.B exprs +on the screen (if you are on a graphics terminal). The +.B xlimit +and +.B ylimit +arguments determine the high and low x- and y-limits of the axes, +respectively. The +.B xindices +arguments determine what range of points are to be plotted \- everything +between the \fBxilo\fR'th point and the \fBxihi\fR'th point is plotted. +The +.B xcompress +argument specifies that only one out of every \fBcomp\fR points should +be plotted. If an \fBxdelta\fR or a \fBydelta\fR parameter is present, +it specifies the spacing between grid lines on the X- and Y-axis. +These parameter names may be abbreviated to +.B xl, +.B yl, +.B xind, +.B xcomp, +.B xdel, +and +.B ydel +respectively. +The +.B xname +argument is an expression to use as the scale on the x-axis. +If \fBxlog\fR or \fBylog\fR are present, the X or Y scale respectively +will be logarithmic. +The \fBxlabel\fR and \fBylabel\fR arguments cause the specified +labels to be used for the X and Y axes, respectively. +If \fBsamep\fR is given, the values of the other parameters (other than +\fBxname\fR) from the previous \fBplot, hardcopy,\fR or \fBasciiplot\fR +command will be used unless re-defined on the command line. +Finally, the \fBtitle\fR argument will be used in the place of the plot +name at the bottom of the graph. +.TP +\fBhardcopy file \fIplotargs\fR +Just like \fBplot\fR, except creates a file called +.B file +containing the plot. The file is an image in \fIplot(5)\fR format, +and can be printed by either the \fBplot(1)\fR program or \fBlpr\fR +with the \fB-g\fR flag. +.TP +\fBasciiplot \fIplotargs\fR +Produce a line printer plot of the vectors. +The plot is sent to the standard +output, so you can put it into a file with \fIasciiplot args ... > file\fR. +The \fBset\fR options \fBwidth, height,\fR and \fBnobreak\fR determine +the width and height of the plot, and whether there are page breaks, +respectively. Note that you will have problems if you try to \fBasciiplot\fR +something with an X-scale that isn't monotonic (i.e, something +like \fIsin(TIME)\fR ), because \fBasciiplot\fR uses a simple-minded sort +of linear interpolation. +.TP +\fBdefine function(arg1, arg2, ...) expression\fR +Define the \fIuser-definable function\fR with the name \fIfunction\fR +and arguments \fIarg1, arg2, ...\fR to be \fIexpression\fR, which +may involve the arguments. When the function is later used, the arguments +it is given are substituted for the formal arguments when it is parsed. +If \fIexpression\fR is not present, any definition for \fIfunction\fR +is printed, and if there are no arguments to \fIdefine\fR then all +currently active definitions are printed. Note that you may have different +functions defined with the same name but different arities. +Some useful definitions are: +.IP +define max(x,y) (x > y) * x + (x <= y) * y +.br +define min(x,y) (x < y) * x + (x >= y) * y +.TP +\fBundefine function ...\fR +Definitions for the named user-defined functions are deleted. +.TP +\fBlet name = expr\fR +Creates a new vector called +.B name +with the value specified by +.B expr, +an expression as described above. If \fBexpr\fR is [] (a zero-length vector) +then the vector becomes undefined. +If there are no arguments, \fBlet\fR is the same as \fBdisplay\fR. +.TP +\fBprint [col] [line] expr ... \fR +Prints the vector described by the expression +.B expr. +If the +.B col +argument is present, print the vectors named side by side. If \fBline\fR +is given, the vectors are printed horizontally. \fBcol\fR is the default, +unless all the vectors named have a length of one, in which case \fBline\fR +is the default. +The options +\fBwidth, length,\fR and \fBnobreak\fR are effective for this +command (see \fBasciiplot\fR). If the expression is \fBall\fR, +all of the vectors available are printed. Thus \fBprint col all > file\fR +will print everything in the file in \s-2SPICE\s+2\&2 format. +The scale vector (time, frequency) will always be in the first column +unless the variable \fBnoprintscale\fR is true. +.TP +\fBload [filename] ... \fR +Loads the raw data in either binary or ascii format +from the files named. The default filename is \fBrawspice\fR, or the argument +to the \fB-r\fR flag if there was one. +.TP +\fBsource filename\fR +Reads commands from the file +.B filename. +Lines beginning with the character \fB*\fR are considered comments and +ignored. +.TP +\fBhelp [all] [command ...]\fR +Prints help. If the argument \fBall\fR is given, a short description +of everything you could possibly type is printed. If \fBcommand\fRs are +given, descriptions of those commands are printed. Otherwise help for +only a few major commands is printed. +.TP +\fBdisplay [varname ...]\fR +Prints a summary of currently defined vectors, or of the names specified. +The vectors are sorted by name unless the variable \fBnosort\fR is set. +The information given is the name of the vector, the length, the +type of the vector, and whether it is real or complex data. Additionally, +one vector will be labeled \fB[scale]\fR. When a command such as +\fIplot\fR is given without a \fIvs\fR argument, this scale is used +for the X-axis. It is always the first vector in a rawfile, or +the first vector defined in a new plot. If you undefine the scale +(i.e, \fIlet TIME = []\fR), a random remaining +vector will become the scale. +.TP +\fBsetplot [plotname]\fR +Set the \fBcurrent plot\fR to the plot with the given +name, or if no name is given, prompt the user with a menu. +(Note that the plots are named as they are loaded, with names +like \fBtran1\fR or \fBop2\fR. These names are shown by the +\fBsetplot\fR and \fBdisplay\fR commands and are used by \fBdiff\fR, +below.) +If the +"New plot" item is selected, the current plot will become one with +no vectors defined. +Note that here the word "plot" refers +to a group of vectors that are the result of one \s-2SPICE\s+2 run. +When +more than one file is loaded in, or more than one plot is present +in one file, \fBnutmeg\fR keeps them seperate and only shows you the +vectors in the current plot. +.TP +\fBsettype type vector ...\fR +Change the type of the named vectors to \fBtype\fR. Type names can +be found in the manual page for \fBsconvert\fR. +.TP +\fBdiff plot1 plot2 [vec ...]\fR +Compare all the vectors in the specified \fIplots\fR, or only the named +vectors if any are given. There are different vectors in the two plots, +or any values in the vectors differ significantly the difference is +reported. The variables \fBabstol, reltol,\fR and \fBvntol\fR are used +to determine what "significantly" means (see the \s-2SPICE\s+2\&3 User's +Manual). +.TP +.B quit +Quit nutmeg. +.TP +.B bug +Send a bug report. (If you have defined BUGADDR, the mail will go there.) +.TP +\fBwrite [file] [exprs]\fR +Writes out the expr's to +.B file. +First vectors are grouped together by plots, and written out as such. +(I.e, if the expression list contained three vectors from one plot +and two from another, then two plots will be written, one with three +vectors and one with two.) Additionally, if the scale for a vector +isn't present, it is automatically written out as well. +The default format +is ascii, but this can be changed with the \fBset filetype\fR command. +The default filename is \fBrawspice\fR, or the argument to the \fB-r\fR +flag on the command line, if there was one, and the default expression +list is \fBall\fR. +.TP +\fBshell [args ...]\fR +Fork a shell, or execute the arguments as a command to the shell. +.TP +\fBalias [word] [text ...]\fR +Causes \fBword\fR to be aliased to \fBtext\fR. History substitutions may +be used, as in C-shell aliases. +.TP +\fBunalias [word ...]\fR +Removes any aliases present for the \fBword\fRs. +.TP +\fBhistory [number]\fR +Print out the history, or the last \fBnumber\fR commands typed at the keyboard. +\fINote:\fR in \*S version 3a7 and earlier, all commands (including ones read +from files) were saved. +.TP +\fBset [word] [word = value] ... \fR +Set the value of \fBword\fR to be \fBvalue\fR, if it is present. +You can set any word to be any value, numeric or string. If no value is +given then the value is the boolean 'true'. The value of \fIword\fR may +be inserted into a command by writing \fI$word\fR. +If a variable is set to a list of values that are enclosed in parentheses +(which +\fBmust\fR be seperated from their values by white space), the value +of the variable is the list. +The variables meaningful to \fBnutmeg\fR (of which there are too many) are: +.IP "" 16 +\fBabstol\fR +.br +The absolute tolerance used by the \fBdiff\fR command. +.IP +\fBappendwrite\fR +.br +Append to the file when a \fBwrite\fR command is issued, if one +already exists. +.IP +\fBcolor\fIN\fR +.br +These variables determine the colors used, if \fBX\fR is being run on +a color display. +\fIN\fR may be between 0 and 15. Color 0 is the background, color 1 +is the grid and text color, and colors 2 through 15 are used in order for +vectors plotted. The value of the \fBcolor\fR variables should be names +of colors, which may be found in the file \fB/usr/lib/rgb.txt\fR. +.IP +\fBcombplot\fR +.br +Plot vectors by drawing a vertical line from each point to the X-axis, +as opposed to joining the points. Note that this option is subsumed +in the \fIplottype\fR option, below. +.IP +\fBcpdebug\fR +.br +Print \fIcshpar\fR debugging information. (Must be complied with the +-DCPDEBUG flag.) +.IP +\fBdebug\fR +.br +If set then a lot of debugging information is printed. (Must be +compiled with the -DFTEDEBUG flag.) +.IP +\fBdevice\fR +.br +The name (/dev/tty??) of the graphics device. If this variable +isn't set then the user's terminal is used. To do plotting on +another monitor you will probably have to set both the \fBdevice\fR +and \fBterm\fR variables. (If \fBdevice\fR is set to the name of +a file, \fBnutmeg\fR will dump the graphics control codes into +this file -- this is useful for saving plots.) +.\".IP +.\"\fBdontplot\fR +.\".br +.\"No graphics control codes are actually sent. (Useful for debugging on +.\"non-graphics terminals.) +.IP +\fBecho\fR +.br +Print out each command before it is executed. +.IP +\fBfiletype\fR +.br +This can be either +.B ascii +or +.B binary, +and determines what the format of +.I rawfiles +will be. The default is +.B ascii. +.IP +\fBfourgridsize\fR +.br +How many points to use for interpolating into when doing fourier analysis. +.\".IP +.\"\fBgeometry\fIN\fR +.\".br +.\"The size and positioning information for X windows. \fIN\fR may be +.\"any positive integer, in which case it is the information for the \fIN\fR'th +.\"window on the screen, or may be omitted, in which case it is used whenever +.\"there is no information for the window. The geometry information is a string +.\"of the form \fR=\fIheight\fBx\fIwidth\fB+\fIxoff\fB+\fIyoff\fR, where the +.\"window will be of size \fIheight\fR by \fIwidth\fR and be positioned at +.\"(\fIxoff, yoff\fR), where (0,0) is the upper left hand corner of the screen. +.\"Either the positioning information or the size information may be omitted, +.\"in which case the window will be opened interactively (as will happen if no +.\"\fBgeometry\fR information is given). The method of interactive sizing is +.\"the same as for other X utilities. +.\"A typical use for the \fBgeometry\fR variables might be to set \fBmaxwins\fR +.\"to 3 and set \fBgeometry1, geometry2,\fR and \fBgeometry3\fR to position three +.\"plot windows in a row across the top of the screen. +.IP +\fBgridsize\fR +.br +If this variable is set to an integer, this number will be used as the number +of equally spaced points to use for the Y-axis when plotting. Otherwise +the current scale will be used (which may not have equally spaced points). +If the current scale isn't strictly monotonic, then this option will have +no effect. +.IP +\fBhcopydev\fR +.br +If this is set, when the \fBhardcopy\fR command is run the resulting file +is automatically printed on the printer named \fBhcopydev\fR with the +command \fIlpr -P\fBhcopydev\fI -g \fBfile\fR. +.IP +\fBhcopydevtype\fR +.br +This variable specifies the type of the printer output to use in the +\fBhardcopy\fR command. If hcopydevtype is not set, plot (5) format +is assumed. The standard distribution currently recognizes \fBpostscript\fR +as an alternative output format. When used in conjunction with +\fBhcopydev\fR, \fBhcopydevtype\fR should specify a format supported by +the printer. +.IP +\fBheight\fR +.br +The length of the page for \fBasciiplot\fR and \fBprint col\fR. +.IP +\fBhistory\fR +.br +The number of events to save in the history list. +.\".IP +.\"\fBmaxwins\fR +.\".br +.\"The maximum number of windows X should have on the screen at one time. +.\"If it has \fBmaxwins\fR or more windows, it will begin re-using them +.\"for plots in an oldest-first manner. +.IP +\fBnfreqs\fR +.br +The number of frequencies to compute in the +.B fourier +command. (Defaults to 10.) +.IP +\fBnobreak\fR +.br +Don't have \fBasciiplot\fR and \fBprint col\fR break between pages. +.IP +\fBnoasciiplotvalue\fR +.br +Don't print the first vector plotted to the left when doing an +\fBasciiplot\fR. +.IP +\fBnoclobber\fR +.br +Don't overwrite existing files when doing IO redirection. +.IP +\fBnoglob\fR +.br +Don't expand the global characters `*', `?', `[', and `]'. This is the +default. +.IP +\fBnogrid\fR +.br +Don't plot a grid when graphing curves (but do label the axes). +.IP +\fBnomoremode\fR +.br +If \fBnomoremode\fR is not set, whenever a large amount of data is being +printed to the screen (e.g, the \fBprint\fR or \fBasciiplot\fR commands), +the output will be stopped every screenful and will continue when +a carriage return is typed. If \fBnomoremode\fR is set then data will scroll +off the screen without hesitation. +.IP +\fBnonomatch\fR +.br +If \fBnoglob\fR is unset and a global expression cannot be matched, use +the global characters literally instead of complaining. +.IP +\fBnosort\fR +.br +Don't have \fBdisplay\fR sort the variable names. +.IP +\fBnoprintscale\fR +.br +Don't print the scale in the leftmost column when a \fBprint col\fR command +is given. +.IP +\fBnumdgt\fR +.br +The number of digits to print when printing tables of data (\fBfourier, print +col\fR). The default precision is 6 digits. On the VAX, approximately +16 decimal digits are available using double precision, so \fBnumdgt\fR +should not be more than 16. If the number is negative, one fewer digit +is printed to ensure constant widths in tables. +.IP +\fBplottype\fR +.br +This should be one of \fInormal\fR, \fIcomb\fR, or \fIpoint:\fBchars\fR. +\fInormal\fR, the default, causes points to be plotted as parts of connected +lines. \fIcomb\fR causes a comb plot to be done (see the description of the +\fIcombplot\fR variable above). \fIpoint\fR causes each point to be plotted +seperately \- the \fBchars\fR are a list of characters that will be used +for each vector plotted. If they are omitted then a default set is used. +.IP +\fBpolydegree\fR +.br +The degree of the polynomial that the \fBplot\fR command should fit +to the data. If \fIpolydegree\fR is N, then \fBnutmeg\fR will fit a degree N +polynomial to every set of N points and draw 10 intermediate points +in between each endpoint. If the points aren't monotonic, then it will try +rotating the curve and reducing the degree until a fit is achieved. +.IP +\fBpolysteps\fR +.br +The number of points to interpolate between every pair of points available +when doing curve fitting. The default is 10. (This should really be done +automatically.) +.IP +\fBprogram\fR +.br +The name of the current program (\fIargv[0]\fR). +.IP +\fBprompt\fR +.br +The prompt, with the character `!' replaced by the current event number. +.IP +\fBrawfile\fR +.br +The default name for rawfiles created. +.IP +\fBreltol\fR +.br +The relative tolerance used by the \fBdiff\fR command. +.IP +\fBrhost\fR +.br +The machine to use for remote \s-2SPICE-3\s+2 runs, instead of the +default one. (See the description of the \fBrspice\fR command, +below.) +.IP +\fBrprogram\fR +.br +The name of the remote program to use in the \fBrspice\fR command. +.\".IP +.\"\fBsavewins\fR +.\".br +.\"If true, then don't get rid of the plot window after the plot is done (X +.\"only). The window may be removed by clicking any mouse button inside of it. +.IP +\fBslowplot\fR +.br +Stop between each graph plotted and wait for the user to type +return before continuing. +.IP +\fBsourcepath\fR +.br +A list of the directories to search when a \fBsource\fR command is given. +The default is the current directory and the standard spice library +(\fI/usr/local/lib/spice\fR, or whatever \fBLIBPATH\fR is #defined to +in the \*S source. +.IP +\fBspicepath\fR +.br +The program to use for the \fBaspice\fR command. The default is +/cad/bin/spice. +.IP +\fBterm\fR +.br +The \fImfb\fR name of the current terminal. +.IP +\fBunits\fR +.br +If this is \fBdegrees\fR, then all the trig functions will use degrees +instead of radians. +.IP +\fBunixcom\fR +.br +If a command isn't defined, try to execute it as a \s-2UNIX\s+2 command. +Setting this option has the effect of giving a \fBrehash\fR command, +below. +This is useful for people who want to use \fBnutmeg\fR as a login shell. +.IP +\fBverbose\fR +.br +Be verbose. This is midway between \fBecho\fR and \fBdebug\fR / \fBcpdebug\fR. +.IP +\fBvntol\fR +.br +The absolute voltage tolerance used by the \fBdiff\fR command. +.IP +\fBwidth\fR +.br +The width of the page for \fBasciiplot\fR and \fBprint col\fR. +.IP +\fBxbrushheight\fR +.br +The height of the brush to use if \fBX\fR is being run. +.IP +\fBxbrushwidth\fR +.br +The width of the brush to use if \fBX\fR is being run. +.IP +\fBxfont\fR +.br +The name of the X font to use when plotting data and entering labels. +The plot may not look entirely great if this is a variable-width font. +.PP +.TP +\fBunset [word] ... \fR +Unset the variables \fBword\fR. +.TP +\fBshift [varname] [number]\fR +If \fIvarname\fR is the name of a list variable, it is shifted to the left +by \fInumber\fR elements. (I.e, the \fInumber\fR leftmost elements are +removed.) The default \fIvarname\fR is \fBargv\fR, and the default +\fInumber\fR is 1. +.TP +\fBrusage [resource ...]\fR +Print resource usage statistics. If any \fBresource\fR\&s are given, +just print the usage of that resource. Currently valid \fBresource\fR\&s +are: +.IP "" 16 +\fBelapsed\fR +.br +The amount of time elapsed since the last \fBrusage elaped\fR call. +.IP +\fBfaults\fR +.br +Number of page faults and context switches (BSD only). +.IP +\fBspace\fR +.br +Data space used. +.IP +\fBtime\fR +.br +CPU time used so far. +.IP +\fBeverything\fR +.br +All of the above. +.TP +\fBcd [directory]\fR +Change the current working directory to \fBdirectory\fR, or to the user's +home directory if none is given. +.TP +\fBaspice [output-file]\fR +Start a \s-2SPICE-3\s+2 run, and when it is finished load the data. The +raw data is kept in a temporary file. If \fIoutput-file\fR is specified +then the diagnostic output is directed into that file, otherwise it +is thrown away. +.TP +\fBjobs\fR +Report on the asynchronous \s-2SPICE-3\s+2 jobs currently running. +\fBNutmeg\fR checks to see if the jobs are finished every time you +execute a command. +If it is done then the data is loaded and becomes available. +.TP +\fBrspice [input file]\fR +Runs a \s-2SPICE-3\s+2 remotely taking the \fBinput file\fR as a +\s-2SPICE-3\s+2 input deck, or the current circuit if no argument is +given. \fBNutmeg\fR waits for the job to complete, and passes output +from the remote job to the user's standard output. When the job is +finished the data is loaded in as with \fRaspice\fR. If the variable +\fIrhost\fR is set, \fBnutmeg\fR will connect to this host instead of +the default remote \s-2SPICE-3\s+2 server machine. Note that this +command will only work if your system administrator is running a +\s-2SPICE-3\s+2 daemon on the remote host. If the variable \fIrprogram\fR +is set, then \fBrspice\fR will use this as the pathname to the program +to run. +.TP +\fBecho [stuff...]\fR +Echos the arguments. +.TP +\fBfourier fundamental_frequency [value ...]\fR +Does a fourier analysis of each of the given values, using the first 10 +multiples of the fundamental frequency (or the first \fInfreqs\fR, if that +variable is set \- see below). The output is like that of +the \fB.four\fR \*S card. The values may be any valid expression. +The values are interpolated onto a fixed-space grid with the number of +points given by the \fBfourgridsize\fR variable, or 200 if it is not set. +The interpolation will be of degree \fBpolydegree\fR if that variable is +set, or 1. If \fBpolydegree\fR is 0, then no interpolation will be done. +This is likely to give erroneous results if the time scale is not monotonic, +though. +.TP +\fBversion [version id]\fR +Print out the version of \fBnutmeg\fR that is running. +If there are arguments, it checks to make sure that the arguments match +the current version of \s-2SPICE\s+2. (This is mainly used as a \fBCommand:\fR +line in rawfiles.) +.TP +\fBrehash\fR +Recalculate the internal hash tables used when looking up UNIX commands, +and make all UNIX commands in the user's PATH available for command +completion. +This is useless unless you have \fBset unixcom\fR first (see above). +.PP +The following control structures are available: +.IP +.nf +\fBwhile\fR \fIcondition\fR + statement + ... +\fBend\fR +.fi +.PP +While \fIcondition\fR, an arbitrary algebraic expression, is true, +execute the statements. +.IP +.nf +\fBrepeat\fR \fI[number]\fR + statement + ... +\fBend\fR +.fi +.PP +Execute the statements \fInumber\fR times, or forever if no argument is +given. +.IP +.nf +\fBdowhile\fR \fIcondition\fR + statement + ... +\fBend\fR +.fi +.PP +The same as \fBwhile\fR, except that the \fIcondition\fR is tested after +the statements are executed. +.IP +.nf +\fBforeach\fR \fIvar\fR \fIvalue ...\fR + statement + ... +\fBend\fR +.fi +.PP +The statements are executed once for each of the \fIvalue\fRs, each time +with the variable \fIvar\fR set to the current one. (\fIvar\fR can be accessed +by the $\fIvar\fR notation \- see below). +.IP +.nf +\fBif\fR \fIcondition\fR + statement + ... +\fBelse\fR + statement + ... +\fBend\fR +.fi +.PP +If the \fIcondition\fR is non-zero then the first set of statements are +executed, otherwise the second set. The \fBelse\fR and the second set +of statements may be omitted. +.IP +\fBlabel\fR \fIword\fR +.PP +If a statement of the form \fBgoto\fI word\fR is encountered, control is +transfered to this point, otherwise this is a no-op. +.IP +\fBgoto\fR \fIword\fR +.PP +If a statement of the form \fBlabel\fI word\fR is present in the block +or an enclosing block, control is transfered there. Note that if the +label is at the top level, it \fImust\fR be before the \fBgoto\fR statement +(i.e, a forward \fBgoto\fR may occur only within a block). +.IP +\fBcontinue\fR +.PP +If there is a \fBwhile, dowhile,\fR or \fBforeach\fR block enclosing this +statement, control passes to the test, or in the case of \fBforeach\fR, +the next value is taken. +Otherwise an +error results. +.IP +\fBbreak\fR +.PP +If there is a \fBwhile, dowhile,\fR or \fBforeach\fR block enclosing this +statement, control passes out of the block. Otherwise an +error results. +.PP +Of course, control structures may be nested. When a block is entered +and the input is the terminal, the prompt becomes a number of >'s +equalling the number of blocks the user has entered. The current control +structures may be examined with the debugging command +.B cdump. +.PP +If a word is typed as a command, and there is no built-in command +with that name, the directories in the \fIsourcepath\fR list are searched +in order for the file. If it is found, it is read in as a command file (as +if it were \fBsource\fRd). Before it is read, however, the variables +\fIargc\fR and \fIargv\fR are set to the number of words following the +filename on the command line, and a list of those words respectively. +After the file is finished, these variables are \fBunset\fR. Note that +if a command file calls another, it must save its \fIargv\fR and \fIargc\fR +since they will get altered. Also, command files may not be re-entrant +since there are no local variables. (Of course, the procedures may +explicitly manipulate a stack...) +This way one can write scripts analogous to shell scripts for \fBnutmeg\fR and +\*S. Note that for the script to work with \*S, it \fBmust\fR begin +with a blank line (or whatever you like, since it will be thrown away) +and then a line with \fB.control\fR on it. This is an unfortunate result +of the \fBsource\fR command being used for both circuit input and command +file execution. Note also that this allows the user to merely type the +name of a circuit file as a command, and it will be automatically run. +.PP +There are various command scripts installed in +\fI/usr/local/lib/spice/scripts\fR (or whatever the path is on your machine), +and the default \fIsourcepath\fR includes this directory, so you can use +these command files (almost) like builtin commands. +.PP +\fBNutmeg\fR will use either \fBX\fR or \fBMFB\fR, depending on whether +it finds the variable \fBDISPLAY\fR in the environment. If you are +using \fBX\fR on a workstation, it should already be present, but if you +want to display graphics on a different machine than the one you +are running \fBnutmeg\fR on, \fBDISPLAY\fR should be of the form +\fImachine\fR:0. +.PP +If \fBX\fR is being used, the cursor may be positioned at any +point on the screen when the window is up and characters typed at the +keyboard will be added to the window at that point. The window may +then be sent to a printer using the \fBxpr(1)\fR program. +.PP +There are a number of pre-defined constants in \fBnutmeg\fR. They are: +.na +.nf + pi pi + e The base of natural logarithms + c The speed of light + i The square root of -1 + kelvin Absolute 0 in Centigrade + echarge The charge on an electron + boltz Boltzman's constant + planck Planck's constant (h) + +.fi +.ad +.PP +These are all in MKS units. If you have another variable with +a name that conflicts with one of these then it takes precedence. +.PP +Nutmeg occasionally checks to see if it +is getting close to running out of space, and warns the user if this +is the case. (This is more likely to be useful with the \s-2SPICE\s+2 +front end.) +.PP +C-shell type quoting with "" and '', and backquote substitution may +be used. Within single quotes, no further substitution (like +history substitution) is done, and within double quotes, the words +are kept together but further substitution is done. Any text between +backquotes is replaced by the result of executing the text as a command +to the shell. +.PP +Tenex-style ('set filec' in the 4.3 C-shell) +command, filename, and keyword completion is possible: If EOF +(control-D) is typed after the first character on the line, a list +of the commands or possible arguments is printed. (If it is alone +on the line it will exit \fBnutmeg\fR.) If escape is typed, then +\fBnutmeg\fR will try to complete what the user has already typed. +To get a list of all commands, the user should type ^D. +.PP +The values of variables may be used in commands by writing \fB$varname\fR +where the value of the variable is to appear. The special variables +\fI$$\fR and \fI$<\fR refer to the process ID of the program and a +line of input which is read from the terminal when the variable +is evaluated, respectively. If a variable has a name of the form +\fB$&word\fR, then \fBword\fR is considered a vector (see above), +and its value is taken to be the value of the variable. +If \fI$foo\fR is a valid variable, and is of type \fBlist\fR, then the +expression \fI$foo[low-high]\fR represents a range of elements. Either +the upper index or the lower may be left out, and the reverse of a list may +be obtained with \fI$foo[len-0]\fR. Also, the notation \fI$?foo\fR evaluates +to 1 if the variable \fIfoo\fR is defined, 0 otherwise, and \fI$#foo\fR +evaluates to the number of elements in \fIfoo\fR if it is a list, 1 if it +is a number or string, and 0 if it is a boolean variable. +.PP +History substitutions, similar to C-shell history substitutions, are +also available \- see the C-shell manual page for all of the details. +.PP +The characters ~, {, and } have the same effects as they do in the +C-Shell, i.e., home directory and alternative expansion. It is +possible to use the wildcard characters *, ?, [, and ] also, +but only if you \fBunset noglob\fR first. This makes them rather +useless for typing algebraic expressions, so you should \fBset noglob\fR +again after you are done with wildcard expansion. Note that the +pattern \fB[^abc]\fR will match all characters \fIexcept\fB a, b, +\fRand\fB c.\fR +.PP +IO redirection is available \- the symbols \fB>, >>, >&, >>&, \fRand\fB <\fR +have the same effects as in the C-shell. +.PP +You may type multiple commands on one line, seperated by semicolons. +.PP +If you want to use a different \fBmfbcap\fR file than the default (usually +\fB~cad/lib/mfbcap\fR), you have to set the environment variable \fBMFBCAP\fR +before you start \fBnutmeg\fR. The \fB-m\fR option and the \fBmfbcap\fR +variable no longer work. +.SH "VMS NOTES" +\fBNutmeg\fR can be run under VAX/VMS. Some features like command, etc +completion, expansion of *, ?, and [], backquote substitution, the +shell command, and so forth do not work. (In fact command completion +only works on 4.2 or 4.3 BSD.) +.PP +\fBNutmeg\fR will look for start-up +commands in the file \fIspice.rc\fR in the current directory. +.PP +The standard suffix for rawspice files in VMS is ".raw". +.PP +You will have to respond to the \fI-more-\fR prompt during plot with a +carriage return instead of any key as you can do on UNIX. +.SH "SEE ALSO" +sconvert(1), spice(1), mfb(3), writedata(3) +.SH AUTHOR +Wayne Christopher (faustus@cad.berkeley.edu) +.SH BUGS +.PP +The label entry facilities are very primitive \- after all, \fBnutmeg\fR isn't +a graphics editor (yet). You must be careful to type very slowly when +entering labels -- \fBnutmeg\fR checks the \fBX\fR event queue once +every second, and can get very confused if characters arrive faster than +that. +.PP +If you redefine colors after creating a plot window with X, and then +cause the window to be redrawn, it will not to the right thing. +.PP +When defining aliases like +.IP +\fIalias pdb plot db( '!:1' - '!:2' )\fR +.PP +you must be careful to quote the argument list substitutions in this +manner. If you quote the whole argument it might not work properly. +.PP +In a user-defined function, the arguments cannot be part of a name that +uses the \fIplot.vec\fR syntax. I.e, +.IP +\fIdefine poke(duck) cos(tran1.duck) +.PP +won't do the right thing. +.PP +If you type \fBplot all all\fR, or otherwise use a wildcard reference for +one plot twice in a command, bad things will happen. +.PP +The \fBasciiplot\fR command doesn't deal with log scales or the \fBdelta\fR +keywords. +.PP +There are probably some features that \fBnutmeg\fR doesn't have yet. +.SH CAVEATS +Often the names of terminals recognised by \fBMFB\fR are different +from those in /etc/termcap. Thus you may have to reset your terminal +type with the command +.IP +\fBset term = termname\fR +.PP +where \fBtermname\fR is the name in the \fBmfbcap\fR file. +.PP +The \fBhardcopy\fR command is useless on VMS and other systems without +the \fBplot\fR command, unless the user has a program that understands +\fIplot(5)\fR format. + diff --git a/man/man1/sconvert.1 b/man/man1/sconvert.1 new file mode 100644 index 000000000..6fcbc3a4f --- /dev/null +++ b/man/man1/sconvert.1 @@ -0,0 +1,127 @@ +.\" RCS Info: $Revision$ on $Date$ +.\" $Source$ +.\" Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +.TH SCONVERT 1 "20 March 1986" +.UC 4 +.SH NAME +sconvert \- convert spice formats +.SH SYNOPSIS +.B sconvert fromtype fromfile totype tofile +.br +.B sconvert fromtype totype +.br +.B sconvert +.br +.SH DESCRIPTION +.B Sconvert +translates spice output files among three formats: the old +binary format, a new binary format, and a new ascii format. +The formats are specified by the +.B fromtype +and +.B totype +arguments: `o' for the old format, `b' for the new binary format, +and `a' for the new ascii format. +.B Fromtype +specifies the format to be read, and +.B totype +specifies the format to be written. +If +.B fromfile +and +.B tofile +are given, then they are used as the input and output, otherwise +standard input and output are used. (Note that this second option is +only available on \s-2UNIX\s+2 systems \- on VMS and other systems you must +supply the filenames.) +If no arguments are given, the parameters are prompted for. +.PP +Binary format is the preferred format for general use, as it is +the most economical in terms of space and speed of access, and ascii is +provided to make it easy to modify data files and transfer them +between machines with different floating-point formats. +The old format is provided only +for backward compatibility. The three formats are as follows: +.br +.nf + +.B Old: + + What Size in Bytes + + title 80 + date 8 + time 8 + numoutputs 2 + the integer 4 2 + variable names -- + char[numoutputs][8] numoutputs * 8 + types of output numoutputs * 2 + node index numoutputs * 2 + plot title numoutputs * 24 + the actual data numpoints * numoutputs * 8 + +.B Ascii: + + Title: \fITitle Card String\fR + Date: \fIDate\fR + [ Plotname: \fIPlot Name\fR + Flags: \fIcomplex\fR or \fIreal\fR + No. Variables: \fInumoutputs\fR + No. Points: \fInumpoints\fR + Command: \fInutmeg command\fR + Variables: 0 \fIvarname1\fR \fItypename1\fR + 1 \fIvarname2\fR \fItypename2\fR + etc... + Values: + 0 n n n n ... + 1 n n n n ... + And so forth... + ] repeated one or more times + +.PP +If one of the flags is \fIcomplex\fR, the points look like r,i where r and i +are floating point (in %e format). Otherwise they are in %e format. +Only one of \fIreal\fR and \fIcomplex\fR should appear. +.PP +The lines are guaranteed to be less than 80 columns wide (unless the +plot title or variable names are very long), so this format is safe +to mail between systems like CMS. +.PP +Any number of \fBCommand:\fR lines may appear between the \fBNo. Points:\fR +and the \fBVariables:\fR lines, and whenever the plot is loaded into +\fBnutmeg\fR they will be executed. +.nf + +.B Binary: + + \fITitle Card\fR (a NULL terminated string) + \fIDate, Time\fR (a NULL terminated string) + [ + \fIPlot title\fR (a NULL terminated string) + \fINumber of variables\fR (an int) + \fINumber of data points\fR (an int) + \fIflags\fR (a short) + \fIvariable header struct\fR (repeated numoutputs times) + \fIvariable name\fR (a NULL terminated string) + \fIvariable type\fR (an int) + \fIset of outputs\fR (repeated numpoints times) + ] repeated one or more times. + +.PP +A set of outputs is a vector of doubles of length numoutputs, or +a vector of real-imaginary pairs of doubles if the data is complex. +.SH "SEE ALSO" +nutmeg(1), spice(1), writedata(3) +.SH AUTHOR +Wayne Christopher (faustus@cad.berkeley.edu) +.SH BUGS +If variable names and the title +and plotname strings have trailing +blanks in them they will be stripped off when the file is read, if +it is in ascii format. +.PP +If a plot title begins with "Title:" \fBnutmeg\fR will be fooled into thinking +that this is an ascii format file. \fBSconvert\fR always requires the +type to be specified, however. + diff --git a/man/man1/spice.1 b/man/man1/spice.1 new file mode 100644 index 000000000..1a70aac5b --- /dev/null +++ b/man/man1/spice.1 @@ -0,0 +1,325 @@ +.\" RCS Info: $Revision$ on $Date$ +.\" $Source$ +.\" Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +.TH SPICE 1 "20 March 1986" +.ds S \s-2SPICE\s+2\&3 +.UC 4 +.SH NAME +spice \- circuit simulator +.SH SYNOPSIS +\fBspice [ -n ] [ -t term ] [ -r rawfile] [ -b ] +[ -i ] [ input file ... ]\fR +.SH DESCRIPTION +This manual page describes the commands available for interactive +use of \*S. For details of circuit descriptions and the +process of simulating a circuit, see the \*S User's Manual. +The commands available are a superset of those available for +\fBnutmeg\fR \- only the additional commands available in \*S +are described here. You should be familiar with the manual page for +\fBnutmeg(1)\fR before reading this manual page. +.PP +Arguments are: +.TP +\fB-n\fR (or \fB-N\fR) +Don't try to source the file ".spiceinit" upon startup. Normally \*S +tries to find the file in the current directory, and if it is not found then +in the user's home directory. +.TP +\fB-t term\fR (or \fB-T term\fR) +The program is being run on a terminal with \fImfb\fR name \fBterm\fR. +.TP +\fB-b\fR (or \fB-B\fR) +Run in batch mode. \*S will read the standard input or the specified +input file and do the simulation. Note that if the standard input +is not a terminal, \*S will default to batch mode, unless the +-i flag is given. +.TP +\fB-s\fR (or \fB-S\fR) +Run in server mode. This is like batch mode, except that a temporary +rawfile is used and then written to the standard output, preceded by +a line with a single "@", after the simulation is done. This mode +is used by the spice daemon. +.TP +\fB-i\fR (or \fB-I\fR) +Run in interactive mode. This is useful if the standard input is +not a terminal but interactive mode is desired. Command completion is +not available unless the standard input is a terminal, however. +.TP +\fB-r rawfile\fR (or \fB-R rawfile\fR) +Use \fBrawfile\fR as the default file into which the results of +the simulation are saved. +.PP +Further arguments are taken to be \*S input decks, which are read +and saved. (If batch mode is requested then they are run immediately.) +.PP +\*S will accept any \s-2SPICE\s+2\&2 input decks, and output +ascii plots, fourier analyses, and node printouts as specified +in .plot, .four, and .print cards. If a \fBout\fR parameter +is given on a .width card, the effect is the same as \fBset width = ...\fR. +Since \*S ascii plots do not use multiple ranges, however, if vectors +together on a .plot card have different ranges they will not provide +as much information as they would in \s-2SPICE\s+2\&2. The output +of \*S is also much less verbose than \s-2SPICE\s+2\&2, in that the only +data printed is that requested by the above cards. +.PP +Vector names are the same as in \fBnutmeg\fR, with this addition: +a name such as \fB@name[param]\fR, where \fBname\fR is either +the name of a device instance or model, denotes the value of the +\fBparam\fR parameter of the device or model. See the \*S User's +Manual for details of what parameters are available. The value is a +vector of length 1. This function is also available with the +\fBshow\fR command, and is available with variables for convenience for +command scripts. +.PP +\*S +commands are as follows (these are only those commands not also +available in \fBnutmeg\fR \- consult the \fBnutmeg\fR manual page for +more commands): +.TP +\fBsetcirc [circuit name]\fR +Change the current circuit. The current circuit is the one that is +used for the simulation commands below. When a circuit is loaded +with the \fIsource\fR command (see below) it becomes the +current circuit. +.TP +\fBop [.op card args]\fR +Do an operating point analysis. +.TP +\fBtran [.tran card args]\fR +Do a transient analysis. +.TP +\fBac [.ac card args]\fR +Do an ac analysis. +.TP +\fBdc [.dc card args]\fR +Do a dc transfer curve analysis. +.TP +\fBlisting [logical] [physical] [deck] [expand]\fR +Print a listing of the current circuit. If the \fBlogical\fR argument +is given, the listing is with all continuation lines collapsed +into one line, and if the \fBphysical\fR +argument is given the lines are printed out as they were found in +the file. The default is \fBlogical\fR. A \fBdeck\fR listing is just like +the \fBphysical\fR listing, except without the line numbers it recreates +the input file verbatim (except that it does not preserve case). +If the word \fBexpand\fR is present, the circuit will be printed with all +subcircuits expanded. +.TP +\fBedit [file]\fR +Print the current \*S deck into a file, call up the editor on that file +and allow the user to modify it, and then read it back in, replacing +the origonal deck. If a \fBfilename\fR is given, then edit that file +and load it, making the circuit the current one. +.TP +\fBresume\fR +Resume a simulation after a stop. +.TP +\fBshow \fR +Show a device parameter. +.TP +\fBalter \fR +Alter a device parameter. +.TP +\fBstate\fR +Print the state of the circuit. (This command is largely unimplemented.) +.TP +\fBsave [all] [output ...]\fR or \fB.save [all] [output ...]\fR +Save a set of outputs, discarding the rest. If a node has been mentioned +in a \fBsave\fR command, it will appear in the working plot after +a run has completed, or in the rawfile if spice is run in batch +mode. If a node is traced or plotted (see below) it will +also be saved. For backward compatibility, if there are \fBno\fR save +commands given, all outputs are saved. +.TP +\fBstop [ after n] [ when something cond something ] ... \fR +Set a breakpoint. The argument \fBafter n\fR means stop after \fBn\fR +iteration number \fBn\fR, and the argument +\fBwhen something cond something\fR means +stop when the first \fBsomething\fR is in the given relation with +the second \fBsomething\fR, the possible relations being +\fBeq\fR or = (equal to), +\fBne\fR or <> (not equal to), +\fBgt\fR or > (greater than), +\fBlt\fR or < (less than), +\fBge\fR or >= (greater than or equal to), and +\fBle\fR or <= (less than or equal to). +IO redirection is disabled for the \fBstop\fR command, since the relational +operations conflict with it (it doesn't produce any output anyway). +The \fBsomething\fR\&s above may be node names in +the running circuit, or real values. +If more than one condition is given, e.g. +\fBstop after 4 when v(1) > 4 when v(2) < 2\fR, the conjunction of +the conditions is implied. +.TP +\fBtrace [ node ...]\fR +Trace nodes. Every iteration the value of the node is printed to the +standard output. +.TP +\fBiplot [ node ...]\fR +Incrementally plot the values of the nodes while \*S runs. +.TP +\fBstep [number]\fR +Iterate \fBnumber\fR times, or once, and then stop. +.TP +\fBstatus\fR +Display all of the traces and breakpoints currently in effect. +.TP +\fBdelete [debug number ...]\fR +Delete the specified breakpoints and traces. The \fBdebug numbers\fR +are those shown by the \fBstatus\fR command. (Unless you do +\fBstatus > file\fR, in which case the debug numbers aren't printed.) +.TP +\fBreset\fR +Throw out any intermediate data in the circuit (e.g, after a breakpoint +or after one or more analyses have been done already), and re-parse +the deck. The circuit can then be re-run. (\fBNote\fR: this command +used to be \fBend\fR in \s-2SPICE\s+2 3a5 and earlier versions -- \fBend\fR +is now used for control structures.) The \fBrun\fR command will take +care of this automatically, so this command should not be necessary... +.TP +\fBrun [rawfile]\fR +Run the simulation as specified in the input file. If there were any +of the control cards .ac, .op, .tran, or .dc, they are executed. The output +is put in \fBrawfile\fR if it was given, in addition to being available +interactively. +.TP +\fBsource file\fR +Read the \*S input file \fBfile\fR. \fBNutmeg\fR and \*S commands may be +included in the file, and must be enclosed between the lines +\fI.control\fR and \fI.endc\fR. These commands +are executed immediately after the circuit is loaded, so a control line +of \fIac ...\fR will work the same as the corresponding \fI.ac\fR card. +The first line in any input file is considered a title +line and not parsed but kept as the name of the circuit. The +exception to this rule is the file \fI.spiceinit\fR. +Thus, a \*S command script must begin with a blank line and then with +a \fI.control\fR line. +Also, any line beginning with the characters *# is considered a control +line. This makes it possible to imbed commands in \*S input files +that will be ignored by earlier versions of \s-2SPICE\s+2. +\fINote:\fR in spice3a7 and before, the \fI.control\fR and \fI.endc\fR +lines were not needed, and any line beginning with the name of a front-end +command would be executed. +.TP +\fBlinearize vec ...\fR +Create a new plot with all of the vectors in the current plot, or +only those mentioned if arguments are given. The new vectors +will be interpolated onto a linear time scale, which is determined +by the values of \fBtstep, tstart,\fR and \fBtstop\fR in the +currently active transient analysis. The currently loaded deck +must include a transient analysis (a \fBtran\fR command may be run +interactively before the last \fBreset\fR, alternately), and the +current plot must be from this transient analysis. This command +is needed because \s-2SPICE\s+2\&3 doesn't output the results +from a transient analysis in the same manner that \s-2SPICE\s+2\&2 did. +.PP +There are several \fBset\fR variables that \*S uses but \fBnutmeg\fR +does not. They are: +.IP "" 16 +\fBeditor\fR +.br +The editor to use for the \fBedit\fR command. +.IP +\fBmodelcard\fR +.br +The name of the model card (normally \fB.model\fR). +.IP +\fBnoaskquit\fR +.br +Do not check to make sure that there are no circuits suspended and +no plots unsaved. Normally \*S will warn the user when he tries to +quit if this is the case. +.IP +\fBnobjthack\fR +.br +Assume that BJT's have 4 nodes. +.IP +\fBnoparse\fR +.br +Don't attempt to parse decks when they are read in (useful for +debugging). Of course, they +cannot be run if they are not parsed. +.IP +\fBnosubckt\fR +.br +Don't expand subcircuits. +.IP +\fBrenumber\fR +.br +Renumber input lines when a deck has \fB.include\fR's. +.IP +\fBsubend\fR +.br +The card to end subcircuits (normally \fB.ends\fR). +.IP +\fBsubinvoke\fR +.br +The prefix to invoke subcircuits (normally \fBx\fR). +.IP +\fBsubstart\fR +.br +The card to begin subcircuits (normally \fB.subckt\fR). +.PP +There are a number of \fBrusage\fR parameters available, in addition +to the ones available in \fBnutmeg\fR: +.IP "" 16 +.PP +If there are subcircuits in the input file, \*S expands instances of them. +A subcircuit is delimited by the cards +.B .subckt +and +.B .ends, +or whatever the value of the variables +.B substart +and +.B subend +is, respectively. An instance of a subcircuit is created by specifying +a device with type 'x' \- the device line is written +.IP +\fBxname node1 node2 ... subcktname\fR +.LP +where the nodes are the node names that replace the formal parameters +on the \fB.subckt\fR line. All nodes that are not formal parameters +are prepended with the name given to the instance and a ':', as are +the names of the devices in the subcircuit. If there are several nested +subcircuits, node and device names look like \fBsubckt1:subckt2:...:name\fR. +If the variable \fBsubinvoke\fR is set, then it is used as the prefix +that specifies instances of subcircuits, instead of 'x'. +.SH "VMS NOTES" +The standard suffix for rawspice files in VMS is ".raw". +.PP +You may have to redefine the value EDITOR if you wish to use the \fBedit\fR +command, since the default for VMS is "vi". +.SH "SEE ALSO" +nutmeg(1), sconvert(1), spice(1), mfb(3), writedata(3) +\*S User's Guide +.SH AUTHORS +\*S: Tom Quarles (quarles@cad.berkeley.edu) +.br +\fBnutmeg\fR / User interface: Wayne Christopher (faustus@cad.berkeley.edu) +.SH BUGS +.PP +\*S will recognise all the notations used in \s-2SPICE\s+2\&2 \fB.plot\fR +cards, and will translate \fBvp(1)\fR into \fBph(v(1))\fR, and so +forth. However, if there are spaces in these names it won't work. Hence +\fBv(1, 2)\fR and \fB(-.5, .5)\fR aren't recognised. +.PP +BJT's can have either 3 or 4 nodes, which makes it difficult for the subcircuit +expansion routines to decide what to rename. If the fourth parameter has +been declared as a model name, then it is assumed that there are 3 nodes, +otherwise it is considered a node. To disable this kludge, you can set +the variable "nobjthack", which will force BJT's to have 4 nodes (for the +purposes of subcircuit expansion, at least). +.PP +The \fB@name[param]\fR notation might not work with \fBtrace, iplot,\fR etc. +yet. +.PP +The first line of a command file (except for the \fI.spiceinit\fR file) +should be a comment. Otherwise \s-2SPICE\s+2 may create an empty circuit +structure. +.SH CAVEATS +.PP +\*S files specified on the command line are read in before the\fB .spiceinit\fR +file is read. Thus if you define aliases there that you call in a +\*S source file mentioned on the command line, they won't be recognised. + diff --git a/notes/Linux.changes b/notes/Linux.changes new file mode 100644 index 000000000..fd4d1329d --- /dev/null +++ b/notes/Linux.changes @@ -0,0 +1,164 @@ +So, this is third version of Spice3f5 for RedHat Linux 2.6. I took re-ported +version of spice3f5 and made changes to fix some bugs. If someone want to help, +please send me "newer" versions wtih more bugs fixed. +I hope that those who wnat to have good spice under Linux (no more Win95) +will find this port useful and maybe help each other to improve it. + +There was a lot of bugs in previus versions, generally in command parsiong routines. +I copy all original files to *.orig and marked all my changes with /* MW. ... */ + +I changed cp/bquote.c and cp/var2.c to handle some special situations +and commands like $foo, `foo`. Also problems with 'gets()' (in sconvert and +inp.c) function are fixed. I chnaget it to fgets(buf, BSIZE_SP, stdin) for +safe use. + +Globing ('[]{}?*') didn't work at all. Now it is removed (form cp/glob.c). +We don't need this features in spice. + +Initial command parsing (cp_lexer() from cp/lexical.c) strip all commas from +strings. This was in conflict with aritchetic expressions. + +com_let() in fte/postcoms.c caused core dump in some situations - fixed. + +Editor problems. Com_edit() in fte/inp.c failed occasionally, when it +tryies to fclose() fp second time. Now inp_spsource() always closes fp, and +other calling functions do not. It seems to work right now. + +vec_get() (fte/vectors.c) has some problems with devices parameters and +memory leaks. I hope that my changes fixed it at all. + +I have to add INPinsertNofree() in inp/inpsymt.c. This is special case for +routines from fte/spiceif.c and fte/outitf.c - It does not do free() for +any pointers that it gets. This may cause small memory leaks, but I don't +know how to make it better. + +com_alter_common() (fte/device.c) caused segmentation faults ocassionally, +due to double free the same pointers. It works right now. + +cp_lexer() corretly gets ^V, ^D, and ESC. I have to #include ioctl.h file in +cp/lexical.c and cp/complete.c + +There were problem with com_iplot() if it was called when X11 does not run. +I have to add additonal check to gr_pmsg() (from fte/graph.c) and now it +works fine. + +Trace failed to display comlex data due to segmentation fault. Someone wants +to plot realdata even if given vector was complex. I changed gr_iplot() +(in fte/graf.c) and now it is fine. + +There are some changes in os_linux.h and os_unix.h, but they are not mandatory, +I think. Also I have to add PI, and some other const. declarations in spice.h +They were needed somewhere. (why someone didn't used M_PI and so on instead ?) + +In file fte/x11.c, was a prloblem with background color for plot windows. I +changed init_colors() and now we can use color0 variable. + +Spice3f5 has a few memory leaks. I suppose that some vectors and maybe other +things are simple 'lost' somewhere. If you (just like me) trying to make this +program better, take care about this also. +Generally I didn't do much with graphisc interface, because it seems to work +quite good. Only problem is core dump, when cliking mouse on help screen. + +Manuals are sometimes in error. Vector creation by [ el. el. ...] is not +supported I think. For indexing we must use [low , hi]. For setting 'list' +variables - ( el. el. ... ). Indexing also doesn't work with let xx[...] = yy. + +Someone should change these f... manuals. + + +And now for those who think about makeing this program better. There is a big +problem with memory, when you run a few simulations. Destroy commad does not +free much memory, and after some time you can see that spice uses 3MB, when +you just clean all vectros. Also I don't know how to unload a circuit - +spice hold all sourced files in the "deck" list and there is no way to free +it from command line (or maybe I didn't find any). + Unfortunatelly I am sure that these are not all off the problems +with this program, but now I can use it quite effectively. If anyone will +know anything about bugs-free, good, commannd driven simulator for Linux +__PLEASE__ let me know. + +For easer use I made special debug file (conf/debug). I used it for makeing +"debug" version of spice with efence library and -g option. Executable files +from this are located in spice3f5/objdbg/bin, when you do 'util/build linux debug'. + +I am an electronic designer, so I really need a good working simulator... + +Original readme file is given below. + + Michael Widlok (widlok@uci.agh.edu.pl) + Uniersity of Mining and Metallurgy + Krakow, Poland. + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is my (re-)port of Spice3f4 to Linux version 2 (I am not the same +person who ported it before). It also wraps in the latest official +pre-3f5 patches from Berkeley I could find (found in +sp3f4.patch.tar.Z). Support for the MFB interface using the Linux +termcap library and some various Linux features have been ported. + +This was not done for the hell of it, but it seemed that something +broke due to some Linux/system/library changes, so I decided to try +porting it from scratch. In fact, if you don't have any problems with +the previous port, your probably fine then. However, if you do have +problems (e.g. exiting Spice leaves you in uppercase mode), or want +MFB for some reason, then try this. It seems to work here. + +Basically, I started out with sp3f4.kit.tar.Z. Then, I applied the +most recent patches contained in sp3f4.patch.tar.Z and wrote new Linux +build files: "linux" and "os_linux.h" (some minor mods to the source +were also necessary, protected with linux conditionals). + +Since the previous spice3f4.tar.gz port file was generally available, +there was no point in duplicating source, so I just diffed from the +spice3f4.tar.gz tree to freshly ported tree and edited or removed a +few of the diffs. A few of the changes made in spice3f4.tar.gz have +been reverted to the distribution defaults, but one notable change is +that performing the install step will install the necessary files into +/usr/local/spice. You'll need to add /usr/local/spice/bin to your +shell path. See the file conf/linux to change the installation +location (this location gets hard-coded in the spice binaries). + +This is a patched file of the original readme.Linux from +spice3f4.tar.gz, and the previous contents by Jeff@EE.Ryerson.Ca is +given below. Just follow the below instructions, so you should be +able to safely do: + + ./util/build linux + ./util/build linux install + +You should then find the spice binaries and library files +in e.g. /usr/local/spice. Example files and the man pages +are not installed, so you might want to copy them by hand. + +Andrew Veliath (veliaa@rpi.edu) +January 25, 1997 + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is my port of Spice3f4 to Linux. It required a few more changes +than the porting document indicated would be necessary, mostly to do +with supported/unsupported functions in Linux libc & libm. + +I've tried to make these changes in as as portable a way as possible, +so it should build cleanly on other Unicies, however I've removed the +MS-DOS support so the tarred and gziped source fits on one disk. + +To build spice3, first have a look in the file readme, but you should +be able to just do... + +./util/build linux +./util/build install linux + +Note that there is a modifyer "gcc" you can try if you have trouble, but +it claims to work around some obscure bug in gcc that I'm positive got +fixed eons ago. To use it anyway, do ./util/build linux gcc. + +I found this source through archie, (look for spice3f3.tar.Z, and then +patched it to 3f4 with patches from ic.berkeley.edu), I assume that the +ftp site I got it from has read thier license from Berkeley, which if +it's the same as the 3e2 license states that the holder can distribute +copies free of charge provided it does not fall into hands unfriendly +to the U.S. So... I guess if that's you, please destroy all copies of this +you might have! + +Jeff@EE.Ryerson.Ca diff --git a/notes/dbx b/notes/dbx new file mode 100644 index 000000000..c7c54c170 --- /dev/null +++ b/notes/dbx @@ -0,0 +1,7 @@ +A note when using dbx (under unix-type operating systems) to debug spice3: + +To avoid a segmentation fault in the initial run, use the following command +in dbx: + setenv SPICE_NO_DATASEG_CHECK "1" +Or, the comparable command in your shell before running dbx. This +disable accurate tracking of how much memory is used. diff --git a/notes/internal b/notes/internal new file mode 100644 index 000000000..a6bf6666c --- /dev/null +++ b/notes/internal @@ -0,0 +1,98 @@ +Internal Changes from 3e2 + + The device structure has changed: The state counter in all device + structures has been moved to correspond to GENstates in the + GENinstance structure. + + Also, a new per-device-type function has been added: XXXunsetup, + which deallocates nodes and other resources created in the + XXXsetup function. ("XXX" is the device abbreviation.) + +Internal Changes from 3d2 + +FILE NAMES: + + Of the changes to spice3 between 3d2 and 3e1, the + the most obvious is the new filenames. All filesnames + have been converted to lowercase and are at most eight + characters plus an optional dot and three character extension. + This change was made to accomodate MS-DOS and other operating + systems which limit the maximum file name length. + + +ORGANIZATION + + The top level directory contains the installation "readme" file + and a "makedefs" files used by the "build" command. + + "src/" contains all of the C source code. This used to be named + "spice3" or "spice3d2" in previous releases. + + "src/lib" is the library or "toolkit" portion of Spice3. Within + it are the following subdirectories: + + ckt/ All of the analysis code. + ni/ Numerical algorithms (used by ckt routines). + sparse/ Sparse matrix package (used by ckt and ni). + misc/ Miscellaneous utility and portability routines. + dev/ All of the device specific code, with a subdir for + each device implementation. + + inp/ Input parsing; could be much smaller. + + fte/ The front end. Really bad. + cp/ More front end -- "C shell". + hlp/ The windowed help system. + + mfb/ Terminal independant graphics package. + mfbpc/ MFB interface for the IBM PC. + + + "src/bin" contains the source for all executable programs (the + location for "main( )"). "main.c" is used by spice, nutmeg, + bspice, and cspice (the latter two for MS-DOS). The function + of "main.c" is altered by defining the pre-processor symbols + SIMULATOR (for either spice, bspice, or cspice), BATCH for + bspice, and BATCH and SPICE2 for cspice (no special defines + give nutmeg). Each variant of the simulator uses "conf.c" (or + "bconf.c" or "cconf.c", or "nconf.c" for nutmeg), which is + automatically generated from "config.c". "config.c" is a + template used to select devices and analyses. "tune.c" + ("tunepc.c") contains the compiled in pathnames. + + + "examples/" contains several spice input files. + + "lib/" contains standard data files for spice, such as the help + files and MFB capability files. + + "man/" contains UNIX style manual pages (ala "man(1)"). + + "util/" contains utility scripts, such as "build" for running the + recursive "make" and "delall.bat" for deleting the distribution on + MS-DOS systems. + + All "Makefile"s have been replaced with "makedefs" (and optionally + "depend" and "makeops"). "makedefs" is combined with other + make definition files with the "build" script. + +SOURCE LEVEL CHANGES + + (Added features are listed in the "README" file). + + DEVICES: The interface to devices has, once again, changed. + The change is small from 3d2. Table size values in the device + information struction are now pointers to integers containing + the table sizes. Per-analyses functions have been surrounded + with "#ifdef AN_xx"/"#else"/"#endif" lines. Note that the + "itf.h" files are stored only in the "include/" subdirectory. + + Adding devices to the master list is done in the file + "src/bin/config.c", instead of "FTE/SPIinit.c". + + SPARSE MATRIX PACKAGE: the sparse matrix package in Spice3e1 + and later is a more efficient implementation than in earlier releases. + The interface is the same. + + + diff --git a/notes/mac_port b/notes/mac_port new file mode 100644 index 000000000..921723936 --- /dev/null +++ b/notes/mac_port @@ -0,0 +1,207 @@ + + + Compiling spice with Think C on a Macintosh. + +A 68020 (Mac II) with co-processor is required. + +The src directory from the spice distribution should be moved into +the C folder. + +**** recompile think c libraries **** + + Both the ANSI and unix libraries must be recompiled with the + following additional compiler settings: + Generate 68020 instructions + Generate 68881 instructions + 4-bytes ints + Native floating-point format + + The "console.c" file must be edited and should be removed from + the ANSI project. I actually recompiled copies of the ANSI and + unix libraries that I called ANSI.68881 and unix.68881. + Copy the "console.c" source (a THINK C file) to a suitable + location so that it can be included in the spice project. (See + the next section for details of how "consol.c" must be modified.) + + +**** creating the project **** + + Create a new project and set the Options as follows: + Laguage Settings + Turn on the following options + Define #__STDC__ + Recognize trigraphs + enums are always ints + Check pointer types + Language Extension + THINK C + Compiler Settings + Turn on the following options + Generate 68020 instructions + Generate 68881 instructions + 4-bytes ints + Native floating-point format + Code Optimization + Turn on all options + Prefix + make sure there is no prefix (remove + default #include ) + + Note: The Language setting 'Strict Prototype Enforcement' must be + turned off. + + Set the project type to application with at least 1024k partition + and turn on the 'Far DATA' option. + +*** Adding the code to the project *** + + Start Adding the code to the project. The code must be divided + into segments that are less that 32K each when compiled. The + following division has been used: + + Segment 1: the ANSI.68881 and unix.68881 libraries. + Segment 2: all *.c files in /src/sparse + Segment 3: all *.c files in /src/lib/ni + Segment 4: all *.c files in /src/lib/misc + Segment 5: files /src/lib/inp/inp2dot.c + and /src/lib/inp/inptree.c + Segment 6: all other *.c files in /src/inp + Segment 7: all *.c files in /src/lib/hlp + Segment 8: all *.c files in /src/lib/cp + except /src/lib/cp/input.c + Segment 9: file /src/lib/ckt/dloadfns.c + Segment 10: files /src/lib/ckt/cktpzstr.c, + /src/lib/ckt/cktsens.c, /src/lib/ckt/dctran.c, + and /src/lib/ckt/distoan.c + Segment 11: all other *.c files in /src/lib/ckt + Segment 12: cmath*.c files in /src/lib/fte + Segment 13: files agraf.c, clip.c, display.c, graf.c, + graphdb.c, plot5.c, plotcurv.c and + postsc.c in /src/lib/fte + + Segment 14: files evaluate.c, parse.c, postcoms.c, + and subckt.c in /src/lib/fte + Segment 15: files breakp.c, device.c, doplot.c, + grid.c and shyu.c in /src/lib/fte + Segment 16: files dotcards.c, inp.c, outif.c, rawfile.c, + spiceif.c and vectors.c in /src/lib/fte + Segment 17: all other *.c files in /src/lib/fte + except nutmegif.c + Segment 18: all *.c files in /src/lib/fte/vsrc + and /src/lib/fte/isrc + Segment 19: all *.c files in /src/lib/fte/jfet + Segment 20: all *.c files in /src/lib/fte/vccs, + /src/lib/fte/vcvs, /src/lib/fte/cccs, + and /src/lib/fte/ccvs + Segment 21: all *.c files in /src/lib/fte/asrc + and /src/lib/fte/urc + Segment 22: all *.c files in /src/lib/fte/cap, + /src/lib/fte/ind, and /src/lib/fte/res + Segment 23: all *.c files in /src/lib/fte/csw, + /src/lib/fte/sw, and /src/lib/fte/tra + Segment 24: all *.c files in /src/lib/fte/mos6 + Segment 25: all *.c files in /src/lib/fte/mes + Segment 26: all *.c files in /src/lib/fte/ltra + Segment 27: file mos3load.c in /src/lib/fte/mos3 + Segment 28: files mos3dist.c, mos3dset.c, + and mos3sld.c in /src/lib/fte/mos3 + Segment 29: remaining *.c files in /src/lib/fte/mos3 + Segment 30: all *.c files in /src/lib/fte/dio + Segment 31: file mos1load.c in /src/lib/fte/mos1 + Segment 32: files mos1dist.c, mos1dset.c, + and mos1sld.c in /src/lib/fte/mos1 + Segment 33: remaining *.c files in /src/lib/fte/mos1 + Segment 34: file bjtload.c in /src/lib/fte/bjt + Segment 35: files bjtdisto.c, bjtdset.c, + and bjtsload.c in /src/lib/fte/bjt + Segment 36: remaining *.c files in /src/lib/fte/bjt + Segment 37: file mos2load.c in /src/lib/fte/mos2 + Segment 38: file mos2dset.c in /src/lib/fte/mos2 + Segment 39: files mos2dist.c, and mos2sld.c + in /src/lib/fte/mos2 + Segment 40: remaining *.c files in /src/lib/fte/mos2 + Segment 41: files b1dset.c, and b1ld.c in /src/lib/fte/bsim1 + Segment 42: files b1disto.c, and b1eval.c in /src/lib/fte/bsim1 + Segment 43: remaining *.c files in /src/lib/fte/bsim1 + Segment 44: files b2eval.c, and b2ld.c in /src/lib/fte/bsim2 + Segment 45: remaining *.c files in /src/lib/fte/bsim2 + Segment 46: all *.c files in /src/lib/dev/disto, + and devsup.c in /src/lib/dev + Segment 47 all *.c files in /src/lib/mac, + and file /src/bin/main.c + + Note that the following files are not included: + /src/lib/cp/input.c + /src/lib/fte/nutmegif.c + + Add "console.c" (the copy made as described above) and make the + following alterations to it: + 1. The lines: + static char console_environment, noPrint, interrupted; + static short console_refnum; + static MenuHandle appleMenu; + static WindowPeek theConsole; + + must be changed to make console_environment and + appleMenu external: + extern char console_environment, noPrint, interrupted; + static char noPrint, interrupted; + static short console_refnum; + extern MenuHandle appleMenu; + static WindowPeek theConsole; + + 2. Alter the function ProcessEvent() to add a default switch + case. The altered section appears following a doEvent label as + (note: this code fragment has 4-space tabs and long lines + broken to fit an 80-column page; these changes do not affect + the code): + + doEvent: + if (event.what == mouseDown) { + switch (FindWindow(event.where, &wp)) { + case inMenuBar: + InitCursor(); + choice = MenuSelect(event.where); + goto doMenu; + case inSysWindow: + SystemClick(&event, wp); + break; + default: /* For spice to pass mouse + events to graphs */ + if ((WindowPtr) wp != FrontWindow()) { + SelectWindow(wp); + in.cnt = 0; + } /* in.cnt=0 forces console to + return to application */ + } + } + + + + + + Compilation takes about 3 to 4 hours on a 25MHz mac. Set the cache + to at least 256k to eliminate a lot of disk access. + +**** makeindx **** + Create a project with the same option settings decribed above. + + Add src/bin/makeidx.c, ANSI.68881 and an unmodified version of + "console.c". + + Build the makeindex application. + + Move the application into lib/helpdir directory of the the spice + distribution. Run it and add the names of the files to be indexed + (nutmeg.txt spice.txt) to the command line and hit return. + +**** proc2mod **** + + Create a project with the same option settings decribed above. + + Add src/bin/proc2mod.c, src/lib/misc/alloc.c, src/lib/misc/string.c + src/lib/inp/inpcfix.c, src/lib/inp/inpeval.c, + src/lib/inp/inpgtok.c, ANSI.68881 and an unmodified + version of console.c. + + Build the proc2mod application. diff --git a/notes/porting b/notes/porting new file mode 100644 index 000000000..7ef93a409 --- /dev/null +++ b/notes/porting @@ -0,0 +1,237 @@ +(ER - 7/08/99) + +These are a few notes on the autoconf porting that is being done. + +Autoconf automaticcaly provides #defines (in config.h) that describe +the system that ng-spice is being compiled on. Thus, all the os_xxx.h +files should no longer be necessary. + + +Here is a (as complete as possible) list of new #defines and their +corresponding #defines in the old build system: + + + + +#define HAS_VAX_FPERRORS - unused (should remove the code) +#define MAXPOSINT 4294967295 - don't know about that one +#define MAX_EXP_ARG 87.0 - same + +---------- Operating System (os_xxx.h) parameters: + +----- Enabling flags +#define AVAIL_MFB -DWANT_MFB passed to cpp +#define AVAIL_X11 X_DISPLAY_MISSING (reversed) + +----- String or character constants +#define DIR_CWD "." now in spice.h +#define DIR_PATHSEP "/" now in spice;h +#define DIR_TERM '/' now in spice.h + +On Unix, I don't think that there are other possibilities. +We should get rid of those. + + +----- sprintf( ) format strings +#define TEMPFORMAT "/tmp/%s%d" /* sprintf format for creating temp files */ +#define SYSTEM_MAIL "mail -s \"%s (%s) Bug Report\" %s" /* mail command */ +#define SYSTEM_PLOT5LPR "lpr -P%s -g %s" /* For printing Unix plot(5) files */ +#define SYSTEM_PSLPR "lpr -P%s %s" /* For printing postscript files */ + + +Same for these I guess... + + + +----- System capabilities +#define HAS_ACCESS HAVE_ACCES +#define HAS_ASCII not handled yet +#define HAS_ATRIGH HAVE_ATANH HAVE_ACOSH HAVE_ASINH +#define HAS_BCOPY HAVE_BCOPY +#define HAS_BSDDIRS HAVE_DIR_H +#define HAS_BSDRANDOM unused +#define HAS_BSDRLIMIT HAVE_GETRLIMIT +#define HAS_BSDRUSAGE HAVE_GETRUSAGE +#define HAS_BSDSOCKETS unused +#define HAS_BSDTIME HAVE_GETTIMEOFDAY +#define HAS_BSDTTY HAVE_SGTTY_H +#define HAS_CHDIR removed +#define HAS_CLEARERR removed +#define HAS_CTYPE HAVE_CTYPE_H +#define HAS_DOSDIRS dos only - should remove code +#define HAS_DUP2 HAVE_DUP2 +#define HAS_ENVIRON removed +#define HAS_EXIT1 vms only - should remove the code +#define HAS_FCNTL HAVE_FCNTL_H +#define HAS_FTIME HAVE_FTIME +#define HAS_GETCWD HAVE_GETCWD +#define HAS_GETPID removed +#define HAS_GETPW HAVE_PWD_H +#define HAS_GETWD HAVE_GETWD +#define HAS_INDEX HAVE_INDEX +#define HAS_NO_IEEE_LOGB HAVE_LOGB HAVE_SCALB HAVE_SCALBN +#define HAS_NO_IEEE_LOGB_DECL removed +#define HAS_ISATTY HAVE_ISATTY +#define HAS_LONGJUMP removed +#define HAS_MINDATA dos only? - should remove code if so +#define HAS_NOINLINE dos only? - should remove code if so +#define HAS_NOVM dos only? - should remove code if so +#define HAS_NO_ATRIGH_DECL removed +#define HAS_PCTERM dos only - should remove code +#define HAS_POPEN HAVE_POPEN +#define HAS_QSORT HAVE_QSORT +#define HAS_SHORTMACRO dos only - should remove code +#define HAS_STAT STAT_MACROS_BROKEN (reversed) +#define HAS_STDLIB STDC_HEADERS +#define HAS_STRCHR HAVE_STRCHR +#define HAS_STRINGS STDC_HEADERS (reversed) not sure about that one! +#define HAS_SYSTEM removed +#define HAS_SYSVDIRS HAVE_DIRENT_H +#define HAS_SYSVRLIMIT HAVE_ULIMIT +#define HAS_SYSVRUSAGE HAVE_UTIME +#define HAS_SYSVTIME HAVE_TIME +#define HAS_SYSVTTY HAVE_TERMIO_H +#define HAS_TERMCAP HAVE_TERMCAP +#define HAS_TERMREAD don't know what to do with this one +#define HAS_UNIX_SIGS removed +#define HAS_UNLINK removed +#define HAS_VFORK HAVE_VFORK_H +#define HAS_VMSHACK vms only - should remove the code +#define HAS_VPERROR removed +#define HAS_WAIT HAVE_WAIT + +plus a few others: + +#define HAS_MEMAVL dos only - should remove code +#define HAS_FLAT_INCLUDES macos only - should remove code +#define HAS_BATCHSIM dos only - should remove code + + + +---------------------------------------------------------------------------- + +PORTING SPICE3e1 + + Porting Spice3 to a new operating system usually consists of listing + the capabilities of that operating system in a new '.h' file and + including this '.h' file in the standard portability sequence. This + also needs to be done separately for the numerical capabilities of the + system hardware (this consist of only two parameters at present). + + For each operating system there is a file in the "include/" directory + named "os_xxx.h", where xxx identifies the given operating system (ex. + "os_bsd.h", "os_aix.h"). These files are selectively #include-d by + "include/port.h". For a new operating system, you should add the + appropriate "#include" line to "include/port.h". Be sure to guard + the new "#include" line with "#ifdef/#endif", as is done with the other + operating system capability files. The same may also need to be done + for your hardware (for the file "hw_xxx.h"), though there is typically + very little difference in hardware. + + Note that operating system which are a derivative of another supported + system can '#include' the "os_xxx.h" file from the other system. For + example, "os_aix.h" includes "os_sysv.h", which in turn includes + "os_unix.h". + + The entries that can go into a "os_xxx.h" file are described below; + most are simple flags (e.g. HAS_xxxx). To turn on a flag, insert the + "#define" line for that flag; to turn off the flag, simply leave the + "#define" line out. Other entries are strings, others single-quoted + characters or numbers. Be sure to use the same type as the example + values shown. + + There are always exceptions to the rule. Some incompatibilities + have not yet been dealt with cleanly; review the other "os_xxx.h" + files, the file "capabil.h", and the file "suffix.h" to understand + how some problems have been handled (note especially the lines like + "#define index strchr"). After trying to compile, you may yet find + non-portable code that is not guarded by one of the following + options. You are encouraged to alter the source code (".c" or ".h" + files) in the style of the current portability scheme. + + Note: to enable X11 or MFB, the flag AVAIL_X11 or AVAIL_MFB, + respectively, must be included in the "os_xxx.h" file; this _was_ to + simplify the problems of forgetting to re-edit the "config.h" file, + but this is no longer necessary. + +---------- Machine architecture numerics (hw_xxx.h) parameters: + (In the future this will be more complete and will be used for + tuning the accuracy or performance of the numerical algorithms) + +#define HAS_VAX_FPERRORS /* Only for Vax */ +#define MAXPOSINT 4294967295 /* == 2^32 - 1, maximum positive integer */ +#define MAX_EXP_ARG 87.0 /* Approximate largest arg to exp() */ + +---------- Operating System (os_xxx.h) parameters: + +----- Enabling flags +#define AVAIL_MFB /* If the MFB package can work on this system */ +#define AVAIL_X11 /* If the X11 Window System can work */ + +----- String or character constants +#define DIR_CWD "." /* Current working directory */ +#define DIR_PATHSEP "/" /* subdirectory separator */ +#define DIR_TERM '/' /* Subdirectory component terminator */ + +----- sprintf( ) format strings +#define TEMPFORMAT "/tmp/%s%d" /* sprintf format for creating temp files */ +#define SYSTEM_MAIL "mail -s \"%s (%s) Bug Report\" %s" /* mail command */ +#define SYSTEM_PLOT5LPR "lpr -P%s -g %s" /* For printing Unix plot(5) files */ +#define SYSTEM_PSLPR "lpr -P%s %s" /* For printing postscript files */ + +----- System capabilities +#define HAS_ACCESS /* access( ) */ +#define HAS_ASCII /* eighth bit of a character is not used */ +#define HAS_ATRIGH /* acosh( ), asinh( ), atanh( ) */ +#define HAS_BCOPY /* bcopy( ), bzero( ) */ +#define HAS_BSDDIRS /* */ +#define HAS_BSDRANDOM /* srandom( ) and random( ) */ +#define HAS_BSDRLIMIT /* getrlimit( ) returns proc limits */ +#define HAS_BSDRUSAGE /* getrusage( ) returns cpu usage */ +#define HAS_BSDSOCKETS /* , socket( ), etc. */ +#define HAS_BSDTIME /* gettimeofday( ) return time */ +#define HAS_BSDTTY /* */ +#define HAS_CHDIR /* for tree filesystems, chdir( ) */ +#define HAS_CLEARERR /* clearerr( ), should be in stdio */ +#define HAS_CTYPE /* , iswhite( ), etc. */ +#define HAS_DOSDIRS /* Emulate opendir, etc. */ +#define HAS_DUP2 /* dup2(a, b) for shifting file descrs. */ +#define HAS_ENVIRON /* getenv( ) */ +#define HAS_EXIT1 /* If exit status of 1 is normal for procs */ +#define HAS_FCNTL /* acosh( ), asinh( ), atanh( ) */ +#define HAS_FTIME /* ftime( ), */ +#define HAS_GETCWD /* getcwd(buf, size) */ +#define HAS_GETPID /* getpid( ) to identify processes */ +#define HAS_GETPW /* getpwuid( ), etc. */ +#define HAS_GETWD /* getwd(buf) */ +#define HAS_INDEX /* index( ) instead of strchr( ) */ +#define HAS_NO_IEEE_LOGB /* no logb( ) and scalb( ) functions */ +#define HAS_NO_IEEE_LOGB_DECL /* logb( ) and scalb( ) not in math.h */ +#define HAS_ISATTY /* isatty( ) */ +#define HAS_LONGJUMP /* setjmp( ), longjmp( ) */ +#define HAS_MINDATA /* Machine has limited data area */ +#define HAS_NOINLINE /* Machine has limited data area */ +#define HAS_NOVM /* Machine has limited data area */ +#define HAS_NO_ATRIGH_DECL /* if asinh( ) is not in math.h */ +#define HAS_PCTERM /* For MS-DOS, use PC graphics for MFB */ +#define HAS_POPEN /* popen( ), pipe through shell command */ +#define HAS_QSORT /* qsort( ) exists */ +#define HAS_SHORTMACRO /* If the compiler can't handle long macros */ +#define HAS_STAT /* stat( ) returns info on files */ +#define HAS_STDLIB /* #include for libc defs */ +#define HAS_STRCHR /* strchr( ) instead of index( ) */ +#define HAS_STRINGS /* #include (else ) */ +#define HAS_SYSTEM /* system( ), execute system command */ +#define HAS_SYSVDIRS /* */ +#define HAS_SYSVRLIMIT /* ulimit( ) reports on proc size limit */ +#define HAS_SYSVRUSAGE /* utimes( ) reports on cpu usage */ +#define HAS_SYSVTIME /* time( ) returns seconds from 1970 */ +#define HAS_SYSVTTY /* */ +#define HAS_TERMCAP /* tgetxxx( ) */ +#define HAS_TERMREAD /* Has "read" syscall from terminals */ +#define HAS_UNIX_SIGS /* signal( ), kill( ) */ +#define HAS_UNLINK /* unlink( ), for removing files */ +#define HAS_VFORK /* BSD-ism, should not be necessary */ +#define HAS_VMSHACK /* Stand on your head for VMS */ +#define HAS_VPERROR /* perror( ) defined by standard '.h's */ +#define HAS_WAIT /* wait( ) wait for processes */ diff --git a/notes/spice2 b/notes/spice2 new file mode 100644 index 000000000..0e239036e --- /dev/null +++ b/notes/spice2 @@ -0,0 +1,15 @@ + + Incompatibilities between spice3 and spice2 + +The output format of spice3 is slightly different for .print and .plot lines. +Most notably, different traces on plots are not scaled independently. This +is most noticeable on phase/magnitude plots from an AC analysis (also, +phase is displayed in radians). Finally, frequency for ".PRINT AC" lines +is displayed as a complex quantity with an all-zero imaginary component. + +For input, "POLY( )" sources are not supported (the non-linear dependent +source provides a more general replacement). Also, the ".ALTER" line +is not supported. The Spice3 parser may be slightly different +on subtle points of reading input (lines need not start at column 1 +for instance). + diff --git a/src/ChangeLog b/src/ChangeLog new file mode 100644 index 000000000..04999df89 --- /dev/null +++ b/src/ChangeLog @@ -0,0 +1,97 @@ +2000-04-04 Paolo Nenzi + + * ngspice.c: Added support for BSIM4. + + * Makefile.am: Added support for bsim4 shared library. + +2000-01-14 Paolo Nenzi + + * conf.c: inserted definitions for bsim3v2 and bsim3v1 devices. + It is necessary to include old models for commercially available + components libraries. + +1999-12-01 Emmanuel Rouat + + * source code: created new directory 'frontend' mainly filled with + files from 'fte' - remaing files go into maths/cmaths (complex maths + routines) + +1999-11-30 Emmanuel Rouat + + * tune.c: removed + + * conf.c/nconf.c : simplified + +1999-09-07 Arno + + * conf.c: removed unused variables `devs' and `ans' + + * help.c: return value from main() changed to int + +1999-09-04 Emmanuel Rouat + + * main.c: removed #include patchlec.h and suffix.h (and related code) + + * Makefile.am: updated to reflect filename changes in fte/ + +1999-08-31 Emmanuel Rouat + + * help.c: renamed helpfile 'ngspice' + + * main.c: renamed helpfile 'ngspice' + +1999-08-28 Emmanuel Rouat + + * Removed all #includes of misc.h and util.h (now in spice.h) + +1999-08-24 Paolo Nenzi + + * conf.c: linked the jfet2 model to the devices table. + +1999-08-08 Emmanuel Rouat + + * makeidx.c: removed HAS_MAC_ARCARGV related code + + * main.c: removed all code related to dos and macos features + +1999-08-06 Emmanuel Rouat + + * proc2mod.c: removed test on HAS_VPERROR (always true on Unix) + + * main.c (main): changed HAS_ISATTY in HAVE_ISATTY + (main): removed test on HAS_LONGJUMP (always have it) + (main): removed test on HAS_UNIX_SIGS (always true on Unix) + (main): removed test on HAS_UNLINK (always true on Unix) + +1999-08-05 Emmanuel Rouat + + * main.c: changed HAS_GETPW in HAVE_PWD_H + (main): removed test on HAS_GETPID + +1999-08-02 Emmanuel Rouat + + * Makefile.am (LIBS): removed '-lm' since it is handled by autoconf + +1999-08-01 Emmanuel Rouat + + * conf.c: changed SIMinfo entry to 'ngspice' + + * Makefile.am: changed binary name to ngspice + +1999-07-31 Emmanuel Rouat + + * Makefile.am: added @X_CFLAGS@ to INCLUDES list + +1999-07-30 Emmanuel Rouat + + * Makefile.am : fixed breaking of 'make distcheck' + +29-07-1999 emmanuel.rouat@wanadoo.fr (Manu Rouat) + + * tune.c: includes which defines SPICEBINDIR etc + +28-07-1999 emmanuel.rouat@wanadoo.fr (Manu Rouat) + + * help.c: Changed HAS_X11 define to X_DISPLAY_MISSING (supplied by + autoconf in config.h) + * removed HAS_X11 in defs flag in Makefile.am diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 000000000..24f81d8b4 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,162 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = analysis circuit devices frontend hlp maths misc parser include + +bin_PROGRAMS = ngspice nutmeg help sconvert proc2mod multidec makeidx + +EXTRA_DIST = ngspice.txt ngspice.idx + +helpdatadir = $(pkgdatadir)/helpdir + +helpdata_DATA = ngspice.idx ngspice.txt + + + +DYNAMIC_DEVICELIBS = \ + devices/asrc/libasrc.la \ + devices/bjt/libbjt.la \ + devices/bsim1/libbsim1.la \ + devices/bsim2/libbsim2.la \ + devices/bsim3/libbsim3.la \ + devices/bsim4/libbsim4.la \ + devices/bsim3v1/libbsim3v1.la \ + devices/bsim3v2/libbsim3v2.la \ + devices/cap/libcap.la \ + devices/cccs/libcccs.la \ + devices/ccvs/libccvs.la \ + devices/csw/libcsw.la \ + devices/devsup/libdevsup.la \ + devices/dio/libdio.la \ + devices/disto/libdisto.la \ + devices/ind/libind.la \ + devices/isrc/libisrc.la \ + devices/jfet/libjfet.la \ + devices/jfet2/libjfet2.la \ + devices/ltra/libltra.la \ + devices/cccs/libcccs.la \ + devices/ccvs/libccvs.la \ + devices/csw/libcsw.la \ + devices/devsup/libdevsup.la \ + devices/dio/libdio.la \ + devices/disto/libdisto.la \ + devices/ind/libind.la \ + devices/isrc/libisrc.la \ + devices/jfet/libjfet.la \ + devices/jfet2/libjfet2.la \ + devices/ltra/libltra.la \ + devices/mes/libmes.la \ + devices/mos1/libmos1.la \ + devices/mos2/libmos2.la \ + devices/mos3/libmos3.la \ + devices/mos6/libmos6.la \ + devices/res/libres.la \ + devices/sw/libsw.la \ + devices/tra/libtra.la \ + devices/urc/liburc.la \ + devices/vccs/libvccs.la \ + devices/vcvs/libvcvs.la \ + devices/vsrc/libvsrc.la + +## Build ngspice first: + +ngspice_SOURCES = \ + conf.c \ + conf.h \ + ngspice.c + +ngspice_LDADD = \ + spice.o \ + frontend/libfte.a \ + $(DYNAMIC_DEVICELIBS) \ + analysis/libckt.a \ + parser/libparser.a \ + hlp/libhlp.a \ + circuit/libinp.a \ + maths/cmaths/libcmaths.a \ + maths/ni/libni.a \ + maths/sparse/libsparse.a \ + misc/libmisc.a + + +spice.o: main.c + $(COMPILE) -DSIMULATOR -o spice.o -c $(srcdir)/main.c + +## nutmeg: + +nutmeg_SOURCES = \ + main.c \ + conf.c \ + conf.h \ + nutmeg.c + +nutmeg_LDADD = \ + frontend/libfte.a \ + parser/libparser.a \ + hlp/libhlp.a \ + maths/cmaths/libcmaths.a \ + misc/libmisc.a + + + +## help: + +help_SOURCES = help.c + +help_LDADD = \ + hlp/libhlp.a \ + parser/libparser.a \ + misc/libmisc.a + + +## sconvert: + +sconvert_SOURCES = sconvert.c + + + +sconvert_LDADD = \ + frontend/libfte.a \ + parser/libparser.a \ + misc/libmisc.a + + +## proc2mod: + +proc2mod_SOURCES = proc2mod.c + +proc2mod_LDADD = \ + parser/libparser.a \ + circuit/libinp.a \ + misc/libmisc.a + + + +## multidec: + +multidec_SOURCES = multidec.c + +multidec_LDADD = \ + maths/sparse/libsparse.a \ + misc/libmisc.a + +## makeidx: + +makeidx_SOURCES = makeidx.c + +makeidx_LDADD = \ + misc/libmisc.a + +## create index for online help: + +all: + ./makeidx $(srcdir)/ngspice.txt + + +## General Includes and libraries: + + +INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/devices @X_CFLAGS@ + +LIBS = @LIBS@ @X_LIBS@ @X_PRE_LIBS@ @X_EXTRA_LIBS@ + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/analysis/ChangeLog b/src/analysis/ChangeLog new file mode 100644 index 000000000..dc7647af0 --- /dev/null +++ b/src/analysis/ChangeLog @@ -0,0 +1,60 @@ +2000-04-04 Paolo Nenzi + + * noisean.c: + Bug: he ac noise analysis in Spice3f4 has a serious bug. In interactive mode, + it fails to reproduce frequency dependence known to exist. In batch (Spice2) + mode, it works only if a corresponding ac analysis has been run first. + Fix: This bug is fixed by providing a call to CKTload() in noisean.c as shown + by the source code patch which is attached below. + + +1999-09-08 Emmanuel Rouat + + * ckt.h: created (and included in Makefile.am) + +1999-09-07 Arno + + * cktpzstr.c: reformatted and corrected(?) complex if condition. + +1999-08-28 Emmanuel Rouat + + * Removed all #includes of misc.h and util.h (now in spice.h) + +1999-08-27 Paolo Nenzi + + * Removed GENERIC and #include "suffix.h" from all the files. + GENERIC has been replaced by void. ANSIfied all functions with + protoize. + +1999-08-26 Paolo Nenzi + + * cktacct.c: added #include "spmatrix.h" to avoid implicit declaration + warning at compile time. + + * dctran.c: ansified and substituted void with void. + * tranasq.c: same as before. + * traninit.c: same as before. + * transetp.c: same as before. + + +1999-08-08 Emmanuel Rouat + + * Removed all HAS_SHORTMACRO and HAS_FLATINCLUDES code in directory + + * cktdest.c (and other files): changed HAS_SENSE2 in WANT_SENSE2 + +1999-08-04 Paolo Nenzi + + * changed dctrcurv.c: added code for temperature sweeps and + resistance sweeps. Now you can execute .dc temp + to do a temp sweep, temp is the keyword for temp + sweeps (The code comes from a patch supplied by Serban-Mihai + Popescu . To do a resitance sweep just + insert resistor name to the .cd line:.dc vin -5 5 1 rin 100 1000 10. + Resistance and temperature sweeps can be nested. diff --git a/src/analysis/Makefile.am b/src/analysis/Makefile.am new file mode 100644 index 000000000..104e57ae6 --- /dev/null +++ b/src/analysis/Makefile.am @@ -0,0 +1,106 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libckt.a + +libckt_a_SOURCES = \ + acan.c \ + acaskq.c \ + acsetp.c \ + cktaccpt.c \ + cktacct.c \ + cktacdum.c \ + cktask.c \ + cktaskaq.c \ + cktasknq.c \ + cktbindn.c \ + cktbkdum.c \ + cktclrbk.c \ + cktcrte.c \ + cktdelt.c \ + cktdest.c \ + cktdisto.c \ + cktdlti.c \ + cktdltm.c \ + cktdltn.c \ + cktdojob.c \ + cktdump.c \ + cktfbran.c \ + cktfdev.c \ + cktfnda.c \ + cktfndm.c \ + cktfnode.c \ + cktftask.c \ + cktgrnd.c \ + ckti2nod.c \ + cktic.c \ + cktinit.c \ + cktlnkeq.c \ + cktload.c \ + cktmapn.c \ + cktmask.c \ + cktmcrt.c \ + cktmkcur.c \ + cktmknod.c \ + cktmkvol.c \ + cktmpar.c \ + cktnames.c \ + cktnewan.c \ + cktneweq.c \ + cktnewn.c \ + cktnodn.c \ + cktnoise.c \ + cktntask.c \ + cktnum2n.c \ + cktop.c \ + cktparam.c \ + cktpartn.c \ + cktpmnam.c \ + cktpname.c \ + cktpzld.c \ + cktpzset.c \ + cktpzstr.c \ + cktsens.c \ + cktsetap.c \ + cktsetbk.c \ + cktsetnp.c \ + cktsetup.c \ + cktsgen.c \ + cktsopt.c \ + ckttemp.c \ + cktterr.c \ + ckttroub.c \ + ckttrunc.c \ + ckttyplk.c \ + daskq.c \ + dcoaskq.c \ + dcop.c \ + dcosetp.c \ + dctaskq.c \ + dctran.c \ + dctrcurv.c \ + dctsetp.c \ + distoan.c \ + dkerproc.c \ + dloadfns.c \ + dsetparm.c \ + naskq.c \ + nevalsrc.c \ + ninteg.c \ + noisean.c \ + nsetparm.c \ + pzan.c \ + pzaskq.c \ + pzsetp.c \ + sensaskq.c \ + senssetp.c \ + tfanal.c \ + tfaskq.c \ + tfsetp.c \ + tranaskq.c \ + traninit.c \ + transetp.c \ + ckt.h + + +INCLUDES = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/devices +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/analysis/acan.c b/src/analysis/acan.c new file mode 100644 index 000000000..ce15f7fce --- /dev/null +++ b/src/analysis/acan.c @@ -0,0 +1,277 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "acdefs.h" +#include "devdefs.h" +#include "sperror.h" + + +int +ACan(CKTcircuit *ckt, int restart) +{ + + double freq; + double freqTol; /* tolerence parameter for finding final frequency */ + double startdTime; + double startsTime; + double startlTime; + double startcTime; + double startkTime; + double startTime; + int error; + int numNames; + IFuid *nameList; + IFuid freqUid; + static void *acPlot; + void *plot; + + if(((ACAN*)ckt->CKTcurJob)->ACsaveFreq == 0 || restart) { + /* start at beginning */ + + if (((ACAN*)ckt->CKTcurJob)->ACnumberSteps < 1) + ((ACAN*)ckt->CKTcurJob)->ACnumberSteps = 1; + + switch(((ACAN*)ckt->CKTcurJob)->ACstepType) { + + case DECADE: + ((ACAN*)ckt->CKTcurJob)->ACfreqDelta = + exp(log(10.0)/((ACAN*)ckt->CKTcurJob)->ACnumberSteps); + break; + case OCTAVE: + ((ACAN*)ckt->CKTcurJob)->ACfreqDelta = + exp(log(2.0)/((ACAN*)ckt->CKTcurJob)->ACnumberSteps); + break; + case LINEAR: + if (((ACAN*)ckt->CKTcurJob)->ACnumberSteps-1 > 1) + ((ACAN*)ckt->CKTcurJob)->ACfreqDelta = + (((ACAN*)ckt->CKTcurJob)->ACstopFreq - + ((ACAN*)ckt->CKTcurJob)->ACstartFreq)/ + (((ACAN*)ckt->CKTcurJob)->ACnumberSteps-1); + else + ((ACAN*)ckt->CKTcurJob)->ACfreqDelta = HUGE; + break; + default: + return(E_BADPARM); + } + error = CKTop(ckt, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, + ckt->CKTdcMaxIter); + if(error) return(error); + + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; + error = CKTload(ckt); + if(error) return(error); + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + + if (ckt->CKTkeepOpInfo) { + /* Dump operating point. */ + error = (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob, "AC Operating Point", + (IFuid)NULL,IF_REAL,numNames,nameList, IF_REAL,&plot); + if(error) return(error); + CKTdump(ckt,(double)0,plot); + (*(SPfrontEnd->OUTendPlot))(plot); + } + + (*(SPfrontEnd->IFnewUid))((void *)ckt,&freqUid,(IFuid)NULL, + "frequency", UID_OTHER,(void **)NULL); + error = (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob, + ckt->CKTcurJob->JOBname,freqUid,IF_REAL,numNames,nameList, + IF_COMPLEX,&acPlot); + if(error) return(error); + + if (((ACAN*)ckt->CKTcurJob)->ACstepType != LINEAR) { + (*(SPfrontEnd->OUTattributes))((void *)acPlot,NULL, + OUT_SCALE_LOG, NULL); + } + freq = ((ACAN*)ckt->CKTcurJob)->ACstartFreq; + + } else { /* continue previous analysis */ + freq = ((ACAN*)ckt->CKTcurJob)->ACsaveFreq; + ((ACAN*)ckt->CKTcurJob)->ACsaveFreq = 0; /* clear the 'old' frequency */ + } + switch(((ACAN*)ckt->CKTcurJob)->ACstepType) { + case DECADE: + case OCTAVE: + freqTol = ((ACAN*)ckt->CKTcurJob)->ACfreqDelta * + ((ACAN*)ckt->CKTcurJob)->ACstopFreq * ckt->CKTreltol; + break; + case LINEAR: + freqTol = ((ACAN*)ckt->CKTcurJob)->ACfreqDelta * ckt->CKTreltol; + break; + default: + return(E_BADPARM); + } + + startTime = SPfrontEnd->IFseconds(); + startdTime = ckt->CKTstat->STATdecompTime; + startsTime = ckt->CKTstat->STATsolveTime; + startlTime = ckt->CKTstat->STATloadTime; + startcTime = ckt->CKTstat->STATcombineTime; + startkTime = ckt->CKTstat->STATsyncTime; + while(freq <= ((ACAN*)ckt->CKTcurJob)->ACstopFreq+freqTol) { + + if( (*(SPfrontEnd->IFpauseTest))() ) { + /* user asked us to pause via an interrupt */ + ((ACAN*)ckt->CKTcurJob)->ACsaveFreq = freq; + return(E_PAUSE); + } + ckt->CKTomega = 2.0 * M_PI *freq; + ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODEAC; + + error = NIacIter(ckt); + if (error) { + ckt->CKTcurrentAnalysis = DOING_AC; + ckt->CKTstat->STATacTime += SPfrontEnd->IFseconds() - startTime; + ckt->CKTstat->STATacDecompTime += ckt->CKTstat->STATdecompTime - + startdTime; + ckt->CKTstat->STATacSolveTime += ckt->CKTstat->STATsolveTime - + startsTime; + ckt->CKTstat->STATacLoadTime += ckt->CKTstat->STATloadTime - + startlTime; + ckt->CKTstat->STATacCombTime += ckt->CKTstat->STATcombineTime - + startcTime; + ckt->CKTstat->STATacSyncTime += ckt->CKTstat->STATsyncTime - + startkTime; + return(error); + } + + + +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode&ACSEN) ){ + + save = ckt->CKTmode; + ckt->CKTmode=(ckt->CKTmode&MODEUIC)|MODEDCOP|MODEINITSMSIG; + save1 = ckt->CKTsenInfo->SENmode; + ckt->CKTsenInfo->SENmode = ACSEN; + if(freq == ((ACAN*)ckt->CKTcurJob)->ACstartFreq){ + ckt->CKTsenInfo->SENacpertflag = 1; + } + else{ + ckt->CKTsenInfo->SENacpertflag = 0; + } + if(error = CKTsenAC(ckt)) return (error); + ckt->CKTmode = save; + ckt->CKTsenInfo->SENmode = save1; + } +#endif + + error = CKTacDump(ckt,freq,acPlot); + if (error) { + ckt->CKTcurrentAnalysis = DOING_AC; + ckt->CKTstat->STATacTime += SPfrontEnd->IFseconds() - startTime; + ckt->CKTstat->STATacDecompTime += ckt->CKTstat->STATdecompTime - + startdTime; + ckt->CKTstat->STATacSolveTime += ckt->CKTstat->STATsolveTime - + startsTime; + ckt->CKTstat->STATacLoadTime += ckt->CKTstat->STATloadTime - + startlTime; + ckt->CKTstat->STATacCombTime += ckt->CKTstat->STATcombineTime - + startcTime; + ckt->CKTstat->STATacSyncTime += ckt->CKTstat->STATsyncTime - + startkTime; + return(error); + } + + /* increment frequency */ + + switch(((ACAN*)ckt->CKTcurJob)->ACstepType) { + case DECADE: + case OCTAVE: + freq *= ((ACAN*)ckt->CKTcurJob)->ACfreqDelta; + if(((ACAN*)ckt->CKTcurJob)->ACfreqDelta==1) goto endsweep; + break; + case LINEAR: + freq += ((ACAN*)ckt->CKTcurJob)->ACfreqDelta; + if(((ACAN*)ckt->CKTcurJob)->ACfreqDelta==0) goto endsweep; + break; + default: + return(E_INTERN); + } + } +endsweep: + (*(SPfrontEnd->OUTendPlot))(acPlot); + ckt->CKTcurrentAnalysis = 0; + ckt->CKTstat->STATacTime += SPfrontEnd->IFseconds() - startTime; + ckt->CKTstat->STATacDecompTime += ckt->CKTstat->STATdecompTime - + startdTime; + ckt->CKTstat->STATacSolveTime += ckt->CKTstat->STATsolveTime - + startsTime; + ckt->CKTstat->STATacLoadTime += ckt->CKTstat->STATloadTime - + startlTime; + ckt->CKTstat->STATacCombTime += ckt->CKTstat->STATcombineTime - + startcTime; + ckt->CKTstat->STATacSyncTime += ckt->CKTstat->STATsyncTime - + startkTime; + return(0); +} + + + /* CKTacLoad(ckt) + * this is a driver program to iterate through all the various + * ac load functions provided for the circuit elements in the + * given circuit + */ + + +int +CKTacLoad(register CKTcircuit *ckt) +{ + extern SPICEdev *DEVices[]; + register int i; + register int size; + int error; +#ifdef PARALLEL_ARCH + long type = MT_ACLOAD, length = 1; +#endif /* PARALLEL_ARCH */ + double startTime; + + startTime = SPfrontEnd->IFseconds(); + size = SMPmatSize(ckt->CKTmatrix); + for (i=0;i<=size;i++) { + *(ckt->CKTrhs+i)=0; + *(ckt->CKTirhs+i)=0; + } + SMPcClear(ckt->CKTmatrix); + + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVacLoad))(ckt->CKThead[i],ckt); +#ifdef PARALLEL_ARCH + if (error) goto combine; +#else + if(error) return(error); +#endif /* PARALLEL_ARCH */ + } + } +#ifdef PARALLEL_ARCH +combine: + ckt->CKTstat->STATloadTime += SPfrontEnd->IFseconds() - startTime; + startTime = SPfrontEnd->IFseconds(); + /* See if any of the DEVload functions bailed. If not, proceed. */ + IGOP_( &type, &error, &length, "max" ); + ckt->CKTstat->STATsyncTime += SPfrontEnd->IFseconds() - startTime; + if (error == OK) { + startTime = SPfrontEnd->IFseconds(); + SMPcCombine( ckt->CKTmatrix, ckt->CKTrhs, ckt->CKTrhsSpare, + ckt->CKTirhs, ckt->CKTirhsSpare ); + ckt->CKTstat->STATcombineTime += SPfrontEnd->IFseconds() - startTime; + return(OK); + } else { + return(error); + } +#else + ckt->CKTstat->STATloadTime += SPfrontEnd->IFseconds() - startTime; + return(OK); +#endif /* PARALLEL_ARCH */ +} diff --git a/src/analysis/acaskq.c b/src/analysis/acaskq.c new file mode 100644 index 000000000..cf2136187 --- /dev/null +++ b/src/analysis/acaskq.c @@ -0,0 +1,63 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "acdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +ACaskQuest(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case AC_START: + value->rValue = ((ACAN*)anal)->ACstartFreq; + break; + + case AC_STOP: + value->rValue = ((ACAN*)anal)->ACstopFreq ; + break; + + case AC_STEPS: + value->iValue = ((ACAN*)anal)->ACnumberSteps; + break; + + case AC_DEC: + if(((ACAN*)anal)->ACstepType == DECADE) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case AC_OCT: + if(((ACAN*)anal)->ACstepType == OCTAVE) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case AC_LIN: + if(((ACAN*)anal)->ACstepType == LINEAR) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + default: + return(E_BADPARM); + } + return(OK); +} + diff --git a/src/analysis/acsetp.c b/src/analysis/acsetp.c new file mode 100644 index 000000000..d4bb6e47b --- /dev/null +++ b/src/analysis/acsetp.c @@ -0,0 +1,105 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "acdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +ACsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case AC_START: + if (value->rValue <= 0.0) { + errMsg = copy("Frequency of 0 is invalid"); + ((ACAN*)anal)->ACstartFreq = 1.0; + return(E_PARMVAL); + } + + ((ACAN*)anal)->ACstartFreq = value->rValue; + break; + + case AC_STOP: + if (value->rValue <= 0.0) { + errMsg = copy("Frequency of 0 is invalid"); + ((ACAN*)anal)->ACstartFreq = 1.0; + return(E_PARMVAL); + } + + ((ACAN*)anal)->ACstopFreq = value->rValue; + break; + + case AC_STEPS: + ((ACAN*)anal)->ACnumberSteps = value->iValue; + break; + + case AC_DEC: + if(value->iValue) { + ((ACAN*)anal)->ACstepType = DECADE; + } else { + if( ((ACAN*)anal)->ACstepType == DECADE) { + ((ACAN*)anal)->ACstepType = 0; + } + } + break; + + case AC_OCT: + if(value->iValue) { + ((ACAN*)anal)->ACstepType = OCTAVE; + } else { + if( ((ACAN*)anal)->ACstepType == OCTAVE) { + ((ACAN*)anal)->ACstepType = 0; + } + } + break; + + case AC_LIN: + if(value->iValue) { + ((ACAN*)anal)->ACstepType = LINEAR; + } else { + if( ((ACAN*)anal)->ACstepType == LINEAR) { + ((ACAN*)anal)->ACstepType = 0; + } + } + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm ACparms[] = { + { "start", AC_START, IF_SET|IF_ASK|IF_REAL, "starting frequency" }, + { "stop", AC_STOP, IF_SET|IF_ASK|IF_REAL, "ending frequency" }, + { "numsteps", AC_STEPS,IF_SET|IF_ASK|IF_INTEGER, "number of frequencies"}, + { "dec", AC_DEC, IF_SET|IF_FLAG, "step by decades" }, + { "oct", AC_OCT, IF_SET|IF_FLAG, "step by octaves" }, + { "lin", AC_LIN, IF_SET|IF_FLAG, "step linearly" } +}; + +SPICEanalysis ACinfo = { + { + "AC", + "A.C. Small signal analysis", + + sizeof(ACparms)/sizeof(IFparm), + ACparms + }, + sizeof(ACAN), + FREQUENCYDOMAIN, + 1, + ACsetParm, + ACaskQuest, + NULL, + ACan +}; diff --git a/src/analysis/ckt.h b/src/analysis/ckt.h new file mode 100644 index 000000000..301002e9e --- /dev/null +++ b/src/analysis/ckt.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 1985 Thomas L. Quarles + * Modified 1999 Paolo Nenzi - Removed non STDC definitions + * Kept only prototypes (structs defined in struct.h) ER + */ + + +#ifndef CKT_H_INCLUDED +#define CKT_H_INCLUDED + + +/* function prototypes */ + +int ACan( CKTcircuit *, int ); +int ACaskQuest( CKTcircuit *, void *, int , IFvalue *); +int ACsetParm( CKTcircuit *, void *, int , IFvalue *); +int CKTacDump( CKTcircuit *, double , void *); +int CKTacLoad( CKTcircuit *); +int CKTaccept( CKTcircuit *); +int CKTacct( CKTcircuit *, void *, int , IFvalue *); +int CKTask( void *, void *, int , IFvalue *, IFvalue *); +int CKTaskAnalQ( void *, void *, int , IFvalue *, IFvalue *); +int CKTaskNodQst( void *, void *, int , IFvalue *, IFvalue *); +int CKTbindNode( void *, void *, int , void *); +void CKTbreakDump( CKTcircuit *); +int CKTclrBreak( CKTcircuit *); +int CKTconvTest( CKTcircuit *); +int CKTcrtElt( void *, void *, void **, IFuid ); +int CKTdelTask( void *, void *); +int CKTdestroy( void *); +int CKTdltAnal( void *, void *, void *); +int CKTdltInst( void *, void *); +int CKTdltMod( void *, void *); +int CKTdltNod( void *, void *); +int CKTdoJob( void *, int , void *); +void CKTdump( CKTcircuit *, double, void *); +int CKTfndAnal( void *, int *, void **, IFuid , void *, IFuid ); +int CKTfndBranch( CKTcircuit *, IFuid); +int CKTfndDev( void *, int *, void **, IFuid , void *, IFuid ); +int CKTfndMod( void *, int *, void **, IFuid ); +int CKTfndNode( void *, void **, IFuid ); +int CKTfndTask( void *, void **, IFuid ); +int CKTground( void *, void **, IFuid ); +int CKTic( CKTcircuit *); +int CKTinit( void **); +int CKTinst2Node( void *, void *, int , void **, IFuid *); +int CKTlinkEq(CKTcircuit*,CKTnode*); +int CKTload( CKTcircuit *); +int CKTmapNode( void *, void **, IFuid ); +int CKTmkCur( CKTcircuit *, CKTnode **, IFuid , char *); +int CKTmkNode(CKTcircuit*,CKTnode**); +int CKTmkVolt( CKTcircuit *, CKTnode **, IFuid , char *); +int CKTmodAsk( void *, void *, int , IFvalue *, IFvalue *); +int CKTmodCrt( void *, int , void **, IFuid ); +int CKTmodParam( void *, void *, int , IFvalue *, IFvalue *); +int CKTnames(CKTcircuit *, int *, IFuid **); +int CKTnewAnal( void *, int , IFuid , void **, void *); +int CKTnewEq( void *, void **, IFuid ); +int CKTnewNode( void *, void **, IFuid ); +int CKTnewTask( void *, void **, IFuid ); +IFuid CKTnodName( CKTcircuit *, int ); +void CKTnodOut( CKTcircuit *); +CKTnode * CKTnum2nod( CKTcircuit *, int ); +int CKTop(CKTcircuit *, long, long, int ); +int CKTpModName( char *, IFvalue *, CKTcircuit *, int , IFuid , GENmodel **); +int CKTpName( char *, IFvalue *, CKTcircuit *, int , char *, GENinstance **); +int CKTparam( void *, void *, int , IFvalue *, IFvalue *); +int CKTpzFindZeros( CKTcircuit *, PZtrial **, int * ); +int CKTpzLoad( CKTcircuit *, SPcomplex * ); +int CKTpzSetup( CKTcircuit *, int); +int CKTsenAC( CKTcircuit *); +int CKTsenComp( CKTcircuit *); +int CKTsenDCtran( CKTcircuit *); +int CKTsenLoad( CKTcircuit *); +void CKTsenPrint( CKTcircuit *); +int CKTsenSetup( CKTcircuit *); +int CKTsenUpdate( CKTcircuit *); +int CKTsetAnalPm( void *, void *, int , IFvalue *, IFvalue *); +int CKTsetBreak( CKTcircuit *, double ); +int CKTsetNodPm( void *, void *, int , IFvalue *, IFvalue *); +int CKTsetOpt( void *, void *, int , IFvalue *); +int CKTsetup( CKTcircuit *); +int CKTunsetup(CKTcircuit *ckt); +int CKTtemp( CKTcircuit *); +char *CKTtrouble(void *, char *); +void CKTterr( int , CKTcircuit *, double *); +int CKTtrunc( CKTcircuit *, double *); +int CKTtypelook( char *); +int DCOaskQuest( CKTcircuit *, void *, int , IFvalue *); +int DCOsetParm( CKTcircuit *, void *, int , IFvalue *); +int DCTaskQuest( CKTcircuit *, void *, int , IFvalue *); +int DCTsetParm( CKTcircuit *, void *, int , IFvalue *); +int DCop( CKTcircuit *); +int DCtrCurv( CKTcircuit *, int ); +int DCtran( CKTcircuit *, int ); +int DISTOan(CKTcircuit *, int); +int NOISEan(CKTcircuit *, int); +int PZan( CKTcircuit *, int ); +int PZinit( CKTcircuit * ); +int PZpost( CKTcircuit * ); +int PZaskQuest( CKTcircuit *, void *, int , IFvalue *); +int PZsetParm( CKTcircuit *, void *, int , IFvalue *); +int SENaskQuest( CKTcircuit *, void *, int , IFvalue *); +void SENdestroy( SENstruct *); +int SENsetParm( CKTcircuit *, void *, int , IFvalue *); +int SENstartup( CKTcircuit *); +int SPIinit( IFfrontEnd *, IFsimulator **); +char * SPerror( int ); +int TFanal( CKTcircuit *, int ); +int TFaskQuest( CKTcircuit *, void *, int , IFvalue *); +int TFsetParm( CKTcircuit *, void *, int , IFvalue *); +int TRANaskQuest( CKTcircuit *, void *, int , IFvalue *); +int TRANsetParm( CKTcircuit *, void *, int , IFvalue *); +int TRANinit(CKTcircuit *, JOB *); +int NIacIter( CKTcircuit * ); +int NIcomCof( CKTcircuit * ); +int NIconvTest(CKTcircuit * ); +void NIdestroy(CKTcircuit * ); +int NIinit( CKTcircuit * ); +int NIintegrate( CKTcircuit *, double *, double *, double , int ); +int NIiter( CKTcircuit * , int ); +int NIpzMuller(PZtrial **, PZtrial *); +int NIpzComplex(PZtrial **, PZtrial *); +int NIpzSym(PZtrial **, PZtrial *); +int NIpzSym2(PZtrial **, PZtrial *); +int NIreinit( CKTcircuit *); +int NIsenReinit( CKTcircuit *); +IFfrontEnd *SPfrontEnd; + +#endif /*CKT*/ diff --git a/src/analysis/cktaccpt.c b/src/analysis/cktaccpt.c new file mode 100644 index 000000000..fddbc5739 --- /dev/null +++ b/src/analysis/cktaccpt.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* CKTaccept(ckt) + * this is a driver program to iterate through all the various + * accept functions provided for the circuit elements in the + * given circuit + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + +int +CKTaccept(register CKTcircuit *ckt) +{ + extern SPICEdev *DEVices[]; + + register int i; + int error; + + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVaccept))(ckt,ckt->CKThead[i]); + if(error) return(error); + } + } +#ifdef PREDICTOR + /* now, move the sols vectors around */ + temp = ckt->CKTsols[7]; + for ( i=7;i>0;i--) { + ckt->CKTsols[i] = ckt->CKTsols[i-1]; + } + ckt->CKTsols[0]=temp; + size = SMPmatSize(ckt->CKTmatrix); + for(i=0;i<=size;i++) { + ckt->CKTsols[0][i]=ckt->CKTrhs[i]; + } +#endif /* PREDICTOR */ + return(OK); +} diff --git a/src/analysis/cktacct.c b/src/analysis/cktacct.c new file mode 100644 index 000000000..3c83d6565 --- /dev/null +++ b/src/analysis/cktacct.c @@ -0,0 +1,142 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* + * CKTacct + * get the specified accounting item into 'value' in the + * given circuit 'ckt'. + */ + +#include "ngspice.h" +#include "const.h" +#include "optdefs.h" +#include "ifsim.h" +#include +#include "cktdefs.h" +#include "spmatrix.h" + + + +/* ARGSUSED */ +int +CKTacct(CKTcircuit *ckt, void *anal, int which, IFvalue *val) +{ + switch(which) { + + case OPT_EQNS: + val->iValue = ckt->CKTmaxEqNum; + break; + case OPT_ORIGNZ: + if ( ckt->CKTmatrix != NULL ) { + val->iValue = spOriginalCount((char *)ckt->CKTmatrix); + } else { + val->iValue = 0; + } + break; + case OPT_FILLNZ: + if ( ckt->CKTmatrix != NULL ) { + val->iValue = spFillinCount((char *)ckt->CKTmatrix); + } else { + val->iValue = 0; + } + break; + case OPT_TOTALNZ: + if ( ckt->CKTmatrix != NULL ) { + val->iValue = spElementCount((char *)ckt->CKTmatrix); + } else { + val->iValue = 0; + } + break; + case OPT_ITERS: + val->iValue = ckt->CKTstat->STATnumIter; + break; + case OPT_TRANIT: + val->iValue = ckt->CKTstat->STATtranIter; + break; + case OPT_TRANCURITER: + val->iValue = ckt->CKTstat->STATnumIter - ckt->CKTstat->STAToldIter; + break; + case OPT_TRANPTS: + val->iValue = ckt->CKTstat->STATtimePts; + break; + case OPT_TRANACCPT: + val->iValue = ckt->CKTstat->STATaccepted; + break; + case OPT_TRANRJCT: + val->iValue = ckt->CKTstat->STATrejected; + break; + case OPT_TOTANALTIME: + val->rValue = ckt->CKTstat->STATtotAnalTime; + break; + case OPT_TRANTIME: + val->rValue = ckt->CKTstat->STATtranTime; + break; + case OPT_ACTIME: + val->rValue = ckt->CKTstat->STATacTime; + break; + case OPT_LOADTIME: + val->rValue = ckt->CKTstat->STATloadTime; + break; + case OPT_SYNCTIME: + val->rValue = ckt->CKTstat->STATsyncTime; + break; + case OPT_COMBTIME: + val->rValue = ckt->CKTstat->STATcombineTime; + break; + case OPT_REORDTIME: + val->rValue = ckt->CKTstat->STATreorderTime; + break; + case OPT_DECOMP: + val->rValue = ckt->CKTstat->STATdecompTime; + break; + case OPT_SOLVE: + val->rValue = ckt->CKTstat->STATsolveTime; + break; + case OPT_TRANLOAD: + val->rValue = ckt->CKTstat->STATtranLoadTime; + break; + case OPT_TRANSYNC: + val->rValue = ckt->CKTstat->STATtranSyncTime; + break; + case OPT_TRANCOMB: + val->rValue = ckt->CKTstat->STATtranCombTime; + break; + case OPT_TRANDECOMP: + val->rValue = ckt->CKTstat->STATtranDecompTime; + break; + case OPT_TRANSOLVE: + val->rValue = ckt->CKTstat->STATtranSolveTime; + break; + case OPT_TRANTRUNC: + val->rValue = ckt->CKTstat->STATtranTruncTime; + break; + case OPT_ACLOAD: + val->rValue = ckt->CKTstat->STATacLoadTime; + break; + case OPT_ACSYNC: + val->rValue = ckt->CKTstat->STATacSyncTime; + break; + case OPT_ACCOMB: + val->rValue = ckt->CKTstat->STATacCombTime; + break; + case OPT_ACDECOMP: + val->rValue = ckt->CKTstat->STATacDecompTime; + break; + case OPT_ACSOLVE: + val->rValue = ckt->CKTstat->STATacSolveTime; + break; + case OPT_TEMP: + val->rValue = ckt->CKTtemp - CONSTCtoK; + break; + case OPT_TNOM: + val->rValue = ckt->CKTnomTemp - CONSTCtoK; + break; + default: + return(-1); + } + return(0); +} diff --git a/src/analysis/cktacdum.c b/src/analysis/cktacdum.c new file mode 100644 index 000000000..590ee65c8 --- /dev/null +++ b/src/analysis/cktacdum.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTacDump(ckt,freq,file) + * this is a simple program to dump the complex rhs vector + * into the rawfile. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "iferrmsg.h" +#include "ifsim.h" + + + +int +CKTacDump(register CKTcircuit *ckt, double freq, void *plot) +{ + register double *rhsold; + register double *irhsold; + register int i; + register IFcomplex *data; + IFvalue freqData; + IFvalue valueData; + + rhsold = ckt->CKTrhsOld; + irhsold = ckt->CKTirhsOld; + freqData.rValue = freq; + valueData.v.numValue = ckt->CKTmaxEqNum-1; + data = (IFcomplex *) MALLOC((ckt->CKTmaxEqNum-1)*sizeof(IFcomplex)); + valueData.v.vec.cVec = data; + for (i=0;iCKTmaxEqNum-1;i++) { + data[i].real = rhsold[i+1]; + data[i].imag = irhsold[i+1]; + } + (*(SPfrontEnd->OUTpData))(plot,&freqData,&valueData); + FREE(data); + return(OK); +} diff --git a/src/analysis/cktask.c b/src/analysis/cktask.c new file mode 100644 index 000000000..f9230ca00 --- /dev/null +++ b/src/analysis/cktask.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTask + * Ask questions about a specified device. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "devdefs.h" +#include "sperror.h" + + +extern SPICEdev *DEVices[]; + +int +CKTask(void *ckt, void *fast, int which, IFvalue *value, IFvalue *selector) +{ + register int type = ((GENinstance *)fast)->GENmodPtr->GENmodType; + int error; +#ifdef PARALLEL_ARCH + long msgtype, length; + long from = ((GENinstance *)fast)->GENowner; +#endif /* PARALLEL_ARCH */ + + if((*DEVices[type]).DEVask) { + error = DEVices[type]->DEVask((CKTcircuit *)ckt, + (GENinstance *)fast,which,value,selector); + } else { + error = E_BADPARM; + } +#ifdef PARALLEL_ARCH + msgtype = MT_ASK; + length = sizeof(IFvalue); + BRDCST_(&msgtype, (char *)value, &length, &from); + msgtype++; + length = sizeof(int); + BRDCST_(&msgtype, (char *)&error, &length, &from); +#endif /* PARALLEL_ARCH */ + return(error); +} diff --git a/src/analysis/cktaskaq.c b/src/analysis/cktaskaq.c new file mode 100644 index 000000000..68ebb5ec5 --- /dev/null +++ b/src/analysis/cktaskaq.c @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "tskdefs.h" +#include "jobdefs.h" +#include "cktdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" + + +extern SPICEanalysis *analInfo[]; + +/* ARGSUSED */ +int +CKTaskAnalQ(void *ckt, void *analPtr, int parm, IFvalue *value, IFvalue *selector) +{ + register int type = ((JOB *)analPtr)->JOBtype; + + if((analInfo[type]->askQuest) == NULL) return(E_BADPARM); + return( (*(analInfo[type]->askQuest))((CKTcircuit*)ckt,analPtr,parm,value)); +} diff --git a/src/analysis/cktasknq.c b/src/analysis/cktasknq.c new file mode 100644 index 000000000..ad568521f --- /dev/null +++ b/src/analysis/cktasknq.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + *CKTaskNodQst + * + * ask about a parameter on a node. + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +int +CKTaskNodQst(void *ckt, void *node, int parm, IFvalue *value, IFvalue *selector) +{ + if(!node) return(E_BADPARM); + switch(parm) { + + case PARM_NS: + value->rValue = ((CKTnode *)node)->nodeset; + break; + + case PARM_IC: + value->rValue = ((CKTnode *)node)->ic; + break; + + case PARM_NODETYPE: + value->iValue = ((CKTnode *)node)->type; + break; + + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/analysis/cktbindn.c b/src/analysis/cktbindn.c new file mode 100644 index 000000000..b77e1da67 --- /dev/null +++ b/src/analysis/cktbindn.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* CKTbindNode + * bind a node of the specified device of the given type to its place + * in the specified circuit. + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + +extern SPICEdev *DEVices[]; + +/*ARGSUSED*/ +int +CKTbindNode(void *ckt, void *fast, int term, void *node) +{ + int mappednode; + register int type = ((GENinstance *)fast)->GENmodPtr->GENmodType; + + mappednode = ((CKTnode *)node)->number; + + if(*((*DEVices[type]).DEVpublic.terms) >= term && term >0 ) { + switch(term) { + default: return(E_NOTERM); + case 1: + ((GENinstance *)fast)->GENnode1 = mappednode; + break; + case 2: + ((GENinstance *)fast)->GENnode2 = mappednode; + break; + case 3: + ((GENinstance *)fast)->GENnode3 = mappednode; + break; + case 4: + ((GENinstance *)fast)->GENnode4 = mappednode; + break; + case 5: + ((GENinstance *)fast)->GENnode5 = mappednode; + break; + } + return(OK); + } else { + return(E_NOTERM); + } +} diff --git a/src/analysis/cktbkdum.c b/src/analysis/cktbkdum.c new file mode 100644 index 000000000..265695928 --- /dev/null +++ b/src/analysis/cktbkdum.c @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTbreakDump(ckt) - dump the breakpoint table associated with + * the given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" + + + +void +CKTbreakDump(CKTcircuit *ckt) +{ + register int i; + for(i=0;iCKTbreakSize;i++) { + (void)printf("breakpoint table entry %d is %g\n",i,*(ckt->CKTbreaks+i)); + } +} diff --git a/src/analysis/cktclrbk.c b/src/analysis/cktclrbk.c new file mode 100644 index 000000000..36bbe9cc0 --- /dev/null +++ b/src/analysis/cktclrbk.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTclrBreak(ckt) + * delete the first time from the breakpoint table for the given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "sperror.h" + + + +int +CKTclrBreak(register CKTcircuit *ckt) +{ + double *tmp; + register int j; + + if(ckt->CKTbreakSize >2) { + tmp = (double *)MALLOC((ckt->CKTbreakSize-1)*sizeof(double)); + if(tmp == (double *)NULL) return(E_NOMEM); + for(j=1;jCKTbreakSize;j++) { + *(tmp+j-1) = *(ckt->CKTbreaks+j); + } + FREE(ckt->CKTbreaks); + ckt->CKTbreakSize--; + ckt->CKTbreaks=tmp; + } else { + *(ckt->CKTbreaks)= *(ckt->CKTbreaks+1); + *(ckt->CKTbreaks+1) = ckt->CKTfinalTime; + } + return(OK); +} diff --git a/src/analysis/cktcrte.c b/src/analysis/cktcrte.c new file mode 100644 index 000000000..d1cbb034e --- /dev/null +++ b/src/analysis/cktcrte.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTcrtElement(ckt,type,inModPtr,inInstPtr,name,subname) + * Create a device of the specified type, with the given name, using + * the specified model in the named circuit. + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + + +/*ARGSUSED*/ +int +CKTcrtElt(void *ckt, void *inModPtr, void **inInstPtr, IFuid name) +{ + GENinstance *instPtr = NULL; + GENmodel *modPtr=(GENmodel*)inModPtr; + extern SPICEdev *DEVices[]; + int error; + int type; + + if((GENmodel *)modPtr==(GENmodel*)NULL) return(E_NOMOD); + type = ((GENmodel*)modPtr)->GENmodType; + error =CKTfndDev(ckt,&type,(void**)&instPtr,name,inModPtr,(char *)NULL ); + if (error== OK) { + if(inInstPtr) *inInstPtr=(void *)instPtr; + return(E_EXISTS); + } else if (error != E_NODEV) return(error); + instPtr = (GENinstance *)MALLOC(*DEVices[type]->DEVinstSize); + if(instPtr == (GENinstance *)NULL) return(E_NOMEM); + instPtr->GENname = name; + instPtr->GENmodPtr = modPtr; + instPtr->GENnextInstance = modPtr->GENinstances; + modPtr->GENinstances = instPtr; + if(inInstPtr != NULL) *inInstPtr = (void *)instPtr; + return(OK); +} diff --git a/src/analysis/cktdelt.c b/src/analysis/cktdelt.c new file mode 100644 index 000000000..baa39e850 --- /dev/null +++ b/src/analysis/cktdelt.c @@ -0,0 +1,27 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "tskdefs.h" +#include "jobdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" + + +/* ARGSUSED */ +int +CKTdelTask(void *ckt, void *task) +{ + JOB *job; + JOB *old=NULL; + for(job = ((TSKtask*)task)->jobs; job; job=job->JOBnextJob){ + if(old) FREE(old); + old=job; + } + if(old)FREE(old); + FREE(task); + return(OK); +} diff --git a/src/analysis/cktdest.c b/src/analysis/cktdest.c new file mode 100644 index 000000000..ead8f3541 --- /dev/null +++ b/src/analysis/cktdest.c @@ -0,0 +1,61 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTdestroy(ckt) + * this is a driver program to iterate through all the various + * destroy functions provided for the circuit elements in the + * given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "sperror.h" + + + +extern SPICEdev *DEVices[]; +int +CKTdestroy(void *inCkt) +{ + register CKTcircuit *ckt = (CKTcircuit *)inCkt; + register int i; + register CKTnode *node; + register CKTnode *nnode; + + +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo){ + if(ckt->CKTrhsOp) FREE(ckt->CKTrhsOp); + if(ckt->CKTsenRhs) FREE(ckt->CKTsenRhs); + if(ckt->CKTseniRhs) FREE(ckt->CKTseniRhs); + SENdestroy(ckt->CKTsenInfo); + } +#endif + + for (i=0;iCKThead[i] != NULL) ){ + (*((*DEVices[i]).DEVdestroy))(&(ckt->CKThead[i])); + } + } + for(i=0;i<=ckt->CKTmaxOrder+1;i++){ + FREE(ckt->CKTstates[i]); + } + if(ckt->CKTmatrix) SMPdestroy(ckt->CKTmatrix); + if(ckt->CKTbreaks) FREE(ckt->CKTbreaks); + for(node = ckt->CKTnodes; node; ) { + nnode = node->next; + FREE(node); + node = nnode; + } + ckt->CKTnodes = (CKTnode *)NULL; + ckt->CKTlastNode = (CKTnode *)NULL; + FREE(ckt); + return(OK); +} diff --git a/src/analysis/cktdisto.c b/src/analysis/cktdisto.c new file mode 100644 index 000000000..dbdf42153 --- /dev/null +++ b/src/analysis/cktdisto.c @@ -0,0 +1,177 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +/* + * CKTdisto (ckt, mode) + */ + + +#include "ngspice.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "vsrc/vsrcdefs.h" +#include "isrc/isrcdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "distodef.h" +#include "sperror.h" +#include + + +int +CKTdisto (register CKTcircuit *ckt, int mode) +{ + extern SPICEdev *DEVices[]; + register DISTOAN* cv = (DISTOAN*) (ckt->CKTcurJob); + register int i; + int error=0; + int size; + + switch(mode) { + + case D_SETUP: + + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVdisto))(mode,ckt->CKThead[i],ckt); + if(error) return(error); + } + } + break; + + case D_TWOF1: + case D_THRF1: + case D_F1PF2: + case D_F1MF2: + case D_2F1MF2: + + size = SMPmatSize(ckt->CKTmatrix); + for (i=1; i<=size; i++) + { + ckt->CKTrhs[i] = 0.0; + ckt->CKTirhs[i] = 0.0; + } + + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVdisto))(mode,ckt->CKThead[i],ckt); + if(error) return(error); + } + } + break; + + case D_RHSF1: + + cv->Df2given = 0; /* will change if any F2 source is found */ + + case D_RHSF2: + + + +{ + int vcode; + int icode; + double mag=0.0; + double phase=0.0; + int size; + + size = SMPmatSize(ckt->CKTmatrix); + for (i=0;i<=size;i++) { + *(ckt->CKTrhs+i)=0; + *(ckt->CKTirhs+i)=0; + } + + vcode = CKTtypelook("Vsource"); + icode = CKTtypelook("Isource"); + + + if(vcode >= 0) { + /* voltage sources are in this version, so use them */ + register VSRCinstance *here; + register VSRCmodel *model; + for(model = (VSRCmodel *)ckt->CKThead[vcode];model != NULL; + model=model->VSRCnextModel){ + for(here=model->VSRCinstances;here!=NULL; + here=here->VSRCnextInstance) { + +/* check if the source has a distortion input*/ + +if (here->VSRCdGiven) { + if (here->VSRCdF2given) cv->Df2given = 1; + if ((here->VSRCdF1given) && (mode == D_RHSF1)) { + + mag = here->VSRCdF1mag; + phase = here->VSRCdF1phase; +} +else if ((here->VSRCdF2given) && (mode == D_RHSF2)) { + + mag = here->VSRCdF2mag; + phase = here->VSRCdF2phase; +} +if (((here->VSRCdF1given) && (mode == D_RHSF1)) || + ((here->VSRCdF2given) && (mode == D_RHSF2))) { + + *(ckt->CKTrhs + here->VSRCbranch) = 0.5*mag* cos(M_PI*phase/180.0); + *(ckt->CKTirhs + here->VSRCbranch) = 0.5*mag*sin(M_PI*phase/180.0); +} + + + } + } + } + } + if(icode >= 0 ) { + /* current sources are in this version, so use them */ + register ISRCinstance *here; + register ISRCmodel *model; + + for(model= (ISRCmodel *)ckt->CKThead[icode];model != NULL; + model=model->ISRCnextModel){ + for(here=model->ISRCinstances;here!=NULL; + here=here->ISRCnextInstance) { + +/* check if the source has a distortion input*/ + +if (here->ISRCdGiven) { + if (here->ISRCdF2given) cv->Df2given = 1; + if ((here->ISRCdF1given) && (mode == D_RHSF1)) { + + mag = here->ISRCdF1mag; + phase = here->ISRCdF1phase; +} +else if ((here->ISRCdF2given) && (mode == D_RHSF2)) { + + mag = here->ISRCdF2mag; + phase = here->ISRCdF2phase; +} +if (((here->ISRCdF1given) && (mode == D_RHSF1)) || + ((here->ISRCdF2given) && (mode == D_RHSF2))) { + + *(ckt->CKTrhs + here->ISRCposNode) = - 0.5 * mag + * cos(M_PI*phase/180.0); + *(ckt->CKTrhs + here->ISRCnegNode) = 0.5 * mag * cos( + M_PI*phase/180.0); + *(ckt->CKTirhs + here->ISRCposNode) = - 0.5 * mag * sin( + M_PI*phase/180.0); + *(ckt->CKTirhs + here->ISRCnegNode) = 0.5 * mag * sin( + M_PI*phase/180.0); +} + } + } + } + } +} +error = 0; +break; + + default: + + error = E_BADPARM; + break; + } + + return(error); + +} diff --git a/src/analysis/cktdlti.c b/src/analysis/cktdlti.c new file mode 100644 index 000000000..ac07253c8 --- /dev/null +++ b/src/analysis/cktdlti.c @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTdltInst + * delete the specified instance - not yet supported in spice + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" + + + +/* ARGSUSED */ +int +CKTdltInst(void *ckt, void *instance) +{ + return(E_UNSUPP); +} diff --git a/src/analysis/cktdltm.c b/src/analysis/cktdltm.c new file mode 100644 index 000000000..17e763da6 --- /dev/null +++ b/src/analysis/cktdltm.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* CKTdltMod + * delete the specified model - not yet supported in spice + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" + + + +/* ARGSUSED */ +int +CKTdltMod(void *cktp, void *modPtr) +{ + CKTcircuit *ckt = (CKTcircuit *) cktp; + GENmodel *m = (GENmodel *) modPtr, *mod, **prevp; + GENinstance *h, *next_i; + int error; + + prevp = &ckt->CKThead[m->GENmodType]; + for (mod = *prevp; m && mod != m; mod = mod->GENnextModel) + prevp = &mod->GENnextModel; + + if (!mod) + return OK; + + *prevp = m->GENnextModel; + + for (h = m->GENinstances; h; h = next_i) { + next_i = h->GENnextInstance; + error = (*(SPfrontEnd->IFdelUid))((void *)ckt,h->GENname, + UID_INSTANCE); + tfree(h); + } + error = (*(SPfrontEnd->IFdelUid))((void *)ckt,m->GENmodName, UID_MODEL); + tfree(m); + return(OK); +} diff --git a/src/analysis/cktdltn.c b/src/analysis/cktdltn.c new file mode 100644 index 000000000..c76e2ff30 --- /dev/null +++ b/src/analysis/cktdltn.c @@ -0,0 +1,59 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +**********/ + +/* CKTdltNod +*/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" + +int CKTdltNNum(void *cktp, int num); + +/* ARGSUSED */ +int +CKTdltNod(void *ckt, void *node) +{ + return CKTdltNNum(ckt, ((CKTnode *) node)->number); +} + +int +CKTdltNNum(void *cktp, int num) +{ + CKTcircuit *ckt = (CKTcircuit *) cktp; + CKTnode *n, *prev, *node, *sprev; + int error; + + prev = NULL; + node = NULL; + sprev = NULL; + + for (n = ckt->CKTnodes; n; n = n->next) { + if (n->number == num) { + node = n; + sprev = prev; + } + prev = n; + } + + if (!node) + return OK; + + ckt->CKTmaxEqNum -= 1; + + if (!sprev) { + ckt->CKTnodes = node->next; + } else { + sprev->next = node->next; + } + if (node == ckt->CKTlastNode) + ckt->CKTlastNode = sprev; + + error = (*(SPfrontEnd->IFdelUid))((void *)ckt,node->name, UID_SIGNAL); + tfree(node); + + return error; +} diff --git a/src/analysis/cktdojob.c b/src/analysis/cktdojob.c new file mode 100644 index 000000000..5a124e915 --- /dev/null +++ b/src/analysis/cktdojob.c @@ -0,0 +1,146 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include +#include "sperror.h" +#include "trandefs.h" + + +extern SPICEanalysis *analInfo[]; +extern int ANALmaxnum; + +int +CKTdoJob(void *inCkt, int reset, void *inTask) +{ + CKTcircuit *ckt = (CKTcircuit *)inCkt; + TSKtask *task = (TSKtask *)inTask; + JOB *job; + double startTime; + int error, i, error2; + +#ifdef WANT_SENSE2 + int senflag; + static int sens_num = -1; + + /* Sensitivity is special */ + if (sens_num < 0) { + for (i = 0; i < ANALmaxnum; i++) + if (!strcmp("SENS2", analInfo[i]->public.name)) + break; + sens_num = i; + } +#endif + + startTime = (*(SPfrontEnd->IFseconds))( ); + + ckt->CKTtemp = task->TSKtemp; + ckt->CKTnomTemp = task->TSKnomTemp; + ckt->CKTmaxOrder = task->TSKmaxOrder; + ckt->CKTintegrateMethod = task->TSKintegrateMethod; + ckt->CKTbypass = task->TSKbypass; + ckt->CKTdcMaxIter = task->TSKdcMaxIter; + ckt->CKTdcTrcvMaxIter = task->TSKdcTrcvMaxIter; + ckt->CKTtranMaxIter = task->TSKtranMaxIter; + ckt->CKTnumSrcSteps = task->TSKnumSrcSteps; + ckt->CKTnumGminSteps = task->TSKnumGminSteps; + ckt->CKTminBreak = task->TSKminBreak; + ckt->CKTabstol = task->TSKabstol; + ckt->CKTpivotAbsTol = task->TSKpivotAbsTol; + ckt->CKTpivotRelTol = task->TSKpivotRelTol; + ckt->CKTreltol = task->TSKreltol; + ckt->CKTchgtol = task->TSKchgtol; + ckt->CKTvoltTol = task->TSKvoltTol; + ckt->CKTgmin = task->TSKgmin; + ckt->CKTdelmin = task->TSKdelmin; + ckt->CKTtrtol = task->TSKtrtol; + ckt->CKTdefaultMosL = task->TSKdefaultMosL; + ckt->CKTdefaultMosW = task->TSKdefaultMosW; + ckt->CKTdefaultMosAD = task->TSKdefaultMosAD; + ckt->CKTdefaultMosAS = task->TSKdefaultMosAS; + ckt->CKTfixLimit = task->TSKfixLimit; + ckt->CKTnoOpIter = task->TSKnoOpIter; + ckt->CKTtryToCompact = task->TSKtryToCompact; + ckt->CKTbadMos3 = task->TSKbadMos3; + ckt->CKTkeepOpInfo = task->TSKkeepOpInfo; + ckt->CKTtroubleNode = 0; + ckt->CKTtroubleElt = NULL; +#ifdef NEWTRUNC + ckt->CKTlteReltol = task->TSKlteReltol; + ckt->CKTlteAbstol = task->TSKlteAbstol; +#endif /* NEWTRUNC */ + + error = 0; + + if (reset) { + + ckt->CKTdelta = 0.0; + ckt->CKTtime = 0.0; + ckt->CKTcurrentAnalysis = 0; + +#ifdef WANT_SENSE2 + senflag = 0; + if (sens_num < ANALmaxnum) + for (job = task->jobs; !error && job; job = job->JOBnextJob) { + if (job->JOBtype == sens_num) { + senflag = 1; + ckt->CKTcurJob = job; + ckt->CKTsenInfo = (SENstruct *) job; + error = (*(analInfo[sens_num]->an_func))(ckt, reset); + } + } + + if (ckt->CKTsenInfo && (!senflag || error)) + FREE(ckt->CKTsenInfo); +#endif + + /* normal reset */ + if (!error) + error = CKTunsetup(ckt); + if (!error) + error = CKTsetup(ckt); + if (!error) + error = CKTtemp(ckt); + if (error) + return error; + } + + error2 = OK; + + /* Analysis order is important */ + for (i = 0; i < ANALmaxnum; i++) { + +#ifdef WANT_SENSE2 + if (i == sens_num) + continue; +#endif + + for (job = task->jobs; job; job = job->JOBnextJob) { + if (job->JOBtype == i) { + ckt->CKTcurJob=job; + error = OK; + if (analInfo[i]->an_init) + error = (*(analInfo[i]->an_init))(ckt, job); + if (!error && analInfo[i]->do_ic) + error = CKTic(ckt); + if (!error) + error = (*(analInfo[i]->an_func))(ckt, reset); + if (error) + error2 = error; + } + } + } + + ckt->CKTstat->STATtotAnalTime += (*(SPfrontEnd->IFseconds))( ) - startTime; + +#ifdef WANT_SENSE2 + if (ckt->CKTsenInfo) + SENdestroy(ckt->CKTsenInfo); +#endif + + return(error2); +} + diff --git a/src/analysis/cktdump.c b/src/analysis/cktdump.c new file mode 100644 index 000000000..75ee9657d --- /dev/null +++ b/src/analysis/cktdump.c @@ -0,0 +1,29 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTdump(ckt) + * this is a simple program to dump the rhs vector to stdout + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" + + + +void +CKTdump(register CKTcircuit *ckt, double ref, void *plot) +{ + IFvalue refData; + IFvalue valData; + + refData.rValue = ref; + valData.v.numValue = ckt->CKTmaxEqNum-1; + valData.v.vec.rVec = ckt->CKTrhsOld+1; + (*(SPfrontEnd->OUTpData))(plot,&refData,&valData); +} diff --git a/src/analysis/cktfbran.c b/src/analysis/cktfbran.c new file mode 100644 index 000000000..c9ea291ac --- /dev/null +++ b/src/analysis/cktfbran.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTfndBranch(ckt,name) + * this is a driver program to iterate through all the various + * findBranch functions provided for the circuit elements in the + * given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" + + + +int +CKTfndBranch(register CKTcircuit *ckt, IFuid name) +{ + extern SPICEdev *DEVices[]; + + register int i; + int j; + + for (i=0;iCKThead[i] != NULL) { + j = (*((*DEVices[i]).DEVfindBranch))(ckt,ckt->CKThead[i],name); + if(j != 0) return(j); + } + } + return(0); +} diff --git a/src/analysis/cktfdev.c b/src/analysis/cktfdev.c new file mode 100644 index 000000000..fd8109a8c --- /dev/null +++ b/src/analysis/cktfdev.c @@ -0,0 +1,86 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "sperror.h" + + + +int +CKTfndDev(void *Ckt, int *type, void **fast, IFuid name, void *modfast, IFuid modname) +{ + register CKTcircuit *ckt=(CKTcircuit *)Ckt; + register GENinstance *here; + register GENmodel *mods; + + if((GENinstance **)fast != (GENinstance **)NULL && + *(GENinstance **)fast != (GENinstance *)NULL) { + /* already have fast, so nothing much to do */ + /* just get & set type */ + if(type) *type = (*((GENinstance**)fast))->GENmodPtr->GENmodType; + return(OK); + } + if(modfast) { + /* have model, just need device */ + mods = (GENmodel*)modfast; + for(here = mods->GENinstances ; here != NULL; + here = here->GENnextInstance) { + if (here->GENname == name) { + if(fast != NULL) *(GENinstance **)fast = here; + if(type) *type = mods->GENmodType; + return(OK); + } + } + return(E_NODEV); + } + if(*type >=0 && *type < DEVmaxnum) { + /* have device type, need to find model & device */ + /* look through all models */ + for(mods=(GENmodel *)ckt->CKThead[*type]; mods != NULL ; + mods = mods->GENnextModel) { + /* and all instances */ + if(modname == (char *)NULL || mods->GENmodName == modname) { + for(here = mods->GENinstances ; here != NULL; + here = here->GENnextInstance) { + if (here->GENname == name) { + if(fast != 0) *(GENinstance **)fast = here; + return(OK); + } + } + if(mods->GENmodName == modname) { + return(E_NODEV); + } + } + } + return(E_NOMOD); + } else if(*type == -1) { + /* look through all types (UGH - worst case - take forever) */ + for(*type = 0;*type CKThead[*type];mods!=NULL; + mods = mods->GENnextModel) { + /* and all instances */ + if(modname == (char *)NULL || mods->GENmodName == modname) { + for(here = mods->GENinstances ; here != NULL; + here = here->GENnextInstance) { + if (here->GENname == name) { + if(fast != 0) *(GENinstance **)fast = here; + return(OK); + } + } + if(mods->GENmodName == modname) { + return(E_NODEV); + } + } + } + } + *type = -1; + return(E_NODEV); + } else return(E_BADPARM); +} diff --git a/src/analysis/cktfnda.c b/src/analysis/cktfnda.c new file mode 100644 index 000000000..4b3fb3189 --- /dev/null +++ b/src/analysis/cktfnda.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTfndAnal + * find the given Analysis given its name and return the Analysis pointer + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "jobdefs.h" +#include "tskdefs.h" +#include "sperror.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +int +CKTfndAnal(void *ckt, int *analIndex, void **anal, IFuid name, void *inTask, IFuid taskName) +{ + TSKtask *task = (TSKtask *)inTask; + register JOB *here; + + for (here = ((TSKtask *)task)->jobs;here;here = here->JOBnextJob) { + if(strcmp(here->JOBname,name)==0) { + if(anal) *anal = (void *)here; + return(OK); + } + } + return(E_NOTFOUND); +} diff --git a/src/analysis/cktfndm.c b/src/analysis/cktfndm.c new file mode 100644 index 000000000..452952924 --- /dev/null +++ b/src/analysis/cktfndm.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" + + + +int +CKTfndMod(void *ckt, int *type, void **modfast, IFuid modname) +{ + register GENmodel *mods; + + if(modfast != NULL && *(GENmodel **)modfast != NULL) { + /* already have modfast, so nothing to do */ + if(type) *type = (*(GENmodel **)modfast)->GENmodType; + return(OK); + } + if(*type >=0 && *type < DEVmaxnum) { + /* have device type, need to find model */ + /* look through all models */ + for(mods=((CKTcircuit *)ckt)->CKThead[*type]; mods != NULL ; + mods = mods->GENnextModel) { + if(mods->GENmodName == modname) { + *modfast = (char *)mods; + return(OK); + } + } + return(E_NOMOD); + } else if(*type == -1) { + /* look through all types (UGH - worst case - take forever) */ + for(*type = 0;*type CKThead[*type];mods!=NULL; + mods = mods->GENnextModel) { + if(mods->GENmodName == modname) { + *modfast = (char *)mods; + return(OK); + } + } + } + *type = -1; + return(E_NOMOD); + } else return(E_BADPARM); +} diff --git a/src/analysis/cktfnode.c b/src/analysis/cktfnode.c new file mode 100644 index 000000000..8cc3d8f34 --- /dev/null +++ b/src/analysis/cktfnode.c @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTfndNode + * find the given node given its name and return the node pointer + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "sperror.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +int +CKTfndNode(void *ckt, void **node, IFuid name) +{ + register CKTnode *here; + + for (here = ((CKTcircuit *)ckt)->CKTnodes; here; here = here->next) { + if(here->name == name) { + if(node) *node = (char *)here; + return(OK); + } + } + return(E_NOTFOUND); +} diff --git a/src/analysis/cktftask.c b/src/analysis/cktftask.c new file mode 100644 index 000000000..d5186845b --- /dev/null +++ b/src/analysis/cktftask.c @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTfndTask + * find the specified task - not yet supported in spice + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" + + + +/* ARGSUSED */ +int +CKTfndTask(void *ckt, void **taskPtr, IFuid taskName) +{ + return(E_UNSUPP); +} diff --git a/src/analysis/cktgrnd.c b/src/analysis/cktgrnd.c new file mode 100644 index 000000000..b154dc085 --- /dev/null +++ b/src/analysis/cktgrnd.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTground(ckt,node) + * specify the node to be the ground node of the given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" + + + +int +CKTground(void *inCkt, void **node, IFuid name) +{ + register CKTcircuit *ckt = (CKTcircuit *)inCkt; + + if(ckt->CKTnodes) { + if(ckt->CKTnodes->name) { + /*already exists - keep old name, but return it */ + if(node)*node = (char *)ckt->CKTnodes; + return(E_EXISTS); + } + ckt->CKTnodes->name = name; + ckt->CKTnodes->type = SP_VOLTAGE; + ckt->CKTnodes->number = 0; + } else { + ckt->CKTnodes = (CKTnode *)MALLOC(sizeof(CKTnode)); + if(ckt->CKTnodes == NULL) return(E_NOMEM); + ckt->CKTnodes->name = name; + ckt->CKTnodes->type = SP_VOLTAGE; + ckt->CKTnodes->number = 0; + ckt->CKTnodes->next = (CKTnode *)NULL; + ckt->CKTlastNode = ckt->CKTnodes; + } + if(node)*node = (char *)ckt->CKTnodes; + return(OK); + +} diff --git a/src/analysis/ckti2nod.c b/src/analysis/ckti2nod.c new file mode 100644 index 000000000..6726e21c1 --- /dev/null +++ b/src/analysis/ckti2nod.c @@ -0,0 +1,66 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTinst2Node + * get the name and node pointer for a node given a device it is + * bound to and the terminal of the device. + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "sperror.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "devdefs.h" + + + +extern SPICEdev *DEVices[]; + +int +CKTinst2Node(void *ckt, void *instPtr, int terminal, void **node, IFuid *nodeName) +{ + int nodenum; + register int type; + CKTnode *here; + + type = ((GENinstance *)instPtr)->GENmodPtr->GENmodType; + + if(*((*DEVices[type]).DEVpublic.terms) >= terminal && terminal >0 ) { + switch(terminal) { + default: return(E_NOTERM); + case 1: + nodenum = ((GENinstance *)instPtr)->GENnode1; + break; + case 2: + nodenum = ((GENinstance *)instPtr)->GENnode2; + break; + case 3: + nodenum = ((GENinstance *)instPtr)->GENnode3; + break; + case 4: + nodenum = ((GENinstance *)instPtr)->GENnode4; + break; + case 5: + nodenum = ((GENinstance *)instPtr)->GENnode5; + break; + } + /* ok, now we know its number, so we just have to find it.*/ + for(here = ((CKTcircuit*)ckt)->CKTnodes;here;here = here->next) { + if(here->number == nodenum) { + /* found it */ + *node = (void*) here; + *nodeName = here->name; + return(OK); + } + } + return(E_NOTFOUND); + } else { + return(E_NOTERM); + } +} diff --git a/src/analysis/cktic.c b/src/analysis/cktic.c new file mode 100644 index 000000000..8bf0f03d8 --- /dev/null +++ b/src/analysis/cktic.c @@ -0,0 +1,57 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "sperror.h" +#include "devdefs.h" + + + +extern SPICEdev *DEVices[]; + +int +CKTic(CKTcircuit *ckt) +{ + int error; + int size; + int i; + CKTnode *node; + + size = SMPmatSize(ckt->CKTmatrix); + for (i=0;i<=size;i++) { + *(ckt->CKTrhs+i)=0; + } + + for(node = ckt->CKTnodes;node != NULL; node = node->next) { + if(node->nsGiven) { + node->ptr = SMPmakeElt(ckt->CKTmatrix,node->number,node->number); + if(node->ptr == (double *)NULL) return(E_NOMEM); + ckt->CKThadNodeset = 1; + *(ckt->CKTrhs+node->number) = node->nodeset; + } + if(node->icGiven) { + if(! ( node->ptr)) { + node->ptr = SMPmakeElt(ckt->CKTmatrix,node->number, + node->number); + if(node->ptr == (double *)NULL) return(E_NOMEM); + } + *(ckt->CKTrhs+node->number) = node->ic; + } + } + + if(ckt->CKTmode & MODEUIC) { + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVsetic))(ckt->CKThead[i],ckt); + if(error) return(error); + } + } + } + + return(OK); +} diff --git a/src/analysis/cktinit.c b/src/analysis/cktinit.c new file mode 100644 index 000000000..c796ef697 --- /dev/null +++ b/src/analysis/cktinit.c @@ -0,0 +1,66 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "const.h" +#include "sperror.h" + + +int +CKTinit(void **ckt) + /* new circuit to create */ +{ + register int i; + register CKTcircuit *sckt; + + sckt = (CKTcircuit *)( *ckt = (char *)MALLOC(sizeof(CKTcircuit)) ); + if(sckt == NULL) return(E_NOMEM); + for (i=0;iCKThead[i] = (GENmodel *) NULL; + } + (sckt)->CKTmaxEqNum = 1; + (sckt)->CKTnodes = (CKTnode *)NULL; + (sckt)->CKTlastNode = (CKTnode *)NULL; + sckt->CKTmatrix = NULL; +#ifdef notdef + error = NIinit(sckt); + if(error) return(error); +#endif + + (sckt)->CKTgmin = 1e-12; + (sckt)->CKTabstol = 1e-12; + (sckt)->CKTreltol = 1e-3; + (sckt)->CKTchgtol = 1e-14; + (sckt)->CKTvoltTol = 1e-6; + (sckt)->CKTtrtol = 7; + (sckt)->CKTbypass = 1; + (sckt)->CKTisSetup = 0; + (sckt)->CKTtranMaxIter = 10; + (sckt)->CKTdcMaxIter = 100; + (sckt)->CKTdcTrcvMaxIter = 50; + (sckt)->CKTintegrateMethod = TRAPEZOIDAL; + (sckt)->CKTorder = 1; + (sckt)->CKTmaxOrder = 2; + (sckt)->CKTpivotAbsTol = 1e-13; + (sckt)->CKTpivotRelTol = 1e-3; + (sckt)->CKTtemp = 300.15; + (sckt)->CKTnomTemp = 300.15; + (sckt)->CKTdefaultMosL = 1e-4; + (sckt)->CKTdefaultMosW = 1e-4; + (sckt)->CKTdefaultMosAD = 0; + (sckt)->CKTdefaultMosAS = 0; + (sckt)->CKTsrcFact=1; + (sckt)->CKTdiagGmin=0; + (sckt)->CKTstat = (STATistics *)MALLOC(sizeof(STATistics)); + (sckt)->CKTtroubleNode = 0; + (sckt)->CKTtroubleElt = NULL; + (sckt)->CKTtimePoints = NULL; + if( (sckt)->CKTstat == (STATistics *)NULL) return(E_NOMEM); + + return(OK); +} diff --git a/src/analysis/cktlnkeq.c b/src/analysis/cktlnkeq.c new file mode 100644 index 000000000..ae9f65286 --- /dev/null +++ b/src/analysis/cktlnkeq.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + *CKTlinkEq + * Link an already allocated node into the necessary structure + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "smpdefs.h" +#include "cktdefs.h" + + +int +CKTlinkEq(CKTcircuit *ckt, CKTnode *node) +{ + if(!(ckt->CKTnodes)) { /* starting the list - allocate both ground and 1 */ + ckt->CKTnodes = (CKTnode *) MALLOC(sizeof(CKTnode)); + if(ckt->CKTnodes == (CKTnode *)NULL) return(E_NOMEM); + ckt->CKTnodes->name = (char *)NULL; + ckt->CKTnodes->type = SP_VOLTAGE; + ckt->CKTnodes->number = 0; + ckt->CKTlastNode = ckt->CKTnodes; + } + if(node == (CKTnode *)NULL) return(E_BADPARM); + ckt->CKTlastNode->next = node; + ckt->CKTlastNode = ckt->CKTlastNode->next; + ckt->CKTlastNode->number = ckt->CKTmaxEqNum++; + ckt->CKTlastNode->next = (CKTnode *)NULL; + return(OK); +} diff --git a/src/analysis/cktload.c b/src/analysis/cktload.c new file mode 100644 index 000000000..bdab4f964 --- /dev/null +++ b/src/analysis/cktload.c @@ -0,0 +1,166 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTload(ckt) + * this is a driver program to iterate through all the various + * load functions provided for the circuit elements in the + * given circuit + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + +static int ZeroNoncurRow(SMPmatrix *matrix, CKTnode *nodes, int rownum); + +int +CKTload(register CKTcircuit *ckt) +{ + extern SPICEdev *DEVices[]; + register int i; + register int size; + double startTime; + CKTnode *node; + int error; +#ifdef PARALLEL_ARCH + int ibuf[2]; + long type = MT_LOAD, length = 2; +#endif /* PARALLEL_ARCH */ +#ifdef STEPDEBUG + int noncon; +#endif /* STEPDEBUG */ + + startTime = (*(SPfrontEnd->IFseconds))(); + size = SMPmatSize(ckt->CKTmatrix); + for (i=0;i<=size;i++) { + *(ckt->CKTrhs+i)=0; + } + SMPclear(ckt->CKTmatrix); +#ifdef STEPDEBUG + noncon = ckt->CKTnoncon; +#endif /* STEPDEBUG */ + + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVload))(ckt->CKThead[i],ckt); + if (ckt->CKTnoncon) + ckt->CKTtroubleNode = 0; +#ifdef STEPDEBUG + if(noncon != ckt->CKTnoncon) { + printf("device type %s nonconvergence\n", + (*DEVices[i]).DEVpublic.name); + noncon = ckt->CKTnoncon; + } +#endif /* STEPDEBUG */ +#ifdef PARALLEL_ARCH + if (error) goto combine; +#else + if(error) return(error); +#endif /* PARALLEL_ARCH */ + } + } + if(ckt->CKTmode & MODEDC) { + /* consider doing nodeset & ic assignments */ + if(ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) { + /* do nodesets */ + for(node=ckt->CKTnodes;node;node=node->next) { + if(node->nsGiven) { + if (ZeroNoncurRow(ckt->CKTmatrix, ckt->CKTnodes, + node->number)) + { + *(ckt->CKTrhs+node->number) = 1.0e10 * node->nodeset; + *(node->ptr) = 1e10; + } else { + *(ckt->CKTrhs+node->number) = node->nodeset; + *(node->ptr) = 1; + } + /* DAG: Original CIDER fix. If above fix doesn't work, + * revert to this. + */ + /* + *(ckt->CKTrhs+node->number) += 1.0e10 * node->nodeset; + *(node->ptr) += 1.0e10; + */ + } + } + } + if( (ckt->CKTmode & MODETRANOP) && (!(ckt->CKTmode & MODEUIC))) { + for(node=ckt->CKTnodes;node;node=node->next) { + if(node->icGiven) { + if (ZeroNoncurRow(ckt->CKTmatrix, ckt->CKTnodes, + node->number)) + { + *(ckt->CKTrhs+node->number) += 1.0e10 * node->ic; + *(node->ptr) += 1.0e10; + } else { + *(ckt->CKTrhs+node->number) = node->ic; + *(node->ptr) = 1; + } + /* DAG: Original CIDER fix. If above fix doesn't work, + * revert to this. + */ + /* + *(ckt->CKTrhs+node->number) += 1.0e10 * node->ic; + *(node->ptr) += 1.0e10; + */ + } + } + } + } + /* SMPprint(ckt->CKTmatrix, stdout); if you want to debug, this is a + good place to start ... */ + +#ifdef PARALLEL_ARCH +combine: + ckt->CKTstat->STATloadTime += SPfrontEnd->IFseconds() - startTime; + startTime = SPfrontEnd->IFseconds(); + /* See if any of the DEVload functions bailed. If not, proceed. */ + ibuf[0] = error; + ibuf[1] = ckt->CKTnoncon; + IGOP_( &type, ibuf, &length, "+" ); + ckt->CKTnoncon = ibuf[1]; + ckt->CKTstat->STATsyncTime += SPfrontEnd->IFseconds() - startTime; + if (ibuf[0] == OK) { + startTime = SPfrontEnd->IFseconds(); + SMPcombine( ckt->CKTmatrix, ckt->CKTrhs, ckt->CKTrhsSpare ); + ckt->CKTstat->STATcombineTime += SPfrontEnd->IFseconds() - startTime; + return(OK); + } else { + if ( ibuf[0] != error ) { + error = E_MULTIERR; + } + return(error); + } +#else + ckt->CKTstat->STATloadTime += SPfrontEnd->IFseconds()-startTime; + return(OK); +#endif /* PARALLEL_ARCH */ +} + +static int +ZeroNoncurRow(SMPmatrix *matrix, CKTnode *nodes, int rownum) +{ + CKTnode *n; + double *x; + int currents; + + currents = 0; + for (n = nodes; n; n = n->next) { + x = (double *) SMPfindElt(matrix, rownum, n->number, 0); + if (x) { + if (n->type == SP_CURRENT) + currents = 1; + else + *x = 0.0; + } + } + return currents; +} diff --git a/src/analysis/cktmapn.c b/src/analysis/cktmapn.c new file mode 100644 index 000000000..61077ea98 --- /dev/null +++ b/src/analysis/cktmapn.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTmapNode(ckt,node) + * map the given node to the compact node numbering set of the + * specified circuit + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "sperror.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +int +CKTmapNode(void *ckt, void **node, IFuid name) +{ + register CKTnode *here; + int error; + IFuid uid; + CKTnode *mynode; + + for (here = ((CKTcircuit *)ckt)->CKTnodes; here; here = here->next) { + if(here->name == name) { + if(node) *node = (char *)here; + return(E_EXISTS); + } + } + /* not found, so must be a new one */ + error = CKTmkNode((CKTcircuit*)ckt,&mynode); /*allocate the node*/ + if(error) return(error); + error = (*(SPfrontEnd->IFnewUid))((void *)ckt, + &uid, + (IFuid) NULL, + name, + UID_SIGNAL, + (void**)mynode); /* get a uid for it */ + if(error) return(error); + mynode->name = uid; /* set the info we have */ + mynode->type = SP_VOLTAGE; + error = CKTlinkEq((CKTcircuit*)ckt,mynode); /* and link it in */ + if(node) *node = (void *)mynode; /* and finally, return it */ + return(OK); +} diff --git a/src/analysis/cktmask.c b/src/analysis/cktmask.c new file mode 100644 index 000000000..8a27c21e8 --- /dev/null +++ b/src/analysis/cktmask.c @@ -0,0 +1,30 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTmodAsk + * Ask questions about a specified device. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "devdefs.h" +#include "sperror.h" + + +extern SPICEdev *DEVices[]; + +/* ARGSUSED */ +int +CKTmodAsk(void *ckt, void *modfast, int which, IFvalue *value, IFvalue *selector) +{ + int type = ((GENmodel *)modfast)->GENmodType; + if((*DEVices[type]).DEVmodAsk) { + return( (*((*DEVices[type]).DEVmodAsk)) ((CKTcircuit *)ckt, + (GENmodel *)modfast,which,value) ); + } + return(E_BADPARM); +} diff --git a/src/analysis/cktmcrt.c b/src/analysis/cktmcrt.c new file mode 100644 index 000000000..73fb7d76a --- /dev/null +++ b/src/analysis/cktmcrt.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTmodCrt(type,name,ckt,fast) + * Create a device model of the specified type, with the given name + * in the named circuit. + */ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "cktdefs.h" +#include "sperror.h" + + + +int +CKTmodCrt(void *ckt, int type, void **modfast, IFuid name) +{ + extern SPICEdev *DEVices[]; + GENmodel *mymodfast = NULL; + int error; + + error = CKTfndMod(ckt,&type,(void**)&mymodfast,name); + if(error == E_NOMOD) { + mymodfast = (GENmodel *)MALLOC(*DEVices[type]->DEVmodSize); + if(mymodfast == (GENmodel *)NULL) return(E_NOMEM); + mymodfast->GENmodType = type; + mymodfast->GENmodName = name; + mymodfast->GENnextModel =(GENmodel *)((CKTcircuit *)ckt)->CKThead[type]; + ((CKTcircuit *)ckt)->CKThead[type]=(GENmodel *)mymodfast; + if(modfast) *modfast=(void *)mymodfast; + return(OK); + } else if (error==0) { + if(modfast) *modfast=(void *)mymodfast; + return(E_EXISTS); + } else { + return(error); + } + /*NOTREACHED*/ +} diff --git a/src/analysis/cktmkcur.c b/src/analysis/cktmkcur.c new file mode 100644 index 000000000..1c5d4b834 --- /dev/null +++ b/src/analysis/cktmkcur.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTmkCur + * make the given name a 'node' of type current in the + * specified circuit + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "sperror.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +int +CKTmkCur(CKTcircuit *ckt, CKTnode **node, IFuid basename, char *suffix) +{ + IFuid uid; + int error; + CKTnode *mynode; + CKTnode *checknode; + + error = CKTmkNode(ckt,&mynode); + if(error) return(error); + checknode = mynode; + error = (*(SPfrontEnd->IFnewUid))((void *)ckt,&uid,basename, + suffix,UID_SIGNAL,(void**)&checknode); + if(error) { + FREE(mynode); + if(node) *node = checknode; + return(error); + } + mynode->name = uid; + mynode->type = SP_CURRENT; + if(node) *node = mynode; + error = CKTlinkEq(ckt,mynode); + return(error); +} diff --git a/src/analysis/cktmknod.c b/src/analysis/cktmknod.c new file mode 100644 index 000000000..ac916fab5 --- /dev/null +++ b/src/analysis/cktmknod.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + *CKTmkNode(ckt,node) + * Tentatively allocate a new circuit equation structure + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "smpdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +CKTmkNode(CKTcircuit *ckt, CKTnode **node) +{ + CKTnode *mynode; + + mynode = (CKTnode *)MALLOC(sizeof(CKTnode)); + if(mynode == (CKTnode *)NULL) return(E_NOMEM); + mynode->next = (CKTnode *)NULL; + mynode->name = (IFuid) 0; + + if(node) *node = mynode; + return(OK); +} diff --git a/src/analysis/cktmkvol.c b/src/analysis/cktmkvol.c new file mode 100644 index 000000000..72b15484c --- /dev/null +++ b/src/analysis/cktmkvol.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* CKTmkVolt + * make the given name a 'node' of type current in the + * specified circuit + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "sperror.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +int +CKTmkVolt(CKTcircuit *ckt, CKTnode **node, IFuid basename, char *suffix) +{ + IFuid uid; + int error; + CKTnode *mynode; + CKTnode *checknode; + + error = CKTmkNode(ckt,&mynode); + if(error) return(error); + checknode = mynode; + error = (*(SPfrontEnd->IFnewUid))((void *)ckt,&uid,basename, + suffix,UID_SIGNAL,(void**)&checknode); + if(error) { + FREE(mynode); + if(node) *node = checknode; + return(error); + } + mynode->name = uid; + mynode->type = SP_VOLTAGE; + if(node) *node = mynode; + error = CKTlinkEq(ckt,mynode); + return(error); +} diff --git a/src/analysis/cktmpar.c b/src/analysis/cktmpar.c new file mode 100644 index 000000000..232db4d88 --- /dev/null +++ b/src/analysis/cktmpar.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTmodParam + * attach the given parameter to the specified model in the given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "devdefs.h" +#include "sperror.h" + + +extern SPICEdev *DEVices[]; + +/* ARGSUSED */ +int +CKTmodParam(void *ckt, void *modfast, int param, IFvalue *val, IFvalue *selector) +{ + register int type = ((GENmodel *)modfast)->GENmodType; + + if (((*DEVices[type]).DEVmodParam)) { + return(((*((*DEVices[type]).DEVmodParam)) (param,val, + (GENmodel *)modfast))); + } else { + return(E_BADPARM); + } +} diff --git a/src/analysis/cktnames.c b/src/analysis/cktnames.c new file mode 100644 index 000000000..da0afb9b6 --- /dev/null +++ b/src/analysis/cktnames.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + + /* + * CKTnames(ckt) + * output information on all circuit nodes/equations + * + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" + + +int +CKTnames(register CKTcircuit *ckt, int *numNames, register IFuid **nameList) +{ + register CKTnode *here; + register int i; + *numNames = ckt->CKTmaxEqNum-1; + *nameList = (IFuid *)MALLOC(*numNames * sizeof(IFuid )); + if ((*nameList) == (IFuid *)NULL) return(E_NOMEM); + i=0; + for (here = ckt->CKTnodes->next; here; here = here->next) { + *((*nameList)+i++) = here->name; + } + return(OK); +} + +int +CKTdnames(CKTcircuit *ckt) +{ + CKTnode *here; + register int i; + + i=0; + for (here = ckt->CKTnodes->next; here; here = here->next) { + printf("%03d: %s\n", here->number, (char *)here->name); + } + return(OK); +} diff --git a/src/analysis/cktnewan.c b/src/analysis/cktnewan.c new file mode 100644 index 000000000..63e10fe29 --- /dev/null +++ b/src/analysis/cktnewan.c @@ -0,0 +1,34 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "tskdefs.h" +#include "jobdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" + + +extern SPICEanalysis *analInfo[]; + +/* ARGSUSED */ +int +CKTnewAnal(void *ckt, int type, IFuid name, void **analPtr, void *taskPtr) +{ + if(type==0) { + /* special case for analysis type 0 == option card */ + *analPtr=taskPtr; /* pointer to the task itself */ + (*(JOB **)analPtr)->JOBname = name; + (*(JOB **)analPtr)->JOBtype = type; + return(OK); /* doesn't need to be created */ + } + *analPtr = (void *)MALLOC(analInfo[type]->size); + if(*analPtr==NULL) return(E_NOMEM); + (*(JOB **)analPtr)->JOBname = name; + (*(JOB **)analPtr)->JOBtype = type; + (*(JOB **)analPtr)->JOBnextJob = ((TSKtask *)taskPtr)->jobs; + ((TSKtask *)taskPtr)->jobs = (JOB *)*analPtr; + return(OK); +} diff --git a/src/analysis/cktneweq.c b/src/analysis/cktneweq.c new file mode 100644 index 000000000..86009cb0f --- /dev/null +++ b/src/analysis/cktneweq.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + *CKTnewEq(ckt,node,name) + * Allocate a new circuit equation number (returned) in the specified + * circuit to contain a new equation or node + * returns -1 for failure to allocate a node number + * + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "smpdefs.h" +#include "cktdefs.h" + + +int +CKTnewEq(void *inCkt, void **node, IFuid name) +{ + CKTnode *mynode; + register CKTcircuit *ckt = (CKTcircuit *)inCkt; + int error; + + error = CKTmkNode(ckt,&mynode); + if(error) return(error); + + if(node) *node = (void *)mynode; + mynode->name = name; + + error = CKTlinkEq(ckt,mynode); + + return(error); +} diff --git a/src/analysis/cktnewn.c b/src/analysis/cktnewn.c new file mode 100644 index 000000000..2b5505fd0 --- /dev/null +++ b/src/analysis/cktnewn.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + *CKTnewNode(ckt,node,name) + * Allocate a new circuit equation number (returned) in the specified + * circuit to contain a new equation or node + * returns -1 for failure to allocate a node number + * + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "smpdefs.h" +#include "cktdefs.h" + + +/* should just call CKTnewEQ and set node type afterwards */ +int +CKTnewNode(void *inCkt, void **node, IFuid name) +{ + register CKTcircuit *ckt = (CKTcircuit *)inCkt; + if(!(ckt->CKTnodes)) { /* starting the list - allocate both ground and 1 */ + ckt->CKTnodes = (CKTnode *) MALLOC(sizeof(CKTnode)); + if(ckt->CKTnodes == (CKTnode *)NULL) return(E_NOMEM); + ckt->CKTnodes->name = (char *)NULL; + ckt->CKTnodes->type = SP_VOLTAGE; + ckt->CKTnodes->number = 0; + ckt->CKTlastNode = ckt->CKTnodes; + } + ckt->CKTlastNode->next = (CKTnode *)MALLOC(sizeof(CKTnode)); + if(ckt->CKTlastNode->next == (CKTnode *)NULL) return(E_NOMEM); + ckt->CKTlastNode = ckt->CKTlastNode->next; + ckt->CKTlastNode->name = name; + ckt->CKTlastNode->number = ckt->CKTmaxEqNum++; + ckt->CKTlastNode->type = SP_VOLTAGE; + ckt->CKTlastNode->next = (CKTnode *)NULL; + + if(node) *node = (void *)ckt->CKTlastNode; + return(OK); +} diff --git a/src/analysis/cktnodn.c b/src/analysis/cktnodn.c new file mode 100644 index 000000000..14f6db467 --- /dev/null +++ b/src/analysis/cktnodn.c @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* + *CKTnodName(ckt) + * output information on all circuit nodes/equations + * + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" + + + +IFuid +CKTnodName(CKTcircuit *ckt, register int nodenum) +{ + register CKTnode *here; + + for(here = ckt->CKTnodes;here; here = here->next) { + if(here->number == nodenum) { + /* found it */ + return(here->name); + } + } + /* doesn't exist - do something */ + return("UNKNOWN NODE"); +} diff --git a/src/analysis/cktnoise.c b/src/analysis/cktnoise.c new file mode 100644 index 000000000..6e51d1e0f --- /dev/null +++ b/src/analysis/cktnoise.c @@ -0,0 +1,140 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +/* + * CKTnoise (ckt, mode, operation, data) + * + * This routine is responsible for naming and evaluating all of the + * noise sources in the circuit. It uses a series of subroutines to + * name and evaluate the sources associated with each model, and then + * it evaluates the noise for the entire circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "sperror.h" + + +int +CKTnoise (CKTcircuit *ckt, int mode, int operation, Ndata *data) +{ + double outNdens; + int i; + extern SPICEdev *DEVices[]; + IFvalue outData; /* output variable (points to list of outputs)*/ + IFvalue refVal; /* reference variable (always 0)*/ + int error; + + outNdens = 0.0; + + /* let each device decide how many and what type of noise sources it has */ + + for (i=0; i < DEVmaxnum; i++) { + if ( ((*DEVices[i]).DEVnoise != NULL) && (ckt->CKThead[i] != NULL) ) { + error = (*((*DEVices[i]).DEVnoise))(mode,operation,ckt->CKThead[i], + ckt,data, &outNdens); + if (error) return (error); + } + } + + switch (operation) { + + case N_OPEN: + + /* take care of the noise for the circuit as a whole */ + + switch (mode) { + + case N_DENS: + + data->namelist = (IFuid *)trealloc((char *)data->namelist, + (data->numPlots + 1)*sizeof(IFuid)); + + (*(SPfrontEnd->IFnewUid))(ckt, &(data->namelist[data->numPlots++]), + (IFuid)NULL,"onoise_spectrum",UID_OTHER,(void **)NULL); + + data->namelist = (IFuid *)trealloc((char *)data->namelist, + (data->numPlots + 1)*sizeof(IFuid)); + + (*(SPfrontEnd->IFnewUid))(ckt, &(data->namelist[data->numPlots++]), + (IFuid)NULL,"inoise_spectrum",UID_OTHER,(void **)NULL); + + /* we've added two more plots */ + + data->outpVector = + (double *)MALLOC(data->numPlots * sizeof(double)); + break; + + case INT_NOIZ: + + data->namelist = (IFuid *)trealloc((char *)data->namelist, + (data->numPlots + 1)*sizeof(IFuid)); + (*(SPfrontEnd->IFnewUid))(ckt, &(data->namelist[data->numPlots++]), + (IFuid)NULL,"onoise_total",UID_OTHER,(void **)NULL); + + data->namelist = (IFuid *)trealloc((char *)data->namelist, + (data->numPlots + 1)*sizeof(IFuid)); + (*(SPfrontEnd->IFnewUid))(ckt, &(data->namelist[data->numPlots++]), + (IFuid)NULL,"inoise_total",UID_OTHER,(void **)NULL); + /* we've added two more plots */ + + data->outpVector = + (double *) MALLOC(data->numPlots * sizeof(double)); + break; + + default: + return (E_INTERN); + } + + break; + + case N_CALC: + + switch (mode) { + + case N_DENS: + if ((((NOISEAN*)ckt->CKTcurJob)->NStpsSm == 0) + || data->prtSummary) + { + data->outpVector[data->outNumber++] = outNdens; + data->outpVector[data->outNumber++] = + (outNdens * data->GainSqInv); + + refVal.rValue = data->freq; /* the reference is the freq */ + outData.v.numValue = data->outNumber; /* vector number */ + outData.v.vec.rVec = data->outpVector; /* vector of outputs */ + (*(SPfrontEnd->OUTpData))(data->NplotPtr,&refVal,&outData); + } + break; + + case INT_NOIZ: + data->outpVector[data->outNumber++] = data->outNoiz; + data->outpVector[data->outNumber++] = data->inNoise; + outData.v.vec.rVec = data->outpVector; /* vector of outputs */ + outData.v.numValue = data->outNumber; /* vector number */ + (*(SPfrontEnd->OUTpData))(data->NplotPtr,&refVal,&outData); + break; + + default: + return (E_INTERN); + } + break; + + case N_CLOSE: + (*(SPfrontEnd->OUTendPlot))(data->NplotPtr); + FREE(data->namelist); + FREE(data->outpVector); + break; + + default: + return (E_INTERN); + } + return (OK); +} diff --git a/src/analysis/cktntask.c b/src/analysis/cktntask.c new file mode 100644 index 000000000..0aa6e035c --- /dev/null +++ b/src/analysis/cktntask.c @@ -0,0 +1,56 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "tskdefs.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "iferrmsg.h" + + +/* ARGSUSED */ +int +CKTnewTask(void *ckt, void **taskPtr, IFuid taskName) +{ + register TSKtask *tsk; + *taskPtr = (void *)MALLOC(sizeof(TSKtask)); + if(*taskPtr==NULL) return(E_NOMEM); + tsk = *(TSKtask **)taskPtr; + tsk->TSKname = taskName; + tsk->TSKgmin = 1e-12; + tsk->TSKabstol = 1e-12; + tsk->TSKreltol = 1e-3; + tsk->TSKchgtol = 1e-14; + tsk->TSKvoltTol = 1e-6; +#ifdef NEWTRUNC + tsk->TSKlteReltol = 1e-3; + tsk->TSKlteAbstol = 1e-6; +#endif /* NEWTRUNC */ + tsk->TSKtrtol = 7; + tsk->TSKbypass = 1; + tsk->TSKtranMaxIter = 10; + tsk->TSKdcMaxIter = 100; + tsk->TSKdcTrcvMaxIter = 50; + tsk->TSKintegrateMethod = TRAPEZOIDAL; + tsk->TSKmaxOrder = 2; + tsk->TSKnumSrcSteps = 10; + tsk->TSKnumGminSteps = 10; + tsk->TSKpivotAbsTol = 1e-13; + tsk->TSKpivotRelTol = 1e-3; + tsk->TSKtemp = 300.15; + tsk->TSKnomTemp = 300.15; + tsk->TSKdefaultMosL = 1e-4; + tsk->TSKdefaultMosW = 1e-4; + tsk->TSKdefaultMosAD = 0; + tsk->TSKdefaultMosAS = 0; + tsk->TSKnoOpIter=0; + tsk->TSKtryToCompact=0; + tsk->TSKbadMos3=0; + tsk->TSKkeepOpInfo=0; + return(OK); +} diff --git a/src/analysis/cktnum2n.c b/src/analysis/cktnum2n.c new file mode 100644 index 000000000..d9e8177fd --- /dev/null +++ b/src/analysis/cktnum2n.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTnum2nod + * find the given node given its name and return the node pointer + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "sperror.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +CKTnode * +CKTnum2nod(CKTcircuit *ckt, int node) +{ + register CKTnode *here; + + for (here = ((CKTcircuit *)ckt)->CKTnodes; here; here = here->next) { + if(here->number == node) { + return(here); + } + } + return((CKTnode *)NULL); +} diff --git a/src/analysis/cktop.c b/src/analysis/cktop.c new file mode 100644 index 000000000..d68fc3e56 --- /dev/null +++ b/src/analysis/cktop.c @@ -0,0 +1,146 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + +int +CKTop(CKTcircuit *ckt, long int firstmode, long int continuemode, int iterlim) +{ + int converged; + int i; + + ckt->CKTmode = firstmode; + if(!ckt->CKTnoOpIter) { + converged = NIiter(ckt,iterlim); + } else { + converged = 1; /* the 'go directly to gmin stepping' option */ + } + if(converged != 0) { + /* no convergence on the first try, so we do something else */ + /* first, check if we should try gmin stepping */ + /* note that no path out of this code allows ckt->CKTdiagGmin to be + * anything but 0.000000000 + */ + if(ckt->CKTnumGminSteps >1) { + ckt->CKTmode = firstmode; + (*(SPfrontEnd->IFerror))(ERR_INFO, + "starting Gmin stepping",(IFuid *)NULL); + ckt->CKTdiagGmin = ckt->CKTgmin; + for(i=0;iCKTnumGminSteps;i++) { + ckt->CKTdiagGmin *= 10; + } + for(i=0;i<=ckt->CKTnumGminSteps;i++) { + ckt->CKTnoncon =1; + converged = NIiter(ckt,iterlim); + if(converged != 0) { + ckt->CKTdiagGmin = 0; + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "Gmin step failed",(IFuid *)NULL); + break; + } + ckt->CKTdiagGmin /= 10; + ckt->CKTmode=continuemode; + (*(SPfrontEnd->IFerror))(ERR_INFO, + "One successful Gmin step",(IFuid *)NULL); + } + ckt->CKTdiagGmin = 0; + converged = NIiter(ckt,iterlim); + if(converged == 0) { + (*(SPfrontEnd->IFerror))(ERR_INFO, + "Gmin stepping completed",(IFuid *)NULL); + return(0); + } + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "Gmin stepping failed",(IFuid *)NULL); + + } + /* now, we'll try source stepping - we scale the sources + * to 0, converge, then start stepping them up until they + * are at their normal values + * + * note that no path out of this code allows ckt->CKTsrcFact to be + * anything but 1.000000000 + */ + if(ckt->CKTnumSrcSteps >1) { + ckt->CKTmode = firstmode; + (*(SPfrontEnd->IFerror))(ERR_INFO, + "starting source stepping",(IFuid *)NULL); + for(i=0;i<=ckt->CKTnumSrcSteps;i++) { + ckt->CKTsrcFact = ((double)i)/((double)ckt->CKTnumSrcSteps); + converged = NIiter(ckt,iterlim); + ckt->CKTmode = continuemode; + if(converged != 0) { + ckt->CKTsrcFact = 1; + ckt->CKTcurrentAnalysis = DOING_TRAN; + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "source stepping failed",(IFuid *)NULL); + return(converged); + } + (*(SPfrontEnd->IFerror))(ERR_INFO, + "One successful source step",(IFuid *)NULL); + } + (*(SPfrontEnd->IFerror))(ERR_INFO, + "Source stepping completed",(IFuid *)NULL); + ckt->CKTsrcFact = 1; + return(0); + } else { + return(converged); + } + } + return(0); +} + +/* CKTconvTest(ckt) + * this is a driver program to iterate through all the various + * convTest functions provided for the circuit elements in the + * given circuit + */ + +int +CKTconvTest(register CKTcircuit *ckt) +{ + extern SPICEdev *DEVices[]; + register int i; + int error = OK; +#ifdef PARALLEL_ARCH + int ibuf[2]; + long type = MT_CONV, length = 2; +#endif /* PARALLEL_ARCH */ + + for (i=0;iCKThead[i] != NULL)) { + error = (*((*DEVices[i]).DEVconvTest))(ckt->CKThead[i],ckt); + } +#ifdef PARALLEL_ARCH + if (error || ckt->CKTnoncon) goto combine; +#else + if (error) return(error); + if (ckt->CKTnoncon) { + /* printf("convTest: device %s failed\n", + (*DEVices[i]).DEVpublic.name); */ + return(OK); + } +#endif /* PARALLEL_ARCH */ + } +#ifdef PARALLEL_ARCH +combine: + /* See if any of the DEVconvTest functions bailed. If not, proceed. */ + ibuf[0] = error; + ibuf[1] = ckt->CKTnoncon; + IGOP_( &type, ibuf, &length, "+" ); + ckt->CKTnoncon = ibuf[1]; + if ( ibuf[0] != error ) { + error = E_MULTIERR; + } + return (error); +#else + return(OK); +#endif /* PARALLEL_ARCH */ +} diff --git a/src/analysis/cktparam.c b/src/analysis/cktparam.c new file mode 100644 index 000000000..355598467 --- /dev/null +++ b/src/analysis/cktparam.c @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTparam + * attach the given parameter to the specified device in the given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "devdefs.h" +#include "sperror.h" + + + +extern SPICEdev *DEVices[]; + +/* ARGSUSED */ +int +CKTparam(void *ckt, void *fast, int param, IFvalue *val, IFvalue *selector) +{ + register int type; + GENinstance *myfast = (GENinstance *)fast; + type = myfast->GENmodPtr->GENmodType; + if(((*DEVices[type]).DEVparam)) { + return(((*((*DEVices[type]).DEVparam)) (param,val,myfast,selector))); + } else { + return(E_BADPARM); + } +} diff --git a/src/analysis/cktpartn.c b/src/analysis/cktpartn.c new file mode 100644 index 000000000..e912ac344 --- /dev/null +++ b/src/analysis/cktpartn.c @@ -0,0 +1,42 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1992 David A. Gates, UC Berkeley CADgroup +**********/ + + /* CKTpartition(ckt) + * this labels each instance of a circuit as belonging to a + * particular processor in a multiprocessor computer. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" + + + +extern SPICEdev *DEVices[]; + +int +CKTpartition(register CKTcircuit *ckt) +{ + register int i, instNum = 0; + register GENmodel *model; + register GENinstance *inst; + + for (i=0;iCKThead[i] != NULL) ) { + for (model = ckt->CKThead[i]; model; model = model->GENnextModel) { + for (inst = model->GENinstances; inst; + inst = inst->GENnextInstance) { + inst->GENowner = instNum % ARCHsize; + instNum++; + } + } + } + } + return(OK); +} diff --git a/src/analysis/cktpmnam.c b/src/analysis/cktpmnam.c new file mode 100644 index 000000000..6743d6e3b --- /dev/null +++ b/src/analysis/cktpmnam.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * CKTpModName() + * + * Take a parameter by Name and set it on the specified model + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "sperror.h" + + + +extern SPICEdev *DEVices[]; + +/* ARGSUSED */ +int +CKTpModName(char *parm, IFvalue *val, CKTcircuit *ckt, int type, IFuid name, GENmodel **modfast) + /* the name of the parameter to set */ + /* the parameter union containing the value to set */ + /* the circuit this model is a member of */ + /* the device type code to the model being parsed */ + /* the name of the model being parsed */ + /* direct pointer to model being parsed */ + +{ + int error; /* int to store evaluate error return codes in */ + int i; + + for(i=0;i<(*(*DEVices[type]).DEVpublic.numModelParms);i++) { + if(strcmp(parm,((*DEVices[type]).DEVpublic.modelParms[i].keyword))==0){ + error = CKTmodParam((void *)ckt,(void *)*modfast, + (*DEVices[type]).DEVpublic.modelParms[i].id,val, + (IFvalue*)NULL); + if(error) return(error); + break; + } + } + if(i==(*(*DEVices[type]).DEVpublic.numModelParms)) { + return(E_BADPARM); + } + return(OK); +} diff --git a/src/analysis/cktpname.c b/src/analysis/cktpname.c new file mode 100644 index 000000000..187e5df3a --- /dev/null +++ b/src/analysis/cktpname.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* + * CKTpName() + * + * Take a parameter by Name and set it on the specified device + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "sperror.h" + + + +extern SPICEdev *DEVices[]; + +/* ARGSUSED */ +int +CKTpName(char *parm, IFvalue *val, CKTcircuit *ckt, int dev, char *name, GENinstance **fast) + /* the name of the parameter to set */ + /* the parameter union containing the value to set */ + /* the circuit this device is a member of */ + /* the device type code to the device being parsed */ + /* the name of the device being parsed */ + /* direct pointer to device being parsed */ + +{ + int error; /* int to store evaluate error return codes in */ + int i; + + for(i=0;i<(*(*DEVices[dev]).DEVpublic.numInstanceParms);i++) { + if(strcmp(parm, + ((*DEVices[dev]).DEVpublic.instanceParms[i].keyword))==0) { + error = CKTparam((void*)ckt,(void *)*fast, + (*DEVices[dev]).DEVpublic.instanceParms[i].id,val, + (IFvalue *)NULL); + if(error) return(error); + break; + } + } + if(i==(*(*DEVices[dev]).DEVpublic.numInstanceParms)) { + return(E_BADPARM); + } + return(OK); +} diff --git a/src/analysis/cktpzld.c b/src/analysis/cktpzld.c new file mode 100644 index 000000000..0abbf31eb --- /dev/null +++ b/src/analysis/cktpzld.c @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include +#include "pzdefs.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "devdefs.h" +#include "sperror.h" + + +extern SPICEdev *DEVices[]; + +int +CKTpzLoad(CKTcircuit *ckt, SPcomplex *s) +{ + PZAN *pzan = (PZAN *) (ckt->CKTcurJob); + int error; + int i; +#ifdef PARALLEL_ARCH + long type = MT_PZLOAD, length = 1; +#endif /* PARALLEL_ARCH */ + + for (i = 0; i <= SMPmatSize(ckt->CKTmatrix); i++) { + ckt->CKTrhs[i] = 0.0; + ckt->CKTirhs[i] = 0.0; + } + + SMPcClear(ckt->CKTmatrix); + for (i = 0; i < DEVmaxnum; i++) { + if (DEVices[i]->DEVpzLoad != NULL && ckt->CKThead[i] != NULL) { + error = (*DEVices[i]->DEVpzLoad)(ckt->CKThead[i], ckt, s); +#ifdef PARALLEL_ARCH + if (error) goto combine; +#else + if(error) return(error); +#endif /* PARALLEL_ARCH */ + } + } +#ifdef PARALLEL_ARCH +combine: + /* See if any of the DEVload functions bailed. If not, proceed. */ + IGOP_( &type, &error, &length, "max" ); + if (error == OK) { + SMPcCombine( ckt->CKTmatrix, ckt->CKTrhs, ckt->CKTrhsSpare, + ckt->CKTirhs, ckt->CKTirhsSpare ); + } else { + return(error); + } +#endif /* PARALLEL_ARCH */ + +#ifdef notdef + printf("*** Before PZ adjustments *\n"); + SMPprint(ckt->CKTmatrix, stdout); +#endif + + if (pzan->PZbalance_col && pzan->PZsolution_col) { + SMPcAddCol(ckt->CKTmatrix, pzan->PZbalance_col, pzan->PZsolution_col); + /* AC sources ?? XXX */ + } + + if (pzan->PZsolution_col) { + SMPcZeroCol(ckt->CKTmatrix, pzan->PZsolution_col); + } + + /* Driving function (current source) */ + if (pzan->PZdrive_pptr) + *pzan->PZdrive_pptr = 1.0; + if (pzan->PZdrive_nptr) + *pzan->PZdrive_nptr = -1.0; + +#ifdef notdef + printf("*** After PZ adjustments *\n"); + SMPprint(ckt->CKTmatrix, stdout); +#endif + + return(OK); +} diff --git a/src/analysis/cktpzset.c b/src/analysis/cktpzset.c new file mode 100644 index 000000000..095c35e29 --- /dev/null +++ b/src/analysis/cktpzset.c @@ -0,0 +1,105 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* CKTpzSetup(ckt) + * iterate through all the various + * pzSetup functions provided for the circuit elements in the + * given circuit, setup ... + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + +#define CKALLOC(var,size,type) \ + if(size && (!(var =(type *)MALLOC((size)*sizeof(type))))){\ + return(E_NOMEM);\ +} + +int +CKTpzSetup(register CKTcircuit *ckt, int type) +{ + extern SPICEdev *DEVices[]; + PZAN *pzan = (PZAN *) ckt->CKTcurJob; + SMPmatrix *matrix; + int error; + int i, temp, solution_col, balance_col; + int input_pos, input_neg, output_pos, output_neg; + + NIdestroy(ckt); + error = NIinit(ckt); + if (error) + return(error); + matrix = ckt->CKTmatrix; + + /* Really awful . . . */ + ckt->CKTnumStates = 0; + + for (i = 0; i < DEVmaxnum; i++) { + if (DEVices[i]->DEVpzSetup != NULL && ckt->CKThead[i] != NULL) { + error = (*DEVices[i]->DEVpzSetup)(matrix, ckt->CKThead[i], + ckt, &ckt->CKTnumStates); + if (error != OK) + return(error); + } + } + + solution_col = 0; + balance_col = 0; + + input_pos = pzan->PZin_pos; + input_neg = pzan->PZin_neg; + + if (type == PZ_DO_ZEROS) { + /* Vo/Ii in Y */ + output_pos = pzan->PZout_pos; + output_neg = pzan->PZout_neg; + } else if (pzan->PZinput_type == PZ_IN_VOL) { + /* Vi/Ii in Y */ + output_pos = pzan->PZin_pos; + output_neg = pzan->PZin_neg; + } else { + /* Denominator */ + output_pos = 0; + output_neg = 0; + input_pos = 0; + input_neg = 0; + } + + if (output_pos) { + solution_col = output_pos; + if (output_neg) + balance_col = output_neg; + } else { + solution_col = output_neg; + temp = input_pos; + input_pos = input_neg; + input_neg = temp; + } + + if (input_pos) + pzan->PZdrive_pptr = SMPmakeElt(matrix, input_pos, solution_col); + else + pzan->PZdrive_pptr = NULL; + + if (input_neg) + pzan->PZdrive_nptr = SMPmakeElt(matrix, input_neg, solution_col); + else + pzan->PZdrive_nptr = NULL; + + pzan->PZsolution_col = solution_col; + pzan->PZbalance_col = balance_col; + + pzan->PZnumswaps = 1; + + error = NIreinit(ckt); + if (error) + return(error); + + return OK; +} diff --git a/src/analysis/cktpzstr.c b/src/analysis/cktpzstr.c new file mode 100644 index 000000000..7f70fa7d6 --- /dev/null +++ b/src/analysis/cktpzstr.c @@ -0,0 +1,1196 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + * A variant on the "zeroin" method. This is a bit convoluted. + */ + +#include "ngspice.h" +#include +#include "pzdefs.h" +#include "complex.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + +#ifdef PZDEBUG +# ifndef notdef +# define DEBUG(N) if (Debug >= (unsigned) (N)) +static unsigned int Debug = 1; +# else +# define DEBUG(N) if (0) +# endif +#endif + +/* static function definitions */ + +static int CKTpzStrat(PZtrial **set); +static int CKTpzStep(int strat, PZtrial **set); +static int CKTpzRunTrial(CKTcircuit *ckt, PZtrial **new_trialp, PZtrial **set); +static int CKTpzVerify(PZtrial **set, PZtrial *new_trial); +static void clear_trials(int mode); +static void check_flat(PZtrial *a, PZtrial *b); +void CKTpzUpdateSet(PZtrial **set, PZtrial *new); +void zaddeq(double *a, int *amag, double x, int xmag, double y, int ymag); +void CKTpzReset(PZtrial **set); + + +#ifdef PZDEBUG +static void show_trial( ); +#endif + +#define NITER_LIM 200 + +#define SHIFT_LEFT 2 +#define SHIFT_RIGHT 3 +#define SKIP_LEFT 4 +#define SKIP_RIGHT 5 +#define INIT 6 + +#define GUESS 7 +#define SPLIT_LEFT 8 +#define SPLIT_RIGHT 9 + +#define MULLER 10 +#define SYM 11 +#define SYM2 12 +#define COMPLEX_INIT 13 +#define COMPLEX_GUESS 14 +#define QUIT 15 + +#define NEAR_LEFT 4 +#define MID_LEFT 5 +#define FAR_LEFT 6 +#define NEAR_RIGHT 7 +#define FAR_RIGHT 8 +#define MID_RIGHT 9 + +#ifdef PZDEBUG +static char *snames[ ] = { + "none", + "none", + "shift left", + "shift right", + "skip left", + "skip right", + "init", + "guess", + "split left", + "split right", + "Muller", + "sym 1", + "sym 2", + "complex_init", + "complex_guess", + "quit", + "none" + }; +#endif + +#define sgn(X) ((X) < 0 ? -1 : (X) == 0 ? 0 : 1) + +#define ISAROOT 2 +#define ISAREPEAT 4 +#define ISANABERRATION 8 +#define ISAMINIMA 16 + +extern double NIpzK; +extern int NIpzK_mag; + +int CKTpzTrapped; + +static int NZeros, NFlat, Max_Zeros; +static PZtrial *ZeroTrial, *Trials; +static int Seq_Num; +static double Guess_Param; +static double High_Guess, Low_Guess; +static int Last_Move, Consec_Moves; +static int NIter, NTrials; +static int Aberr_Num; + +int PZeval(int strat, PZtrial **set, PZtrial **new_trial_p); +static PZtrial *pzseek(PZtrial *t, int dir); +static int alter(PZtrial *new, PZtrial *nearto, double abstol, double reltol); + +int +CKTpzFindZeros(CKTcircuit *ckt, PZtrial **rootinfo, int *rootcount) +{ + PZtrial *new_trial; + PZtrial *neighborhood[3]; + int strat; + int error; + char ebuf[513]; + + NIpzK = 0.0; + NIpzK_mag = 0; + High_Guess = -1.0; + Low_Guess = 1.0; + ZeroTrial = 0; + Trials = 0; + NZeros = 0; + NFlat = 0; + Max_Zeros = SMPmatSize(ckt->CKTmatrix); + NIter = 0; + error = OK; + CKTpzTrapped = 0; + Aberr_Num = 0; + NTrials = 0; + ckt->CKTniState |= NIPZSHOULDREORDER; /* Initial for LU fill-ins */ + + Seq_Num = 1; + + CKTpzReset(neighborhood); + + do { + + while ((strat = CKTpzStrat(neighborhood)) < GUESS && !CKTpzTrapped) + if (!CKTpzStep(strat, neighborhood)) { + strat = GUESS; +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "\t\tGuess\n"); +#endif + break; + } + + NIter += 1; + + /* Evaluate current strategy */ + error = PZeval(strat, neighborhood, &new_trial); + if (error != OK) + return error; + + error = CKTpzRunTrial(ckt, &new_trial, neighborhood); + if (error != OK) + return error; + + if (new_trial->flags & ISAROOT) { + if (CKTpzVerify(neighborhood, new_trial)) { + NIter = 0; + CKTpzReset(neighborhood); + } else + /* XXX Verify fails ?!? */ + CKTpzUpdateSet(neighborhood, new_trial); + } else if (new_trial->flags & ISANABERRATION) { + CKTpzReset(neighborhood); + Aberr_Num += 1; + free(new_trial); + } else if (new_trial->flags & ISAMINIMA) { + neighborhood[0] = NULL; + neighborhood[1] = new_trial; + neighborhood[2] = NULL; + } else { + CKTpzUpdateSet(neighborhood, new_trial); /* Replace a value */ + } + + if ((*(SPfrontEnd->IFpauseTest))( )) { + sprintf(ebuf, + "Pole-Zero analysis interrupted; %d trials, %d roots\n", + Seq_Num, NZeros); + (*(SPfrontEnd->IFerror))(ERR_WARNING, ebuf, 0); + error = E_PAUSE; + break; + } + } while (High_Guess - Low_Guess < 1e40 + && NZeros < Max_Zeros + && NIter < NITER_LIM && Aberr_Num < 3 + && High_Guess - Low_Guess < 1e35 /* XXX Should use mach const */ + && (!neighborhood[0] || !neighborhood[2] || CKTpzTrapped + || neighborhood[2]->s.real - neighborhood[0]->s.real < 1e22)); + /* XXX ZZZ */ + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, + "Finished: NFlat %d, NZeros: %d, NTrials %d, Guess %g to %g, aber %d\n", + NFlat, NZeros, NTrials, Low_Guess, High_Guess, Aberr_Num); +#endif + + if (NZeros >= Seq_Num - 1) { + /* Short */ + clear_trials(ISAROOT); + *rootinfo = NULL; + *rootcount = 0; + ERROR(E_SHORT, "The input signal is shorted on the way to the output"); + } else + clear_trials(0); + + *rootinfo = Trials; + *rootcount = NZeros; + + if (Aberr_Num > 2) { + sprintf(ebuf, + "Pole-zero converging to numerical aberrations; giving up after %d trials", + Seq_Num); + (*(SPfrontEnd->IFerror))(ERR_WARNING, ebuf, 0); + } + + if (NIter >= NITER_LIM) { + sprintf(ebuf, + "Pole-zero iteration limit reached; giving up after %d trials", + Seq_Num); + (*(SPfrontEnd->IFerror))(ERR_WARNING, ebuf, 0); + } + + return error; +} + +/* PZeval: evaluate an estimation function (given by 'strat') for the next + guess (returned in a PZtrial) */ + +/* XXX ZZZ */ +int +PZeval(int strat, PZtrial **set, PZtrial **new_trial_p) +{ + int error; + PZtrial *new_trial; + + new_trial = NEW(PZtrial); + new_trial->multiplicity = 0; + new_trial->count = 0; + new_trial->seq_num = Seq_Num++; + + switch (strat) { + case GUESS: + if (High_Guess < Low_Guess) + Guess_Param = 0.0; + else if (Guess_Param > 0.0) { + if (High_Guess > 0.0) + Guess_Param = High_Guess * 10.0; + else + Guess_Param = 1.0; + } else { + if (Low_Guess < 0.0) + Guess_Param = Low_Guess * 10.0; + else + Guess_Param = -1.0; + } + if (Guess_Param > High_Guess) + High_Guess = Guess_Param; + if (Guess_Param < Low_Guess) + Low_Guess = Guess_Param; + new_trial->s.real = Guess_Param; + if (set[1]) + new_trial->s.imag = set[1]->s.imag; + else + new_trial->s.imag = 0.0; + error = OK; + break; + + case SYM: + case SYM2: + error = NIpzSym(set, new_trial); + + if (CKTpzTrapped == 1) { + if (new_trial->s.real < set[0]->s.real + || new_trial->s.real > set[1]->s.real) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, + "FIXED UP BAD Strat: %s (%d) was (%.15g,%.15g)\n", + snames[strat], CKTpzTrapped, + new_trial->s.real, new_trial->s.imag); +#endif + new_trial->s.real = (set[0]->s.real + set[1]->s.real) / 2.0; + } + } else if (CKTpzTrapped == 2) { + if (new_trial->s.real < set[1]->s.real + || new_trial->s.real > set[2]->s.real) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, + "FIXED UP BAD Strat: %s (%d) was (%.15g,%.15g)\n", + snames[strat], CKTpzTrapped, + new_trial->s.real, new_trial->s.imag); +#endif + new_trial->s.real = (set[1]->s.real + set[2]->s.real) / 2.0; + } + } else if (CKTpzTrapped == 3) { + if ((new_trial->s.real <= set[0]->s.real + || new_trial->s.real == set[1]->s.real) + && (new_trial->s.imag == set[1]->s.imag + || new_trial->s.real >= set[2]->s.real)) { +#ifdef PZDEBUG + DEBUG(1) + fprintf(stderr, + "FIXED UP BAD Strat: %s (%d), was (%.15g %.15g)\n", + snames[strat], CKTpzTrapped, + new_trial->s.real, new_trial->s.imag); +#endif + new_trial->s.real = (set[0]->s.real + set[2]->s.real) / 2.0; + if (new_trial->s.real == set[1]->s.real) { +#ifdef PZDEBUG + DEBUG(1) + fprintf(stderr, "Still off!"); +#endif + if (Last_Move == MID_LEFT || Last_Move == NEAR_RIGHT) + new_trial->s.real = (set[0]->s.real + set[1]->s.real) + / 2.0; + else + new_trial->s.real = (set[1]->s.real + set[2]->s.real) + / 2.0; + } + } + } + + break; + + case COMPLEX_INIT: + /* Not automatic */ +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "\tPZ minima at: %-30g %d\n", + NIpzK, NIpzK_mag); +#endif + + new_trial->s.real = set[1]->s.real; + + /* NIpzK is a good idea, but the value gets trashed + * due to the numerics when zooming in on a minima. + * The key is to know when to stop taking new values for NIpzK + * (which I don't). For now I take the first value indicated + * by the NIpzSym2 routine. A "hack". + */ + + if (NIpzK != 0.0 && NIpzK_mag > -10) { + while (NIpzK_mag > 0) { + NIpzK *= 2.0; + NIpzK_mag -= 1; + } + while (NIpzK_mag < 0) { + NIpzK /= 2.0; + NIpzK_mag += 1; + } + new_trial->s.imag = NIpzK; + } else + new_trial->s.imag = 10000.0; + + /* + * Reset NIpzK so the same value doesn't get used again. + */ + + NIpzK = 0.0; + NIpzK_mag = 0; + error = OK; + break; + + case COMPLEX_GUESS: + if (!set[2]) { + new_trial->s.real = set[0]->s.real; + new_trial->s.imag = 1.0e8; + } else { + new_trial->s.real = set[0]->s.real; + new_trial->s.imag = 1.0e12; + } + error = OK; + break; + + case MULLER: + error = NIpzMuller(set, new_trial); + break; + + case SPLIT_LEFT: + new_trial->s.real = (set[0]->s.real + 2 * set[1]->s.real) / 3.0; + error = OK; + break; + + case SPLIT_RIGHT: + new_trial->s.real = (set[2]->s.real + 2 * set[1]->s.real) / 3.0; + error = OK; + break; + + default: + ERROR(E_PANIC, "Step type unkown"); + break; + } + + *new_trial_p = new_trial; + return error; +} + +/* CKTpzStrat: given three points, determine a good direction or method for + guessing the next zero */ + +/* XXX ZZZ what is a strategy for complex hunting? */ +int CKTpzStrat(PZtrial **set) +{ + int suggestion; + double a, b; + int a_mag, b_mag; + double k1, k2; + int new_trap; + + new_trap = 0; + + if (set[1] && (set[1]->flags & ISAMINIMA)) { + suggestion = COMPLEX_INIT; + } else if (set[0] && set[0]->s.imag != 0.0) { + if (!set[1] || !set[2]) + suggestion = COMPLEX_GUESS; + else + suggestion = MULLER; + } else if (!set[0] || !set[1] || !set[2]) { + suggestion = INIT; + } else { + if (sgn(set[0]->f_def.real) != sgn(set[1]->f_def.real)) { + /* Zero crossing between s[0] and s[1] */ + new_trap = 1; + suggestion = SYM2; + } else if (sgn(set[1]->f_def.real) != sgn(set[2]->f_def.real)) { + /* Zero crossing between s[1] and s[2] */ + new_trap = 2; + suggestion = SYM2; + } else { + + zaddeq(&a, &a_mag, set[1]->f_def.real, set[1]->mag_def, + -set[0]->f_def.real, set[0]->mag_def); + zaddeq(&b, &b_mag, set[2]->f_def.real, set[2]->mag_def, + -set[1]->f_def.real, set[1]->mag_def); + + if (!CKTpzTrapped) { + + k1 = set[1]->s.real - set[0]->s.real; + k2 = set[2]->s.real - set[1]->s.real; + if (a_mag + 10 < set[0]->mag_def + && a_mag + 10 < set[1]->mag_def + && b_mag + 10 < set[1]->mag_def + && b_mag + 10 < set[2]->mag_def) { + if (k1 > k2) + suggestion = SKIP_RIGHT; + else + suggestion = SKIP_LEFT; + } else if (sgn(a) != -sgn(b)) { + if (a == 0.0) + suggestion = SKIP_LEFT; + else if (b == 0.0) + suggestion = SKIP_RIGHT; + else if (sgn(a) == sgn(set[1]->f_def.real)) + suggestion = SHIFT_LEFT; + else + suggestion = SHIFT_RIGHT; + } else if (sgn(a) == -sgn(set[1]->f_def.real)) { + new_trap = 3; + /* minima in magnitude above the x axis */ + /* Search for exact mag. minima, look for complex pair */ + suggestion = SYM; + } else if (k1 > k2) + suggestion = SKIP_RIGHT; + else + suggestion = SKIP_LEFT; + } else { + new_trap = 3; /* still */ + /* XXX ? Are these tests needed or is SYM safe all the time? */ + if (sgn(a) != sgn(b)) { + /* minima in magnitude */ + /* Search for exact mag. minima, look for complex pair */ + suggestion = SYM; + } else if ((a_mag > b_mag || a_mag == b_mag) + && fabs(a) > fabs(b)) + suggestion = SPLIT_LEFT; + else + suggestion = SPLIT_RIGHT; + } + } + if (Consec_Moves >= 3 && CKTpzTrapped == new_trap) { + new_trap = CKTpzTrapped; + if (Last_Move == MID_LEFT || Last_Move == NEAR_RIGHT) + suggestion = SPLIT_LEFT; + else if (Last_Move == MID_RIGHT || Last_Move == NEAR_LEFT) + suggestion = SPLIT_RIGHT; + else + abort( ); /* XXX */ + Consec_Moves = 0; + } + } + + CKTpzTrapped = new_trap; +#ifdef PZDEBUG + DEBUG(1) { + if (set[0] && set[1] && set[2]) + fprintf(stderr, "given %.15g %.15g / %.15g %.15g / %.15g %.15g\n", + set[0]->s.real, set[0]->s.imag, set[1]->s.real, set[1]->s.imag, + set[2]->s.real, set[2]->s.imag); + fprintf(stderr, "suggestion(%d/%d/%d | %d): %s\n", + NFlat, NZeros, Max_Zeros, CKTpzTrapped, snames[suggestion]); + } +#endif + return suggestion; +} + +/* CKTpzRunTrial: eval the function at a given 's', fold in deflation */ + +int +CKTpzRunTrial(CKTcircuit *ckt, PZtrial **new_trialp, PZtrial **set) +{ + PZtrial *match, *base, *new_trial; + PZtrial *p, *prev; + SPcomplex def_frac, diff_frac; + double reltol, abstol; + int def_mag, diff_mag, error; + int i; + int pretest, shifted, was_shifted; + int repeat; + + new_trial = *new_trialp; + + if (new_trial->s.imag < 0.0) + new_trial->s.imag *= -1.0; + + /* Insert the trial into the list of Trials, while calculating + the deflation factor from previous zeros */ + + pretest = 0; + shifted = 0; + repeat = 0; + + do { + + def_mag = 0; + def_frac.real = 1.0; + def_frac.imag = 0.0; + was_shifted = shifted; + shifted = 0; + + prev = NULL; + base = NULL; + match = NULL; + + for (p = Trials; p != NULL; p = p->next) { + + C_SUBEQ(diff_frac,p->s,new_trial->s); + + if ((diff_frac.real < 0.0 + || diff_frac.real == 0.0) && diff_frac.imag < 0.0) { + prev = p; + if (p->flags & ISAMINIMA) + base = p; + } + + if (p->flags & ISAROOT) { + abstol = 1e-5; + reltol = 1e-6; + } else { + abstol = 1e-20; + reltol = 1e-12; + } + + if (diff_frac.imag == 0.0 && + fabs(diff_frac.real) / (fabs(p->s.real) + abstol/reltol) + < reltol) { + +#ifdef PZDEBUG + DEBUG(1) { + fprintf(stderr, + "diff_frac.real = %10g, p->s = %10g, nt = %10g\n", + diff_frac.real, p->s.real, new_trial->s.real); + fprintf(stderr, "ab=%g,rel=%g\n", abstol, reltol); + } +#endif + if (was_shifted || p->count >= 3 + || !alter(new_trial, set[1], abstol, reltol)) { + /* assume either a root or minima */ + p->count = 0; + pretest = 1; + break; + } else + p->count += 1; /* try to shift */ + + shifted = 1; /* Re-calculate deflation */ + break; + + } else { + if (!CKTpzTrapped) + p->count = 0; + if (p->flags & ISAROOT) { + diff_mag = 0; + C_NORM(diff_frac,diff_mag); + if (diff_frac.imag != 0.0) { + C_MAG2(diff_frac); + diff_mag *= 2; + } + C_NORM(diff_frac,diff_mag); + + for (i = p->multiplicity; i > 0; i--) { + C_MUL(def_frac,diff_frac); + def_mag += diff_mag; + C_NORM(def_frac,def_mag); + } + } else if (!match) + match = p; + } + } + + } while (shifted); + + if (pretest) { + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "Pre-test taken\n"); + + /* XXX Should catch the double-zero right off + * if K is 0.0 + * instead of forcing a re-converge */ + DEBUG(1) { + fprintf(stderr, "NIpzK == %g, mag = %d\n", NIpzK, NIpzK_mag); + fprintf(stderr, "over at %.30g %.30g (new %.30g %.30g, %x)\n", + p->s.real, p->s.imag, new_trial->s.real, new_trial->s.imag, + p->flags); + } +#endif + if (!(p->flags & ISAROOT) && CKTpzTrapped == 3 + && NIpzK != 0.0 && NIpzK_mag > -10) { +#ifdef notdef + if (p->flags & ISAROOT) { + /* Ugh! muller doesn't work right */ + new_trial->flags = ISAMINIMA; + new_trial->s.imag = scalb(NIpzK, (int) (NIpzK_mag / 2)); + pretest = 0; + } else { +#endif + p->flags |= ISAMINIMA; + free(new_trial); + *new_trialp = p; + repeat = 1; + } else if (p->flags & ISAROOT) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "Repeat at %.30g %.30g\n", + p->s.real, p->s.imag); +#endif + *new_trialp = p; + p->flags |= ISAREPEAT; + p->multiplicity += 1; + repeat = 1; + } else { + /* Regular zero, as precise as we can get it */ + error = E_SINGULAR; + } + + } + + if (!repeat) { + if (!pretest) { + /* Run the trial */ + ckt->CKTniState |= NIPZSHOULDREORDER; /* XXX */ + if (!(ckt->CKTniState & NIPZSHOULDREORDER)) { + CKTpzLoad(ckt, &new_trial->s); +#ifdef PZDEBUG + DEBUG(3) { + printf("Original:\n"); + SMPprint(ckt->CKTmatrix, stdout); + } +#endif + error = SMPcLUfac(ckt->CKTmatrix, ckt->CKTpivotAbsTol); + if (error == E_SINGULAR) { +#ifdef PZDEBUG + DEBUG(1) printf("Needs reordering\n"); +#endif + ckt->CKTniState |= NIPZSHOULDREORDER; + } else if (error != OK) + return error; + } + if (ckt->CKTniState & NIPZSHOULDREORDER) { + CKTpzLoad(ckt, &new_trial->s); + error = SMPcReorder(ckt->CKTmatrix, 1.0e-30, + 0.0 /* 0.1 Piv. Rel. */, + &(((PZAN *) ckt->CKTcurJob)->PZnumswaps)); + } + + if (error != E_SINGULAR) { + ckt->CKTniState &= ~NIPZSHOULDREORDER; +#ifdef PZDEBUG + DEBUG(3) { + printf("Factored:\n"); + SMPprint(ckt->CKTmatrix, stdout); + } +#endif + error = SMPcDProd(ckt->CKTmatrix, &new_trial->f_raw, + &new_trial->mag_raw); + } + } + + if ((error == E_SINGULAR || new_trial->f_raw.real == 0.0) + && new_trial->f_raw.imag == 0.0) { + new_trial->f_raw.real = 0.0; + new_trial->f_raw.imag = 0.0; + new_trial->mag_raw = 0; + new_trial->f_def.real = 0.0; + new_trial->f_def.imag = 0.0; + new_trial->mag_def = 0; + new_trial->flags = ISAROOT; + /*printf("SMP Det: Singular\n");*/ + } else if (error != OK) + return error; + else { + + /* PZnumswaps is either 0 or 1 */ + new_trial->f_raw.real *= ((PZAN *) ckt->CKTcurJob)->PZnumswaps; + new_trial->f_raw.imag *= ((PZAN *) ckt->CKTcurJob)->PZnumswaps; + /* + printf("SMP Det: (%g,%g)^%d\n", new_trial->f_raw.real, + new_trial->f_raw.imag, new_trial->mag_raw); + */ + + new_trial->f_def.real = new_trial->f_raw.real; + new_trial->f_def.imag = new_trial->f_raw.imag; + new_trial->mag_def = new_trial->mag_raw; + + C_DIV(new_trial->f_def,def_frac); + new_trial->mag_def -= def_mag; + C_NORM(new_trial->f_def,new_trial->mag_def); + } + + /* Link into the rest of the list */ + if (prev) { + new_trial->next = prev->next; + if (prev->next) + prev->next->prev = new_trial; + prev->next = new_trial; + } else { + if (Trials) + Trials->prev = new_trial; + else + ZeroTrial = new_trial; + new_trial->next = Trials; + Trials = new_trial; + } + new_trial->prev = prev; + + NTrials += 1; + + if (!(new_trial->flags & ISAROOT)) { + if (match) + check_flat(match, new_trial); + else + NFlat = 1; + } + } + +#ifdef PZDEBUG + show_trial(new_trial, '*'); +#endif + + return OK; +} + +/* Process a zero; inc. zero count, deflate other trials */ + +int +CKTpzVerify(PZtrial **set, PZtrial *new_trial) +{ + PZtrial *next; + int diff_mag; + SPcomplex diff_frac; + double tdiff; + + PZtrial *t, *prev; + + NZeros += 1; + if (new_trial->s.imag != 0.0) + NZeros += 1; + NFlat = 0; + + if (new_trial->multiplicity == 0) { + new_trial->flags |= ISAROOT; + new_trial->multiplicity = 1; + } + + prev = NULL; + + for (t = Trials; t; t = next) { + + next = t->next; + + if (t->flags & ISAROOT) { + prev = t; + /* Don't need to bother */ + continue; + } + + C_SUBEQ(diff_frac,new_trial->s,t->s); + if (new_trial->s.imag != 0.0) + C_MAG2(diff_frac); + + tdiff = diff_frac.real; + /* Note that Verify is called for each time the root is found, so + * multiplicity is not significant + */ + if (diff_frac.real != 0.0) { + diff_mag = 0; + C_NORM(diff_frac,diff_mag); + diff_mag *= -1; + C_DIV(t->f_def,diff_frac); + C_NORM(t->f_def,diff_mag); + t->mag_def += diff_mag; + } + + if (t->s.imag != 0.0 + || fabs(tdiff) / (fabs(new_trial->s.real) + 200) < 0.005) { + if (prev) + prev->next = t->next; + if (t->next) + t->next->prev = prev; + NTrials -= 1; +#ifdef PZDEBUG + show_trial(t, '-'); +#endif + if (t == ZeroTrial) { + if (t->next) + ZeroTrial = t->next; + else if (t->prev) + ZeroTrial = t->prev; + else + ZeroTrial = NULL; + } + if (t == Trials) { + Trials = t->next; + } + free(t); + } else { + + if (prev) + check_flat(prev, t); + else + NFlat = 1; + + if (t->flags & ISAMINIMA) + t->flags &= ~ISAMINIMA; + + prev = t; +#ifdef PZDEBUG + show_trial(t, '+'); +#endif + } + + } + + return 1; /* always ok */ +} + +/* pzseek: search the trial list (given a starting point) for the first + * non-zero entry; direction: -1 for prev, 1 for next, 0 for next + * -or- first. Also, sets "Guess_Param" at the next reasonable + * value to guess at if the search falls of the end of the list + */ + +static PZtrial * +pzseek(PZtrial *t, int dir) +{ + Guess_Param = dir; + if (t == NULL) + return NULL; + + if (dir == 0 && !(t->flags & ISAROOT) && !(t->flags & ISAMINIMA)) + return t; + + do { + if (dir >= 0) + t = t->next; + else + t = t->prev; + } while (t && ((t->flags & ISAROOT) || (t->flags & ISAMINIMA))); + + return t; +} + +static void +clear_trials(int mode) +{ + PZtrial *t, *next, *prev; + + prev = NULL; + + for (t = Trials; t; t = next) { + next = t->next; + if (mode || !(t->flags & ISAROOT)) { + free(t); + } else { + if (prev) + prev->next = t; + else + Trials = t; + t->prev = prev; + prev = t; + } + } + + if (prev) + prev->next = NULL; + else + Trials = NULL; +} + +void +CKTpzUpdateSet(PZtrial **set, PZtrial *new) +{ + int this_move; + + this_move = 0; + + if (new->s.imag != 0.0) { + set[2] = set[1]; + set[1] = set[0]; + set[0] = new; + } else if (!set[1]) + set[1] = new; + else if (!set[2] && new->s.real > set[1]->s.real) { + set[2] = new; + } else if (!set[0]) { + set[0] = new; + } else if (new->flags & ISAMINIMA) { + set[1] = new; + } else if (new->s.real < set[0]->s.real) { + set[2] = set[1]; + set[1] = set[0]; + set[0] = new; + this_move = FAR_LEFT; + } else if (new->s.real < set[1]->s.real) { + if ((!CKTpzTrapped || new->mag_def < set[1]->mag_def + || new->mag_def == set[1]->mag_def) + && fabs(new->f_def.real) < fabs(set[1]->f_def.real)) { + /* Really should check signs, not just compare fabs( ) */ + set[2] = set[1]; /* XXX = set[2]->prev :: possible opt */ + set[1] = new; + this_move = MID_LEFT; + } else { + set[0] = new; + this_move = NEAR_LEFT; + } + } else if (new->s.real < set[2]->s.real) { + if ((!CKTpzTrapped || new->mag_def < set[1]->mag_def + || new->mag_def == set[1]->mag_def) + && fabs(new->f_def.real) < fabs(set[1]->f_def.real)) { + /* Really should check signs, not just compare fabs( ) */ + set[0] = set[1]; + set[1] = new; + this_move = MID_RIGHT; + } else { + set[2] = new; + this_move = NEAR_RIGHT; + } + } else { + set[0] = set[1]; + set[1] = set[2]; + set[2] = new; + this_move = FAR_RIGHT; + } + + if (CKTpzTrapped && this_move == Last_Move) + Consec_Moves += 1; + else + Consec_Moves = 0; + Last_Move = this_move; +} + +void +zaddeq(double *a, int *amag, double x, int xmag, double y, int ymag) +{ + /* Balance magnitudes . . . */ + if (xmag > ymag) { + *amag = xmag; + if (xmag > 50 + ymag) + y = 0.0; + else + for (xmag -= ymag; xmag > 0; xmag--) + y /= 2.0; + } else { + *amag = ymag; + if (ymag > 50 + xmag) + x = 0.0; + else + for (ymag -= xmag; ymag > 0; ymag--) + x /= 2.0; + } + + *a = x + y; + if (*a == 0.0) + *amag = 0; + else { + while (fabs(*a) > 1.0) { + *a /= 2.0; + *amag += 1; + } + while (fabs(*a) < 0.5) { + *a *= 2.0; + *amag -= 1; + } + } +} + +#ifdef PZDEBUG +static void +show_trial(new_trial, x) + PZtrial *new_trial; + char x; +{ + DEBUG(1) fprintf(stderr, "%c (%3d/%3d) %.15g %.15g :: %.30g %.30g %d\n", x, + NIter, new_trial->seq_num, new_trial->s.real, new_trial->s.imag, + new_trial->f_def.real, new_trial->f_def.imag, new_trial->mag_def); + DEBUG(1) + if (new_trial->flags & ISANABERRATION) { + fprintf(stderr, "*** numerical aberration ***\n"); + } +} +#endif + +static void +check_flat(PZtrial *a, PZtrial *b) +{ + int diff_mag; + SPcomplex diff_frac; + double mult; + + diff_mag = a->mag_def - b->mag_def; + if (abs(diff_mag) <= 1) { + if (diff_mag == 1) + mult = 2.0; + else if (diff_mag == -1) + mult = 0.5; + else + mult = 1.0; + C_SUBEQ(diff_frac, mult * a->f_def, b->f_def); + C_MAG2(diff_frac); + if (diff_frac.real < 1.0e-20) + NFlat += 1; + } + /* XXX else NFlat = ?????? */ +} + +/* XXX ZZZ */ +int +CKTpzStep(int strat, PZtrial **set) +{ + switch (strat) { + case INIT: + if (!set[1]) { + set[1] = pzseek(ZeroTrial, 0); + } else if (!set[2]) + set[2] = pzseek(set[1], 1); + else if (!set[0]) + set[0] = pzseek(set[1], -1); + break; + + case SKIP_LEFT: + set[0] = pzseek(set[0], -1); + break; + + case SKIP_RIGHT: + set[2] = pzseek(set[2], 1); + break; + + case SHIFT_LEFT: + set[2] = set[1]; + set[1] = set[0]; + set[0] = pzseek(set[0], -1); + break; + + case SHIFT_RIGHT: + set[0] = set[1]; + set[1] = set[2]; + set[2] = pzseek(set[2], 1); + break; + + } + if (!set[0] || !set[1] || !set[2]) + return 0; + else + return 1; +} + +void +CKTpzReset(PZtrial **set) +{ + CKTpzTrapped = 0; + Consec_Moves = 0; + + set[1] = pzseek(ZeroTrial, 0); + if (set[1] != NULL) { + set[0] = pzseek(set[1], -1); + set[2] = pzseek(set[1], 1); + } else { + set[0] = NULL; + set[2] = NULL; + } +} + +static int +alter(PZtrial *new, PZtrial *nearto, double abstol, double reltol) +{ + double p1, p2; + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "ALTER from: %.30g %.30g\n", + new->s.real, new->s.imag); + DEBUG(1) fprintf(stderr, "nt->next %g\n", nearto->prev->s.real); + DEBUG(1) fprintf(stderr, "nt->next %g\n", nearto->next->s.real); +#endif + + if (CKTpzTrapped != 2) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "not 2\n"); +#endif + p1 = nearto->s.real; + if (nearto->flags & ISAROOT) + p1 -= 1e-6 * nearto->s.real + 1e-5; + if (nearto->prev) { + p1 += nearto->prev->s.real; +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "p1 %g\n", p1); +#endif + } else + p1 -= 10.0 * (fabs(p1) + 1.0); + + p1 /= 2.0; + } else + p1 = nearto->s.real; + + if (CKTpzTrapped != 1) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "not 1\n"); +#endif + p2 = nearto->s.real; + if (nearto->flags & ISAROOT) + p2 += 1e-6 * nearto->s.real + 1e-5; /* XXX Would rather use pow(2)*/ + if (nearto->next) { + p2 += nearto->next->s.real; +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "p2 %g\n", p2); +#endif + } else + p2 += 10.0 * (fabs(p2)+ 1.0); + + p2 /= 2.0; + } else + p2 = nearto->s.real; + + if ((nearto->prev && + fabs(p1 - nearto->prev->s.real) / + fabs(nearto->prev->s.real) + abstol/reltol < reltol) + || + (nearto->next && + fabs(p2 - nearto->next->s.real) / + fabs(nearto->next->s.real) + abstol/reltol < reltol)) { + +#ifdef PZDEBUG + DEBUG(1) + fprintf(stderr, "Bailed out\n"); +#endif + + return 0; + } + + if (CKTpzTrapped != 2 && nearto->s.real - p1 > p2 - nearto->s.real) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "take p1\n"); +#endif + new->s.real = p1; + } else { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "take p2\n"); +#endif + new->s.real = p2; + } + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "ALTER to : %.30g %.30g\n", + new->s.real, new->s.imag); +#endif + return 1; + +} diff --git a/src/analysis/cktsens.c b/src/analysis/cktsens.c new file mode 100644 index 000000000..7ebc8e824 --- /dev/null +++ b/src/analysis/cktsens.c @@ -0,0 +1,788 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include "ifsim.h" +#include "sperror.h" +#include "spmatrix.h" +#include "gendefs.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "sensdefs.h" +#include "sensgen.h" + +/* #define ASDEBUG */ +#ifdef ASDEBUG +#define DEBUG(X) if ((X) < Sens_Debug) +int Sens_Debug = 0; +char SF1[] = "res"; +char SF2[] = "dc"; +char SF3[] = "bf"; +#endif + +char *Sfilter = NULL; +double Sens_Delta = 0.000001; +double Sens_Abs_Delta = 0.000001; + +static int sens_setp(sgen *sg, CKTcircuit *ckt, IFvalue *val); +static int sens_load(sgen *sg, CKTcircuit *ckt, int is_dc); +static int sens_temp(sgen *sg, CKTcircuit *ckt); +static int count_steps(int type, double low, double high, int steps, double *stepsize); +static double inc_freq(double freq, int type, double step_size); + +extern SPICEdev *DEVices[]; + +/* + * Procedure: + * + * Determine operating point (call CKTop) + * + * For each frequency point: + * (for AC) call NIacIter to get base node voltages + * For each element/parameter in the test list: + * construct the perturbation matrix + * Solve for the sensitivities: + * delta_E = Y^-1 (delta_Y E - delta_I) + * save results + */ + +static int error; +int sens_sens(CKTcircuit *ckt, int restart) +{ + SENS_AN *sen_info = ((SENS_AN *) ckt->CKTcurJob); + static int size; + static double *delta_I, *delta_iI, + *delta_I_delta_Y, *delta_iI_delta_Y; + sgen *sg; + static double freq; + static int nfreqs; + static int i; + static SMPmatrix *delta_Y = NULL, *Y; + static double step_size; + double *E, *iE; + IFvalue value, nvalue; + double *output_values; + IFcomplex *output_cvalues; + double delta_var; + int (*fn)( ); + static int is_dc; + int k, j, n; + int num_vars, branch_eq; + char *sen_data; + char namebuf[513]; + IFuid *output_names, freq_name; + int bypass; + int type; + +#ifndef notdef +#ifdef notdef + for (sg = sgen_init(ckt, 0); sg; sgen_next(&sg)) { + if (sg->is_instparam) + printf("%s:%s:%s -> param %s\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword); + else + printf("%s:%s:%s -> mparam %s\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword); + } +#endif +#ifdef ASDEBUG + DEBUG(1) + printf(">>> restart : %d\n", restart); +#endif + + /* get to work */ + + restart = 1; + if (restart) { + + freq = 0.0; + is_dc = (sen_info->step_type == SENS_DC); + nfreqs = count_steps(sen_info->step_type, sen_info->start_freq, + sen_info->stop_freq, sen_info->n_freq_steps, + &step_size); + + if (!is_dc) + freq = sen_info->start_freq; + + error = CKTop(ckt, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, + ckt->CKTdcMaxIter); + +#ifdef notdef + ckt->CKTmode = (ckt->CKTmode & MODEUIC) + | MODEDCOP | MODEINITSMSIG; +#endif + if (error) + return error; + + size = spGetSize(ckt->CKTmatrix, 1); + + /* Create the perturbation matrix */ + /* XXX check error return, '1' is complex -- necessary? + * only in ac */ + delta_Y = spCreate(size, !is_dc, &error); + + size += 1; + + /* Create an extra rhs */ + delta_I = NEWN(double, size); + delta_iI = NEWN(double, size); + + delta_I_delta_Y = NEWN(double, size); + delta_iI_delta_Y = NEWN(double, size); + + + num_vars = 0; + for (sg = sgen_init(ckt, is_dc); sg; sgen_next(&sg)) { + num_vars += 1; + } + + if (!num_vars) + return OK; /* XXXX Should be E_ something */ + + k = 0; + output_names = NEWN(IFuid, num_vars); + for (sg = sgen_init(ckt, is_dc); sg; sgen_next(&sg)) { + if (!sg->is_instparam) { + sprintf(namebuf, "%s:%s", + sg->instance->GENname, + sg->ptable[sg->param].keyword); + } else if ((sg->ptable[sg->param].dataType + & IF_PRINCIPAL) && sg->is_principle == 1) + { + sprintf(namebuf, "%s", sg->instance->GENname); + } else { + sprintf(namebuf, "%s_%s", + sg->instance->GENname, + sg->ptable[sg->param].keyword); + } + + (*SPfrontEnd->IFnewUid)((void *) ckt, + output_names + k, NULL, + namebuf, UID_OTHER, NULL); + k += 1; + } + + if (is_dc) { + type = IF_REAL; + freq_name = NULL; + } else { + type = IF_COMPLEX; + (*SPfrontEnd->IFnewUid)((void *) ckt, + &freq_name, NULL, + "frequency", UID_OTHER, NULL); + } + + error = (*SPfrontEnd->OUTpBeginPlot)((void *) ckt, + (void *) ckt->CKTcurJob, + ckt->CKTcurJob->JOBname, freq_name, IF_REAL, num_vars, + output_names, type, (void **) &sen_data); + if (error) + return error; + + FREE(output_names); + if (is_dc) { + output_values = NEWN(double, num_vars); + output_cvalues = NULL; + } else { + output_values = NULL; + output_cvalues = NEWN(IFcomplex, num_vars); + if (sen_info->step_type != SENS_LINEAR) + (*(SPfrontEnd->OUTattributes))((void *)sen_data, + NULL, OUT_SCALE_LOG, NULL); + + } + + } else { + /*XXX Restore saved state */ + } + +#ifdef ASDEBUG + DEBUG(1) + printf("start: %f, num: %d, dc: %d\n", freq, nfreqs, is_dc); +#endif + + if (!sen_info->output_volt) + branch_eq = CKTfndBranch(ckt, sen_info->output_src); + bypass = ckt->CKTbypass; + ckt->CKTbypass = 0; + + /* The unknown vector of node voltages overwrites rhs */ + E = ckt->CKTrhs; + iE = ckt->CKTirhs; + ckt->CKTrhsOld = E; + ckt->CKTirhsOld = iE; + Y = ckt->CKTmatrix; +#ifdef ASDEBUG + DEBUG(1) { + printf("Operating point:\n"); + for (i = 0; i < size; i++) + printf(" E [%d] = %20.15g\n", i, E[i]); + } +#endif + +#ifdef notdef + for (j = 0; j <= ckt->CKTmaxOrder + 1; j++) { + save_states[j] = ckt->CKTstates[j]; + ckt->CKTstates[j] = NULL; + } +#endif + + for (i = 0; i < nfreqs; i++) { + /* XXX handle restart */ + + n = 0; + + if ((*SPfrontEnd->IFpauseTest)( )) { + /* XXX Save State */ + return E_PAUSE; + } + + for (j = 0; j < size; j++) { + delta_I[j] = 0.0; + delta_iI[j] = 0.0; + } + + if (freq != 0.0) { + ckt->CKTrhs = E; + ckt->CKTirhs = iE; + ckt->CKTmatrix = Y; + + /* This generates Y in LU form */ + ckt->CKTomega = 2.0 * M_PI * freq; + + /* Yes, all this has to be re-done */ + /* XXX Free old states */ + error = CKTunsetup(ckt); + if (error) + return error; + + /* XXX ckt->CKTmatrix = Y; */ + + error = CKTsetup(ckt); + if (error) + return error; + + E = ckt->CKTrhs; + iE = ckt->CKTirhs; + Y = ckt->CKTmatrix; +#ifdef notdef + for (j = 0; j <= ckt->CKTmaxOrder + 1; j++) { + /* XXX Free new states */ + ckt->CKTstates[j] = save_states[j]; + } +#endif + error = CKTtemp(ckt); + if (error) + return error; + error = CKTload(ckt); /* INITSMSIGS */ + if (error) + return error; + error = NIacIter(ckt); + if (error) + return error; + +#ifdef notdef + /* XXX Why? */ + for (j = 0; j <= ckt->CKTmaxOrder + 1; j++) { + ckt->CKTstates[j] = NULL; + } +#endif + + } + + /* Use a different vector & matrix */ + ckt->CKTrhs = delta_I; + ckt->CKTirhs = delta_iI; + ckt->CKTmatrix = delta_Y; + + /* calc. effect of each param */ + for (sg = sgen_init(ckt, is_dc /* sen_info->plist */); + sg; sgen_next(&sg)) + { + +#ifdef ASDEBUG + DEBUG(2) { + printf("E/iE: %x/%x; delta_I/iI: %x/%x\n", + E, iE, delta_I, delta_iI); + printf("cktrhs/irhs: %x/%x\n", + ckt->CKTrhs, ckt->CKTirhs); + + if (sg->is_instparam) + printf("%s:%s:%s -> param %s\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword); + else + printf("%s:%s:%s -> mparam %s\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword); + } +#endif + + spClear(delta_Y); + + for (j = 0; j < size; j++) { + delta_I[j] = 0.0; + delta_iI[j] = 0.0; + } + + /* ? should this just call CKTsetup + * ? but then CKThead would have to get fiddled with */ + + ckt->CKTnumStates = sg->istate; + + fn = DEVices[sg->dev]->DEVsetup; + if (fn) + (*fn)(delta_Y, sg->model, ckt, + /* XXXX insert old state base here ?? */ + &ckt->CKTnumStates); + + /* ? CKTsetup would call NIreinit instead */ + ckt->CKTniState = NISHOULDREORDER | NIACSHOULDREORDER; + + /* XXX instead of calling temp here, just swap + * back to the original states */ + (void) sens_temp(sg, ckt); + + /* XXX Leave original E until here!! so that temp reads + * the right node voltages */ + + if (sens_load(sg, ckt, is_dc)) { + if (error && error != E_BADPARM) + return error; /* XXX */ + continue; + } + + /* Alter the parameter */ + +#ifdef ASDEBUG + DEBUG(1) printf("Original value: %g\n", sg->value); +#endif + +#ifdef ASDEBUG + DEBUG(2) { + printf("Effect of device:\n"); + spPrint(delta_Y, 0, 1, 1); + printf("LHS:\n"); + for (j = 0; j < size; j++) + printf("%d: %g, %g\n", j, + delta_I[j], delta_iI[j]); + } +#endif + + if (sg->value != 0.0) + delta_var = sg->value * Sens_Delta; + else + delta_var = Sens_Abs_Delta; + + nvalue.rValue = sg->value + delta_var; + +#ifdef ASDEBUG + DEBUG(1) + printf("New value: %g\n", nvalue.rValue); +#endif + + sens_setp(sg, ckt, &nvalue); + if (error && error != E_BADPARM) + return error; + + spConstMult(delta_Y, -1.0); + for (j = 0; j < size; j++) { + delta_I[j] *= -1.0; + delta_iI[j] *= -1.0; + } + +#ifdef ASDEBUG + DEBUG(2) { + printf("Effect of negating matrix:\n"); + spPrint(delta_Y, 0, 1, 1); + for (j = 0; j < size; j++) + printf("%d: %g, %g\n", j, + delta_I[j], delta_iI[j]); + } +#endif + + /* XXX swap back to temp states ?? Naw ... */ + (void) sens_temp(sg, ckt); + +#ifdef ASDEBUG + DEBUG(1) { + if (sens_getp(sg, ckt, &value)) { + continue; + } + + printf("New value in device: %g\n", + value.rValue); + } +#endif + + sens_load(sg, ckt, is_dc); + +#ifdef ASDEBUG + DEBUG(2) { + printf("Effect of changing the parameter:\n"); + spPrint(delta_Y, 0, 1, 1); + for (j = 0; j < size; j++) + printf("%d: %g, %g\n", j, + delta_I[j], delta_iI[j]); + } +#endif + /* Set the perturbed variable back to it's + * original value + */ + + value.rValue = sg->value; + sens_setp(sg, ckt, &value); + (void) sens_temp(sg, ckt); /* XXX is this necessary? */ + + /* Back to business . . . */ + +#ifdef ASDEBUG + DEBUG(2) + for (j = 0; j < size; j++) + printf(" E [%d] = %20.15g\n", + j, E[j]); +#endif + + /* delta_Y E */ + spMultiply(delta_Y, delta_I_delta_Y, E, + delta_iI_delta_Y, iE); + +#ifdef ASDEBUG + DEBUG(2) + for (j = 0; j < size; j++) + printf("delta_Y * E [%d] = %20.15g\n", + j, delta_I_delta_Y[j]); +#endif + + /* delta_I - delta_Y E */ + for (j = 0; j < size; j++) { + delta_I[j] -= delta_I_delta_Y[j]; + delta_iI[j] -= delta_iI_delta_Y[j]; + } + +#ifdef ASDEBUG + DEBUG(2) { + printf(">>> Y:\n"); + spPrint(Y, 0, 1, 1); + for (j = 0; j < size; j++) + printf("%d: %g, %g\n", j, + delta_I[j], delta_iI[j]); + } +#endif + /* Solve; Y already factored */ + spSolve(Y, delta_I, delta_I, delta_iI, delta_iI); + +#ifdef ASDEBUG + DEBUG(2) { + for (j = 1; j < size; j++) { + + if (sg->is_instparam) + printf("%d/%s.%s = %g, %g\n", + j, + sg->instance->GENname, + sg->ptable[sg->param].keyword, + delta_I[j], delta_iI[j]); + else + printf("%d/%s:%s = %g, %g\n", + j, + sg->instance->GENname, + sg->ptable[sg->param].keyword, + delta_I[j], delta_iI[j]); + + } + } +#endif + + /* delta_I is now equal to delta_E */ + + if (is_dc) { + if (sen_info->output_volt) + output_values[n] = delta_I + [sen_info->output_pos->number] + - delta_I + [sen_info->output_neg->number]; + else { + output_values[n] = delta_I[branch_eq]; + } + output_values[n] /= delta_var; + } else { + if (sen_info->output_volt) { + output_cvalues[n].real = delta_I + [sen_info->output_pos->number] + - delta_I + [sen_info->output_neg->number]; + output_cvalues[n].imag = delta_iI + [sen_info->output_pos->number] + - delta_iI + [sen_info->output_neg->number]; + } else { + output_cvalues[n].real = + delta_I[branch_eq]; + output_cvalues[n].imag = + delta_iI[branch_eq]; + } + output_cvalues[n].real /= delta_var; + output_cvalues[n].imag /= delta_var; + } + + n += 1; + + } + + if (is_dc) + nvalue.v.vec.rVec = output_values; + else + nvalue.v.vec.cVec = output_cvalues; + + value.rValue = freq; + OUTpData(sen_data, &value, &nvalue); + freq = inc_freq(freq, sen_info->step_type, step_size); + + } + + (*SPfrontEnd->OUTendPlot)((void *) sen_data); + + if (is_dc) { + FREE(output_values); /* XXX free various vectors */ + } else { + FREE(output_cvalues); /* XXX free various vectors */ + } + + spDestroy(delta_Y); + FREE(delta_I); + FREE(delta_iI); + + ckt->CKTrhs = E; + ckt->CKTirhs = iE; + ckt->CKTmatrix = Y; + ckt->CKTbypass = bypass; + +#ifdef notdef + for (j = 0; j <= ckt->CKTmaxOrder + 1; j++) { + if (ckt->CKTstates[j]) + FREE(ckt->CKTstates[j]); + ckt->CKTstates[j] = save_states[j]; + } +#endif +#endif + + return OK; +} + +double +inc_freq(double freq, int type, double step_size) +{ + if (type != LINEAR) + freq *= step_size; + else + freq += step_size; + + return freq; +} + +double +next_freq(int type, double freq, double stepsize) +{ + double s; + + switch (type) { + case SENS_DC: + s = 0; + break; + + case SENS_LINEAR: + s = freq + stepsize; + break; + + case SENS_DECADE: + case SENS_OCTAVE: + s = freq * stepsize; + break; + } + return s; +} + +int +count_steps(int type, double low, double high, int steps, double *stepsize) +{ + double s; + int n; + + if (steps < 1) + steps = 1; + + switch (type) { + default: + case SENS_DC: + n = 0; + s = 0; + break; + + case SENS_LINEAR: + n = steps; + s = (high - low) / steps; + break; + + case SENS_DECADE: + if (low <= 0.0) + low = 1e-3; + if (high <= low) + high = 10.0 * low; + n = steps * log10(high/low) + 1.01; + s = pow(10.0, 1.0 / steps); + break; + + case SENS_OCTAVE: + if (low <= 0.0) + low = 1e-3; + if (high <= low) + high = 2.0 * low; + n = steps * log(high/low) / M_LOG2E + 1.01; + s = pow(2.0, 1.0 / steps); + break; + } + + if (n <= 0) + n = 1; + + *stepsize = s; + return n; +} + +static int +sens_load(sgen *sg, CKTcircuit *ckt, int is_dc) +{ + int (*fn)( ); + + error = 0; + + if (!is_dc) + fn = DEVices[sg->dev]->DEVacLoad; + else + fn = DEVices[sg->dev]->DEVload; + + if (fn) + error = (*fn)(sg->model, ckt); + else + return 1; + + return error; +} + + +static int +sens_temp(sgen *sg, CKTcircuit *ckt) +{ + int (*fn)( ); + + error = 0; + + fn = DEVices[sg->dev]->DEVtemperature; + + if (fn) + error = (*fn)(sg->model, ckt); + else + return 1; + + return error; +} + +/* Get parameter value */ +int +sens_getp(sgen *sg, CKTcircuit *ckt, IFvalue *val) +{ + int (*fn)( ); + int pid; + + error = 0; + + if (sg->is_instparam) { + fn = DEVices[sg->dev]->DEVask; + pid = DEVices[sg->dev]->DEVpublic.instanceParms[sg->param].id; + if (fn) + error = (*fn)(ckt, sg->instance, pid, val, NULL); + else + return 1; + } else { + fn = DEVices[sg->dev]->DEVmodAsk; + pid = DEVices[sg->dev]->DEVpublic.modelParms[sg->param].id; + if (fn) + error = (*fn)(ckt, sg->model, pid, val, NULL); + else + return 1; + } + + if (error) { + if (sg->is_instparam) + printf("GET ERROR: %s:%s:%s -> param %s (%d)\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword, pid); + else + printf("GET ERROR: %s:%s:%s -> mparam %s (%d)\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword, pid); + } + + return error; +} + +/* Get parameter value */ +int +sens_setp(sgen *sg, CKTcircuit *ckt, IFvalue *val) +{ + int (*fn)( ); + int pid; + + error = 0; + + if (sg->is_instparam) { + fn = DEVices[sg->dev]->DEVparam; + pid = DEVices[sg->dev]->DEVpublic.instanceParms[sg->param].id; + if (fn) + error = (*fn)(pid, val, sg->instance, NULL); + else + return 1; + } else { + fn = DEVices[sg->dev]->DEVmodParam; + pid = DEVices[sg->dev]->DEVpublic.modelParms[sg->param].id; + if (fn) + error = (*fn)(pid, val, sg->model); + else + return 1; + } + + if (error) { + if (sg->is_instparam) + printf("SET ERROR: %s:%s:%s -> param %s (%d)\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword, pid); + else + printf("SET ERROR: %s:%s:%s -> mparam %s (%d)\n", + DEVices[sg->dev]->DEVpublic.name, + sg->model->GENmodName, + sg->instance->GENname, + sg->ptable[sg->param].keyword, pid); + } + + return error; +} diff --git a/src/analysis/cktsetap.c b/src/analysis/cktsetap.c new file mode 100644 index 000000000..657b670b1 --- /dev/null +++ b/src/analysis/cktsetap.c @@ -0,0 +1,24 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "tskdefs.h" +#include "jobdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" + + +extern SPICEanalysis *analInfo[]; + +/* ARGSUSED */ +int +CKTsetAnalPm(void *ckt, void *analPtr, int parm, IFvalue *value, IFvalue *selector) +{ + register int type = ((JOB *)analPtr)->JOBtype; + if((analInfo[type]->setParm)==NULL) return(E_BADPARM); + return( (*(analInfo[type]->setParm))(ckt,analPtr,parm,value) ); +} diff --git a/src/analysis/cktsetbk.c b/src/analysis/cktsetbk.c new file mode 100644 index 000000000..77ed328a5 --- /dev/null +++ b/src/analysis/cktsetbk.c @@ -0,0 +1,69 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* CKTsetBreak(ckt,time) + * add the given time to the breakpoint table for the given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" + + + +int +CKTsetBreak(register CKTcircuit *ckt, double time) +{ + double *tmp; + register int i,j; + + if(ckt->CKTtime > time) { + (*(SPfrontEnd->IFerror))(ERR_PANIC,"breakpoint in the past - HELP!", + (IFuid *)NULL); + return(E_INTERN); + } + for(i=0;iCKTbreakSize;i++) { + if(*(ckt->CKTbreaks+i)>time) { /* passed */ + if((*(ckt->CKTbreaks+i)-time) <= ckt->CKTminBreak) { + /* very close together - take earlier point */ + *(ckt->CKTbreaks+i) = time; + return(OK); + } + if(time-*(ckt->CKTbreaks+i-1) <= ckt->CKTminBreak) { + /* very close together, but after, so skip */ + return(OK); + } + /* fits in middle - new array & insert */ + tmp = (double *)MALLOC((ckt->CKTbreakSize+1)*sizeof(double)); + if(tmp == (double *)NULL) return(E_NOMEM); + for(j=0;jCKTbreaks+j); + } + *(tmp+i)=time; + for(j=i;jCKTbreakSize;j++) { + *(tmp+j+1) = *(ckt->CKTbreaks+j); + } + FREE(ckt->CKTbreaks); + ckt->CKTbreakSize++; + ckt->CKTbreaks=tmp; + return(OK); + } + } + /* never found it - beyond end of time - extend out idea of time */ + if(time-ckt->CKTbreaks[ckt->CKTbreakSize-1]<=ckt->CKTminBreak) { + /* very close tegether - keep earlier, throw out new point */ + return(OK); + } + /* fits at end - grow array & add on */ + ckt->CKTbreaks = (double *)REALLOC(ckt->CKTbreaks, + (ckt->CKTbreakSize+1)*sizeof(double)); + ckt->CKTbreakSize++; + ckt->CKTbreaks[ckt->CKTbreakSize-1]=time; + return(OK); +} diff --git a/src/analysis/cktsetnp.c b/src/analysis/cktsetnp.c new file mode 100644 index 000000000..db4c86010 --- /dev/null +++ b/src/analysis/cktsetnp.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + *CKTsetNodPm + * + * set a parameter on a node. + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" + + + +/* ARGSUSED */ +int +CKTsetNodPm(void *ckt, void *node, int parm, IFvalue *value, IFvalue *selector) +{ + if(!node) return(E_BADPARM); + switch(parm) { + + case PARM_NS: + ((CKTnode *)node)->nodeset = value->rValue; + ((CKTnode *)node)->nsGiven = 1; + break; + + case PARM_IC: + ((CKTnode *)node)->ic = value->rValue; + ((CKTnode *)node)->icGiven = 1; + break; + + case PARM_NODETYPE: + ((CKTnode *)node)->type = value->iValue; + break; + + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/analysis/cktsetup.c b/src/analysis/cktsetup.c new file mode 100644 index 000000000..096c0a78c --- /dev/null +++ b/src/analysis/cktsetup.c @@ -0,0 +1,112 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTsetup(ckt) + * this is a driver program to iterate through all the various + * setup functions provided for the circuit elements in the + * given circuit + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" + + + +#define CKALLOC(var,size,type) \ + if(size && (!(var =(type *)MALLOC((size)*sizeof(type))))){\ + return(E_NOMEM);\ +} + +extern SPICEdev *DEVices[]; + +int +CKTsetup(register CKTcircuit *ckt) +{ + register int i; + int error; + + register SMPmatrix *matrix; + ckt->CKTnumStates=0; + +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo){ + if (error = CKTsenSetup(ckt)) return(error); + } +#endif + + if (ckt->CKTisSetup) + return E_NOCHANGE; + + CKTpartition(ckt); + + error = NIinit(ckt); + if (error) return(error); + ckt->CKTisSetup = 1; + + matrix = ckt->CKTmatrix; + + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVsetup))(matrix,ckt->CKThead[i],ckt, + &ckt->CKTnumStates); + if(error) return(error); + } + } + for(i=0;i<=ckt->CKTmaxOrder+1;i++) { + CKALLOC(ckt->CKTstates[i],ckt->CKTnumStates,double); + } +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo){ + /* to allocate memory to sensitivity structures if + * it is not done before */ + + error = NIsenReinit(ckt); + if(error) return(error); + } +#endif + if(ckt->CKTniState & NIUNINITIALIZED) { + error = NIreinit(ckt); + if(error) return(error); + } + + return(OK); +} + +int +CKTunsetup(CKTcircuit *ckt) +{ + int i, error, e2; + + error = OK; + if (!ckt->CKTisSetup) + return OK; + + for(i=0;i<=ckt->CKTmaxOrder+1;i++) { + tfree(ckt->CKTstates[i]); + } + + for (i=0;iCKThead[i] != NULL) ){ + e2 = (*((*DEVices[i]).DEVunsetup))(ckt->CKThead[i],ckt); + if (!error && e2) + error = e2; + } + } + ckt->CKTisSetup = 0; + if(error) return(error); + + NIdestroy(ckt); + /* + if (ckt->CKTmatrix) + SMPdestroy(ckt->CKTmatrix); + ckt->CKTmatrix = NULL; + */ + + return OK; +} diff --git a/src/analysis/cktsgen.c b/src/analysis/cktsgen.c new file mode 100644 index 000000000..e431807db --- /dev/null +++ b/src/analysis/cktsgen.c @@ -0,0 +1,250 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include "gendefs.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "ifsim.h" +#include "sensgen.h" +#include + +extern SPICEdev *DEVices[]; /* XXX */ +extern char *Sfilter; + +sgen * +sgen_init(CKTcircuit *ckt, int is_dc) +{ + sgen *sg; + + sg = NEW(sgen); + sg->param = 99999; + sg->is_instparam = 0; + sg->dev = -1; + sg->istate = 0; + sg->ckt = ckt; + sg->devlist = ckt->CKThead; + sg->instance = sg->first_instance = sg->next_instance = NULL; + sg->model = sg->next_model = NULL; + sg->ptable = NULL; + sg->is_dc = is_dc; + sg->is_principle = 0; + sg->is_q = 0; + sg->is_zerook = 0; + sg->value = 0.0; + + sgen_next(&sg); /* get the ball rolling XXX check return val? */ + + return sg; +} + +int +sgen_next(sgen **xsg) +{ + sgen *sg = *xsg; + int good, done; + int i; + + done = 0; + i = sg->dev; + + do { + if (sg->instance) { + if (sg->ptable) { + do { + sg->param += 1; + } while (sg->param < sg->max_param + && !set_param(sg)); + } else { + sg->max_param = -1; + } + + if (sg->param < sg->max_param) { + done = 1; + } else if (!sg->is_instparam) { + /* Try instance parameters now */ + sg->is_instparam = 1; + sg->param = -1; + sg->max_param = + *DEVices[i]->DEVpublic.numInstanceParms; + sg->ptable = + DEVices[i]->DEVpublic.instanceParms; + } else { + sg->is_principle = 0; + sg->instance->GENnextInstance = + sg->next_instance; + sg->instance->GENstate = sg->istate; + sg->instance = NULL; + } + + } else if (sg->model) { + + /* Find the first/next good instance for this model */ + for (good = 0; !good && sg->next_instance; + good = set_inst(sg)) + { + sg->instance = sg->next_instance; + sg->next_instance = + sg->instance->GENnextInstance; + } + + + if (good) { + sg->is_principle = 0; + sg->istate = sg->instance->GENstate; + sg->instance->GENnextInstance = NULL; + sg->model->GENinstances = sg->instance; + if (DEVices[i]->DEVpublic.modelParms) { + sg->max_param = + *DEVices[i]->DEVpublic. + numModelParms; + sg->ptable = + DEVices[i]->DEVpublic. + modelParms; + } else { + sg->ptable = NULL; + } + sg->param = -1; + sg->is_instparam = 0; + } else { + /* No good instances of this model */ + sg->model->GENinstances = sg->first_instance; + sg->model->GENnextModel = sg->next_model; + sg->model = NULL; + } + + } else if (i >= 0) { + + /* Find the first/next good model for this device */ + for (good = 0; !good && sg->next_model; + good = set_model(sg)) + { + sg->model = sg->next_model; + sg->next_model = sg->model->GENnextModel; + } + + if (good) { + sg->model->GENnextModel = NULL; + sg->devlist[i] = sg->model; + if (DEVices[i]->DEVpublic.modelParms) { + sg->max_param = + *DEVices[i]->DEVpublic. + numModelParms; + sg->ptable = + DEVices[i]->DEVpublic. + modelParms; + } else { + sg->ptable = NULL; + } + sg->next_instance = sg->first_instance + = sg->model->GENinstances; + } else { + /* No more good models for this device */ + sg->devlist[i] = sg->first_model; + i = -1; /* Try the next good device */ + } + + } else if (i < DEVmaxnum && sg->dev < DEVmaxnum) { + + /* Find the next good device in this circuit */ + + do + sg->dev++; + while (sg->dev < DEVmaxnum && sg->devlist[sg->dev] + && !set_dev(sg)); + + i = sg->dev; + + if (i > DEVmaxnum) + done = 1; + sg->first_model = sg->next_model = sg->devlist[i]; + + } else { + done = 1; + } + + } while (!done); + + if (sg->dev >= DEVmaxnum) { + FREE(sg); + *xsg = NULL; + } + return 1; +} + +int set_inst(sgen *sg) +{ + return 1; +} + +int set_model(sgen *sg) +{ + return 1; +} + +int set_dev(sgen *sg) +{ + return 1; +} + +int set_param(sgen *sg) +{ + IFvalue ifval; + + if (!sg->ptable[sg->param].keyword) + return 0; + if (Sfilter && strncmp(sg->ptable[sg->param].keyword, Sfilter, + strlen(Sfilter))) + return 0; + if ((sg->ptable[sg->param].dataType & + (IF_SET|IF_ASK|IF_REAL|IF_VECTOR|IF_REDUNDANT|IF_NONSENSE)) + != (IF_SET|IF_ASK|IF_REAL)) + return 0; + if (sg->is_dc && + (sg->ptable[sg->param].dataType & (IF_AC | IF_AC_ONLY))) + return 0; + if ((sg->ptable[sg->param].dataType & IF_CHKQUERY) && !sg->is_q) + return 0; + + if (sens_getp(sg, sg->ckt, &ifval)) + return 0; + + if (fabs(ifval.rValue) < 1e-30) { + if (sg->ptable[sg->param].dataType & IF_SETQUERY) + sg->is_q = 0; + + if (!sg->is_zerook + && !(sg->ptable[sg->param].dataType & IF_PRINCIPAL)) + return 0; + + } else if (sg->ptable[sg->param].dataType & (IF_SETQUERY|IF_ORQUERY)) + sg->is_q = 1; + + if (sg->ptable[sg->param].dataType & IF_PRINCIPAL) + sg->is_principle += 1; + + sg->value = ifval.rValue; + + return 1; +} + +#ifdef notdef +sgen_suspend(sg) + sgen *sg; +{ + sg->devlist[sg->dev] = sg->first_model; + sg->model->GENnextModel = sg->next_model; + sg->instance->GENnextInstance = sg->next_instance; + sg->model->GENinstances = sg->first_instance; +} + +sgen_restore(sg) + sgen *sg; +{ + sg->devlist[sg->dev] = sg->model; + sg->model->GENnextModel = NULL; + sg->instance->GENnextInstance = NULL; + sg->model->GENinstances = sg->instance; +} +#endif diff --git a/src/analysis/cktsopt.c b/src/analysis/cktsopt.c new file mode 100644 index 000000000..eba172ad7 --- /dev/null +++ b/src/analysis/cktsopt.c @@ -0,0 +1,223 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + * CKTsetOpt(ckt,opt,value) + * set the specified 'opt' to have value 'value' in the + * given circuit 'ckt'. + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "optdefs.h" +#include "tskdefs.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "sperror.h" + + +/* ARGSUSED */ +int +CKTsetOpt(void *ckt, void *anal, int opt, IFvalue *val) +{ + register TSKtask *task = (TSKtask *)anal; + + switch(opt) { + + case OPT_NOOPITER: + task->TSKnoOpIter = val->iValue; + break; + case OPT_GMIN: + task->TSKgmin = val->rValue; + break; + case OPT_RELTOL: + task->TSKreltol = val->rValue; + break; + case OPT_ABSTOL: + task->TSKabstol = val->rValue; + break; + case OPT_VNTOL: + task->TSKvoltTol = val->rValue; + break; + case OPT_TRTOL: + task->TSKtrtol = val->rValue; + break; + case OPT_CHGTOL: + task->TSKchgtol = val->rValue; + break; + case OPT_PIVTOL: + task->TSKpivotAbsTol = val->rValue; + break; + case OPT_PIVREL: + task->TSKpivotRelTol = val->rValue; + break; + case OPT_TNOM: + task->TSKnomTemp = val->rValue + CONSTCtoK; /* Centegrade to Kelvin */ + break; + case OPT_TEMP: + task->TSKtemp = val->rValue + CONSTCtoK; /* Centegrade to Kelvin */ + break; + case OPT_ITL1: + task->TSKdcMaxIter = val->iValue; + break; + case OPT_ITL2: + task->TSKdcTrcvMaxIter = val->iValue; + break; + case OPT_ITL3: + break; + case OPT_ITL4: + task->TSKtranMaxIter = val->iValue; + break; + case OPT_ITL5: + break; + case OPT_SRCSTEPS: + task->TSKnumSrcSteps = val->iValue; + break; + case OPT_GMINSTEPS: + task->TSKnumGminSteps = val->iValue; + break; + case OPT_DEFL: + task->TSKdefaultMosL = val->rValue; + break; + case OPT_DEFW: + task->TSKdefaultMosW = val->rValue; + break; + case OPT_DEFAD: + task->TSKdefaultMosAD = val->rValue; + break; + case OPT_DEFAS: + task->TSKdefaultMosAD = val->rValue; + break; + case OPT_BYPASS: + task->TSKbypass = val->iValue; + break; + case OPT_MAXORD: + task->TSKmaxOrder = val->iValue; + break; + case OPT_OLDLIMIT: + task->TSKfixLimit = val->iValue; + break; + case OPT_MINBREAK: + task->TSKminBreak = val->rValue; + break; + case OPT_METHOD: + if(strncmp(val->sValue,"trap", 4)==0) + task->TSKintegrateMethod=TRAPEZOIDAL; + else if (strcmp(val->sValue,"gear")==0) + task->TSKintegrateMethod=GEAR; + else return(E_METHOD); + break; + case OPT_TRYTOCOMPACT: + task->TSKtryToCompact = val->iValue; + break; + case OPT_BADMOS3: + task->TSKbadMos3 = val->iValue; + break; + case OPT_KEEPOPINFO: + task->TSKkeepOpInfo = val->iValue; + break; + default: + return(-1); + } + return(0); +} +static IFparm OPTtbl[] = { + { "noopiter", OPT_NOOPITER,IF_SET|IF_FLAG,"Go directly to gmin stepping" }, + { "gmin", OPT_GMIN,IF_SET|IF_REAL,"Minimum conductance" }, + { "reltol", OPT_RELTOL,IF_SET|IF_REAL ,"Relative error tolerence"}, + { "abstol", OPT_ABSTOL,IF_SET|IF_REAL,"Absolute error tolerence" }, + { "vntol", OPT_VNTOL,IF_SET|IF_REAL,"Voltage error tolerence" }, + { "trtol", OPT_TRTOL,IF_SET|IF_REAL,"Truncation error overestimation factor" }, + { "chgtol", OPT_CHGTOL,IF_SET|IF_REAL, "Charge error tolerence" }, + { "pivtol", OPT_PIVTOL,IF_SET|IF_REAL, "Minimum acceptable pivot" }, + { "pivrel", OPT_PIVREL,IF_SET|IF_REAL, "Minimum acceptable ratio of pivot" }, + { "tnom", OPT_TNOM,IF_SET|IF_ASK|IF_REAL, "Nominal temperature" }, + { "temp", OPT_TEMP,IF_SET|IF_ASK|IF_REAL, "Operating temperature" }, + { "itl1", OPT_ITL1,IF_SET|IF_INTEGER,"DC iteration limit" }, + { "itl2", OPT_ITL2,IF_SET|IF_INTEGER,"DC transfer curve iteration limit" }, + { "itl3", OPT_ITL3, IF_INTEGER,"Lower transient iteration limit"}, + { "itl4", OPT_ITL4,IF_SET|IF_INTEGER,"Upper transient iteration limit" }, + { "itl5", OPT_ITL5, IF_INTEGER,"Total transient iteration limit"}, + { "itl6", OPT_SRCSTEPS, IF_SET|IF_INTEGER,"number of source steps"}, + { "srcsteps", OPT_SRCSTEPS, IF_SET|IF_INTEGER,"number of source steps"}, + { "gminsteps", OPT_GMINSTEPS, IF_SET|IF_INTEGER,"number of Gmin steps"}, + { "acct", 0, IF_FLAG ,"Print accounting"}, + { "list", 0, IF_FLAG, "Print a listing" }, + { "nomod", 0, IF_FLAG, "Don't print a model summary" }, + { "nopage", 0, IF_FLAG, "Don't insert page breaks" }, + { "node", 0, IF_FLAG,"Print a node connection summary" }, + { "opts", 0, IF_FLAG, "Print a list of the options" }, + { "oldlimit", OPT_OLDLIMIT, IF_SET|IF_FLAG, "use SPICE2 MOSfet limiting" }, + { "numdgt", 0, IF_INTEGER, "Set number of digits printed"}, + { "cptime", 0, IF_REAL, "Total cpu time in seconds" }, + { "limtim", 0, IF_INTEGER, "Time to reserve for output" }, + { "limpts", 0,IF_INTEGER,"Maximum points per analysis"}, + { "lvlcod", 0, IF_INTEGER,"Generate machine code" }, + { "lvltim", 0, IF_INTEGER,"Type of timestep control" }, + { "method", OPT_METHOD, IF_SET|IF_STRING,"Integration method" }, + { "maxord", OPT_MAXORD, IF_SET|IF_INTEGER,"Maximum integration order" }, + { "defl", OPT_DEFL,IF_SET|IF_REAL,"Default MOSfet length" }, + { "defw", OPT_DEFW,IF_SET|IF_REAL,"Default MOSfet width" }, + { "minbreak", OPT_MINBREAK,IF_SET|IF_REAL,"Minimum time between breakpoints" }, + { "defad", OPT_DEFAD,IF_SET|IF_REAL,"Default MOSfet area of drain" }, + { "defas", OPT_DEFAS,IF_SET|IF_REAL,"Default MOSfet area of source" }, + { "bypass",OPT_BYPASS,IF_SET|IF_INTEGER,"Allow bypass of unchanging elements"}, + { "totiter", OPT_ITERS, IF_ASK|IF_INTEGER,"Total iterations" }, + { "traniter", OPT_TRANIT, IF_ASK|IF_INTEGER ,"Transient iterations"}, + { "equations", OPT_EQNS, IF_ASK|IF_INTEGER,"Circuit Equations" }, + { "originalnz", OPT_ORIGNZ, IF_ASK|IF_INTEGER,"Circuit original non-zeroes" }, + { "fillinnz", OPT_FILLNZ, IF_ASK|IF_INTEGER,"Circuit fill-in non-zeroes" }, + { "totalnz", OPT_TOTALNZ, IF_ASK|IF_INTEGER,"Circuit total non-zeroes" }, + { "tranpoints", OPT_TRANPTS, IF_ASK|IF_INTEGER,"Transient timepoints" }, + { "accept", OPT_TRANACCPT, IF_ASK|IF_INTEGER,"Accepted timepoints" }, + { "rejected", OPT_TRANRJCT, IF_ASK|IF_INTEGER,"Rejected timepoints" }, + { "time", OPT_TOTANALTIME, IF_ASK|IF_REAL,"Total analysis time" }, + { "loadtime", OPT_LOADTIME, IF_ASK|IF_REAL,"Matrix load time" }, + { "synctime", OPT_SYNCTIME, IF_ASK|IF_REAL,"Matrix synchronize time" }, + { "combinetime", OPT_COMBTIME, IF_ASK|IF_REAL,"Matrix combine time" }, + { "reordertime", OPT_REORDTIME, IF_ASK|IF_REAL,"Matrix reorder time" }, + { "factortime", OPT_DECOMP, IF_ASK|IF_REAL,"Matrix factor time" }, + { "solvetime", OPT_SOLVE, IF_ASK|IF_REAL,"Matrix solve time" }, + { "trantime", OPT_TRANTIME, IF_ASK|IF_REAL,"Transient analysis time" }, + { "tranloadtime", OPT_TRANLOAD, IF_ASK|IF_REAL,"Transient load time" }, + { "transynctime", OPT_TRANSYNC, IF_ASK|IF_REAL,"Transient sync time" }, + { "trancombinetime", OPT_TRANCOMB, IF_ASK|IF_REAL,"Transient combine time" }, + { "tranfactortime", OPT_TRANDECOMP,IF_ASK|IF_REAL,"Transient factor time" }, + { "transolvetime", OPT_TRANSOLVE, IF_ASK|IF_REAL,"Transient solve time" }, + { "trantrunctime", OPT_TRANTRUNC, IF_ASK|IF_REAL,"Transient trunc time" }, + { "trancuriters", OPT_TRANCURITER, IF_ASK|IF_INTEGER, + "Transient iters per point" }, + { "actime", OPT_ACTIME, IF_ASK|IF_REAL,"AC analysis time" }, + { "acloadtime", OPT_ACLOAD, IF_ASK|IF_REAL,"AC load time" }, + { "acsynctime", OPT_ACSYNC, IF_ASK|IF_REAL,"AC sync time" }, + { "accombinetime", OPT_ACCOMB, IF_ASK|IF_REAL,"AC combine time" }, + { "acfactortime", OPT_ACDECOMP,IF_ASK|IF_REAL,"AC factor time" }, + { "acsolvetime", OPT_ACSOLVE, IF_ASK|IF_REAL,"AC solve time" }, + { "trytocompact", OPT_TRYTOCOMPACT, IF_SET|IF_FLAG, + "Try compaction for LTRA lines" }, + { "badmos3", OPT_BADMOS3, IF_SET|IF_FLAG, + "use old mos3 model (discontinuous with respect to kappa)" }, + { "keepopinfo", OPT_KEEPOPINFO, IF_SET|IF_FLAG, + "Record operating point for each small-signal analysis" } +}; + +int OPTcount = sizeof(OPTtbl)/sizeof(IFparm); + +SPICEanalysis OPTinfo = { + { + "options", + "Task option selection", + sizeof(OPTtbl)/sizeof(IFparm), + OPTtbl + }, + 0, /* no size associated with options */ + NODOMAIN, + 0, + CKTsetOpt, + CKTacct, + NULL, + NULL +}; diff --git a/src/analysis/ckttemp.c b/src/analysis/ckttemp.c new file mode 100644 index 000000000..fa93cfda4 --- /dev/null +++ b/src/analysis/ckttemp.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTtemp(ckt) + * this is a driver program to iterate through all the various + * temperature dependency functions provided for the circuit + * elements in the given circuit + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" + + + +extern SPICEdev *DEVices[]; + +int +CKTtemp(register CKTcircuit *ckt) +{ + int error; + register int i; + + ckt->CKTvt = CONSTKoverQ * ckt->CKTtemp; + + for (i=0;iCKThead[i] != NULL) ){ + error = (*((*DEVices[i]).DEVtemperature))(ckt->CKThead[i],ckt); + if(error) return(error); + } + } + return(OK); +} diff --git a/src/analysis/cktterr.c b/src/analysis/cktterr.c new file mode 100644 index 000000000..6f3493c62 --- /dev/null +++ b/src/analysis/cktterr.c @@ -0,0 +1,79 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" + + + +#define ccap (qcap+1) + +void +CKTterr(register int qcap, register CKTcircuit *ckt, register double *timeStep) +{ + double volttol; + double chargetol; + double tol; + double del; + double diff[8]; + double deltmp[8]; + double factor; + register int i; + register int j; + static double gearCoeff[] = { + .5, + .2222222222, + .1363636364, + .096, + .07299270073, + .05830903790 + }; + static double trapCoeff[] = { + .5, + .08333333333 + }; + + volttol = ckt->CKTabstol + ckt->CKTreltol * + MAX( fabs(*(ckt->CKTstate0+ccap)), fabs(*(ckt->CKTstate1+ccap))); + + chargetol = MAX(fabs(*(ckt->CKTstate0 +qcap)),fabs(*(ckt->CKTstate1+qcap))); + chargetol = ckt->CKTreltol * MAX(chargetol,ckt->CKTchgtol)/ckt->CKTdelta; + tol = MAX(volttol,chargetol); + /* now divided differences */ + for(i=ckt->CKTorder+1;i>=0;i--) { + diff[i] = *(ckt->CKTstates[i] + qcap); + } + for(i=0 ; i <= ckt->CKTorder ; i++) { + deltmp[i] = ckt->CKTdeltaOld[i]; + } + j = ckt->CKTorder; + while(1) { + for(i=0;i <= j;i++) { + diff[i] = (diff[i] - diff[i+1])/deltmp[i]; + } + if (--j < 0) break; + for(i=0;i <= j;i++) { + deltmp[i] = deltmp[i+1] + ckt->CKTdeltaOld[i]; + } + } + switch(ckt->CKTintegrateMethod) { + case GEAR: + factor = gearCoeff[ckt->CKTorder-1]; + break; + + case TRAPEZOIDAL: + factor = trapCoeff[ckt->CKTorder - 1] ; + break; + } + del = ckt->CKTtrtol * tol/MAX(ckt->CKTabstol,factor * fabs(diff[0])); + if(ckt->CKTorder == 2) { + del = sqrt(del); + } else if (ckt->CKTorder > 2) { + del = exp(log(del)/ckt->CKTorder); + } + *timeStep = MIN(*timeStep,del); + return; +} diff --git a/src/analysis/ckttroub.c b/src/analysis/ckttroub.c new file mode 100644 index 000000000..0cdca9bd3 --- /dev/null +++ b/src/analysis/ckttroub.c @@ -0,0 +1,96 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include +#include "trandefs.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "vsrc/vsrcdefs.h" +#include "isrc/isrcdefs.h" +#include "jobdefs.h" + + +extern SPICEdev *DEVices[]; +extern SPICEanalysis *analInfo[]; + +char * +CKTtrouble(void *cktp, char *optmsg) +{ + CKTcircuit *ckt = (CKTcircuit *) cktp; + char msg_buf[513]; + char *emsg; + TRCV *cv; + int vcode, icode; + char *msg_p; + SPICEanalysis *an; + int i; + + if (!ckt || !ckt->CKTcurJob) + return NULL; + + an = analInfo[ckt->CKTcurJob->JOBtype]; + + if (optmsg && *optmsg) { + sprintf(msg_buf, "%s: %s; ", an->public.name, optmsg); + } else { + sprintf(msg_buf, "%s: ", an->public.name); + } + + msg_p = msg_buf + strlen(msg_buf); + + switch (an->domain) { + case TIMEDOMAIN: + if (ckt->CKTtime == 0.0) + sprintf(msg_p, "initial timepoint: "); + else + sprintf(msg_p, "time = %g, timestep = %g: ", ckt->CKTtime, + ckt->CKTdelta); + break; + + case FREQUENCYDOMAIN: + sprintf(msg_p, "frequency = %g: ", ckt->CKTomega / (2.0 * M_PI)); + break; + + case SWEEPDOMAIN: + cv = (TRCV*) ckt->CKTcurJob; + vcode = CKTtypelook("Vsource"); + icode = CKTtypelook("Isource"); + + for (i = 0; i <= cv->TRCVnestLevel; i++) { + msg_p += strlen(msg_p); + if(cv->TRCVvType[i]==vcode) { /* voltage source */ + sprintf(msg_p, " %s = %g: ", cv->TRCVvName[i], + ((VSRCinstance*)(cv->TRCVvElt[i]))->VSRCdcValue); + } else { + sprintf(msg_p, " %s = %g: ", cv->TRCVvName[i], + ((ISRCinstance*)(cv->TRCVvElt[i]))->ISRCdcValue); + } + } + break; + + case NODOMAIN: + default: + break; + } + + msg_p += strlen(msg_p); + + if (ckt->CKTtroubleNode) { + sprintf(msg_p, "trouble with node \"%s\"\n", + CKTnodName(ckt, ckt->CKTtroubleNode)); + } else if (ckt->CKTtroubleElt) { + /* "-" for dop */ + sprintf(msg_p, "trouble with %s-instance %s\n", + ckt->CKTtroubleElt->GENmodPtr->GENmodName, + ckt->CKTtroubleElt->GENname); + } else { + sprintf(msg_p, "cause unrecorded.\n"); + } + + emsg = MALLOC(strlen(msg_buf)+1); + strcpy(emsg,msg_buf); + + return emsg; +} diff --git a/src/analysis/ckttrunc.c b/src/analysis/ckttrunc.c new file mode 100644 index 000000000..3baed0e50 --- /dev/null +++ b/src/analysis/ckttrunc.c @@ -0,0 +1,201 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* CKTtrunc(ckt) + * this is a driver program to iterate through all the various + * truncation error functions provided for the circuit elements in the + * given circuit + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "devdefs.h" +#include "sperror.h" + + + +extern SPICEdev *DEVices[]; + +int +CKTtrunc(register CKTcircuit *ckt, double *timeStep) +{ +#ifndef NEWTRUNC + register int i; + double timetemp; +#ifdef PARALLEL_ARCH + long type = MT_TRUNC, length = 1; +#endif /* PARALLEL_ARCH */ +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + double startTime; + int error = OK; + + startTime = SPfrontEnd->IFseconds(); + + timetemp = HUGE; + for (i=0;iCKThead[i] != NULL) { +#ifdef STEPDEBUG + debugtemp = timetemp; +#endif /* STEPDEBUG */ + error = (*((*DEVices[i]).DEVtrunc))(ckt->CKThead[i],ckt,&timetemp); + if(error) { + ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() + - startTime; + return(error); + } +#ifdef STEPDEBUG + if(debugtemp != timetemp) { + printf("timestep cut by device type %s from %g to %g\n", + (*DEVices[i]).DEVpublic.name, debugtemp,timetemp); + } +#endif /* STEPDEBUG */ + } + } + *timeStep = MIN(2 * *timeStep,timetemp); + +#ifdef PARALLEL_ARCH + DGOP_( &type, timeStep, &length, "min" ); +#endif /* PARALLEL_ARCH */ + + ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() - startTime; + return(OK); +#else /* NEWTRUNC */ + register int i; + register CKTnode *node; + double timetemp; + double tmp; + double diff; + double tol; + double startTime; + int size; + + startTime = (*(SPfrontEnd->IFseconds))(); + + timetemp = HUGE; + size = SMPmatSize(ckt->CKTmatrix); +#ifdef STEPDEBUG + printf("at time %g, delta %g\n",ckt->CKTtime,ckt->CKTdeltaOld[0]); +#endif STEPDEBUG + node = ckt->CKTnodes; + switch(ckt->CKTintegrateMethod) { + + case TRAPEZOIDAL: + switch(ckt->CKTorder) { + case 1: + for(i=1;iCKTrhs[i]),fabs(ckt->CKTpred[i]))* + ckt->CKTlteReltol+ckt->CKTlteAbstol; + node = node->next; + if(node->type!= 3) continue; + diff = ckt->CKTrhs[i]-ckt->CKTpred[i]; +#ifdef STEPDEBUG + printf("%s: cor=%g, pred=%g ",node->name, + ckt->CKTrhs[i],ckt->CKTpred[i]); +#endif + if(diff != 0) { + tmp = ckt->CKTtrtol * tol * 2 /diff; + tmp = ckt->CKTdeltaOld[0]*sqrt(fabs(tmp)); + timetemp = MIN(timetemp,tmp); +#ifdef STEPDEBUG + printf("tol = %g, diff = %g, h->%g\n",tol,diff,tmp); +#endif + } else { +#ifdef STEPDEBUG + printf("diff is 0\n"); +#endif + } + } + break; + case 2: + for(i=1;iCKTrhs[i]),fabs(ckt->CKTpred[i]))* + ckt->CKTlteReltol+ckt->CKTlteAbstol; + node = node->next; + if(node->type!= 3) continue; + diff = ckt->CKTrhs[i]-ckt->CKTpred[i]; +#ifdef STEPDEBUG + printf("%s: cor=%g, pred=%g ",node->name,ckt->CKTrhs[i], + ckt->CKTpred[i]); +#endif + if(diff != 0) { + tmp = ckt->CKTdeltaOld[0]*ckt->CKTtrtol * tol * 3 * + (ckt->CKTdeltaOld[0]+ckt->CKTdeltaOld[1])/diff; + tmp = fabs(tmp); + timetemp = MIN(timetemp,tmp); +#ifdef STEPDEBUG + printf("tol = %g, diff = %g, h->%g\n",tol,diff,tmp); +#endif + } else { +#ifdef STEPDEBUG + printf("diff is 0\n"); +#endif + } + } + break; + default: + return(E_ORDER); + break; + + } + break; + + case GEAR: { + double delsum=0; + for(i=0;i<=ckt->CKTorder;i++) { + delsum += ckt->CKTdeltaOld[i]; + } + for(i=1;inext; + if(node->type!= 3) continue; + tol = MAX( fabs(ckt->CKTrhs[i]),fabs(ckt->CKTpred[i]))* + ckt->CKTlteReltol+ckt->CKTlteAbstol; + diff = (ckt->CKTrhs[i]-ckt->CKTpred[i]); +#ifdef STEPDEBUG + printf("%s: cor=%g, pred=%g ",node->name,ckt->CKTrhs[i], + ckt->CKTpred[i]); +#endif + if(diff != 0) { + tmp = tol*ckt->CKTtrtol*delsum/(diff*ckt->CKTdelta); + tmp = fabs(tmp); + switch(ckt->CKTorder) { + case 0: + break; + case 1: + tmp = sqrt(tmp); + break; + default: + tmp = exp(log(tmp)/(ckt->CKTorder+1)); + break; + } + tmp *= ckt->CKTdelta; + timetemp = MIN(timetemp,tmp); +#ifdef STEPDEBUG + printf("tol = %g, diff = %g, h->%g\n",tol,diff,tmp); +#endif + } else { +#ifdef STEPDEBUG + printf("diff is 0\n"); +#endif + } + } + } + break; + + default: + return(E_METHOD); + + } + *timeStep = MIN(2 * *timeStep,timetemp); +#ifdef PARALLEL_ARCH + DGOP_( &type, timeStep, &length, "min" ); +#endif /* PARALLEL_ARCH */ + ckt->CKTstat->STATtranTruncTime += SPfrontEnd->IFseconds() - startTime; + return(OK); +#endif /* NEWTRUNC */ +} diff --git a/src/analysis/ckttyplk.c b/src/analysis/ckttyplk.c new file mode 100644 index 000000000..acd136426 --- /dev/null +++ b/src/analysis/ckttyplk.c @@ -0,0 +1,31 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* look up the 'type' in the device description struct and return the + * appropriatestrchr for the device found, or -1 for not found + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include "devdefs.h" + + + +extern SPICEdev *DEVices[]; + +int +CKTtypelook(char *type) +{ + + int i; + for(i=0;i +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" +#include "distodef.h" + + +/* ARGSUSED */ +int +DaskQuest(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case D_START: + value->rValue = ((DISTOAN*)anal)->DstartF1; + break; + + case D_STOP: + value->rValue = ((DISTOAN*)anal)->DstopF1 ; + break; + + case D_STEPS: + value->iValue = ((DISTOAN*)anal)->DnumSteps; + break; + + case D_DEC: + if(((DISTOAN*)anal)->DstepType == DECADE) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case D_OCT: + if(((DISTOAN*)anal)->DstepType == OCTAVE) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case D_LIN: + if(((DISTOAN*)anal)->DstepType == LINEAR) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case D_F2OVRF1: + value->rValue = ((DISTOAN*)anal)->Df2ovrF1; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/analysis/dcoaskq.c b/src/analysis/dcoaskq.c new file mode 100644 index 000000000..67fd67c83 --- /dev/null +++ b/src/analysis/dcoaskq.c @@ -0,0 +1,20 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "opdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +DCOaskQuest(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + return(E_BADPARM); +} + diff --git a/src/analysis/dcop.c b/src/analysis/dcop.c new file mode 100644 index 000000000..39d88f585 --- /dev/null +++ b/src/analysis/dcop.c @@ -0,0 +1,63 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "sperror.h" +#include "ifsim.h" + + +int +DCop(CKTcircuit *ckt) +{ + int CKTload(register CKTcircuit *ckt); + int converged; + int error; + IFuid *nameList; + int numNames; + void *plot; + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + error = (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob, ckt->CKTcurJob->JOBname, + (IFuid)NULL,IF_REAL,numNames,nameList, IF_REAL,&plot); + if(error) return(error); + + converged = CKTop(ckt, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, + ckt->CKTdcMaxIter); + if(converged != 0) return(converged); + + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; + + +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo && ((ckt->CKTsenInfo->SENmode&DCSEN) || + (ckt->CKTsenInfo->SENmode&ACSEN)) ){ +#ifdef SENSDEBUG + printf("\nDC Operating Point Sensitivity Results\n\n"); + CKTsenPrint(ckt); +#endif /* SENSDEBUG */ + senmode = ckt->CKTsenInfo->SENmode; + save = ckt->CKTmode; + ckt->CKTsenInfo->SENmode = DCSEN; + size = SMPmatSize(ckt->CKTmatrix); + for(i = 1; i<=size ; i++){ + *(ckt->CKTrhsOp + i) = *(ckt->CKTrhsOld + i); + } + if(error = CKTsenDCtran(ckt)) return(error); + ckt->CKTmode = save; + ckt->CKTsenInfo->SENmode = senmode; + + } +#endif + converged = CKTload(ckt); + CKTdump(ckt,(double)0,plot); + (*(SPfrontEnd->OUTendPlot))(plot); + return(converged); +} diff --git a/src/analysis/dcosetp.c b/src/analysis/dcosetp.c new file mode 100644 index 000000000..31d507c65 --- /dev/null +++ b/src/analysis/dcosetp.c @@ -0,0 +1,42 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" +#include "opdefs.h" + + +/* ARGSUSED */ +int +DCOsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + default: + break; + } + return(E_BADPARM); +} + + +SPICEanalysis DCOinfo = { + { + "OP", + "D.C. Operating point analysis", + + 0, + NULL, + }, + sizeof(OP), + NODOMAIN, + 1, + DCOsetParm, + DCOaskQuest, + NULL, + DCop +}; diff --git a/src/analysis/dctaskq.c b/src/analysis/dctaskq.c new file mode 100644 index 000000000..9748a61bf --- /dev/null +++ b/src/analysis/dctaskq.c @@ -0,0 +1,26 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "trcvdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +DCTaskQuest(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + default: + break; + } + /* NOTREACHED */ /* TEMPORARY until cases get added */ + return(E_BADPARM); +} + diff --git a/src/analysis/dctran.c b/src/analysis/dctran.c new file mode 100644 index 000000000..04e99cafd --- /dev/null +++ b/src/analysis/dctran.c @@ -0,0 +1,498 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* subroutine to do DC TRANSIENT analysis + --- ONLY, unlike spice2 routine with the same name! */ + +#include "ngspice.h" +#include +#include "trandefs.h" +#include "cktdefs.h" +#include "sperror.h" + +int +DCtran(CKTcircuit *ckt, int restart) +/* restart: forced restart flag */ +{ + int i; + double olddelta; + double delta; + double new; + double *temp; + double startdTime; + double startsTime; + double startlTime; + double startcTime; + double startkTime; + double startTime; + int startIters; + int converged; + int firsttime; + int error; +#ifdef WANT_SENSE2 +#ifdef SENSDEBUG + FILE *outsen; +#endif /* SENSDEBUG */ +#endif + int save_order; + long save_mode; + IFuid timeUid; + IFuid *nameList; + int numNames; + double maxstepsize=0.0; + + int ltra_num; +#ifdef PARALLEL_ARCH + long type = MT_TRANAN, length = 1; +#endif /* PARALLEL_ARCH */ + + if(restart || ckt->CKTtime == 0) { + delta=MIN(ckt->CKTfinalTime/50,ckt->CKTstep)/10; + + /* begin LTRA code addition */ + if (ckt->CKTtimePoints != NULL) + FREE(ckt->CKTtimePoints); + + if (ckt->CKTstep >= ckt->CKTmaxStep) + maxstepsize = ckt->CKTstep; + else + maxstepsize = ckt->CKTmaxStep; + + ckt->CKTsizeIncr = 10; + ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */ + ckt->CKTtimeListSize = ckt->CKTfinalTime / maxstepsize + 0.5; + ltra_num = CKTtypelook("LTRA"); + if (ltra_num >= 0 && ckt->CKThead[ltra_num] != NULL) + ckt->CKTtimePoints = NEWN(double, ckt->CKTtimeListSize); + /* end LTRA code addition */ + + if(ckt->CKTbreaks) FREE(ckt->CKTbreaks); + ckt->CKTbreaks=(double *)MALLOC(2*sizeof(double)); + if(ckt->CKTbreaks == (double *)NULL) return(E_NOMEM); + *(ckt->CKTbreaks)=0; + *(ckt->CKTbreaks+1)=ckt->CKTfinalTime; + ckt->CKTbreakSize=2; + if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5; + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + (*(SPfrontEnd->IFnewUid))((void *)ckt,&timeUid,(IFuid)NULL, + "time", UID_OTHER, (void **)NULL); + error = (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob, + ckt->CKTcurJob->JOBname,timeUid,IF_REAL,numNames,nameList, + IF_REAL,&(((TRANan*)ckt->CKTcurJob)->TRANplot)); + if(error) return(error); + + ckt->CKTtime = 0; + ckt->CKTdelta = 0; + ckt->CKTbreak=1; + firsttime = 1; + save_mode = (ckt->CKTmode&MODEUIC)|MODETRANOP | MODEINITJCT; + save_order = ckt->CKTorder; + converged = CKTop(ckt, + (ckt->CKTmode & MODEUIC)|MODETRANOP| MODEINITJCT, + (ckt->CKTmode & MODEUIC)|MODETRANOP| MODEINITFLOAT, + ckt->CKTdcMaxIter); + if(converged != 0) return(converged); + ckt->CKTstat->STATtimePts ++; + ckt->CKTorder=1; + for(i=0;i<7;i++) { + ckt->CKTdeltaOld[i]=ckt->CKTmaxStep; + } + ckt->CKTdelta = delta; +#ifdef STEPDEBUG + (void)printf("delta initialized to %g\n",ckt->CKTdelta); +#endif + ckt->CKTsaveDelta = ckt->CKTfinalTime/50; + +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){ +#ifdef SENSDEBUG + printf("\nTransient Sensitivity Results\n\n"); + CKTsenPrint(ckt); +#endif /* SENSDEBUG */ + save = ckt->CKTsenInfo->SENmode; + ckt->CKTsenInfo->SENmode = TRANSEN; + save1 = ckt->CKTmode; + save2 = ckt->CKTorder; + ckt->CKTmode = save_mode; + ckt->CKTorder = save_order; + if(error = CKTsenDCtran(ckt)) return(error); + ckt->CKTmode = save1; + ckt->CKTorder = save2; + } +#endif + + ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN; + /* modeinittran set here */ + ckt->CKTag[0]=ckt->CKTag[1]=0; + bcopy((char *)ckt->CKTstate0,(char *)ckt->CKTstate1, + ckt->CKTnumStates*sizeof(double)); + +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){ + size = SMPmatSize(ckt->CKTmatrix); + for(i = 1; i<=size ; i++) + *(ckt->CKTrhsOp + i) = *(ckt->CKTrhsOld + i); + } +#endif + + startTime=(*(SPfrontEnd->IFseconds))(); + startIters = ckt->CKTstat->STATnumIter; + startdTime = ckt->CKTstat->STATdecompTime; + startsTime = ckt->CKTstat->STATsolveTime; + startlTime = ckt->CKTstat->STATloadTime; + startcTime = ckt->CKTstat->STATcombineTime; + startkTime = ckt->CKTstat->STATsyncTime; + } else { + startTime=(*(SPfrontEnd->IFseconds))(); + startIters = ckt->CKTstat->STATnumIter; + startdTime = ckt->CKTstat->STATdecompTime; + startsTime = ckt->CKTstat->STATsolveTime; + startlTime = ckt->CKTstat->STATloadTime; + startcTime = ckt->CKTstat->STATcombineTime; + startkTime = ckt->CKTstat->STATsyncTime; + if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5; + firsttime=0; + goto resume; + } + +/* 650 */ +nextTime: + + /* begin LTRA code addition */ + if (ckt->CKTtimePoints) { + ckt->CKTtimeIndex++; + if (ckt->CKTtimeIndex >= ckt->CKTtimeListSize) { + /* need more space */ + int need; + need = 0.5 + (ckt->CKTfinalTime - ckt->CKTtime) / maxstepsize; + if (need < ckt->CKTsizeIncr) + need = ckt->CKTsizeIncr; + ckt->CKTtimeListSize += need; + ckt->CKTtimePoints = (double *) REALLOC( (char *) + ckt->CKTtimePoints, sizeof(double) * ckt->CKTtimeListSize); + ckt->CKTsizeIncr *= 1.4; + } + *(ckt->CKTtimePoints + ckt->CKTtimeIndex) = ckt->CKTtime; + } + /* end LTRA code addition */ + + error = CKTaccept(ckt); + /* check if current breakpoint is outdated; if so, clear */ + if (ckt->CKTtime > *(ckt->CKTbreaks)) CKTclrBreak(ckt); + +/* + * Breakpoint handling scheme: + * When a timepoint t is accepted (by CKTaccept), clear all previous + * breakpoints, because they will never be needed again. + * + * t may itself be a breakpoint, or indistinguishably close. DON'T + * clear t itself; recognise it as a breakpoint and act accordingly + * + * if t is not a breakpoint, limit the timestep so that the next + * breakpoint is not crossed + */ + +#ifdef STEPDEBUG + printf("accepted at %g\n",ckt->CKTtime); +#endif /* STEPDEBUG */ + ckt->CKTstat->STATaccepted ++; + ckt->CKTbreak=0; + /* XXX Error will cause single process to bail. */ + if(error) { + ckt->CKTcurrentAnalysis = DOING_TRAN; + ckt->CKTstat->STATtranTime += (*(SPfrontEnd->IFseconds))()-startTime; + ckt->CKTstat->STATtranIter += ckt->CKTstat->STATnumIter - startIters; + ckt->CKTstat->STATtranDecompTime += ckt->CKTstat->STATdecompTime - + startdTime; + ckt->CKTstat->STATtranSolveTime += ckt->CKTstat->STATsolveTime - + startsTime; + ckt->CKTstat->STATtranLoadTime += ckt->CKTstat->STATloadTime - + startlTime; + ckt->CKTstat->STATtranCombTime += ckt->CKTstat->STATcombineTime - + startcTime; + ckt->CKTstat->STATtranSyncTime += ckt->CKTstat->STATsyncTime - + startkTime; + return(error); + } + if(ckt->CKTtime >= ckt->CKTinitTime) CKTdump(ckt,ckt->CKTtime, + (((TRANan*)ckt->CKTcurJob)->TRANplot)); + ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter; + if(fabs(ckt->CKTtime - ckt->CKTfinalTime) < ckt->CKTminBreak) { + /*printf(" done: time is %g, final time is %g, and tol is %g\n",*/ + /*ckt->CKTtime,ckt->CKTfinalTime,ckt->CKTminBreak);*/ + (*(SPfrontEnd->OUTendPlot))( (((TRANan*)ckt->CKTcurJob)->TRANplot)); + ckt->CKTcurrentAnalysis = 0; + ckt->CKTstat->STATtranTime += (*(SPfrontEnd->IFseconds))()-startTime; + ckt->CKTstat->STATtranIter += ckt->CKTstat->STATnumIter - startIters; + ckt->CKTstat->STATtranDecompTime += ckt->CKTstat->STATdecompTime - + startdTime; + ckt->CKTstat->STATtranSolveTime += ckt->CKTstat->STATsolveTime - + startsTime; + ckt->CKTstat->STATtranLoadTime += ckt->CKTstat->STATloadTime - + startlTime; + ckt->CKTstat->STATtranCombTime += ckt->CKTstat->STATcombineTime - + startcTime; + ckt->CKTstat->STATtranSyncTime += ckt->CKTstat->STATsyncTime - + startkTime; +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){ + ckt->CKTsenInfo->SENmode = save; +#ifdef SENSDEBUG + fclose(outsen); +#endif /* SENSDEBUG */ + } +#endif + return(OK); + } + if( (*(SPfrontEnd->IFpauseTest))() ) { + /* user requested pause... */ + ckt->CKTcurrentAnalysis = DOING_TRAN; + ckt->CKTstat->STATtranTime += (*(SPfrontEnd->IFseconds))()-startTime; + ckt->CKTstat->STATtranIter += ckt->CKTstat->STATnumIter - startIters; + ckt->CKTstat->STATtranDecompTime += ckt->CKTstat->STATdecompTime - + startdTime; + ckt->CKTstat->STATtranSolveTime += ckt->CKTstat->STATsolveTime - + startsTime; + ckt->CKTstat->STATtranLoadTime += ckt->CKTstat->STATloadTime - + startlTime; + ckt->CKTstat->STATtranCombTime += ckt->CKTstat->STATcombineTime - + startcTime; + ckt->CKTstat->STATtranSyncTime += ckt->CKTstat->STATsyncTime - + startkTime; + return(E_PAUSE); + } +resume: +#ifdef STEPDEBUG + if( (ckt->CKTdelta <= ckt->CKTfinalTime/50) && + (ckt->CKTdelta <= ckt->CKTmaxStep)) { + ; + } else { + if(ckt->CKTfinalTime/50CKTmaxStep) { + (void)printf("limited by Tstop/50\n"); + } else { + (void)printf("limited by Tmax\n"); + } + } +#endif + ckt->CKTdelta = + MIN(ckt->CKTdelta,ckt->CKTmaxStep); + /* are we at a breakpoint, or indistinguishably close? */ + if ((ckt->CKTtime == *(ckt->CKTbreaks)) || (*(ckt->CKTbreaks) - + (ckt->CKTtime) <= ckt->CKTdelmin)) { + /* first timepoint after a breakpoint - cut integration order */ + /* and limit timestep to .1 times minimum of time to next breakpoint, + * and previous timestep + */ + ckt->CKTorder = 1; +#ifdef STEPDEBUG + if( (ckt->CKTdelta >.1* ckt->CKTsaveDelta) || + (ckt->CKTdelta > .1*(*(ckt->CKTbreaks+1)-*(ckt->CKTbreaks))) ) { + if(ckt->CKTsaveDelta < (*(ckt->CKTbreaks+1)-*(ckt->CKTbreaks))) { + (void)printf("limited by pre-breakpoint delta\n"); + } else { + (void)printf("limited by next breakpoint\n"); + } + } +#endif + + ckt->CKTdelta = MIN(ckt->CKTdelta, .1 * MIN(ckt->CKTsaveDelta, + *(ckt->CKTbreaks+1)-*(ckt->CKTbreaks))); + + if(firsttime) { + ckt->CKTdelta /= 10; +#ifdef STEPDEBUG + (void)printf("delta cut for initial timepoint\n"); +#endif + } + + /* don't want to get below delmin for no reason */ + ckt->CKTdelta = MAX(ckt->CKTdelta, ckt->CKTdelmin*2.0); + } + else if(ckt->CKTtime + ckt->CKTdelta >= *(ckt->CKTbreaks)) { + ckt->CKTsaveDelta = ckt->CKTdelta; + ckt->CKTdelta = *(ckt->CKTbreaks) - ckt->CKTtime; +#ifdef STEPDEBUG + (void)printf("delta cut to hit breakpoint\n"); +#endif + ckt->CKTbreak = 1; /* why? the current pt. is not a bkpt. */ + } + +#ifdef PARALLEL_ARCH + DGOP_( &type, &(ckt->CKTdelta), &length, "min" ); +#endif /* PARALLEL_ARCH */ + + for(i=5;i>=0;i--) { + ckt->CKTdeltaOld[i+1]=ckt->CKTdeltaOld[i]; + } + ckt->CKTdeltaOld[0]=ckt->CKTdelta; + + temp = ckt->CKTstates[ckt->CKTmaxOrder+1]; + for(i=ckt->CKTmaxOrder;i>=0;i--) { + ckt->CKTstates[i+1] = ckt->CKTstates[i]; + } + ckt->CKTstates[0] = temp; + +/* 600 */ + while (1) { + olddelta=ckt->CKTdelta; + /* time abort? */ + ckt->CKTtime += ckt->CKTdelta; + ckt->CKTdeltaOld[0]=ckt->CKTdelta; + NIcomCof(ckt); +#ifdef PREDICTOR + error = NIpred(ckt); +#endif /* PREDICTOR */ + save_mode = ckt->CKTmode; + save_order = ckt->CKTorder; + converged = NIiter(ckt,ckt->CKTtranMaxIter); + ckt->CKTstat->STATtimePts ++; + ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITPRED; + if(firsttime) { + for(i=0;iCKTnumStates;i++) { + *(ckt->CKTstate2+i) = *(ckt->CKTstate1+i); + *(ckt->CKTstate3+i) = *(ckt->CKTstate1+i); + } + } + if(converged != 0) { + ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; + ckt->CKTstat->STATrejected ++; + ckt->CKTdelta = ckt->CKTdelta/8; +#ifdef STEPDEBUG + (void)printf("delta cut for non-convergence\n"); +#endif + if(firsttime) { + ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN; + } + ckt->CKTorder = 1; + } else { + if (firsttime) { +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){ + save1 = ckt->CKTmode; + save2 = ckt->CKTorder; + ckt->CKTmode = save_mode; + ckt->CKTorder = save_order; + if(error = CKTsenDCtran(ckt)) return(error); + ckt->CKTmode = save1; + ckt->CKTorder = save2; + } +#endif + firsttime =0; + goto nextTime; /* no check on + * first time point + */ + } + new = ckt->CKTdelta; + error = CKTtrunc(ckt,&new); + if(error) { + ckt->CKTcurrentAnalysis = DOING_TRAN; + ckt->CKTstat->STATtranTime += + (*(SPfrontEnd->IFseconds))()-startTime; + ckt->CKTstat->STATtranIter += + ckt->CKTstat->STATnumIter - startIters; + ckt->CKTstat->STATtranDecompTime += ckt->CKTstat->STATdecompTime + - startdTime; + ckt->CKTstat->STATtranSolveTime += ckt->CKTstat->STATsolveTime + - startsTime; + ckt->CKTstat->STATtranLoadTime += ckt->CKTstat->STATloadTime + - startlTime; + ckt->CKTstat->STATtranCombTime += ckt->CKTstat->STATcombineTime + - startcTime; + ckt->CKTstat->STATtranSyncTime += ckt->CKTstat->STATsyncTime + - startkTime; + return(error); + } + if(new>.9 * ckt->CKTdelta) { + if(ckt->CKTorder == 1) { + new = ckt->CKTdelta; + ckt->CKTorder = 2; + error = CKTtrunc(ckt,&new); + if(error) { + ckt->CKTcurrentAnalysis = DOING_TRAN; + ckt->CKTstat->STATtranTime += + (*(SPfrontEnd->IFseconds))()-startTime; + ckt->CKTstat->STATtranIter += + ckt->CKTstat->STATnumIter - startIters; + ckt->CKTstat->STATtranDecompTime += + ckt->CKTstat->STATdecompTime - startdTime; + ckt->CKTstat->STATtranSolveTime += + ckt->CKTstat->STATsolveTime - startsTime; + ckt->CKTstat->STATtranLoadTime += + ckt->CKTstat->STATloadTime - startlTime; + ckt->CKTstat->STATtranCombTime += + ckt->CKTstat->STATcombineTime - startcTime; + ckt->CKTstat->STATtranSyncTime += + ckt->CKTstat->STATsyncTime - startkTime; + return(error); + } + if(new <= 1.05 * ckt->CKTdelta) { + ckt->CKTorder = 1; + } + } + /* time point OK - 630*/ + ckt->CKTdelta = new; +#ifdef STEPDEBUG + (void)printf( + "delta set to truncation error result:point accepted\n"); +#endif +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){ + save1 = ckt->CKTmode; + save2 = ckt->CKTorder; + ckt->CKTmode = save_mode; + ckt->CKTorder = save_order; + if(error = CKTsenDCtran(ckt)) return(error); + ckt->CKTmode = save1; + ckt->CKTorder = save2; + } +#endif + /* go to 650 - trapezoidal */ + goto nextTime; + } else { + ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta; + ckt->CKTstat->STATrejected ++; + ckt->CKTdelta = new; +#ifdef STEPDEBUG + (void)printf( + "delta set to truncation error result:point rejected\n"); +#endif + } + } +#ifdef PARALLEL_ARCH + DGOP_( &type, &(ckt->CKTdelta), &length, "min" ); +#endif /* PARALLEL_ARCH */ + + if (ckt->CKTdelta <= ckt->CKTdelmin) { + if (olddelta > ckt->CKTdelmin) { + ckt->CKTdelta = ckt->CKTdelmin; +#ifdef STEPDEBUG + (void)printf("delta at delmin\n"); +#endif + } else { + ckt->CKTcurrentAnalysis = DOING_TRAN; + ckt->CKTstat->STATtranTime += + (*(SPfrontEnd->IFseconds))()-startTime; + ckt->CKTstat->STATtranIter += + ckt->CKTstat->STATnumIter - startIters; + ckt->CKTstat->STATtranDecompTime += + ckt->CKTstat->STATdecompTime - startdTime; + ckt->CKTstat->STATtranSolveTime += + ckt->CKTstat->STATsolveTime - startsTime; + ckt->CKTstat->STATtranLoadTime += + ckt->CKTstat->STATloadTime - startlTime; + ckt->CKTstat->STATtranCombTime += + ckt->CKTstat->STATcombineTime - startcTime; + ckt->CKTstat->STATtranSyncTime += + ckt->CKTstat->STATsyncTime - startkTime; + errMsg = CKTtrouble((void *) ckt, "Timestep too small"); + return(E_TIMESTEP); + } + } + } + /* NOTREACHED */ +} diff --git a/src/analysis/dctrcurv.c b/src/analysis/dctrcurv.c new file mode 100644 index 000000000..016e5a717 --- /dev/null +++ b/src/analysis/dctrcurv.c @@ -0,0 +1,403 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: 1999 Paolo Nenzi +**********/ + +#include "ngspice.h" +#include + +#include "vsrc/vsrcdefs.h" +#include "isrc/isrcdefs.h" +#include "res/resdefs.h" + +#include "cktdefs.h" +#include "const.h" +#include "sperror.h" + + +int +DCtrCurv(CKTcircuit *ckt, int restart) + + /* forced restart flag */ +{ + register TRCV* cv = (TRCV*)ckt->CKTcurJob; /* Where we get the job to do */ + int i; + double *temp; + int converged; + int rcode; + int vcode; + int icode; + int j; + int error; + IFuid varUid; + IFuid *nameList; + int numNames; + int firstTime=1; + static void *plot; + +#ifdef WANT_SENSE2 +#ifdef SENSDEBUG + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode&DCSEN) ){ + printf("\nDC Sensitivity Results\n\n"); + CKTsenPrint(ckt); + } +#endif /* SENSDEBUG */ +#endif + + + rcode = CKTtypelook("Resistor"); + vcode = CKTtypelook("Vsource"); + icode = CKTtypelook("Isource"); + if(!restart && cv->TRCVnestState >= 0) { + /* continuing */ + i = cv->TRCVnestState; + goto resume; + } + ckt->CKTtime = 0; + ckt->CKTdelta = cv->TRCVvStep[0]; + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCTRANCURVE | MODEINITJCT ; + ckt->CKTorder=1; + + + /* Save the state of the circuit */ + for(i=0;i<7;i++) { + ckt->CKTdeltaOld[i]=ckt->CKTdelta; + } + + for(i=0;i<=cv->TRCVnestLevel;i++) { + if(rcode >= 0) { + /* resistances are in this version, so use them */ + register RESinstance *here; + register RESmodel *model; + for(model = (RESmodel *)ckt->CKThead[rcode];model != NULL; + model=model->RESnextModel){ + for(here=model->RESinstances;here!=NULL; + here=here->RESnextInstance) { + if(here->RESname == cv->TRCVvName[i]) { + cv->TRCVvElt[i] = (GENinstance *)here; + cv->TRCVvSave[i] = here->RESresist; + cv->TRCVgSave[i] = here->RESresGiven; + cv->TRCVvType[i] = rcode; + here->RESresist = cv->TRCVvStart[i]; + here->RESresGiven = 1; + printf("** Resistor sweep is highly alpha code\n**Results may not be accurate.\n"); + goto found; + } + } + } + } + if(vcode >= 0) { + /* voltage sources are in this version, so use them */ + register VSRCinstance *here; + register VSRCmodel *model; + for(model = (VSRCmodel *)ckt->CKThead[vcode];model != NULL; + model=model->VSRCnextModel){ + for(here=model->VSRCinstances;here!=NULL; + here=here->VSRCnextInstance) { + if(here->VSRCname == cv->TRCVvName[i]) { + cv->TRCVvElt[i] = (GENinstance *)here; + cv->TRCVvSave[i] = here->VSRCdcValue; + cv->TRCVgSave[i] = here->VSRCdcGiven; + cv->TRCVvType[i] = vcode; + here->VSRCdcValue = cv->TRCVvStart[i]; + here->VSRCdcGiven = 1; + goto found; + } + } + } + } + if(icode >= 0 ) { + /* current sources are in this version, so use them */ + register ISRCinstance *here; + register ISRCmodel *model; + + for(model= (ISRCmodel *)ckt->CKThead[icode];model != NULL; + model=model->ISRCnextModel){ + for(here=model->ISRCinstances;here!=NULL; + here=here->ISRCnextInstance) { + if(here->ISRCname == cv->TRCVvName[i]) { + cv->TRCVvElt[i] = (GENinstance *)here; + cv->TRCVvSave[i] = here->ISRCdcValue; + cv->TRCVgSave[i] = here->ISRCdcGiven; + cv->TRCVvType[i] = icode; + here->ISRCdcValue = cv->TRCVvStart[i]; + here->ISRCdcGiven = 1; + goto found; + } + } + } + } + + if(!strcmp(cv->TRCVvName[i], "temp")) + { + cv->TRCVvSave[i]=ckt->CKTtemp; /* Saves the old circuit temperature */ + cv->TRCVvType[i]=TEMP_CODE; /* Set the sweep type code */ + ckt->CKTtemp = cv->TRCVvStart[i] + CONSTCtoK; /* Set the new circuit temp */ + printf("Temperature sweep is alpha code\nresults may not be accurate\n"); + goto found; + } + + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "DCtrCurv: source / resistor %s not in circuit", &(cv->TRCVvName[i])); + return(E_NODEV); + +found:; + } + + i--; /* PN: This seems to do nothing ??? */ + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + + if (cv->TRCVvType[i]==vcode) + (*(SPfrontEnd->IFnewUid))((void *)ckt,&varUid,(IFuid )NULL, + "v-sweep", UID_OTHER, (void **)NULL); + else if (cv->TRCVvType[i]==icode) + (*(SPfrontEnd->IFnewUid))((void *)ckt,&varUid,(IFuid )NULL, + "i-sweep", UID_OTHER, (void **)NULL); + else if (cv->TRCVvType[i]==TEMP_CODE) + (*(SPfrontEnd->IFnewUid))((void *)ckt,&varUid,(IFuid )NULL, + "temp-sweep", UID_OTHER, (void **)NULL); + /* PN Resistance Sweep */ + else if (cv->TRCVvType[i]==rcode) + (*(SPfrontEnd->IFnewUid))((void *)ckt,&varUid,(IFuid )NULL, + "res-sweep", UID_OTHER, (void **)NULL); + else + (*(SPfrontEnd->IFnewUid))((void *)ckt,&varUid,(IFuid )NULL, + "?-sweep", UID_OTHER, (void **)NULL); + + error = (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob, ckt->CKTcurJob->JOBname, + varUid,IF_REAL,numNames,nameList, IF_REAL,&plot); + + if(error) return(error); + /* now have finished the initialization - can start doing hard part */ + + i = 0; + +resume: + + for(;;) { + + if(cv->TRCVvType[i]==vcode) { /* voltage source */ + if((((VSRCinstance*)(cv->TRCVvElt[i]))->VSRCdcValue)* + SIGN(1.,cv->TRCVvStep[i]) - + SIGN(1.,cv->TRCVvStep[i]) * cv->TRCVvStop[i] > + 0.5 * fabs(cv->TRCVvStep[i])) + { + i++ ; + firstTime=1; + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | + MODEDCTRANCURVE | MODEINITJCT ; + if (i > cv->TRCVnestLevel ) break ; + goto nextstep; + } + } else if(cv->TRCVvType[i]==icode) { /* current source */ + if((((ISRCinstance*)(cv->TRCVvElt[i]))->ISRCdcValue)* + SIGN(1.,cv->TRCVvStep[i]) - + SIGN(1.,cv->TRCVvStep[i]) * cv->TRCVvStop[i] > + 0.5 * fabs(cv->TRCVvStep[i])) + { + i++ ; + firstTime=1; + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | + MODEDCTRANCURVE | MODEINITJCT ; + if (i > cv->TRCVnestLevel ) break ; + goto nextstep; + } + + } else if(cv->TRCVvType[i]==rcode) { /* resistance */ + if((((RESinstance*)(cv->TRCVvElt[i]))->RESresist)* + SIGN(1.,cv->TRCVvStep[i]) - + SIGN(1.,cv->TRCVvStep[i]) * cv->TRCVvStop[i] > + 0.5 * fabs(cv->TRCVvStep[i])) + { + i++ ; + firstTime=1; + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | + MODEDCTRANCURVE | MODEINITJCT ; + if (i > cv->TRCVnestLevel ) break ; + goto nextstep; + } + } else if(cv->TRCVvType[i]==TEMP_CODE) { /* temp sweep */ + if(((ckt->CKTtemp) - CONSTCtoK) * SIGN(1.,cv->TRCVvStep[i]) - + SIGN(1.,cv->TRCVvStep[i]) * cv->TRCVvStop[i] > + 0.5 * fabs(cv->TRCVvStep[i])) + { + i++ ; + firstTime=1; + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | + MODEDCTRANCURVE | MODEINITJCT ; + if (i > cv->TRCVnestLevel ) break ; + goto nextstep; + + } + + } /* else not possible */ + while (i > 0) { + /* init(i); */ + i--; + if(cv->TRCVvType[i]==vcode) { /* voltage source */ + ((VSRCinstance *)(cv->TRCVvElt[i]))->VSRCdcValue = + cv->TRCVvStart[i]; + + } else if(cv->TRCVvType[i]==icode) { /* current source */ + ((ISRCinstance *)(cv->TRCVvElt[i]))->ISRCdcValue = + cv->TRCVvStart[i]; + + } else if(cv->TRCVvType[i]==TEMP_CODE) { + ckt->CKTtemp = cv->TRCVvStart[i] + CONSTCtoK; + CKTtemp(ckt); + + } else if(cv->TRCVvType[i]==rcode) { + ((RESinstance *)(cv->TRCVvElt[i]))->RESresist = + cv->TRCVvStart[i]; + ((RESinstance *)(cv->TRCVvElt[i]))->RESconduct = + 1/(((RESinstance *)(cv->TRCVvElt[i]))->RESresist); + /* Note: changing the resistance does nothing */ + /* changing the conductance 1/r instead */ + RESload((GENmodel*)(cv->TRCVvElt[i]->GENmodPtr),ckt); + + + } /* else not possible */ + } + + /* Rotate state vectors. */ + temp = ckt->CKTstates[ckt->CKTmaxOrder+1]; + for(j=ckt->CKTmaxOrder;j>=0;j--) { + ckt->CKTstates[j+1] = ckt->CKTstates[j]; + } + ckt->CKTstate0 = temp; + + /* do operation */ + converged = NIiter(ckt,ckt->CKTdcTrcvMaxIter); + if(converged != 0) { + converged = CKTop(ckt, + (ckt->CKTmode&MODEUIC)|MODEDCTRANCURVE | MODEINITJCT, + (ckt->CKTmode&MODEUIC)|MODEDCTRANCURVE | MODEINITFLOAT, + ckt->CKTdcMaxIter); + if(converged != 0) { + return(converged); + } + } + ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODEDCTRANCURVE | MODEINITPRED ; + if(cv->TRCVvType[0] == vcode) { + ckt->CKTtime = ((VSRCinstance *)(cv->TRCVvElt[i])) + ->VSRCdcValue ; + } else if(cv->TRCVvType[0] == icode) { + ckt->CKTtime = ((ISRCinstance *)(cv->TRCVvElt[i])) + ->ISRCdcValue ; + } else if(cv->TRCVvType[0] == rcode) { + ckt->CKTtime = ((RESinstance *)(cv->TRCVvElt[i])) + ->RESresist; + } + /* PN Temp sweep */ + else + { + ckt->CKTtime = ckt->CKTtemp - CONSTCtoK ; + } +#ifdef WANT_SENSE2 +/* + if(!ckt->CKTsenInfo) printf("sensitivity structure does not exist\n"); + */ + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode&DCSEN) ){ + int senmode; + +#ifdef SENSDEBUG + if(cv->TRCVvType[i]==vcode) { /* voltage source */ + printf("Voltage Source Value : %.5e V\n", + ((VSRCinstance*) (cv->TRCVvElt[i]))->VSRCdcValue); + } + if(cv->TRCVvType[i]==icode) { /* current source */ + printf("Current Source Value : %.5e A\n", + ((ISRCinstance*)(cv->TRCVvElt[i]))->ISRCdcValue); + } + if(cv->TRCVvType[i]==rcode) { /* resistance */ + printf("Current Resistance Value : %.5e Ohm\n", + ((RESinstance*)(cv->TRCVvElt[i]->GENmodPtr))->RESresist); + } + if(cv->TRCVvType[i]==TEMP_CODE) { /* Temperature */ + printf("Current Circuit Temperature : %.5e C\n", + ckt-CKTtime - CONSTCtoK); + } + +#endif /* SENSDEBUG */ + + senmode = ckt->CKTsenInfo->SENmode; + save = ckt->CKTmode; + ckt->CKTsenInfo->SENmode = DCSEN; + if(error = CKTsenDCtran(ckt)) return (error); + ckt->CKTmode = save; + ckt->CKTsenInfo->SENmode = senmode; + + } +#endif + + + CKTdump(ckt,ckt->CKTtime,plot); + if(firstTime) { + firstTime=0; + bcopy((char *)ckt->CKTstate0,(char *)ckt->CKTstate1, + ckt->CKTnumStates*sizeof(double)); + } + +nextstep:; + if(cv->TRCVvType[i]==vcode) { /* voltage source */ + ((VSRCinstance*)(cv->TRCVvElt[i]))->VSRCdcValue += + cv->TRCVvStep[i]; + } else if(cv->TRCVvType[i]==icode) { /* current source */ + ((ISRCinstance*)(cv->TRCVvElt[i]))->ISRCdcValue += + cv->TRCVvStep[i]; + } else if(cv->TRCVvType[i]==rcode) { /* resistance */ + ((RESinstance*)(cv->TRCVvElt[i]))->RESresist += + cv->TRCVvStep[i]; + /* This code should update resistance and conductance */ + ((RESinstance*)(cv->TRCVvElt[i]))->RESconduct = + 1/(((RESinstance*)(cv->TRCVvElt[i]))->RESresist); + RESload((GENmodel*)(cv->TRCVvElt[i]->GENmodPtr),ckt); + } + /* PN Temp Sweep - serban */ + else if (cv->TRCVvType[i]==TEMP_CODE) + { + ckt->CKTtemp += cv->TRCVvStep[i]; + CKTtemp(ckt); + } /* else not possible */ + + if( (*(SPfrontEnd->IFpauseTest))() ) { + /* user asked us to pause, so save state */ + cv->TRCVnestState = i; + return(E_PAUSE); + } + } + + /* all done, lets put everything back */ + + for(i=0;i<=cv->TRCVnestLevel;i++) { + if(cv->TRCVvType[i] == vcode) { /* voltage source */ + ((VSRCinstance*)(cv->TRCVvElt[i]))->VSRCdcValue = + cv->TRCVvSave[i]; + ((VSRCinstance*)(cv->TRCVvElt[i]))->VSRCdcGiven = cv->TRCVgSave[i]; + } else if(cv->TRCVvType[i] == icode) /*current source */ { + ((ISRCinstance*)(cv->TRCVvElt[i]))->ISRCdcValue = + cv->TRCVvSave[i]; + ((ISRCinstance*)(cv->TRCVvElt[i]))->ISRCdcGiven = cv->TRCVgSave[i]; + } else if(cv->TRCVvType[i] == rcode) /* Resistance */ { + ((RESinstance*)(cv->TRCVvElt[i]))->RESresist = + cv->TRCVvSave[i]; + /* We restore both resistance and conductance */ + ((RESinstance*)(cv->TRCVvElt[i]))->RESconduct = + 1/(((RESinstance*)(cv->TRCVvElt[i]))->RESresist); + + ((RESinstance*)(cv->TRCVvElt[i]))->RESresGiven = cv->TRCVgSave[i]; + RESload((GENmodel*)(cv->TRCVvElt[i]->GENmodPtr),ckt); + } + else if(cv->TRCVvType[i] == TEMP_CODE) { + ckt->CKTtemp = cv->TRCVvSave[i]; + CKTtemp(ckt); + } /* else not possible */ + } + (*(SPfrontEnd->OUTendPlot))(plot); + + return(OK); +} diff --git a/src/analysis/dctsetp.c b/src/analysis/dctsetp.c new file mode 100644 index 000000000..fc199ff12 --- /dev/null +++ b/src/analysis/dctsetp.c @@ -0,0 +1,116 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "trcvdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +DCTsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + register TRCV* cv= (TRCV*)anal; + switch(which) { + + case DCT_START1: + cv->TRCVvStart[0] = value->rValue; + cv->TRCVnestLevel = MAX(0,cv->TRCVnestLevel); + cv->TRCVset[0]=TRUE; + break; + + case DCT_STOP1: + cv->TRCVvStop[0] = value->rValue; + cv->TRCVnestLevel = MAX(0,cv->TRCVnestLevel); + cv->TRCVset[0]=TRUE; + break; + + case DCT_STEP1: + cv->TRCVvStep[0] = value->rValue; + cv->TRCVnestLevel = MAX(0,cv->TRCVnestLevel); + cv->TRCVset[0]=TRUE; + break; + + case DCT_START2: + cv->TRCVvStart[1] = value->rValue; + cv->TRCVnestLevel = MAX(1,cv->TRCVnestLevel); + cv->TRCVset[1]=TRUE; + break; + + case DCT_STOP2: + cv->TRCVvStop[1] = value->rValue; + cv->TRCVnestLevel = MAX(1,cv->TRCVnestLevel); + cv->TRCVset[1]=TRUE; + break; + + case DCT_STEP2: + cv->TRCVvStep[1] = value->rValue; + cv->TRCVnestLevel = MAX(1,cv->TRCVnestLevel); + cv->TRCVset[1]=TRUE; + break; + + case DCT_NAME1: + cv->TRCVvName[0] = value->uValue; + cv->TRCVnestLevel = MAX(0,cv->TRCVnestLevel); + cv->TRCVset[0]=TRUE; + break; + + case DCT_NAME2: + cv->TRCVvName[1] = value->uValue; + cv->TRCVnestLevel = MAX(1,cv->TRCVnestLevel); + cv->TRCVset[1]=TRUE; + break; + + case DCT_TYPE1: + cv->TRCVvType[0] = value->iValue; + cv->TRCVnestLevel = MAX(0,cv->TRCVnestLevel); + cv->TRCVset[0]=TRUE; + break; + + case DCT_TYPE2: + cv->TRCVvType[1] = value->iValue; + cv->TRCVnestLevel = MAX(1,cv->TRCVnestLevel); + cv->TRCVset[1]=TRUE; + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm DCTparms[] = { + { "start1", DCT_START1, IF_SET|IF_REAL, "starting voltage/current"}, + { "stop1", DCT_STOP1, IF_SET|IF_REAL, "ending voltage/current" }, + { "step1", DCT_STEP1, IF_SET|IF_REAL, "voltage/current step" }, + { "start2", DCT_START2, IF_SET|IF_REAL, "starting voltage/current"}, + { "stop2", DCT_STOP2, IF_SET|IF_REAL, "ending voltage/current" }, + { "step2", DCT_STEP2, IF_SET|IF_REAL, "voltage/current step" }, + { "name1", DCT_NAME1, IF_SET|IF_INSTANCE, "name of source to step" }, + { "name2", DCT_NAME2, IF_SET|IF_INSTANCE, "name of source to step" }, + { "type1", DCT_TYPE1, IF_SET|IF_INTEGER, "type of source to step" }, + { "type2", DCT_TYPE2, IF_SET|IF_INTEGER, "type of source to step" } +}; + +SPICEanalysis DCTinfo = { + { + "DC", + "D.C. Transfer curve analysis", + + sizeof(DCTparms)/sizeof(IFparm), + DCTparms + }, + sizeof(TRCV), + SWEEPDOMAIN, + 1, + DCTsetParm, + DCTaskQuest, + NULL, + DCtrCurv +}; diff --git a/src/analysis/distoan.c b/src/analysis/distoan.c new file mode 100644 index 000000000..9ab5c2dda --- /dev/null +++ b/src/analysis/distoan.c @@ -0,0 +1,668 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "distodef.h" +#include "sperror.h" + + +void +DISswap(double **a, double **b) +{ +double *c; + +c = *a; +*a = *b; +*b = c; +} + +void +DmemAlloc(double **a, int size) +{ +*a = (double *) MALLOC( sizeof(double) * size + 1); +} + + + +void +DstorAlloc(double ***header, int size) +{ +*header = (double **) MALLOC( sizeof(double *)*size); +} + + +#ifdef STDC +extern int CKTdisto(CKTcircuit*, int); +extern int DkerProc(int,double*,double*,int,DISTOan*); +#else +extern int CKTdisto(register CKTcircuit *ckt, int mode); +extern int DkerProc(int type, double *rPtr, double *iPtr, int size, DISTOAN *job); +#endif + + +int +DISTOan(CKTcircuit *ckt, int restart) +{ + + double freq; + static double freqTol; /* tolerence parameter for finding final frequency */ + static int NoOfPoints; + static int size; + static int displacement; + int error; + int i; + int numNames; + IFuid *nameList; + IFuid freqUid; + void *acPlot; + register DISTOAN* job = (DISTOAN *) (ckt->CKTcurJob); + static char *nof2src = "No source with f2 distortion input"; +#ifdef DISTODEBUG + double time,time1; +#endif + + + /* start at beginning */ + +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))(); +#endif + switch(job->DstepType) { + + case DECADE: + job->DfreqDelta = + exp(log(10.0)/job->DnumSteps); + freqTol = job->DfreqDelta * + job->DstopF1 * ckt->CKTreltol; + NoOfPoints = 1 + floor ((job->DnumSteps) / log(10.0) * log((job->DstopF1+freqTol)/(job->DstartF1))); + break; + case OCTAVE: + job->DfreqDelta = + exp(log(2.0)/job->DnumSteps); + freqTol = job->DfreqDelta * + job->DstopF1 * ckt->CKTreltol; + NoOfPoints = 1 + floor ((job->DnumSteps) / log(2.0) * log((job->DstopF1+freqTol)/(job->DstartF1))); + break; + case LINEAR: + job->DfreqDelta = + (job->DstopF1 - + job->DstartF1)/ + (job->DnumSteps+1); + freqTol = job->DfreqDelta * ckt->CKTreltol; + NoOfPoints = job->DnumSteps+1+ floor(freqTol/(job->DfreqDelta)); + break; + default: + return(E_BADPARM); + } + + error = CKTop(ckt, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, + ckt->CKTdcMaxIter); + if(error) return(error); + + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; + error = CKTload(ckt); + if(error) return(error); + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + + if (ckt->CKTkeepOpInfo) { + /* Dump operating point. */ + error = (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob, "Distortion Operating Point", + (IFuid)NULL,IF_REAL,numNames,nameList, IF_REAL,&acPlot); + if(error) return(error); + CKTdump(ckt,(double)0,acPlot); + (*(SPfrontEnd->OUTendPlot))(acPlot); + } + +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))() - time1; +printf("Time for initial work (including op. pt.): %g seconds \n", time1); +#endif + +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_SETUP); +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))() - time1; +printf("Time outside D_SETUP: %g seconds \n", time1); +#endif + if (error) return(error); + + displacement = 0; + +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))(); +#endif + freq = job->DstartF1; + if (job->Df2wanted) { + /* + omegadelta = 2.0 * M_PI * freq *(1. - job->Df2ovrF1); + */ + /* keeping f2 const to be compatible with spectre */ + job->Domega2 = 2.0 * M_PI * freq * job->Df2ovrF1; + } + DstorAlloc( &(job->r1H1stor),NoOfPoints+2); + DstorAlloc( &(job->r2H11stor),NoOfPoints+2); + DstorAlloc( &(job->i1H1stor),NoOfPoints+2); + DstorAlloc( &(job->i2H11stor),NoOfPoints+2); + size = SMPmatSize(ckt->CKTmatrix); + if (! job->r1H1ptr) + { + DmemAlloc( &(job->r1H1ptr) , size+2); + if (! job->r1H1ptr) return (E_NOMEM); + } + + if (! job->r2H11ptr) + { + DmemAlloc( &(job->r2H11ptr) , size+2); + if (! job->r2H11ptr) return (E_NOMEM); + } + if (! job->i1H1ptr) + { + DmemAlloc( &(job->i1H1ptr) , size+2); + if (! job->i1H1ptr) return (E_NOMEM); + } + + if (! job->i2H11ptr) + { + DmemAlloc( &(job->i2H11ptr) , size+2); + if (! job->i2H11ptr) return (E_NOMEM); + } + + if (! (job->Df2wanted)) + { + DstorAlloc( &(job->r3H11stor),NoOfPoints+2); + DstorAlloc( &(job->i3H11stor),NoOfPoints+2); + if (! job->r3H11ptr) + { + DmemAlloc( &(job->r3H11ptr) , size+2); + if (! job->r3H11ptr) return (E_NOMEM); + } + if (! job->i3H11ptr) + { + DmemAlloc( &(job->i3H11ptr) , size+2); + if (! job->i3H11ptr) return (E_NOMEM); + } + } else { + DstorAlloc ( &(job->r1H2stor),NoOfPoints+2); + DstorAlloc ( &(job->i1H2stor),NoOfPoints+2); + DstorAlloc ( &(job->r2H12stor),NoOfPoints+2); + DstorAlloc ( &(job->i2H12stor),NoOfPoints+2); + DstorAlloc ( &(job->r2H1m2stor),NoOfPoints+2); + DstorAlloc ( &(job->i2H1m2stor),NoOfPoints+2); + DstorAlloc ( &(job->r3H1m2stor),NoOfPoints+2); + DstorAlloc ( &(job->i3H1m2stor),NoOfPoints+2); + if (! job->r1H2ptr) + { + DmemAlloc( &(job->r1H2ptr) , size+2); + if (! job->r1H2ptr) return (E_NOMEM); + } + + if (! job->r2H12ptr) + { + DmemAlloc( &(job->r2H12ptr) , size+2); + if (! job->r2H12ptr) return (E_NOMEM); + } + + if (! job->r2H1m2ptr) + { + DmemAlloc( &(job->r2H1m2ptr) , size+2); + if (! job->r2H1m2ptr) return (E_NOMEM); + } + + if (! job->r3H1m2ptr) + { + DmemAlloc( &(job->r3H1m2ptr) , size+2); + if (! job->r3H1m2ptr) return (E_NOMEM); + } + if (! job->i1H2ptr) + { + DmemAlloc( &(job->i1H2ptr) , size+2); + if (! job->i1H2ptr) return (E_NOMEM); + } + + if (! job->i2H12ptr) + { + DmemAlloc( &(job->i2H12ptr) , size+2); + if (! job->i2H12ptr) return (E_NOMEM); + } + + if (! job->i2H1m2ptr) + { + DmemAlloc( &(job->i2H1m2ptr) , size+2); + if (! job->i2H1m2ptr) return (E_NOMEM); + } + + if (! job->i3H1m2ptr) + { + DmemAlloc( &(job->i3H1m2ptr) , size+2); + if (! job->i3H1m2ptr) return (E_NOMEM); + } +} + +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))() - time1; +printf("Time for other setup (storage allocation etc.): %g seconds \n", time1); +#endif + + + +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))(); +#endif + while(freq <= job->DstopF1+freqTol) { + +/* + if( (*(SPfrontEnd->IFpauseTest))() ) { + job->DsaveF1 = freq; + return(E_PAUSE); + } + */ + ckt->CKTomega = 2.0 * M_PI *freq; + job->Domega1 = ckt->CKTomega; + ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODEAC; +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTacLoad(ckt); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time for CKTacLoad: %g seconds \n", time); +#endif + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_RHSF1); /* sets up the RHS vector + for all inputs corresponding to F1 */ +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time outside DISTO_RHSFIX: %g seconds \n", time); +#endif + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = NIdIter(ckt); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time for NIdIter: %g seconds \n", time); +#endif + if (error) return(error); + DISswap(&(ckt->CKTrhsOld),&(job->r1H1ptr)); + DISswap(&(ckt->CKTirhsOld),&(job->i1H1ptr)); + + ckt->CKTomega *= 2; + error = CKTacLoad(ckt); + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_TWOF1); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time outside D_TWOF1: %g seconds \n", time); +#endif + if (error) return(error); + error = NIdIter(ckt); + if (error) return(error); + DISswap(&(ckt->CKTrhsOld),&(job->r2H11ptr)); + DISswap(&(ckt->CKTirhsOld),&(job->i2H11ptr)); + + if (! (job->Df2wanted )) + { + + + ckt->CKTomega = 3 * job->Domega1; + error = CKTacLoad(ckt); + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_THRF1); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time outside D_THRF1: %g seconds \n", time); +#endif + if (error) return(error); + error = NIdIter(ckt); + if (error) return(error); + DISswap(&(ckt->CKTrhsOld),&(job->r3H11ptr)); + DISswap(&(ckt->CKTirhsOld),&(job->i3H11ptr)); + + + } + else if (job->Df2given) + { + + + /* + ckt->CKTomega = job->Domega1 - omegadelta; + job->Domega2 = ckt->CKTomega; + */ + ckt->CKTomega = job->Domega2; + error = CKTacLoad(ckt); + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_RHSF2); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time outside DISTO_RHSFIX: %g seconds \n", time); +#endif + if (error) return(error); + error = NIdIter(ckt); + if (error) return(error); + DISswap(&(ckt->CKTrhsOld),&(job->r1H2ptr)); + DISswap(&(ckt->CKTirhsOld),&(job->i1H2ptr)); + + + ckt->CKTomega = job->Domega1 + + job->Domega2; + error = CKTacLoad(ckt); + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_F1PF2); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time outside D_F1PF2: %g seconds \n", time); +#endif + if (error) return(error); + error = NIdIter(ckt); + if (error) return(error); + DISswap(&(ckt->CKTrhsOld),&(job->r2H12ptr)); + DISswap(&(ckt->CKTirhsOld),&(job->i2H12ptr)); + + + + ckt->CKTomega = job->Domega1 - + job->Domega2; + error = CKTacLoad(ckt); + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_F1MF2); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time outside D_F1MF2: %g seconds \n", time); +#endif + if (error) return(error); + error = NIdIter(ckt); + if (error) return(error); + DISswap(&(ckt->CKTrhsOld),&(job->r2H1m2ptr)); + DISswap(&(ckt->CKTirhsOld),&(job->i2H1m2ptr)); + + + ckt->CKTomega = 2*job->Domega1 - + job->Domega2; + error = CKTacLoad(ckt); + if (error) return(error); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))(); +#endif + error = CKTdisto(ckt,D_2F1MF2); +#ifdef D_DBG_SMALLTIMES +time = (*(SPfrontEnd->IFseconds))() - time; +printf("Time outside D_2F1MF2: %g seconds \n", time); +#endif + if (error) return(error); + error = NIdIter(ckt); + if (error) return(error); + DISswap(&(ckt->CKTrhsOld),&(job->r3H1m2ptr)); + DISswap(&(ckt->CKTirhsOld),&(job->i3H1m2ptr)); + + + } + else + { + errMsg = MALLOC(strlen(nof2src)+1); + strcpy(errMsg,nof2src); + return(E_NOF2SRC); + } + + + + + DmemAlloc( &(job->r1H1stor[displacement]),size); + DISswap(&(job->r1H1stor[displacement]),&(job->r1H1ptr)); + job->r1H1stor[displacement][0]=freq; + DmemAlloc( &(job->r2H11stor[displacement]),size); + DISswap(&(job->r2H11stor[displacement]),&((job->r2H11ptr))); + job->r2H11stor[displacement][0]=freq; + DmemAlloc( &(job->i1H1stor[displacement]),size); + DISswap(&(job->i1H1stor[displacement]),&((job->i1H1ptr))); + job->i1H1stor[displacement][0]=0.0; + DmemAlloc( &(job->i2H11stor[displacement]),size); + DISswap(&(job->i2H11stor[displacement]),&((job->i2H11ptr))); + job->i2H11stor[displacement][0]=0.0; + if (! (job->Df2wanted)) + { + DmemAlloc( &(job->r3H11stor[displacement]),size); + DISswap(&(job->r3H11stor[displacement]),&((job->r3H11ptr))); + job->r3H11stor[displacement][0]=freq; + DmemAlloc( &(job->i3H11stor[displacement]),size); + DISswap(&(job->i3H11stor[displacement]),&((job->i3H11ptr))); + job->i3H11stor[displacement][0]=0.0; + } else { + DmemAlloc( &(job->r1H2stor[displacement]),size); + DISswap(&(job->r1H2stor[displacement]),&((job->r1H2ptr))); + job->r1H2stor[displacement][0]=freq; + DmemAlloc( &(job->r2H12stor[displacement]),size); + DISswap(&(job->r2H12stor[displacement]),&((job->r2H12ptr))); + job->r2H12stor[displacement][0]=freq; + DmemAlloc( &(job->r2H1m2stor[displacement]),size); + DISswap(&(job->r2H1m2stor[displacement]),&((job->r2H1m2ptr))); + job->r2H1m2stor[displacement][0]=freq; + DmemAlloc( &(job->r3H1m2stor[displacement]),size); + DISswap(&(job->r3H1m2stor[displacement]),&((job->r3H1m2ptr))); + job->r3H1m2stor[displacement][0]=freq; + + DmemAlloc( &(job->i1H2stor[displacement]),size); + DISswap(&(job->i1H2stor[displacement]),&((job->i1H2ptr))); + job->i1H2stor[displacement][0]=0.0; + DmemAlloc( &(job->i2H12stor[displacement]),size); + DISswap(&(job->i2H12stor[displacement]),&((job->i2H12ptr))); + job->i2H12stor[displacement][0]=0.0; + DmemAlloc( &(job->i2H1m2stor[displacement]),size); + DISswap(&(job->i2H1m2stor[displacement]),&((job->i2H1m2ptr))); + job->i2H1m2stor[displacement][0]=0.0; + DmemAlloc( &(job->i3H1m2stor[displacement]),size); + DISswap(&(job->i3H1m2stor[displacement]),&((job->i3H1m2ptr))); + job->i3H1m2stor[displacement][0]=0.0; + } + displacement++; + + + + switch(job->DstepType) { + case DECADE: + case OCTAVE: + freq *= job->DfreqDelta; + if(job->DfreqDelta==1) goto endsweep; + break; + case LINEAR: + freq += job->DfreqDelta; + if(job->DfreqDelta==0) goto endsweep; + break; + default: + return(E_INTERN); + } + } +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))() - time1; +printf("Time inside frequency loop: %g seconds \n", time1); +#endif + +endsweep: + + + /* output routines to process the H's and output actual ckt variable + values */ +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))(); +#endif + + + + if (! job->Df2wanted) { + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + (*(SPfrontEnd->IFnewUid))((void *)ckt,&freqUid,(IFuid)NULL, + "frequency", UID_OTHER,(void **)NULL); + (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob,"DISTORTION - 2nd harmonic", + freqUid,IF_REAL, numNames,nameList,IF_COMPLEX,&acPlot); + if (job->DstepType != LINEAR) { + (*(SPfrontEnd->OUTattributes))((void *)acPlot,NULL, + OUT_SCALE_LOG, NULL); + } + for (i=0; i< displacement ; i++) + { + DkerProc(D_TWOF1,*(job->r2H11stor + i), + *(job->i2H11stor + i), + size, job); + ckt->CKTrhsOld = *((job->r2H11stor) + i); + ckt->CKTirhsOld = *((job->i2H11stor) + i); + error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot); + if(error) return(error); + } + (*(SPfrontEnd->OUTendPlot))(acPlot); + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + (*(SPfrontEnd->IFnewUid))((void *)ckt,&freqUid,(IFuid)NULL, + "frequency", UID_OTHER,(void **)NULL); + (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob,"DISTORTION - 3rd harmonic",freqUid,IF_REAL, + numNames,nameList,IF_COMPLEX,&acPlot); + for (i=0; i< displacement ; i++) + { + DkerProc(D_THRF1,*(job->r3H11stor + i), + *(job->i3H11stor + i), + size, job); + ckt->CKTrhsOld = *((job->r3H11stor) + i); + ckt->CKTirhsOld = *((job->i3H11stor) + i); + error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot); + } + (*(SPfrontEnd->OUTendPlot))(acPlot); + + } else { + + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + (*(SPfrontEnd->IFnewUid))((void *)ckt,&freqUid,(IFuid)NULL, + "frequency", UID_OTHER,(void **)NULL); + (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob,"DISTORTION - IM: f1+f2",freqUid,IF_REAL, + numNames,nameList,IF_COMPLEX,&acPlot); + for (i=0; i< displacement ; i++) + { + DkerProc(D_F1PF2,*(job->r2H12stor + i), + *(job->i2H12stor + i), + size, job); + ckt->CKTrhsOld = *((job->r2H12stor) + i); + ckt->CKTirhsOld = *((job->i2H12stor) + i); + error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot); + if(error) return(error); + } + (*(SPfrontEnd->OUTendPlot))(acPlot); + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + (*(SPfrontEnd->IFnewUid))((void *)ckt,&freqUid,(IFuid)NULL, + "frequency", UID_OTHER,(void **)NULL); + (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob,"DISTORTION - IM: f1-f2",freqUid,IF_REAL, + numNames,nameList,IF_COMPLEX,&acPlot); + for (i=0; i< displacement ; i++) + { + DkerProc(D_F1MF2, + *(job->r2H1m2stor + i), + *(job->i2H1m2stor + i), + size, job); + ckt->CKTrhsOld = *((job->r2H1m2stor) + i); + ckt->CKTirhsOld = *((job->i2H1m2stor) + i); + error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot); + if(error) return(error); + } + (*(SPfrontEnd->OUTendPlot))(acPlot); + + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + (*(SPfrontEnd->IFnewUid))((void *)ckt,&freqUid,(IFuid)NULL, + "frequency", UID_OTHER,(void **)NULL); + (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob,"DISTORTION - IM: 2f1-f2",freqUid,IF_REAL, + numNames,nameList,IF_COMPLEX,&acPlot); + for (i=0; i< displacement ; i++) + { + DkerProc(D_2F1MF2, + *(job->r3H1m2stor + i), + *(job->i3H1m2stor + i), + size, job); + ckt->CKTrhsOld = *((job->r3H1m2stor) + i); + ckt->CKTirhsOld = *((job->i3H1m2stor) + i); + error = CKTacDump(ckt,ckt->CKTrhsOld[0],acPlot); + if(error) return(error); + } + (*(SPfrontEnd->OUTendPlot))(acPlot); + + } +FREE(job->r1H1ptr); +FREE(job->i1H1ptr); +FREE(job->r2H11ptr); +FREE(job->i2H11ptr); + +FREE(job->r1H1stor); +FREE(job->i1H1stor); +FREE(job->r2H11stor); +FREE(job->i2H11stor); + + if (! (job->Df2wanted)) + { +FREE(job->r3H11ptr); +FREE(job->i3H11ptr); + +FREE(job->i3H11stor); +FREE(job->r3H11stor); +} +else { + +FREE(job->r2H1m2ptr); +FREE(job->r3H1m2ptr); +FREE(job->r1H2ptr); +FREE(job->i1H2ptr); +FREE(job->r2H12ptr); +FREE(job->i2H12ptr); +FREE(job->i2H1m2ptr); +FREE(job->i3H1m2ptr); + +FREE(job->r1H2stor); +FREE(job->r2H12stor); +FREE(job->r2H1m2stor); +FREE(job->r3H1m2stor); +FREE(job->i1H2stor); +FREE(job->i2H12stor); +FREE(job->i2H1m2stor); +FREE(job->i3H1m2stor); + } +#ifdef D_DBG_BLOCKTIMES +time1 = (*(SPfrontEnd->IFseconds))() - time1; +printf("Time for output and deallocation: %g seconds \n", time1); +#endif + return(OK); +} diff --git a/src/analysis/dkerproc.c b/src/analysis/dkerproc.c new file mode 100644 index 000000000..887769338 --- /dev/null +++ b/src/analysis/dkerproc.c @@ -0,0 +1,102 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "sperror.h" +#include "distodef.h" + + +int +DkerProc(int type, double *rPtr, double *iPtr, int size, DISTOAN *job) +{ +int i; + +switch(type) { + + case D_F1: + + + for (i=1;i<=size;i++) + { + iPtr[i] *= 2.0; /* convert to sinusoid amplitude */ + rPtr[i] *= 2.0; + } + + break; + + case D_F2: + + + for (i=1;i<=size;i++) + { + rPtr[i] *= 2.0; + iPtr[i] *= 2.0; + } + + break; + + case D_TWOF1: + + + for (i=1;i<=size;i++) + { + iPtr[i] *= 2.0; + rPtr[i] *= 2.0; + } + + break; + + case D_THRF1: + + + for (i=1;i<=size;i++) + { + iPtr[i] *= 2.0; + rPtr[i] *= 2.0; + } + + break; + + case D_F1PF2: + + + for (i=1;i<=size;i++) + { + iPtr[i] *= 4.0; + rPtr[i] *= 4.0; + } + + break; + + case D_F1MF2: + + + for (i=1;i<=size;i++) + { + iPtr[i] *= 4.0; + rPtr[i] *= 4.0; + } + + break; + + case D_2F1MF2: + + for (i=1;i<=size;i++) + { + iPtr[i] *= 6.0; + rPtr[i] *= 6.0; + } + + break; + + default: + + return(E_BADPARM); + +} + +return(OK); +} diff --git a/src/analysis/dloadfns.c b/src/analysis/dloadfns.c new file mode 100644 index 000000000..e404a214d --- /dev/null +++ b/src/analysis/dloadfns.c @@ -0,0 +1,673 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" + + +/* + * all subFns are local to this file so they need not be renamed to + * the awful 7 letter standard; however, for reasons of uniformity, + * they are being renamed, losing all readability in the process. + * the renaming convention is as follows: + * example: 3v3F1m2 + * 3v => 3 variable term xyz + * 2F1m2 => Two F1 minus F2 + * therefore the old name would be : S3v3F1minusF2 + * for the imaginary sub functions, the v is replaced by an i + * + */ +double +S2v2F1(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y) + + /* 5 arguments */ + +{ +return(cxy*(r1h1x*r1h1y - i1h1x*i1h1y)); +} + +double +S2i2F1(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y) + + /* 5 arguments */ + +{ +return(cxy*(r1h1x*i1h1y + i1h1x*r1h1y)); +} + +double +S2v3F1(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r2h11x, double i2h11x, double r2h11y, double i2h11y) + + /* 9 arguments */ + + +{ +return(cxy*(r1h1x*r2h11y - i1h1x*i2h11y + r1h1y*r2h11x - i1h1y* + i2h11x)); +} + + +double +S2i3F1(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r2h11x, double i2h11x, double r2h11y, double i2h11y) + + /* 9 arguments */ + + +{ +return(cxy*(r1h1x*i2h11y + i1h1x*r2h11y + r1h1y*i2h11x + i1h1y* + r2h11x)); +} + +double +S2vF12(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h2x, double i1h2x, double r1h2y, double i1h2y) + + /* 9 arguments */ + + +{ +return(cxy*(r1h1x*r1h2y - i1h1x*i1h2y + r1h1y*r1h2x - i1h1y*i1h2x)); +} + +double +S2iF12(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h2x, double i1h2x, double r1h2y, double i1h2y) + + /* 9 arguments */ + + +{ +return(cxy*(r1h1x*i1h2y + i1h1x*r1h2y + r1h1y*i1h2x + i1h1y*r1h2x)); +} + +double +S2v2F12(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h2x, double i1h2x, double r1h2y, double i1h2y, double r2h11x, double i2h11x, double r2h11y, double i2h11y, double h2f1f2x, double ih2f1f2x, double h2f1f2y, double ih2f1f2y) + + /* 17 arguments */ + + + + +{ +return ( cxy * ( + 2*(r1h1x*h2f1f2y - i1h1x*ih2f1f2y + +r1h1y*h2f1f2x - i1h1y*ih2f1f2x) + + r1h2x*r2h11y - i1h2x*i2h11y + + r1h2y*r2h11x - i1h2y*i2h11x + )); +} + +double +S2i2F12(double cxy, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h2x, double i1h2x, double r1h2y, double i1h2y, double r2h11x, double i2h11x, double r2h11y, double i2h11y, double h2f1f2x, double ih2f1f2x, double h2f1f2y, double ih2f1f2y) + + /* 17 arguments */ + + + + +{ +return ( cxy * ( + 2*(r1h1x*ih2f1f2y + i1h1x*h2f1f2y + +r1h1y*ih2f1f2x + i1h1y*h2f1f2x) + + r1h2x*i2h11y + i1h2x*r2h11y + + r1h2y*i2h11x + i1h2y*r2h11x + )); +} + +double +S3v3F1(double cxyz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z) + + /* 7 arguments */ + + +{ +return( cxyz * ( + (r1h1x*r1h1y - i1h1x*i1h1y)*r1h1z - (i1h1x*r1h1y + r1h1x*i1h1y)*i1h1z + )); +} + +double +S3i3F1(double cxyz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z) + + /* 7 arguments */ + + +{ +return( cxyz * ( + (r1h1x*r1h1y - i1h1x*i1h1y)*i1h1z + (i1h1x*r1h1y + r1h1x*i1h1y)*r1h1z + )); +} + +double +S3v2F12(double cxyz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z, double r1h2x, double i1h2x, double r1h2y, double i1h2y, double r1h2z, double i1h2z) + + /* 13 arguments */ + + + +{ +return ( cxyz * ( + (r1h1x*r1h1y - i1h1x*i1h1y)*r1h2z - (i1h1x*r1h1y + r1h1x*i1h1y)*i1h2z + + + (r1h1x*r1h1z - i1h1x*i1h1z)*r1h2y - (i1h1x*r1h1z + r1h1x*i1h1z)*i1h2y + + + (r1h1z*r1h1y - i1h1z*i1h1y)*r1h2x - (i1h1z*r1h1y + r1h1z*i1h1y)*i1h2x + )); +} + +double +S3i2F12(double cxyz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z, double r1h2x, double i1h2x, double r1h2y, double i1h2y, double r1h2z, double i1h2z) + + /* 13 arguments */ + + + +{ +return ( cxyz * ( + (r1h1x*r1h1y - i1h1x*i1h1y)*i1h2z + (i1h1x*r1h1y + r1h1x*i1h1y)*r1h2z + + + (r1h1x*r1h1z - i1h1x*i1h1z)*i1h2y + (i1h1x*r1h1z + r1h1x*i1h1z)*r1h2y + + + (r1h1z*r1h1y - i1h1z*i1h1y)*i1h2x + (i1h1z*r1h1y + r1h1z*i1h1y)*r1h2x + )); +} + + /* the load functions */ + /* also renamed... */ +double +DFn2F1(double cxx, double cyy, double czz, double cxy, double cyz, double cxz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z) + + /* 12 variables */ + + +{ +double temp; + + temp = S2v2F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x) + + S2v2F1(cyy,r1h1y,i1h1y,r1h1y,i1h1y) + + S2v2F1(czz,r1h1z,i1h1z,r1h1z,i1h1z) + + S2v2F1(cxy,r1h1x,i1h1x,r1h1y,i1h1y) + + S2v2F1(cyz,r1h1y,i1h1y,r1h1z,i1h1z) + + S2v2F1(cxz,r1h1x,i1h1x,r1h1z,i1h1z); + + return(temp); +} + +double +DFi2F1(double cxx, double cyy, double czz, double cxy, double cyz, double cxz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z) + + /* 12 variables */ + + +{ +double temp; + + temp = S2i2F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x) + + S2i2F1(cyy,r1h1y,i1h1y,r1h1y,i1h1y) + + S2i2F1(czz,r1h1z,i1h1z,r1h1z,i1h1z) + + S2i2F1(cxy,r1h1x,i1h1x,r1h1y,i1h1y) + + S2i2F1(cyz,r1h1y,i1h1y,r1h1z,i1h1z) + + S2i2F1(cxz,r1h1x,i1h1x,r1h1z,i1h1z); + + return(temp); +} + +double +DFn3F1(double cxx, double cyy, double czz, double cxy, double cyz, double cxz, double cxxx, double cyyy, double czzz, double cxxy, double cxxz, double cxyy, double cyyz, double cxzz, double cyzz, double cxyz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z, double r2h11x, double i2h11x, double r2h11y, double i2h11y, double r2h11z, double i2h11z) + /* 28 args - 16 + 6 + 6 */ + + + +{ +double temp; + + temp = S2v3F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r2h11x,i2h11x,r2h11x,i2h11x) + +S2v3F1(cyy,r1h1y,i1h1y,r1h1y,i1h1y,r2h11y,i2h11y,r2h11y,i2h11y) + +S2v3F1(czz,r1h1z,i1h1z,r1h1z,i1h1z,r2h11z,i2h11z,r2h11z,i2h11z); + temp += + S2v3F1(cxy,r1h1x,i1h1x,r1h1y,i1h1y,r2h11x,i2h11x,r2h11y,i2h11y) + +S2v3F1(cyz,r1h1y,i1h1y,r1h1z,i1h1z,r2h11y,i2h11y,r2h11z,i2h11z) + +S2v3F1(cxz,r1h1x,i1h1x,r1h1z,i1h1z,r2h11x,i2h11x,r2h11z,i2h11z) + +S3v3F1(cxxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h1x,i1h1x); + temp += + S3v3F1(cyyy,r1h1y,i1h1y,r1h1y,i1h1y,r1h1y,i1h1y) + +S3v3F1(czzz,r1h1z,i1h1z,r1h1z,i1h1z,r1h1z,i1h1z) + +S3v3F1(cxxy,r1h1x,i1h1x,r1h1x,i1h1x,r1h1y,i1h1y) + +S3v3F1(cxxz,r1h1x,i1h1x,r1h1x,i1h1x,r1h1z,i1h1z) + +S3v3F1(cxyy,r1h1x,i1h1x,r1h1y,i1h1y,r1h1y,i1h1y); + temp += + S3v3F1(cyyz,r1h1y,i1h1y,r1h1y,i1h1y,r1h1z,i1h1z) + +S3v3F1(cxzz,r1h1x,i1h1x,r1h1z,i1h1z,r1h1z,i1h1z) + +S3v3F1(cyzz,r1h1y,i1h1y,r1h1z,i1h1z,r1h1z,i1h1z) + +S3v3F1(cxyz,r1h1x,i1h1x,r1h1y,i1h1y,r1h1z,i1h1z); + + return(temp); +} + +double +DFi3F1(double cxx, double cyy, double czz, double cxy, double cyz, double cxz, double cxxx, double cyyy, double czzz, double cxxy, double cxxz, double cxyy, double cyyz, double cxzz, double cyzz, double cxyz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z, double r2h11x, double i2h11x, double r2h11y, double i2h11y, double r2h11z, double i2h11z) + /* 28 args - 10 + 6 + 6 */ + + + +{ +double temp; + + temp = S2i3F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r2h11x,i2h11x,r2h11x,i2h11x) + +S2i3F1(cyy,r1h1y,i1h1y,r1h1y,i1h1y,r2h11y,i2h11y,r2h11y,i2h11y) + +S2i3F1(czz,r1h1z,i1h1z,r1h1z,i1h1z,r2h11z,i2h11z,r2h11z,i2h11z) + +S2i3F1(cxy,r1h1x,i1h1x,r1h1y,i1h1y,r2h11x,i2h11x,r2h11y,i2h11y); + temp += + S2i3F1(cyz,r1h1y,i1h1y,r1h1z,i1h1z,r2h11y,i2h11y,r2h11z,i2h11z) + +S2i3F1(cxz,r1h1x,i1h1x,r1h1z,i1h1z,r2h11x,i2h11x,r2h11z,i2h11z) + +S3i3F1(cxxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h1x,i1h1x) + +S3i3F1(cyyy,r1h1y,i1h1y,r1h1y,i1h1y,r1h1y,i1h1y); + temp += + S3i3F1(czzz,r1h1z,i1h1z,r1h1z,i1h1z,r1h1z,i1h1z) + +S3i3F1(cxxy,r1h1x,i1h1x,r1h1x,i1h1x,r1h1y,i1h1y) + +S3i3F1(cxxz,r1h1x,i1h1x,r1h1x,i1h1x,r1h1z,i1h1z) + +S3i3F1(cxyy,r1h1x,i1h1x,r1h1y,i1h1y,r1h1y,i1h1y); + temp += + S3i3F1(cyyz,r1h1y,i1h1y,r1h1y,i1h1y,r1h1z,i1h1z) + +S3i3F1(cxzz,r1h1x,i1h1x,r1h1z,i1h1z,r1h1z,i1h1z) + +S3i3F1(cyzz,r1h1y,i1h1y,r1h1z,i1h1z,r1h1z,i1h1z) + +S3i3F1(cxyz,r1h1x,i1h1x,r1h1y,i1h1y,r1h1z,i1h1z); + + return(temp); +} + +double +DFnF12(double cxx, double cyy, double czz, double cxy, double cyz, double cxz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z, double r1h2x, double i1h2x, double r1h2y, double i1h2y, double r1h2z, double i1h2z) + + /* 18 args - 6 + 6 + 6 */ + + + +{ +double temp; + + temp = S2vF12(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h2x,i1h2x,r1h2x,i1h2x) + +S2vF12(cyy,r1h1y,i1h1y,r1h1y,i1h1y,r1h2y,i1h2y,r1h2y,i1h2y) + +S2vF12(czz,r1h1z,i1h1z,r1h1z,i1h1z,r1h2z,i1h2z,r1h2z,i1h2z); + temp += + S2vF12(cxy,r1h1x,i1h1x,r1h1y,i1h1y,r1h2x,i1h2x,r1h2y,i1h2y) + +S2vF12(cyz,r1h1y,i1h1y,r1h1z,i1h1z,r1h2y,i1h2y,r1h2z,i1h2z) + +S2vF12(cxz,r1h1x,i1h1x,r1h1z,i1h1z,r1h2x,i1h2x,r1h2z,i1h2z); + + return(0.5*temp); +} + +double +DFiF12(double cxx, double cyy, double czz, double cxy, double cyz, double cxz, double r1h1x, double i1h1x, double r1h1y, double i1h1y, double r1h1z, double i1h1z, double r1h2x, double i1h2x, double r1h2y, double i1h2y, double r1h2z, double i1h2z) + + /* 18 args - 6 + 6 + 6 */ + + + +{ +double temp; + + temp = S2iF12(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h2x,i1h2x,r1h2x,i1h2x) + +S2iF12(cyy,r1h1y,i1h1y,r1h1y,i1h1y,r1h2y,i1h2y,r1h2y,i1h2y) + +S2iF12(czz,r1h1z,i1h1z,r1h1z,i1h1z,r1h2z,i1h2z,r1h2z,i1h2z); + temp += + S2iF12(cxy,r1h1x,i1h1x,r1h1y,i1h1y,r1h2x,i1h2x,r1h2y,i1h2y) + +S2iF12(cyz,r1h1y,i1h1y,r1h1z,i1h1z,r1h2y,i1h2y,r1h2z,i1h2z) + +S2iF12(cxz,r1h1x,i1h1x,r1h1z,i1h1z,r1h2x,i1h2x,r1h2z,i1h2z); + + return(temp*0.5); /* divided by two to scale down */ +} + +double +DFn2F12(DpassStr *p) + + /* 40 vars - 16 + 6 + 6 + 6 + 6 */ +/* + * a structure because a standard C compiler can handle only + * 32 variables. + * + */ +{ +double temp; + + temp = S2v2F12(p->cxx,p->r1h1x,p->i1h1x, + p->r1h1x,p->i1h1x, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x, + p->r2h11x,p->i2h11x, + p->r2h11x,p->i2h11x, + p->h2f1f2x,p->ih2f1f2x, + p->h2f1f2x,p->ih2f1f2x); + temp += + S2v2F12(p->cyy,p->r1h1y,p->i1h1y, + p->r1h1y,p->i1h1y, + p->r1h2y,p->i1h2y, + p->r1h2y,p->i1h2y, + p->r2h11y,p->i2h11y, + p->r2h11y,p->i2h11y, + p->h2f1f2y,p->ih2f1f2y, + p->h2f1f2y,p->ih2f1f2y); + temp += + S2v2F12(p->czz,p->r1h1z,p->i1h1z, + p->r1h1z,p->i1h1z, + p->r1h2z,p->i1h2z, + p->r1h2z,p->i1h2z, + p->r2h11z,p->i2h11z, + p->r2h11z,p->i2h11z, + p->h2f1f2z,p->ih2f1f2z, + p->h2f1f2z,p->ih2f1f2z); + temp += + S2v2F12(p->cxy,p->r1h1x,p->i1h1x, + p->r1h1y,p->i1h1y, + p->r1h2x,p->i1h2x, + p->r1h2y,p->i1h2y, + p->r2h11x,p->i2h11x, + p->r2h11y,p->i2h11y, + p->h2f1f2x,p->ih2f1f2x, + p->h2f1f2y,p->ih2f1f2y); + temp += + S2v2F12(p->cyz,p->r1h1y,p->i1h1y, + p->r1h1z,p->i1h1z, + p->r1h2y,p->i1h2y, + p->r1h2z,p->i1h2z, + p->r2h11y,p->i2h11y, + p->r2h11z,p->i2h11z, + p->h2f1f2y,p->ih2f1f2y, + p->h2f1f2z,p->ih2f1f2z); + temp += + S2v2F12(p->cxz,p->r1h1x,p->i1h1x, + p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2z,p->i1h2z, + p->r2h11x,p->i2h11x, + p->r2h11z,p->i2h11z, + p->h2f1f2x,p->ih2f1f2x, + p->h2f1f2z,p->ih2f1f2z); + temp += + S3v2F12(p->cxxx,p->r1h1x, + p->i1h1x,p->r1h1x,p->i1h1x,p->r1h1x,p->i1h1x, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x,p->r1h2x,p->i1h2x) + +S3v2F12(p->cyyy,p->r1h1y, + p->i1h1y,p->r1h1y,p->i1h1y,p->r1h1y,p->i1h1y, + p->r1h2y,p->i1h2y, + p->r1h2y,p->i1h2y,p->r1h2y,p->i1h2y); + temp += + S3v2F12(p->czzz,p->r1h1z, + p->i1h1z,p->r1h1z,p->i1h1z,p->r1h1z,p->i1h1z, + p->r1h2z,p->i1h2z, + p->r1h2z,p->i1h2z,p->r1h2z,p->i1h2z) + +S3v2F12(p->cxxy,p->r1h1x, + p->i1h1x,p->r1h1x,p->i1h1x,p->r1h1y,p->i1h1y, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x,p->r1h2y,p->i1h2y); + temp += + S3v2F12(p->cxxz,p->r1h1x, + p->i1h1x,p->r1h1x,p->i1h1x,p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x,p->r1h2z,p->i1h2z) + +S3v2F12(p->cxyy,p->r1h1x, + p->i1h1x,p->r1h1y,p->i1h1y,p->r1h1y,p->i1h1y, + p->r1h2x,p->i1h2x, + p->r1h2y,p->i1h2y,p->r1h2y,p->i1h2y); + temp += + S3v2F12(p->cyyz,p->r1h1y, + p->i1h1y,p->r1h1y,p->i1h1y,p->r1h1z,p->i1h1z, + p->r1h2y,p->i1h2y, + p->r1h2y,p->i1h2y,p->r1h2z,p->i1h2z) + +S3v2F12(p->cxzz,p->r1h1x, + p->i1h1x,p->r1h1z,p->i1h1z,p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2z,p->i1h2z,p->r1h2z,p->i1h2z); + temp += + S3v2F12(p->cyzz,p->r1h1y, + p->i1h1y,p->r1h1z,p->i1h1z,p->r1h1z,p->i1h1z, + p->r1h2y,p->i1h2y, + p->r1h2z,p->i1h2z,p->r1h2z,p->i1h2z) + +S3v2F12(p->cxyz,p->r1h1x, + p->i1h1x,p->r1h1y,p->i1h1y,p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2y,p->i1h2y,p->r1h2z,p->i1h2z); + + return(temp/3.); /* divided by 3 to get kernel (otherwise we get 3*kernel) */ +} + +double +DFi2F12(DpassStr *p) + + /* 40 vars - 16 + 6 + 6 + 6 + 6 */ +{ +double temp; + + temp = S2i2F12(p->cxx,p->r1h1x,p->i1h1x, + p->r1h1x,p->i1h1x, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x, + p->r2h11x,p->i2h11x, + p->r2h11x,p->i2h11x, + p->h2f1f2x,p->ih2f1f2x, + p->h2f1f2x,p->ih2f1f2x); + temp += + S2i2F12(p->cyy,p->r1h1y,p->i1h1y, + p->r1h1y,p->i1h1y, + p->r1h2y,p->i1h2y, + p->r1h2y,p->i1h2y, + p->r2h11y,p->i2h11y, + p->r2h11y,p->i2h11y, + p->h2f1f2y,p->ih2f1f2y, + p->h2f1f2y,p->ih2f1f2y); + temp += + S2i2F12(p->czz,p->r1h1z,p->i1h1z, + p->r1h1z,p->i1h1z, + p->r1h2z,p->i1h2z, + p->r1h2z,p->i1h2z, + p->r2h11z,p->i2h11z, + p->r2h11z,p->i2h11z, + p->h2f1f2z,p->ih2f1f2z, + p->h2f1f2z,p->ih2f1f2z); + temp += + S2i2F12(p->cxy,p->r1h1x,p->i1h1x, + p->r1h1y,p->i1h1y, + p->r1h2x,p->i1h2x, + p->r1h2y,p->i1h2y, + p->r2h11x,p->i2h11x, + p->r2h11y,p->i2h11y, + p->h2f1f2x,p->ih2f1f2x, + p->h2f1f2y,p->ih2f1f2y); + temp += + S2i2F12(p->cyz,p->r1h1y,p->i1h1y, + p->r1h1z,p->i1h1z, + p->r1h2y,p->i1h2y, + p->r1h2z,p->i1h2z, + p->r2h11y,p->i2h11y, + p->r2h11z,p->i2h11z, + p->h2f1f2y,p->ih2f1f2y, + p->h2f1f2z,p->ih2f1f2z); + temp += + S2i2F12(p->cxz,p->r1h1x,p->i1h1x, + p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2z,p->i1h2z, + p->r2h11x,p->i2h11x, + p->r2h11z,p->i2h11z, + p->h2f1f2x,p->ih2f1f2x, + p->h2f1f2z,p->ih2f1f2z); + temp += + S3i2F12(p->cxxx,p->r1h1x, + p->i1h1x,p->r1h1x,p->i1h1x,p->r1h1x,p->i1h1x, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x,p->r1h2x,p->i1h2x); + temp += + S3i2F12(p->cyyy,p->r1h1y, + p->i1h1y,p->r1h1y,p->i1h1y,p->r1h1y,p->i1h1y, + p->r1h2y,p->i1h2y, + p->r1h2y,p->i1h2y,p->r1h2y,p->i1h2y) + +S3i2F12(p->czzz,p->r1h1z, + p->i1h1z,p->r1h1z,p->i1h1z,p->r1h1z,p->i1h1z, + p->r1h2z,p->i1h2z, + p->r1h2z,p->i1h2z,p->r1h2z,p->i1h2z); + temp += + S3i2F12(p->cxxy,p->r1h1x, + p->i1h1x,p->r1h1x,p->i1h1x,p->r1h1y,p->i1h1y, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x,p->r1h2y,p->i1h2y) + +S3i2F12(p->cxxz,p->r1h1x, + p->i1h1x,p->r1h1x,p->i1h1x,p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2x,p->i1h2x,p->r1h2z,p->i1h2z); + temp += + S3i2F12(p->cxyy,p->r1h1x, + p->i1h1x,p->r1h1y,p->i1h1y,p->r1h1y,p->i1h1y, + p->r1h2x,p->i1h2x, + p->r1h2y,p->i1h2y,p->r1h2y,p->i1h2y) + +S3i2F12(p->cyyz,p->r1h1y, + p->i1h1y,p->r1h1y,p->i1h1y,p->r1h1z,p->i1h1z, + p->r1h2y,p->i1h2y, + p->r1h2y,p->i1h2y,p->r1h2z,p->i1h2z); + temp += + S3i2F12(p->cxzz,p->r1h1x, + p->i1h1x,p->r1h1z,p->i1h1z,p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2z,p->i1h2z,p->r1h2z,p->i1h2z); + temp += S3i2F12(p->cyzz,p->r1h1y, + p->i1h1y,p->r1h1z,p->i1h1z,p->r1h1z,p->i1h1z, + p->r1h2y,p->i1h2y, + p->r1h2z,p->i1h2z,p->r1h2z,p->i1h2z) + +S3i2F12(p->cxyz,p->r1h1x, + p->i1h1x,p->r1h1y,p->i1h1y,p->r1h1z,p->i1h1z, + p->r1h2x,p->i1h2x, + p->r1h2y,p->i1h2y,p->r1h2z,p->i1h2z); + + return(temp/3.); /* divided by 3 to get kernel (otherwise we get 3*kernel) */ +} + +double +D1n2F1(double cxx, double r1h1x, double i1h1x) + + /* 12 variables */ + + +{ +double temp; + + temp = S2v2F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x); + + return(temp); +} + +double +D1n3F1(double cxx, double cxxx, double r1h1x, double i1h1x, double r2h11x, double i2h11x) +{ +double temp; + + temp = S2v3F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r2h11x,i2h11x,r2h11x,i2h11x) + +S3v3F1(cxxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h1x,i1h1x); + + return(temp); +} + + +double +D1nF12(double cxx, double r1h1x, double i1h1x, double r1h2x, double i1h2x) + + /* 18 args - 6 + 6 + 6 */ + + + +{ +double temp; + + temp = S2vF12(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h2x,i1h2x,r1h2x,i1h2x); + + return(0.5*temp); +} + + +double +D1n2F12(double cxx, double cxxx, double r1h1x, double i1h1x, double r1h2x, double i1h2x, double r2h11x, double i2h11x, double h2f1f2x, double ih2f1f2x) + + /* 40 vars - 16 + 6 + 6 + 6 + 6 */ + + + + + +{ +double temp; + + temp = S2v2F12(cxx,r1h1x,i1h1x,r1h1x,i1h1x, + r1h2x,i1h2x,r1h2x,i1h2x, + r2h11x,i2h11x,r2h11x,i2h11x, + h2f1f2x,ih2f1f2x,h2f1f2x,ih2f1f2x) + +S3v2F12(cxxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h1x,i1h1x, + r1h2x,i1h2x,r1h2x,i1h2x,r1h2x,i1h2x); + + return(temp/3.); /* divided by 3 to get kernel (otherwise we get 3*kernel) */ +} + + +double +D1i2F1(double cxx, double r1h1x, double i1h1x) + + /* 12 variables */ + + +{ +double temp; + + temp = S2i2F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x); + + return(temp); +} + + +double +D1i3F1(double cxx, double cxxx, double r1h1x, double i1h1x, double r2h11x, double i2h11x) +{ +double temp; + + temp = S2i3F1(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r2h11x,i2h11x,r2h11x,i2h11x) + +S3i3F1(cxxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h1x,i1h1x); + + return(temp); +} + + +double +D1iF12(double cxx, double r1h1x, double i1h1x, double r1h2x, double i1h2x) + + /* 18 args - 6 + 6 + 6 */ + + + +{ +double temp; + + temp = S2iF12(cxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h2x,i1h2x,r1h2x,i1h2x); + + return(0.5*temp); +} + + +double +D1i2F12(double cxx, double cxxx, double r1h1x, double i1h1x, double r1h2x, double i1h2x, double r2h11x, double i2h11x, double h2f1f2x, double ih2f1f2x) + + /* 40 vars - 16 + 6 + 6 + 6 + 6 */ + + + + + +{ +double temp; + + temp = S2i2F12(cxx,r1h1x,i1h1x,r1h1x,i1h1x, + r1h2x,i1h2x,r1h2x,i1h2x, + r2h11x,i2h11x,r2h11x,i2h11x, + h2f1f2x,ih2f1f2x,h2f1f2x,ih2f1f2x) + +S3i2F12(cxxx,r1h1x,i1h1x,r1h1x,i1h1x,r1h1x,i1h1x, + r1h2x,i1h2x,r1h2x,i1h2x,r1h2x,i1h2x); + + return(temp/3.); /* divided by 3 to get kernel (otherwise we get 3*kernel) */ +} + diff --git a/src/analysis/dsetparm.c b/src/analysis/dsetparm.c new file mode 100644 index 000000000..fc96b0606 --- /dev/null +++ b/src/analysis/dsetparm.c @@ -0,0 +1,93 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" +#include "distodef.h" + + +/* ARGSUSED */ +int +DsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case D_START: + if (value->rValue <= 0.0) { + errMsg = copy("Frequency of 0 is invalid"); + ((DISTOAN*)anal)->DstartF1 = 1.0; + return(E_PARMVAL); + } + + ((DISTOAN*)anal)->DstartF1 = value->rValue; + break; + + case D_STOP: + if (value->rValue <= 0.0) { + errMsg = copy("Frequency of 0 is invalid"); + ((DISTOAN*)anal)->DstartF1 = 1.0; + return(E_PARMVAL); + } + + ((DISTOAN*)anal)->DstopF1 = value->rValue; + break; + + case D_STEPS: + ((DISTOAN*)anal)->DnumSteps = value->iValue; + break; + + case D_DEC: + ((DISTOAN*)anal)->DstepType = DECADE; + break; + + case D_OCT: + ((DISTOAN*)anal)->DstepType = OCTAVE; + break; + + case D_LIN: + ((DISTOAN*)anal)->DstepType = LINEAR; + break; + + case D_F2OVRF1: + ((DISTOAN*)anal)->Df2ovrF1 = value->rValue; + ((DISTOAN*)anal)->Df2wanted = 1; + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm Dparms[] = { + { "start", D_START, IF_SET|IF_REAL, "starting frequency" }, + { "stop", D_STOP, IF_SET|IF_REAL, "ending frequency" }, + { "numsteps", D_STEPS, IF_SET|IF_INTEGER, "number of frequencies" }, + { "dec", D_DEC, IF_SET|IF_FLAG, "step by decades" }, + { "oct", D_OCT, IF_SET|IF_FLAG, "step by octaves" }, + { "lin", D_LIN, IF_SET|IF_FLAG, "step linearly" }, + { "f2overf1", D_F2OVRF1, IF_SET|IF_REAL, "ratio of F2 to F1" }, +}; + +SPICEanalysis DISTOinfo = { + { + "DISTO", + "Small signal distortion analysis", + + sizeof(Dparms)/sizeof(IFparm), + Dparms + }, + sizeof(DISTOAN), + FREQUENCYDOMAIN, + 1, + DsetParm, + DaskQuest, + NULL, + DISTOan +}; diff --git a/src/analysis/naskq.c b/src/analysis/naskq.c new file mode 100644 index 000000000..9138819b7 --- /dev/null +++ b/src/analysis/naskq.c @@ -0,0 +1,76 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "noisedef.h" + + +int +NaskQuest(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case N_OUTPUT: + value->nValue = ((NOISEAN*)anal)->output; + break; + + case N_OUTREF: + value->nValue = ((NOISEAN*)anal)->outputRef; + break; + + case N_INPUT: + value->uValue = ((NOISEAN*)anal)->input; + break; + + case N_DEC: + if(((NOISEAN*)anal)->NstpType == DECADE) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case N_OCT: + if(((NOISEAN*)anal)->NstpType == OCTAVE) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case N_LIN: + if(((NOISEAN*)anal)->NstpType == LINEAR) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case N_STEPS: + value->iValue = ((NOISEAN*)anal)->NnumSteps; + break; + + case N_START: + value->rValue = ((NOISEAN*)anal)->NstartFreq; + break; + + case N_STOP: + value->rValue = ((NOISEAN*)anal)->NstopFreq; + break; + + case N_PTSPERSUM: + value->iValue = ((NOISEAN*)anal)->NStpsSm; + break; + + default: + return(E_BADPARM); + } + return(OK); +} + diff --git a/src/analysis/nevalsrc.c b/src/analysis/nevalsrc.c new file mode 100644 index 000000000..14fb6d952 --- /dev/null +++ b/src/analysis/nevalsrc.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +/* + * NevalSrc (noise, lnNoise, ckt, type, node1, node2, param) + * This routine evaluates the noise due to different physical + * phenomena. This includes the "shot" noise associated with dc + * currents in semiconductors and the "thermal" noise associated with + * resistance. Although semiconductors also display "flicker" (1/f) + * noise, the lack of a unified model requires us to handle it on a + * "case by case" basis. What we CAN provide, though, is the noise + * gain associated with the 1/f source. + */ + + +#include "ngspice.h" +#include "cktdefs.h" +#include "const.h" +#include "noisedef.h" + + +void +NevalSrc (double *noise, double *lnNoise, CKTcircuit *ckt, int type, int node1, int node2, double param) +{ + double realVal; + double imagVal; + double gain; + + realVal = *((ckt->CKTrhs) + node1) - *((ckt->CKTrhs) + node2); + imagVal = *((ckt->CKTirhs) + node1) - *((ckt->CKTirhs) + node2); + gain = (realVal*realVal) + (imagVal*imagVal); + switch (type) { + + case SHOTNOISE: + *noise = gain * 2 * CHARGE * fabs(param); /* param is the dc current in a semiconductor */ + *lnNoise = log( MAX(*noise,N_MINLOG) ); + break; + + case THERMNOISE: + *noise = gain * 4 * CONSTboltz * ckt->CKTtemp * param; /* param is the conductance of a resistor */ + *lnNoise = log( MAX(*noise,N_MINLOG) ); + break; + + case N_GAIN: + *noise = gain; + break; + + } +} diff --git a/src/analysis/ninteg.c b/src/analysis/ninteg.c new file mode 100644 index 000000000..b98832b02 --- /dev/null +++ b/src/analysis/ninteg.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +/* + * Nintegrate.c (noizDens, lnNdens, lnNlstDens, data) + * + * This subroutine evaluates the integral of the function + * + * EXPONENT + * NOISE = a * (FREQUENCY) + * + * given two points from the curve. If EXPONENT is relatively close + * to 0, the noise is simply multiplied by the change in frequency. + * If it isn't, a more complicated expression must be used. Note that + * EXPONENT = -1 gives a different equation than EXPONENT <> -1. + * Hence, the reason for the constant 'N_INTUSELOG'. + */ + +#include +#include "ngspice.h" +#include "noisedef.h" + + +double +Nintegrate (double noizDens, double lnNdens, double lnNlstDens, register Ndata *data) +{ + double exponent; + double a; + + exponent = (lnNdens - lnNlstDens) / data->delLnFreq; + if ( fabs(exponent) < N_INTFTHRESH ) { + return (noizDens * data->delFreq); + } else { + a = exp(lnNdens - exponent*data->lnFreq); + exponent += 1.0; + if (fabs(exponent) < N_INTUSELOG) { + return (a * (data->lnFreq - data->lnLastFreq)); + } else { + return (a * ((exp(exponent * data->lnFreq) - exp(exponent * data->lnLastFreq)) / + exponent)); + } + } +} diff --git a/src/analysis/noisean.c b/src/analysis/noisean.c new file mode 100644 index 000000000..184af4f50 --- /dev/null +++ b/src/analysis/noisean.c @@ -0,0 +1,286 @@ +/* Patch to noisean.c by Richard D. McRoberts. + * Patched with modifications from Weidong Lu (2000) + * There is a strange #ifdef near the end of the file. + */ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#define INT_NOISE /* Inserted to compile the ifdef'd code */ + +#include "ngspice.h" +#include +#include "acdefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "sperror.h" +#include "vsrc/vsrcdefs.h" +#include "isrc/isrcdefs.h" + +int +NOISEan (CKTcircuit *ckt, int restart) +{ + register Ndata *data; + double realVal; + double imagVal; + int error; + int posOutNode; + int negOutNode; + int code; + int step; + /* register CKTnode *node; WL but not used ???? */ + IFuid freqUid; + void *inst; /* PN fixes incompatible pointer type warning */ + double freqTol; /* tolerence parameter for finding final frequency; hack */ + + register NOISEAN *job = (NOISEAN*) (ckt->CKTcurJob); + static char *noacinput = "noise input source has no AC value"; + + posOutNode = ((CKTnode*) (job->output))->number; + negOutNode = ((CKTnode*) (job->outputRef))->number; + + /* see if the source specified is AC */ + inst = NULL; + code = CKTtypelook("Vsource"); + if (code != -1) { + error = CKTfndDev((void *)ckt,&code,&inst, + job->input, (void *)NULL, (IFuid)NULL); + if (!error && !((VSRCinstance *)inst)->VSRCacGiven) { + errMsg = MALLOC(strlen(noacinput)+1); + strcpy(errMsg,noacinput); + return (E_NOACINPUT); + } + } + + code = CKTtypelook("Isource"); + if (code != -1 && inst==NULL) { + error = CKTfndDev((void *)ckt,&code,&inst, + job->input, (void *)NULL,(IFuid)NULL); + if (error) { + /* XXX ??? */ + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "Noise input source %s not in circuit", + &job->input); + return (E_NOTFOUND); + } + if (!((ISRCinstance *)inst)->ISRCacGiven) { + errMsg = MALLOC(strlen(noacinput)+1); + strcpy(errMsg,noacinput); + return (E_NOACINPUT); + } + } + + if ( (job->NsavFstp == 0) || restart) { + switch (job->NstpType) { + + + case DECADE: + job->NfreqDelta = exp(log(10.0)/ + job->NnumSteps); + break; + + case OCTAVE: + job->NfreqDelta = exp(log(2.0)/ + job->NnumSteps); + break; + + case LINEAR: + job->NfreqDelta = (job->NstopFreq - + job->NstartFreq)/ + (job->NnumSteps+1); + break; + + default: + return(E_BADPARM); + } + + /* error = DCop(ckt); */ + error = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, + ckt->CKTdcMaxIter); + if (error) return(error); + + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; + error = CKTload(ckt); + if (error) return(error); + + data = (Ndata*)MALLOC(sizeof(Ndata)); + step = 0; + data->freq = job->NstartFreq; + data->outNoiz = 0.0; + data->inNoise = 0.0; + + /* the current front-end needs the namelist to be fully + declared before an OUTpBeginplot */ + + (*(SPfrontEnd->IFnewUid))((void *)ckt,&freqUid,(IFuid)NULL, + "frequency", UID_OTHER,(void **)NULL); + + data->numPlots = 0; /* we don't have any plots yet */ + error = CKTnoise(ckt,N_DENS,N_OPEN,data); + if (error) return(error); + + /* + * all names in the namelist have been declared. now start the + * plot + */ + + error = (*(SPfrontEnd->OUTpBeginPlot))(ckt,(void *)(ckt->CKTcurJob), + "Noise Spectral Density Curves - (V^2 or A^2)/Hz", + freqUid,IF_REAL,data->numPlots,data->namelist,IF_REAL, + &(data->NplotPtr)); + if (error) return(error); + + if (job->NstpType != LINEAR) { + (*(SPfrontEnd->OUTattributes))((void *)data->NplotPtr,NULL, + OUT_SCALE_LOG, NULL); + } + + } else { /* we must have paused before. pick up where we left off */ + step = job->NsavFstp; + switch (job->NstpType) { + + case DECADE: + case OCTAVE: + data->freq = job->NstartFreq * exp (step * + log (job->NfreqDelta)); + break; + + case LINEAR: + data->freq = job->NstartFreq + step * + job->NfreqDelta; + break; + + default: + return(E_BADPARM); + + } + job->NsavFstp = 0; + data->outNoiz = job->NsavOnoise; + data->inNoise = job->NsavInoise; + } + + switch (job->NstpType) { + case DECADE: + case OCTAVE: + freqTol = job->NfreqDelta * job->NstopFreq * ckt->CKTreltol; + break; + case LINEAR: + freqTol = job->NfreqDelta * ckt->CKTreltol; + break; + default: + return(E_BADPARM); + } + + data->lstFreq = data->freq; + + /* do the noise analysis over all frequencies */ + + while (data->freq <= job->NstopFreq + freqTol) { + if( (*(SPfrontEnd->IFpauseTest))() ) { + job->NsavFstp = step; /* save our results */ + job->NsavOnoise = data->outNoiz; /* up until now */ + job->NsavInoise = data->inNoise; + return (E_PAUSE); + } + ckt->CKTomega = 2.0 * M_PI * data->freq; + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEAC; + + /* + * solve the original AC system to get the transfer + * function between the input and output + */ + + NIacIter(ckt); + realVal = *((ckt->CKTrhsOld) + posOutNode) + - *((ckt->CKTrhsOld) + negOutNode); + imagVal = *((ckt->CKTirhsOld) + posOutNode) + - *((ckt->CKTirhsOld) + negOutNode); + data->GainSqInv = 1.0 / MAX(((realVal*realVal) + + (imagVal*imagVal)),N_MINGAIN); + data->lnGainInv = log(data->GainSqInv); + + /* set up a block of "common" data so we don't have to + * recalculate it for every device + */ + + data->delFreq = data->freq - data->lstFreq; + data->lnFreq = log(MAX(data->freq,N_MINLOG)); + data->lnLastFreq = log(MAX(data->lstFreq,N_MINLOG)); + data->delLnFreq = data->lnFreq - data->lnLastFreq; + + if ((job->NStpsSm != 0) && ((step % (job->NStpsSm)) == 0)) { + data->prtSummary = TRUE; + } else { + data->prtSummary = FALSE; + } + + /* + data->outNumber = 1; + */ + + data->outNumber = 0; + /* the frequency will NOT be stored in array[0] as before; instead, + * it will be given in refVal.rValue (see later) + */ + + NInzIter(ckt,posOutNode,negOutNode); /* solve the adjoint system */ + + /* now we use the adjoint system to calculate the noise + * contributions of each generator in the circuit + */ + + error = CKTnoise(ckt,N_DENS,N_CALC,data); + if (error) return(error); + data->lstFreq = data->freq; + + /* update the frequency */ + + switch (job->NstpType) { + + case DECADE: + case OCTAVE: + data->freq *= job->NfreqDelta; + break; + + case LINEAR: + data->freq += job->NfreqDelta; + break; + + default: + return(E_INTERN); + } + step++; + } + + error = CKTnoise(ckt,N_DENS,N_CLOSE,data); + if (error) return(error); + +#ifdef INT_NOISE /* WL */ + data->numPlots = 0; + data->outNumber = 0; + + if (job->NstartFreq != job->NstopFreq) { + error = CKTnoise(ckt,INT_NOIZ,N_OPEN,data); + + if (error) return(error); + + (*(SPfrontEnd->OUTpBeginPlot))(ckt,(void *)(ckt->CKTcurJob), + "Integrated Noise - V^2 or A^2", + (IFuid)NULL,(int)0,data->numPlots,data->namelist,IF_REAL, + &(data->NplotPtr)); + + error = CKTnoise(ckt,INT_NOIZ,N_CALC,data); + if (error) return(error); + + error = CKTnoise(ckt,INT_NOIZ,N_CLOSE,data); + if (error) return(error); + } +#endif + + FREE(data); + return(OK); +} diff --git a/src/analysis/nsetparm.c b/src/analysis/nsetparm.c new file mode 100644 index 000000000..d1e932178 --- /dev/null +++ b/src/analysis/nsetparm.c @@ -0,0 +1,106 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "noisedef.h" + + +int +NsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case N_OUTPUT: + ((NOISEAN*)anal)->output = value->nValue; + break; + + case N_OUTREF: + ((NOISEAN*)anal)->outputRef = value->nValue; + break; + + case N_INPUT: + ((NOISEAN*)anal)->input = value->uValue; + break; + + case N_DEC: + ((NOISEAN*)anal)->NstpType = DECADE; + break; + + case N_OCT: + ((NOISEAN*)anal)->NstpType = OCTAVE; + break; + + case N_LIN: + ((NOISEAN*)anal)->NstpType = LINEAR; + break; + + case N_STEPS: + ((NOISEAN*)anal)->NnumSteps = value->iValue; + break; + + case N_START: + if (value->rValue <= 0.0) { + errMsg = copy("Frequency of 0 is invalid"); + ((NOISEAN*)anal)->NstartFreq = 1.0; + return(E_PARMVAL); + } + + ((NOISEAN*)anal)->NstartFreq = value->rValue; + break; + + case N_STOP: + if (value->rValue <= 0.0) { + errMsg = copy("Frequency of 0 is invalid"); + ((NOISEAN*)anal)->NstartFreq = 1.0; + return(E_PARMVAL); + } + + ((NOISEAN*)anal)->NstopFreq = value->rValue; + break; + + case N_PTSPERSUM: + ((NOISEAN*)anal)->NStpsSm = value->iValue; + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm Nparms[] = { + { "output", N_OUTPUT, IF_SET|IF_STRING, "output noise summation node" }, + { "outputref", N_OUTREF, IF_SET|IF_STRING, "output noise reference node" }, + { "input", N_INPUT, IF_SET|IF_STRING, "input noise source" }, + { "dec", N_DEC, IF_SET|IF_FLAG, "step by decades" }, + { "oct", N_OCT, IF_SET|IF_FLAG, "step by octaves" }, + { "lin", N_LIN, IF_SET|IF_FLAG, "step linearly" }, + { "numsteps", N_STEPS, IF_SET|IF_INTEGER, "number of frequencies" }, + { "start", N_START, IF_SET|IF_REAL, "starting frequency" }, + { "stop", N_STOP, IF_SET|IF_REAL, "ending frequency" }, + { "ptspersum", N_PTSPERSUM, IF_SET|IF_INTEGER, "frequency points per summary report" } +}; + +SPICEanalysis NOISEinfo = { + { + "NOISE", + "Noise analysis", + + sizeof(Nparms)/sizeof(IFparm), + Nparms + }, + sizeof(NOISEAN), + FREQUENCYDOMAIN, + 1, + NsetParm, + NaskQuest, + NULL, + NOISEan +}; diff --git a/src/analysis/pzan.c b/src/analysis/pzan.c new file mode 100644 index 000000000..40e1dad7a --- /dev/null +++ b/src/analysis/pzan.c @@ -0,0 +1,197 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include +#include "complex.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "pzdefs.h" +#include "trandefs.h" /* only to get the 'mode' definitions */ +#include "sperror.h" + + +#define DEBUG if (0) + +/* ARGSUSED */ +int +PZan(CKTcircuit *ckt, int reset) +{ + PZAN *pzan = (PZAN *) ckt->CKTcurJob; + int error; + int numNames; + IFuid *nameList; + void *plot; + + error = PZinit(ckt); + if (error != OK) return error; + + /* Calculate small signal parameters at the operating point */ + error = CKTop(ckt, (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, + ckt->CKTdcMaxIter); + if (error) + return(error); + + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; + error = CKTload(ckt); /* Make sure that all small signal params are + * set */ + if (error) + return(error); + + if (ckt->CKTkeepOpInfo) { + /* Dump operating point. */ + error = CKTnames(ckt,&numNames,&nameList); + if(error) return(error); + error = (*(SPfrontEnd->OUTpBeginPlot))((void *)ckt, + (void*)ckt->CKTcurJob, "Distortion Operating Point", + (IFuid)NULL,IF_REAL,numNames,nameList, IF_REAL,&plot); + if(error) return(error); + CKTdump(ckt,(double)0,plot); + (*(SPfrontEnd->OUTendPlot))(plot); + } + + if (pzan->PZwhich & PZ_DO_POLES) { + error = CKTpzSetup(ckt, PZ_DO_POLES); + if (error != OK) + return error; + error = CKTpzFindZeros(ckt, &pzan->PZpoleList, &pzan->PZnPoles); + if (error != OK) + return(error); + } + + if (pzan->PZwhich & PZ_DO_ZEROS) { + error = CKTpzSetup(ckt, PZ_DO_ZEROS); + if (error != OK) + return error; + error = CKTpzFindZeros(ckt, &pzan->PZzeroList, &pzan->PZnZeros); + if (error != OK) + return(error); + } + + return PZpost(ckt); +} + +/* + * Perform error checking + */ + +int +PZinit(CKTcircuit *ckt) +{ + PZAN *pzan = (PZAN *) ckt->CKTcurJob; + int i; + + i = CKTtypelook("transmission line"); + if (i == -1) { + i = CKTtypelook("Tranline"); + if (i == -1) + i = CKTtypelook("LTRA"); + } + if (i != -1 && ckt->CKThead[i] != NULL) + ERROR(E_XMISSIONLINE, "Transmission lines not supported") + + pzan->PZpoleList = (PZtrial *) NULL; + pzan->PZzeroList = (PZtrial *) NULL; + pzan->PZnPoles = 0; + pzan->PZnZeros = 0; + + if (pzan->PZin_pos == pzan->PZin_neg) + ERROR(E_SHORT, "Input is shorted") + + if (pzan->PZout_pos == pzan->PZout_neg) + ERROR(E_SHORT, "Output is shorted") + + if (pzan->PZin_pos == pzan->PZout_pos + && pzan->PZin_neg == pzan->PZout_neg + && pzan->PZinput_type == PZ_IN_VOL) + ERROR(E_INISOUT, "Transfer function is unity") + else if (pzan->PZin_pos == pzan->PZout_neg + && pzan->PZin_neg == pzan->PZout_pos + && pzan->PZinput_type == PZ_IN_VOL) + ERROR(E_INISOUT, "Transfer function is -1") + + return(OK); +} + +/* + * PZpost Post-processing of the pole-zero analysis results + */ + +int +PZpost(CKTcircuit *ckt) +{ + PZAN *pzan = (PZAN *) ckt->CKTcurJob; + void *pzPlotPtr; /* the plot pointer for front end */ + IFcomplex *out_list; + IFvalue outData; /* output variable (points to out_list) */ + IFuid *namelist; + PZtrial *root; + char name[50]; + int i, j; + + namelist = (IFuid *) MALLOC((pzan->PZnPoles + + pzan->PZnZeros)*sizeof(IFuid)); + out_list = (IFcomplex *)MALLOC((pzan->PZnPoles + + pzan->PZnZeros)*sizeof(IFcomplex)); + + j = 0; + for (i = 0; i < pzan->PZnPoles; i++) { + sprintf(name, "pole(%-u)", i+1); + (*(SPfrontEnd->IFnewUid))(ckt,&(namelist[j++]),(IFuid)NULL, + name,UID_OTHER,(void **)NULL); + } + for (i = 0; i < pzan->PZnZeros; i++) { + sprintf(name, "zero(%-u)", i+1); + (*(SPfrontEnd->IFnewUid))(ckt,&(namelist[j++]),(IFuid)NULL, + name,UID_OTHER,(void **)NULL); + } + + (*SPfrontEnd->OUTpBeginPlot)(ckt, (void *)pzan, pzan->JOBname, + (IFuid)NULL, (int)0, pzan->PZnPoles + pzan->PZnZeros, namelist, + IF_COMPLEX, &pzPlotPtr); + + j = 0; + if (pzan->PZnPoles > 0) { + for (root = pzan->PZpoleList; root != NULL; root = root->next) { + for (i = 0; i < root->multiplicity; i++) { + out_list[j].real = root->s.real; + out_list[j].imag = root->s.imag; + j += 1; + if (root->s.imag != 0.0) { + out_list[j].real = root->s.real; + out_list[j].imag = -root->s.imag; + j += 1; + } + } + DEBUG printf("LIST pole: (%g,%g) x %d\n", + root->s.real, root->s.imag, root->multiplicity); + } + } + + if (pzan->PZnZeros > 0) { + for (root = pzan->PZzeroList; root != NULL; root = root->next) { + for (i = 0; i < root->multiplicity; i++) { + out_list[j].real = root->s.real; + out_list[j].imag = root->s.imag; + j += 1; + if (root->s.imag != 0.0) { + out_list[j].real = root->s.real; + out_list[j].imag = -root->s.imag; + j += 1; + } + } + DEBUG printf("LIST zero: (%g,%g) x %d\n", + root->s.real, root->s.imag, root->multiplicity); + } + } + + outData.v.numValue = pzan->PZnPoles + pzan->PZnZeros; + outData.v.vec.cVec = out_list; + + (*SPfrontEnd->OUTpData)(pzPlotPtr, (IFvalue *) 0, &outData); + (*(SPfrontEnd->OUTendPlot))(pzPlotPtr); + + return(OK); +} diff --git a/src/analysis/pzaskq.c b/src/analysis/pzaskq.c new file mode 100644 index 000000000..c1f41c42d --- /dev/null +++ b/src/analysis/pzaskq.c @@ -0,0 +1,80 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "pzdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +PZaskQuest(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case PZ_NODEI: + value->nValue = (IFnode)CKTnum2nod(ckt,((PZAN*)anal)->PZin_pos); + break; + + case PZ_NODEG: + value->nValue = (IFnode)CKTnum2nod(ckt,((PZAN*)anal)->PZin_neg); + break; + + case PZ_NODEJ: + value->nValue = (IFnode)CKTnum2nod(ckt,((PZAN*)anal)->PZout_pos); + break; + + case PZ_NODEK: + value->nValue = (IFnode)CKTnum2nod(ckt,((PZAN*)anal)->PZout_neg); + break; + + case PZ_V: + if( ((PZAN*)anal)->PZinput_type == PZ_IN_VOL) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case PZ_I: + if( ((PZAN*)anal)->PZinput_type == PZ_IN_CUR) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case PZ_POL: + if( ((PZAN*)anal)->PZwhich == PZ_DO_POLES) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case PZ_ZER: + if( ((PZAN*)anal)->PZwhich == PZ_DO_ZEROS) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + case PZ_PZ: + if( ((PZAN*)anal)->PZwhich == (PZ_DO_POLES | PZ_DO_ZEROS)) { + value->iValue=1; + } else { + value->iValue=0; + } + break; + + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/analysis/pzsetp.c b/src/analysis/pzsetp.c new file mode 100644 index 000000000..6e2822542 --- /dev/null +++ b/src/analysis/pzsetp.c @@ -0,0 +1,100 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "pzdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +PZsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case PZ_NODEI: + ((PZAN*)anal)->PZin_pos = ((CKTnode*)value->nValue)->number; + break; + + case PZ_NODEG: + ((PZAN*)anal)->PZin_neg = ((CKTnode*)value->nValue)->number; + break; + + case PZ_NODEJ: + ((PZAN*)anal)->PZout_pos = ((CKTnode*)value->nValue)->number; + break; + + case PZ_NODEK: + ((PZAN*)anal)->PZout_neg = ((CKTnode*)value->nValue)->number; + break; + + case PZ_V: + if(value->iValue) { + ((PZAN*)anal)->PZinput_type = PZ_IN_VOL; + } + break; + + case PZ_I: + if(value->iValue) { + ((PZAN*)anal)->PZinput_type = PZ_IN_CUR; + } + break; + + case PZ_POL: + if(value->iValue) { + ((PZAN*)anal)->PZwhich = PZ_DO_POLES; + } + break; + + case PZ_ZER: + if(value->iValue) { + ((PZAN*)anal)->PZwhich = PZ_DO_ZEROS; + } + break; + + case PZ_PZ: + if(value->iValue) { + ((PZAN*)anal)->PZwhich = PZ_DO_POLES | PZ_DO_ZEROS; + } + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm PZparms[] = { + { "nodei", PZ_NODEI, IF_SET|IF_ASK|IF_NODE, "" }, + { "nodeg", PZ_NODEG, IF_SET|IF_ASK|IF_NODE, "" }, + { "nodej", PZ_NODEJ, IF_SET|IF_ASK|IF_NODE, "" }, + { "nodek", PZ_NODEK, IF_SET|IF_ASK|IF_NODE, "" }, + { "vol", PZ_V, IF_SET|IF_ASK|IF_FLAG, "" }, + { "cur", PZ_I, IF_SET|IF_ASK|IF_FLAG, "" }, + { "pol", PZ_POL, IF_SET|IF_ASK|IF_FLAG, "" }, + { "zer", PZ_ZER, IF_SET|IF_ASK|IF_FLAG, "" }, + { "pz", PZ_PZ, IF_SET|IF_ASK|IF_FLAG, "" } +}; + +SPICEanalysis PZinfo = { + { + "PZ", + "pole-zero analysis", + + sizeof(PZparms)/sizeof(IFparm), + PZparms + }, + sizeof(PZAN), + NODOMAIN, + 1, + PZsetParm, + PZaskQuest, + NULL, + PZan +}; diff --git a/src/analysis/sensaskq.c b/src/analysis/sensaskq.c new file mode 100644 index 000000000..caff46c98 --- /dev/null +++ b/src/analysis/sensaskq.c @@ -0,0 +1,59 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" +#include "sensdefs.h" + + +/* ARGSUSED */ +int +SENSask(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + SENS_AN *sinfo = (SENS_AN *) anal; + + switch (which) { + + case SENS_START: + value->rValue = sinfo->start_freq; + break; + + case SENS_STOP: + value->rValue = sinfo->stop_freq; + break; + + case SENS_STEPS: + value->iValue = sinfo->n_freq_steps; + break; + + case SENS_DEC: + case SENS_OCT: + case SENS_LIN: + case SENS_DC: + value->iValue = sinfo->step_type == which; + break; + + case SENS_DEFTOL: + sinfo->deftol = value->rValue; + break; + + case SENS_DEFPERTURB: + value->rValue = sinfo->defperturb; + break; + +#ifdef notdef + case SENS_TYPE: + value->sValue = sinfo->type; + break; +#endif + + default: + return(E_BADPARM); + } + return(OK); +} + diff --git a/src/analysis/senssetp.c b/src/analysis/senssetp.c new file mode 100644 index 000000000..879e4c06b --- /dev/null +++ b/src/analysis/senssetp.c @@ -0,0 +1,145 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "cktdefs.h" +#include "sensdefs.h" + + +/* ARGSUSED */ +int +SENSsetParam(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + SENS_AN *sinfo = (SENS_AN *) anal; + + switch(which) { + + case SENS_POS: + sinfo->output_pos = (CKTnode *) value->nValue; + sinfo->output_neg = NULL; + sinfo->output_volt = 1; + sinfo->step_type = SENS_DC; + break; + + case SENS_NEG: + sinfo->output_neg = (CKTnode *) value->nValue; + break; + + case SENS_SRC: + sinfo->output_src = value->uValue; + sinfo->output_volt = 0; + sinfo->step_type = SENS_DC; + break; + + case SENS_NAME: + sinfo->output_name = value->sValue; + break; + + case SENS_START: + sinfo->start_freq = value->rValue; + break; + + case SENS_STOP: + sinfo->stop_freq = value->rValue; + break; + + case SENS_STEPS: + sinfo->n_freq_steps = value->iValue; + break; + + case SENS_DEC: + sinfo->step_type = SENS_DECADE; + break; + + case SENS_OCT: + sinfo->step_type = SENS_OCTAVE; + break; + + case SENS_LIN: + sinfo->step_type = SENS_LINEAR; + break; + + case SENS_DC: + sinfo->step_type = SENS_DC; + break; + + case SENS_DEFTOL: + sinfo->deftol = value->rValue; + break; + + case SENS_DEFPERTURB: + sinfo->defperturb = value->rValue; + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm SENSparms[] = { + /* TF like parameters */ + { "outpos", SENS_POS, IF_SET|IF_ASK|IF_NODE, "output positive node" }, + { "outneg", SENS_NEG, IF_SET|IF_ASK|IF_NODE, "output negative node" }, + { "outsrc", SENS_SRC, IF_SET|IF_ASK|IF_INSTANCE, "output current" }, + { "outname", SENS_NAME, IF_SET|IF_ASK|IF_STRING, + "Name of output variable" }, + + /* AC parameters */ + { "start", SENS_START, IF_SET|IF_ASK|IF_REAL, "starting frequency" }, + { "stop", SENS_STOP, IF_SET|IF_ASK|IF_REAL, "ending frequency" }, + { "numsteps", SENS_STEPS,IF_SET|IF_ASK|IF_INTEGER, + "number of frequencies"}, + { "dec", SENS_DEC, IF_SET|IF_FLAG, "step by decades" }, + { "oct", SENS_OCT, IF_SET|IF_FLAG, "step by octaves" }, + { "lin", SENS_LIN, IF_SET|IF_FLAG, "step linearly" }, + { "dc", SENS_DC, IF_SET|IF_FLAG, "analysis at DC" }, + +#ifdef notdef + /* Future coding */ + /* perturbation limits */ + /* defaults for the analysis */ + { "deftol", SENS_DEFTOL, IF_SET|IF_REAL, "default tolerance" }, + { "defperturb", SENS_DEFPERT, IF_SET|IF_REAL, "default perterbation" }, + { "type", SENS_TYPE, IF_SET|IF_INTEGER, + "describe device, model or element parameters" }, + + { "device", SENS_DEVICE, IF_STRING, "type of model or device" }, + { "devdeftol", SENS_DEVDEFTOL, IF_SET|IF_REAL, + "default tolerance (device type)" }, + { "devdefperturb",SENS_DEVDEFPERT, IF_SET|IF_REAL, + "default perturbation (device type)" }, + { "moddeftol", SENS_DEVDEFTOL, IF_SET|IF_REAL, + "default tolerance (model)" }, + { "moddefperturb",SENS_DEVDEFPERT, IF_SET|IF_REAL, + "default perturbation (model)" }, + + /*{ "name", SENS_NAME, IF_SET|IF_STRING, + "name of model or element" }, */ + { "param", SENS_PARAM,IF_SET|IF_STRING, "name of parameter" }, + { "tol", SENS_TOL, IF_SET|IF_REAL, "tolerance" }, + { "perturb", SENS_PERT, IF_SET|IF_REAL, "perturbation" } +#endif + +}; + +SPICEanalysis SENSinfo = { + { + "SENS", + "Sensitivity analysis", + sizeof(SENSparms)/sizeof(IFparm), + SENSparms + }, + sizeof(SENS_AN), + FREQUENCYDOMAIN, + 1, + SENSsetParam, + SENSask, + NULL, + sens_sens +}; diff --git a/src/analysis/tfanal.c b/src/analysis/tfanal.c new file mode 100644 index 000000000..8effddfa1 --- /dev/null +++ b/src/analysis/tfanal.c @@ -0,0 +1,186 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +/* subroutine to do DC Transfer Function analysis */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "smpdefs.h" +#include "tfdefs.h" + + +/* ARGSUSED */ +int +TFanal(CKTcircuit *ckt, int restart) + + /* forced restart flag */ +{ + int size; + int insrc,outsrc; + double outputs[3]; + IFvalue outdata; /* structure for output data vector, will point to + * outputs vector above */ + IFvalue refval; /* structure for 'reference' value (not used here) */ + int error; + int converged; + register int i; + void *plotptr; /* pointer to out plot */ + void *ptr = NULL; + IFuid uids[3]; + int Itype; + int Vtype; + char *name; +#define tfuid (uids[0]) /* unique id for the transfer function output */ +#define inuid (uids[1]) /* unique id for the transfer function input imp. */ +#define outuid (uids[2]) /* unique id for the transfer function out. imp. */ + + + /* first, find the operating point */ + converged = CKTop(ckt, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, + (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, + ckt->CKTdcMaxIter); + +#ifdef notdef + /* don't need this any more since newconvtest leaves the matrix factored */ + ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT; + error = CKTload(ckt); + if(error) return(error); + + error=SMPluFac(ckt->CKTmatrix,ckt->CKTpivotAbsTol,ckt->CKTdiagGmin); + if(error) return(error); +#endif /* notdef */ + + Itype = CKTtypelook("Isource"); + Vtype = CKTtypelook("Vsource"); + if(Itype != -1) { + error = CKTfndDev((void*)ckt,&Itype,&ptr, + ((TFan*)ckt->CKTcurJob)->TFinSrc, (void *)NULL,(IFuid)NULL); + if(error ==0) { + ((TFan*)ckt->CKTcurJob)->TFinIsI = 1; + ((TFan*)ckt->CKTcurJob)->TFinIsV = 0; + } else { + ptr = NULL; + } + } + + if( (Vtype != -1) && (ptr==NULL) ) { + error = CKTfndDev((void*)ckt,&Vtype,&ptr, + ((TFan*)ckt->CKTcurJob)->TFinSrc, (void *)NULL, + (IFuid)NULL); + ((TFan*)ckt->CKTcurJob)->TFinIsV = 1; + ((TFan*)ckt->CKTcurJob)->TFinIsI = 0; + if(error !=0) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "Transfer function source %s not in circuit", + &(((TFan*)ckt->CKTcurJob)->TFinSrc)); + ((TFan*)ckt->CKTcurJob)->TFinIsV = 0; + return(E_NOTFOUND); + } + } + + size = SMPmatSize(ckt->CKTmatrix); + for(i=0;i<=size;i++) { + ckt->CKTrhs[i] = 0; + } + + if(((TFan*)ckt->CKTcurJob)->TFinIsI) { + ckt->CKTrhs[((GENinstance*)ptr)->GENnode1] -= 1; + ckt->CKTrhs[((GENinstance*)ptr)->GENnode2] += 1; + } else { + insrc = CKTfndBranch(ckt,((TFan*)ckt->CKTcurJob)->TFinSrc); + ckt->CKTrhs[insrc] += 1; + } + + + SMPsolve(ckt->CKTmatrix,ckt->CKTrhs,ckt->CKTrhsSpare); + ckt->CKTrhs[0]=0; + + /* make a UID for the transfer function output */ + (*(SPfrontEnd->IFnewUid))(ckt,&tfuid,(IFuid)NULL,"Transfer_function", + UID_OTHER,(void **)NULL); + + /* make a UID for the input impedance */ + (*(SPfrontEnd->IFnewUid))(ckt,&inuid,((TFan*)ckt->CKTcurJob)->TFinSrc, + "Input_impedance", UID_OTHER,(void **)NULL); + + /* make a UID for the output impedance */ + if(((TFan*)ckt->CKTcurJob)->TFoutIsI) { + (*(SPfrontEnd->IFnewUid))(ckt,&outuid,((TFan*)ckt->CKTcurJob)->TFoutSrc + ,"Output_impedance", UID_OTHER,(void **)NULL); + } else { + name = (char *) + MALLOC(sizeof(char)*(strlen(((TFan*)ckt->CKTcurJob)->TFoutName)+22)); + (void)sprintf(name,"output_impedance_at_%s", + ((TFan*)ckt->CKTcurJob)->TFoutName); + (*(SPfrontEnd->IFnewUid))(ckt,&outuid,(IFuid)NULL, + name, UID_OTHER,(void **)NULL); + } + + error = (*(SPfrontEnd->OUTpBeginPlot))(ckt,(void *)(ckt->CKTcurJob), + ((TFan*)(ckt->CKTcurJob))->JOBname,(IFuid)NULL,(int)0,3, + uids,IF_REAL,&plotptr); + if(error) return(error); + + /*find transfer function */ + if(((TFan*)ckt->CKTcurJob)->TFoutIsV) { + outputs[0] = ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutPos->number] - + ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutNeg->number] ; + } else { + outsrc = CKTfndBranch(ckt,((TFan*)ckt->CKTcurJob)->TFoutSrc); + outputs[0] = ckt->CKTrhs[outsrc]; + } + + /* now for input resistance */ + if(((TFan*)ckt->CKTcurJob)->TFinIsI) { + outputs[1] = ckt->CKTrhs[((GENinstance*)ptr)->GENnode2] - + ckt->CKTrhs[((GENinstance*)ptr)->GENnode1]; + } else { + if(fabs(ckt->CKTrhs[insrc])<1e-20) { + outputs[1]=1e20; + } else { + outputs[1] = -1/ckt->CKTrhs[insrc]; + } + } + + if(((TFan*)ckt->CKTcurJob)->TFoutIsI && + (((TFan*)ckt->CKTcurJob)->TFoutSrc == + ((TFan*)ckt->CKTcurJob)->TFinSrc)) { + outputs[2]=outputs[1]; + goto done; + /* no need to compute output resistance when it is the same as + the input */ + } + /* now for output resistance */ + for(i=0;i<=size;i++) { + ckt->CKTrhs[i] = 0; + } + if(((TFan*)ckt->CKTcurJob)->TFoutIsV) { + ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutPos->number] -= 1; + ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutNeg->number] += 1; + } else { + ckt->CKTrhs[outsrc] += 1; + } + SMPsolve(ckt->CKTmatrix,ckt->CKTrhs,ckt->CKTrhsSpare); + ckt->CKTrhs[0]=0; + if(((TFan*)ckt->CKTcurJob)->TFoutIsV) { + outputs[2]= ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutNeg->number] - + ckt->CKTrhs[((TFan*)ckt->CKTcurJob)->TFoutPos->number]; + } else { + outputs[2] = 1/MAX(1e-20,ckt->CKTrhs[outsrc]); + } +done: + outdata.v.numValue=3; + outdata.v.vec.rVec=outputs; + refval.rValue = 0; + (*(SPfrontEnd->OUTpData))(plotptr,&refval,&outdata); + (*(SPfrontEnd->OUTendPlot))(plotptr); + return(OK); +} + + diff --git a/src/analysis/tfaskq.c b/src/analysis/tfaskq.c new file mode 100644 index 000000000..1a51786e2 --- /dev/null +++ b/src/analysis/tfaskq.c @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "trcvdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +TFaskQuest(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + default: + break; + } + return(E_BADPARM); +} + diff --git a/src/analysis/tfsetp.c b/src/analysis/tfsetp.c new file mode 100644 index 000000000..411d78829 --- /dev/null +++ b/src/analysis/tfsetp.c @@ -0,0 +1,72 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "tfdefs.h" +#include "cktdefs.h" + + +/* ARGSUSED */ +int +TFsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case TF_OUTPOS: + ((TFan *)anal)->TFoutPos = (CKTnode *)value->nValue; + ((TFan *)anal)->TFoutIsV = TRUE; + ((TFan *)anal)->TFoutIsI = FALSE; + break; + case TF_OUTNEG: + ((TFan *)anal)->TFoutNeg = (CKTnode *)value->nValue; + ((TFan *)anal)->TFoutIsV = TRUE; + ((TFan *)anal)->TFoutIsI = FALSE; + break; + case TF_OUTNAME: + ((TFan *)anal)->TFoutName = value->sValue; + break; + case TF_OUTSRC: + ((TFan *)anal)->TFoutSrc = value->uValue; + ((TFan *)anal)->TFoutIsV = FALSE; + ((TFan *)anal)->TFoutIsI = TRUE; + break; + case TF_INSRC: + ((TFan *)anal)->TFinSrc = value->uValue; + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm TFparms[] = { + { "outpos", TF_OUTPOS, IF_SET|IF_NODE, "Positive output node" }, + { "outneg", TF_OUTNEG, IF_SET|IF_NODE, "Negative output node" }, + { "outname", TF_OUTNAME, IF_SET|IF_STRING,"Name of output variable"}, + { "outsrc", TF_OUTSRC, IF_SET|IF_INSTANCE, "Output source" }, + { "insrc", TF_INSRC, IF_SET|IF_INSTANCE, "Input source" } +}; + +SPICEanalysis TFinfo = { + { + "TF", + "transfer function analysis", + + sizeof(TFparms)/sizeof(IFparm), + TFparms + }, + sizeof(TFan), + NODOMAIN, + 0, + TFsetParm, + TFaskQuest, + NULL, + TFanal +}; diff --git a/src/analysis/tranaskq.c b/src/analysis/tranaskq.c new file mode 100644 index 000000000..2f2bd7b2c --- /dev/null +++ b/src/analysis/tranaskq.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "trandefs.h" +#include "cktdefs.h" + +/* ARGSUSED */ +int +TRANaskQuest(CKTcircuit *ckt, void *anal, int which,IFvalue *value) +{ + switch(which) { + + case TRAN_TSTOP: + value->rValue = ((TRANan *)anal)->TRANfinalTime; + break; + case TRAN_TSTEP: + value->rValue = ((TRANan *)anal)->TRANstep; + break; + case TRAN_TSTART: + value->rValue = ((TRANan *)anal)->TRANinitTime; + break; + case TRAN_TMAX: + value->rValue = ((TRANan *)anal)->TRANmaxStep; + break; + case TRAN_UIC: + if(((TRANan *)anal)->TRANmode & MODEUIC) { + value->iValue = 1; + } else { + value->iValue = 0; + } + break; + + + default: + return(E_BADPARM); + } + return(OK); +} + diff --git a/src/analysis/traninit.c b/src/analysis/traninit.c new file mode 100644 index 000000000..b91a02859 --- /dev/null +++ b/src/analysis/traninit.c @@ -0,0 +1,28 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "trandefs.h" +#include "iferrmsg.h" + +/* + * this used to be in setup, but we need it here now + * (must be done after mode is set as below) + */ + +int TRANinit(CKTcircuit *ckt, JOB *job) +{ + ckt->CKTfinalTime = ((TRANan*)job)->TRANfinalTime; + ckt->CKTstep = ((TRANan*)job)->TRANstep; + ckt->CKTinitTime = ((TRANan*)job)->TRANinitTime; + ckt->CKTmaxStep = ((TRANan*)job)->TRANmaxStep; + if(ckt->CKTmaxStep == 0) { + ckt->CKTmaxStep = (ckt->CKTfinalTime-ckt->CKTinitTime)/50; + } + ckt->CKTdelmin = 1e-9*ckt->CKTmaxStep; /* XXX */ + ckt->CKTmode = ((TRANan*)job)->TRANmode; + + return OK; +} diff --git a/src/analysis/transetp.c b/src/analysis/transetp.c new file mode 100644 index 000000000..1c81b851a --- /dev/null +++ b/src/analysis/transetp.c @@ -0,0 +1,67 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "trandefs.h" +#include "cktdefs.h" + +/* ARGSUSED */ +int +TRANsetParm(CKTcircuit *ckt, void *anal, int which, IFvalue *value) +{ + switch(which) { + + case TRAN_TSTOP: + ((TRANan *)anal)->TRANfinalTime = value->rValue; + break; + case TRAN_TSTEP: + ((TRANan *)anal)->TRANstep = value->rValue; + break; + case TRAN_TSTART: + ((TRANan *)anal)->TRANinitTime = value->rValue; + break; + case TRAN_TMAX: + ((TRANan *)anal)->TRANmaxStep = value->rValue; + break; + case TRAN_UIC: + if(value->iValue) { + ((TRANan *)anal)->TRANmode |= MODEUIC; + } + break; + + default: + return(E_BADPARM); + } + return(OK); +} + + +static IFparm TRANparms[] = { + { "tstart", TRAN_TSTART, IF_SET|IF_REAL, "starting time" }, + { "tstop", TRAN_TSTOP, IF_SET|IF_REAL, "ending time" }, + { "tstep", TRAN_TSTEP, IF_SET|IF_REAL, "time step" }, + { "tmax", TRAN_TMAX, IF_SET|IF_REAL, "maximum time step" }, + { "uic", TRAN_UIC, IF_SET|IF_FLAG, "use initial conditions" }, +}; + +SPICEanalysis TRANinfo = { + { + "TRAN", + "Transient analysis", + + sizeof(TRANparms)/sizeof(IFparm), + TRANparms + }, + sizeof(TRANan), + TIMEDOMAIN, + 1, + TRANsetParm, + TRANaskQuest, + TRANinit, + DCtran +}; diff --git a/src/circuit/ChangeLog b/src/circuit/ChangeLog new file mode 100644 index 000000000..bc6d059bf --- /dev/null +++ b/src/circuit/ChangeLog @@ -0,0 +1,85 @@ +2000-04-04 Paolo Nenzi + + * inpfindl.c: Modified the file for BSIM4 and future extensions to + BSIM5 and BSIM6. I have merged the inpfindl.c coming + with the BSIM4 distribution. + * inp2r.c: Added acval=val to initialize the acval parameter to + a significative value. Hope does not brak anything. + + + * inp2m.c: Added BSIM4 support. + + * inpdomod.c: Added support for BSIM4 device model. + +2000-03-28 Paolo Nenzi + + * ptfuncs.c: I have applied a couple of patches by GLAO Dezay. He noted + that PTln, PTlog and PTsqrt returned non consistent values + if the argument was out of domain. If arg <0 they returned + f(-arg). The patch is masked by #ifdef EXPERIMENTAL_CODE. + You have to remove these lines or #define it to compile + Dezai's patched code. + +2000-03-11 Paolo Nenzi + * inp2dot.c: Applied Glao Dezai patch, adding which = -1 in the .sens code. + +2000-01-17 Paolo Nenzi + * inp2m.c, inpdomod.c: Inserted code to dupport BSIM3V1 model as + level 49. + +2000-01-16 Paolo Nenzi + + * inp2r.c: Modified resistor code. Added ac value (ala HSPICE), from + Serban Popescu contributed sources. + +2000-01-15 Paolo Nenzi + + * inp2m.c, inpdomod.c : Inserted code to support BSIM3V2 model as + level 50. + +1999-12-20 Paolo Nenzi + + * inpgtok.c, inpptree.c: Bug Fix + Bug: Scale factors (eg. m, k, meg, etc.) for constants in arbitrary + source (b devices) are not recognized. + Fix: Changes to inpgtok.c and inpptree.c, as supplied by Berkeley. + NOTE: These changes were orignally supplied to me as a patch to 3e2 + by Beorn Johnson who was maintaining Spice a while back. They were + supposed to have been incorporated in Spice 3f2 at that time, but are + missing from the 3f5 version that I recently got from Berkeley. I + don't know if they were removed in ignorance or because of a conflict + with some other requirement, but they appear to work in 3f5. ALSO, + the fix for 3e2 had many more changes, all of which remain in 3f5, so + don't try these alone on 3e2. + +1999-09-07 Arno + + * inpsymt.c: removed unused function prototype for local_remove(). + + * sperror.c: removed unused variable `notempty' + +1999-09-05 Emmanuel Rouat + + * inpptree.c (PTdifferentiate): removed superfluous argument + to 2 occurences of function mkf + + * *.c: put all function prototypes in inp.h + +1999-08-28 Emmanuel Rouat + + * Removed all #includes of misc.h and util.h (now in spice.h) + +1999-08-24 Paolo Nenzi + + * inpdomod.c: added level check for ps model, jfet level 2 + + * inp2j.c: added code for ps model, jfet level 2 +1999-08-08 Emmanuel Rouat + + * inp2dot.c (INP2dot):changed HAS_SENSE2 in WANT_SENSE2 + +1999-08-03 Emmanuel Rouat + + * ptfuncs.c: changed HAS_ATRIGH to HAVE_ACOSH,HAVE_ASINH and + HAVE_ATANH provided in config.h + diff --git a/src/circuit/Makefile.am b/src/circuit/Makefile.am new file mode 100644 index 000000000..f05d7645a --- /dev/null +++ b/src/circuit/Makefile.am @@ -0,0 +1,64 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libinp.a + +libinp_a_SOURCES = \ + ifeval.c \ + ifnewuid.c \ + inp2b.c \ + inp2c.c \ + inp2d.c \ + inp2dot.c \ + inp2e.c \ + inp2f.c \ + inp2g.c \ + inp2h.c \ + inp2i.c \ + inp2j.c \ + inp2k.c \ + inp2l.c \ + inp2m.c \ + inp2o.c \ + inp2q.c \ + inp2r.c \ + inp2s.c \ + inp2t.c \ + inp2u.c \ + inp2v.c \ + inp2w.c \ + inp2z.c \ + inpaname.c \ + inpapnam.c \ + inpcfix.c \ + inpdomod.c \ + inpdoopt.c \ + inpdpar.c \ + inperrc.c \ + inperror.c \ + inpeval.c \ + inpfindl.c \ + inpgmod.c \ + inpgstr.c \ + inpgtitl.c \ + inpgtok.c \ + inpgval.c \ + inpkmods.c \ + inplist.c \ + inplkmod.c \ + inpmkmod.c \ + inpmktmp.c \ + inppas1.c \ + inppas2.c \ + inppname.c \ + inpptree.c \ + inpsymt.c \ + inptyplk.c \ + ptfuncs.c \ + sperror.c \ + inp.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/circuit/ifeval.c b/src/circuit/ifeval.c new file mode 100644 index 000000000..54aa5b008 --- /dev/null +++ b/src/circuit/ifeval.c @@ -0,0 +1,108 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpmacs.h" +#include "fteext.h" +#include "iferrmsg.h" +#include "inpptree.h" +#include "inp.h" + + + + +extern double PTfudge_factor; + +static int PTeval(INPparseNode *tree, double gmin, double *res, double *vals); + + + +int +IFeval(IFparseTree *tree, double gmin, double *result, double *vals, double *derivs) +{ + int i, err; + INPparseTree *myTree = (INPparseTree*) tree;; + +/* +INPptPrint("calling PTeval, tree = ", myTree); +printf("values:"); +for (i = 0; i < myTree->p.numVars; i++) +printf("\tvar%d = %lg\n", i, vals[i]); +*/ + + if ((err = PTeval(myTree->tree, gmin, result, vals)) != OK) + return (err); + + for (i = 0; i < myTree->p.numVars; i++) + if ((err = PTeval(myTree->derivs[i], gmin, &derivs[i], vals)) != OK) + return (err); + +/* +printf("results: function = %lg\n", *result); +for (i = 0; i < myTree->p.numVars; i++) +printf("\td / d var%d = %lg\n", i, derivs[i]); +*/ + + return (OK); +} + +static int +PTeval(INPparseNode *tree, double gmin, double *res, double *vals) +{ + double r1, r2; + int err; + + PTfudge_factor = gmin; + switch (tree->type) { + case PT_CONSTANT: + *res = tree->constant; + break; + + case PT_VAR: + *res = vals[tree->valueIndex]; + break; + + case PT_FUNCTION: + err = PTeval(tree->left, gmin, &r1, vals); + if (err != OK) + return (err); + *res = (*tree->function)(r1); + if (*res == HUGE) { + fprintf(stderr, "Error: %g out of range for %s\n", + r1, tree->funcname); + return (E_PARMVAL); + } + break; + + case PT_PLUS: + case PT_MINUS: + case PT_TIMES: + case PT_DIVIDE: + case PT_POWER: + err = PTeval(tree->left, gmin, &r1, vals); + if (err != OK) + return (err); + err = PTeval(tree->right, gmin, &r2, vals); + if (err != OK) + return (err); + *res = (*tree->function)(r1, r2); + if (*res == HUGE) { + fprintf(stderr, "Error: %g, %g out of range for %s\n", + r1, r2, tree->funcname); + return (E_PARMVAL); + } + break; + + default: + fprintf(stderr, "Internal Error: bad node type %d\n", + tree->type); + return (E_PANIC); + } + + return (OK); +} + diff --git a/src/circuit/ifnewuid.c b/src/circuit/ifnewuid.c new file mode 100644 index 000000000..366775126 --- /dev/null +++ b/src/circuit/ifnewuid.c @@ -0,0 +1,82 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "cpdefs.h" +#include "fteext.h" +#include "inp.h" + + +int +IFnewUid(void *ckt, IFuid *newuid, IFuid olduid, char *suffix, int type, void **nodedata) +{ + char *newname; + int error; + + if(olduid) { + newname=(char *) + MALLOC(sizeof(char)*(strlen(suffix)+strlen((char*)olduid)+2)); + /* 2 = '#' + '\0' */ + sprintf(newname,"%s#%s",(char*)olduid,suffix); + } else { + newname=(char *)MALLOC(sizeof(char)* + (strlen(suffix)+1)); /* 1 = '\0' */ + sprintf(newname,"%s",suffix); + } + + switch(type) { + case UID_ANALYSIS: + case UID_TASK: + case UID_INSTANCE: + case UID_OTHER: + case UID_MODEL: + error = INPinsert(&newname, + (INPtables *)ft_curckt->ci_symtab); + if(error && error != E_EXISTS) return(error); + *newuid = (IFuid) newname; + break; + + case UID_SIGNAL: + error = INPmkTerm(ckt,&newname, + (INPtables *)ft_curckt->ci_symtab,nodedata); + if(error && error != E_EXISTS) return(error); + *newuid = (IFuid) newname; + break; + + default: + return(E_BADPARM); + } + return(OK); +} + +int +IFdelUid(void *ckt, IFuid uid, int type) +{ + int error; + + switch(type) { + case UID_ANALYSIS: + case UID_TASK: + case UID_INSTANCE: + case UID_OTHER: + case UID_MODEL: + error = INPremove(uid, (INPtables *)ft_curckt->ci_symtab); + if(error && error != E_EXISTS) return(error); + break; + + case UID_SIGNAL: + error = INPremTerm(uid, (INPtables *)ft_curckt->ci_symtab); + if(error && error != E_EXISTS) return(error); + break; + + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/circuit/inp.h b/src/circuit/inp.h new file mode 100644 index 000000000..0edacf41c --- /dev/null +++ b/src/circuit/inp.h @@ -0,0 +1,127 @@ +/************* + * Header file for inpxx.c + * 1999 E. Rouat + ************/ + +#ifndef INP_H_INCLUDED +#define INP_H_INCLUDED + +/* ifeval.c */ + +int IFeval(IFparseTree *tree, double gmin, double *result, double *vals, + double *derivs); + +/* ifnewuid.c */ + +int IFnewUid(void *ckt, IFuid *newuid, IFuid olduid, char *suffix, int type, + void **nodedata); +int IFdelUid(void *ckt, IFuid uid, int type); + +/* inp2xx.c */ + +void INP2B(void *ckt, INPtables *tab, card *current); +void INP2C(void *ckt, INPtables *tab, card *current); +void INP2D(void *ckt, INPtables *tab, card *current); +void INP2E(void *ckt, INPtables *tab, card *current); +void INP2F(void *ckt, INPtables *tab, card *current); +void INP2G(void *ckt, INPtables *tab, card *current); +void INP2H(void *ckt, INPtables *tab, card *current); +void INP2I(void *ckt, INPtables *tab, card *current); +void INP2J(void *ckt, INPtables *tab, card *current); +void INP2K(void *ckt, INPtables *tab, card *current); +void INP2L(void *ckt, INPtables *tab, card *current); +void INP2M(void *ckt, INPtables *tab, card *current); +void INP2O(void *ckt, INPtables *tab, card *current); +void INP2Q(void *ckt, INPtables *tab, card *current, void *gnode); +void INP2R(void *ckt, INPtables *tab, card *current); +void INP2S(void *ckt, INPtables *tab, card *current); +void INP2T(void *ckt, INPtables *tab, card *current); +void INP2U(void *ckt, INPtables *tab, card *current); +void INP2V(void *ckt, INPtables *tab, card *current); +void INP2W(void *ckt, INPtables *tab, card *current); +void INP2Z(void *ckt, INPtables *tab, card *current); +int INP2dot(void *ckt, INPtables *tab, card *current, void *task, void *gnode); + +/* inpxxxx.c */ + +int INPaName(char *parm, IFvalue *val, void *ckt, int *dev, char *devnam, + void **fast, IFsimulator *sim, int *dataType, IFvalue *selector); +int INPapName(void *ckt, int type, void *analPtr, char *parmname, IFvalue *value); +void INPcaseFix(register char *string); +char * INPdomodel(void *ckt, card *image, INPtables *tab); +void INPdoOpts(void *ckt, void *anal, card *optCard, INPtables *tab); +char * INPdevParse(char **line, void *ckt, int dev, void *fast, double *leading, + int *waslead, INPtables *tab); +char * INPerrCat(char *a, char *b); +char * INPerror(int type); +double INPevaluate(char **line, int *error, int gobble); +char * INPfindLev(char *line, int *level); +char * INPgetMod(void *ckt, char *name, INPmodel **model, INPtables *tab); +int INPgetStr(char **line, char **token, int gobble); +int INPgetTitle(void **ckt, card **data); +int INPgetTok(char **line, char **token, int gobble); +int INPgetUTok(char **line, char **token, int gobble); +IFvalue * INPgetValue(void *ckt, char **line, int type, INPtables *tab); +void INPkillMods(void); +void INPlist(FILE *file, card *deck, int type); +int INPlookMod(char *name); +int INPmakeMod(char *token, int type, card *line); +char * INPmkTemp(char *string); +void INPpas1(void *ckt, card *deck, INPtables *tab); +void INPpas2(void *ckt, card *data, INPtables *tab, void *task); +int INPpName(char *parm, IFvalue *val, void *ckt, int dev, void *fast); + +/* inpptree.c */ + +void INPgetTree(char **line, INPparseTree **pt, void *ckt, INPtables *tab); + + +/* inpsymt.c */ + +INPtables * INPtabInit(int numlines); +int INPtermInsert(void *ckt, char **token, INPtables *tab, void **node); +int INPmkTerm(void *ckt, char **token, INPtables *tab, void **node); +int INPgndInsert(void *ckt, char **token, INPtables *tab, void **node); +int INPretrieve(char **token, INPtables *tab); +int INPinsert(char **token, INPtables *tab); +int INPinsertNofree(char **token, INPtables *tab); +int INPremove(char *token, INPtables *tab); +int INPremTerm(char *token, INPtables *tab); +void INPtabEnd(INPtables *tab); + +int INPtypelook(char *type); + +/* ptfuncs.c */ + +double PTabs(double arg); +double PTsgn(double arg); +double PTplus(double arg1, double arg2); +double PTminus(double arg1, double arg2); +double PTtimes(double arg1, double arg2); +double PTtimes(double arg1, double arg2); +double PTdivide(double arg1, double arg2); +double PTpower(double arg1, double arg2); +double PTacos(double arg); +double PTacosh(double arg); +double PTasin(double arg); +double PTasinh(double arg); +double PTatan(double arg); +double PTatanh(double arg); +double PTustep(double arg); +double PTuramp(double arg); +double PTcos(double arg); +double PTcosh(double arg); +double PTexp(double arg); +double PTln(double arg); +double PTlog(double arg); +double PTsin(double arg); +double PTsinh(double arg); +double PTsqrt(double arg); +double PTtan(double arg); +double PTuminus(double arg); + +/* sperror.c */ + +char * SPerror(int type); + +#endif diff --git a/src/circuit/inp2b.c b/src/circuit/inp2b.c new file mode 100644 index 000000000..df61af1dd --- /dev/null +++ b/src/circuit/inp2b.c @@ -0,0 +1,59 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2B(void *ckt, INPtables *tab, card *current) +{ + + /* Bname [V=expr] [I=expr] */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model name */ + + /* Arbitrary source. */ + type = INPtypelook("ASRC"); + if (type < 0) { + LITERR("Device type Asource not supported by this binary\n") + return; + } + + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + + INPgetTok(&line,&nname1,1); + error = INPtermInsert(ckt,&nname1,tab,&node1); + + INPgetTok(&line,&nname2,1); + error = INPtermInsert(ckt,&nname2,tab,&node2); + + if(!tab->defBmod) { + /* create default B model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"B",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defBmod),uid)) + } + IFC(newInstance,(ckt,tab->defBmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) +} diff --git a/src/circuit/inp2c.c b/src/circuit/inp2c.c new file mode 100644 index 000000000..e5ba57c40 --- /dev/null +++ b/src/circuit/inp2c.c @@ -0,0 +1,91 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2C(void *ckt, INPtables *tab, card *current) +{ + +/* parse a capacitor card */ +/* Cname [IC=] */ + +int mytype; /* the type we determine resistors are */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *model; /* the name of the resistor's model */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +double val; /* temp to held resistance */ +int error; /* error code temporary */ +INPmodel *thismodel; /* pointer to model structure describing our model */ +void *mdfast; /* pointer to the actual model */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default cap model */ + + mytype = INPtypelook("Capacitor"); + if(mytype < 0 ) { + LITERR("Device type Capacitor not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + val = INPevaluate(&line,&error,1); + if(error == 0) { /* Looks like a number */ + type = mytype; + ptemp.rValue = val; + if(!tab->defCmod) { + IFnewUid(ckt,&uid,(IFuid)NULL,"C",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defCmod),uid)) + } + IFC(newInstance,(ckt,tab->defCmod,&fast,name)) + GCA(INPpName,("capacitance",&ptemp,ckt,type,fast)) + } else { /* looks like character strings */ + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + thismodel = (INPmodel *)NULL; + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + type = mytype; + mdfast = thismodel->INPmodfast; + } else { + type = mytype; + if(!tab->defCmod) { + IFnewUid(ckt,&uid,(IFuid)NULL,"C",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defCmod),uid)) + } + mdfast = tab->defCmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + } + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("capacitance",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2d.c b/src/circuit/inp2d.c new file mode 100644 index 000000000..ace8c2343 --- /dev/null +++ b/src/circuit/inp2d.c @@ -0,0 +1,77 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2D(void *ckt, INPtables *tab, card *current) +{ + +/* Dname [] [OFF] [IC=] */ + +int mytype; /* the type we looked up */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +char *model; /* the name of the model */ +INPmodel *thismodel; /* pointer to model description for user's model */ +void *mdfast; /* pointer to the actual model */ +IFuid uid; /* uid of default model */ + + mytype = INPtypelook("Diode"); + if(mytype < 0 ) { + LITERR("Device type Diode not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + type = mytype; + mdfast = (thismodel->INPmodfast); + } else { + type = mytype; + if(!tab->defDmod) { + /* create default D model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"D",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defDmod),uid)) + } + mdfast = tab->defDmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("area",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2dot.c b/src/circuit/inp2dot.c new file mode 100644 index 000000000..722b172f8 --- /dev/null +++ b/src/circuit/inp2dot.c @@ -0,0 +1,602 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +int +INP2dot(void *ckt, INPtables *tab, card *current, void *task, void *gnode) +{ + + /* . Many possibilities */ + +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *point; +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +IFvalue ptemp; /* a value structure to package resistance into */ +IFvalue *parm; /* a pointer to a value struct for function returns */ +IFparm *prm; /* pointer to parameter to search through array */ +char *token; /* a token from the line */ +int which; /* which analysis we are performing */ +int found; +int i; /* generic loop variable */ +void *foo; /* pointer to analysis */ +int length; /* length of a name */ +char *steptype; /* ac analysis, type of stepping function */ +double dtemp; /* random double precision temporary */ +char *word; /* something to stick a word of input into */ + + + line = current->line; + INPgetTok(&line,&token,1); + if (strcmp(token,".model")==0) { + /* don't have to do anything, since models were all done in + * pass 1 + */ + return(0); + } else if ((strcmp(token,".width") == 0) || + strcmp(token,".print") == 0 || + strcmp(token,".plot") == 0) { + /* obsolete - ignore */ + LITERR(" Warning: obsolete control card - ignored \n") + return(0); + } else if ( (strcmp(token,".temp")==0)){ + /* .temp temp1 temp2 temp3 temp4 ..... */ + /* not yet implemented - warn & ignore */ + LITERR(" Warning: .TEMP card obsolete - use .options TEMP and TNOM\n") + return(0); + } else if ( (strcmp(token,".op")==0)){ + /* .op */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"OP")==0) { + which=i; + break; + } + } + if(which == -1) { + LITERR("DC operating point analysis unsupported\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"Operating Point",&foo, task)) + return(0); + } else if ( (strcmp(token,".nodeset")==0)){ + /* .nodeset */ + which = -1; + for(prm=ft_sim->nodeParms; + prmnodeParms+ft_sim->numNodeParms;prm++) { + if(strcmp(prm->keyword,"nodeset")==0) { + which=prm->id; + break; + } + } + if(which == -1) { + LITERR("nodeset unknown to simulator. \n") + return(0); + } + for(;;) { /* loop until we run out of data */ + INPgetTok(&line,&name,1); + /* check to see if in the form V(xxx) and grab the xxx */ + if( *name == (char)NULL) break; /* end of line */ + length = strlen(name); + if( (*name == 'V' || *(name) == 'v') && (length == 1)){ + /* looks like V - must be V(xx) - get xx now*/ + INPgetTok(&line,&name,1); + INPtermInsert(ckt,&name,tab,&node1); + ptemp.rValue = INPevaluate(&line,&error,1); + IFC(setNodeParm,(ckt,node1,which,&ptemp,(IFvalue*)NULL)) + continue; + } + LITERR(" Error: .nodeset syntax error.\n") + break; + } + return(0); + } else if ( (strcmp(token,".disto")==0)){ + /* .disto {DEC OCT LIN} NP FSTART FSTOP */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"DISTO")==0) { + which=i; + break; + } + } + if(which == -1) { + LITERR("Small signal distortion analysis unsupported.\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"Distortion Analysis",&foo, task)) + INPgetTok(&line,&steptype,1); /* get DEC, OCT, or LIN */ + ptemp.iValue=1; + GCA(INPapName,(ckt,which,foo,steptype,&ptemp)) + parm=INPgetValue(ckt,&line,IF_INTEGER,tab);/* number of points*/ + GCA(INPapName,(ckt,which,foo,"numsteps",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstart */ + GCA(INPapName,(ckt,which,foo,"start",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstop */ + GCA(INPapName,(ckt,which,foo,"stop",parm)) + if(*line) { + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* f1phase */ + GCA(INPapName,(ckt,which,foo,"f2overf1",parm)) + } + return(0); + } else if ( (strcmp(token,".noise")==0)){ + /* .noise V(OUTPUT,REF) SRC {DEC OCT LIN} NP FSTART FSTOP */ + which = -1; + for (i=0; inumAnalyses; i++) { + if (strcmp(ft_sim->analyses[i]->name, "NOISE") == 0) { + which = i; + break; + } + } + if (which == -1) { + LITERR("Noise analysis unsupported.\n"); + return(0); + } + IFC(newAnalysis, (ckt,which,"Noise Analysis",&foo,task)) + INPgetTok(&line,&name,1); + + /* Make sure the ".noise" command is followed by */ + /* V(xxxx). If it is, extract 'xxxx'. If not, report an error. */ + + if (name != NULL) { + length = strlen(name); + if (((*name == 'V') || (*name == 'v')) && (length == 1)) { + + INPgetTok(&line,&nname1,0); + INPtermInsert(ckt,&nname1,tab,&node1); + ptemp.nValue=(IFnode)node1; + GCA(INPapName,(ckt,which,foo,"output",&ptemp)) + + if (*line != /* match ( */ ')') { + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + ptemp.nValue=(IFnode)node2; + } else { + ptemp.nValue=(IFnode)gnode; + } + GCA(INPapName,(ckt,which,foo,"outputref",&ptemp)) + + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + GCA(INPapName,(ckt,which,foo,"input",&ptemp)) + + INPgetTok(&line,&steptype,1); + ptemp.iValue = 1; + error=INPapName(ckt,which,foo,steptype,&ptemp); + if (error) + current->error = INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_INTEGER,tab); + error = INPapName(ckt,which,foo,"numsteps",parm); + if (error) + current->error = INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); + error = INPapName(ckt,which,foo,"start",parm); + if (error) + current->error = INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); + error = INPapName(ckt,which,foo,"stop",parm); + if (error) + current->error = INPerrCat(current->error,INPerror(error)); + + /* now see if "ptspersum" has been specified by the user */ + + for (found=0, point=line; (!found) && (*point != '\0'); + found = ((*point != ' ') && (*(point++) != '\t'))); + if (found) { + parm = INPgetValue(ckt,&line,IF_INTEGER,tab); + error = INPapName(ckt,which,foo,"ptspersum",parm); + if (error) + current->error = + INPerrCat(current->error,INPerror(error)); + } else { + ptemp.iValue = 0; + error = INPapName(ckt,which,foo,"ptspersum",&ptemp); + if (error) current->error = + INPerrCat(current->error,INPerror(error)); + } + } else + LITERR( +"bad syntax [.noise v(OUT) SRC {DEC OCT LIN} NP FSTART FSTOP ]\n"); + } + else { + LITERR( +"bad syntax [.noise v(OUT) SRC {DEC OCT LIN} NP FSTART FSTOP ]\n"); + } + return(0); + } else if ( (strcmp(token,".four")==0) || (strcmp(token,".fourier")==0) ){ + /* .four */ + /* not implemented - warn & ignore */ + LITERR("Use fourier command to obtain fourier analysis\n") + return(0); + } else if ( (strcmp(token,".ic")==0)){ + /* .ic */ + which = -1; + for(prm=ft_sim->nodeParms; + prmnodeParms+ft_sim->numNodeParms;prm++) { + if(strcmp(prm->keyword,"ic")==0) { + which=prm->id; + break; + } + } + if(which==-1) { + LITERR("ic unknown to simulator. \n") + return(0); + } + for(;;) { /* loop until we run out of data */ + INPgetTok(&line,&name,1); + /* check to see if in the form V(xxx) and grab the xxx */ + if( *name == 0) break; /* end of line */ + length = strlen(name); + if( (*name == 'V' || *(name) == 'v') && (length == 1)){ + /* looks like V - must be V(xx) - get xx now*/ + INPgetTok(&line,&name,1); + INPtermInsert(ckt,&name,tab,&node1); + ptemp.rValue = INPevaluate(&line,&error,1); + IFC(setNodeParm,(ckt,node1,which,&ptemp,(IFvalue*)NULL)) + continue; + } + LITERR(" Error: .ic syntax error.\n") + break; + } + return(0); + } else if ( (strcmp(token,".ac")==0)){ + /* .ac {DEC OCT LIN} NP FSTART FSTOP */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"AC")==0) { + which=i; + break; + } + } + if(which == -1) { + LITERR("AC small signal analysis unsupported.\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"AC Analysis",&foo, task)) + INPgetTok(&line,&steptype,1); /* get DEC, OCT, or LIN */ + ptemp.iValue=1; + GCA(INPapName,(ckt,which,foo,steptype,&ptemp)) + parm=INPgetValue(ckt,&line,IF_INTEGER,tab);/* number of points*/ + GCA(INPapName,(ckt,which,foo,"numsteps",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstart */ + GCA(INPapName,(ckt,which,foo,"start",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstop */ + GCA(INPapName,(ckt,which,foo,"stop",parm)) + return(0); + } else if ( (strcmp(token,".pz")==0)){ + /* .pz nodeI nodeG nodeJ nodeK {V I} {POL ZER PZ} */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"PZ")==0) { + which=i; + break; + } + } + if(which == -1) { + LITERR("Pole-zero analysis unsupported.\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"Pole-Zero Analysis",&foo, task)) + parm = INPgetValue(ckt,&line,IF_NODE,tab); + GCA(INPapName,(ckt,which,foo,"nodei",parm)) + parm = INPgetValue(ckt,&line,IF_NODE,tab); + GCA(INPapName,(ckt,which,foo,"nodeg",parm)) + parm = INPgetValue(ckt,&line,IF_NODE,tab); + GCA(INPapName,(ckt,which,foo,"nodej",parm)) + parm = INPgetValue(ckt,&line,IF_NODE,tab); + GCA(INPapName,(ckt,which,foo,"nodek",parm)) + INPgetTok(&line,&steptype,1); /* get V or I */ + ptemp.iValue=1; + GCA(INPapName,(ckt,which,foo,steptype,&ptemp)) + INPgetTok(&line,&steptype,1); /* get POL, ZER, or PZ */ + ptemp.iValue=1; + GCA(INPapName,(ckt,which,foo,steptype,&ptemp)) + return(0); + } else if ( (strcmp(token,".dc")==0)){ + /* .dc SRC1NAME Vstart1 Vstop1 Vinc1 [SRC2NAME Vstart2 */ + /* Vstop2 Vinc2 */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"DC")==0) { + which=i; + break; + } + } + if(which==-1) { + LITERR("DC transfer curve analysis unsupported\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"DC transfer characteristic",&foo, task)) + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + GCA(INPapName,(ckt,which,foo,"name1",&ptemp)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstart1 */ + GCA(INPapName,(ckt,which,foo,"start1",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstop1 */ + GCA(INPapName,(ckt,which,foo,"stop1",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vinc1 */ + GCA(INPapName,(ckt,which,foo,"step1",parm)) + if(*line) { + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + GCA(INPapName,(ckt,which,foo,"name2",&ptemp)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstart1 */ + GCA(INPapName,(ckt,which,foo,"start2",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstop1 */ + GCA(INPapName,(ckt,which,foo,"stop2",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vinc1 */ + GCA(INPapName,(ckt,which,foo,"step2",parm)) + } + return(0); + } else if ( (strcmp(token,".tf")==0)){ + /* .tf v( node1, node2 ) src */ + /* .tf vsrc2 src */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"TF")==0) { + which=i; + break; + } + } + if(which==-1) { + LITERR("Transfer Function analysis unsupported.\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"Transfer Function",&foo,task)) + INPgetTok(&line,&name,0); + /* name is now either V or I or a serious error */ + if(*name == 'v' && strlen(name)==1) { + if(*line != '(' /* match) */ ) { + /* error, bad input format */ + } + INPgetTok(&line,&nname1,0); + INPtermInsert(ckt,&nname1,tab,&node1); + ptemp.nValue=(IFnode)node1; + GCA(INPapName,(ckt,which,foo,"outpos",&ptemp)) + if(*line != /* match ( */ ')') { + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + ptemp.nValue=(IFnode)node2; + GCA(INPapName,(ckt,which,foo,"outneg",&ptemp)) + ptemp.sValue = (char *) + MALLOC(sizeof(char)*(5+strlen(nname1)+strlen(nname2))); + (void)sprintf(ptemp.sValue,"V(%s,%s)",nname1,nname2); + GCA(INPapName,(ckt,which,foo,"outname",&ptemp)) + } else { + ptemp.nValue=(IFnode)gnode; + GCA(INPapName,(ckt,which,foo,"outneg",&ptemp)) + ptemp.sValue = (char *)MALLOC(sizeof(char)*(4+strlen(nname1))); + (void)sprintf(ptemp.sValue,"V(%s)",nname1); + GCA(INPapName,(ckt,which,foo,"outname",&ptemp)) + } + } else if(*name == 'i' && strlen(name)==1) { + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + GCA(INPapName,(ckt,which,foo,"outsrc",&ptemp)) + } else { + LITERR("Syntax error: voltage or current expected.\n") + return 0; + } + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + GCA(INPapName,(ckt,which,foo,"insrc",&ptemp)) + return(0); + } else if ( (strcmp(token,".tran")==0)){ + /* .tran Tstep Tstop > */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"TRAN")==0) { + which=i; + break; + } + } + if(which == -1) { + LITERR("Transient analysis unsupported.\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"Transient Analysis",&foo, task)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* Tstep */ + GCA(INPapName,(ckt,which,foo,"tstep",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* Tstop */ + GCA(INPapName,(ckt,which,foo,"tstop",parm)) + if(*line) { + dtemp = INPevaluate(&line,&error,1); /* tstart? */ + if(error==0) { + ptemp.rValue=dtemp; + GCA(INPapName,(ckt,which,foo,"tstart",&ptemp)) + dtemp = INPevaluate(&line,&error,1); /* tmax? */ + if(error==0) { + ptemp.rValue=dtemp; + GCA(INPapName,(ckt,which,foo,"tmax",&ptemp)) + } + } + } + if(*line) { + INPgetTok(&line,&word,1); /* uic? */ + if(strcmp(word,"uic")==0) { + ptemp.iValue=1; + GCA(INPapName,(ckt,which,foo,"uic",&ptemp)) + } else { + LITERR(" Error: unknown parameter on .tran - ignored\n") + } + } + return(0); + } else if ( (strcmp(token,".subckt")==0) || + (strcmp(token,".ends")==0) ){ + /* not yet implemented - warn & ignore */ + LITERR(" Warning: Subcircuits not yet implemented - ignored \n") + return(0); + } else if ( (strcmp(token,".end")==0)){ + /* .end - end of input */ + /* not allowed to pay attention to additional input - return */ + return(1); + /*NOTREACHED*/ + } else if ( (strcmp(token,".options")==0) || + (strcmp(token,".option")==0) || + (strcmp(token,".opt")==0) ){ + /* .option - specify program options - rather complicated */ + /* use a subroutine to handle all of them to keep this */ + /* subroutine managable */ + INPdoOpts(ckt,ft_curckt->ci_curOpt,current,tab); + return(0); + } else if (strcmp(token, ".sens") == 0) { + which = -1; /* Bug fix from Glao Dezai */ + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"SENS")==0) { + which=i; + break; + } + } + if(which==-1) { + LITERR("Sensitivity unsupported.\n") + return(0); + } + + IFC(newAnalysis,(ckt,which,"Sensitivity Analysis",&foo, task)) + + /* Format is: + * .sens + * + [ac [dec|lin|oct] | dc ] + */ + + /* Get the output voltage or current */ + INPgetTok(&line,&name,0); + /* name is now either V or I or a serious error */ + if (*name == 'v' && strlen(name) == 1) { + if (*line != '(' /* match) */) { + LITERR("Syntax error: '(' expected after 'v'\n"); + return 0; + } + INPgetTok(&line, &nname1, 0); + INPtermInsert(ckt, &nname1, tab, &node1); + ptemp.nValue=(IFnode)node1; + GCA(INPapName,(ckt,which,foo,"outpos",&ptemp)) + + if(*line != /* match ( */ ')') { + INPgetTok(&line, &nname2, 1); + INPtermInsert(ckt, &nname2, tab, &node2); + ptemp.nValue = (IFnode)node2; + GCA(INPapName,(ckt,which,foo,"outneg",&ptemp)) + ptemp.sValue = (char *) + MALLOC(sizeof(char)*(5+strlen(nname1)+strlen(nname2))); + (void)sprintf(ptemp.sValue,"V(%s,%s)",nname1,nname2); + GCA(INPapName,(ckt,which,foo,"outname",&ptemp)) + } else { + ptemp.nValue=(IFnode)gnode; + GCA(INPapName,(ckt,which,foo,"outneg",&ptemp)) + ptemp.sValue = (char *)MALLOC(sizeof(char)*(4+strlen(nname1))); + (void)sprintf(ptemp.sValue,"V(%s)",nname1); + GCA(INPapName,(ckt,which,foo,"outname",&ptemp)) + } + } else if (*name == 'i' && strlen(name) == 1) { + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + GCA(INPapName,(ckt,which,foo,"outsrc",&ptemp)) + } else { + LITERR("Syntax error: voltage or current expected.\n") + return 0; + } + + INPgetTok(&line,&name,1); + if (name && !strcmp(name, "pct")) { + ptemp.iValue = 1; + GCA(INPapName,(ckt,which,foo,"pct",&ptemp)) + INPgetTok(&line,&name,1); + } + if (name && !strcmp(name, "ac")) { + INPgetTok(&line,&steptype,1); /* get DEC, OCT, or LIN */ + ptemp.iValue=1; + GCA(INPapName,(ckt,which,foo,steptype,&ptemp)) + parm=INPgetValue(ckt,&line,IF_INTEGER,tab);/* number of points*/ + GCA(INPapName,(ckt,which,foo,"numsteps",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstart */ + GCA(INPapName,(ckt,which,foo,"start",parm)) + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstop */ + GCA(INPapName,(ckt,which,foo,"stop",parm)) + return(0); + } else if (name && *name && strcmp(name, "dc")) { + /* Bad flag */ + LITERR("Syntax error: 'ac' or 'dc' expected.\n") + return 0; + } + return(0); + } +#ifdef WANT_SENSE2 + else if ( (strcmp(token,".sens2")==0)) { + /* .sens {AC} {DC} {TRAN} [dev=nnn parm=nnn]* */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"SENS2")==0) { + which=i; + break; + } + } + if(which == -1) { + LITERR("Sensitivity-2 analysis unsupported\n") + return(0); + } + IFC(newAnalysis,(ckt,which,"Sensitivity-2 Analysis",&foo, task)) + while(*line) { /* read the entire line */ + INPgetTok(&line,&token,1); + for(i=0;ianalyses[which]->numParms;i++) { + /* find the parameter */ + if(0==strcmp(token , + ft_sim->analyses[which]->analysisParms[i]. + keyword) ){ + /* found it, analysis which, parameter i */ + if(ft_sim->analyses[which]->analysisParms[i]. + dataType & IF_FLAG) { + /* one of the keywords! */ + ptemp.iValue = 1; + error = (*(ft_sim->setAnalysisParm))(ckt, + foo, ft_sim->analyses[which]-> + analysisParms[i].id,&ptemp,(IFvalue*)NULL); + if(error) current->error = INPerrCat( + current->error, INPerror(error)); + } else { + parm = INPgetValue(ckt,&line,ft_sim-> + analyses[which]->analysisParms[i]. + dataType,tab); + error = (*(ft_sim->setAnalysisParm))(ckt, + foo, ft_sim->analyses[which]-> + analysisParms[i].id,parm,(IFvalue*)NULL); + if(error) current->error = INPerrCat( + current->error, INPerror(error)); + + } + break; + } + } + if(i==ft_sim->analyses[which]->numParms) { + /* didn't find it! */ + LITERR(" Error: unknown parameter on .sens-ignored \n") + } + } + return(0); + } +#endif + else if ( (strcmp(token,".probe")==0)) { + /* Maybe generate a "probe" format file in the future. */ + return 0; + } + LITERR(" unimplemented control card - error \n") + return(0); +} diff --git a/src/circuit/inp2e.c b/src/circuit/inp2e.c new file mode 100644 index 000000000..0346060f6 --- /dev/null +++ b/src/circuit/inp2e.c @@ -0,0 +1,69 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2E(void *ckt, INPtables *tab, card *current) +{ + +/* Ename */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +char *nname4; /* the fourth node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +void *node4; /* the fourth node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + type = INPtypelook("VCVS"); + if(type < 0 ) { + LITERR("Device type VCVS not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&nname4,1); + INPtermInsert(ckt,&nname4,tab,&node4); + if(!tab->defEmod) { + /* create default E model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"E",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defEmod),uid)) + } + IFC(newInstance,(ckt,tab->defEmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + IFC(bindNode,(ckt,fast,4,node4)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("gain",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2f.c b/src/circuit/inp2f.c new file mode 100644 index 000000000..ff398b236 --- /dev/null +++ b/src/circuit/inp2f.c @@ -0,0 +1,62 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2F(void *ckt, INPtables *tab, card *current) +{ + +/* Fname */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +IFvalue *parm; /* a pointer to a value structure to pick things up into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + type = INPtypelook("CCCS"); + if(type < 0 ) { + LITERR("Device type CCCS not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + if(!tab->defFmod) { + /* create default F model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"F",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defFmod),uid)) + } + IFC(newInstance,(ckt,tab->defFmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + parm=INPgetValue(ckt,&line,IF_INSTANCE,tab); + GCA(INPpName,("control",parm,ckt,type,fast)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("gain",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2g.c b/src/circuit/inp2g.c new file mode 100644 index 000000000..6943c1c62 --- /dev/null +++ b/src/circuit/inp2g.c @@ -0,0 +1,69 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2G(void *ckt, INPtables *tab, card *current) +{ + +/* Gname */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +char *nname4; /* the fourth node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +void *node4; /* the fourth node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid of default model to be created */ + + type = INPtypelook("VCCS"); + if(type < 0 ) { + LITERR("Device type VCCS not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&nname4,1); + INPtermInsert(ckt,&nname4,tab,&node4); + if(!tab->defGmod) { + /* create default G model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"G",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defGmod),uid)) + } + IFC(newInstance,(ckt,tab->defGmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + IFC(bindNode,(ckt,fast,4,node4)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("gain",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2h.c b/src/circuit/inp2h.c new file mode 100644 index 000000000..658907107 --- /dev/null +++ b/src/circuit/inp2h.c @@ -0,0 +1,62 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2H(void *ckt, INPtables *tab, card *current) +{ + +/* Hname */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +IFvalue *parm; /* pointer to a value structure for functions which return one*/ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model to be created */ + + type = INPtypelook("CCVS"); + if(type < 0 ) { + LITERR("Device type CCVS not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + if(!tab->defHmod) { + /* create default H model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"H",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defHmod),uid)) + } + IFC(newInstance,(ckt,tab->defHmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + parm=INPgetValue(ckt,&line,IF_INSTANCE,tab); + GCA(INPpName,("control",parm,ckt,type,fast)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("gain",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2i.c b/src/circuit/inp2i.c new file mode 100644 index 000000000..fc426d029 --- /dev/null +++ b/src/circuit/inp2i.c @@ -0,0 +1,60 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2I(void *ckt, INPtables *tab, card *current) +{ + + /* Iname [ [DC] ] [AC [ [ ] ] ] + * [] */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + type = INPtypelook("Isource"); + if(type < 0 ) { + LITERR("Device type Isource not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + if(!tab->defImod) { + /* create default I model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"I",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defImod),uid)) + } + IFC(newInstance,(ckt,tab->defImod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("dc",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2j.c b/src/circuit/inp2j.c new file mode 100644 index 000000000..089b82ffd --- /dev/null +++ b/src/circuit/inp2j.c @@ -0,0 +1,84 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2J(void *ckt, INPtables *tab, card *current) +{ + + /* Jname [] [OFF] [IC=,] */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +char *model; /* the name of the model */ +INPmodel *thismodel; /* pointer to model description for user's model */ +void *mdfast; /* pointer to the actual model */ +IFuid uid; /* uid of default model */ + + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + thismodel = (INPmodel *)NULL; + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if (thismodel->INPmodType != INPtypelook("JFET") + && thismodel->INPmodType != INPtypelook("JFET2") + ) + { + LITERR("incorrect model type") + return; + } + type = thismodel->INPmodType; + mdfast = (thismodel->INPmodfast); + } else { + type = INPtypelook("JFET"); + if(type < 0 ) { + LITERR("Device type JFET not supported by this binary\n") + return; + } + if(!tab->defJmod) { + /* create default J model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"J",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defJmod),uid)) + } + mdfast = tab->defJmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("area",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2k.c b/src/circuit/inp2k.c new file mode 100644 index 000000000..7614955f3 --- /dev/null +++ b/src/circuit/inp2k.c @@ -0,0 +1,56 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2K(void *ckt, INPtables *tab, card *current) +{ + +/* Kname Lname Lname */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +IFvalue *parm; /* ptr to a value structure for function return values */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + line = current->line; + type = INPtypelook("mutual"); + if(type < 0 ) { + LITERR("Device type mutual not supported by this binary\n") + return; + } + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + if(!tab->defKmod) { + /* create deafult K model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"K",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defKmod),uid)) + } + IFC(newInstance,(ckt,tab->defKmod,&fast,name)) + + parm = INPgetValue(ckt,&line,IF_INSTANCE,tab); + GCA(INPpName,("inductor1",parm,ckt,type,fast)) + parm = INPgetValue(ckt,&line,IF_INSTANCE,tab); + GCA(INPpName,("inductor2",parm,ckt,type,fast)) + + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("coefficient",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2l.c b/src/circuit/inp2l.c new file mode 100644 index 000000000..d2282dba5 --- /dev/null +++ b/src/circuit/inp2l.c @@ -0,0 +1,59 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2L(void *ckt, INPtables *tab, card *current) +{ +/* parse an inductor card */ +/* Lname [IC=] */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + type = INPtypelook("Inductor"); + if(type < 0 ) { + LITERR("Device type Inductor not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + if(!tab->defLmod) { + /* create default L model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"L",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defLmod),uid)) + } + IFC(newInstance,(ckt,tab->defLmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("inductance",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2m.c b/src/circuit/inp2m.c new file mode 100644 index 000000000..d0b203f74 --- /dev/null +++ b/src/circuit/inp2m.c @@ -0,0 +1,101 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2M(void *ckt, INPtables *tab, card *current) +{ + + /* Mname [L=] + * [W=] [AD=] [AS=] [PD=] + * [PS=] [NRD=] [NRS=] [OFF] + * [IC=,,] + */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +char *nname4; /* the fourth node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +void *node4; /* the fourth node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +char *model; /* the name of the model */ +INPmodel *thismodel; /* pointer to model description for user's model */ +void *mdfast; /* pointer to the actual model */ +IFuid uid; /* uid for default model */ + + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&nname4,1); + INPtermInsert(ckt,&nname4,tab,&node4); + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + thismodel = (INPmodel *)NULL; + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if (thismodel->INPmodType != INPtypelook("Mos1") + && thismodel->INPmodType != INPtypelook("Mos2") + && thismodel->INPmodType != INPtypelook("Mos3") + && thismodel->INPmodType != INPtypelook("Mos5") + && thismodel->INPmodType != INPtypelook("Mos6") + && thismodel->INPmodType != INPtypelook("Mos8") + && thismodel->INPmodType != INPtypelook("BSIM1") + && thismodel->INPmodType != INPtypelook("BSIM2") + && thismodel->INPmodType != INPtypelook("BSIM3") + && thismodel->INPmodType != INPtypelook("BSIM4") + && thismodel->INPmodType != INPtypelook("BSIM3V1") + && thismodel->INPmodType != INPtypelook("BSIM3V2") + ) + { + LITERR("incorrect model type") + return; + } + type = thismodel->INPmodType; + mdfast = (thismodel->INPmodfast); + } else { + type = INPtypelook("Mos1"); + if(type < 0 ) { + LITERR("Device type MOS1 not supported by this binary\n") + return; + } + if(!tab->defMmod) { + /* create default M model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"M",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defMmod),uid)) + } + mdfast = tab->defMmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + IFC(bindNode,(ckt,fast,4,node4)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + LITERR(" error: no unlabeled parameter permitted on mosfet\n") + } +} diff --git a/src/circuit/inp2o.c b/src/circuit/inp2o.c new file mode 100644 index 000000000..cb6bc1210 --- /dev/null +++ b/src/circuit/inp2o.c @@ -0,0 +1,91 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + + +void +INP2O(void *ckt, INPtables *tab, card *current) +{ + + /* Oname [IC=,,,] */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +char *nname4; /* the fourth node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +void *node4; /* the fourth node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +char *model; /* the name of the model */ +INPmodel *thismodel; /* pointer to model description for user's model */ +void *mdfast; /* pointer to the actual model */ +IFuid uid; /* uid for default model */ + + + type = INPtypelook("LTRA"); + if(type < 0 ) { + LITERR("Device type LossyXmissionLine not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&nname4,1); + INPtermInsert(ckt,&nname4,tab,&node4); + INPgetTok(&line,&model,1); + if( INPlookMod(model) ) { + /* do nothing for now */ + /* no action required */ + } else { + /* + nname4 = model; + INPtermInsert(ckt,&nname4,tab,&node4); + INPgetTok(&line,&model,1); + */ + } + INPinsert(&model,tab); + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(type != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + mdfast = (thismodel->INPmodfast); + } else { + if(!tab->defOmod) { + /* create default O model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"O",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defOmod),uid)) + } + mdfast = tab->defOmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + IFC(bindNode,(ckt,fast,4,node4)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) +} diff --git a/src/circuit/inp2q.c b/src/circuit/inp2q.c new file mode 100644 index 000000000..1992854e1 --- /dev/null +++ b/src/circuit/inp2q.c @@ -0,0 +1,95 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2Q(void *ckt, INPtables *tab, card *current, void *gnode) +{ + + /* Qname [] [] [OFF] + * [IC=,] */ + +int mytype; /* the type we looked up */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +char *nname4; /* the fourth node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +void *node4; /* the fourth node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +char *model; /* the name of the model */ +INPmodel *thismodel; /* pointer to model description for user's model */ +void *mdfast; /* pointer to the actual model */ +IFuid uid; /* uid of default model */ + + mytype = INPtypelook("BJT"); + if(mytype < 0 ) { + LITERR("Device type BJT not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&model,1); + if( INPlookMod(model) ) { + /* do nothing for now */ + node4 = gnode; + /* no action required */ + } else { + nname4 = model; + INPtermInsert(ckt,&nname4,tab,&node4); + INPgetTok(&line,&model,1); + } + INPinsert(&model,tab); + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + type = mytype; + mdfast = (thismodel->INPmodfast); + } else { + type = mytype; + if(!tab->defQmod) { + /* create default Q model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"Q",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defQmod),uid)) + } + mdfast = tab->defQmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + IFC(bindNode,(ckt,fast,4,node4)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("area",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2r.c b/src/circuit/inp2r.c new file mode 100644 index 000000000..29b683436 --- /dev/null +++ b/src/circuit/inp2r.c @@ -0,0 +1,116 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2R(void *ckt, INPtables *tab, card *current) +{ +/* parse a resistor card */ +/* serban */ +/* Rname [][][w=][l=][ac=] */ + +int mytype; /* the type we determine resistors are */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *model; /* the name of the resistor's model */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +double val; /* temp to held resistance */ +double acval; /* temp to held resistance */ +int error; /* error code temporary */ +int error1; /* secondary error code temporary */ +int error2; /* third error code temporary */ +INPmodel *thismodel; /* pointer to model structure describing our model */ +void *mdfast; /* pointer to the actual model */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + mytype = INPtypelook("Resistor"); + if(mytype < 0 ) { + LITERR("Device type Resistor not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + val = INPevaluate(&line,&error1,1); + acval = val; /* PN: This is a safe choice */ + /* either not a number -> model, or + * follows a number, so must be a model name + * -> MUST be a model name (or null) + */ +again: + INPgetTok(&line,&model,1); + if(*model) { /* token isn't null */ + if(!strcmp(model, "ac")) { + acval = INPevaluate(&line,&error2,1); + goto again; + } else { + INPinsert(&model,tab); + thismodel = (INPmodel *)NULL; + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + mdfast = thismodel->INPmodfast; + type = thismodel->INPmodType; + } else { + type = mytype; + if(!tab->defRmod) { + /* create default R model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"R",UID_MODEL,(void **)NULL); + IFC(newModel, (ckt,type,&(tab->defRmod),uid)) + } + mdfast = tab->defRmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + } + } else { + type = mytype; + if(!tab->defRmod) { + /* create default R model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"R",UID_MODEL,(void **)NULL); + IFC(newModel, (ckt,type,&(tab->defRmod),uid)) + } + IFC(newInstance,(ckt,tab->defRmod,&fast,name)) + } + if(error1 == 0) { /* got a resistance above */ + ptemp.rValue = val; + GCA(INPpName,("resistance",&ptemp,ckt,type,fast)) + } + if(error2 == 0) { /* got an AC resistance above */ + ptemp.rValue = acval; + GCA(INPpName,("ac",&ptemp,ckt,type,fast)) + } + + + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("resistance",&ptemp,ckt,type,fast)) + } + return; +} diff --git a/src/circuit/inp2s.c b/src/circuit/inp2s.c new file mode 100644 index 000000000..406df4329 --- /dev/null +++ b/src/circuit/inp2s.c @@ -0,0 +1,86 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2S(void *ckt, INPtables *tab, card *current) +{ + + /* Sname [] [IC] */ + /* VOLTAGE CONTROLLED SWITCH */ + +int mytype; /* the type we determine resistors are */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *model; /* the name of the resistor's model */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +char *nname4; /* the fourth node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +void *node4; /* the fourth node's node pointer */ +int error; /* error code temporary */ +INPmodel *thismodel; /* pointer to model structure describing our model */ +void *mdfast; /* pointer to the actual model */ +void *fast; /* pointer to the actual instance */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid of default model */ + + mytype = INPtypelook("Switch"); + if(mytype < 0 ) { + LITERR("Device type Switch not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&nname4,1); + INPtermInsert(ckt,&nname4,tab,&node4); + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + type = mytype; + mdfast = (thismodel->INPmodfast); + } else { + type = mytype; + if(!tab->defSmod) { + /* create deafult S model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"S",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defSmod),uid)) + } + mdfast = tab->defSmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + IFC(bindNode,(ckt,fast,4,node4)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + /* ignore a number */ + } +} diff --git a/src/circuit/inp2t.c b/src/circuit/inp2t.c new file mode 100644 index 000000000..05b619ffd --- /dev/null +++ b/src/circuit/inp2t.c @@ -0,0 +1,66 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2T(void *ckt, INPtables *tab, card *current) +{ + + /* Tname [TD=] + * [F= [NL=]][IC=,,,] */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +char *nname4; /* the fourth node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +void *node4; /* the fourth node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + + type = INPtypelook("Tranline"); + if(type < 0 ) { + LITERR("Device type Tranline not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&nname4,1); + INPtermInsert(ckt,&nname4,tab,&node4); + if(!tab->defTmod) { + /* create deafult T model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"T",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defTmod),uid)) + } + IFC(newInstance,(ckt,tab->defTmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + IFC(bindNode,(ckt,fast,4,node4)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) +} diff --git a/src/circuit/inp2u.c b/src/circuit/inp2u.c new file mode 100644 index 000000000..18b1afc72 --- /dev/null +++ b/src/circuit/inp2u.c @@ -0,0 +1,77 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2U(void *ckt, INPtables *tab, card *current) +{ + + /* Uname [l=] [n=] */ + +int mytype; /* the type my lookup says URC is */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +char *model; /* name of the model */ +INPmodel *thismodel; /* pointer to our model descriptor */ +void *mdfast; /* pointer to the actual model */ +IFuid uid; /* uid for default model */ + + mytype = INPtypelook("URC"); + if(mytype < 0 ) { + LITERR("Device type URC not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + type = mytype; + mdfast = (thismodel->INPmodfast); + } else { + type = mytype; + if(!tab->defUmod) { + /* create deafult U model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"U",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defUmod),uid)) + } + mdfast = tab->defUmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) +} diff --git a/src/circuit/inp2v.c b/src/circuit/inp2v.c new file mode 100644 index 000000000..7a0a42cb7 --- /dev/null +++ b/src/circuit/inp2v.c @@ -0,0 +1,60 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2V(void *ckt, INPtables *tab, card *current) +{ + + /* Vname [ [DC] ] [AC [ [ ] ] ] + * [] */ + +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + type = INPtypelook("Vsource"); + if(type < 0 ) { + LITERR("Device type Vsource not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + if(!tab->defVmod) { + /* create default V model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"V",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defVmod),uid)) + } + IFC(newInstance,(ckt,tab->defVmod,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("dc",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inp2w.c b/src/circuit/inp2w.c new file mode 100644 index 000000000..01bdb62e1 --- /dev/null +++ b/src/circuit/inp2w.c @@ -0,0 +1,83 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2W(void *ckt, INPtables *tab, card *current) +{ + + /* Wname [] [IC] */ + /* CURRENT CONTROLLED SWITCH */ + +int mytype; /* the type we determine resistors are */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *model; /* the name of the resistor's model */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +int error; /* error code temporary */ +INPmodel *thismodel; /* pointer to model structure describing our model */ +void *mdfast; /* pointer to the actual model */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +IFvalue *parm; /* pointer to a value structure for functions to return */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +IFuid uid; /* uid for default model */ + + mytype = INPtypelook("CSwitch"); + if(mytype < 0 ) { + LITERR("Device type CSwitch not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + parm=INPgetValue(ckt,&line,IF_INSTANCE,tab); + ptemp.uValue = parm->uValue; + + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + type = mytype; + mdfast = (thismodel->INPmodfast); + } else { + type = mytype; + if(!tab->defWmod) { + /* create deafult W model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"W",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defWmod),uid)) + } + mdfast = tab->defWmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + + GCA(INPpName,("control",&ptemp,ckt,type,fast)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + /* ignore a number */ + } +} diff --git a/src/circuit/inp2z.c b/src/circuit/inp2z.c new file mode 100644 index 000000000..0db46a852 --- /dev/null +++ b/src/circuit/inp2z.c @@ -0,0 +1,83 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpmacs.h" +#include "fteext.h" +#include "inp.h" + +void +INP2Z(void *ckt, INPtables *tab, card *current) +{ + + /* Zname [] [OFF] [IC=,] */ + +int mytype; /* the type we looked up */ +int type; /* the type the model says it is */ +char *line; /* the part of the current line left to parse */ +char *name; /* the resistor's name */ +char *nname1; /* the first node's name */ +char *nname2; /* the second node's name */ +char *nname3; /* the third node's name */ +void *node1; /* the first node's node pointer */ +void *node2; /* the second node's node pointer */ +void *node3; /* the third node's node pointer */ +int error; /* error code temporary */ +void *fast; /* pointer to the actual instance */ +IFvalue ptemp; /* a value structure to package resistance into */ +int waslead; /* flag to indicate that funny unlabeled number was found */ +double leadval; /* actual value of unlabeled number */ +char *model; /* the name of the model */ +INPmodel *thismodel; /* pointer to model description for user's model */ +void *mdfast; /* pointer to the actual model */ +IFuid uid; /* uid for default model */ + + mytype = INPtypelook("MES"); + if(mytype < 0 ) { + LITERR("Device type MES not supported by this binary\n") + return; + } + line = current->line; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + INPgetTok(&line,&nname1,1); + INPtermInsert(ckt,&nname1,tab,&node1); + INPgetTok(&line,&nname2,1); + INPtermInsert(ckt,&nname2,tab,&node2); + INPgetTok(&line,&nname3,1); + INPtermInsert(ckt,&nname3,tab,&node3); + INPgetTok(&line,&model,1); + INPinsert(&model,tab); + thismodel = (INPmodel *)NULL; + current->error = INPgetMod(ckt,model,&thismodel,tab); + if(thismodel != NULL) { + if(mytype != thismodel->INPmodType) { + LITERR("incorrect model type") + return; + } + type = mytype; + mdfast = (thismodel->INPmodfast); + } else { + type = mytype; + if(!tab->defZmod) { + /* create default Z model */ + IFnewUid(ckt,&uid,(IFuid)NULL,"Z",UID_MODEL,(void**)NULL); + IFC(newModel,(ckt,type,&(tab->defZmod),uid)) + } + mdfast = tab->defZmod; + } + IFC(newInstance,(ckt,mdfast,&fast,name)) + IFC(bindNode,(ckt,fast,1,node1)) + IFC(bindNode,(ckt,fast,2,node2)) + IFC(bindNode,(ckt,fast,3,node3)) + PARSECALL((&line,ckt,type,fast,&leadval,&waslead,tab)) + if(waslead) { + ptemp.rValue = leadval; + GCA(INPpName,("area",&ptemp,ckt,type,fast)) + } +} diff --git a/src/circuit/inpaname.c b/src/circuit/inpaname.c new file mode 100644 index 000000000..a461a7cac --- /dev/null +++ b/src/circuit/inpaname.c @@ -0,0 +1,68 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + * INPaName() + * + * Take a parameter by Name and ask for the specified value + * *dev is -1 if type unknown, otherwise, device type + * **fast is a device, and will be set if possible. + */ + +#include "ngspice.h" +#include +#include "cpdefs.h" +#include "fteext.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "inp.h" + +int +INPaName(char *parm, IFvalue *val, void *ckt, int *dev, char *devnam, void **fast, IFsimulator *sim, int *dataType, IFvalue *selector) + /* the name of the parameter to set */ + /* the parameter union containing the value to set */ + /* the circuit this device is a member of */ + /* the device type code to the device being parsed */ + /* the name of the device */ + /* direct pointer to device being parsed */ + /* the simulator data structure */ + /* the datatype of the returned value structure */ + /* data sub-selector for questions */ + +{ + int error; /* int to store evaluate error return codes in */ + int i; + + /* find the instance - don't know about model, so use null there, + * otherwise pass on as much info as we have about the device + * (name, type, direct pointer) - the type and direct pointer + * WILL be set on return unless error is not OK + */ + error = (*(sim->findInstance))(ckt,dev,fast,devnam,(void *)NULL, + (char *)NULL); + if(error) return(error); + + /* now find the parameter - hunt through the parameter tables for + * this device type and look for a name match of an 'ask'able + * parameter. + */ + for(i=0;i<(*(*(sim->devices)[*dev]).numInstanceParms);i++) { + if(strcmp(parm, + ((*(sim->devices)[*dev]).instanceParms[i].keyword))==0 && + (((*(sim->devices)[*dev]).instanceParms[i].dataType)&IF_ASK)) { + /* found it, so we ask the question using the device info we got + * above and put the results in the IFvalue structure our caller + * gave us originally + */ + error = (*(sim->askInstanceQuest))(ckt,*fast, + (*(sim->devices)[*dev]).instanceParms[i].id,val, + selector); + if(dataType) *dataType = + (*(sim->devices)[*dev]).instanceParms[i].dataType; + return(error); + } + } + return(E_BADPARM); +} diff --git a/src/circuit/inpapnam.c b/src/circuit/inpapnam.c new file mode 100644 index 000000000..88a53cd87 --- /dev/null +++ b/src/circuit/inpapnam.c @@ -0,0 +1,30 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "cpdefs.h" +#include "fteext.h" +#include "inp.h" + +int +INPapName(void *ckt, int type, void *analPtr, char *parmname, IFvalue *value) +{ + int i; + + if (parmname && ft_sim->analyses[type]) { + for(i=0;ianalyses[type]->numParms;i++) + if (strcmp(parmname, + ft_sim->analyses[type]->analysisParms[i].keyword) == 0) + { + return (*(ft_sim->setAnalysisParm))(ckt, analPtr, + ft_sim->analyses[type]->analysisParms[i].id, + value, (IFvalue*)NULL); + } + } + return(E_BADPARM); +} diff --git a/src/circuit/inpcfix.c b/src/circuit/inpcfix.c new file mode 100644 index 000000000..a0969b1bd --- /dev/null +++ b/src/circuit/inpcfix.c @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "fteext.h" +#include "inpdefs.h" +#include "inp.h" + + +void +INPcaseFix(register char *string) +{ + + while(*string) { + if(isupper(*string)) { + *string = tolower(*string); + } + string++; + } +} diff --git a/src/circuit/inpdomod.c b/src/circuit/inpdomod.c new file mode 100644 index 000000000..f5bbc41e0 --- /dev/null +++ b/src/circuit/inpdomod.c @@ -0,0 +1,227 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "iferrmsg.h" +#include "inpdefs.h" +#include "inp.h" + + +char * +INPdomodel(void *ckt, card *image, INPtables *tab) +{ + + char *modname; + int type=-1; + int lev; + char *typename; + char *err = (char *)NULL; + char *line; + + line = image->line; + INPgetTok(&line,&modname,1); /* throw away '.model' */ + INPgetTok(&line,&modname,1); + INPinsert(&modname,tab); + INPgetTok(&line,&typename,1); + if( (strcmp(typename,"npn") == 0)||(strcmp(typename,"pnp")==0) ) { + type = INPtypelook("BJT"); + if(type < 0) { + err = INPmkTemp("Device type BJT not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if(strcmp(typename,"d") == 0) { + type = INPtypelook("Diode"); + if(type < 0) { + err = INPmkTemp("Device type Diode not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if( (strcmp(typename,"njf") == 0) || (strcmp(typename,"pjf") == 0)){ + err = INPfindLev(line,&lev); + switch(lev) { + case 0: + case 1: + type = INPtypelook("JFET"); + if(type < 0) { + err = INPmkTemp( + "Device type JFET not available in this binary\n"); + } + break; + case 2: + type = INPtypelook("JFET2"); + if(type < 0) { + err = INPmkTemp( + "Device type JFET2 not available in this binary\n"); + } + break; + default: /* placeholder; use level 3 for the next model */ + err = INPmkTemp( + "Only JFET device levels 1-2 are supported in this binary\n"); + break; + } + INPmakeMod(modname,type,image); + } else if( (strcmp(typename,"nmf") == 0) || (strcmp(typename,"pmf")==0) ) { + type = INPtypelook("MES"); + if(type < 0) { + err = INPmkTemp("Device type MES not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if(strcmp(typename,"urc") == 0) { + type = INPtypelook("URC"); + if(type < 0) { + err = INPmkTemp("Device type URC not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if( (strcmp(typename,"nmos")==0) || (strcmp(typename,"pmos")==0) ) { + err = INPfindLev(line,&lev); + switch(lev) { + case 0: + case 1: + type = INPtypelook("Mos1"); + if(type < 0) { + err = INPmkTemp( + "Device type MOS1 not available in this binary\n"); + } + break; + case 2: + type = INPtypelook("Mos2"); + if(type < 0) { + err = INPmkTemp( + "Device type MOS2 not available in this binary\n"); + } + break; + case 3: + type = INPtypelook("Mos3"); + if(type < 0) { + err = INPmkTemp( + "Device type MOS3 not available in this binary\n"); + } + break; + case 4: + type = INPtypelook("BSIM1"); + if(type < 0) { + err = INPmkTemp( + "Device type BSIM1 not available in this binary\n"); + } + break; + case 5: + type = INPtypelook("BSIM2"); + if(type < 0) { + err = INPmkTemp( + "Device type BSIM2 not available in this binary\n"); + } + break; + case 6: + type = INPtypelook("Mos6"); + if(type < 0) { + err = INPmkTemp( + "Device type MOS6 not available in this binary\n"); + } + break; + case 7: + type = INPtypelook("MOS7"); + if(type < 0) { + err = INPmkTemp( + "Device type MOS7 not available in this binary\n"); + } + break; + case 8: + type = INPtypelook("BSIM3"); + if(type < 0) { + err = INPmkTemp( + "Device type BSIM3 not available in this binary\n"); + } + break; + case 9: + type = INPtypelook("BSIMsoi"); + if(type < 0) { + err = INPmkTemp( + "Device type BSIMsoi not available in this binary\n"); + } + break; + case 14: + type = INPtypelook("BSIM4"); + if(type < 0) { + err = INPmkTemp( + "Device type BSIM4 not available in this binary\n"); } + break; + case 15: + type = INPtypelook("BSIM5"); + if(type < 0) { + err = INPmkTemp( + "Placeholder: Device type BSIM5 not available in this binary\n"); + } + break; + case 16: + type = INPtypelook("BSIM6"); + if(type < 0) { + err = INPmkTemp( + "Placeholder: Device type BSIM6 not available in this binary\n"); + } + break; + case 49: + type = INPtypelook("BSIM3V1"); + if (type < 0) { + err = INPmkTemp( + "Device type BSIM3V1 not available in this binary\n"); + } + break; + + + case 50: + type = INPtypelook("BSIM3V2"); + if(type < 0) { + err = INPmkTemp( + "Device type BSIM3V2 not available in this binary\n"); + } + break; + default: /* placeholder; use level xxx for the next model */ + err = INPmkTemp( + "Only MOS device levels 1-6,8,14 are supported in this binary\n"); + break; + } + INPmakeMod(modname,type,image); + } else if(strcmp(typename,"r") == 0) { + type = INPtypelook("Resistor"); + if(type < 0) { + err = INPmkTemp( + "Device type Resistor not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if(strcmp(typename,"c") == 0) { + type = INPtypelook("Capacitor"); + if(type < 0) { + err = INPmkTemp( + "Device type Capacitor not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if(strcmp(typename,"sw") == 0) { + type = INPtypelook("Switch"); + if(type < 0) { + err = INPmkTemp( + "Device type Switch not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if(strcmp(typename,"csw") == 0) { + type = INPtypelook("CSwitch"); + if(type < 0) { + err = INPmkTemp( + "Device type CSwitch not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else if(strcmp(typename,"ltra") == 0) { + type = INPtypelook("LTRA"); + if(type < 0) { + err = INPmkTemp( + "Device type LTRA not available in this binary\n"); + } + INPmakeMod(modname,type,image); + } else { + type = -1; + err = (char *)MALLOC(35 + strlen(typename)); + (void)sprintf(err,"unknown model type %s - ignored\n",typename); + } + return(err); +} diff --git a/src/circuit/inpdoopt.c b/src/circuit/inpdoopt.c new file mode 100644 index 000000000..baa937ee4 --- /dev/null +++ b/src/circuit/inpdoopt.c @@ -0,0 +1,82 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* INPdoOpts(ckt,option card) + * parse the options off of the given option card and add them to + * the given circuit + */ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "ifsim.h" +#include "cpdefs.h" +#include "fteext.h" +#include "inp.h" + +void +INPdoOpts(void *ckt, void *anal, card *optCard, INPtables *tab) +{ + char *line; + char *token; + char *errmsg; + IFvalue *val; + int error; + int i; + int which; + IFanalysis *prm=NULL; + + which = -1; + i=0; + for(i=0;inumAnalyses;i++) { + prm = ft_sim->analyses[i]; + if(strcmp(prm->name,"options")==0) { + which = i; + break; + } + i++; + } + if(which == -1) { + optCard->error = INPerrCat(optCard->error,INPmkTemp( + "errr: analysis options table not found\n")); + return; + } + line = optCard->line; + INPgetTok(&line,&token,1); /* throw away '.option' */ + while (*line) { + INPgetTok(&line,&token,1); + for(i=0;inumParms;i++) { + if(strcmp(token,prm->analysisParms[i].keyword) == 0) { + if(!(prm->analysisParms[i].dataType & IF_UNIMP_MASK)) { + errmsg = (char *)MALLOC((45+strlen(token)) * sizeof(char)); + (void) sprintf(errmsg, + " Warning: %s not yet implemented - ignored \n",token); + optCard->error = INPerrCat(optCard->error,errmsg); + val = INPgetValue(ckt,&line, + prm->analysisParms[i].dataType, tab); + break; + } + if(prm->analysisParms[i].dataType & IF_SET) { + val = INPgetValue(ckt,&line, + prm->analysisParms[i].dataType&IF_VARTYPES, tab); + error = (*(ft_sim->setAnalysisParm))(ckt,anal, + prm->analysisParms[i].id,val,(IFvalue*)NULL); + if(error) { + errmsg =(char *)MALLOC((35+strlen(token))*sizeof(char)); + (void) sprintf(errmsg, + "Warning: can't set optione %s\n", token); + optCard->error = INPerrCat(optCard->error, errmsg); + } + break; + } + } + } + if(i == prm->numParms) { + errmsg = (char *)MALLOC(100 * sizeof(char)); + (void) strcpy(errmsg," Error: unknown option - ignored\n"); + optCard->error = INPerrCat(optCard->error,errmsg); + } + } +} diff --git a/src/circuit/inpdpar.c b/src/circuit/inpdpar.c new file mode 100644 index 000000000..0d8def06c --- /dev/null +++ b/src/circuit/inpdpar.c @@ -0,0 +1,74 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + * INPdevParse() + * + * parse a given input according to the standard rules - look + * for the parameters given in the parmlists, In addition, + * an optional leading numeric parameter is handled. + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "iferrmsg.h" +#include "cpdefs.h" +#include "fteext.h" +#include "inp.h" + +char * +INPdevParse(char **line, void *ckt, int dev, void *fast, double *leading, int *waslead, INPtables *tab) + /* the line to parse */ + /* the circuit this device is a member of */ + /* the device type code to the device being parsed */ + /* direct pointer to device being parsed */ + /* the optional leading numeric parameter */ + /* flag - 1 if leading double given, 0 otherwise */ + + +{ + int error; /* int to store evaluate error return codes in */ + char *parm; + char *errbuf; + int i; + IFvalue *val; + + /* check for leading value */ + *waslead = 0; + *leading = INPevaluate(line,&error,1); + if(error == 0) { /* found a good leading number */ + *waslead = 1; + } else *leading=0.0; + while (**line != (char) 0) { + error = INPgetTok(line,&parm,1); + if (!*parm) + continue; + if(error) return(INPerror(error)); + for(i=0;i<(*(*(ft_sim->devices)[dev]).numInstanceParms);i++) { + if(strcmp(parm, + ((*(ft_sim->devices)[dev]).instanceParms[i].keyword)) ==0) { + val = INPgetValue(ckt,line, + ((*(ft_sim->devices)[dev]).instanceParms[i].dataType), + tab); + if (!val) + return (INPerror(E_PARMVAL)); + error = (*(ft_sim->setInstanceParm))(ckt,fast, + (*(ft_sim->devices)[dev]).instanceParms[i].id, + val,(IFvalue*)NULL); + if(error) return(INPerror(error)); + break; + } + } + if(i==(*(*(ft_sim->devices)[dev]).numInstanceParms)) { + errbuf = MALLOC(strlen(parm)+25); + (void)sprintf(errbuf," unknown parameter (%s) \n",parm); + return(errbuf); + } + FREE(parm); + } + return((char *)NULL); +} diff --git a/src/circuit/inperrc.c b/src/circuit/inperrc.c new file mode 100644 index 000000000..44d8b559e --- /dev/null +++ b/src/circuit/inperrc.c @@ -0,0 +1,34 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "inp.h" + + +char * +INPerrCat(char *a, char *b) +{ + + if(a != (char *)NULL) { + if(b == (char *)NULL) { /* a valid, b null, return a */ + return(a); + } else { /* both valid - hard work...*/ + register char *errtmp; + errtmp = (char *)MALLOC( (strlen(a) + strlen(b)+2)*sizeof(char)); + (void) strcpy(errtmp,a); + (void) strcat(errtmp,"\n"); + (void) strcat(errtmp,b); + FREE(a); + FREE(b); + return(errtmp); + } + } else { /* a null, so return b */ + return(b); + } +} diff --git a/src/circuit/inperror.c b/src/circuit/inperror.c new file mode 100644 index 000000000..265415b8c --- /dev/null +++ b/src/circuit/inperror.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * provide the error message appropriate for the given error code + */ + +#include "ngspice.h" +#include +#include "fteext.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "sperror.h" +#include "inp.h" + +char * +INPerror(int type) +{ + char *val; + char ebuf[513]; + + val = SPerror(type); + + if (!val) + return(val); + + if(errRtn) + sprintf(ebuf, "%s detected in routine \"%s\"\n", val, errRtn); + else + sprintf(ebuf, "%s\n", val); + + FREE(val); + val = MALLOC(strlen(ebuf) + 1); + if (val) + strcpy(val, ebuf); + + return(val); +} + diff --git a/src/circuit/inpeval.c b/src/circuit/inpeval.c new file mode 100644 index 000000000..1f72902cb --- /dev/null +++ b/src/circuit/inpeval.c @@ -0,0 +1,172 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include +#include "inpdefs.h" +#include "inp.h" + +double +INPevaluate(char **line, int *error, int gobble) + /* non-zero to gobble rest of token, zero to leave it alone */ +{ + char * token; + char * here; + double mantis; + int expo1; + int expo2; + int sign; + int expsgn; + char * tmpline; + + /* setup */ + tmpline = *line; + if(gobble) { + *error = INPgetUTok(line,&token,1); + if(*error) return((double)0.0); + } else { + token = *line; + *error = 0; + } + mantis=0; + expo1=0; + expo2=0; + sign=1; + expsgn=1; + /* loop through all of the input token */ + here = token; + if(*here == '+') here++; /* plus, so do nothing except skip it */ + if(*here == '-') { /* minus, so skip it, and change sign */ + here++; + sign = -1; + } + if( (*here == 0) || ((!(isdigit(*here))) && (*here != '.'))) { + /* number looks like just a sign! */ + *error = 1; + /* back out the 'gettok' operation */ + *line = tmpline; + if(gobble) { FREE(token); }else{ *line=here;} + return(0); + } + while(isdigit(*here)) { + /* digit, so accumulate it. */ + mantis=10*mantis+*here-'0'; + here++; + } + if(*here == 0) { + /* reached the end of token - done. */ + if(gobble) { FREE(token); }else{ *line=here;} + return ((double)mantis*sign); + } + if(*here == ':') { + /* hack for subcircuit node numbering */ + *error = 1; + *line = tmpline; + return 0.0; + } + /* after decimal point! */ + if(*here == '.') { + /* found a decimal point! */ + here++; /* skip to next character */ + if(*here == 0) { + /* number ends in the decimal point */ + if(gobble) { FREE(token); }else{ *line=here;} + return ((double)mantis*sign); + } + while(isdigit(*here)) { + /* digit, so accumulate it. */ + mantis=10*mantis+*here - '0'; + expo1=expo1-1; + if(*here == 0) { + /* reached the end of token - done. */ + if(gobble) { FREE(token); }else{ *line=here;} + return (mantis*sign*pow(10.,(double)expo1)); + } + here++; + } + } + /* now look for "E","e",etc to indicate an exponent */ + if((*here == 'E') || (*here == 'e') || (*here == 'D') || (*here == 'd') ) { + /* have an exponent, so skip the e */ + here++; + /* now look for exponent sign */ + if(*here == '+') here++; /* just skip + */ + if(*here == '-') { + here++; /* skip over minus sign */ + expsgn = -1; /* and make a negative exponent */ + /* now look for the digits of the exponent */ + } + while (isdigit(*here)) { + expo2=10*expo2+*here - '0'; + here++; + } + } + /* now we have all of the numeric part of the number, time to + * look for the scale factor (alphabetic) + */ + switch(*here) { + case 't': + case 'T': + expo1=expo1+12; + break; + case 'g': + case 'G': + expo1=expo1+9; + break; + case 'k': + case 'K': + expo1=expo1+3; + break; + case 'u': + case 'U': + expo1=expo1-6; + break; + case 'n': + case 'N': + expo1=expo1-9; + break; + case 'p': + case 'P': + expo1=expo1-12; + break; + case 'f': + case 'F': + expo1=expo1-15; + break; + case 'm': + case 'M': + { + /* special case for m - may be m or mil or meg */ + if(*(here+1) != 0 && *(here+2) != 0) { + /* at least 2 characters, so check them. */ + if((*(here+1) == 'E') || (*(here+1) == 'e')) { + if((*(here+2) == 'G') || (*(here+2) == 'g')) { + expo1=expo1+6; + if(gobble) { FREE(token); }else{ *line=here;} + return (sign*mantis* + pow((double)10,(double)(expo1+expsgn*expo2))); + } + } + else if ((*(here+1) == 'I') || (*(here+1) == 'i')) { + if( (*(here+2) == 'L') || (*(here+2) == 'l')) { + expo1=expo1-6; + mantis=mantis*25.4; + if(gobble) { FREE(token); }else{ *line=here;} + return (sign*mantis* + pow((double)10,(double)(expo1+expsgn*expo2))); + } + } + } + /* not either special case, so just m => 1e-3 */ + expo1=expo1-3; + } + break; + default: + break; + } + if(gobble) { FREE(token); }else{ *line=here;} + return (sign*mantis*pow((double)10,(double)(expo1+expsgn*expo2))); +} diff --git a/src/circuit/inpfindl.c b/src/circuit/inpfindl.c new file mode 100644 index 000000000..02504b0e2 --- /dev/null +++ b/src/circuit/inpfindl.c @@ -0,0 +1,67 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: 1999 Paolo Nenzi - Now we can use a two digits level code - +**********/ + + /* INPfindLev(line,level) + * find the 'level' parameter on the given line and return its + * value (1,2,..,99 for now, 1 default) + * + */ + +#include "ngspice.h" +#include +#include +#include "inpdefs.h" +#include "inp.h" + +char * +INPfindLev(char *line, int *level) +{ + char *where; + + where = line; + + where=strstr(line, "level"); + + if (where!=NULL) { /* found a level keyword on the line */ + + where += 5; /* skip the level keyword */ + while( (*where == ' ') || (*where == '\t') || (*where == '=') || + (*where == ',') || (*where == '(') || (*where == ')') || + (*where == '+') ) { /* legal white space - ignore */ + where++; + } + + /* now the magic number */ + sscanf(where,"%2d",level); /* We get the level number */ + if (*level<0) { + *level=1; + printf("Illegal value for level.\n"); + printf("Level must be >0 (Setting level to 1)\n"); + return(INPmkTemp(" illegal (negative) argument to level parameter - level=1 assumed")); + } + + if (*level>99) { /* Limit to change in the future */ + *level=1; + printf("Illegal value for level.\n"); + printf("Level must be <99 (Setting Level to 1)\n"); + return(INPmkTemp(" illegal (too high) argument to level parameter - level=1 assumed")); + } + + return((char *)NULL); + } + + + + else { /* no level on the line => default */ + *level = 1; + printf("Level not specified: Using level 1.\n"); + return((char *)NULL); + } + + + + +} diff --git a/src/circuit/inpgmod.c b/src/circuit/inpgmod.c new file mode 100644 index 000000000..465142bd8 --- /dev/null +++ b/src/circuit/inpgmod.c @@ -0,0 +1,98 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "ifsim.h" +#include "cpstd.h" +#include "fteext.h" +#include "inp.h" + +extern INPmodel *modtab; + +char * +INPgetMod(void *ckt, char *name, INPmodel **model, INPtables *tab) +{ + INPmodel *modtmp; + IFvalue * val; + register int j; + char * line; + char *parm; + char *err = NULL; + char *temp; + int error; + + for (modtmp = modtab;modtmp != (INPmodel *)NULL;modtmp = + ((modtmp)->INPnextModel)) { + if (strcmp((modtmp)->INPmodName,name) == 0) { + /* found the model in question - now instantiate if necessary */ + /* and return an appropriate pointer to it */ + if(modtmp->INPmodType<0) { + /* illegal device type, so can't handle */ + *model = (INPmodel *)NULL; + err = (char *)MALLOC((35+strlen(name)) * sizeof(char)); + (void) sprintf(err, + "Unknown device type for model %s \n",name); + return(err); + } + if(! ((modtmp)->INPmodUsed )) { + /* not already defined, so create & give parameters */ + error = (*(ft_sim->newModel))( ckt,(modtmp)->INPmodType, + &((modtmp)->INPmodfast), (modtmp)->INPmodName); + if(error) return(INPerror(error)); + /* parameter isolation, identification, binding */ + line = ((modtmp)->INPmodLine)->line; + INPgetTok(&line,&parm,1); /* throw away '.model' */ + INPgetTok(&line,&parm,1); /* throw away 'modname' */ + while(*line != 0) { + INPgetTok(&line,&parm,1); + if (!*parm) + continue; + for(j=0;j<(*(*(ft_sim->devices)[(modtmp)->INPmodType]). + numModelParms); j++) { + if (strcmp(parm,((*(ft_sim->devices) [ (modtmp)-> + INPmodType ]).modelParms[j].keyword)) == 0) { + val = INPgetValue(ckt,&line, + ((*(ft_sim->devices)[(modtmp)-> + INPmodType ]).modelParms[j]. + dataType),tab); + error = (*(ft_sim->setModelParm))(ckt, + ((modtmp)->INPmodfast), + (*(ft_sim->devices)[(modtmp)->INPmodType ]). + modelParms[j].id,val,(IFvalue*)NULL); + if(error) return(INPerror(error)); + break; + } + } + if (strcmp(parm,"level")==0) { + /* just grab the level number and throw away */ + /* since we already have that info from pass1 */ + val = INPgetValue(ckt,&line,IF_REAL,tab); + } else if(j >= + (*(*(ft_sim->devices)[(modtmp)->INPmodType]). + numModelParms)) { + temp = (char *)MALLOC((40+strlen(parm)) * sizeof(char)); + (void)sprintf(temp, + "unrecognized parameter (%s) - ignored\n", parm); + err = INPerrCat(err,temp); + } + FREE(parm); + } + (modtmp)->INPmodUsed=1; + (modtmp)->INPmodLine->error = err; + } + *model = modtmp; + return((char *)NULL); + } + } + /* didn't find model - ERROR - return model */ + *model = (INPmodel *)NULL; + err = (char *)MALLOC((60+strlen(name)) * sizeof(char)); + (void) sprintf(err, + " unable to find definition of model %s - default assumed \n",name); + return(err); +} + diff --git a/src/circuit/inpgstr.c b/src/circuit/inpgstr.c new file mode 100644 index 000000000..f6208fd45 --- /dev/null +++ b/src/circuit/inpgstr.c @@ -0,0 +1,73 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * Get string input token from 'line', and return a pointer to it in 'token' + */ + +#include "ngspice.h" +#include +#include "iferrmsg.h" +#include "inpdefs.h" +#include "inp.h" + +int +INPgetStr(char **line, char **token, int gobble) + /* eat non-whitespace trash AFTER token? */ +{ + char *point; + char separator = '\0'; + + /* Scan along throwing away garbage characters. */ + for (point = *line; *point != '\0'; point++) { + if ( (*point == ' ') || + (*point == '\t') || + (*point == '=') || + (*point == '(') || + (*point == ')') || + (*point == ',') ) continue; + break; + } + if (*point == '"') { + separator = '"'; + point++; + } else if (*point == '\'') { + separator = '\''; + point++; + } + /* mark beginning of token */ + *line = point; + /* now find all good characters */ + for (point = *line; *point != '\0'; point++) { + if ( (*point == ' ') || + (*point == '\t') || + (*point == '=') || + (*point == '(') || + (*point == ')') || + (*point == ',') || + (*point == separator) ) break; + } + + /* Create token */ + *token = (char *) MALLOC(1 + point - *line); + if (!*token) + return (E_NOMEM); + (void) strncpy(*token, *line, point - *line); + *(*token + (point - *line)) = '\0'; + *line = point; + + /* Gobble garbage to next token. */ + if (separator && **line == separator) { + (*line)++; /* Skip one closing separator */ + } + for (; **line != '\0'; (*line)++) { + if(**line == ' ') continue; + if(**line == '\t') continue; + if((**line == '=') && gobble) continue; + if((**line == ',') && gobble) continue; + break; + } + return (OK); +} diff --git a/src/circuit/inpgtitl.c b/src/circuit/inpgtitl.c new file mode 100644 index 000000000..ff5b679a7 --- /dev/null +++ b/src/circuit/inpgtitl.c @@ -0,0 +1,29 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* INPgetTitle(ckt,data) + * get the title card from the specified data deck and pass + * it through to SPICE-3. + */ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "iferrmsg.h" +#include "cpstd.h" +#include "fteext.h" +#include "inp.h" + +int +INPgetTitle(void **ckt, card **data) +{ + int error; + + error = (*(ft_sim->newCircuit))(ckt); + if(error) return(error); + *data = (*data)->nextcard; + return(OK); +} + diff --git a/src/circuit/inpgtok.c b/src/circuit/inpgtok.c new file mode 100644 index 000000000..925ee3803 --- /dev/null +++ b/src/circuit/inpgtok.c @@ -0,0 +1,179 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* get input token from 'line', + * and return a pointer to it in 'token' + */ + +/* INPgetTok: node names + INPgetUTok: numbers and other elements in expressions + (called from INPevaluate) + */ + +#include "ngspice.h" +#include +#include "iferrmsg.h" +#include "inpdefs.h" +#include "inp.h" + +int +INPgetTok(char **line, char **token, int gobble) + /* eat non-whitespace trash AFTER token? */ +{ + char * point; + int signstate; + + /* scan along throwing away garbage characters */ + for(point = *line;*point != '\0' ; point++ ) { + if(*point == ' ') continue; + if(*point == '\t') continue; + if(*point == '=') continue; + if(*point == '(') continue; + if(*point == ')') continue; + if(*point == ',') continue; + break; + } + /* mark beginning of token */ + *line = point; + /* now find all good characters */ + signstate = 0; + for(point = *line;*point!='\0';point++) { + if(*point == ' ') break; + if(*point == '\t') break; + if(*point == '=') break; + if(*point == '(') break; + if(*point == ')') break; + if(*point == ',') break; + /* This is not complex enough to catch all errors, but it will get the "good" parses */ + if(*point == '+' && (signstate == 1 || signstate == 3)) break; + if(*point == '-' && (signstate == 1 || signstate == 3)) break; + if(*point == '*') break; + if(*point == '/') break; + if(*point == '^') break; + if (isdigit(*point) || *point == '.') { + if (signstate > 1) + signstate = 3; + else + signstate = 1; + } else if (tolower(*point) == 'e' && signstate == 1) + signstate = 2; + else + signstate = 3; + + } + if (point == *line && *point) /* Weird items, 1 char */ + point++; + *token=(char *)MALLOC(1+point-*line); + if(!*token) return(E_NOMEM); + (void) strncpy(*token,*line,point-*line); + *(*token + (point-*line)) = '\0'; + *line = point; + /* gobble garbage to next token */ + for( ;**line != '\0' ; (*line)++ ) { + if(**line == ' ') continue; + if(**line == '\t') continue; + if((**line == '=') && gobble) continue; + if((**line == ',') && gobble) continue; +#ifdef notdef + /* This is the wrong thing to do for expression-valued parameters. The + parens will get taken out at the beginning, leave them here for + parse trees */ + if((**line == /* (match */')') && gobble) continue; + if((**line == '(' /* match) */) && gobble) continue; +#endif + break; + } + /*printf("found token (%s) and rest of line (%s)\n",*token,*line);*/ + return(OK); +} + +int +INPgetUTok(char **line, char **token, int gobble) + + + /* eat non-whitespace trash AFTER token? */ +{ + char * point, separator; + int signstate; + /* scan along throwing away garbage characters */ + for(point = *line;*point != '\0' ; point++ ) { + if(*point == ' ') continue; + if(*point == '\t') continue; + if(*point == '=') continue; + if(*point == '(') continue; + if(*point == ')') continue; + if(*point == ',') continue; + break; + } + if (*point == '"') { + separator = '"'; + point++; + } else if (*point == '\'') { + separator = '\''; + point++; + } else + separator = 0; + + /* mark beginning of token */ + *line = point; + + /* now find all good characters */ + signstate = 0; + for(point = *line;*point!='\0';point++) { + if (separator) { + if (*point == separator) + break; + else + continue; + } + if(*point == ' ') break; + if(*point == '\t') break; + if(*point == '=') break; + if(*point == '(') break; + if(*point == ')') break; + if(*point == ',') break; + /* This is not complex enough to catch all errors, but it will + get the "good" parses */ + if(*point == '+' && (signstate == 1 || signstate == 3)) break; + if(*point == '-') { + if (signstate == 1 || signstate == 3) break; + signstate += 1; + continue; + } + if(*point == '*') break; + if(*point == '/') break; + if(*point == '^') break; + if (isdigit(*point) || *point == '.') { + if (signstate > 1) + signstate = 3; + else + signstate = 1; + } else if (tolower(*point) == 'e' && signstate == 1) + signstate = 2; + else + signstate = 3; + } + if (separator && *point == separator) + point--; + if (point == *line && *point) /* Weird items, 1 char */ + point++; + *token=(char *)MALLOC(1+point-*line); + if(!*token) return(E_NOMEM); + (void) strncpy(*token,*line,point-*line); + *(*token + (point-*line)) = '\0'; + /* gobble garbage to next token */ + for( ;*point != '\0' ; point++ ) { + if (*point == separator) + continue; + if(*point == ' ') continue; + if(*point == '\t') continue; + if((*point == '=') && gobble) continue; + if((*point == ',') && gobble) continue; + break; + } + *line = point; + /* printf("found token (%s) and rest of line (%s)\n",*token,*line); */ + return(OK); +} diff --git a/src/circuit/inpgval.c b/src/circuit/inpgval.c new file mode 100644 index 000000000..31129be7c --- /dev/null +++ b/src/circuit/inpgval.c @@ -0,0 +1,78 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inpdefs.h" +#include "inpptree.h" +#include "inp.h" + +IFvalue * +INPgetValue(void *ckt, char **line, int type, INPtables *tab) +{ + double *list; + int *ilist; + double tmp; + char *word; + int error; + static IFvalue temp; + INPparseTree *pt; + + /* make sure we get rid of extra bits in type */ + type &= IF_VARTYPES; + if(type == IF_INTEGER) { + temp.iValue = INPevaluate(line,&error,1); + /*printf(" returning integer value %d\n",temp.iValue);*/ + } else if (type == IF_REAL) { + temp.rValue = INPevaluate(line,&error,1); + /*printf(" returning real value %e\n",temp.rValue);*/ + } else if (type == IF_REALVEC) { + temp.v.numValue = 0; + list = (double *)MALLOC(sizeof(double)); + tmp = INPevaluate(line,&error,1); + while (error == 0) { + /*printf(" returning vector value %g\n",tmp); */ + temp.v.numValue++; + list=(double *)REALLOC((char *)list,temp.v.numValue*sizeof(double)); + *(list+temp.v.numValue-1) = tmp; + tmp = INPevaluate(line,&error,1); + } + temp.v.vec.rVec=list; + } else if (type == IF_INTVEC) { + temp.v.numValue = 0; + ilist = (int *)MALLOC(sizeof(int)); + tmp = INPevaluate(line,&error,1); + while (error == 0) { + /*printf(" returning vector value %g\n",tmp); */ + temp.v.numValue++; + ilist=(int *)REALLOC((char *)ilist,temp.v.numValue*sizeof(int)); + *(ilist+temp.v.numValue-1) = tmp; + tmp = INPevaluate(line,&error,1); + } + temp.v.vec.iVec=ilist; + } else if (type == IF_FLAG) { + temp.iValue = 1; + } else if (type == IF_NODE) { + INPgetTok(line,&word,1); + INPtermInsert(ckt,&word,tab,&(temp.nValue)); + } else if (type == IF_INSTANCE) { + INPgetTok(line,&word,1); + INPinsert(&word,tab); + temp.nValue = word; + } else if (type == IF_STRING) { + INPgetStr(line,&word,1); + temp.sValue = word; + } else if (type == IF_PARSETREE) { + INPgetTree(line, &pt, ckt, tab); + if (!pt) + return((IFvalue *)NULL); + temp.tValue = (IFparseTree *) pt; + /*INPptPrint("Parse tree is: ", temp.tValue);*/ + } else { /* don't know what type of parameter caller is talking about! */ + return((IFvalue *)NULL); + } + return(&temp); +} diff --git a/src/circuit/inpkmods.c b/src/circuit/inpkmods.c new file mode 100644 index 000000000..8981bc840 --- /dev/null +++ b/src/circuit/inpkmods.c @@ -0,0 +1,30 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "inp.h" + + +extern INPmodel *modtab; + +void +INPkillMods(void) +{ + INPmodel *modtmp; + INPmodel *prev = NULL; + + for (modtmp = modtab;modtmp != (INPmodel *)NULL;modtmp = + modtmp->INPnextModel) { + if(prev) FREE(prev); + prev = modtmp; + } + if(prev) FREE(prev); + modtab = (INPmodel *)NULL; +} + diff --git a/src/circuit/inplist.c b/src/circuit/inplist.c new file mode 100644 index 000000000..87e4e0e89 --- /dev/null +++ b/src/circuit/inplist.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* INPlist(file,deck,type) + * provide an input listing on the specified file of the given + * card deck. The listing should be of either PHYSICAL or LOGICAL + * lines as specified by the type parameter. + */ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "inp.h" + + +void +INPlist(FILE *file, card *deck, int type) +{ + + card *here; + card *there; + + if(type == LOGICAL) { + for(here = deck;here != NULL;here = here->nextcard) { + fprintf(file,"%6d : %s\n",here->linenum, here->line); + if(here->error != (char *)NULL) { + fprintf(file,"%s",here->error); + } + } + } else if (type == PHYSICAL) { + for(here = deck;here != NULL;here = here->nextcard) { + if(here->actualLine == (card *)NULL) { + fprintf(file,"%6d : %s\n",here->linenum,here->line); + if(here->error != (char *)NULL) { + fprintf(file,"%s",here->error); + } + } else { + for(there = here->actualLine;there != NULL; + there=there->nextcard) { + fprintf(file,"%6d : %s\n",there->linenum, there->line); + if(there->error != (char *)NULL) { + fprintf(file,"%s",there->error); + } + } + } + } + } +} + + diff --git a/src/circuit/inplkmod.c b/src/circuit/inplkmod.c new file mode 100644 index 000000000..38bfb0d09 --- /dev/null +++ b/src/circuit/inplkmod.c @@ -0,0 +1,31 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "inp.h" + + +extern INPmodel *modtab; + + +int +INPlookMod(char *name) +{ + register INPmodel **i; + + for (i = &modtab;*i != (INPmodel *)NULL;i = &((*i)->INPnextModel)) { + if (strcmp((*i)->INPmodName,name) == 0) { + /* found the model in question - return TRUE */ + return(1); + } + } + /* didn't find model - return FALSE */ + return(0); +} + diff --git a/src/circuit/inpmkmod.c b/src/circuit/inpmkmod.c new file mode 100644 index 000000000..d6819b738 --- /dev/null +++ b/src/circuit/inpmkmod.c @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "iferrmsg.h" +#include "inp.h" + +INPmodel *modtab; + + /* create/lookup a 'model' entry */ + +int +INPmakeMod(char *token, int type, card *line) +{ + register INPmodel **i; + + for (i = &modtab;*i != (INPmodel *)NULL;i = &((*i)->INPnextModel)) { + if (strcmp((*i)->INPmodName,token) == 0) { + return(OK); + } + } + *i = (INPmodel *)MALLOC(sizeof(INPmodel)); + if(*i==NULL) return(E_NOMEM); + (*i)->INPmodName = token; + (*i)->INPmodType = type; + (*i)->INPnextModel = (INPmodel *)NULL; + (*i)->INPmodUsed = 0; + (*i)->INPmodLine = line; + (*i)->INPmodfast = NULL; + return(OK); +} diff --git a/src/circuit/inpmktmp.c b/src/circuit/inpmktmp.c new file mode 100644 index 000000000..b2c9e102b --- /dev/null +++ b/src/circuit/inpmktmp.c @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "inp.h" + + +char * +INPmkTemp(char *string) +{ +int len; +char *temp; + + len = strlen(string); + temp = MALLOC(len+1); + if(temp!=(char *)NULL) (void)strcpy(temp,string); + return(temp); + +} diff --git a/src/circuit/inppas1.c b/src/circuit/inppas1.c new file mode 100644 index 000000000..a55d1114d --- /dev/null +++ b/src/circuit/inppas1.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "ifsim.h" +#include "inp.h" + +/* + * The first pass of the circuit parser just looks for '.model' lines + */ + +void +INPpas1(void *ckt, card *deck, INPtables *tab) +{ + card *current; + char *INPdomodel(void *ckt, card *image, INPtables *tab); + char *temp, *thisline; + + for(current = deck;current != NULL;current = current->nextcard) { + /* SPICE-2 keys off of the first character of the line */ + thisline = current->line; + + while (*thisline && ((*thisline == ' ') || (*thisline == '\t'))) + thisline++; + + if (*thisline == '.') { + if(strncmp(thisline,".model",6)==0) { + temp = INPdomodel(ckt,current,tab); + current->error = INPerrCat(current->error,temp); + } + } + + /* for now, we do nothing with the other cards - just + * keep them in the list for pass 2 + */ + } +} diff --git a/src/circuit/inppas2.c b/src/circuit/inppas2.c new file mode 100644 index 000000000..863e88917 --- /dev/null +++ b/src/circuit/inppas2.c @@ -0,0 +1,156 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cpdefs.h" +#include "fteext.h" +#include "ftedefs.h" +#include "inpdefs.h" +#include "iferrmsg.h" +#include "tskdefs.h" +#include "inpmacs.h" +#include "inp.h" + +/* pass 2 - Scan through the lines. ".model" cards have processed + * in pass1 and are ignored here. + */ + +void +INPpas2(void *ckt, card *data, INPtables *tab, void *task) +{ + +card *current; +char c; +char * groundname="0"; +char * gname; +void *gnode; +int error; /* used by the macros defined above */ + + error = INPgetTok(&groundname,&gname,1); + if(error) data->error = INPerrCat(data->error,INPmkTemp( + "can't read internal ground node name!\n")); + + error = INPgndInsert(ckt,&gname,tab,&gnode); + if(error && error!=E_EXISTS)data->error = INPerrCat(data->error,INPmkTemp( + "can't insert internal ground node in symbol table!\n")); + + for(current = data; current != NULL; current = current->nextcard) { + + c = *(current->line); + c = islower(c) ? toupper(c) : c; + + switch(c) { + + case ' ': /* blank line (space leading) */ + case '\t': /* blank line (tab leading) */ + break; + + case 'R': /* Rname [][][w=][l=] */ + INP2R(ckt,tab,current); + break; + case 'C': /* Cname [IC=] */ + INP2C(ckt,tab,current); + break; + case 'L': /* Lname [IC=] */ + INP2L(ckt,tab,current); + break; + case 'G': /* Gname */ + INP2G(ckt,tab,current); + break; + case 'E': /* Ename */ + INP2E(ckt,tab,current); + break; + case 'F': /* Fname */ + INP2F(ckt,tab,current); + break; + case 'H': /* Hname */ + INP2H(ckt,tab,current); + break; + case 'D': /* Dname [] [OFF] [IC=] */ + INP2D(ckt,tab,current); + break; + case 'J': /* Jname [] [OFF] + * [IC=,] */ + INP2J(ckt,tab,current); + break; + case 'Z': /* Zname [] [OFF] + * [IC=,] */ + INP2Z(ckt,tab,current); + break; + case 'M': /* Mname [L=] + * [W=] [AD=] [AS=] [PD=] + * [PS=] [NRD=] [NRS=] [OFF] + * [IC=,,] */ + INP2M(ckt,tab,current); + break; + + case 'O': /* Oname + * [IC=,,,] */ + INP2O(ckt,tab,current); + break; + + case 'V': /* Vname [ [DC] ] [AC [ [ ] ] ] + * [] */ + INP2V(ckt,tab,current); + break; + case 'I': /* Iname [ [DC] ] [AC [ [ ] ] ] + * [] */ + INP2I(ckt,tab,current); + break; + + case 'Q': /* Qname [] [] [OFF] + * [IC=,] */ + INP2Q(ckt,tab,current,gnode); + break; + + case 'T': /* Tname [TD=] + * [F= [NL=]][IC=,,,] */ + INP2T(ckt,tab,current); + break; + + case 'S': /* Sname [] [IC] */ + INP2S(ckt,tab,current); + break; + + case 'W': /* Wname [] [IC] */ + /* CURRENT CONTROLLED SWITCH */ + INP2W(ckt,tab,current); + break; + + case 'U': /* Uname [l=] [n=] */ + INP2U(ckt,tab,current); + break; + + case 'K': /* Kname Lname Lname */ + INP2K(ckt,tab,current); + break; + + case '*': /* * - a comment - ignore */ + break; + + case 'B': /* Bname [V=expr] [I=expr] */ + /* Arbitrary source. */ + INP2B(ckt,tab,current); + break; + + case '.': /* . Many possibilities */ + if (INP2dot(ckt,tab,current,task,gnode)) goto end; + break; + + case 0: + break; + + default: + /* the un-implemented device */ + LITERR(" unknown device type - error \n") + break; + } + } +end: + return; +} + diff --git a/src/circuit/inppname.c b/src/circuit/inppname.c new file mode 100644 index 000000000..3b8e78c2a --- /dev/null +++ b/src/circuit/inppname.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* + * INPpName() + * + * Take a parameter by Name and set it on the specified device + */ + +#include "ngspice.h" +#include +#include "cpdefs.h" +#include "fteext.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "inp.h" + +int +INPpName(char *parm, IFvalue *val, void *ckt, int dev, void *fast) + /* the name of the parameter to set */ + /* the parameter union containing the value to set */ + /* the circuit this device is a member of */ + /* the device type code to the device being parsed */ + /* direct pointer to device being parsed */ + +{ + int error; /* int to store evaluate error return codes in */ + int i; + + for(i=0;i<(*(*(ft_sim->devices)[dev]).numInstanceParms);i++) { + if(strcmp(parm, + ((*(ft_sim->devices)[dev]).instanceParms[i].keyword))==0) { + error = (*(ft_sim->setInstanceParm))(ckt,fast, (*(ft_sim-> + devices)[dev]).instanceParms[i].id,val,(IFvalue*)NULL); + if(error) return(error); + break; + } + } + if(i==(*(*(ft_sim->devices)[dev]).numInstanceParms)) { + return(E_BADPARM); + } + return(OK); +} diff --git a/src/circuit/inpptree.c b/src/circuit/inpptree.c new file mode 100644 index 000000000..80721bd28 --- /dev/null +++ b/src/circuit/inpptree.c @@ -0,0 +1,1087 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include +#include +#include "ifsim.h" +#include "iferrmsg.h" +#include "inpdefs.h" +#include "inpptree.h" +#include "inp.h" + +static INPparseNode * mkcon(double value); +static INPparseNode * mkb(int type, INPparseNode *left, INPparseNode *right); +static INPparseNode * mkf(int type, INPparseNode *arg); +static int PTcheck(INPparseNode *p); +static INPparseNode * PTparse(char **line); +static INPparseNode * makepnode(PTelement *elem); +static INPparseNode * mkbnode(int opnum, INPparseNode *arg1, INPparseNode *arg2); +static INPparseNode * mkfnode(char *fname, INPparseNode *arg); +static INPparseNode * mknnode(double number); +static INPparseNode * mksnode(char *string); +static INPparseNode * PTdifferentiate(INPparseNode *p, int varnum); +static PTelement * PTlexer(char **line); + +static IFvalue *values = NULL; +static int *types; +static int numvalues; +static void *circuit; +static INPtables *tables; + + + +extern IFsimulator *ft_sim; /* XXX */ + +/* Some tables that the parser uses. */ + +static struct op { + int number; + char *name; + double (*funcptr)(); +} ops[] = { + { PT_COMMA, ",", NULL } , + { PT_PLUS, "+", PTplus } , + { PT_MINUS, "-", PTminus } , + { PT_TIMES, "*", PTtimes } , + { PT_DIVIDE, "/", PTdivide } , + { PT_POWER, "^", PTpower } +} ; + +#define NUM_OPS (sizeof (ops) / sizeof (struct op)) + +static struct func { + char *name; + int number; + double (*funcptr)(); +} funcs[] = { + { "abs", PTF_ABS, PTabs } , + { "acos", PTF_ACOS, PTacos } , + { "acosh", PTF_ACOSH, PTacosh } , + { "asin", PTF_ASIN, PTasin } , + { "asinh", PTF_ASINH, PTasinh } , + { "atan", PTF_ATAN, PTatan } , + { "atanh", PTF_ATANH, PTatanh } , + { "cos", PTF_COS, PTcos } , + { "cosh", PTF_COSH, PTcosh } , + { "exp", PTF_EXP, PTexp } , + { "ln", PTF_LN, PTln } , + { "log", PTF_LOG, PTlog } , + { "sgn", PTF_SGN, PTsgn } , + { "sin", PTF_SIN, PTsin } , + { "sinh", PTF_SINH, PTsinh } , + { "sqrt", PTF_SQRT, PTsqrt } , + { "tan", PTF_TAN, PTtan } , + { "tanh", PTF_TANH, PTtanh } , + { "u", PTF_USTEP, PTustep } , + { "uramp", PTF_URAMP, PTuramp } , + { "-", PTF_UMINUS, PTuminus } +} ; + +#define NUM_FUNCS (sizeof (funcs) / sizeof (struct func)) + +/* These are all the constants any sane person needs. */ + +static struct constant { + char *name; + double value; +} constants[] = { + { "e", M_E }, + { "pi", M_PI } +} ; + +#define NUM_CONSTANTS (sizeof (constants) / sizeof (struct constant)) + +/* Parse the expression in *line as far as possible, and return the parse + * tree obtained. If there is an error, *pt will be set to NULL and an error + * message will be printed. + */ + +void +INPgetTree(char **line, INPparseTree **pt, void *ckt, INPtables *tab) +{ + INPparseNode *p; + int i; + + values = NULL; + types = NULL; + numvalues = 0; + + circuit = ckt; + tables = tab; + + p = PTparse(line); + + if (!p || !PTcheck(p)) { + *pt = NULL; + return; + } + + (*pt) = (INPparseTree *) MALLOC(sizeof (INPparseTree)); + + (*pt)->p.numVars = numvalues; + (*pt)->p.varTypes = types; + (*pt)->p.vars = values; + (*pt)->p.IFeval = IFeval; + (*pt)->tree = p; + + (*pt)->derivs = (INPparseNode **) + MALLOC(numvalues * sizeof (INPparseNode *)); + + for (i = 0; i < numvalues; i++) + (*pt)->derivs[i] = PTdifferentiate(p, i); + + return; +} + +/* This routine takes the partial derivative of the parse tree with respect to + * the i'th variable. We try to do optimizations like getting rid of 0-valued + * terms. + * + *** Note that in the interests of simplicity we share some subtrees between + *** the function and its derivatives. This means that you can't free the + *** trees. + */ + +static INPparseNode * +PTdifferentiate(INPparseNode *p, int varnum) +{ + INPparseNode *arg1, *arg2, *newp; + +/* printf("differentiating: "); printTree(p); printf(" wrt var %d\n", varnum);*/ + + switch (p->type) { + case PT_CONSTANT: + newp = mkcon((double) 0); + break; + + case PT_VAR: + /* Is this the variable we're differentiating wrt? */ + if (p->valueIndex == varnum) + newp = mkcon((double) 1); + else + newp = mkcon((double) 0); + break; + + case PT_PLUS: + case PT_MINUS: + arg1 = PTdifferentiate(p->left, varnum); + arg2 = PTdifferentiate(p->right, varnum); + newp = mkb(p->type, arg1, arg2); + break; + + case PT_TIMES: + /* d(a * b) = d(a) * b + d(b) * a */ + arg1 = PTdifferentiate(p->left, varnum); + arg2 = PTdifferentiate(p->right, varnum); + + newp = mkb(PT_PLUS, mkb(PT_TIMES, arg1, p->right), + mkb(PT_TIMES, p->left, arg2)); + break; + + case PT_DIVIDE: + /* d(a / b) = (d(a) * b - d(b) * a) / b^2 */ + arg1 = PTdifferentiate(p->left, varnum); + arg2 = PTdifferentiate(p->right, varnum); + + newp = mkb(PT_DIVIDE, mkb(PT_MINUS, mkb(PT_TIMES, arg1, + p->right), mkb(PT_TIMES, p->left, arg2)), + mkb(PT_POWER, p->right, mkcon((double) 2))); + break; + + case PT_POWER: + /* Two cases... If the power is a constant then we're cool. + * Otherwise we have to be tricky. + */ + if (p->right->type == PT_CONSTANT) { + arg1 = PTdifferentiate(p->left, varnum); + + newp = mkb(PT_TIMES, mkb(PT_TIMES, + mkcon(p->right->constant), + mkb(PT_POWER, p->left, + mkcon(p->right->constant - 1))), + arg1); + } else { + /* This is complicated. f(x) ^ g(x) -> + * exp(y(x) * ln(f(x)) ... + */ + arg1 = PTdifferentiate(p->left, varnum); + arg2 = PTdifferentiate(p->right, varnum); + newp = mkb(PT_TIMES, mkf(PTF_EXP, mkb(PT_TIMES, + p->right, mkf(PTF_LN, p->left))), + mkb(PT_PLUS, mkb(PT_TIMES, p->right, + mkb(PT_DIVIDE, arg1, p->left)), + mkb(PT_TIMES, arg2, + mkf(PTF_LN, arg1)))); + + } + break; + + case PT_FUNCTION: + /* Many cases. Set arg1 to the derivative of the function, + * and arg2 to the derivative of the argument. + */ + switch (p->funcnum) { + case PTF_ABS: /* sgn(u) */ + /* arg1 = mkf(PTF_SGN, p->left, 0); */ + arg1 = mkf(PTF_SGN, p->left); + break; + + case PTF_SGN: + arg1 = mkcon((double) 0.0); + break; + + case PTF_ACOS: /* - 1 / sqrt(1 - u^2) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) -1), mkf(PTF_SQRT, + mkb(PT_MINUS, mkcon((double) 1), + mkb(PT_POWER, p->left, mkcon((double) + 2))))); + break; + + case PTF_ACOSH: /* 1 / sqrt(u^2 - 1) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkf(PTF_SQRT, + mkb(PT_MINUS, mkb(PT_POWER, p->left, + mkcon((double) 2)), + mkcon((double) 1)))); + + break; + + case PTF_ASIN: /* 1 / sqrt(1 - u^2) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkf(PTF_SQRT, + mkb(PT_MINUS, mkcon((double) 1), + mkb(PT_POWER, p->left, mkcon((double) + 2))))); + break; + + case PTF_ASINH: /* 1 / sqrt(u^2 + 1) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkf(PTF_SQRT, + mkb(PT_PLUS, mkb(PT_POWER, p->left, + mkcon((double) 2)), + mkcon((double) 1)))); + break; + + case PTF_ATAN: /* 1 / (1 + u^2) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkb(PT_PLUS, + mkb(PT_POWER, p->left, mkcon((double) + 2)), mkcon((double) 1))); + break; + + case PTF_ATANH: /* 1 / (1 - u^2) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkb(PT_MINUS, + mkcon((double) 1), mkb(PT_POWER, + p->left, mkcon((double) 2)))); + break; + + case PTF_COS: /* - sin(u) */ + arg1 = mkf(PTF_UMINUS, mkf(PTF_SIN, p->left)); + break; + + case PTF_COSH: /* sinh(u) */ + arg1 = mkf(PTF_SINH, p->left); + break; + + case PTF_EXP: /* exp(u) */ + /* arg1 = mkf(PTF_EXP, p->left, 0); */ + arg1 = mkf(PTF_EXP, p->left); + break; + + case PTF_LN: /* 1 / u */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), p->left); + break; + + case PTF_LOG: /* log(e) / u */ + arg1 = mkb(PT_DIVIDE, mkcon((double) M_LOG10E), p->left); + break; + + case PTF_SIN: /* cos(u) */ + arg1 = mkf(PTF_COS, p->left); + break; + + case PTF_SINH: /* cosh(u) */ + arg1 = mkf(PTF_COSH, p->left); + break; + + case PTF_SQRT: /* 1 / (2 * sqrt(u)) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkb(PT_TIMES, + mkcon((double) 2), mkf(PTF_SQRT, + p->left))); + break; + + case PTF_TAN: /* 1 / (cos(u) ^ 2) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkb(PT_POWER, + mkf(PTF_COS, p->left), mkcon((double) + 2))); + break; + + case PTF_TANH: /* 1 / (cosh(u) ^ 2) */ + arg1 = mkb(PT_DIVIDE, mkcon((double) 1), mkb(PT_POWER, + mkf(PTF_COSH, p->left), mkcon((double) + 2))); + break; + + case PTF_USTEP: + arg1 = mkcon((double) 0.0); + break; + + case PTF_URAMP: + arg1 = mkf(PTF_USTEP, p->left); + break; + + case PTF_UMINUS: /* - 1 ; like a constant (was 0 !) */ + arg1 = mkcon((double) - 1.0); + break; + + default: + fprintf(stderr, "Internal Error: bad function # %d\n", + p->funcnum); + newp = NULL; + break; + } + + arg2 = PTdifferentiate(p->left, varnum); + + newp = mkb(PT_TIMES, arg1, arg2); + + break; + + default: + fprintf(stderr, "Internal error: bad node type %d\n", p->type); + newp = NULL; + break; + } + +/* printf("result is: "); printTree(newp); printf("\n"); */ + return (newp); +} + +static INPparseNode * +mkcon(double value) +{ + INPparseNode *p = (INPparseNode *) MALLOC(sizeof (INPparseNode)); + + p->type = PT_CONSTANT; + p->constant = value; + + return (p); +} + +static INPparseNode * +mkb(int type, INPparseNode *left, INPparseNode *right) +{ + INPparseNode *p = (INPparseNode *) MALLOC(sizeof (INPparseNode)); + int i; + + if ((right->type == PT_CONSTANT) && (left->type == PT_CONSTANT)) { + switch (type) { + case PT_TIMES: + return (mkcon(left->constant * right->constant)); + + case PT_DIVIDE: + return (mkcon(left->constant / right->constant)); + + case PT_PLUS: + return (mkcon(left->constant + right->constant)); + + case PT_MINUS: + return (mkcon(left->constant - right->constant)); + + case PT_POWER: + return (mkcon(pow(left->constant, right->constant))); + } + } + switch (type) { + case PT_TIMES: + if ((left->type == PT_CONSTANT) && (left->constant == 0)) + return (left); + else if ((right->type == PT_CONSTANT) && (right->constant == 0)) + return (right); + else if ((left->type == PT_CONSTANT) && (left->constant == 1)) + return (right); + else if ((right->type == PT_CONSTANT) && (right->constant == 1)) + return (left); + break; + + case PT_DIVIDE: + if ((left->type == PT_CONSTANT) && (left->constant == 0)) + return (left); + else if ((right->type == PT_CONSTANT) && (right->constant == 1)) + return (left); + break; + + case PT_PLUS: + if ((left->type == PT_CONSTANT) && (left->constant == 0)) + return (right); + else if ((right->type == PT_CONSTANT) && (right->constant == 0)) + return (left); + break; + + case PT_MINUS: + if ((right->type == PT_CONSTANT) && (right->constant == 0)) + return (left); + else if ((left->type == PT_CONSTANT) && (left->constant == 0)) + return (mkf(PTF_UMINUS, right)); + break; + + case PT_POWER: + if (right->type == PT_CONSTANT) { + if (right->constant == 0) + return (mkcon(1.0)); + else if (right->constant == 1) + return (left); + } + break; + } + + p->type = type; + p->left = left; + p->right = right; + + for (i = 0; i < NUM_OPS; i++) + if (ops[i].number == type) + break; + if (i == NUM_OPS) { + fprintf(stderr, "Internal Error: bad type %d\n", type); + return (NULL); + } + p->function = ops[i].funcptr; + p->funcname = ops[i].name; + + return (p); +} + +static INPparseNode * +mkf(int type, INPparseNode *arg) +{ + INPparseNode *p = (INPparseNode *) MALLOC(sizeof (INPparseNode)); + int i; + double constval; + + for (i = 0; i < NUM_FUNCS; i++) + if (funcs[i].number == type) + break; + if (i == NUM_FUNCS) { + fprintf(stderr, "Internal Error: bad type %d\n", type); + return (NULL); + } + + if (arg->type == PT_CONSTANT) { + constval = ((*funcs[i].funcptr) (arg->constant)); + return (mkcon(constval)); + } + + p->type = PT_FUNCTION; + p->left = arg; + + p->funcnum = i; + p->function = funcs[i].funcptr; + p->funcname = funcs[i].name; + + return (p); +} + +/* Check for remaining PT_PLACEHOLDERs in the parse tree. Returns 1 if ok. */ + +static int +PTcheck(INPparseNode *p) +{ + switch (p->type) { + case PT_PLACEHOLDER: + return (0); + + case PT_CONSTANT: + case PT_VAR: + return (1); + + case PT_FUNCTION: + return (PTcheck(p->left)); + + case PT_PLUS: + case PT_MINUS: + case PT_TIMES: + case PT_DIVIDE: + case PT_POWER: + return (PTcheck(p->left) && PTcheck(p->right)); + + default: + fprintf(stderr, "Internal error: bad node type %d\n", p->type); + return (0); + } +} + +/* The operator-precedence table for the parser. */ + +#define G 1 /* Greater than. */ +#define L 2 /* Less than. */ +#define E 3 /* Equal. */ +#define R 4 /* Error. */ + +static char prectable[11][11] = { + /* $ + - * / ^ u- ( ) v , */ +/* $ */ { R, L, L, L, L, L, L, L, R, L, R }, +/* + */ { G, G, G, L, L, L, L, L, G, L, G }, +/* - */ { G, G, G, L, L, L, L, L, G, L, G }, +/* * */ { G, G, G, G, G, L, L, L, G, L, G }, +/* / */ { G, G, G, G, G, L, L, L, G, L, G }, +/* ^ */ { G, G, G, G, G, L, L, L, G, L, G }, +/* u-*/ { G, G, G, G, G, G, G, L, G, L, R }, +/* ( */ { R, L, L, L, L, L, L, L, E, L, L }, +/* ) */ { G, G, G, G, G, G, G, R, G, R, G }, +/* v */ { G, G, G, G, G, G, G, G, G, R, G }, +/* , */ { G, L, L, L, L, L, L, L, G, L, G } + +} ; + +/* Return an expr. */ + +static INPparseNode * +PTparse(char **line) +{ + PTelement stack[PT_STACKSIZE]; + int sp = 0, st, i; + PTelement *top, *next; + INPparseNode *pn, *lpn, *rpn; + + stack[0].token = TOK_END; + next = PTlexer(line); + + while ((sp > 1) || (next->token != TOK_END)) { + /* Find the top-most terminal. */ + i = sp; + do { + top = &stack[i--]; + } while (top->token == TOK_VALUE); + + + switch (prectable[top->token][next->token]) { + case L: + case E: + /* Push the token read. */ + if (sp == (PT_STACKSIZE - 1)) { + fprintf(stderr, "Error: stack overflow\n"); + return (NULL); + } + bcopy((char *) next, (char *) &stack[++sp], + sizeof (PTelement)); + next = PTlexer(line); + continue; + + case R: + fprintf(stderr, "Syntax error.\n"); + return (NULL); + + case G: + /* Reduce. Make st and sp point to the elts on the + * stack at the end and beginning of the junk to + * reduce, then try and do some stuff. When scanning + * back for a <, ignore VALUES. + */ + st = sp; + if (stack[sp].token == TOK_VALUE) + sp--; + while (sp > 0) { + if (stack[sp - 1].token == TOK_VALUE) + i = 2; /* No 2 pnodes together... */ + else + i = 1; + if (prectable[stack[sp - i].token] + [stack[sp].token] == L) + break; + else + sp = sp - i; + } + if (stack[sp - 1].token == TOK_VALUE) + sp--; + /* Now try and see what we can make of this. + * The possibilities are: - node + * node op node + * ( node ) + * func ( node ) + * func ( node, node, node, ... ) <- new + * node + */ + if (st == sp) { + pn = makepnode(&stack[st]); + if (pn == NULL) + goto err; + } else if ((stack[sp].token == TOK_UMINUS) && + (st == sp + 1)) { + lpn = makepnode(&stack[st]); + if (lpn == NULL) + goto err; + pn = mkfnode("-", lpn); + } else if ((stack[sp].token == TOK_LPAREN) && + (stack[st].token == TOK_RPAREN)) { + pn = makepnode(&stack[sp + 1]); + if (pn == NULL) + goto err; + } else if ((stack[sp + 1].token == TOK_LPAREN) && + (stack[st].token == TOK_RPAREN)) { + lpn = makepnode(&stack[sp + 2]); + if ((lpn == NULL) || (stack[sp].type != TYP_STRING)) + goto err; + if (!(pn = mkfnode(stack[sp].value.string, lpn))) + return (NULL); + } else { /* node op node */ + lpn = makepnode(&stack[sp]); + rpn = makepnode(&stack[st]); + if ((lpn == NULL) || (rpn == NULL)) + goto err; + pn = mkbnode(stack[sp + 1].token, lpn, rpn); + } + stack[sp].token = TOK_VALUE; + stack[sp].type = TYP_PNODE; + stack[sp].value.pnode = pn; + continue; + } + } + pn = makepnode(&stack[1]); + if (pn) + return (pn); +err: + fprintf(stderr, "Syntax error.\n"); + return (NULL); +} + +/* Given a pointer to an element, make a pnode out of it (if it already + * is one, return a pointer to it). If it isn't of type VALUE, then return + * NULL. + */ + +static INPparseNode * +makepnode(PTelement *elem) +{ + if (elem->token != TOK_VALUE) + return (NULL); + + switch (elem->type) { + case TYP_STRING: + return (mksnode(elem->value.string)); + + case TYP_NUM: + return (mknnode(elem->value.real)); + + case TYP_PNODE: + return (elem->value.pnode); + + default: + fprintf(stderr, "Internal Error: bad token type\n"); + return (NULL); + } +} + +/* Binop node. */ + +static INPparseNode * +mkbnode(int opnum, INPparseNode *arg1, INPparseNode *arg2) +{ + INPparseNode *p; + int i; + + for (i = 0; i < NUM_OPS; i++) + if (ops[i].number == opnum) + break; + + if (i == NUM_OPS) { + fprintf(stderr, "Internal Error: no such op num %d\n", + opnum); + return (NULL); + } + p = (INPparseNode *) MALLOC(sizeof (INPparseNode)); + + p->type = opnum; + p->funcname = ops[i].name; + p->function = ops[i].funcptr; + p->left = arg1; + p->right = arg2; + + return (p); +} + +static INPparseNode * +mkfnode(char *fname, INPparseNode *arg) +{ + int i; + INPparseNode *p; + char buf[128], *name, *s; + IFvalue temp; + + /* Make sure the case is ok. */ + (void) strcpy(buf, fname); + for (s = buf; *s; s++) + if (isupper(*s)) + *s = tolower(*s); + + p = (INPparseNode *) MALLOC(sizeof (INPparseNode)); + + if (!strcmp(buf, "v")) { + name = MALLOC(128); + if (arg->type == PT_PLACEHOLDER) { + strcpy(name, arg->funcname); + } else if (arg->type == PT_CONSTANT) { + (void) sprintf(name, "%d", (int) arg->constant); + } else if (arg->type != PT_COMMA) { + fprintf(stderr, "Error: badly formed node voltage\n"); + return (NULL); + } + + if (arg->type == PT_COMMA) { + /* Change v(a,b) into v(a) - v(b) */ + p = mkb(PT_MINUS, mkfnode(fname, arg->left), + mkfnode(fname, arg->right)); + } else { + /* printf("getting a node called '%s'\n", name); */ + INPtermInsert(circuit, &name, tables, &(temp.nValue)); + for (i = 0; i < numvalues; i++) + if ((types[i] == IF_NODE) && (values[i].nValue == + temp.nValue)) + break; + if (i == numvalues) { + if (numvalues) { + values = (IFvalue *) + REALLOC((char *) values, (numvalues + 1) * sizeof (IFvalue)); + types = (int *) + REALLOC((char *) types, (numvalues + 1) * sizeof (int)); + } else { + values = (IFvalue *) MALLOC(sizeof (IFvalue)); + types = (int *) MALLOC(sizeof (int)); + } + values[i] = temp; + types[i] = IF_NODE; + numvalues++; + } + p->valueIndex = i; + p->type = PT_VAR; + } + } else if (!strcmp(buf, "i")) { + name = MALLOC(128); + if (arg->type == PT_PLACEHOLDER) + strcpy(name, arg->funcname); + else if (arg->type == PT_CONSTANT) + (void) sprintf(name, "%d", (int) arg->constant); + else { + fprintf(stderr, "Error: badly formed branch current\n"); + return (NULL); + } +/* printf("getting a device called '%s'\n", name); */ + INPinsert(&name, tables); + for (i = 0; i < numvalues; i++) + if ((types[i] == IF_INSTANCE) && (values[i].uValue == + temp.uValue)) + break; + if (i == numvalues) { + if (numvalues) { + values = (IFvalue *) + REALLOC((char *) values, (numvalues + 1) * sizeof (IFvalue)); + types = (int *) + REALLOC((char *) types, (numvalues + 1) * sizeof (int)); + } else { + values = (IFvalue *) MALLOC(sizeof (IFvalue)); + types = (int *) MALLOC(sizeof (int)); + } + values[i].uValue = (IFuid) name; + types[i] = IF_INSTANCE; + numvalues++; + } + p->valueIndex = i; + p->type = PT_VAR; + } else { + for (i = 0; i < NUM_FUNCS; i++) + if (!strcmp(funcs[i].name, buf)) + break; + + if (i == NUM_FUNCS) { + fprintf(stderr, "Error: no such function '%s'\n", buf); + return (NULL); + } + + p->type = PT_FUNCTION; + p->left = arg; + p->funcname = funcs[i].name; + p->funcnum = funcs[i].number; + p->function = funcs[i].funcptr; + } + + return (p); +} + +/* Number node. */ + +static INPparseNode * +mknnode(double number) +{ + struct INPparseNode *p; + + p = (INPparseNode *) MALLOC(sizeof (INPparseNode)); + + p->type = PT_CONSTANT; + p->constant = number; + + return (p); +} + +/* String node. */ + +static INPparseNode * +mksnode(char *string) +{ + int i, j; + char buf[128], *s; + INPparseNode *p; + + /* Make sure the case is ok. */ + (void) strcpy(buf, string); + for (s = buf; *s; s++) + if (isupper(*s)) + *s = tolower(*s); + + p = (INPparseNode *) MALLOC(sizeof (INPparseNode)); + + /* First see if it's something special. */ + for (i = 0; i < ft_sim->numSpecSigs; i++) + if (!strcmp(ft_sim->specSigs[i], buf)) + break; + if (i < ft_sim->numSpecSigs) { + for (j = 0; j < numvalues; j++) + if ((types[j] == IF_STRING) && !strcmp(buf, + values[i].sValue)) + break; + if (j == numvalues) { + if (numvalues) { + values = (IFvalue *) + REALLOC((char *) values, (numvalues + 1) * sizeof (IFvalue)); + types = (int *) + REALLOC((char *) types, (numvalues + 1) * sizeof (int)); + } else { + values = (IFvalue *) MALLOC(sizeof (IFvalue)); + types = (int *) MALLOC(sizeof (int)); + } + values[i].sValue = MALLOC(strlen(buf) + 1); + strcpy(values[i].sValue, buf); + types[i] = IF_STRING; + numvalues++; + } + p->valueIndex = i; + p->type = PT_VAR; + return (p); + } + + for (i = 0; i < NUM_CONSTANTS; i++) + if (!strcmp(constants[i].name, buf)) + break; + + if (i == NUM_CONSTANTS) { + /* We'd better save this in case it's part of i(something). */ + p->type = PT_PLACEHOLDER; + p->funcname = string; + } else { + p->type = PT_CONSTANT; + p->constant = constants[i].value; + } + + return (p); +} + +/* The lexical analysis routine. */ + +static PTelement * +PTlexer(char **line) +{ + double td; + int err; + static PTelement el; + static char *specials = " \t()^+-*/,"; + static int lasttoken = TOK_END, lasttype; + char *sbuf, *s; + + sbuf = *line; +#ifdef notdef + printf("entering lexer, sbuf = '%s', lastoken = %d, lasttype = %d\n", + sbuf, lasttoken, lasttype); +#endif + while ((*sbuf == ' ') || (*sbuf == '\t') || (*sbuf == '=')) + sbuf++; + + switch (*sbuf) { + case '\0': + el.token = TOK_END; + break; + + case ',': + el.token = TOK_COMMA; + sbuf++; + break; + + case '-': + if ((lasttoken == TOK_VALUE) || (lasttoken == TOK_RPAREN)) + el.token = TOK_MINUS; + else + el.token = TOK_UMINUS; + sbuf++; + break; + + case '+': + el.token = TOK_PLUS; + sbuf++; + break; + + case '*': + el.token = TOK_TIMES; + sbuf++; + break; + + case '/': + el.token = TOK_DIVIDE; + sbuf++; + break; + + case '^': + el.token = TOK_POWER; + sbuf++; + break; + + case '(': + if (((lasttoken == TOK_VALUE) && ((lasttype == TYP_NUM))) || + (lasttoken == TOK_RPAREN)) { + el.token = TOK_END; + } else { + el.token = TOK_LPAREN; + sbuf++; + } + break; + + case ')': + el.token = TOK_RPAREN; + sbuf++; + break; + + default: + if ((lasttoken == TOK_VALUE) || (lasttoken == TOK_RPAREN)) { + el.token = TOK_END; + break; + } + + td = INPevaluate(&sbuf, &err, 1); + if (err == OK) { + el.token = TOK_VALUE; + el.type = TYP_NUM; + el.value.real = td; + } else { + el.token = TOK_VALUE; + el.type = TYP_STRING; + for (s = sbuf; *s; s++) + if (index(specials, *s)) + break; + el.value.string = MALLOC(s - sbuf + 1); + strncpy(el.value.string, sbuf, s - sbuf); + el.value.string[s - sbuf] = '\0'; + sbuf = s; + } + } + + lasttoken = el.token; + lasttype = el.type; + + *line = sbuf; + +/* printf("PTlexer: token = %d, type = %d, left = '%s'\n", + el.token, el.type, sbuf); */ + + return (&el); +} + +#ifdef notdef + +/* Debugging stuff. */ + +#ifdef __STDC__ +void printTree(INPparseNode*); +#else /* stdc */ +void printTree(); +#endif /* stdc */ +void +INPptPrint(str, ptree) + char *str; + IFparseTree *ptree; +{ + int i; + + printf("%s\n\t", str); + printTree(((INPparseTree *) ptree)->tree); + printf("\n"); + for (i = 0; i < ptree->numVars; i++) { + printf("d / d v%d : ", i); + printTree(((INPparseTree *) ptree)->derivs[i]); + printf("\n"); + } + return; +} + +void +printTree(pt) + INPparseNode *pt; +{ + switch (pt->type) { + case PT_CONSTANT: + printf("%g", pt->constant); + break; + + case PT_VAR: + printf("v%d", pt->valueIndex); + break; + + case PT_PLUS: + printf("("); + printTree(pt->left); + printf(") + ("); + printTree(pt->right); + printf(")"); + break; + + case PT_MINUS: + printf("("); + printTree(pt->left); + printf(") - ("); + printTree(pt->right); + printf(")"); + break; + + case PT_TIMES: + printf("("); + printTree(pt->left); + printf(") * ("); + printTree(pt->right); + printf(")"); + break; + + case PT_DIVIDE: + printf("("); + printTree(pt->left); + printf(") / ("); + printTree(pt->right); + printf(")"); + break; + + case PT_POWER: + printf("("); + printTree(pt->left); + printf(") ^ ("); + printTree(pt->right); + printf(")"); + break; + + case PT_FUNCTION: + printf("%s (", pt->funcname); + printTree(pt->left); + printf(")"); + break; + + default: + printf("oops"); + break; + } + return; +} + +#endif diff --git a/src/circuit/inpsymt.c b/src/circuit/inpsymt.c new file mode 100644 index 000000000..b228bd20c --- /dev/null +++ b/src/circuit/inpsymt.c @@ -0,0 +1,280 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Stuff for the terminal and node symbol tables. + * Defined: INPtabInit, INPinsert, INPtermInsert, INPtabEnd + */ +/* MW. Special INPinsertNofree for routines from spiceif.c and outif.c */ + +#include "ngspice.h" +#include /* Take this out soon. */ +#include "ifsim.h" +#include "iferrmsg.h" +#include "inpdefs.h" +#include "cpstd.h" +#include "fteext.h" +#include "inp.h" + + +static int hash(char *name, int tsize); + +/* Initialize the symbol tables. */ + +INPtables * +INPtabInit(int numlines) +{ + INPtables *tab; + + tab = (INPtables *)tmalloc(sizeof(INPtables)); + tab->INPsymtab = (struct INPtab **) tmalloc((numlines / 4 + 1) * + sizeof (struct INPtab *)); + ZERO(tab->INPsymtab, (numlines / 4 + 1) * sizeof (struct INPtab *)); + tab->INPtermsymtab = (struct INPnTab **) tmalloc(numlines * + sizeof (struct INPnTab *)); + ZERO(tab->INPtermsymtab, numlines * sizeof (struct INPnTab *)); + tab->INPsize = numlines / 4 + 1; + tab->INPtermsize = numlines; + return(tab); +} + +/* insert 'token' into the terminal symbol table */ +/* create a NEW NODE and return a pointer to it in *node */ + +int +INPtermInsert(void *ckt, char **token, INPtables *tab, void **node) +{ + int key; + int error; + struct INPnTab *t; + + key = hash(*token, tab->INPtermsize); + for (t = tab->INPtermsymtab[key]; t; t = t->t_next) { + if (!strcmp(*token, t->t_ent)) { + FREE(*token); + *token = t->t_ent; + if(node) *node = t->t_node; + return(E_EXISTS); + } + } + t = (struct INPnTab *) tmalloc(sizeof (struct INPnTab)); + if(t == (struct INPnTab*)NULL) return(E_NOMEM); + ZERO(t,struct INPnTab); + error = (*(ft_sim->newNode))(ckt,&t->t_node,*token); + if(error) return(error); + if(node) *node = t->t_node; + t->t_ent = *token; + t->t_next = tab->INPtermsymtab[key]; + tab->INPtermsymtab[key] = t; + return(OK); +} + + +/* insert 'token' into the terminal symbol table */ +/* USE node as the node pointer */ + + +int +INPmkTerm(void *ckt, char **token, INPtables *tab, void **node) +{ + int key; + struct INPnTab *t; + + key = hash(*token, tab->INPtermsize); + for (t = tab->INPtermsymtab[key]; t; t = t->t_next) { + if (!strcmp(*token, t->t_ent)) { + FREE(*token); + *token = t->t_ent; + if(node) *node = t->t_node; + return(E_EXISTS); + } + } + t = (struct INPnTab *) tmalloc(sizeof (struct INPnTab)); + if(t == (struct INPnTab*)NULL) return(E_NOMEM); + ZERO(t,struct INPnTab); + t->t_node = *node ; + t->t_ent = *token; + t->t_next = tab->INPtermsymtab[key]; + tab->INPtermsymtab[key] = t; + return(OK); +} + +/* insert 'token' into the terminal symbol table as a name for ground*/ + +int +INPgndInsert(void *ckt, char **token, INPtables *tab, void **node) +{ + int key; + int error; + struct INPnTab *t; + + key = hash(*token, tab->INPtermsize); + for (t = tab->INPtermsymtab[key]; t; t = t->t_next) { + if (!strcmp(*token, t->t_ent)) { + FREE(*token); + *token = t->t_ent; + if(node) *node = t->t_node; + return(E_EXISTS); + } + } + t = (struct INPnTab *) tmalloc(sizeof (struct INPnTab)); + if(t == (struct INPnTab*)NULL) return(E_NOMEM); + ZERO(t,struct INPnTab); + error = (*(ft_sim->groundNode))(ckt,&t->t_node,*token); + if(error) return(error); + if(node) *node = t->t_node; + t->t_ent = *token; + t->t_next = tab->INPtermsymtab[key]; + tab->INPtermsymtab[key] = t; + return(OK); +} + +/* retrieve 'token' from the symbol table */ + +int +INPretrieve(char **token, INPtables *tab) +{ + struct INPtab *t; + int key; + + key = hash(*token, tab->INPsize); + for (t = tab->INPsymtab[key]; t; t = t->t_next) + if (!strcmp(*token, t->t_ent)) { + *token = t->t_ent; + return(OK); + } + return(E_BADPARM); +} + + +/* insert 'token' into the symbol table */ + +int +INPinsert(char **token, INPtables *tab) +{ + struct INPtab *t; + int key; + + key = hash(*token, tab->INPsize); + for (t = tab->INPsymtab[key]; t; t = t->t_next) + if (!strcmp(*token, t->t_ent)) { + FREE(*token); + *token = t->t_ent; + return(E_EXISTS); + } + t = (struct INPtab *) tmalloc(sizeof (struct INPtab)); + if(t == (struct INPtab*)NULL) return(E_NOMEM); + ZERO(t,struct INPtab); + t->t_ent = *token; + t->t_next = tab->INPsymtab[key]; + tab->INPsymtab[key] = t; + return(OK); +} + + +/* MW. insert 'token' into the symbol table but no free() token pointer. +* Calling routine should take care for this */ + +int +INPinsertNofree(char **token, INPtables *tab) +{ + struct INPtab *t; + int key; + + key = hash(*token, tab->INPsize); + for (t = tab->INPsymtab[key]; t; t = t->t_next) + if (!strcmp(*token, t->t_ent)) { + + /* MW. We can't touch memory pointed by token now */ + *token = t->t_ent; + return(E_EXISTS); + } + t = (struct INPtab *) tmalloc(sizeof (struct INPtab)); + if(t == (struct INPtab*)NULL) return(E_NOMEM); + ZERO(t,struct INPtab); + t->t_ent = *token; + t->t_next = tab->INPsymtab[key]; + tab->INPsymtab[key] = t; + return(OK); +} + +/* remove 'token' from the symbol table */ +int +INPremove(char *token, INPtables *tab) +{ + struct INPtab *t, **prevp; + int key; + + key = hash(token, tab->INPsize); + prevp = &tab->INPsymtab[key]; + for (t = *prevp; t && token != t->t_ent; t = t->t_next) + prevp = &t->t_next; + if (!t) + return OK; + + *prevp = t->t_next; + tfree(t->t_ent); + tfree(t); + + return OK; +} + +/* remove 'token' from the symbol table */ +int +INPremTerm(char *token, INPtables *tab) +{ + struct INPnTab *t, **prevp; + int key; + + key = hash(token, tab->INPtermsize); + prevp = &tab->INPtermsymtab[key]; + for (t = *prevp; t && token != t->t_ent; t = t->t_next) + prevp = &t->t_next; + if (!t) + return OK; + + *prevp = t->t_next; + tfree(t->t_ent); + tfree(t); + + return OK; +} + +/* Free the space used by the symbol tables. */ + +void +INPtabEnd(INPtables *tab) +{ + struct INPtab *t, *lt; + struct INPnTab *n, *ln; + int i; + + for (i = 0; i < tab->INPsize; i++) + for (t = tab->INPsymtab[i]; t; t = lt) { + lt = t->t_next; + FREE(t); /* But not t_ent ! */ + } + FREE(tab->INPsymtab); + for (i = 0; i < tab->INPtermsize; i++) + for (n = tab->INPtermsymtab[i]; n; n = ln) { + ln = n->t_next; + FREE(n); /* But not t_ent ! */ + } + FREE(tab->INPtermsymtab); + FREE(tab); + return; +} + +static int +hash(char *name, int tsize) +{ + char *s; + register int i = 0; + + for (s = name; *s; s++) + i += *s; + return (i % tsize); +} + diff --git a/src/circuit/inptyplk.c b/src/circuit/inptyplk.c new file mode 100644 index 000000000..ec23011ad --- /dev/null +++ b/src/circuit/inptyplk.c @@ -0,0 +1,30 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* look up the 'type' in the device description struct and return the + * appropriatestrchr for the device found, or -1 for not found + */ + +#include "ngspice.h" +#include "inpdefs.h" +#include "cpdefs.h" +#include "fteext.h" +#include "ifsim.h" +#include "inp.h" + +int +INPtypelook(char *type) +{ + + int i; + for(i=0;inumDevices;i++) { + if(strcmp(type,(*(ft_sim->devices)[i]).name)==0) { + /*found the device - return it */ + return(i); + } + } + return(-1); +} + diff --git a/src/circuit/ptfuncs.c b/src/circuit/ptfuncs.c new file mode 100644 index 000000000..69783bdcb --- /dev/null +++ b/src/circuit/ptfuncs.c @@ -0,0 +1,244 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * All the functions used in the parse tree. These functions return HUGE + * if their argument is out of range. + */ + +#include +#include "ngspice.h" +#include +#include "fteext.h" +#include "ifsim.h" +#include "inpptree.h" +#include "inp.h" + +/* XXX These should be in math.h */ + + +#ifndef HAVE_ATANH +extern double asinh(), acosh(), atanh(); +#endif + +double PTfudge_factor; + +#define MODULUS(NUM,LIMIT) ((NUM) - ((int) ((NUM) / (LIMIT))) * (LIMIT)) + +double +PTabs(double arg) +{ + return arg >= 0.0 ? arg : -arg; +} + +double +PTsgn(double arg) +{ + return arg > 0.0 ? 1.0 : arg < 0.0 ? -1.0 : 0.0; +} + +double +PTplus(double arg1, double arg2) +{ + return (arg1 + arg2); +} + +double +PTminus(double arg1, double arg2) +{ + return (arg1 - arg2); +} + +double +PTtimes(double arg1, double arg2) +{ + return (arg1 * arg2); +} + +double +PTdivide(double arg1, double arg2) +{ + if (arg2 >= 0.0) + arg2 += PTfudge_factor; + else + arg2 -= PTfudge_factor; + + if (arg2 == 0.0) + return (HUGE); + + return (arg1 / arg2); +} + +double +PTpower(double arg1, double arg2) +{ + if (arg1 < 0.0) { + if (fabs(arg2 - ((int) arg2)) / (arg2 + 0.001) < 0.000001) { + arg2 = (int) arg2; + } else { + arg1 = -arg1; + } + } + return (pow(arg1, arg2)); +} + +double +PTacos(double arg) +{ + return (acos(arg)); +} + +double +PTacosh(double arg) +{ +#ifdef HAVE_ACOSH + return (acosh(arg)); +#else + if (arg < 1.0) + arg = 1.0; + return (log(arg + sqrt(arg*arg-1.0))); +#endif +} + +double +PTasin(double arg) +{ + return (asin(arg)); +} + +double +PTasinh(double arg) +{ +#ifdef HAVE_ASINH + return (asinh(arg)); +#else + return log(arg + sqrt(arg * arg + 1.0)); +#endif +} + +double +PTatan(double arg) +{ + return (atan(arg)); +} + +double +PTatanh(double arg) +{ +#ifdef HAVE_ATANH + return (atanh(arg)); +#else + if (arg < -1.0) + arg = -1.0 + PTfudge_factor + 1e-10; + else if (arg > 1.0) + arg = 1.0 - PTfudge_factor - 1e-10; + return (log((1.0 + arg) / (1.0 - arg)) / 2.0); +#endif +} + +double +PTustep(double arg) +{ + if (arg < 0.0) + return 0.0; + else if (arg > 0.0) + return 1.0; + else + return 0.5; /* Ick! */ +} + +double +PTuramp(double arg) +{ + if (arg < 0.0) + return 0.0; + else + return arg; +} + +double +PTcos(double arg) +{ + return (cos(MODULUS(arg, 2 * M_PI))); +} + +double +PTcosh(double arg) +{ + return (cosh(arg)); +} + +double +PTexp(double arg) +{ + return (exp(arg)); +} + +double +PTln(double arg) +{ + if (arg < 0.0) +#ifdef EXPERIMENTAL_CODE + return (HUGE); +#else + arg = -arg; +#endif + return (log(arg)); +} + +double +PTlog(double arg) +{ + if (arg <= 0.0) +#ifdef EXPERIMENTAL_CODE + return (HUGE); +#else + arg = -arg; +#endif + return (log10(arg)); +} + +double +PTsin(double arg) +{ + return (sin(MODULUS(arg, 2 * M_PI))); +} + +double +PTsinh(double arg) +{ + return (sinh(arg)); +} + +double +PTsqrt(double arg) +{ + if (arg < 0.0) +#ifdef EXPERIMENTAL_CODE + return (HUGE); +#else + arg = -arg; +#endif + return (sqrt(arg)); +} + +double +PTtan(double arg) +{ + return (tan(MODULUS(arg, M_PI))); +} + +double +PTtanh(double arg) +{ + return (tanh(arg)); +} + +double +PTuminus(double arg) +{ + return (- arg); +} + diff --git a/src/circuit/sperror.c b/src/circuit/sperror.c new file mode 100644 index 000000000..17760307e --- /dev/null +++ b/src/circuit/sperror.c @@ -0,0 +1,137 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * provide the error message appropriate for the given error code + */ + +#include "ngspice.h" +#include +#include "fteext.h" +#include "sperror.h" +#include "cktdefs.h" +#include "ifsim.h" +#include "inp.h" + +#define MSG(a) \ + msg = a; \ + break; + +static char *unknownError = "Unknown error code"; +static char *Pause = "Pause requested"; +static char *intern = "Impossible error - can't occur"; +static char *exists = "Device already exists, existing one being used"; +static char *nodev = "No such device"; +static char *noterm = "No such terminal on this device"; +static char *nomod = "No such model"; +static char *badparm = "No such parameter on this device"; +static char *nomem = "Out of Memory"; +static char *nodecon = "Node already connected; connection replaced"; +static char *unsupp = "operation not supported"; +static char *parmval = "parameter value out of range or the wrong type"; +static char *badmatrix = "Matrix can't be decomposed as is"; +static char *singular = "Matrix is singular"; +static char *iterlim = "Iteration limit reached"; +static char *order = "Unsupported integration order"; +static char *method = "Unsupported integration method"; +static char *timestep = "Timestep too small"; +static char *xmission = "transmission lines not supported by pole-zero"; +static char *toobig = "magnitude overflow"; +static char *isshort = "input or output shorted"; +static char *inisout = "transfer function is 1"; +static char *nodisto = "Distortion analysis not present"; +static char *nonoise = "Noise analysis not present"; +static char *noacinput = "AC input not found"; +static char *noanal = "No such analysis type"; +static char *nochange = "Unsupported action; no change made"; +static char *notfound = "Not found"; +static char *nof2src = "No F2 source for IM disto analysis"; +#ifdef PARALLEL_ARCH +static char *multierr = "Multiple errors detected by parallel machine"; +#endif /* PARALLEL_ARCH */ + +char * +SPerror(int type) +{ + char *val; + char *msg; + + switch(type) { + default: + MSG(unknownError) + case E_PAUSE: + MSG(Pause) + case OK: + return(NULL); + case E_INTERN: + MSG(intern) + case E_EXISTS: + MSG(exists) + case E_NODEV: + MSG(nodev) + case E_NOMOD: + MSG(nomod) + case E_NOTERM: + MSG(noterm) + case E_BADPARM: + MSG(badparm) + case E_NOMEM: + MSG(nomem) + case E_NODECON: + MSG(nodecon) + case E_UNSUPP: + MSG(unsupp) + case E_PARMVAL: + MSG(parmval) + case E_BADMATRIX: + MSG(badmatrix) + case E_SINGULAR: + MSG(singular) + case E_ITERLIM: + MSG(iterlim) + case E_ORDER: + MSG(order) + case E_METHOD: + MSG(method) + case E_TIMESTEP: + MSG(timestep) + case E_XMISSIONLINE: + MSG(xmission) + case E_MAGEXCEEDED: + MSG(toobig) + case E_SHORT: + MSG(isshort) + case E_INISOUT: + MSG(inisout) + case E_NODISTO: + MSG(nodisto) + case E_NONOISE: + MSG(nonoise) + case E_NOANAL: + MSG(noanal) + case E_NOCHANGE: + MSG(nochange) + case E_NOTFOUND: + MSG(notfound) + case E_NOACINPUT: + MSG(noacinput) + case E_NOF2SRC: + MSG(nof2src) +#ifdef PARALLEL_ARCH + case E_MULTIERR: + MSG(multierr) +#endif /* PARALLEL_ARCH */ + } + + val = MALLOC(strlen(msg) + 1); + if (val) { + (void) strcpy(val, msg); + } +#ifdef notdef + else + (*(SPfrontEnd->IFerror))(ERR_PANIC,nomem,(IFuid *)NULL); +#endif + return(val); +} diff --git a/src/conf.c b/src/conf.c new file mode 100644 index 000000000..ccc8fddf8 --- /dev/null +++ b/src/conf.c @@ -0,0 +1,18 @@ +/* Common configuration file for ng-spice and nutmeg */ + +#include + +#include "conf.h" + +char Spice_Version[ ] = VERSION; +char Spice_Notice[ ] = "Please submit bug-reports to: ng-spice-bugs@ieee.ing.uniroma1.it"; +char Spice_Build_Date[ ] = NGSPICEBUILDDATE; +char *Spice_Exec_Dir = NGSPICEBINDIR; +char *Spice_Lib_Dir = NGSPICEDATADIR; +char *Def_Editor = "vi"; +int AsciiRawFile = 0; + +char *Bug_Addr = "ng-spice-bugs@ieee.ing.uniroma1.it"; +char *Spice_Host = ""; +char *Spiced_Log = ""; + diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 000000000..9ef299f17 --- /dev/null +++ b/src/conf.h @@ -0,0 +1,16 @@ +#ifndef __CONF_H +#define __CONF_H + +char Spice_Version[]; +char Spice_Notice[]; +char Spice_Build_Date[]; +char *Spice_Exec_Dir; +char *Spice_Lib_Dir; +char *Def_Editor; +int AsciiRawFile; + +char *Bug_Addr; +char *Spice_Host; +char *Spiced_Log; + +#endif diff --git a/src/frontend/ChangeLog b/src/frontend/ChangeLog new file mode 100644 index 000000000..2c38e19e4 --- /dev/null +++ b/src/frontend/ChangeLog @@ -0,0 +1,154 @@ +2000-03-22 Paolo Nenzi + + * rawfile.c: Applied Michael Widlok patch. + + * spiceif.c: Applied Michael Widlok patch. + +2000-03-12 Paolo Nenzi + + * x11.c: Cleared the code. Rewmoved some empty return on void functions. + +1999-12-20 Paolo Nenzi + outif.c: + To fix various "save"-related segmentation faults, make this one-line patch + to outitf.c: line 356, change + unique = devname; to unique = copy(devname); + +1999-12-20 Paolo Nenzi + subckt.c: + Bug: Current controlled switch subcircuit does not expand + the controlling source correctly: vsrc expands to name:vsrc, + not to v:name:src. + Fix: changed this file to indicate that w device has only 2 + not 3 nodes and 1 not zero controlling sources. + +1999-09-07 Emmanuel Rouat + + * *.c: put back static functions declarations back in the .c files (shouldn't + be in .h files!) + +1999-09-07 Arno + + * aspice.c: template to fprintf now conform to argument types. + + * cmath1.c: + + * cmath2.c: removed most warnings about possible use of + uninitialized variables. Only two remain in cx_sqrt(). + +1999-09-06 Arno Peters + + * dotcards.c: Put proper braces around an + ambiguous if/else construct. + + * postcoms.c: + + * postsc.c: Removed unused variables. + +1999-09-04 Emmanuel Rouat + + * Makefile.am (libfte_a_SOURCES): forgot display.h in list + + * typesdef.c: moved types.c to typesdef.c + + * signal_handler.c: moved signal.c to signal_handler.c + + * *.c: added header file for all .c files + +1999-09-01 Emmanuel Rouat + + * *.c: removed lots of unnecessary HAS_XX tests and code + + * Makefile.am (libfte_a_SOURCES): removed mfb.c from sources + + * signal.c (ft_sigintr): removed HAS_MFB test + +1999-08-30 Paolo Nenzi + + * Removed #include "suffix.h" and replaced GENERIC with void. + +1999-08-28 Emmanuel Rouat + + * Makefile.am (libfte_a_SOURCES): removed x10.c from source files + + * clip.c: removed MAX/MIN #defines + + * Removed all #includes of misc.h and util.h (now in spice.h) + +1999-08-19 Paolo Nenzi + + * Makefile.am: added spec.c. + + * spcmdtab.c: added code for spec command support. The original + patch came from ftp.mpce.mq.edu.au. + + * spec.c: added this file containing the spec command code. + +1999-08-08 Emmanuel Rouat + + * Makefile.am (DEFS): removed -DWANT_MFB (don't need it) + + * resource.c : removed HAS_RLIMIT_ tests + + * error.c: removed HAS_VAXFPERROR code + + * cmath3.c: removed HAS_SHORTMACRO code + + * display.c : removed HAS_X10 code + + * mfb.c (Mfb_Init): removed HAS_PCTERM code + + * resource.c: removed all code related to HAS_MEMAVL + +1999-08-06 Emmanuel Rouat + + * resource.c: removed tests on HAS_UNIX_SEGMENT_HACK + + * xgraph.c (ft_xgraph): + * options.c (cp_usrset): + * misccoms.c: removed tests on HAS_SYSTEM + + * nutinp.c: + * inp.c (com_source): + (doedit): removed tests on HAS_SYSTEM (always true?) + + * doplot.c (com_hardcopy): removed tests on HAS_UNLINK (always true) + (com_hardcopy): removed tests on HAS_SYSTEM (always true?) + + * signal.c: + * evaluate.c (doop): + * error.c (fatal): + * aspice.c: removed test on HAS_UNIX_SIGS (always true) + + * signal.c: + * evaluate.c: removed test on HAS_LONGJUMP (always true) + +1999-08-04 Emmanuel Rouat + + * aspice.c: changed HAS_WAIT into HAVE_SYS_WAIT_H + + * inpcom.c: + * breakp.c: changed HAS_CTYPE into HAVE_CTYPE_H + +1999-08-03 Emmanuel Rouat + + * signal.c: + * resource.c: + * evaluate.c: + * aspice.c: changed SIGNAL_TYPE into RETSIGTYPE + +1999-07-31 Emmanuel Rouat + + * Makefile.am: added @X_CFLAGS@ (X11 header files) to INCLUDES and removed + unused LIBS list. + +28-07-1999 emmanuel.rouat@wanadoo.fr (Manu Rouat) + + * graf.c: + * display.c: + * doplot.c: + * x11.c: changed HAS_X11 define to X_DISPLAY_MISSING, which is supplied + by autoconf in config.h + + * removed -DWANT_X11 in Makefile.am + diff --git a/src/frontend/Makefile.am b/src/frontend/Makefile.am new file mode 100644 index 000000000..d5fa3dbf5 --- /dev/null +++ b/src/frontend/Makefile.am @@ -0,0 +1,127 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libfte.a + +libfte_a_SOURCES = \ + agraf.c \ + agraf.h \ + arg.c \ + arg.h \ + aspice.c \ + aspice.h \ + breakp.c \ + breakp.h \ + breakp2.c \ + breakp2.h \ + circuits.c \ + circuits.h \ + clip.c \ + clip.h \ + compose.c \ + compose.h \ + cpitf.c \ + cpitf.h \ + debugcom.c \ + debugcom.h \ + define.c \ + define.h \ + device.c \ + device.h \ + diff.c \ + diff.h \ + dimens.c \ + dimens.h \ + display.c \ + display.h \ + doplot.c \ + doplot.h \ + dotcards.c \ + dotcards.h \ + error.c \ + error.h \ + evaluate.c \ + evaluate.h \ + fourier.c \ + fourier.h \ + gens.c \ + gens.h \ + graf.c \ + graf.h \ + graphdb.c \ + graphdb.h \ + grid.c \ + grid.h \ + inp.c \ + inp.h \ + inpcom.c \ + inpcom.h \ + interp.c \ + interp.h \ + linear.c \ + linear.h \ + misccoms.c \ + misccoms.h \ + miscvars.c \ + miscvars.h \ + mw_coms.c \ + mw_coms.h \ + newcoms.c \ + newcoms.h \ + nutctab.c \ + nutctab.h \ + nutinp.c \ + nutinp.h \ + nutmegif.c \ + nutmegif.h \ + options.c \ + options.h \ + outitf.c \ + outitf.h \ + parse.c \ + parse.h \ + plot5.c \ + plot5.h \ + plotcurv.c \ + plotcurv.h \ + points.c \ + points.h \ + postcoms.c \ + postcoms.h \ + postsc.c \ + postsc.h \ + rawfile.c \ + rawfile.h \ + resource.c \ + resource.h \ + runcoms.c \ + runcoms.h \ + runcoms2.c \ + runcoms2.h \ + shyu.c \ + shyu.h \ + signal_handler.c\ + signal_handler.h\ + spec.c \ + spec.h \ + spcmdtab.c \ + spiceif.c \ + spiceif.h \ + subckt.c \ + subckt.h \ + typesdef.c \ + typesdef.h \ + vectors.c \ + vectors.h \ + where.c \ + where.h \ + x11.c \ + x11.h \ + xgraph.c \ + xgraph.h + + + + +INCLUDES = -I$(top_srcdir)/src/include @X_CFLAGS@ + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/frontend/agraf.c b/src/frontend/agraf.c new file mode 100644 index 000000000..e036221d0 --- /dev/null +++ b/src/frontend/agraf.c @@ -0,0 +1,334 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Line-printer (ASCII) plots. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "agraf.h" + +#define FUDGE 7 +#define MARGIN_BASE 11 +#define LCHAR '.' +#define MCHAR 'X' +#define PCHARS "+*=$%!0123456789" + +/* We should really deal with the xlog and delta arguments. This routine is + * full of magic numbers that make the formatting correct. + */ + + +void +ft_agraf(double *xlims, double *ylims, struct dvec *xscale, struct plot *plot, struct dvec *vecs, double xdel, double ydel, bool xlog, bool ylog, bool nointerp) +{ + int height; + bool nobreakp, novalue; + int maxx, maxy, omaxy; /* The size of the plotting area. */ + bool /* xlogscale = FALSE, */ ylogscale = FALSE; + char *field, buf[BSIZE_SP]; + char *line1, *line2, c, cb; + double xrange[2], yrange[2], x1, x2, yy1, y2, x, y; + int mag, hmt, lmt, dst, spacing, nsp, ypt, upper, lower, curline; + double tenpowmag, diff, *values; + struct dvec *v; + int margin = MARGIN_BASE; + int omargin; + register int i, j, k; + int shift; + + + /* ANSI C does not specify how many digits are in an exponent for %c + * We assumed it was 2. If it's more, shift starting position over. + */ + (void) sprintf(buf, "%1.1e", 0.0); /* expect 0.0e+00 */ + shift = strlen(buf) - 7; + margin += shift; + + /* Make sure the margin is correct */ + omargin = margin; + if (!cp_getvar("noasciiplotvalue", VT_BOOL, (char *) &novalue) && + !vec_eq(xscale, vecs)) { + margin *= 2; + } else + novalue = TRUE; + if ((xscale->v_gridtype == GRID_YLOG) || + (xscale->v_gridtype == GRID_LOGLOG)) + ylogscale = TRUE; + if (!cp_getvar("width", VT_NUM, (char *) &maxy)) { + maxy = DEF_WIDTH; + } + if (!cp_getvar("height", VT_NUM, (char *) &height)) + height = DEF_HEIGHT; + if (ft_nopage) + nobreakp = TRUE; + else + cp_getvar("nobreak", VT_BOOL, (char *) &nobreakp); + maxy -= (margin + FUDGE); + maxx = xscale->v_length; + xrange[0] = xlims[0]; + xrange[1] = xlims[1]; + yrange[0] = ylims[0]; + yrange[1] = ylims[1]; + + if (maxx < 2) { + fprintf(cp_err, + "Error: asciiplot can't handle scale with length < 2\n"); + return; + } + + if (maxx <= 0) { + fprintf(cp_err, "Note: no points to plot\n"); + return; + } + + for (v = vecs, i = 0; v; v = v->v_link2) { + v->v_linestyle = (PCHARS[i] ? PCHARS[i++] : '#'); + } + /* Now allocate the field and stuff. */ + field = tmalloc((maxy + 1) * (maxx + 1)); + line1 = tmalloc(maxy + margin + FUDGE + 1); + line2 = tmalloc(maxy + margin + FUDGE + 1); + if (!novalue) + values = (double *) tmalloc(maxx * sizeof (double)); + + /* Clear the field, put the lines in the right places, and create + * the headers. + */ + for (i = 0, j = (maxx + 1) * (maxy + 1); i < j; i++) + field[i] = ' '; + for (i = 0, j = maxy + margin + FUDGE; i < j; i++) { + line1[i] = '-'; + line2[i] = ' '; + } + line1[j] = line2[j] = '\0'; + + /* The following is similar to the stuff in grid.c */ + if ((xrange[0] > xrange[1]) || (yrange[0] > yrange[1])) { + fprintf(cp_err, + "ft_agraf: Internal Error: bad limits %g, %g, %g, %g\n", + xrange[0], xrange[1], yrange[0], yrange[1]); + return; + } + + /* gcc doesn't like !double */ + if (ylims[1] == 0.0) { + mag = (int) floor(mylog10(- ylims[0])); + tenpowmag = pow(10.0, (double) mag); + } else if (ylims[0] == 0.0) { + mag = (int) floor(mylog10(ylims[1])); + tenpowmag = pow(10.0, (double) mag); + } else { + diff = ylims[1] - ylims[0]; + mag = (int) floor(mylog10(diff)); + tenpowmag = pow(10.0, (double) mag); + } + + lmt = (int) floor(ylims[0] / tenpowmag); + yrange[0] = ylims[0] = lmt * tenpowmag; + hmt = (int) ceil(ylims[1] / tenpowmag); + yrange[1] = ylims[1] = hmt * tenpowmag; + + dst = hmt - lmt; + + /* This is a strange case; I don't know why it's here. */ + if (dst == 11) + dst = 12; + else if (dst == 1) { + dst = 10; + mag++; + hmt *= 10.0; + lmt *= 10.0; + } else if (dst == 0) { + dst = 2; + lmt -= 1; + hmt += 1; + } + + for (nsp = 4; nsp < 8; nsp++) + if (!(dst % nsp)) + break; + if (nsp == 8) + for (nsp = 2; nsp < 4; nsp++) + if (!(dst % nsp)) + break; + spacing = maxy / nsp; + + /* Reset the max X coordinate to deal with round-off error. */ + omaxy = maxy + 1; + maxy = spacing * nsp; + + for (i = 0, j = lmt; j <= hmt; i += spacing, j += dst / nsp) { + for (k = 0; k < maxx; k++) + field[k * omaxy + i] = LCHAR; + line1[i + margin + 2 * shift] = '|'; + (void) sprintf(buf, "%.2e", j * pow(10.0, (double) mag)); + bcopy(buf, &line2[i + margin - ((j < 0) ? 2 : 1) - shift], + strlen(buf)); + } + line1[i - spacing + margin + 1] = '\0'; + + for (i = 1; i < omargin - 1 && xscale->v_name[i - 1]; i++) + line2[i] = xscale->v_name[i - 1]; + if (!novalue) + for (i = omargin + 1; + i < margin - 2 && (vecs->v_name[i - omargin - 1]); + i++) + line2[i] = vecs->v_name[i - omargin - 1]; + + /* Now the buffers are all set up properly. Plot points for each + * vector using interpolation. For each point on the x-axis, find the + * two bracketing points in xscale, and then interpolate their + * y values for each vector. + */ + + upper = lower = 0; + for (i = 0; i < maxx; i++) { + if (nointerp) + x = isreal(xscale) ? xscale->v_realdata[i] : + realpart(&xscale->v_compdata[i]); + else if (xlog && xrange[0] > 0.0 && xrange[1] > 0.0) + x = xrange[0] * pow( 10.0, mylog10(xrange[1]/xrange[0]) + * i / (maxx - 1)); + else + x = xrange[0] + (xrange[1] - xrange[0]) * i / + (maxx - 1); + while ((isreal(xscale) ? (xscale->v_realdata[upper] < x) : + (realpart(&xscale->v_compdata[upper]) < x)) && + (upper < xscale->v_length - 1)) + upper++; + while ((isreal(xscale) ? (xscale->v_realdata[lower] < x) : + (realpart(&xscale->v_compdata[lower]) < x)) && + (lower < xscale->v_length - 1)) + lower++; + if ((isreal(xscale) ? (xscale->v_realdata[lower] > x) : + (realpart(&xscale->v_compdata[lower]) > x)) && + (lower > 0)) + lower--; + x1 = (isreal(xscale) ? xscale->v_realdata[lower] : + realpart(&xscale->v_compdata[lower])); + x2 = (isreal(xscale) ? xscale->v_realdata[upper] : + realpart(&xscale->v_compdata[upper])); + if (x1 > x2) { + fprintf(cp_err, "Error: X scale (%s) not monotonic\n", + xscale->v_name); + return; + } + for (v = vecs; v; v = v->v_link2) { + yy1 = (isreal(v) ? v->v_realdata[lower] : + realpart(&v->v_compdata[lower])); + y2 = (isreal(v) ? v->v_realdata[upper] : + realpart(&v->v_compdata[upper])); + if (x1 == x2) + y = yy1; + else + y = yy1 + (y2 - yy1) * (x - x1) / (x2 - x1); + if (!novalue && (v == vecs)) + values[i] = y; + ypt = ft_findpoint(y, yrange, maxy, 0, ylogscale); + c = field[omaxy * i + ypt]; + if ((c == ' ') || (c == LCHAR)) + field[omaxy * i + ypt] = (char) v->v_linestyle; + else + field[omaxy * i + ypt] = MCHAR; + } + } + + out_init(); + for (i = 0; i < omaxy + margin; i++) + out_send("-"); + out_send("\n"); + i = (omaxy + margin - strlen(plot->pl_title)) / 2; + while (i-- > 0) + out_send(" "); + (void) strcpy(buf, plot->pl_title); + buf[maxy + margin] = '\0'; /* Cut off if too wide */ + out_send(buf); + out_send("\n"); + (void) sprintf(buf, "%s %s", plot->pl_name, plot->pl_date); + buf[maxy + margin] = '\0'; + i = (omaxy + margin - strlen(buf)) / 2; + while (i-- > 0) + out_send(" "); + out_send(buf); + out_send("\n\n"); + curline = 7; + out_send("Legend: "); + i = 0; + j = (maxx + margin - 8) / 20; + if (j == 0) + j = 1; + for (v = vecs; v; v = v->v_link2) { + out_pbuf[0] = (char) v->v_linestyle; + out_pbuf[1] = '\0'; +/* out_printf("%c = %-17s", (char) v->v_linestyle, v->v_name); */ + out_printf("%s = %-17s", out_pbuf, v->v_name); + if (!(++i % j) && v->v_link2) { + out_send("\n "); + curline++; + } + } + out_send("\n"); + for (i = 0; i < omaxy + margin; i++) + out_send("-"); + out_send("\n"); + i = 0; + out_printf("%s\n%s\n", line2, line1); + curline += 2; + for (i = 0; i < maxx; i++) { + if (nointerp) + x = isreal(xscale) ? xscale->v_realdata[i] : + realpart(&xscale->v_compdata[i]); + else if (xlog && xrange[0] > 0.0 && xrange[1] > 0.0) + x = xrange[0] * pow( 10.0, mylog10(xrange[1]/xrange[0]) + * i / (maxx - 1)); + else + x = xrange[0] + (xrange[1] - xrange[0]) * i / (maxx - 1); + if (x < 0.0) { + sprintf(out_pbuf, "%.3e ", x); + out_send(out_pbuf); +/* out_printf("%.3e ", x); */ + } else { + sprintf(out_pbuf, " %.3e ", x); + out_send(out_pbuf); +/* out_printf(" %.3e ", x); */ + } + if (!novalue) { + if (values[i] < 0.0) { + sprintf(out_pbuf, "%.3e ", values[i]); + out_send(out_pbuf); +/* out_printf("%.3e ", values[i]); */ + } else { + sprintf(out_pbuf, " %.3e ", values[i]); + out_send(out_pbuf); +/* out_printf(" %.3e ", values[i]); */ + } + } + cb = field[(i + 1) * omaxy]; + field[(i + 1) * omaxy] = '\0'; + out_send(&field[i * omaxy]); + field[(i + 1) * omaxy] = cb; + out_send("\n"); + if (((curline++ % height) == 0) && (i < maxx - 1) && + !nobreakp) { + out_printf("%s\n%s\n\014\n%s\n%s\n", line1, line2, + line2, line1); + curline += 5; + } + } + out_printf("%s\n%s\n", line1, line2); + + tfree(field); + tfree(line1); + tfree(line2); + if (!novalue) + tfree(values); + return; +} + diff --git a/src/frontend/agraf.h b/src/frontend/agraf.h new file mode 100644 index 000000000..eb54ee764 --- /dev/null +++ b/src/frontend/agraf.h @@ -0,0 +1,13 @@ +/************* + * Header file for agraf.c + * 1999 E. Rouat + ************/ + +#ifndef AGRAF_H_INCLUDED +#define AGRAF_H_INCLUDED + +void ft_agraf(double *xlims, double *ylims, struct dvec *xscale, struct plot *plot, + struct dvec *vecs, double xdel, double ydel, bool xlog, bool ylog, + bool nointerp); + +#endif diff --git a/src/frontend/arg.c b/src/frontend/arg.c new file mode 100644 index 000000000..e62afde7c --- /dev/null +++ b/src/frontend/arg.c @@ -0,0 +1,133 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Jeffrey M. Hsu +**********/ + +/* + This files contains the routines to evalute arguments to a command + and prompt the user if necessary. +*/ + +#include "ngspice.h" +#include "fteinput.h" +#include "cpdefs.h" +#include "fteext.h" +#include "arg.h" + + +static void common(char *string, struct wordlist *wl, struct comm *command); + + +/* returns a private copy of the string */ + +char *prompt(FILE *fp) +{ + char buf[100]; + char *p; + int n; + + if (!fgets(buf, sizeof(buf), fp)) + return 0; + n = strlen(buf) - 1; + buf[n] = '\0'; /* fgets leaves the \n */ + p = (char *) tmalloc(n + 1); + strcpy(p, buf); + return p; +} + +int countargs(wordlist *wl) +{ + + int number=0; + wordlist *w; + + for (w = wl; w; w = w->wl_next) { + number++ ; + } + return(number); + +} + +wordlist *process(wordlist *wlist) +{ + + wlist = cp_variablesubst(wlist); + wlist = cp_bquote(wlist); + wlist = cp_doglob(wlist); + return (wlist); + +} + +void arg_print(wordlist *wl, struct comm *command) +{ + + common("which variable", wl, command); + +} + +void arg_plot(wordlist *wl, struct comm *command) +{ + + common("which variable", wl, command); + +} + +void arg_load(wordlist *wl, struct comm *command) +{ + /* just call com_load */ + (*command->co_func) (wl); + +} + +void arg_let(wordlist *wl, struct comm *command) +{ + + common("which vector", wl, command); + +} + +void arg_set(wordlist *wl, struct comm *command) +{ + + common("which variable", wl, command); + +} + +void arg_display(void) +{ + + /* just return; display does the right thing */ + +} + +/* a common prompt routine */ +static void +common(char *string, struct wordlist *wl, struct comm *command) +{ + + struct wordlist *w; + char *buf; + + if (!countargs(wl)) { + outmenuprompt(string); + if ((buf = prompt(cp_in)) == NULL) /* prompt aborted */ + return; /* don't execute command */ + /* do something with the wordlist */ + w = alloc(struct wordlist); + w->wl_word = buf; + w->wl_next = NULL; + + w = process(w); + /* O.K. now call fn */ + (*command->co_func) (w); + } + +} + +void +outmenuprompt(char *string) +{ + fprintf(cp_out, "%s: ", string); + fflush(cp_out); + return; +} diff --git a/src/frontend/arg.h b/src/frontend/arg.h new file mode 100644 index 000000000..e407ee9c5 --- /dev/null +++ b/src/frontend/arg.h @@ -0,0 +1,21 @@ +/************* + * Header file for arg.c + * 1999 E. Rouat + ************/ + +#ifndef ARG_H_INCLUDED +#define ARG_H_INCLUDED + +char *prompt(FILE *fp); +int countargs(wordlist *wl); +wordlist *process(wordlist *wlist); +void arg_print(wordlist *wl, struct comm *command); +void arg_plot(wordlist *wl, struct comm *command); +void arg_load(wordlist *wl, struct comm *command); +void arg_let(wordlist *wl, struct comm *command); +void arg_set(wordlist *wl, struct comm *command); +void arg_display(void); +void outmenuprompt(char *string); + + +#endif diff --git a/src/frontend/aspice.c b/src/frontend/aspice.c new file mode 100644 index 000000000..1e4aadc1c --- /dev/null +++ b/src/frontend/aspice.c @@ -0,0 +1,442 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Stuff for asynchronous spice runs, and also rspice. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "aspice.h" + + +# ifdef HAVE_SYS_WAIT_H + /* should be more tests here I think */ +# define OK_ASPICE +# endif + +#ifdef OK_ASPICE + +#ifdef HAVE_PWD_H +# include +#endif + +#include +#include +#include + +#include + +#include "fteinp.h" +#include "ftedata.h" + + +#ifndef SEEK_SET +# define SEEK_SET 0 +#endif + +static RETSIGTYPE sigchild(void); + +struct proc { + int pr_pid; /* The pid of the spice job. */ + char *pr_rawfile; /* The temporary raw file. */ + char *pr_name; /* The name of the spice run. */ + char *pr_inpfile; /* The name of the input file. */ + char *pr_outfile; /* The name of the (tmp) output file. */ + bool pr_saveout; /* Don't (void) unlink the output file */ + struct proc *pr_next; /* Link. */ +} ; + +static struct proc *running = NULL; +static int numchanged = 0; /* How many children have changed in state. */ + + +extern pid_t fork (void); +extern int dup2 (int, int); +extern int execl (const char *, const char *, ...); +extern int unlink (const char *); +extern int pipe (int *); +extern int close (int); +extern int execlp (const char *, const char *, ...); + +void +com_aspice(wordlist *wl) +{ + char *deck, *output = NULL, spicepath[BSIZE_SP], s[BSIZE_SP]; + char *raw, *t; + FILE *inp; + struct proc *p; + int pid; + bool saveout = FALSE; + + deck = wl->wl_word; + if (!cp_getvar("spicepath", VT_STRING, spicepath)) { + if (!Spice_Path || !*Spice_Path) { + fprintf(cp_err, + "No spice-3 binary is available for the aspice command.\n"); + return; + } + (void) strcpy(spicepath, Spice_Path); + } + + if (wl->wl_next) { + output = wl->wl_next->wl_word; + saveout = TRUE; + } else { + output = smktemp("spout"); + } + + if ((inp = fopen(deck, "r")) == NULL) { + perror(deck); + return; + } + if (!fgets(s, BSIZE_SP, inp)) { + fprintf(cp_err, "Error: bad deck %s\n", deck); + (void) fclose(inp); + return; + } + for (t = s; *t && (*t != '\n'); t++) + ; + *t = '\0'; + fprintf(cp_out, "Starting spice run for:\n%s\n", s); + (void) fclose(inp); + raw = smktemp("raw"); + (void) fclose(fopen(raw, "w")); /* So there isn't a race condition. */ + pid = fork(); + if (pid == 0) { + if (!(freopen(deck, "r", stdin))) { + perror(deck); + exit (EXIT_BAD); + } + if (!(freopen(output, "w", stdout))) { + perror(output); + exit (EXIT_BAD); + } + (void) dup2(fileno(stdout), fileno(stderr)); + + (void) execl(spicepath, spicepath, "-r", raw, 0); + + /* Screwed up. */ + perror(spicepath); + exit(EXIT_BAD); + } + + /* Add this one to the job list. */ + p = alloc(struct proc); + p->pr_pid = pid; + p->pr_name = copy(s); + p->pr_rawfile = copy(raw); + p->pr_inpfile = copy(deck); + p->pr_outfile = copy(output); + p->pr_saveout = saveout; + if (running) + p->pr_next = running; + running = p; +# ifdef SIGCHLD + (void) signal(SIGCHLD, (SIGNAL_FUNCTION) sigchild); +# else +# ifdef SIGCLD + (void) signal(SIGCLD, (SIGNAL_FUNCTION) sigchild); +# endif +# endif + return; +} + + +void +com_jobs(wordlist *wl) +{ + struct proc *p; + + for (p = running; p; p = p->pr_next) + fprintf(cp_out, "%d\t%.70s\n", p->pr_pid, p->pr_name); + return; +} + +static RETSIGTYPE +sigchild(void) +{ + numchanged++; + if (ft_asyncdb) + fprintf(cp_err, "%d jobs done now\n", numchanged); + if (cp_cwait) { + ft_checkkids(); + } + return; +} + +/* This gets called every once in a while, and checks to see if any + * jobs have finished. If they have it gets the data. The problem is + * that wait(0) is probably more portable, but it can't tell + * whether the exit was normal or not. + */ + +void +ft_checkkids(void) +{ + struct proc *p, *lp; + char buf[BSIZE_SP]; + FILE *fp; + int pid; + static bool here = FALSE; /* Don't want to be re-entrant. */ + + if (!numchanged || here) + return; + + here = TRUE; + + while (numchanged > 0) { + pid = wait((union wait *) NULL); + if (pid == -1) { + fprintf(cp_err, +"ft_checkkids: Internal Error: should be %d jobs done but there aren't any.\n", + numchanged); + numchanged = 0; + running = NULL; + here = FALSE; + return; + } + for (p = running; p; p = p->pr_next) { + if (p->pr_pid == pid) + break; + lp = p; + } + if (p == NULL) { + fprintf(cp_err, + "ft_checkkids: Internal Error: Process %d not a job!\n", + pid); + here = FALSE; + return; + } + if (p == running) + running = p->pr_next; + else + lp->pr_next = p->pr_next; + fprintf(cp_out, "Job finished: %.60s\n", p->pr_name); + numchanged--; + ft_loadfile(p->pr_rawfile); + (void) unlink(p->pr_rawfile); + out_init(); + if (!(fp = fopen(p->pr_outfile, "r"))) { + perror(p->pr_outfile); + here = FALSE; + return; + } + while (fgets(buf, BSIZE_SP, fp)) + out_send(buf); + (void) fclose(fp); + if (!p->pr_saveout) + (void) unlink(p->pr_outfile); + printf("\n-----\n"); + } + printf("\n"); +#ifdef TIOCSTI + (void) ioctl(0, TIOCSTI, "\022"); /* Reprint the line. */ +#endif + here = FALSE; + return; +} + +/* Run a spice job remotely. See the description of the spice daemon for + * the protocol. This is no longer 4.2 specific. + */ + +void +com_rspice(wordlist *wl) +{ + char rhost[64], program[128], buf[BSIZE_SP]; + char remote_shell[513]; + char *outfile; + FILE *inp, *serv, *out, *srv_input, *err_outp; + struct plot *pl; + int i; + int to_serv[2], from_serv[2], err_serv[2]; + int pid; + long pos; + int num; + char *p; + + /* Figure out where the spicedaemon is and connect to it. */ + if (!cp_getvar("rhost", VT_STRING, rhost)) + (void) strcpy(rhost, Spice_Host); + if (!cp_getvar("rprogram", VT_STRING, program)) + *program = '\0'; + if (!cp_getvar("remote_shell", VT_STRING, remote_shell)) + strcpy(remote_shell, "rsh"); + + if (*rhost == '\0') { + fprintf(cp_err, + "Error: there is no remote ngspice.host for this site -- set \"rhost\".\n"); + return; + } + if (*program == '\0') { + fprintf(cp_err, +"Error: there is no remote spice program for this site -- set \"rprogram\".\n"); + return; + } + + if (pipe(to_serv) < 0) { + perror("pipe to server"); + return; + } + if (pipe(from_serv) < 0) { + perror("pipe from server"); + return; + } + if (pipe(err_serv) < 0) { + perror("2nd pipe from server"); + return; + } + + pid = fork( ); + if (pid == 0) { +#ifdef notdef + char com_buf[200]; + + sprintf(com_buf, "%s %s %s -s", remote_shell, rhost, program); + printf("executing: \"%s\"\n", com_buf); +#endif + /* I am the "server" process */ + close(to_serv[1]); + close(from_serv[0]); + close(err_serv[0]); + + fclose(stdin); + fclose(stdout); + fclose(stderr); + + dup2(to_serv[0], 0); /* stdin */ + dup2(from_serv[1], 1); /* stdout */ + dup2(err_serv[1], 2); /* stderr */ + + execlp(remote_shell, remote_shell, rhost, program, "-s", 0); + /* system(com_buf); */ + perror(remote_shell); + exit(-1); + } else if (pid == -1) { + perror("fork"); + return; + } + + /* I am the "client" side */ + close(to_serv[0]); + close(from_serv[1]); + close(err_serv[1]); + srv_input = fdopen(to_serv[1], "w"); + serv = fdopen(from_serv[0], "r"); + err_outp = fdopen(err_serv[0], "r"); + + /* Send the circuit over. */ + if (wl) { + while (wl) { + if (!(inp = fopen(wl->wl_word, "r"))) { + perror(wl->wl_word); + wl = wl->wl_next; + continue; /* Should be careful */ + } + while ((i = fread(buf, 1, BSIZE_SP, inp)) > 0) + (void) fwrite(buf, 1, strlen(buf), srv_input); + /* (void) write(s, buf, i); */ + wl = wl->wl_next; + fclose(inp); + } + /* (void) write(s, "@\n", 3);*/ + } else { + if (ft_nutmeg || !ft_curckt) { + fprintf(cp_err, "Error: no circuits loaded\n"); + fclose(srv_input); + fclose(serv); + return; + } + + inp_list(srv_input, ft_curckt->ci_deck, ft_curckt->ci_options, + LS_DECK); + } + fclose(srv_input); + + /* Now wait for things to come through */ + while ((p = fgets(buf, BSIZE_SP, serv)) != NULL) { + if (!strncmp(buf, "Title:", 6)) + break; + fputs(buf, cp_out); + } + outfile = smktemp("rsp"); + if (!(out = fopen(outfile, "w+"))) { + perror(outfile); + (void) fclose(serv); + return; + } + if (p) + fputs(buf, out); + while ((i = fread(buf, 1, BSIZE_SP, serv))) { + (void) fwrite(buf, 1, i, out); + } + /* We hope that positioning info + error messages < pipe size */ + while (fgets(buf, BSIZE_SP, err_outp)) { + if (!strncmp("@@@", buf, 3)) { + if (sscanf(buf, "@@@ %ld %d", &pos, &num) != 2) { + fprintf(stderr, "Error reading rawdata: %s\n", buf); + continue; + } +#ifdef notdef + fprintf(stderr, "adjusting rawfile: write \"%d\" at %ld\n", + num, pos); +#endif + if (fseek(out, pos, SEEK_SET)) + fprintf(stderr, + "Error adjusting rawfile: write \"%d\" at %ld\n", + num, pos); + else + fprintf(out, "%d", num); + } else + fprintf(stderr, "%s", buf); + } + + (void) fclose(out); + (void) fclose(serv); + (void) fclose(err_outp); + + pl = raw_read(outfile); + if (pl) + plot_add(pl); + (void) unlink(outfile); + fprintf(stderr, "done.\n"); + return; +} + +#else + +void +com_aspice(wl) + wordlist *wl; +{ + fprintf(cp_err, "Asynchronous spice jobs are not available.\n"); + return; +} + +void +com_jobs(wl) + wordlist *wl; +{ + fprintf(cp_err, "Asynchronous spice jobs are not available.\n"); + return; +} + +void +ft_checkkids( ) +{ + return; +} + +void +com_rspice(wl) + wordlist *wl; +{ + fprintf(cp_err, "Remote spice jobs are not available.\n"); + return; +} + +#endif diff --git a/src/frontend/aspice.h b/src/frontend/aspice.h new file mode 100644 index 000000000..89331ae5f --- /dev/null +++ b/src/frontend/aspice.h @@ -0,0 +1,16 @@ +/************* + * Header file for aspice.c + * 1999 E. Rouat + ************/ + +#ifndef ASPICE_H_INCLUDED +#define ASPICE_H_INCLUDED + + +void com_aspice(wordlist *wl); +void com_jobs(wordlist *wl); +void ft_checkkids(void); +void com_rspice(wordlist *wl); + + +#endif diff --git a/src/frontend/breakp.c b/src/frontend/breakp.c new file mode 100644 index 000000000..1496cba6d --- /dev/null +++ b/src/frontend/breakp.c @@ -0,0 +1,510 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Code to deal with breakpoints and tracing. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftedebug.h" +#include "breakp.h" + + +static bool satisfied(struct dbcomm *d, struct plot *plot); +static void printcond(struct dbcomm *d, FILE *fp); + +void dbfree(struct dbcomm *db); +extern struct dbcomm *dbs; /* export for iplot */ +extern int debugnumber; +static int howmanysteps = 0; +static int steps = 0; + +/* Set a breakpoint. Possible commands are: + * stop after n + * stop when var cond val + * + * If more than one is given on a command line, then this is a conjunction. + */ + + +extern void settrace (wordlist *wl, int what, char *name); + +void +com_stop(wordlist *wl) +{ + struct dbcomm *thisone = NULL; + struct dbcomm *d = NULL; + char *s, buf[64]; + int i; + double *val; + + while (wl) { + if (thisone == NULL) + thisone = d = alloc(struct dbcomm); + else { + d->db_also = alloc(struct dbcomm); + d = d->db_also; + } + + /* Figure out what the first condition is. */ + d->db_analysis = NULL; + if (eq(wl->wl_word, "after") && wl->wl_next) { + d->db_type = DB_STOPAFTER; + d->db_number = debugnumber; + if (!wl->wl_next->wl_word) + i = 0; + else { +#ifdef HAVE_CTYPE_H + for (s = wl->wl_next->wl_word, i = 0; *s; s++) + if (!isdigit(*s)) + goto bad; + else + i = i * 10 + (*s - '0'); +#else + i = atoi(wl->wl_next->wl_word); /* etoi ??? */ +#endif + } + d->db_iteration = i; + wl = wl->wl_next->wl_next; + } else if (eq(wl->wl_word, "when") && wl->wl_next && + wl->wl_next->wl_next && /* ick */ + wl->wl_next->wl_next->wl_next) { + wl = wl->wl_next; + d->db_number = debugnumber; + d->db_type = DB_STOPWHEN; + s = wl->wl_word; + val = ft_numparse(&s, FALSE); + if (val) + d->db_value1 = *val; + else + d->db_nodename1 = copy(wl->wl_word); + wl = wl->wl_next; + + /* Now get the condition */ + if (eq(wl->wl_word, "eq") || eq(wl->wl_word, "=")) + d->db_op = DBC_EQU; + else if (eq(wl->wl_word, "ne") || eq(wl->wl_word, "<>")) + d->db_op = DBC_NEQ; + else if (eq(wl->wl_word, "gt") || eq(wl->wl_word, ">")) + d->db_op = DBC_GT; + else if (eq(wl->wl_word, "lt") || eq(wl->wl_word, "<")) + d->db_op = DBC_LT; + else if (eq(wl->wl_word, "ge") || eq(wl->wl_word, ">=")) + d->db_op = DBC_GTE; + else if (eq(wl->wl_word, "le") || eq(wl->wl_word, "<=")) + d->db_op = DBC_LTE; + else + goto bad; + wl = wl->wl_next; + + /* Now see about the second one. */ + s = wl->wl_word; + val = ft_numparse(&s, FALSE); + if (val) + d->db_value2 = *val; + else + d->db_nodename2 = copy(wl->wl_word); + wl = wl->wl_next; + } else + goto bad; + } + if (thisone) { + if (dbs) { + for (d = dbs; d->db_next; d = d->db_next); + d->db_next = thisone; + } else + dbs = thisone; + (void) sprintf(buf, "%d", debugnumber); + cp_addkword(CT_DBNUMS, buf); + debugnumber++; + } + + return; + +bad: fprintf(cp_err, "Syntax error parsing breakpoint specification.\n"); + return; +} + +/* Trace a node (have wrd_point print it). Usage is "trace node ..."*/ + +void +com_trce(wordlist *wl) +{ + settrace(wl, VF_PRINT, 0); + return; +} + +/* Incrementally plot a value. This is just like trace. */ + +void +com_iplot(wordlist *wl) +{ + + /* settrace(wl, VF_PLOT); */ + + struct dbcomm *d, *td, *currentdb = NULL; + char *s; + + /* We use a modified ad-hoc algorithm here where db_also denotes + vectors on the same command line and db_next denotes + separate iplot commands. */ + while (wl) { + s = cp_unquote(wl->wl_word); + d = alloc(struct dbcomm); + d->db_analysis = NULL; + d->db_number = debugnumber++; + if (eq(s, "all")) { + d->db_type = DB_IPLOTALL; + } else { + d->db_type = DB_IPLOT; + d->db_nodename1 = copy(s); + } + d->db_also = currentdb; + currentdb = d; + wl = wl->wl_next; + } + if (dbs) { + for (td = dbs; td->db_next; td = td->db_next) + ; + td->db_next = currentdb; + } else + dbs = currentdb; + + return; + +} + +/* Step a number of iterations. */ + +void +com_step(wordlist *wl) +{ + if (wl) + steps = howmanysteps = atoi(wl->wl_word); + else + steps = howmanysteps = 1; + com_resume((wordlist *) NULL); + return; +} + +/* Print out the currently active breakpoints and traces. If we are printing + * to a file, assume that the file will be used for a later source and leave + * off the event numbers (with UNIX, that is). -- I don't like this. + */ + +#define isatty(xxxx) 1 + + +void +com_sttus(wordlist *wl) +{ + struct dbcomm *d, *dc; + + for (d = dbs; d; d = d->db_next) { + if (d->db_type == DB_TRACENODE) { + if (isatty(fileno(cp_out))) + fprintf(cp_out, "%-4d trace %s", d->db_number, + d->db_nodename1); + else + fprintf(cp_out, "trace %s", d->db_nodename1); + } else if (d->db_type == DB_IPLOT) { + if (isatty(fileno(cp_out))) { + fprintf(cp_out, "%-4d iplot %s", d->db_number, + d->db_nodename1); + } else { + fprintf(cp_out, "iplot %s", d->db_nodename1); + } + for (dc = d->db_also; dc; dc = dc->db_also) { + fprintf(cp_out, " %s", dc->db_nodename1); + } + } else if (d->db_type == DB_SAVE) { + if (isatty(fileno(cp_out))) + fprintf(cp_out, "%-4d save %s", d->db_number, + d->db_nodename1); + else + fprintf(cp_out, "save %s", d->db_nodename1); + } else if (d->db_type == DB_TRACEALL) { + if (isatty(fileno(cp_out))) + fprintf(cp_out, "%-4d trace all", d->db_number); + else + fprintf(cp_out, "trace all"); + } else if (d->db_type == DB_IPLOTALL) { + if (isatty(fileno(cp_out))) + fprintf(cp_out, "%-4d iplot all", d->db_number); + else + fprintf(cp_out, "iplot all"); + } else if (d->db_type == DB_SAVEALL) { + if (isatty(fileno(cp_out))) + fprintf(cp_out, "%-4d save all", d->db_number); + else + fprintf(cp_out, "save all"); + } else if ((d->db_type == DB_STOPAFTER) || + (d->db_type == DB_STOPWHEN)) { + if (isatty(fileno(cp_out))) + fprintf(cp_out, "%-4d stop", d->db_number); + else + fprintf(cp_out, "stop"); + printcond(d, cp_out); + } else if ((d->db_type == DB_DEADIPLOT)) { + if (isatty(fileno(cp_out))) { + fprintf(cp_out, "%-4d exiting iplot %s", d->db_number, + d->db_nodename1); + } else { + fprintf(cp_out, "exiting iplot %s", d->db_nodename1); + } + for (dc = d->db_also; dc; dc = dc->db_also) { + fprintf(cp_out, " %s", dc->db_nodename1); + } + } else + fprintf(cp_err, + "com_sttus: Internal Error: bad db %d\n", d->db_type); + (void) putc('\n', cp_out); + } + return; +} + +void +dbfree(struct dbcomm *db) +{ + struct dbcomm *dd, *dn; + + for (dd = db; dd; dd = dn) { + dn = dd->db_also; + tfree(dd->db_nodename1); + tfree(dd->db_nodename2); + tfree(dd); + } + return; +} + +/* Delete breakpoints and traces. Usage is delete [number ...] */ + +void +com_delete(wordlist *wl) +{ + int i; + char *s, buf[64]; + struct dbcomm *d, *dt; + + if (wl && eq(wl->wl_word, "all")) { + for (dt = dbs; dt; dt = d) { + d = dt->db_next; + dbfree(dt); + } + dbs = NULL; + return; + } else if (!wl) { + if (!dbs) { + fprintf(cp_err, "Error: no debugs in effect\n"); + return; + } + } + while (wl) { + if (wl->wl_word) { +#ifdef HAVE_CTYPE_H + for (s = wl->wl_word, i = 0; *s; s++) + if (!isdigit(*s)) { + fprintf(cp_err, "Error: %s isn't a number.\n", + wl->wl_word); + goto bad; + } else + i = i * 10 + (*s - '0'); +#else + i = atoi(wl->wl_next->wl_word); /* etoi ??? */ +#endif + } else + i = 0; + for (d = dbs, dt = NULL; d; d = d->db_next) { + if (d->db_number == i) { + if (dt) + dt->db_next = d->db_next; + else + dbs = d->db_next; + dbfree(d); + (void) sprintf(buf, "%d", i); + cp_remkword(CT_DBNUMS, buf); + break; + } + dt = d; + } +bad: wl = wl->wl_next; + } + return; +} + +/* Writedata calls this routine to see if it should keep going. If it + * returns TRUE, then the run should resume. + */ + +bool +ft_bpcheck(struct plot *runplot, int iteration) +{ + struct dbcomm *d, *dt; + + if ((howmanysteps > 0) && (--howmanysteps == 0)) { + if (steps > 1) + fprintf(cp_err, "Stopped after %d steps.\n", steps); + return (FALSE); + } + + /* Check the debugs set. */ + for (d = dbs; d; d = d->db_next) { + for (dt = d; dt; dt = dt->db_also) { + switch (dt->db_type) { + case DB_TRACENODE: + case DB_TRACEALL: + case DB_IPLOT: + case DB_DEADIPLOT: + case DB_IPLOTALL: + case DB_SAVE: + case DB_SAVEALL: + goto more; + case DB_STOPAFTER: + if (iteration == dt->db_iteration) + break; + else + goto more; + case DB_STOPWHEN: + /* See if the condition is TRUE. */ + if (satisfied(dt, runplot)) + break; + else + goto more; + default: + fprintf(cp_err, "ft_bpcheck: Internal Error: bad db %d\n", + dt->db_type); + } + } + if (dt == NULL) { + /* It made it */ + fprintf(cp_err, "%-2d: condition met: stop ", + d->db_number); + printcond(d, cp_err); + (void) putc('\n', cp_err); + return (FALSE); + } +more: /* Just continue */ ; + } + return (TRUE); +} + +/* This is called to determine whether a STOPWHEN is TRUE. */ + +static bool +satisfied(struct dbcomm *d, struct plot *plot) +{ + struct dvec *v1 = NULL, *v2 = NULL; + double d1, d2; + + if (d->db_nodename1) { + if ((v1 = vec_fromplot(d->db_nodename1, plot)) == NULL) { + fprintf(cp_err, "Error: %s: no such node\n", + d->db_nodename1); + return (FALSE); + } + if (isreal(v1)) + d1 = v1->v_realdata[v1->v_length - 1]; + else + d1 = realpart(&(v1->v_compdata[v1->v_length - 1])); + } else + d1 = d->db_value1; + + if (d->db_nodename2) { + if ((v2 = vec_fromplot(d->db_nodename2, plot)) == NULL) { + fprintf(cp_err, "Error: %s: no such node\n", + d->db_nodename2); + return (FALSE); + } + if (isreal(v2)) + d2 = v2->v_realdata[v2->v_length - 1]; + else + d2 = realpart(&(v2->v_compdata[v2->v_length - 1])); + } else + d2 = d->db_value2; + + switch (d->db_op) { + case DBC_EQU: + return ((d1 == d2) ? TRUE : FALSE); + case DBC_NEQ: + return ((d1 != d2) ? TRUE : FALSE); + case DBC_GTE: + return ((d1 >= d2) ? TRUE : FALSE); + case DBC_LTE: + return ((d1 <= d2) ? TRUE : FALSE); + case DBC_GT: + return ((d1 > d2) ? TRUE : FALSE); + case DBC_LT: + return ((d1 < d2) ? TRUE : FALSE); + default: + fprintf(cp_err, + "satisfied: Internal Error: bad cond %d\n", + d->db_op); + return (FALSE); + } +} + +/* Writedata calls this before it starts a run, to set the proper flags + * on the dvecs. If a change is made during a break, then the routine + * wrd_chtrace is used from these routines. We have to be clever with save: + * if there was no save given, then save everything. Unfortunately you + * can't stop in the middle, do a save, and have the rest then discarded. + */ + +void +ft_trquery(void) +{ + return; +} + +static void +printcond(struct dbcomm *d, FILE *fp) +{ + struct dbcomm *dt; + + for (dt = d; dt; dt = dt->db_also) { + if (dt->db_type == DB_STOPAFTER) + fprintf(fp, " after %d", dt->db_iteration); + else { + if (dt->db_nodename1) + fprintf(fp, " when %s", + dt->db_nodename1); + else + fprintf(fp, " when %g", dt->db_value1); + switch (dt->db_op) { + case DBC_EQU: + fputs(" =", fp); + break; + case DBC_NEQ: + fputs(" <>", fp); + break; + case DBC_GT: + fputs(" >", fp); + break; + case DBC_LT: + fputs(" <", fp); + break; + case DBC_GTE: + fputs(" >=", fp); + break; + case DBC_LTE: + fputs(" <=", fp); + break; + default: + fprintf(cp_err, + "printcond: Internal Error: bad cond %d", + dt->db_op); + } + if (dt->db_nodename2) + fprintf(fp, " %s", dt->db_nodename2); + else + fprintf(fp, " %g", dt->db_value2); + } + } + return; +} + diff --git a/src/frontend/breakp.h b/src/frontend/breakp.h new file mode 100644 index 000000000..beda7cab3 --- /dev/null +++ b/src/frontend/breakp.h @@ -0,0 +1,22 @@ +/************* + * Header file for breakp.c + * 1999 E. Rouat + ************/ + +#ifndef BREAKP_H_INCLUDED +#define BREAKP_H_INCLUDED + +void com_stop(wordlist *wl); +void com_trce(wordlist *wl); +void com_iplot(wordlist *wl); +void com_step(wordlist *wl); +void com_sttus(wordlist *wl); +void dbfree(struct dbcomm *db); +void com_delete(wordlist *wl); +bool ft_bpcheck(struct plot *runplot, int iteration); +void ft_trquery(void); + + + + +#endif diff --git a/src/frontend/breakp2.c b/src/frontend/breakp2.c new file mode 100644 index 000000000..01e8b84f3 --- /dev/null +++ b/src/frontend/breakp2.c @@ -0,0 +1,126 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Code to deal with breakpoints and tracing. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftedebug.h" +#include "breakp2.h" + + +struct dbcomm *dbs = NULL; /* export for iplot */ +int debugnumber = 1; +void settrace(wordlist *wl, int what, char *name); + +/* Set a breakpoint. Possible commands are: + * stop after n + * stop when var cond val + * + * If more than one is given on a command line, then this is a conjunction. + */ + +/* Save a vector. */ + +void +com_save(wordlist *wl) +{ + settrace(wl, VF_ACCUM, NULL); + return; +} + +void +com_save2(wordlist *wl, char *name) +{ + settrace(wl, VF_ACCUM, name); + return; +} + +void +settrace(wordlist *wl, int what, char *name) +{ + struct dbcomm *d, *td; + char *s; + + while (wl) { + s = cp_unquote(wl->wl_word); + d = alloc(struct dbcomm); + d->db_number = debugnumber++; + d->db_analysis = name; + if (eq(s, "all")) { + switch (what) { + case VF_PRINT: + d->db_type = DB_TRACEALL; + break; +/* case VF_PLOT: + d->db_type = DB_IPLOTALL; + break; */ + case VF_ACCUM: + /* d->db_type = DB_SAVEALL; */ + d->db_nodename1 = copy(s); + d->db_type = DB_SAVE; + break; + } +/* wrd_chtrace((char *) NULL, TRUE, what); */ + } else { + switch (what) { + case VF_PRINT: + d->db_type = DB_TRACENODE; + break; +/* case VF_PLOT: + d->db_type = DB_IPLOT; + break; */ + case VF_ACCUM: + d->db_type = DB_SAVE; + break; + } + d->db_nodename1 = copy(s); +/* wrd_chtrace(s, TRUE, what); */ + } + if (dbs) { + for (td = dbs; td->db_next; td = td->db_next) + ; + td->db_next = d; + } else + dbs = d; + wl = wl->wl_next; + } + return; +} + +int +ft_getSaves(struct save_info **savesp) +{ + struct dbcomm *d; + int count = 0, i = 0; + struct save_info *array; + + for (d = dbs; d; d = d->db_next) + if (d->db_type == DB_SAVE) + count++; + + if (!count) + return (0); + + *savesp = array = (struct save_info *) + tmalloc(sizeof (struct save_info) * count); + + for (d = dbs; d; d = d->db_next) + if (d->db_type == DB_SAVE) { + array[i].used = 0; + if (d->db_analysis) + array[i].analysis = (IFuid *) copy(d->db_analysis); + else + array[i].analysis = NULL; + array[i++].name = copy(d->db_nodename1); + } + + return (count); +} + diff --git a/src/frontend/breakp2.h b/src/frontend/breakp2.h new file mode 100644 index 000000000..1fdf7cca1 --- /dev/null +++ b/src/frontend/breakp2.h @@ -0,0 +1,16 @@ +/************* + * Header file for breakp2.c + * 1999 E. Rouat + ************/ + +#ifndef BREAKP2_H_INCLUDED +#define BREAKP2_H_INCLUDED + + +void com_save(wordlist *wl); +void com_save2(wordlist *wl, char *name); +void settrace(wordlist *wl, int what, char *name); +int ft_getSaves(struct save_info **savesp); + + +#endif diff --git a/src/frontend/circuits.c b/src/frontend/circuits.c new file mode 100644 index 000000000..c0afbffca --- /dev/null +++ b/src/frontend/circuits.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Routines for dealing with the circuit database. This is currently + * unimplemented. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "circuits.h" + + +struct circ *ft_curckt = NULL; /* The default active circuit. */ +struct circ *ft_circuits = NULL; + +struct subcirc *ft_subcircuits = NULL; + +/* Now stuff to deal with circuits */ + + +void +ft_setccirc(char *name) +{ +} + +/* Add a circuit to the circuit list */ + +void +ft_newcirc(struct circ *ckt) +{ + ckt->ci_next = ft_circuits; + ft_circuits = ckt; + return; +} + +/* Add a new subcircuit to the subcircuit list */ + + +void +ft_newsubcirc(struct subcirc *sckt) +{ +} + diff --git a/src/frontend/circuits.h b/src/frontend/circuits.h new file mode 100644 index 000000000..842c6ca62 --- /dev/null +++ b/src/frontend/circuits.h @@ -0,0 +1,15 @@ +/************* + * Header file for circuits.c + * 1999 E. Rouat + ************/ + +#ifndef CIRCUITS_H_INCLUDED +#define CIRCUITS_H_INCLUDED + + +void ft_setccirc(char *name); +void ft_newcirc(struct circ *ckt); +void ft_newsubcirc(struct subcirc *sckt); + + +#endif diff --git a/src/frontend/clip.c b/src/frontend/clip.c new file mode 100644 index 000000000..d7da33f89 --- /dev/null +++ b/src/frontend/clip.c @@ -0,0 +1,214 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopyher, U. C. Berkeley CAD Group +Author: 1982 Giles Billingsley +**********/ + +/* + * Some routines to do clipping of polygons, etc to boxes. Most of this code + * was rescued from MFB: + * sccsid "@(#)mfbclip.c 1.2 12/21/83" + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "clip.h" + + +#define POLYGONBUFSIZE 512 +/* XXX */ + +#define CODEMINX 1 +#define CODEMINY 2 +#define CODEMAXX 4 +#define CODEMAXY 8 +#define CODE(x,y,c) c = 0;\ + if (x < l)\ + c = CODEMINX;\ + else if (x > r)\ + c = CODEMAXX;\ + if (y < b)\ + c |= CODEMINY;\ + else if (y > t)\ + c |= CODEMAXY; + + +#define SWAPINT(a, b) { int xxxx = (a); (a) = (b); (b) = xxxx; } + +/* clip_line will clip a line to a rectangular area. The returned + * value is 'TRUE' if the line is out of the AOI (therefore does not + * need to be displayed) and 'FALSE' if the line is in the AOI. + */ + +bool +clip_line(int *pX1, int *pY1, int *pX2, int *pY2, int l, int b, int r, int t) +{ + int x1 = *pX1; + int y1 = *pY1; + int x2 = *pX2; + int y2 = *pY2; + int x,y,c,c1,c2; + + CODE(x1,y1,c1) + CODE(x2,y2,c2) + while (c1 || c2) { + if (c1 & c2) + return (TRUE); /* Line is invisible. */ + if (!(c = c1)) + c = c2; + if (c & CODEMINX) { + y = y1+(y2-y1)*(l-x1)/(x2-x1); + x = l; + } else if (c & CODEMAXX) { + y = y1+(y2-y1)*(r-x1)/(x2-x1); + x = r; + } else if (c & CODEMINY) { + x = x1+(x2-x1)*(b-y1)/(y2-y1); + y = b; + } else if (c & CODEMAXY) { + x = x1+(x2-x1)*(t-y1)/(y2-y1); + y = t; + } + if (c == c1) { + x1 = x; + y1 = y; + CODE(x,y,c1) + } else { + x2 = x; + y2 = y; + CODE(x,y,c2) + } + } + *pX1 = x1; + *pY1 = y1; + *pX2 = x2; + *pY2 = y2; + return (FALSE); /* Line is at least partially visible.*/ +} + +/* This routine will clip a line to a circle, returning TRUE if the line + * is entirely outside the circle. Note that we have to be careful not + * to switch the points around, since in grid.c we need to know which is + * the outer point for putting the label on. + */ + +bool +clip_to_circle(int *x1, int *y1, int *x2, int *y2, int cx, int cy, int rad) +{ + double perplen, a, b, c; + double tx, ty, dt; + double dtheta; + double theta1, theta2, tt, alpha, beta, gamma; + bool flip = FALSE; + int i; + + /* Get the angles between the origin and the endpoints. */ + if ((*x1-cx) || (*y1-cy)) + theta1 = atan2((double) *y1 - cy, (double) *x1 - cx); + else + theta1 = M_PI; + if ((*x2-cx) || (*y2-cy)) + theta2 = atan2((double) *y2 - cy, (double) *x2 - cx); + else + theta2 = M_PI; + + if (theta1 < 0.0) + theta1 = 2 * M_PI + theta1; + if (theta2 < 0.0) + theta2 = 2 * M_PI + theta2; + + dtheta = theta2 - theta1; + if (dtheta > M_PI) + dtheta = dtheta - 2 * M_PI; + else if (dtheta < - M_PI) + dtheta = 2 * M_PI - dtheta; + + /* Make sure that p1 is the first point */ + if (dtheta < 0) { + tt = theta1; + theta1 = theta2; + theta2 = tt; + i = *x1; + *x1 = *x2; + *x2 = i; + i = *y1; + *y1 = *y2; + *y2 = i; + flip = TRUE; + dtheta = -dtheta; + } + + /* Figure out the distances between the points */ + a = sqrt((double) ((*x1 - cx) * (*x1 - cx) + (*y1 - cy) * (*y1 - cy))); + b = sqrt((double) ((*x2 - cx) * (*x2 - cx) + (*y2 - cy) * (*y2 - cy))); + c = sqrt((double) ((*x1 - *x2) * (*x1 - *x2) + + (*y1 - *y2) * (*y1 - *y2))); + + /* We have three cases now -- either the midpoint of the line is + * closest to the origon, or point 1 or point 2 is. Actually the + * midpoint won't in general be the closest, but if a point besides + * one of the endpoints is closest, the midpoint will be closer than + * both endpoints. + */ + tx = (*x1 + *x2) / 2; + ty = (*y1 + *y2) / 2; + dt = sqrt((double) ((tx - cx) * (tx - cx) + (ty - cy) * (ty - cy))); + if ((dt < a) && (dt < b)) { + /* This is wierd -- round-off errors I guess. */ + tt = (a * a + c * c - b * b) / (2 * a * c); + if (tt > 1.0) + tt = 1.0; + else if (tt < -1.0) + tt = -1.0; + alpha = acos(tt); + perplen = a * sin(alpha); + } else if (a < b) { + perplen = a; + } else { + perplen = b; + } + + /* Now we should see if the line is outside of the circle */ + if (perplen >= rad) + return (TRUE); + + /* It's at least partially inside */ + if (a > rad) { + tt = (a * a + c * c - b * b) / (2 * a * c); + if (tt > 1.0) + tt = 1.0; + else if (tt < -1.0) + tt = -1.0; + alpha = acos(tt); + gamma = asin(sin(alpha) * a / rad); + if (gamma < M_PI / 2) + gamma = M_PI - gamma; + beta = M_PI - alpha - gamma; + *x1 = cx + rad * cos(theta1 + beta); + *y1 = cy + rad * sin(theta1 + beta); + } + if (b > rad) { + tt = (c * c + b * b - a * a) / (2 * b * c); + if (tt > 1.0) + tt = 1.0; + else if (tt < -1.0) + tt = -1.0; + alpha = acos(tt); + gamma = asin(sin(alpha) * b / rad); + if (gamma < M_PI / 2) + gamma = M_PI - gamma; + beta = M_PI - alpha - gamma; + *x2 = cx + rad * cos(theta2 - beta); + *y2 = cy + rad * sin(theta2 - beta); + } + if (flip) { + i = *x1; + *x1 = *x2; + *x2 = i; + i = *y1; + *y1 = *y2; + *y2 = i; + } + return (FALSE); +} diff --git a/src/frontend/clip.h b/src/frontend/clip.h new file mode 100644 index 000000000..d5eee1f39 --- /dev/null +++ b/src/frontend/clip.h @@ -0,0 +1,15 @@ +/************* + * Header file for clip.c + * 1999 E. Rouat + ************/ + +#ifndef CLIP_H_INCLUDED +#define CLIP_H_INCLUDED + + +bool clip_line(int *pX1, int *pY1, int *pX2, int *pY2, int l, int b, int r, int t); +bool clip_to_circle(int *x1, int *y1, int *x2, int *y2, int cx, int cy, int rad); + + + +#endif diff --git a/src/frontend/compose.c b/src/frontend/compose.c new file mode 100644 index 000000000..6dbcbf947 --- /dev/null +++ b/src/frontend/compose.c @@ -0,0 +1,484 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * The 'compose' command. This is a more powerful and convenient form of the + * 'let' command. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "compose.h" + + +static void dimxpand(struct dvec *v, int *newdims, double *data); + + +/* The general syntax is 'compose name parm = val ...' + * The possible parms are: + * start The value at which the vector should start. + * stop The value at which the vector should end. + * step The difference between sucessive elements. + * lin The number of points, linearly spaced. + * log The number of points, logarithmically spaced. + * dec The number of points per decade, logarithmically spaced. + * center Where to center the range of points. + * span The size of the range of points. + * unif ?? + * gauss The number of points in the gaussian distribution. + * mean The mean value for the gass. dist. + * sd The standard deviation for the gauss. dist. + * random The number of randomly selected points. + * pool The name of a vector (must be already defined) to get + * random values -- default is 'unitvec(npoints)' + * + * The case 'compose name values val val ...' takes the values and creates a + * new vector -- the vals may be arbitrary expressions. + * + * NOTE: most of this doesn't work -- there will be plenty of unused variable + * lint messages... + */ + +void +com_compose(wordlist *wl) +{ + double start, stop, step, lin; + double center; + double span; + double mean, sd; + bool startgiven = FALSE, stopgiven = FALSE, stepgiven = FALSE; + bool lingiven = FALSE; + bool loggiven = FALSE, decgiven = FALSE, gaussgiven = FALSE; + bool randmgiven = FALSE; + bool spangiven = FALSE; + bool centergiven = FALSE; + bool meangiven = FALSE; + bool poolgiven = FALSE; + bool sdgiven = FALSE; + int log, dec, gauss, randm; + char *pool; + int i; + + char *resname, *s, *var, *val; + double *td, tt; + double *data; + complex *cdata; + int length, dim, type = SV_NOTYPE, blocksize; + bool realflag = TRUE; + int dims[MAXDIMS]; + struct dvec *result, *vecs = NULL, *v, *lv = NULL; + struct pnode *pn, *first_pn; + bool reverse = FALSE; + + resname = cp_unquote(wl->wl_word); + vec_remove(resname); + wl = wl->wl_next; + if (eq(wl->wl_word, "values")) { + /* Build up the vector from the rest of the line... */ + wl = wl->wl_next; + if (!(pn = ft_getpnames(wl, TRUE))) + return; + first_pn = pn; + while (pn) { + if (!(v = ft_evaluate(pn))) + return; + if (!vecs) + vecs = lv = v; + else + lv->v_link2 = v; + for (lv = v; lv->v_link2; lv = lv->v_link2) + ; + pn = pn->pn_next; + } + free_pnode(first_pn); + /* Now make sure these are all of the same dimensionality. We + * can coerce the sizes... + */ + dim = vecs->v_numdims; + if (dim < 2) + dim = (vecs->v_length > 1) ? 1 : 0; + if (dim == MAXDIMS) { + fprintf(cp_err, "Error: max dimensionality is %d\n", + MAXDIMS); + return; + } + for (v = vecs; v; v = v->v_link2) + if (v->v_numdims < 2) + v->v_dims[0] = v->v_length; + + for (v = vecs->v_link2, length = 1; v; v = v->v_link2) { + i = v->v_numdims; + if (i < 2) + i = (v->v_length > 1) ? 1 : 0; + if (i != dim) { + fprintf(cp_err, + "Error: all vectors must be of the same dimensionality\n"); + return; + } + length++; + if (iscomplex(v)) + realflag = FALSE; + } + for (i = 0; i < dim; i++) { + dims[i] = vecs->v_dims[i]; + for (v = vecs->v_link2; v; v = v->v_link2) + if (v->v_dims[i] > dims[i]) + dims[i] = v->v_dims[i]; + } + dim++; + dims[dim - 1] = length; + for (i = 0, blocksize = 1; i < dim - 1; i++) + blocksize *= dims[i]; + if (realflag) + data = (double *) tmalloc(sizeof (double) * length * + blocksize); + else + cdata = (complex *) tmalloc(sizeof (complex) * length * + blocksize); + + /* Now copy all the data over... If the sizes are too small + * then the extra elements are left as 0. + */ + for (v = vecs, i = 0; v; v = v->v_link2) { + if (dim == 1) { + if (realflag && isreal(v)) + data[i] = v->v_realdata[0]; + else if (isreal(v)) { + realpart(&cdata[i]) = + realpart(&v->v_compdata[0]); + imagpart(&cdata[i]) = 0.0; + } else { + realpart(&cdata[i]) = + realpart(&v->v_compdata[0]); + imagpart(&cdata[i]) = + imagpart(&v->v_compdata[0]); + } + i++; + continue; + } + dimxpand(v, dims, (realflag ? (data + i * blocksize) : + (double *) (cdata + i * blocksize))); + } + + length *= blocksize; + } else { + /* Parse the line... */ + while (wl) { + if ((s =strchr(wl->wl_word, '=')) && s[1]) { + /* This is var=val. */ + *s = '\0'; + var = wl->wl_word; + val = s + 1; + wl = wl->wl_next; + } else if (index(wl->wl_word, '=')) { + /* This is var= val. */ + *s = '\0'; + var = wl->wl_word; + wl = wl->wl_next; + if (wl) { + val = wl->wl_word; + wl = wl->wl_next; + } else { + fprintf(cp_err, "Error: bad syntax\n"); + return; + } + } else { + /* This is var =val or var = val. */ + var = wl->wl_word; + wl = wl->wl_next; + if (wl) { + val = wl->wl_word; + if (*val != '=') { + fprintf(cp_err, + "Error: bad syntax\n"); + return; + } + val++; + if (!*val) { + wl = wl->wl_next; + if (wl) { + val = wl->wl_word; + } else { + fprintf(cp_err, + "Error: bad syntax\n"); + return; + } + } + wl = wl->wl_next; + } else { + fprintf(cp_err, "Error: bad syntax\n"); + return; + } + } + if (cieq(var, "start")) { + startgiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + start = *td; + } else if (cieq(var, "stop")) { + stopgiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + stop = *td; + } else if (cieq(var, "step")) { + stepgiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + step = *td; + } else if (cieq(var, "center")) { + centergiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + center = *td; + } else if (cieq(var, "span")) { + spangiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + span = *td; + } else if (cieq(var, "mean")) { + meangiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + mean = *td; + } else if (cieq(var, "sd")) { + sdgiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + sd = *td; + } else if (cieq(var, "lin")) { + lingiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + lin = *td; + } else if (cieq(var, "log")) { + loggiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + log = *td; + } else if (cieq(var, "dec")) { + decgiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + dec = *td; + } else if (cieq(var, "gauss")) { + gaussgiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + gauss = *td; + } else if (cieq(var, "random")) { + randmgiven = TRUE; + if (!(td = ft_numparse(&val, FALSE))) { + fprintf(cp_err, + "Error: bad parm %s = %s\n", + var, val); + return; + } + randm = *td; + } else if (cieq(var, "pool")) { + poolgiven = TRUE; + pool = val; + } + } + +#ifdef LINT +/* XXX Now, doesn't this look just a little suspicious */ + if (centergiven || spangiven || meangiven || sdgiven || + poolgiven) + j = k = l = m = q = inds = center + span + mean + sd + + log + dec + gauss + randm + pool; +#endif + /* Now see what we have... start and stop are pretty much + * compatible with everything... + */ + if (stepgiven && (step == 0.0)) { + fprintf(cp_err, "Error: step cannot = 0.0\n"); + return; + } + if (startgiven && stopgiven && (start > stop)) { + tt = start; + start = stop; + stop = tt; + reverse = TRUE; + } + if (lingiven + loggiven + decgiven + randmgiven + gaussgiven + > 1) { + fprintf(cp_err, + "Error: can have at most one of (lin, log, dec, random, gauss)\n"); + return; + } else if (lingiven + loggiven + decgiven + randmgiven + + gaussgiven == 0) { + /* Hmm, if we have a start, stop, and step we're ok. */ + if (startgiven && stopgiven && stepgiven) { + lingiven = TRUE; + lin = (stop - start) / step + 1; + stepgiven = FALSE; /* Problems below... */ + } else { + fprintf(cp_err, +"Error: either one of (lin, log, dec, random, gauss) must be given, or all\n"); + fprintf(cp_err, + "\tof (start, stop, and step) must be given.\n"); + return; + } + } + if (lingiven) { + /* Create a linear sweep... */ + data = (double *) tmalloc(sizeof (double) * (int) lin); + if (stepgiven && startgiven && stopgiven) { + if (step != (stop - start) / lin * (reverse ? + -1 : 1)) { + fprintf(cp_err, + "Warning: bad step -- should be %g\n", + (stop - start) / lin * + (reverse ? -1 : 1)); + stepgiven = FALSE; + } + } + if (!startgiven) { + if (stopgiven && stepgiven) { + start = stop - step * lin; + } else if (stopgiven) { + start = stop - lin; + } else { + start = 0; + } + startgiven = TRUE; + } + if (!stopgiven) { + if (stepgiven) + stop = start + lin * step; + else + stop = start + lin; + stopgiven = TRUE; + } + if (!stepgiven) { + step = (stop - start) / lin; + } + if (reverse) + for (i = 0, tt = stop; i < lin; + i++, tt -= step) + data[i] = tt; + else + for (i = 0, tt = start; i < lin; + i++, tt += step) + data[i] = tt; + length = lin; + } else if (loggiven || decgiven) { + /* Create a log sweep... */ + } else if (randmgiven) { + /* Create a set of random values... */ + } else if (gaussgiven) { + /* Create a gaussian distribution... */ + } + } + result = alloc(struct dvec); + ZERO(result, struct dvec); + result->v_name = copy(resname); + result->v_type = type; + result->v_flags = (realflag ? VF_REAL : VF_COMPLEX) | VF_PERMANENT; + if (realflag) + result->v_realdata = data; + else + result->v_compdata = cdata; + result->v_length = length; + result->v_numdims = 1; + result->v_dims[0] = length; + vec_new(result); + cp_addkword(CT_VECTOR, result->v_name); + return; +} + +/* Copy the data from a vector into a buffer with larger dimensions. */ + +static void +dimxpand(struct dvec *v, int *newdims, double *data) +{ + complex *cdata = (complex *) data; + bool realflag = isreal(v); + int i, j, o, n, t, u; + int ncount[MAXDIMS], ocount[MAXDIMS]; + + for (i = 0; i < MAXDIMS; i++) + ncount[i] = ocount[i] = 0; + + for (;;) { + for (o = n = i = 0; i < v->v_numdims; i++) { + for (j = i, t = u = 1; j < v->v_numdims; j++) { + t *= v->v_dims[j]; + u *= newdims[j]; + } + o += ocount[i] * t; + n += ncount[i] * u; + } + + if (realflag) { + data[n] = v->v_realdata[o]; + } else { + realpart(&cdata[n]) = realpart(&v->v_compdata[o]); + imagpart(&cdata[n]) = imagpart(&v->v_compdata[o]); + } + /* Now find the nextstrchr element... */ + for (i = v->v_numdims - 1; i >= 0; i--) { + if ((ocount[i] < v->v_dims[i] - 1) && + (ncount[i] < newdims[i] - 1)) { + ocount[i]++; + ncount[i]++; + break; + } else + ocount[i] = ncount[i] = 0; + } + if (i < 0) + break; + } + + return; +} + diff --git a/src/frontend/compose.h b/src/frontend/compose.h new file mode 100644 index 000000000..7e03a72e9 --- /dev/null +++ b/src/frontend/compose.h @@ -0,0 +1,12 @@ +/************* + * Header file for compose.c + * 1999 E. Rouat + ************/ + +#ifndef COMPOSE_H_INCLUDED +#define COMPOSE_H_INCLUDED + +void com_compose(wordlist *wl); + + +#endif diff --git a/src/frontend/cpitf.c b/src/frontend/cpitf.c new file mode 100644 index 000000000..f57463341 --- /dev/null +++ b/src/frontend/cpitf.c @@ -0,0 +1,331 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "cpitf.h" + + +/* Set some standard variables and aliases, etc, and init the ccom stuff. */ + +void +ft_cpinit(void) +{ + wordlist *wl; + wordlist wl1, wl2, wl3; + bool found = FALSE, t = TRUE; + char buf[BSIZE_SP], **x, *s, *r; + struct comm *c; + int i; + FILE *fp; + static char *predefs[] = { + "yes", "1", + "TRUE", "1", + "no", "0", + "FALSE", "0", + "pi", "3.14159265358979323846", + "e", "2.71828182844590452353", + "c", "2.997925e8", + "i", "0,1", + "kelvin", "-273.15", + "echarge", "1.60219e-19", + "boltz", "1.38062e-23", + "planck", "6.62620e-34" + } ; + static char *udfs[] = { + "max(x,y)", "(x gt y) * x + (x le y) * y", + "min(x,y)", "(x lt y) * x + (x ge y) * y", + "vdb(x)", "db(v(x))", + "vdb(x,y)", "db(v(x) - v(y))", + "vi(x)", "im(v(x))", + "vi(x,y)", "im(v(x) - v(y))", + "vm(x)", "mag(v(x))", + "vm(x,y)", "mag(v(x) - v(y))", + "vp(x)", "ph(v(x))", + "vp(x,y)", "ph(v(x) - v(y))", + "vr(x)", "re(v(x))", + "vr(x,y)", "re(v(x) - v(y))" + } ; + + cp_ccon(TRUE); /* So the user can type ahead... */ + cp_init(); + + if (!cp_nocc) { + /* Add commands... */ + for (c = cp_coms; c->co_func; c++) { + if (c->co_spiceonly && ft_nutmeg) + continue; + cp_addcomm(c->co_comname, c->co_cctypes[0], + c->co_cctypes[1], c->co_cctypes[2], + c->co_cctypes[3]); + cp_addkword(CT_COMMANDS, c->co_comname); + } + /* And keywords... These are the ones that are constant... */ + if (!ft_nutmeg) { + cp_addkword(CT_LISTINGARGS, "deck"); + cp_addkword(CT_LISTINGARGS, "logical"); + cp_addkword(CT_LISTINGARGS, "physical"); + cp_addkword(CT_LISTINGARGS, "expand"); + + cp_addkword(CT_STOPARGS, "when"); + cp_addkword(CT_STOPARGS, "after"); + } + + cp_addkword(CT_PLOT, "new"); + + cp_addkword(CT_PLOTKEYWORDS, "xlimit"); + cp_addkword(CT_PLOTKEYWORDS, "ylimit"); + cp_addkword(CT_PLOTKEYWORDS, "vs"); + cp_addkword(CT_PLOTKEYWORDS, "xindices"); + cp_addkword(CT_PLOTKEYWORDS, "xcompress"); + cp_addkword(CT_PLOTKEYWORDS, "xdelta"); + cp_addkword(CT_PLOTKEYWORDS, "ydelta"); + cp_addkword(CT_PLOTKEYWORDS, "lingrid"); + cp_addkword(CT_PLOTKEYWORDS, "loglog"); + cp_addkword(CT_PLOTKEYWORDS, "linear"); + cp_addkword(CT_PLOTKEYWORDS, "xlog"); + cp_addkword(CT_PLOTKEYWORDS, "ylog"); + cp_addkword(CT_PLOTKEYWORDS, "polar"); + cp_addkword(CT_PLOTKEYWORDS, "smith"); + cp_addkword(CT_PLOTKEYWORDS, "smithgrid"); + cp_addkword(CT_PLOTKEYWORDS, "nointerp"); + cp_addkword(CT_PLOTKEYWORDS, "title"); + cp_addkword(CT_PLOTKEYWORDS, "xlabel"); + cp_addkword(CT_PLOTKEYWORDS, "ylabel"); + cp_addkword(CT_PLOTKEYWORDS, "linplot"); + cp_addkword(CT_PLOTKEYWORDS, "combplot"); + cp_addkword(CT_PLOTKEYWORDS, "pointplot"); + + cp_addkword(CT_RUSEARGS, "time"); + cp_addkword(CT_RUSEARGS, "space"); + cp_addkword(CT_RUSEARGS, "faults"); + cp_addkword(CT_RUSEARGS, "elapsed"); + cp_addkword(CT_RUSEARGS, "totiter"); + cp_addkword(CT_RUSEARGS, "traniter"); + cp_addkword(CT_RUSEARGS, "tranpoints"); + cp_addkword(CT_RUSEARGS, "accept"); + cp_addkword(CT_RUSEARGS, "rejected"); + cp_addkword(CT_RUSEARGS, "time"); + cp_addkword(CT_RUSEARGS, "trantime"); + cp_addkword(CT_RUSEARGS, "lutime"); + cp_addkword(CT_RUSEARGS, "solvetime"); + cp_addkword(CT_RUSEARGS, "transolvetime"); + cp_addkword(CT_RUSEARGS, "loadtime"); + cp_addkword(CT_RUSEARGS, "all"); + + cp_addkword(CT_VECTOR, "all"); + + for (x = ft_setkwords; *x; x++) + cp_addkword(CT_VARIABLES, *x); + for (i = 0; ; i++) { + if (!(s = ft_typenames(i))) + break; + cp_addkword(CT_TYPENAMES, s); + } + } + + cp_vset("program", VT_STRING, cp_program); + + /* Make the prompt use only the last component of the path... */ + + if (DIR_TERM) { + for (s = cp_program; s && *s; s++) + ; + s--; + while ((s > cp_program) && (*s != DIR_TERM)) + s--; + if (*s == DIR_TERM) + s++; + (void) strcpy(buf, s); + for (s = buf; *s && (*s != '.'); s++) + ; + *s = '\0'; + (void) strcat(buf, " ! -> "); + } else + (void) sprintf(buf, "%s ! -> ", cp_program); + + cp_vset("prompt", VT_STRING, buf); + cp_vset("noglob", VT_BOOL, (char *) &t); + + /* Now do a bunch of things that used to be in the spiceinit file + * but were too slow to read in... + */ + wl1.wl_next = &wl2; + wl1.wl_prev = NULL; + wl2.wl_next = NULL; + wl2.wl_prev = &wl1; + wl1.wl_word = "if"; + wl2.wl_word = "1"; + cp_setalias("begin", &wl1); + wl1.wl_next = NULL; + wl1.wl_word = "end"; + cp_setalias("endif", &wl1); + cp_setalias("endwhile", &wl1); + cp_setalias("endforeach", &wl1); + cp_setalias("endrepeat", &wl1); + cp_setalias("enddowhile", &wl1); + wl1.wl_word = "help"; + cp_setalias("?", &wl1); + + wl1.wl_next = &wl2; + wl2.wl_next = &wl3; + wl2.wl_prev = &wl1; + wl3.wl_prev = &wl2; + wl3.wl_next = NULL; + wl2.wl_word = "="; + for (i = 0; i < sizeof (predefs) / sizeof (char *); i += 2) { + wl1.wl_word = predefs[i]; + wl3.wl_word = predefs[i + 1]; + com_let(&wl1); + } + + wl2.wl_next = NULL; + for (i = 0; i < sizeof (udfs) / sizeof (char *); i += 2) { + wl1.wl_word = udfs[i]; + wl2.wl_word = udfs[i + 1]; + com_define(&wl1); + } + + /* Reset this for the front end. */ + cp_hash = '*'; + + if (Lib_Path && *Lib_Path) { + (void) sprintf(buf, "sourcepath = ( %s %s )", DIR_CWD, Lib_Path); + wl = cp_doglob(cp_lexer(buf)); + cp_striplist(wl); + com_set(wl); + + /* Now source the standard startup file. */ + /* XXX strange */ + for (s = cp_tildexpand(Lib_Path); s && *s; ) { + while (isspace(*s)) + s++; + for (r = buf; *s && !isspace(*s); r++, s++) + *r = *s; + (void) strcpy(r, DIR_PATHSEP); + (void) strcat(r, "spinit"); + if ((fp = fopen(buf, "r"))) { + cp_interactive = FALSE; + inp_spsource(fp, TRUE, buf); + cp_interactive = TRUE; + + /* the following caused me SIGSEGV's since inp_spsource + already closes fp - A. Veliath 12/7/97 + + MW. Its really needed - I changed inp_spsource to + close fp always. */ + + /* (void) fclose(fp); */ + + found = TRUE; + break; + } else if (ft_controldb) + fprintf(cp_err, "Note: can't open \"%s\".\n", buf); + } + if (!found) + fprintf(cp_err, "Note: can't find init file.\n"); + } + + tcap_init( ); + + return; +} + +/* Decide whether a condition is TRUE or not. */ + +bool +cp_isTRUE(wordlist *wl) +{ + int i; + struct dvec *v; + struct pnode *pn; + +/* fprintf(stderr, "isTRUE: "); wl_print(wl, stderr); fprintf(stderr, "\n"); */ + /* First do all the csh-type stuff here... */ + wl = wl_copy(wl); + wl = cp_variablesubst(wl); + wl = cp_bquote(wl); + cp_striplist(wl); + + pn = ft_getpnames(wl, TRUE); + v = ft_evaluate(pn); + free_pnode(pn); + + /* It makes no sense to say while (all), but what the heck... */ + while (v) { + if (isreal(v)) { + for (i = 0; i < v->v_length; i++) + if (v->v_realdata[i] != 0.0) + return (TRUE); + } else { + for (i = 0; i < v->v_length; i++) + if ((realpart(&v->v_compdata[i]) != 0.0) || + (imagpart(&v->v_compdata[i]) != 0.0)) + return (TRUE); + } + v = v->v_link2; + } + return (FALSE); +} + +/* This gets called before every command is executed... */ + +void +cp_periodic(void) +{ + ft_setflag = ft_intrpt = FALSE; + ft_ckspace(); + ft_checkkids(); + vec_gc(); + return; +} + +void +cp_doquit(void) +{ + com_quit((wordlist *) NULL); + return; +} + +/* This is how we deal with emulation of commands by scripts... If the script + * is found, then set the variables argc and argv and call the script. Note + * that this also allows us to type a filename to load a spice deck... + */ + +bool +cp_oddcomm(char *s, wordlist *wl) +{ + FILE *fp; + char buf[BSIZE_SP]; + wordlist ww; + + if ((fp = inp_pathopen(s, "r"))) { + (void) fclose(fp); + (void) sprintf(buf, "argc = %d argv = ( ", wl_length(wl)); + while (wl) { + (void) strcat(buf, wl->wl_word); + (void) strcat(buf, " "); + wl = wl->wl_next; + } + (void) strcat(buf, ")"); + com_set(cp_lexer(buf)); + inp_source(s); + cp_remvar("argc"); + cp_remvar("argv"); + return (TRUE); + } else if (wl && eq(wl->wl_word, "=")) { + ww.wl_next = wl; + wl->wl_prev = &ww; + ww.wl_prev = NULL; + ww.wl_word = s; + com_let(&ww); + return (TRUE); + } else + return (FALSE); +} + diff --git a/src/frontend/cpitf.h b/src/frontend/cpitf.h new file mode 100644 index 000000000..32857b028 --- /dev/null +++ b/src/frontend/cpitf.h @@ -0,0 +1,16 @@ +/************* + * Header file for cpitf.c + * 1999 E. Rouat + ************/ + +#ifndef CPITF_H_INCLUDED +#define CPITF_H_INCLUDED + +void ft_cpinit(void); +bool cp_istrue(wordlist *wl); +void cp_periodic(void); +void cp_doquit(void); +bool cp_oddcomm(char *s, wordlist *wl); + + +#endif diff --git a/src/frontend/debugcom.c b/src/frontend/debugcom.c new file mode 100644 index 000000000..bc2c6584f --- /dev/null +++ b/src/frontend/debugcom.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Circuit debugging commands. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedebug.h" +#include "ftedata.h" +#include "fteinp.h" +#include "debugcom.h" + + +void +com_state(wordlist *wl) +{ + if (!ft_curckt) { + fprintf(cp_err, "Error: no circuit loaded.\n"); + return; + } + fprintf(cp_out, "Current circuit: %s\n", ft_curckt->ci_name); + if (!ft_curckt->ci_inprogress) { + fprintf(cp_out, "No run in progress.\n"); + return; + } + fprintf(cp_out, "Type of run: %s\n", plot_cur->pl_name); + fprintf(cp_out, "Number of points so far: %d\n", + plot_cur->pl_scale->v_length); + fprintf(cp_out, "(That's all this command does so far)\n"); + return; +} + + +void +com_dump(wordlist *wl) +{ + if (!ft_curckt || !ft_curckt->ci_ckt) { + fprintf(cp_err, "Error: no circuit loaded.\n"); + return; + } + if_dump(ft_curckt->ci_ckt, cp_out); + return; +} + diff --git a/src/frontend/debugcom.h b/src/frontend/debugcom.h new file mode 100644 index 000000000..54399ee4e --- /dev/null +++ b/src/frontend/debugcom.h @@ -0,0 +1,14 @@ +/************* + * Header file for debugcom.c + * 1999 E. Rouat + ************/ + +#ifndef DEBUGCOM_H_INCLUDED +#define DEBUGCOM_H_INCLUDED + +void com_state(wordlist *wl); +void com_dump(wordlist *wl); + + + +#endif diff --git a/src/frontend/define.c b/src/frontend/define.c new file mode 100644 index 000000000..acb430aba --- /dev/null +++ b/src/frontend/define.c @@ -0,0 +1,448 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * User-defined functions. The user defines the function with + * define func(arg1, arg2, arg3) + * Then when he types "func(1, 2, 3)", the commas are interpreted as + * binary operations of the lowest priority by the parser, and ft_substdef() + * below is given a chance to fill things in and return what the parse tree + * would have been had the entire thing been typed. + * Note that we have to take some care to distinguish between functions + * with the same name and different arities. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "define.h" + + +/* static declarations */ +static void savetree(struct pnode *pn); +static void prdefs(char *name); +static void prtree(struct udfunc *ud); +static void prtree1(struct pnode *pn, FILE *fp); +static struct pnode * trcopy(struct pnode *tree, char *args, struct pnode *nn); +static struct pnode * ntharg(int num, struct pnode *args); + + +static struct udfunc *udfuncs = NULL; + +/* Set up a function definition. */ + +void +com_define(wordlist *wlist) +{ + int arity = 0, i; + char buf[BSIZE_SP], tbuf[BSIZE_SP], *s, *t, *b; + wordlist *wl; + struct pnode *pn; + struct udfunc *udf; + + /* If there's nothing then print all the definitions. */ + if (wlist == NULL) { + prdefs((char *) NULL); + return; + } + + /* Accumulate the function head in the buffer, w/out spaces. A + * useful thing here would be to check to make sure that there + * are no formal parameters here called "list". But you have + * to try really hard to break this here. + */ + buf[0] = '\0'; + for (wl = wlist; wl && (index(wl->wl_word, /* ( */ ')') == NULL); + wl = wl->wl_next) + (void) strcat(buf, wl->wl_word); + if (wl) { + for (t = buf; *t; t++); + for (s = wl->wl_word; *s && (*s != /* ( */ ')'); s++, t++) + *t = *s; + *t++ = /* ( */ ')'; + *t = '\0'; + if (*++s) + wl->wl_word = copy(s); + else + wl = wl->wl_next; + } + + /* If that's all, then print the definition. */ + if (wl == NULL) { + prdefs(buf); + return; + } + + /* Now check to see if this is a valid name for a function (i.e, + * there isn't a predefined function of the same name). + */ + (void) strcpy(tbuf, buf); + for (b = tbuf; *b; b++) + if (isspace(*b) || (*b == '(' /* ) */)) { + *b = '\0'; + break; + } + for (i = 0; ft_funcs[i].fu_name; i++) + if (eq(ft_funcs[i].fu_name, tbuf)) { + fprintf(cp_err, "Error: %s is a predefined function.\n", + tbuf); + return; + } + + /* Parse the rest of it. We can't know if there are the right + * number of undefined variables in the expression. + */ + if (!(pn = ft_getpnames(wl, FALSE))) + return; + + /* This is a pain -- when things are garbage-collected, any + * vectors that may have been mentioned here will be thrown + * away. So go down the tree and save any vectors that aren't + * formal parameters. + */ + savetree(pn); + + /* Format the name properly and add to the list. */ + b = copy(buf); + for (s = b; *s; s++) { + if (*s == '(') { /*)*/ + *s = '\0'; + if (s[1] != /*(*/ ')') + arity++; /* It will have been 0. */ + } else if (*s == /*(*/ ')') { + *s = '\0'; + } else if (*s == ',') { + *s = '\0'; + arity++; + } + } + for (udf = udfuncs; udf; udf = udf->ud_next) + if (prefix(b, udf->ud_name) && (arity == udf->ud_arity)) + break; + if (udf == NULL) { + udf = alloc(struct udfunc); + if (udfuncs == NULL) { + udfuncs = udf; + udf->ud_next = NULL; + } else { + udf->ud_next = udfuncs; + udfuncs = udf; + } + } + udf->ud_text = pn; + udf->ud_name = b; + udf->ud_arity = arity; + cp_addkword(CT_UDFUNCS, b); + return; +} + +/* Kludge. */ + +static void +savetree(struct pnode *pn) +{ + struct dvec *d; + + if (pn->pn_value) { + /* We specifically don't add this to the plot list + * so it won't get gc'ed. + */ + d = pn->pn_value; + if ((d->v_length != 0) || eq(d->v_name, "list")) { + pn->pn_value = alloc(struct dvec); + ZERO(pn->pn_value, struct dvec); + pn->pn_value->v_name = copy(d->v_name); + pn->pn_value->v_length = d->v_length; + pn->pn_value->v_type = d->v_type; + pn->pn_value->v_flags = d->v_flags; + pn->pn_value->v_plot = d->v_plot; + if (isreal(d)) { + pn->pn_value->v_realdata = (double *) + tmalloc(sizeof (double) * d->v_length); + bcopy((char *) d->v_realdata, + (char *) pn->pn_value->v_realdata, + sizeof (double) * d->v_length); + } else { + pn->pn_value->v_compdata = (complex *) + tmalloc(sizeof (complex) * d->v_length); + bcopy((char *) d->v_compdata, + (char *) pn->pn_value->v_compdata, + sizeof (complex) * d->v_length); + } + } + } else if (pn->pn_op) { + savetree(pn->pn_left); + if (pn->pn_op->op_arity == 2) + savetree(pn->pn_right); + } else if (pn->pn_func) { + savetree(pn->pn_left); + } + return; +} + +/* A bunch of junk to print out nodes. */ + +static void +prdefs(char *name) +{ + struct udfunc *udf; + char *s; + + if (name) { + s =strchr(name, '(' /* ) */); + if (s) + *s = '\0'; + } + if (name && *name) { /* You never know what people will do */ + for (udf = udfuncs; udf; udf = udf->ud_next) + if (eq(name, udf->ud_name)) + prtree(udf); + } else + for (udf = udfuncs; udf; udf = udf->ud_next) + prtree(udf); + return; +} + +/* Print out one definition. */ + +static void +prtree(struct udfunc *ud) +{ + char *s, buf[BSIZE_SP]; + + /* Print the head. */ + buf[0] = '\0'; + (void) strcat(buf, ud->ud_name); + for (s = ud->ud_name; *s; s++); + (void) strcat(buf, " ("); + s++; + while (*s) { + (void) strcat(buf, s); + while (*s) + s++; + if (s[1]) + (void) strcat(buf, ", "); + s++; + } + (void) strcat(buf, ") = "); + fputs(buf, cp_out); + prtree1(ud->ud_text, cp_out); + (void) putc('\n', cp_out); + return; +} + +static void +prtree1(struct pnode *pn, FILE *fp) +{ + if (pn->pn_value) { + fputs(pn->pn_value->v_name, fp); + } else if (pn->pn_func) { + fprintf(fp, "%s (", pn->pn_func->fu_name); + prtree1(pn->pn_left, fp); + fputs(")", fp); + } else if (pn->pn_op && (pn->pn_op->op_arity == 2)) { + fputs("(", fp); + prtree1(pn->pn_left, fp); + fprintf(fp, ")%s(", pn->pn_op->op_name); + prtree1(pn->pn_right, fp); + fputs(")", fp); + } else if (pn->pn_op && (pn->pn_op->op_arity == 1)) { + fprintf(fp, "%s(", pn->pn_op->op_name); + prtree1(pn->pn_left, fp); + fputs(")", fp); + } else + fputs("", fp); + return; +} + +struct pnode * +ft_substdef(char *name, struct pnode *args) +{ + struct udfunc *udf; + struct pnode *tp; + char *s; + int arity = 0, rarity; + bool found = FALSE; + + if (args) + arity = 1; + for (tp = args; tp && tp->pn_op && (tp->pn_op->op_num == COMMA); tp = + tp->pn_right) + arity++; + for (udf = udfuncs; udf; udf = udf->ud_next) + if (eq(name, udf->ud_name)) { + if (arity == udf->ud_arity) + break; + else { + found = TRUE; + rarity = udf->ud_arity; + } + } + if (udf == NULL) { + if (found) + fprintf(cp_err, + "Warning: the user-defined function %s has %d args\n", + name, rarity); + return (NULL); + } + for (s = udf->ud_name; *s; s++) + ; + s++; + + /* Now we have to traverse the tree and copy it over, + * substituting args. + */ + return (trcopy(udf->ud_text, s, args)); +} + +/* Copy the tree and replace formal args with the right stuff. The way + * we know that something might be a formal arg is when it is a dvec + * with length 0 and a name that isn't "list". I hope nobody calls their + * formal parameters "list". + */ + +static struct pnode * +trcopy(struct pnode *tree, char *args, struct pnode *nn) +{ + struct pnode *pn; + struct dvec *d; + char *s; + int i; + + if (tree->pn_value) { + d = tree->pn_value; + if ((d->v_length == 0) && strcmp(d->v_name, "list")) { + /* Yep, it's a formal parameter. Substitute for it. + * IMPORTANT: we never free parse trees, so we + * needn't worry that they aren't trees here. + */ + s = args; + i = 1; + while (*s) { + if (eq(s, d->v_name)) + break; + else + i++; + while (*s++); /* Get past the last '\0'. */ + } + if (*s) + return (ntharg(i, nn)); + else + return (tree); + } else + return (tree); + } else if (tree->pn_func) { + struct func *func; + + func = alloc(struct func); + func->fu_name = copy(tree->pn_func->fu_name); + func->fu_func = tree->pn_func->fu_func; + + pn = alloc(struct pnode); + pn->pn_value = NULL; + pn->pn_func = func; + pn->pn_op = NULL; + pn->pn_left = trcopy(tree->pn_left, args, nn); + pn->pn_right = NULL; + pn->pn_next = NULL; + + } else if (tree->pn_op) { + struct op *op; + + op = alloc(struct op); + op->op_num = tree->pn_op->op_num; + op->op_arity = tree->pn_op->op_arity; + op->op_func = tree->pn_op->op_func; + op->op_name = copy(tree->pn_op->op_name); + + pn = alloc(struct pnode); + pn->pn_value = NULL; + pn->pn_func = NULL; + pn->pn_op = op; + pn->pn_left = trcopy(tree->pn_left, args, nn); + if (op->op_arity == 2) + pn->pn_right = trcopy(tree->pn_right, args, nn); + else + pn->pn_right = NULL; + pn->pn_next = NULL; + } else { + fprintf(cp_err, "trcopy: Internal Error: bad parse node\n"); + return (NULL); + } + return (pn); +} + +/* Find the n'th arg in the arglist, returning NULL if there isn't one. + * Since comma has such a low priority and associates to the right, + * we can just follow the right branch of the tree num times. + * Note that we start at 1 when numbering the args. + */ + +static struct pnode * +ntharg(int num, struct pnode *args) +{ + struct pnode *ptry; + + ptry = args; + if (num > 1) { + while (--num > 0) { + if (ptry && ptry->pn_op && + (ptry->pn_op->op_num != COMMA)) { + if (num == 1) + break; + else + return (NULL); + } + ptry = ptry->pn_right; + } + } + if (ptry && ptry->pn_op && (ptry->pn_op->op_num == COMMA)) + ptry = ptry->pn_left; + return (ptry); +} + +void +com_undefine(wordlist *wlist) +{ + struct udfunc *udf, *ludf = NULL; + + if (!wlist) + return; + if (*wlist->wl_word == '*') { + udfuncs = NULL; /* Be sloppy. */ + return; + } + while (wlist) { + for (udf = udfuncs; udf; udf = udf->ud_next) { + if (eq(wlist->wl_word, udf->ud_name)) { + if (ludf) + ludf->ud_next = udf->ud_next; + else + udfuncs = udf->ud_next; + cp_remkword(CT_UDFUNCS, wlist->wl_word); + } else + ludf = udf; + } + wlist = wlist->wl_next; + } + return; +} + +#ifndef LINT + +/* Watch out, this is not at all portable. It's only here so I can + * call it from dbx with an int value (all you can give with "call")... + */ + +void +ft_pnode(struct pn *pn) +{ + prtree1(pn, cp_err); +} + +#endif + diff --git a/src/frontend/define.h b/src/frontend/define.h new file mode 100644 index 000000000..bb8b826b8 --- /dev/null +++ b/src/frontend/define.h @@ -0,0 +1,15 @@ +/************* + * Header file for define.c + * 1999 E. Rouat + ************/ + +#ifndef DEFINE_H_INCLUDED +#define DEFINE_H_INCLUDED + +void com_define(wordlist *wlist); +struct pnode * ft_substdef(char *name, struct pnode *args); +void com_undefine(wordlist *wlist); + + + +#endif diff --git a/src/frontend/device.c b/src/frontend/device.c new file mode 100644 index 000000000..373ae20f2 --- /dev/null +++ b/src/frontend/device.c @@ -0,0 +1,756 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines to query and alter devices. + */ + +#include "ngspice.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "dgen.h" +#include "device.h" + + + +static wordlist *devexpand(char *name); +static void all_show(wordlist *wl, int mode); + + +/* + * show: list device operating point info + * show + * show devs : params + * show devs : params ; devs : params + * show dev dev dev : param param param , dev dev : param param + * show t : param param param, t : param param + * + */ + + +static int count; + + +extern void dgen_nth_next (dgen **dg, int n); +extern int dgen_for_n (dgen *dg, int n, int (*fn) (/* ??? */), char *data, int subindex); +extern void wl_forall (wordlist *wl, int (*fn) (/* ??? */), char *data); + +void +com_showmod(wordlist *wl) +{ + all_show(wl, 1); +} + +void +com_show(wordlist *wl) +{ + all_show(wl, 0); +} + +static void +all_show(wordlist *wl, int mode) +{ + wordlist *params, *nextgroup, *thisgroup; + wordlist *prev, *next, *w; + int screen_width; + dgen *dg, *listdg; + int instances; + int i, j, n; + int param_flag, dev_flag; + + if (!ft_curckt) { + fprintf(cp_err, "Error: no circuit loaded\n"); + return; + } + + if (wl && wl->wl_word && eq(wl->wl_word, "-v")) { + old_show(wl->wl_next); + return; + } + + if (!cp_getvar("width", VT_NUM, (char *) &screen_width)) + screen_width = DEF_WIDTH; + count = screen_width / 11 - 1; + + n = 0; + do { + prev = NULL; + params = NULL; + nextgroup = NULL; + thisgroup = wl; + param_flag = 0; + dev_flag = 0; + + /* find the parameter list and the nextgroup */ + for (w = wl; w && !nextgroup; w = next) { + next = w->wl_next; + if (eq(w->wl_word, "++") || eq(w->wl_word, "all")) { + if (params) { + param_flag = DGEN_ALLPARAMS; + if (prev) + prev->wl_next = w->wl_next; + else + params = next; + } else { + dev_flag = DGEN_ALLDEVS; + if (prev) + prev->wl_next = w->wl_next; + else + thisgroup = next; + } + /* + tfree(w->wl_word); + tfree(w); + */ + w = NULL; + } else if (eq(w->wl_word, "+")) { + if (params) { + param_flag = DGEN_DEFPARAMS; + if (prev) + prev->wl_next = w->wl_next; + else + params = next; + } else { + dev_flag = DGEN_DEFDEVS; + if (prev) + prev->wl_next = w->wl_next; + else + thisgroup = next; + } + tfree(w->wl_word); + tfree(w); + w = NULL; + } else if (eq(w->wl_word, ":")) { + tfree(w->wl_word); + tfree(w); + w = NULL; + if (!params) { + params = next; + if (prev) + prev->wl_next = NULL; + else + thisgroup = NULL; + } else { + if (prev) + prev->wl_next = next; + else + params = next; + } + } else if (eq(w->wl_word, ";") || eq(w->wl_word, ",")) { + nextgroup = next; + tfree(w->wl_word); + tfree(w); + w = NULL; + if (prev) + prev->wl_next = NULL; + break; + } + prev = w; + } + + instances = 0; + for (dg = dgen_init(ft_curckt->ci_ckt, thisgroup, 1, dev_flag, mode); + dg; dgen_nth_next(&dg, count)) + { + instances = 1; + if (dg->flags & DGEN_INSTANCE) { + instances = 2; + printf(" %s: %s\n", + ft_sim->devices[dg->dev_type_no]->name, + ft_sim->devices[dg->dev_type_no]->description); + n += 1; + + i = 0; + do { + printf(" device "); + j = dgen_for_n(dg, count, printstr, "n", i); + i += 1; + printf("\n"); + } while (j); + + if (ft_sim->devices[dg->dev_type_no]->numModelParms) { + i = 0; + do { + printf(" model "); + j = dgen_for_n(dg, count, printstr, "m", i); + i += 1; + printf("\n"); + } while (j); + } + listdg = dg; + + if (param_flag) + param_forall(dg, param_flag); + else if (!params) + param_forall(dg, DGEN_DEFPARAMS); + if (params) + wl_forall(params, listparam, dg); + printf("\n"); + + } else if (ft_sim->devices[dg->dev_type_no]->numModelParms) { + printf(" %s models (%s)\n", + ft_sim->devices[dg->dev_type_no]->name, + ft_sim->devices[dg->dev_type_no]->description); + n += 1; + i = 0; + do { + printf(" model "); + j = dgen_for_n(dg, count, printstr, "m", i); + i += 1; + printf("\n"); + } while (j); + printf("\n"); + + if (param_flag) + param_forall(dg, param_flag); + else if (!params) + param_forall(dg, DGEN_DEFPARAMS); + if (params) + wl_forall(params, listparam, dg); + printf("\n"); + } + } + + wl = nextgroup; + + } while (wl); + + if (!n) { + if (instances == 0) + printf("No matching instances or models\n"); + else if (instances == 1) + printf("No matching models\n"); + else + printf("No matching elements\n"); + } +} + +int +printstr(dgen *dg, char *name) +{ + if (*name == 'n') { + if (dg->instance) + printf(" %9.9s", dg->instance->GENname); + else + printf(" "); + } else if (*name == 'm') { + if (dg->model) + printf(" %9.9s", dg->model->GENmodName); + else + printf(" "); + } else + printf(" "); + + return 0; +} + +void +param_forall(dgen *dg, int flags) +{ + int i, j, k, found; + int xcount; + IFparm *plist; + + found = 0; + + if (dg->flags & DGEN_INSTANCE) { + xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms; + plist = ft_sim->devices[dg->dev_type_no]->instanceParms; + } else { + xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms; + plist = ft_sim->devices[dg->dev_type_no]->modelParms; + } + + for (i = 0; i < xcount; i++) { + if (plist[i].dataType & IF_ASK) { + if ((((CKTcircuit *) (dg->ckt))->CKTrhsOld + || (plist[i].dataType & IF_SET)) + && (!(plist[i].dataType & (IF_REDUNDANT | IF_UNINTERESTING)) + || (flags == DGEN_ALLPARAMS + && !(plist[i].dataType & IF_REDUNDANT)))) + { + j = 0; + do { + if (!j) + printf("%10.10s", plist[i].keyword); + else + printf(" "); + k = dgen_for_n(dg, count, printvals, + (char *) (plist + i), j); + printf("\n"); + j += 1; + } while (k); + } + } + } +} + +void +listparam(wordlist *p, dgen *dg) +{ + int i, j, k, found; + int xcount; + IFparm *plist; + + found = 0; + + if (dg->flags & DGEN_INSTANCE) { + xcount = *ft_sim->devices[dg->dev_type_no]->numInstanceParms; + plist = ft_sim->devices[dg->dev_type_no]->instanceParms; + } else { + xcount = *ft_sim->devices[dg->dev_type_no]->numModelParms; + plist = ft_sim->devices[dg->dev_type_no]->modelParms; + } + + for (i = 0; i < xcount; i++) { + if (eqc(p->wl_word, plist[i].keyword) && (plist[i].dataType & IF_ASK)) + { + found = 1; + break; + } + } + + if (found) { + if ((((CKTcircuit *) (dg->ckt))->CKTrhsOld + || (plist[i].dataType & IF_SET))) + { + j = 0; + do { + if (!j) + printf("%10.10s", p->wl_word); + else + printf(" "); + k = dgen_for_n(dg, count, printvals, plist + i, j); + printf("\n"); + j += 1; + } while (k > 0); + } else { + j = 0; + do { + if (!j) + printf("%10.10s", p->wl_word); + else + printf(" "); + k = dgen_for_n(dg, count, bogus1, 0, j); + printf("\n"); + j += 1; + } while (k > 0); + } + } else { + j = 0; + do { + if (!j) + printf("%10.10s", p->wl_word); + else + printf(" "); + k = dgen_for_n(dg, count, bogus2, 0, j); + printf("\n"); + j += 1; + } while (k > 0); + } +} + +int bogus1(dgen *dg) +{ + printf(" ---------"); + return 0; +} + +int bogus2(dgen *dg) +{ + printf(" ?????????"); + return 0; +} + +int +printvals(dgen *dg, IFparm *p, int i) +{ + IFvalue val; + int n; + + if (dg->flags & DGEN_INSTANCE) + (*ft_sim->askInstanceQuest)(ft_curckt->ci_ckt, dg->instance, + p->id, &val, &val); + else + (*ft_sim->askModelQuest)(ft_curckt->ci_ckt, dg->model, + p->id, &val, &val); + + if (p->dataType & IF_VECTOR) + n = val.v.numValue; + else + n = 1; + + if (((p->dataType & IF_VARTYPES) & ~IF_VECTOR) == IF_COMPLEX) + n *= 2; + + if (i >= n) { + if (i == 0) + printf(" -"); + else + printf(" "); + return 0; + } + + if (p->dataType & IF_VECTOR) { + switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) { + case IF_FLAG: + printf(" % 9d", val.v.vec.iVec[i]); + break; + case IF_INTEGER: + printf(" % 9d", val.v.vec.iVec[i]); + break; + case IF_REAL: + printf(" % 9.3g", val.v.vec.rVec[i]); + break; + case IF_COMPLEX: + if (!(i % 2)) + printf(" % 9.3g", val.v.vec.cVec[i / 2].real); + else + printf(" % 9.3g", val.v.vec.cVec[i / 2].imag); + break; + case IF_STRING: + printf(" %9.9s", val.v.vec.sVec[i]); + break; + case IF_INSTANCE: + printf(" %9.9s", val.v.vec.uVec[i]); + break; + default: + printf(" ******** "); + } + } else { + switch ((p->dataType & IF_VARTYPES) & ~IF_VECTOR) { + case IF_FLAG: + printf(" % 9d", val.iValue); + break; + case IF_INTEGER: + printf(" % 9d", val.iValue); + break; + case IF_REAL: + printf(" % 9.3g", val.rValue); + break; + case IF_COMPLEX: + if (i % 2) + printf(" % 9.3g", val.cValue.real); + else + printf(" % 9.3g", val.cValue.imag); + break; + case IF_STRING: + printf(" %9.9s", val.sValue); + break; + case IF_INSTANCE: + printf(" %9.9s ", val.uValue); + break; + default: + printf(" ******** "); + } + } + + return n - 1; +} + + +/* (old "show" command) + * Display various device parameters. The syntax of this command is + * show devicelist : parmlist + * where devicelist can be "all", the name of a device, a string like r*, + * which means all devices with names that begin with 'r', repeated one + * or more times. The parms are names of parameters that are (hopefully) + * valid for all the named devices, or "all". + */ + +void +old_show(wordlist *wl) +{ + wordlist *devs, *parms, *tw, *ww; + struct variable *v; + char *nn; + + devs = wl; + while (wl && !eq(wl->wl_word, ":")) + wl = wl->wl_next; + if (!wl) + parms = NULL; + else { + if (wl->wl_prev) + wl->wl_prev->wl_next = NULL; + parms = wl->wl_next; + if (parms) + parms->wl_prev = NULL; + } + + /* Now expand the devicelist... */ + for (tw = NULL; devs; devs = devs->wl_next) { + inp_casefix(devs->wl_word); + tw = wl_append(tw, devexpand(devs->wl_word)); + } + + devs = tw; + for (tw = parms; tw; tw = tw->wl_next) + if (eq(tw->wl_word, "all")) + break; + if (tw) + parms = NULL; + + /* This is a crock... */ + if (!devs) + devs = cp_cctowl(ft_curckt->ci_devices); + + out_init(); + + while (devs) { + out_printf("%s:\n", devs->wl_word); + if (parms) { + for (tw = parms; tw; tw = tw->wl_next) { + nn = copy(devs->wl_word); + v = (*if_getparam)(ft_curckt->ci_ckt, + &nn, tw->wl_word, 0, 0); + if (!v) + v = (*if_getparam)(ft_curckt->ci_ckt, + &nn, tw->wl_word, 0, 1); + if (v) { + out_printf("\t%s =", tw->wl_word); + for (ww = cp_varwl(v); ww; ww = + ww->wl_next) + out_printf(" %s", ww->wl_word); + out_send("\n"); + } + } + } else { + nn = copy(devs->wl_word); + v = (*if_getparam)(ft_curckt->ci_ckt, &nn, "all", 0, 0); + if (!v) + v = (*if_getparam)(ft_curckt->ci_ckt, &nn, "all", 0, 1); + while (v) { + out_printf("\t%s =", v->va_name); + for (ww = cp_varwl(v); ww; ww = ww->wl_next) + out_printf(" %s", ww->wl_word); + out_send("\n"); + v = v->va_next; + } + } + devs = devs->wl_next; + } + return; +} + +/* Alter a device parameter. The new syntax here is + * alter @device[parameter] = expr + * alter device = expr + * alter device parameter = expr + * expr must be real (complex isn't handled right now, integer is fine though, + * but no strings ... for booleans, use 0/1). + */ + +void +com_alter(wordlist *wl) +{ + if (!wl) { + fprintf(cp_err, "usage: alter dev param = expression\n"); + fprintf(cp_err, " or alter @dev[param] = expression\n"); + fprintf(cp_err, " or alter dev = expression\n"); + return; + } + com_alter_common(wl, 0); +} + +void +com_altermod(wordlist *wl) +{ + com_alter_common(wl, 1); +} + +void +com_alter_common(wordlist *wl, int do_model) +{ +#ifdef notdef + struct variable var, *nv, *prev; + double *dd; +#endif + wordlist *eqword, *words; + char *dev, *p; + char *param; + struct dvec *dv; + struct pnode *names; + + if (!ft_curckt) { + fprintf(cp_err, "Error: no circuit loaded\n"); + return; + } + + words = wl; + while (words) { + p = words->wl_word; + eqword = words; + words = words->wl_next; + if (eq(p, "=")) { + break; + } + } + if (!words) { + fprintf(cp_err, "Error: no assignment found.\n"); + return; + } + + /* device parameter = expr + device = expr + @dev[param] = expr + */ + + dev = NULL; + param = NULL; + words = wl; + while (words != eqword) { + p = words->wl_word; + if (param) { + fprintf(cp_err, "Error: excess parameter name \"%s\" ignored.\n", + p); + } else if (dev) { + param = words->wl_word; + } else if (*p == '@' || *p == '#') { + dev = p + 1; + p =strchr(p, '['); + if (p) { + *p++ = 0; + param = p; + p =strchr(p, ']'); + if (p) + *p = 0; + } + } else { + dev = p; + } + words = words->wl_next; + } + if (!dev) { + fprintf(cp_err, "Error: no model or device name provided.\n" ); + return; + } + + words = eqword->wl_next; + names = ft_getpnames(words, FALSE); + if (!names) { + fprintf(cp_err, "Error: cannot parse new parameter value.\n"); + return; + } + dv = ft_evaluate(names); + free_pnode(names); + if (!dv) + return; + if (dv->v_length < 1) { + fprintf(cp_err, "Error: cannot evaluate new parameter value.\n"); + return; + } + + if_setparam(ft_curckt->ci_ckt, &dev, param, dv, do_model); + + /* Vector data (dv) should get garbage-collected. */ + + return; + +#ifdef notdef + while (wl) { + param = wl->wl_word; + wl = wl->wl_next; + + if (!wl) { + val = param; + param = NULL; + } else { + val = wl->wl_word; + wl = wl->wl_next; + } + + /* Now figure out what the value should be... */ + if (eq(val, "TRUE")) { + var.va_type = VT_BOOL; + var.va_bool = TRUE; + } else if (eq(val, "FALSE")) { + var.va_type = VT_BOOL; + var.va_bool = FALSE; + } else if (eq(val, "[")) { + var.va_type = VT_LIST; + prev = NULL; + while (wl && !eq(wl->wl_word, "]")) { + val = wl->wl_word; + nv = alloc(struct variable); + if (dd = ft_numparse(&val, FALSE)) { + nv->va_type = VT_REAL; + nv->va_real = *dd; + } else { + fprintf(cp_err, "Error: \"%s\" is not a number\n", val); + break; + } + if (!prev) + var.va_vlist = nv; + else + prev->va_next = nv; + nv->va_next = NULL; + wl = wl->wl_next; + prev = nv; + } + if (wl && eq(wl->wl_word, "]")) { + wl = wl->wl_next; + } else { + while (nv) { + prev = nv->va_next; + tfree(nv); + nv = prev; + } + return; + } + } else if (dd = ft_numparse(&val, FALSE)) { + var.va_type = VT_REAL; + var.va_real = *dd; + } else { + var.va_type = VT_STRING; + var.va_string = val; + } + + if_setparam(ft_curckt->ci_ckt, &dev, param, &var, do_model); + + if (var.va_type == VT_LIST) { + for (nv = var.va_vlist; nv; nv = prev) { + prev = nv->va_next; + tfree(nv); + } + } + + } +#endif + +} + +/* Given a device name, possibly with wildcards, return the matches. */ + +static wordlist * +devexpand(char *name) +{ + wordlist *wl, *devices, *tw; + + if (index(name, '*') ||strchr(name, '[') ||strchr(name, '?')) { + devices = cp_cctowl(ft_curckt->ci_devices); + for (wl = NULL; devices; devices = devices->wl_next) + if (cp_globmatch(name, devices->wl_word)) { + tw = alloc(struct wordlist); + if (wl) { + wl->wl_prev = tw; + tw->wl_next = wl; + wl = tw; + } else + wl = tw; + wl->wl_word = devices->wl_word; + } + } else if (eq(name, "all")) { + wl = cp_cctowl(ft_curckt->ci_devices); + } else { + wl = alloc(struct wordlist); + wl->wl_word = name; + } + wl_sort(wl); + return (wl); +} + diff --git a/src/frontend/device.h b/src/frontend/device.h new file mode 100644 index 000000000..4899e7d8f --- /dev/null +++ b/src/frontend/device.h @@ -0,0 +1,25 @@ +/************* + * Header file for device.c + * 1999 E. Rouat + ************/ + +#ifndef DEVICE_H_INCLUDED +#define DEVICE_H_INCLUDED + +void com_showmod(wordlist *wl); +void com_show(wordlist *wl); +int printstr(dgen *dg, char *name); +void param_forall(dgen *dg, int flags); +void listparam(wordlist *p, dgen *dg); +int bogus1(dgen *dg); +int bogus2(dgen *dg); +int printvals(dgen *dg, IFparm *p, int i); +void old_show(wordlist *wl); +void com_alter(wordlist *wl); +void com_altermod(wordlist *wl); +void com_alter_common(wordlist *wl, int do_model); + + + + +#endif diff --git a/src/frontend/diff.c b/src/frontend/diff.c new file mode 100644 index 000000000..e4c80cefb --- /dev/null +++ b/src/frontend/diff.c @@ -0,0 +1,241 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Do a 'diff' of two plots. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftecmath.h" +#include "diff.h" + + +/* Determine if two vectors have the 'same' name. */ + +static bool +nameeq(char *n1, char *n2) +{ + char buf1[BSIZE_SP], buf2[BSIZE_SP]; + int i; + + if (eq(n1, n2)) + return (TRUE); + if (isdigit(*n1)) + (void) sprintf(buf1, "v(%s)", n1); + else + (void) strcpy(buf1, n1); + if (isdigit(*n2)) + (void) sprintf(buf2, "v(%s)", n2); + else + (void) strcpy(buf2, n2); + for (i = 0; buf1[i]; i++) + if (isupper(buf1[i])) + buf1[i] = tolower(buf1[i]); + for (i = 0; buf2[i]; i++) + if (isupper(buf2[i])) + buf2[i] = tolower(buf2[i]); + return (eq(buf1, buf2) ? TRUE : FALSE); +} + +void +com_diff(wordlist *wl) +{ + double vntol, abstol, reltol, tol, cmax, cm1, cm2; + struct plot *p1, *p2 = NULL; + struct dvec *v1, *v2; + double d1, d2; + complex c1, c2, c3; + register int i, j; + wordlist *tw; + + if (!cp_getvar("diff_vntol", VT_REAL, (char *) &vntol)) + vntol = 1.0e-6; + if (!cp_getvar("diff_abstol", VT_REAL, (char *) &abstol)) + abstol = 1.0e-12; + if (!cp_getvar("diff_reltol", VT_REAL, (char *) &reltol)) + reltol = 0.001; + + /* Let's try to be clever about defaults. This code is ugly. */ + if (!wl || !wl->wl_next) { + if (plot_list && plot_list->pl_next && + !plot_list->pl_next->pl_next) { + p1 = plot_list; + p2 = plot_list->pl_next; + if (wl && !eq(wl->wl_word, p1->pl_typename) && + !eq(wl->wl_word, p2->pl_typename)) { + fprintf(cp_err, "Error: no such plot \"%s\"\n", + wl->wl_word); + return; + } + fprintf(cp_err, "Plots are \"%s\" and \"%s\"\n", + plot_list->pl_typename, + plot_list->pl_next->pl_typename); + if (wl) + wl = NULL; + } else { + fprintf(cp_err, "Error: plot names not given.\n"); + return; + } + } else { + for (p1 = plot_list; p1; p1 = p1->pl_next) + if (eq(wl->wl_word, p1->pl_typename)) + break; + if (!p1) { + fprintf(cp_err, "Error: no such plot %s\n", + wl->wl_word); + return; + } + wl = wl->wl_next; + } + + if (!p2) { + for (p2 = plot_list; p2; p2 = p2->pl_next) + if (eq(wl->wl_word, p2->pl_typename)) + break; + if (!p2) { + fprintf(cp_err, "Error: no such plot %s\n", + wl->wl_word); + return; + } + wl = wl->wl_next; + } + + /* Now do some tests to make sure these plots are really the + * same type, etc. + */ + if (!eq(p1->pl_name, p2->pl_name)) + fprintf(cp_err, + "Warning: plots %s and %s seem to be of different types\n", + p1->pl_typename, p2->pl_typename); + if (!eq(p1->pl_title, p2->pl_title)) + fprintf(cp_err, + "Warning: plots %s and %s seem to be from different circuits\n", + p1->pl_typename, p2->pl_typename); + + /* This may not be the best way to do this */ + for (v1 = p1->pl_dvecs; v1; v1 = v1->v_next) + v1->v_link2 = NULL; + for (v2 = p2->pl_dvecs; v2; v2 = v2->v_next) + v2->v_link2 = NULL; + + for (v1 = p1->pl_dvecs; v1; v1 = v1->v_next) { + for (v2 = p2->pl_dvecs; v2; v2 = v2->v_next) + if (!v2->v_link2 && nameeq(v1->v_name, v2->v_name) && + ((v1->v_flags & (VF_REAL | VF_COMPLEX)) == + (v2->v_flags & (VF_REAL | VF_COMPLEX))) && + (v1->v_type == v2->v_type)) { + v1->v_link2 = v2; + v2->v_link2 = v1; + break; + } + } + + for (v1 = p1->pl_dvecs; v1; v1 = v1->v_next) + if (!v1->v_link2) + fprintf(cp_err, + ">>> %s vector %s in %s not in %s, or of wrong type\n", + isreal(v1) ? "real" : "complex", + v1->v_name, p1->pl_typename, + p2->pl_typename); + for (v2 = p2->pl_dvecs; v2; v2 = v2->v_next) + if (!v2->v_link2) + fprintf(cp_err, + ">>> %s vector %s in %s not in %s, or of wrong type\n", + isreal(v2) ? "real" : "complex", + v2->v_name, p2->pl_typename, + p1->pl_typename); + + /* Throw out the ones that aren't in the arg list */ + if (wl && !eq(wl->wl_word, "all")) { /* Just in case */ + for (v1 = p1->pl_dvecs; v1; v1 = v1->v_next) + if (v1->v_link2) { + for (tw = wl; tw; tw = tw->wl_next) + if (nameeq(v1->v_name, tw->wl_word)) + break; + if (!tw) + v1->v_link2 = NULL; + } + for (v2 = p2->pl_dvecs; v2; v2 = v2->v_next) + if (v2->v_link2) { + for (tw = wl; tw; tw = tw->wl_next) + if (nameeq(v2->v_name, tw->wl_word)) + break; + if (!tw) + v2->v_link2 = NULL; + } + } + + /* Now we have all the vectors linked to their twins. Travel + * down each one and print values that differ enough. + */ + for (v1 = p1->pl_dvecs; v1; v1 = v1->v_next) { + if (!v1->v_link2) + continue; + v2 = v1->v_link2; + if (v1->v_type == SV_VOLTAGE) + tol = vntol; + else + tol = abstol; + j = MAX(v1->v_length, v2->v_length); + for (i = 0; i < j; i++) { + if (v1->v_length <= i) { + fprintf(cp_out, + ">>> %s is %d long in %s and %d long in %s\n", + v1->v_name, v1->v_length, + p1->pl_typename, v2->v_length, + p2->pl_typename); + break; + } else if (v2->v_length <= i) { + fprintf(cp_out, + ">>> %s is %d long in %s and %d long in %s\n", + v2->v_name, v2->v_length, + p2->pl_typename, v1->v_length, + p1->pl_typename); + break; + } else { + if (isreal(v1)) { + d1 = v1->v_realdata[i]; + d2 = v2->v_realdata[i]; + if (MAX(fabs(d1), fabs(d2)) * reltol + + tol < fabs(d1 - d2)) { + fprintf(cp_out, + "%s.%s[%d] = %-15s ", + p1->pl_typename, v1->v_name, i, + printnum(d1)); + fprintf(cp_out, + "%s.%s[%d] = %s\n", + p2->pl_typename, v2->v_name, i, + printnum(d2)); + } + } else { + c1 = v1->v_compdata[i]; + c2 = v2->v_compdata[i]; + realpart(&c3) = realpart(&c1) - realpart(&c2); + imagpart(&c3) = imagpart(&c1) - imagpart(&c2); + /* Stupid evil PC compilers */ + cm1 = cmag(&c1); + cm2 = cmag(&c2); + cmax = MAX(cm1, cm2); + if (cmax * reltol + + tol < cmag(&c3)) { + fprintf(cp_out, + "%s.%s[%d] = %-10s, %-10s %s.%s[%d] = %-10s, %s\n", + p1->pl_typename, v1->v_name, i, + copy(printnum(realpart(&c1))), + copy(printnum(imagpart(&c1))), + p2->pl_typename, v2->v_name, i, + copy(printnum(realpart(&c2))), + copy(printnum(imagpart(&c2)))); + } + } + } + } + } + return; +} + diff --git a/src/frontend/diff.h b/src/frontend/diff.h new file mode 100644 index 000000000..63b2557b1 --- /dev/null +++ b/src/frontend/diff.h @@ -0,0 +1,14 @@ +/************* + * Header file for diff.c + * 1999 E. Rouat + ************/ + +#ifndef DIFF_H_INCLUDED +#define DIFF_H_INCLUDED + +void com_diff(wordlist *wl); + + + + +#endif diff --git a/src/frontend/dimens.c b/src/frontend/dimens.c new file mode 100644 index 000000000..db8788273 --- /dev/null +++ b/src/frontend/dimens.c @@ -0,0 +1,214 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1992 David A. Gates, U. C. Berkeley CAD Group +**********/ + +/* + * Read and write dimension/index arrays via strings. + */ + +#include "ngspice.h" +#include "ftedata.h" /* For MAXDIMS */ +#include "dimens.h" + + +/* + * Create a string of the form "12,1,10". + */ +char * +dimstring(int *data, int length) +{ + int i; + char buf[BSIZE_SP]; + + if (!data || length < 1) + return NULL; + + buf[0] = '\0'; + for (i=0; i < length; i++) { + sprintf(buf + strlen(buf), "%d%s", data[i], + (i < length - 1) ? "," : ""); + } + /* XXX Should I return a copy instead? */ + return(buf); +} + +/* + * Create a string of the form "[12][1][10]". + */ +char * +indexstring(int *data, int length) +{ + int i; + char buf[BSIZE_SP]; + + if (!data || length < 1) + return NULL; + + buf[0] = '\0'; + for (i=0; i < length; i++) { + sprintf(buf + strlen(buf), "[%d]", data[i]); + } + return(buf); +} + +/* + * Add one to anstrchr into an array with sizes in dims. + * Return 1 when all counters overflow at once. + */ +int +incindex(int *counts, int numcounts, int *dims, int numdims) +{ + int i, start; + + if (!counts || numcounts < 1 || !dims || numdims < 1) + return 0; + + start = numcounts - 1; + for (i = start; i >= 0; i--) { + if (++counts[i] < dims[i]) + break; /* This counter is not maxed out. */ + else + counts[i] = 0; + } + if (i == 0) + return(1); + else + return(0); +} + +/* + * Count number of empty dimensions in an array. + */ +int +emptydims(int *data, int length) +{ + int i, numempty = 0; + + for (i=0; i < length; i++) { + if (data[i] == 0) + numempty++; + } + return(numempty); +} + +/* + * Read a string of one of the following forms into a dimensions array: + * [12][1][10] + * [12,1,10] + * 12,1,10 + * 12, 1, 10 + * 12 , 1 , 10 + * Basically, we require that all brackets be matched, that all numbers + * be separated by commas or by "][", that all whitespace is ignored, and + * the beginning [ and end ] are ignored if they exist. The only valid + * characters in the string are brackets, commas, spaces, and digits. + * If any dimension is blank, its entry in the array is set to 0. + * + * Return 0 on success, 1 on failure. + */ +int +atodims(char *p, int *data, int *outlength) +{ + int length = 0; + int state = 0; + int err = 0; + int needbracket = 0; + char sep = '\0'; + + if (!data || !outlength) + return 1; + + if (!p) { + *outlength = 0; + return 0; + } + + while (*p && isspace(*p)) + p++; + + if (*p == '[') { + p++; + while (*p && isspace(*p)) + p++; + needbracket = 1; + } + + while (*p && state != 3) { + switch (state) { + case 0: /* p just at or before a number */ + if (length >= MAXDIMS) { + if (length == MAXDIMS) + printf("Error: maximum of %d dimensions allowed.\n", + MAXDIMS); + length += 1; + } else if (!isdigit(*p)) { + data[length++] = 0; /* This position was empty. */ + } else { + data[length++] = atoi(p); + while (isdigit(*p)) + p++; + } + state = 1; + break; + + case 1: /* p after a number, looking for ',' or ']' */ + if (sep == '\0') { + sep = *p; + } + if (*p == ']' && *p == sep) { + p++; + state = 2; + } else if (*p == ',' && *p == sep) { + p++; + state = 0; + } else /* Funny character following a # */ + break; + break; + + case 2: /* p after a ']', either at the end or looking for '[' */ + if (*p == '[') { + p++; + state = 0; + } else { + state = 3; + } + break; + } + + while (*p && isspace(*p)) + p++; + } + + *outlength = length; + if (length > MAXDIMS) { + return(1); + } + if (state == 3) { /* We finished with a closing bracket */ + err = !needbracket; + } else if (*p) { /* We finished by hitting a bad character after a # */ + err = 1; + } else { /* We finished by exhausting the string */ + err = needbracket; + } + if (err) { + *outlength = 0; + } + return(err); +} + +/* + * Skip to the first character that cannot be part of a dimension string. + */ +char * +skipdims(char *p) +{ + if (!p) + return NULL; + + while(*p && (*p == '[' || *p == ']' || *p == ',' + || isspace(*p) || isdigit(*p))) + p++; + + return(p); +} diff --git a/src/frontend/dimens.h b/src/frontend/dimens.h new file mode 100644 index 000000000..fa55fc668 --- /dev/null +++ b/src/frontend/dimens.h @@ -0,0 +1,18 @@ +/************* + * Header file for dimens.c + * 1999 E. Rouat + ************/ + +#ifndef DIMENS_H_INCLUDED +#define DIMENS_H_INCLUDED + +char * dimstring(int *data, int length); +char * indexstring(int *data, int length); +int incindex(int *counts, int numcounts, int *dims, int numdims); +int emptydims(int *data, int length); +int atodims(char *p, int *data, int *outlength); +char * skipdims(char *p); + + + +#endif diff --git a/src/frontend/display.c b/src/frontend/display.c new file mode 100644 index 000000000..6f2006f42 --- /dev/null +++ b/src/frontend/display.c @@ -0,0 +1,385 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + + +#include "ngspice.h" +#include "ftegraph.h" +#include "ftedev.h" +#include "fteinput.h" +#include "cpdefs.h" /* for VT_STRING */ +#include "ftedefs.h" /* for mylog() */ +#include "display.h" + + + + +/* static declarations */ +static int gen_DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny); +static int gen_Input(REQUEST *request, RESPONSE *response); +static int nop(void); +static int nodev(void); + + + + +#ifndef X_DISPLAY_MISSING +extern int X11_Init(void), X11_NewViewport(GRAPH *graph), X11_Close(void), X11_Clear(void), + X11_DrawLine(int x1, int y1, int x2, int y2), X11_Arc(int x0, int y0, int radius, double theta1, double theta2), X11_Text(char *text, int x, int y), X11_DefineColor(int colorid, double red, double green, double blue), + X11_DefineLinestyle(int linestyleid, int mask), X11_SetLinestyle(int linestyleid), X11_SetColor(int colorid), + X11_Update(void), + X11_Input(REQUEST *request, RESPONSE *response); +#endif + + + + + +extern int Plt5_Init(void), Plt5_NewViewport(GRAPH *graph), Plt5_Close(void), Plt5_Clear(void), + Plt5_DrawLine(int x1, int y1, int x2, int y2), Plt5_Arc(int x0, int y0, int radius, double theta1, double theta2), Plt5_Text(char *text, int x, int y), + Plt5_DefineLinestyle(), Plt5_SetLinestyle(int linestyleid), Plt5_SetColor(int colorid), + Plt5_Update(void); + +extern int PS_Init(void), PS_NewViewport(GRAPH *graph), PS_Close(void), PS_Clear(void), + PS_DrawLine(int x1, int y1, int x2, int y2), PS_Arc(int x0, int y0, int r, double theta1, double theta2), PS_Text(char *text, int x, int y), + PS_DefineLinestyle(), PS_SetLinestyle(int linestyleid), PS_SetColor(int colorid), + PS_Update(void); + +DISPDEVICE device[] = { + + {"error", 0, 0, 0, 0, 0, 0, nop, nop, + nop, nop, + nop, nop, nop, nop, nop, + nop, nop, nop, + nop, nop, nop, gen_Input, + nop,}, + +#ifndef X_DISPLAY_MISSING + {"X11", 0, 0, 1024, 864, 0, 0, X11_Init, X11_NewViewport, + X11_Close, X11_Clear, + X11_DrawLine, X11_Arc, X11_Text, X11_DefineColor, X11_DefineLinestyle, + X11_SetLinestyle, X11_SetColor, X11_Update, + nodev, nodev, nodev, X11_Input, + gen_DatatoScreen,}, +#endif + + + {"plot5", 0, 0, 1000, 1000, 0, 0, Plt5_Init, Plt5_NewViewport, + Plt5_Close, Plt5_Clear, + Plt5_DrawLine, Plt5_Arc, Plt5_Text, nodev, nodev, + Plt5_SetLinestyle, Plt5_SetColor, Plt5_Update, + nodev, nodev, nodev, nodev, + gen_DatatoScreen,}, + + {"postscript", 0, 0, 1000, 1000, 0, 0, PS_Init, PS_NewViewport, + PS_Close, PS_Clear, + PS_DrawLine, PS_Arc, PS_Text, nodev, nodev, + PS_SetLinestyle, PS_SetColor, PS_Update, + nodev, nodev, nodev, nodev, + gen_DatatoScreen,}, + + {"printf", 0, 0, 24, 80, 0, 0, nodev, nodev, + nodev, nodev, + nodev, nodev, nodev, nodev, nodev, + nodev, nodev, nodev, + nodev, nodev, nodev, gen_Input, + nodev,}, + +}; + +DISPDEVICE *dispdev = device + NUMELEMS(device) - 1; + +#define XtNumber(arr) (sizeof(arr) / sizeof(arr[0])) + + +extern void internalerror (char *message); +extern void externalerror (char *message); + +DISPDEVICE *FindDev(char *name) +{ + int i; + + for (i=0; i < XtNumber(device); i++) { + if (!strcmp(name, device[i].name)) { + return(&device[i]); + } + } + sprintf(ErrorMessage, "Can't find device %s.", name); + internalerror(ErrorMessage); + return(&device[0]); + +} + +void +DevInit(void) +{ + + char buf[128]; + +/* note: do better determination */ + +/* + dumb tradition that got passed on from gi_interface + to do compile time determination +*/ + + dispdev = NULL; + +#ifndef X_DISPLAY_MISSING + /* determine display type */ + if (getenv("DISPLAY") || cp_getvar("display", VT_STRING, buf)) { + +#ifndef X_DISPLAY_MISSING + dispdev = FindDev("X11"); +#endif + } +#endif + + + + if (!dispdev) { + externalerror( + "no graphics interface; please check compiling instructions"); + dispdev = FindDev("error"); + } else if ((*(dispdev->Init))()) { + fprintf(cp_err, + "Warning: can't initialize display device for graphics.\n"); + dispdev = FindDev("error"); + } + +} + +/* NewViewport is responsible for filling in graph->viewport */ +int +NewViewport(GRAPH *pgraph) +{ + + return (*(dispdev->NewViewport))(pgraph); + +} + +void DevClose(void) +{ + + (*(dispdev->Close))(); + +} + +void DevClear(void) +{ + + (*(dispdev->Clear))(); + +} + +void DrawLine(int x1, int y1, int x2, int y2) +{ + (*(dispdev->DrawLine))(x1, y1, x2, y2); + +} + +void Arc(int x0, int y0, int radius, double theta1, double theta2) +{ + + (*(dispdev->Arc))(x0, y0, radius, theta1, theta2); + +} + +void Text(char *text, int x, int y) +{ + + (*(dispdev->Text))(text, x, y); + +} + +void DefineColor(int colorid, double red, double green, double blue) +{ + + (*(dispdev->DefineColor))(colorid, red, green, blue); + +} + +void DefineLinestyle(int linestyleid, int mask) +{ + + (*(dispdev->DefineLinestyle))(linestyleid, mask); + +} + +void SetLinestyle(int linestyleid) +{ + + (*(dispdev->SetLinestyle))(linestyleid); + +} + +void SetColor(int colorid) +{ + + (*(dispdev->SetColor))(colorid); + +} + +void Update(void) +{ + + if (dispdev) + (*(dispdev->Update))(); + +} + +/* note: screen coordinates are relative to window + so need to add viewport offsets */ +static int +gen_DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny) +{ + + double low, high; + + /* note: may want to cache datawindowsize/viewportsize */ /* done */ + + /* note: think this out---Is 1 part of the viewport? Do we handle + this correctly? */ + + /* have to handle several types of grids */ + + /* note: we can't compensate for X's demented y-coordinate system here + since the grid routines use DrawLine w/o calling this routine */ + if ((graph->grid.gridtype == GRID_LOGLOG) || + (graph->grid.gridtype == GRID_YLOG)) { + low = mylog10(graph->datawindow.ymin); + high = mylog10(graph->datawindow.ymax); + *screeny = (mylog10(y) - low) / (high - low) * graph->viewport.height + + 0.5 + graph->viewportyoff; + } else { + *screeny = ((y - graph->datawindow.ymin) / graph->aspectratioy) + + 0.5 + graph->viewportyoff; + } + + if ((graph->grid.gridtype == GRID_LOGLOG) || + (graph->grid.gridtype == GRID_XLOG)) { + low = mylog10(graph->datawindow.xmin); + high = mylog10(graph->datawindow.xmax); + *screenx = (mylog10(x) - low) / (high - low) * graph->viewport.width + + 0.5 + graph ->viewportxoff; + } else { + *screenx = (x - graph->datawindow.xmin) / graph->aspectratiox + + 0.5 + graph ->viewportxoff; + } + +} + +void DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny) +{ + + (*(dispdev->DatatoScreen))(graph, x, y, screenx, screeny); + +} + +#ifdef notdef +/* +NDCtoScreen(x0, y0, px, py) + double x0, y0; + int *px, *py; +{ + + (*(dispdev->NDCtoScreen))(x0, y0, px, py); + +} +*/ +#endif + +void Input(REQUEST *request, RESPONSE *response) +{ + + (*(dispdev->Input))(request, response); + +} + +static int +gen_Input(REQUEST *request, RESPONSE *response) +{ + + switch (request->option) { + case char_option: + response->reply.ch = inchar(request->fp); + response->option = request->option; + break; + default: + /* just ignore, since we don't want a million error messages */ + if (response) + response->option = error_option; + break; + } +} + +/* no operation, do nothing */ +static int nop(void) +{ + return(1); /* so NewViewport will fail */ +} + +static int nodev(void) +{ + + sprintf(ErrorMessage, + "This operation is not defined for display type %s.", + dispdev->name); + internalerror(ErrorMessage); + return(1); + +} + +void SaveText(GRAPH *graph, char *text, int x, int y) +{ + + struct _keyed *keyed; + + keyed = (struct _keyed *) calloc(1, sizeof(struct _keyed)); + + if (!graph->keyed) { + graph->keyed = keyed; + } else { + keyed->next = graph->keyed; + graph->keyed = keyed; + } + + keyed->text = tmalloc(strlen(text) + 1); + strcpy(keyed->text, text); + + keyed->x = x; + keyed->y = y; + + keyed->colorindex = graph->currentcolor; + +} + +/* if given name of a hardcopy device, finds it and switches devices + if given NULL, switches back */ +int DevSwitch(char *devname) +{ + + static DISPDEVICE *lastdev = NULL; + + if (devname != NULL) { + if (lastdev != NULL) { + internalerror("DevSwitch w/o changing back"); + return (1); + } + lastdev = dispdev; + dispdev = FindDev(devname); + if (!strcmp(dispdev->name, "error")) { + internalerror("no hardcopy device"); + dispdev = lastdev; /* undo */ + lastdev = NULL; + return (1); + } + (*(dispdev->Init))(); + } else { + (*(dispdev->Close))(); + dispdev = lastdev; + lastdev = NULL; + } + return(0); + +} diff --git a/src/frontend/display.h b/src/frontend/display.h new file mode 100644 index 000000000..a0a9e2d3d --- /dev/null +++ b/src/frontend/display.h @@ -0,0 +1,30 @@ +/************* + * Header file for display.c + * 1999 E. Rouat + ************/ + +#ifndef DISPLAY_H_INCLUDED +#define DISPLAY_H_INCLUDED + +DISPDEVICE *FindDev(char *name); +void DevInit(void); +int NewViewport(GRAPH *pgraph); +void DevClose(void); +void DevClear(void); +void DrawLine(int x1, int y1, int x2, int y2); +void Arc(int x0, int y0, int radius, double theta1, double theta2); +void Text(char *text, int x, int y); +void DefineColor(int colorid, double red, double green, double blue); +void DefineLinestyle(int linestyleid, int mask); +void SetLinestyle(int linestyleid); +void SetColor(int colorid); +void Update(void); +void DatatoScreen(GRAPH *graph, double x, double y, int *screenx, int *screeny); +void Input(REQUEST *request, RESPONSE *response); +void SaveText(GRAPH *graph, char *text, int x, int y); +int DevSwitch(char *devname); + + + + +#endif diff --git a/src/frontend/doplot.c b/src/frontend/doplot.c new file mode 100644 index 000000000..310978bda --- /dev/null +++ b/src/frontend/doplot.c @@ -0,0 +1,1276 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Plotting routines + */ + +#include "ngspice.h" +#include "fteinput.h" +#include "ftedbgra.h" +#include "cpdefs.h" +#include "fteconst.h" +#include "ftedefs.h" +#include "ftedev.h" +#include "ftedata.h" +#include "fteparse.h" +#include "fteext.h" +#include "doplot.h" + + + +extern double *ft_SMITHminmax(struct dvec *v, bool yval); +extern void ft_xgraph(double *xlims, double *ylims, char *filename, char *title, char *xlabel, char *ylabel, GRIDTYPE gridtype, PLOTTYPE plottype, struct dvec *vecs); + +static bool sameflag; + +static bool plotit(wordlist *wl, char *hcopy, char *devname); +static double * getlims(wordlist *wl, char *name, int number); +static char * getword(wordlist *wl, char *name); +static bool getflag(wordlist *wl, char *name); +static void xtend(struct dvec *v, int length); +static void compress(struct dvec *d, double *xcomp, double *xind); + + + + +/* asciiplot file name ... [xlimit] xhi xlo] [vs xname] */ + + +extern void Input (REQUEST *request, RESPONSE *response); +extern int DevSwitch (char *devname); +extern int NewViewport (GRAPH *pgraph); +extern void gr_resize (GRAPH *graph); +extern void gr_redraw (GRAPH *graph); +extern int DestroyGraph (int id); +extern int unlink (const char *); + +void +com_asciiplot(wordlist *wl) +{ + (void) plotit(wl, (char *) NULL, "lpr"); + return; +} + +/* xgraph file plotargs + */ + +void +com_xgraph(wordlist *wl) +{ + char *fname; + bool tempf = FALSE; + + if (wl) { + fname = wl->wl_word; + wl = wl->wl_next; + } + if (!wl) { + return; + } + if (cieq(fname, "temp") || cieq(fname, "tmp")) { + fname = smktemp("xg"); + tempf = TRUE; + } + + (void) plotit(wl, fname, "xgraph"); + +/* Leave temp file sitting around so xgraph can grab it from background. + if (tempf) + (void) unlink(fname); +*/ + + + return; +} + +/* hardcopy file plotargs, or 'hardcopy file' -- with no other args this + * prompts the user for a window to dump to a plot file. XXX no it doesn't. + */ + +void +com_hardcopy(wordlist *wl) +{ + char *buf2, *prompt(FILE *fp); + wordlist *process(wordlist *wlist); + char *fname; + char buf[BSIZE_SP], device[BSIZE_SP]; + bool tempf = FALSE; + char *devtype; + char format[513]; + int printed; + int hc_button; + int foundit; + + if (!cp_getvar("hcopydev", VT_STRING, device)) + *device = '\0'; + + if (wl) { + hc_button = 0; + fname = wl->wl_word; + wl = wl->wl_next; + } else { + hc_button = 1; + fname = smktemp("hc"); + tempf = TRUE; + } + + if (!cp_getvar("hcopydevtype", VT_STRING, buf)) { + devtype = "plot5"; + } else { + devtype = buf; + } + +/* enable screen plot selection for these display types */ + + foundit = 0; + +#ifndef X_DISPLAY_MISSING + if (!wl && hc_button) { + + REQUEST request; + RESPONSE response; + GRAPH *tempgraph; + + request.option = click_option; + Input(&request, &response); + + if (response.option == error_option) return; + + if (response.reply.graph) { + + if (DevSwitch(devtype)) return; + tempgraph = CopyGraph(response.reply.graph); + tempgraph->devdep = fname; + if (NewViewport(tempgraph)) { + DevSwitch(NULL); + return; + } + gr_resize(tempgraph); + gr_redraw(tempgraph); + DestroyGraph(tempgraph->graphid); + DevSwitch(NULL); + foundit = 1; + } + } + +#endif + + + if (!foundit) { + + if (!wl) { + outmenuprompt("which variable ? "); + if ((buf2 = prompt(cp_in)) == (char *) -1) /* XXXX Sick */ + return; + wl = alloc(struct wordlist); + wl->wl_word = buf2; + wl->wl_next = NULL; + wl = process(wl); + } + + + + if (DevSwitch(devtype)) return; + + if (!wl || !plotit(wl, fname, (char *) NULL)) { + printf("com_hardcopy: graph not defined\n"); + DevSwitch(NULL); /* remember to switch back */ + return; + } + + DevSwitch(NULL); + + } + + printed = 0; + + + if (*device) { +#ifdef SYSTEM_PLOT5LPR + if (!strcmp(devtype, "plot5") || !strcmp(devtype, "MFB")) { + if (!cp_getvar("lprplot5", VT_STRING, format)) + strcpy(format, SYSTEM_PLOT5LPR); + (void) sprintf(buf, format, device, fname); + fprintf(cp_out, "Printing %s on the %s printer.\n", fname, device); + (void) system(buf); + printed = 1; + } +#endif +#ifdef SYSTEM_PSLPR + if (!printed && !strcmp(devtype, "postscript")) { + /* note: check if that was a postscript printer XXX */ + if (!cp_getvar("lprps", VT_STRING, format)) + strcpy(format, SYSTEM_PSLPR); + (void) sprintf(buf, format, device, fname); + fprintf(cp_out, "Printing %s on the %s printer.\n", fname, device); + (void) system(buf); + printed = 1; + } +#endif + } + + if (!printed) { + if (!strcmp(devtype, "plot5")) { + fprintf(cp_out, + "The file \"%s\" may be printed with the Unix \"plot\" command,\n", + fname); + fprintf(cp_out, + "\tor by using the '-g' flag to the Unix lpr command.\n"); + } else if (!strcmp(devtype, "postscript")) { + fprintf(cp_out, + "The file \"%s\" may be printed on a postscript printer.\n", + fname); + } else if (!strcmp(devtype, "MFB")) { + fprintf(cp_out, + "The file \"%s\" may be printed on a MFB device.\n", + fname); + } + } + + if (tempf && *device) + (void) unlink(fname); + + return; +} + +/* plot name ... [xl[imit]] xlo xhi] [yl[imit ylo yhi] [vs xname] */ + +void +com_plot(wordlist *wl) +{ + (void) plotit(wl, (char *) NULL, (char *) NULL); + return; +} + +/* The common routine for all plotting commands. This does hardcopy + * and graphics plotting. + */ + +static wordlist *wl_root; + +static bool +plotit(wordlist *wl, char *hcopy, char *devname) +{ + /* All these things are static so that "samep" will work. */ + static double *xcompress = NULL, *xindices = NULL; + static double *xlim = NULL, *ylim = NULL; + static double *xdelta = NULL, *ydelta = NULL; + static char *xlabel = NULL, *ylabel = NULL, *title = NULL; + static bool nointerp = FALSE; + static GRIDTYPE gtype = GRID_LIN; + static PLOTTYPE ptype = PLOT_LIN; + + bool gfound = FALSE, pfound = FALSE, oneval = FALSE; + double *dd, ylims[2], xlims[2]; + struct pnode *n, *names; + struct dvec *dv, *d = NULL, *vecs = NULL, *lv, *lastvs = NULL; + char *xn; + int i, j, xt; + double tt, mx, my, rad; + wordlist *wwl, *tw; + char cline[BSIZE_SP], buf[BSIZE_SP], *pname; + + int newlen; + struct dvec *v, *newv_scale; + double *newdata, *newscale; + double tstep, tstart, tstop, ttime; + + if (!wl) + return FALSE; + wl_root = wl; + + /* First get the command line, without the limits. */ + wwl = wl_copy(wl); + (void) getlims(wwl, "xl", 2); + (void) getlims(wwl, "xlimit", 2); + (void) getlims(wwl, "yl", 2); + (void) getlims(wwl, "ylimit", 2); + (void) sprintf(cline, "plot %s", wl_flatten(wwl)); + + wl_free(wwl); + + /* Now extract all the parameters. */ + + /* In case the parameter is the first on the line, we need a + * "buffer" word... + */ + tw = alloc(struct wordlist); + wl->wl_prev = tw; + tw->wl_next = wl; + wl = tw; + tw->wl_word = ""; + + sameflag = getflag(wl, "samep"); + + if (!sameflag || !xlim) { + xlim = getlims(wl, "xl", 2); + if (!xlim) + xlim = getlims(wl, "xlimit", 2); + } else { + (void) getlims(wl, "xl", 2); + (void) getlims(wl, "xlimit", 2); + } + + if (!sameflag || !ylim) { + ylim = getlims(wl, "yl", 2); + if (!ylim) + ylim = getlims(wl, "ylimit", 2); + } else { + (void) getlims(wl, "yl", 2); + (void) getlims(wl, "ylimit", 2); + } + + if (!sameflag || !xcompress) { + xcompress = getlims(wl, "xcompress", 1); + if (!xcompress) + xcompress = getlims(wl, "xcomp", 1); + } else { + (void) getlims(wl, "xcompress", 1); + (void) getlims(wl, "xcomp", 1); + } + + if (!sameflag || !xindices) { + xindices = getlims(wl, "xindices", 2); + if (!xindices) + xindices = getlims(wl, "xind", 2); + } else { + (void) getlims(wl, "xindices", 2); + (void) getlims(wl, "xind", 2); + } + + if (!sameflag || !xdelta) { + xdelta = getlims(wl, "xdelta", 1); + if (!xdelta) + xdelta = getlims(wl, "xdel", 1); + } else { + (void) getlims(wl, "xdelta", 1); + (void) getlims(wl, "xdel", 1); + } + if (!sameflag || !ydelta) { + ydelta = getlims(wl, "ydelta", 1); + if (!ydelta) + ydelta = getlims(wl, "ydel", 1); + } else { + (void) getlims(wl, "ydelta", 1); + (void) getlims(wl, "ydel", 1); + } + + /* Get the grid type and the point type. Note we can't do if-else + * here because we want to catch all the grid types. + */ + if (getflag(wl, "lingrid")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_LIN; + gfound = TRUE; + } + } + if (getflag(wl, "loglog")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_LOGLOG; + gfound = TRUE; + } + } + if (getflag(wl, "nogrid")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_NONE; + gfound = TRUE; + } + } + if (getflag(wl, "linear")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_LIN; + gfound = TRUE; + } + } + if (getflag(wl, "xlog")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_XLOG; + gfound = TRUE; + } + } + if (getflag(wl, "ylog")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_YLOG; + gfound = TRUE; + } + } + if (getflag(wl, "polar")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_POLAR; + gfound = TRUE; + } + } + if (getflag(wl, "smith")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_SMITH; + gfound = TRUE; + } + } + if (getflag(wl, "smithgrid")) { + if (gfound) + fprintf(cp_err, + "Warning: too many grid types given\n"); + else { + gtype = GRID_SMITHGRID; + gfound = TRUE; + } + } + + if (!sameflag && !gfound) { + if (cp_getvar("gridstyle", VT_STRING, buf)) { + if (eq(buf, "lingrid")) + gtype = GRID_LIN; + else if (eq(buf, "loglog")) + gtype = GRID_LOGLOG; + else if (eq(buf, "xlog")) + gtype = GRID_XLOG; + else if (eq(buf, "ylog")) + gtype = GRID_YLOG; + else if (eq(buf, "smith")) + gtype = GRID_SMITH; + else if (eq(buf, "smithgrid")) + gtype = GRID_SMITHGRID; + else if (eq(buf, "polar")) + gtype = GRID_POLAR; + else if (eq(buf, "nogrid")) + gtype = GRID_NONE; + else { + fprintf(cp_err, + "Warning: strange grid type %s\n", + buf); + gtype = GRID_LIN; + } + gfound = TRUE; + } else + gtype = GRID_LIN; + } + + /* Now get the point type. */ + + if (getflag(wl, "linplot")) { + if (pfound) + fprintf(cp_err, + "Warning: too many plot types given\n"); + else { + ptype = PLOT_LIN; + pfound = TRUE; + } + } + if (getflag(wl, "combplot")) { + if (pfound) + fprintf(cp_err, + "Warning: too many plot types given\n"); + else { + ptype = PLOT_COMB; + pfound = TRUE; + } + } + if (getflag(wl, "pointplot")) { + if (pfound) + fprintf(cp_err, + "Warning: too many plot types given\n"); + else { + ptype = PLOT_POINT; + pfound = TRUE; + } + } + + if (!sameflag && !pfound) { + if (cp_getvar("plotstyle", VT_STRING, buf)) { + if (eq(buf, "linplot")) + ptype = PLOT_LIN; + else if (eq(buf, "combplot")) + ptype = PLOT_COMB; + else if (eq(buf, "pointplot")) + ptype = PLOT_POINT; + else { + fprintf(cp_err, + "Warning: strange plot type %s\n", + buf); + ptype = PLOT_LIN; + } + pfound = TRUE; + } else + ptype = PLOT_LIN; + } + + if (!sameflag || !xlabel) + xlabel = getword(wl, "xlabel"); + else + (void) getword(wl, "xlabel"); + if (!sameflag || !ylabel) + ylabel = getword(wl, "ylabel"); + else + (void) getword(wl, "ylabel"); + if (!sameflag || !title) + title = getword(wl, "title"); + else + (void) getword(wl, "title"); + + if (!sameflag) + nointerp = getflag(wl, "nointerp"); + else if (getflag(wl, "nointerp")) + nointerp = TRUE; + + wl = wl->wl_next; + if (!wl) { + fprintf(cp_err, "Error: no vectors given\n"); + return (FALSE); + } + + wl->wl_prev = NULL; + + /* Now parse the vectors. We have a list of the form + * "a b vs c d e vs f g h". Since it's a bit of a hassle for + * us to parse the vector boundaries here, we do this -- call + * ft_getpnames() without the check flag, and then look for 0-length + * vectors with the name "vs"... This is a sort of a gross hack, + * since we have to check for 0-length vectors ourselves after + * evaulating the pnodes... + */ + + names = ft_getpnames(wl, FALSE); + if (names == NULL) + return (FALSE); + + /* Now evaluate the names. */ + for (n = names, lv = NULL; n; n = n->pn_next) { + if (n->pn_value && (n->pn_value->v_length == 0) && + eq(n->pn_value->v_name, "vs")) { + if (!lv) { + fprintf(cp_err, "Error: misplaced vs arg\n"); + return (FALSE); + } else { + if (!(n = n->pn_next)) { + fprintf(cp_err, + "Error: missing vs arg\n"); + return (FALSE); + } + dv = ft_evaluate(n); + if (!dv) + return (FALSE); + if (lastvs) + lv = lastvs->v_link2; + else + lv = vecs; + while (lv) { + lv->v_scale = dv; + lastvs = lv; + lv = lv->v_link2; + } + } + continue; + } + dv = ft_evaluate(n); + if (!dv) + return (FALSE); + if (!d) + vecs = dv; + else + d->v_link2 = dv; + for (d = dv; d->v_link2; d = d->v_link2) + ; + lv = dv; + } + free_pnode(names); + d->v_link2 = NULL; + + /* Now check for 0-length vectors. */ + for (d = vecs; d; d = d->v_link2) + if (!d->v_length) { + fprintf(cp_err, "Error: %s: no such vector\n", + d->v_name); + return (FALSE); + } + + /* If there are higher dimensional vectors, transform them into a + * family of vectors. + */ + for (d = vecs, lv = NULL; d; d = d->v_link2) { + if (d->v_numdims > 1) { + if (lv) + lv->v_link2 = vec_mkfamily(d); + else + vecs = lv = vec_mkfamily(d); + while (lv->v_link2) + lv = lv->v_link2; + lv->v_link2 = d->v_link2; + d = lv; + } else { + lv = d; + } + } + + /* Now fill in the scales for vectors who aren't already fixed up. */ + for (d = vecs; d; d = d->v_link2) + if (!d->v_scale) { + if (d->v_plot->pl_scale) + d->v_scale = d->v_plot->pl_scale; + else + d->v_scale = d; + } + + + /* See if the log flag is set anywhere... */ + if (!gfound) { + for (d = vecs; d; d = d->v_link2) + if (d->v_scale && (d->v_scale->v_gridtype == GRID_XLOG)) + gtype = GRID_XLOG; + for (d = vecs; d; d = d->v_link2) + if (d->v_gridtype == GRID_YLOG) { + if ((gtype == GRID_XLOG) || + (gtype == GRID_LOGLOG)) + gtype = GRID_LOGLOG; + else + gtype = GRID_YLOG; + } + for (d = vecs; d; d = d->v_link2) + if (d->v_gridtype == GRID_SMITH || d->v_gridtype == GRID_SMITHGRID + || d->v_gridtype == GRID_POLAR) + { + gtype = d->v_gridtype; + break; + } + } + + /* See if there are any default plot types... Here, like above, we + * don't do entirely the best thing when there is a mixed set of + * default plot types... + */ + if (!sameflag && !pfound) { + ptype = PLOT_LIN; + for (d = vecs; d; d = d->v_link2) + if (d->v_plottype != PLOT_LIN) { + ptype = d->v_plottype; + break; + } + } + + /* Check and see if this is pole zero stuff. */ + if ((vecs->v_type == SV_POLE) || (vecs->v_type == SV_ZERO)) + oneval = TRUE; + + for (d = vecs; d; d = d->v_link2) + if (((d->v_type == SV_POLE) || (d->v_type == SV_ZERO)) != + oneval ? 1 : 0) { + fprintf(cp_err, +"Error: plot must be either all pole-zero or contain no poles or zeros\n"); + return (FALSE); + } + + if ((gtype == GRID_POLAR) || (gtype == GRID_SMITH + || gtype == GRID_SMITHGRID)) + { + oneval = TRUE; + } + + /* If we are plotting scalars, make sure there is enough + * data to fit on the screen. + */ + + for (d = vecs; d; d = d->v_link2) + if (d->v_length == 1) + xtend(d, d->v_scale->v_length); + + /* Now patch up each vector with the compression and thestrchr + * selection. + */ + if (xcompress || xindices) { + for (d = vecs; d; d = d->v_link2) { + compress(d, xcompress, xindices); + d->v_scale = vec_copy(d->v_scale); + compress(d->v_scale, xcompress, xindices); + } + } + + /* Transform for smith plots */ + if (gtype == GRID_SMITH) { + double re, im, rex, imx; + double r, i, x; + struct dvec **prevvp, *n; + int j; + + prevvp = &vecs; + for (d = vecs; d; d = d->v_link2) { + if (d->v_flags & VF_PERMANENT) { + n = vec_copy(d); + n->v_flags &= ~VF_PERMANENT; + n->v_link2 = d->v_link2; + d = n; + *prevvp = d; + } + prevvp = &d->v_link2; + + if (isreal(d)) { + fprintf(cp_err, + "Warning: plotting real data \"%s\" on a smith grid\n", + d->v_name); + + for (j = 0; j < d->v_length; j++) { + r = d->v_realdata[j]; + d->v_realdata[j] = (r - 1) / (r + 1); + } + } else { + for (j = 0; j < d->v_length; j++) { + /* (re - 1, im) / (re + 1, im) */ + + re = realpart(d->v_compdata + j); + im = imagpart(d->v_compdata + j); + + rex = re + 1; + imx = im; + re = re - 1; + + /* (re, im) / (rex, imx) */ + x = 1 - (imx / rex) * (imx / rex); + r = re / rex + im / rex * imx / rex; + i = im / rex - re / rex * imx / rex; + + realpart(d->v_compdata + j) = r / x; + imagpart(d->v_compdata + j) = i / x; + } + } + } + } + + /* Figure out the proper x- and y-axis limits. */ + if (ylim) { +#ifdef notdef + if (gtype == GRID_SMITH) { + if (xlim) { + SMITH_tfm(xlim[0], ylim[0], &dummy, &ylims[0]); + SMITH_tfm(xlim[1], ylim[1], &dummy, &ylims[1]); + } else { + SMITH_tfm(0.0, ylim[0], &dummy, &ylims[0]); + SMITH_tfm(0.0, ylim[1], &dummy, &ylims[1]); + } + } else { + } +#endif + ylims[0] = ylim[0]; + ylims[1] = ylim[1]; + } else if (oneval) { + ylims[0] = HUGE; + ylims[1] = - ylims[0]; + for (d = vecs; d; d = d->v_link2) { +#ifdef notdef + if (gtype == GRID_SMITH) { + dd = ft_SMITHminmax(d, TRUE); + if( dd[0] < 0.0 ) + dd[0] *= 1.1; + else + dd[0] *= 0.9; + if( dd[1] >= 0.0 ) + dd[1] *= 1.1; + else + dd[1] *= 0.9; + } else +#endif + dd = ft_minmax(d, TRUE); + if (dd[0] < ylims[0]) + ylims[0] = dd[0]; + if (dd[1] > ylims[1]) + ylims[1] = dd[1]; + } + } else { + ylims[0] = HUGE; + ylims[1] = - ylims[0]; + for (d = vecs; d; d = d->v_link2) { + dd = ft_minmax(d, TRUE); + if (dd[0] < ylims[0]) + ylims[0] = dd[0]; + if (dd[1] > ylims[1]) + ylims[1] = dd[1]; + } + + /* XXX */ + for (d = vecs; d; d = d->v_link2) { + if (d->v_flags & VF_MINGIVEN) + if (ylims[0] < d->v_minsignal) + ylims[0] = d->v_minsignal; + if (d->v_flags & VF_MAXGIVEN) + if (ylims[1] > d->v_maxsignal) + ylims[1] = d->v_maxsignal; + } + } + + if (xlim) { +#ifdef notdef + if (gtype == GRID_SMITH) { + if (ylim) { + SMITH_tfm(xlim[0], ylim[0], &xlims[0], &dummy); + SMITH_tfm(xlim[1], ylim[1], &xlims[1], &dummy); + } else { + SMITH_tfm(xlim[0], 0.0, &xlims[0], &dummy); + SMITH_tfm(xlim[1], 0.0, &xlims[1], &dummy); + } + } else { + } +#endif + xlims[0] = xlim[0]; + xlims[1] = xlim[1]; + } else if (oneval) { + xlims[0] = HUGE; + xlims[1] = - xlims[0]; + for (d = vecs; d; d = d->v_link2) { +#ifdef notdef + if (gtype == GRID_SMITH) { + dd = ft_SMITHminmax(d, FALSE); + if( dd[0] < 0.0 ) + dd[0] *= 1.1; + else + dd[0] *= 0.9; + if( dd[1] >= 0.0 ) + dd[1] *= 1.1; + else + dd[1] *= 0.9; + } else +#endif + dd = ft_minmax(d, FALSE); + + if (dd[0] < xlims[0]) + xlims[0] = dd[0]; + if (dd[1] > xlims[1]) + xlims[1] = dd[1]; + } + } else { + xlims[0] = HUGE; + xlims[1] = - xlims[0]; + for (d = vecs; d; d = d->v_link2) { + dd = ft_minmax(d->v_scale, TRUE); + if (dd[0] < xlims[0]) + xlims[0] = dd[0]; + if (dd[1] > xlims[1]) + xlims[1] = dd[1]; + } + for (d = vecs; d; d = d->v_link2) { + if (d->v_scale->v_flags & VF_MINGIVEN) + if (xlims[0] < d->v_scale->v_minsignal) + xlims[0] = d->v_scale->v_minsignal; + if (d->v_scale->v_flags & VF_MAXGIVEN) + if (xlims[1] > d->v_scale->v_maxsignal) + xlims[1] = d->v_scale->v_maxsignal; + } + } + + /* Do some coercion of the limits to make them reasonable. */ + if ((xlims[0] == 0) && (xlims[1] == 0)) { + xlims[0] = -1.0; + xlims[1] = 1.0; + } + if ((ylims[0] == 0) && (ylims[1] == 0)) { + ylims[0] = -1.0; + ylims[1] = 1.0; + } + if (xlims[0] > xlims[1]) { + tt = xlims[1]; + xlims[1] = xlims[0]; + xlims[0] = tt; + } + if (ylims[0] > ylims[1]) { + tt = ylims[1]; + ylims[1] = ylims[0]; + ylims[0] = tt; + } + if (xlims[0] == xlims[1]) { + xlims[0] *= (xlims[0] > 0) ? 0.9 : 1.1; + xlims[1] *= (xlims[1] > 0) ? 1.1 : 0.9; + } + if (ylims[0] == ylims[1]) { + /* || fabs(ylims[0])/(ylims[1]-ylims[0]) > 1.0e9 + || fabs(ylims[1])/(ylims[1]-ylims[0]) > 1.0e9) */ + ylims[0] *= (ylims[0] > 0) ? 0.9 : 1.1; + ylims[1] *= (ylims[1] > 0) ? 1.1 : 0.9; + } + +#ifdef notdef + /* Now shrink the limits very slightly -- this helps prevent round-off + * error from doing bad things. + */ + if (gtype != GRID_LOGLOG && gtype != GRID_XLOG + && gtype != GRID_POLAR && gtype != GRID_SMITH) + { + tt = xlims[1] - xlims[0]; + xlims[0] += tt * 0.001; + xlims[1] -= tt * 0.001; + } + if (gtype != GRID_LOGLOG && gtype != GRID_YLOG + && gtype != GRID_POLAR && gtype != GRID_SMITH) { + tt = ylims[1] - ylims[0]; + ylims[0] += tt * 0.001; + ylims[1] -= tt * 0.001; + } +#endif + + if ((xlims[0] <= 0.0) && ((gtype == GRID_XLOG) || + (gtype == GRID_LOGLOG))) { + fprintf(cp_err, + "Error: X values must be > 0 for log scale\n"); + return (FALSE); + } + if ((ylims[0] <= 0.0) && ((gtype == GRID_YLOG) || + (gtype == GRID_LOGLOG))) { + fprintf(cp_err, + "Error: Y values must be > 0 for log scale\n"); + return (FALSE); + } + + /* Fix the plot limits for smith and polar grids. */ + if ((!xlim || !ylim) && (gtype == GRID_POLAR)) { + /* (0,0) must be in the center of the screen. */ + mx = (fabs(xlims[0]) > fabs(xlims[1])) ? fabs(xlims[0]) : + fabs(xlims[1]); + my = (fabs(ylims[0]) > fabs(ylims[1])) ? fabs(ylims[0]) : + fabs(ylims[1]); + rad = (mx > my) ? mx : my; + /* rad = sqrt(mx * mx + my * my); */ + xlims[0] = - rad; + xlims[1] = rad; + ylims[0] = - rad; + ylims[1] = rad; + } else if ((!xlim || !ylim) && (gtype == GRID_SMITH + || gtype == GRID_SMITHGRID)) + { +#ifdef notdef + /* Let the user zoom in */ + mx = (fabs(xlims[0]) > fabs(xlims[1])) ? fabs(xlims[0]) : + fabs(xlims[1]); + my = (fabs(ylims[0]) > fabs(ylims[1])) ? fabs(ylims[0]) : + fabs(ylims[1]); + rad = (mx > my) ? mx : my; + /* XXX */ + xlims[0] = - rad; + xlims[1] = rad; + ylims[0] = - rad; + ylims[1] = rad; +#endif + xlims[0] = -1.0; + xlims[1] = 1.0; + ylims[0] = -1.0; + ylims[1] = 1.0; + } + + /* We don't want to try to deal with smith plots for asciiplot. */ + if (devname && eq(devname, "lpr")) { + /* check if we should (can) linearize */ + if (!(!ft_curckt || !ft_curckt->ci_ckt || + strcmp(ft_curckt->ci_name, plot_cur->pl_title) || + !if_tranparams(ft_curckt, &tstart, &tstop, &tstep) || + ((tstop - tstart) * tstep <= 0.0) || + ((tstop - tstart) < tstep) || + !plot_cur || !plot_cur->pl_dvecs || + !plot_cur->pl_scale || + !isreal(plot_cur->pl_scale) || + !ciprefix("tran", plot_cur->pl_typename))) { + + newlen = (tstop - tstart) / tstep + 1.5; + + newscale = (double *) tmalloc(newlen * sizeof(double)); + + newv_scale = alloc(struct dvec); + newv_scale->v_flags = vecs->v_scale->v_flags; + newv_scale->v_type = vecs->v_scale->v_type; + newv_scale->v_gridtype = vecs->v_scale->v_gridtype; + newv_scale->v_length = newlen; + newv_scale->v_name = copy(vecs->v_scale->v_name); + newv_scale->v_realdata = newscale; + + for (i = 0, ttime = tstart; i < newlen; i++, ttime += tstep) + newscale[i] = ttime; + + for (v = vecs; v; v= v->v_link2) { + newdata = (double *) tmalloc(newlen * sizeof (double)); + + if (!ft_interpolate(v->v_realdata, newdata, + v->v_scale->v_realdata, v->v_scale->v_length, + newscale, newlen, 1)) { + fprintf(cp_err, + "Error: can't interpolate %s\n", v->v_name); + return(FALSE); + } + + tfree(v->v_realdata); + v->v_realdata = newdata; + + /* Why go to all this trouble if agraf ignores it? */ + nointerp = TRUE; + } + + vecs->v_scale = newv_scale; + + } + ft_agraf(xlims, ylims, vecs->v_scale, vecs->v_plot, vecs, + xdelta ? *xdelta : 0.0, ydelta ? *ydelta : 0.0, + ((gtype == GRID_XLOG) || (gtype == GRID_LOGLOG)), + ((gtype == GRID_YLOG) || (gtype == GRID_LOGLOG)), + nointerp); + return (TRUE); + } + + /* See if there is one type we can give for the y scale... */ + for (j = vecs->v_type, d = vecs->v_link2; d; d = d->v_link2) + if (d->v_type != j) { + j = SV_NOTYPE; + break; + } + + if (devname && eq(devname, "xgraph")) { + /* Interface to XGraph-11 Plot Program */ + ft_xgraph(xlims, ylims, hcopy, + title ? title : vecs->v_plot->pl_title, + xlabel ? xlabel : ft_typabbrev(vecs->v_scale->v_type), + ylabel ? ylabel : ft_typabbrev(j), + gtype, ptype, vecs); + return (TRUE); + } + for (d = vecs, i = 0; d; d = d->v_link2) + i++; + + /* Figure out the X name and the X type. This is sort of bad... */ + xn = vecs->v_scale->v_name; + xt = vecs->v_scale->v_type; + + pname = plot_cur->pl_typename; + + if (!gr_init(xlims, ylims, (oneval ? (char *) NULL : xn), + title ? title : vecs->v_plot->pl_title, hcopy, i, + xdelta ? *xdelta : 0.0, ydelta ? *ydelta : 0.0, gtype, + ptype, xlabel, ylabel, xt, j, pname, cline)) + return (FALSE); + + /* Now plot all the graphs. */ + for (d = vecs; d; d = d->v_link2) + ft_graf(d, oneval ? (struct dvec *) NULL : d->v_scale, FALSE); + + gr_clean(); + + return (TRUE); +} + +/* This routine gets parameters from the command line, which are of the + * form "name number ..." It returns a pointer to the parameter values. + */ + +static double * +getlims(wordlist *wl, char *name, int number) +{ + double *d, *td; + wordlist *beg, *wk; + char *ss; + int n; + + for (beg = wl; beg; beg = beg->wl_next) { + if (eq(beg->wl_word, name)) { + if (beg == wl) { + fprintf(cp_err, + "Syntax error: looking for plot parameters \"%s\".\n", + name); + return (NULL); + } + wk = beg; + if (number) { + d = (double *) tmalloc(sizeof (double) * + number); + for (n = 0; n < number; n++) { + wk = wk->wl_next; + if (!wk) { + fprintf(cp_err, + "Syntax error: not enough parameters for \"%s\".\n", + name); + return (NULL); + } + ss = wk->wl_word; + td = ft_numparse(&ss, FALSE); + if (td == NULL) + goto bad; + d[n] = *td; + } + } else + /* Minor hack... */ + d = (double *) 1; + + if (beg->wl_prev) + beg->wl_prev->wl_next = wk->wl_next; + if (wk->wl_next) { + wk->wl_next->wl_prev = beg->wl_prev; + wk->wl_next = NULL; + } + if (beg != wl_root) + wl_free(beg); + return (d); + } + } + return (NULL); +bad: + fprintf(cp_err, "Syntax error: bad parameters for \"%s\".\n", name); + return (NULL); +} + +/* Return a parameter of the form "xlabel foo" */ + +static char * +getword(wordlist *wl, char *name) +{ + wordlist *beg; + char *s; + + for (beg = wl; beg; beg = beg->wl_next) { + if (eq(beg->wl_word, name)) { + if ((beg == wl) || !beg->wl_next) { + fprintf(cp_err, + "Syntax error: looking for plot keyword at \"%s\".\n", + name); + return (NULL); + } + s = copy(beg->wl_next->wl_word); + beg->wl_prev->wl_next = beg->wl_next->wl_next; + if (beg->wl_next->wl_next) + beg->wl_next->wl_next->wl_prev = beg->wl_prev; + beg->wl_next->wl_next = NULL; + wl_free(beg); + return (s); + } + } + return (NULL); +} + +/* Check for and remove a one-word keyword. */ + +static bool +getflag(wordlist *wl, char *name) +{ + while (wl) { + if (eq(wl->wl_word, name)) { + if (wl->wl_prev) + wl->wl_prev->wl_next = wl->wl_next; + if (wl->wl_next) + wl->wl_next->wl_prev = wl->wl_prev; + return (TRUE); + } + wl = wl->wl_next; + } + return (FALSE); +} + +/* Extend a data vector to length by replicating the + * last element, or truncate it if it is too long. + */ + +static void +xtend(struct dvec *v, int length) +{ + int i; + complex c, *oc; + double d, *od; + + if (v->v_length == length) + return; + if (v->v_length > length) { + v->v_length = length; + return; + } + if (isreal(v)) { + od = v->v_realdata; + v->v_realdata = (double *) tmalloc(length * sizeof (double)); + for (i = 0; i < v->v_length; i++) + v->v_realdata[i] = od[i]; + d = od[--i]; + while (i < length) + v->v_realdata[i++] = d; + tfree(od); + } else { + oc = v->v_compdata; + v->v_compdata = (complex *) tmalloc(length * sizeof (complex)); + for (i = 0; i < v->v_length; i++) { + realpart(&v->v_compdata[i]) = realpart(&oc[i]); + imagpart(&v->v_compdata[i]) = imagpart(&oc[i]); + } + realpart(&c) = realpart(&oc[--i]); + imagpart(&c) = imagpart(&oc[i]); + while (i < length) { + realpart(&v->v_compdata[i]) = realpart(&c); + imagpart(&v->v_compdata[i++]) = imagpart(&c); + tfree(oc); + } + } + v->v_length = length; + return; +} + +/* Collapse every *xcomp elements into one, and use only the elements + * between xind[0] and xind[1]. + */ + +static void +compress(struct dvec *d, double *xcomp, double *xind) +{ + int cfac, ihi, ilo, newlen, i; + int sz = isreal(d) ? sizeof (double) : sizeof (complex); + double *dd; + complex *cc; + + if (xind) { + ilo = (int) xind[0]; + ihi = (int) xind[1]; + if ((ilo <= ihi) && (ilo > 0) && (ilo < d->v_length) && + (ihi > 1) && (ihi <= d->v_length)) { + newlen = ihi - ilo; + dd = (double *) tmalloc(newlen * sz); + cc = (complex *) dd; + if (isreal(d)) { + bcopy((char *) (d->v_realdata + ilo), + (char *) dd, newlen * sz); + tfree(d->v_realdata); + d->v_realdata = dd; + } else { + bcopy((char *) (d->v_compdata + ilo), + (char *) cc, newlen * sz); + tfree(d->v_compdata); + d->v_compdata = cc; + } + d->v_length = newlen; + } + } + + if (xcomp) { + cfac = (int) *xcomp; + if ((cfac > 1) && (cfac < d->v_length)) { + for (i = 0; i * cfac < d->v_length; i++) + if (isreal(d)) + d->v_realdata[i] = + d->v_realdata[i * cfac]; + else + d->v_compdata[i] = + d->v_compdata[i * cfac]; + d->v_length = i; + } + } + return; +} diff --git a/src/frontend/doplot.h b/src/frontend/doplot.h new file mode 100644 index 000000000..45b6950d0 --- /dev/null +++ b/src/frontend/doplot.h @@ -0,0 +1,15 @@ +/************* + * Header file for doplot.c + * 1999 E. Rouat + ************/ + +#ifndef DOPLOT_H_INCLUDED +#define DOPLOT_H_INCLUDED + +void com_asciiplot(wordlist *wl); +void com_xgraph(wordlist *wl); +void com_hardcopy(wordlist *wl); +void com_plot(wordlist *wl); + + +#endif diff --git a/src/frontend/dotcards.c b/src/frontend/dotcards.c new file mode 100644 index 000000000..9bc26e27e --- /dev/null +++ b/src/frontend/dotcards.c @@ -0,0 +1,614 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Spice-2 compatibility stuff for .plot, .print, .four, and .width. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteinp.h" +#include "dotcards.h" + + + +/* Extract all the .save lines */ + +static void fixdotplot(wordlist *wl); +static void fixdotprint(wordlist *wl); +static char * fixem(char *string); +static bool setcplot(char *name); +static wordlist * gettoks(char *s); + + +extern void com_save2 (wordlist *wl, char *name); + +void +ft_dotsaves(void) +{ + wordlist *iline, *wl = NULL; + char *s; + + if (!ft_curckt) /* Shouldn't happen. */ + return; + + for (iline = ft_curckt->ci_commands; iline; iline = iline->wl_next) { + if (ciprefix(".save", iline->wl_word)) { + s = iline->wl_word; + (void) gettok(&s); + wl = wl_append(wl, gettoks(s)); + } + } + + com_save(wl); + return; +} + +/* Go through the dot lines given and make up a big "save" command with + * all the node names mentioned. Note that if a node is requested for + * one analysis, it is saved for all of them. + */ + +static char *plot_opts[ ] = { + "linear", + "xlog", + "ylog", + "loglog" + }; + +int +ft_savedotargs(void) +{ + wordlist *w, *wl = NULL, *iline, **prev_wl, *w_next; + char *name; + char *s; + int some = 0; + static wordlist all = { "all", NULL }; + int isaplot; + int i; + + if (!ft_curckt) /* Shouldn't happen. */ + return 0; + + for (iline = ft_curckt->ci_commands; iline; iline = iline->wl_next) { + s = iline->wl_word; + if (ciprefix(".plot", s)) + isaplot = 1; + else + isaplot = 0; + + if (isaplot || ciprefix(".print", s)) { + (void) gettok(&s); + name = gettok(&s); + + if (!(w = gettoks(s))) { + fprintf(cp_err, "Warning: no nodes given: %s\n", + iline->wl_word); + } else { + if (isaplot) { + prev_wl = &w; + for (wl = w; wl; wl = w_next) { + w_next = wl->wl_next; + for (i = 0; i < NUMELEMS(plot_opts); i++) { + if (!strcmp(wl->wl_word, plot_opts[i])) { + /* skip it */ + *prev_wl = w_next; + tfree(wl); + break; + } + } + if (i == NUMELEMS(plot_opts)) + prev_wl = &wl->wl_next; + } + } + some = 1; + com_save2(w, name); + } + } else if (ciprefix(".four", s)) { + (void) gettok(&s); + (void) gettok(&s); + if (!(w = gettoks(s))) + fprintf(cp_err, "Warning: no nodes given: %s\n", + iline->wl_word); + else { + some = 1; + com_save2(w, "TRAN"); /* A hack */ + } + } else if (ciprefix(".op", s)) { + some = 1; + com_save2(&all, "OP"); + } else if (ciprefix(".tf", s)) { + some = 1; + com_save2(&all, "TF"); + } + } + + return some; +} + +/* Execute the .whatever lines found in the deck, after we are done running. + * We'll be cheap and use cp_lexer to get the words... This should make us + * spice-2 compatible. If terse is TRUE then there was a rawfile, so don't + * print lots of junk. + */ + +int +ft_cktcoms(bool terse) +{ + wordlist *coms, *command, all; + char *plottype, *s; + struct dvec *v; + static wordlist twl = { "col", NULL, NULL } ; + struct plot *pl; + int i, found; + + all.wl_next = NULL; + all.wl_word = "all"; + + if (!ft_curckt) + return 1; + if (!ft_curckt->ci_commands) + goto nocmds; + coms = ft_curckt->ci_commands; + cp_interactive = FALSE; + + /* Circuit name */ + fprintf(cp_out, "Circuit: %s\nDate: %s\n\n", ft_curckt->ci_name, + datestring()); + fprintf(cp_out, "\n"); + + /* Listing */ + if (ft_listprint) { + if (terse) + fprintf(cp_err, ".options: no listing, rawfile was generated.\n"); + else + inp_list(cp_out, ft_curckt->ci_deck, ft_curckt->ci_options, + LS_DECK); + } + + /* If there was a .op line, then we have to do the .op output. */ + if (setcplot("op")) { + if (terse) { + fprintf(cp_out, "OP information in rawfile.\n"); + } else { + fprintf(cp_out, "\nOperating point information:\n\n"); + fprintf(cp_out, "\tNode\tVoltage\n"); + fprintf(cp_out, "\t----\t-------\n"); + for (v = plot_cur->pl_dvecs; v; v = v->v_next) { + if (!isreal(v)) { + fprintf(cp_err, + "Internal error: op vector %s not real\n", + v->v_name); + continue; + } + if (v->v_type == SV_VOLTAGE) + fprintf(cp_out, "\t%s\t%s\n", v->v_name, + printnum(v->v_realdata[0])); + } + fprintf(cp_out, "\n\tSource\tCurrent\n"); + fprintf(cp_out, "\t------\t-------\n\n"); + for (v = plot_cur->pl_dvecs; v; v = v->v_next) + if (v->v_type == SV_CURRENT) + fprintf(cp_out, "\t%s\t%s\n", v->v_name, + printnum(v->v_realdata[0])); + fprintf(cp_out, "\n"); + + if (!ft_nomod) + com_showmod(&all); + com_show(&all); + } + } + + for (pl = plot_list; pl; pl = pl->pl_next) { + if (ciprefix("tf", pl->pl_typename)) { + if (terse) { + fprintf(cp_out, "TF information in rawfile.\n"); + break; + } + plot_cur = pl; + fprintf(cp_out, "Transfer function information:\n"); + com_print(&all); + fprintf(cp_out, "\n"); + } + } + + /* Now all the '.' lines */ + while (coms) { + command = cp_lexer(coms->wl_word); + if (!command) + goto bad; + if (eq(command->wl_word, ".width")) { + do { + command = command->wl_next; + } while (command && !ciprefix("out", command->wl_word)); + if (command) { + s =strchr(command->wl_word, '='); + if (!s || !s[1]) { + fprintf(cp_err, "Error: bad line %s\n", coms->wl_word); + coms = coms->wl_next; + continue; + } + i = atoi(++s); + cp_vset("width", VT_NUM, (char *) &i); + } + } else if (eq(command->wl_word, ".print")) { + if (terse) { + fprintf(cp_out, + ".print line ignored since rawfile was produced.\n"); + } else { + command = command->wl_next; + if (!command) { + fprintf(cp_err, "Error: bad line %s\n", coms->wl_word); + coms = coms->wl_next; + continue; + } + plottype = command->wl_word; + command = command->wl_next; + fixdotprint(command); + twl.wl_next = command; + found = 0; + for (pl = plot_list; pl; pl = pl->pl_next) { + if (ciprefix(plottype, pl->pl_typename)) { + plot_cur = pl; + com_print(&twl); + fprintf(cp_out, "\n"); + found = 1; + } + } + if (!found) + fprintf(cp_err, "Error: .print: no %s analysis found.\n", + plottype); + } + } else if (eq(command->wl_word, ".plot")) { + if (terse) { + fprintf(cp_out, + ".plot line ignored since rawfile was produced.\n"); + } else { + command = command->wl_next; + if (!command) { + fprintf(cp_err, "Error: bad line %s\n", + coms->wl_word); + coms = coms->wl_next; + continue; + } + plottype = command->wl_word; + command = command->wl_next; + fixdotplot(command); + found = 0; + for (pl = plot_list; pl; pl = pl->pl_next) { + if (ciprefix(plottype, pl->pl_typename)) { + plot_cur = pl; + com_asciiplot(command); + fprintf(cp_out, "\n"); + found = 1; + } + } + if (!found) + fprintf(cp_err, "Error: .plot: no %s analysis found.\n", + plottype); + } + } else if (ciprefix(".four", command->wl_word)) { + if (terse) { + fprintf(cp_out, + ".fourier line ignored since rawfile was produced.\n"); + } else if (setcplot("tran")) { + com_fourier(command->wl_next); + fprintf(cp_out, "\n\n"); + } else + fprintf(cp_err, + "No transient data available for fourier analysis"); + } else if (!eq(command->wl_word, ".save") + && !eq(command->wl_word, ".op") + && !eq(command->wl_word, ".tf")) + { + goto bad; + } + coms = coms->wl_next; + } + +nocmds: + /* Now the node table */ + if (ft_nodesprint) + ; + + /* The options */ + if (ft_optsprint) { + fprintf(cp_err, "Options:\n\n"); + cp_vprint(); + (void) putc('\n', cp_out); + } + + /* And finally the accounting info. */ + if (ft_acctprint) { + static wordlist ww = { "everything", NULL, NULL } ; + com_rusage(&ww); + } else + com_rusage((wordlist *) NULL); + + (void) putc('\n', cp_out); + return 0; + +bad: fprintf(cp_err, "Internal Error: ft_cktcoms: bad commands\n"); + return 1; +} + +/* These routines make sure that the arguments to .plot and .print in + * spice2 decks are acceptable to spice3. The things we look for are: + * trailing (a,b) in .plot -> xlimit a b + * vm(x) -> mag(v(x)) + * vp(x) -> ph(v(x)) + * v(x,0) -> v(x) + * v(0,x) -> -v(x) + */ + +static void +fixdotplot(wordlist *wl) +{ + char buf[BSIZE_SP], *s; + double *d, d1, d2; + + while (wl) { + wl->wl_word = fixem(wl->wl_word); + + /* Is this a trailing (a,b) ? Note that we require it to be + * one word. + */ + if (!wl->wl_next && (*wl->wl_word == '(')) /*)*/ { + s = wl->wl_word + 1; + d = ft_numparse(&s, FALSE); + if (*s != ',') { + fprintf(cp_err, "Error: bad limits \"%s\"\n", + wl->wl_word); + return; + } + d1 = *d; + s++; + d = ft_numparse(&s, FALSE); + if ((*s != /*(*/ ')') || s[1]) { + fprintf(cp_err, "Error: bad limits \"%s\"\n", + wl->wl_word); + return; + } + d2 = *d; + tfree(wl->wl_word); + wl->wl_word = copy("xlimit"); + wl->wl_next = alloc(struct wordlist); + wl->wl_next->wl_prev = wl; + wl = wl->wl_next; + (void) strcpy(buf, printnum(d1)); + wl->wl_word = copy(buf); + wl->wl_next = alloc(struct wordlist); + wl->wl_next->wl_prev = wl; + wl = wl->wl_next; + (void) strcpy(buf, printnum(d2)); + wl->wl_word = copy(buf); + } + wl = wl->wl_next; + } + return; +} + +static void +fixdotprint(wordlist *wl) +{ + while (wl) { + wl->wl_word = fixem(wl->wl_word); + wl = wl->wl_next; + } + return; +} + +static char * +fixem(char *string) +{ + char buf[BSIZE_SP], *s, *t, *ss = string; + + if (ciprefix("v(", string) &&strchr(string, ',')) { + for (s = string; *s && (*s != ','); s++) + ; + *s++ = '\0'; + for (t = s; *t && (*t != ')'); t++) + ; + *t = '\0'; + if (eq(s, "0")) + (void) sprintf(buf, "v(%s)", string + 2); + else if (eq(string + 2, "0")) + (void) sprintf(buf, "-v(%s)", s); + else + (void) sprintf(buf, "v(%s)-v(%s)", string + 2, s); + tfree(ss); + string = copy(buf); + } else if (ciprefix("vm(", string)) { + for (s = string; *s && (*s != ')'); s++) + ; + *s = '\0'; + (void) sprintf(buf, "mag(v(%s))", string + 3); + tfree(ss); + string = copy(buf); + } else if (ciprefix("vp(", string)) { + for (s = string; *s && (*s != ')'); s++) + ; + *s = '\0'; + (void) sprintf(buf, "ph(v(%s))", string + 3); + tfree(ss); + string = copy(buf); + } else if (ciprefix("vi(", string)) { + for (s = string; *s && (*s != ')'); s++) + ; + *s = '\0'; + (void) sprintf(buf, "imag(v(%s))", string + 3); + tfree(ss); + string = copy(buf); + } else if (ciprefix("vr(", string)) { + for (s = string; *s && (*s != ')'); s++) + ; + *s = '\0'; + (void) sprintf(buf, "real(v(%s))", string + 3); + tfree(ss); + string = copy(buf); + } else if (ciprefix("vdb(", string)) { + for (s = string; *s && (*s != ')'); s++) + ; + *s = '\0'; + (void) sprintf(buf, "db(v(%s))", string + 4); + tfree(ss); + string = copy(buf); + } else if (ciprefix("i(", string)) { + for (s = string; *s && (*s != ')'); s++) + ; + *s = '\0'; + string += 2; + (void) sprintf(buf, "%s#branch", string); + tfree(ss); + string = copy(buf); + } + return (string); +} + +/* Don't bother with ccom strangeness here. */ + +static bool +setcplot(char *name) +{ + struct plot *pl; + + for (pl = plot_list; pl; pl = pl->pl_next) { + if (ciprefix(name, pl->pl_typename)) { + plot_cur = pl; + return (TRUE); + } + } + return (FALSE); +} + +#ifdef notdef +static wordlist * +gettoks(s) + char *s; +{ + char *t, *r, buf[64]; + wordlist *wl = NULL, *end = NULL; + bool iflag; + + while (t = gettok(&s)) { + if (*t == '(' /* ) */) { + /* This is a (upper, lower) thing -- ignore. */ + continue; + } else if (!index(t, '(' /*)*/ )) { + if (end) { + end->wl_next = alloc(struct wordlist); + end->wl_next->wl_prev = end; + end = end->wl_next; + } else + wl = end = alloc(struct wordlist); + end->wl_word = copy(t); + } else if (!index(t, ',')) { + iflag = ((*t == 'i') || (*t == 'I')) ? TRUE : FALSE; + while (*t != '(' /*)*/) + t++; + t++; + for (r = t; *r && *r != /*(*/ ')'; r++) + ; + *r = '\0'; + if (end) { + end->wl_next = alloc(struct wordlist); + end->wl_next->wl_prev = end; + end = end->wl_next; + } else + wl = end = alloc(struct wordlist); + if (iflag) { + (void) sprintf(buf, "%s#branch", t); + t = buf; + } + end->wl_word = copy(t); + } else { + /* The painful case */ + while (*t != '(' /*)*/) + t++; + t++; + for (r = t; *r && *r != ','; r++) + ; + *r = '\0'; + if (end) { + end->wl_next = alloc(struct wordlist); + end->wl_next->wl_prev = end; + end = end->wl_next; + } else + wl = end = alloc(struct wordlist); + end->wl_word = copy(t); + t = r + 1; + for (r = t; *r && *r != /*(*/ ')'; r++) + ; + *r = '\0'; + if (end) { + end->wl_next = alloc(struct wordlist); + end->wl_next->wl_prev = end; + end = end->wl_next; + } else + wl = end = alloc(struct wordlist); + end->wl_word = copy(t); + } + } + return (wl); +} +#endif + +static wordlist * +gettoks(char *s) +{ + char *t; + char *l, *r, *c; /* left, right, center/comma */ + wordlist *wl, *list, **prevp; + + + list = NULL; + prevp = &list; + + while ((t = gettok(&s))) { + if (*t == '(') + continue; + l =strrchr(t, '('/*)*/); + if (!l) { + wl = alloc(struct wordlist); + wl->wl_word = copy(t); + *prevp = wl; + prevp = &wl->wl_next; + continue; + } + + r =strchr(t, /*(*/')'); + + c =strchr(t, ','); + if (!c) + c = r; + + if (c) + *c = 0; + + wl = alloc(struct wordlist); + + if (*(l - 1) == 'i' || *(l - 1) == 'I') { + char buf[513]; + sprintf(buf, "%s#branch", l + 1); + wl->wl_word = copy(buf); + c = r = NULL; + } else + wl->wl_word = copy(l + 1); + + *prevp = wl; + prevp = &wl->wl_next; + + if (c != r) { + *r = 0; + wl = alloc(struct wordlist); + wl->wl_word = copy(c + 1); + *prevp = wl; + prevp = &wl->wl_next; + } + } + return list; +} diff --git a/src/frontend/dotcards.h b/src/frontend/dotcards.h new file mode 100644 index 000000000..337b2c014 --- /dev/null +++ b/src/frontend/dotcards.h @@ -0,0 +1,14 @@ +/************* + * Header file for dotcards.c + * 1999 E. Rouat + ************/ + +#ifndef DOTCARDS_H_INCLUDED +#define DOTCARDS_H_INCLUDED + +void ft_dotsaves(void); +int ft_savedotargs(void); +int ft_cktcoms(bool terse); + + +#endif diff --git a/src/frontend/error.c b/src/frontend/error.c new file mode 100644 index 000000000..f59039a24 --- /dev/null +++ b/src/frontend/error.c @@ -0,0 +1,70 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Print out in more detail what a floating point error was. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include +#include "error.h" + + +/* global error message buffer */ +char ErrorMessage[1024]; + + + +void +fperror(char *mess, int code) +{ + fprintf(cp_err, "%s: floating point exception.\n", mess); + return; +} + + + +/* Print a spice error message. */ + +void +ft_sperror(int code, char *mess) +{ + fprintf(cp_err, "%s: %s\n", mess, if_errstring(code)); + return; +} + +void +fatal(void) +{ + cp_ccon(FALSE); +#ifdef FTEDEBUG +#ifdef SIGQUIT + (void) signal(SIGQUIT, SIG_DFL); + (void) kill(getpid(), SIGQUIT); +#endif +#endif + exit(EXIT_BAD); +} + +/* These error messages are from internal consistency checks. */ +void +internalerror(char *message) +{ + + fprintf(stderr, "internal error: %s\n", message); + +} + +/* These errors are from external routines like fopen. */ +void +externalerror(char *message) +{ + + fprintf(stderr, "external error: %s\n", message); + +} diff --git a/src/frontend/error.h b/src/frontend/error.h new file mode 100644 index 000000000..3105cc41b --- /dev/null +++ b/src/frontend/error.h @@ -0,0 +1,17 @@ +/************* + * Header file for error.c + * 1999 E. Rouat + ************/ + +#ifndef ERROR_H_INCLUDED +#define ERROR_H_INCLUDED + +void fperror(char *mess, int code); +void ft_sperror(int code, char *mess); +void fatal(void); +void internalerror(char *message); + + + + +#endif diff --git a/src/frontend/evaluate.c b/src/frontend/evaluate.c new file mode 100644 index 000000000..92189e32f --- /dev/null +++ b/src/frontend/evaluate.c @@ -0,0 +1,800 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Convert a parse tree to a list of data vectors. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "ftecmath.h" +#include +#include +#include "evaluate.h" + + +/* static declarations */ +static RETSIGTYPE sig_matherr(void); +static struct dvec * apply_func(struct func *func, struct pnode *arg); +static char * mkcname(char what, char *v1, char *v2); +static struct dvec * doop(char what, void *(*func) (/* ??? */), + struct pnode *arg1, struct pnode *arg2); + + + +/* We are careful here to catch SIGILL and recognise them as math errors. + * The only trouble is that the (void) signal handler we installed before will + * be lost, but that's no great loss. + */ + +static jmp_buf matherrbuf; + +static RETSIGTYPE +sig_matherr(void) +{ + fprintf(cp_err, "Error: argument out of range for math function\n"); + longjmp(matherrbuf, 1); +} + + +/* Note that ft_evaluate will return NULL on invalid expressions. */ + +struct dvec * +ft_evaluate(struct pnode *node) +{ + struct dvec *d; + + if (!node) + return (NULL); + else if (node->pn_value) + d = node->pn_value; + else if (node->pn_func) + d = apply_func(node->pn_func, node->pn_left); + else if (node->pn_op) { + if (node->pn_op->op_arity == 1) + d = (struct dvec *) + ((*node->pn_op->op_func) (node->pn_left)); + else if (node->pn_op->op_arity == 2) + d = (struct dvec *) ((*node->pn_op->op_func) + (node->pn_left, node->pn_right)); + } else { + fprintf(cp_err, "ft_evaluate: Internal Error: bad node\n"); + return (NULL); + } + + if (!d) { + return NULL; + } + + if (node->pn_name && !ft_evdb && d && !d->v_link2) + d->v_name = copy(node->pn_name); + + if (!d->v_length) { + fprintf(cp_err, "Error: no such vector %s\n", d->v_name); + return (NULL); + } else + return (d); +} + +/* The binary operations. */ + +struct dvec * +op_plus(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('+', cx_plus, arg1, arg2)); +} + +struct dvec * +op_minus(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('-', cx_minus, arg1, arg2)); +} + +struct dvec * +op_comma(struct pnode *arg1, struct pnode *arg2) +{ + return (doop(',', cx_comma, arg1, arg2)); +} + +struct dvec * +op_times(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('*', cx_times, arg1, arg2)); +} + +struct dvec * +op_mod(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('%', cx_mod, arg1, arg2)); +} + +struct dvec * +op_divide(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('/', cx_divide, arg1, arg2)); +} + +struct dvec * +op_power(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('^', cx_power, arg1, arg2)); +} + +struct dvec * +op_eq(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('=', cx_eq, arg1, arg2)); +} + +struct dvec * +op_gt(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('>', cx_gt, arg1, arg2)); +} + +struct dvec * +op_lt(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('<', cx_lt, arg1, arg2)); +} + +struct dvec * +op_ge(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('G', cx_ge, arg1, arg2)); +} + +struct dvec * +op_le(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('L', cx_le, arg1, arg2)); +} + +struct dvec * +op_ne(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('N', cx_ne, arg1, arg2)); +} + +struct dvec * +op_and(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('&', cx_and, arg1, arg2)); +} + +struct dvec * +op_or(struct pnode *arg1, struct pnode *arg2) +{ + return (doop('|', cx_or, arg1, arg2)); +} + +/* This is an odd operation. The first argument is the name of a vector, and + * the second is a range in the scale, so that v(1)[[10, 20]] gives all the + * values of v(1) for which the TIME value is between 10 and 20. If there is + * one argument it picks out the values which have that scale value. + * NOTE that we totally ignore multi-dimensionality here -- the result is + * a 1-dim vector. + */ + +struct dvec * +op_range(struct pnode *arg1, struct pnode *arg2) +{ + struct dvec *v, *ind, *res, *scale; /* , *nscale; */ + double up, low, td; + int len, i, j; + bool rev = FALSE; + + v = ft_evaluate(arg1); + ind = ft_evaluate(arg2); + if (!v || !ind) + return (NULL); + scale = v->v_scale; + if (!scale) + scale = v->v_plot->pl_scale; + if (!scale) { + fprintf(cp_err, "Error: no scale for vector %s\n", v->v_name); + return (NULL); + } + + if (ind->v_length != 1) { + fprintf(cp_err, "Error: strange range specification\n"); + return (NULL); + } + if (isreal(ind)) { + up = low = *ind->v_realdata; + } else { + up = imagpart(ind->v_compdata); + low = realpart(ind->v_compdata); + } + if (up < low) { + td = up; + up = low; + low = td; + rev = TRUE; + } + for (i = len = 0; i < scale->v_length; i++) { + td = isreal(scale) ? scale->v_realdata[i] : + realpart(&scale->v_compdata[i]); + if ((td <= up) && (td >= low)) + len++; + } + + res = alloc(struct dvec); + ZERO(res,struct dvec); + res->v_name = mkcname('R', v->v_name, ind->v_name); + res->v_type = v->v_type; + res->v_flags = v->v_flags; + + res->v_gridtype = v->v_gridtype; + res->v_plottype = v->v_plottype; + res->v_defcolor = v->v_defcolor; + res->v_length = len; + res->v_scale = /* nscale; */ scale; + /* Dave says get rid of this + res->v_numdims = v->v_numdims; + for (i = 0; i < v->v_numdims; i++) + res->v_dims[i] = v->v_dims[i]; + */ + res->v_numdims = 1; + res->v_dims[0] = len; + + if (isreal(res)) + res->v_realdata = (double *) tmalloc(sizeof (double) * len); + else + res->v_compdata = (complex *) tmalloc(sizeof (complex) * len); + + /* Toss in the data */ + + j = 0; + for (i = (rev ? v->v_length - 1 : 0); i != (rev ? -1 : v->v_length); + rev ? i-- : i++) { + td = isreal(scale) ? scale->v_realdata[i] : + realpart(&scale->v_compdata[i]); + if ((td <= up) && (td >= low)) { + if (isreal(res)) { + res->v_realdata[j] = v->v_realdata[i]; + } else { + realpart(&res->v_compdata[j]) = + realpart(&v->v_compdata[i]); + imagpart(&res->v_compdata[j]) = + imagpart(&v->v_compdata[i]); + } + j++; + } + } + if (j != len) + fprintf(cp_err, "Error: something funny..\n"); + + /* Note that we DON'T do a vec_new, since we want this vector to be + * invisible to everybody except the result of this operation. + * Doing this will cause a lot of core leaks, though. XXX + */ + + vec_new(res); + return (res); +} + +/* This is another operation we do specially -- if the argument is a vector of + * dimension n, n > 0, the result will be either a vector of dimension n - 1, + * or a vector of dimension n with only a certain range of vectors present. + */ + +struct dvec * +op_ind(struct pnode *arg1, struct pnode *arg2) +{ + struct dvec *v, *ind, *res; + int length, newdim, i, j, k, up, down; + int majsize, blocksize; + bool rev = FALSE; + + v = ft_evaluate(arg1); + ind = ft_evaluate(arg2); + if (!v || !ind) + return (NULL); + + /* First let's check to make sure that the vector is consistent */ + if (v->v_numdims > 1) { + for (i = 0, j = 1; i < v->v_numdims; i++) + j *= v->v_dims[i]; + if (v->v_length != j) { + fprintf(cp_err, + "op_ind: Internal Error: len %d should be %d\n", + v->v_length, j); + return (NULL); + } + } else { + /* Just in case we were sloppy */ + v->v_numdims = 1; + v->v_dims[0] = v->v_length; + if (v->v_length <= 1) { + fprintf(cp_err, "Error: nostrchring on a scalar (%s)\n", + v->v_name); + return (NULL); + } + } + + if (ind->v_length != 1) { + fprintf(cp_err, "Error:strchr %s is not of length 1\n", + ind->v_name); + return (NULL); + } + + majsize = v->v_dims[0]; + blocksize = v->v_length / majsize; + + /* Now figure out if we should put the dim down by one. Because of the + * way we parse thestrchr, we figure that if the value is complex + * (e.g, "[1,2]"), the guy meant a range. This is sort of bad though. + */ + if (isreal(ind)) { + newdim = v->v_numdims - 1; + down = up = ind->v_realdata[0]; + } else { + newdim = v->v_numdims; + down = realpart(&ind->v_compdata[0]); + up = imagpart(&ind->v_compdata[0]); + } + if (up < down) { + i = up; + up = down; + down = i; + rev = TRUE; + } + if (up < 0) { + fprintf(cp_err, "Warning: upper limit %d should be 0\n", up); + up = 0; + } + if (up >= majsize) { + fprintf(cp_err, "Warning: upper limit %d should be %d\n", up, + majsize - 1); + up = majsize - 1; + } + if (down < 0) { + fprintf(cp_err, "Warning: lower limit %d should be 0\n", down); + down = 0; + } + if (down >= majsize) { + fprintf(cp_err, "Warning: lower limit %d should be %d\n", down, + majsize - 1); + down = majsize - 1; + } + + if (up == down) + length = blocksize; + else + length = blocksize * (up - down + 1); + + /* Make up the new vector. */ + res = alloc(struct dvec); + ZERO(res,struct dvec); + res->v_name = mkcname('[', v->v_name, ind->v_name); + res->v_type = v->v_type; + res->v_flags = v->v_flags; + + res->v_defcolor = v->v_defcolor; + res->v_gridtype = v->v_gridtype; + res->v_plottype = v->v_plottype; + res->v_length = length; + res->v_numdims = newdim; + if (up != down) { + for (i = 0; i < newdim; i++) + res->v_dims[i] = v->v_dims[i]; + res->v_dims[0] = up - down + 1; + } else { + for (i = 0; i < newdim; i++) + res->v_dims[i] = v->v_dims[i + 1]; + } + + if (isreal(res)) + res->v_realdata = (double *) tmalloc(sizeof (double) * length); + else + res->v_compdata = (complex *) tmalloc(sizeof (complex) * length); + + /* And toss in the new data */ + for (j = 0; j < up - down + 1; j++) { + if (rev) + k = (up - down) - j; + else + k = j; + for (i = 0; i < blocksize; i++) + if (isreal(res)) + res->v_realdata[k * blocksize + i] = + v->v_realdata[(down + j) * blocksize + i]; + else { + realpart(&res->v_compdata[k * blocksize + i]) = + realpart(&v->v_compdata[(down + j) * blocksize + i]); + imagpart(&res->v_compdata[k * blocksize + i]) = + imagpart(&v->v_compdata[(down + j) * blocksize + i]); + } + } + + /* This is a problem -- the old scale will be no good. I guess we + * should make an altered copy of the old scale also. + */ + /* Even though the old scale is no good and we should somehow decide + * on a new scale, using the vector as its own scale is not the + * solution. + */ + /* + * res->v_scale = res; + */ + + vec_new(res); + return (res); +} + +/* Apply a function to an argument. Complex functions are called as follows: + * cx_something(data, type, length, &newlength, &newtype), + * and returns a char * that is cast to complex or double. + */ + +static struct dvec * +apply_func(struct func *func, struct pnode *arg) +{ + struct dvec *v, *t, *newv = NULL, *end = NULL; + int len, i; + short type; + char *data, buf[BSIZE_SP]; + + /* Special case. This is not good -- happens when vm(), etc are used + * and it gets caught as a user-definable function. Usually v() + * is caught in the parser. + */ + if (!func->fu_func) { + if (!arg->pn_value /* || (arg->pn_value->v_length != 1) XXX */) { + fprintf(cp_err, "Error: bad v() syntax\n"); + return (NULL); + } + (void) sprintf(buf, "v(%s)", arg->pn_value->v_name); + t = vec_fromplot(buf, plot_cur); + if (!t) { + fprintf(cp_err, "Error: no such vector %s\n", buf); + return (NULL); + } + t = vec_copy(t); + vec_new(t); + return (t); + } + v = ft_evaluate(arg); + if (v == NULL) + return (NULL); + + + for (; v; v = v->v_link2) { + + /* Some of the math routines generate SIGILL if the argument is + * out of range. Catch this here. + */ + if (setjmp(matherrbuf)) { + (void) signal(SIGILL, SIG_DFL); + return (NULL); + } + (void) signal(SIGILL, (SIGNAL_FUNCTION) sig_matherr); + + if (eq(func->fu_name, "interpolate") + || eq(func->fu_name, "deriv")) /* Ack */ + { + data = ((*func->fu_func) ((isreal(v) ? + (void *) v->v_realdata : + (void *) v->v_compdata), + (short) (isreal(v) ? VF_REAL : + VF_COMPLEX), + v->v_length, &len, &type, + v->v_plot, plot_cur, v->v_dims[0])); + } else { + data = ((*func->fu_func) ((isreal(v) ? (void *) + v->v_realdata : + (void *) v->v_compdata), + (short) (isreal(v) ? VF_REAL : + VF_COMPLEX), + v->v_length, &len, &type)); + } + /* Back to normal */ + (void) signal(SIGILL, SIG_DFL); + + if (!data) + return (NULL); + + t = alloc(struct dvec); + ZERO(t,struct dvec); + + t->v_flags = (v->v_flags & ~VF_COMPLEX & ~VF_REAL & + ~VF_PERMANENT & ~VF_MINGIVEN & ~VF_MAXGIVEN); + t->v_flags |= type; +#ifdef FTEDEBUG + if (ft_evdb) + fprintf(cp_err, + "apply_func: func %s to %s len %d, type %d\n", + func->fu_name, v->v_name, len, type); +#endif + if (isreal(t)) + t->v_realdata = (double *) data; + else + t->v_compdata = (complex *) data; + if (eq(func->fu_name, "minus")) + t->v_name = mkcname('a', func->fu_name, v->v_name); + else if (eq(func->fu_name, "not")) + t->v_name = mkcname('c', func->fu_name, v->v_name); + else + t->v_name = mkcname('b', v->v_name, (char *) NULL); + t->v_type = v->v_type; /* This is strange too. */ + t->v_length = len; + t->v_scale = v->v_scale; + + /* Copy a few useful things */ + t->v_defcolor = v->v_defcolor; + t->v_gridtype = v->v_gridtype; + t->v_plottype = v->v_plottype; + t->v_numdims = v->v_numdims; + for (i = 0; i < t->v_numdims; i++) + t->v_dims[i] = v->v_dims[i]; + + vec_new(t); + + if (end) + end->v_link2 = t; + else + newv = t; + end = t; + } + + return (newv); +} + +/* The unary minus operation. */ + +struct dvec * +op_uminus(struct pnode *arg) +{ + return (apply_func(&func_uminus, arg)); +} + +struct dvec * +op_not(struct pnode *arg) +{ + return (apply_func(&func_not, arg)); +} + +/* Create a reasonable name for the result of a function application, etc. + * The what values 'a' and 'b' mean "make a function name" and "make a + * unary minus", respectively. + */ + +static char * +mkcname(char what, char *v1, char *v2) +{ + char buf[BSIZE_SP], *s; + + if (what == 'a') + (void) sprintf(buf, "%s(%s)", v1, v2); + else if (what == 'b') + (void) sprintf(buf, "-(%s)", v1); + else if (what == 'c') + (void) sprintf(buf, "~(%s)", v1); + else if (what == '[') + (void) sprintf(buf, "%s[%s]", v1, v2); + else if (what == 'R') + (void) sprintf(buf, "%s[[%s]]", v1, v2); + else + (void) sprintf(buf, "(%s)%c(%s)", v1, what, v2); + s = copy(buf); + return (s); +} + +/* Operate on two vectors, and return a third with the data, length, and flags + * fields filled in. Add it to the current plot and get rid of the two args. + */ + +static struct dvec * +doop(char what, void*(*func) (/* ??? */), struct pnode *arg1, + struct pnode *arg2) +{ + struct dvec *v1, *v2, *res; + complex *c1, *c2, lc; + double *d1, *d2, ld; + int length, i; + void *data; + bool free1 = FALSE, free2 = FALSE, relflag = FALSE; + + v1 = ft_evaluate(arg1); + v2 = ft_evaluate(arg2); + if (!v1 || !v2) + return (NULL); + + /* Now the question is, what do we do when one or both of these + * has more than one vector? This is definitely not a good + * thing. For the time being don't do anything. + */ + if (v1->v_link2 || v2->v_link2) { + fprintf(cp_err, "Warning: no operations on wildcards yet.\n"); + if (v1->v_link2 && v2->v_link2) + fprintf(cp_err, "\t(You couldn't do that one anyway)\n"); + return (NULL); + } + + /* How do we handle operations on multi-dimensional vectors? + * For now, we only allow operations between one-D vectors, + * equivalently shaped multi-D vectors, or a multi-D vector and + * a one-D vector. It's not at all clear what to do in the other cases. + * So only check shape requirement if its an operation between two multi-D + * arrays. + */ + if ((v1->v_numdims > 1) && (v2->v_numdims > 1)) { + if (v1->v_numdims != v2->v_numdims) { + fprintf(cp_err, + "Warning: operands %s and %s have incompatible shapes.\n", + v1->v_name, v2->v_name); + return (NULL); + } + for (i = 1; i < v1->v_numdims; i++) { + if ((v1->v_dims[i] != v2->v_dims[i])) { + fprintf(cp_err, + "Warning: operands %s and %s have incompatible shapes.\n", + v1->v_name, v2->v_name); + return (NULL); + } + } + } + + /* This is a bad way to do this. */ + switch (what) { + case '=': + case '>': + case '<': + case 'G': + case 'L': + case 'N': + case '&': + case '|': + case '~': + relflag = TRUE; + } + + /* Don't bother to do type checking. Maybe this should go in at + * some point. + */ + + /* Make sure we have data of the same length. */ + length = ((v1->v_length > v2->v_length) ? v1->v_length : v2->v_length); + if (v1->v_length < length) { + free1 = TRUE; + if (isreal(v1)) { + ld = 0.0; + d1 = (double *) tmalloc(length * sizeof (double)); + for (i = 0; i < v1->v_length; i++) + d1[i] = v1->v_realdata[i]; + if (length > 0) + ld = v1->v_realdata[v1->v_length - 1]; + for ( ; i < length; i++) + d1[i] = ld; + } else { + realpart(&lc) = 0.0; + imagpart(&lc) = 0.0; + c1 = (complex *) tmalloc(length * sizeof (complex)); + for (i = 0; i < v1->v_length; i++) + c1[i] = v1->v_compdata[i]; + if (length > 0) + lc = v1->v_compdata[v1->v_length - 1]; + for ( ; i < length; i++) + c1[i] = lc; + } + } else + if (isreal(v1)) + d1 = v1->v_realdata; + else + c1 = v1->v_compdata; + if (v2->v_length < length) { + free2 = TRUE; + if (isreal(v2)) { + ld = 0.0; + d2 = (double *) tmalloc(length * sizeof (double)); + for (i = 0; i < v2->v_length; i++) + d2[i] = v2->v_realdata[i]; + if (length > 0) + ld = v2->v_realdata[v2->v_length - 1]; + for ( ; i < length; i++) + d2[i] = ld; + } else { + realpart(&lc) = 0.0; + imagpart(&lc) = 0.0; + c2 = (complex *) tmalloc(length * sizeof (complex)); + for (i = 0; i < v2->v_length; i++) + c2[i] = v2->v_compdata[i]; + if (length > 0) + lc = v2->v_compdata[v1->v_length - 1]; + for ( ; i < length; i++) + c2[i] = lc; + } + } else + if (isreal(v2)) + d2 = v2->v_realdata; + else + c2 = v2->v_compdata; + + /* Some of the math routines generate SIGILL if the argument is + * out of range. Catch this here. + */ + if (setjmp(matherrbuf)) { + return (NULL); + } + (void) signal(SIGILL, (SIGNAL_FUNCTION) sig_matherr); + + /* Now pass the vectors to the appropriate function. */ + data = ((*func) ((isreal(v1) ? (void *) d1 : (void *) c1), + (isreal(v2) ? (void *) d2 : (void *) c2), + (isreal(v1) ? VF_REAL : VF_COMPLEX), + (isreal(v2) ? VF_REAL : VF_COMPLEX), + length)); + /* Back to normal */ + (void) signal(SIGILL, SIG_DFL); + + if (!data) + return (NULL); + /* Make up the new vector. */ + res = alloc(struct dvec); + ZERO(res,struct dvec); + if (relflag || (isreal(v1) && isreal(v2) && (func != cx_comma))) { + res->v_flags = (v1->v_flags | v2->v_flags | + VF_REAL) & ~ VF_COMPLEX; + res->v_realdata = (double *) data; + } else { + res->v_flags = (v1->v_flags | v2->v_flags | + VF_COMPLEX) & ~ VF_REAL; + res->v_compdata = (complex *) data; + } + + res->v_name = mkcname(what, v1->v_name, v2->v_name); + res->v_length = length; + + /* This is a non-obvious thing */ + if (v1->v_scale != v2->v_scale) { + fprintf(cp_err, "Warning: scales of %s and %s are different.\n", + v1->v_name, v2->v_name); + res->v_scale = NULL; + } else + res->v_scale = v1->v_scale; + + /* Copy a few useful things */ + res->v_defcolor = v1->v_defcolor; + res->v_gridtype = v1->v_gridtype; + res->v_plottype = v1->v_plottype; + + /* Copy dimensions. */ + if (v1->v_numdims > v2->v_numdims) { + res->v_numdims = v1->v_numdims; + for (i = 0; i < v1->v_numdims; i++) + res->v_dims[i] = v1->v_dims[i]; + } else { + res->v_numdims = v2->v_numdims; + for (i = 0; i < v2->v_numdims; i++) + res->v_dims[i] = v2->v_dims[i]; + } + + /* This depends somewhat on what the operation is. XXX Should fix */ + res->v_type = v1->v_type; + vec_new(res); + + /* Free the temporary data areas we used, if we allocated any. */ + if (free1) { + if (isreal(v1)) { + tfree(d1); + } else { + tfree(c1); + } + } + if (free2) { + if (isreal(v2)) { + tfree(d2); + } else { + tfree(c2); + } + } + + return (res); +} + diff --git a/src/frontend/evaluate.h b/src/frontend/evaluate.h new file mode 100644 index 000000000..155805142 --- /dev/null +++ b/src/frontend/evaluate.h @@ -0,0 +1,31 @@ +/************* + * Header file for evaluate.c + * 1999 E. Rouat + ************/ + +#ifndef EVALUATE_H_INCLUDED +#define EVALUATE_H_INCLUDED + +struct dvec * ft_evaluate(struct pnode *node); +struct dvec * op_plus(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_minus(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_comma(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_times(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_mod(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_divide(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_power(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_eq(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_gt(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_lt(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_ge(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_le(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_ne(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_and(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_or(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_range(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_ind(struct pnode *arg1, struct pnode *arg2); +struct dvec * op_uminus(struct pnode *arg); +struct dvec * op_not(struct pnode *arg); + + +#endif diff --git a/src/frontend/fourier.c b/src/frontend/fourier.c new file mode 100644 index 000000000..e68f3dde0 --- /dev/null +++ b/src/frontend/fourier.c @@ -0,0 +1,383 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Code to do fourier transforms on data. Note that we do interpolation + * to get a uniform grid. Note that if polydegree is 0 then no interpolation + * is done. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "sperror.h" +#include "const.h" +#include "fourier.h" + + +/* static declarations */ +static char * pn(double num); +static int CKTfour(int ndata, int numFreq, double *thd, double *Time, double *Value, + double FundFreq, double *Freq, double *Mag, double *Phase, double *nMag, + double *nPhase); + + + +#define DEF_FOURGRIDSIZE 200 + +/* CKTfour(ndata,numFreq,thd,Time,Value,FundFreq,Freq,Mag,Phase,nMag,nPhase) + * len 10 ? inp inp inp out out out out out + */ + +void +com_fourier(wordlist *wl) +{ + struct dvec *time, *vec; + struct pnode *names, *first_name; + double *ff, fundfreq, *dp, *stuff; + int nfreqs, fourgridsize, polydegree; + double *freq, *mag, *phase, *nmag, *nphase; /* Outputs from CKTfour */ + double thd, *timescale, *grid, d; + char *s; + int i, err, fw; + char xbuf[20]; + int shift; + + sprintf(xbuf, "%1.1e", 0.0); + shift = strlen(xbuf) - 7; + if (!plot_cur || !plot_cur->pl_scale) { + fprintf(cp_err, "Error: no vectors loaded.\n"); + return; + } + + if ((!cp_getvar("nfreqs", VT_NUM, (char *) &nfreqs)) || (nfreqs < 1)) + nfreqs = 10; + if ((!cp_getvar("polydegree", VT_NUM, (char *) &polydegree)) || + (polydegree < 0)) + polydegree = 1; + if ((!cp_getvar("fourgridsize", VT_NUM, (char *) &fourgridsize)) || + (fourgridsize < 1)) + fourgridsize = DEF_FOURGRIDSIZE; + + time = plot_cur->pl_scale; + if (!isreal(time)) { + fprintf(cp_err, "Error: fourier needs real time scale\n"); + return; + } + s = wl->wl_word; + if (!(ff = ft_numparse(&s, FALSE)) || (*ff <= 0.0)) { + fprintf(cp_err, "Error: bad fund freq %s\n", wl->wl_word); + return; + } + fundfreq = *ff; + + freq = (double *) tmalloc(nfreqs * sizeof (double)); + mag = (double *) tmalloc(nfreqs * sizeof (double)); + phase = (double *) tmalloc(nfreqs * sizeof (double)); + nmag = (double *) tmalloc(nfreqs * sizeof (double)); + nphase = (double *) tmalloc(nfreqs * sizeof (double)); + + wl = wl->wl_next; + names = ft_getpnames(wl, TRUE); + first_name = names; + while (names) { + vec = ft_evaluate(names); + names = names->pn_next; + while (vec) { + if (vec->v_length != time->v_length) { + fprintf(cp_err, + "Error: lengths don't match: %d, %d\n", + vec->v_length, time->v_length); + continue; + } + if (!isreal(vec)) { + fprintf(cp_err, "Error: %s isn't real!\n", + vec->v_name); + continue; + } + + if (polydegree) { + /* Build the grid... */ + grid = (double *) tmalloc(fourgridsize * + sizeof (double)); + stuff = (double *) tmalloc(fourgridsize * + sizeof (double)); + dp = ft_minmax(time, TRUE); + + /* Now get the last fund freq... */ + d = 1 / fundfreq; /* The wavelength... */ + if (dp[1] - dp[0] < d) { + fprintf(cp_err, + "Error: wavelength longer than time span\n"); + return; + } else if (dp[1] - dp[0] > d) { + dp[0] = dp[1] - d; + } + + d = (dp[1] - dp[0]) / fourgridsize; + for (i = 0; i < fourgridsize; i++) + grid[i] = dp[0] + i * d; + + /* Now interpolate the stuff... */ + if (!ft_interpolate(vec->v_realdata, stuff, + time->v_realdata, vec->v_length, + grid, fourgridsize, + polydegree)) { + fprintf(cp_err, + "Error: can't interpolate\n"); + return; + } + timescale = grid; + } else { + fourgridsize = vec->v_length; + stuff = vec->v_realdata; + timescale = time->v_realdata; + } + + err = CKTfour(fourgridsize, nfreqs, &thd, timescale, + stuff, fundfreq, freq, mag, phase, nmag, + nphase); + if (err != OK) { + ft_sperror(err, "fourier"); + return; + } + + fprintf(cp_out, "Fourier analysis for %s:\n", + vec->v_name); + fprintf(cp_out, +" No. Harmonics: %d, THD: %g %%, Gridsize: %d, Interpolation Degree: %d\n\n", + nfreqs, thd, fourgridsize, + polydegree); + /* Each field will have width cp_numdgt + 6 (or 7 + * with HP-UX) + 1 if there is a - sign. + */ + fw = ((cp_numdgt > 0) ? cp_numdgt : 6) + 5 + shift; + fprintf(cp_out, "Harmonic %-*s %-*s %-*s %-*s %-*s\n", + fw, "Frequency", fw, "Magnitude", + fw, "Phase", fw, "Norm. Mag", + fw, "Norm. Phase"); + fprintf(cp_out, "-------- %-*s %-*s %-*s %-*s %-*s\n", + fw, "---------", fw, "---------", + fw, "-----", fw, "---------", + fw, "-----------"); + for (i = 0; i < nfreqs; i++) + fprintf(cp_out, + " %-4d %-*s %-*s %-*s %-*s %-*s\n", + i, + fw, pn(freq[i]), + fw, pn(mag[i]), + fw, pn(phase[i]), + fw, pn(nmag[i]), + fw, pn(nphase[i])); + fputs("\n", cp_out); + vec = vec->v_link2; + } + } + free_pnode(first_name); + tfree(freq); + tfree(mag); + tfree(phase); + tfree(nmag); + tfree(nphase); + return; +} + +static char * +pn(double num) +{ + char buf[BSIZE_SP]; + int i = cp_numdgt; + + if (i < 1) + i = 6; + + if (num < 0.0) + (void) sprintf(buf, "%.*g", i - 1, num); + else + (void) sprintf(buf, "%.*g", i, num); + return (copy(buf)); +} + +/* + * CKTfour() - perform fourier analysis of an output vector. + * Due to the construction of the program which places all the + * output data in the post-processor, the fourier analysis can not + * be done directly. This function allows the post processor to + * hand back vectors of time and data values to have the fourier analysis + * performed on them. + * + */ + + +static int +CKTfour(int ndata, int numFreq, double *thd, double *Time, double *Value, double FundFreq, double *Freq, double *Mag, double *Phase, double *nMag, double *nPhase) + /* number of entries in the Time and Value arrays */ + /* number of harmonics to calculate */ + /* total harmonic distortion (percent) to be returned */ + /* times at which the voltage/current values were measured*/ + /* voltage or current vector whose transform is desired */ + /* the fundamental frequency of the analysis */ + /* the frequency value of the various harmonics */ + /* the Magnitude of the fourier transform */ + /* the Phase of the fourier transform */ + /* the normalized magnitude of the transform: nMag(fund)=1*/ + /* the normalized phase of the transform: Nphase(fund)=0 */ + /* note we can consider these as a set of arrays: The sizes are: + * Time[ndata], Value[ndata] + * Freq[numFreq],Mag[numfreq],Phase[numfreq],nMag[numfreq],nPhase[numfreq] + * The arrays must all be allocated by the caller. + * The Time and Value array must be reasonably distributed over at + * least one full period of the fundamental Frequency for the + * fourier transform to be useful. The function will take the + * last period of the frequency as data for the transform. + */ + +{ +/* we are assuming that the caller has provided exactly one period + * of the fundamental frequency. + */ + int i; + int j; + double tmp; + /* clear output/computation arrays */ + + for(i=0;i1) *thd += nMag[i]*nMag[i]; + } + *thd = 100*sqrt(*thd); + return(OK); +} + +#ifdef notdef + /* What is this code? An old DFT? */ + double initial; /* starting time */ + double final; /* final time */ + double elapsed; /* elapsed time */ + double tmp; + int start=0; + int n; + int m; + int edge; + + *thd = 0; + final = Time[ndata-1]; + initial = Time[0]; + elapsed = final - initial; + if( (elapsed-1/FundFreq)< -.01/FundFreq ){ + /* not enough data for a full period */ + return(E_BADPARM); + } + elapsed = 1/FundFreq; /* set to desired elapsed time */ + initial = final - elapsed; /* set to desired starting time */ + while(Time[start] initial) { + /* interesting case - need to handle previous point */ + /* first, make sure that there is a point on the other side of + * the beginning of time. + */ + if(start-2 < 0) { + /* point doesn't exist, so we have to fudge + * things slightly - by bumping edge up, we re-use the first + * point in the interval for the last point before the + * interval - should be only for very small error in + * interval boundaries, so shouldn't be significant, and is + * better than ignoring the interval + */ + edge = start-1; + } else { + edge = start-2; + } + for(m=0;m1) *thd += nMag[m] * nMag[m]; + } + *thd = 100 * sqrt(*thd); + return(OK); + +#endif diff --git a/src/frontend/fourier.h b/src/frontend/fourier.h new file mode 100644 index 000000000..597f7cf2f --- /dev/null +++ b/src/frontend/fourier.h @@ -0,0 +1,13 @@ +/************* + * Header file for fourier.c + * 1999 E. Rouat + ************/ + +#ifndef FOURIER_H_INCLUDED +#define FOURIER_H_INCLUDED + +void com_fourier(wordlist *wl); + + + +#endif diff --git a/src/frontend/gens.c b/src/frontend/gens.c new file mode 100644 index 000000000..7951bebbc --- /dev/null +++ b/src/frontend/gens.c @@ -0,0 +1,348 @@ +#include "ngspice.h" +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "cpstd.h" +#include "ftedefs.h" +#include "fteext.h" +#include "devdefs.h" +#include "dgen.h" +#include "gens.h" + + +/* static declarations */ +static void dgen_next(dgen **dgx); + + + +void +wl_forall(wordlist *wl, int (*fn) (/* ??? */), char *data) +{ + while (wl) { + (*fn)(wl, data); + wl = wl->wl_next; + } +} + +dgen * +dgen_init(GENcircuit *ckt, wordlist *wl, int nomix, int flag, int model) +{ + dgen *dg; + wordlist **prevp; + + dg = NEW(dgen); + dg->ckt = ckt; + dg->instance = NULL; + dg->model = NULL; + dg->dev_type_no = -1; + dg->dev_list = wl; + dg->flags = 0; + + prevp = &wl; + +#ifdef notdef + for (w = wl; w; w = w->wl_next) { + if (!strcmp(w->wl_word, "#")) { + model = 1; + *prevp = w->wl_next; + flag |= DGEN_DEFDEVS; + } else if (index(w->wl_word, '#')) + model = 1; + else + instance = 1; + prevp = &w->wl_next; + } + + if (instance && model) { + fprintf(stderr, + "Error: can't mix instances and models"); + tfree(dg); + return NULL; + } +#endif + + if (model) + dg->flags = (DGEN_ALL & ~ DGEN_INSTANCE) | DGEN_INIT; + else + dg->flags = DGEN_ALL | DGEN_INIT; + + if (wl) + dg->flags |= flag; + else + dg->flags |= DGEN_DEFDEVS | flag; + + dgen_next(&dg); + + return dg; +} + +int +dgen_for_n(dgen *dg, int n, int (*fn) (/* ??? */), char *data, int subindex) +{ + dgen dgx, *dgxp; + int dnum, i, j, k; + + dgxp = &dgx; + bcopy(dg, dgxp, sizeof(dgx)); + + dnum = dgxp->dev_type_no; + + k = 0; + for (i = 0; dgxp && dgxp->dev_type_no == dnum && i < n; i++) { + /*printf("Loop at %d\n", i);*/ + j = (*fn)(dgxp, data, subindex); + if (j > k) + k = j; + dgen_next(&dgxp); + } + + return k - subindex; +} + +void +dgen_nth_next(dgen **dg, int n) +{ + int i, dnum; + + dnum = (*dg)->dev_type_no; + + for (i = 0; *dg && (*dg)->dev_type_no == dnum && i < n; i++) { + dgen_next(dg); + } +} + +static void +dgen_next(dgen **dgx) +{ + int done; + dgen *dg; + char *p; + int need; + wordlist *w; + char type, *subckt, *device, *model; + char *Top_Level = "\001"; + int subckt_len; + int head_match; + char *word, *dev_name, *mod_name; + + dg = *dgx; + if (!dg) + return; + + /* Prime the "model only" or "device type only" iteration, + * required because the filtering (below) may request additional + * detail. + */ + if (!(dg->flags & DGEN_INSTANCE)) { + if (!(dg->flags & DGEN_MODEL)) + dg->model = NULL; + dg->instance = NULL; + } + + need = dg->flags; + done = 0; + + while (!done) { + + if (dg->instance) { + /* next instance */ + dg->instance = dg->instance->GENnextInstance; + } else if (dg->model) { + dg->model = dg->model->GENnextModel; + if (dg->model) + dg->instance = dg->model->GENinstances; + } else if (dg->dev_type_no < DEVmaxnum) { + dg->dev_type_no += 1; + if (dg->dev_type_no < DEVmaxnum) { + dg->model = ((CKTcircuit *) + (dg->ckt))->CKThead[dg->dev_type_no]; + if (dg->model) + dg->instance = dg->model->GENinstances; + } else { + done = 2; + break; + } + } else { + done = 2; + break; + } + + if (need & DGEN_INSTANCE && !dg->instance) + continue; + if (need & DGEN_MODEL && !dg->model) + continue; + +#ifdef notdef + if (dg->instance) + printf("Maybe : %s\n", dg->instance->GENname); + if (dg->model) + printf("Maybe mod : %s\n", dg->model->GENmodName); +#endif + + /* Filter */ + + if (!dg->dev_list) { + if ((dg->flags & DGEN_ALLDEVS) + || ((dg->flags & DGEN_DEFDEVS) + && (ft_sim->devices[dg->dev_type_no]->flags + & DEV_DEFAULT))) + { + done = 1; + } else { + done = 0; + } + continue; + } + + done = 0; + + for (w = dg->dev_list; w && !done; w = w->wl_next) { + + /* assume a match (have to reset done every time + * through + */ + done = 1; + word = w->wl_word; + + if (!word || !*word) { + break; + } + + /* Break up word into type, subcircuit, model, device, + * must be nodestructive to "word" + */ + + /* type */ + if (*word == ':' || *word == '#') + type = '\0'; + else + type = *word++; + + /* subcircuit */ + + subckt = word; + /* look for last ":" or "#" in word */ + for (p = word + strlen(word) /* do '\0' first time */; + p != word && *p != ':' && *p != '#'; p--) + { + ; + } + + if (*p != ':' && *p != '#') { + /* No subcircuit name specified */ + subckt = NULL; + subckt_len = 0; + } else { + + if (p[-1] == ':') { + head_match = 1; + subckt_len = p - word - 1; + } else { + head_match = 0; + subckt_len = p - word; + } + + if (subckt_len == 0) { + /* Top level only */ + if (head_match) + subckt = NULL; + else + subckt = Top_Level; + } + word = p + 1; + } + + /* model or device */ + + if (*p == '#') { + model = word; + device = NULL; + } else { + model = NULL; + device = word; + } + + /* Now compare */ +#ifdef notdef + printf("Type: %c, subckt: %s, name: %s\n", + type ? type : '0', subckt, device); +#endif + + if (dg->instance) + dev_name = dg->instance->GENname; + else + dev_name = NULL; + + if (dg->model) + mod_name = dg->model->GENmodName; + else + mod_name = NULL; + + if (type) { + if (!dev_name) { + done = 0; + /*printf("No device.\n");*/ + need |= DGEN_MODEL; + continue; + } else if (type != *dev_name) { + done = 0; + /*printf("Wrong type.\n");*/ + /* Bleh ... plan breaks down here */ + /* need = DGEN_TYPE; */ + continue; + } + } + + if (subckt == Top_Level) { + if (dev_name && dev_name[1] == ':') { + need |= DGEN_INSTANCE; + done = 0; + /*printf("Wrong level.\n");*/ + continue; + } + } else if (subckt && (!dev_name + || !ciprefix(subckt, dev_name + 1))) + { + need |= DGEN_INSTANCE; + done = 0; + /*printf("Wrong subckt.\n"); */ + continue; + } + + if (device && *device) { + need |= DGEN_INSTANCE | DGEN_MODEL; + if (!dev_name) { + done = 0; + /*printf("Didn't get dev name.\n");*/ + continue; + } else if (strcmp(device, + dev_name + 1 + subckt_len)) + { + done = 0; + /*printf("Wrong name.\n");*/ + continue; + } + } else if (model && *model) { + if (strcmp(model, mod_name)) { + done = 0; + need |= DGEN_MODEL; + /*printf("Wrong model name.\n");*/ + continue; + } + } + + break; + } + +#ifdef notdef + if (done == 1) + printf("Accepted\n"); + else + printf("Skipped\n"); +#endif + + } + + if (done == 2) + *dgx = NULL; +} diff --git a/src/frontend/gens.h b/src/frontend/gens.h new file mode 100644 index 000000000..c1c206b11 --- /dev/null +++ b/src/frontend/gens.h @@ -0,0 +1,16 @@ +/************* + * Header file for gens.c + * 1999 E. Rouat + ************/ + +#ifndef GENS_H_INCLUDED +#define GENS_H_INCLUDED + +void wl_forall(wordlist *wl, int (*fn) (/* ??? */), char *data); +dgen * dgen_init(GENcircuit *ckt, wordlist *wl, int nomix, int flag, int model); +int dgen_for_n(dgen *dg, int n, int (*fn) (/* ??? */), char *data, int subindex); +void dgen_nth_next(dgen **dg, int n); + + + +#endif diff --git a/src/frontend/graf.c b/src/frontend/graf.c new file mode 100644 index 000000000..eaa082a0f --- /dev/null +++ b/src/frontend/graf.c @@ -0,0 +1,1090 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jeffrey M. Hsu +**********/ + +/* + * Most of the gr_ module resides here, in particular, gr_init + * and gr_point, expect for the gr_ grid routines. + * + */ + + +#include "ngspice.h" +#include "cpdefs.h" /* for VT_ */ +#include "cpextern.h" +#include "fteconst.h" +#include "ftedebug.h" /* for iplot */ +#include "ftedata.h" /* for struct dvec */ +#include "ftedefs.h" /* for FTEextern.h and IPOINT{MIN,MAX} */ +#include "fteinput.h" +#include "ftegraph.h" +#include "ftedbgra.h" +#include "ftedev.h" +#include "graf.h" + + +/* static declarations */ +static void gr_start_internal(struct dvec *dv, bool copyvec); +static int iplot(struct plot *pl, int id); +static void set(struct plot *plot, struct dbcomm *db, bool unset, int mode); +static char * getitright(char *buf, double num); + + +extern struct dbcomm *dbs; /* for iplot */ + +/* note: let's try to get rid of these */ +/* global variables */ +/* Graphics mode in progress, so signal handlers know to call gr_clean */ +/* bool gr_gmode = FALSE; */ + +/* for legends, set in gr_start, reset in gr_iplot and gr_init */ +static int plotno; +static int curcolor = 1; /* for assigning unique colors */ +static int curlst = 0; /* for assigning line styles */ + +/* invariant: currentgraph contains the current graph */ + +/* These are what gets plotted as points when you specify point plots */ +static char pointchars[128]; +#define DEFPOINTCHARS "oxabcdefhgijklmnpqrstuvwyz" + +/* Buffer for ticmarks if given a list */ +static char ticbuf[1024]; +static char *ticlist = ticbuf; +#define MAXTICS 100 +double *readtics(char *string); + +#define XFACTOR 2 /* How much to expand the X scale during iplot. */ +#define YFACTOR 1.5 /* How much to expand the Y scale during iplot. */ + +/* + * Start of a new graph. + * Fill in the data that gets displayed. + * Difference from old gr_init + * we don't try to determine the look of the screen from here + * leave to lower level routines + * + */ + +extern void SetGraphContext (int graphid); +extern void internalerror (char *message); +extern int NewViewport (GRAPH *pgraph); +extern void DevClear (void); +extern void gr_redrawgrid (GRAPH *graph); +extern void DatatoScreen (GRAPH *graph, double x, double y, int *screenx, int *screeny); +extern void SetLinestyle (int linestyleid); +extern void SetColor (int colorid); +extern void DrawLine (int x1, int y1, int x2, int y2); +extern void Text (char *text, int x, int y); +extern void SaveText (GRAPH *graph, char *text, int x, int y); +extern void Update (void); +extern void PushGraphContext (GRAPH *graph); +extern void PopGraphContext (void); +extern void Input (REQUEST *request, RESPONSE *response); +extern int DestroyGraph (int id); + +int +gr_init(double *xlims, double *ylims, char *xname, char *plotname, char *hcopy, int nplots, double xdelta, double ydelta, GRIDTYPE gridtype, PLOTTYPE plottype, char *xlabel, char *ylabel, int xtype, int ytype, char *pname, char *commandline) + /* The size of the screen. */ + /* What to label things. */ + /* The raster file. */ + /* How many plots there will be. */ + /* Line increments for the scale. */ + /* The grid type */ + /* and the plot type. */ + /* Labels for axes. */ + /* The types of the data graphed. */ + + /* For xi_zoomdata() */ +{ + + GRAPH *graph; + int b; + wordlist *wl; + char *comb_title; + + + if (!(graph = NewGraph())) { + return(FALSE); + } + + /* + The global currentgraph will always be the current graph. + */ + SetGraphContext(graph->graphid); + + graph->onevalue = (xname ? FALSE : TRUE); + + /* communicate filename to plot 5 driver */ + if (hcopy) { + graph->devdep = hcopy; + } + + plotno = 0; + + /* note: should do only once, maybe in gr_init_once */ + if (!cp_getvar("pointchars", VT_STRING, pointchars)) + (void) strcpy(pointchars, DEFPOINTCHARS); + + if (!cp_getvar("ticmarks", VT_NUM, (char *) &graph->ticmarks)) { + if (cp_getvar("ticmarks", VT_BOOL, (char *) &b)) + graph->ticmarks = 10; + else + graph->ticmarks = 0; + } + + if (cp_getvar("ticlist", VT_LIST, ticlist)) { + wl = (wordlist *)vareval("ticlist"); + ticlist = (char *)wl_flatten(wl); + graph->ticdata = (double *) readtics(ticlist); + } else + graph->ticdata = NULL; + + /* set slow flag to stop between each plot and prompt the + user for a return + This is used mainly for graphics terminals w/o windows. + */ +/* + if (incremental) + slow = FALSE; + else + (void) cp_getvar("slowplot", VT_BOOL, (char *) &slow); +*/ + + if (!xlims || !ylims) { + internalerror("gr_init: no range specified"); + return(FALSE); + } + + /* indicate some graphics going on */ +/* gr_gmode = TRUE; */ + + /* save upper and lower limits */ + graph->data.xmin = xlims[0]; + graph->data.xmax = xlims[1]; + graph->data.ymin = ylims[0]; + graph->data.ymax = ylims[1]; + + /* note: have enum here or some better convention */ + if (NewViewport(graph) == 1) { + /* note: where is the error message generated? */ + /* note: undo mallocs */ + fprintf(cp_err, "Can't open viewport for graphics.\n"); + return(FALSE); + } + + /* layout decisions */ + /* note: have to do before gr_fixgrid and after NewViewport */ + graph->viewportxoff = graph->fontwidth * 8; /* 8 lines on left */ + graph->viewportyoff = graph->fontheight * 4; /* 4 on bottom */ + + DevClear(); + + graph->grid.gridtype = gridtype; + graph->plottype = plottype; + graph->grid.xdatatype = xtype; + graph->grid.ydatatype = ytype; + graph->grid.xdelta = xdelta; + graph->grid.ydelta = ydelta; + graph->grid.ysized = 0; + graph->grid.xsized = 0; + + if (!graph->onevalue) { + if (xlabel) { + graph->grid.xlabel = xlabel; + } else { + graph->grid.xlabel = xname; + } + if (ylabel) { + graph->grid.ylabel = ylabel; + } + } else { + if (xlabel) { + graph->grid.xlabel = xlabel; + } else { + graph->grid.xlabel = "real"; + } + if (ylabel) { + graph->grid.ylabel = ylabel; + } else { + graph->grid.ylabel = "imag"; + } + } + + if (!pname) + pname = "(unknown)"; + if (!plotname) + plotname = "(unknown)"; + comb_title = tmalloc(strlen(plotname) + strlen(pname) + 3); + sprintf(comb_title, "%s: %s", pname, plotname); + graph->plotname = comb_title; + + gr_resize_internal(graph); + gr_redrawgrid(graph); + + /* Set up colors and line styles. */ + if (dispdev->numlinestyles == 1) + curlst = 0; /* Use the same one all the time. */ + else + curlst = 1; + /* XXX Special exception for SMITH */ + if (dispdev->numcolors > 2 && (graph->grid.gridtype == GRID_SMITH + || graph->grid.gridtype == GRID_SMITHGRID)) + { + curcolor = 3; + } else + curcolor = 1; + + graph->commandline = copy(commandline); + + return(TRUE); + +} + +/* + * Add a point to the curve we're currently drawing. + * Should be in between a gr_init() and a gr_end() + * expect when iplotting, very bad hack + * Differences from old gr_point: + * We save points here, instead of in lower levels. + * Assume we are in right context + * Save points in data space (not screen space). + * We pass two points in so we can multiplex plots. + * + */ +void +gr_point(struct dvec *dv, double newx, double newy, double oldx, double oldy, int np) +{ + int oldtox, oldtoy; /* value before clipping */ + + char pointc[2]; + + int fromx, fromy, tox, toy; + int ymin, dummy; + + DatatoScreen(currentgraph, oldx, oldy, &fromx, &fromy); + DatatoScreen(currentgraph, newx, newy, &tox, &toy); + +/* note: we do not particularly want to clip here */ + oldtox = tox; oldtoy = toy; + if (!currentgraph->grid.circular) { + if (clip_line(&fromx, &fromy, &tox, &toy, + currentgraph->viewportxoff, currentgraph->viewportyoff, + currentgraph->viewport.width + currentgraph->viewportxoff, + currentgraph->viewport.height + currentgraph->viewportyoff)) + return; + } else { + if (clip_to_circle(&fromx, &fromy, &tox, &toy, + currentgraph->grid.xaxis.circular.center, + currentgraph->grid.yaxis.circular.center, + currentgraph->grid.xaxis.circular.radius)) + return; + } + + if (currentgraph->plottype != PLOT_POINT) { + SetLinestyle(dv->v_linestyle); + } else { + /* if PLOT_POINT, + don't want to plot an endpoint which have been clipped */ + if (tox != oldtox || toy != oldtoy) + return; + } + SetColor(dv->v_color); + + switch (currentgraph->plottype) { + double *tics; + case PLOT_LIN: + + /* If it's a linear plot, ignore first point since we don't want + to connect with oldx and oldy. */ + if (np) + DrawLine(fromx, fromy, tox, toy); + if ((tics = (double *) currentgraph->ticdata)) { + for (; *tics < HUGE; tics++) { + if (*tics == (double) np) { + Text("x", (int) (tox - currentgraph->fontwidth / 2), + (int) (toy - currentgraph->fontheight / 2)); + SaveText(currentgraph, "x", + (int) (tox - currentgraph->fontwidth / 2), + (int) (toy - currentgraph->fontheight / 2)); + break; + } + } + } else if ((currentgraph->ticmarks >0) && (np > 0) + && (np % currentgraph->ticmarks == 0)) + { + /* Draw an 'x' */ + Text("x", (int) (tox - currentgraph->fontwidth / 2), + (int) (toy - currentgraph->fontheight / 2)); + SaveText(currentgraph, "x", + (int) (tox - currentgraph->fontwidth / 2), + (int) (toy - currentgraph->fontheight / 2)); + } + break; + case PLOT_COMB: + DatatoScreen(currentgraph, + (double) 0, currentgraph->datawindow.ymin, + &dummy, &ymin); + DrawLine(tox, ymin, tox, toy); + break; + case PLOT_POINT: + /* Here, gi_linestyle is the character used for the point. */ + pointc[0] = dv->v_linestyle; + pointc[1] = '\0'; + Text(pointc, (int) (tox - currentgraph->fontwidth / 2), + (int) (toy - currentgraph->fontheight / 2)); + /* gr_redraw will redraw this w/o our having to save it */ + /* SaveText(currentgraph, pointc, + (int) (tox - currentgraph->fontwidth / 2), + (int) (toy - currentgraph->fontheight / 2)); */ + default: + break; + } + +} + +static void +gr_start_internal(struct dvec *dv, bool copyvec) +{ + + struct dveclist *link; + char *s; + + /* Do something special with poles and zeros. Poles are 'x's, and + * zeros are 'o's. + */ + s = ft_typenames(dv->v_type); + if (eq(s, "pole")) { + dv->v_linestyle = 'x'; + return; + } else if (eq(s, "zero")) { + dv->v_linestyle = 'o'; + return; + } + + /* Find a (hopefully) new line style and color. */ + if (currentgraph->plottype == PLOT_POINT) { + if (pointchars[curlst - 1]) + curlst++; + else + curlst = 2; + } else if ((curlst > 0) && (++curlst == dispdev->numlinestyles)) + curlst = 2; + if ((curcolor > 0) && (++curcolor == dispdev->numcolors)) + curcolor = (((currentgraph->grid.gridtype == GRID_SMITH + || currentgraph->grid.gridtype == GRID_SMITHGRID) && + (dispdev->numcolors > 3)) ? 4 : 2); + if (currentgraph->plottype == PLOT_POINT) + dv->v_linestyle = pointchars[curlst - 2]; + else + dv->v_linestyle = curlst; + dv->v_color = curcolor; + +/* note: XXX */ +#ifdef notdef + /* This is a minor hack -- reset the color */ + if (dv->v_defcolor) + ReSetColor(curcolor, dv->v_defcolor); +#endif + + /* save the data so we can refresh */ + link = (struct dveclist *) calloc(1, sizeof(struct dveclist)); + link->next = currentgraph->plotdata; + + if (copyvec) { + link->vector = vec_copy(dv); + /* vec_copy doesn't set v_color or v_linestyle */ + link->vector->v_color = dv->v_color; + link->vector->v_linestyle = dv->v_linestyle; + link->vector->v_flags |= VF_PERMANENT; + } else { + link->vector = dv; + } + + currentgraph->plotdata = link; + + /* Put the legend entry on the screen. */ + drawlegend(currentgraph, plotno, dv); + + plotno++; + +} + +/* start one plot of a graph */ +void +gr_start(struct dvec *dv) +{ + + gr_start_internal(dv, TRUE); + +} + +/* make sure the linestyles in this graph don't exceed the number of + linestyles available in the current display device */ +void +gr_relinestyle(GRAPH *graph) +{ + + struct dveclist *link; + + for (link = graph->plotdata; link; link = link->next) { + if (graph->plottype == PLOT_POINT) continue; + if (!(link->vector->v_linestyle < dispdev->numlinestyles)) { + link->vector->v_linestyle %= dispdev->numlinestyles; + } + if (!(link->vector->v_color < dispdev->numcolors)) { + link->vector->v_color %= dispdev->numcolors; + } + } + +} + + /* PN static */ +void +drawlegend(GRAPH *graph, int plotno, struct dvec *dv) +{ + + int x, y, i; + char buf[16]; + + x = ((plotno % 2) ? graph->viewportxoff : + ((graph->viewport.width) / 2)); + y = graph->absolute.height - graph->fontheight + - ((plotno + 2) / 2) * (graph->fontheight); + i = y + graph->fontheight / 2 + 1; + SetColor(dv->v_color); + if (graph->plottype == PLOT_POINT) { + (void) sprintf(buf, "%c : ", dv->v_linestyle); + Text(buf, x + graph->viewport.width / 20 + - 3 * graph->fontwidth, y); + } else { + SetLinestyle(dv->v_linestyle); + DrawLine(x, i, x + graph->viewport.width / 20, i); + } + SetColor(1); + Text(dv->v_name, x + graph->viewport.width / 20 + + graph->fontwidth, y); + +} + +/* end one plot of a graph */ +void +gr_end(struct dvec *dv) +{ + Update(); +} + +/* Print text in the bottom line. */ + +void +gr_pmsg(char *text) +{ + char buf[BSIZE_SP]; + buf[0] = 0; + + Update(); + + if (cp_getvar("device", VT_STRING, buf) + && !(strcmp("/dev/tty", buf) == 0)) + fprintf(cp_err, "%s", text); + else + + if (currentgraph->grid.xlabel) /* MW. grid.xlabel may be NULL */ + Text(text, currentgraph->viewport.width + - (strlen(currentgraph->grid.xlabel) + 3) + * currentgraph->fontwidth, + currentgraph->absolute.height - currentgraph->fontheight); + + else fprintf(cp_err, " %s \n", text); + + Update(); + (void) getchar(); + return; +} + +void +gr_clean(void) +{ + Update(); + return; +} + +/* call this routine after viewport size changes */ +void +gr_resize(GRAPH *graph) +{ + + double oldxratio, oldyratio; + double scalex, scaley; + struct _keyed *k; + + oldxratio = graph->aspectratiox; + oldyratio = graph->aspectratioy; + + graph->grid.xsized = 0; + graph->grid.ysized = 0; + + gr_resize_internal(graph); + + /* scale keyed text */ + scalex = oldxratio / graph->aspectratiox; + scaley = oldyratio / graph->aspectratioy; + for (k = graph->keyed; k; k = k->next) { + k->x = (k->x - graph->viewportxoff) * scalex + graph->viewportxoff; + k->y = (k->y - graph->viewportyoff) * scaley + graph->viewportyoff; + } + + /* X also generates an expose after a resize + This is handled in X10 by not redrawing on resizes and waiting for + the expose event to redraw. In X11, the expose routine tries to + be clever and only redraws the region specified in an expose + event, which does not cover the entire region of the plot if the + resize was from a small window to a larger window. So in order + to keep the clever X11 expose event handling, we have the X11 + resize routine pull out expose events for that window, and we + redraw on resize also. + */ +#ifdef X_DISPLAY_MISSING + gr_redraw(graph); +#endif + +} + +/* PN static */ +void +gr_resize_internal(GRAPH *graph) +{ + + if (!graph->grid.xsized) + graph->viewport.width = graph->absolute.width - + 1.4 * graph->viewportxoff; + if (!graph->grid.ysized) + graph->viewport.height = graph->absolute.height - + 2 * graph->viewportyoff; + + gr_fixgrid(graph, graph->grid.xdelta, graph->grid.ydelta, + graph->grid.xdatatype, graph->grid.ydatatype); + + /* cache width and height info to make DatatoScreen go fast */ + /* note: XXX see if this is actually used anywhere */ + graph->datawindow.width = graph->datawindow.xmax - + graph->datawindow.xmin; + graph->datawindow.height = graph->datawindow.ymax - + graph->datawindow.ymin; + + /* cache (datawindow size) / (viewport size) */ + graph->aspectratiox = graph->datawindow.width / graph->viewport.width; + graph->aspectratioy = graph->datawindow.height / graph->viewport.height; + +} + +/* redraw everything in struct graph */ +void +gr_redraw(GRAPH *graph) +{ + + struct dveclist *link; + + /* establish current graph so default graphic calls will work right */ + PushGraphContext(graph); + + DevClear(); + + /* redraw grid */ + gr_redrawgrid(graph); + + for (link=graph->plotdata, plotno = 0; link; + link = link->next, plotno++) { + /* redraw legend */ + drawlegend(graph, plotno, link->vector); + + /* replot data + if onevalue, pass it a NULL scale + otherwise, if vec has its own scale, pass that + else pass vec's plot's scale + */ + ft_graf(link->vector, + graph->onevalue ? (struct dvec *) NULL : + (link->vector->v_scale ? + link->vector->v_scale : + link->vector->v_plot->pl_scale), + TRUE); + } + + gr_restoretext(graph); + + PopGraphContext(); + +} + +void +gr_restoretext(GRAPH *graph) +{ + + struct _keyed *k; + + /* restore text */ + for (k=graph->keyed; k; k = k->next) { + SetColor(k->colorindex); + Text(k->text, k->x, k->y); + } + +} + +/* Do some incremental plotting. 3 cases -- first, if length < IPOINTMIN, don't + * do anything. Second, if length = IPOINTMIN, plot what we have so far. Third, + * if length > IPOINTMIN, plot the last points and resize if needed. + * Note we don't check for pole / zero because they are of length 1. + */ + +/* note: there is a problem with multiple iplots that use the same vector, + namely, that vector has the same color throughout. This is another + reason why we need to pull color and linestyle out of dvec XXX + Or maybe even something more drastic ?? */ + +extern bool resumption; + +static int +iplot(struct plot *pl, int id) +{ + int len = pl->pl_scale->v_length; + struct dvec *v, *xs = pl->pl_scale; + double *lims, dy; + double start, stop, step; + register int j; + bool changed = FALSE; + int yt; + char *yl = NULL; + double xlims[2], ylims[2]; + static REQUEST reqst = { checkup_option, 0 }; + int inited = 0; + char commandline[513]; + + for (j = 0, v = pl->pl_dvecs; v; v = v->v_next) + if (v->v_flags & VF_PLOT) + j++; + if (!j) + return(0); + if (ft_grdb) + fprintf(cp_err, "Entering iplot, len = %d\n\r", len); + + if (len < IPOINTMIN) { + /* Nothing yet */ + return(0); + } else if (len == IPOINTMIN || !id + /* || (len > IPOINTMIN && resumption) */) { + resumption = FALSE; + /* Draw the grid for the first time, and plot everything. */ + lims = ft_minmax(xs, TRUE); + xlims[0] = lims[0]; + xlims[1] = lims[1]; + ylims[0] = HUGE; + ylims[1] = - ylims[0]; + for (v = pl->pl_dvecs; v; v = v->v_next) + if (v->v_flags & VF_PLOT) { + lims = ft_minmax(v, TRUE); + if (lims[0] < ylims[0]) + ylims[0] = lims[0]; + if (lims[1] > ylims[1]) + ylims[1] = lims[1]; + if (!yl) + yl = v->v_name; + } + if (ft_grdb) + fprintf(cp_err, + "iplot: after 5, xlims = %G, %G, ylims = %G, %G\n\r", + xlims[0], + xlims[1], + ylims[0], + ylims[1]); + for (yt = pl->pl_dvecs->v_type, v = pl->pl_dvecs->v_next; v; + v = v->v_next) + if ((v->v_flags & VF_PLOT) && (v->v_type != yt)) { + yt = 0; + break; + } +/* + (void) gr_init((double *) NULL, (double *) NULL, xs->v_name, + pl->pl_title, (char *) NULL, j, xdelta, ydelta, + GRID_LIN, plottype, xs->v_name, yl, xs->v_type, yt, + commandline, plotname); +*/ +/* note: have command options for iplot to specify xdelta, etc. + So don't need static variables hack. + Assume default values for now. +*/ + sprintf(commandline, "iplot %s", xs->v_name); + + (void) gr_init(xlims, ylims, xs->v_name, + pl->pl_title, (char *) NULL, j, 0.0, 0.0, + GRID_LIN, PLOT_LIN, xs->v_name, yl, xs->v_type, yt, + plot_cur->pl_typename, commandline); + for (v = pl->pl_dvecs; v; v = v->v_next) + if (v->v_flags & VF_PLOT) { + gr_start_internal(v, FALSE); + ft_graf(v, xs, TRUE); + } + inited = 1; + } else { + Input(&reqst, 0); + /* First see if we have to make the screen bigger */ + dy = (isreal(xs) ? xs->v_realdata[len - 1] : + realpart(&xs->v_compdata[len - 1])); + if (ft_grdb) + fprintf(cp_err, "x = %G\n\r", dy); + if (!if_tranparams(ft_curckt, &start, &stop, &step) || + !ciprefix("tran", pl->pl_typename)) { + stop = HUGE; + start = - stop; + } + while (dy < currentgraph->data.xmin) { + changed = TRUE; + if (ft_grdb) + fprintf(cp_err, "resize: xlo %G -> %G\n\r", + currentgraph->data.xmin, + currentgraph->data.xmin - + (currentgraph->data.xmax - + currentgraph->data.xmin) + * XFACTOR); + currentgraph->data.xmin -= + (currentgraph->data.xmax - + currentgraph->data.xmin) + * XFACTOR; + if (currentgraph->data.xmin < start) { + currentgraph->data.xmin = start; + break; + } + } + if (currentgraph->data.xmax < + currentgraph->data.xmin) + currentgraph->data.xmax = + currentgraph->data.xmin; + while (dy > currentgraph->data.xmax) { + changed = TRUE; + if (ft_grdb) + fprintf(cp_err, "resize: xhi %G -> %G\n\r", + currentgraph->data.xmax, + currentgraph->data.xmax + + (currentgraph->data.xmax - + currentgraph->data.xmin) * XFACTOR); + currentgraph->data.xmax += + (currentgraph->data.xmax - + currentgraph->data.xmin) * + XFACTOR; + if (currentgraph->data.xmax > stop) { + currentgraph->data.xmax = stop; + break; + } + } + for (v = pl->pl_dvecs; v; v = v->v_next) { + if (!(v->v_flags & VF_PLOT)) + continue; + dy = (isreal(v) ? v->v_realdata[len - 1] : + realpart(&v->v_compdata[len - 1])); + if (ft_grdb) + fprintf(cp_err, "y = %G\n\r", dy); + while (dy < currentgraph->data.ymin) { + changed = TRUE; + if (ft_grdb) + fprintf(cp_err, "resize: ylo %G -> %G\n\r", + currentgraph->data.ymin, + currentgraph->data.ymin - + (currentgraph->data.ymax - + currentgraph->data.ymin) * YFACTOR); + currentgraph->data.ymin -= + (currentgraph->data.ymax - + currentgraph->data.ymin) * YFACTOR; + } + if (currentgraph->data.ymax < + currentgraph->data.ymin) + currentgraph->data.ymax = + currentgraph->data.ymin; + while (dy > currentgraph->data.ymax) { + changed = TRUE; + if (ft_grdb) + fprintf(cp_err, "resize: yhi %G -> %G\n\r", + currentgraph->data.ymax, + currentgraph->data.ymax + + (currentgraph->data.ymax - + currentgraph->data.ymin) * YFACTOR); + currentgraph->data.ymax += + (currentgraph->data.ymax - + currentgraph->data.ymin) * YFACTOR; + } + } + if (changed) { + /* Redraw everything. */ + gr_pmsg("Resizing screen"); + gr_resize(currentgraph); + gr_redraw(currentgraph); + } else { + /* Just connect the last two points. This won't + * be done with curve interpolation, so it might + * look funny. + */ + for (v = pl->pl_dvecs; v; v = v->v_next) + if (v->v_flags & VF_PLOT) { + gr_point(v, + (isreal(xs) ? xs->v_realdata[len - 1] : + realpart(&xs->v_compdata[len - 1])), + (isreal(v) ? v->v_realdata[len - 1] : + realpart(&v->v_compdata[len - 1])), + (isreal(xs) ? xs->v_realdata[len - 2] : + realpart(&xs->v_compdata[len - 2])), + (isreal(v) ? v->v_realdata[len - 2] : + realpart(&v->v_compdata[len - 2])), + len - 1); + } + } + } + Update(); + return(inited); +} + +static void +set(struct plot *plot, struct dbcomm *db, bool unset, int mode) +{ + + struct dvec *v; + struct dbcomm *dc; + + if (db->db_type == DB_IPLOTALL || db->db_type == DB_TRACEALL) { + for (v = plot->pl_dvecs; v; v = v->v_next) { + if (unset) + v->v_flags &= ~mode; + else + v->v_flags |= mode; + } + return; + } + for (dc = db; dc; dc = dc->db_also) { + v = vec_fromplot(dc->db_nodename1, plot); + if (!v || v->v_plot != plot) { + if (!eq(dc->db_nodename1, "0") && !unset) { + fprintf(cp_err, "Warning: node %s non-existent in %s.\n", + dc->db_nodename1, plot->pl_name); + /* note: XXX remove it from dbs, so won't get further errors */ + } + continue; + } + if (unset) + v->v_flags &= ~mode; + else + v->v_flags |= mode; + } + return; +} + +static char * +getitright(char *buf, double num) +{ + char *p; + int k; + + sprintf(buf, " % .5g", num); + p =strchr(buf, '.'); + + if (p) { + return p - 4; + } else { + k = strlen(buf); + if (k > 8) + return buf + 4; + else /* k >= 4 */ + return buf + k - 4; + } +} + +static int hit, hit2; + +void reset_trace(void) +{ + hit = -1; + hit2 = -1; +} + +void +gr_iplot(struct plot *plot) +{ + + struct dbcomm *db; + int dontpop; /* So we don't pop w/o push. */ + char buf[30]; + + hit = 0; + for (db = dbs; db; db = db->db_next) { + if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) { + + if (db->db_graphid) PushGraphContext(FindGraph(db->db_graphid)); + + set(plot, db, FALSE, VF_PLOT); + + dontpop = 0; + if (iplot(plot, db->db_graphid)) { + /* graph just assigned */ + db->db_graphid = currentgraph->graphid; + dontpop = 1; + } + + set(plot, db, TRUE, VF_PLOT); + + if (!dontpop && db->db_graphid) PopGraphContext(); + + } else if (db->db_type == DB_TRACENODE || db->db_type == DB_TRACEALL) { + + struct dvec *v, *u; + int len; + + set(plot, db, FALSE, VF_PRINT); + + len = plot->pl_scale->v_length; + + dontpop = 0; + for (v = plot->pl_dvecs; v; v = v->v_next) { + if (v->v_flags & VF_PRINT) { + u = plot->pl_scale; + if (len <= 1 || hit <= 0 || hit2 < 0) { + if (len <= 1 || hit2 < 0) + term_clear( ); + else + term_home( ); + hit = 1; + hit2 = 1; + printf( + "\tExecution trace (remove with the \"delete\" command)"); + term_cleol( ); + printf("\n"); + + if (u) { + printf("%12s:", u->v_name); + if (isreal(u)) { + printf("%s", + getitright(buf, u->v_realdata[len - 1])); + } else { + + /* MW. Complex data here, realdata is NULL + (why someone use realdata here again) */ + printf("%s", + getitright(buf, u->v_compdata[len - 1].cx_real)); + printf(", %s", + getitright(buf, u->v_compdata[len - 1].cx_imag)); + } + term_cleol( ); + printf("\n"); + } + } + if (v == u) + continue; + printf("%12s:", v->v_name); + if (isreal(v)) { + printf("%s", getitright(buf, v->v_realdata[len - 1])); + } else { + + /* MW. Complex data again */ + printf("%s", getitright(buf, v->v_compdata[len - 1].cx_real)); + printf(", %s", getitright(buf, v->v_compdata[len - 1].cx_imag)); + } + term_cleol( ); + printf("\n"); + } + } + set(plot, db, TRUE, VF_PRINT); + + } + + } + +} + +/* + * This gets called after iplotting is done. We clear out the db_graphid + * fields. Copy the dvecs, which we referenced by reference, so + * DestroyGraph gets to free its own copy. Note: This is a clear + * case for separating the linestyle and color fields from dvec. + */ + +void +gr_end_iplot(void) +{ + + struct dbcomm *db, *prev, *next; + GRAPH *graph; + struct dveclist *link; + struct dvec *dv; + + prev = NULL; + for (db = dbs; db; prev = db, db = next) { + next = db->db_next; + if (db->db_type == DB_DEADIPLOT) { + if (db->db_graphid) { + DestroyGraph(db->db_graphid); + if (prev) + prev->db_next = next; + else + dbs = next; + dbfree(db); + } + } else if (db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL) { + if (db->db_graphid) { + + /* get private copy of dvecs */ + graph = FindGraph(db->db_graphid); + + link = graph->plotdata; + + while (link) { + dv = link->vector; + link->vector = vec_copy(dv); + /* vec_copy doesn't set v_color or v_linestyle */ + link->vector->v_color = dv->v_color; + link->vector->v_linestyle = dv->v_linestyle; + link->vector->v_flags |= VF_PERMANENT; + link = link->next; + } + + db->db_graphid = 0; + } else { + /* warn that this wasn't plotted */ + fprintf(cp_err, "Warning: iplot %d was not executed.\n", + db->db_number); + } + } + } + + + return; +} + +double * +readtics(char *string) +{ + int i, k; + char *words, *worde; + double *tics, *ticsk; + + tics = (double *) tmalloc(MAXTICS * sizeof(double)); + ticsk = tics; + words = string; + + for (i = k = 0; *words && k < MAXTICS; words = worde) { + + while (isspace(*words)) + words++; + + worde = words; + while (isalpha(*worde) || isdigit(*worde)) + worde++; + + if (*worde) + *worde++ = '\0'; + + sscanf(words, "%lf", ticsk++); + + k++; + + } + *ticsk = HUGE; + return(tics); +} + diff --git a/src/frontend/graf.h b/src/frontend/graf.h new file mode 100644 index 000000000..7f72e0a06 --- /dev/null +++ b/src/frontend/graf.h @@ -0,0 +1,30 @@ +/************* + * Header file for graf.c + * 1999 E. Rouat + ************/ + +#ifndef GRAF_H_INCLUDED +#define GRAF_H_INCLUDED + +int gr_init(double *xlims, double *ylims, char *xname, char *plotname, char *hcopy, + int nplots, double xdelta, double ydelta, GRIDTYPE gridtype, PLOTTYPE plottype, + char *xlabel, char *ylabel, int xtype, int ytype, char *pname, char *commandline); +void gr_point(struct dvec *dv, double newx, double newy, double oldx, double oldy, int np); +void gr_start(struct dvec *dv); +void gr_relinestyle(GRAPH *graph); +void drawlegend(GRAPH *graph, int plotno, struct dvec *dv); +void gr_end(struct dvec *dv); +void gr_pmsg(char *text); +void gr_clean(void); +void gr_resize(GRAPH *graph); +void gr_resize_internal(GRAPH *graph); +void gr_redraw(GRAPH *graph); +void gr_restoretext(GRAPH *graph); +void reset_trace(void); +void gr_iplot(struct plot *plot); +void gr_end_iplot(void); +double * readtics(char *string); + + + +#endif diff --git a/src/frontend/graphdb.c b/src/frontend/graphdb.c new file mode 100644 index 000000000..6477da792 --- /dev/null +++ b/src/frontend/graphdb.c @@ -0,0 +1,284 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + Manage graph data structure. +*/ + +#include "ngspice.h" +#include "ftegraph.h" +#include "ftedebug.h" +#include "fteext.h" +#include "graphdb.h" + + + +/* invariant: currentgraph contains the current graph */ +GRAPH *currentgraph; + +/* + * We use a linked list rather than a circular one because we + * expect few links per list and we don't need to add at the + * end of a list (we can add at the beginning). + */ + +/* linked list of graphs */ +typedef struct listgraph { + /* we use GRAPH here instead of a pointer to save a calloc */ + GRAPH graph; + struct listgraph *next; +} LISTGRAPH; +#define NEWLISTGRAPH (LISTGRAPH *) calloc(1, sizeof(LISTGRAPH)) + +#define NUMGBUCKETS 16 + +typedef struct gbucket { + LISTGRAPH *list; +} GBUCKET; +/* #define NEWGBUCKET (GBUCKET *) calloc(1, sizeof(GBUCKET)) */ + +static GBUCKET GBucket[NUMGBUCKETS]; + +/* note: Zero is not a valid id. This is used in plot() in graf.c. */ +static int RunningId = 1; + +/* initialize graph structure */ +#define SETGRAPH(pgraph, id) (pgraph)->graphid = (id); \ + (pgraph)->degree = 1; \ + (pgraph)->linestyle = -1 + +/* returns NULL on error */ + +extern void internalerror (char *message); +extern void SaveText (GRAPH *graph, char *text, int x, int y); + +GRAPH *NewGraph(void) +{ + + GRAPH *pgraph; + LISTGRAPH *list; + int BucketId = RunningId % NUMGBUCKETS; + + if (!(list = NEWLISTGRAPH)) { + internalerror("can't allocate a listgraph"); + return((GRAPH *) NULL); + } + + pgraph = &list->graph; + SETGRAPH(pgraph, RunningId); + + if (!GBucket[BucketId].list) { + GBucket[BucketId].list = list; + } else { + /* insert at front of current list */ + list->next = GBucket[BucketId].list; + GBucket[BucketId].list = list; + } + + RunningId++ ; + + return(pgraph); + +} + +/* Given graph id, return graph */ +GRAPH *FindGraph(int id) +{ + + LISTGRAPH *list; + + for (list = GBucket[id % NUMGBUCKETS].list; + list && list->graph.graphid != id; + list = list->next) + + ; + + if (list) + return(&list->graph); + else + return(NULL); + +} + +GRAPH *CopyGraph(GRAPH *graph) +{ + + GRAPH *ret; + struct _keyed *k; + struct dveclist *link, *newlink; + + ret = NewGraph(); + bcopy(graph, ret, sizeof(struct graph)); + + ret->graphid = RunningId - 1; /* restore id */ + + /* copy keyed */ + for (ret->keyed = NULL, k = graph->keyed; k; k = k->next) { + SaveText(ret, k->text, k->x, k->y); + } + + /* copy dvecs */ + ret->plotdata = NULL; + for (link = graph->plotdata; link; link = link->next) { + newlink = (struct dveclist *) calloc(1, sizeof(struct dveclist)); + newlink->next = ret->plotdata; + newlink->vector = vec_copy(link->vector); + /* vec_copy doesn't set v_color or v_linestyle */ + newlink->vector->v_color = link->vector->v_color; + newlink->vector->v_linestyle = link->vector->v_linestyle; + newlink->vector->v_flags |= VF_PERMANENT; + ret->plotdata = newlink; + } + + ret->commandline = copy(graph->commandline); + ret->plotname = copy(graph->plotname); + + return(ret); + +} + +int +DestroyGraph(int id) +{ + + LISTGRAPH *list, *lastlist; + struct _keyed *k, *nextk; + struct dveclist *d, *nextd; + extern struct dbcomm *dbs; + struct dbcomm *db; + + list = GBucket[id % NUMGBUCKETS].list; + lastlist = NULL; + while (list) { + if (list->graph.graphid == id) { /* found it */ + + /* Fix the iplot/trace dbs list */ + for (db = dbs; db && db->db_graphid != id; db = db->db_next) + ; + + if (db && (db->db_type == DB_IPLOT + || db->db_type == DB_IPLOTALL)) { + db->db_type = DB_DEADIPLOT; + /* Delete this later */ + return(0); + } + + /* adjust bucket pointers */ + if (lastlist) { + lastlist->next = list->next; + } else { + GBucket[id % NUMGBUCKETS].list = list->next; + } + + /* run through and de-allocate dynamically allocated keyed list */ + k=list->graph.keyed; + while (k) { + nextk = k->next; + free(k->text); + free(k); + k = nextk; + } + + /* de-allocate dveclist */ + d = list->graph.plotdata; + while (d) { + nextd = d->next; + tfree(d->vector->v_name); + if (isreal(d->vector)) { + tfree(d->vector->v_realdata); + } else { + tfree(d->vector->v_compdata); + } + free(d->vector); + free(d); + d = nextd; + } + + free(list->graph.commandline); + free(list->graph.plotname); + + /* If device dependent space allocated, free it. */ + if (list->graph.devdep) + free(list->graph.devdep); + free(list); + + return(1); + } + lastlist = list; + list = list->next; + } + + internalerror("tried to destroy non-existent graph"); + return (0); + +} + +/* free up all dynamically allocated data structures */ +void +FreeGraphs(void) +{ + + GBUCKET *gbucket; + LISTGRAPH *list, *deadl; + + for (gbucket = GBucket; gbucket < &GBucket[NUMGBUCKETS]; gbucket++) { + list = gbucket->list; + while (list) { + deadl = list; + list = list->next; + free(deadl); + } + } + +} + +void +SetGraphContext(int graphid) +{ + + currentgraph = FindGraph(graphid); + +} + +typedef struct gcstack { + GRAPH *pgraph; + struct gcstack *next; +} GCSTACK; +GCSTACK *gcstacktop; +#define NEWGCSTACK (GCSTACK *) calloc(1, sizeof(GCSTACK)) + +/* note: This Push and Pop has tricky semantics. + Push(graph) will push the currentgraph onto the stack + and set currentgraph to graph. + Pop() simply sets currentgraph to the top of the stack and pops stack. +*/ +void +PushGraphContext(GRAPH *graph) +{ + + GCSTACK *gcstack = NEWGCSTACK; + + if (!gcstacktop) { + gcstacktop = gcstack; + } else { + gcstack->next = gcstacktop; + gcstacktop = gcstack; + } + gcstacktop->pgraph = currentgraph; + currentgraph = graph; + +} + +void +PopGraphContext(void) +{ + + GCSTACK *dead; + + currentgraph = gcstacktop->pgraph; + dead = gcstacktop; + gcstacktop = gcstacktop->next; + free(dead); + +} diff --git a/src/frontend/graphdb.h b/src/frontend/graphdb.h new file mode 100644 index 000000000..130e1450d --- /dev/null +++ b/src/frontend/graphdb.h @@ -0,0 +1,20 @@ +/************* + * Header file for graphdb.c + * 1999 E. Rouat + ************/ + +#ifndef GRAPHDB_H_INCLUDED +#define GRAPHDB_H_INCLUDED + +GRAPH *NewGraph(void); +GRAPH *FindGraph(int id); +GRAPH *CopyGraph(GRAPH *graph); +int DestroyGraph(int id); +void FreeGraphs(void); +void SetGraphContext(int graphid); +void PushGraphContext(GRAPH *graph); +void PopGraphContext(void); + + + +#endif diff --git a/src/frontend/grid.c b/src/frontend/grid.c new file mode 100644 index 000000000..7f2fd635f --- /dev/null +++ b/src/frontend/grid.c @@ -0,0 +1,1602 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + + Routines to draw the various sorts of grids -- linear, log, polar. +*/ + +#include "ngspice.h" +#include "ftegraph.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "grid.h" + + +#define RAD_TO_DEG (180.0 / M_PI) +#define LABEL_CHARS 20 + + +/* static declarations */ +static double * lingrid(GRAPH *graph, double lo, double hi, double delta, int type, Axis axis); +static double * loggrid(GRAPH *graph, double lo, double hi, int type, Axis axis); +static void polargrid(GRAPH *graph); +static void drawpolargrid(GRAPH *graph); +static void adddeglabel(GRAPH *graph, int deg, int x, int y, int cx, int cy, int lx, int ly); +static void addradlabel(GRAPH *graph, int lab, double theta, int x, int y); +static void smithgrid(GRAPH *graph); +static void drawsmithgrid(GRAPH *graph); +static void arcset(GRAPH *graph, double rad, double prevrad, double irad, double iprevrad, + double radoff, int maxrad, int centx, int centy, int xoffset, int yoffset, + char *plab, char *nlab, int pdeg, int ndeg, int pxmin, int pxmax); +static double cliparc(double cx, double cy, double rad, double start, double end, int iclipx, + int iclipy, int icliprad, int flag); + + + + +/* note: scaleunits is static and never changed in this file + ie, can get rid of it */ +static bool scaleunits = TRUE; + + +extern void SetColor (int colorid); +extern void SetLinestyle (int linestyleid); +extern void Text (char *text, int x, int y); +void drawloggrid (GRAPH *graph, char *units, int hmt, int lmt, int decsp, int subs, int pp, Axis axis); +void drawlingrid (GRAPH *graph, char *units, int spacing, int nsp, double dst, double lmt, double hmt, bool onedec, int mult, double mag, int digits, Axis axis); +extern void DrawLine (int x1, int y1, int x2, int y2); +extern void Update (void); +extern void Arc (int x0, int y0, int radius, double theta1, double theta2); + +void +gr_fixgrid(GRAPH *graph, double xdelta, double ydelta, int xtype, int ytype) +{ + double *dd; + + if (graph->grid.gridtype == GRID_NONE) { + graph->grid.gridtype = GRID_LIN; + } + + SetColor(1); + SetLinestyle(1); + + if ((graph->data.xmin > graph->data.xmax) + || (graph->data.ymin > graph->data.ymax)) { + fprintf(cp_err, + "gr_fixgrid: Internal Error - bad limits: %g, %g, %g, %g\r\n", + graph->data.xmin, graph->data.xmax, + graph->data.ymin, graph->data.ymax); + return; + } + + if (graph->grid.gridtype == GRID_POLAR) { + graph->grid.circular = TRUE; + polargrid(graph); + return; + } else if (graph->grid.gridtype == GRID_SMITH + || graph->grid.gridtype == GRID_SMITHGRID) + { + graph->grid.circular = TRUE; + smithgrid(graph); + return; + } + graph->grid.circular = FALSE; + + if ((graph->grid.gridtype == GRID_YLOG) + || (graph->grid.gridtype == GRID_LOGLOG)) + dd = loggrid(graph, graph->data.ymin, graph->data.ymax, + ytype, y_axis); + else + dd = lingrid(graph, graph->data.ymin, graph->data.ymax, + ydelta, ytype, y_axis); + + graph->datawindow.ymin = dd[0]; + graph->datawindow.ymax = dd[1]; + + if ((graph->grid.gridtype == GRID_XLOG) + || (graph->grid.gridtype == GRID_LOGLOG)) + dd = loggrid(graph, graph->data.xmin, graph->data.xmax, + xtype, x_axis); + else + dd = lingrid(graph, graph->data.xmin, graph->data.xmax, + xdelta, xtype, x_axis); + + graph->datawindow.xmin = dd[0]; + graph->datawindow.xmax = dd[1]; + +/* do we really need this? */ +/* + SetLinestyle(0); + DrawLine(graph->viewportxoff, graph->viewportyoff, + graph->viewport.width + graph->viewportxoff, + graph->viewportyoff); + DrawLine(graph->viewportxoff, graph->viewportyoff, + graph->viewportxoff, + graph->viewport.height + graph->viewportyoff); + SetLinestyle(1); +*/ + + return; +} + +void +gr_redrawgrid(GRAPH *graph) +{ + + SetColor(1); + SetLinestyle(1); + /* draw labels */ + if (graph->grid.xlabel) { + Text(graph->grid.xlabel, + (int) (graph->absolute.width * 0.35), + graph->fontheight); + } + if (graph->grid.ylabel) { + if (graph->grid.gridtype == GRID_POLAR + || graph->grid.gridtype == GRID_SMITH + || graph->grid.gridtype == GRID_SMITHGRID) { + Text(graph->grid.ylabel, + graph->fontwidth, + (graph->absolute.height * 3) / 4 ); + } else { + Text(graph->grid.ylabel, + graph->fontwidth, + graph->absolute.height / 2 ); + } + } + + switch( graph->grid.gridtype ) { + case GRID_POLAR: + drawpolargrid(graph); + break; + case GRID_SMITH: + drawsmithgrid(graph); + break; + case GRID_SMITHGRID: + drawsmithgrid(graph); + break; + + + case GRID_XLOG: + case GRID_LOGLOG: + drawloggrid(graph, + graph->grid.xaxis.log.units, + graph->grid.xaxis.log.hmt, + graph->grid.xaxis.log.lmt, + graph->grid.xaxis.log.decsp, + graph->grid.xaxis.log.subs, + graph->grid.xaxis.log.pp, x_axis); + break; + default: + drawlingrid(graph, + graph->grid.xaxis.lin.units, + graph->grid.xaxis.lin.spacing, + graph->grid.xaxis.lin.numspace, + graph->grid.xaxis.lin.distance, + graph->grid.xaxis.lin.lowlimit, + graph->grid.xaxis.lin.highlimit, + graph->grid.xaxis.lin.onedec, + graph->grid.xaxis.lin.mult, + graph->grid.xaxis.lin.tenpowmag + / graph->grid.xaxis.lin.tenpowmagx, + graph->grid.xaxis.lin.digits, + x_axis); + break; + } + + switch( graph->grid.gridtype ) { + case GRID_POLAR: + case GRID_SMITH: + case GRID_SMITHGRID: + break; + + case GRID_YLOG: + case GRID_LOGLOG: + drawloggrid(graph, + graph->grid.yaxis.log.units, + graph->grid.yaxis.log.hmt, + graph->grid.yaxis.log.lmt, + graph->grid.yaxis.log.decsp, + graph->grid.yaxis.log.subs, + graph->grid.yaxis.log.pp, y_axis); + break; + default: + drawlingrid(graph, + graph->grid.yaxis.lin.units, + graph->grid.yaxis.lin.spacing, + graph->grid.yaxis.lin.numspace, + graph->grid.yaxis.lin.distance, + graph->grid.yaxis.lin.lowlimit, + graph->grid.yaxis.lin.highlimit, + graph->grid.yaxis.lin.onedec, + graph->grid.yaxis.lin.mult, + graph->grid.yaxis.lin.tenpowmag + / graph->grid.yaxis.lin.tenpowmagx, + graph->grid.yaxis.lin.digits, + y_axis); + break; + } + +} + +/* Plot a linear grid. Returns the new hi and lo limits. */ +static double * +lingrid(GRAPH *graph, double lo, double hi, double delta, int type, Axis axis) +{ + int mag, mag2, mag3; + double hmt, lmt, dst; + int nsp; + double tenpowmag, tenpowmag2, step, spacing; + bool onedec = FALSE; + int margin; + int max; + static double dd[2]; + int mult = 1; + char buf[LABEL_CHARS], *s; + int slim, digits; + + if (axis == y_axis && graph->grid.ysized) { + lmt = graph->grid.yaxis.lin.lowlimit; + hmt = graph->grid.yaxis.lin.highlimit; + tenpowmag = graph->grid.yaxis.lin.tenpowmag; + dd[0] = lmt * tenpowmag; + dd[1] = hmt * tenpowmag; + return dd; + } + + if (axis == x_axis && graph->grid.xsized) { + lmt = graph->grid.xaxis.lin.lowlimit; + hmt = graph->grid.xaxis.lin.highlimit; + tenpowmag = graph->grid.xaxis.lin.tenpowmag; + dd[0] = lmt * tenpowmag; + dd[1] = hmt * tenpowmag; + return dd; + } + + if (delta < 0.0) { + fprintf(cp_err, "Warning: %cdelta is negative -- reversed\n", + (axis == x_axis) ? 'x' : 'y'); + delta = -delta; + } + + mag2 = floor(log10(fabs(hi - lo))); + tenpowmag2 = pow(10.0, (double) mag2); + + /* Round lo down, and hi up */ + + /* First, round lo _up_ and hi _down_ out to the 3rd digit of accuracy */ + lmt = (ceil(1000 * lo / tenpowmag2)) / 1000.0; + hmt = (floor(1000 * hi / tenpowmag2 + 0.9)) / 1000.0; + + lmt = floor(10.0 * lmt) / 10.0; + hmt = ceil(10.0 * hmt) / 10.0; + + lo = lmt * tenpowmag2; + hi = hmt * tenpowmag2; + + if (fabs(hi) > fabs(lo)) + mag = floor(log10(fabs(hi))); + else + mag = floor(log10(fabs(lo))); + + if (mag >= 0) + mag3 = ((int) (mag / 3)) * 3; + else + mag3 = - ((int) ((2 - mag) / 3)) * 3; + + if (scaleunits) + digits = mag3 - mag2; + else { + digits = mag - mag2; + mag3 = mag; + } + + if (digits < 1) + digits = 0; + + if (axis == x_axis) { + margin = graph->viewportxoff; + /*max = graph->viewport.width + graph->viewportxoff;*/ + max = graph->absolute.width - graph->viewportxoff; + } else { + graph->viewportxoff = (digits + 5 + mag - mag3) * graph->fontwidth; + margin = graph->viewportyoff; + /*max = graph->viewport.height + graph->viewportyoff;*/ + max = graph->absolute.height - graph->viewportyoff; + } + + /* Express the difference between the high and low values as + * diff = d * 10^mag. We know diff >= 0.0. If scaleunits is + * set then make sure that mag is modulo 3. + */ + + dst = hmt - lmt; + + /* We have to go from lmt to hmt, so think of some useful places + * to put grid lines. We will have a total of nsp lines, one + * every spacing pixels, which is every dst / nsp units. + */ + + if (scaleunits) { + static char scaleletters[ ] = "afpnum\0kMGT"; + char *p; + int i, j; + + tenpowmag = pow(10.0, (double) mag3); + + *buf = 0; + + i = (mag3 + 18) / 3; + + if (i < 0) + i = 6; /* No scale units */ + else if (i >= sizeof(scaleletters) - 1) { + /* sizeof includes '\0' at end, which is useless */ + /* i = sizeof(scaleletters) - 2; */ + i = 6; /* No scale units */ + } + + j = mag3 - i * 3 + 18; + if (j == 1) + (void) sprintf(buf, "x10 "); + else if (j == 2) + (void) sprintf(buf, "x100 "); + else if (j) + (void) sprintf(buf, "x10^%d ", j); + + if (scaleletters[i]) { + for (p = buf; *p; p++) + ; + *p++ = scaleletters[i]; + *p++ = 0; + } + + } else if (mag > 1) { + tenpowmag = pow(10.0, (double) mag); + (void) sprintf(buf, "x10^%d ", mag); + } + + if ((s = ft_typabbrev(type))) { + (void) strcat(buf, s); + } else { + (void) strcat(buf, "Units"); + } + + if (delta == 0.0) { + int i; + double step; + + static struct { float div_lim, step; } div_list[ ] = { + { 100.0, 10.0 }, + { 50.0, 5.0 }, + { 20.0, 2.0 }, + { 6.0, 1.0 }, + { 3.0, 0.5 }, + { 1.0, 0.2 }, + { 0.5, 0.1 }, + { 0.0, 0.05 }, + { 0.0, 0.01 } + }; + + for (i = 0; i < NUMELEMS(div_list); i++) { + if (dst > div_list[i].div_lim) { + break; + } + } + + do { + step = div_list[i].step; + nsp = (dst + step - 0.0001) / step; + spacing = (max - margin) / nsp; + i += 1; + } while (i < NUMELEMS(div_list) && spacing > 50); + + if (axis == x_axis) { + slim = digits + 5 + mag - mag3; + slim = graph->fontwidth * (slim + 1); + } else + slim = graph->fontheight * 3; + + while (i > 0 && spacing < slim + 3) { + i -= 1; + step = div_list[i].step; + nsp = (dst + step - 0.0001) / step; + spacing = (max - margin) / nsp; + } + + if (lmt < 0) + lmt = - ceil(-lmt / step) * step; + else + lmt = floor(lmt / step) * step; + + if (hmt < 0) + hmt = - floor(-hmt / step) * step; + else + hmt = ceil(hmt / step) * step; + + dst = hmt - lmt; + + lo = lmt * tenpowmag2; + hi = hmt * tenpowmag2; + + nsp = (dst + step - 0.0001) / step; + + } else { + /* The user told us where to put the grid lines. They will + * not be equally spaced in this case (i.e, the right edge + * won't be a line). + */ + nsp = (hi - lo) / delta; + if (nsp > 100) + nsp = 100; + step = (max - margin) * delta / (hi - lo); + } + spacing = (max - margin) / nsp; + + dd[0] = lo; + dd[1] = hi; + + /* Reset the max coordinate to deal with round-off error. */ + if (nsp && (delta == 0.0)) { + if (axis == x_axis) + graph->viewport.width = spacing * nsp; + else + graph->viewport.height = spacing * nsp; + } else if (!nsp) { + nsp = 1; + } + + /* have to save non-intuitive variables left over + from old algorithms for redraws */ + + if (axis == x_axis) { + graph->grid.xsized = 1; + graph->grid.xaxis.lin.onedec = onedec; + graph->grid.xaxis.lin.mult = mult; + graph->grid.xaxis.lin.tenpowmag = tenpowmag2; + graph->grid.xaxis.lin.tenpowmagx = tenpowmag; + graph->grid.xaxis.lin.digits = digits; + (void) strcpy(graph->grid.xaxis.lin.units, buf); + graph->grid.xaxis.lin.distance = dst; + graph->grid.xaxis.lin.lowlimit = lmt; + graph->grid.xaxis.lin.highlimit = hmt; + graph->grid.xaxis.lin.spacing = spacing; + graph->grid.xaxis.lin.numspace = nsp; + } else { + graph->grid.ysized = 1; + graph->grid.yaxis.lin.onedec = onedec; + graph->grid.yaxis.lin.mult = mult; + graph->grid.yaxis.lin.tenpowmag = tenpowmag2; + graph->grid.yaxis.lin.tenpowmagx = tenpowmag; + graph->grid.yaxis.lin.digits = digits; + (void) strcpy(graph->grid.yaxis.lin.units, buf); + graph->grid.yaxis.lin.distance = dst; + graph->grid.yaxis.lin.lowlimit = lmt; + graph->grid.yaxis.lin.highlimit = hmt; + graph->grid.yaxis.lin.spacing = spacing; + graph->grid.yaxis.lin.numspace = nsp; + } + + return (dd); +} + +/* PN static */ +void +drawlingrid(GRAPH *graph, char *units, int spacing, int nsp, double dst, double lmt, double hmt, bool onedec, int mult, double mag, int digits, Axis axis) +{ + + int i, j; + double m, step; + char buf[LABEL_CHARS]; + + /* i counts how many pixels we have drawn, and j counts which unit + * we are at. + */ + SetLinestyle(1); + step = floor((double) dst / nsp * 100.0 + 0.000001); + for (i = 0, m = lmt * 100.0; m - 0.001 <= hmt * 100.0; + i += spacing, m += step) + { + j = m; + if (j == 0) + SetLinestyle(0); + if (graph->grid.gridtype != GRID_NONE) { + if (axis == x_axis) + DrawLine(graph->viewportxoff + i, + graph->viewportyoff, graph->viewportxoff + i, + graph->viewport.height + graph->viewportyoff); + else + DrawLine(graph->viewportxoff, + graph->viewportyoff + i, + graph->viewport.width + graph->viewportxoff, + graph->viewportyoff + i); + } + if (j == 0) + SetLinestyle(1); + + (void) sprintf(buf, "%.*f", digits + 1, m * mag / 100.0); + +#ifdef notdef + if (floor(step/10.0) != step/10.0) + (void) sprintf(buf, "%.*lf", mag, m * mag / 100.0); + else if (floor(step/100.0) != step/100.0) + (void) sprintf(buf, "%.1lf", m * mag / 100.0); + else + (void) sprintf(buf, "%lg", j * mag / 100); +#endif + + if (axis == x_axis) + Text(buf, graph->viewportxoff + i - + strlen(buf) / 2 * graph->fontwidth, + (int) (graph->fontheight * 2.5)); + else + Text(buf, graph->viewportxoff - + graph->fontwidth * (strlen(buf)), + graph->viewportyoff + i - + graph->fontheight / 2); + + /* This is to make sure things work when delta > hi - lo. */ + if (nsp == 1) + j += 1000; + } + if (axis == x_axis) + Text(units, (int) (graph->absolute.width * 0.6), + graph->fontheight); + else + Text(units, graph->fontwidth, + (int) (graph->absolute.height - 2 * graph->fontheight)); + Update(); + +} + +/* Plot a log grid. Note that we pay no attention to x- and y-delta here. */ +static double * +loggrid(GRAPH *graph, double lo, double hi, int type, Axis axis) +{ + static double dd[2]; + int margin; + int max; + int subs, pp, decsp, lmt, hmt; + int i, j; + double k; + double decs; + char buf[LABEL_CHARS], *s; + + if (axis == x_axis && graph->grid.xsized) { + lmt = graph->grid.xaxis.log.lmt; + hmt = graph->grid.xaxis.log.hmt; + dd[0] = pow(10.0, (double) lmt); + dd[1] = pow(10.0, (double) hmt); + return dd; + } else if (axis == y_axis && graph->grid.ysized) { + lmt = graph->grid.yaxis.log.lmt; + hmt = graph->grid.yaxis.log.hmt; + dd[0] = pow(10.0, (double) lmt); + dd[1] = pow(10.0, (double) hmt); + return dd; + } + + if (axis == x_axis) { + margin = graph->viewportxoff; + max = graph->absolute.width - graph->viewportxoff; + } else { + margin = graph->viewportyoff; + max = graph->absolute.height - graph->viewportyoff; + } + + /* How many orders of magnitude. We are already guaranteed that hi + * and lo are positive. + */ + + lmt = floor(mylog10(lo)); + hmt = ceil(mylog10(hi)); + + decs = hmt - lmt; + + pp = 1; + decsp = (max - margin) / decs; + + if (decsp < 20) { + pp = ceil(20.0 / decsp); + decsp *= pp; + subs = 1; + } else if (decsp > 50) { + static int divs[ ] = { 20, 10, 5, 4, 2, 1 }; + + k = 5.0 / decsp; + + for (i = 0; i < NUMELEMS(divs) - 1; i++) { + j = divs[i]; + if (-log10(((double) j - 1.0) / j) > k) + break; + } + + subs = divs[i]; + + } else + subs = 1; + + /* Start at a line */ + lmt = floor((double) lmt / pp) * pp; + decs = hmt - lmt; + decsp = (max - margin) / decs; + + dd[0] = pow(10.0, (double) lmt); + dd[1] = pow(10.0, (double) hmt); + + if ((s = ft_typabbrev(type))) { + (void) strcpy(buf, s); + } else { + (void) strcpy(buf, "Units"); + } + + if (axis == x_axis) { + (void) strcpy(graph->grid.xaxis.log.units, buf); + graph->viewport.width = decs * decsp; + graph->grid.xaxis.log.hmt = hmt; + graph->grid.xaxis.log.lmt = lmt; + graph->grid.xaxis.log.decsp = decsp; + graph->grid.xaxis.log.subs = subs; + graph->grid.xaxis.log.pp = pp; + graph->grid.xsized = 1; + } else { + (void) strcpy(graph->grid.yaxis.log.units, buf); + graph->viewport.height = decs * decsp; + graph->grid.yaxis.log.hmt = hmt; + graph->grid.yaxis.log.lmt = lmt; + graph->grid.yaxis.log.decsp = decsp; + graph->grid.yaxis.log.subs = subs; + graph->grid.yaxis.log.pp = pp; + graph->grid.ysized = 1; + } + + return (dd); + +} + +/* PN static */ +void +drawloggrid(GRAPH *graph, char *units, int hmt, int lmt, int decsp, int subs, int pp, Axis axis) +{ + int i, j, k, m; + double t; + char buf[LABEL_CHARS]; + + /* Now plot every pp'th decade line, with subs lines between them. */ + if (subs > 1) + SetLinestyle(0); + for (i = 0, j = lmt; j <= hmt; i += decsp * pp, j += pp) { + /* Draw the decade line */ + if (graph->grid.gridtype != GRID_NONE) { + if (axis == x_axis) + DrawLine(graph->viewportxoff + i, + graph->viewportyoff, + graph->viewportxoff + i, + graph->viewport.height + +graph->viewportyoff); + else + DrawLine(graph->viewportxoff, + graph->viewportyoff + i, + graph->viewport.width + + graph->viewportxoff, + graph->viewportyoff + i); + } + if (j == -2) + (void) sprintf(buf, "0.01"); + else if (j == -1) + (void) sprintf(buf, "0.1"); + else if (j == 0) + (void) sprintf(buf, "1"); + else if (j == 1) + (void) sprintf(buf, "10"); + else if (j == 2) + (void) sprintf(buf, "100"); + else + (void) sprintf(buf, "10^%d", j); + if (axis == x_axis) + Text(buf, graph->viewportxoff + i - strlen(buf) / 2, + (int) (graph->fontheight * 2.5)); + else + Text(buf, graph->viewportxoff - graph->fontwidth * + (strlen(buf) + 1), + graph->viewportyoff + i - + graph->fontheight / 2); + + if (j >= hmt) + break; + + /* Now draw the subdivision lines */ + if (subs > 1) { + SetLinestyle(1); + t = 10.0 / subs; + for (k = ceil(subs / 10.0) + 1; k < subs; k++) { + m = i + decsp * log10((double) t * k); + if (graph->grid.gridtype != GRID_NONE) { + if (axis == x_axis) + DrawLine(graph->viewportxoff + m, + graph->viewportyoff, + graph->viewportxoff + m, + graph->viewport.height + + graph->viewportyoff); + else + DrawLine(graph->viewportxoff, + graph->viewportyoff + m, + graph->viewport.width + + graph->viewportxoff, + graph->viewportyoff + m); + } + } + SetLinestyle(0); + } + } + if (axis == x_axis) + Text(units, (int) (graph->absolute.width * 0.6), + graph->fontheight); + else + Text(units, graph->fontwidth, + (int) (graph->absolute.height - 2 * graph->fontheight)); + Update(); +} + +/* Polar grids */ + +static void +polargrid(GRAPH *graph) +{ + double d, mx, my, tenpowmag; + int hmt, lmt, mag; + double minrad, maxrad; + bool centered = FALSE; + + /* Make sure that our area is square. */ + if (graph->viewport.width > graph->viewport.height) { + graph->viewport.width = graph->viewport.height; + } else { + graph->viewport.height = graph->viewport.width; + } + + /* Make sure that the borders are even */ + if (graph->viewport.width & 1) { + graph->viewport.width += 1; + graph->viewport.height += 1; + } + graph->grid.xaxis.circular.center = graph->viewport.width / 2 + + graph->viewportxoff; + graph->grid.yaxis.circular.center = graph->viewport.height / 2 + + graph->viewportyoff; + + graph->grid.xaxis.circular.radius = graph->viewport.width / 2; + + /* Figure out the minimum and maximum radii we're dealing with. */ + mx = (graph->data.xmin + graph->data.xmax) / 2; + my = (graph->data.ymin + graph->data.ymax) / 2; + d = sqrt(mx * mx + my * my); + maxrad = d + (graph->data.xmax - graph->data.xmin) / 2; + minrad = d - (graph->data.xmax - graph->data.xmin) / 2; + + if (maxrad == 0.0) { + fprintf(cp_err, "Error: 0 radius in polargrid\n"); + return; + } + if ((graph->data.xmin < 0) && (graph->data.ymin < 0) && + (graph->data.xmax > 0) && (graph->data.ymax > 0)) + minrad = 0; + if ((graph->data.xmin == - graph->data.xmax) + && (graph->data.ymin == -graph->data.ymax) + && (graph->data.xmin == graph->data.ymin)) + centered = TRUE; + + mag = floor(mylog10(maxrad)); + tenpowmag = pow(10.0, (double) mag); + hmt = maxrad / tenpowmag; + lmt = minrad / tenpowmag; + if (hmt * tenpowmag < maxrad) + hmt++; + if (lmt * tenpowmag > minrad) + lmt--; + maxrad = hmt * tenpowmag; + minrad = lmt * tenpowmag; + + /* Make sure that the range is square */ + mx = graph->data.xmax - graph->data.xmin; + my = graph->data.ymax - graph->data.ymin; + graph->datawindow.xmin = graph->data.xmin; + graph->datawindow.xmax = graph->data.xmax; + graph->datawindow.ymin = graph->data.ymin; + graph->datawindow.ymax = graph->data.ymax; + if (mx > my) { + graph->datawindow.ymin -= (mx - my) / 2; + graph->datawindow.ymax += (mx - my) / 2; + } else if (mx < my) { + graph->datawindow.xmin -= (my - mx) / 2; + graph->datawindow.xmax += (my - mx) / 2; + } + + /* Range is square with upper bound maxrad */ + +#ifdef notdef + xx = graph->datawindow.xmin + graph->datawindow.xmax; + yy = graph->datawindow.ymin + graph->datawindow.ymax; + graph->datawindow.xmin = xx - maxrad; + graph->datawindow.xmax = xx + maxrad; + graph->datawindow.ymin = yy - maxrad; + graph->datawindow.ymax = yy + maxrad; +#endif + + +#ifdef notdef + if (ft_grdb) + printf("polar: maxrad = %g, center = (%g, %g)\n", maxrad, xx, yy); + + if ((minrad == 0) && ((hmt - lmt) > 5)) { + if (!((hmt - lmt) % 2)) + step = 2; + else if (!((hmt - lmt) % 3)) + step = 3; + else + step = 1; + } else + step = 1; + + graph->grid.xaxis.circular.lmt = lmt; + graph->grid.yaxis.circular.lmt = step; +#endif + + graph->grid.xaxis.circular.hmt = hmt; + graph->grid.xaxis.circular.lmt = lmt; + graph->grid.xaxis.circular.mag = mag; + +#ifdef notdef + graph->datawindow.xmin = xx - maxrad; + graph->datawindow.xmax = xx + maxrad; + graph->datawindow.ymin = yy - maxrad; + graph->datawindow.ymax = yy + maxrad; +#endif + +} + + +static void +drawpolargrid(GRAPH *graph) +{ + double tenpowmag, theta; + int hmt, lmt, i, step, mag; + int relcx, relcy, relrad, dist, degs; + int x1, y1, x2, y2; + double minrad, maxrad, pixperunit; + char buf[64]; + +#ifdef notdef + step = graph->grid.yaxis.circular.lmt; + mag = floor(mylog10(maxrad)); + tenpowmag = pow(10.0, (double) mag); + pixperunit = graph->grid.xaxis.circular.radius / (maxrad - minrad); +#endif + hmt = graph->grid.xaxis.circular.hmt; + lmt = graph->grid.xaxis.circular.lmt; + mag = graph->grid.xaxis.circular.mag; + tenpowmag = pow(10.0, (double) mag); + maxrad = hmt * tenpowmag; + minrad = lmt * tenpowmag; + + if ((minrad == 0) && ((hmt - lmt) > 5)) { + if (!((hmt - lmt) % 2)) + step = 2; + else if (!((hmt - lmt) % 3)) + step = 3; + else + step = 1; + } else + step = 1; + pixperunit = graph->grid.xaxis.circular.radius * 2 / + (graph->datawindow.xmax - graph->datawindow.xmin); + + relcx = - (graph->datawindow.xmin + graph->datawindow.xmax) / 2 + * pixperunit; + relcy = - (graph->datawindow.ymin + graph->datawindow.ymax) / 2 + * pixperunit; + + /* The distance from the center of the plotting area to the center of + * the logical area. + */ + dist = sqrt((double) (relcx * relcx + relcy * relcy)); + + SetLinestyle(0); + Arc(graph->grid.xaxis.circular.center, + graph->grid.yaxis.circular.center, + graph->grid.xaxis.circular.radius, + (double) 0.0, (double) 0.0); + SetLinestyle(1); + + /* Now draw the circles. */ + for (i = lmt; + (relrad = i * tenpowmag * pixperunit) + <= dist + graph->grid.xaxis.circular.radius; + i += step) + { + cliparc((double) graph->grid.xaxis.circular.center + relcx, + (double) graph->grid.yaxis.circular.center + relcy, + (double) relrad, 0.0, 0.0, + graph->grid.xaxis.circular.center, + graph->grid.yaxis.circular.center, + graph->grid.xaxis.circular.radius, 0); + /* Toss on the label */ + if (relcx || relcy) + theta = atan2((double) relcy, (double) relcx); + else + theta = M_PI; + if (i && (relrad > dist - graph->grid.xaxis.circular.radius)) + addradlabel(graph, i, theta, + (int) (graph->grid.xaxis.circular.center - + (relrad - dist) * cos(theta)), + (int) (graph->grid.yaxis.circular.center + - (relrad - dist) * sin(theta))); + } + + /* Now draw the spokes. We have two possible cases -- first, the + * origin may be inside the area -- in this case draw 12 spokes. + * Otherwise, draw several spokes at convenient places. + */ + if ((graph->datawindow.xmin <= 0.0) + && (graph->datawindow.xmax >= 0.0) + && (graph->datawindow.ymin <= 0.0) + && (graph->datawindow.ymax >= 0.0)) { + for (i = 0; i < 12; i++) { + x1 = graph->grid.xaxis.circular.center + relcx; + y1 = graph->grid.yaxis.circular.center + relcy; + x2 = x1 + graph->grid.xaxis.circular.radius * 2 + * cos(i * M_PI / 6); + y2 = y1 + graph->grid.xaxis.circular.radius * 2 + * sin(i * M_PI / 6); + if (!clip_to_circle(&x1, &y1, &x2, &y2, + graph->grid.xaxis.circular.center, + graph->grid.yaxis.circular.center, + graph->grid.xaxis.circular.radius)) + { + DrawLine(x1, y1, x2, y2); + /* Add a label here */ + /*XXXX*/ + adddeglabel(graph, i * 30, x2, y2, x1, y1, + graph->grid.xaxis.circular.center, + graph->grid.yaxis.circular.center); + } + } + } else { + /* Figure out the angle that we have to fill up */ + theta = 2 * asin((double) graph->grid.xaxis.circular.radius + / dist); + theta = theta * 180 / M_PI; /* Convert to degrees. */ + + /* See if we should put lines at 30, 15, 5, or 1 degree + * increments. + */ + if (theta / 30 > 3) + degs = 30; + else if (theta / 15 > 3) + degs = 15; + else if (theta / 5 > 3) + degs = 5; + else + degs = 1; + + /* We'll be cheap */ + for (i = 0; i < 360; i+= degs) { + x1 = graph->grid.xaxis.circular.center + relcx; + y1 = graph->grid.yaxis.circular.center + relcy; + x2 = x1 + dist * 2 * cos(i * M_PI / 180); + y2 = y1 + dist * 2 * sin(i * M_PI / 180); + if (!clip_to_circle(&x1, &y1, &x2, &y2, + graph->grid.xaxis.circular.center, + graph->grid.yaxis.circular.center, + graph->grid.xaxis.circular.radius)) { + DrawLine(x1, y1, x2, y2); + /* Put on the label */ + adddeglabel(graph, i, x2, y2, x1, y1, + graph->grid.xaxis.circular.center, + graph->grid.yaxis.circular.center); + } + } + } + + (void) sprintf(buf, "e%d", mag); + Text(buf, graph->grid.xaxis.circular.center + + graph->grid.xaxis.circular.radius, + graph->grid.yaxis.circular.center + - graph->grid.xaxis.circular.radius); + Update(); + return; +} + +/* Put a degree label on the screen, with 'deg' as the label, near point (x, y) + * such that the perpendicular to (cx, cy) and (x, y) doesn't overwrite the + * label. If the distance between the center and the point is + * too small, don't put the label on. + */ + +#define LOFF 5 +#define MINDIST 10 + +static void +adddeglabel(GRAPH *graph, int deg, int x, int y, int cx, int cy, int lx, int ly) +{ + char buf[8]; + int d, w, h; + double angle; + + if (sqrt((double) (x - cx) * (x - cx) + (y - cy) * (y - cy)) < MINDIST) + return; + (void) sprintf(buf, "%d", deg); + w = graph->fontwidth * (strlen(buf) + 1); + h = graph->fontheight * 1.5; + angle = atan2((double) (y - ly), (double) (x - lx)); + d = fabs(cos(angle)) * w / 2 + fabs(sin(angle)) * h / 2 + LOFF; + + x = x + d * cos(angle) - w / 2; + y = y + d * sin(angle) - h / 2; + + Text(buf, x, y); + Text("o", x + strlen(buf) * graph->fontwidth, + y + graph->fontheight / 2); + return; +} + +/* This is kind of wierd. If dist = 0, then this is the normal case, where + * the labels should go along the positive X-axis. Otherwise, to make + * sure that all circles drawn have labels, put the label near the circle + * along the line from the logical center to the physical center. + */ + +static void +addradlabel(GRAPH *graph, int lab, double theta, int x, int y) +{ + char buf[32]; + + (void) sprintf(buf, "%d", lab); + if (theta == M_PI) { + y = y - graph->fontheight - 2; + x = x - graph->fontwidth * strlen(buf) - 3; + } else + x = x - graph->fontwidth * strlen(buf) - 3; + Text(buf, x, y); + return; +} + + +/* Smith charts. */ + +#define gr_xcenter graph->grid.xaxis.circular.center +#define gr_ycenter graph->grid.yaxis.circular.center +#define gr_radius graph->grid.xaxis.circular.radius +#define gi_fntwidth graph->fontwidth +#define gi_fntheight graph->fontheight +#define gi_maxx graph->viewport.width+graph->viewportxoff +#define gr_xmargin graph->viewportxoff +#define gr_ymargin graph->viewportyoff + +static void +smithgrid(GRAPH *graph) +{ + double mx, my; + bool centered = FALSE; + + SetLinestyle(0); + + /* Make sure that our area is square. */ + if (graph->viewport.width > graph->viewport.height) { + graph->viewport.width = graph->viewport.height; + } else { + graph->viewport.height = graph->viewport.width; + } + + /* Make sure that the borders are even */ + if (graph->viewport.width & 1) { + graph->viewport.width += 1; + graph->viewport.height += 1; + } + + graph->grid.xaxis.circular.center = graph->viewport.width / 2 + + graph->viewportxoff; + graph->grid.yaxis.circular.center = graph->viewport.height / 2 + + graph->viewportyoff; + graph->grid.xaxis.circular.radius = graph->viewport.width / 2; + + + /* We have to make sure that the range is square. */ + graph->datawindow.xmin = graph->data.xmin; + graph->datawindow.xmax = graph->data.xmax; + graph->datawindow.ymin = graph->data.ymin; + graph->datawindow.ymax = graph->data.ymax; + + if (graph->datawindow.ymin > 0) + graph->datawindow.ymin *= -1; + if (graph->datawindow.xmin > 0) + graph->datawindow.xmin *= -1; + + if (graph->datawindow.ymax < 0) + graph->datawindow.ymax *= -1; + if (graph->datawindow.xmax < 0) + graph->datawindow.xmax *= -1; + + if (fabs(graph->datawindow.ymin) > fabs(graph->datawindow.ymax)) + graph->datawindow.ymax = - graph->datawindow.ymin; + else + graph->datawindow.ymin = - graph->datawindow.ymax; + + if (fabs(graph->datawindow.xmin) > fabs(graph->datawindow.xmax)) + graph->datawindow.xmax = - graph->datawindow.xmin; + else + graph->datawindow.xmin = - graph->datawindow.xmax; + + mx = graph->datawindow.xmax - graph->datawindow.xmin; + my = graph->datawindow.ymax - graph->datawindow.ymin; + if (mx > my) { + graph->datawindow.ymin -= (mx - my) / 2; + graph->datawindow.ymax += (mx - my) / 2; + } else if (mx < my) { + graph->datawindow.xmin -= (my - mx) / 2; + graph->datawindow.xmax += (my - mx) / 2; + } + + if ((graph->datawindow.xmin == - graph->datawindow.xmax) && + (graph->datawindow.ymin == - + graph->datawindow.ymax) && (graph->datawindow.xmin == + graph->datawindow.ymin)) + centered = TRUE; + +#ifdef notdef + /* Figure out the minimum and maximum radii we're dealing with. */ + mx = (graph->datawindow.xmin + graph->datawindow.xmax) / 2; + my = (graph->datawindow.ymin + graph->datawindow.ymax) / 2; + d = sqrt(mx * mx + my * my); + maxrad = d + (graph->datawindow.xmax - graph->datawindow.xmin) / 2; + minrad = d - (graph->datawindow.xmax - graph->datawindow.xmin) / 2; +#endif + + /* Issue a warning if our data range is not normalized */ + if (graph->datawindow.ymax > 1.1) { + printf("\nwarning: exceeding range for smith chart"); + printf("\nplease normalize your data to -1 < r < +1\n"); + } + +} + +/* maximum number of circles */ +#define CMAX 50 + +static void +drawsmithgrid(GRAPH *graph) +{ + double mx, my, tenpowmag, d, dphi[CMAX], minrad, maxrad, rnorm[CMAX]; + double pixperunit; + int mag, i, j, k; + double ir[CMAX], rr[CMAX], ki[CMAX], kr[CMAX], ks[CMAX]; + int xoff, yoff, zheight; + int basemag, plen; + char buf[64], plab[32], nlab[32]; + + /* Figure out the minimum and maximum radii we're dealing with. */ + mx = (graph->datawindow.xmin + graph->datawindow.xmax) / 2; + my = (graph->datawindow.ymin + graph->datawindow.ymax) / 2; + d = sqrt(mx * mx + my * my); + maxrad = d + (graph->datawindow.xmax - graph->datawindow.xmin) / 2; + minrad = d - (graph->datawindow.xmax - graph->datawindow.xmin) / 2; + + mag = floor(mylog10(maxrad)); + tenpowmag = pow(10.0, (double) mag); + + pixperunit = graph->viewport.width / (graph->datawindow.xmax - + graph->datawindow.xmin); + + xoff = - pixperunit * (graph->datawindow.xmin + graph->datawindow.xmax) / 2; + yoff = - pixperunit * (graph->datawindow.ymin + graph->datawindow.ymax) / 2; + + /* Sweep the range from 10e-20 to 10e20. If any arcs fall into the + * picture, plot the arc set. + */ + for (mag = -20; mag < 20; mag++) { + i = gr_radius * pow(10.0, (double) mag) / maxrad; + if (i > 10) { + j = 1; + break; + } else if (i > 5) { + j = 2; + break; + } else if (i > 2) { + j = 5; + break; + } + } + k = 1; + + /* SetLinestyle(1); takes too long */ + /* Problems with Suns on very large radii && linestyle */ + SetLinestyle(0); + + /* Now plot all the arc sets. Go as high as 5 times the radius that + * will fit on the screen. The base magnitude is one more than + * the least magnitude that will fit... + */ + if (i > 20) + basemag = mag; + else + basemag = mag + 1; + /* Go back one order of magnitude and have a closer look */ + mag -= 2; + j *= 10; + while (mag < 20) { + i = j * pow(10.0, (double) mag) * pixperunit / 2; + if (i / 5 > gr_radius + ((xoff > 0) ? xoff : - xoff)) + break; + rnorm[k] = j * pow(10.0, (double) (mag - basemag)); + dphi[k] = 2.0 * atan(rnorm[k]); + ir[k] = pixperunit * (1 + cos(dphi[k])) / sin(dphi[k]); + rr[k] = pixperunit * 0.5 * (((1 - rnorm[k]) / (1 + rnorm[k])) + 1); + (void) sprintf(plab, "%g", rnorm[k]); + plen = strlen(plab); + + /* See if the label will fit on the upper xaxis */ + /* wait for some k, so we don't get fooled */ + if (k > 6) { + if ((int) (gr_radius - xoff - pixperunit + 2 * rr[k]) < + plen * gi_fntwidth + 2) + break; + } + /* See if the label will fit on the lower xaxis */ + /* First look at the leftmost circle possible*/ + if ((int) (pixperunit - 2 * rr[k] + gr_radius + xoff + + fabs((double) yoff)) < plen * gi_fntwidth + 4) { + if (j == 95) { + j = 10; + mag++; + } else { + if (j < 20) + j += 1; + else + j += 5; + } + continue; + } + /* Then look at the circles following in the viewport */ + if (k>1 && (int) 2 * (rr[k-1] - rr[k]) < plen * gi_fntwidth + 4) { + if (j == 95) { + j = 10; + mag++; + } else { + if (j < 20) + j += 1; + else + j += 5; + } + continue; + } + if (j == 95) { + j = 10; + mag++; + } else { + if (j < 20) + j += 1; + else + j += 5; + } + ki[k-1] = ir[k]; + kr[k-1] = rr[k]; + k++; + if (k == CMAX) { + printf("drawsmithgrid: grid too complex\n"); + break; + } + } + k--; + + /* Now adjust the clipping radii */ + for (i = 0; i < k; i++) + ks[i] = ki[i]; + for (i = k-1, j = k-1; i >= 0; i -= 2, j--) { + ki[i] = ks[j]; + if (i > 0) + ki[i-1] = ks[j]; + } + for (i = 0; i < k; i++) + ks[i] = kr[i]; + for (i = k-1, j = k-1; (i >= 0) && (dphi[i] > M_PI / 2); i -= 2, j--) { + kr[i] = ks[j]; + if (i > 0) + kr[i-1] = ks[j]; + } + for ( ; i >= 0; i--, j--) + kr[i] = ks[j]; + + if ((yoff > - gr_radius) && (yoff < gr_radius)) { + zheight = gr_radius * cos(asin((double) yoff / gr_radius)); + zheight = (zheight > 0) ? zheight : - zheight; + } else { + zheight = gr_radius; + } + for (ki[k] = kr[k] = (double) 0; k > 0; k--) { + (void) sprintf(plab, "%g", rnorm[k]); + (void) sprintf(nlab, "-%g", rnorm[k]); + arcset(graph, rr[k], kr[k], ir[k], ki[k], pixperunit, + gr_radius, gr_xcenter, gr_ycenter, + xoff, yoff, plab, nlab, + (int) (0.5 + RAD_TO_DEG * (M_PI - dphi[k])), + (int) (0.5 + RAD_TO_DEG * (M_PI + dphi[k])), + gr_xcenter - zheight, + gr_xcenter + zheight); + } + if (mag == 20) { + fprintf(cp_err, "smithgrid: Internal Error: screwed up\n"); + return; + } + + SetLinestyle(0); + + Arc(gr_xcenter, gr_ycenter, gr_radius, 0.0, 0.0); +/* + if ((xoff > - gr_radius) && (xoff < gr_radius)) { + zheight = gr_radius * sin(acos((double) xoff / gr_radius)); + if (zheight < 0) + zheight = - zheight; + DrawLine(gr_xcenter + xoff, gr_ycenter - zheight, + gr_xcenter + xoff, gr_ycenter + zheight); + } + */ + if ((yoff > - gr_radius) && (yoff < gr_radius)) { + zheight = gr_radius * cos(asin((double) yoff / gr_radius)); + if (zheight < 0) + zheight = - zheight; + DrawLine(gr_xcenter - zheight, gr_ycenter + yoff, + gr_xcenter + zheight, gr_ycenter + yoff); + Text("0", gr_xcenter + zheight + gi_fntwidth, gr_ycenter + yoff - + gi_fntheight / 2); + Text("o", gr_xcenter + zheight + gi_fntwidth * 2, gr_ycenter + yoff); + Text("180", gr_xcenter - zheight - gi_fntwidth * 5, gr_ycenter + + yoff - gi_fntheight / 2); + Text("o", gr_xcenter - zheight - gi_fntwidth * 2, gr_ycenter + yoff); + } + +/* (void) sprintf(buf, "e%d", basemag); */ + (void) sprintf(buf, "e%d", 0); + Text(buf, gr_xcenter + gr_radius, gr_ycenter - gr_radius); + + Update(); + return; +} + +/* Draw one arc set. The arcs should have radius rad. The outermost circle is + * described by (centx, centy) and maxrad, and the distance from the right side + * of the bounding circle to the logical center of the other circles in pixels + * is xoffset (positive brings the negative plane into the picture). + * plab and nlab are the labels to put on the positive and negative X-arcs, + * respectively... If the X-axis isn't on the screen, then we have to be + * clever... + */ + +static void +arcset(GRAPH *graph, double rad, double prevrad, double irad, double iprevrad, double radoff, int maxrad, int centx, int centy, int xoffset, int yoffset, char *plab, char *nlab, int pdeg, int ndeg, int pxmin, int pxmax) +{ + double aclip; + double angle = atan2((double) iprevrad, (double) rad); + double iangle = atan2((double) prevrad, (double) irad); + int x, xlab, ylab; + + /* Let's be lazy and just draw everything -- we won't get called too + * much and the circles get clipped anyway... + */ + SetColor(18); + + cliparc((double) (centx + xoffset + radoff - rad), + (double) (centy + yoffset), rad, 2*angle, + 2 * M_PI - 2 * angle, centx, centy, maxrad, 0); + + + /* These circles are not part of the smith chart + * Let's draw them anyway + */ + cliparc((double) (centx + xoffset + radoff + rad), + (double) (centy + yoffset), rad, M_PI + 2 * angle, + M_PI - 2 * angle, centx, centy, maxrad, 0); + + /* Draw the upper and lower circles. */ + SetColor(19); + aclip = cliparc((double) (centx + xoffset + radoff), + (double) (centy + yoffset + irad), irad, + (double) (M_PI * 1.5 + 2 * iangle), + (double) (M_PI * 1.5 - 2 * iangle), centx, centy, maxrad, 1); + if ((aclip > M_PI / 180) && (pdeg > 1)) { + xlab = centx + xoffset + radoff + irad * cos(aclip); + ylab = centy + yoffset + irad * (1 + sin(aclip)); + if ((ylab - gr_ycenter) > graph->fontheight) { + SetColor(1); + adddeglabel(graph, pdeg, xlab, ylab, + gr_xcenter, gr_ycenter, gr_xcenter, gr_ycenter); +/* + ylab = centy + yoffset - irad * (1 + sin(aclip)); + adddeglabel(graph, ndeg, xlab, ylab, + gr_xcenter, gr_ycenter, gr_xcenter, gr_ycenter); + */ + SetColor(19); + } + } + aclip = cliparc((double) (centx + xoffset + radoff), + (double) (centy + yoffset - irad), irad, + (double) (M_PI / 2 + 2 * iangle), + (double) (M_PI / 2 - 2 * iangle), centx, centy, maxrad, + (iangle == 0)?2:0); + if ((aclip >= 0 && aclip < 2*M_PI - M_PI/180) && (pdeg < 359)) { + xlab = centx + xoffset + radoff + irad * cos(aclip); + ylab = centy + yoffset + irad * (sin(aclip) - 1); + SetColor(1); + adddeglabel(graph, ndeg, xlab, ylab, + gr_xcenter, gr_ycenter, gr_xcenter, gr_ycenter); + SetColor(19); + } + + /* Now toss the labels on... */ + SetColor(1); + + x = centx + xoffset + (int)radoff - 2 * (int)rad - + gi_fntwidth * strlen(plab) - 2; + if ((x > pxmin) && (x < pxmax)) { + if ((yoffset > - gr_radius) && (yoffset < gr_radius)) + Text(plab, x, centy + yoffset - gi_fntheight - 1); + else + Text(plab, x, gr_ymargin - 3 * gi_fntheight - 2); + } +/* + x = centx + xoffset + (int) radoff + 2 * (int)rad - + gi_fntwidth * strlen(nlab) - 2; + if ((x > gr_xmargin) && (x < gi_maxx)) + Text(nlab, x, centy + yoffset - gi_fntheight - 1); + */ + + return; +} + +/* This routine draws an arc and clips it to a circle. It's hard to figure + * out how it works without looking at the piece of scratch paaper I have + * in front of me, so let's hope it doesn't break... + * Converted to all doubles for CRAYs + */ + +static double +cliparc(double cx, double cy, double rad, double start, double end, int iclipx, int iclipy, int icliprad, int flag) +{ + double clipx, clipy, cliprad; + double sclip, eclip; + double x, y, tx, ty, dist; + double alpha, theta, phi, a1, a2, d, l; + bool in; + + clipx = (double) iclipx; + clipy = (double) iclipy; + cliprad = (double) icliprad; + x = cx - clipx; + y = cy - clipy; + dist = sqrt((double) (x * x + y * y)); + + if (!rad || !cliprad) + return(-1); + if (dist + rad < cliprad) { + /* The arc is entirely in the boundary. */ + Arc((int)cx, (int)cy, (int)rad, start, end); + return(flag?start:end); + } else if ((dist - rad >= cliprad) || (rad - dist >= cliprad)) { + /* The arc is outside of the boundary. */ + return(-1); + } + /* Now let's figure out the angles at which the arc crosses the + * circle. We know dist != 0. + */ + if (x) + phi = atan2((double) y, (double) x); + else if (y > 0) + phi = M_PI * 1.5; + else + phi = M_PI / 2; + if (cx > clipx) + theta = M_PI + phi; + else + theta = phi; + + alpha = (double) (dist * dist + rad * rad - cliprad * cliprad) / + (2 * dist * rad); + + /* Sanity check */ + if (alpha > 1.0) + alpha = 0.0; + else if (alpha < -1.0) + alpha = M_PI; + else + alpha = acos(alpha); + + a1 = theta + alpha; + a2 = theta - alpha; + while (a1 < 0) + a1 += M_PI * 2; + while (a2 < 0) + a2 += M_PI * 2; + while (a1 >= M_PI * 2) + a1 -= M_PI * 2; + while (a2 >= M_PI * 2) + a2 -= M_PI * 2; + + tx = cos(start) * rad + x; + ty = sin(start) * rad + y; + d = sqrt((double) tx * tx + ty * ty); + in = (d > cliprad) ? FALSE : TRUE; + + /* Now begin with start. If the point is in, draw to either end, a1, + * or a2, whichever comes first. + */ + d = M_PI * 3; + if ((end < d) && (end > start)) + d = end; + if ((a1 < d) && (a1 > start)) + d = a1; + if ((a2 < d) && (a2 > start)) + d = a2; + if (d == M_PI * 3) { + d = end; + if (a1 < d) + d = a1; + if (a2 < d) + d = a2; + } + + if (in) { + if (start > d) { + double tmp; + tmp = start; + start = d; + d = tmp; + } + Arc((int)cx, (int)cy, (int)rad, start, d); + sclip = start; + eclip = d; + } + if (d == end) + return(flag?sclip:eclip); + if (a1 != a2) + in = in ? FALSE : TRUE; + + /* Now go from here to the next point. */ + l = d; + d = M_PI * 3; + if ((end < d) && (end > l)) + d = end; + if ((a1 < d) && (a1 > l)) + d = a1; + if ((a2 < d) && (a2 > l)) + d = a2; + if (d == M_PI * 3) { + d = end; + if (a1 < d) + d = a1; + if (a2 < d) + d = a2; + } + + if (in) { + Arc((int)cx, (int)cy, (int)rad, l, d); + sclip = l; + eclip = d; + } + if (d == end) + return(flag?sclip:eclip); + in = in ? FALSE : TRUE; + + /* And from here to the end. */ + if (in) { + Arc((int)cx, (int)cy, (int)rad, d, end); + /* special case */ + if (flag != 2) { + sclip = d; + eclip = end; + } + } + return(flag%2?sclip:eclip); +} diff --git a/src/frontend/grid.h b/src/frontend/grid.h new file mode 100644 index 000000000..44db7c411 --- /dev/null +++ b/src/frontend/grid.h @@ -0,0 +1,18 @@ +/************* + * Header file for grid.c + * 1999 E. Rouat + ************/ + +#ifndef GRID_H_INCLUDED +#define GRID_H_INCLUDED + +typedef enum { x_axis, y_axis } Axis; + +void gr_fixgrid(GRAPH *graph, double xdelta, double ydelta, int xtype, int ytype); +void gr_redrawgrid(GRAPH *graph); +void drawlingrid(GRAPH *graph, char *units, int spacing, int nsp, double dst, double lmt, + double hmt, bool onedec, int mult, double mag, int digits, Axis axis); +void drawloggrid(GRAPH *graph, char *units, int hmt, int lmt, int decsp, int subs, + int pp, Axis axis); + +#endif diff --git a/src/frontend/inp.c b/src/frontend/inp.c new file mode 100644 index 000000000..66e626b3c --- /dev/null +++ b/src/frontend/inp.c @@ -0,0 +1,757 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher +**********/ + +/* + * Stuff for dealing with spice input decks and command scripts, and + * the listing routines. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "inpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteinp.h" +#include "inp.h" + + + +/* static declarations */ +static char * upper(register char *string); +static bool doedit(char *filename); + + +/* Do a listing. Use is listing [expanded] [logical] [physical] [deck] */ + + +extern int unlink (const char *); + +void +com_listing(wordlist *wl) +{ + int type = LS_LOGICAL; + bool expand = FALSE; + char *s; + + if (ft_curckt) { + while (wl) { + s = wl->wl_word; + switch (*s) { + case 'l': + case 'L': + type = LS_LOGICAL; + break; + case 'p': + case 'P': + type = LS_PHYSICAL; + break; + case 'd': + case 'D': + type = LS_DECK; + break; + case 'e': + case 'E': + expand = TRUE; + break; + default: + fprintf(cp_err, + "Error: bad listing type %s\n", s); + } + wl = wl->wl_next; + } + if (type != LS_DECK) + fprintf(cp_out, "\t%s\n\n", ft_curckt->ci_name); + inp_list(cp_out, expand ? ft_curckt->ci_deck : + ft_curckt->ci_origdeck, ft_curckt->ci_options, + type); + } else + fprintf(cp_err, "Error: no circuit loaded.\n"); + return; +} + +static char * +upper(register char *string) +{ + + static char buf[BSIZE_SP]; + + if (string) { + strncpy(buf, string, BSIZE_SP - 1); + buf[BSIZE_SP - 1] = 0; + inp_casefix(buf); + } else { + strcpy(buf, ""); + } + + return buf; + +} + +/* Provide an input listing on the specified file of the given + * card deck. The listing should be of either LS_PHYSICAL or LS_LOGICAL + * or LS_DECK lines as specified by the type parameter. + */ + +void +inp_list(FILE *file, struct line *deck, struct line *extras, int type) +{ + struct line *here; + struct line *there; + bool renumber; + bool useout = (file == cp_out); + int i = 1; + + if (useout) + out_init(); + (void) cp_getvar("renumber", VT_BOOL, (char *) &renumber); + if (type == LS_LOGICAL) { +top1: for (here = deck; here; here = here->li_next) { + if (renumber) + here->li_linenum = i; + i++; + if (ciprefix(".end", here->li_line) && + !isalpha(here->li_line[4])) + continue; + if (*here->li_line != '*') { + if (useout) { + sprintf(out_pbuf, "%6d : %s\n", + here->li_linenum, + upper(here->li_line)); + out_send(out_pbuf); +/* out_printf("%6d : %s\n", + here->li_linenum, + upper(here->li_line)); */ + } else + fprintf(file, "%6d : %s\n", + here->li_linenum, + upper(here->li_line)); + if (here->li_error) { + if (useout) { + out_printf("%s\n", here->li_error); + } else + fprintf(file, "%s\n", here->li_error); + } + } + } + if (extras) { + deck = extras; + extras = NULL; + goto top1; + } + if (useout) { +/* out_printf("%6d : .end\n", i); */ + sprintf(out_pbuf, "%6d : .end\n", i); + out_send(out_pbuf); + } else + fprintf(file, "%6d : .end\n", i); + } else if ((type == LS_PHYSICAL) || (type == LS_DECK)) { +top2: for (here = deck; here; here = here->li_next) { + if ((here->li_actual == NULL) || (here == deck)) { + if (renumber) + here->li_linenum = i; + i++; + if (ciprefix(".end", here->li_line) && + !isalpha(here->li_line[4])) + continue; + if (type == LS_PHYSICAL) { + if (useout) { + sprintf(out_pbuf, "%6d : %s\n", + here->li_linenum, + upper(here->li_line)); + out_send(out_pbuf); + } else + fprintf(file, "%6d : %s\n", + here->li_linenum, + upper(here->li_line)); + } else { + if (useout) + out_printf("%s\n", + upper(here->li_line)); + else + fprintf(file, "%s\n", + upper(here->li_line)); + } + if (here->li_error && (type == LS_PHYSICAL)) { + if (useout) + out_printf("%s\n", + here->li_error); + else + fprintf(file, "%s\n", + here->li_error); + } + } else { + for (there = here->li_actual; there; + there = there->li_next) { + there->li_linenum = i++; + if (ciprefix(".end", here->li_line) && + isalpha(here->li_line[4])) + continue; + if (type == LS_PHYSICAL) { + if (useout) { + sprintf(out_pbuf, "%6d : %s\n", + there->li_linenum, + upper(there->li_line)); + out_send(out_pbuf); + } else + fprintf(file, "%6d : %s\n", + there->li_linenum, + upper(there->li_line)); + } else { + if (useout) + out_printf("%s\n", + upper(there->li_line)); + else + fprintf(file, "%s\n", + upper(there->li_line)); + } + if (there->li_error && + (type == LS_PHYSICAL)) { + if (useout) + out_printf("%s\n", + there->li_error); + else + fprintf(file, "%s\n", + there->li_error); + } + } + here->li_linenum = i; + } + } + if (extras) { + deck = extras; + extras = NULL; + goto top2; + } + if (type == LS_PHYSICAL) { + if (useout) { + sprintf(out_pbuf, "%6d : .end\n", i); + out_send(out_pbuf); + } else + fprintf(file, "%6d : .end\n", i); + } else { + if (useout) + out_printf(".end\n"); + else + fprintf(file, ".end\n"); + } + } else + fprintf(cp_err, "inp_list: Internal Error: bad type %d\n", + type); + return; +} + +/* The routine to source a spice input deck. We read the deck in, take out + * the front-end commands, and create a CKT structure. Also we filter out + * the following cards: .save, .width, .four, .print, and .plot, to perform + * after the run is over. + */ + +void +inp_spsource(FILE *fp, bool comfile, char *filename) +{ + struct line *deck, *dd, *ld; + struct line *realdeck, *options; + char *tt, name[BSIZE_SP], *s, *t; + bool nosubckts, commands = FALSE; + wordlist *wl = NULL, *end = NULL, *wl_first = NULL; + wordlist *controls = NULL; + FILE *lastin, *lastout, *lasterr; + char c; + + inp_readall(fp, &deck); + + if (!deck) { /* MW. We must close fp always when returning */ + (void) fclose(fp); + return; + } + + if (!comfile) + options = inp_getopts(deck); + + realdeck = inp_deckcopy(deck); + + if (!comfile) { + /* Save the title before INPgetTitle gets it. */ + tt = copy(deck->li_line); + if (!deck->li_next) + fprintf(cp_err, "Warning: no lines in input\n"); + } + fclose(fp); + + /* Now save the IO context and start a new control set. After + * we are done with the source we'll put the old file descriptors + * back. I guess we could use a FILE stack, but since this routine + * is recursive anyway. + */ + lastin = cp_curin; + lastout = cp_curout; + lasterr = cp_curerr; + cp_curin = cp_in; + cp_curout = cp_out; + cp_curerr = cp_err; + + cp_pushcontrol(); + + /* We should now go through the deck and execute front-end + * commands and remove them. Front-end commands are enclosed by + * the cards .control and .endc, unless comfile + * is TRUE, in which case every line must be a front-end command. + * There are too many problems with matching the first word on + * the line. + */ + ld = deck; + if (comfile) { + /* This is easy. */ + for (dd = deck; dd; dd = ld) { + ld = dd->li_next; + if ((dd->li_line[0] == '*') && (dd->li_line[1] != '#')) + continue; + if (!ciprefix(".control", dd->li_line) && + !ciprefix(".endc", dd->li_line)) { + if (dd->li_line[0] == '*') + (void) cp_evloop(dd->li_line + 2); + else + (void) cp_evloop(dd->li_line); + } + tfree(dd->li_line); + tfree(dd); + } + } else { + for (dd = deck->li_next; dd; dd = ld->li_next) { + for (s = dd->li_line; (c = *s) && c <= ' '; s++) + ; + if (c == '*' && (s != deck->li_line || s[1] != '#')) { + ld = dd; + continue; + } + (void) strncpy(name, dd->li_line, BSIZE_SP); + for (s = name; *s && isspace(*s); s++) + ; + for (t = s; *t && !isspace(*t); t++) + ; + *t = '\0'; + + if (ciprefix(".control", dd->li_line)) { + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + if (commands) + fprintf(cp_err, + "Warning: redundant .control card\n"); + else + commands = TRUE; + } else if (ciprefix(".endc", dd->li_line)) { + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + if (commands) + commands = FALSE; + else + fprintf(cp_err, + "Warning: misplaced .endc card\n"); + } else if (commands || prefix("*#", dd->li_line)) { + wl = alloc(struct wordlist); + if (controls) { + wl->wl_next = controls; + controls->wl_prev = wl; + controls = wl; + } else + controls = wl; + if (prefix("*#", dd->li_line)) + wl->wl_word = copy(dd->li_line + 2); + else + wl->wl_word = dd->li_line; + ld->li_next = dd->li_next; + tfree(dd); + } else if (!*dd->li_line) { + /* So blank lines in com files don't get + * considered as circuits. + */ + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + } else { + inp_casefix(s); + inp_casefix(dd->li_line); + if (eq(s, ".width") || ciprefix(".four", s) || eq(s, ".plot") + || eq(s, ".print") || eq(s, ".save") + || eq(s, ".op") || eq(s, ".tf")) + { + if (end) { + end->wl_next = alloc(struct wordlist); + end->wl_next->wl_prev = end; + end = end->wl_next; + } else + wl_first = end = alloc(struct wordlist); + end->wl_word = copy(dd->li_line); + + if (!eq(s, ".op") && !eq(s, ".tf")) { + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + } else + ld = dd; + } else + ld = dd; + } + } + if (deck->li_next) { + /* There is something left after the controls. */ + fprintf(cp_out, "\nCircuit: %s\n\n", tt); + + /* Now expand subcircuit macros. Note that we have to + * fix the case before we do this but after we + * deal with the commands. + */ + if (!cp_getvar("nosubckt", VT_BOOL, (char *) + &nosubckts)) + deck->li_next = inp_subcktexpand(deck-> + li_next); + deck->li_actual = realdeck; + inp_dodeck(deck, tt, wl_first, FALSE, options, filename); + } + + /* Now that the deck is loaded, do the commands */ + if (controls) { + for (end = wl = wl_reverse(controls); wl; + wl = wl->wl_next) + (void) cp_evloop(wl->wl_word); + + wl_free(end); + /* MW. Memory leak fixed here */ + + } + } + + /* Now reset everything. Pop the control stack, and fix up the IO + * as it was before the source. + */ + cp_popcontrol(); + + cp_curin = lastin; + cp_curout = lastout; + cp_curerr = lasterr; + return; +} + +/* This routine is cut in half here because com_rset has to do what follows + * also. End is the list of commands we execute when the job is finished: + * we only bother with this if we might be running in batch mode, since + * it isn't much use otherwise. + */ + +void +inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse, struct line *options, char *filename) +{ + struct circ *ct; + struct line *dd; + char *ckt, *s; + INPtables *tab; + struct variable *eev = NULL; + wordlist *wl; + bool noparse, ii; + + /* First throw away any old error messages there might be and fix + * the case of the lines. + */ + for (dd = deck; dd; dd = dd->li_next) { + if (dd->li_error) { + tfree(dd->li_error); + dd->li_error = NULL; + } + } + if (reuse) { + ct = ft_curckt; + } else { + if (ft_curckt) { + ft_curckt->ci_devices = cp_kwswitch(CT_DEVNAMES, + (char *) NULL); + ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES, + (char *) NULL); + } + ft_curckt = ct = alloc(struct circ); + } + (void) cp_getvar("noparse", VT_BOOL, (char *) &noparse); + if (!noparse) + ckt = if_inpdeck(deck, &tab); + else + ckt = NULL; + + out_init(); + for (dd = deck; dd; dd = dd->li_next) + if (dd->li_error) { + char *p, *q; + p = dd->li_error; + do { + q =strchr(p, '\n'); + if (q) + *q = 0; + + if (p == dd->li_error) + out_printf("Error on line %d : %s\n\t%s\n", + dd->li_linenum, dd->li_line, dd->li_error); + else + out_printf("\t%s\n", p); + + if (q) + *q++ = '\n'; + p = q; + } while (p && *p); + } + + /* Add this circuit to the circuit list. If reuse is TRUE then + * use the ft_curckt structure. + */ + + if (!reuse) { +#ifdef notdef + /* Unused time-waster. */ + for (dd = deck->li_next; dd; dd = dd->li_next) + if_setndnames(dd->li_line); +#endif + + /* Be sure that ci_devices and ci_nodes are valid */ + ft_curckt->ci_devices = cp_kwswitch(CT_DEVNAMES, + (char *) NULL); + (void) cp_kwswitch(CT_DEVNAMES, ft_curckt->ci_devices); + ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES, (char *) NULL); + (void) cp_kwswitch(CT_NODENAMES, ft_curckt->ci_nodes); + ft_newcirc(ct); + /* ft_setccirc(); */ ft_curckt = ct; + } + ct->ci_name = tt; + ct->ci_deck = deck; + ct->ci_options = options; + if (deck->li_actual) + ct->ci_origdeck = deck->li_actual; + else + ct->ci_origdeck = ct->ci_deck; + ct->ci_ckt = ckt; + ct->ci_symtab = tab; + ct->ci_inprogress = FALSE; + ct->ci_runonce = FALSE; + ct->ci_commands = end; + if (filename) + ct->ci_filename = copy(filename); + else + ct->ci_filename = NULL; + + if (!noparse) { + for (; options; options = options->li_next) { + for (s = options->li_line; *s && !isspace(*s); s++) + ; + ii = cp_interactive; + cp_interactive = FALSE; + wl = cp_lexer(s); + cp_interactive = ii; + if (!wl || !wl->wl_word || !*wl->wl_word) + continue; + if (eev) + eev->va_next = cp_setparse(wl); + else + ct->ci_vars = eev = cp_setparse(wl); + while (eev->va_next) + eev = eev->va_next; + } + for (eev = ct->ci_vars; eev; eev = eev->va_next) { + static int one = 1; + switch (eev->va_type) { + case VT_BOOL: + if_option(ct->ci_ckt, eev->va_name, + eev->va_type, &one); + break; + case VT_NUM: + if_option(ct->ci_ckt, eev->va_name, + eev->va_type, (char *) &eev->va_num); + break; + case VT_REAL: + if_option(ct->ci_ckt, eev->va_name, + eev->va_type, (char *) &eev->va_real); + break; + case VT_STRING: + if_option(ct->ci_ckt, eev->va_name, + eev->va_type, eev->va_string); + break; + } + } + } + + cp_addkword(CT_CKTNAMES, tt); + return; +} + +/* Edit and re-load the current input deck. Note that if these commands are + * used on a non-unix machine, they will leave spice.tmp junk files lying + * around. + */ + +void +com_edit(wordlist *wl) +{ + char *filename; + FILE *fp; + bool inter, permfile; + char buf[BSIZE_SP]; + + inter = cp_interactive; + cp_interactive = FALSE; + if (wl) { + if (!doedit(wl->wl_word)) { + cp_interactive = inter; + return; + } + if (!(fp = inp_pathopen(wl->wl_word, "r"))) { + perror(wl->wl_word); + cp_interactive = inter; + return; + } + inp_spsource(fp, FALSE, wl->wl_word); + } else { + /* If there is no circuit yet, then create one */ + if (ft_curckt && ft_curckt->ci_filename) { + filename = ft_curckt->ci_filename; + permfile = TRUE; + } else { + filename = smktemp("sp"); + permfile = FALSE; + } + if (ft_curckt && !ft_curckt->ci_filename) { + if (!(fp = fopen(filename, "w"))) { + perror(filename); + cp_interactive = inter; + return; + } + inp_list(fp, ft_curckt->ci_deck, ft_curckt->ci_options, + LS_DECK); + fprintf(cp_err, + "Warning: editing a temporary file -- circuit not saved\n"); + (void) fclose(fp); + } else if (!ft_curckt) { + if (!(fp = fopen(filename, "w"))) { + perror(filename); + cp_interactive = inter; + return; + } + fprintf(fp, "SPICE 3 test deck\n"); + (void) fclose(fp); + } + if (!doedit(filename)) { + cp_interactive = inter; + return; + } + + if (!(fp = fopen(filename, "r"))) { + perror(filename); + cp_interactive = inter; + return; + } + inp_spsource(fp, FALSE, permfile ? filename : (char *) NULL); + + /* (void) fclose(fp); */ + /* MW. inp_spsource already closed fp */ + + if (ft_curckt && !ft_curckt->ci_filename) + (void) unlink(filename); + } + + cp_interactive = inter; + + /* note: default is to run circuit after successful edit */ + + fprintf(cp_out, "run circuit? "); + fflush(cp_out); + (void) fgets(buf, BSIZE_SP, stdin); + if (buf[0] != 'n') { + fprintf(cp_out, "running circuit\n"); + com_run(NULL); + } + + return; +} + +static bool +doedit(char *filename) +{ + char buf[BSIZE_SP], buf2[BSIZE_SP], *editor; + + if (cp_getvar("editor", VT_STRING, buf2)) { + editor = buf2; + } else { + if (!(editor = getenv("EDITOR"))) { + if (Def_Editor && *Def_Editor) + editor = Def_Editor; + else + editor = "/usr/ucb/vi"; + } + } + (void) sprintf(buf, "%s %s", editor, filename); + return (system(buf) ? FALSE : TRUE); + +} + +void +com_source(wordlist *wl) +{ + + FILE *fp, *tp; + char buf[BSIZE_SP]; + bool inter; + char *tempfile = NULL; + + wordlist *owl = wl; + int i; + + inter = cp_interactive; + cp_interactive = FALSE; + if (wl->wl_next) { + /* There are several files -- put them into a temp file */ + tempfile = smktemp("sp"); + if (!(fp = inp_pathopen(tempfile, "w+"))) { + perror(tempfile); + cp_interactive = TRUE; + return; + } + while (wl) { + if (!(tp = inp_pathopen(wl->wl_word, "r"))) { + perror(wl->wl_word); + (void) fclose(fp); + cp_interactive = TRUE; + (void) unlink(tempfile); + return; + } + while ((i = fread(buf, 1, BSIZE_SP, tp)) > 0) + (void) fwrite(buf, 1, i, fp); + (void) fclose(tp); + wl = wl->wl_next; + } + (void) fseek(fp, (long) 0, 0); + } else + fp = inp_pathopen(wl->wl_word, "r"); + if (fp == NULL) { + perror(wl->wl_word); + cp_interactive = TRUE; + return; + } + + /* Don't print the title if this is a .spiceinit file. */ + if (ft_nutmeg || substring(".spiceinit", owl->wl_word) + || substring("spice.rc", owl->wl_word)) + inp_spsource(fp, TRUE, tempfile ? (char *) NULL : wl->wl_word); + else + inp_spsource(fp, FALSE, tempfile ? (char *) NULL : wl->wl_word); + cp_interactive = inter; + if (tempfile) + (void) unlink(tempfile); + return; +} + +void +inp_source(char *file) +{ + static struct wordlist wl = { NULL, NULL, NULL } ; + wl.wl_word = file; + com_source(&wl); + return; +} diff --git a/src/frontend/inp.h b/src/frontend/inp.h new file mode 100644 index 000000000..1ec0dfa84 --- /dev/null +++ b/src/frontend/inp.h @@ -0,0 +1,19 @@ +/************* + * Header file for inp.c + * 1999 E. Rouat + ************/ + +#ifndef INP_H_INCLUDED +#define INP_H_INCLUDED + +void com_listing(wordlist *wl); +void inp_list(FILE *file, struct line *deck, struct line *extras, int type); +void inp_spsource(FILE *fp, bool comfile, char *filename); +void inp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse, + struct line *options, char *filename); +void com_edit(wordlist *wl); +void com_source(wordlist *wl); +void inp_source(char *file); + + +#endif diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c new file mode 100644 index 000000000..bef3c6203 --- /dev/null +++ b/src/frontend/inpcom.c @@ -0,0 +1,268 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher +**********/ + +/* + * For dealing with spice input decks and command scripts + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteinp.h" +#include "inpcom.h" + + +/* This routine reads a line (of arbitrary length), up to a '\n' or 'EOF' + * and returns a pointer to the resulting null terminated string. + * The '\n' if found, is included in the returned string. + * From: jason@ucbopal.BERKELEY.EDU (Jason Venner) + * Newsgroups: net.sources + */ + +#define STRGROW 256 + +static char * +readline(FILE *fd) +{ + int c; + int memlen; + char *strptr; + int strlen; + + strptr = NULL; + strlen = 0; + memlen = STRGROW; + strptr = tmalloc(memlen); + memlen -= 1; /* Save constant -1's in while loop */ + while((c = getc(fd)) != EOF) { + if (strlen == 0 && c == '\n') + continue; + strptr[strlen] = c; + strlen++; + if( strlen >= memlen ) { + memlen += STRGROW; + if( !(strptr = trealloc(strptr, memlen + 1))) { + return (NULL); + } + } + if (c == '\n') { + break; + } + } + if (!strlen) { + free(strptr); + return (NULL); + } + strptr[strlen] = '\0'; + /* Trim the string */ + strptr = trealloc(strptr, strlen + 1); + return (strptr); +} + +/* Look up the variable sourcepath and try everything in the list in order + * if the file isn't in . and it isn't an abs path name. + */ + +FILE * +inp_pathopen(char *name, char *mode) +{ + FILE *fp; + char buf[BSIZE_SP]; + struct variable *v; + + /* If this is an abs pathname, or there is no sourcepath var, just + * do an fopen. + */ + if (index(name, DIR_TERM) + || !cp_getvar("sourcepath", VT_LIST, (char *) &v)) + return (fopen(name, mode)); + + while (v) { + switch (v->va_type) { + case VT_STRING: + cp_wstrip(v->va_string); + (void) sprintf(buf, "%s%s%s", v->va_string, DIR_PATHSEP, name); + break; + case VT_NUM: + (void) sprintf(buf, "%d%s%s", v->va_num, DIR_PATHSEP, name); + break; + case VT_REAL: /* This is foolish */ + (void) sprintf(buf, "%g%s%s", v->va_real, DIR_PATHSEP, name); + break; + } + if ((fp = fopen(buf, mode))) + return (fp); + v = v->va_next; + } + return (NULL); +} + +/* Read the entire input file and return a pointer to the first line of + * the linked list of 'card' records in data. + */ + +void +inp_readall(FILE *fp, struct line **data) +{ + struct line *end = NULL, *cc, *prev = NULL, *working, *newcard; + char *buffer, *s, *t, c; + int line = 1; + FILE *newfp; + + while ((buffer = readline(fp))) { + if (*buffer == '@') + break; + for (s = buffer; *s && (*s != '\n'); s++) + ; + if (!*s) { + fprintf(cp_err, "Warning: premature EOF\n"); + } + *s = '\0'; /* Zap the newline. */ + + if (ciprefix(".include", buffer)) { + for (s = buffer; *s && !isspace(*s); s++) + ; + while (isspace(*s)) + s++; + if (!*s) { + fprintf(cp_err, + "Error: .include filename missing\n"); + continue; + } + for (t = s; *t && !isspace(*t); t++) + ; + *t = '\0'; + if (*s == '~') + s = cp_tildexpand(s); + if (!(newfp = inp_pathopen(s, "r"))) { + perror(s); + continue; + } + inp_readall(newfp, &newcard); + (void) fclose(newfp); + + /* Make the .include a comment */ + *buffer = '*'; + if (end) { + end->li_next = alloc(struct line); + end = end->li_next; + } else { + end = cc = alloc(struct line); + } + end->li_next = NULL; + end->li_error = NULL; + end->li_actual = NULL; + end->li_line = copy(buffer); + end->li_linenum = line++; + end->li_next = newcard; + + /* Renumber the lines */ + for (end = newcard; end && end->li_next; end = end->li_next) + end->li_linenum = line++; + + /* Fix the buffer up a bit. */ + (void) strncpy(buffer + 1, "end of:", 7); + } + + if (end) { + end->li_next = alloc(struct line); + end = end->li_next; + } else { + end = cc = alloc(struct line); + } + end->li_next = NULL; + end->li_error = NULL; + end->li_actual = NULL; + end->li_line = buffer; + end->li_linenum = line++; + } + if (!end) { /* No stuff here */ + *data = NULL; + return; + } + + /* Now make logical lines. */ + working = cc->li_next; /* Skip title. */ + + while (working) { + for (s = working->li_line; (c = *s) && c <= ' '; s++) + ; + switch (c) { + case '#': + case '$': + case '*': + case '\0': + /* + prev = NULL; + */ + working = working->li_next; + break; + case '+': + if (!prev) { + working->li_error = copy( + "Illegal continuation line: ignored."); + working = working->li_next; + break; + } + buffer = tmalloc(strlen(prev->li_line) + strlen(s) + 2); + (void) sprintf(buffer, "%s %s", prev->li_line, s + 1); + s = prev->li_line; + prev->li_line = buffer; + prev->li_next = working->li_next; + working->li_next = NULL; + if (prev->li_actual) { + for (end = prev->li_actual; + end->li_next; end = end->li_next) + ; + end->li_next = working; + tfree(s); + } else { + newcard = alloc(struct line); + newcard->li_linenum = prev->li_linenum; + newcard->li_line = s; + newcard->li_next = working; + newcard->li_error = NULL; + newcard->li_actual = NULL; + prev->li_actual = newcard; + } + working = prev->li_next; + break; + default: + prev = working; + working = working->li_next; + break; + } + } + + *data = cc; + return; +} + +void +inp_casefix(register char *string) +{ +#ifdef HAVE_CTYPE_H + if (string) + while (*string) { + /* Let's make this really idiot-proof. */ +#ifdef HAS_ASCII + *string = strip(*string); +#endif + if (*string == '"') { + *string++ = ' '; + while (*string && *string != '"') string++; + if (*string == '"') *string = ' '; + } + if (!isspace(*string) && !isprint(*string)) + *string = '_'; + if (isupper(*string)) + *string = tolower(*string); + string++; + } + return; +#endif +} diff --git a/src/frontend/inpcom.h b/src/frontend/inpcom.h new file mode 100644 index 000000000..0eb243435 --- /dev/null +++ b/src/frontend/inpcom.h @@ -0,0 +1,13 @@ +/************* + * Header file for inpcom.c + * 1999 E. Rouat + ************/ + +#ifndef INPCOM_H_INCLUDED +#define INPCOM_H_INCLUDED + +FILE * inp_pathopen(char *name, char *mode); +void inp_readall(FILE *fp, struct line **data); +void inp_casefix(register char *string); + +#endif diff --git a/src/frontend/interp.c b/src/frontend/interp.c new file mode 100644 index 000000000..b5957d1d5 --- /dev/null +++ b/src/frontend/interp.c @@ -0,0 +1,385 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Polynomial interpolation code. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "interp.h" + + +/* Interpolate data from oscale to nscale. data is assumed to be olen long, + * ndata will be nlen long. Returns FALSE if the scales are too strange + * to deal with. Note that we are guaranteed that either both scales are + * strictly increasing or both are strictly decreasing. + */ + + +/* static declarations */ +static int putinterval(double *poly, int degree, double *nvec, int last, double *nscale, + int nlen, double oval, int sign); +static void printmat(char *name, double *mat, int m, int n); + + +bool +ft_interpolate(double *data, double *ndata, double *oscale, int olen, double *nscale, int nlen, int degree) +{ + double *result, *scratch, *xdata, *ydata; + int sign, lastone, i, l; + + if ((olen < 2) || (nlen < 2)) { + fprintf(cp_err, "Error: lengths too small to interpolate.\n"); + return (FALSE); + } + if ((degree < 1) || (degree > olen)) { + fprintf(cp_err, "Error: degree is %d, can't interpolate.\n", + degree); + return (FALSE); + } + + if (oscale[1] < oscale[0]) + sign = -1; + else + sign = 1; + + scratch = (double *) tmalloc((degree + 1) * (degree + 2) * + sizeof (double)); + result = (double *) tmalloc((degree + 1) * sizeof (double)); + xdata = (double *) tmalloc((degree + 1) * sizeof (double)); + ydata = (double *) tmalloc((degree + 1) * sizeof (double)); + + /* Deal with the first degree pieces. */ + bcopy((char *) data, (char *) ydata, (degree + 1) * sizeof (double)); + bcopy((char *) oscale, (char *) xdata, (degree + 1) * sizeof (double)); + + while (!ft_polyfit(xdata, ydata, result, degree, scratch)) { + /* If it doesn't work this time, bump the interpolation + * degree down by one. + */ + + if (--degree == 0) { + fprintf(cp_err, "ft_interpolate: Internal Error.\n"); + return (FALSE); + } + + } + + /* Add this part of the curve. What we do is evaluate the polynomial + * at those points between the last one and the one that is greatest, + * without being greater than the leftmost old scale point, or least + * if the scale is decreasing at the end of the interval we are looking + * at. + */ + lastone = -1; + for (i = 0; i < degree; i++) { + lastone = putinterval(result, degree, ndata, lastone, + nscale, nlen, xdata[i], sign); + } + + /* Now plot the rest, piece by piece. l is the + * last element under consideration. + */ + for (l = degree + 1; l < olen; l++) { + + /* Shift the old stuff by one and get another value. */ + for (i = 0; i < degree; i++) { + xdata[i] = xdata[i + 1]; + ydata[i] = ydata[i + 1]; + } + ydata[i] = data[l]; + xdata[i] = oscale[l]; + + while (!ft_polyfit(xdata, ydata, result, degree, scratch)) { + if (--degree == 0) { + fprintf(cp_err, + "interpolate: Internal Error.\n"); + return (FALSE); + } + } + lastone = putinterval(result, degree, ndata, lastone, + nscale, nlen, xdata[i], sign); + } + if (lastone < nlen - 1) /* ??? */ + ndata[nlen - 1] = data[olen - 1]; + tfree(scratch); + tfree(xdata); + tfree(ydata); + tfree(result); + return (TRUE); +} + +/* Takes n = (degree+1) doubles, and fills in result with the n coefficients + * of the polynomial that will fit them. It also takes a pointer to an + * array of n ^ 2 + n doubles to use for scratch -- we want to make this + * fast and avoid doing mallocs for each call. + */ + +bool +ft_polyfit(double *xdata, double *ydata, double *result, int degree, double *scratch) +{ + register double *mat1 = scratch; + register int l, k, j, i; + register int n = degree + 1; + register double *mat2 = scratch + n * n; /* XXX These guys are hacks! */ + double d; + +/* +fprintf(cp_err, "n = %d, xdata = ( ", n); + for (i = 0; i < n; i++) + fprintf(cp_err, "%G ", xdata[i]); + fprintf(cp_err, ")\n"); + fprintf(cp_err, "ydata = ( "); + for (i = 0; i < n; i++) + fprintf(cp_err, "%G ", ydata[i]); + fprintf(cp_err, ")\n"); +*/ + + bzero((char *) result, n * sizeof(double)); + bzero((char *) mat1, n * n * sizeof (double)); + bcopy((char *) ydata, (char *) mat2, n * sizeof (double)); + + /* Fill in the matrix with x^k for 0 <= k <= degree for each point */ + l = 0; + for (i = 0; i < n; i++) { + d = 1.0; + for (j = 0; j < n; j++) { + mat1[l] = d; + d *= xdata[i]; + l += 1; + } + } + + /* Do Gauss-Jordan elimination on mat1. */ + for (i = 0; i < n; i++) { + int lindex; + double largest; + /* choose largest pivot */ + for (j=i, largest = mat1[i * n + i], lindex = i; j < n; j++) { + if (fabs(mat1[j * n + i]) > largest) { + largest = fabs(mat1[j * n + i]); + lindex = j; + } + } + if (lindex != i) { + /* swap rows i and lindex */ + for (k = 0; k < n; k++) { + d = mat1[i * n + k]; + mat1[i * n + k] = mat1[lindex * n + k]; + mat1[lindex * n + k] = d; + } + d = mat2[i]; + mat2[i] = mat2[lindex]; + mat2[lindex] = d; + } +#ifdef notdef + if (mat1[i * n + i] == 0.0) + for (j = i; j < n; j++) + if (mat1[j * n + i] != 0.0) { + /* Swap rows i and j. */ + for (k = 0; k < n; k++) { + d = mat1[i * n + k]; + mat1[i * n + k] = + mat1[j * n + k]; + mat1[j * n + k] = d; + } + d = mat2[i]; + mat2[i] = mat2[j]; + mat2[j] = d; + break; + } +#endif + /* Make sure we have a non-zero pivot. */ + if (mat1[i * n + i] == 0.0) { + /* this should be rotated. */ + return (FALSE); + } + for (j = i + 1; j < n; j++) { + d = mat1[j * n + i] / mat1[i * n + i]; + for (k = 0; k < n; k++) + mat1[j * n + k] -= d * mat1[i * n + k]; + mat2[j] -= d * mat2[i]; + } + } + + for (i = n - 1; i > 0; i--) + for (j = i - 1; j >= 0; j--) { + d = mat1[j * n + i] / mat1[i * n + i]; + for (k = 0; k < n; k++) + mat1[j * n + k] -= + d * mat1[i * n + k]; + mat2[j] -= d * mat2[i]; + } + + /* Now write the stuff into the result vector. */ + for (i = 0; i < n; i++) { + result[i] = mat2[i] / mat1[i * n + i]; + /* printf(cp_err, "result[%d] = %G\n", i, result[i]);*/ + } + +#define ABS_TOL 0.001 +#define REL_TOL 0.001 + + /* Let's check and make sure the coefficients are ok. If they aren't, + * just return FALSE. This is not the best way to do it. + */ + for (i = 0; i < n; i++) { + d = ft_peval(xdata[i], result, degree); + if (fabs(d - ydata[i]) > ABS_TOL) { + /* + fprintf(cp_err, + "Error: polyfit: x = %le, y = %le, int = %le\n", + xdata[i], ydata[i], d); + printmat("mat1", mat1, n, n); + printmat("mat2", mat2, n, 1); + */ + return (FALSE); + } else if (fabs(d - ydata[i]) / (fabs(d) > ABS_TOL ? fabs(d) : + ABS_TOL) > REL_TOL) { + /* + fprintf(cp_err, + "Error: polyfit: x = %le, y = %le, int = %le\n", + xdata[i], ydata[i], d); + printmat("mat1", mat1, n, n); + printmat("mat2", mat2, n, 1); + */ + return (FALSE); + } + } + + return (TRUE); +} + +/* Returns thestrchr of the last element that was calculated. oval is the + * value of the old scale at the end of the interval that is being interpolated + * from, and sign is 1 if the old scale was increasing, and -1 if it was + * decreasing. + */ + +static int +putinterval(double *poly, int degree, double *nvec, int last, double *nscale, int nlen, double oval, int sign) +{ + int end, i; + + /* See how far we have to go. */ + for (end = last + 1; end < nlen; end++) + if (nscale[end] * sign > oval * sign) + break; + end--; + + for (i = last + 1; i <= end; i++) + nvec[i] = ft_peval(nscale[i], poly, degree); + return (end); +} + +static void +printmat(char *name, double *mat, int m, int n) +{ + int i, j; + + printf("\n\r=== Matrix: %s ===\n\r", name); + for (i = 0; i < m; i++) { + printf(" | "); + for (j = 0; j < n; j++) + printf("%G ", mat[i * n + j]); + printf("|\n\r"); + } + printf("===\n\r"); + return; +} + +double +ft_peval(double x, double *coeffs, int degree) +{ + double y; + int i; + + if (!coeffs) + return 0.0; /* XXX Should not happen */ + + y = coeffs[degree]; /* there are (degree+1) coeffs */ + + for (i = degree - 1; i >= 0; i--) { + y *= x; + y += coeffs[i]; + } + + return y; +} + +#ifdef notdef + +XXX The following code is rediculous + +/* This should be a macro or be asm coded if possible. */ + +double +ft_peval(pt, coeffs, degree) + double pt, *coeffs; + register int degree; +{ + register int i, j; + double d = 0.0, f; + + /* fprintf(cp_err, "peval "); + for (i = 0; i <= degree; i++) + fprintf(cp_err, "%G ", coeffs[i]); + fprintf(cp_err, "at %G", pt); + */ + for (i = 0; i <= degree; i++) { + f = 1.0; + for (j = 0; j < i; j++) + f *= pt; + d += f * coeffs[i]; + } + /* fprintf(cp_err, " = %G\n", d);*/ + return (d); +} +#endif + +void +lincopy(struct dvec *ov, double *newscale, int newlen, struct dvec *oldscale) +{ + struct dvec *v; + double *nd; + + if (!isreal(ov)) { + fprintf(cp_err, "Warning: %s is not real\n", ov->v_name); + return; + } + if (ov->v_length < oldscale->v_length) { + fprintf(cp_err, "Warning: %s is too short\n", ov->v_name); + return; + } + v = alloc(struct dvec); + v->v_name = copy(ov->v_name); + v->v_type = ov->v_type; + v->v_flags = ov->v_flags; + v->v_flags |= VF_PERMANENT; + v->v_length = newlen; + + nd = (double *) tmalloc(newlen * sizeof (double)); + if (!ft_interpolate(ov->v_realdata, nd, oldscale->v_realdata, + oldscale->v_length, newscale, newlen, 1)) { + fprintf(cp_err, "Error: can't interpolate %s\n", ov->v_name); + return; + } + v->v_realdata = nd; + vec_new(v); + return; +} + +void +ft_polyderiv(double *coeffs, int degree) +{ + int i; + + for (i = 0; i < degree; i++) { + coeffs[i] = (i + 1) * coeffs[i + 1]; + } +} diff --git a/src/frontend/interp.h b/src/frontend/interp.h new file mode 100644 index 000000000..248357f0a --- /dev/null +++ b/src/frontend/interp.h @@ -0,0 +1,17 @@ +/************* + * Header file for interp.c + * 1999 E. Rouat + ************/ + +#ifndef INTERP_H_INCLUDED +#define INTERP_H_INCLUDED + +bool ft_interpolate(double *data, double *ndata, double *oscale, int olen, double *nscale, + int nlen, int degree); +bool ft_polyfit(double *xdata, double *ydata, double *result, int degree, double *scratch); +double ft_peval(double x, double *coeffs, int degree); +void lincopy(struct dvec *ov, double *newscale, int newlen, struct dvec *oldscale); +void ft_polyderiv(double *coeffs, int degree); + + +#endif diff --git a/src/frontend/linear.c b/src/frontend/linear.c new file mode 100644 index 000000000..0ac8006fc --- /dev/null +++ b/src/frontend/linear.c @@ -0,0 +1,99 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "linear.h" + + +/* Interpolate all the vectors in a plot to a linear time scale, which + * we determine by looking at the transient parameters in the CKT struct. + */ + + +extern void lincopy (struct dvec *ov, double *newscale, int newlen, struct dvec *oldscale); + +void +com_linearize(wordlist *wl) +{ + double tstart, tstop, tstep, d; + struct plot *new, *old; + struct dvec *newtime, *v; + struct dvec *oldtime; + int len, i; + char buf[BSIZE_SP]; + + if (!ft_curckt || !ft_curckt->ci_ckt || + !if_tranparams(ft_curckt, &tstart, &tstop, &tstep)) { + fprintf(cp_err, + "Error: can't get transient parameters from circuit\n"); + return; + } + if (((tstop - tstart) * tstep <= 0.0) || ((tstop - tstart) < tstep)) { + fprintf(cp_err, + "Error: bad parameters -- start = %G, stop = %G, step = %G\n", + tstart, tstop, tstep); + return; + } + if (!plot_cur || !plot_cur->pl_dvecs || !plot_cur->pl_scale) { + fprintf(cp_err, "Error: no vectors available\n"); + return; + } + if (!isreal(plot_cur->pl_scale)) { + fprintf(cp_err, "Error: non-real time scale for %s\n", + plot_cur->pl_typename); + return; + } + if (!ciprefix("tran", plot_cur->pl_typename)) { + fprintf(cp_err, "Error: plot must be a transient analysis\n"); + return; + } + old = plot_cur; + oldtime = old->pl_scale; + new = plot_alloc("transient"); + (void) sprintf(buf, "%s (linearized)", old->pl_name); + new->pl_name = copy(buf); + new->pl_title = copy(old->pl_title); + new->pl_date = copy(old->pl_date); + new->pl_next = plot_list; + plot_new(new); + plot_setcur(new->pl_typename); + plot_list = new; + len = (tstop - tstart) / tstep + 1.5; + newtime = alloc(struct dvec); + newtime->v_name = copy(oldtime->v_name); + newtime->v_type = oldtime->v_type; + newtime->v_flags = oldtime->v_flags; + newtime->v_flags |= VF_PERMANENT; + newtime->v_length = len; + newtime->v_plot = new; + newtime->v_realdata = (double *) tmalloc(len * sizeof (double)); + for (i = 0, d = tstart; i < len; i++, d += tstep) + newtime->v_realdata[i] = d; + new->pl_scale = new->pl_dvecs = newtime; + + if (wl) { + while (wl) { + v = vec_fromplot(wl->wl_word, old); + if (!v) { + fprintf(cp_err, "Error: no such vector %s\n", + wl->wl_word); + continue; + } + lincopy(v, newtime->v_realdata, len, oldtime); + wl = wl->wl_next; + } + } else { + for (v = old->pl_dvecs; v; v = v->v_next) { + if (v == old->pl_scale) + continue; + lincopy(v, newtime->v_realdata, len, oldtime); + } + } + return; + +} diff --git a/src/frontend/linear.h b/src/frontend/linear.h new file mode 100644 index 000000000..fff8e8f49 --- /dev/null +++ b/src/frontend/linear.h @@ -0,0 +1,12 @@ +/************* + * Header file for linear.c + * 1999 E. Rouat + ************/ + +#ifndef LINEAR_H_INCLUDED +#define LINEAR_H_INCLUDED + +void com_linearize(wordlist *wl); + + +#endif diff --git a/src/frontend/misccoms.c b/src/frontend/misccoms.c new file mode 100644 index 000000000..636e4f3b7 --- /dev/null +++ b/src/frontend/misccoms.c @@ -0,0 +1,392 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftehelp.h" +#include "hlpdefs.h" +#include "misccoms.h" + + +static void byemesg(void); + +void +com_help(wordlist *wl) +{ + struct comm *c; + struct comm *ccc[512]; /* Should be enough. */ + int numcoms, i; + bool allflag = FALSE; + + if (wl && eq(wl->wl_word, "all")) { + allflag = TRUE; + wl = NULL; /* XXX Probably right */ + } + + /* We want to use more mode whether "moremode" is set or not. */ + out_moremode = TRUE; + out_init(); + out_moremode = FALSE; + if (wl == NULL) { + out_printf( + "For a complete description read the Spice3 User's Manual manual.\n"); + + if (!allflag) { + out_printf( + "For a list of all commands type \"help all\", for a short\n"); + out_printf( + "description of \"command\", type \"help command\".\n"); + } + + /* Sort the commands */ + for (numcoms = 0; cp_coms[numcoms].co_func != NULL; numcoms++) + ccc[numcoms] = &cp_coms[numcoms]; + qsort((char *) ccc, numcoms, sizeof (struct comm *), hcomp); + + for (i = 0; i < numcoms; i++) { + if ((ccc[i]->co_spiceonly && ft_nutmeg) || + (ccc[i]->co_help == NULL) || + (!allflag && !ccc[i]->co_major)) + continue; + out_printf("%s ", ccc[i]->co_comname); + out_printf(ccc[i]->co_help, cp_program); + out_send("\n"); + } + } else { + while (wl != NULL) { + for (c = &cp_coms[0]; c->co_func != NULL; c++) + if (eq(wl->wl_word, c->co_comname)) { + out_printf("%s ", c->co_comname); + out_printf(c->co_help, cp_program); + if (c->co_spiceonly && ft_nutmeg) + out_send( + " (Not available in nutmeg)"); + out_send("\n"); + break; + } + if (c->co_func == NULL) { + /* See if this is aliased. */ + struct alias *al; + + for (al = cp_aliases; al; al = al->al_next) + if (eq(al->al_name, wl->wl_word)) + break; + if (al == NULL) + fprintf(cp_out, + "Sorry, no help for %s.\n", + wl->wl_word); + else { + out_printf("%s is aliased to ", + wl->wl_word); + /* Minor badness here... */ + wl_print(al->al_text, cp_out); + out_send("\n"); + } + } + wl = wl->wl_next; + } + } + out_send("\n"); + return; +} + +void +com_ahelp(wordlist *wl) +{ + + int i, n; + /* assert: number of commands must be less than 512 */ + struct comm *cc[512]; + int env = 0; + struct comm *com; + int level; + char slevel[256]; + + if (wl) { + com_help(wl); + return; + } + + out_init(); + + /* determine environment */ + if (plot_list->pl_next) { /* plots load */ + env |= E_HASPLOTS; + } else { + env |= E_NOPLOTS; + } + + /* determine level */ + if (cp_getvar("level", VT_STRING, slevel)) { + switch (*slevel) { + case 'b': level = 1; + break; + case 'i': level = 2; + break; + case 'a': level = 4; + break; + default: level = 1; + break; + } + } else { + level = 1; + } + + out_printf( + "For a complete description read the Spice3 User's Manual manual.\n"); + out_printf( + "For a list of all commands type \"help all\", for a short\n"); + out_printf( + "description of \"command\", type \"help command\".\n"); + + /* sort the commands */ + for (n = 0; cp_coms[n].co_func != (void (*)()) NULL; n++) { + cc[n] = &cp_coms[n]; + } + qsort((char *) cc, n, sizeof(struct comm *), hcomp); + + /* filter the commands */ + for (i=0; i< n; i++) { + com = cc[i]; + if ((com->co_env < (level << 13)) && (!(com->co_env & 4095) || + (env & com->co_env))) { + if ((com->co_spiceonly && ft_nutmeg) || + (com->co_help == (char *) NULL)) { + continue; + } + out_printf("%s ", com->co_comname); + out_printf(com->co_help, cp_program); + out_send("\n"); + } + } + + out_send("\n"); + + return; + +} + +void +com_ghelp(wordlist *wl) +{ + char *npath, *path = Help_Path, buf[BSIZE_SP]; + int i; + + if (cp_getvar("helppath", VT_STRING, buf)) + path = copy(buf); + if (!path) { + fprintf(cp_err, "Note: defaulting to old help.\n\n"); + com_help(wl); + return; + } + if (!(npath = cp_tildexpand(path))) { + fprintf(cp_err, "Note: can't find help dir %s\n", path); + fprintf(cp_err, "Defaulting to old help.\n\n"); + com_help(wl); + return; + } + path = npath; + if (cp_getvar("helpregfont", VT_STRING, buf)) + hlp_regfontname = copy(buf); + if (cp_getvar("helpboldfont", VT_STRING, buf)) + hlp_boldfontname = copy(buf); + if (cp_getvar("helpitalicfont", VT_STRING, buf)) + hlp_italicfontname = copy(buf); + if (cp_getvar("helptitlefont", VT_STRING, buf)) + hlp_titlefontname = copy(buf); + if (cp_getvar("helpbuttonfont", VT_STRING, buf)) + hlp_buttonfontname = copy(buf); + if (cp_getvar("helpinitxpos", VT_NUM, (char *) &i)) + hlp_initxpos = i; + if (cp_getvar("helpinitypos", VT_NUM, (char *) &i)) + hlp_initypos = i; + if (cp_getvar("helpbuttonstyle", VT_STRING, buf)) { + if (cieq(buf, "left")) + hlp_buttonstyle = BS_LEFT; + else if (cieq(buf, "center")) + hlp_buttonstyle = BS_CENTER; + else if (cieq(buf, "unif")) + hlp_buttonstyle = BS_UNIF; + else + fprintf(cp_err, "Warning: no such button style %s\n", + buf); + } + if (cp_getvar("width", VT_NUM, (char *) &i)) + hlp_width = i; + if (cp_getvar("display", VT_STRING, buf)) + hlp_displayname = copy(buf); + else if (cp_getvar("device", VT_STRING, buf)) + hlp_displayname = copy(buf); + else + hlp_displayname = NULL; + hlp_main(path, wl); + return; +} + +int +hcomp(struct comm **c1, struct comm **c2) +{ + return (strcmp((*c1)->co_comname, (*c2)->co_comname)); +} + + +void +com_quit(wordlist *wl) +{ + struct circ *cc; + struct plot *pl; + int ncc = 0, npl = 0; + char buf[64]; + bool noask; + + (void) cp_getvar("noaskquit", VT_BOOL, (char *) &noask); + gr_clean(); + cp_ccon(FALSE); + + /* Make sure the guy really wants to quit. */ + if (!ft_nutmeg && !noask) { + for (cc = ft_circuits; cc; cc = cc->ci_next) + if (cc->ci_inprogress) + ncc++; + for (pl = plot_list; pl; pl = pl->pl_next) + if (!pl->pl_written && pl->pl_dvecs) + npl++; + if (ncc || npl) { + fprintf(cp_out, "Warning: "); + if (ncc) { + fprintf(cp_out, + "the following simulation%s still in progress:\n", + (ncc > 1) ? "s are" : " is"); + for (cc = ft_circuits; cc; cc = cc->ci_next) + if (cc->ci_inprogress) + fprintf(cp_out, "\t%s\n", + cc->ci_name); + } + if (npl) { + if (ncc) + fprintf(cp_out, "and "); + fprintf(cp_out, + "the following plot%s been saved:\n", + (npl > 1) ? "s haven't" : " hasn't"); + for (pl = plot_list; pl; pl = pl->pl_next) + if (!pl->pl_written && pl->pl_dvecs) + fprintf(cp_out, "%s\t%s, %s\n", + pl->pl_typename, + pl->pl_title, + pl->pl_name); + } + fprintf(cp_out, + "\nAre you sure you want to quit (yes)? "); + (void) fflush(cp_out); + if (!fgets(buf, BSIZE_SP, stdin)) { + clearerr(stdin); + *buf = 'y'; + } + if ((*buf == 'y') || (*buf == 'Y') || (*buf == '\n')) + byemesg(); + else { + return; + } + } else + byemesg(); + } else + byemesg(); + + exit(EXIT_NORMAL); + +} + + +#ifdef SYSTEM_MAIL +#define MAIL_BUGS_ +#endif + +#ifdef MAIL_BUGS_ + + +void +com_bug(wordlist *wl) +{ + char buf[BSIZE_SP]; + + if (!Bug_Addr || !*Bug_Addr) { + fprintf(cp_err, "Error: No address to send bug reports to.\n"); + return; + } + fprintf(cp_out, "Calling the mail program . . .(sending to %s)\n\n", + Bug_Addr); + fprintf(cp_out, + "Please include the OS version number and machine architecture.\n"); + fprintf(cp_out, + "If the problem is with a specific circuit, please include the\n"); + fprintf(cp_out, "input file.\n"); + + (void) sprintf(buf, SYSTEM_MAIL, ft_sim->simulator, + ft_sim->version, Bug_Addr); + (void) system(buf); + fprintf(cp_out, "Bug report sent. Thank you.\n"); + return; +} + +#else + + +void +com_bug(wordlist *wl) +{ + fprintf(cp_out, "Send mail to the address ng-spice@ieee.ing.uniroma1.it\n"); + return; +} + +#endif + +void +com_version(wordlist *wl) +{ + char *s; + + if (!wl) { + fprintf(cp_out, "******\n"); + + fprintf(cp_out, "** %s-%s : %s\n", ft_sim->simulator, + ft_sim->version, ft_sim->description); + fprintf(cp_out, "** The U. C. Berkeley CAD Group\n"); + fprintf(cp_out, + "** Copyright 1985-1994, Regents of the University of California.\n"); + if (Spice_Notice && *Spice_Notice) + fprintf(cp_out, "** %s\n", Spice_Notice); + if (Spice_Build_Date && *Spice_Build_Date) + fprintf(cp_out, "** Creation Date: %s\n", Spice_Build_Date); + fprintf(cp_out, "******\n"); + + } else { + s = wl_flatten(wl); + if (!strncmp(s, "-s", 2)) { + fprintf(cp_out, "******\n"); + fprintf(cp_out, "** %s-%s\n", ft_sim->simulator, + ft_sim->version); + if (Spice_Notice && *Spice_Notice) + fprintf(cp_out, "** %s\n", Spice_Notice); + if (Spice_Build_Date && *Spice_Build_Date) + fprintf(cp_out, "** Creation Date: %s\n", Spice_Build_Date); + fprintf(cp_out, "******\n"); + } else if (!eq(ft_sim->version, s)) { + fprintf(stderr, + "Note: rawfile is version %s (current version is %s)\n", + wl->wl_word, ft_sim->version); + } + tfree(s); + } + return; +} + +static void +byemesg(void) +{ + printf("%s-%s done\n", ft_sim->simulator, ft_sim->version); + return; +} diff --git a/src/frontend/misccoms.h b/src/frontend/misccoms.h new file mode 100644 index 000000000..849f84c92 --- /dev/null +++ b/src/frontend/misccoms.h @@ -0,0 +1,18 @@ +/************* + * Header file for misccoms.c + * 1999 E. Rouat + ************/ + +#ifndef MISCCOMS_H_INCLUDED +#define MISCCOMS_H_INCLUDED + +void com_help(wordlist *wl); +void com_ahelp(wordlist *wl); +void com_ghelp(wordlist *wl); +int hcomp(struct comm **c1, struct comm **c2); +void com_quit(wordlist *wl); +void com_bug(wordlist *wl); +void com_version(wordlist *wl); + + +#endif diff --git a/src/frontend/miscvars.c b/src/frontend/miscvars.c new file mode 100644 index 000000000..eeb4c8a57 --- /dev/null +++ b/src/frontend/miscvars.c @@ -0,0 +1,128 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteinp.h" +#include "miscvars.h" + + +bool ft_nomod = FALSE; +bool ft_nopage = FALSE; +bool ft_parsedb = FALSE; +bool ft_vecdb = FALSE; +bool ft_simdb = FALSE; +bool ft_evdb = FALSE; +bool ft_grdb = FALSE; +bool ft_gidb = FALSE; +bool ft_controldb = FALSE; +bool ft_asyncdb = FALSE; + +char *ft_setkwords[] = { + + "acct", + "appendwrite", + "bypass", + "chgtol", + "color", + "cpdebug", + "cptime", + "curplot", + "curplotdate", + "curplotname", + "curplottitle", + "debug", + "defad", + "defas", + "defl", + "defw", + "device", + "diff_abstol", + "diff_reltol", + "diff_vntol", + "display", + "dontplot", + "dpolydegree", + "editor", + "filetype", + "fourgridsize", + "geometry", + "geometry", + "gmin", + "gridsize", + "hcopydev", + "hcopydevtype", + "hcopyfont", + "hcopyfontsize", + "hcopyscale", + "height", + "history", + "ignoreeof", + "itl1", + "itl2", + "itl3", + "itl4", + "itl5", + "list", + "lprplot5", + "lprps", + "maxwins", + "modelcard", + "modelline", + "nfreqs", + "noasciiplotvalue", + "noaskquit", + "nobjthack", + "nobreak", + "noclobber", + "node", + "noglob", + "nogrid", + "nomod", + "nomoremode", + "nonomatch", + "nopadding", + "nopage", + "noparse", + "noprintscale", + "nosort", + "nosubckt", + "numdgt", + "opts", + "pivrel", + "pivtol", + "plots", + "pointchars", + "polydegree", + "polysteps", + "program", + "prompt", + "rawfile", + "rawfileprec", + "renumber", + "rhost", + "rprogram", + "slowplot", + "sourcepath", + "spicepath", + "subend", + "subinvoke", + "substart", + "term", + "ticmarks", + "tnom", + "trtol", + "units", + "unixcom", + "width", + "x11lineararcs", + "xbrushheight", + "xbrushwidth", + "xfont", + + NULL +} ; diff --git a/src/frontend/miscvars.h b/src/frontend/miscvars.h new file mode 100644 index 000000000..8ca0865c7 --- /dev/null +++ b/src/frontend/miscvars.h @@ -0,0 +1,12 @@ +/************* + * Header file for miscvars.c + * 1999 E. Rouat + ************/ + +#ifndef MISCVARS_H_INCLUDED +#define MISCVARS_H_INCLUDED + + + + +#endif diff --git a/src/frontend/mw_coms.c b/src/frontend/mw_coms.c new file mode 100644 index 000000000..fd7fab110 --- /dev/null +++ b/src/frontend/mw_coms.c @@ -0,0 +1,44 @@ +/* Michael Widlok 2 Jun 1999 */ + +/* New commands for unloading circuits */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedev.h" +#include "ftedebug.h" +#include "ftedata.h" +#include "mw_coms.h" + + +extern FILE *rawfileFp; +extern bool rawfileBinary; +extern struct dbcomm *dbs; + +/* Clears ckt and removes current circ. form database */ + +void +com_removecirc(wordlist *wl) +{ + struct variable *v, *next; + struct circ *ct; + + if (ft_curckt == NULL) { + fprintf(cp_err, "Error: there is no circuit loaded.\n"); + return; + } + + ct = ft_curckt; + + if_cktfree(ct->ci_ckt, ct->ci_symtab); + for (v = ct->ci_vars; v; v = next) { + next = v->va_next; + tfree(v); + } + + ct->ci_vars = NULL; + + + return; +} + diff --git a/src/frontend/mw_coms.h b/src/frontend/mw_coms.h new file mode 100644 index 000000000..8fb1ebd87 --- /dev/null +++ b/src/frontend/mw_coms.h @@ -0,0 +1,12 @@ +/************* + * Header file for mw_coms.c + * 1999 E. Rouat + ************/ + +#ifndef MW_COMS_H_INCLUDED +#define MW_COMS_H_INCLUDED + +void com_removecirc(wordlist *wl); + + +#endif diff --git a/src/frontend/newcoms.c b/src/frontend/newcoms.c new file mode 100644 index 000000000..93ded1cc6 --- /dev/null +++ b/src/frontend/newcoms.c @@ -0,0 +1,213 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +**********/ + +/* + * Some new post-processor commands having to do with vectors. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteparse.h" +#include "ftedata.h" +#include "newcoms.h" + + +/* + * reshape v(1) vxx#branch [10] + * reshape v(1) vxx#branch [10,4] + * reshape v(1) [,4] + */ + +void +com_reshape(wordlist *wl) +{ + wordlist *w, *w2, *wlast, *wsave; + char *p; + struct dvec *dv, *d; + int numdims; + int *dims; + int local_dims[MAXDIMS]; + int state; + int empty; + int err; + int missing, nprod, prod; + char *vname; + int i; + + do { + if (!wl) + return; + + /* find the first '[' */ + + p = NULL; + for (w = wl; w; w = w->wl_next) { + if ((p =strchr(w->wl_word, '['))) + break; + } + + if (p && *p) { + if (p != w->wl_word) + w = w->wl_next; + wlast = w; + *p++ = 0; + } else + wlast = NULL; + + /* get the dimensions */ + dims = local_dims; + numdims = 0; + state = 0; + empty = -1; + err = 0; + wsave = NULL; + do { + + if (!p || !*p) { + if (!wlast) + break; + p = wlast->wl_word; + if (state == 2) + wsave = wlast; + else + wsave = NULL; + wlast = wlast->wl_next; + } + + while (*p && isspace(*p)) + p++; + + switch (state) { + case 0: /* p just at or before a number */ + + if (numdims >= MAXDIMS) { + if (numdims == MAXDIMS) + printf("Maximum of %d dimensions possible\n", MAXDIMS); + numdims += 1; + } else if (!isdigit(*p)) { + if (empty > -1) { + printf("dimensions underspecified at dimension %d\n", + numdims++); + err = 1; + } else { + empty = numdims; + dims[numdims++] = 1; + } + } else { + dims[numdims++] = atoi(p); + while (isdigit(*p)) + p++; + } + state = 1; + break; + + case 1: /* p after a number, looking for ',' or ']' */ + if (*p == ']') { + p++; + state = 2; + } else if (*p == ',') { + p++; + state = 0; + } else if (isdigit(*p)) { + state = 0; + break; + } else if (!isspace(*p)) + /* error */ + state = 4; + break; + + case 2: /* p after a ']', either at the end or looking for '[' */ + if (*p == '[') { + p++; + state = 0; + } else { + state = 3; + } + } + + while (*p && isspace(*p)) + p++; + + } while (state < 3); + + if (state == 2) { + wlast = wsave; + } else if ((state == 4 || state < 2) && ((state != 0 || p) && *p)) { + printf("syntax error specifying dimensions\n"); + return; + } + + if (numdims > MAXDIMS) + continue; + if (err) + continue; + + /* Copy dimensions from the first item if none are explicitly given */ + if (!numdims) { + /* Copy from the first */ + vname = cp_unquote(wl->wl_word); + dv = vec_get(vname); + if (!dv) { + printf("'%s' dimensions vector not found\n", vname); + return; + } + numdims = dv->v_numdims; + dims = dv->v_dims; + wl = wl->wl_next; + empty = -1; /* just in case */ + } + + prod = 1; + for (i = 0; i < numdims; i++) + prod *= dims[i]; + + /* resize each vector */ + for (w2 = wl; w2 && w2 != w; w2 = w2->wl_next) { + vname = cp_unquote(w2->wl_word); + + dv = vec_get(vname); + if (!dv) { + printf("'%s' vector not found\n", vname); + continue; + } + + /* The name may expand to several vectors */ + for (d = dv; d; d = d->v_link2) { + nprod = 1; + for (i = 0; i < d->v_numdims; i++) + nprod *= d->v_dims[i]; + if (nprod != d->v_length) { + printf("dimensions of \"%s\" were inconsistent\n", + d->v_name); + nprod = d->v_length; + } + + missing = nprod / prod; + if (missing * prod != nprod) { + printf("dimensions don't fit \"%s\" (total size = %d)\n", + d->v_name, nprod); + continue; + } + + if (missing > 1 && empty < 0) { + /* last dimension unspecified */ + d->v_numdims = numdims + 1; + d->v_dims[numdims] = missing; + } else + d->v_numdims = numdims; + + /* fill in dimensions */ + for (i = 0; i < numdims; i++) { + if (i == empty) + d->v_dims[i] = missing; + else + d->v_dims[i] = dims[i]; + } + } + if (vname) + tfree(vname); + } + } while ((wl = wlast)); +} diff --git a/src/frontend/newcoms.h b/src/frontend/newcoms.h new file mode 100644 index 000000000..8bb632985 --- /dev/null +++ b/src/frontend/newcoms.h @@ -0,0 +1,12 @@ +/************* + * Header file for newcoms.c + * 1999 E. Rouat + ************/ + +#ifndef NEWCOMS_H_INCLUDED +#define NEWCOMS_H_INCLUDED + +void com_reshape(wordlist *wl); + + +#endif diff --git a/src/frontend/nutctab.c b/src/frontend/nutctab.c new file mode 100644 index 000000000..e8286291c --- /dev/null +++ b/src/frontend/nutctab.c @@ -0,0 +1,369 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Table of available commands. Note that they're sorted so that the commands + * that appear in the spiceinit file are at the top. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftehelp.h" +#include "nutctab.h" + + +/* Bool fields: stringargs, spiceonly, major */ + +struct comm nutcp_coms[] = { + { "let", com_let, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + arg_let, + "varname = expr : Assign vector variables." } , + { "reshape", com_reshape, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + arg_let, + "vector ... [ shape ] : change the dimensions of a vector." } , + { "define", com_define, FALSE, FALSE, TRUE, + { 010000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[[func (args)] stuff] : Define a user-definable function." } , + { "set", com_set, FALSE, FALSE, TRUE, + { 020000, 020000, 020000, 020000 }, E_DEFHMASK, 0, LOTS, + arg_set, + "[option] [option = value] ... : Set a variable." } , + { "alias", com_alias, FALSE, FALSE, FALSE, + { 02, 04, 04, 04 }, E_ADVANCED, 0, LOTS, + (int (*)()) NULL, + "[[word] alias] : Define an alias." } , + { "deftype", com_dftype, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 3, LOTS, + (int (*)()) NULL, + "spec name pat ... : Redefine vector and plot types.\n" } , + { "plot", com_plot, FALSE, FALSE, TRUE, + { 041000, 041000, 041000, 041000 }, E_BEGINNING | E_HASPLOTS, 1, LOTS, + arg_plot, + "expr ... [vs expr] [xl xlo xhi] [yl ylo yhi] : Plot things." }, + { "display", com_display, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_BEGINNING, 0, LOTS, + arg_display, + ": Display vector status." } , + { "destroy", com_destroy, FALSE, FALSE, FALSE, + { 0400, 0400, 0400, 0400 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[plotname] ... : Throw away all the data in the plot." } , + { "setplot", com_splot, FALSE, FALSE, TRUE, + { 0400, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[plotname] : Change the current working plot." } , + { "setcirc", NULL, FALSE, TRUE, FALSE, + { 04, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[circuit name] : Change the current circuit." } , + { "setscale", com_setscale, FALSE, FALSE, FALSE, + { 040000, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[vecname] : Change default scale of current working plot." } , + { "transpose", com_transpose, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "varname ... : Perform matrix transposition on multi-D vectors." } , + { "xgraph", com_xgraph, FALSE, FALSE, TRUE, + { 1, 041000, 041000, 041000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "file plotargs : Send plot to Xgraph-11." } , + { "hardcopy", com_hardcopy, FALSE, FALSE, TRUE, + { 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "file plotargs : Produce hardcopy plots." } , + { "asciiplot", com_asciiplot, FALSE, FALSE, TRUE, + { 041000, 041000, 041000, 041000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "plotargs : Produce ascii plots." } , + { "write", com_write, FALSE, FALSE, TRUE, + { 1, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "file expr ... : Write data to a file." } , + { "compose", com_compose, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "var parm=val ... : Compose a vector." } , + { "unlet", com_unlet, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "varname ... : Undefine vectors." } , + { "print", com_print, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, + arg_print, + "[col] expr ... : Print vector values." } , + { "load", com_load, FALSE, FALSE, TRUE, + { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS, + arg_load, + "file ... : Load in data." } , + { "cross", com_cross, FALSE, FALSE, TRUE, + { 040000, 0, 040000, 040000 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "vecname number [ vector ... ] : Make a vector in a strange way." } , + { "undefine", com_undefine, FALSE, FALSE, FALSE, + { 010000, 010000, 010000, 010000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[func ...] : Undefine a user-definable function." } , + { "op", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.op line args] : Determine the operating point of the circuit." } , + { "tran", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.tran line args] : Do a transient analysis." } , + { "ac", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.ac line args] : Do an ac analysis." } , + { "dc", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.dc line args] : Do a dc analysis." } , + { "pz", NULL, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.pz line args] : Do a pole / zero analysis." } , + { "sens", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.ac line args] : Do a sensitivity analysis." } , + { "disto", NULL, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.disto line args] : Do an distortion analysis." } , + { "noise", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.noise line args] : Do a noise analysis." } , + { "listing", NULL, FALSE, TRUE, TRUE, + { 0100, 0100, 0100, 0100 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[logical] [physical] [deck] : Print the current circuit." } , + { "edit", NULL, FALSE, TRUE, TRUE, + { 1, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[filename] : Edit a spice deck and then load it in." } , + { "dump", NULL, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Print a dump of the current circuit." } , + { "fourier", com_fourier, FALSE, FALSE, TRUE, + { 0, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "fund_freq vector ... : Do a fourier analysis of some data." } , + { "show", NULL, FALSE, TRUE, FALSE, + { 040, 040, 040, 040 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "devspecs ... : parmspecs ... : Print out device parameters." } , + { "alter", NULL, FALSE, TRUE, FALSE, + { 040, 040, 040, 040 }, E_DEFHMASK, 3, LOTS, + (int (*)()) NULL, + "devspecs : parmname value : Alter device parameters." } , + { "altermod", NULL, FALSE, TRUE, FALSE, + { 040, 040, 040, 040 }, E_DEFHMASK, 3, LOTS, + (int (*)()) NULL, + "devspecs : parmname value : Alter model parameters." } , + { "resume", NULL, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Continue after a stop." } , + { "state", NULL, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "(unimplemented) : Print the state of the circuit." }, + { "stop", NULL, FALSE, TRUE, FALSE, + { 04200, 04200, 04200, 04200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[stop args] : Set a breakpoint." } , + { "trace", NULL, FALSE, TRUE, FALSE, + { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [node ...] : Trace a node." } , + { "save", NULL, FALSE, TRUE, FALSE, + { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [node ...] : Save a spice output." } , + { "iplot", NULL, FALSE, TRUE, TRUE, + { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [node ...] : Incrementally plot a node." } , + { "status", NULL, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Print the current breakpoints and traces." } , + { "delete", NULL, FALSE, TRUE, FALSE, + { 020, 020, 020, 020 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [break number ...] : Delete breakpoints and traces." } , + { "step", NULL, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[number] : Iterate number times, or one." } , + { "reset", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Terminate a simulation after a breakpoint (formerly 'end')." } , + { "run", NULL, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[rawfile] : Run the simulation as specified in the input file." } , +#ifdef notdef + { "aspice", com_aspice, FALSE, FALSE, FALSE, + { 1, 1, 1, 1 }, E_DEFHMASK, 1, 2, + (int (*)()) NULL, + "file [outfile] : Run a spice job asynchronously." } , + { "jobs", com_jobs, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Report on asynchronous spice jobs." } , + { "rspice", com_rspice, FALSE, FALSE, FALSE, + { 1, 1, 1, 1 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[input file] : Run a spice job remotely." } , +#endif + { "bug", com_bug, FALSE, FALSE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Report a %s bug." } , + { "newhelp", com_ahelp, FALSE, FALSE, TRUE, + { 010, 010, 010, 010 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[command name] ... : help." }, + { "tutorial", com_ghelp, FALSE, FALSE, TRUE, + { 023010, 023010, 023010, 023010 }, E_BEGINNING, 0, LOTS, + (int (*)()) NULL, + "[subject] ... : Hierarchical documentation browser." } , + { "help", com_ghelp, FALSE, FALSE, TRUE, + { 023010, 023010, 023010, 023010 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[subject] ... : Hierarchical documentation browser." } , + { "oldhelp", com_help, FALSE, FALSE, TRUE, + { 010, 010, 010, 010 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[command name] ... : Print help." } , + { "quit", com_quit, FALSE, FALSE, TRUE, + { 0, 0, 0, 0 }, E_BEGINNING, 0, 0, + (int (*)()) NULL, + ": Quit %s." } , + { "source", nutcom_source, FALSE, FALSE, TRUE, + { 1, 1, 1, 1 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "file : Source a %s file." } , + { "shift", com_shift, FALSE, FALSE, FALSE, + { 020000, 0, 0, 0 }, E_DEFHMASK, 0, 2, + (int (*)()) NULL, + "[var] [number] : Shift argv or the named list var to the left." } , + { "unset", com_unset, FALSE, FALSE, FALSE, + { 020000, 020000, 020000, 020000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "varname ... : Unset a variable." } , + { "unalias", com_unalias, FALSE, FALSE, FALSE, + { 02, 02, 02, 02 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "word ... : Undefine an alias." } , + { "history", com_history, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 2, + (int (*)()) NULL, + "[-r] [number] : Print command history." } , + { "echo", com_echo, FALSE, FALSE, FALSE, + { 1, 1, 1, 1 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[stuff ...] : Print stuff." } , + { "shell", com_shell, FALSE, FALSE, TRUE, + { 1, 1, 1, 1 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[args] : Fork a shell, or execute the command." } , + { "rusage", com_rusage, FALSE, FALSE, FALSE, + { 02000, 02000, 02000, 02000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[resource ...] : Print current resource usage." } , + { "cd", com_chdir, FALSE, FALSE, FALSE, + { 1, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[directory] : Change working directory." } , + { "version", com_version, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[number] : Print the version number." } , + { "diff", com_diff, FALSE, FALSE, FALSE, + { 0400, 0400, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "plotname plotname [vec ...] : 'diff' two plots." } , + { "rehash", com_rehash, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Rebuild the unix command database." } , + { "while", NULL, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "condition : Execute while the condition is TRUE." } , + { "repeat", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0}, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[number] : Repeat number times, or forever." } , + { "dowhile", NULL, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "condition : Execute while the condition is TRUE." } , + { "foreach", NULL, FALSE, FALSE, FALSE, + { 0, 040000, 040000, 040000 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "variable value ... : Do once for each value." } , + { "if", NULL, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "condition : Execute if the condition is TRUE." } , + { "else", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Goes with if." } , + { "end", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": End a block." } , + { "break", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Break out of a block." } , + { "continue", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Continue a loop." } , + { "label", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 1, 1, + (int (*)()) NULL, + "word : Create someplace to go to." } , + { "goto", NULL, FALSE, FALSE, FALSE, + { 0100000, 0, 0, 0 }, E_DEFHMASK, 1, 1, + (int (*)()) NULL, + "word : Go to a label." } , + { "cdump", com_cdump, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Dump the current control structures." } , + { "settype", com_stype, FALSE, FALSE, FALSE, + { 0200000, 040000, 040000, 040000 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "type vec ... : Change the type of a vector." } , + { "strcmp", com_strcmp, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 3, 3, + (int (*)()) NULL, + "varname s1 s2 : Set $varname to strcmp(s1, s2)." } , + { "linearize", NULL, FALSE, TRUE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + " [ vec ... ] : Convert plot into one with linear scale." } , + + { 0, NULL, FALSE, FALSE, FALSE, { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + NULL } + +} ; + diff --git a/src/frontend/nutctab.h b/src/frontend/nutctab.h new file mode 100644 index 000000000..f94f5b947 --- /dev/null +++ b/src/frontend/nutctab.h @@ -0,0 +1,12 @@ +/************* + * Header file for nutctab.c + * 1999 E. Rouat + ************/ + +#ifndef NUTCTAB_H_INCLUDED +#define NUTCTAB_H_INCLUDED + + + + +#endif diff --git a/src/frontend/nutinp.c b/src/frontend/nutinp.c new file mode 100644 index 000000000..7b38dc68c --- /dev/null +++ b/src/frontend/nutinp.c @@ -0,0 +1,275 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher +**********/ + +/* + * For dealing with nutmeg input decks and command scripts + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteinp.h" +#include "nutinp.h" + + +/* The routine to source a spice input deck. We read the deck in, take out + * the front-end commands, and create a CKT structure. Also we filter out + * the following lines: .save, .width, .four, .print, and .plot, to perform + * after the run is over. + */ + + +extern int unlink (const char *); + +void +inp_nutsource(FILE *fp, bool comfile, char *filename) +{ + struct line *deck, *dd, *ld; + struct line *realdeck, *options; + char *tt, name[BSIZE_SP], *s, *t; + bool nosubckts, commands = FALSE; + wordlist *wl = NULL, *end = NULL; + wordlist *controls = NULL; + FILE *lastin, *lastout, *lasterr; + + inp_readall(fp, &deck); + if (!deck) + return; + + realdeck = inp_deckcopy(deck); + + if (!comfile) { + /* Save the title before INPgetTitle gets it. */ + tt = copy(deck->li_line); + if (!deck->li_next) + fprintf(cp_err, "Warning: no lines in deck...\n"); + } + (void) fclose(fp); + + /* Now save the IO context and start a new control set... After + * we are done with the source we'll put the old file descriptors + * back. I guess we could use a FILE stack, but since this routine + * is recursive anyway... + */ + lastin = cp_curin; + lastout = cp_curout; + lasterr = cp_curerr; + cp_curin = cp_in; + cp_curout = cp_out; + cp_curerr = cp_err; + + cp_pushcontrol(); + + /* We should now go through the deck and execute front-end + * commands and remove them. Front-end commands are enclosed by + * the lines .control and .endc, unless comfile + * is TRUE, in which case every line must be a front-end command. + * There are too many problems with matching the first word on + * the line. + */ + ld = deck; + if (comfile) { + /* This is easy. */ + for (dd = deck; dd; dd = ld) { + ld = dd->li_next; + if ((dd->li_line[0] == '*') && (dd->li_line[1] != '#')) + continue; + if (!ciprefix(".control", dd->li_line) && + !ciprefix(".endc", dd->li_line)) { + if (dd->li_line[0] == '*') + (void) cp_evloop(dd->li_line + 2); + else + (void) cp_evloop(dd->li_line); + } + tfree(dd->li_line); + tfree(dd); + } + } else { + for (dd = deck->li_next; dd; dd = ld->li_next) { + if ((dd->li_line[0] == '*') && + (dd->li_line[1] != '#')) { + ld = dd; + continue; + } + (void) strncpy(name, dd->li_line, BSIZE_SP); + for (s = name; *s && isspace(*s); s++) + ; + for (t = s; *t && !isspace(*t); t++) + ; + *t = '\0'; + + if (ciprefix(".control", dd->li_line)) { + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + if (commands) + fprintf(cp_err, + "Warning: redundant .control line\n"); + else + commands = TRUE; + } else if (ciprefix(".endc", dd->li_line)) { + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + if (commands) + commands = FALSE; + else + fprintf(cp_err, + "Warning: misplaced .endc line\n"); + } else if (commands || prefix("*#", dd->li_line)) { + wl = alloc(struct wordlist); + if (controls) { + wl->wl_next = controls; + controls->wl_prev = wl; + controls = wl; + } else + controls = wl; + if (prefix("*#", dd->li_line)) + wl->wl_word = copy(dd->li_line + 2); + else + wl->wl_word = dd->li_line; + ld->li_next = dd->li_next; + tfree(dd); + } else if (!*dd->li_line) { + /* So blank lines in com files don't get + * considered as circuits. + */ + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + } else { + inp_casefix(s); + inp_casefix(dd->li_line); + if (eq(s, ".width") || ciprefix(".four", s) || + eq(s, ".plot") || + eq(s, ".print") || + eq(s, ".save")) { + if (end) { + end->wl_next = alloc(struct wordlist); + end->wl_next->wl_prev = end; + end = end->wl_next; + } else + wl = end = alloc(struct wordlist); + end->wl_word = copy(dd->li_line); + ld->li_next = dd->li_next; + tfree(dd->li_line); + tfree(dd); + } else + ld = dd; + } + } + if (deck->li_next) { + /* There is something left after the controls. */ + fprintf(cp_out, "\nCircuit: %s\n\n", tt); + + /* Now expand subcircuit macros. Note that we have to + * fix the case before we do this but after we + * deal with the commands. + */ + if (!cp_getvar("nosubckt", VT_BOOL, (char *) + &nosubckts)) + deck->li_next = inp_subcktexpand(deck-> + li_next); + deck->li_actual = realdeck; + nutinp_dodeck(deck, tt, wl, FALSE, options, filename); + } + + /* Now that the deck is loaded, do the commands... */ + if (controls) { + for (end = wl = wl_reverse(controls); wl; + wl = wl->wl_next) + (void) cp_evloop(wl->wl_word); + wl_free(end); + } + } + + /* Now reset everything. Pop the control stack, and fix up the IO + * as it was before the source. + */ + cp_popcontrol(); + + cp_curin = lastin; + cp_curout = lastout; + cp_curerr = lasterr; + return; +} + +void +nutcom_source(wordlist *wl) +{ + FILE *fp, *tp; + char buf[BSIZE_SP]; + bool inter; + char *tempfile = NULL; + wordlist *owl = wl; + int i; + + inter = cp_interactive; + cp_interactive = FALSE; + if (wl->wl_next) { + /* There are several files -- put them into a temp file... */ + tempfile = smktemp("sp"); + if (!(fp = inp_pathopen(tempfile, "w+"))) { + perror(tempfile); + cp_interactive = TRUE; + return; + } + while (wl) { + if (!(tp = inp_pathopen(wl->wl_word, "r"))) { + perror(wl->wl_word); + (void) fclose(fp); + cp_interactive = TRUE; + (void) unlink(tempfile); + return; + } + while ((i = fread(buf, 1, BSIZE_SP, tp)) > 0) + (void) fwrite(buf, 1, i, fp); + (void) fclose(tp); + wl = wl->wl_next; + } + (void) fseek(fp, (long) 0, 0); + } else + fp = inp_pathopen(wl->wl_word, "r"); + if (fp == NULL) { + perror(wl->wl_word); + cp_interactive = TRUE; + return; + } + + /* Don't print the title if this is a .spiceinit file. */ + if (ft_nutmeg || substring(".spiceinit", owl->wl_word) + || substring("spice.rc", owl->wl_word)) + inp_nutsource(fp, TRUE, tempfile ? (char *) NULL : wl->wl_word); + else + inp_nutsource(fp, FALSE, tempfile ? (char *) NULL : wl->wl_word); + cp_interactive = inter; + if (tempfile) + (void) unlink(tempfile); + return; +} + +void +nutinp_source(char *file) +{ + static struct wordlist wl = { NULL, NULL, NULL } ; + + wl.wl_word = file; + nutcom_source(&wl); + return; +} + + +/* This routine is cut in half here because com_rset has to do what follows + * also. End is the list of commands we execute when the job is finished: + * we only bother with this if we might be running in batch mode, since + * it isn't much use otherwise. + */ + +void +nutinp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse, struct line *options, char *filename) +{ + /* This was "ifdef notdef"-ed out, so I tossed it */ +} diff --git a/src/frontend/nutinp.h b/src/frontend/nutinp.h new file mode 100644 index 000000000..a04e73cbf --- /dev/null +++ b/src/frontend/nutinp.h @@ -0,0 +1,17 @@ +/************* + * Header file for nutinp.c + * 1999 E. Rouat + ************/ + +#ifndef NUTINP_H_INCLUDED +#define NUTINP_H_INCLUDED + +void inp_nutsource(FILE *fp, bool comfile, char *filename); +void nutcom_source(wordlist *wl); +void nutinp_source(char *file); +void nutinp_dodeck(struct line *deck, char *tt, wordlist *end, bool reuse, + struct line *options, char *filename); + + + +#endif diff --git a/src/frontend/nutmegif.c b/src/frontend/nutmegif.c new file mode 100644 index 000000000..ebae7f0e9 --- /dev/null +++ b/src/frontend/nutmegif.c @@ -0,0 +1,19 @@ + +/* + * Dummy interface stuff, for nutmeg. This is the easiest way of + * making sure that nutmeg doesn't try to load spice in also. + */ + +#include "ngspice.h" +#include "ifsim.h" +#include "sperror.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteinp.h" +#include "nutmegif.h" + + +struct variable * nutif_getparam(char *ckt, char **name, char *param, int ind, int do_model) +{ return ((struct variable *) NULL); } + + diff --git a/src/frontend/nutmegif.h b/src/frontend/nutmegif.h new file mode 100644 index 000000000..c771e6940 --- /dev/null +++ b/src/frontend/nutmegif.h @@ -0,0 +1,12 @@ +/************* + * Header file for nutmegif.c + * 1999 E. Rouat + ************/ + +#ifndef NUTMEGIF_H_INCLUDED +#define NUTMEGIF_H_INCLUDED + +struct variable * nutif_getparam(char *ckt, char **name, char *param, int ind, int do_model); + + +#endif diff --git a/src/frontend/options.c b/src/frontend/options.c new file mode 100644 index 000000000..369166e57 --- /dev/null +++ b/src/frontend/options.c @@ -0,0 +1,405 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * The user-supplied routine to deal with variables. Most variables we + * don't use often, so just call cp_getvar when they are needed. Spice + * variables, though, and a few commonly used ones are dealt with here. + */ + + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteinp.h" +#include "options.h" + + + +/* static declarations */ +static void setdb(char *str); + +bool ft_acctprint = FALSE, ft_listprint = FALSE; +bool ft_nodesprint = FALSE, ft_optsprint = FALSE; + +/* The user-supplied routine to query the values of variables. This + * recognises the $&varname notation, and also searches the values of + * plot and circuit environment variables. + */ + +struct variable * +cp_enqvar(char *word) +{ + struct dvec *d; + struct variable *vv, *tv; + struct plot *pl; + int i; + + if (*word == '&') { + word++; + d = vec_get(word); + if (d) { + if (d->v_length == 1) { + vv = alloc(struct variable); + vv->va_name = copy(word); + vv->va_next = NULL; + vv->va_type = VT_REAL; + if (isreal(d)) { + vv->va_real = d->v_realdata[0]; + } else { + vv->va_real = + realpart(&d->v_compdata[0]); + } + } else { + vv = alloc(struct variable); + vv->va_next = NULL; + vv->va_name = copy(word); + vv->va_type = VT_LIST; + vv->va_vlist = NULL; + for (i = d->v_length - 1; i >= 0; i--) { + tv = alloc(struct variable); + tv->va_type = VT_REAL; + if (isreal(d)) { + tv->va_real = d->v_realdata[i]; + } else { + tv->va_real = + realpart(&d->v_compdata[i]); + } + tv->va_next = vv->va_vlist; + vv->va_vlist = tv; + } + } + if (d->v_link2) + fprintf(cp_err, + "Warning: only one vector may be accessed with the $& notation.\n"); + return (vv); + } else + return (NULL); + } + if (plot_cur) { + for (vv = plot_cur->pl_env; vv; vv = vv->va_next) + if (eq(vv->va_name, word)) + break; + if (vv) + return (vv); + if (eq(word, "curplotname")) { + vv = alloc(struct variable); + vv->va_next = NULL; + vv->va_name = word; + vv->va_type = VT_STRING; + vv->va_string = copy(plot_cur->pl_name); + } else if (eq(word, "curplottitle")) { + vv = alloc(struct variable); + vv->va_next = NULL; + vv->va_name = word; + vv->va_type = VT_STRING; + vv->va_string = copy(plot_cur->pl_title); + } else if (eq(word, "curplotdate")) { + vv = alloc(struct variable); + vv->va_next = NULL; + vv->va_name = word; + vv->va_type = VT_STRING; + vv->va_string = copy(plot_cur->pl_date); + } else if (eq(word, "curplot")) { + vv = alloc(struct variable); + vv->va_next = NULL; + vv->va_name = word; + vv->va_type = VT_STRING; + vv->va_string = copy(plot_cur->pl_typename); + } else if (eq(word, "plots")) { + vv = alloc(struct variable); + vv->va_next = NULL; + vv->va_vlist = NULL; + vv->va_name = word; + vv->va_type = VT_LIST; + vv->va_vlist = NULL; + for (pl = plot_list; pl; pl = pl->pl_next) { + tv = alloc(struct variable); + tv->va_type = VT_STRING; + tv->va_string = copy(pl->pl_typename); + tv->va_next = vv->va_vlist; + vv->va_vlist = tv; + } + } + if (vv) { + return (vv); + } + } + if (ft_curckt) { + for (vv = ft_curckt->ci_vars; vv; vv = vv->va_next) + if (eq(vv->va_name, word)) + break; + if (vv) + return (vv); + } + return (NULL); +} + +/* Return the plot and ckt env vars, $plots, and $curplot{name,title,date,} */ + +void +cp_usrvars(struct variable **v1, struct variable **v2) +{ + struct variable *v, *tv; + + if (plot_cur) + v = plot_cur->pl_env; + else + v = NULL; + if ((tv = cp_enqvar("plots"))) { + tv->va_next = v; + v = tv; + } + if ((tv = cp_enqvar("curplot"))) { + tv->va_next = v; + v = tv; + } + if ((tv = cp_enqvar("curplottitle"))) { + tv->va_next = v; + v = tv; + } + if ((tv = cp_enqvar("curplotname"))) { + tv->va_next = v; + v = tv; + } + if ((tv = cp_enqvar("curplotdate"))) { + tv->va_next = v; + v = tv; + } + *v1 = v; + if (ft_curckt) + *v2 = ft_curckt->ci_vars; + else + *v2 = NULL; + return; +} + + +/* Extract the .option lines from the deck */ + +struct line * +inp_getopts(struct line *deck) +{ + struct line *last = NULL, *opts = NULL, *dd, *next = NULL; + + for (dd = deck->li_next; dd; dd = next) { + next = dd->li_next; + if (ciprefix(".opt", dd->li_line)) { + inp_casefix(dd->li_line); + if (last) + last->li_next = dd->li_next; + else + deck->li_next = dd->li_next; + dd->li_next = opts; + opts = dd; + } else + last = dd; + } + return (opts); +} + +static void setdb(char *str); + +/* The one variable that we consider read-only so far is plots. The ones + * that are 'dontrecord' are curplottitle, curplotname, and curplotdate. + * Also things already in the plot env are 'dontrecord'. + */ + +int +cp_usrset(struct variable *var, bool isset) +{ + char val[BSIZE_SP]; + char *vv, *s; + struct variable *tv; + int iv; + double dv; + bool bv; + + if (eq(var->va_name, "debug")) { + if (var->va_type == VT_BOOL) { + cp_debug = ft_simdb = ft_parsedb = ft_evdb = ft_vecdb = + ft_grdb = ft_gidb = ft_controldb = isset; + } else if (var->va_type == VT_LIST) { + for (tv = var->va_vlist; tv; tv = tv->va_next) + if (var->va_type != VT_STRING) + fprintf(cp_err, + "Error: bad type for debug var\n"); + else + setdb(tv->va_string); + } else if (var->va_type == VT_STRING) { + setdb(var->va_string); + } else + fprintf(cp_err, "Error: bad type for debug var\n"); +#ifndef FTEDEBUG + fprintf(cp_err, "Warning: %s compiled without debug messages\n", + cp_program); +#endif + } else if (eq(var->va_name, "program")) { + cp_program = copy(var->va_string); + } else if (eq(var->va_name, "rawfile")) { + ft_rawfile = copy(var->va_string); + } else if (eq(var->va_name, "acct")) { + ft_acctprint = isset; + } else if (eq(var->va_name, "list")) { + ft_listprint = isset; + } else if (eq(var->va_name, "nopage")) { + ft_nopage = isset; + } else if (eq(var->va_name, "nomod")) { + ft_nomod = isset; + } else if (eq(var->va_name, "node")) { + ft_nodesprint = isset; + } else if (eq(var->va_name, "opts")) { + ft_optsprint = isset; + } else if (eq(var->va_name, "strictnumparse")) { + ft_strictnumparse = isset; + } else if (eq(var->va_name, "rawfileprec")) { + if ((var->va_type == VT_BOOL) && (isset == FALSE)) + raw_prec = -1; + else if (var->va_type == VT_REAL) + raw_prec = var->va_real; + else if (var->va_type == VT_NUM) + raw_prec = var->va_num; + else + fprintf(cp_err, "Bad 'rawfileprec' \"%s\"\n", var->va_name); + } else if (eq(var->va_name, "numdgt")) { + if ((var->va_type == VT_BOOL) && (isset == FALSE)) + cp_numdgt = -1; + else if (var->va_type == VT_REAL) + cp_numdgt = var->va_real; + else if (var->va_type == VT_NUM) + cp_numdgt = var->va_num; + else + fprintf(cp_err, "Excuse me??\n"); + } else if (eq(var->va_name, "unixcom")) { + + cp_dounixcom = isset; + if (isset) { + s = getenv("PATH"); + if (s) + cp_rehash(s, TRUE); + else + fprintf(cp_err, "Warning: no PATH in environment.\n"); + } + + } else if (eq(var->va_name, "units") && (var->va_type == VT_STRING)) { + if (isset && ((*var->va_string == 'd') || + (*var->va_string == 'D'))) + cx_degrees = TRUE; + else + cx_degrees = FALSE; + } else if (eq(var->va_name, "curplot")) { + if (var->va_type == VT_STRING) + plot_setcur(var->va_string); + else + fprintf(cp_err, "Error: plot name not a string\n"); + return (US_DONTRECORD); + } else if (eq(var->va_name, "curplotname")) { + if (plot_cur && (var->va_type == VT_STRING)) + plot_cur->pl_name = copy(var->va_string); + else + fprintf(cp_err, "Error: can't set plot name\n"); + return (US_DONTRECORD); + } else if (eq(var->va_name, "curplottitle")) { + if (plot_cur && (var->va_type == VT_STRING)) + plot_cur->pl_title = copy(var->va_string); + else + fprintf(cp_err, "Error: can't set plot title\n"); + return (US_DONTRECORD); + } else if (eq(var->va_name, "curplotdate")) { + if (plot_cur && (var->va_type == VT_STRING)) + plot_cur->pl_date = copy(var->va_string); + else + fprintf(cp_err, "Error: can't set plot date\n"); + return (US_DONTRECORD); + } else if (eq(var->va_name, "plots")) { + return (US_READONLY); + } + + if (plot_cur) + for (tv = plot_cur->pl_env; tv; tv = tv->va_next) + if (eq(tv->va_name, var->va_name)) + return (US_READONLY); + /* + if (ft_curckt) + for (tv = ft_curckt->ci_vars; tv; tv = tv->va_next) + if (eq(tv->va_name, var->va_name)) + return (US_READONLY); + */ + + if (ft_nutmeg) + return (US_OK); + + /* Now call the interface option routine. */ + switch (var->va_type) { + case VT_BOOL: + if (var->va_bool) { + /*val[0] = '\0';*/ + bv = TRUE; + vv = (char *) &bv; + /*break;*/ + } else { + bv = FALSE; + vv = (char *) &bv; + } + break; + case VT_STRING: + (void) strcpy(val, var->va_string); + vv = val; + break; + case VT_NUM: + /*(void) sprintf(val, "%d", var->va_num);*/ + iv = var->va_num; + vv = (char *) &iv; + break; + case VT_REAL: + /*(void) strcpy(val, printnum(var->va_real));*/ + dv = var->va_real; + vv = (char *) &dv; + break; + case VT_LIST: + /* if_option can't handle lists anyway. */ + vv = NULL; + break; + default: + fprintf(cp_err, + "cp_usrset: Internal Error: Bad var type %d\n", + var->va_type); + return (0); + } + + if (ft_curckt) { + if (if_option(ft_curckt->ci_ckt, var->va_name, var->va_type, vv)) + return US_SIMVAR; + } else if (if_option(NULL, var->va_name, var->va_type, vv)) + return US_NOSIMVAR; + return (US_OK); +} + +static void +setdb(char *str) +{ + if (eq(str, "siminterface")) + ft_simdb = TRUE; + else if (eq(str, "cshpar")) + cp_debug = TRUE; + else if (eq(str, "parser")) + ft_parsedb = TRUE; + else if (eq(str, "eval")) + ft_evdb = TRUE; + else if (eq(str, "vecdb")) + ft_vecdb = TRUE; + else if (eq(str, "graf")) + ft_grdb = TRUE; + else if (eq(str, "ginterface")) + ft_gidb = TRUE; + else if (eq(str, "control")) + ft_controldb = TRUE; + else if (eq(str, "async")) + ft_asyncdb = TRUE; + else + fprintf(cp_err, "Warning: no such debug class %s\n", str); + return; +} diff --git a/src/frontend/options.h b/src/frontend/options.h new file mode 100644 index 000000000..53c39dbf3 --- /dev/null +++ b/src/frontend/options.h @@ -0,0 +1,15 @@ +/************* + * Header file for options.c + * 1999 E. Rouat + ************/ + +#ifndef OPTIONS_H_INCLUDED +#define OPTIONS_H_INCLUDED + +struct variable * cp_enqvar(char *word); +void cp_usrvars(struct variable **v1, struct variable **v2); +struct line * inp_getopts(struct line *deck); +int cp_usrset(struct variable *var, bool isset); + + +#endif diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c new file mode 100644 index 000000000..db5de7c17 --- /dev/null +++ b/src/frontend/outitf.c @@ -0,0 +1,948 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * This module replaces the old "writedata" routines in nutmeg. + * Unlike the writedata routines, the OUT routines are only called by + * the simulator routines, and only call routines in nutmeg. The rest + * of nutmeg doesn't deal with OUT at all. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteconst.h" +#include "inpdefs.h" /* for INPtables */ +#include "ifsim.h" +#include "jobdefs.h" +#include "iferrmsg.h" +#include "outitf.h" + + +extern void gr_end_iplot(void); +extern SPICEanalysis *analInfo[]; + +/* static declarations */ +static int beginPlot(void *analysisPtr, void *circuitPtr, char *cktName, char *analName, + char *refName, int refType, int numNames, char **dataNames, int dataType, + bool windowed, runDesc **runp); +static int addDataDesc(runDesc *run, char *name, int type, int ind); +static int addSpecialDesc(runDesc *run, char *name, char *devname, char *param, int depind); +static void fileInit(runDesc *run); +static void fileInit_pass2(runDesc *run); +static void fileStartPoint(FILE *fp, bool bin, int num); +static void fileAddRealValue(FILE *fp, bool bin, double value); +static void fileAddComplexValue(FILE *fp, bool bin, IFcomplex value); +static void fileEndPoint(FILE *fp, bool bin); +static void fileEnd(runDesc *run); +static void plotInit(runDesc *run); +static void plotAddRealValue(dataDesc *desc, double value); +static void plotAddComplexValue(dataDesc *desc, IFcomplex value); +static void plotEnd(runDesc *run); +static bool parseSpecial(char *name, char *dev, char *param, char *ind); +static bool name_eq(char *n1, char *n2); +static bool getSpecial(dataDesc *desc, runDesc *run, IFvalue *val); +static void freeRun(runDesc *run); + + + +#define DOUBLE_PRECISION 15 + + + + +static bool shouldstop = FALSE; /* Tell simulator to stop next time it asks. */ +static bool printinfo = FALSE; /* Print informational "error messages". */ + +/* The two "begin plot" routines share all their internals... */ + + +extern int ft_getSaves (struct save_info **savesp); +extern bool ft_getOutReq (FILE **fpp, struct plot **plotp, bool *binp, char *name, char *title); + +int +OUTpBeginPlot(void *circuitPtr, void *analysisPtr, IFuid analName, IFuid refName, int refType, int numNames, IFuid *dataNames, int dataType, void **plotPtr) +{ + char *name; + +#ifdef PARALLEL_ARCH +if (ARCHme != 0) return(OK); +#endif /* PARALLEL_ARCH */ + + + if (ft_curckt->ci_ckt == circuitPtr) + name = ft_curckt->ci_name; + else + name = "circuit name"; + + return (beginPlot(analysisPtr, circuitPtr, name, + (char *) analName, (char *) refName, refType, numNames, + (char **) dataNames, dataType, FALSE, + (runDesc **) plotPtr)); +} + +int +OUTwBeginPlot(void *circuitPtr, void *analysisPtr, IFuid analName, IFuid refName, int refType, int numNames, IFuid *dataNames, int dataType, void **plotPtr) +{ +#ifdef PARALLEL_ARCH + if (ARCHme != 0) return(OK); +#endif /* PARALLEL_ARCH */ + + return (beginPlot(analysisPtr, circuitPtr, "circuit name", + (char *) analName, (char *) refName, refType, numNames, + (char **) dataNames, dataType, TRUE, + (runDesc **) plotPtr)); +} + +static int +beginPlot(void *analysisPtr, void *circuitPtr, char *cktName, char *analName, char *refName, int refType, int numNames, char **dataNames, int dataType, bool windowed, runDesc **runp) +{ + runDesc *run; + struct save_info *saves; + bool *savesused; + int numsaves; + int i, j, depind; + char namebuf[BSIZE_SP], parambuf[BSIZE_SP], depbuf[BSIZE_SP]; + bool saveall = TRUE; + char *an_name; + + /* Check to see if we want to print informational data. */ + if (cp_getvar("printinfo", VT_BOOL, (char *) &printinfo)) + fprintf(cp_err, "(debug printing enabled)\n"); + + *runp = run = alloc(struct runDesc); + + /* First fill in some general information. */ + run->analysis = analysisPtr; + run->circuit = circuitPtr; + run->name = copy(cktName); + run->type = copy(analName); + run->windowed = windowed; + run->numData = 0; + + an_name = analInfo[((JOB *) analysisPtr)->JOBtype]->public.name; + + /* Now let's see which of these things we need. First toss in the + * reference vector. Then toss in anything that getSaves() tells + * us to save that we can find in the name list. Finally unpack + * the remaining saves into parameters. + */ + numsaves = ft_getSaves(&saves); + if (numsaves) { + savesused = (bool *) tmalloc(sizeof (bool) * numsaves); + saveall = FALSE; + for (i = 0; i < numsaves; i++) { + if (saves[i].analysis && !cieq(saves[i].analysis, an_name)) { + /* ignore this one this time around */ + savesused[i] = TRUE; + continue; + } + if (cieq(saves[i].name, "all")) { + saveall = TRUE; + savesused[i] = TRUE; + saves[i].used = 1; + continue; + } + } + } + + /* Pass 0. */ + if (refName) { + addDataDesc(run, refName, refType, -1); + for (i = 0; i < numsaves; i++) + if (!savesused[i] && name_eq(saves[i].name, refName)) { + savesused[i] = TRUE; + saves[i].used = 1; + } + } else { + run->refIndex = -1; + } + + + /* Pass 1. */ + if (numsaves && !saveall) { + for (i = 0; i < numsaves; i++) { + if (!savesused[i]) { + for (j = 0; j < numNames; j++) { + if (name_eq(saves[i].name, dataNames[j])) { + addDataDesc(run, dataNames[j], dataType, j); + savesused[i] = TRUE; + saves[i].used = 1; + break; + } + } + } + } + } else { + for (i = 0; i < numNames; i++) + if (!refName || !name_eq(dataNames[i], refName)) { + addDataDesc(run, dataNames[i], dataType, i); + } + } + + /* Pass 2. */ + for (i = 0; i < numsaves; i++) { + if (savesused[i]) + continue; + if (!parseSpecial(saves[i].name, namebuf, parambuf, depbuf)) { + if (saves[i].analysis) + fprintf(cp_err, "Warning: can't parse '%s': ignored\n", + saves[i].name); + continue; + } + /* Now, if there's a dep variable, do we already have it? */ + if (*depbuf) { + for (j = 0; j < run->numData; j++) + if (name_eq(depbuf, run->data[j].name)) + break; + if (j == run->numData) { + /* Better add it. */ + for (j = 0; j < numNames; j++) + if (name_eq(depbuf, dataNames[j])) + break; + if (j == numNames) { + fprintf(cp_err, + "Warning: can't find '%s': value '%s' ignored\n", + depbuf, saves[i].name); + continue; + } + addDataDesc(run, dataNames[j], dataType, j); + savesused[i] = TRUE; + saves[i].used = 1; + depind = j; + } else + depind = run->data[j].outIndex; + } + addSpecialDesc(run, saves[i].name, namebuf, parambuf, depind); + } + + if (numsaves) { + for (i = 0; i < numsaves; i++) { + tfree(saves[i].analysis); + tfree(saves[i].name); + } + tfree(savesused); + } + + if (numNames + && (run->numData == 1 + && (run->refIndex != -1 + || run->numData == 0) + && run->refIndex == -1)) + { + fprintf(cp_err, "Error: no data saved for %s; analysis not run\n", + analInfo[((JOB *) analysisPtr)->JOBtype]->public.description); + return E_NOTFOUND; + } + + /* Now that we have our own data structures built up, let's see what + * nutmeg wants us to do. + */ + run->writeOut = ft_getOutReq(&run->fp, &run->runPlot, &run->binary, + run->type, run->name); + + if (run->writeOut) + fileInit(run); + else { + plotInit(run); + if (refName) + run->runPlot->pl_ndims = 1; + } + + return (OK); +} + +static int +addDataDesc(runDesc *run, char *name, int type, int ind) +{ + dataDesc *data; + + if (!run->numData) + run->data = (dataDesc *) tmalloc(sizeof (dataDesc)); + else + run->data = (dataDesc *) trealloc((char *) run->data, + sizeof (dataDesc) * (run->numData + 1)); + data = &run->data[run->numData]; + /* so freeRun will get nice NULL pointers for the fields we don't set */ + bzero(data, sizeof(dataDesc)); + + data->name = copy(name); + data->type = type; + data->gtype = GRID_LIN; + data->regular = TRUE; + data->outIndex = ind; + + if (ind == -1) { + /* It's the reference vector. */ + run->refIndex = run->numData; + } + + run->numData++; + + return (OK); +} + +static int +addSpecialDesc(runDesc *run, char *name, char *devname, char *param, int depind) +{ + dataDesc *data; + char *unique; /* unique char * from back-end */ + + if (!run->numData) + run->data = (dataDesc *) tmalloc(sizeof (dataDesc)); + else + run->data = (dataDesc *) trealloc((char *) run->data, + sizeof (dataDesc) * (run->numData + 1)); + data = &run->data[run->numData]; + /* so freeRun will get nice NULL pointers for the fields we don't set */ + bzero(data, sizeof(dataDesc)); + + data->name = copy(name); + + unique = copy(devname); + + /* MW. My "special" routine here */ + INPinsertNofree(&unique, (INPtables *) ft_curckt->ci_symtab); + data->specName = unique; + + data->specParamName = copy(param); + + data->specIndex = depind; + data->specType = -1; + data->specFast = NULL; + data->regular = FALSE; + + run->numData++; + + return (OK); +} + + + +int +OUTpData(void *plotPtr, IFvalue *refValue, IFvalue *valuePtr) +{ + runDesc *run = (runDesc *) plotPtr; + IFvalue val; + int i; +#ifdef PARALLEL_ARCH + if (ARCHme != 0) return(OK); +#endif /* PARALLEL_ARCH */ + + run->pointCount++; + + if (run->writeOut) { + if (run->pointCount == 1) + fileInit_pass2(plotPtr); + fileStartPoint(run->fp, run->binary, run->pointCount); + + if (run->refIndex != -1) { + if (run->isComplex) + fileAddComplexValue(run->fp, run->binary, refValue->cValue); + else + fileAddRealValue(run->fp, run->binary, refValue->rValue); + } + + for (i = 0; i < run->numData; i++) { + /* we've already printed reference vec first */ + if (run->data[i].outIndex == -1) continue; + + if (run->data[i].regular) { + if(run->data[i].type == IF_REAL) + fileAddRealValue(run->fp, run->binary, + valuePtr->v.vec.rVec + [run->data[i].outIndex]); + else if (run->data[i].type == IF_COMPLEX) + fileAddComplexValue(run->fp, run->binary, + valuePtr->v.vec.cVec + [run->data[i].outIndex]); + else + fprintf(stderr, "OUTpData: unsupported data type\n"); + } else { + /* should pre-check instance */ + if (!getSpecial(&run->data[i], run, &val)) + continue; + if (run->data[i].type == IF_REAL) + fileAddRealValue(run->fp, run->binary, + val.rValue); + else if (run->data[i].type == IF_COMPLEX) + fileAddComplexValue(run->fp, run->binary, + val.cValue); + else + fprintf(stderr, "OUTpData: unsupported data type\n"); + } + } + fileEndPoint(run->fp, run->binary); + } else { + for (i = 0; i < run->numData; i++) { + if (run->data[i].outIndex == -1) { + if (run->data[i].type == IF_REAL) + plotAddRealValue(&run->data[i], + refValue->rValue); + else if (run->data[i].type == IF_COMPLEX) + plotAddComplexValue(&run->data[i], + refValue->cValue); + } else if (run->data[i].regular) { + if (run->data[i].type == IF_REAL) + plotAddRealValue(&run->data[i], + valuePtr->v.vec.rVec + [run->data[i].outIndex]); + else if (run->data[i].type == IF_COMPLEX) + plotAddComplexValue(&run->data[i], + valuePtr->v.vec.cVec + [run->data[i].outIndex]); + } else { + /* should pre-check instance */ + if (!getSpecial(&run->data[i], run, &val)) + continue; + if (run->data[i].type == IF_REAL) + plotAddRealValue(&run->data[i], + val.rValue); + else if (run->data[i].type == IF_COMPLEX) + plotAddComplexValue(&run->data[i], + val.cValue); + else + fprintf(stderr, "OUTpData: unsupported data type\n"); + } + } + gr_iplot(run->runPlot); + } + + if (ft_bpcheck(run->runPlot, run->pointCount) == FALSE) + shouldstop = TRUE; + + return (OK); +} + + + +/* ARGSUSED */ /* until some code gets written */ +int +OUTwReference(void *plotPtr, IFvalue *valuePtr, void **refPtr) +{ + return (OK); +} +/* ARGSUSED */ /* until some code gets written */ +int +OUTwData(void *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr) +{ + return (OK); +} + +/* ARGSUSED */ /* until some code gets written */ +int +OUTwEnd(void *plotPtr) +{ + return (OK); +} + + + +int +OUTendPlot(void *plotPtr) +{ + runDesc *run = (runDesc *) plotPtr; + +#ifdef PARALLEL_ARCH + if (ARCHme != 0) return(OK); +#endif /* PARALLEL_ARCH */ + + if (run->writeOut) + fileEnd(run); + else { + gr_end_iplot(); + plotEnd(run); + } + + freeRun(run); + + return (OK); +} + + + +/* ARGSUSED */ /* until some code gets written */ +int +OUTbeginDomain(void *plotPtr, char *refName, int refType, IFvalue *outerRefValue) +{ + return (OK); +} + +/* ARGSUSED */ /* until some code gets written */ +int +OUTendDomain(void *plotPtr) +{ + return (OK); +} + + + +/* ARGSUSED */ /* until some code gets written */ +int +OUTattributes(void *plotPtr, char *varName, int param, IFvalue *value) +{ + runDesc *run = (runDesc *) plotPtr; + struct dvec *d; + int type; + int i; + + if (param == OUT_SCALE_LIN) + type = GRID_LIN; + else if (param == OUT_SCALE_LOG) + type = GRID_XLOG; + else + return E_UNSUPP; + + if (run->writeOut) { + if (varName) { + for (i = 0; i < run->numData; i++) + if (!strcmp(varName, run->data[i].name)) + run->data[i].gtype = type; + } else { + run->data[run->refIndex].gtype = type; + } + } else { + if (varName) { + for (d = run->runPlot->pl_dvecs; d; d = d->v_next) + if (!strcmp(varName, d->v_name)) + d->v_gridtype = type; + } else { + run->runPlot->pl_scale->v_gridtype = type; + } + } + + return (OK); +} + + + +/* The file writing routines. */ + +static void +fileInit(runDesc *run) +{ + char buf[513]; + int i; + + /* This is a hack. */ + run->isComplex = FALSE; + for (i = 0; i < run->numData; i++) + if (run->data[i].type == IF_COMPLEX) + run->isComplex = TRUE; + + i = 0; + sprintf(buf, "Title: %s\n", run->name); + i += strlen(buf); + fputs(buf, run->fp); + sprintf(buf, "Date: %s\n", datestring()); + i += strlen(buf); + fputs(buf, run->fp); + sprintf(buf, "Plotname: %s\n", run->type); + i += strlen(buf); + fputs(buf, run->fp); + sprintf(buf, "Flags: %s\n", run->isComplex ? "complex" : "real"); + i += strlen(buf); + fputs(buf, run->fp); + sprintf(buf, "No. Variables: %d\n", run->numData); + i += strlen(buf); + fputs(buf, run->fp); + sprintf(buf, "No. Points: "); + i += strlen(buf); + fputs(buf, run->fp); + + fflush(run->fp); /* Gotta do this for LATTICE. */ + if (run->fp == stdout || (run->pointPos = ftell(run->fp)) <= 0) + run->pointPos = i; + fprintf(run->fp, "0 \n"); /* Save 8 spaces here. */ + + fprintf(run->fp, "Command: version %s\n", ft_sim->version); + fprintf(run->fp, "Variables:\n"); + + return; +} + +static void +fileInit_pass2(runDesc *run) +{ + int i, type; + char *name, buf[BSIZE_SP]; + + for (i = 0; i < run->numData; i++) { + if (isdigit(*run->data[i].name)) { + (void) sprintf(buf, "V(%s)", run->data[i].name); + name = buf; + } else { + name = run->data[i].name; + } + if (substring("#branch", name)) + type = SV_CURRENT; + else if (cieq(name, "time")) + type = SV_TIME; + else if (cieq(name, "frequency")) + type = SV_FREQUENCY; + else + type = SV_VOLTAGE; + + fprintf(run->fp, "\t%d\t%s\t%s", i, name, + ft_typenames(type)); + if (run->data[i].gtype == GRID_XLOG) + fprintf(run->fp, "\tgrid=3"); + fprintf(run->fp, "\n"); + + } + + fprintf(run->fp, "%s:\n", run->binary ? "Binary" : "Values"); + + return; +} + +static void +fileStartPoint(FILE *fp, bool bin, int num) +{ + if (!bin) + fprintf(fp, "%d\t", num - 1); + + return; +} + +static void +fileAddRealValue(FILE *fp, bool bin, double value) +{ + if (bin) + fwrite((char *) &value, sizeof (double), 1, fp); + else + fprintf(fp, "\t%.*e\n", DOUBLE_PRECISION, value); + + return; +} + +static void +fileAddComplexValue(FILE *fp, bool bin, IFcomplex value) +{ + + if (bin) { + fwrite((char *) &value.real, sizeof (double), 1, fp); + fwrite((char *) &value.imag, sizeof (double), 1, fp); + } else { + fprintf(fp, "\t%.*e,%.*e\n", DOUBLE_PRECISION, value.real, + DOUBLE_PRECISION, value.imag); + } + +} + +/* ARGSUSED */ /* until some code gets written */ +static void +fileEndPoint(FILE *fp, bool bin) +{ + return; +} + +/* Here's the hack... Run back and fill in the number of points. */ + +static void +fileEnd(runDesc *run) +{ + long place; + + if (run->fp != stdout) { + place = ftell(run->fp); + fseek(run->fp, run->pointPos, 0); + fprintf(run->fp, "%d", run->pointCount); + fseek(run->fp, place, 0); + } else { + /* Yet another hack-around */ + fprintf(stderr, "@@@ %ld %d\n", run->pointPos, run->pointCount); + } + fflush(run->fp); + + return; +} + + + +/* The plot maintenance routines. */ + +static void +plotInit(runDesc *run) +{ + struct plot *pl = plot_alloc(run->type); + char buf[100]; + struct dvec *v; + dataDesc *dd; + int i; + + pl->pl_title = copy(run->name); + pl->pl_name = copy(run->type); + pl->pl_date = copy(datestring( )); + pl->pl_ndims = 0; + plot_new(pl); + plot_setcur(pl->pl_typename); + run->runPlot = pl; + + /* This is a hack. */ + /* if any of them complex, make them all complex */ + run->isComplex = FALSE; + for (i = 0; i < run->numData; i++) { + if (run->data[i].type == IF_COMPLEX) run->isComplex = TRUE; + } + + for (i = 0; i < run->numData; i++) { + dd = &run->data[i]; + v = alloc(struct dvec); + if (isdigit(*dd->name)) { + (void) sprintf(buf, "V(%s)", dd->name); + v->v_name = copy(buf); + } else + v->v_name = copy(dd->name); + if (substring("#branch", v->v_name)) + v->v_type = SV_CURRENT; + else if (cieq(v->v_name, "time")) + v->v_type = SV_TIME; + else if (cieq(v->v_name, "frequency")) + v->v_type = SV_FREQUENCY; + else + v->v_type = SV_VOLTAGE; + v->v_length = 0; + v->v_scale = NULL; + if (!run->isComplex) { + v->v_flags = VF_REAL; + v->v_realdata = NULL; + } else { + v->v_flags = VF_COMPLEX; + v->v_compdata = NULL; + } + + v->v_flags |= VF_PERMANENT; + + vec_new(v); + dd->vec = v; + } +} + +static void +plotAddRealValue(dataDesc *desc, double value) +{ + struct dvec *v = desc->vec; + + if (isreal(v)) { + v->v_realdata = (double *) trealloc((char *) v->v_realdata, + sizeof (double) * (v->v_length + 1)); + v->v_realdata[v->v_length] = value; + } else { + /* a real parading as a VF_COMPLEX */ + v->v_compdata = (complex *) trealloc((char *) v->v_compdata, + sizeof (complex) * (v->v_length + 1)); + v->v_compdata[v->v_length].cx_real = value; + v->v_compdata[v->v_length].cx_imag = (double) 0; + } + v->v_length++; + + return; +} + +static void +plotAddComplexValue(dataDesc *desc, IFcomplex value) +{ + struct dvec *v = desc->vec; + + v->v_compdata = (complex *) trealloc((char *) v->v_compdata, + sizeof (complex) * (v->v_length + 1)); + v->v_compdata[v->v_length].cx_real = value.real; + v->v_compdata[v->v_length].cx_imag = value.imag; + v->v_length++; + + return; +} + +/* ARGSUSED */ /* until some code gets written */ +static void +plotEnd(runDesc *run) +{ + + return; +} + + + +/* ParseSpecial takes something of the form "@name[param,index]" and rips + * out name, param, andstrchr. + */ + +static bool +parseSpecial(char *name, char *dev, char *param, char *ind) +{ + char *s; + + *dev = *param = *ind = '\0'; + + if (*name != '@') + return (FALSE); + name++; + + s = dev; + while (*name && (*name != '[')) + *s++ = *name++; + *s = '\0'; + if (!*name) + return (TRUE); + name++; + + s = param; + while (*name && (*name != ',') && (*name != ']')) + *s++ = *name++; + *s = '\0'; + if (*name == ']') + return (!name[1] ? TRUE : FALSE); + else if (!*name) + return (FALSE); + name++; + + s = ind; + while (*name && (*name != ']')) + *s++ = *name++; + *s = '\0'; + if (*name && !name[1]) + return (TRUE); + else + return (FALSE); +} + +/* This routine must match two names with or without a V() around them. */ + +static bool +name_eq(char *n1, char *n2) +{ + char buf1[BSIZE_SP], buf2[BSIZE_SP], *s; + + if ((s =strchr(n1, '('))) { + strcpy(buf1, s); + if (!(s =strchr(buf1, ')'))) + return (FALSE); + *s = '\0'; + n1 = buf1; + } + if ((s =strchr(n2, '('))) { + strcpy(buf2, s); + if (!(s =strchr(buf2, ')'))) + return (FALSE); + *s = '\0'; + n2 = buf2; + } + + return (strcmp(n1, n2) ? FALSE : TRUE); +} + +static bool +getSpecial(dataDesc *desc, runDesc *run, IFvalue *val) +{ + IFvalue selector; + struct variable *vv; + + selector.iValue = desc->specIndex; + if (INPaName(desc->specParamName, val, run->circuit, &desc->specType, + desc->specName, &desc->specFast, ft_sim, &desc->type, + &selector) == OK) { + desc->type &= (IF_REAL | IF_COMPLEX); /* mask out other bits */ + return(TRUE); + } else if ((vv = if_getstat(run->circuit, &desc->name[1]))) { + /* skip @ sign */ + desc->type = IF_REAL; + if (vv->va_type == VT_REAL) + val->rValue = vv->va_real; + else if (vv->va_type == VT_NUM) + val->rValue = vv->va_num; + else if (vv->va_type == VT_BOOL) + val->rValue = (vv->va_bool ? 1.0 : 0.0); + else { + return (FALSE); /* not a real */ + } + tfree(vv); + return(TRUE); + } + + return (FALSE); +} + +static void +freeRun(runDesc *run) +{ + + int i; + + for (i=0; i < run->numData; i++) { +/* vec_free(run->data[i].vec); */ /* kill run, leave plot */ + tfree(run->data[i].name); + tfree(run->data[i].specParamName); + } + tfree(run->data); + +/* killplot(run->runPlot); */ /* kill run, leave plot */ + + free(run->type); + free(run->name); + free(run); + +} + +int +OUTstopnow(void) +{ + + if (ft_intrpt || shouldstop) { + ft_intrpt = shouldstop = FALSE; + return (1); + } else + return (0); + +} + +/* Print out error messages. */ + +static struct mesg { + char *string; + long flag; +} msgs[] = { + { "Warning", ERR_WARNING } , + { "Fatal error", ERR_FATAL } , + { "Panic", ERR_PANIC } , + { "Note", ERR_INFO } , + { NULL, 0 } +} ; + +void +OUTerror(int flags, char *format, IFuid *names) +{ + + struct mesg *m; + char buf[BSIZE_SP], *s, *bptr; + int nindex = 0; + + if ((flags == ERR_INFO) && cp_getvar("printinfo", VT_BOOL, + (char *) &printinfo)) + return; + + for (m = msgs; m->flag; m++) + if (flags & m->flag) + fprintf(cp_err, "%s: ", m->string); + + for (s = format, bptr = buf; *s; s++) { + if (*s == '%' && (s == format || *(s-1) != '%') && *(s+1) == 's') { + if (names[nindex]) + strcpy(bptr, names[nindex]); + else + strcpy(bptr, "(null)"); + bptr += strlen(bptr); + s++; + nindex++; + } else { + *bptr++ = *s; + } + } + *bptr = '\0'; + fprintf(cp_err, "%s\n", buf); + fflush(cp_err); + +} diff --git a/src/frontend/outitf.h b/src/frontend/outitf.h new file mode 100644 index 000000000..39bcf3be7 --- /dev/null +++ b/src/frontend/outitf.h @@ -0,0 +1,58 @@ +/************* + * Header file for outitf.c + * 1999 E. Rouat + ************/ + +#ifndef OUTITF_H_INCLUDED +#define OUTITF_H_INCLUDED +typedef struct dataDesc { + char *name; /* The name of the vector. */ + int type; /* The type. */ + int gtype; /* default plot scale */ + bool regular; /* Is this given to us? */ + int outIndex; /* If regular then the index. */ + char *specName; /* The device name if special. */ + char *specParamName; /* The parameter name if special. */ + int specIndex; /* For sensitivity, if special. */ + int specType; + void *specFast; + int refIndex; /* The index of our ref vector. */ + struct dvec *vec; +} dataDesc; + +typedef struct runDesc { + void *analysis; + void *circuit; + char *name; + char *type; + int numData; + int refIndex; + dataDesc *data; + bool writeOut; + bool windowed; + bool binary; + struct plot *runPlot; + FILE *fp; + long pointPos; /* where to write pointCount */ + int pointCount; + int isComplex; + int windowCount; +} runDesc; + +int OUTpBeginPlot(void *circuitPtr, void *analysisPtr, IFuid analName, IFuid refName, + int refType, int numNames, IFuid *dataNames, int dataType, void **plotPtr); +int OUTwBeginPlot(void *circuitPtr, void *analysisPtr, IFuid analName, IFuid refName, + int refType, int numNames, IFuid *dataNames, int dataType, void **plotPtr); +int OUTpData(void *plotPtr, IFvalue *refValue, IFvalue *valuePtr); +int OUTwReference(void *plotPtr, IFvalue *valuePtr, void **refPtr); +int OUTwData(void *plotPtr, int dataIndex, IFvalue *valuePtr, void *refPtr); +int OUTwEnd(void *plotPtr); +int OUTendPlot(void *plotPtr); +int OUTbeginDomain(void *plotPtr, char *refName, int refType, IFvalue *outerRefValue); +int OUTendDomain(void *plotPtr); +int OUTattributes(void *plotPtr, char *varName, int param, IFvalue *value); +int OUTstopnow(void); +void OUTerror(int flags, char *format, IFuid *names); + + +#endif diff --git a/src/frontend/parse.c b/src/frontend/parse.c new file mode 100644 index 000000000..88cbf86a5 --- /dev/null +++ b/src/frontend/parse.c @@ -0,0 +1,813 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * A simple operator-precedence parser for algebraic expressions. + * This also handles relational and logical expressions. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteparse.h" +#include "ftedata.h" +#include "ftecmath.h" +#include "parse.h" + + +/* static declarations */ +static bool checkvalid(struct pnode *pn); +static struct element * lexer(void); +static struct pnode * parse(void); +static struct pnode * makepnode(struct element *elem); +static struct pnode * mkbnode(int opnum, struct pnode *arg1, struct pnode *arg2); +static struct pnode * mkunode(int op, struct pnode *arg); +static struct pnode * mkfnode(char *func, struct pnode *arg); +static struct pnode * mknnode(double number); +static struct pnode * mksnode(char *string); + + +static int lasttoken = END, lasttype; +static char *sbuf; + +struct pnode * +ft_getpnames(wordlist *wl, bool check) +{ + struct pnode *pn = NULL, *lpn = NULL, *p; + char *xsbuf; + char buf[BSIZE_SP], *thisone, *s; + + if (!wl) { + fprintf(cp_err, "Warning: NULL arithmetic expression\n"); + return (NULL); + } + + lasttoken = END; + xsbuf = sbuf = wl_flatten(wl); + thisone = sbuf; + while (*sbuf != '\0') { + if (!(p = parse())) { + tfree(xsbuf); + return (NULL); + } + + /* Now snag the name... Much trouble... */ + while (isspace(*thisone)) + thisone++; + for (s = buf; thisone < sbuf; s++, thisone++) + *s = *thisone; + *s = '\0'; + p->pn_name = copy(buf); + + if (pn) { + lpn->pn_next = p; + lpn = p; + } else + pn = lpn = p; + } + tfree(xsbuf); + if (check) + if (!checkvalid(pn)) + return (NULL); + return (pn); +} + +/* See if there are any variables around which have length 0 and are + * not named 'list'. There should really be another flag for this... + */ + +static bool +checkvalid(struct pnode *pn) +{ + while (pn) { + if (pn->pn_value) { + if ((pn->pn_value->v_length == 0) && + !eq(pn->pn_value->v_name, "list")) { + if (eq(pn->pn_value->v_name, "all")) + fprintf(cp_err, + "Error: %s: no matching vectors.\n", + pn->pn_value->v_name); + else + fprintf(cp_err, + "Error: %s: no such vector.\n", + pn->pn_value->v_name); + return (FALSE); + } + } else if (pn->pn_func || + (pn->pn_op && (pn->pn_op->op_arity == 1))) { + if (!checkvalid(pn->pn_left)) + return (FALSE); + } else if (pn->pn_op && (pn->pn_op->op_arity == 2)) { + if (!checkvalid(pn->pn_left)) + return (FALSE); + if (!checkvalid(pn->pn_right)) + return (FALSE); + } else + fprintf(cp_err, + "checkvalid: Internal Error: bad node\n"); + pn = pn->pn_next; + } + return (TRUE); +} + +/* Everything else is a string or a number. Quoted strings are kept in + * the form "string", and the lexer strips off the quotes... + */ + +static struct element * +lexer(void) +{ + double *td; + int j = 0; + static struct element el; + static struct element end = { END }; + static char *specials = " \t%()-^+*,/|&<>~="; + static bool bracflag = FALSE; + char *ss, *s; + int atsign; + + if (bracflag) { + bracflag = FALSE; + el.e_token = LPAREN; + goto done; + } + + el.e_token = END; + while ((*sbuf == ' ') || (*sbuf == '\t')) + sbuf++; + if (*sbuf == '\0') + goto done; + + switch (*sbuf) { + + case '-': + if ((lasttoken == VALUE) || (lasttoken == RPAREN)) + el.e_token = MINUS; + else + el.e_token = UMINUS; + sbuf++; + break; + + case '+': + el.e_token = PLUS; + sbuf++; + break; + + case ',': + el.e_token = COMMA; + sbuf++; + break; + + case '*': + el.e_token = TIMES; + sbuf++; + break; + + case '%': + el.e_token = MOD; + sbuf++; + break; + + case '/': + el.e_token = DIVIDE; + sbuf++; + break; + + case '^': + el.e_token = POWER; + sbuf++; + break; + + case '[': + if (sbuf[1] == '[') { + el.e_token = RANGE; + sbuf += 2; + } else { + el.e_token = INDX; + sbuf++; + } + bracflag = TRUE; + break; + + case '(': + if (((lasttoken == VALUE) && ((lasttype == NUM))) || (lasttoken + == RPAREN)) { + el = end; + goto done; + } else { + el.e_token = LPAREN; + sbuf++; + break; + } + + case ']': + el.e_token = RPAREN; + if (sbuf[1] == ']') + sbuf += 2; + else + sbuf++; + break; + + case ')': + el.e_token = RPAREN; + sbuf++; + break; + + case '=': + el.e_token = EQ; + sbuf++; + break; + + case '>': + case '<': + for (j = 0; isspace(sbuf[j]); j++) + ; /* The lexer makes <> into < > */ + if (((sbuf[j] == '<') || (sbuf[j] == '>')) && + (sbuf[0] != sbuf[j])) { + /* Allow both <> and >< for NE. */ + el.e_token = NE; + sbuf += 2 + j; + } else if (sbuf[1] == '=') { + if (sbuf[0] == '>') + el.e_token = GE; + else + el.e_token = LE; + sbuf += 2; + } else { + if (sbuf[0] == '>') + el.e_token = GT; + else + el.e_token = LT; + sbuf++; + } + break; + + case '&': + el.e_token = AND; + sbuf++; + break; + + case '|': + el.e_token = OR; + sbuf++; + break; + + case '~': + el.e_token = NOT; + sbuf++; + break; + + case '"': + if ((lasttoken == VALUE) || (lasttoken == RPAREN)) { + el = end; + goto done; + } + el.e_token = VALUE; + el.e_type = STRING; + el.e_string = copy(++sbuf); + for (s = el.e_string; *s && (*s != '"'); s++, sbuf++) + ; + *s = '\0'; + sbuf++; + break; + } + + if (el.e_token != END) + goto done; + + ss = sbuf; + td = ft_numparse(&ss, FALSE); + if ((!ss || *ss != ':') && td) { + if ((lasttoken == VALUE) || (lasttoken == RPAREN)) { + el = end; + goto done; + } + el.e_double = *td; + el.e_type = NUM; + el.e_token = VALUE; + sbuf = ss; + if (ft_parsedb) + fprintf(stderr, "lexer: double %G\n", + el.e_double); + } else { + /* First, let's check for eq, ne, and so on. */ + if ((sbuf[0] == 'g') && (sbuf[1] == 't') && + strchr(specials, sbuf[2])) { + el.e_token = GT; + sbuf += 2; + } else if ((sbuf[0] == 'l') && (sbuf[1] == 't') && + strchr(specials, sbuf[2])) { + el.e_token = LT; + sbuf += 2; + } else if ((sbuf[0] == 'g') && (sbuf[1] == 'e') && + strchr(specials, sbuf[2])) { + el.e_token = GE; + sbuf += 2; + } else if ((sbuf[0] == 'l') && (sbuf[1] == 'e') && + strchr(specials, sbuf[2])) { + el.e_token = LE; + sbuf += 2; + } else if ((sbuf[0] == 'n') && (sbuf[1] == 'e') && + strchr(specials, sbuf[2])) { + el.e_token = NE; + sbuf += 2; + } else if ((sbuf[0] == 'e') && (sbuf[1] == 'q') && + strchr(specials, sbuf[2])) { + el.e_token = EQ; + sbuf += 2; + } else if ((sbuf[0] == 'o') && (sbuf[1] == 'r') && + strchr(specials, sbuf[2])) { + el.e_token = OR; + sbuf += 2; + } else if ((sbuf[0] == 'a') && (sbuf[1] == 'n') && + (sbuf[2] == 'd') &&strchr(specials, sbuf[3])) { + el.e_token = AND; + sbuf += 3; + } else if ((sbuf[0] == 'n') && (sbuf[1] == 'o') && + (sbuf[2] == 't') &&strchr(specials, sbuf[3])) { + el.e_token = NOT; + sbuf += 3; + } else { + if ((lasttoken == VALUE) || (lasttoken == RPAREN)) { + el = end; + goto done; + } + el.e_string = copy(sbuf); /* XXXX !!!! */ + /* It is bad how we have to recognise '[' -- sometimes + * it is part of a word, when it defines a parameter + * name, and otherwise it isn't. + */ + atsign = 0; + for (s = el.e_string; *s && !index(specials, *s); s++, sbuf++) { + if (*s == '@') + atsign = 1; + else if (*s == '[' && !atsign) + break; + } + if (*s) + *s = '\0'; + el.e_type = STRING; + el.e_token = VALUE; + if (ft_parsedb) + fprintf(stderr, "lexer: string %s\n", + el.e_string); + } + } +done: + lasttoken = el.e_token; + lasttype = el.e_type; + if (ft_parsedb) + fprintf(stderr, "lexer: token %d\n", el.e_token); + return (&el); +} + +/* The operator-precedence parser. */ + +#define G 1 /* Greater than. */ +#define L 2 /* Less than. */ +#define E 3 /* Equal. */ +#define R 4 /* Error. */ + +#define STACKSIZE 200 + +static char prectable[23][23] = { + /* $ + - * % / ^ u- ( ) , v = > < >= <= <> & | ~ IDX R */ +/* $ */ { R, L, L, L, L, L, L, L, L, R, L, L, L, L, L, L, L, L, L, L, L, L, L }, +/* + */ { G, G, G, L, L, L, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L }, +/* - */ { G, G, G, L, L, L, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L }, +/* * */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L }, +/* % */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L }, +/* / */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L }, +/* ^ */ { G, G, G, G, G, G, L, L, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L }, +/* u-*/ { G, G, G, G, G, G, G, G, L, G, G, L, G, G, G, G, G, G, G, G, G, L, L }, +/* ( */ { R, L, L, L, L, L, L, L, L, E, L, L, L, L, L, L, L, L, L, L, L, L, L }, +/* ) */ { G, G, G, G, G, G, G, G, R, G, G, R, G, G, G, G, G, G, G, G, G, G, G }, +/* , */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, G, L, L }, +/* v */ { G, G, G, G, G, G, G, G, G, G, G, R, G, G, G, G, G, G, G, G, G, G, G }, +/* = */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L }, +/* > */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L }, +/* < */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L }, +/* >=*/ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L }, +/* <=*/ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L }, +/* <>*/ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, L, L, L }, +/* & */ { G, L, L, L, L, L, L, L, L, G, L, L, L, L, L, L, L, L, G, G, L, L, L }, +/* | */ { G, L, L, L, L, L, L, L, L, G, L, L, L, L, L, L, L, L, L, G, L, L, L }, +/* ~ */ { G, L, L, L, L, L, L, L, L, G, L, L, G, G, G, G, G, G, G, G, G, L, L }, +/*INDX*/{ G, G, G, G, G, G, G, G, L, G, G, L, G, G, G, G, G, G, G, G, G, G, L }, +/*RAN*/ { G, G, G, G, G, G, G, G, L, G, G, L, G, G, G, G, G, G, G, G, G, G, G } +} ; + +/* Return an expr. */ + +static struct pnode * +parse(void) +{ + struct element stack[STACKSIZE]; + int sp = 0, st, i; + struct element *top, *next; + struct pnode *pn, *lpn, *rpn; + char rel; + + stack[0].e_token = END; + next = lexer(); + + while ((sp > 1) || (next->e_token != END)) { + /* Find the top-most terminal. */ + i = sp; + do { + top = &stack[i--]; + } while (top->e_token == VALUE); + rel = prectable[top->e_token][next->e_token]; + switch (rel) { + case L: + case E: + /* Push the token read. */ + if (sp == (STACKSIZE - 1)) { + fprintf(cp_err, "Error: stack overflow\n"); + return (NULL); + } + bcopy((char *) next, (char *) &stack[++sp], + sizeof (struct element)); + next = lexer(); + continue; + + case R: + fprintf(cp_err, "Syntax error: parsing expression.\n"); + return (NULL); + + case G: + /* Reduce. Make st and sp point to the elts on the + * stack at the end and beginning of the junk to + * reduce, then try and do some stuff. When scanning + * back for a <, ignore VALUES. + */ + st = sp; + if (stack[sp].e_token == VALUE) + sp--; + while (sp > 0) { + if (stack[sp - 1].e_token == VALUE) + i = 2; /* No 2 pnodes together... */ + else + i = 1; + if (prectable[stack[sp - i].e_token] + [stack[sp].e_token] == L) + break; + else + sp = sp - i; + } + if (stack[sp - 1].e_token == VALUE) + sp--; + /* Now try and see what we can make of this. + * The possibilities are: unop node + * node op node + * ( node ) + * func ( node ) + * node + * node [ node ] is considered node op node. + */ + if (st == sp) { + pn = makepnode(&stack[st]); + if (pn == NULL) + goto err; + } else if (((stack[sp].e_token == UMINUS) || + (stack[sp].e_token == NOT)) && + (st == sp + 1)) { + lpn = makepnode(&stack[st]); + if (lpn == NULL) + goto err; + pn = mkunode(stack[sp].e_token, lpn); + } else if ((stack[sp].e_token == LPAREN) && + (stack[st].e_token == RPAREN)) { + pn = makepnode(&stack[sp + 1]); + if (pn == NULL) + goto err; + } else if ((stack[sp + 1].e_token == LPAREN) && + (stack[st].e_token == RPAREN)) { + lpn = makepnode(&stack[sp + 2]); + if ((lpn == NULL) || (stack[sp].e_type != + STRING)) + goto err; + if (!(pn = mkfnode(stack[sp].e_string, lpn))) + return (NULL); + } else { /* node op node */ + lpn = makepnode(&stack[sp]); + rpn = makepnode(&stack[st]); + if ((lpn == NULL) || (rpn == NULL)) + goto err; + pn = mkbnode(stack[sp + 1].e_token, + lpn, rpn); + } + stack[sp].e_token = VALUE; + stack[sp].e_type = PNODE; + stack[sp].e_pnode = pn; + continue; + } + } + pn = makepnode(&stack[1]); + if (pn) + return (pn); +err: + fprintf(cp_err, "Syntax error: expression not understood.\n"); + return (NULL); +} + +/* Given a pointer to an element, make a pnode out of it (if it already + * is one, return a pointer to it). If it isn't of type VALUE, then return + * NULL. + */ + +static struct pnode * +makepnode(struct element *elem) +{ + if (elem->e_token != VALUE) + return (NULL); + switch (elem->e_type) { + case STRING: + return (mksnode(elem->e_string)); + case NUM: + return (mknnode(elem->e_double)); + case PNODE: + return (elem->e_pnode); + default: + return (NULL); + } +} + +/* Some auxiliary functions for building the parse tree. */ + +static +struct op ops[] = { + { PLUS, "+", 2, op_plus } , + { MINUS, "-", 2, op_minus } , + { TIMES, "*", 2, op_times } , + { MOD, "%", 2, op_mod } , + { DIVIDE, "/", 2, op_divide } , + { COMMA, ",", 2, op_comma } , + { POWER, "^", 2, op_power } , + { EQ, "=", 2, op_eq } , + { GT, ">", 2, op_gt } , + { LT, "<", 2, op_lt } , + { GE, ">=", 2, op_ge } , + { LE, "<=", 2, op_le } , + { NE, "<>", 2, op_ne } , + { AND, "&", 2, op_and } , + { OR, "|", 2, op_or } , + { INDX, "[", 2, op_ind } , + { RANGE, "[[", 2, op_range } , + { 0, NULL, 0, NULL } +} ; + +static +struct op uops[] = { + { UMINUS, "-", 1, op_uminus } , + { NOT, "~", 1, op_not } , + { 0, NULL, 0, NULL } +} ; + +/* We have 'v' declared as a function, because if we don't then the defines + * we do for vm(), etc won't work. This is caught in evaluate(). Bad kludge. + */ + +struct func ft_funcs[] = { + { "mag", cx_mag } , + { "magnitude", cx_mag } , + { "ph", cx_ph } , + { "phase", cx_ph } , + { "j", cx_j } , + { "real", cx_real } , + { "re", cx_real } , + { "imag", cx_imag } , + { "im", cx_imag } , + { "db", cx_db } , + { "log", cx_log } , + { "log10", cx_log } , + { "ln", cx_ln } , + { "exp", cx_exp } , + { "abs", cx_mag } , + { "sqrt", cx_sqrt } , + { "sin", cx_sin } , + { "cos", cx_cos } , + { "tan", cx_tan } , + { "atan", cx_atan } , + { "norm", cx_norm } , + { "rnd", cx_rnd } , + { "pos", cx_pos } , + { "mean", cx_mean } , + { "vector", cx_vector } , + { "unitvec", cx_unitvec } , + { "length", cx_length } , + { "interpolate",cx_interpolate } , + { "deriv", cx_deriv } , + { "v", NULL } , + { NULL, NULL } +} ; + +struct func func_uminus = { "minus", cx_uminus }; + +struct func func_not = { "not", cx_not }; + +/* Binop node. */ + +static struct pnode * +mkbnode(int opnum, struct pnode *arg1, struct pnode *arg2) +{ + struct op *o; + struct pnode *p; + + for (o = &ops[0]; o->op_name; o++) + if (o->op_num == opnum) + break; + if (!o->op_name) + fprintf(cp_err, "mkbnode: Internal Error: no such op num %d\n", + opnum); + p = alloc(struct pnode); + p->pn_value = NULL; + p->pn_func = NULL; + p->pn_op = o; + p->pn_left = arg1; + p->pn_right = arg2; + p->pn_next = NULL; + return (p); +} + +/* Unop node. */ + +static struct pnode * +mkunode(int op, struct pnode *arg) +{ + struct pnode *p; + struct op *o; + + p = alloc(struct pnode); + for (o = uops; o->op_name; o++) + if (o->op_num == op) + break; + if (!o->op_name) + fprintf(cp_err, "mkunode: Internal Error: no such op num %d\n", + op); + + p->pn_op = o; + p->pn_value = NULL; + p->pn_func = NULL; + p->pn_left = arg; + p->pn_right = NULL; + p->pn_next = NULL; + return (p); +} + +/* Function node. We have to worry about a lot of things here. Something + * like f(a) could be three things -- a call to a standard function, which + * is easiest to deal with, a variable name, in which case we do the + * kludge with 0-length lists, or it could be a user-defined function, + * in which case we have to figure out which one it is, substitute for + * the arguments, and then return a copy of the expression that it was + * defined to be. + */ + +static struct pnode * +mkfnode(char *func, struct pnode *arg) +{ + struct func *f; + struct pnode *p, *q; + struct dvec *d; + char buf[BSIZE_SP], *s; + + (void) strcpy(buf, func); + for (s = buf; *s; s++) /* Make sure the case is ok. */ + if (isupper(*s)) + *s = tolower(*s); + for (f = &ft_funcs[0]; f->fu_name; f++) + if (eq(f->fu_name, buf)) + break; + if (f->fu_name == NULL) { + /* Give the user-defined functions a try. */ + q = ft_substdef(func, arg); + if (q) + return (q); + } + if ((f->fu_name == NULL) && arg->pn_value) { + /* Kludge -- maybe it is really a variable name. */ + (void) sprintf(buf, "%s(%s)", func, arg->pn_value->v_name); + d = vec_get(buf); + if (d == NULL) { + /* Well, too bad. */ + fprintf(cp_err, "Error: no such function as %s.\n", + func); + return (NULL); + } + /* (void) strcpy(buf, d->v_name); XXX */ + return (mksnode(buf)); + } else if (f->fu_name == NULL) { + fprintf(cp_err, "Error: no function as %s with that arity.\n", + func); + return (NULL); + } + + if (!f->fu_func && arg->pn_op && arg->pn_op->op_num == COMMA) { + p = mkbnode(MINUS, mkfnode(func, arg->pn_left), + mkfnode(func, arg->pn_right)); + tfree(arg); + return p; + } + + p = alloc(struct pnode); + p->pn_name = NULL; + p->pn_value = NULL; + p->pn_func = f; + p->pn_op = NULL; + p->pn_left = arg; + p->pn_right = NULL; + p->pn_next = NULL; + return (p); +} + +/* Number node. */ + +static struct pnode * +mknnode(double number) +{ + struct pnode *p; + struct dvec *v; + char buf[BSIZE_SP]; + + p = alloc(struct pnode); + v = alloc(struct dvec); + ZERO(v, struct dvec); + p->pn_name = NULL; + p->pn_value = v; + p->pn_func = NULL; + p->pn_op = NULL; + p->pn_left = p->pn_right = NULL; + p->pn_next = NULL; + + /* We don't use printnum because it screws up mkfnode above. We have + * to be careful to deal properly with node numbers that are quite + * large... + */ + if (number < MAXPOSINT) + (void) sprintf(buf, "%d", (int) number); + else + (void) sprintf(buf, "%G", number); + v->v_name = copy(buf); + v->v_type = SV_NOTYPE; + v->v_flags = VF_REAL; + v->v_realdata = (double *) tmalloc(sizeof (double)); + *v->v_realdata = number; + v->v_length = 1; + v->v_plot = NULL; + vec_new(v); + return (p); +} + +/* String node. */ + +static struct pnode * +mksnode(char *string) +{ + struct dvec *v, *nv, *vs, *newv = NULL, *end = NULL; + struct pnode *p; + + p = alloc(struct pnode); + p->pn_name = NULL; + p->pn_func = NULL; + p->pn_op = NULL; + p->pn_left = p->pn_right = NULL; + p->pn_next = NULL; + v = vec_get(string); + if (v == NULL) { + nv = alloc(struct dvec); + ZERO(nv, struct dvec); + p->pn_value = nv; + nv->v_name = copy(string); + return (p); + } + p->pn_value = NULL; + + /* It's not obvious that we should be doing this, but... */ + for (vs = v; vs; vs = vs->v_link2) { + nv = vec_copy(vs); + vec_new(nv); + if (end) + end->v_link2 = nv; + else + newv = end = nv; + end = nv; + } + p->pn_value = newv; + return (p); +} + + +void +free_pnode(struct pnode *t) +{ + if (!t) + return; + free_pnode(t->pn_left); + free_pnode(t->pn_right); + free_pnode(t->pn_next); + tfree(t); +} + diff --git a/src/frontend/parse.h b/src/frontend/parse.h new file mode 100644 index 000000000..46d8bbe61 --- /dev/null +++ b/src/frontend/parse.h @@ -0,0 +1,13 @@ +/************* + * Header file for parse.c + * 1999 E. Rouat + ************/ + +#ifndef PARSE_H_INCLUDED +#define PARSE_H_INCLUDED + +struct pnode * ft_getpnames(wordlist *wl, bool check); +void free_pnode(struct pnode *t); + + +#endif diff --git a/src/frontend/plot5.c b/src/frontend/plot5.c new file mode 100644 index 000000000..4a1e7de85 --- /dev/null +++ b/src/frontend/plot5.c @@ -0,0 +1,180 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include "ftegraph.h" +#include "ftedev.h" +#include "fteinput.h" +#include "plot5.h" + +static FILE *plotfile; + +#define putsi(a) putc((char) (a), plotfile); \ + putc((char) ((a) >> 8), plotfile) + +#define SOLID 0 +static char *linestyle[] = { "solid", "dotted", "longdashed", "shortdashed", + "dotdashed" }; +static int currentlinestyle = SOLID; + + +extern void gr_relinestyle (GRAPH *graph); +extern void internalerror (char *message); + +int +Plt5_Init(void) +{ + + dispdev->numlinestyles = 4; + dispdev->numcolors = 2; + + /* arbitrary */ + dispdev->width = 1000; + dispdev->height = 1000; + + return(0); + +} + +int +Plt5_NewViewport(GRAPH *graph) +{ + + if (!(plotfile = fopen(graph->devdep, "w"))) { + graph->devdep = (char *) NULL; + perror(graph->devdep); + return(1); + } + + if (graph->absolute.width) { + + /* hardcopying from the scree, + ie, we are passed a copy of an existing graph */ + putc('s', plotfile); + putsi(0); + putsi(0); + putsi(graph->absolute.width); + putsi(graph->absolute.height); + + /* re-scale linestyles */ + gr_relinestyle(graph); + + } else { + /* scale space */ + putc('s', plotfile); + putsi(0); + putsi(0); + putsi(dispdev->width); + putsi(dispdev->height); + + /* reasonable values, used in gr_ for placement */ + graph->fontwidth = 12; + graph->fontheight = 24; + + graph->absolute.width = dispdev->width; + graph->absolute.height = dispdev->height; + + } + + /* set to NULL so graphdb doesn't incorrectly de-allocate it */ + graph->devdep = (char *) NULL; + + return(0); + +} + +void +Plt5_Close(void) +{ + + /* in case Plt5_Close is called as part of an abort, + w/o having reached Plt5_NewViewport */ + if (plotfile) + fclose(plotfile); + +} + +void +Plt5_Clear(void) +{ + + /* do nothing */ + +} + +void +Plt5_DrawLine(int x1, int y1, int x2, int y2) +{ + + putc('l', plotfile); + putsi(x1); + putsi(y1); + putsi(x2); + putsi(y2); + +} + +/* ARGSUSED */ /* until some code gets written */ +void +Plt5_Arc(int x0, int y0, int radius, double theta1, double theta2) +{ + + +} + +void +Plt5_Text(char *text, int x, int y) +{ + + int savedlstyle; + + /* set linestyle to solid + or may get funny color text on some plotters */ + savedlstyle = currentlinestyle; + Plt5_SetLinestyle(SOLID); + + /* move to (x, y) */ + putc('m', plotfile); + putsi(x); + putsi(y); + + /* use the label option */ + fprintf(plotfile, "t%s\n", text); + + /* restore old linestyle */ + Plt5_SetLinestyle(savedlstyle); + +} + +int +Plt5_SetLinestyle(int linestyleid) +{ + + if (linestyleid < 0 || linestyleid > dispdev->numlinestyles) { + internalerror("bad linestyleid"); + return 0; + } + putc('f', plotfile); + fprintf(plotfile, "%s\n", linestyle[linestyleid]); + currentlinestyle = linestyleid; + return 0; +} + +/* ARGSUSED */ +void +Plt5_SetColor(int colorid) +{ + + /* do nothing */ + +} + +void +Plt5_Update(void) +{ + + fflush(plotfile); + +} + diff --git a/src/frontend/plot5.h b/src/frontend/plot5.h new file mode 100644 index 000000000..4b4e68528 --- /dev/null +++ b/src/frontend/plot5.h @@ -0,0 +1,20 @@ +/************* + * Header file for plot5.c + * 1999 E. Rouat + ************/ + +#ifndef PLOT5_H_INCLUDED +#define PLOT5_H_INCLUDED + +int Plt5_Init(void); +int Plt5_NewViewport(GRAPH *graph); +void Plt5_Close(void); +void Plt5_Clear(void); +void Plt5_DrawLine(int x1, int y1, int x2, int y2); +void Plt5_Arc(int x0, int y0, int radius, double theta1, double theta2); +void Plt5_Text(char *text, int x, int y); +int Plt5_SetLinestyle(int linestyleid); +void Plt5_SetColor(int colorid); +void Plt5_Update(void); + +#endif diff --git a/src/frontend/plotcurv.c b/src/frontend/plotcurv.c new file mode 100644 index 000000000..d52896561 --- /dev/null +++ b/src/frontend/plotcurv.c @@ -0,0 +1,364 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Curve plotting routines and general (non-graphics) plotting things. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftegraph.h" +#include "ftedbgra.h" +#include "plotcurv.h" + + +static void plotinterval(struct dvec *v, double lo, double hi, register double *coeffs, + int degree, bool rotated); + + +/* Plot the vector v, with scale xs. If we are doing curve-fitting, then + * do some tricky stuff. + */ + +void +ft_graf(struct dvec *v, struct dvec *xs, bool nostart) +{ + int degree, gridsize, length; + register int i, j, l; + double *scratch, *result, *gridbuf, *mm; + register double *xdata, *ydata; + bool rot, increasing; + double dx, dy, lx = 0, ly = 0; + int dir; + + /* if already started, use saved degree */ + if (nostart) { + degree = currentgraph->degree; + } else { + if (!cp_getvar("polydegree", VT_NUM, (char *) °ree)) + degree = 1; + currentgraph->degree = degree; + } + if (degree > v->v_length) + degree = v->v_length; + if (degree < 1) { + fprintf(cp_err, "Error: polydegree is %d, can't plot...\n", + degree); + return; + } + + if (!cp_getvar("gridsize", VT_NUM, (char *) &gridsize)) + gridsize = 0; + if ((gridsize < 0) || (gridsize > 10000)) { + fprintf(cp_err, "Error: bad grid size %d\n", gridsize); + return; + } + if (gridsize && xs) { + if( isreal(xs) ) { + increasing = (xs->v_realdata[0] < xs->v_realdata[1]); + for (i = 0; i < xs->v_length - 1; i++) + if (increasing != (xs->v_realdata[i] < + xs->v_realdata[i + 1])) { + fprintf(cp_err, + "Warning: scale not monotonic, gridsize not relevant.\n"); + gridsize = 0; + break; + } + } else { + increasing = (realpart (&xs->v_compdata[0]) < + realpart( &xs->v_compdata[1])); + for (i = 0; i < xs->v_length - 1; i++) + if (increasing != (realpart( &xs->v_compdata[i]) < + realpart( &xs->v_compdata[i + 1]))) { + fprintf(cp_err, + "Warning: scale not monotonic, gridsize not relevant.\n"); + gridsize = 0; + break; + } + } + } + + if (!nostart) + gr_start(v); + + /* Do the one value case */ + + if (!xs) { + for (i = 0; i < v->v_length; i++) { + +/* We should do the one - point case too! + * Important for pole-zero for example + */ + if( v->v_length == 1 ) { + j = 0; + } else { + j = i-1; + if( i == 0 ) + continue; + } + + if (isreal(v)) { + /* This isn't good but we may as well do + * something useful. + */ + gr_point(v, v->v_realdata[i], + v->v_realdata[i], + v->v_realdata[j], + v->v_realdata[j], (j==i ? 1 : i)); + } else { + gr_point(v, realpart(&v->v_compdata[i]), + imagpart(&v->v_compdata[i]), + realpart(&v->v_compdata[j]), + imagpart(&v->v_compdata[j]), (j==i ? 1 : i)); + } + } + gr_end(v); + return; + } + + xs->v_flags |= VF_PERMANENT; + + /* First check the simple case, where we don't have to do any + * interpolation. + */ + if ((degree == 1) && (gridsize == 0)) { + dir = 0; + for (i = 0, j = v->v_length; i < j; i++) { + dx = isreal(xs) ? xs->v_realdata[i] : + realpart(&xs->v_compdata[i]); + dy = isreal(v) ? v->v_realdata[i] : + realpart(&v->v_compdata[i]); + if ((i == 0 || (dir > 0 ? lx > dx : dir < 0 ? lx < dx : 0)) + && xs->v_plot->pl_scale == xs) + { + gr_point(v, dx, dy, lx, ly, 0); + } else { + gr_point(v, dx, dy, lx, ly, i); + if (!dir) + dir = lx > dx ? -1 : lx < dx ? 1 : 0; + } + lx = dx; + ly = dy; + } + if (v->v_length == 1) + gr_point(v, dx, dy, lx, ly, 1); + gr_end(v); + return; + } + + if (gridsize < degree + 1) + gridsize = 0; + + if (gridsize) { + /* This is done quite differently from what we do below... */ + gridbuf = (double *) tmalloc(gridsize * sizeof (double)); + result = (double *) tmalloc(gridsize * sizeof (double)); + if (isreal(v)) + ydata = v->v_realdata; + else { + ydata = (double *) tmalloc(v->v_length * + sizeof (double)); + for (i = 0; i < v->v_length; i++) + ydata[i] = realpart(&v->v_compdata[i]); + } + if (isreal(xs)) + xdata = xs->v_realdata; + else { + xdata = (double *) tmalloc(xs->v_length * + sizeof (double)); + for (i = 0; i < xs->v_length; i++) + xdata[i] = realpart(&xs->v_compdata[i]); + } + + mm = ft_minmax(xs, TRUE); + dx = (mm[1] - mm[0]) / gridsize; + if (increasing) + for (i = 0, dy = mm[0]; i < gridsize; i++, dy += dx) + gridbuf[i] = dy; + else + for (i = 0, dy = mm[1]; i < gridsize; i++, dy -= dx) + gridbuf[i] = dy; + if (!ft_interpolate(ydata, result, xdata, v->v_length, gridbuf, + gridsize, degree)) { + fprintf(cp_err, "Error: can't put %s on gridsize %d\n", + v->v_name, gridsize); + return; + } + /* Now this is a problem. There's no way that we can + * figure out where to put the tic marks to correspond with + * the actual data... + */ + for (i = 0; i < gridsize; i++) + gr_point(v, gridbuf[i], result[i], gridbuf[i ? (i - 1) + : i], result[i ? (i - 1) : i], -1); + gr_end(v); + tfree(gridbuf); + tfree(result); + if (!isreal(v)) + tfree(ydata); + if (!isreal(xs)) + tfree(xdata); + return; + } + + /* We need to do curve fitting now. First get some scratch + * space + */ + scratch = (double *) tmalloc((degree + 1) * (degree + 2) * + sizeof (double)); + result = (double *) tmalloc((degree + 1) * sizeof (double)); + xdata = (double *) tmalloc((degree + 1) * sizeof (double)); + ydata = (double *) tmalloc((degree + 1) * sizeof (double)); + + + /* Plot the first degree segments... */ + if (isreal(v)) + bcopy((char *) v->v_realdata, (char *) ydata, + (degree + 1) * sizeof (double)); + else + for (i = 0; i <= degree; i++) + ydata[i] = realpart(&v->v_compdata[i]); + if (isreal(xs)) + bcopy((char *) xs->v_realdata, (char *) xdata, + (degree + 1) * sizeof (double)); + else + for (i = 0; i <= degree; i++) + xdata[i] = realpart(&xs->v_compdata[i]); + + rot = FALSE; + while (!ft_polyfit(xdata, ydata, result, degree, scratch)) { + /* Rotate the coordinate system 90 degrees and try again. + * If it doesn't work this time, bump the interpolation + * degree down by one... + */ + if (ft_polyfit(ydata, xdata, result, degree, scratch)) { + rot = TRUE; + break; + } + if (--degree == 0) { + fprintf(cp_err, "plotcurve: Internal Error: ack...\n"); + return; + } + } + + /* Plot this part of the curve... */ + for (i = 0; i < degree; i++) + if (rot) + plotinterval(v, ydata[i], ydata[i + 1], result, degree, + TRUE); + else + plotinterval(v, xdata[i], xdata[i + 1], result, degree, + FALSE); + + /* Now plot the rest, piece by piece... l is the + * last element under consideration. + */ + length = v->v_length; + for (l = degree + 1; l < length; l++) { + + /* Shift the old stuff by one and get another value. */ + for (i = 0; i < degree; i++) { + xdata[i] = xdata[i + 1]; + ydata[i] = ydata[i + 1]; + } + if (isreal(v)) + ydata[i] = v->v_realdata[l]; + else + ydata[i] = realpart(&v->v_compdata[l]); + if (isreal(xs)) + xdata[i] = xs->v_realdata[l]; + else + xdata[i] = realpart(&xs->v_compdata[l]); + + rot = FALSE; + while (!ft_polyfit(xdata, ydata, result, degree, scratch)) { + if (ft_polyfit(ydata, xdata, result, degree, scratch)) { + rot = TRUE; + break; + } + if (--degree == 0) { + fprintf(cp_err, + "plotcurve: Internal Error: ack...\n"); + return; + } + } + if (rot) + plotinterval(v, ydata[degree - 1], ydata[degree], + result, degree, TRUE); + else + plotinterval(v, xdata[degree - 1], xdata[degree], + result, degree, FALSE); + } + tfree(scratch); + tfree(xdata); + tfree(ydata); + tfree(result); + gr_end(v); + return; +} + +#define GRANULARITY 10 + +static void +plotinterval(struct dvec *v, double lo, double hi, register double *coeffs, int degree, bool rotated) +{ + double incr, dx, dy, lx, ly; + register int i; + int steps; + + /* + fprintf(cp_err, "plotinterval(%s, %G, %G, [ ", v->v_name, lo, hi); + for (i = 0; i <= degree; i++) + fprintf(cp_err, "%G ", coeffs[i]); + fprintf(cp_err, "], %d, %s)\n\r", degree, rotated ? "TRUE" : "FALSE"); + */ + + /* This is a problem -- how do we know what granularity to use? If + * the guy cares about this he will use gridsize. + */ + if (!cp_getvar("polysteps", VT_NUM, (char *) &steps)) + steps = GRANULARITY; + + incr = (hi - lo) / (double) (steps + 1); + dx = lo + incr; + lx = lo; + ly = ft_peval(lo, coeffs, degree); + for (i = 0; i <= steps; i++, dx += incr) { + dy = ft_peval(dx, coeffs, degree); + if (rotated) + gr_point(v, dy, dx, ly, lx, -1); + else + gr_point(v, dx, dy, lx, ly, -1); + lx = dx; + ly = dy; + /* fprintf(cp_err, "plot (%G, %G)\n\r", dx, dy); */ + } + return; +} + +#ifdef notdef + +static void +printmat(name, mat, m, n) + char *name; + double *mat; +{ + int i, j; + + printf("\n\r=== Matrix: %s ===\n\r", name); + for (i = 0; i < m; i++) { + printf(" | "); + for (j = 0; j < n; j++) + printf("%G ", mat[i * n + j]); + printf("|\n\r"); + } + printf("===\n\r"); + return; +} + +#endif + diff --git a/src/frontend/plotcurv.h b/src/frontend/plotcurv.h new file mode 100644 index 000000000..5f466cc6d --- /dev/null +++ b/src/frontend/plotcurv.h @@ -0,0 +1,12 @@ +/************* + * Header file for plotcurv.c + * 1999 E. Rouat + ************/ + +#ifndef PLOTCURV_H_INCLUDED +#define PLOTCURV_H_INCLUDED + +void ft_graf(struct dvec *v, struct dvec *xs, bool nostart); + + +#endif diff --git a/src/frontend/points.c b/src/frontend/points.c new file mode 100644 index 000000000..cfe2ee74c --- /dev/null +++ b/src/frontend/points.c @@ -0,0 +1,113 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftegraph.h" +#include "ftedbgra.h" +#include "points.h" + + +/* Returns the minimum and maximum values of a dvec. Returns a pointer to + * static data. If real is TRUE look at the real parts, otherwise the imag + * parts. + */ + + + +double * +ft_minmax(struct dvec *v, bool real) +{ + static double res[2]; + register int i; + double d; + + res[0] = HUGE; + res[1] = - res[0]; + + for (i = 0; i < v->v_length; i++) { + if (isreal(v)) + d = v->v_realdata[i]; + else if (real) + d = realpart(&v->v_compdata[i]); + else + d = imagpart(&v->v_compdata[i]); + if (d < res[0]) + res[0] = d; + if (d > res[1]) + res[1] = d; + } + return (res); +} + +/* Figure out where a point should go, given the limits of the plotting + * area and the type of scale (log or linear). + */ + +int +ft_findpoint(double pt, double *lims, int maxp, int minp, bool islog) +{ + double tl, th; + + if (pt < lims[0]) + pt = lims[0]; + if (pt > lims[1]) + pt = lims[1]; + if (islog) { + tl = mylog10(lims[0]); + th = mylog10(lims[1]); + return (((mylog10(pt) - tl) / (th - tl)) * + (maxp - minp) + minp); + } else { + return (((pt - lims[0]) / (lims[1] - lims[0])) * + (maxp - minp) + minp); + } +} + +/* Will report the minimum and maximum in "reflection coefficient" space + */ + +double * +ft_SMITHminmax(struct dvec *v, bool yval) +{ + static double res[2]; + register int i; + double d, d2; + + res[0] = HUGE; + res[1] = - res[0]; + + for (i = 0; i < v->v_length; i++) { + if (isreal(v)) + SMITH_tfm( v->v_realdata[i], 0.0, &d, &d2 ); + else + SMITH_tfm( realpart(&v->v_compdata[i]), imagpart(&v->v_compdata[i]), + &d, &d2 ); +/* Are we are looking for min/max X or Y ralue + */ + if( yval ) + d = d2; + + if (d < res[0]) + res[0] = d; + if (d > res[1]) + res[1] = d; + } + return (res); +} + +int +SMITH_tfm(double re, double im, double *x, double *y) +{ + double dnom; + + dnom = (re + 1) * (re + 1) + im * im; + *x = (re * re + im * im - 1) / dnom; + *y = 2 * im / dnom; + + return 0; +} diff --git a/src/frontend/points.h b/src/frontend/points.h new file mode 100644 index 000000000..74b9c268d --- /dev/null +++ b/src/frontend/points.h @@ -0,0 +1,16 @@ +/************* + * Header file for points.c + * 1999 E. Rouat + ************/ + +#ifndef POINTS_H_INCLUDED +#define POINTS_H_INCLUDED + +double * ft_minmax(struct dvec *v, bool real); +int ft_findpoint(double pt, double *lims, int maxp, int minp, bool islog); +double * ft_SMITHminmax(struct dvec *v, bool yval); +int SMITH_tfm(double re, double im, double *x, double *y); + + + +#endif diff --git a/src/frontend/postcoms.c b/src/frontend/postcoms.c new file mode 100644 index 000000000..89b79fb0a --- /dev/null +++ b/src/frontend/postcoms.c @@ -0,0 +1,1136 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Various post-processor commands having to do with vectors. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteparse.h" +#include "ftedata.h" +#include "postcoms.h" + + +/* static declarations */ +static void pvec(struct dvec *d); +static int dcomp(struct dvec **v1, struct dvec **v2); +static void killplot(struct plot *pl); + + +void +com_let(wordlist *wl) +{ + char *p, *q, *s; + int indices[MAXDIMS]; + int numdims; + wordlist fake_wl; + int need_open; + int offset, length; + struct pnode *nn; + struct dvec *n, *t; + int i, cube; + int depth; + int newvec; + char *rhs; + + fake_wl.wl_next = NULL; + + if (!wl) { + com_display((wordlist *) NULL); + return; + } + + p = wl_flatten(wl); + + /* extract indices */ + numdims = 0; + if ((rhs =strchr(p, '='))) { + *rhs++ = 0; + } else { + fprintf(cp_err, "Error: bad let syntax\n"); + return; + } + if ((s =strchr(p, '['))) { + need_open = 0; + *s++ = 0; + while (!need_open || *s == '[') { + depth = 0; + if (need_open) + s++; + for (q = s; *q && (*q != ']' && (*q != ',' || depth > 0)); q++) { + switch (*q) { + case '[': + depth += 1; + break; + case ']': + depth -= 1; + break; + } + } + + if (depth != 0 || !*q) { + printf("syntax error specifyingstrchr\n"); + return; + } + + if (*q == ']') + need_open = 1; + else + need_open = 0; + if (*q) + *q++ = 0; + +/* MW. let[x,y] is not supported - we don't need this code + + * evaluate expression between s and q + fake_wl.wl_word = s; + nn = ft_getpnames(&fake_wl, TRUE); + t = ft_evaluate(nn); + + free_pnode(nn); + + if (!t) { + fprintf(cp_err, "Error: badstrchr.\n"); // MW. When t == NULL something is wrong + tfree(p); + return; + } + + if (!isreal(t) || t->v_link2 || t->v_length != 1 || !t->v_realdata) + { + fprintf(cp_err, "Error:strchr is not a scalar.\n"); + tfree(p); + + return; + } + j = t->v_realdata[0]; + * ignore sanity checks for now + + if (j < 0) { + printf("negativestrchr (%d) is not allowed\n", j); + tfree(p); + return; + } + + indices[numdims++] = j; + + + + + * MW. Next line does not hurt. I don't know what it is doing + */ + + for (s = q; *s && isspace(*s); s++) + ; + } + } + /* vector name at p */ + + for (q = p + strlen(p) - 1; *q <= ' ' && p <= q; q--) + ; + + *++q = 0; + + /* sanity check */ + if (eq(p, "all") ||strchr(p, '@')) { + fprintf(cp_err, "Error: bad variable name %s\n", p); + return; + } + + /* evaluate rhs */ + fake_wl.wl_word = rhs; + nn = ft_getpnames(&fake_wl, TRUE); + if (nn == NULL) { + /* XXX error message */ + tfree(p); + return; + } + t = ft_evaluate(nn); + if (!t) { + fprintf(cp_err, "Error: Can't evaluate %s\n", rhs); + tfree(p); + return; + } + + if (t->v_link2) + fprintf(cp_err, "Warning: extra wildcard values ignored\n"); + + n = vec_get(p); + + if (n) { + /* re-allocate? */ + /* vec_free(n); */ + newvec = 0; + } else { + if (numdims) { + fprintf(cp_err, "Can't assign into a subindex of a new vector\n"); + tfree(p); + return; + } + + /* create and assign a new vector */ + n = alloc(struct dvec); + ZERO(n, struct dvec); + n->v_name = copy(p); + n->v_type = t->v_type; + n->v_flags = (t->v_flags | VF_PERMANENT); + n->v_length = t->v_length; + + if (!t->v_numdims) { + n->v_numdims = 1; + n->v_dims[0] = n->v_length; + } else { + n->v_numdims = t->v_numdims; + for (i = 0; i < t->v_numdims; i++) + n->v_dims[i] = t->v_dims[i]; + } + + if (isreal(t)) + n->v_realdata = (double *) tmalloc(n->v_length * sizeof(double)); + else + n->v_compdata = (complex *) tmalloc(n->v_length * sizeof(complex)); + newvec = 1; + vec_new(n); + } + + /* fix-up dimensions */ + if (n->v_numdims < 1) { + n->v_numdims = 1; + n->v_dims[0] = n->v_length; + } + + /* Compare dimensions */ + offset = 0; + length = n->v_length; + + cube = 1; + for (i = n->v_numdims - 1; i >= numdims; i--) + cube *= n->v_dims[i]; + + for (i = numdims - 1; i >= 0; i--) { + offset += cube * indices[i]; + if (i < n->v_numdims) { + cube *= n->v_dims[i]; + length /= n->v_dims[i]; + } + } + + /* length is the size of the unit refered to */ + /* cube ends up being the length */ + + if (length > t->v_length) { + fprintf(cp_err, "left-hand expression is too small (need %d)\n", + length * cube); + if (newvec) + n->v_flags &= ~VF_PERMANENT; + tfree(p); + return; + } + if (isreal(t) != isreal(n)) { + fprintf(cp_err, + "Types of vectors are not the same (real vs. complex)\n"); + if (newvec) + n->v_flags &= ~VF_PERMANENT; + tfree(p); + return; + } else if (isreal(t)) { + bcopy((char *) t->v_realdata, (char *) (n->v_realdata + offset), + length * sizeof (double)); + } else { + bcopy((char *) t->v_compdata, (char *) (n->v_compdata + offset), + length * sizeof (complex)); + } + + n->v_minsignal = 0.0; /* How do these get reset ??? */ + n->v_maxsignal = 0.0; + + n->v_scale = t->v_scale; + + if (newvec) + cp_addkword(CT_VECTOR, n->v_name); + + /* XXXX Free t !?! */ + tfree(p); + return; +} + +/* Undefine vectors. */ + +void +com_unlet(wordlist *wl) +{ + while (wl) { + vec_remove(wl->wl_word); + wl = wl->wl_next; + } + return; +} + +/* Load in a file. */ + +void +com_load(wordlist *wl) +{ + + if (!wl) + ft_loadfile(ft_rawfile); + else + while (wl) { + ft_loadfile(cp_unquote(wl->wl_word)); + wl = wl->wl_next; + } + + /* note: default is to display the vectors in the last (current) plot */ + com_display(NULL); + + return; +} + +/* Print out the value of an expression. When we are figuring out what to + * print, link the vectors we want with v_link2... This has to be done + * because of the way temporary vectors are linked together with permanent + * ones under the plot. + */ + +void +com_print(wordlist *wl) +{ + struct dvec *v, *lv, *bv, *nv, *vecs = NULL; + int i, j, ll, width = DEF_WIDTH, height = DEF_HEIGHT, npoints, lineno; + struct pnode *nn; + struct plot *p; + bool col = TRUE, nobreak = FALSE, noprintscale, plotnames = FALSE; + bool optgiven = FALSE; + char *s, buf[BSIZE_SP], buf2[BSIZE_SP]; + int ngood; + + if (wl == NULL) + return; + if (eq(wl->wl_word, "col")) { + col = TRUE; + optgiven = TRUE; + wl = wl->wl_next; + } else if (eq(wl->wl_word, "line")) { + col = FALSE; + optgiven = TRUE; + wl = wl->wl_next; + } + + ngood = 0; + for (nn = ft_getpnames(wl, TRUE); nn; nn = nn->pn_next) { + if (!(v = ft_evaluate(nn))) + continue; + if (!vecs) + vecs = lv = v; + else + lv->v_link2 = v; + for (lv = v; lv->v_link2; lv = lv->v_link2) + ; + ngood += 1; + } + + if (!ngood) + return; + + /* See whether we really have to print plot names. */ + for (v = vecs; v; v = v->v_link2) + if (vecs->v_plot != v->v_plot) { + plotnames = TRUE; + break; + } + + if (!optgiven) { + /* Figure out whether col or line should be used... */ + col = FALSE; + for (v = vecs; v; v = v->v_link2) + if (v->v_length > 1) { + col = TRUE; + break; + } + } + + out_init(); + if (!col) { + for (v = vecs; v; v = v->v_link2) { + if (plotnames) { + (void) sprintf(buf, "%s.%s", v->v_plot->pl_typename, + vec_basename(v)); + } else { + (void) strcpy(buf, vec_basename(v)); + } + for (s = buf; *s; s++) + ; + s--; + while (isspace(*s)) { + *s = '\0'; + s--; + } + ll = 10; + if (v->v_length == 1) { + if (isreal(v)) { + out_printf("%s = %s\n", buf, + printnum(*v->v_realdata)); + } else { + out_printf("%s = %s,%s\n", buf, + copy(printnum(realpart(v->v_compdata))), + copy(printnum(imagpart(v->v_compdata)))); + } + } else { + out_printf("%s = ( ", buf); + for (i = 0; i < v->v_length; i++) + if (isreal(v)) { + (void) strcpy(buf, + printnum(v->v_realdata[i])); + out_send(buf); + ll += strlen(buf); + ll = (ll + 7) / 8; + ll = ll * 8 + 1; + if (ll > 60) { + out_send("\n\t"); + ll = 9; + } else + out_send("\t"); + } else { + (void) sprintf(buf, "%s,%s", + copy(printnum(realpart(&v->v_compdata[i]))), + copy(printnum(imagpart(&v->v_compdata[i])))); + out_send(buf); + ll += strlen(buf); + ll = (ll + 7) / 8; + ll = ll * 8 + 1; + if (ll > 60) { + out_send("\n\t"); + ll = 9; + } else + out_send("\t"); + } + out_send(")\n"); + } + } + } else { /* Print in columns. */ + if (cp_getvar("width", VT_NUM, (char *) &i)) + width = i; + if (width < 40) + width = 40; + if (cp_getvar("height", VT_NUM, (char *) &i)) + height = i; + if (height < 20) + height = 20; + if (!cp_getvar("nobreak", VT_BOOL, (char *) &nobreak) && !ft_nopage) + nobreak = FALSE; + else + nobreak = TRUE; + (void) cp_getvar("noprintscale", VT_BOOL, (char *) + &noprintscale); + bv = vecs; +nextpage: + /* Make the first vector of every page be the scale... */ + /* XXX But what if there is no scale? e.g. op, pz */ + if (!noprintscale && bv->v_plot->pl_ndims) { + if (bv->v_plot->pl_scale && !vec_eq(bv, bv->v_plot->pl_scale)) { + nv = vec_copy(bv->v_plot->pl_scale); + vec_new(nv); + nv->v_link2 = bv; + bv = nv; + } + } + ll = 8; + for (lv = bv; lv; lv = lv->v_link2) { + if (isreal(lv)) + ll += 16; /* Two tabs for real, */ + else + ll += 32; /* 4 for complex. */ + /* Make sure we have at least 2 vectors per page... */ + if ((ll > width) && (lv != bv) && (lv != bv->v_link2)) + break; + } + + /* Print the header on the first page only. */ + p = bv->v_plot; + j = (width - (int) strlen(p->pl_title)) / 2; /* Yes, keep "(int)" */ + if (j < 0) + j = 0; + for (i = 0; i < j; i++) + buf2[i] = ' '; + buf2[j] = '\0'; + out_send(buf2); + out_send(p->pl_title); + out_send("\n"); + out_send(buf2); + (void) sprintf(buf, "%s %s", p->pl_name, p->pl_date); + j = (width - strlen(buf)) / 2; + out_send(buf); + out_send("\n"); + for (i = 0; i < width; i++) + buf2[i] = '-'; + buf2[width] = '\n'; + buf2[width+1] = '\0'; + out_send(buf2); + (void) sprintf(buf, "Index "); + for (v = bv; v && (v != lv); v = v->v_link2) { + if (isreal(v)) + (void) sprintf(buf2, "%-16.15s", v->v_name); + else + (void) sprintf(buf2, "%-32.31s", v->v_name); + (void) strcat(buf, buf2); + } + lineno = 3; + j = 0; + npoints = 0; + for (v = bv; (v && (v != lv)); v = v->v_link2) + if (v->v_length > npoints) + npoints = v->v_length; +pbreak: /* New page. */ + out_send(buf); + out_send("\n"); + for (i = 0; i < width; i++) + buf2[i] = '-'; + buf2[width] = '\n'; + buf2[width+1] = '\0'; + out_send(buf2); + lineno += 2; +loop: + while ((j < npoints) && (lineno < height)) { +/* out_printf("%d\t", j); */ + sprintf(out_pbuf, "%d\t", j); + out_send(out_pbuf); + for (v = bv; (v && (v != lv)); v = v->v_link2) { + if (v->v_length <= j) { + if (isreal(v)) + out_send("\t\t"); + else + out_send("\t\t\t\t"); + } else { + if (isreal(v)) { + sprintf(out_pbuf, "%e\t", + v->v_realdata[j]); + out_send(out_pbuf); + } else { + sprintf(out_pbuf, "%e,\t%e\t", + realpart(&v->v_compdata[j]), + imagpart(&v->v_compdata[j])); + out_send(out_pbuf); + } + } + } + out_send("\n"); + j++; + lineno++; + } + if ((j == npoints) && (lv == NULL)) /* No more to print. */ + goto done; + if (j == npoints) { /* More vectors to print. */ + bv = lv; + out_send("\f\n"); /* Form feed. */ + goto nextpage; + } + + /* Otherwise go to a new page. */ + lineno = 0; + if (nobreak) + goto loop; + else + out_send("\f\n"); /* Form feed. */ + goto pbreak; + } +done: + /* Get rid of the vectors. */ + return; +} + +/* Write out some data. write filename expr ... Some cleverness here is + * required. If the user mentions a few vectors from various plots, + * probably he means for them to be written out seperate plots. In any + * case, we have to be sure to write out the scales for everything we + * write... + */ + +void +com_write(wordlist *wl) +{ + char *file, buf[BSIZE_SP]; + struct pnode *n; + struct dvec *d, *vecs = NULL, *lv = NULL, *end, *vv; + static wordlist all = { "all", NULL, NULL } ; + struct pnode *names; + bool ascii = AsciiRawFile; + bool scalefound, appendwrite; + struct plot *tpl, newplot; + + if (wl) { + file = wl->wl_word; + wl = wl->wl_next; + } else + file = ft_rawfile; + if (cp_getvar("filetype", VT_STRING, buf)) { + if (eq(buf, "binary")) + ascii = FALSE; + else if (eq(buf, "ascii")) + ascii = TRUE; + else + fprintf(cp_err, "Warning: strange file type %s\n", buf); + } + (void) cp_getvar("appendwrite", VT_BOOL, (char *) &appendwrite); + + if (wl) + names = ft_getpnames(wl, TRUE); + else + names = ft_getpnames(&all, TRUE); + if (names == NULL) + return; + for (n = names; n; n = n->pn_next) { + d = ft_evaluate(n); + if (!d) + return; + if (vecs) + lv->v_link2 = d; + else + vecs = d; + for (lv = d; lv->v_link2; lv = lv->v_link2) + ; + } + + /* Now we have to write them out plot by plot. */ + + while (vecs) { + tpl = vecs->v_plot; + tpl->pl_written = TRUE; + end = NULL; + bcopy((char *) tpl, (char *) &newplot, sizeof (struct plot)); + scalefound = FALSE; + + /* Figure out how many vectors are in this plot. Also look + * for the scale, or a copy of it, which may have a different + * name. + */ + for (d = vecs; d; d = d->v_link2) { + if (d->v_plot == tpl) { + vv = vec_copy(d); + /* Note that since we are building a new plot + * we don't want to vec_new this one... + */ + vv->v_name = vec_basename(vv); + + if (end) + end->v_next = vv; + else + end = newplot.pl_dvecs = vv; + end = vv; + + if (vec_eq(d, tpl->pl_scale)) { + newplot.pl_scale = vv; + scalefound = TRUE; + } + } + } + end->v_next = NULL; + + /* Maybe we shouldn't make sure that the default scale is + * present if nobody uses it. + */ + if (!scalefound) { + newplot.pl_scale = vec_copy(tpl->pl_scale); + newplot.pl_scale->v_next = newplot.pl_dvecs; + newplot.pl_dvecs = newplot.pl_scale; + } + + /* Now let's go through and make sure that everything that + * has its own scale has it in the plot. + */ + for (;;) { + scalefound = FALSE; + for (d = newplot.pl_dvecs; d; d = d->v_next) { + if (d->v_scale) { + for (vv = newplot.pl_dvecs; vv; vv = + vv->v_next) + if (vec_eq(vv, d->v_scale)) + break; + /* We have to grab it... */ + vv = vec_copy(d->v_scale); + vv->v_next = newplot.pl_dvecs; + newplot.pl_dvecs = vv; + scalefound = TRUE; + } + } + if (!scalefound) + break; + /* Otherwise loop through again... */ + } + + if (ascii) + raw_write(file, &newplot, appendwrite, FALSE); + else + raw_write(file, &newplot, appendwrite, TRUE); + + /* Now throw out the vectors we have written already... */ + for (d = vecs, lv = NULL; d; d = d->v_link2) + if (d->v_plot == tpl) { + if (lv) { + lv->v_link2 = d->v_link2; + d = lv; + } else + vecs = d->v_link2; + } else + lv = d; + /* If there are more plots we want them appended... */ + appendwrite = TRUE; + } + return; +} + +/* If the named vectors have more than 1 dimension, then consider + * to be a collection of one or more matrices. This command transposes + * each named matrix. + */ +void +com_transpose(wordlist *wl) +{ + struct dvec *d; + char *s; + + while (wl) { + s = cp_unquote(wl->wl_word); + d = vec_get(s); + if (d == NULL) + fprintf(cp_err, "Error: no such vector as %s.\n", + wl->wl_word); + else + while (d) { + vec_transpose(d); + d = d->v_link2; + } + if (wl->wl_next == NULL) + return; + wl = wl->wl_next; + } +} + +/* Set the default scale to the named vector. If no vector named, + * find and print the default scale. + */ + +void +com_setscale(wordlist *wl) +{ + struct dvec *d; + char *s; + + if (plot_cur) { + if (wl) { + s = cp_unquote(wl->wl_word); + d = vec_get(s); + if (d == NULL) + fprintf(cp_err, "Error: no such vector as %s.\n", + wl->wl_word); + else + plot_cur->pl_scale = d; + } else if (plot_cur->pl_scale) { + pvec(plot_cur->pl_scale); + } + } else { + fprintf(cp_err, "Error: no current plot.\n"); + } +} + + +/* Display vector status, etc. Note that this only displays stuff from the + * current plot, and you must do a setplot to see the rest of it. + */ + +void +com_display(wordlist *wl) +{ + struct dvec *d; + struct dvec **dvs; + int len = 0, i = 0; + bool b; + char *s; + + /* Maybe he wants to know about just a few vectors. */ + + out_init(); + while (wl) { + s = cp_unquote(wl->wl_word); + d = vec_get(s); + if (d == NULL) + fprintf(cp_err, "Error: no such vector as %s.\n", + wl->wl_word); + else + while (d) { + pvec(d); + d = d->v_link2; + } + if (wl->wl_next == NULL) + return; + wl = wl->wl_next; + } + if (plot_cur) + for (d = plot_cur->pl_dvecs; d; d = d->v_next) + len++; + if (len == 0) { + fprintf(cp_out, "There are no vectors currently active.\n"); + return; + } + out_printf("Here are the vectors currently active:\n\n"); + dvs = (struct dvec **) tmalloc(len * (sizeof (struct dvec *))); + for (d = plot_cur->pl_dvecs, i = 0; d; d = d->v_next, i++) + dvs[i] = d; + if (!cp_getvar("nosort", VT_BOOL, (char *) &b)) + qsort((char *) dvs, len, sizeof (struct dvec *), dcomp); + + out_printf("Title: %s\n", plot_cur->pl_title); + out_printf("Name: %s (%s)\nDate: %s\n\n", + plot_cur->pl_typename, plot_cur->pl_name, + plot_cur->pl_date); + for (i = 0; i < len; i++) { + d = dvs[i]; + pvec(d); + } + return; +} + +static void +pvec(struct dvec *d) +{ + char buf[BSIZE_SP], buf2[BSIZE_SP]; + + sprintf(buf, " %-20s: %s, %s, %d long", d->v_name, + ft_typenames(d->v_type), isreal(d) ? "real" : + "complex", d->v_length); + if (d->v_flags & VF_MINGIVEN) { + sprintf(buf2, ", min = %g", d->v_minsignal); + strcat(buf, buf2); + } + if (d->v_flags & VF_MAXGIVEN) { + sprintf(buf2, ", max = %g", d->v_maxsignal); + strcat(buf, buf2); + } + switch (d->v_gridtype) { + + case GRID_LOGLOG: + strcat(buf, ", grid = loglog"); + break; + + case GRID_XLOG: + strcat(buf, ", grid = xlog"); + break; + + case GRID_YLOG: + strcat(buf, ", grid = ylog"); + break; + + case GRID_POLAR: + strcat(buf, ", grid = polar"); + break; + + case GRID_SMITH: + strcat(buf, ", grid = smith (xformed)"); + break; + + case GRID_SMITHGRID: + strcat(buf, ", grid = smithgrid (not xformed)"); + break; + } + switch (d->v_plottype) { + + case PLOT_COMB: + strcat(buf, ", plot = comb"); + break; + + case PLOT_POINT: + strcat(buf, ", plot = point"); + break; + + } + if (d->v_defcolor) { + sprintf(buf2, ", color = %s", d->v_defcolor); + strcat(buf, buf2); + } + if (d->v_scale) { + sprintf(buf2, ", scale = %s", d->v_scale->v_name); + strcat(buf, buf2); + } + if (d->v_numdims > 1) { + sprintf(buf2, ", dims = [%s]", dimstring(d->v_dims, d->v_numdims)); + strcat(buf, buf2); + } + if (d->v_plot->pl_scale == d) { + strcat(buf, " [default scale]\n"); + } else { + strcat(buf, "\n"); + } + out_send(buf); + return; +} + +#ifdef notdef + +/* Set the current working plot. */ + +void +com_splot(wl) + wordlist *wl; +{ + struct plot *p; + char buf[BSIZE_SP], *s; + + if (wl == NULL) { + fprintf(cp_out, "\tType the name of the desired plot:\n\n"); + fprintf(cp_out, "\tnew\tNew plot\n"); + for (p = plot_list; p; p = p->pl_next) { + if (plot_cur == p) + fprintf(cp_out, "Current"); + fprintf(cp_out, "\t%s\t%s (%s)\n", + p->pl_typename, p->pl_title, p->pl_name); + } + fprintf(cp_out, "? "); + (void) fflush(cp_out); + (void) fgets(buf, BSIZE_SP, cp_in); + clearerr(cp_in); + for (s = buf; *s && !isspace(*s); s++) + ; + *s = '\0'; + } else { + (void) strcpy(buf, wl->wl_word); + } + if (prefix("new", buf)) { + p = plot_alloc("unknown"); + p->pl_title = copy("Anonymous"); + p->pl_name = copy("unknown"); + p->pl_next = plot_list; + plot_list = p; + } else { + for (p = plot_list; p; p = p->pl_next) + if (plot_prefix(buf, p->pl_typename)) + break; + if (!p) { + fprintf(cp_err, "Error: no such plot.\n"); + return; + } + } + plot_cur->pl_ccom = cp_kwswitch(CT_VECTOR, p->pl_ccom); + plot_cur = p; + plot_docoms(plot_cur->pl_commands); + if (wl) + fprintf(cp_out, "%s %s (%s)\n", p->pl_typename, p->pl_title, + p->pl_name); + return; +} + +#endif + +/* For the sort in display. */ + +static int +dcomp(struct dvec **v1, struct dvec **v2) +{ + return (strcmp((*v1)->v_name, (*v2)->v_name)); +} + +#ifdef notdef + +/* Figure out what the name of this vector should be (if it is a number, + * then make it 'V' or 'I')... Note that the data is static. + */ + +static char * +dname(d) + struct dvec *d; +{ + static char buf[128]; + char *s; + + for (s = d->v_name; *s; s++) + if (!isdigit(*s)) + return (d->v_name); + switch (d->v_type) { + case SV_VOLTAGE: + (void) sprintf(buf, "V(%s)", d->v_name); + return (buf); + case SV_CURRENT: + (void) sprintf(buf, "I(%s)", d->v_name); + return (buf); + } + return (d->v_name); +} + +#endif + +/* Take a set of vectors and form a new vector of the nth elements of each. */ + +void +com_cross(wordlist *wl) +{ + char *newvec, *s; + struct dvec *n, *v, *vecs = NULL, *lv = NULL; + struct pnode *pn; + int i, ind; + bool comp = FALSE; + double *d; + + newvec = wl->wl_word; + wl = wl->wl_next; + s = wl->wl_word; + if (!(d = ft_numparse(&s, FALSE))) { + fprintf(cp_err, "Error: bad number %s\n", wl->wl_word); + return; + } + if ((ind = *d) < 0) { + fprintf(cp_err, "Error: badstrchr %d\n", ind); + return; + } + wl = wl->wl_next; + pn = ft_getpnames(wl, TRUE); + while (pn) { + if (!(n = ft_evaluate(pn))) + return; + if (!vecs) + vecs = lv = n; + else + lv->v_link2 = n; + for (lv = n; lv->v_link2; lv = lv->v_link2) + ; + pn = pn->pn_next; + } + for (n = vecs, i = 0; n; n = n->v_link2) { + if (iscomplex(n)) + comp = TRUE; + i++; + } + + vec_remove(newvec); + v = alloc(struct dvec); + v->v_name = copy(newvec); + v->v_type = vecs ? vecs->v_type : SV_NOTYPE; + v->v_length = i; + v->v_flags |= VF_PERMANENT; + v->v_flags = comp ? VF_COMPLEX : VF_REAL; + if (comp) + v->v_compdata = (complex *) tmalloc(i * sizeof (complex)); + else + v->v_realdata = (double *) tmalloc(i * sizeof (double)); + + /* Now copy the ind'ths elements into this one. */ + for (n = vecs, i = 0; n; n = n->v_link2, i++) + if (n->v_length > ind) { + if (comp) { + realpart(&v->v_compdata[i]) = + realpart(&n->v_compdata[ind]); + imagpart(&v->v_compdata[i]) = + imagpart(&n->v_compdata[ind]); + } else + v->v_realdata[i] = n->v_realdata[ind]; + } else { + if (comp) { + realpart(&v->v_compdata[i]) = 0.0; + imagpart(&v->v_compdata[i]) = 0.0; + } else + v->v_realdata[i] = 0.0; + } + vec_new(v); + v->v_flags |= VF_PERMANENT; + cp_addkword(CT_VECTOR, v->v_name); + return; +} + +void +com_destroy(wordlist *wl) +{ + struct plot *pl, *npl = NULL; + + if (!wl) + killplot(plot_cur); + else if (eq(wl->wl_word, "all")) { + for (pl = plot_list; pl; pl = npl) { + npl = pl->pl_next; + if (!eq(pl->pl_typename, "const")) + killplot(pl); + } + } else { + while (wl) { + for (pl = plot_list; pl; pl = pl->pl_next) + if (eq(pl->pl_typename, wl->wl_word)) + break; + if (pl) + killplot(pl); + else + fprintf(cp_err, "Error: no such plot %s\n", + wl->wl_word); + wl = wl->wl_next; + } + } + return; +} + +static void +killplot(struct plot *pl) +{ + struct dvec *v, *nv = NULL; + struct plot *op; + + if (eq(pl->pl_typename, "const")) { + fprintf(cp_err, "Error: can't destroy the constant plot\n"); + return; + } + for (v = pl->pl_dvecs; v; v = nv) { + nv = v->v_next; + vec_free(v); + } + if (pl == plot_list) { + plot_list = pl->pl_next; + if (pl == plot_cur) + plot_cur = plot_list; + } else { + for (op = plot_list; op; op = op->pl_next) + if (op->pl_next == pl) + break; + if (!op) + fprintf(cp_err, + "Internal Error: kill plot -- not in list\n"); + op->pl_next = pl->pl_next; + if (pl == plot_cur) + plot_cur = op; + } + tfree(pl->pl_title); + tfree(pl->pl_name); + tfree(pl->pl_typename); + wl_free(pl->pl_commands); + + /* Never mind about the rest... */ + + return; +} + +void +com_splot(wordlist *wl) +{ + struct plot *pl; + char buf[BSIZE_SP], *s, *t; + + if (wl) { + plot_setcur(wl->wl_word); + return; + } + fprintf(cp_out, "\tType the name of the desired plot:\n\n"); + fprintf(cp_out, "\tnew\tNew plot\n"); + for (pl = plot_list; pl; pl = pl->pl_next) + fprintf(cp_out, "%s%s\t%s (%s)\n", + (pl == plot_cur) ? "Current " : "\t", + pl->pl_typename, pl->pl_title, pl->pl_name); + + fprintf(cp_out, "? "); + if (!fgets(buf, BSIZE_SP, cp_in)) { + clearerr(cp_in); + return; + } + t = buf; + if (!(s = gettok(&t))) + return; + + plot_setcur(s); + return; +} + diff --git a/src/frontend/postcoms.h b/src/frontend/postcoms.h new file mode 100644 index 000000000..6703cc4fc --- /dev/null +++ b/src/frontend/postcoms.h @@ -0,0 +1,22 @@ +/************* + * Header file for postcoms.c + * 1999 E. Rouat + ************/ + +#ifndef POSTCOMS_H_INCLUDED +#define POSTCOMS_H_INCLUDED + +void com_let(wordlist *wl); +void com_unlet(wordlist *wl); +void com_load(wordlist *wl); +void com_print(wordlist *wl); +void com_write(wordlist *wl); +void com_transpose(wordlist *wl); +void com_setscale(wordlist *wl); +void com_display(wordlist *wl); +void com_cross(wordlist *wl); +void com_destroy(wordlist *wl); +void com_splot(wordlist *wl); + + +#endif diff --git a/src/frontend/postsc.c b/src/frontend/postsc.c new file mode 100644 index 000000000..a8ee78d18 --- /dev/null +++ b/src/frontend/postsc.c @@ -0,0 +1,397 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jeffrey M. Hsu +**********/ + +/* + Postscript driver +*/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftegraph.h" +#include "ftedbgra.h" +#include "ftedev.h" +#include "fteinput.h" +#include "postsc.h" + + +#define RAD_TO_DEG (180.0 / M_PI) +#define DEVDEP(g) (*((PSdevdep *) (g)->devdep)) +#define MAX_PS_LINES 1000 +#define SOLID 0 +#define DOTTED 1 + +#define gtype graph->grid.gridtype +#define xoff dispdev->minx +#define yoff dispdev->miny +#define XOFF 48 /* printer left margin */ +#define YOFF 48 /* printer bottom margin */ +#define XTADJ 0 /* printer text adjustment x */ +#define YTADJ 4 /* printer text adjustment y */ + +#define GRIDSIZE 420 /* printer gridsize divisible by 10, [7-2] */ +#define GRIDSIZES 360 /* printer gridsize divisible by [10-8], [6-2] */ + +#define FONTSIZE 10 /* printer default fontsize */ +#define FONTWIDTH 6 /* printer default fontwidth */ +#define FONTHEIGHT 14 /* printer default fontheight */ + +typedef struct { + int lastlinestyle; /* initial invalid value */ + int lastx, lasty, linecount; +} PSdevdep; + +static char *linestyle[] = { + "[]", /* solid */ + "[1 2]", /* dotted */ + "[7 7]", /* longdashed */ + "[3 3]", /* shortdashed */ + "[7 2 2 2]", /* longdotdashed */ + "[3 2 1 2]", /* shortdotdashed */ + "[8 3 2 3]", + "[14 2]", + "[3 5 1 5]" /* dotdashed */ + }; + +static FILE *plotfile; +char psfont[128], psfontsize[32], psscale[32]; +static int fontsize = FONTSIZE; +static int fontwidth = FONTWIDTH; +static int fontheight = FONTHEIGHT; +static int screenflag = 0; +static double scale; /* Used for fine tuning */ +static int xtadj; /* text adjustment x */ +static int ytadj; /* text adjustment y */ +static int hcopygraphid; + + +extern int DestroyGraph (int id); +int PS_SetLinestyle (int linestyleid); +extern void internalerror (char *message); + +int +PS_Init(void) +{ + if (!cp_getvar("hcopyscale", VT_STRING, psscale)) { + scale = 1.0; + } else { + sscanf(psscale, "%lf", &scale); + if ((scale <= 0) || (scale > 10)) + scale = 1.0; + } + + dispdev->numlinestyles = NUMELEMS(linestyle); + dispdev->numcolors = 2; + + dispdev->width = 7.75 * 72.0 * scale; /* (8 1/2 - 3/4) * 72 */ + dispdev->height = dispdev->width; + + /* The following side effects have to be considered + * when the printer is called by com_hardcopy ! + * gr_init: + * viewportxoff = 8 * fontwidth + * viewportyoff = 4 * fontheight + * gr_resize_internal: + * viewport.width = absolute.width - 2 * viewportxoff + * viewport.height = absolute.height - 2 * viewportyoff + */ + + if (!cp_getvar("hcopyfont", VT_STRING, psfont)) + strcpy(psfont, "Helvetica"); + if (!cp_getvar("hcopyfontsize", VT_STRING, psfontsize)) { + fontsize = 10; + fontwidth = 6; + fontheight = 14; + xtadj = XTADJ * scale; + ytadj = YTADJ * scale; + } else { + sscanf(psfontsize, "%d", &fontsize); + if ((fontsize < 10) || (fontsize > 14)) + fontsize = 10; + fontwidth = 0.5 + 0.6 * fontsize; + fontheight = 2.5 + 1.2 * fontsize; + xtadj = XTADJ * scale * fontsize / 10; + ytadj = YTADJ * scale * fontsize / 10; + } + +#ifdef notdef + if (fontsize > 11) + gridsize = GRIDSIZES; + else + gridsize = GRIDSIZE; + + dispdev->width = gridsize+16*fontwidth; /* was 612, p.w.h. */ + dispdev->height = gridsize+8*fontheight; /* was 612, p.w.h. */ +#endif + + screenflag = 0; + dispdev->minx = XOFF / scale; + dispdev->miny = YOFF / scale; + + return(0); + +} + +/* devdep initially contains name of output file */ +int +PS_NewViewport(GRAPH *graph) +{ + hcopygraphid = graph->graphid; + + if (!(plotfile = fopen(graph->devdep, "w"))) { + perror(graph->devdep); + graph->devdep = (char *) NULL; + return(1); + } + + if (graph->absolute.width) { + /* hardcopying from the screen */ + + screenflag = 1; + + /* scale to fit on 8 1/2 square */ +#ifdef notdef + /* Face it, this is bogus */ +#ifdef notdef + fprintf(plotfile, "%g %g scale\n", + (double) dispdev->width / graph->absolute.width, + (double) dispdev->height / graph->absolute.height); +#endif + + scalex = (double) graph->absolute.width / dispdev->width; + scaley = (double) graph->absolute.height / dispdev->width; + /* scale left and bottom printer margin */ + scaleps = ((scalex > scaley) ? scalex : scaley) / scale; + xoff = (int) (scaleps * (double) XOFF); + yoff = (int) (scaleps * (double) YOFF); + xtadj = 0; + ytadj = 0; + scalex = (double) dispdev->width / graph->absolute.width; + scaley = (double) dispdev->width / graph->absolute.height; + + if (gtype == GRID_SMITH || gtype == GRID_SMITHGRID + || gtype == GRID_POLAR) + { + scaleps = scale * ((scalex < scaley) ? scalex : scaley); + fprintf(plotfile, "%g %g scale\n", scaleps, scaleps); + } else { + fprintf(plotfile, "%g %g scale\n", scale*scalex, scale*scaley); + } + + /* re-scale linestyles */ + gr_relinestyle(graph); +#endif + + } + + /* reasonable values, used in gr_ for placement */ + graph->fontwidth = fontwidth * scale; /* was 12, p.w.h. */ + graph->fontheight = fontheight * scale; /* was 24, p.w.h. */ + + graph->absolute.width = dispdev->width; + graph->absolute.height = dispdev->height; + /* Also done in gr_init, if called . . . */ + graph->viewportxoff = 8 * fontwidth; + graph->viewportyoff = 4 * fontheight; + + xoff = scale * XOFF; + yoff = scale * YOFF; + + /* start file off with a % */ + fprintf(plotfile, "%%!PS-Adobe-3.0 EPSF-3.0\n"); + fprintf(plotfile, "%%%%Creator: nutmeg\n"); + fprintf(plotfile, "%%%%BoundingBox: %d %d %d %d\n", + (int) (.75 * 72), (int) (.75 * 72), + (int) (8.5 * 72), (int) (8.5 * 72)); + +#ifdef notdef + if (!screenflag) +#endif + fprintf(plotfile, "%g %g scale\n", 1.0 / scale, 1.0 / scale); + + /* set up a reasonable font */ + fprintf(plotfile, "/%s findfont %d scalefont setfont\n", + psfont, (int) (fontsize * scale)); + + graph->devdep = tmalloc(sizeof(PSdevdep)); + DEVDEP(graph).lastlinestyle = -1; + DEVDEP(graph).lastx = -1; + DEVDEP(graph).lasty = -1; + DEVDEP(graph).linecount = 0; + graph->linestyle = -1; + + return 0; +} + +void +PS_Close(void) +{ + + /* in case PS_Close is called as part of an abort, + w/o having reached PS_NewViewport */ + if (plotfile) { + if (DEVDEP(currentgraph).lastlinestyle != -1) { + /* haven't stroked last path */ + fprintf(plotfile, "stroke\n"); + DEVDEP(currentgraph).linecount = 0; + } + fprintf(plotfile, "showpage\n"); + fclose(plotfile); + plotfile = NULL; + } + /* In case of hardcopy command destroy the hardcopy graph + * and reset currentgraph to graphid 1, if possible + */ + if (!screenflag) { + DestroyGraph(hcopygraphid); + currentgraph = FindGraph(1); + } +} + +void +PS_Clear(void) +{ + + /* do nothing */ + +} + +void +PS_DrawLine(int x1, int y1, int x2, int y2) +{ + + /* note: this is not extendible to more than one graph + => will have to give NewViewport a writeable graph XXX */ + + if (DEVDEP(currentgraph).lastlinestyle != currentgraph->linestyle + || DEVDEP(currentgraph).linecount > MAX_PS_LINES) + { + fprintf(plotfile, "stroke\n"); + fprintf(plotfile, "newpath\n"); + DEVDEP(currentgraph).linecount = 0; + } + + if (DEVDEP(currentgraph).linecount == 0 + || x1 != DEVDEP(currentgraph).lastx + || y1 != DEVDEP(currentgraph).lasty) + { + fprintf(plotfile, "%d %d moveto ", x1 + xoff, y1 + yoff); + } + if (x1 != x2 || y1 != y2) { + fprintf(plotfile, "%d %d lineto\n", x2 + xoff, y2 + yoff); + DEVDEP(currentgraph).linecount += 1; + } + + DEVDEP(currentgraph).lastx = x2; + DEVDEP(currentgraph).lasty = y2; + DEVDEP(currentgraph).lastlinestyle = currentgraph->linestyle; + +} + + +void +PS_Arc(int x0, int y0, int r, double theta1, double theta2) +{ + double x1, y1; + double angle1, angle2; + + while (theta1 >= theta2) + theta2 += 2 * M_PI; + + angle1 = (double) (RAD_TO_DEG * theta1); + angle2 = (double) (RAD_TO_DEG * theta2); + x1 = (double) x0 + r * cos(theta1); + y1 = (double) y0 + r * sin(theta1); + + fprintf(plotfile, "%f %f moveto ", x1+(double)xoff, y1+(double)yoff); + fprintf(plotfile, "%d %d %d %f %f arc\n", x0+xoff, y0+yoff, r, + angle1, angle2); + fprintf(plotfile, "stroke\n"); + + DEVDEP(currentgraph).linecount = 0; +} + +void +PS_Text(char *text, int x, int y) +{ + + int savedlstyle; + + /* set linestyle to solid + or may get funny color text on some plotters */ + savedlstyle = currentgraph->linestyle; + PS_SetLinestyle(SOLID); + + if (DEVDEP(currentgraph).linecount) { + fprintf(plotfile, "stroke\n"); + fprintf(plotfile, "newpath\n"); + DEVDEP(currentgraph).linecount = 0; + } + /* move to (x, y) */ + fprintf(plotfile, "%d %d moveto\n", x + xoff + xtadj, y + yoff + ytadj); + fprintf(plotfile, "(%s) show\n", text); + + DEVDEP(currentgraph).lastx = -1; + DEVDEP(currentgraph).lasty = -1; + + /* restore old linestyle */ + PS_SetLinestyle(savedlstyle); + +} + +int +PS_SetLinestyle(int linestyleid) +{ + + /* special case + get it when PS_Text restores a -1 linestyle */ + if (linestyleid == -1) { + currentgraph->linestyle = -1; + return 0; + } + + if (linestyleid < 0 || linestyleid > dispdev->numlinestyles) { + internalerror("bad linestyleid"); + return 0; + } + + if (currentgraph->linestyle != linestyleid) { + if (DEVDEP(currentgraph).lastlinestyle != -1) { + fprintf(plotfile, "stroke\n"); + fprintf(plotfile, "newpath\n"); + DEVDEP(currentgraph).linecount = 0; + } + fprintf(plotfile, "%s 0 setdash\n", linestyle[linestyleid]); + currentgraph->linestyle = linestyleid; + } + return 0; + +} + + +void +PS_SetColor(int colorid) +{ + static int flag = 0; /* A hack */ + + /* XXXX Set line style dotted for smith grids */ + if ((colorid == 18) || (colorid == 19)) { + PS_SetLinestyle(DOTTED); + flag = 1; + } + if (flag && (colorid == 1)) { + PS_SetLinestyle(SOLID); + flag = 0; + } + +} + +void +PS_Update(void) +{ + + fflush(plotfile); + +} + diff --git a/src/frontend/postsc.h b/src/frontend/postsc.h new file mode 100644 index 000000000..530d0d787 --- /dev/null +++ b/src/frontend/postsc.h @@ -0,0 +1,21 @@ +/************* + * Header file for postsc.c + * 1999 E. Rouat + ************/ + +#ifndef POSTSC_H_INCLUDED +#define POSTSC_H_INCLUDED + +int PS_Init(void); +int PS_NewViewport(GRAPH *graph); +void PS_Close(void); +void PS_Clear(void); +void PS_DrawLine(int x1, int y1, int x2, int y2); +void PS_Arc(int x0, int y0, int r, double theta1, double theta2); +void PS_Text(char *text, int x, int y); +int PS_SetLinestyle(int linestyleid); +void PS_SetColor(int colorid); +void PS_Update(void); + + +#endif diff --git a/src/frontend/rawfile.c b/src/frontend/rawfile.c new file mode 100644 index 000000000..8f96ac24e --- /dev/null +++ b/src/frontend/rawfile.c @@ -0,0 +1,673 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Read and write the ascii and binary rawfile formats. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "rawfile.h" + + +/* static declarations */ +static void fixdims(struct dvec *v, char *s); + + +int raw_prec = -1; /* How many sigfigs to use, default 15 (max). */ + +#define DEFPREC 15 + +/* Write a raw file. We write everything in the plot pointed to. */ + +void +raw_write(char *name, struct plot *pl, bool app, bool binary) +{ + FILE *fp; + bool realflag = TRUE, writedims; + bool raw_padding; + int length, numdims, dims[MAXDIMS]; + int nvars, i, j, prec; + struct dvec *v, *lv; + wordlist *wl; + struct variable *vv; + double dd; + + if (!cp_getvar("nopadding", VT_BOOL, (char *) &raw_padding)) + raw_padding = FALSE; + /* Invert since we want to know if we should pad. */ + raw_padding = !raw_padding; + + /* Why bother printing out an empty plot? */ + if (!pl->pl_dvecs) { + fprintf(cp_err, "Error: plot is empty, nothing written.\n"); + return; + } + + if (raw_prec != -1) + prec = raw_prec; + else + prec = DEFPREC; + + if (!(fp = fopen(name, app ? "a" : "w"))) { + perror(name); + return; + } + + numdims = nvars = length = 0; + for (v = pl->pl_dvecs; v; v = v->v_next) { + if (iscomplex(v)) + realflag = FALSE; + nvars++; + /* Find the length and dimensions of the longest vector + * in the plot. + * Be paranoid and assume somewhere we may have + * forgotten to set the dimensions of 1-D vectors. + */ + if (v->v_numdims <= 1) { + v->v_numdims = 1; + v->v_dims[0] = v->v_length; + } + if (v->v_length > length) { + length = v->v_length; + numdims = v->v_numdims; + for (j = 0; j < numdims; j++) { + dims[j] = v->v_dims[j]; + } + } + } + + fprintf(fp, "Title: %s\n", pl->pl_title); + fprintf(fp, "Date: %s\n", pl->pl_date); + fprintf(fp, "Plotname: %s\n", pl->pl_name); + fprintf(fp, "Flags: %s%s\n", + realflag ? "real" : "complex", raw_padding ? "" : " unpadded" ); + fprintf(fp, "No. Variables: %d\n", nvars); + fprintf(fp, "No. Points: %d\n", length); + if (numdims > 1) { + fprintf(fp, "Dimensions: %s\n", dimstring(dims, numdims)); + } + + for (wl = pl->pl_commands; wl; wl = wl->wl_next) + fprintf(fp, "Command: %s\n", wl->wl_word); + + for (vv = pl->pl_env; vv; vv = vv->va_next) { + wl = cp_varwl(vv); + if (vv->va_type == VT_BOOL) { + fprintf(fp, "Option: %s\n", vv->va_name); + } else { + fprintf(fp, "Option: %s = ", vv->va_name); + if (vv->va_type == VT_LIST) + fprintf(fp, "( "); + wl_print(wl, fp); + if (vv->va_type == VT_LIST) + fprintf(fp, " )"); + (void) putc('\n', fp); + } + } + + /* Before we write the stuff out, make sure that the scale is the first + * in the list. + */ + for (lv = NULL, v = pl->pl_dvecs; v != pl->pl_scale; v = v->v_next) + lv = v; + if (lv) { + lv->v_next = v->v_next; + v->v_next = pl->pl_dvecs; + pl->pl_dvecs = v; + } + + fprintf(fp, "Variables:\n"); + for (i = 0, v = pl->pl_dvecs; v; v = v->v_next) { + fprintf(fp, "\t%d\t%s\t%s", i++, v->v_name, + ft_typenames(v->v_type)); + if (v->v_flags & VF_MINGIVEN) + fprintf(fp, " min=%e", v->v_minsignal); + if (v->v_flags & VF_MAXGIVEN) + fprintf(fp, " max=%e", v->v_maxsignal); + if (v->v_defcolor) + fprintf(fp, " color=%s", v->v_defcolor); + if (v->v_gridtype) + fprintf(fp, " grid=%d", v->v_gridtype); + if (v->v_plottype) + fprintf(fp, " plot=%d", v->v_gridtype); + /* Only write dims if they are different from default. */ + writedims = FALSE; + if (v->v_numdims != numdims) { + writedims = TRUE; + } else { + for (j = 0; j < numdims; j++) + if (dims[j] != v->v_dims[j]) + writedims = TRUE; + } + if (writedims) { + fprintf(fp, " dims=%s", dimstring(v->v_dims, v->v_numdims)); + } + (void) putc('\n', fp); + } + + if (binary) { + fprintf(fp, "Binary:\n"); + for (i = 0; i < length; i++) { + for (v = pl->pl_dvecs; v; v = v->v_next) { + /* Don't run off the end of this vector's data. */ + if (i < v->v_length) { + if (realflag) { + dd = (isreal(v) ? v->v_realdata[i] : + realpart(&v->v_compdata[i])); + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + } else if (isreal(v)) { + dd = v->v_realdata[i]; + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + dd = 0.0; + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + } else { + dd = realpart(&v->v_compdata[i]); + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + dd = imagpart(&v->v_compdata[i]); + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + } + } else if (raw_padding) { + dd = 0.0; + if (realflag) { + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + } else { + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + (void) fwrite((char *) &dd, sizeof + (double), 1, fp); + } + } + } + } + } else { + fprintf(fp, "Values:\n"); + for (i = 0; i < length; i++) { + fprintf(fp, " %d", i); + for (v = pl->pl_dvecs; v; v = v->v_next) { + if (i < v->v_length) { + if (realflag) + fprintf(fp, "\t%.*e\n", prec, + isreal(v) ? v->v_realdata[i] : + realpart(&v->v_compdata[i])); + else if (isreal(v)) + fprintf(fp, "\t%.*e,0.0\n", prec, + v->v_realdata[i]); + else + fprintf(fp, "\t%.*e,%.*e\n", prec, + realpart(&v->v_compdata[i]), + prec, + imagpart(&v->v_compdata[i])); + } else if (raw_padding) { + if (realflag) { + fprintf(fp, "\t%.*e\n", prec, 0.0); + } else { + fprintf(fp, "\t%.*e,%.*e\n", + prec, 0.0, prec, 0.0); + } + } + } + (void) putc('\n', fp); + } + } + (void) fclose(fp); + return; +} + +/* Read a raw file. Returns a list of plot structures. This routine should be + * very flexible about what it expects to see in the rawfile. Really all we + * require is that there be one variables and one values section per plot + * and that the variables precede the values. + */ + +#define skip(s) while (*(s) && !isspace(*(s)))(s)++; while (isspace(*(s)))(s)++ +#define nonl(s) r = (s); while (*r && (*r != '\n')) r++; *r = '\0' + +struct plot * +raw_read(char *name) +{ + char *title = "default title"; + char *date = 0; + struct plot *plots = NULL, *curpl = NULL; + char buf[BSIZE_SP], buf2[BSIZE_SP], *s, *t, *r; + int flags, nvars, npoints, i, j; + int ndimpoints, numdims=0, dims[MAXDIMS]; + bool raw_padded = TRUE; + double junk; + struct dvec *v, *nv; + struct variable *vv; + wordlist *wl, *nwl; + FILE *fp, *lastin, *lastout, *lasterr; + + if (!(fp = fopen(name, "r"))) { + perror(name); + return (NULL); + } + + /* Since we call cp_evloop() from here, we have to do this junk. */ + lastin = cp_curin; + lastout = cp_curout; + lasterr = cp_curerr; + cp_curin = cp_in; + cp_curout = cp_out; + cp_curerr = cp_err; + + cp_pushcontrol(); + + while (fgets(buf, BSIZE_SP, fp)) { + /* Figure out what this line is... */ + if (ciprefix("title:", buf)) { + s = buf; + skip(s); + nonl(s); + title = copy(s); + } else if (ciprefix("date:", buf)) { + s = buf; + skip(s); + nonl(s); + date = copy(s); + } else if (ciprefix("plotname:", buf)) { + s = buf; + skip(s); + nonl(s); + if (curpl) { /* reverse commands list */ + for (wl=curpl->pl_commands, + curpl->pl_commands=NULL; wl && + wl->wl_next; wl=nwl) { + nwl = wl->wl_next; + wl->wl_next = curpl->pl_commands; + curpl->pl_commands = wl; + } + } + curpl = alloc(struct plot); + curpl->pl_next = plots; + plots = curpl; + curpl->pl_name = copy(s); + if (!date) + date = copy(datestring( )); + curpl->pl_date = date; + curpl->pl_title = copy(title); + flags = VF_PERMANENT; + nvars = npoints = 0; + } else if (ciprefix("flags:", buf)) { + s = buf; + skip(s); + while (t = gettok(&s)) { + if (cieq(t, "real")) + flags |= VF_REAL; + else if (cieq(t, "complex")) + flags |= VF_COMPLEX; + else if (cieq(t, "unpadded")) + raw_padded = FALSE; + else if (cieq(t, "padded")) + raw_padded = TRUE; + else + fprintf(cp_err, + "Warning: unknown flag %s\n", + t); + } + } else if (ciprefix("no. variables:", buf)) { + s = buf; + skip(s); + skip(s); + nvars = scannum(s); + } else if (ciprefix("no. points:", buf)) { + s = buf; + skip(s); + skip(s); + npoints = scannum(s); + } else if (ciprefix("dimensions:", buf)) { + if (npoints == 0) { + fprintf(cp_err, + "Error: misplaced Dimensions: line\n"); + continue; + } + s = buf; + skip(s); + if (atodims(s, dims, &numdims)) { /* Something's wrong. */ + fprintf(cp_err, + "Warning: syntax error in dimensions, ignored.\n"); + numdims = 0; + continue; + } + if (numdims > MAXDIMS) { + numdims = 0; + continue; + } + /* Let's just make sure that the no. of points + * and the dimensions are consistent. + */ + for (j = 0, ndimpoints = 1; j < numdims; j++) { + ndimpoints *= dims[j]; + } + + if (ndimpoints != npoints) { + fprintf(cp_err, + "Warning: dimensions inconsistent with no. of points, ignored.\n"); + numdims = 0; + } + } else if (ciprefix("command:", buf)) { + /* Note that we reverse these commands eventually... */ + s = buf; + skip(s); + nonl(s); + if (curpl) { + wl = alloc(struct wordlist); + wl->wl_word = copy(s); + wl->wl_next = curpl->pl_commands; + if (curpl->pl_commands) + curpl->pl_commands->wl_prev = wl; + curpl->pl_commands = wl; + } else + fprintf(cp_err, + "Error: misplaced Command: line\n"); + /* Now execute the command if we can. */ + (void) cp_evloop(s); + } else if (ciprefix("option:", buf)) { + s = buf; + skip(s); + nonl(s); + if (curpl) { + wl = cp_lexer(s); + for (vv = curpl->pl_env; vv && vv->va_next; + vv = vv->va_next) + ; + if (vv) + vv->va_next = cp_setparse(wl); + else + curpl->pl_env = cp_setparse(wl); + } else + fprintf(cp_err, + "Error: misplaced Option: line\n"); + } else if (ciprefix("variables:", buf)) { + /* We reverse the dvec list eventually... */ + if (!curpl) { + fprintf(cp_err, "Error: no plot name given\n"); + plots = NULL; + break; + } + s = buf; + skip(s); + if (!*s) { + (void) fgets(buf, BSIZE_SP, fp); + s = buf; + } + if (numdims == 0) { + numdims = 1; + dims[0] = npoints; + } + /* Now read all the variable lines in. */ + for (i = 0; i < nvars; i++) { + v = alloc(struct dvec); + ZERO(v, struct dvec); + v->v_next = curpl->pl_dvecs; + curpl->pl_dvecs = v; + if (!curpl->pl_scale) + curpl->pl_scale = v; + v->v_flags = flags; + v->v_plot = curpl; + v->v_length = npoints; + v->v_numdims = 0; + /* Length and dims might be changed by options. */ + + if (!i) + curpl->pl_scale = v; + else { + (void) fgets(buf, BSIZE_SP, fp); + s = buf; + } + (void) gettok(&s); /* The strchr field. */ + if ((t = gettok(&s))) + v->v_name = t; + else { + fprintf(cp_err, + "Error: bad var line %s\n", + buf); +/* MW. v_name must be valid in the case that no. points = 0 */ + v->v_name = "no vars\n"; + } + t = gettok(&s); /* The type name. */ + if (t) + v->v_type = ft_typnum(t); + else + fprintf(cp_err, + "Error: bad var line %s\n", + buf); + + /* Fix the name... */ + if (isdigit(*v->v_name) && (r = ft_typabbrev(v + ->v_type))) { + (void) sprintf(buf2, "%s(%s)", r, + v->v_name); + v->v_name = copy(buf2); + } + /* Now come the strange options... */ + while (t = gettok(&s)) { + if (ciprefix("min=", t)) { + if (sscanf(t + 4, "%lf", + &v->v_minsignal) != 1) + fprintf(cp_err, + "Error: bad arg %s\n", + t); + v->v_flags |= VF_MINGIVEN; + } else if (ciprefix("max=", t)) { + if (sscanf(t + 4, "%lf", + &v->v_maxsignal) != 1) + fprintf(cp_err, + "Error: bad arg %s\n", + t); + v->v_flags |= VF_MAXGIVEN; + } else if (ciprefix("color=", t)) { + v->v_defcolor = copy(t + 6); + } else if (ciprefix("scale=", t)) { + /* This is bad, but... */ + v->v_scale = (struct dvec *) + copy(t + 6); + } else if (ciprefix("grid=", t)) { + v->v_gridtype = (GRIDTYPE) + scannum(t + 5); + } else if (ciprefix("plot=", t)) { + v->v_plottype = (PLOTTYPE) + scannum(t + 5); + } else if (ciprefix("dims=", t)) { + fixdims(v, t + 5); + } else { + fprintf(cp_err, + "Warning: bad var param %s\n", + t); + } + } + /* Now we default any missing dimensions. */ + if (!v->v_numdims) { + v->v_numdims = numdims; + for (j = 0; j < numdims; j++) + v->v_dims[j] = dims[j]; + } + /* And allocate the data array. We would use + * the desired vector length, but this would + * be dangerous if the file is invalid. + */ + if (isreal(v)) + v->v_realdata = (double *) tmalloc( + npoints * sizeof (double)); + else + v->v_compdata = (complex *) tmalloc( + npoints * sizeof (complex)); + } + } else if (ciprefix("values:", buf) || + ciprefix("binary:", buf)) { + if (!curpl) { + fprintf(cp_err, "Error: no plot name given\n"); + plots = NULL; + break; + } + + /* We'd better reverse the dvec list now... */ + for (v = curpl->pl_dvecs, curpl->pl_dvecs = NULL; v; + v = nv) { + nv = v->v_next; + v->v_next = curpl->pl_dvecs; + curpl->pl_dvecs = v; + } + + /* And fix the scale pointers. */ + for (v = curpl->pl_dvecs; v; v = v->v_next) { + if (v->v_scale) { + for (nv = curpl->pl_dvecs; nv; nv = + nv->v_next) + if (cieq((char *) v->v_scale, + nv->v_name)) { + v->v_scale = nv; + break; + } + if (!nv) { + fprintf(cp_err, + "Error: no such vector %s\n", + (char *) v->v_scale); + v->v_scale = NULL; + } + } + } + for (i = 0; i < npoints; i++) { + if ((*buf == 'v') || (*buf == 'V')) { + /* It's an ASCII file. */ + (void) fscanf(fp, " %d", &j); + for (v = curpl->pl_dvecs; v; v = v->v_next) { + if (i < v->v_length) { + if (flags & VF_REAL) { + if (fscanf(fp, " %lf", + &v->v_realdata[i]) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + } else { + if (fscanf(fp, " %lf, %lf", + &realpart(&v->v_compdata[i]), + &imagpart(&v->v_compdata[i])) != 2) + fprintf(cp_err, + "Error: bad rawfile\n"); + } + } else if (raw_padded) { + if (flags & VF_REAL) { + if (fscanf(fp, " %lf", + &junk) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + } else { + if (fscanf(fp, " %lf, %lf", + &junk, &junk) != 2) + fprintf(cp_err, + "Error: bad rawfile\n"); + } + } + } + } else { + /* It's a Binary file. */ + for (v = curpl->pl_dvecs; v; v = v->v_next) { + if (i < v->v_length) { + if (flags & VF_REAL) { + if (fread((char *) &v->v_realdata[i], + sizeof (double), 1, fp) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + } else { + if (fread((char *) &v->v_compdata[i].cx_real, + sizeof (double), 1, fp) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + if (fread((char *) &v->v_compdata[i].cx_imag, + sizeof (double), 1, fp) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + } + } else if (raw_padded) { + if (flags & VF_REAL) { + if (fread((char *) &junk, + sizeof (double), 1, fp) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + } else { + if (fread((char *) &junk, + sizeof (double), 1, fp) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + if (fread((char *) &junk, + sizeof (double), 1, fp) != 1) + fprintf(cp_err, + "Error: bad rawfile\n"); + } + } + } + } + } + } else { + s = buf; + skip(s); + if (*s) { + fprintf(cp_err, + "Error: strange line in rawfile;\n\t\"%s\"\nload aborted.\n", s); + return (NULL); + } + } + } + + if (curpl) { /* reverse commands list */ + for (wl=curpl->pl_commands, + curpl->pl_commands=NULL; wl && + wl->wl_next; wl=nwl) { + nwl = wl->wl_next; + wl->wl_next = curpl->pl_commands; + curpl->pl_commands = wl; + } + } + + /* Fix everything up nicely again. */ + cp_popcontrol(); + cp_curin = lastin; + cp_curout = lastout; + cp_curerr = lasterr; + (void) fclose(fp); + return (plots); +} + +/* s is a string of the form d1,d2,d3... */ + +static void +fixdims(struct dvec *v, char *s) +{ + int i, ndimpoints; + + if (atodims(s, v->v_dims, &(v->v_numdims))) { /* Something's wrong. */ + fprintf(cp_err, + "Warning: syntax error in dimensions, ignored.\n"); + return; + } else if (v->v_numdims > MAXDIMS) { + return; + } + + /* If the no. of points is less than the the total data length, + * truncate the vector length. If it's greater in length, we + * have serious problems with this vector. Try to fix + * by setting to default dimensions when we return. + */ + for (i = 0, ndimpoints = 1; i < v->v_numdims; i++) { + ndimpoints *= v->v_dims[i]; + } + + if (ndimpoints > v->v_length) { + v->v_numdims = 0; + } else { + v->v_length = ndimpoints; + } + return; +} diff --git a/src/frontend/rawfile.h b/src/frontend/rawfile.h new file mode 100644 index 000000000..c3411a957 --- /dev/null +++ b/src/frontend/rawfile.h @@ -0,0 +1,14 @@ +/************* + * Header file for rawfile.c + * 1999 E. Rouat + ************/ + +#ifndef RAWFILE_H_INCLUDED +#define RAWFILE_H_INCLUDED + +void raw_write(char *name, struct plot *pl, bool app, bool binary); +struct plot * raw_read(char *name); + + + +#endif diff --git a/src/frontend/resource.c b/src/frontend/resource.c new file mode 100644 index 000000000..6645c36ea --- /dev/null +++ b/src/frontend/resource.c @@ -0,0 +1,374 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Resource-related routines. + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "resource.h" + + + + +/* static declarations */ +static void printres(char *name); +static RETSIGTYPE fault(void); +static void * baseaddr(void); + + + +char *startdata; +char *enddata; + + + +void +init_rlimits(void) +{ + + startdata = (char *) baseaddr( ); + enddata = sbrk(0); + +} + +void +init_time(void) +{ + +#ifdef HAVE_GETRUSAGE +#else +# ifdef HAVE_TIMES +# else +# ifdef HAVE_FTIME + ftime(&timebegin); +# endif +# endif +#endif + +} + + +void +com_rusage(wordlist *wl) +{ + /* Fill in the SPICE accounting structure... */ + + if (wl && (eq(wl->wl_word, "everything") || eq(wl->wl_word, "all"))) { + printres((char *) NULL); + } else if (wl) { + for (; wl; wl = wl->wl_next) { + printres(cp_unquote(wl->wl_word)); + if (wl->wl_next) + (void) putc('\n', cp_out); + } + } else { + printres("cputime"); + (void) putc('\n', cp_out); + printres("totalcputime"); + (void) putc('\n', cp_out); + printres("space"); + } + return; +} + +/* Find out if the user is approaching his maximum data size. */ + +void +ft_ckspace(void) +{ + long usage, limit; + static long old_usage = 0; + char *hi; + + +# ifdef HAVE_GETRLIMIT + + struct rlimit rld; + getrlimit(RLIMIT_DATA, &rld); + if (rld.rlim_cur == RLIM_INFINITY) + return; + limit = rld.rlim_cur - (enddata - startdata); /* rlim_max not used */ + +# else + + /* SYSVRLIMIT */ + limit = ulimit(3, 0L) - (enddata - startdata); + +# endif + hi=sbrk(0); + usage = (long) (hi - enddata); + + + if (limit < 0) + return; /* what else do you do? */ + + if (usage <= old_usage) + return; + + old_usage = usage; + + if (usage > limit * 0.9) { + fprintf(cp_err, "Warning - approaching max data size: "); + fprintf(cp_err, "current size = %ld, limit = %ld.\n", usage, limit); + } + + return; +} + +/* Print out one piece of resource usage information. */ + +static void +printres(char *name) +{ + bool yy = FALSE; + static long lastsec = 0, lastusec = 0; + struct variable *v; + char *cpu_elapsed; + + if (!name || eq(name, "totalcputime") || eq(name, "cputime")) { + int total, totalu; + +#ifdef ipsc +# define NO_RUDATA +#else + +# ifdef HAVE_GETRUSAGE + struct rusage ruse; + (void) getrusage(RUSAGE_SELF, &ruse); + total = ruse.ru_utime.tv_sec + ruse.ru_stime.tv_sec; + totalu = (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec) / 1000; + cpu_elapsed = "CPU"; +# else +# ifdef HAVE_TIMES + struct tms ruse; + realt = times(&ruse); + total = (ruse.tms_utime + ruse.tms_stime)/ HZ; + totalu = (ruse.tms_utime + ruse.tms_utime) * 1000 / HZ; + cpu_elapsed = "CPU"; +# else +# ifdef HAVE_FTIME + struct timeb timenow; + int sec, msec; + ftime(&timenow); + timediff(&timenow, &timebegin, &total, &totalu); + totalu /= 1000; + cpu_elapsed = "elapsed"; +# else +# define NO_RUDATA +# endif +# endif +# endif +#endif + + +#ifndef NO_RUDATA + if (!name || eq(name, "totalcputime")) { + total += totalu / 1000; + totalu %= 1000; + fprintf(cp_out, "Total %s time: %u.%03u seconds.\n", + cpu_elapsed, total, totalu); + } + + if (!name || eq(name, "cputime")) { + lastusec = totalu - lastusec; + lastsec = total - lastsec; + while (lastusec < 0) { + lastusec += 1000; + lastsec -= 1; + } + while (lastusec > 1000) { + lastusec -= 1000; + lastsec += 1; + } + + fprintf(cp_out, "%s time since last call: %lu.%03lu seconds.\n", + cpu_elapsed, lastsec, lastusec); + + lastsec = total; + lastusec = totalu; + } + + yy = TRUE; +#else + if (!name || eq(name, "totalcputime")) + fprintf(cp_out, "Total CPU time: ??.??? seconds.\n"); + if (!name || eq(name, "cputime")) + fprintf(cp_out, "CPU time since last call: ??.??? seconds.\n"); + yy = TRUE; +#endif + + } + + if (!name || eq(name, "space")) { + long usage = 0, limit = 0; +#ifdef ipsc + NXINFO cur = nxinfo, start = nxinfo_snap; + + usage = cur.dataend - cur.datastart; + limit = start.availmem; +#else +# ifdef HAVE_GETRLIMIT + struct rlimit rld; + char *hi; + + getrlimit(RLIMIT_DATA, &rld); + limit = rld.rlim_cur - (enddata - startdata); + hi = sbrk(0); + usage = (long) (hi - enddata); +# else +# ifdef HAVE_ULIMIT + char *hi; + + limit = ulimit(3, 0L) - (enddata - startdata); + hi = sbrk(0); + usage = (long) (hi - enddata); +# endif +# endif +#endif + fprintf(cp_out, "Current dynamic memory usage = %ld,\n", usage); + fprintf(cp_out, "Dynamic memory limit = %ld.\n", limit); + yy = TRUE; + } + + if (!name || eq(name, "faults")) { +#ifdef HAVE_GETRUSAGE + struct rusage ruse; + + (void) getrusage(RUSAGE_SELF, &ruse); + fprintf(cp_out, + "%lu page faults, %lu vol + %lu invol = %lu context switches.\n", + ruse.ru_majflt, ruse.ru_nvcsw, ruse.ru_nivcsw, + ruse.ru_nvcsw + ruse.ru_nivcsw); + yy = TRUE; +#endif + } + + /* Now get all the spice resource stuff. */ + if (ft_curckt && ft_curckt->ci_ckt) { + if (name && eq(name, "task")) + v = if_getstat(ft_curckt->ci_ckt, NULL); + else + v = if_getstat(ft_curckt->ci_ckt, name); + if (name && v) { + fprintf(cp_out, "%s = ", v->va_name); + wl_print(cp_varwl(v), cp_out); + (void) putc('\n', cp_out); + yy = TRUE; + } else if (v) { + (void) putc('\n', cp_out); + while (v) { + fprintf(cp_out, "%s = ", v->va_name); + wl_print(cp_varwl(v), cp_out); + (void) putc('\n', cp_out); + v = v->va_next; + } + yy = TRUE; + } + } + + if (!yy) { + fprintf(cp_err, "Note: no resource usage information for '%s',\n", + name); + fprintf(cp_err, "\tor no active circuit available\n"); + + } + return; +} + + +#include +#include + +/* + * baseaddr( ) returns the base address of the data segment on most Unix + * systems. It's an ugly hack for info that should be provided by the OS. + */ + +/* Does anyone use a pagesize < 256 bytes?? I'll bet not; + * too small doesn't hurt + */ + +#define LOG2_PAGESIZE 8 + +static jmp_buf env; + +static RETSIGTYPE +fault(void) +{ + signal(SIGSEGV, (SIGNAL_FUNCTION) fault); /* SysV style */ + longjmp(env, 1); +} + +static void * +baseaddr(void) +{ + char *low, *high, *at; + /* char *sbrk(int); */ + long x; + RETSIGTYPE (*orig_signal)( ); + + if (getenv("SPICE_NO_DATASEG_CHECK")) + return 0; + + low = 0; + high = (char *) ((unsigned long) sbrk(0) & ~((1 << LOG2_PAGESIZE) - 1)); + + orig_signal = signal(SIGSEGV, (SIGNAL_FUNCTION) fault); + + do { + + at = (char *) ((((long)low >> LOG2_PAGESIZE) + + ((long)high >> LOG2_PAGESIZE)) + << (LOG2_PAGESIZE - 1)); +# ifdef notdef + at = (char *) ((((int) low + (int) high) / 2 + 0x7ff) + & ~(long) 0xfff); + /* nearest page */ +# endif +# ifdef notdef + printf( + "high = %#8x low = %#8x at = %#8x\n", + high, low, at); +# endif + + if (at == low || at == high) { + break; + } + + if (setjmp(env)) { + low = at; + continue; + } else + x = *at; + + if (setjmp(env)) { + low = at; + continue; + } else + *at = x; + + high = at; + + } while (1); + +# ifdef notdef + printf ("start is at %#x, end is at %#x\n", high, sbrk(0)); +# endif + (void) signal(SIGSEGV, (SIGNAL_FUNCTION) orig_signal); + return (void *) high; +} + +# ifdef notdef +main( ) +{ + printf("testing\n"); + printf("baseaddr: %#8x topaddr: %#8x\n", baseaddr( ), sbrk(0)); +} +# endif + diff --git a/src/frontend/resource.h b/src/frontend/resource.h new file mode 100644 index 000000000..152db13e3 --- /dev/null +++ b/src/frontend/resource.h @@ -0,0 +1,15 @@ +/************* + * Header file for resources.c + * 1999 E. Rouat + ************/ + +#ifndef RESOURCES_H_INCLUDED +#define RESOURCES_H_INCLUDED + +void init_rlimits(void); +void init_time(void); +void com_rusage(wordlist *wl); +void ft_ckspace(void); + + +#endif diff --git a/src/frontend/runcoms.c b/src/frontend/runcoms.c new file mode 100644 index 000000000..4b37c2cba --- /dev/null +++ b/src/frontend/runcoms.c @@ -0,0 +1,312 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Circuit simulation commands. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedev.h" +#include "ftedebug.h" +#include "ftedata.h" +#include "runcoms.h" + +/* static declarations */ +static int dosim(char *what, wordlist *wl); + +extern struct dbcomm *dbs; + +/* Routines for the commands op, tran, ac, dc, listing, device, state, + * resume, stop, trace, run, end. Op, tran, ac, and dc cause the action + * to be performed immediately, and run causes whatever actions were + * present in the deck to be carried out. End has the effect of stopping + * any simulations in progress, as opposed to ending te input deck as + * the .end line does. + */ + +FILE *rawfileFp; +bool rawfileBinary; + +void +com_scirc(wordlist *wl) +{ + struct circ *p; + int i, j = 0; + char buf[BSIZE_SP]; + + if (ft_circuits == NULL) { + fprintf(cp_err, "Error: there aren't any circuits loaded.\n"); + return; + } + if (wl == NULL) { + fprintf(cp_out, + "\tType the number of the desired circuit:\n\n"); + for (p = ft_circuits; p; p = p->ci_next) { + if (ft_curckt == p) + fprintf(cp_out, "Current"); + fprintf(cp_out, "\t%d\t%s\n", ++j, p->ci_name); + } + fprintf(cp_out, "? "); + (void) fflush(cp_out); + (void) fgets(buf, BSIZE_SP, cp_in); + clearerr(cp_in); + if ((sscanf(buf, " %d ", &i) != 1) || (i < 0) || (i > j)) + return; + for (p = ft_circuits; --i > 0; p = p->ci_next); + } else { + for (p = ft_circuits; p; p = p->ci_next) + if (ciprefix(wl->wl_word, p->ci_name)) + break; + if (p == NULL) { + fprintf(cp_err, "Warning: no such circuit \"%s\"\n", + wl->wl_word); + return; + } + fprintf(cp_out, "\t%s\n", p->ci_name); + } + if (ft_curckt) { + /* Actually this can't be FALSE */ + ft_curckt->ci_devices = + cp_kwswitch(CT_DEVNAMES, p->ci_devices); + ft_curckt->ci_nodes = cp_kwswitch(CT_NODENAMES, p->ci_nodes); + } + ft_curckt = p; + return; +} + +void +com_pz(wordlist *wl) +{ + dosim("pz", wl); + return; +} + +void +com_op(wordlist *wl) +{ + dosim("op", wl); + return; +} + +void +com_dc(wordlist *wl) +{ + dosim("dc", wl); + return; +} + +void +com_ac(wordlist *wl) +{ + dosim("ac", wl); + return; +} + +void +com_tf(wordlist *wl) +{ + dosim("tf", wl); + return; +} + +void +com_tran(wordlist *wl) +{ + dosim("tran", wl); + return; +} + +void +com_sens(wordlist *wl) +{ + dosim("sens", wl); + return; +} + +void +com_disto(wordlist *wl) +{ + dosim("disto", wl); + return; +} + +void +com_noise(wordlist *wl) +{ + dosim("noise", wl); + return; +} + +static int +dosim(char *what, wordlist *wl) +{ + wordlist *ww; + bool dofile = FALSE; + char buf[BSIZE_SP]; + struct circ *ct; + int err = 0; + bool ascii = AsciiRawFile; + + if (eq(what, "run") && wl) + dofile = TRUE; + if (!dofile) { + ww = alloc(struct wordlist); + ww->wl_next = wl; + if (wl) + wl->wl_prev = ww; + ww->wl_word = copy(what); + } + + if (cp_getvar("filetype", VT_STRING, buf)) { + if (eq(buf, "binary")) + ascii = FALSE; + else if (eq(buf, "ascii")) + ascii = TRUE; + else + fprintf(cp_err, + "Warning: strange file type \"%s\" (using \"ascii\")\n", + buf); + } + + if (!ft_curckt) { + fprintf(cp_err, "Error: there aren't any circuits loaded.\n"); + return 1; + } else if (ft_curckt->ci_ckt == NULL) { /* Set noparse? */ + fprintf(cp_err, "Error: circuit not parsed.\n"); + return 1; + } + for (ct = ft_circuits; ct; ct = ct->ci_next) + if (ct->ci_inprogress && (ct != ft_curckt)) { + fprintf(cp_err, + "Warning: losing old state for circuit '%s'\n", + ct->ci_name); + ct->ci_inprogress = FALSE; + } + if (ft_curckt->ci_inprogress && eq(what, "resume")) { + ft_setflag = TRUE; + ft_intrpt = FALSE; + fprintf(cp_err, "Warning: resuming run in progress.\n"); + com_resume((wordlist *) NULL); + ft_setflag = FALSE; + return 0; + } +#ifdef notdef + if (ft_curckt->ci_runonce) + com_rset((wordlist *) NULL); +#endif + + /* From now on until the next prompt, an interrupt will just + * set a flag and let spice finish up, then control will be + * passed back to the user. + */ + ft_setflag = TRUE; + ft_intrpt = FALSE; + if (dofile) { +#ifdef PARALLEL_ARCH + if (ARCHme == 0) { +#endif /* PARALLEL_ARCH */ + if (!*wl->wl_word) + rawfileFp = stdout; + else if (!(rawfileFp = fopen(wl->wl_word, "w"))) { + perror(wl->wl_word); + ft_setflag = FALSE; + return 1; + } + rawfileBinary = !ascii; +#ifdef PARALLEL_ARCH + } else { + rawfileFp = NULL; + } +#endif /* PARALLEL_ARCH */ + } else { + rawfileFp = NULL; +#ifdef notdef + XXX why? + plot_num++; /* There should be a better way */ +#endif + } + + /* Spice calls wrd_init and wrd_end itself */ + ft_curckt->ci_inprogress = TRUE; + if (eq(what,"sens2")) { + if (if_sens_run(ft_curckt->ci_ckt, ww, ft_curckt->ci_symtab) == 1) { + /* The circuit was interrupted somewhere. */ + + fprintf(cp_err, "%s simulation interrupted\n", what); + } else + ft_curckt->ci_inprogress = FALSE; + } else { + err = if_run(ft_curckt->ci_ckt, what, ww, ft_curckt->ci_symtab); + if (err == 1) { + /* The circuit was interrupted somewhere. */ + fprintf(cp_err, "%s simulation interrupted\n", what); + err = 0; + } else if (err == 2) { + fprintf(cp_err, "%s simulation(s) aborted\n", what); + ft_curckt->ci_inprogress = FALSE; + err = 1; + } else + ft_curckt->ci_inprogress = FALSE; + } + if (rawfileFp) + (void) fclose(rawfileFp); + ft_curckt->ci_runonce = TRUE; + ft_setflag = FALSE; + return err; +} + +/* Usage is run [filename] Do the wrd_{open,run} and wrd_(void) close + * here, and let the CKT stuff do wrd_init and wrd_end. + */ + +void +com_run(wordlist *wl) +{ +/* ft_getsaves(); */ + dosim("run", wl); + return; +} + +int +ft_dorun(char *file) +{ + static wordlist wl = { NULL, NULL, NULL } ; + + wl.wl_word = file; + if (file) + return dosim("run", &wl); + else + return dosim("run", (wordlist *) NULL); +} + +/* ARGSUSED */ /* until the else clause gets put back */ +bool +ft_getOutReq(FILE **fpp, struct plot **plotp, bool *binp, char *name, char *title) +{ + /*struct plot *pl;*/ + + if (rawfileFp) { + *fpp = rawfileFp; + *binp = rawfileBinary; + return (TRUE); + } else { +/* + pl = plot_alloc(name); + pl->pl_title = copy(title); + pl->pl_name = copy(name); + pl->pl_date = copy(datestring( )); + + pl->pl_next = plot_list; + plot_list = pl; + plot_cur = pl; + + *plotp = pl; +*/ + return (FALSE); + } +} + diff --git a/src/frontend/runcoms.h b/src/frontend/runcoms.h new file mode 100644 index 000000000..ed4ed3f0e --- /dev/null +++ b/src/frontend/runcoms.h @@ -0,0 +1,25 @@ +/************* + * Header file for runcoms.c + * 1999 E. Rouat + ************/ + +#ifndef RUNCOMS_H_INCLUDED +#define RUNCOMS_H_INCLUDED + +void com_scirc(wordlist *wl); +void com_pz(wordlist *wl); +void com_op(wordlist *wl); +void com_dc(wordlist *wl); +void com_ac(wordlist *wl); +void com_tf(wordlist *wl); +void com_tran(wordlist *wl); +void com_sens(wordlist *wl); +void com_disto(wordlist *wl); +void com_noise(wordlist *wl); +void com_run(wordlist *wl); +int ft_dorun(char *file); +bool ft_getOutReq(FILE **fpp, struct plot **plotp, bool *binp, char *name, char *title); + + + +#endif diff --git a/src/frontend/runcoms2.c b/src/frontend/runcoms2.c new file mode 100644 index 000000000..adef8c205 --- /dev/null +++ b/src/frontend/runcoms2.c @@ -0,0 +1,96 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Circuit simulation commands. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedev.h" +#include "ftedebug.h" +#include "ftedata.h" +#include "runcoms2.h" + + +extern FILE *rawfileFp; +extern bool rawfileBinary; +extern struct dbcomm *dbs; + +/* Continue a simulation. If there is non in progress, this is the + * equivalent of "run". + */ + +/* ARGSUSED */ + +/* This is a hack to tell iplot routine to redraw the grid and initialize + the display device + */ + +bool resumption = FALSE; + + +extern void reset_trace (void); + +void +com_resume(wordlist *wl) +{ + struct dbcomm *db; + int err; + + if (ft_curckt->ci_inprogress == FALSE) { + fprintf(cp_err, "Note: run starting\n"); + com_run((wordlist *) NULL); + return; + } + ft_curckt->ci_inprogress = TRUE; + ft_setflag = TRUE; + + reset_trace( ); + for ( db = dbs, resumption = FALSE; db; db = db->db_next ) + if( db->db_type == DB_IPLOT || db->db_type == DB_IPLOTALL ) { + resumption = TRUE; + } + err = if_run(ft_curckt->ci_ckt, "resume", (wordlist *) NULL, + ft_curckt->ci_symtab); + if (err == 1) { + /* The circuit was interrupted somewhere. */ + + fprintf(cp_err, "simulation interrupted\n"); + } else if (err == 2) { + fprintf(cp_err, "simulation aborted\n"); + ft_curckt->ci_inprogress = FALSE; + } else + ft_curckt->ci_inprogress = FALSE; + return; +} + +/* Throw out the circuit struct and recreate it from the deck. This command + * should be obsolete. + */ + +/* ARGSUSED */ +void +com_rset(wordlist *wl) +{ + struct variable *v, *next; + + if (ft_curckt == NULL) { + fprintf(cp_err, "Error: there is no circuit loaded.\n"); + return; + } + + if_cktfree(ft_curckt->ci_ckt, ft_curckt->ci_symtab); + for (v = ft_curckt->ci_vars; v; v = next) { + next = v->va_next; + tfree(v); + } + ft_curckt->ci_vars = NULL; + + inp_dodeck(ft_curckt->ci_deck, ft_curckt->ci_name, (wordlist *) NULL, + TRUE, ft_curckt->ci_options, ft_curckt->ci_filename); + return; +} diff --git a/src/frontend/runcoms2.h b/src/frontend/runcoms2.h new file mode 100644 index 000000000..ac89626df --- /dev/null +++ b/src/frontend/runcoms2.h @@ -0,0 +1,13 @@ +/************* + * Header file for runcoms2.c + * 1999 E. Rouat + ************/ + +#ifndef RUNCOMS2_H_INCLUDED +#define RUNCOMS2_H_INCLUDED + +void com_resume(wordlist *wl); +void com_rset(wordlist *wl); + + +#endif diff --git a/src/frontend/shyu.c b/src/frontend/shyu.c new file mode 100644 index 000000000..ebb364c40 --- /dev/null +++ b/src/frontend/shyu.c @@ -0,0 +1,337 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* Do a run of the circuit, of the given type. Type "resume" is special -- + * it means to resume whatever simulation that was in progress. The + * return value of this routine is 0 if the exit was ok, and 1 if there was + * a reason to interrupt the circuit (interrupt typed at the keyboard, + * error in the simulation, etc). args should be the entire command line, + * e.g. "tran 1 10 20 uic" + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteinp.h" +#include "fteconst.h" +#include "devdefs.h" +#include "inpdefs.h" +#include "iferrmsg.h" +#include "ifsim.h" +#include "shyu.h" + + +int +if_sens_run(char *t, wordlist *args, INPtables *tab) +{ + void *ckt = (void *) t; + void *senseJob; + void *acJob; + void *opJob; + void *dcJob; + void *tranJob; + card *current; + IFvalue ptemp; + IFvalue *parm; + char buf[BSIZE_SP]; + int err; + char *token; + char *steptype; + char *name; + char *line; + struct line deck; + int i; + int j; + int error; + int save ; + int flag = 0; + int which = -1; + + (void) sprintf(buf, ".%s", wl_flatten(args)); + deck.li_next = deck.li_actual = NULL; + deck.li_error = NULL; + deck.li_linenum = 0; + deck.li_line = buf; + + current = (card *) &deck; + line = current->line; + INPgetTok(&line,&token,1); + + if(ft_curckt->ci_specTask) { + err=(*(ft_sim->deleteTask))(ft_curckt->ci_ckt, + ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"deleteTask"); + return(0); /* temporary */ + } + } + err = (*(ft_sim->newTask))(ft_curckt->ci_ckt, + (void **) &(ft_curckt->ci_specTask),"special"); + if(err) { + ft_sperror(err,"newTask"); + return(0); /* temporary */ + } + for(j=0;jnumAnalyses;j++) { + if(strcmp(ft_sim->analyses[j]->name,"options")==0) { + which = j; + break; + } + } + if(which != -1) { + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,"options", + (void **) &(ft_curckt->ci_specOpt),ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"createOptions"); + return(0);/* temporary */ + } + ft_curckt->ci_curOpt = ft_curckt->ci_specOpt; + } + else ; + { /* in DEEP trouble */ + } + ft_curckt->ci_curTask = ft_curckt->ci_specTask; + which = -1; + for(j=0;jnumAnalyses;j++) { + if(strcmp(ft_sim->analyses[j]->name,"SEN")==0) { + which = j; + break; + } + } + if(which != -1) { + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,"sense", + &(senseJob),ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"createSense"); + return(0);/* temporary */ + } + } + else{ + current->error = INPerrCat(current->error,INPmkTemp( + "sensetivity analysis unsupported\n")); + return(0); + } + save = which; + INPgetTok(&line,&token,1); + if(strcmp(token ,"ac")==0){ + which = -1; + for(j=0;jnumAnalyses;j++) { + if(strcmp(ft_sim->analyses[j]->name,"AC")==0) { + which = j; + break; + } + } + if(which != -1) { + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,"acan", + &(acJob),ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"createAC"); /* or similar error message */ + return(0); + } + } + else{ + current->error = INPerrCat(current->error,INPmkTemp( + "ac analysis unsupported\n")); + } + + INPgetTok(&line,&steptype,1); /* get DEC, OCT, or LIN */ + ptemp.iValue=1; + error = INPapName(ckt,which,acJob,steptype,&ptemp); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + parm=INPgetValue(ckt,&line,IF_INTEGER,tab);/* number of points*/ + error = INPapName(ckt,which,acJob,"numsteps",parm); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstart */ + error = INPapName(ckt,which,acJob,"start",parm); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* fstop */ + error = INPapName(ckt,which,acJob,"stop",parm); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + + } + if(strcmp(token ,"op")==0){ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"DCOP")==0) { + which=i; + break; + } + } + if(which == -1) { + current->error = INPerrCat(current->error,INPmkTemp( + "DC operating point analysis unsupported\n")); + } + else { + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,"dcop", + &(opJob),ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"createOP"); /* or similar error message */ + return(0); + } + } + } + if(strcmp(token ,"dc")==0){ + /* .dc SRC1NAME Vstart1 Vstop1 Vinc1 [SRC2NAME Vstart2 */ + /* Vstop2 Vinc2 */ + which = -1; + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"DCTransfer")==0) { + which=i; + break; + } + } + if(which==-1) { + current->error = INPerrCat(current->error,INPmkTemp( + "DC transfer curve analysis unsupported\n")); + } + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,"DCtransfer", + &(dcJob),ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"createOP"); /* or similar error message */ + return(0); + } + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + error = INPapName(ckt,which,dcJob,"name1",&ptemp); + if(error) current->error = INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstart1 */ + error = INPapName(ckt,which,dcJob,"start1",parm); + if(error) current->error = INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstop1 */ + error = INPapName(ckt,which,dcJob,"stop1",parm); + if(error) current->error = INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vinc1 */ + error = INPapName(ckt,which,dcJob,"step1",parm); + if(error) current->error = INPerrCat(current->error,INPerror(error)); + if(*line) { + if(*line == 'd') goto next; + INPgetTok(&line,&name,1); + INPinsert(&name,tab); + ptemp.uValue=name; + error = INPapName(ckt,which,dcJob,"name2",&ptemp); + if(error) current->error= INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstart1 */ + error = INPapName(ckt,which,dcJob,"start2",parm); + if(error) current->error= INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vstop1 */ + error = INPapName(ckt,which,dcJob,"stop2",parm); + if(error) current->error= INPerrCat(current->error,INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* vinc1 */ + error = INPapName(ckt,which,dcJob,"step2",parm); + if(error) current->error= INPerrCat(current->error,INPerror(error)); + } + } + if(strcmp(token ,"tran")==0){ + which = -1; + for(j=0;jnumAnalyses;j++) { + if(strcmp(ft_sim->analyses[j]->name,"TRAN")==0) { + which = j; + break; + } + } + if(which != -1) { + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,"tranan", + &(tranJob),ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"createTRAN"); + return(0); + } + } + else{ + current->error = INPerrCat(current->error,INPmkTemp( + "transient analysis unsupported\n")); + } + + parm=INPgetValue(ckt,&line,IF_REAL,tab);/* Tstep */ + error = INPapName(ckt,which,tranJob,"tstep",parm); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + parm = INPgetValue(ckt,&line,IF_REAL,tab); /* Tstop*/ + error = INPapName(ckt,which,tranJob,"tstop",parm); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + if(*line){ + if(*line == 'd') goto next; + if(*line == 'u') goto uic; + parm=INPgetValue(ckt,&line,IF_REAL,tab);/* Tstart */ + error = INPapName(ckt,which,tranJob,"tstart",parm); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + if(*line == 'u') goto uic; + parm=INPgetValue(ckt,&line,IF_REAL,tab);/* Tmax */ + error = INPapName(ckt,which,tranJob,"tmax",parm); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); +uic: + if(*line == 'u') { + INPgetTok(&line,&name,1); + if(strcmp(name,"uic")==0) { + ptemp.iValue = 1; + error = INPapName(ckt,which,tranJob,"tstart",&ptemp); + if(error) current->error = INPerrCat(current->error, + INPerror(error)); + + } + } + + } + } + +next: + while(*line) { /* read the entire line */ + if(flag){ + INPgetTok(&line,&token,1); + } + else{ + flag = 1; + } + for(i=0;ianalyses[save]->numParms;i++) { + /* find the parameter */ + if(0==strcmp(token , + ft_sim->analyses[save]->analysisParms[i]. + keyword) ){ + /* found it, analysis which, parameter i */ + if(ft_sim->analyses[save]->analysisParms[i]. + dataType & IF_FLAG) { + /* one of the keywords! */ + ptemp.iValue = 1; + error = (*(ft_sim->setAnalysisParm))(ckt, + senseJob, ft_sim->analyses[save]-> + analysisParms[i].id,&ptemp,(IFvalue*)NULL); + if(error) current->error = INPerrCat( + current->error, INPerror(error)); + } + else { + parm = INPgetValue(ckt,&line,ft_sim-> + analyses[save]->analysisParms[i]. + dataType,tab); + error = (*(ft_sim->setAnalysisParm))(ckt, + senseJob, ft_sim->analyses[save]-> + analysisParms[i].id,parm,(IFvalue*)NULL); + if(error) current->error = INPerrCat( + current->error, INPerror(error)); + + } + break; + } + } + if(i==ft_sim->analyses[save]->numParms) { + /* didn't find it! */ + current->error = INPerrCat(current->error,INPmkTemp( + " Error: unknown parameter on .sens - ignored \n")); + } + } + + + + if((err = (*(ft_sim->doAnalyses))(ckt, 1, ft_curckt->ci_curTask))!=OK){ + ft_sperror(err, "doAnalyses"); + return(0);/* temporary */ + } + return(0); +} diff --git a/src/frontend/shyu.h b/src/frontend/shyu.h new file mode 100644 index 000000000..8b8aad892 --- /dev/null +++ b/src/frontend/shyu.h @@ -0,0 +1,12 @@ +/************* + * Header file for shyu.c + * 1999 E. Rouat + ************/ + +#ifndef SHYU_H_INCLUDED +#define SHYU_H_INCLUDED + +int if_sens_run(char *t, wordlist *args, INPtables *tab); + + +#endif diff --git a/src/frontend/signal_handler.c b/src/frontend/signal_handler.c new file mode 100644 index 000000000..4f51bab0d --- /dev/null +++ b/src/frontend/signal_handler.c @@ -0,0 +1,125 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * The signal routines for spice 3 and nutmeg. + */ + + +#include "ngspice.h" +#include "ifsim.h" +#include "iferrmsg.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedev.h" +#include +#include +#include "signal_handler.h" + + + + +extern jmp_buf jbuf; + +/* The (void) signal handlers... SIGINT is the only one that gets reset (by + * cshpar) so it is global. They are ifdef BSD because of the sigmask + * stuff in sigstop. We set the interrupt flag and return if ft_setflag + * is TRUE. + */ + + +extern pid_t getpid (void); + +RETSIGTYPE +ft_sigintr(void) +{ + + gr_clean(); + + (void) signal( SIGINT, (SIGNAL_FUNCTION) ft_sigintr ); + + if (ft_intrpt) + fprintf(cp_err, "Interrupt (ouch)\n"); + else { + fprintf(cp_err, "Interrupt\n"); + ft_intrpt = TRUE; + } + if (ft_setflag) + return; +/* To restore screen after an interrupt to a plot for instance + */ + + cp_interactive = TRUE; + cp_resetcontrol(); + longjmp(jbuf, 1); +} + + +RETSIGTYPE +sigfloat(int sig, int code) +{ + gr_clean(); + fperror("Error", code); + rewind(cp_out); + (void) signal( SIGFPE, (SIGNAL_FUNCTION) sigfloat ); + longjmp(jbuf, 1); +} + +/* This should give a new prompt if cshpar is waiting for input. */ + +# ifdef SIGTSTP + +RETSIGTYPE +sigstop(void) +{ + gr_clean(); + cp_ccon(FALSE); + (void) signal(SIGTSTP, SIG_DFL); + (void) kill(getpid(), SIGTSTP); /* This should stop us */ + return; +} + +RETSIGTYPE +sigcont(void) +{ + (void) signal(SIGTSTP, (SIGNAL_FUNCTION) sigstop); + if (cp_cwait) + longjmp(jbuf, 1); +} + +# endif + +/* Special (void) signal handlers. */ + +RETSIGTYPE +sigill(void) +{ + fprintf(cp_err, "\ninternal error -- illegal instruction\n"); + fatal(); +} + +RETSIGTYPE +sigbus(void) +{ + fprintf(cp_err, "\ninternal error -- bus error\n"); + fatal(); +} + +RETSIGTYPE +sigsegv(void) +{ + fprintf(cp_err, "\ninternal error -- segmentation violation\n"); + fatal(); +} + +RETSIGTYPE +sig_sys(void) +{ + fprintf(cp_err, + "\ninternal error -- bad argument to system call\n"); + fatal(); +} + + diff --git a/src/frontend/signal_handler.h b/src/frontend/signal_handler.h new file mode 100644 index 000000000..5d46d1625 --- /dev/null +++ b/src/frontend/signal_handler.h @@ -0,0 +1,18 @@ +/************* + * Header file for signal_handler.c + * 1999 E. Rouat + ************/ + +#ifndef SIGNAL_HANDLER_H_INCLUDED +#define SIGNAL_HANDLER_H_INCLUDED + +RETSIGTYPE ft_sigintr(void); +RETSIGTYPE sigfloat(int sig, int code); +RETSIGTYPE sigstop(void); +RETSIGTYPE sigcont(void); +RETSIGTYPE sigill(void); +RETSIGTYPE sigbus(void); +RETSIGTYPE sigsegv(void); +RETSIGTYPE sig_sys(void); + +#endif diff --git a/src/frontend/spcmdtab.c b/src/frontend/spcmdtab.c new file mode 100644 index 000000000..482441e96 --- /dev/null +++ b/src/frontend/spcmdtab.c @@ -0,0 +1,381 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Table of available commands. Note that they're sorted so that the commands + * that appear in the spiceinit file are at the top. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftehelp.h" + + +/* Bool fields: stringargs, spiceonly, major */ + +struct comm spcp_coms[] = { + + { "let", com_let, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + arg_let, + "varname = expr : Assign vector variables." } , + { "reshape", com_reshape, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + arg_let, + "vector ... [ shape ] : change the dimensions of a vector." } , + { "define", com_define, FALSE, FALSE, TRUE, + { 010000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[[func (args)] stuff] : Define a user-definable function." } , + { "set", com_set, FALSE, FALSE, TRUE, + { 020000, 020000, 020000, 020000 }, E_DEFHMASK, 0, LOTS, + arg_set, + "[option] [option = value] ... : Set a variable." } , + { "alias", com_alias, FALSE, FALSE, FALSE, + { 02, 04, 04, 04 }, E_ADVANCED, 0, LOTS, + (int (*)()) NULL, + "[[word] alias] : Define an alias." } , + { "deftype", com_dftype, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 3, LOTS, + (int (*)()) NULL, + "spec name pat ... : Redefine vector and plot types.\n" } , + { "plot", com_plot, FALSE, FALSE, TRUE, + { 041000, 041000, 041000, 041000 }, E_BEGINNING | E_HASPLOTS, 1, LOTS, + arg_plot, + "expr ... [vs expr] [xl xlo xhi] [yl ylo yhi] : Plot things." }, + { "display", com_display, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_BEGINNING, 0, LOTS, + arg_display, + ": Display vector status." } , + { "destroy", com_destroy, FALSE, FALSE, FALSE, + { 0400, 0400, 0400, 0400 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[plotname] ... : Throw away all the data in the plot." } , + { "setplot", com_splot, FALSE, FALSE, TRUE, + { 0400, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[plotname] : Change the current working plot." } , + { "setcirc", com_scirc, FALSE, TRUE, FALSE, + { 04, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[circuit name] : Change the current circuit." } , + { "setscale", com_setscale, FALSE, FALSE, FALSE, + { 040000, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[vecname] : Change default scale of current working plot." } , + { "transpose", com_transpose, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "varname ... : Perform matrix transposition on multi-D vectors." } , + { "xgraph", com_xgraph, FALSE, FALSE, TRUE, + { 1, 041000, 041000, 041000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "file plotargs : Send plot to Xgraph-11." } , + { "hardcopy", com_hardcopy, FALSE, FALSE, TRUE, + { 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "file plotargs : Produce hardcopy plots." } , + { "asciiplot", com_asciiplot, FALSE, FALSE, TRUE, + { 041000, 041000, 041000, 041000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "plotargs : Produce ascii plots." } , + { "write", com_write, FALSE, FALSE, TRUE, + { 1, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "file expr ... : Write data to a file." } , + { "compose", com_compose, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "var parm=val ... : Compose a vector." } , + { "unlet", com_unlet, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "varname ... : Undefine vectors." } , + { "print", com_print, FALSE, FALSE, TRUE, + { 040000, 040000, 040000, 040000 }, E_BEGINNING, 1, LOTS, + arg_print, + "[col] expr ... : Print vector values." } , + { "load", com_load, FALSE, FALSE, TRUE, + { 1, 1, 1, 1 }, E_BEGINNING | E_NOPLOTS, 1, LOTS, + arg_load, + "file ... : Load in data." } , + { "cross", com_cross, FALSE, FALSE, TRUE, + { 040000, 0, 040000, 040000 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "vecname number [ vector ... ] : Make a vector in a strange way." } , + { "undefine", com_undefine, FALSE, FALSE, FALSE, + { 010000, 010000, 010000, 010000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[func ...] : Undefine a user-definable function." } , + { "op", com_op, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.op line args] : Determine the operating point of the circuit." } , + { "tf", com_tf, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.tran line args] : Do a transient analysis." } , + { "tran", com_tran, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.tran line args] : Do a transient analysis." } , + { "ac", com_ac, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.ac line args] : Do an ac analysis." } , + { "dc", com_dc, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.dc line args] : Do a dc analysis." } , + { "pz", com_pz, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.pz line args] : Do a pole / zero analysis." } , + { "sens", com_sens, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.sens line args] : Do a sensitivity analysis." } , + { "disto", com_disto, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.disto line args] : Do an distortion analysis." } , + { "noise", com_noise, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[.noise line args] : Do a noise analysis." } , + { "listing", com_listing, FALSE, TRUE, TRUE, + { 0100, 0100, 0100, 0100 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[logical] [physical] [deck] : Print the current circuit." } , + { "edit", com_edit, FALSE, TRUE, TRUE, + { 1, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[filename] : Edit a spice deck and then load it in." } , + { "dump", com_dump, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Print a dump of the current circuit." } , + { "fourier", com_fourier, FALSE, FALSE, TRUE, + { 0, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "fund_freq vector ... : Do a fourier analysis of some data." } , + { "spec", com_spec, FALSE, FALSE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 4, LOTS, + (int (*)()) NULL, + "start_freq stop_freq step_freq vector ... : Create a frequency domain plot." } , + { "show", com_show, FALSE, TRUE, FALSE, + { 040, 040, 040, 040 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "devices ... : parameters ... : Print out device summary." } , + { "showmod", com_showmod, FALSE, TRUE, FALSE, + { 040, 040, 040, 040 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "models ... : parameters ... : Print out model summary." } , + { "alter", com_alter, FALSE, TRUE, FALSE, + { 040, 040, 040, 040 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "devspecs : parmname value : Alter device parameters." } , + { "altermod", com_altermod, FALSE, TRUE, FALSE, + { 040, 040, 040, 040 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "devspecs : parmname value : Alter model parameters." } , + { "resume", com_resume, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Continue after a stop." } , + { "state", com_state, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "(unimplemented) : Print the state of the circuit." }, + { "stop", com_stop, FALSE, TRUE, FALSE, + { 04200, 04200, 04200, 04200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[stop args] : Set a breakpoint." } , + { "trace", com_trce, FALSE, TRUE, FALSE, + { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [node ...] : Trace a node." } , + { "save", com_save, FALSE, TRUE, FALSE, + { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [node ...] : Save a spice output." } , + { "iplot", com_iplot, FALSE, TRUE, TRUE, + { 0200, 0200, 0200, 0200 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [node ...] : Incrementally plot a node." } , + { "status", com_sttus, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Print the current breakpoints and traces." } , + { "delete", com_delete, FALSE, TRUE, FALSE, + { 020, 020, 020, 020 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[all] [break number ...] : Delete breakpoints and traces." } , + { "step", com_step, FALSE, TRUE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[number] : Iterate number times, or one." } , + { "reset", com_rset, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Terminate a simulation after a breakpoint (formerly 'end')." } , + { "run", com_run, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[rawfile] : Run the simulation as specified in the input file." } , + { "aspice", com_aspice, FALSE, FALSE, FALSE, + { 1, 1, 1, 1 }, E_DEFHMASK, 1, 2, + (int (*)()) NULL, + "file [outfile] : Run a spice job asynchronously." } , + { "jobs", com_jobs, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Report on asynchronous spice jobs." } , + { "rspice", com_rspice, FALSE, FALSE, FALSE, + { 1, 1, 1, 1 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[input file] : Run a spice job remotely." } , + { "bug", com_bug, FALSE, FALSE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Report a %s bug." } , + { "where", com_where, FALSE, TRUE, TRUE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Print last non-converging node or device" } , + { "newhelp", com_ahelp, FALSE, FALSE, TRUE, + { 010, 010, 010, 010 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[command name] ... : help." }, + { "tutorial", com_ghelp, FALSE, FALSE, TRUE, + { 023010, 023010, 023010, 023010 }, E_BEGINNING, 0, LOTS, + (int (*)()) NULL, + "[subject] ... : Hierarchical documentation browser." } , + { "help", com_ghelp, FALSE, FALSE, TRUE, + { 023010, 023010, 023010, 023010 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[subject] ... : Hierarchical documentation browser." } , + { "oldhelp", com_help, FALSE, FALSE, TRUE, + { 010, 010, 010, 010 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[command name] ... : Print help." } , + { "quit", com_quit, FALSE, FALSE, TRUE, + { 0, 0, 0, 0 }, E_BEGINNING, 0, 0, + (int (*)()) NULL, + ": Quit %s." } , + { "source", com_source, FALSE, FALSE, TRUE, + { 1, 1, 1, 1 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "file : Source a %s file." } , + { "shift", com_shift, FALSE, FALSE, FALSE, + { 020000, 0, 0, 0 }, E_DEFHMASK, 0, 2, + (int (*)()) NULL, + "[var] [number] : Shift argv or the named list var to the left." } , + { "unset", com_unset, FALSE, FALSE, FALSE, + { 020000, 020000, 020000, 020000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "varname ... : Unset a variable." } , + { "unalias", com_unalias, FALSE, FALSE, FALSE, + { 02, 02, 02, 02 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "word ... : Undefine an alias." } , + { "history", com_history, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 2, + (int (*)()) NULL, + "[-r] [number] : Print command history." } , + { "echo", com_echo, FALSE, FALSE, FALSE, + { 1, 1, 1, 1 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[stuff ...] : Print stuff." } , + { "shell", com_shell, FALSE, FALSE, TRUE, + { 1, 1, 1, 1 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[args] : Fork a shell, or execute the command." } , + { "rusage", com_rusage, FALSE, FALSE, FALSE, + { 02000, 02000, 02000, 02000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[resource ...] : Print current resource usage." } , + { "cd", com_chdir, FALSE, FALSE, FALSE, + { 1, 0, 0, 0 }, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[directory] : Change working directory." } , + { "version", com_version, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "[number] : Print the version number." } , + { "diff", com_diff, FALSE, FALSE, FALSE, + { 0400, 0400, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + "plotname plotname [vec ...] : 'diff' two plots." } , + { "rehash", com_rehash, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Rebuild the unix command database." } , + { "while", NULL, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "condition : Execute while the condition is TRUE." } , + { "repeat", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0}, E_DEFHMASK, 0, 1, + (int (*)()) NULL, + "[number] : Repeat number times, or forever." } , + { "dowhile", NULL, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "condition : Execute while the condition is TRUE." } , + { "foreach", NULL, FALSE, FALSE, FALSE, + { 0, 040000, 040000, 040000 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "variable value ... : Do once for each value." } , + { "if", NULL, FALSE, FALSE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 1, LOTS, + (int (*)()) NULL, + "condition : Execute if the condition is TRUE." } , + { "else", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Goes with if." } , + { "end", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": End a block." } , + { "break", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Break out of a block." } , + { "continue", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Continue a loop." } , + { "label", NULL, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 1, 1, + (int (*)()) NULL, + "word : Create someplace to go to." } , + { "goto", NULL, FALSE, FALSE, FALSE, + { 0100000, 0, 0, 0 }, E_DEFHMASK, 1, 1, + (int (*)()) NULL, + "word : Go to a label." } , + { "cdump", com_cdump, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 0, 0, + (int (*)()) NULL, + ": Dump the current control structures." } , + { "settype", com_stype, FALSE, FALSE, FALSE, + { 0200000, 040000, 040000, 040000 }, E_DEFHMASK, 2, LOTS, + (int (*)()) NULL, + "type vec ... : Change the type of a vector." } , + { "strcmp", com_strcmp, FALSE, FALSE, FALSE, + { 0, 0, 0, 0 }, E_DEFHMASK, 3, 3, + (int (*)()) NULL, + "varname s1 s2 : Set $varname to strcmp(s1, s2)." } , + { "linearize", com_linearize, FALSE, TRUE, FALSE, + { 040000, 040000, 040000, 040000 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + " [ vec ... ] : Convert plot into one with linear scale." } , + { 0, NULL, FALSE, FALSE, FALSE, { 0, 0, 0, 0 }, E_DEFHMASK, 0, LOTS, + (int (*)()) NULL, + NULL } +}; + diff --git a/src/frontend/spec.c b/src/frontend/spec.c new file mode 100644 index 000000000..b78f369c7 --- /dev/null +++ b/src/frontend/spec.c @@ -0,0 +1,285 @@ +/********** +Copyright 1994 Macquarie University, Sydney Australia. All rights reserved. +Author: 1994 Anthony E. Parker, Department of Electronics, Macquarie Uni. +**********/ + +/* + * Code to do fourier transforms on data. + */ + +#include "ngspice.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "spec.h" + + +void +com_spec(wordlist *wl) +{ + complex **fdvec; + double **tdvec; + double *freq, *win, *time, *dc; + double startf, stopf, stepf, span; + int fpts, i, j, k, tlen, ngood; + bool trace; + char *s; + struct dvec *f, *vlist, *lv, *vec; + struct pnode *names, *first_name; + + if (!plot_cur || !plot_cur->pl_scale) { + fprintf(cp_err, "Error: no vectors loaded.\n"); + return; + } + if (!isreal(plot_cur->pl_scale) || + ((plot_cur->pl_scale)->v_type != SV_TIME)) { + fprintf(cp_err, "Error: spec needs real time scale\n"); + return; + } + s = wl->wl_word; + tlen = (plot_cur->pl_scale)->v_length; + if (!(freq = ft_numparse(&s, FALSE)) || (*freq < 0.0)) { + fprintf(cp_err, "Error: bad start freq %s\n", wl->wl_word); + return; + } + startf = *freq; + wl = wl->wl_next; + s = wl->wl_word; + if (!(freq = ft_numparse(&s, FALSE)) || (*freq <= startf)) { + fprintf(cp_err, "Error: bad stop freq %s\n", wl->wl_word); + return; + } + stopf = *freq; + wl = wl->wl_next; + s = wl->wl_word; + if (!(freq = ft_numparse(&s, FALSE)) || !(*freq <= (stopf-startf))) { + fprintf(cp_err, "Error: bad step freq %s\n", wl->wl_word); + return; + } + stepf = *freq; + wl = wl->wl_next; + time = (plot_cur->pl_scale)->v_realdata; + span = time[tlen-1] - time[0]; + if (stopf > 0.5*tlen/span) { + fprintf(cp_err, + "Error: nyquist limit exceeded, try stop freq less than %e Hz\n", + tlen/2/span); + return; + } + span = ((int)(span*stepf*1.000000000001))/stepf; + if (span > 0) { + startf = (int)(startf/stepf*1.000000000001) * stepf; + fpts = (stopf - startf)/stepf + 1; + if (stopf > startf + (fpts-1)*stepf) fpts++; + } else { + fprintf(cp_err,"Error: time span limits step freq to %1.1e Hz\n", + 1/(time[tlen-1] - time[0])); + return; + } + win = (double *) tmalloc(tlen * sizeof (double)); + { + char window[BSIZE_SP]; + double maxt = time[tlen-1]; + if (!cp_getvar("specwindow", VT_STRING, window)) + strcpy(window,"hanning"); + if (eq(window, "none")) + for(i=0; i span) { + win[i] = 0; + } else { + win[i] = 1; + } + } + else if (eq(window, "hanning") || eq(window, "cosine")) + for(i=0; i span) { + win[i] = 0; + } else { + win[i] = 1 - cos(2*M_PI*(time[i]-maxt)/span); + } + } + else if (eq(window, "hamming")) + for(i=0; i span) { + win[i] = 0; + } else { + win[i] = 1 - 0.92/1.08*cos(2*M_PI*(time[i]-maxt)/span); + } + } + else if (eq(window, "triangle") || eq(window, "bartlet")) + for(i=0; i span) { + win[i] = 0; + } else { + win[i] = 2 - fabs(2+4*(time[i]-maxt)/span); + } + } + else if (eq(window, "blackman")) { + int order; + if (!cp_getvar("specwindoworder", VT_NUM, &order)) order = 2; + if (order < 2) order = 2; /* only order 2 supported here */ + for(i=0; i span) { + win[i] = 0; + } else { + win[i] = 1; + win[i] -= 0.50/0.42*cos(2*M_PI*(time[i]-maxt)/span); + win[i] += 0.08/0.42*cos(4*M_PI*(time[i]-maxt)/span); + } + } + } else if (eq(window, "gaussian")) { + int order; + double scale; + extern double erfc(double); + if (!cp_getvar("specwindoworder", VT_NUM, &order)) order = 2; + if (order < 2) order = 2; + scale = pow(2*M_PI/order,0.5)*(0.5-erfc(pow(order,0.5))); + for(i=0; i span) { + win[i] = 0; + } else { + win[i] = exp(-0.5*order*(1-2*(maxt-time[i])/span) + *(1-2*(maxt-time[i])/span))/scale; + } + } + } else { + fprintf(cp_err, "Warning: unknown window type %s\n", window); + tfree(win); + return; + } + } + + names = ft_getpnames(wl, TRUE); + first_name = names; + vlist = NULL; + ngood = 0; + while (names) { + vec = ft_evaluate(names); + names = names->pn_next; + while (vec) { + if (vec->v_length != tlen) { + fprintf(cp_err, "Error: lengths don't match: %d, %d\n", + vec->v_length, tlen); + vec = vec->v_link2; + continue; + } + if (!isreal(vec)) { + fprintf(cp_err, "Error: %s isn't real!\n", + vec->v_name); + vec = vec->v_link2; + continue; + } + if (vec->v_type == SV_TIME) { + vec = vec->v_link2; + continue; + } + if (!vlist) + vlist = vec; + else + lv->v_link2 = vec; + lv = vec; + vec = vec->v_link2; + ngood++; + } + } + free_pnode(first_name); + if (!ngood) { + tfree(win); + return; + } + + plot_cur = plot_alloc("spectrum"); + plot_cur->pl_next = plot_list; + plot_list = plot_cur; + plot_cur->pl_title = copy((plot_cur->pl_next)->pl_title); + plot_cur->pl_name = copy("Spectrum"); + plot_cur->pl_date = copy(datestring( )); + + freq = (double *) tmalloc(fpts * sizeof(double)); + f = alloc(struct dvec); + ZERO(f, struct dvec); + f->v_name = copy("frequency"); + f->v_type = SV_FREQUENCY; + f->v_flags = (VF_REAL | VF_PERMANENT | VF_PRINT); + f->v_length = fpts; + f->v_realdata = freq; + vec_new(f); + + tdvec = (double **) tmalloc(ngood * sizeof(double *)); + fdvec = (complex **) tmalloc(ngood * sizeof(complex *)); + for (i = 0, vec = vlist; iv_realdata; + fdvec[i] = (complex *) tmalloc(fpts * sizeof(complex)); + f = alloc(struct dvec); + ZERO(f, struct dvec); + f->v_name = vec_basename(vec); + f->v_type = vec->v_type; + f->v_flags = (VF_COMPLEX | VF_PERMANENT); + f->v_length = fpts; + f->v_compdata = fdvec[i]; + vec_new(f); + vec = vec->v_link2; + } + + dc = (double *) tmalloc(ngood * sizeof(double)); + for (i = 0; iv_name = copy("win"); + f->v_type = SV_NOTYPE; + f->v_flags = (VF_REAL | VF_PERMANENT); + f->v_length = tlen; + f->v_realdata = win; + vec_new(f); +#else + tfree(win); +#endif + + return; +} + diff --git a/src/frontend/spec.h b/src/frontend/spec.h new file mode 100644 index 000000000..1cec3757a --- /dev/null +++ b/src/frontend/spec.h @@ -0,0 +1,12 @@ +/************* + * Header file for spec.c + * 1999 E. Rouat + ************/ + +#ifndef SPEC_H_INCLUDED +#define SPEC_H_INCLUDED + +void com_spec(wordlist *wl); + + +#endif diff --git a/src/frontend/spiceif.c b/src/frontend/spiceif.c new file mode 100644 index 000000000..af414b488 --- /dev/null +++ b/src/frontend/spiceif.c @@ -0,0 +1,886 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Interface routines. These are specific to spice. The only changes to FTE + * that should be needed to make FTE work with a different simulator is + * to rewrite this file. What each routine is expected to do can be + * found in the programmer's manual. This file should be the only one + * that includes ngspice.header files. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteinp.h" +#include "fteconst.h" +#include "inpdefs.h" +#include "iferrmsg.h" +#include "ifsim.h" +#include "spiceif.h" + + +/* static declarations */ +static struct variable * parmtovar(IFvalue *pv, IFparm *opt); +static IFparm * parmlookup(IFdevice *dev, GENinstance **inptr, char *param, + int do_model, int inout); +static IFvalue * doask(void *ckt, int typecode, GENinstance *dev, GENmodel *mod, + IFparm *opt, int ind); +static int doset(void *ckt, int typecode, GENinstance *dev, GENmodel *mod, + IFparm *opt, struct dvec *val); +static int finddev(void *ck, char *name, void **devptr, void **modptr); + + +/* Input a single deck, and return a pointer to the circuit. */ + +char * +if_inpdeck(struct line *deck, INPtables **tab) +{ + void *ckt; + int err, i, j; + struct line *ll; + IFuid taskUid; + IFuid optUid; + int which = -1; + + for (i = 0, ll = deck; ll; ll = ll->li_next) + i++; + *tab = INPtabInit(i); + ft_curckt->ci_symtab = *tab; + if ((err = (*(ft_sim->newCircuit))(&ckt)) + != OK) { + ft_sperror(err, "CKTinit"); + return (NULL); + } + err = IFnewUid(ckt,&taskUid,(IFuid)NULL,"default",UID_TASK,(void**)NULL); + if(err) { + ft_sperror(err,"newUid"); + return(NULL); + } + err = (*(ft_sim->newTask))(ckt,(void**)&(ft_curckt->ci_defTask),taskUid); + if(err) { + ft_sperror(err,"newTask"); + return(NULL); + } + for(j=0;jnumAnalyses;j++) { + if(strcmp(ft_sim->analyses[j]->name,"options")==0) { + which = j; + break; + } + } + if(which != -1) { + err = IFnewUid(ckt,&optUid,(IFuid)NULL,"options",UID_ANALYSIS, + (void**)NULL); + if(err) { + ft_sperror(err,"newUid"); + return(NULL); + } + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,optUid, + (void**)&(ft_curckt->ci_defOpt), + (void*)ft_curckt->ci_defTask); + if(err) { + ft_sperror(err,"createOptions"); + return(NULL); + } + ft_curckt->ci_curOpt = ft_curckt->ci_defOpt; + } + ft_curckt->ci_curTask = ft_curckt->ci_defTask; + INPpas1((void *) ckt, (card *) deck->li_next,(INPtables *)*tab); + INPpas2((void *) ckt, (card *) deck->li_next, + (INPtables *) *tab,ft_curckt->ci_defTask); + INPkillMods(); + return (ckt); +} + +/* Do a run of the circuit, of the given type. Type "resume" is special -- + * it means to resume whatever simulation that was in progress. The + * return value of this routine is 0 if the exit was ok, and 1 if there was + * a reason to interrupt the circuit (interrupt typed at the keyboard, + * error in the simulation, etc). args should be the entire command line, + * e.g. "tran 1 10 20 uic" + */ + +int +if_run(char *t, char *what, wordlist *args, char *tab) +{ + void *ckt = (void *) t; + int err; + struct line deck; + char buf[BSIZE_SP]; + int j; + int which = -1; + IFuid specUid,optUid; + + /* First parse the line... */ + if (eq(what, "tran") || eq(what, "ac") || eq(what, "dc") + || eq(what, "op") || eq(what, "pz") || eq(what,"disto") + || eq(what, "adjsen") || eq(what, "sens") || eq(what,"tf") + || eq(what, "noise")) { + (void) sprintf(buf, ".%s", wl_flatten(args)); + deck.li_next = deck.li_actual = NULL; + deck.li_error = NULL; + deck.li_linenum = 0; + deck.li_line = buf; + if(ft_curckt->ci_specTask) { + err=(*(ft_sim->deleteTask))(ft_curckt->ci_ckt, + ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"deleteTask"); + return(2); + } + } + err = IFnewUid(ft_curckt->ci_ckt,&specUid,(IFuid)NULL,"special", + UID_TASK,(void**)NULL); + if(err) { + ft_sperror(err,"newUid"); + return(2); + } + err = (*(ft_sim->newTask))(ft_curckt->ci_ckt, + (void**)&(ft_curckt->ci_specTask),specUid); + if(err) { + ft_sperror(err,"newTask"); + return(2); + } + for(j=0;jnumAnalyses;j++) { + if(strcmp(ft_sim->analyses[j]->name,"options")==0) { + which = j; + break; + } + } + if(which != -1) { + err = IFnewUid(ft_curckt->ci_ckt,&optUid,(IFuid)NULL,"options", + UID_ANALYSIS,(void**)NULL); + if(err) { + ft_sperror(err,"newUid"); + return(2); + } + err = (*(ft_sim->newAnalysis))(ft_curckt->ci_ckt,which,optUid, + (void**)&(ft_curckt->ci_specOpt), + (void*)ft_curckt->ci_specTask); + if(err) { + ft_sperror(err,"createOptions"); + return(2); + } + ft_curckt->ci_curOpt = ft_curckt->ci_specOpt; + } + ft_curckt->ci_curTask = ft_curckt->ci_specTask; + INPpas2(ckt, (card *) &deck, (INPtables *)tab, ft_curckt->ci_specTask); + if (deck.li_error) { + fprintf(cp_err, "Warning: %s\n", deck.li_error); + return 2; + } + } + if( eq(what,"run") ) { + ft_curckt->ci_curTask = ft_curckt->ci_defTask; + ft_curckt->ci_curOpt = ft_curckt->ci_defOpt; + } + + if ( (eq(what, "tran")) || + (eq(what, "ac")) || + (eq(what, "dc")) || + (eq(what, "op")) || + (eq(what, "pz")) || + (eq(what, "disto")) || + (eq(what, "noise")) || + eq(what, "adjsen") || eq(what, "sens") || eq(what,"tf") || + (eq(what, "run")) ) { + if ((err = (*(ft_sim->doAnalyses))(ckt, 1, ft_curckt->ci_curTask))!=OK){ + ft_sperror(err, "doAnalyses"); + /* wrd_end(); */ + if (err == E_PAUSE) + return (1); + else + return (2); + } + } else if (eq(what, "resume")) { + if ((err = (*(ft_sim->doAnalyses))(ckt, 0, ft_curckt->ci_curTask))!=OK){ + ft_sperror(err, "doAnalyses"); + /* wrd_end(); */ + if (err == E_PAUSE) + return (1); + else + return (2); + } + } else { + fprintf(cp_err, "if_run: Internal Error: bad run type %s\n", + what); + return (2); + } + return (0); +} + +/* Set an option in the circuit. Arguments are option name, type, and + * value (the last a char *), suitable for casting to whatever needed... + */ + +static char *unsupported[] = { + "itl3", + "itl5", + "lvltim", + "maxord", + "method", + NULL +} ; + +static char *obsolete[] = { + "limpts", + "limtim", + "lvlcod", + NULL +} ; + +int +if_option(void *ckt, char *name, int type, char *value) +{ + IFvalue pval; + int err, i; + void *cc = (void *) ckt; + char **vv; + int which = -1; + + if (eq(name, "acct")) { + ft_acctprint = TRUE; + return 0; + } else if (eq(name, "list")) { + ft_listprint = TRUE; + return 0; + } else if (eq(name, "node")) { + ft_nodesprint = TRUE; + return 0; + } else if (eq(name, "opts")) { + ft_optsprint = TRUE; + return 0; + } else if (eq(name, "nopage")) { + ft_nopage = TRUE; + return 0; + } else if (eq(name, "nomod")) { + ft_nomod = TRUE; + return 0; + } + + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"options")==0) { + which = i; + break; + } + } + if(which==-1) { + fprintf(cp_err,"Warning: .options line unsupported\n"); + return 0; + } + + for (i = 0; i < ft_sim->analyses[which]->numParms; i++) + if (eq(ft_sim->analyses[which]->analysisParms[i].keyword, name) && + (ft_sim->analyses[which]->analysisParms[i].dataType & IF_SET)) + break; + if (i == ft_sim->analyses[which]->numParms) { + /* See if this is unsupported or obsolete. */ + for (vv = unsupported; *vv; vv++) + if (eq(name, *vv)) { + fprintf(cp_err, + "Warning: option %s is currently unsupported.\n", name); + return 1; + } + for (vv = obsolete; *vv; vv++) + if (eq(name, *vv)) { + fprintf(cp_err, + "Warning: option %s is obsolete.\n", name); + return 1; + } + return 0; + } + + switch (ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) { + case IF_REAL: + if (type == VT_REAL) + pval.rValue = *((double *) value); + else if (type == VT_NUM) + pval.rValue = *((int *) value); + else + goto badtype; + break; + case IF_INTEGER: + if (type == VT_NUM) + pval.iValue = *((int *) value); + else if (type == VT_REAL) + pval.iValue = *((double *) value); + else + goto badtype; + break; + case IF_STRING: + if (type == VT_STRING) + pval.sValue = copy(value); + else + goto badtype; + break; + case IF_FLAG: + /* Do nothing. */ + pval.iValue = *((int *) value); + break; + default: + fprintf(cp_err, + "if_option: Internal Error: bad option type %d.\n", + ft_sim->analyses[which]->analysisParms[i].dataType); + } + + if (!ckt) { + /* XXX No circuit loaded */ + fprintf(cp_err, "Simulation parameter \"%s\" can't be set until\n", + name); + fprintf(cp_err, "a circuit has been loaded.\n"); + return 1; + } + + if ((err = (*(ft_sim->setAnalysisParm))(cc, (void *)ft_curckt->ci_curOpt, + ft_sim->analyses[which]->analysisParms[i].id, &pval, + (IFvalue *)NULL)) != OK) + ft_sperror(err, "setAnalysisParm(options)"); + return 1; +badtype: + fprintf(cp_err, "Error: bad type given for option %s --\n", name); + fprintf(cp_err, "\ttype given was "); + switch (type) { + case VT_BOOL: fputs("boolean", cp_err); break; + case VT_NUM: fputs("integer", cp_err); break; + case VT_REAL: fputs("real", cp_err); break; + case VT_STRING: fputs("string", cp_err); break; + case VT_LIST: fputs("list", cp_err); break; + default: fputs("something strange", cp_err); break; + } + fprintf(cp_err, ", type expected was "); + switch(ft_sim->analyses[which]->analysisParms[i].dataType & IF_VARTYPES) { + case IF_REAL: fputs("real.\n", cp_err); break; + case IF_INTEGER:fputs("integer.\n", cp_err); break; + case IF_STRING: fputs("string.\n", cp_err); break; + case IF_FLAG: fputs("flag.\n", cp_err); break; + default: fputs("something strange.\n", cp_err); break; + } + if (type == VT_BOOL) +fputs("\t(Note that you must use an = to separate option name and value.)\n", + cp_err); + return 0; +} + + +void +if_dump(void *ckt, FILE *file) +{ + /*void *cc = (void *) ckt;*/ + + fprintf(file,"diagnostic output dump unavailable."); + return; +} + +void +if_cktfree(void *ckt, char *tab) +{ + void *cc = (void *) ckt; + + (*(ft_sim->deleteCircuit))(cc); + INPtabEnd((INPtables *) tab); + return; +} + +/* Return a string describing an error code. */ + + +/* BLOW THIS AWAY.... */ + +char * +if_errstring(int code) +{ + return (INPerror(code)); +} + +/* Get a parameter value from the circuit. If name is left unspecified, + * we want a circuit parameter. + */ + +struct variable * +spif_getparam(void *ckt, char **name, char *param, int ind, int do_model) +{ + struct variable *vv = NULL, *tv; + IFvalue *pv; + IFparm *opt; + int typecode, i; + GENinstance *dev=(GENinstance *)NULL; + GENmodel *mod=(GENmodel *)NULL; + IFdevice *device; + + /* fprintf(cp_err, "Calling if_getparam(%s, %s)\n", *name, param); */ + + if (param && eq(param, "all")) { + + /* MW. My "special routine here" */ + INPretrieve(name,(INPtables *)ft_curckt->ci_symtab); + + typecode = finddev(ckt, *name,(void**) &dev,(void **) &mod); + if (typecode == -1) { + fprintf(cp_err, + "Error: no such device or model name %s\n", + *name); + return (NULL); + } + device = ft_sim->devices[typecode]; + for (i = 0; i < *(device->numInstanceParms); i++) { + opt = &device->instanceParms[i]; + if(opt->dataType & IF_REDUNDANT || !opt->description) + continue; + if(!(opt->dataType & IF_ASK)) continue; + pv = doask(ckt, typecode, dev, mod, opt, ind); + if (pv) { + tv = parmtovar(pv, opt); + if (vv) + tv->va_next = vv; + vv = tv; + } else + fprintf(cp_err, + "Internal Error: no parameter '%s' on device '%s'\n", + device->instanceParms[i].keyword, + device->name); + } + return (vv); + } else if (param) { + + /* MW. */ + INPretrieve(name,(INPtables *)ft_curckt->ci_symtab); + typecode = finddev(ckt, *name, (void**)&dev, (void **)&mod); + if (typecode == -1) { + fprintf(cp_err, + "Error: no such device or model name %s\n", + *name); + return (NULL); + } + device = ft_sim->devices[typecode]; + opt = parmlookup(device, &dev, param, do_model, 0); + if (!opt) { + fprintf(cp_err, "Error: no such parameter %s.\n", + param); + return (NULL); + } + pv = doask(ckt, typecode, dev, mod, opt, ind); + if (pv) + vv = parmtovar(pv, opt); + return (vv); + } else + return (if_getstat(ckt, *name)); +} + +void +if_setparam(void *ckt, char **name, char *param, struct dvec *val, int do_model) +{ + IFparm *opt; + IFdevice *device; + GENmodel *mod=(GENmodel *)NULL; + GENinstance *dev=(GENinstance *)NULL; + int typecode; + + /* PN */ + INPretrieve(name,(INPtables *)ft_curckt->ci_symtab); + typecode = finddev(ckt, *name, (void**)&dev, (void **)&mod); + if (typecode == -1) { + fprintf(cp_err, "Error: no such device or model name %s\n", *name); + return; + } + device = ft_sim->devices[typecode]; + opt = parmlookup(device, &dev, param, do_model, 1); + if (!opt) { + if (param) + fprintf(cp_err, "Error: no such parameter %s.\n", param); + else + fprintf(cp_err, "Error: no default parameter.\n"); + return; + } + if (do_model && !mod) { + mod = dev->GENmodPtr; + dev = (GENinstance *)NULL; + } + doset(ckt, typecode, dev, mod, opt, val); +} + +static struct variable * +parmtovar(IFvalue *pv, IFparm *opt) +{ + struct variable *vv = alloc(struct variable); + struct variable *nv; + int i = 0; + + switch (opt->dataType & IF_VARTYPES) { + case IF_INTEGER: + vv->va_type = VT_NUM; + vv->va_num = pv->iValue; + break; + case IF_REAL: + case IF_COMPLEX: + vv->va_type = VT_REAL; + vv->va_real = pv->rValue; + break; + case IF_STRING: + vv->va_type = VT_STRING; + vv->va_string = pv->sValue; + break; + case IF_FLAG: + vv->va_type = VT_BOOL; + vv->va_bool = pv->iValue ? TRUE : FALSE; + break; + case IF_REALVEC: + vv->va_type = VT_LIST; + for (i = 0; i < pv->v.numValue; i++) { + nv = alloc(struct variable); + nv->va_next = vv->va_vlist; + vv->va_vlist = nv; + nv->va_type = VT_REAL; + nv->va_real = pv->v.vec.rVec[i]; + } + break; + default: + fprintf(cp_err, + "parmtovar: Internal Error: bad PARM type %d.\n", + opt->dataType); + return (NULL); + } + + /* It's not clear whether we want the keyword or the desc here... */ + vv->va_name = copy(opt->description); + vv->va_next = NULL; + return (vv); +} + +/* Extract the IFparm structure from the device. If isdev is TRUE, then get + * the DEVmodQuest, otherwise get the DEVquest. + */ + +static IFparm * +parmlookup(IFdevice *dev, GENinstance **inptr, char *param, int do_model, int inout) +{ + int i; + + /* fprintf(cp_err, "Called: parmlookup(%x, %c, %s)\n", + dev, isdev, param); */ + + /* First try the device questions... */ + if (!do_model && dev->numInstanceParms) { + for (i = 0; i < *(dev->numInstanceParms); i++) { + if (!param && (dev->instanceParms[i].dataType & IF_PRINCIPAL)) + return (&dev->instanceParms[i]); + else if (!param) + continue; + else if ((((dev->instanceParms[i].dataType & IF_SET) && inout == 1) + || ((dev->instanceParms[i].dataType & IF_ASK) && inout == 0)) + && eq(dev->instanceParms[i].keyword, param)) + { + if (dev->instanceParms[i].dataType & IF_REDUNDANT) + i -= 1; + return (&dev->instanceParms[i]); + } + } + return NULL; + } + + if (dev->numModelParms) { + for (i = 0; i < *(dev->numModelParms); i++) + if ((((dev->modelParms[i].dataType & IF_SET) && inout == 1) + || ((dev->modelParms[i].dataType & IF_ASK) && inout == 0)) + && eq(dev->modelParms[i].keyword, param)) + { + if (dev->modelParms[i].dataType & IF_REDUNDANT) + i -= 1; + return (&dev->modelParms[i]); + } + } + + return (NULL); +} + +/* Perform the CKTask call. We have both 'fast' and 'modfast', so the other + * parameters aren't necessary. + */ + + +static IFvalue * +doask(void *ckt, int typecode, GENinstance *dev, GENmodel *mod, IFparm *opt, int ind) +{ + static IFvalue pv; + int err; + + pv.iValue = ind; /* Sometimes this will be junk and ignored... */ + + /* fprintf(cp_err, "Calling doask(%d, %x, %x, %x)\n", + typecode, dev, mod, opt); */ + if (dev) + err = (*(ft_sim->askInstanceQuest))((void *)ckt, (void *)dev, + opt->id, &pv, (IFvalue *)NULL); + else + err = (*(ft_sim->askModelQuest))((void*)ckt, (void *) mod, + opt->id, &pv, (IFvalue *)NULL); + if (err != OK) { + ft_sperror(err, "if_getparam"); + return (NULL); + } + + return (&pv); +} + +/* Perform the CKTset call. We have both 'fast' and 'modfast', so the other + * parameters aren't necessary. + */ + + +static int +doset(void *ckt, int typecode, GENinstance *dev, GENmodel *mod, IFparm *opt, struct dvec *val) +{ + IFvalue nval; + int err; + int n; + int *iptr; + double *dptr; + int i; + + /* Count items */ + if (opt->dataType & IF_VECTOR) { + n = nval.v.numValue = val->v_length; + + dptr = val->v_realdata; + /* XXXX compdata!!! */ + + switch (opt->dataType & (IF_VARTYPES & ~IF_VECTOR)) { + case IF_FLAG: + case IF_INTEGER: + iptr = nval.v.vec.iVec = NEWN(int, n); + + for (i = 0; i < n; i++) + *iptr++ = *dptr++; + break; + + case IF_REAL: + nval.v.vec.rVec = val->v_realdata; + break; + + default: + fprintf(cp_err, + "Can't assign value to \"%s\" (unsupported vector type)\n", + opt->keyword); + return E_UNSUPP; + } + } else { + switch (opt->dataType & IF_VARTYPES) { + case IF_FLAG: + case IF_INTEGER: + nval.iValue = *val->v_realdata; + break; + + case IF_REAL: +/*kensmith don't blow up with NULL dereference*/ + if (!val->v_realdata) { + fprintf(cp_err,"Unable to determine the value\n"); + return E_UNSUPP; + } + + nval.rValue = *val->v_realdata; + break; + + default: + fprintf(cp_err, + "Can't assign value to \"%s\" (unsupported type)\n", + opt->keyword); + return E_UNSUPP; + } + } + + /* fprintf(cp_err, "Calling doask(%d, %x, %x, %x)\n", + typecode, dev, mod, opt); */ + + if (dev) + err = (*(ft_sim->setInstanceParm))((void *)ckt, (void *)dev, + opt->id, &nval, (IFvalue *)NULL); + else + err = (*(ft_sim->setModelParm))((void*)ckt, (void *) mod, + opt->id, &nval, (IFvalue *)NULL); + + return err; +} + + + +/* Get pointers to a device, its model, and its type number given the name. If + * there is no such device, try to find a model with that name. + */ + +static int +finddev(void *ck, char *name, void **devptr, void **modptr) +{ + int err; + int type = -1; + + err = (*(ft_sim->findInstance))((void *)ck,&type,devptr,name,NULL,NULL); + if(err == OK) return(type); + type = -1; + *devptr = (void *)NULL; + err = (*(ft_sim->findModel))((void *)ck,&type,modptr,name); + if(err == OK) return(type); + *modptr = (void *)NULL; + return(-1); + +} + +#ifdef notdef +/* XXX Not useful */ +/* Extract the node and device names from the line and add them to the command + * completion structure. This is probably not a good thing to do if it + * takes too much time. + */ + + /* BLOW THIS AWAY */ + +void +if_setndnames(line) + char *line; +{ + char *t; + int i; + + while (isspace(*line)) + line++; + + if (!*line || (*line == '*') || (*line == '.')) + return; + t = gettok(&line); + + if (!(i = inp_numnodes(*t))) + return; + if ((*t == 'q') || (*t == 'Q')) + i = 3; + + cp_addkword(CT_DEVNAMES, t); + while (i-- > 0) { + t = gettok(&line); + if (t) + cp_addkword(CT_NODENAMES, t); + } + return; +} +#endif + +/* get an analysis parameter by name instead of id */ + +int +if_analQbyName(void *ckt, int which, void *anal, char *name, IFvalue *parm) +{ + int i; + for(i=0;ianalyses[which]->numParms;i++) { + if(strcmp(ft_sim->analyses[which]->analysisParms[i].keyword,name)==0) { + return( (*(ft_sim->askAnalysisQuest))(ckt,anal, + ft_sim->analyses[which]->analysisParms[i].id,parm, + (IFvalue *)NULL) ); + } + } + return(E_BADPARM); +} + +/* Get the parameters tstart, tstop, and tstep from the CKT struct. */ + +/* BLOW THIS AWAY TOO */ + +bool +if_tranparams(struct circ *ci, double *start, double *stop, double *step) +{ + IFvalue tmp; + int err; + int which = -1; + int i; + void *anal; + IFuid tranUid; + + if(!ci->ci_curTask) return(FALSE); + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"TRAN")==0){ + which = i; + break; + } + } + if(which == -1) return(FALSE); + + err = IFnewUid(ci->ci_ckt,&tranUid,(IFuid)NULL,"Transient Analysis", + UID_ANALYSIS, (void**)NULL); + if(err != OK) return(FALSE); + err =(*(ft_sim->findAnalysis))(ci->ci_ckt,&which, &anal,tranUid, + ci->ci_curTask,(IFuid *)NULL); + if(err != OK) return(FALSE); + err = if_analQbyName(ci->ci_ckt,which,anal,"tstart",&tmp); + if(err != OK) return(FALSE); + *start = tmp.rValue; + err = if_analQbyName(ci->ci_ckt,which,anal,"tstop",&tmp); + if(err != OK) return(FALSE); + *stop = tmp.rValue; + err = if_analQbyName(ci->ci_ckt,which,anal,"tstep",&tmp); + if(err != OK) return(FALSE); + *step = tmp.rValue; + return (TRUE); +} + +/* Get the statistic called 'name'. If this is NULL get all statistics + * available. + */ + +struct variable * +if_getstat(void *ckt, char *name) +{ + int i; + struct variable *v, *vars; + IFvalue parm; + int which = -1; + + for(i=0;inumAnalyses;i++) { + if(strcmp(ft_sim->analyses[i]->name,"options")==0) { + which = i; + break; + } + } + if(which==-1) { + fprintf(cp_err,"Warning: statistics unsupported\n"); + return(NULL); + } + + if (name) { + for (i = 0; i < ft_sim->analyses[which]->numParms; i++) + if (eq(ft_sim->analyses[which]->analysisParms[i].keyword, name)) + break; + if (i == ft_sim->analyses[which]->numParms) + return (NULL); + if ((*(ft_sim->askAnalysisQuest))(ckt, ft_curckt->ci_curTask, + ft_sim->analyses[which]->analysisParms[i].id, &parm, + (IFvalue *)NULL) == -1) { + fprintf(cp_err, + "if_getstat: Internal Error: can't get %s\n", + name); + return (NULL); + } + return (parmtovar(&parm, &(ft_sim->analyses[which]->analysisParms[i]))); + } else { + for (i = 0, vars = v = NULL; ianalyses[which]->numParms; i++) { + if(!(ft_sim->analyses[which]->analysisParms[i].dataType&IF_ASK)) { + continue; + } + if ((*(ft_sim->askAnalysisQuest))(ckt, ft_curckt->ci_curTask, + ft_sim->analyses[which]->analysisParms[i].id, + &parm, (IFvalue *)NULL) == -1) { + fprintf(cp_err, + "if_getstat: Internal Error: can't get %s\n", + name); + return (NULL); + } + if (v) { + v->va_next = parmtovar(&parm, + &(ft_sim->analyses[which]->analysisParms[i])); + v = v->va_next; + } else { + vars = v = parmtovar(&parm, + &(ft_sim->analyses[which]->analysisParms[i])); + } + } + return (vars); + } +} + diff --git a/src/frontend/spiceif.h b/src/frontend/spiceif.h new file mode 100644 index 000000000..4367e29af --- /dev/null +++ b/src/frontend/spiceif.h @@ -0,0 +1,23 @@ +/************* + * Header file for spiceif.c + * 1999 E. Rouat + ************/ + +#ifndef SPICEIF_H_INCLUDED +#define SPICEIF_H_INCLUDED + +char * if_inpdeck(struct line *deck, INPtables **tab); +int if_run(char *t, char *what, wordlist *args, char *tab); +int if_option(void *ckt, char *name, int type, char *value); +void if_dump(void *ckt, FILE *file); +void if_cktfree(void *ckt, char *tab); +char * if_errstring(int code); +struct variable * spif_getparam(void *ckt, char **name, char *param, int ind, int do_model); +void if_setparam(void *ckt, char **name, char *param, struct dvec *val, int do_model); +int if_analQbyName(void *ckt, int which, void *anal, char *name, IFvalue *parm); +bool if_tranparams(struct circ *ci, double *start, double *stop, double *step); +struct variable * if_getstat(void *ckt, char *name); + + + +#endif diff --git a/src/frontend/subckt.c b/src/frontend/subckt.c new file mode 100644 index 000000000..dbc26a588 --- /dev/null +++ b/src/frontend/subckt.c @@ -0,0 +1,948 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Expand subcircuits. This is very spice-dependent. Bug fixes by Norbert + * Jeske on 10/5/85. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteinp.h" +#include "subckt.h" + + +/* static declarations */ +static struct line * doit(struct line *deck); +static int translate(struct line *deck, char *formal, char *actual, char *scname, + char *subname); +static void finishLine(char *dst, char *src, char *scname); +static int settrans(char *formal, char *actual, char *subname); +static char * gettrans(char *name); +static int numnodes(char *name); +static int numdevs(char *s); +static bool modtranslate(struct line *deck, char *subname); +static void devmodtranslate(struct line *deck, char *subname); + + + +struct subs { + char *su_name; /* The name. */ + char *su_args; /* The arguments, space seperated. */ + int su_numargs; + struct line *su_def; /* The deck that is to be substituted. */ + struct subs *su_next; +} ; + +/* Expand all subcircuits in the deck. This handles imbedded .subckt + * definitions. The variables substart, subend, and subinvoke can be used + * to redefine the controls used. The syntax is invariant though. + * NOTE: the deck must be passed without the title line. + * What we do is as follows: first make one pass through the circuit + * and collect all of the subcircuits. Then, whenever a line that starts + * with 'x' is found, copy the subcircuit associated with that name and + * splice it in. A few of the problems: the nodes in the spliced-in + * stuff must be unique, so when we copy it, append "subcktname:" to + * each node. If we are in a nested subcircuit, use foo:bar:...:node. + * Then we have to systematically change all references to the renamed + * nodes. On top of that, we have to know how many args BJT's have, + * so we have to keep track of model names. + */ + +static wordlist *modnames, *submod; +static struct subs *subs = NULL; +static bool nobjthack = FALSE; + +static char start[32], sbend[32], invoke[32], model[32]; + +struct line * +inp_subcktexpand(struct line *deck) +{ + struct line *ll, *c; + char *s; + + if(!cp_getvar("substart", VT_STRING, start)) + (void) strcpy(start, ".subckt"); + if(!cp_getvar("subend", VT_STRING, sbend)) + (void) strcpy(sbend, ".ends"); + if(!cp_getvar("subinvoke", VT_STRING, invoke)) + (void) strcpy(invoke, "X"); + if(!cp_getvar("modelcard", VT_STRING, model)) + (void) strcpy(model, ".model"); + if(!cp_getvar("modelline", VT_STRING, model)) + (void) strcpy(model, ".model"); + (void) cp_getvar("nobjthack", VT_BOOL, (char *) &nobjthack); + + /* Let's do a few cleanup things first... Get rid of ( ) around node + * lists... + */ + for (c = deck; c; c = c->li_next) { + if (prefix(start, c->li_line)) { + for (s = c->li_line; *s && (*s != '('); s++) + ; + if (*s) { + while (s[0] && (s[1] != ')')) { + s[0] = s[1]; + s++; + } + while (s[1]) { + s[0] = s[2]; + s++; + } + } + } else { + for (s = c->li_line; *s && !isspace(*s); s++) + ; + while (isspace(*s)) + s++; + if (*s == '(') { + while (s[0] && (s[1] != ')')) { + s[0] = s[1]; + s++; + } + while (s[1]) { + s[0] = s[2]; + s++; + } + } + } + } + + ll = doit(deck); + + return (ll); +} + +#define MAXNEST 21 + +static struct line * +doit(struct line *deck) +{ + struct line *c, *last, *lc, *lcc; + struct subs *sss = (struct subs *) NULL, *ks; + char *s, *t, *scname, *subname; + int nest, numpasses = MAXNEST, i; + bool gotone; + wordlist *wl; + wordlist *tmodnames = modnames; + wordlist *tsubmod = submod; + struct subs *ts = subs; + int error; + + /* Save all the old stuff... */ + modnames = NULL; + subs = NULL; + submod = NULL; + + /* Extract all the .subckts */ + for (last = deck, lc = NULL; last; ) { + if (prefix(sbend, last->li_line)) { + fprintf(cp_err, "Error: misplaced %s line: %s\n", sbend, + last->li_line); + return (NULL); + } else if (prefix(start, last->li_line)) { + if (last->li_next == NULL) { + fprintf(cp_err, "Error: no %s line.\n", sbend); + return (NULL); + } + lcc = NULL; + wl_free(submod); + submod = NULL; + gotone = FALSE; + for (nest = 0, c = last->li_next; c; c = c->li_next) { + if (prefix(sbend, c->li_line)) { + if (!nest) + break; + else { + nest--; + lcc = c; + continue; + } + } else if (prefix(start, c->li_line)) + nest++; + lcc = c; + } + if (!c) { + fprintf(cp_err, "Error: no %s line.\n", sbend); + return (NULL); + } + sss = alloc(struct subs); + if (!lcc) + lcc = last; + lcc->li_next = NULL; + if (lc) + lc->li_next = c->li_next; + else + deck = c->li_next; + sss->su_def = last->li_next; + s = last->li_line; + (void) gettok(&s); + sss->su_name = gettok(&s); + sss->su_args = copy(s); + for (sss->su_numargs = 0, i = 0; s[i]; ) { + while (isspace(s[i])) + i++; + if (s[i]) { + sss->su_numargs++; + while (s[i] && !isspace(s[i])) + i++; + } + } + sss->su_next = subs; + subs = sss; + last = c->li_next; + lcc = subs->su_def; + } else { + lc = last; + last = last->li_next; + } + } + + if (!sss) + return (deck); + + /* Expand sub-subcircuits. */ + for (ks = sss = subs; sss; sss = sss->su_next) + if (!(sss->su_def = doit(sss->su_def))) + return (NULL); + subs = ks; + + /* Get all the model names so we can deal with BJT's. */ + for (c = deck; c; c = c->li_next) + if (prefix(model, c->li_line)) { + s = c->li_line; + (void) gettok(&s); + wl = alloc(struct wordlist); + wl->wl_next = modnames; + if (modnames) + modnames->wl_prev = wl; + modnames = wl; + wl->wl_word = gettok(&s); + } + + error = 0; + /* Now do the replacements. */ + do { + gotone = FALSE; + for (c = deck, lc = NULL; c; ) { + if (ciprefix(invoke, c->li_line)) { + gotone = TRUE; + t = s = copy(c->li_line); + scname = gettok(&s); + scname += strlen(invoke); + while ((*scname == ' ') || (*scname == '\t') || + (*scname == ':')) + scname++; + while(*s) + s++; + s--; + while ((*s == ' ') || (*s == '\t')) + *s-- = '\0'; + while ((*s != ' ') && (*s != '\t')) + s--; + s++; + for (sss = subs; sss; sss = sss->su_next) + if (eq(sss->su_name, s)) + break; + /* Don't complain -- this might be an + * instance of a subckt that is defined above. + */ + if (!sss) { + lc = c; + c = c->li_next; + continue; + } + /* Now we have to replace this line with the + * macro definition. + */ + subname = copy(sss->su_name); + lcc = inp_deckcopy(sss->su_def); + + /* Change the names of the models... */ + if (modtranslate(lcc, scname)) + devmodtranslate(lcc, scname); + + s = sss->su_args; + (void) gettok(&t); /* Throw out the name. */ + + if (!translate(lcc, s, t, scname, subname)) + error = 1; + + /* Now splice the decks together. */ + if (lc) + lc->li_next = lcc; + else + deck = lcc; + while (lcc->li_next != NULL) + lcc = lcc->li_next; + lcc->li_next = c->li_next; + c = lcc->li_next; + lc = lcc; + } else { + lc = c; + c = c->li_next; + } + } + } while (!error && numpasses-- && gotone); + + if (!numpasses) { + fprintf(cp_err, "Error: infinite subckt recursion\n"); + return (NULL); + } + + /* Now check to see if there are still subckt instances undefined... */ + for (c = deck; c; c = c->li_next) + if (ciprefix(invoke, c->li_line)) { + fprintf(cp_err, "Error: unknown subckt: %s\n", + c->li_line); + error = 1; + } + + if (error) + return NULL; /* error message already reported; should free( ) */ + + subs = ts; + modnames = tmodnames; + submod = tsubmod; + + return (deck); +} + +/* Copy a deck, including the actual lines. */ + +struct line * +inp_deckcopy(struct line *deck) +{ + struct line *d = NULL, *nd = NULL; + + while (deck) { + if (nd) { + d->li_next = alloc(struct line); + d = d->li_next; + } else + nd = d = alloc(struct line); + d->li_linenum = deck->li_linenum; + d->li_line = copy(deck->li_line); + if (deck->li_error) + d->li_error = copy(deck->li_error); + d->li_actual = inp_deckcopy(deck->li_actual); + deck = deck->li_next; + } + return (nd); +} + +/* Translate all of the device names and node names in the deck. They are + * pre-pended with subname:, unless they are in the formal list, in which case + * they are replaced with the corresponding entry in the actual list. + * The one special case is node 0 -- this is always ground and we don't + * touch it. + */ + +static int +translate(struct line *deck, char *formal, char *actual, char *scname, char *subname) +{ + struct line *c; + char *buffer, *name, *s, *t, ch; + int nnodes, i; + + i = settrans(formal, actual, subname); + if (i < 0) { + fprintf(stderr, + "Too few parameters for subcircuit type \"%s\" (instance: x%s)\n", + subname, scname); + return 0; + } else if (i > 0) { + fprintf(stderr, + "Too many parameters for subcircuit type \"%s\" (instance: x%s)\n", + subname, scname); + return 0; + } + + for (c = deck; c; c = c->li_next) { + /* Rename the device. */ + switch (*c->li_line) { + case '\0': + case '*': + case '.': + /* Nothing any good here. */ + continue; + + default: + s = c->li_line; + name = gettok(&s); + if (!name) + continue; + if (!*name) { + tfree(name); + continue; + } + ch = *name; + buffer = tmalloc(10000); /* XXXXX */ + name++; + if (*name == ':') + name++; + if (*name) + (void) sprintf(buffer, "%c:%s:%s ", ch, scname, + name); + else + (void) sprintf(buffer, "%c:%s ", ch, scname); + + nnodes = numnodes(c->li_line); + while (nnodes-- > 0) { + name = gettok(&s); + if (name == NULL) { + fprintf(cp_err, "Error: too few nodes: %s\n", + c->li_line); + return 0; + } + t = gettrans(name); + if (t) + (void) sprintf(buffer + strlen(buffer), "%s ", + t); + else + (void) sprintf(buffer + strlen(buffer), + "%s:%s ", scname, name); + } + nnodes = numdevs(c->li_line); + while (nnodes-- > 0) { + name = gettok(&s); + if (name == NULL) { + fprintf(cp_err, "Error: too few devs: %s\n", + c->li_line); + return 0; + } + ch = *name; + name++; + if (*name == ':') + name++; + if (*name) + (void) sprintf(buffer + strlen(buffer), + "%c:%s:%s ", ch, scname, name); + else + (void) sprintf(buffer + strlen(buffer), + "%c:%s ", ch, scname); + } + /* Now scan through the line for v(something) and + * i(something)... + */ + finishLine(buffer + strlen(buffer), s, scname); + s = ""; + } + (void) strcat(buffer, s); + tfree(c->li_line); + c->li_line = copy(buffer); + tfree(buffer); + } + return 1; +} + +static void +finishLine(char *dst, char *src, char *scname) +{ + char buf[4 * BSIZE_SP], which; + char *s; + int i; + int lastwasalpha; + + lastwasalpha = 0; + while (*src) { + /* Find the next instance of "[vi](" in + * this string. + */ + if (((*src != 'v') && (*src != 'V') && + (*src != 'i') && (*src != 'I')) || + lastwasalpha) { + lastwasalpha = isalpha(*src); + *dst++ = *src++; + continue; + } + for (s = src + 1; *s && isspace(*s); s++) + ; + if (!*s || (*s != '(')) { + lastwasalpha = isalpha(*src); + *dst++ = *src++; + continue; + } + lastwasalpha = 0; + which = *dst++ = *src; + src = s; + *dst++ = *src++; + while (isspace(*src)) + src++; + for (i = 0; *src && !isspace(*src) && *src != ',' && (*src != ')'); + i++) + { + buf[i] = *src++; + } + buf[i] = '\0'; + + if ((which == 'v') || (which == 'V')) + s = gettrans(buf); + else + s = NULL; + + if (s) { + while (*s) + *dst++ = *s++; + } else { + /* + * i(vname) -> i(v:subckt:name) + * i(v:other:name) -> i(v:subckt:other:name) + */ + if (buf[0] == 'v' || buf[0] == 'V') { + *dst++ = buf[0]; + *dst++ = ':'; + i = 1; + } else { + i = 0; + } + for (s = scname; *s; ) + *dst++ = *s++; + *dst++ = ':'; + for (s = buf + i; *s; ) + *dst++ = *s++; + } + + /* translate the reference node, as in the "2" in "v(4,2)" */ + + if ((which == 'v') || (which == 'V')) { + while (*src && (isspace(*src) || *src == ',')) { + src++; + } + if (*src && *src != ')') { + for (i = 0; *src && !isspace(*src) && (*src != ')'); i++) + buf[i] = *src++; + buf[i] = '\0'; + s = gettrans(buf); + *dst++ = ','; + if (s) { + while (*s) + *dst++ = *s++; + } else { + for (s = scname; *s; ) + *dst++ = *s++; + *dst++ = ':'; + for (s = buf; *s; ) + *dst++ = *s++; + } + } + } + } + + return; +} + +static struct tab { + char *t_old; + char *t_new; +} table[512]; /* That had better be enough. */ + +static int +settrans(char *formal, char *actual, char *subname) +{ + int i; + + for (i = 0; ; i++) { + table[i].t_old = gettok(&formal); + table[i].t_new = gettok(&actual); + + if (table[i].t_new == NULL) { + return -1; /* Too few actual / too many formal */ + } else if (table[i].t_old == NULL) { + if (eq(table[i].t_new, subname)) + break; + else + return 1; /* Too many actual / too few formal */ + } + } + return 0; +} + +static char * +gettrans(char *name) +{ + int i; + + if (eq(name, "0")) + return (name); + for (i = 0; table[i].t_old; i++) + if (eq(table[i].t_old, name)) + return (table[i].t_new); + return (NULL); +} + +static int +numnodes(char *name) +{ + char c; + struct subs *sss; + char *s, *t, buf[4 * BSIZE_SP]; + wordlist *wl; + int n, i; + + while (*name && isspace(*name)) + name++; + + c = (isupper(*name) ? tolower(*name) : *name); + + (void) strncpy(buf, name, sizeof(buf)); + s = buf; + if (c == 'x') { /* Handle this ourselves. */ + while(*s) + s++; + s--; + while ((*s == ' ') || (*s == '\t')) + *s-- = '\0'; + while ((*s != ' ') && (*s != '\t')) + s--; + s++; + for (sss = subs; sss; sss = sss->su_next) + if (eq(sss->su_name, s)) + break; + if (!sss) { + fprintf(cp_err, "Error: no such subcircuit: %s\n", s); + return (0); + } + return (sss->su_numargs); + } + n = inp_numnodes(c); + if (nobjthack || (c != 'q')) + return (n); + for (s = buf, i = 0; *s && (i < 4); i++) + (void) gettok(&s); + if (i == 3) + return (3); + else if (i < 4) { + fprintf(cp_err, "Error: too few nodes for BJT: %s\n", name); + return (0); + } + /* Now, is this a model? */ + t = gettok(&s); + for (wl = modnames; wl; wl = wl->wl_next) + if (eq(t, wl->wl_word)) + return (3); + return (4); +} + +static int +numdevs(char *s) +{ + + while (*s && isspace(*s)) + s++; + switch (*s) { + case 'K': + case 'k': + return (2); + + case 'F': + case 'f': + case 'H': + case 'h': + /* 2 lines here added to fix w bug, NCF 1/31/95 */ + case 'W': + case 'w': + return (1); + + default: + return (0); + } +} + +static bool +modtranslate(struct line *deck, char *subname) +{ + struct line *c; + char *buffer, *name, *t, model[4 * BSIZE_SP]; + wordlist *wl, *wlsub; + bool gotone; + + (void) strcpy(model, ".model"); + gotone = FALSE; + for (c = deck; c; c = c->li_next) { + if (prefix(model, c->li_line)) { + gotone = TRUE; + t = c->li_line; + name = gettok(&t); + buffer = tmalloc(strlen(name) + strlen(t) + + strlen(subname) + 4); + (void) sprintf(buffer, "%s ",name); + name = gettok(&t); + wlsub = alloc(struct wordlist); + wlsub->wl_next = submod; + if (submod) + submod->wl_prev = wlsub; + submod = wlsub; + wlsub->wl_word = name; + (void) sprintf(buffer + strlen(buffer), "%s:%s ", + subname, name); + (void) strcat(buffer, t); + tfree(c->li_line); + c->li_line = buffer; + t = c->li_line; + (void) gettok(&t); + wl = alloc(struct wordlist); + wl->wl_next = modnames; + if (modnames) + modnames->wl_prev = wl; + modnames = wl; + wl->wl_word = gettok(&t); + } + } + return(gotone); +} + +static void +devmodtranslate(struct line *deck, char *subname) +{ + struct line *s; + char *buffer, *name, *t, c; + wordlist *wlsub; + bool found; + + for (s = deck; s; s = s->li_next) { + t = s->li_line; + while (*t && isspace(*t)) + t++; + c = isupper(*t) ? tolower(*t) : *t; + found = FALSE; + buffer = tmalloc(strlen(t) + strlen(subname) + 4); + + switch (c) { + + case 'r': + case 'c': + name = gettok(&t); + (void) sprintf(buffer,"%s ",name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + + if (*t) { + name = gettok(&t); + /* Now, is this a subcircuit model? */ + for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { + if (eq(name, wlsub->wl_word)) { + (void) sprintf(buffer + strlen(buffer), "%s:%s ", + subname, name); + found = TRUE; + break; + } + } + if (!found) + (void) sprintf(buffer + strlen(buffer), "%s ", name); + } + + found = FALSE; + if (*t) { + name = gettok(&t); + /* Now, is this a subcircuit model? */ + for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { + if (eq(name, wlsub->wl_word)) { + (void) sprintf(buffer + strlen(buffer), "%s:%s ", + subname, name); + found = TRUE; + break; + } + } + if (!found) + (void) sprintf(buffer + strlen(buffer), "%s ", name); + } + + (void) strcat(buffer, t); + tfree(s->li_line); + s->li_line = buffer; + break; + + case 'd': + name = gettok(&t); + (void) sprintf(buffer,"%s ",name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + + /* Now, is this a subcircuit model? */ + for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { + if (eq(name, wlsub->wl_word)) { + (void) sprintf(buffer + strlen(buffer), "%s:%s ", + subname, name); + found = TRUE; + break; + } + } + + if (!found) + (void) sprintf(buffer + strlen(buffer), "%s ", name); + (void) strcat(buffer, t); + tfree(s->li_line); + s->li_line = buffer; + break; + + case 'w': + case 'u': + case 'j': + case 'z': + name = gettok(&t); + (void) sprintf(buffer,"%s ",name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + + /* Now, is this a subcircuit model? */ + for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { + if (eq(name, wlsub->wl_word)) { + (void) sprintf(buffer + strlen(buffer), "%s:%s ", + subname, name); + found = TRUE; + break; + } + } + + if (!found) + (void) sprintf(buffer + strlen(buffer), "%s ", name); + (void) strcat(buffer, t); + tfree(s->li_line); + s->li_line = buffer; + break; + + case 'o': + case 's': + case 'm': + name = gettok(&t); + (void) sprintf(buffer,"%s ",name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + + /* Now, is this a subcircuit model? */ + for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { + if (eq(name, wlsub->wl_word)) { + (void) sprintf(buffer + strlen(buffer), "%s:%s ", + subname, name); + found = TRUE; + break; + } + } + + if (!found) + (void) sprintf(buffer + strlen(buffer), "%s ", name); + (void) strcat(buffer, t); + tfree(s->li_line); + s->li_line = buffer; + break; + + case 'q': + name = gettok(&t); + (void) sprintf(buffer,"%s ",name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + (void) sprintf(buffer + strlen(buffer), "%s ", name); + name = gettok(&t); + + /* Now, is this a subcircuit model? */ + for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { + if (eq(name, wlsub->wl_word)) { + (void) sprintf(buffer + strlen(buffer), "%s:%s ", + subname, name); + found = TRUE; + break; + } + } + if (!found) + (void) sprintf(buffer + strlen(buffer), "%s ", name); + + found = FALSE; + if (*t) { + name = gettok(&t); + /* Now, is this a subcircuit model? */ + for (wlsub = submod; wlsub; wlsub = wlsub->wl_next) { + if (eq(name, wlsub->wl_word)) { + (void) sprintf(buffer + strlen(buffer), + "%s:%s ", subname, name); + found = TRUE; + break; + } + } + if (!found) + (void) sprintf(buffer + strlen(buffer), "%s ", name); + } + + (void) strcat(buffer, t); + tfree(s->li_line); + s->li_line = buffer; + break; + + default: + tfree(buffer); + break; + } + } + return; +} + +/* This is a spice-dependent thing. It should probably go somewhere + * else, but... Note that we pretend that dependent sources and mutual + * inductors have more nodes than they really do... + */ + +int +inp_numnodes(char c) +{ + if (isupper(c)) + c = tolower(c); + switch (c) { + case ' ': + case '\t': + case '.': + case 'x': + case '*': + return (0); + + case 'b': return (2); + case 'c': return (2); + case 'd': return (2); + case 'e': return (4); + case 'f': return (2); + case 'g': return (4); + case 'h': return (2); + case 'i': return (2); + case 'j': return (3); + case 'k': return (0); + case 'l': return (2); + case 'm': return (4); + case 'o': return (4); + case 'q': return (4); + case 'r': return (2); + case 's': return (4); + case 't': return (4); + case 'u': return (3); + case 'v': return (2); + /* change 3 to 2 here to fix w bug, NCF 1/31/95 */ + case 'w': return (2); + case 'z': return (3); + + default: + fprintf(cp_err, "Warning: unknown device type: %c\n", c); + return (2); + } +} + diff --git a/src/frontend/subckt.h b/src/frontend/subckt.h new file mode 100644 index 000000000..2a134e1cc --- /dev/null +++ b/src/frontend/subckt.h @@ -0,0 +1,15 @@ +/************* + * Header file for subckt.c + * 1999 E. Rouat + ************/ + +#ifndef SUBCKT_H_INCLUDED +#define SUBCKT_H_INCLUDED + +struct line * inp_subcktexpand(struct line *deck); +struct line * inp_deckcopy(struct line *deck); +int inp_numnodes(char c); + + + +#endif diff --git a/src/frontend/typesdef.c b/src/frontend/typesdef.c new file mode 100644 index 000000000..0c53ab906 --- /dev/null +++ b/src/frontend/typesdef.c @@ -0,0 +1,242 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Stuff to deal with nutmeg "types" for vectors and plots. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "typesdef.h" + + +#define NUMTYPES 128 /* If this is too little we can use a list. */ +#define NUMPLOTTYPES 512 /* Since there may be more than 1 pat/type. */ + +struct type { + char *t_name; + char *t_abbrev; +}; + +/* The stuff for plot names. */ + +struct plotab { + char *p_name; + char *p_pattern; +}; + +/* note: This should correspond to SV_ defined in FTEconstant.h */ +struct type types[NUMTYPES] = { + { "notype", NULL } , + { "time", "S" } , + { "frequency", "Hz" } , + { "voltage", "V" } , + { "current", "A" } , + { "onoise-spectrum", "(V or A)^2/Hz" } , + { "onoise-integrated", "V or A" } , + { "inoise-spectrum", "(V or A)^2/Hz" } , + { "inoise-integrated", "V or A" } , + { "output-noise", NULL } , + { "input-noise", NULL } , +#ifdef notdef + { "HD2", NULL } , + { "HD3", NULL } , + { "DIM2", NULL } , + { "SIM2", NULL } , + { "DIM3", NULL } , +#endif + { "pole", NULL } , + { "zero", NULL } , + { "s-param", NULL } , +} ; + +/* The stuff for plot names. */ + +struct plotab plotabs[NUMPLOTTYPES] = { + { "tran", "transient" } , + { "op", "op" } , + { "tf", "function" }, + { "dc", "d.c." } , + { "dc", "dc" } , + { "dc", "transfer" } , + { "ac", "a.c." } , + { "ac", "ac" } , + { "pz", "pz" } , + { "pz", "p.z." } , + { "pz", "pole-zero"} , + { "disto", "disto" } , + { "dist", "dist" } , + { "noise", "noise" } , + { "sens", "sens" } , + { "sens", "sensitivity" } , + { "sens2", "sens2" } , + { "sp", "s.p." } , + { "sp", "sp" } , + { "harm", "harm" }, + { "spect", "spect" }, +} ; + +int notypes = 14; +int noplotabs = 18; + +/* A command to define types for vectors and plots. This will generally + * be used in the Command: field of the rawfile. + * The syntax is "deftype v typename abbrev", where abbrev will be used to + * parse things like abbrev(name) and to label axes with M, instead + * of numbers. It may be ommitted. + * Also, the command "deftype p plottype pattern ..." will assign plottype as + * the name to any plot with one of the patterns in its Name: field. + */ + +void +com_dftype(wordlist *wl) +{ + char *name, *abb; + int i; + + switch (*wl->wl_word) { + case 'v': + case 'V': + wl = wl->wl_next; + name = copy(wl->wl_word); + wl = wl->wl_next; + abb = copy(wl->wl_word); + for (i = 0; i < notypes; i++) + if (cieq(types[i].t_name, name)) { + types[i].t_abbrev = abb; + return; + } + if (notypes >= NUMTYPES - 1) { + fprintf(cp_err, "Error: too many types defined\n"); + return; + } + types[notypes].t_name = name; + types[notypes].t_abbrev = abb; + notypes++; + break; + + case 'p': + case 'P': + wl = wl->wl_next; + name = copy(wl->wl_word); + wl = wl->wl_next; + while (wl) { + for (i = 0; i < noplotabs; i++) + if (cieq(plotabs[i].p_pattern, wl->wl_word)) { + plotabs[i].p_name = name; + wl = wl->wl_next; + break; + } + if (i != noplotabs) + continue; + if (noplotabs >= NUMPLOTTYPES - 1) { + fprintf(cp_err, "Error: too many plot abs\n"); + return; + } + plotabs[noplotabs].p_name = name; + plotabs[noplotabs].p_pattern = copy(wl->wl_word); + wl = wl->wl_next; + noplotabs++; + } + break; + + default: + fprintf(cp_err, "Error: missing 'p' or 'v' argument\n"); + break; + } + return; +} + +/* Return the abbreviation associated with a number. */ + +char * +ft_typabbrev(int typenum) +{ + if ((typenum < NUMTYPES) && (typenum >= 0)) + return (types[typenum].t_abbrev); + else + return (NULL); +} + +/* Return the typename associated with a number. */ + +char * +ft_typenames(int typenum) +{ + if ((typenum < NUMTYPES) && (typenum >= 0)) + return (types[typenum].t_name); + else + return (NULL); +} + +/* Return the type number associated with the name. */ + +int +ft_typnum(char *name) +{ + int i; + + if (eq(name, "none")) + name = "notype"; + for (i = 0; (i < NUMTYPES) && types[i].t_name; i++) + if (cieq(name, types[i].t_name)) + return (i); + return (0); +} + +/* For plots... */ + +char * +ft_plotabbrev(char *string) +{ + char buf[128]; + int i; + + if (!string) + return (NULL); + for (i = 0; string[i]; i++) + buf[i] = isupper(string[i]) ? tolower(string[i]) : string[i]; + buf[i] = '\0'; + + for (i = 0; plotabs[i].p_name; i++) + if (substring(plotabs[i].p_pattern, buf)) + return (plotabs[i].p_name); + + return (NULL); +} + +/* Change the type of a vector. */ + +void +com_stype(wordlist *wl) +{ + char *type = wl->wl_word; + int tt; + struct dvec *v, *vv; + char *s; + + for (tt = 0; ; tt++) { + if (!(s = ft_typenames(tt)) || eq(type, s)) + break; + } + if (!s) { + fprintf(cp_err, "Error: no such type as '%s'\n", type); + return; + } + for (wl = wl->wl_next; wl; wl = wl->wl_next) { + v = vec_get(wl->wl_word); + if (!v) + fprintf(cp_err, "Error: no such vector %s.\n", + wl->wl_word); + else + for (vv = v; vv; vv = vv->v_link2) + if (vv->v_flags & VF_PERMANENT) + vv->v_type = tt; + } + return; +} + diff --git a/src/frontend/typesdef.h b/src/frontend/typesdef.h new file mode 100644 index 000000000..5929a3b5f --- /dev/null +++ b/src/frontend/typesdef.h @@ -0,0 +1,17 @@ +/************* + * Header file for typesdef.c + * 1999 E. Rouat + ************/ + +#ifndef TYPESDEF_H_INCLUDED +#define TYPESDEF_H_INCLUDED + +void com_dftype(wordlist *wl); +char * ft_typabbrev(int typenum); +char * ft_typenames(int typenum); +int ft_typnum(char *name); +char * ft_plotabbrev(char *string); +void com_stype(wordlist *wl); + + +#endif diff --git a/src/frontend/vectors.c b/src/frontend/vectors.c new file mode 100644 index 000000000..380903428 --- /dev/null +++ b/src/frontend/vectors.c @@ -0,0 +1,895 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines for dealing with the vector database. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "vectors.h" + +/* static declarations */ + +static struct dvec * findvec(char *word, struct plot *pl); +static struct dvec * sortvecs(struct dvec *d); +static int veccmp(struct dvec **d1, struct dvec **d2); +static int namecmp(char *s, char *t); + + +/* Where 'constants' go when defined on initialization. */ + +static struct plot constantplot = { + "Constant values", "Sat Aug 16 10:55:15 PDT 1986", "constants", + "const", NULL, NULL, NULL, NULL, NULL, NULL, TRUE +} ; + +struct plot *plot_cur = &constantplot; +struct plot *plot_list = &constantplot; +int plotl_changed; /* TRUE after a load */ + +int plot_num = 1; + +/* Load in a rawfile. */ + +void +ft_loadfile(char *file) +{ + struct plot *pl, *np, *pp; + + fprintf(cp_out, "Loading raw data file (\"%s\") . . . ", file); + pl = raw_read(file); + if (pl) + fprintf(cp_out, "done.\n"); + else + fprintf(cp_out, "no data read.\n"); + + /* This is a minor annoyance -- we should reverse the plot list so + * they get numbered in the correct order. + */ + for (pp = pl, pl = NULL; pp; pp = np) { + np = pp->pl_next; + pp->pl_next = pl; + pl = pp; + } + for (; pl; pl = np) { + np = pl->pl_next; + plot_add(pl); + /* Don't want to get too many "plot not written" messages. */ + pl->pl_written = TRUE; + } + plot_num++; + plotl_changed = TRUE; + return; +} + +void +plot_add(struct plot *pl) +{ + struct dvec *v; + struct plot *tp; + char *s, buf[BSIZE_SP]; + + fprintf(cp_out, "Title: %s\nName: %s\nDate: %s\n\n", pl->pl_title, + pl->pl_name, pl->pl_date); + + if (plot_cur) + plot_cur->pl_ccom = cp_kwswitch(CT_VECTOR, pl->pl_ccom); + + for (v = pl->pl_dvecs; v; v = v->v_next) + cp_addkword(CT_VECTOR, v->v_name); + cp_addkword(CT_VECTOR, "all"); + + if (!(s = ft_plotabbrev(pl->pl_name))) + s = "unknown"; + do { + (void) sprintf(buf, "%s%d", s, plot_num); + for (tp = plot_list; tp; tp = tp->pl_next) + if (cieq(tp->pl_typename, buf)) { + plot_num++; + break; + } + } while (tp); + + pl->pl_typename = copy(buf); + plot_new(pl); + cp_addkword(CT_PLOT, buf); + pl->pl_ccom = cp_kwswitch(CT_VECTOR, (char *) NULL); + plot_setcur(pl->pl_typename); + + return; +} + +/* Remove a vector from the database, if it is there. */ + +void +vec_remove(char *name) +{ + struct dvec *ov; + + for (ov = plot_cur->pl_dvecs; ov; ov = ov->v_next) { + if (cieq(name, ov->v_name) && (ov->v_flags & VF_PERMANENT)) + break; + } + if (!ov) + return; + + ov->v_flags &= ~VF_PERMANENT; + + /* Remove from the keyword list. */ + cp_remkword(CT_VECTOR, name); + return; +} + +/* Get a vector by name. This deals with v(1), etc. almost properly. Also, + * it checks for pre-defined vectors. + */ + +struct dvec * +vec_fromplot(char *word, struct plot *plot) +{ + struct dvec *d; + char buf[BSIZE_SP], buf2[BSIZE_SP], cc, *s; + + d = findvec(word, plot); + if (!d) { + (void) strcpy(buf, word); + for (s = buf; *s; s++) + if (isupper(*s)) + *s = tolower(*s); + d = findvec(buf, plot); + } + if (!d) { + (void) strcpy(buf, word); + for (s = buf; *s; s++) + if (islower(*s)) + *s = *s - 'a' + 'A'; + d = findvec(buf, plot); + } + + /* scanf("%c(%s)" doesn't do what it should do. ) */ + if (!d && (sscanf(word, "%c(%s", /* ) */ &cc, buf) == 2) && + /* ( */ ((s =strrchr(buf, ')')) != NULL) && + (*(s + 1) == '\0')) { + *s = '\0'; + if (prefix("i(", /* ) */ word)) { + /* Spice dependency... */ + (void) sprintf(buf2, "%s#branch", buf); + (void) strcpy(buf, buf2); + } + d = findvec(buf, plot); + } + + return (d); +} + +/* This is the main lookup routine for names. The possible types of names are: + * name An ordinary vector. + * plot.name A vector from a particular plot. + * @device[parm] A device parameter. + * @model[parm] A model parameter. + * @param A circuit parameter. + * For the @ cases, we construct a dvec with length 1 to hold the value. + * In the other two cases, either the plot or the name can be "all", a + * wildcard. + * The vector name may have imbedded dots -- if the first component is a plot + * name, it is considered the plot, otherwise the current plot is used. + */ + +#define SPECCHAR '@' + +struct dvec * +vec_get(char *word) +{ + struct dvec *d, *end = NULL, *newv = NULL; + struct plot *pl; + char buf[BSIZE_SP], *s, *wd, *whole, *name = NULL, *param; + int i = 0; + struct variable *vv; + + wd = word = copy(word); /* Gets mangled below... */ + + if (index(word, '.')) { + /* Snag the plot... */ + for (i = 0, s = word; *s != '.'; i++, s++) + buf[i] = *s; + buf[i] = '\0'; + if (cieq(buf, "all")) { + word = ++s; + pl = NULL; /* NULL pl signifies a wildcard. */ + } else { + for (pl = plot_list; pl && !plot_prefix(buf, + pl->pl_typename); pl = pl->pl_next) + ; + if (pl) { + word = ++s; + } else { + /* This used to be an error... */ + pl = plot_cur; + } + } + } else + pl = plot_cur; + + if (pl) { + d = vec_fromplot(word, pl); + if (!d) + d = vec_fromplot(word, &constantplot); + } else { + for (pl = plot_list; pl; pl = pl->pl_next) { + if (cieq(pl->pl_typename, "const")) + continue; + d = vec_fromplot(word, pl); + if (d) { + if (end) + end->v_link2 = d; + else + newv = d; + for (end = d; end->v_link2; end = end->v_link2) + ; + } + } + d = newv; + if (!d) { + fprintf(cp_err, + "Error: plot wildcard (name %s) matches nothing\n", + word); + + /* MW. I don't want core leaks here */ + tfree(wd); + return (NULL); + } + } + + if (!d && (*word == SPECCHAR)) { + /* This is a special quantity... */ + if (ft_nutmeg) { + fprintf(cp_err, + "Error: circuit parameters only available with spice\n"); + + tfree(wd); /* MW. Memory leak fixed again */ + return (FALSE); + } + + whole=copy(word); + name = ++word; + for (param = name; *param && (*param != '['); param++) + ; + + if (*param) { + *param++ = '\0'; + for (s = param; *s && *s != ']'; s++) + ; + *s = '\0'; + } else + param = NULL; + + + if (ft_curckt) { + + vv = (*if_getparam)(ft_curckt->ci_ckt, &name, param, 0, 0); + if (!vv) { + tfree(whole); + tfree(wd); + return (NULL); + } + } else { + fprintf(cp_err, "Error: No circuit loaded.\n"); + tfree(whole); + tfree(wd); + return (NULL); + } + + d = alloc(struct dvec); + ZERO(d, struct dvec); + d->v_name = copy(whole); /* MW. The same as word before */ + d->v_type = SV_NOTYPE; + d->v_flags |= VF_REAL; /* No complex values yet... */ + d->v_realdata = (double *) tmalloc(sizeof (double)); + d->v_length = 1; + *d->v_realdata = vv->va_real; + + tfree(wd); + vec_new(d); + tfree(whole); + tfree(wd); + return (d); + } + + tfree(wd); + return (sortvecs(d)); +} + +/* Find a named vector in a plot. We are careful to copy the vector + * if v_link2 is set, because otherwise we will get screwed up. + */ + +static struct dvec * +findvec(char *word, struct plot *pl) +{ + struct dvec *d, *newv = NULL, *end = NULL, *v; + char buf[BSIZE_SP]; + + if (pl == NULL) + return (NULL); + + if (cieq(word, "all")) { + for (d = pl->pl_dvecs; d; d = d->v_next) { + if (d->v_flags & VF_PERMANENT) { + if (d->v_link2) { + v = vec_copy(d); + vec_new(v); + } else + v = d; + if (end) + end->v_link2 = v; + else + newv = v; + end = v; + } + } + return (newv); + } + + for (d = pl->pl_dvecs; d; d = d->v_next) + if (cieq(word, d->v_name) && (d->v_flags & VF_PERMANENT)) + break; + if (!d) { + (void) sprintf(buf, "v(%s)", word); + for (d = pl->pl_dvecs; d; d = d->v_next) + if (cieq(buf, d->v_name) && (d->v_flags & VF_PERMANENT)) + break; + } + if (d && d->v_link2) { + d = vec_copy(d); + vec_new(d); + } + + return (d); +} + +/* Execute the commands for a plot. This is done whenever a plot becomes + * the current plot. + */ + +void +plot_docoms(wordlist *wl) +{ + bool inter; + + inter = cp_interactive; + cp_interactive = FALSE; + while (wl) { + (void) cp_evloop(wl->wl_word); + wl = wl->wl_next; + } + cp_resetcontrol(); + cp_interactive = inter; + return; +} + +/* Create a copy of a vector. */ + +struct dvec * +vec_copy(struct dvec *v) +{ + struct dvec *nv; + int i; + + if (!v) + return (NULL); + + nv = alloc(struct dvec); + nv->v_name = copy(v->v_name); + nv->v_type = v->v_type; + nv->v_flags = v->v_flags & ~VF_PERMANENT; + + if (isreal(v)) { + nv->v_realdata = (double *) tmalloc(sizeof (double) * + v->v_length); + bcopy((char *) v->v_realdata, (char *) nv->v_realdata, + sizeof (double) * v->v_length); + nv->v_compdata = NULL; + } else { + nv->v_realdata = NULL; + nv->v_compdata = (complex *) tmalloc(sizeof (complex) * + v->v_length); + bcopy((char *) v->v_compdata, (char *) nv->v_compdata, + sizeof (complex) * v->v_length); + } + + nv->v_minsignal = v->v_minsignal; + nv->v_maxsignal = v->v_maxsignal; + nv->v_gridtype = v->v_gridtype; + nv->v_plottype = v->v_plottype; + nv->v_length = v->v_length; + nv->v_rlength = 0; /*XXX???*/ + nv->v_outindex = 0; /*XXX???*/ + nv->v_linestyle = 0; /*XXX???*/ + nv->v_color = 0; /*XXX???*/ + nv->v_defcolor = v->v_defcolor; + nv->v_numdims = v->v_numdims; + for (i = 0; i < v->v_numdims; i++) + nv->v_dims[i] = v->v_dims[i]; + nv->v_plot = v->v_plot; + nv->v_next = NULL; + nv->v_link2 = NULL; + nv->v_scale = v->v_scale; + + return (nv); +} + +/* Create a new plot structure. This just fills in the typename and sets up + * the ccom struct. + */ + +struct plot * +plot_alloc(char *name) +{ + struct plot *pl = alloc(struct plot), *tp; + char *s; + char buf[BSIZE_SP]; + + ZERO(pl, struct plot); + if (!(s = ft_plotabbrev(name))) + s = "unknown"; + do { + (void) sprintf(buf, "%s%d", s, plot_num); + for (tp = plot_list; tp; tp = tp->pl_next) + if (cieq(tp->pl_typename, buf)) { + plot_num++; + break; + } + } while (tp); + pl->pl_typename = copy(buf); + cp_addkword(CT_PLOT, buf); + s = cp_kwswitch(CT_VECTOR, (char *) NULL); + cp_addkword(CT_VECTOR, "all"); + pl->pl_ccom = cp_kwswitch(CT_VECTOR, s); + return (pl); +} + +/* Stick a new vector in the proper place in the plot list. */ + +void +vec_new(struct dvec *d) +{ +#ifdef FTEDEBUG + if (ft_vecdb) + fprintf(cp_err, "new vector %s\n", d->v_name); +#endif + /* Note that this can't happen. */ + if (plot_cur == NULL) { + fprintf(cp_err, "vec_new: Internal Error: no cur plot\n"); + } + if ((d->v_flags & VF_PERMANENT) && (plot_cur->pl_scale == NULL)) + plot_cur->pl_scale = d; + if (!d->v_plot) + d->v_plot = plot_cur; + if (d->v_numdims < 1) { + d->v_numdims = 1; + d->v_dims[0] = d->v_length; + } + d->v_next = d->v_plot->pl_dvecs; + d->v_plot->pl_dvecs = d; + return; +} + +/* Because of the way that all vectors, including temporary vectors, + * are linked together under the current plot, they can often be + * left lying around. This gets rid of all vectors that don't have + * the permanent flag set. Also, for the remaining vectors, it + * clears the v_link2 pointer. + */ + +void +vec_gc(void) +{ + struct dvec *d, *nd; + struct plot *pl; + + for (pl = plot_list; pl; pl = pl->pl_next) + for (d = pl->pl_dvecs; d; d = nd) { + nd = d->v_next; + if (!(d->v_flags & VF_PERMANENT)) { + if (ft_vecdb) + fprintf(cp_err, + "vec_gc: throwing away %s.%s\n", + pl->pl_typename, d->v_name); + vec_free(d); + } + } + + for (pl = plot_list; pl; pl = pl->pl_next) + for (d = pl->pl_dvecs; d; d = d->v_next) + d->v_link2 = NULL; + + return; +} + +/* Free a dvector. This is sort of a pain because we also have to make sure + * that it has been unlinked from its plot structure. If the name of the + * vector is NULL, then we have already freed it so don't try again. (This + * situation can happen with user-defined functions.) Note that this depends + * on our having tfree set its argument to NULL. Note that if all the vectors + * in a plot are gone it stays around... + */ + +void +vec_free(struct dvec *v) +{ + struct plot *pl; + struct dvec *lv; + + if ((v == NULL) || (v->v_name == NULL)) + return; + pl = v->v_plot; + + /* Now we have to take this dvec out of the plot list. */ + if (pl == NULL) + fprintf(cp_err, "vec_free: Internal Error: plot ptr is 0\n"); + if (pl->pl_dvecs == v) + pl->pl_dvecs = v->v_next; + else { + for (lv = pl->pl_dvecs; lv->v_next; lv = lv->v_next) + if (lv->v_next == v) + break; + if (lv->v_next == NULL) + fprintf(cp_err, + "vec_free: Internal Error: %s not in plot\n", + v->v_name); + lv->v_next = v->v_next; + } + if (pl->pl_scale == v) { + if (pl->pl_dvecs) + pl->pl_scale = pl->pl_dvecs; /* Random one... */ + else + pl->pl_scale = NULL; + } + tfree(v->v_name); + if (isreal(v)) { + tfree(v->v_realdata); + } else { + tfree(v->v_compdata); + } + tfree(v); + return; +} + +/* This is something we do in a few places... Since vectors get copied a lot, + * we can't just compare pointers to tell if two vectors are 'really' the same. + */ + +bool +vec_eq(struct dvec *v1, struct dvec *v2) +{ + char *s1, *s2; + + if (v1->v_plot != v2->v_plot) + return (FALSE); + + s1 = vec_basename(v1); + s2 = vec_basename(v2); + + if (cieq(s1, s2)) + return (TRUE); + else + return (FALSE); +} + +/* Return the name of the vector with the plot prefix stripped off. This + * is no longer trivial since '.' doesn't always mean 'plot prefix'. + */ + +char * +vec_basename(struct dvec *v) +{ + char buf[BSIZE_SP], *t, *s; + int i; + + if (index(v->v_name, '.')) { + for (t = v->v_name, i = 0; *t; t++) + buf[i++] = *t; + buf[i] = '\0'; + if (cieq(v->v_plot->pl_typename, buf)) + (void) strcpy(buf, t + 1); + else + (void) strcpy(buf, v->v_name); + } else + (void) strcpy(buf, v->v_name); + + for (t = buf; *t; t++) + if (isupper(*t)) + *t = tolower(*t); + for (t = buf; isspace(*t); t++) + ; + s = t; + for (t = s; *t; t++) + ; + while ((t > s) && isspace(t[-1])) + *--t = '\0'; + return (copy(s)); +} + +/* Sort all the vectors in d, first by plot name and then by vector name. + * Do the right thing with numbers. + */ + +static struct dvec * +sortvecs(struct dvec *d) +{ + struct dvec **array, *t; + int i, j; + + for (t = d, i = 0; t; t = t->v_link2) + i++; + if (i < 2) + return (d); + array = (struct dvec **) tmalloc(i * sizeof (struct dvec *)); + for (t = d, i = 0; t; t = t->v_link2) + array[i++] = t; + + qsort((char *) array, i, sizeof (struct dvec *), veccmp); + + /* Now string everything back together... */ + for (j = 0; j < i - 1; j++) + array[j]->v_link2 = array[j + 1]; + array[j]->v_link2 = NULL; + d = array[0]; + tfree(array); + return (d); +} + +static int +veccmp(struct dvec **d1, struct dvec **d2) +{ + int i; + + if ((i = namecmp((*d1)->v_plot->pl_typename, + (*d2)->v_plot->pl_typename)) != 0) + return (i); + return (namecmp((*d1)->v_name, (*d2)->v_name)); +} + +/* If there are imbedded numeric strings, compare them numerically, not + * alphabetically. + */ + +static int +namecmp(char *s, char *t) +{ + int i, j; + + for (;;) { + while ((*s == *t) && !isdigit(*s) && *s) + s++, t++; + if (!*s) + return (0); + if ((*s != *t) && (!isdigit(*s) || !isdigit(*t))) + return (*s - *t); + + /* The beginning of a number... Grab the two numbers + * and then compare them... + */ + for (i = 0; isdigit(*s); s++) + i = i * 10 + *s - '0'; + for (j = 0; isdigit(*t); t++) + j = j * 10 + *t - '0'; + + if (i != j) + return (i - j); + } +} + + +/* Make a plot the current one. This gets called by cp_usrset() when one + * does a 'set curplot = name'. + */ + +void +plot_setcur(char *name) +{ + struct plot *pl; + + if (cieq(name, "new")) { + pl = plot_alloc("unknown"); + pl->pl_title = copy("Anonymous"); + pl->pl_name = copy("unknown"); + pl->pl_date = copy(datestring( )); + plot_new(pl); + plot_cur = pl; + return; + } + for (pl = plot_list; pl; pl = pl->pl_next) + if (plot_prefix(name, pl->pl_typename)) + break; + if (!pl) { + fprintf(cp_err, "Error: no such plot named %s\n", name); + return; + } + if (plot_cur) + plot_cur->pl_ccom = cp_kwswitch(CT_VECTOR, pl->pl_ccom); + plot_cur = pl; + return; +} + +/* Add a plot to the plot list. This is different from plot_add() in that + * all this does is update the list and the variable $plots. + */ + +void +plot_new(struct plot *pl) +{ + pl->pl_next = plot_list; + plot_list = pl; + + return; +} + +/* This routine takes a multi-dimensional vector, treats it as a + * group of 2-dimensional matrices and transposes each matrix. + * The data array is replaced with a new one that has the elements + * in the proper order. Otherwise the transposition is done in place. + */ + +void +vec_transpose(struct dvec *v) +{ + int dim0, dim1, nummatrices; + int i, j, k, joffset, koffset, blocksize; + double *newreal, *oldreal; + complex *newcomp, *oldcomp; + + if (v->v_numdims < 2 || v->v_length <= 1) + return; + + dim0 = v->v_dims[v->v_numdims-1]; + dim1 = v->v_dims[v->v_numdims-2]; + v->v_dims[v->v_numdims-1] = dim1; + v->v_dims[v->v_numdims-2] = dim0; + /* Assume length is a multiple of each dimension size. + * This may not be safe, in which case a test should be + * made that the length is the product of all the dimensions. + */ + blocksize = dim0*dim1; + nummatrices = v->v_length / blocksize; + + /* Note: + * olda[i,j] is at data[i*dim0+j] + * newa[j,i] is at data[j*dim1+i] + * where j is in [0, dim0-1] and i is in [0, dim1-1] + * Since contiguous data in the old array is scattered in the new array + * we can't use bcopy :(. There is probably a BLAS2 function for this + * though. The formulation below gathers scattered old data into + * consecutive new data. + */ + + if (isreal(v)) { + newreal = (double *) tmalloc(sizeof (double) * v->v_length); + oldreal = v->v_realdata; + koffset = 0; + for ( k=0; k < nummatrices; k++ ) { + joffset = 0; + for ( j=0; j < dim0; j++ ) { + for ( i=0; i < dim1; i++ ) { + newreal[ koffset + joffset + i ] = + oldreal[ koffset + i*dim0 + j ]; + } + joffset += dim1; /* joffset = j*dim0 */ + } + koffset += blocksize; /* koffset = k*blocksize = k*dim0*dim1 */ + } + tfree(oldreal); + v->v_realdata = newreal; + } else { + newcomp = (complex *) tmalloc(sizeof (complex) * v->v_length); + oldcomp = v->v_compdata; + koffset = 0; + for ( k=0; k < nummatrices; k++ ) { + joffset = 0; + for ( j=0; j < dim0; j++ ) { + for ( i=0; i < dim1; i++ ) { + realpart(&newcomp[ koffset + joffset + i ]) = + realpart(&oldcomp[ koffset + i*dim0 + j ]); + imagpart(&newcomp[ koffset + joffset + i ]) = + imagpart(&oldcomp[ koffset + i*dim0 + j ]); + } + joffset += dim1; /* joffset = j*dim0 */ + } + koffset += blocksize; /* koffset = k*blocksize = k*dim0*dim1 */ + } + tfree(oldcomp); + v->v_compdata = newcomp; + } +} + +/* This routine takes a multi-dimensional vector and turns it into a family + * of 1-d vectors, linked together with v_link2. It is here so that plot + * can do intelligent things. + */ + +struct dvec * +vec_mkfamily(struct dvec *v) +{ + int size, numvecs, i, j, count[MAXDIMS]; + int totalsize; + struct dvec *vecs, *d; + char buf[BSIZE_SP]; + + if (v->v_numdims < 2) + return (v); + + size = v->v_dims[v->v_numdims - 1]; + for (i = 0, numvecs = 1; i < v->v_numdims - 1; i++) + numvecs *= v->v_dims[i]; + for (i = 0, vecs = d = NULL; i < numvecs; i++) { + if (vecs) { + d = d->v_link2 = alloc(struct dvec); + ZERO(d, struct dvec); + } else { + d = vecs = alloc(struct dvec); + ZERO(d, struct dvec); + } + } + for (i = 0; i < MAXDIMS; i++) + count[i] = 0; + for (d = vecs, j = 0; d; j++, d = d->v_link2) { + (void) sprintf(buf, "%s%s", v->v_name, + indexstring(count, v->v_numdims - 1)); + d->v_name = copy(buf); + d->v_type = v->v_type; + d->v_flags = v->v_flags; + d->v_minsignal = v->v_minsignal; + d->v_maxsignal = v->v_maxsignal; + d->v_gridtype = v->v_gridtype; + d->v_plottype = v->v_plottype; + d->v_scale = v->v_scale; + /* Don't copy the default color, since there will be many + * of these things... + */ + d->v_numdims = 1; + d->v_length = size; + + if (isreal(v)) { + totalsize = sizeof (double) * size; + d->v_realdata = (double *) tmalloc(totalsize); + bcopy((char *) v->v_realdata + totalsize * j, + (char *) d->v_realdata, totalsize); + } else { + totalsize = sizeof (complex) * size; + d->v_realdata = (double *) tmalloc(totalsize); + bcopy((char *) v->v_compdata + totalsize * j, + (char *) d->v_compdata, totalsize); + } + /* Add one to the counter. */ + (void) incindex(count, v->v_numdims - 1, v->v_dims, v->v_numdims); + } + + for (d = vecs; d; d = d->v_link2) + vec_new(d); + + return (vecs); +} + +/* This function will match "op" with "op1", but not "op1" with "op12". */ + +bool +plot_prefix(char *pre, char *str) +{ + if (!*pre) + return (TRUE); + while (*pre && *str) { + if (*pre != *str) + break; + pre++; str++; + } + if (*pre || (*str && isdigit(pre[-1]))) + return (FALSE); + else + return (TRUE); +} + diff --git a/src/frontend/vectors.h b/src/frontend/vectors.h new file mode 100644 index 000000000..5a8207ef1 --- /dev/null +++ b/src/frontend/vectors.h @@ -0,0 +1,29 @@ +/************* + * Header file for vectors.c + * 1999 E. Rouat + ************/ + +#ifndef VECTORS_H_INCLUDED +#define VECTORS_H_INCLUDED + +void ft_loadfile(char *file); +void plot_add(struct plot *pl); +void vec_remove(char *name); +struct dvec * vec_fromplot(char *word, struct plot *plot); +struct dvec * vec_get(char *word); +void plot_docoms(wordlist *wl); +struct dvec * vec_copy(struct dvec *v); +struct plot * plot_alloc(char *name); +void vec_new(struct dvec *d); +void vec_gc(void); +void vec_free(struct dvec *v); +bool vec_eq(struct dvec *v1, struct dvec *v2); +char * vec_basename(struct dvec *v); +void plot_setcur(char *name); +void plot_new(struct plot *pl); +void vec_transpose(struct dvec *v); +struct dvec * vec_mkfamily(struct dvec *v); +bool plot_prefix(char *pre, char *str); + + +#endif diff --git a/src/frontend/where.c b/src/frontend/where.c new file mode 100644 index 000000000..b8d27ab23 --- /dev/null +++ b/src/frontend/where.c @@ -0,0 +1,26 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftehelp.h" +#include "hlpdefs.h" +#include "where.h" + + +void +com_where(void) +{ + char *msg; + + if (ft_curckt) { + msg = (*ft_sim->nonconvErr)((void *) (ft_curckt->ci_ckt), 0); + fprintf(cp_out, "%s", msg); + } else { + fprintf(cp_err, "Error: no circuit loaded.\n"); + } +} diff --git a/src/frontend/where.h b/src/frontend/where.h new file mode 100644 index 000000000..b26a52e37 --- /dev/null +++ b/src/frontend/where.h @@ -0,0 +1,12 @@ +/************* + * Header file for where.c + * 1999 E. Rouat + ************/ + +#ifndef WHERE_H_INCLUDED +#define WHERE_H_INCLUDED + +void com_where(void); + + +#endif diff --git a/src/frontend/x11.c b/src/frontend/x11.c new file mode 100644 index 000000000..9753dea85 --- /dev/null +++ b/src/frontend/x11.c @@ -0,0 +1,1090 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jeffrey M. Hsu +**********/ + +/* + X11 drivers. +*/ + + +#include "ngspice.h" + +#ifndef X_DISPLAY_MISSING + +# include +# include /* PN */ +# include /* PN */ + + +# include "ftegraph.h" +# include "ftedbgra.h" +# include "ftedev.h" +# include "fteinput.h" +# include "cpdefs.h" +# include "ftedefs.h" + +/* Added X11/ prefix to the next includes - ER */ + +# include +# include +# include +# include +# include +# include +# include +# include +# include + +#include "x11.h" + +static void linear_arc(int x0, int y0, int radius, double theta1, double theta2); + + +# ifdef DEBUG +extern int _Xdebug; +# endif + + +#define RAD_TO_DEG (180.0 / M_PI) + +/* X dependent default parameters */ +#define DEF_FONT "10x14" +#define NUMLINESTYLES 8 +#define MW_LINEWIDTH 2 /* MW. I want larger lines */ +#define NXPLANES 5 /* note: What is this used for? */ +#define BOXSIZE 30 /* initial size of bounding box for zoomin */ + +typedef struct x11info { + Window window; + int isopen; + Widget shell, form, view, buttonbox, buttons[2]; + XFontStruct *font; + GC gc; + int lastx, lasty; /* used in X_DrawLine */ + int lastlinestyle; /* used in X_DrawLine */ +} X11devdep; + +#define DEVDEP(g) (*((X11devdep *) (g)->devdep)) + +static void linear_arc(int x0, int y0, int radius, double theta1, double theta2); +static Display *display; +static GC xorgc; +static char *xlinestyles[NUMLINESTYLES] = { /* test patterns XXX */ + "\001\001\001\001", /* solid */ + "\001\002\001\002", /* dots */ + "\007\007\007\007", /* longdash */ + "\003\003\003\003", /* shortdash */ + "\007\002\002\002", /* dots longdash */ + "\003\002\001\002", /* dots shortdash */ + "\003\003\007\003", /* short/longdash */ +}; + +static Widget toplevel; +static Bool noclear = False; +static GRAPH *lasthardcopy; /* graph user selected */ +static int X11_Open = 0; +static int numdispplanes; + + +extern void internalerror (char *message); +extern void externalerror (char *message); +void initlinestyles (void); +void initcolors (GRAPH *graph); +extern void PushGraphContext (GRAPH *graph); +extern void SetColor (int colorid); +extern void Text (char *text, int x, int y); +extern void SaveText (GRAPH *graph, char *text, int x, int y); +extern void PopGraphContext (void); +void slopelocation (GRAPH *graph, int x0, int y0); +void zoomin (GRAPH *graph); +void X_ScreentoData (GRAPH *graph, int x, int y, double *fx, double *fy); +extern int DestroyGraph (int id); +extern void gr_redraw (GRAPH *graph); +extern void gr_resize (GRAPH *graph); + +int +X11_Init(void) +{ + + char buf[512]; + char *displayname; + + XGCValues gcvalues; + + /* grrr, Xtk forced contortions */ + char *argv[2]; + int argc = 2; + + if (cp_getvar("display", VT_STRING, buf)) { + displayname = buf; + } else if (!(displayname = getenv("DISPLAY"))) { + internalerror("Can't open X display."); + return (1); + } + +# ifdef DEBUG + _Xdebug = 1; +# endif + + argv[0] = "ngspice"; + argv[1] = displayname; +/* + argv[2] = "-geometry"; + argv[3] = "=1x1+2+2"; +*/ + + /* initialize X toolkit */ + toplevel = XtInitialize("ngspice", "Nutmeg", NULL, 0, &argc, argv); + + display = XtDisplay(toplevel); + + X11_Open = 1; + + /* "invert" works better than "xor" for B&W */ + + /* xor gc should be a function of the pixels that are written on */ + gcvalues.function = GXxor; + gcvalues.line_width = 1; + gcvalues.foreground = 1; + gcvalues.background = 0; + + xorgc = XCreateGC(display, DefaultRootWindow(display), + GCLineWidth | GCFunction | GCForeground | GCBackground, + &gcvalues); + + /* set correct information */ + dispdev->numlinestyles = NUMLINESTYLES; + dispdev->numcolors = NUMCOLORS; + + dispdev->width = DisplayWidth(display, DefaultScreen(display)); + dispdev->height = DisplayHeight(display, DefaultScreen(display)); + + /* we don't want non-fatal X errors to call exit */ + XSetErrorHandler(errorhandler); + + numdispplanes = DisplayPlanes(display, DefaultScreen(display)); + + return (0); + +} + +void +errorhandler(Display *display, XErrorEvent *errorev) +{ + XGetErrorText(display, errorev->error_code, ErrorMessage, 1024); + externalerror(ErrorMessage); +} + +/* Recover from bad NewViewPort call. */ +#define RECOVERNEWVIEWPORT() free((char *) graph);\ + graph = (GRAPH *) NULL; + /* need to do this or else DestroyGraph will free it again */ + +/* NewViewport is responsible for filling in graph->viewport */ +int +X11_NewViewport(GRAPH *graph) +{ + + char fontname[513]; /* who knows . . . */ + char *p, *q; + Cursor cursor; + XSetWindowAttributes w_attrs; + XGCValues gcvalues; + static Arg formargs[ ] = { + { XtNleft, (XtArgVal) XtChainLeft }, + { XtNresizable, (XtArgVal) TRUE } + }; + static Arg bboxargs[ ] = { + { XtNfromHoriz, (XtArgVal) NULL }, + { XtNbottom, (XtArgVal) XtChainTop }, + { XtNtop, (XtArgVal) XtChainTop }, + { XtNleft, (XtArgVal) XtChainRight }, + { XtNright, (XtArgVal) XtChainRight } + }; + static Arg buttonargs[ ] = { + { XtNlabel, (XtArgVal) NULL }, + { XtNfromVert, (XtArgVal) NULL }, + { XtNbottom, (XtArgVal) XtChainTop }, + { XtNtop, (XtArgVal) XtChainTop }, + { XtNleft, (XtArgVal) XtRubber }, + { XtNright, (XtArgVal) XtRubber }, + { XtNresizable, (XtArgVal) TRUE } + }; + static Arg viewargs[] = { + { XtNresizable, (XtArgVal) TRUE }, + { XtNwidth, (XtArgVal) 300 }, + { XtNheight, (XtArgVal) 300 }, + { XtNright, (XtArgVal) XtChainRight } + }; + int trys; + + graph->devdep = calloc(1, sizeof(X11devdep)); + + /* set up new shell */ + DEVDEP(graph).shell = XtCreateApplicationShell("shell", + topLevelShellWidgetClass, NULL, 0); + + /* set up form widget */ + DEVDEP(graph).form = XtCreateManagedWidget("form", + formWidgetClass, DEVDEP(graph).shell, formargs, XtNumber(formargs)); + + /* set up viewport */ + DEVDEP(graph).view = XtCreateManagedWidget("viewport", widgetClass, + DEVDEP(graph).form, viewargs, XtNumber(viewargs)); + XtAddEventHandler(DEVDEP(graph).view, ButtonPressMask, FALSE, + handlebuttonev, graph); + XtAddEventHandler(DEVDEP(graph).view, KeyPressMask, FALSE, + handlekeypressed, graph); + XtAddEventHandler(DEVDEP(graph).view, StructureNotifyMask, FALSE, + resize, graph); + XtAddEventHandler(DEVDEP(graph).view, ExposureMask, FALSE, + redraw, graph); + + /* set up button box */ + XtSetArg(bboxargs[1], XtNfromHoriz, DEVDEP(graph).view); + DEVDEP(graph).buttonbox = XtCreateManagedWidget("buttonbox", + boxWidgetClass, DEVDEP(graph).form, bboxargs, XtNumber(bboxargs)); + + /* set up buttons */ + XtSetArg(buttonargs[0], XtNlabel, "quit"); + XtSetArg(bboxargs[1], XtNfromVert, NULL); + DEVDEP(graph).buttons[0] = XtCreateManagedWidget("quit", + commandWidgetClass, DEVDEP(graph).buttonbox, + buttonargs, 1); + XtAddCallback(DEVDEP(graph).buttons[0], XtNcallback, killwin, graph); + + XtSetArg(buttonargs[0], XtNlabel, "hardcopy"); + XtSetArg(bboxargs[1], XtNfromVert, DEVDEP(graph).buttons[0]); + DEVDEP(graph).buttons[1] = XtCreateManagedWidget("hardcopy", + commandWidgetClass, DEVDEP(graph).buttonbox, + buttonargs, 1); + XtAddCallback(DEVDEP(graph).buttons[1], XtNcallback, hardcopy, graph); + + /* set up fonts */ + if (!cp_getvar("font", VT_STRING, fontname)) { + (void) strcpy(fontname, DEF_FONT); + } + + for (p = fontname; *p && *p <= ' '; p++) + ; + if (p != fontname) { + for (q = fontname; *p; *q++ = *p++) + ; + *q = 0; + } + + trys = 1; + while (!(DEVDEP(graph).font = XLoadQueryFont(display, fontname))) { + sprintf(ErrorMessage, "can't open font %s", fontname); + strcpy(fontname, "fixed"); + if (trys > 1) { + internalerror(ErrorMessage); + RECOVERNEWVIEWPORT(); + return(1); + } + trys += 1; + } + + graph->fontwidth = DEVDEP(graph).font->max_bounds.rbearing - + DEVDEP(graph).font->min_bounds.lbearing + 1; + graph->fontheight = DEVDEP(graph).font->max_bounds.ascent + + DEVDEP(graph).font->max_bounds.descent + 1; + + XtRealizeWidget(DEVDEP(graph).shell); + + DEVDEP(graph).window = XtWindow(DEVDEP(graph).view); + DEVDEP(graph).isopen = 0; + w_attrs.bit_gravity = ForgetGravity; + XChangeWindowAttributes(display, DEVDEP(graph).window, CWBitGravity, + &w_attrs); + /* have to note font and set mask GCFont in XCreateGC, p.w.h. */ + gcvalues.font = DEVDEP(graph).font->fid; + gcvalues.line_width = MW_LINEWIDTH; + gcvalues.cap_style = CapNotLast; + gcvalues.function = GXcopy; + DEVDEP(graph).gc = XCreateGC(display, DEVDEP(graph).window, + GCFont | GCLineWidth | GCCapStyle | GCFunction, &gcvalues); + + /* should absolute.positions really be shell.pos? */ + graph->absolute.xpos = DEVDEP(graph).view->core.x; + graph->absolute.ypos = DEVDEP(graph).view->core.y; + graph->absolute.width = DEVDEP(graph).view->core.width; + graph->absolute.height = DEVDEP(graph).view->core.height; + + initlinestyles(); + initcolors(graph); + + /* set up cursor */ + cursor = XCreateFontCursor(display, XC_left_ptr); + XDefineCursor(display, DEVDEP(graph).window, cursor); + + return (0); +} + +static void +initlinestyles(void) +{ + + int i; + + if (numdispplanes > 1) { + /* Dotted lines are a distraction when we have colors. */ + for (i = 2; i < NUMLINESTYLES; i++) { + xlinestyles[i] = xlinestyles[0]; + } + } + +} + +static void +initcolors(GRAPH *graph) +{ + int i; + static char *colornames[] = { "black", /* white */ + "white", "red", "blue", + "orange", "green", "pink", + "brown", "khaki", "plum", + "orchid", "violet", "maroon", + "turquoise", "sienna", "coral", + "cyan", "magenta", "gold", + "yellow", "" + }; + + XColor visualcolor, exactcolor; + char buf[BSIZE_SP], colorstring[BSIZE_SP]; + int xmaxcolors = NUMCOLORS; /* note: can we get rid of this? */ + + if (numdispplanes == 1) { + /* black and white */ + xmaxcolors = 2; + graph->colors[0] = DEVDEP(graph).view->core.background_pixel; + if (graph->colors[0] == WhitePixel(display, DefaultScreen(display))) + graph->colors[1] = BlackPixel(display, DefaultScreen(display)); + else + graph->colors[1] = WhitePixel(display, DefaultScreen(display)); + + } else { + if (numdispplanes < NXPLANES) + xmaxcolors = 1 << numdispplanes; + + for (i = 0; i < xmaxcolors; i++) { + (void) sprintf(buf, "color%d", i); + if (!cp_getvar(buf, VT_STRING, colorstring)) + (void) strcpy(colorstring, colornames[i]); + if (!XAllocNamedColor(display, + DefaultColormap(display, DefaultScreen(display)), + colorstring, &visualcolor, &exactcolor)) { + (void) sprintf(ErrorMessage, + "can't get color %s\n", colorstring); + externalerror(ErrorMessage); + graph->colors[i] = i ? BlackPixel(display, + DefaultScreen(display)) + : WhitePixel(display, DefaultScreen(display)); + continue; + } + graph->colors[i] = visualcolor.pixel; + + + /* MW. I don't need this, everyone must know what he is doing + if (i > 0 && + graph->colors[i] == DEVDEP(graph).view->core.background_pixel) { + graph->colors[i] = graph->colors[0]; + } */ + + } + /* MW. Set Beackgroound here */ + XSetWindowBackground(display, DEVDEP(graph).window, graph->colors[0]); + +/* if (graph->colors[0] != DEVDEP(graph).view->core.background_pixel) { + graph->colors[0] = DEVDEP(graph).view->core.background_pixel; + } */ + } + + for (i = xmaxcolors; i < NUMCOLORS; i++) { + graph->colors[i] = graph->colors[i + 1 - xmaxcolors]; + } +} + +/* This routine closes the X connection. + It is not to be called for finishing a graph. */ +void +X11_Close(void) +{ + XCloseDisplay(display); +} + +void +X11_DrawLine(int x1, int y1, int x2, int y2) +{ + + if (DEVDEP(currentgraph).isopen) + XDrawLine(display, DEVDEP(currentgraph).window, + DEVDEP(currentgraph).gc, + x1, currentgraph->absolute.height - y1, + x2, currentgraph->absolute.height - y2); + + +} + + +void +X11_Arc(int x0, int y0, int radius, double theta1, double theta2) +{ + + int t1, t2; + + if (!cp_getvar("x11lineararcs", VT_BOOL, (char *) &t1)) { + linear_arc(x0, y0, radius, theta1, theta2); + } + + if (DEVDEP(currentgraph).isopen) { + if (theta1 >= theta2) + theta2 = 2 * M_PI + theta2; + t1 = 64 * (180.0 / M_PI) * theta1; + t2 = 64 * (180.0 / M_PI) * theta2 - t1; + if (t2 == 0) + return; + XDrawArc(display, DEVDEP(currentgraph).window, DEVDEP(currentgraph).gc, + x0 - radius, + currentgraph->absolute.height - radius - y0, + 2 * radius, 2 * radius, t1, t2); +# ifdef notdef + printf("at %d, %d, %g %g x %d :: (%d, %d)\n", + x0, y0, theta1, theta2, radius, t1, t2); + printf("skip\n"); + XSync(display, 0); + printf("XDrawArc(%d, %d, %d, %d, %d, %d)\n", x0 - radius, + currentgraph->absolute.height - radius - y0, + 2 * radius, 2 * radius, t1, t2); +# endif + } +} + +/* note: x and y are the LOWER left corner of text */ +void +X11_Text(char *text, int x, int y) +{ + +/* We specify text position by lower left corner, so have to adjust for + X11's font nonsense. */ + + if (DEVDEP(currentgraph).isopen) + XDrawString(display, DEVDEP(currentgraph).window, + DEVDEP(currentgraph).gc, x, + currentgraph->absolute.height + - (y + DEVDEP(currentgraph).font->max_bounds.descent), + text, strlen(text)); + + /* note: unlike before, we do not save any text here */ + +} + + +int +X11_DefineColor(int colorid, double red, double green, double blue) +{ + internalerror("X11_DefineColor not implemented."); + return(0); +} + + +void +X11_DefineLinestyle(int linestyleid, int mask) +{ + internalerror("X11_DefineLinestyle not implemented."); +} + +void +X11_SetLinestyle(int linestyleid) +{ + XGCValues values; + + if (currentgraph->linestyle != linestyleid) { + +# ifdef notdef + switch (linestyleid %3) { + case 0: + values.line_style = LineSolid; + break; + case 1: + values.line_style = LineOnOffDash; + break; + case 2: + values.line_style = LineDoubleDash; + break; + } +# endif + if ((linestyleid == 0 || numdispplanes > 1) && linestyleid != 1) { + /* solid if linestyle 0 or if has color, allow only one + * dashed linestyle */ + values.line_style = LineSolid; + } else { + values.line_style = LineOnOffDash; + } + XChangeGC(display, DEVDEP(currentgraph).gc, GCLineStyle, &values); + + currentgraph->linestyle = linestyleid; + XSetDashes(display, DEVDEP(currentgraph).gc, 0, + xlinestyles[linestyleid], 4); + } +} + +void +X11_SetColor(int colorid) +{ + + currentgraph->currentcolor = colorid; + XSetForeground(display, DEVDEP(currentgraph).gc, + currentgraph->colors[colorid]); + +} + +void +X11_Update(void) +{ + + if (X11_Open) + XSync(display, 0); + +} + +void +X11_Clear(void) +{ + + if (!noclear) /* hack so exposures look like they're handled nicely */ + XClearWindow(display, DEVDEP(currentgraph).window); + +} + +void +handlekeypressed(Widget w, caddr_t clientdata, caddr_t calldata) +{ + + XKeyEvent *keyev = (XKeyPressedEvent *) calldata; + GRAPH *graph = (GRAPH *) clientdata; + char text[4]; + int nbytes; + + nbytes = XLookupString(keyev, text, 4, NULL, NULL); + if (!nbytes) return; + /* write it */ + PushGraphContext(graph); + text[nbytes] = '\0'; + SetColor(1); + Text(text, keyev->x, graph->absolute.height - keyev->y); + /* save it */ + SaveText(graph, text, keyev->x, graph->absolute.height - keyev->y); + /* warp mouse so user can type in sequence */ + XWarpPointer(display, None, DEVDEP(graph).window, 0, 0, 0, 0, + keyev->x + XTextWidth(DEVDEP(graph).font, text, nbytes), + keyev->y); + PopGraphContext(); + +} + +# ifdef notdef +void +keyhandler(clientdata, source, id) +caddr_t clientdata; +int *source; +XtInputId id; +{ + +# ifdef notdef + KEYwaiting = TRUE; +# endif + +} +# endif + +void +handlebuttonev(Widget w, caddr_t clientdata, caddr_t calldata) +{ + + XButtonEvent *buttonev = (XButtonEvent *) calldata; + + switch (buttonev->button) { + case Button1: + slopelocation((GRAPH *) clientdata, buttonev->x, buttonev->y); + break; + case Button3: + zoomin((GRAPH *) clientdata); + break; + } + +} + +# ifdef notdef +handlemotionev(w, clientdata, calldata) +Widget w; +caddr_t clientdata, calldata; +{ + + XMotionEvent *motionev = (XMotionEvent *) calldata; + + switch +} +# endif + +void +slopelocation(GRAPH *graph, int x0, int y0) + + /* initial position of mouse */ +{ + + int x1, y1; + int x, y; + Window rootwindow, childwindow; + int rootx, rooty; + unsigned int state; + double fx0, fx1, fy0, fy1; + double angle; + + x1 = x0; + y1 = y0; + XQueryPointer(display, DEVDEP(graph).window, &rootwindow, &childwindow, + &rootx, &rooty, &x, &y, &state); + XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y0, x0, y1-1); + XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y1, x1, y1); + while (state & Button1Mask) { + if (x != x1 || y != y1) { + XDrawLine(display, DEVDEP(graph).window, xorgc, + x0, y0, x0, y1-1); + XDrawLine(display, DEVDEP(graph).window, xorgc, + x0, y1, x1, y1); + x1 = x; + y1 = y; + XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y0, x0, y1-1); + XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y1, x1, y1); + } + XQueryPointer(display, DEVDEP(graph).window, &rootwindow, + &childwindow, &rootx, &rooty, &x, &y, &state); + } + XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y0, x0, y1-1); + XDrawLine(display, DEVDEP(graph).window, xorgc, x0, y1, x1, y1); + + X_ScreentoData(graph, x0, y0, &fx0, &fy0); + X_ScreentoData(graph, x1, y1, &fx1, &fy1); + + /* print it out */ + if (x1 == x0 && y1 == y0) { /* only one location */ + fprintf(stdout, "\nx0 = %g, y0 = %g\n", fx0, fy0); + if (graph->grid.gridtype == GRID_POLAR + || graph->grid.gridtype == GRID_SMITH + || graph->grid.gridtype == GRID_SMITHGRID) + { + angle = RAD_TO_DEG * atan2( fy0, fx0 ); + fprintf(stdout, "r0 = %g, a0 = %g\n", + sqrt( fx0*fx0 + fy0*fy0 ), + (angle>0)?angle:(double) 360+angle); + } + + + } else { /* need to print info about two points */ + fprintf(stdout, "\nx0 = %g, y0 = %g x1 = %g, y1 = %g\n", + fx0, fy0, fx1, fy1); + fprintf(stdout, "dx = %g, dy = %g\n", fx1-fx0, fy1 - fy0); + if (x1 != x0 && y1 != y0) { + /* add slope info if both dx and dy are zero, + because otherwise either dy/dx or dx/dy is zero, + which is uninteresting + */ + fprintf(stdout, "dy/dx = %g dx/dy = %g\n", + (fy1-fy0)/(fx1-fx0), (fx1-fx0)/(fy1-fy0)); + } + } + + return; + +} + +/* should be able to do this by sleight of hand on graph parameters */ +void +zoomin(GRAPH *graph) +{ +/* note: need to add circular boxes XXX */ + + int x0, y0, x1, y1; + double fx0, fx1, fy0, fy1, ftemp; + char buf[BSIZE_SP]; + char buf2[128]; + char *t; + wordlist *wl; + int dummy; + + Window rootwindow, childwindow; + int rootx, rooty; + unsigned int state; + int x, y, upperx, uppery, lowerx, lowery; + + /* open box and get area to zoom in on */ + + XQueryPointer(display, DEVDEP(graph).window, &rootwindow, + &childwindow, &rootx, &rooty, &x0, &y0, &state); + + x = lowerx = x1 = x0 + BOXSIZE; + y = lowery = y1 = y0 + BOXSIZE; + upperx = x0; + uppery = y0; + + XDrawRectangle(display, DEVDEP(graph).window, xorgc, + upperx, uppery, lowerx - upperx, lowery - uppery); + +/* note: what are src_x, src_y, src_width, and src_height for? XXX */ + XWarpPointer(display, None, DEVDEP(graph).window, 0, 0, 0, 0, x1, y1); + + while (state & Button3Mask) { + if (x != x1 || y != y1) { + XDrawRectangle(display, DEVDEP(graph).window, xorgc, + upperx, uppery, lowerx - upperx, lowery - uppery); + x1 = x; + y1 = y; + /* figure out upper left corner */ + /* remember X11's (and X10's) demented coordinate system */ + if (y0 < y1) { + uppery = y0; + upperx = x0; + lowery = y1; + lowerx = x1; + } else { + uppery = y1; + upperx = x1; + lowery = y0; + lowerx = x0; + } + XDrawRectangle(display, DEVDEP(graph).window, xorgc, + upperx, uppery, lowerx - upperx, lowery - uppery); + } + XQueryPointer(display, DEVDEP(graph).window, &rootwindow, + &childwindow, &rootx, &rooty, &x, &y, &state); + } + XDrawRectangle(display, DEVDEP(graph).window, xorgc, + upperx, uppery, lowerx - upperx, lowery - uppery); + + X_ScreentoData(graph, x0, y0, &fx0, &fy0); + X_ScreentoData(graph, x1, y1, &fx1, &fy1); + + if (fx0 > fx1) { + ftemp = fx0; + fx0 = fx1; + fx1 = ftemp; + } + if (fy0 > fy1) { + ftemp = fy0; + fy0 = fy1; + fy1 = ftemp; + } + + strncpy(buf2, graph->plotname, sizeof(buf2)); + if ((t =strchr(buf2, ':'))) + *t = 0; + + if (!eq(plot_cur->pl_typename, buf2)) { + (void) sprintf(buf, +"setplot %s; %s xlimit %.20e %.20e ylimit %.20e %.20e; setplot $curplot\n", + buf2, graph->commandline, fx0, fx1, fy0, fy1); + } else { + (void) sprintf(buf, "%s xlimit %e %e ylimit %e %e\n", + graph->commandline, fx0, fx1, fy0, fy1); + } + + /* hack for Gordon Jacobs */ + /* add to history list if plothistory is set */ + if (cp_getvar("plothistory", VT_BOOL, (char *) &dummy)) { + wl = cp_parse(buf); + (void) cp_addhistent(cp_event++, wl); + } + + (void) cp_evloop(buf); + +} + +void +hardcopy(Widget w, caddr_t client_data, caddr_t call_data) +{ + + lasthardcopy = (GRAPH *) client_data; + com_hardcopy(NULL); + +} + +void +killwin(Widget w, caddr_t client_data, caddr_t call_data) +{ + + GRAPH *graph = (GRAPH *) client_data; + + /* Iplots are done asynchronously */ + DEVDEP(graph).isopen = 0; + DestroyGraph(graph->graphid); + XtDestroyWidget(DEVDEP(graph).shell); + +} + +/* call higher gr_redraw routine */ +void +redraw(Widget w, caddr_t client_data, caddr_t call_data) +{ + + GRAPH *graph = (GRAPH *) client_data; + XExposeEvent *pev = (XExposeEvent *) call_data; + XEvent ev; + XRectangle rects[30]; + int n = 1; + + DEVDEP(graph).isopen = 1; +# ifdef notdef + /* if there is a resize, let the resize routine handle the exposures */ + if (XCheckWindowEvent(display, DEVDEP(graph).window, + (long) StructureNotifyMask, &ev)) { + resize(w, client_data, &ev); + return; + } +# endif + + rects[0].x = pev->x; + rects[0].y = pev->y; + rects[0].width = pev->width; + rects[0].height = pev->height; + + /* XXX */ + /* pull out all other expose regions that need to be redrawn */ + while (n < 30 && XCheckWindowEvent(display, DEVDEP(graph).window, + (long) ExposureMask, &ev)) { + pev = (XExposeEvent *) &ev; + rects[n].x = pev->x; + rects[n].y = pev->y; + rects[n].width = pev->width; + rects[n].height = pev->height; + n++; + } + XSetClipRectangles(display, DEVDEP(graph).gc, 0, 0, + rects, n, Unsorted); + + noclear = True; + gr_redraw(graph); + noclear = False; + + XSetClipMask(display, DEVDEP(graph).gc, None); + +} + +void +resize(Widget w, caddr_t client_data, caddr_t call_data) +{ + + GRAPH *graph = (GRAPH *) client_data; + XEvent ev; + + /* pull out all other exposure events + Also, get rid of other StructureNotify events on this window. */ + + while (XCheckWindowEvent(display, DEVDEP(graph).window, + (long) /* ExposureMask | */ StructureNotifyMask, &ev)) + ; + + XClearWindow(display, DEVDEP(graph).window); + graph->absolute.width = w->core.width; + graph->absolute.height = w->core.height; + gr_resize(graph); + +} + +# ifdef notdef +/* stolen from CP/lexical.c */ + +/* A special 'getc' so that we can deal with ^D properly. There is no way for + * stdio to know if we have typed a ^D after some other characters, so + * don't use buffering at all... + */ +static int inchar(fp) + FILE *fp; +{ + + char c; + int i; + extern int errno; + +# ifdef HAS_TERMREAD + if (cp_interactive && !cp_nocc) { + i = read((int) fileno(fp), &c, 1); + if (i == 0) + return (EOF); + else if (i == -1) { + perror("read"); + return (EOF); + } else + return ((int) c); + } +# endif + c = getc(fp); + return ((int) c); +} +# endif + +void +X11_Input(REQUEST *request, RESPONSE *response) +{ + + XEvent ev; + int nfds, readfds; + + switch (request->option) { + case char_option: + + nfds = ConnectionNumber(display) > fileno(request->fp) ? + ConnectionNumber(display) : + fileno(request->fp); + + while (1) { + + /* first read off the queue before doing the select */ + while (XtPending()) { + XtNextEvent(&ev); + XtDispatchEvent(&ev); + } + + readfds = 1 << fileno(request->fp) | + 1 << ConnectionNumber(display); + + /* block on ConnectionNumber and request->fp */ + /* PN: added fd_set * casting */ + select(nfds + 1, (fd_set *)&readfds, (fd_set *) NULL, (fd_set *) NULL, NULL); + + /* handle X events first */ + if (readfds & (1 << ConnectionNumber(display))) { + /* handle ALL X events */ + while (XtPending()) { + XtNextEvent(&ev); + XtDispatchEvent(&ev); + } + } + + if (readfds & (1 << fileno(request->fp))) { + response->reply.ch = inchar(request->fp); + goto out; + } + + } + break; + + case click_option: + /* let's fake this */ + response->reply.graph = lasthardcopy; + break; + + case button_option: + /* sit and handle events until get a button selection */ + internalerror("button_option not implemented"); + response->option = error_option; + return; + break; + + case checkup_option: + /* first read off the queue before doing the select */ + while (XtPending()) { + XtNextEvent(&ev); + XtDispatchEvent(&ev); + } + break; + + default: + internalerror("unrecognized input type"); + response->option = error_option; + return; + break; + } + +out: + if (response) + response->option = request->option; + return; + +} + +static +void +X_ScreentoData(GRAPH *graph, int x, int y, double *fx, double *fy) +{ + double lmin, lmax; + + if (graph->grid.gridtype == GRID_XLOG + || graph->grid.gridtype == GRID_LOGLOG) + { + lmin = log10(graph->datawindow.xmin); + lmax = log10(graph->datawindow.xmax); + *fx = exp(((x - graph->viewportxoff) + * (lmax - lmin) / graph->viewport.width + lmin) + * M_LN10); + } else { + *fx = (x - graph->viewportxoff) * graph->aspectratiox + + graph->datawindow.xmin; + } + + if (graph->grid.gridtype == GRID_YLOG + || graph->grid.gridtype == GRID_LOGLOG) + { + lmin = log10(graph->datawindow.ymin); + lmax = log10(graph->datawindow.ymax); + *fy = exp(((graph->absolute.height - y - graph->viewportxoff) + * (lmax - lmin) / graph->viewport.height + lmin) + * M_LN10); + } else { + *fy = ((graph->absolute.height - y) - graph->viewportyoff) + * graph->aspectratioy + graph->datawindow.ymin; + } + +} + + +static void +linear_arc(int x0, int y0, int radius, double theta1, double theta2) + /* x coordinate of center */ + /* y coordinate of center */ + /* radius of arc */ + /* initial angle ( +x axis = 0 rad ) */ + /* final angle ( +x axis = 0 rad ) */ + /* + * Notes: + * Draws an arc of radius and center at (x0,y0) beginning at + * angle theta1 (in rad) and ending at theta2 + */ +{ + int x1, y1, x2, y2; + int s = 60; + double dphi, phi; + + x2 = x0 + (int) (radius * cos(theta1)); + y2 = y0 + (int) (radius * sin(theta1)); + + while(theta1 >= theta2) + theta2 += 2 * M_PI; + dphi = (theta2 - theta1) / s; + + if ((theta1 + dphi) == theta1) { + theta2 += 2 * M_PI; + dphi = (theta2 - theta1) / s; + } + + + for(phi = theta1 + dphi; phi < theta2; phi += dphi) { + x1 = x2; + y1 = y2; + x2 = x0 + (int)(radius * cos(phi)); + y2 = y0 + (int)(radius * sin(phi)); + X11_DrawLine(x1,y1,x2,y2); + } + + x1 = x2; + y1 = y2; + x2 = x0 + (int)(radius * cos(theta2)); + y2 = y0 + (int)(radius * sin(theta2)); + X11_DrawLine(x1,y1,x2,y2); +} + +#else +int x11_dummy_symbol; +/* otherwise, some linkers get upset */ +#endif /* X_DISPLAY_MISSING */ diff --git a/src/frontend/x11.h b/src/frontend/x11.h new file mode 100644 index 000000000..f9a6f1d5e --- /dev/null +++ b/src/frontend/x11.h @@ -0,0 +1,37 @@ +/************* + * Header file for x11.c + * 1999 E. Rouat + ************/ + +#ifndef X11_H_INCLUDED +#define X11_H_INCLUDED + +int X11_Init(void); +void errorhandler(Display *display, XErrorEvent *errorev); +int X11_NewViewport(GRAPH *graph); +void initlinestyles(void); +void initcolors(GRAPH *graph); +void X11_Close(void); +void X11_DrawLine(int x1, int y1, int x2, int y2); +void X11_Arc(int x0, int y0, int radius, double theta1, double theta2); +void X11_Text(char *text, int x, int y); +int X11_DefineColor(int colorid, double red, double green, double blue); +void X11_DefineLinestyle(int linestyleid, int mask); +void X11_SetLinestyle(int linestyleid); +void X11_SetColor(int colorid); +void X11_Update(void); +void X11_Clear(void); +void handlekeypressed(Widget w, caddr_t clientdata, caddr_t calldata); +void handlebuttonev(Widget w, caddr_t clientdata, caddr_t calldata); +void slopelocation(GRAPH *graph, int x0, int y0); +void zoomin(GRAPH *graph); +void hardcopy(Widget w, caddr_t client_data, caddr_t call_data); +void killwin(Widget w, caddr_t client_data, caddr_t call_data); +void redraw(Widget w, caddr_t client_data, caddr_t call_data); +void resize(Widget w, caddr_t client_data, caddr_t call_data); +void X11_Input(REQUEST *request, RESPONSE *response); +void X_ScreentoData(GRAPH *graph, int x, int y, double *fx, double *fy); + + + +#endif diff --git a/src/frontend/xgraph.c b/src/frontend/xgraph.c new file mode 100644 index 000000000..266b1f6f3 --- /dev/null +++ b/src/frontend/xgraph.c @@ -0,0 +1,166 @@ +/********** +Copyright 1992 Regents of the University of California. All rights reserved. +Author: 1992 David A. Gates, U. C. Berkeley CAD Group +**********/ + +/* + * Xgraph-11 plots. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "fteparse.h" +#include "xgraph.h" + + +#define XG_MAXVECTORS 64 + +void +ft_xgraph(double *xlims, double *ylims, char *filename, char *title, char *xlabel, char *ylabel, GRIDTYPE gridtype, PLOTTYPE plottype, struct dvec *vecs) +{ + + FILE *file; + struct dvec *v, *scale; + double xval, yval; + int i, numVecs, linewidth; + bool xlog, ylog, nogrid, markers; + char buf[BSIZE_SP], pointstyle[BSIZE_SP], *text; + + /* Sanity checking. */ + for ( v = vecs, numVecs = 0; v; v = v->v_link2 ) { + numVecs++; + } + if (numVecs == 0) { + return; + } else if (numVecs > XG_MAXVECTORS) { + fprintf( cp_err, "Error: too many vectors for Xgraph.\n" ); + return; + } + if (!cp_getvar("xbrushwidth", VT_NUM, &linewidth)) + linewidth = 1; + if (linewidth < 1) linewidth = 1; + + if (!cp_getvar("pointstyle", VT_STRING, pointstyle)) { + markers = FALSE; + } else { + if (cieq(pointstyle,"markers")) { + markers = TRUE; + } else { + markers = FALSE; + } + } + + + /* Make sure the gridtype is supported. */ + switch (gridtype) { + case GRID_LIN: + nogrid = xlog = ylog = FALSE; + break; + case GRID_XLOG: + xlog = TRUE; + nogrid = ylog = FALSE; + break; + case GRID_YLOG: + ylog = TRUE; + nogrid = xlog = FALSE; + break; + case GRID_LOGLOG: + xlog = ylog = TRUE; + nogrid = FALSE; + break; + case GRID_NONE: + nogrid = TRUE; + xlog = ylog = FALSE; + break; + default: + fprintf( cp_err, "Error: grid type unsupported by Xgraph.\n" ); + return; + } + + /* Open the output file. */ + if (!(file = fopen(filename, "w"))) { + perror(filename); + return; + } + + /* Set up the file header. */ + if (title) { + text = cp_unquote(title); + fprintf( file, "TitleText: %s\n", text ); + tfree(text); + } + if (xlabel) { + text = cp_unquote(xlabel); + fprintf( file, "XUnitText: %s\n", text ); + tfree(text); + } + if (ylabel) { + text = cp_unquote(ylabel); + fprintf( file, "YUnitText: %s\n", text ); + tfree(text); + } + if (nogrid) { + fprintf( file, "Ticks: True\n" ); + } + if (xlog) { + fprintf( file, "LogX: True\n" ); + if (xlims) { + fprintf( file, "XLowLimit: % e\n", log10(xlims[0]) ); + fprintf( file, "XHighLimit: % e\n", log10(xlims[1]) ); + } + } else { + if (xlims) { + fprintf( file, "XLowLimit: % e\n", xlims[0] ); + fprintf( file, "XHighLimit: % e\n", xlims[1] ); + } + } + if (ylog) { + fprintf( file, "LogY: True\n" ); + if (ylims) { + fprintf( file, "YLowLimit: % e\n", log10(ylims[0]) ); + fprintf( file, "YHighLimit: % e\n", log10(ylims[1]) ); + } + } else { + if (ylims) { + fprintf( file, "YLowLimit: % e\n", ylims[0] ); + fprintf( file, "YHighLimit: % e\n", ylims[1] ); + } + } + fprintf( file, "LineWidth: %d\n", linewidth ); + fprintf( file, "BoundBox: True\n" ); + if (plottype == PLOT_COMB) { + fprintf( file, "BarGraph: True\n" ); + fprintf( file, "NoLines: True\n" ); + } else if (plottype == PLOT_POINT) { + if (markers) { + fprintf( file, "Markers: True\n" ); + } else { + fprintf( file, "LargePixels: True\n" ); + } + fprintf( file, "NoLines: True\n" ); + } + + /* Write out the data. */ + for ( v = vecs; v; v = v->v_link2 ) { + scale = v->v_scale; + if (v->v_name) { + fprintf( file, "\"%s\"\n", v->v_name ); + } + for ( i = 0; i < scale->v_length; i++ ) { + xval = isreal(scale) ? + scale->v_realdata[i] : realpart(&scale->v_compdata[i]); + yval = isreal(v) ? + v->v_realdata[i] : realpart(&v->v_compdata[i]); + fprintf( file, "% e % e\n", xval, yval ); + } + fprintf( file, "\n" ); + } + (void) fclose( file ); + (void) sprintf( buf, "xgraph %s &", filename ); + (void) system( buf ); + + + return; +} diff --git a/src/frontend/xgraph.h b/src/frontend/xgraph.h new file mode 100644 index 000000000..47cdc18c3 --- /dev/null +++ b/src/frontend/xgraph.h @@ -0,0 +1,16 @@ +/************* + * Header file for xgraph.c + * 1999 E. Rouat + ************/ + +#ifndef XGRAPH_H_INCLUDED +#define XGRAPH_H_INCLUDED + +void ft_xgraph(double *xlims, double *ylims, char *filename, char *title, + char *xlabel, char *ylabel, GRIDTYPE gridtype, PLOTTYPE plottype, + struct dvec *vecs); + + + + +#endif diff --git a/src/help.c b/src/help.c new file mode 100644 index 000000000..12ac354eb --- /dev/null +++ b/src/help.c @@ -0,0 +1,114 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * The main routine for the help system in stand-alone mode. + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "hlpdefs.h" + + + +#ifndef X_DISPLAY_MISSING +Widget toplevel; +#endif + +FILE *cp_in, *cp_out, *cp_err; +char *Spice_Exec_Dir = NGSPICEBINDIR; +char *Spice_Lib_Dir = NGSPICEDATADIR; +char *Def_Editor = "vi"; +int AsciiRawFile = 0; + +char *Bug_Addr = ""; +char *Spice_Host = ""; +char *Spiced_Log = ""; + +/* dummy declaration so CP.a doesn't pull in lexical.o and other objects */ +bool cp_interactive = FALSE; + +char *hlp_filelist[] = { "ngspice", 0 }; + +int +main(int ac, char **av) +{ + wordlist *wl = NULL; + +#ifndef X_DISPLAY_MISSING + char *displayname; + /* grrr, Xtk forced contortions */ + char *argv[2]; + int argc = 2; + char buf[512]; +#endif + + ivars( ); + + cp_in = stdin; + cp_out = stdout; + cp_err = stderr; + +#ifndef X_DISPLAY_MISSING + + if (cp_getvar("display", VT_STRING, buf)) { + displayname = buf; + } else if (!(displayname = getenv("DISPLAY"))) { + fprintf(stderr, "Can't open X display."); + goto out; + } + + argv[0] = "nutmeg"; + argv[1] = displayname; + /* initialize X toolkit */ + toplevel = XtInitialize("nutmeg", "Nutmeg", NULL, 0, &argc, argv); + +#endif + +out: + if (ac > 1) + wl = wl_build(av + 1); + hlp_main(Help_Path, wl); + +#ifndef X_DISPLAY_MISSING + if (hlp_usex) { + printf("Hit control-C when done.\n"); /* sigh */ + XtMainLoop(); + } +#endif + + exit(EXIT_NORMAL); +} + +void +fatal(char *s) +{ + fprintf(stderr, "fatal error: %s\n", s); + exit(1); +} + +/* There is a conflict witj another cp_printword in cp/quote.c +static void +cp_printword(s) + char *s; +{ + printf("%s", s); + return; +} + +*/ + +bool +cp_getvar(char *n, int t, char *r) +{ + return (FALSE); +} + +char * +cp_tildexpand(char *s) +{ + return tilde_expand(s); +} diff --git a/src/hlp/ChangeLog b/src/hlp/ChangeLog new file mode 100644 index 000000000..d6163fa49 --- /dev/null +++ b/src/hlp/ChangeLog @@ -0,0 +1,32 @@ +1999-08-12 Emmanuel Rouat + + * x11disp.c: made a cast to (XtCallbackProc) when necessary + + * readhelp.c: sanitised the code slighly + + * *.c: changed functions from K&R into ANSI using protoize + +1999-08-08 Emmanuel Rouat + + * xdisplay.c: removed all X10 related code + + * Makefile.am (DEFS): removed -DWANT_MFB (don't need it) + +1999-08-03 Emmanuel Rouat + + * readhelp.c: HAVE_SYS_DIR_H and HAVE_DIRENT_H instead of + HAS_BSDDIRS and HAS_SYSVDIRS. + +1999-07-31 Emmanuel Rouat + + * Makefile.am: added @X_CFLAGS@ in INCLUDES list and removed unused LIBS + + +28-07-1999 emmanuel.rouat@wanadoo.fr (Manu Rouat) + + * help.c: + * provide.c: + * x11disp.c: changed HAS_X11 define to X_DISPLAY_MISSING, which is supplied + by autoconf in config.h + + * removed -DWANT_X11 in Makefile.am \ No newline at end of file diff --git a/src/hlp/Makefile.am b/src/hlp/Makefile.am new file mode 100644 index 000000000..e2871d998 --- /dev/null +++ b/src/hlp/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libhlp.a + +libhlp_a_SOURCES = \ + help.c \ + provide.c \ + readhelp.c \ + textdisp.c \ + xdisplay.c \ + x11disp.c + + + +INCLUDES = -I$(top_srcdir)/src/include @X_CFLAGS@ + + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/hlp/help.c b/src/hlp/help.c new file mode 100644 index 000000000..603b4c99e --- /dev/null +++ b/src/hlp/help.c @@ -0,0 +1,171 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +Modified 1999 Emmanuel Rouat +**********/ + +/* + * The main entry point for the help system. + */ + +#include +#include "ngspice.h" +#include "cpstd.h" +#include "hlpdefs.h" +#include "suffix.h" + +char *hlp_directory; +extern char *hlp_filelist[]; +int hlp_ftablesize = 0; + +void +hlp_main(char *path, wordlist *wl) +{ + topic *top; + fplace *place; + + hlp_directory = path; + + if (wl) { + while (wl) { + if (!(place = findglobalsubject(wl->wl_word))) { + fprintf(stderr, "Error: No such topic: %s\n", + wl->wl_word); + wl = wl->wl_next; + continue; + } + if (!(top = hlp_read(place))) { + fprintf(stderr, "Error: can't read topic\n"); + wl = wl->wl_next; + continue; + } + hlp_provide(top); + wl = wl->wl_next; + } + } else { + if (!(place = findglobalsubject("main"))) { + fprintf(stderr, "Error: no main topic\n"); + return; + } + if (!(top = hlp_read(place))) { + fprintf(stderr, "Error: can't read topic\n"); + return; + } + hlp_provide(top); + } + +#ifdef X_DISPLAY_MISSING + hlp_free(); +#endif + + return; +} + +fplace * +findglobalsubject(char *subject) +{ + + fplace *place; + char **dict; + long fpos; + + place = 0; + for (dict = hlp_filelist; *dict && **dict; dict++) { + fpos = findsubject(*dict, subject); + if (fpos != -1) { + place = (fplace *) tmalloc(sizeof(fplace)); + place->fpos = fpos; + place->filename = copy(*dict); + place->fp = hlp_fopen(*dict); + break; + } + } + return(place); +} + +/* see if file is on filelist */ +bool +hlp_approvedfile(char *filename) +{ + char **s; + + for (s = hlp_filelist; *s && **s; s++) { + if (cieq(*s, filename)) return(TRUE); + } + return(FALSE); +} + +/* keep file pointers on top level files so we don't always have to do + fopen's */ +FILE *hlp_fopen(char *filename) +{ + static struct { + char filename[BSIZE_SP]; + FILE *fp; + } hlp_ftable[32]; + int i; + char buf[BSIZE_SP]; + + for (i=0; i < hlp_ftablesize; i++) { + if (cieq(filename, hlp_ftable[i].filename)) { + return(hlp_ftable[i].fp); + } + } + + /* not already in table */ + strcpy(buf, hlp_directory); /* set up pathname */ + strcat(buf, DIR_PATHSEP); + strcat(buf, filename); + strcat(buf, ".txt"); + hlp_pathfix(buf); + if (!(hlp_ftable[hlp_ftablesize].fp = fopen(buf, "r"))) { + perror(buf); + return (NULL); + } + + strcpy(hlp_ftable[hlp_ftablesize].filename, filename); + hlp_ftablesize++; + + return(hlp_ftable[hlp_ftablesize - 1].fp); + +} + +/* ARGSUSED */ +void +hlp_pathfix(char *buf) +{ + char *s, *t, *u, bufx[1025]; + char *dir_pathsep; + extern char *cp_tildexpand( ); + + dir_pathsep = DIR_PATHSEP; + + if (!buf) + return; + + s = cp_tildexpand(buf); + if (sizeof(DIR_PATHSEP) == 2) { + if (*dir_pathsep != '/') { + for (t = s; *t; t++) { + if (*t == '/') + *t = *dir_pathsep; + } + } else + strcpy(buf, s); + } else { + /* For vms; this probably doesn't work, but neither did the old code */ + for (s = bufx, t = buf; *t; t++) { + if (*t == '/') + for (u = DIR_PATHSEP; *u; u++) { + *s++ = *u; + } + else + *s++ = *t; + } + *s = 0; + strcpy(buf, s); + } + if (s) + tfree(s); + return; +} diff --git a/src/hlp/provide.c b/src/hlp/provide.c new file mode 100644 index 000000000..7afcdf301 --- /dev/null +++ b/src/hlp/provide.c @@ -0,0 +1,145 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +Modified 1999 Emmanuel Rouat +**********/ + +/* + * faustus@cad.berkeley.edu, ucbvax!faustus + * Permission is granted to modify and re-distribute this code in any manner + * as long as this notice is preserved. All standard disclaimers apply. + * + * Toss the help window up on the screen, and deal with the graph... + */ + +#include +#include "ngspice.h" +#include "cpstd.h" +#include "hlpdefs.h" +#include "suffix.h" + +bool hlp_usex = FALSE; + +void +hlp_provide(topic *top) +{ + toplink *res; + topic *parent, *newtop; + + if (!top) + return; + +#ifndef X_DISPLAY_MISSING + if (getenv("DISPLAY") || hlp_displayname) + hlp_usex = TRUE; +#endif + + top->xposition = top->yposition = 0; + if (hlp_usex) { + if (!hlp_xdisplay(top)) { + fprintf(stderr, "Couldn't open X display.\n"); + return; + } + } else { + if (!hlp_tdisplay(top)) { + fprintf(stderr, "Couldn't display text\n"); + return; + } + } + +#ifndef X_DISPLAY_MISSING /* X11 does this asynchronously */ + if (hlp_usex) return; +#endif + + for (;;) { + if (hlp_usex) + res = hlp_xhandle(&parent); + else + res = hlp_thandle(&parent); + if (!res && !parent) { + /* No more windows. */ + hlp_killfamily(top); + if (hlp_usex) hlp_xclosedisplay(); /* need to change + display pointer back J.H. */ + return; + } + if (res) { + /* Create a new window... */ + if (hlp_usex) + hlp_xwait(parent, TRUE); + if (!(newtop = hlp_read(res->place))) { + fprintf(stderr, "Internal error: bad link\n"); + hlp_xwait(parent, FALSE); + continue; + } + if (hlp_usex) + hlp_xwait(parent, FALSE); + newtop->next = parent->children; + parent->children = newtop; + newtop->parent = parent; + newtop->xposition = parent->xposition + 50; + newtop->yposition = parent->yposition + 50; + if (hlp_usex) { + if (!hlp_xdisplay(newtop)) { + fprintf(stderr, "Couldn't open win\n"); + return; + } + } else { + if (!hlp_tdisplay(newtop)) { + fprintf(stderr, "Couldn't display\n"); + return; + } + } + } else { + /* Blow this one and its descendants away. */ + hlp_killfamily(parent); + hlp_fixchildren(parent); + if (parent == top) + return; + } + } + +} + +void +hlp_fixchildren(topic *parent) +{ + + topic *pa; + + if (parent->parent) { + if (parent->parent->children == parent) + parent->parent->children = + parent->next; + else { + for (pa = parent->parent->children; + pa->next; pa = pa->next) + if (pa->next == parent) + break; + if (!pa->next) { + fprintf(stderr, "bah...\n"); + } + pa->next = pa->next->next; + } + } +} + +/* Note that this doesn't actually free the data structures, just gets + * rid of the window. + */ + +void +hlp_killfamily(topic *top) +{ + topic *ch; + + for (ch = top->children; ch; ch = ch->next) + hlp_killfamily(ch); + if (hlp_usex) + hlp_xkillwin(top); + else + hlp_tkillwin(top); + top->children = NULL; + return; +} + diff --git a/src/hlp/readhelp.c b/src/hlp/readhelp.c new file mode 100644 index 000000000..029992bd7 --- /dev/null +++ b/src/hlp/readhelp.c @@ -0,0 +1,338 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +Modified 1999 Emmanuel Rouat +**********/ + + + +#include +#include "ngspice.h" +#include "cpstd.h" +#include "hlpdefs.h" + +#ifdef notdef + +# ifdef HAVE_SYS_DIR_H +# include +# include +# include +# else +# ifdef HAVE_DIRENT_H +# include +# include +# ifndef direct +# define direct dirent +# endif +# endif +# endif + + +#endif + +#include "suffix.h" + +static char *getsubject(fplace *place); +static toplink *getsubtoplink(char **ss); +extern void sortlist(toplink **tlp), tlfree(toplink *tl); +extern int sortcmp(toplink **tlp1, toplink **tlp2); + +static topic *alltopics = NULL; + +static fplace *copy_fplace(fplace *place); + +topic * +hlp_read(fplace *place) +{ + char buf[BSIZE_SP]; + topic *top = alloc(topic); + toplink *topiclink; + toplink *tl, *tend = NULL; + wordlist *wl, *end = NULL; + int i, fchanges; + char *s; + bool mof; + + if (!place) + return 0; + + top->place = copy_fplace(place); + + /* get the title */ + if (!place->fp) place->fp = hlp_fopen(place->filename); + if (!place->fp) return(NULL); + fseek(place->fp, place->fpos, 0); + (void) fgets(buf, BSIZE_SP, place->fp); /* skip subject */ + (void) fgets(buf, BSIZE_SP, place->fp); + for (s = buf; *s && (*s != '\n'); s++) + ; + *s = '\0'; + top->title = copy(&buf[7]); /* don't copy "TITLE: " */ + + /* get the text */ + /* skip to TEXT: */ + while (fgets(buf, BSIZE_SP, place->fp)) { + if (!strncmp("TEXT: ", buf, 6)) break; + if ((*buf = '\0') || + !strncmp("SEEALSO: ", buf, 9) || + !strncmp("SUBTOPIC: ", buf, 10)) { + /* no text */ + top->text = NULL; + goto endtext; + } + } + mof = TRUE; + while (mof && !strncmp("TEXT: ", buf, 6)) { + for (s = &buf[6], fchanges = 0; *s && (*s != '\n'); s++) + if (((s[0] == '\033') && s[1]) || + ((s[0] == '_') && (s[1] == '\b'))) + fchanges++; + *s = '\0'; + wl = alloc(wordlist); + wl->wl_word = copy(&buf[6]); + if (end) + end->wl_next = wl; + else + top->text = wl; + wl->wl_prev = end; + end = wl; + top->numlines++; + if ((i = strlen(&buf[6]) - fchanges) > top->maxcols) + top->maxcols = i; + mof = fgets(buf, BSIZE_SP, place->fp) == NULL ? FALSE : TRUE; + } +endtext: + + /* get subtopics */ + while(mof && !strncmp("SUBTOPIC: ", buf, 10)) { + s = &buf[10]; + /* process tokens within line, updating pointer */ + while (*s) { + if ((topiclink = getsubtoplink(&s))) { + if (tend) + tend->next = topiclink; + else + top->subtopics = topiclink; + tend = topiclink; + } + } + mof = fgets(buf, BSIZE_SP, place->fp) == NULL ? FALSE : TRUE; + } + + /* get see alsos */ + tend = NULL; + while(mof && !strncmp("SEEALSO: ", buf, 9)) { + s = &buf[9]; + /* process tokens within line, updating pointer */ + while (*s) { + if ((topiclink = getsubtoplink(&s))) { + if (tend) + tend->next = topiclink; + else + top->seealso = topiclink; + tend = topiclink; + } + } + mof = fgets(buf, BSIZE_SP, place->fp) == NULL ? FALSE : TRUE; + } + + /* Now we have to fill in the subjects + for the seealsos and subtopics. */ + for (tl = top->seealso; tl; tl = tl->next) + tl->description = getsubject(tl->place); + for (tl = top->subtopics; tl; tl = tl->next) + tl->description = getsubject(tl->place); + + sortlist(&top->seealso); + /* sortlist(&top->subtopics); It looks nicer if they + are in the original order */ + + top->readlink = alltopics; + alltopics = top; + + return (top); +} + +/* *ss is of the form filename:subject */ +static toplink *getsubtoplink(char **ss) +{ + toplink *tl; + char *tmp, *s, *t; + char subject[BSIZE_SP]; + + if (!**ss) return(NULL); + + s = *ss; + + tl = alloc(toplink); + if ((tmp =strchr(s, ':'))) { + tl->place = alloc(fplace); + tl->place->filename = strncpy( + calloc(1, (unsigned) (sizeof (char) * (tmp - s + 1))), + s, (tmp - s)); + tl->place->filename[tmp - s] = '\0'; + strtolower(tl->place->filename); + + /* see if filename is on approved list */ + if (!hlp_approvedfile(tl->place->filename)) { + tfree(tl->place); + tfree(tl); + /* skip up to next comma or newline */ + while (*s && *s != ',' && *s != '\n') s++; + while (*s && (*s == ',' || *s == ' ' || *s == '\n')) s++; + *ss = s; + return(NULL); + } + + tl->place->fp = hlp_fopen(tl->place->filename); + for (s = tmp + 1, t = subject; *s && *s != ',' && *s != '\n'; s++) { + *t++ = *s; + } + *t = '\0'; + tl->place->fpos = findsubject(tl->place->filename, subject); + if (tl->place->fpos == -1) { + tfree(tl->place); + tfree(tl); + while (*s && (*s == ',' || *s == ' ' || *s == '\n')) s++; + *ss = s; + return(NULL); + } + } else { + fprintf(stderr, "bad filename:subject pair %s\n", s); + /* skip up to next free space */ + while (*s && *s != ',' && *s != '\n') s++; + while (*s && (*s == ',' || *s == ' ' || *s == '\n')) s++; + *ss = s; + tfree(tl->place); + tfree(tl); + return(NULL); + } + while (*s && (*s == ',' || *s == ' ' || *s == '\n')) s++; + *ss = s; + return(tl); +} + +/* returns a file position, -1 on error */ +long +findsubject(char *filename, char *subject) +{ + + FILE *fp; + char buf[BSIZE_SP]; + struct hlp_index indexitem; + + if (!filename) { + return -1; + } + + /* open up index for filename */ + sprintf(buf, "%s%s%s.idx", hlp_directory, DIR_PATHSEP, filename); + hlp_pathfix(buf); + if (!(fp = fopen(buf, "rb"))) { + perror(buf); + return(-1); + } + + while(fread((char *) &indexitem, sizeof (struct hlp_index), 1, fp)) { + if (!strncmp(subject, indexitem.subject, 64)) { + fclose(fp); + return(indexitem.fpos); + } + } + + fclose(fp); + return(-1); + +} + +static char * +getsubject(fplace *place) +{ + char buf[BSIZE_SP], *s; + + if (!place->fp) place->fp = hlp_fopen(place->filename); + if (!place->fp) return(NULL); + + fseek(place->fp, place->fpos, 0); + (void) fgets(buf, BSIZE_SP, place->fp); + for (s = buf; *s && (*s != '\n'); s++) + ; + *s = '\0'; + return (copy(&buf[9])); /* don't copy "SUBJECT: " */ +} + +static + void sortlist(toplink **tlp) +{ + toplink **vec, *tl; + int num = 0, i; + + for (tl = *tlp; tl; tl = tl->next) + num++; + if (!num) + return; + vec = (toplink **) tmalloc(sizeof (toplink *) * num); + for (tl = *tlp, i = 0; tl; tl = tl->next, i++) + vec[i] = tl; + (void) qsort((char *) vec, num, sizeof (toplink *), sortcmp); + *tlp = vec[0]; + for (i = 0; i < num - 1; i++) + vec[i]->next = vec[i + 1]; + vec[i]->next = NULL; + tfree(vec); + return; +} + +static int +sortcmp(toplink **tlp1, toplink **tlp2) +{ + return (strcmp((*tlp1)->description, (*tlp2)->description)); +} + +void +hlp_free(void) +{ + topic *top, *nt = NULL; + + for (top = alltopics; top; top = nt) { + nt = top->readlink; + tfree(top->title); + tfree(top->place); + wl_free(top->text); + tlfree(top->subtopics); + tlfree(top->seealso); + tfree(top); + } + alltopics = NULL; + return; +} + +static +void tlfree(toplink *tl) +{ + toplink *nt = NULL; + + while (tl) { + tfree(tl->description); + tfree(tl->place->filename); + tfree(tl->place); + /* Don't free the button stuff... */ + nt = tl->next; + tfree(tl); + tl = nt; + } + return; +} + +static fplace * +copy_fplace(fplace *place) +{ + fplace *newplace; + + newplace = (fplace *) malloc(sizeof(fplace)); + newplace->filename = copy(place->filename); + newplace->fpos = place->fpos; + newplace->fp = place->fp; + + return(newplace); +} diff --git a/src/hlp/textdisp.c b/src/hlp/textdisp.c new file mode 100644 index 000000000..556a50dae --- /dev/null +++ b/src/hlp/textdisp.c @@ -0,0 +1,201 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + + +/* + * faustus@cad.berkeley.edu, ucbvax!faustus + * Permission is granted to modify and re-distribute this code in any manner + * as long as this notice is preserved. All standard disclaimers apply. + * + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "hlpdefs.h" +#include "suffix.h" + +static topic *curtop; +static bool quitflag; + +static void putline(char *s); +static int putstuff(toplink *tl, int base); + +int hlp_width = 72; + +bool +hlp_tdisplay(topic *top) +{ + wordlist *wl; + int i = 0; + + curtop = top; + + out_init(); + out_printf("\n\t%s\n", top->title); + for (wl = top->text; wl; wl = wl->wl_next) + putline(wl->wl_word); + if (top->subtopics) { + out_printf("\tSub-Topics:\n\n"); + i = putstuff(top->subtopics, 0); + } + if (top->seealso) { + out_printf("\n\tSee Also:\n\n"); + (void) putstuff(top->seealso, i); + } + out_printf("\n"); + return (TRUE); +} + +toplink * +hlp_thandle(topic **parent) +{ + char buf[BSIZE_SP], *s; + toplink *tl; + int num; + + quitflag = FALSE; + if (!curtop) { + *parent = NULL; + return (NULL); + } + for (;;) { + fprintf(cp_out, "Selection (`?' for help): "); + (void) fflush(cp_out); + if (!fgets(buf, BSIZE_SP, cp_in)) { + clearerr(stdin); + quitflag = TRUE; + *parent = NULL; + return (NULL); + } + + for (s = buf; *s && isspace(*s); s++) + ; + switch (*s) { + case '?': + fprintf(cp_out, +"\nType the number of a sub-topic or see also, or one of:\n\ +\tr\tReprint the current topic\n\ +\tp or CR\tReturn to the previous topic\n\ +\tq\tQuit help\n\ +\t?\tPrint this message\n\n"); + continue; + + case 'r': + (void) hlp_tdisplay(curtop); + continue; + + case 'q': + quitflag = TRUE; + *parent = NULL; + return (NULL); + + case 'p': + case '\n': + case '\r': + case '\0': + *parent = curtop; + return (NULL); + } + if (!isdigit(*s)) { + fprintf(cp_err, "Invalid command\n"); + continue; + } + num = atoi(s); + if (num <= 0) { + fprintf(cp_err, "Bad choice.\n"); + continue; + } + for (tl = curtop->subtopics; tl; tl = tl->next) + if (--num == 0) + break; + if (num) { + for (tl = curtop->seealso; tl; tl = tl->next) + if (--num == 0) + break; + } + if (num) { + fprintf(cp_err, "Bad choice.\n"); + continue; + } + *parent = curtop; + return (tl); + } +} + +/* ARGSUSED */ +void +hlp_tkillwin(topic *top) +{ + if (curtop) + curtop = curtop->parent; + if (curtop && !quitflag) + (void) hlp_tdisplay(curtop); + return; +} + +/* This has to rip out the font changes from the lines... */ + +static void +putline(char *s) +{ + char buf[BSIZE_SP]; + int i = 0; + + while (*s) { + if (((*s == '\033') && s[1]) || + ((*s == '_') && (s[1] == '\b'))) + s += 2; + else + buf[i++] = *s++; + } + buf[i] = '\0'; + out_printf("%s\n", buf); + return; +} + +/* Figure out the number of columns we can use. Assume an entry like + * nn) word -- add 5 characters to the width... + */ + +static int +putstuff(toplink *tl, int base) +{ + int maxwidth = 0, ncols, nrows, nbuts = 0, i, j, k; + toplink *tt; + + for (tt = tl; tt; tt = tt->next) { + if (strlen(tt->description) + 5 > maxwidth) + maxwidth = strlen(tt->description) + 5; + nbuts++; + } + ncols = hlp_width / maxwidth; + if (!ncols) { + fprintf(stderr, "Help, button too big!!\n"); + return (0); + } + if (ncols > nbuts) + ncols = nbuts; + maxwidth = hlp_width / ncols; + nrows = nbuts / ncols; + if (nrows * ncols < nbuts) + nrows++; + + for (i = 0; i < nrows; i++) { + for (tt = tl, j = 0; j < i; j++, tt = tt->next) + ; + for (j = 0; j < ncols; j++) { + if (tt) + out_printf("%2d) %-*s ", base + j * nrows + i + + 1, maxwidth - 5, tt->description); + for (k = 0; k < nrows; k++) + if (tt) + tt = tt->next; + + } + out_printf("\n"); + } + return (nbuts); +} + diff --git a/src/hlp/x11disp.c b/src/hlp/x11disp.c new file mode 100644 index 000000000..d3a42d1f6 --- /dev/null +++ b/src/hlp/x11disp.c @@ -0,0 +1,299 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: Jeffrey M. Hsu +Modified 1999 Emmanuel Rouat +**********/ + +#include +#include "ngspice.h" + +#ifndef X_DISPLAY_MISSING + +#include "cpstd.h" +#include "hlpdefs.h" +#include +#include +#include +#include +#include +#include +#include +#include + +static bool started = FALSE; +static topic *topics = NULL; +void newtopic(Widget w, caddr_t client_data, caddr_t call_data), delete(Widget w, caddr_t client_data, caddr_t call_data), quit(Widget w, caddr_t client_data, caddr_t call_data); +static void sputline(char *buf, char *s); + +/* Create a new window... */ +bool +hlp_xdisplay(topic *top) +{ + + toplink *tl; + handle *hand; + + wordlist *wl; + char *buf; + + static Arg titleargs[] = { + { XtNtop, (XtArgVal) XtChainTop }, + { XtNbottom, (XtArgVal) XtChainTop }, + { XtNleft, (XtArgVal) XtChainLeft }, + { XtNright, (XtArgVal) XtChainLeft }, + { XtNwidth, (XtArgVal) 650 }, + }; + + static Arg formargs[ ] = { + { XtNtop, (XtArgVal) XtChainTop }, + { XtNtop, (XtArgVal) XtChainTop }, + { XtNtop, (XtArgVal) XtChainTop }, + { XtNbottom, (XtArgVal) XtChainBottom }, + }; + Arg htextargs[7]; +/* Arg vportargs[5]; */ + static Arg bboxargs[ ] = { + { XtNtop, (XtArgVal) XtChainBottom }, + { XtNtop, (XtArgVal) XtChainBottom }, + { XtNtop, (XtArgVal) XtChainBottom }, + { XtNtop, (XtArgVal) XtChainBottom }, + { XtNbottom, (XtArgVal) XtChainBottom }, + { XtNleft, (XtArgVal) XtChainLeft }, + { XtNright, (XtArgVal) XtChainLeft }, + }; + Arg buttonargs[1]; + Arg labelargs[3]; + Widget buttonwidget; + + if (!started) { /* have to init everything */ + + /* assume X toolkit already initialize */ + + started = TRUE; + + } + + top->shellwidget = XtCreateApplicationShell("shell", + topLevelShellWidgetClass, NULL, 0); + + if (!top->parent) { + top->xposition = hlp_initxpos; + top->yposition = hlp_initypos; + } else { + top->xposition = top->parent->xposition + X_INCR; + top->yposition = top->parent->yposition + Y_INCR; + } + XtSetArg(formargs[0], XtNx, top->xposition); + XtSetArg(formargs[1], XtNy, top->yposition); + top->formwidget = XtCreateManagedWidget("form", formWidgetClass, + top->shellwidget, formargs, XtNumber(formargs)); + + /* we really want a title bar widget for this, sigh */ + top->titlewidget = XtCreateManagedWidget("title", + boxWidgetClass, top->formwidget, + titleargs, XtNumber(titleargs)); + XtSetArg(labelargs[0], XtNlabel, top->title); + XtCreateManagedWidget("titlelabel", labelWidgetClass, + top->titlewidget, labelargs, 1); + XtSetArg(buttonargs[0], XtNlabel, "quit help"); + buttonwidget = XtCreateManagedWidget("quit", commandWidgetClass, + top->titlewidget, buttonargs, 1); + XtAddCallback(buttonwidget, XtNcallback, (XtCallbackProc) quit, top); + XtSetArg(buttonargs[0], XtNlabel, "delete window"); + buttonwidget = XtCreateManagedWidget("delete", commandWidgetClass, + top->titlewidget, buttonargs, XtNumber(buttonargs)); + XtAddCallback(buttonwidget, XtNcallback, (XtCallbackProc) delete, top); + +#ifdef notdef + /* enclose text string w/in a viewport widget for scrolling */ + XtSetArg(vportargs[0], XtNfromVert, top->titlewidget); + XtSetArg(vportargs[1], XtNallowResize, True); + XtSetArg(vportargs[2], XtNallowVert, True); + XtSetArg(vportargs[3], XtNallowHoriz, True); + XtSetArg(vportargs[4], XtNforceBars, True); + top->viewwidget = XtCreateManagedWidget("viewport", + viewportWidgetClass, top->formwidget, + vportargs, 5); +#endif + + buf = tmalloc(80 * top->numlines + 100); + buf[0] = '\0'; + for (wl = top->text; wl; wl = wl->wl_next) { + sputline(buf, wl->wl_word); + } + top->chartext = buf; /* make sure gets deallocated later XXX */ + XtSetArg(htextargs[0], XtNstring, top->chartext); + XtSetArg(htextargs[1], XtNallowResize, True); + XtSetArg(htextargs[2], XtNscrollHorizontal, True ); + XtSetArg(htextargs[3], XtNscrollVertical, True ); + XtSetArg(htextargs[4], XtNfromVert, top->titlewidget); + XtSetArg(htextargs[5], XtNwidth, 660); + XtSetArg(htextargs[6], XtNheight, 350); + top->textwidget = XtCreateManagedWidget("helptext", + asciiTextWidgetClass, top->formwidget, htextargs, + XtNumber(htextargs)); + + if (top->subtopics) { + XtSetArg(labelargs[0], XtNfromVert, top->textwidget); + XtSetArg(labelargs[1], XtNvertDistance, 8); + XtSetArg(labelargs[2], XtNlabel, "Subtopics: "); + top->sublabelwidget = XtCreateManagedWidget("sublabel", + labelWidgetClass, top->formwidget, labelargs, XtNumber(labelargs)); + + XtSetArg(bboxargs[0], XtNwidth, 400); + XtSetArg(bboxargs[1], XtNallowResize, True); + XtSetArg(bboxargs[2], XtNfromVert, top->sublabelwidget); + top->subboxwidget = XtCreateManagedWidget("buttonbox", + boxWidgetClass, top->formwidget, bboxargs, XtNumber(bboxargs)); + + for (tl = top->subtopics; tl; tl = tl->next) { + tl->button.text = tl->description; + tl->button.tag = tl->place; + if (!tl->button.text) + tl->button.text = ""; + + XtSetArg(buttonargs[0], XtNlabel, tl->button.text); + buttonwidget = XtCreateManagedWidget(tl->button.text, + commandWidgetClass, top->subboxwidget, buttonargs, + XtNumber(buttonargs)); + /* core leak XXX */ + hand = (handle *) calloc(1, sizeof (struct handle)); + hand->result = tl; + hand->parent = top; + XtAddCallback(buttonwidget, XtNcallback, (XtCallbackProc) newtopic, hand); + } + } + + if (top->seealso) { + if (top->subtopics) + XtSetArg(labelargs[0], XtNfromVert, top->subboxwidget); + else + XtSetArg(labelargs[0], XtNfromVert, top->textwidget); + XtSetArg(labelargs[1], XtNvertDistance, 8); + XtSetArg(labelargs[2], XtNlabel, "See also: "); + top->seelabelwidget = XtCreateManagedWidget("seelabel", + labelWidgetClass, top->formwidget, labelargs, XtNumber(labelargs)); + + XtSetArg(bboxargs[0], XtNwidth, 400); + XtSetArg(bboxargs[1], XtNallowResize, True); + XtSetArg(bboxargs[2], XtNfromVert, top->seelabelwidget); + top->seeboxwidget = XtCreateManagedWidget("buttonbox", + boxWidgetClass, top->formwidget, bboxargs, XtNumber(bboxargs)); + + for (tl = top->seealso; tl; tl = tl->next) { + tl->button.text = tl->description; + tl->button.tag = tl->place; + if (!tl->button.text) + tl->button.text = ""; + + XtSetArg(buttonargs[0], XtNlabel, tl->button.text); + buttonwidget = XtCreateManagedWidget(tl->button.text, + commandWidgetClass, top->seeboxwidget, buttonargs, 1); + hand = (handle *) calloc(1, sizeof (struct handle)); + /* core leak XXX */ + hand->result = tl; + hand->parent = top; + XtAddCallback(buttonwidget, XtNcallback, (XtCallbackProc) newtopic, hand); + } + } + + XtRealizeWidget(top->shellwidget); + + top->winlink = topics; + topics = top; + + return (TRUE); + +} + +void +newtopic(Widget w, caddr_t client_data, caddr_t call_data) +{ + topic *parent = ((handle *) client_data)->parent; + toplink *result = ((handle *) client_data)->result; + topic *newtop; + + if (!(newtop = hlp_read(result->place))) { + fprintf(stderr, "Internal error: bad link\n"); + } + + newtop->next = parent->children; + parent->children = newtop; + newtop->parent = parent; + newtop->xposition = parent->xposition + 50; + newtop->yposition = parent->yposition + 50; + if (!hlp_xdisplay(newtop)) { + fprintf(stderr, "Couldn't open win\n"); + return; + } +} + +void +delete(Widget w, caddr_t client_data, caddr_t call_data) +{ + + topic *top = (topic *) client_data; + + hlp_killfamily(top); + hlp_fixchildren(top); +} + +void +quit(Widget w, caddr_t client_data, caddr_t call_data) +{ + + topic *top = (topic *) client_data, *parent = top->parent; + + while (parent && parent->parent) parent = parent->parent; + hlp_killfamily(parent ? parent : top); +} + +void +hlp_xkillwin(topic *top) +{ + topic *last; + + if (top == topics) + topics = top->winlink; + else if (top->winlink) { /* we need this check for the + pathological case where you have two helps running, + normally hp_killfamily doesn't let this happen */ + for (last = topics; last->winlink; last = last->winlink) + if (last->winlink == top) { + last->winlink = top->winlink; + break; + } + if (!last->winlink) { + fprintf(stderr, "window not in list!!\n"); + return; + } + } + XtDestroyWidget(top->shellwidget); + return; +} + +/* rip out font changes and write at end of buffer */ +static void +sputline(char *buf, char *s) +{ + + char tmp[BSIZE_SP], *tmpp; + int i = 0; + + while (*s) { + if (((*s == '\033') && s[1]) || + ((*s == '_') && (s[1] == '\b'))) + s += 2; + else + tmp[i++] = *s++; + } + tmp[i] = '\0'; + + /* strcat can't handle long strings */ + tmpp = buf + strlen(buf); + sprintf(tmpp, "%s\n", tmp); + + return; +} + +#endif /* X_DISPLAY_MISSING */ diff --git a/src/hlp/xdisplay.c b/src/hlp/xdisplay.c new file mode 100644 index 000000000..6b86f85da --- /dev/null +++ b/src/hlp/xdisplay.c @@ -0,0 +1,34 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +Modified 1999 Emmanuel Rouat +**********/ + +#include +#include "ngspice.h" +#include "cpstd.h" +#include "hlpdefs.h" +#include "suffix.h" + + +char *hlp_boldfontname = BOLD_FONT; +char *hlp_regfontname = REG_FONT; +char *hlp_italicfontname = ITALIC_FONT; +char *hlp_titlefontname = TITLE_FONT; +char *hlp_buttonfontname = BUTTON_FONT; +char *hlp_displayname = NULL; +int hlp_initxpos = START_XPOS; +int hlp_initypos = START_YPOS; +int hlp_buttonstyle = BS_LEFT; + + + +#ifdef X_DISPLAY_MISSING +/* ARGSUSED */ bool hlp_xdisplay(topic *top) { return (FALSE); } +/* ARGSUSED */ void hlp_xkillwin(topic *top) { } +#endif + +/* ARGSUSED */ void hlp_xwait(topic *top, bool on) { } +void hlp_xclosedisplay(void) {} +toplink * hlp_xhandle(topic **pp) { *pp = NULL; return (NULL); } + diff --git a/src/include/ChangeLog b/src/include/ChangeLog new file mode 100644 index 000000000..1dacb9d72 --- /dev/null +++ b/src/include/ChangeLog @@ -0,0 +1,98 @@ +1999-11-30 Emmanuel Rouat + + * ngspice.h: substitutes spice.h + +1999-09-08 Arno + + * distodef.h: added prototypes for derivative functions, retained + only ANSI conforming prototypes. + +1999-09-07 Arno + + * ifsim.h: changed the typedef for IFuid from GENERIC to char *. + +1999-09-06 Arno Peters + + * fteext.h: changed parameters and return values for math functions from + char * to void *. + +1999-09-04 Emmanuel Rouat + + * Makefile.am (noinst_HEADERS): removed patchlev.h + added ngspice.h + +1999-09-03 Emmanuel Rouat + + * ngspice.h: added this generic header file (will eventually replace + spice.h) + +1999-08-28 Emmanuel Rouat + + * cpstd.h: now #includes spice.h instead of misc.h + + * spice.h: removed capabil.h from #includes + #includes "hw_ieee.h" instead of "hw.h" (removes vms support) + merged spice.h with misc.h and util.h + + * misc.h: suppressed code related to HAS_MEMAVL and HAS_BSDRAND + +1999-08-26 Paolo Nenzi + + * spmatrix.h: added externs for spOriginalCount + +1999-08-19 Paolo Nenzi + * fteext.h: patched for spec command downloaded from: + ftp://ftp.mpce.mq.edu.au/pub/elec/spice/patches. + +1999-08-12 Emmanuel Rouat + + * hlpdefs.h: ansi-fied function declarations + + * complex.h (C_NORM): fixed a bug in C_NORM macros + +1999-10-08 Paolo Nenzi + * cktdefs.h: removed non STDC definitions and converted to ANSI + prototypes the functions. Marked with ??? the circuit elements + whose function is unknown. If you know their meaning, please write + me an email describing it. Thank you. + + * complex.h: Removed HAS_SHORTMACRO definitions. Defined macros + should be better documented. + +1999-08-08 Emmanuel Rouat + + * spice.h: removed 'porth.h' from #includes - now everything + shold be handled by autoconf + +1999-08-07 Emmanuel Rouat + + * strext.h: changed HAS_STRINGS into STDC_HEADERS (reversed) + +1999-08-06 Emmanuel Rouat + + * capabil.h: removed X10 defines + + * misc.h: removed test on HAS_VPERROR + removed test on HAS_CLEARERR + +1999-08-05 Emmanuel Rouat + + * util.h: + * misc.h: changed HAS_STDLIB to STDC_HEADERS + + * spice.h: removed 'port.h' from includes + +1999-08-04 Emmanuel Rouat + + * mfb.h: changed HAS_STAT into STAT_MACROS_BROKEN + +04-08-1999 Paolo Nenzi + + * changed trcvdefs.h: now includes the TEMP code for the temperature + sweep code supplied by Serban-Mihai Popescu. + +29-07-1999 emmanuel.rouat@wanadoo.fr (Manu Rouat) + + * removed old config.h (used my ms-dos only) to avoid confusion + with autoconf config.h + diff --git a/src/include/Makefile.am b/src/include/Makefile.am new file mode 100644 index 000000000..45b7561a3 --- /dev/null +++ b/src/include/Makefile.am @@ -0,0 +1,59 @@ +## Process this file with automake to produce Makefile.in + +noinst_HEADERS = \ + acdefs.h \ + arch.h \ + cktdefs.h \ + complex.h \ + const.h \ + cpdefs.h \ + cpextern.h \ + cpstd.h \ + defines.h \ + devdefs.h \ + dgen.h \ + distodef.h \ + ftecmath.h \ + fteconst.h \ + ftedata.h \ + ftedbgra.h \ + ftedebug.h \ + ftedefs.h \ + ftedev.h \ + fteext.h \ + ftegraf.h \ + ftegraph.h \ + ftehelp.h \ + fteinp.h \ + fteinput.h \ + fteparse.h \ + gendefs.h \ + hlpdefs.h \ + iferrmsg.h \ + ifsim.h \ + inpdefs.h \ + inpmacs.h \ + inpptree.h \ + jobdefs.h \ + macros.h \ + missing_math.h \ + ngspice.h \ + noisedef.h \ + opdefs.h \ + optdefs.h \ + pzdefs.h \ + sen2defs.h \ + sensdefs.h \ + sensgen.h \ + smpdefs.h \ + spconfig.h \ + sperror.h \ + spmatrix.h \ + struct.h \ + suffix.h \ + tfdefs.h \ + trandefs.h \ + trcvdefs.h \ + tskdefs.h + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/include/acdefs.h b/src/include/acdefs.h new file mode 100644 index 000000000..3a670fa44 --- /dev/null +++ b/src/include/acdefs.h @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef ACDEFS +#define ACDEFS + +#include "jobdefs.h" + + /* structure used to describe an AC analysis to be performed */ + +typedef struct { + int JOBtype; + JOB *JOBnextJob; /* pointer to next thing to do */ + char *JOBname; /* name of this job */ + double ACstartFreq; + double ACstopFreq; + double ACfreqDelta; /* multiplier for decade/octave stepping, */ + /* step for linear steps. */ + double ACsaveFreq; /* frequency at which we left off last time*/ + int ACstepType; /* values described below */ + int ACnumberSteps; +} ACAN; + +/* available step types: XXX should be somewhere else */ + +#define DECADE 1 +#define OCTAVE 2 +#define LINEAR 3 + +#define AC_DEC 1 +#define AC_OCT 2 +#define AC_LIN 3 +#define AC_START 4 +#define AC_STOP 5 +#define AC_STEPS 6 + +#endif /*ACDEFS*/ diff --git a/src/include/arch.h b/src/include/arch.h new file mode 100644 index 000000000..172cb6894 --- /dev/null +++ b/src/include/arch.h @@ -0,0 +1,27 @@ +/********** +Copyright 1993 Regents of the University of California. All rights reserved. +Author: 1993 David A. Gates +**********/ +/* + */ +#ifndef ARCH +#define ARCH + +#ifdef PARALLEL_ARCH +#include "sndrcv.h" +#include "evlog.h" + +#define MT_LOAD 100 +#define MT_ACLOAD 200 +#define MT_PZLOAD 300 +#define MT_TRANAN 400 +#define MT_TRUNC 500 +#define MT_COMBINE 600 +#define MT_CONV 700 +#define MT_ASK 800 +#endif /* PARALLEL_ARCH */ + +extern int ARCHme; /* My logical process number */ +extern int ARCHsize; /* Total number of processes */ + +#endif /* ARCH */ diff --git a/src/include/cktdefs.h b/src/include/cktdefs.h new file mode 100644 index 000000000..b4d20bce8 --- /dev/null +++ b/src/include/cktdefs.h @@ -0,0 +1,339 @@ +/* + * Copyright (c) 1985 Thomas L. Quarles + * Modified 1999 Paolo Nenzi - Removed non STDC definitions + */ +#ifndef CKT +#define CKT "CKTdefs.h $Revision$ on $Date$ " + +#define MAXNUMDEVS 32 /* Max number of possible devices; */ +extern int DEVmaxnum; /* Not sure if still used */ +#define MAXNUMDEVNODES 4 /* Max No. of nodes per device */ + /* Need to change for SOI devs ? */ + +#include "smpdefs.h" +#include "ifsim.h" +#include "acdefs.h" +#include "gendefs.h" +#include "trcvdefs.h" +#include "optdefs.h" +#include "sen2defs.h" +#include "pzdefs.h" +#include "noisedef.h" + + + +typedef struct sCKTnode { + IFuid name; + int type; + +#define SP_VOLTAGE 3 +#define SP_CURRENT 4 +#define NODE_VOLTAGE SP_VOLTAGE +#define NODE_CURRENT SP_CURRENT + + int number; /* Number of the node */ + double ic; /* Value of the initial condition */ + double nodeset; /* Value of the .nodeset option */ + double *ptr; /* ??? */ + struct sCKTnode *next; /* pointer to the next node */ + unsigned int icGiven:1; /* FLAG ic given */ + unsigned int nsGiven:1; /* FLAG nodeset given */ +} CKTnode; + +/* defines for node parameters */ +#define PARM_NS 1 +#define PARM_IC 2 +#define PARM_NODETYPE 3 + + + +typedef struct { + GENmodel *CKThead[MAXNUMDEVS]; /* The max number of loadable devices */ + STATistics *CKTstat; /* The STATistics structure */ + double *(CKTstates[8]); /* Used as memory of past steps ??? */ + + /* Some shortcut for CKTstates */ +#define CKTstate0 CKTstates[0] +#define CKTstate1 CKTstates[1] +#define CKTstate2 CKTstates[2] +#define CKTstate3 CKTstates[3] +#define CKTstate4 CKTstates[4] +#define CKTstate5 CKTstates[5] +#define CKTstate6 CKTstates[6] +#define CKTstate7 CKTstates[7] + double CKTtime; /* ??? */ + double CKTdelta; /* ??? */ + double CKTdeltaOld[7]; /* Memory for ??? */ + double CKTtemp; /* Actual temperature of CKT */ + double CKTnomTemp; /* Reference temperature 27 C ? */ + double CKTvt; /* Thernmal voltage at CKTtemp */ + double CKTag[7]; /* the gear variable coefficient matrix */ +#ifdef PREDICTOR + double CKTagp[7]; /* the gear predictor variable coefficient matrix */ +#endif /*PREDICTOR*/ + int CKTorder; /* the integration method order */ + int CKTmaxOrder; /* maximum integration method order */ + int CKTintegrateMethod; /* the integration method to be used */ + +/* known integration methods */ +#define TRAPEZOIDAL 1 +#define GEAR 2 + + SMPmatrix *CKTmatrix; /* pointer to sparse matrix */ + int CKTniState; /* internal state */ + double *CKTrhs; /* current rhs value - being loaded */ + double *CKTrhsOld; /* previous rhs value for convergence testing */ + double *CKTrhsSpare; /* spare rhs value for reordering */ + double *CKTirhs; /* current rhs value - being loaded (imag) */ + double *CKTirhsOld; /* previous rhs value (imaginary)*/ + double *CKTirhsSpare; /* spare rhs value (imaginary)*/ +#ifdef PREDICTOR + double *CKTpred; /* predicted solution vector */ + double *CKTsols[8]; /* previous 8 solutions */ +#endif /* PREDICTOR */ + + double *CKTrhsOp; /* opearating point values */ + double *CKTsenRhs; /* current sensitivity rhs values */ + double *CKTseniRhs; /* current sensitivity rhs values (imag)*/ + + +/* + * symbolic constants for CKTniState + * Note that they are bitwise disjoint + * What is their meaning ???? + */ + +#define NISHOULDREORDER 0x1 +#define NIREORDERED 0x2 +#define NIUNINITIALIZED 0x4 +#define NIACSHOULDREORDER 0x10 +#define NIACREORDERED 0x20 +#define NIACUNINITIALIZED 0x40 +#define NIDIDPREORDER 0x100 +#define NIPZSHOULDREORDER 0x200 + + int CKTmaxEqNum; /* And this ? */ + int CKTcurrentAnalysis; /* the analysis in progress (if any) */ + +/* defines for the value of CKTcurrentAnalysis */ +/* are in TSKdefs.h */ + + CKTnode *CKTnodes; /* ??? */ + CKTnode *CKTlastNode; /* ??? */ + + /* This define should be somewhere else ??? */ +#define NODENAME(ckt,nodenum) CKTnodName(ckt,nodenum) + int CKTnumStates; /* Number of sates effectively valid ??? */ + long CKTmode; /* Mode of operation of the circuit ??? */ + +/* defines for CKTmode */ + +/* old 'mode' parameters */ +#define MODE 0x3 +#define MODETRAN 0x1 +#define MODEAC 0x2 + +/* old 'modedc' parameters */ +#define MODEDC 0x70 +#define MODEDCOP 0x10 +#define MODETRANOP 0x20 +#define MODEDCTRANCURVE 0x40 + +/* old 'initf' parameters */ +#define INITF 0x3f00 +#define MODEINITFLOAT 0x100 +#define MODEINITJCT 0x200 +#define MODEINITFIX 0x400 +#define MODEINITSMSIG 0x800 +#define MODEINITTRAN 0x1000 +#define MODEINITPRED 0x2000 + +/* old 'nosolv' paramater */ +#define MODEUIC 0x10000l + + int CKTbypass; /* bypass option, how does it work ? */ + int CKTdcMaxIter; /* iteration limit for dc op. (itl1) */ + int CKTdcTrcvMaxIter; /* iteration limit for dc tran. curv (itl2) */ + int CKTtranMaxIter; /* iteration limit for each timepoint for tran*/ + /* (itl4) */ + int CKTbreakSize; /* ??? */ + int CKTbreak; /* ??? */ + double CKTsaveDelta; /* ??? */ + double CKTminBreak; /* ??? */ + double *CKTbreaks; /* List of breakpoints ??? */ + double CKTabstol; /* --- */ + double CKTpivotAbsTol; /* --- */ + double CKTpivotRelTol; /* --- */ + double CKTreltol; /* --- */ + double CKTchgtol; /* --- */ + double CKTvoltTol; /* --- */ + /* What is this define for ? */ +#ifdef NEWTRUNC + double CKTlteReltol; + double CKTlteAbstol; +#endif /* NEWTRUNC */ + double CKTgmin; /* Parallel Conductance --- */ + double CKTdelmin; /* ??? */ + double CKTtrtol; /* ??? */ + double CKTfinalTime; /* ??? */ + double CKTstep; /* ??? */ + double CKTmaxStep; /* ??? */ + double CKTinitTime; /* ??? */ + double CKTomega; /* ??? */ + double CKTsrcFact; /* ??? */ + double CKTdiagGmin; /* ??? */ + int CKTnumSrcSteps; /* ??? */ + int CKTnumGminSteps; /* ??? */ + int CKTnoncon; /* ??? */ + double CKTdefaultMosL; /* Default Channel Lenght of MOS devices */ + double CKTdefaultMosW; /* Default Channel Width of MOS devics */ + double CKTdefaultMosAD; /* Default Drain Area of MOS */ + double CKTdefaultMosAS; /* Default Source Area of MOS */ + unsigned int CKThadNodeset:1; /* ??? */ + unsigned int CKTfixLimit:1; /* flag to indicate that the limiting of + * MOSFETs should be done as in SPICE2 */ + unsigned int CKTnoOpIter:1; /* flag to indicate not to try the operating + * point brute force, but to use gmin stepping + * first */ + unsigned int CKTisSetup:1; /* flag to indicate if CKTsetup done */ + JOB *CKTcurJob; /* Next analysis to be performed ??? */ + + SENstruct *CKTsenInfo; /* the sensitivity information */ + double *CKTtimePoints; /* list of all accepted timepoints in the + current transient simulation */ + double *CKTdeltaList; /* list of all timesteps in the current + transient simulation */ + int CKTtimeListSize; /* size of above lists */ + int CKTtimeIndex; /* current position in above lists */ + int CKTsizeIncr; /* amount to increment size of above arrays + when you run out of space */ + unsigned int CKTtryToCompact:1; /* try to compact past history for LTRA + lines */ + unsigned int CKTbadMos3:1; /* Use old, unfixed MOS3 equations */ + unsigned int CKTkeepOpInfo:1; /* flag for small signal analyses */ + int CKTtroubleNode; /* Non-convergent node number */ + GENinstance *CKTtroubleElt; /* Non-convergent device instance */ + +} CKTcircuit; + +/* Now function prottypes */ + +extern int ACan( CKTcircuit *, int ); +extern int ACaskQuest( CKTcircuit *, void *, int , IFvalue *); +extern int ACsetParm( CKTcircuit *, void *, int , IFvalue *); +extern int CKTacDump( CKTcircuit *, double , void *); +extern int CKTacLoad( CKTcircuit *); +extern int CKTaccept( CKTcircuit *); +extern int CKTacct( CKTcircuit *, void *, int , IFvalue *); +extern int CKTask( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTaskAnalQ( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTaskNodQst( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTbindNode( void *, void *, int , void *); +extern void CKTbreakDump( CKTcircuit *); +extern int CKTclrBreak( CKTcircuit *); +extern int CKTconvTest( CKTcircuit *); +extern int CKTcrtElt( void *, void *, void **, IFuid ); +extern int CKTdelTask( void *, void *); +extern int CKTdestroy( void *); +extern int CKTdltAnal( void *, void *, void *); +extern int CKTdltInst( void *, void *); +extern int CKTdltMod( void *, void *); +extern int CKTdltNod( void *, void *); +extern int CKTdoJob( void *, int , void *); +extern void CKTdump( CKTcircuit *, double, void *); +extern int CKTfndAnal( void *, int *, void **, IFuid , void *, IFuid ); +extern int CKTfndBranch( CKTcircuit *, IFuid); +extern int CKTfndDev( void *, int *, void **, IFuid , void *, IFuid ); +extern int CKTfndMod( void *, int *, void **, IFuid ); +extern int CKTfndNode( void *, void **, IFuid ); +extern int CKTfndTask( void *, void **, IFuid ); +extern int CKTground( void *, void **, IFuid ); +extern int CKTic( CKTcircuit *); +extern int CKTinit( void **); +extern int CKTinst2Node( void *, void *, int , void **, IFuid *); +extern int CKTlinkEq(CKTcircuit*,CKTnode*); +extern int CKTload( CKTcircuit *); +extern int CKTmapNode( void *, void **, IFuid ); +extern int CKTmkCur( CKTcircuit *, CKTnode **, IFuid , char *); +extern int CKTmkNode(CKTcircuit*,CKTnode**); +extern int CKTmkVolt( CKTcircuit *, CKTnode **, IFuid , char *); +extern int CKTmodAsk( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTmodCrt( void *, int , void **, IFuid ); +extern int CKTmodParam( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTnames(CKTcircuit *, int *, IFuid **); +extern int CKTnewAnal( void *, int , IFuid , void **, void *); +extern int CKTnewEq( void *, void **, IFuid ); +extern int CKTnewNode( void *, void **, IFuid ); +extern int CKTnewTask( void *, void **, IFuid ); +extern int CKTnoise (CKTcircuit *ckt, int mode, int operation, Ndata *data); +extern IFuid CKTnodName( CKTcircuit *, int ); +extern void CKTnodOut( CKTcircuit *); +extern CKTnode * CKTnum2nod( CKTcircuit *, int ); +extern int CKTop(CKTcircuit *, long, long, int ); +extern int CKTpModName( char *, IFvalue *, CKTcircuit *, int , IFuid , GENmodel **); +extern int CKTpName( char *, IFvalue *, CKTcircuit *, int , char *, GENinstance **); +extern int CKTparam( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTpartition(register CKTcircuit *ckt); +extern int CKTpzFindZeros( CKTcircuit *, PZtrial **, int * ); +extern int CKTpzLoad( CKTcircuit *, SPcomplex * ); +extern int CKTpzSetup( CKTcircuit *, int); +extern int CKTsenAC( CKTcircuit *); +extern int CKTsenComp( CKTcircuit *); +extern int CKTsenDCtran( CKTcircuit *); +extern int CKTsenLoad( CKTcircuit *); +extern void CKTsenPrint( CKTcircuit *); +extern int CKTsenSetup( CKTcircuit *); +extern int CKTsenUpdate( CKTcircuit *); +extern int CKTsetAnalPm( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTsetBreak( CKTcircuit *, double ); +extern int CKTsetNodPm( void *, void *, int , IFvalue *, IFvalue *); +extern int CKTsetOpt( void *, void *, int , IFvalue *); +extern int CKTsetup( CKTcircuit *); +extern int CKTunsetup(CKTcircuit *ckt); +extern int CKTtemp( CKTcircuit *); +extern char *CKTtrouble(void *, char *); +extern void CKTterr( int , CKTcircuit *, double *); +extern int CKTtrunc( CKTcircuit *, double *); +extern int CKTtypelook( char *); +extern int DCOaskQuest( CKTcircuit *, void *, int , IFvalue *); +extern int DCOsetParm( CKTcircuit *, void *, int , IFvalue *); +extern int DCTaskQuest( CKTcircuit *, void *, int , IFvalue *); +extern int DCTsetParm( CKTcircuit *, void *, int , IFvalue *); +extern int DCop( CKTcircuit *); +extern int DCtrCurv( CKTcircuit *, int ); +extern int DCtran( CKTcircuit *, int ); +extern int DISTOan(CKTcircuit *, int); +extern int NOISEan(CKTcircuit *, int); +extern int PZan( CKTcircuit *, int ); +extern int PZinit( CKTcircuit * ); +extern int PZpost( CKTcircuit * ); +extern int PZaskQuest( CKTcircuit *, void *, int , IFvalue *); +extern int PZsetParm( CKTcircuit *, void *, int , IFvalue *); +extern int SENaskQuest( CKTcircuit *, void *, int , IFvalue *); +extern void SENdestroy( SENstruct *); +extern int SENsetParm( CKTcircuit *, void *, int , IFvalue *); +extern int SENstartup( CKTcircuit *); +extern int SPIinit( IFfrontEnd *, IFsimulator **); +extern char * SPerror( int ); +extern int TFanal( CKTcircuit *, int ); +extern int TFaskQuest( CKTcircuit *, void *, int , IFvalue *); +extern int TFsetParm( CKTcircuit *, void *, int , IFvalue *); +extern int TRANaskQuest( CKTcircuit *, void *, int , IFvalue *); +extern int TRANsetParm( CKTcircuit *, void *, int , IFvalue *); +extern int TRANinit(CKTcircuit *, JOB *); +extern int NIacIter( CKTcircuit * ); +extern int NIcomCof( CKTcircuit * ); +extern int NIconvTest(CKTcircuit * ); +extern void NIdestroy(CKTcircuit * ); +extern int NIinit( CKTcircuit * ); +extern int NIintegrate( CKTcircuit *, double *, double *, double , int ); +extern int NIiter( CKTcircuit * , int ); +extern int NIpzMuller(PZtrial **, PZtrial *); +extern int NIpzComplex(PZtrial **, PZtrial *); +extern int NIpzSym(PZtrial **, PZtrial *); +extern int NIpzSym2(PZtrial **, PZtrial *); +extern int NIreinit( CKTcircuit *); +extern int NIsenReinit( CKTcircuit *); +extern IFfrontEnd *SPfrontEnd; + +#endif /*CKT*/ diff --git a/src/include/complex.h b/src/include/complex.h new file mode 100644 index 000000000..5aff8e5c4 --- /dev/null +++ b/src/include/complex.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 1985 Thomas L. Quarles + * Modified: Paolo Nenzi 1999 + */ +#ifndef CMPLX +#define CMPLX "complex.h $Revision$ on $Date$ " + +/* header file containing definitions for complex functions + * + * Each expects two arguments for each complex number - a real and an + * imaginary part. + */ +typedef struct { + double real; + double imag; +} SPcomplex; + + +#define DC_ABS(a,b) (fabs(a) + fabs(b)) + +/* Why that ??? */ +#ifdef notdef +#define DC_DIV(a,b,c,d,x,y) { \ + double r,s;\ + if(fabs(c)>fabs(d)) { \ + r=(d)/(c);\ + s=(c)+r*(d);\ + x=((a)+(b)*r)/s;\ + y=((b)-(a)*r)/s;\ + } else { \ + r=(c)/(d);\ + s=(d)+r*(c);\ + x=((a)*r+(b))/s;\ + y=((b)*r-(a))/s;\ + }\ +} +#endif /*notdef */ + +/* + * Division among complex numbers + */ +#define DC_DIVEQ(a,b,c,d) { \ + double r,s,x,y;\ + if(fabs(c)>fabs(d)) { \ + r=(d)/(c);\ + s=(c)+r*(d);\ + x=((*(a))+(*(b))*r)/s;\ + y=((*(b))-(*(a))*r)/s;\ + } else { \ + r=(c)/(d);\ + s=(d)+r*(c);\ + x=((*(a))*r+(*(b)))/s;\ + y=((*(b))*r-(*(a)))/s;\ + }\ + (*(a)) = x; \ + (*(b)) = y; \ +} + +/* + * This is the standard multiplication among complex numbers: + * (x+jy)=(a+jb)*(c+jd) + * x = ac - bd and y = ad + bc + */ +#define DC_MULT(a,b,c,d,x,y) { \ + *(x) = (a) * (c) - (b) * (d) ;\ + *(y) = (a) * (d) + (b) * (c) ;\ +} + + +/* Why that ??? */ +#ifdef notdef +#define DC_MINUS(a,b,c,d,x,y) { \ + (x) = (a) - (c) ;\ + (y) = (b) - (d) ;\ +} +#endif /*notdef*/ + +/* + * Difference among complex numbers a+jb and c+jd + * a = a - c amd b = b - d + */ +#define DC_MINUSEQ(a,b,c,d) { \ + *(a) -= (c) ;\ + *(b) -= (d) ;\ +} + +/* + * Square root among complex numbers + * We need to treat all the cases because the sqrt() function + * works only on real numbers. + */ +#define C_SQRT(A) { \ + double _mag, _a; \ + if ((A).imag == 0.0) { \ + if ((A).real < 0.0) { \ + (A).imag = sqrt(-(A).real); \ + (A).real = 0.0; \ + } else { \ + (A).real = sqrt((A).real); \ + (A).imag = 0.0; \ + } \ + } else { \ + _mag = sqrt((A).real * (A).real + (A).imag * (A).imag); \ + _a = (_mag - (A).real) / 2.0; \ + if (_a <= 0.0) { \ + (A).real = sqrt(_mag); \ + (A).imag /= (2.0 * (A).real); /*XXX*/ \ + } else { \ + _a = sqrt(_a); \ + (A).real = (A).imag / (2.0 * _a); \ + (A).imag = _a; \ + } \ + } \ + } + +/* + * This macro calculates the squared modulus of the complex number + * and return it as the real part of the same number: + * a+jb -> a = (a*a) + (b*b) + */ +#define C_MAG2(A) (((A).real = (A).real * (A).real + (A).imag * (A).imag), \ + (A).imag = 0.0) + +/* + * Two macros to obtain the colpex conjugate of a number, + * The first one replace the given complex with the conjugate, + * the second sets A as the conjugate of B. + */ +#define C_CONJ(A) ((A).imag *= -1.0) + +#define C_CONJEQ(A,B) { \ + (A).real = (B.real); \ + (A).imag = - (B.imag); \ + } + +/* + * Simple assignement + */ +#define C_EQ(A,B) { \ + (A).real = (B.real); \ + (A).imag = (B.imag); \ + } + +/* + * Normalization ??? + * + */ + + +#define C_NORM(A,B) { \ + if ((A).real == 0.0 && (A).imag == 0.0) { \ + (B) = 0; \ + } else { \ + while (fabs((A).real) > 1.0 || fabs((A).imag) > 1.0) { \ + (B) += 1; \ + (A).real /= 2.0; \ + (A).imag /= 2.0; \ + } \ + while (fabs((A).real) <= 0.5 && fabs((A).imag) <= 0.5) { \ + (B) -= 1; \ + (A).real *= 2.0; \ + (A).imag *= 2.0; \ + } \ + } \ + } + +/* + * The magnitude of the complex number + */ + +#define C_ABS(A) (sqrt((A).real * (A.real) + (A.imag * A.imag))) + +/* + * Standard arithmetic between complex numbers + * + */ + +#define C_MUL(A,B) { \ + double TMP1, TMP2; \ + TMP1 = (A.real); \ + TMP2 = (B.real); \ + (A).real = TMP1 * TMP2 - (A.imag) * (B.imag); \ + (A).imag = TMP1 * (B.imag) + (A.imag) * TMP2; \ + } + +#define C_MULEQ(A,B,C) { \ + (A).real = (B.real) * (C.real) - (B.imag) * (C.imag); \ + (A).imag = (B.real) * (C.imag) + (B.imag) * (C.real); \ + } + +#define C_DIV(A,B) { \ + double _tmp, _mag; \ + _tmp = (A.real); \ + (A).real = _tmp * (B.real) + (A).imag * (B.imag); \ + (A).imag = - _tmp * (B.imag) + (A.imag) * (B.real); \ + _mag = (B.real) * (B.real) + (B.imag) * (B.imag); \ + (A).real /= _mag; \ + (A).imag /= _mag; \ + } + +#define C_DIVEQ(A,B,C) { \ + double _mag; \ + (A).real = (B.real) * (C.real) + (B.imag) * (C.imag); \ + (A).imag = (B.imag) * (C.real) - (B.real) * (C.imag) ; \ + _mag = (C.real) * (C.real) + (C.imag) * (C.imag); \ + (A).real /= _mag; \ + (A).imag /= _mag; \ + } + +#define C_ADD(A,B) { \ + (A).real += (B.real); \ + (A).imag += (B.imag); \ + } + +#define C_ADDEQ(A,B,C) { \ + (A).real = (B.real) + (C.real); \ + (A).imag = (B.imag) + (C.imag); \ + } + +#define C_SUB(A,B) { \ + (A).real -= (B.real); \ + (A).imag -= (B.imag); \ + } + +#define C_SUBEQ(A,B,C) { \ + (A).real = (B.real) - (C.real); \ + (A).imag = (B.imag) - (C.imag); \ + } + + + +#endif /*CMPLX*/ diff --git a/src/include/const.h b/src/include/const.h new file mode 100644 index 000000000..c03df6849 --- /dev/null +++ b/src/include/const.h @@ -0,0 +1,20 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ +#ifndef CONST +#define CONST + +#define CHARGE (1.6021918e-19) +#define CONSTCtoK (273.15) +#define CONSTboltz (1.3806226e-23) +#define REFTEMP 300.15 /* 27 degrees C */ + + extern double CONSTroot2; + extern double CONSTvt0; + extern double CONSTKoverQ; + extern double CONSTe; + +#endif /*CONST*/ diff --git a/src/include/cpdefs.h b/src/include/cpdefs.h new file mode 100644 index 000000000..f6b62f2d6 --- /dev/null +++ b/src/include/cpdefs.h @@ -0,0 +1,116 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * General stuff for the C-shell parser. + */ + +/* Standard definitions */ +#ifndef CPDEFS +#define CPDEFS + +#include "cpstd.h" + +#define MAXWORDS 512 + +/* Information about spice commands. */ + +struct comm { + char *co_comname; /* The name of the command. */ + void (*co_func) (); /* The function that handles the command. */ + bool co_stringargs; /* Collapse the arguments into a string. */ + bool co_spiceonly; /* These can't be used from nutmeg. */ + bool co_major; /* Is this a "major" command? */ + long co_cctypes[4]; /* Bitmasks for command completion. */ + unsigned int co_env;/* print help message on this environment mask */ + int co_minargs; /* minimum number of arguments required */ + int co_maxargs; /* maximum number of arguments allowed */ + int (*co_argfn) (); /* The fn that prompts the user. */ + char *co_help; /* When these are printed, printf(string, av[0]) .. */ +}; + +#define LOTS 1000 + +/* The history list. Things get put here after the first (basic) parse. + * The word list will change later, so be sure to copy it. + */ + +struct histent { + int hi_event; + wordlist *hi_wlist; + struct histent *hi_next; + struct histent *hi_prev; +}; + +/* Variables that are accessible to the parser via $varname expansions. + * If the type is VT_LIST the value is a pointer to a list of the elements. + */ + +struct variable { + char va_type; + char *va_name; + union { + bool vV_bool; + int vV_num; + double vV_real; + char *vV_string; + struct variable *vV_list; + } va_V; + struct variable *va_next; /* Link. */ +} ; + +#define va_bool va_V.vV_bool +#define va_num va_V.vV_num +#define va_real va_V.vV_real +#define va_string va_V.vV_string +#define va_vlist va_V.vV_list + +#define VT_BOOL 1 +#define VT_NUM 2 +#define VT_REAL 3 +#define VT_STRING 4 +#define VT_LIST 5 + +/* The values returned by cp_userset(). */ + +#define US_OK 1 /* Either not relevant or nothing special. */ +#define US_READONLY 2 /* Complain and don't set this var. */ +#define US_DONTRECORD 3 /* Ok, but don't keep track of this one. */ +#define US_SIMVAR 4 /* OK, recorded in options struct */ +#define US_NOSIMVAR 5 /* Not OK, simulation param but circuit not loaded */ + +/* Aliases. These will be expanded if the word is the first in an input + * line. The substitution string may contain arg selectors. + */ + +struct alias { + char *al_name; /* The word to be substituted for. */ + wordlist *al_text; /* What to substitute for it. */ + struct alias *al_next; + struct alias *al_prev; +} ; + +/* The current record of what characters are special. */ + +#define CPC_BRR 004 /* Break word to right of character. */ +#define CPC_BRL 010 /* Break word to left of character. */ + +/* For quoting individual characters. '' strings are all quoted, but `` and + * "" strings are maintained as single words with the quotes around them. + * Note that this won't work on non-ascii machines. + */ + +#define quote(c) ((c) | 0200) +#define strip(c) ((c) & 0177) + + +#define CT_ALIASES 1 +#define CT_LABEL 15 + +/* Get all the extern definitions... */ + +#include "cpextern.h" + +#endif /*CPDEFS*/ diff --git a/src/include/cpextern.h b/src/include/cpextern.h new file mode 100644 index 000000000..345b43aef --- /dev/null +++ b/src/include/cpextern.h @@ -0,0 +1,185 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Definitions for all external symbols in CP. + */ + +#ifndef CPEXTERN_H +#define CPEXTERN_H + +/* alias.c */ + +extern struct alias *cp_aliases; +extern void com_alias(); +extern void com_unalias(); +extern void cp_paliases(); +extern void cp_setalias(); +extern void cp_unalias(); +extern wordlist *cp_doalias(); + +/* backquote.c */ + +extern char cp_back; +extern wordlist *cp_bquote(); + +/* complete.c */ + +extern bool cp_nocc; +extern bool cp_comlook(char *word); +extern char *cp_kwswitch(int class, char *tree); +extern void cp_addcomm(char *word, long int bits0, long int bits1, long int bits2, long int bits3); +extern void cp_addkword(int class, char *word); +extern void cp_ccom(wordlist *wlist, char *buf, bool esc); +extern void cp_ccon(bool on); +extern void cp_ccrestart(bool kwords); +extern void cp_remcomm(char *word); +extern void cp_remkword(int class, char *word); +extern wordlist *cp_cctowl(char *stuff); + +/* cshpar.c */ + +extern FILE *cp_in; +extern FILE *cp_out; +extern FILE *cp_err; +extern FILE *cp_curin; +extern FILE *cp_curout; +extern FILE *cp_curerr; +extern bool cp_debug; +extern char cp_amp; +extern char cp_gt; +extern char cp_lt; +extern void com_chdir(); +extern void com_echo(); +extern void com_strcmp(); +extern void com_rehash(); +extern void com_shell(); +extern void cp_ioreset(); +extern wordlist *cp_redirect(); +extern wordlist *cp_parse(); + +/* front.c */ + +extern bool cp_cwait; +extern bool cp_dounixcom; +extern char *cp_csep; +extern int cp_evloop(char *string); +extern void com_cdump(wordlist *wl); +extern void cp_resetcontrol(void); +extern void cp_toplevel(void); +extern void cp_popcontrol(void); +extern void cp_pushcontrol(void); + +/* glob.c */ + +extern bool cp_globmatch(char *p, char *s); +extern char *cp_tildexpand(char *string); +extern char cp_cbrac; +extern char cp_ccurl; +extern char cp_comma; +extern char cp_huh; +extern char cp_obrac; +extern char cp_ocurl; +extern char cp_star; +extern char cp_til; +extern wordlist *cp_doglob(wordlist *wlist); + +/* history.c */ + +extern bool cp_didhsubst; +extern char cp_bang; +extern char cp_hat; +extern int cp_maxhistlength; +extern struct histent *cp_lastone; +extern void com_history(); +extern void cp_addhistent(); +extern void cp_hprint(); +extern wordlist *cp_histsubst(); + +/* lexical.c */ + +extern FILE *cp_inp_cur; +extern bool cp_bqflag; +extern bool cp_interactive; +extern char *cp_altprompt; +extern char *cp_promptstring; +extern char cp_hash; +extern int cp_event; +extern wordlist *cp_lexer(char *string); +extern int inchar(FILE *fp); + +/* modify.c */ + +extern char cp_chars[]; +extern void cp_init(void); + +/* output.c */ + +extern char out_pbuf[]; +extern bool out_moremode; +extern bool out_isatty; +extern void out_init(); +#ifndef out_printf +/* don't want to declare it if we have #define'ed it */ +extern void out_printf(); +#endif +extern void out_send(); + +/* quote.c */ + +extern char *cp_unquote(char *string); +extern void cp_quoteword(char *str); +extern void cp_striplist(wordlist *wlist); +extern void cp_wstrip(char *str); +extern void cp_printword(char *string, FILE *fp); + + + +/* unixcom.c */ + +extern bool cp_unixcom(); +extern void cp_hstat(); +extern void cp_rehash(); + +/* variable.c */ + + +extern bool cp_ignoreeof; +extern bool cp_noclobber; +extern bool cp_noglob; +extern bool cp_nonomatch; +extern char cp_dol; +extern void cp_remvar(char *varname); +extern void cp_vset(char *varname, char type, char *value); +extern wordlist *cp_varwl(struct variable *var); +extern struct variable *cp_setparse(wordlist *wl); + +/* var2.c */ +extern wordlist *vareval(char *string); +extern wordlist *cp_variablesubst(wordlist *wlist); +extern void cp_vprint(void); +extern void com_set(wordlist *wl); +extern void com_unset(wordlist *wl); +extern void com_shift(wordlist *wl); +extern bool cp_getvar(char *name, int type, char *retval); +extern wordlist *cp_variablesubst(wordlist *wlist); + +/* cpinterface.c etc -- stuff CP needs from FTE */ + +extern bool cp_istrue(); +extern bool cp_oddcomm(); +extern void cp_doquit(); +extern void cp_periodic(); +extern void ft_cpinit(); +extern struct comm *cp_coms; +extern double *ft_numparse(); +extern char *cp_program; +extern bool ft_nutmeg; +extern struct variable *cp_enqvar(); +extern void cp_usrvars(); +extern int cp_usrset(); +extern void fatal(); + +#endif diff --git a/src/include/cpstd.h b/src/include/cpstd.h new file mode 100644 index 000000000..d1dd24e56 --- /dev/null +++ b/src/include/cpstd.h @@ -0,0 +1,73 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Standard definitions. This file serves as the header file for std.c and + * wlist.c + */ + +#ifndef _STD_H_ +#define _STD_H_ + +typedef int bool; + + +#ifndef FILE +/* XXX Bogus */ +# include +#endif + +/* Doubly linked lists of words. */ + +struct wordlist { + char *wl_word; + struct wordlist *wl_next; + struct wordlist *wl_prev; +} ; + +typedef struct wordlist wordlist; + +/* Complex numbers. */ + +struct _complex { /* IBM portability... */ + double cx_real; + double cx_imag; +} ; + +typedef struct _complex complex; + +#define realpart(cval) ((struct _complex *) (cval))->cx_real +#define imagpart(cval) ((struct _complex *) (cval))->cx_imag + +/* Externs defined in std.c */ + +extern char *getusername(); +extern char *gethome(); +extern char *tildexpand(); +extern char *printnum(); +extern int cp_numdgt; +extern void fatal(); + +/* extern void setenv(); */ + +extern void cp_printword(); + +/* Externs from wlist.c */ + +extern char **wl_mkvec(); +extern char *wl_flatten(); +extern int wl_length(); +extern void wl_free(); +extern void wl_print(); +extern void wl_sort(); +extern wordlist *wl_append(); +extern wordlist *wl_build(); +extern wordlist *wl_copy(); +extern wordlist *wl_range(); +extern wordlist *wl_nthelem(); +extern wordlist *wl_reverse(); +extern wordlist *wl_splice(); + +#endif /* _STD_H_*/ diff --git a/src/include/defines.h b/src/include/defines.h new file mode 100644 index 000000000..f519e467f --- /dev/null +++ b/src/include/defines.h @@ -0,0 +1,126 @@ +/************* + * Definitions header file + * 1999 E. Rouat + ************/ + +/* + * This file will contain all #defines needed + * by ngspice code (in construction) + * It should only #define numeric constants, not macros. + */ + + +#ifndef _DEFINES_H_ +#define _DEFINES_H_ + + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif +#ifndef M_E +# define M_E 2.7182818284590452354 +#endif +#ifndef M_LOG2E +# define M_LOG2E 1.4426950408889634074 +#endif +#ifndef M_LOG10E +# define M_LOG10E 0.43429448190325182765 +#endif + + +/* + * IEEE Floating point + */ + +#define MAX_EXP_ARG 709.0 + +#ifndef DBL_EPSILON +# define DBL_EPSILON 8.9e-15 +#endif +#ifndef DBL_MAX +# define DBL_MAX 1.79769313486231e+308 +#endif +#ifndef DBL_MIN +# define DBL_MIN 2.22507385850721e-308 +#endif +#ifndef SHRT_MAX +# define SHRT_MAX 32766 +#endif +#ifndef INT_MAX +# define INT_MAX 2147483646 +#endif +#ifndef LONG_MAX +# define LONG_MAX 2147483646 +#endif + +#define MAXPOSINT INT_MAX + +/* + * Physical constants (const.h) + */ + +#define CHARGE (1.6021918e-19) +#define CONSTCtoK (273.15) +#define CONSTboltz (1.3806226e-23) +#define REFTEMP 300.15 /* 27 degrees C */ + + + +#define DIR_PATHSEP "/" +#define DIR_TERM '/' +#define DIR_CWD "." + +#define TEMPFORMAT "/tmp/%s%d" +#define SYSTEM_PLOT5LPR "lpr -P%s -g %s" +#define SYSTEM_PSLPR "lpr -P%s %s" +#define SYSTEM_MAIL "Mail -s \"%s (%s) Bug Report\" %s" + + +/* + * #define-s that are always on + */ + +#define CAPZEROBYPASS +#define NEWCONV +/* #define CAPBYPASS Internal use only */ + + +/* On Unix the following should always be true, so they should jump out */ + +#define HAS_ASCII +#define HAS_TTY_ +#define HAS_TIME_ +#define HAS_RLIMIT_ + + + +#ifndef SIGNAL_FUNCTION +# define SIGNAL_FUNCTION RETSIGTYPE (*)( ) +#endif + +#define BSIZE_SP 512 + + +#define EXIT_NORMAL 0 +#define EXIT_BAD 1 + +#define TRUE 1 +#define FALSE 0 + + + +#define DIR_PATHSEP "/" +#define DIR_TERM '/' +#define DIR_CWD "." + +#define TEMPFORMAT "/tmp/%s%d" +#define SYSTEM_PLOT5LPR "lpr -P%s -g %s" +#define SYSTEM_PSLPR "lpr -P%s %s" +#define SYSTEM_MAIL "Mail -s \"%s (%s) Bug Report\" %s" + + + + + +#endif /* _DEFINES_H_ */ + diff --git a/src/include/devdefs.h b/src/include/devdefs.h new file mode 100644 index 000000000..739a7a877 --- /dev/null +++ b/src/include/devdefs.h @@ -0,0 +1,197 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef DEV +#define DEV + +#include "optdefs.h" +#include "gendefs.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "noisedef.h" +#include "complex.h" + +#ifdef __STDC__ +double DEVlimvds(double,double); +double DEVpnjlim(double,double,double,double,int*); +double DEVfetlim(double,double,double); +void DEVcmeyer(double,double,double,double,double,double,double,double,double, + double,double,double*,double*,double*,double,double,double,double); +void DEVqmeyer(double,double,double,double,double,double*,double*,double*, + double,double); +#ifdef notdef +void DEVcap(CKTcircuit*, double, double, double, double, double, double, + double, double, double, double, double, double, double, double, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double, double, + double, double*, double*, double); +#endif +double DEVpred(CKTcircuit*,int); +#else /* stdc */ +double DEVlimvds(); +double DEVpnjlim(); +double DEVfetlim(); +void DEVcmeyer(); +void DEVqmeyer(); +#ifdef notdef +void DEVcap(); +#endif +double DEVpred(); +#endif /* stdc */ + +typedef struct SPICEdev { + IFdevice DEVpublic; + +#ifdef __STDC__ + int (*DEVparam)(int,IFvalue*,GENinstance*,IFvalue *); + /* routine to input a parameter to a device instance */ + int (*DEVmodParam)(int,IFvalue*,GENmodel*); + /* routine to input a paramater to a model */ + int (*DEVload)(GENmodel*,CKTcircuit*); + /* routine to load the device into the matrix */ + int (*DEVsetup)(SMPmatrix*,GENmodel*,CKTcircuit*,int*); + /* setup routine to preprocess devices once before soloution begins */ + int (*DEVunsetup)(GENmodel*,CKTcircuit*); + /* clean up before running again */ + int (*DEVpzSetup)(SMPmatrix*,GENmodel*,CKTcircuit*,int*); + /* setup routine to process devices specially for pz analysis */ + int (*DEVtemperature)(GENmodel*,CKTcircuit*); + /* subroutine to do temperature dependent setup processing */ + int (*DEVtrunc)(GENmodel*,CKTcircuit*,double*); + /* subroutine to perform truncation error calc. */ + int (*DEVfindBranch)(CKTcircuit*,GENmodel*,IFuid); + /* subroutine to search for device branch eq.s */ + int (*DEVacLoad)(GENmodel*,CKTcircuit*); + /* ac analysis loading function */ + int (*DEVaccept)(CKTcircuit*,GENmodel*); + /* subroutine to call on acceptance of a timepoint */ + void (*DEVdestroy)(GENmodel**); + /* subroutine to destroy all models and instances */ + int (*DEVmodDelete)(GENmodel**,IFuid,GENmodel*); + /* subroutine to delete a model and all instances */ + int (*DEVdelete)(GENmodel*,IFuid,GENinstance**); + /* subroutine to delete an instance */ + int (*DEVsetic)(GENmodel*,CKTcircuit*); + /* routine to pick up device init conds from rhs */ + int (*DEVask)(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); + /* routine to ask about device details*/ + int (*DEVmodAsk)(CKTcircuit*,GENmodel*,int,IFvalue*); + /* routine to ask about model details*/ + int (*DEVpzLoad)(GENmodel*,CKTcircuit*,SPcomplex*); + /* routine to load for pole-zero analysis */ + int (*DEVconvTest)(GENmodel*,CKTcircuit*); + /* convergence test function */ + + int (*DEVsenSetup)(SENstruct*,GENmodel*); + /* routine to setup the device sensitivity info */ + int (*DEVsenLoad)(GENmodel*,CKTcircuit*); + /* routine to load the device sensitivity info */ + int (*DEVsenUpdate)(GENmodel*,CKTcircuit*); + /* routine to update the device sensitivity info */ + int (*DEVsenAcLoad)(GENmodel*,CKTcircuit*); + /* routine to load the device ac sensitivity info */ + void (*DEVsenPrint)(GENmodel*,CKTcircuit*); + /* subroutine to print out sensitivity info */ + int (*DEVsenTrunc)(GENmodel*,CKTcircuit*,double*); + /* subroutine to print out sensitivity info */ + int (*DEVdisto)(int,GENmodel*,CKTcircuit*); + /* procedure to do distortion operations */ + int (*DEVnoise)(int, int, GENmodel*,CKTcircuit*, Ndata *, double *); + /* noise routine */ + +#else /* stdc */ + + int (*DEVparam)(); /* routine to input a parameter to a device instance */ + int (*DEVmodParam)(); /* routine to input a paramater to a model */ + int (*DEVload)(); /* routine to load the device into the matrix */ + int (*DEVsetup)(); /* setup routine to preprocess devices once before + * soloution begins */ + int (*DEVunsetup)(); /* clean up before running again */ + + int (*DEVpzSetup)(); /* setup routine to process devices specially for + * pz analysis */ + int (*DEVtemperature)(); /* subroutine to do temperature dependent + * setup processing */ + int (*DEVtrunc)(); /* subroutine to perform truncation error calc. */ + int (*DEVfindBranch)(); /* subroutine to search for device branch eq.s */ + int (*DEVacLoad)(); /* ac analysis loading function */ + int (*DEVaccept)(); /* subroutine to call on acceptance of a timepoint */ + void (*DEVdestroy)(); /* subroutine to destroy all models and instances */ + int (*DEVmodDelete)(); /* subroutine to delete a model and all instances */ + int (*DEVdelete)(); /* subroutine to delete an instance */ + int (*DEVsetic)(); /* routine to pick up device init conds from rhs */ + int (*DEVask)(); /* routine to ask about device details*/ + int (*DEVmodAsk)(); /* routine to ask about model details*/ + int (*DEVpzLoad)(); /* routine to load for pole-zero analysis */ + int (*DEVconvTest)(); /* convergence test function */ + + int (*DEVsenSetup)(); /* routine to setup the device sensitivity info */ + int (*DEVsenLoad)(); /* routine to load the device sensitivity info */ + int (*DEVsenUpdate)(); /* routine to update the device sensitivity info */ + int (*DEVsenAcLoad)(); /* routine to load the device ac sensitivity info*/ + void (*DEVsenPrint)(); /* subroutine to print out sensitivity info */ + int (*DEVsenTrunc)(); /* subroutine to print out sensitivity info */ + int (*DEVdisto)(); /* distortion routine */ + int (*DEVnoise)(); /* noise routine */ + +#endif /* stdc */ + + int *DEVinstSize; /* size of an instance */ + int *DEVmodSize; /* size of a model */ + +} SPICEdev; /* instance of structure for each possible type of device */ + +/* IOP( ) Input/output parameter + * IOPP( ) IO parameter which the principle value of a device (used + * for naming output variables in sensetivity) + * IOPA( ) IO parameter significant for time-varying (non-dc) analyses + * IOPAP( ) Principle value is significant for time-varying analyses + * IOPAA( ) IO parameter significant for ac analyses only + * IOPAAP( ) IO parameter principle value for ac analyses only + * IOPN( ) IO parameter significant for noise analyses only + * IOPR( ) Redundant IO parameter name (e.g. "vto" vs. "vt0") + * IOPX( ) IO parameter which is not used by sensetivity in any case + * + * IOPQ( ) This (Q) parameter must be non-zero for sensetivity of + * following Z parameter (model params done first) + * IOPZ( ) Prev. 'Q' parameter must be non-zero for sensetivity + * IOPQO( ) Like Q, but or-ed with previous Q value + * ....U( ) uninteresting for default "show" command output + */ + + +# define IOP(a,b,c,d) { a, b, c|IF_SET|IF_ASK, d } +# define IOPU(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_UNINTERESTING, d } +# define IOPP(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_PRINCIPAL, d } +# define IOPA(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_AC, d } +# define IOPAU(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_AC|IF_UNINTERESTING,d } +# define IOPAP(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_AC|IF_PRINCIPAL, d } +# define IOPAA(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_AC_ONLY, d } +# define IOPAAU(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_AC_ONLY|IF_UNINTERESTING,d} +# define IOPPA(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_AC_ONLY|IF_PRINCIPAL, d } +# define IOPN(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_NOISE, d } +# define IOPR(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_REDUNDANT, NULL } +# define IOPX(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_NONSENSE, d } +# define IOPXU(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_NONSENSE|IF_UNINTERESTING,\ + d } +# define IOPQ(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_SETQUERY, d } +# define IOPQU(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_SETQUERY|IF_UNINTERESTING,\ + d } +# define IOPZ(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_CHKQUERY, d } +# define IOPZU(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_CHKQUERY|IF_UNINTERESTING,\ + d } +# define IOPQO(a,b,c,d) { a, b, c|IF_SET|IF_ASK|IF_ORQUERY, d } + +# define IP(a,b,c,d) { a , b , c|IF_SET , d } +# define OP(a,b,c,d) { a , b , c|IF_ASK , d } +# define OPU(a,b,c,d) { a , b , c|IF_ASK|IF_UNINTERESTING , d } +# define OPR(a,b,c,d) { a , b , c|IF_ASK|IF_REDUNDANT , d } +# define P(a,b,c,d) { a , b , c , d } + + + +#define DEV_DEFAULT 0x1 + +#endif /*DEV*/ diff --git a/src/include/dgen.h b/src/include/dgen.h new file mode 100644 index 000000000..c21c0f67d --- /dev/null +++ b/src/include/dgen.h @@ -0,0 +1,26 @@ +typedef struct st_dgen dgen; + +struct st_dgen { + GENcircuit *ckt; + wordlist *dev_list; + int flags; + int dev_type_no; + int dev; + GENinstance *instance; + GENmodel *model; +}; + + +#define DGEN_ALL 0x00e +#define DGEN_TYPE 0x002 +#define DGEN_MODEL 0x004 +#define DGEN_INSTANCE 0x008 +#define DGEN_INIT 0x010 + +#define DGEN_DEFDEVS 0x020 +#define DGEN_ALLDEVS 0x040 + +#define DGEN_DEFPARAMS 0x001 +#define DGEN_ALLPARAMS 0x002 + +extern dgen *dgen_init( ); diff --git a/src/include/distodef.h b/src/include/distodef.h new file mode 100644 index 000000000..cf5bfcbec --- /dev/null +++ b/src/include/distodef.h @@ -0,0 +1,217 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#ifndef DISTODEF +#define DISTODEF + +#ifdef D_DBG_ALLTIMES +#define D_DBG_BLOCKTIMES +#define D_DBG_SMALLTIMES +#endif + +#include "jobdefs.h" +#include "gendefs.h" +#include "cktdefs.h" + +/* structure for passing a large number of values */ +typedef struct { + double cxx; + double cyy; + double czz; + double cxy; + double cyz; + double cxz; + double cxxx; + double cyyy; + double czzz; + double cxxy; + double cxxz; + double cxyy; + double cyyz; + double cxzz; + double cyzz; + double cxyz; + double r1h1x; + double i1h1x; + double r1h1y; + double i1h1y; + double r1h1z; + double i1h1z; + double r1h2x; + double i1h2x; + double r1h2y; + double i1h2y; + double r1h2z; + double i1h2z; + double r2h11x; + double i2h11x; + double r2h11y; + double i2h11y; + double r2h11z; + double i2h11z; + double h2f1f2x; + double ih2f1f2x; + double h2f1f2y; + double ih2f1f2y; + double h2f1f2z; + double ih2f1f2z; +} DpassStr; + +/* structure to keep derivatives of upto 3rd order w.r.t 3 variables */ +typedef struct { + double value; + double d1_p; + double d1_q; + double d1_r; + double d2_p2; + double d2_q2; + double d2_r2; + double d2_pq; + double d2_qr; + double d2_pr; + double d3_p3; + double d3_q3; + double d3_r3; + double d3_p2q; + double d3_p2r; + double d3_pq2; + double d3_q2r; + double d3_pr2; + double d3_qr2; + double d3_pqr; +} Dderivs; + + /* structure used to describe an DISTO analysis to be performed */ +typedef struct { + int JOBtype; + JOB *JOBnextJob; /* pointer to next thing to do */ + char *JOBname; /* name of this job */ + double DstartF1; /* the start value of the higher + frequency for distortion analysis */ + double DstopF1; /* the stop value ove above */ + double DfreqDelta; /* multiplier for decade/octave + stepping, step for linear steps. */ + double DsaveF1; /* frequency at which we left off last time*/ + int DstepType; /* values described below */ + int DnumSteps; + int Df2wanted; /* set if f2overf1 is given in the + disto command line */ + int Df2given; /* set if at least 1 source has an f2 + input */ + double Df2ovrF1; /* ratio of f2 over f1 if 2 + frequencies given should be < 1 */ + double Domega1; /* current omega1 */ + double Domega2; /* current omega2 */ + + double* r1H1ptr; + double* i1H1ptr; + double* r2H11ptr; + double* i2H11ptr; + double* r3H11ptr; + double* i3H11ptr; + double* r1H2ptr; /* distortion analysis Volterra transforms */ + double* i1H2ptr; + double* r2H12ptr; + double* i2H12ptr; + double* r2H1m2ptr; + double* i2H1m2ptr; + double* r3H1m2ptr; + double* i3H1m2ptr; + + double** r1H1stor; + double** i1H1stor; + double** r2H11stor; + double** i2H11stor; + double** r3H11stor; + double** i3H11stor; /*these store computed values*/ + double** r1H2stor; /* for the plots */ + double** i1H2stor; + double** r2H12stor; + double** i2H12stor; + double** r2H1m2stor; + double** i2H1m2stor; + double** r3H1m2stor; + double** i3H1m2stor; +} DISTOAN; + +/* available step types: */ + +#define DECADE 1 +#define OCTAVE 2 +#define LINEAR 3 + +/* defns. used in DsetParm */ + +#define D_DEC 1 +#define D_OCT 2 +#define D_LIN 3 +#define D_START 4 +#define D_STOP 5 +#define D_STEPS 6 +#define D_F2OVRF1 7 + +/* defns. used by CKTdisto for calling different functions */ + +#define D_SETUP 1 +#define D_F1 2 +#define D_F2 3 +#define D_TWOF1 4 +#define D_THRF1 5 +#define D_F1PF2 6 +#define D_F1MF2 7 +#define D_2F1MF2 8 +#define D_RHSF1 9 +#define D_RHSF2 10 + +extern int DsetParm(CKTcircuit*,void *,int,IFvalue*); +extern int DaskQuest(CKTcircuit*,void *,int,IFvalue*); +extern double D1i2F1(double, double, double); +extern double D1i3F1(double, double, double, double, double, double); +extern double D1iF12(double, double, double, double, double); +extern double D1i2F12(double, double, double, double, double, double, double, double, double, double); +extern double D1n2F1(double, double, double); +extern double D1n3F1(double, double, double, double, double, double); +extern double D1nF12(double, double, double, double, double); +extern double D1n2F12(double, double, double, double, double, double, double, double, double, double); +extern double DFn2F1(double, double, double, double, double, + double, double, double, double, double, double, double); +extern double DFi2F1(double, double, double, double, double, + double, double, double, double, double, double, double); +extern double DFi3F1(double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double); +extern double DFn3F1(double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double); +extern double DFnF12(double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double); +extern double DFiF12(double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double); +extern double DFn2F12(DpassStr*); +extern double DFi2F12(DpassStr*); + +extern void EqualDeriv(Dderivs *new, Dderivs *old); +extern void TimesDeriv(Dderivs *new, Dderivs *old, double k); +extern void InvDeriv(Dderivs *new, Dderivs *old); +extern void MultDeriv(Dderivs *new, Dderivs *old1, Dderivs *old2); +extern void CubeDeriv(Dderivs *new, Dderivs *old); +extern void PlusDeriv(Dderivs *new, Dderivs *old1, Dderivs *old2); +extern void SqrtDeriv(Dderivs *new, Dderivs *old); +extern void DivDeriv(Dderivs *new, Dderivs *old1, Dderivs *old2); +extern void PowDeriv(Dderivs *new, Dderivs *old, double emm); +extern void AtanDeriv(Dderivs *new, Dderivs *old); +extern void CosDeriv(Dderivs *new, Dderivs *old); +extern void ExpDeriv(Dderivs *new, Dderivs *old); + + + + +#endif /*DISTODEFS*/ diff --git a/src/include/ftecmath.h b/src/include/ftecmath.h new file mode 100644 index 000000000..1584fd704 --- /dev/null +++ b/src/include/ftecmath.h @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Macros for complex mathematical functions. + */ + +/* Some defines used mainly in cmath.c. */ +#define alloc_c(len) ((complex *) tmalloc((len) * sizeof (complex))) +#define alloc_d(len) ((double *) tmalloc((len) * sizeof (double))) +#define FTEcabs(d) (((d) < 0.0) ? - (d) : (d)) +#define cph(c) (atan2(imagpart(c), (realpart(c)))) +#define cmag(c) (sqrt(imagpart(c) * imagpart(c) + realpart(c) * realpart(c))) +#define radtodeg(c) (cx_degrees ? ((c) / 3.14159265358979323846 * 180) : (c)) +#define degtorad(c) (cx_degrees ? ((c) * 3.14159265358979323846 / 180) : (c)) +#define rcheck(cond, name) if (!(cond)) { \ + fprintf(cp_err, "Error: argument out of range for %s\n", name); \ + return (NULL); } + + +#define cdiv(r1, i1, r2, i2, r3, i3) \ +{ \ + double r, s; \ + if (FTEcabs(r2) > FTEcabs(i2)) { \ + r = (i2) / (r2); \ + s = (r2) + r * (i2); \ + (r3) = ((r1) + r * (i1)) / s; \ + (i3) = ((i1) - r * (r1)) / s; \ + } else { \ + r = (r2) / (i2); \ + s = (i2) + r * (r2); \ + (r3) = (r * (r1) + (i1)) / s; \ + (i3) = (r * (i1) - (r1)) / s; \ + } \ +} + + + + diff --git a/src/include/fteconst.h b/src/include/fteconst.h new file mode 100644 index 000000000..c36ab9e05 --- /dev/null +++ b/src/include/fteconst.h @@ -0,0 +1,101 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* Vector types. */ + +#ifndef _CONSTANTS_ +#define _CONSTANTS_ + +#define SV_NOTYPE 0 +#define SV_TIME 1 +#define SV_FREQUENCY 2 +#define SV_VOLTAGE 3 +#define SV_CURRENT 4 +#define SV_OUTPUT_N_DENS 5 +#define SV_OUTPUT_NOISE 6 +#define SV_INPUT_N_DENS 7 +#define SV_INPUT_NOISE 8 +#define SV_POLE 9 +#define SV_ZERO 10 +#define SV_SPARAM 11 + +#ifdef notdef +#define SV_OUTPUT_NOISE 5 +#define SV_INPUT_NOISE 6 +#define SV_HD2 7 +#define SV_HD3 8 +#define SV_DIM2 9 +#define SV_SIM2 10 +#define SV_DIM3 11 +#define SV_POLE 12 +#define SV_ZERO 13 +#define SV_SPARAM 14 +#endif + +/* Dvec flags. */ + +#define VF_REAL (1 << 0) /* The data is real. */ +#define VF_COMPLEX (1 << 1) /* The data is complex. */ +#define VF_ACCUM (1 << 2) /* writedata should save this vector. */ +#define VF_PLOT (1 << 3) /* writedata should incrementally plot it. */ +#define VF_PRINT (1 << 4) /* writedata should print this vector. */ +#define VF_MINGIVEN (1 << 5) /* The v_minsignal value is valid. */ +#define VF_MAXGIVEN (1 << 6) /* The v_maxsignal value is valid. */ +#define VF_PERMANENT (1 << 7) /* Don't garbage collect this vector. */ + +/* Grid types. */ + +/* +#define GRID_NONE 0 +#define GRID_LIN 1 +#define GRID_LOGLOG 2 +#define GRID_XLOG 3 +#define GRID_YLOG 4 +#define GRID_POLAR 5 +#define GRID_SMITH 6 +*/ + +/* SMITHGRID is only a smith grid, SMITH transforms the data */ +typedef enum { + GRID_NONE = 0, GRID_LIN = 1, GRID_LOGLOG = 2, GRID_XLOG = 3, + GRID_YLOG = 4, GRID_POLAR = 5, GRID_SMITH = 6, GRID_SMITHGRID = 7 +} GRIDTYPE; + +/* Plot types. */ + +/* +#define PLOT_LIN 0 +#define PLOT_COMB 1 +#define PLOT_POINT 2 +*/ + +typedef enum { + PLOT_LIN = 0, PLOT_COMB = 1, PLOT_POINT = 2 +} PLOTTYPE; + +/* The types for command completion keywords. Note that these constants + * are built into cmdtab.c, so DON'T change them unless you want to + * change all of the bitmasks in cp_coms. + * Note that this is spice- and nutmeg- dependent. + */ + +#define CT_FILENAME 0 +#define CT_CKTNAMES 2 +#define CT_COMMANDS 3 +#define CT_DBNUMS 4 +#define CT_DEVNAMES 5 +#define CT_LISTINGARGS 6 +#define CT_NODENAMES 7 +#define CT_PLOT 8 +#define CT_PLOTKEYWORDS 9 +#define CT_RUSEARGS 10 +#define CT_STOPARGS 11 +#define CT_UDFUNCS 12 +#define CT_VARIABLES 13 +#define CT_VECTOR 14 +#define CT_TYPENAMES 16 + +#endif + diff --git a/src/include/ftedata.h b/src/include/ftedata.h new file mode 100644 index 000000000..ff478cd84 --- /dev/null +++ b/src/include/ftedata.h @@ -0,0 +1,72 @@ + +/* RCS Info: $Revision$ on $Date$ + * $Source$ + * Copyright (c) 1985 Wayne A. Christopher, U. C. Berkeley CAD Group + * + * Structures used for representing spice data in nutmeg. + */ + +#ifndef FTEdata_h +#define FTEdata_h + +#include "cpstd.h" /* for struct complex */ +#include "fteconst.h" + +/* A (possibly multi-dimensional) data vector. The data is represented + * internally by a 1-d array. The number of dimensions and the size + * of each dimension is recorded, along with v_length, the total size of + * the array. If the dimensionality is 0 or 1, v_length is significant + * instead of v_numdims and v_dims, and the vector is handled in the old + * manner. + */ + +#define MAXDIMS 8 + +struct dvec { + char *v_name; /* Same as so_vname. */ + int v_type; /* Same as so_vtype. */ + short v_flags; /* Flags (a combination of VF_*). */ + double *v_realdata; /* Real data. */ + complex *v_compdata; /* Complex data. */ + double v_minsignal; /* Minimum value to plot. */ + double v_maxsignal; /* Maximum value to plot. */ + GRIDTYPE v_gridtype; /* One of GRID_*. */ + PLOTTYPE v_plottype; /* One of PLOT_*. */ + int v_length; /* Length of the vector. */ + int v_rlength; /* How much space we really have. */ + int v_outindex; /* Index if writedata is building the + vector. */ + int v_linestyle; /* What line style we are using. */ + int v_color; /* What color we are using. */ + char *v_defcolor; /* The name of a color to use. */ + int v_numdims; /* How many dims -- 0 = scalar (len = 1). */ + int v_dims[MAXDIMS]; /* The actual size in each dimension. */ + struct plot *v_plot; /* The plot structure (if it has one). */ + struct dvec *v_next; /* Link for list of plot vectors. */ + struct dvec *v_link2; /* Extra link for things like print. */ + struct dvec *v_scale; /* If this has a non-standard scale... */ +} ; + +#define isreal(v) ((v)->v_flags & VF_REAL) +#define iscomplex(v) ((v)->v_flags & VF_COMPLEX) + +/* The information for a particular set of vectors that come from one + * plot. + */ + +struct plot { + char *pl_title; /* The title card. */ + char *pl_date; /* Date. */ + char *pl_name; /* The plot name. */ + char *pl_typename; /* Tran1, op2, etc. */ + struct dvec *pl_dvecs; /* The data vectors in this plot. */ + struct dvec *pl_scale; /* The "scale" for the rest of the vectors. */ + struct plot *pl_next; /* List of plots. */ + wordlist *pl_commands; /* Commands to execute for this plot. */ + struct variable *pl_env;/* The 'environment' for this plot. */ + char *pl_ccom; /* The ccom struct for this plot. */ + bool pl_written; /* Some or all of the vecs have been saved. */ + int pl_ndims; /* Number of dimensions */ +} ; + +#endif /* FTEdata_h */ diff --git a/src/include/ftedbgra.h b/src/include/ftedbgra.h new file mode 100644 index 000000000..6518313c3 --- /dev/null +++ b/src/include/ftedbgra.h @@ -0,0 +1,18 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Jeffrey M. Hsu +**********/ + +/* + $Header$ + + External definitions for the graph database module. +*/ + +extern GRAPH *currentgraph; + +extern GRAPH *NewGraph(); + +extern GRAPH *FindGraph(); + +extern GRAPH *CopyGraph(); diff --git a/src/include/ftedebug.h b/src/include/ftedebug.h new file mode 100644 index 000000000..32914586a --- /dev/null +++ b/src/include/ftedebug.h @@ -0,0 +1,48 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Stuff for debugging a spice run. Debugging information will be printed + * on the standard output. + */ + +#define DB_TRACENODE 1 /* Print the value of a node every iteration. */ +#define DB_TRACEALL 2 /* Trace all nodes. */ +#define DB_STOPAFTER 3 /* Break after this many iterations. */ +#define DB_STOPWHEN 4 /* Break when a node reaches this value. */ +#define DB_IPLOT 5 /* Incrementally plot the stuff. */ +#define DB_IPLOTALL 6 /* Incrementally plot everything. */ +#define DB_SAVE 7 /* Save a node. */ +#define DB_SAVEALL 8 /* Save everything. */ +#define DB_DEADIPLOT 9 /* Incrementally plot the stuff. */ + +/* These only make sense in the real case, so always use realpart(). It's too + * bad that we have to say "ge" instead of ">=", etc, but cshpar takes + * the <>'s. + */ + +#define DBC_EQU 1 /* == (eq) */ +#define DBC_NEQ 2 /* != (ne) */ +#define DBC_GT 3 /* > (gt) */ +#define DBC_LT 4 /* < (lt) */ +#define DBC_GTE 5 /* >= (ge) */ +#define DBC_LTE 6 /* <= (le) */ + +struct dbcomm { + int db_number; /* The number of this debugging command. */ + char db_type; /* One of the above. */ + char *db_nodename1; /* What node. */ + char *db_nodename2; /* What node. */ + char *db_analysis; /* for a specific analysis. */ + int db_iteration; /* For the DB_STOPAFTER command. */ + char db_op; /* For DB_STOPWHEN. */ + double db_value1; /* If this is DB_STOPWHEN. */ + double db_value2; /* If this is DB_STOPWHEN. */ + int db_graphid; /* If iplot, id of graph. */ + struct dbcomm *db_also; /* Link for conjunctions. */ + struct dbcomm *db_next; /* List of active debugging commands. */ +} ; + diff --git a/src/include/ftedefs.h b/src/include/ftedefs.h new file mode 100644 index 000000000..accd88509 --- /dev/null +++ b/src/include/ftedefs.h @@ -0,0 +1,58 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * General front end stuff. + */ +#ifndef FTEdefs_h +#define FTEdefs_h + +#define DEF_WIDTH 80 /* Line printer width. */ +#define DEF_HEIGHT 60 /* Line printer height. */ +#define IPOINTMIN 20 /* When we start plotting incremental plots. */ +#include "fteparse.h" +#include "fteinp.h" + +/* The curcuits that are currently available to the user. */ + +struct circ { + char *ci_name; /* What the circuit can be called. */ + char *ci_ckt; /* The CKTcircuit structure. */ + INPtables *ci_symtab; /* The INP symbol table. */ + struct line *ci_deck; /* The input deck. */ + struct line *ci_origdeck;/* The input deck, before subckt expansion. */ + struct line *ci_options;/* The .option cards from the deck... */ + struct variable *ci_vars; /* ... and the parsed versions. */ + bool ci_inprogress; /* We are in a break now. */ + bool ci_runonce; /* So com_run can to a reset if necessary... */ + wordlist *ci_commands; /* Things to do when this circuit is done. */ + struct circ *ci_next; /* The next in the list. */ + char *ci_nodes; /* ccom structs for the nodes... */ + char *ci_devices; /* and devices in the circuit. */ + char *ci_filename; /* Where this circuit came from. */ + char *ci_defTask; /* the default task for this circuit */ + char *ci_specTask; /* the special task for command line jobs */ + char *ci_curTask; /* the most recent task for this circuit */ + char *ci_defOpt; /* the default options anal. for this circuit */ + char *ci_specOpt; /* the special options anal. for command line jobs */ + char *ci_curOpt; /* the most recent options anal. for the circuit */ +} ; + +struct subcirc { + char *sc_name; /* Whatever... */ +} ; + +struct save_info { + char *name; + IFuid *analysis; + int used; +}; + +#define mylog10(xx) (((xx) > 0.0) ? log10(xx) : (- log10(HUGE))) + +#include "fteext.h" + +#endif /* FTEdefs_h */ diff --git a/src/include/ftedev.h b/src/include/ftedev.h new file mode 100644 index 000000000..272cf02f8 --- /dev/null +++ b/src/include/ftedev.h @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Jeffrey M. Hsu +**********/ + +/* + $Header$ + + The display device structure. +*/ + +typedef struct { + char *name; + int minx, miny; + int width, height; /* in screen coordinate system */ + int numlinestyles, numcolors; /* number supported */ + int (*Init)(); + int (*NewViewport)(); + int (*Close)(); + int (*Clear)(); + int (*DrawLine)(); + int (*Arc)(); + int (*Text)(); + int (*DefineColor)(); + int (*DefineLinestyle)(); + int (*SetLinestyle)(); + int (*SetColor)(); + int (*Update)(); +/* int (*NDCtoScreen)(); */ + int (*Track)(); + int (*MakeMenu)(); + int (*MakeDialog)(); + int (*Input)(); + int (*DatatoScreen)(); +} DISPDEVICE; + +extern DISPDEVICE *dispdev; diff --git a/src/include/fteext.h b/src/include/fteext.h new file mode 100644 index 000000000..d808a2209 --- /dev/null +++ b/src/include/fteext.h @@ -0,0 +1,531 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +Modified: 1999 Paolo Nenzi +**********/ + +/* + * Definitions for all external symbols in FTE. + */ + +#ifndef FTEext_h +#define FTEext_h + +#include + +/* needed to find out what the interface structures look like */ +#include "ifsim.h" +#include "fteparse.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "fteinp.h" + +/* agraf.c */ + +extern void ft_agraf(); + +/* arg.c */ + +extern void arg_plot(); +extern void arg_display(); +extern void arg_print(); +extern void arg_let(); +extern void arg_load(); +extern void arg_set(); +extern void outmenuprompt(); + +/* aspice.c */ + +extern void com_aspice(); +extern void com_jobs(); +extern void com_rspice(); +extern void ft_checkkids(); + +/* binary.c */ + +extern void braw_write(); +extern struct plot *braw_read(); + +/* breakpoint.c */ + +extern bool ft_bpcheck(); +extern void com_delete(); +extern void com_iplot(); +extern void com_save(); +extern void com_step(); +extern void com_stop(); +extern void com_sttus(); +extern void com_trce(); +extern void ft_trquery(); +extern void dbfree( ); + +/* circuits.c */ + +extern struct circ *ft_curckt; +extern struct circ *ft_circuits; +extern struct subcirc *ft_subcircuits; +extern void ft_setccirc(); +extern void ft_newcirc(); +extern void ft_newsubcirc(); + +/* clip.c */ + +extern bool clip_line(); +extern bool clip_to_circle(); + +/* cmath1.c */ + +extern bool cx_degrees; +extern void *cx_mag(void *, short int , int , int *, short int *); +extern void *cx_ph(void *, short int , int , int *, short int *); +extern void *cx_j(void *, short int , int , int *, short int *); +extern void *cx_real(void *, short int , int , int *, short int *); +extern void *cx_imag(void *, short int , int , int *, short int *); +extern void *cx_pos(void *, short int , int , int *, short int *); +extern void *cx_db(void *, short int , int , int *, short int *); +extern void *cx_log(void *, short int , int , int *, short int *); +extern void *cx_ln(void *, short int , int , int *, short int *); +extern void *cx_exp(void *, short int , int , int *, short int *); +extern void *cx_sqrt(void *, short int , int , int *, short int *); +extern void *cx_sin(void *, short int , int , int *, short int *); +extern void *cx_cos(void *, short int , int , int *, short int *); + +/* cmath2.c */ + +extern void *cx_tan(void *, short int , int , int *, short int *); +extern void *cx_atan(void *, short int , int , int *, short int *); +extern void *cx_norm(void *, short int , int , int *, short int *); +extern void *cx_uminus(void *, short int , int , int *, short int *); +extern void *cx_rnd(void *, short int , int , int *, short int *); +extern void *cx_mean(void *, short int , int , int *, short int *); +extern void *cx_length(void *, short int , int , int *, short int *); +extern void *cx_vector(void *, short int , int , int *, short int *); +extern void *cx_unitvec(void *, short int , int , int *, short int *); + +extern void *cx_plus(void *, void *, short int , short int , int ); +extern void *cx_minus(void *, void *, short int , short int , int ); +extern void *cx_times(void *, void *, short int , short int , int ); +extern void *cx_mod(void *, void *, short int , short int , int ); + +/* cmath3.c */ + +extern void *cx_divide(void *, void *, short int , short int , int ); +extern void *cx_comma(void *, void *, short int , short int , int ); +extern void *cx_power(void *, void *, short int , short int , int ); +extern void *cx_eq(void *, void *, short int , short int , int ); +extern void *cx_gt(void *, void *, short int , short int , int ); +extern void *cx_lt(void *, void *, short int , short int , int ); +extern void *cx_ge(void *, void *, short int , short int , int ); +extern void *cx_le(void *, void *, short int , short int , int ); +extern void *cx_ne(void *, void *, short int , short int , int ); + +/* cmath4.c */ + +extern void *cx_and(void *, void *, short int , short int , int ); +extern void *cx_or(void *, void *, short int , short int , int ); +extern void *cx_not(void *, short int , int , int *, short int * ); +extern void *cx_interpolate(void *, short int , int , int *, short int *, struct plot *, struct plot *, int ); +extern void *cx_deriv(void *, short int , int , int *, short int *, struct plot *, struct plot *, int ); + +/* cmdtab.c */ + +extern struct comm *cp_coms; + +/* compose.c */ + +extern void com_compose(); + +/* cpinterface.c symbols declared in CPextern.h */ + +/* debugcoms.c */ + +extern void com_dump(); +extern void com_state(); + +/* define.c */ + +extern struct pnode *ft_substdef(); +extern void com_define(); +extern void com_undefine(); +extern void ft_pnode(); + +/* device.c */ + +extern void com_show(); +extern void com_showmod(); +extern void com_alter(); +extern void com_altermod(); + +/* diff.c */ + +extern void com_diff(); + +/* doplot.c */ + +extern void com_asciiplot(); +extern void com_hardcopy(); +extern void com_plot(); +extern void com_xgraph(); + +/* dotcards.c */ + +extern bool ft_acctprint; +extern bool ft_listprint; +extern bool ft_nopage; +extern bool ft_nomod; +extern bool ft_nodesprint; +extern bool ft_optsprint; +extern int ft_cktcoms(); +extern void ft_dotsaves(); +extern int ft_savedotargs(); + +/* error.c */ + +extern void fatal(); +extern void fperror(); +extern void ft_sperror(); +extern char ErrorMessage[]; + +/* evaluate.c */ + +extern struct dvec *op_and(); +extern struct dvec *op_comma(); +extern struct dvec *op_divide(); +extern struct dvec *op_eq(); +extern struct dvec *ft_evaluate(); +extern struct dvec *op_ge(); +extern struct dvec *op_gt(); +extern struct dvec *op_le(); +extern struct dvec *op_lt(); +extern struct dvec *op_minus(); +extern struct dvec *op_mod(); +extern struct dvec *op_ne(); +extern struct dvec *op_not(); +extern struct dvec *op_or(); +extern struct dvec *op_ind(); +extern struct dvec *op_plus(); +extern struct dvec *op_power(); +extern struct dvec *op_times(); +extern struct dvec *op_uminus(); +extern struct dvec *op_range(); + +/* fourier.c */ + +extern void com_fourier(); + +/* spec.c */ + +extern void com_spec(); + +/* ginterface.c */ + +extern bool gi_init(); +extern bool gi_endpause; +extern bool gi_rottext; +extern int gi_fntheight; +extern int gi_fntwidth; +extern int gi_maxx; +extern int gi_maxy; +extern int gi_nolst; +extern int gi_nocolors; +extern int gi_package; +extern void gi_arc(); +extern void gi_clearscreen(); +extern void gi_close(); +extern void gi_drawline(); +extern void gi_redraw(); +extern void gi_setcolor(); +extern void gi_resetcolor(); +extern void gi_setlinestyle(); +extern void gi_text(); +extern void gi_update(); + +/* graf.c */ + +extern bool gr_gmode; +extern bool gr_hmode; +extern bool gr_init(); +extern void gr_clean(); +extern void gr_end(); +extern void gr_iplot(); +extern void gr_iplot_end(); +extern void gr_pmsg(); +extern void gr_point(); +extern void gr_start(); +extern double gr_xrange[2]; +extern double gr_yrange[2]; +extern int gr_xmargin; +extern int gr_ymargin; +extern int gr_xcenter; +extern int gr_ycenter; +extern int gr_radius; +extern bool gr_circular; + +/* grid.c */ + +extern void gr_fixgrid(); + +/* inp.c */ + +extern void com_edit(); +extern void com_listing(); +extern void com_source(); +extern void inp_dodeck(); +extern void inp_source(); +extern void inp_spsource(); +extern void inp_casefix(); +extern void inp_list(); +extern void inp_readall(); +extern FILE *inp_pathopen(); + +/* nutinp.c */ + +extern void inp_nutsource(); +extern void nutinp_dodeck(); +extern void nutcom_source(); + +/* interpolate.c */ + +extern bool ft_interpolate(); +extern bool ft_polyfit(); +extern double ft_peval(); +extern void ft_polyderiv( ); +extern void com_linearize(); + +/* mfbinterface.c */ + +extern void mi_arc(); +extern bool mi_init(); +extern void mi_clearscreen(); +extern void mi_close(); +extern void mi_drawline(); +extern void mi_resetcolor(); +extern void mi_setcolor(); +extern void mi_setlinestyle(); +extern void mi_text(); +extern void mi_update(); + +/* misccoms.c */ + +extern void com_bug(); +extern void com_ahelp(); +extern void com_ghelp(); +extern void com_help(); +extern void com_quit(); +extern void com_version(); +extern int hcomp(); +extern void com_where(); + +/* numparse.c */ + +extern bool ft_strictnumparse; +extern double *ft_numparse(); + +/* options.c */ + +extern bool ft_simdb; +extern bool ft_parsedb; +extern bool ft_evdb; +extern bool ft_vecdb; +extern bool ft_grdb; +extern bool ft_gidb; +extern bool ft_controldb; +extern bool ft_asyncdb; +extern char *ft_setkwords[]; +extern struct line *inp_getopts(); +extern struct variable *cp_enqvar(); +extern struct variable *cp_uservars(); +extern int cp_userset(); + +/* parse.c */ + +extern struct func ft_funcs[]; +extern struct func func_not; +extern struct func func_uminus; +extern struct pnode *ft_getpnames(); +extern void free_pnode(); + +/* plotcurve.c */ + +extern int ft_findpoint(); +extern double *ft_minmax(); +extern void ft_graf(); + +/* plotinterface.c */ + +extern void pi_arc(); +extern bool pi_init(); +extern void pi_clearscreen(); +extern void pi_close(); +extern void pi_drawline(); +extern void pi_resetcolor(); +extern void pi_setcolor(); +extern void pi_setlinestyle(); +extern void pi_text(); +extern void pi_update(); + +/* postcoms.c */ + +extern void com_cross(); +extern void com_display(); +extern void com_let(); +extern void com_unlet(); +extern void com_load(); +extern void com_print(); +extern void com_write(); +extern void com_destroy(); +extern void com_splot(); +extern void com_setscale(); +extern void com_transpose(); + +/* rawfile.c */ + +extern int raw_prec; +extern void raw_write(); +extern struct plot *raw_read(); + +/* resource.c */ + +extern void com_rusage(); +extern void ft_ckspace(); +extern void init_rlimits(); + +/* runcoms.c */ + +extern void com_ac(); +extern void com_dc(); +extern void com_op(); +extern void com_pz(); +extern void com_sens(); +extern void com_rset(); +extern void com_resume(); +extern void com_run(); +extern void com_tran(); +extern void com_tf(); +extern void com_scirc(); +extern void com_disto(); +extern void com_noise(); +extern int ft_dorun(); + +/* spice.c & nutmeg.c */ + +extern bool ft_nutmeg; +extern IFsimulator *ft_sim; +extern char *ft_rawfile; +extern char *cp_program; +extern RETSIGTYPE ft_sigintr(); +extern RETSIGTYPE sigfloat(); +extern RETSIGTYPE sigstop(); +extern RETSIGTYPE sigquit(); +extern RETSIGTYPE sigill(); +extern RETSIGTYPE sigbus(); +extern RETSIGTYPE sigsegv(); +extern RETSIGTYPE sig_sys(); +extern int main(); + +/* spiceif.c & nutmegif.c */ + +extern bool if_tranparams(); +extern char *if_errstring(); +extern char *if_inpdeck(); +extern int if_run(); +extern int if_sens_run(); +extern struct variable *(*if_getparam)(); +extern struct variable *nutif_getparam(); +extern struct variable *spif_getparam(); +extern void if_cktfree(); +extern void if_dump(); +extern int if_option(); +extern void if_setndnames(); +extern void if_setparam(); +extern struct variable *if_getstat(); + +/* subckt.c */ + +extern struct line *inp_deckcopy(); +extern struct line *inp_subcktexpand(); +extern int inp_numnodes(char); + +/* types.c */ + +extern void com_dftype(); +extern void com_stype(); +extern char *ft_typabbrev(); +extern char *ft_typenames(); +extern char *ft_plotabbrev(); +extern int ft_typnum(); + +/* vectors.c */ + +extern bool vec_eq(); +extern int plot_num; +extern struct dvec *vec_fromplot(); +extern struct dvec *vec_copy(); +extern struct dvec *vec_get(); +extern struct dvec *vec_mkfamily(); +extern struct plot *plot_cur; +extern struct plot *plot_alloc(); +extern struct plot *plot_list; +extern int plotl_changed; +extern void plot_add(); +extern void vec_free(); +extern void vec_gc(); +extern void ft_loadfile(); +extern void vec_new(); +extern void plot_docoms(); +extern void vec_remove(); +extern void ft_sdatafree(); +extern void plot_setcur(); +extern void plot_new(); +extern char *vec_basename(); +extern bool plot_prefix(); +extern void vec_transpose(); + +/* writedata.c */ + +extern bool ft_intrpt; +extern bool ft_setflag; +extern int wrd_close(); +extern int wrd_command(); +extern int wrd_cptime; +extern int wrd_end(); +extern int wrd_init(); +extern int wrd_limpts; +extern int wrd_open(); +extern int wrd_output(); +extern int wrd_point(); +extern int wrd_pt2(); +extern int wrd_run(); +extern int wrd_stopnow(); +extern void wrd_chtrace(); +extern void wrd_error(); +extern void wrd_version(); +extern wordlist *wrd_saves; + +/* xinterface.c */ + +extern void xi_arc(); +extern bool xi_init(); +extern bool xi_dump(); +extern void xi_clearscreen(); +extern void xi_close(); +extern void xi_drawline(); +extern void xi_resetcolor(); +extern void xi_setcolor(); +extern void xi_setlinestyle(); +extern void xi_text(); +extern void xi_update(); +extern void xi_zoomdata(); +extern struct screen *screens; +extern void com_clearplot(); + +/* newcoms.c */ +extern void com_reshape(); + +/* dimens.c */ +extern char *dimstring(); +extern int atodims(); +extern char *indexstring(); +extern int incindex( ); + +#endif /* FTEext_h */ diff --git a/src/include/ftegraf.h b/src/include/ftegraf.h new file mode 100644 index 000000000..6e5da6db1 --- /dev/null +++ b/src/include/ftegraf.h @@ -0,0 +1,16 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Definitions common to the various graphics modules. + */ + +#define G_NONE 0 +#define G_HCOPY 1 +#define G_TERM 2 +#define G_MFB 3 +#define G_X 4 + diff --git a/src/include/ftegraph.h b/src/include/ftegraph.h new file mode 100644 index 000000000..f5d73e2e8 --- /dev/null +++ b/src/include/ftegraph.h @@ -0,0 +1,143 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jeffrey M. Hsu +**********/ + +/* + This file contains the graph structure. +*/ + +#ifndef _GRAPH_H_ +#define _GRAPH_H_ + +#include "fteconst.h" +#include "ftedata.h" /* for struct dvec */ + +/* Device-independent data structure for plots. */ + +#define NUMCOLORS 20 + +/* list of data vectors being displayed */ +struct dveclist { + struct dvec *vector; + struct dveclist *next; +}; + +typedef struct graph { + int graphid; + struct dveclist *plotdata; /* normalized data */ + char *plotname; /* name of plot this graph is in */ + int onevalue; /* boolean variable, + true if plotting one value + against itself (real vs imaginary) */ + int degree; /* degree of polynomial interpretation */ + + int currentcolor; + int linestyle; + + struct { + int height, width; + } viewport; + int viewportxoff; /* x offset of viewport w/in graph */ + int viewportyoff; /* y offset of viewport w/in graph */ + + struct { + int xpos; /* x position of graph in screen coord */ + int ypos; /* y position of graph in screen coord */ + int width; /* width of window on screen */ + int height; /* height of window on screen */ + } absolute; + + struct { + double xmin, ymin, xmax, ymax; + } data; + + struct { + double xmin, ymin, xmax, ymax; + /* cache: width = xmax - xmin height = ymax - ymin */ + double width, height; + } datawindow; + + /* note: this int is device dependent */ + int colors[NUMCOLORS]; + + /* cache (datawindow size) / (viewport size) */ + double aspectratiox, aspectratioy; + + int ticmarks; /* mark every ticmark'th point */ + double *ticdata; + int fontwidth, fontheight; /* for use in grid */ + + PLOTTYPE plottype; /* defined in FTEconstant.h */ + struct { + GRIDTYPE gridtype; /* defined in FTEconstant.h */ + int circular; /* TRUE if circular plot area */ + union { + struct { + char units[16]; /* unit labels */ + int spacing, numspace; + double distance, lowlimit, highlimit; + int mult; + int onedec; /* a boolean */ + int hacked; /* true if hi - lo already hacked up */ + double tenpowmag; + double tenpowmagx; + int digits; + } lin; + struct { + char units[16]; /* unit labels */ + int hmt, lmt, decsp, subs, pp; + } log; + struct { + char units[16]; /* unit labels */ + int radius, center; + double mrad; + int lmt; + int hmt, mag; /* added, p.w.h. */ + } circular; /* bogus, rework when write polar grids, etc */ + } xaxis, yaxis; + int xdatatype, ydatatype; + int xsized, ysized; + double xdelta, ydelta; /* if non-zero, user-specified deltas */ + char *xlabel, *ylabel; + } grid; + + int numbuttons; /* number of buttons */ + struct { + int id; + char *message; + } *buttons; + int buttonsxoff; /* viewportxoff + x size of viewport */ + int buttonsyoff; + + struct { + int width, height; + char message[161]; /* two lines of text */ + } messagebox; + int messagexoff; + int messageyoff; + + /* characters the user typed on graph */ +/* note: think up better names */ + struct _keyed { + char *text; + int x, y; + int colorindex; /* index into colors array */ + struct _keyed *next; + } *keyed; + + /* for zoomin */ + char *commandline; + + /* Space here is allocated by NewViewport + and de-allocated by DestroyGraph. + */ + char *devdep; + +} GRAPH; + +#define NEWGRAPH (GRAPH *) calloc(1, sizeof(GRAPH)) + +#define rnd(x) (int) ((x)+0.5) + +#endif /* notdef _GRAPH_H_ */ diff --git a/src/include/ftehelp.h b/src/include/ftehelp.h new file mode 100644 index 000000000..de368fe80 --- /dev/null +++ b/src/include/ftehelp.h @@ -0,0 +1,22 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Jeffrey M. Hsu +**********/ + +/* + + Defines for help. +*/ + +#define E_HASPLOTS 1 +#define E_NOPLOTS 2 +#define E_HASGRAPHS 4 +#define E_MENUMODE 8 + +#define E_BEGINNING 4096 +#define E_INTERMED 8192 +#define E_ADVANCED 16384 +#define E_ALWAYS 32768 + +/* default is intermediate level */ +#define E_DEFHMASK 8192 diff --git a/src/include/fteinp.h b/src/include/fteinp.h new file mode 100644 index 000000000..0efc28c43 --- /dev/null +++ b/src/include/fteinp.h @@ -0,0 +1,31 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Note that this definition must be the same as struct card in INPdefs.h... + */ + +#ifndef FTEinput_h +#define FTEinput_h + +#include "inpdefs.h" + +struct line { + int li_linenum; + char *li_line; + char *li_error; + struct line *li_next; + struct line *li_actual; +} ; + +/* Listing types. */ + +#define LS_LOGICAL 1 +#define LS_PHYSICAL 2 +#define LS_DECK 3 + +#endif /* FTEinput_h */ + diff --git a/src/include/fteinput.h b/src/include/fteinput.h new file mode 100644 index 000000000..d50bb8dd1 --- /dev/null +++ b/src/include/fteinput.h @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jeffrey M. Hsu +**********/ + +/* + $Header$ + + Defs to use the Input routine. + + char_option is used by the lexer and the command interpreter + response.reply contains a pointer to a character + button_option is used by the menu system and the help package + response.reply contains the button number + click_option is used in the X10 version for the hardcopy command + response.reply is the associated graph structure + checkup_option is for handling and pending asynchonous events +*/ + +#ifndef _INPUT_H_ +#define _INPUT_H_ + + +#include +#include "ftegraph.h" + +typedef enum { + error_option, /* a reply option only */ + button_option, + char_option, + click_option, + checkup_option +} OPTION; + +typedef struct request { + OPTION option; + FILE *fp; +} REQUEST; + +typedef struct response { + OPTION option; + union { + int ch; + GRAPH *graph; + int button; + } reply; +} RESPONSE; + +#endif /* notdef _INPUT_H_ */ diff --git a/src/include/fteparse.h b/src/include/fteparse.h new file mode 100644 index 000000000..160e1f4a2 --- /dev/null +++ b/src/include/fteparse.h @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Stuff for parsing -- used by the parser and in ft_evaluate(). + */ + +#ifndef FTEPARSE +#define FTEPARSE + + +#include "ftedata.h" + +struct pnode { + char *pn_name; /* If non-NULL, the name. */ + struct dvec *pn_value; /* Non-NULL in a terminal node. */ + struct func *pn_func; /* Non-NULL is a function. */ + struct op *pn_op; /* Operation if the above two NULL. */ + struct pnode *pn_left; /* Left branch or function argument. */ + struct pnode *pn_right; /* Right branch. */ + struct pnode *pn_next; /* For expression lists. */ +} ; + +/* Operations. These should really be considered functions. */ + +struct op { + int op_num; /* From parser #defines. */ + char *op_name; /* Printing name. */ + char op_arity; /* One or two. */ + struct dvec *(*op_func)(); /* The function to do the work. */ +} ; + +/* The functions that are available. */ + +struct func { + char *fu_name; /* The print name of the function. */ + void *(*fu_func)(); /* The function. */ +} ; + +/* User-definable functions. The idea of ud_name is that the args are + * kept in strings after the name, all seperated by '\0's. There + * will be ud_arity of them. + */ + +struct udfunc { + char *ud_name; /* The name. */ + int ud_arity; /* The arity of the function. */ + struct pnode *ud_text; /* The definition. */ + struct udfunc *ud_next; /* Link pointer. */ +} ; + +#define MAXARITY 32 + +/* Parser elements. */ + +struct element { + int e_token; /* One of the below. */ + int e_type; /* If the token is VALUE. */ + union { + char *un_string; + double un_double; + struct pnode *un_pnode; + } e_un; +#define e_string e_un.un_string +#define e_double e_un.un_double +#define e_indices e_un.un_indices +#define e_pnode e_un.un_pnode +}; + +/* See the table in parse.c */ + +#define END 0 +#define PLUS 1 +#define MINUS 2 +#define TIMES 3 +#define MOD 4 +#define DIVIDE 5 +#define POWER 6 +#define UMINUS 7 +#define LPAREN 8 +#define RPAREN 9 +#define COMMA 10 +#define VALUE 11 +#define EQ 12 +#define GT 13 +#define LT 14 +#define GE 15 +#define LE 16 +#define NE 17 +#define AND 18 +#define OR 19 +#define NOT 20 +#define INDX 21 +#define RANGE 22 + +#define NUM 1 +#define STRING 2 +#define PNODE 3 + +#endif /* FTEPARSE */ diff --git a/src/include/gendefs.h b/src/include/gendefs.h new file mode 100644 index 000000000..805ec2243 --- /dev/null +++ b/src/include/gendefs.h @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef GEN +#define GEN + +#include "ifsim.h" + + /* definitions used to describe generic devices */ + +/* information used to describe a single instance */ + +typedef struct sGENinstance { + struct sGENmodel *GENmodPtr; /* backpointer to model */ + struct sGENinstance *GENnextInstance; /* pointer to next instance of + * current model*/ + IFuid GENname; /* pointer to character string naming this instance */ + int GENowner; /* number of owner process */ + int GENstate; /* state index number */ + int GENnode1; /* appropriate node numbers */ + int GENnode2; /* appropriate node numbers */ + int GENnode3; /* appropriate node numbers */ + int GENnode4; /* appropriate node numbers */ + int GENnode5; /* appropriate node numbers */ +} GENinstance ; + + +/* Generic circuit data */ + +typedef void GENcircuit; + +/* per model data */ + +typedef struct sGENmodel { /* model structure for a resistor */ + int GENmodType; /* type index of this device type */ + struct sGENmodel *GENnextModel; /* pointer to next possible model in + * linked list */ + GENinstance * GENinstances; /* pointer to list of instances that have this + * model */ + IFuid GENmodName; /* pointer to character string naming this model */ +} GENmodel; + +#endif /*GEN*/ diff --git a/src/include/hlpdefs.h b/src/include/hlpdefs.h new file mode 100644 index 000000000..d539cbc17 --- /dev/null +++ b/src/include/hlpdefs.h @@ -0,0 +1,153 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +Modified 1999 Emmanuel Rouat +**********/ + +/* + * Definitions for the help system. + */ +# include + + + +#ifndef X_DISPLAY_MISSING +# include +#endif + +typedef struct fplace { + char *filename; + long fpos; + FILE *fp; +} fplace; + +typedef struct button { + char *text; + fplace *tag; /* Why isn't used for anything? */ + int x; + int y; + int width; + int height; +} button; + +struct hlp_index { + char subject[64]; + long fpos; +}; + +typedef struct toplink { + char *description; /* really the subject */ + fplace *place; + struct toplink *next; + button button; +} toplink; + +typedef struct topic { + char *subject; + char *title; + fplace *place; + wordlist *text; + char *chartext; + toplink *subtopics; + toplink *seealso; + int xposition; + int yposition; + struct topic *parent; + struct topic *children; + struct topic *next; + struct topic *winlink; + struct topic *readlink; + int numlines; + int maxcols; + int curtopline; + +#ifndef X_DISPLAY_MISSING + Widget shellwidget, formwidget, titlewidget, buttonwidget, + textwidget, seelabelwidget, sublabelwidget, seeboxwidget, subboxwidget; +#endif +} topic; + +typedef struct handle { + topic *parent; + toplink *result; +} handle; + +#define REG_FONT "timrom12" +#define BOLD_FONT "timrom12b" +#define ITALIC_FONT "timrom12i" +#define TITLE_FONT "accordb" +#define BUTTON_FONT "6x10" + +#define X_INCR 20 +#define Y_INCR 20 +#define BORDER_WIDTH 3 +#define INT_BORDER 10 +#define BUTTON_XPAD 4 +#define BUTTON_YPAD 2 + +#define START_XPOS 100 +#define START_YPOS 100 + +/* If the MAX_LINES and SCROLL_INCR are different, it is very confusing... */ + +#define MIN_COLS 40 +#define MAX_COLS 90 + +#define MAX_LINES 25 +#define SCROLL_INCR 25 + +#define BS_LEFT 0 +#define BS_CENTER 1 +#define BS_UNIF 2 + +/* External symbols. */ + +/* help.c */ + +extern char *hlp_directory; + +extern void hlp_main(char *path, wordlist *wl); +extern FILE *hlp_fopen(char *filename); +extern fplace *findglobalsubject(char *subject); +extern bool hlp_approvedfile(char *filename); +extern void hlp_pathfix(char *buf); + + +/* readhelp.c */ + +extern topic *hlp_read(fplace *place); +extern void hlp_free(void); +extern long findsubject(char *filename, char *subject); + +/* provide.c */ + +extern void hlp_provide(topic *top); +extern bool hlp_usex; +extern void hlp_fixchildren(topic *parent); +extern void hlp_killfamily(topic *top); + +/* xdisplay.c */ + +extern char *hlp_regfontname; +extern char *hlp_boldfontname; +extern char *hlp_italicfontname; +extern char *hlp_titlefontname; +extern char *hlp_buttonfontname; +extern int hlp_initxpos; +extern int hlp_initypos; +extern int hlp_buttonstyle; +extern char *hlp_displayname; +extern bool hlp_xdisplay(topic *top); +extern void hlp_xclosedisplay(void); +extern toplink *hlp_xhandle(topic **pp); +extern void hlp_xkillwin(topic *top); +extern void hlp_xwait(topic *top, bool on); + + +/* textdisp.c */ + +extern bool hlp_tdisplay(topic *top); +extern toplink *hlp_thandle(topic **parent); +extern void hlp_tkillwin(topic *top); +extern int hlp_width; + diff --git a/src/include/iferrmsg.h b/src/include/iferrmsg.h new file mode 100644 index 000000000..630b5b293 --- /dev/null +++ b/src/include/iferrmsg.h @@ -0,0 +1,58 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Thomas L. Quarles +**********/ + +/* + */ + +#ifndef IFERRMSGS +#define IFERRMSGS + + + /* common error message descriptions */ + +#define E_PAUSE -1 /* pausing on demand */ + +#define OK 0 + +#define E_PANIC 1 /* vague internal error for "can't get here" cases */ +#define E_EXISTS 2 /* warning/error - attempt to create duplicate */ + /* instance or model. Old one reused instead */ +#define E_NODEV 3 /* attempt to modify a non-existant instance */ +#define E_NOMOD 4 /* attempt to modify a non-existant model */ +#define E_NOANAL 5 /* attempt to modify a non-existant analysis */ +#define E_NOTERM 6 /* attempt to bind to a non-existant terminal */ +#define E_BADPARM 7 /* attempt to specify a non-existant parameter */ +#define E_NOMEM 8 /* insufficient memory available - VERY FATAL */ +#define E_NODECON 9 /* warning/error - node already connected, old */ + /* connection replaced */ +#define E_UNSUPP 10 /* the specified operation is unsupported by the */ + /* simulator */ +#define E_PARMVAL 11 /* the parameter value specified is illegal */ +#define E_NOTEMPTY 12 /* deleted still referenced item. */ +#define E_NOCHANGE 13 /* simulator can't tolerate any more topology changes */ +#define E_NOTFOUND 14 /* simulator can't find something it was looking for */ +#define E_BAD_DOMAIN 15 /* output interface begin/end domain calls mismatched */ + + +#define E_PRIVATE 100 /* messages above this number are private to */ + /* the simulator and MUST be accompanied by */ + /* a proper setting of errMsg */ + /* this constant should be added to all such messages */ + /* to ensure error free operation if it must be */ + /* changed in the future */ + +extern char *errMsg; /* descriptive message about what went wrong */ + /* MUST be malloc()'d - front end will free() */ + /* this should be a detailed message,and is assumed */ + /* malloc()'d so that you will feel free to add */ + /* lots of descriptive information with sprintf*/ + +extern char *errRtn; /* name of the routine declaring error */ + /* should not be malloc()'d, will not be free()'d */ + /* This should be a simple constant in your routine */ + /* and thus can be set correctly even if we run out */ + /* of memory */ + +#endif /*IFERRMSGS*/ diff --git a/src/include/ifsim.h b/src/include/ifsim.h new file mode 100644 index 000000000..8f5a4f734 --- /dev/null +++ b/src/include/ifsim.h @@ -0,0 +1,518 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Thomas L. Quarles +**********/ + +#ifndef IFSIMULATOR +#define IFSIMULATOR + +/* + * We don't always have access to an ANSI C compiler yet, so we + * make the following convenient definition + */ + + +/* Removed code for non STDC compilers Paolo Nenzi 2000*/ + +/* + * structure: IFparm + * + * + * The structure used to describe all values passed + * between the front end and the simulator when there is any + * possibility one argument of the function could have more + * than one type. + * + * keyword is provided for the front end and is the token + * the user is expected to label the data with. + * + * id is an integer intended to uniquely identify the parameter + * to the simulator + * + * dataType is an integer which indicates the type of argument + * that must be passed for this parameter + * + * description is a longer description intended for help menus + * the description should all fit on one line, but should + * give a knowledgable user a good idea what the parameter is + * used for. + */ + +typedef struct sIFparm { + char *keyword; + int id; + int dataType; + char *description; +} IFparm; + +/* + * + * datatype: IFuid + * + * unique identifier for all name-type data in the simulator. + * this permits the front end to use something other than + * a unique, fully qualified character string to identify + * an object. + * + */ + +typedef char *IFuid; + +/* + * + * types for IFnewUid + * + */ + +#define UID_ANALYSIS 0x1 +#define UID_TASK 0x2 +#define UID_INSTANCE 0x4 +#define UID_MODEL 0x8 +#define UID_SIGNAL 0x10 +#define UID_OTHER 0x20 + + +/* + * dataType values: + * + * Note: These structures are put together by ORing together the + * appropriate bits from the fields below as is shown for the vector + * types. + * IF_REQUIRED indicates that the parameter must be specified. + * The front end does not NEED to check for this, but can to save time, + * since failure to do so will cause the simulator to fail. + * IF_SET indicates that the specified item is an input parameter. + * IF_ASK indicates that the specified item is something the simulator + * can provide information about. + * IF_SET and IF_ASK are NOT mutually exclusive. + * if IF_SET and IF_ASK are both zero, it indicates a parameter that + * the simulator recoginizes are being a reasonable paremeter, but + * which this simulator does not implement. + */ + +#define IF_FLAG 0x1 +#define IF_INTEGER 0x2 +#define IF_REAL 0x4 +#define IF_COMPLEX 0x8 +#define IF_NODE 0x10 +#define IF_STRING 0x20 +#define IF_INSTANCE 0x40 +#define IF_PARSETREE 0x80 + +/* indicates that for a query the integer field will have a selector + * in it to pick a sub-field */ +#define IF_SELECT 0x800 +#define IF_VSELECT 0x400 + +/* indicates a vector of the specified type */ +#define IF_VECTOR 0x8000 + +#define IF_FLAGVEC (IF_FLAG|IF_VECTOR) +#define IF_INTVEC (IF_INTEGER|IF_VECTOR) +#define IF_REALVEC (IF_REAL|IF_VECTOR) +#define IF_CPLXVEC (IF_COMPLEX|IF_VECTOR) +#define IF_NODEVEC (IF_NODE|IF_VECTOR) +#define IF_STRINGVEC (IF_STRING|IF_VECTOR) +#define IF_INSTVEC (IF_INSTANCE|IF_VECTOR) + +#define IF_REQUIRED 0x4000 + +#define IF_VARTYPES 0x80ff + +#define IF_SET 0x2000 +#define IF_ASK 0x1000 + +/* If you AND with IF_UNIMP_MASK and get 0, it is recognized, but not + * implemented + */ +#define IF_UNIMP_MASK (~0xfff) + +/* Used by sensetivity to check if a parameter is or is not useful */ +#define IF_REDUNDANT 0x0010000 +#define IF_PRINCIPAL 0x0020000 +#define IF_AC 0x0040000 +#define IF_AC_ONLY 0x0080000 +#define IF_NOISE 0x0100000 +#define IF_NONSENSE 0x0200000 + +#define IF_SETQUERY 0x0400000 +#define IF_ORQUERY 0x0800000 +#define IF_CHKQUERY 0x1000000 + +/* For "show" command: do not print value in a table by default */ +#define IF_UNINTERESTING 0x2000000 + +/* Structure: IFparseTree + * + * This structure is returned by the parser for a IF_PARSETREE valued + * parameter and describes the information that the simulator needs + * to know about the parse tree in order to use it. + * It is expected that the front end will have a more extensive + * structure which this structure will be a prefix of. + * + * Note that the function pointer is provided as a hook for + * versions which may want to compile code for the parse trees + * if they are used heavily. + * + */ + +typedef struct sIFparseTree { + int numVars; /* number of variables used */ + int *varTypes; /* array of types of variables */ + union uIFvalue * vars; /* array of structures describing values */ +#ifdef __STDC__ + int ((*IFeval)(struct sIFparseTree*,double,double*,double*,double*)); +#else + int ((*IFeval)()); /* function to call to get evaluated */ +#endif /* STDC */ +} IFparseTree; + + +/* + * Structure: IFvalue + * + * structure used to pass the values corresponding to the above + * dataType. All types are passed in one of these structures, with + * relatively simple rules concerning the handling of the structure. + * + * whoever makes the subroutine call allocates a single instance of the + * structure. The basic data structure belongs to you, and you + * should arrange to free it when appropriate. + * + * The responsibilities of the data supplier are: + * Any vectors referenced by the structure are to be malloc()'d + * and are assumed to have been turned over to the recipient and + * thus should not be re-used or free()'d. + * + * The responsibilities of the data recipient are: + * scalar valued data is to be copied by the recipient + * vector valued data is now the property of the recipient, + * and must be free()'d when no longer needed. + * + * Character strings are a special case: Since it is assumed + * that all character strings are directly descended from input + * tokens, it is assumed that they are static, thus nobody + * frees them until the circuit is deleted, when the front end + * may do so. + * + * EVERYBODY's responsibility is to be SURE that the right data + * is filled in and read out of the structure as per the IFparm + * structure describing the parameter being passed. Programs + * neglecting this rule are fated to die of data corruption + * + */ + +/* + * Some preliminary definitions: + * + * IFnode's are returned by the simulator, thus we don't really + * know what they look like, just that we get to carry pointers + * to them around all the time, and will need to save them occasionally + * + */ + + +typedef void * IFnode; + +/* + * and of course, the standard complex data type + */ +typedef struct sIFcomplex { + double real; + double imag; +} IFcomplex; + + +typedef union uIFvalue { + int iValue; /* integer or flag valued data */ + double rValue; /* real valued data */ + IFcomplex cValue; /* complex valued data */ + char *sValue; /* string valued data */ + IFuid uValue; /* UID valued data */ + IFnode nValue; /* node valued data */ + IFparseTree *tValue; /* parse tree */ + struct { + int numValue; /* length of vector */ + union { + int *iVec; /* pointer to integer vector */ + double *rVec; /* pointer to real vector */ + IFcomplex *cVec;/* pointer to complex vector */ + char **sVec; /* pointer to string vector */ + IFuid *uVec; /* pointer to UID vector */ + IFnode *nVec; /* pointer to node vector */ + }vec; + }v; +} IFvalue; + + +/* + * structure: IFdevice + * + * This structure contains all the information available to the + * front end about a particular device. The simulator will + * present the front end with an array of pointers to these structures + * which it will use to determine legal device types and parameters. + * + * Note to simulators: you are passing an array of pointers to + * these structures, so you may in fact make this the first component + * in a larger, more complex structure which includes other data + * which you need, but which is not needed in the common + * front end interface. + * + */ + +typedef struct sIFdevice { + char *name; /* name of this type of device */ + char *description; /* description of this type of device */ + + int *terms; /* number of terminals on this device */ + int *numNames; /* number of names in termNames */ + char **termNames; /* pointer to array of pointers to names */ + /* array contains 'terms' pointers */ + + int *numInstanceParms; /* number of instance parameter descriptors */ + IFparm *instanceParms; /* array of instance parameter descriptors */ + + int *numModelParms; /* number of model parameter descriptors */ + IFparm *modelParms; /* array of model parameter descriptors */ + + int flags; /* DEV_ */ + +} IFdevice; + + +/* + * Structure: IFanalysis + * + * This structure contains all the information available to the + * front end about a particular analysis type. The simulator will + * present the front end with an array of pointers to these structures + * which it will use to determine legal analysis types and parameters. + * + * Note to simulators: As for IFdevice above, you pass an array of pointers + * to these, so you can make this structure a prefix to a larger structure + * which you use internally. + * + */ + +typedef struct sIFanalysis { + char *name; /* name of this analysis type */ + char *description; /* description of this type of analysis */ + + int numParms; /* number of analysis parameter descriptors */ + IFparm *analysisParms; /* array of analysis parameter descriptors */ + +} IFanalysis; + + +/* + * Structure: IFsimulator + * + * This is what we have been leading up to all along. + * This structure describes a simulator to the front end, and is + * returned from the SIMinit command to the front end. + * This is where all those neat structures we described in the first + * few hundred lines of this file come from. + * + */ + +typedef struct sIFsimulator { + char *simulator; /* the simulator's name */ + char *description; /* description of this simulator */ + char *version; /* version or revision level of simulator*/ + +#ifdef __STDC__ + int ((*newCircuit)(void **)); + /* create new circuit */ + int ((*deleteCircuit)(void *)); + /* destroy old circuit's data structures*/ + + int ((*newNode)(void *,void**,IFuid)); + /* create new node */ + int ((*groundNode)(void*,void**,IFuid)); + /* create ground node */ + int ((*bindNode)(void *,void*,int,void*)); + /* bind a node to a terminal */ + int ((*findNode)(void *,void**,IFuid)); + /* find a node by name */ + int ((*instToNode)(void *,void *,int,void **,IFuid *)); + /* find the node attached to a terminal */ + int ((*setNodeParm)(void*,void*,int,IFvalue*,IFvalue*)); + /* set a parameter on a node */ + int ((*askNodeQuest)(void*,void*,int,IFvalue*,IFvalue*)); + /* ask a question about a node */ + int ((*deleteNode)(void*,void*)); + /* delete a node from the circuit */ + + int ((*newInstance)(void*,void*,void**,IFuid)); + /* create new instance */ + int ((*setInstanceParm)(void*,void*,int,IFvalue*,IFvalue*)); + /* set a parameter on an instance */ + int ((*askInstanceQuest)(void*,void*,int,IFvalue*,IFvalue*)); + /* ask a question about an instance */ + int ((*findInstance)(void*,int*,void**,IFuid,void*,IFuid)); + /* find a specific instance */ + int ((*deleteInstance)(void*,void*)); + /* delete an instance from the circuit */ + + int ((*newModel)(void*,int,void**,IFuid)); + /* create new model */ + int ((*setModelParm)(void*,void*,int,IFvalue*,IFvalue*)); + /* set a parameter on a model */ + int ((*askModelQuest)(void*,void*,int,IFvalue*,IFvalue*)); + /* ask a questions about a model */ + int ((*findModel)(void*,int*,void**,IFuid)); + /* find a specific model */ + int ((*deleteModel)(void*,void*)); + /* delete a model from the circuit*/ + + int ((*newTask)(void*,void**,IFuid)); + /* create a new task */ + int ((*newAnalysis)(void*,int,IFuid,void**,void*)); + /* create new analysis within a task */ + int ((*setAnalysisParm)(void*,void*,int,IFvalue*,IFvalue*)); + /* set a parameter on an analysis */ + int ((*askAnalysisQuest)(void*,void*,int,IFvalue*,IFvalue*)); + /* ask a question about an analysis */ + int ((*findAnalysis)(void*,int*,void**,IFuid,void*,IFuid)); + /* find a specific analysis */ + int ((*findTask)(void*,void**,IFuid)); + /* find a specific task */ + int ((*deleteTask)(void*,void*)); + /* delete a task */ + + int ((*doAnalyses)(void*,int,void*)); + char *((*nonconvErr)(void*,char *)); /* return nonconvergence error */ +#else + int ((*newCircuit)()); /* create new circuit */ + int ((*deleteCircuit)()); /* destroy old circuit's data structures */ + + int ((*newNode)()); /* create new node */ + int ((*groundNode)()); /* create ground node */ + int ((*bindNode)()); /* bind a node to a terminal */ + int ((*findNode)()); /* find a node by name */ + int ((*instToNode)()); /* find the node attached to a terminal */ + int ((*setNodeParm)()); /* set a parameter on a node */ + int ((*askNodeQuest)()); /* ask a question about a node */ + int ((*deleteNode)()); /* delete a node from the circuit */ + + int ((*newInstance)()); /* create new instance */ + int ((*setInstanceParm)()); /* set a parameter on an instance */ + int ((*askInstanceQuest)()); /* ask a question about an instance */ + int ((*findInstance)()); /* find a specific instance */ + int ((*deleteInstance)()); /* delete an instance from the circuit */ + + int ((*newModel)()); /* create new model */ + int ((*setModelParm)()); /* set a parameter on a model */ + int ((*askModelQuest)()); /* ask a questions about a model */ + int ((*findModel)()); /* find a specific model */ + int ((*deleteModel)()); /* delete a model from the circuit*/ + + int ((*newTask)()); /* create a new task */ + int ((*newAnalysis)()); /* create new analysis within a task */ + int ((*setAnalysisParm)()); /* set a parameter on an analysis */ + int ((*askAnalysisQuest)()); /* ask a question about an analysis */ + int ((*findAnalysis)()); /* find a specific analysis */ + int ((*findTask)()); /* find a specific task */ + int ((*deleteTask)()); /* delete a task */ + + int ((*doAnalyses)()); /* run a specified task */ + char *((*nonconvErr)()); /* return nonconvergence error */ +#endif /* STDC */ + + int numDevices; /* number of device types supported */ + IFdevice **devices; /* array of device type descriptors */ + + int numAnalyses; /* number of analysis types supported */ + IFanalysis **analyses; /* array of analysis type descriptors */ + + int numNodeParms; /* number of node parameters supported */ + IFparm *nodeParms; /* array of node parameter descriptors */ + + int numSpecSigs; /* number of special signals legal in parse trees */ + char **specSigs; /* names of special signals legal in parse trees */ + +} IFsimulator; + +/* + * Structure: IFfrontEnd + * + * This structure provides the simulator with all the information + * it needs about the front end. This is the entire set of + * front end and back end related routines the simulator + * should know about. + * + */ + +typedef struct sIFfrontEnd { +#ifdef __STDC__ + int ((*IFnewUid)(void*,IFuid*,IFuid,char*,int,void**)); + /* create a new UID in the circuit */ + int ((*IFdelUid)(void*,IFuid,int)); + /* create a new UID in the circuit */ + int ((*IFpauseTest)(void)); + /* should we stop now? */ + double ((*IFseconds)(void)); + /* what time is it? */ + int ((*IFerror)(int,char*,IFuid*)); + /* output an error or warning message */ + int ((*OUTpBeginPlot)(void*,void*,IFuid,IFuid,int, + int,IFuid*,int,void**)); + /* start pointwise output plot */ + int ((*OUTpData)(void*,IFvalue*,IFvalue*)); + /* data for pointwise plot */ + int ((*OUTwBeginPlot)(void*,void*,IFuid,IFuid,int, + int,IFuid*,int,void**)); + /* start windowed output plot */ + int ((*OUTwReference)(void*,IFvalue*,void**)); + /* independent vector for windowed plot */ + int ((*OUTwData)(void*,int,IFvalue*,void*)); + /* data for windowed plot */ + int ((*OUTwEnd)(void*)); + /* signal end of windows */ + int ((*OUTendPlot)(void*)); + /* end of plot */ + int ((*OUTbeginDomain)(void*,IFuid,int,IFvalue*)); + /* start nested domain */ + int ((*OUTendDomain)(void*)); + /* end nested domain */ + int ((*OUTattributes)(void *,IFuid*,int,IFvalue*)); + /* specify output attributes of node */ +#else /* not STDC */ + int ((*IFnewUid)()); /* create a new UID in the circuit */ + int ((*IFdelUid)()); /* create a new UID in the circuit */ + int ((*IFpauseTest)()); /* should we stop now? */ + double ((*IFseconds)()); /* what time is it? */ + int ((*IFerror)()); /* output an error or warning message */ + int ((*OUTpBeginPlot)()); /* start pointwise output plot */ + int ((*OUTpData)()); /* data for pointwise plot */ + int ((*OUTwBeginPlot)()); /* start windowed output plot */ + int ((*OUTwReference)()); /* independent vector for windowed plot */ + int ((*OUTwData)()); /* data for windowed plot */ + int ((*OUTwEnd)()); /* signal end of windows */ + int ((*OUTendPlot)()); /* end of plot */ + int ((*OUTbeginDomain)()); /* start nested domain */ + int ((*OUTendDomain)()); /* end nested domain */ + int ((*OUTattributes)()); /* specify output attributes of node */ +#endif /* STDC */ +} IFfrontEnd; + +/* flags for the first argument to IFerror */ +#define ERR_WARNING 0x1 +#define ERR_FATAL 0x2 +#define ERR_PANIC 0x4 +#define ERR_INFO 0x8 + + /* valid values for the second argument to doAnalyses */ + + /* continue the analysis from where we left off */ +#define RESUME 0 + /* start everything over from the beginning of this task*/ +#define RESTART 1 + /* abandon the current analysis and go on the the next in the task*/ +#define SKIPTONEXT 2 + +#define OUT_SCALE_LIN 1 +#define OUT_SCALE_LOG 2 + +#endif /*IFSIMULATOR*/ diff --git a/src/include/inpdefs.h b/src/include/inpdefs.h new file mode 100644 index 000000000..8f7cfa7e1 --- /dev/null +++ b/src/include/inpdefs.h @@ -0,0 +1,197 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef INP +#define INP + + /* structure declarations used by either/both input package */ + +#include "ifsim.h" +#include "gendefs.h" +#include "inpptree.h" + +struct INPtab { + char *t_ent; + struct INPtab *t_next; +}; + +struct INPnTab { + char *t_ent; + void* t_node; + struct INPnTab *t_next; +}; + +typedef struct sINPtables{ + struct INPtab **INPsymtab; + struct INPnTab **INPtermsymtab; + int INPsize; + int INPtermsize; + void *defAmod; + void *defBmod; + void *defCmod; + void *defDmod; + void *defEmod; + void *defFmod; + void *defGmod; + void *defHmod; + void *defImod; + void *defJmod; + void *defKmod; + void *defLmod; + void *defMmod; + void *defNmod; + void *defOmod; + void *defPmod; + void *defQmod; + void *defRmod; + void *defSmod; + void *defTmod; + void *defUmod; + void *defVmod; + void *defWmod; + void *defYmod; + void *defZmod; +} INPtables; + +typedef struct card{ + int linenum; + char *line; + char *error; + struct card *nextcard; + struct card *actualLine; +} card; + +/* structure used to save models in after they are read during pass 1 */ +typedef struct sINPmodel{ + IFuid INPmodName; /* uid of model */ + int INPmodType; /* type index of device type */ + struct sINPmodel *INPnextModel; /* link to next model */ + int INPmodUsed; /* flag to indicate it has already been used */ + card *INPmodLine; /* pointer to line describing model */ + void *INPmodfast; /* high speed pointer to model for access */ +} INPmodel; + +/* listing types - used for debug listings */ +#define LOGICAL 1 +#define PHYSICAL 2 + +#ifdef __STDC__ +int IFnewUid(void*,IFuid*,IFuid,char*,int,void**); +int IFdelUid(void*,IFuid,int); +int INPaName(char*,IFvalue*,void*,int*,char*,void**,IFsimulator*,int*, + IFvalue*); +int INPapName(void*,int,void*,char*,IFvalue*); +void INPcaseFix(char*); +char * INPdevParse(char**,void*,int,void*,double*,int*,INPtables*); +char *INPdomodel(void *,card*, INPtables*); +void INPdoOpts(void*,void*,card*,INPtables*); +char *INPerrCat(char *, char *); +char *INPerror(int); +double INPevaluate(char**,int*,int); +char * INPfindLev(char*,int*); +char * INPgetMod(void*,char*,INPmodel**,INPtables*); +int INPgetTok(char**,char**,int); +void INPgetTree(char**,INPparseTree**,void*,INPtables*); +IFvalue * INPgetValue(void*,char**,int,INPtables*); +int INPgndInsert(void*,char**,INPtables*,void**); +int INPinsert(char**,INPtables*); +int INPretrieve(char**,INPtables*); +int INPremove(char*,INPtables*); +int INPlookMod(char*); +int INPmakeMod(char*,int,card*); +char *INPmkTemp(char*); +void INPpas1(void*,card*,INPtables*); +void INPpas2(void*,card*,INPtables*,void *); +int INPpName(char*,IFvalue*,void*,int,void*); +int INPtermInsert(void*,char**,INPtables*,void**); +int INPmkTerm(void*,char**,INPtables*,void**); +int INPtypelook(char*); +void INP2B(void*,INPtables*,card*); +void INP2C(void*,INPtables*,card*); +void INP2D(void*,INPtables*,card*); +void INP2E(void*,INPtables*,card*); +void INP2F(void*,INPtables*,card*); +void INP2G(void*,INPtables*,card*); +void INP2H(void*,INPtables*,card*); +void INP2I(void*,INPtables*,card*); +void INP2J(void*,INPtables*,card*); +void INP2K(void*,INPtables*,card*); +void INP2L(void*,INPtables*,card*); +void INP2M(void*,INPtables*,card*); +void INP2O(void*,INPtables*,card*); +void INP2Q(void*,INPtables*,card*,void*); +void INP2R(void*,INPtables*,card*); +void INP2S(void*,INPtables*,card*); +void INP2T(void*,INPtables*,card*); +void INP2U(void*,INPtables*,card*); +void INP2V(void*,INPtables*,card*); +void INP2W(void*,INPtables*,card*); +void INP2Z(void*,INPtables*,card*); +int INP2dot(void*,INPtables*,card*,void*,void*); +INPtables *INPtabInit(int); +void INPkillMods(void); +void INPtabEnd(INPtables *); +#else /* stdc */ +int IFnewUid(); +int IFdelUid(); +int INPaName(); +IFvalue * INPgetValue(); +INPtables *INPtabInit(); +char * INPdevParse(); +char * INPdomodel(); +char * INPerrCat(); +char * INPfindLev(); +char * INPgetMod(); +char *INPerror(); +char *INPmkTemp(); +double INPevaluate(); +int INPapName(); +int INPgetTitle(); +int INPgetTok(); +int INPgndInsert(); +int INPlookMod(); +int INPmakeMod(); +int INPpName(); +int INPreadAll(); +int INPtermInsert(); +int INPmkTerm(); +int INPtypelook(); +void INPcaseFix(); +void INPdoOpts(); +int INPinsert(); +int INPretrieve(); +int INPremove(); +void INPkillMods(); +void INPlist(); +void INPpas1() ; +void INPpas2() ; +void INPtabEnd(); +void INPptPrint(); +void INPgetTree(); +void INP2B(); +void INP2C(); +void INP2D(); +void INP2E(); +void INP2F(); +void INP2G(); +void INP2H(); +void INP2I(); +void INP2J(); +void INP2K(); +void INP2L(); +void INP2M(); +void INP2O(); +void INP2Q(); +void INP2R(); +void INP2S(); +void INP2T(); +void INP2U(); +void INP2V(); +void INP2W(); +void INP2Z(); +int INP2dot(); +#endif /* stdc */ + +#endif /*INP*/ diff --git a/src/include/inpmacs.h b/src/include/inpmacs.h new file mode 100644 index 000000000..02aaa7604 --- /dev/null +++ b/src/include/inpmacs.h @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +/* a couple of macros to make much of the input code + * much much shorter and easier to handle. + * + * First, call the simulator function 'func', giving it the arglist + * 'args' (must have its own parens!) and check the error returned. + * If necessary, get the proper error message and tack it on the current + * error + */ +#define IFC(func,args)\ +error=(*(ft_sim->func))args;\ +if(error)current->error = INPerrCat(current->error,INPerror(error)); + +/* and one for calling more General functions that still return an + * error code as above + */ +#define GCA(func,args)\ +error=func args;\ +if(error)current->error = INPerrCat(current->error,INPerror(error)); + +/* and one for putting our own error messages onto the current + * line's error string + */ +#define LITERR(text) current->error=INPerrCat(current->error,INPmkTemp(text)); + + +/* and now a special one for calling INPdevParse which returns an + * already concatenated list of error messages or NUL + */ +#define PARSECALL(args)\ +current->error = INPerrCat(current->error,INPdevParse args ); diff --git a/src/include/inpptree.h b/src/include/inpptree.h new file mode 100644 index 000000000..1d08ea7df --- /dev/null +++ b/src/include/inpptree.h @@ -0,0 +1,170 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * faustus@cad.berkeley.edu, ucbvax!faustus + * + * These definitions specify the format of the parse tree parameter type. + * The first four are the elements of IFparseTree, defined in IFsim.h. + */ + +#include "ifsim.h" + +#ifndef INP_PARSE +#define INP_PARSE + + +/* This is the parameter value passed to the device routines. To get the + * value of the function, where tree is a pointer to the INPparseTree, + * result is a pointer to where you want the result, derivs is a pointer to + * an vector of numVars doubles, and vals is a pointer to the selected + * elements from the RHS, do + * tree->p.IFeval(&tree, result, vals, derivs) + * This routine will return either OK, E_PARMVAL, or E_PANIC. If an error + * is reported the eval function will have printed something to standard + * out before returning. + */ + +typedef struct INPparseTree { + IFparseTree p; + struct INPparseNode *tree; /* The real stuff. */ + struct INPparseNode **derivs; /* The derivative parse trees. */ +} INPparseTree; + +/* This is what is passed as the actual parameter value. The fields will all + * be filled in as needed. + * + * Values with names like v(something) and i(something) are treated specially. + * They are considered voltages at nodes and branch currents through + * voltage sources, respectively. The corresponding parameters will be of + * type IF_NODE and IF_INSTANCE, respectively. + */ + +typedef struct INPparseNode { + int type; /* One of PT_*, below. */ + struct INPparseNode *left; /* Left operand, or single operand. */ + struct INPparseNode *right; /* Right operand, if there is one. */ + double constant; /* If INP_CONSTANT. */ + int valueIndex; /* If INP_VAR, index into vars array. */ + char *funcname; /* If INP_FUNCTION, name of function, */ + int funcnum; /* ... one of PTF_*, */ + double (*function)(); /* ... and pointer to the function. */ +} INPparseNode; + +/* These are the possible types of nodes we can have in the parse tree. The + * numbers for the ops 1 - 5 have to be the same as the token numbers, + * below. + */ + +#define PT_PLACEHOLDER 0 /* For i(something) ... */ +#define PT_PLUS 1 +#define PT_MINUS 2 +#define PT_TIMES 3 +#define PT_DIVIDE 4 +#define PT_POWER 5 +#define PT_FUNCTION 6 +#define PT_CONSTANT 7 +#define PT_VAR 8 +#define PT_COMMA 10 + +/* These are the functions that we support. */ + +#define PTF_ACOS 0 +#define PTF_ACOSH 1 +#define PTF_ASIN 2 +#define PTF_ASINH 3 +#define PTF_ATAN 4 +#define PTF_ATANH 5 +#define PTF_COS 6 +#define PTF_COSH 7 +#define PTF_EXP 8 +#define PTF_LN 9 +#define PTF_LOG 10 +#define PTF_SIN 11 +#define PTF_SINH 12 +#define PTF_SQRT 13 +#define PTF_TAN 14 +#define PTF_TANH 15 +#define PTF_UMINUS 16 +#define PTF_ABS 17 +#define PTF_SGN 18 +#define PTF_USTEP 19 +#define PTF_URAMP 20 + +/* The following things are used by the parser -- these are the token types the + * lexer returns. + */ + +#define TOK_END 0 +#define TOK_PLUS 1 +#define TOK_MINUS 2 +#define TOK_TIMES 3 +#define TOK_DIVIDE 4 +#define TOK_POWER 5 +#define TOK_UMINUS 6 +#define TOK_LPAREN 7 +#define TOK_RPAREN 8 +#define TOK_VALUE 9 +#define TOK_COMMA 10 + +/* And the types for value tokens... */ + +#define TYP_NUM 0 +#define TYP_STRING 1 +#define TYP_PNODE 2 + +/* A parser stack element. */ + +typedef struct PTelement { + int token; + int type; + union { + char *string; + double real; + INPparseNode *pnode; + } value; +} PTelement ; + +#define PT_STACKSIZE 200 + +/* These are things defined in PTfunctions.c */ + +extern double PTplus(); +extern double PTminus(); +extern double PTtimes(); +extern double PTdivide(); +extern double PTpower(); +extern double PTacos(); +extern double PTabs(); +extern double PTacosh(); +extern double PTasin(); +extern double PTasinh(); +extern double PTatan(); +extern double PTatanh(); +extern double PTcos(); +extern double PTcosh(); +extern double PTexp(); +extern double PTln(); +extern double PTlog(); +extern double PTsgn(); +extern double PTsin(); +extern double PTsinh(); +extern double PTsqrt(); +extern double PTtan(); +extern double PTtanh(); +extern double PTustep(); +extern double PTuramp(); +extern double PTuminus(); + +/* And in IFeval.c */ + +#ifdef __STDC__ +extern int IFeval(IFparseTree *, double, double*, double*, double*); +#else /* stdc */ +extern int IFeval(); +#endif /* stdc */ + +#endif + diff --git a/src/include/jobdefs.h b/src/include/jobdefs.h new file mode 100644 index 000000000..71bbe2412 --- /dev/null +++ b/src/include/jobdefs.h @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef JOBdef +#define JOBdef + + +#include "ifsim.h" + +typedef struct sJOB{ + int JOBtype; /* type of job */ + struct sJOB *JOBnextJob; /* next job in list */ + IFuid JOBname; /* name of this job */ + +} JOB; + +typedef struct { + IFanalysis public; + int size; + int domain; + int do_ic; + int (*(setParm))( ); + int (*(askQuest))( ); + int (*an_init)( ); + int (*an_func)( ); +} SPICEanalysis; + +#define NODOMAIN 0 +#define TIMEDOMAIN 1 +#define FREQUENCYDOMAIN 2 +#define SWEEPDOMAIN 3 + +#endif /*JOBdef*/ diff --git a/src/include/macros.h b/src/include/macros.h new file mode 100644 index 000000000..486df0741 --- /dev/null +++ b/src/include/macros.h @@ -0,0 +1,114 @@ +/************* + * Macros definitions header file + * 1999 E. Rouat + ************/ + +/* + * This file will contain all macros definitions needed + * by ngspice code. (in construction) + */ + + +#ifndef _MACROS_H_ +#define _MACROS_H_ + +#define NUMELEMS(ARRAY) (sizeof(ARRAY)/sizeof(*ARRAY)) + +/* + * Macros for complex mathematical functions. + */ + +/* Some defines used mainly in cmath.c. */ +#define alloc_c(len) ((complex *) tmalloc((len) * sizeof (complex))) +#define alloc_d(len) ((double *) tmalloc((len) * sizeof (double))) +#define FTEcabs(d) (((d) < 0.0) ? - (d) : (d)) +#define cph(c) (atan2(imagpart(c), (realpart(c)))) +#define cmag(c) (sqrt(imagpart(c) * imagpart(c) + realpart(c) * realpart(c))) +#define radtodeg(c) (cx_degrees ? ((c) / 3.14159265358979323846 * 180) : (c)) +#define degtorad(c) (cx_degrees ? ((c) * 3.14159265358979323846 / 180) : (c)) +#define rcheck(cond, name) if (!(cond)) { \ + fprintf(cp_err, "Error: argument out of range for %s\n", name); \ + return (NULL); } + + +#define cdiv(r1, i1, r2, i2, r3, i3) \ +{ \ + double r, s; \ + if (FTEcabs(r2) > FTEcabs(i2)) { \ + r = (i2) / (r2); \ + s = (r2) + r * (i2); \ + (r3) = ((r1) + r * (i1)) / s; \ + (i3) = ((i1) - r * (r1)) / s; \ + } else { \ + r = (r2) / (i2); \ + s = (i2) + r * (r2); \ + (r3) = (r * (r1) + (i1)) / s; \ + (i3) = (r * (i1) - (r1)) / s; \ + } \ +} + + + + +#define tfree(x) (txfree(x), x = 0) +#define alloc(TYPE) ((TYPE *) tmalloc(sizeof(TYPE))) + + +#define eq(a,b) (!strcmp((a), (b))) +#define eqc(a,b) (cieq((a), (b))) +#define isalphanum(c) (isalpha(c) || isdigit(c)) +#define hexnum(c) ((((c) >= '0') && ((c) <= '9')) ? ((c) - '0') : ((((c) >= \ + 'a') && ((c) <= 'f')) ? ((c) - 'a' + 10) : ((((c) >= 'A') && \ + ((c) <= 'F')) ? ((c) - 'A' + 10) : 0))) + +#define MALLOC(x) tmalloc((unsigned)(x)) +#define FREE(x) {if (x) {free((char *)(x));(x) = 0;}} +#define REALLOC(x,y) trealloc((char *)(x),(unsigned)(y)) +#define ZERO(PTR,TYPE) (bzero((PTR),sizeof(TYPE))) + + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define SIGN(a,b) ( b >= 0 ? (a >= 0 ? a : - a) : (a >= 0 ? - a : a)) + +#define ABORT() fflush(stderr);fflush(stdout);abort(); + +#define ERROR(CODE,MESSAGE) { \ + errMsg = MALLOC(strlen(MESSAGE) + 1); \ + strcpy(errMsg, (MESSAGE)); \ + return (CODE); \ + } + +#define NEW(TYPE) ((TYPE *) MALLOC(sizeof(TYPE))) +#define NEWN(TYPE,COUNT) ((TYPE *) MALLOC(sizeof(TYPE) * (COUNT))) + + +#define R_NORM(A,B) { \ + if ((A) == 0.0) { \ + (B) = 0; \ + } else { \ + while (fabs(A) > 1.0) { \ + (B) += 1; \ + (A) /= 2.0; \ + } \ + while (fabs(A) < 0.5) { \ + (B) -= 1; \ + (A) *= 2.0; \ + } \ + } \ + } + + +#ifdef DEBUG +#define DEBUGMSG(textargs) printf(textargs) +#else +#define DEBUGMSG(testargs) +#endif + + +#define realpart(cval) ((struct _complex *) (cval))->cx_real +#define imagpart(cval) ((struct _complex *) (cval))->cx_imag + + + +#endif /* _MACROS_H_ */ diff --git a/src/include/missing_math.h b/src/include/missing_math.h new file mode 100644 index 000000000..85218b50e --- /dev/null +++ b/src/include/missing_math.h @@ -0,0 +1,21 @@ +/********** +Copyright 1999 Emmanuel Rouat +**********/ + + +/* Decl. for missing maths functions, if any */ + + +#ifndef HAVE_ERFC +extern double erfc(double); +#endif + +#ifndef HAVE_LOGB +extern double logb(double); +#endif + +#ifndef HAVE_SCALB +# ifndef HAVE_SCALBN +extern double scalb(double, int); +#endif +#endif diff --git a/src/include/ngspice.h b/src/include/ngspice.h new file mode 100644 index 000000000..31026b5d1 --- /dev/null +++ b/src/include/ngspice.h @@ -0,0 +1,154 @@ +/************* + * Main header file for ngspice + * 1999 E. Rouat + ************/ + +/* + * This file will eventually replace spice.h and lots of other + * files in src/include + */ + + +#include +#include +#include + + + +#include "defines.h" +#include "macros.h" + + +#ifdef STDC_HEADERS +# include +# include +#else +# include +#endif + +#ifdef HAVE_CTYPE_H +# include +#endif + +#ifdef HAVE_TERMIOS_H +#include +#else +# ifdef HAVE_SGTTY_H +# include +# else +# ifdef HAVE_TERMIO_H +# include +# endif +# endif +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + +#ifdef HAVE_SYS_DIR_H +#include +#include +#else +# ifdef HAVE_DIRENT_H +# include +# include +# ifndef direct +# define direct dirent +# endif +# endif +#endif + +#ifdef HAVE_GETRLIMIT +# include +# include +#endif +#ifdef HAVE_GETRUSAGE +# ifndef HAVE_GETRLIMIT +# include +# include +# endif +#else +# ifdef HAVE_TIMES +# include +# include +# else +# ifdef HAVE_FTIME +# include +struct timeb timebegin; +# endif +# endif +#endif + +#ifdef HAVE_INDEX +# define strchr index +# define strrchr rindex +#endif + +#ifdef HAS_TIME_ +# ifdef HAVE_GETTIMEOFDAY +/* extern char *timezone(); */ /* never used ? (ER) */ +# endif +extern char *asctime(); +extern struct tm *localtime(); +#endif + +extern char *sbrk(); + + + +/* Functions declarations from src/misc/[].c */ + +extern void *tmalloc(size_t num); +extern void *trealloc(void *str, size_t num); +extern void txfree(void *ptr); + +extern char *gettok(char **s); +extern void appendc(char *s, char c); +extern int scannum(char *str); +extern int ciprefix(register char *p, register char *s); +extern int cieq(register char *p, register char *s); +extern void strtolower(char *str); +extern char *tilde_expand(char *string); + +extern char *smktemp(char *id); + +extern char *copy(); +extern int prefix(); +extern int substring(); +extern void cp_printword(); + +extern char *datestring(); +extern double seconds(void); + +/* Some external variables */ + +extern char *Spice_Exec_Dir; +extern char *Spice_Lib_Dir; +extern char *Def_Editor; +extern char *Bug_Addr; +extern int AsciiRawFile; +extern char *Spice_Host; +extern char *Spiced_Log; + +extern char Spice_Notice[ ]; +extern char Spice_Version[ ]; +extern char Spice_Build_Date[ ]; + +extern char *News_File; +extern char *Default_MFB_Cap; +extern char *Spice_Path; +extern char *Help_Path; +extern char *Lib_Path; + +extern int ARCHme; /* My logical process number */ +extern int ARCHsize; /* Total number of processes */ diff --git a/src/include/noisedef.h b/src/include/noisedef.h new file mode 100644 index 000000000..db5452082 --- /dev/null +++ b/src/include/noisedef.h @@ -0,0 +1,127 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#ifndef NOISEDEFS +#define NOISEDEFS + +#include "jobdefs.h" + + /* structure used to describe an noise analysis */ + +typedef struct { + int JOBtype; + JOB *JOBnextJob; /* pointer to next thing to do */ + char *JOBname; /* name of this job */ + IFnode output; /* noise output summation node */ + IFnode outputRef; /* noise output reference node */ + IFuid input; /* name of the AC source used as input reference */ + double NstartFreq; + double NstopFreq; + double NfreqDelta; /* multiplier for decade/octave stepping, */ + /* step for linear steps. */ + double NsavFstp; /* frequency step at which we stopped last time */ + double NsavOnoise; /* integrated output noise when we left off last time */ + double NsavInoise; /* integrated input noise when we left off last time */ + int NstpType; /* values described below */ + int NnumSteps; + int NStpsSm; /* number of steps before we output a noise summary report */ +} NOISEAN; + + + + /* structure used to carry information between subparts of the noise analysis code */ + +typedef struct { + double freq; + double lstFreq; + double delFreq; + double outNoiz; /* integrated output noise as of the last frequency point */ + double inNoise; /* integrated input noise as of the last frequency point */ + double GainSqInv; + double lnGainInv; + double lnFreq; + double lnLastFreq; + double delLnFreq; + int outNumber; /* keeps track of the current output variable */ + int numPlots; /* keeps track of the number of active plots so we can close them in */ + /* a do loop. */ + unsigned int prtSummary; + double *outpVector; /* pointer to our array of noise outputs */ + void *NplotPtr; /* the plot pointer */ + IFuid *namelist; /* list of plot names */ +} Ndata; + + +/* codes for saving and retrieving integrated noise data */ + +#define LNLSTDENS 0 /* array location that the log of the last noise density is stored */ +#define OUTNOIZ 1 /* array location that integrated output noise is stored */ +#define INNOIZ 2 /* array location that integrated input noise is stored */ + +#define NSTATVARS 3 /* number of "state" variables that must be stored for each noise */ + /* generator. in this case it is three: LNLSTDENS, OUTNOIZ */ + /* and INNOIZ */ + + +/* available step types: */ + +#define DECADE 1 +#define OCTAVE 2 +#define LINEAR 3 + + +/* noise analysis parameters */ + +#define N_OUTPUT 1 +#define N_OUTREF 2 +#define N_INPUT 3 +#define N_START 4 +#define N_STOP 5 +#define N_STEPS 6 +#define N_PTSPERSUM 7 +#define N_DEC 8 +#define N_OCT 9 +#define N_LIN 10 + + +/* noise routine operations/modes */ + +#define N_DENS 1 +#define INT_NOIZ 2 +#define N_OPEN 1 +#define N_CALC 2 +#define N_CLOSE 3 +#define SHOTNOISE 1 +#define THERMNOISE 2 +#define N_GAIN 3 + + +/* tolerances and limits to make numerical analysis more robust */ + +#define N_MINLOG 1E-38 /* the smallest number we can take the log of */ +#define N_MINGAIN 1E-20 /* the smallest input-output gain we can tolerate */ + /* (to calculate input-referred noise we divide */ + /* the output noise by the gain) */ +#define N_INTFTHRESH 1E-10 /* the largest slope (of a log-log noise spectral */ + /* density vs. freq plot) at which the noise */ + /* spectum is still considered flat. (no need for */ + /* log curve fitting) */ +#define N_INTUSELOG 1E-10 /* decides which expression to use for the integral of */ + /* x**k. If k is -1, then we must use a 'ln' form. */ + /* Otherwise, we use a 'power' form. This */ + /* parameter is the region around (k=) -1 for which */ + /* use the 'ln' form. */ + + +/* misc constants */ + +#define N_MXVLNTH 64 /* maximum length for noise output variables we will generate */ + /* (see MAXVLENGTH in FTE/writedata.c) */ + + + +extern int NsetParm(); +extern int NaskQuest(); +#endif /*NOISEDEFS*/ diff --git a/src/include/opdefs.h b/src/include/opdefs.h new file mode 100644 index 000000000..f4c868a1e --- /dev/null +++ b/src/include/opdefs.h @@ -0,0 +1,25 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef DCOP +#define DCOP + + +#include "jobdefs.h" +#include "tskdefs.h" + /* + * structures used to describe D.C. operationg point analyses to + * be performed. + */ + +typedef struct { + int JOBtype; + JOB *JOBnextJob; + char *JOBname; +} OP; + +extern int DCOsetParm(); +extern int DCOaskQuest(); +#endif /*DCOP*/ diff --git a/src/include/optdefs.h b/src/include/optdefs.h new file mode 100644 index 000000000..d31eb690a --- /dev/null +++ b/src/include/optdefs.h @@ -0,0 +1,107 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef OPT +#define OPT + + /* structure used to describe the statistics to be collected */ + +typedef struct { + + int STATnumIter; /* number of total iterations performed */ + int STATtranIter; /* number of iterations for transient analysis */ + int STAToldIter; /* number of iterations at the end of the last point */ + /* used to compute iterations per point */ + + int STATtimePts; /* total number of timepoints */ + int STATaccepted; /* number of timepoints accepted */ + int STATrejected; /* number of timepoints rejected */ + + double STATtotAnalTime; /* total time for all analysis */ + double STATloadTime; /* total time spent in device loading */ + double STATdecompTime; /* total time spent in LU decomposition */ + double STATsolveTime; /* total time spent in F-B subst. */ + double STATreorderTime; /* total time spent reordering */ + double STATcombineTime; /* total time spent combining */ + double STATsyncTime; /* total time spent sync'ing after load */ + double STATtranTime; /* transient analysis time */ + double STATtranDecompTime; /* time spent in transient LU decomposition */ + double STATtranSolveTime; /* time spent in transient F-B subst. */ + double STATtranLoadTime; /* time spent in transient device loading */ + double STATtranTruncTime; /* time spent calculating LTE and new step */ + double STATtranCombTime; /* time spent in transient combining */ + double STATtranSyncTime; /* time spent in transient sync'ing */ + double STATacTime; /* AC analysis time */ + double STATacDecompTime; /* time spent in AC LU decomposition */ + double STATacSolveTime; /* time spent in AC F-B subst. */ + double STATacLoadTime; /* time spent in AC device loading */ + double STATacCombTime; /* time spent in AC combining */ + double STATacSyncTime; /* time spent in transient sync'ing */ + +} STATistics; + +#define OPT_GMIN 1 +#define OPT_RELTOL 2 +#define OPT_ABSTOL 3 +#define OPT_VNTOL 4 +#define OPT_TRTOL 5 +#define OPT_CHGTOL 6 +#define OPT_PIVTOL 7 +#define OPT_PIVREL 8 +#define OPT_TNOM 9 +#define OPT_ITL1 10 +#define OPT_ITL2 11 +#define OPT_ITL3 12 +#define OPT_ITL4 13 +#define OPT_ITL5 14 +#define OPT_DEFL 15 +#define OPT_DEFW 16 +#define OPT_DEFAD 17 +#define OPT_DEFAS 18 +#define OPT_BYPASS 19 +#define OPT_MAXORD 20 + +#define OPT_ITERS 21 +#define OPT_TRANIT 22 +#define OPT_TRANPTS 23 +#define OPT_TRANACCPT 24 +#define OPT_TRANRJCT 25 +#define OPT_TOTANALTIME 26 +#define OPT_TRANTIME 27 +#define OPT_LOADTIME 28 +#define OPT_DECOMP 29 +#define OPT_SOLVE 30 +#define OPT_TRANDECOMP 31 +#define OPT_TRANSOLVE 32 +#define OPT_TEMP 33 +#define OPT_OLDLIMIT 34 +#define OPT_TRANCURITER 35 +#define OPT_SRCSTEPS 36 +#define OPT_GMINSTEPS 37 +#define OPT_MINBREAK 38 +#define OPT_NOOPITER 39 +#define OPT_EQNS 40 +#define OPT_REORDTIME 41 +#define OPT_METHOD 42 +#define OPT_TRYTOCOMPACT 43 +#define OPT_BADMOS3 44 +#define OPT_KEEPOPINFO 45 +#define OPT_TRANLOAD 46 +#define OPT_TRANTRUNC 47 +#define OPT_ACTIME 48 +#define OPT_ACLOAD 49 +#define OPT_ACDECOMP 50 +#define OPT_ACSOLVE 51 +#define OPT_ORIGNZ 52 +#define OPT_FILLNZ 53 +#define OPT_TOTALNZ 54 +#define OPT_COMBTIME 55 +#define OPT_TRANCOMB 56 +#define OPT_ACCOMB 57 +#define OPT_SYNCTIME 58 +#define OPT_TRANSYNC 59 +#define OPT_ACSYNC 60 + +#endif /*OPT*/ diff --git a/src/include/pzdefs.h b/src/include/pzdefs.h new file mode 100644 index 000000000..a73cd101d --- /dev/null +++ b/src/include/pzdefs.h @@ -0,0 +1,55 @@ +#ifndef PZDEFS +#define PZDEFS "PZdefs.h $Revision$ on $Date$ " + + /* structure used to describe an PZ analysis to be performed */ + +#include "jobdefs.h" +#include "complex.h" + +typedef struct strial { + SPcomplex s, f_raw, f_def; + struct strial *next, *prev; + int mag_raw, mag_def; + int multiplicity; + int flags; + int seq_num; + int count; +} PZtrial; + +typedef struct { + int JOBtype; + JOB *JOBnextJob; + IFuid JOBname; + int PZin_pos; + int PZin_neg; + int PZout_pos; + int PZout_neg; + int PZinput_type; + int PZwhich; + int PZnumswaps; + int PZbalance_col; + int PZsolution_col; + PZtrial *PZpoleList; + PZtrial *PZzeroList; + int PZnPoles; + int PZnZeros; + double *PZdrive_pptr; + double *PZdrive_nptr; +} PZAN; + +#define PZ_DO_POLES 0x1 +#define PZ_DO_ZEROS 0x2 +#define PZ_IN_VOL 1 +#define PZ_IN_CUR 2 + +#define PZ_NODEI 1 +#define PZ_NODEG 2 +#define PZ_NODEJ 3 +#define PZ_NODEK 4 +#define PZ_V 5 +#define PZ_I 6 +#define PZ_POL 7 +#define PZ_ZER 8 +#define PZ_PZ 9 + +#endif /*PZDEFS*/ diff --git a/src/include/sen2defs.h b/src/include/sen2defs.h new file mode 100644 index 000000000..8cf755ac5 --- /dev/null +++ b/src/include/sen2defs.h @@ -0,0 +1,69 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +/* + * SENdefs.h - structures for sensitivity package + */ + +#ifndef SENSTRUCTS +#define SENSTRUCTS + + +#include "smpdefs.h" +#include "jobdefs.h" + +typedef struct { + int JOBtype; + JOB *JOBnextJob; /* pointer to next thing to do */ + char *JOBname; /* name of this job */ + + int SENnumVal; /* length of the next two arrays */ + char **SENdevices; /* names of the devices to do sensetivity analysis of */ + char **SENparmNames;/* parameters of the above devices to do analysis wrt */ + + unsigned int SENinitflag :1 ; /* indicates whether sensitivity structure*/ + /* is to be initialized */ + unsigned int SENicflag :1 ; /* indicates whether initial conditions + are specified for transient analysis */ + + unsigned int SENstatus :1; /* indicates whether perturbation + is in progress*/ + unsigned int SENacpertflag :1; /* indictes whether the perturbation + is to be carried out in ac analysis + (is done only for first frequency )*/ + int SENmode; /* indicates the type of sensitivity analysis + reqired: DC, Transient, or AC */ + int SENparms; /* # of design parameters */ + double SENpertfac; /* perturbation factor (for active + devices )*/ + double **SEN_Sap; /* sensitivity matrix (DC and transient )*/ + double **SEN_RHS; /* RHS matrix (real part) + contains the sensitivity values after SMPsolve*/ + double **SEN_iRHS; /* RHS matrix (imag part ) + contains the sensitivity values after SMPsolve*/ + int SENsize; /* stores the number of rows of each of the above + three matrices */ + SMPmatrix *SEN_Jacmat; /* sensitivity Jacobian matrix, */ + double *SEN_parmVal; /* table containing values of design parameters */ + char **SEN_parmName; /* table containing names of design parameters */ + +} SENstruct; + +/* SENmode */ +#define DCSEN 0x1 +#define TRANSEN 0x2 +#define ACSEN 0x4 + +#define NORMAL 0 +#define PERTURBATION 1 +#define OFF 0 +#define ON 1 + + +#define SEN_AC 1 +#define SEN_DC 2 +#define SEN_TRAN 3 +#define SEN_DEV 4 +#define SEN_PARM 5 + +#endif /* SENSTRUCTS */ diff --git a/src/include/sensdefs.h b/src/include/sensdefs.h new file mode 100644 index 000000000..3bf453513 --- /dev/null +++ b/src/include/sensdefs.h @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#ifndef SENS_DEFS +#define SENS_DEFS + +#include "jobdefs.h" + + /* structure used to describe an Adjoint Sensitivity analysis */ + +typedef struct st_sens SENS_AN; +typedef struct st_devsen DevSenList; +typedef struct st_modsen ModSenList; +typedef struct st_devsen ParamSenList; +typedef struct st_nodes Nodes; +typedef struct st_output output; + +struct st_sens { + int JOBtype; + JOB *JOBnextJob; /* pointer to next thing to do */ + char *JOBname; /* name of this job */ + + DevSenList *first; + double start_freq; + double stop_freq; + + int step_type; + int n_freq_steps; + + CKTnode *output_pos, *output_neg; + IFuid output_src; + char *output_name; + int output_volt; + + double deftol; + double defperturb; + unsigned int pct_flag :1; + +}; + +struct st_output { + int type; + int pos, neg; +}; + +struct st_nodes { + int pos, neg; +}; + +struct st_paramsenlist { + ParamSenList *next; + int param_no; + double delta, tol; +}; + +struct st_modsenlist { + ModSenList *next; + int mod_no; + ParamSenList *first; +}; + +struct st_devsenlist { + DevSenList *next; + int dev_no; + ModSenList *first; +}; + +extern int SENSask( ); +extern int SENSsetParam( ); +extern int sens_sens( ); + +#define SENS_POS 2 +#define SENS_NEG 3 +#define SENS_SRC 4 +#define SENS_NAME 5 + +#define SENS_START 10 +#define SENS_STOP 11 +#define SENS_STEPS 12 + +#define SENS_DEC 13 +#define SENS_OCT 14 +#define SENS_LIN 15 + +#define SENS_DECADE 13 +#define SENS_OCTAVE 14 +#define SENS_LINEAR 15 + +#define SENS_DC 16 +#define SENS_DEFTOL 17 +#define SENS_DEFPERT 18 +#define SENS_DEFPERTURB 18 +#define SENS_DEVDEFTOL 19 +#define SENS_DEVDEFPERT 20 +#define SENS_TYPE 21 +#define SENS_DEVICE 22 +#define SENS_PARAM 24 +#define SENS_TOL 25 +#define SENS_PERT 26 + +#endif /*DEFS*/ + diff --git a/src/include/sensgen.h b/src/include/sensgen.h new file mode 100644 index 000000000..60aaa76cd --- /dev/null +++ b/src/include/sensgen.h @@ -0,0 +1,20 @@ +typedef struct s_sgen sgen; +struct s_sgen { + CKTcircuit *ckt; + GENmodel **devlist; + GENmodel *model, *next_model, *first_model; + GENinstance *instance, *next_instance, *first_instance; + IFparm *ptable; + double value; + int dev; + int istate; + int param, max_param; + int is_dc; + int is_instparam; + int is_q; + int is_principle; + int is_zerook; +}; + +extern sgen *sgen_init( ); +extern int sgen_next( ); diff --git a/src/include/smpdefs.h b/src/include/smpdefs.h new file mode 100644 index 000000000..bb3b6e8f5 --- /dev/null +++ b/src/include/smpdefs.h @@ -0,0 +1,63 @@ +#ifndef SMP +#define SMP + +typedef char SMPmatrix; +typedef struct MatrixElement *SMPelement; + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "complex.h" +#include + +#ifdef __STDC__ +int SMPaddElt( SMPmatrix *, int , int , double ); +void SMPcClear( SMPmatrix *); +int SMPcLUfac( SMPmatrix *, double ); +int SMPcProdDiag( SMPmatrix *, SPcomplex *, int *); +int SMPcReorder( SMPmatrix * , double , double , int *); +void SMPcSolve( SMPmatrix *, double [], double [], double [], double []); +void SMPclear( SMPmatrix *); +void SMPcolSwap( SMPmatrix * , int , int ); +void SMPdestroy( SMPmatrix *); +int SMPfillup( SMPmatrix * ); +SMPelement * SMPfindElt( SMPmatrix *, int , int , int ); +void SMPgetError( SMPmatrix *, int *, int *); +int SMPluFac( SMPmatrix *, double , double ); +double * SMPmakeElt( SMPmatrix * , int , int ); +int SMPmatSize( SMPmatrix *); +int SMPnewMatrix( SMPmatrix ** ); +int SMPnewNode( int , SMPmatrix *); +int SMPpreOrder( SMPmatrix *); +void SMPprint( SMPmatrix * , FILE *); +int SMPreorder( SMPmatrix * , double , double , double ); +void SMProwSwap( SMPmatrix * , int , int ); +void SMPsolve( SMPmatrix *, double [], double []); +#else /* stdc */ +int SMPaddElt(); +void SMPcClear(); +int SMPcLUfac(); +int SMPcProdDiag(); +int SMPcReorder(); +void SMPcSolve(); +void SMPclear(); +void SMPcolSwap(); +void SMPdestroy(); +int SMPfillup(); +SMPelement * SMPfindElt(); +void SMPgetError(); +int SMPluFac(); +double * SMPmakeElt(); +int SMPmatSize(); +int SMPnewMatrix(); +int SMPnewNode(); +int SMPpreOrder(); +void SMPprint(); +int SMPreorder(); +void SMProwSwap(); +void SMPsolve(); +#endif /* stdc */ + +#endif /*SMP*/ diff --git a/src/include/spconfig.h b/src/include/spconfig.h new file mode 100644 index 000000000..17ecf3dea --- /dev/null +++ b/src/include/spconfig.h @@ -0,0 +1,460 @@ +/* + * CONFIGURATION MACRO DEFINITIONS for sparse matrix routines + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * U.C. Berkeley + * + * This file contains macros for the sparse matrix routines that are used + * to define the personality of the routines. The user is expected to + * modify this file to maximize the performance of the routines with + * his/her matrices. + * + * Macros are distinguished by using solely capital letters in their + * identifiers. This contrasts with C defined identifiers which are + * strictly lower case, and program variable and procedure names which use + * both upper and lower case. + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + * + * $Date$ + * $Revision$ + */ + + +#ifndef spCONFIG_DEFS +#define spCONFIG_DEFS + + + + +#ifdef spINSIDE_SPARSE +/* + * OPTIONS + * + * These are compiler options. Set each option to one to compile that + * section of the code. If a feature is not desired, set the macro + * to NO. Recommendations are given in brackets, [ignore them]. + * + * >>> Option descriptions: + * Arithmetic Precision + * The precision of the arithmetic used by Sparse can be set by + * changing changing the spREAL macro. This macro is + * contained in the file spMatrix.h. It is strongly suggested to + * used double precision with circuit simulators. Note that + * because C always performs arithmetic operations in double + * precision, the only benefit to using single precision is that + * less storage is required. There is often a noticeable speed + * penalty when using single precision. Sparse internally refers + * to a spREAL as a RealNumber. + * REAL + * This specifies that the routines are expected to handle real + * systems of equations. The routines can be compiled to handle + * both real and complex systems at the same time, but there is a + * slight speed and memory advantage if the routines are complied + * to handle only real systems of equations. + * spCOMPLEX + * This specifies that the routines will be complied to handle + * complex systems of equations. + * EXPANDABLE + * Setting this compiler flag true (1) makes the matrix + * expandable before it has been factored. If the matrix is + * expandable, then if an element is added that would be + * considered out of bounds in the current matrix, the size of + * the matrix is increased to hold that element. As a result, + * the size of the matrix need not be known before the matrix is + * built. The matrix can be allocated with size zero and + * expanded. + * TRANSLATE + * This option allows the set of external row and column numbers + * to be non-packed. In other words, the row and column numbers + * do not have to be contiguous. The priced paid for this + * flexibility is that when TRANSLATE is set true, the time + * required to initially build the matrix will be greater because + * the external row and column number must be translated into + * internal equivalents. This translation brings about other + * benefits though. First, the spGetElement() and + * spGetAdmittance() routines may be used after the matrix has + * been factored. Further, elements, and even rows and columns, + * may be added to the matrix, and row and columns may be deleted + * from the matrix, after it has been factored. Note that when + * the set of row and column number is not a packed set, neither + * are the RHS and Solution vectors. Thus the size of these + * vectors must be at least as large as the external size, which + * is the value of the largest given row or column numbers. + * INITIALIZE + * Causes the spInitialize(), spGetInitInfo(), and + * spInstallInitInfo() routines to be compiled. These routines + * allow the user to store and read one pointer in each nonzero + * element in the matrix. spInitialize() then calls a user + * specified function for each structural nonzero in the matrix, + * and includes this pointer as well as the external row and + * column numbers as arguments. This allows the user to write + * custom matrix initialization routines. + * DIAGONAL_PIVOTING + * Many matrices, and in particular node- and modified-node + * admittance matrices, tend to be nearly symmetric and nearly + * diagonally dominant. For these matrices, it is a good idea to + * select pivots from the diagonal. With this option enabled, + * this is exactly what happens, though if no satisfactory pivot + * can be found on the diagonal, an off-diagonal pivot will be + * used. If this option is disabled, Sparse does not + * preferentially search the diagonal. Because of this, Sparse + * has a wider variety of pivot candidates available, and so + * presumably fewer fill-ins will be created. However, the + * initial pivot selection process will take considerably longer. + * If working with node admittance matrices, or other matrices + * with a strong diagonal, it is probably best to use + * DIAGONAL_PIVOTING for two reasons. First, accuracy will be + * better because pivots will be chosen from the large diagonal + * elements, thus reducing the chance of growth. Second, a near + * optimal ordering will be chosen quickly. If the class of + * matrices you are working with does not have a strong diagonal, + * do not use DIAGONAL_PIVOTING, but consider using a larger + * threshold. When DIAGONAL_PIVOTING is turned off, the following + * options and constants are not used: MODIFIED_MARKOWITZ, + * MAX_MARKOWITZ_TIES, and TIES_MULTIPLIER. + * ARRAY_OFFSET + * This determines whether arrays start at an index of zero or one. + * This option is necessitated by the fact that standard C + * convention dictates that arrays begin with an index of zero but + * the standard mathematic convention states that arrays begin with + * an index of one. So if you prefer to start your arrays with + * zero, or your calling Sparse from FORTRAN, set ARRAY_OFFSET to + * NO or 0. Otherwise, set ARRAY_OFFSET to YES or 1. Note that if + * you use an offset of one, the arrays that you pass to Sparse + * must have an allocated length of one plus the size of the + * matrix. ARRAY_OFFSET must be either 0 or 1, no other offsets + * are valid. + * spSEPARATED_COMPLEX_VECTORS + * This specifies the format for complex vectors. If this is set + * false then a complex vector is made up of one double sized + * array of RealNumber's in which the real and imaginary numbers + * are placed in the alternately array in the array. In other + * words, the first entry would be Complex[1].Real, then comes + * Complex[1].Imag, then Complex[1].Real, etc. If + * spSEPARATED_COMPLEX_VECTORS is set true, then each complex + * vector is represented by two arrays of RealNumbers, one with + * the real terms, the other with the imaginary. [NO] + * MODIFIED_MARKOWITZ + * This specifies that the modified Markowitz method of pivot + * selection is to be used. The modified Markowitz method differs + * from standard Markowitz in two ways. First, under modified + * Markowitz, the search for a pivot can be terminated early if a + * adequate (in terms of sparsity) pivot candidate is found. + * Thus, when using modified Markowitz, the initial factorization + * can be faster, but at the expense of a suboptimal pivoting + * order that may slow subsequent factorizations. The second + * difference is in the way modified Markowitz breaks Markowitz + * ties. When two or more elements are pivot candidates and they + * all have the same Markowitz product, then the tie is broken by + * choosing the element that is best numerically. The numerically + * best element is the one with the largest ratio of its magnitude + * to the magnitude of the largest element in the same column, + * excluding itself. The modified Markowitz method results in + * marginally better accuracy. This option is most appropriate + * for use when working with very large matrices where the initial + * factor time represents an unacceptable burden. [NO] + * DELETE + * This specifies that the spDeleteRowAndCol() routine + * should be compiled. Note that for this routine to be + * compiled, both DELETE and TRANSLATE should be set true. + * STRIP + * This specifies that the spStripFills() routine should be compiled. + * MODIFIED_NODAL + * This specifies that the routine that preorders modified node + * admittance matrices should be compiled. This routine results + * in greater speed and accuracy if used with this type of + * matrix. + * QUAD_ELEMENT + * This specifies that the routines that allow four related + * elements to be entered into the matrix at once should be + * compiled. These elements are usually related to an + * admittance. The routines affected by QUAD_ELEMENT are the + * spGetAdmittance, spGetQuad and spGetOnes routines. + * TRANSPOSE + * This specifies that the routines that solve the matrix as if + * it was transposed should be compiled. These routines are + * useful when performing sensitivity analysis using the adjoint + * method. + * SCALING + * This specifies that the routine that performs scaling on the + * matrix should be complied. Scaling is not strongly + * supported. The routine to scale the matrix is provided, but + * no routines are provided to scale and descale the RHS and + * Solution vectors. It is suggested that if scaling is desired, + * it only be preformed when the pivot order is being chosen [in + * spOrderAndFactor()]. This is the only time scaling has + * an effect. The scaling may then either be removed from the + * solution by the user or the scaled factors may simply be + * thrown away. [NO] + * DOCUMENTATION + * This specifies that routines that are used to document the + * matrix, such as spPrint() and spFileMatrix(), should be + * compiled. + * DETERMINANT + * This specifies that the routine spDeterminant() should be complied. + * STABILITY + * This specifies that spLargestElement() and spRoundoff() should + * be compiled. These routines are used to check the stability (and + * hence the quality of the pivoting) of the factorization by + * computing a bound on the size of the element is the matrix E = + * A - LU. If this bound is very high after applying + * spOrderAndFactor(), then the pivot threshold should be raised. + * If the bound increases greatly after using spFactor(), then the + * matrix should probably be reordered. + * CONDITION + * This specifies that spCondition() and spNorm(), the code that + * computes a good estimate of the condition number of the matrix, + * should be compiled. + * PSEUDOCONDITION + * This specifies that spPseudoCondition(), the code that computes + * a crude and easily fooled indicator of ill-conditioning in the + * matrix, should be compiled. + * MULTIPLICATION + * This specifies that the routines to multiply the unfactored + * matrix by a vector should be compiled. + * FORTRAN + * This specifies that the FORTRAN interface routines should be + * compiled. When interfacing to FORTRAN programs, the ARRAY_OFFSET + * options should be set to NO. + * DEBUG + * This specifies that additional error checking will be compiled. + * The type of error checked are those that are common when the + * matrix routines are first integrated into a user's program. Once + * the routines have been integrated in and are running smoothly, this + * option should be turned off. + * spCOMPATIBILITY + * This specifies that Sparse1.3 should be configured to be upward + * compatible from Sparse1.2. This option is not suggested for use + * in new software. Sparse1.3, when configured to be compatible with + * Sparse1.2, is not completely compatible. In particular, if + * recompiling the calling program, it is necessary to change the + * of the Sparse include files. This option will go away in future + * versions of Sparse. [0] + */ + +/* Begin options. */ +#define REAL YES +#define EXPANDABLE YES +#define TRANSLATE YES +#define INITIALIZE NO +#define DIAGONAL_PIVOTING YES +#define ARRAY_OFFSET YES +#define MODIFIED_MARKOWITZ NO +#define DELETE NO +#define STRIP NO +#define MODIFIED_NODAL YES +#define QUAD_ELEMENT NO +#define TRANSPOSE YES +#define SCALING NO +#define DOCUMENTATION YES +#define MULTIPLICATION YES +#define DETERMINANT YES +#define DETERMINANT2 YES +#define STABILITY NO +#define CONDITION NO +#define PSEUDOCONDITION NO +#define FORTRAN NO +#ifdef HAS_MINDATA +# define DEBUG NO +#else +# define DEBUG YES +#endif + +/* + * The following options affect Sparse exports and so are exported as a + * side effect. For this reason they use the `sp' prefix. The boolean + * constants YES an NO are not defined in spMatrix.h to avoid conflicts + * with user code, so use 0 for NO and 1 for YES. + */ +#endif /* spINSIDE_SPARSE */ +#define spCOMPLEX 1 +#define spSEPARATED_COMPLEX_VECTORS 1 +#define spCOMPATIBILITY 0 +#ifdef spINSIDE_SPARSE + + + + + + + +/* + * MATRIX CONSTANTS + * + * These constants are used throughout the sparse matrix routines. They + * should be set to suit the type of matrix being solved. Recommendations + * are given in brackets. + * + * Some terminology should be defined. The Markowitz row count is the number + * of non-zero elements in a row excluding the one being considered as pivot. + * There is one Markowitz row count for every row. The Markowitz column + * is defined similarly for columns. The Markowitz product for an element + * is the product of its row and column counts. It is a measure of how much + * work would be required on the next step of the factorization if that + * element were chosen to be pivot. A small Markowitz product is desirable. + * + * >>> Constants descriptions: + * DEFAULT_THRESHOLD + * The relative threshold used if the user enters an invalid + * threshold. Also the threshold used by spFactor() when + * calling spOrderAndFactor(). The default threshold should + * not be less than or equal to zero nor larger than one. [0.001] + * DIAG_PIVOTING_AS_DEFAULT + * This indicates whether spOrderAndFactor() should use diagonal + * pivoting as default. This issue only arises when + * spOrderAndFactor() is called from spFactor(). + * SPACE_FOR_ELEMENTS + * This number multiplied by the size of the matrix equals the number + * of elements for which memory is initially allocated in + * spCreate(). [6] + * SPACE_FOR_FILL_INS + * This number multiplied by the size of the matrix equals the number + * of elements for which memory is initially allocated and specifically + * reserved for fill-ins in spCreate(). [4] + * ELEMENTS_PER_ALLOCATION + * The number of matrix elements requested from the malloc utility on + * each call to it. Setting this value greater than 1 reduces the + * amount of overhead spent in this system call. On a virtual memory + * machine, its good to allocate slightly less than a page worth of + * elements at a time (or some multiple thereof). + * [For the VAX, for real only use 41, otherwise use 31] + * MINIMUM_ALLOCATED_SIZE + * The minimum allocated size of a matrix. Note that this does not + * limit the minimum size of a matrix. This just prevents having to + * resize a matrix many times if the matrix is expandable, large and + * allocated with an estimated size of zero. This number should not + * be less than one. + * EXPANSION_FACTOR + * The amount the allocated size of the matrix is increased when it + * is expanded. + * MAX_MARKOWITZ_TIES + * This number is used for two slightly different things, both of which + * relate to the search for the best pivot. First, it is the maximum + * number of elements that are Markowitz tied that will be sifted + * through when trying to find the one that is numerically the best. + * Second, it creates an upper bound on how large a Markowitz product + * can be before it eliminates the possibility of early termination + * of the pivot search. In other words, if the product of the smallest + * Markowitz product yet found and TIES_MULTIPLIER is greater than + * MAX_MARKOWITZ_TIES, then no early termination takes place. + * Set MAX_MARKOWITZ_TIES to some small value if no early termination of + * the pivot search is desired. An array of RealNumbers is allocated + * of size MAX_MARKOWITZ_TIES so it must be positive and shouldn't + * be too large. Active when MODIFIED_MARKOWITZ is 1 (true). [100] + * TIES_MULTIPLIER + * Specifies the number of Markowitz ties that are allowed to occur + * before the search for the pivot is terminated early. Set to some + * large value if no early termination of the pivot search is desired. + * This number is multiplied times the Markowitz product to determine + * how many ties are required for early termination. This means that + * more elements will be searched before early termination if a large + * number of fill-ins could be created by accepting what is currently + * considered the best choice for the pivot. Active when + * MODIFIED_MARKOWITZ is 1 (true). Setting this number to zero + * effectively eliminates all pivoting, which should be avoided. + * This number must be positive. TIES_MULTIPLIER is also used when + * diagonal pivoting breaks down. [5] + * DEFAULT_PARTITION + * Which partition mode is used by spPartition() as default. + * Possibilities include + * spDIRECT_PARTITION -- each row used direct addressing, best for + * a few relatively dense matrices. + * spINDIRECT_PARTITION -- each row used indirect addressing, best + * for a few very sparse matrices. + * spAUTO_PARTITION -- direct or indirect addressing is chosen on + * a row-by-row basis, carries a large overhead, but speeds up + * both dense and sparse matrices, best if there is a large + * number of matrices that can use the same ordering. + */ + +/* Begin constants. */ +#define DEFAULT_THRESHOLD 1.0e-3 +#define DIAG_PIVOTING_AS_DEFAULT YES +#define SPACE_FOR_ELEMENTS 6 +#define SPACE_FOR_FILL_INS 4 +#define ELEMENTS_PER_ALLOCATION 31 +#define MINIMUM_ALLOCATED_SIZE 6 +#define EXPANSION_FACTOR 1.5 +#define MAX_MARKOWITZ_TIES 100 +#define TIES_MULTIPLIER 5 +#define DEFAULT_PARTITION spAUTO_PARTITION + + + + + + +/* + * PRINTER WIDTH + * + * This macro characterize the printer for the spPrint() routine. + * + * >>> Macros: + * PRINTER_WIDTH + * The number of characters per page width. Set to 80 for terminal, + * 132 for line printer. + */ + +/* Begin printer constants. */ +#define PRINTER_WIDTH 80 + + + + + + +/* + * MACHINE CONSTANTS + * + * These numbers must be updated when the program is ported to a new machine. + */ + +/* Begin machine constants. */ + +/* + * Grab from Spice include files + */ + +#include "ngspice.h" +#define MACHINE_RESOLUTION DBL_EPSILON +#define LARGEST_REAL DBL_MAX +#define SMALLEST_REAL DBL_MIN +#define LARGEST_SHORT_INTEGER SHRT_MAX +#define LARGEST_LONG_INTEGER LONG_MAX + + +/* + * ANNOTATION + * + * This macro changes the amount of annotation produced by the matrix + * routines. The annotation is used as a debugging aid. Change the number + * associated with ANNOTATE to change the amount of annotation produced by + * the program. + */ + +/* Begin annotation definitions. */ +#define ANNOTATE NONE + +#define NONE 0 +#define ON_STRANGE_BEHAVIOR 1 +#define FULL 2 + +#endif /* spINSIDE_SPARSE */ +#endif /* spCONFIG_DEFS */ diff --git a/src/include/sperror.h b/src/include/sperror.h new file mode 100644 index 000000000..2c9fe3486 --- /dev/null +++ b/src/include/sperror.h @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef ERRORS +#define ERRORS + +#include "ngspice.h" +#include "iferrmsg.h" + + /* + * definitions for error codes returned by SPICE3 routines. + */ + +#define E_INTERN E_PANIC +#define E_BADMATRIX (E_PRIVATE+1)/* ill-formed matrix can't be decomposed */ +#define E_SINGULAR (E_PRIVATE+2) /* matrix is singular */ +#define E_ITERLIM (E_PRIVATE+3) /* iteration limit reached,operation aborted */ +#define E_ORDER (E_PRIVATE+4) /* integration order not supported */ +#define E_METHOD (E_PRIVATE+5) /* integration method not supported */ +#define E_TIMESTEP (E_PRIVATE+6) /* timestep too small */ +#define E_XMISSIONLINE (E_PRIVATE+7) /* transmission line in pz analysis */ +#define E_MAGEXCEEDED (E_PRIVATE+8) /* pole-zero magnitude too large */ +#define E_SHORT (E_PRIVATE+9) /* pole-zero input or output shorted */ +#define E_INISOUT (E_PRIVATE+10) /* pole-zero input is output */ +#define E_ASKCURRENT (E_PRIVATE+11) /* ac currents cannot be ASKed */ +#define E_ASKPOWER (E_PRIVATE+12) /* ac powers cannot be ASKed */ +#define E_NODUNDEF (E_PRIVATE+13) /* node not defined in noise anal */ +#define E_NOACINPUT (E_PRIVATE+14) /* no ac input src specified for noise */ +#define E_NOF2SRC (E_PRIVATE+15) /* no source at F2 for IM disto analysis */ +#define E_NODISTO (E_PRIVATE+16) /* no distortion analysis - NODISTO defined */ +#define E_NONOISE (E_PRIVATE+17) /* no noise analysis - NONOISE defined */ +#ifdef PARALLEL_ARCH +#define E_MULTIERR (E_PRIVATE+18) /* multiple errors from diff. processes */ +#endif /* PARALLEL_ARCH */ + +char *SPerror(); +#endif diff --git a/src/include/spmatrix.h b/src/include/spmatrix.h new file mode 100644 index 000000000..83afafc15 --- /dev/null +++ b/src/include/spmatrix.h @@ -0,0 +1,441 @@ +/* + * EXPORTS for sparse matrix routines with SPICE3. + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains definitions that are useful to the calling + * program. In particular, this file contains error keyword + * definitions, some macro functions that are used to quickly enter + * data into the matrix and the type definition of a data structure + * that acts as a template for entering admittances into the matrix. + * Also included is the type definitions for the various functions + * available to the user. + * + * This file is a modified version of spMatrix.h that is used when + * interfacing to Spice3. + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + * + * $Date$ + * $Revision$ + */ + + + + +#ifndef spOKAY + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + */ + +#include "spconfig.h" + + + + + + +/* + * ERROR KEYWORDS + * + * The actual numbers used in the error codes are not sacred, they can be + * changed under the condition that the codes for the nonfatal errors are + * less than the code for spFATAL and similarly the codes for the fatal + * errors are greater than that for spFATAL. + * + * >>> Error descriptions: + * spOKAY + * No error has occurred. + * spSMALL_PIVOT + * When reordering the matrix, no element was found which satisfies the + * threshold criteria. The largest element in the matrix was chosen + * as pivot. Non-fatal. + * spZERO_DIAG + * Fatal error. A zero was encountered on the diagonal the matrix. This + * does not necessarily imply that the matrix is singular. When this + * error occurs, the matrix should be reconstructed and factored using + * spOrderAndFactor(). In spCOMPATIBILITY mode, spZERO_DIAG is + * indistinguishable from spSINGULAR. + * spSINGULAR + * Fatal error. Matrix is singular, so no unique solution exists. + * spNO_MEMORY + * Fatal error. Indicates that not enough memory is available to handle + * the matrix. + * spPANIC + * Fatal error indicating that the routines are not prepared to + * handle the matrix that has been requested. This may occur when + * the matrix is specified to be real and the routines are not + * compiled for real matrices, or when the matrix is specified to + * be complex and the routines are not compiled to handle complex + * matrices. + * spFATAL + * Not an error flag, but rather the dividing line between fatal errors + * and warnings. + */ + +#include "sperror.h" /* Spice error definitions. */ + +/* Begin error macros. */ +#define spOKAY OK +#define spSMALL_PIVOT OK +#define spZERO_DIAG E_SINGULAR +#define spSINGULAR E_SINGULAR +#define spNO_MEMORY E_NOMEM +#define spPANIC E_BADMATRIX + +#define spFATAL E_BADMATRIX + + +#if spCOMPATIBILITY +#define NO_ERROR spOKAY +#define UNDER_FLOW spOKAY +#define OVER_FLOW spOKAY +#define ILL_CONDITIONED spSMALL_PIVOT +#define SINGULAR spSINGULAR +#define NO_MEMORY spNO_MEMORY +#define RANGE spPANIC + +#define FATAL spFATAL + +#undef spZERO_DIAG +#define spZERO_DIAG spSINGULAR +#endif /* spCOMPATIBILITY */ + + + + + +/* + * KEYWORD DEFINITIONS + * + * Here we define what precision arithmetic Sparse will use. Double + * precision is suggested as being most appropriate for circuit + * simulation and for C. However, it is possible to change spREAL + * to a float for single precision arithmetic. Note that in C, single + * precision arithmetic is often slower than double precision. Sparse + * internally refers to spREALs as RealNumbers. + * + * Some C compilers, notably the old VMS compiler, do not handle the keyword + * "void" correctly. If this is true for your compiler, remove the + * comment delimiters from the redefinition of void to int below. + */ + +#define spREAL double +/* #define void int */ + +#if spCOMPATIBILITY +#define SPARSE_REAL spREAL +#endif + + + +/* + * PARTITION TYPES + * + * When factoring a previously ordered matrix using spFactor(), Sparse + * operates on a row-at-a-time basis. For speed, on each step, the row + * being updated is copied into a full vector and the operations are + * performed on that vector. This can be done one of two ways, either + * using direct addressing or indirect addressing. Direct addressing + * is fastest when the matrix is relatively dense and indirect addressing + * is quite sparse. The user can select which partitioning mode is used. + * The following keywords are passed to spPartition() and indicate that + * Sparse should use only direct addressing, only indirect addressing, or + * that it should choose the best mode on a row-by-row basis. The time + * required to choose a partition is of the same order of the cost to factor + * the matrix. + * + * If you plan to factor a large number of matrices with the same structure, + * it is best to let Sparse choose the partition. Otherwise, you should + * choose the partition based on the predicted density of the matrix. + */ + +/* Begin partition keywords. */ + +#define spDEFAULT_PARTITION 0 +#define spDIRECT_PARTITION 1 +#define spINDIRECT_PARTITION 2 +#define spAUTO_PARTITION 3 + + + + + +/* + * MACRO FUNCTION DEFINITIONS + * + * >>> Macro descriptions: + * spADD_REAL_ELEMENT + * Macro function that adds data to a real element in the matrix by a + * pointer. + * spADD_IMAG_ELEMENT + * Macro function that adds data to a imaginary element in the matrix by + * a pointer. + * spADD_COMPLEX_ELEMENT + * Macro function that adds data to a complex element in the matrix by a + * pointer. + * spADD_REAL_QUAD + * Macro function that adds data to each of the four real matrix elements + * specified by the given template. + * spADD_IMAG_QUAD + * Macro function that adds data to each of the four imaginary matrix + * elements specified by the given template. + * spADD_COMPLEX_QUAD + * Macro function that adds data to each of the four complex matrix + * elements specified by the given template. + */ + +/* Begin Macros. */ +#define spADD_REAL_ELEMENT(element,real) *(element) += real + +#define spADD_IMAG_ELEMENT(element,imag) *(element+1) += imag + +#define spADD_COMPLEX_ELEMENT(element,real,imag) \ +{ *(element) += real; \ + *(element+1) += imag; \ +} + +#define spADD_REAL_QUAD(template,real) \ +{ *((template).Element1) += real; \ + *((template).Element2) += real; \ + *((template).Element3Negated) -= real; \ + *((template).Element4Negated) -= real; \ +} + +#define spADD_IMAG_QUAD(template,imag) \ +{ *((template).Element1+1) += imag; \ + *((template).Element2+1) += imag; \ + *((template).Element3Negated+1) -= imag; \ + *((template).Element4Negated+1) -= imag; \ +} + +#define spADD_COMPLEX_QUAD(template,real,imag) \ +{ *((template).Element1) += real; \ + *((template).Element2) += real; \ + *((template).Element3Negated) -= real; \ + *((template).Element4Negated) -= real; \ + *((template).Element1+1) += imag; \ + *((template).Element2+1) += imag; \ + *((template).Element3Negated+1) -= imag; \ + *((template).Element4Negated+1) -= imag; \ +} + +#if spCOMPATIBILITY +#define ADD_REAL_ELEMENT_TO_MATRIX spADD_REAL_ELEMENT +#define ADD_IMAG_ELEMENT_TO_MATRIX spADD_IMAG_ELEMENT +#define ADD_COMPLEX_ELEMENT_TO_MATRIX spADD_COMPLEX_ELEMENT +#define ADD_REAL_QUAD_ELEMENT_TO_MATRIX spADD_REAL_ELEMENT +#define ADD_IMAG_QUAD_ELEMENT_TO_MATRIX spADD_IMAG_ELEMENT +#define ADD_COMPLEX_QUAD_ELEMENT_TO_MATRIX spADD_COMPLEX_ELEMENT +#endif + + + + + + +/* + * TYPE DEFINITION FOR COMPONENT TEMPLATE + * + * This data structure is used to hold pointers to four related elements in + * matrix. It is used in conjunction with the routines + * spGetAdmittance + * spGetQuad + * spGetOnes + * These routines stuff the structure which is later used by the spADD_QUAD + * macro functions above. It is also possible for the user to collect four + * pointers returned by spGetElement and stuff them into the template. + * The spADD_QUAD routines stuff data into the matrix in locations specified + * by Element1 and Element2 without changing the data. The data is negated + * before being placed in Element3 and Element4. + */ + +#if spCOMPATIBILITY +#define spTemplate TemplateStruct +#endif + +/* Begin `spTemplate'. */ +struct spTemplate +{ spREAL *Element1 ; + spREAL *Element2 ; + spREAL *Element3Negated; + spREAL *Element4Negated; +}; + + + + + +/* + * FUNCTION TYPE DEFINITIONS + * + * The type of every user accessible function is declared here. + */ + +/* Begin function declarations. */ + +#ifdef __STDC__ + +/* For compilers that understand function prototypes. */ + +extern void spClear( char* ); +extern spREAL spCondition( char*, spREAL, int* ); +extern char *spCreate( int, int, int* ); +extern void spDeleteRowAndCol( char*, int, int ); +extern void spDestroy( char* ); +extern int spElementCount( char* ); +extern int spError( char* ); +extern int spFactor( char* ); +extern int spFileMatrix( char*, char*, char*, int, int, int ); +extern int spFileStats( char*, char*, char* ); +extern int spFillinCount( char* ); +extern int spGetAdmittance( char*, int, int, struct spTemplate* ); +extern spREAL *spGetElement( char*, int, int ); +extern char *spGetInitInfo( spREAL* ); +extern int spGetOnes( char*, int, int, int, struct spTemplate* ); +extern int spGetQuad( char*, int, int, int, int, struct spTemplate* ); +extern int spGetSize( char*, int ); +extern int spInitialize( char*, int (*)() ); +extern void spInstallInitInfo( spREAL*, char* ); +extern spREAL spLargestElement( char* ); +extern void spMNA_Preorder( char* ); +extern spREAL spNorm( char* ); +extern int spOrderAndFactor( char*, spREAL*, spREAL, spREAL, int ); +extern int spOriginalCount( char *); +extern void spPartition( char*, int ); +extern void spPrint( char*, int, int, int ); +extern spREAL spPseudoCondition( char* ); +extern spREAL spRoundoff( char*, spREAL ); +extern void spScale( char*, spREAL*, spREAL* ); +extern void spSetComplex( char* ); +extern void spSetReal( char* ); +extern void spStripFills( char* ); +extern void spWhereSingular( char*, int*, int* ); + +/* Functions with argument lists that are dependent on options. */ + +#if spCOMPLEX +extern void spDeterminant ( char*, int*, spREAL*, spREAL* ); +#else /* NOT spCOMPLEX */ +extern void spDeterminant ( char*, int*, spREAL* ); +#endif /* NOT spCOMPLEX */ +#if spCOMPLEX && spSEPARATED_COMPLEX_VECTORS +extern int spFileVector( char*, char* , spREAL*, spREAL*); +extern void spMultiply( char*, spREAL*, spREAL*, spREAL*, spREAL* ); +extern void spMultTransposed(char*,spREAL*,spREAL*,spREAL*,spREAL*); +extern void spSolve( char*, spREAL*, spREAL*, spREAL*, spREAL* ); +extern void spSolveTransposed(char*,spREAL*,spREAL*,spREAL*,spREAL*); +#else /* NOT (spCOMPLEX && spSEPARATED_COMPLEX_VECTORS) */ +extern int spFileVector( char*, char* , spREAL* ); +extern void spMultiply( char*, spREAL*, spREAL* ); +extern void spMultTransposed( char*, spREAL*, spREAL* ); +extern void spSolve( char*, spREAL*, spREAL* ); +extern void spSolveTransposed( char*, spREAL*, spREAL* ); +#endif /* NOT (spCOMPLEX && spSEPARATED_COMPLEX_VECTORS) */ + +#else /* NOT defined(__STDC__) */ + +/* For compilers that do not understand function prototypes. */ + +extern void spClear(); +extern spREAL spCondition(); +extern char *spCreate(); +extern void spDeleteRowAndCol(); +extern void spDestroy(); +extern void spDeterminant (); +extern int spElementCount(); +extern int spError(); +extern int spFactor(); +extern int spFileMatrix(); +extern int spFileStats(); +extern int spFileVector(); +extern int spFillinCount(); +extern int spGetAdmittance(); +extern spREAL *spGetElement(); +extern char *spGetInitInfo(); +extern int spGetOnes(); +extern int spGetQuad(); +extern int spGetSize(); +extern int spInitialize(); +extern void spInstallInitInfo(); +extern spREAL spLargestElement(); +extern void spMNA_Preorder(); +extern void spMultiply(); +extern void spMultTransposed(); +extern spREAL spNorm(); +extern int spOrderAndFactor(); +extern int spOriginalCount(); +extern void spPartition(); +extern void spPrint(); +extern spREAL spPseudoCondition(); +extern spREAL spRoundoff(); +extern void spScale(); +extern void spSetComplex(); +extern void spSetReal(); +extern void spSolve(); +extern void spSolveTransposed(); +extern void spStripFills(); +extern void spWhereSingular(); +#endif /* defined(__STDC__) */ + +#if spCOMPATIBILITY +extern char *AllocateMatrix(); +extern spREAL *AddElementToMatrix(); +extern void AddRealElementToMatrix(); +extern void AddImagElementToMatrix(); +extern void AddComplexElementToMatrix(); +extern void AddAdmittanceToMatrix(); +extern void AddOnesToMatrix(); +extern void AddQuadToMatrix(); +extern void AddRealQuadElementToMatrix(); +extern void AddImagQuadElementToMatrix(); +extern void AddComplexQuadElementToMatrix(); +extern void CleanMatrix(); +extern void ClearMatrix(); +extern int ClearMatrixError(); +extern void DeallocateMatrix(); +extern void DeleteRowAndColFromMatrix(); +extern void Determinant(); +extern int DecomposeMatrix(); +extern int GetMatrixSize(); +extern int MatrixElementCount(); +extern int MatrixFillinCount(); +extern void MatrixMultiply(); +extern spREAL MatrixRoundoffError(); +extern int MatrixError(); +extern int OrderAndDecomposeMatrix(); +extern void OutputMatrixToFile(); +extern void OutputStatisticsToFile(); +extern void OutputVectorToFile(); +extern void PreorderForModifiedNodal(); +extern void PrintMatrix(); +extern void SetMatrixComplex(); +extern void SetMatrixReal(); +extern void SolveMatrix(); +extern void SolveTransposedMatrix(); +extern void ScaleMatrix(); +#endif /* spCOMPATIBILITY */ + +#endif /* spOKAY */ diff --git a/src/include/struct.h b/src/include/struct.h new file mode 100644 index 000000000..0e967765d --- /dev/null +++ b/src/include/struct.h @@ -0,0 +1,199 @@ +/************* + * Structure definitions header file + * 1999 E. Rouat + ************/ + +/* + * This file will contain all extern structure definitions needed + * by ngspice code. (in construction) + */ + +#ifndef _STRUCT_H_ +#define _STRUCT_H_ + + +/* cpstd.h */ + +/* Doubly linked lists of words. */ + +struct wordlist { + char *wl_word; + struct wordlist *wl_next; + struct wordlist *wl_prev; +} ; + +typedef struct wordlist wordlist; + +/* Complex numbers. */ + +struct _complex { /* IBM portability... */ + double cx_real; + double cx_imag; +} ; + +typedef struct _complex complex; + + +/* + * The display device structure (ftedev.h) + */ + +typedef struct { + char *name; + int minx, miny; + int width, height; /* in screen coordinate system */ + int numlinestyles, numcolors; /* number supported */ + int (*Init)(); + int (*NewViewport)(); + int (*Close)(); + int (*Clear)(); + int (*DrawLine)(); + int (*Arc)(); + int (*Text)(); + int (*DefineColor)(); + int (*DefineLinestyle)(); + int (*SetLinestyle)(); + int (*SetColor)(); + int (*Update)(); +/* int (*NDCtoScreen)(); */ + int (*Track)(); + int (*MakeMenu)(); + int (*MakeDialog)(); + int (*Input)(); + int (*DatatoScreen)(); +} DISPDEVICE; + +extern DISPDEVICE *dispdev; + + + +/* ckt */ + + +typedef struct sCKTnode { + IFuid name; + int type; + int number; /* Number of the node */ + double ic; /* Value of the initial condition */ + double nodeset; /* Value of the .nodeset option */ + double *ptr; /* ??? */ + struct sCKTnode *next; /* pointer to the next node */ + unsigned int icGiven:1; /* FLAG ic given */ + unsigned int nsGiven:1; /* FLAG nodeset given */ +} CKTnode; + + +/* the following structure is REALLY MESSY!! */ + + +typedef struct { + GENmodel *CKThead[MAXNUMDEVS]; /* The max number of loadable devices */ + STATistics *CKTstat; /* The STATistics structure */ + double *(CKTstates[8]); /* Used as memory of past steps ??? */ + double CKTtime; /* ??? */ + double CKTdelta; /* ??? */ + double CKTdeltaOld[7]; /* Memory for ??? */ + double CKTtemp; /* Actual temperature of CKT */ + double CKTnomTemp; /* Reference temperature 27 C ? */ + double CKTvt; /* Thernmal voltage at CKTtemp */ + double CKTag[7]; /* the gear variable coefficient matrix */ +#ifdef PREDICTOR + double CKTagp[7]; /* the gear predictor variable coefficient matrix */ +#endif /*PREDICTOR*/ + int CKTorder; /* the integration method order */ + int CKTmaxOrder; /* maximum integration method order */ + int CKTintegrateMethod; /* the integration method to be used */ + SMPmatrix *CKTmatrix; /* pointer to sparse matrix */ + int CKTniState; /* internal state */ + double *CKTrhs; /* current rhs value - being loaded */ + double *CKTrhsOld; /* previous rhs value for convergence testing */ + double *CKTrhsSpare; /* spare rhs value for reordering */ + double *CKTirhs; /* current rhs value - being loaded (imag) */ + double *CKTirhsOld; /* previous rhs value (imaginary)*/ + double *CKTirhsSpare; /* spare rhs value (imaginary)*/ +#ifdef PREDICTOR + double *CKTpred; /* predicted solution vector */ + double *CKTsols[8]; /* previous 8 solutions */ +#endif /* PREDICTOR */ + double *CKTrhsOp; /* opearating point values */ + double *CKTsenRhs; /* current sensitivity rhs values */ + double *CKTseniRhs; /* current sensitivity rhs values (imag)*/ + int CKTmaxEqNum; /* And this ? */ + int CKTcurrentAnalysis; /* the analysis in progress (if any) */ + +/* defines for the value of CKTcurrentAnalysis */ +/* are in TSKdefs.h */ + + CKTnode *CKTnodes; /* ??? */ + CKTnode *CKTlastNode; /* ??? */ + int CKTnumStates; /* Number of sates effectively valid ??? */ + long CKTmode; /* Mode of operation of the circuit ??? */ + int CKTbypass; /* bypass option, how does it work ? */ + int CKTdcMaxIter; /* iteration limit for dc op. (itl1) */ + int CKTdcTrcvMaxIter; /* iteration limit for dc tran. curv (itl2) */ + int CKTtranMaxIter; /* iteration limit for each timepoint for tran*/ + /* (itl4) */ + int CKTbreakSize; /* ??? */ + int CKTbreak; /* ??? */ + double CKTsaveDelta; /* ??? */ + double CKTminBreak; /* ??? */ + double *CKTbreaks; /* List of breakpoints ??? */ + double CKTabstol; /* --- */ + double CKTpivotAbsTol; /* --- */ + double CKTpivotRelTol; /* --- */ + double CKTreltol; /* --- */ + double CKTchgtol; /* --- */ + double CKTvoltTol; /* --- */ + /* What is this define for ? */ +#ifdef NEWTRUNC + double CKTlteReltol; + double CKTlteAbstol; +#endif /* NEWTRUNC */ + double CKTgmin; /* Parallel Conductance --- */ + double CKTdelmin; /* ??? */ + double CKTtrtol; /* ??? */ + double CKTfinalTime; /* ??? */ + double CKTstep; /* ??? */ + double CKTmaxStep; /* ??? */ + double CKTinitTime; /* ??? */ + double CKTomega; /* ??? */ + double CKTsrcFact; /* ??? */ + double CKTdiagGmin; /* ??? */ + int CKTnumSrcSteps; /* ??? */ + int CKTnumGminSteps; /* ??? */ + int CKTnoncon; /* ??? */ + double CKTdefaultMosL; /* Default Channel Lenght of MOS devices */ + double CKTdefaultMosW; /* Default Channel Width of MOS devics */ + double CKTdefaultMosAD; /* Default Drain Area of MOS */ + double CKTdefaultMosAS; /* Default Source Area of MOS */ + unsigned int CKThadNodeset:1; /* ??? */ + unsigned int CKTfixLimit:1; /* flag to indicate that the limiting of + * MOSFETs should be done as in SPICE2 */ + unsigned int CKTnoOpIter:1; /* flag to indicate not to try the operating + * point brute force, but to use gmin stepping + * first */ + unsigned int CKTisSetup:1; /* flag to indicate if CKTsetup done */ + JOB *CKTcurJob; /* Next analysis to be performed ??? */ + + SENstruct *CKTsenInfo; /* the sensitivity information */ + double *CKTtimePoints; /* list of all accepted timepoints in the + current transient simulation */ + double *CKTdeltaList; /* list of all timesteps in the current + transient simulation */ + int CKTtimeListSize; /* size of above lists */ + int CKTtimeIndex; /* current position in above lists */ + int CKTsizeIncr; /* amount to increment size of above arrays + when you run out of space */ + unsigned int CKTtryToCompact:1; /* try to compact past history for LTRA + lines */ + unsigned int CKTbadMos3:1; /* Use old, unfixed MOS3 equations */ + unsigned int CKTkeepOpInfo:1; /* flag for small signal analyses */ + int CKTtroubleNode; /* Non-convergent node number */ + GENinstance *CKTtroubleElt; /* Non-convergent device instance */ + +} CKTcircuit; + + + + +#endif /* _STRUCT_H_ */ diff --git a/src/include/suffix.h b/src/include/suffix.h new file mode 100644 index 000000000..2464bf671 --- /dev/null +++ b/src/include/suffix.h @@ -0,0 +1 @@ +/* Null file */ diff --git a/src/include/tfdefs.h b/src/include/tfdefs.h new file mode 100644 index 000000000..4beb6543e --- /dev/null +++ b/src/include/tfdefs.h @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef TF +#define TF + +#include "jobdefs.h" +#include "tskdefs.h" +#include "cktdefs.h" + + /* TFdefs.h - defs for transfer function analyses */ + +typedef struct { + int JOBtype; + JOB *JOBnextJob; + IFuid JOBname; + CKTnode *TFoutPos; + CKTnode *TFoutNeg; + IFuid TFoutSrc; + IFuid TFinSrc; + char *TFoutName; /* a printable name for an output v(x,y) */ + unsigned int TFoutIsV :1; + unsigned int TFoutIsI :1; + unsigned int TFinIsV :1; + unsigned int TFinIsI :1; +} TFan; + +#define TF_OUTPOS 1 +#define TF_OUTNEG 2 +#define TF_OUTSRC 3 +#define TF_INSRC 4 +#define TF_OUTNAME 5 +extern int TFsetParm(); +extern int TFaskQuest(); +#endif /*TF*/ diff --git a/src/include/trandefs.h b/src/include/trandefs.h new file mode 100644 index 000000000..4de4d61b3 --- /dev/null +++ b/src/include/trandefs.h @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + +#ifndef TRAN +#define TRAN + + +#include "jobdefs.h" +#include "tskdefs.h" + /* + * TRANdefs.h - defs for transient analyses + */ + +typedef struct { + int JOBtype; + JOB *JOBnextJob; + char *JOBname; + double TRANfinalTime; + double TRANstep; + double TRANmaxStep; + double TRANinitTime; + long TRANmode; + void * TRANplot; +} TRANan; + +#define TRAN_TSTART 1 +#define TRAN_TSTOP 2 +#define TRAN_TSTEP 3 +#define TRAN_TMAX 4 +#define TRAN_UIC 5 +extern int TRANsetParm(); +extern int TRANaskQuest(); +#endif /*TRAN*/ diff --git a/src/include/trcvdefs.h b/src/include/trcvdefs.h new file mode 100644 index 000000000..23ce7c6d7 --- /dev/null +++ b/src/include/trcvdefs.h @@ -0,0 +1,57 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: 1999 Paolo Nenzi +**********/ +/* + */ +#ifndef DCTR +#define DCTR + + +#include "jobdefs.h" +#include "tskdefs.h" +#include "gendefs.h" + /* + * structures used to describe D.C. transfer curve analyses to + * be performed. + */ + +#define TRCVNESTLEVEL 2 /* depth of nesting of curves - 2 for spice2 */ + +/* PN: The following define is for temp sweep */ +/* Courtesy of: Serban M. Popescu */ +#ifndef TEMP_CODE +#define TEMP_CODE 1023 +#endif + +typedef struct { + int JOBtype; + JOB *JOBnextJob; + char *JOBname; + double TRCVvStart[TRCVNESTLEVEL]; /* starting voltage/current */ + double TRCVvStop[TRCVNESTLEVEL]; /* ending voltage/current */ + double TRCVvStep[TRCVNESTLEVEL]; /* voltage/current step */ + double TRCVvSave[TRCVNESTLEVEL]; /* voltage of this source BEFORE + * analysis-to restore when done */ + int TRCVgSave[TRCVNESTLEVEL]; /* dcGiven flag; as with vSave */ + IFuid TRCVvName[TRCVNESTLEVEL]; /* source being varied */ + GENinstance *TRCVvElt[TRCVNESTLEVEL]; /* pointer to source */ + int TRCVvType[TRCVNESTLEVEL]; /* type of element being varied */ + int TRCVset[TRCVNESTLEVEL]; /* flag to indicate this nest level used */ + int TRCVnestLevel; /* number of levels of nesting called for */ + int TRCVnestState; /* iteration state during pause */ +} TRCV; + +#define DCT_START1 1 +#define DCT_STOP1 2 +#define DCT_STEP1 3 +#define DCT_NAME1 4 +#define DCT_TYPE1 5 +#define DCT_START2 6 +#define DCT_STOP2 7 +#define DCT_STEP2 8 +#define DCT_NAME2 9 +#define DCT_TYPE2 10 + +#endif /*DCTR*/ diff --git a/src/include/tskdefs.h b/src/include/tskdefs.h new file mode 100644 index 000000000..f009e8744 --- /dev/null +++ b/src/include/tskdefs.h @@ -0,0 +1,61 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ +#ifndef TSK +#define TSK + + +#include "jobdefs.h" + +typedef struct { + JOB taskOptions; /* job structure at the front to hold options */ + JOB *jobs; + char *TSKname; + double TSKtemp; + double TSKnomTemp; + int TSKmaxOrder; /* maximum integration method order */ + int TSKintegrateMethod; /* the integration method to be used */ + int TSKcurrentAnalysis; /* the analysis in progress (if any) */ + +/* defines for the value of TSKcurrentAnalysis */ +#define DOING_DCOP 1 +#define DOING_TRCV 2 +#define DOING_AC 4 +#define DOING_TRAN 8 + + int TSKbypass; + int TSKdcMaxIter; /* iteration limit for dc op. (itl1) */ + int TSKdcTrcvMaxIter; /* iteration limit for dc tran. curv (itl2) */ + int TSKtranMaxIter; /* iteration limit for each timepoint for tran*/ + /* (itl4) */ + int TSKnumSrcSteps; /* number of steps for source stepping */ + int TSKnumGminSteps; /* number of steps for Gmin stepping */ + double TSKminBreak; + double TSKabstol; + double TSKpivotAbsTol; + double TSKpivotRelTol; + double TSKreltol; + double TSKchgtol; + double TSKvoltTol; +#ifdef NEWTRUNC + double TSKlteReltol; + double TSKlteAbstol; +#endif /* NEWTRUNC */ + double TSKgmin; + double TSKdelmin; + double TSKtrtol; + double TSKdefaultMosL; + double TSKdefaultMosW; + double TSKdefaultMosAD; + double TSKdefaultMosAS; + unsigned int TSKfixLimit:1; + unsigned int TSKnoOpIter:1; /* no OP iterating, go straight to gmin step */ + unsigned int TSKtryToCompact:1; /* flag for LTRA lines */ + unsigned int TSKbadMos3:1; /* flag for MOS3 models */ + unsigned int TSKkeepOpInfo:1; /* flag for small signal analyses */ +}TSKtask; + +#endif /*TSK*/ diff --git a/src/main.c b/src/main.c new file mode 100644 index 000000000..1f0b6f062 --- /dev/null +++ b/src/main.c @@ -0,0 +1,650 @@ +/* Copyright 1990 + Regents of the University of California. + All rights reserved. + + Author: 1985 Wayne A. Christopher + + The main routine for ngspice */ +#include +#include +#include + +#include + +#define _GNU_SOURCE +#include + +#include "ngspice.h" +#include "ifsim.h" +#include "inpdefs.h" +#include "iferrmsg.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedev.h" +#include "ftedebug.h" +#include "const.h" + +#ifdef HAVE_PWD_H +#include +#endif + +#ifndef HAVE_GETRUSAGE +#ifdef HAVE_FTIME +#include +#endif +#endif + +/* Main options */ +static bool ft_servermode = FALSE; +static bool ft_batchmode = FALSE; + +/* Frontend options */ +bool ft_intrpt = FALSE; /* Set by the (void) signal handlers. */ +bool ft_setflag = FALSE; /* Don't abort after an interrupt. */ +char *ft_rawfile = "rawspice.raw"; + +/* Frontend and circuit options */ +IFsimulator *ft_sim = NULL; + + + +/* (Virtual) Machine architecture parameters */ +int ARCHme; +int ARCHsize; + +char *errRtn; +char *errMsg; +char *cp_program; + +struct variable *(*if_getparam)( ); + + + +jmp_buf jbuf; + +static int started = FALSE; + + + +#ifndef HAVE_GETRUSAGE +#ifdef HAVE_FTIME +extern struct timeb timebegin; /* for use w/ ftime */ +#endif +#endif + +extern IFsimulator SIMinfo; + +#ifdef SIMULATOR + +bool ft_nutmeg = FALSE; +extern struct comm spcp_coms[ ]; +struct comm *cp_coms = spcp_coms; + +#else + +bool ft_nutmeg = TRUE; +extern struct comm nutcp_coms[ ]; +struct comm *cp_coms = nutcp_coms; +static IFfrontEnd nutmeginfo; + +int +if_run(char *t, char *w, wordlist *s, char *b) +{ + return (0); +} + +int +if_sens_run(char *t, char *w, wordlist *s, char *b) +{ + return (0); +} + +void +if_dump(char *ckt, FILE *fp) +{} + +char * +if_inpdeck(struct line *deck, char **tab) +{ + return ((char *) 0); +} + +int +if_option(char *ckt, char *name, int type, char *value) +{ + return 0; +} + +void if_cktfree(char *ckt, char *tab) +{} + +void if_setndnames(char *line) +{} + +char * +if_errstring(int code) +{ + return ("spice error"); +} + +void +if_setparam(char *ckt, char *name, char *param, struct variable *val) +{} + +bool +if_tranparams(struct circ *ckt, double *start, double *stop, double *step) +{ + return (FALSE); +} + +struct variable * +if_getstat(char *n, char *c) +{ + return (NULL); +} + +#endif /* SIMULATOR */ + +char *hlp_filelist[] = { "ngspice", 0 }; + + +/* allocate space for global constants in 'CONST.h' */ + +double CONSTroot2; +double CONSTvt0; +double CONSTKoverQ; +double CONSTe; +IFfrontEnd *SPfrontEnd = NULL; + + + +int SIMinit(IFfrontEnd *frontEnd, IFsimulator **simulator) +{ + SPfrontEnd = frontEnd; + *simulator = &SIMinfo; + CONSTroot2 = sqrt(2.); + CONSTvt0 = CONSTboltz * (27 /* deg c */ + CONSTCtoK ) / CHARGE; + CONSTKoverQ = CONSTboltz / CHARGE; + CONSTe = exp((double)1.0); + return(OK); +} + + +/* Shutdown gracefully. */ +int +shutdown(int exitval) +{ + cleanvars(); +#ifdef PARALLEL_ARCH + if (exitval == EXIT_BAD) { + Error("Fatal error in SPICE", -1); + } else { + PEND_(); + } +#endif /* PARALLEL_ARCH */ + exit (exitval); +} + +void +show_help(void) +{ + printf("Usage: %s [OPTION]... [FILE]...\n" + "Simulate the electical circuits in FILE.\n" + "\n" + " -b, --batch process FILE in batch mode\n" + " -c, --circuitfile=FILE set the circuitfile\n" + " -i, --interactive run in interactive mode\n" + " -n, --no-spiceinit don't load the .spiceinit configfile\n" + " -o, --output=FILE set the outputfile\n" + " -q, --completion activate command completion\n" + " -r, --rawfile=FILE set the rawfile output\n" + " -s, --server run spice as a server process\n" + " -t, --term=TERM set the terminal type\n" + " -h, --help display this help and exit\n" + " -v, --version output version information and exit\n" + "\n" + "Report bugs to %s.\n", cp_program, Bug_Addr); +} + +void +show_version(void) +{ + printf("%s compiled from %s revision %s\n" + "Written originally by Berkeley University\n" + "Currently maintained by the NG-Spice Project\n\n" + "Copyright (C) 1985-1996," + " The Regents of the University of California\n" + "Copyright (C) 1999-2000," + " The NG-Spice Project\n", cp_program, PACKAGE, VERSION); +} + +void +append_to_stream(FILE *dest, FILE *source) +{ + char *buf[BSIZE_SP]; + int i; + + while ((i = fread(buf, 1, BSIZE_SP, source)) > 0) + fwrite(buf, i, 1, dest); +} + +int +main(int argc, char **argv) +{ + int c; + int err; + bool gotone = FALSE; + +#ifdef SIMULATOR + int error2; + + extern int OUTpBeginPlot(), OUTpData(), OUTwBeginPlot(), OUTwReference(); + extern int OUTwData(), OUTwEnd(), OUTendPlot(), OUTbeginDomain(); + extern int OUTendDomain(), OUTstopnow(), OUTerror(), OUTattributes(); + static IFfrontEnd nutmeginfo = { + IFnewUid, + IFdelUid, + OUTstopnow, + seconds, + OUTerror, + OUTpBeginPlot, + OUTpData, + OUTwBeginPlot, + OUTwReference, + OUTwData, + OUTwEnd, + OUTendPlot, + OUTbeginDomain, + OUTendDomain, + OUTattributes + }; +#else /* ~ SIMULATOR */ + bool gdata = TRUE; +#endif /* ~ SIMULATOR */ + + + char buf[BSIZE_SP]; + bool ciprefix(); + bool readinit = TRUE; + bool rflag = FALSE; + bool istty = TRUE; + bool iflag = FALSE; + bool qflag = FALSE; + FILE *fp; + FILE *circuit_file; + + + /* MFB tends to jump to 0 on errors. This tends to catch it. */ + if (started) { + fprintf(cp_err, "main: Internal Error: jump to zero\n"); + shutdown(EXIT_BAD); + } + started = TRUE; + +#ifdef PARALLEL_ARCH + PBEGIN_(argc, argv); + ARCHme = NODEID_(); + ARCHsize = NNODES_(); + SETDBG_(&debug_flag); + fprintf( stderr, "On-line: process %d of %d total.\n", ARCHme, ARCHsize ); + evlog(EVKEY_ENABLE, EVKEY_EVENT, "On-line", EVKEY_DUMP, EVKEY_DISABLE, + EVKEY_LAST_ARG); +#else + ARCHme = 0; + ARCHsize = 1; +#endif /* PARALLEL_ARCH */ + + + ivars( ); + + cp_in = stdin; + cp_out = stdout; + cp_err = stderr; + + circuit_file = stdin; + + + +#ifdef MALLOCTRACE + mallocTraceInit("malloc.out"); +#endif +#ifdef HAVE_ISATTY + istty = (bool) isatty(fileno(stdin)); +#endif + + + + init_time( ); + + err = SIMinit(&nutmeginfo,&ft_sim); + if(err != OK) { + ft_sperror(err,"SIMinit"); + shutdown(EXIT_BAD); + } + cp_program = ft_sim->simulator; + + srandom(getpid()); + + + while (1) { + int option_index = 0; + static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"version", 0, 0, 'v'}, + {"batch", 0, 0, 'b'}, + {"circuitfile", 0, 0, 'c'}, + {"interactive", 0, 0, 'i'}, + {"no-spiceinit", 0, 0, 'n'}, + {"output", 0, 0, 'o'}, + {"completion", 0, 0, 'q'}, + {"rawfile", 1, 0, 'r'}, + {"server", 0, 0, 's'}, + {"terminal", 1, 0, 't'}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "hvbc:ihno:qr:st:", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': /* Help */ + show_help(); + shutdown (EXIT_NORMAL); + break; + + case 'v': /* Version info */ + show_version(); + shutdown (EXIT_NORMAL); + break; + + case 'b': /* Batch mode */ + ft_batchmode = TRUE; + break; + + case 'c': /* Circuit file */ + if (optarg) { + if (!(circuit_file = fopen(optarg, "r"))) { + perror("circuit file not available"); + shutdown(EXIT_BAD); + } + istty = FALSE; + } + break; + + case 'i': /* Interactive mode */ + iflag = TRUE; + break; + + case 'n': /* Don't read .spiceinit */ + readinit = FALSE; + break; + + case 'o': /* Output file */ + if (optarg) { +#ifdef PARALLEL_ARCH + sprintf (buf, "%s%03d", optarg, ARCHme); +#else + sprintf (buf, "%s", optarg); +#endif + if (!(freopen (buf, "w", stdout))) { + perror (buf); + shutdown (EXIT_BAD); + } + } + break; + + case 'q': /* Command completion */ + qflag = TRUE; + break; + + case 'r': /* The raw file */ + if (optarg) { + cp_vset("rawfile", VT_STRING, optarg); + } + rflag = TRUE; + break; + + case 's': /* Server mode */ + ft_servermode = TRUE; + break; + + case 't': + if (optarg) { + cp_vset("term", VT_STRING, optarg); + } + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + +#ifdef SIMULATOR + if_getparam = spif_getparam; +#else + if_getparam = nutif_getparam; + + if (optind == argc) { + /* No raw file */ + gdata = FALSE; + } +#endif + + + if ((!iflag && !istty) || ft_servermode) + ft_batchmode = TRUE; + if ((iflag && !istty) || qflag) + cp_nocc = TRUE; + if (ft_servermode) + readinit = FALSE; + if (!istty || ft_batchmode) + out_moremode = FALSE; + + /* Would like to do this later, but cpinit evals commands */ + init_rlimits( ); + + /* Have to initialize cp now. */ + ft_cpinit(); + + /* To catch interrupts during .spiceinit... */ + if (setjmp(jbuf) == 1) { + fprintf(cp_err, "Warning: error executing .spiceinit.\n"); + if (!ft_batchmode) + goto bot; + } + + /* Set up signal handling */ + if (!ft_batchmode) { + signal(SIGINT, ft_sigintr); + signal(SIGFPE, sigfloat); +#ifdef SIGTSTP + signal(SIGTSTP, sigstop); +#endif + } + + /* Set up signal handling for fatal errors. */ + signal(SIGILL, sigill); + +#ifdef SIGBUS + signal(SIGBUS, sigbus); +#endif +#ifdef SIGSEGV + signal(SIGSEGV, sigsegv); +#endif +#ifdef SIGSYS + signal(SIGSYS, sig_sys); +#endif + + + if (readinit) { +#ifdef HAVE_PWD_H + /* Try to source either .spiceinit or ~/.spiceinit. */ + if (access(".spiceinit", 0) == 0) + inp_source(".spiceinit"); + else { + char *s; + struct passwd *pw; + + pw = getpwuid(getuid()); + asprintf(&s, "%s/.spiceinit", pw->pw_dir); + if (access(s, 0) == 0) + inp_source(s); + /* free(s); */ + /* FIXME: Do we need to free() char* fields in pw as well? */ + /* free(pw); */ + } +#else /* ~ HAVE_PWD_H */ + /* Try to source the file "spice.rc" in the current directory. */ + if ((fp = fopen("spice.rc", "r")) != NULL) { + (void) fclose(fp); + inp_source("spice.rc"); + } +#endif /* ~ HAVE_PWD_H */ + } + + if (!ft_batchmode) { + com_version(NULL); + DevInit( ); + if (News_File && *News_File) { + fp = fopen(cp_tildexpand(News_File), "r"); + if (fp) { + while (fgets(buf, BSIZE_SP, fp)) + fputs(buf, stdout); + (void) fclose(fp); + } + } + } + + +bot: + + /* Pass 2 -- get the filenames. If we are spice, then this means + * build a circuit for this file. If this is in server mode, don't + * process any of these args. */ + + if (setjmp(jbuf) == 1) + goto evl; + + + cp_interactive = FALSE; + err = 0; + +#ifdef SIMULATOR + if (!ft_servermode && !ft_nutmeg) { + /* Concatenate all non-option arguments into a temporary file + and load that file into the spice core. + + The original routine took a special path if there was only + one non-option argument. In that case, it didn't create + the temporary file but used the original file instead. The + current algorithm is uniform at the expense of a little + startup time. */ + FILE *tempfile; + + tempfile = tmpfile(); + if (optind == argc && !istty) { + append_to_stream(tempfile, stdin); + } + while (optind < argc) { + char *arg; + FILE *tp; + + /* Copy all the arguments into the temporary file */ + arg = argv[optind++]; + tp = fopen(arg, "r"); + if (!tp) { + perror(arg); + err = 1; + break; + } + append_to_stream(tempfile, tp); + fclose(tp); + } + fseek(tempfile, (long) 0, 0); + + if (tempfile && (!err || !ft_batchmode)) { + inp_spsource(tempfile, FALSE, NULL); + gotone = TRUE; + } + if (ft_batchmode && err) + shutdown(EXIT_BAD); + } + + if (!gotone && ft_batchmode && !ft_nutmeg) + inp_spsource(circuit_file, FALSE, (char *) NULL); + +evl: + if (ft_batchmode) { + /* If we get back here in batch mode then something is wrong, + * so exit. */ + bool st = FALSE; + + (void) setjmp(jbuf); + + if (st == TRUE) { + shutdown(EXIT_BAD); + } + st = TRUE; + if (ft_servermode) { + if (ft_curckt == NULL) { + fprintf(cp_err, "Error: no circuit loaded!\n"); + shutdown(EXIT_BAD); + } + if (ft_dorun("")) + shutdown(EXIT_BAD); + shutdown(EXIT_NORMAL); + } + + /* If -r is specified, then we don't bother with the dot + * cards. Otherwise, we use wrd_run, but we are careful not to + * save too much. */ + cp_interactive = FALSE; + if (rflag) { + ft_dotsaves(); + error2 = ft_dorun(ft_rawfile); + if (ft_cktcoms(TRUE) || error2) + shutdown(EXIT_BAD); + } else if (ft_savedotargs()) { + error2 = ft_dorun(NULL); + if (ft_cktcoms(FALSE) || error2) + shutdown(EXIT_BAD); + } else { + fprintf(stderr, + "Note: No \".plot\", \".print\", or \".fourier\" lines; " + "no simulations run\n"); + shutdown(EXIT_BAD); + } + } else { + (void) setjmp(jbuf); + cp_interactive = TRUE; + while (cp_evloop((char *) NULL) == 1) ; + } + +#else /* ~ SIMULATOR */ + + if (ft_nutmeg && gdata) { + while (optind < argc) { + ft_loadfile(argv[optind++]); + gotone = TRUE; + } + if (!gotone) + ft_loadfile(ft_rawfile); + } + +evl: + /* Nutmeg "main" */ + (void) setjmp(jbuf); + cp_interactive = TRUE; + while (cp_evloop((char *) NULL) == 1) ; + +#endif /* ~ SIMULATOR */ + + shutdown(EXIT_NORMAL); + return EXIT_NORMAL; +} diff --git a/src/makeidx.c b/src/makeidx.c new file mode 100644 index 000000000..fe7febb4a --- /dev/null +++ b/src/makeidx.c @@ -0,0 +1,59 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* from FILENAME.txt, make FILENAME.idx */ + +#include "ngspice.h" +#include +#include "cpdefs.h" +#include "hlpdefs.h" +#include "suffix.h" + + + +int +main(argc, argv) +int argc; +char *argv[]; +{ + + FILE *fp; + FILE *wfp; + char buf[BSIZE_SP]; + long fpos; + char subject[BSIZE_SP]; + struct hlp_index indexitem; + char *pos; + + + while (--argc) { + if (!(fp = fopen(argv[argc], "r"))) { + perror(argv[argc]); + continue; + } + strcpy(buf, argv[argc]); + if (((pos =strrchr(buf, '.')) == 0) || + strcmp(pos, ".txt")) { + fprintf(stderr, "%s does not end in .txt\n", buf); + continue; + } + *++pos = 'i'; *++pos = 'd'; *++pos = 'x'; + if (!(wfp = fopen(buf, "wb"))) { + perror(buf); + continue; + } + fpos = 0; + while (fgets(buf, sizeof(buf), fp)) { + if (!strncmp(buf, "SUBJECT: ", 9)) { + strcpy(subject, &buf[9]); + subject[strlen(subject) - 1] = '\0'; /* get rid of '\n' */ + strncpy(indexitem.subject, subject, 64); /* zero out end */ + indexitem.fpos = fpos; + fwrite(&indexitem, sizeof(struct hlp_index), 1, wfp); + } + fpos = ftell(fp); + } + } + exit(0); +} diff --git a/src/maths/Makefile.am b/src/maths/Makefile.am new file mode 100644 index 000000000..793998744 --- /dev/null +++ b/src/maths/Makefile.am @@ -0,0 +1,4 @@ +# Process this file with automake + +SUBDIRS = cmaths ni sparse +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/maths/cmaths/Makefile.am b/src/maths/cmaths/Makefile.am new file mode 100644 index 000000000..b9795ae61 --- /dev/null +++ b/src/maths/cmaths/Makefile.am @@ -0,0 +1,19 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libcmaths.a + +libcmaths_a_SOURCES = \ + cmath1.c \ + cmath1.h \ + cmath2.c \ + cmath2.h \ + cmath3.c \ + cmath3.h \ + cmath4.c \ + cmath4.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/maths/cmaths/cmath1.c b/src/maths/cmaths/cmath1.c new file mode 100644 index 000000000..fd61677ff --- /dev/null +++ b/src/maths/cmaths/cmath1.c @@ -0,0 +1,456 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines to do complex mathematical functions. These routines require + * the -lm libraries. We sacrifice a lot of space to be able + * to avoid having to do a seperate call for every vector element, + * but it pays off in time savings. These routines should never + * allow FPE's to happen. + * + * Complex functions are called as follows: + * cx_something(data, type, length, &newlength, &newtype), + * and return a char * that is cast to complex or double. + * + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftecmath.h" +#include "cmath1.h" + + +/* This flag determines whether degrees or radians are used. The radtodeg + * and degtorad macros are no-ops if this is FALSE. + */ + +bool cx_degrees = FALSE; + +void * +cx_mag(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d = alloc_d(length); + double *dd = (double *) data; + complex *cc = (complex *) data; + int i; + + *newlength = length; + *newtype = VF_REAL; + if (type == VF_REAL) + for (i = 0; i < length; i++) + d[i] = FTEcabs(dd[i]); + else + for (i = 0; i < length; i++) + d[i] = cmag(&cc[i]); + return ((void *) d); +} + +void * +cx_ph(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d = alloc_d(length); + complex *cc = (complex *) data; + int i; + + *newlength = length; + *newtype = VF_REAL; + if (type == VF_COMPLEX) + for (i = 0; i < length; i++) { + d[i] = radtodeg(cph(&cc[i])); + } + /* Otherwise it is 0, but tmalloc zeros the stuff already. */ + return ((void *) d); +} + +/* If this is pure imaginary we might get real, but never mind... */ + +void * +cx_j(void *data, short int type, int length, int *newlength, short int *newtype) +{ + complex *c = alloc_c(length); + complex *cc = (complex *) data; + double *dd = (double *) data; + int i; + + *newlength = length; + *newtype = VF_COMPLEX; + if (type == VF_COMPLEX) + for (i = 0; i < length; i++) { + realpart(&c[i]) = - imagpart(&cc[i]); + imagpart(&c[i]) = realpart(&cc[i]); + } + else + for (i = 0; i < length; i++) { + imagpart(&c[i]) = dd[i]; + /* Real part is already 0. */ + } + return ((void *) c); +} + +void * +cx_real(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d = alloc_d(length); + double *dd = (double *) data; + complex *cc = (complex *) data; + int i; + + *newlength = length; + *newtype = VF_REAL; + if (type == VF_COMPLEX) + for (i = 0; i < length; i++) + d[i] = realpart(&cc[i]); + else + for (i = 0; i < length; i++) + d[i] = dd[i]; + return ((void *) d); +} + +void * +cx_imag(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d = alloc_d(length); + double *dd = (double *) data; + complex *cc = (complex *) data; + int i; + + *newlength = length; + *newtype = VF_REAL; + if (type == VF_COMPLEX) + for (i = 0; i < length; i++) + d[i] = imagpart(&cc[i]); + else + for (i = 0; i < length; i++) + d[i] = dd[i]; + return ((void *) d); +} + +/* This is obsolete... */ + +void * +cx_pos(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d = alloc_d(length); + double *dd = (double *) data; + complex *cc = (complex *) data; + int i; + + *newlength = length; + *newtype = VF_REAL; + if (type == VF_COMPLEX) + for (i = 0; i < length; i++) + d[i] = ((realpart(&cc[i]) > 0.0) ? 1.0 : 0.0); + else + for (i = 0; i < length; i++) + d[i] = ((dd[i] > 0.0) ? 1.0 : 0.0); + return ((void *) d); +} + +void * +cx_db(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d = alloc_d(length); + double *dd = (double *) data; + complex *cc = (complex *) data; + double tt; + int i; + + *newlength = length; + *newtype = VF_REAL; + if (type == VF_COMPLEX) + for (i = 0; i < length; i++) { + tt = cmag(&cc[i]); + rcheck(tt > 0, "db"); + /* + if (tt == 0.0) + d[i] = 20.0 * - log(HUGE); + else + */ + d[i] = 20.0 * log10(tt); + } + else + for (i = 0; i < length; i++) { + rcheck(dd[i] > 0, "db"); + /* + if (dd[i] == 0.0) + d[i] = 20.0 * - log(HUGE); + else + */ + d[i] = 20.0 * log10(dd[i]); + } + return ((void *) d); +} + +void * +cx_log(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + double td; + + td = cmag(&cc[i]); + /* Perhaps we should trap when td = 0.0, but Ken wants + * this to be possible... + */ + rcheck(td >= 0, "log"); + if (td == 0.0) { + realpart(&c[i]) = - log10(HUGE); + imagpart(&c[i]) = 0.0; + } else { + realpart(&c[i]) = log10(td); + imagpart(&c[i]) = atan2(imagpart(&cc[i]), + realpart(&cc[i])); + } + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + for (i = 0; i < length; i++) { + rcheck(dd[i] >= 0, "log"); + if (dd[i] == 0.0) + d[i] = - log10(HUGE); + else + d[i] = log10(dd[i]); + } + return ((void *) d); + } +} + +void * +cx_ln(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + double td; + + td = cmag(&cc[i]); + rcheck(td >= 0, "ln"); + if (td == 0.0) { + realpart(&c[i]) = - log(HUGE); + imagpart(&c[i]) = 0.0; + } else { + realpart(&c[i]) = log(td); + imagpart(&c[i]) = atan2(imagpart(&cc[i]), + realpart(&cc[i])); + } + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + for (i = 0; i < length; i++) { + rcheck(dd[i] >= 0, "ln"); + if (dd[i] == 0.0) + d[i] = - log(HUGE); + else + d[i] = log(dd[i]); + } + return ((void *) d); + } +} + +void * +cx_exp(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + double td; + + td = exp(realpart(&cc[i])); + realpart(&c[i]) = td * cos(imagpart(&cc[i])); + imagpart(&c[i]) = td * sin(imagpart(&cc[i])); + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + for (i = 0; i < length; i++) + d[i] = exp(dd[i]); + return ((void *) d); + } +} + +void * +cx_sqrt(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d; + complex *c; + double *dd = (double *) data; + complex *cc = (complex *) data; + int i, cres = (type == VF_REAL) ? 0 : 1; + + if (type == VF_REAL) + for (i = 0; i < length; i++) + if (dd[i] < 0.0) + cres = 1; + if (cres) { + c = alloc_c(length); + *newtype = VF_COMPLEX; + } else { + d = alloc_d(length); + *newtype = VF_REAL; + } + *newlength = length; + if (type == VF_COMPLEX) { + for (i = 0; i < length; i++) { + if (realpart(&cc[i]) == 0.0) { + if (imagpart(&cc[i]) == 0.0) { + realpart(&c[i]) = 0.0; + imagpart(&c[i]) = 0.0; + } else if (imagpart(&cc[i]) > 0.0) { + realpart(&c[i]) = sqrt (0.5 * + imagpart(&cc[i])); + imagpart(&c[i]) = realpart(&c[i]); + } else { + imagpart(&c[i]) = sqrt( -0.5 * + imagpart(&cc[i])); + realpart(&c[i]) = - imagpart(&c[i]); + } + } else if (realpart(&cc[i]) > 0.0) { + if (imagpart(&cc[i]) == 0.0) { + realpart(&c[i]) = + sqrt(realpart(&cc[i])); + imagpart(&c[i]) = 0.0; + } else if (imagpart(&cc[i]) < 0.0) { + realpart(&c[i]) = -sqrt(0.5 * + (cmag(&cc[i]) + realpart(&cc[i]))); + } else { + realpart(&c[i]) = sqrt(0.5 * + (cmag(&cc[i]) + realpart(&cc[i]))); + } + imagpart(&c[i]) = imagpart(&cc[i]) / (2.0 * + realpart(&c[i])); + } else { /* realpart(&cc[i]) < 0.0) */ + if (imagpart(&cc[i]) == 0.0) { + realpart(&c[i]) = 0.0; + imagpart(&c[i]) = + sqrt(- realpart(&cc[i])); + } else { + if (imagpart(&cc[i]) < 0.0) + imagpart(&c[i]) = - sqrt(0.5 * + (cmag(&cc[i]) - + realpart(&cc[i]))); + else + imagpart(&c[i]) = sqrt(0.5 * + (cmag(&cc[i]) - + realpart(&cc[i]))); + realpart(&c[i]) = imagpart(&cc[i]) / + (2.0 * imagpart(&c[i])); + } + } + } + return ((void *) c); + } else if (cres) { + for (i = 0; i < length; i++) + if (dd[i] < 0.0) + imagpart(&c[i]) = sqrt(- dd[i]); + else + realpart(&c[i]) = sqrt(dd[i]); + return ((void *) c); + } else { + for (i = 0; i < length; i++) + d[i] = sqrt(dd[i]); + return ((void *) d); + } +} + +void * +cx_sin(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + realpart(&c[i]) = sin(degtorad(realpart(&cc[i]))) * + cosh(degtorad(imagpart(&cc[i]))); + imagpart(&c[i]) = cos(degtorad(realpart(&cc[i]))) * + sinh(degtorad(imagpart(&cc[i]))); + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + for (i = 0; i < length; i++) + d[i] = sin(degtorad(dd[i])); + return ((void *) d); + } +} + +void * +cx_cos(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + realpart(&c[i]) = cos(degtorad(realpart(&cc[i]))) * + cosh(degtorad(imagpart(&cc[i]))); + imagpart(&c[i]) = - sin(degtorad(realpart(&cc[i]))) * + sinh(degtorad(imagpart(&cc[i]))); + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + for (i = 0; i < length; i++) + d[i] = cos(degtorad(dd[i])); + return ((void *) d); + } +} + diff --git a/src/maths/cmaths/cmath1.h b/src/maths/cmaths/cmath1.h new file mode 100644 index 000000000..777a60bae --- /dev/null +++ b/src/maths/cmaths/cmath1.h @@ -0,0 +1,26 @@ +/************* + * Header file for cmath1.c + * 1999 E. Rouat + ************/ + +#ifndef CMATH1_H_INCLUDED +#define CMATH1_H_INCLUDED + + +void * cx_mag(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_ph(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_j(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_real(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_imag(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_pos(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_db(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_log(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_ln(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_exp(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_sqrt(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_sin(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_cos(void *data, short int type, int length, int *newlength, short int *newtype); + + + +#endif diff --git a/src/maths/cmaths/cmath2.c b/src/maths/cmaths/cmath2.c new file mode 100644 index 000000000..4333867d1 --- /dev/null +++ b/src/maths/cmaths/cmath2.c @@ -0,0 +1,522 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines to do complex mathematical functions. These routines require + * the -lm libraries. We sacrifice a lot of space to be able + * to avoid having to do a seperate call for every vector element, + * but it pays off in time savings. These routines should never + * allow FPE's to happen. + * + * Complex functions are called as follows: + * cx_something(data, type, length, &newlength, &newtype), + * and return a char * that is cast to complex or double. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftecmath.h" +#include "cmath2.h" + +static double * +d_tan(double *dd, int length) +{ + double *d; + int i; + + d = alloc_d(length); + for (i = 0; i < length; i++) { + rcheck(cos(degtorad(dd[i])) != 0, "tan"); + d[i] = sin(degtorad(dd[i])) / cos(degtorad(dd[i])); + } + return d; +} + +static complex * +c_tan(complex *cc, int length) +{ + complex *c; + int i; + + c = alloc_c(length); + for (i = 0; i < length; i++) { + double u, v; + + rcheck(cos(degtorad(realpart(&cc[i]))) * + cosh(degtorad(imagpart(&cc[i]))), "tan"); + rcheck(sin(degtorad(realpart(&cc[i]))) * + sinh(degtorad(imagpart(&cc[i]))), "tan"); + u = degtorad(realpart(&cc[i])); + v = degtorad(imagpart(&cc[i])); + /* The Lattice C compiler won't take multi-line macros, and + * CMS won't take >80 column lines.... + */ +#define xx1 sin(u) * cosh(v) +#define xx2 cos(u) * sinh(v) +#define xx3 cos(u) * cosh(v) +#define xx4 sin(u) * sinh(v) + cdiv(xx1, xx2, xx3, xx4, realpart(&c[i]), imagpart(&c[i])); + } + return c; +} + +void * +cx_tan(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_REAL) { + *newtype = VF_REAL; + return (void *) d_tan((double *) data, length); + } else { + *newtype = VF_COMPLEX; + return (void *) c_tan((complex *) data, length); + } +} + + + +void * +cx_atan(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d; + + d = alloc_d(length); + *newtype = VF_REAL; + *newlength = length; + if (type == VF_COMPLEX) { + complex *cc = (complex *) data; + int i; + + for (i = 0; i < length; i++) + d[i] = radtodeg(atan(realpart(&cc[i]))); + } else { + double *dd = (double *) data; + int i; + + for (i = 0; i < length; i++) + d[i] = radtodeg(atan(dd[i])); + } + return ((void *) d); +} + + +double +cx_max(void *data, short int type, int length) +{ + double largest = 0.0; + + if (type == VF_COMPLEX) { + complex *cc = (complex *) data; + int i; + + for (i = 0; i < length; i++) + if (cmag(&cc[i]) > largest) + largest = cmag(&cc[i]); + } else { + double *dd = (double *) data; + int i; + + for (i = 0; i < length; i++) + if (FTEcabs(dd[i]) > largest) + largest = FTEcabs(dd[i]); + } + return largest; +} + +/* Normalize the data so that the magnitude of the greatest value is 1. */ + +void * +cx_norm(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double largest = 0.0; + + largest = cx_max(data, type, length); + if (largest == 0.0) { + fprintf(cp_err, "Error: can't normalize a 0 vector\n"); + return (NULL); + } + + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + + for (i = 0; i < length; i++) { + realpart(&c[i]) = realpart(&cc[i]) / largest; + imagpart(&c[i]) = imagpart(&cc[i]) / largest; + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + + for (i = 0; i < length; i++) + d[i] = dd[i] / largest; + return ((void *) d); + } +} + +void * +cx_uminus(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + realpart(&c[i]) = - realpart(&cc[i]); + imagpart(&c[i]) = - imagpart(&cc[i]); + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + for (i = 0; i < length; i++) + d[i] = - dd[i]; + return ((void *) d); + } +} + +void * +cx_rnd(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = length; + if (type == VF_COMPLEX) { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(length); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + int j, k; + + j = floor(realpart(&cc[i])); + k = floor(imagpart(&cc[i])); + realpart(&c[i]) = j ? random() % j : 0; + imagpart(&c[i]) = k ? random() % k : 0; + } + return ((void *) c); + } else { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + for (i = 0; i < length; i++) { + int j; + + j = floor(dd[i]); + d[i] = j ? random() % j : 0; + } + return ((void *) d); + } +} + +/* Compute the mean of a vector. */ + +void * +cx_mean(void *data, short int type, int length, int *newlength, short int *newtype) +{ + *newlength = 1; + rcheck(length > 0, "mean"); + if (type == VF_REAL) { + double *d; + double *dd = (double *) data; + int i; + + d = alloc_d(1); + *newtype = VF_REAL; + for (i = 0; i < length; i++) + *d += dd[i]; + *d /= length; + return ((void *) d); + } else { + complex *c; + complex *cc = (complex *) data; + int i; + + c = alloc_c(1); + *newtype = VF_COMPLEX; + for (i = 0; i < length; i++) { + realpart(c) += realpart(cc + i); + imagpart(c) += imagpart(cc + i); + } + realpart(c) /= length; + imagpart(c) /= length; + return ((void *) c); + } +} + + +void * +cx_length(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d; + + *newlength = 1; + *newtype = VF_REAL; + d = alloc_d(1); + *d = length; + return ((void *) d); +} + +/* Return a vector from 0 to the magnitude of the argument. Length of the + * argument is irrelevent. + */ + + +void * +cx_vector(void *data, short int type, int length, int *newlength, short int *newtype) +{ + complex *cc = (complex *) data; + double *dd = (double *) data; + int i, len; + double *d; + + if (type == VF_REAL) + len = FTEcabs(*dd); + else + len = cmag(cc); + if (len == 0) + len = 1; + d = alloc_d(len); + *newlength = len; + *newtype = VF_REAL; + for (i = 0; i < len; i++) + d[i] = i; + return ((void *) d); +} + +/* Create a vector of the given length composed of all ones. */ + + +void * +cx_unitvec(void *data, short int type, int length, int *newlength, short int *newtype) +{ + complex *cc = (complex *) data; + double *dd = (double *) data; + int i, len; + double *d; + + if (type == VF_REAL) + len = FTEcabs(*dd); + else + len = cmag(cc); + if (len == 0) + len = 1; + d = alloc_d(len); + *newlength = len; + *newtype = VF_REAL; + for (i = 0; i < len; i++) + d[i] = 1; + return ((void *) d); +} + +/* Calling methods for these functions are: + * cx_something(data1, data2, datatype1, datatype2, length) + * + * The length of the two data vectors is always the same, and is the length + * of the result. The result type is complex iff one of the args is + * complex. + */ + +void * +cx_plus(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex *c, c1, c2; + int i; + + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + d = alloc_d(length); + for (i = 0; i < length; i++) + d[i] = dd1[i] + dd2[i]; + return ((void *) d); + } else { + c = alloc_c(length); + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + realpart(&c[i]) = realpart(&c1) + realpart(&c2); + imagpart(&c[i]) = imagpart(&c1) + imagpart(&c2); + } + return ((void *) c); + } +} + +void * +cx_minus(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex *c, c1, c2; + int i; + + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + d = alloc_d(length); + for (i = 0; i < length; i++) + d[i] = dd1[i] - dd2[i]; + return ((void *) d); + } else { + c = alloc_c(length); + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + realpart(&c[i]) = realpart(&c1) - realpart(&c2); + imagpart(&c[i]) = imagpart(&c1) - imagpart(&c2); + } + return ((void *) c); + } +} + +void * +cx_times(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex *c, c1, c2; + int i; + + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + d = alloc_d(length); + for (i = 0; i < length; i++) + d[i] = dd1[i] * dd2[i]; + return ((void *) d); + } else { + c = alloc_c(length); + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + realpart(&c[i]) = realpart(&c1) * realpart(&c2) + - imagpart(&c1) * imagpart(&c2); + imagpart(&c[i]) = imagpart(&c1) * realpart(&c2) + + realpart(&c1) * imagpart(&c2); + } + return ((void *) c); + } +} + +void * +cx_mod(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex *c, c1, c2; + int i, r1, r2, i1, i2, r3, i3; + + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + d = alloc_d(length); + for (i = 0; i < length; i++) { + r1 = floor(FTEcabs(dd1[i])); + rcheck(r1 > 0, "mod"); + r2 = floor(FTEcabs(dd2[i])); + rcheck(r2 > 0, "mod"); + r3 = r1 % r2; + d[i] = (double) r3; + } + return ((void *) d); + } else { + c = alloc_c(length); + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + r1 = floor(FTEcabs(realpart(&c1))); + rcheck(r1 > 0, "mod"); + r2 = floor(FTEcabs(realpart(&c2))); + rcheck(r2 > 0, "mod"); + i1 = floor(FTEcabs(imagpart(&c1))); + rcheck(i1 > 0, "mod"); + i2 = floor(FTEcabs(imagpart(&c2))); + rcheck(i2 > 0, "mod"); + r3 = r1 % r2; + i3 = i1 % i2; + realpart(&c[i]) = (double) r3; + imagpart(&c[i]) = (double) i3; + } + return ((void *) c); + } +} + diff --git a/src/maths/cmaths/cmath2.h b/src/maths/cmaths/cmath2.h new file mode 100644 index 000000000..1be23e970 --- /dev/null +++ b/src/maths/cmaths/cmath2.h @@ -0,0 +1,25 @@ +/************* + * Header file for cmath2.c + * 1999 E. Rouat + ************/ + +#ifndef CMATH2_H_INCLUDED +#define CMATH2_H_INCLUDED + + +void * cx_tan(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_atan(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_norm(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_uminus(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_rnd(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_mean(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_length(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_vector(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_unitvec(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_plus(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_minus(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_times(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_mod(void *data1, void *data2, short int datatype1, short int datatype2, int length); + + +#endif diff --git a/src/maths/cmaths/cmath3.c b/src/maths/cmaths/cmath3.c new file mode 100644 index 000000000..db6b799d7 --- /dev/null +++ b/src/maths/cmaths/cmath3.c @@ -0,0 +1,463 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines to do complex mathematical functions. These routines require + * the -lm libraries. We sacrifice a lot of space to be able + * to avoid having to do a seperate call for every vector element, + * but it pays off in time savings. These routines should never + * allow FPE's to happen. + * + * Complex functions are called as follows: + * cx_something(data, type, length, &newlength, &newtype), + * and return a char * that is cast to complex or double. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftecmath.h" +#include "cmath3.h" + + +static complex *cexp(complex *c); +static complex *cln(complex *c); +static complex *ctimes(complex *c1, complex *c2); + +void * +cx_divide(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex *c, c1, c2; + int i; + + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + d = alloc_d(length); + for (i = 0; i < length; i++) { + rcheck(dd2[i] != 0, "divide"); + d[i] = dd1[i] / dd2[i]; + } + return ((void *) d); + } else { + c = alloc_c(length); + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + rcheck((realpart(&c2) != 0) || (imagpart(&c2) != 0), "divide"); +#define xx5 realpart(&c1) +#define xx6 imagpart(&c1) +cdiv(xx5, xx6, realpart(&c2), imagpart(&c2), realpart(&c[i]), imagpart(&c[i])); + } + return ((void *) c); + } +} + +/* Should just use "j( )" */ +/* The comma operator. What this does (unless it is part of the argument + * list of a user-defined function) is arg1 + j(arg2). + */ + +void * +cx_comma(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex *c, c1, c2; + int i; + + c = alloc_c(length); + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + + realpart(&c[i]) = realpart(&c1) + imagpart(&c2); + imagpart(&c[i]) = imagpart(&c1) + realpart(&c2); + } + return ((void *) c); +} + +void * +cx_power(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex *c, c1, c2, *t; + int i; + + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + d = alloc_d(length); + for (i = 0; i < length; i++) { + rcheck((dd1[i] >= 0) || (floor(dd2[i]) == ceil(dd2[i])), "power"); + d[i] = pow(dd1[i], dd2[i]); + } + return ((void *) d); + } else { + c = alloc_c(length); + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + + if ((realpart(&c1) == 0.0) && (imagpart(&c1) == 0.0)) { + realpart(&c[i]) = 0.0; + imagpart(&c[i]) = 0.0; + } else { /* if ((imagpart(&c1) != 0.0) && + (imagpart(&c2) != 0.0)) */ + t = cexp(ctimes(&c2, cln(&c1))); + realpart(&c[i]) = realpart(t); + imagpart(&c[i]) = imagpart(t); + /* + } else { + realpart(&c[i]) = pow(realpart(&c1), + realpart(&c2)); + imagpart(&c[i]) = 0.0; + */ + } + } + return ((void *) c); + } +} + +/* These are unnecessary... Only cx_power uses them... */ + +static complex * +cexp(complex *c) +{ + static complex r; + double d; + + d = exp(realpart(c)); + realpart(&r) = d * cos(imagpart(c)); + if (imagpart(c) != 0.0) + imagpart(&r) = d * sin(imagpart(c)); + else + imagpart(&r) = 0.0; + return (&r); +} + +static complex * +cln(complex *c) +{ + static complex r; + + rcheck(cmag(c) != 0, "ln"); + realpart(&r) = log(cmag(c)); + if (imagpart(c) != 0.0) + imagpart(&r) = atan2(imagpart(c), realpart(c)); + else + imagpart(&r) = 0.0; + return (&r); +} + +static complex * +ctimes(complex *c1, complex *c2) +{ + static complex r; + + realpart(&r) = realpart(c1) * realpart(c2) - + imagpart(c1) * imagpart(c2); + imagpart(&r) = imagpart(c1) * realpart(c2) + + realpart(c1) * imagpart(c2); + return (&r); +} + + + +/* Now come all the relational and logical functions. It's overkill to put + * them here, but... Note that they always return a real value, with the + * result the same length as the arguments. + */ + +void * +cx_eq(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + if (dd1[i] == dd2[i]) + d[i] = 1.0; + else + d[i] = 0.0; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) == realpart(&c2)) && + (imagpart(&c1) == imagpart(&c2))); + } + } + return ((void *) d); +} + +void * +cx_gt(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + if (dd1[i] > dd2[i]) + d[i] = 1.0; + else + d[i] = 0.0; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) > realpart(&c2)) && + (imagpart(&c1) > imagpart(&c2))); + } + } + return ((void *) d); +} + +void * +cx_lt(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + if (dd1[i] < dd2[i]) + d[i] = 1.0; + else + d[i] = 0.0; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) < realpart(&c2)) && + (imagpart(&c1) < imagpart(&c2))); + } + } + return ((void *) d); +} + +void * +cx_ge(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + if (dd1[i] >= dd2[i]) + d[i] = 1.0; + else + d[i] = 0.0; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) >= realpart(&c2)) && + (imagpart(&c1) >= imagpart(&c2))); + } + } + return ((void *) d); +} + +void * +cx_le(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + if (dd1[i] <= dd2[i]) + d[i] = 1.0; + else + d[i] = 0.0; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) <= realpart(&c2)) && + (imagpart(&c1) <= imagpart(&c2))); + } + } + return ((void *) d); +} + +void * +cx_ne(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + if (dd1[i] != dd2[i]) + d[i] = 1.0; + else + d[i] = 0.0; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) != realpart(&c2)) && + (imagpart(&c1) != imagpart(&c2))); + } + } + return ((void *) d); +} + diff --git a/src/maths/cmaths/cmath3.h b/src/maths/cmaths/cmath3.h new file mode 100644 index 000000000..a657a827d --- /dev/null +++ b/src/maths/cmaths/cmath3.h @@ -0,0 +1,21 @@ +/************* + * Header file for cmath3.c + * 1999 E. Rouat + ************/ + +#ifndef CMATH3_H_INCLUDED +#define CMATH3_H_INCLUDED + + +void * cx_divide(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_comma(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_power(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_eq(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_gt(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_lt(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_ge(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_le(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_ne(void *data1, void *data2, short int datatype1, short int datatype2, int length); + + +#endif diff --git a/src/maths/cmaths/cmath4.c b/src/maths/cmaths/cmath4.c new file mode 100644 index 000000000..833d13560 --- /dev/null +++ b/src/maths/cmaths/cmath4.c @@ -0,0 +1,379 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines to do complex mathematical functions. These routines require + * the -lm libraries. We sacrifice a lot of space to be able + * to avoid having to do a seperate call for every vector element, + * but it pays off in time savings. These routines should never + * allow FPE's to happen. + * + * Complex functions are called as follows: + * cx_something(data, type, length, &newlength, &newtype), + * and return a char * that is cast to complex or double. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "ftecmath.h" +#include "cmath4.h" + + +void * +cx_and(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + d[i] = dd1[i] && dd2[i]; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) && realpart(&c2)) && + (imagpart(&c1) && imagpart(&c2))); + } + } + return ((void *) d); +} + +void * +cx_or(void *data1, void *data2, short int datatype1, short int datatype2, int length) +{ + double *dd1 = (double *) data1; + double *dd2 = (double *) data2; + double *d; + complex *cc1 = (complex *) data1; + complex *cc2 = (complex *) data2; + complex c1, c2; + int i; + + d = alloc_d(length); + if ((datatype1 == VF_REAL) && (datatype2 == VF_REAL)) { + for (i = 0; i < length; i++) + d[i] = dd1[i] || dd2[i]; + } else { + for (i = 0; i < length; i++) { + if (datatype1 == VF_REAL) { + realpart(&c1) = dd1[i]; + imagpart(&c1) = 0.0; + } else { + realpart(&c1) = realpart(&cc1[i]); + imagpart(&c1) = imagpart(&cc1[i]); + } + if (datatype2 == VF_REAL) { + realpart(&c2) = dd2[i]; + imagpart(&c2) = 0.0; + } else { + realpart(&c2) = realpart(&cc2[i]); + imagpart(&c2) = imagpart(&cc2[i]); + } + d[i] = ((realpart(&c1) || realpart(&c2)) && + (imagpart(&c1) || imagpart(&c2))); + } + } + return ((void *) d); +} + +void * +cx_not(void *data, short int type, int length, int *newlength, short int *newtype) +{ + double *d; + double *dd = (double *) data; + complex *cc = (complex *) data; + int i; + + d = alloc_d(length); + *newtype = VF_REAL; + *newlength = length; + if (type == VF_COMPLEX) { + for (i = 0; i < length; i++) { + /* gcc doens't like !double */ + d[i] = realpart(&cc[i]) ? 0 : 1; + d[i] = imagpart(&cc[i]) ? 0 : 1; + } + } else { + for (i = 0; i < length; i++) + d[i] = ! dd[i]; + } + return ((void *) d); +} + +/* This is a strange function. What we do is fit a polynomial to the + * curve, of degree $polydegree, and then evaluate it at the points + * in the time scale. What we do is this: for every set of points that + * we fit a polynomial to, fill in as much of the new vector as we can + * (i.e, between the last value of the old scale we went from to this + * one). At the ends we just use what we have... We have to detect + * badness here too... + * Note that we pass arguments differently for this one cx_ function... + */ + +void * +cx_interpolate(void *data, short int type, int length, int *newlength, short int *newtype, struct plot *pl, struct plot *newpl, int grouping) +{ + struct dvec *ns, *os; + double *d; + int degree; + register int i, oincreasing = 1, nincreasing = 1; + int base; + + if (grouping == 0) + grouping = length; + + /* First do some sanity checks. */ + if (!pl || !pl->pl_scale || !newpl || !newpl->pl_scale) { + fprintf(cp_err, "Internal error: cx_interpolate: bad scale\n"); + return (NULL); + } + ns = newpl->pl_scale; + os = pl->pl_scale; + if (iscomplex(ns)) { + fprintf(cp_err, "Error: new scale has complex data\n"); + return (NULL); + /* + for (i = ns->v_length - 1; i >= 0; i--) + if (imagpart(&ns->v_compdata[i])) { + fprintf(cp_err, + "Error: new scale has complex data\n"); + return (NULL); + } + osbuf = alloc_d(olen); + */ + } + if (iscomplex(os)) { + fprintf(cp_err, "Error: old scale has complex data\n"); + return (NULL); + /* + for (i = os->v_length - 1; i >= 0; i--) + if (imagpart(&os->v_compdata[i])) { + fprintf(cp_err, + "Error: old scale has complex data\n"); + return (NULL); + } + nsbuf = alloc_d(nlen); + */ + } + + if (length != os->v_length) { + fprintf(cp_err, "Error: lengths don't match\n"); + return (NULL); + } + if (type != VF_REAL) { + fprintf(cp_err, "Error: argument has complex data\n"); + return (NULL); + } + + /* Now make sure that either both scales are strictly increasing or + * both are strictly decreasing. + */ + if (os->v_realdata[0] < os->v_realdata[1]) + oincreasing = TRUE; + else + oincreasing = FALSE; + for (i = 0; i < os->v_length - 1; i++) + if ((os->v_realdata[i] < os->v_realdata[i + 1]) + != oincreasing) { + fprintf(cp_err, "Error: old scale not monotonic\n"); + return (NULL); + } + if (ns->v_realdata[0] < ns->v_realdata[1]) + nincreasing = TRUE; + else + nincreasing = FALSE; + for (i = 0; i < ns->v_length - 1; i++) + if ((ns->v_realdata[i] < ns->v_realdata[i + 1]) + != nincreasing) { + fprintf(cp_err, "Error: new scale not monotonic\n"); + return (NULL); + } + + *newtype = VF_REAL; + *newlength = ns->v_length; + d = alloc_d(ns->v_length); + + if (!cp_getvar("polydegree", VT_NUM, (void *) °ree)) + degree = 1; + + for (base = 0; base < length; base += grouping) { + if (!ft_interpolate((double *) data + base, d + base, + os->v_realdata + base, grouping, + ns->v_realdata + base, grouping, degree)) + { + tfree(d); + return (NULL); + } + } + + return ((void *) d); +} + +void * +cx_deriv(void *data, short int type, int length, int *newlength, short int *newtype, struct plot *pl, struct plot *newpl, int grouping) +{ + double *scratch; + double *spare; + double x; + int i, j, k; + int degree; + int n, base; + + if (grouping == 0) + grouping = length; + /* First do some sanity checks. */ + if (!pl || !pl->pl_scale || !newpl || !newpl->pl_scale) { + fprintf(cp_err, "Internal error: cx_deriv: bad scale\n"); + return (NULL); + } + + if (!cp_getvar("dpolydegree", VT_NUM, (void *) °ree)) + degree = 2; /* default quadratic */ + + n = degree + 1; + + spare = alloc_d(n); + scratch = alloc_d(n * (n + 1)); + + *newlength = length; + *newtype = type; + + if (type == VF_COMPLEX) { + complex *c_outdata, *c_indata; + double *r_coefs, *i_coefs; + double *scale; + + r_coefs = alloc_d(n); + i_coefs = alloc_d(n); + c_indata = (complex *) data; + c_outdata = alloc_c(length); + scale = alloc_d(length); /* XXX */ + if (pl->pl_scale->v_type == VF_COMPLEX) + /* Not ideal */ + for (i = 0; i < length; i++) + scale[i] = realpart(&pl->pl_scale->v_compdata[i]); + else + for (i = 0; i < length; i++) + scale[i] = pl->pl_scale->v_realdata[i]; + for (base = 0; base < length; base += grouping) { + k = 0; + for (i = degree; i < grouping; i += 1) { + + /* real */ + for (j = 0; j < n; j++) + spare[j] = c_indata[j + i + base].cx_real; + if (!ft_polyfit(scale + i + base - degree, + spare, r_coefs, degree, scratch)) + { + fprintf(stderr, "ft_polyfit @ %d failed\n", i); + } + ft_polyderiv(r_coefs, degree); + + /* for loop gets the beginning part */ + for (j = k; j <= i + degree / 2; j++) { + x = scale[j + base]; + c_outdata[j + base].cx_real = + ft_peval(x, r_coefs, degree - 1); + } + + /* imag */ + for (j = 0; j < n; j++) + spare[j] = c_indata[j + i + base].cx_imag; + if (!ft_polyfit(scale + i - degree + base, + spare, i_coefs, degree, scratch)) + { + fprintf(stderr, "ft_polyfit @ %d failed\n", i); + } + ft_polyderiv(i_coefs, degree); + + /* for loop gets the beginning part */ + for (j = k; j <= i - degree / 2; j++) { + x = scale[j + base]; + c_outdata[j + base].cx_imag = + ft_peval(x, i_coefs, degree - 1); + } + k = j; + } + + /* get the tail */ + for (j = k; j < length; j++) { + x = scale[j + base]; + /* real */ + c_outdata[j + base].cx_real = ft_peval(x, r_coefs, degree - 1); + /* imag */ + c_outdata[j + base].cx_imag = ft_peval(x, i_coefs, degree - 1); + } + } + + tfree(r_coefs); + tfree(i_coefs); + tfree(scale); + return (void *) c_outdata; + + } else { + /* all-real case */ + double *coefs; + + double *outdata, *indata; + double *scale; + + coefs = alloc_d(n); + indata = (double *) data; + outdata = alloc_d(length); + scale = alloc_d(length); /* XXX */ + for (i = 0; i < length; i++) + scale[i] = pl->pl_scale->v_realdata[i]; + for (base = 0; base < length; base += grouping) { + k = 0; + for (i = degree; i < grouping; i += 1) { + if (!ft_polyfit(scale + i - degree + base, + indata + i - degree + base, coefs, degree, scratch)) + { + fprintf(stderr, "ft_polyfit @ %d failed\n", i + base); + } + ft_polyderiv(coefs, degree); + + /* for loop gets the beginning part */ + for (j = k; j <= i - degree / 2; j++) { + x = pl->pl_scale->v_realdata[j + base]; + outdata[j + base] = ft_peval(x, coefs, degree - 1); + } + k = j; + } + + for (j = k; j < length; j++) { + x = pl->pl_scale->v_realdata[j + base]; + outdata[j + base] = ft_peval(x, coefs, degree - 1); + } + } + + + tfree(coefs); + tfree(scale); /* XXX */ + return (void *) outdata; + } + +} diff --git a/src/maths/cmaths/cmath4.h b/src/maths/cmaths/cmath4.h new file mode 100644 index 000000000..dcf55a18d --- /dev/null +++ b/src/maths/cmaths/cmath4.h @@ -0,0 +1,18 @@ +/************* + * Header file for cmath4.c + * 1999 E. Rouat + ************/ + +#ifndef CMATH4_H_INCLUDED +#define CMATH4_H_INCLUDED + +void * cx_and(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_or(void *data1, void *data2, short int datatype1, short int datatype2, int length); +void * cx_not(void *data, short int type, int length, int *newlength, short int *newtype); +void * cx_interpolate(void *data, short int type, int length, int *newlength, + short int *newtype, struct plot *pl, struct plot *newpl, int grouping); +void * cx_deriv(void *data, short int type, int length, int *newlength, short int *newtype, + struct plot *pl, struct plot *newpl, int grouping); + + +#endif diff --git a/src/maths/ni/ChangeLog b/src/maths/ni/ChangeLog new file mode 100644 index 000000000..97fb7914c --- /dev/null +++ b/src/maths/ni/ChangeLog @@ -0,0 +1,18 @@ +1999-09-03 Emmanuel Rouat + + * *.h: added header file for each .c file + +1999-09-01 Paolo Nenzi + + * *.c: replaced GENERIC with void and removed #include suffix.h. + +1999-08-12 Emmanuel Rouat + + * nipzmeth.c (NIpzMuller): removed unused variables + + * *.c : made functions ANSI compliant using 'protoize' + +1999-08-08 Emmanuel Rouat + + * niiter.c: changed HAS_SENSE2 in WANT_SENSE2 + diff --git a/src/maths/ni/Makefile.am b/src/maths/ni/Makefile.am new file mode 100644 index 000000000..f685a50a3 --- /dev/null +++ b/src/maths/ni/Makefile.am @@ -0,0 +1,36 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libni.a + +libni_a_SOURCES = \ + niaciter.c \ + niaciter.h \ + nicomcof.c \ + nicomcof.h \ + niconv.c \ + niconv.h \ + nidest.c \ + nidest.h \ + niditer.c \ + niditer.h \ + niinit.c \ + niinit.h \ + niinteg.c \ + niinteg.h \ + niiter.c \ + niiter.h \ + niniter.c \ + niniter.h \ + nipred.c \ + nipred.h \ + nipzmeth.c \ + nipzmeth.h \ + nireinit.c \ + nireinit.h \ + nisenre.c \ + nisenre.h + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/maths/ni/niaciter.c b/src/maths/ni/niaciter.c new file mode 100644 index 000000000..02c5eb8f5 --- /dev/null +++ b/src/maths/ni/niaciter.c @@ -0,0 +1,91 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified 1999 Emmanuel Rouat +**********/ + + /* + * NIacIter(ckt) + * + * This subroutine performs the actual numerical iteration. + * It uses the sparse matrix stored in the NIstruct by NIinit, + * along with the matrix loading program, the load data, the + * convergence test function, and the convergence parameters + * - return value is non-zero for convergence failure + */ + +#include "ngspice.h" +#include +#include "trandefs.h" +#include "cktdefs.h" +#include "sperror.h" +#include "niaciter.h" + + +int +NIacIter(register CKTcircuit *ckt) +{ + int error; + int ignore; + double *temp; + double startTime; + +retry: + ckt->CKTnoncon=0; + + error = CKTacLoad(ckt); + if(error) return(error); + + if(ckt->CKTniState & NIACSHOULDREORDER) { + startTime = SPfrontEnd->IFseconds(); + error = SMPcReorder(ckt->CKTmatrix,ckt->CKTpivotAbsTol, + ckt->CKTpivotRelTol,&ignore); + ckt->CKTstat->STATreorderTime += + SPfrontEnd->IFseconds()- startTime; + ckt->CKTniState &= ~NIACSHOULDREORDER; + if(error != 0) { + /* either singular equations or no memory, in either case, + * let caller handle problem + */ + return(error); + } + } else { + startTime = SPfrontEnd->IFseconds(); + error = SMPcLUfac(ckt->CKTmatrix,ckt->CKTpivotAbsTol); + ckt->CKTstat->STATdecompTime += + SPfrontEnd->IFseconds()-startTime; + if(error != 0) { + if(error == E_SINGULAR) { + /* the problem is that the matrix can't be solved with the + * current LU factorization. Maybe if we reload and + * try to reorder again it will help... + */ + ckt->CKTniState |= NIACSHOULDREORDER; + goto retry; + } + return(error); /* can't handle E_BADMATRIX, so let caller */ + } + } + startTime = SPfrontEnd->IFseconds(); + SMPcSolve(ckt->CKTmatrix,ckt->CKTrhs, + ckt->CKTirhs, ckt->CKTrhsSpare, + ckt->CKTirhsSpare); + ckt->CKTstat->STATsolveTime += SPfrontEnd->IFseconds() - startTime; + + *ckt->CKTrhs = 0; + *ckt->CKTrhsSpare = 0; + *ckt->CKTrhsOld = 0; + *ckt->CKTirhs = 0; + *ckt->CKTirhsSpare = 0; + *ckt->CKTirhsOld = 0; + + temp = ckt->CKTirhsOld; + ckt->CKTirhsOld = ckt->CKTirhs; + ckt->CKTirhs = temp; + + temp = ckt->CKTrhsOld; + ckt->CKTrhsOld = ckt->CKTrhs; + ckt->CKTrhs = temp; + + return(OK); +} diff --git a/src/maths/ni/niaciter.h b/src/maths/ni/niaciter.h new file mode 100644 index 000000000..889e80f0a --- /dev/null +++ b/src/maths/ni/niaciter.h @@ -0,0 +1,12 @@ +/************* + * Header file for niaciter.c + * 1999 E. Rouat + ************/ + +#ifndef NIACITER_H_INCLUDED +#define NIACITER_H_INCLUDED + +int NIacIter(register CKTcircuit *ckt); + + +#endif diff --git a/src/maths/ni/nicomcof.c b/src/maths/ni/nicomcof.c new file mode 100644 index 000000000..59798dc2d --- /dev/null +++ b/src/maths/ni/nicomcof.c @@ -0,0 +1,207 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "sperror.h" +#include "nicomcof.h" + + +int +NIcomCof(CKTcircuit *ckt) +{ + + double mat[8][8]; /* matrix to compute the gear coefficients in */ + int i,j,k; /* generic loop indicies */ + double arg; + double arg1; + + /* this routine calculates the timestep-dependent terms used in the + * numerical integration. + */ + + /* + * compute coefficients for particular integration method + */ + switch(ckt->CKTintegrateMethod) { + + case TRAPEZOIDAL: + switch(ckt->CKTorder) { + + case 1: + ckt->CKTag[0] = 1/ckt->CKTdelta; + ckt->CKTag[1] = -1/ckt->CKTdelta; + break; + + case 2: + ckt->CKTag[0]=1.0/ckt->CKTdelta/(1.0-0.5) ; + ckt->CKTag[1]=0.5/(1.0 - 0.5) ; + /* above lines should have 'xmu' instead of .5 eventually */ + /* (in all three places) */ + break; + + default: + return(E_ORDER); + } + break; + + case GEAR: + switch(ckt->CKTorder) { + + case 1: + /* ckt->CKTag[0] = 1/ckt->CKTdelta; + ckt->CKTag[1] = -1/ckt->CKTdelta; + break;*/ + + case 2: + case 3: + case 4: + case 5: + case 6: + bzero(ckt->CKTag,7*sizeof(double)); + ckt->CKTag[1] = -1/ckt->CKTdelta; + /* first, set up the matrix */ + arg=0; + for(i=0;i<=ckt->CKTorder;i++) { mat[0][i]=1; } + for(i=1;i<=ckt->CKTorder;i++) { mat[i][0]=0; } + /* SPICE2 difference warning + * the following block builds the corrector matrix + * using (sum of h's)/h(final) instead of just (sum of h's) + * because the h's are typically ~1e-10, so h^7 is an + * underflow on many machines, but the ratio is ~1 + * and produces much better results + */ + for(i=1;i<=ckt->CKTorder;i++) { + arg += ckt->CKTdeltaOld[i-1]; + arg1 = 1; + for(j=1;j<=ckt->CKTorder;j++) { + arg1 *= arg/ckt->CKTdelta; + mat[j][i]=arg1; + } + } + /* lu decompose */ + /* weirdness warning! + * The following loop (and the first one after the forward + * substitution comment) start at one instead of zero + * because of a SPECIAL CASE - the first column is 1 0 0 ... + * thus, the first iteration of both loops does nothing, + * so it is skipped + */ + for(i=1;i<=ckt->CKTorder;i++) { + for(j=i+1;j<=ckt->CKTorder;j++) { + mat[j][i] /= mat[i][i]; + for(k=i+1;k<=ckt->CKTorder;k++) { + mat[j][k] -= mat[j][i]*mat[i][k]; + } + } + } + /* forward substitution */ + for(i=1;i<=ckt->CKTorder;i++) { + for(j=i+1;j<=ckt->CKTorder;j++) { + ckt->CKTag[j]=ckt->CKTag[j]-mat[j][i]*ckt->CKTag[i]; + } + } + /* backward substitution */ + ckt->CKTag[ckt->CKTorder] /= mat[ckt->CKTorder][ckt->CKTorder]; + for(i=ckt->CKTorder-1;i>=0;i--) { + for(j=i+1;j<=ckt->CKTorder;j++) { + ckt->CKTag[i]=ckt->CKTag[i]-mat[i][j]*ckt->CKTag[j]; + } + ckt->CKTag[i] /= mat[i][i]; + } + break; + + + default: + return(E_ORDER); + } + break; + + default: + return(E_METHOD); + } + +#ifdef PREDICTOR + /* ok, have the coefficients for corrector, now for the predictor */ + + switch(ckt->CKTintegrateMethod) { + + default: + return(E_METHOD); + + case TRAPEZOIDAL: + /* ADAMS-BASHFORD PREDICTOR FOR TRAPEZOIDAL CORRECTOR + * MAY BE SUPPLEMENTED BY SECOND ORDER GEAR CORRECTOR + * AGP(1) STORES b0 AND AGP(2) STORES b1 + */ + arg = ckt->CKTdelta/(2*ckt->CKTdeltaOld[1]); + ckt->CKTagp[0] = 1+arg; + ckt->CKTagp[1] = -arg; + break; + + case GEAR: + + /* + * CONSTRUCT GEAR PREDICTOR COEFICENT MATRIX + * MUST STILL ACCOUNT FOR ARRAY AGP() + * KEEP THE SAME NAME FOR GMAT + */ + bzero(ckt->CKTagp,7*sizeof(double)); + /* SET UP RHS OF EQUATIONS */ + ckt->CKTagp[0]=1; + for(i=0;i<=ckt->CKTorder;i++) { + mat[0][i] = 1; + } + arg = 0; + for(i=0;i<=ckt->CKTorder;i++){ + arg += ckt->CKTdeltaOld[i]; + arg1 = 1; + for(j=1;j<=ckt->CKTorder;j++) { + arg1 *= arg/ckt->CKTdelta; + mat[j][i]=arg1; + } + } + /* + * SOLVE FOR GEAR COEFFICIENTS AGP(*) + */ + + /* + * LU DECOMPOSITION + */ + for(i=0;i<=ckt->CKTorder;i++) { + for(j=i+1;j<=ckt->CKTorder;j++) { + mat[j][i] /= mat[i][i]; + for(k=i+1;k<=ckt->CKTorder;k++) { + mat[j][k] -= mat[j][i]*mat[i][k]; + } + } + } + /* + * FORWARD SUBSTITUTION + */ + for(i=0;i<=ckt->CKTorder;i++) { + for(j=i+1;j<=ckt->CKTorder;j++) { + ckt->CKTagp[j] -= mat[j][i]*ckt->CKTagp[i]; + } + } + /* + * BACKWARD SUBSTITUTION + */ + ckt->CKTagp[ckt->CKTorder] /= mat[ckt->CKTorder][ckt->CKTorder]; + for(i=ckt->CKTorder-1;i>=0;i--) { + for(j=i+1;j<=ckt->CKTorder;j++) { + ckt->CKTagp[i] -= mat[i][j]*ckt->CKTagp[j]; + } + ckt->CKTagp[i] /= mat[i][i]; + } + /* + * FINISHED + */ + break; + } +#endif /* PREDICTOR */ + return(OK); +} diff --git a/src/maths/ni/nicomcof.h b/src/maths/ni/nicomcof.h new file mode 100644 index 000000000..59edb80ea --- /dev/null +++ b/src/maths/ni/nicomcof.h @@ -0,0 +1,12 @@ +/************* + * Header file for nicomcof.c + * 1999 E. Rouat + ************/ + +#ifndef NICOMCOF_H_INCLUDED +#define NICOMCOF_H_INCLUDED + +int NIcomCof(CKTcircuit *ckt); + + +#endif diff --git a/src/maths/ni/niconv.c b/src/maths/ni/niconv.c new file mode 100644 index 000000000..d85028914 --- /dev/null +++ b/src/maths/ni/niconv.c @@ -0,0 +1,70 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * NIconvTest(ckt) + * perform the convergence test - returns 1 if any of the + * values in the old and new arrays have changed by more + * than absTol + relTol*(max(old,new)), otherwise returns 0 + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "niconv.h" + + +int +NIconvTest(register CKTcircuit *ckt) +{ + register int i; /* generic loop variable */ + register int size; /* size of the matrix */ + register CKTnode *node; /* current matrix entry */ + double old; + double new; + double tol; + + node = ckt->CKTnodes; + size = SMPmatSize(ckt->CKTmatrix); + for (i=1;i<=size;i++) { + node = node->next; + new = *((ckt->CKTrhs) + i ) ; + old = *((ckt->CKTrhsOld) + i ) ; + if(node->type == 3) { + tol = ckt->CKTreltol * (MAX(fabs(old),fabs(new))) + + ckt->CKTvoltTol; + if (fabs(new-old) >tol ) { +#ifdef STEPDEBUG + printf(" non-convergence at node %s\n",CKTnodName(ckt,i)); +#endif /* STEPDEBUG */ + ckt->CKTtroubleNode = i; + ckt->CKTtroubleElt = NULL; + return(1); + } + } else { + tol = ckt->CKTreltol * (MAX(fabs(old),fabs(new))) + + ckt->CKTabstol; + if (fabs(new-old) >tol ) { +#ifdef STEPDEBUG + printf(" non-convergence at node %s\n",CKTnodName(ckt,i)); +#endif /* STEPDEBUG */ + ckt->CKTtroubleNode = i; + ckt->CKTtroubleElt = NULL; + return(1); + } + } + } + + +#ifdef NEWCONV + i = CKTconvTest(ckt); + if (i) + ckt->CKTtroubleNode = 0; + return(i); +#else /* NEWCONV */ + return(0); +#endif /* NEWCONV */ +} diff --git a/src/maths/ni/niconv.h b/src/maths/ni/niconv.h new file mode 100644 index 000000000..3e5bbb527 --- /dev/null +++ b/src/maths/ni/niconv.h @@ -0,0 +1,12 @@ +/************* + * Header file for niconv.c + * 1999 E. Rouat + ************/ + +#ifndef NICONV_H_INCLUDED +#define NICONV_H_INCLUDED + +int NIconvTest(register CKTcircuit *ckt); + + +#endif diff --git a/src/maths/ni/nidest.c b/src/maths/ni/nidest.c new file mode 100644 index 000000000..205e0a2ab --- /dev/null +++ b/src/maths/ni/nidest.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* NIdestroy(ckt) + * delete the data structures allocated for numeric integration. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "nidest.h" + + +void +NIdestroy(register CKTcircuit *ckt) +{ + if (ckt->CKTmatrix) + SMPdestroy(ckt->CKTmatrix); + ckt->CKTmatrix = 0; + if(ckt->CKTrhs) FREE(ckt->CKTrhs); + if(ckt->CKTrhsOld) FREE(ckt->CKTrhsOld); + if(ckt->CKTrhsSpare) FREE(ckt->CKTrhsSpare); + if(ckt->CKTirhs) FREE(ckt->CKTirhs); + if(ckt->CKTirhsOld) FREE(ckt->CKTirhsOld); + if(ckt->CKTirhsSpare) FREE(ckt->CKTirhsSpare); +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo){ + if(ckt->CKTrhsOp) FREE(((CKTcircuit *)ckt)->CKTrhsOp); + if(ckt->CKTsenRhs) FREE(((CKTcircuit *)ckt)->CKTsenRhs); + if(ckt->CKTseniRhs) FREE(((CKTcircuit *)ckt)->CKTseniRhs); + SENdestroy(ckt->CKTsenInfo); + } +#endif +} diff --git a/src/maths/ni/nidest.h b/src/maths/ni/nidest.h new file mode 100644 index 000000000..2cd786d87 --- /dev/null +++ b/src/maths/ni/nidest.h @@ -0,0 +1,12 @@ +/************* + * Header file for nidest.c + * 1999 E. Rouat + ************/ + +#ifndef NIDEST_H_INCLUDED +#define NIDEST_H_INCLUDED + + +void NIdestroy(register CKTcircuit *ckt); + +#endif diff --git a/src/maths/ni/niditer.c b/src/maths/ni/niditer.c new file mode 100644 index 000000000..1fc447b35 --- /dev/null +++ b/src/maths/ni/niditer.c @@ -0,0 +1,98 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S. Roychowdhury +**********/ + + /* + * NIdIter(ckt) + * + * This is absolutely the same as NIacIter, except that the RHS + * vector is stored before acLoad so that it is not lost. Moreover, + * acLoading is done only if reordering is necessary + * + */ + +#include "ngspice.h" +#include +#include "trandefs.h" +#include "cktdefs.h" +#include "sperror.h" +#include "niditer.h" + + +int +NIdIter(register CKTcircuit *ckt) +{ + int error; + int ignore; + double *temp; + + ckt->CKTnoncon = 0; + goto skip; +retry: + ckt->CKTnoncon=0; + + temp = ckt->CKTrhs; + ckt->CKTrhs = ckt->CKTrhsSpare; + ckt->CKTrhsSpare = temp; + + temp = ckt->CKTirhs; + ckt->CKTirhs = ckt->CKTirhsSpare; + ckt->CKTirhsSpare = temp; + + error = CKTacLoad(ckt); + if(error) return(error); + + temp = ckt->CKTrhs; + ckt->CKTrhs = ckt->CKTrhsSpare; + ckt->CKTrhsSpare = temp; + + temp = ckt->CKTirhs; + ckt->CKTirhs = ckt->CKTirhsSpare; + ckt->CKTirhsSpare = temp; + +skip: + if(ckt->CKTniState & NIACSHOULDREORDER) { + error = SMPcReorder(ckt->CKTmatrix,ckt->CKTpivotAbsTol, + ckt->CKTpivotRelTol,&ignore); + ckt->CKTniState &= ~NIACSHOULDREORDER; + if(error != 0) { + /* either singular equations or no memory, in either case, + * let caller handle problem + */ + return(error); + } + } else { + error = SMPcLUfac(ckt->CKTmatrix,ckt->CKTpivotAbsTol); + if(error != 0) { + if(error == E_SINGULAR) { + /* the problem is that the matrix can't be solved with the + * current LU factorization. Maybe if we reload and + * try to reorder again it will help... + */ + ckt->CKTniState |= NIACSHOULDREORDER; + goto retry; + } + return(error); /* can't handle E_BADMATRIX, so let caller */ + } + } + SMPcSolve(ckt->CKTmatrix,ckt->CKTrhs, + ckt->CKTirhs, ckt->CKTrhsSpare, + ckt->CKTirhsSpare); + + *ckt->CKTrhs = 0; + *ckt->CKTrhsSpare = 0; + *ckt->CKTrhsOld = 0; + *ckt->CKTirhs = 0; + *ckt->CKTirhsSpare = 0; + *ckt->CKTirhsOld = 0; + + temp = ckt->CKTirhsOld; + ckt->CKTirhsOld = ckt->CKTirhs; + ckt->CKTirhs = temp; + + temp = ckt->CKTrhsOld; + ckt->CKTrhsOld = ckt->CKTrhs; + ckt->CKTrhs = temp; + return(OK); +} diff --git a/src/maths/ni/niditer.h b/src/maths/ni/niditer.h new file mode 100644 index 000000000..722071221 --- /dev/null +++ b/src/maths/ni/niditer.h @@ -0,0 +1,13 @@ +/************* + * Header file for niditer.c + * 1999 E. Rouat + ************/ + +#ifndef NIDITER_H_INCLUDED +#define NIDITER_H_INCLUDED + + +int NIdIter(register CKTcircuit *ckt); + + +#endif diff --git a/src/maths/ni/niinit.c b/src/maths/ni/niinit.c new file mode 100644 index 000000000..e8a0ac4a3 --- /dev/null +++ b/src/maths/ni/niinit.c @@ -0,0 +1,31 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + /* + * NIinit(nistruct,loadpkg) + * + * Initialize the Numerical iteration package to perform Newton-Raphson + * iterations on a sparse matrix filled by the specified load package, + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include +#include "sperror.h" +#include "smpdefs.h" +#include "niinit.h" + + +int +NIinit(CKTcircuit *ckt) +{ +#ifdef SPARSE +/* a concession to Ken Kundert's sparse matrix package - SMP doesn't need this*/ + int Error; +#endif /* SPARSE */ + ckt->CKTniState = NIUNINITIALIZED; + return(SMPnewMatrix( &(ckt->CKTmatrix) ) ); +} diff --git a/src/maths/ni/niinit.h b/src/maths/ni/niinit.h new file mode 100644 index 000000000..cf49eba71 --- /dev/null +++ b/src/maths/ni/niinit.h @@ -0,0 +1,13 @@ +/************* + * Header file for niinit.c + * 1999 E. Rouat + ************/ + +#ifndef NIINIT_H_INCLUDED +#define NIINIT_H_INCLUDED + + +int NIinit(CKTcircuit *ckt); + + +#endif diff --git a/src/maths/ni/niinteg.c b/src/maths/ni/niinteg.c new file mode 100644 index 000000000..6ccce77b3 --- /dev/null +++ b/src/maths/ni/niinteg.c @@ -0,0 +1,82 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* NIintegrate(ckt,geq,ceq,cap,qcap) + * integrate the specified capacitor - method and order in the + * ckt structure, ccap follows qcap. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "sperror.h" +#include "niinteg.h" + +#define ccap qcap+1 + +int +NIintegrate(register CKTcircuit *ckt, double *geq, double *ceq, double cap, int qcap) +{ + static char *ordmsg = "Illegal integration order"; + static char *methodmsg = "Unknown integration method"; + + switch(ckt->CKTintegrateMethod) { + + case TRAPEZOIDAL: + switch(ckt->CKTorder) { + case 1: + *(ckt->CKTstate0+ccap) = ckt->CKTag[0] * (*(ckt->CKTstate0+qcap)) + + ckt->CKTag[1] * (*(ckt->CKTstate1+qcap)); + break; + case 2: + *(ckt->CKTstate0+ccap) = - *(ckt->CKTstate1+ccap) * ckt->CKTag[1] + + ckt->CKTag[0] * + ( *(ckt->CKTstate0+qcap) - *(ckt->CKTstate1+qcap) ); + break; + default: + errMsg = MALLOC(strlen(ordmsg)+1); + strcpy(errMsg,ordmsg); + return(E_ORDER); + } + break; + case GEAR: + *(ckt->CKTstate0+ccap)=0; + switch(ckt->CKTorder) { + + case 6: + *(ckt->CKTstate0+ccap) += ckt->CKTag[6]* *(ckt->CKTstate6+qcap); + /* fall through */ + case 5: + *(ckt->CKTstate0+ccap) += ckt->CKTag[5]* *(ckt->CKTstate5+qcap); + /* fall through */ + case 4: + *(ckt->CKTstate0+ccap) += ckt->CKTag[4]* *(ckt->CKTstate4+qcap); + /* fall through */ + case 3: + *(ckt->CKTstate0+ccap) += ckt->CKTag[3]* *(ckt->CKTstate3+qcap); + /* fall through */ + case 2: + *(ckt->CKTstate0+ccap) += ckt->CKTag[2]* *(ckt->CKTstate2+qcap); + /* fall through */ + case 1: + *(ckt->CKTstate0+ccap) += ckt->CKTag[1]* *(ckt->CKTstate1+qcap); + *(ckt->CKTstate0+ccap) += ckt->CKTag[0]* *(ckt->CKTstate0+qcap); + break; + + default: + return(E_ORDER); + + } + break; + + default: + errMsg = MALLOC(strlen(methodmsg)+1); + strcpy(errMsg,methodmsg); + return(E_METHOD); + } + *ceq = *(ckt->CKTstate0+ccap) - ckt->CKTag[0] * *(ckt->CKTstate0+qcap); + *geq = ckt->CKTag[0] * cap; + return(OK); +} diff --git a/src/maths/ni/niinteg.h b/src/maths/ni/niinteg.h new file mode 100644 index 000000000..a7dbc59b8 --- /dev/null +++ b/src/maths/ni/niinteg.h @@ -0,0 +1,13 @@ +/************* + * Header file for niinteg.c + * 1999 E. Rouat + ************/ + +#ifndef NIINTEG_H_INCLUDED +#define NIINTEG_H_INCLUDED + + +int NIintegrate(register CKTcircuit *ckt, double *geq, double *ceq, double cap, int qcap); + + +#endif diff --git a/src/maths/ni/niiter.c b/src/maths/ni/niiter.c new file mode 100644 index 000000000..9b58daef8 --- /dev/null +++ b/src/maths/ni/niiter.c @@ -0,0 +1,234 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * NIiter(ckt,maxIter) + * + * This subroutine performs the actual numerical iteration. + * It uses the sparse matrix stored in the circuit struct + * along with the matrix loading program, the load data, the + * convergence test function, and the convergence parameters + */ + +#include "ngspice.h" +#include +#include "trandefs.h" +#include "cktdefs.h" +#include "smpdefs.h" +#include "sperror.h" +#include "niiter.h" + + +/* NIiter() - return value is non-zero for convergence failure */ + +int +NIiter(register CKTcircuit *ckt, int maxIter) +{ + int iterno; + int ipass; + int error; + int i,j; /* temporaries for finding error location */ + char *message; /* temporary message buffer */ + double *temp; + double startTime; + static char *msg = "Too many iterations without convergence"; + + + iterno=0; + ipass=0; + + + if( (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)){ + temp = ckt->CKTrhsOld; + ckt->CKTrhsOld = ckt->CKTrhs; + ckt->CKTrhs = temp; + error = CKTload(ckt); + if(error) { + return(error); + } + return(OK); + } +#ifdef WANT_SENSE2 + if(ckt->CKTsenInfo){ + error = NIsenReinit(ckt); + if(error) return(error); + } +#endif + if(ckt->CKTniState & NIUNINITIALIZED) { + error = NIreinit(ckt); + if(error){ +#ifdef STEPDEBUG + printf("re-init returned error \n"); +#endif + return(error); + } + } + for(;;){ + ckt->CKTnoncon=0; +#ifdef NEWPRED + if(!(ckt->CKTmode & MODEINITPRED)) { +#else /* NEWPRED */ + if(1) { /* } */ +#endif /* NEWPRED */ + error = CKTload(ckt); + /*printf("loaded, noncon is %d\n",ckt->CKTnoncon);*/ + /*fflush(stdout);*/ + iterno++; + if(error) { + ckt->CKTstat->STATnumIter += iterno; +#ifdef STEPDEBUG + printf("load returned error \n"); +#endif + return(error); + } + /*printf("after loading, before solving\n");*/ + /*CKTdump(ckt);*/ + + if(!(ckt->CKTniState & NIDIDPREORDER)) { + error = SMPpreOrder(ckt->CKTmatrix); + if(error) { + ckt->CKTstat->STATnumIter += iterno; +#ifdef STEPDEBUG + printf("pre-order returned error \n"); +#endif + return(error); /* badly formed matrix */ + } + ckt->CKTniState |= NIDIDPREORDER; + } + if( (ckt->CKTmode & MODEINITJCT) || + ( (ckt->CKTmode & MODEINITTRAN) && (iterno==1))) { + ckt->CKTniState |= NISHOULDREORDER; + } + + if(ckt->CKTniState & NISHOULDREORDER) { + startTime = (*(SPfrontEnd->IFseconds))(); + error = SMPreorder(ckt->CKTmatrix,ckt->CKTpivotAbsTol, + ckt->CKTpivotRelTol,ckt->CKTdiagGmin); + ckt->CKTstat->STATreorderTime += + (*(SPfrontEnd->IFseconds))()-startTime; + if(error) { + /* new feature - we can now find out something about what is + * wrong - so we ask for the troublesome entry + */ + SMPgetError(ckt->CKTmatrix,&i,&j); + message = (char *)MALLOC(1000); /* should be enough */ + (void)sprintf(message, + "singular matrix: check nodes %s and %s\n", + NODENAME(ckt,i),NODENAME(ckt,j)); + (*(SPfrontEnd->IFerror))(ERR_WARNING,message,(IFuid *)NULL); + FREE(message); + ckt->CKTstat->STATnumIter += iterno; +#ifdef STEPDEBUG + printf("reorder returned error \n"); +#endif + return(error); /* can't handle these errors - pass up! */ + } + ckt->CKTniState &= ~NISHOULDREORDER; + } else { + startTime = (*(SPfrontEnd->IFseconds))(); + error=SMPluFac(ckt->CKTmatrix,ckt->CKTpivotAbsTol, + ckt->CKTdiagGmin); + ckt->CKTstat->STATdecompTime += + (*(SPfrontEnd->IFseconds))()-startTime; + if(error) { + if( error == E_SINGULAR ) { + ckt->CKTniState |= NISHOULDREORDER; + DEBUGMSG(" forced reordering....\n"); + continue; + } + /*CKTload(ckt);*/ + /*SMPprint(ckt->CKTmatrix,stdout);*/ + /* seems to be singular - pass the bad news up */ + ckt->CKTstat->STATnumIter += iterno; +#ifdef STEPDEBUG + printf("lufac returned error \n"); +#endif + return(error); + } + } + + startTime = (*(SPfrontEnd->IFseconds))(); + SMPsolve(ckt->CKTmatrix,ckt->CKTrhs,ckt->CKTrhsSpare); + ckt->CKTstat->STATsolveTime += (*(SPfrontEnd->IFseconds))()- + startTime; +#ifdef STEPDEBUG +/*XXXX*/ + if (*ckt->CKTrhs != 0.0) + printf("NIiter: CKTrhs[0] = %g\n", *ckt->CKTrhs); + if (*ckt->CKTrhsSpare != 0.0) + printf("NIiter: CKTrhsSpare[0] = %g\n", *ckt->CKTrhsSpare); + if (*ckt->CKTrhsOld != 0.0) + printf("NIiter: CKTrhsOld[0] = %g\n", *ckt->CKTrhsOld); +/*XXXX*/ +#endif + *ckt->CKTrhs = 0; + *ckt->CKTrhsSpare = 0; + *ckt->CKTrhsOld = 0; + + if(iterno > maxIter) { + /*printf("too many iterations without convergence: %d iter's\n", + iterno);*/ + ckt->CKTstat->STATnumIter += iterno; + errMsg = MALLOC(strlen(msg)+1); + strcpy(errMsg,msg); +#ifdef STEPDEBUG + printf("iterlim exceeded \n"); +#endif + return(E_ITERLIM); + } + if(ckt->CKTnoncon==0 && iterno!=1) { + ckt->CKTnoncon = NIconvTest(ckt); + } else { + ckt->CKTnoncon = 1; + } +#ifdef STEPDEBUG + printf("noncon is %d\n",ckt->CKTnoncon); +#endif + } + + if(ckt->CKTmode & MODEINITFLOAT) { + if ((ckt->CKTmode & MODEDC) && + ( ckt->CKThadNodeset) ) { + if(ipass) { + ckt->CKTnoncon=ipass; + } + ipass=0; + } + if(ckt->CKTnoncon == 0) { + ckt->CKTstat->STATnumIter += iterno; + return(OK); + } + } else if(ckt->CKTmode & MODEINITJCT) { + ckt->CKTmode = (ckt->CKTmode&(~INITF))|MODEINITFIX; + ckt->CKTniState |= NISHOULDREORDER; + } else if (ckt->CKTmode & MODEINITFIX) { + if(ckt->CKTnoncon==0) ckt->CKTmode = + (ckt->CKTmode&(~INITF))|MODEINITFLOAT; + ipass=1; + } else if (ckt->CKTmode & MODEINITSMSIG) { + ckt->CKTmode = (ckt->CKTmode&(~INITF))|MODEINITFLOAT; + } else if (ckt->CKTmode & MODEINITTRAN) { + if(iterno<=1) ckt->CKTniState |= NISHOULDREORDER; + ckt->CKTmode = (ckt->CKTmode&(~INITF))|MODEINITFLOAT; + } else if (ckt->CKTmode & MODEINITPRED) { + ckt->CKTmode = (ckt->CKTmode&(~INITF))|MODEINITFLOAT; + } else { + ckt->CKTstat->STATnumIter += iterno; +#ifdef STEPDEBUG + printf("bad initf state \n"); +#endif + return(E_INTERN); + /* impossible - no such INITF flag! */ + } + + /* build up the lvnim1 array from the lvn array */ + temp = ckt->CKTrhsOld; + ckt->CKTrhsOld = ckt->CKTrhs; + ckt->CKTrhs = temp; + /*printf("after loading, after solving\n");*/ + /*CKTdump(ckt);*/ + } + /*NOTREACHED*/ +} diff --git a/src/maths/ni/niiter.h b/src/maths/ni/niiter.h new file mode 100644 index 000000000..c8ea7934a --- /dev/null +++ b/src/maths/ni/niiter.h @@ -0,0 +1,13 @@ +/************* + * Header file for niiter.c + * 1999 E. Rouat + ************/ + +#ifndef NIITER_H_INCLUDED +#define NIITER_H_INCLUDED + + +int NIiter(register CKTcircuit *ckt, int maxIter); + + +#endif diff --git a/src/maths/ni/niniter.c b/src/maths/ni/niniter.c new file mode 100644 index 000000000..fc09a209c --- /dev/null +++ b/src/maths/ni/niniter.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include "cktdefs.h" +#include "niniter.h" + +/* + * NInzIter (ckt, posDrive, negDrive) + * + * This routine solves the adjoint system. It assumes that the matrix has + * already been loaded by a call to NIacIter, so it only alters the right + * hand side vector. The unit-valued current excitation is applied + * between nodes posDrive and negDrive. + */ + + +extern void SMPcaSolve(); + +void +NInzIter(CKTcircuit *ckt, int posDrive, int negDrive) +{ + int i; + + /* clear out the right hand side vector */ + + for (i=0; i<= SMPmatSize((SMPmatrix *)ckt->CKTmatrix); i++) { + *((ckt->CKTrhs) + i) = 0.0; + *((ckt->CKTirhs) + i) = 0.0; + } + + *((ckt->CKTrhs) + posDrive) = 1.0; /* apply unit current excitation */ + *((ckt->CKTrhs) + negDrive) = -1.0; + SMPcaSolve(ckt->CKTmatrix, ckt->CKTrhs, ckt->CKTirhs, ckt->CKTrhsSpare, + ckt->CKTirhsSpare); + *ckt->CKTrhs = 0.0; + *ckt->CKTirhs = 0.0; +} diff --git a/src/maths/ni/niniter.h b/src/maths/ni/niniter.h new file mode 100644 index 000000000..a31eb11cd --- /dev/null +++ b/src/maths/ni/niniter.h @@ -0,0 +1,12 @@ +/************* + * Header file for niniter.c + * 1999 E. Rouat + ************/ + +#ifndef NINITER_H_INCLUDED +#define NINITER_H_INCLUDED + +void NInzIter(CKTcircuit *ckt, int posDrive, int negDrive); + + +#endif diff --git a/src/maths/ni/nipred.c b/src/maths/ni/nipred.c new file mode 100644 index 000000000..574411ac0 --- /dev/null +++ b/src/maths/ni/nipred.c @@ -0,0 +1,155 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* + * NIpred(ckt) + * + * This subroutine does node voltage prediction based on the + * integration method + */ + +#include "ngspice.h" +#include +#include "trandefs.h" +#include "cktdefs.h" +#include "sperror.h" +#include "smpdefs.h" +#include "nipred.h" + + +#ifdef PREDICTOR +int +NIpred(register CKTcircuit * ckt) + +{ + int i; + double *temp; + int size; + register CKTnode *node; + + /* for our prediction, we have: + * ckt->CKTrhs[] is the current solution + * ckt->CKTsols[8][] is the set of previous solutions + * + * we want: + * ckt->CKTpred[] = ckt->CKTrhs = prediction based on proper number of + * previous time steps. + */ + + + size = SMPmatSize(ckt->CKTmatrix); + + switch(ckt->CKTintegrateMethod) { + + case TRAPEZOIDAL: { + double dd0,dd1,a,b; + switch(ckt->CKTorder) { + + case 1: + for(i=0;i<=size;i++) { + dd0=(ckt->CKTsols[0][i]-ckt->CKTsols[1][i])/ + (ckt->CKTdeltaOld[1]); + ckt->CKTpred[i] = ckt->CKTrhs[i] = ckt->CKTsols[0][i]+ + ckt->CKTdeltaOld[0]*dd0; + } + break; + + case 2: + for(i=0;i<=size;i++) { + b = -ckt->CKTdeltaOld[0]/(2*ckt->CKTdeltaOld[1]); + a = 1-b; + dd0=(ckt->CKTsols[0][i]-ckt->CKTsols[1][i])/ + (ckt->CKTdeltaOld[1]); + dd1= ((ckt->CKTsols[1][i]-ckt->CKTsols[2][i])/ + ckt->CKTdeltaOld[2] ); + ckt->CKTpred[i] = ckt->CKTrhs[i] = + ckt->CKTsols[0][i]+ + (b*dd1 + a*dd0)* ckt->CKTdeltaOld[0]; + } + break; + + default: + return(E_ORDER); + } + case GEAR: + node = ckt->CKTnodes; + switch(ckt->CKTorder) { + + case 1: + for(i=0;i<=size;i++) { + ckt->CKTpred[i]=ckt->CKTrhs[i] = + ckt->CKTagp[0]* ckt->CKTsols[0][i] + + ckt->CKTagp[1]* ckt->CKTsols[1][i] ; + node = node->next; + } + break; + case 2: + for(i=0;i<=size;i++) { + ckt->CKTpred[i]=ckt->CKTrhs[i] = + ckt->CKTagp[0]* ckt->CKTsols[0][i] + + ckt->CKTagp[1]* ckt->CKTsols[1][i] + + ckt->CKTagp[2]* ckt->CKTsols[2][i] ; + node = node->next; + } + break; + case 3: + for(i=0;i<=size;i++) { + ckt->CKTpred[i]=ckt->CKTrhs[i] = + ckt->CKTagp[0]* ckt->CKTsols[0][i] + + ckt->CKTagp[1]* ckt->CKTsols[1][i] + + ckt->CKTagp[2]* ckt->CKTsols[2][i] + + ckt->CKTagp[3]* ckt->CKTsols[3][i] ; + } + break; + case 4: + for(i=0;i<=size;i++) { + ckt->CKTpred[i]=ckt->CKTrhs[i] = + ckt->CKTagp[0]* ckt->CKTsols[0][i] + + ckt->CKTagp[1]* ckt->CKTsols[1][i] + + ckt->CKTagp[2]* ckt->CKTsols[2][i] + + ckt->CKTagp[3]* ckt->CKTsols[3][i] + + ckt->CKTagp[4]* ckt->CKTsols[4][i] ; + } + break; + case 5: + for(i=0;i<=size;i++) { + ckt->CKTpred[i]=ckt->CKTrhs[i] = + ckt->CKTagp[0]* ckt->CKTsols[0][i] + + ckt->CKTagp[1]* ckt->CKTsols[1][i] + + ckt->CKTagp[2]* ckt->CKTsols[2][i] + + ckt->CKTagp[3]* ckt->CKTsols[3][i] + + ckt->CKTagp[4]* ckt->CKTsols[4][i] + + ckt->CKTagp[5]* ckt->CKTsols[5][i] ; + } + break; + case 6: + for(i=0;i<=size;i++) { + ckt->CKTpred[i]=ckt->CKTrhs[i] = + ckt->CKTagp[0]* ckt->CKTsols[0][i] + + ckt->CKTagp[1]* ckt->CKTsols[1][i] + + ckt->CKTagp[2]* ckt->CKTsols[2][i] + + ckt->CKTagp[3]* ckt->CKTsols[3][i] + + ckt->CKTagp[4]* ckt->CKTsols[4][i] + + ckt->CKTagp[5]* ckt->CKTsols[5][i] + + ckt->CKTagp[6]* ckt->CKTsols[6][i] ; + } + break; + default: + return(E_ORDER); + } + + } + break; + + default: + return(E_METHOD); + } + return(OK); +} +#else +int Dummy_Symbol; +#endif /* PREDICTOR */ diff --git a/src/maths/ni/nipred.h b/src/maths/ni/nipred.h new file mode 100644 index 000000000..96a23bf92 --- /dev/null +++ b/src/maths/ni/nipred.h @@ -0,0 +1,15 @@ +/************* + * Header file for nipred.c + * 1999 E. Rouat + ************/ + +#ifndef NIPRED_H_INCLUDED +#define NIPRED_H_INCLUDED + +#ifdef PREDICTOR + +intNIpred(register CKTcircuit * ckt); + +#endif /* PREDICTOR */ + +#endif diff --git a/src/maths/ni/nipzmeth.c b/src/maths/ni/nipzmeth.c new file mode 100644 index 000000000..ff2482f99 --- /dev/null +++ b/src/maths/ni/nipzmeth.c @@ -0,0 +1,487 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include +#include "pzdefs.h" +#include "complex.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "sperror.h" +#include "nipzmeth.h" + + +#ifdef PZDEBUG +#define DEBUG(N) if (0) +/*if (Debug >= (unsigned) (N)) +static unsigned int Debug = 0; +*/ +#endif + +extern int CKTpzTrapped; +double NIpzK; +int NIpzK_mag; + +int +NIpzSym(PZtrial **set, PZtrial *new) +{ +#ifndef notdef + return NIpzSym2(set, new); +#else + double a, b, c, x0, x1; + double dx0, dx1; + int a_mag, b_mag, c_mag; + + dx0 = set[1]->s.real - set[0]->s.real; + dx1 = set[2]->s.real - set[1]->s.real; + + zaddeq(&a, &a_mag, set[1]->f_def.real, set[1]->mag_def, + -set[0]->f_def.real, set[0]->mag_def); + a /= dx0; + zaddeq(&b, &b_mag, set[2]->f_def.real, set[2]->mag_def, + -set[1]->f_def.real, set[1]->mag_def); + b /= dx1; + zaddeq(&c, &c_mag, b, b_mag, -a, a_mag); + + /* XXX What if c == 0.0 ? */ + + x0 = (set[0]->s.real + set[1]->s.real) / 2.0; + x1 = (set[1]->s.real + set[2]->s.real) / 2.0; + + c /= (x1 - x0); + + new->s.real = - a / c; + c_mag -= a_mag; + + new->s.imag = 0.0; + + while (c_mag > 0) { + new->s.real /= 2.0; + c_mag -= 1; + } + while (c_mag < 0) { + new->s.real *= 2.0; + c_mag += 1; + } + new->s.real += set[0]->s.real; +#endif +} + +int +NIpzComplex(PZtrial **set, PZtrial *new) +{ + return NIpzSym2(set, new); +#ifdef notdef + NIpzMuller(set, new); +#endif +} + +int +NIpzMuller(PZtrial **set, PZtrial *newtry) +{ + SPcomplex A, B, C, D, E; + SPcomplex h0, h1; + SPcomplex lambda_i, delta_i; + double scale[3]; + double q; + int mag[3], magx, min; + int i, j , total; + + min = -999999; + j = 0; + total = 0; + for (i = 0; i < 3; i++) { + if (set[i]->f_def.real != 0.0 || set[i]->f_def.imag != 0.0) { + if (min < set[i]->mag_def - 50) + min = set[i]->mag_def - 50; + total += set[i]->mag_def; + j += 1; + } + } + + magx = total / j; + if (magx < min) + magx = min; + +#ifdef PZDEBUG + DEBUG(2) fprintf(stderr, "Base scale: %d / %d (0: %d, 1: %d, 2: %d)\n", + magx, min, set[0]->mag_def, set[1]->mag_def, set[2]->mag_def); +#endif + + for (i = 0; i < 3; i++) { + mag[i] = set[i]->mag_def - magx; + scale[i] = 1.0; + while (mag[i] > 0) { + scale[i] *= 2.0; + mag[i] -= 1; + } + if (mag[i] < -90) + scale[i] = 0.0; + else { + while (mag[i] < 0) { + scale[i] /= 2.0; + mag[i] += 1; + } + } + } + + C_SUBEQ(h0,set[0]->s,set[1]->s); + C_SUBEQ(h1,set[1]->s,set[2]->s); + C_DIVEQ(lambda_i,h0,h1); + + /* Quadratic interpolation (Muller's method) */ + + C_EQ(delta_i,lambda_i); + delta_i.real += 1.0; + + /* Quadratic coefficients A, B, C (Note: reciprocal form of eqn) */ + + /* A = lambda_i * (f[i-2] * lambda_i - f[i-1] * delta_i + f[i]) */ + C_MULEQ(A,scale[2] * set[2]->f_def,lambda_i); + C_MULEQ(C,scale[1] * set[1]->f_def,delta_i); + C_SUB(A,C); + C_ADD(A,scale[0] * set[0]->f_def); + C_MUL(A,lambda_i); + + /* B = f[i-2] * lambda_i * lambda_1 - f[i-1] * delta_i * delta_i + + f[i] * (lambda_i + delta_i) */ + C_MULEQ(B,lambda_i,lambda_i); + C_MUL(B,scale[2] * set[2]->f_def); + C_MULEQ(C,delta_i,delta_i); + C_MUL(C,scale[1] * set[1]->f_def); + C_SUB(B,C); + C_ADDEQ(C,lambda_i,delta_i); + C_MUL(C,scale[0] * set[0]->f_def); + C_ADD(B,C); + + /* C = delta_i * f[i] */ + C_MULEQ(C,delta_i,scale[0] * set[0]->f_def); + + while (fabs(A.real) > 1.0 || fabs(A.imag) > 1.0 + || fabs(B.real) > 1.0 || fabs(B.imag) > 1.0 + || fabs(C.real) > 1.0 || fabs(C.imag) > 1.0) { + A.real /= 2.0; + B.real /= 2.0; + C.real /= 2.0; + A.imag /= 2.0; + B.imag /= 2.0; + C.imag /= 2.0; + } + + /* discriminate = B * B - 4 * A * C */ + C_MULEQ(D,B,B); + C_MULEQ(E,4.0 * A,C); + C_SUB(D,E); + +#ifdef PZDEBUG + DEBUG(2) fprintf(stderr, " Discr: (%g,%g)\n",D.real, D.imag); +#endif + C_SQRT(D); +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, " sqrtDiscr: (%g,%g)\n",D.real, D.imag); +#endif + +#ifndef notdef + /* Maximize denominator */ + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, " B: (%g,%g)\n",B.real, B.imag); +#endif + /* Dot product */ + q = B.real * D.real + B.imag * D.imag; + if (q > 0.0) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, " add\n"); +#endif + C_ADD(B,D); + } else { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, " sub\n"); +#endif + C_SUB(B,D); + } + +#else + /* For trapped zeros, the step should always be positive */ + if (C.real >= 0.0) { + if (B.real < D.real) { + C_SUB(B,D); + } else { + C_ADD(B,D); + } + } else { + if (B.real > D.real) { + C_SUB(B,D); + } else { + C_ADD(B,D); + } + } +#endif + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, " C: (%g,%g)\n", C.real, C.imag); +#endif + C_DIV(C,-0.5 * B); + + newtry->next = NULL; + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, " lambda: (%g,%g)\n",C.real, C.imag); +#endif + C_MULEQ(newtry->s,h0,C); + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, " h: (%g,%g)\n", newtry->s.real, newtry->s.imag); +#endif + + C_ADD(newtry->s,set[0]->s); + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "New try: (%g,%g)\n", + newtry->s.real, newtry->s.imag); +#endif + + return OK; + +} + + +int +NIpzSym2(PZtrial **set, PZtrial *new) +{ + double a, b, c, x0, x1; + double dx0, dx1, d2x, diff; + double disc; + int a_mag, b_mag, c_mag; + int tmag; + int error; + int disc_mag; + int new_mag; + + error = OK; + + /* + NIpzK = 0.0; + NIpzK_mag = 0; + */ + + /* Solve for X = the distance from set[1], where X > 0 => root < set[1] */ + dx0 = set[1]->s.real - set[0]->s.real; + dx1 = set[2]->s.real - set[1]->s.real; + + x0 = (set[0]->s.real + set[1]->s.real) / 2.0; + x1 = (set[1]->s.real + set[2]->s.real) / 2.0; + /* d2x = x1 - x0; */ + d2x = (set[2]->s.real - set[0]->s.real) / 2.0; + + zaddeq(&a, &a_mag, set[1]->f_def.real, set[1]->mag_def, + -set[0]->f_def.real, set[0]->mag_def); + + tmag = 0; + R_NORM(dx0,tmag); + a /= dx0; + a_mag -= tmag; + R_NORM(a,a_mag); + + zaddeq(&b, &b_mag, set[2]->f_def.real, set[2]->mag_def, + -set[1]->f_def.real, set[1]->mag_def); + + tmag = 0; + R_NORM(dx1,tmag); + b /= dx1; + b_mag -= tmag; + R_NORM(b,b_mag); + + zaddeq(&c, &c_mag, b, b_mag, -a, a_mag); + + tmag = 0; + R_NORM(d2x,tmag); + c /= d2x; /* = f'' */ + c_mag -= tmag; + R_NORM(c,c_mag); + + if (c == 0.0 || ((a == 0.0 || c_mag < a_mag - 40) + && (b = 0.0 ||c_mag < b_mag - 40))) { + /*fprintf(stderr, "\t- linear (%g, %d)\n", c, c_mag);*/ + if (a == 0.0) { + a = b; + a_mag = b_mag; + } + if (a != 0.0) { + new->s.real = - set[1]->f_def.real / a; + a_mag -= set[1]->mag_def; + while (a_mag > 0) { + new->s.real /= 2.0; + a_mag -= 1; + } + while (a_mag < 0) { + new->s.real *= 2.0; + a_mag += 1; + } + new->s.real += set[1]->s.real; + } else + new->s.real = set[1]->s.real; + } else { + + /* Quadratic power series about set[1]->s.real */ + /* c : d2f/dx2 @ s1 (assumed constant for all s), or "2A" */ + + /* a : (df/dx) / (d2f/dx2) @ s1, or "B/2A" */ + a /= c; + R_NORM(a,a_mag); + a_mag -= c_mag; + + diff = set[1]->s.real - x0; + tmag = 0; + R_NORM(diff,tmag); + + zaddeq(&a, &a_mag, a, a_mag, diff, tmag); + + /* b : f(s1) / (1/2 d2f/ds2), or "C / A" */ + b = 2.0 * set[1]->f_def.real / c; + b_mag = set[1]->mag_def - c_mag; + R_NORM(b,b_mag); + + disc = a * a; + disc_mag = 2 * a_mag; + + /* disc = a^2 - b :: (B/2A)^2 - C/A */ + zaddeq(&disc, &disc_mag, disc, disc_mag, - b, b_mag); + + if (disc < 0.0) { + /* Look for minima instead, but save radical for later work */ + disc *= -1; + new_mag = 1; + } + + if (disc_mag % 2 == 0) + disc = sqrt(disc); + else { + disc = sqrt(2.0 * disc); + disc_mag -= 1; + } + disc_mag /= 2; + + if (new_mag != 0) { + if (NIpzK == 0.0) { + NIpzK = disc; + NIpzK_mag = disc_mag; +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "New NIpzK: %g*2^%d\n", + NIpzK, NIpzK_mag); +#endif + } else { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, + "Ignore NIpzK: %g*2^%d for previous value of %g*2^%d\n", + disc, disc_mag, + NIpzK, NIpzK_mag); +#endif + } + disc = 0.0; + disc_mag = 0; + } + + /* NOTE: c & b get reused here-after */ + + if (a * disc >= 0.0) { + zaddeq(&c, &c_mag, a, a_mag, disc, disc_mag); + } else { + zaddeq(&c, &c_mag, a, a_mag, -disc, disc_mag); + } + + /* second root = C / (first root) */ + if (c != 0.0) { + b /= c; + b_mag -= c_mag; + } else { + /* special case */ + b = 0.0; + b = 0; + } + + zaddeq(&b, &b_mag, set[1]->s.real, 0, -b, b_mag); + zaddeq(&c, &c_mag, set[1]->s.real, 0, -c, c_mag); + + while (b_mag > 0) { + b *= 2.0; + b_mag -= 1; + } + while (b_mag < 0) { + b /= 2.0; + b_mag += 1; + } + + while (c_mag > 0) { + c *= 2.0; + c_mag -= 1; + } + while (c_mag < 0) { + c /= 2.0; + c_mag += 1; + } + +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ (%.15g) -vs- (%.15g)\n", b, c); +#endif + /* XXXX */ + if (b < set[0]->s.real || b > set[2]->s.real) { + /* b not in range */ + if (c < set[0]->s.real || c > set[2]->s.real) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ both are junk\n"); +#endif + if (CKTpzTrapped == 1) + new->s.real = (set[0]->s.real + set[1]->s.real) / 2.0; + else if (CKTpzTrapped == 2) + new->s.real = (set[1]->s.real + set[2]->s.real) / 2.0; + else if (CKTpzTrapped == 3) { + if (fabs(set[1]->s.real - c) < fabs(set[1]->s.real - b)) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ mix w/second (c)\n"); +#endif + new->s.real = (set[1]->s.real + c) / 2.0; + } else { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ mix w/first (b)\n"); +#endif + new->s.real = (set[1]->s.real + b) / 2.0; + } + } else + ERROR(E_PANIC,"Lost numerical stability"); + } else { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ take second (c)\n"); +#endif + new->s.real = c; + } + } else { + /* b in range */ + if (c < set[0]->s.real || c > set[2]->s.real) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ take first (b)\n"); +#endif + new->s.real = b; + } else { + /* Both in range -- take the smallest mag */ + if (a > 0.0) { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ push -- first (b)\n"); +#endif + new->s.real = b; + } else { +#ifdef PZDEBUG + DEBUG(1) fprintf(stderr, "@@@ push -- first (b)\n"); +#endif + new->s.real = c; + } + } + } + + } + + new->s.imag = 0.0; + + return error; +} diff --git a/src/maths/ni/nipzmeth.h b/src/maths/ni/nipzmeth.h new file mode 100644 index 000000000..ccdf40982 --- /dev/null +++ b/src/maths/ni/nipzmeth.h @@ -0,0 +1,14 @@ +/************* + * Header file for nipzmeth.c + * 1999 E. Rouat + ************/ + +#ifndef NIPZMETH_H_INCLUDED +#define NIPZMETH_H_INCLUDED + +int NIpzSym(PZtrial **set, PZtrial *new); +int NIpzComplex(PZtrial **set, PZtrial *new); +int NIpzMuller(PZtrial **set, PZtrial *newtry); +int NIpzSym2(PZtrial **set, PZtrial *new); + +#endif diff --git a/src/maths/ni/nireinit.c b/src/maths/ni/nireinit.c new file mode 100644 index 000000000..8b50e1bb7 --- /dev/null +++ b/src/maths/ni/nireinit.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* NIreinit(ckt) + * Perform reinitialization necessary for the numerical iteration + * package - the matrix has now been fully accessed once, so we know + * how big it is, so allocate RHS vector + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include +#include "smpdefs.h" +#include "sperror.h" +#include "nireinit.h" + + +#define CKALLOC(ptr,size,type) if(( ckt->ptr =\ + (type *) MALLOC((size)*sizeof(type))) == NULL) return(E_NOMEM); + +int +NIreinit(register CKTcircuit *ckt) +{ + register int size; + + size = SMPmatSize(ckt->CKTmatrix); + CKALLOC(CKTrhs,size+1,double); + CKALLOC(CKTrhsOld,size+1,double); + CKALLOC(CKTrhsSpare,size+1,double); + CKALLOC(CKTirhs,size+1,double); + CKALLOC(CKTirhsOld,size+1,double); + CKALLOC(CKTirhsSpare,size+1,double); +#ifdef PREDICTOR + CKALLOC(CKTpred,size+1,double); + for(i=0;i<8;i++) { + CKALLOC(CKTsols[i],size+1,double); + } +#endif /* PREDICTOR */ + ckt->CKTniState = NISHOULDREORDER | NIACSHOULDREORDER | NIPZSHOULDREORDER; + return(0); +} diff --git a/src/maths/ni/nireinit.h b/src/maths/ni/nireinit.h new file mode 100644 index 000000000..1827dd4cc --- /dev/null +++ b/src/maths/ni/nireinit.h @@ -0,0 +1,11 @@ +/************* + * Header file for nireinit.c + * 1999 E. Rouat + ************/ + +#ifndef NIREINIT_H_INCLUDED +#define NIREINIT_H_INCLUDED + +int NIreinit(register CKTcircuit *ckt); + +#endif diff --git a/src/maths/ni/nisenre.c b/src/maths/ni/nisenre.c new file mode 100644 index 000000000..fa271fe3d --- /dev/null +++ b/src/maths/ni/nisenre.c @@ -0,0 +1,77 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* NIsenReinit(ckt) + * Perform reinitialization necessary for the numerical iteration + * package - the matrix has now been fully accessed once, so we know + * how big it is, so allocate RHS vector + */ + +#include "ngspice.h" +#include "cktdefs.h" +#include +#include "smpdefs.h" +#include "sperror.h" +#include "nisenre.h" + + +#define CKALLOC(ptr,size,type) if(( ckt->ptr =\ +(type *) MALLOC((size)*sizeof(type))) == NULL) return(E_NOMEM); + +int +NIsenReinit(register CKTcircuit *ckt) +{ + register int size; + int senparms; + int i; + +#ifdef SENSDEBUG + printf("NIsenReinit \n"); + printf("senflag = %d\n",ckt->CKTsenInfo->SENinitflag); + if(ckt->CKTniState & NIUNINITIALIZED) { + printf("circuit uninitialized\n"); + } + else{ + printf("circuit already initialized\n"); + } +#endif /* SENSDEBUG */ + size = SMPmatSize(ckt->CKTmatrix); + if(ckt->CKTsenInfo->SENinitflag){ + if(!(ckt->CKTniState & NIUNINITIALIZED)) { +#ifdef SENSDEBUG + printf("NIsenReinit1\n"); +#endif /* SENSDEBUG */ + if(ckt->CKTrhsOp) FREE(ckt->CKTrhsOp); + if(ckt->CKTsenRhs) FREE(ckt->CKTsenRhs); + if(ckt->CKTseniRhs) FREE(ckt->CKTseniRhs); + } + senparms = ckt->CKTsenInfo->SENparms; +#ifdef SENSDEBUG + printf("NIsenReinit2\n"); +#endif /* SENSDEBUG */ + /* + CKALLOC(CKTsenInfo->SEN_parmVal,senparms+1,double); + */ + ckt->CKTsenInfo->SENsize = size; + CKALLOC(CKTrhsOp,size+1,double); + CKALLOC(CKTsenRhs,size+1,double); + CKALLOC(CKTseniRhs,size+1,double); + CKALLOC(CKTsenInfo->SEN_Sap,size+1,double*); + CKALLOC(CKTsenInfo->SEN_RHS,size+1,double*); + CKALLOC(CKTsenInfo->SEN_iRHS,size+1,double*); + for(i=0;i<=(size);i++){ + CKALLOC(CKTsenInfo->SEN_Sap[i],senparms+1,double); + CKALLOC(CKTsenInfo->SEN_RHS[i],senparms+1,double); + CKALLOC(CKTsenInfo->SEN_iRHS[i],senparms+1,double); + } +#ifdef SENSDEBUG + printf("NIsenReinit3\n"); +#endif /* SENSDEBUG */ + ckt->CKTsenInfo->SENinitflag = OFF; + } + return(0); +} diff --git a/src/maths/ni/nisenre.h b/src/maths/ni/nisenre.h new file mode 100644 index 000000000..9b3d89b78 --- /dev/null +++ b/src/maths/ni/nisenre.h @@ -0,0 +1,11 @@ +/************* + * Header file for nisenre.c + * 1999 E. Rouat + ************/ + +#ifndef NISENRE_H_INCLUDED +#define NISENRE_H_INCLUDED + +int NIsenReinit(register CKTcircuit *ckt); + +#endif diff --git a/src/maths/sparse/ChangeLog b/src/maths/sparse/ChangeLog new file mode 100644 index 000000000..4212a55f5 --- /dev/null +++ b/src/maths/sparse/ChangeLog @@ -0,0 +1,5 @@ +1999-08-28 Emmanuel Rouat + + * spdefs.h: #includes spice.h instead of misc.h + added a few #undefs to avoid redaclarations + diff --git a/src/maths/sparse/Makefile.am b/src/maths/sparse/Makefile.am new file mode 100644 index 000000000..a9fb22371 --- /dev/null +++ b/src/maths/sparse/Makefile.am @@ -0,0 +1,22 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libsparse.a + +libsparse_a_SOURCES = \ + spalloc.c \ + spbuild.c \ + spcombin.c \ + spdefs.h \ + spextra.c \ + spfactor.c \ + spoutput.c \ + spsmp.c \ + spsolve.c \ + sputils.c + + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/maths/sparse/spalloc.c b/src/maths/sparse/spalloc.c new file mode 100644 index 000000000..733a2b3d1 --- /dev/null +++ b/src/maths/sparse/spalloc.c @@ -0,0 +1,952 @@ +/* + * MATRIX ALLOCATION MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the allocation and deallocation routines for the + * sparse matrix routines. + * + * >>> User accessible functions contained in this file: + * spCreate + * spDestroy + * spError + * spWhereSingular + * spGetSize + * spSetReal + * spSetComplex + * spFillinCount + * spElementCount + * spOriginalCount + * + * >>> Other functions contained in this file: + * spcGetElement + * InitializeElementBlocks + * spcGetFillin + * RecordAllocation + * AllocateBlockOfAllocationList + * EnlargeMatrix + * ExpandTranslationArrays + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header$"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" +#ifdef PARALLEL_ARCH +#define COMBINE 1 +#endif /* PARALLEL_ARCH */ + + + + + +/* + * Function declarations + */ + +#ifdef __STDC__ +static void InitializeElementBlocks( MatrixPtr, int, int ); +static void RecordAllocation( MatrixPtr, char* ); +static void AllocateBlockOfAllocationList( MatrixPtr ); +#else /* __STDC__ */ +static void InitializeElementBlocks(); +static void RecordAllocation(); +static void AllocateBlockOfAllocationList(); +#endif /* __STDC__ */ + + + + +/* + * MATRIX ALLOCATION + * + * Allocates and initializes the data structures associated with a matrix. + * + * >>> Returned: + * A pointer to the matrix is returned cast into the form of a pointer to + * a character. This pointer is then passed and used by the other matrix + * routines to refer to a particular matrix. If an error occurs, the NULL + * pointer is returned. + * + * >>> Arguments: + * Size (int) + * Size of matrix or estimate of size of matrix if matrix is EXPANDABLE. + * Complex (int) + * Type of matrix. If Complex is 0 then the matrix is real, otherwise + * the matrix will be complex. Note that if the routines are not set up + * to handle the type of matrix requested, then a spPANIC error will occur. + * Further note that if a matrix will be both real and complex, it must + * be specified here as being complex. + * pError (int *) + * Returns error flag, needed because function spError() will not work + * correctly if spCreate() returns NULL. + * + * >>> Local variables: + * AllocatedSize (int) + * The size of the matrix being allocated. + * Matrix (MatrixPtr) + * A pointer to the matrix frame being created. + * + * >>> Possible errors: + * spNO_MEMORY + * spPANIC + * Error is cleared in this routine. + */ + +char * +spCreate( Size, Complex, pError ) + +int Size, *pError; +BOOLEAN Complex; +{ +register unsigned SizePlusOne; +register MatrixPtr Matrix; +register int I; +int AllocatedSize; + +/* Begin `spCreate'. */ +/* Clear error flag. */ + *pError = spOKAY; + +/* Test for valid size. */ + if ((Size < 0) OR (Size == 0 AND NOT EXPANDABLE)) + { *pError = spPANIC; + return NULL; + } + +/* Test for valid type. */ +#if NOT spCOMPLEX + if (Complex) + { *pError = spPANIC; + return NULL; + } +#endif +#if NOT REAL + if (NOT Complex) + { *pError = spPANIC; + return NULL; + } +#endif + +/* Create Matrix. */ + AllocatedSize = MAX( Size, MINIMUM_ALLOCATED_SIZE ); + SizePlusOne = (unsigned)(AllocatedSize + 1); + + if ((Matrix = ALLOC(struct MatrixFrame, 1)) == NULL) + { *pError = spNO_MEMORY; + return NULL; + } + +/* Initialize matrix */ + Matrix->ID = SPARSE_ID; + Matrix->Complex = Complex; + Matrix->PreviousMatrixWasComplex = Complex; + Matrix->Factored = NO; + Matrix->Elements = 0; + Matrix->Error = *pError; + Matrix->Originals = 0; + Matrix->Fillins = 0; + Matrix->Reordered = NO; + Matrix->NeedsOrdering = YES; + Matrix->NumberOfInterchangesIsOdd = NO; + Matrix->Partitioned = NO; + Matrix->RowsLinked = NO; + Matrix->InternalVectorsAllocated = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->Size = Size; + Matrix->AllocatedSize = AllocatedSize; + Matrix->ExtSize = Size; + Matrix->AllocatedExtSize = AllocatedSize; + Matrix->CurrentSize = 0; + Matrix->ExtToIntColMap = NULL; + Matrix->ExtToIntRowMap = NULL; + Matrix->IntToExtColMap = NULL; + Matrix->IntToExtRowMap = NULL; + Matrix->MarkowitzRow = NULL; + Matrix->MarkowitzCol = NULL; + Matrix->MarkowitzProd = NULL; + Matrix->DoCmplxDirect = NULL; + Matrix->DoRealDirect = NULL; + Matrix->Intermediate = NULL; + Matrix->RelThreshold = DEFAULT_THRESHOLD; + Matrix->AbsThreshold = 0.0; + + Matrix->TopOfAllocationList = NULL; + Matrix->RecordsRemaining = 0; + Matrix->ElementsRemaining = 0; + Matrix->FillinsRemaining = 0; + + RecordAllocation( Matrix, (char *)Matrix ); + if (Matrix->Error == spNO_MEMORY) goto MemoryError; + +/* Take out the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + Matrix->TrashCan.Row = 0; + Matrix->TrashCan.Col = 0; + Matrix->TrashCan.NextInRow = NULL; + Matrix->TrashCan.NextInCol = NULL; +#if INITIALIZE + Matrix->TrashCan.pInitInfo = NULL; +#endif + +/* Allocate space in memory for Diag pointer vector. */ + CALLOC( Matrix->Diag, ElementPtr, SizePlusOne); + if (Matrix->Diag == NULL) + goto MemoryError; + +/* Allocate space in memory for FirstInCol pointer vector. */ + CALLOC( Matrix->FirstInCol, ElementPtr, SizePlusOne); + if (Matrix->FirstInCol == NULL) + goto MemoryError; + +/* Allocate space in memory for FirstInRow pointer vector. */ + CALLOC( Matrix->FirstInRow, ElementPtr, SizePlusOne); + if (Matrix->FirstInRow == NULL) + goto MemoryError; + +/* Allocate space in memory for IntToExtColMap vector. */ + if (( Matrix->IntToExtColMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Allocate space in memory for IntToExtRowMap vector. */ + if (( Matrix->IntToExtRowMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Initialize MapIntToExt vectors. */ + for (I = 1; I <= AllocatedSize; I++) + { Matrix->IntToExtRowMap[I] = I; + Matrix->IntToExtColMap[I] = I; + } + +#if TRANSLATE +/* Allocate space in memory for ExtToIntColMap vector. */ + if (( Matrix->ExtToIntColMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Allocate space in memory for ExtToIntRowMap vector. */ + if (( Matrix->ExtToIntRowMap = ALLOC(int, SizePlusOne)) == NULL) + goto MemoryError; + +/* Initialize MapExtToInt vectors. */ + for (I = 1; I <= AllocatedSize; I++) + { Matrix->ExtToIntColMap[I] = -1; + Matrix->ExtToIntRowMap[I] = -1; + } + Matrix->ExtToIntColMap[0] = 0; + Matrix->ExtToIntRowMap[0] = 0; +#endif + +/* Allocate space for fill-ins and initial set of elements. */ + InitializeElementBlocks( Matrix, SPACE_FOR_ELEMENTS*AllocatedSize, + SPACE_FOR_FILL_INS*AllocatedSize ); + if (Matrix->Error == spNO_MEMORY) + goto MemoryError; + + return (char *)Matrix; + +MemoryError: + +/* Deallocate matrix and return no pointer to matrix if there is not enough + memory. */ + *pError = spNO_MEMORY; + spDestroy( (char *)Matrix); + return NULL; +} + + + + + + + + + +/* + * ELEMENT ALLOCATION + * + * This routine allocates space for matrix elements. It requests large blocks + * of storage from the system and doles out individual elements as required. + * This technique, as opposed to allocating elements individually, tends to + * speed the allocation process. + * + * >>> Returned: + * A pointer to an element. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the first element in the group of elements being allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcGetElement( Matrix ) + +MatrixPtr Matrix; +{ +ElementPtr pElements; + +/* Begin `spcGetElement'. */ + +#if NOT COMBINE OR STRIP OR LINT +/* Allocate block of MatrixElements if necessary. */ + if (Matrix->ElementsRemaining == 0) + { pElements = ALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); + RecordAllocation( Matrix, (char *)pElements ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->ElementsRemaining = ELEMENTS_PER_ALLOCATION; + Matrix->NextAvailElement = pElements; + } +#endif + +#if COMBINE OR STRIP OR LINT + if (Matrix->ElementsRemaining == 0) + { pListNode = Matrix->LastElementListNode; + +/* First see if there are any stripped elements left. */ + if (pListNode->Next != NULL) + { Matrix->LastElementListNode = pListNode = pListNode->Next; + Matrix->ElementsRemaining = pListNode->NumberOfElementsInList; + Matrix->NextAvailElement = pListNode->pElementList; + } + else + { +/* Allocate block of elements. */ + pElements = ALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); + RecordAllocation( Matrix, (char *)pElements ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->ElementsRemaining = ELEMENTS_PER_ALLOCATION; + Matrix->NextAvailElement = pElements; + +/* Allocate an element list structure. */ + pListNode->Next = ALLOC(struct ElementListNodeStruct,1); + RecordAllocation( Matrix, (char *)pListNode->Next ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->LastElementListNode = pListNode = pListNode->Next; + + pListNode->pElementList = pElements; + pListNode->NumberOfElementsInList = ELEMENTS_PER_ALLOCATION; + pListNode->Next = NULL; + } + } +#endif + +/* Update Element counter and return pointer to Element. */ + Matrix->ElementsRemaining--; + return Matrix->NextAvailElement++; + +} + + + + + + + + +/* + * ELEMENT ALLOCATION INITIALIZATION + * + * This routine allocates space for matrix fill-ins and an initial set of + * elements. Besides being faster than allocating space for elements one + * at a time, it tends to keep the fill-ins physically close to the other + * matrix elements in the computer memory. This keeps virtual memory paging + * to a minimum. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * InitialNumberOfElements (int) + * This number is used as the size of the block of memory, in + * MatrixElements, reserved for elements. If more than this number of + * elements are generated, then more space is allocated later. + * NumberOfFillinsExpected (int) + * This number is used as the size of the block of memory, in + * MatrixElements, reserved for fill-ins. If more than this number of + * fill-ins are generated, then more space is allocated, but they may + * not be physically close in computer's memory. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the first element in the group of elements being allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +InitializeElementBlocks( Matrix, InitialNumberOfElements, + NumberOfFillinsExpected ) + +MatrixPtr Matrix; +int InitialNumberOfElements, NumberOfFillinsExpected; +{ +ElementPtr pElement; + +/* Begin `InitializeElementBlocks'. */ + +/* Allocate block of MatrixElements for elements. */ + pElement = ALLOC(struct MatrixElement, InitialNumberOfElements); + RecordAllocation( Matrix, (char *)pElement ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->ElementsRemaining = InitialNumberOfElements; + Matrix->NextAvailElement = pElement; + +/* Allocate an element list structure. */ + Matrix->FirstElementListNode = ALLOC(struct ElementListNodeStruct,1); + RecordAllocation( Matrix, (char *)Matrix->FirstElementListNode ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->LastElementListNode = Matrix->FirstElementListNode; + + Matrix->FirstElementListNode->pElementList = pElement; + Matrix->FirstElementListNode->NumberOfElementsInList = + InitialNumberOfElements; + Matrix->FirstElementListNode->Next = NULL; + +/* Allocate block of MatrixElements for fill-ins. */ + pElement = ALLOC(struct MatrixElement, NumberOfFillinsExpected); + RecordAllocation( Matrix, (char *)pElement ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->FillinsRemaining = NumberOfFillinsExpected; + Matrix->NextAvailFillin = pElement; + +/* Allocate a fill-in list structure. */ + Matrix->FirstFillinListNode = ALLOC(struct FillinListNodeStruct,1); + RecordAllocation( Matrix, (char *)Matrix->FirstFillinListNode ); + if (Matrix->Error == spNO_MEMORY) return; + Matrix->LastFillinListNode = Matrix->FirstFillinListNode; + + Matrix->FirstFillinListNode->pFillinList = pElement; + Matrix->FirstFillinListNode->NumberOfFillinsInList =NumberOfFillinsExpected; + Matrix->FirstFillinListNode->Next = NULL; + + return; +} + + + + + + + + + + +/* + * FILL-IN ALLOCATION + * + * This routine allocates space for matrix fill-ins. It requests large blocks + * of storage from the system and doles out individual elements as required. + * This technique, as opposed to allocating elements individually, tends to + * speed the allocation process. + * + * >>> Returned: + * A pointer to the fill-in. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcGetFillin( Matrix ) + +MatrixPtr Matrix; +{ +/* Begin `spcGetFillin'. */ + +#if NOT STRIP OR LINT + if (Matrix->FillinsRemaining == 0) + return spcGetElement( Matrix ); +#endif +#if STRIP OR LINT + + if (Matrix->FillinsRemaining == 0) + { pListNode = Matrix->LastFillinListNode; + +/* First see if there are any stripped fill-ins left. */ + if (pListNode->Next != NULL) + { Matrix->LastFillinListNode = pListNode = pListNode->Next; + Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; + Matrix->NextAvailFillin = pListNode->pFillinList; + } + else + { +/* Allocate block of fill-ins. */ + pFillins = ALLOC(struct MatrixElement, ELEMENTS_PER_ALLOCATION); + RecordAllocation( Matrix, (char *)pFillins ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->FillinsRemaining = ELEMENTS_PER_ALLOCATION; + Matrix->NextAvailFillin = pFillins; + +/* Allocate a fill-in list structure. */ + pListNode->Next = ALLOC(struct FillinListNodeStruct,1); + RecordAllocation( Matrix, (char *)pListNode->Next ); + if (Matrix->Error == spNO_MEMORY) return NULL; + Matrix->LastFillinListNode = pListNode = pListNode->Next; + + pListNode->pFillinList = pFillins; + pListNode->NumberOfFillinsInList = ELEMENTS_PER_ALLOCATION; + pListNode->Next = NULL; + } + } +#endif + +/* Update Fill-in counter and return pointer to Fill-in. */ + Matrix->FillinsRemaining--; + return Matrix->NextAvailFillin++; +} + + + + + + + + + +/* + * RECORD A MEMORY ALLOCATION + * + * This routine is used to record all memory allocations so that the memory + * can be freed later. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * AllocatedPtr (char *) + * The pointer returned by malloc or calloc. These pointers are saved in + * a list so that they can be easily freed. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +RecordAllocation( Matrix, AllocatedPtr ) + +MatrixPtr Matrix; +char *AllocatedPtr; +{ +/* Begin `RecordAllocation'. */ +/* + * If Allocated pointer is NULL, assume that malloc returned a NULL pointer, + * which indicates a spNO_MEMORY error. + */ + if (AllocatedPtr == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* Allocate block of MatrixElements if necessary. */ + if (Matrix->RecordsRemaining == 0) + { AllocateBlockOfAllocationList( Matrix ); + if (Matrix->Error == spNO_MEMORY) + { FREE(AllocatedPtr); + return; + } + } + +/* Add Allocated pointer to Allocation List. */ + (++Matrix->TopOfAllocationList)->AllocatedPtr = AllocatedPtr; + Matrix->RecordsRemaining--; + return; + +} + + + + + + + + +/* + * ADD A BLOCK OF SLOTS TO ALLOCATION LIST + * + * This routine increases the size of the allocation list. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * + * >>> Local variables: + * ListPtr (AllocationListPtr) + * Pointer to the list that contains the pointers to segments of memory + * that were allocated by the operating system for the current matrix. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +AllocateBlockOfAllocationList( Matrix ) + +MatrixPtr Matrix; +{ +register int I; +register AllocationListPtr ListPtr; + +/* Begin `AllocateBlockOfAllocationList'. */ +/* Allocate block of records for allocation list. */ + ListPtr = ALLOC(struct AllocationRecord, (ELEMENTS_PER_ALLOCATION+1)); + if (ListPtr == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* String entries of allocation list into singly linked list. List is linked + such that any record points to the one before it. */ + + ListPtr->NextRecord = Matrix->TopOfAllocationList; + Matrix->TopOfAllocationList = ListPtr; + ListPtr += ELEMENTS_PER_ALLOCATION; + for (I = ELEMENTS_PER_ALLOCATION; I > 0; I--) + { ListPtr->NextRecord = ListPtr - 1; + ListPtr--; + } + +/* Record allocation of space for allocation list on allocation list. */ + Matrix->TopOfAllocationList->AllocatedPtr = (char *)ListPtr; + Matrix->RecordsRemaining = ELEMENTS_PER_ALLOCATION; + + return; +} + + + + + + + + +/* + * MATRIX DEALLOCATION + * + * Deallocates pointers and elements of Matrix. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix frame which is to be removed from memory. + * + * >>> Local variables: + * ListPtr (AllocationListPtr) + * Pointer into the linked list of pointers to allocated data structures. + * Points to pointer to structure to be freed. + * NextListPtr (AllocationListPtr) + * Pointer into the linked list of pointers to allocated data structures. + * Points to the next pointer to structure to be freed. This is needed + * because the data structure to be freed could include the current node + * in the allocation list. + */ + +void +spDestroy( eMatrix ) + +register char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register AllocationListPtr ListPtr, NextListPtr; + + +/* Begin `spDestroy'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Deallocate the vectors that are located in the matrix frame. */ + FREE( Matrix->IntToExtColMap ); + FREE( Matrix->IntToExtRowMap ); + FREE( Matrix->ExtToIntColMap ); + FREE( Matrix->ExtToIntRowMap ); + FREE( Matrix->Diag ); + FREE( Matrix->FirstInRow ); + FREE( Matrix->FirstInCol ); + FREE( Matrix->MarkowitzRow ); + FREE( Matrix->MarkowitzCol ); + FREE( Matrix->MarkowitzProd ); + FREE( Matrix->DoCmplxDirect ); + FREE( Matrix->DoRealDirect ); + FREE( Matrix->Intermediate ); + +/* Sequentially step through the list of allocated pointers freeing pointers + * along the way. */ + ListPtr = Matrix->TopOfAllocationList; + while (ListPtr != NULL) + { NextListPtr = ListPtr->NextRecord; + if ((char *) ListPtr == ListPtr->AllocatedPtr) + { + FREE( ListPtr ); + } + else + { + FREE( ListPtr->AllocatedPtr ); + } + ListPtr = NextListPtr; + } + return; +} + + + + + + + +/* + * RETURN MATRIX ERROR STATUS + * + * This function is used to determine the error status of the given matrix. + * + * >>> Returned: + * The error status of the given matrix. + * + * >>> Arguments: + * eMatrix (char *) + * The matrix for which the error status is desired. + */ + +int +spError( eMatrix ) + +char *eMatrix; +{ +/* Begin `spError'. */ + + if (eMatrix != NULL) + { ASSERT(((MatrixPtr)eMatrix)->ID == SPARSE_ID); + return ((MatrixPtr)eMatrix)->Error; + } + else return spNO_MEMORY; /* This error may actually be spPANIC, + * no way to tell. */ +} + + + + + + + + + +/* + * WHERE IS MATRIX SINGULAR + * + * This function returns the row and column number where the matrix was + * detected as singular or where a zero was detected on the diagonal. + * + * >>> Arguments: + * eMatrix (char *) + * The matrix for which the error status is desired. + * pRow (int *) + * The row number. + * pCol (int *) + * The column number. + */ + +void +spWhereSingular( eMatrix, pRow, pCol ) + +char *eMatrix; +int *pRow, *pCol; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; + +/* Begin `spWhereSingular'. */ + ASSERT( IS_SPARSE( Matrix ) ); + + if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG) + { *pRow = Matrix->SingularRow; + *pCol = Matrix->SingularCol; + } + else *pRow = *pCol = 0; + return; +} + + + + + + +/* + * MATRIX SIZE + * + * Returns the size of the matrix. Either the internal or external size of + * the matrix is returned. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to matrix. + * External (BOOLEAN) + * If External is set TRUE, the external size , i.e., the value of the + * largest external row or column number encountered is returned. + * Otherwise the TRUE size of the matrix is returned. These two sizes + * may differ if the TRANSLATE option is set TRUE. + */ + +int +spGetSize( eMatrix, External ) + +char *eMatrix; +BOOLEAN External; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; + +/* Begin `spGetSize'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +#if TRANSLATE + if (External) + return Matrix->ExtSize; + else + return Matrix->Size; +#else + return Matrix->Size; +#endif +} + + + + + + + + +/* + * SET MATRIX COMPLEX OR REAL + * + * Forces matrix to be either real or complex. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to matrix. + */ + +void +spSetReal( eMatrix ) + +char *eMatrix; +{ +/* Begin `spSetReal'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) AND REAL); + ((MatrixPtr)eMatrix)->Complex = NO; + return; +} + + +void +spSetComplex( eMatrix ) + +char *eMatrix; +{ +/* Begin `spSetComplex'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) AND spCOMPLEX); + ((MatrixPtr)eMatrix)->Complex = YES; + return; +} + + + + + + + + + +/* + * ELEMENT, FILL-IN OR ORIGINAL COUNT + * + * Two functions used to return simple statistics. Either the number + * of total elements, or the number of fill-ins, or the number + * of original elements can be returned. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to matrix. + */ + +int +spFillinCount( eMatrix ) + +char *eMatrix; +{ +/* Begin `spFillinCount'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) ); + return ((MatrixPtr)eMatrix)->Fillins; +} + + +int +spElementCount( eMatrix ) + +char *eMatrix; +{ +/* Begin `spElementCount'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) ); + return ((MatrixPtr)eMatrix)->Elements; +} + +int +spOriginalCount( eMatrix ) + +char *eMatrix; +{ +/* Begin `spOriginalCount'. */ + + ASSERT( IS_SPARSE( (MatrixPtr)eMatrix ) ); + return ((MatrixPtr)eMatrix)->Originals; +} diff --git a/src/maths/sparse/spbuild.c b/src/maths/sparse/spbuild.c new file mode 100644 index 000000000..b4d404dc4 --- /dev/null +++ b/src/maths/sparse/spbuild.c @@ -0,0 +1,1189 @@ +/* + * MATRIX BUILD MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the routines associated with clearing, loading and + * preprocessing the matrix for the sparse matrix routines. + * + * >>> User accessible functions contained in this file: + * spClear + * spGetElement + * spGetAdmittance + * spGetQuad + * spGetOnes + * spInstallInitInfo + * spGetInitInfo + * spInitialize + * + * >>> Other functions contained in this file: + * spcFindElementInCol + * Translate + * spcCreateElement + * spcLinkRows + * EnlargeMatrix + * ExpandTranslationArrays + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header$"; +#endif + + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" + + + + + +/* + * Function declarations + */ + +#ifdef __STDC__ +static void Translate( MatrixPtr, int*, int* ); +static void EnlargeMatrix( MatrixPtr, int ); +static void ExpandTranslationArrays( MatrixPtr, int ); +#else /* __STDC__ */ +static void Translate(); +static void EnlargeMatrix(); +static void ExpandTranslationArrays(); +#endif /* __STDC__ */ + + + + + + +/* + * CLEAR MATRIX + * + * Sets every element of the matrix to zero and clears the error flag. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix that is to be cleared. + * + * >>> Local variables: + * pElement (ElementPtr) + * A pointer to the element being cleared. + */ + +void +spClear( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I; + +/* Begin `spClear'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Clear matrix. */ +#if spCOMPLEX + if (Matrix->PreviousMatrixWasComplex OR Matrix->Complex) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { pElement->Real = 0.0; + pElement->Imag = 0.0; + pElement = pElement->NextInCol; + } + } + } + else +#endif + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { pElement->Real = 0.0; + pElement = pElement->NextInCol; + } + } + } + +/* Empty the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + + Matrix->Error = spOKAY; + Matrix->Factored = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->PreviousMatrixWasComplex = Matrix->Complex; + return; +} + + + + + + + + + + + +/* + * SINGLE ELEMENT ADDITION TO MATRIX BY INDEX + * + * Finds element [Row,Col] and returns a pointer to it. If element is + * not found then it is created and spliced into matrix. This routine + * is only to be used after spCreate() and before spMNA_Preorder(), + * spFactor() or spOrderAndFactor(). Returns a pointer to the + * Real portion of a MatrixElement. This pointer is later used by + * spADD_xxx_ELEMENT to directly access element. + * + * >>> Returns: + * Returns a pointer to the element. This pointer is then used to directly + * access the element during successive builds. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix that the element is to be added to. + * Row (int) + * Rowstrchr for element. Must be in the range of [0..Size] unless + * the options EXPANDABLE or TRANSLATE are used. Elements placed in + * row zero are discarded. In no case may Row be less than zero. + * Col (int) + * Columnstrchr for element. Must be in the range of [0..Size] unless + * the options EXPANDABLE or TRANSLATE are used. Elements placed in + * column zero are discarded. In no case may Col be less than zero. + * + * >>> Local variables: + * pElement (RealNumber *) + * Pointer to the element. + * + * >>> Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +RealNumber * +spGetElement( eMatrix, Row, Col ) + +char *eMatrix; +int Row, Col; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +RealNumber *pElement; +ElementPtr spcFindElementInCol(); +void Translate(); + +/* Begin `spGetElement'. */ + ASSERT( IS_SPARSE( Matrix ) AND Row >= 0 AND Col >= 0 ); + + if ((Row == 0) OR (Col == 0)) + return &Matrix->TrashCan.Real; + +#if NOT TRANSLATE + ASSERT(Matrix->NeedsOrdering); +#endif + +#if TRANSLATE + Translate( Matrix, &Row, &Col ); + if (Matrix->Error == spNO_MEMORY) return NULL; +#endif + +#if NOT TRANSLATE +#if NOT EXPANDABLE + ASSERT(Row <= Matrix->Size AND Col <= Matrix->Size); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if ((Row > Matrix->Size) OR (Col > Matrix->Size)) + EnlargeMatrix( Matrix, MAX(Row, Col) ); + if (Matrix->Error == spNO_MEMORY) return NULL; +#endif +#endif + +/* + * The condition part of the following if statement tests to see if the + * element resides along the diagonal, if it does then it tests to see + * if the element has been created yet (Diag pointer not NULL). The + * pointer to the element is then assigned to Element after it is cast + * into a pointer to a RealNumber. This casting makes the pointer into + * a pointer to Real. This statement depends on the fact that Real + * is the first record in the MatrixElement structure. + */ + + if ((Row != Col) OR ((pElement = (RealNumber *)Matrix->Diag[Row]) == NULL)) + { +/* + * Element does not exist or does not reside along diagonal. Search + * column for element. As in the if statement above, the pointer to the + * element which is returned by spcFindElementInCol is cast into a + * pointer to Real, a RealNumber. + */ + pElement = (RealNumber*)spcFindElementInCol( Matrix, + &(Matrix->FirstInCol[Col]), + Row, Col, YES ); + } + return pElement; +} + + + + + + + + + + + +/* + * FIND ELEMENT BY SEARCHING COLUMN + * + * Searches column starting at element specified at PtrAddr and finds element + * in Row. If Element does not exists, it is created. The pointer to the + * element is returned. + * + * >>> Returned: + * A pointer to the desired element: + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to Matrix. + * LastAddr (ElementPtr *) + * Address of pointer that initially points to the element in Col at which + * the search is started. The pointer in this location may be changed if + * a fill-in is required in and adjacent element. For this reason it is + * important that LastAddr be the address of a FirstInCol or a NextInCol + * rather than a temporary variable. + * Row (int) + * Row being searched for. + * Col (int) + * Column being searched. + * CreateIfMissing (BOOLEAN) + * Indicates what to do if element is not found, create one or return a + * NULL pointer. + * + * Local variables: + * pElement (ElementPtr) + * Pointer used to search through matrix. + */ + +ElementPtr +spcFindElementInCol( Matrix, LastAddr, Row, Col, CreateIfMissing ) + +MatrixPtr Matrix; +register ElementPtr *LastAddr; +register int Row; +int Col; +BOOLEAN CreateIfMissing; +{ +register ElementPtr pElement; +ElementPtr spcCreateElement(); + +/* Begin `spcFindElementInCol'. */ + pElement = *LastAddr; + +/* Search for element. */ + while (pElement != NULL) + { if (pElement->Row < Row) + { +/* Have not reached element yet. */ + LastAddr = &(pElement->NextInCol); + pElement = pElement->NextInCol; + } + else if (pElement->Row == Row) + { +/* Reached element. */ + return pElement; + } + else break; /* while loop */ + } + +/* Element does not exist and must be created. */ + if (CreateIfMissing) + return spcCreateElement( Matrix, Row, Col, LastAddr, NO ); + else return NULL; +} + + + + + + + + +#if TRANSLATE + +/* + * TRANSLATE EXTERNAL INDICES TO INTERNAL + * + * Convert external row and column numbers to internal row and column numbers. + * Also updates Ext/Int maps. + * + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * Row (int *) + * Upon entry Row is either a external row number or an external node + * number. Upon return, the internal equivalent is supplied. + * Col (int *) + * Upon entry Column is either a external column number or an external node + * number. Upon return, the internal equivalent is supplied. + * + * >>> Local variables: + * ExtCol (int) + * Temporary variable used to hold the external column or node number + * during the external to internal column number translation. + * ExtRow (int) + * Temporary variable used to hold the external row or node number during + * the external to internal row number translation. + * IntCol (int) + * Temporary variable used to hold the internal column or node number + * during the external to internal column number translation. + * IntRow (int) + * Temporary variable used to hold the internal row or node number during + * the external to internal row number translation. + */ + +static void +Translate( Matrix, Row, Col ) + +MatrixPtr Matrix; +int *Row, *Col; +{ +register int IntRow, IntCol, ExtRow, ExtCol; + +/* Begin `Translate'. */ + ExtRow = *Row; + ExtCol = *Col; + +/* Expand translation arrays if necessary. */ + if ((ExtRow > Matrix->AllocatedExtSize) OR + (ExtCol > Matrix->AllocatedExtSize)) + { + ExpandTranslationArrays( Matrix, MAX(ExtRow, ExtCol) ); + if (Matrix->Error == spNO_MEMORY) return; + } + +/* Set ExtSize if necessary. */ + if ((ExtRow > Matrix->ExtSize) OR (ExtCol > Matrix->ExtSize)) + Matrix->ExtSize = MAX(ExtRow, ExtCol); + +/* Translate external row or node number to internal row or node number. */ + if ((IntRow = Matrix->ExtToIntRowMap[ExtRow]) == -1) + { Matrix->ExtToIntRowMap[ExtRow] = ++Matrix->CurrentSize; + Matrix->ExtToIntColMap[ExtRow] = Matrix->CurrentSize; + IntRow = Matrix->CurrentSize; + +#if NOT EXPANDABLE + ASSERT(IntRow <= Matrix->Size); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if (IntRow > Matrix->Size) + EnlargeMatrix( Matrix, IntRow ); + if (Matrix->Error == spNO_MEMORY) return; +#endif + + Matrix->IntToExtRowMap[IntRow] = ExtRow; + Matrix->IntToExtColMap[IntRow] = ExtRow; + } + +/* Translate external column or node number to internal column or node number.*/ + if ((IntCol = Matrix->ExtToIntColMap[ExtCol]) == -1) + { Matrix->ExtToIntRowMap[ExtCol] = ++Matrix->CurrentSize; + Matrix->ExtToIntColMap[ExtCol] = Matrix->CurrentSize; + IntCol = Matrix->CurrentSize; + +#if NOT EXPANDABLE + ASSERT(IntCol <= Matrix->Size); +#endif + +#if EXPANDABLE +/* Re-size Matrix if necessary. */ + if (IntCol > Matrix->Size) + EnlargeMatrix( Matrix, IntCol ); + if (Matrix->Error == spNO_MEMORY) return; +#endif + + Matrix->IntToExtRowMap[IntCol] = ExtCol; + Matrix->IntToExtColMap[IntCol] = ExtCol; + } + + *Row = IntRow; + *Col = IntCol; + return; +} +#endif + + + + + + +#if QUAD_ELEMENT +/* + * ADDITION OF ADMITTANCE TO MATRIX BY INDEX + * + * Performs same function as spGetElement except rather than one + * element, all four Matrix elements for a floating component are + * added. This routine also works if component is grounded. Positive + * elements are placed at [Node1,Node2] and [Node2,Node1]. This + * routine is only to be used after spCreate() and before + * spMNA_Preorder(), spFactor() or spOrderAndFactor(). + * + * >>> Returns: + * Error code. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix that component is to be entered in. + * Node1 (int) + * Row and column indices for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the + * ground node. In no case may Node1 be less than zero. + * Node2 (int) + * Row and column indices for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Node zero is the + * ground node. In no case may Node2 be less than zero. + * Template (struct spTemplate *) + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + * + * Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +int +spGetAdmittance( Matrix, Node1, Node2, Template ) + +char *Matrix; +int Node1, Node2; +struct spTemplate *Template; +{ + +/* Begin `spGetAdmittance'. */ + Template->Element1 = spGetElement(Matrix, Node1, Node1 ); + Template->Element2 = spGetElement(Matrix, Node2, Node2 ); + Template->Element3Negated = spGetElement( Matrix, Node2, Node1 ); + Template->Element4Negated = spGetElement( Matrix, Node1, Node2 ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + if (Node1 == 0) + SWAP( RealNumber*, Template->Element1, Template->Element2 ); + + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + + + +#if QUAD_ELEMENT +/* + * ADDITION OF FOUR ELEMENTS TO MATRIX BY INDEX + * + * Similar to spGetAdmittance, except that spGetAdmittance only + * handles 2-terminal components, whereas spGetQuad handles simple + * 4-terminals as well. These 4-terminals are simply generalized + * 2-terminals with the option of having the sense terminals different + * from the source and sink terminals. spGetQuad adds four + * elements to the matrix. Positive elements occur at Row1,Col1 + * Row2,Col2 while negative elements occur at Row1,Col2 and Row2,Col1. + * The routine works fine if any of the rows and columns are zero. + * This routine is only to be used after spCreate() and before + * spMNA_Preorder(), spFactor() or spOrderAndFactor() + * unless TRANSLATE is set TRUE. + * + * >>> Returns: + * Error code. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix that component is to be entered in. + * Row1 (int) + * First rowstrchr for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Row1 be less than zero. + * Row2 (int) + * Second rowstrchr for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Row2 be less than zero. + * Col1 (int) + * First columnstrchr for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground column. In no case may Col1 be less than zero. + * Col2 (int) + * Second columnstrchr for elements. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground column. In no case may Col2 be less than zero. + * Template (struct spTemplate *) + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + * Real (RealNumber) + * Real data to be added to elements. + * Imag (RealNumber) + * Imag data to be added to elements. If matrix is real, this argument + * may be deleted. + * + * Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +int +spGetQuad( Matrix, Row1, Row2, Col1, Col2, Template ) + +char *Matrix; +int Row1, Row2, Col1, Col2; +struct spTemplate *Template; +{ +/* Begin `spGetQuad'. */ + Template->Element1 = spGetElement( Matrix, Row1, Col1); + Template->Element2 = spGetElement( Matrix, Row2, Col2 ); + Template->Element3Negated = spGetElement( Matrix, Row2, Col1 ); + Template->Element4Negated = spGetElement( Matrix, Row1, Col2 ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + if (Template->Element1 == &((MatrixPtr)Matrix)->TrashCan.Real) + SWAP( RealNumber *, Template->Element1, Template->Element2 ); + + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + + + +#if QUAD_ELEMENT +/* + * ADDITION OF FOUR STRUCTURAL ONES TO MATRIX BY INDEX + * + * Performs similar function to spGetQuad() except this routine is + * meant for components that do not have an admittance representation. + * + * The following stamp is used: + * Pos Neg Eqn + * Pos [ . . 1 ] + * Neg [ . . -1 ] + * Eqn [ 1 -1 . ] + * + * >>> Returns: + * Error code. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix that component is to be entered in. + * Pos (int) + * See stamp above. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Pos be less than zero. + * Neg (int) + * See stamp above. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Neg be less than zero. + * Eqn (int) + * See stamp above. Must be in the range of [0..Size] + * unless the options EXPANDABLE or TRANSLATE are used. Zero is the + * ground row. In no case may Eqn be less than zero. + * Template (struct spTemplate *) + * Collection of pointers to four elements that are later used to directly + * address elements. User must supply the template, this routine will + * fill it. + * + * Possible errors: + * spNO_MEMORY + * Error is not cleared in this routine. + */ + +int +spGetOnes(Matrix, Pos, Neg, Eqn, Template) + +char *Matrix; +int Pos, Neg, Eqn; +struct spTemplate *Template; +{ +/* Begin `spGetOnes'. */ + Template->Element4Negated = spGetElement( Matrix, Neg, Eqn ); + Template->Element3Negated = spGetElement( Matrix, Eqn, Neg ); + Template->Element2 = spGetElement( Matrix, Pos, Eqn ); + Template->Element1 = spGetElement( Matrix, Eqn, Pos ); + if + ( (Template->Element1 == NULL) + OR (Template->Element2 == NULL) + OR (Template->Element3Negated == NULL) + OR (Template->Element4Negated == NULL) + ) return spNO_MEMORY; + + spADD_REAL_QUAD( *Template, 1.0 ); + return spOKAY; +} +#endif /* QUAD_ELEMENT */ + + + + + + + +/* + * + * CREATE AND SPLICE ELEMENT INTO MATRIX + * + * This routine is used to create new matrix elements and splice them into the + * matrix. + * + * >>> Returned: + * A pointer to the element that was created is returned. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Row (int) + * Rowstrchr for element. + * Col (int) + * Columnstrchr for element. + * LastAddr (ElementPtr *) + * This contains the address of the pointer to the element just above the + * one being created. It is used to speed the search and it is updated with + * address of the created element. + * Fillin (BOOLEAN) + * Flag that indicates if created element is to be a fill-in. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. It is used to refer to the newly + * created element and to restring the pointers of the element's row and + * column. + * pLastElement (ElementPtr) + * Pointer to the element in the matrix that was just previously pointed + * to by pElement. It is used to restring the pointers of the element's + * row and column. + * pCreatedElement (ElementPtr) + * Pointer to the desired element, the one that was just created. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +ElementPtr +spcCreateElement( Matrix, Row, Col, LastAddr, Fillin ) + +MatrixPtr Matrix; +int Row; +register int Col; +register ElementPtr *LastAddr; +BOOLEAN Fillin; +{ +register ElementPtr pElement, pLastElement; +ElementPtr pCreatedElement, spcGetElement(), spcGetFillin(); + +/* Begin `spcCreateElement'. */ + + if (Matrix->RowsLinked) + { +/* Row pointers cannot be ignored. */ + if (Fillin) + { pElement = spcGetFillin( Matrix ); + Matrix->Fillins++; + } + else + { pElement = spcGetElement( Matrix ); + Matrix->Originals++; + Matrix->NeedsOrdering = YES; + } + if (pElement == NULL) return NULL; + +/* If element is on diagonal, store pointer in Diag. */ + if (Row == Col) Matrix->Diag[Row] = pElement; + +/* Initialize Element. */ + pCreatedElement = pElement; + pElement->Row = Row; + pElement->Col = Col; + pElement->Real = 0.0; +#if spCOMPLEX + pElement->Imag = 0.0; +#endif +#if INITIALIZE + pElement->pInitInfo = NULL; +#endif + +/* Splice element into column. */ + pElement->NextInCol = *LastAddr; + *LastAddr = pElement; + + /* Search row for proper element position. */ + pElement = Matrix->FirstInRow[Row]; + pLastElement = NULL; + while (pElement != NULL) + { +/* Search for element row position. */ + if (pElement->Col < Col) + { +/* Have not reached desired element. */ + pLastElement = pElement; + pElement = pElement->NextInRow; + } + else pElement = NULL; + } + +/* Splice element into row. */ + pElement = pCreatedElement; + if (pLastElement == NULL) + { +/* Element is first in row. */ + pElement->NextInRow = Matrix->FirstInRow[Row]; + Matrix->FirstInRow[Row] = pElement; + } + else +/* Element is not first in row. */ + { + pElement->NextInRow = pLastElement->NextInRow; + pLastElement->NextInRow = pElement; + } + + } + else + { +/* + * Matrix has not been factored yet. Thus get element rather than fill-in. + * Also, row pointers can be ignored. + */ + +/* Allocate memory for Element. */ + pElement = spcGetElement( Matrix ); + Matrix->Originals++; + if (pElement == NULL) return NULL; + +/* If element is on diagonal, store pointer in Diag. */ + if (Row == Col) Matrix->Diag[Row] = pElement; + +/* Initialize Element. */ + pCreatedElement = pElement; + pElement->Row = Row; +#if DEBUG + pElement->Col = Col; +#endif + pElement->Real = 0.0; +#if spCOMPLEX + pElement->Imag = 0.0; +#endif +#if INITIALIZE + pElement->pInitInfo = NULL; +#endif + +/* Splice element into column. */ + pElement->NextInCol = *LastAddr; + *LastAddr = pElement; + } + + Matrix->Elements++; + return pCreatedElement; +} + + + + + + + + +/* + * + * LINK ROWS + * + * This routine is used to generate the row links. The spGetElement() + * routines do not create row links, which are needed by the spFactor() + * routines. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * FirstInRowEntry (ElementPtr *) + * A pointer into the FirstInRow array. Points to the FirstInRow entry + * currently being operated upon. + * FirstInRowArray (ArrayOfElementPtrs) + * A pointer to the FirstInRow array. Same as Matrix->FirstInRow but + * resides in a register and requires less indirection so is faster to + * use. + * Col (int) + * Column currently being operated upon. + */ + +void +spcLinkRows( Matrix ) + +MatrixPtr Matrix; +{ +register ElementPtr pElement, *FirstInRowEntry; +register ArrayOfElementPtrs FirstInRowArray; +register int Col; + +/* Begin `spcLinkRows'. */ + FirstInRowArray = Matrix->FirstInRow; + for (Col = Matrix->Size; Col >= 1; Col--) + { +/* Generate row links for the elements in the Col'th column. */ + pElement = Matrix->FirstInCol[Col]; + + while (pElement != NULL) + { pElement->Col = Col; + FirstInRowEntry = &FirstInRowArray[pElement->Row]; + pElement->NextInRow = *FirstInRowEntry; + *FirstInRowEntry = pElement; + pElement = pElement->NextInCol; + } + } + Matrix->RowsLinked = YES; + return; +} + + + + + + + + +/* + * ENLARGE MATRIX + * + * Increases the size of the matrix. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * NewSize (int) + * The new size of the matrix. + * + * >>> Local variables: + * OldAllocatedSize (int) + * The allocated size of the matrix before it is expanded. + */ + +static void +EnlargeMatrix( Matrix, NewSize ) + +MatrixPtr Matrix; +register int NewSize; +{ +register int I, OldAllocatedSize = Matrix->AllocatedSize; + +/* Begin `EnlargeMatrix'. */ + Matrix->Size = NewSize; + + if (NewSize <= OldAllocatedSize) + return; + +/* Expand the matrix frame. */ + NewSize = MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize ); + Matrix->AllocatedSize = NewSize; + + if (( REALLOC(Matrix->IntToExtColMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->IntToExtRowMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->Diag, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->FirstInCol, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->FirstInRow, ElementPtr, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* + * Destroy the Markowitz and Intermediate vectors, they will be recreated + * in spOrderAndFactor(). + */ + FREE( Matrix->MarkowitzRow ); + FREE( Matrix->MarkowitzCol ); + FREE( Matrix->MarkowitzProd ); + FREE( Matrix->DoRealDirect ); + FREE( Matrix->DoCmplxDirect ); + FREE( Matrix->Intermediate ); + Matrix->InternalVectorsAllocated = NO; + +/* Initialize the new portion of the vectors. */ + for (I = OldAllocatedSize+1; I <= NewSize; I++) + { Matrix->IntToExtColMap[I] = I; + Matrix->IntToExtRowMap[I] = I; + Matrix->Diag[I] = NULL; + Matrix->FirstInRow[I] = NULL; + Matrix->FirstInCol[I] = NULL; + } + + return; +} + + + + + + + + +#if TRANSLATE + +/* + * EXPAND TRANSLATION ARRAYS + * + * Increases the size arrays that are used to translate external to internal + * row and column numbers. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * NewSize (int) + * The new size of the translation arrays. + * + * >>> Local variables: + * OldAllocatedSize (int) + * The allocated size of the translation arrays before being expanded. + */ + +static void +ExpandTranslationArrays( Matrix, NewSize ) + +MatrixPtr Matrix; +register int NewSize; +{ +register int I, OldAllocatedSize = Matrix->AllocatedExtSize; + +/* Begin `ExpandTranslationArrays'. */ + Matrix->ExtSize = NewSize; + + if (NewSize <= OldAllocatedSize) + return; + +/* Expand the translation arrays ExtToIntRowMap and ExtToIntColMap. */ + NewSize = MAX( NewSize, EXPANSION_FACTOR * OldAllocatedSize ); + Matrix->AllocatedExtSize = NewSize; + + if (( REALLOC(Matrix->ExtToIntRowMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + if (( REALLOC(Matrix->ExtToIntColMap, int, NewSize+1)) == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + +/* Initialize the new portion of the vectors. */ + for (I = OldAllocatedSize+1; I <= NewSize; I++) + { Matrix->ExtToIntRowMap[I] = -1; + Matrix->ExtToIntColMap[I] = -1; + } + + return; +} +#endif + + + + + + + + + +#if INITIALIZE +/* + * INITIALIZE MATRIX + * + * With the INITIALIZE compiler option (see spConfig.h) set TRUE, + * Sparse allows the user to keep initialization information with each + * structurally nonzero matrix element. Each element has a pointer + * that is set and used by the user. The user can set this pointer + * using spInstallInitInfo and may be read using spGetInitInfo. Both + * may be used only after the element exists. The function + * spInitialize() is a user customizable way to initialize the matrix. + * Passed to this routine is a function pointer. spInitialize() sweeps + * through every element in the matrix and checks the pInitInfo + * pointer (the user supplied pointer). If the pInitInfo is NULL, + * which is TRUE unless the user changes it (almost always TRUE for + * fill-ins), then the element is zeroed. Otherwise, the function + * pointer is called and passed the pInitInfo pointer as well as the + * element pointer and the external row and column numbers. If the + * user sets the value of each element, then spInitialize() replaces + * spClear(). + * + * The user function is expected to return a nonzero integer if there + * is a fatal error and zero otherwise. Upon encountering a nonzero + * return code, spInitialize() terminates and returns the error code. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * + * >>> Possible Errors: + * Returns nonzero if error, zero otherwise. + */ + +void +spInstallInitInfo( pElement, pInitInfo ) + +RealNumber *pElement; +char *pInitInfo; +{ +/* Begin `spInstallInitInfo'. */ + ASSERT(pElement != NULL); + + ((ElementPtr)pElement)->pInitInfo = pInitInfo; +} + + +char * +spGetInitInfo( pElement ) + +RealNumber *pElement; +{ +/* Begin `spGetInitInfo'. */ + ASSERT(pElement != NULL); + + return (char *)((ElementPtr)pElement)->pInitInfo; +} + + +int +spInitialize( eMatrix, pInit ) + +char *eMatrix; +int (*pInit)(); +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +int J, Error, Col; + +/* Begin `spInitialize'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +#if spCOMPLEX +/* Clear imaginary part of matrix if matrix is real but was complex. */ + if (Matrix->PreviousMatrixWasComplex AND NOT Matrix->Complex) + { for (J = Matrix->Size; J > 0; J--) + { pElement = Matrix->FirstInCol[J]; + while (pElement != NULL) + { pElement->Imag = 0.0; + pElement = pElement->NextInCol; + } + } + } +#endif /* spCOMPLEX */ + +/* Initialize the matrix. */ + for (J = Matrix->Size; J > 0; J--) + { pElement = Matrix->FirstInCol[J]; + Col = Matrix->IntToExtColMap[J]; + while (pElement != NULL) + { if (pElement->pInitInfo == NULL) + { pElement->Real = 0.0; +# if spCOMPLEX + pElement->Imag = 0.0; +# endif + } + else + { Error = (*pInit)((RealNumber *)pElement, pElement->pInitInfo, + Matrix->IntToExtRowMap[pElement->Row], Col); + if (Error) + { Matrix->Error = spFATAL; + return Error; + } + + } + pElement = pElement->NextInCol; + } + } + +/* Empty the trash. */ + Matrix->TrashCan.Real = 0.0; +#if spCOMPLEX + Matrix->TrashCan.Imag = 0.0; +#endif + + Matrix->Error = spOKAY; + Matrix->Factored = NO; + Matrix->SingularCol = 0; + Matrix->SingularRow = 0; + Matrix->PreviousMatrixWasComplex = Matrix->Complex; + return 0; +} +#endif /* INITIALIZE */ diff --git a/src/maths/sparse/spcombin.c b/src/maths/sparse/spcombin.c new file mode 100644 index 000000000..d262520b1 --- /dev/null +++ b/src/maths/sparse/spcombin.c @@ -0,0 +1,331 @@ +/* + * MATRIX UTILITY MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains various optional utility routines. + * + * >>> User accessible functions contained in this file: + * spCombine + * + * >>> Other functions contained in this file: + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header$"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" + + + + + + +#ifdef PARALLEL_ARCH +#define COMBINE 1 +#endif /* PARALLEL_ARCH */ + + +#if COMBINE +#ifdef __STDC__ +#if spSEPARATED_COMPLEX_VECTORS +static void CombineComplexMatrix( MatrixPtr, + RealVector, RealVector, RealVector, RealVector ); +#else +static void CombineComplexMatrix( MatrixPtr, RealVector, RealVector ); +#endif +static void ClearBuffer( MatrixPtr, int, int, ElementPtr ); +static void ClearComplexBuffer( MatrixPtr, int, int, ElementPtr ); +#else /* __STDC__ */ +static void CombineComplexMatrix(); +static void ClearBuffer(); +static void ClearComplexBuffer(); +#endif /* __STDC__ */ + +/* + * COMBINE MATRICES ON A MULTIPROCESSOR + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix to be combined. + * + * >>> Local variables: + * Size (int) + * Local version of the size of the matrix. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + */ + +#define SPBSIZE 256*1024 +static double Buffer[SPBSIZE]; + +void +spCombine( eMatrix, RHS, Spare IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Spare IMAG_VECTORS; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I, Size; +ElementPtr FirstBufElement, pLastElement; +int FirstBufCol, BufIndex; +struct ElementListNodeStruct *pListNode; +long type = MT_COMBINE, length = Matrix->Size + 1; + +/* Begin `spCombine'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored ); + if (NOT Matrix->InternalVectorsAllocated) + spcCreateInternalVectors( Matrix ); + +#if spCOMPLEX + if (Matrix->Complex) { + CombineComplexMatrix( Matrix, RHS, Spare IMAG_VECTORS ); + return; + } +#endif + +#if REAL + Size = Matrix->Size; + +/* Mark original non-zeroes. */ + pListNode = Matrix->FirstElementListNode; + while (pListNode != NULL) + { pElement = pListNode->pElementList; + if (pListNode == Matrix->LastElementListNode) { + pLastElement = Matrix->NextAvailElement - 1; + } else { + pLastElement = &(pElement[ pListNode->NumberOfElementsInList - 1 ]); + } + while (pElement <= pLastElement) + { + (pElement++)->Col = -1; + } + pListNode = pListNode->Next; + } + +/* Stripmine the communication to reduce overhead */ + BufIndex = 0; + FirstBufCol = 1; + FirstBufElement = Matrix->FirstInCol[ FirstBufCol ]; + for (I = 1; I <= Size; I++) + { + pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { + if ( BufIndex >= SPBSIZE ) + { /* Buffer is Full. */ + ClearBuffer( Matrix, BufIndex, FirstBufCol, FirstBufElement ); + BufIndex = 0; + FirstBufCol = I; + FirstBufElement = pElement; + } + if ( pElement->Col == -1 ) { + Buffer[ BufIndex++ ] = pElement->Real; + } + pElement = pElement->NextInCol; + } + } +/* Clean out the last, partially full buffer. */ + if ( BufIndex != 0 ) + { + ClearBuffer( Matrix, BufIndex, FirstBufCol, FirstBufElement ); + } + +/* Sum all RHS's together */ + DGOP_( &type, RHS, &length, "+" ); + + return; +#endif /* REAL */ +} + +#if spCOMPLEX +static void +CombineComplexMatrix( Matrix, RHS, Spare IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Spare IMAG_VECTORS; +{ +register ElementPtr pElement; +register int I, Size; +ElementPtr FirstBufElement, pLastElement; +int FirstBufCol, BufIndex; +struct ElementListNodeStruct *pListNode; +long type = MT_COMBINE, length = Matrix->Size + 1; + +/* Begin `CombineComplexMatrix'. */ + ASSERT(Matrix->Complex); + Size = Matrix->Size; + +/* Mark original non-zeroes. */ + pListNode = Matrix->FirstElementListNode; + while (pListNode != NULL) + { pElement = pListNode->pElementList; + if (pListNode == Matrix->LastElementListNode) { + pLastElement = Matrix->NextAvailElement - 1; + } else { + pLastElement = &(pElement[ pListNode->NumberOfElementsInList - 1 ]); + } + while (pElement <= pLastElement) + { + (pElement++)->Col = -1; + } + pListNode = pListNode->Next; + } + +/* Stripmine the communication to reduce overhead */ + BufIndex = 0; + FirstBufCol = 1; + FirstBufElement = Matrix->FirstInCol[ FirstBufCol ]; + for (I = 1; I <= Size; I++) + { + pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { + if ( BufIndex >= SPBSIZE/2 ) + { /* Buffer is Full. */ + ClearComplexBuffer( Matrix, BufIndex, FirstBufCol, + FirstBufElement ); + BufIndex = 0; + FirstBufCol = I; + FirstBufElement = pElement; + } + if ( pElement->Col == -1 ) { + Buffer[ BufIndex++ ] = pElement->Real; + Buffer[ BufIndex++ ] = pElement->Imag; + } + pElement = pElement->NextInCol; + } + } +/* Clean out the last, partially full buffer. */ + if ( BufIndex != 0 ) + { + ClearComplexBuffer( Matrix, BufIndex, FirstBufCol, FirstBufElement ); + } + +/* Sum all RHS's together */ +#if spSEPARATED_COMPLEX_VECTORS + DGOP_( &type, RHS, &length, "+" ); + DGOP_( &type, iRHS, &length, "+" ); +#else + length *= 2; + DGOP_( &type, RHS, &length, "+" ); +#endif + + return; +} +#endif /* spCOMPLEX */ + +#if REAL +static void +ClearBuffer( Matrix, NumElems, StartCol, StartElement ) + +MatrixPtr Matrix; +int NumElems, StartCol; +ElementPtr StartElement; +{ + register ElementPtr pElement = StartElement; + register int Index, Col = StartCol; + long type = MT_COMBINE; + +/* First globalize the buffer. */ + DGOP_( &type, Buffer, &NumElems, "+" ); + +/* Now, copy all of the data back into the matrix. */ + for ( Index = 0; Index < NumElems; Index++ ) + { + if ( pElement == NULL ) + { + pElement = Matrix->FirstInCol[ ++Col ]; + } + while ( pElement->Col != -1 ) { + pElement = pElement->NextInCol; + if ( pElement == NULL ) + { + pElement = Matrix->FirstInCol[ ++Col ]; + } + } + pElement->Real = Buffer[ Index ]; + pElement->Col = Col; + pElement = pElement->NextInCol; + } +} +#endif REAL + +#if spCOMPLEX +static void +ClearComplexBuffer( Matrix, DataCount, StartCol, StartElement ) + +MatrixPtr Matrix; +int DataCount, StartCol; +ElementPtr StartElement; +{ + register ElementPtr pElement = StartElement; + register int Index, Col = StartCol; + long type = MT_COMBINE; + +/* First globalize the buffer. */ + DGOP_( &type, Buffer, &DataCount, "+" ); + +/* Now, copy all of the data back into the matrix. */ + for ( Index = 0; Index < DataCount; ) + { + if ( pElement == NULL ) + { + pElement = Matrix->FirstInCol[ ++Col ]; + } + while ( pElement->Col != -1 ) { + pElement = pElement->NextInCol; + if ( pElement == NULL ) + { + pElement = Matrix->FirstInCol[ ++Col ]; + } + } + pElement->Real = Buffer[ Index++ ]; + pElement->Imag = Buffer[ Index++ ]; + pElement->Col = Col; + pElement = pElement->NextInCol; + } +} +#endif /* spCOMPLEX */ +#endif /* COMBINE */ diff --git a/src/maths/sparse/spdefs.h b/src/maths/sparse/spdefs.h new file mode 100644 index 000000000..faefba48a --- /dev/null +++ b/src/maths/sparse/spdefs.h @@ -0,0 +1,906 @@ +/* + * DATA STRUCTURE AND MACRO DEFINITIONS for Sparse. + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains common type definitions and macros for the sparse + * matrix routines. These definitions are of no interest to the user. + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + * + * $Date$ + * $Revision$ + */ + + + + +/* + * IMPORTS + */ + +#include +#include "ngspice.h" + +#undef ABORT +#undef MALLOC +#undef FREE +#undef REALLOC + +/* + * If running lint, change some of the compiler options to get a more + * complete inspection. + */ + +#ifdef lint +#undef REAL +#undef spCOMPLEX +#undef EXPANDABLE +#undef TRANSLATE +#undef INITIALIZE +#undef DELETE +#undef STRIP +#undef MODIFIED_NODAL +#undef QUAD_ELEMENT +#undef TRANSPOSE +#undef SCALING +#undef DOCUMENTATION +#undef MULTIPLICATION +#undef DETERMINANT +#undef CONDITION +#undef PSEUDOCONDITION +#undef FORTRAN +#undef DEBUG +#undef spCOMPATIBILITY + + + +#define REAL YES +#define spCOMPLEX YES +#define EXPANDABLE YES +#define TRANSLATE YES +#define INITIALIZE YES +#define DELETE YES +#define STRIP YES +#define MODIFIED_NODAL YES +#define QUAD_ELEMENT YES +#define TRANSPOSE YES +#define SCALING YES +#define DOCUMENTATION YES +#define MULTIPLICATION YES +#define DETERMINANT YES +#define CONDITION YES +#define PSEUDOCONDITION YES +#define FORTRAN YES +#define DEBUG YES +#define spCOMPATIBILITY YES + +#define LINT YES +#else /* not lint */ +#define LINT NO +#endif /* not lint */ + + + + + + + +/* + * MACRO DEFINITIONS + * + * Macros are distinguished by using solely capital letters in their + * identifiers. This contrasts with C defined identifiers which are strictly + * lower case, and program variable and procedure names which use both upper + * and lower case. + */ + +/* Begin macros. */ + +/* Boolean data type */ +#define BOOLEAN int +#define NO 0 +#define YES 1 +#define NOT ! +#define AND && +#define OR || + +/* NULL pointer */ +#ifndef NULL +#define NULL 0 +#endif + +#define SPARSE_ID 0x772773 /* Arbitrary (is Sparse on phone). */ +#define IS_SPARSE(matrix) ((matrix) != NULL && \ + (matrix)->ID == SPARSE_ID) +#define IS_VALID(matrix) ((matrix) != NULL && \ + (matrix)->ID == SPARSE_ID && \ + (matrix)->Error >= spOKAY && \ + (matrix)->Error < spFATAL) +#define IS_FACTORED(matrix) ((matrix)->Factored && !(matrix)->NeedsOrdering) + +/* Macro commands */ +/* Macro functions that return the maximum or minimum independent of type. */ +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* Macro function that returns the absolute value of a floating point number. */ +#define ABS(a) ((a) < 0 ? -(a) : (a)) + +/* Macro function that returns the square of a number. */ +#define SQR(a) ((a)*(a)) + +/* Macro procedure that swaps two entities. */ +#define SWAP(type, a, b) {type swapx; swapx = a; a = b; b = swapx;} + +/* Macro function that returns the approx absolute value of a complex number. */ +#if spCOMPLEX +#define ELEMENT_MAG(ptr) (ABS((ptr)->Real) + ABS((ptr)->Imag)) +#else +#define ELEMENT_MAG(ptr) ((ptr)->Real < 0.0 ? -(ptr)->Real : (ptr)->Real) +#endif + +/* Complex assignment statements. */ +#define CMPLX_ASSIGN(to,from) \ +{ (to).Real = (from).Real; \ + (to).Imag = (from).Imag; \ +} +#define CMPLX_CONJ_ASSIGN(to,from) \ +{ (to).Real = (from).Real; \ + (to).Imag = -(from).Imag; \ +} +#define CMPLX_NEGATE_ASSIGN(to,from) \ +{ (to).Real = -(from).Real; \ + (to).Imag = -(from).Imag; \ +} +#define CMPLX_CONJ_NEGATE_ASSIGN(to,from) \ +{ (to).Real = -(from).Real; \ + (to).Imag = (from).Imag; \ +} +#define CMPLX_CONJ(a) (a).Imag = -(a).Imag +#define CMPLX_NEGATE(a) \ +{ (a).Real = -(a).Real; \ + (a).Imag = -(a).Imag; \ +} + +/* Macro that returns the approx magnitude (L-1 norm) of a complex number. */ +#define CMPLX_1_NORM(a) (ABS((a).Real) + ABS((a).Imag)) + +/* Macro that returns the approx magnitude (L-infinity norm) of a complex. */ +#define CMPLX_INF_NORM(a) (MAX (ABS((a).Real),ABS((a).Imag))) + +/* Macro function that returns the magnitude (L-2 norm) of a complex number. */ +#define CMPLX_2_NORM(a) (sqrt((a).Real*(a).Real + (a).Imag*(a).Imag)) + +/* Macro function that performs complex addition. */ +#define CMPLX_ADD(to,from_a,from_b) \ +{ (to).Real = (from_a).Real + (from_b).Real; \ + (to).Imag = (from_a).Imag + (from_b).Imag; \ +} + +/* Macro function that performs complex subtraction. */ +#define CMPLX_SUBT(to,from_a,from_b) \ +{ (to).Real = (from_a).Real - (from_b).Real; \ + (to).Imag = (from_a).Imag - (from_b).Imag; \ +} + +/* Macro function that is equivalent to += operator for complex numbers. */ +#define CMPLX_ADD_ASSIGN(to,from) \ +{ (to).Real += (from).Real; \ + (to).Imag += (from).Imag; \ +} + +/* Macro function that is equivalent to -= operator for complex numbers. */ +#define CMPLX_SUBT_ASSIGN(to,from) \ +{ (to).Real -= (from).Real; \ + (to).Imag -= (from).Imag; \ +} + +/* Macro function that multiplies a complex number by a scalar. */ +#define SCLR_MULT(to,sclr,cmplx) \ +{ (to).Real = (sclr) * (cmplx).Real; \ + (to).Imag = (sclr) * (cmplx).Imag; \ +} + +/* Macro function that multiply-assigns a complex number by a scalar. */ +#define SCLR_MULT_ASSIGN(to,sclr) \ +{ (to).Real *= (sclr); \ + (to).Imag *= (sclr); \ +} + +/* Macro function that multiplies two complex numbers. */ +#define CMPLX_MULT(to,from_a,from_b) \ +{ (to).Real = (from_a).Real * (from_b).Real - \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag = (from_a).Real * (from_b).Imag + \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that implements to *= from for complex numbers. */ +#define CMPLX_MULT_ASSIGN(to,from) \ +{ RealNumber to_real_ = (to).Real; \ + (to).Real = to_real_ * (from).Real - \ + (to).Imag * (from).Imag; \ + (to).Imag = to_real_ * (from).Imag + \ + (to).Imag * (from).Real; \ +} + +/* Macro function that multiplies two complex numbers, the first of which is + * conjugated. */ +#define CMPLX_CONJ_MULT(to,from_a,from_b) \ +{ (to).Real = (from_a).Real * (from_b).Real + \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag = (from_a).Real * (from_b).Imag - \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to another. to = add + mult_a * mult_b */ +#define CMPLX_MULT_ADD(to,mult_a,mult_b,add) \ +{ (to).Real = (mult_a).Real * (mult_b).Real - \ + (mult_a).Imag * (mult_b).Imag + (add).Real; \ + (to).Imag = (mult_a).Real * (mult_b).Imag + \ + (mult_a).Imag * (mult_b).Real + (add).Imag; \ +} + +/* Macro function that subtracts the product of two complex numbers from + * another. to = subt - mult_a * mult_b */ +#define CMPLX_MULT_SUBT(to,mult_a,mult_b,subt) \ +{ (to).Real = (subt).Real - (mult_a).Real * (mult_b).Real + \ + (mult_a).Imag * (mult_b).Imag; \ + (to).Imag = (subt).Imag - (mult_a).Real * (mult_b).Imag - \ + (mult_a).Imag * (mult_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to another. to = add + mult_a* * mult_b where mult_a* represents mult_a + * conjugate. */ +#define CMPLX_CONJ_MULT_ADD(to,mult_a,mult_b,add) \ +{ (to).Real = (mult_a).Real * (mult_b).Real + \ + (mult_a).Imag * (mult_b).Imag + (add).Real; \ + (to).Imag = (mult_a).Real * (mult_b).Imag - \ + (mult_a).Imag * (mult_b).Real + (add).Imag; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to another. to += mult_a * mult_b */ +#define CMPLX_MULT_ADD_ASSIGN(to,from_a,from_b) \ +{ (to).Real += (from_a).Real * (from_b).Real - \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag += (from_a).Real * (from_b).Imag + \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then subtracts them + * from another. */ +#define CMPLX_MULT_SUBT_ASSIGN(to,from_a,from_b) \ +{ (to).Real -= (from_a).Real * (from_b).Real - \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag -= (from_a).Real * (from_b).Imag + \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then adds them + * to the destination. to += from_a* * from_b where from_a* represents from_a + * conjugate. */ +#define CMPLX_CONJ_MULT_ADD_ASSIGN(to,from_a,from_b) \ +{ (to).Real += (from_a).Real * (from_b).Real + \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag += (from_a).Real * (from_b).Imag - \ + (from_a).Imag * (from_b).Real; \ +} + +/* Macro function that multiplies two complex numbers and then subtracts them + * from the destination. to -= from_a* * from_b where from_a* represents from_a + * conjugate. */ +#define CMPLX_CONJ_MULT_SUBT_ASSIGN(to,from_a,from_b) \ +{ (to).Real -= (from_a).Real * (from_b).Real + \ + (from_a).Imag * (from_b).Imag; \ + (to).Imag -= (from_a).Real * (from_b).Imag - \ + (from_a).Imag * (from_b).Real; \ +} + +/* + * Macro functions that provide complex division. + */ + +/* Complex division: to = num / den */ +#define CMPLX_DIV(to,num,den) \ +{ RealNumber r_, s_; \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ + { r_ = (den).Imag / (den).Real; \ + s_ = (den).Real + r_*(den).Imag; \ + (to).Real = ((num).Real + r_*(num).Imag)/s_; \ + (to).Imag = ((num).Imag - r_*(num).Real)/s_; \ + } \ + else \ + { r_ = (den).Real / (den).Imag; \ + s_ = (den).Imag + r_*(den).Real; \ + (to).Real = (r_*(num).Real + (num).Imag)/s_; \ + (to).Imag = (r_*(num).Imag - (num).Real)/s_; \ + } \ +} + +/* Complex division and assignment: num /= den */ +#define CMPLX_DIV_ASSIGN(num,den) \ +{ RealNumber r_, s_, t_; \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ + { r_ = (den).Imag / (den).Real; \ + s_ = (den).Real + r_*(den).Imag; \ + t_ = ((num).Real + r_*(num).Imag)/s_; \ + (num).Imag = ((num).Imag - r_*(num).Real)/s_; \ + (num).Real = t_; \ + } \ + else \ + { r_ = (den).Real / (den).Imag; \ + s_ = (den).Imag + r_*(den).Real; \ + t_ = (r_*(num).Real + (num).Imag)/s_; \ + (num).Imag = (r_*(num).Imag - (num).Real)/s_; \ + (num).Real = t_; \ + } \ +} + +/* Complex reciprocation: to = 1.0 / den */ +#define CMPLX_RECIPROCAL(to,den) \ +{ RealNumber r_; \ + if (((den).Real >= (den).Imag AND (den).Real > -(den).Imag) OR \ + ((den).Real < (den).Imag AND (den).Real <= -(den).Imag)) \ + { r_ = (den).Imag / (den).Real; \ + (to).Imag = -r_*((to).Real = 1.0/((den).Real + r_*(den).Imag)); \ + } \ + else \ + { r_ = (den).Real / (den).Imag; \ + (to).Real = -r_*((to).Imag = -1.0/((den).Imag + r_*(den).Real));\ + } \ +} + + + + + + +/* + * ASSERT and ABORT + * + * Macro used to assert that if the code is working correctly, then + * a condition must be true. If not, then execution is terminated + * and an error message is issued stating that there is an internal + * error and giving the file and line number. These assertions are + * not evaluated unless the DEBUG flag is true. + */ + +#if DEBUG +#define ASSERT(condition) if (NOT(condition)) ABORT() +#else +#define ASSERT(condition) +#endif + +#if DEBUG +#define ABORT() \ +{ (void)fflush(stdout); \ + (void)fprintf(stderr, "sparse: panic in file `%s' at line %d.\n", \ + __FILE__, __LINE__); \ + (void)fflush(stderr); \ + abort(); \ +} +#else +#define ABORT() +#endif + + + + + +/* + * IMAGINARY VECTORS + * + * The imaginary vectors iRHS and iSolution are only needed when the + * options spCOMPLEX and spSEPARATED_COMPLEX_VECTORS are set. The following + * macro makes it easy to include or exclude these vectors as needed. + */ + +#if spCOMPLEX AND spSEPARATED_COMPLEX_VECTORS +#define IMAG_VECTORS , iRHS, iSolution +#define IMAG_RHS , iRHS +#else +#define IMAG_VECTORS +#define IMAG_RHS +#endif + +#define ALLOC(type,number) ((type *)tmalloc((unsigned)(sizeof(type)*(number)))) +#define REALLOC(ptr,type,number) \ + ptr = (type *)trealloc((char *)ptr,(unsigned)(sizeof(type)*(number))) +#define FREE(ptr) { if ((ptr) != NULL) txfree((char *)(ptr)); (ptr) = NULL; } + + +/* Calloc that properly handles allocating a cleared vector. */ +#define CALLOC(ptr,type,number) \ +{ int i; ptr = ALLOC(type, number); \ + if (ptr != (type *)NULL) \ + for(i=(number)-1;i>=0; i--) ptr[i] = (type) 0; \ +} + + + + + + + +/* + * REAL NUMBER + */ + +/* Begin `RealNumber'. */ + +typedef spREAL RealNumber, *RealVector; + + + + + + + + +/* + * COMPLEX NUMBER DATA STRUCTURE + * + * >>> Structure fields: + * Real (RealNumber) + * The real portion of the number. Real must be the first + * field in this structure. + * Imag (RealNumber) + * The imaginary portion of the number. This field must follow + * immediately after Real. + */ + +/* Begin `ComplexNumber'. */ + +typedef struct +{ RealNumber Real; + RealNumber Imag; +} ComplexNumber, *ComplexVector; + + + + + + + + +/* + * MATRIX ELEMENT DATA STRUCTURE + * + * Every nonzero element in the matrix is stored in a dynamically allocated + * MatrixElement structure. These structures are linked together in an + * orthogonal linked list. Two different MatrixElement structures exist. + * One is used when only real matrices are expected, it is missing an entry + * for imaginary data. The other is used if complex matrices are expected. + * It contains an entry for imaginary data. + * + * >>> Structure fields: + * Real (RealNumber) + * The real portion of the value of the element. Real must be the first + * field in this structure. + * Imag (RealNumber) + * The imaginary portion of the value of the element. If the matrix + * routines are not compiled to handle complex matrices, then this + * field does not exist. If it exists, it must follow immediately after + * Real. + * Row (int) + * The row number of the element. + * Col (int) + * The column number of the element. + * NextInRow (struct MatrixElement *) + * NextInRow contains a pointer to the next element in the row to the + * right of this element. If this element is the last nonzero in the + * row then NextInRow contains NULL. + * NextInCol (struct MatrixElement *) + * NextInCol contains a pointer to the next element in the column below + * this element. If this element is the last nonzero in the column then + * NextInCol contains NULL. + * pInitInfo (char *) + * Pointer to user data used for initialization of the matrix element. + * Initialized to NULL. + * + * >>> Type definitions: + * ElementPtr + * A pointer to a MatrixElement. + * ArrayOfElementPtrs + * An array of ElementPtrs. Used for FirstInRow, FirstInCol and + * Diag pointer arrays. + */ + +/* Begin `MatrixElement'. */ + +struct MatrixElement +{ RealNumber Real; +#if spCOMPLEX + RealNumber Imag; +#endif + int Row; + int Col; + struct MatrixElement *NextInRow; + struct MatrixElement *NextInCol; +#if INITIALIZE + char *pInitInfo; +#endif +}; + +typedef struct MatrixElement *ElementPtr; +typedef ElementPtr *ArrayOfElementPtrs; + + + + + + + + +/* + * ALLOCATION DATA STRUCTURE + * + * The sparse matrix routines keep track of all memory that is allocated by + * the operating system so the memory can later be freed. This is done by + * saving the pointers to all the chunks of memory that are allocated to a + * particular matrix in an allocation list. That list is organized as a + * linked list so that it can grow without a priori bounds. + * + * >>> Structure fields: + * AllocatedPtr (char *) + * Pointer to chunk of memory that has been allocated for the matrix. + * NextRecord (struct AllocationRecord *) + * Pointer to the next allocation record. + */ + +/* Begin `AllocationRecord'. */ +struct AllocationRecord +{ char *AllocatedPtr; + struct AllocationRecord *NextRecord; +}; + +typedef struct AllocationRecord *AllocationListPtr; + + + + + + + + + +/* + * FILL-IN LIST DATA STRUCTURE + * + * The sparse matrix routines keep track of all fill-ins separately from + * user specified elements so they may be removed by spStripFills(). Fill-ins + * are allocated in bunched in what is called a fill-in lists. The data + * structure defined below is used to organize these fill-in lists into a + * linked-list. + * + * >>> Structure fields: + * pFillinList (ElementPtr) + * Pointer to a fill-in list, or a bunch of fill-ins arranged contiguously + * in memory. + * NumberOfFillinsInList (int) + * Seems pretty self explanatory to me. + * Next (struct FillinListNodeStruct *) + * Pointer to the next fill-in list structures. + */ + +/* Begin `FillinListNodeStruct'. */ +struct FillinListNodeStruct +{ ElementPtr pFillinList; + int NumberOfFillinsInList; + struct FillinListNodeStruct *Next; +}; + +/* Similar to above, but keeps track of the original Elements */ +/* Begin `ElementListNodeStruct'. */ +struct ElementListNodeStruct +{ ElementPtr pElementList; + int NumberOfElementsInList; + struct ElementListNodeStruct *Next; +}; + + + + + + + + + + +/* + * MATRIX FRAME DATA STRUCTURE + * + * This structure contains all the pointers that support the orthogonal + * linked list that contains the matrix elements. Also included in this + * structure are other numbers and pointers that are used globally by the + * sparse matrix routines and are associated with one particular matrix. + * + * >>> Type definitions: + * MatrixPtr + * A pointer to MatrixFrame. Essentially, a pointer to the matrix. + * + * >>> Structure fields: + * AbsThreshold (RealNumber) + * The absolute magnitude an element must have to be considered as a + * pivot candidate, except as a last resort. + * AllocatedExtSize (int) + * The allocated size of the arrays used to translate external row and + * column numbers to their internal values. + * AllocatedSize (int) + * The currently allocated size of the matrix; the size the matrix can + * grow to when EXPANDABLE is set true and AllocatedSize is the largest + * the matrix can get without requiring that the matrix frame be + * reallocated. + * Complex (BOOLEAN) + * The flag which indicates whether the matrix is complex (true) or + * real. + * CurrentSize (int) + * This number is used during the building of the matrix when the + * TRANSLATE option is set true. It indicates the number of internal + * rows and columns that have elements in them. + * Diag (ArrayOfElementPtrs) + * Array of pointers that points to the diagonal elements. + * DoCmplxDirect (BOOLEAN *) + * Array of flags, one for each column in matrix. If a flag is true + * then corresponding column in a complex matrix should be eliminated + * in spFactor() using direct addressing (rather than indirect + * addressing). + * DoRealDirect (BOOLEAN *) + * Array of flags, one for each column in matrix. If a flag is true + * then corresponding column in a real matrix should be eliminated + * in spFactor() using direct addressing (rather than indirect + * addressing). + * Elements (int) + * The total number of elements present in matrix. + * Error (int) + * The error status of the sparse matrix package. + * ExtSize (int) + * The value of the largest external row or column number encountered. + * ExtToIntColMap (int []) + * An array that is used to convert external columns number to internal + * external column numbers. Present only if TRANSLATE option is set true. + * ExtToIntRowMap (int []) + * An array that is used to convert external row numbers to internal + * external row numbers. Present only if TRANSLATE option is set true. + * Factored (BOOLEAN) + * Indicates if matrix has been factored. This flag is set true in + * spFactor() and spOrderAndFactor() and set false in spCreate() + * and spClear(). + * Fillins (int) + * The number of fill-ins created during the factorization the matrix. + * FirstInCol (ArrayOfElementPtrs) + * Array of pointers that point to the first nonzero element of the + * column corresponding to the index. + * FirstInRow (ArrayOfElementPtrs) + * Array of pointers that point to the first nonzero element of the row + * corresponding to the index. + * ID (unsigned long int) + * A constant that provides the sparse data structure with a signature. + * When DEBUG is true, all externally available sparse routines check + * this signature to assure they are operating on a valid matrix. + * Intermediate (RealVector) + * Temporary storage used in the spSolve routines. Intermediate is an + * array used during forward and backward substitution. It is + * commonly called y when the forward and backward substitution process is + * denoted Ax = b => Ly = b and Ux = y. + * InternalVectorsAllocated (BOOLEAN) + * A flag that indicates whether the Markowitz vectors and the + * Intermediate vector have been created. + * These vectors are created in spcCreateInternalVectors(). + * IntToExtColMap (int []) + * An array that is used to convert internal column numbers to external + * external column numbers. + * IntToExtRowMap (int []) + * An array that is used to convert internal row numbers to external + * external row numbers. + * MarkowitzCol (int []) + * An array that contains the count of the non-zero elements excluding + * the pivots for each column. Used to generate and update MarkowitzProd. + * MarkowitzProd (long []) + * The array of the products of the Markowitz row and column counts. The + * element with the smallest product is the best pivot to use to maintain + * sparsity. + * MarkowitzRow (int []) + * An array that contains the count of the non-zero elements excluding + * the pivots for each row. Used to generate and update MarkowitzProd. + * MaxRowCountInLowerTri (int) + * The maximum number of off-diagonal element in the rows of L, the + * lower triangular matrix. This quantity is used when computing an + * estimate of the roundoff error in the matrix. + * NeedsOrdering (BOOLEAN) + * This is a flag that signifies that the matrix needs to be ordered + * or reordered. NeedsOrdering is set true in spCreate() and + * spGetElement() or spGetAdmittance() if new elements are added to the + * matrix after it has been previously factored. It is set false in + * spOrderAndFactor(). + * NumberOfInterchangesIsOdd (BOOLEAN) + * Flag that indicates the sum of row and column interchange counts + * is an odd number. Used when determining the sign of the determinant. + * Originals (int) + * The number of original elements (total elements minus fill ins) + * present in matrix. + * Partitioned (BOOLEAN) + * This flag indicates that the columns of the matrix have been + * partitioned into two groups. Those that will be addressed directly + * and those that will be addressed indirectly in spFactor(). + * PivotsOriginalCol (int) + * Column pivot was chosen from. + * PivotsOriginalRow (int) + * Row pivot was chosen from. + * PivotSelectionMethod (char) + * Character that indicates which pivot search method was successful. + * PreviousMatrixWasComplex (BOOLEAN) + * This flag in needed to determine how to clear the matrix. When + * dealing with real matrices, it is important that the imaginary terms + * in the matrix elements be zero. Thus, if the previous matrix was + * complex, then the current matrix will be cleared as if it were complex + * even if it is real. + * RelThreshold (RealNumber) + * The magnitude an element must have relative to others in its row + * to be considered as a pivot candidate, except as a last resort. + * Reordered (BOOLEAN) + * This flag signifies that the matrix has been reordered. It + * is cleared in spCreate(), set in spMNA_Preorder() and + * spOrderAndFactor() and is used in spPrint(). + * RowsLinked (BOOLEAN) + * A flag that indicates whether the row pointers exist. The AddByIndex + * routines do not generate the row pointers, which are needed by some + * of the other routines, such as spOrderAndFactor() and spScale(). + * The row pointers are generated in the function spcLinkRows(). + * SingularCol (int) + * Normally zero, but if matrix is found to be singular, SingularCol is + * assigned the external column number of pivot that was zero. + * SingularRow (int) + * Normally zero, but if matrix is found to be singular, SingularRow is + * assigned the external row number of pivot that was zero. + * Singletons (int) + * The number of singletons available for pivoting. Note that if row I + * and column I both contain singletons, only one of them is counted. + * Size (int) + * Number of rows and columns in the matrix. Does not change as matrix + * is factored. + * TrashCan (MatrixElement) + * This is a dummy MatrixElement that is used to by the user to stuff + * data related to the zero row or column. In other words, when the user + * adds an element in row zero or column zero, then the matrix returns + * a pointer to TrashCan. In this way the user can have a uniform way + * data into the matrix independent of whether a component is connected + * to ground. + * + * >>> The remaining fields are related to memory allocation. + * TopOfAllocationList (AllocationListPtr) + * Pointer which points to the top entry in a list. The list contains + * all the pointers to the segments of memory that have been allocated + * to this matrix. This is used when the memory is to be freed on + * deallocation of the matrix. + * RecordsRemaining (int) + * Number of slots left in the list of allocations. + * NextAvailElement (ElementPtr) + * Pointer to the next available element which has been allocated but as + * yet is unused. Matrix elements are allocated in groups of + * ELEMENTS_PER_ALLOCATION in order to speed element allocation and + * freeing. + * ElementsRemaining (int) + * Number of unused elements left in last block of elements allocated. + * NextAvailFillin (ElementPtr) + * Pointer to the next available fill-in which has been allocated but + * as yet is unused. Fill-ins are allocated in a group in order to keep + * them physically close in memory to the rest of the matrix. + * FillinsRemaining (int) + * Number of unused fill-ins left in the last block of fill-ins + * allocated. + * FirstFillinListNode (FillinListNodeStruct *) + * A pointer to the head of the linked-list that keeps track of the + * lists of fill-ins. + * LastFillinListNode (FillinListNodeStruct *) + * A pointer to the tail of the linked-list that keeps track of the + * lists of fill-ins. + */ + +/* Begin `MatrixFrame'. */ +struct MatrixFrame +{ RealNumber AbsThreshold; + int AllocatedSize; + int AllocatedExtSize; + BOOLEAN Complex; + int CurrentSize; + ArrayOfElementPtrs Diag; + BOOLEAN *DoCmplxDirect; + BOOLEAN *DoRealDirect; + int Elements; + int Error; + int ExtSize; + int *ExtToIntColMap; + int *ExtToIntRowMap; + BOOLEAN Factored; + int Fillins; + ArrayOfElementPtrs FirstInCol; + ArrayOfElementPtrs FirstInRow; + unsigned long ID; + RealVector Intermediate; + BOOLEAN InternalVectorsAllocated; + int *IntToExtColMap; + int *IntToExtRowMap; + int *MarkowitzRow; + int *MarkowitzCol; + long *MarkowitzProd; + int MaxRowCountInLowerTri; + BOOLEAN NeedsOrdering; + BOOLEAN NumberOfInterchangesIsOdd; + int Originals; + BOOLEAN Partitioned; + int PivotsOriginalCol; + int PivotsOriginalRow; + char PivotSelectionMethod; + BOOLEAN PreviousMatrixWasComplex; + RealNumber RelThreshold; + BOOLEAN Reordered; + BOOLEAN RowsLinked; + int SingularCol; + int SingularRow; + int Singletons; + int Size; + struct MatrixElement TrashCan; + + AllocationListPtr TopOfAllocationList; + int RecordsRemaining; + ElementPtr NextAvailElement; + int ElementsRemaining; + struct ElementListNodeStruct *FirstElementListNode; + struct ElementListNodeStruct *LastElementListNode; + ElementPtr NextAvailFillin; + int FillinsRemaining; + struct FillinListNodeStruct *FirstFillinListNode; + struct FillinListNodeStruct *LastFillinListNode; +}; +typedef struct MatrixFrame *MatrixPtr; + + + + +/* + * Function declarations + */ + +#ifdef __STDC__ +extern ElementPtr spcGetElement( MatrixPtr ); +extern ElementPtr spcGetFillin( MatrixPtr ); +extern ElementPtr spcFindElementInCol( MatrixPtr, ElementPtr*, int, int, int ); +extern ElementPtr spcCreateElement( MatrixPtr, int, int, ElementPtr*, int ); +extern void spcCreateInternalVectors( MatrixPtr ); +extern void spcLinkRows( MatrixPtr ); +extern void spcColExchange( MatrixPtr, int, int ); +extern void spcRowExchange( MatrixPtr, int, int ); +#else /* __STDC__ */ +extern ElementPtr spcGetElement(); +extern ElementPtr spcGetFillin(); +extern ElementPtr spcFindElementInCol(); +extern ElementPtr spcCreateElement(); +extern void spcCreateInternalVectors(); +extern void spcLinkRows(); +extern void spcColExchange(); +extern void spcRowExchange(); +#endif /* __STDC__ */ diff --git a/src/maths/sparse/spextra.c b/src/maths/sparse/spextra.c new file mode 100644 index 000000000..58fbfb780 --- /dev/null +++ b/src/maths/sparse/spextra.c @@ -0,0 +1,212 @@ +/* + * MATRIX UTILITY MODULE + * + * This file contains new routines for Spice3f + * + * >>> User accessible functions contained in this file: + * spConstMul + * + * >>> Other functions contained in this file: + */ + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" + + + + + +/* + * Function declarations + */ + +#ifdef __STDC__ +#if spSEPARATED_COMPLEX_VECTORS +#else +#endif +#else /* __STDC__ */ +#endif /* __STDC__ */ + +void +spConstMult(matrix, constant) + MatrixPtr matrix; + double constant; +{ + ElementPtr e; + int i; + int size = matrix->Size; + + for (i = 1; i <= size; i++) { + for (e = matrix->FirstInCol[i]; e; e = e->NextInCol) { + e->Real *= constant; + e->Imag *= constant; + } + } + +} + +#ifdef notdef + +int spccc = 0; +int spccc_hold = -1; +int spccc_h1 = 1; +int spccc_h2 = 1; +int spccc_h3 = 1; +int spccc_h4 = 1; +int spccc_h5 = 1; +int spccc_h11 = 1; +int spccc_h12 = 1; +int spccc_h13 = 1; +int spccc_h15 = 1; +int spccc_h99 = 1; + +spCheck(matrix, key) + MatrixPtr matrix; + int key; +{ + ElementPtr e; + int i, n, k; + int size = matrix->Size; + + spccc += 1; + if (spccc == spccc_hold) + hold_matrix99( ); + + for (i = 1; i <= size; i++) { + k = -1; + if (!(key & 2)) { + for (n = 0, e = matrix->FirstInCol[i]; e && n <= size; + e = e->NextInCol) + { + if (k >= e->Row) + hold_matrix2( ); + if (e->Col != i) + hold_matrix3( ); + if (e->NextInRow && e->Col >= e->NextInRow->Col) + hold_matrix5( ); + + k = e->Row; + n += 1; + } + if (n > size) + hold_matrix1( ); + } + + k = -1; + if (matrix->RowsLinked && !(key & 1)) { + for (n = 0, e = matrix->FirstInRow[i]; e && n <= size; + e = e->NextInRow) + { + if (k >= e->Col) + hold_matrix12( ); + if (e->Row != i) + hold_matrix13( ); + if (e->NextInCol && e->Row >= e->NextInCol->Row) + hold_matrix15( ); + + k = e->Col; + n += 1; + } + if (n > size) + hold_matrix11( ); + } + } + +} + +hold_matrix1( ) +{ + if (spccc_h1) { + printf("BAD MATRIX"); + fflush(stdout); + } +} + +hold_matrix2( ) +{ + if (spccc_h2) { + printf("BAD MATRIX 2"); + fflush(stdout); + } +} + +hold_matrix3( ) +{ + if (spccc_h3) { + printf("BAD MATRIX 3"); + fflush(stdout); + } +} + +hold_matrix4( ) +{ + if (spccc_h4) { + printf("BAD MATRIX 3"); + fflush(stdout); + } +} + +hold_matrix5( ) +{ + if (spccc_h5) { + printf("BAD MATRIX 5"); + fflush(stdout); + } +} + +hold_matrix11( ) +{ + if (spccc_h11) { + printf("BAD MATRIX 11"); + fflush(stdout); + } +} + +hold_matrix12( ) +{ + if (spccc_h12) { + printf("BAD MATRIX 12"); + fflush(stdout); + } +} + +hold_matrix13( ) +{ + if (spccc_h13) { + printf("BAD MATRIX 13"); + fflush(stdout); + } +} + +hold_matrix15( ) +{ + if (spccc_h15) { + printf("BAD MATRIX 15"); + fflush(stdout); + } +} + +hold_matrix99( ) +{ + if (spccc_h99) { + printf("BAD MATRIX 99"); + fflush(stdout); + } +} + +#endif diff --git a/src/maths/sparse/spfactor.c b/src/maths/sparse/spfactor.c new file mode 100644 index 000000000..41406691f --- /dev/null +++ b/src/maths/sparse/spfactor.c @@ -0,0 +1,3159 @@ +/* + * MATRIX FACTORIZATION MODULE + * + * Author: Advising Professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the routines to factor the matrix into LU form. + * + * >>> User accessible functions contained in this file: + * spOrderAndFactor + * spFactor + * spPartition + * + * >>> Other functions contained in this file: + * FactorComplexMatrix spcCreateInternalVectors + * CountMarkowitz MarkowitzProducts + * SearchForPivot SearchForSingleton + * QuicklySearchDiagonal SearchDiagonal + * SearchEntireMatrix FindLargestInCol + * FindBiggestInColExclude ExchangeRowsAndCols + * spcRowExchange spcColExchange + * ExchangeColElements ExchangeRowElements + * RealRowColElimination ComplexRowColElimination + * UpdateMarkowitzNumbers CreateFillin + * MatrixIsSingular ZeroPivot + * WriteStatus + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header$"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" + + + + + +/* + * Function declarations + */ + +static int FactorComplexMatrix( MatrixPtr ); +static void CountMarkowitz( MatrixPtr, RealVector, int ); +static void MarkowitzProducts( MatrixPtr, int ); +static ElementPtr SearchForPivot( MatrixPtr, int, int ); +static ElementPtr SearchForSingleton( MatrixPtr, int ); +static ElementPtr QuicklySearchDiagonal( MatrixPtr, int ); +static ElementPtr SearchDiagonal( MatrixPtr, int ); +static ElementPtr SearchEntireMatrix( MatrixPtr, int ); +static RealNumber FindLargestInCol( ElementPtr ); +static RealNumber FindBiggestInColExclude( MatrixPtr, ElementPtr, int ); +static void ExchangeRowsAndCols( MatrixPtr, ElementPtr, int ); +static void ExchangeColElements( MatrixPtr, int, ElementPtr, int, + ElementPtr, int ); +static void ExchangeRowElements( MatrixPtr, int, ElementPtr, int, + ElementPtr, int ); +static void RealRowColElimination( MatrixPtr, ElementPtr ); +static void ComplexRowColElimination( MatrixPtr, ElementPtr ); +static void UpdateMarkowitzNumbers( MatrixPtr, ElementPtr ); +static ElementPtr CreateFillin( MatrixPtr, int, int ); +static int MatrixIsSingular( MatrixPtr, int ); +static int ZeroPivot( MatrixPtr, int ); + + + +/* + * ORDER AND FACTOR MATRIX + * + * This routine chooses a pivot order for the matrix and factors it + * into LU form. It handles both the initial factorization and subsequent + * factorizations when a reordering is desired. This is handled in a manner + * that is transparent to the user. The routine uses a variation of + * Gauss's method where the pivots are associated with L and the + * diagonal terms of U are one. + * + * >>> Returned: + * The error code is returned. Possible errors are listed below. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * RHS (RealVector) + * Representative right-hand side vector that is used to determine + * pivoting order when the right hand side vector is sparse. If + * RHS is a NULL pointer then the RHS vector is assumed to + * be full and it is not used when determining the pivoting + * order. + * RelThreshold (RealNumber) + * This number determines what the pivot relative threshold will + * be. It should be between zero and one. If it is one then the + * pivoting method becomes complete pivoting, which is very slow + * and tends to fill up the matrix. If it is set close to zero + * the pivoting method becomes strict Markowitz with no + * threshold. The pivot threshold is used to eliminate pivot + * candidates that would cause excessive element growth if they + * were used. Element growth is the cause of roundoff error. + * Element growth occurs even in well-conditioned matrices. + * Setting the RelThreshold large will reduce element growth and + * roundoff error, but setting it too large will cause execution + * time to be excessive and will result in a large number of + * fill-ins. If this occurs, accuracy can actually be degraded + * because of the large number of operations required on the + * matrix due to the large number of fill-ins. A good value seems + * to be 0.001. The default is chosen by giving a value larger + * than one or less than or equal to zero. This value should be + * increased and the matrix resolved if growth is found to be + * excessive. Changing the pivot threshold does not improve + * performance on matrices where growth is low, as is often the + * case with ill-conditioned matrices. Once a valid threshold is + * given, it becomes the new default. The default value of + * RelThreshold was choosen for use with nearly diagonally + * dominant matrices such as node- and modified-node admittance + * matrices. For these matrices it is usually best to use + * diagonal pivoting. For matrices without a strong diagonal, it + * is usually best to use a larger threshold, such as 0.01 or + * 0.1. + * AbsThreshold (RealNumber) + * The absolute magnitude an element must have to be considered + * as a pivot candidate, except as a last resort. This number + * should be set significantly smaller than the smallest diagonal + * element that is is expected to be placed in the matrix. If + * there is no reasonable prediction for the lower bound on these + * elements, then AbsThreshold should be set to zero. + * AbsThreshold is used to reduce the possibility of choosing as a + * pivot an element that has suffered heavy cancellation and as a + * result mainly consists of roundoff error. Once a valid + * threshold is given, it becomes the new default. + * DiagPivoting (BOOLEAN) + * A flag indicating that pivot selection should be confined to the + * diagonal if possible. If DiagPivoting is nonzero and if + * DIAGONAL_PIVOTING is enabled pivots will be chosen only from + * the diagonal unless there are no diagonal elements that satisfy + * the threshold criteria. Otherwise, the entire reduced + * submatrix is searched when looking for a pivot. The diagonal + * pivoting in Sparse is efficient and well refined, while the + * off-diagonal pivoting is not. For symmetric and near symmetric + * matrices, it is best to use diagonal pivoting because it + * results in the best performance when reordering the matrix and + * when factoring the matrix without ordering. If there is a + * considerable amount of nonsymmetry in the matrix, then + * off-diagonal pivoting may result in a better equation ordering + * simply because there are more pivot candidates to choose from. + * A better ordering results in faster subsequent factorizations. + * However, the initial pivot selection process takes considerably + * longer for off-diagonal pivoting. + * + * >>> Local variables: + * pPivot (ElementPtr) + * Pointer to the element being used as a pivot. + * ReorderingRequired (BOOLEAN) + * Flag that indicates whether reordering is required. + * + * >>> Possible errors: + * spNO_MEMORY + * spSINGULAR + * spSMALL_PIVOT + * Error is cleared in this function. + */ + +int +spOrderAndFactor( eMatrix, RHS, RelThreshold, AbsThreshold, DiagPivoting ) + +char *eMatrix; +RealNumber RHS[], RelThreshold, AbsThreshold; +BOOLEAN DiagPivoting; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +ElementPtr pPivot; +int Step, Size, ReorderingRequired; +ElementPtr SearchForPivot(); +RealNumber LargestInCol, FindLargestInCol(); + +/* Begin `spOrderAndFactor'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored); + + Matrix->Error = spOKAY; + Size = Matrix->Size; + if (RelThreshold <= 0.0) RelThreshold = Matrix->RelThreshold; + if (RelThreshold > 1.0) RelThreshold = Matrix->RelThreshold; + Matrix->RelThreshold = RelThreshold; + if (AbsThreshold < 0.0) AbsThreshold = Matrix->AbsThreshold; + Matrix->AbsThreshold = AbsThreshold; + ReorderingRequired = NO; + + if (NOT Matrix->NeedsOrdering) + { +/* Matrix has been factored before and reordering is not required. */ + for (Step = 1; Step <= Size; Step++) + { pPivot = Matrix->Diag[Step]; + LargestInCol = FindLargestInCol(pPivot->NextInCol); + if ((LargestInCol * RelThreshold < ELEMENT_MAG(pPivot))) + { if (Matrix->Complex) + ComplexRowColElimination( Matrix, pPivot ); + else + RealRowColElimination( Matrix, pPivot ); + } + else + { ReorderingRequired = YES; + break; /* for loop */ + } + } + if (NOT ReorderingRequired) + goto Done; + else + { +/* + * A pivot was not large enough to maintain accuracy, + * so a partial reordering is required. + */ + +#if (ANNOTATE >= ON_STRANGE_BEHAVIOR) + printf("Reordering, Step = %1d\n", Step); +#endif + } + } /* End of if(NOT Matrix->NeedsOrdering) */ + else + { +/* + * This is the first time the matrix has been factored. These few statements + * indicate to the rest of the code that a full reodering is required rather + * than a partial reordering, which occurs during a failure of a fast + * factorization. + */ + Step = 1; + if (NOT Matrix->RowsLinked) + spcLinkRows( Matrix ); + if (NOT Matrix->InternalVectorsAllocated) + spcCreateInternalVectors( Matrix ); + if (Matrix->Error >= spFATAL) + return Matrix->Error; + } + +/* Form initial Markowitz products. */ + CountMarkowitz( Matrix, RHS, Step ); + MarkowitzProducts( Matrix, Step ); + Matrix->MaxRowCountInLowerTri = -1; + +/* Perform reordering and factorization. */ + for (; Step <= Size; Step++) + { pPivot = SearchForPivot( Matrix, Step, DiagPivoting ); + if (pPivot == NULL) return MatrixIsSingular( Matrix, Step ); + ExchangeRowsAndCols( Matrix, pPivot, Step ); + + if (Matrix->Complex) + ComplexRowColElimination( Matrix, pPivot ); + else + RealRowColElimination( Matrix, pPivot ); + + if (Matrix->Error >= spFATAL) return Matrix->Error; + UpdateMarkowitzNumbers( Matrix, pPivot ); + +#if (ANNOTATE == FULL) + WriteStatus( Matrix, Step ); +#endif + } + +Done: + Matrix->NeedsOrdering = NO; + Matrix->Reordered = YES; + Matrix->Factored = YES; + + return Matrix->Error; +} + + + + + + + +/* + * FACTOR MATRIX + * + * This routine is the companion routine to spOrderAndFactor(). + * Unlike spOrderAndFactor(), spFactor() cannot change the ordering. + * It is also faster than spOrderAndFactor(). The standard way of + * using these two routines is to first use spOrderAndFactor() for the + * initial factorization. For subsequent factorizations, spFactor() + * is used if there is some assurance that little growth will occur + * (say for example, that the matrix is diagonally dominant). If + * spFactor() is called for the initial factorization of the matrix, + * then spOrderAndFactor() is automatically called with the default + * threshold. This routine uses "row at a time" LU factorization. + * Pivots are associated with the lower triangular matrix and the + * diagonals of the upper triangular matrix are ones. + * + * >>> Returned: + * The error code is returned. Possible errors are listed below. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * + * >>> Possible errors: + * spNO_MEMORY + * spSINGULAR + * spZERO_DIAG + * spSMALL_PIVOT + * Error is cleared in this function. + */ + +int +spFactor( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register ElementPtr pColumn; +register int Step, Size; +RealNumber Mult; + +/* Begin `spFactor'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored); + + if (Matrix->NeedsOrdering) + { return spOrderAndFactor( eMatrix, (RealVector)NULL, + 0.0, 0.0, DIAG_PIVOTING_AS_DEFAULT ); + } + if (NOT Matrix->Partitioned) spPartition( eMatrix, spDEFAULT_PARTITION ); +#if spCOMPLEX + if (Matrix->Complex) return FactorComplexMatrix( Matrix ); +#endif + +#if REAL + Size = Matrix->Size; + + if (Matrix->Diag[1]->Real == 0.0) return ZeroPivot( Matrix, 1 ); + Matrix->Diag[1]->Real = 1.0 / Matrix->Diag[1]->Real; + +/* Start factorization. */ + for (Step = 2; Step <= Size; Step++) + { if (Matrix->DoRealDirect[Step]) + { /* Update column using direct addressing scatter-gather. */ + register RealNumber *Dest = (RealNumber *)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { Dest[pElement->Row] = pElement->Real; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + pColumn->Real = Dest[pColumn->Row] * pElement->Real; + while ((pElement = pElement->NextInCol) != NULL) + Dest[pElement->Row] -= pColumn->Real * pElement->Real; + pColumn = pColumn->NextInCol; + } + +/* Gather. */ + pElement = Matrix->Diag[Step]->NextInCol; + while (pElement != NULL) + { pElement->Real = Dest[pElement->Row]; + pElement = pElement->NextInCol; + } + +/* Check for singular matrix. */ + if (Dest[Step] == 0.0) return ZeroPivot( Matrix, Step ); + Matrix->Diag[Step]->Real = 1.0 / Dest[Step]; + } + else + { /* Update column using indirect addressing scatter-gather. */ + register RealNumber **pDest = (RealNumber **)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { pDest[pElement->Row] = &pElement->Real; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + Mult = (*pDest[pColumn->Row] *= pElement->Real); + while ((pElement = pElement->NextInCol) != NULL) + *pDest[pElement->Row] -= Mult * pElement->Real; + pColumn = pColumn->NextInCol; + } + +/* Check for singular matrix. */ + if (Matrix->Diag[Step]->Real == 0.0) + return ZeroPivot( Matrix, Step ); + Matrix->Diag[Step]->Real = 1.0 / Matrix->Diag[Step]->Real; + } + } + + Matrix->Factored = YES; + return (Matrix->Error = spOKAY); +#endif /* REAL */ +} + + + + + + +#if spCOMPLEX +/* + * FACTOR COMPLEX MATRIX + * + * This routine is the companion routine to spFactor(), it + * handles complex matrices. It is otherwise identical. + * + * >>> Returned: + * The error code is returned. Possible errors are listed below. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * + * >>> Possible errors: + * spSINGULAR + * Error is cleared in this function. + */ + +static int +FactorComplexMatrix( Matrix ) + +MatrixPtr Matrix; +{ +register ElementPtr pElement; +register ElementPtr pColumn; +register int Step, Size; +ComplexNumber Mult, Pivot; + +/* Begin `FactorComplexMatrix'. */ + ASSERT(Matrix->Complex); + + Size = Matrix->Size; + pElement = Matrix->Diag[1]; + if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, 1 ); +/* Cmplx expr: *pPivot = 1.0 / *pPivot. */ + CMPLX_RECIPROCAL( *pElement, *pElement ); + +/* Start factorization. */ + for (Step = 2; Step <= Size; Step++) + { if (Matrix->DoCmplxDirect[Step]) + { /* Update column using direct addressing scatter-gather. */ + register ComplexNumber *Dest; + Dest = (ComplexNumber *)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { Dest[pElement->Row] = *(ComplexNumber *)pElement; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + /* Cmplx expr: Mult = Dest[pColumn->Row] * (1.0 / *pPivot). */ + CMPLX_MULT(Mult, Dest[pColumn->Row], *pElement); + CMPLX_ASSIGN(*pColumn, Mult); + while ((pElement = pElement->NextInCol) != NULL) + { /* Cmplx expr: Dest[pElement->Row] -= Mult * pElement */ + CMPLX_MULT_SUBT_ASSIGN(Dest[pElement->Row],Mult,*pElement); + } + pColumn = pColumn->NextInCol; + } + +/* Gather. */ + pElement = Matrix->Diag[Step]->NextInCol; + while (pElement != NULL) + { *(ComplexNumber *)pElement = Dest[pElement->Row]; + pElement = pElement->NextInCol; + } + +/* Check for singular matrix. */ + Pivot = Dest[Step]; + if (CMPLX_1_NORM(Pivot) == 0.0) return ZeroPivot( Matrix, Step ); + CMPLX_RECIPROCAL( *Matrix->Diag[Step], Pivot ); + } + else + { /* Update column using direct addressing scatter-gather. */ + register ComplexNumber **pDest; + pDest = (ComplexNumber **)Matrix->Intermediate; + +/* Scatter. */ + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { pDest[pElement->Row] = (ComplexNumber *)pElement; + pElement = pElement->NextInCol; + } + +/* Update column. */ + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + /* Cmplx expr: Mult = *pDest[pColumn->Row] * (1.0 / *pPivot). */ + CMPLX_MULT(Mult, *pDest[pColumn->Row], *pElement); + CMPLX_ASSIGN(*pDest[pColumn->Row], Mult); + while ((pElement = pElement->NextInCol) != NULL) + { /* Cmplx expr: *pDest[pElement->Row] -= Mult * pElement */ + CMPLX_MULT_SUBT_ASSIGN(*pDest[pElement->Row],Mult,*pElement); + } + pColumn = pColumn->NextInCol; + } + +/* Check for singular matrix. */ + pElement = Matrix->Diag[Step]; + if (ELEMENT_MAG(pElement) == 0.0) return ZeroPivot( Matrix, Step ); + CMPLX_RECIPROCAL( *pElement, *pElement ); + } + } + + Matrix->Factored = YES; + return (Matrix->Error = spOKAY); +} +#endif /* spCOMPLEX */ + + + + + + +/* + * PARTITION MATRIX + * + * This routine determines the cost to factor each row using both + * direct and indirect addressing and decides, on a row-by-row basis, + * which addressing mode is fastest. This information is used in + * spFactor() to speed the factorization. + * + * When factoring a previously ordered matrix using spFactor(), Sparse + * operates on a row-at-a-time basis. For speed, on each step, the + * row being updated is copied into a full vector and the operations + * are performed on that vector. This can be done one of two ways, + * either using direct addressing or indirect addressing. Direct + * addressing is fastest when the matrix is relatively dense and + * indirect addressing is best when the matrix is quite sparse. The + * user selects the type of partition used with Mode. If Mode is set + * to spDIRECT_PARTITION, then the all rows are placed in the direct + * addressing partition. Similarly, if Mode is set to + * spINDIRECT_PARTITION, then the all rows are placed in the indirect + * addressing partition. By setting Mode to spAUTO_PARTITION, the + * user allows Sparse to select the partition for each row + * individually. spFactor() generally runs faster if Sparse is + * allowed to choose its own partitioning, however choosing a + * partition is expensive. The time required to choose a partition is + * of the same order of the cost to factor the matrix. If you plan to + * factor a large number of matrices with the same structure, it is + * best to let Sparse choose the partition. Otherwise, you should + * choose the partition based on the predicted density of the matrix. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * Mode (int) + * Mode must be one of three special codes: spDIRECT_PARTITION, + * spINDIRECT_PARTITION, or spAUTO_PARTITION. + */ + +void +spPartition( eMatrix, Mode ) + +char *eMatrix; +int Mode; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement, pColumn; +register int Step, Size; +register int *Nc, *No, *Nm; +BOOLEAN *DoRealDirect, *DoCmplxDirect; + +/* Begin `spPartition'. */ + ASSERT( IS_SPARSE( Matrix ) ); + if (Matrix->Partitioned) return; + Size = Matrix->Size; + DoRealDirect = Matrix->DoRealDirect; + DoCmplxDirect = Matrix->DoCmplxDirect; + Matrix->Partitioned = YES; + +/* If partition is specified by the user, this is easy. */ + if (Mode == spDEFAULT_PARTITION) Mode = DEFAULT_PARTITION; + if (Mode == spDIRECT_PARTITION) + { for (Step = 1; Step <= Size; Step++) +#if REAL + DoRealDirect[Step] = YES; +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = YES; +#endif + return; + } + else if (Mode == spINDIRECT_PARTITION) + { for (Step = 1; Step <= Size; Step++) +#if REAL + DoRealDirect[Step] = NO; +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = NO; +#endif + return; + } + else ASSERT( Mode == spAUTO_PARTITION ); + +/* Otherwise, count all operations needed in when factoring matrix. */ + Nc = (int *)Matrix->MarkowitzRow; + No = (int *)Matrix->MarkowitzCol; + Nm = (int *)Matrix->MarkowitzProd; + +/* Start mock-factorization. */ + for (Step = 1; Step <= Size; Step++) + { Nc[Step] = No[Step] = Nm[Step] = 0; + + pElement = Matrix->FirstInCol[Step]; + while (pElement != NULL) + { Nc[Step]++; + pElement = pElement->NextInCol; + } + + pColumn = Matrix->FirstInCol[Step]; + while (pColumn->Row < Step) + { pElement = Matrix->Diag[pColumn->Row]; + Nm[Step]++; + while ((pElement = pElement->NextInCol) != NULL) + No[Step]++; + pColumn = pColumn->NextInCol; + } + } + + for (Step = 1; Step <= Size; Step++) + { +/* + * The following are just estimates based on a count on the number of + * machine instructions used on each machine to perform the various + * tasks. It was assumed that each machine instruction required the + * same amount of time (I don't believe this is TRUE for the VAX, and + * have no idea if this is TRUE for the 68000 family). For optimum + * performance, these numbers should be tuned to the machine. + * Nc is the number of nonzero elements in the column. + * Nm is the number of multipliers in the column. + * No is the number of operations in the inner loop. + */ + +#define generic +#ifdef hp9000s300 +#if REAL + DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX + /* On the hp350, it is never profitable to use direct for complex. */ + DoCmplxDirect[Step] = NO; +#endif +#undef generic +#endif + +#ifdef vax +#if REAL + DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]); +#endif +#undef generic +#endif + +#ifdef generic +#if REAL + DoRealDirect[Step] = (Nm[Step] + No[Step] > 3*Nc[Step] - 2*Nm[Step]); +#endif +#if spCOMPLEX + DoCmplxDirect[Step] = (Nm[Step] + No[Step] > 7*Nc[Step] - 4*Nm[Step]); +#endif +#undef generic +#endif + } + +#if (ANNOTATE == FULL) + { int Ops = 0; + for (Step = 1; Step <= Size; Step++) + Ops += No[Step]; + printf("Operation count for inner loop of factorization = %d.\n", Ops); + } +#endif + return; +} + + + + + + + +/* + * CREATE INTERNAL VECTORS + * + * Creates the Markowitz and Intermediate vectors. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * + * >>> Local variables: + * SizePlusOne (unsigned) + * Size of the arrays to be allocated. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +void +spcCreateInternalVectors( Matrix ) + +MatrixPtr Matrix; +{ +int Size; + +/* Begin `spcCreateInternalVectors'. */ +/* Create Markowitz arrays. */ + Size= Matrix->Size; + + if (Matrix->MarkowitzRow == NULL) + { if (( Matrix->MarkowitzRow = ALLOC(int, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } + if (Matrix->MarkowitzCol == NULL) + { if (( Matrix->MarkowitzCol = ALLOC(int, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } + if (Matrix->MarkowitzProd == NULL) + { if (( Matrix->MarkowitzProd = ALLOC(long, Size+2)) == NULL) + Matrix->Error = spNO_MEMORY; + } + +/* Create DoDirect vectors for use in spFactor(). */ +#if REAL + if (Matrix->DoRealDirect == NULL) + { if (( Matrix->DoRealDirect = ALLOC(BOOLEAN, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } +#endif +#if spCOMPLEX + if (Matrix->DoCmplxDirect == NULL) + { if (( Matrix->DoCmplxDirect = ALLOC(BOOLEAN, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } +#endif + +/* Create Intermediate vectors for use in MatrixSolve. */ +#if spCOMPLEX + if (Matrix->Intermediate == NULL) + { if ((Matrix->Intermediate = ALLOC(RealNumber,2*(Size+1))) == NULL) + Matrix->Error = spNO_MEMORY; + } +#else + if (Matrix->Intermediate == NULL) + { if ((Matrix->Intermediate = ALLOC(RealNumber, Size+1)) == NULL) + Matrix->Error = spNO_MEMORY; + } +#endif + + if (Matrix->Error != spNO_MEMORY) + Matrix->InternalVectorsAllocated = YES; + return; +} + + + + + + + +/* + * COUNT MARKOWITZ + * + * Scans Matrix to determine the Markowitz counts for each row and column. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * RHS (RealVector) + * Representative right-hand side vector that is used to determine + * pivoting order when the right hand side vector is sparse. If + * RHS is a NULL pointer then the RHS vector is assumed to be full + * and it is not used when determining the pivoting order. + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * Count (int) + * Temporary counting variable. + * ExtRow (int) + * The external row number that corresponds to I. + * pElement (ElementPtr) + * Pointer to matrix elements. + * Size (int) + * The size of the matrix. + */ + +static void +CountMarkowitz( Matrix, RHS, Step ) + +MatrixPtr Matrix; +register RealVector RHS; +int Step; +{ +register int Count, I, Size = Matrix->Size; +register ElementPtr pElement; +int ExtRow; + +/* Begin `CountMarkowitz'. */ + +/* Correct array pointer for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX + if (RHS != NULL) --RHS; +#else + if (RHS != NULL) + { if (Matrix->Complex) RHS -= 2; + else --RHS; + } +#endif +#endif + +/* Generate MarkowitzRow Count for each row. */ + for (I = Step; I <= Size; I++) + { +/* Set Count to -1 initially to remove count due to pivot element. */ + Count = -1; + pElement = Matrix->FirstInRow[I]; + while (pElement != NULL AND pElement->Col < Step) + pElement = pElement->NextInRow; + while (pElement != NULL) + { Count++; + pElement = pElement->NextInRow; + } + +/* Include nonzero elements in the RHS vector. */ + ExtRow = Matrix->IntToExtRowMap[I]; + +#if spSEPARATED_COMPLEX_VECTORS OR NOT spCOMPLEX + if (RHS != NULL) + if (RHS[ExtRow] != 0.0) Count++; +#else + if (RHS != NULL) + { if (Matrix->Complex) + { if ((RHS[2*ExtRow] != 0.0) OR (RHS[2*ExtRow+1] != 0.0)) + Count++; + } + else if (RHS[I] != 0.0) Count++; + } +#endif + Matrix->MarkowitzRow[I] = Count; + } + +/* Generate the MarkowitzCol count for each column. */ + for (I = Step; I <= Size; I++) + { +/* Set Count to -1 initially to remove count due to pivot element. */ + Count = -1; + pElement = Matrix->FirstInCol[I]; + while (pElement != NULL AND pElement->Row < Step) + pElement = pElement->NextInCol; + while (pElement != NULL) + { Count++; + pElement = pElement->NextInCol; + } + Matrix->MarkowitzCol[I] = Count; + } + return; +} + + + + + + + + + + +/* + * MARKOWITZ PRODUCTS + * + * Calculates MarkowitzProduct for each diagonal element from the Markowitz + * counts. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local Variables: + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. Is used to + * sequentially access entries quickly. + * pMarkowitzRow (int *) + * Pointer that points into MarkowitzRow array. Is used to sequentially + * access entries quickly. + * pMarkowitzCol (int *) + * Pointer that points into MarkowitzCol array. Is used to sequentially + * access entries quickly. + * Product (long) + * Temporary storage for Markowitz product./ + * Size (int) + * The size of the matrix. + */ + +static void +MarkowitzProducts( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register int I, *pMarkowitzRow, *pMarkowitzCol; +register long Product, *pMarkowitzProduct; +register int Size = Matrix->Size; +double fProduct; + +/* Begin `MarkowitzProducts'. */ + Matrix->Singletons = 0; + + pMarkowitzProduct = &(Matrix->MarkowitzProd[Step]); + pMarkowitzRow = &(Matrix->MarkowitzRow[Step]); + pMarkowitzCol = &(Matrix->MarkowitzCol[Step]); + + for (I = Step; I <= Size; I++) + { +/* If chance of overflow, use real numbers. */ + if ((*pMarkowitzRow > LARGEST_SHORT_INTEGER AND *pMarkowitzCol != 0) OR + (*pMarkowitzCol > LARGEST_SHORT_INTEGER AND *pMarkowitzRow != 0)) + { fProduct = (double)(*pMarkowitzRow++) * (double)(*pMarkowitzCol++); + if (fProduct >= LARGEST_LONG_INTEGER) + *pMarkowitzProduct++ = LARGEST_LONG_INTEGER; + else + *pMarkowitzProduct++ = fProduct; + } + else + { Product = *pMarkowitzRow++ * *pMarkowitzCol++; + if ((*pMarkowitzProduct++ = Product) == 0) + Matrix->Singletons++; + } + } + return; +} + + + + + + + + + + + +/* + * SEARCH FOR BEST PIVOT + * + * Performs a search to determine the element with the lowest Markowitz + * Product that is also acceptable. An acceptable element is one that is + * larger than the AbsThreshold and at least as large as RelThreshold times + * the largest element in the same column. The first step is to look for + * singletons if any exist. If none are found, then all the diagonals are + * searched. The diagonal is searched once quickly using the assumption that + * elements on the diagonal are large compared to other elements in their + * column, and so the pivot can be chosen only on the basis of the Markowitz + * criterion. After a element has been chosen to be pivot on the basis of + * its Markowitz product, it is checked to see if it is large enough. + * Waiting to the end of the Markowitz search to check the size of a pivot + * candidate saves considerable time, but is not guaranteed to find an + * acceptable pivot. Thus if unsuccessful a second pass of the diagonal is + * made. This second pass checks to see if an element is large enough during + * the search, not after it. If still no acceptable pivot candidate has + * been found, the search expands to cover the entire matrix. + * + * >>> Returned: + * A pointer to the element chosen to be pivot. If every element in the + * matrix is zero, then NULL is returned. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Step (int) + * The row and column number of the beginning of the reduced submatrix. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to element that has been chosen to be the pivot. + * + * >>> Possible errors: + * spSINGULAR + * spSMALL_PIVOT + */ + +static ElementPtr +SearchForPivot( Matrix, Step, DiagPivoting ) + +MatrixPtr Matrix; +int Step, DiagPivoting; +{ +register ElementPtr ChosenPivot; +ElementPtr SearchForSingleton(); +ElementPtr QuicklySearchDiagonal(); +ElementPtr SearchDiagonal(); +ElementPtr SearchEntireMatrix(); + +/* Begin `SearchForPivot'. */ + +/* If singletons exist, look for an acceptable one to use as pivot. */ + if (Matrix->Singletons) + { ChosenPivot = SearchForSingleton( Matrix, Step ); + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 's'; + return ChosenPivot; + } + } + +#if DIAGONAL_PIVOTING + if (DiagPivoting) + { +/* + * Either no singletons exist or they weren't acceptable. Take quick first + * pass at searching diagonal. First search for element on diagonal of + * remaining submatrix with smallest Markowitz product, then check to see + * if it okay numerically. If not, QuicklySearchDiagonal fails. + */ + ChosenPivot = QuicklySearchDiagonal( Matrix, Step ); + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 'q'; + return ChosenPivot; + } + +/* + * Quick search of diagonal failed, carefully search diagonal and check each + * pivot candidate numerically before even tentatively accepting it. + */ + ChosenPivot = SearchDiagonal( Matrix, Step ); + if (ChosenPivot != NULL) + { Matrix->PivotSelectionMethod = 'd'; + return ChosenPivot; + } + } +#endif /* DIAGONAL_PIVOTING */ + +/* No acceptable pivot found yet, search entire matrix. */ + ChosenPivot = SearchEntireMatrix( Matrix, Step ); + Matrix->PivotSelectionMethod = 'e'; + + return ChosenPivot; +} + + + + + + + + + +/* + * SEARCH FOR SINGLETON TO USE AS PIVOT + * + * Performs a search to find a singleton to use as the pivot. The + * first acceptable singleton is used. A singleton is acceptable if + * it is larger in magnitude than the AbsThreshold and larger + * than RelThreshold times the largest of any other elements in the same + * column. It may seem that a singleton need not satisfy the + * relative threshold criterion, however it is necessary to prevent + * excessive growth in the RHS from resulting in overflow during the + * forward and backward substitution. A singleton does not need to + * be on the diagonal to be selected. + * + * >>> Returned: + * A pointer to the singleton chosen to be pivot. In no singleton is + * acceptable, return NULL. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to element that has been chosen to be the pivot. + * PivotMag (RealNumber) + * Magnitude of ChosenPivot. + * Singletons (int) + * The count of the number of singletons that can be used as pivots. + * A local version of Matrix->Singletons. + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + */ + +static ElementPtr +SearchForSingleton( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register ElementPtr ChosenPivot; +register int I; +register long *pMarkowitzProduct; +int Singletons; +RealNumber PivotMag, FindBiggestInColExclude(); + +/* Begin `SearchForSingleton'. */ +/* Initialize pointer that is to scan through MarkowitzProduct vector. */ + pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+1]); + Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; + +/* Decrement the count of available singletons, on the assumption that an + * acceptable one will be found. */ + Singletons = Matrix->Singletons--; + +/* + * Assure that following while loop will always terminate, this is just + * preventive medicine, if things are working right this should never + * be needed. + */ + Matrix->MarkowitzProd[Step-1] = 0; + + while (Singletons-- > 0) + { +/* Singletons exist, find them. */ + +/* + * This is tricky. Am using a pointer to sequentially step through the + * MarkowitzProduct array. Search terminates when singleton (Product = 0) + * is found. Note that the conditional in the while statement + * ( *pMarkowitzProduct ) is TRUE as long as the MarkowitzProduct is not + * equal to zero. The row (and column)strchr on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element, the singleton. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ + + while ( *pMarkowitzProduct-- ) + { /* + * N bottles of beer on the wall; + * N bottles of beer. + * you take one down and pass it around; + * N-1 bottles of beer on the wall. + */ + } + I = pMarkowitzProduct - Matrix->MarkowitzProd + 1; + +/* Assure that I is valid. */ + if (I < Step) break; /* while (Singletons-- > 0) */ + if (I > Matrix->Size) I = Step; + +/* Singleton has been found in either/both row or/and column I. */ + if ((ChosenPivot = Matrix->Diag[I]) != NULL) + { +/* Singleton lies on the diagonal. */ + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, Step ) + ) return ChosenPivot; + } + else + { +/* Singleton does not lie on diagonal, find it. */ + if (Matrix->MarkowitzCol[I] == 0) + { ChosenPivot = Matrix->FirstInCol[I]; + while ((ChosenPivot != NULL) AND (ChosenPivot->Row < Step)) + ChosenPivot = ChosenPivot->NextInCol; + if (ChosenPivot != NULL) + { /* Reduced column has no elements, matrix is singular. */ + break; + } + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, + Step ) + ) return ChosenPivot; + else + { if (Matrix->MarkowitzRow[I] == 0) + { ChosenPivot = Matrix->FirstInRow[I]; + while((ChosenPivot != NULL) AND (ChosenPivot->ColNextInRow; + if (ChosenPivot != NULL) + { /* Reduced row has no elements, matrix is singular. */ + break; + } + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, + ChosenPivot, + Step ) + ) return ChosenPivot; + } + } + } + else + { ChosenPivot = Matrix->FirstInRow[I]; + while ((ChosenPivot != NULL) AND (ChosenPivot->Col < Step)) + ChosenPivot = ChosenPivot->NextInRow; + if (ChosenPivot != NULL) + { /* Reduced row has no elements, matrix is singular. */ + break; + } + PivotMag = ELEMENT_MAG(ChosenPivot); + if + ( PivotMag > Matrix->AbsThreshold AND + PivotMag > Matrix->RelThreshold * + FindBiggestInColExclude( Matrix, ChosenPivot, + Step ) + ) return ChosenPivot; + } + } +/* Singleton not acceptable (too small), try another. */ + } /* end of while(lSingletons>0) */ + +/* + * All singletons were unacceptable. Restore Matrix->Singletons count. + * Initial assumption that an acceptable singleton would be found was wrong. + */ + Matrix->Singletons++; + return NULL; +} + + + + + + + + + + + + +#if DIAGONAL_PIVOTING +#if MODIFIED_MARKOWITZ +/* + * QUICK SEARCH OF DIAGONAL FOR PIVOT WITH MODIFIED MARKOWITZ CRITERION + * + * Searches the diagonal looking for the best pivot. For a pivot to be + * acceptable it must be larger than the pivot RelThreshold times the largest + * element in its reduced column. Among the acceptable diagonals, the + * one with the smallest MarkowitzProduct is sought. Search terminates + * early if a diagonal is found with a MarkowitzProduct of one and its + * magnitude is larger than the other elements in its row and column. + * Since its MarkowitzProduct is one, there is only one other element in + * both its row and column, and, as a condition for early termination, + * these elements must be located symmetricly in the matrix. If a tie + * occurs between elements of equal MarkowitzProduct, then the element with + * the largest ratio between its magnitude and the largest element in its + * column is used. The search will be terminated after a given number of + * ties have occurred and the best (largest ratio) of the tied element will + * be used as the pivot. The number of ties that will trigger an early + * termination is MinMarkowitzProduct * TIES_MULTIPLIER. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no diagonal is + * acceptable, a NULL is returned. + * + * >>> Arguments: + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * LargestOffDiagonal (RealNumber) + * Magnitude of the largest of the off-diagonal terms associated with + * a diagonal with MarkowitzProduct equal to one. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MaxRatio (RealNumber) + * Among the elements tied with the smallest Markowitz product, MaxRatio + * is the best (smallest) ratio of LargestInCol to the diagonal Magnitude + * found so far. The smaller the ratio, the better numerically the + * element will be as pivot. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of pivot candidates that lie along + * diagonal. + * NumberOfTies (int) + * A count of the number of Markowitz ties that have occurred at current + * MarkowitzProduct. + * pDiag (ElementPtr) + * Pointer to current diagonal element. + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + * Ratio (RealNumber) + * For the current pivot candidate, Ratio is the ratio of the largest + * element in its column (excluding itself) to its magnitude. + * TiedElements (ElementPtr[]) + * Array of pointers to the elements with the minimum Markowitz + * product. + * pOtherInCol (ElementPtr) + * When there is only one other element in a column other than the + * diagonal, pOtherInCol is used to point to it. Used when Markowitz + * product is to determine if off diagonals are placed symmetricly. + * pOtherInRow (ElementPtr) + * When there is only one other element in a row other than the diagonal, + * pOtherInRow is used to point to it. Used when Markowitz product is + * to determine if off diagonals are placed symmetricly. + */ + +static ElementPtr +QuicklySearchDiagonal( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register long MinMarkowitzProduct, *pMarkowitzProduct; +register ElementPtr pDiag, pOtherInRow, pOtherInCol; +int I, NumberOfTies; +ElementPtr ChosenPivot, TiedElements[MAX_MARKOWITZ_TIES + 1]; +RealNumber Magnitude, LargestInCol, Ratio, MaxRatio; +RealNumber LargestOffDiagonal; +RealNumber FindBiggestInColExclude(); + +/* Begin `QuicklySearchDiagonal'. */ + NumberOfTies = -1; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]); + Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; + +/* Assure that following while loop will always terminate. */ + Matrix->MarkowitzProd[Step-1] = -1; + +/* + * This is tricky. Am using a pointer in the inner while loop to + * sequentially step through the MarkowitzProduct array. Search + * terminates when the Markowitz product of zero placed at location + * Step-1 is found. The row (and column)strchr on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element. The outer for loop is infinite, broken by using + * break. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ + + for(;;) /* Endless for loop. */ + { while (MinMarkowitzProduct < *(--pMarkowitzProduct)) + { /* + * N bottles of beer on the wall; + * N bottles of beer. + * You take one down and pass it around; + * N-1 bottles of beer on the wall. + */ + } + + I = pMarkowitzProduct - Matrix->MarkowitzProd; + +/* Assure that I is valid; if I < Step, terminate search. */ + if (I < Step) break; /* Endless for loop */ + if (I > Matrix->Size) I = Step; + + if ((pDiag = Matrix->Diag[I]) == NULL) + continue; /* Endless for loop */ + if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) + continue; /* Endless for loop */ + + if (*pMarkowitzProduct == 1) + { +/* Case where only one element exists in row and column other than diagonal. */ + +/* Find off diagonal elements. */ + pOtherInRow = pDiag->NextInRow; + pOtherInCol = pDiag->NextInCol; + if (pOtherInRow == NULL AND pOtherInCol == NULL) + { pOtherInRow = Matrix->FirstInRow[I]; + while(pOtherInRow != NULL) + { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I) + break; + pOtherInRow = pOtherInRow->NextInRow; + } + pOtherInCol = Matrix->FirstInCol[I]; + while(pOtherInCol != NULL) + { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I) + break; + pOtherInCol = pOtherInCol->NextInCol; + } + } + +/* Accept diagonal as pivot if diagonal is larger than off diagonals and the + * off diagonals are placed symmetricly. */ + if (pOtherInRow != NULL AND pOtherInCol != NULL) + { if (pOtherInRow->Col == pOtherInCol->Row) + { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), + ELEMENT_MAG(pOtherInCol)); + if (Magnitude >= LargestOffDiagonal) + { +/* Accept pivot, it is unlikely to contribute excess error. */ + return pDiag; + } + } + } + } + + if (*pMarkowitzProduct < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ + TiedElements[0] = pDiag; + MinMarkowitzProduct = *pMarkowitzProduct; + NumberOfTies = 0; + } + else + { +/* This case handles Markowitz ties. */ + if (NumberOfTies < MAX_MARKOWITZ_TIES) + { TiedElements[++NumberOfTies] = pDiag; + if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) + break; /* Endless for loop */ + } + } + } /* End of endless for loop. */ + +/* Test to see if any element was chosen as a pivot candidate. */ + if (NumberOfTies < 0) + return NULL; + +/* Determine which of tied elements is best numerically. */ + ChosenPivot = NULL; + MaxRatio = 1.0 / Matrix->RelThreshold; + + for (I = 0; I <= NumberOfTies; I++) + { pDiag = TiedElements[I]; + Magnitude = ELEMENT_MAG(pDiag); + LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step ); + Ratio = LargestInCol / Magnitude; + if (Ratio < MaxRatio) + { ChosenPivot = pDiag; + MaxRatio = Ratio; + } + } + return ChosenPivot; +} + + + + + + + + + + +#else /* Not MODIFIED_MARKOWITZ */ +/* + * QUICK SEARCH OF DIAGONAL FOR PIVOT WITH CONVENTIONAL MARKOWITZ + * CRITERION + * + * Searches the diagonal looking for the best pivot. For a pivot to be + * acceptable it must be larger than the pivot RelThreshold times the largest + * element in its reduced column. Among the acceptable diagonals, the + * one with the smallest MarkowitzProduct is sought. Search terminates + * early if a diagonal is found with a MarkowitzProduct of one and its + * magnitude is larger than the other elements in its row and column. + * Since its MarkowitzProduct is one, there is only one other element in + * both its row and column, and, as a condition for early termination, + * these elements must be located symmetricly in the matrix. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no diagonal is + * acceptable, a NULL is returned. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * LargestOffDiagonal (RealNumber) + * Magnitude of the largest of the off-diagonal terms associated with + * a diagonal with MarkowitzProduct equal to one. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of pivot candidates which are + * acceptable. + * pDiag (ElementPtr) + * Pointer to current diagonal element. + * pMarkowitzProduct (long *) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + * pOtherInCol (ElementPtr) + * When there is only one other element in a column other than the + * diagonal, pOtherInCol is used to point to it. Used when Markowitz + * product is to determine if off diagonals are placed symmetricly. + * pOtherInRow (ElementPtr) + * When there is only one other element in a row other than the diagonal, + * pOtherInRow is used to point to it. Used when Markowitz product is + * to determine if off diagonals are placed symmetricly. + */ + +static ElementPtr +QuicklySearchDiagonal( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register long MinMarkowitzProduct, *pMarkowitzProduct; +register ElementPtr pDiag; +int I; +ElementPtr ChosenPivot, pOtherInRow, pOtherInCol; +RealNumber Magnitude, LargestInCol, LargestOffDiagonal; +RealNumber FindBiggestInColExclude(); + +/* Begin `QuicklySearchDiagonal'. */ + ChosenPivot = NULL; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + pMarkowitzProduct = &(Matrix->MarkowitzProd[Matrix->Size+2]); + Matrix->MarkowitzProd[Matrix->Size+1] = Matrix->MarkowitzProd[Step]; + +/* Assure that following while loop will always terminate. */ + Matrix->MarkowitzProd[Step-1] = -1; + +/* + * This is tricky. Am using a pointer in the inner while loop to + * sequentially step through the MarkowitzProduct array. Search + * terminates when the Markowitz product of zero placed at location + * Step-1 is found. The row (and column)strchr on the diagonal is then + * calculated by subtracting the pointer to the Markowitz product of + * the first diagonal from the pointer to the Markowitz product of the + * desired element. The outer for loop is infinite, broken by using + * break. + * + * Search proceeds from the end (high row and column numbers) to the + * beginning (low row and column numbers) so that rows and columns with + * large Markowitz products will tend to be move to the bottom of the + * matrix. However, choosing Diag[Step] is desirable because it would + * require no row and column interchanges, so inspect it first by + * putting its Markowitz product at the end of the MarkowitzProd + * vector. + */ + + for (;;) /* Endless for loop. */ + { while (*(--pMarkowitzProduct) >= MinMarkowitzProduct) + { /* Just passing through. */ + } + + I = pMarkowitzProduct - Matrix->MarkowitzProd; + +/* Assure that I is valid; if I < Step, terminate search. */ + if (I < Step) break; /* Endless for loop */ + if (I > Matrix->Size) I = Step; + + if ((pDiag = Matrix->Diag[I]) == NULL) + continue; /* Endless for loop */ + if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) + continue; /* Endless for loop */ + + if (*pMarkowitzProduct == 1) + { +/* Case where only one element exists in row and column other than diagonal. */ + +/* Find off-diagonal elements. */ + pOtherInRow = pDiag->NextInRow; + pOtherInCol = pDiag->NextInCol; + if (pOtherInRow == NULL AND pOtherInCol == NULL) + { pOtherInRow = Matrix->FirstInRow[I]; + while(pOtherInRow != NULL) + { if (pOtherInRow->Col >= Step AND pOtherInRow->Col != I) + break; + pOtherInRow = pOtherInRow->NextInRow; + } + pOtherInCol = Matrix->FirstInCol[I]; + while(pOtherInCol != NULL) + { if (pOtherInCol->Row >= Step AND pOtherInCol->Row != I) + break; + pOtherInCol = pOtherInCol->NextInCol; + } + } + +/* Accept diagonal as pivot if diagonal is larger than off-diagonals and the + * off-diagonals are placed symmetricly. */ + if (pOtherInRow != NULL AND pOtherInCol != NULL) + { if (pOtherInRow->Col == pOtherInCol->Row) + { LargestOffDiagonal = MAX(ELEMENT_MAG(pOtherInRow), + ELEMENT_MAG(pOtherInCol)); + if (Magnitude >= LargestOffDiagonal) + { +/* Accept pivot, it is unlikely to contribute excess error. */ + return pDiag; + } + } + } + } + + MinMarkowitzProduct = *pMarkowitzProduct; + ChosenPivot = pDiag; + } /* End of endless for loop. */ + + if (ChosenPivot != NULL) + { LargestInCol = FindBiggestInColExclude( Matrix, ChosenPivot, Step ); + if( ELEMENT_MAG(ChosenPivot) <= Matrix->RelThreshold * LargestInCol ) + ChosenPivot = NULL; + } + return ChosenPivot; +} +#endif /* Not MODIFIED_MARKOWITZ */ + + + + + + + + + +/* + * SEARCH DIAGONAL FOR PIVOT WITH MODIFIED MARKOWITZ CRITERION + * + * Searches the diagonal looking for the best pivot. For a pivot to be + * acceptable it must be larger than the pivot RelThreshold times the largest + * element in its reduced column. Among the acceptable diagonals, the + * one with the smallest MarkowitzProduct is sought. If a tie occurs + * between elements of equal MarkowitzProduct, then the element with + * the largest ratio between its magnitude and the largest element in its + * column is used. The search will be terminated after a given number of + * ties have occurred and the best (smallest ratio) of the tied element will + * be used as the pivot. The number of ties that will trigger an early + * termination is MinMarkowitzProduct * TIES_MULTIPLIER. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no diagonal is + * acceptable, a NULL is returned. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * Size (int) + * Local version of size which is placed in a register to increase speed. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of those pivot candidates which are + * acceptable. + * NumberOfTies (int) + * A count of the number of Markowitz ties that have occurred at current + * MarkowitzProduct. + * pDiag (ElementPtr) + * Pointer to current diagonal element. + * pMarkowitzProduct (long*) + * Pointer that points into MarkowitzProduct array. It is used to quickly + * access successive Markowitz products. + * Ratio (RealNumber) + * For the current pivot candidate, Ratio is the + * Ratio of the largest element in its column to its magnitude. + * RatioOfAccepted (RealNumber) + * For the best pivot candidate found so far, RatioOfAccepted is the + * Ratio of the largest element in its column to its magnitude. + */ + +static ElementPtr +SearchDiagonal( Matrix, Step ) + +MatrixPtr Matrix; +register int Step; +{ +register int J; +register long MinMarkowitzProduct, *pMarkowitzProduct; +register int I; +register ElementPtr pDiag; +int NumberOfTies, Size = Matrix->Size; +ElementPtr ChosenPivot; +RealNumber Magnitude, Ratio, RatioOfAccepted, LargestInCol; +RealNumber FindBiggestInColExclude(); + +/* Begin `SearchDiagonal'. */ + ChosenPivot = NULL; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + pMarkowitzProduct = &(Matrix->MarkowitzProd[Size+2]); + Matrix->MarkowitzProd[Size+1] = Matrix->MarkowitzProd[Step]; + +/* Start search of diagonal. */ + for (J = Size+1; J > Step; J--) + { + if (*(--pMarkowitzProduct) > MinMarkowitzProduct) + continue; /* for loop */ + if (J > Matrix->Size) + I = Step; + else + I = J; + if ((pDiag = Matrix->Diag[I]) == NULL) + continue; /* for loop */ + if ((Magnitude = ELEMENT_MAG(pDiag)) <= Matrix->AbsThreshold) + continue; /* for loop */ + +/* Test to see if diagonal's magnitude is acceptable. */ + LargestInCol = FindBiggestInColExclude( Matrix, pDiag, Step ); + if (Magnitude <= Matrix->RelThreshold * LargestInCol) + continue; /* for loop */ + + if (*pMarkowitzProduct < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ + ChosenPivot = pDiag; + MinMarkowitzProduct = *pMarkowitzProduct; + RatioOfAccepted = LargestInCol / Magnitude; + NumberOfTies = 0; + } + else + { +/* This case handles Markowitz ties. */ + NumberOfTies++; + Ratio = LargestInCol / Magnitude; + if (Ratio < RatioOfAccepted) + { ChosenPivot = pDiag; + RatioOfAccepted = Ratio; + } + if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) + return ChosenPivot; + } + } /* End of for(Step) */ + return ChosenPivot; +} +#endif /* DIAGONAL_PIVOTING */ + + + + + + + + + + +/* + * SEARCH ENTIRE MATRIX FOR BEST PIVOT + * + * Performs a search over the entire matrix looking for the acceptable + * element with the lowest MarkowitzProduct. If there are several that + * are tied for the smallest MarkowitzProduct, the tie is broken by using + * the ratio of the magnitude of the element being considered to the largest + * element in the same column. If no element is acceptable then the largest + * element in the reduced submatrix is used as the pivot and the + * matrix is declared to be spSMALL_PIVOT. If the largest element is + * zero, the matrix is declared to be spSINGULAR. + * + * >>> Returned: + * A pointer to the diagonal element chosen to be pivot. If no element is + * found, then NULL is returned and the matrix is spSINGULAR. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * ChosenPivot (ElementPtr) + * Pointer to the element that has been chosen to be the pivot. + * LargestElementMag (RealNumber) + * Magnitude of the largest element yet found in the reduced submatrix. + * Size (int) + * Local version of Size; placed in a register for speed. + * Magnitude (RealNumber) + * Absolute value of diagonal element. + * MinMarkowitzProduct (long) + * Smallest Markowitz product found of pivot candidates which are + * acceptable. + * NumberOfTies (int) + * A count of the number of Markowitz ties that have occurred at current + * MarkowitzProduct. + * pElement (ElementPtr) + * Pointer to current element. + * pLargestElement (ElementPtr) + * Pointer to the largest element yet found in the reduced submatrix. + * Product (long) + * Markowitz product for the current row and column. + * Ratio (RealNumber) + * For the current pivot candidate, Ratio is the + * Ratio of the largest element in its column to its magnitude. + * RatioOfAccepted (RealNumber) + * For the best pivot candidate found so far, RatioOfAccepted is the + * Ratio of the largest element in its column to its magnitude. + * + * >>> Possible errors: + * spSINGULAR + * spSMALL_PIVOT + */ + +static ElementPtr +SearchEntireMatrix( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +register int I, Size = Matrix->Size; +register ElementPtr pElement; +int NumberOfTies; +long Product, MinMarkowitzProduct; +ElementPtr ChosenPivot, pLargestElement; +RealNumber Magnitude, LargestElementMag, Ratio, RatioOfAccepted, LargestInCol; +RealNumber FindLargestInCol(); + +/* Begin `SearchEntireMatrix'. */ + ChosenPivot = NULL; + LargestElementMag = 0.0; + MinMarkowitzProduct = LARGEST_LONG_INTEGER; + +/* Start search of matrix on column by column basis. */ + for (I = Step; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + + while (pElement != NULL AND pElement->Row < Step) + pElement = pElement->NextInCol; + + if((LargestInCol = FindLargestInCol(pElement)) == 0.0) + continue; /* for loop */ + + while (pElement != NULL) + { +/* Check to see if element is the largest encountered so far. If so, record + its magnitude and address. */ + if ((Magnitude = ELEMENT_MAG(pElement)) > LargestElementMag) + { LargestElementMag = Magnitude; + pLargestElement = pElement; + } +/* Calculate element's MarkowitzProduct. */ + Product = Matrix->MarkowitzRow[pElement->Row] * + Matrix->MarkowitzCol[pElement->Col]; + +/* Test to see if element is acceptable as a pivot candidate. */ + if ((Product <= MinMarkowitzProduct) AND + (Magnitude > Matrix->RelThreshold * LargestInCol) AND + (Magnitude > Matrix->AbsThreshold)) + { +/* Test to see if element has lowest MarkowitzProduct yet found, or whether it + is tied with an element found earlier. */ + if (Product < MinMarkowitzProduct) + { +/* Notice strict inequality in test. This is a new smallest MarkowitzProduct. */ + ChosenPivot = pElement; + MinMarkowitzProduct = Product; + RatioOfAccepted = LargestInCol / Magnitude; + NumberOfTies = 0; + } + else + { +/* This case handles Markowitz ties. */ + NumberOfTies++; + Ratio = LargestInCol / Magnitude; + if (Ratio < RatioOfAccepted) + { ChosenPivot = pElement; + RatioOfAccepted = Ratio; + } + if (NumberOfTies >= MinMarkowitzProduct * TIES_MULTIPLIER) + return ChosenPivot; + } + } + pElement = pElement->NextInCol; + } /* End of while(pElement != NULL) */ + } /* End of for(Step) */ + + if (ChosenPivot != NULL) return ChosenPivot; + + if (LargestElementMag == 0.0) + { Matrix->Error = spSINGULAR; + return NULL; + } + + Matrix->Error = spSMALL_PIVOT; + return pLargestElement; +} + + + + + + + + + + + + +/* + * DETERMINE THE MAGNITUDE OF THE LARGEST ELEMENT IN A COLUMN + * + * This routine searches a column and returns the magnitude of the largest + * element. This routine begins the search at the element pointed to by + * pElement, the parameter. + * + * The search is conducted by starting at the element specified by a pointer, + * which should be one below the diagonal, and moving down the column. On + * the way down the column, the magnitudes of the elements are tested to see + * if they are the largest yet found. + * + * >>> Returned: + * The magnitude of the largest element in the column below and including + * the one pointed to by the input parameter. + * + * >>> Arguments: + * pElement (ElementPtr) + * The pointer to the first element to be tested. Also, used by the + * routine to access all lower elements in the column. + * + * >>> Local variables: + * Largest (RealNumber) + * The magnitude of the largest element. + * Magnitude (RealNumber) + * The magnitude of the currently active element. + */ + +static RealNumber +FindLargestInCol( pElement ) + +register ElementPtr pElement; +{ +RealNumber Magnitude, Largest = 0.0; + +/* Begin `FindLargestInCol'. */ +/* Search column for largest element beginning at Element. */ + while (pElement != NULL) + { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) + Largest = Magnitude; + pElement = pElement->NextInCol; + } + + return Largest; +} + + + + + + + + + + +/* + * DETERMINE THE MAGNITUDE OF THE LARGEST ELEMENT IN A COLUMN + * EXCLUDING AN ELEMENT + * + * This routine searches a column and returns the magnitude of the largest + * element. One given element is specifically excluded from the search. + * + * The search is conducted by starting at the first element in the column + * and moving down the column until the active part of the matrix is entered, + * i.e. the reduced submatrix. The rest of the column is then traversed + * looking for the largest element. + * + * >>> Returned: + * The magnitude of the largest element in the active portion of the column, + * excluding the specified element, is returned. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * pElement (ElementPtr) + * The pointer to the element that is to be excluded from search. Column + * to be searched is one that contains this element. Also used to + * access the elements in the column. + * Step (int) + * Index of the diagonal currently being eliminated. Indicates where + * the active part of the matrix begins. + * + * >>> Local variables: + * Col (int) + * The number of the column to be searched. Also the column number of + * the element to be avoided in the search. + * Largest (RealNumber) + * The magnitude of the largest element. + * Magnitude (RealNumber) + * The magnitude of the currently active element. + * Row (int) + * The row number of element to be excluded from the search. + */ + +static RealNumber +FindBiggestInColExclude( Matrix, pElement, Step ) + +MatrixPtr Matrix; +register ElementPtr pElement; +register int Step; +{ +register int Row; +int Col; +RealNumber Largest, Magnitude; + +/* Begin `FindBiggestInColExclude'. */ + Row = pElement->Row; + Col = pElement->Col; + pElement = Matrix->FirstInCol[Col]; + +/* Travel down column until reduced submatrix is entered. */ + while ((pElement != NULL) AND (pElement->Row < Step)) + pElement = pElement->NextInCol; + +/* Initialize the variable Largest. */ + if (pElement->Row != Row) + Largest = ELEMENT_MAG(pElement); + else + Largest = 0.0; + +/* Search rest of column for largest element, avoiding excluded element. */ + while ((pElement = pElement->NextInCol) != NULL) + { if ((Magnitude = ELEMENT_MAG(pElement)) > Largest) + { if (pElement->Row != Row) + Largest = Magnitude; + } + } + + return Largest; +} + + + + + + + + + + +/* + * EXCHANGE ROWS AND COLUMNS + * + * Exchanges two rows and two columns so that the selected pivot is moved to + * the upper left corner of the remaining submatrix. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * pPivot (ElementPtr) + * Pointer to the current pivot. + * Step (int) + * Index of the diagonal currently being eliminated. + * + * >>> Local variables: + * Col (int) + * Column where the pivot was found. + * Row (int) + * Row where the pivot was found. + * OldMarkowitzProd_Col (long) + * Markowitz product associated with the diagonal element in the row + * the pivot was found in. + * OldMarkowitzProd_Row (long) + * Markowitz product associated with the diagonal element in the column + * the pivot was found in. + * OldMarkowitzProd_Step (long) + * Markowitz product associated with the diagonal element that is being + * moved so that the pivot can be placed in the upper left-hand corner + * of the reduced submatrix. + */ + +static void +ExchangeRowsAndCols( Matrix, pPivot, Step ) + +MatrixPtr Matrix; +ElementPtr pPivot; +register int Step; +{ +register int Row, Col; +long OldMarkowitzProd_Step, OldMarkowitzProd_Row, OldMarkowitzProd_Col; +ElementPtr spcFindElementInCol(); + +/* Begin `ExchangeRowsAndCols'. */ + Row = pPivot->Row; + Col = pPivot->Col; + Matrix->PivotsOriginalRow = Row; + Matrix->PivotsOriginalCol = Col; + + if ((Row == Step) AND (Col == Step)) return; + +/* Exchange rows and columns. */ + if (Row == Col) + { spcRowExchange( Matrix, Step, Row ); + spcColExchange( Matrix, Step, Col ); + SWAP( long, Matrix->MarkowitzProd[Step], Matrix->MarkowitzProd[Row] ); + SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Step] ); + } + else + { + +/* Initialize variables that hold old Markowitz products. */ + OldMarkowitzProd_Step = Matrix->MarkowitzProd[Step]; + OldMarkowitzProd_Row = Matrix->MarkowitzProd[Row]; + OldMarkowitzProd_Col = Matrix->MarkowitzProd[Col]; + +/* Exchange rows. */ + if (Row != Step) + { spcRowExchange( Matrix, Step, Row ); + Matrix->NumberOfInterchangesIsOdd = + NOT Matrix->NumberOfInterchangesIsOdd; + Matrix->MarkowitzProd[Row] = Matrix->MarkowitzRow[Row] * + Matrix->MarkowitzCol[Row]; + +/* Update singleton count. */ + if ((Matrix->MarkowitzProd[Row]==0) != (OldMarkowitzProd_Row==0)) + { if (OldMarkowitzProd_Row == 0) + Matrix->Singletons--; + else + Matrix->Singletons++; + } + } + +/* Exchange columns. */ + if (Col != Step) + { spcColExchange( Matrix, Step, Col ); + Matrix->NumberOfInterchangesIsOdd = + NOT Matrix->NumberOfInterchangesIsOdd; + Matrix->MarkowitzProd[Col] = Matrix->MarkowitzCol[Col] * + Matrix->MarkowitzRow[Col]; + +/* Update singleton count. */ + if ((Matrix->MarkowitzProd[Col]==0) != (OldMarkowitzProd_Col==0)) + { if (OldMarkowitzProd_Col == 0) + Matrix->Singletons--; + else + Matrix->Singletons++; + } + + Matrix->Diag[Col] = spcFindElementInCol( Matrix, + Matrix->FirstInCol+Col, + Col, Col, NO ); + } + if (Row != Step) + { Matrix->Diag[Row] = spcFindElementInCol( Matrix, + Matrix->FirstInCol+Row, + Row, Row, NO ); + } + Matrix->Diag[Step] = spcFindElementInCol( Matrix, + Matrix->FirstInCol+Step, + Step, Step, NO ); + +/* Update singleton count. */ + Matrix->MarkowitzProd[Step] = Matrix->MarkowitzCol[Step] * + Matrix->MarkowitzRow[Step]; + if ((Matrix->MarkowitzProd[Step]==0) != (OldMarkowitzProd_Step==0)) + { if (OldMarkowitzProd_Step == 0) + Matrix->Singletons--; + else + Matrix->Singletons++; + } + } + return; +} + + + + + + + + + +/* + * EXCHANGE ROWS + * + * Performs all required operations to exchange two rows. Those operations + * include: swap FirstInRow pointers, fixing up the NextInCol pointers, + * swapping rowstrchres in MatrixElements, and swapping Markowitz row + * counts. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * Row1 (int) + * Rowstrchr of one of the rows, becomes the smalleststrchr. + * Row2 (int) + * Rowstrchr of the other row, becomes the largeststrchr. + * + * Local variables: + * Column (int) + * Column in which row elements are currently being exchanged. + * Row1Ptr (ElementPtr) + * Pointer to an element in Row1. + * Row2Ptr (ElementPtr) + * Pointer to an element in Row2. + * Element1 (ElementPtr) + * Pointer to the element in Row1 to be exchanged. + * Element2 (ElementPtr) + * Pointer to the element in Row2 to be exchanged. + */ + +void +spcRowExchange( Matrix, Row1, Row2 ) + +MatrixPtr Matrix; +int Row1, Row2; +{ +register ElementPtr Row1Ptr, Row2Ptr; +int Column; +ElementPtr Element1, Element2; + +/* Begin `spcRowExchange'. */ + if (Row1 > Row2) SWAP(int, Row1, Row2); + + Row1Ptr = Matrix->FirstInRow[Row1]; + Row2Ptr = Matrix->FirstInRow[Row2]; + while (Row1Ptr != NULL OR Row2Ptr != NULL) + { +/* Exchange elements in rows while traveling from left to right. */ + if (Row1Ptr == NULL) + { Column = Row2Ptr->Col; + Element1 = NULL; + Element2 = Row2Ptr; + Row2Ptr = Row2Ptr->NextInRow; + } + else if (Row2Ptr == NULL) + { Column = Row1Ptr->Col; + Element1 = Row1Ptr; + Element2 = NULL; + Row1Ptr = Row1Ptr->NextInRow; + } + else if (Row1Ptr->Col < Row2Ptr->Col) + { Column = Row1Ptr->Col; + Element1 = Row1Ptr; + Element2 = NULL; + Row1Ptr = Row1Ptr->NextInRow; + } + else if (Row1Ptr->Col > Row2Ptr->Col) + { Column = Row2Ptr->Col; + Element1 = NULL; + Element2 = Row2Ptr; + Row2Ptr = Row2Ptr->NextInRow; + } + else /* Row1Ptr->Col == Row2Ptr->Col */ + { Column = Row1Ptr->Col; + Element1 = Row1Ptr; + Element2 = Row2Ptr; + Row1Ptr = Row1Ptr->NextInRow; + Row2Ptr = Row2Ptr->NextInRow; + } + + ExchangeColElements( Matrix, Row1, Element1, Row2, Element2, Column); + } /* end of while(Row1Ptr != NULL OR Row2Ptr != NULL) */ + + if (Matrix->InternalVectorsAllocated) + SWAP( int, Matrix->MarkowitzRow[Row1], Matrix->MarkowitzRow[Row2]); + SWAP( ElementPtr, Matrix->FirstInRow[Row1], Matrix->FirstInRow[Row2]); + SWAP( int, Matrix->IntToExtRowMap[Row1], Matrix->IntToExtRowMap[Row2]); +#if TRANSLATE + Matrix->ExtToIntRowMap[ Matrix->IntToExtRowMap[Row1] ] = Row1; + Matrix->ExtToIntRowMap[ Matrix->IntToExtRowMap[Row2] ] = Row2; +#endif + + return; +} + + + + + + + + + +/* + * EXCHANGE COLUMNS + * + * Performs all required operations to exchange two columns. Those operations + * include: swap FirstInCol pointers, fixing up the NextInRow pointers, + * swapping columnstrchres in MatrixElements, and swapping Markowitz + * column counts. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * Col1 (int) + * Columnstrchr of one of the columns, becomes the smalleststrchr. + * Col2 (int) + * Columnstrchr of the other column, becomes the largeststrchr + * + * Local variables: + * Row (int) + * Row in which column elements are currently being exchanged. + * Col1Ptr (ElementPtr) + * Pointer to an element in Col1. + * Col2Ptr (ElementPtr) + * Pointer to an element in Col2. + * Element1 (ElementPtr) + * Pointer to the element in Col1 to be exchanged. + * Element2 (ElementPtr) + * Pointer to the element in Col2 to be exchanged. + */ + +void +spcColExchange( Matrix, Col1, Col2 ) + +MatrixPtr Matrix; +int Col1, Col2; +{ +register ElementPtr Col1Ptr, Col2Ptr; +int Row; +ElementPtr Element1, Element2; + +/* Begin `spcColExchange'. */ + if (Col1 > Col2) SWAP(int, Col1, Col2); + + Col1Ptr = Matrix->FirstInCol[Col1]; + Col2Ptr = Matrix->FirstInCol[Col2]; + while (Col1Ptr != NULL OR Col2Ptr != NULL) + { +/* Exchange elements in rows while traveling from top to bottom. */ + if (Col1Ptr == NULL) + { Row = Col2Ptr->Row; + Element1 = NULL; + Element2 = Col2Ptr; + Col2Ptr = Col2Ptr->NextInCol; + } + else if (Col2Ptr == NULL) + { Row = Col1Ptr->Row; + Element1 = Col1Ptr; + Element2 = NULL; + Col1Ptr = Col1Ptr->NextInCol; + } + else if (Col1Ptr->Row < Col2Ptr->Row) + { Row = Col1Ptr->Row; + Element1 = Col1Ptr; + Element2 = NULL; + Col1Ptr = Col1Ptr->NextInCol; + } + else if (Col1Ptr->Row > Col2Ptr->Row) + { Row = Col2Ptr->Row; + Element1 = NULL; + Element2 = Col2Ptr; + Col2Ptr = Col2Ptr->NextInCol; + } + else /* Col1Ptr->Row == Col2Ptr->Row */ + { Row = Col1Ptr->Row; + Element1 = Col1Ptr; + Element2 = Col2Ptr; + Col1Ptr = Col1Ptr->NextInCol; + Col2Ptr = Col2Ptr->NextInCol; + } + + ExchangeRowElements( Matrix, Col1, Element1, Col2, Element2, Row); + } /* end of while(Col1Ptr != NULL OR Col2Ptr != NULL) */ + + if (Matrix->InternalVectorsAllocated) + SWAP( int, Matrix->MarkowitzCol[Col1], Matrix->MarkowitzCol[Col2]); + SWAP( ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]); + SWAP( int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]); +#if TRANSLATE + Matrix->ExtToIntColMap[ Matrix->IntToExtColMap[Col1] ] = Col1; + Matrix->ExtToIntColMap[ Matrix->IntToExtColMap[Col2] ] = Col2; +#endif + + return; +} + + + + + + + +/* + * EXCHANGE TWO ELEMENTS IN A COLUMN + * + * Performs all required operations to exchange two elements in a column. + * Those operations are: restring NextInCol pointers and swapping rowstrchres + * in the MatrixElements. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * Row1 (int) + * Row of top element to be exchanged. + * Element1 (ElementPtr) + * Pointer to top element to be exchanged. + * Row2 (int) + * Row of bottom element to be exchanged. + * Element2 (ElementPtr) + * Pointer to bottom element to be exchanged. + * Column (int) + * Column that exchange is to take place in. + * + * >>> Local variables: + * ElementAboveRow1 (ElementPtr *) + * Location of pointer which points to the element above Element1. This + * pointer is modified so that it points to correct element on exit. + * ElementAboveRow2 (ElementPtr *) + * Location of pointer which points to the element above Element2. This + * pointer is modified so that it points to correct element on exit. + * ElementBelowRow1 (ElementPtr) + * Pointer to element below Element1. + * ElementBelowRow2 (ElementPtr) + * Pointer to element below Element2. + * pElement (ElementPtr) + * Pointer used to traverse the column. + */ + +static void +ExchangeColElements( Matrix, Row1, Element1, Row2, Element2, Column ) + +MatrixPtr Matrix; +register ElementPtr Element1, Element2; +int Row1, Row2, Column; +{ +ElementPtr *ElementAboveRow1, *ElementAboveRow2; +ElementPtr ElementBelowRow1, ElementBelowRow2; +register ElementPtr pElement; + +/* Begin `ExchangeColElements'. */ +/* Search to find the ElementAboveRow1. */ + ElementAboveRow1 = &(Matrix->FirstInCol[Column]); + pElement = *ElementAboveRow1; + while (pElement->Row < Row1) + { ElementAboveRow1 = &(pElement->NextInCol); + pElement = *ElementAboveRow1; + } + if (Element1 != NULL) + { ElementBelowRow1 = Element1->NextInCol; + if (Element2 == NULL) + { +/* Element2 does not exist, move Element1 down to Row2. */ + if ( ElementBelowRow1 != NULL AND ElementBelowRow1->Row < Row2 ) + { +/* Element1 must be removed from linked list and moved. */ + *ElementAboveRow1 = ElementBelowRow1; + +/* Search column for Row2. */ + pElement = ElementBelowRow1; + do + { ElementAboveRow2 = &(pElement->NextInCol); + pElement = *ElementAboveRow2; + } while (pElement != NULL AND pElement->Row < Row2); + +/* Place Element1 in Row2. */ + *ElementAboveRow2 = Element1; + Element1->NextInCol = pElement; + *ElementAboveRow1 =ElementBelowRow1; + } + Element1->Row = Row2; + } + else + { +/* Element2 does exist, and the two elements must be exchanged. */ + if ( ElementBelowRow1->Row == Row2) + { +/* Element2 is just below Element1, exchange them. */ + Element1->NextInCol = Element2->NextInCol; + Element2->NextInCol = Element1; + *ElementAboveRow1 = Element2; + } + else + { +/* Element2 is not just below Element1 and must be searched for. */ + pElement = ElementBelowRow1; + do + { ElementAboveRow2 = &(pElement->NextInCol); + pElement = *ElementAboveRow2; + } while (pElement->Row < Row2); + + ElementBelowRow2 = Element2->NextInCol; + +/* Switch Element1 and Element2. */ + *ElementAboveRow1 = Element2; + Element2->NextInCol = ElementBelowRow1; + *ElementAboveRow2 = Element1; + Element1->NextInCol = ElementBelowRow2; + } + Element1->Row = Row2; + Element2->Row = Row1; + } + } + else + { +/* Element1 does not exist. */ + ElementBelowRow1 = pElement; + +/* Find Element2. */ + if (ElementBelowRow1->Row != Row2) + { do + { ElementAboveRow2 = &(pElement->NextInCol); + pElement = *ElementAboveRow2; + } while (pElement->Row < Row2); + + ElementBelowRow2 = Element2->NextInCol; + +/* Move Element2 to Row1. */ + *ElementAboveRow2 = Element2->NextInCol; + *ElementAboveRow1 = Element2; + Element2->NextInCol = ElementBelowRow1; + } + Element2->Row = Row1; + } + return; +} + + + + + + + +/* + * EXCHANGE TWO ELEMENTS IN A ROW + * + * Performs all required operations to exchange two elements in a row. + * Those operations are: restring NextInRow pointers and swapping column + * strchres in the MatrixElements. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * Col1 (int) + * Col of left-most element to be exchanged. + * Element1 (ElementPtr) + * Pointer to left-most element to be exchanged. + * Col2 (int) + * Col of right-most element to be exchanged. + * Element2 (ElementPtr) + * Pointer to right-most element to be exchanged. + * Row (int) + * Row that exchange is to take place in. + * + * >>> Local variables: + * ElementLeftOfCol1 (ElementPtr *) + * Location of pointer which points to the element to the left of + * Element1. This pointer is modified so that it points to correct + * element on exit. + * ElementLeftOfCol2 (ElementPtr *) + * Location of pointer which points to the element to the left of + * Element2. This pointer is modified so that it points to correct + * element on exit. + * ElementRightOfCol1 (ElementPtr) + * Pointer to element right of Element1. + * ElementRightOfCol2 (ElementPtr) + * Pointer to element right of Element2. + * pElement (ElementPtr) + * Pointer used to traverse the row. + */ + +static void +ExchangeRowElements( Matrix, Col1, Element1, Col2, Element2, Row ) + +MatrixPtr Matrix; +int Col1, Col2, Row; +register ElementPtr Element1, Element2; +{ +ElementPtr *ElementLeftOfCol1, *ElementLeftOfCol2; +ElementPtr ElementRightOfCol1, ElementRightOfCol2; +register ElementPtr pElement; + +/* Begin `ExchangeRowElements'. */ +/* Search to find the ElementLeftOfCol1. */ + ElementLeftOfCol1 = &(Matrix->FirstInRow[Row]); + pElement = *ElementLeftOfCol1; + while (pElement->Col < Col1) + { ElementLeftOfCol1 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol1; + } + if (Element1 != NULL) + { ElementRightOfCol1 = Element1->NextInRow; + if (Element2 == NULL) + { +/* Element2 does not exist, move Element1 to right to Col2. */ + if ( ElementRightOfCol1 != NULL AND ElementRightOfCol1->Col < Col2 ) + { +/* Element1 must be removed from linked list and moved. */ + *ElementLeftOfCol1 = ElementRightOfCol1; + +/* Search Row for Col2. */ + pElement = ElementRightOfCol1; + do + { ElementLeftOfCol2 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol2; + } while (pElement != NULL AND pElement->Col < Col2); + +/* Place Element1 in Col2. */ + *ElementLeftOfCol2 = Element1; + Element1->NextInRow = pElement; + *ElementLeftOfCol1 =ElementRightOfCol1; + } + Element1->Col = Col2; + } + else + { +/* Element2 does exist, and the two elements must be exchanged. */ + if ( ElementRightOfCol1->Col == Col2) + { +/* Element2 is just right of Element1, exchange them. */ + Element1->NextInRow = Element2->NextInRow; + Element2->NextInRow = Element1; + *ElementLeftOfCol1 = Element2; + } + else + { +/* Element2 is not just right of Element1 and must be searched for. */ + pElement = ElementRightOfCol1; + do + { ElementLeftOfCol2 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol2; + } while (pElement->Col < Col2); + + ElementRightOfCol2 = Element2->NextInRow; + +/* Switch Element1 and Element2. */ + *ElementLeftOfCol1 = Element2; + Element2->NextInRow = ElementRightOfCol1; + *ElementLeftOfCol2 = Element1; + Element1->NextInRow = ElementRightOfCol2; + } + Element1->Col = Col2; + Element2->Col = Col1; + } + } + else + { +/* Element1 does not exist. */ + ElementRightOfCol1 = pElement; + +/* Find Element2. */ + if (ElementRightOfCol1->Col != Col2) + { do + { ElementLeftOfCol2 = &(pElement->NextInRow); + pElement = *ElementLeftOfCol2; + } while (pElement->Col < Col2); + + ElementRightOfCol2 = Element2->NextInRow; + +/* Move Element2 to Col1. */ + *ElementLeftOfCol2 = Element2->NextInRow; + *ElementLeftOfCol1 = Element2; + Element2->NextInRow = ElementRightOfCol1; + } + Element2->Col = Col1; + } + return; +} + + + + + + + + + + + +/* + * PERFORM ROW AND COLUMN ELIMINATION ON REAL MATRIX + * + * Eliminates a single row and column of the matrix and leaves single row of + * the upper triangular matrix and a single column of the lower triangular + * matrix in its wake. Uses Gauss's method. + * + * >>> Argument: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * pPivot (ElementPtr) + * Pointer to the current pivot. + * + * >>> Local variables: + * pLower (ElementPtr) + * Points to matrix element in lower triangular column. + * pSub (ElementPtr) + * Points to elements in the reduced submatrix. + * Row (int) + * Rowstrchr. + * pUpper (ElementPtr) + * Points to matrix element in upper triangular row. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static void +RealRowColElimination( Matrix, pPivot ) + +MatrixPtr Matrix; +register ElementPtr pPivot; +{ +#if REAL +register ElementPtr pSub; +register int Row; +register ElementPtr pLower, pUpper; +extern ElementPtr CreateFillin(); + +/* Begin `RealRowColElimination'. */ + +/* Test for zero pivot. */ + if (ABS(pPivot->Real) == 0.0) + { (void)MatrixIsSingular( Matrix, pPivot->Row ); + return; + } + pPivot->Real = 1.0 / pPivot->Real; + + pUpper = pPivot->NextInRow; + while (pUpper != NULL) + { +/* Calculate upper triangular element. */ + pUpper->Real *= pPivot->Real; + + pSub = pUpper->NextInCol; + pLower = pPivot->NextInCol; + while (pLower != NULL) + { Row = pLower->Row; + +/* Find element in row that lines up with current lower triangular element. */ + while (pSub != NULL AND pSub->Row < Row) + pSub = pSub->NextInCol; + +/* Test to see if desired element was not found, if not, create fill-in. */ + if (pSub == NULL OR pSub->Row > Row) + { pSub = CreateFillin( Matrix, Row, pUpper->Col ); + if (pSub == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + } + pSub->Real -= pUpper->Real * pLower->Real; + pSub = pSub->NextInCol; + pLower = pLower->NextInCol; + } + pUpper = pUpper->NextInRow; + } + return; +#endif /* REAL */ +} + + + + + + + + + +/* + * PERFORM ROW AND COLUMN ELIMINATION ON COMPLEX MATRIX + * + * Eliminates a single row and column of the matrix and leaves single row of + * the upper triangular matrix and a single column of the lower triangular + * matrix in its wake. Uses Gauss's method. + * + * >>> Argument: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * pPivot (ElementPtr) + * Pointer to the current pivot. + * + * >>> Local variables: + * pLower (ElementPtr) + * Points to matrix element in lower triangular column. + * pSub (ElementPtr) + * Points to elements in the reduced submatrix. + * Row (int) + * Rowstrchr. + * pUpper (ElementPtr) + * Points to matrix element in upper triangular row. + * + * Possible errors: + * spNO_MEMORY + */ + +static void +ComplexRowColElimination( Matrix, pPivot ) + +MatrixPtr Matrix; +register ElementPtr pPivot; +{ +#if spCOMPLEX +register ElementPtr pSub; +register int Row; +register ElementPtr pLower, pUpper; +ElementPtr CreateFillin(); + +/* Begin `ComplexRowColElimination'. */ + +/* Test for zero pivot. */ + if (ELEMENT_MAG(pPivot) == 0.0) + { (void)MatrixIsSingular( Matrix, pPivot->Row ); + return; + } + CMPLX_RECIPROCAL(*pPivot, *pPivot); + + pUpper = pPivot->NextInRow; + while (pUpper != NULL) + { +/* Calculate upper triangular element. */ +/* Cmplx expr: *pUpper = *pUpper * (1.0 / *pPivot). */ + CMPLX_MULT_ASSIGN(*pUpper, *pPivot); + + pSub = pUpper->NextInCol; + pLower = pPivot->NextInCol; + while (pLower != NULL) + { Row = pLower->Row; + +/* Find element in row that lines up with current lower triangular element. */ + while (pSub != NULL AND pSub->Row < Row) + pSub = pSub->NextInCol; + +/* Test to see if desired element was not found, if not, create fill-in. */ + if (pSub == NULL OR pSub->Row > Row) + { pSub = CreateFillin( Matrix, Row, pUpper->Col ); + if (pSub == NULL) + { Matrix->Error = spNO_MEMORY; + return; + } + } + +/* Cmplx expr: pElement -= *pUpper * pLower. */ + CMPLX_MULT_SUBT_ASSIGN(*pSub, *pUpper, *pLower); + pSub = pSub->NextInCol; + pLower = pLower->NextInCol; + } + pUpper = pUpper->NextInRow; + } + return; +#endif /* spCOMPLEX */ +} + + + + + +/* + * UPDATE MARKOWITZ NUMBERS + * + * Updates the Markowitz numbers after a row and column have been eliminated. + * Also updates singleton count. + * + * >>> Argument: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * pPivot (ElementPtr) + * Pointer to the current pivot. + * + * >>> Local variables: + * Row (int) + * Rowstrchr. + * Col (int) + * Columnstrchr. + * ColPtr (ElementPtr) + * Points to matrix element in upper triangular column. + * RowPtr (ElementPtr) + * Points to matrix element in lower triangular row. + */ + +static void +UpdateMarkowitzNumbers( Matrix, pPivot ) + +MatrixPtr Matrix; +ElementPtr pPivot; +{ +register int Row, Col; +register ElementPtr ColPtr, RowPtr; +register int *MarkoRow = Matrix->MarkowitzRow, *MarkoCol = Matrix->MarkowitzCol; +double Product; + +/* Begin `UpdateMarkowitzNumbers'. */ + +/* Update Markowitz numbers. */ + for (ColPtr = pPivot->NextInCol; ColPtr != NULL; ColPtr = ColPtr->NextInCol) + { Row = ColPtr->Row; + --MarkoRow[Row]; + +/* Form Markowitz product while being cautious of overflows. */ + if ((MarkoRow[Row] > LARGEST_SHORT_INTEGER AND MarkoCol[Row] != 0) OR + (MarkoCol[Row] > LARGEST_SHORT_INTEGER AND MarkoRow[Row] != 0)) + { Product = MarkoCol[Row] * MarkoRow[Row]; + if (Product >= LARGEST_LONG_INTEGER) + Matrix->MarkowitzProd[Row] = LARGEST_LONG_INTEGER; + else + Matrix->MarkowitzProd[Row] = Product; + } + else Matrix->MarkowitzProd[Row] = MarkoRow[Row] * MarkoCol[Row]; + if (MarkoRow[Row] == 0) + Matrix->Singletons++; + } + + for (RowPtr = pPivot->NextInRow; RowPtr != NULL; RowPtr = RowPtr->NextInRow) + { Col = RowPtr->Col; + --MarkoCol[Col]; + +/* Form Markowitz product while being cautious of overflows. */ + if ((MarkoRow[Col] > LARGEST_SHORT_INTEGER AND MarkoCol[Col] != 0) OR + (MarkoCol[Col] > LARGEST_SHORT_INTEGER AND MarkoRow[Col] != 0)) + { Product = MarkoCol[Col] * MarkoRow[Col]; + if (Product >= LARGEST_LONG_INTEGER) + Matrix->MarkowitzProd[Col] = LARGEST_LONG_INTEGER; + else + Matrix->MarkowitzProd[Col] = Product; + } + else Matrix->MarkowitzProd[Col] = MarkoRow[Col] * MarkoCol[Col]; + if ((MarkoCol[Col] == 0) AND (MarkoRow[Col] != 0)) + Matrix->Singletons++; + } + return; +} + + + + + + + + +/* + * CREATE FILL-IN + * + * This routine is used to create fill-ins and splice them into the + * matrix. + * + * >>> Returns: + * Pointer to fill-in. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * Col (int) + * Columnstrchr for element. + * Row (int) + * Rowstrchr for element. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * ppElementAbove (ElementPtr *) + * This contains the address of the pointer to the element just above the + * one being created. It is used to speed the search and it is updated + * with address of the created element. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static ElementPtr +CreateFillin( Matrix, Row, Col ) + +MatrixPtr Matrix; +register int Row; +int Col; +{ +register ElementPtr pElement, *ppElementAbove; +ElementPtr spcCreateElement(); + +/* Begin `CreateFillin'. */ + +/* Find Element above fill-in. */ + ppElementAbove = &Matrix->FirstInCol[Col]; + pElement = *ppElementAbove; + while (pElement != NULL) + { if (pElement->Row < Row) + { ppElementAbove = &pElement->NextInCol; + pElement = *ppElementAbove; + } + else break; /* while loop */ + } + +/* End of search, create the element. */ + pElement = spcCreateElement( Matrix, Row, Col, ppElementAbove, YES ); + +/* Update Markowitz counts and products. */ + Matrix->MarkowitzProd[Row] = ++Matrix->MarkowitzRow[Row] * + Matrix->MarkowitzCol[Row]; + if ((Matrix->MarkowitzRow[Row] == 1) AND (Matrix->MarkowitzCol[Row] != 0)) + Matrix->Singletons--; + Matrix->MarkowitzProd[Col] = ++Matrix->MarkowitzCol[Col] * + Matrix->MarkowitzRow[Col]; + if ((Matrix->MarkowitzRow[Col] != 0) AND (Matrix->MarkowitzCol[Col] == 1)) + Matrix->Singletons--; + + return pElement; +} + + + + + + + + +/* + * ZERO PIVOT ENCOUNTERED + * + * This routine is called when a singular matrix is found. It then + * records the current row and column and exits. + * + * >>> Returned: + * The error code spSINGULAR or spZERO_DIAG is returned. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to matrix. + * Step (int) + * Index of diagonal that is zero. + */ + +static int +MatrixIsSingular( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +/* Begin `MatrixIsSingular'. */ + + Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ]; + Matrix->SingularCol = Matrix->IntToExtColMap[ Step ]; + return (Matrix->Error = spSINGULAR); +} + + +static int +ZeroPivot( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +/* Begin `ZeroPivot'. */ + + Matrix->SingularRow = Matrix->IntToExtRowMap[ Step ]; + Matrix->SingularCol = Matrix->IntToExtColMap[ Step ]; + return (Matrix->Error = spZERO_DIAG); +} + + + + + + +#if (ANNOTATE == FULL) + +/* + * + * WRITE STATUS + * + * Write a summary of important variables to standard output. + */ + +static void +WriteStatus( Matrix, Step ) + +MatrixPtr Matrix; +int Step; +{ +int I; + +/* Begin `WriteStatus'. */ + + printf("Step = %1d ", Step); + printf("Pivot found at %1d,%1d using ", Matrix->PivotsOriginalRow, + Matrix->PivotsOriginalCol); + switch(Matrix->PivotSelectionMethod) + { case 's': printf("SearchForSingleton\n"); break; + case 'q': printf("QuicklySearchDiagonal\n"); break; + case 'd': printf("SearchDiagonal\n"); break; + case 'e': printf("SearchEntireMatrix\n"); break; + } + + printf("MarkowitzRow = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->MarkowitzRow[I]); + printf("\n"); + + printf("MarkowitzCol = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->MarkowitzCol[I]); + printf("\n"); + + printf("MarkowitzProduct = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->MarkowitzProd[I]); + printf("\n"); + + printf("Singletons = %2d\n", Matrix->Singletons); + + printf("IntToExtRowMap = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->IntToExtRowMap[I]); + printf("\n"); + + printf("IntToExtColMap = "); + for (I = 1; I <= Matrix->Size; I++) + printf("%2d ", Matrix->IntToExtColMap[I]); + printf("\n"); + + printf("ExtToIntRowMap = "); + for (I = 1; I <= Matrix->ExtSize; I++) + printf("%2d ", Matrix->ExtToIntRowMap[I]); + printf("\n"); + + printf("ExtToIntColMap = "); + for (I = 1; I <= Matrix->ExtSize; I++) + printf("%2d ", Matrix->ExtToIntColMap[I]); + printf("\n\n"); + +/* spPrint((char *)Matrix, NO, YES); */ + + return; + +} +#endif /* ANNOTATE == FULL */ diff --git a/src/maths/sparse/spoutput.c b/src/maths/sparse/spoutput.c new file mode 100644 index 000000000..35cb3fd98 --- /dev/null +++ b/src/maths/sparse/spoutput.c @@ -0,0 +1,773 @@ +/* + * MATRIX OUTPUT MODULE + * + * Author: Advisor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the output-to-file and output-to-screen routines for + * the matrix package. + * + * >>> User accessible functions contained in this file: + * spPrint + * spFileMatrix + * spFileVector + * spFileStats + * + * >>> Other functions contained in this file: + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "$Header$"; +#endif + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" + +int Printer_Width = PRINTER_WIDTH; + + + + + +#if DOCUMENTATION + +/* + * PRINT MATRIX + * + * Formats and send the matrix to standard output. Some elementary + * statistics are also output. The matrix is output in a format that is + * readable by people. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * PrintReordered (int) + * Indicates whether the matrix should be printed out in its original + * form, as input by the user, or whether it should be printed in its + * reordered form, as used by the matrix routines. A zero indicates that + * the matrix should be printed as inputed, a one indicates that it + * should be printed reordered. + * Data (int) + * Boolean flag that when FALSE indicates that output should be + * compressed such that only the existence of an element should be + * indicated rather than giving the actual value. Thus 11 times as + * many can be printed on a row. A zero signifies that the matrix + * should be printed compressed. A one indicates that the matrix + * should be printed in all its glory. + * Header (int) + * Flag indicating that extra information should be given, such as row + * and column numbers. + * + * >>> Local variables: + * Col (int) + * Column being printed. + * ElementCount (int) + * Variable used to count the number of nonzero elements in the matrix. + * LargestElement (RealNumber) + * The magnitude of the largest element in the matrix. + * LargestDiag (RealNumber) + * The magnitude of the largest diagonal in the matrix. + * Magnitude (RealNumber) + * The absolute value of the matrix element being printed. + * PrintOrdToIntColMap (int []) + * A translation array that maps the order that columns will be + * printed in (if not PrintReordered) to the internal column numbers. + * PrintOrdToIntRowMap (int []) + * A translation array that maps the order that rows will be + * printed in (if not PrintReordered) to the internal row numbers. + * pElement (ElementPtr) + * Pointer to the element in the matrix that is to be printed. + * pImagElements (ElementPtr [ ]) + * Array of pointers to elements in the matrix. These pointers point + * to the elements whose real values have just been printed. They are + * used to quickly access those same elements so their imaginary values + * can be printed. + * Row (int) + * Row being printed. + * Size (int) + * The size of the matrix. + * SmallestDiag (RealNumber) + * The magnitude of the smallest diagonal in the matrix. + * SmallestElement (RealNumber) + * The magnitude of the smallest element in the matrix excluding zero + * elements. + * StartCol (int) + * The column number of the first column to be printed in the group of + * columns currently being printed. + * StopCol (int) + * The column number of the last column to be printed in the group of + * columns currently being printed. + * Top (int) + * The largest expected external row or column number. + */ + +void +spPrint( eMatrix, PrintReordered, Data, Header ) + +char *eMatrix; +int PrintReordered, Data, Header; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int J = 0; +int I, Row, Col, Size, Top, StartCol = 1, StopCol, Columns, ElementCount = 0; +double Magnitude, SmallestDiag, SmallestElement; +double LargestElement = 0.0, LargestDiag = 0.0; +ElementPtr pElement, *pImagElements; +int *PrintOrdToIntRowMap, *PrintOrdToIntColMap; + +/* Begin `spPrint'. */ + ASSERT( IS_SPARSE( Matrix ) ); + Size = Matrix->Size; + CALLOC(pImagElements, ElementPtr, Printer_Width / 10 + 1); + if ( pImagElements == NULL) + { Matrix->Error = spNO_MEMORY; + FREE(pImagElements); + return; + } + +/* Create a packed external to internal row and column translation array. */ +# if TRANSLATE + Top = Matrix->AllocatedExtSize; +#else + Top = Matrix->AllocatedSize; +#endif + CALLOC( PrintOrdToIntRowMap, int, Top + 1 ); + if ( PrintOrdToIntRowMap == NULL) + { Matrix->Error = spNO_MEMORY; + FREE(pImagElements); + return; + } + CALLOC( PrintOrdToIntColMap, int, Top + 1 ); + if (PrintOrdToIntColMap == NULL) + { Matrix->Error = spNO_MEMORY; + FREE(pImagElements); + FREE(PrintOrdToIntRowMap); + return; + } + for (I = 1; I <= Size; I++) + { PrintOrdToIntRowMap[ Matrix->IntToExtRowMap[I] ] = I; + PrintOrdToIntColMap[ Matrix->IntToExtColMap[I] ] = I; + } + +/* Pack the arrays. */ + for (J = 1, I = 1; I <= Top; I++) + { if (PrintOrdToIntRowMap[I] != 0) + PrintOrdToIntRowMap[ J++ ] = PrintOrdToIntRowMap[ I ]; + } + for (J = 1, I = 1; I <= Top; I++) + { if (PrintOrdToIntColMap[I] != 0) + PrintOrdToIntColMap[ J++ ] = PrintOrdToIntColMap[ I ]; + } + +/* Print header. */ + if (Header) + { printf("MATRIX SUMMARY\n\n"); + printf("Size of matrix = %1d x %1d.\n", Size, Size); + if ( Matrix->Reordered AND PrintReordered ) + printf("Matrix has been reordered.\n"); + putchar('\n'); + + if ( Matrix->Factored ) + printf("Matrix after factorization:\n"); + else + printf("Matrix before factorization:\n"); + + SmallestElement = LARGEST_REAL; + SmallestDiag = SmallestElement; + } + +/* Determine how many columns to use. */ + Columns = Printer_Width; + if (Header) Columns -= 5; + if (Data) Columns = (Columns+1) / 10; + +/* + * Print matrix by printing groups of complete columns until all the columns + * are printed. + */ + J = 0; + while ( J <= Size ) + +/* Calculatestrchr of last column to printed in this group. */ + { StopCol = StartCol + Columns - 1; + if (StopCol > Size) + StopCol = Size; + +/* Label the columns. */ + if (Header) + { if (Data) + { printf(" "); + for (I = StartCol; I <= StopCol; I++) + { if (PrintReordered) + Col = I; + else + Col = PrintOrdToIntColMap[I]; + printf(" %9d", Matrix->IntToExtColMap[ Col ]); + } + printf("\n\n"); + } + else + { if (PrintReordered) + printf("Columns %1d to %1d.\n",StartCol,StopCol); + else + { printf("Columns %1d to %1d.\n", + Matrix->IntToExtColMap[ PrintOrdToIntColMap[StartCol] ], + Matrix->IntToExtColMap[ PrintOrdToIntColMap[StopCol] ]); + } + } + } + +/* Print every row ... */ + for (I = 1; I <= Size; I++) + { if (PrintReordered) + Row = I; + else + Row = PrintOrdToIntRowMap[I]; + + if (Header) + { if (PrintReordered AND NOT Data) + printf("%4d", I); + else + printf("%4d", Matrix->IntToExtRowMap[ Row ]); + if (NOT Data) putchar(' '); + } + +/* ... in each column of the group. */ + for (J = StartCol; J <= StopCol; J++) + { if (PrintReordered) + Col = J; + else + Col = PrintOrdToIntColMap[J]; + + pElement = Matrix->FirstInCol[Col]; + while(pElement != NULL AND pElement->Row != Row) + pElement = pElement->NextInCol; + + if (Data) + pImagElements[J - StartCol] = pElement; + + if (pElement != NULL) + +/* Case where element exists */ + { if (Data) + printf(" %9.3g", (double)pElement->Real); + else + putchar('x'); + +/* Update status variables */ + if ( (Magnitude = ELEMENT_MAG(pElement)) > LargestElement ) + LargestElement = Magnitude; + if ((Magnitude < SmallestElement) AND (Magnitude != 0.0)) + SmallestElement = Magnitude; + ElementCount++; + } + +/* Case where element is structurally zero */ + else + { if (Data) + printf(" ..."); + else + putchar('.'); + } + } + putchar('\n'); + +#if spCOMPLEX + if (Matrix->Complex AND Data) + { printf(" "); + for (J = StartCol; J <= StopCol; J++) + { if (pImagElements[J - StartCol] != NULL) + { printf(" %8.2gj", + (double)pImagElements[J-StartCol]->Imag); + } + else printf(" "); + } + putchar('\n'); + } +#endif /* spCOMPLEX */ + } + +/* Calculatestrchr of first column in next group. */ + StartCol = StopCol; + StartCol++; + putchar('\n'); + } + if (Header) + { printf("\nLargest element in matrix = %-1.4g.\n", LargestElement); + printf("Smallest element in matrix = %-1.4g.\n", SmallestElement); + +/* Search for largest and smallest diagonal values */ + for (I = 1; I <= Size; I++) + { if (Matrix->Diag[I] != NULL) + { Magnitude = ELEMENT_MAG( Matrix->Diag[I] ); + if ( Magnitude > LargestDiag ) LargestDiag = Magnitude; + if ( Magnitude < SmallestDiag ) SmallestDiag = Magnitude; + } + } + + /* Print the largest and smallest diagonal values */ + if ( Matrix->Factored ) + { printf("\nLargest diagonal element = %-1.4g.\n", LargestDiag); + printf("Smallest diagonal element = %-1.4g.\n", SmallestDiag); + } + else + { printf("\nLargest pivot element = %-1.4g.\n", LargestDiag); + printf("Smallest pivot element = %-1.4g.\n", SmallestDiag); + } + + /* Calculate and print sparsity and number of fill-ins created. */ + printf("\nDensity = %2.2f%%.\n", ((double)(ElementCount * 100)) / + ((double)(Size * Size))); + + printf("Number of originals = %1d.\n", Matrix->Originals); + if (NOT Matrix->NeedsOrdering) + printf("Number of fill-ins = %1d.\n", Matrix->Fillins); + } + putchar('\n'); + (void)fflush(stdout); + + FREE(PrintOrdToIntColMap); + FREE(PrintOrdToIntRowMap); + return; +} + + + + + + + + + + + +/* + * OUTPUT MATRIX TO FILE + * + * Writes matrix to file in format suitable to be read back in by the + * matrix test program. + * + * >>> Returns: + * One is returned if routine was successful, otherwise zero is returned. + * The calling function can query errno (the system global error variable) + * as to the reason why this routine failed. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * File (char *) + * Name of file into which matrix is to be written. + * Label (char *) + * String that is transferred to file and is used as a label. + * Reordered (BOOLEAN) + * Specifies whether matrix should be output in reordered form, + * or in original order. + * Data (BOOLEAN) + * Indicates that the element values should be output along with + * the indices for each element. This parameter must be TRUE if + * matrix is to be read by the sparse test program. + * Header (BOOLEAN) + * Indicates that header is desired. This parameter must be TRUE if + * matrix is to be read by the sparse test program. + * + * >>> Local variables: + * Col (int) + * The original column number of the element being output. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pMatrixFile (FILE *) + * File pointer to the matrix file. + * Row (int) + * The original row number of the element being output. + * Size (int) + * The size of the matrix. + */ + +int +spFileMatrix( eMatrix, File, Label, Reordered, Data, Header ) + +char *eMatrix, *Label, *File; +int Reordered, Data, Header; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size; +register ElementPtr pElement; +int Row, Col, Err; +FILE *pMatrixFile, *fopen(); + +/* Begin `spFileMatrix'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Open file matrix file in write mode. */ + if ((pMatrixFile = fopen(File, "w")) == NULL) + return 0; + +/* Output header. */ + Size = Matrix->Size; + if (Header) + { if (Matrix->Factored AND Data) + { Err = fprintf + ( pMatrixFile, + "Warning : The following matrix is factored in to LU form.\n" + ); + if (Err < 0) return 0; + } + if (fprintf(pMatrixFile, "%s\n", Label) < 0) return 0; + Err = fprintf( pMatrixFile, "%d\t%s\n", Size, + (Matrix->Complex ? "complex" : "real")); + if (Err < 0) return 0; + } + +/* Output matrix. */ + if (NOT Data) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { if (Reordered) + { Row = pElement->Row; + Col = I; + } + else + { Row = Matrix->IntToExtRowMap[pElement->Row]; + Col = Matrix->IntToExtColMap[I]; + } + pElement = pElement->NextInCol; + if (fprintf(pMatrixFile, "%d\t%d\n", Row, Col) < 0) return 0; + } + } +/* Output terminator, a line of zeros. */ + if (Header) + if (fprintf(pMatrixFile, "0\t0\n") < 0) return 0; + } + +#if spCOMPLEX + if (Data AND Matrix->Complex) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { if (Reordered) + { Row = pElement->Row; + Col = I; + } + else + { Row = Matrix->IntToExtRowMap[pElement->Row]; + Col = Matrix->IntToExtColMap[I]; + } + Err = fprintf + ( pMatrixFile,"%d\t%d\t%-.15g\t%-.15g\n", + Row, Col, (double)pElement->Real, (double)pElement->Imag + ); + if (Err < 0) return 0; + pElement = pElement->NextInCol; + } + } +/* Output terminator, a line of zeros. */ + if (Header) + if (fprintf(pMatrixFile,"0\t0\t0.0\t0.0\n") < 0) return 0; + + } +#endif /* spCOMPLEX */ + +#if REAL + if (Data AND NOT Matrix->Complex) + { for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { Row = Matrix->IntToExtRowMap[pElement->Row]; + Col = Matrix->IntToExtColMap[I]; + Err = fprintf + ( pMatrixFile,"%d\t%d\t%-.15g\n", + Row, Col, (double)pElement->Real + ); + if (Err < 0) return 0; + pElement = pElement->NextInCol; + } + } +/* Output terminator, a line of zeros. */ + if (Header) + if (fprintf(pMatrixFile,"0\t0\t0.0\n") < 0) return 0; + + } +#endif /* REAL */ + +/* Close file. */ + if (fclose(pMatrixFile) < 0) return 0; + return 1; +} + + + + + + + +/* + * OUTPUT SOURCE VECTOR TO FILE + * + * Writes vector to file in format suitable to be read back in by the + * matrix test program. This routine should be executed after the function + * spFileMatrix. + * + * >>> Returns: + * One is returned if routine was successful, otherwise zero is returned. + * The calling function can query errno (the system global error variable) + * as to the reason why this routine failed. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * File (char *) + * Name of file into which matrix is to be written. + * RHS (RealNumber []) + * Right-hand side vector. This is only the real portion if + * spSEPARATED_COMPLEX_VECTORS is TRUE. + * iRHS (RealNumber []) + * Right-hand side vector, imaginary portion. Not necessary if matrix + * is real or if spSEPARATED_COMPLEX_VECTORS is set FALSE. + * + * >>> Local variables: + * pMatrixFile (FILE *) + * File pointer to the matrix file. + * Size (int) + * The size of the matrix. + * + * >>> Obscure Macros + * IMAG_RHS + * Replaces itself with `, iRHS' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +int +spFileVector( eMatrix, File, RHS IMAG_RHS ) + +char *eMatrix, *File; +RealVector RHS IMAG_RHS; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size, Err; +FILE *pMatrixFile; +FILE *fopen(); + +/* Begin `spFileVector'. */ + ASSERT( IS_SPARSE( Matrix ) AND RHS != NULL) + +/* Open File in append mode. */ + if ((pMatrixFile = fopen(File,"a")) == NULL) + return 0; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spCOMPLEX + if (Matrix->Complex) + { +#if spSEPARATED_COMPLEX_VECTORS + ASSERT(iRHS != NULL) + --RHS; + --iRHS; +#else + RHS -= 2; +#endif + } + else +#endif /* spCOMPLEX */ + --RHS; +#endif /* NOT ARRAY_OFFSET */ + + +/* Output vector. */ + Size = Matrix->Size; +#if spCOMPLEX + if (Matrix->Complex) + { +#if spSEPARATED_COMPLEX_VECTORS + for (I = 1; I <= Size; I++) + { Err = fprintf + ( pMatrixFile, "%-.15g\t%-.15g\n", + (double)RHS[I], (double)iRHS[I] + ); + if (Err < 0) return 0; + } +#else + for (I = 1; I <= Size; I++) + { Err = fprintf + ( pMatrixFile, "%-.15g\t%-.15g\n", + (double)RHS[2*I], (double)RHS[2*I+1] + ); + if (Err < 0) return 0; + } +#endif + } +#endif /* spCOMPLEX */ +#if REAL AND spCOMPLEX + else +#endif +#if REAL + { for (I = 1; I <= Size; I++) + { if (fprintf(pMatrixFile, "%-.15g\n", (double)RHS[I]) < 0) + return 0; + } + } +#endif /* REAL */ + +/* Close file. */ + if (fclose(pMatrixFile) < 0) return 0; + return 1; +} + + + + + + + + + +/* + * OUTPUT STATISTICS TO FILE + * + * Writes useful information concerning the matrix to a file. Should be + * executed after the matrix is factored. + * + * >>> Returns: + * One is returned if routine was successful, otherwise zero is returned. + * The calling function can query errno (the system global error variable) + * as to the reason why this routine failed. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * File (char *) + * Name of file into which matrix is to be written. + * Label (char *) + * String that is transferred to file and is used as a label. + * + * >>> Local variables: + * Data (RealNumber) + * The value of the matrix element being output. + * LargestElement (RealNumber) + * The largest element in the matrix. + * NumberOfElements (int) + * Number of nonzero elements in the matrix. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pStatsFile (FILE *) + * File pointer to the statistics file. + * Size (int) + * The size of the matrix. + * SmallestElement (RealNumber) + * The smallest element in the matrix excluding zero elements. + */ + +int +spFileStats( eMatrix, File, Label ) + +char *eMatrix, *File, *Label; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int Size, I; +register ElementPtr pElement; +int NumberOfElements; +RealNumber Data, LargestElement, SmallestElement; +FILE *pStatsFile, *fopen(); + +/* Begin `spFileStats'. */ + ASSERT( IS_SPARSE( Matrix ) ); + +/* Open File in append mode. */ + if ((pStatsFile = fopen(File, "a")) == NULL) + return 0; + +/* Output statistics. */ + Size = Matrix->Size; + if (NOT Matrix->Factored) + fprintf(pStatsFile, "Matrix has not been factored.\n"); + fprintf(pStatsFile, "||| Starting new matrix |||\n"); + fprintf(pStatsFile, "%s\n", Label); + if (Matrix->Complex) + fprintf(pStatsFile, "Matrix is complex.\n"); + else + fprintf(pStatsFile, "Matrix is real.\n"); + fprintf(pStatsFile," Size = %d\n",Size); + +/* Search matrix. */ + NumberOfElements = 0; + LargestElement = 0.0; + SmallestElement = LARGEST_REAL; + + for (I = 1; I <= Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { NumberOfElements++; + Data = ELEMENT_MAG(pElement); + if (Data > LargestElement) + LargestElement = Data; + if (Data < SmallestElement AND Data != 0.0) + SmallestElement = Data; + pElement = pElement->NextInCol; + } + } + + SmallestElement = MIN( SmallestElement, LargestElement ); + +/* Output remaining statistics. */ + fprintf(pStatsFile, " Initial number of elements = %d\n", + NumberOfElements - Matrix->Fillins); + fprintf(pStatsFile, + " Initial average number of elements per row = %f\n", + (double)(NumberOfElements - Matrix->Fillins) / (double)Size); + fprintf(pStatsFile, " Fill-ins = %d\n",Matrix->Fillins); + fprintf(pStatsFile, " Average number of fill-ins per row = %f%%\n", + (double)Matrix->Fillins / (double)Size); + fprintf(pStatsFile, " Total number of elements = %d\n", + NumberOfElements); + fprintf(pStatsFile, " Average number of elements per row = %f\n", + (double)NumberOfElements / (double)Size); + fprintf(pStatsFile," Density = %f%%\n", + (double)(100.0*NumberOfElements)/(double)(Size*Size)); + fprintf(pStatsFile," Relative Threshold = %e\n", Matrix->RelThreshold); + fprintf(pStatsFile," Absolute Threshold = %e\n", Matrix->AbsThreshold); + fprintf(pStatsFile," Largest Element = %e\n", LargestElement); + fprintf(pStatsFile," Smallest Element = %e\n\n\n", SmallestElement); + +/* Close file. */ + (void)fclose(pStatsFile); + return 1; +} +#endif /* DOCUMENTATION */ diff --git a/src/maths/sparse/spsmp.c b/src/maths/sparse/spsmp.c new file mode 100644 index 000000000..39af150e5 --- /dev/null +++ b/src/maths/sparse/spsmp.c @@ -0,0 +1,620 @@ +/* + * Spice3 COMPATIBILITY MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This module contains routines that make Sparse1.3 a direct + * replacement for the SMP sparse matrix package in Spice3c1 or Spice3d1. + * Sparse1.3 is in general a faster and more robust package than SMP. + * These advantages become significant on large circuits. + * + * >>> User accessible functions contained in this file: + * SMPaddElt + * SMPmakeElt + * SMPcClear + * SMPclear + * SMPcLUfac + * SMPluFac + * SMPcReorder + * SMPreorder + * SMPcaSolve + * SMPcSolve + * SMPsolve + * SMPmatSize + * SMPnewMatrix + * SMPdestroy + * SMPpreOrder + * SMPprint + * SMPgetError + * SMPcProdDiag + * LoadGmin + * SMPfindElt + * SMPcombine + * SMPcCombine + */ + +/* + * To replace SMP with Sparse, rename the file spSpice3.h to + * spMatrix.h and place Sparse in a subdirectory of SPICE called + * `sparse'. Then on UNIX compile Sparse by executing `make spice'. + * If not on UNIX, after compiling Sparse and creating the sparse.a + * archive, compile this file (spSMP.c) and spSMP.o to the archive, + * then copy sparse.a into the SPICE main directory and rename it + * SMP.a. Finally link SPICE. + * + * To be compatible with SPICE, the following Sparse compiler options + * (in spConfig.h) should be set as shown below: + * + * REAL YES + * EXPANDABLE YES + * TRANSLATE NO + * INITIALIZE NO or YES, YES for use with test prog. + * DIAGONAL_PIVOTING YES + * ARRAY_OFFSET YES + * MODIFIED_MARKOWITZ NO + * DELETE NO + * STRIP NO + * MODIFIED_NODAL YES + * QUAD_ELEMENT NO + * TRANSPOSE YES + * SCALING NO + * DOCUMENTATION YES + * MULTIPLICATION NO + * DETERMINANT YES + * STABILITY NO + * CONDITION NO + * PSEUDOCONDITION NO + * FORTRAN NO + * DEBUG YES + * spCOMPLEX 1 + * spSEPARATED_COMPLEX_VECTORS 1 + * spCOMPATIBILITY 0 + * + * spREAL double + */ + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and supporting + * documentation and that the authors and the University of California + * are properly credited. The authors and the University of California + * make no representations as to the suitability of this software for + * any purpose. It is provided `as is', without express or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header$"; +#endif + + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spMatrix.h + * Sparse macros and declarations. + * SMPdefs.h + * Spice3's matrix macro definitions. + */ + +#include "ngspice.h" +#include +#include "spmatrix.h" +#include "smpdefs.h" +#include "spdefs.h" + +/* #define NO 0 */ +/* #define YES 1 */ + +#ifdef __STDC__ +static void LoadGmin( char * /*eMatrix*/, double /*Gmin*/ ); +#else +static void LoadGmin( ); +#endif + +/* + * SMPaddElt() + */ +int +SMPaddElt( Matrix, Row, Col, Value ) +SMPmatrix *Matrix; +int Row, Col; +double Value; +{ + *spGetElement( (char *)Matrix, Row, Col ) = Value; + return spError( (char *)Matrix ); +} + +/* + * SMPmakeElt() + */ +double * +SMPmakeElt( Matrix, Row, Col ) +SMPmatrix *Matrix; +int Row, Col; +{ + return spGetElement( (char *)Matrix, Row, Col ); +} + +/* + * SMPcClear() + */ +void +SMPcClear( Matrix ) +SMPmatrix *Matrix; +{ + spClear( (char *)Matrix ); +} + +/* + * SMPclear() + */ +void +SMPclear( Matrix ) +SMPmatrix *Matrix; +{ + spClear( (char *)Matrix ); +} + +/* + * SMPcLUfac() + */ +/*ARGSUSED*/ +int +SMPcLUfac( Matrix, PivTol ) +SMPmatrix *Matrix; +double PivTol; +{ + spSetComplex( (char *)Matrix ); + return spFactor( (char *)Matrix ); +} + +/* + * SMPluFac() + */ +/*ARGSUSED*/ +int +SMPluFac( Matrix, PivTol, Gmin ) +SMPmatrix *Matrix; +double PivTol, Gmin; +{ + spSetReal( (char *)Matrix ); + LoadGmin( (char *)Matrix, Gmin ); + return spFactor( (char *)Matrix ); +} + +/* + * SMPcReorder() + */ +int +SMPcReorder( Matrix, PivTol, PivRel, NumSwaps ) +SMPmatrix *Matrix; +double PivTol, PivRel; +int *NumSwaps; +{ + *NumSwaps = 1; + spSetComplex( (char *)Matrix ); + return spOrderAndFactor( (char *)Matrix, (spREAL*)NULL, + (spREAL)PivRel, (spREAL)PivTol, YES ); +} + +/* + * SMPreorder() + */ +int +SMPreorder( Matrix, PivTol, PivRel, Gmin ) +SMPmatrix *Matrix; +double PivTol, PivRel, Gmin; +{ + spSetReal( (char *)Matrix ); + LoadGmin( (char *)Matrix, Gmin ); + return spOrderAndFactor( (char *)Matrix, (spREAL*)NULL, + (spREAL)PivRel, (spREAL)PivTol, YES ); +} + +/* + * SMPcaSolve() + */ +void +SMPcaSolve( Matrix, RHS, iRHS, Spare, iSpare) +SMPmatrix *Matrix; +double RHS[], iRHS[], Spare[], iSpare[]; +{ + spSolveTransposed( (char *)Matrix, RHS, RHS, iRHS, iRHS ); +} + +/* + * SMPcSolve() + */ +void +SMPcSolve( Matrix, RHS, iRHS, Spare, iSpare) +SMPmatrix *Matrix; +double RHS[], iRHS[], Spare[], iSpare[]; +{ + spSolve( (char *)Matrix, RHS, RHS, iRHS, iRHS ); +} + +/* + * SMPsolve() + */ +void +SMPsolve( Matrix, RHS, Spare ) +SMPmatrix *Matrix; +double RHS[], Spare[]; +{ + spSolve( (char *)Matrix, RHS, RHS, (spREAL*)NULL, (spREAL*)NULL ); +} + +/* + * SMPmatSize() + */ +int +SMPmatSize( Matrix ) +SMPmatrix *Matrix; +{ + return spGetSize( (char *)Matrix, 1 ); +} + +/* + * SMPnewMatrix() + */ +int +SMPnewMatrix( pMatrix ) +SMPmatrix **pMatrix; +{ +int Error; + *pMatrix = (SMPmatrix *)spCreate( 0, 1, &Error ); + return Error; +} + +/* + * SMPdestroy() + */ +void +SMPdestroy( Matrix ) +SMPmatrix *Matrix; +{ + spDestroy( (char *)Matrix ); +} + +/* + * SMPpreOrder() + */ +int +SMPpreOrder( Matrix ) +SMPmatrix *Matrix; +{ + spMNA_Preorder( (char *)Matrix ); + return spError( (char *)Matrix ); +} + +/* + * SMPprint() + */ +/*ARGSUSED*/ +void +SMPprint( Matrix, File ) +SMPmatrix *Matrix; +FILE *File; +{ + spPrint( (char *)Matrix, 0, 1, 1 ); +} + +/* + * SMPgetError() + */ +void +SMPgetError( Matrix, Col, Row) +SMPmatrix *Matrix; +int *Row, *Col; +{ + spWhereSingular( (char *)Matrix, Row, Col ); +} + +/* + * SMPcProdDiag() + * note: obsolete for Spice3d2 and later + */ +int +SMPcProdDiag( Matrix, pMantissa, pExponent) +SMPmatrix *Matrix; +SPcomplex *pMantissa; +int *pExponent; +{ + spDeterminant( (char *)Matrix, pExponent, &(pMantissa->real), + &(pMantissa->imag) ); + return spError( (char *)Matrix ); +} + +/* + * SMPcDProd() + */ +int +SMPcDProd( Matrix, pMantissa, pExponent) +SMPmatrix *Matrix; +SPcomplex *pMantissa; +int *pExponent; +{ + double re, im, x, y, z; + int p; + + spDeterminant( (char *)Matrix, &p, &re, &im); + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 +#endif + +#ifdef debug_print + printf("Determinant 10: (%20g,%20g)^%d\n", re, im, p); +#endif + + /* Convert base 10 numbers to base 2 numbers, for comparison */ + y = p * M_LN10 / M_LN2; + x = (int) y; + y -= x; + + /* ASSERT + * x = integral part of exponent, y = fraction part of exponent + */ + + /* Fold in the fractional part */ +#ifdef debug_print + printf(" ** base10 -> base2 int = %g, frac = %20g\n", x, y); +#endif + z = pow(2.0, y); + re *= z; + im *= z; +#ifdef debug_print + printf(" ** multiplier = %20g\n", z); +#endif + + /* Re-normalize (re or im may be > 2.0 or both < 1.0 */ + if (re != 0.0) { + y = logb(re); + if (im != 0.0) + z = logb(im); + else + z = 0; + } else if (im != 0.0) { + z = logb(im); + y = 0; + } else { + /* Singular */ + /*printf("10 -> singular\n");*/ + y = 0; + z = 0; + } + +#ifdef debug_print + printf(" ** renormalize changes = %g,%g\n", y, z); +#endif + if (y < z) + y = z; + + *pExponent = x + y; + x = scalb(re, (int) -y); + z = scalb(im, (int) -y); +#ifdef debug_print + printf(" ** values are: re %g, im %g, y %g, re' %g, im' %g\n", + re, im, y, x, z); +#endif + pMantissa->real = scalb(re, (int) -y); + pMantissa->imag = scalb(im, (int) -y); + +#ifdef debug_print + printf("Determinant 10->2: (%20g,%20g)^%d\n", pMantissa->real, + pMantissa->imag, *pExponent); +#endif + return spError( (char *)Matrix ); +} + + + +/* + * The following routines need internal knowledge of the Sparse data + * structures. + */ + +/* + * LOAD GMIN + * + * This routine adds Gmin to each diagonal element. Because Gmin is + * added to the current diagonal, which may bear little relation to + * what the outside world thinks is a diagonal, and because the + * elements that are diagonals may change after calling spOrderAndFactor, + * use of this routine is not recommended. It is included here simply + * for compatibility with Spice3. + */ + +static void +LoadGmin( eMatrix, Gmin ) +char *eMatrix; +register double Gmin; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I; +register ArrayOfElementPtrs Diag; +register ElementPtr diag; + +/* Begin `LoadGmin'. */ + ASSERT( IS_SPARSE( Matrix ) ); + + if (Gmin != 0.0) { + Diag = Matrix->Diag; + for (I = Matrix->Size; I > 0; I--) { + if ((diag = Diag[I])) + diag->Real += Gmin; + } + } + return; +} + + + + +/* + * FIND ELEMENT + * + * This routine finds an element in the matrix by row and column number. + * If the element exists, a pointer to it is returned. If not, then NULL + * is returned unless the CreateIfMissing flag is TRUE, in which case a + * pointer to the new element is returned. + */ + +SMPelement * +SMPfindElt( eMatrix, Row, Col, CreateIfMissing ) + +SMPmatrix *eMatrix; +int Row, Col; +int CreateIfMissing; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +ElementPtr Element; + +/* Begin `SMPfindElt'. */ + ASSERT( IS_SPARSE( Matrix ) ); + Row = Matrix->ExtToIntRowMap[Row]; + Col = Matrix->ExtToIntColMap[Col]; + Element = Matrix->FirstInCol[Col]; + Element = spcFindElementInCol(Matrix, &Element, Row, Col, CreateIfMissing); + return (SMPelement *)Element; +} + +/* XXX The following should probably be implemented in spUtils */ + +/* + * SMPcZeroCol() + */ +int +SMPcZeroCol( Matrix, Col ) +MatrixPtr Matrix; +int Col; +{ + ElementPtr Element; + + Col = Matrix->ExtToIntColMap[Col]; + + for (Element = Matrix->FirstInCol[Col]; + Element != NULL; + Element = Element->NextInCol) + { + Element->Real = 0.0; + Element->Imag = 0.0; + } + + return spError( (char *)Matrix ); +} + +/* + * SMPcAddCol() + */ +int +SMPcAddCol( Matrix, Accum_Col, Addend_Col ) +MatrixPtr Matrix; +int Accum_Col, Addend_Col; +{ + ElementPtr Accum, Addend, *Prev; + + Accum_Col = Matrix->ExtToIntColMap[Accum_Col]; + Addend_Col = Matrix->ExtToIntColMap[Addend_Col]; + + Addend = Matrix->FirstInCol[Addend_Col]; + Prev = &Matrix->FirstInCol[Accum_Col]; + Accum = *Prev;; + + while (Addend != NULL) { + while (Accum && Accum->Row < Addend->Row) { + Prev = &Accum->NextInCol; + Accum = *Prev; + } + if (!Accum || Accum->Row > Addend->Row) { + Accum = spcCreateElement(Matrix, Addend->Row, Accum_Col, Prev, 0); + } + Accum->Real += Addend->Real; + Accum->Imag += Addend->Imag; + Addend = Addend->NextInCol; + } + + return spError( (char *)Matrix ); +} + +/* + * SMPzeroRow() + */ +int +SMPzeroRow( Matrix, Row ) +MatrixPtr Matrix; +int Row; +{ + ElementPtr Element; + + Row = Matrix->ExtToIntColMap[Row]; + + if (Matrix->RowsLinked == NO) + spcLinkRows(Matrix); + +#if spCOMPLEX + if (Matrix->PreviousMatrixWasComplex OR Matrix->Complex) { + for (Element = Matrix->FirstInRow[Row]; + Element != NULL; + Element = Element->NextInRow) + { + Element->Real = 0.0; + Element->Imag = 0.0; + } + } else +#endif + { + for (Element = Matrix->FirstInRow[Row]; + Element != NULL; + Element = Element->NextInRow) + { + Element->Real = 0.0; + } + } + + return spError( (char *)Matrix ); +} + +#ifdef PARALLEL_ARCH +/* + * SMPcombine() + */ +void +SMPcombine( Matrix, RHS, Spare ) +SMPmatrix *Matrix; +double RHS[], Spare[]; +{ + spSetReal( (char *)Matrix ); + spCombine( (char *)Matrix, RHS, Spare, (spREAL*)NULL, (spREAL*)NULL ); +} + +/* + * SMPcCombine() + */ +void +SMPcCombine( Matrix, RHS, Spare, iRHS, iSpare ) +SMPmatrix *Matrix; +double RHS[], Spare[]; +double iRHS[], iSpare[]; +{ + spSetComplex( (char *)Matrix ); + spCombine( (char *)Matrix, RHS, Spare, iRHS, iSpare ); +} +#endif /* PARALLEL_ARCH */ diff --git a/src/maths/sparse/spsolve.c b/src/maths/sparse/spsolve.c new file mode 100644 index 000000000..2b65a0ed8 --- /dev/null +++ b/src/maths/sparse/spsolve.c @@ -0,0 +1,710 @@ +/* + * MATRIX SOLVE MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains the forward and backward substitution routines for + * the sparse matrix routines. + * + * >>> User accessible functions contained in this file: + * spSolve + * spSolveTransposed + * + * >>> Other functions contained in this file: + * SolveComplexMatrix + * SolveComplexTransposedMatrix + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header$"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" + + + + +/* + * Function declarations + */ + +#ifdef __STDC__ +#if spSEPARATED_COMPLEX_VECTORS +static void SolveComplexMatrix( MatrixPtr, + RealVector, RealVector, RealVector, RealVector ); +static void SolveComplexTransposedMatrix( MatrixPtr, + RealVector, RealVector, RealVector, RealVector ); +#else +static void SolveComplexMatrix( MatrixPtr, RealVector, RealVector ); +static void SolveComplexTransposedMatrix( MatrixPtr, RealVector, RealVector ); +#endif +#else /* __STDC__ */ +static void SolveComplexMatrix(); +static void SolveComplexTransposedMatrix(); +#endif /* __STDC__ */ + + + + + + + +/* + * SOLVE MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and factored matrix. This + * routine assumes that the pivots are associated with the lower + * triangular (L) matrix and that the diagonal of the upper triangular + * (U) matrix consists of ones. This routine arranges the computation + * in different way than is traditionally used in order to exploit the + * sparsity of the right-hand side. See the reference in spRevision. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * RHS (RealVector) + * RHS is the input data array, the right hand side. This data is + * undisturbed and may be reused for other solves. + * Solution (RealVector) + * Solution is the output data array. This routine is constructed such that + * RHS and Solution can be the same array. + * iRHS (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * This argument is only necessary if matrix is complex and if + * spSEPARATED_COMPLEX_VECTOR is set TRUE. + * iSolution (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. This argument is only necessary if matrix is complex + * and if spSEPARATED_COMPLEX_VECTOR is set TRUE. + * + * >>> Local variables: + * Intermediate (RealVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c Local version of + * Matrix->Intermediate, which was created during the initial + * factorization in function spcCreateInternalVectors() in the matrix + * factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtColMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (RealNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +/*VARARGS3*/ + +void +spSolve( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector Intermediate; +register RealNumber Temp; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +void SolveComplexMatrix(); + +/* Begin `spSolve'. */ + ASSERT( IS_VALID(Matrix) AND IS_FACTORED(Matrix) ); + +#if spCOMPLEX + if (Matrix->Complex) + { SolveComplexMatrix( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL + Intermediate = Matrix->Intermediate; + Size = Matrix->Size; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + for (I = Size; I > 0; I--) + Intermediate[I] = RHS[*(pExtOrder--)]; + +/* Forward elimination. Solves Lc = b.*/ + for (I = 1; I <= Size; I++) + { +/* This step of the elimination is skipped if Temp equals zero. */ + if ((Temp = Intermediate[I]) != 0.0) + { pPivot = Matrix->Diag[I]; + Intermediate[I] = (Temp *= pPivot->Real); + + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Intermediate[pElement->Row] -= Temp * pElement->Real; + pElement = pElement->NextInCol; + } + } + } + +/* Backward Substitution. Solves Ux = c.*/ + for (I = Size; I > 0; I--) + { Temp = Intermediate[I]; + pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { Temp -= pElement->Real * Intermediate[pElement->Col]; + pElement = pElement->NextInRow; + } + Intermediate[I] = Temp; + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + for (I = Size; I > 0; I--) + Solution[*(pExtOrder--)] = Intermediate[I]; + + return; +#endif /* REAL */ +} + + + + + + + + + + + +#if spCOMPLEX +/* + * SOLVE COMPLEX MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and factored matrix. This + * routine assumes that the pivots are associated with the lower + * triangular (L) matrix and that the diagonal of the upper triangular + * (U) matrix consists of ones. This routine arranges the computation + * in different way than is traditionally used in order to exploit the + * sparsity of the right-hand side. See the reference in spRevision. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * RHS (RealVector) + * RHS is the real portion of the input data array, the right hand + * side. This data is undisturbed and may be reused for other solves. + * Solution (RealVector) + * Solution is the real portion of the output data array. This routine + * is constructed such that RHS and Solution can be the same + * array. + * iRHS (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * If spSEPARATED_COMPLEX_VECTOR is set FALSE, there is no need to + * supply this array. + * iSolution (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. If spSEPARATED_COMPLEX_VECTOR is set FALSE, there is no + * need to supply this array. + * + * >>> Local variables: + * Intermediate (ComplexVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c. + * Local version of Matrix->Intermediate, which was created during + * the initial factorization in function spcCreateInternalVectors() in the + * matrix factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtColMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (ComplexNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +SolveComplexMatrix( Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Intermediate; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +ComplexNumber Temp; + +/* Begin `SolveComplexMatrix'. */ + + Size = Matrix->Size; + Intermediate = (ComplexVector)Matrix->Intermediate; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Intermediate[I].Real = RHS[*(pExtOrder)]; + Intermediate[I].Imag = iRHS[*(pExtOrder--)]; + } +#else + ExtVector = (ComplexVector)RHS; + for (I = Size; I > 0; I--) + Intermediate[I] = ExtVector[*(pExtOrder--)]; +#endif + +/* Forward substitution. Solves Lc = b.*/ + for (I = 1; I <= Size; I++) + { Temp = Intermediate[I]; + +/* This step of the substitution is skipped if Temp equals zero. */ + if ((Temp.Real != 0.0) OR (Temp.Imag != 0.0)) + { pPivot = Matrix->Diag[I]; +/* Cmplx expr: Temp *= (1.0 / Pivot). */ + CMPLX_MULT_ASSIGN(Temp, *pPivot); + Intermediate[I] = Temp; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { +/* Cmplx expr: Intermediate[Element->Row] -= Temp * *Element. */ + CMPLX_MULT_SUBT_ASSIGN(Intermediate[pElement->Row], + Temp, *pElement); + pElement = pElement->NextInCol; + } + } + } + +/* Backward Substitution. Solves Ux = c.*/ + for (I = Size; I > 0; I--) + { Temp = Intermediate[I]; + pElement = Matrix->Diag[I]->NextInRow; + + while (pElement != NULL) + { +/* Cmplx expr: Temp -= *Element * Intermediate[Element->Col]. */ + CMPLX_MULT_SUBT_ASSIGN(Temp, *pElement,Intermediate[pElement->Col]); + pElement = pElement->NextInRow; + } + Intermediate[I] = Temp; + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Solution[*(pExtOrder)] = Intermediate[I].Real; + iSolution[*(pExtOrder--)] = Intermediate[I].Imag; + } +#else + ExtVector = (ComplexVector)Solution; + for (I = Size; I > 0; I--) + ExtVector[*(pExtOrder--)] = Intermediate[I]; +#endif + + return; +} +#endif /* spCOMPLEX */ + + + + + + + + + + + + + + +#if TRANSPOSE +/* + * SOLVE TRANSPOSED MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and transposed factored + * matrix. This routine is useful when performing sensitivity analysis + * on a circuit using the adjoint method. This routine assumes that + * the pivots are associated with the untransposed lower triangular + * (L) matrix and that the diagonal of the untransposed upper + * triangular (U) matrix consists of ones. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * RHS (RealVector) + * RHS is the input data array, the right hand side. This data is + * undisturbed and may be reused for other solves. + * Solution (RealVector) + * Solution is the output data array. This routine is constructed such that + * RHS and Solution can be the same array. + * iRHS (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * If spSEPARATED_COMPLEX_VECTOR is set FALSE, or if matrix is real, there + * is no need to supply this array. + * iSolution (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. If spSEPARATED_COMPLEX_VECTOR is set FALSE, or if + * matrix is real, there is no need to supply this array. + * + * >>> Local variables: + * Intermediate (RealVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c. Local version of + * Matrix->Intermediate, which was created during the initial + * factorization in function spcCreateInternalVectors() in the matrix + * factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtRowMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (RealNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +/*VARARGS3*/ + +void +spSolveTransposed( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector Intermediate; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +RealNumber Temp; +void SolveComplexTransposedMatrix(); + +/* Begin `spSolveTransposed'. */ + ASSERT( IS_VALID(Matrix) AND IS_FACTORED(Matrix) ); + +#if spCOMPLEX + if (Matrix->Complex) + { SolveComplexTransposedMatrix( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL + Size = Matrix->Size; + Intermediate = Matrix->Intermediate; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + for (I = Size; I > 0; I--) + Intermediate[I] = RHS[*(pExtOrder--)]; + +/* Forward elimination. */ + for (I = 1; I <= Size; I++) + { +/* This step of the elimination is skipped if Temp equals zero. */ + if ((Temp = Intermediate[I]) != 0.0) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { Intermediate[pElement->Col] -= Temp * pElement->Real; + pElement = pElement->NextInRow; + } + + } + } + +/* Backward Substitution. */ + for (I = Size; I > 0; I--) + { pPivot = Matrix->Diag[I]; + Temp = Intermediate[I]; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Temp -= pElement->Real * Intermediate[pElement->Row]; + pElement = pElement->NextInCol; + } + Intermediate[I] = Temp * pPivot->Real; + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + for (I = Size; I > 0; I--) + Solution[*(pExtOrder--)] = Intermediate[I]; + + return; +#endif /* REAL */ +} +#endif /* TRANSPOSE */ + + + + + + + + + + +#if TRANSPOSE AND spCOMPLEX +/* + * SOLVE COMPLEX TRANSPOSED MATRIX EQUATION + * + * Performs forward elimination and back substitution to find the + * unknown vector from the RHS vector and transposed factored + * matrix. This routine is useful when performing sensitivity analysis + * on a circuit using the adjoint method. This routine assumes that + * the pivots are associated with the untransposed lower triangular + * (L) matrix and that the diagonal of the untransposed upper + * triangular (U) matrix consists of ones. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to matrix. + * RHS (RealVector) + * RHS is the input data array, the right hand + * side. This data is undisturbed and may be reused for other solves. + * This vector is only the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set TRUE. + * Solution (RealVector) + * Solution is the real portion of the output data array. This routine + * is constructed such that RHS and Solution can be the same array. + * This vector is only the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set TRUE. + * iRHS (RealVector) + * iRHS is the imaginary portion of the input data array, the right + * hand side. This data is undisturbed and may be reused for other solves. + * If either spCOMPLEX or spSEPARATED_COMPLEX_VECTOR is set FALSE, there + * is no need to supply this array. + * iSolution (RealVector) + * iSolution is the imaginary portion of the output data array. This + * routine is constructed such that iRHS and iSolution can be + * the same array. If spCOMPLEX or spSEPARATED_COMPLEX_VECTOR is set + * FALSE, there is no need to supply this array. + * + * >>> Local variables: + * Intermediate (ComplexVector) + * Temporary storage for use in forward elimination and backward + * substitution. Commonly referred to as c, when the LU factorization + * equations are given as Ax = b, Lc = b, Ux = c. Local version of + * Matrix->Intermediate, which was created during + * the initial factorization in function spcCreateInternalVectors() in the + * matrix factorization module. + * pElement (ElementPtr) + * Pointer used to address elements in both the lower and upper triangle + * matrices. + * pExtOrder (int *) + * Pointer used to sequentially access each entry in IntToExtRowMap + * and IntToExtColMap arrays. Used to quickly scramble and unscramble + * RHS and Solution to account for row and column interchanges. + * pPivot (ElementPtr) + * Pointer that points to current pivot or diagonal element. + * Size (int) + * Size of matrix. Made local to reduce indirection. + * Temp (ComplexNumber) + * Temporary storage for entries in arrays. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +SolveComplexTransposedMatrix(Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Intermediate; +register int I, *pExtOrder, Size; +ElementPtr pPivot; +ComplexNumber Temp; + +/* Begin `SolveComplexTransposedMatrix'. */ + + Size = Matrix->Size; + Intermediate = (ComplexVector)Matrix->Intermediate; + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector. */ + pExtOrder = &Matrix->IntToExtColMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Intermediate[I].Real = RHS[*(pExtOrder)]; + Intermediate[I].Imag = iRHS[*(pExtOrder--)]; + } +#else + ExtVector = (ComplexVector)RHS; + for (I = Size; I > 0; I--) + Intermediate[I] = ExtVector[*(pExtOrder--)]; +#endif + +/* Forward elimination. */ + for (I = 1; I <= Size; I++) + { Temp = Intermediate[I]; + +/* This step of the elimination is skipped if Temp equals zero. */ + if ((Temp.Real != 0.0) OR (Temp.Imag != 0.0)) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { +/* Cmplx expr: Intermediate[Element->Col] -= Temp * *Element. */ + CMPLX_MULT_SUBT_ASSIGN( Intermediate[pElement->Col], + Temp, *pElement); + pElement = pElement->NextInRow; + } + } + } + +/* Backward Substitution. */ + for (I = Size; I > 0; I--) + { pPivot = Matrix->Diag[I]; + Temp = Intermediate[I]; + pElement = pPivot->NextInCol; + + while (pElement != NULL) + { +/* Cmplx expr: Temp -= Intermediate[Element->Row] * *Element. */ + CMPLX_MULT_SUBT_ASSIGN(Temp,Intermediate[pElement->Row],*pElement); + + pElement = pElement->NextInCol; + } +/* Cmplx expr: Intermediate = Temp * (1.0 / *pPivot). */ + CMPLX_MULT(Intermediate[I], Temp, *pPivot); + } + +/* Unscramble Intermediate vector while placing data in to Solution vector. */ + pExtOrder = &Matrix->IntToExtRowMap[Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Size; I > 0; I--) + { Solution[*(pExtOrder)] = Intermediate[I].Real; + iSolution[*(pExtOrder--)] = Intermediate[I].Imag; + } +#else + ExtVector = (ComplexVector)Solution; + for (I = Size; I > 0; I--) + ExtVector[*(pExtOrder--)] = Intermediate[I]; +#endif + + return; +} +#endif /* TRANSPOSE AND spCOMPLEX */ diff --git a/src/maths/sparse/sputils.c b/src/maths/sparse/sputils.c new file mode 100644 index 000000000..491d1a85c --- /dev/null +++ b/src/maths/sparse/sputils.c @@ -0,0 +1,2283 @@ +/* + * MATRIX UTILITY MODULE + * + * Author: Advising professor: + * Kenneth S. Kundert Alberto Sangiovanni-Vincentelli + * UC Berkeley + * + * This file contains various optional utility routines. + * + * >>> User accessible functions contained in this file: + * spMNA_Preorder + * spScale + * spMultiply + * spMultTransposed + * spDeterminant + * spStripFills + * spDeleteRowAndCol + * spPseudoCondition + * spCondition + * spNorm + * spLargestElement + * spRoundoff + * spErrorMessage + * + * >>> Other functions contained in this file: + * CountTwins + * SwapCols + * ScaleComplexMatrix + * ComplexMatrixMultiply + * ComplexCondition + */ + + +/* + * Revision and copyright information. + * + * Copyright (c) 1985,86,87,88,89,90 + * by Kenneth S. Kundert and the University of California. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the copyright notices appear in all copies and + * supporting documentation and that the authors and the University of + * California are properly credited. The authors and the University of + * California make no representations as to the suitability of this + * software for any purpose. It is provided `as is', without express + * or implied warranty. + */ + +#ifdef notdef +static char copyright[] = + "Sparse1.3: Copyright (c) 1985,86,87,88,89,90 by Kenneth S. Kundert"; +static char RCSid[] = + "@(#)$Header$"; +#endif + + + +/* + * IMPORTS + * + * >>> Import descriptions: + * spConfig.h + * Macros that customize the sparse matrix routines. + * spMatrix.h + * Macros and declarations to be imported by the user. + * spDefs.h + * Matrix type and macro definitions for the sparse matrix routines. + */ + +#define spINSIDE_SPARSE +#include "spconfig.h" +#include "spmatrix.h" +#include "spdefs.h" + + + + + +/* + * Function declarations + */ + +static int CountTwins( MatrixPtr, int, ElementPtr*, ElementPtr* ); +static void SwapCols( MatrixPtr, ElementPtr, ElementPtr ); +#if spSEPARATED_COMPLEX_VECTORS +static void ComplexMatrixMultiply( MatrixPtr, RealVector, RealVector, + RealVector, RealVector ); +static void ComplexTransposedMatrixMultiply( MatrixPtr, RealVector, RealVector, + RealVector, RealVector); +#else +static void ComplexMatrixMultiply( MatrixPtr, RealVector, RealVector ); +static void ComplexTransposedMatrixMultiply(MatrixPtr, RealVector, RealVector); +#endif + + + + + +#if MODIFIED_NODAL +/* + * PREORDER MODIFIED NODE ADMITTANCE MATRIX TO REMOVE ZEROS FROM DIAGONAL + * + * This routine massages modified node admittance matrices to remove + * zeros from the diagonal. It takes advantage of the fact that the + * row and column associated with a zero diagonal usually have + * structural ones placed symmetricly. This routine should be used + * only on modified node admittance matrices and should be executed + * after the matrix has been built but before the factorization + * begins. It should be executed for the initial factorization only + * and should be executed before the rows have been linked. Thus it + * should be run before using spScale(), spMultiply(), + * spDeleteRowAndCol(), or spNorm(). + * + * This routine exploits the fact that the structural ones are placed + * in the matrix in symmetric twins. For example, the stamps for + * grounded and a floating voltage sources are + * grounded: floating: + * [ x x 1 ] [ x x 1 ] + * [ x x ] [ x x -1 ] + * [ 1 ] [ 1 -1 ] + * Notice for the grounded source, there is one set of twins, and for + * the floating, there are two sets. We remove the zero from the diagonal + * by swapping the rows associated with a set of twins. For example: + * grounded: floating 1: floating 2: + * [ 1 ] [ 1 -1 ] [ x x 1 ] + * [ x x ] [ x x -1 ] [ 1 -1 ] + * [ x x 1 ] [ x x 1 ] [ x x -1 ] + * + * It is important to deal with any zero diagonals that only have one + * set of twins before dealing with those that have more than one because + * swapping row destroys the symmetry of any twins in the rows being + * swapped, which may limit future moves. Consider + * [ x x 1 ] + * [ x x -1 1 ] + * [ 1 -1 ] + * [ 1 ] + * There is one set of twins for diagonal 4 and two for diagonal 3. + * Dealing with diagonal 4 first requires swapping rows 2 and 4. + * [ x x 1 ] + * [ 1 ] + * [ 1 -1 ] + * [ x x -1 1 ] + * We can now deal with diagonal 3 by swapping rows 1 and 3. + * [ 1 -1 ] + * [ 1 ] + * [ x x 1 ] + * [ x x -1 1 ] + * And we are done, there are no zeros left on the diagonal. However, if + * we originally dealt with diagonal 3 first, we could swap rows 2 and 3 + * [ x x 1 ] + * [ 1 -1 ] + * [ x x -1 1 ] + * [ 1 ] + * Diagonal 4 no longer has a symmetric twin and we cannot continue. + * + * So we always take care of lone twins first. When none remain, we + * choose arbitrarily a set of twins for a diagonal with more than one set + * and swap the rows corresponding to that twin. We then deal with any + * lone twins that were created and repeat the procedure until no + * zero diagonals with symmetric twins remain. + * + * In this particular implementation, columns are swapped rather than rows. + * The algorithm used in this function was developed by Ken Kundert and + * Tom Quarles. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix to be preordered. + * + * >>> Local variables; + * J (int) + * Column with zero diagonal being currently considered. + * pTwin1 (ElementPtr) + * Pointer to the twin found in the column belonging to the zero diagonal. + * pTwin2 (ElementPtr) + * Pointer to the twin found in the row belonging to the zero diagonal. + * belonging to the zero diagonal. + * AnotherPassNeeded (BOOLEAN) + * Flag indicating that at least one zero diagonal with symmetric twins + * remain. + * StartAt (int) + * Column number of first zero diagonal with symmetric twins. + * Swapped (BOOLEAN) + * Flag indicating that columns were swapped on this pass. + * Twins (int) + * Number of symmetric twins corresponding to current zero diagonal. + */ + +void +spMNA_Preorder( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int J, Size; +ElementPtr pTwin1, pTwin2; +int Twins, StartAt = 1; +BOOLEAN Swapped, AnotherPassNeeded; + +/* Begin `spMNA_Preorder'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored ); + + if (Matrix->RowsLinked) return; + Size = Matrix->Size; + Matrix->Reordered = YES; + + do + { AnotherPassNeeded = Swapped = NO; + +/* Search for zero diagonals with lone twins. */ + for (J = StartAt; J <= Size; J++) + { if (Matrix->Diag[J] == NULL) + { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); + if (Twins == 1) + { /* Lone twins found, swap rows. */ + SwapCols( Matrix, pTwin1, pTwin2 ); + Swapped = YES; + } + else if ((Twins > 1) AND NOT AnotherPassNeeded) + { AnotherPassNeeded = YES; + StartAt = J; + } + } + } + +/* All lone twins are gone, look for zero diagonals with multiple twins. */ + if (AnotherPassNeeded) + { for (J = StartAt; NOT Swapped AND (J <= Size); J++) + { if (Matrix->Diag[J] == NULL) + { Twins = CountTwins( Matrix, J, &pTwin1, &pTwin2 ); + SwapCols( Matrix, pTwin1, pTwin2 ); + Swapped = YES; + } + } + } + } while (AnotherPassNeeded); + return; +} + + + + +/* + * COUNT TWINS + * + * This function counts the number of symmetric twins associated with + * a zero diagonal and returns one set of twins if any exist. The + * count is terminated early at two. + */ + +static int +CountTwins( Matrix, Col, ppTwin1, ppTwin2 ) + +MatrixPtr Matrix; +int Col; +ElementPtr *ppTwin1, *ppTwin2; +{ +int Row, Twins = 0; +ElementPtr pTwin1, pTwin2; + +/* Begin `CountTwins'. */ + + pTwin1 = Matrix->FirstInCol[Col]; + while (pTwin1 != NULL) + { if (ABS(pTwin1->Real) == 1.0) + { Row = pTwin1->Row; + pTwin2 = Matrix->FirstInCol[Row]; + while ((pTwin2 != NULL) AND (pTwin2->Row != Col)) + pTwin2 = pTwin2->NextInCol; + if ((pTwin2 != NULL) AND (ABS(pTwin2->Real) == 1.0)) + { /* Found symmetric twins. */ + if (++Twins >= 2) return Twins; +#ifdef notdef + (*ppTwin1 = pTwin1)/*->Col = Col XXX */; + (*ppTwin2 = pTwin2)/*->Col = Row XXX */; +#else + (*ppTwin1 = pTwin1)->Col = Col; + (*ppTwin2 = pTwin2)->Col = Row; +#endif + } + } + pTwin1 = pTwin1->NextInCol; + } + return Twins; +} + + + + +/* + * SWAP COLUMNS + * + * This function swaps two columns and is applicable before the rows are + * linked. + */ + +static void +SwapCols( Matrix, pTwin1, pTwin2 ) + +MatrixPtr Matrix; +ElementPtr pTwin1, pTwin2; +{ +int Col1 = pTwin1->Col, Col2 = pTwin2->Col; + +/* Begin `SwapCols'. */ + +#ifdef notdef +ElementPtr e; /*XXX*/ + /* XXX Update column numbers */ + for (e = Matrix->FirstInCol[Col1]; e != NULL; e = e->NextInCol) + e->Col = Col2; + for (e = Matrix->FirstInCol[Col2]; e != NULL; e = e->NextInCol) + e->Col = Col1; +#endif + + SWAP (ElementPtr, Matrix->FirstInCol[Col1], Matrix->FirstInCol[Col2]); + SWAP (int, Matrix->IntToExtColMap[Col1], Matrix->IntToExtColMap[Col2]); +#if TRANSLATE + Matrix->ExtToIntColMap[Matrix->IntToExtColMap[Col2]]=Col2; + Matrix->ExtToIntColMap[Matrix->IntToExtColMap[Col1]]=Col1; +#endif + + Matrix->Diag[Col1] = pTwin2; + Matrix->Diag[Col2] = pTwin1; + Matrix->NumberOfInterchangesIsOdd = NOT Matrix->NumberOfInterchangesIsOdd; + return; +} +#endif /* MODIFIED_NODAL */ + + + + + + + + + +#if SCALING +/* + * SCALE MATRIX + * + * This function scales the matrix to enhance the possibility of + * finding a good pivoting order. Note that scaling enhances accuracy + * of the solution only if it affects the pivoting order, so it makes + * no sense to scale the matrix before spFactor(). If scaling is + * desired it should be done before spOrderAndFactor(). There + * are several things to take into account when choosing the scale + * factors. First, the scale factors are directly multiplied against + * the elements in the matrix. To prevent roundoff, each scale factor + * should be equal to an integer power of the number base of the + * machine. Since most machines operate in base two, scale factors + * should be a power of two. Second, the matrix should be scaled such + * that the matrix of element uncertainties is equilibrated. Third, + * this function multiplies the scale factors by the elements, so if + * one row tends to have uncertainties 1000 times smaller than the + * other rows, then its scale factor should be 1024, not 1/1024. + * Fourth, to save time, this function does not scale rows or columns + * if their scale factors are equal to one. Thus, the scale factors + * should be normalized to the most common scale factor. Rows and + * columns should be normalized separately. For example, if the size + * of the matrix is 100 and 10 rows tend to have uncertainties near + * 1e-6 and the remaining 90 have uncertainties near 1e-12, then the + * scale factor for the 10 should be 1/1,048,576 and the scale factors + * for the remaining 90 should be 1. Fifth, since this routine + * directly operates on the matrix, it is necessary to apply the scale + * factors to the RHS and Solution vectors. It may be easier to + * simply use spOrderAndFactor() on a scaled matrix to choose the + * pivoting order, and then throw away the matrix. Subsequent + * factorizations, performed with spFactor(), will not need to have + * the RHS and Solution vectors descaled. Lastly, this function + * should not be executed before the function spMNA_Preorder. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix to be scaled. + * SolutionScaleFactors (RealVector) + * The array of Solution scale factors. These factors scale the columns. + * All scale factors are real valued. + * RHS_ScaleFactors (RealVector) + * The array of RHS scale factors. These factors scale the rows. + * All scale factors are real valued. + * + * >>> Local variables: + * lSize (int) + * Local version of the size of the matrix. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pExtOrder (int *) + * Pointer into either IntToExtRowMap or IntToExtColMap vector. Used to + * compensate for any row or column swaps that have been performed. + * ScaleFactor (RealNumber) + * The scale factor being used on the current row or column. + */ + +void +spScale( eMatrix, RHS_ScaleFactors, SolutionScaleFactors ) + +char *eMatrix; +register RealVector RHS_ScaleFactors, SolutionScaleFactors; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I, lSize, *pExtOrder; +RealNumber ScaleFactor; +void ScaleComplexMatrix(); + +/* Begin `spScale'. */ + ASSERT( IS_VALID(Matrix) AND NOT Matrix->Factored ); + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); + +#if spCOMPLEX + if (Matrix->Complex) + { ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors ); + return; + } +#endif + +#if REAL + lSize = Matrix->Size; + +/* Correct pointers to arrays for ARRAY_OFFSET */ +#if NOT ARRAY_OFFSET + --RHS_ScaleFactors; + --SolutionScaleFactors; +#endif + +/* Scale Rows */ + pExtOrder = &Matrix->IntToExtRowMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInRow[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement = pElement->NextInRow; + } + } + } + +/* Scale Columns */ + pExtOrder = &Matrix->IntToExtColMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInCol[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement = pElement->NextInCol; + } + } + } + return; + +#endif /* REAL */ +} +#endif /* SCALING */ + + + + + + + + + +#if spCOMPLEX AND SCALING +/* + * SCALE COMPLEX MATRIX + * + * This function scales the matrix to enhance the possibility of + * finding a good pivoting order. Note that scaling enhances accuracy + * of the solution only if it affects the pivoting order, so it makes + * no sense to scale the matrix before spFactor(). If scaling is + * desired it should be done before spOrderAndFactor(). There + * are several things to take into account when choosing the scale + * factors. First, the scale factors are directly multiplied against + * the elements in the matrix. To prevent roundoff, each scale factor + * should be equal to an integer power of the number base of the + * machine. Since most machines operate in base two, scale factors + * should be a power of two. Second, the matrix should be scaled such + * that the matrix of element uncertainties is equilibrated. Third, + * this function multiplies the scale factors by the elements, so if + * one row tends to have uncertainties 1000 times smaller than the + * other rows, then its scale factor should be 1024, not 1/1024. + * Fourth, to save time, this function does not scale rows or columns + * if their scale factors are equal to one. Thus, the scale factors + * should be normalized to the most common scale factor. Rows and + * columns should be normalized separately. For example, if the size + * of the matrix is 100 and 10 rows tend to have uncertainties near + * 1e-6 and the remaining 90 have uncertainties near 1e-12, then the + * scale factor for the 10 should be 1/1,048,576 and the scale factors + * for the remaining 90 should be 1. Fifth, since this routine + * directly operates on the matrix, it is necessary to apply the scale + * factors to the RHS and Solution vectors. It may be easier to + * simply use spOrderAndFactor() on a scaled matrix to choose the + * pivoting order, and then throw away the matrix. Subsequent + * factorizations, performed with spFactor(), will not need to have + * the RHS and Solution vectors descaled. Lastly, this function + * should not be executed before the function spMNA_Preorder. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix to be scaled. + * SolutionScaleFactors (RealVector) + * The array of Solution scale factors. These factors scale the columns. + * All scale factors are real valued. + * RHS_ScaleFactors (RealVector) + * The array of RHS scale factors. These factors scale the rows. + * All scale factors are real valued. + * + * >>> Local variables: + * lSize (int) + * Local version of the size of the matrix. + * pElement (ElementPtr) + * Pointer to an element in the matrix. + * pExtOrder (int *) + * Pointer into either IntToExtRowMap or IntToExtColMap vector. Used to + * compensate for any row or column swaps that have been performed. + * ScaleFactor (RealNumber) + * The scale factor being used on the current row or column. + */ + +static void +ScaleComplexMatrix( Matrix, RHS_ScaleFactors, SolutionScaleFactors ) + +MatrixPtr Matrix; +register RealVector RHS_ScaleFactors, SolutionScaleFactors; +{ +register ElementPtr pElement; +register int I, lSize, *pExtOrder; +RealNumber ScaleFactor; + +/* Begin `ScaleComplexMatrix'. */ + lSize = Matrix->Size; + +/* Correct pointers to arrays for ARRAY_OFFSET */ +#if NOT ARRAY_OFFSET + --RHS_ScaleFactors; + --SolutionScaleFactors; +#endif + +/* Scale Rows */ + pExtOrder = &Matrix->IntToExtRowMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = RHS_ScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInRow[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement->Imag *= ScaleFactor; + pElement = pElement->NextInRow; + } + } + } + +/* Scale Columns */ + pExtOrder = &Matrix->IntToExtColMap[1]; + for (I = 1; I <= lSize; I++) + { if ((ScaleFactor = SolutionScaleFactors[*(pExtOrder++)]) != 1.0) + { pElement = Matrix->FirstInCol[I]; + + while (pElement != NULL) + { pElement->Real *= ScaleFactor; + pElement->Imag *= ScaleFactor; + pElement = pElement->NextInCol; + } + } + } + return; +} +#endif /* SCALING AND spCOMPLEX */ + + + + + + + + +#if MULTIPLICATION +/* + * MATRIX MULTIPLICATION + * + * Multiplies matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. It should not be used + * before spMNA_Preorder(). + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix. + * RHS (RealVector) + * RHS is the right hand side. This is what is being solved for. + * Solution (RealVector) + * Solution is the vector being multiplied by the matrix. + * iRHS (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * iSolution (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +void +spMultiply( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register RealVector Vector; +register RealNumber Sum; +register int I, *pExtOrder; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +extern void ComplexMatrixMultiply(); + +/* Begin `spMultiply'. */ + ASSERT( IS_SPARSE( Matrix ) AND NOT Matrix->Factored ); + if (NOT Matrix->RowsLinked) + spcLinkRows(Matrix); + if (NOT Matrix->InternalVectorsAllocated) + spcCreateInternalVectors( Matrix ); + +#if spCOMPLEX + if (Matrix->Complex) + { ComplexMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL +#if NOT ARRAY_OFFSET +/* Correct array pointers for ARRAY_OFFSET. */ + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + Vector[I] = Solution[*(pExtOrder--)]; + + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + Sum = 0.0; + + while (pElement != NULL) + { Sum += pElement->Real * Vector[pElement->Col]; + pElement = pElement->NextInRow; + } + RHS[*pExtOrder--] = Sum; + } + return; +#endif /* REAL */ +} +#endif /* MULTIPLICATION */ + + + + + + + +#if spCOMPLEX AND MULTIPLICATION +/* + * COMPLEX MATRIX MULTIPLICATION + * + * Multiplies matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix. + * RHS (RealVector) + * RHS is the right hand side. This is what is being solved for. + * This is only the real portion of the right-hand side if the matrix + * is complex and spSEPARATED_COMPLEX_VECTORS is set TRUE. + * Solution (RealVector) + * Solution is the vector being multiplied by the matrix. This is only + * the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set TRUE. + * iRHS (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * iSolution (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +ComplexMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Vector; +ComplexNumber Sum; +register int I, *pExtOrder; + +/* Begin `ComplexMatrixMultiply'. */ + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = (ComplexVector)Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Matrix->Size; I > 0; I--) + { Vector[I].Real = Solution[*pExtOrder]; + Vector[I].Imag = iSolution[*(pExtOrder--)]; + } +#else + for (I = Matrix->Size; I > 0; I--) + Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)]; +#endif + + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + Sum.Real = Sum.Imag = 0.0; + + while (pElement != NULL) + { /* Cmplx expression : Sum += Element * Vector[Col] */ + CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Col] ); + pElement = pElement->NextInRow; + } + +#if spSEPARATED_COMPLEX_VECTORS + RHS[*pExtOrder] = Sum.Real; + iRHS[*pExtOrder--] = Sum.Imag; +#else + ((ComplexVector)RHS)[*pExtOrder--] = Sum; +#endif + } + return; +} +#endif /* spCOMPLEX AND MULTIPLICATION */ + + + + + + + + +#if MULTIPLICATION AND TRANSPOSE +/* + * TRANSPOSED MATRIX MULTIPLICATION + * + * Multiplies transposed matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. It should not be used + * before spMNA_Preorder(). + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix. + * RHS (RealVector) + * RHS is the right hand side. This is what is being solved for. + * Solution (RealVector) + * Solution is the vector being multiplied by the matrix. + * iRHS (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * iSolution (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +void +spMultTransposed( eMatrix, RHS, Solution IMAG_VECTORS ) + +char *eMatrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register RealVector Vector; +register RealNumber Sum; +register int I, *pExtOrder; +MatrixPtr Matrix = (MatrixPtr)eMatrix; +extern void ComplexTransposedMatrixMultiply(); + +/* Begin `spMultTransposed'. */ + ASSERT( IS_SPARSE( Matrix ) AND NOT Matrix->Factored ); + if (NOT Matrix->InternalVectorsAllocated) + spcCreateInternalVectors( Matrix ); + +#if spCOMPLEX + if (Matrix->Complex) + { ComplexTransposedMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ); + return; + } +#endif + +#if REAL +#if NOT ARRAY_OFFSET +/* Correct array pointers for ARRAY_OFFSET. */ + --RHS; + --Solution; +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + Vector[I] = Solution[*(pExtOrder--)]; + + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + Sum = 0.0; + + while (pElement != NULL) + { Sum += pElement->Real * Vector[pElement->Row]; + pElement = pElement->NextInCol; + } + RHS[*pExtOrder--] = Sum; + } + return; +#endif /* REAL */ +} +#endif /* MULTIPLICATION AND TRANSPOSE */ + + + + + + + +#if spCOMPLEX AND MULTIPLICATION AND TRANSPOSE +/* + * COMPLEX TRANSPOSED MATRIX MULTIPLICATION + * + * Multiplies transposed matrix by solution vector to find source vector. + * Assumes matrix has not been factored. This routine can be used + * as a test to see if solutions are correct. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix. + * RHS (RealVector) + * RHS is the right hand side. This is what is being solved for. + * This is only the real portion of the right-hand side if the matrix + * is complex and spSEPARATED_COMPLEX_VECTORS is set TRUE. + * Solution (RealVector) + * Solution is the vector being multiplied by the matrix. This is only + * the real portion if the matrix is complex and + * spSEPARATED_COMPLEX_VECTORS is set TRUE. + * iRHS (RealVector) + * iRHS is the imaginary portion of the right hand side. This is + * what is being solved for. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * iSolution (RealVector) + * iSolution is the imaginary portion of the vector being multiplied + * by the matrix. This is only necessary if the matrix is + * complex and spSEPARATED_COMPLEX_VECTORS is TRUE. + * + * >>> Obscure Macros + * IMAG_VECTORS + * Replaces itself with `, iRHS, iSolution' if the options spCOMPLEX and + * spSEPARATED_COMPLEX_VECTORS are set, otherwise it disappears + * without a trace. + */ + +static void +ComplexTransposedMatrixMultiply( Matrix, RHS, Solution IMAG_VECTORS ) + +MatrixPtr Matrix; +RealVector RHS, Solution IMAG_VECTORS; +{ +register ElementPtr pElement; +register ComplexVector Vector; +ComplexNumber Sum; +register int I, *pExtOrder; + +/* Begin `ComplexMatrixMultiply'. */ + +/* Correct array pointers for ARRAY_OFFSET. */ +#if NOT ARRAY_OFFSET +#if spSEPARATED_COMPLEX_VECTORS + --RHS; --iRHS; + --Solution; --iSolution; +#else + RHS -= 2; Solution -= 2; +#endif +#endif + +/* Initialize Intermediate vector with reordered Solution vector. */ + Vector = (ComplexVector)Matrix->Intermediate; + pExtOrder = &Matrix->IntToExtRowMap[Matrix->Size]; + +#if spSEPARATED_COMPLEX_VECTORS + for (I = Matrix->Size; I > 0; I--) + { Vector[I].Real = Solution[*pExtOrder]; + Vector[I].Imag = iSolution[*(pExtOrder--)]; + } +#else + for (I = Matrix->Size; I > 0; I--) + Vector[I] = ((ComplexVector)Solution)[*(pExtOrder--)]; +#endif + + pExtOrder = &Matrix->IntToExtColMap[Matrix->Size]; + for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInCol[I]; + Sum.Real = Sum.Imag = 0.0; + + while (pElement != NULL) + { /* Cmplx expression : Sum += Element * Vector[Row] */ + CMPLX_MULT_ADD_ASSIGN( Sum, *pElement, Vector[pElement->Row] ); + pElement = pElement->NextInCol; + } + +#if spSEPARATED_COMPLEX_VECTORS + RHS[*pExtOrder] = Sum.Real; + iRHS[*pExtOrder--] = Sum.Imag; +#else + ((ComplexVector)RHS)[*pExtOrder--] = Sum; +#endif + } + return; +} +#endif /* spCOMPLEX AND MULTIPLICATION AND TRANSPOSE */ + + + + + + + + +#if DETERMINANT +/* + * CALCULATE DETERMINANT + * + * This routine in capable of calculating the determinant of the + * matrix once the LU factorization has been performed. Hence, only + * use this routine after spFactor() and before spClear(). + * The determinant equals the product of all the diagonal elements of + * the lower triangular matrix L, except that this product may need + * negating. Whether the product or the negative product equals the + * determinant is determined by the number of row and column + * interchanges performed. Note that the determinants of matrices can + * be very large or very small. On large matrices, the determinant + * can be far larger or smaller than can be represented by a floating + * point number. For this reason the determinant is scaled to a + * reasonable value and the logarithm of the scale factor is returned. + * + * >>> Arguments: + * eMatrix (char *) + * A pointer to the matrix for which the determinant is desired. + * pExponent (int *) + * The logarithm base 10 of the scale factor for the determinant. To find + * the actual determinant, Exponent should be added to the exponent of + * Determinant. + * pDeterminant (RealNumber *) + * The real portion of the determinant. This number is scaled to be + * greater than or equal to 1.0 and less than 10.0. + * piDeterminant (RealNumber *) + * The imaginary portion of the determinant. When the matrix is real + * this pointer need not be supplied, nothing will be returned. This + * number is scaled to be greater than or equal to 1.0 and less than 10.0. + * + * >>> Local variables: + * Norm (RealNumber) + * L-infinity norm of a complex number. + * Size (int) + * Local storage for Matrix->Size. Placed in a register for speed. + * Temp (RealNumber) + * Temporary storage for real portion of determinant. + */ + +#if spCOMPLEX +void +spDeterminant( eMatrix, pExponent, pDeterminant, piDeterminant ) +RealNumber *piDeterminant; +#else +void +spDeterminant( eMatrix, pExponent, pDeterminant ) +#endif + +char *eMatrix; +register RealNumber *pDeterminant; +int *pExponent; +{ +register MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I, Size; +RealNumber Norm, nr, ni; +ComplexNumber Pivot, cDeterminant; + +#define NORM(a) (nr = ABS((a).Real), ni = ABS((a).Imag), MAX (nr,ni)) + +/* Begin `spDeterminant'. */ + ASSERT( IS_SPARSE( Matrix ) AND IS_FACTORED(Matrix) ); + *pExponent = 0; + + if (Matrix->Error == spSINGULAR) + { *pDeterminant = 0.0; +#if spCOMPLEX + if (Matrix->Complex) *piDeterminant = 0.0; +#endif + return; + } + + Size = Matrix->Size; + I = 0; + +#if spCOMPLEX + if (Matrix->Complex) /* Complex Case. */ + { cDeterminant.Real = 1.0; + cDeterminant.Imag = 0.0; + + while (++I <= Size) + { CMPLX_RECIPROCAL( Pivot, *Matrix->Diag[I] ); + CMPLX_MULT_ASSIGN( cDeterminant, Pivot ); + +/* Scale Determinant. */ + Norm = NORM( cDeterminant ); + if (Norm != 0.0) + { while (Norm >= 1.0e12) + { cDeterminant.Real *= 1.0e-12; + cDeterminant.Imag *= 1.0e-12; + *pExponent += 12; + Norm = NORM( cDeterminant ); + } + while (Norm < 1.0e-12) + { cDeterminant.Real *= 1.0e12; + cDeterminant.Imag *= 1.0e12; + *pExponent -= 12; + Norm = NORM( cDeterminant ); + } + } + } + +/* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */ + Norm = NORM( cDeterminant ); + if (Norm != 0.0) + { while (Norm >= 10.0) + { cDeterminant.Real *= 0.1; + cDeterminant.Imag *= 0.1; + (*pExponent)++; + Norm = NORM( cDeterminant ); + } + while (Norm < 1.0) + { cDeterminant.Real *= 10.0; + cDeterminant.Imag *= 10.0; + (*pExponent)--; + Norm = NORM( cDeterminant ); + } + } + if (Matrix->NumberOfInterchangesIsOdd) + CMPLX_NEGATE( cDeterminant ); + + *pDeterminant = cDeterminant.Real; + *piDeterminant = cDeterminant.Imag; + } +#endif /* spCOMPLEX */ +#if REAL AND spCOMPLEX + else +#endif +#if REAL + { /* Real Case. */ + *pDeterminant = 1.0; + + while (++I <= Size) + { *pDeterminant /= Matrix->Diag[I]->Real; + +/* Scale Determinant. */ + if (*pDeterminant != 0.0) + { while (ABS(*pDeterminant) >= 1.0e12) + { *pDeterminant *= 1.0e-12; + *pExponent += 12; + } + while (ABS(*pDeterminant) < 1.0e-12) + { *pDeterminant *= 1.0e12; + *pExponent -= 12; + } + } + } + +/* Scale Determinant again, this time to be between 1.0 <= x < 10.0. */ + if (*pDeterminant != 0.0) + { while (ABS(*pDeterminant) >= 10.0) + { *pDeterminant *= 0.1; + (*pExponent)++; + } + while (ABS(*pDeterminant) < 1.0) + { *pDeterminant *= 10.0; + (*pExponent)--; + } + } + if (Matrix->NumberOfInterchangesIsOdd) + *pDeterminant = -*pDeterminant; + } +#endif /* REAL */ +} +#endif /* DETERMINANT */ + + + + + + + + + +#if STRIP +/* + * STRIP FILL-INS FROM MATRIX + * + * Strips the matrix of all fill-ins. + * + * >>> Arguments: + * Matrix (char *) + * Pointer to the matrix to be stripped. + * + * >>> Local variables: + * pElement (ElementPtr) + * Pointer that is used to step through the matrix. + * ppElement (ElementPtr *) + * Pointer to the location of an ElementPtr. This location will be + * updated if a fill-in is stripped from the matrix. + * pFillin (ElementPtr) + * Pointer used to step through the lists of fill-ins while marking them. + * pLastFillin (ElementPtr) + * A pointer to the last fill-in in the list. Used to terminate a loop. + * pListNode (struct FillinListNodeStruct *) + * A pointer to a node in the FillinList linked-list. + */ + +void +spStripFills( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +struct FillinListNodeStruct *pListNode; + +/* Begin `spStripFills'. */ + ASSERT( IS_SPARSE( Matrix ) ); + if (Matrix->Fillins == 0) return; + Matrix->NeedsOrdering = YES; + Matrix->Elements -= Matrix->Fillins; + Matrix->Fillins = 0; + +/* Mark the fill-ins. */ + { register ElementPtr pFillin, pLastFillin; + + pListNode = Matrix->LastFillinListNode = Matrix->FirstFillinListNode; + Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; + Matrix->NextAvailFillin = pListNode->pFillinList; + + while (pListNode != NULL) + { pFillin = pListNode->pFillinList; + pLastFillin = &(pFillin[ pListNode->NumberOfFillinsInList - 1 ]); + while (pFillin <= pLastFillin) + (pFillin++)->Row = 0; + pListNode = pListNode->Next; + } + } + +/* Unlink fill-ins by searching for elements marked with Row = 0. */ + { register ElementPtr pElement, *ppElement; + register int I, Size = Matrix->Size; + +/* Unlink fill-ins in all columns. */ + for (I = 1; I <= Size; I++) + { ppElement = &(Matrix->FirstInCol[I]); + while ((pElement = *ppElement) != NULL) + { if (pElement->Row == 0) + { *ppElement = pElement->NextInCol; /* Unlink fill-in. */ + if (Matrix->Diag[pElement->Col] == pElement) + Matrix->Diag[pElement->Col] = NULL; + } + else + ppElement = &pElement->NextInCol; /* Skip element. */ + } + } + +/* Unlink fill-ins in all rows. */ + for (I = 1; I <= Size; I++) + { ppElement = &(Matrix->FirstInRow[I]); + while ((pElement = *ppElement) != NULL) + { if (pElement->Row == 0) + *ppElement = pElement->NextInRow; /* Unlink fill-in. */ + else + ppElement = &pElement->NextInRow; /* Skip element. */ + } + } + } + return; +} + +/* Same as above, but strips entire matrix without destroying the frame. + * This assumes that the matrix will be replaced with one of the same size. + */ +void +spStripMatrix( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; + +/* Begin `spStripMatrix'. */ + ASSERT( IS_SPARSE( Matrix ) ); + if (Matrix->Elements == 0) return; + Matrix->RowsLinked = NO; + Matrix->NeedsOrdering = YES; + Matrix->Elements = 0; + Matrix->Originals = 0; + Matrix->Fillins = 0; + +/* Reset the element lists. */ + { register ElementPtr pElement; + struct ElementListNodeStruct *pListNode; + + pListNode = Matrix->LastElementListNode = Matrix->FirstElementListNode; + Matrix->ElementsRemaining = pListNode->NumberOfElementsInList; + Matrix->NextAvailElement = pListNode->pElementList; + } + +/* Reset the fill-in lists. */ + { register ElementPtr pFillin; + struct FillinListNodeStruct *pListNode; + + pListNode = Matrix->LastFillinListNode = Matrix->FirstFillinListNode; + Matrix->FillinsRemaining = pListNode->NumberOfFillinsInList; + Matrix->NextAvailFillin = pListNode->pFillinList; + } + +/* Reset the Row, Column and Diag pointers */ + { register int I, Size = Matrix->Size; + for (I = 1; I <= Size; I++) + { Matrix->FirstInRow[I] = NULL; + Matrix->FirstInCol[I] = NULL; + Matrix->Diag[I] = NULL; + } + } +} +#endif + + + + + + + +#if TRANSLATE AND DELETE +/* + * DELETE A ROW AND COLUMN FROM THE MATRIX + * + * Deletes a row and a column from a matrix. + * + * Sparse will abort if an attempt is made to delete a row or column that + * doesn't exist. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix in which the row and column are to be deleted. + * Row (int) + * Row to be deleted. + * Col (int) + * Column to be deleted. + * + * >>> Local variables: + * ExtCol (int) + * The external column that is being deleted. + * ExtRow (int) + * The external row that is being deleted. + * pElement (ElementPtr) + * Pointer to an element in the matrix. Used when scanning rows and + * columns in order to eliminate elements from the last row or column. + * ppElement (ElementPtr *) + * Pointer to the location of an ElementPtr. This location will be + * filled with a NULL pointer if it is the new last element in its row + * or column. + * pElement (ElementPtr) + * Pointer to an element in the last row or column of the matrix. + * Size (int) + * The local version Matrix->Size, the size of the matrix. + */ + +void +spDeleteRowAndCol( eMatrix, Row, Col ) + +char *eMatrix; +int Row, Col; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement, *ppElement, pLastElement; +int Size, ExtRow, ExtCol; +ElementPtr spcFindElementInCol(); + +/* Begin `spDeleteRowAndCol'. */ + + ASSERT( IS_SPARSE(Matrix) AND Row > 0 AND Col > 0 ); + ASSERT( Row <= Matrix->ExtSize AND Col <= Matrix->ExtSize ); + + Size = Matrix->Size; + ExtRow = Row; + ExtCol = Col; + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); + + Row = Matrix->ExtToIntRowMap[Row]; + Col = Matrix->ExtToIntColMap[Col]; + ASSERT( Row > 0 AND Col > 0 ); + +/* Move Row so that it is the last row in the matrix. */ + if (Row != Size) spcRowExchange( Matrix, Row, Size ); + +/* Move Col so that it is the last column in the matrix. */ + if (Col != Size) spcColExchange( Matrix, Col, Size ); + +/* Correct Diag pointers. */ + if (Row == Col) + SWAP( ElementPtr, Matrix->Diag[Row], Matrix->Diag[Size] ) + else + { Matrix->Diag[Row] = spcFindElementInCol( Matrix, Matrix->FirstInCol+Row, + Row, Row, NO ); + Matrix->Diag[Col] = spcFindElementInCol( Matrix, Matrix->FirstInCol+Col, + Col, Col, NO ); + } + +/* + * Delete last row and column of the matrix. + */ +/* Break the column links to every element in the last row. */ + pLastElement = Matrix->FirstInRow[ Size ]; + while (pLastElement != NULL) + { ppElement = &(Matrix->FirstInCol[ pLastElement->Col ]); + while ((pElement = *ppElement) != NULL) + { if (pElement == pLastElement) + *ppElement = NULL; /* Unlink last element in column. */ + else + ppElement = &pElement->NextInCol; /* Skip element. */ + } + pLastElement = pLastElement->NextInRow; + } + +/* Break the row links to every element in the last column. */ + pLastElement = Matrix->FirstInCol[ Size ]; + while (pLastElement != NULL) + { ppElement = &(Matrix->FirstInRow[ pLastElement->Row ]); + while ((pElement = *ppElement) != NULL) + { if (pElement == pLastElement) + *ppElement = NULL; /* Unlink last element in row. */ + else + ppElement = &pElement->NextInRow; /* Skip element. */ + } + pLastElement = pLastElement->NextInCol; + } + +/* Clean up some details. */ + Matrix->Size = Size - 1; + Matrix->Diag[Size] = NULL; + Matrix->FirstInRow[Size] = NULL; + Matrix->FirstInCol[Size] = NULL; + Matrix->CurrentSize--; + Matrix->ExtToIntRowMap[ExtRow] = -1; + Matrix->ExtToIntColMap[ExtCol] = -1; + Matrix->NeedsOrdering = YES; + + return; +} +#endif + + + + + + + + +#if PSEUDOCONDITION +/* + * CALCULATE PSEUDOCONDITION + * + * Computes the magnitude of the ratio of the largest to the smallest + * pivots. This quantity is an indicator of ill-conditioning in the + * matrix. If this ratio is large, and if the matrix is scaled such + * that uncertainties in the RHS and the matrix entries are + * equilibrated, then the matrix is ill-conditioned. However, a small + * ratio does not necessarily imply that the matrix is + * well-conditioned. This routine must only be used after a matrix has + * been factored by spOrderAndFactor() or spFactor() and before it is + * cleared by spClear() or spInitialize(). The pseudocondition is + * faster to compute than the condition number calculated by + * spCondition(), but is not as informative. + * + * >>> Returns: + * The magnitude of the ratio of the largest to smallest pivot used during + * previous factorization. If the matrix was singular, zero is returned. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix. + */ + +RealNumber +spPseudoCondition( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I; +register ArrayOfElementPtrs Diag; +RealNumber MaxPivot, MinPivot, Mag; + +/* Begin `spPseudoCondition'. */ + + ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) ); + if (Matrix->Error == spSINGULAR OR Matrix->Error == spZERO_DIAG) + return 0.0; + + Diag = Matrix->Diag; + MaxPivot = MinPivot = ELEMENT_MAG( Diag[1] ); + for (I = 2; I <= Matrix->Size; I++) + { Mag = ELEMENT_MAG( Diag[I] ); + if (Mag > MaxPivot) + MaxPivot = Mag; + else if (Mag < MinPivot) + MinPivot = Mag; + } + ASSERT( MaxPivot > 0.0); + return MaxPivot / MinPivot; +} +#endif + + + + + + + + +#if CONDITION +/* + * ESTIMATE CONDITION NUMBER + * + * Computes an estimate of the condition number using a variation on + * the LINPACK condition number estimation algorithm. This quantity is + * an indicator of ill-conditioning in the matrix. To avoid problems + * with overflow, the reciprocal of the condition number is returned. + * If this number is small, and if the matrix is scaled such that + * uncertainties in the RHS and the matrix entries are equilibrated, + * then the matrix is ill-conditioned. If the this number is near + * one, the matrix is well conditioned. This routine must only be + * used after a matrix has been factored by spOrderAndFactor() or + * spFactor() and before it is cleared by spClear() or spInitialize(). + * + * Unlike the LINPACK condition number estimator, this routines + * returns the L infinity condition number. This is an artifact of + * Sparse placing ones on the diagonal of the upper triangular matrix + * rather than the lower. This difference should be of no importance. + * + * References: + * A.K. Cline, C.B. Moler, G.W. Stewart, J.H. Wilkinson. An estimate + * for the condition number of a matrix. SIAM Journal on Numerical + * Analysis. Vol. 16, No. 2, pages 368-375, April 1979. + * + * J.J. Dongarra, C.B. Moler, J.R. Bunch, G.W. Stewart. LINPACK + * User's Guide. SIAM, 1979. + * + * Roger G. Grimes, John G. Lewis. Condition number estimation for + * sparse matrices. SIAM Journal on Scientific and Statistical + * Computing. Vol. 2, No. 4, pages 384-388, December 1981. + * + * Dianne Prost O'Leary. Estimating matrix condition numbers. SIAM + * Journal on Scientific and Statistical Computing. Vol. 1, No. 2, + * pages 205-209, June 1980. + * + * >>> Returns: + * The reciprocal of the condition number. If the matrix was singular, + * zero is returned. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix. + * NormOfMatrix (RealNumber) + * The L-infinity norm of the unfactored matrix as computed by + * spNorm(). + * pError (int *) + * Used to return error code. + * + * >>> Possible errors: + * spSINGULAR + * spNO_MEMORY + */ + +RealNumber +spCondition( eMatrix, NormOfMatrix, pError ) + +char *eMatrix; +RealNumber NormOfMatrix; +int *pError; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register RealVector T, Tm; +register int I, K, Row; +ElementPtr pPivot; +int Size; +RealNumber E, Em, Wp, Wm, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor; +RealNumber Linpack, OLeary, InvNormOfInverse, ComplexCondition(); +#define SLACK 1e4 + +/* Begin `spCondition'. */ + + ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) ); + *pError = Matrix->Error; + if (Matrix->Error >= spFATAL) return 0.0; + if (NormOfMatrix == 0.0) + { *pError = spSINGULAR; + return 0.0; + } + +#if spCOMPLEX + if (Matrix->Complex) + return ComplexCondition( Matrix, NormOfMatrix, pError ); +#endif + +#if REAL + Size = Matrix->Size; + T = Matrix->Intermediate; +#if spCOMPLEX + Tm = Matrix->Intermediate + Size; +#else + Tm = ALLOC( RealNumber, Size+1 ); + if (Tm == NULL) + { *pError = spNO_MEMORY; + return 0.0; + } +#endif + for (I = Size; I > 0; I--) T[I] = 0.0; + +/* + * Part 1. Ay = e. + * Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign + * chosen to maximize the size of w in Lw = e. Since the terms in w can + * get very large, scaling is used to avoid overflow. + */ + +/* Forward elimination. Solves Lw = e while choosing e. */ + E = 1.0; + for (I = 1; I <= Size; I++) + { pPivot = Matrix->Diag[I]; + if (T[I] < 0.0) Em = -E; else Em = E; + Wm = (Em + T[I]) * pPivot->Real; + if (ABS(Wm) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(Wm) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + E *= ScaleFactor; + Em *= ScaleFactor; + Wm = (Em + T[I]) * pPivot->Real; + } + Wp = (T[I] - Em) * pPivot->Real; + ASp = ABS(T[I] - Em); + ASm = ABS(Em + T[I]); + +/* Update T for both values of W, minus value is placed in Tm. */ + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Row = pElement->Row; + Tm[Row] = T[Row] - (Wm * pElement->Real); + T[Row] -= (Wp * pElement->Real); + ASp += ABS(T[Row]); + ASm += ABS(Tm[Row]); + pElement = pElement->NextInCol; + } + +/* If minus value causes more growth, overwrite T with its values. */ + if (ASm > ASp) + { T[I] = Wm; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { T[pElement->Row] = Tm[pElement->Row]; + pElement = pElement->NextInCol; + } + } + else T[I] = Wp; + } + +/* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */ + for (ASw = 0.0, I = Size; I > 0; I--) ASw += ABS(T[I]); + ScaleFactor = 1.0 / (SLACK * ASw); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + E *= ScaleFactor; + } + +/* Backward Substitution. Solves Uy = w.*/ + for (I = Size; I >= 1; I--) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { T[I] -= pElement->Real * T[pElement->Col]; + pElement = pElement->NextInRow; + } + if (ABS(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + E *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */ + for (ASy = 0.0, I = Size; I > 0; I--) ASy += ABS(T[I]); + ScaleFactor = 1.0 / (SLACK * ASy); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + ASy = 1.0 / SLACK; + E *= ScaleFactor; + } + +/* Compute infinity-norm of T for O'Leary's estimate. */ + for (MaxY = 0.0, I = Size; I > 0; I--) + if (MaxY < ABS(T[I])) MaxY = ABS(T[I]); + +/* + * Part 2. A* z = y where the * represents the transpose. + * Recall that A = LU implies A* = U* L*. + */ + +/* Forward elimination, U* v = y. */ + for (I = 1; I <= Size; I++) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { T[pElement->Col] -= T[I] * pElement->Real; + pElement = pElement->NextInRow; + } + if (ABS(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */ + for (ASv = 0.0, I = Size; I > 0; I--) ASv += ABS(T[I]); + ScaleFactor = 1.0 / (SLACK * ASv); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) T[I] *= ScaleFactor; + ASy *= ScaleFactor; + } + +/* Backward Substitution, L* z = v. */ + for (I = Size; I >= 1; I--) + { pPivot = Matrix->Diag[I]; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { T[I] -= pElement->Real * T[pElement->Row]; + pElement = pElement->NextInCol; + } + T[I] *= pPivot->Real; + if (ABS(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), ABS(T[I]) ); + for (K = Size; K > 0; K--) T[K] *= ScaleFactor; + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains z. */ + for (ASz = 0.0, I = Size; I > 0; I--) ASz += ABS(T[I]); + +#if NOT spCOMPLEX + FREE( Tm ); +#endif + + Linpack = ASy / ASz; + OLeary = E / MaxY; + InvNormOfInverse = MIN( Linpack, OLeary ); + return InvNormOfInverse / NormOfMatrix; +#endif /* REAL */ +} + + + + + +#if spCOMPLEX +/* + * ESTIMATE CONDITION NUMBER + * + * Complex version of spCondition(). + * + * >>> Returns: + * The reciprocal of the condition number. + * + * >>> Arguments: + * Matrix (MatrixPtr) + * Pointer to the matrix. + * NormOfMatrix (RealNumber) + * The L-infinity norm of the unfactored matrix as computed by + * spNorm(). + * pError (int *) + * Used to return error code. + * + * >>> Possible errors: + * spNO_MEMORY + */ + +static RealNumber +ComplexCondition( Matrix, NormOfMatrix, pError ) + +MatrixPtr Matrix; +RealNumber NormOfMatrix; +int *pError; +{ +register ElementPtr pElement; +register ComplexVector T, Tm; +register int I, K, Row; +ElementPtr pPivot; +int Size; +RealNumber E, Em, ASp, ASm, ASw, ASy, ASv, ASz, MaxY, ScaleFactor; +RealNumber Linpack, OLeary, InvNormOfInverse; +ComplexNumber Wp, Wm; + +/* Begin `ComplexCondition'. */ + + Size = Matrix->Size; + T = (ComplexVector)Matrix->Intermediate; + Tm = ALLOC( ComplexNumber, Size+1 ); + if (Tm == NULL) + { *pError = spNO_MEMORY; + return 0.0; + } + for (I = Size; I > 0; I--) T[I].Real = T[I].Imag = 0.0; + +/* + * Part 1. Ay = e. + * Solve Ay = LUy = e where e consists of +1 and -1 terms with the sign + * chosen to maximize the size of w in Lw = e. Since the terms in w can + * get very large, scaling is used to avoid overflow. + */ + +/* Forward elimination. Solves Lw = e while choosing e. */ + E = 1.0; + for (I = 1; I <= Size; I++) + { pPivot = Matrix->Diag[I]; + if (T[I].Real < 0.0) Em = -E; else Em = E; + Wm = T[I]; + Wm.Real += Em; + ASm = CMPLX_1_NORM( Wm ); + CMPLX_MULT_ASSIGN( Wm, *pPivot ); + if (CMPLX_1_NORM(Wm) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(Wm) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + E *= ScaleFactor; + Em *= ScaleFactor; + ASm *= ScaleFactor; + SCLR_MULT_ASSIGN( Wm, ScaleFactor ); + } + Wp = T[I]; + Wp.Real -= Em; + ASp = CMPLX_1_NORM( Wp ); + CMPLX_MULT_ASSIGN( Wp, *pPivot ); + +/* Update T for both values of W, minus value is placed in Tm. */ + pElement = pPivot->NextInCol; + while (pElement != NULL) + { Row = pElement->Row; + /* Cmplx expr: Tm[Row] = T[Row] - (Wp * *pElement). */ + CMPLX_MULT_SUBT( Tm[Row], Wm, *pElement, T[Row] ); + /* Cmplx expr: T[Row] -= Wp * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[Row], Wm, *pElement ); + ASp += CMPLX_1_NORM(T[Row]); + ASm += CMPLX_1_NORM(Tm[Row]); + pElement = pElement->NextInCol; + } + +/* If minus value causes more growth, overwrite T with its values. */ + if (ASm > ASp) + { T[I] = Wm; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { T[pElement->Row] = Tm[pElement->Row]; + pElement = pElement->NextInCol; + } + } + else T[I] = Wp; + } + +/* Compute 1-norm of T, which now contains w, and scale ||T|| to 1/SLACK. */ + for (ASw = 0.0, I = Size; I > 0; I--) ASw += CMPLX_1_NORM(T[I]); + ScaleFactor = 1.0 / (SLACK * ASw); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); + E *= ScaleFactor; + } + +/* Backward Substitution. Solves Uy = w.*/ + for (I = Size; I >= 1; I--) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { /* Cmplx expr: T[I] -= T[pElement->Col] * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Col], *pElement ); + pElement = pElement->NextInRow; + } + if (CMPLX_1_NORM(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + E *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains y, and scale ||T|| to 1/SLACK. */ + for (ASy = 0.0, I = Size; I > 0; I--) ASy += CMPLX_1_NORM(T[I]); + ScaleFactor = 1.0 / (SLACK * ASy); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); + ASy = 1.0 / SLACK; + E *= ScaleFactor; + } + +/* Compute infinity-norm of T for O'Leary's estimate. */ + for (MaxY = 0.0, I = Size; I > 0; I--) + if (MaxY < CMPLX_1_NORM(T[I])) MaxY = CMPLX_1_NORM(T[I]); + +/* + * Part 2. A* z = y where the * represents the transpose. + * Recall that A = LU implies A* = U* L*. + */ + +/* Forward elimination, U* v = y. */ + for (I = 1; I <= Size; I++) + { pElement = Matrix->Diag[I]->NextInRow; + while (pElement != NULL) + { /* Cmplx expr: T[pElement->Col] -= T[I] * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[pElement->Col], T[I], *pElement ); + pElement = pElement->NextInRow; + } + if (CMPLX_1_NORM(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains v, and scale ||T|| to 1/SLACK. */ + for (ASv = 0.0, I = Size; I > 0; I--) ASv += CMPLX_1_NORM(T[I]); + ScaleFactor = 1.0 / (SLACK * ASv); + if (ScaleFactor < 0.5) + { for (I = Size; I > 0; I--) SCLR_MULT_ASSIGN( T[I], ScaleFactor ); + ASy *= ScaleFactor; + } + +/* Backward Substitution, L* z = v. */ + for (I = Size; I >= 1; I--) + { pPivot = Matrix->Diag[I]; + pElement = pPivot->NextInCol; + while (pElement != NULL) + { /* Cmplx expr: T[I] -= T[pElement->Row] * *pElement. */ + CMPLX_MULT_SUBT_ASSIGN( T[I], T[pElement->Row], *pElement ); + pElement = pElement->NextInCol; + } + CMPLX_MULT_ASSIGN( T[I], *pPivot ); + if (CMPLX_1_NORM(T[I]) > SLACK) + { ScaleFactor = 1.0 / MAX( SQR( SLACK ), CMPLX_1_NORM(T[I]) ); + for (K = Size; K > 0; K--) SCLR_MULT_ASSIGN( T[K], ScaleFactor ); + ASy *= ScaleFactor; + } + } + +/* Compute 1-norm of T, which now contains z. */ + for (ASz = 0.0, I = Size; I > 0; I--) ASz += CMPLX_1_NORM(T[I]); + + FREE( Tm ); + + Linpack = ASy / ASz; + OLeary = E / MaxY; + InvNormOfInverse = MIN( Linpack, OLeary ); + return InvNormOfInverse / NormOfMatrix; +} +#endif /* spCOMPLEX */ + + + + + +/* + * L-INFINITY MATRIX NORM + * + * Computes the L-infinity norm of an unfactored matrix. It is a fatal + * error to pass this routine a factored matrix. + * + * One difficulty is that the rows may not be linked. + * + * >>> Returns: + * The largest absolute row sum of matrix. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix. + */ + +RealNumber +spNorm( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int I; +RealNumber Max = 0.0, AbsRowSum; + +/* Begin `spNorm'. */ + ASSERT( IS_SPARSE(Matrix) AND NOT IS_FACTORED(Matrix) ); + if (NOT Matrix->RowsLinked) spcLinkRows( Matrix ); + +/* Compute row sums. */ +#if REAL + if (NOT Matrix->Complex) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + AbsRowSum = 0.0; + while (pElement != NULL) + { AbsRowSum += ABS( pElement->Real ); + pElement = pElement->NextInRow; + } + if (Max < AbsRowSum) Max = AbsRowSum; + } + } +#endif +#if spCOMPLEX + if (Matrix->Complex) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + AbsRowSum = 0.0; + while (pElement != NULL) + { AbsRowSum += CMPLX_1_NORM( *pElement ); + pElement = pElement->NextInRow; + } + if (Max < AbsRowSum) Max = AbsRowSum; + } + } +#endif + return Max; +} +#endif /* CONDITION */ + + + + + + +#if STABILITY +/* + * STABILITY OF FACTORIZATION + * + * The following routines are used to gauge the stability of a + * factorization. If the factorization is determined to be too unstable, + * then the matrix should be reordered. The routines compute quantities + * that are needed in the computation of a bound on the error attributed + * to any one element in the matrix during the factorization. In other + * words, there is a matrix E = [e_ij] of error terms such that A+E = LU. + * This routine finds a bound on |e_ij|. Erisman & Reid [1] showed that + * |e_ij| < 3.01 u rho m_ij, where u is the machine rounding unit, + * rho = max a_ij where the max is taken over every row i, column j, and + * step k, and m_ij is the number of multiplications required in the + * computation of l_ij if i > j or u_ij otherwise. Barlow [2] showed that + * rho < max_i || l_i ||_p max_j || u_j ||_q where 1/p + 1/q = 1. + * + * The first routine finds the magnitude on the largest element in the + * matrix. If the matrix has not yet been factored, the largest + * element is found by direct search. If the matrix is factored, a + * bound on the largest element in any of the reduced submatrices is + * computed using Barlow with p = oo and q = 1. The ratio of these + * two numbers is the growth, which can be used to determine if the + * pivoting order is adequate. A large growth implies that + * considerable error has been made in the factorization and that it + * is probably a good idea to reorder the matrix. If a large growth + * in encountered after using spFactor(), reconstruct the matrix and + * refactor using spOrderAndFactor(). If a large growth is + * encountered after using spOrderAndFactor(), refactor using + * spOrderAndFactor() with the pivot threshold increased, say to 0.1. + * + * Using only the size of the matrix as an upper bound on m_ij and + * Barlow's bound, the user can estimate the size of the matrix error + * terms e_ij using the bound of Erisman and Reid. The second routine + * computes a tighter bound (with more work) based on work by Gear + * [3], |e_ij| < 1.01 u rho (t c^3 + (1 + t)c^2) where t is the + * threshold and c is the maximum number of off-diagonal elements in + * any row of L. The expensive part of computing this bound is + * determining the maximum number of off-diagonals in L, which changes + * only when the order of the matrix changes. This number is computed + * and saved, and only recomputed if the matrix is reordered. + * + * [1] A. M. Erisman, J. K. Reid. Monitoring the stability of the + * triangular factorization of a sparse matrix. Numerische + * Mathematik. Vol. 22, No. 3, 1974, pp 183-186. + * + * [2] J. L. Barlow. A note on monitoring the stability of triangular + * decomposition of sparse matrices. "SIAM Journal of Scientific + * and Statistical Computing." Vol. 7, No. 1, January 1986, pp 166-168. + * + * [3] I. S. Duff, A. M. Erisman, J. K. Reid. "Direct Methods for Sparse + * Matrices." Oxford 1986. pp 99. + */ + +/* + * LARGEST ELEMENT IN MATRIX + * + * >>> Returns: + * If matrix is not factored, returns the magnitude of the largest element in + * the matrix. If the matrix is factored, a bound on the magnitude of the + * largest element in any of the reduced submatrices is returned. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix. + */ + +RealNumber +spLargestElement( eMatrix ) + +char *eMatrix; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register int I; +RealNumber Mag, AbsColSum, Max = 0.0, MaxRow = 0.0, MaxCol = 0.0; +RealNumber Pivot; +ComplexNumber cPivot; +register ElementPtr pElement, pDiag; + +/* Begin `spLargestElement'. */ + ASSERT( IS_SPARSE(Matrix) ); + +#if REAL + if (Matrix->Factored AND NOT Matrix->Complex) + { if (Matrix->Error == spSINGULAR) return 0.0; + +/* Find the bound on the size of the largest element over all factorization. */ + for (I = 1; I <= Matrix->Size; I++) + { pDiag = Matrix->Diag[I]; + +/* Lower triangular matrix. */ + Pivot = 1.0 / pDiag->Real; + Mag = ABS( Pivot ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = Matrix->FirstInRow[I]; + while (pElement != pDiag) + { Mag = ABS( pElement->Real ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = pElement->NextInRow; + } + +/* Upper triangular matrix. */ + pElement = Matrix->FirstInCol[I]; + AbsColSum = 1.0; /* Diagonal of U is unity. */ + while (pElement != pDiag) + { AbsColSum += ABS( pElement->Real ); + pElement = pElement->NextInCol; + } + if (AbsColSum > MaxCol) MaxCol = AbsColSum; + } + } + else if (NOT Matrix->Complex) + { for (I = 1; I <= Matrix->Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { Mag = ABS( pElement->Real ); + if (Mag > Max) Max = Mag; + pElement = pElement->NextInCol; + } + } + return Max; + } +#endif +#if spCOMPLEX + if (Matrix->Factored AND Matrix->Complex) + { if (Matrix->Error == spSINGULAR) return 0.0; + +/* Find the bound on the size of the largest element over all factorization. */ + for (I = 1; I <= Matrix->Size; I++) + { pDiag = Matrix->Diag[I]; + +/* Lower triangular matrix. */ + CMPLX_RECIPROCAL( cPivot, *pDiag ); + Mag = CMPLX_1_NORM( cPivot ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = Matrix->FirstInRow[I]; + while (pElement != pDiag) + { Mag = CMPLX_1_NORM( *pElement ); + if (Mag > MaxRow) MaxRow = Mag; + pElement = pElement->NextInRow; + } + +/* Upper triangular matrix. */ + pElement = Matrix->FirstInCol[I]; + AbsColSum = 1.0; /* Diagonal of U is unity. */ + while (pElement != pDiag) + { AbsColSum += CMPLX_1_NORM( *pElement ); + pElement = pElement->NextInCol; + } + if (AbsColSum > MaxCol) MaxCol = AbsColSum; + } + } + else if (Matrix->Complex) + { for (I = 1; I <= Matrix->Size; I++) + { pElement = Matrix->FirstInCol[I]; + while (pElement != NULL) + { Mag = CMPLX_1_NORM( *pElement ); + if (Mag > Max) Max = Mag; + pElement = pElement->NextInCol; + } + } + return Max; + } +#endif + return MaxRow * MaxCol; +} + + + + +/* + * MATRIX ROUNDOFF ERROR + * + * >>> Returns: + * Returns a bound on the magnitude of the largest element in E = A - LU. + * + * >>> Arguments: + * eMatrix (char *) + * Pointer to the matrix. + * Rho (RealNumber) + * The bound on the magnitude of the largest element in any of the + * reduced submatrices. This is the number computed by the function + * spLargestElement() when given a factored matrix. If this number is + * negative, the bound will be computed automatically. + */ + +RealNumber +spRoundoff( eMatrix, Rho ) + +char *eMatrix; +RealNumber Rho; +{ +MatrixPtr Matrix = (MatrixPtr)eMatrix; +register ElementPtr pElement; +register int Count, I, MaxCount = 0; +RealNumber Reid, Gear; + +/* Begin `spRoundoff'. */ + ASSERT( IS_SPARSE(Matrix) AND IS_FACTORED(Matrix) ); + +/* Compute Barlow's bound if it is not given. */ + if (Rho < 0.0) Rho = spLargestElement( eMatrix ); + +/* Find the maximum number of off-diagonals in L if not previously computed. */ + if (Matrix->MaxRowCountInLowerTri < 0) + { for (I = Matrix->Size; I > 0; I--) + { pElement = Matrix->FirstInRow[I]; + Count = 0; + while (pElement->Col < I) + { Count++; + pElement = pElement->NextInRow; + } + if (Count > MaxCount) MaxCount = Count; + } + Matrix->MaxRowCountInLowerTri = MaxCount; + } + else MaxCount = Matrix->MaxRowCountInLowerTri; + +/* Compute error bound. */ + Gear = 1.01*((MaxCount + 1) * Matrix->RelThreshold + 1.0) * SQR(MaxCount); + Reid = 3.01 * Matrix->Size; + + if (Gear < Reid) + return (MACHINE_RESOLUTION * Rho * Gear); + else + return (MACHINE_RESOLUTION * Rho * Reid); +} +#endif + + + + + + + + +#if DOCUMENTATION +/* + * SPARSE ERROR MESSAGE + * + * This routine prints a short message to a stream describing the error + * error state of sparse. No message is produced if there is no error. + * + * >>> Arguments: + * eMatrix (char *) + * Matrix for which the error message is to be printed. + * Stream (FILE *) + * Stream to which the error message is to be printed. + * Originator (char *) + * Name of originator of error message. If NULL, `sparse' is used. + * If zero-length string, no originator is printed. + */ + +void +spErrorMessage( eMatrix, Stream, Originator ) + +char *eMatrix, *Originator; +FILE *Stream; +{ +int Row, Col, Error; + +/* Begin `spErrorMessage'. */ + if (eMatrix == NULL) + Error = spNO_MEMORY; + else + { ASSERT(((MatrixPtr)eMatrix)->ID == SPARSE_ID); + Error = ((MatrixPtr)eMatrix)->Error; + } + + if (Error == spOKAY) return; + if (Originator == NULL) Originator = "sparse"; + if (Originator[0] != '\0') fprintf( Stream, "%s: ", Originator); + if (Error >= spFATAL) + fprintf( Stream, "fatal error, "); + else + fprintf( Stream, "warning, "); +/* + * Print particular error message. + * Do not use switch statement because error codes may not be unique. + */ + if (Error == spPANIC) + fprintf( Stream, "Sparse called improperly.\n"); + else if (Error == spNO_MEMORY) + fprintf( Stream, "insufficient memory available.\n"); + else if (Error == spSINGULAR) + { spWhereSingular( eMatrix, &Row, &Col ); + fprintf( Stream, "singular matrix detected at row %d and column %d.\n", + Row, Col); + } + else if (Error == spZERO_DIAG) + { spWhereSingular( eMatrix, &Row, &Col ); + fprintf( Stream, "zero diagonal detected at row %d and column %d.\n", + Row, Col); + } + else if (Error == spSMALL_PIVOT) + { fprintf( Stream, + "unable to find a pivot that is larger than absolute threshold.\n"); + } + else ABORT(); + return; +} +#endif /* DOCUMENTATION */ diff --git a/src/misc/ChangeLog b/src/misc/ChangeLog new file mode 100644 index 000000000..1fa6bbd2f --- /dev/null +++ b/src/misc/ChangeLog @@ -0,0 +1,60 @@ +2000-03-11 Paolo Nenzi + + * missing_math.c: as Chris wrote: + In missing_math.c line 50: changed the preprocessor directive "#elif" to "#else" because the + elif must have a condition (ie. else if ...). + Again seemingly no adverse side effects. + +1999-09-07 Arno + + * string.c: put extra braces around assignment in if condition. + +1999-09-03 Emmanuel Rouat + + * misc_time.c: renamed time.c into misc_time.c + + * missing_math.c: renamed math.c into missing_math.c + + * *.c: added header file for all .c files + +1999-08-30 Paolo Nenzi + + * Removed suffix.h and replaced GENERIC with void + + * alloc.c: Modified the code of tmalloc, tralloc and txfree + functions. Now tmalloc uses calloc() instead of malloc+bzero + and all of them works on void *. + +1999-08-29 Emmanuel Rouat + + * Made function decls ANSI using protoize + +1999-08-28 Emmanuel Rouat + + * Removed all #includes of misc.h and util.h (now in spice.h) + +1999-08-08 Emmanuel Rouat + + * Makefile.am (libmisc_a_SOURCES): removed dos_dirs.c (unused) + + * string.c: changed HAS_INDEX in HAVE_INDEX + + * dup2.c (dup2): changed HAS_FCNTL in HAVE_FCNTL_H + +1999-08-06 Emmanuel Rouat + + * time.c: changed HAS_LOCALTIME in HAVE_LOCALTIME + + * dup2.c: + changed HAS_DUP2 into HAVE_DUP2 + +1999-08-05 Emmanuel Rouat + + * ivars.c (env_overr): removed HAS_ENVIRON tests + + * mktemp.c (smktemp): removed test on HAS_GETPID + +1999-08-03 Emmanuel Rouat + + * string.c (bcopy): changed HAS_BCOPY into HAVE_BCOPY + diff --git a/src/misc/Makefile.am b/src/misc/Makefile.am new file mode 100644 index 000000000..d3f96ba5a --- /dev/null +++ b/src/misc/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libmisc.a + +libmisc_a_SOURCES = \ + alloc.c \ + alloc.h \ + dup2.c \ + dup2.h \ + ivars.c \ + ivars.h \ + missing_math.c \ + missing_math.h \ + mktemp.c \ + mktemp.h \ + printnum.c \ + printnum.h \ + string.c \ + string.h \ + tilde.c \ + tilde.h \ + misc_time.c \ + misc_time.h + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/misc/alloc.c b/src/misc/alloc.c new file mode 100644 index 000000000..bea3931f5 --- /dev/null +++ b/src/misc/alloc.c @@ -0,0 +1,116 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + * Memory alloction functions + */ + +#include "ngspice.h" +#include +#include "alloc.h" + + +/* Malloc num bytes and initialize to zero. Fatal error if the space can't + * be malloc'd. Return NULL for a request for 0 bytes. + */ + +/* New implementation of tmalloc, it uses calloc and does not call bzero() */ + +void * +tmalloc(size_t num) +{ + void *s; + if (!num) + return NULL; + s = calloc(num,1); + if (!s){ + fprintf(stderr, + "malloc: Internal Error: can't allocate %d bytes. \n", num); + exit(EXIT_BAD); + } + return(s); +} + +void * +trealloc(void *ptr, size_t num) +{ + void *s; + + if (!num) { + if (ptr) + free(ptr); + return NULL; + } + + if (!ptr) + s = tmalloc(num); + else + s = realloc(ptr, num); + + if (!s) { + fprintf(stderr, + "realloc: Internal Error: can't allocate %d bytes.\n", num); + exit(EXIT_BAD); + } + return(s); +} + + + +/* Original Berkeley Implementation */ +/* +void * +tmalloc(size_t num) +{ + void *s; + + if (!num) + return NULL; + + s = malloc((unsigned) num); + if (!s) { + fprintf(stderr, + "malloc: Internal Error: can't allocate %d bytes.\n", num); + exit(EXIT_BAD); + } + + bzero(s, num); + + return(s); +} + +void * +trealloc(void *str, size_t num) +{ + void *s; + + if (!num) { + if (str) + free(str); + return NULL; + } + + if (!str) + s = tmalloc(num); + else + s = realloc(str, (unsigned) num); + + if (!s) { + fprintf(stderr, + "realloc: Internal Error: can't allocate %d bytes.\n", num); + exit(EXIT_BAD); + } + return(s); +} + +*/ + + +void +txfree(void *ptr) +{ + if (ptr) + free(ptr); +} + diff --git a/src/misc/alloc.h b/src/misc/alloc.h new file mode 100644 index 000000000..7a9a98386 --- /dev/null +++ b/src/misc/alloc.h @@ -0,0 +1,13 @@ +/************* + * Header file for alloc.c + * 1999 E. Rouat + ************/ + +#ifndef ALLOC_H_INCLUDED +#define ALLOC_H_INCLUDED + +void * tmalloc(size_t num); +void * trealloc(void *ptr, size_t num); +void txfree(void *ptr); + +#endif diff --git a/src/misc/dup2.c b/src/misc/dup2.c new file mode 100644 index 000000000..b25bd8861 --- /dev/null +++ b/src/misc/dup2.c @@ -0,0 +1,20 @@ +#include +#include "ngspice.h" +#include "dup2.h" + +#ifndef HAVE_DUP2 +#include + +dup2(int oldd, int newd) +{ +#ifdef HAVE_FCNTL_H + close(newd); +#ifdef F_DUPFD + (void) fcntl(oldd, F_DUPFD, newd); +#endif +#endif + return 0; +} +#else +int Dummy_Symbol; +#endif diff --git a/src/misc/dup2.h b/src/misc/dup2.h new file mode 100644 index 000000000..37462f014 --- /dev/null +++ b/src/misc/dup2.h @@ -0,0 +1,15 @@ +/************* + * Header file for dup2.c + * 1999 E. Rouat + ************/ + +#ifndef DUP2_H_INCLUDED +#define DUP2_H_INCLUDED + +#ifndef HAVE_DUP2 + +dup2(int oldd, int newd); + +#endif + +#endif diff --git a/src/misc/ivars.c b/src/misc/ivars.c new file mode 100644 index 000000000..20490d6a1 --- /dev/null +++ b/src/misc/ivars.c @@ -0,0 +1,64 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" +#include "ivars.h" +#include + +char *Spice_Path; +char *News_File; +char *Default_MFB_Cap; +char *Help_Path; +char *Lib_Path; + + +static void +env_overr(char **v, char *e) +{ + char *p; + if (v && e && (p = getenv(e))) + *v = p; +} + +static void +mkvar(char **p, char *path_prefix, char *var_dir, char *env_var) +{ + char *buffer; + + /* Override by environment variables */ + buffer = getenv(env_var); + if (buffer) + asprintf(p, "%s", buffer); + else + asprintf(p, "%s%s%s", path_prefix, DIR_PATHSEP, var_dir); +} + +void +ivars(void) +{ + + env_overr(&Spice_Exec_Dir, "SPICE_EXEC_DIR"); + env_overr(&Spice_Lib_Dir, "SPICE_LIB_DIR"); + + mkvar(&News_File, Spice_Lib_Dir, "news", "SPICE_NEWS"); + mkvar(&Default_MFB_Cap, Spice_Lib_Dir, "mfbcap", "SPICE_MFBCAP"); + mkvar(&Help_Path, Spice_Lib_Dir, "helpdir", "SPICE_HELP_DIR"); + mkvar(&Lib_Path, Spice_Lib_Dir, "scripts", "SPICE_SCRIPTS"); + mkvar(&Spice_Path, Spice_Exec_Dir, "ngspice", "SPICE_PATH"); + + env_overr(&Spice_Host, "SPICE_HOST"); + env_overr(&Bug_Addr, "SPICE_BUGADDR"); + env_overr(&Def_Editor, "SPICE_EDITOR"); + env_overr(&AsciiRawFile, "SPICE_ASCIIRAWFILE"); +} + +void +cleanvars(void) +{ + free(News_File); + free(Default_MFB_Cap); + free(Help_Path); + free(Lib_Path); + free(Spice_Path); +} diff --git a/src/misc/ivars.h b/src/misc/ivars.h new file mode 100644 index 000000000..dfbe30b18 --- /dev/null +++ b/src/misc/ivars.h @@ -0,0 +1,13 @@ +/************* + * Header file for ivars.c + * 1999 E. Rouat + ************/ + +#ifndef IVARS_H_INCLUDED +#define IVARS_H_INCLUDED + + +void ivars(void); +void cleanvars(void); + +#endif diff --git a/src/misc/misc_time.c b/src/misc/misc_time.c new file mode 100644 index 000000000..acbfd12af --- /dev/null +++ b/src/misc/misc_time.c @@ -0,0 +1,130 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + * Date and time utility functions + */ + +#include +#include "ngspice.h" +#include +#include "misc_time.h" + +#ifdef HAVE_LOCALTIME +#include +#endif + +#ifdef HAVE_GETRUSAGE +# include +# include +# include +#else +# ifdef HAVE_TIMES +# include +# include +# include +# else +# ifdef HAVE_FTIME +/* default to ftime if we can't get real CPU times */ +# include +# include +# endif +# endif +#endif + + + +/* Return the date. Return value is static data. */ + +char * +datestring(void) +{ + +#ifdef HAVE_LOCALTIME + static char tbuf[45]; + struct tm *tp; + char *ap; + int i; + + time_t tloc; + time(&tloc); + tp = localtime(&tloc); + ap = asctime(tp); + (void) sprintf(tbuf, "%.20s", ap); + (void) strcat(tbuf, ap + 19); + i = strlen(tbuf); + tbuf[i - 1] = '\0'; + return (tbuf); + +#else + + return ("today"); + +#endif +} + +/* return time interval in seconds and milliseconds */ + +#ifndef HAVE_GETRUSAGE +#ifndef HAVE_TIMES +#ifdef HAVE_FTIME + +struct timeb timebegin; + +void timediff(struct timeb *now, struct timeb *begin, int *sec, int *msec) +{ + + *msec = now->millitm - begin->millitm; + *sec = now->time - begin->time; + if (*msec < 0) { + *msec += 1000; + (*sec)--; + } + return; + +} + +#endif +#endif +#endif + +/* How many seconds have elapsed in running time. */ + +double +seconds(void) +{ +#ifdef HAVE_GETRUSAGE + struct rusage ruse; + +#ifdef PARALLEL_ARCH + return (TCGTIME_()); +#else + (void) getrusage(RUSAGE_SELF, &ruse); + return (ruse.ru_utime.tv_sec + (double) ruse.ru_utime.tv_usec / 1000000.0); +#endif /* PARALLEL_ARCH */ +#else +#ifdef HAVE_TIMES + + struct tms tmsbuf; + + times(&tmsbuf); + return((double) tmsbuf.tms_utime / HZ); + +#else +#ifdef HAVE_FTIME + struct timeb timenow; + int sec, msec; + + ftime(&timenow); + timediff(&timenow, &timebegin, &sec, &msec); + return(sec + (double) msec / 1000.0); + +#else /* unknown */ + /* don't know how to do this in general. */ + return(-1.0); /* Obvious error condition */ + +#endif /* !FTIME */ +#endif /* !SYSV */ +#endif /* !BSD */ +} diff --git a/src/misc/misc_time.h b/src/misc/misc_time.h new file mode 100644 index 000000000..d35b2e326 --- /dev/null +++ b/src/misc/misc_time.h @@ -0,0 +1,12 @@ +/************* + * Header file for misc_time.c + * 1999 E. Rouat + ************/ + +#ifndef MISC_TIME_H_INCLUDED +#define MISC_TIME_H_INCLUDED + +char * datestring(void); +double seconds(void); + +#endif diff --git a/src/misc/missing_math.c b/src/misc/missing_math.c new file mode 100644 index 000000000..096e0c780 --- /dev/null +++ b/src/misc/missing_math.c @@ -0,0 +1,98 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + +/* + * Missing math functions + */ +#include +#include "ngspice.h" +#include +#include "missing_math.h" + + + +#ifndef HAVE_LOGB + +double +logb(double x) +{ + double y = 0.0; + + if (x != 0.0) + { + if (x < 0.0) + x = - x; + while (x > 2.0) + { + y += 1.0; + x /= 2.0; + } + while (x < 1.0) + { + y -= 1.0; + x *= 2.0; + } + } + else + y = 0.0; + + return y; +} +#endif + + + + +#ifndef HAVE_SCALB +# ifdef HAVE_SCALBN +# define scalb scalbn +#else /* Chris Inbody */ + +double +scalb(double x, int n) +{ + double y, z = 1.0, k = 2.0; + + if (n < 0) { + n = -n; + k = 0.5; + } + + if (x != 0.0) + for (y = 1.0; n; n >>= 1) { + y *= k; + if (n & 1) + z *= y; + } + + return x * z; +} +# endif /* HAVE_SCALBN */ +#endif /* HAVE_SCALB */ + + +#ifndef HAVE_ERFC +/* From C. Hastings, Jr., Approximations for digital computers, + Princeton Univ. Press, 1955. + Approximation accurate to within 1.5E-7 + (making some assumptions about your machine's floating point mechanism) +*/ + +double +erfc(double x) + +{ + double t, z; + + t = 1/(1 + 0.3275911*x); + z = 1.061405429; + z = -1.453152027 + t * z; + z = 1.421413741 + t * z; + z = -0.284496736 + t * z; + z = 0.254829592 + t * z; + z = exp(-x*x) * t * z; + + return(z); +} +#endif diff --git a/src/misc/missing_math.h b/src/misc/missing_math.h new file mode 100644 index 000000000..49cf65160 --- /dev/null +++ b/src/misc/missing_math.h @@ -0,0 +1,23 @@ +/************* + * Header file for missing_math.c + * 1999 E. Rouat + ************/ + +#ifndef MISSING_MATH_H_INCLUDED +#define MISSING_MATH_H_INCLUDED + +#ifndef HAVE_ERFC +double erfc(double); +#endif + +#ifndef HAVE_LOGB +double logb(double); +#endif + +#ifndef HAVE_SCALB +# ifndef HAVE_SCALBN +double scalb(double, int); +#endif +#endif + +#endif diff --git a/src/misc/mktemp.c b/src/misc/mktemp.c new file mode 100644 index 000000000..39cbd0643 --- /dev/null +++ b/src/misc/mktemp.c @@ -0,0 +1,42 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + * A more portable version of the standard "mktemp( )" function + * + * FIXME: remove smktemp() and adjust all callers to use tmpfile(3). + */ + +#include "ngspice.h" +#include "stdio.h" +#include "mktemp.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef TEMPFORMAT +#define TEMPFORMAT "temp%s%d" +#endif + +char * +smktemp(char *id) +{ + char rbuf[513]; + char *nbuf; + int num; + + + num = getpid( ); + + + if (!id) + id = "sp"; + + sprintf(rbuf, TEMPFORMAT, id, num); + nbuf = (char *) malloc(strlen(rbuf) + 1); + strcpy(nbuf, rbuf); + + return nbuf; +} diff --git a/src/misc/mktemp.h b/src/misc/mktemp.h new file mode 100644 index 000000000..995d54aec --- /dev/null +++ b/src/misc/mktemp.h @@ -0,0 +1,11 @@ +/************* + * Header file for mktemp.c + * 1999 E. Rouat + ************/ + +#ifndef MKTEMP_H_INCLUDED +#define MKTEMP_H_INCLUDED + +char * smktemp(char *id); + +#endif diff --git a/src/misc/printnum.c b/src/misc/printnum.c new file mode 100644 index 000000000..6ff51adfb --- /dev/null +++ b/src/misc/printnum.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* Print a number in a reasonable form. This is the sort of thing that + * %G does, but more appropriate for spice. Returns static data. + */ + +#include "ngspice.h" +#include "printnum.h" +#include + +int cp_numdgt = -1; + +char * +printnum(double num) +{ + static char buf[128]; + int n; + + if (cp_numdgt > 1) + n = cp_numdgt; + else + n = 6; + if (num < 0.0) + n--; + + (void) sprintf(buf, "%.*le", n, num); + + return (buf); +} diff --git a/src/misc/printnum.h b/src/misc/printnum.h new file mode 100644 index 000000000..3995f210b --- /dev/null +++ b/src/misc/printnum.h @@ -0,0 +1,11 @@ +/************* + * Header file for printnum.c + * 1999 E. Rouat + ************/ + +#ifndef PRINTNUM_H_INCLUDED +#define PRINTNUM_H_INCLUDED + +char * printnum(double num); + +#endif diff --git a/src/misc/string.c b/src/misc/string.c new file mode 100644 index 000000000..54e114762 --- /dev/null +++ b/src/misc/string.c @@ -0,0 +1,183 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +/* + * String functions + */ + +#include +#include "ngspice.h" +#include "stdio.h" +#include "string.h" + +int +prefix(register char *p, register char *s) +{ + while (*p && (*p == *s)) + p++, s++; + if (!*p) + return (TRUE); + else + return (FALSE); +} + +/* Create a copy of a string. */ + +char * +copy(char *str) +{ + char *p; + + if ((p = tmalloc(strlen(str) + 1))) + (void) strcpy(p, str); + return(p); +} + +/* Determine whether sub is a substring of str. */ +/* Like strstr( ) XXX */ + +int +substring(register char *sub, register char *str) +{ + char *s, *t; + + while (*str) { + if (*str == *sub) { + t = str; + for (s = sub; *s; s++) { + if (!*t || (*s != *t++)) + break; + } + if (*s == '\0') + return (TRUE); + } + str++; + } + return (FALSE); +} + +/* Append one character to a string. Don't check for overflow. */ +/* Almost like strcat( ) XXX */ + +void +appendc(char *s, char c) +{ + while (*s) + s++; + *s++ = c; + *s = '\0'; + return; +} + +/* Try to identify an integer that begins a string. Stop when a non- + * numeric character is reached. + */ +/* Like atoi( ) XXX */ + +int +scannum(char *str) +{ + int i = 0; + + while(isdigit(*str)) + i = i * 10 + *(str++) - '0'; + return(i); +} + +/* Case insensitive str eq. */ +/* Like strcasecmp( ) XXX */ + +int +cieq(register char *p, register char *s) +{ + while (*p) { + if ((isupper(*p) ? tolower(*p) : *p) != + (isupper(*s) ? tolower(*s) : *s)) + return(FALSE); + p++; + s++; + } + return (*s ? FALSE : TRUE); +} + +/* Case insensitive prefix. */ + +int +ciprefix(register char *p, register char *s) +{ + while (*p) { + if ((isupper(*p) ? tolower(*p) : *p) != + (isupper(*s) ? tolower(*s) : *s)) + return(FALSE); + p++; + s++; + } + return (TRUE); +} + +void +strtolower(char *str) +{ + if (str) + while (*str) { + *str = tolower(*str); + str++; + } +} + +char * +gettok(char **s) +{ + char buf[BSIZE_SP]; + int i = 0; + char c; + int paren; + + paren = 0; + while (isspace(**s)) + (*s)++; + if (!**s) + return (NULL); + while ((c = **s) && !isspace(c)) { + if (c == '('/*)*/) + paren += 1; + else if (c == /*(*/')') + paren -= 1; + else if (c == ',' && paren < 1) + break; + buf[i++] = *(*s)++; + } + buf[i] = '\0'; + while (isspace(**s) || **s == ',') + (*s)++; + return (copy(buf)); +} + + + +#ifndef HAVE_BCOPY + +#ifndef bcopy +void +bcopy(register char *from, register char *to, register int num) +{ + while (num-- > 0) + *to++ = *from++; + return; +} +#endif + +#ifndef bzero +/* can't declare void here, because we've already used it in this file */ +/* and haven't declared it void before the use */ +int +bzero(register char *ptr, register int num) +{ + while (num-- > 0) + *ptr++ = '\0'; + return (0); +} + +#endif +#endif diff --git a/src/misc/string.h b/src/misc/string.h new file mode 100644 index 000000000..c03391abf --- /dev/null +++ b/src/misc/string.h @@ -0,0 +1,33 @@ +/************* + * Header file for string.c + * 1999 E. Rouat + ************/ + +#ifndef STRING_H_INCLUDED +#define STRING_H_INCLUDED + +int prefix(register char *p, register char *s); +char * copy(char *str); +int substring(register char *sub, register char *str); +void appendc(char *s, char c); +int scannum(char *str); +int cieq(register char *p, register char *s); +int ciprefix(register char *p, register char *s); +void strtolower(char *str); +char * gettok(char **s); + +#ifndef HAVE_INDEX + +char * index(register char *s, register char c); +char * rindex(register char *s,register char c ); + +#endif /* HAVE_INDEX */ + +#ifndef HAVE_BCOPY + +void bcopy(register char *from, register char *to, register int num); +int bzero(register char *ptr, register int num); + +#endif /* HAVE_BCOPY */ + +#endif diff --git a/src/misc/tilde.c b/src/misc/tilde.c new file mode 100644 index 000000000..8633e366b --- /dev/null +++ b/src/misc/tilde.c @@ -0,0 +1,60 @@ +/********** +Copyright 1991 Regents of the University of California. All rights reserved. +**********/ + + +#include +#include "ngspice.h" +#include +#include "tilde.h" + +#ifdef HAVE_PWD_H +#include +#endif + + + +char * +tilde_expand(char *string) +{ +#ifdef HAVE_PWD_H + struct passwd *pw; + /*extern struct passwd *getpwuid( );*/ + char buf[BSIZE_SP]; + char *k, c; + + if (!string) + return NULL; + + while (*string && isspace(*string)) + string++; + + if (*string != '~') + return copy(string); + + string += 1; + + if (!*string || *string == '/') { + pw = getpwuid(getuid()); + *buf = 0; + } else { + k = buf; + while ((c = *string) && c != '/') + *k++ = c, string++; + *k = 0; + pw = getpwnam(buf); + } + + if (pw) { + strcpy(buf, pw->pw_dir); + if (*string) + strcat(buf, string); + } else + return NULL; + + return copy(buf); + +#else + return copy(string); +#endif +} diff --git a/src/misc/tilde.h b/src/misc/tilde.h new file mode 100644 index 000000000..9f98faa16 --- /dev/null +++ b/src/misc/tilde.h @@ -0,0 +1,12 @@ +/************* + * Header file for tilde.c + * 1999 E. Rouat + ************/ + +#ifndef TILDE_H_INCLUDED +#define TILDE_H_INCLUDED + +char * tilde_expand(char *string); + + +#endif diff --git a/src/multidec.c b/src/multidec.c new file mode 100644 index 000000000..6ec9e60a1 --- /dev/null +++ b/src/multidec.c @@ -0,0 +1,427 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet Roychowdury +**********/ + +#include "ngspice.h" +#include +#include +#include "spmatrix.h" + +#define THRSH 0.01 +#define ABS_THRSH 0 +#define DIAG_PIVOTING 1 + +#undef DEBUG_LEVEL1 + + +extern void usage(); +extern void comments(); +extern double phi(); + +int + main (argc, argv) + int argc; + char **argv; +{ + int ch; + int errflg=0,i,j; + double l,c,ctot,r=0.0,g=0.0,k=0.0,lm=0.0,cm=0.0,len; + unsigned gotl=0,gotc=0,gotr=0,gotg=0,gotk=0,gotcm=0,gotlen=0; + unsigned gotname=0, gotnum=0; + char *name; + double **matrix, **inverse; + double *tpeigenvalues, *gammaj; + char *options; + int num, node; + char **pname, *s; + int use_opt; + char *optarg; + + pname = argv; + argv++; + argc--; + + ch = 0; + while (argc > 0) { + s = *argv++; + argc--; + while ((ch = *s++)) { + if (*s) + optarg = s; + else if (argc) + optarg = *argv; + else + optarg = NULL; + use_opt = 0; + + switch (ch) { + case 'o': + name = (char *) malloc((unsigned) (strlen(optarg)*sizeof(char))); + (void) strcpy(name,optarg); + gotname=1; + use_opt = 1; + break; + case 'l': + sscanf(optarg,"%lf",&l); + gotl=1; + use_opt = 1; + break; + case 'c': + sscanf(optarg,"%lf",&c); + gotc=1; + use_opt = 1; + break; + case 'r': + sscanf(optarg,"%lf",&r); + use_opt = 1; + gotr=1; + break; + case 'g': + sscanf(optarg,"%lf",&g); + use_opt = 1; + gotg=1; + break; + case 'k': + sscanf(optarg,"%lf",&k); + use_opt = 1; + gotk=1; + break; + case 'x': + sscanf(optarg,"%lf",&cm); + use_opt = 1; + gotcm=1; + break; + case 'L': + sscanf(optarg,"%lf",&len); + use_opt = 1; + gotlen=1; + break; + case 'n': + sscanf(optarg,"%d",&num); + use_opt = 1; + gotnum=1; + break; + case 'u': + usage(pname); + exit(1); + break; + case '-': + break; + default: + usage(pname); + exit(2); + break; + } + if (use_opt) { + if (optarg == s) + s += strlen(s); + else if (optarg) { + argc--; + argv++; + } + } + } + } + + if (errflg) { + usage(argv); + exit (2); + } + + if (gotl + gotc + gotname + gotnum + gotlen < 5) { + fprintf(stderr,"l, c, model_name, number_of_conductors and length must be specified.\n"); + fprintf(stderr,"%s -u for details.\n",pname[0]); + fflush(stdout); + exit(1); + } + + if ( (k<0.0?-k:k) >=1.0 ) { + fprintf(stderr,"Error: |k| must be less than 1.0\n"); + fflush(stderr); + exit(1); + } + + if (num == 1) { + fprintf(stdout,"* single conductor line\n"); + fflush(stdout); + exit(1); + } + + lm = l*k; + switch(num) { + + case 1: ctot = c; break; + case 2: ctot = c + cm; break; + default: ctot = c + 2*cm; break; + } + + comments(r,l,g,c,ctot,cm,lm,k,name,num,len); + + matrix = (double **) malloc((unsigned) (sizeof(double*)*(num+1))); + inverse = (double **) malloc((unsigned) (sizeof(double*)*(num+1))); + tpeigenvalues = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + + for (i=1;i<=num;i++) { + matrix[i] = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + inverse[i] = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + } + + for (i=1;i<=num;i++) { + tpeigenvalues[i] = -2.0 * cos(M_PI*i/(num+1)); + } + + for (i=1;i<=num;i++) { + for (j=1;j<=num;j++) { + matrix[i][j] = phi(i-1,tpeigenvalues[j]); + } + } + gammaj = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + + for (j=1;j<=num;j++) { + gammaj[j] = 0.0; + for (i=1;i<=num;i++) { + gammaj[j] += matrix[i][j] * matrix[i][j]; + } + gammaj[j] = sqrt(gammaj[j]); + } + + for (j=1;j<=num;j++) { + for (i=1;i<=num; i++) { + matrix[i][j] /= gammaj[j]; + } + } + + free(gammaj); + + /* matrix = M set up */ + + { + char *othermatrix; + double *rhs, *solution; + double *irhs, *isolution; + int errflg, err, singular_row, singular_col; + double *elptr; + + rhs = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + irhs = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + solution = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + isolution = (double *) malloc((unsigned) (sizeof(double)*(num+1))); + + othermatrix = spCreate(num,0,&errflg); + + for (i=1;i<=num;i++) { + for (j=1; j<=num; j++) { + elptr = spGetElement(othermatrix,i,j); + *elptr = matrix[i][j]; + } + } + +#ifdef DEBUG_LEVEL1 + (void) spPrint(othermatrix,0,1,0); +#endif + + for (i=1;i<=num;i++) rhs[i] = 0.0; + rhs[1]=1.0; + + err = + spOrderAndFactor(othermatrix,rhs,THRSH,ABS_THRSH,DIAG_PIVOTING); + + spErrorMessage(othermatrix,stderr,NULL); + + switch(err) { + + case spNO_MEMORY: + fprintf(stderr,"No memory in spOrderAndFactor\n"); + fflush(stderr); + exit(1); + case spSINGULAR: + (void) + spWhereSingular(othermatrix,&singular_row,&singular_col); + fprintf(stderr,"Singular matrix: problem in row %d and col %d\n", singular_row, singular_col); + fflush(stderr); + exit(1); +#ifdef notdef + /* For the original "sparse" interface; doesn't work with the spice3 interface + to sparse */ + case spSMALL_PIVOT: + fprintf(stderr,"* Warning: matrix is illconditioned.\n"); + fflush(stderr); + break; +#endif + default: break; + } + + for (i=1;i<=num;i++) { + for (j=1;j<=num;j++) { + rhs[j] = (j==i?1.0:0.0); + irhs[j] = 0.0; + } + (void) spSolveTransposed(othermatrix,rhs,solution, irhs, isolution); + for (j=1;j<=num;j++) { + inverse[i][j] = solution[j]; + } + } + + free(rhs); free(solution); + } + + /* inverse = M^{-1} set up */ + + fprintf(stdout,"\n"); + fprintf(stdout,"* Lossy line models\n"); + + options = (char *) malloc((unsigned) 256); + (void) strcpy(options,"rel=1.2 nocontrol"); + for (i=1;i<=num;i++) { + fprintf(stdout,".model mod%d_%s ltra %s r=%0.12g l=%0.12g g=%0.12g c=%0.12g len=%0.12g\n", + i,name,options,r,l+tpeigenvalues[i]*lm,g,ctot-tpeigenvalues[i]*cm,len); + /*i,name,options,r,l+tpeigenvalues[i]*lm,g,ctot+tpeigenvalues[i]*cm,len);*/ + } + + + fprintf(stdout,"\n"); + fprintf(stdout,"* subcircuit m_%s - modal transformation network for %s\n",name,name); + fprintf(stdout,".subckt m_%s", name); + for (i=1;i<= 2*num; i++) { + fprintf(stdout," %d",i); + } + fprintf(stdout,"\n"); + for (j=1;j<=num;j++) fprintf(stdout,"v%d %d 0 0v\n",j,j+2*num); + + for (j=1;j<=num;j++) { + for (i=1; i<=num; i++) { + fprintf(stdout,"f%d 0 %d v%d %0.12g\n", + (j-1)*num+i,num+j,i,inverse[j][i]); + } + } + + node = 3*num+1; + for (j=1;j<=num;j++) { + fprintf(stdout,"e%d %d %d %d 0 %0.12g\n", (j-1)*num+1, + node, 2*num+j, num+1, matrix[j][1]); + node++; + for (i=2; i -c\n",argv[0]); +fprintf(stderr," -r -g \n"); +fprintf(stderr," -k \n"); +fprintf(stderr," -x -o \n"); +fprintf(stderr," -n -L -u\n"); +fprintf(stderr,"Example: %s -n4 -l9e-9 -c20e-12 -r5.3 -x5e-12 -k0.7 -otest -L5.4\n\n",argv[0]); + +fprintf(stderr,"See \"Efficient Transient Simulation of Lossy Interconnect\",\n"); +fprintf(stderr,"J.S. Roychowdhury and D.O. Pederson, Proc. DAC 91 for details\n"); +fprintf(stderr,"\n"); +fflush(stderr); +} + +void +comments(r,l,g,c,ctot,cm,lm,k,name,num,len) +double r,l,g,c,ctot,cm,lm,k,len; +char *name; +int num; +{ + +fprintf(stdout,"* Subcircuit %s\n",name); +fprintf(stdout,"* %s is a subcircuit that models a %d-conductor transmission line with\n",name,num); +fprintf(stdout,"* the following parameters: l=%g, c=%g, r=%g, g=%g,\n",l,c,r,g); +fprintf(stdout,"* inductive_coeff_of_coupling k=%g, inter-line capacitance cm=%g,\n",k,cm); +fprintf(stdout,"* length=%g. Derived parameters are: lm=%g, ctot=%g.\n",len,lm,ctot); +fprintf(stdout,"* \n"); +fprintf(stdout,"* It is important to note that the model is a simplified one - the\n"); +fprintf(stdout,"* following assumptions are made: 1. The self-inductance l, the\n"); +fprintf(stdout,"* self-capacitance ctot (note: not c), the series resistance r and the\n"); +fprintf(stdout,"* parallel capacitance g are the same for all lines, and 2. Each line\n"); +fprintf(stdout,"* is coupled only to the two lines adjacent to it, with the same\n"); +fprintf(stdout,"* coupling parameters cm and lm. The first assumption implies that edge\n"); +fprintf(stdout,"* effects have to be neglected. The utility of these assumptions is\n"); +fprintf(stdout,"* that they make the sL+R and sC+G matrices symmetric, tridiagonal and\n"); +fprintf(stdout,"* Toeplitz, with useful consequences (see \"Efficient Transient\n"); +fprintf(stdout,"* Simulation of Lossy Interconnect\", by J.S. Roychowdhury and\n"); +fprintf(stdout,"* D.O Pederson, Proc. DAC 91).\n\n"); +fprintf(stdout,"* It may be noted that a symmetric two-conductor line is\n"); +fprintf(stdout,"* represented accurately by this model.\n\n"); +fprintf(stdout,"* Subckt node convention:\n"); +fprintf(stdout,"* \n"); +fprintf(stdout,"* |--------------------------|\n"); +fprintf(stdout,"* 1-----| |-----n+1\n"); +fprintf(stdout,"* 2-----| |-----n+2\n"); +fprintf(stdout,"* : | n-wire multiconductor | :\n"); +fprintf(stdout,"* : | line | :\n"); +fprintf(stdout,"* n-1-----|(node 0=common gnd plane) |-----2n-1\n"); +fprintf(stdout,"* n-----| |-----2n\n"); +fprintf(stdout,"* |--------------------------|\n\n"); +fflush(stdout); +} + +double +phi(i,arg) + int i; + double arg; +{ + double rval; + + switch (i) { + + case 0: + rval = 1.0; + break; + case 1: + rval = arg; + break; + default: + rval = arg*phi(i-1,arg) - phi(i-2,arg); + } + return rval; +} diff --git a/src/ngspice.c b/src/ngspice.c new file mode 100644 index 000000000..b30de3a59 --- /dev/null +++ b/src/ngspice.c @@ -0,0 +1,232 @@ +/* Configuration file for ng-spice */ +#include + +#include "conf.h" + +/* + * Analyses + */ +#define AN_op +#define AN_dc +#define AN_tf +#define AN_ac +#define AN_tran +#define AN_pz +#define AN_disto +#define AN_noise +#define AN_sense + +/* + * Devices + */ +#define DEV_asrc +#define DEV_bjt +#define DEV_bsim1 +#define DEV_bsim2 +#define DEV_bsim3 +#define DEV_bsim4 +#define DEV_bsim3v1 +#define DEV_bsim3v2 +#define DEV_cap +#define DEV_cccs +#define DEV_ccvs +#define DEV_csw +#define DEV_dio +#define DEV_ind +#define DEV_isrc +#define DEV_jfet +#define DEV_jfet2 +#define DEV_ltra +#define DEV_mes +#define DEV_mos1 +#define DEV_mos2 +#define DEV_mos3 +#define DEV_mos6 +#define DEV_res +#define DEV_sw +#define DEV_tra +#define DEV_urc +#define DEV_vccs +#define DEV_vcvs +#define DEV_vsrc + +#define DEVICES_USED "asrc bjt bsim1 bsim2 bsim3 bsim3v2 bsim3v1 cap cccs ccvs csw dio ind isrc jfet ltra mes mos1 mos2 mos3 mos6 res sw tra urc vccs vcvs vsrc" +#define ANALYSES_USED "op dc tf ac tran pz disto noise sense" + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" + + +#define CONFIG + + + +#include +#include "noisedef.h" +#include "devdefs.h" +#include "suffix.h" + +#include "asrc/asrcitf.h" +#include "bjt/bjtitf.h" +#include "cap/capitf.h" +#include "cccs/cccsitf.h" +#include "ccvs/ccvsitf.h" +#include "csw/cswitf.h" +#include "dio/dioitf.h" +#include "ind/inditf.h" +#include "isrc/isrcitf.h" +#include "mos1/mos1itf.h" +#include "mos6/mos6itf.h" +#include "res/resitf.h" +#include "sw/switf.h" +#include "vccs/vccsitf.h" +#include "vcvs/vcvsitf.h" +#include "vsrc/vsrcitf.h" +#include "bsim1/bsim1itf.h" +#include "bsim2/bsim2itf.h" +#include "bsim3/bsim3itf.h" +#include "bsim4/bsim4itf.h" +#include "bsim3v1/bsim3v1itf.h" +#include "bsim3v2/bsim3v2itf.h" +#include "mos2/mos2itf.h" +#include "mos3/mos3itf.h" +#include "jfet/jfetitf.h" +#include "jfet2/jfet2itf.h" +#include "mes/mesitf.h" +#include "ltra/ltraitf.h" +#include "tra/traitf.h" +#include "urc/urcitf.h" + + + +extern SPICEanalysis OPTinfo; +extern SPICEanalysis ACinfo; +extern SPICEanalysis DCTinfo; +extern SPICEanalysis DCOinfo; +extern SPICEanalysis TRANinfo; +extern SPICEanalysis PZinfo; +extern SPICEanalysis TFinfo; +extern SPICEanalysis DISTOinfo; +extern SPICEanalysis NOISEinfo; +extern SPICEanalysis SENSinfo; + + +SPICEanalysis *analInfo[] = { + &OPTinfo, + &ACinfo, + &DCTinfo, + &DCOinfo, + &TRANinfo, + &PZinfo, + &TFinfo, + &DISTOinfo, + &NOISEinfo, + &SENSinfo, + +}; + +int ANALmaxnum = sizeof(analInfo)/sizeof(SPICEanalysis*); +SPICEdev *DEVices[] = { + + /* URC must appear before the resistor, capacitor, and diode */ + &URCinfo, + &ASRCinfo, + &BJTinfo, + &B1info, + &B2info, + &BSIM3info, + &B4info, + &BSIM3V2info, + &BSIM3V1info, + &CAPinfo, + &CCCSinfo, + &CCVSinfo, + &CSWinfo, + &DIOinfo, + &INDinfo, + &MUTinfo, + &ISRCinfo, + &JFETinfo, + &JFET2info, + <RAinfo, + &MESinfo, + &MOS1info, + &MOS2info, + &MOS3info, + &MOS6info, + &RESinfo, + &SWinfo, + &TRAinfo, + &VCCSinfo, + &VCVSinfo, + &VSRCinfo, +}; + +/* my internal global constant for number of device types */ +int DEVmaxnum = sizeof(DEVices)/sizeof(SPICEdev *); +/* XXX Should be -1 ? There is always an extra null element at the end ? */ +static char * specSigList[] = { + "time" +}; + +static IFparm nodeParms[] = { + IP( "nodeset",PARM_NS ,IF_REAL,"suggested initial voltage"), + IP( "ic",PARM_IC ,IF_REAL,"initial voltage"), + IP( "type",PARM_NODETYPE ,IF_INTEGER,"output type of equation") +}; + +IFsimulator SIMinfo = { + "ngspice", /* name */ + "Circuit level simulation program", /* more about me */ + Spice_Version, /* version */ + + CKTinit, /* newCircuit function */ + CKTdestroy, /* deleteCircuit function */ + + CKTnewNode, /* newNode function */ + CKTground, /* groundNode function */ + CKTbindNode, /* bindNode function */ + CKTfndNode, /* findNode function */ + CKTinst2Node, /* instToNode function */ + CKTsetNodPm, /* setNodeParm function */ + CKTaskNodQst, /* askNodeQuest function */ + CKTdltNod, /* deleteNode function */ + + CKTcrtElt, /* newInstance function */ + CKTparam, /* setInstanceParm function */ + CKTask, /* askInstanceQuest function */ + CKTfndDev, /* findInstance funciton */ + CKTdltInst, /* deleteInstance function */ + + CKTmodCrt, /* newModel function */ + CKTmodParam, /* setModelParm function */ + CKTmodAsk, /* askModelQuest function */ + CKTfndMod, /* findModel function */ + CKTdltMod, /* deleteModel function */ + + CKTnewTask, /* newTask function */ + CKTnewAnal, /* newAnalysis function */ + CKTsetAnalPm, /* setAnalysisParm function */ + CKTaskAnalQ, /* askAnalysisQuest function */ + CKTfndAnal, /* findAnalysis function */ + CKTfndTask, /* findTask function */ + CKTdelTask, /* deleteTask function */ + + CKTdoJob, /* doAnalyses function */ + CKTtrouble, /* non-convergence message function */ + + sizeof(DEVices)/sizeof(SPICEdev *), + (IFdevice**)DEVices, + + sizeof(analInfo)/sizeof(SPICEanalysis *), + (IFanalysis **)analInfo, + + sizeof(nodeParms)/sizeof(IFparm), + nodeParms, + + sizeof(specSigList)/sizeof(char *), + specSigList, +}; diff --git a/src/ngspice.idx b/src/ngspice.idx new file mode 100644 index 000000000..5036ddd30 Binary files /dev/null and b/src/ngspice.idx differ diff --git a/src/ngspice.txt b/src/ngspice.txt new file mode 100644 index 000000000..f54c3b931 --- /dev/null +++ b/src/ngspice.txt @@ -0,0 +1,8271 @@ +SUBJECT: main +TITLE: Table of Contents +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +SUBTOPIC: SPICE:INTRODUCTION +SUBTOPIC: SPICE:CIRCUIT DESCRIPTION +SUBTOPIC: SPICE:CIRCUIT ELEMENTS AND MODELS +SUBTOPIC: SPICE:ANALYSES AND OUTPUT CONTROL +SUBTOPIC: SPICE:INTERACTIVE INTERPRETER +SUBTOPIC: SPICE:BIBLIOGRAPHY +SUBTOPIC: SPICE:APPENDIX A +SUBTOPIC: SPICE:APPENDIX B +SUBJECT: INTRODUCTION +TITLE: INTRODUCTION +TEXT: H +TEXT: H _1. _I_N_T_R_O_D_U_C_T_I_O_N +TEXT: H +TEXT: H +TEXT: H SPICE is a general-purpose circuit simulation program +TEXT: H for nonlinear dc, nonlinear transient, and linear ac ana- +TEXT: H lyses. Circuits may contain resistors, capacitors, induc- +TEXT: H tors, mutual inductors, independent voltage and current +TEXT: H sources, four types of dependent sources, lossless and lossy +TEXT: H transmission lines (two separate implementations), switches, +TEXT: H uniform distributed RC lines, and the five most common sem- +TEXT: H iconductor devices: diodes, BJTs, JFETs, MESFETs, and MOS- +TEXT: H FETs. +TEXT: H +TEXT: H The SPICE3 version is based directly on SPICE 2G.6. +TEXT: H While SPICE3 is being developed to include new features, it +TEXT: H continues to support those capabilities and models which +TEXT: H remain in extensive use in the SPICE2 program. +TEXT: H +TEXT: H SPICE has built-in models for the semiconductor dev- +TEXT: H ices, and the user need specify only the pertinent model +TEXT: H parameter values. The model for the BJT is based on the +TEXT: H integral-charge model of Gummel and Poon; however, if the +TEXT: H Gummel- Poon parameters are not specified, the model reduces +TEXT: H to the simpler Ebers-Moll model. In either case, charge- +TEXT: H storage effects, ohmic resistances, and a current-dependent +TEXT: H output conductance may be included. The diode model can be +TEXT: H used for either junction diodes or Schottky barrier diodes. +TEXT: H The JFET model is based on the FET model of Shichman and +TEXT: H Hodges. Six MOSFET models are implemented: MOS1 is +TEXT: H described by a square-law I-V characteristic, MOS2 [1] is an +TEXT: H analytical model, while MOS3 [1] is a semi-empirical model; +TEXT: H MOS6 [2] is a simple analytic model accurate in the short- +TEXT: H channel region; MOS4 [3, 4] and MOS5 [5] are the BSIM +TEXT: H (Berkeley Short-channel IGFET Model) and BSIM2. MOS2, MOS3, +TEXT: H and MOS4 include second-order effects such as channel-length +TEXT: H modulation, subthreshold conduction, scattering-limited +TEXT: H velocity saturation, small-size effects, and charge- +TEXT: H controlled capacitances. +SUBTOPIC: SPICE:TYPES OF ANALYSIS +SUBTOPIC: SPICE:ANALYSIS AT DIFFERENT TEMPERATURES +SUBTOPIC: SPICE:CONVERGENCE + +SUBJECT: TYPES OF ANALYSIS +TITLE: TYPES OF ANALYSIS +TEXT: H +TEXT: H _1._1. _T_Y_P_E_S _O_F _A_N_A_L_Y_S_I_S +TEXT: H +SUBTOPIC: SPICE:DC Analysis +SUBTOPIC: SPICE:AC SmallSignal Analysis +SUBTOPIC: SPICE:Transient Analysis +SUBTOPIC: SPICE:PoleZero Analysis +SUBTOPIC: SPICE:SmallSignal Distortion Analysis +SUBTOPIC: SPICE:Sensitivity Analysis +SUBTOPIC: SPICE:Noise Analysis + +SUBJECT: DC Analysis +TITLE: DC Analysis +TEXT: H +TEXT: H _1._1._1. _D_C _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H +TEXT: H The dc analysis portion of SPICE determines the dc +TEXT: H operating point of the circuit with inductors shorted and +TEXT: H capacitors opened. The dc analysis options are specified on +TEXT: H the .DC, .TF, and .OP control lines. A dc analysis is +TEXT: H automatically performed prior to a transient analysis to +TEXT: H determine the transient initial conditions, and prior to an +TEXT: H ac small-signal analysis to determine the linearized, +TEXT: H small-signal models for nonlinear devices. If requested, +TEXT: H the dc small-signal value of a transfer function (ratio of +TEXT: H output variable to input source), input resistance, and out- +TEXT: H put resistance is also computed as a part of the dc solu- +TEXT: H tion. The dc analysis can also be used to generate dc +TEXT: H transfer curves: a specified independent voltage or current +TEXT: H source is stepped over a user-specified range and the dc +TEXT: H output variables are stored for each sequential source +TEXT: H value. +TEXT: H + +SUBJECT: AC SmallSignal Analysis +TITLE: AC Small-Signal Analysis +TEXT: H +TEXT: H _1._1._2. _A_C _S_m_a_l_l-_S_i_g_n_a_l _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H +TEXT: H The ac small-signal portion of SPICE computes the ac +TEXT: H output variables as a function of frequency. The program +TEXT: H first computes the dc operating point of the circuit and +TEXT: H determines linearized, small-signal models for all of the +TEXT: H nonlinear devices in the circuit. The resultant linear cir- +TEXT: H cuit is then analyzed over a user-specified range of fre- +TEXT: H quencies. The desired output of an ac small- signal +TEXT: H analysis is usually a transfer function (voltage gain, tran- +TEXT: H simpedance, etc). If the circuit has only one ac input, it +TEXT: H is convenient to set that input to unity and zero phase, so +TEXT: H that output variables have the same value as the transfer +TEXT: H function of the output variable with respect to the input. +TEXT: H + +SUBJECT: Transient Analysis +TITLE: Transient Analysis +TEXT: H +TEXT: H _1._1._3. _T_r_a_n_s_i_e_n_t _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H The transient analysis portion of SPICE computes the +TEXT: H transient output variables as a function of time over a +TEXT: H user-specified time interval. The initial conditions are +TEXT: H automatically determined by a dc analysis. All sources +TEXT: H which are not time dependent (for example, power supplies) +TEXT: H are set to their dc value. The transient time interval is +TEXT: H specified on a .TRAN control line. +TEXT: H + +SUBJECT: PoleZero Analysis +TITLE: Pole-Zero Analysis +TEXT: H +TEXT: H _1._1._4. _P_o_l_e-_Z_e_r_o _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H +TEXT: H The pole-zero analysis portion of SPICE computes the +TEXT: H poles and/or zeros in the small-signal ac transfer function. +TEXT: H The program first computes the dc operating point and then +TEXT: H determines the linearized, small-signal models for all the +TEXT: H nonlinear devices in the circuit. This circuit is then used +TEXT: H to find the poles and zeros of the transfer function. +TEXT: H +TEXT: H Two types of transfer functions are allowed : one of +TEXT: H the form (output voltage)/(input voltage) and the other of +TEXT: H the form (output voltage)/(input current). These two types +TEXT: H of transfer functions cover all the cases and one can find +TEXT: H the poles/zeros of functions like input/output impedance and +TEXT: H voltage gain. The input and output ports are specified as +TEXT: H two pairs of nodes. +TEXT: H +TEXT: H The pole-zero analysis works with resistors, capaci- +TEXT: H tors, inductors, linear-controlled sources, independent +TEXT: H sources, BJTs, MOSFETs, JFETs and diodes. Transmission +TEXT: H lines are not supported. +TEXT: H +TEXT: H The method used in the analysis is a sub-optimal numer- +TEXT: H ical search. For large circuits it may take a considerable +TEXT: H time or fail to find all poles and zeros. For some cir- +TEXT: H cuits, the method becomes "lost" and finds an excessive +TEXT: H number of poles or zeros. +TEXT: H + +SUBJECT: SmallSignal Distortion Analysis +TITLE: Small-Signal Distortion Analysis +TEXT: H +TEXT: H _1._1._5. _S_m_a_l_l-_S_i_g_n_a_l _D_i_s_t_o_r_t_i_o_n _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H +TEXT: H The distortion analysis portion of SPICE computes +TEXT: H steady-state harmonic and intermodulation products for small +TEXT: H input signal magnitudes. If signals of a single frequency +TEXT: H are specified as the input to the circuit, the complex +TEXT: H values of the second and third harmonics are determined at +TEXT: H every point in the circuit. If there are signals of two +TEXT: H frequencies input to the circuit, the analysis finds out the +TEXT: H complex values of the circuit variables at the sum and +TEXT: H difference of the input frequencies, and at the difference +TEXT: H of the smaller frequency from the second harmonic of the +TEXT: H larger frequency. +TEXT: H +TEXT: H Distortion analysis is supported for the following non- +TEXT: H linear devices: diodes (DIO), BJT, JFET, MOSFETs (levels 1, +TEXT: H 2, 3, 4/BSIM1, 5/BSIM2, and 6) and MESFETS. All linear dev- +TEXT: H ices are automatically supported by distortion analysis. If +TEXT: H there are switches present in the circuit, the analysis con- +TEXT: H tinues to be accurate provided the switches do not change +TEXT: H state under the small excitations used for distortion calcu- +TEXT: H lations. +TEXT: H + +SUBJECT: Sensitivity Analysis +TITLE: Sensitivity Analysis +TEXT: H +TEXT: H _1._1._6. _S_e_n_s_i_t_i_v_i_t_y _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H +TEXT: H Spice3 will calculate either the DC operating-point +TEXT: H sensitivity or the AC small-signal sensitivity of an output +TEXT: H variable with respect to all circuit variables, including +TEXT: H model parameters. Spice calculates the difference in an +TEXT: H output variable (either a node voltage or a branch current) +TEXT: H by perturbing each parameter of each device independently. +TEXT: H Since the method is a numerical approximation, the results +TEXT: H may demonstrate second order affects in highly sensitive +TEXT: H parameters, or may fail to show very low but non-zero sensi- +TEXT: H tivity. Further, since each variable is perturb by a small +TEXT: H fraction of its value, zero-valued parameters are not analy- +TEXT: H ized (this has the benefit of reducing what is usually a +TEXT: H very large amount of data). +TEXT: H + +SUBJECT: Noise Analysis +TITLE: Noise Analysis +TEXT: H +TEXT: H _1._1._7. _N_o_i_s_e _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H +TEXT: H The noise analysis portion of SPICE does analysis +TEXT: H device-generated noise for the given circuit. When provided +TEXT: H with an input source and an output port, the analysis calcu- +TEXT: H lates the noise contributions of each device (and each noise +TEXT: H generator within the device) to the output port voltage. It +TEXT: H also calculates the input noise to the circuit, equivalent +TEXT: H to the output noise referred to the specified input source. +TEXT: H This is done for every frequency point in a specified range +TEXT: H - the calculated value of the noise corresponds to the spec- +TEXT: H tral density of the circuit variable viewed as a stationary +TEXT: H gaussian stochastic process. +TEXT: H +TEXT: H After calculating the spectral densities, noise +TEXT: H analysis integrates these values over the specified fre- +TEXT: H quency range to arrive at the total noise voltage/current +TEXT: H (over this frequency range). This calculated value +TEXT: H corresponds to the variance of the circuit variable viewed +TEXT: H as a stationary gaussian process. + +SUBJECT: ANALYSIS AT DIFFERENT TEMPERATURES +TITLE: ANALYSIS AT DIFFERENT TEMPERATURES +TEXT: H +TEXT: H _1._2. _A_N_A_L_Y_S_I_S _A_T _D_I_F_F_E_R_E_N_T _T_E_M_P_E_R_A_T_U_R_E_S +TEXT: H +TEXT: H +TEXT: H All input data for SPICE is assumed to have been meas- +TEXT: H o +TEXT: H ured at a nominal temperature of 27 C, which can be changed +TEXT: H by use of the TNOM parameter on the .OPTION control line. +TEXT: H This value can further be overridden for any device which +TEXT: H models temperature effects by specifying the TNOM parameter +TEXT: H on the model itself. The circuit simulation is performed at +TEXT: H o +TEXT: H a temperature of 27 C, unless overridden by a TEMP parameter +TEXT: H on the .OPTION control line. Individual instances may +TEXT: H further override the circuit temperature through the specif- +TEXT: H ication of a TEMP parameter on the instance. +TEXT: H +TEXT: H Temperature dependent support is provided for resis- +TEXT: H tors, diodes, JFETs, BJTs, and level 1, 2, and 3 MOSFETs. +TEXT: H BSIM (levels 4 and 5) MOSFETs have an alternate temperature +TEXT: H dependency scheme which adjusts all of the model parameters +TEXT: H before input to SPICE. For details of the BSIM temperature +TEXT: H adjustment, see [6] and [7]. +TEXT: H +TEXT: H +TEXT: H Temperature appears explicitly in the exponential terms +TEXT: H of the BJT and diode model equations. In addition, satura- +TEXT: H tion currents have a built-in temperature dependence. The +TEXT: H temperature dependence of the saturation current in the BJT +TEXT: H models is determined by: +TEXT: H +TEXT: H XTI +TEXT: H |T | | E q(T T )| +TEXT: H 1 g 1 0 +TEXT: H I (T ) = I (T ) |--| exp|-----------| +TEXT: H S 1 S 0 +TEXT: H |T | |k (T - T )| +TEXT: H 0 1 0 +TEXT: H +TEXT: H +TEXT: H +TEXT: H where k is Boltzmann's constant, q is the electronic +TEXT: H charge, E is the energy gap which is a model parameter, +TEXT: H G +TEXT: H and XTI is the saturation current temperature exponent +TEXT: H (also a model parameter, and usually equal to 3). +TEXT: H +TEXT: H +TEXT: H +TEXT: H The temperature dependence of forward and reverse beta +TEXT: H is according to the formula: +TEXT: H +TEXT: H XTB +TEXT: H |T | +TEXT: H 1 +TEXT: H B(T ) = B(T ) |--| +TEXT: H 1 0 +TEXT: H |T | +TEXT: H 0 +TEXT: H +TEXT: H +TEXT: H +TEXT: H where T and T are in degrees Kelvin, and XTB is a +TEXT: H 1 0 +TEXT: H user-supplied model parameter. Temperature effects on +TEXT: H beta are carried out by appropriate adjustment to the +TEXT: H values of B , I , B , and I (spice model parameters +TEXT: H F SE R SC +TEXT: H BF, ISE, BR, and ISC, respectively). +TEXT: H +TEXT: H +TEXT: H +TEXT: H Temperature dependence of the saturation current in the +TEXT: H junction diode model is determined by: +TEXT: H +TEXT: H XTI +TEXT: H --- +TEXT: H N +TEXT: H |T | | E q(T T ) | +TEXT: H 1 g 1 0 +TEXT: H I (T ) = I (T ) |--| exp|-------------| +TEXT: H S 1 S 0 +TEXT: H |T | |N k (T - T )| +TEXT: H 0 1 0 +TEXT: H +TEXT: H +TEXT: H +TEXT: H where N is the emission coefficient, which is a model +TEXT: H parameter, and the other symbols have the same meaning +TEXT: H as above. Note that for Schottky barrier diodes, the +TEXT: H value of the saturation current temperature exponent, +TEXT: H XTI, is usually 2. +TEXT: H +TEXT: H +TEXT: H +TEXT: H Temperature appears explicitly in the value of junction +TEXT: H potential, U (in spice PHI), for all the device models. The +TEXT: H temperature dependence is determined by: +TEXT: H +TEXT: H +TEXT: H | N N | +TEXT: H a d +TEXT: H kT |------ | +TEXT: H U(T) = -- log 2 +TEXT: H q e |N (T) | +TEXT: H i +TEXT: H +TEXT: H +TEXT: H where k is Boltzmann's constant, q is the electronic +TEXT: H charge, N is the acceptor impurity density, N is the +TEXT: H a d +TEXT: H donor impurity density, N is the intrinsic carrier con- +TEXT: H i +TEXT: H centration, and E is the energy gap. +TEXT: H g +TEXT: H +TEXT: H +TEXT: H +TEXT: H Temperature appears explicitly in the value of surface +TEXT: H mobility, M (or UO), for the MOSFET model. The temperature +TEXT: H 0 +TEXT: H dependence is determined by: +TEXT: H +TEXT: H +TEXT: H M (T ) +TEXT: H 0 0 +TEXT: H M (T) = ------- +TEXT: H 0 1.5 +TEXT: H | T| +TEXT: H |--| +TEXT: H |T | +TEXT: H 0 +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The effects of temperature on resistors is modeled by +TEXT: H the formula: +TEXT: H +TEXT: H +TEXT: H 2 +TEXT: H R(T) = R(T ) [1 + TC (T - T ) + TC (T - T ) ] +TEXT: H 0 1 0 2 0 +TEXT: H +TEXT: H +TEXT: H +TEXT: H where T is the circuit temperature, T is the nominal +TEXT: H 0 +TEXT: H temperature, and TC and TC are the first- and second- +TEXT: H 1 2 +TEXT: H order temperature coefficients. +TEXT: H + +SUBJECT: CONVERGENCE +TITLE: CONVERGENCE +TEXT: H +TEXT: H _1._3. _C_O_N_V_E_R_G_E_N_C_E +TEXT: H +TEXT: H +TEXT: H Both dc and transient solutions are obtained by an +TEXT: H iterative process which is terminated when both of the fol- +TEXT: H lowing conditions hold: +TEXT: H +TEXT: H +TEXT: H 1) The nonlinear branch currents converge to within a +TEXT: H tolerance of 0.1% or 1 picoamp (1.0e-12 Amp), whichever +TEXT: H is larger. +TEXT: H +TEXT: H 2) The node voltages converge to within a tolerance of +TEXT: H 0.1% or 1 microvolt (1.0e-6 Volt), whichever is larger. +TEXT: H +TEXT: H Although the algorithm used in SPICE has been found to +TEXT: H be very reliable, in some cases it fails to converge to a +TEXT: H solution. When this failure occurs, the program terminates +TEXT: H the job. +TEXT: H +TEXT: H Failure to converge in dc analysis is usually due to an +TEXT: H error in specifying circuit connections, element values, or +TEXT: H model parameter values. Regenerative switching circuits or +TEXT: H circuits with positive feedback probably will not converge +TEXT: H in the dc analysis unless the OFF option is used for some of +TEXT: H the devices in the feedback path, or the .NODESET control +TEXT: H line is used to force the circuit to converge to the desired +TEXT: H state. + +SUBJECT: CIRCUIT DESCRIPTION +TITLE: CIRCUIT DESCRIPTION +TEXT: H +TEXT: H _2. _C_I_R_C_U_I_T _D_E_S_C_R_I_P_T_I_O_N +SUBTOPIC: SPICE:GENERAL STRUCTURE AND CONVENTIONS +SUBTOPIC: SPICE:TITLE LINE COMMENT LINES AND .END LINE +SUBTOPIC: SPICE:DEVICE MODELS +SUBTOPIC: SPICE:SUBCIRCUITS +SUBTOPIC: SPICE:COMBINING FILES + +SUBJECT: GENERAL STRUCTURE AND CONVENTIONS +TITLE: GENERAL STRUCTURE AND CONVENTIONS +TEXT: H +TEXT: H _2._1. _G_E_N_E_R_A_L _S_T_R_U_C_T_U_R_E _A_N_D _C_O_N_V_E_N_T_I_O_N_S +TEXT: H +TEXT: H +TEXT: H The circuit to be analyzed is described to SPICE by a +TEXT: H set of element lines, which define the circuit topology and +TEXT: H element values, and a set of control lines, which define the +TEXT: H model parameters and the run controls. The first line in +TEXT: H the input file must be the title, and the last line must be +TEXT: H ".END". The order of the remaining lines is arbitrary +TEXT: H (except, of course, that continuation lines must immediately +TEXT: H follow the line being continued). +TEXT: H +TEXT: H Each element in the circuit is specified by an element +TEXT: H line that contains the element name, the circuit nodes to +TEXT: H which the element is connected, and the values of the param- +TEXT: H eters that determine the electrical characteristics of the +TEXT: H element. The first letter of the element name specifies the +TEXT: H element type. The format for the SPICE element types is +TEXT: H given in what follows. The strings XXXXXXX, YYYYYYY, and +TEXT: H ZZZZZZZ denote arbitrary alphanumeric strings. For example, +TEXT: H a resistor name must begin with the letter R and can contain +TEXT: H one or more characters. Hence, R, R1, RSE, ROUT, and +TEXT: H R3AC2ZY are valid resistor names. Details of each type of +TEXT: H device are supplied in a following section. +TEXT: H +TEXT: H Fields on a line are separated by one or more blanks, a +TEXT: H comma, an equal ('=') sign, or a left or right parenthesis; +TEXT: H extra spaces are ignored. A line may be continued by enter- +TEXT: H ing a '+' (plus) in column 1 of the following line; SPICE +TEXT: H continues reading beginning with column 2. +TEXT: H +TEXT: H A name field must begin with a letter (A through Z) and +TEXT: H cannot contain any delimiters. +TEXT: H +TEXT: H +TEXT: H A number field may be an integer field (12, -44), a +TEXT: H floating point field (3.14159), either an integer or float- +TEXT: H ing point number followed by an integer exponent (1e-14, +TEXT: H 2.65e3), or either an integer or a floating point number +TEXT: H followed by one of the following scale factors: +TEXT: H +TEXT: H 12 9 6 3 -6 +TEXT: H T = 10 G = 10 Meg = 10 K = 10 mil = 25.4 +TEXT: H -3 -6 -9 -12 -15 +TEXT: H m = 10 u (or M) = 10 n = 10 p = 10 f = 10 +TEXT: H +TEXT: H +TEXT: H +TEXT: H Letters immediately following a number that are not scale +TEXT: H factors are ignored, and letters immediately following a +TEXT: H scale factor are ignored. Hence, 10, 10V, 10Volts, and 10Hz +TEXT: H all represent the same number, and M, MA, MSec, and MMhos +TEXT: H all represent the same scale factor. Note that 1000, +TEXT: H 1000.0, 1000Hz, 1e3, 1.0e3, 1KHz, and 1K all represent the +TEXT: H same number. +TEXT: H +TEXT: H Nodes names may be arbitrary character strings. The +TEXT: H datum (ground) node must be named '0'. Note the difference +TEXT: H in SPICE3 where the nodes are treated as character strings +TEXT: H and not evaluated as numbers, thus '0' and '00' are distinct +TEXT: H nodes in SPICE3 but not in SPICE2. The circuit cannot con- +TEXT: H tain a loop of voltage sources and/or inductors and cannot +TEXT: H contain a cut-set of current sources and/or capacitors. +TEXT: H Each node in the circuit must have a dc path to ground. +TEXT: H Every node must have at least two connections except for +TEXT: H transmission line nodes (to permit unterminated transmission +TEXT: H lines) and MOSFET substrate nodes (which have two internal +TEXT: H connections anyway). +TEXT: H + +SUBJECT: TITLE LINE COMMENT LINES AND .END LINE +TITLE: TITLE LINE, COMMENT LINES AND .END LINE +TEXT: H +TEXT: H _2._2. _T_I_T_L_E _L_I_N_E, _C_O_M_M_E_N_T _L_I_N_E_S _A_N_D ._E_N_D _L_I_N_E +TEXT: H +SUBTOPIC: SPICE:Title Line +SUBTOPIC: SPICE:.END Line +SUBTOPIC: SPICE:Comments + +SUBJECT: Title Line +TITLE: Title Line +TEXT: H +TEXT: H _2._2._1. _T_i_t_l_e _L_i_n_e +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H POWER AMPLIFIER CIRCUIT +TEXT: H TEST OF CAM CELL +TEXT: H +TEXT: H +TEXT: H The title line must be the first in the input file. +TEXT: H Its contents are printed verbatim as the heading for each +TEXT: H section of output. +TEXT: H +TEXT: H + +SUBJECT: .END Line +TITLE: .END Line +TEXT: H +TEXT: H _2._2._2. ._E_N_D _L_i_n_e +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .END +TEXT: H +TEXT: H +TEXT: H The "End" line must always be the last in the input +TEXT: H file. Note that the period is an integral part of the +TEXT: H name. +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Comments +TITLE: Comments +TEXT: H +TEXT: H _2._2._3. _C_o_m_m_e_n_t_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m: +TEXT: H +TEXT: H * +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H * RF=1K Gain should be 100 +TEXT: H * Check open-loop gain and phase margin +TEXT: H +TEXT: H +TEXT: H The asterisk in the first column indicates that +TEXT: H this line is a comment line. Comment lines may be +TEXT: H placed anywhere in the circuit description. Note that +TEXT: H SPICE3 also considers any line with leading white space +TEXT: H to be a comment. +TEXT: H +TEXT: H + +SUBJECT: DEVICE MODELS +TITLE: DEVICE MODELS +TEXT: H +TEXT: H _2._3. _D_E_V_I_C_E _M_O_D_E_L_S +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .MODEL MNAME TYPE(PNAME1=PVAL1 PNAME2=PVAL2 ... ) +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .MODEL MOD1 NPN (BF=50 IS=1E-13 VBF=50) +TEXT: H +TEXT: H +TEXT: H +TEXT: H Most simple circuit elements typically require only a +TEXT: H few parameter values. However, some devices (semiconductor +TEXT: H devices in particular) that are included in SPICE require +TEXT: H many parameter values. Often, many devices in a circuit are +TEXT: H defined by the same set of device model parameters. For +TEXT: H these reasons, a set of device model parameters is defined +TEXT: H on a separate .MODEL line and assigned a unique model name. +TEXT: H The device element lines in SPICE then refer to the model +TEXT: H name. +TEXT: H +TEXT: H For these more complex device types, each device ele- +TEXT: H ment line contains the device name, the nodes to which the +TEXT: H device is connected, and the device model name. In addi- +TEXT: H tion, other optional parameters may be specified for some +TEXT: H devices: geometric factors and an initial condition (see +TEXT: H the following section on Transistors and Diodes for more de- +TEXT: H tails). +TEXT: H +TEXT: H MNAME in the above is the model name, and type is one +TEXT: H of the following fifteen types: +TEXT: H +TEXT: H R Semiconductor resistor model +TEXT: H C Semiconductor capacitor model +TEXT: H SW Voltage controlled switch +TEXT: H CSW Current controlled switch +TEXT: H URC Uniform distributed RC model +TEXT: H LTRA Lossy transmission line model +TEXT: H D Diode model +TEXT: H NPN NPN BJT model +TEXT: H PNP PNP BJT model +TEXT: H NJF N-channel JFET model +TEXT: H PJF P-channel JFET model +TEXT: H NMOS N-channel MOSFET model +TEXT: H PMOS P-channel MOSFET model +TEXT: H NMF N-channel MESFET model +TEXT: H PMF P-channel MESFET model +TEXT: H +TEXT: H +TEXT: H +TEXT: H Parameter values are defined by appending the parameter +TEXT: H name followed by an equal sign and the parameter value. +TEXT: H Model parameters that are not given a value are assigned the +TEXT: H default values given below for each model type. Models, +TEXT: H model parameters, and default values are listed in the next +TEXT: H section along with the description of device element lines. +TEXT: H + +SUBJECT: SUBCIRCUITS +TITLE: SUBCIRCUITS +TEXT: H +TEXT: H _2._4. _S_U_B_C_I_R_C_U_I_T_S +TEXT: H +TEXT: H +TEXT: H A subcircuit that consists of SPICE elements can be +TEXT: H defined and referenced in a fashion similar to device +TEXT: H models. The subcircuit is defined in the input file by a +TEXT: H grouping of element lines; the program then automatically +TEXT: H inserts the group of elements wherever the subcircuit is +TEXT: H referenced. There is no limit on the size or complexity of +TEXT: H subcircuits, and subcircuits may contain other subcircuits. +TEXT: H An example of subcircuit usage is given in Appendix A. +TEXT: H +TEXT: H +SUBTOPIC: SPICE:.SUBCKT Line +SUBTOPIC: SPICE:.ENDS Line +SUBTOPIC: SPICE:Subcircuit Calls + +SUBJECT: .SUBCKT Line +TITLE: .SUBCKT Line +TEXT: H +TEXT: H _2._4._1. ._S_U_B_C_K_T _L_i_n_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .SUBCKT subnam N1 +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .SUBCKT OPAMP 1 2 3 4 +TEXT: H +TEXT: H +TEXT: H +TEXT: H A circuit definition is begun with a .SUBCKT line. +TEXT: H SUBNAM is the subcircuit name, and N1, N2, ... are the +TEXT: H external nodes, which cannot be zero. The group of element +TEXT: H lines which immediately follow the .SUBCKT line define the +TEXT: H subcircuit. The last line in a subcircuit definition is the +TEXT: H .ENDS line (see below). Control lines may not appear within +TEXT: H a subcircuit definition; however, subcircuit definitions +TEXT: H may contain anything else, including other subcircuit defin- +TEXT: H itions, device models, and subcircuit calls (see below). +TEXT: H Note that any device models or subcircuit definitions +TEXT: H included as part of a subcircuit definition are strictly +TEXT: H local (i.e., such models and definitions are not known out- +TEXT: H side the subcircuit definition). Also, any element nodes +TEXT: H not included on the .SUBCKT line are strictly local, with +TEXT: H the exception of 0 (ground) which is always global. +TEXT: H +TEXT: H + +SUBJECT: .ENDS Line +TITLE: .ENDS Line +TEXT: H +TEXT: H _2._4._2. ._E_N_D_S _L_i_n_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .ENDS +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .ENDS OPAMP +TEXT: H +TEXT: H +TEXT: H The "Ends" line must be the last one for any sub- +TEXT: H circuit definition. The subcircuit name, if included, +TEXT: H indicates which subcircuit definition is being terminat- +TEXT: H ed; if omitted, all subcircuits being defined are ter- +TEXT: H minated. The name is needed only when nested subcircuit +TEXT: H definitions are being made. +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Subcircuit Calls +TITLE: Subcircuit Calls +TEXT: H +TEXT: H _2._4._3. _S_u_b_c_i_r_c_u_i_t _C_a_l_l_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H XYYYYYYY N1 SUBNAM +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H X1 2 4 17 3 1 MULTI +TEXT: H +TEXT: H +TEXT: H Subcircuits are used in SPICE by specifying +TEXT: H pseudo-elements beginning with the letter X, followed by +TEXT: H the circuit nodes to be used in expanding the subcir- +TEXT: H cuit. +TEXT: H +TEXT: H + +SUBJECT: COMBINING FILES +TITLE: COMBINING FILES: .INCLUDE LINES +TEXT: H +TEXT: H _2._5. _C_O_M_B_I_N_I_N_G _F_I_L_E_S: ._I_N_C_L_U_D_E _L_I_N_E_S +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .INCLUDE _f_i_l_e_n_a_m_e +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .INCLUDE /users/spice/common/wattmeter.cir +TEXT: H +TEXT: H +TEXT: H Frequently, portions of circuit descriptions will be +TEXT: H reused in several input files, particularly with common +TEXT: H models and subcircuits. In any spice input file, the +TEXT: H ".include" line may be used to copy some other file as if +TEXT: H that second file appeared in place of the ".include" line in +TEXT: H the original file. There is no restriction on the file name +TEXT: H imposed by spice beyond those imposed by the local operating +TEXT: H system. + +SUBJECT: CIRCUIT ELEMENTS AND MODELS +TITLE: CIRCUIT ELEMENTS AND MODELS +TEXT: H +TEXT: H _3. _C_I_R_C_U_I_T _E_L_E_M_E_N_T_S _A_N_D _M_O_D_E_L_S +TEXT: H +TEXT: H +TEXT: H Data fields that are enclosed in less-than and +TEXT: H greater-than signs ('< >') are optional. All indicated +TEXT: H punctuation (parentheses, equal signs, etc.) is optional but +TEXT: H indicate the presence of any delimiter. Further, future +TEXT: H implementations may require the punctuation as stated. A +TEXT: H consistent style adhering to the punctuation shown here +TEXT: H makes the input easier to understand. With respect to +TEXT: H branch voltages and currents, SPICE uniformly uses the asso- +TEXT: H ciated reference convention (current flows in the direction +TEXT: H of voltage drop). +SUBTOPIC: SPICE:ELEMENTARY DEVICES +SUBTOPIC: SPICE:VOLTAGE AND CURRENT SOURCES +SUBTOPIC: SPICE:TRANSMISSION LINES +SUBTOPIC: SPICE:TRANSISTORS AND DIODES + +SUBJECT: ELEMENTARY DEVICES +TITLE: ELEMENTARY DEVICES +TEXT: H +TEXT: H _3._1. _E_L_E_M_E_N_T_A_R_Y _D_E_V_I_C_E_S +TEXT: H +SUBTOPIC: SPICE:Resistors +SUBTOPIC: SPICE:Semiconductor Resistors +SUBTOPIC: SPICE:Semiconductor Resistor Model +SUBTOPIC: SPICE:Capacitors +SUBTOPIC: SPICE:Semiconductor Capacitors +SUBTOPIC: SPICE:Semiconductor Capacitor Model +SUBTOPIC: SPICE:Inductors +SUBTOPIC: SPICE:Coupled Inductors +SUBTOPIC: SPICE:Switches +SUBTOPIC: SPICE:Switch Model + +SUBJECT: Resistors +TITLE: Resistors +TEXT: H +TEXT: H _3._1._1. _R_e_s_i_s_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H RXXXXXXX N1 N2 VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H R1 1 2 100 +TEXT: H RC1 12 17 1K +TEXT: H +TEXT: H +TEXT: H N1 and N2 are the two element nodes. VALUE is the +TEXT: H resistance (in ohms) and may be positive or negative but not +TEXT: H zero. +TEXT: H +TEXT: H + +SUBJECT: Semiconductor Resistors +TITLE: Semiconductor Resistors +TEXT: H +TEXT: H _3._1._2. _S_e_m_i_c_o_n_d_u_c_t_o_r _R_e_s_i_s_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H RXXXXXXX N1 N2 +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H RLOAD 2 10 10K +TEXT: H RMOD 3 7 RMODEL L=10u W=1u +TEXT: H +TEXT: H +TEXT: H +TEXT: H This is the more general form of the resistor presented +TEXT: H in section 6.1, and allows the modeling of temperature +TEXT: H effects and for the calculation of the actual resistance +TEXT: H value from strictly geometric information and the specifica- +TEXT: H tions of the process. If VALUE is specified, it overrides +TEXT: H the geometric information and defines the resistance. If +TEXT: H MNAME is specified, then the resistance may be calculated +TEXT: H from the process information in the model MNAME and the +TEXT: H given LENGTH and WIDTH. If VALUE is not specified, then +TEXT: H MNAME and LENGTH must be specified. If WIDTH is not speci- +TEXT: H fied, then it is taken from the default width given in the +TEXT: H model. The (optional) TEMP value is the temperature at +TEXT: H which this device is to operate, and overrides the tempera- +TEXT: H ture specification on the .OPTION control line. +TEXT: H +TEXT: H + +SUBJECT: Semiconductor Resistor Model +TITLE: Semiconductor Resistor Model (R) +TEXT: H +TEXT: H _3._1._3. _S_e_m_i_c_o_n_d_u_c_t_o_r _R_e_s_i_s_t_o_r _M_o_d_e_l (_R) +TEXT: H +TEXT: H +TEXT: H The resistor model consists of process-related device +TEXT: H data that allow the resistance to be calculated from +TEXT: H geometric information and to be corrected for temperature. +TEXT: H The parameters available are: +TEXT: H +TEXT: H name parameter units default example +TEXT: H +TEXT: H o +TEXT: H TC1 first order temperature coeff. Z/ C 0.0 - +TEXT: H o 2 +TEXT: H TC2 second order temperature coeff. Z/ C 0.0 - +TEXT: H RSH sheet resistance Z/[] - 50 +TEXT: H DEFW default width meters 1e-6 2e-6 +TEXT: H NARROW narrowing due to side etching meters 0.0 1e-7 +TEXT: H o +TEXT: H TNOM parameter measurement temperature C 27 50 +TEXT: H +TEXT: H +TEXT: H +TEXT: H The sheet resistance is used with the narrowing parame- +TEXT: H ter and L and W from the resistor device to determine the +TEXT: H nominal resistance by the formula +TEXT: H +TEXT: H L - NARROW +TEXT: H R = RSH ---------- +TEXT: H W - NARROW +TEXT: H +TEXT: H DEFW is used to supply a default value for W if one is not +TEXT: H specified for the device. If either RSH or L is not speci- +TEXT: H fied, then the standard default resistance value of 1k Z is +TEXT: H used. TNOM is used to override the circuit-wide value given +TEXT: H on the .OPTIONS control line where the parameters of this +TEXT: H model have been measured at a different temperature. After +TEXT: H the nominal resistance is calculated, it is adjusted for +TEXT: H temperature by the formula: +TEXT: H +TEXT: H 2 +TEXT: H R(T) = R(T ) [1 + TC1 (T - T ) + TC2 (T-T ) ] +TEXT: H 0 0 0 +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Capacitors +TITLE: Capacitors +TEXT: H +TEXT: H _3._1._4. _C_a_p_a_c_i_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H CXXXXXXX N+ N- VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H CBYP 13 0 1UF +TEXT: H COSC 17 23 10U IC=3V +TEXT: H +TEXT: H +TEXT: H N+ and N- are the positive and negative element +TEXT: H nodes, respectively. VALUE is the capacitance in +TEXT: H Farads. +TEXT: H +TEXT: H +TEXT: H The (optional) initial condition is the initial (time- +TEXT: H zero) value of capacitor voltage (in Volts). Note that the +TEXT: H initial conditions (if any) apply 'only' if the UIC option +TEXT: H is specified on the .TRAN control line. +TEXT: H +TEXT: H + +SUBJECT: Semiconductor Capacitors +TITLE: Semiconductor Capacitors +TEXT: H +TEXT: H _3._1._5. _S_e_m_i_c_o_n_d_u_c_t_o_r _C_a_p_a_c_i_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H CXXXXXXX N1 N2 +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H CLOAD 2 10 10P +TEXT: H CMOD 3 7 CMODEL L=10u W=1u +TEXT: H +TEXT: H +TEXT: H +TEXT: H This is the more general form of the Capacitor +TEXT: H presented in section 6.2, and allows for the calculation of +TEXT: H the actual capacitance value from strictly geometric infor- +TEXT: H mation and the specifications of the process. If VALUE is +TEXT: H specified, it defines the capacitance. If MNAME is speci- +TEXT: H fied, then the capacitance is calculated from the process +TEXT: H information in the model MNAME and the given LENGTH and +TEXT: H WIDTH. If VALUE is not specified, then MNAME and LENGTH +TEXT: H must be specified. If WIDTH is not specified, then it is +TEXT: H taken from the default width given in the model. Either +TEXT: H VALUE or MNAME, LENGTH, and WIDTH may be specified, but not +TEXT: H both sets. +TEXT: H +TEXT: H + +SUBJECT: Semiconductor Capacitor Model +TITLE: Semiconductor Capacitor Model (C) +TEXT: H +TEXT: H _3._1._6. _S_e_m_i_c_o_n_d_u_c_t_o_r _C_a_p_a_c_i_t_o_r _M_o_d_e_l (_C) +TEXT: H +TEXT: H +TEXT: H The capacitor model contains process information that +TEXT: H may be used to compute the capacitance from strictly +TEXT: H geometric information. +TEXT: H +TEXT: H +TEXT: H +TEXT: H name parameter units default example +TEXT: H +TEXT: H 2 +TEXT: H CJ junction bottom capacitance F/meters - 5e-5 +TEXT: H CJSW junction sidewall capacitance F/meters - 2e-11 +TEXT: H DEFW default device width meters 1e-6 2e-6 +TEXT: H NARROW narrowing due to side etching meters 0.0 1e-7 +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The capacitor has a capacitance computed as +TEXT: H +TEXT: H CAP = CJ (LENGTH - NARROW) (WIDTH - NARROW) + 2 CJSW (LENGTH + WIDTH - 2 NARROW) +TEXT: H +TEXT: H + +SUBJECT: Inductors +TITLE: Inductors +TEXT: H +TEXT: H _3._1._7. _I_n_d_u_c_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H LYYYYYYY N+ N- VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H LLINK 42 69 1UH +TEXT: H LSHUNT 23 51 10U IC=15.7MA +TEXT: H +TEXT: H +TEXT: H N+ and N- are the positive and negative element +TEXT: H nodes, respectively. VALUE is the inductance in Hen- +TEXT: H ries. +TEXT: H +TEXT: H +TEXT: H The (optional) initial condition is the initial (time- +TEXT: H zero) value of inductor current (in Amps) that flows from +TEXT: H N+, through the inductor, to N-. Note that the initial con- +TEXT: H ditions (if any) apply only if the UIC option is specified +TEXT: H on the .TRAN analysis line. +TEXT: H +TEXT: H + +SUBJECT: Coupled Inductors +TITLE: Coupled (Mutual) Inductors +TEXT: H +TEXT: H _3._1._8. _C_o_u_p_l_e_d (_M_u_t_u_a_l) _I_n_d_u_c_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H KXXXXXXX LYYYYYYY LZZZZZZZ VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H K43 LAA LBB 0.999 +TEXT: H KXFRMR L1 L2 0.87 +TEXT: H +TEXT: H +TEXT: H LYYYYYYY and LZZZZZZZ are the names of the two cou- +TEXT: H pled inductors, and VALUE is the coefficient of cou- +TEXT: H pling, K, which must be greater than 0 and less than or +TEXT: H equal to 1. Using the 'dot' convention, place a 'dot' +TEXT: H on the first node of each inductor. +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Switches +TITLE: Switches +TEXT: H +TEXT: H _3._1._9. _S_w_i_t_c_h_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H SXXXXXXX N+ N- NC+ NC- MODEL +TEXT: H WYYYYYYY N+ N- VNAM MODEL +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H s1 1 2 3 4 switch1 ON +TEXT: H s2 5 6 3 0 sm2 off +TEXT: H Switch1 1 2 10 0 smodel1 +TEXT: H w1 1 2 vclock switchmod1 +TEXT: H W2 3 0 vramp sm1 ON +TEXT: H wreset 5 6 vclck lossyswitch OFF +TEXT: H +TEXT: H +TEXT: H Nodes 1 and 2 are the nodes between which the +TEXT: H switch terminals are connected. The model name is man- +TEXT: H datory while the initial conditions are optional. For +TEXT: H the voltage controlled switch, nodes 3 and 4 are the po- +TEXT: H sitive and negative controlling nodes respectively. For +TEXT: H the current controlled switch, the controlling current +TEXT: H is that through the specified voltage source. The +TEXT: H direction of positive controlling current flow is from +TEXT: H the positive node, through the source, to the negative +TEXT: H node. +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Switch Model +TITLE: Switch Model (SW/CSW) +TEXT: H +TEXT: H _3._1._1_0. _S_w_i_t_c_h _M_o_d_e_l (_S_W/_C_S_W) +TEXT: H +TEXT: H +TEXT: H The switch model allows an almost ideal switch to be +TEXT: H described in SPICE. The switch is not quite ideal, in that +TEXT: H the resistance can not change from 0 to infinity, but must +TEXT: H always have a finite positive value. By proper selection of +TEXT: H the on and off resistances, they can be effectively zero and +TEXT: H infinity in comparison to other circuit elements. The +TEXT: H parameters available are: +TEXT: H +TEXT: H name parameter units default switch +TEXT: H +TEXT: H VT threshold voltage Volts 0.0 S +TEXT: H IT threshold current Amps 0.0 W +TEXT: H VH hysteresis voltage Volts 0.0 S +TEXT: H IH hysteresis current Amps 0.0 W +TEXT: H RON on resistance Z 1.0 both +TEXT: H ROFF off resistance Z 1/GMIN* both +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H *(See the .OPTIONS control line for a description of +TEXT: H GMIN, its default value results in an off-resistance of +TEXT: H 1.0e+12 ohms.) +TEXT: H +TEXT: H +TEXT: H The use of an ideal element that is highly nonlinear +TEXT: H such as a switch can cause large discontinuities to occur in +TEXT: H the circuit node voltages. A rapid change such as that +TEXT: H associated with a switch changing state can cause numerical +TEXT: H roundoff or tolerance problems leading to erroneous results +TEXT: H or timestep difficulties. The user of switches can improve +TEXT: H the situation by taking the following steps: +TEXT: H +TEXT: H First, it is wise to set ideal switch impedances just +TEXT: H high or low enough to be negligible with respect to other +TEXT: H circuit elements. Using switch impedances that are close to +TEXT: H "ideal" in all cases aggravates the problem of discontinui- +TEXT: H ties mentioned above. Of course, when modeling real devices +TEXT: H such as MOSFETS, the on resistance should be adjusted to a +TEXT: H realistic level depending on the size of the device being +TEXT: H modeled. +TEXT: H +TEXT: H If a wide range of ON to OFF resistance must be used in +TEXT: H the switches (ROFF/RON >1e+12), then the tolerance on errors +TEXT: H allowed during transient analysis should be decreased by +TEXT: H using the .OPTIONS control line and specifying TRTOL to be +TEXT: H less than the default value of 7.0. When switches are +TEXT: H placed around capacitors, then the option CHGTOL should also +TEXT: H be reduced. Suggested values for these two options are 1.0 +TEXT: H and 1e-16 respectively. These changes inform SPICE3 to be +TEXT: H more careful around the switch points so that no errors are +TEXT: H made due to the rapid change in the circuit. +TEXT: H + +SUBJECT: VOLTAGE AND CURRENT SOURCES +TITLE: VOLTAGE AND CURRENT SOURCES +TEXT: H +TEXT: H _3._2. _V_O_L_T_A_G_E _A_N_D _C_U_R_R_E_N_T _S_O_U_R_C_E_S +TEXT: H +SUBTOPIC: SPICE:Independent Sources +SUBTOPIC: SPICE:Linear Dependent Sources +SUBTOPIC: SPICE:Nonlinear Dependent Sources + +SUBJECT: Independent Sources +TITLE: Independent Sources +TEXT: H +TEXT: H _3._2._1. _I_n_d_e_p_e_n_d_e_n_t _S_o_u_r_c_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H VXXXXXXX N+ N- < DC/TRAN VALUE> >> +TEXT: H + >> >> +TEXT: H IYYYYYYY N+ N- < DC/TRAN VALUE> >> +TEXT: H + >> >> +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H VCC 10 0 DC 6 +TEXT: H VIN 13 2 0.001 AC 1 SIN(0 1 1MEG) +TEXT: H ISRC 23 21 AC 0.333 45.0 SFFM(0 1 10K 5 1K) +TEXT: H VMEAS 12 9 +TEXT: H VCARRIER 1 0 DISTOF1 0.1 -90.0 +TEXT: H VMODULATOR 2 0 DISTOF2 0.01 +TEXT: H IIN1 1 5 AC 1 DISTOF1 DISTOF2 0.001 +TEXT: H +TEXT: H +TEXT: H N+ and N- are the positive and negative nodes, respec- +TEXT: H tively. Note that voltage sources need not be grounded. +TEXT: H Positive current is assumed to flow from the positive node, +TEXT: H through the source, to the negative node. A current source +TEXT: H of positive value forces current to flow out of the N+ node, +TEXT: H through the source, and into the N- node. Voltage sources, +TEXT: H in addition to being used for circuit excitation, are the +TEXT: H 'ammeters' for SPICE, that is, zero valued voltage sources +TEXT: H may be inserted into the circuit for the purpose of measur- +TEXT: H ing current. They of course have no effect on circuit +TEXT: H operation since they represent short-circuits. +TEXT: H +TEXT: H +TEXT: H DC/TRAN is the dc and transient analysis value of the +TEXT: H source. If the source value is zero both for dc and tran- +TEXT: H sient analyses, this value may be omitted. If the source +TEXT: H value is time-invariant (e.g., a power supply), then the +TEXT: H value may optionally be preceded by the letters DC. +TEXT: H +TEXT: H +TEXT: H ACMAG is the ac magnitude and ACPHASE is the ac phase. +TEXT: H The source is set to this value in the ac analysis. If +TEXT: H ACMAG is omitted following the keyword AC, a value of unity +TEXT: H is assumed. If ACPHASE is omitted, a value of zero is +TEXT: H assumed. If the source is not an ac small-signal input, the +TEXT: H keyword AC and the ac values are omitted. +TEXT: H +TEXT: H +TEXT: H DISTOF1 and DISTOF2 are the keywords that specify that +TEXT: H the independent source has distortion inputs at the frequen- +TEXT: H cies F1 and F2 respectively (see the description of the +TEXT: H .DISTO control line). The keywords may be followed by an +TEXT: H optional magnitude and phase. The default values of the +TEXT: H magnitude and phase are 1.0 and 0.0 respectively. +TEXT: H +TEXT: H +TEXT: H Any independent source can be assigned a time-dependent +TEXT: H value for transient analysis. If a source is assigned a +TEXT: H time-dependent value, the time-zero value is used for dc +TEXT: H analysis. There are five independent source functions: +TEXT: H pulse, exponential, sinusoidal, piece-wise linear, and +TEXT: H single-frequency FM. If parameters other than source values +TEXT: H are omitted or set to zero, the default values shown are +TEXT: H assumed. (TSTEP is the printing increment and TSTOP is the +TEXT: H final time (see the .TRAN control line for explanation)). +TEXT: H +TEXT: H +SUBTOPIC: SPICE:Pulse +SUBTOPIC: SPICE:Sinusoidal +SUBTOPIC: SPICE:Exponential +SUBTOPIC: SPICE:PieceWise Linear +SUBTOPIC: SPICE:SingleFrequency FM + +SUBJECT: Pulse +TITLE: Pulse +TEXT: H +TEXT: H _3._2._1._1. _P_u_l_s_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H PULSE(V1 V2 TD TR TF PW PER) +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H VIN 3 0 PULSE(-1 1 2NS 2NS 2NS 50NS 100NS) +TEXT: H +TEXT: H +TEXT: H +TEXT: H parameter default value units +TEXT: H ----------------------------------------------------- +TEXT: H V1 (initial value) Volts or Amps +TEXT: H V2 (pulsed value) Volts or Amps +TEXT: H TD (delay time) 0.0 seconds +TEXT: H TR (rise time) TSTEP seconds +TEXT: H TF (fall time) TSTEP seconds +TEXT: H PW (pulse width) TSTOP seconds +TEXT: H PER(period) TSTOP seconds +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H A single pulse so specified is described by the follow- +TEXT: H ing table: +TEXT: H +TEXT: H +TEXT: H +TEXT: H time value +TEXT: H ------------------- +TEXT: H 0 V1 +TEXT: H TD V1 +TEXT: H TD+TR V2 +TEXT: H TD+TR+PW V2 +TEXT: H TD+TR+PW+TF V1 +TEXT: H TSTOP V1 +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H Intermediate points are determined by linear interpola- +TEXT: H tion. +TEXT: H +TEXT: H + +SUBJECT: Sinusoidal +TITLE: Sinusoidal +TEXT: H +TEXT: H _3._2._1._2. _S_i_n_u_s_o_i_d_a_l +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H SIN(VO VA FREQ TD THETA) +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H VIN 3 0 SIN(0 1 100MEG 1NS 1E10) +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H parameters default value units +TEXT: H ------------------------------------------------------- +TEXT: H VO (offset) Volts or Amps +TEXT: H VA (amplitude) Volts or Amps +TEXT: H FREQ (frequency) 1/TSTOP Hz +TEXT: H TD (delay) 0.0 seconds +TEXT: H THETA (damping factor) 0.0 1/seconds +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The shape of the waveform is described by the following +TEXT: H table: +TEXT: H +TEXT: H +TEXT: H time value +TEXT: H ------------------------------------------------------------ +TEXT: H 0 to TD VO +TEXT: H -(t - TD)THETA +TEXT: H TD to TSTOP VO + VA e sin(2 J FREQ (t + TD)) +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Exponential +TITLE: Exponential +TEXT: H +TEXT: H _3._2._1._3. _E_x_p_o_n_e_n_t_i_a_l +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m: +TEXT: H +TEXT: H EXP(V1 V2 TD1 TAU1 TD2 TAU2) +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H VIN 3 0 EXP(-4 -1 2NS 30NS 60NS 40NS) +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H parameter default value units +TEXT: H --------------------------------------------------------- +TEXT: H V1 (initial value) Volts or Amps +TEXT: H V2 (pulsed value) Volts or Amps +TEXT: H TD1 (rise delay time) 0.0 seconds +TEXT: H TAU1 (rise time constant) TSTEP seconds +TEXT: H TD2 (fall delay time) TD1+TSTEP seconds +TEXT: H TAU2 (fall time constant) TSTEP seconds +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The shape of the waveform is described by the following +TEXT: H table: +TEXT: H +TEXT: H +TEXT: H +TEXT: H time value +TEXT: H ---------------------------------------------------------------------------- +TEXT: H 0 to TD1 V1 +TEXT: H | ------------| +TEXT: H TAU1 +TEXT: H | -(t - TD1) | -(t - TD2) +TEXT: H TD1 to TD2 V1 + (V2 - V1) 1 - e +TEXT: H | ----------| | ----------| +TEXT: H | TAU1 | | TAU2 | +TEXT: H TD2 to TSTOP V1 + (V2 - V1) - e + (V1 - V2) 1 - e +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: PieceWise Linear +TITLE: Piece-Wise Linear +TEXT: H +TEXT: H _3._2._1._4. _P_i_e_c_e-_W_i_s_e _L_i_n_e_a_r +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m: +TEXT: H +TEXT: H PWL(T1 V1 ) +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H VCLOCK 7 5 PWL(0 -7 10NS -7 11NS -3 17NS -3 18NS -7 50NS -7) +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H Each pair of values (Ti, Vi) specifies that the value +TEXT: H of the source is Vi (in Volts or Amps) at time=Ti. The +TEXT: H value of the source at intermediate values of time is deter- +TEXT: H mined by using linear interpolation on the input values. +TEXT: H +TEXT: H + +SUBJECT: SingleFrequency FM +TITLE: Single-Frequency FM +TEXT: H +TEXT: H _3._2._1._5. _S_i_n_g_l_e-_F_r_e_q_u_e_n_c_y _F_M +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m: +TEXT: H +TEXT: H SFFM(VO VA FC MDI FS) +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H V1 12 0 SFFM(0 1M 20K 5 1K) +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H parameter default value units +TEXT: H ------------------------------------------------------- +TEXT: H VO (offset) Volts or Amps +TEXT: H VA (amplitude) Volts or Amps +TEXT: H FC (carrier frequency) 1/TSTOP Hz +TEXT: H MDI (modulation index) +TEXT: H FS (signal frequency) 1/TSTOP Hz +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The shape of the waveform is described by the following +TEXT: H equation: +TEXT: H +TEXT: H +TEXT: H | | +TEXT: H V(t)=V + V sin 2 J FC t + MDI sin(2 J FS t) +TEXT: H O A | | +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Linear Dependent Sources +TITLE: Linear Dependent Sources +TEXT: H +TEXT: H _3._2._2. _L_i_n_e_a_r _D_e_p_e_n_d_e_n_t _S_o_u_r_c_e_s +TEXT: H +TEXT: H +TEXT: H SPICE allows circuits to contain linear dependent +TEXT: H sources characterized by any of the four equations +TEXT: H +TEXT: H i = g v v = e v i = f i v +TEXT: H = h i +TEXT: H +TEXT: H where g, e, f, and h are constants representing transconduc- +TEXT: H tance, voltage gain, current gain, and transresistance, +TEXT: H respectively. +TEXT: H +TEXT: H +TEXT: H +SUBTOPIC: SPICE:Linear VoltageControlled Current Sources +SUBTOPIC: SPICE:Linear VoltageControlled Voltage Sources +SUBTOPIC: SPICE:Linear CurrentControlled Current Sources +SUBTOPIC: SPICE:Linear CurrentControlled Voltage Sources + +SUBJECT: Linear VoltageControlled Current Sources +TITLE: Linear Voltage-Controlled Current Sources +TEXT: H +TEXT: H _3._2._2._1. _L_i_n_e_a_r _V_o_l_t_a_g_e-_C_o_n_t_r_o_l_l_e_d _C_u_r_r_e_n_t _S_o_u_r_c_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H GXXXXXXX N+ N- NC+ NC- VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H G1 2 0 5 0 0.1MMHO +TEXT: H +TEXT: H +TEXT: H N+ and N- are the positive and negative nodes, +TEXT: H respectively. Current flow is from the positive node, +TEXT: H through the source, to the negative node. NC+ and NC- +TEXT: H are the positive and negative controlling nodes, respec- +TEXT: H tively. VALUE is the transconductance (in mhos). +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Linear VoltageControlled Voltage Sources +TITLE: Linear Voltage-Controlled Voltage Sources +TEXT: H +TEXT: H _3._2._2._2. _L_i_n_e_a_r _V_o_l_t_a_g_e-_C_o_n_t_r_o_l_l_e_d _V_o_l_t_a_g_e _S_o_u_r_c_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H EXXXXXXX N+ N- NC+ NC- VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H E1 2 3 14 1 2.0 +TEXT: H +TEXT: H +TEXT: H N+ is the positive node, and N- is the negative +TEXT: H node. NC+ and NC- are the positive and negative con- +TEXT: H trolling nodes, respectively. VALUE is the voltage +TEXT: H gain. +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Linear CurrentControlled Current Sources +TITLE: Linear Current-Controlled Current Sources +TEXT: H +TEXT: H _3._2._2._3. _L_i_n_e_a_r _C_u_r_r_e_n_t-_C_o_n_t_r_o_l_l_e_d _C_u_r_r_e_n_t _S_o_u_r_c_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H FXXXXXXX N+ N- VNAM VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H F1 13 5 VSENS 5 +TEXT: H +TEXT: H +TEXT: H N+ and N- are the positive and negative nodes, +TEXT: H respectively. Current flow is from the positive node, +TEXT: H through the source, to the negative node. VNAM is the +TEXT: H name of a voltage source through which the controlling +TEXT: H current flows. The direction of positive controlling +TEXT: H current flow is from the positive node, through the +TEXT: H source, to the negative node of VNAM. VALUE is the +TEXT: H current gain. +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Linear CurrentControlled Voltage Sources +TITLE: Linear Current-Controlled Voltage Sources +TEXT: H +TEXT: H _3._2._2._4. _L_i_n_e_a_r _C_u_r_r_e_n_t-_C_o_n_t_r_o_l_l_e_d _V_o_l_t_a_g_e _S_o_u_r_c_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H HXXXXXXX N+ N- VNAM VALUE +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H HX 5 17 VZ 0.5K +TEXT: H +TEXT: H +TEXT: H N+ and N- are the positive and negative nodes, +TEXT: H respectively. VNAM is the name of a voltage source +TEXT: H through which the controlling current flows. The direc- +TEXT: H tion of positive controlling current flow is from the +TEXT: H positive node, through the source, to the negative node +TEXT: H of VNAM. VALUE is the transresistance (in ohms). +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Nonlinear Dependent Sources +TITLE: Non-linear Dependent Sources +TEXT: H +TEXT: H _3._2._3. _N_o_n-_l_i_n_e_a_r _D_e_p_e_n_d_e_n_t _S_o_u_r_c_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H BXXXXXXX N+ N- +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H B1 0 1 I=cos(v(1))+sin(v(2)) +TEXT: H B1 0 1 V=ln(cos(log(v(1,2)^2)))-v(3)^4+v(2)^v(1) +TEXT: H B1 3 4 I=17 +TEXT: H B1 3 4 V=exp(pi^i(vdd)) +TEXT: H +TEXT: H +TEXT: H +TEXT: H _N+ is the positive node, and _N- is the negative node. +TEXT: H The values of the V and I parameters determine the voltages +TEXT: H and currents across and through the device, respectively. +TEXT: H If I is given then the device is a current source, and if V +TEXT: H is given the device is a voltage source. One and only one +TEXT: H of these parameters must be given. +TEXT: H +TEXT: H The small-signal AC behavior of the nonlinear source is +TEXT: H a linear dependent source (or sources) with a proportional- +TEXT: H ity constant equal to the derivative (or derivatives) of the +TEXT: H source at the DC operating point. +TEXT: H +TEXT: H +TEXT: H The expressions given for V and I may be any function +TEXT: H of voltages and currents through voltage sources in the sys- +TEXT: H tem. The following functions of real variables are defined: +TEXT: H +TEXT: H abs asinh cosh sin +TEXT: H acos atan exp sinh +TEXT: H acosh atanh ln sqrt +TEXT: H asin cos log tan +TEXT: H +TEXT: H +TEXT: H +TEXT: H The function "u" is the unit step function, with a +TEXT: H value of one for arguments greater than one and a value of +TEXT: H zero for arguments less than zero. The function "uramp" is +TEXT: H the integral of the unit step: for an input _x, the value is +TEXT: H zero if _x is less than zero, or if _x is greater than zero +TEXT: H the value is _x. These two functions are useful in sythesiz- +TEXT: H ing piece-wise non-linear functions, though convergence may +TEXT: H be adversely affected. +TEXT: H +TEXT: H +TEXT: H The following standard operators are defined: +TEXT: H +TEXT: H + - * / ^ unary - +TEXT: H +TEXT: H +TEXT: H If the argument of log, ln, or sqrt becomes less than +TEXT: H zero, the absolute value of the argument is used. If a +TEXT: H divisor becomes zero or the argument of log or ln becomes +TEXT: H zero, an error will result. Other problems may occur when +TEXT: H the argument for a function in a partial derivative enters a +TEXT: H region where that function is undefined. +TEXT: H +TEXT: H +TEXT: H To get time into the expression you can integrate the +TEXT: H current from a constant current source with a capacitor and +TEXT: H use the resulting voltage (don't forget to set the initial +TEXT: H voltage across the capacitor). Non-linear resistors, capa- +TEXT: H citors, and inductors may be synthesized with the nonlinear +TEXT: H dependent source. Non-linear resistors are obvious. Non- +TEXT: H linear capacitors and inductors are implemented with their +TEXT: H linear counterparts by a change of variables implemented +TEXT: H with the nonlinear dependent source. The following subcir- +TEXT: H cuit will implement a nonlinear capacitor: +TEXT: H +TEXT: H .Subckt nlcap pos neg +TEXT: H * Bx: calculate f(input voltage) +TEXT: H Bx 1 0 v = f(v(pos,neg)) +TEXT: H * Cx: linear capacitance +TEXT: H Cx 2 0 1 +TEXT: H * Vx: Ammeter to measure current into the capacitor +TEXT: H Vx 2 1 DC 0Volts +TEXT: H * Drive the current through Cx back into the circuit +TEXT: H Fx pos neg Vx 1 +TEXT: H .ends +TEXT: H +TEXT: H +TEXT: H Non-linear inductors are similar. +TEXT: H +TEXT: H + +SUBJECT: TRANSMISSION LINES +TITLE: TRANSMISSION LINES +TEXT: H +TEXT: H _3._3. _T_R_A_N_S_M_I_S_S_I_O_N _L_I_N_E_S +TEXT: H +SUBTOPIC: SPICE:Lossless Transmission Lines +SUBTOPIC: SPICE:Lossy Transmission Lines +SUBTOPIC: SPICE:Lossy Transmission Line Model +SUBTOPIC: SPICE:Uniform Distributed RC Lines +SUBTOPIC: SPICE:Uniform Distributed RC Model + +SUBJECT: Lossless Transmission Lines +TITLE: Lossless Transmission Lines +TEXT: H +TEXT: H _3._3._1. _L_o_s_s_l_e_s_s _T_r_a_n_s_m_i_s_s_i_o_n _L_i_n_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H TXXXXXXX N1 N2 N3 N4 Z0=VALUE > +TEXT: H + +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H T1 1 0 2 0 Z0=50 TD=10NS +TEXT: H +TEXT: H +TEXT: H N1 and N2 are the nodes at port 1; N3 and N4 are the +TEXT: H nodes at port 2. Z0 is the characteristic impedance. The +TEXT: H length of the line may be expressed in either of two forms. +TEXT: H The transmission delay, TD, may be specified directly (as +TEXT: H TD=10ns, for example). Alternatively, a frequency F may be +TEXT: H given, together with NL, the normalized electrical length of +TEXT: H the transmission line with respect to the wavelength in the +TEXT: H line at the frequency F. If a frequency is specified but NL +TEXT: H is omitted, 0.25 is assumed (that is, the frequency is +TEXT: H assumed to be the quarter-wave frequency). Note that +TEXT: H although both forms for expressing the line length are indi- +TEXT: H cated as optional, one of the two must be specified. +TEXT: H +TEXT: H Note that this element models only one propagating +TEXT: H mode. If all four nodes are distinct in the actual circuit, +TEXT: H then two modes may be excited. To simulate such a situa- +TEXT: H tion, two transmission-line elements are required. (see the +TEXT: H example in Appendix A for further clarification.) +TEXT: H +TEXT: H The (optional) initial condition specification consists +TEXT: H of the voltage and current at each of the transmission line +TEXT: H ports. Note that the initial conditions (if any) apply +TEXT: H 'only' if the UIC option is specified on the .TRAN control +TEXT: H line. +TEXT: H +TEXT: H Note that a lossy transmission line (see below) with +TEXT: H zero loss may be more accurate than than the lossless +TEXT: H transmission line due to implementation details. +TEXT: H +TEXT: H + +SUBJECT: Lossy Transmission Lines +TITLE: Lossy Transmission Lines +TEXT: H +TEXT: H _3._3._2. _L_o_s_s_y _T_r_a_n_s_m_i_s_s_i_o_n _L_i_n_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H OXXXXXXX N1 N2 N3 N4 MNAME +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H O23 1 0 2 0 LOSSYMOD +TEXT: H OCONNECT 10 5 20 5 INTERCONNECT +TEXT: H +TEXT: H +TEXT: H +TEXT: H This is a two-port convolution model for single- +TEXT: H conductor lossy transmission lines. N1 and N2 are the nodes +TEXT: H at port 1; N3 and N4 are the nodes at port 2. Note that a +TEXT: H lossy transmission line with zero loss may be more accurate +TEXT: H than than the lossless transmission line due to implementa- +TEXT: H tion details. +TEXT: H + +SUBJECT: Lossy Transmission Line Model +TITLE: Lossy Transmission Line Model (LTRA) +TEXT: H +TEXT: H _3._3._3. _L_o_s_s_y _T_r_a_n_s_m_i_s_s_i_o_n _L_i_n_e _M_o_d_e_l (_L_T_R_A) +TEXT: H +TEXT: H +TEXT: H The uniform RLC/RC/LC/RG transmission line model (re- +TEXT: H ferred to as the LTRA model henceforth) models a uniform +TEXT: H constant-parameter distributed transmission line. The RC +TEXT: H and LC cases may also be modeled using the URC and TRA +TEXT: H models; however, the newer LTRA model is usually faster and +TEXT: H more accurate than the others. The operation of the LTRA +TEXT: H model is based on the convolution of the transmission line's +TEXT: H impulse responses with its inputs (see [8]). +TEXT: H +TEXT: H The LTRA model takes a number of parameters, some of +TEXT: H which must be given and some of which are optional. +TEXT: H +TEXT: H name parameter units/type default example +TEXT: H +TEXT: H R resistance/length Z/unit 0.0 0.2 +TEXT: H L inductance/length henrys/unit 0.0 9.13e-9 +TEXT: H G conductance/length mhos/unit 0.0 0.0 +TEXT: H C capacitance/length farads/unit 0.0 3.65e-12 +TEXT: H LEN length of line no default 1.0 +TEXT: H REL breakpoint control arbitrary unit 1 0.5 +TEXT: H ABS breakpoint control 1 5 +TEXT: H NOSTEPLIMIT don't limit timestep to less than flag not set set +TEXT: H line delay +TEXT: H NOCONTROL don't do complex timestep control flag not set set +TEXT: H LININTERP use linear interpolation flag not set set +TEXT: H MIXEDINTERP use linear when quadratic seems bad not set set +TEXT: H COMPACTREL special reltol for history compaction flag RELTOL 1.0e-3 +TEXT: H COMPACTABS special abstol for history compaction ABSTOL 1.0e-9 +TEXT: H TRUNCNR use Newton-Raphson method for flag not set set +TEXT: H timestep control +TEXT: H TRUNCDONTCUT don't limit timestep to keep flag not set set +TEXT: H impulse-response errors low +TEXT: H +TEXT: H +TEXT: H +TEXT: H The following types of lines have been implemented so +TEXT: H far: RLC (uniform transmission line with series loss only), +TEXT: H RC (uniform RC line), LC (lossless transmission line), and +TEXT: H RG (distributed series resistance and parallel conductance +TEXT: H only). Any other combination will yield erroneous results +TEXT: H and should not be tried. The length LEN of the line must be +TEXT: H specified. +TEXT: H +TEXT: H NOSTEPLIMIT is a flag that will remove the default res- +TEXT: H triction of limiting time-steps to less than the line delay +TEXT: H in the RLC case. NOCONTROL is a flag that prevents the +TEXT: H default limiting of the time-step based on convolution error +TEXT: H criteria in the RLC and RC cases. This speeds up simulation +TEXT: H but may in some cases reduce the accuracy of results. +TEXT: H LININTERP is a flag that, when specified, will use linear +TEXT: H interpolation instead of the default quadratic interpolation +TEXT: H for calculating delayed signals. MIXEDINTERP is a flag +TEXT: H that, when specified, uses a metric for judging whether qua- +TEXT: H dratic interpolation is not applicable and if so uses linear +TEXT: H interpolation; otherwise it uses the default quadratic +TEXT: H interpolation. TRUNCDONTCUT is a flag that removes the +TEXT: H default cutting of the time-step to limit errors in the +TEXT: H actual calculation of impulse-response related quantities. +TEXT: H COMPACTREL and COMPACTABS are quantities that control the +TEXT: H compaction of the past history of values stored for convolu- +TEXT: H tion. Larger values of these lower accuracy but usually +TEXT: H increase simulation speed. These are to be used with the +TEXT: H TRYTOCOMPACT option, described in the .OPTIONS section. +TEXT: H TRUNCNR is a flag that turns on the use of Newton-Raphson +TEXT: H iterations to determine an appropriate timestep in the +TEXT: H timestep control routines. The default is a trial and error +TEXT: H procedure by cutting the previous timestep in half. REL and +TEXT: H ABS are quantities that control the setting of breakpoints. +TEXT: H +TEXT: H The option most worth experimenting with for increasing +TEXT: H the speed of simulation is REL. The default value of 1 is +TEXT: H usually safe from the point of view of accuracy but occa- +TEXT: H sionally increases computation time. A value greater than 2 +TEXT: H eliminates all breakpoints and may be worth trying depending +TEXT: H on the nature of the rest of the circuit, keeping in mind +TEXT: H that it might not be safe from the viewpoint of accuracy. +TEXT: H Breakpoints may usually be entirely eliminated if it is +TEXT: H expected the circuit will not display sharp discontinuities. +TEXT: H Values between 0 and 1 are usually not required but may be +TEXT: H used for setting many breakpoints. +TEXT: H +TEXT: H COMPACTREL may also be experimented with when the +TEXT: H option TRYTOCOMPACT is specified in a .OPTIONS card. The +TEXT: H legal range is between 0 and 1. Larger values usually +TEXT: H decrease the accuracy of the simulation but in some cases +TEXT: H improve speed. If TRYTOCOMPACT is not specified on a +TEXT: H .OPTIONS card, history compaction is not attempted and accu- +TEXT: H racy is high. NOCONTROL, TRUNCDONTCUT and NOSTEPLIMIT also +TEXT: H tend to increase speed at the expense of accuracy. +TEXT: H + +SUBJECT: Uniform Distributed RC Lines +TITLE: Uniform Distributed RC Lines (Lossy) +TEXT: H +TEXT: H _3._3._4. _U_n_i_f_o_r_m _D_i_s_t_r_i_b_u_t_e_d _R_C _L_i_n_e_s (_L_o_s_s_y) +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H UXXXXXXX N1 N2 N3 MNAME L=LEN +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H U1 1 2 0 URCMOD L=50U +TEXT: H URC2 1 12 2 UMODL l=1MIL N=6 +TEXT: H +TEXT: H +TEXT: H +TEXT: H N1 and N2 are the two element nodes the RC line con- +TEXT: H nects, while N3 is the node to which the capacitances are +TEXT: H connected. MNAME is the model name, LEN is the length of +TEXT: H the RC line in meters. LUMPS, if specified, is the number +TEXT: H of lumped segments to use in modeling the RC line (see the +TEXT: H model description for the action taken if this parameter is +TEXT: H omitted). +TEXT: H + +SUBJECT: Uniform Distributed RC Model +TITLE: Uniform Distributed RC Model (URC) +TEXT: H +TEXT: H _3._3._5. _U_n_i_f_o_r_m _D_i_s_t_r_i_b_u_t_e_d _R_C _M_o_d_e_l (_U_R_C) +TEXT: H +TEXT: H +TEXT: H The URC model is derived from a model proposed by L. +TEXT: H Gertzberrg in 1974. The model is accomplished by a subcir- +TEXT: H cuit type expansion of the URC line into a network of lumped +TEXT: H RC segments with internally generated nodes. The RC seg- +TEXT: H ments are in a geometric progression, increasing toward the +TEXT: H middle of the URC line, with K as a proportionality con- +TEXT: H stant. The number of lumped segments used, if not specified +TEXT: H for the URC line device, is determined by the following for- +TEXT: H mula: +TEXT: H 2 +TEXT: H | R C |(K-1)| | +TEXT: H _ _ 2 +TEXT: H log|F 2 J L |-----| | +TEXT: H max +TEXT: H | L L | K | | +TEXT: H +TEXT: H N = ------------------------------ +TEXT: H log K +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The URC line is made up strictly of resistor and capa- +TEXT: H citor segments unless the ISPERL parameter is given a non- +TEXT: H zero value, in which case the capacitors are replaced with +TEXT: H reverse biased diodes with a zero-bias junction capacitance +TEXT: H equivalent to the capacitance replaced, and with a satura- +TEXT: H tion current of ISPERL amps per meter of transmission line +TEXT: H and an optional series resistance equivalent to RSPERL ohms +TEXT: H per meter. +TEXT: H +TEXT: H name parameter units default example area +TEXT: H +TEXT: H 1 K Propagation Constant - 2.0 1.2 - +TEXT: H 2 FMAX Maximum Frequency of interest Hz 1.0G 6.5Meg - +TEXT: H 3 RPERL Resistance per unit length Z/m 1000 10 - +TEXT: H 4 CPERL Capacitance per unit length F/m 1.0e-15 1pF - +TEXT: H 5 ISPERL Saturation Current per unit length A/m 0 - - +TEXT: H 6 RSPERL Diode Resistance per unit length Z/m 0 - - +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: TRANSISTORS AND DIODES +TITLE: TRANSISTORS AND DIODES +TEXT: H +TEXT: H _3._4. _T_R_A_N_S_I_S_T_O_R_S _A_N_D _D_I_O_D_E_S +TEXT: H +TEXT: H +TEXT: H The area factor used on the diode, BJT, JFET, and MES- +TEXT: H FET devices determines the number of equivalent parallel +TEXT: H devices of a specified model. The affected parameters are +TEXT: H marked with an asterisk under the heading 'area' in the +TEXT: H model descriptions below. Several geometric factors associ- +TEXT: H ated with the channel and the drain and source diffusions +TEXT: H can be specified on the MOSFET device line. +TEXT: H +TEXT: H Two different forms of initial conditions may be speci- +TEXT: H fied for some devices. The first form is included to +TEXT: H improve the dc convergence for circuits that contain more +TEXT: H than one stable state. If a device is specified OFF, the dc +TEXT: H operating point is determined with the terminal voltages for +TEXT: H that device set to zero. After convergence is obtained, the +TEXT: H program continues to iterate to obtain the exact value for +TEXT: H the terminal voltages. If a circuit has more than one dc +TEXT: H stable state, the OFF option can be used to force the solu- +TEXT: H tion to correspond to a desired state. If a device is +TEXT: H specified OFF when in reality the device is conducting, the +TEXT: H program still obtains the correct solution (assuming the +TEXT: H solutions converge) but more iterations are required since +TEXT: H the program must independently converge to two separate +TEXT: H solutions. The .NODESET control line serves a similar pur- +TEXT: H pose as the OFF option. The .NODESET option is easier to +TEXT: H apply and is the preferred means to aid convergence. +TEXT: H +TEXT: H The second form of initial conditions are specified for +TEXT: H use with the transient analysis. These are true 'initial +TEXT: H conditions' as opposed to the convergence aids above. See +TEXT: H the description of the .IC control line and the .TRAN con- +TEXT: H trol line for a detailed explanation of initial conditions. +TEXT: H +TEXT: H +TEXT: H +SUBTOPIC: SPICE:Junction Diodes +SUBTOPIC: SPICE:Diode Model +SUBTOPIC: SPICE:Bipolar Junction Transistors +SUBTOPIC: SPICE:BJT Models +SUBTOPIC: SPICE:Junction FieldEffect Transistors +SUBTOPIC: SPICE:JFET Models +SUBTOPIC: SPICE:MOSFETs +SUBTOPIC: SPICE:MOSFET Models +SUBTOPIC: SPICE:MESFETs +SUBTOPIC: SPICE:MESFET Models + +SUBJECT: Junction Diodes +TITLE: Junction Diodes +TEXT: H +TEXT: H _3._4._1. _J_u_n_c_t_i_o_n _D_i_o_d_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H DXXXXXXX N+ N- MNAME +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H DBRIDGE 2 10 DIODE1 +TEXT: H DCLMP 3 7 DMOD 3.0 IC=0.2 +TEXT: H +TEXT: H +TEXT: H +TEXT: H N+ and N- are the positive and negative nodes, respec- +TEXT: H tively. MNAME is the model name, AREA is the area factor, +TEXT: H and OFF indicates an (optional) starting condition on the +TEXT: H device for dc analysis. If the area factor is omitted, a +TEXT: H value of 1.0 is assumed. The (optional) initial condition +TEXT: H specification using IC=VD is intended for use with the UIC +TEXT: H option on the .TRAN control line, when a transient analysis +TEXT: H is desired starting from other than the quiescent operating +TEXT: H point. The (optional) TEMP value is the temperature at +TEXT: H which this device is to operate, and overrides the tempera- +TEXT: H ture specification on the .OPTION control line. +TEXT: H +TEXT: H + +SUBJECT: Diode Model +TITLE: Diode Model (D) +TEXT: H +TEXT: H _3._4._2. _D_i_o_d_e _M_o_d_e_l (_D) +TEXT: H +TEXT: H +TEXT: H The dc characteristics of the diode are determined by +TEXT: H the parameters IS and N. An ohmic resistance, RS, is in- +TEXT: H cluded. Charge storage effects are modeled by a transit +TEXT: H time, TT, and a nonlinear depletion layer capacitance which +TEXT: H is determined by the parameters CJO, VJ, and M. The tem- +TEXT: H perature dependence of the saturation current is defined by +TEXT: H the parameters EG, the energy and XTI, the saturation +TEXT: H current temperature exponent. The nominal temperature at +TEXT: H which these parameters were measured is TNOM, which defaults +TEXT: H to the circuit-wide value specified on the .OPTIONS control +TEXT: H line. Reverse breakdown is modeled by an exponential in- +TEXT: H crease in the reverse diode current and is determined by the +TEXT: H parameters BV and IBV (both of which are positive numbers). +TEXT: H +TEXT: H +TEXT: H +TEXT: H name parameter units default example area +TEXT: H +TEXT: H 1 IS saturation current A 1.0e-14 1.0e-14 * +TEXT: H 2 RS ohmic resistance Z 0 10 * +TEXT: H 3 N emission coefficient - 1 1.0 +TEXT: H 4 TT transit-time sec 0 0.1ns +TEXT: H 5 CJO zero-bias junction capacitance F 0 2pF * +TEXT: H 6 VJ junction potential V 1 0.6 +TEXT: H 7 M grading coefficient - 0.5 0.5 +TEXT: H 8 EG activation energy eV 1.11 1.11 Si +TEXT: H 0.69 Sbd +TEXT: H 0.67 Ge +TEXT: H 9 XTI saturation-current temp. exp - 3.0 3.0 jn +TEXT: H 2.0 Sbd +TEXT: H 10 KF flicker noise coefficient - 0 +TEXT: H 11 AF flicker noise exponent - 1 +TEXT: H 12 FC coefficient for forward-bias - 0.5 +TEXT: H depletion capacitance formula +TEXT: H 13 BV reverse breakdown voltage V infinite 40.0 +TEXT: H 14 IBV current at breakdown voltage A 1.0e-3 +TEXT: H o +TEXT: H 15 TNOM parameter measurement temperature C 27 50 +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Bipolar Junction Transistors +TITLE: Bipolar Junction Transistors (BJTs) +TEXT: H +TEXT: H _3._4._3. _B_i_p_o_l_a_r _J_u_n_c_t_i_o_n _T_r_a_n_s_i_s_t_o_r_s (_B_J_T_s) +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H QXXXXXXX NC NB NE MNAME +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H Q23 10 24 13 QMOD IC=0.6, 5.0 +TEXT: H Q50A 11 26 4 20 MOD1 +TEXT: H +TEXT: H +TEXT: H +TEXT: H NC, NB, and NE are the collector, base, and emitter +TEXT: H nodes, respectively. NS is the (optional) substrate node. +TEXT: H If unspecified, ground is used. MNAME is the model name, +TEXT: H AREA is the area factor, and OFF indicates an (optional) +TEXT: H initial condition on the device for the dc analysis. If the +TEXT: H area factor is omitted, a value of 1.0 is assumed. The +TEXT: H (optional) initial condition specification using IC=VBE, VCE +TEXT: H is intended for use with the UIC option on the .TRAN control +TEXT: H line, when a transient analysis is desired starting from +TEXT: H other than the quiescent operating point. See the .IC con- +TEXT: H trol line description for a better way to set transient ini- +TEXT: H tial conditions. The (optional) TEMP value is the tempera- +TEXT: H ture at which this device is to operate, and overrides the +TEXT: H temperature specification on the .OPTION control line. +TEXT: H +TEXT: H + +SUBJECT: BJT Models +TITLE: BJT Models (NPN/PNP) +TEXT: H +TEXT: H _3._4._4. _B_J_T _M_o_d_e_l_s (_N_P_N/_P_N_P) +TEXT: H +TEXT: H +TEXT: H The bipolar junction transistor model in SPICE is an +TEXT: H adaptation of the integral charge control model of Gummel +TEXT: H and Poon. This modified Gummel-Poon model extends the ori- +TEXT: H ginal model to include several effects at high bias levels. +TEXT: H The model automatically simplifies to the simpler Ebers-Moll +TEXT: H model when certain parameters are not specified. The param- +TEXT: H eter names used in the modified Gummel-Poon model have been +TEXT: H chosen to be more easily understood by the program user, and +TEXT: H to reflect better both physical and circuit design thinking. +TEXT: H +TEXT: H +TEXT: H The dc model is defined by the parameters IS, BF, NF, +TEXT: H ISE, IKF, and NE which determine the forward current gain +TEXT: H characteristics, IS, BR, NR, ISC, IKR, and NC which deter- +TEXT: H mine the reverse current gain characteristics, and VAF and +TEXT: H VAR which determine the output conductance for forward and +TEXT: H reverse regions. Three ohmic resistances RB, RC, and RE are +TEXT: H included, where RB can be high current dependent. Base +TEXT: H charge storage is modeled by forward and reverse transit +TEXT: H times, TF and TR, the forward transit time TF being bias +TEXT: H dependent if desired, and nonlinear depletion layer capaci- +TEXT: H tances which are determined by CJE, VJE, and MJE for the B-E +TEXT: H junction , CJC, VJC, and MJC for the B-C junction and CJS, +TEXT: H VJS, and MJS for the C-S (Collector-Substrate) junction. +TEXT: H The temperature dependence of the saturation current, IS, is +TEXT: H determined by the energy-gap, EG, and the saturation current +TEXT: H temperature exponent, XTI. Additionally base current tem- +TEXT: H perature dependence is modeled by the beta temperature +TEXT: H exponent XTB in the new model. The values specified are +TEXT: H assumed to have been measured at the temperature TNOM, which +TEXT: H can be specified on the .OPTIONS control line or overridden +TEXT: H by a specification on the .MODEL line. +TEXT: H +TEXT: H The BJT parameters used in the modified Gummel-Poon +TEXT: H model are listed below. The parameter names used in earlier +TEXT: H versions of SPICE2 are still accepted. +TEXT: H +TEXT: H Modified Gummel-Poon BJT Parameters. +TEXT: H +TEXT: H +TEXT: H name parameter units default example area +TEXT: H +TEXT: H 1 IS transport saturation current A 1.0e-16 1.0e-15 * +TEXT: H 2 BF ideal maximum forward beta - 100 100 +TEXT: H 3 NF forward current emission coefficient - 1.0 1 +TEXT: H 4 VAF forward Early voltage V infinite 200 +TEXT: H 5 IKF corner for forward beta +TEXT: H high current roll-off A infinite 0.01 * +TEXT: H 6 ISE B-E leakage saturation current A 0 1.0e-13 * +TEXT: H 7 NE B-E leakage emission coefficient - 1.5 2 +TEXT: H 8 BR ideal maximum reverse beta - 1 0.1 +TEXT: H 9 NR reverse current emission coefficient - 1 1 +TEXT: H 10 VAR reverse Early voltage V infinite 200 +TEXT: H 11 IKR corner for reverse beta +TEXT: H high current roll-off A infinite 0.01 * +TEXT: H 12 ISC B-C leakage saturation current A 0 1.0e-13 * +TEXT: H 13 NC B-C leakage emission coefficient - 2 1.5 +TEXT: H 14 RB zero bias base resistance Z 0 100 * +TEXT: H 15 IRB current where base resistance +TEXT: H falls halfway to its min value A infinite 0.1 * +TEXT: H 16 RBM minimum base resistance +TEXT: H at high currents Z RB 10 * +TEXT: H 17 RE emitter resistance Z 0 1 * +TEXT: H 18 RC collector resistance Z 0 10 * +TEXT: H 19 CJE B-E zero-bias depletion capacitance F 0 2pF * +TEXT: H 20 VJE B-E built-in potential V 0.75 0.6 +TEXT: H 21 MJE B-E junction exponential factor - 0.33 0.33 +TEXT: H 22 TF ideal forward transit time sec 0 0.1ns +TEXT: H 23 XTF coefficient for bias dependence of TF - 0 +TEXT: H 24 VTF voltage describing VBC +TEXT: H dependence of TF V infinite +TEXT: H 25 ITF high-current parameter +TEXT: H for effect on TF A 0 * +TEXT: H 26 PTF excess phase at freq=1.0/(TF*2PI) Hz deg 0 +TEXT: H 27 CJC B-C zero-bias depletion capacitance F 0 2pF * +TEXT: H 28 VJC B-C built-in potential V 0.75 0.5 +TEXT: H 29 MJC B-C junction exponential factor - 0.33 0.5 +TEXT: H 30 XCJC fraction of B-C depletion capacitance - 1 +TEXT: H connected to internal base node +TEXT: H 31 TR ideal reverse transit time sec 0 10ns +TEXT: H 32 CJS zero-bias collector-substrate +TEXT: H capacitance F 0 2pF * +TEXT: H 33 VJS substrate junction built-in potential V 0.75 +TEXT: H 34 MJS substrate junction exponential factor - 0 0.5 +TEXT: H 35 XTB forward and reverse beta +TEXT: H temperature exponent - 0 +TEXT: H 36 EG energy gap for temperature +TEXT: H effect on IS eV 1.11 +TEXT: H 37 XTI temperature exponent for effect on IS - 3 +TEXT: H 38 KF flicker-noise coefficient - 0 +TEXT: H 39 AF flicker-noise exponent - 1 +TEXT: H 40 FC coefficient for forward-bias +TEXT: H depletion capacitance formula - 0.5 +TEXT: H o +TEXT: H 41 TNOM Parameter measurement temperature C 27 50 +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Junction FieldEffect Transistors +TITLE: Junction Field-Effect Transistors (JFETs) +TEXT: H +TEXT: H _3._4._5. _J_u_n_c_t_i_o_n _F_i_e_l_d-_E_f_f_e_c_t _T_r_a_n_s_i_s_t_o_r_s (_J_F_E_T_s) +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H JXXXXXXX ND NG NS MNAME +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H J1 7 2 3 JM1 OFF +TEXT: H +TEXT: H +TEXT: H +TEXT: H ND, NG, and NS are the drain, gate, and source nodes, +TEXT: H respectively. MNAME is the model name, AREA is the area +TEXT: H factor, and OFF indicates an (optional) initial condition on +TEXT: H the device for dc analysis. If the area factor is omitted, +TEXT: H a value of 1.0 is assumed. The (optional) initial condition +TEXT: H specification, using IC=VDS, VGS is intended for use with +TEXT: H the UIC option on the .TRAN control line, when a transient +TEXT: H analysis is desired starting from other than the quiescent +TEXT: H operating point. See the .IC control line for a better way +TEXT: H to set initial conditions. The (optional) TEMP value is the +TEXT: H temperature at which this device is to operate, and over- +TEXT: H rides the temperature specification on the .OPTION control +TEXT: H line. +TEXT: H +TEXT: H + +SUBJECT: JFET Models +TITLE: JFET Models (NJF/PJF) +TEXT: H +TEXT: H _3._4._6. _J_F_E_T _M_o_d_e_l_s (_N_J_F/_P_J_F) +TEXT: H +TEXT: H +TEXT: H The JFET model is derived from the FET model of Shich- +TEXT: H man and Hodges. The dc characteristics are defined by the +TEXT: H parameters VTO and BETA, which determine the variation of +TEXT: H drain current with gate voltage, LAMBDA, which determines +TEXT: H the output conductance, and IS, the saturation current of +TEXT: H the two gate junctions. Two ohmic resistances, RD and RS, +TEXT: H are included. Charge storage is modeled by nonlinear deple- +TEXT: H tion layer capacitances for both gate junctions which vary +TEXT: H as the -1/2 power of junction voltage and are defined by the +TEXT: H parameters CGS, CGD, and PB. +TEXT: H +TEXT: H Note that in Spice3f and later, a fitting parameter B +TEXT: H has been added. For details, see [9]. +TEXT: H +TEXT: H +TEXT: H name parameter units default example area +TEXT: H +TEXT: H 1 VTO threshold voltage (V V -2.0 -2.0 +TEXT: H TO 2 +TEXT: H 2 BETA transconductance parameter (B) A/V 1.0e-4 1.0e-3 * +TEXT: H 3 LAMBDA channel-length modulation +TEXT: H parameter (L) 1/V 0 1.0e-4 +TEXT: H 4 RD drain ohmic resistance Z 0 100 * +TEXT: H 5 RS source ohmic resistance Z 0 100 * +TEXT: H 6 CGS zero-bias G-S junction capacitance (C ) F 0 5pF * +TEXT: H gs +TEXT: H 7 CGD zero-bias G-D junction capacitance (C ) F 0 1pF * +TEXT: H gs +TEXT: H 8 PB gate junction potential V 1 0.6 +TEXT: H 9 IS gate junction saturation current (I ) A 1.0e-14 1.0e-14 * +TEXT: H S +TEXT: H 10 B doping tail parameter - 1 1.1 +TEXT: H 11 KF flicker noise coefficient - 0 +TEXT: H 12 AF flicker noise exponent - 1 +TEXT: H 13 FC coefficient for forward-bias - 0.5 +TEXT: H depletion capacitance formula +TEXT: H o +TEXT: H 14 TNOM parameter measurement temperature C 27 50 +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: MOSFETs +TITLE: MOSFETs +TEXT: H +TEXT: H _3._4._7. _M_O_S_F_E_T_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H MXXXXXXX ND NG NS NB MNAME +TEXT: H + +TEXT: H + +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H M1 24 2 0 20 TYPE1 +TEXT: H M31 2 17 6 10 MODM L=5U W=2U +TEXT: H M1 2 9 3 0 MOD1 L=10U W=5U AD=100P AS=100P PD=40U PS=40U +TEXT: H +TEXT: H +TEXT: H ND, NG, NS, and NB are the drain, gate, source, and bulk +TEXT: H (substrate) nodes, respectively. MNAME is the model name. +TEXT: H L and W are the channel length and width, in meters. AD and +TEXT: H AS are the areas of the drain and source diffusions, in +TEXT: H 2 +TEXT: H meters . Note that the suffix U specifies microns (1e-6 m) +TEXT: H 2 +TEXT: H and P sq-microns (1e-12 m ). If any of L, W, AD, or AS are +TEXT: H not specified, default values are used. The use of defaults +TEXT: H simplifies input file preparation, as well as the editing +TEXT: H required if device geometries are to be changed. PD and PS +TEXT: H are the perimeters of the drain and source junctions, in +TEXT: H meters. NRD and NRS designate the equivalent number of +TEXT: H squares of the drain and source diffusions; these values +TEXT: H multiply the sheet resistance RSH specified on the .MODEL +TEXT: H control line for an accurate representation of the parasitic +TEXT: H series drain and source resistance of each transistor. PD +TEXT: H and PS default to 0.0 while NRD and NRS to 1.0. OFF indi- +TEXT: H cates an (optional) initial condition on the device for dc +TEXT: H analysis. The (optional) initial condition specification +TEXT: H using IC=VDS, VGS, VBS is intended for use with the UIC +TEXT: H option on the .TRAN control line, when a transient analysis +TEXT: H is desired starting from other than the quiescent operating +TEXT: H point. See the .IC control line for a better and more con- +TEXT: H venient way to specify transient initial conditions. The +TEXT: H (optional) TEMP value is the temperature at which this dev- +TEXT: H ice is to operate, and overrides the temperature specifica- +TEXT: H tion on the .OPTION control line. The temperature specifi- +TEXT: H cation is ONLY valid for level 1, 2, 3, and 6 MOSFETs, not +TEXT: H for level 4 or 5 (BSIM) devices. +TEXT: H +TEXT: H + +SUBJECT: MOSFET Models +TITLE: MOSFET Models (NMOS/PMOS) +TEXT: H +TEXT: H _3._4._8. _M_O_S_F_E_T _M_o_d_e_l_s (_N_M_O_S/_P_M_O_S) +TEXT: H +TEXT: H +TEXT: H SPICE provides four MOSFET device models, which differ +TEXT: H in the formulation of the I-V characteristic. The variable +TEXT: H LEVEL specifies the model to be used: +TEXT: H +TEXT: H LEVEL=1 -> Shichman-Hodges +TEXT: H LEVEL=2 -> MOS2 (as described in [1]) +TEXT: H LEVEL=3 -> MOS3, a semi-empirical model(see [1]) +TEXT: H LEVEL=4 -> BSIM (as described in [3]) +TEXT: H LEVEL=5 -> new BSIM (BSIM2; as described in [5]) +TEXT: H LEVEL=6 -> MOS6 (as described in [2]) +TEXT: H +TEXT: H +TEXT: H The dc characteristics of the level 1 through level 3 MOS- +TEXT: H FETs are defined by the device parameters VTO, KP, LAMBDA, +TEXT: H PHI and GAMMA. These parameters are computed by SPICE if +TEXT: H process parameters (NSUB, TOX, ...) are given, but user- +TEXT: H specified values always override. VTO is positive (nega- +TEXT: H tive) for enhancement mode and negative (positive) for +TEXT: H depletion mode N-channel (P-channel) devices. Charge +TEXT: H storage is modeled by three constant capacitors, CGSO, CGDO, +TEXT: H and CGBO which represent overlap capacitances, by the non- +TEXT: H linear thin-oxide capacitance which is distributed among the +TEXT: H gate, source, drain, and bulk regions, and by the nonlinear +TEXT: H depletion-layer capacitances for both substrate junctions +TEXT: H divided into bottom and periphery, which vary as the MJ and +TEXT: H MJSW power of junction voltage respectively, and are deter- +TEXT: H mined by the parameters CBD, CBS, CJ, CJSW, MJ, MJSW and PB. +TEXT: H Charge storage effects are modeled by the piecewise linear +TEXT: H voltages-dependent capacitance model proposed by Meyer. The +TEXT: H thin-oxide charge-storage effects are treated slightly dif- +TEXT: H ferent for the LEVEL=1 model. These voltage-dependent capa- +TEXT: H citances are included only if TOX is specified in the input +TEXT: H description and they are represented using Meyer's formula- +TEXT: H tion. +TEXT: H +TEXT: H There is some overlap among the parameters describing +TEXT: H the junctions, e.g. the reverse current can be input either +TEXT: H 2 +TEXT: H as IS (in A) or as JS (in A/m ). Whereas the first is an +TEXT: H absolute value the second is multiplied by AD and AS to give +TEXT: H the reverse current of the drain and source junctions +TEXT: H respectively. This methodology has been chosen since there +TEXT: H is no sense in relating always junction characteristics with +TEXT: H AD and AS entered on the device line; the areas can be +TEXT: H defaulted. The same idea applies also to the zero-bias +TEXT: H junction capacitances CBD and CBS (in F) on one hand, and CJ +TEXT: H 2 +TEXT: H (in F/m ) on the other. The parasitic drain and source +TEXT: H series resistance can be expressed as either RD and RS (in +TEXT: H ohms) or RSH (in ohms/sq.), the latter being multiplied by +TEXT: H the number of squares NRD and NRS input on the device line. +TEXT: H +TEXT: H A discontinuity in the MOS level 3 model with respect +TEXT: H to the KAPPA parameter has been detected (see [10]). The +TEXT: H supplied fix has been implemented in Spice3f2 and later. +TEXT: H Since this fix may affect parameter fitting, the option +TEXT: H "BADMOS3" may be set to use the old implementation (see the +TEXT: H section on simulation variables and the ".OPTIONS" line). +TEXT: H SPICE level 1, 2, 3 and 6 parameters: +TEXT: H +TEXT: H +TEXT: H name parameter units default example +TEXT: H +TEXT: H 1 LEVEL model index - 1 +TEXT: H 2 VTO zero-bias threshold voltage (V ) V 0.0 1.0 +TEXT: H TO 2 +TEXT: H 3 KP transconductance parameter A/V 2.0e-5 3.1e-5 +TEXT: H 1/2 +TEXT: H 4 GAMMA bulk threshold parameter (\) V 0.0 0.37 +TEXT: H 5 PHI surface potential (U) V 0.6 0.65 +TEXT: H 6 LAMBDA channel-length modulation +TEXT: H (MOS1 and MOS2 only) (L) 1/V 0.0 0.02 +TEXT: H 7 RD drain ohmic resistance Z 0.0 1.0 +TEXT: H 8 RS source ohmic resistance Z 0.0 1.0 +TEXT: H 9 CBD zero-bias B-D junction capacitance F 0.0 20fF +TEXT: H 10 CBS zero-bias B-S junction capacitance F 0.0 20fF +TEXT: H 11 IS bulk junction saturation current (I ) A 1.0e-14 1.0e-15 +TEXT: H S +TEXT: H 12 PB bulk junction potential V 0.8 0.87 +TEXT: H 13 CGSO gate-source overlap capacitance +TEXT: H per meter channel width F/m 0.0 4.0e-11 +TEXT: H 14 CGDO gate-drain overlap capacitance +TEXT: H per meter channel width F/m 0.0 4.0e-11 +TEXT: H 15 CGBO gate-bulk overlap capacitance +TEXT: H per meter channel length F/m 0.0 2.0e-10 +TEXT: H 16 RSH drain and source diffusion +TEXT: H sheet resistance Z/[] 0.0 10.0 +TEXT: H 17 CJ zero-bias bulk junction bottom cap. +TEXT: H 2 +TEXT: H per sq-meter of junction area F/m 0.0 2.0e-4 +TEXT: H 18 MJ bulk junction bottom grading coeff. - 0.5 0.5 +TEXT: H 19 CJSW zero-bias bulk junction sidewall cap. +TEXT: H per meter of junction perimeter F/m 0.0 1.0e-9 +TEXT: H 20 MJSW bulk junction sidewall grading coeff. - 0.50(level1) +TEXT: H 0.33(level2, 3) +TEXT: H 21 JS bulk junction saturation current +TEXT: H 2 +TEXT: H per sq-meter of junction area A/m 1.0e-8 +TEXT: H 22 TOX oxide thickness meter 1.0e-7 1.0e-7 +TEXT: H 3 +TEXT: H 23 NSUB substrate doping 1/cm 0.0 4.0e15 +TEXT: H 2 +TEXT: H 24 NSS surface state density 1/cm 0.0 1.0e10 +TEXT: H 2 +TEXT: H 25 NFS fast surface state density 1/cm 0.0 1.0e10 +TEXT: H +TEXT: H _c_o_n_t_i_n_u_e_d +TEXT: H +TEXT: H name parameter units default example +TEXT: H +TEXT: H 26 TPG type of gate material: - 1.0 +TEXT: H +1 opp. to substrate +TEXT: H -1 same as substrate +TEXT: H 0 Al gate +TEXT: H 27 XJ metallurgical junction depth meter 0.0 1M +TEXT: H 28 LD lateral diffusion meter 0.0 0.8M +TEXT: H 2 +TEXT: H 29 UO surface mobility cm /Vs 600 700 +TEXT: H 30 UCRIT critical field for mobility +TEXT: H degradation (MOS2 only) V/cm 1.0e4 1.0e4 +TEXT: H 31 UEXP critical field exponent in +TEXT: H mobility degradation (MOS2 only) - 0.0 0.1 +TEXT: H 32 UTRA transverse field coeff. (mobility) +TEXT: H (deleted for MOS2) - 0.0 0.3 +TEXT: H 33 VMAX maximum drift velocity of carriers m/s 0.0 5.0e4 +TEXT: H 34 NEFF total channel-charge (fixed and +TEXT: H mobile) coefficient (MOS2 only) - 1.0 5.0 +TEXT: H 35 KF flicker noise coefficient - 0.0 1.0e-26 +TEXT: H 36 AF flicker noise exponent - 1.0 1.2 +TEXT: H 37 FC coefficient for forward-bias +TEXT: H depletion capacitance formula - 0.5 +TEXT: H 38 DELTA width effect on threshold voltage +TEXT: H (MOS2 and MOS3) - 0.0 1.0 +TEXT: H 39 THETA mobility modulation (MOS3 only) 1/V 0.0 0.1 +TEXT: H 40 ETA static feedback (MOS3 only) - 0.0 1.0 +TEXT: H 41 KAPPA saturation field factor (MOS3 only) - 0.2 0.5 +TEXT: H o +TEXT: H 42 TNOM parameter measurement temperature C 27 50 +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The level 4 and level 5 (BSIM1 and BSIM2) parameters +TEXT: H are all values obtained from process characterization, and +TEXT: H can be generated automatically. J. Pierret [4] describes a +TEXT: H means of generating a 'process' file, and the program +TEXT: H Proc2Mod provided with SPICE3 converts this file into a se- +TEXT: H quence of BSIM1 ".MODEL" lines suitable for inclusion in a +TEXT: H SPICE input file. Parameters marked below with an * in the +TEXT: H l/w column also have corresponding parameters with a length +TEXT: H and width dependency. For example, VFB is the basic parame- +TEXT: H ter with units of Volts, and LVFB and WVFB also exist and +TEXT: H have units of Volt-Mmeter The formula +TEXT: H +TEXT: H P P +TEXT: H L W +TEXT: H P = P + ---------- + ---------- +TEXT: H 0 +TEXT: H L W +TEXT: H effective effective +TEXT: H +TEXT: H is used to evaluate the parameter for the actual device +TEXT: H specified with +TEXT: H +TEXT: H L = L - DL +TEXT: H effective input +TEXT: H and +TEXT: H +TEXT: H W = W - DW +TEXT: H effective input +TEXT: H +TEXT: H +TEXT: H +TEXT: H Note that unlike the other models in SPICE, the BSIM +TEXT: H model is designed for use with a process characterization +TEXT: H system that provides all the parameters, thus there are no +TEXT: H defaults for the parameters, and leaving one out is con- +TEXT: H sidered an error. For an example set of parameters and the +TEXT: H format of a process file, see the SPICE2 implementation +TEXT: H notes[3]. +TEXT: H +TEXT: H For more information on BSIM2, see reference [5]. +TEXT: H +TEXT: H SPICE BSIM (level 4) parameters. +TEXT: H +TEXT: H +TEXT: H name parameter units l/w +TEXT: H +TEXT: H VFB flat-band voltage V * +TEXT: H PHI surface inversion potential V * +TEXT: H 1/2 +TEXT: H K1 body effect coefficient V * +TEXT: H K2 drain/source depletion charge-sharing coefficient - * +TEXT: H ETA zero-bias drain-induced barrier-lowering coefficient - * +TEXT: H 2 +TEXT: H MUZ zero-bias mobility cm /V-s +TEXT: H DL shortening of channel Mm +TEXT: H DW narrowing of channel Mm +TEXT: H -1 +TEXT: H U0 zero-bias transverse-field mobility degradation coefficient V * +TEXT: H U1 zero-bias velocity saturation coefficient Mm/V * +TEXT: H 2 2 +TEXT: H X2MZ sens. of mobility to substrate bias at v =0 cm /V -s * +TEXT: H ds -1 +TEXT: H X2E sens. of drain-induced barrier lowering effect to substrate bias V * +TEXT: H -1 +TEXT: H X3E sens. of drain-induced barrier lowering effect to drain bias at V =V V * +TEXT: H ds dd -2 +TEXT: H X2U0 sens. of transverse field mobility degradation effect to substrate bias V * +TEXT: H -2 +TEXT: H X2U1 sens. of velocity saturation effect to substrate bias MmV * +TEXT: H 2 2 +TEXT: H MUS mobility at zero substrate bias and at V =V cm /V -s +TEXT: H ds dd 2 2 +TEXT: H X2MS sens. of mobility to substrate bias at V =V cm /V -s * +TEXT: H ds dd 2 2 +TEXT: H X3MS sens. of mobility to drain bias at V =V cm /V -s * +TEXT: H ds dd -2 +TEXT: H X3U1 sens. of velocity saturation effect on drain bias at V =V MmV * +TEXT: H ds dd +TEXT: H TOX gate oxide thickness Mm +TEXT: H o +TEXT: H TEMP temperature at which parameters were measured C +TEXT: H VDD measurement bias range V +TEXT: H CGDO gate-drain overlap capacitance per meter channel width F/m +TEXT: H CGSO gate-source overlap capacitance per meter channel width F/m +TEXT: H CGBO gate-bulk overlap capacitance per meter channel length F/m +TEXT: H XPART gate-oxide capacitance-charge model flag - +TEXT: H N0 zero-bias subthreshold slope coefficient - * +TEXT: H NB sens. of subthreshold slope to substrate bias - * +TEXT: H ND sens. of subthreshold slope to drain bias - * +TEXT: H RSH drain and source diffusion sheet resistance Z/[] +TEXT: H 2 +TEXT: H JS source drain junction current density A/m +TEXT: H PB built in potential of source drain junction V +TEXT: H MJ Grading coefficient of source drain junction - +TEXT: H PBSW built in potential of source, drain junction sidewall V +TEXT: H MJSW grading coefficient of source drain junction sidewall - +TEXT: H 2 +TEXT: H CJ Source drain junction capacitance per unit area F/m +TEXT: H CJSW source drain junction sidewall capacitance per unit length F/m +TEXT: H WDF source drain junction default width m +TEXT: H DELL Source drain junction length reduction m +TEXT: H +TEXT: H +TEXT: H +TEXT: H XPART = 0 selects a 40/60 drain/source charge partition +TEXT: H in saturation, while XPART=1 selects a 0/100 drain/source +TEXT: H charge partition. +TEXT: H +TEXT: H +TEXT: H ND, NG, and NS are the drain, gate, and source nodes, +TEXT: H respectively. MNAME is the model name, AREA is the area +TEXT: H factor, and OFF indicates an (optional) initial condition on +TEXT: H the device for dc analysis. If the area factor is omitted, +TEXT: H a value of 1.0 is assumed. The (optional) initial condition +TEXT: H specification, using IC=VDS, VGS is intended for use with +TEXT: H the UIC option on the .TRAN control line, when a transient +TEXT: H analysis is desired starting from other than the quiescent +TEXT: H operating point. See the .IC control line for a better way +TEXT: H to set initial conditions. +TEXT: H +TEXT: H + +SUBJECT: MESFETs +TITLE: MESFETs +TEXT: H +TEXT: H _3._4._9. _M_E_S_F_E_T_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H ZXXXXXXX ND NG NS MNAME +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H Z1 7 2 3 ZM1 OFF +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: MESFET Models +TITLE: MESFET Models (NMF/PMF) +TEXT: H +TEXT: H _3._4._1_0. _M_E_S_F_E_T _M_o_d_e_l_s (_N_M_F/_P_M_F) +TEXT: H +TEXT: H +TEXT: H The MESFET model is derived from the GaAs FET model of +TEXT: H Statz et al. as described in [11]. The dc characteristics +TEXT: H are defined by the parameters VTO, B, and BETA, which deter- +TEXT: H mine the variation of drain current with gate voltage, AL- +TEXT: H PHA, which determines saturation voltage, and LAMBDA, which +TEXT: H determines the output conductance. The formula are given +TEXT: H by: +TEXT: H +TEXT: H 3 +TEXT: H 2 +TEXT: H B (V -V ) | | V | | 3 +TEXT: H gs T ds _ +TEXT: H I = --------------- |1 - |1-A---| |(1 + L V ) for 0 < V < +TEXT: H d ds ds +TEXT: H 1 + b(V - V ) | | 3 | | A +TEXT: H gs T +TEXT: H 2 +TEXT: H B (V -V ) 3 +TEXT: H gs T _ +TEXT: H I = ---------------(1 + L V ) for V > +TEXT: H d ds ds +TEXT: H 1 + b(V - V ) A +TEXT: H gs T +TEXT: H +TEXT: H +TEXT: H Two ohmic resistances, RD and RS, are included. Charge +TEXT: H storage is modeled by total gate charge as a function of +TEXT: H gate-drain and gate-source voltages and is defined by the +TEXT: H parameters CGS, CGD, and PB. +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H name parameter units default example area +TEXT: H +TEXT: H 1 VTO pinch-off voltage V -2.0 -2.0 +TEXT: H 2 +TEXT: H 2 BETA transconductance parameter A/V 1.0e-4 1.0e-3 * +TEXT: H 3 B doping tail extending parameter 1/V 0.3 0.3 * +TEXT: H 4 ALPHA saturation voltage parameter 1/V 2 2 * +TEXT: H 5 LAMBDA channel-length modulation +TEXT: H parameter 1/V 0 1.0e-4 +TEXT: H 6 RD drain ohmic resistance Z 0 100 * +TEXT: H 7 RS source ohmic resistance Z 0 100 * +TEXT: H 8 CGS zero-bias G-S junction capacitance F 0 5pF * +TEXT: H 9 CGD zero-bias G-D junction capacitance F 0 1pF * +TEXT: H 10 PB gate junction potential V 1 0.6 +TEXT: H 11 KF flicker noise coefficient - 0 +TEXT: H 12 AF flicker noise exponent - 1 +TEXT: H 13 FC coefficient for forward-bias - 0.5 +TEXT: H depletion capacitance formula +TEXT: H +TEXT: H + +SUBJECT: ANALYSES AND OUTPUT CONTROL +TITLE: ANALYSES AND OUTPUT CONTROL +TEXT: H +TEXT: H _4. _A_N_A_L_Y_S_E_S _A_N_D _O_U_T_P_U_T _C_O_N_T_R_O_L +TEXT: H +TEXT: H +TEXT: H The following command lines are for specifying analyses +TEXT: H or plots within the circuit description file. Parallel com- +TEXT: H mands exist in the interactive command interpreter (detailed +TEXT: H in the following section). Specifying analyses and plots +TEXT: H (or tables) in the input file is useful for batch runs. +TEXT: H Batch mode is entered when either the -b option is given or +TEXT: H when the default input source is redirected from a file. In +TEXT: H batch mode, the analyses specified by the control lines in +TEXT: H the input file (e.g. ".ac", ".tran", etc.) are immediately +TEXT: H executed (unless ".control" lines exists; see the section on +TEXT: H the interactive command interpretor). If the -r _r_a_w_f_i_l_e +TEXT: H option is given then all data generated is written to a +TEXT: H Spice3 rawfile. The rawfile may be read by either the +TEXT: H interactive mode of Spice3 or by nutmeg; see the previous +TEXT: H section for details. In this case, the .SAVE line (see +TEXT: H below) may be used to record the value of internal device +TEXT: H variables (see Appendix B). +TEXT: H +TEXT: H If a rawfile is not specified, then output plots (in +TEXT: H "line-printer" form) and tables can be printed according to +TEXT: H the .PRINT, .PLOT, and .FOUR control lines, described next. +TEXT: H .PLOT, .PRINT, and .FOUR lines are meant for compatibility +TEXT: H with Spice2. +TEXT: H +SUBTOPIC: SPICE:SIMULATOR VARIABLES +SUBTOPIC: SPICE:INITIAL CONDITIONS +SUBTOPIC: SPICE:ANALYSES +SUBTOPIC: SPICE:BATCH OUTPUT + +SUBJECT: SIMULATOR VARIABLES +TITLE: SIMULATOR VARIABLES (.OPTIONS) +TEXT: H +TEXT: H _4._1. _S_I_M_U_L_A_T_O_R _V_A_R_I_A_B_L_E_S (._O_P_T_I_O_N_S) +TEXT: H +TEXT: H +TEXT: H Various parameters of the simulations available in +TEXT: H Spice3 can be altered to control the accuracy, speed, or +TEXT: H default values for some devices. These parameters may be +TEXT: H changed via the "set" command (described later in the sec- +TEXT: H tion on the interactive front-end) or via the ".OPTIONS" +TEXT: H line: +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .OPTIONS OPT1 OPT2 ... (or OPT=OPTVAL ...) +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .OPTIONS RELTOL=.005 TRTOL=8 +TEXT: H +TEXT: H +TEXT: H The options line allows the user to reset program con- +TEXT: H trol and user options for specific simulation purposes. +TEXT: H Additional options for Nutmeg may be specified as well and +TEXT: H take effect when Nutmeg reads the input file. Options +TEXT: H specified to Nutmeg via the 'set' command are also passed on +TEXT: H to SPICE3 as if specified on a .OPTIONS line. See the fol- +TEXT: H lowing section on the interactive command interpreter for +TEXT: H the parameters which may be set with a .OPTIONS line and the +TEXT: H format of the 'set' command. Any combination of the follow- +TEXT: H ing options may be included, in any order. 'x' (below) +TEXT: H represents some positive number. +TEXT: H +TEXT: H option effect +TEXT: H +TEXT: H ABSTOL=x resets the absolute current error tolerance of the +TEXT: H program. +TEXT: H The default value is 1 picoamp. +TEXT: H BADMOS3 Use the older version of the MOS3 model with the "kappa" +TEXT: H discontinuity. +TEXT: H CHGTOL=x resets the charge tolerance of the program. The default +TEXT: H value is 1.0e-14. +TEXT: H DEFAD=x resets the value for MOS drain diffusion area; the +TEXT: H default is 0.0. +TEXT: H DEFAS=x resets the value for MOS source diffusion area; the +TEXT: H default is 0.0. +TEXT: H DEFL=x resets the value for MOS channel length; the default +TEXT: H is 100.0 micrometer. +TEXT: H DEFW=x resets the value for MOS channel width; the default +TEXT: H is 100.0 micrometer. +TEXT: H GMIN=x resets the value of GMIN, the minimum conductance +TEXT: H allowed by the program. +TEXT: H The default value is 1.0e-12. +TEXT: H ITL1=x resets the dc iteration limit. The default is 100. +TEXT: H ITL2=x resets the dc transfer curve iteration limit. The +TEXT: H default is 50. +TEXT: H ITL3=x resets the lower transient analysis iteration limit. +TEXT: H the default value is 4. (Note: not implemented in Spice3). +TEXT: H ITL4=x resets the transient analysis timepoint iteration limit. +TEXT: H the default is 10. +TEXT: H ITL5=x resets the transient analysis total iteration limit. +TEXT: H the default is 5000. Set ITL5=0 to omit this test. +TEXT: H (Note: not implemented in Spice3). +TEXT: H KEEPOPINFO Retain the operating point information when either an +TEXT: H AC, Distortion, or Pole-Zero analysis is run. +TEXT: H This is particularly useful if the circuit is large +TEXT: H and you do not want to run a (redundant) ".OP" analysis. +TEXT: H METHOD=name sets the numerical integration method used by SPICE. +TEXT: H Possible names are "Gear" or "trapezoidal" (or just "trap"). +TEXT: H The default is trapezoidal. +TEXT: H PIVREL=x resets the relative ratio between the largest column entry +TEXT: H and an acceptable pivot value. The default value is 1.0e-3. +TEXT: H In the numerical pivoting algorithm the allowed minimum +TEXT: H pivot value is determined by +TEXT: H EPSREL=AMAX1(PIVREL*MAXVAL, PIVTOL) +TEXT: H where MAXVAL is the maximum element in the column where +TEXT: H a pivot is sought (partial pivoting). +TEXT: H PIVTOL=x resets the absolute minimum value for a matrix entry +TEXT: H to be accepted as a pivot. The default value is 1.0e-13. +TEXT: H RELTOL=x resets the relative error tolerance of the program. +TEXT: H The +TEXT: H default value is 0.001 (0.1%). +TEXT: H TEMP=x Resets the operating temperature of the circuit. The +TEXT: H default value is 27 deg C (300 deg K). TEMP can be overridden +TEXT: H by a temperature specification on any temperature dependent +TEXT: H instance. +TEXT: H TNOM=x resets the nominal temperature at which device parameters +TEXT: H are measured. The default value is 27 deg C (300 deg K). +TEXT: H TNOM can be overridden by a specification on any temperature +TEXT: H dependent device model. +TEXT: H TRTOL=x resets the transient error tolerance. The default value +TEXT: H is 7.0. This parameter is an estimate of the factor by +TEXT: H which SPICE overestimates the actual truncation error. +TEXT: H TRYTOCOMPACT Applicable only to the LTRA model. +TEXT: H When specified, the simulator tries to condense LTRA transmission +TEXT: H lines' past history of input voltages and currents. +TEXT: H VNTOL=x resets the absolute voltage error tolerance of the +TEXT: H program. The default value is 1 microvolt. +TEXT: H +TEXT: H +TEXT: H In addition, the following options have the listed +TEXT: H effect when operating in spice2 emulation mode: +TEXT: H +TEXT: H option effect +TEXT: H +TEXT: H option effect +TEXT: H ACCT causes accounting and run time statistics to be printed +TEXT: H LIST causes the summary listing of the input data to be printed +TEXT: H NOMOD suppresses the printout of the model parameters +TEXT: H NOPAGE suppresses page ejects +TEXT: H NODE causes the printing of the node table. +TEXT: H OPTS causes the option values to be printed. +TEXT: H +TEXT: H + +SUBJECT: INITIAL CONDITIONS +TITLE: INITIAL CONDITIONS +TEXT: H +TEXT: H _4._2. _I_N_I_T_I_A_L _C_O_N_D_I_T_I_O_N_S +TEXT: H +SUBTOPIC: SPICE:.NODESET +SUBTOPIC: SPICE:.IC + +SUBJECT: .NODESET +TITLE: .NODESET: Specify Initial Node Voltage Guesses +TEXT: H +TEXT: H _4._2._1. ._N_O_D_E_S_E_T: _S_p_e_c_i_f_y _I_n_i_t_i_a_l _N_o_d_e _V_o_l_t_a_g_e _G_u_e_s_s_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .NODESET V(NODNUM)=VAL V(NODNUM)=VAL ... +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .NODESET V(12)=4.5 V(4)=2.23 +TEXT: H +TEXT: H +TEXT: H +TEXT: H The Nodeset line helps the program find the dc or ini- +TEXT: H tial transient solution by making a preliminary pass with +TEXT: H the specified nodes held to the given voltages. The res- +TEXT: H triction is then released and the iteration continues to the +TEXT: H true solution. The .NODESET line may be necessary for con- +TEXT: H vergence on bistable or a-stable circuits. In general, this +TEXT: H line should not be necessary. +TEXT: H +TEXT: H + +SUBJECT: .IC +TITLE: .IC: Set Initial Conditions +TEXT: H +TEXT: H _4._2._2. ._I_C: _S_e_t _I_n_i_t_i_a_l _C_o_n_d_i_t_i_o_n_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .IC V(NODNUM)=VAL V(NODNUM)=VAL ... +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .IC V(11)=5 V(4)=-5 V(2)=2.2 +TEXT: H +TEXT: H +TEXT: H +TEXT: H The IC line is for setting transient initial condi- +TEXT: H tions. It has two different interpretations, depending on +TEXT: H whether the UIC parameter is specified on the .TRAN control +TEXT: H line. Also, one should not confuse this line with the +TEXT: H .NODESET line. The .NODESET line is only to help dc conver- +TEXT: H gence, and does not affect final bias solution (except for +TEXT: H multi-stable circuits). The two interpretations of this +TEXT: H line are as follows: +TEXT: H +TEXT: H 1. When the UIC parameter is specified on the .TRAN line, +TEXT: H then the node voltages specified on the .IC control line are +TEXT: H used to compute the capacitor, diode, BJT, JFET, and MOSFET +TEXT: H initial conditions. This is equivalent to specifying the +TEXT: H IC=... parameter on each device line, but is much more con- +TEXT: H venient. The IC=... parameter can still be specified and +TEXT: H takes precedence over the .IC values. Since no dc bias +TEXT: H (initial transient) solution is computed before the tran- +TEXT: H sient analysis, one should take care to specify all dc +TEXT: H source voltages on the .IC control line if they are to be +TEXT: H used to compute device initial conditions. +TEXT: H +TEXT: H 2. When the UIC parameter is not specified on the .TRAN +TEXT: H control line, the dc bias (initial transient) solution is +TEXT: H computed before the transient analysis. In this case, the +TEXT: H node voltages specified on the .IC control line is forced to +TEXT: H the desired initial values during the bias solution. During +TEXT: H transient analysis, the constraint on these node voltages is +TEXT: H removed. This is the preferred method since it allows SPICE +TEXT: H to compute a consistent dc solution. +TEXT: H + +SUBJECT: ANALYSES +TITLE: ANALYSES +TEXT: H +TEXT: H _4._3. _A_N_A_L_Y_S_E_S +TEXT: H +TEXT: H +SUBTOPIC: SPICE:.AC +SUBTOPIC: SPICE:.DC +SUBTOPIC: SPICE:.DISTO +SUBTOPIC: SPICE:.NOISE +SUBTOPIC: SPICE:.OP +SUBTOPIC: SPICE:.PZ +SUBTOPIC: SPICE:.SENS +SUBTOPIC: SPICE:.TF +SUBTOPIC: SPICE:.TRAN + +SUBJECT: .AC +TITLE: .AC: Small-Signal AC Analysis +TEXT: H +TEXT: H _4._3._1. ._A_C: _S_m_a_l_l-_S_i_g_n_a_l _A_C _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .AC DEC ND FSTART FSTOP +TEXT: H .AC OCT NO FSTART FSTOP +TEXT: H .AC LIN NP FSTART FSTOP +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .AC DEC 10 1 10K +TEXT: H .AC DEC 10 1K 100MEG +TEXT: H .AC LIN 100 1 100HZ +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H DEC stands for decade variation, and ND is the number +TEXT: H of points per decade. OCT stands for octave variation, and +TEXT: H NO is the number of points per octave. LIN stands for +TEXT: H linear variation, and NP is the number of points. FSTART is +TEXT: H the starting frequency, and FSTOP is the final frequency. +TEXT: H If this line is included in the input file, SPICE performs +TEXT: H an AC analysis of the circuit over the specified frequency +TEXT: H range. Note that in order for this analysis to be meaning- +TEXT: H ful, at least one independent source must have been speci- +TEXT: H fied with an ac value. +TEXT: H +TEXT: H + +SUBJECT: .DC +TITLE: .DC: DC Transfer Function +TEXT: H +TEXT: H _4._3._2. ._D_C: _D_C _T_r_a_n_s_f_e_r _F_u_n_c_t_i_o_n +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .DC SRCNAM VSTART VSTOP VINCR [SRC2 START2 STOP2 INCR2] +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .DC VIN 0.25 5.0 0.25 +TEXT: H .DC VDS 0 10 .5 VGS 0 5 1 +TEXT: H .DC VCE 0 10 .25 IB 0 10U 1U +TEXT: H +TEXT: H +TEXT: H +TEXT: H The DC line defines the dc transfer curve source and +TEXT: H sweep limits (again with capacitors open and inductors +TEXT: H shorted). SRCNAM is the name of an independent voltage or +TEXT: H current source. VSTART, VSTOP, and VINCR are the starting, +TEXT: H final, and incrementing values respectively. The first +TEXT: H example causes the value of the voltage source VIN to be +TEXT: H swept from 0.25 Volts to 5.0 Volts in increments of 0.25 +TEXT: H Volts. A second source (SRC2) may optionally be specified +TEXT: H with associated sweep parameters. In this case, the first +TEXT: H source is swept over its range for each value of the second +TEXT: H source. This option can be useful for obtaining semiconduc- +TEXT: H tor device output characteristics. See the second example +TEXT: H circuit description in Appendix A. +TEXT: H +TEXT: H + +SUBJECT: .DISTO +TITLE: .DISTO: Distortion Analysis +TEXT: H +TEXT: H _4._3._3. ._D_I_S_T_O: _D_i_s_t_o_r_t_i_o_n _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .DISTO DEC ND FSTART FSTOP +TEXT: H .DISTO OCT NO FSTART FSTOP +TEXT: H .DISTO LIN NP FSTART FSTOP +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .DISTO DEC 10 1kHz 100Mhz +TEXT: H .DISTO DEC 10 1kHz 100Mhz 0.9 +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The Disto line does a small-signal distortion analysis +TEXT: H of the circuit. A multi-dimensional Volterra series +TEXT: H analysis is done using multi-dimensional Taylor series to +TEXT: H represent the nonlinearities at the operating point. Terms +TEXT: H of up to third order are used in the series expansions. +TEXT: H +TEXT: H If the optional parameter F2OVERF1 is not specified, +TEXT: H .DISTO does a harmonic analysis - i.e., it analyses distor- +TEXT: H tion in the circuit using only a single input frequency F1, +TEXT: H which is swept as specified by arguments of the .DISTO com- +TEXT: H mand exactly as in the .AC command. Inputs at this fre- +TEXT: H quency may be present at more than one input source, and +TEXT: H their magnitudes and phases are specified by the arguments +TEXT: H of the DISTOF1 keyword in the input file lines for the input +TEXT: H sources (see the description for independent sources). (The +TEXT: H arguments of the DISTOF2 keyword are not relevant in this +TEXT: H case). The analysis produces information about the A.C. +TEXT: H values of all node voltages and branch currents at the har- +TEXT: H monic frequencies 2F1 and 3F1, vs. the input frequency F1 as +TEXT: H it is swept. (A value of 1 (as a complex distortion output) +TEXT: H signifies cos(2J(2F1)t) at 2F1 and cos(2J(3F1)t) at 3F1, +TEXT: H using the convention that 1 at the input fundamental fre- +TEXT: H quency is equivalent to cos(2JF1t).) The distortion com- +TEXT: H ponent desired (2F1 or 3F1) can be selected using commands +TEXT: H in nutmeg, and then printed or plotted. (Normally, one is +TEXT: H interested primarily in the magnitude of the harmonic com- +TEXT: H ponents, so the magnitude of the AC distortion value is +TEXT: H looked at). It should be noted that these are the A.C. +TEXT: H values of the actual harmonic components, and are not equal +TEXT: H to HD2 and HD3. To obtain HD2 and HD3, one must divide by +TEXT: H the corresponding A.C. values at F1, obtained from an .AC +TEXT: H line. This division can be done using nutmeg commands. +TEXT: H +TEXT: H If the optional F2OVERF1 parameter is specified, it +TEXT: H should be a real number between (and not equal to) 0.0 and +TEXT: H 1.0; in this case, .DISTO does a spectral analysis. It con- +TEXT: H siders the circuit with sinusoidal inputs at two different +TEXT: H frequencies F1 and F2. F1 is swept according to the .DISTO +TEXT: H control line options exactly as in the .AC control line. F2 +TEXT: H is kept fixed at a single frequency as F1 sweeps - the value +TEXT: H at which it is kept fixed is equal to F2OVERF1 times FSTART. +TEXT: H Each independent source in the circuit may potentially have +TEXT: H two (superimposed) sinusoidal inputs for distortion, at the +TEXT: H frequencies F1 and F2. The magnitude and phase of the F1 +TEXT: H component are specified by the arguments of the DISTOF1 key- +TEXT: H word in the source's input line (see the description of +TEXT: H independent sources); the magnitude and phase of the F2 com- +TEXT: H ponent are specified by the arguments of the DISTOF2 key- +TEXT: H word. The analysis produces plots of all node +TEXT: H voltages/branch currents at the intermodulation product fre- +TEXT: H quencies F1 + F2, F1 - F2, and (2 F1) - F2, vs the swept +TEXT: H frequency F1. The IM product of interest may be selected +TEXT: H using the setplot command, and displayed with the print and +TEXT: H plot commands. It is to be noted as in the harmonic +TEXT: H analysis case, the results are the actual AC voltages and +TEXT: H currents at the intermodulation frequencies, and need to be +TEXT: H normalized with respect to .AC values to obtain the IM +TEXT: H parameters. +TEXT: H +TEXT: H If the DISTOF1 or DISTOF2 keywords are missing from the +TEXT: H description of an independent source, then that source is +TEXT: H assumed to have no input at the corresponding frequency. +TEXT: H The default values of the magnitude and phase are 1.0 and +TEXT: H 0.0 respectively. The phase should be specified in degrees. +TEXT: H +TEXT: H It should be carefully noted that the number F2OVERF1 +TEXT: H should ideally be an irrational number, and that since this +TEXT: H is not possible in practice, efforts should be made to keep +TEXT: H the denominator in its fractional representation as large as +TEXT: H possible, certainly above 3, for accurate results (i.e., if +TEXT: H F2OVERF1 is represented as a fraction A/B, where A and B are +TEXT: H integers with no common factors, B should be as large as +TEXT: H possible; note that A < B because F2OVERF1 is constrained to +TEXT: H be < 1). To illustrate why, consider the cases where +TEXT: H F2OVERF1 is 49/100 and 1/2. In a spectral analysis, the +TEXT: H outputs produced are at F1 + F2, F1 - F2 and 2 F1 - F2. In +TEXT: H the latter case, F1 - F2 = F2, so the result at the F1-F2 +TEXT: H component is erroneous because there is the strong fundamen- +TEXT: H tal F2 component at the same frequency. Also, F1 + F2 = 2 +TEXT: H F1 - F2 in the latter case, and each result is erroneous +TEXT: H individually. This problem is not there in the case where +TEXT: H F2OVERF1 = 49/100, because F1-F2 = 51/100 F1 < > 49/100 F1 = +TEXT: H F2. In this case, there are two very closely spaced fre- +TEXT: H quency components at F2 and F1 - F2. One of the advantages +TEXT: H of the Volterra series technique is that it computes distor- +TEXT: H tions at mix frequencies expressed symbolically (i.e. n F1 + +TEXT: H m F2), therefore one is able to obtain the strengths of dis- +TEXT: H tortion components accurately even if the separation between +TEXT: H them is very small, as opposed to transient analysis for +TEXT: H example. The disadvantage is of course that if two of the +TEXT: H mix frequencies coincide, the results are not merged +TEXT: H together and presented (though this could presumably be done +TEXT: H as a postprocessing step). Currently, the interested user +TEXT: H should keep track of the mix frequencies himself or herself +TEXT: H and add the distortions at coinciding mix frequencies +TEXT: H together should it be necessary. +TEXT: H +TEXT: H + +SUBJECT: .NOISE +TITLE: .NOISE: Noise Analysis +TEXT: H +TEXT: H _4._3._4. ._N_O_I_S_E: _N_o_i_s_e _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .NOISE V(OUTPUT <,REF>) SRC ( DEC | LIN | OCT ) PTS FSTART FSTOP +TEXT: H + +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .NOISE V(5) VIN DEC 10 1kHZ 100Mhz +TEXT: H .NOISE V(5,3) V1 OCT 8 1.0 1.0e6 1 +TEXT: H +TEXT: H +TEXT: H +TEXT: H The Noise line does a noise analysis of the circuit. +TEXT: H OUTPUT is the node at which the total output noise is +TEXT: H desired; if REF is specified, then the noise voltage +TEXT: H V(OUTPUT) - V(REF) is calculated. By default, REF is +TEXT: H assumed to be ground. SRC is the name of an independent +TEXT: H source to which input noise is referred. PTS, FSTART and +TEXT: H FSTOP are .AC type parameters that specify the frequency +TEXT: H range over which plots are desired. PTS_PER_SUMMARY is an +TEXT: H optional integer; if specified, the noise contributions of +TEXT: H each noise generator is produced every PTS_PER_SUMMARY fre- +TEXT: H quency points. +TEXT: H +TEXT: H The .NOISE control line produces two plots - one for +TEXT: H the Noise Spectral Density curves and one for the total +TEXT: H Integrated Noise over the specified frequency range. All +TEXT: H 2 +TEXT: H noise voltages/currents are in squared units (V /Hz and +TEXT: H 2 2 2 +TEXT: H A /Hz for spectral density, V and A for integrated noise). +TEXT: H + +SUBJECT: .OP +TITLE: .OP: Operating Point Analysis +TEXT: H +TEXT: H _4._3._5. ._O_P: _O_p_e_r_a_t_i_n_g _P_o_i_n_t _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .OP +TEXT: H +TEXT: H +TEXT: H +TEXT: H The inclusion of this line in an input file directs +TEXT: H SPICE to determine the dc operating point of the circuit +TEXT: H with inductors shorted and capacitors opened. Note: a DC +TEXT: H analysis is automatically performed prior to a transient +TEXT: H analysis to determine the transient initial conditions, and +TEXT: H prior to an AC small-signal, Noise, and Pole-Zero analysis +TEXT: H to determine the linearized, small-signal models for non- +TEXT: H linear devices (see the KEEPOPINFO variable above). +TEXT: H +TEXT: H + +SUBJECT: .PZ +TITLE: .PZ: Pole-Zero Analysis +TEXT: H +TEXT: H _4._3._6. ._P_Z: _P_o_l_e-_Z_e_r_o _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .PZ NODE1 NODE2 NODE3 NODE4 CUR POL +TEXT: H .PZ NODE1 NODE2 NODE3 NODE4 CUR ZER +TEXT: H .PZ NODE1 NODE2 NODE3 NODE4 CUR PZ +TEXT: H .PZ NODE1 NODE2 NODE3 NODE4 VOL POL +TEXT: H .PZ NODE1 NODE2 NODE3 NODE4 VOL ZER +TEXT: H .PZ NODE1 NODE2 NODE3 NODE4 VOL PZ +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .PZ 1 0 3 0 CUR POL +TEXT: H .PZ 2 3 5 0 VOL ZER +TEXT: H .PZ 4 1 4 1 CUR PZ +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H CUR stands for a transfer function of the type (output +TEXT: H voltage)/(input current) while VOL stands for a transfer +TEXT: H function of the type (output voltage)/(input voltage). POL +TEXT: H stands for pole analysis only, ZER for zero analysis only +TEXT: H and PZ for both. This feature is provided mainly because if +TEXT: H there is a nonconvergence in finding poles or zeros, then, +TEXT: H at least the other can be found. Finally, NODE1 and NODE2 +TEXT: H are the two input nodes and NODE3 and NODE4 are the two out- +TEXT: H put nodes. Thus, there is complete freedom regarding the +TEXT: H output and input ports and the type of transfer function. +TEXT: H +TEXT: H In interactive mode, the command syntax is the same +TEXT: H except that the first field is PZ instead of .PZ. To print +TEXT: H the results, one should use the command 'print all'. +TEXT: H +TEXT: H + +SUBJECT: .SENS +TITLE: .SENS: DC or Small-Signal AC Sensitivity Analysis +TEXT: H +TEXT: H _4._3._7. ._S_E_N_S: _D_C _o_r _S_m_a_l_l-_S_i_g_n_a_l _A_C _S_e_n_s_i_t_i_v_i_t_y _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .SENS OUTVAR +TEXT: H .SENS OUTVAR AC DEC ND FSTART FSTOP +TEXT: H .SENS OUTVAR AC OCT NO FSTART FSTOP +TEXT: H .SENS OUTVAR AC LIN NP FSTART FSTOP +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .SENS V(1,OUT) +TEXT: H .SENS V(OUT) AC DEC 10 100 100k +TEXT: H .SENS I(VTEST) +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H The sensitivity of OUTVAR to all non-zero device param- +TEXT: H eters is calculated when the SENS analysis is specified. +TEXT: H OUTVAR is a circuit variable (node voltage or voltage-source +TEXT: H branch current). The first form calculates sensitivity of +TEXT: H the DC operating-point value of OUTVAR. The second form +TEXT: H calculates sensitivity of the AC values of OUTVAR. The +TEXT: H parameters listed for AC sensitivity are the same as in an +TEXT: H AC analysis (see ".AC" above). The output values are in +TEXT: H dimensions of change in output per unit change of input (as +TEXT: H opposed to percent change in output or per percent change of +TEXT: H input). +TEXT: H +TEXT: H + +SUBJECT: .TF +TITLE: .TF: Transfer Function Analysis +TEXT: H +TEXT: H _4._3._8. ._T_F: _T_r_a_n_s_f_e_r _F_u_n_c_t_i_o_n _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .TF OUTVAR INSRC +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .TF V(5, 3) VIN +TEXT: H .TF I(VLOAD) VIN +TEXT: H +TEXT: H +TEXT: H +TEXT: H The TF line defines the small-signal output and input +TEXT: H for the dc small-signal analysis. OUTVAR is the small- +TEXT: H signal output variable and INSRC is the small-signal input +TEXT: H source. If this line is included, SPICE computes the dc +TEXT: H small-signal value of the transfer function (output/input), +TEXT: H input resistance, and output resistance. For the first +TEXT: H example, SPICE would compute the ratio of V(5, 3) to VIN, +TEXT: H the small-signal input resistance at VIN, and the small- +TEXT: H signal output resistance measured across nodes 5 and 3. +TEXT: H +TEXT: H + +SUBJECT: .TRAN +TITLE: .TRAN: Transient Analysis +TEXT: H +TEXT: H _4._3._9. ._T_R_A_N: _T_r_a_n_s_i_e_n_t _A_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .TRAN TSTEP TSTOP > +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .TRAN 1NS 100NS +TEXT: H .TRAN 1NS 1000NS 500NS +TEXT: H .TRAN 10NS 1US +TEXT: H +TEXT: H +TEXT: H +TEXT: H TSTEP is the printing or plotting increment for line- +TEXT: H printer output. For use with the post-processor, TSTEP is +TEXT: H the suggested computing increment. TSTOP is the final time, +TEXT: H and TSTART is the initial time. If TSTART is omitted, it is +TEXT: H assumed to be zero. The transient analysis always begins at +TEXT: H time zero. In the interval , the circuit is +TEXT: H analyzed (to reach a steady state), but no outputs are +TEXT: H stored. In the interval , the circuit is +TEXT: H analyzed and outputs are stored. TMAX is the maximum step- +TEXT: H size that SPICE uses; for default, the program chooses +TEXT: H either TSTEP or (TSTOP-TSTART)/50.0, whichever is smaller. +TEXT: H TMAX is useful when one wishes to guarantee a computing +TEXT: H interval which is smaller than the printer increment, TSTEP. +TEXT: H +TEXT: H UIC (use initial conditions) is an optional keyword +TEXT: H which indicates that the user does not want SPICE to solve +TEXT: H for the quiescent operating point before beginning the tran- +TEXT: H sient analysis. If this keyword is specified, SPICE uses +TEXT: H the values specified using IC=... on the various elements as +TEXT: H the initial transient condition and proceeds with the +TEXT: H analysis. If the .IC control line has been specified, then +TEXT: H the node voltages on the .IC line are used to compute the +TEXT: H initial conditions for the devices. Look at the description +TEXT: H on the .IC control line for its interpretation when UIC is +TEXT: H not specified. +TEXT: H + +SUBJECT: BATCH OUTPUT +TITLE: BATCH OUTPUT +TEXT: H +TEXT: H _4._4. _B_A_T_C_H _O_U_T_P_U_T +TEXT: H +TEXT: H +SUBTOPIC: SPICE:.SAVE Lines +SUBTOPIC: SPICE:.PRINT Lines +SUBTOPIC: SPICE:.PLOT Lines +SUBTOPIC: SPICE:.FOUR + +SUBJECT: .SAVE Lines +TITLE: .SAVE Lines +TEXT: H +TEXT: H _4._4._1. ._S_A_V_E _L_i_n_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .SAVE _v_e_c_t_o_r _v_e_c_t_o_r _v_e_c_t_o_r ... +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .SAVE i(vin) input output +TEXT: H .SAVE @m1[id] +TEXT: H +TEXT: H +TEXT: H +TEXT: H The vectors listed on the .SAVE line are recorded in +TEXT: H the rawfile for use later with spice3 or nutmeg (nutmeg is +TEXT: H just the data-analysis half of spice3, without the ability +TEXT: H to simulate). The standard vector names are accepted. If +TEXT: H no .SAVE line is given, then the default set of vectors are +TEXT: H saved (node voltages and voltage source branch currents). +TEXT: H If .SAVE lines are given, only those vectors specified are +TEXT: H saved. For more discussion on internal device data, see +TEXT: H Appendix B. See also the section on the interactive command +TEXT: H interpretor for information on how to use the rawfile. +TEXT: H + +SUBJECT: .PRINT Lines +TITLE: .PRINT Lines +TEXT: H +TEXT: H _4._4._2. ._P_R_I_N_T _L_i_n_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .PRINT PRTYPE OV1 +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .PRINT TRAN V(4) I(VIN) +TEXT: H .PRINT DC V(2) I(VSRC) V(23, 17) +TEXT: H .PRINT AC VM(4, 2) VR(7) VP(8, 3) +TEXT: H +TEXT: H +TEXT: H The Print line defines the contents of a tabular list- +TEXT: H ing of one to eight output variables. PRTYPE is the type of +TEXT: H the analysis (DC, AC, TRAN, NOISE, or DISTO) for which the +TEXT: H specified outputs are desired. The form for voltage or +TEXT: H current output variables is the same as given in the previ- +TEXT: H ous section for the print command; Spice2 restricts the out- +TEXT: H put variable to the following forms (though this restriction +TEXT: H is not enforced by Spice3): +TEXT: H +TEXT: H +TEXT: H V(N1<,N2>) +TEXT: H specifies the voltage difference between nodes N1 +TEXT: H and N2. If N2 (and the preceding comma) is omit- +TEXT: H ted, ground (0) is assumed. See the print command +TEXT: H in the previous section for more details. For +TEXT: H compatibility with spice2, the following five +TEXT: H additional values can be accessed for the ac +TEXT: H analysis by replacing the "V" in V(N1,N2) with: +TEXT: H +TEXT: H +TEXT: H VR - real part +TEXT: H VI - imaginary part +TEXT: H VM - magnitude +TEXT: H VP - phase +TEXT: H VDB - 20 log10(magnitude) +TEXT: H +TEXT: H +TEXT: H +TEXT: H I(VXXXXXXX) +TEXT: H specifies the current flowing in the independent +TEXT: H voltage source named VXXXXXXX. Positive current +TEXT: H flows from the positive node, through the source, +TEXT: H to the negative node. For the ac analysis, the +TEXT: H corresponding replacements for the letter I may be +TEXT: H made in the same way as described for voltage out- +TEXT: H puts. +TEXT: H +TEXT: H +TEXT: H Output variables for the noise and distortion analyses +TEXT: H have a different general form from that of the other ana- +TEXT: H lyses. +TEXT: H +TEXT: H There is no limit on the number of .PRINT lines for +TEXT: H each type of analysis. +TEXT: H +TEXT: H + +SUBJECT: .PLOT Lines +TITLE: .PLOT Lines +TEXT: H +TEXT: H _4._4._3. ._P_L_O_T _L_i_n_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .PLOT PLTYPE OV1 <(PLO1, PHI1)> ... OV8> +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .PLOT DC V(4) V(5) V(1) +TEXT: H .PLOT TRAN V(17, 5) (2, 5) I(VIN) V(17) (1, 9) +TEXT: H .PLOT AC VM(5) VM(31, 24) VDB(5) VP(5) +TEXT: H .PLOT DISTO HD2 HD3(R) SIM2 +TEXT: H .PLOT TRAN V(5, 3) V(4) (0, 5) V(7) (0, 10) +TEXT: H +TEXT: H +TEXT: H The Plot line defines the contents of one plot of +TEXT: H from one to eight output variables. PLTYPE is the type +TEXT: H of analysis (DC, AC, TRAN, NOISE, or DISTO) for which +TEXT: H the specified outputs are desired. The syntax for the +TEXT: H OVI is identical to that for the .PRINT line and for the +TEXT: H plot command in the interactive mode. +TEXT: H +TEXT: H +TEXT: H The overlap of two or more traces on any plot is indi- +TEXT: H cated by the letter X. +TEXT: H +TEXT: H When more than one output variable appears on the same +TEXT: H plot, the first variable specified is printed as well as +TEXT: H plotted. If a printout of all variables is desired, then a +TEXT: H companion .PRINT line should be included. +TEXT: H +TEXT: H There is no limit on the number of .PLOT lines speci- +TEXT: H fied for each type of analysis. +TEXT: H +TEXT: H + +SUBJECT: .FOUR +TITLE: .FOUR: Fourier Analysis of Transient Analysis Output +TEXT: H +TEXT: H _4._4._4. ._F_O_U_R: _F_o_u_r_i_e_r _A_n_a_l_y_s_i_s _o_f _T_r_a_n_s_i_e_n_t _A_n_a_l_y_s_i_s _O_u_t- +TEXT: H _p_u_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _f_o_r_m: +TEXT: H +TEXT: H .FOUR FREQ OV1 +TEXT: H +TEXT: H +TEXT: H _E_x_a_m_p_l_e_s: +TEXT: H +TEXT: H .FOUR 100K V(5) +TEXT: H +TEXT: H +TEXT: H The Four (or Fourier) line controls whether SPICE +TEXT: H performs a Fourier analysis as a part of the transient +TEXT: H analysis. FREQ is the fundamental frequency, and OV1, +TEXT: H desired. The Fourier analysis is performed over the in- +TEXT: H terval , where TSTOP is the final +TEXT: H time specified for the transient analysis, and period is +TEXT: H one period of the fundamental frequency. The dc com- +TEXT: H ponent and the first nine harmonics are determined. For +TEXT: H maximum accuracy, TMAX (see the .TRAN line) should be +TEXT: H set to period/100.0 (or less for very high-Q circuits). +TEXT: H + +SUBJECT: INTERACTIVE INTERPRETER +TITLE: INTERACTIVE INTERPRETER +TEXT: H +TEXT: H _5. _I_N_T_E_R_A_C_T_I_V_E _I_N_T_E_R_P_R_E_T_E_R +TEXT: H +TEXT: H Spice3 consists of a simulator and a front-end for data +TEXT: H analysis and plotting. The front-end may be run as a +TEXT: H separate "stand-alone" program under the name Nutmeg. +TEXT: H +TEXT: H _N_u_t_m_e_g will read in the "raw" data output file created +TEXT: H by spice -r or with the write command in an interactive +TEXT: H Spice3 session. Nutmeg or interactive Spice3 can plot data +TEXT: H from a simulation on a graphics terminal or a workstation +TEXT: H display. Most of the commands available in the interactive +TEXT: H Spice3 front end are available in nutmeg; where this is not +TEXT: H the case, Spice-only commands have been marked with an +TEXT: H asterisk ("*"). Note that the raw output file is different +TEXT: H from the data that Spice2 writes to the standard output, +TEXT: H which may also be produced by spice3 with the "-b" command +TEXT: H line option. +TEXT: H +TEXT: H Spice and Nutmeg use the X Window System for plotting +TEXT: H if they find the environment variable DISPLAY. Otherwise, a +TEXT: H graphics-terminal independent interface (MFB) is used. If +TEXT: H you are using X on a workstation, the DISPLAY variable +TEXT: H should already be set; if you want to display graphics on a +TEXT: H system different from the one you are running Spice3 or Nut- +TEXT: H meg on, DISPLAY should be of the form "_m_a_c_h_i_n_e:0.0". See +TEXT: H the appropriate documentation on the X Window Sytem for more +TEXT: H details. +TEXT: H +TEXT: H +TEXT: H _C_o_m_m_a_n_d _S_y_n_o_p_s_i_s +TEXT: H +TEXT: H spice [ -n ] [ -t term ] [ -r rawfile] [ -b ] [ -i ] [ input file ... ] +TEXT: H +TEXT: H nutmeg [ - ] [ -n ] [ -t term ] [ datafile ... ] +TEXT: H +TEXT: H +TEXT: H +TEXT: H +TEXT: H Options are: +TEXT: H +TEXT: H - Don't try to load the default data file +TEXT: H ("rawspice.raw") if no other files are given. Nutmeg +TEXT: H only. +TEXT: H +TEXT: H -n (or -N) +TEXT: H Don't try to source the file ".spiceinit" upon startup. +TEXT: H Normally spice and nutmeg try to find the file in the +TEXT: H current directory, and if it is not found then in the +TEXT: H user's home directory. +TEXT: H +TEXT: H -t term (or -T term) +TEXT: H The program is being run on a terminal with _m_f_b name +TEXT: H term. +TEXT: H +TEXT: H -b (or -B) +TEXT: H Run in batch mode. Spice3 reads the default input +TEXT: H source (e.g. keyboard) or reads the given input file +TEXT: H and performs the analyses specified; output is either +TEXT: H Spice2-like line-printer plots ("ascii plots") or a +TEXT: H spice rawfile. See the following section for details. +TEXT: H Note that if the input source is not a terminal (e.g. +TEXT: H using the IO redirection notation of "<") Spice3 de- +TEXT: H faults to batch mode (-i overrides). This option is +TEXT: H valid for Spice3 only. +TEXT: H +TEXT: H +TEXT: H +TEXT: H -s (or -S) +TEXT: H Run in server mode. This is like batch mode, except +TEXT: H that a temporary rawfile is used and then written to +TEXT: H the standard output, preceded by a line with a single +TEXT: H "@", after the simulation is done. This mode is used +TEXT: H by the spice daemon. This option is valid for Spice3 +TEXT: H only. +TEXT: H +TEXT: H +TEXT: H +TEXT: H -i (or -I) +TEXT: H Run in interactive mode. This is useful if the stan- +TEXT: H dard input is not a terminal but interactive mode is +TEXT: H desired. Command completion is not available unless +TEXT: H the standard input is a terminal, however. This option +TEXT: H is valid for Spice3 only. +TEXT: H +TEXT: H +TEXT: H +TEXT: H -r _r_a_w_f_i_l_e (or -P _r_a_w_f_i_l_e) +TEXT: H Use _r_a_w_f_i_l_e as the default file into which the results +TEXT: H of the simulation are saved. This option is valid for +TEXT: H Spice3 only. +TEXT: H +TEXT: H +TEXT: H Further arguments to spice are taken to be Spice3 input +TEXT: H files, which are read and saved (if running in batch mode +TEXT: H then they are run immediately). Spice3 accepts most Spice2 +TEXT: H input file, and output ascii plots, fourier analyses, and +TEXT: H node printouts as specified in .plot, .four, and .print +TEXT: H cards. If an out parameter is given on a .width card, the +TEXT: H effect is the same as set width = .... Since Spice3 ascii +TEXT: H plots do not use multiple ranges, however, if vectors +TEXT: H together on a .plot card have different ranges they are not +TEXT: H provide as much information as they would in Spice2. The +TEXT: H output of Spice3 is also much less verbose than Spice2, in +TEXT: H that the only data printed is that requested by the above +TEXT: H cards. +TEXT: H +TEXT: H For nutmeg, further arguments are taken to be data +TEXT: H files in binary or ascii format (see sconvert(1)) which are +TEXT: H loaded into nutmeg. If the file is in binary format, it may +TEXT: H be only partially completed (useful for examining Spice2 +TEXT: H output before the simulation is finished). One file may +TEXT: H contain any number of data sets from different analyses. +SUBTOPIC: SPICE:EXPRESSIONS FUNCTIONS AND CONSTANTS +SUBTOPIC: SPICE:COMMAND INTERPRETATION +SUBTOPIC: SPICE:COMMANDS +SUBTOPIC: SPICE:CONTROL STRUCTURES +SUBTOPIC: SPICE:VARIABLES +SUBTOPIC: SPICE:MISCELLANEOUS +SUBTOPIC: SPICE:BUGS + +SUBJECT: EXPRESSIONS FUNCTIONS AND CONSTANTS +TITLE: EXPRESSIONS, FUNCTIONS, AND CONSTANTS +TEXT: H +TEXT: H _5._1. _E_X_P_R_E_S_S_I_O_N_S, _F_U_N_C_T_I_O_N_S, _A_N_D _C_O_N_S_T_A_N_T_S +TEXT: H +TEXT: H Spice and Nutmeg data is in the form of vectors: time, +TEXT: H voltage, etc. Each vector has a type, and vectors can be +TEXT: H operated on and combined algebraicly in ways consistent with +TEXT: H their types. Vectors are normally created when a data file +TEXT: H is read in (see the _l_o_a_d command below), and when the ini- +TEXT: H tial datafile is loaded. They can also be created with the +TEXT: H _l_e_t command. +TEXT: H +TEXT: H +TEXT: H An expression is an algebraic formula involving vectors +TEXT: H and scalars (a scalar is a vector of length 1) and the fol- +TEXT: H lowing operations: +TEXT: H +TEXT: H + - * / ^ % +TEXT: H +TEXT: H +TEXT: H % is the modulo operator, and the comma operator has two +TEXT: H meanings: if it is present in the argument list of a user- +TEXT: H definable function, it serves to separate the arguments. +TEXT: H Otherwise, the term x , y is synonymous with x + j(y). +TEXT: H +TEXT: H +TEXT: H +TEXT: H Also available are the logical operations & (and), | +TEXT: H (or), ! (not), and the relational operations <, >, >=, <=, +TEXT: H =, and <> (not equal). If used in an algebraic expression +TEXT: H they work like they would in C, producing values of 0 or 1. +TEXT: H The relational operators have the following synonyms: +TEXT: H +TEXT: H +TEXT: H gt > +TEXT: H lt < +TEXT: H ge >= +TEXT: H le <= +TEXT: H ne <> +TEXT: H eq = +TEXT: H and & +TEXT: H or | +TEXT: H not ! +TEXT: H +TEXT: H +TEXT: H These are useful when < and > might be confused with IO +TEXT: H redirection (which is almost always). +TEXT: H +TEXT: H +TEXT: H +TEXT: H The following functions are available: +TEXT: H +TEXT: H mag(vector) The magnitude of vector +TEXT: H ph(vector) The phase of vector +TEXT: H j(vector) _i (sqrt(-1)) times vector +TEXT: H real(vector) The real component of vector +TEXT: H imag(vector) The imaginary part of vector +TEXT: H db(vector) 20 log10(mag(vector)) +TEXT: H log(vector) The logarithm (base 10) of vector +TEXT: H ln(vector) The natural logarithm (base e) of vector +TEXT: H exp(vector) e to the vector power +TEXT: H abs(vector) The absolute value of vector. +TEXT: H sqrt(vector) The square root of vector. +TEXT: H sin(vector) The sine of vector. +TEXT: H cos(vector) The cosine of vector. +TEXT: H tan(vector) The tangent of vector. +TEXT: H atan(vector) The inverse tangent of vector. +TEXT: H norm(vector) The vector normalized to 1 (i.e, the +TEXT: H largest magnitude of any component is +TEXT: H 1). +TEXT: H rnd(vector) A vector with each component a random +TEXT: H integer between 0 and the absolute value +TEXT: H of the vectors's corresponding com- +TEXT: H ponent. +TEXT: H mean(vector) The result is a scalar (a length 1 vec- +TEXT: H tor) that is the mean of the elements of +TEXT: H vector. +TEXT: H vector(number) The result is a vector of length number, +TEXT: H with elements 0, 1, ... number - 1. If +TEXT: H number is a vector then just the first +TEXT: H element is taken, and if it isn't an in- +TEXT: H teger then the floor of the magnitude is +TEXT: H used. +TEXT: H length(vector) The length of vector. +TEXT: H interpolate(plot.vector) The result of interpolating the named +TEXT: H vector onto the scale of the current +TEXT: H plot. This function uses the variable +TEXT: H polydegree to determine the degree of +TEXT: H interpolation. +TEXT: H deriv(vector) Calculates the derivative of the given +TEXT: H vector. This uses numeric differentia- +TEXT: H tion by interpolating a polynomial and +TEXT: H may not produce satisfactory results +TEXT: H (particularly with iterated differentia- +TEXT: H tion). The implementation only cacu- +TEXT: H lates the dirivative with respect to the +TEXT: H real componant of that vector's scale. +TEXT: H +TEXT: H +TEXT: H A vector may be either the name of a vector already +TEXT: H defined or a floating-point number (a scalar). A number may +TEXT: H be written in any format acceptable to SPICE, such as +TEXT: H 14.6Meg or -1.231e-4. Note that you can either use scien- +TEXT: H tific notation or one of the abbreviations like _M_E_G or _G, +TEXT: H but not both. As with SPICE, a number may have trailing +TEXT: H alphabetic characters after it. +TEXT: H +TEXT: H The notation expr [num] denotes the num'th element of +TEXT: H expr. For multi-dimensional vectors, a vector of one less +TEXT: H dimension is returned. Also for multi-dimensional vectors, +TEXT: H the notation expr[m][n] will return the _nth element of the +TEXT: H mth subvector. To get a subrange of a vector, use the form +TEXT: H expr[lower, upper]. +TEXT: H +TEXT: H To reference vectors in a plot that is not the _c_u_r_r_e_n_t +TEXT: H _p_l_o_t (see the setplot command, below), the notation +TEXT: H plotname.vecname can be used. +TEXT: H +TEXT: H +TEXT: H Either a plotname or a vector name may be the wildcard +TEXT: H all. If the plotname is all, matching vectors from all +TEXT: H plots are specified, and if the vector name is all, all vec- +TEXT: H tors in the specified plots are referenced. Note that you +TEXT: H may not use binary operations on expressions involving wild- +TEXT: H cards - it is not obvious what all + all should denote, for +TEXT: H instance. Thus some (contrived) examples of expressions +TEXT: H are: +TEXT: H +TEXT: H cos(TIME) + db(v(3)) +TEXT: H sin(cos(log([1 2 3 4 5 6 7 8 9 10]))) +TEXT: H TIME * rnd(v(9)) - 15 * cos(vin#branch) ^ [7.9e5 8] +TEXT: H not ((ac3.FREQ[32] & tran1.TIME[10]) gt 3) +TEXT: H +TEXT: H +TEXT: H +TEXT: H Vector names in spice may have a name such as +TEXT: H @name[param], where name is either the name of a device +TEXT: H instance or model. This denotes the value of the param +TEXT: H parameter of the device or model. See Appendix B for +TEXT: H details of what parameters are available. The value is a +TEXT: H vector of length 1. This function is also available with +TEXT: H the show command, and is available with variables for con- +TEXT: H venience for command scripts. +TEXT: H +TEXT: H +TEXT: H There are a number of pre-defined constants in nutmeg. +TEXT: H They are: +TEXT: H +TEXT: H pi J (3.14159...) +TEXT: H e The base of natural logarithms (2.71828...) +TEXT: H c The speed of light (299,792,500 m/sec) +TEXT: H i The square root of -1 +TEXT: H o +TEXT: H kelvin Absolute 0 in Centigrade (-273.15 C) +TEXT: H echarge The charge on an electron (1.6021918e-19 C) +TEXT: H boltz Boltzman's constant (1.3806226e-23) +TEXT: H planck Planck's constant (h = 6.626200e-34) +TEXT: H +TEXT: H +TEXT: H These are all in MKS units. If you have another vari- +TEXT: H able with a name that conflicts with one of these then it +TEXT: H takes precedence. +TEXT: H + +SUBJECT: COMMAND INTERPRETATION +TITLE: COMMAND INTERPRETATION +TEXT: H +TEXT: H _5._2. _C_O_M_M_A_N_D _I_N_T_E_R_P_R_E_T_A_T_I_O_N +TEXT: H +TEXT: H If a word is typed as a command, and there is no +TEXT: H built-in command with that name, the directories in the +TEXT: H _s_o_u_r_c_e_p_a_t_h list are searched in order for the file. If it +TEXT: H is found, it is read in as a command file (as if it were +TEXT: H sourced). Before it is read, however, the variables _a_r_g_c +TEXT: H and _a_r_g_v are set to the number of words following the +TEXT: H filename on the command line, and a list of those words +TEXT: H respectively. After the file is finished, these variables +TEXT: H are unset. Note that if a command file calls another, it +TEXT: H must save its _a_r_g_v and _a_r_g_c since they are altered. Also, +TEXT: H command files may not be re-entrant since there are no local +TEXT: H variables. (Of course, the procedures may explicitly mani- +TEXT: H pulate a stack...) This way one can write scripts analogous +TEXT: H to shell scripts for nutmeg and Spice3. +TEXT: H +TEXT: H Note that for the script to work with Spice3, it must +TEXT: H begin with a blank line (or whatever else, since it is +TEXT: H thrown away) and then a line with .control on it. This is +TEXT: H an unfortunate result of the source command being used for +TEXT: H both circuit input and command file execution. Note also +TEXT: H that this allows the user to merely type the name of a cir- +TEXT: H cuit file as a command and it is automatically run. The +TEXT: H commands are executed immediately, without running any ana- +TEXT: H lyses that may be spicified in the circuit (to execute the +TEXT: H analyses before the script executes, include a "run" command +TEXT: H in the script). +TEXT: H +TEXT: H There are various command scripts installed in +TEXT: H /_u_s_r/_l_o_c_a_l/_l_i_b/_s_p_i_c_e/_s_c_r_i_p_t_s (or whatever the path is on +TEXT: H your machine), and the default _s_o_u_r_c_e_p_a_t_h includes this +TEXT: H directory, so you can use these command files (almost) like +TEXT: H builtin commands. + +SUBJECT: COMMANDS +TITLE: COMMANDS +TEXT: H +TEXT: H _5._3. _C_O_M_M_A_N_D_S +TEXT: H +TEXT: H +SUBTOPIC: SPICE:Ac +SUBTOPIC: SPICE:Alias +SUBTOPIC: SPICE:Alter +SUBTOPIC: SPICE:Asciiplot +SUBTOPIC: SPICE:Aspice +SUBTOPIC: SPICE:Bug +SUBTOPIC: SPICE:Cd +SUBTOPIC: SPICE:Destroy +SUBTOPIC: SPICE:Dc +SUBTOPIC: SPICE:Define +SUBTOPIC: SPICE:Delete +SUBTOPIC: SPICE:Diff +SUBTOPIC: SPICE:Display +SUBTOPIC: SPICE:Echo +SUBTOPIC: SPICE:Edit +SUBTOPIC: SPICE:Fourier +SUBTOPIC: SPICE:Hardcopy +SUBTOPIC: SPICE:Help +SUBTOPIC: SPICE:History +SUBTOPIC: SPICE:Iplot +SUBTOPIC: SPICE:Jobs +SUBTOPIC: SPICE:Let +SUBTOPIC: SPICE:Linearize +SUBTOPIC: SPICE:Listing +SUBTOPIC: SPICE:Load +SUBTOPIC: SPICE:Op +SUBTOPIC: SPICE:Plot +SUBTOPIC: SPICE:Print +SUBTOPIC: SPICE:Quit +SUBTOPIC: SPICE:Rehash +SUBTOPIC: SPICE:Reset +SUBTOPIC: SPICE:Reshape +SUBTOPIC: SPICE:Resume +SUBTOPIC: SPICE:Rspice +SUBTOPIC: SPICE:Run +SUBTOPIC: SPICE:Rusage +SUBTOPIC: SPICE:Save +SUBTOPIC: SPICE:Sens +SUBTOPIC: SPICE:Set +SUBTOPIC: SPICE:Setcirc +SUBTOPIC: SPICE:Setplot +SUBTOPIC: SPICE:Settype +SUBTOPIC: SPICE:Shell +SUBTOPIC: SPICE:Shift +SUBTOPIC: SPICE:Show +SUBTOPIC: SPICE:Showmod +SUBTOPIC: SPICE:Source +SUBTOPIC: SPICE:Status +SUBTOPIC: SPICE:Step +SUBTOPIC: SPICE:Stop +SUBTOPIC: SPICE:Tf +SUBTOPIC: SPICE:Trace +SUBTOPIC: SPICE:Tran +SUBTOPIC: SPICE:Transpose +SUBTOPIC: SPICE:Unalias +SUBTOPIC: SPICE:Undefine +SUBTOPIC: SPICE:Unset +SUBTOPIC: SPICE:Version +SUBTOPIC: SPICE:Where +SUBTOPIC: SPICE:Write +SUBTOPIC: SPICE:Xgraph + +SUBJECT: Ac +TITLE: Ac*: Perform an AC, small-signal frequency response analysis +TEXT: H +TEXT: H _5._3._1. _A_c*: _P_e_r_f_o_r_m _a_n _A_C, _s_m_a_l_l-_s_i_g_n_a_l _f_r_e_q_u_e_n_c_y _r_e_s_p_o_n_s_e +TEXT: H _a_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H ac ( DEC | OCT | LIN ) _N _F_s_t_a_r_t _F_s_t_o_p +TEXT: H +TEXT: H +TEXT: H Do an ac analysis. See the previous sections of +TEXT: H this manual for more details. +TEXT: H +TEXT: H + +SUBJECT: Alias +TITLE: Alias: Create an alias for a command +TEXT: H +TEXT: H _5._3._2. _A_l_i_a_s: _C_r_e_a_t_e _a_n _a_l_i_a_s _f_o_r _a _c_o_m_m_a_n_d +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H alias [word] [text ...] +TEXT: H +TEXT: H +TEXT: H Causes word to be aliased to text. History substi- +TEXT: H tutions may be used, as in C-shell aliases. +TEXT: H +TEXT: H + +SUBJECT: Alter +TITLE: Alter*: Change a device or model parameter +TEXT: H +TEXT: H _5._3._3. _A_l_t_e_r*: _C_h_a_n_g_e _a _d_e_v_i_c_e _o_r _m_o_d_e_l _p_a_r_a_m_e_t_e_r +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H alter _d_e_v_i_c_e _v_a_l_u_e +TEXT: H alter _d_e_v_i_c_e _p_a_r_a_m_e_t_e_r _v_a_l_u_e [ _p_a_r_a_m_e_t_e_r _v_a_l_u_e ] +TEXT: H +TEXT: H +TEXT: H Alter changes the value for a device or a specified +TEXT: H parameter of a device or model. The first form is used +TEXT: H by simple devices which have one principal value (resis- +TEXT: H tors, capacitors, etc.) where the second form is for +TEXT: H more complex devices (bjt's, etc.). Model parameters +TEXT: H can be changed with the second form if the name contains +TEXT: H a "#". +TEXT: H +TEXT: H For specifying vectors as values, start the vector +TEXT: H with "[", followed by the values in the vector, and end +TEXT: H with "]". Be sure to place a space between each of the +TEXT: H values and before and after the "[" and "]". +TEXT: H +TEXT: H + +SUBJECT: Asciiplot +TITLE: Asciiplot: Plot values using old-style character plots +TEXT: H +TEXT: H _5._3._4. _A_s_c_i_i_p_l_o_t: _P_l_o_t _v_a_l_u_e_s _u_s_i_n_g _o_l_d-_s_t_y_l_e _c_h_a_r_a_c_t_e_r +TEXT: H _p_l_o_t_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H asciiplot _p_l_o_t_a_r_g_s +TEXT: H +TEXT: H +TEXT: H Produce a line printer plot of the vectors. The +TEXT: H plot is sent to the standard output, so you can put it +TEXT: H into a file with _a_s_c_i_i_p_l_o_t _a_r_g_s ... > _f_i_l_e. The set op- +TEXT: H tions width, height, and nobreak determine the width and +TEXT: H height of the plot, and whether there are page breaks, +TEXT: H respectively. Note that you will have problems if you +TEXT: H try to asciiplot something with an X-scale that isn't +TEXT: H monotonic (i.e, something like _s_i_n(_T_I_M_E) ), because as- +TEXT: H ciiplot uses a simple-minded linear interpolation. +TEXT: H +TEXT: H + +SUBJECT: Aspice +TITLE: Aspice: Asynchronous spice run +TEXT: H +TEXT: H _5._3._5. _A_s_p_i_c_e: _A_s_y_n_c_h_r_o_n_o_u_s _s_p_i_c_e _r_u_n +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H aspice input-file [output-file] +TEXT: H +TEXT: H +TEXT: H Start a SPICE-3 run, and when it is finished load +TEXT: H the resulting data. The raw data is kept in a temporary +TEXT: H file. If _o_u_t_p_u_t-_f_i_l_e is specified then the diagnostic +TEXT: H output is directed into that file, otherwise it is +TEXT: H thrown away. +TEXT: H +TEXT: H + +SUBJECT: Bug +TITLE: Bug: Mail a bug report +TEXT: H +TEXT: H _5._3._6. _B_u_g: _M_a_i_l _a _b_u_g _r_e_p_o_r_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H bug +TEXT: H +TEXT: H +TEXT: H Send a bug report. Please include a short summary +TEXT: H of the problem, the version number and name of the +TEXT: H operating system that you are running, the version of +TEXT: H Spice that you are running, and the relevant spice input +TEXT: H file. (If you have defined BUGADDR, the mail is +TEXT: H delivered to there.) +TEXT: H +TEXT: H + +SUBJECT: Cd +TITLE: Cd: Change directory +TEXT: H +TEXT: H _5._3._7. _C_d: _C_h_a_n_g_e _d_i_r_e_c_t_o_r_y +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H cd [directory] +TEXT: H +TEXT: H +TEXT: H Change the current working directory to directory, +TEXT: H or to the user's home directory if none is given. +TEXT: H +TEXT: H + +SUBJECT: Destroy +TITLE: Destroy: Delete a data set +TEXT: H +TEXT: H _5._3._8. _D_e_s_t_r_o_y: _D_e_l_e_t_e _a _d_a_t_a _s_e_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H destroy [_p_l_o_t_n_a_m_e_s | all] +TEXT: H +TEXT: H +TEXT: H Release the memory holding the data for the speci- +TEXT: H fied runs. +TEXT: H +TEXT: H + +SUBJECT: Dc +TITLE: Dc*: Perform a DC-sweep analysis +TEXT: H +TEXT: H _5._3._9. _D_c*: _P_e_r_f_o_r_m _a _D_C-_s_w_e_e_p _a_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H dc _S_o_u_r_c_e-_N_a_m_e _V_s_t_a_r_t _V_s_t_o_p _V_i_n_c_r [ _S_o_u_r_c_e_2 _V_s_t_a_r_t_2 _V_s_t_o_p_2 _V_i_n_c_r_2 ] +TEXT: H +TEXT: H +TEXT: H Do a dc transfer curve analysis. See the previous +TEXT: H sections of this manual for more details. +TEXT: H +TEXT: H + +SUBJECT: Define +TITLE: Define: Define a function +TEXT: H +TEXT: H _5._3._1_0. _D_e_f_i_n_e: _D_e_f_i_n_e _a _f_u_n_c_t_i_o_n +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H define function(arg1, arg2, ...) expression +TEXT: H +TEXT: H +TEXT: H Define the _u_s_e_r-_d_e_f_i_n_a_b_l_e _f_u_n_c_t_i_o_n with the name +TEXT: H _f_u_n_c_t_i_o_n and arguments _a_r_g_1, _a_r_g_2, ... to be _e_x_p_r_e_s_s_i_o_n, +TEXT: H which may involve the arguments. When the function is +TEXT: H later used, the arguments it is given are substituted +TEXT: H for the formal arguments when it is parsed. If _e_x_p_r_e_s- +TEXT: H _s_i_o_n is not present, any definition for _f_u_n_c_t_i_o_n is +TEXT: H printed, and if there are no arguments to _d_e_f_i_n_e then +TEXT: H all currently active definitions are printed. Note that +TEXT: H you may have different functions defined with the same +TEXT: H name but different arities. +TEXT: H +TEXT: H +TEXT: H +TEXT: H Some useful definitions are: +TEXT: H +TEXT: H define max(x,y) (x > y) * x + (x <= y) * y +TEXT: H define min(x,y) (x < y) * x + (x >= y) * y +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Delete +TITLE: Delete*: Remove a trace or breakpoint +TEXT: H +TEXT: H _5._3._1_1. _D_e_l_e_t_e*: _R_e_m_o_v_e _a _t_r_a_c_e _o_r _b_r_e_a_k_p_o_i_n_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H delete [ _d_e_b_u_g-_n_u_m_b_e_r ... ] +TEXT: H +TEXT: H +TEXT: H Delete the specified breakpoints and traces. The +TEXT: H debug numbers are those shown by the status command (un- +TEXT: H less you do status > file, in which case the debug +TEXT: H numbers are not printed). +TEXT: H +TEXT: H + +SUBJECT: Diff +TITLE: Diff: Compare vectors +TEXT: H +TEXT: H _5._3._1_2. _D_i_f_f: _C_o_m_p_a_r_e _v_e_c_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H diff plot1 plot2 [vec ...] +TEXT: H +TEXT: H +TEXT: H Compare all the vectors in the specified _p_l_o_t_s, or +TEXT: H only the named vectors if any are given. There are dif- +TEXT: H ferent vectors in the two plots, or any values in the +TEXT: H vectors differ significantly the difference is reported. +TEXT: H The variable diff_abstol, diff_reltol, and diff_vntol +TEXT: H are used to determine a significant difference. +TEXT: H +TEXT: H + +SUBJECT: Display +TITLE: Display: List known vectors and types +TEXT: H +TEXT: H _5._3._1_3. _D_i_s_p_l_a_y: _L_i_s_t _k_n_o_w_n _v_e_c_t_o_r_s _a_n_d _t_y_p_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H display [varname ...] +TEXT: H +TEXT: H +TEXT: H Prints a summary of currently defined vectors, or +TEXT: H of the names specified. The vectors are sorted by name +TEXT: H unless the variable nosort is set. The information +TEXT: H given is the name of the vector, the length, the type of +TEXT: H the vector, and whether it is real or complex data. Ad- +TEXT: H ditionally, one vector is labeled [scale]. When a com- +TEXT: H mand such as _p_l_o_t is given without a _v_s argument, this +TEXT: H scale is used for the X-axis. It is always the first +TEXT: H vector in a rawfile, or the first vector defined in a +TEXT: H new plot. If you undefine the scale (i.e, _l_e_t _T_I_M_E = +TEXT: H []), one of the remaining vectors becomes the new scale +TEXT: H (which is undetermined). +TEXT: H +TEXT: H + +SUBJECT: Echo +TITLE: Echo: Print text +TEXT: H +TEXT: H _5._3._1_4. _E_c_h_o: _P_r_i_n_t _t_e_x_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H echo [text...] +TEXT: H +TEXT: H +TEXT: H Echos the given text to the screen. +TEXT: H +TEXT: H + +SUBJECT: Edit +TITLE: Edit*: Edit the current circuit +TEXT: H +TEXT: H _5._3._1_5. _E_d_i_t*: _E_d_i_t _t_h_e _c_u_r_r_e_n_t _c_i_r_c_u_i_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H edit [ _f_i_l_e ] +TEXT: H +TEXT: H +TEXT: H Print the current Spice3 input file into a file, +TEXT: H call up the editor on that file and allow the user to +TEXT: H modify it, and then read it back in, replacing the ori- +TEXT: H ginal file. If a _f_i_l_e_n_a_m_e is given, then edit that file +TEXT: H and load it, making the circuit the current one. +TEXT: H +TEXT: H + +SUBJECT: Fourier +TITLE: Fourier: Perform a fourier transform +TEXT: H +TEXT: H _5._3._1_6. _F_o_u_r_i_e_r: _P_e_r_f_o_r_m _a _f_o_u_r_i_e_r _t_r_a_n_s_f_o_r_m +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H fourier fundamental_frequency [value ...] +TEXT: H +TEXT: H +TEXT: H Does a fourier analysis of each of the given +TEXT: H values, using the first 10 multiples of the fundamental +TEXT: H frequency (or the first _n_f_r_e_q_s, if that variable is set +TEXT: H - see below). The output is like that of the .four +TEXT: H Spice3 line. The values may be any valid expression. +TEXT: H The values are interpolated onto a fixed-space grid with +TEXT: H the number of points given by the fourgridsize variable, +TEXT: H or 200 if it is not set. The interpolation is of degree +TEXT: H polydegree if that variable is set, or 1. If polydegree +TEXT: H is 0, then no interpolation is done. This is likely to +TEXT: H give erroneous results if the time scale is not monoton- +TEXT: H ic, though. +TEXT: H +TEXT: H + +SUBJECT: Hardcopy +TITLE: Hardcopy: Save a plot to a file for printing +TEXT: H +TEXT: H _5._3._1_7. _H_a_r_d_c_o_p_y: _S_a_v_e _a _p_l_o_t _t_o _a _f_i_l_e _f_o_r _p_r_i_n_t_i_n_g +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H hardcopy file _p_l_o_t_a_r_g_s +TEXT: H +TEXT: H +TEXT: H Just like plot, except creates a file called _f_i_l_e +TEXT: H containing the plot. The file is an image in _p_l_o_t(_5) +TEXT: H format, and can be printed by either the plot(1) program +TEXT: H or lpr with the -g flag. +TEXT: H +TEXT: H + +SUBJECT: Help +TITLE: Help: Print summaries of Spice3 commands +TEXT: H +TEXT: H _5._3._1_8. _H_e_l_p: _P_r_i_n_t _s_u_m_m_a_r_i_e_s _o_f _S_p_i_c_e_3 _c_o_m_m_a_n_d_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H help [all] [command ...] +TEXT: H +TEXT: H +TEXT: H Prints help. If the argument all is given, a short +TEXT: H description of everything you could possibly type is +TEXT: H printed. If commands are given, descriptions of those +TEXT: H commands are printed. Otherwise help for only a few ma- +TEXT: H jor commands is printed. +TEXT: H +TEXT: H + +SUBJECT: History +TITLE: History: Review previous commands +TEXT: H +TEXT: H _5._3._1_9. _H_i_s_t_o_r_y: _R_e_v_i_e_w _p_r_e_v_i_o_u_s _c_o_m_m_a_n_d_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H history [number] +TEXT: H +TEXT: H +TEXT: H Print out the history, or the last number commands +TEXT: H typed at the keyboard. _N_o_t_e: in Spice3 version 3a7 and +TEXT: H earlier, all commands (including ones read from files) +TEXT: H were saved. +TEXT: H +TEXT: H + +SUBJECT: Iplot +TITLE: Iplot*: Incremental plot +TEXT: H +TEXT: H _5._3._2_0. _I_p_l_o_t*: _I_n_c_r_e_m_e_n_t_a_l _p_l_o_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H iplot [ node ...] +TEXT: H +TEXT: H +TEXT: H Incrementally plot the values of the nodes while +TEXT: H Spice3 runs. The iplot command can be used with the +TEXT: H where command to find trouble spots in a transient simu- +TEXT: H lation. +TEXT: H +TEXT: H + +SUBJECT: Jobs +TITLE: Jobs: List active asynchronous spice runs +TEXT: H +TEXT: H _5._3._2_1. _J_o_b_s: _L_i_s_t _a_c_t_i_v_e _a_s_y_n_c_h_r_o_n_o_u_s _s_p_i_c_e _r_u_n_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H jobs +TEXT: H +TEXT: H +TEXT: H Report on the asynchronous SPICE-3 jobs currently +TEXT: H running. Nutmeg checks to see if the jobs are finished +TEXT: H every time you execute a command. If it is done then +TEXT: H the data is loaded and becomes available. +TEXT: H +TEXT: H + +SUBJECT: Let +TITLE: Let: Assign a value to a vector +TEXT: H +TEXT: H _5._3._2_2. _L_e_t: _A_s_s_i_g_n _a _v_a_l_u_e _t_o _a _v_e_c_t_o_r +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H let name = expr +TEXT: H +TEXT: H +TEXT: H Creates a new vector called _n_a_m_e with the value +TEXT: H specified by _e_x_p_r, an expression as described above. If +TEXT: H expr is [] (a zero-length vector) then the vector be- +TEXT: H comes undefined. Individual elements of a vector may be +TEXT: H modified by appending a subscript to name (ex. name[0]). +TEXT: H If there are no arguments, let is the same as display. +TEXT: H +TEXT: H + +SUBJECT: Linearize +TITLE: Linearize*: Interpolate to a linear scale +TEXT: H +TEXT: H _5._3._2_3. _L_i_n_e_a_r_i_z_e*: _I_n_t_e_r_p_o_l_a_t_e _t_o _a _l_i_n_e_a_r _s_c_a_l_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H linearize vec ... +TEXT: H +TEXT: H +TEXT: H Create a new plot with all of the vectors in the +TEXT: H current plot, or only those mentioned if arguments are +TEXT: H given. The new vectors are interpolated onto a linear +TEXT: H time scale, which is determined by the values of tstep, +TEXT: H tstart, and tstop in the currently active transient +TEXT: H analysis. The currently loaded input file must include +TEXT: H a transient analysis (a tran command may be run interac- +TEXT: H tively before the last reset, alternately), and the +TEXT: H current plot must be from this transient analysis. This +TEXT: H command is needed because Spice3 doesn't output the +TEXT: H results from a transient analysis in the same manner +TEXT: H that Spice2 did. +TEXT: H +TEXT: H + +SUBJECT: Listing +TITLE: Listing*: Print a listing of the current circuit +TEXT: H +TEXT: H _5._3._2_4. _L_i_s_t_i_n_g*: _P_r_i_n_t _a _l_i_s_t_i_n_g _o_f _t_h_e _c_u_r_r_e_n_t _c_i_r_c_u_i_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H listing [logical] [physical] [deck] [expand] +TEXT: H +TEXT: H +TEXT: H If the logical argument is given, the listing is +TEXT: H with all continuation lines collapsed into one line, and +TEXT: H if the physical argument is given the lines are printed +TEXT: H out as they were found in the file. The default is log- +TEXT: H ical. A deck listing is just like the physical listing, +TEXT: H except without the line numbers it recreates the input +TEXT: H file verbatim (except that it does not preserve case). +TEXT: H If the word expand is present, the circuit is printed +TEXT: H with all subcircuits expanded. +TEXT: H +TEXT: H + +SUBJECT: Load +TITLE: Load: Load rawfile data +TEXT: H +TEXT: H _5._3._2_5. _L_o_a_d: _L_o_a_d _r_a_w_f_i_l_e _d_a_t_a +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H load [filename] ... +TEXT: H +TEXT: H +TEXT: H Loads either binary or ascii format rawfile data +TEXT: H from the files named. The default filename is +TEXT: H rawspice.raw, or the argument to the -r flag if there +TEXT: H was one. +TEXT: H +TEXT: H + +SUBJECT: Op +TITLE: Op*: Perform an operating point analysis +TEXT: H +TEXT: H _5._3._2_6. _O_p*: _P_e_r_f_o_r_m _a_n _o_p_e_r_a_t_i_n_g _p_o_i_n_t _a_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H op +TEXT: H +TEXT: H +TEXT: H Do an operating point analysis. See the previous +TEXT: H sections of this manual for more details. +TEXT: H +TEXT: H + +SUBJECT: Plot +TITLE: Plot: Plot values on the display +TEXT: H +TEXT: H _5._3._2_7. _P_l_o_t: _P_l_o_t _v_a_l_u_e_s _o_n _t_h_e _d_i_s_p_l_a_y +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H plot exprs [ylimit ylo yhi] [xlimit xlo xhi] [xindices xilo xihi] +TEXT: H [xcompress comp] [xdelta xdel] [ydelta ydel] [xlog] [ylog] [loglog] +TEXT: H [vs xname] [xlabel word] [ylabel word] [title word] [samep] +TEXT: H [linear] +TEXT: H +TEXT: H +TEXT: H +TEXT: H Plot the given _e_x_p_r_s on the screen (if you are on a +TEXT: H graphics terminal). The _x_l_i_m_i_t and _y_l_i_m_i_t arguments deter- +TEXT: H mine the high and low x- and y-limits of the axes, respec- +TEXT: H tively. The _x_i_n_d_i_c_e_s arguments determine what range of +TEXT: H points are to be plotted - everything between the xilo'th +TEXT: H point and the xihi'th point is plotted. The _x_c_o_m_p_r_e_s_s argu- +TEXT: H ment specifies that only one out of every comp points should +TEXT: H be plotted. If an xdelta or a ydelta parameter is present, +TEXT: H it specifies the spacing between grid lines on the X- and +TEXT: H Y-axis. These parameter names may be abbreviated to _x_l, _y_l, +TEXT: H _x_i_n_d, _x_c_o_m_p, _x_d_e_l, and _y_d_e_l respectively. +TEXT: H +TEXT: H The _x_n_a_m_e argument is an expression to use as the scale +TEXT: H on the x-axis. If xlog or ylog are present then the X or Y +TEXT: H scale, respectively, is logarithmic (loglog is the same as +TEXT: H specifying both). The xlabel and ylabel arguments cause the +TEXT: H specified labels to be used for the X and Y axes, respec- +TEXT: H tively. +TEXT: H +TEXT: H If samep is given, the values of the other parameters +TEXT: H (other than xname) from the previous plot, hardcopy, or +TEXT: H asciiplot command is used unless re-defined on the command +TEXT: H line. +TEXT: H +TEXT: H The title argument is used in the place of the plot +TEXT: H name at the bottom of the graph. +TEXT: H +TEXT: H The linear keyword is used to override a default log- +TEXT: H scale plot (as in the output for an AC analysis). +TEXT: H +TEXT: H Finally, the keyword polar to generate a polar plot. +TEXT: H To produce a smith plot, use the keyword smith. Note that +TEXT: H the data is transformed, so for smith plots you will see the +TEXT: H data transformed by the function (x-1)/(x+1). To produce a +TEXT: H polar plot with a smith grid but without performing the +TEXT: H smith transform, use the keyword smithgrid. +TEXT: H + +SUBJECT: Print +TITLE: Print: Print values +TEXT: H +TEXT: H _5._3._2_8. _P_r_i_n_t: _P_r_i_n_t _v_a_l_u_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H print [col] [line] expr ... +TEXT: H +TEXT: H +TEXT: H Prints the vector described by the expression _e_x_p_r. +TEXT: H If the _c_o_l argument is present, print the vectors named +TEXT: H side by side. If line is given, the vectors are printed +TEXT: H horizontally. col is the default, unless all the vec- +TEXT: H tors named have a length of one, in which case line is +TEXT: H the default. The options width, length, and nobreak are +TEXT: H effective for this command (see asciiplot). If the ex- +TEXT: H pression is all, all of the vectors available are print- +TEXT: H ed. Thus print col all > file prints everything in the +TEXT: H file in SPICE2 format. The scale vector (time, frequen- +TEXT: H cy) is always in the first column unless the variable +TEXT: H noprintscale is true. +TEXT: H +TEXT: H + +SUBJECT: Quit +TITLE: Quit: Leave Spice3 or Nutmeg +TEXT: H +TEXT: H _5._3._2_9. _Q_u_i_t: _L_e_a_v_e _S_p_i_c_e_3 _o_r _N_u_t_m_e_g +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H quit +TEXT: H +TEXT: H +TEXT: H Quit nutmeg or spice. +TEXT: H +TEXT: H + +SUBJECT: Rehash +TITLE: Rehash: Reset internal hash tables +TEXT: H +TEXT: H _5._3._3_0. _R_e_h_a_s_h: _R_e_s_e_t _i_n_t_e_r_n_a_l _h_a_s_h _t_a_b_l_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H rehash +TEXT: H +TEXT: H +TEXT: H Recalculate the internal hash tables used when +TEXT: H looking up UNIX commands, and make all UNIX commands in +TEXT: H the user's PATH available for command completion. This +TEXT: H is useless unless you have set unixcom first (see +TEXT: H above). +TEXT: H +TEXT: H + +SUBJECT: Reset +TITLE: Reset*: Reset an analysis +TEXT: H +TEXT: H _5._3._3_1. _R_e_s_e_t*: _R_e_s_e_t _a_n _a_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H reset +TEXT: H +TEXT: H +TEXT: H Throw out any intermediate data in the circuit +TEXT: H (e.g, after a breakpoint or after one or more analyses +TEXT: H have been done already), and re-parse the input file. +TEXT: H The circuit can then be re-run from it's initial state, +TEXT: H overriding the affect of any set or alter commands. In +TEXT: H Spice-3e and earlier versions this was done automatical- +TEXT: H ly by the run command. +TEXT: H +TEXT: H + +SUBJECT: Reshape +TITLE: Reshape: Alter the dimensionality or dimensions of a vector +TEXT: H +TEXT: H _5._3._3_2. _R_e_s_h_a_p_e: _A_l_t_e_r _t_h_e _d_i_m_e_n_s_i_o_n_a_l_i_t_y _o_r _d_i_m_e_n_s_i_o_n_s _o_f +TEXT: H _a _v_e_c_t_o_r +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H reshape _v_e_c_t_o_r _v_e_c_t_o_r ... +TEXT: H or +TEXT: H reshape _v_e_c_t_o_r _v_e_c_t_o_r ... [ _d_i_m_e_n_s_i_o_n, _d_i_m_e_n_s_i_o_n, ... ] +TEXT: H or +TEXT: H reshape _v_e_c_t_o_r _v_e_c_t_o_r ... [ _d_i_m_e_n_s_i_o_n ][ _d_i_m_e_n_s_i_o_n ] ... +TEXT: H +TEXT: H +TEXT: H This command changes the dimensions of a vector or +TEXT: H a set of vectors. The final dimension may be left off +TEXT: H and it will be filled in automatically. If no dimen- +TEXT: H sions are specified, then the dimensions of the first +TEXT: H vector are copied to the other vectors. An error mes- +TEXT: H sage of the form 'dimensions of _x were inconsistent' can +TEXT: H be ignored. +TEXT: H +TEXT: H + +SUBJECT: Resume +TITLE: Resume*: Continue a simulation after a stop +TEXT: H +TEXT: H _5._3._3_3. _R_e_s_u_m_e*: _C_o_n_t_i_n_u_e _a _s_i_m_u_l_a_t_i_o_n _a_f_t_e_r _a _s_t_o_p +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H resume +TEXT: H +TEXT: H +TEXT: H Resume a simulation after a stop or interruption +TEXT: H (control-C). +TEXT: H +TEXT: H + +SUBJECT: Rspice +TITLE: Rspice: Remote spice submission +TEXT: H +TEXT: H _5._3._3_4. _R_s_p_i_c_e: _R_e_m_o_t_e _s_p_i_c_e _s_u_b_m_i_s_s_i_o_n +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H rspice _i_n_p_u_t _f_i_l_e +TEXT: H +TEXT: H +TEXT: H Runs a SPICE-3 remotely taking the input file as a +TEXT: H SPICE-3 input file, or the current circuit if no argu- +TEXT: H ment is given. Nutmeg or Spice3 waits for the job to +TEXT: H complete, and passes output from the remote job to the +TEXT: H user's standard output. When the job is finished the +TEXT: H data is loaded in as with aspice. If the variable _r_h_o_s_t +TEXT: H is set, nutmeg connects to this host instead of the de- +TEXT: H fault remote Spice3 server machine. This command uses +TEXT: H the "rsh" command and thereby requires authentication +TEXT: H via a ".rhosts" file or other equivalent method. Note +TEXT: H that "rsh" refers to the "remote shell" program, which +TEXT: H may be "remsh" on your system; to override the default +TEXT: H name of "rsh", set the variable _r_e_m_o_t_e__s_h_e_l_l. If the +TEXT: H variable _r_p_r_o_g_r_a_m is set, then rspice uses this as the +TEXT: H pathname to the program to run on the remote system. +TEXT: H +TEXT: H Note: rspice will not acknowledge elements that +TEXT: H have been changed via the "alter" or "altermod" com- +TEXT: H mands. +TEXT: H +TEXT: H + +SUBJECT: Run +TITLE: Run*: Run analysis from the input file +TEXT: H +TEXT: H _5._3._3_5. _R_u_n*: _R_u_n _a_n_a_l_y_s_i_s _f_r_o_m _t_h_e _i_n_p_u_t _f_i_l_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H run [rawfile] +TEXT: H +TEXT: H +TEXT: H Run the simulation as specified in the input file. +TEXT: H If there were any of the control lines .ac, .op, .tran, +TEXT: H or .dc, they are executed. The output is put in rawfile +TEXT: H if it was given, in addition to being available interac- +TEXT: H tively. In Spice-3e and earlier versions, the input +TEXT: H file would be re-read and any affects of the set or +TEXT: H alter commands would be reversed. This is no longer the +TEXT: H affect. +TEXT: H +TEXT: H + +SUBJECT: Rusage +TITLE: Rusage: Resource usage +TEXT: H +TEXT: H _5._3._3_6. _R_u_s_a_g_e: _R_e_s_o_u_r_c_e _u_s_a_g_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H rusage [resource ...] +TEXT: H +TEXT: H +TEXT: H Print resource usage statistics. If any resources +TEXT: H are given, just print the usage of that resource. Most +TEXT: H resources require that a circuit be loaded. Currently +TEXT: H valid resources are: +TEXT: H +TEXT: H elapsed The amount of time elapsed since the last rusage +TEXT: H elaped call. +TEXT: H faults Number of page faults and context switches (BSD only). +TEXT: H space Data space used. +TEXT: H time CPU time used so far. +TEXT: H +TEXT: H temp Operating temperature. +TEXT: H tnom Temperature at which device parameters were measured. +TEXT: H equations Circuit Equations +TEXT: H +TEXT: H time Total Analysis Time +TEXT: H totiter Total iterations +TEXT: H accept Accepted timepoints +TEXT: H rejected Rejected timepoints +TEXT: H +TEXT: H loadtime Time spent loading the circuit matrix and RHS. +TEXT: H reordertime Matrix reordering time +TEXT: H lutime L-U decomposition time +TEXT: H solvetime Matrix solve time +TEXT: H +TEXT: H trantime Transient analysis time +TEXT: H tranpoints Transient timepoints +TEXT: H traniter Transient iterations +TEXT: H trancuriters Transient iterations for the last time point* +TEXT: H tranlutime Transient L-U decomposition time +TEXT: H transolvetime Transient matrix solve time +TEXT: H +TEXT: H everything All of the above. +TEXT: H +TEXT: H * listed incorrectly as "Transient iterations per point". +TEXT: H +TEXT: H + +SUBJECT: Save +TITLE: Save*: Save a set of outputs +TEXT: H +TEXT: H _5._3._3_7. _S_a_v_e*: _S_a_v_e _a _s_e_t _o_f _o_u_t_p_u_t_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H save [all | _o_u_t_p_u_t ...] +TEXT: H .save [all | _o_u_t_p_u_t ...] +TEXT: H +TEXT: H +TEXT: H Save a set of outputs, discarding the rest. If a +TEXT: H node has been mentioned in a save command, it appears in +TEXT: H the working plot after a run has completed, or in the +TEXT: H rawfile if spice is run in batch mode. If a node is +TEXT: H traced or plotted (see below) it is also saved. For +TEXT: H backward compatibility, if there are no save commands +TEXT: H given, all outputs are saved. +TEXT: H +TEXT: H When the keyword "all" appears in the save command, +TEXT: H all default values (node voltages and voltage source +TEXT: H currents) are saved in addition to any other values +TEXT: H listed. +TEXT: H +TEXT: H + +SUBJECT: Sens +TITLE: Sens*: Run a sensitivity analysis +TEXT: H +TEXT: H _5._3._3_8. _S_e_n_s*: _R_u_n _a _s_e_n_s_i_t_i_v_i_t_y _a_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H sens _o_u_t_p_u_t__v_a_r_i_a_b_l_e +TEXT: H sens _o_u_t_p_u_t__v_a_r_i_a_b_l_e ac ( DEC | OCT | LIN ) _N _F_s_t_a_r_t _F_s_t_o_p +TEXT: H +TEXT: H +TEXT: H Perform a Sensitivity analysis. _o_u_t_p_u_t__v_a_r_i_a_b_l_e is +TEXT: H either a node voltage (ex. "v(1)" or "v(A,out)") or a +TEXT: H current through a voltage source (ex. "i(vtest)"). The +TEXT: H first form calculates DC sensitivities, the second form +TEXT: H calculates AC sensitivies. The output values are in di- +TEXT: H mensions of change in output per unit change of input +TEXT: H (as opposed to percent change in output or per percent +TEXT: H change of input). +TEXT: H +TEXT: H + +SUBJECT: Set +TITLE: Set: Set the value of a variable +TEXT: H +TEXT: H _5._3._3_9. _S_e_t: _S_e_t _t_h_e _v_a_l_u_e _o_f _a _v_a_r_i_a_b_l_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H set [word] +TEXT: H set [word = value] ... +TEXT: H +TEXT: H +TEXT: H Set the value of word to be value, if it is +TEXT: H present. You can set any word to be any value, numeric +TEXT: H or string. If no value is given then the value is the +TEXT: H boolean 'true'. +TEXT: H +TEXT: H +TEXT: H The value of _w_o_r_d may be inserted into a command by +TEXT: H writing $_w_o_r_d. If a variable is set to a list of values +TEXT: H that are enclosed in parentheses (which must be separated +TEXT: H from their values by white space), the value of the variable +TEXT: H is the list. +TEXT: H +TEXT: H The variables used by nutmeg are listed in the follow- +TEXT: H ing section. +TEXT: H + +SUBJECT: Setcirc +TITLE: Setcirc*: Change the current circuit +TEXT: H +TEXT: H _5._3._4_0. _S_e_t_c_i_r_c*: _C_h_a_n_g_e _t_h_e _c_u_r_r_e_n_t _c_i_r_c_u_i_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H setcirc [circuit name] +TEXT: H +TEXT: H +TEXT: H The current circuit is the one that is used for the +TEXT: H simulation commands below. When a circuit is loaded +TEXT: H with the source command (see below) it becomes the +TEXT: H current circuit. +TEXT: H +TEXT: H + +SUBJECT: Setplot +TITLE: Setplot: Switch the current set of vectors +TEXT: H +TEXT: H _5._3._4_1. _S_e_t_p_l_o_t: _S_w_i_t_c_h _t_h_e _c_u_r_r_e_n_t _s_e_t _o_f _v_e_c_t_o_r_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H setplot [plotname] +TEXT: H +TEXT: H +TEXT: H Set the current plot to the plot with the given +TEXT: H name, or if no name is given, prompt the user with a +TEXT: H menu. (Note that the plots are named as they are loaded, +TEXT: H with names like tran1 or op2. These names are shown by +TEXT: H the setplot and display commands and are used by diff, +TEXT: H below.) If the "New plot" item is selected, the current +TEXT: H plot becomes one with no vectors defined. +TEXT: H +TEXT: H Note that here the word "plot" refers to a group of +TEXT: H vectors that are the result of one SPICE run. When more +TEXT: H than one file is loaded in, or more than one plot is +TEXT: H present in one file, nutmeg keeps them separate and only +TEXT: H shows you the vectors in the current plot. +TEXT: H +TEXT: H + +SUBJECT: Settype +TITLE: Settype: Set the type of a vector +TEXT: H +TEXT: H _5._3._4_2. _S_e_t_t_y_p_e: _S_e_t _t_h_e _t_y_p_e _o_f _a _v_e_c_t_o_r +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H settype type vector ... +TEXT: H +TEXT: H +TEXT: H Change the type of the named vectors to type. Type +TEXT: H names can be found in the manual page for sconvert. +TEXT: H +TEXT: H + +SUBJECT: Shell +TITLE: Shell: Call the command interpreter +TEXT: H +TEXT: H _5._3._4_3. _S_h_e_l_l: _C_a_l_l _t_h_e _c_o_m_m_a_n_d _i_n_t_e_r_p_r_e_t_e_r +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H shell [ _c_o_m_m_a_n_d ] +TEXT: H +TEXT: H +TEXT: H Call the operating system's command interpreter; +TEXT: H execute the specified command or call for interactive +TEXT: H use. +TEXT: H +TEXT: H + +SUBJECT: Shift +TITLE: Shift: Alter a list variable +TEXT: H +TEXT: H _5._3._4_4. _S_h_i_f_t: _A_l_t_e_r _a _l_i_s_t _v_a_r_i_a_b_l_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H shift [varname] [number] +TEXT: H +TEXT: H +TEXT: H If _v_a_r_n_a_m_e is the name of a list variable, it is +TEXT: H shifted to the left by _n_u_m_b_e_r elements (i.e, the _n_u_m_b_e_r +TEXT: H leftmost elements are removed). The default _v_a_r_n_a_m_e is +TEXT: H argv, and the default _n_u_m_b_e_r is 1. +TEXT: H +TEXT: H + +SUBJECT: Show +TITLE: Show*: List device state +TEXT: H +TEXT: H _5._3._4_5. _S_h_o_w*: _L_i_s_t _d_e_v_i_c_e _s_t_a_t_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H show _d_e_v_i_c_e_s [ : _p_a_r_a_m_e_t_e_r_s ] , ... +TEXT: H +TEXT: H +TEXT: H _O_l_d _F_o_r_m +TEXT: H +TEXT: H show -v @_d_e_v_i_c_e [ [ _n_a_m_e ] ] +TEXT: H +TEXT: H +TEXT: H The show command prints out tables summarizing the +TEXT: H operating condition of selected devices (much like the +TEXT: H spice2 operation point summary). If _d_e_v_i_c_e is missing, +TEXT: H a default set of devices are listed, if _d_e_v_i_c_e is a sin- +TEXT: H gle letter, devices of that type are listed; if _d_e_v_i_c_e +TEXT: H is a subcircuit name (beginning and ending in ":") only +TEXT: H devices in that subcircuit are shown (end the name in a +TEXT: H double-":" to get devices within sub-subcircuits recur- +TEXT: H sively). The second and third forms may be combined +TEXT: H ("letter:subcircuit:") or "letter:subcircuit::") to +TEXT: H select a specific type of device from a subcircuit. A +TEXT: H device's full name may be specified to list only that +TEXT: H device. Finally, devices may be selected by model by +TEXT: H using the form "#modelname" or ":subcircuit#modelname" +TEXT: H or "letter:subcircuit#modelname". +TEXT: H +TEXT: H If no _p_a_r_a_m_e_t_e_r_s are specified, the values for a +TEXT: H standard set of parameters are listed. If the list of +TEXT: H _p_a_r_a_m_e_t_e_r_s contains a "+", the default set of parameters +TEXT: H is listed along with any other specified parameters. +TEXT: H +TEXT: H For both _d_e_v_i_c_e_s and _p_a_r_a_m_e_t_e_r_s, the word "all" has +TEXT: H the obvious meaning. Note: there must be spaces +TEXT: H separating the ":" that divides the _d_e_v_i_c_e list from the +TEXT: H _p_a_r_a_m_e_t_e_r list. +TEXT: H +TEXT: H The "old form" (with "-v") prints the data in a +TEXT: H older, more verbose pre-spice3f format. +TEXT: H +TEXT: H + +SUBJECT: Showmod +TITLE: Showmod*: List model parameter values +TEXT: H +TEXT: H _5._3._4_6. _S_h_o_w_m_o_d*: _L_i_s_t _m_o_d_e_l _p_a_r_a_m_e_t_e_r _v_a_l_u_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H showmod _m_o_d_e_l_s [ : _p_a_r_a_m_e_t_e_r_s ] , ... +TEXT: H +TEXT: H +TEXT: H The showmod command operates like the show command +TEXT: H (above) but prints out model parameter values. The ap- +TEXT: H plicable forms for _m_o_d_e_l_s are a single letter specifying +TEXT: H the device type letter, "letter:subckt:", "modelname", +TEXT: H ":subckt:modelname", or "letter:subcircuit:modelname". +TEXT: H +TEXT: H + +SUBJECT: Source +TITLE: Source: Read a Spice3 input file +TEXT: H +TEXT: H _5._3._4_7. _S_o_u_r_c_e: _R_e_a_d _a _S_p_i_c_e_3 _i_n_p_u_t _f_i_l_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H source _f_i_l_e +TEXT: H +TEXT: H +TEXT: H For Spice3: Read the Spice3 input file file. Nut- +TEXT: H meg and Spice3 commands may be included in the file, and +TEXT: H must be enclosed between the lines ._c_o_n_t_r_o_l and ._e_n_d_c. +TEXT: H These commands are executed immediately after the cir- +TEXT: H cuit is loaded, so a control line of _a_c ... works the +TEXT: H same as the corresponding ._a_c card. The first line in +TEXT: H any input file is considered a title line and not parsed +TEXT: H but kept as the name of the circuit. The exception to +TEXT: H this rule is the file ._s_p_i_c_e_i_n_i_t. Thus, a Spice3 com- +TEXT: H mand script must begin with a blank line and then with a +TEXT: H acters *# is considered a control line. This makes it +TEXT: H possible to imbed commands in Spice3 input files that +TEXT: H are ignored by earlier versions of Spice2 +TEXT: H +TEXT: H For Nutmeg: Reads commands from the file _f_i_l_e_n_a_m_e. +TEXT: H Lines beginning with the character * are considered com- +TEXT: H ments and ignored. +TEXT: H +TEXT: H + +SUBJECT: Status +TITLE: Status*: Display breakpoint information +TEXT: H +TEXT: H _5._3._4_8. _S_t_a_t_u_s*: _D_i_s_p_l_a_y _b_r_e_a_k_p_o_i_n_t _i_n_f_o_r_m_a_t_i_o_n +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H status +TEXT: H +TEXT: H +TEXT: H Display all of the traces and breakpoints currently +TEXT: H in effect. +TEXT: H +TEXT: H + +SUBJECT: Step +TITLE: Step*: Run a fixed number of timepoints +TEXT: H +TEXT: H _5._3._4_9. _S_t_e_p*: _R_u_n _a _f_i_x_e_d _n_u_m_b_e_r _o_f _t_i_m_e_p_o_i_n_t_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H step [number] +TEXT: H +TEXT: H +TEXT: H Iterate number times, or once, and then stop. +TEXT: H +TEXT: H + +SUBJECT: Stop +TITLE: Stop*: Set a breakpoint +TEXT: H +TEXT: H _5._3._5_0. _S_t_o_p*: _S_e_t _a _b_r_e_a_k_p_o_i_n_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H stop [ after n] [ when _v_a_l_u_e _c_o_n_d _v_a_l_u_e ] ... +TEXT: H +TEXT: H +TEXT: H Set a breakpoint. The argument after n means stop +TEXT: H after n iteration number n, and the argument when _v_a_l_u_e +TEXT: H _c_o_n_d _v_a_l_u_e means stop when the first _v_a_l_u_e is in the +TEXT: H given relation with the second _v_a_l_u_e, the possible rela- +TEXT: H tions being +TEXT: H +TEXT: H eq or = equal to +TEXT: H ne or <> not equal to +TEXT: H gt or > greater than +TEXT: H lt or < less than +TEXT: H ge or >= greater than or equal to +TEXT: H le or <= less than or equal to +TEXT: H +TEXT: H +TEXT: H IO redirection is disabled for the stop command, since the +TEXT: H relational operations conflict with it (it doesn't produce +TEXT: H any output anyway). The _v_a_l_u_es above may be node names in +TEXT: H the running circuit, or real values. If more than one con- +TEXT: H dition is given, e.g. stop after 4 when v(1) > 4 when v(2) +TEXT: H < 2, the conjunction of the conditions is implied. +TEXT: H +TEXT: H + +SUBJECT: Tf +TITLE: Tf*: Run a Transfer Function analysis +TEXT: H +TEXT: H _5._3._5_1. _T_f*: _R_u_n _a _T_r_a_n_s_f_e_r _F_u_n_c_t_i_o_n _a_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H tf _o_u_t_p_u_t__n_o_d_e _i_n_p_u_t__s_o_u_r_c_e +TEXT: H +TEXT: H +TEXT: H The tf command performs a transfer function +TEXT: H analysis, returning the transfer function +TEXT: H (output/input), output resistance, and input resistance +TEXT: H between the given output node and the given input +TEXT: H source. The analysis assumes a small-signal DC (slowly +TEXT: H varying) input. +TEXT: H +TEXT: H + +SUBJECT: Trace +TITLE: Trace*: Trace nodes +TEXT: H +TEXT: H _5._3._5_2. _T_r_a_c_e*: _T_r_a_c_e _n_o_d_e_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H trace [ node ...] +TEXT: H +TEXT: H +TEXT: H For every step of an analysis, the value of the +TEXT: H node is printed. Several traces may be active at once. +TEXT: H Tracing is not applicable for all analyses. To remove a +TEXT: H trace, use the delete command. +TEXT: H +TEXT: H + +SUBJECT: Tran +TITLE: Tran*: Perform a transient analysis +TEXT: H +TEXT: H _5._3._5_3. _T_r_a_n*: _P_e_r_f_o_r_m _a _t_r_a_n_s_i_e_n_t _a_n_a_l_y_s_i_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H tran _T_s_t_e_p _T_s_t_o_p [ _T_s_t_a_r_t [ _T_m_a_x ] ] [ UIC ] +TEXT: H +TEXT: H +TEXT: H Perform a transient analysis. See the previous +TEXT: H sections of this manual for more details. +TEXT: H +TEXT: H + +SUBJECT: Transpose +TITLE: Transpose: Swap the elements in a multi-dimensional data set +TEXT: H +TEXT: H _5._3._5_4. _T_r_a_n_s_p_o_s_e: _S_w_a_p _t_h_e _e_l_e_m_e_n_t_s _i_n _a _m_u_l_t_i-_d_i_m_e_n_s_i_o_n_a_l +TEXT: H _d_a_t_a _s_e_t +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H transpose _v_e_c_t_o_r _v_e_c_t_o_r ... +TEXT: H +TEXT: H +TEXT: H This command transposes a multidimensional vector. +TEXT: H No analysis in Spice3 produces multidimensional vectors, +TEXT: H although the DC transfer curve may be run with two vary- +TEXT: H ing sources. You must use the "reshape" command to re- +TEXT: H form the one-dimensional vectors into two dimensional +TEXT: H vectors. In addition, the default scale is incorrect +TEXT: H for plotting. You must plot versus the vector +TEXT: H corresponding to the second source, but you must also +TEXT: H refer only to the first segment of this second source +TEXT: H vector. For example (circuit to produce the tranfer +TEXT: H characteristic of a MOS transistor): +TEXT: H +TEXT: H spice3 > dc vgg 0 5 1 vdd 0 5 1 +TEXT: H spice3 > plot i(vdd) +TEXT: H spice3 > reshape all [6,6] +TEXT: H spice3 > transpose i(vdd) v(drain) +TEXT: H spice3 > plot i(vdd) vs v(drain)[0] +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Unalias +TITLE: Unalias: Retract an alias +TEXT: H +TEXT: H _5._3._5_5. _U_n_a_l_i_a_s: _R_e_t_r_a_c_t _a_n _a_l_i_a_s +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H unalias [word ...] +TEXT: H +TEXT: H +TEXT: H Removes any aliases present for the words. +TEXT: H +TEXT: H + +SUBJECT: Undefine +TITLE: Undefine: Retract a definition +TEXT: H +TEXT: H _5._3._5_6. _U_n_d_e_f_i_n_e: _R_e_t_r_a_c_t _a _d_e_f_i_n_i_t_i_o_n +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H undefine function +TEXT: H +TEXT: H +TEXT: H Definitions for the named user-defined functions +TEXT: H are deleted. +TEXT: H +TEXT: H + +SUBJECT: Unset +TITLE: Unset: Clear a variable +TEXT: H +TEXT: H _5._3._5_7. _U_n_s_e_t: _C_l_e_a_r _a _v_a_r_i_a_b_l_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H unset [_w_o_r_d ...] +TEXT: H +TEXT: H +TEXT: H Clear the value of the specified variable(s) +TEXT: H (_w_o_r_d). +TEXT: H +TEXT: H + +SUBJECT: Version +TITLE: Version: Print the version of Spice +TEXT: H +TEXT: H _5._3._5_8. _V_e_r_s_i_o_n: _P_r_i_n_t _t_h_e _v_e_r_s_i_o_n _o_f _S_p_i_c_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H version [version id] +TEXT: H +TEXT: H +TEXT: H Print out the version of nutmeg that is running. +TEXT: H If there are arguments, it checks to make sure that the +TEXT: H arguments match the current version of SPICE. (This is +TEXT: H mainly used as a Command: line in rawfiles.) +TEXT: H +TEXT: H + +SUBJECT: Where +TITLE: Where: Identify troublesome node or device +TEXT: H +TEXT: H _5._3._5_9. _W_h_e_r_e: _I_d_e_n_t_i_f_y _t_r_o_u_b_l_e_s_o_m_e _n_o_d_e _o_r _d_e_v_i_c_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H where +TEXT: H +TEXT: H +TEXT: H When performing a transient or operating point +TEXT: H analysis, the name of the last node or device to cause +TEXT: H non-convergence is saved. The where command prints out +TEXT: H this information so that you can examine the circuit and +TEXT: H either correct the problem or make a bug report. You +TEXT: H may do this either in the middle of a run or after the +TEXT: H simulator has given up on the analysis. For transient +TEXT: H simulation, the iplot command can be used to monitor the +TEXT: H progress of the analysis. When the analysis slows down +TEXT: H severly or hangs, interrupt the simulator (with +TEXT: H control-C) and issue the where command. Note that only +TEXT: H one node or device is printed; there may be problems +TEXT: H with more than one node. +TEXT: H +TEXT: H + +SUBJECT: Write +TITLE: Write: Write data to a file +TEXT: H +TEXT: H _5._3._6_0. _W_r_i_t_e: _W_r_i_t_e _d_a_t_a _t_o _a _f_i_l_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H write [file] [exprs] +TEXT: H +TEXT: H +TEXT: H Writes out the expressions to _f_i_l_e. +TEXT: H +TEXT: H First vectors are grouped together by plots, and +TEXT: H written out as such (i.e, if the expression list con- +TEXT: H tained three vectors from one plot and two from another, +TEXT: H then two plots are written, one with three vectors and +TEXT: H one with two). Additionally, if the scale for a vector +TEXT: H isn't present, it is automatically written out as well. +TEXT: H +TEXT: H The default format is ascii, but this can be +TEXT: H changed with the set filetype command. The default +TEXT: H filename is rawspice.raw, or the argument to the -r flag +TEXT: H on the command line, if there was one, and the default +TEXT: H expression list is all. +TEXT: H +TEXT: H + +SUBJECT: Xgraph +TITLE: Xgraph: use the xgraph(1) program for plotting. +TEXT: H +TEXT: H _5._3._6_1. _X_g_r_a_p_h: _u_s_e _t_h_e _x_g_r_a_p_h(_1) _p_r_o_g_r_a_m _f_o_r _p_l_o_t_t_i_n_g. +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H xgraph _f_i_l_e [exprs] [plot options] +TEXT: H +TEXT: H +TEXT: H The spice3/nutmeg xgraph command plots data like +TEXT: H the plot command but via xgraph, a popular X11 plotting +TEXT: H program. +TEXT: H +TEXT: H If _f_i_l_e is either "temp" or "tmp" a temporary file +TEXT: H is used to hold the data while being plotted. For +TEXT: H available plot options, see the plot command. All op- +TEXT: H tions except for polar or smith plots are supported. +TEXT: H + +SUBJECT: CONTROL STRUCTURES +TITLE: CONTROL STRUCTURES +TEXT: H +TEXT: H _5._4. _C_O_N_T_R_O_L _S_T_R_U_C_T_U_R_E_S +TEXT: H +TEXT: H +SUBTOPIC: SPICE:While End +SUBTOPIC: SPICE:Repeat End +SUBTOPIC: SPICE:Dowhile End +SUBTOPIC: SPICE:Foreach End +SUBTOPIC: SPICE:If Then Else +SUBTOPIC: SPICE:Label +SUBTOPIC: SPICE:Goto +SUBTOPIC: SPICE:Continue +SUBTOPIC: SPICE:Break + +SUBJECT: While End +TITLE: While - End +TEXT: H +TEXT: H _5._4._1. _W_h_i_l_e - _E_n_d +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H while _c_o_n_d_i_t_i_o_n +TEXT: H statement +TEXT: H ... +TEXT: H end +TEXT: H +TEXT: H +TEXT: H While _c_o_n_d_i_t_i_o_n, an arbitrary algebraic expression, +TEXT: H is true, execute the statements. +TEXT: H +TEXT: H + +SUBJECT: Repeat End +TITLE: Repeat - End +TEXT: H +TEXT: H _5._4._2. _R_e_p_e_a_t - _E_n_d +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H repeat [_n_u_m_b_e_r] +TEXT: H statement +TEXT: H ... +TEXT: H end +TEXT: H +TEXT: H +TEXT: H Execute the statements _n_u_m_b_e_r times, or forever if +TEXT: H no argument is given. +TEXT: H +TEXT: H + +SUBJECT: Dowhile End +TITLE: Dowhile - End +TEXT: H +TEXT: H _5._4._3. _D_o_w_h_i_l_e - _E_n_d +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H dowhile _c_o_n_d_i_t_i_o_n +TEXT: H statement +TEXT: H ... +TEXT: H end +TEXT: H +TEXT: H +TEXT: H The same as while, except that the _c_o_n_d_i_t_i_o_n is +TEXT: H tested after the statements are executed. +TEXT: H +TEXT: H + +SUBJECT: Foreach End +TITLE: Foreach - End +TEXT: H +TEXT: H _5._4._4. _F_o_r_e_a_c_h - _E_n_d +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H foreach _v_a_r _v_a_l_u_e ... +TEXT: H statement +TEXT: H ... +TEXT: H end +TEXT: H +TEXT: H +TEXT: H The statements are executed once for each of the +TEXT: H _v_a_l_u_es, each time with the variable _v_a_r set to the +TEXT: H current one. (_v_a_r can be accessed by the $_v_a_r notation +TEXT: H - see below). +TEXT: H +TEXT: H + +SUBJECT: If Then Else +TITLE: If - Then - Else +TEXT: H +TEXT: H _5._4._5. _I_f - _T_h_e_n - _E_l_s_e +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H if _c_o_n_d_i_t_i_o_n +TEXT: H statement +TEXT: H ... +TEXT: H else +TEXT: H statement +TEXT: H ... +TEXT: H end +TEXT: H +TEXT: H +TEXT: H If the _c_o_n_d_i_t_i_o_n is non-zero then the first set of +TEXT: H statements are executed, otherwise the second set. The +TEXT: H else and the second set of statements may be omitted. +TEXT: H +TEXT: H + +SUBJECT: Label +TITLE: Label +TEXT: H +TEXT: H _5._4._6. _L_a_b_e_l +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H label _w_o_r_d +TEXT: H +TEXT: H +TEXT: H If a statement of the form goto _w_o_r_d is encoun- +TEXT: H tered, control is transferred to this point, otherwise +TEXT: H this is a no-op. +TEXT: H +TEXT: H + +SUBJECT: Goto +TITLE: Goto +TEXT: H +TEXT: H _5._4._7. _G_o_t_o +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H goto _w_o_r_d +TEXT: H +TEXT: H +TEXT: H If a statement of the form label _w_o_r_d is present in +TEXT: H the block or an enclosing block, control is transferred +TEXT: H there. Note that if the label is at the top level, it +TEXT: H _m_u_s_t be before the goto _s_t_a_t_e_m_e_n_t (_i._e, _a _f_o_r_w_a_r_d _g_o_t_o +TEXT: H may occur only within a block). +TEXT: H +TEXT: H + +SUBJECT: Continue +TITLE: Continue +TEXT: H +TEXT: H _5._4._8. _C_o_n_t_i_n_u_e +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H continue +TEXT: H +TEXT: H +TEXT: H If there is a while, dowhile, or foreach block en- +TEXT: H closing this statement, control passes to the test, or +TEXT: H in the case of foreach, the next value is taken. Other- +TEXT: H wise an error results. +TEXT: H +TEXT: H + +SUBJECT: Break +TITLE: Break +TEXT: H +TEXT: H _5._4._9. _B_r_e_a_k +TEXT: H +TEXT: H _G_e_n_e_r_a_l _F_o_r_m +TEXT: H +TEXT: H break +TEXT: H +TEXT: H +TEXT: H If there is a while, dowhile, or foreach block en- +TEXT: H closing this statement, control passes out of the block. +TEXT: H Otherwise an error results. +TEXT: H +TEXT: H Of course, control structures may be nested. When +TEXT: H a block is entered and the input is the terminal, the +TEXT: H prompt becomes a number of >'s corresponding to the +TEXT: H number of blocks the user has entered. The current con- +TEXT: H trol structures may be examined with the debugging com- +TEXT: H mand _c_d_u_m_p. +TEXT: H + +SUBJECT: VARIABLES +TITLE: VARIABLES +TEXT: H +TEXT: H _5._5. _V_A_R_I_A_B_L_E_S +TEXT: H +TEXT: H +TEXT: H The operation of both Nutmeg and Spice3 may be affected +TEXT: H by setting variables with the "set" command. In addition to +TEXT: H the variables mentioned below, the set command in Spice3 +TEXT: H also affect the behaviour of the simulator via the options +TEXT: H previously described under the section on ".OPTIONS". +TEXT: H +TEXT: H The variables meaningful to nutmeg which may be altered +TEXT: H by the set command are: +TEXT: H +TEXT: H diff_abstol The absolute tolerance used by the diff command. +TEXT: H appendwrite Append to the file when a write command is is- +TEXT: H sued, if one already exists. +TEXT: H color_N These variables determine the colors used, if X +TEXT: H is being run on a color display. _N may be +TEXT: H between 0 and 15. Color 0 is the background, +TEXT: H color 1 is the grid and text color, and colors 2 +TEXT: H through 15 are used in order for vectors plot- +TEXT: H ted. The value of the color variables should be +TEXT: H names of colors, which may be found in the file +TEXT: H /usr/lib/rgb.txt. +TEXT: H combplot Plot vectors by drawing a vertical line from +TEXT: H each point to the X-axis, as opposed to joining +TEXT: H the points. Note that this option is subsumed +TEXT: H in the _p_l_o_t_t_y_p_e option, below. +TEXT: H cpdebug Print _c_s_h_p_a_r debugging information (must be com- +TEXT: H plied with the -DCPDEBUG flag). Unsupported in +TEXT: H the current release. +TEXT: H +TEXT: H +TEXT: H debug If set then a lot of debugging information is +TEXT: H printed (must be compiled with the -DFTEDEBUG +TEXT: H flag). Unsupported in the current release. +TEXT: H device The name (/dev/tty??) of the graphics device. +TEXT: H If this variable isn't set then the user's +TEXT: H terminal is used. To do plotting on another +TEXT: H monitor you probably have to set both the +TEXT: H device and term variables. (If device is set +TEXT: H to the name of a file, nutmeg dumps the +TEXT: H graphics control codes into this file -- this +TEXT: H is useful for saving plots.) +TEXT: H echo Print out each command before it is executed. +TEXT: H filetype This can be either _a_s_c_i_i or _b_i_n_a_r_y, and +TEXT: H determines what format are. The default is +TEXT: H _a_s_c_i_i. +TEXT: H +TEXT: H +TEXT: H fourgridsize How many points to use for interpolating +TEXT: H into when doing fourier analysis. +TEXT: H gridsize If this variable is set to an integer, +TEXT: H this number is used as the number of +TEXT: H equally spaced points to use for the Y- +TEXT: H axis when plotting. Otherwise the +TEXT: H current scale is used (which may not +TEXT: H have equally spaced points). If the +TEXT: H current scale isn't strictly monotonic, +TEXT: H then this option has no effect. +TEXT: H hcopydev If this is set, when the hardcopy com- +TEXT: H mand is run the resulting file is au- +TEXT: H tomatically printed on the printer named +TEXT: H hcopydev with the command _l_p_r -_Phcopydev +TEXT: H -_g file. +TEXT: H +TEXT: H +TEXT: H hcopyfont This variable specifies the font name +TEXT: H for hardcopy output plots. The value is +TEXT: H device dependent. +TEXT: H hcopyfontsize This is a scaling factor for the font +TEXT: H used in hardcopy plots. +TEXT: H hcopydevtype This variable specifies the type of the +TEXT: H printer output to use in the hardcopy +TEXT: H command. If hcopydevtype is not set, +TEXT: H plot (5) format is assumed. The stan- +TEXT: H dard distribution currently recognizes +TEXT: H postscript as an alternative output for- +TEXT: H mat. When used in conjunction with +TEXT: H hcopydev, hcopydevtype should specify a +TEXT: H format supported by the printer. +TEXT: H height The length of the page for asciiplot and +TEXT: H print col. +TEXT: H history The number of events to save in the his- +TEXT: H tory list. +TEXT: H lprplot5 This is a printf(3s) style format string +TEXT: H used to specify the command to use for +TEXT: H sending plot(5)-style plots to a printer +TEXT: H or plotter. The first parameter sup- +TEXT: H plied is the printer name, the second +TEXT: H parameter supplied is a file name con- +TEXT: H taining the plot. Both parameters are +TEXT: H strings. It is trivial to cause Spice3 +TEXT: H to abort by supplying a unreasonable +TEXT: H format string. +TEXT: H lprps This is a printf(3s) style format string +TEXT: H used to specify the command to use for +TEXT: H sending PostScript plots to a printer or +TEXT: H plotter. The first parameter supplied +TEXT: H is the printer name, the second parame- +TEXT: H ter supplied is a file name containing +TEXT: H the plot. Both parameters are strings. +TEXT: H It is trivial to cause Spice3 to abort +TEXT: H by supplying a unreasonable format +TEXT: H string. +TEXT: H nfreqs The number of frequencies to compute in +TEXT: H the _f_o_u_r_i_e_r command. (Defaults to 10.) +TEXT: H nobreak Don't have asciiplot and print col break +TEXT: H between pages. +TEXT: H +TEXT: H +TEXT: H noasciiplotvalue Don't print the first vector plotted to +TEXT: H the left when doing an asciiplot. +TEXT: H noclobber Don't overwrite existing files when do- +TEXT: H ing IO redirection. +TEXT: H noglob Don't expand the global characters `*', +TEXT: H `?', `[', and `]'. This is the default. +TEXT: H nogrid Don't plot a grid when graphing curves +TEXT: H (but do label the axes). +TEXT: H nomoremode If nomoremode is not set, whenever a +TEXT: H large amount of data is being printed to +TEXT: H the screen (e.g, the print or asciiplot +TEXT: H commands), the output is stopped every +TEXT: H screenful and continues when a carriage +TEXT: H return is typed. If nomoremode is set +TEXT: H then data scrolls off the screen without +TEXT: H check. +TEXT: H nonomatch If noglob is unset and a global expres- +TEXT: H sion cannot be matched, use the global +TEXT: H characters literally instead of com- +TEXT: H plaining. +TEXT: H +TEXT: H +TEXT: H nosort Don't have display sort the variable names. +TEXT: H noprintscale Don't print the scale in the leftmost +TEXT: H column when a print col command is given. +TEXT: H numdgt The number of digits to print when printing +TEXT: H tables of data (fourier, print col). The +TEXT: H default precision is 6 digits. On the VAX, +TEXT: H approximately 16 decimal digits are avail- +TEXT: H able using double precision, so numdgt +TEXT: H should not be more than 16. If the number +TEXT: H is negative, one fewer digit is printed to +TEXT: H ensure constant widths in tables. +TEXT: H plottype This should be one of normal, comb, or +TEXT: H point:_c_h_a_r_s. normal, the default, causes +TEXT: H points to be plotted as parts of connected +TEXT: H lines. comb causes a comb plot to be done +TEXT: H (see the description of the combplot vari- +TEXT: H able above). point causes each point to be +TEXT: H plotted separately - the chars are a list +TEXT: H of characters that are used for each vector +TEXT: H plotted. If they are omitted then a de- +TEXT: H fault set is used. +TEXT: H polydegree The degree of the polynomial that the plot +TEXT: H command should fit to the data. If _p_o_l_y_d_e- +TEXT: H _g_r_e_e is N, then nutmeg fits a degree N po- +TEXT: H lynomial to every set of N points and draw +TEXT: H 10 intermediate points in between each end- +TEXT: H point. If the points aren't monotonic, +TEXT: H then it tries rotating the curve and reduc- +TEXT: H ing the degree until a fit is achieved. +TEXT: H polysteps The number of points to interpolate between +TEXT: H every pair of points available when doing +TEXT: H curve fitting. The default is 10. +TEXT: H program The name of the current program (_a_r_g_v[_0]). +TEXT: H prompt The prompt, with the character `!' replaced +TEXT: H by the current event number. +TEXT: H +TEXT: H +TEXT: H rawfile The default name for rawfiles created. +TEXT: H diff_reltol The relative tolerance used by the diff command. +TEXT: H remote_shell Overrides the name used for generating rspice +TEXT: H runs (default is "rsh"). +TEXT: H rhost The machine to use for remote SPICE-3 runs, in- +TEXT: H stead of the default one (see the description of +TEXT: H the rspice command, below). +TEXT: H rprogram The name of the remote program to use in the +TEXT: H rspice command. +TEXT: H slowplot Stop between each graph plotted and wait for the +TEXT: H user to type return before continuing. +TEXT: H sourcepath A list of the directories to search when a +TEXT: H source command is given. The default is the +TEXT: H current directory and the standard spice library +TEXT: H (/_u_s_r/_l_o_c_a_l/_l_i_b/_s_p_i_c_e, or whatever LIBPATH is +TEXT: H #defined to in the Spice3 source. +TEXT: H spicepath The program to use for the aspice command. The +TEXT: H default is /cad/bin/spice. +TEXT: H term The _m_f_b name of the current terminal. +TEXT: H units If this is degrees, then all the trig functions +TEXT: H will use degrees instead of radians. +TEXT: H unixcom If a command isn't defined, try to execute it as +TEXT: H a UNIX command. Setting this option has the ef- +TEXT: H fect of giving a rehash command, below. This is +TEXT: H useful for people who want to use nutmeg as a +TEXT: H login shell. +TEXT: H verbose Be verbose. This is midway between echo and de- +TEXT: H bug / cpdebug. +TEXT: H diff_vntol The absolute voltage tolerance used by the diff +TEXT: H command. +TEXT: H +TEXT: H +TEXT: H width The width of the page for asciiplot and +TEXT: H print col. +TEXT: H x11lineararcs Some X11 implementations have poor arc +TEXT: H drawing. If you set this option, Spice3 +TEXT: H will plot using an approximation to the +TEXT: H curve using straight lines. +TEXT: H xbrushheight The height of the brush to use if X is +TEXT: H being run. +TEXT: H xbrushwidth The width of the brush to use if X is +TEXT: H being run. +TEXT: H xfont The name of the X font to use when plot- +TEXT: H ting data and entering labels. The plot +TEXT: H may not look good if this is a +TEXT: H variable-width font. +TEXT: H +TEXT: H +TEXT: H There are several set variables that Spice3 uses but +TEXT: H Nutmeg does not. They are: +TEXT: H +TEXT: H editor The editor to use for the edit command. +TEXT: H modelcard The name of the model card (normally +TEXT: H May.in -432u +TEXT: H noaskquit Do not check to make sure that there are +TEXT: H no circuits suspended and no plots un- +TEXT: H saved. Normally Spice3 warns the user +TEXT: H when he tries to quit if this is the +TEXT: H case. +TEXT: H nobjthack Assume that BJTs have 4 nodes. +TEXT: H noparse Don't attempt to parse input files when +TEXT: H they are read in (useful for debugging). +TEXT: H Of course, they cannot be run if they +TEXT: H are not parsed. +TEXT: H nosubckt Don't expand subcircuits. +TEXT: H renumber Renumber input lines when an input file +TEXT: H has .include's. +TEXT: H subend The card to end subcircuits (normally +TEXT: H subinvoke The prefix to invoke subcircuits (nor- +TEXT: H mally x). +TEXT: H substart The card to begin subcircuits (normally +TEXT: H +TEXT: H + +SUBJECT: MISCELLANEOUS +TITLE: MISCELLANEOUS +TEXT: H +TEXT: H _5._6. _M_I_S_C_E_L_L_A_N_E_O_U_S +TEXT: H +TEXT: H If there are subcircuits in the input file, Spice3 +TEXT: H expands instances of them. A subcircuit is delimited by the +TEXT: H cards ._s_u_b_c_k_t and ._e_n_d_s, or whatever the value of the vari- +TEXT: H ables _s_u_b_s_t_a_r_t and _s_u_b_e_n_d is, respectively. An instance of +TEXT: H a subcircuit is created by specifying a device with type 'x' +TEXT: H - the device line is written +TEXT: H +TEXT: H xname node1 node2 ... subcktname +TEXT: H +TEXT: H +TEXT: H where the nodes are the node names that replace the formal +TEXT: H parameters on the .subckt line. All nodes that are not for- +TEXT: H mal parameters are prepended with the name given to the +TEXT: H instance and a ':', as are the names of the devices in the +TEXT: H subcircuit. If there are several nested subcircuits, node +TEXT: H and device names look like subckt1:subckt2:...:name. If the +TEXT: H variable subinvoke is set, then it is used as the prefix +TEXT: H that specifies instances of subcircuits, instead of 'x'. +TEXT: H +TEXT: H Nutmeg occasionally checks to see if it is getting +TEXT: H close to running out of space, and warns the user if this is +TEXT: H the case. (This is more likely to be useful with the SPICE +TEXT: H front end.) +TEXT: H +TEXT: H C-shell type quoting with "" and '', and backquote sub- +TEXT: H stitution may be used. Within single quotes, no further +TEXT: H substitution (like history substitution) is done, and within +TEXT: H double quotes, the words are kept together but further sub- +TEXT: H stitution is done. Any text between backquotes is replaced +TEXT: H by the result of executing the text as a command to the +TEXT: H shell. +TEXT: H +TEXT: H Tenex-style ('set filec' in the 4.3 C-shell) command, +TEXT: H filename, and keyword completion is possible: If EOF +TEXT: H (control-D) is typed after the first character on the line, +TEXT: H a list of the commands or possible arguments is printed (If +TEXT: H it is alone on the line it exits nutmeg). If escape is +TEXT: H typed, then nutmeg trys to complete what the user has +TEXT: H already typed. To get a list of all commands, the user +TEXT: H should type ^D. +TEXT: H +TEXT: H The values of variables may be used in commands by +TEXT: H writing $varname where the value of the variable is to +TEXT: H appear. The special variables $$ and $< refer to the pro- +TEXT: H cess ID of the program and a line of input which is read +TEXT: H from the terminal when the variable is evaluated, respec- +TEXT: H tively. If a variable has a name of the form $&word, then +TEXT: H word is considered a vector (see above), and its value is +TEXT: H taken to be the value of the variable. If $_f_o_o is a valid +TEXT: H variable, and is of type list, then the expression +TEXT: H $_f_o_o[_l_o_w-_h_i_g_h] represents a range of elements. Either the +TEXT: H upper index or the lower may be left out, and the reverse of +TEXT: H a list may be obtained with $_f_o_o[_l_e_n-_0]. Also, the notation +TEXT: H $?_f_o_o evaluates to 1 if the variable _f_o_o is defined, 0 oth- +TEXT: H erwise, and $#_f_o_o evaluates to the number of elements in _f_o_o +TEXT: H if it is a list, 1 if it is a number or string, and 0 if it +TEXT: H is a boolean variable. +TEXT: H +TEXT: H History substitutions, similar to C-shell history sub- +TEXT: H stitutions, are also available - see the C-shell manual page +TEXT: H for all of the details. +TEXT: H +TEXT: H The characters ~, {, and } have the same effects as +TEXT: H they do in the C-Shell, i.e., home directory and alternative +TEXT: H expansion. It is possible to use the wildcard characters *, +TEXT: H ?, [, and ] also, but only if you unset noglob first. This +TEXT: H makes them rather useless for typing algebraic expressions, +TEXT: H so you should set noglob again after you are done with wild- +TEXT: H card expansion. Note that the pattern [^abc] matchs all +TEXT: H characters _e_x_c_e_p_t a, b, _a_n_d c. +TEXT: H +TEXT: H IO redirection is available - the symbols >, >>, >&, +TEXT: H >>&, and < have the same effects as in the C-shell. +TEXT: H +TEXT: H You may type multiple commands on one line, separated +TEXT: H by semicolons. +TEXT: H +TEXT: H If you want to use a different mfbcap file than the +TEXT: H default (usually ~cad/lib/mfbcap), you have to set the +TEXT: H environment variable SPICE_MFBCAP before you start nutmeg or +TEXT: H spice. The -m option and the mfbcap variable no longer +TEXT: H work. +TEXT: H +TEXT: H If X is being used, the cursor may be positioned at any +TEXT: H point on the screen when the window is up and characters +TEXT: H typed at the keyboard are added to the window at that point. +TEXT: H The window may then be sent to a printer using the xpr(1) +TEXT: H program. +TEXT: H +TEXT: H Nutmeg can be run under VAX/VMS, as well as several +TEXT: H other operating systems. Some features like command comple- +TEXT: H tion, expansion of *, ?, and [], backquote substitution, the +TEXT: H shell command, and so forth do not work. +TEXT: H +TEXT: H On some systems you have to respond to the -_m_o_r_e- +TEXT: H prompt during plot with a carriage return instead of any key +TEXT: H as you can do on UNIX. + +SUBJECT: BUGS +TITLE: BUGS +TEXT: H +TEXT: H _5._7. _B_U_G_S +TEXT: H +TEXT: H The label entry facilities are primitive. You must be +TEXT: H careful to type slowly when entering labels -- nutmeg checks +TEXT: H for input once every second, and can get confused if charac- +TEXT: H ters arrive faster. +TEXT: H +TEXT: H If you redefine colors after creating a plot window +TEXT: H with X, and then cause the window to be redrawn, it does not +TEXT: H redraw in the correct colors. +TEXT: H +TEXT: H +TEXT: H When defining aliases like +TEXT: H +TEXT: H alias pdb plot db( '!:1' - '!:2' ) +TEXT: H +TEXT: H +TEXT: H you must be careful to quote the argument list substitu- +TEXT: H tions in this manner. If you quote the whole argument +TEXT: H it might not work properly. +TEXT: H +TEXT: H +TEXT: H +TEXT: H In a user-defined function, the arguments cannot be +TEXT: H part of a name that uses the _p_l_o_t._v_e_c syntax. For example: +TEXT: H +TEXT: H define check(v(1)) cos(tran1.v(1)) +TEXT: H +TEXT: H +TEXT: H does not work. +TEXT: H +TEXT: H +TEXT: H If you type plot all all, or otherwise use a wildcard +TEXT: H reference for one plot twice in a command, the effect is +TEXT: H unpredictable. +TEXT: H +TEXT: H The asciiplot command doesn't deal with log scales or +TEXT: H the delta keywords. +TEXT: H +TEXT: H +TEXT: H Often the names of terminals recognized by MFB are dif- +TEXT: H ferent from those in /etc/termcap. Thus you may have to +TEXT: H reset your terminal type with the command +TEXT: H +TEXT: H set term = termname +TEXT: H +TEXT: H +TEXT: H where termname is the name in the mfbcap file. +TEXT: H +TEXT: H +TEXT: H The hardcopy command is useless on VMS and other sys- +TEXT: H tems without the plot command, unless the user has a program +TEXT: H that understands _p_l_o_t(_5) format. +TEXT: H +TEXT: H Spice3 recognizes all the notations used in SPICE2 +TEXT: H .plot cards, and translates vp(1) into ph(v(1)), and so +TEXT: H forth. However, if there are spaces in these names it won't +TEXT: H work. Hence v(1, 2) and (-.5, .5) aren't recognized. +TEXT: H +TEXT: H BJTs can have either 3 or 4 nodes, which makes it dif- +TEXT: H ficult for the subcircuit expansion routines to decide what +TEXT: H to rename. If the fourth parameter has been declared as a +TEXT: H model name, then it is assumed that there are 3 nodes, oth- +TEXT: H erwise it is considered a node. To disable this, you can +TEXT: H set the variable "nobjthack" which forces BJTs to have 4 +TEXT: H nodes (for the purposes of subcircuit expansion, at least). +TEXT: H +TEXT: H The @name[param] notation might not work with trace, +TEXT: H iplot, etc. yet. +TEXT: H +TEXT: H The first line of a command file (except for the ._s_p_i_- +TEXT: H _c_e_i_n_i_t file) should be a comment, otherwise SPICE may create +TEXT: H an empty circuit. +TEXT: H +TEXT: H Files specified on the command line are read before +TEXT: H .spiceinit is read. + +SUBJECT: BIBLIOGRAPHY +TITLE: BIBLIOGRAPHY +TEXT: H +TEXT: H _6. _B_I_B_L_I_O_G_R_A_P_H_Y +TEXT: H +TEXT: H +TEXT: H [1] A. Vladimirescu and S. Liu, _T_h_e _S_i_m_u_l_a_t_i_o_n _o_f _M_O_S +TEXT: H _I_n_t_e_g_r_a_t_e_d _C_i_r_c_u_i_t_s _U_s_i_n_g _S_P_I_C_E_2 +TEXT: H ERL Memo No. ERL M80/7, Electronics Research Laboratory +TEXT: H University of California, Berkeley, October 1980 +TEXT: H +TEXT: H [2] T. Sakurai and A. R. Newton, _A _S_i_m_p_l_e _M_O_S_F_E_T _M_o_d_e_l _f_o_r +TEXT: H _C_i_r_c_u_i_t _A_n_a_l_y_s_i_s _a_n_d _i_t_s _a_p_p_l_i_c_a_t_i_o_n _t_o _C_M_O_S _g_a_t_e _d_e_l_a_y +TEXT: H _a_n_a_l_y_s_i_s _a_n_d _s_e_r_i_e_s-_c_o_n_n_e_c_t_e_d _M_O_S_F_E_T _S_t_r_u_c_t_u_r_e +TEXT: H ERL Memo No. ERL M90/19, Electronics Research Labora- +TEXT: H tory, +TEXT: H University of California, Berkeley, March 1990 +TEXT: H +TEXT: H [3] B. J. Sheu, D. L. Scharfetter, and P. K. Ko, _S_P_I_C_E_2 +TEXT: H _I_m_p_l_e_m_e_n_t_a_t_i_o_n _o_f _B_S_I_M +TEXT: H ERL Memo No. ERL M85/42, Electronics Research Labora- +TEXT: H tory +TEXT: H University of California, Berkeley, May 1985 +TEXT: H +TEXT: H [4] J. R. Pierret, _A _M_O_S _P_a_r_a_m_e_t_e_r _E_x_t_r_a_c_t_i_o_n _P_r_o_g_r_a_m _f_o_r +TEXT: H _t_h_e _B_S_I_M _M_o_d_e_l +TEXT: H ERL Memo Nos. ERL M84/99 and M84/100, Electronics +TEXT: H Research Laboratory +TEXT: H University of California, Berkeley, November 1984 +TEXT: H +TEXT: H [5] Min-Chie Jeng, _D_e_s_i_g_n _a_n_d _M_o_d_e_l_i_n_g _o_f _D_e_e_p- +TEXT: H _S_u_b_m_i_c_r_o_m_e_t_e_r _M_O_S_F_E_T_S_s +TEXT: H ERL Memo Nos. ERL M90/90, Electronics Research Labora- +TEXT: H tory +TEXT: H University of California, Berkeley, October 1990 +TEXT: H +TEXT: H [6] Soyeon Park, _A_n_a_l_y_s_i_s _a_n_d _S_P_I_C_E _i_m_p_l_e_m_e_n_t_a_t_i_o_n _o_f _H_i_g_h +TEXT: H _T_e_m_p_e_r_a_t_u_r_e _E_f_f_e_c_t_s _o_n _M_O_S_F_E_T, +TEXT: H Master's thesis, University of California, Berkeley, +TEXT: H December 1986. +TEXT: H +TEXT: H [7] Clement Szeto, _S_i_m_u_l_a_t_o_r _o_f _T_e_m_p_e_r_a_t_u_r_e _E_f_f_e_c_t_s _i_n _M_O_S_- +TEXT: H _F_E_T_s (_S_T_E_I_M), +TEXT: H Master's thesis, University of California, Berkeley, +TEXT: H May 1988. +TEXT: H +TEXT: H [8] J.S. Roychowdhury and D.O. Pederson, _E_f_f_i_c_i_e_n_t _T_r_a_n_- +TEXT: H _s_i_e_n_t _S_i_m_u_l_a_t_i_o_n _o_f _L_o_s_s_y _I_n_t_e_r_c_o_n_n_e_c_t, +TEXT: H Proc. of the 28th ACM/IEEE Design Automation Confer- +TEXT: H ence, June 17-21 1991, San Francisco +TEXT: H +TEXT: H [9] A. E. Parker and D. J. Skellern, _A_n _I_m_p_r_o_v_e_d _F_E_T _M_o_d_e_l +TEXT: H _f_o_r _C_o_m_p_u_t_e_r _S_i_m_u_l_a_t_o_r_s, +TEXT: H IEEE Trans CAD, vol. 9, no. 5, pp. 551-553, May 1990. +TEXT: H +TEXT: H [10] R. Saleh and A. Yang, Editors, _S_i_m_u_l_a_t_i_o_n _a_n_d _M_o_d_e_l_i_n_g, +TEXT: H IEEE Circuits and Devices, vol. 8, no. 3, pp. 7-8 and +TEXT: H 49, May 1992 +TEXT: H +TEXT: H [11] H.Statz et al., _G_a_A_s _F_E_T _D_e_v_i_c_e _a_n_d _C_i_r_c_u_i_t _S_i_m_u_l_a_t_i_o_n +TEXT: H _i_n _S_P_I_C_E, +TEXT: H IEEE Transactions on Electron Devices, V34, Number 2, +TEXT: H February, 1987 pp160-169. + +SUBJECT: APPENDIX A +TITLE: APPENDIX A: EXAMPLE CIRCUITS +TEXT: H +TEXT: H _A. _A_P_P_E_N_D_I_X _A: _E_X_A_M_P_L_E _C_I_R_C_U_I_T_S +TEXT: H +TEXT: H +SUBTOPIC: SPICE:Circuit 1 +SUBTOPIC: SPICE:Circuit 2 +SUBTOPIC: SPICE:Circuit 3 +SUBTOPIC: SPICE:Circuit 4 +SUBTOPIC: SPICE:Circuit 5 + +SUBJECT: Circuit 1 +TITLE: Circuit 1: Differential Pair +TEXT: H +TEXT: H _A._1. _C_i_r_c_u_i_t _1: _D_i_f_f_e_r_e_n_t_i_a_l _P_a_i_r +TEXT: H +TEXT: H +TEXT: H The following deck determines the dc operating point of +TEXT: H a simple differential pair. In addition, the ac small-signal +TEXT: H response is computed over the frequency range 1Hz to +TEXT: H 100MEGHz. +TEXT: H +TEXT: H SIMPLE DIFFERENTIAL PAIR +TEXT: H VCC 7 0 12 +TEXT: H VEE 8 0 -12 +TEXT: H VIN 1 0 AC 1 +TEXT: H RS1 1 2 1K +TEXT: H RS2 6 0 1K +TEXT: H Q1 3 2 4 MOD1 +TEXT: H Q2 5 6 4 MOD1 +TEXT: H RC1 7 3 10K +TEXT: H RC2 7 5 10K +TEXT: H RE 4 8 10K +TEXT: H .MODEL MOD1 NPN BF=50 VAF=50 IS=1.E-12 RB=100 CJC=.5PF TF=.6NS +TEXT: H .TF V(5) VIN +TEXT: H .AC DEC 10 1 100MEG +TEXT: H .END +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Circuit 2 +TITLE: Circuit 2: MOSFET Characterization +TEXT: H +TEXT: H _A._2. _C_i_r_c_u_i_t _2: _M_O_S_F_E_T _C_h_a_r_a_c_t_e_r_i_z_a_t_i_o_n +TEXT: H +TEXT: H The following deck computes the output characteristics of a +TEXT: H MOSFET device over the range 0-10V for VDS and 0-5V for VGS. +TEXT: H +TEXT: H +TEXT: H MOS OUTPUT CHARACTERISTICS +TEXT: H .OPTIONS NODE NOPAGE +TEXT: H VDS 3 0 +TEXT: H VGS 2 0 +TEXT: H M1 1 2 0 0 MOD1 L=4U W=6U AD=10P AS=10P +TEXT: H * VIDS MEASURES ID, WE COULD HAVE USED VDS, BUT ID WOULD BE NEGATIVE +TEXT: H VIDS 3 1 +TEXT: H .MODEL MOD1 NMOS VTO=-2 NSUB=1.0E15 UO=550 +TEXT: H .DC VDS 0 10 .5 VGS 0 5 1 +TEXT: H .END +TEXT: H +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Circuit 3 +TITLE: Circuit 3: RTL Inverter +TEXT: H +TEXT: H _A._3. _C_i_r_c_u_i_t _3: _R_T_L _I_n_v_e_r_t_e_r +TEXT: H +TEXT: H +TEXT: H The following deck determines the dc transfer curve and +TEXT: H the transient pulse response of a simple RTL inverter. The +TEXT: H input is a pulse from 0 to 5 Volts with delay, rise, and +TEXT: H fall times of 2ns and a pulse width of 30ns. The transient +TEXT: H interval is 0 to 100ns, with printing to be done every +TEXT: H nanosecond. +TEXT: H +TEXT: H +TEXT: H SIMPLE RTL INVERTER +TEXT: H VCC 4 0 5 +TEXT: H VIN 1 0 PULSE 0 5 2NS 2NS 2NS 30NS +TEXT: H RB 1 2 10K +TEXT: H Q1 3 2 0 Q1 +TEXT: H RC 3 4 1K +TEXT: H .MODEL Q1 NPN BF 20 RB 100 TF .1NS CJC 2PF +TEXT: H .DC VIN 0 5 0.1 +TEXT: H .TRAN 1NS 100NS +TEXT: H .END +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Circuit 4 +TITLE: Circuit 4: Four-Bit Binary Adder +TEXT: H +TEXT: H _A._4. _C_i_r_c_u_i_t _4: _F_o_u_r-_B_i_t _B_i_n_a_r_y _A_d_d_e_r +TEXT: H +TEXT: H +TEXT: H The following deck simulates a four-bit binary adder, +TEXT: H using several subcircuits to describe various pieces of the +TEXT: H overall circuit. +TEXT: H +TEXT: H +TEXT: H ADDER - 4 BIT ALL-NAND-GATE BINARY ADDER +TEXT: H +TEXT: H *** SUBCIRCUIT DEFINITIONS +TEXT: H .SUBCKT NAND 1 2 3 4 +TEXT: H * NODES: INPUT(2), OUTPUT, VCC +TEXT: H Q1 9 5 1 QMOD +TEXT: H D1CLAMP 0 1 DMOD +TEXT: H Q2 9 5 2 QMOD +TEXT: H D2CLAMP 0 2 DMOD +TEXT: H RB 4 5 4K +TEXT: H R1 4 6 1.6K +TEXT: H Q3 6 9 8 QMOD +TEXT: H R2 8 0 1K +TEXT: H RC 4 7 130 +TEXT: H Q4 7 6 10 QMOD +TEXT: H DVBEDROP 10 3 DMOD +TEXT: H Q5 3 8 0 QMOD +TEXT: H .ENDS NAND +TEXT: H +TEXT: H .SUBCKT ONEBIT 1 2 3 4 5 6 +TEXT: H * NODES: INPUT(2), CARRY-IN, OUTPUT, CARRY-OUT, VCC +TEXT: H X1 1 2 7 6 NAND +TEXT: H X2 1 7 8 6 NAND +TEXT: H X3 2 7 9 6 NAND +TEXT: H X4 8 9 10 6 NAND +TEXT: H X5 3 10 11 6 NAND +TEXT: H X6 3 11 12 6 NAND +TEXT: H X7 10 11 13 6 NAND +TEXT: H X8 12 13 4 6 NAND +TEXT: H X9 11 7 5 6 NAND +TEXT: H .ENDS ONEBIT +TEXT: H +TEXT: H .SUBCKT TWOBIT 1 2 3 4 5 6 7 8 9 +TEXT: H * NODES: INPUT - BIT0(2) / BIT1(2), OUTPUT - BIT0 / BIT1, +TEXT: H * CARRY-IN, CARRY-OUT, VCC +TEXT: H X1 1 2 7 5 10 9 ONEBIT +TEXT: H X2 3 4 10 6 8 9 ONEBIT +TEXT: H .ENDS TWOBIT +TEXT: H +TEXT: H .SUBCKT FOURBIT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 +TEXT: H * NODES: INPUT - BIT0(2) / BIT1(2) / BIT2(2) / BIT3(2), +TEXT: H * OUTPUT - BIT0 / BIT1 / BIT2 / BIT3, CARRY-IN, CARRY-OUT, VCC +TEXT: H X1 1 2 3 4 9 10 13 16 15 TWOBIT +TEXT: H X2 5 6 7 8 11 12 16 14 15 TWOBIT +TEXT: H .ENDS FOURBIT +TEXT: H +TEXT: H *** DEFINE NOMINAL CIRCUIT +TEXT: H .MODEL DMOD D +TEXT: H .MODEL QMOD NPN(BF=75 RB=100 CJE=1PF CJC=3PF) +TEXT: H VCC 99 0 DC 5V +TEXT: H VIN1A 1 0 PULSE(0 3 0 10NS 10NS 10NS 50NS) +TEXT: H VIN1B 2 0 PULSE(0 3 0 10NS 10NS 20NS 100NS) +TEXT: H VIN2A 3 0 PULSE(0 3 0 10NS 10NS 40NS 200NS) +TEXT: H VIN2B 4 0 PULSE(0 3 0 10NS 10NS 80NS 400NS) +TEXT: H VIN3A 5 0 PULSE(0 3 0 10NS 10NS 160NS 800NS) +TEXT: H VIN3B 6 0 PULSE(0 3 0 10NS 10NS 320NS 1600NS) +TEXT: H VIN4A 7 0 PULSE(0 3 0 10NS 10NS 640NS 3200NS) +TEXT: H VIN4B 8 0 PULSE(0 3 0 10NS 10NS 1280NS 6400NS) +TEXT: H X1 1 2 3 4 5 6 7 8 9 10 11 12 0 13 99 FOURBIT +TEXT: H RBIT0 9 0 1K +TEXT: H RBIT1 10 0 1K +TEXT: H RBIT2 11 0 1K +TEXT: H RBIT3 12 0 1K +TEXT: H RCOUT 13 0 1K +TEXT: H +TEXT: H *** (FOR THOSE WITH MONEY (AND MEMORY) TO BURN) +TEXT: H .TRAN 1NS 6400NS +TEXT: H .END +TEXT: H +TEXT: H +TEXT: H + +SUBJECT: Circuit 5 +TITLE: Circuit 5: Transmission-Line Inverter +TEXT: H +TEXT: H _A._5. _C_i_r_c_u_i_t _5: _T_r_a_n_s_m_i_s_s_i_o_n-_L_i_n_e _I_n_v_e_r_t_e_r +TEXT: H +TEXT: H +TEXT: H The following deck simulates a transmission-line in- +TEXT: H verter. Two transmission-line elements are required since +TEXT: H two propagation modes are excited. In the case of a coaxial +TEXT: H line, the first line (T1) models the inner conductor with +TEXT: H respect to the shield, and the second line (T2) models the +TEXT: H shield with respect to the outside world. +TEXT: H +TEXT: H +TEXT: H TRANSMISSION-LINE INVERTER +TEXT: H V1 1 0 PULSE(0 1 0 0.1N) +TEXT: H R1 1 2 50 +TEXT: H X1 2 0 0 4 TLINE +TEXT: H R2 4 0 50 +TEXT: H +TEXT: H .SUBCKT TLINE 1 2 3 4 +TEXT: H T1 1 2 3 4 Z0=50 TD=1.5NS +TEXT: H T2 2 0 4 0 Z0=100 TD=1NS +TEXT: H .ENDS TLINE +TEXT: H +TEXT: H .TRAN 0.1NS 20NS +TEXT: H .END +TEXT: H +TEXT: H + +SUBJECT: APPENDIX B +TITLE: APPENDIX B: MODEL AND DEVICE PARAMETERS +TEXT: H +TEXT: H _B. _A_P_P_E_N_D_I_X _B: _M_O_D_E_L _A_N_D _D_E_V_I_C_E _P_A_R_A_M_E_T_E_R_S +TEXT: H +TEXT: H The following tables summarize the parameters available +TEXT: H on each of the devices and models in (note that for some +TEXT: H systems with limited memory, output parameters are not +TEXT: H available). There are several tables for each type of dev- +TEXT: H ice supported by . Input parameters to instances and models +TEXT: H are parameters that can occur on an instance or model defin- +TEXT: H ition line in the form "keyword=value" where "keyword" is +TEXT: H the parameter name as given in the tables. Default input +TEXT: H parameters (such as the resistance of a resistor or the +TEXT: H capacitance of a capacitor) obviously do not need the key- +TEXT: H word specified. +TEXT: H +TEXT: H Output parameters are those additional parameters which +TEXT: H are available for many types of instances for the output of +TEXT: H operating point and debugging information. These parameters +TEXT: H are specified as "@device[keyword]" and are available for +TEXT: H the most recent point computed or, if specified in a ".save" +TEXT: H statement, for an entire simulation as a normal output vec- +TEXT: H tor. Thus, to monitor the gate-to-source capacitance of a +TEXT: H MOSFET, a command +TEXT: H +TEXT: H save @m1[cgs] +TEXT: H +TEXT: H given before a transient simulation causes the specified +TEXT: H capacitance value to be saved at each timepoint, and a sub- +TEXT: H sequent command such as +TEXT: H +TEXT: H plot @m1[cgs] +TEXT: H +TEXT: H produces the desired plot. (Note that the show command does +TEXT: H not use this format). +TEXT: H +TEXT: H Some variables are listed as both input and output, and +TEXT: H their output simply returns the previously input value, or +TEXT: H the default value after the simulation has been run. Some +TEXT: H parameter are input only because the output system can not +TEXT: H handle variables of the given type yet, or the need for them +TEXT: H as output variables has not been apparent. Many such input +TEXT: H variables are available as output variables in a different +TEXT: H format, such as the initial condition vectors that can be +TEXT: H retrieved as individual initial condition values. Finally, +TEXT: H internally derived values are output only and are provided +TEXT: H for debugging and operating point output purposes. +TEXT: H +TEXT: H Please note that these tables do not provide the +TEXT: H detailed information available about the parameters provided +TEXT: H in the section on each device and model, but are provided as +TEXT: H a quick reference guide. +SUBTOPIC: SPICE:URC +SUBTOPIC: SPICE:ASRC +SUBTOPIC: SPICE:BJT +SUBTOPIC: SPICE:BSIM1 +SUBTOPIC: SPICE:BSIM2 +SUBTOPIC: SPICE:Capacitor +SUBTOPIC: SPICE:CCCS +SUBTOPIC: SPICE:CCVS +SUBTOPIC: SPICE:CSwitch +SUBTOPIC: SPICE:Diode +SUBTOPIC: SPICE:Inductor +SUBTOPIC: SPICE:mutual +SUBTOPIC: SPICE:Isource +SUBTOPIC: SPICE:JFET +SUBTOPIC: SPICE:LTRA +SUBTOPIC: SPICE:MES +SUBTOPIC: SPICE:Mos1 +SUBTOPIC: SPICE:Mos2 +SUBTOPIC: SPICE:Mos3 +SUBTOPIC: SPICE:Mos6 +SUBTOPIC: SPICE:Resistor +SUBTOPIC: SPICE:Switch +SUBTOPIC: SPICE:Tranline +SUBTOPIC: SPICE:VCCS +SUBTOPIC: SPICE:VCVS +SUBTOPIC: SPICE:Vsource + +SUBJECT: URC +TITLE: URC: Uniform R.C. line +TEXT: H +TEXT: H _B._1. _U_R_C: _U_n_i_f_o_r_m _R._C. _l_i_n_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| URC - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| l Length of transmission line | +TEXT: H| n Number of lumps | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| URC - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node Positive node of URC | +TEXT: H| neg_node Negative node of URC | +TEXT: H| gnd Ground node of URC | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| URC - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| urc Uniform R.C. line model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| URC - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| k Propagation constant | +TEXT: H| fmax Maximum frequency of interest | +TEXT: H| rperl Resistance per unit length | +TEXT: H| cperl Capacitance per unit length | +TEXT: H| isperl Saturation current per length | +TEXT: H| rsperl Diode resistance per length | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: ASRC +TITLE: ASRC: Arbitrary Source +TEXT: H +TEXT: H _B._2. _A_S_R_C: _A_r_b_i_t_r_a_r_y _S_o_u_r_c_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| ASRC - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| i Current source | +TEXT: H| v Voltage source | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| ASRC - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| i Current through source | +TEXT: H| v Voltage across source | +TEXT: H| pos_node Positive Node | +TEXT: H| neg_node Negative Node | +TEXT: H ------------------------------------------------------------ + +SUBJECT: BJT +TITLE: BJT: Bipolar Junction Transistor +TEXT: H +TEXT: H _B._3. _B_J_T: _B_i_p_o_l_a_r _J_u_n_c_t_i_o_n _T_r_a_n_s_i_s_t_o_r +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BJT - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ic Initial condition vector | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BJT - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device initially off | +TEXT: H| icvbe Initial B-E voltage | +TEXT: H| icvce Initial C-E voltage | +TEXT: H| area Area factor | +TEXT: H| temp instance temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BJT - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| colnode Number of collector node | +TEXT: H| basenode Number of base node | +TEXT: H| emitnode Number of emitter node | +TEXT: H| substnode Number of substrate node | +TEXT: H ------------------------------------------------------------ +TEXT: H| colprimenode Internal collector node | +TEXT: H| baseprimenode Internal base node | +TEXT: H| emitprimenode Internal emitter node | +TEXT: H| ic Current at collector node | +TEXT: H|-----------------------------------------------------------+ +TEXT: H ib Current at base node +TEXT: H| ie Emitter current | +TEXT: H| is Substrate current | +TEXT: H| vbe B-E voltage | +TEXT: H ------------------------------------------------------------ +TEXT: H| vbc B-C voltage | +TEXT: H| gm Small signal transconductance | +TEXT: H| gpi Small signal input conductance - pi | +TEXT: H| gmu Small signal conductance - mu | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gx Conductance from base to internal base | +TEXT: H| go Small signal output conductance | +TEXT: H| geqcb d(Ibe)/d(Vbc) | +TEXT: H| gccs Internal C-S cap. equiv. cond. | +TEXT: H ------------------------------------------------------------ +TEXT: H| geqbx Internal C-B-base cap. equiv. cond. | +TEXT: H| cpi Internal base to emitter capactance | +TEXT: H| cmu Internal base to collector capactiance | +TEXT: H| cbx Base to collector capacitance | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ccs Collector to substrate capacitance | +TEXT: H| cqbe Cap. due to charge storage in B-E jct. | +TEXT: H| cqbc Cap. due to charge storage in B-C jct. | +TEXT: H| cqcs Cap. due to charge storage in C-S jct. | +TEXT: H| cqbx Cap. due to charge storage in B-X jct. | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BJT - instance output-only parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cexbc Total Capacitance in B-X junction | +TEXT: H| qbe Charge storage B-E junction | +TEXT: H| qbc Charge storage B-C junction | +TEXT: H| qcs Charge storage C-S junction | +TEXT: H| qbx Charge storage B-X junction | +TEXT: H| p Power dissipation | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BJT - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| npn NPN type device | +TEXT: H| pnp PNP type device | +TEXT: H| is Saturation Current | +TEXT: H| bf Ideal forward beta | +TEXT: H ------------------------------------------------------------ +TEXT: H| nf Forward emission coefficient | +TEXT: H| vaf Forward Early voltage | +TEXT: H| va (null) | +TEXT: H| ikf Forward beta roll-off corner current | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ik (null) | +TEXT: H| ise B-E leakage saturation current | +TEXT: H| ne B-E leakage emission coefficient | +TEXT: H| br Ideal reverse beta | +TEXT: H ------------------------------------------------------------ +TEXT: H| nr Reverse emission coefficient | +TEXT: H| var Reverse Early voltage | +TEXT: H| vb (null) | +TEXT: H| ikr reverse beta roll-off corner current | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| isc B-C leakage saturation current | +TEXT: H| nc B-C leakage emission coefficient | +TEXT: H| rb Zero bias base resistance | +TEXT: H| irb Current for base resistance=(rb+rbm)/2 | +TEXT: H ------------------------------------------------------------ +TEXT: H| rbm Minimum base resistance | +TEXT: H| re Emitter resistance | +TEXT: H| rc Collector resistance | +TEXT: H| cje Zero bias B-E depletion capacitance | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vje B-E built in potential | +TEXT: H| pe (null) | +TEXT: H| mje B-E junction grading coefficient | +TEXT: H| me (null) | +TEXT: H ------------------------------------------------------------ +TEXT: H| tf Ideal forward transit time | +TEXT: H| xtf Coefficient for bias dependence of TF | +TEXT: H| vtf Voltage giving VBC dependence of TF | +TEXT: H| itf High current dependence of TF | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ptf Excess phase | +TEXT: H| cjc Zero bias B-C depletion capacitance | +TEXT: H| vjc B-C built in potential | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BJT - model input-output parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pc (null) | +TEXT: H| mjc B-C junction grading coefficient | +TEXT: H| mc (null) | +TEXT: H| xcjc Fraction of B-C cap to internal base | +TEXT: H ------------------------------------------------------------ +TEXT: H| tr Ideal reverse transit time | +TEXT: H| cjs Zero bias C-S capacitance | +TEXT: H| ccs Zero bias C-S capacitance | +TEXT: H| vjs Substrate junction built in potential | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ps (null) | +TEXT: H| mjs Substrate junction grading coefficient | +TEXT: H| ms (null) | +TEXT: H| xtb Forward and reverse beta temp. exp. | +TEXT: H ------------------------------------------------------------ +TEXT: H| eg Energy gap for IS temp. dependency | +TEXT: H| xti Temp. exponent for IS | +TEXT: H| fc Forward bias junction fit parameter | +TEXT: H| tnom Parameter measurement temperature | +TEXT: H| kf Flicker Noise Coefficient | +TEXT: H| af Flicker Noise Exponent | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BJT - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| type NPN or PNP | +TEXT: H| invearlyvoltf Inverse early voltage:forward | +TEXT: H| invearlyvoltr Inverse early voltage:reverse | +TEXT: H| invrollofff Inverse roll off - forward | +TEXT: H ------------------------------------------------------------ +TEXT: H| invrolloffr Inverse roll off - reverse | +TEXT: H| collectorconduct Collector conductance | +TEXT: H| emitterconduct Emitter conductance | +TEXT: H| transtimevbcfact Transit time VBC factor | +TEXT: H| excessphasefactor Excess phase fact. | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: BSIM1 +TITLE: BSIM1: Berkeley Short Channel IGFET Model +TEXT: H +TEXT: H _B._4. _B_S_I_M_1: _B_e_r_k_e_l_e_y _S_h_o_r_t _C_h_a_n_n_e_l _I_G_F_E_T _M_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM1 - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ic Vector of DS,GS,BS initial voltages | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM1 - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| l Length | +TEXT: H| w Width | +TEXT: H| ad Drain area | +TEXT: H| as Source area | +TEXT: H ------------------------------------------------------------ +TEXT: H| pd Drain perimeter | +TEXT: H| ps Source perimeter | +TEXT: H| nrd Number of squares in drain | +TEXT: H| nrs Number of squares in source | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device is initially off | +TEXT: H| vds Initial D-S voltage | +TEXT: H| vgs Initial G-S voltage | +TEXT: H| vbs Initial B-S voltage | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM1 - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| nmos Flag to indicate NMOS | +TEXT: H| pmos Flag to indicate PMOS | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM1 - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vfb Flat band voltage | +TEXT: H lvfb Length dependence of vfb +TEXT: H| wvfb Width dependence of vfb | +TEXT: H| phi Strong inversion surface potential | +TEXT: H ------------------------------------------------------------ +TEXT: H| lphi Length dependence of phi | +TEXT: H| wphi Width dependence of phi | +TEXT: H| k1 Bulk effect coefficient 1 | +TEXT: H| lk1 Length dependence of k1 | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| wk1 Width dependence of k1 | +TEXT: H| k2 Bulk effect coefficient 2 | +TEXT: H| lk2 Length dependence of k2 | +TEXT: H| wk2 Width dependence of k2 | +TEXT: H ------------------------------------------------------------ +TEXT: H| eta VDS dependence of threshold voltage | +TEXT: H| leta Length dependence of eta | +TEXT: H| weta Width dependence of eta | +TEXT: H| x2e VBS dependence of eta | +TEXT: H| lx2e Length dependence of x2e | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H --------------------------------------------------------------------- +TEXT: H| BSIM1 - model input-output parameters - _c_o_n_t_i_n_u_e_d| +TEXT: H|--------------------------------------------------------------------+ +TEXT: H|wx2e Width dependence of x2e | +TEXT: H|x3e VDS dependence of eta | +TEXT: H|lx3e Length dependence of x3e | +TEXT: H|wx3e Width dependence of x3e | +TEXT: H --------------------------------------------------------------------- +TEXT: H|dl Channel length reduction in um | +TEXT: H|dw Channel width reduction in um | +TEXT: H|muz Zero field mobility at VDS=0 VGS=VTH | +TEXT: H|x2mz VBS dependence of muz | +TEXT: H|--------------------------------------------------------------------+ +TEXT: H|lx2mz Length dependence of x2mz | +TEXT: H|wx2mz Width dependence of x2mz | +TEXT: H mus Mobility at VDS=VDD VGS=VTH, channel length modulation +TEXT: H|lmus Length dependence of mus | +TEXT: H --------------------------------------------------------------------- +TEXT: H|wmus Width dependence of mus | +TEXT: H|x2ms VBS dependence of mus | +TEXT: H|lx2ms Length dependence of x2ms | +TEXT: H|wx2ms Width dependence of x2ms | +TEXT: H|--------------------------------------------------------------------+ +TEXT: H|x3ms VDS dependence of mus | +TEXT: H|lx3ms Length dependence of x3ms | +TEXT: H|wx3ms Width dependence of x3ms | +TEXT: H|u0 VGS dependence of mobility | +TEXT: H --------------------------------------------------------------------- +TEXT: H|lu0 Length dependence of u0 | +TEXT: H|wu0 Width dependence of u0 | +TEXT: H|x2u0 VBS dependence of u0 | +TEXT: H|lx2u0 Length dependence of x2u0 | +TEXT: H|--------------------------------------------------------------------+ +TEXT: H|wx2u0 Width dependence of x2u0 | +TEXT: H|u1 VDS depence of mobility, velocity saturation | +TEXT: H|lu1 Length dependence of u1 | +TEXT: H|wu1 Width dependence of u1 | +TEXT: H --------------------------------------------------------------------- +TEXT: H|x2u1 VBS depence of u1 | +TEXT: H|lx2u1 Length depence of x2u1 | +TEXT: H|wx2u1 Width depence of x2u1 | +TEXT: H|x3u1 VDS depence of u1 | +TEXT: H|--------------------------------------------------------------------+ +TEXT: H|lx3u1 Length dependence of x3u1 | +TEXT: H|wx3u1 Width depence of x3u1 | +TEXT: H|n0 Subthreshold slope | +TEXT: H ln0 Length dependence of n0 +TEXT: H --------------------------------------------------------------------- +TEXT: H|wn0 Width dependence of n0 | +TEXT: H|nb VBS dependence of subthreshold slope | +TEXT: H|lnb Length dependence of nb | +TEXT: H|wnb Width dependence of nb | +TEXT: H|--------------------------------------------------------------------+ +TEXT: H|nd VDS dependence of subthreshold slope | +TEXT: H|lnd Length dependence of nd | +TEXT: H|wnd Width dependence of nd | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H --------------------------------------------------------------------- +TEXT: H +TEXT: H +TEXT: H --------------------------------------------------------------------------- +TEXT: H| BSIM1 - model input-output parameters - _c_o_n_t_i_n_u_e_d | +TEXT: H|--------------------------------------------------------------------------+ +TEXT: H|tox Gate oxide thickness in um | +TEXT: H|temp Temperature in degree Celcius | +TEXT: H|vdd Supply voltage to specify mus | +TEXT: H|cgso Gate source overlap capacitance per unit channel width(m) | +TEXT: H --------------------------------------------------------------------------- +TEXT: H|cgdo Gate drain overlap capacitance per unit channel width(m) | +TEXT: H|cgbo Gate bulk overlap capacitance per unit channel length(m) | +TEXT: H|xpart Flag for channel charge partitioning | +TEXT: H|rsh Source drain diffusion sheet resistance in ohm per square | +TEXT: H|--------------------------------------------------------------------------+ +TEXT: H|js Source drain junction saturation current per unit area | +TEXT: H|pb Source drain junction built in potential | +TEXT: H mj Source drain bottom junction capacitance grading coefficient +TEXT: H|pbsw Source drain side junction capacitance built in potential | +TEXT: H --------------------------------------------------------------------------- +TEXT: H|mjsw Source drain side junction capacitance grading coefficient | +TEXT: H|cj Source drain bottom junction capacitance per unit area | +TEXT: H|cjsw Source drain side junction capacitance per unit area | +TEXT: H|wdf Default width of source drain diffusion in um | +TEXT: H|dell Length reduction of source drain diffusion | +TEXT: H --------------------------------------------------------------------------- +TEXT: H + +SUBJECT: BSIM2 +TITLE: BSIM2: Berkeley Short Channel IGFET Model +TEXT: H +TEXT: H _B._5. _B_S_I_M_2: _B_e_r_k_e_l_e_y _S_h_o_r_t _C_h_a_n_n_e_l _I_G_F_E_T _M_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM2 - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ic Vector of DS,GS,BS initial voltages | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM2 - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| l Length | +TEXT: H| w Width | +TEXT: H| ad Drain area | +TEXT: H| as Source area | +TEXT: H ------------------------------------------------------------ +TEXT: H| pd Drain perimeter | +TEXT: H| ps Source perimeter | +TEXT: H| nrd Number of squares in drain | +TEXT: H| nrs Number of squares in source | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device is initially off | +TEXT: H| vds Initial D-S voltage | +TEXT: H| vgs Initial G-S voltage | +TEXT: H| vbs Initial B-S voltage | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM2 - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| nmos Flag to indicate NMOS | +TEXT: H| pmos Flag to indicate PMOS | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM2 - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|vfb Flat band voltage | +TEXT: H|lvfb Length dependence of vfb | +TEXT: H|wvfb Width dependence of vfb | +TEXT: H|phi Strong inversion surface potential | +TEXT: H ------------------------------------------------------------ +TEXT: H|lphi Length dependence of phi | +TEXT: H|wphi Width dependence of phi | +TEXT: H|k1 Bulk effect coefficient 1 | +TEXT: H|lk1 Length dependence of k1 | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|wk1 Width dependence of k1 | +TEXT: H|k2 Bulk effect coefficient 2 | +TEXT: H|lk2 Length dependence of k2 | +TEXT: H|wk2 Width dependence of k2 | +TEXT: H ------------------------------------------------------------ +TEXT: H|eta0 VDS dependence of threshold voltage at VDD=0 +TEXT: H|leta0 Length dependence of eta0 | +TEXT: H|weta0 Width dependence of eta0 | +TEXT: H|etab VBS dependence of eta | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|letab Length dependence of etab | +TEXT: H|wetab Width dependence of etab | +TEXT: H|dl Channel length reduction in um | +TEXT: H|dw Channel width reduction in um | +TEXT: H ------------------------------------------------------------ +TEXT: H|mu0 Low-field mobility, at VDS=0 VGS=VTH | +TEXT: H|mu0b VBS dependence of low-field mobility | +TEXT: H|lmu0b Length dependence of mu0b | +TEXT: H|wmu0b Width dependence of mu0b | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|mus0 Mobility at VDS=VDD VGS=VTH | +TEXT: H|lmus0 Length dependence of mus0 | +TEXT: H|wmus0 Width dependence of mus | +TEXT: H|musb VBS dependence of mus | +TEXT: H ------------------------------------------------------------ +TEXT: H|lmusb Length dependence of musb | +TEXT: H|wmusb Width dependence of musb | +TEXT: H|mu20 VDS dependence of mu in tanh term | +TEXT: H|lmu20 Length dependence of mu20 | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|wmu20 Width dependence of mu20 | +TEXT: H|mu2b VBS dependence of mu2 | +TEXT: H|lmu2b Length dependence of mu2b | +TEXT: H|wmu2b Width dependence of mu2b | +TEXT: H ------------------------------------------------------------ +TEXT: H|mu2g VGS dependence of mu2 | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| BSIM2 - model input-output parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-----------------------------------------------------------+ +TEXT: H| lmu2g Length dependence of mu2g | +TEXT: H| wmu2g Width dependence of mu2g | +TEXT: H| mu30 VDS dependence of mu in linear term | +TEXT: H| lmu30 Length dependence of mu30 | +TEXT: H ------------------------------------------------------------ +TEXT: H| wmu30 Width dependence of mu30 | +TEXT: H| mu3b VBS dependence of mu3 | +TEXT: H| lmu3b Length dependence of mu3b | +TEXT: H| wmu3b Width dependence of mu3b | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| mu3g VGS dependence of mu3 | +TEXT: H| lmu3g Length dependence of mu3g | +TEXT: H| wmu3g Width dependence of mu3g | +TEXT: H| mu40 VDS dependence of mu in linear term | +TEXT: H ------------------------------------------------------------ +TEXT: H| lmu40 Length dependence of mu40 | +TEXT: H| wmu40 Width dependence of mu40 | +TEXT: H| mu4b VBS dependence of mu4 | +TEXT: H| lmu4b Length dependence of mu4b | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| wmu4b Width dependence of mu4b | +TEXT: H| mu4g VGS dependence of mu4 | +TEXT: H| lmu4g Length dependence of mu4g | +TEXT: H| wmu4g Width dependence of mu4g | +TEXT: H ------------------------------------------------------------ +TEXT: H| ua0 Linear VGS dependence of mobility | +TEXT: H| lua0 Length dependence of ua0 | +TEXT: H| wua0 Width dependence of ua0 | +TEXT: H| uab VBS dependence of ua | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| luab Length dependence of uab | +TEXT: H| wuab Width dependence of uab | +TEXT: H| ub0 Quadratic VGS dependence of mobility | +TEXT: H| lub0 Length dependence of ub0 | +TEXT: H ------------------------------------------------------------ +TEXT: H| wub0 Width dependence of ub0 | +TEXT: H| ubb VBS dependence of ub | +TEXT: H| lubb Length dependence of ubb | +TEXT: H| wubb Width dependence of ubb | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| u10 VDS depence of mobility | +TEXT: H| lu10 Length dependence of u10 | +TEXT: H wu10 Width dependence of u10 +TEXT: H| u1b VBS depence of u1 | +TEXT: H ------------------------------------------------------------ +TEXT: H| lu1b Length depence of u1b | +TEXT: H| wu1b Width depence of u1b | +TEXT: H| u1d VDS depence of u1 | +TEXT: H| lu1d Length depence of u1d | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| wu1d Width depence of u1d | +TEXT: H| n0 Subthreshold slope at VDS=0 VBS=0 | +TEXT: H| ln0 Length dependence of n0 | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------------------ +TEXT: H| BSIM2 - model input-output parameters - _c_o_n_t_i_n_u_e_d | +TEXT: H|-----------------------------------------------------------------------+ +TEXT: H|wn0 Width dependence of n0 | +TEXT: H|nb VBS dependence of n | +TEXT: H|lnb Length dependence of nb | +TEXT: H|wnb Width dependence of nb | +TEXT: H ------------------------------------------------------------------------ +TEXT: H|nd VDS dependence of n | +TEXT: H|lnd Length dependence of nd | +TEXT: H|wnd Width dependence of nd | +TEXT: H|vof0 Threshold voltage offset AT VDS=0 VBS=0 | +TEXT: H|-----------------------------------------------------------------------+ +TEXT: H|lvof0 Length dependence of vof0 | +TEXT: H|wvof0 Width dependence of vof0 | +TEXT: H|vofb VBS dependence of vof | +TEXT: H|lvofb Length dependence of vofb | +TEXT: H ------------------------------------------------------------------------ +TEXT: H|wvofb Width dependence of vofb | +TEXT: H|vofd VDS dependence of vof | +TEXT: H|lvofd Length dependence of vofd | +TEXT: H|wvofd Width dependence of vofd | +TEXT: H|-----------------------------------------------------------------------+ +TEXT: H|ai0 Pre-factor of hot-electron effect. | +TEXT: H|lai0 Length dependence of ai0 | +TEXT: H|wai0 Width dependence of ai0 | +TEXT: H|aib VBS dependence of ai | +TEXT: H ------------------------------------------------------------------------ +TEXT: H|laib Length dependence of aib | +TEXT: H|waib Width dependence of aib | +TEXT: H|bi0 Exponential factor of hot-electron effect. | +TEXT: H|lbi0 Length dependence of bi0 | +TEXT: H|-----------------------------------------------------------------------+ +TEXT: H|wbi0 Width dependence of bi0 | +TEXT: H|bib VBS dependence of bi | +TEXT: H|lbib Length dependence of bib | +TEXT: H|wbib Width dependence of bib | +TEXT: H ------------------------------------------------------------------------ +TEXT: H|vghigh Upper bound of the cubic spline function. | +TEXT: H|lvghigh Length dependence of vghigh | +TEXT: H|wvghigh Width dependence of vghigh | +TEXT: H|vglow Lower bound of the cubic spline function. | +TEXT: H|-----------------------------------------------------------------------+ +TEXT: H|lvglow Length dependence of vglow | +TEXT: H|wvglow Width dependence of vglow | +TEXT: H|tox Gate oxide thickness in um | +TEXT: H|temp Temperature in degree Celcius | +TEXT: H ------------------------------------------------------------------------ +TEXT: H|vdd Maximum Vds | +TEXT: H|vgg Maximum Vgs | +TEXT: H|vbb Maximum Vbs | +TEXT: H|cgso Gate source overlap capacitance per unit channel width(m) +TEXT: H|-----------------------------------------------------------------------+ +TEXT: H|cgdo Gate drain overlap capacitance per unit channel width(m)| +TEXT: H|cgbo Gate bulk overlap capacitance per unit channel length(m)| +TEXT: H|xpart Flag for channel charge partitioning | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H --------------------------------------------------------------------------- +TEXT: H| BSIM2 - model input-output parameters - _c_o_n_t_i_n_u_e_d | +TEXT: H|--------------------------------------------------------------------------+ +TEXT: H|rsh Source drain diffusion sheet resistance in ohm per square | +TEXT: H|js Source drain junction saturation current per unit area | +TEXT: H|pb Source drain junction built in potential | +TEXT: H mj Source drain bottom junction capacitance grading coefficient +TEXT: H| | +TEXT: H --------------------------------------------------------------------------- +TEXT: H|pbsw Source drain side junction capacitance built in potential | +TEXT: H|mjsw Source drain side junction capacitance grading coefficient | +TEXT: H|cj Source drain bottom junction capacitance per unit area | +TEXT: H|cjsw Source drain side junction capacitance per unit area | +TEXT: H|wdf Default width of source drain diffusion in um | +TEXT: H|dell Length reduction of source drain diffusion | +TEXT: H --------------------------------------------------------------------------- +TEXT: H + +SUBJECT: Capacitor +TITLE: Capacitor: Fixed capacitor +TEXT: H +TEXT: H _B._6. _C_a_p_a_c_i_t_o_r: _F_i_x_e_d _c_a_p_a_c_i_t_o_r +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Capacitor - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| capacitance Device capacitance | +TEXT: H| ic Initial capacitor voltage | +TEXT: H| w Device width | +TEXT: H| l Device length | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Capacitor - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| i Device current | +TEXT: H| p Instantaneous device power | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Capacitor - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| c Capacitor model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Capacitor - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cj Bottom Capacitance per area | +TEXT: H| cjsw Sidewall capacitance per meter | +TEXT: H| defw Default width | +TEXT: H| narrow width correction factor | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: CCCS +TITLE: CCCS: Current controlled current source +TEXT: H +TEXT: H _B._7. _C_C_C_S: _C_u_r_r_e_n_t _c_o_n_t_r_o_l_l_e_d _c_u_r_r_e_n_t _s_o_u_r_c_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CCCS - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gain Gain of source | +TEXT: H| control Name of controlling source | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CCCS - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| neg_node Negative node of source | +TEXT: H| pos_node Positive node of source | +TEXT: H| i CCCS output current | +TEXT: H| v CCCS voltage at output | +TEXT: H| p CCCS power | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: CCVS +TITLE: CCVS: Linear current controlled current source +TEXT: H +TEXT: H _B._8. _C_C_V_S: _L_i_n_e_a_r _c_u_r_r_e_n_t _c_o_n_t_r_o_l_l_e_d _c_u_r_r_e_n_t _s_o_u_r_c_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CCVS - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gain Transresistance (gain) | +TEXT: H| control Controlling voltage source | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CCVS - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node Positive node of source | +TEXT: H| neg_node Negative node of source | +TEXT: H| i CCVS output current | +TEXT: H| v CCVS output voltage | +TEXT: H| p CCVS power | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: CSwitch +TITLE: CSwitch: Current controlled ideal switch +TEXT: H +TEXT: H _B._9. _C_S_w_i_t_c_h: _C_u_r_r_e_n_t _c_o_n_t_r_o_l_l_e_d _i_d_e_a_l _s_w_i_t_c_h +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CSwitch - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| on Initially closed | +TEXT: H| off Initially open | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CSwitch - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| control Name of controlling source | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CSwitch - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node Positive node of switch | +TEXT: H| neg_node Negative node of switch | +TEXT: H| i Switch current | +TEXT: H| p Instantaneous power | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CSwitch - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| csw Current controlled switch model | +TEXT: H| it Threshold current | +TEXT: H| ih Hysterisis current | +TEXT: H| ron Closed resistance | +TEXT: H| roff Open resistance | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| CSwitch - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gon Closed conductance | +TEXT: H| goff Open conductance | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Diode +TITLE: Diode: Junction Diode model +TEXT: H +TEXT: H _B._1_0. _D_i_o_d_e: _J_u_n_c_t_i_o_n _D_i_o_d_e _m_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Diode - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Initially off | +TEXT: H| temp Instance temperature | +TEXT: H| ic Initial device voltage | +TEXT: H| area Area factor | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Diode - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vd Diode voltage | +TEXT: H| id Diode current | +TEXT: H| c Diode current | +TEXT: H| gd Diode conductance | +TEXT: H ------------------------------------------------------------ +TEXT: H| cd Diode capacitance | +TEXT: H| charge Diode capacitor charge | +TEXT: H| capcur Diode capacitor current | +TEXT: H| p Diode power | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Diode - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| d Diode model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Diode - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| is Saturation current | +TEXT: H| tnom Parameter measurement temperature | +TEXT: H| rs Ohmic resistance | +TEXT: H| n Emission Coefficient | +TEXT: H ------------------------------------------------------------ +TEXT: H| tt Transit Time | +TEXT: H| cjo Junction capacitance | +TEXT: H| cj0 (null) | +TEXT: H| vj Junction potential | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| m Grading coefficient | +TEXT: H| eg Activation energy | +TEXT: H| xti Saturation current temperature exp. | +TEXT: H| kf flicker noise coefficient | +TEXT: H ------------------------------------------------------------ +TEXT: H| af flicker noise exponent | +TEXT: H| fc Forward bias junction fit parameter | +TEXT: H| bv Reverse breakdown voltage | +TEXT: H| ibv Current at reverse breakdown voltage | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Diode - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cond Ohmic conductance | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Inductor +TITLE: Inductor: Inductors +TEXT: H +TEXT: H _B._1_1. _I_n_d_u_c_t_o_r: _I_n_d_u_c_t_o_r_s +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Inductor - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| inductance Inductance of inductor | +TEXT: H| ic Initial current through inductor | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------- +TEXT: H| Inductor - instance parameters (output-only) | +TEXT: H|------------------------------------------------------------+ +TEXT: H|flux Flux through inductor | +TEXT: H|v Terminal voltage of inductor | +TEXT: H|volt | +TEXT: H|i Current through the inductor | +TEXT: H|current | +TEXT: H p instantaneous power dissipated by the inductor +TEXT: H| | +TEXT: H ------------------------------------------------------------- +TEXT: H + +SUBJECT: mutual +TITLE: mutual: Mutual inductors +TEXT: H +TEXT: H _B._1_2. _m_u_t_u_a_l: _M_u_t_u_a_l _i_n_d_u_c_t_o_r_s +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| mutual - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| k Mutual inductance | +TEXT: H| coefficient (null) | +TEXT: H| inductor1 First coupled inductor | +TEXT: H| inductor2 Second coupled inductor | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Isource +TITLE: Isource: Independent current source +TEXT: H +TEXT: H _B._1_3. _I_s_o_u_r_c_e: _I_n_d_e_p_e_n_d_e_n_t _c_u_r_r_e_n_t _s_o_u_r_c_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Isource - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pulse Pulse description | +TEXT: H| sine Sinusoidal source description | +TEXT: H| sin Sinusoidal source description | +TEXT: H| exp Exponential source description | +TEXT: H ------------------------------------------------------------ +TEXT: H| pwl Piecewise linear description | +TEXT: H| sffm single freq. FM description | +TEXT: H| ac AC magnitude,phase vector | +TEXT: H| c Current through current source | +TEXT: H| distof1 f1 input for distortion | +TEXT: H| distof2 f2 input for distortion | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Isource - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| dc DC value of source | +TEXT: H| acmag AC magnitude | +TEXT: H| acphase AC phase | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Isource - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| neg_node Negative node of source | +TEXT: H| pos_node Positive node of source | +TEXT: H acreal AC real part +TEXT: H| acimag AC imaginary part | +TEXT: H ------------------------------------------------------------ +TEXT: H| function Function of the source | +TEXT: H| order Order of the source function | +TEXT: H| coeffs Coefficients of the source | +TEXT: H| v Voltage across the supply | +TEXT: H| p Power supplied by the source | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: JFET +TITLE: JFET: Junction Field effect transistor +TEXT: H +TEXT: H _B._1_4. _J_F_E_T: _J_u_n_c_t_i_o_n _F_i_e_l_d _e_f_f_e_c_t _t_r_a_n_s_i_s_t_o_r +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| JFET - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device initially off | +TEXT: H| ic Initial VDS,VGS vector | +TEXT: H| area Area factor | +TEXT: H| ic-vds Initial D-S voltage | +TEXT: H| ic-vgs Initial G-S volrage | +TEXT: H| temp Instance temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H --------------------------------------------------------------- +TEXT: H| JFET - instance parameters (output-only) | +TEXT: H|--------------------------------------------------------------+ +TEXT: H|drain-node Number of drain node | +TEXT: H|gate-node Number of gate node | +TEXT: H|source-node Number of source node | +TEXT: H|drain-prime-node Internal drain node | +TEXT: H --------------------------------------------------------------- +TEXT: H|source-prime-nodeInternal source node | +TEXT: H|vgs Voltage G-S | +TEXT: H|vgd Voltage G-D | +TEXT: H|ig Current at gate node | +TEXT: H|--------------------------------------------------------------+ +TEXT: H|id Current at drain node | +TEXT: H|is Source current | +TEXT: H|igd Current G-D | +TEXT: H|gm Transconductance | +TEXT: H --------------------------------------------------------------- +TEXT: H|gds Conductance D-S | +TEXT: H|ggs Conductance G-S | +TEXT: H|ggd Conductance G-D | +TEXT: H|qgs Charge storage G-S junction | +TEXT: H|--------------------------------------------------------------+ +TEXT: H|qgd Charge storage G-D junction | +TEXT: H cqgs Capacitance due to charge storage G-S junction +TEXT: H| | +TEXT: H cqgd Capacitance due to charge storage G-D junction +TEXT: H|p Power dissipated by the JFET | +TEXT: H --------------------------------------------------------------- +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| JFET - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| njf N type JFET model | +TEXT: H| pjf P type JFET model | +TEXT: H| vt0 Threshold voltage | +TEXT: H| vto (null) | +TEXT: H ------------------------------------------------------------ +TEXT: H| beta Transconductance parameter | +TEXT: H| lambda Channel length modulation param. | +TEXT: H| rd Drain ohmic resistance | +TEXT: H| rs Source ohmic resistance | +TEXT: H| cgs G-S junction capactance | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| JFET - model input-output parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cgd G-D junction cap | +TEXT: H| pb Gate junction potential | +TEXT: H| is Gate junction saturation current | +TEXT: H| fc Forward bias junction fit parm. | +TEXT: H ------------------------------------------------------------ +TEXT: H| b Doping tail parameter | +TEXT: H| tnom parameter measurement temperature | +TEXT: H| kf Flicker Noise Coefficient | +TEXT: H| af Flicker Noise Exponent | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| JFET - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| type N-type or P-type JFET model | +TEXT: H| gd Drain conductance | +TEXT: H| gs Source conductance | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: LTRA +TITLE: LTRA: Lossy transmission line +TEXT: H +TEXT: H _B._1_5. _L_T_R_A: _L_o_s_s_y _t_r_a_n_s_m_i_s_s_i_o_n _l_i_n_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| LTRA - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ic Initial condition vector:v1,i1,v2,i2 | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| LTRA - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| v1 Initial voltage at end 1 | +TEXT: H| v2 Initial voltage at end 2 | +TEXT: H| i1 Initial current at end 1 | +TEXT: H| i2 Initial current at end 2 | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| LTRA - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node1 Positive node of end 1 of t-line | +TEXT: H| neg_node1 Negative node of end 1 of t.line | +TEXT: H| pos_node2 Positive node of end 2 of t-line | +TEXT: H| neg_node2 Negative node of end 2 of t-line | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| LTRA - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|ltra LTRA model | +TEXT: H|r Resistance per metre | +TEXT: H|l Inductance per metre | +TEXT: H|g (null) | +TEXT: H ------------------------------------------------------------ +TEXT: H|c Capacitance per metre | +TEXT: H|len length of line | +TEXT: H|nocontrol No timestep control | +TEXT: H|steplimit always limit timestep to 0.8*(delay of line) +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H ----------------------------------------------------------------------------------- +TEXT: H| LTRA - model input-output parameters - _c_o_n_t_i_n_u_e_d | +TEXT: H|----------------------------------------------------------------------------------+ +TEXT: H|nosteplimit don't always limit timestep to 0.8*(delay of line) | +TEXT: H|lininterp use linear interpolation | +TEXT: H|quadinterp use quadratic interpolation | +TEXT: H|mixedinterp use linear interpolation if quadratic results look unacceptable | +TEXT: H ----------------------------------------------------------------------------------- +TEXT: H|truncnr use N-R iterations for step calculation in LTRAtrunc | +TEXT: H|truncdontcut don't limit timestep to keep impulse response calculation errors low +TEXT: H|compactrel special reltol for straight line checking | +TEXT: H|compactabs special abstol for straight line checking | +TEXT: H ----------------------------------------------------------------------------------- +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| LTRA - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| rel Rel. rate of change of deriv. for bkpt | +TEXT: H| abs Abs. rate of change of deriv. for bkpt | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: MES +TITLE: MES: GaAs MESFET model +TEXT: H +TEXT: H _B._1_6. _M_E_S: _G_a_A_s _M_E_S_F_E_T _m_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| MES - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| area Area factor | +TEXT: H| icvds Initial D-S voltage | +TEXT: H| icvgs Initial G-S voltage | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| MES - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|off Device initially off | +TEXT: H|dnode Number of drain node | +TEXT: H|gnode Number of gate node | +TEXT: H|snode Number of source node | +TEXT: H ------------------------------------------------------------ +TEXT: H|dprimenode Number of internal drain node | +TEXT: H|sprimenode Number of internal source node | +TEXT: H|vgs Gate-Source voltage | +TEXT: H|vgd Gate-Drain voltage | +TEXT: H|-----------------------------------------------------------+ +TEXT: H|cg Gate capacitance | +TEXT: H|cd Drain capacitance | +TEXT: H|cgd Gate-Drain capacitance | +TEXT: H|gm Transconductance | +TEXT: H ------------------------------------------------------------ +TEXT: H|gds Drain-Source conductance | +TEXT: H|ggs Gate-Source conductance | +TEXT: H|ggd Gate-Drain conductance | +TEXT: H|cqgs Capacitance due to gate-source charge storage +TEXT: H|-----------------------------------------------------------+ +TEXT: H|cqgd Capacitance due to gate-drain charge storage| +TEXT: H|qgs Gate-Source charge storage | +TEXT: H|qgd Gate-Drain charge storage | +TEXT: H|is Source current | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| MES - instance output-only parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-----------------------------------------------------------+ +TEXT: H| p Power dissipated by the mesfet | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| MES - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| nmf N type MESfet model | +TEXT: H| pmf P type MESfet model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| MES - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vt0 Pinch-off voltage | +TEXT: H| vto (null) | +TEXT: H| alpha Saturation voltage parameter | +TEXT: H| beta Transconductance parameter | +TEXT: H ------------------------------------------------------------ +TEXT: H| lambda Channel length modulation parm. | +TEXT: H| b Doping tail extending parameter | +TEXT: H| rd Drain ohmic resistance | +TEXT: H| rs Source ohmic resistance | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cgs G-S junction capacitance | +TEXT: H| cgd G-D junction capacitance | +TEXT: H| pb Gate junction potential | +TEXT: H| is Junction saturation current | +TEXT: H ------------------------------------------------------------ +TEXT: H| fc Forward bias junction fit parm. | +TEXT: H| kf Flicker noise coefficient | +TEXT: H| af Flicker noise exponent | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| MES - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| type N-type or P-type MESfet model | +TEXT: H| gd Drain conductance | +TEXT: H| gs Source conductance | +TEXT: H| depl_cap Depletion capacitance | +TEXT: H| vcrit Critical voltage | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Mos1 +TITLE: Mos1: Level 1 MOSfet model with Meyer capacitance model +TEXT: H +TEXT: H _B._1_7. _M_o_s_1: _L_e_v_e_l _1 _M_O_S_f_e_t _m_o_d_e_l _w_i_t_h _M_e_y_e_r _c_a_p_a_c_i_t_a_n_c_e +TEXT: H _m_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos1 - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device initially off | +TEXT: H| ic Vector of D-S, G-S, B-S voltages | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos1 - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| l Length | +TEXT: H| w Width | +TEXT: H| ad Drain area | +TEXT: H| as Source area | +TEXT: H ------------------------------------------------------------ +TEXT: H| pd Drain perimeter | +TEXT: H| ps Source perimeter | +TEXT: H| nrd Drain squares | +TEXT: H| nrs Source squares | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| icvds Initial D-S voltage | +TEXT: H| icvgs Initial G-S voltage | +TEXT: H| icvbs Initial B-S voltage | +TEXT: H| temp Instance temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos1 - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| id Drain current | +TEXT: H| is Source current | +TEXT: H| ig Gate current | +TEXT: H| ib Bulk current | +TEXT: H ------------------------------------------------------------ +TEXT: H| ibd B-D junction current | +TEXT: H| ibs B-S junction current | +TEXT: H| vgs Gate-Source voltage | +TEXT: H| vds Drain-Source voltage | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vbs Bulk-Source voltage | +TEXT: H| vbd Bulk-Drain voltage | +TEXT: H| dnode Number of the drain node | +TEXT: H| gnode Number of the gate node | +TEXT: H ------------------------------------------------------------ +TEXT: H| snode Number of the source node | +TEXT: H| bnode Number of the node | +TEXT: H| dnodeprime Number of int. drain node | +TEXT: H| snodeprime Number of int. source node | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| von | +TEXT: H| vdsat Saturation drain voltage | +TEXT: H| sourcevcrit Critical source voltage | +TEXT: H| drainvcrit Critical drain voltage | +TEXT: H| rs Source resistance | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H -------------------------------------------------------------- +TEXT: H| Mos1 - instance output-only parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-------------------------------------------------------------+ +TEXT: H|sourceconductanceConductance of source | +TEXT: H|rd Drain conductance | +TEXT: H|drainconductance Conductance of drain | +TEXT: H|gm Transconductance | +TEXT: H -------------------------------------------------------------- +TEXT: H|gds Drain-Source conductance | +TEXT: H|gmb Bulk-Source transconductance | +TEXT: H|gmbs | +TEXT: H|gbd Bulk-Drain conductance | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|gbs Bulk-Source conductance | +TEXT: H|cbd Bulk-Drain capacitance | +TEXT: H|cbs Bulk-Source capacitance | +TEXT: H|cgs Gate-Source capacitance | +TEXT: H -------------------------------------------------------------- +TEXT: H|cgd Gate-Drain capacitance | +TEXT: H|cgb Gate-Bulk capacitance | +TEXT: H|cqgs Capacitance due to gate-source charge storage +TEXT: H|cqgd Capacitance due to gate-drain charge storage| +TEXT: H|-------------------------------------------------------------+ +TEXT: H|cqgb Capacitance due to gate-bulk charge storage | +TEXT: H|cqbd Capacitance due to bulk-drain charge storage| +TEXT: H cqbs Capacitance due to bulk-source charge storage +TEXT: H|cbd0 Zero-Bias B-D junction capacitance | +TEXT: H -------------------------------------------------------------- +TEXT: H|cbdsw0 | +TEXT: H|cbs0 Zero-Bias B-S junction capacitance | +TEXT: H|cbssw0 | +TEXT: H|qgs Gate-Source charge storage | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|qgd Gate-Drain charge storage | +TEXT: H|qgb Gate-Bulk charge storage | +TEXT: H|qbd Bulk-Drain charge storage | +TEXT: H|qbs Bulk-Source charge storage | +TEXT: H|p Instaneous power | +TEXT: H -------------------------------------------------------------- +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos1 - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| nmos N type MOSfet model | +TEXT: H| pmos P type MOSfet model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos1 - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vto Threshold voltage | +TEXT: H| vt0 (null) | +TEXT: H| kp Transconductance parameter | +TEXT: H| gamma Bulk threshold parameter | +TEXT: H ------------------------------------------------------------ +TEXT: H| phi Surface potential | +TEXT: H| lambda Channel length modulation | +TEXT: H| rd Drain ohmic resistance | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos1 - model input-output parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-----------------------------------------------------------+ +TEXT: H| rs Source ohmic resistance | +TEXT: H| cbd B-D junction capacitance | +TEXT: H| cbs B-S junction capacitance | +TEXT: H| is Bulk junction sat. current | +TEXT: H ------------------------------------------------------------ +TEXT: H| pb Bulk junction potential | +TEXT: H| cgso Gate-source overlap cap. | +TEXT: H| cgdo Gate-drain overlap cap. | +TEXT: H| cgbo Gate-bulk overlap cap. | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| rsh Sheet resistance | +TEXT: H| cj Bottom junction cap per area | +TEXT: H| mj Bottom grading coefficient | +TEXT: H| cjsw Side junction cap per area | +TEXT: H ------------------------------------------------------------ +TEXT: H| mjsw Side grading coefficient | +TEXT: H| js Bulk jct. sat. current density | +TEXT: H| tox Oxide thickness | +TEXT: H| ld Lateral diffusion | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| u0 Surface mobility | +TEXT: H| uo (null) | +TEXT: H| fc Forward bias jct. fit parm. | +TEXT: H| nsub Substrate doping | +TEXT: H ------------------------------------------------------------ +TEXT: H| tpg Gate type | +TEXT: H| nss Surface state density | +TEXT: H| tnom Parameter measurement temperature | +TEXT: H| kf Flicker noise coefficient | +TEXT: H| af Flicker noise exponent | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos1 - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| type N-channel or P-channel MOS | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Mos2 +TITLE: Mos2: Level 2 MOSfet model with Meyer capacitance model +TEXT: H +TEXT: H _B._1_8. _M_o_s_2: _L_e_v_e_l _2 _M_O_S_f_e_t _m_o_d_e_l _w_i_t_h _M_e_y_e_r _c_a_p_a_c_i_t_a_n_c_e +TEXT: H _m_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos2 - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device initially off | +TEXT: H| ic Vector of D-S, G-S, B-S voltages | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos2 - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| l Length | +TEXT: H| w Width | +TEXT: H| ad Drain area | +TEXT: H| as Source area | +TEXT: H ------------------------------------------------------------ +TEXT: H| pd Drain perimeter | +TEXT: H| ps Source perimeter | +TEXT: H| nrd Drain squares | +TEXT: H| nrs Source squares | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| icvds Initial D-S voltage | +TEXT: H| icvgs Initial G-S voltage | +TEXT: H| icvbs Initial B-S voltage | +TEXT: H| temp Instance operating temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos2 - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| id Drain current | +TEXT: H| cd | +TEXT: H| ibd B-D junction current | +TEXT: H| ibs B-S junction current | +TEXT: H ------------------------------------------------------------ +TEXT: H| is Source current | +TEXT: H| ig Gate current | +TEXT: H| ib Bulk current | +TEXT: H| vgs Gate-Source voltage | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vds Drain-Source voltage | +TEXT: H| vbs Bulk-Source voltage | +TEXT: H| vbd Bulk-Drain voltage | +TEXT: H| dnode Number of drain node | +TEXT: H ------------------------------------------------------------ +TEXT: H| gnode Number of gate node | +TEXT: H| snode Number of source node | +TEXT: H| bnode Number of bulk node | +TEXT: H| dnodeprime Number of internal drain node | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| snodeprime Number of internal source node | +TEXT: H| von | +TEXT: H| vdsat Saturation drain voltage | +TEXT: H| sourcevcrit Critical source voltage | +TEXT: H| drainvcrit Critical drain voltage | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H -------------------------------------------------------------- +TEXT: H| Mos2 - instance output-only parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-------------------------------------------------------------+ +TEXT: H|rs Source resistance | +TEXT: H|sourceconductanceSource conductance | +TEXT: H|rd Drain resistance | +TEXT: H|drainconductance Drain conductance | +TEXT: H -------------------------------------------------------------- +TEXT: H|gm Transconductance | +TEXT: H|gds Drain-Source conductance | +TEXT: H|gmb Bulk-Source transconductance | +TEXT: H|gmbs | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|gbd Bulk-Drain conductance | +TEXT: H|gbs Bulk-Source conductance | +TEXT: H|cbd Bulk-Drain capacitance | +TEXT: H|cbs Bulk-Source capacitance | +TEXT: H -------------------------------------------------------------- +TEXT: H|cgs Gate-Source capacitance | +TEXT: H|cgd Gate-Drain capacitance | +TEXT: H|cgb Gate-Bulk capacitance | +TEXT: H|cbd0 Zero-Bias B-D junction capacitance | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|cbdsw0 | +TEXT: H|cbs0 Zero-Bias B-S junction capacitance | +TEXT: H|cbssw0 | +TEXT: H cqgs Capacitance due to gate-source charge storage +TEXT: H| | +TEXT: H -------------------------------------------------------------- +TEXT: H|cqgd Capacitance due to gate-drain charge storage| +TEXT: H|cqgb Capacitance due to gate-bulk charge storage | +TEXT: H|cqbd Capacitance due to bulk-drain charge storage| +TEXT: H|cqbs Capacitance due to bulk-source charge storage +TEXT: H|-------------------------------------------------------------+ +TEXT: H|qgs Gate-Source charge storage | +TEXT: H|qgd Gate-Drain charge storage | +TEXT: H|qgb Gate-Bulk charge storage | +TEXT: H|qbd Bulk-Drain charge storage | +TEXT: H|qbs Bulk-Source charge storage | +TEXT: H|p Instantaneous power | +TEXT: H -------------------------------------------------------------- +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos2 - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| nmos N type MOSfet model | +TEXT: H| pmos P type MOSfet model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos2 - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vto Threshold voltage | +TEXT: H| vt0 (null) | +TEXT: H| kp Transconductance parameter | +TEXT: H| gamma Bulk threshold parameter | +TEXT: H ------------------------------------------------------------ +TEXT: H| phi Surface potential | +TEXT: H| lambda Channel length modulation | +TEXT: H| rd Drain ohmic resistance | +TEXT: H| rs Source ohmic resistance | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cbd B-D junction capacitance | +TEXT: H| cbs B-S junction capacitance | +TEXT: H| is Bulk junction sat. current | +TEXT: H| pb Bulk junction potential | +TEXT: H ------------------------------------------------------------ +TEXT: H| cgso Gate-source overlap cap. | +TEXT: H| cgdo Gate-drain overlap cap. | +TEXT: H| cgbo Gate-bulk overlap cap. | +TEXT: H| rsh Sheet resistance | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cj Bottom junction cap per area | +TEXT: H| mj Bottom grading coefficient | +TEXT: H| cjsw Side junction cap per area | +TEXT: H| mjsw Side grading coefficient | +TEXT: H ------------------------------------------------------------ +TEXT: H| js Bulk jct. sat. current density | +TEXT: H| tox Oxide thickness | +TEXT: H| ld Lateral diffusion | +TEXT: H| u0 Surface mobility | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| uo (null) | +TEXT: H| fc Forward bias jct. fit parm. | +TEXT: H| nsub Substrate doping | +TEXT: H| tpg Gate type | +TEXT: H ------------------------------------------------------------ +TEXT: H| nss Surface state density | +TEXT: H| delta Width effect on threshold | +TEXT: H| uexp Crit. field exp for mob. deg. | +TEXT: H| ucrit Crit. field for mob. degradation | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vmax Maximum carrier drift velocity | +TEXT: H| xj Junction depth | +TEXT: H| neff Total channel charge coeff. | +TEXT: H| nfs Fast surface state density | +TEXT: H ------------------------------------------------------------ +TEXT: H| tnom Parameter measurement temperature | +TEXT: H| kf Flicker noise coefficient | +TEXT: H| af Flicker noise exponent | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos2 - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| type N-channel or P-channel MOS | +TEXT: H ------------------------------------------------------------ + +SUBJECT: Mos3 +TITLE: Mos3: Level 3 MOSfet model with Meyer capacitance model +TEXT: H +TEXT: H _B._1_9. _M_o_s_3: _L_e_v_e_l _3 _M_O_S_f_e_t _m_o_d_e_l _w_i_t_h _M_e_y_e_r _c_a_p_a_c_i_t_a_n_c_e +TEXT: H _m_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos3 - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device initially off | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos3 - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| l Length | +TEXT: H| w Width | +TEXT: H| ad Drain area | +TEXT: H| as Source area | +TEXT: H ------------------------------------------------------------ +TEXT: H| pd Drain perimeter | +TEXT: H| ps Source perimeter | +TEXT: H| nrd Drain squares | +TEXT: H| nrs Source squares | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| icvds Initial D-S voltage | +TEXT: H| icvgs Initial G-S voltage | +TEXT: H| icvbs Initial B-S voltage | +TEXT: H| ic Vector of D-S, G-S, B-S voltages | +TEXT: H| temp Instance operating temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos3 - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| id Drain current | +TEXT: H| cd Drain current | +TEXT: H| ibd B-D junction current | +TEXT: H| ibs B-S junction current | +TEXT: H ------------------------------------------------------------ +TEXT: H| is Source current | +TEXT: H| ig Gate current | +TEXT: H| ib Bulk current | +TEXT: H| vgs Gate-Source voltage | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vds Drain-Source voltage | +TEXT: H| vbs Bulk-Source voltage | +TEXT: H| vbd Bulk-Drain voltage | +TEXT: H| dnode Number of drain node | +TEXT: H ------------------------------------------------------------ +TEXT: H| gnode Number of gate node | +TEXT: H| snode Number of source node | +TEXT: H| bnode Number of bulk node | +TEXT: H| dnodeprime Number of internal drain node | +TEXT: H| snodeprime Number of internal source node | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H -------------------------------------------------------------- +TEXT: H| Mos3 - instance output-only parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-------------------------------------------------------------+ +TEXT: H|von Turn-on voltage | +TEXT: H|vdsat Saturation drain voltage | +TEXT: H|sourcevcrit Critical source voltage | +TEXT: H|drainvcrit Critical drain voltage | +TEXT: H -------------------------------------------------------------- +TEXT: H|rs Source resistance | +TEXT: H|sourceconductanceSource conductance | +TEXT: H|rd Drain resistance | +TEXT: H|drainconductance Drain conductance | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|gm Transconductance | +TEXT: H|gds Drain-Source conductance | +TEXT: H|gmb Bulk-Source transconductance | +TEXT: H|gmbs Bulk-Source transconductance | +TEXT: H -------------------------------------------------------------- +TEXT: H|gbd Bulk-Drain conductance | +TEXT: H|gbs Bulk-Source conductance | +TEXT: H|cbd Bulk-Drain capacitance | +TEXT: H|cbs Bulk-Source capacitance | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|cgs Gate-Source capacitance | +TEXT: H|cgd Gate-Drain capacitance | +TEXT: H|cgb Gate-Bulk capacitance | +TEXT: H cqgs Capacitance due to gate-source charge storage +TEXT: H| | +TEXT: H -------------------------------------------------------------- +TEXT: H|cqgd Capacitance due to gate-drain charge storage| +TEXT: H|cqgb Capacitance due to gate-bulk charge storage | +TEXT: H|cqbd Capacitance due to bulk-drain charge storage| +TEXT: H|cqbs Capacitance due to bulk-source charge storage +TEXT: H|-------------------------------------------------------------+ +TEXT: H|cbd0 Zero-Bias B-D junction capacitance | +TEXT: H|cbdsw0 Zero-Bias B-D sidewall capacitance | +TEXT: H|cbs0 Zero-Bias B-S junction capacitance | +TEXT: H|cbssw0 Zero-Bias B-S sidewall capacitance | +TEXT: H -------------------------------------------------------------- +TEXT: H|qbs Bulk-Source charge storage | +TEXT: H|qgs Gate-Source charge storage | +TEXT: H|qgd Gate-Drain charge storage | +TEXT: H|qgb Gate-Bulk charge storage | +TEXT: H|qbd Bulk-Drain charge storage | +TEXT: H|p Instantaneous power | +TEXT: H -------------------------------------------------------------- +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos3 - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| nmos N type MOSfet model | +TEXT: H| pmos P type MOSfet model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos3 - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vto Threshold voltage | +TEXT: H| vt0 (null) | +TEXT: H| kp Transconductance parameter | +TEXT: H| gamma Bulk threshold parameter | +TEXT: H ------------------------------------------------------------ +TEXT: H| phi Surface potential | +TEXT: H| rd Drain ohmic resistance | +TEXT: H| rs Source ohmic resistance | +TEXT: H| cbd B-D junction capacitance | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cbs B-S junction capacitance | +TEXT: H| is Bulk junction sat. current | +TEXT: H| pb Bulk junction potential | +TEXT: H| cgso Gate-source overlap cap. | +TEXT: H ------------------------------------------------------------ +TEXT: H| cgdo Gate-drain overlap cap. | +TEXT: H| cgbo Gate-bulk overlap cap. | +TEXT: H| rsh Sheet resistance | +TEXT: H| cj Bottom junction cap per area | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| mj Bottom grading coefficient | +TEXT: H| cjsw Side junction cap per area | +TEXT: H| mjsw Side grading coefficient | +TEXT: H| js Bulk jct. sat. current density | +TEXT: H ------------------------------------------------------------ +TEXT: H| tox Oxide thickness | +TEXT: H| ld Lateral diffusion | +TEXT: H| u0 Surface mobility | +TEXT: H| uo (null) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| fc Forward bias jct. fit parm. | +TEXT: H| nsub Substrate doping | +TEXT: H| tpg Gate type | +TEXT: H| nss Surface state density | +TEXT: H ------------------------------------------------------------ +TEXT: H| vmax Maximum carrier drift velocity | +TEXT: H| xj Junction depth | +TEXT: H| nfs Fast surface state density | +TEXT: H| xd Depletion layer width | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| alpha Alpha | +TEXT: H| eta Vds dependence of threshold voltage | +TEXT: H| delta Width effect on threshold | +TEXT: H| input_delta (null) | +TEXT: H ------------------------------------------------------------ +TEXT: H| theta Vgs dependence on mobility | +TEXT: H| kappa Kappa | +TEXT: H| tnom Parameter measurement temperature | +TEXT: H| kf Flicker noise coefficient | +TEXT: H| af Flicker noise exponent | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos3 - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| type N-channel or P-channel MOS | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Mos6 +TITLE: Mos6: Level 6 MOSfet model with Meyer capacitance model +TEXT: H +TEXT: H _B._2_0. _M_o_s_6: _L_e_v_e_l _6 _M_O_S_f_e_t _m_o_d_e_l _w_i_t_h _M_e_y_e_r _c_a_p_a_c_i_t_a_n_c_e +TEXT: H _m_o_d_e_l +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos6 - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| off Device initially off | +TEXT: H| ic Vector of D-S, G-S, B-S voltages | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos6 - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| l Length | +TEXT: H| w Width | +TEXT: H| ad Drain area | +TEXT: H| as Source area | +TEXT: H ------------------------------------------------------------ +TEXT: H| pd Drain perimeter | +TEXT: H| ps Source perimeter | +TEXT: H| nrd Drain squares | +TEXT: H| nrs Source squares | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| icvds Initial D-S voltage | +TEXT: H| icvgs Initial G-S voltage | +TEXT: H| icvbs Initial B-S voltage | +TEXT: H| temp Instance temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos6 - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| id Drain current | +TEXT: H| cd Drain current | +TEXT: H| is Source current | +TEXT: H| ig Gate current | +TEXT: H ------------------------------------------------------------ +TEXT: H| ib Bulk current | +TEXT: H| ibs B-S junction capacitance | +TEXT: H| ibd B-D junction capacitance | +TEXT: H| vgs Gate-Source voltage | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vds Drain-Source voltage | +TEXT: H| vbs Bulk-Source voltage | +TEXT: H| vbd Bulk-Drain voltage | +TEXT: H| dnode Number of the drain node | +TEXT: H ------------------------------------------------------------ +TEXT: H| gnode Number of the gate node | +TEXT: H| snode Number of the source node | +TEXT: H| bnode Number of the node | +TEXT: H| dnodeprime Number of int. drain node | +TEXT: H| snodeprime Number of int. source node | +TEXT: H| _c_o_n_t_i_n_u_e_d | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H -------------------------------------------------------------- +TEXT: H| Mos6 - instance output-only parameters - _c_o_n_t_i_n_u_e_d +TEXT: H|-------------------------------------------------------------+ +TEXT: H|rs Source resistance | +TEXT: H|sourceconductanceSource conductance | +TEXT: H|rd Drain resistance | +TEXT: H|drainconductance Drain conductance | +TEXT: H -------------------------------------------------------------- +TEXT: H|von Turn-on voltage | +TEXT: H|vdsat Saturation drain voltage | +TEXT: H|sourcevcrit Critical source voltage | +TEXT: H|drainvcrit Critical drain voltage | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|gmbs Bulk-Source transconductance | +TEXT: H|gm Transconductance | +TEXT: H|gds Drain-Source conductance | +TEXT: H|gbd Bulk-Drain conductance | +TEXT: H -------------------------------------------------------------- +TEXT: H|gbs Bulk-Source conductance | +TEXT: H|cgs Gate-Source capacitance | +TEXT: H|cgd Gate-Drain capacitance | +TEXT: H|cgb Gate-Bulk capacitance | +TEXT: H|-------------------------------------------------------------+ +TEXT: H|cbd Bulk-Drain capacitance | +TEXT: H|cbs Bulk-Source capacitance | +TEXT: H|cbd0 Zero-Bias B-D junction capacitance | +TEXT: H|cbdsw0 | +TEXT: H -------------------------------------------------------------- +TEXT: H|cbs0 Zero-Bias B-S junction capacitance | +TEXT: H|cbssw0 | +TEXT: H|cqgs Capacitance due to gate-source charge storage +TEXT: H|cqgd Capacitance due to gate-drain charge storage| +TEXT: H|-------------------------------------------------------------+ +TEXT: H|cqgb Capacitance due to gate-bulk charge storage | +TEXT: H|cqbd Capacitance due to bulk-drain charge storage| +TEXT: H cqbs Capacitance due to bulk-source charge storage +TEXT: H|qgs Gate-Source charge storage | +TEXT: H -------------------------------------------------------------- +TEXT: H|qgd Gate-Drain charge storage | +TEXT: H|qgb Gate-Bulk charge storage | +TEXT: H|qbd Bulk-Drain charge storage | +TEXT: H|qbs Bulk-Source charge storage | +TEXT: H|p Instaneous power | +TEXT: H -------------------------------------------------------------- +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos6 - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| nmos N type MOSfet model | +TEXT: H| pmos P type MOSfet model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos6 - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| vto Threshold voltage | +TEXT: H| vt0 (null) | +TEXT: H| kv Saturation voltage factor | +TEXT: H| nv Saturation voltage coeff. | +TEXT: H ------------------------------------------------------------ +TEXT: H| kc Saturation current factor | +TEXT: H| nc Saturation current coeff. | +TEXT: H| nvth Threshold voltage coeff. | +TEXT: H| ps Sat. current modification par. | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gamma Bulk threshold parameter | +TEXT: H| gamma1 Bulk threshold parameter 1 | +TEXT: H| sigma Static feedback effect par. | +TEXT: H| phi Surface potential | +TEXT: H ------------------------------------------------------------ +TEXT: H| lambda Channel length modulation param. | +TEXT: H| lambda0 Channel length modulation param. 0 | +TEXT: H| lambda1 Channel length modulation param. 1 | +TEXT: H| rd Drain ohmic resistance | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| rs Source ohmic resistance | +TEXT: H| cbd B-D junction capacitance | +TEXT: H| cbs B-S junction capacitance | +TEXT: H| is Bulk junction sat. current | +TEXT: H ------------------------------------------------------------ +TEXT: H| pb Bulk junction potential | +TEXT: H| cgso Gate-source overlap cap. | +TEXT: H| cgdo Gate-drain overlap cap. | +TEXT: H| cgbo Gate-bulk overlap cap. | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| rsh Sheet resistance | +TEXT: H| cj Bottom junction cap per area | +TEXT: H| mj Bottom grading coefficient | +TEXT: H| cjsw Side junction cap per area | +TEXT: H ------------------------------------------------------------ +TEXT: H| mjsw Side grading coefficient | +TEXT: H| js Bulk jct. sat. current density | +TEXT: H| ld Lateral diffusion | +TEXT: H| tox Oxide thickness | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| u0 Surface mobility | +TEXT: H| uo (null) | +TEXT: H| fc Forward bias jct. fit parm. | +TEXT: H| tpg Gate type | +TEXT: H ------------------------------------------------------------ +TEXT: H| nsub Substrate doping | +TEXT: H| nss Surface state density | +TEXT: H| tnom Parameter measurement temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Mos6 - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| type N-channel or P-channel MOS | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Resistor +TITLE: Resistor: Simple linear resistor +TEXT: H +TEXT: H _B._2_1. _R_e_s_i_s_t_o_r: _S_i_m_p_l_e _l_i_n_e_a_r _r_e_s_i_s_t_o_r +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Resistor - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| resistance Resistance | +TEXT: H| temp Instance operating temperature | +TEXT: H| l Length | +TEXT: H| w Width | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Resistor - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| i Current | +TEXT: H| p Power | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Resistor - model parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| r Device is a resistor model | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Resistor - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| rsh Sheet resistance | +TEXT: H| narrow Narrowing of resistor | +TEXT: H| tc1 First order temp. coefficient | +TEXT: H| tc2 Second order temp. coefficient | +TEXT: H| defw Default device width | +TEXT: H| tnom Parameter measurement temperature | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Switch +TITLE: Switch: Ideal voltage controlled switch +TEXT: H +TEXT: H _B._2_2. _S_w_i_t_c_h: _I_d_e_a_l _v_o_l_t_a_g_e _c_o_n_t_r_o_l_l_e_d _s_w_i_t_c_h +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Switch - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| on Switch initially closed | +TEXT: H| off Switch initially open | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Switch - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node Positive node of switch | +TEXT: H| neg_node Negative node of switch | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Switch - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| cont_p_node Positive contr. node of switch | +TEXT: H| cont_n_node Positive contr. node of switch | +TEXT: H| i Switch current | +TEXT: H| p Switch power | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Switch - model parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| sw Switch model | +TEXT: H| vt Threshold voltage | +TEXT: H| vh Hysteresis voltage | +TEXT: H| ron Resistance when closed | +TEXT: H| roff Resistance when open | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Switch - model parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gon Conductance when closed | +TEXT: H| goff Conductance when open | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Tranline +TITLE: Tranline: Lossless transmission line +TEXT: H +TEXT: H _B._2_3. _T_r_a_n_l_i_n_e: _L_o_s_s_l_e_s_s _t_r_a_n_s_m_i_s_s_i_o_n _l_i_n_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Tranline - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ic Initial condition vector:v1,i1,v2,i2 | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Tranline - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| z0 Characteristic impedance | +TEXT: H| zo (null) | +TEXT: H| f Frequency | +TEXT: H| td Transmission delay | +TEXT: H ------------------------------------------------------------ +TEXT: H| nl Normalized length at frequency given | +TEXT: H| v1 Initial voltage at end 1 | +TEXT: H| v2 Initial voltage at end 2 | +TEXT: H| i1 Initial current at end 1 | +TEXT: H| i2 Initial current at end 2 | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Tranline - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| rel Rel. rate of change of deriv. for bkpt | +TEXT: H| abs Abs. rate of change of deriv. for bkpt | +TEXT: H| pos_node1 Positive node of end 1 of t. line | +TEXT: H| neg_node1 Negative node of end 1 of t. line | +TEXT: H ------------------------------------------------------------ +TEXT: H| pos_node2 Positive node of end 2 of t. line | +TEXT: H| neg_node2 Negative node of end 2 of t. line | +TEXT: H| delays Delayed values of excitation | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: VCCS +TITLE: VCCS: Voltage controlled current source +TEXT: H +TEXT: H _B._2_4. _V_C_C_S: _V_o_l_t_a_g_e _c_o_n_t_r_o_l_l_e_d _c_u_r_r_e_n_t _s_o_u_r_c_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| VCCS - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ic Initial condition of controlling source | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| VCCS - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gain Transconductance of source (gain) | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| VCCS - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node Positive node of source | +TEXT: H| neg_node Negative node of source | +TEXT: H| cont_p_node Positive node of contr. source | +TEXT: H| cont_n_node Negative node of contr. source | +TEXT: H ------------------------------------------------------------ +TEXT: H| i Output current | +TEXT: H| v Voltage across output | +TEXT: H| p Power | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: VCVS +TITLE: VCVS: Voltage controlled voltage source +TEXT: H +TEXT: H _B._2_5. _V_C_V_S: _V_o_l_t_a_g_e _c_o_n_t_r_o_l_l_e_d _v_o_l_t_a_g_e _s_o_u_r_c_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| VCVS - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| ic Initial condition of controlling source | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| VCVS - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| gain Voltage gain | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| VCVS - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node Positive node of source | +TEXT: H| neg_node Negative node of source | +TEXT: H| cont_p_node Positive node of contr. source | +TEXT: H cont_n_node Negative node of contr. source +TEXT: H ------------------------------------------------------------ +TEXT: H| i Output current | +TEXT: H| v Output voltage | +TEXT: H| p Power | +TEXT: H ------------------------------------------------------------ +TEXT: H + +SUBJECT: Vsource +TITLE: Vsource: Independent voltage source +TEXT: H +TEXT: H _B._2_6. _V_s_o_u_r_c_e: _I_n_d_e_p_e_n_d_e_n_t _v_o_l_t_a_g_e _s_o_u_r_c_e +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Vsource - instance parameters (input-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pulse Pulse description | +TEXT: H| sine Sinusoidal source description | +TEXT: H| sin Sinusoidal source description | +TEXT: H| exp Exponential source description | +TEXT: H ------------------------------------------------------------ +TEXT: H| pwl Piecewise linear description | +TEXT: H| sffm Single freq. FM descripton | +TEXT: H| ac AC magnitude, phase vector | +TEXT: H| distof1 f1 input for distortion | +TEXT: H| distof2 f2 input for distortion | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Vsource - instance parameters (input-output) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| dc D.C. source value | +TEXT: H| acmag A.C. Magnitude | +TEXT: H| acphase A.C. Phase | +TEXT: H ------------------------------------------------------------ +TEXT: H +TEXT: H +TEXT: H ------------------------------------------------------------ +TEXT: H| Vsource - instance parameters (output-only) | +TEXT: H|-----------------------------------------------------------+ +TEXT: H| pos_node Positive node of source | +TEXT: H| neg_node Negative node of source | +TEXT: H| function Function of the source | +TEXT: H| order Order of the source function | +TEXT: H ------------------------------------------------------------ +TEXT: H| coeffs Coefficients for the function | +TEXT: H| acreal AC real part | +TEXT: H| acimag AC imaginary part | +TEXT: H| i Voltage source current | +TEXT: H| p Instantaneous power | +TEXT: H ------------------------------------------------------------ + diff --git a/src/nutmeg.c b/src/nutmeg.c new file mode 100644 index 000000000..51b90b6df --- /dev/null +++ b/src/nutmeg.c @@ -0,0 +1,64 @@ +/* Configuration file for nutmeg */ +#include + +#include "conf.h" + + +/* + * Devices + */ + +#define DEVICES_USED "" +#define ANALYSES_USED "" + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ + +#include "ngspice.h" + +#define CONFIG +#include +#include "ifsim.h" +#include "suffix.h" + +IFsimulator SIMinfo = { + "nutmeg", /* my name */ + "data analysis and manipulation program", /* more about me */ + Spice_Version, /* my version */ + NULL, /* newCircuit function */ + NULL, /* deleteCircuit function */ + NULL, /* newNode function */ /* NEEDED */ + NULL, /* groundNode function */ + NULL, /* bindNode function */ + NULL, /* findNode function */ /* NEEDED */ + NULL, /* instToNode function */ /* NEEDED */ + NULL, /* setNodeParm function */ /* NEEDED */ + NULL, /* askNodeQuest function */ /* NEEDED */ + NULL, /* deleteNode function */ /* NEEDED */ + NULL, /* newInstance function */ + NULL, /* setInstanceParm function */ + NULL, /* askInstanceQuest function */ + NULL, /* findInstance funciton */ + NULL, /* deleteInstance function */ /* to be added later */ + NULL, /* newModel function */ + NULL, /* setModelParm function */ + NULL, /* askModelQuest function */ + NULL, /* findModel function */ + NULL, /* deleteModel function */ /* to be added later */ + NULL, /* newTask function */ + NULL, /* newAnalysis function */ + NULL, /* setAnalysisParm function */ + NULL, /* askAnalysisQeust function */ + NULL, /* findAnalysis function */ + NULL, /* findTask function */ + NULL, /* deleteTask function */ + NULL, /* doAnalyses function */ + NULL, /* non-convergence message function */ + 0, + NULL, + 0, + NULL, + 0, + NULL, +}; diff --git a/src/parser/ChangeLog b/src/parser/ChangeLog new file mode 100644 index 000000000..4a58b0104 --- /dev/null +++ b/src/parser/ChangeLog @@ -0,0 +1,95 @@ +2000-03-11 Paolo Nenzi + + * numparse.c: as wrote in Chris Inbody patch: + In numparse.c line 17 changed the arg type of "num" + to double. This (so far :) seems to have had no adverse effect. + +2000-03-11 Paolo Nenzi + + * history.c: applied Chris Inbody patch. As he wrote: + I had some trouble running ng-spice in batch mode on a fairly repetitive job + (probably 10 - 20 commands repeated 256 times in a single session :), it was + giving me "mangled history" errors and then seg faulting. + [...] + In history.c line 425, added an exit(0) call to the else condition to prevent + seg fault upon generation of the history list error. On line 25, changed + cp_maxhistlength to 10000 vs 1000. The value of 10000 was enough to keep my + task from crashing but there may be a better way to do this,.. I didn't try + an arbitrarily high number because I'm not sure what effect it would have on + memory usage or progam size or speed. Maybe that's the best answer, just + bump the value to 1e6 or something that no one would ever approach. + +1999-09-07 Arno + + * lexical.c: read() requires #include of unistd.h. + + * modify.c: removed warning about char subscript for array. + + * unixcom.h: removed prototypes for static tryexec(), hash(). + + * var2.c: added default case to remove warning. + +1999-09-04 Emmanuel Rouat + + * *.c: added header files for .c files + +1999-08-28 Emmanuel Rouat + + * Removed all #includes of misc.h and util.h (now in spice.h) + +1999-08-27 Paolo Nenzi + + * Removed #include "suffix.h", replaced GENERIC with void and + ansified the code with protoize. + +1999-08-08 Emmanuel Rouat + + * Removed HAS_DOSDIRS and HAS_POW10 code in directory + + * Makefile.am (libcp_a_SOURCES): removed spawn.c (vms only) + +1999-08-06 Emmanuel Rouat + + * unixcom.c (cp_unixcom): + * cshpar.c: removed test on HAS_SYSTEM (always true on Unix?) + + * backq.c (backeval): changed HAS_POPEN in HAVE_POPEN + + * cshpar.c (fileexists): changed HAS_ACCESS in HAVE_ACCESS + (com_chdir): removed test on HAS_CHDIR (always true on Unix) + (com_shell): removed test on HAS_UNIX_SIGS (always true on Unix) + + * unixcom.c (cp_unixcom): changed HAS_INTSYSWAIT in HAVE_SYS_WAIT_H + +1999-08-05 Emmanuel Rouat + + * cshpar.c (com_chdir): removed HAS_GETENV tests. + + * var2.c (vareval): removed test on HAS_GETPID + + * unixcom.c: changed HAS_GETCWD in HAVE_GETCWD and HAS_GETWD into HAVE_GETWD + + * lexical.c: + * gloc.c: + * cshpar.c: changed HAS_GETPW in HAVE_PWD_H + (com_chdir): changed HAS_GETCWD in HAVE_GETCWD (and #included unistd.h) + + * std.c: changed HAS_QSORT in HAVE_QSORT + +1999-08-04 Emmanuel Rouat + + * cshpar.c: changed HAS_WAIT2(??) into HAVE_SYS_WAIT_H + +1999-08-03 Emmanuel Rouat + + * output.c: changed HAS_TERMCAP in HAVE_TERMCAP + + * unixcom.c: changed HAS_VFORK in HAVE_VORK_H + + * unixcom.c: + * complete.c: + * glob.c: HAVE_SYS_DIR_H and HAVE_DIRENT_H (instead of + HAS_BSDDIRS and HAS_SYSVDIRS) + + * cshpar.c (com_shell): changed HAS_VFORK in HAVE_VORK_H + diff --git a/src/parser/Makefile.am b/src/parser/Makefile.am new file mode 100644 index 000000000..a92eaed35 --- /dev/null +++ b/src/parser/Makefile.am @@ -0,0 +1,44 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libparser.a + +libparser_a_SOURCES = \ + alias.c \ + alias.h \ + backq.c \ + backq.h \ + complete.c \ + complete.h \ + cshpar.c \ + cshpar.h \ + front.c \ + front.h \ + glob.c \ + glob.h \ + history.c \ + history.h \ + input.c \ + input.h \ + lexical.c \ + lexical.h \ + modify.c \ + modify.h \ + numparse.c \ + numparse.h \ + output.c \ + output.h \ + quote.c \ + quote.h \ + std.c \ + unixcom.c \ + unixcom.h \ + variable.c \ + variable.h \ + var2.c \ + var2.h \ + wlist.c \ + wlist.h + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/parser/alias.c b/src/parser/alias.c new file mode 100644 index 000000000..28682a430 --- /dev/null +++ b/src/parser/alias.c @@ -0,0 +1,254 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Do alias substitution. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "alias.h" + +static wordlist *asubst(wordlist *wlist); + +struct alias *cp_aliases = NULL; + +wordlist * +cp_doalias(wordlist *wlist) +{ + int ntries; + wordlist *realw, *nwl, *nextc = NULL, *end = NULL; + wordlist *comm; + + while (wlist && eq(wlist->wl_word, cp_csep)) + wlist = wlist->wl_next; + wlist->wl_prev = NULL; + + /* The alias process is going to modify the "last" line typed, + * so save a copy of what it really is and restore it after + * aliasing is done. We have to do tricky things do get around + * the problems with ; ... + */ + realw = wl_copy(cp_lastone->hi_wlist); + comm = wlist; + do { + end = comm->wl_prev; + comm->wl_prev = NULL; + for (nextc = comm; nextc; nextc = nextc->wl_next) + if (eq(nextc->wl_word, cp_csep)) { + if (nextc->wl_prev) + nextc->wl_prev->wl_next = NULL; + break; + } + + wl_free(cp_lastone->hi_wlist); + cp_lastone->hi_wlist = wl_copy(comm); + for (ntries = 21; ntries; ntries--) { + nwl = asubst(comm); + if (nwl == NULL) + break; + if (eq(nwl->wl_word, comm->wl_word)) { + /* Just once through... */ + wl_free(comm); + comm = nwl; + break; + } else { + wl_free(comm); + comm = nwl; + } + } + + if (!ntries) { + fprintf(cp_err, "Error: alias loop.\n"); + wlist->wl_word = NULL; + return (wlist); + } + comm->wl_prev = end; + if (!end) + wlist = comm; + else + end->wl_next = comm; + while (comm->wl_next) + comm = comm->wl_next; + comm->wl_next = nextc; + if (nextc) { + nextc->wl_prev = comm; + nextc = nextc->wl_next; + comm = nextc; + } + } while (nextc); + + wl_free(cp_lastone->hi_wlist); + cp_lastone->hi_wlist = realw; + return (wlist); +} + +/* Return NULL if no alias was found. We can get away with just calling + * cp_histsubst now because the line will have gone onto the history list + * by now and cp_histsubst will look in the right place. + */ + +static wordlist * +asubst(wordlist *wlist) +{ + struct alias *al; + wordlist *wl, *w = NULL; + char *word; + + word = wlist->wl_word; + if (*word == '\\') { + wlist->wl_word++; + return (NULL); + } + for (al = cp_aliases; al; al = al->al_next) + if (eq(word, al->al_name)) + break; + if (!al) + return (NULL); + wl = cp_histsubst(wl_copy(al->al_text)); + + if (cp_didhsubst) { + /* Make sure that we have an up-to-date last history entry. */ + wl_free(cp_lastone->hi_wlist); + cp_lastone->hi_wlist = wl_copy(wl); + } else { + /* If it had no history args, then append the rest of the wl */ + for (w = wl; w->wl_next; w = w->wl_next); + w->wl_next = wl_copy(wlist->wl_next); + if (w->wl_next) + w->wl_next->wl_prev = w; + } + return (wl); +} + +/* If we use this, aliases will be in alphabetical order. */ + +void +cp_setalias(char *word, wordlist *wlist) +{ + struct alias *al, *ta; + + cp_unalias(word); + cp_addkword(CT_ALIASES, word); + if (cp_aliases == NULL) { + /* printf("first one...\n"); */ + al = cp_aliases = alloc(struct alias); + al->al_next = NULL; + al->al_prev = NULL; + } else { + /* printf("inserting %s: %s ...\n", word, wlist->wl_word); */ + for (al = cp_aliases; al->al_next; al = al->al_next) { + /* printf("checking %s...\n", al->al_name); */ + if (strcmp(al->al_name, word) > 0) + break; + } + /* The new one goes before al */ + if (al->al_prev) { + al = al->al_prev; + ta = al->al_next; + al->al_next = alloc(struct alias); + al->al_next->al_prev = al; + al = al->al_next; + al->al_next = ta; + ta->al_prev = al; + } else { + cp_aliases = alloc(struct alias); + cp_aliases->al_next = al; + cp_aliases->al_prev = NULL; + al->al_prev = cp_aliases; + al = cp_aliases; + } + } + al->al_name = copy(word); + al->al_text = wl_copy(wlist); + cp_striplist(al->al_text); + /* We can afford to not worry about the bits, because before + * the keyword lookup is done the alias is evaluated. + * Make everything file completion, just in case... + */ + cp_addcomm(word, (long) 1, (long) 1, (long) 1, (long) 1); + /* printf("word %s, next = %s, prev = %s...\n", al->al_name, + al->al_next ? al->al_next->al_name : "(none)", + al->al_prev ? al->al_prev->al_name : "(none)"); */ + return; +} + +void +cp_unalias(char *word) +{ + struct alias *al; + + cp_remkword(CT_ALIASES, word); + for (al = cp_aliases; al; al = al->al_next) + if (eq(word, al->al_name)) + break; + if (al == NULL) + return; + if (al->al_next) + al->al_next->al_prev = al->al_prev; + if (al->al_prev) + al->al_prev->al_next = al->al_next; + else { + al->al_next->al_prev = NULL; + cp_aliases = al->al_next; + } + wl_free(al->al_text); + tfree(al->al_name); + tfree(al); + cp_remcomm(word); + return; +} + +void +cp_paliases(char *word) +{ + struct alias *al; + + for (al = cp_aliases; al; al = al->al_next) + if ((word == NULL) || eq(al->al_name, word)) { + if (!word) + fprintf(cp_out, "%s\t", al->al_name); + wl_print(al->al_text, cp_out); + (void) putc('\n', cp_out); + } + return; +} + +/* The routine for the "alias" command. */ + +void +com_alias(wordlist *wl) +{ + if (wl == NULL) + cp_paliases((char *) NULL); + else if (wl->wl_next == NULL) + cp_paliases(wl->wl_word); + else + cp_setalias(wl->wl_word, wl->wl_next); + return; +} + +void +com_unalias(wordlist *wl) +{ + struct alias *al, *na; + + if (eq(wl->wl_word, "*")) { + for (al = cp_aliases; al; al = na) { + na = al->al_next; + wl_free(al->al_text); + tfree(al->al_name); + tfree(al); + } + cp_aliases = NULL; + wl = wl->wl_next; + } + while (wl != NULL) { + cp_unalias(wl->wl_word); + wl = wl->wl_next; + } + return; +} + diff --git a/src/parser/alias.h b/src/parser/alias.h new file mode 100644 index 000000000..446117ba9 --- /dev/null +++ b/src/parser/alias.h @@ -0,0 +1,16 @@ +/************* + * Header file for alias.c + * 1999 E. Rouat + ************/ + +#ifndef ALIAS_H_INCLUDED +#define ALIAS_H_INCLUDED + +wordlist * cp_doalias(wordlist *wlist); +void cp_setalias(char *word, wordlist *wlist); +void cp_unalias(char *word); +void cp_paliases(char *word); +void com_alias(wordlist *wl); +void com_unalias(wordlist *wl); + +#endif diff --git a/src/parser/backq.c b/src/parser/backq.c new file mode 100644 index 000000000..4b8afcb60 --- /dev/null +++ b/src/parser/backq.c @@ -0,0 +1,116 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Do backquote substitution on a word list. + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "backq.h" + + +static wordlist *backeval(char *string); + +char cp_back = '`'; + +wordlist * +cp_bquote(wordlist *wlist) +{ + wordlist *wl, *nwl; + char *s, *t, buf[BSIZE_SP], wbuf[BSIZE_SP], tbuf[BSIZE_SP]; + int i; + + for (wl = wlist; wl; wl = wl->wl_next) { + + t = wl->wl_word; + if (!t) + continue; + i = 0; +loop: s =strchr(t, cp_back); + if (s == NULL) + continue; + while (t < s) + wbuf[i++] = *t++; + wbuf[i] = '\0'; + (void) strcpy(buf, ++s); + s = buf; + t++; + while (*s && (*s != cp_back)) { + t++; /* Get s and t past the next backquote. */ + s++; + } + /* What the heck, let "echo `foo" work... */ + *s = '\0'; + t++; /* Get past the second ` */ + if (!(nwl = backeval(buf))) { + wlist->wl_word = NULL; + return (wlist); + } + (void) strcpy(buf, wbuf); + if (nwl->wl_word) { + (void) strcat(buf, nwl->wl_word); + tfree(nwl->wl_word); + } + nwl->wl_word = copy(buf); + + (void) strcpy(tbuf, t); + wl = wl_splice(wl, nwl); + for(wlist = wl; wlist->wl_prev; wlist = wlist->wl_prev); + /* MW. We must move to the begging of new wordlist. */ + + (void) strcpy(buf, wl->wl_word); + i = strlen(buf); + (void) strcat(buf, tbuf); + tfree(wl->wl_word); + wl->wl_word = copy(buf); + t = &wl->wl_word[i]; + s = wl->wl_word; + for (i = 0; s < t; s++) + wbuf[i++] = *s; + goto loop; + } + return (wlist); +} + +/* Do a popen with the string, and then reset the file pointers so that + * we can use the first pass of the parser on the output. + */ + +static wordlist * +backeval(char *string) +{ +#ifdef HAVE_POPEN + FILE *proc, *old; + wordlist *wl; + bool intv; + extern FILE *popen(const char *, const char *); + + proc = popen(string, "r"); + if (proc == NULL) { + fprintf(cp_err, "Error: can't evaluate %s.\n", string); + return (NULL); + } + old = cp_inp_cur; + cp_inp_cur = proc; + intv = cp_interactive; + cp_interactive = FALSE; + cp_bqflag = TRUE; + wl = cp_lexer((char *) NULL); + cp_bqflag = FALSE; + cp_inp_cur = old; + cp_interactive = intv; + (void) pclose(proc); + return (wl); +#else + wordlist *wl = alloc(struct wordlist); + + wl->wl_word = copy(string); + return (wl); +#endif +} + diff --git a/src/parser/backq.h b/src/parser/backq.h new file mode 100644 index 000000000..98a6ce1de --- /dev/null +++ b/src/parser/backq.h @@ -0,0 +1,12 @@ +/************* + * Header file for backq.c + * 1999 E. Rouat + ************/ + +#ifndef BACKQ_H_INCLUDED +#define BACKQ_H_INCLUDED + +wordlist * cp_bquote(wordlist *wlist); + + +#endif diff --git a/src/parser/complete.c b/src/parser/complete.c new file mode 100644 index 000000000..647a5e4b6 --- /dev/null +++ b/src/parser/complete.c @@ -0,0 +1,690 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +Modified: 1999 Paolo Nenzi +**********/ + +/* + * Command completion code. We keep a data structure with information on each + * command, to make lookups fast. We also keep NCLASSES (which is sort of + * hardwired as 32) sets of keywords. Each command has an array of NARGS + * bitmasks (also hardwired as 4), stating whether the command takes that + * particular class of keywords in that position. Class 0 always means + * filename completion. + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "complete.h" + + +#ifdef HAVE_SYS_DIR_H +#include +#include +#else +# ifdef HAVE_DIRENT_H +# include +# include +# ifndef direct +# define direct dirent +# endif +# endif +#endif +#ifdef HAVE_PWD_H +#include +#endif + + /* MW. We also need ioctl.h here I think */ +#include + +/* Be sure the ioctls get included in the following */ +#ifdef HAVE_SGTTY_H +#include +#else +#ifdef HAVE_TERMIO_H +#include +#else +#ifdef HAVE_TERMIOS_H +#include +#endif +#endif +#endif + + +#define CNTRL_D '\004' +#define ESCAPE '\033' +#define NCLASSES 32 + +bool cp_nocc; /* Don't do command completion. */ + + + +static struct ccom *commands = NULL; /* The available commands. */ +static struct ccom *keywords[NCLASSES]; /* Keywords. */ + + +/* static declarations */ + +static struct ccom * getccom(char *first); +static wordlist * ccfilec(char *buf); +static wordlist * ccmatch(char *word, struct ccom **dbase); +static void printem(wordlist *wl); +static wordlist * cctowl(struct ccom *cc, bool sib); +static struct ccom * clookup(register char *word, struct ccom **dd, bool pref, + bool create); +static void cdelete(struct ccom *node); + + +#ifdef TIOCSTI + +void +cp_ccom(wordlist *wlist, char *buf, bool esc) +{ + struct ccom *cc; + wordlist *a, *pmatches = NULL; + char wbuf[BSIZE_SP], *s; + int i=0; + int j, arg; + + buf = cp_unquote(copy(buf)); + cp_wstrip(buf); + if (wlist->wl_next) { /* Not the first word. */ + cc = getccom(wlist->wl_word); + if (cc && cc->cc_invalid) + cc = NULL; + arg = wl_length(wlist) - 2; + if (arg > 3) + arg = 3; + /* First filenames. */ + if (cc && (cc->cc_kwords[arg] & 1)) { + pmatches = ccfilec(buf); + s =strrchr(buf, '/'); + i = strlen(s ? s + 1 : buf); + if ((*buf == '~') && !index(buf, '/')) + i--; + } + + /* The keywords. */ + for (j = 1; j < NCLASSES; j++) { + if (cc && (cc->cc_kwords[arg] & (1 << j))) { + /* Find all the matching keywords. */ + a = ccmatch(buf, &keywords[j]); + i = strlen(buf); + if (pmatches) + pmatches = wl_append(pmatches, a); + else + pmatches = a; + } + } + wl_sort(pmatches); + } else { + pmatches = ccmatch(buf, &commands); + i = strlen(buf); + } + if (!esc) { + printem(pmatches); + wl_free(pmatches); + return; + } + + if (pmatches == NULL) { + (void) putchar('\07'); + (void) fflush(cp_out); + return; + } + if (pmatches->wl_next == NULL) { + (void) strcpy(wbuf, &pmatches->wl_word[i]); + goto found; + } + /* Now we know which words might work. Extend the command as much + * as possible, then TIOCSTI the characters out. + */ + for (j = 0;; j++, i++) { + wbuf[j] = pmatches->wl_word[i]; + for (a = pmatches->wl_next; a; a = a->wl_next) + if (a->wl_word[i] != wbuf[j]) { + (void) putchar('\07'); + (void) fflush(cp_out); + wbuf[j] = '\0'; + goto found; + } + if (wbuf[j] == '\0') + goto found; + } +found: for (i = 0; wbuf[i]; i++) + (void) ioctl(fileno(cp_in), TIOCSTI, &wbuf[i]); + wl_free(pmatches); + return; +} + +/* Figure out what the command is, given the name. Returns NULL if there + * is no such command in the command list. This is tricky, because we have + * to do a preliminary history and alias parse. (Or at least we should.) + */ + +static struct ccom * +getccom(char *first) +{ + struct alias *al; + int ntries = 21; + + /* First look for aliases. Just interested in the first word... + * Don't bother doing history yet -- that might get complicated. + */ + while (ntries-- > 0) { + for (al = cp_aliases; al; al = al->al_next) + if (eq(first, al->al_name)) { + first = al->al_text->wl_word; + break; + } + if (al == NULL) + break; + } + if (ntries == 0) { + fprintf(cp_err, "\nError: alias loop.\n"); + return (NULL); + } + return (clookup(first, &commands, FALSE, FALSE)); +} + +/* Figure out what files match the prefix. */ + +static wordlist * +ccfilec(char *buf) +{ + DIR *wdir; + char *lcomp, *dir; + struct direct *de; + wordlist *wl = NULL, *t; + struct passwd *pw; + + buf = copy(buf); /* Don't mangle anything... */ + + lcomp =strrchr(buf, '/'); + if (lcomp == NULL) { + dir = "."; + lcomp = buf; + if (*buf == cp_til) { /* User name completion... */ + buf++; + while ((pw = getpwent())) { + if (prefix(buf, pw->pw_name)) { + if (wl == NULL) { + wl = alloc(struct wordlist); + wl->wl_next = NULL; + wl->wl_prev = NULL; + } else { + t = wl; + wl = alloc(struct wordlist); + wl->wl_prev = NULL; + wl->wl_next = t; + t->wl_prev = wl; + } + wl->wl_word = copy(pw->pw_name); + } + } + (void) endpwent(); + return (wl); + } + } else { + dir = buf; + *lcomp = '\0'; + lcomp++; + if (*dir == cp_til) { + dir = cp_tildexpand(dir); + if (dir == NULL) + return (NULL); + } + } + if (!(wdir = opendir(dir))) + return (NULL); + while ((de = readdir(wdir))) + if ((prefix(lcomp, de->d_name)) && (*lcomp || + (*de->d_name != '.'))) { + if (wl == NULL) { + wl = alloc(struct wordlist); + wl->wl_next = NULL; + wl->wl_prev = NULL; + } else { + t = wl; + wl = alloc(struct wordlist); + wl->wl_next = t; + t->wl_prev = wl; + wl->wl_prev = NULL; + } + wl->wl_word = copy(de->d_name); + } + (void) closedir(wdir); + + wl_sort(wl); + return (wl); +} + +/* See what keywords or commands match the prefix. Check extra also for + * matches, if it is non-NULL. Return a wordlist which is in alphabetical + * order. Note that we have to call this once for each class. + */ + +static wordlist * +ccmatch(char *word, struct ccom **dbase) +{ + wordlist *wl; + register struct ccom *cc; + + cc = clookup(word, dbase, TRUE, FALSE); + if (cc) { + if (*word) /* This is a big drag. */ + wl = cctowl(cc, FALSE); + else + wl = cctowl(cc, TRUE); + } else + wl = NULL; + return (wl); +} + +/* Print the words in the wordlist in columns. They are already sorted... + * This is a hard thing to do with wordlists... + */ + +static void +printem(wordlist *wl) +{ + wordlist *ww; + int maxl = 0, num, i, j, k, width = 79, ncols, nlines; + + (void) putchar('\n'); + if (wl == NULL) { + return; + } + num = wl_length(wl); + for (ww = wl; ww; ww = ww->wl_next) { + j = strlen(ww->wl_word); + if (j > maxl) + maxl = j; + } + if (++maxl % 8) + maxl += 8 - (maxl % 8); + ncols = width / maxl; + if (ncols == 0) + ncols = 1; + nlines = num / ncols + (num % ncols ? 1 : 0); + for (k = 0; k < nlines; k++) { + for (i = 0; i < ncols; i++) { + j = i * nlines + k; + if (j < num) { + fprintf(cp_out, "%-*s", maxl, + wl_nthelem(j, wl)->wl_word); + } else + break; + } + (void) putchar('\n'); + } + return; +} + +#else /* if not TIOCSTI */ +void +cp_ccom(wordlist *wlist, char *buf, bool esc) +{ + return; +} +#endif + +static wordlist * +cctowl(struct ccom *cc, bool sib) +{ + wordlist *wl, *end; + + if (!cc) + return (NULL); + if (!cc->cc_invalid) { + wl = alloc(struct wordlist); + wl->wl_word = copy(cc->cc_name); + wl->wl_prev = NULL; + wl->wl_next = cctowl(cc->cc_child, TRUE); + if (wl->wl_next) + wl->wl_next->wl_prev = wl; + } else + wl = cctowl(cc->cc_child, TRUE); + if (sib) { + if (wl) { + for (end = wl; end->wl_next; end = end->wl_next) + ; + end->wl_next = cctowl(cc->cc_sibling, TRUE); + if (end->wl_next) + end->wl_next->wl_prev = wl; + } else + wl = cctowl(cc->cc_sibling, TRUE); + } + return (wl); +} + +/* We use this in com_device... */ + +wordlist * +cp_cctowl(char *stuff) +{ + return (cctowl((struct ccom *) stuff, TRUE)); +} + +/* Turn on and off the escape break character and cooked mode. */ + +void +cp_ccon(bool on) +{ +#ifdef TIOCSTI +#ifdef HAVE_SGTTY_H + static bool ison = FALSE; + struct tchars tbuf; + struct sgttyb sbuf; + + if (cp_nocc || !cp_interactive || (ison == on)) + return; + ison = on; + + /* Set the terminal up -- make escape the break character, and + * make sure we aren't in raw or cbreak mode. Hope the (void) ioctl's + * won't fail. + */ + (void) ioctl(fileno(cp_in), TIOCGETC, (char *) &tbuf); + if (on) + tbuf.t_brkc = ESCAPE; + else + tbuf.t_brkc = '\0'; + (void) ioctl(fileno(cp_in), TIOCSETC, (char *) &tbuf); + + (void) ioctl(fileno(cp_in), TIOCGETP, (char *) &sbuf); + sbuf.sg_flags &= ~(RAW|CBREAK); + (void) ioctl(fileno(cp_in), TIOCSETP, (char *) &sbuf); +#else + +# ifdef HAVE_TERMIO_H + +# define TERM_GET TCGETA +# define TERM_SET TCSETA + static struct termio sbuf; + static struct termio OS_Buf; + +# else +# ifdef HAVE_TERMIOS_H + +# define TERM_GET TCGETS +# define TERM_SET TCSETS + static struct termios sbuf; + static struct termios OS_Buf; + +# endif +# endif + +# ifdef TERM_GET + static bool ison = FALSE; + + if (cp_nocc || !cp_interactive || (ison == on)) + return; + ison = on; + + if (ison == TRUE) { + (void) ioctl(fileno(cp_in), TERM_GET, (char *) &OS_Buf); + sbuf = OS_Buf; + sbuf.c_cc[VEOF] = 0; + sbuf.c_cc[VEOL] = ESCAPE; + sbuf.c_cc[VEOL2] = CNTRL_D; + (void) ioctl(fileno(cp_in), TERM_SET, (char *) &sbuf); + } else { + (void) ioctl(fileno(cp_in), TERM_SET, (char *) &OS_Buf); + } + +# endif +#endif + +#endif + + return; +} + +/* The following routines deal with the command and keyword databases. + * Say whether a given word exists in the command database. + */ + +bool +cp_comlook(char *word) +{ + if (word && *word && clookup(word, &commands, FALSE, FALSE)) + return (TRUE); + else + return (FALSE); +} + +/* Add a command to the database, with the given keywords and filename flag. */ + +void +cp_addcomm(char *word, long int bits0, long int bits1, long int bits2, long int bits3) +{ + struct ccom *cc; + + cc = clookup(word, &commands, FALSE, TRUE); + cc->cc_invalid = 0; + cc->cc_kwords[0] = bits0; + cc->cc_kwords[1] = bits1; + cc->cc_kwords[2] = bits2; + cc->cc_kwords[3] = bits3; + return; +} + +/* Remove a command from the database. */ + +void +cp_remcomm(char *word) +{ + struct ccom *cc; + + cc = clookup(word, &commands, FALSE, FALSE); + if (cc) + cdelete(cc); + return; +} + +/* Add a keyword to the database. */ + +void +cp_addkword(int class, char *word) +{ + struct ccom *cc; + + if ((class < 1) || (class >= NCLASSES)) { + fprintf(cp_err, "cp_addkword: Internal Error: bad class %d\n", + class); + return; + } + word = copy(word); + cc = clookup(word, &keywords[class], FALSE, TRUE); + cc->cc_invalid = 0; + return; +} + +/* Remove a keyword from the database. */ + +void +cp_remkword(int class, char *word) +{ + struct ccom *cc; + + if ((class < 1) || (class >= NCLASSES)) { + fprintf(cp_err, "cp_addkword: Internal Error: bad class %d\n", + class); + return; + } + cc = clookup(word, &keywords[class], FALSE, FALSE); + if (cc) + cdelete(cc); + return; +} + +/* This routine is used when there are several keyword sets that are + * to be switched between rapidly. The return value is the old tree at + * that position, and the keyword class given is set to the argument. + */ + +char * +cp_kwswitch(int class, char *tree) +{ + char *old; + + if ((class < 1) || (class >= NCLASSES)) { + fprintf(cp_err, "cp_addkword: Internal Error: bad class %d\n", + class); + return (NULL); + } + old = (char *) keywords[class]; + keywords[class] = (struct ccom *) tree; + return (old); +} + +/* Throw away all the stuff and prepare to rebuild it from scratch... */ + + +void +cp_ccrestart(bool kwords) +{ + /* Ack. */ + return; +} + +void +throwaway(struct ccom *dbase) +{ + if (dbase->cc_child) + throwaway(dbase->cc_child); + if (dbase->cc_sibling) + throwaway(dbase->cc_sibling); + tfree(dbase); + return; +} + +/* Look up a word in the database. Because of the + * way the tree is set up, this also works for looking up all words with + * a given prefix (if the pref arg is TRUE). If create is TRUE, then the + * node is created if it doesn't already exist. + */ + +static struct ccom * +clookup(register char *word, struct ccom **dd, bool pref, bool create) +{ + register struct ccom *place = *dd, *tmpc; + int ind = 0, i; + char buf[BSIZE_SP]; + +/* printf("----- adding %s -----\n", word); */ +/* prcc(); */ + + if (!place) { + /* This is the first time we were called. */ + if (!create) + return (NULL); + else { + *dd = place = alloc(struct ccom); + ZERO(place, struct ccom); + buf[0] = *word; + buf[1] = '\0'; + place->cc_name = copy(buf); + if (word[1]) + place->cc_invalid = 1; + } + } + while (word[ind]) { + /* Walk down the sibling list until we find a node that + * matches 'word' to 'ind' places. + */ + while ((place->cc_name[ind] < word[ind]) && place->cc_sibling) + place = place->cc_sibling; + if (place->cc_name[ind] < word[ind]) { + /* This line doesn't go out that far... */ + if (create) { + place->cc_sibling = alloc(struct ccom); + ZERO(place->cc_sibling, struct ccom); + place->cc_sibling->cc_ysibling = place; + place->cc_sibling->cc_parent = place->cc_parent; + place = place->cc_sibling; + place->cc_name = tmalloc(ind + 2); + for (i = 0; i < ind + 1; i++) + place->cc_name[i] = word[i]; + place->cc_name[ind + 1] = '\0'; + place->cc_invalid = 1; + } else { + return (NULL); + } + } else if (place->cc_name[ind] > word[ind]) { + if (create) { + /* Put this one between place and its pred. */ + tmpc = alloc(struct ccom); + ZERO(tmpc, struct ccom); + tmpc->cc_parent = place->cc_parent; + tmpc->cc_sibling = place; + tmpc->cc_ysibling = place->cc_ysibling; + place->cc_ysibling = tmpc; + place = tmpc; + if (tmpc->cc_ysibling) + tmpc->cc_ysibling->cc_sibling = tmpc; + else if (tmpc->cc_parent) + tmpc->cc_parent->cc_child = tmpc; + else + *dd = place; + place->cc_name = tmalloc(ind + 2); + for (i = 0; i < ind + 1; i++) + place->cc_name[i] = word[i]; + place->cc_name[ind + 1] = '\0'; + place->cc_invalid = 1; + } else { + return (NULL); + } + } + + /* place now points to that node that matches the word for + * ind + 1 characters. + */ +/* printf("place %s, word %s, ind %d\n", place->cc_name, word, ind); */ + if (word[ind + 1]) { /* More to go... */ + if (!place->cc_child) { + /* No children, maybe make one and go on. */ + if (create) { + tmpc = alloc(struct ccom); + ZERO(tmpc, struct ccom); + tmpc->cc_parent = place; + place->cc_child = tmpc; + place = tmpc; + place->cc_name = tmalloc(ind + 3); + for (i = 0; i < ind + 2; i++) + place->cc_name[i] = word[i]; + place->cc_name[ind + 2] = '\0'; + if (word[ind + 2]) + place->cc_invalid = 1; + } else { + return (NULL); + } + } else + place = place->cc_child; + ind++; + } else + break; + } + if (!pref && !create && place->cc_invalid) { + /* This is no good, we want a real word. */ + return (NULL); + } + return (place); +} + +/* Delete a node from the tree. Returns the new tree... */ + +static void +cdelete(struct ccom *node) +{ + node->cc_invalid = 1; + free(node->cc_name); + free(node->cc_child); + free(node->cc_sibling); + free(node->cc_ysibling); + free(node->cc_parent); + return; +} + diff --git a/src/parser/complete.h b/src/parser/complete.h new file mode 100644 index 000000000..1399d0e39 --- /dev/null +++ b/src/parser/complete.h @@ -0,0 +1,45 @@ +/************* + * Header file for complete.c + * 1999 E. Rouat + ************/ + +#ifndef COMPLETE_H_INCLUDED +#define COMPLETE_H_INCLUDED + +/* The data structure for the commands is as follows: every node has a pointer + * to its leftmost child, where the children of a node are those of which + * the node is a prefix. This means that for a word like "ducks", there + * must be nodes "d", "du", "duc", etc (which are all marked "invalid", + * of course). This data structure is called a "trie". + */ + + + +#define NARGS 4 + +struct ccom { + char *cc_name; /* Command or keyword name. */ + long cc_kwords[NARGS]; /* What this command takes. */ + char cc_invalid; /* This node has been deleted. */ + struct ccom *cc_child; /* Left-most child. */ + struct ccom *cc_sibling;/* Right (alph. greater) sibling. */ + struct ccom *cc_ysibling;/* Left (alph. less) sibling. */ + struct ccom *cc_parent; /* Parent node. */ +} ; + + +void cp_ccom(wordlist *wlist, char *buf, bool esc); +wordlist * cp_cctowl(char *stuff); +void cp_ccon(bool on); +bool cp_comlook(char *word); +void cp_addcomm(char *word, long int bits0, long int bits1, long int bits2, + long int bits3); +void cp_remcomm(char *word); +void cp_addkword(int class, char *word); +void cp_remkword(int class, char *word); +char * cp_kwswitch(int class, char *tree); +void cp_ccrestart(bool kwords); +void throwaway(struct ccom *dbase); + + +#endif diff --git a/src/parser/cshpar.c b/src/parser/cshpar.c new file mode 100644 index 000000000..74eb68dee --- /dev/null +++ b/src/parser/cshpar.c @@ -0,0 +1,479 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * The main entry point for cshpar. + */ + + +#include "ngspice.h" +#include "cpdefs.h" +#include +#include "cshpar.h" + +#ifdef HAVE_SGTTY_H +#include +#else +#ifdef HAVE_TERMIO_H +#include +#else +#ifdef HAVE_TERMIOS_H +#include +#endif +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#endif + + +#ifdef HAVE_SYS_WAIT_H +#include +#endif + + + +/* Things go as follows: + * (1) Read the line and do some initial quoting (by setting the 8th bit), + * and command ignoring. Also deal with command completion. + * (2) Do history substitutions. (!, ^) + * (3) Do alias substitution. + * + * In front.c these things get done: + * (4) Do variable substitution. ($varname) + * (5) Do backquote substitution. (``) + * (6) Do globbing. (*, ?, [], {}, ~) + * (7) Do io redirection. + */ + + +static bool fileexists(char *name); +void fixdescriptors(void); +static void pwlist(wordlist *wlist, char *name); + +bool cp_debug = FALSE; +char cp_gt = '>'; +char cp_lt = '<'; +char cp_amp = '&'; + +FILE *cp_in; +FILE *cp_out; +FILE *cp_err; + +/* These are the fps that cp_ioreset resets the cp_* to. They are changed + * by the source routines. + */ + +FILE *cp_curin = NULL; +FILE *cp_curout = NULL; +FILE *cp_curerr = NULL; + +wordlist * +cp_parse(char *string) +{ + wordlist *wlist; + + wlist = cp_lexer(string); + + if (!string) + cp_event++; + + if (!wlist || !wlist->wl_word) + return (wlist); + + pwlist(wlist, "Initial parse"); + + wlist = cp_histsubst(wlist); + if (!wlist || !wlist->wl_word) + return (wlist); + pwlist(wlist, "After history substitution"); + if (cp_didhsubst) { + wl_print(wlist, stdout); + (void) putc('\n', stdout); + } + + /* Add the word list to the history. */ + if (*wlist->wl_word) + cp_addhistent(cp_event - 1, wlist); + + wlist = cp_doalias(wlist); + pwlist(wlist, "After alias substitution"); + + if (string && cp_lastone) { + /* Don't put this one in... */ + cp_lastone = cp_lastone->hi_prev; + if (cp_lastone) + cp_lastone->hi_next = NULL; + } + + pwlist(wlist, "Returning "); + return (wlist); +} + +static void +pwlist(wordlist *wlist, char *name) +{ + wordlist *wl; + + if (!cp_debug) + return; + fprintf(cp_err, "%s : [ ", name); + for (wl = wlist; wl; wl = wl->wl_next) + fprintf(cp_err, "%s ", wl->wl_word); + fprintf(cp_err, "]\n"); + return; +} + +/* This has to go somewhere... */ + +void +com_echo(wordlist *wlist) +{ + bool nl = TRUE; + + if (wlist && eq(wlist->wl_word, "-n")) { + wlist = wlist->wl_next; + nl = FALSE; + } + + while (wlist) { + fputs(cp_unquote(wlist->wl_word), cp_out); + if (wlist->wl_next) + fputs(" ", cp_out); + wlist = wlist->wl_next; + } + if (nl) + fputs("\n", cp_out); +} + +/* This routine sets the cp_{in,out,err} pointers and takes the io + * directions out of the command line. + */ + +wordlist * +cp_redirect(wordlist *wl) +{ + bool gotinput = FALSE, gotoutput = FALSE, goterror = FALSE; + bool app = FALSE, erralso = FALSE; + wordlist *w, *bt, *nw; + char *s; + FILE *tmpfp; + + w = wl->wl_next; /* Don't consider empty commands. */ + while (w) { + if (*w->wl_word == cp_lt) { + bt = w; + if (gotinput) { + fprintf(cp_err, + "Error: ambiguous input redirect.\n"); + goto error; + } + gotinput = TRUE; + w = w->wl_next; + if (w == NULL) { + fprintf(cp_err, + "Error: missing name for input.\n"); + return (NULL); + } + if (*w->wl_word == cp_lt) { + /* Do reasonable stuff here... */ + } else { + tmpfp = fopen(cp_unquote(w->wl_word), "r"); + if (!tmpfp) { + perror(w->wl_word); + goto error; + } else + cp_in = tmpfp; + } +#ifdef CPDEBUG + if (cp_debug) + fprintf(cp_err, "Input file is %s...\n", + w->wl_word); +#endif + bt->wl_prev->wl_next = w->wl_next; + if (w->wl_next) + w->wl_next->wl_prev = bt->wl_prev; + nw = w->wl_next; + w->wl_next = NULL; + w = nw; + wl_free(bt); + } else if (*w->wl_word == cp_gt) { + bt = w; + if (gotoutput) { + fprintf(cp_err, + "Error: ambiguous output redirect.\n"); + goto error; + } + gotoutput = TRUE; + w = w->wl_next; + if (w == NULL) { + fprintf(cp_err, + "Error: missing name for output.\n"); + return (NULL); + } + if (*w->wl_word == cp_gt) { + app = TRUE; + w = w->wl_next; + if (w == NULL) { + fprintf(cp_err, + "Error: missing name for output.\n"); + return (NULL); + } + } + if (*w->wl_word == cp_amp) { + erralso = TRUE; + if (goterror) { + fprintf(cp_err, + "Error: ambiguous error redirect.\n"); + return (NULL); + } + goterror = TRUE; + w = w->wl_next; + if (w == NULL) { + fprintf(cp_err, + "Error: missing name for output.\n"); + return (NULL); + } + } + s = cp_unquote(w->wl_word); + if (cp_noclobber && fileexists(s)) { + fprintf(stderr, "Error: %s: file exists\n", s); + goto error; + } + if (app) + tmpfp = fopen(s, "a"); + else + tmpfp = fopen(s, "w+"); + if (!tmpfp) { + perror(w->wl_word); + goto error; + } else { + cp_out = tmpfp; + out_isatty = FALSE; + } +#ifdef CPDEBUG + if (cp_debug) + fprintf(cp_err, "Output file is %s... %s\n", + w->wl_word, app ? "(append)" : ""); +#endif + bt->wl_prev->wl_next = w->wl_next; + if (w->wl_next) + w->wl_next->wl_prev = bt->wl_prev; + w = w->wl_next; + if (w) + w->wl_prev->wl_next = NULL; + wl_free(bt); + if (erralso) + cp_err = cp_out; + } else + w = w->wl_next; + } + return (wl); + +error: wl_free(wl); + return (NULL); +} + +/* Reset the cp_* FILE pointers to the standard ones. This is tricky, since + * if we are sourcing a command file, and io has been redirected from inside + * the file, we have to reset it back to what it was for the source, not for + * the top level. That way if you type "foo > bar" where foo is a script, + * and it has redirections of its own inside of it, none of the output from + * foo will get sent to stdout... + */ + +void +cp_ioreset(void) +{ + if (cp_in != cp_curin) { + if (cp_in) + (void) fclose(cp_in); + cp_in = cp_curin; + } + if (cp_out != cp_curout) { + if (cp_out) + (void) fclose(cp_out); + cp_out = cp_curout; + } + if (cp_err != cp_curerr) { + if (cp_err) + (void) fclose(cp_err); + cp_err = cp_curerr; + } + + /*** Minor bug here... */ + out_isatty = TRUE; + return; +} + +static bool +fileexists(char *name) +{ +#ifdef HAVE_ACCESS + if (access(name, 0) == 0) + return (TRUE); +#endif + return (FALSE); +} + + +/* Fork a shell. */ + +void +com_shell(wordlist *wl) +{ + char *com, *shell = NULL; + + shell = getenv("SHELL"); + if (shell == NULL) + shell = "/bin/csh"; + + cp_ccon(FALSE); + +#ifdef HAVE_VFORK_H + /* XXX Needs to switch process groups. Also, worry about suspend */ + /* Only bother for efficiency */ + pid = vfork(); + if (pid == 0) { + fixdescriptors(); + if (wl == NULL) { + (void) execl(shell, shell, 0); + _exit(99); + } else { + com = wl_flatten(wl); + (void) execl("/bin/sh", "sh", "-c", com, 0); + } + } else { + /* XXX Better have all these signals */ + svint = signal(SIGINT, SIG_DFL); + svquit = signal(SIGQUIT, SIG_DFL); + svtstp = signal(SIGTSTP, SIG_DFL); + /* XXX Sig on proc group */ + do { + r = wait((union wait *) NULL); + } while ((r != pid) && pid != -1); + (void) signal(SIGINT, (SIGNAL_FUNCTION) svint); + (void) signal(SIGQUIT, (SIGNAL_FUNCTION) svquit); + (void) signal(SIGTSTP, (SIGNAL_FUNCTION) svtstp); + } +#else + /* Easier to forget about changing the io descriptors. */ + if (wl) { + com = wl_flatten(wl); + (void) system(com); + } else + (void) system(shell); +#endif + + return; +} + + +/* Do this only right before an exec, since we lose the old std*'s. */ + +void +fixdescriptors(void) +{ + if (cp_in != stdin) + (void) dup2(fileno(cp_in), fileno(stdin)); + if (cp_out != stdout) + (void) dup2(fileno(cp_out), fileno(stdout)); + if (cp_err != stderr) + (void) dup2(fileno(cp_err), fileno(stderr)); + return; +} + + +void +com_rehash(wordlist *wl) +{ + char *s; + + if (!cp_dounixcom) { + fprintf(cp_err, "Error: unixcom not set.\n"); + return; + } + s = getenv("PATH"); + if (s) + cp_rehash(s, TRUE); + else + fprintf(cp_err, "Error: no PATH in environment.\n"); + return; +} + +void +com_chdir(wordlist *wl) +{ + char *s; + struct passwd *pw; + extern struct passwd *getpwuid(uid_t); + char localbuf[257]; + int copied = 0; + + s = NULL; + + if (wl == NULL) { + + s = getenv("HOME"); + +#ifdef HAVE_PWD_H + if (s == NULL) { + pw = getpwuid(getuid()); + if (pw == NULL) { + fprintf(cp_err, "Can't get your password entry\n"); + return; + } + s = pw->pw_dir; + } +#endif + } else { + s = cp_unquote(wl->wl_word); + copied = 1; + } + + + + if (*s && chdir(s) == -1) + perror(s); + + if (copied) + tfree(s); + +#ifdef HAVE_GETCWD + if ((s = (char *)getcwd(localbuf, sizeof(localbuf)))) + printf("Current directory: %s\n", s); + else + fprintf(cp_err, "Can't get current working directory.\n"); +#endif + + return; + +} + + + +/* This is a truly evil thing */ + +void +com_strcmp(wordlist *wl) +{ + char *var, *s1, *s2; + int i; + + var = wl->wl_word; + s1 = cp_unquote(wl->wl_next->wl_word); + s2 = cp_unquote(wl->wl_next->wl_next->wl_word); + + i = strcmp(s1, s2); + + cp_vset(var, VT_NUM, (char *) &i); + return; +} + diff --git a/src/parser/cshpar.h b/src/parser/cshpar.h new file mode 100644 index 000000000..735302a60 --- /dev/null +++ b/src/parser/cshpar.h @@ -0,0 +1,20 @@ +/************* + * Header file for cshpar.c + * 1999 E. Rouat + ************/ + +#ifndef CSHPAR_H_INCLUDED +#define CSHPAR_H_INCLUDED + +wordlist * cp_parse(char *string); +void com_echo(wordlist *wlist); +wordlist * cp_redirect(wordlist *wl); +void cp_ioreset(void); +void com_shell(wordlist *wl); +void fixdescriptors(void); +void com_rehash(wordlist *wl); +void com_chdir(wordlist *wl); +void com_strcmp(wordlist *wl); + + +#endif diff --git a/src/parser/front.c b/src/parser/front.c new file mode 100644 index 000000000..8852ec84c --- /dev/null +++ b/src/parser/front.c @@ -0,0 +1,960 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * The front-end command loop. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "front.h" + +/* Return values from doblock(). I am assuming that nobody will use these + * characters in a string. + */ + +#define NORMAL '\001' +#define BROKEN '\002' +#define CONTINUED '\003' +#define NORMAL_STR "\001" +#define BROKEN_STR "\002" +#define CONTINUED_STR "\003" + +/* Are we waiting for a command? This lets (void) signal handling be +more clever. */ + +bool cp_cwait = FALSE; +char *cp_csep = ";"; + +bool cp_dounixcom = FALSE; + + + + +#define CO_UNFILLED 0 +#define CO_STATEMENT 1 +#define CO_WHILE 2 +#define CO_DOWHILE 3 +#define CO_IF 4 +#define CO_FOREACH 5 +#define CO_BREAK 6 +#define CO_CONTINUE 7 +#define CO_LABEL 8 +#define CO_GOTO 9 +#define CO_REPEAT 10 + +/* We have to keep the control structures in a stack, so that when we do + * a 'source', we can push a fresh set onto the top... Actually there have + * to be two stacks -- one for the pointer to the list of control structs, + * and one for the 'current command' pointer... + */ + +#define CONTROLSTACKSIZE 256 /* Better be enough. */ +static struct control *control[CONTROLSTACKSIZE], *cend[CONTROLSTACKSIZE]; + + +/* static declarations */ +static char * doblock(struct control *bl, int *num); +static struct control * findlabel(char *s, struct control *ct); +static void docommand(register wordlist *wlist); +static wordlist * getcommand(char *string); +static void pwlist(wordlist *wlist, char *name); +static void dodump(struct control *cc); + + +static int stackp = 0; + +/* If there is an argument, give this to cshpar to use instead of stdin. In + * a few places, we call cp_evloop again if it returns 1 and exit (or close + * a file) if it returns 0... Because of the way sources are done, we can't + * allow the control structures to get blown away every time we return -- + * probably every time we type source at the keyboard and every time a + * source returns to keyboard input is ok though -- use ft_controlreset. + */ + +static char *noredirect[] = { "stop", NULL } ; /* Only one?? */ + + + + + +int +cp_evloop(char *string) +{ + wordlist *wlist, *ww; + struct control *x; + char *i; + int nn; + +#define newblock cend[stackp]->co_children = alloc(struct control); \ + ZERO(cend[stackp]->co_children,struct control), \ + cend[stackp]->co_children->co_parent = cend[stackp]; \ + cend[stackp] = cend[stackp]->co_children; \ + cend[stackp]->co_type = CO_UNFILLED; + + for (;;) { + wlist = getcommand(string); + if (wlist == NULL) { /* End of file or end of user input. */ + if (cend[stackp]->co_parent && !string) { + cp_resetcontrol(); + continue; + } else + return (0); + } + if ((wlist->wl_word == NULL) || (*wlist->wl_word == '\0')) { + /* User just typed return. */ + if (string) + return (1); + else { + cp_event--; + continue; + } + } + + /* Just a check... */ + for (ww = wlist; ww; ww = ww->wl_next) + if (!ww->wl_word) { + fprintf(cp_err, + "cp_evloop: Internal Error: NULL word pointer\n"); + continue; + } + + + /* Add this to the control structure list. If cend->co_type + * is CO_UNFILLED, the last line was the beginning of a + * block, and this is the unfilled first statement. + */ + if (cend[stackp] && (cend[stackp]->co_type != CO_UNFILLED)) { + cend[stackp]->co_next = alloc(struct control); + ZERO(cend[stackp]->co_next, struct control); + cend[stackp]->co_next->co_prev = cend[stackp]; + cend[stackp]->co_next->co_parent = + cend[stackp]->co_parent; + cend[stackp] = cend[stackp]->co_next; + } else if (!cend[stackp]) { + control[stackp] = cend[stackp] = alloc(struct control); + ZERO(cend[stackp], struct control); + } + + if (eq(wlist->wl_word, "while")) { + cend[stackp]->co_type = CO_WHILE; + cend[stackp]->co_cond = wlist->wl_next; + if (!cend[stackp]->co_cond) { + fprintf(stderr, + "Error: missing while condition.\n"); + } + newblock; + } else if (eq(wlist->wl_word, "dowhile")) { + cend[stackp]->co_type = CO_DOWHILE; + cend[stackp]->co_cond = wlist->wl_next; + if (!cend[stackp]->co_cond) { + fprintf(stderr, + "Error: missing dowhile condition.\n"); + } + newblock; + } else if (eq(wlist->wl_word, "repeat")) { + cend[stackp]->co_type = CO_REPEAT; + if (!wlist->wl_next) { + cend[stackp]->co_numtimes = -1; + } else { + char *s; + double *dd; + wlist = cp_variablesubst(cp_bquote( + cp_doglob(wl_copy(wlist)))); + s = wlist->wl_next->wl_word; + + dd = ft_numparse(&s, FALSE); + if (dd) { + if (*dd < 0) { + fprintf(cp_err, + "Error: can't repeat a negative number of times\n"); + *dd = 0.0; + } + cend[stackp]->co_numtimes = (int) *dd; + } else + fprintf(cp_err, + "Error: bad repeat argument %s\n", + wlist->wl_next->wl_word); + } + newblock; + } else if (eq(wlist->wl_word, "if")) { + cend[stackp]->co_type = CO_IF; + cend[stackp]->co_cond = wlist->wl_next; + if (!cend[stackp]->co_cond) { + fprintf(stderr, + "Error: missing if condition.\n"); + } + newblock; + } else if (eq(wlist->wl_word, "foreach")) { + cend[stackp]->co_type = CO_FOREACH; + if (wlist->wl_next) { + wlist = wlist->wl_next; + cend[stackp]->co_foreachvar = + copy(wlist->wl_word); + wlist = wlist->wl_next; + } else + fprintf(stderr, + "Error: missing foreach variable.\n"); + wlist = cp_doglob(wlist); + cend[stackp]->co_text = wl_copy(wlist); + newblock; + } else if (eq(wlist->wl_word, "label")) { + cend[stackp]->co_type = CO_LABEL; + if (wlist->wl_next) { + cend[stackp]->co_text = wl_copy(wlist->wl_next); + /* I think of everything, don't I? */ + cp_addkword(CT_LABEL, wlist->wl_next->wl_word); + if (wlist->wl_next->wl_next) + fprintf(cp_err, + "Warning: ignored extra junk after label.\n"); + } else + fprintf(stderr, "Error: missing label.\n"); + } else if (eq(wlist->wl_word, "goto")) { + /* Incidentally, this won't work if the values 1 and + * 2 ever get to be valid character pointers -- I + * think it's reasonably safe to assume they aren't... + */ + cend[stackp]->co_type = CO_GOTO; + if (wlist->wl_next) { + cend[stackp]->co_text = wl_copy(wlist->wl_next); + if (wlist->wl_next->wl_next) + fprintf(cp_err, + "Warning: ignored extra junk after goto.\n"); + } else + fprintf(stderr, "Error: missing label.\n"); + } else if (eq(wlist->wl_word, "continue")) { + cend[stackp]->co_type = CO_CONTINUE; + if (wlist->wl_next) { + cend[stackp]->co_numtimes = scannum(wlist-> + wl_next->wl_word); + if (wlist->wl_next->wl_next) + fprintf(cp_err, + "Warning: ignored extra junk after continue %d.\n", + cend[stackp]->co_numtimes); + } else + cend[stackp]->co_numtimes = 1; + } else if (eq(wlist->wl_word, "break")) { + cend[stackp]->co_type = CO_BREAK; + if (wlist->wl_next) { + cend[stackp]->co_numtimes = scannum(wlist-> + wl_next->wl_word); + if (wlist->wl_next->wl_next) + fprintf(cp_err, + "Warning: ignored extra junk after break %d.\n", + cend[stackp]->co_numtimes); + } else + cend[stackp]->co_numtimes = 1; + } else if (eq(wlist->wl_word, "end")) { + /* Throw away this thing. */ + if (!cend[stackp]->co_parent) { + fprintf(stderr, "Error: no block to end.\n"); + cend[stackp]->co_type = CO_UNFILLED; + } else if (cend[stackp]->co_prev) { + cend[stackp]->co_prev->co_next = NULL; + x = cend[stackp]; + cend[stackp] = cend[stackp]->co_parent; + tfree(x); + } else { + x = cend[stackp]; + cend[stackp] = cend[stackp]->co_parent; + cend[stackp]->co_children = NULL; + tfree(x); + } + } else if (eq(wlist->wl_word, "else")) { + if (!cend[stackp]->co_parent || + (cend[stackp]->co_parent->co_type != + CO_IF)) { + fprintf(stderr, "Error: misplaced else.\n"); + cend[stackp]->co_type = CO_UNFILLED; + } else { + if (cend[stackp]->co_prev) + cend[stackp]->co_prev->co_next = NULL; + else + cend[stackp]->co_parent->co_children = + NULL; + cend[stackp]->co_parent->co_elseblock = + cend[stackp]; + cend[stackp]->co_prev = NULL; + } + } else { + cend[stackp]->co_type = CO_STATEMENT; + cend[stackp]->co_text = wlist; + } + if (!cend[stackp]->co_parent) { + x = cend[stackp]; + /* We have to toss this do-while loop in here so + * that gotos at the top level will work. + */ + do { + i = doblock(x, &nn); + switch (*i) { + case NORMAL: + break; + case BROKEN: + fprintf(cp_err, + "Error: break not in loop or too many break levels given\n"); + break; + case CONTINUED: + fprintf(cp_err, + "Error: continue not in loop or too many continue levels given\n"); + break; + default: + x = findlabel(i, + control[stackp]); + if (!x) + fprintf(cp_err, + "Error: label %s not found\n", + i); + } + if (x) + x = x->co_next; + } while (x); + } + if (string) + return (1); /* The return value is irrelevant. */ + } +} + +/* Execute a block. There can be a number of return values from this routine. + * NORMAL indicates a normal termination + * BROKEN indicates a break -- if the caller is a breakable loop, + * terminate it, otherwise pass the break upwards + * CONTINUED indicates a continue -- if the caller is a continuable loop, + * continue, else pass the continue upwards + * Any other return code is considered a pointer to a string which is + * a label somewhere -- if this label is present in the block, + * goto it, otherwise pass it up. Note that this prevents jumping + * into a loop, which is good. + * Note that here is where we expand variables, ``, and globs for controls. + * The 'num' argument is used by break n and continue n. + */ + +static char * +doblock(struct control *bl, int *num) +{ + struct control *ch, *cn = NULL; + wordlist *wl; + char *i; + int nn; + + switch (bl->co_type) { + + case CO_WHILE: + while (bl->co_cond && cp_isTRUE(bl->co_cond)) { + for (ch = bl->co_children; ch; ch = cn) { + cn = ch->co_next; + i = doblock(ch, &nn); + switch (*i) { + + case NORMAL: + break; + + case BROKEN: /* Break. */ + if (nn < 2) + return (NORMAL_STR); + else { + *num = nn - 1; + return (BROKEN_STR); + } + + case CONTINUED: /* Continue. */ + if (nn < 2) { + cn = NULL; + break; + } else { + *num = nn - 1; + return (CONTINUED_STR); + } + + default: + cn = findlabel(i, bl->co_children); + if (!cn) + return (i); + } + } + } + break; + + case CO_DOWHILE: + do { + for (ch = bl->co_children; ch; ch = cn) { + cn = ch->co_next; + i = doblock(ch, &nn); + switch (*i) { + + case NORMAL: + break; + + case BROKEN: /* Break. */ + if (nn < 2) + return (NORMAL_STR); + else { + *num = nn - 1; + return (BROKEN_STR); + } + + case CONTINUED: /* Continue. */ + if (nn < 2) { + cn = NULL; + break; + } else { + *num = nn - 1; + return (CONTINUED_STR); + } + + default: + cn = findlabel(i, bl->co_children); + if (!cn) + return (i); + } + } + } while (bl->co_cond && cp_isTRUE(bl->co_cond)); + break; + + case CO_REPEAT: + while ((bl->co_numtimes > 0) || + (bl->co_numtimes == -1)) { + if (bl->co_numtimes != -1) + bl->co_numtimes--; + for (ch = bl->co_children; ch; ch = cn) { + cn = ch->co_next; + i = doblock(ch, &nn); + switch (*i) { + + case NORMAL: + break; + + case BROKEN: /* Break. */ + if (nn < 2) + return (NORMAL_STR); + else { + *num = nn - 1; + return (BROKEN_STR); + } + + case CONTINUED: /* Continue. */ + if (nn < 2) { + cn = NULL; + break; + } else { + *num = nn - 1; + return (CONTINUED_STR); + } + + default: + cn = findlabel(i, bl->co_children); + if (!cn) + return (i); + } + } + } + break; + + case CO_IF: + if (bl->co_cond && cp_isTRUE(bl->co_cond)) { + for (ch = bl->co_children; ch; ch = cn) { + cn = ch->co_next; + i = doblock(ch, &nn); + if (*i > 2) { + cn = findlabel(i, + bl->co_children); + if (!cn) + return (i); + } else if (*i != NORMAL) { + *num = nn; + return (i); + } + } + } else { + for (ch = bl->co_elseblock; ch; ch = cn) { + cn = ch->co_next; + i = doblock(ch, &nn); + if (*i > 2) { + cn = findlabel(i, + bl->co_elseblock); + if (!cn) + return (i); + } else if (*i != NORMAL) { + *num = nn; + return (i); + } + } + } + break; + + case CO_FOREACH: + for (wl = cp_variablesubst(cp_bquote(cp_doglob(wl_copy(bl-> + co_text)))); wl; wl = wl->wl_next) { + cp_vset(bl->co_foreachvar, VT_STRING, + wl->wl_word); + for (ch = bl->co_children; ch; ch = cn) { + cn = ch->co_next; + i = doblock(ch, &nn); + switch (*i) { + + case NORMAL: + break; + + case BROKEN: /* Break. */ + if (nn < 2) + return (NORMAL_STR); + else { + *num = nn - 1; + return (BROKEN_STR); + } + + case CONTINUED: /* Continue. */ + if (nn < 2) { + cn = NULL; + break; + } else { + *num = nn - 1; + return (CONTINUED_STR); + } + + default: + cn = findlabel(i, bl->co_children); + if (!cn) + return (i); + } + } + } + break; + + case CO_BREAK: + if (bl->co_numtimes > 0) { + *num = bl->co_numtimes; + return (BROKEN_STR); + } else { + fprintf(cp_err, "Warning: break %d a no-op\n", + bl->co_numtimes); + return (NORMAL_STR); + } + + case CO_CONTINUE: + if (bl->co_numtimes > 0) { + *num = bl->co_numtimes; + return (CONTINUED_STR); + } else { + fprintf(cp_err, "Warning: continue %d a no-op\n", + bl->co_numtimes); + return (NORMAL_STR); + } + + case CO_GOTO: + wl = cp_variablesubst(cp_bquote(cp_doglob( + wl_copy(bl->co_text)))); + return (wl->wl_word); + + case CO_LABEL: + /* Do nothing. */ + break; + + case CO_STATEMENT: + docommand(wl_copy(bl->co_text)); + break; + + case CO_UNFILLED: + /* There was probably an error here... */ + fprintf(cp_err, "Warning: ignoring previous error\n"); + break; + + default: + fprintf(cp_err, + "doblock: Internal Error: bad block type %d\n", + bl->co_type); + return (NORMAL_STR); + } + return (NORMAL_STR); +} +static struct control * +findlabel(char *s, struct control *ct) +{ + while (ct) { + if ((ct->co_type == CO_LABEL) && eq(s, ct->co_text->wl_word)) + break; + ct = ct->co_next; + } + return (ct); +} + +/* This blows away the control structures... */ + +void +cp_resetcontrol(void) +{ + if (cend[stackp] && cend[stackp]->co_parent) + fprintf(cp_err, "Warning: EOF before block terminated\n"); + /* We probably should free the control structures... */ + control[0] = cend[0] = NULL; + stackp = 0; + (void) cp_kwswitch(CT_LABEL, (char *) NULL); + return; +} + +/* Push or pop a new control structure set... */ + +void +cp_popcontrol(void) +{ + if (cp_debug) + fprintf(cp_err, "pop: stackp: %d -> %d\n", stackp, stackp - 1); + if (stackp < 1) + fprintf(cp_err, "cp_popcontrol: Internal Error: stack empty\n"); + else + stackp--; + return; +} + +void +cp_pushcontrol(void) +{ + if (cp_debug) + fprintf(cp_err, "push: stackp: %d -> %d\n", stackp, stackp + 1); + if (stackp > CONTROLSTACKSIZE - 2) { + fprintf(cp_err, "Error: stack overflow -- max depth = %d\n", + CONTROLSTACKSIZE); + stackp = 0; + } else { + stackp++; + control[stackp] = cend[stackp] = NULL; + } + return; +} + +/* And this returns to the top level (for use in the interrupt handlers). */ + +void +cp_toplevel(void) +{ + stackp = 0; + if (cend[stackp]) + while (cend[stackp]->co_parent) + cend[stackp] = cend[stackp]->co_parent; + return; +} + +/* Note that we only do io redirection when we get to here - we also + * postpone some other things until now. + */ + +static void +docommand(register wordlist *wlist) +{ + register char *r, *s, *t; + char *lcom; + int nargs; + register int i; + struct comm *command; + wordlist *wl, *nextc, *ee, *rwlist; + + if (cp_debug) { + printf("docommand "); + wl_print(wlist, stdout); + (void) putc('\n', stdout); + } + + /* Do all the things that used to be done by cshpar when the line + * was read... + */ + wlist = cp_variablesubst(wlist); + pwlist(wlist, "After variable substitution"); + + wlist = cp_bquote(wlist); + pwlist(wlist, "After backquote substitution"); + + wlist = cp_doglob(wlist); + pwlist(wlist, "After globbing"); + + if (!wlist || !wlist->wl_word) + return; + + /* Now loop through all of the commands given. */ + rwlist = wlist; + do { + for (nextc = wlist; nextc; nextc = nextc->wl_next) + if (eq(nextc->wl_word, cp_csep)) + break; + + /* Temporarily hide the rest of the command... */ + if (nextc && nextc->wl_prev) + nextc->wl_prev->wl_next = NULL; + ee = wlist->wl_prev; + if (ee) + wlist->wl_prev = NULL; + + if (nextc == wlist) { + /* There was no text... */ + goto out; + } + + /* And do the redirection. */ + cp_ioreset(); + for (i = 0; noredirect[i]; i++) + if (eq(wlist->wl_word, noredirect[i])) + break; + if (!noredirect[i]) { + if (!(wlist = cp_redirect(wlist))) { + cp_ioreset(); + return; + } + } + + /* Get rid of all the 8th bits now... */ + cp_striplist(wlist); + + s = wlist->wl_word; + + /* Look for the command in the command list. */ + for (i = 0; cp_coms[i].co_comname; i++) { + /* strcmp(cp_coms[i].co_comname, s) ... */ + for (t = cp_coms[i].co_comname, r = s; *t && *r; + t++, r++) + if (*t != *r) + break; + if (!*t && !*r) + break; + } + + /* Now give the user-supplied command routine a try... */ + if (!cp_coms[i].co_func && cp_oddcomm(s, wlist->wl_next)) + goto out; + + /* If it's not there, try it as a unix command. */ + if (!cp_coms[i].co_comname) { + if (cp_dounixcom && cp_unixcom(wlist)) + goto out; + fprintf(cp_err,"%s: no such command available in %s\n", + s, cp_program); + goto out; + + /* If it's there but spiceonly, and this is nutmeg, error. */ + } else if (!cp_coms[i].co_func && ft_nutmeg && + (cp_coms[i].co_spiceonly)) { + fprintf(cp_err,"%s: command available only in spice\n", + s); + goto out; + } + + /* The command was a valid spice/nutmeg command. */ + command = &cp_coms[i]; + nargs = 0; + for (wl = wlist->wl_next; wl; wl = wl->wl_next) + nargs++; + if (command->co_stringargs) { + lcom = wl_flatten(wlist->wl_next); + (*command->co_func) (lcom); + } else { + if (nargs < command->co_minargs) { + if (command->co_argfn) { + (*command->co_argfn) (wlist->wl_next, command); + } else { + fprintf(cp_err, "%s: too few args.\n", s); + } + } else if (nargs > command->co_maxargs) { + fprintf(cp_err, "%s: too many args.\n", s); + } else + (*command->co_func) (wlist->wl_next); + } + + /* Now fix the pointers and advance wlist. */ +out: wlist->wl_prev = ee; + if (nextc) { + if (nextc->wl_prev) + nextc->wl_prev->wl_next = nextc; + wlist = nextc->wl_next; + } + } while (nextc && wlist); + + wl_free(rwlist); + + /* Do periodic sorts of things... */ + cp_periodic(); + + cp_ioreset(); + return; +} + +/* Get a command. This does all the bookkeeping things like turning + * command completion on and off... + */ + +static wordlist * +getcommand(char *string) +{ + wordlist *wlist; + int i = 0, j; + static char buf[64]; + struct control *c; + + if (cp_debug) + fprintf(cp_err, "calling getcommand %s\n", + string ? string : ""); + if (cend[stackp]) { + for (c = cend[stackp]->co_parent; c; c = c->co_parent) + i++; + if (i) { + for (j = 0; j < i; j++) + buf[j] = '>'; + buf[j] = ' '; + buf[j + 1] = '\0'; + cp_altprompt = buf; + } else + cp_altprompt = NULL; + } else + cp_altprompt = NULL; + + cp_cwait = TRUE; + wlist = cp_parse(string); + cp_cwait = FALSE; + if (cp_debug) { + printf("getcommand "); + wl_print(wlist, stdout); + (void) putc('\n', stdout); + } + return (wlist); +} + +/* This is also in cshpar.c ... */ + +static void +pwlist(wordlist *wlist, char *name) +{ + wordlist *wl; + + if (!cp_debug) + return; + fprintf(cp_err, "%s : [ ", name); + for (wl = wlist; wl; wl = wl->wl_next) + fprintf(cp_err, "%s ", wl->wl_word); + fprintf(cp_err, "]\n"); + return; +} + +static int indent; + + +void +com_cdump(wordlist *wl) +{ + struct control *c; + + indent = 0; + for (c = control[stackp]; c; c = c->co_next) + dodump(c); + return; +} + +#define tab(num) for (i = 0; i < num; i++) (void) putc(' ', cp_out); + +static void +dodump(struct control *cc) +{ + int i; + struct control *tc; + + switch (cc->co_type) { + case CO_UNFILLED: + tab(indent); + fprintf(cp_out, "(unfilled)\n"); + break; + case CO_STATEMENT: + tab(indent); + wl_print(cc->co_text, cp_out); + (void) putc('\n', cp_out); + break; + case CO_WHILE: + tab(indent); + fprintf(cp_out, "while "); + wl_print(cc->co_cond, cp_out); + (void) putc('\n', cp_out); + indent += 8; + for (tc = cc->co_children; tc; tc = tc->co_next) + dodump(tc); + indent -= 8; + tab(indent); + fprintf(cp_out, "end\n"); + break; + case CO_REPEAT: + tab(indent); + fprintf(cp_out, "repeat "); + if (cc->co_numtimes != -1) + fprintf(cp_out, "%d\n", cc->co_numtimes); + else + (void) putc('\n', cp_out); + indent += 8; + for (tc = cc->co_children; tc; tc = tc->co_next) + dodump(tc); + indent -= 8; + tab(indent); + fprintf(cp_out, "end\n"); + break; + case CO_DOWHILE: + tab(indent); + fprintf(cp_out, "dowhile "); + wl_print(cc->co_cond, cp_out); + (void) putc('\n', cp_out); + indent += 8; + for (tc = cc->co_children; tc; tc = tc->co_next) + dodump(tc); + indent -= 8; + tab(indent); + fprintf(cp_out, "end\n"); + break; + case CO_IF: + tab(indent); + fprintf(cp_out, "if "); + wl_print(cc->co_cond, cp_out); + (void) putc('\n', cp_out); + indent += 8; + for (tc = cc->co_children; tc; tc = tc->co_next) + dodump(tc); + indent -= 8; + tab(indent); + fprintf(cp_out, "end\n"); + break; + case CO_FOREACH: + tab(indent); + fprintf(cp_out, "foreach %s ", cc->co_foreachvar); + wl_print(cc->co_text, cp_out); + (void) putc('\n', cp_out); + indent += 8; + for (tc = cc->co_children; tc; tc = tc->co_next) + dodump(tc); + indent -= 8; + tab(indent); + fprintf(cp_out, "end\n"); + break; + case CO_BREAK: + tab(indent); + if (cc->co_numtimes != 1) + fprintf(cp_out, "break %d\n", cc->co_numtimes); + else + fprintf(cp_out, "break\n"); + break; + case CO_CONTINUE: + tab(indent); + if (cc->co_numtimes != 1) + fprintf(cp_out, "continue %d\n", + cc->co_numtimes); + else + fprintf(cp_out, "continue\n"); + break; + case CO_LABEL: + tab(indent); + fprintf(cp_out, "label %s\n", cc->co_text->wl_word); + break; + case CO_GOTO: + tab(indent); + fprintf(cp_out, "goto %s\n", cc->co_text->wl_word); + break; + default: + tab(indent); + fprintf(cp_out, "bad type %d\n", cc->co_type); + break; + } + return; +} + diff --git a/src/parser/front.h b/src/parser/front.h new file mode 100644 index 000000000..b261bf57d --- /dev/null +++ b/src/parser/front.h @@ -0,0 +1,40 @@ +/************* + * Header file for front.c + * 1999 E. Rouat + ************/ + +#ifndef FRONT_H_INCLUDED +#define FRONT_H_INCLUDED + +/* Stuff to do control structures. We keep a history (seperate from the + * cshpar history, for now at least) of commands and their event numbers, + * with a block considered as a statement. In a goto, the first word in + * co_text is where to go, likewise for label. For conditional controls, + * we have to call ft_getpnames and ft_evaluate each time, since the + * dvec pointers will change... Also we should do variable and backquote + * substitution each time... + */ + +struct control { + int co_type; /* One of CO_* ... */ + wordlist *co_cond; /* if, while, dowhile */ + char *co_foreachvar; /* foreach */ + int co_numtimes; /* repeat, break & continue levels */ + wordlist *co_text; /* Ordinary text and foreach values. */ + struct control *co_parent; /* If this is inside a block. */ + struct control *co_children; /* The contents of this block. */ + struct control *co_elseblock; /* For if-then-else. */ + struct control *co_next; + struct control *co_prev; +} ; + +int cp_evloop(char *string); +void cp_resetcontrol(void); +void cp_popcontrol(void); +void cp_pushcontrol(void); +void cp_toplevel(void); +void com_cdump(wordlist *wl); + + + +#endif diff --git a/src/parser/glob.c b/src/parser/glob.c new file mode 100644 index 000000000..e58d1f1f3 --- /dev/null +++ b/src/parser/glob.c @@ -0,0 +1,97 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Expand global characters. + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "glob.h" + +#ifdef HAVE_SYS_DIR_H +#include +#include +#else + +#ifdef HAVE_DIRENT_H +#include +#include +#ifndef direct +#define direct dirent +#endif +#endif + +#endif + +#ifdef HAVE_PWD_H +#include +#endif + + + +bool noglobs(); + +char cp_comma = ','; +char cp_til = '~'; + +/* For each word, go through two steps: expand the {}'s, and then do ?*[] + * globbing in them. Sort after the second phase but not the first... + */ + +/* MW. Now only tilde is supportef, {}*? don't work */ + +wordlist * +cp_doglob(wordlist *wlist) +{ + wordlist *wl; + char *s; + + + /* Do tilde expansion. */ + + for (wl = wlist; wl; wl = wl->wl_next) + if (*wl->wl_word == cp_til) { + s = cp_tildexpand(wl->wl_word); + if (!s) + *wl->wl_word = '\0'; /* MW. We Con't touch malloc addres */ + else + wl->wl_word = s; + } + + return (wlist); +} + +/* Expand tildes. */ + +char * +cp_tildexpand(char *string) +{ + char *result; + + result = tilde_expand(string); + + if (!result) { + if (cp_nonomatch) { + return copy(string); + } else { + return NULL; + } + } + return result; +} + + +/* Say whether the pattern p can match the string s. */ + +/* MW. Now simply compare strings */ + +bool +cp_globmatch(char *p, char *s) +{ + return(!(strcmp(p, s))); +} + diff --git a/src/parser/glob.h b/src/parser/glob.h new file mode 100644 index 000000000..01f73ce66 --- /dev/null +++ b/src/parser/glob.h @@ -0,0 +1,14 @@ +/************* + * Header file for glob.c + * 1999 E. Rouat + ************/ + +#ifndef GLOB_H_INCLUDED +#define GLOB_H_INCLUDED + +wordlist * cp_doglob(wordlist *wlist); +char * cp_tildexpand(char *string); +bool cp_globmatch(char *p, char *s); + + +#endif diff --git a/src/parser/history.c b/src/parser/history.c new file mode 100644 index 000000000..3fd80a272 --- /dev/null +++ b/src/parser/history.c @@ -0,0 +1,489 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Do history substitutions. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "history.h" + + +/* static declarations */ +static wordlist * dohsubst(char *string); +static wordlist * dohmod(char **string, wordlist *wl); +static wordlist * hpattern(char *buf); +static wordlist * hprefix(char *buf); +static wordlist * getevent(int num); +static void freehist(int num); +static char * dohs(char *pat, char *str); + + +struct histent *cp_lastone = NULL; +int cp_maxhistlength = 10000; /* Chris Inbody */ +char cp_hat = '^'; +char cp_bang = '!'; +bool cp_didhsubst; + +static struct histent *histlist = NULL; +static int histlength = 0; + +/* First check for a ^ at the beginning + * of the line, and then search each word for !. Following this can be any + * of string, number, ?string, -number ; then there may be a word specifier, + * the same as csh, and then the : modifiers. For the :s modifier, + * the syntax is :sXoooXnnnX, where X is any character, and ooo and nnn are + * strings not containing X. + */ + +wordlist * +cp_histsubst(wordlist *wlist) +{ + wordlist *nwl, *w, *n; + char buf[BSIZE_SP], *s, *b; + + /* Replace ^old^new with !:s^old^new. */ + + cp_didhsubst = FALSE; + if (*wlist->wl_word == cp_hat) { + (void) sprintf(buf, "%c%c:s%s", cp_bang, cp_bang, + wlist->wl_word); + tfree(wlist->wl_word); + wlist->wl_word = copy(buf); + } + for (w = wlist; w; w = w->wl_next) { + b = w->wl_word; + for (s = b; *s; s++) + if (*s == cp_bang) { + cp_didhsubst = TRUE; + n = dohsubst(s + 1); + if (!n) { + wlist->wl_word = NULL; + return (wlist); + } + if (b < s) { + (void) sprintf(buf, "%.*s%s", s - b, b, + n->wl_word); + tfree(n->wl_word); + n->wl_word = copy(buf); + } + nwl = wl_splice(w, n); + if (wlist == w) + wlist = n; + w = nwl; + break; + } + } + return (wlist); +} + +/* Do a history substitution on one word. Figure out which event is + * being referenced, then do word selections and modifications, and + * then stick anything left over on the end of the last word. + */ + +static wordlist * +dohsubst(char *string) +{ + wordlist *wl, *nwl; + char buf[BSIZE_SP], *s, *r = NULL, *t; + + if (*string == cp_bang) { + if (cp_lastone) { + wl = cp_lastone->hi_wlist; + string++; + } else { + fprintf(cp_err, "0: event not found.\n"); + return (NULL); + } + } else { + switch(*string) { + + case '-': + wl = getevent(cp_event - scannum(++string)); + if (!wl) + return (NULL); + while (isdigit(*string)) + string++; + break; + + case '?': + (void) strcpy(buf, string + 1); + if ((s =strchr(buf, '?'))) + *s = '\0'; + wl = hpattern(buf); + if (!wl) + return (NULL); + if (s == NULL) /* No modifiers on this one. */ + return (wl_copy(wl)); + break; + + case '\0': /* Maybe this should be cp_event. */ + wl = alloc(struct wordlist); + wl->wl_word = copy("!"); + wl->wl_next = NULL; + wl->wl_prev = NULL; + cp_didhsubst = FALSE; + return (wl); + + default: + if (isdigit(*string)) { + wl = getevent(scannum(string)); + if (!wl) + return (NULL); + while (isdigit(*string)) + string++; + } else { + (void) strcpy(buf, string); + for (s = ":^$*-%"; *s; s++) { + t =strchr(buf, *s); + if (t && ((t < r) || !r)) { + r = t; + string += r - buf; + } + } + if (r) + *r = '\0'; + else + while (*string) + string++; + if ((buf[0] == '\0') && cp_lastone) + wl = cp_lastone->hi_wlist; + else + wl = hprefix(buf); + if (!wl) + return (NULL); + } + } + } + if (wl == NULL) { /* Shouldn't happen. */ + fprintf(cp_err, "Event not found.\n"); + return (NULL); + } + nwl = dohmod(&string, wl_copy(wl)); + if (!nwl) + return (NULL); + if (*string) { + for (wl = nwl; wl->wl_next; wl = wl->wl_next) + ; + (void) sprintf(buf, "%s%s", wl->wl_word, string); + tfree(wl->wl_word); + wl->wl_word = copy(buf); + } + return (nwl); +} + +static wordlist * +dohmod(char **string, wordlist *wl) +{ + wordlist *w; + char *s; + char *r = NULL, *t; + int numwords, eventlo, eventhi, i; + bool globalsubst; + +anothermod: + numwords = wl_length(wl); + globalsubst = FALSE; + eventlo = 0; + eventhi = numwords - 1; + + /* Now we know what wordlist we want. Take care of modifiers now. */ + r = NULL; + for (s = ":^$*-%"; *s; s++) { + t =strchr(*string, *s); + if (t && ((t < r) || (r == NULL))) + r = t; + } + if (!r) /* No more modifiers. */ + return (wl); + + *string = r; + if (**string == ':') + (*string)++; + + switch(**string) { + case '$': /* Last word. */ + eventhi = eventlo = numwords - 1; + break; + case '*': /* Words 1 through $ */ + if (numwords == 1) + return (NULL); + eventlo = 1; + eventhi = numwords - 1; + break; + case '-': /* Words 0 through ... */ + eventlo = 0; + if (*(*string + 1)) + eventhi = scannum(*string + 1); + else + eventhi = numwords - 1; + if (eventhi > numwords - 1) + eventhi = numwords - 1; + break; + case 'p': /* Print the command and don't execute it. + * This doesn't work quite like csh. + */ + wl_print(wl, cp_out); + (void) putc('\n', cp_out); + return (NULL); + case 's': /* Do a substitution. */ + for (w = wl; w; w = w->wl_next) { + s = dohs(*string + 1, w->wl_word); + if (s) { + tfree(w->wl_word); + w->wl_word = s; + if (globalsubst == FALSE) { + while (**string) + (*string)++; + break; + } + } + } + /* In case globalsubst is TRUE... */ + while (**string) + (*string)++; + break; + default: + if (!isdigit(**string)) { + fprintf(cp_err, "Error: %s: bad modifier.\n", + *string); + return (NULL); + } + i = scannum(*string); + if (i > eventhi) { + fprintf(cp_err, "Error: bad event number %d\n", + i); + return (NULL); + } + eventhi = eventlo = i; + while (isdigit(**string)) + (*string)++; + if (**string == '*') + eventhi = numwords - 1; + if (**string == '-') { + if (!isdigit(*(*string + 1))) + eventhi = numwords - 1; + else { + eventhi = scannum(++*string); + while (isdigit(**string)) + (*string)++; + } + } + } + /* Now change the word list accordingly and make another pass + * if there is more of the substitute left. + */ + + wl = wl_range(wl, eventlo, eventhi); + numwords = wl_length(wl); + if (**string && *++*string) + goto anothermod; + return (wl); +} + +/* Look for an event with a pattern in it... */ + +static wordlist * +hpattern(char *buf) +{ + struct histent *hi; + wordlist *wl; + + if (*buf == '\0') { + fprintf(cp_err, "Bad pattern specification.\n"); + return (NULL); + } + for (hi = cp_lastone; hi; hi = hi->hi_prev) + for (wl = hi->hi_wlist; wl; wl = wl->wl_next) + if (substring(buf, wl->wl_word)) + return (hi->hi_wlist); + fprintf(cp_err, "%s: event not found.\n", buf); + return (NULL); +} + +static wordlist * +hprefix(char *buf) +{ + struct histent *hi; + + if (*buf == '\0') { + fprintf(cp_err, "Bad pattern specification.\n"); + return (NULL); + } + for (hi = cp_lastone; hi; hi = hi->hi_prev) + if (hi->hi_wlist && prefix(buf, hi->hi_wlist->wl_word)) + return (hi->hi_wlist); + fprintf(cp_err, "%s: event not found.\n", buf); + return (NULL); +} + +/* Add a wordlist to the history list. (Done after the first parse.) Note + * that if event numbers are given in a random order that's how they'll + * show up in the history list. + */ + +void +cp_addhistent(int event, wordlist *wlist) +{ + if (cp_lastone && !cp_lastone->hi_wlist) + fprintf(cp_err, "Internal error: bad history list\n"); + if (cp_lastone == NULL) { + cp_lastone = histlist = alloc(struct histent); + cp_lastone->hi_prev = NULL; + } else { + cp_lastone->hi_next = alloc(struct histent); + cp_lastone->hi_next->hi_prev = cp_lastone; + cp_lastone = cp_lastone->hi_next; + } + cp_lastone->hi_next = NULL; + cp_lastone->hi_event = event; + cp_lastone->hi_wlist = wl_copy(wlist); + freehist(histlength - cp_maxhistlength); + histlength++; + return; +} + +/* Get a copy of the wordlist associated with an event. Error if out + * of range. + */ + +static wordlist * +getevent(int num) +{ + struct histent *hi; + + for (hi = histlist; hi; hi = hi->hi_next) + if (hi->hi_event == num) + break; + if (hi == NULL) { + fprintf(cp_err, "%d: event not found.\n", num); + return (NULL); + } + return (wl_copy(hi->hi_wlist)); +} + +/* Print out history between eventhi and eventlo. + * This doesn't remember quoting, so 'hodedo' prints as hodedo. + */ + +void +cp_hprint(int eventhi, int eventlo, bool rev) +{ + struct histent *hi; + + if (rev) { + for (hi = histlist; hi->hi_next; hi = hi->hi_next) + ; + for (; hi; hi = hi->hi_prev) + if ((hi->hi_event <= eventhi) && + (hi->hi_event >= eventlo) && + hi->hi_wlist) { + fprintf(cp_out, "%d\t", hi->hi_event); + wl_print(hi->hi_wlist, cp_out); + (void) putc('\n', cp_out); + } + } else { + for (hi = histlist; hi; hi = hi->hi_next) + if ((hi->hi_event <= eventhi) && + (hi->hi_event >= eventlo) && + hi->hi_wlist) { + fprintf(cp_out, "%d\t", hi->hi_event); + wl_print(hi->hi_wlist, cp_out); + (void) putc('\n', cp_out); + } + } + return; +} + +/* This just gets rid of the first num entries on the history list, and + * decrements histlength. + */ + +static void +freehist(int num) +{ + struct histent *hi; + + if (num < 1) + return; + histlength -= num; + hi = histlist; + while (num-- && histlist->hi_next) + histlist = histlist->hi_next; + if (histlist->hi_prev) { + histlist->hi_prev->hi_next = NULL; + histlist->hi_prev = NULL; + } else + { + fprintf(cp_err, "Internal error: history list mangled\n"); + exit(0); /* Chris Inbody */ + } + while (hi->hi_next) { + wl_free(hi->hi_wlist); + hi = hi->hi_next; + tfree(hi->hi_prev); + } + wl_free(hi->hi_wlist); + tfree(hi); + return; +} + +/* Do a :s substitution. */ + +static char * +dohs(char *pat, char *str) +{ + char schar, *s, *p, buf[BSIZE_SP]; + int i = 0, plen; + bool ok = FALSE; + + pat = copy(pat); /* Don't want to mangle anything. */ + schar = *pat++; + s =strchr(pat, schar); + if (s == NULL) { + fprintf(cp_err, "Bad substitute.\n"); + return (NULL); + } + *s++ = '\0'; + p =strchr(s, schar); + if (p) + *p = '\0'; + plen = strlen(pat) - 1; + for (i = 0; *str; str++) { + if ((*str == *pat) && prefix(pat, str) && (ok == FALSE)) { + for (p = s; *p; p++) + buf[i++] = *p; + str += plen; + ok = TRUE; + } else + buf[i++] = *str; + } + buf[i] = '\0'; + if (ok) + return (copy(buf)); + else + return (NULL); +} + +/* The "history" command. history [-r] [number] */ + +void +com_history(wordlist *wl) +{ + bool rev = FALSE; + + if (wl && eq(wl->wl_word, "-r")) { + wl = wl->wl_next; + rev = TRUE; + } + if (wl == NULL) + cp_hprint(cp_event - 1, cp_event - histlength, rev); + else + cp_hprint(cp_event - 1, cp_event - 1 - atoi(wl->wl_word), rev); + return; +} + diff --git a/src/parser/history.h b/src/parser/history.h new file mode 100644 index 000000000..a98a3ab25 --- /dev/null +++ b/src/parser/history.h @@ -0,0 +1,16 @@ +/************* + * Header file for history.c + * 1999 E. Rouat + ************/ + +#ifndef HISTORY_H_INCLUDED +#define HISTORY_H_INCLUDED + +wordlist * cp_histsubst(wordlist *wlist); +void cp_addhistent(int event, wordlist *wlist); +void cp_hprint(int eventhi, int eventlo, bool rev); +void com_history(wordlist *wl); + + + +#endif diff --git a/src/parser/input.c b/src/parser/input.c new file mode 100644 index 000000000..71ff3032e --- /dev/null +++ b/src/parser/input.c @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jeffrey M. Hsu +**********/ + +/* + * Stand-alone input routine. + */ + +#include "ngspice.h" +#include "fteinput.h" +#include "input.h" + + +extern int inchar(FILE *fp); + +void +Input(REQUEST *request, RESPONSE *response) +{ + + switch (request->option) { + case char_option: + response->reply.ch = inchar(request->fp); + response->option = request->option; + break; + default: + /* just ignore, since we don't want a million error messages */ + response->option = error_option; + break; + } + return; + +} diff --git a/src/parser/input.h b/src/parser/input.h new file mode 100644 index 000000000..25c9f88f3 --- /dev/null +++ b/src/parser/input.h @@ -0,0 +1,13 @@ +/************* + * Header file for input.c + * 1999 E. Rouat + ************/ + +#ifndef INPUT_H_INCLUDED +#define INPUT_H_INCLUDED + + +void Input(REQUEST *request, RESPONSE *response); + + +#endif diff --git a/src/parser/lexical.c b/src/parser/lexical.c new file mode 100644 index 000000000..5c0d8e8b0 --- /dev/null +++ b/src/parser/lexical.c @@ -0,0 +1,368 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Initial lexer. + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_PWD_H +#include +#include +#endif + + /* MW. Linux has TIOCSTI, so we include all headers here */ +#include + +#ifdef HAVE_SGTTY_H +#include +#include +#else +#ifdef HAVE_TERMIO_H +#include +#include +#else +#ifdef HAVE_TERMIOS_H +#include +#include +#endif +#endif +#endif + + +#include "fteinput.h" +#include "lexical.h" + +static void prompt(void); + + +FILE *cp_inp_cur = NULL; +int cp_event = 1; +bool cp_interactive = TRUE; +bool cp_bqflag = FALSE; +char *cp_promptstring = NULL; +char *cp_altprompt = NULL; +char cp_hash = '#'; + +static int numeofs = 0; + + +extern void Input(); + +#define ESCAPE '\033' + +/* Return a list of words, with backslash quoting and '' quoting done. + * Strings en(void) closed in "" or `` are made single words and returned, + * but with the "" or `` still present. For the \ and '' cases, the + * 8th bit is turned on (as in csh) to prevent them from being recogized, + * and stripped off once all processing is done. We also have to deal with + * command, filename, and keyword completion here. + * If string is non-NULL, then use it instead of the fp. Escape and EOF + * have no business being in the string. + */ + +#define newword cw->wl_word = copy(buf); \ + cw->wl_next = alloc(struct wordlist); \ + cw->wl_next->wl_prev = cw; \ + cw = cw->wl_next; \ + cw->wl_next = NULL; \ + bzero(buf, BSIZE_SP); \ + i = 0; + +wordlist * +cp_lexer(char *string) +{ + int c; + int i, j; + wordlist *wlist = NULL, *cw = NULL; + char buf[BSIZE_SP], linebuf[BSIZE_SP], d; + int paren; + + if (cp_inp_cur == NULL) + cp_inp_cur = cp_in; + + if (!string && cp_interactive) { + cp_ccon(TRUE); + prompt(); + } +nloop: i = 0; + j = 0; + paren = 0; + bzero(linebuf, BSIZE_SP); + bzero(buf, BSIZE_SP); + wlist = cw = alloc(struct wordlist); + cw->wl_next = cw->wl_prev = NULL; + for (;;) { + if (string) { + c = *string++; + if (c == '\0') + c = '\n'; + if (c == ESCAPE) + c = '['; + } else + c = input(cp_inp_cur); + +gotchar: + if ((c != EOF) && (c != ESCAPE)) + linebuf[j++] = c; + if (c != EOF) + numeofs = 0; + if (i == BSIZE_SP - 1) { + fprintf(cp_err, "Warning: word too long.\n"); + c = ' '; + } + if (j == BSIZE_SP - 1) { + fprintf(cp_err, "Warning: line too long.\n"); + if (cp_bqflag) + c = EOF; + else + c = '\n'; + } + if (c != EOF) + c = strip(c); /* Don't need to do this really. */ + if ((c == '\\' && DIR_TERM != '\\') || (c == '\026') /* ^V */ ) { + c = quote(string ? *string++ : input(cp_inp_cur)); + linebuf[j++] = strip(c); + } + if ((c == '\n') && cp_bqflag) + c = ' '; + if ((c == EOF) && cp_bqflag) + c = '\n'; + if ((c == cp_hash) && !cp_interactive && (j == 1)) { + if (string) + return (NULL); + while (((c = input(cp_inp_cur)) != '\n') && + (c != EOF)); + goto nloop; + } + + if ((c == '(') || (c == '[')) /* MW. Nedded by parse() */ + paren++; + else if ((c == ')') || (c == ']')) + paren--; + + switch (c) { + case ' ': + case '\t': + if (i > 0) { + newword; + } + break; + + case '\n': + if (i) { + buf[i] = '\0'; + cw->wl_word = copy(buf); + } else if (cw->wl_prev) { + cw->wl_prev->wl_next = NULL; + tfree(cw); + } else { + cw->wl_word = NULL; + } + goto done; + + case '\'': + while (((c = (string ? *string++ : + input(cp_inp_cur))) != '\'') + && (i < BSIZE_SP - 1)) { + if ((c == '\n') || (c == EOF) || (c == ESCAPE)) + goto gotchar; + else { + buf[i++] = quote(c); + linebuf[j++] = c; + } + } + linebuf[j++] = '\''; + break; + + case '"': + case '`': + d = c; + buf[i++] = d; + while (((c = (string ? *string++ : input(cp_inp_cur))) + != d) && (i < BSIZE_SP - 2)) { + if ((c == '\n') || (c == EOF) || (c == ESCAPE)) + goto gotchar; + else if (c == '\\') { + linebuf[j++] = c; + c = (string ? *string++ : + input(cp_inp_cur)); + buf[i++] = quote(c); + linebuf[j++] = c; + } else { + buf[i++] = c; + linebuf[j++] = c; + } + } + buf[i++] = d; + linebuf[j++] = d; + break; + + case '\004': + case EOF: + if (cp_interactive && !cp_nocc && + (string == NULL)) { + if (j == 0) { + if (cp_ignoreeof && (numeofs++ + < 23)) { + fputs( + "Use \"quit\" to quit.\n", + stdout); + } else { + fputs("quit\n", stdout); + cp_doquit(); + } + goto done; + } + cp_ccom(wlist, buf, FALSE); + wl_free(wlist); + (void) fputc('\r', cp_out); + prompt(); + for (j = 0; linebuf[j]; j++) +#ifdef TIOCSTI + (void) ioctl(fileno(cp_out), TIOCSTI, linebuf + j); +#else + fputc(linebuf[j], cp_out); /* But you can't edit */ +#endif + goto nloop; + } else /* EOF during a source */ + { + if (cp_interactive) { + fputs("quit\n", stdout); + cp_doquit(); + goto done; + } else + return (NULL); + } + case ESCAPE: + if (cp_interactive && !cp_nocc) { + fputs("\b\b \b\b\r", cp_out); + prompt(); + for (j = 0; linebuf[j]; j++) +#ifdef TIOCSTI + (void) ioctl(fileno(cp_out), TIOCSTI, linebuf + j); +#else + fputc(linebuf[j], cp_out); /* But you can't edit */ +#endif + cp_ccom(wlist, buf, TRUE); + wl_free(wlist); + goto nloop; + } /* Else fall through */ + case ',': + if (paren < 1 && i > 0) { + newword; + break; + } + default: + /* We have to remember the special case $< + * here + */ + if ((cp_chars[c] & CPC_BRL) && (i > 0)) { + if ((c != '<') || (buf[i - 1] != '$')) { + newword; + } + } + buf[i++] = c; + if (cp_chars[c] & CPC_BRR) { + if ((c != '<') || (i < 2) || + (buf[i - 2] != '$')) { + newword; + } + } + } + } +done: + return (wlist); +} + +static void +prompt(void) +{ + char *s; + + if (cp_interactive == FALSE) + return; + if (cp_promptstring == NULL) + s = "-> "; + else + s = cp_promptstring; + if (cp_altprompt) + s = cp_altprompt; +#ifdef notdef + /* XXXX VMS */ + /* this is for VMS/RMS which otherwise won't output the LF + * part of the newline on the previous line if this line + * doesn't also end in newline, and most prompts don't, so... + * we force an extra line here. + */ + fprintf(cp_out,"\n"); +#endif + while (*s) { + switch (strip(*s)) { + case '!': + fprintf(cp_out, "%d", cp_event); + break; + case '\\': + if (*(s + 1)) + (void) putc(strip(*++s), cp_out); + default: + (void) putc(strip(*s), cp_out); + } + s++; + } + (void) fflush(cp_out); + return; +} + + +/* A special 'getc' so that we can deal with ^D properly. There is no way for + * stdio to know if we have typed a ^D after some other characters, so + * don't use buffering at all + */ +int +inchar(FILE *fp) +{ + + char c; + int i; + + if (cp_interactive && !cp_nocc) { + do { + i = read((int) fileno(fp), &c, 1); + } while (i == -1 && errno == EINTR); + if (i == 0 || c == '\004') + return (EOF); + else if (i == -1) { + perror("read"); + return (EOF); + } else + return ((int) c); + } else + c = getc(fp); + return ((int) c); +} + +int +input(FILE *fp) +{ + + REQUEST request; + RESPONSE response; + + request.option = char_option; + request.fp = fp; + Input(&request, &response); + return(response.reply.ch); + +} + diff --git a/src/parser/lexical.h b/src/parser/lexical.h new file mode 100644 index 000000000..cf08fbee9 --- /dev/null +++ b/src/parser/lexical.h @@ -0,0 +1,15 @@ +/************* + * Header file for lexical.c + * 1999 E. Rouat + ************/ + +#ifndef LEXICAL_H_INCLUDED +#define LEXICAL_H_INCLUDED + + +wordlist * cp_lexer(char *string); +int inchar(FILE *fp); +int input(FILE *fp); + + +#endif diff --git a/src/parser/modify.c b/src/parser/modify.c new file mode 100644 index 000000000..c76bea376 --- /dev/null +++ b/src/parser/modify.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "modify.h" + + +char cp_chars[128]; + +static char *singlec = "<>;&"; + +/* Initialize stuff. */ + +void +cp_init(void) +{ + char *s, *getenv(const char *); + + bzero(cp_chars, 128); + for (s = singlec; *s; s++) + cp_chars[(int) *s] = (CPC_BRR | CPC_BRL); + cp_vset("history", VT_NUM, (char *) &cp_maxhistlength); + + cp_curin = stdin; + cp_curout = stdout; + cp_curerr = stderr; + + cp_ioreset(); + + return; +} + diff --git a/src/parser/modify.h b/src/parser/modify.h new file mode 100644 index 000000000..db3110874 --- /dev/null +++ b/src/parser/modify.h @@ -0,0 +1,13 @@ +/************* + * Header file for modify.c + * 1999 E. Rouat + ************/ + +#ifndef MODIFY_H_INCLUDED +#define MODIFY_H_INCLUDED + + +void cp_init(void); + + +#endif diff --git a/src/parser/numparse.c b/src/parser/numparse.c new file mode 100644 index 000000000..dd48320fa --- /dev/null +++ b/src/parser/numparse.c @@ -0,0 +1,169 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * This routine parses a number. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "ftedefs.h" +#include "numparse.h" + + +static double +pow10( double num) /* Chris Inbody */ +{ + double d = 1.0; + + while (num-- > 0) + d *= 10.0; + return (d); +} + + +bool ft_strictnumparse = FALSE; + +/* Parse a number. This will handle things like 10M, etc... If the number + * must not end before the end of the string, then whole is TRUE. + * If whole is FALSE and there is more left to the number, the argument + * is advanced to the end of the word. Returns NULL + * if no number can be found or if there are trailing characters when + * whole is TRUE. + * If ft_strictnumparse is TRUE, and whole is FALSE, the first of the + * trailing characters must be a '_'. + */ + +double * +ft_numparse(char **s, bool whole) +{ + double mant = 0.0; + int sign = 1, exsign = 1, p; + double expo = 0.0; + static double num; + char *string = *s; + + /* See if the number begins with + or -. */ + if (*string == '+') + string++; + else if (*string == '-') { + string++; + sign = -1; + } + + /* We don't want to recognise "P" as 0P, or .P as 0.0P... */ + if ((!isdigit(*string) && *string != '.') || + ((*string == '.') && !isdigit(string[1]))) + return (NULL); + + /* Now accumulate a number. Note ascii dependencies here... */ + while (isdigit(*string)) + mant = mant * 10.0 + (*string++ - '0'); + + /* Now maybe a decimal point. */ + if (*string == '.') { + string++; + p = 1; + while (isdigit(*string)) + mant += (*string++ - '0') / pow10(p++); + } + + /* Now look for the scale factor or the exponent (can't have both). */ + switch (*string) { + case 'e': + case 'E': + /* Parse another number. */ + string++; + if (*string == '+') { + exsign = 1; + string++; + } else if (*string == '-') { + exsign = -1; + string++; + } + while(isdigit(*string)) + expo = expo * 10.0 + (*string++ - '0'); + if (*string == '.') { + string++; + p = 1; + while (isdigit(*string)) + expo += (*string++ - '0') / pow10(p++); + } + expo *= exsign; + break; + case 't': + case 'T': + expo = 12.0; + string++; + break; + case 'g': + case 'G': + expo = 9.0; + string++; + break; + case 'k': + case 'K': + expo = 3.0; + string++; + break; + case 'u': + case 'U': + expo = -6.0; + string++; + break; + case 'n': + case 'N': + expo = -9.0; + string++; + break; + case 'p': + case 'P': + expo = -12.0; + string++; + break; + case 'f': + case 'F': + expo = -15.0; + string++; + break; + case 'm': + case 'M': + /* Can be either m, mil, or meg. */ + if (string[1] && string[2] && + ((string[1] == 'e') || (string[1] == 'E')) && + ((string[2] == 'g') || (string[2] == 'G'))) { + expo = 6.0; + string += 3; + } else if (string[1] && string[2] && + ((string[1] == 'i') || (string[1] == 'I')) && + ((string[2] == 'l') || (string[2] == 'L'))) { + expo = -6.0; + mant *= 25.4; + string += 3; + } else { + expo = -3.0; + string++; + } + break; + } + + if (whole && *string != '\0') { + return (NULL); + } else if (ft_strictnumparse && *string && isdigit(string[-1])) { + if (*string == '_') + while (isalpha(*string) || (*string == '_')) + string++; + else + return (NULL); + } else { + while (isalpha(*string) || (*string == '_')) + string++; + } + *s = string; + num = sign * mant * pow(10.0, expo); + if (ft_parsedb) + fprintf(cp_err, "numparse: got %e, left = %s\n", num, *s); + return (&num); +} diff --git a/src/parser/numparse.h b/src/parser/numparse.h new file mode 100644 index 000000000..44fd91fbc --- /dev/null +++ b/src/parser/numparse.h @@ -0,0 +1,14 @@ +/************* + * Header file for numparse.c + * 1999 E. Rouat + ************/ + +#ifndef NUMPARSE_H_INCLUDED +#define NUMPARSE_H_INCLUDED + + +double * ft_numparse(char **s, bool whole); + + + +#endif diff --git a/src/parser/output.c b/src/parser/output.c new file mode 100644 index 000000000..46f80f7ac --- /dev/null +++ b/src/parser/output.c @@ -0,0 +1,336 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1986 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines to handle "more"d output. There are some serious system + * dependencies in here, and it isn't clear that versions of this stuff + * can be written for every possible machine... + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "output.h" + +#ifdef HAVE_SGTTY_H +#include +#endif + +static void bufputc(char c); +static int outfn(char c); + + +#define DEF_SCRHEIGHT 24 +#define DEF_SCRWIDTH 80 + +bool out_moremode = TRUE; +bool out_isatty = TRUE; + +static int xsize, ysize; +static int xpos, ypos; +static bool noprint, nopause; + +static char *motion_chars; +static char *clear_chars; +static char *home_chars; +static char *cleol_chars; + + +/* out_printf doesn't handle double arguments correctly, so we + sprintf into this buf and call out_send w/ it */ +char out_pbuf[BSIZE_SP]; + +/* Start output... */ + +void +out_init(void) +{ +#ifdef TIOCGWINSZ + struct winsize ws; +#endif + bool moremode; + + noprint = nopause = FALSE; + + if (cp_getvar("nomoremode", VT_BOOL, (char *) &moremode)) + out_moremode = FALSE; + else + out_moremode = TRUE; + if (!out_moremode || !cp_interactive) + out_isatty = FALSE; + + if (!out_isatty) + return; + + xsize = ysize = 0; + + /* Figure out the screen size. We try, in order, TIOCGSIZE, + * tgetent(), and cp_getvar(height). Default is 24 x 80. + */ + +#ifdef TIOCGWINSZ + if (!xsize || !ysize) { + (void) ioctl(fileno(stdout), TIOCGWINSZ, (char *) &ws); + xsize = ws.ws_col; + ysize = ws.ws_row; + } +#endif + + if (!xsize) + (void) cp_getvar("width", VT_NUM, (char *) &xsize); + if (!ysize) + (void) cp_getvar("height", VT_NUM, (char *) &ysize); + + if (!xsize) + xsize = DEF_SCRWIDTH; + if (!ysize) + ysize = DEF_SCRHEIGHT; + ysize -= 2; /* Fudge room... */ + xpos = ypos = 0; + + return; +} + +/* Putc may not be buffered (sp?), so we do it ourselves. */ + +static char staticbuf[BUFSIZ]; +struct { + int count; + char *ptr; +} ourbuf = { BUFSIZ, staticbuf }; + +/* send buffer out */ +void +outbufputc(void) +{ + + if (ourbuf.count != BUFSIZ) { + fputs(staticbuf, cp_out); + bzero(staticbuf, BUFSIZ-ourbuf.count); + ourbuf.count = BUFSIZ; + ourbuf.ptr = staticbuf; + } + +} + +static void +bufputc(char c) +{ + if (--ourbuf.count >= 0) { + *ourbuf.ptr++ = c; + } else { + /* Flush and reset the buffer */ + outbufputc(); + /* and store the character. */ + ourbuf.count--; + *ourbuf.ptr++ = c; + } +} + +#ifdef NOTDEF +/* This tricky little macro + recursive routine was giving the Ultrix + * global optimizer serious fits, so it was nuked. + * The replacement above is not quite as fast, but somehow I don't think + * that will cause too many problems these days. + */ +#define bufputc(c) ( --ourbuf.count >= 0 ? ((int) \ + (*ourbuf.ptr++ = (unsigned)(c))) : fbufputc((unsigned) (c))) + +static int +fbufputc(c) +unsigned char c; +{ + + ourbuf.count = 0; + outbufputc(); + ourbuf.count = BUFSIZ; + ourbuf.ptr = staticbuf; + bufputc(c); + +} +#endif + +/* prompt for a return */ +void +promptreturn(void) +{ + char buf[16]; +moe: + fprintf(cp_out, + "\n\t-- hit return for more, ? for help -- "); + if (!fgets(buf, 16, cp_in)) { + clearerr(cp_in); + *buf = 'q'; + } + switch (*buf) { + case '\n': + break; + case 'q': + noprint = TRUE; + break; + case 'c': + nopause = TRUE; + break; + case ' ': + break; + case '?': + fprintf(cp_out, +"\nPossible responses:\n\ +\t : Print another screenful\n\ +\tq : Discard the rest of the output\n\ +\tc : Continuously print the rest of the output\n\ +\t? : Print this help message\n"); + goto moe; + default: + fprintf(cp_out, "Character %d is no good\n", *buf); + goto moe; + } + +} + +/* Print a string to the output. If this would cause the screen to scroll, + * print "more". + */ + +void +out_send(char *string) +{ + + if (noprint) + return; + if (!out_isatty || nopause) { + fputs(string, cp_out); + return; + } + while (*string) { + switch (*string) { + case '\n': + xpos = 0; + ypos++; + break; + case '\f': + ypos = ysize; + xpos = 0; + break; + case '\t': + xpos = xpos / 8 + 1; + xpos *= 8; + break; + default: + xpos++; + break; + } + while (xpos >= xsize) { + xpos -= xsize; + ypos++; + } + if (ypos >= ysize) { + outbufputc(); /* out goes buffer */ + promptreturn(); + (void) fflush(cp_out); + ypos = xpos = 0; + } + bufputc(*string); /* we need to buffer these */ + string++; + } + (void) outbufputc(); + return; +} + +/* Printf some stuff using more mode. */ + +#define MAXLEN 4096 + + +void +out_printf(char *fmt, char *s1, char *s2, char *s3, char *s4, char *s5, char *s6, char *s7, char *s8, char *s9, char *s10) +{ + char buf[MAXLEN]; + + sprintf(buf, fmt, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10); + + out_send(buf); + return; +} + +void +term_clear(void) +{ +#ifdef HAVE_TERMCAP + if (*clear_chars) + tputs(clear_chars, 1, outfn); + else + fputs("\n", stdout); +#endif +} + +void +term_home(void) +{ +#ifdef HAVE_TERMCAP + if (*home_chars) + tputs(home_chars, 1, outfn); + else if (*motion_chars) + tputs(tgoto(motion_chars, 1, 1), 1, outfn); + else + fputs("\n", stdout); +#endif +} + +void +term_cleol(void) +{ +#ifdef HAVE_TERMCAP + if (*cleol_chars) + tputs(cleol_chars, 1, outfn); +#endif +} + +static int +outfn(char c) +{ + putc(c, stdout); + return c; +} + +void +tcap_init(void) +{ + char *s; +#ifdef HAVE_TERMCAP + char tbuf[1025]; + static char buf2[100]; + char *charbuf; + + charbuf = buf2; + + if ((s = getenv("TERM"))) { + if (tgetent(tbuf, s) != -1) { + xsize = tgetnum("co"); + ysize = tgetnum("li"); + if ((xsize <= 0) || (ysize <= 0)) + xsize = ysize = 0; + clear_chars = (char *) tgetstr("cl", &charbuf); + motion_chars = (char *) tgetstr("cm", &charbuf); + home_chars = (char *) tgetstr("ho", &charbuf); + cleol_chars = (char *) tgetstr("ce", &charbuf); + } + } +#endif + + if (!xsize) { + if ((s = getenv("COLS"))) + xsize = atoi(s); + if (xsize <= 0) + xsize = 0; + } + + if (!ysize) { + if ((s = getenv("LINES"))) + ysize = atoi(s); + if (ysize <= 0) + ysize = 0; + } +} diff --git a/src/parser/output.h b/src/parser/output.h new file mode 100644 index 000000000..2e709343a --- /dev/null +++ b/src/parser/output.h @@ -0,0 +1,21 @@ +/************* + * Header file for output.c + * 1999 E. Rouat + ************/ + +#ifndef OUTPUT_H_INCLUDED +#define OUTPUT_H_INCLUDED + +void out_init(void); +void outbufputc(void); +void promptreturn(void); +void out_send(char *string); +void out_printf(char *fmt, char *s1, char *s2, char *s3, char *s4, char *s5, char *s6, + char *s7, char *s8, char *s9, char *s10); +void term_clear(void); +void term_home(void); +void term_cleol(void); +void tcap_init(void); + + +#endif diff --git a/src/parser/quote.c b/src/parser/quote.c new file mode 100644 index 000000000..6bf95f88c --- /dev/null +++ b/src/parser/quote.c @@ -0,0 +1,92 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Various things for quoting words. If this is not ascii, quote and + * strip are no-ops, so '' and \ quoting won't work. To fix this, sell + * your IBM machine and buy a vax. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "quote.h" + + +/* Strip all the 8th bits from a string (destructively). */ + +void +cp_wstrip(char *str) +{ + char c, d; + + if (str) + while ((c = *str)) { /* assign and test */ + d = strip(c); + if (c != d) + *str = d; + str++; + } + return; +} + +/* Quote all characters in a word. */ + +void +cp_quoteword(char *str) +{ + if (str) + while (*str) { + *str = quote(*str); + str++; + } + return; +} + +/* Print a word (strip the word first). */ + +void +cp_printword(char *string, FILE *fp) +{ + char *s; + + if (string) + for (s = string; *s; s++) + (void) putc((strip(*s)), fp); + return; +} + +/* (Destructively) strip all the words in a wlist. */ + +void +cp_striplist(wordlist *wlist) +{ + wordlist *wl; + + for (wl = wlist; wl; wl = wl->wl_next) + cp_wstrip(wl->wl_word); + return; +} + +/* Remove the "" from a string. */ + +char * +cp_unquote(char *string) +{ + char *s; + int l; + if (string) { + s = copy(string); + + if (*s == '"') + s++; + + l = strlen(s) - 1; + if (s[l] == '"') + s[l] = '\0'; + return (s); + } else + return 0; +} diff --git a/src/parser/quote.h b/src/parser/quote.h new file mode 100644 index 000000000..5a9b659cc --- /dev/null +++ b/src/parser/quote.h @@ -0,0 +1,17 @@ +/************* + * Header file for quote.c + * 1999 E. Rouat + ************/ + +#ifndef QUOTE_H_INCLUDED +#define QUOTE_H_INCLUDED + + +void cp_wstrip(char *str); +void cp_quoteword(char *str); +void cp_printword(char *string, FILE *fp); +void cp_striplist(wordlist *wlist); +char * cp_unquote(char *string); + + +#endif diff --git a/src/parser/std.c b/src/parser/std.c new file mode 100644 index 000000000..217084c12 --- /dev/null +++ b/src/parser/std.c @@ -0,0 +1,22 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Standard utility routines. + * Most moved to MISC/ + */ + +#include +#include "ngspice.h" +#include "cpstd.h" + + +/* This might not be around. If not then forget about sorting. */ + +#ifndef HAVE_QSORT +#ifndef qsort +qsort() {} +#endif +#endif diff --git a/src/parser/unixcom.c b/src/parser/unixcom.c new file mode 100644 index 000000000..270d9bb5b --- /dev/null +++ b/src/parser/unixcom.c @@ -0,0 +1,306 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Routines to do execution of unix commands. + */ + +#include +#include "ngspice.h" +#include "cpdefs.h" +#include "unixcom.h" + +#ifdef HAVE_VFORK_H + +/* The only reason this exists is efficiency */ + +# ifdef HAVE_SYS_DIR_H +# include +# include +# else + +# ifdef HAVE_DIRENT_H +# include +# include +# ifndef direct +# define direct dirent +# endif +# endif +# endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include + + +static bool tryexec(char *name, char *argv[]); +static int hash(register char *str); + + +struct hashent { + char *h_name; + char *h_path; + struct hashent *h_next; +} ; + +#define HASHSIZE 256 + +static struct hashent *hashtab[HASHSIZE]; +static char *dirbuffer; +static int dirlength, dirpos; + +/* Create the hash table for the given search path. pathlist is a : seperated + * list of directories. If docc is TRUE, then all the commands found are + * added to the command completion lists. + */ + +void +cp_rehash(char *pathlist, bool docc) +{ + register int i; + struct hashent *hh, *ht; + char buf[BSIZE_SP], pbuf[BSIZE_SP], *curpath; + DIR *pdir; + struct direct *entry; + + /* First clear out the old hash table. */ + for (i = 0; i < HASHSIZE; i++) { + for (hh = hashtab[i]; hh; hh = ht) { + ht = hh->h_next; + /* Don't free any of the other stuff -- it is too + * strange. + */ + tfree(hh); + } + hashtab[i] = NULL; + } + + while (pathlist && *pathlist) { + /* Copy one path to buf. We have to make sure that the path + * is a full path name. + */ + if (*pathlist == '/') + i = 0; + else { +#ifdef HAVE_GETWD + (void) getwd(buf); +#else +# ifdef HAVE_GETCWD + (void) getcwd(buf, sizeof(buf)); +# else + *buf = 0; +# endif +#endif + i = strlen(buf); + } + while (*pathlist && (*pathlist != ':')) + buf[i++] = *pathlist++; + while (*pathlist == ':') + pathlist++; + buf[i] = '\0'; + + curpath = copy(buf); + if (!(pdir = opendir(curpath))) + continue; + while (entry = readdir(pdir)) { + (void) strcpy(pbuf, curpath); + (void) strcat(pbuf, "/"); + (void) strcat(pbuf, entry->d_name); + /* Now we could make sure that it is really an + * executable, but that is too slow + * (as if "we" really cared). + */ + hh = alloc(struct hashent); + hh->h_name = copy(entry->d_name); + hh->h_path = curpath; + i = hash(entry->d_name); + /* Make sure this goes at the end, with + * possible duplications of names. + */ + if (hashtab[i]) { + ht = hashtab[i]; + while (ht->h_next) + ht = ht->h_next; + ht->h_next = hh; + } else + hashtab[i] = hh; + if (docc) { + /* Add to completion hash table. */ + cp_addcomm(entry->d_name, (long) 0, (long) 0, (long) 0, + (long) 0); + } + } + closedir(pdir); + } + return; +} + +/* The return value is FALSE if no command was found, and TRUE if it was. */ + +bool +cp_unixcom(wordlist *wl) +{ + int i; + register struct hashent *hh; + register char *name; + char **argv; + char buf[BSIZE_SP]; + + if (!wl) + return (FALSE); + name = wl->wl_word; + argv = wl_mkvec(wl); + if (cp_debug) { + printf("name: %s, argv: ", name); + wl_print(wl, stdout); + printf(".\n"); + } + if (index(name, '/')) + return (tryexec(name, argv)); + i = hash(name); + for (hh = hashtab[i]; hh; hh = hh->h_next) { + if (eq(name, hh->h_name)) { + (void) sprintf(buf, "%s/%s", hh->h_path, hh->h_name); + if (tryexec(buf, argv)) + return (TRUE); + } + } + return (FALSE); +} + +static bool +tryexec(char *name, char *argv[]) +{ +# ifdef HAVE_SYS_WAIT_H + int status; +# else + union wait status; +# endif + int pid, j; + RETSIGTYPE (*svint)( ), (*svquit)( ), (*svtstp)( ); + + pid = vfork( ); + if (pid == 0) { + fixdescriptors(); + (void) execv(name, argv); + (void) _exit(120); /* A random value. */ + /* NOTREACHED */ + } else { + svint = signal(SIGINT, SIG_DFL); + svquit = signal(SIGQUIT, SIG_DFL); + svtstp = signal(SIGTSTP, SIG_DFL); + do { + j = wait(&status); + } while (j != pid); + (void) signal(SIGINT, (SIGNAL_FUNCTION) svint); + (void) signal(SIGQUIT, (SIGNAL_FUNCTION) svquit); + (void) signal(SIGTSTP, (SIGNAL_FUNCTION) svtstp); + } + if (WTERMSIG(status) == 0 && WEXITSTATUS(status) == 120) + /*if ((status.w_termsig == 0) && (status.w_retcode == 120)) */ + return (FALSE); + else + return (TRUE); +} + +static int +hash(register char *str) +{ + register int i = 0; + + while (*str) + i += *str++; + return (i % HASHSIZE); +} + +/* Debugging. */ + +void +cp_hstat(void) +{ + struct hashent *hh; + int i; + + for (i = 0; i < HASHSIZE; i++) + for (hh = hashtab[i]; hh; hh = hh->h_next) + fprintf(cp_err, "i = %d, name = %s, path = %s\n", + i, hh->h_name, hh->h_path); + return; +} + +#ifdef notdef +/*** The person who wrote this should be strung up ***/ +/* Some strange stuff... Don't ever free the dir buffer, because we keep + * pointers into it in the command hash table. + */ + +static bool +myopendir(char *path) +{ + struct stat stbuf; + int i; + + if (!path) + return (0); + if (stat(path, &stbuf)) + return (FALSE); + if ((i = open(path, O_RDONLY)) == -1) + return (0); + dirbuffer = tmalloc(stbuf.st_size); + if (read(i, dirbuffer, stbuf.st_size) != stbuf.st_size) { + fprintf(cp_err, "Error: bad read on directory %s\n", path); + return (0); + } + dirlength = stbuf.st_size; + dirpos = 0; + return (1); +} + +static char * +myreaddir(void) +{ + struct direct *dp; + + /* Advance us to the next valid directory entry. */ + for (;;) { + dp = (struct direct *) &dirbuffer[dirpos]; + if (dirpos >= dirlength) + return (NULL); + while (dp->d_ino == 0) { + dirpos += dp->d_reclen; + goto x; /* Ack... */ + } + break; +x: ; + } + dirpos += dp->d_reclen; + return (dp->d_name); +} +# endif + +#else + +void +cp_rehash(char *pathlist, bool docc) +{ } + +bool +cp_unixcom(wordlist *wl) +{ + char *s = wl_flatten(wl); + + if (system(s)) + return (FALSE); + else + return (TRUE); + +} + +#endif + diff --git a/src/parser/unixcom.h b/src/parser/unixcom.h new file mode 100644 index 000000000..64b15c02d --- /dev/null +++ b/src/parser/unixcom.h @@ -0,0 +1,16 @@ +/************* + * Header file for unixcom.c + * 1999 E. Rouat + ************/ + +#ifndef UNIXCOM_H_INCLUDED +#define UNIXCOM_H_INCLUDED + + +void cp_rehash(char *pathlist, bool docc); +bool cp_unixcom(wordlist *wl); +void cp_hstat(void); + + + +#endif diff --git a/src/parser/var2.c b/src/parser/var2.c new file mode 100644 index 000000000..988338ed9 --- /dev/null +++ b/src/parser/var2.c @@ -0,0 +1,491 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Do variable substitution. + */ + +#include "ngspice.h" +#include "cpdefs.h" +#include "var2.h" + +/* Print the values of currently defined variables. */ + + +static int vcmp(struct xxx *v1, struct xxx *v2); + +extern struct variable *variables; + +/* A variable substitution is + * indicated by a $, and the variable name is the following string of + * non-special characters. All variable values are inserted as a single + * word, except for lists, which are a list of words. + * A routine cp_usrset must be supplied by the host program to deal + * with variables that aren't used by cshpar -- it should be + * cp_usrset(var, isset), where var is a variable *, and isset is + * TRUE if the variable is being set, FALSE if unset. + * Also required is a routine cp_enqvar(name) which returns a struct + * variable *, which allows the host program to provide values for + * non-cshpar variables. + */ + +char cp_dol = '$'; + +/* Non-alphanumeric characters that may appear in variable names. < is very + * special... + */ + +#define VALIDCHARS "$-_<#?@.()[]&" + +wordlist * +cp_variablesubst(wordlist *wlist) +{ + wordlist *wl, *nwl; + char *s, *t, buf[BSIZE_SP], wbuf[BSIZE_SP], tbuf[BSIZE_SP]; + /* MW. tbuf holds curret word after wl_splice() calls free() on it */ + int i; + + for (wl = wlist; wl; wl = wl->wl_next) { + t = wl->wl_word; + i = 0; + while ((s =strchr(t, cp_dol))) { + while (t < s) + wbuf[i++] = *t++; + wbuf[i] = '\0'; + (void) strcpy(buf, ++s); + s = buf; + t++; + while (*s && (isalphanum(*s) || + strchr(VALIDCHARS, *s))) { + /* Get s and t past the end of the var name. */ + t++; + s++; + } + *s = '\0'; + nwl = vareval(buf); + if (i) { + (void) strcpy(buf, wbuf); + if (nwl) { + (void) strcat(buf, nwl->wl_word); + tfree(nwl->wl_word); + } else { + nwl = alloc(struct wordlist); + nwl->wl_next = nwl->wl_prev = NULL; + } + nwl->wl_word = copy(buf); + } + + (void) strcpy(tbuf, t); /* MW. Save t*/ + if (!(wl = wl_splice(wl, nwl))) + return (NULL); + /* This is bad... */ + for (wlist = wl; wlist->wl_prev; wlist = wlist->wl_prev) + ; + (void) strcpy(buf, wl->wl_word); + i = strlen(buf); + (void) strcat(buf, tbuf); /* MW. tbuf is used here only */ + + tfree(wl->wl_word); + wl->wl_word = copy(buf); + t = &wl->wl_word[i]; + s = wl->wl_word; + for (i = 0; s < t; s++) + wbuf[i++] = *s; + } + } + return (wlist); +} + +/* Evaluate a variable. */ + +wordlist * +vareval(char *string) +{ + struct variable *v; + wordlist *wl; + char buf[BSIZE_SP], *s; + char *oldstring = copy(string); + char *range = NULL; + int i, up, low; + + cp_wstrip(string); + if ((s =strchr(string, '['))) { + *s = '\0'; + range = s + 1; + } + + switch (*string) { + + case '$': + wl = alloc(struct wordlist); + wl->wl_next = wl->wl_prev = NULL; + + + (void) sprintf(buf, "%d", getpid()); + + wl->wl_word = copy(buf); + return (wl); + + case '<': + (void) fflush(cp_out); + if (!fgets(buf, BSIZE_SP, cp_in)) { + clearerr(cp_in); + (void) strcpy(buf, "EOF"); + } + for (s = buf; *s && (*s != '\n'); s++) + ; + *s = '\0'; + wl = cp_lexer(buf); + /* This is a hack. */ + if (!wl->wl_word) + wl->wl_word = copy(""); + return (wl); + + case '?': + wl = alloc(struct wordlist); + wl->wl_next = wl->wl_prev = NULL; + string++; + for (v = variables; v; v = v->va_next) + if (eq(v->va_name, string)) + break; + if (!v) + v = cp_enqvar(string); + wl->wl_word = copy(v ? "1" : "0"); + return (wl); + + case '#': + wl = alloc(struct wordlist); + wl->wl_next = wl->wl_prev = NULL; + string++; + for (v = variables; v; v = v->va_next) + if (eq(v->va_name, string)) + break; + if (!v) + v = cp_enqvar(string); + if (!v) { + fprintf(cp_err, "Error: %s: no such variable.\n", + string); + return (NULL); + } + if (v->va_type == VT_LIST) + for (v = v->va_vlist, i = 0; v; v = v->va_next) + i++; + else + i = (v->va_type != VT_BOOL); + (void) sprintf(buf, "%d", i); + wl->wl_word = copy(buf); + return (wl); + + case '\0': + wl = alloc(struct wordlist); + wl->wl_next = wl->wl_prev = NULL; + wl->wl_word = copy("$"); + return (wl); + } + + /* The notation var[stuff] has two meanings... If this is a real + * variable, then the [] denotes range, but if this is a strange + * (e.g, device parameter) variable, it could be anything... + */ + for (v = variables; v; v = v->va_next) + if (eq(v->va_name, string)) + break; + if (!v && isdigit(*string)) { + for (v = variables; v; v = v->va_next) + if (eq(v->va_name, "argv")) + break; + range = string; + } + if (!v) { + range = NULL; + string = oldstring; + v = cp_enqvar(string); + } + if (!v && (s = getenv(string))) { + wl = alloc(struct wordlist); + wl->wl_next = wl->wl_prev = NULL; + wl->wl_word = copy(s); + return (wl); + } + if (!v) { + fprintf(cp_err, "Error: %s: no such variable.\n", string); + return (NULL); + } + wl = cp_varwl(v); + + /* Now parse and deal with 'range' ... */ + if (range) { + for (low = 0; isdigit(*range); range++) + low = low * 10 + *range - '0'; + if ((*range == '-') && isdigit(range[1])) + for (up = 0, range++; isdigit(*range); range++) + up = up * 10 + *range - '0'; + else if (*range == '-') + up = wl_length(wl); + else + up = low; + up--, low--; + wl = wl_range(wl, low, up); + } + + return (wl); +} + + + +void +cp_vprint(void) +{ + struct variable *v; + struct variable *uv1, *uv2; + wordlist *wl; + int i, j; + char *s; + struct xxx *vars; + + cp_usrvars(&uv1, &uv2); + + for (v = uv1, i = 0; v; v = v->va_next) + i++; + for (v = uv2; v; v = v->va_next) + i++; + for (v = variables; v; v = v->va_next) + i++; + + vars = (struct xxx *) tmalloc(sizeof (struct xxx) * i); + + out_init(); + for (v = variables, i = 0; v; v = v->va_next, i++) { + vars[i].x_v = v; + vars[i].x_char = ' '; + } + for (v = uv1; v; v = v->va_next, i++) { + vars[i].x_v = v; + vars[i].x_char = '*'; + } + for (v = uv2; v; v = v->va_next, i++) { + vars[i].x_v = v; + vars[i].x_char = '+'; + } + + qsort((char *) vars, i, sizeof (struct xxx), vcmp); + + for (j = 0; j < i; j++) { + if (j && eq(vars[j].x_v->va_name, vars[j - 1].x_v->va_name)) + continue; + v = vars[j].x_v; + if (v->va_type == VT_BOOL) { +/* out_printf("%c %s\n", vars[j].x_char, v->va_name); */ + sprintf(out_pbuf, "%c %s\n", vars[j].x_char, v->va_name); + out_send(out_pbuf); + } else { + out_printf("%c %s\t", vars[j].x_char, v->va_name); + wl = vareval(v->va_name); + s = wl_flatten(wl); + if (v->va_type == VT_LIST) { + out_printf("( %s )\n", s); + } else + out_printf("%s\n", s); + } + } + + tfree(vars); + return; +} + +static int +vcmp(struct xxx *v1, struct xxx *v2) +{ + int i; + + if ((i = strcmp(v1->x_v->va_name, v2->x_v->va_name))) + return (i); + else + return (v1->x_char - v2->x_char); +} + +/* The set command. Syntax is + * set [opt ...] [opt = val ...]. Val may be a string, an int, a float, + * or a list of the form (elt1 elt2 ...). + */ + + +void +com_set(wordlist *wl) +{ + struct variable *vars; + char *s; + + if (wl == NULL) { + cp_vprint(); + return; + } + vars = cp_setparse(wl); + + /* This is sort of a hassle... */ + while (vars) { + switch (vars->va_type) { + case VT_BOOL: + s = (char *) &vars->va_bool; + break; + case VT_NUM: + s = (char *) &vars->va_num; + break; + case VT_REAL: + s = (char *) &vars->va_real; + break; + case VT_STRING: + s = vars->va_string; + break; + case VT_LIST: + s = (char *) vars->va_vlist; + break; + default: + s = (char *) NULL; + } + cp_vset(vars->va_name, vars->va_type, s); + vars = vars->va_next; + } + return; +} + +void +com_unset(wordlist *wl) +{ + register char *name; + struct variable *var, *nv; + + if (eq(wl->wl_word, "*")) { + for (var = variables; var; var = nv) { + nv = var->va_next; + cp_remvar(var->va_name); + } + wl = wl->wl_next; + } + while (wl != NULL) { + name = wl->wl_word; + cp_remvar(name); + wl = wl->wl_next; + } + return; +} + +/* Shift a list variable, by default argv, one to the left (or more if a + * second argument is given. + */ + +void +com_shift(wordlist *wl) +{ + struct variable *v, *vv; + char *n = "argv"; + int num = 1; + + if (wl) { + n = wl->wl_word; + wl = wl->wl_next; + } + if (wl) + num = scannum(wl->wl_word); + + for (v = variables; v; v = v->va_next) + if (eq(v->va_name, n)) + break; + if (!v) { + fprintf(cp_err, "Error: %s: no such variable\n", n); + return; + } + if (v->va_type != VT_LIST) { + fprintf(cp_err, "Error: %s not of type list\n", n); + return; + } + for (vv = v->va_vlist; vv && (num > 0); num--) + vv = vv->va_next; + if (num) { + fprintf(cp_err, "Error: variable %s not long enough\n", n); + return; + } + + v->va_vlist = vv; + return; +} + +/* Determine the value of a variable. Fail if the variable is unset, + * and if the type doesn't match, try and make it work... + */ + +bool +cp_getvar(char *name, int type, char *retval) +{ + struct variable *v; + + for (v = variables; v; v = v->va_next) + if (eq(name, v->va_name)) + break; + if (v == NULL) { + if (type == VT_BOOL) + * (bool *) retval = FALSE; + return (FALSE); + } + if (v->va_type == type) { + switch (type) { + case VT_BOOL: + * (bool *) retval = TRUE; + break; + case VT_NUM: { + int *i; + i = (int *) retval; + *i = v->va_num; + break; + } + case VT_REAL: { + double *d; + d = (double *) retval; + *d = v->va_real; + break; + } + case VT_STRING: { /* Gotta be careful to have room. */ + char *s; + s = cp_unquote(v->va_string); + cp_wstrip(s); + (void) strcpy(retval, s); + break; + } + case VT_LIST: { /* Funny case... */ + struct variable **tv; + tv = (struct variable **) retval; + *tv = v->va_vlist; + break; + } + default: + fprintf(cp_err, + "cp_getvar: Internal Error: bad var type %d.\n", + type); + break; + } + return (TRUE); + } else { + /* Try to coerce it.. */ + if ((type == VT_NUM) && (v->va_type == VT_REAL)) { + int *i; + i = (int *) retval; + *i = (int) v->va_real; + return (TRUE); + } else if ((type == VT_REAL) && (v->va_type == VT_NUM)) { + double *d; + d = (double *) retval; + *d = (double) v->va_num; + return (TRUE); + } else if ((type == VT_STRING) && (v->va_type == VT_NUM)) { + (void) sprintf(retval, "%d", v->va_num); + return (TRUE); + } else if ((type == VT_STRING) && (v->va_type == VT_REAL)) { + (void) sprintf(retval, "%f", v->va_real); + return (TRUE); + } + return (FALSE); + } +} + diff --git a/src/parser/var2.h b/src/parser/var2.h new file mode 100644 index 000000000..a553639ce --- /dev/null +++ b/src/parser/var2.h @@ -0,0 +1,26 @@ +/************* + * Header file for var2.c + * 1999 E. Rouat + ************/ + +#ifndef VAR2_H_INCLUDED +#define VAR2_H_INCLUDED + + +struct xxx { + struct variable *x_v; + char x_char; +} ; + +wordlist * cp_variablesubst(wordlist *wlist); +wordlist * vareval(char *string); +void cp_vprint(void); +void com_set(wordlist *wl); +void com_unset(wordlist *wl); +void com_shift(wordlist *wl); +bool cp_getvar(char *name, int type, char *retval); + + + + +#endif diff --git a/src/parser/variable.c b/src/parser/variable.c new file mode 100644 index 000000000..f1d3bffa4 --- /dev/null +++ b/src/parser/variable.c @@ -0,0 +1,429 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +#include "ngspice.h" +#include "cpdefs.h" +#include "fteext.h" +#include "ftedefs.h" +#include "variable.h" + + +bool cp_noglob = TRUE; +bool cp_nonomatch = FALSE; +bool cp_noclobber = FALSE; +bool cp_ignoreeof = FALSE; + +struct variable *variables = NULL; + +wordlist * +cp_varwl(struct variable *var) +{ + wordlist *wl = NULL, *w, *wx = NULL; + char buf[BSIZE_SP]; + struct variable *vt; + + switch(var->va_type) { + case VT_BOOL: + /* Can't ever be FALSE. */ + (void) sprintf(buf, "%s", var->va_bool ? "TRUE" : + "FALSE"); + break; + case VT_NUM: + (void) sprintf(buf, "%d", var->va_num); + break; + case VT_REAL: + /* This is a case where printnum isn't too good... */ + (void) sprintf(buf, "%G", var->va_real); + break; + case VT_STRING: + (void) strcpy(buf, cp_unquote(var->va_string)); + break; + case VT_LIST: /* The tricky case. */ + for (vt = var->va_vlist; vt; vt = vt->va_next) { + w = cp_varwl(vt); + if (wl == NULL) + wl = wx = w; + else { + wx->wl_next = w; + w->wl_prev = wx; + wx = w; + } + } + return (wl); + default: + fprintf(cp_err, + "cp_varwl: Internal Error: bad variable type %d\n", + var->va_type); + return (NULL); + } + wl = alloc(struct wordlist); + wl->wl_next = wl->wl_prev = NULL; + wl->wl_word = copy(buf); + return (wl); +} + +/* Set a variable. */ + +void +cp_vset(char *varname, char type, char *value) +{ + struct variable *v, *u, *w; + int i; + bool alreadythere = FALSE; + +/* for (v = variables; v; v = v->va_next) ; printf("ok while setting %s\n", + varname);*/ + varname = cp_unquote(varname); + w = NULL; + for (v = variables; v; v = v->va_next) { + if (eq(varname, v->va_name)) { + alreadythere = TRUE; + break; + } + w = v; + } + if (!v) { + v = alloc(struct variable); + v->va_name = copy(varname); + v->va_next = NULL; + } + switch (type) { + case VT_BOOL: + if (* ((bool *) value) == FALSE) { + cp_remvar(varname); + return; + } else + v->va_bool = TRUE; + break; + + case VT_NUM: + v->va_num = * (int *) value; + break; + + case VT_REAL: + v->va_real = * (double *) value; + break; + + case VT_STRING: + v->va_string = copy(value); + break; + + case VT_LIST: + v->va_vlist = (struct variable *) value; + break; + + default: + fprintf(cp_err, + "cp_vset: Internal Error: bad variable type %d.\n", + type); + return; + } + v->va_type = type; + + /* Now, see if there is anything interesting going on. We recognise + * these special variables: noglob, nonomatch, history, echo, + * noclobber, prompt, and verbose. cp_remvar looks for these variables + * too. The host program will get any others. + */ + + if (eq(varname, "noglob")) + cp_noglob = TRUE; + else if (eq(varname, "nonomatch")) + cp_nonomatch = TRUE; + else if (eq(varname, "history") && (type == VT_NUM)) + cp_maxhistlength = v->va_num; + else if (eq(varname, "history") && (type == VT_REAL)) + cp_maxhistlength = v->va_real; + else if (eq(varname, "noclobber")) + cp_noclobber = TRUE; + else if (eq(varname, "prompt") && (type == VT_STRING)) + cp_promptstring = copy(v->va_string); + else if (eq(varname, "ignoreeof")) + cp_ignoreeof = TRUE; + else if (eq(varname, "cpdebug")) { + cp_debug = TRUE; +#ifndef CPDEBUG + fprintf(cp_err, + "Warning: program not compiled with cshpar debug messages\n"); +#endif + } + + switch (i = cp_usrset(v, TRUE)) { + + case US_OK: + /* Normal case. */ + if (!alreadythere) { + v->va_next = variables; + variables = v; + } + break; + + case US_DONTRECORD: + /* Do nothing... */ + if (alreadythere) { + fprintf(cp_err, + "cp_vset: Internal Error: %s already there, but 'dont record'\n", + v->va_name); + } + break; + + case US_READONLY: + fprintf(cp_err, "Error: %s is a read-only variable.\n", + v->va_name); + if (alreadythere) + fprintf(cp_err, + "cp_vset: Internal Error: it was already there too!!\n"); + break; + + case US_SIMVAR: + if (alreadythere) { + /* somehow it got into the front-end list of variables */ + if (w) { + w->va_next = v->va_next; + } else { + variables = v->va_next; + } + } + alreadythere = FALSE; + if (ft_curckt) { + for (u = ft_curckt->ci_vars; u; u = u->va_next) + if (eq(varname, u->va_name)) { + alreadythere = TRUE; + break; + } + if (!alreadythere) { + v->va_next = ft_curckt->ci_vars; + ft_curckt->ci_vars = v; + } else { + w = u->va_next; + bcopy(v, u, sizeof(*u)); + u->va_next = w; + } + } + break; + + case US_NOSIMVAR: + /* What do you do? */ + tfree(v); + break; + + default: + fprintf(cp_err, "cp_vset: Internal Error: bad US val %d\n", i); + break; + } + + return; +} + +struct variable * +cp_setparse(wordlist *wl) +{ + char *name, *val, *s, *ss; + double *td; + struct variable *listv = NULL, *vv, *lv = NULL; + struct variable *vars = NULL; + int balance; + + while (wl) { + name = cp_unquote(wl->wl_word); + wl = wl->wl_next; + if (((wl == NULL) || (*wl->wl_word != '=')) && + strchr(name, '=') == NULL) { + vv = alloc(struct variable); + vv->va_name = copy(name); + vv->va_type = VT_BOOL; + vv->va_bool = TRUE; + vv->va_next = vars; + vars = vv; + continue; + } + if (wl && eq(wl->wl_word, "=")) { + wl = wl->wl_next; + if (wl == NULL) { + fprintf(cp_err, "Error: bad set form.\n"); + return (NULL); + } + val = wl->wl_word; + wl = wl->wl_next; + } else if (wl && (*wl->wl_word == '=')) { + val = wl->wl_word + 1; + wl = wl->wl_next; + } else if ((s =strchr(name, '='))) { + val = s + 1; + *s = '\0'; + if (*val == '\0') { + if (!wl) { + fprintf(cp_err, + "Error: %s equals what?.\n", + name); + return (NULL); + } else { + val = wl->wl_word; + wl = wl->wl_next; + } + } + } else { + fprintf(cp_err, "Error: bad set form.\n"); + return (NULL); + } + val = cp_unquote(val); + if (eq(val, "(")) { /* ) */ + /* The beginning of a list... We have to walk down + * the list until we find a close paren... If there + * are nested ()'s, treat them as tokens... + */ + balance = 1; + while (wl && wl->wl_word) { + if (eq(wl->wl_word, "(")) { /* ) ( */ + balance++; + } else if (eq(wl->wl_word, ")")) { + if (!--balance) + break; + } + vv = alloc(struct variable); + vv->va_next = NULL; + ss = cp_unquote(wl->wl_word); + td = ft_numparse(&ss, FALSE); + if (td) { + vv->va_type = VT_REAL; + vv->va_real = *td; + } else { + vv->va_type = VT_STRING; + vv->va_string = copy(ss); + } + if (listv) { + lv->va_next = vv; + lv = vv; + } else + listv = lv = vv; + wl = wl->wl_next; + } + if (balance && !wl) { + fprintf(cp_err, "Error: bad set form.\n"); + return (NULL); + } + + vv = alloc(struct variable); + vv->va_name = copy(name); + vv->va_type = VT_LIST; + vv->va_vlist = listv; + vv->va_next = vars; + vars = vv; + + wl = wl->wl_next; + continue; + } + + ss = cp_unquote(val); + td = ft_numparse(&ss, FALSE); + vv = alloc(struct variable); + vv->va_name = copy(name); + vv->va_next = vars; + vars = vv; + if (td) { + /*** We should try to get VT_NUM's... */ + vv->va_type = VT_REAL; + vv->va_real = *td; + } else { + vv->va_type = VT_STRING; + vv->va_string = copy(val); + } + } + return (vars); +} + +void +cp_remvar(char *varname) +{ + struct variable *v, *u, *lv = NULL; + bool found = TRUE; + int i; + + for (v = variables; v; v = v->va_next) { + if (eq(v->va_name, varname)) + break; + lv = v; + } + if (!v) { + /* Gotta make up a var struct for cp_usrset()... */ + v = alloc(struct variable); + ZERO(v, struct variable); + v->va_name = varname; + v->va_type = VT_NUM; + v->va_bool = 0; + found = FALSE; + } + + /* Note that 'unset history' doesn't do anything here... Causes + * trouble... + */ + if (eq(varname, "noglob")) + cp_noglob = FALSE; + else if (eq(varname, "nonomatch")) + cp_nonomatch = FALSE; + else if (eq(varname, "noclobber")) + cp_noclobber = FALSE; + else if (eq(varname, "prompt")) + cp_promptstring = ""; + else if (eq(varname, "cpdebug")) + cp_debug = FALSE; + else if (eq(varname, "ignoreeof")) + cp_ignoreeof = FALSE; + + switch (i = cp_usrset(v, FALSE)) { + + case US_OK: + /* Normal case. */ + if (found) { + if (lv) + lv->va_next = v->va_next; + else + variables = v->va_next; + } + break; + + case US_DONTRECORD: + /* Do nothing... */ + if (found) + fprintf(cp_err, + "cp_remvar: Internal Error: var %d\n", *varname); + break; + + case US_READONLY: + /* Badness... */ + fprintf(cp_err, "Error: %s is read-only.\n", + v->va_name); + if (found) + fprintf(cp_err, + "cp_remvar: Internal Error: var %d\n", *varname); + break; + + case US_SIMVAR: + lv = NULL; + if (ft_curckt) { + for (u = ft_curckt->ci_vars; u; u = u->va_next) { + if (eq(varname, u->va_name)) { + break; + } + lv = u; + } + if (u) { + if (lv) + lv->va_next = u->va_next; + else + ft_curckt->ci_vars = u->va_next; + tfree(u); + } + } + break; + + default: + fprintf(cp_err, "cp_remvar: Internal Error: US val %d\n", i); + break; + } + + tfree(v); + return; +} diff --git a/src/parser/variable.h b/src/parser/variable.h new file mode 100644 index 000000000..2b012ec3d --- /dev/null +++ b/src/parser/variable.h @@ -0,0 +1,17 @@ +/************* + * Header file for variable.c + * 1999 E. Rouat + ************/ + +#ifndef VARIABLE_H_INCLUDED +#define VARIABLE_H_INCLUDED + + +wordlist * cp_varwl(struct variable *var); +void cp_vset(char *varname, char type, char *value); +struct variable * cp_setparse(wordlist *wl); +void cp_remvar(char *varname); + + + +#endif diff --git a/src/parser/wlist.c b/src/parser/wlist.c new file mode 100644 index 000000000..89528ca64 --- /dev/null +++ b/src/parser/wlist.c @@ -0,0 +1,283 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * + * Wordlist manipulation stuff. + */ + +#include "ngspice.h" +#include "cpstd.h" +#include "wlist.h" + + +static int wlcomp(char **s, char **t); + + +/* Determine the length of a word list. */ + +int +wl_length(wordlist *wlist) +{ + register int i = 0; + register wordlist *wl; + + for (wl = wlist; wl; wl = wl->wl_next) + i++; + return (i); +} + +/* Free the storage used by a word list. */ + +void +wl_free(wordlist *wlist) +{ + wordlist *wl, *nw; + + for (wl = wlist; wl; wl = nw) { + nw = wl->wl_next; + tfree(wl->wl_word); + tfree(wl); + } + return; +} + +/* Copy a wordlist and the words. */ + +wordlist * +wl_copy(wordlist *wlist) +{ + register wordlist *wl, *nwl = NULL, *w = NULL; + + for (wl = wlist; wl; wl = wl->wl_next) { + if (nwl == NULL) { + nwl = w = alloc(struct wordlist); + w->wl_prev = NULL; + w->wl_next = NULL; + } else { + w->wl_next = alloc(struct wordlist); + w->wl_next->wl_prev = w; + w = w->wl_next; + w->wl_next = NULL; + } + w->wl_word = copy(wl->wl_word); + } + return (nwl); +} + +/* Substitute a wordlist for one element of a wordlist, and return a pointer + * to the last element of the inserted list. + */ + +wordlist * +wl_splice(wordlist *elt, wordlist *list) +{ + + if (list) + list->wl_prev = elt->wl_prev; + if (elt->wl_prev) + elt->wl_prev->wl_next = list; + if (list) { + while (list->wl_next) + list = list->wl_next; + list->wl_next = elt->wl_next; + } + if (elt->wl_next) + elt->wl_next->wl_prev = list; + tfree(elt->wl_word); + tfree(elt); + return (list); +} + +/* Print a word list. (No \n at the end...) */ + +void +wl_print(wordlist *wlist, FILE *fp) +{ + wordlist *wl; + + for (wl = wlist; wl; wl = wl->wl_next) { + cp_printword(wl->wl_word, fp); + if (wl->wl_next) + (void) putc(' ', fp); + } + return; +} + +/* Turn an array of char *'s into a wordlist. */ + +wordlist * +wl_build(char **v) +{ + wordlist *wlist, *wl = NULL, *cwl; + + while (*v) { + cwl = alloc(struct wordlist); + cwl->wl_prev = wl; + if (wl) + wl->wl_next = cwl; + else { + wlist = cwl; + cwl->wl_next = NULL; + } + cwl->wl_word = copy(*v); + wl = cwl; + v++; + } + return (wlist); +} + +char ** +wl_mkvec(wordlist *wl) +{ + int len, i; + char **v; + + len = wl_length(wl); + v = (char **) tmalloc((len + 1) * sizeof (char **)); + for (i = 0; i < len; i++) { + v[i] = copy(wl->wl_word); + wl = wl->wl_next; + } + v[i] = NULL; + return (v); +} + +/* Nconc two wordlists together. */ + +wordlist * +wl_append(wordlist *wlist, wordlist *nwl) +{ + wordlist *wl; + if (wlist == NULL) + return (nwl); + if (nwl == NULL) + return (wlist); + for (wl = wlist; wl->wl_next; wl = wl->wl_next); + wl->wl_next = nwl; + nwl->wl_prev = wl; + return (wlist); +} + +/* Reverse a word list. */ + +wordlist * +wl_reverse(wordlist *wl) +{ + wordlist *w, *t; + + for (w = wl; ; w = t) { + t = w->wl_next; + w->wl_next = w->wl_prev; + w->wl_prev = t; + if (t == NULL) + break; + } + return (w); +} + +/* Convert a wordlist into a string. */ + +char * +wl_flatten(wordlist *wl) +{ + char *buf; + wordlist *tw; + int i = 0; + + for (tw = wl; tw; tw = tw->wl_next) + i += strlen(tw->wl_word) + 1; + buf = tmalloc(i + 1); + *buf = 0; + + while (wl != NULL) { + (void) strcat(buf, wl->wl_word); + if (wl->wl_next) + (void) strcat(buf, " "); + wl = wl->wl_next; + } + return (buf); +} + +/* Return the nth element of a wordlist, or the last one if n is too big. + * Numbering starts at 0... + */ + +wordlist * +wl_nthelem(register int i, wordlist *wl) +{ + register wordlist *ww = wl; + + while ((i-- > 0) && ww->wl_next) + ww = ww->wl_next; + return (ww); +} + +void +wl_sort(wordlist *wl) +{ + register int i = 0; + register wordlist *ww = wl; + char **stuff; + + for (i = 0; ww; i++) + ww = ww->wl_next; + if (i < 2) + return; + stuff = (char **) tmalloc(i * sizeof (char *)); + for (i = 0, ww = wl; ww; i++, ww = ww->wl_next) + stuff[i] = ww->wl_word; + qsort((char *) stuff, i, sizeof (char *), wlcomp); + for (i = 0, ww = wl; ww; i++, ww = ww->wl_next) + ww->wl_word = stuff[i]; + tfree(stuff); + return; +} + +static int +wlcomp(char **s, char **t) +{ + return (strcmp(*s, *t)); +} + +/* Return a range of wordlist elements... */ + +wordlist * +wl_range(wordlist *wl, int low, int up) +{ + int i; + wordlist *tt; + bool rev = FALSE; + + if (low > up) { + i = up; + up = low; + low = i; + rev = TRUE; + } + up -= low; + while (wl && (low > 0)) { + tt = wl->wl_next; + tfree(wl->wl_word); + tfree(wl); + wl = tt; + if (wl) + wl->wl_prev = NULL; + low--; + } + tt = wl; + while (tt && (up > 0)) { + tt = tt->wl_next; + up--; + } + if (tt && tt->wl_next) { + wl_free(tt->wl_next); + tt->wl_next = NULL; + } + if (rev) + wl = wl_reverse(wl); + return (wl); +} + diff --git a/src/parser/wlist.h b/src/parser/wlist.h new file mode 100644 index 000000000..fcd38ca02 --- /dev/null +++ b/src/parser/wlist.h @@ -0,0 +1,26 @@ +/************* + * Header file for wlist.c + * 1999 E. Rouat + ************/ + +#ifndef WLIST_H_INCLUDED +#define WLIST_H_INCLUDED + +int wl_length(wordlist *wlist); +void wl_free(wordlist *wlist); +wordlist * wl_copy(wordlist *wlist); +wordlist * wl_splice(wordlist *elt, wordlist *list); +void wl_print(wordlist *wlist, FILE *fp); +wordlist * wl_build(char **v); +char ** wl_mkvec(wordlist *wl); +wordlist * wl_append(wordlist *wlist, wordlist *nwl); +wordlist * wl_reverse(wordlist *wl); +char * wl_flatten(wordlist *wl); +wordlist * wl_nthelem(register int i, wordlist *wl); +void wl_sort(wordlist *wl); +wordlist * wl_range(wordlist *wl, int low, int up); + + + + +#endif diff --git a/src/proc2mod.c b/src/proc2mod.c new file mode 100644 index 000000000..447763dfa --- /dev/null +++ b/src/proc2mod.c @@ -0,0 +1,339 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +/* convert .process file to set of .model cards */ + +#include +#include "ngspice.h" +#include +#include "inpdefs.h" +#include "suffix.h" + + +void exit(); + +#ifdef __STDC__ +void getdata(double*,int,int); +#else /* stdc */ +void getdata(); +#endif /* stdc */ + +typedef struct snmod { + struct snmod *nnext; + char *nname; + double nparms[69]; +} nmod; +typedef struct spmod { + struct spmod *pnext; + char *pname; + double pparms[69]; +} pmod; +typedef struct sdmod { + struct sdmod *dnext; + char *dname; + double dparms[10]; +} dmod; +typedef struct symod { + struct symod *ynext; + char *yname; + double yparms[10]; +} ymod; +typedef struct smmod { + struct smmod *mnext; + char *mname; + double mparms[10]; +} mmod; + +FILE *m = NULL; +FILE *p = NULL; +char *dataline; + + +int +main(void) { + char *typeline; + char *prname; + nmod *nlist=NULL,*ncur; + pmod *plist=NULL,*pcur; + dmod *dlist=NULL,*dcur; + ymod *ylist=NULL,*ycur; + mmod *mlist=NULL,*mcur; + char *filename; + + + filename = (char *)malloc(1024); + typeline = (char *)malloc(1024); + dataline = (char *)malloc(1024); + + while(p == NULL) { + printf("name of process file (input): "); + if(scanf("%s",filename)!=1) { + printf("error reading process file name\n"); + exit(1); + } + p = fopen(filename,"r"); + if(p==NULL) { + printf("can't open %s:",filename); + perror(""); + } + } + while(m == NULL) { + printf("name of .model file (output): "); + if(scanf("%s",filename)!=1) { + printf("error reading model file name\n"); + exit(1); + } + m = fopen(filename,"w"); + if(m==NULL) { + printf("can't open %s:",filename); + perror(""); + } + } + printf("process name : "); + if(scanf("%s",filename)!=1) { + printf("error reading process name\n"); + exit(1); + } + prname = filename; + if(fgets(typeline,1023,p)==NULL) { + printf("error reading input description line\n"); + exit(1); + } + INPcaseFix(typeline); + while(1) { + while(*typeline == ' ' || *typeline == '\t' || *typeline == ',' || + *typeline == '\n' ) { + typeline ++; + } + if(*typeline == 0) break; + if(strncmp("nm",typeline,2) == 0) { + ncur = (nmod *)malloc(sizeof(nmod)); + ncur->nnext = NULL; + ncur->nname = typeline; + *(typeline+3) = (char)NULL; + typeline += 4; + getdata(ncur->nparms,69,3); + ncur->nnext = nlist; + nlist = ncur; + } else if(strncmp("pm",typeline,2) == 0) { + pcur = (pmod *)malloc(sizeof(pmod)); + pcur->pnext = NULL; + pcur->pname = typeline; + *(typeline+3) = (char)NULL; + typeline += 4; + getdata(pcur->pparms,69,3); + pcur->pnext = plist; + plist = pcur; + } else if(strncmp("py",typeline,2) == 0) { + ycur = (ymod *)malloc(sizeof(ymod)); + ycur->ynext = NULL; + ycur->yname = typeline; + *(typeline+3) = (char)NULL; + typeline += 4; + getdata(ycur->yparms,10,5); + ycur->ynext = ylist; + ylist = ycur; + } else if(strncmp("du",typeline,2) == 0) { + dcur = (dmod *)malloc(sizeof(dmod)); + dcur->dnext = NULL; + dcur->dname = typeline; + *(typeline+3) = (char)NULL; + typeline += 4; + getdata(dcur->dparms,10,5); + dcur->dnext = dlist; + dlist = dcur; + } else if(strncmp("ml",typeline,2) == 0) { + mcur = (mmod *)malloc(sizeof(mmod)); + mcur->mnext = NULL; + mcur->mname = typeline; + *(typeline+3) = (char)NULL; + typeline += 4; + getdata(mcur->mparms,10,5); + mcur->mnext = mlist; + mlist = mcur; + } else { + printf(" illegal header line in process file: run terminated\n"); + printf(" error occurred while parsing %s\n",typeline); + exit(1); + } + } + for(dcur=dlist;dcur;dcur=dcur->dnext) { + fprintf(m,".model %s_%s r rsh = %g defw = %g narrow = %g\n", + prname,dcur->dname,dcur->dparms[0],dcur->dparms[8],dcur->dparms[9]); + fprintf(m,".model %s_%s c cj = %g cjsw = %g defw = %g narrow = %g\n", + prname,dcur->dname,dcur->dparms[1],dcur->dparms[2],dcur->dparms[8], + dcur->dparms[9]); + } + for(ycur=ylist;ycur;ycur=ycur->ynext) { + fprintf(m,".model %s_%s r rsh = %g defw = %g narrow = %g\n", + prname,ycur->yname,ycur->yparms[0],ycur->yparms[8],ycur->yparms[9]); + fprintf(m,".model %s_%s c cj = %g cjsw = %g defw = %g narrow = %g\n", + prname,ycur->yname,ycur->yparms[1],ycur->yparms[2],ycur->yparms[8], + ycur->yparms[9]); + } + for(mcur=mlist;mcur;mcur=mcur->mnext) { + fprintf(m,".model %s_%s r rsh = %g defw = %g narrow = %g\n", + prname,mcur->mname,mcur->mparms[0],mcur->mparms[8],mcur->mparms[9]); + fprintf(m,".model %s_%s c cj = %g cjsw = %g defw = %g narrow = %g\n", + prname,mcur->mname,mcur->mparms[1],mcur->mparms[2],mcur->mparms[8], + mcur->mparms[9]); + } + for(pcur=plist;pcur;pcur=pcur->pnext) { + for(dcur=dlist;dcur;dcur=dcur->dnext) { + fprintf(m,".model %s_%s_%s pmos level=4\n",prname,pcur->pname, + dcur->dname); + fprintf(m,"+ vfb = %g lvfb = %g wvfb = %g\n", + pcur->pparms[0],pcur->pparms[1],pcur->pparms[2]); + fprintf(m,"+ phi = %g lphi = %g wphi = %g\n", + pcur->pparms[3],pcur->pparms[4],pcur->pparms[5]); + fprintf(m,"+ k1 = %g lk1 = %g wk1 = %g\n", + pcur->pparms[6],pcur->pparms[7],pcur->pparms[8]); + fprintf(m,"+ k2 = %g lk2 = %g wk2 = %g\n", + pcur->pparms[9],pcur->pparms[10],pcur->pparms[11]); + fprintf(m,"+ eta = %g leta = %g weta = %g\n", + pcur->pparms[12],pcur->pparms[13],pcur->pparms[14]); + fprintf(m,"+ muz = %g dl = %g dw = %g\n", + pcur->pparms[15],pcur->pparms[16],pcur->pparms[17]); + fprintf(m,"+ u0 = %g lu0 = %g wu0 = %g\n", + pcur->pparms[18],pcur->pparms[19],pcur->pparms[20]); + fprintf(m,"+ u1 = %g lu1 = %g wu1 = %g\n", + pcur->pparms[21],pcur->pparms[22],pcur->pparms[23]); + fprintf(m,"+ x2mz = %g lx2mz = %g wx2mz = %g\n", + pcur->pparms[24],pcur->pparms[25],pcur->pparms[26]); + fprintf(m,"+ x2e = %g lx2e = %g wx2e = %g\n", + pcur->pparms[27],pcur->pparms[28],pcur->pparms[29]); + fprintf(m,"+ x3e = %g lx3e = %g wx3e = %g\n", + pcur->pparms[30],pcur->pparms[31],pcur->pparms[32]); + fprintf(m,"+ x2u0 = %g lx2u0 = %g wx2u0 = %g\n", + pcur->pparms[33],pcur->pparms[34],pcur->pparms[35]); + fprintf(m,"+ x2u1 = %g lx2u1 = %g wx2u1 = %g\n", + pcur->pparms[36],pcur->pparms[37],pcur->pparms[38]); + fprintf(m,"+ mus = %g lmus = %g wmus = %g\n", + pcur->pparms[39],pcur->pparms[40],pcur->pparms[41]); + fprintf(m,"+ x2ms = %g lx2ms = %g wx2ms = %g\n", + pcur->pparms[42],pcur->pparms[43],pcur->pparms[44]); + fprintf(m,"+ x3ms = %g lx3ms = %g wx3ms = %g\n", + pcur->pparms[45],pcur->pparms[46],pcur->pparms[47]); + fprintf(m,"+ x3u1 = %g lx3u1 = %g wx3u1 = %g\n", + pcur->pparms[48],pcur->pparms[49],pcur->pparms[50]); + fprintf(m,"+ tox = %g temp = %g vdd = %g\n", + pcur->pparms[51],pcur->pparms[52],pcur->pparms[53]); + fprintf(m,"+ cgdo = %g cgso = %g cgbo = %g\n", + pcur->pparms[54],pcur->pparms[55],pcur->pparms[56]); + fprintf(m,"+ xpart = %g \n", + pcur->pparms[57]); + fprintf(m,"+ n0 = %g ln0 = %g wn0 = %g\n", + pcur->pparms[60],pcur->pparms[61],pcur->pparms[62]); + fprintf(m,"+ nb = %g lnb = %g wnb = %g\n", + pcur->pparms[63],pcur->pparms[64],pcur->pparms[65]); + fprintf(m,"+ nd = %g lnd = %g wnd = %g\n", + pcur->pparms[66],pcur->pparms[67],pcur->pparms[68]); + fprintf(m,"+ rsh = %g cj = %g cjsw = %g\n", + dcur->dparms[0], dcur->dparms[1], dcur->dparms[2]); + fprintf(m,"+ js = %g pb = %g pbsw = %g\n", + dcur->dparms[3], dcur->dparms[4], dcur->dparms[5]); + fprintf(m,"+ mj = %g mjsw = %g wdf = %g\n", + dcur->dparms[6], dcur->dparms[7], dcur->dparms[8]); + fprintf(m,"+ dell = %g\n", + dcur->dparms[9]); + } + } + for(ncur=nlist;ncur;ncur=ncur->nnext) { + for(dcur=dlist;dcur;dcur=dcur->dnext) { + fprintf(m,".model %s_%s_%s nmos level=4\n",prname,ncur->nname, + dcur->dname); + fprintf(m,"+ vfb = %g lvfb = %g wvfb = %g\n", + ncur->nparms[0],ncur->nparms[1],ncur->nparms[2]); + fprintf(m,"+ phi = %g lphi = %g wphi = %g\n", + ncur->nparms[3],ncur->nparms[4],ncur->nparms[5]); + fprintf(m,"+ k1 = %g lk1 = %g wk1 = %g\n", + ncur->nparms[6],ncur->nparms[7],ncur->nparms[8]); + fprintf(m,"+ k2 = %g lk2 = %g wk2 = %g\n", + ncur->nparms[9],ncur->nparms[10],ncur->nparms[11]); + fprintf(m,"+ eta = %g leta = %g weta = %g\n", + ncur->nparms[12],ncur->nparms[13],ncur->nparms[14]); + fprintf(m,"+ muz = %g dl = %g dw = %g\n", + ncur->nparms[15],ncur->nparms[16],ncur->nparms[17]); + fprintf(m,"+ u0 = %g lu0 = %g wu0 = %g\n", + ncur->nparms[18],ncur->nparms[19],ncur->nparms[20]); + fprintf(m,"+ u1 = %g lu1 = %g wu1 = %g\n", + ncur->nparms[21],ncur->nparms[22],ncur->nparms[23]); + fprintf(m,"+ x2mz = %g lx2mz = %g wx2mz = %g\n", + ncur->nparms[24],ncur->nparms[25],ncur->nparms[26]); + fprintf(m,"+ x2e = %g lx2e = %g wx2e = %g\n", + ncur->nparms[27],ncur->nparms[28],ncur->nparms[29]); + fprintf(m,"+ x3e = %g lx3e = %g wx3e = %g\n", + ncur->nparms[30],ncur->nparms[31],ncur->nparms[32]); + fprintf(m,"+ x2u0 = %g lx2u0 = %g wx2u0 = %g\n", + ncur->nparms[33],ncur->nparms[34],ncur->nparms[35]); + fprintf(m,"+ x2u1 = %g lx2u1 = %g wx2u1 = %g\n", + ncur->nparms[36],ncur->nparms[37],ncur->nparms[38]); + fprintf(m,"+ mus = %g lmus = %g wmus = %g\n", + ncur->nparms[39],ncur->nparms[40],ncur->nparms[41]); + fprintf(m,"+ x2ms = %g lx2ms = %g wx2ms = %g\n", + ncur->nparms[42],ncur->nparms[43],ncur->nparms[44]); + fprintf(m,"+ x3ms = %g lx3ms = %g wx3ms = %g\n", + ncur->nparms[45],ncur->nparms[46],ncur->nparms[47]); + fprintf(m,"+ x3u1 = %g lx3u1 = %g wx3u1 = %g\n", + ncur->nparms[48],ncur->nparms[49],ncur->nparms[50]); + fprintf(m,"+ tox = %g temp = %g vdd = %g\n", + ncur->nparms[51],ncur->nparms[52],ncur->nparms[53]); + fprintf(m,"+ cgdo = %g cgso = %g cgbo = %g\n", + ncur->nparms[54],ncur->nparms[55],ncur->nparms[56]); + fprintf(m,"+ xpart = %g \n", + ncur->nparms[57]); + fprintf(m,"+ n0 = %g ln0 = %g wn0 = %g\n", + ncur->nparms[60],ncur->nparms[61],ncur->nparms[62]); + fprintf(m,"+ nb = %g lnb = %g wnb = %g\n", + ncur->nparms[63],ncur->nparms[64],ncur->nparms[65]); + fprintf(m,"+ nd = %g lnd = %g wnd = %g\n", + ncur->nparms[66],ncur->nparms[67],ncur->nparms[68]); + fprintf(m,"+ rsh = %g cj = %g cjsw = %g\n", + dcur->dparms[0], dcur->dparms[1], dcur->dparms[2]); + fprintf(m,"+ js = %g pb = %g pbsw = %g\n", + dcur->dparms[3], dcur->dparms[4], dcur->dparms[5]); + fprintf(m,"+ mj = %g mjsw = %g wdf = %g\n", + dcur->dparms[6], dcur->dparms[7], dcur->dparms[8]); + fprintf(m,"+ dell = %g\n", + dcur->dparms[9]); + } + } + return EXIT_NORMAL; +} + +void +getdata(vals,count,width) + double vals[]; + int count; + int width; /* maximum number of values to accept per line */ +{ + int i; + int error; + int start; + char *c; + + do { + if(fgets(dataline,1023,p)==NULL) { + printf("premature end of file getting input data line\n"); + exit(1); + } + start=0; + } while (*dataline == '*') ; + c = dataline; + for(i=0;iwidth)) { /* end of line, so read another one */ + do { + if(fgets(dataline,1023,p)==NULL) { + printf("premature end of file reading input data line \n"); + exit(1); + } + start=0; + } while (*dataline == '*') ; + c = dataline; + goto retry; + } + } +} diff --git a/src/sconvert.c b/src/sconvert.c new file mode 100644 index 000000000..1ff4ee425 --- /dev/null +++ b/src/sconvert.c @@ -0,0 +1,440 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group +**********/ + +/* + * Main routine for sconvert. + */ + +#include "ngspice.h" +#include +#include "cpdefs.h" +#include "ftedefs.h" +#include "ftedata.h" +#include "suffix.h" + +FILE *cp_in = 0; +FILE *cp_out = 0; +FILE *cp_err = 0; +FILE *cp_curin = 0; +FILE *cp_curout = 0; +FILE *cp_curerr = 0; +int cp_maxhistlength; +bool cp_debug = FALSE; +char cp_chars[128]; +bool cp_nocc = TRUE; +bool ft_parsedb = FALSE; +struct circ *ft_curckt = NULL; + +char *cp_program = "sconvert"; + +/* doesn't get used, but some unused routine in some file references it */ +char out_pbuf[BSIZE_SP]; + +static void oldwrite(); +static struct plot *oldread(); +static char *fixdate(); + +int +main(ac, av) + char **av; +{ + char *sf, *af; + char buf[BSIZE_SP]; + char t, f; + struct plot *pl; + int i; + char *infile; + char *outfile; + FILE *fp; + cp_in = stdin; + cp_out = stdout; + cp_err = stderr; + cp_curin = stdin; + cp_curout = stdout; + cp_curerr = stderr; + + switch (ac) { + case 5: + sf = av[2]; + af = av[4]; + f = *av[1]; + t = *av[3]; + break; + + case 3: + f = *av[1]; + t = *av[2]; + /* This is a pain, but there is no choice */ + sf = infile = smktemp("scin"); + af = outfile = smktemp("scout"); + if (!(fp = fopen(infile, "w"))) { + perror(infile); + exit(EXIT_BAD); + } + while ((i = fread(buf, 1, sizeof(buf), stdin))) + (void) fwrite(buf, 1, i, fp); + (void) fclose(fp); + break; + + case 1: printf("Input file: "); + (void) fflush(stdout); + (void) fgets(buf, BSIZE_SP, stdin); + sf = copy(buf); + printf("Input type: "); + (void) fflush(stdout); + (void) fgets(buf, BSIZE_SP, stdin); + f = buf[0]; + printf("Output file: "); + (void) fflush(stdout); + (void) fgets(buf, BSIZE_SP, stdin); + af = copy(buf); + printf("Output type: "); + (void) fflush(stdout); + (void) fgets(buf, BSIZE_SP, stdin); + t = buf[0]; + break; + default: + fprintf(cp_err, + "Usage: %s fromtype fromfile totype tofile,\n", + cp_program); + fprintf(cp_err, "\twhere types are o, b, or a\n"); + fprintf(cp_err, + "\tor, %s fromtype totype, used as a filter.\n", + cp_program); + exit(EXIT_BAD); + } + switch(f) { + case 'o' : + pl = oldread(sf); + break; + + case 'b' : + case 'a' : + pl = raw_read(sf); + break; + + default: + fprintf(cp_err, "Types are o, a, or b\n"); + exit(EXIT_BAD); + } + if (!pl) + exit(EXIT_BAD); + + switch(t) { + case 'o' : + oldwrite(af, FALSE, pl); + break; + + case 'b' : + raw_write(af, pl, FALSE, TRUE); + break; + + case 'a' : + raw_write(af, pl, FALSE, FALSE); + break; + + default: + fprintf(cp_err, "Types are o, a, or b\n"); + exit(EXIT_BAD); + } + if (ac == 3) { + /* Gotta finish this stuff up */ + if (!(fp = fopen(outfile, "r"))) { + perror(outfile); + exit(EXIT_BAD); + } + while ((i = fread(buf, 1, sizeof(buf), fp))) + (void) fwrite(buf, 1, i, stdout); + (void) fclose(fp); + (void) unlink(infile); + (void) unlink(outfile); + } + exit(EXIT_NORMAL); +} + +#define tfread(ptr, siz, nit, fp) if (fread((char *) (ptr), (siz), \ + (nit), (fp)) != (nit)) { \ + fprintf(cp_err, "Error: unexpected EOF\n"); \ + return (NULL); } + +#define tfwrite(ptr, siz, nit, fp) if (fwrite((char *) (ptr), (siz), \ + (nit), (fp)) != (nit)) { \ + fprintf(cp_err, "Write error\n"); \ + return; } + +static struct plot * +oldread(name) + char *name; +{ + struct plot *pl; + char buf[BSIZE_SP]; + struct dvec *v, *end = NULL; + short nv; /* # vars */ + long np; /* # points/var. */ + long i, j; + short a; /* The magic number. */ + float f1, f2; + FILE *fp; + + if (!(fp = fopen(name, "r"))) { + perror(name); + return (NULL); + } + pl = alloc(struct plot); + tfread(buf, 1, 80, fp); + buf[80] = '\0'; + for (i = strlen(buf) - 1; (i > 1) && (buf[i] == ' '); i--) + ; + buf[i + 1] = '\0'; + pl->pl_title = copy(buf); + + tfread(buf, 1, 16, fp); + buf[16] = '\0'; + pl->pl_date = copy(fixdate(buf)); + + tfread(&nv, sizeof (short), 1, fp); + + tfread(&a, sizeof (short), 1, fp); + if (a != 4) + fprintf(cp_err, "Warning: magic number 4 is wrong...\n"); + + for (i = 0; i < nv; i++) { + v = alloc(struct dvec); + if (end) + end->v_next = v; + else + pl->pl_scale = pl->pl_dvecs = v; + end = v; + tfread(buf, 1, 8, fp); + buf[8] = '\0'; + v->v_name = copy(buf); + } + for (v = pl->pl_dvecs; v; v = v->v_next) { + tfread(&a, sizeof (short), 1, fp); + v->v_type = a; + } + + /* If the first output variable is type FREQ then there is complex + * data, otherwise the data is real. + */ + i = pl->pl_dvecs->v_type; + if ((i == SV_FREQUENCY) || (i == SV_POLE) || (i == SV_ZERO)) + for (v = pl->pl_dvecs; v; v = v->v_next) + v->v_flags |= VF_COMPLEX; + else + for (v = pl->pl_dvecs; v; v = v->v_next) + v->v_flags |= VF_REAL; + + /* Check the node indices -- this shouldn't be a problem ever. */ + for (i = 0; i < nv; i++) { + tfread(&a, sizeof(short), 1, fp); + if (a != i + 1) + fprintf(cp_err, "Warning: output %d should be %ld\n", + a, i); + } + tfread(buf, 1, 24, fp); + buf[24] = '\0'; + pl->pl_name = copy(buf); + /* Now to figure out how many points of data there are left in + * the file. + */ + i = ftell(fp); + (void) fseek(fp, (long) 0, 2); + j = ftell(fp); + (void) fseek(fp, i, 0); + i = j - i; + if (i % 8) { /* Data points are always 8 bytes... */ + fprintf(cp_err, "Error: alignment error in data\n"); + (void) fclose(fp); + return (NULL); + } + i = i / 8; + if (i % nv) { + fprintf(cp_err, "Error: alignment error in data\n"); + (void) fclose(fp); + return (NULL); + } + np = i / nv; + + for (v = pl->pl_dvecs; v; v = v->v_next) { + v->v_length = np; + if (isreal(v)) { + v->v_realdata = (double *) tmalloc(sizeof (double) + * np); + } else { + v->v_compdata = (complex *) tmalloc(sizeof (complex) + * np); + } + } + for (i = 0; i < np; i++) { + /* Read in the output vector for point i. If the type is + * complex it will be float and we want double. + */ + for (v = pl->pl_dvecs; v; v = v->v_next) { + if (v->v_flags & VF_REAL) { + tfread(&v->v_realdata[i], sizeof (double), + 1, fp); + } else { + tfread(&f1, sizeof (float), 1, fp); + tfread(&f2, sizeof (float), 1, fp); + realpart(&v->v_compdata[i]) = f1; + imagpart(&v->v_compdata[i]) = f2; + } + } + } + (void) fclose(fp); + return (pl); +} + +static void +oldwrite(name, app, pl) + char *name; + bool app; + struct plot *pl; +{ + short four = 4, k; + struct dvec *v; + float f1, f2, zero = 0.0; + char buf[80]; + int i, j, tp = VF_REAL, numpts = 0, numvecs = 0; + FILE *fp; + + if (!(fp = fopen(name, app ? "a" : "w"))) { + perror(name); + return; + } + + for (v = pl->pl_dvecs; v; v = v->v_next) { + if (v->v_length > numpts) + numpts = v->v_length; + numvecs++; + if (iscomplex(v)) + tp = VF_COMPLEX; + } + + /* This may not be a good idea... */ + if (tp == VF_COMPLEX) + pl->pl_scale->v_type = SV_FREQUENCY; + + for (i = 0; i < 80; i++) + buf[i] = ' '; + for (i = 0; i < 80; i++) + if (pl->pl_title[i] == '\0') + break; + else + buf[i] = pl->pl_title[i]; + tfwrite(buf, 1, 80, fp); + + for (i = 0; i < 80; i++) + buf[i] = ' '; + for (i = 0; i < 16; i++) + if (pl->pl_date[i] == '\0') + break; + else + buf[i] = pl->pl_date[i]; + tfwrite(buf, 1, 16, fp); + + tfwrite(&numvecs, sizeof (short), 1, fp); + tfwrite(&four, sizeof (short), 1, fp); + + for (v = pl->pl_dvecs; v; v = v->v_next) { + for (j = 0; j < 80; j++) + buf[j] = ' '; + for (j = 0; j < 8; j++) + if (v->v_name[j] == '\0') + break; + else + buf[j] = v->v_name[j]; + tfwrite(buf, 1, 8, fp); + } + + for (v = pl->pl_dvecs; v; v = v->v_next) { + j = (short) v->v_type; + tfwrite(&j, sizeof (short), 1, fp); + } + + for (k = 1; k < numvecs + 1; k++) + tfwrite(&k, sizeof (short), 1, fp); + for (j = 0; j < 80; j++) + buf[j] = ' '; + for (j = 0; j < 24; j++) + if (pl->pl_name[j] == '\0') + break; + else + buf[j] = pl->pl_name[j]; + tfwrite(buf, 1, 24, fp); + for (i = 0; i < numpts; i++) { + for (v = pl->pl_dvecs; v; v = v->v_next) { + if ((tp == VF_REAL) && isreal(v)) { + if (i < v->v_length) { + tfwrite(&v->v_realdata[i], sizeof (double), 1, fp); + } else { + tfwrite(&v->v_realdata[v->v_length - 1], sizeof (double), 1, fp); + } + } else if ((tp == VF_REAL) && iscomplex(v)) { + if (i < v->v_length) + f1 = realpart(&v->v_compdata[i]); + else + f1 = realpart(&v->v_compdata[v-> v_length - 1]); + tfwrite(&f1, sizeof (double), 1, fp); + } else if ((tp == VF_COMPLEX) && isreal(v)) { + if (i < v->v_length) + f1 = v->v_realdata[i]; + else + f1 = v->v_realdata[v->v_length - 1]; + tfwrite(&f1, sizeof (float), 1, fp); + tfwrite(&zero, sizeof (float), 1, fp); + } else if ((tp == VF_COMPLEX) && iscomplex(v)) { + if (i < v->v_length) { + f1 = realpart(&v->v_compdata[i]); + f2 = imagpart(&v->v_compdata[i]); + } else { + f1 = realpart(&v->v_compdata[v-> v_length - 1]); + f2 = imagpart(&v->v_compdata[v-> v_length - 1]); + } + tfwrite(&f1, sizeof (float), 1, fp); + tfwrite(&f2, sizeof (float), 1, fp); + } + } + } + + (void) fclose(fp); + return; +} + +static char * +fixdate(date) + char *date; +{ + char buf[20]; + int i; + + (void) strcpy(buf, date); + for (i = 17; i > 8; i--) + buf[i] = buf[i - 1]; + buf[8] = ' '; + buf[18] = '\0'; + return (copy(buf)); +} + +void cp_pushcontrol() { } +void cp_popcontrol() { } +void out_init() { } +void cp_doquit() { exit(0); } +/* ARGSUSED */ void cp_usrvars(v1, v2) struct variable **v1, **v2; { return; } +/* ARGSUSED */ int cp_evloop(s) char *s; { return (0); } +/* ARGSUSED */ void cp_ccon(o) bool o; { } +/* ARGSUSED */ char *if_errstring(c) int c; { return ("error"); } +#ifndef out_printf +/* VARARGS1 ARGSUSED */ void out_printf(fmt, args) char *fmt; { } +#endif +/* ARGSUSED */ void out_send(string) char *string; {} +/* ARGSUSED */ struct variable * cp_enqvar(word) char *word; { return (NULL); } +/* ARGSUSED */ struct dvec *vec_get(word) char *word; { return (NULL); } +/* ARGSUSED */ void cp_ccom(w, b, e) wordlist *w; char *b; bool e; { return; } +/* ARGSUSED */ int cp_usrset(v, i) struct variable *v; bool i;{return(US_OK); } + +int disptype; +void XtDispatchEvent(pev) char *pev; {} diff --git a/src/spicelib/devices/ChangeLog b/src/spicelib/devices/ChangeLog new file mode 100644 index 000000000..566a103f8 --- /dev/null +++ b/src/spicelib/devices/ChangeLog @@ -0,0 +1,13 @@ +2000-04-04 Paolo Nenzi + + * Makefile.am: Added support for BSIM4 + +2000-01-16 Emmanuel Rouat + + * *.c : replaced all FABS macros by the 'fabs' function + +2000-01-14 Paolo Nenzi + + * Added bsim3v1 and bsim3v2 directories. They containthe old bsim3 + models V3.2 and V3.1. This models are still used in commercial + simulators and some components libraries relies upon them. diff --git a/src/spicelib/devices/Makefile.am b/src/spicelib/devices/Makefile.am new file mode 100644 index 000000000..6fa8ebcaa --- /dev/null +++ b/src/spicelib/devices/Makefile.am @@ -0,0 +1,38 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = \ + asrc \ + bjt \ + bsim1 \ + bsim2 \ + bsim3 \ + bsim4 \ + bsim3v1 \ + bsim3v2 \ + cap \ + cccs \ + ccvs \ + csw \ + devsup \ + dio \ + disto \ + ind \ + isrc \ + jfet \ + jfet2 \ + ltra \ + mes \ + mos1 \ + mos2 \ + mos3 \ + mos6 \ + res \ + sw \ + tra \ + urc \ + vccs \ + vcvs \ + vsrc + + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/asrc/ChangeLog b/src/spicelib/devices/asrc/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/asrc/Makefile.am b/src/spicelib/devices/asrc/Makefile.am new file mode 100644 index 000000000..0aa14b0ea --- /dev/null +++ b/src/spicelib/devices/asrc/Makefile.am @@ -0,0 +1,25 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libasrc.la + +libasrc_la_SOURCES = \ + asrc.c \ + asrcacld.c \ + asrcask.c \ + asrcconv.c \ + asrcdefs.h \ + asrcdel.c \ + asrcdest.c \ + asrcext.h \ + asrcfbr.c \ + asrcitf.h \ + asrcload.c \ + asrcmdel.c \ + asrcpar.c \ + asrcpzld.c \ + asrcset.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/asrc/asrc.c b/src/spicelib/devices/asrc/asrc.c new file mode 100644 index 000000000..247501583 --- /dev/null +++ b/src/spicelib/devices/asrc/asrc.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "asrcdefs.h" +#include "suffix.h" + +/* Arbitrary source */ +IFparm ASRCpTable[] = { /* parameters */ + IP( "i", ASRC_CURRENT, IF_PARSETREE, "Current source "), + IP( "v", ASRC_VOLTAGE, IF_PARSETREE, "Voltage source"), + OP( "i", ASRC_OUTPUTCURRENT, IF_REAL, "Current through source "), + OP( "v", ASRC_OUTPUTVOLTAGE, IF_REAL, "Voltage across source"), + OP( "pos_node", ASRC_POS_NODE, IF_INTEGER, "Positive Node"), + OP( "neg_node", ASRC_NEG_NODE, IF_INTEGER, "Negative Node") +}; + +char *ASRCnames[] = { + "src+", + "src-" +}; + +int ASRCnSize = NUMELEMS(ASRCnames); +int ASRCpTSize = NUMELEMS(ASRCpTable); +int ASRCmPTSize = 0; +int ASRCiSize = sizeof(ASRCinstance); +int ASRCmSize = sizeof(ASRCmodel); diff --git a/src/spicelib/devices/asrc/asrcacld.c b/src/spicelib/devices/asrc/asrcacld.c new file mode 100644 index 000000000..9321518cc --- /dev/null +++ b/src/spicelib/devices/asrc/asrcacld.c @@ -0,0 +1,108 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +ASRCacLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + + /* + * Actually load the current voltage value into the + * sparse matrix previously provided. The values have + * been precomputed and stored with the instance model. + */ + + register ASRCmodel *model = (ASRCmodel*)inModel; + register ASRCinstance *here; + int i, v_first, j; + double *derivs; + double rhs; + + /* loop through all the Arbitrary source models */ + for( ; model != NULL; model = model->ASRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ASRCinstances; here != NULL ; + here = here->ASRCnextInstance) { + if (here->ASRCowner != ARCHme) continue; + + /* + * Get the function and its derivatives from the + * field in the instance structure. The field is + * an array of doubles holding the rhs, and the + * entries of the jacobian. + */ + + v_first = 1; + j=0; + derivs = here->ASRCacValues; + rhs = (here->ASRCacValues)[here->ASRCtree->numVars]; + + for(i=0; i < here->ASRCtree->numVars; i++){ + switch(here->ASRCtree->varTypes[i]){ + case IF_INSTANCE: + if( here->ASRCtype == ASRC_VOLTAGE){ + /* CCVS */ + if(v_first){ + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) += 1.0; + v_first = 0; + } + *(here->ASRCposptr[j++]) -= derivs[i]; + } else{ + /* CCCS */ + *(here->ASRCposptr[j++]) += derivs[i]; + *(here->ASRCposptr[j++]) -= derivs[i]; + } + break; + case IF_NODE: + if(here->ASRCtype == ASRC_VOLTAGE){ + /* VCVS */ + if( v_first){ + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) += 1.0; + v_first = 0; + } + *(here->ASRCposptr[j++]) -= derivs[i]; + } else { + /*VCCS*/ + *(here->ASRCposptr[j++]) += derivs[i]; + *(here->ASRCposptr[j++]) -= derivs[i]; + } + break; + default: + return(E_BADPARM); + } + } +#ifdef notdef + /* Insert the RHS */ + if( here->ASRCtype == ASRC_VOLTAGE){ + *(ckt->CKTrhs+(here->ASRCbranch)) += rhs; + } else { + *(ckt->CKTrhs+(here->ASRCposNode)) -= rhs; + *(ckt->CKTrhs+(here->ASRCnegNode)) += rhs; + } +#endif + } + } + return(OK); +} diff --git a/src/spicelib/devices/asrc/asrcask.c b/src/spicelib/devices/asrc/asrcask.c new file mode 100644 index 000000000..8059aed46 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcask.c @@ -0,0 +1,61 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +/* + * This routine gives access to the internal device parameters + * of Current Controlled Voltage Source + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +ASRCask(ckt,instPtr,which,value,select) + CKTcircuit *ckt; + GENinstance *instPtr; + int which; + IFvalue *value; + IFvalue *select; +{ + register ASRCinstance *here = (ASRCinstance*)instPtr; + + switch(which) { + case ASRC_CURRENT: + value->tValue = here->ASRCtype == ASRC_CURRENT ? + here->ASRCtree : NULL; + return (OK); + case ASRC_VOLTAGE: + value->tValue = here->ASRCtype == ASRC_VOLTAGE ? + here->ASRCtree : NULL; + return (OK); + case ASRC_POS_NODE: + value->iValue = here->ASRCposNode; + return (OK); + case ASRC_NEG_NODE: + value->iValue = here->ASRCnegNode; + return (OK); + case ASRC_OUTPUTCURRENT: + value->rValue = ckt->CKTrhsOld[here->ASRCbranch]; + return (OK); + case ASRC_OUTPUTVOLTAGE: + value->rValue = ckt->CKTrhsOld[here->ASRCposNode] - + ckt->CKTrhsOld[here->ASRCnegNode]; + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/asrc/asrcconv.c b/src/spicelib/devices/asrc/asrcconv.c new file mode 100644 index 000000000..95afcb913 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcconv.c @@ -0,0 +1,78 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Kanwar Jit Singh +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +ASRCconvTest( inModel, ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + register ASRCmodel *model = (ASRCmodel *)inModel; + register ASRCinstance *here; + int i, node_num, branch; + double diff; + double prev; + double tol; + double rhs; + + for( ; model != NULL; model = model->ASRCnextModel) { + for( here = model->ASRCinstances; here != NULL; + here = here->ASRCnextInstance) { + if (here->ASRCowner != ARCHme) continue; + + i = here->ASRCtree->numVars; + if (asrc_nvals < i) { + if (asrc_nvals) { + FREE(asrc_vals); + FREE(asrc_derivs); + } + asrc_nvals = i; + asrc_vals = NEWN(double, i); + asrc_derivs = NEWN(double, i); + } + + for( i=0; i < here->ASRCtree->numVars; i++){ + if( here->ASRCtree->varTypes[i] == IF_INSTANCE){ + branch = CKTfndBranch(ckt,here->ASRCtree->vars[i].uValue); + asrc_vals[i] = *(ckt->CKTrhsOld+branch); + } else { + node_num = ((CKTnode *)(here->ASRCtree->vars[i].nValue)) + ->number; + asrc_vals[i] = *(ckt->CKTrhsOld+node_num); + } + } + + if( (*(here->ASRCtree->IFeval))(here->ASRCtree, ckt->CKTgmin, &rhs, + asrc_vals,asrc_derivs) == OK){ + + prev = here->ASRCprev_value; + diff = fabs( prev - rhs); + if ( here->ASRCtype == ASRC_VOLTAGE){ + tol = ckt->CKTreltol * + MAX(fabs(rhs),fabs(prev)) + ckt->CKTvoltTol; + } else { + tol = ckt->CKTreltol * + MAX(fabs(rhs),fabs(prev)) + ckt->CKTabstol; + } + + if ( diff > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); + } + } else { + + return(E_BADPARM); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/asrc/asrcdefs.h b/src/spicelib/devices/asrc/asrcdefs.h new file mode 100644 index 000000000..ab0e3cfed --- /dev/null +++ b/src/spicelib/devices/asrc/asrcdefs.h @@ -0,0 +1,75 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef ASRC +#define ASRC + + +#include "cktdefs.h" +#include "ifsim.h" +#include "complex.h" + + /* + * structures to describe Arbitrary sources + */ + +/* information to describe a single instance */ + +typedef struct sASRCinstance { + struct sASRCmodel *ARRCmodPtr; /* backpointer to model */ + struct sASRCinstance *ASRCnextInstance; /* pointer to next instance of + *current model*/ + IFuid ASRCname; /* pointer to character string naming this instance */ + int ASRCowner; /* number of owner process */ + int ASRCstates; /* state info */ + int ASRCposNode; /* number of positive node of source */ + int ASRCnegNode; /* number of negative node of source */ + int ASRCtype; /* Whether source is voltage or current */ + int ASRCbranch; /* number of branch equation added for v source */ + IFparseTree *ASRCtree; /* The parse tree */ + double **ASRCposptr; /* pointer to pointers of the elements + * in the sparce matrix */ + double ASRCprev_value; /* Previous value for the convergence test */ + double *ASRCacValues; /* Store rhs and derivatives for ac anal */ + int ASRCcont_br; /* Temporary store for controlling current branch */ + +} ASRCinstance ; + +#define ASRCvOld ASRCstates +#define ASRCcontVOld ASRCstates + 1 + +/* per model data */ + +typedef struct sASRCmodel { /* model structure for a source */ + int ASRCmodType; /* type index of this device */ + struct sASRCmodel *ASRCnextModel; /* pointer to next possible model + *in linked list */ + ASRCinstance * ASRCinstances; /* pointer to list of instances + * that have this model */ + IFuid ASRCmodName; /* pointer to character string naming this model */ +} ASRCmodel; + +/* device parameters */ +#define ASRC_VOLTAGE 1 +#define ASRC_CURRENT 2 +#define ASRC_POS_NODE 3 +#define ASRC_NEG_NODE 4 +#define ASRC_PARSE_TREE 5 +#define ASRC_OUTPUTVOLTAGE 6 +#define ASRC_OUTPUTCURRENT 7 + +/* module-wide variables */ + +extern double *asrc_vals, *asrc_derivs; +extern int asrc_nvals; + +/* model parameters */ + +/* device questions */ + +/* model questions */ + +#include "asrcext.h" +#endif /*ASRC*/ diff --git a/src/spicelib/devices/asrc/asrcdel.c b/src/spicelib/devices/asrc/asrcdel.c new file mode 100644 index 000000000..ebfb5e79f --- /dev/null +++ b/src/spicelib/devices/asrc/asrcdel.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +#include "ngspice.h" +#include +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +ASRCdelete(model,name,fast) + GENmodel *model; + IFuid name; + GENinstance **fast; + +{ + register ASRCinstance **instPtr = (ASRCinstance**)fast; + ASRCmodel *modPtr = (ASRCmodel*)model; + + ASRCinstance **prev = NULL; + ASRCinstance *here; + + for( ; modPtr ; modPtr = modPtr->ASRCnextModel) { + prev = &(modPtr->ASRCinstances); + for(here = *prev; here ; here = *prev) { + if(here->ASRCname == name || (instPtr && here==*instPtr) ) { + *prev= here->ASRCnextInstance; + FREE(here); + return(OK); + } + prev = &(here->ASRCnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/asrc/asrcdest.c b/src/spicelib/devices/asrc/asrcdest.c new file mode 100644 index 000000000..2f930a6b6 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcdest.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ + +#include "ngspice.h" +#include +#include "asrcdefs.h" +#include "suffix.h" + +void +ASRCdestroy(model) + GENmodel **model; + +{ + ASRCmodel **start = (ASRCmodel**)model; /* starting model */ + ASRCinstance *here; /* current instance */ + ASRCinstance *next; + ASRCmodel *mod = *start; /* current model */ + ASRCmodel *nextmod; + + for( ; mod ; mod = nextmod) { + for(here = mod->ASRCinstances ; here ; here = next) { + next = here->ASRCnextInstance; + FREE(here->ASRCacValues); + FREE(here); + } + nextmod = mod->ASRCnextModel; + FREE(mod); + } + *model = NULL; +} diff --git a/src/spicelib/devices/asrc/asrcext.h b/src/spicelib/devices/asrc/asrcext.h new file mode 100644 index 000000000..8de0047fb --- /dev/null +++ b/src/spicelib/devices/asrc/asrcext.h @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int ASRCask(CKTcircuit*,GENinstance *,int,IFvalue *,IFvalue*); +extern int ASRCconvTest(GENmodel *,CKTcircuit*); +extern int ASRCdelete(GENmodel *,IFuid,GENinstance **); +extern void ASRCdestroy(GENmodel**); +extern int ASRCfindBr(CKTcircuit *,GENmodel *,IFuid); +extern int ASRCload(GENmodel *,CKTcircuit*); +extern int ASRCmDelete(GENmodel**,IFuid,GENmodel*); +extern int ASRCparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int ASRCpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int ASRCacLoad(GENmodel*,CKTcircuit*); +extern int ASRCsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int ASRCunsetup(GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int ASRCask(); +extern int ASRCconvTest(); +extern int ASRCdelete(); +extern void ASRCdestroy(); +extern int ASRCfindBr(); +extern int ASRCload(); +extern int ASRCmDelete(); +extern int ASRCparam(); +extern int ASRCpzLoad(); +extern int ASRCacLoad(); +extern int ASRCsetup(); +extern int ASRCunsetup(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/asrc/asrcfbr.c b/src/spicelib/devices/asrc/asrcfbr.c new file mode 100644 index 000000000..d3f05cb51 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcfbr.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ifsim.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +ASRCfindBr(ckt,inputModel,name) + register CKTcircuit *ckt; + GENmodel *inputModel; + register IFuid name; +{ + register ASRCinstance *here; + register ASRCmodel *model = (ASRCmodel*)inputModel; + int error; + CKTnode *tmp; + + for( ; model != NULL; model = model->ASRCnextModel) { + for (here = model->ASRCinstances; here != NULL; + here = here->ASRCnextInstance) { + if(here->ASRCname == name) { + if(here->ASRCbranch == 0) { + error = CKTmkCur(ckt,&tmp, here->ASRCname,"branch"); + if(error) return(error); + here->ASRCbranch = tmp->number; + } + return(here->ASRCbranch); + } + } + } + return(0); +} diff --git a/src/spicelib/devices/asrc/asrcitf.h b/src/spicelib/devices/asrc/asrcitf.h new file mode 100644 index 000000000..fa64272b1 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcitf.h @@ -0,0 +1,80 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_asrc + +#ifndef DEV_ASRC +#define DEV_ASRC + +#include "asrcext.h" +extern IFparm ASRCpTable[ ]; +extern char *ASRCnames[ ]; +extern int ASRCpTSize; +extern int ASRCnSize; +extern int ASRCiSize; +extern int ASRCmSize; + +SPICEdev ASRCinfo = { + { + "ASRC", + "Arbitrary Source ", + + &ASRCnSize, + &ASRCnSize, + ASRCnames, + + &ASRCpTSize, + ASRCpTable, + + 0, + NULL, + DEV_DEFAULT + }, + + ASRCparam, + NULL, + ASRCload, + ASRCsetup, + ASRCunsetup, + ASRCsetup, + NULL, + NULL, + ASRCfindBr, + ASRCacLoad, /* ac and normal load functions NOT identical */ + NULL, + ASRCdestroy, +#ifdef DELETES + ASRCmDelete, + ASRCdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + NULL, + NULL, +#ifdef AN_pz + ASRCpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + ASRCconvTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* DISTO */ + NULL, /* NOISE */ + + &ASRCiSize, + &ASRCmSize +}; + +#endif +#endif diff --git a/src/spicelib/devices/asrc/asrcload.c b/src/spicelib/devices/asrc/asrcload.c new file mode 100644 index 000000000..04717c527 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcload.c @@ -0,0 +1,178 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + +double *asrc_vals, *asrc_derivs; +int asrc_nvals; + +/*ARGSUSED*/ +int +ASRCload(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + + /* actually load the current voltage value into the + * sparse matrix previously provided + */ + + register ASRCmodel *model = (ASRCmodel*)inModel; + register ASRCinstance *here; + int i, v_first, j, branch; + int node_num; + int size; + double rhs; + + /* loop through all the Arbitrary source models */ + for( ; model != NULL; model = model->ASRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ASRCinstances; here != NULL ; + here=here->ASRCnextInstance) + { + if (here->ASRCowner != ARCHme) continue; + + /* + * Get the function and its derivatives evaluated + */ + v_first = 1; + i = here->ASRCtree->numVars; + if (asrc_nvals < i) { + if (asrc_nvals) { + FREE(asrc_vals); + FREE(asrc_derivs); + } + asrc_nvals = i; + asrc_vals = NEWN(double, i); + asrc_derivs = NEWN(double, i); + } + + j=0; + + /* + * Fill the vector of values from the previous solution + */ + for( i=0; i < here->ASRCtree->numVars; i++){ + if( here->ASRCtree->varTypes[i] == IF_INSTANCE){ + branch = CKTfndBranch(ckt, + here->ASRCtree->vars[i].uValue); + asrc_vals[i] = *(ckt->CKTrhsOld+branch); + } else { + node_num = ((CKTnode *)(here->ASRCtree->vars[i]. + nValue))->number; + asrc_vals[i] = *(ckt->CKTrhsOld+node_num); + } + } + + if ((*(here->ASRCtree->IFeval))(here->ASRCtree,ckt->CKTgmin, &rhs, + asrc_vals,asrc_derivs) == OK) + { + + /* The convergence test */ + + if ( (ckt->CKTmode & MODEINITFIX) || + (ckt->CKTmode & MODEINITFLOAT) ) + { +#ifndef NEWCONV + prev = here->ASRCprev_value; + diff = fabs( prev - rhs); + if ( here->ASRCtype == ASRC_VOLTAGE) { + tol = ckt->CKTreltol * + MAX(fabs(rhs),fabs(prev)) + ckt->CKTvoltTol; + } else { + tol = ckt->CKTreltol * + MAX(fabs(rhs),fabs(prev)) + ckt->CKTabstol; + } + + if ( diff > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } +#endif /* NEWCONV */ + } + here->ASRCprev_value = rhs; + + /* The ac load precomputation and storage */ + + if (ckt->CKTmode & MODEINITSMSIG) { + size = (here->ASRCtree->numVars)+1 ; + here->ASRCacValues = NEWN(double, size); + for ( i = 0; i < here->ASRCtree->numVars; i++){ + here->ASRCacValues[i] = asrc_derivs[i]; + } + } + + for(i=0; i < here->ASRCtree->numVars; i++) { + rhs -= (asrc_vals[i] * asrc_derivs[i]); + switch(here->ASRCtree->varTypes[i]){ + case IF_INSTANCE: + if( here->ASRCtype == ASRC_VOLTAGE){ + /* CCVS */ + if(v_first){ + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) += 1.0; + v_first = 0; + } + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } else{ + /* CCCS */ + *(here->ASRCposptr[j++]) += asrc_derivs[i]; + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } + break; + + case IF_NODE: + if(here->ASRCtype == ASRC_VOLTAGE) { + /* VCVS */ + if( v_first){ + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) += 1.0; + v_first = 0; + } + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } else { + /*VCCS*/ + *(here->ASRCposptr[j++]) += asrc_derivs[i]; + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } + break; + + default: + return(E_BADPARM); + } + } + + /* Insert the RHS */ + if( here->ASRCtype == ASRC_VOLTAGE){ + *(ckt->CKTrhs+(here->ASRCbranch)) += rhs; + } else { + *(ckt->CKTrhs+(here->ASRCposNode)) -= rhs; + *(ckt->CKTrhs+(here->ASRCnegNode)) += rhs; + } + + /* Store the rhs for small signal analysis */ + if (ckt->CKTmode & MODEINITSMSIG){ + here->ASRCacValues[here->ASRCtree->numVars] = rhs; + } + } else{ + return(E_BADPARM); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/asrc/asrcmdel.c b/src/spicelib/devices/asrc/asrcmdel.c new file mode 100644 index 000000000..20d6825f4 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcmdel.c @@ -0,0 +1,48 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +#include "ngspice.h" +#include +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +ASRCmDelete(modList,modname,killModel) + GENmodel **modList; + IFuid modname; + GENmodel *killModel; + +{ + + register ASRCmodel **model = (ASRCmodel**)modList; + register ASRCmodel *modfast = (ASRCmodel*)killModel; + register ASRCinstance *here; + register ASRCinstance *prev = NULL; + register ASRCmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->ASRCnextModel)) { + if( (*model)->ASRCmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->ASRCnextModel; /* cut deleted device out of list */ + for(here = (*model)->ASRCinstances ; here ; here = here->ASRCnextInstance) { + FREE(here->ASRCacValues); + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/asrc/asrcpar.c b/src/spicelib/devices/asrc/asrcpar.c new file mode 100644 index 000000000..76df8202e --- /dev/null +++ b/src/spicelib/devices/asrc/asrcpar.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +ASRCparam(param,value,fast,select) + int param; + IFvalue *value; + GENinstance *fast; + IFvalue *select; +{ + register ASRCinstance *here = (ASRCinstance*)fast; + switch(param) { + case ASRC_VOLTAGE: + here->ASRCtype = ASRC_VOLTAGE; + here->ASRCtree = value->tValue; + break; + case ASRC_CURRENT: + here->ASRCtype = ASRC_CURRENT; + here->ASRCtree = value->tValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/asrc/asrcpzld.c b/src/spicelib/devices/asrc/asrcpzld.c new file mode 100644 index 000000000..f9c5b1fec --- /dev/null +++ b/src/spicelib/devices/asrc/asrcpzld.c @@ -0,0 +1,118 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" +#include "complex.h" + +/*ARGSUSED*/ +int +ASRCpzLoad(inModel,ckt,s) + + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; + + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register ASRCmodel *model = (ASRCmodel*)inModel; + register ASRCinstance *here; + double value; + int i, v_first, j, branch; + int node_num; + + /* loop through all the Arbitrary source models */ + for( ; model != NULL; model = model->ASRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ASRCinstances; here != NULL ; + here=here->ASRCnextInstance) + { + if (here->ASRCowner != ARCHme) continue; + j = 0; + /* Get the function evaluated and the derivatives too */ + v_first = 1; + i = here->ASRCtree->numVars; + if (asrc_nvals < i) { + if (asrc_nvals) { + FREE(asrc_vals); + FREE(asrc_derivs); + } + asrc_nvals = i; + asrc_vals = NEWN(double, i); + asrc_derivs = NEWN(double, i); + } + + /* Fill the vector of values from the previous solution */ + for( i=0; i < here->ASRCtree->numVars; i++){ + if( here->ASRCtree->varTypes[i] == IF_INSTANCE){ + branch = CKTfndBranch(ckt,here->ASRCtree->vars[i].uValue); + asrc_vals[i] = *(ckt->CKTrhsOld+branch); + } else { + node_num = ((CKTnode *)(here->ASRCtree->vars[i].nValue))-> + number; + asrc_vals[i] = *(ckt->CKTrhsOld+node_num); + } + } + + if( (*(here->ASRCtree->IFeval))(here->ASRCtree, ckt->CKTgmin, + &value, asrc_vals, asrc_derivs) == OK){ + for(i=0; i < here->ASRCtree->numVars; i++){ + switch(here->ASRCtree->varTypes[i]){ + case IF_INSTANCE: + if( here->ASRCtype == ASRC_VOLTAGE){ + /* CCVS */ + if(v_first){ + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + v_first = 0; + } else { + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } + } else { + /* CCCS */ + *(here->ASRCposptr[j++]) += asrc_derivs[i]; + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } + break; + case IF_NODE: + if(here->ASRCtype == ASRC_VOLTAGE){ + /* VCVS */ + if( v_first){ + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) -= 1.0; + *(here->ASRCposptr[j++]) += 1.0; + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + v_first = 0; + } else { + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } + } else { + /* VCCS */ + *(here->ASRCposptr[j++]) += asrc_derivs[i]; + *(here->ASRCposptr[j++]) -= asrc_derivs[i]; + } + break; + default: + return(E_BADPARM); + } + } + } else { + return(E_BADPARM); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/asrc/asrcset.c b/src/spicelib/devices/asrc/asrcset.c new file mode 100644 index 000000000..10708d3c4 --- /dev/null +++ b/src/spicelib/devices/asrc/asrcset.c @@ -0,0 +1,168 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Kanwar Jit Singh +**********/ +/* + * singh@ic.Berkeley.edu + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "asrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +ASRCsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; + /* load the voltage source structure with those + * pointers needed later for fast matrix loading + */ + +{ + register ASRCinstance *here; + register ASRCmodel *model = (ASRCmodel*)inModel; + int error, i, j; + int v_first; + CKTnode *tmp; + + /* loop through all the user models*/ + for( ; model != NULL; model = model->ASRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ASRCinstances; here != NULL ; + here=here->ASRCnextInstance) { + + here->ASRCposptr = (double **)MALLOC(0); + j=0; /*strchr of the array holding ptrs to SMP */ + v_first = 1; + if( here->ASRCtype == ASRC_VOLTAGE){ + if(here->ASRCbranch==0) { + error = CKTmkCur(ckt,&tmp,here->ASRCname,"branch"); + if(error) return(error); + here->ASRCbranch = tmp->number; + } + } + + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + +#define MY_TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,((CKTnode*)(second))->number))\ + ==(double *)NULL){\ + return(E_NOMEM);\ +} + + /* For each controlling variable set the entries + in the vector of the positions of the SMP */ + if (!here->ASRCtree) + return E_PARMVAL; + for( i=0; i < here->ASRCtree->numVars; i++){ + switch(here->ASRCtree->varTypes[i]){ + case IF_INSTANCE: + here->ASRCcont_br = CKTfndBranch(ckt, + here->ASRCtree->vars[i].uValue); + if(here->ASRCcont_br == 0) { + IFuid namarray[2]; + namarray[0] = here->ASRCname; + namarray[1] = here->ASRCtree->vars[i].uValue; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: unknown controlling source %s",namarray); + return(E_BADPARM); + } + if( here->ASRCtype == ASRC_VOLTAGE){ + /* CCVS */ + if(v_first){ + here->ASRCposptr = (double **) + REALLOC(here->ASRCposptr, (sizeof(double *)*(j+5))); + TSTALLOC(ASRCposptr[j++],ASRCposNode,ASRCbranch); + TSTALLOC(ASRCposptr[j++],ASRCnegNode,ASRCbranch); + TSTALLOC(ASRCposptr[j++],ASRCbranch,ASRCnegNode); + TSTALLOC(ASRCposptr[j++],ASRCbranch,ASRCposNode); + TSTALLOC(ASRCposptr[j++],ASRCbranch,ASRCcont_br); + v_first = 0; + } else{ + here->ASRCposptr = (double **) + REALLOC(here->ASRCposptr, (sizeof(double *)*(j+1))); + TSTALLOC(ASRCposptr[j++],ASRCbranch,ASRCcont_br); + } + } else if(here->ASRCtype == ASRC_CURRENT){ + /* CCCS */ + here->ASRCposptr = (double **) + REALLOC(here->ASRCposptr, (sizeof(double *) * (j+2))); + TSTALLOC(ASRCposptr[j++],ASRCposNode,ASRCcont_br); + TSTALLOC(ASRCposptr[j++],ASRCnegNode,ASRCcont_br); + } else{ + return (E_BADPARM); + } + break; + case IF_NODE: + if( here->ASRCtype == ASRC_VOLTAGE){ + /* VCVS */ + if(v_first){ + here->ASRCposptr = (double **) + REALLOC(here->ASRCposptr, (sizeof(double *) * (j+5))); + TSTALLOC(ASRCposptr[j++],ASRCposNode,ASRCbranch); + TSTALLOC(ASRCposptr[j++],ASRCnegNode,ASRCbranch); + TSTALLOC(ASRCposptr[j++],ASRCbranch,ASRCnegNode); + TSTALLOC(ASRCposptr[j++],ASRCbranch,ASRCposNode); + MY_TSTALLOC(ASRCposptr[j++],ASRCbranch,here->ASRCtree->vars[i].nValue); + v_first = 0; + } else{ + here->ASRCposptr = (double **) + REALLOC(here->ASRCposptr, (sizeof(double *) * (j+1))); + MY_TSTALLOC(ASRCposptr[j++],ASRCbranch,here->ASRCtree->vars[i].nValue); + } + } else if(here->ASRCtype == ASRC_CURRENT){ + /* VCCS */ + here->ASRCposptr = (double **) + REALLOC(here->ASRCposptr, (sizeof(double *) * (j+2))); + MY_TSTALLOC(ASRCposptr[j++],ASRCposNode,here->ASRCtree->vars[i].nValue); + MY_TSTALLOC(ASRCposptr[j++],ASRCnegNode,here->ASRCtree->vars[i].nValue); + } else{ + return (E_BADPARM); + } + break; + default: + break; + } + } + } + } + return(OK); +} + +int +ASRCunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + ASRCmodel *model; + ASRCinstance *here; + + for (model = (ASRCmodel *)inModel; model != NULL; + model = model->ASRCnextModel) + { + for (here = model->ASRCinstances; here != NULL; + here=here->ASRCnextInstance) + { + if (here->ASRCbranch) { + CKTdltNNum(ckt, here->ASRCbranch); + here->ASRCbranch = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/bjt/ChangeLog b/src/spicelib/devices/bjt/ChangeLog new file mode 100644 index 000000000..bc1d9061c --- /dev/null +++ b/src/spicelib/devices/bjt/ChangeLog @@ -0,0 +1,8 @@ +1999-09-07 Arno + + * bjtnoise.c: removed unused variable `error'. + +1999-09-06 Arno Peters + + * bjtnoise.c: Reformatted comment. + diff --git a/src/spicelib/devices/bjt/Makefile.am b/src/spicelib/devices/bjt/Makefile.am new file mode 100644 index 000000000..0cefc40f7 --- /dev/null +++ b/src/spicelib/devices/bjt/Makefile.am @@ -0,0 +1,39 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libbjt.la + +libbjt_la_SOURCES = \ + bjt.c \ + bjtacld.c \ + bjtask.c \ + bjtconv.c \ + bjtdefs.h \ + bjtdel.c \ + bjtdest.c \ + bjtdisto.c \ + bjtdset.c \ + bjtdset.h \ + bjtext.h \ + bjtgetic.c \ + bjtitf.h \ + bjtload.c \ + bjtmask.c \ + bjtmdel.c \ + bjtmpar.c \ + bjtnoise.c \ + bjtparam.c \ + bjtpzld.c \ + bjtsacl.c \ + bjtsetup.c \ + bjtsload.c \ + bjtsprt.c \ + bjtsset.c \ + bjtsupd.c \ + bjttemp.c \ + bjttrunc.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/bjt/bjt.c b/src/spicelib/devices/bjt/bjt.c new file mode 100644 index 000000000..4153a6317 --- /dev/null +++ b/src/spicelib/devices/bjt/bjt.c @@ -0,0 +1,154 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * This file defines the BJT data structures that are + * available to the next level(s) up the calling hierarchy + */ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "bjtdefs.h" +#include "suffix.h" + +IFparm BJTpTable[] = { /* parameters */ + IOPU("off", BJT_OFF, IF_FLAG, "Device initially off"), + IOPAU("icvbe", BJT_IC_VBE, IF_REAL, "Initial B-E voltage"), + IOPAU("icvce", BJT_IC_VCE, IF_REAL, "Initial C-E voltage"), + IOPU("area", BJT_AREA, IF_REAL, "Area factor"), + IP("ic", BJT_IC, IF_REALVEC, "Initial condition vector"), + IP("sens_area",BJT_AREA_SENS,IF_FLAG, "flag to request sensitivity WRT area"), + OPU("colnode", BJT_QUEST_COLNODE, IF_INTEGER, "Number of collector node"), + OPU("basenode", BJT_QUEST_BASENODE, IF_INTEGER, "Number of base node"), + OPU("emitnode", BJT_QUEST_EMITNODE, IF_INTEGER, "Number of emitter node"), + OPU("substnode",BJT_QUEST_SUBSTNODE,IF_INTEGER, "Number of substrate node"), + OPU("colprimenode",BJT_QUEST_COLPRIMENODE,IF_INTEGER, + "Internal collector node"), + OPU("baseprimenode",BJT_QUEST_BASEPRIMENODE,IF_INTEGER,"Internal base node"), + OPU("emitprimenode",BJT_QUEST_EMITPRIMENODE,IF_INTEGER, + "Internal emitter node"), + OP("ic", BJT_QUEST_CC, IF_REAL, "Current at collector node"), + OP("ib", BJT_QUEST_CB, IF_REAL, "Current at base node"), + OP("ie", BJT_QUEST_CE, IF_REAL, "Emitter current"), + OPU("is", BJT_QUEST_CS, IF_REAL, "Substrate current"), + OP("vbe", BJT_QUEST_VBE, IF_REAL, "B-E voltage"), + OP("vbc", BJT_QUEST_VBC, IF_REAL, "B-C voltage"), + OP("gm", BJT_QUEST_GM, IF_REAL, "Small signal transconductance"), + OP("gpi", BJT_QUEST_GPI, IF_REAL, "Small signal input conductance - pi"), + OP("gmu", BJT_QUEST_GMU, IF_REAL, "Small signal conductance - mu"), + OP("gx", BJT_QUEST_GX, IF_REAL, "Conductance from base to internal base"), + OP("go", BJT_QUEST_GO, IF_REAL, "Small signal output conductance"), + OPU("geqcb",BJT_QUEST_GEQCB,IF_REAL, "d(Ibe)/d(Vbc)"), + OPU("gccs", BJT_QUEST_GCCS, IF_REAL, "Internal C-S cap. equiv. cond."), + OPU("geqbx",BJT_QUEST_GEQBX,IF_REAL, "Internal C-B-base cap. equiv. cond."), + + OP("cpi",BJT_QUEST_CPI, IF_REAL, "Internal base to emitter capactance"), + OP("cmu",BJT_QUEST_CMU, IF_REAL, "Internal base to collector capactiance"), + OP("cbx",BJT_QUEST_CBX, IF_REAL, "Base to collector capacitance"), + OP("ccs",BJT_QUEST_CCS, IF_REAL, "Collector to substrate capacitance"), + + OPU("cqbe",BJT_QUEST_CQBE, IF_REAL, "Cap. due to charge storage in B-E jct."), + OPU("cqbc",BJT_QUEST_CQBC, IF_REAL, "Cap. due to charge storage in B-C jct."), + OPU("cqcs", BJT_QUEST_CQCS, IF_REAL, "Cap. due to charge storage in C-S jct."), + OPU("cqbx", BJT_QUEST_CQBX, IF_REAL, "Cap. due to charge storage in B-X jct."), + OPU("cexbc",BJT_QUEST_CEXBC,IF_REAL, "Total Capacitance in B-X junction"), + + OPU("qbe", BJT_QUEST_QBE, IF_REAL, "Charge storage B-E junction"), + OPU("qbc", BJT_QUEST_QBC, IF_REAL, "Charge storage B-C junction"), + OPU("qcs", BJT_QUEST_QCS, IF_REAL, "Charge storage C-S junction"), + OPU("qbx", BJT_QUEST_QBX, IF_REAL, "Charge storage B-X junction"), + OPU("p", BJT_QUEST_POWER,IF_REAL, "Power dissipation"), + OPU("sens_dc", BJT_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU("sens_real", BJT_QUEST_SENS_REAL, IF_REAL,"real part of ac sensitivity"), + OPU("sens_imag",BJT_QUEST_SENS_IMAG,IF_REAL, + "dc sens. & imag part of ac sens."), + OPU("sens_mag", BJT_QUEST_SENS_MAG, IF_REAL, "sensitivity of ac magnitude"), + OPU("sens_ph", BJT_QUEST_SENS_PH, IF_REAL, "sensitivity of ac phase"), + OPU("sens_cplx", BJT_QUEST_SENS_CPLX, IF_COMPLEX, "ac sensitivity"), + IOPU("temp", BJT_TEMP, IF_REAL, "instance temperature") +}; + +IFparm BJTmPTable[] = { /* model parameters */ + OP("type", BJT_MOD_TYPE, IF_STRING, "NPN or PNP"), + IOPU("npn", BJT_MOD_NPN, IF_FLAG, "NPN type device"), + IOPU("pnp", BJT_MOD_PNP, IF_FLAG, "PNP type device"), + IOP("is", BJT_MOD_IS, IF_REAL, "Saturation Current"), + IOP("bf", BJT_MOD_BF, IF_REAL, "Ideal forward beta"), + IOP("nf", BJT_MOD_NF, IF_REAL, "Forward emission coefficient"), + IOP("vaf", BJT_MOD_VAF, IF_REAL, "Forward Early voltage"), + IOPR("va", BJT_MOD_VAF, IF_REAL, "Forward Early voltage"), + IOP("ikf", BJT_MOD_IKF, IF_REAL, "Forward beta roll-off corner current"), + IOPR("ik", BJT_MOD_IKF, IF_REAL, "Forward beta roll-off corner current"), + IOP("ise", BJT_MOD_ISE, IF_REAL, "B-E leakage saturation current"), + /*IOP("c2", BJT_MOD_C2, IF_REAL, "Obsolete parameter name"),*/ + IOP("ne", BJT_MOD_NE, IF_REAL, "B-E leakage emission coefficient"), + IOP("br", BJT_MOD_BR, IF_REAL, "Ideal reverse beta"), + IOP("nr", BJT_MOD_NR, IF_REAL, "Reverse emission coefficient"), + IOP("var", BJT_MOD_VAR, IF_REAL, "Reverse Early voltage"), + IOPR("vb", BJT_MOD_VAR, IF_REAL, "Reverse Early voltage"), + IOP("ikr", BJT_MOD_IKR, IF_REAL, "reverse beta roll-off corner current"), + IOP("isc", BJT_MOD_ISC, IF_REAL, "B-C leakage saturation current"), + /*IOP("c4", BJT_MOD_C4, IF_REAL, "Obsolete parameter name"),*/ + IOP("nc", BJT_MOD_NC, IF_REAL, "B-C leakage emission coefficient"), + IOP("rb", BJT_MOD_RB, IF_REAL, "Zero bias base resistance"), + IOP("irb", BJT_MOD_IRB, IF_REAL, "Current for base resistance=(rb+rbm)/2"), + IOP("rbm", BJT_MOD_RBM, IF_REAL, "Minimum base resistance"), + IOP("re", BJT_MOD_RE, IF_REAL, "Emitter resistance"), + IOP("rc", BJT_MOD_RC, IF_REAL, "Collector resistance"), + IOPA("cje", BJT_MOD_CJE, IF_REAL,"Zero bias B-E depletion capacitance"), + IOPA("vje", BJT_MOD_VJE, IF_REAL, "B-E built in potential"), + IOPR("pe", BJT_MOD_VJE, IF_REAL, "B-E built in potential"), + IOPA("mje", BJT_MOD_MJE, IF_REAL, "B-E junction grading coefficient"), + IOPR("me", BJT_MOD_MJE, IF_REAL, "B-E junction grading coefficient"), + IOPA("tf", BJT_MOD_TF, IF_REAL, "Ideal forward transit time"), + IOPA("xtf", BJT_MOD_XTF, IF_REAL, "Coefficient for bias dependence of TF"), + IOPA("vtf", BJT_MOD_VTF, IF_REAL, "Voltage giving VBC dependence of TF"), + IOPA("itf", BJT_MOD_ITF, IF_REAL, "High current dependence of TF"), + IOPA("ptf", BJT_MOD_PTF, IF_REAL, "Excess phase"), + IOPA("cjc", BJT_MOD_CJC, IF_REAL, "Zero bias B-C depletion capacitance"), + IOPA("vjc", BJT_MOD_VJC, IF_REAL, "B-C built in potential"), + IOPR("pc", BJT_MOD_VJC, IF_REAL, "B-C built in potential"), + IOPA("mjc", BJT_MOD_MJC, IF_REAL, "B-C junction grading coefficient"), + IOPR("mc", BJT_MOD_MJC, IF_REAL, "B-C junction grading coefficient"), + IOPA("xcjc",BJT_MOD_XCJC, IF_REAL, "Fraction of B-C cap to internal base"), + IOPA("tr", BJT_MOD_TR, IF_REAL, "Ideal reverse transit time"), + IOPA("cjs", BJT_MOD_CJS, IF_REAL, "Zero bias C-S capacitance"), + IOPA("ccs", BJT_MOD_CJS, IF_REAL, "Zero bias C-S capacitance"), + IOPA("vjs", BJT_MOD_VJS, IF_REAL, "Substrate junction built in potential"), + IOPR("ps", BJT_MOD_VJS, IF_REAL, "Substrate junction built in potential"), + IOPA("mjs", BJT_MOD_MJS, IF_REAL, "Substrate junction grading coefficient"), + IOPR("ms", BJT_MOD_MJS, IF_REAL, "Substrate junction grading coefficient"), + IOP("xtb", BJT_MOD_XTB, IF_REAL, "Forward and reverse beta temp. exp."), + IOP("eg", BJT_MOD_EG, IF_REAL, "Energy gap for IS temp. dependency"), + IOP("xti", BJT_MOD_XTI, IF_REAL, "Temp. exponent for IS"), + IOP("fc", BJT_MOD_FC, IF_REAL, "Forward bias junction fit parameter"), + OPU("invearlyvoltf",BJT_MOD_INVEARLYF,IF_REAL,"Inverse early voltage:forward"), + OPU("invearlyvoltr",BJT_MOD_INVEARLYR,IF_REAL,"Inverse early voltage:reverse"), + OPU("invrollofff",BJT_MOD_INVROLLOFFF, IF_REAL,"Inverse roll off - forward"), + OPU("invrolloffr",BJT_MOD_INVROLLOFFR, IF_REAL,"Inverse roll off - reverse"), + OPU("collectorconduct",BJT_MOD_COLCONDUCT,IF_REAL,"Collector conductance"), + OPU("emitterconduct", BJT_MOD_EMITTERCONDUCT,IF_REAL, "Emitter conductance"), + OPU("transtimevbcfact",BJT_MOD_TRANSVBCFACT,IF_REAL,"Transit time VBC factor"), + OPU("excessphasefactor",BJT_MOD_EXCESSPHASEFACTOR,IF_REAL, + "Excess phase fact."), + IOP("tnom", BJT_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), + IOP("kf", BJT_MOD_KF, IF_REAL, "Flicker Noise Coefficient"), + IOP("af",BJT_MOD_AF, IF_REAL,"Flicker Noise Exponent") +}; + +char *BJTnames[] = { + "collector", + "base", + "emitter", + "substrate" +}; + + +int BJTnSize = NUMELEMS(BJTnames); +int BJTpTSize = NUMELEMS(BJTpTable); +int BJTmPTSize = NUMELEMS(BJTmPTable); +int BJTiSize = sizeof(BJTinstance); +int BJTmSize = sizeof(BJTmodel); diff --git a/src/spicelib/devices/bjt/bjtacld.c b/src/spicelib/devices/bjt/bjtacld.c new file mode 100644 index 000000000..2f1b45b8b --- /dev/null +++ b/src/spicelib/devices/bjt/bjtacld.c @@ -0,0 +1,104 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * Function to load the COMPLEX circuit matrix using the + * small signal parameters saved during a previous DC operating + * point analysis. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +BJTacLoad(inModel,ckt) + register GENmodel *inModel; + CKTcircuit *ckt; + +{ + register BJTinstance *here; + register BJTmodel *model = (BJTmodel*)inModel; + double gcpr; + double gepr; + double gpi; + double gmu; + double go; + double xgm; + double td; + double arg; + double gm; + double gx; + double xcpi; + double xcmu; + double xcbx; + double xccs; + double xcmcb; + + for( ; model != NULL; model = model->BJTnextModel) { + for( here = model->BJTinstances; here!= NULL; + here = here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + gcpr=model->BJTcollectorConduct * here->BJTarea; + gepr=model->BJTemitterConduct * here->BJTarea; + gpi= *(ckt->CKTstate0 + here->BJTgpi); + gmu= *(ckt->CKTstate0 + here->BJTgmu); + gm= *(ckt->CKTstate0 + here->BJTgm); + go= *(ckt->CKTstate0 + here->BJTgo); + xgm=0; + td=model->BJTexcessPhaseFactor; + if(td != 0) { + arg = td*ckt->CKTomega; + gm = gm+go; + xgm = -gm * sin(arg); + gm = gm * cos(arg)-go; + } + gx= *(ckt->CKTstate0 + here->BJTgx); + xcpi= *(ckt->CKTstate0 + here->BJTcqbe) * ckt->CKTomega; + xcmu= *(ckt->CKTstate0 + here->BJTcqbc) * ckt->CKTomega; + xcbx= *(ckt->CKTstate0 + here->BJTcqbx) * ckt->CKTomega; + xccs= *(ckt->CKTstate0 + here->BJTcqcs) * ckt->CKTomega; + xcmcb= *(ckt->CKTstate0 + here->BJTcexbc) * ckt->CKTomega; + *(here->BJTcolColPtr) += (gcpr); + *(here->BJTbaseBasePtr) += (gx); + *(here->BJTbaseBasePtr + 1) += (xcbx); + *(here->BJTemitEmitPtr) += (gepr); + *(here->BJTcolPrimeColPrimePtr) += (gmu+go+gcpr); + *(here->BJTcolPrimeColPrimePtr + 1) += (xcmu+xccs+xcbx); + *(here->BJTbasePrimeBasePrimePtr) += (gx+gpi+gmu); + *(here->BJTbasePrimeBasePrimePtr + 1) += (xcpi+xcmu+xcmcb); + *(here->BJTemitPrimeEmitPrimePtr) += (gpi+gepr+gm+go); + *(here->BJTemitPrimeEmitPrimePtr + 1) += (xcpi+xgm); + *(here->BJTcolColPrimePtr) += (-gcpr); + *(here->BJTbaseBasePrimePtr) += (-gx); + *(here->BJTemitEmitPrimePtr) += (-gepr); + *(here->BJTcolPrimeColPtr) += (-gcpr); + *(here->BJTcolPrimeBasePrimePtr) += (-gmu+gm); + *(here->BJTcolPrimeBasePrimePtr + 1) += (-xcmu+xgm); + *(here->BJTcolPrimeEmitPrimePtr) += (-gm-go); + *(here->BJTcolPrimeEmitPrimePtr + 1) += (-xgm); + *(here->BJTbasePrimeBasePtr) += (-gx); + *(here->BJTbasePrimeColPrimePtr) += (-gmu); + *(here->BJTbasePrimeColPrimePtr + 1) += (-xcmu-xcmcb); + *(here->BJTbasePrimeEmitPrimePtr) += (-gpi); + *(here->BJTbasePrimeEmitPrimePtr + 1) += (-xcpi); + *(here->BJTemitPrimeEmitPtr) += (-gepr); + *(here->BJTemitPrimeColPrimePtr) += (-go); + *(here->BJTemitPrimeColPrimePtr + 1) += (xcmcb); + *(here->BJTemitPrimeBasePrimePtr) += (-gpi-gm); + *(here->BJTemitPrimeBasePrimePtr + 1) += (-xcpi-xgm-xcmcb); + *(here->BJTsubstSubstPtr + 1) += (xccs); + *(here->BJTcolPrimeSubstPtr + 1) += (-xccs); + *(here->BJTsubstColPrimePtr + 1) += (-xccs); + *(here->BJTbaseColPrimePtr + 1) += (-xcbx); + *(here->BJTcolPrimeBasePtr + 1) += (-xcbx); + } + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtask.c b/src/spicelib/devices/bjt/bjtask.c new file mode 100644 index 000000000..7015732a4 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtask.c @@ -0,0 +1,277 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Mathew Lew and Thomas L. Quarles +**********/ + +/* + * This routine gives access to the internal device + * parameters for BJTs + */ + +#include "ngspice.h" +#include "const.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +BJTask(ckt,instPtr,which,value,select) + CKTcircuit *ckt; + GENinstance *instPtr; + int which; + IFvalue *value; + IFvalue *select; +{ + BJTinstance *here = (BJTinstance*)instPtr; + double tmp; + int itmp; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case BJT_QUEST_FT: + tmp = MAX(*(ckt->CKTstate0 + here->BJTcqbc), + *(ckt->CKTstate0 + here->BJTcqbx)); + value->rValue = here->BJTgm/(2 * M_PI * + MAX(*(ckt->CKTstate0 + here->BJTcqbe),tmp)); + return(OK); + case BJT_TEMP: + value->rValue = here->BJTtemp - CONSTCtoK; + return(OK); + case BJT_AREA: + value->rValue = here->BJTarea; + return(OK); + case BJT_OFF: + value->iValue = here->BJToff; + return(OK); + case BJT_IC_VBE: + value->rValue = here->BJTicVBE; + return(OK); + case BJT_IC_VCE: + value->rValue = here->BJTicVCE; + return(OK); + case BJT_QUEST_COLNODE: + value->iValue = here->BJTcolNode; + return(OK); + case BJT_QUEST_BASENODE: + value->iValue = here->BJTbaseNode; + return(OK); + case BJT_QUEST_EMITNODE: + value->iValue = here->BJTemitNode; + return(OK); + case BJT_QUEST_SUBSTNODE: + value->iValue = here->BJTsubstNode; + return(OK); + case BJT_QUEST_COLPRIMENODE: + value->iValue = here->BJTcolPrimeNode; + return(OK); + case BJT_QUEST_BASEPRIMENODE: + value->iValue = here->BJTbasePrimeNode; + return(OK); + case BJT_QUEST_EMITPRIMENODE: + value->iValue = here->BJTemitPrimeNode; + return(OK); + case BJT_QUEST_VBE: + value->rValue = *(ckt->CKTstate0 + here->BJTvbe); + return(OK); + case BJT_QUEST_VBC: + value->rValue = *(ckt->CKTstate0 + here->BJTvbc); + return(OK); + case BJT_QUEST_CC: + value->rValue = *(ckt->CKTstate0 + here->BJTcc); + return(OK); + case BJT_QUEST_CB: + value->rValue = *(ckt->CKTstate0 + here->BJTcb); + return(OK); + case BJT_QUEST_GPI: + value->rValue = *(ckt->CKTstate0 + here->BJTgpi); + return(OK); + case BJT_QUEST_GMU: + value->rValue = *(ckt->CKTstate0 + here->BJTgmu); + return(OK); + case BJT_QUEST_GM: + value->rValue = *(ckt->CKTstate0 + here->BJTgm); + return(OK); + case BJT_QUEST_GO: + value->rValue = *(ckt->CKTstate0 + here->BJTgo); + return(OK); + case BJT_QUEST_QBE: + value->rValue = *(ckt->CKTstate0 + here->BJTqbe); + return(OK); + case BJT_QUEST_CQBE: + value->rValue = *(ckt->CKTstate0 + here->BJTcqbe); + return(OK); + case BJT_QUEST_QBC: + value->rValue = *(ckt->CKTstate0 + here->BJTqbc); + return(OK); + case BJT_QUEST_CQBC: + value->rValue = *(ckt->CKTstate0 + here->BJTcqbc); + return(OK); + case BJT_QUEST_QCS: + value->rValue = *(ckt->CKTstate0 + here->BJTqcs); + return(OK); + case BJT_QUEST_CQCS: + value->rValue = *(ckt->CKTstate0 + here->BJTcqcs); + return(OK); + case BJT_QUEST_QBX: + value->rValue = *(ckt->CKTstate0 + here->BJTqbx); + return(OK); + case BJT_QUEST_CQBX: + value->rValue = *(ckt->CKTstate0 + here->BJTcqbx); + return(OK); + case BJT_QUEST_GX: + value->rValue = *(ckt->CKTstate0 + here->BJTgx); + return(OK); + case BJT_QUEST_CEXBC: + value->rValue = *(ckt->CKTstate0 + here->BJTcexbc); + return(OK); + case BJT_QUEST_GEQCB: + value->rValue = *(ckt->CKTstate0 + here->BJTgeqcb); + return(OK); + case BJT_QUEST_GCCS: + value->rValue = *(ckt->CKTstate0 + here->BJTgccs); + return(OK); + case BJT_QUEST_GEQBX: + value->rValue = *(ckt->CKTstate0 + here->BJTgeqbx); + return(OK); + case BJT_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->BJTsenParmNo); + } + return(OK); + case BJT_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->BJTsenParmNo); + } + return(OK); + case BJT_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->BJTsenParmNo); + } + return(OK); + case BJT_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->BJTsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->BJTsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case BJT_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->BJTsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->BJTsenParmNo); + + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case BJT_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + itmp = select->iValue + 1; + value->cValue.real= *(ckt->CKTsenInfo->SEN_RHS[itmp]+ + here->BJTsenParmNo); + value->cValue.imag= *(ckt->CKTsenInfo->SEN_iRHS[itmp]+ + here->BJTsenParmNo); + } + return(OK); + case BJT_QUEST_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "BJTask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { + value->rValue = 0; + } else if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + (ckt->CKTmode & MODETRANOP)) { + value->rValue = 0; + } else { + value->rValue = -*(ckt->CKTstate0 + here->BJTcqcs); + } + return(OK); + case BJT_QUEST_CE : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "BJTask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -*(ckt->CKTstate0 + here->BJTcc); + value->rValue -= *(ckt->CKTstate0 + here->BJTcb); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue += *(ckt->CKTstate0 + here->BJTcqcs); + } + } + return(OK); + case BJT_QUEST_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "BJTask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTstate0 + here->BJTcc) * + *(ckt->CKTrhsOld + here->BJTcolNode); + value->rValue += *(ckt->CKTstate0 + here->BJTcb) * + *(ckt->CKTrhsOld + here->BJTbaseNode); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && !(ckt->CKTmode & + MODETRANOP)) { + value->rValue -= *(ckt->CKTstate0 + here->BJTcqcs) * + *(ckt->CKTrhsOld + here->BJTsubstNode); + } + tmp = -*(ckt->CKTstate0 + here->BJTcc); + tmp -= *(ckt->CKTstate0 + here->BJTcb); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + tmp += *(ckt->CKTstate0 + here->BJTcqcs); + } + value->rValue += tmp * *(ckt->CKTrhsOld + + here->BJTemitNode); + } + return(OK); + case BJT_QUEST_CPI: + value->rValue = here->BJTcapbe; + return(OK); + case BJT_QUEST_CMU: + value->rValue = here->BJTcapbc; + return(OK); + case BJT_QUEST_CBX: + value->rValue = here->BJTcapbx; + return(OK); + case BJT_QUEST_CCS: + value->rValue = here->BJTcapcs; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bjt/bjtconv.c b/src/spicelib/devices/bjt/bjtconv.c new file mode 100644 index 000000000..17a5ec917 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtconv.c @@ -0,0 +1,79 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * This routine performs the device convergence test for + * BJTs in the circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +BJTconvTest(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + +{ + register BJTinstance *here; + register BJTmodel *model = (BJTmodel *) inModel; + double tol; + double cc; + double cchat; + double cb; + double cbhat; + double vbe; + double vbc; + double delvbe; + double delvbc; + + + + for( ; model != NULL; model = model->BJTnextModel) { + for(here=model->BJTinstances;here!=NULL;here = here->BJTnextInstance){ + if (here->BJTowner != ARCHme) continue; + + vbe=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- + *(ckt->CKTrhsOld+here->BJTemitPrimeNode)); + vbc=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + delvbe=vbe- *(ckt->CKTstate0 + here->BJTvbe); + delvbc=vbc- *(ckt->CKTstate0 + here->BJTvbc); + cchat= *(ckt->CKTstate0 + here->BJTcc)+(*(ckt->CKTstate0 + + here->BJTgm)+ *(ckt->CKTstate0 + here->BJTgo))*delvbe- + (*(ckt->CKTstate0 + here->BJTgo)+*(ckt->CKTstate0 + + here->BJTgmu))*delvbc; + cbhat= *(ckt->CKTstate0 + here->BJTcb)+ *(ckt->CKTstate0 + + here->BJTgpi)*delvbe+ *(ckt->CKTstate0 + here->BJTgmu)* + delvbc; + cc = *(ckt->CKTstate0 + here->BJTcc); + cb = *(ckt->CKTstate0 + here->BJTcb); + /* + * check convergence + */ + tol=ckt->CKTreltol*MAX(fabs(cchat),fabs(cc))+ckt->CKTabstol; + if (fabs(cchat-cc) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue - we've failed... */ + } else { + tol=ckt->CKTreltol*MAX(fabs(cbhat),fabs(cb))+ + ckt->CKTabstol; + if (fabs(cbhat-cb) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue - we've failed... */ + } + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtdefs.h b/src/spicelib/devices/bjt/bjtdefs.h new file mode 100644 index 000000000..b94d16d52 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtdefs.h @@ -0,0 +1,512 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef BJT +#define BJT + +#include "cktdefs.h" +#include "ifsim.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + +/* structures to describe Bipolar Junction Transistors */ + +/* data needed to describe a single instance */ + +typedef struct sBJTinstance { + struct sBJTmodel *BJTmodPtr; /* backpointer to model */ + struct sBJTinstance *BJTnextInstance; /* pointer to next instance of + * current model*/ + IFuid BJTname; /* pointer to character string naming this instance */ + int BJTowner; /* number of owner process */ + int BJTstate; /* pointer to start of state vector for bjt */ + + int BJTcolNode; /* number of collector node of bjt */ + int BJTbaseNode; /* number of base node of bjt */ + int BJTemitNode; /* number of emitter node of bjt */ + int BJTsubstNode; /* number of substrate node of bjt */ + int BJTcolPrimeNode; /* number of internal collector node of bjt */ + int BJTbasePrimeNode; /* number of internal base node of bjt */ + int BJTemitPrimeNode; /* number of internal emitter node of bjt */ + double BJTarea; /* area factor for the bjt */ + double BJTicVBE; /* initial condition voltage B-E*/ + double BJTicVCE; /* initial condition voltage C-E*/ + double BJTtemp; /* instance temperature */ + double BJTtSatCur; /* temperature adjusted saturation current */ + double BJTtBetaF; /* temperature adjusted forward beta */ + double BJTtBetaR; /* temperature adjusted reverse beta */ + double BJTtBEleakCur; /* temperature adjusted B-E leakage current */ + double BJTtBCleakCur; /* temperature adjusted B-C leakage current */ + double BJTtBEcap; /* temperature adjusted B-E capacitance */ + double BJTtBEpot; /* temperature adjusted B-E potential */ + double BJTtBCcap; /* temperature adjusted B-C capacitance */ + double BJTtBCpot; /* temperature adjusted B-C potential */ + double BJTtDepCap; /* temperature adjusted join point in diode curve */ + double BJTtf1; /* temperature adjusted polynomial coefficient */ + double BJTtf4; /* temperature adjusted polynomial coefficient */ + double BJTtf5; /* temperature adjusted polynomial coefficient */ + double BJTtVcrit; /* temperature adjusted critical voltage */ + + double *BJTcolColPrimePtr; /* pointer to sparse matrix at + * (collector,collector prime) */ + double *BJTbaseBasePrimePtr; /* pointer to sparse matrix at + * (base,base prime) */ + double *BJTemitEmitPrimePtr; /* pointer to sparse matrix at + * (emitter,emitter prime) */ + double *BJTcolPrimeColPtr; /* pointer to sparse matrix at + * (collector prime,collector) */ + double *BJTcolPrimeBasePrimePtr; /* pointer to sparse matrix at + * (collector prime,base prime) */ + double *BJTcolPrimeEmitPrimePtr; /* pointer to sparse matrix at + * (collector prime,emitter prime) */ + double *BJTbasePrimeBasePtr; /* pointer to sparse matrix at + * (base prime,base ) */ + double *BJTbasePrimeColPrimePtr; /* pointer to sparse matrix at + * (base prime,collector prime) */ + double *BJTbasePrimeEmitPrimePtr; /* pointer to sparse matrix at + * (base primt,emitter prime) */ + double *BJTemitPrimeEmitPtr; /* pointer to sparse matrix at + * (emitter prime,emitter) */ + double *BJTemitPrimeColPrimePtr; /* pointer to sparse matrix at + * (emitter prime,collector prime) */ + double *BJTemitPrimeBasePrimePtr; /* pointer to sparse matrix at + * (emitter prime,base prime) */ + double *BJTcolColPtr; /* pointer to sparse matrix at + * (collector,collector) */ + double *BJTbaseBasePtr; /* pointer to sparse matrix at + * (base,base) */ + double *BJTemitEmitPtr; /* pointer to sparse matrix at + * (emitter,emitter) */ + double *BJTcolPrimeColPrimePtr; /* pointer to sparse matrix at + * (collector prime,collector prime) */ + double *BJTbasePrimeBasePrimePtr; /* pointer to sparse matrix at + * (base prime,base prime) */ + double *BJTemitPrimeEmitPrimePtr; /* pointer to sparse matrix at + * (emitter prime,emitter prime) */ + double *BJTsubstSubstPtr; /* pointer to sparse matrix at + * (substrate,substrate) */ + double *BJTcolPrimeSubstPtr; /* pointer to sparse matrix at + * (collector prime,substrate) */ + double *BJTsubstColPrimePtr; /* pointer to sparse matrix at + * (substrate,collector prime) */ + double *BJTbaseColPrimePtr; /* pointer to sparse matrix at + * (base,collector prime) */ + double *BJTcolPrimeBasePtr; /* pointer to sparse matrix at + * (collector prime,base) */ + + unsigned BJToff :1; /* 'off' flag for bjt */ + unsigned BJTtempGiven :1; /* temperature given for bjt instance*/ + unsigned BJTareaGiven :1; /* flag to indicate area was specified */ + unsigned BJTicVBEGiven :1; /* flag to indicate VBE init. cond. given */ + unsigned BJTicVCEGiven :1; /* flag to indicate VCE init. cond. given */ + unsigned BJTsenPertFlag :1; /* indictes whether the the parameter of + the particular instance is to be perturbed */ + + int BJTsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + double BJTcapbe; + double BJTcapbc; + double BJTcapcs; + double BJTcapbx; + double *BJTsens; + +#define BJTsenGpi BJTsens /* stores the perturbed values of gpi */ +#define BJTsenGmu BJTsens+5 /* stores the perturbed values of gmu */ +#define BJTsenGm BJTsens+10 /* stores the perturbed values of gm */ +#define BJTsenGo BJTsens+15 /* stores the perturbed values of go */ +#define BJTsenGx BJTsens+20 /* stores the perturbed values of gx */ +#define BJTsenCpi BJTsens+25 /* stores the perturbed values of cpi */ +#define BJTsenCmu BJTsens+30 /* stores the perturbed values of cmu */ +#define BJTsenCbx BJTsens+35 /* stores the perturbed values of cbx */ +#define BJTsenCmcb BJTsens+40 /* stores the perturbed values of cmcb */ +#define BJTsenCcs BJTsens+45 /* stores the perturbed values of ccs */ +#define BJTdphibedp BJTsens+51 +#define BJTdphibcdp BJTsens+52 +#define BJTdphicsdp BJTsens+53 +#define BJTdphibxdp BJTsens+54 + +/* + * distortion stuff + * the following naming convention is used: + * x = vbe + * y = vbc + * z = vbb + * w = vbed (vbe delayed for the linear gm delay) + * therefore ic_xyz stands for the coefficient of the vbe*vbc*vbb + * term in the multidimensional Taylor expansion for ic; and ibb_x2y + * for the coeff. of the vbe*vbe*vbc term in the ibb expansion. + */ + +#define BJTNDCOEFFS 65 + +#ifndef NODISTO + double BJTdCoeffs[BJTNDCOEFFS]; +#else /* NODISTO */ + double *BJTdCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define ic_x BJTdCoeffs[0] +#define ic_y BJTdCoeffs[1] +#define ic_xd BJTdCoeffs[2] +#define ic_x2 BJTdCoeffs[3] +#define ic_y2 BJTdCoeffs[4] +#define ic_w2 BJTdCoeffs[5] +#define ic_xy BJTdCoeffs[6] +#define ic_yw BJTdCoeffs[7] +#define ic_xw BJTdCoeffs[8] +#define ic_x3 BJTdCoeffs[9] +#define ic_y3 BJTdCoeffs[10] +#define ic_w3 BJTdCoeffs[11] +#define ic_x2w BJTdCoeffs[12] +#define ic_x2y BJTdCoeffs[13] +#define ic_y2w BJTdCoeffs[14] +#define ic_xy2 BJTdCoeffs[15] +#define ic_xw2 BJTdCoeffs[16] +#define ic_yw2 BJTdCoeffs[17] +#define ic_xyw BJTdCoeffs[18] + +#define ib_x BJTdCoeffs[19] +#define ib_y BJTdCoeffs[20] +#define ib_x2 BJTdCoeffs[21] +#define ib_y2 BJTdCoeffs[22] +#define ib_xy BJTdCoeffs[23] +#define ib_x3 BJTdCoeffs[24] +#define ib_y3 BJTdCoeffs[25] +#define ib_x2y BJTdCoeffs[26] +#define ib_xy2 BJTdCoeffs[27] + +#define ibb_x BJTdCoeffs[28] +#define ibb_y BJTdCoeffs[29] +#define ibb_z BJTdCoeffs[30] +#define ibb_x2 BJTdCoeffs[31] +#define ibb_y2 BJTdCoeffs[32] +#define ibb_z2 BJTdCoeffs[33] +#define ibb_xy BJTdCoeffs[34] +#define ibb_yz BJTdCoeffs[35] +#define ibb_xz BJTdCoeffs[36] +#define ibb_x3 BJTdCoeffs[37] +#define ibb_y3 BJTdCoeffs[38] +#define ibb_z3 BJTdCoeffs[39] +#define ibb_x2z BJTdCoeffs[40] +#define ibb_x2y BJTdCoeffs[41] +#define ibb_y2z BJTdCoeffs[42] +#define ibb_xy2 BJTdCoeffs[43] +#define ibb_xz2 BJTdCoeffs[44] +#define ibb_yz2 BJTdCoeffs[45] +#define ibb_xyz BJTdCoeffs[46] + +#define qbe_x BJTdCoeffs[47] +#define qbe_y BJTdCoeffs[48] +#define qbe_x2 BJTdCoeffs[49] +#define qbe_y2 BJTdCoeffs[50] +#define qbe_xy BJTdCoeffs[51] +#define qbe_x3 BJTdCoeffs[52] +#define qbe_y3 BJTdCoeffs[53] +#define qbe_x2y BJTdCoeffs[54] +#define qbe_xy2 BJTdCoeffs[55] + +#define capbc1 BJTdCoeffs[56] +#define capbc2 BJTdCoeffs[57] +#define capbc3 BJTdCoeffs[58] + +#define capbx1 BJTdCoeffs[59] +#define capbx2 BJTdCoeffs[60] +#define capbx3 BJTdCoeffs[61] + +#define capsc1 BJTdCoeffs[62] +#define capsc2 BJTdCoeffs[63] +#define capsc3 BJTdCoeffs[64] + +#endif + +/* indices to array of BJT noise sources */ + +#define BJTRCNOIZ 0 +#define BJTRBNOIZ 1 +#define BJT_RE_NOISE 2 +#define BJTICNOIZ 3 +#define BJTIBNOIZ 4 +#define BJTFLNOIZ 5 +#define BJTTOTNOIZ 6 + +#define BJTNSRCS 7 /* the number of BJT noise sources */ + +#ifndef NONOISE + double BJTnVar[NSTATVARS][BJTNSRCS]; +#else /*NONOISE*/ + double **BJTnVar; +#endif /*NONOISE*/ +/* the above to avoid allocating memory when it is not needed */ + +} BJTinstance ; + +/* entries in the state vector for bjt: */ +#define BJTvbe BJTstate +#define BJTvbc BJTstate+1 +#define BJTcc BJTstate+2 +#define BJTcb BJTstate+3 +#define BJTgpi BJTstate+4 +#define BJTgmu BJTstate+5 +#define BJTgm BJTstate+6 +#define BJTgo BJTstate+7 +#define BJTqbe BJTstate+8 +#define BJTcqbe BJTstate+9 +#define BJTqbc BJTstate+10 +#define BJTcqbc BJTstate+11 +#define BJTqcs BJTstate+12 +#define BJTcqcs BJTstate+13 +#define BJTqbx BJTstate+14 +#define BJTcqbx BJTstate+15 +#define BJTgx BJTstate+16 +#define BJTcexbc BJTstate+17 +#define BJTgeqcb BJTstate+18 +#define BJTgccs BJTstate+19 +#define BJTgeqbx BJTstate+20 +#define BJTnumStates 21 + +#define BJTsensxpbe BJTstate+21 /* charge sensitivities and their + derivatives. +22 for the derivatives - + pointer to the beginning of the array */ +#define BJTsensxpbc BJTstate+23 +#define BJTsensxpcs BJTstate+25 +#define BJTsensxpbx BJTstate+27 + +#define BJTnumSenStates 8 + +/* per model data */ +typedef struct sBJTmodel { /* model structure for a bjt */ + int BJTmodType; /* type index of this device type */ + struct sBJTmodel *BJTnextModel; /* pointer to next possible model in + * linked list */ + BJTinstance * BJTinstances; /* pointer to list of instances + * that have this model */ + IFuid BJTmodName; /* pointer to character string naming this model */ + int BJTtype; + + double BJTtnom; /* nominal temperature */ + double BJTsatCur; /* input - don't use */ + double BJTbetaF; /* input - don't use */ + double BJTemissionCoeffF; + double BJTearlyVoltF; + double BJTrollOffF; + double BJTleakBEcurrent; /* input - don't use */ + double BJTc2; + double BJTleakBEemissionCoeff; + double BJTbetaR; /* input - don't use */ + double BJTemissionCoeffR; + double BJTearlyVoltR; + double BJTrollOffR; + double BJTleakBCcurrent; /* input - don't use */ + double BJTc4; + double BJTleakBCemissionCoeff; + double BJTbaseResist; + double BJTbaseCurrentHalfResist; + double BJTminBaseResist; + double BJTemitterResist; + double BJTcollectorResist; + double BJTdepletionCapBE; /* input - don't use */ + double BJTpotentialBE; /* input - don't use */ + double BJTjunctionExpBE; + double BJTtransitTimeF; + double BJTtransitTimeBiasCoeffF; + double BJTtransitTimeFVBC; + double BJTtransitTimeHighCurrentF; + double BJTexcessPhase; + double BJTdepletionCapBC; /* input - don't use */ + double BJTpotentialBC; /* input - don't use */ + double BJTjunctionExpBC; + double BJTbaseFractionBCcap; + double BJTtransitTimeR; + double BJTcapCS; + double BJTpotentialSubstrate; + double BJTexponentialSubstrate; + double BJTbetaExp; + double BJTenergyGap; + double BJTtempExpIS; + double BJTdepletionCapCoeff; + double BJTfNcoef; + double BJTfNexp; + + double BJTinvEarlyVoltF; /* inverse of BJTearlyVoltF */ + double BJTinvEarlyVoltR; /* inverse of BJTearlyVoltR */ + double BJTinvRollOffF; /* inverse of BJTrollOffF */ + double BJTinvRollOffR; /* inverse of BJTrollOffR */ + double BJTcollectorConduct; /* collector conductance */ + double BJTemitterConduct; /* emitter conductance */ + double BJTtransitTimeVBCFactor; /* */ + double BJTexcessPhaseFactor; + double BJTf2; + double BJTf3; + double BJTf6; + double BJTf7; + + unsigned BJTtnomGiven : 1; + unsigned BJTsatCurGiven : 1; + unsigned BJTbetaFGiven : 1; + unsigned BJTemissionCoeffFGiven : 1; + unsigned BJTearlyVoltFGiven : 1; + unsigned BJTrollOffFGiven : 1; + unsigned BJTleakBEcurrentGiven : 1; + unsigned BJTc2Given : 1; + unsigned BJTleakBEemissionCoeffGiven : 1; + unsigned BJTbetaRGiven : 1; + unsigned BJTemissionCoeffRGiven : 1; + unsigned BJTearlyVoltRGiven : 1; + unsigned BJTrollOffRGiven : 1; + unsigned BJTleakBCcurrentGiven : 1; + unsigned BJTc4Given : 1; + unsigned BJTleakBCemissionCoeffGiven : 1; + unsigned BJTbaseResistGiven : 1; + unsigned BJTbaseCurrentHalfResistGiven : 1; + unsigned BJTminBaseResistGiven : 1; + unsigned BJTemitterResistGiven : 1; + unsigned BJTcollectorResistGiven : 1; + unsigned BJTdepletionCapBEGiven : 1; + unsigned BJTpotentialBEGiven : 1; + unsigned BJTjunctionExpBEGiven : 1; + unsigned BJTtransitTimeFGiven : 1; + unsigned BJTtransitTimeBiasCoeffFGiven : 1; + unsigned BJTtransitTimeFVBCGiven : 1; + unsigned BJTtransitTimeHighCurrentFGiven : 1; + unsigned BJTexcessPhaseGiven : 1; + unsigned BJTdepletionCapBCGiven : 1; + unsigned BJTpotentialBCGiven : 1; + unsigned BJTjunctionExpBCGiven : 1; + unsigned BJTbaseFractionBCcapGiven : 1; + unsigned BJTtransitTimeRGiven : 1; + unsigned BJTcapCSGiven : 1; + unsigned BJTpotentialSubstrateGiven : 1; + unsigned BJTexponentialSubstrateGiven : 1; + unsigned BJTbetaExpGiven : 1; + unsigned BJTenergyGapGiven : 1; + unsigned BJTtempExpISGiven : 1; + unsigned BJTdepletionCapCoeffGiven : 1; + unsigned BJTfNcoefGiven : 1; + unsigned BJTfNexpGiven :1; +} BJTmodel; + +#ifndef NPN +#define NPN 1 +#define PNP -1 +#endif /*NPN*/ + +/* device parameters */ +#define BJT_AREA 1 +#define BJT_OFF 2 +#define BJT_IC_VBE 3 +#define BJT_IC_VCE 4 +#define BJT_IC 5 +#define BJT_AREA_SENS 6 +#define BJT_TEMP 7 + +/* model parameters */ +#define BJT_MOD_NPN 101 +#define BJT_MOD_PNP 102 +#define BJT_MOD_IS 103 +#define BJT_MOD_BF 104 +#define BJT_MOD_NF 105 +#define BJT_MOD_VAF 106 +#define BJT_MOD_IKF 107 +#define BJT_MOD_ISE 108 +#define BJT_MOD_C2 109 +#define BJT_MOD_NE 110 +#define BJT_MOD_BR 111 +#define BJT_MOD_NR 112 +#define BJT_MOD_VAR 113 +#define BJT_MOD_IKR 114 +#define BJT_MOD_ISC 115 +#define BJT_MOD_C4 116 +#define BJT_MOD_NC 117 +#define BJT_MOD_RB 118 +#define BJT_MOD_IRB 119 +#define BJT_MOD_RBM 120 +#define BJT_MOD_RE 121 +#define BJT_MOD_RC 122 +#define BJT_MOD_CJE 123 +#define BJT_MOD_VJE 124 +#define BJT_MOD_MJE 125 +#define BJT_MOD_TF 126 +#define BJT_MOD_XTF 127 +#define BJT_MOD_VTF 128 +#define BJT_MOD_ITF 129 +#define BJT_MOD_PTF 130 +#define BJT_MOD_CJC 131 +#define BJT_MOD_VJC 132 +#define BJT_MOD_MJC 133 +#define BJT_MOD_XCJC 134 +#define BJT_MOD_TR 135 +#define BJT_MOD_CJS 136 +#define BJT_MOD_VJS 137 +#define BJT_MOD_MJS 138 +#define BJT_MOD_XTB 139 +#define BJT_MOD_EG 140 +#define BJT_MOD_XTI 141 +#define BJT_MOD_FC 142 +#define BJT_MOD_TNOM 143 +#define BJT_MOD_AF 144 +#define BJT_MOD_KF 145 + +/* device questions */ +#define BJT_QUEST_FT 201 +#define BJT_QUEST_COLNODE 202 +#define BJT_QUEST_BASENODE 203 +#define BJT_QUEST_EMITNODE 204 +#define BJT_QUEST_SUBSTNODE 205 +#define BJT_QUEST_COLPRIMENODE 206 +#define BJT_QUEST_BASEPRIMENODE 207 +#define BJT_QUEST_EMITPRIMENODE 208 +#define BJT_QUEST_VBE 209 +#define BJT_QUEST_VBC 210 +#define BJT_QUEST_CC 211 +#define BJT_QUEST_CB 212 +#define BJT_QUEST_GPI 213 +#define BJT_QUEST_GMU 214 +#define BJT_QUEST_GM 215 +#define BJT_QUEST_GO 216 +#define BJT_QUEST_QBE 217 +#define BJT_QUEST_CQBE 218 +#define BJT_QUEST_QBC 219 +#define BJT_QUEST_CQBC 220 +#define BJT_QUEST_QCS 221 +#define BJT_QUEST_CQCS 222 +#define BJT_QUEST_QBX 223 +#define BJT_QUEST_CQBX 224 +#define BJT_QUEST_GX 225 +#define BJT_QUEST_CEXBC 226 +#define BJT_QUEST_GEQCB 227 +#define BJT_QUEST_GCCS 228 +#define BJT_QUEST_GEQBX 229 +#define BJT_QUEST_SENS_REAL 230 +#define BJT_QUEST_SENS_IMAG 231 +#define BJT_QUEST_SENS_MAG 232 +#define BJT_QUEST_SENS_PH 233 +#define BJT_QUEST_SENS_CPLX 234 +#define BJT_QUEST_SENS_DC 235 +#define BJT_QUEST_CE 236 +#define BJT_QUEST_CS 237 +#define BJT_QUEST_POWER 238 + +#define BJT_QUEST_CPI 239 +#define BJT_QUEST_CMU 240 +#define BJT_QUEST_CBX 241 +#define BJT_QUEST_CCS 242 + +/* model questions */ +#define BJT_MOD_INVEARLYF 301 +#define BJT_MOD_INVEARLYR 302 +#define BJT_MOD_INVROLLOFFF 303 +#define BJT_MOD_INVROLLOFFR 304 +#define BJT_MOD_COLCONDUCT 305 +#define BJT_MOD_EMITTERCONDUCT 306 +#define BJT_MOD_TRANSVBCFACT 307 +#define BJT_MOD_EXCESSPHASEFACTOR 308 +#define BJT_MOD_TYPE 309 + + +#include "bjtext.h" +#endif /*BJT*/ diff --git a/src/spicelib/devices/bjt/bjtdel.c b/src/spicelib/devices/bjt/bjtdel.c new file mode 100644 index 000000000..e2fe50f0c --- /dev/null +++ b/src/spicelib/devices/bjt/bjtdel.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * This routine deletes a BJT instance from the circuit and frees + * the storage it was using. + */ + +#include "ngspice.h" +#include +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BJTdelete(inModel,name,kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; + +{ + BJTmodel *model = (BJTmodel*)inModel; + BJTinstance **fast = (BJTinstance**)kill; + + BJTinstance **prev = NULL; + BJTinstance *here; + + for( ; model ; model = model->BJTnextModel) { + prev = &(model->BJTinstances); + for(here = *prev; here ; here = *prev) { + if(here->BJTname == name || (fast && here==*fast) ) { + *prev= here->BJTnextInstance; + FREE(here); + return(OK); + } + prev = &(here->BJTnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/bjt/bjtdest.c b/src/spicelib/devices/bjt/bjtdest.c new file mode 100644 index 000000000..763fdb80c --- /dev/null +++ b/src/spicelib/devices/bjt/bjtdest.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine deletes all BJTs from the circuit and frees + * all storage they were using. + */ + +#include "ngspice.h" +#include +#include "bjtdefs.h" +#include "suffix.h" + + +void +BJTdestroy(inModel) + GENmodel **inModel; + +{ + + BJTmodel **model = (BJTmodel**)inModel; + BJTinstance *here; + BJTinstance *prev = NULL; + BJTmodel *mod = *model; + BJTmodel *oldmod = NULL; + + for( ; mod ; mod = mod->BJTnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (BJTinstance *)NULL; + for(here = mod->BJTinstances ; here ; here = here->BJTnextInstance) { + if(prev){ + if(prev->BJTsens) FREE(prev->BJTsens); + FREE(prev); + } + prev = here; + } + if(prev){ + if(prev->BJTsens) FREE(prev->BJTsens); + FREE(prev); + } + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/bjt/bjtdisto.c b/src/spicelib/devices/bjt/bjtdisto.c new file mode 100644 index 000000000..08c993454 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtdisto.c @@ -0,0 +1,1836 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" +#include "bjtdset.h" + + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +int +BJTdisto(int mode, GENmodel *genmodel, register CKTcircuit *ckt) +{ + BJTmodel *model = (BJTmodel *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + double td; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h1z, i1h1z; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1h2z, i1h2z; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r1hm2z, i1hm2z; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h11z, i2h11z; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double r2h1m2z, i2h1m2z; + double temp, itemp; + register BJTinstance *here; +#ifdef DISTODEBUG + double time; +#endif + + if (mode == D_SETUP) + return(BJTdSetup(model,ckt)); + + if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the BJT models */ + for( ; model != NULL; model = model->BJTnextModel ) { + td = model->BJTexcessPhaseFactor; + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + /* getting Volterra kernels */ + /* until further notice x = vbe, y = vbc, z= vbed */ + + r1h1x = *(job->r1H1ptr + (here->BJTbasePrimeNode)) - + *(job->r1H1ptr + (here->BJTemitPrimeNode)); + i1h1x = *(job->i1H1ptr + (here->BJTbasePrimeNode)) - + *(job->i1H1ptr + (here->BJTemitPrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->BJTbasePrimeNode)) - + *(job->r1H1ptr + (here->BJTcolPrimeNode)); + i1h1y = *(job->i1H1ptr + (here->BJTbasePrimeNode)) - + *(job->i1H1ptr + (here->BJTcolPrimeNode)); + + if (td != 0) { + + temp = job->Domega1 * td; + + /* multiplying r1h1x by exp(-j omega td) */ + r1h1z = r1h1x*cos(temp) + i1h1x*sin(temp); + i1h1z = i1h1x*cos(temp) - r1h1x*sin(temp); + } + else { + r1h1z = r1h1x; + i1h1z = i1h1x; + } + + if ((mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + r1hm2x = *(job->r1H2ptr + (here->BJTbasePrimeNode)) - + *(job->r1H2ptr + (here->BJTemitPrimeNode)); + i1hm2x = -(*(job->i1H2ptr + (here->BJTbasePrimeNode)) - + *(job->i1H2ptr + (here->BJTemitPrimeNode))); + + r1hm2y = *(job->r1H2ptr + (here->BJTbasePrimeNode)) - + *(job->r1H2ptr + (here->BJTcolPrimeNode)); + i1hm2y = -(*(job->i1H2ptr + (here->BJTbasePrimeNode)) - + *(job->i1H2ptr + (here->BJTcolPrimeNode))); + + if (td != 0) { + + temp = -job->Domega2 * td; + r1hm2z = r1hm2x*cos(temp) + i1hm2x*sin(temp); + i1hm2z = i1hm2x*cos(temp) - r1hm2x*sin(temp); + } + else { + r1hm2z = r1hm2x; + i1hm2z = i1hm2x; + } + } + if ((mode == D_THRF1) || (mode == D_2F1MF2)){ + + + r2h11x = *(job->r2H11ptr + (here->BJTbasePrimeNode)) - + *(job->r2H11ptr + (here->BJTemitPrimeNode)); + i2h11x = *(job->i2H11ptr + (here->BJTbasePrimeNode)) - + *(job->i2H11ptr + (here->BJTemitPrimeNode)); + + r2h11y = *(job->r2H11ptr + (here->BJTbasePrimeNode)) - + *(job->r2H11ptr + (here->BJTcolPrimeNode)); + i2h11y = *(job->i2H11ptr + (here->BJTbasePrimeNode)) - + *(job->i2H11ptr + (here->BJTcolPrimeNode)); + + if (td != 0) { + temp = 2*job->Domega1* td ; + r2h11z = r2h11x*cos(temp) + i2h11x*sin(temp); + i2h11z = i2h11x*cos(temp) - r2h11x*sin(temp); + } + else { + r2h11z = r2h11x; + i2h11z = i2h11x; + } + } + + if ((mode == D_2F1MF2)){ + + r2h1m2x = *(job->r2H1m2ptr + (here->BJTbasePrimeNode)) - + *(job->r2H1m2ptr + (here->BJTemitPrimeNode)); + i2h1m2x = *(job->i2H1m2ptr + (here->BJTbasePrimeNode)) + - *(job->i2H1m2ptr + (here->BJTemitPrimeNode)); + + r2h1m2y = *(job->r2H1m2ptr + (here->BJTbasePrimeNode)) - + *(job->r2H1m2ptr + (here->BJTcolPrimeNode)); + i2h1m2y = *(job->i2H1m2ptr + (here->BJTbasePrimeNode)) + - *(job->i2H1m2ptr + (here->BJTcolPrimeNode)); + + if (td != 0) { + + temp = (job->Domega1 - job->Domega2) * td; + r2h1m2z = r2h1m2x*cos(temp) + + i2h1m2x*sin(temp); + i2h1m2z = i2h1m2x*cos(temp) + - r2h1m2x*sin(temp); + } + else { + r2h1m2z = r2h1m2x; + i2h1m2z = i2h1m2x; + } + } + if ((mode == D_F1PF2)){ + + r1h2x = *(job->r1H2ptr + (here->BJTbasePrimeNode)) - + *(job->r1H2ptr + (here->BJTemitPrimeNode)); + i1h2x = *(job->i1H2ptr + (here->BJTbasePrimeNode)) - + *(job->i1H2ptr + (here->BJTemitPrimeNode)); + + r1h2y = *(job->r1H2ptr + (here->BJTbasePrimeNode)) - + *(job->r1H2ptr + (here->BJTcolPrimeNode)); + i1h2y = *(job->i1H2ptr + (here->BJTbasePrimeNode)) - + *(job->i1H2ptr + (here->BJTcolPrimeNode)); + + + if (td != 0) { + temp = job->Domega2 * td; + r1h2z = r1h2x*cos(temp) + i1h2x*sin(temp); + i1h2z = i1h2x*cos(temp) - r1h2x*sin(temp); + } + else { + r1h2z = r1h2x; + i1h2z = i1h2x; + } + } + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + + + /* ic term */ + +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = DFn2F1( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = DFi2F1( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for DFn2F1: %g seconds \n", time); +#endif + + *(ckt->CKTrhs + here->BJTcolPrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* finish ic term */ + /* loading ib term */ + /* x and y still the same */ + temp = DFn2F1( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + itemp = DFi2F1( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* ib term over */ + /* loading ibb term */ + /* now x = vbe, y = vbc, z = vbb */ + if ( !((model->BJTminBaseResist == 0.0) && + (model->BJTbaseResist == model->BJTminBaseResist))) { + + r1h1z = *(job->r1H1ptr + (here->BJTbaseNode)) - + *(job->r1H1ptr + (here->BJTbasePrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTbaseNode)) - + *(job->i1H1ptr + (here->BJTbasePrimeNode)); + + temp = DFn2F1( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = DFi2F1( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTbasePrimeNode) += temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) += itemp; + } + + /* ibb term over */ + /* loading qbe term */ + /* x = vbe, y = vbc, z not used */ + /* (have to multiply by j omega for charge storage + * elements to get the current) + */ + + temp = - ckt->CKTomega* + DFi2F1( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFn2F1( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* qbe term over */ + /* loading qbx term */ + /* z = vbx= vb - vcPrime */ + + r1h1z = r1h1z + r1h1y; + i1h1z = i1h1z + i1h1y; +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = - ckt->CKTomega * + D1i2F1(here->capbx2, + r1h1z, + i1h1z); + itemp = ckt->CKTomega * + D1n2F1(here->capbx2, + r1h1z, + i1h1z); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for D1n2F1: %g seconds \n", time); +#endif + + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbx term over */ + + /* loading qbc term */ + + temp = - ckt->CKTomega * + D1i2F1(here->capbc2, + r1h1y, + i1h1y); + itemp = ckt->CKTomega * + D1n2F1(here->capbc2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbc term over */ + + + /* loading qsc term */ + /* z = vsc */ + + + + r1h1z = *(job->r1H1ptr + (here->BJTsubstNode)) - + *(job->r1H1ptr + (here->BJTcolPrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTsubstNode)) - + *(job->i1H1ptr + (here->BJTcolPrimeNode)); + + temp = - ckt->CKTomega * + D1i2F1(here->capsc2, + r1h1z, + i1h1z); + itemp = ckt->CKTomega * + D1n2F1(here->capsc2, + r1h1z, + i1h1z); + + + *(ckt->CKTrhs + here->BJTsubstNode) -= temp; + *(ckt->CKTirhs + here->BJTsubstNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qsc term over */ + + + break; + + case D_THRF1: + /* ic term */ + +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = DFn3F1( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + here->ic_x3, + here->ic_y3, + here->ic_w3, + here->ic_x2y, + here->ic_x2w, + here->ic_xy2, + here->ic_y2w, + here->ic_xw2, + here->ic_yw2, + here->ic_xyw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + itemp = DFi3F1( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + here->ic_x3, + here->ic_y3, + here->ic_w3, + here->ic_x2y, + here->ic_x2w, + here->ic_xy2, + here->ic_y2w, + here->ic_xw2, + here->ic_yw2, + here->ic_xyw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for DFn3F1: %g seconds \n", time); +#endif + + *(ckt->CKTrhs + here->BJTcolPrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* finish ic term */ + /* loading ib term */ + /* x and y still the same */ + temp = DFn3F1( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + here->ib_x3, + here->ib_y3, + 0.0, + here->ib_x2y, + 0.0, + here->ib_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + itemp = DFi3F1( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + here->ib_x3, + here->ib_y3, + 0.0, + here->ib_x2y, + 0.0, + here->ib_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* ib term over */ + /* loading ibb term */ + if ( !((model->BJTminBaseResist == 0.0) && + (model->BJTbaseResist == model->BJTminBaseResist))) { + + /* now x = vbe, y = vbc, z = vbb */ + r1h1z = *(job->r1H1ptr + (here->BJTbaseNode)) - + *(job->r1H1ptr + (here->BJTbasePrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTbaseNode)) - + *(job->i1H1ptr + (here->BJTbasePrimeNode)); + + r2h11z = *(job->r2H11ptr + (here->BJTbaseNode)) - + *(job->r2H11ptr + (here->BJTbasePrimeNode)); + i2h11z = *(job->i2H11ptr + (here->BJTbaseNode)) - + *(job->i2H11ptr + (here->BJTbasePrimeNode)); + + temp = DFn3F1( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + here->ibb_x3, + here->ibb_y3, + here->ibb_z3, + here->ibb_x2y, + here->ibb_x2z, + here->ibb_xy2, + here->ibb_y2z, + here->ibb_xz2, + here->ibb_yz2, + here->ibb_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + itemp = DFi3F1( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + here->ibb_x3, + here->ibb_y3, + here->ibb_z3, + here->ibb_x2y, + here->ibb_x2z, + here->ibb_xy2, + here->ibb_y2z, + here->ibb_xz2, + here->ibb_yz2, + here->ibb_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTbasePrimeNode) += temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) += itemp; + + } + /* ibb term over */ + /* loading qbe term */ + /* x = vbe, y = vbc, z not used */ + /* (have to multiply by j omega for charge storage + * elements to get the current) + */ + + temp = - ckt->CKTomega* + DFi3F1( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + here->qbe_x3, + here->qbe_y3, + 0.0, + here->qbe_x2y, + 0.0, + here->qbe_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFn3F1( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + here->qbe_x3, + here->qbe_y3, + 0.0, + here->qbe_x2y, + 0.0, + here->qbe_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* qbe term over */ + /* loading qbx term */ + /* z = vbx= vb - vcPrime */ + + r1h1z = r1h1z + r1h1y; + i1h1z = i1h1z + i1h1y; + r2h11z = r2h11z + r2h11y; + i2h11z = i2h11z + i2h11y; +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = - ckt->CKTomega * + D1i3F1(here->capbx2, + here->capbx3, + r1h1z, + i1h1z, + r2h11z, + i2h11z); + itemp = ckt->CKTomega * + D1n3F1(here->capbx2, + here->capbx3, + r1h1z, + i1h1z, + r2h11z, + i2h11z); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for D1n3F1: %g seconds \n", time); +#endif + + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbx term over */ + + /* loading qbc term */ + + temp = - ckt->CKTomega * + D1i3F1(here->capbc2, + here->capbc3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + itemp = ckt->CKTomega * + D1n3F1(here->capbc2, + here->capbc3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbc term over */ + + + /* loading qsc term */ + /* z = vsc */ + + + + r1h1z = *(job->r1H1ptr + (here->BJTsubstNode)) - + *(job->r1H1ptr + (here->BJTcolPrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTsubstNode)) - + *(job->i1H1ptr + (here->BJTcolPrimeNode)); + + r2h11z = *(job->r2H11ptr + (here->BJTsubstNode)) - + *(job->r2H11ptr + (here->BJTcolPrimeNode)); + i2h11z = *(job->i2H11ptr + (here->BJTsubstNode)) - + *(job->i2H11ptr + (here->BJTcolPrimeNode)); + + temp = - ckt->CKTomega * + D1i3F1(here->capsc2, + here->capsc3, + r1h1z, + i1h1z, + r2h11z, + i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capsc2, + here->capsc3, + r1h1z, + i1h1z, + r2h11z, + i2h11z); + + + *(ckt->CKTrhs + here->BJTsubstNode) -= temp; + *(ckt->CKTirhs + here->BJTsubstNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qsc term over */ + + + break; + case D_F1PF2: + /* ic term */ + + temp = DFnF12( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = DFiF12( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + here->BJTcolPrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* finish ic term */ + /* loading ib term */ + /* x and y still the same */ +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = DFnF12( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); + + itemp = DFiF12( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for DFnF12: %g seconds \n", time); +#endif + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* ib term over */ + /* loading ibb term */ + if ( !((model->BJTminBaseResist == 0.0) && + (model->BJTbaseResist == model->BJTminBaseResist))) { + + /* now x = vbe, y = vbc, z = vbb */ + r1h1z = *(job->r1H1ptr + (here->BJTbaseNode)) - + *(job->r1H1ptr + (here->BJTbasePrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTbaseNode)) - + *(job->i1H1ptr + (here->BJTbasePrimeNode)); + + r1h2z = *(job->r1H2ptr + (here->BJTbaseNode)) - + *(job->r1H2ptr + (here->BJTbasePrimeNode)); + i1h2z = *(job->i1H2ptr + (here->BJTbaseNode)) - + *(job->i1H2ptr + (here->BJTbasePrimeNode)); + + temp = DFnF12( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = DFiF12( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTbasePrimeNode) += temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) += itemp; + + } + /* ibb term over */ + /* loading qbe term */ + /* x = vbe, y = vbc, z not used */ + /* (have to multiply by j omega for charge storage + * elements - to get the current) + */ + + temp = - ckt->CKTomega* + DFiF12( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFnF12( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* qbe term over */ + /* loading qbx term */ + /* z = vbx= vb - vcPrime */ + + r1h1z = r1h1z + r1h1y; + i1h1z = i1h1z + i1h1y; + r1h2z = r1h2z + r1h2y; + i1h2z = i1h2z + i1h2y; +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = - ckt->CKTomega * + D1iF12(here->capbx2, + r1h1z, + i1h1z, + r1h2z, + i1h2z); + itemp = ckt->CKTomega * + D1nF12(here->capbx2, + r1h1z, + i1h1z, + r1h2z, + i1h2z); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for D1nF12: %g seconds \n", time); +#endif + + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbx term over */ + + /* loading qbc term */ + + temp = - ckt->CKTomega * + D1iF12(here->capbc2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + itemp = ckt->CKTomega * + D1nF12(here->capbc2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbc term over */ + + + /* loading qsc term */ + /* z = vsc */ + + + + r1h1z = *(job->r1H1ptr + (here->BJTsubstNode)) - + *(job->r1H1ptr + (here->BJTcolPrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTsubstNode)) - + *(job->i1H1ptr + (here->BJTcolPrimeNode)); + r1h2z = *(job->r1H2ptr + (here->BJTsubstNode)) - + *(job->r1H2ptr + (here->BJTcolPrimeNode)); + i1h2z = *(job->i1H2ptr + (here->BJTsubstNode)) - + *(job->i1H2ptr + (here->BJTcolPrimeNode)); + + temp = - ckt->CKTomega * + D1iF12(here->capsc2, + r1h1z, + i1h1z, + r1h2z, + i1h2z); + itemp = ckt->CKTomega * + D1nF12(here->capsc2, + r1h1z, + i1h1z, + r1h2z, + i1h2z); + + + *(ckt->CKTrhs + here->BJTsubstNode) -= temp; + *(ckt->CKTirhs + here->BJTsubstNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qsc term over */ + + + break; + case D_F1MF2: + /* ic term */ + + temp = DFnF12( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = DFiF12( here->ic_x2, + here->ic_y2, + here->ic_w2, + here->ic_xy, + here->ic_yw, + here->ic_xw, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + here->BJTcolPrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* finish ic term */ + /* loading ib term */ + /* x and y still the same */ + temp = DFnF12( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + itemp = DFiF12( here->ib_x2, + here->ib_y2, + 0.0, + here->ib_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* ib term over */ + /* loading ibb term */ + if ( !((model->BJTminBaseResist == 0.0) && + (model->BJTbaseResist == model->BJTminBaseResist))) { + + /* now x = vbe, y = vbc, z = vbb */ + r1h1z = *(job->r1H1ptr + (here->BJTbaseNode)) - + *(job->r1H1ptr + (here->BJTbasePrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTbaseNode)) - + *(job->i1H1ptr + (here->BJTbasePrimeNode)); + + r1hm2z = *(job->r1H2ptr + (here->BJTbaseNode)) - + *(job->r1H2ptr + (here->BJTbasePrimeNode)); + i1hm2z = *(job->i1H2ptr + (here->BJTbaseNode)) - + *(job->i1H2ptr + (here->BJTbasePrimeNode)); + + temp = DFnF12( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = DFiF12( here->ibb_x2, + here->ibb_y2, + here->ibb_z2, + here->ibb_xy, + here->ibb_yz, + here->ibb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTbasePrimeNode) += temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) += itemp; + } + + /* ibb term over */ + /* loading qbe term */ + /* x = vbe, y = vbc, z not used */ + /* (have to multiply by j omega for charge storage + * elements - to get the current) + */ + + temp = - ckt->CKTomega* + DFiF12( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFnF12( here->qbe_x2, + here->qbe_y2, + 0.0, + here->qbe_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* qbe term over */ + /* loading qbx term */ + /* z = vbx= vb - vcPrime */ + + r1h1z = r1h1z + r1h1y; + i1h1z = i1h1z + i1h1y; + r1hm2z = r1hm2z + r1hm2y; + i1hm2z = i1hm2z + i1hm2y; + temp = - ckt->CKTomega * + D1iF12(here->capbx2, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z); + itemp = ckt->CKTomega * + D1nF12(here->capbx2, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z); + + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbx term over */ + + /* loading qbc term */ + + temp = - ckt->CKTomega * + D1iF12(here->capbc2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + itemp = ckt->CKTomega * + D1nF12(here->capbc2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbc term over */ + + + /* loading qsc term */ + /* z = vsc */ + + + + r1h1z = *(job->r1H1ptr + (here->BJTsubstNode)) - + *(job->r1H1ptr + (here->BJTcolPrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTsubstNode)) - + *(job->i1H1ptr + (here->BJTcolPrimeNode)); + r1hm2z = *(job->r1H2ptr + (here->BJTsubstNode)) - + *(job->r1H2ptr + (here->BJTcolPrimeNode)); + i1hm2z = *(job->i1H2ptr + (here->BJTsubstNode)) - + *(job->i1H2ptr + (here->BJTcolPrimeNode)); + + temp = - ckt->CKTomega * + D1iF12(here->capsc2, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z); + itemp = ckt->CKTomega * + D1nF12(here->capsc2, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z); + + + *(ckt->CKTrhs + here->BJTsubstNode) -= temp; + *(ckt->CKTirhs + here->BJTsubstNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qsc term over */ + + + break; + case D_2F1MF2: + /* ic term */ + + { + pass.cxx = here->ic_x2; + pass.cyy = here->ic_y2; + pass.czz = here->ic_w2; + pass.cxy = here->ic_xy; + pass.cyz = here->ic_yw; + pass.cxz = here->ic_xw; + pass.cxxx = here->ic_x3; + pass.cyyy = here->ic_y3; + pass.czzz = here->ic_w3; + pass.cxxy = here->ic_x2y; + pass.cxxz = here->ic_x2w; + pass.cxyy = here->ic_xy2; + pass.cyyz = here->ic_y2w; + pass.cxzz = here->ic_xw2; + pass.cyzz = here->ic_yw2; + pass.cxyz = here->ic_xyw; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = r1h1z; + pass.i1h1z = i1h1z; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = r1hm2z; + pass.i1h2z = i1hm2z; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = r2h11z; + pass.i2h11z = i2h11z; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = r2h1m2z; + pass.ih2f1f2z = i2h1m2z; +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = DFn2F12(&pass); + + + itemp = DFi2F12(&pass); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for DFn2F12: %g seconds \n", time); +#endif + } + + *(ckt->CKTrhs + here->BJTcolPrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* finish ic term */ + /* loading ib term */ + /* x and y still the same */ + { + pass.cxx = here->ib_x2; + pass.cyy = here->ib_y2; + pass.czz = 0.0; + pass.cxy = here->ib_xy; + pass.cyz = 0.0; + pass.cxz = 0.0; + pass.cxxx = here->ib_x3; + pass.cyyy = here->ib_y3; + pass.czzz = 0.0; + pass.cxxy = here->ib_x2y; + pass.cxxz = 0.0; + pass.cxyy = here->ib_xy2; + pass.cyyz = 0.0; + pass.cxzz = 0.0; + pass.cyzz = 0.0; + pass.cxyz = 0.0; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = 0.0; + pass.i1h1z = 0.0; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = 0.0; + pass.i1h2z = 0.0; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = 0.0; + pass.i2h11z = 0.0; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = 0.0; + pass.ih2f1f2z = 0.0; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + } + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* ib term over */ + /* loading ibb term */ + if ( !((model->BJTminBaseResist == 0.0) && + (model->BJTbaseResist == model->BJTminBaseResist))) { + + /* now x = vbe, y = vbc, z = vbb */ + r1h1z = *(job->r1H1ptr + (here->BJTbaseNode)) - + *(job->r1H1ptr + (here->BJTbasePrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTbaseNode)) - + *(job->i1H1ptr + (here->BJTbasePrimeNode)); + + r1hm2z = *(job->r1H2ptr + (here->BJTbaseNode)) - + *(job->r1H2ptr + (here->BJTbasePrimeNode)); + i1hm2z = -(*(job->i1H2ptr + (here->BJTbaseNode)) - + *(job->i1H2ptr + (here->BJTbasePrimeNode))); + + r2h11z = *(job->r2H11ptr + (here->BJTbaseNode)) - + *(job->r2H11ptr + (here->BJTbasePrimeNode)); + i2h11z = *(job->i2H11ptr + (here->BJTbaseNode)) - + *(job->i2H11ptr + (here->BJTbasePrimeNode)); + + r2h1m2z = *(job->r2H1m2ptr + (here->BJTbaseNode)) - + *(job->r2H1m2ptr + (here->BJTbasePrimeNode)); + i2h1m2z = *(job->i2H1m2ptr + (here->BJTbaseNode)) - + *(job->i2H1m2ptr + (here->BJTbasePrimeNode)); + + { + pass.cxx = here->ibb_x2; + pass.cyy = here->ibb_y2; + pass.czz = here->ibb_z2; + pass.cxy = here->ibb_xy; + pass.cyz = here->ibb_yz; + pass.cxz = here->ibb_xz; + pass.cxxx = here->ibb_x3; + pass.cyyy = here->ibb_y3; + pass.czzz = here->ibb_z3; + pass.cxxy = here->ibb_x2y; + pass.cxxz = here->ibb_x2z; + pass.cxyy = here->ibb_xy2; + pass.cyyz = here->ibb_y2z; + pass.cxzz = here->ibb_xz2; + pass.cyzz = here->ibb_yz2; + pass.cxyz = here->ibb_xyz; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = r1h1z; + pass.i1h1z = i1h1z; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = r1hm2z; + pass.i1h2z = i1hm2z; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = r2h11z; + pass.i2h11z = i2h11z; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = r2h1m2z; + pass.ih2f1f2z = i2h1m2z; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + } + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTbasePrimeNode) += temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) += itemp; + + } + /* ibb term over */ + /* loading qbe term */ + /* x = vbe, y = vbc, z not used */ + /* (have to multiply by j omega for charge storage + * elements to get the current) + */ + + { + pass.cxx = here->qbe_x2; + pass.cyy = here->qbe_y2; + pass.czz = 0.0; + pass.cxy = here->qbe_xy; + pass.cyz = 0.0; + pass.cxz = 0.0; + pass.cxxx = here->qbe_x3; + pass.cyyy = here->qbe_y3; + pass.czzz = 0.0; + pass.cxxy = here->qbe_x2y; + pass.cxxz = 0.0; + pass.cxyy = here->qbe_xy2; + pass.cyyz = 0.0; + pass.cxzz = 0.0; + pass.cyzz = 0.0; + pass.cxyz = 0.0; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = 0.0; + pass.i1h1z = 0.0; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = 0.0; + pass.i1h2z = 0.0; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = 0.0; + pass.i2h11z = 0.0; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = 0.0; + pass.ih2f1f2z = 0.0; + temp = - ckt->CKTomega* + DFi2F12(&pass); + + itemp = ckt->CKTomega* + DFn2F12(&pass); + } + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTemitPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTemitPrimeNode) += itemp; + + /* qbe term over */ + /* loading qbx term */ + /* z = vbx= vb - vcPrime */ + + r1h1z = r1h1z + r1h1y; + i1h1z = i1h1z + i1h1y; + r1hm2z = r1hm2z + r1hm2y; + i1hm2z = i1hm2z + i1hm2y; + r2h11z = r2h11z + r2h11y; + i2h11z = i2h11z + i2h11y; + r2h1m2z = r2h1m2z + r2h1m2y; + i2h1m2z = i2h1m2z + i2h1m2y; +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))(); +#endif + temp = - ckt->CKTomega * + D1i2F12(here->capbx2, + here->capbx3, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z, + r2h11z, + i2h11z, + r2h1m2z, + i2h1m2z); + itemp = ckt->CKTomega * + D1n2F12(here->capbx2, + here->capbx3, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z, + r2h11z, + i2h11z, + r2h1m2z, + i2h1m2z); +#ifdef D_DBG_SMALLTIMES + time = (*(SPfrontEnd->IFseconds))() - time; + printf("Time for D1n2F12: %g seconds \n", time); +#endif + + + *(ckt->CKTrhs + here->BJTbaseNode) -= temp; + *(ckt->CKTirhs + here->BJTbaseNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbx term over */ + + /* loading qbc term */ + + temp = - ckt->CKTomega * + D1i2F12(here->capbc2, + here->capbc3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + itemp = ckt->CKTomega * + D1n2F12(here->capbc2, + here->capbc3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + + + *(ckt->CKTrhs + here->BJTbasePrimeNode) -= temp; + *(ckt->CKTirhs + here->BJTbasePrimeNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qbc term over */ + + + /* loading qsc term */ + /* z = vsc */ + + + + r1h1z = *(job->r1H1ptr + (here->BJTsubstNode)) - + *(job->r1H1ptr + (here->BJTcolPrimeNode)); + i1h1z = *(job->i1H1ptr + (here->BJTsubstNode)) - + *(job->i1H1ptr + (here->BJTcolPrimeNode)); + + r1hm2z = *(job->r1H2ptr + (here->BJTsubstNode)) - + *(job->r1H2ptr + (here->BJTcolPrimeNode)); + i1hm2z = -(*(job->i1H2ptr + (here->BJTsubstNode)) - + *(job->i1H2ptr + (here->BJTcolPrimeNode))); + + r2h11z = *(job->r2H11ptr + (here->BJTsubstNode)) - + *(job->r2H11ptr + (here->BJTcolPrimeNode)); + i2h11z = *(job->i2H11ptr + (here->BJTsubstNode)) - + *(job->i2H11ptr + (here->BJTcolPrimeNode)); + + r2h1m2z = *(job->r2H1m2ptr + (here->BJTsubstNode)) - + *(job->r2H1m2ptr + (here->BJTcolPrimeNode)); + i2h1m2z = *(job->i2H1m2ptr + (here->BJTsubstNode)) - + *(job->i2H1m2ptr + (here->BJTcolPrimeNode)); + + temp = - ckt->CKTomega * + D1i2F12(here->capsc2, + here->capsc3, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z, + r2h11z, + i2h11z, + r2h1m2z, + i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capsc2, + here->capsc3, + r1h1z, + i1h1z, + r1hm2z, + i1hm2z, + r2h11z, + i2h11z, + r2h1m2z, + i2h1m2z); + + + *(ckt->CKTrhs + here->BJTsubstNode) -= temp; + *(ckt->CKTirhs + here->BJTsubstNode) -= itemp; + *(ckt->CKTrhs + here->BJTcolPrimeNode) += temp; + *(ckt->CKTirhs + here->BJTcolPrimeNode) += itemp; + + /* qsc term over */ + + + break; + default: + ; + ; + } + } + } + return(OK); + } + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/bjt/bjtdset.c b/src/spicelib/devices/bjt/bjtdset.c new file mode 100644 index 000000000..fae419274 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtdset.c @@ -0,0 +1,707 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "distodef.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +/* + * This function initialises the Taylor coeffs for the + * BJT's in the circuit + */ + +/* actually load the current resistance value into the sparse matrix + * previously provided */ +int +BJTdSetup(GENmodel *inModel, CKTcircuit *ckt) +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + double arg; + double c2; + double c4; + double lcapbe1,lcapbe2,lcapbe3; + double lcapbx1,lcapbx2,lcapbx3; + double cb; + double cbc; + double cbcn; + double cbe; + double cben; + double cdis; + double csat; + double ctot; + double czbc; + double czbcf2; + double czbe; + double czbef2; + double czbx; + double czbxf2; + double czcs; + double evbc; + double evbcn; + double evbe; + double evben; + double f1; + double f2; + double f3; + double fcpc; + double fcpe; + double gbb1; + double gbc; + double gbcn; + double gbe; + double gbe2,gbe3; + double gbc2,gbc3; + double gben2,gben3; + double gbcn2,gbcn3; + double gben; + double gbb2, gbb3; + double oik; + double oikr; + double ovtf; + double pc; + double pe; + double ps; + double q1; + double q2; + double qb; + double rbpi; + double rbpr; + double sarg; + double sqarg; + double tf; + double tr; + double vbc; + double vbe; + double vbx; + double vsc; + double vt; + double vtc; + double vte; + double vtn; + double xjrb; + double xjtf; + double xmc; + double xme; + double xms; + double xtf; + double vbed; + double vbb; + +double lcapbc1 = 0.0; +double lcapbc2 = 0.0; +double lcapbc3 = 0.0; + +double lcapsc1 = 0.0; +double lcapsc2 = 0.0; +double lcapsc3 = 0.0; +double ic; +double dummy; +Dderivs d_p, d_q, d_r; +Dderivs d_dummy, d_q1, d_qb, d_dummy2; +Dderivs d_arg, d_sqarg, d_ic, d_q2; +Dderivs d_z, d_tanz, d_vbb, d_ibb, d_rbb; +Dderivs d_ib, d_cbe, d_tff, d_qbe; + +d_p.value = 0.0; +d_p.d1_p = 1.0; +d_p.d1_q = 0.0; +d_p.d1_r = 0.0; +d_p.d2_p2 = 0.0; +d_p.d2_q2 = 0.0; +d_p.d2_r2 = 0.0; +d_p.d2_pq = 0.0; +d_p.d2_qr = 0.0; +d_p.d2_pr = 0.0; +d_p.d3_p3 = 0.0; +d_p.d3_q3 = 0.0; +d_p.d3_r3 = 0.0; +d_p.d3_p2q = 0.0; +d_p.d3_p2r = 0.0; +d_p.d3_pq2 = 0.0; +d_p.d3_q2r = 0.0; +d_p.d3_pr2 = 0.0; +d_p.d3_qr2 = 0.0; +d_p.d3_pqr = 0.0; + +EqualDeriv(&d_q, &d_p); +d_q.d1_q = 1.0; +d_q.d1_p = 0.0; + +EqualDeriv(&d_r, &d_p); +d_r.d1_r = 1.0; +d_r.d1_p = 0.0; + + +/* loop through all the models */ +for( ; model != NULL; model = model->BJTnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + + vt = here->BJTtemp * CONSTKoverQ; + + + /* + * dc model paramters + */ + csat=here->BJTtSatCur*here->BJTarea; + rbpr=model->BJTminBaseResist/here->BJTarea; + rbpi=model->BJTbaseResist/here->BJTarea-rbpr; + oik=model->BJTinvRollOffF/here->BJTarea; + c2=here->BJTtBEleakCur*here->BJTarea; + vte=model->BJTleakBEemissionCoeff*vt; + oikr=model->BJTinvRollOffR/here->BJTarea; + c4=here->BJTtBCleakCur*here->BJTarea; + vtc=model->BJTleakBCemissionCoeff*vt; + xjrb=model->BJTbaseCurrentHalfResist*here->BJTarea; + + + /* + * initialization + */ + vbe= model->BJTtype*(*(ckt->CKTrhsOld + here->BJTbasePrimeNode) - + *(ckt->CKTrhsOld + here->BJTemitPrimeNode)); + vbc= model->BJTtype*(*(ckt->CKTrhsOld + here->BJTbaseNode) - + *(ckt->CKTrhsOld + here->BJTcolPrimeNode)); + vbx=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbaseNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + vsc=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTsubstNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + + vbb=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbaseNode) - + *(ckt->CKTrhsOld+here->BJTbasePrimeNode)); + + + vbed = vbe; /* this is just a dummy variable + * it is the delayed vbe to be + * used in the delayed gm generator + */ + + + /* ic = f1(vbe,vbc,vbed) + f2(vbc) + f3(vbc) + * + * we shall calculate the taylor coeffs of + * ic wrt vbe, vbed, and vbc and store them away. + * the equations f1 f2 and f3 are given elsewhere; + * we shall start off with f1, compute + * derivs. upto third order and then do f2 and + * f3 and add their derivatives. + * + * Since f1 above is a function of three variables, it + * will be convenient to use derivative structures + * to compute the derivatives of f1. For this + * computation, p=vbe, q=vbc, r=vbed. + * + * ib = f1(vbe) + f2(vbc) (not the same f's as + * above, in case you are + * wondering!) + * the gbe's gbc's gben's and gbcn's are + * convenient subsidiary variables. + * + * irb = f(vbe, vbc, vbb) - the vbe & vbc + * dependencies arise from the + * qb term. + * qbe = f1(vbe,vbc) + f2(vbe) + * + * derivative structures will be used again in the + * above two equations. p=vbe, q=vbc, r=vbb. + * + * qbc = f(vbc) ; qbx = f(vbx) + * + * qss = f(vsc) + */ + /* + * determine dc current and derivitives + */ + vtn=vt*model->BJTemissionCoeffF; + if(vbe > -5*vtn){ + evbe=exp(vbe/vtn); + cbe=csat*(evbe-1)+ckt->CKTgmin*vbe; + gbe=csat*evbe/vtn+ckt->CKTgmin; + gbe2 = csat*evbe/vtn/vtn; + gbe3 = gbe2/vtn; + + /* note - these are actually derivs, not Taylor + * coeffs. - not divided by 2! and 3! + */ + if (c2 == 0) { + cben=0; + gben=gben2=gben3=0; + } else { + evben=exp(vbe/vte); + cben=c2*(evben-1); + gben=c2*evben/vte; + gben2=gben/vte; + gben3=gben2/vte; + } + } else { + gbe = -csat/vbe+ckt->CKTgmin; + gbe2=gbe3=gben2=gben3=0; + cbe=gbe*vbe; + gben = -c2/vbe; + cben=gben*vbe; + } + vtn=vt*model->BJTemissionCoeffR; + if(vbc > -5*vtn) { + evbc=exp(vbc/vtn); + cbc=csat*(evbc-1)+ckt->CKTgmin*vbc; + gbc=csat*evbc/vtn+ckt->CKTgmin; + gbc2=csat*evbc/vtn/vtn; + gbc3=gbc2/vtn; + if (c4 == 0) { + cbcn=0; + gbcn=0; + gbcn2=gbcn3=0; + } else { + evbcn=exp(vbc/vtc); + cbcn=c4*(evbcn-1); + gbcn=c4*evbcn/vtc; + gbcn2=gbcn/vtc; + gbcn3=gbcn2/vtc; + } + } else { + gbc = -csat/vbc+ckt->CKTgmin; + gbc2=gbc3=0; + cbc = gbc*vbc; + gbcn = -c4/vbc; + gbcn2=gbcn3=0; + cbcn=gbcn*vbc; + } + /* + * determine base charge terms + */ + /* q1 is a function of 2 variables p=vbe and q=vbc. r= + * anything + */ + q1=1/(1-model->BJTinvEarlyVoltF*vbc-model->BJTinvEarlyVoltR*vbe); + dummy = (1-model->BJTinvEarlyVoltF*vbc- + model->BJTinvEarlyVoltR*vbe); + EqualDeriv(&d_dummy, &d_p); + d_dummy.value = dummy; + d_dummy.d1_p = - model->BJTinvEarlyVoltR; + d_dummy.d1_q = - model->BJTinvEarlyVoltF; + /* q1 = 1/dummy */ + InvDeriv(&d_q1, &d_dummy); /* now q1 and its derivatives are + set up */ + if(oik == 0 && oikr == 0) { + qb=q1; + EqualDeriv(&d_qb, &d_q1); + } else { + q2=oik*cbe+oikr*cbc; + EqualDeriv(&d_q2, &d_p); + d_q2.value = q2; + d_q2.d1_p = oik*gbe; + d_q2.d1_q = oikr*gbc; + d_q2.d2_p2 = oik*gbe2; + d_q2.d2_q2 = oikr*gbc2; + d_q2.d3_p3 = oik*gbe3; + d_q2.d3_q3 = oikr*gbc3; + arg=MAX(0,1+4*q2); + if (arg == 0.) + { + EqualDeriv(&d_arg,&d_p); + d_arg.d1_p = 0.0; + } + else + { + TimesDeriv(&d_arg,&d_q2,4.0); + d_arg.value += 1.; + } + sqarg=1; + EqualDeriv(&d_sqarg,&d_p); + d_sqarg.value = 1.0; + d_sqarg.d1_p = 0.0; + if(arg != 0){ + sqarg=sqrt(arg); + SqrtDeriv(&d_sqarg, &d_arg); + } + + qb=q1*(1+sqarg)/2; + dummy = 1 + sqarg; + EqualDeriv(&d_dummy, &d_sqarg); + d_dummy.value += 1.0; + MultDeriv(&d_qb, &d_q1, &d_dummy); + TimesDeriv(&d_qb, &d_qb, 0.5); + } + +ic = (cbe - cbc)/qb; +/* cbe is a fn of vbed only; cbc of vbc; and qb of vbe and vbc */ +/* p=vbe, q=vbc, r=vbed; now dummy = cbe - cbc */ +EqualDeriv(&d_dummy, &d_p); +d_dummy.d1_p = 0.0; +d_dummy.value = cbe-cbc; +d_dummy.d1_r = gbe; +d_dummy.d2_r2 = gbe2; +d_dummy.d3_r3 = gbe3; +d_dummy.d1_q = -gbc; +d_dummy.d2_q2 = -gbc2; +d_dummy.d3_q3 = -gbc3; + +DivDeriv(&d_ic, &d_dummy, &d_qb); + + +d_ic.value -= cbc/here->BJTtBetaR + cbcn; +d_ic.d1_q -= gbc/here->BJTtBetaR + gbcn; +d_ic.d2_q2 -= gbc2/here->BJTtBetaR + gbcn2; +d_ic.d3_q3 -= gbc3/here->BJTtBetaR + gbcn3; + +/* check this point: where is the f2(vbe) contribution to ic ? */ + + /* ic derivatives all set up now */ + /* base spread resistance */ + + if ( !((rbpr == 0.0) && (rbpi == 0.0))) + { + cb=cbe/here->BJTtBetaF+cben+cbc/here->BJTtBetaR+cbcn; + /* we are calculating derivatives w.r.t cb itself */ + /* + gx=rbpr+rbpi/qb; + */ + + if (cb != 0.0) { + if((xjrb != 0.0) && (rbpi != 0.0)) { + /* p = ib, q, r = anything */ + dummy=MAX(cb/xjrb,1e-9); + EqualDeriv(&d_dummy, &d_p); + d_dummy.value = dummy; + d_dummy.d1_p = 1/xjrb; + SqrtDeriv(&d_dummy, &d_dummy); + TimesDeriv(&d_dummy, &d_dummy, 2.4317); + + /* + dummy2=(-1+sqrt(1+14.59025*MAX(cb/xjrb,1e-9))); + */ + EqualDeriv(&d_dummy2, &d_p); + d_dummy2.value = 1+14.59025*MAX(cb/xjrb,1e-9); + d_dummy2.d1_p = 14.59025/xjrb; + SqrtDeriv(&d_dummy2, &d_dummy2); + d_dummy2.value -= 1.0; + + DivDeriv(&d_z, &d_dummy2, &d_dummy); + TanDeriv(&d_tanz, &d_z); + + /*now using dummy = tanz - z and dummy2 = z*tanz*tanz */ + TimesDeriv(&d_dummy, &d_z, -1.0); + PlusDeriv(&d_dummy, &d_dummy, &d_tanz); + + MultDeriv(&d_dummy2, &d_tanz, &d_tanz); + MultDeriv(&d_dummy2, &d_dummy2, &d_z); + + DivDeriv(&d_rbb , &d_dummy, &d_dummy2); + TimesDeriv(&d_rbb,&d_rbb, 3.0*rbpi); + d_rbb.value += rbpr; + + MultDeriv(&d_vbb, &d_rbb, &d_p); + + /* power series inversion to get the conductance derivatives */ + + if (d_vbb.d1_p != 0) { + gbb1 = 1/d_vbb.d1_p; + gbb2 = -(d_vbb.d2_p2*0.5)*gbb1*gbb1; + gbb3 = gbb1*gbb1*gbb1*gbb1*(-(d_vbb.d3_p3/6.0) + + 2*(d_vbb.d2_p2*0.5)*(d_vbb.d2_p2*0.5)*gbb1); + } + else + printf("\nd_vbb.d1_p = 0 in base spread resistance calculations\n"); + + +/* r = vbb */ +EqualDeriv(&d_ibb, &d_r); +d_ibb.value = cb; +d_ibb.d1_r = gbb1; +d_ibb.d2_r2 = 2*gbb2; +d_ibb.d3_r3 = 6.0*gbb3; + } + else + { + /* + rbb = rbpr + rbpi/qb; + ibb = vbb /rbb; = f(vbe, vbc, vbb) + */ + + EqualDeriv(&d_rbb,&d_p); + d_rbb.d1_p = 0.0; + if (rbpi != 0.0) { + InvDeriv(&d_rbb, &d_qb); + TimesDeriv(&d_rbb, &d_rbb,rbpi); + } + d_rbb.value += rbpr; + + EqualDeriv(&d_ibb,&d_r); + d_ibb.value = vbb; + DivDeriv(&d_ibb,&d_ibb,&d_rbb); + + } + } + else + { + EqualDeriv(&d_ibb,&d_r); + if (rbpr != 0.0) + d_ibb.d1_r = 1/rbpr; + } + } + else + { + EqualDeriv(&d_ibb,&d_p); + d_ibb.d1_p = 0.0; + } + + /* formulae for base spread resistance over! */ + + /* ib term */ + + EqualDeriv(&d_ib, &d_p); + d_ib.d1_p = 0.0; + d_ib.value = cb; + d_ib.d1_p = gbe/here->BJTtBetaF + gben; + d_ib.d2_p2 = gbe2/here->BJTtBetaF + gben2; + d_ib.d3_p3 = gbe3/here->BJTtBetaF + gben3; + + d_ib.d1_q = gbc/here->BJTtBetaR + gbcn; + d_ib.d2_q2 = gbc2/here->BJTtBetaR + gbcn2; + d_ib.d3_q3 = gbc3/here->BJTtBetaR + gbcn3; + + /* ib term over */ + /* + * charge storage elements + */ + tf=model->BJTtransitTimeF; + tr=model->BJTtransitTimeR; + czbe=here->BJTtBEcap*here->BJTarea; + pe=here->BJTtBEpot; + xme=model->BJTjunctionExpBE; + cdis=model->BJTbaseFractionBCcap; + ctot=here->BJTtBCcap*here->BJTarea; + czbc=ctot*cdis; + czbx=ctot-czbc; + pc=here->BJTtBCpot; + xmc=model->BJTjunctionExpBC; + fcpe=here->BJTtDepCap; + czcs=model->BJTcapCS*here->BJTarea; + ps=model->BJTpotentialSubstrate; + xms=model->BJTexponentialSubstrate; + xtf=model->BJTtransitTimeBiasCoeffF; + ovtf=model->BJTtransitTimeVBCFactor; + xjtf=model->BJTtransitTimeHighCurrentF*here->BJTarea; + if(tf != 0 && vbe >0) { + EqualDeriv(&d_cbe, &d_p); + d_cbe.value = cbe; + d_cbe.d1_p = gbe; + d_cbe.d2_p2 = gbe2; + d_cbe.d3_p3 = gbe3; + if(xtf != 0){ + if(ovtf != 0) { + /* dummy = exp ( vbc*ovtf) */ + EqualDeriv(&d_dummy, &d_q); + d_dummy.value = vbc*ovtf; + d_dummy.d1_q = ovtf; + ExpDeriv(&d_dummy, &d_dummy); + } + else + { + EqualDeriv(&d_dummy,&d_p); + d_dummy.value = 1.0; + d_dummy.d1_p = 0.0; + } + if(xjtf != 0) { + EqualDeriv(&d_dummy2, &d_cbe); + d_dummy2.value += xjtf; + DivDeriv(&d_dummy2, &d_cbe, &d_dummy2); + MultDeriv (&d_dummy2, &d_dummy2, &d_dummy2); + } + else + { + EqualDeriv(&d_dummy2,&d_p); + d_dummy2.value = 1.0; + d_dummy2.d1_p = 0.0; + } + + MultDeriv(&d_tff, &d_dummy, &d_dummy2); + TimesDeriv(&d_tff, &d_tff, tf*xtf); + d_tff.value += tf; + } + else + { + EqualDeriv(&d_tff,&d_p); + d_tff.value = tf; + d_tff.d1_p = 0.0; + } + + + + + /* qbe = tff/qb*cbe */ + +/* + dummy = tff/qb; + */ + /* these are the cbe coeffs */ +DivDeriv(&d_dummy, &d_tff, &d_qb); +MultDeriv(&d_qbe, &d_dummy, &d_cbe); + + } + else + { + EqualDeriv(&d_qbe, &d_p); + d_qbe.value = 0.0; + d_qbe.d1_p = 0.0; + } + if (vbe < fcpe) { + arg=1-vbe/pe; + sarg=exp(-xme*log(arg)); + lcapbe1 = czbe*sarg; + lcapbe2 = + 0.5*czbe*xme*sarg/(arg*pe); + lcapbe3 = + czbe*xme*(xme+1)*sarg/(arg*arg*pe*pe*6); + } else { + f1=here->BJTtf1; + f2=model->BJTf2; + f3=model->BJTf3; + czbef2=czbe/f2; + lcapbe1 = czbef2*(f3+xme*vbe/pe); + lcapbe2 = 0.5*xme*czbef2/pe; + lcapbe3 = 0.0; + } + d_qbe.d1_p += lcapbe1; + d_qbe.d2_p2 += lcapbe2*2.; + d_qbe.d3_p3 += lcapbe3*6.; + + + fcpc=here->BJTtf4; + f1=here->BJTtf5; + f2=model->BJTf6; + f3=model->BJTf7; + if (vbc < fcpc) { + arg=1-vbc/pc; + sarg=exp(-xmc*log(arg)); + lcapbc1 = czbc*sarg; + lcapbc2 = + 0.5*czbc*xmc*sarg/(arg*pc); + lcapbc3 = + czbc*xmc*(xmc+1)*sarg/(arg*arg*pc*pc*6); + } else { + czbcf2=czbc/f2; + lcapbc1 = czbcf2*(f3+xmc*vbc/pc); + lcapbc2 = 0.5*xmc*czbcf2/pc; + lcapbc3 = 0; + } + if(vbx < fcpc) { + arg=1-vbx/pc; + sarg=exp(-xmc*log(arg)); + lcapbx1 = czbx*sarg; + lcapbx2 = + 0.5*czbx*xmc*sarg/(arg*pc); + lcapbx3 = + czbx*xmc*(xmc+1)*sarg/(arg*arg*pc*pc*6); + } else { + czbxf2=czbx/f2; + lcapbx1 = czbxf2*(f3+xmc*vbx/pc); + lcapbx2 = 0.5*xmc*czbxf2/pc; + lcapbx3 = 0; + } + if(vsc < 0){ + arg=1-vsc/ps; + sarg=exp(-xms*log(arg)); + lcapsc1 = czcs*sarg; + lcapsc2 = + 0.5*czcs*xms*sarg/(arg*ps); + lcapsc3 = + czcs*xms*(xms+1)*sarg/(arg*arg*ps*ps*6); + } else { + lcapsc1 = czcs*(1+xms*vsc/ps); + lcapsc2 = czcs*0.5*xms/ps; + lcapsc3 = 0; + } + + /* + * store small-signal parameters + */ +here->ic_x = d_ic.d1_p; +here->ic_y = d_ic.d1_q; +here->ic_xd = d_ic.d1_r; +here->ic_x2 = 0.5*model->BJTtype*d_ic.d2_p2; +here->ic_y2 = 0.5*model->BJTtype*d_ic.d2_q2; +here->ic_w2 = 0.5*model->BJTtype*d_ic.d2_r2; +here->ic_xy = model->BJTtype*d_ic.d2_pq; +here->ic_yw = model->BJTtype*d_ic.d2_qr; +here->ic_xw = model->BJTtype*d_ic.d2_pr; +here->ic_x3 = d_ic.d3_p3/6.; +here->ic_y3 = d_ic.d3_q3/6.; +here->ic_w3 = d_ic.d3_r3/6.; +here->ic_x2w = 0.5*d_ic.d3_p2r; +here->ic_x2y = 0.5*d_ic.d3_p2q; +here->ic_y2w = 0.5*d_ic.d3_q2r; +here->ic_xy2 = 0.5*d_ic.d3_pq2; +here->ic_xw2 = 0.5*d_ic.d3_pr2; +here->ic_yw2 = 0.5*d_ic.d3_qr2; +here->ic_xyw = d_ic.d3_pqr; + +here->ib_x = d_ib.d1_p; +here->ib_y = d_ib.d1_q; +here->ib_x2 = 0.5*model->BJTtype*d_ib.d2_p2; +here->ib_y2 = 0.5*model->BJTtype*d_ib.d2_q2; +here->ib_xy = model->BJTtype*d_ib.d2_pq; +here->ib_x3 = d_ib.d3_p3/6.; +here->ib_y3 = d_ib.d3_q3/6.; +here->ib_x2y = 0.5*d_ib.d3_p2q; +here->ib_xy2 = 0.5*d_ib.d3_pq2; + +here->ibb_x = d_ibb.d1_p; +here->ibb_y = d_ibb.d1_q; +here->ibb_z = d_ibb.d1_r; +here->ibb_x2 = 0.5*model->BJTtype*d_ibb.d2_p2; +here->ibb_y2 = 0.5*model->BJTtype*d_ibb.d2_q2; +here->ibb_z2 = 0.5*model->BJTtype*d_ibb.d2_r2; +here->ibb_xy = model->BJTtype*d_ibb.d2_pq; +here->ibb_yz = model->BJTtype*d_ibb.d2_qr; +here->ibb_xz = model->BJTtype*d_ibb.d2_pr; +here->ibb_x3 = d_ibb.d3_p3/6.; +here->ibb_y3 = d_ibb.d3_q3/6.; +here->ibb_z3 = d_ibb.d3_r3/6.; +here->ibb_x2z = 0.5*d_ibb.d3_p2r; +here->ibb_x2y = 0.5*d_ibb.d3_p2q; +here->ibb_y2z = 0.5*d_ibb.d3_q2r; +here->ibb_xy2 = 0.5*d_ibb.d3_pq2; +here->ibb_xz2 = 0.5*d_ibb.d3_pr2; +here->ibb_yz2 = 0.5*d_ibb.d3_qr2; +here->ibb_xyz = d_ibb.d3_pqr; + +here->qbe_x = d_qbe.d1_p; +here->qbe_y = d_qbe.d1_q; +here->qbe_x2 = 0.5*model->BJTtype*d_qbe.d2_p2; +here->qbe_y2 = 0.5*model->BJTtype*d_qbe.d2_q2; +here->qbe_xy = model->BJTtype*d_qbe.d2_pq; +here->qbe_x3 = d_qbe.d3_p3/6.; +here->qbe_y3 = d_qbe.d3_q3/6.; +here->qbe_x2y = 0.5*d_qbe.d3_p2q; +here->qbe_xy2 = 0.5*d_qbe.d3_pq2; + +here->capbc1 = lcapbc1; +here->capbc2 = lcapbc2; +here->capbc3 = lcapbc3; + +here->capbx1 = lcapbx1; +here->capbx2 = lcapbx2; +here->capbx3 = lcapbx3; + +here->capsc1 = lcapsc1; +here->capsc2 = lcapsc2; +here->capsc3 = lcapsc3; + } + } + return(OK); + } diff --git a/src/spicelib/devices/bjt/bjtdset.h b/src/spicelib/devices/bjt/bjtdset.h new file mode 100644 index 000000000..b13f82662 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtdset.h @@ -0,0 +1,6 @@ +#ifndef __BJTDSET_H +#define __BJTDSET_H + +int BJTdSetup(BJTmodel *inModel, CKTcircuit *ckt); + +#endif diff --git a/src/spicelib/devices/bjt/bjtext.h b/src/spicelib/devices/bjt/bjtext.h new file mode 100644 index 000000000..8e48adc2e --- /dev/null +++ b/src/spicelib/devices/bjt/bjtext.h @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int BJTacLoad(GENmodel *,CKTcircuit*); +extern int BJTask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int BJTconvTest(GENmodel*,CKTcircuit*); +extern int BJTdelete(GENmodel*,IFuid,GENinstance**); +extern void BJTdestroy(GENmodel**); +extern int BJTgetic(GENmodel*,CKTcircuit*); +extern int BJTload(GENmodel*,CKTcircuit*); +extern int BJTmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int BJTmDelete(GENmodel**,IFuid,GENmodel*); +extern int BJTmParam(int,IFvalue*,GENmodel*); +extern int BJTparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int BJTpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int BJTsAcLoad(GENmodel*,CKTcircuit*); +extern int BJTsLoad(GENmodel*,CKTcircuit*); +extern void BJTsPrint(GENmodel*,CKTcircuit*); +extern int BJTsSetup(SENstruct*,GENmodel*); +extern int BJTsUpdate(GENmodel*,CKTcircuit*); +extern int BJTsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int BJTunsetup(GENmodel*,CKTcircuit*); +extern int BJTtemp(GENmodel*,CKTcircuit*); +extern int BJTtrunc(GENmodel*,CKTcircuit*,double*); +extern int BJTdisto(int,GENmodel*,CKTcircuit*); +extern int BJTnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); +#else /* stdc */ +extern int BJTacLoad(); +extern int BJTask(); +extern int BJTconvTest(); +extern int BJTdelete(); +extern void BJTdestroy(); +extern int BJTgetic(); +extern int BJTload(); +extern int BJTmAsk(); +extern int BJTmDelete(); +extern int BJTmParam(); +extern int BJTparam(); +extern int BJTpzLoad(); +extern int BJTsAcLoad(); +extern int BJTsLoad(); +extern void BJTsPrint(); +extern int BJTsSetup(); +extern int BJTsUpdate(); +extern int BJTsetup(); +extern int BJTunsetup(); +extern int BJTtemp(); +extern int BJTtrunc(); +extern int BJTdisto(); +extern int BJTnoise(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/bjt/bjtgetic.c b/src/spicelib/devices/bjt/bjtgetic.c new file mode 100644 index 000000000..45d3cde95 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtgetic.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gets the device initial conditions for the BJTs + * from the RHS vector + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BJTgetic(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + +{ + + BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->BJTnextModel) { + for(here = model->BJTinstances; here ; here = here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + if(!here->BJTicVBEGiven) { + here->BJTicVBE = + *(ckt->CKTrhs + here->BJTbaseNode) - + *(ckt->CKTrhs + here->BJTemitNode); + } + if(!here->BJTicVCEGiven) { + here->BJTicVCE = + *(ckt->CKTrhs + here->BJTcolNode) - + *(ckt->CKTrhs + here->BJTemitNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtitf.h b/src/spicelib/devices/bjt/bjtitf.h new file mode 100644 index 000000000..f1e2c9181 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtitf.h @@ -0,0 +1,99 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_bjt + +#ifndef DEV_BJT +#define DEV_BJT + +#include "bjtext.h" +extern IFparm BJTpTable[ ]; +extern IFparm BJTmPTable[ ]; +extern char *BJTnames[ ]; +extern int BJTpTSize; +extern int BJTmPTSize; +extern int BJTnSize; +extern int BJTiSize; +extern int BJTmSize; + +SPICEdev BJTinfo = { + { "BJT", + "Bipolar Junction Transistor", + + &BJTnSize, + &BJTnSize, + BJTnames, + + &BJTpTSize, + BJTpTable, + + &BJTmPTSize, + BJTmPTable, + DEV_DEFAULT + }, + + BJTparam, + BJTmParam, + BJTload, + BJTsetup, + BJTunsetup, + BJTsetup, + BJTtemp, + BJTtrunc, + NULL, + BJTacLoad, + NULL, + BJTdestroy, +#ifdef DELETES + BJTmDelete, + BJTdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + BJTgetic, + BJTask, + BJTmAsk, +#ifdef AN_pz + BJTpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + BJTconvTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + +#ifdef AN_sense2 + BJTsSetup, + BJTsLoad, + BJTsUpdate, + BJTsAcLoad, + BJTsPrint, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ + NULL, +#ifdef AN_disto + BJTdisto, +#else /* AN_disto */ + NULL, +#endif /* AN_disto */ +#ifdef AN_noise + BJTnoise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &BJTiSize, + &BJTmSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/bjt/bjtload.c b/src/spicelib/devices/bjt/bjtload.c new file mode 100644 index 000000000..3e8d4ef5a --- /dev/null +++ b/src/spicelib/devices/bjt/bjtload.c @@ -0,0 +1,754 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * This is the function called each iteration to evaluate the + * BJTs in the circuit and load them into the matrix as appropriate + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "trandefs.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +BJTload(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + double arg1; + double arg2; + double arg3; + double arg; + double argtf; + double c2; + double c4; + double capbc; + double capbe; + double capbx=0; + double capcs=0; + double cb; + double cbc; + double cbcn; + double cbe; + double cben; + double cbhat; + double cc; + double cchat; + double cdis; + double ceq; + double ceqbc; + double ceqbe; + double ceqbx; + double ceqcs; + double cex; + double csat; + double ctot; + double czbc; + double czbcf2; + double czbe; + double czbef2; + double czbx; + double czbxf2; + double czcs; + double delvbc; + double delvbe; + double denom; + double dqbdvc; + double dqbdve; + double evbc; + double evbcn; + double evbe; + double evben; + double f1; + double f2; + double f3; + double fcpc; + double fcpe; + double gbc; + double gbcn; + double gbe; + double gben; + double gccs; + double gcpr; + double gepr; + double geq; + double geqbx; + double geqcb; + double gex; + double gm; + double gmu; + double go; + double gpi; + double gx; + double oik; + double oikr; + double ovtf; + double pc; + double pe; + double ps; + double q1; + double q2; + double qb; + double rbpi; + double rbpr; + double sarg; + double sqarg; + double td; + double temp; + double tf; + double tr; + double vbc; + double vbe; + double vbx; + double vce; + double vcs; + double vt; + double vtc; + double vte; + double vtn; + double xfact; + double xjrb; + double xjtf; + double xmc; + double xme; + double xms; + double xtf; + int icheck; + int ichk1; + int error; + int SenCond=0; + /* loop through all the models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + vt = here->BJTtemp * CONSTKoverQ; + + if(ckt->CKTsenInfo){ +#ifdef SENSDEBUG + printf("BJTload \n"); +#endif /* SENSDEBUG */ + + if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&& + (here->BJTsenPertFlag == OFF)) continue; + SenCond = here->BJTsenPertFlag; + } + + + gccs=0; + ceqcs=0; + geqbx=0; + ceqbx=0; + geqcb=0; + /* + * dc model paramters + */ + csat=here->BJTtSatCur*here->BJTarea; + rbpr=model->BJTminBaseResist/here->BJTarea; + rbpi=model->BJTbaseResist/here->BJTarea-rbpr; + gcpr=model->BJTcollectorConduct*here->BJTarea; + gepr=model->BJTemitterConduct*here->BJTarea; + oik=model->BJTinvRollOffF/here->BJTarea; + c2=here->BJTtBEleakCur*here->BJTarea; + vte=model->BJTleakBEemissionCoeff*vt; + oikr=model->BJTinvRollOffR/here->BJTarea; + c4=here->BJTtBCleakCur*here->BJTarea; + vtc=model->BJTleakBCemissionCoeff*vt; + td=model->BJTexcessPhaseFactor; + xjrb=model->BJTbaseCurrentHalfResist*here->BJTarea; + + if(SenCond){ +#ifdef SENSDEBUG + printf("BJTsenPertFlag = ON \n"); +#endif /* SENSDEBUG */ + + if((ckt->CKTsenInfo->SENmode == TRANSEN)&& + (ckt->CKTmode & MODEINITTRAN)) { + vbe = *(ckt->CKTstate1 + here->BJTvbe); + vbc = *(ckt->CKTstate1 + here->BJTvbc); + vbx=model->BJTtype*( + *(ckt->CKTrhsOp+here->BJTbaseNode)- + *(ckt->CKTrhsOp+here->BJTcolPrimeNode)); + vcs=model->BJTtype*( + *(ckt->CKTrhsOp+here->BJTsubstNode)- + *(ckt->CKTrhsOp+here->BJTcolPrimeNode)); + } + else{ + vbe = *(ckt->CKTstate0 + here->BJTvbe); + vbc = *(ckt->CKTstate0 + here->BJTvbc); + if((ckt->CKTsenInfo->SENmode == DCSEN)|| + (ckt->CKTsenInfo->SENmode == TRANSEN)){ + vbx=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbaseNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + vcs=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTsubstNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + } + if(ckt->CKTsenInfo->SENmode == ACSEN){ + vbx=model->BJTtype*( + *(ckt->CKTrhsOp+here->BJTbaseNode)- + *(ckt->CKTrhsOp+here->BJTcolPrimeNode)); + vcs=model->BJTtype*( + *(ckt->CKTrhsOp+here->BJTsubstNode)- + *(ckt->CKTrhsOp+here->BJTcolPrimeNode)); + } + } + goto next1; + } + + /* + * initialization + */ + icheck=1; + if(ckt->CKTmode & MODEINITSMSIG) { + vbe= *(ckt->CKTstate0 + here->BJTvbe); + vbc= *(ckt->CKTstate0 + here->BJTvbc); + vbx=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbaseNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + vcs=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTsubstNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + } else if(ckt->CKTmode & MODEINITTRAN) { + vbe = *(ckt->CKTstate1 + here->BJTvbe); + vbc = *(ckt->CKTstate1 + here->BJTvbc); + vbx=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbaseNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + vcs=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTsubstNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + if( (ckt->CKTmode & MODETRAN) && (ckt->CKTmode & MODEUIC) ) { + vbx=model->BJTtype*(here->BJTicVBE-here->BJTicVCE); + vcs=0; + } + } else if((ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)){ + vbe=model->BJTtype*here->BJTicVBE; + vce=model->BJTtype*here->BJTicVCE; + vbc=vbe-vce; + vbx=vbc; + vcs=0; + } else if((ckt->CKTmode & MODEINITJCT) && (here->BJToff==0)) { + vbe=here->BJTtVcrit; + vbc=0; + /* ERROR: need to initialize VCS, VBX here */ + vcs=vbx=0; + } else if((ckt->CKTmode & MODEINITJCT) || + ( (ckt->CKTmode & MODEINITFIX) && (here->BJToff!=0))) { + vbe=0; + vbc=0; + /* ERROR: need to initialize VCS, VBX here */ + vcs=vbx=0; + } else { +#ifndef PREDICTOR + if(ckt->CKTmode & MODEINITPRED) { + xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->BJTvbe) = + *(ckt->CKTstate1 + here->BJTvbe); + vbe = (1+xfact)**(ckt->CKTstate1 + here->BJTvbe)- + xfact* *(ckt->CKTstate2 + here->BJTvbe); + *(ckt->CKTstate0 + here->BJTvbc) = + *(ckt->CKTstate1 + here->BJTvbc); + vbc = (1+xfact)**(ckt->CKTstate1 + here->BJTvbc)- + xfact* *(ckt->CKTstate2 + here->BJTvbc); + *(ckt->CKTstate0 + here->BJTcc) = + *(ckt->CKTstate1 + here->BJTcc); + *(ckt->CKTstate0 + here->BJTcb) = + *(ckt->CKTstate1 + here->BJTcb); + *(ckt->CKTstate0 + here->BJTgpi) = + *(ckt->CKTstate1 + here->BJTgpi); + *(ckt->CKTstate0 + here->BJTgmu) = + *(ckt->CKTstate1 + here->BJTgmu); + *(ckt->CKTstate0 + here->BJTgm) = + *(ckt->CKTstate1 + here->BJTgm); + *(ckt->CKTstate0 + here->BJTgo) = + *(ckt->CKTstate1 + here->BJTgo); + *(ckt->CKTstate0 + here->BJTgx) = + *(ckt->CKTstate1 + here->BJTgx); + } else { +#endif /* PREDICTOR */ + /* + * compute new nonlinear branch voltages + */ + vbe=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- + *(ckt->CKTrhsOld+here->BJTemitPrimeNode)); + vbc=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbasePrimeNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + delvbe=vbe- *(ckt->CKTstate0 + here->BJTvbe); + delvbc=vbc- *(ckt->CKTstate0 + here->BJTvbc); + vbx=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTbaseNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + vcs=model->BJTtype*( + *(ckt->CKTrhsOld+here->BJTsubstNode)- + *(ckt->CKTrhsOld+here->BJTcolPrimeNode)); + cchat= *(ckt->CKTstate0 + here->BJTcc)+(*(ckt->CKTstate0 + + here->BJTgm)+ *(ckt->CKTstate0 + here->BJTgo))*delvbe- + (*(ckt->CKTstate0 + here->BJTgo)+*(ckt->CKTstate0 + + here->BJTgmu))*delvbc; + cbhat= *(ckt->CKTstate0 + here->BJTcb)+ *(ckt->CKTstate0 + + here->BJTgpi)*delvbe+ *(ckt->CKTstate0 + here->BJTgmu)* + delvbc; +#ifndef NOBYPASS + /* + * bypass if solution has not changed + */ + /* the following collections of if's would be just one + * if the average compiler could handle it, but many + * find the expression too complicated, thus the split. + */ + if( (ckt->CKTbypass) && + (!(ckt->CKTmode & MODEINITPRED)) && + (fabs(delvbe) < (ckt->CKTreltol*MAX(fabs(vbe), + fabs(*(ckt->CKTstate0 + here->BJTvbe)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvbc) < ckt->CKTreltol*MAX(fabs(vbc), + fabs(*(ckt->CKTstate0 + here->BJTvbc)))+ + ckt->CKTvoltTol) ) + if( (fabs(cchat-*(ckt->CKTstate0 + here->BJTcc)) < + ckt->CKTreltol* MAX(fabs(cchat), + fabs(*(ckt->CKTstate0 + here->BJTcc)))+ + ckt->CKTabstol) ) + if( (fabs(cbhat-*(ckt->CKTstate0 + here->BJTcb)) < + ckt->CKTreltol* MAX(fabs(cbhat), + fabs(*(ckt->CKTstate0 + here->BJTcb)))+ + ckt->CKTabstol) ) { + /* + * bypassing.... + */ + vbe = *(ckt->CKTstate0 + here->BJTvbe); + vbc = *(ckt->CKTstate0 + here->BJTvbc); + cc = *(ckt->CKTstate0 + here->BJTcc); + cb = *(ckt->CKTstate0 + here->BJTcb); + gpi = *(ckt->CKTstate0 + here->BJTgpi); + gmu = *(ckt->CKTstate0 + here->BJTgmu); + gm = *(ckt->CKTstate0 + here->BJTgm); + go = *(ckt->CKTstate0 + here->BJTgo); + gx = *(ckt->CKTstate0 + here->BJTgx); + geqcb = *(ckt->CKTstate0 + here->BJTgeqcb); + gccs = *(ckt->CKTstate0 + here->BJTgccs); + geqbx = *(ckt->CKTstate0 + here->BJTgeqbx); + goto load; + } +#endif /*NOBYPASS*/ + /* + * limit nonlinear branch voltages + */ + ichk1=1; + vbe = DEVpnjlim(vbe,*(ckt->CKTstate0 + here->BJTvbe),vt, + here->BJTtVcrit,&icheck); + vbc = DEVpnjlim(vbc,*(ckt->CKTstate0 + here->BJTvbc),vt, + here->BJTtVcrit,&ichk1); + if (ichk1 == 1) icheck=1; + } + /* + * determine dc current and derivitives + */ +next1: vtn=vt*model->BJTemissionCoeffF; + if(vbe > -5*vtn){ + evbe=exp(vbe/vtn); + cbe=csat*(evbe-1)+ckt->CKTgmin*vbe; + gbe=csat*evbe/vtn+ckt->CKTgmin; + if (c2 == 0) { + cben=0; + gben=0; + } else { + evben=exp(vbe/vte); + cben=c2*(evben-1); + gben=c2*evben/vte; + } + } else { + gbe = -csat/vbe+ckt->CKTgmin; + cbe=gbe*vbe; + gben = -c2/vbe; + cben=gben*vbe; + } + vtn=vt*model->BJTemissionCoeffR; + if(vbc > -5*vtn) { + evbc=exp(vbc/vtn); + cbc=csat*(evbc-1)+ckt->CKTgmin*vbc; + gbc=csat*evbc/vtn+ckt->CKTgmin; + if (c4 == 0) { + cbcn=0; + gbcn=0; + } else { + evbcn=exp(vbc/vtc); + cbcn=c4*(evbcn-1); + gbcn=c4*evbcn/vtc; + } + } else { + gbc = -csat/vbc+ckt->CKTgmin; + cbc = gbc*vbc; + gbcn = -c4/vbc; + cbcn=gbcn*vbc; + } + /* + * determine base charge terms + */ + q1=1/(1-model->BJTinvEarlyVoltF*vbc-model->BJTinvEarlyVoltR*vbe); + if(oik == 0 && oikr == 0) { + qb=q1; + dqbdve=q1*qb*model->BJTinvEarlyVoltR; + dqbdvc=q1*qb*model->BJTinvEarlyVoltF; + } else { + q2=oik*cbe+oikr*cbc; + arg=MAX(0,1+4*q2); + sqarg=1; + if(arg != 0) sqarg=sqrt(arg); + qb=q1*(1+sqarg)/2; + dqbdve=q1*(qb*model->BJTinvEarlyVoltR+oik*gbe/sqarg); + dqbdvc=q1*(qb*model->BJTinvEarlyVoltF+oikr*gbc/sqarg); + } + /* + * weil's approx. for excess phase applied with backward- + * euler integration + */ + cc=0; + cex=cbe; + gex=gbe; + if(ckt->CKTmode & (MODETRAN | MODEAC) && td != 0) { + arg1=ckt->CKTdelta/td; + arg2=3*arg1; + arg1=arg2*arg1; + denom=1+arg1+arg2; + arg3=arg1/denom; + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->BJTcexbc)=cbe/qb; + *(ckt->CKTstate2 + here->BJTcexbc)= + *(ckt->CKTstate1 + here->BJTcexbc); + } + cc=(*(ckt->CKTstate1 + here->BJTcexbc)*(1+ckt->CKTdelta/ + ckt->CKTdeltaOld[1]+arg2)- + *(ckt->CKTstate2 + here->BJTcexbc)*ckt->CKTdelta/ + ckt->CKTdeltaOld[1])/denom; + cex=cbe*arg3; + gex=gbe*arg3; + *(ckt->CKTstate0 + here->BJTcexbc)=cc+cex/qb; + } + /* + * determine dc incremental conductances + */ + cc=cc+(cex-cbc)/qb-cbc/here->BJTtBetaR-cbcn; + cb=cbe/here->BJTtBetaF+cben+cbc/here->BJTtBetaR+cbcn; + gx=rbpr+rbpi/qb; + if(xjrb != 0) { + arg1=MAX(cb/xjrb,1e-9); + arg2=(-1+sqrt(1+14.59025*arg1))/2.4317/sqrt(arg1); + arg1=tan(arg2); + gx=rbpr+3*rbpi*(arg1-arg2)/arg2/arg1/arg1; + } + if(gx != 0) gx=1/gx; + gpi=gbe/here->BJTtBetaF+gben; + gmu=gbc/here->BJTtBetaR+gbcn; + go=(gbc+(cex-cbc)*dqbdvc/qb)/qb; + gm=(gex-(cex-cbc)*dqbdve/qb)/qb-go; + if( (ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) || + (ckt->CKTmode & MODEINITSMSIG)) { + /* + * charge storage elements + */ + tf=model->BJTtransitTimeF; + tr=model->BJTtransitTimeR; + czbe=here->BJTtBEcap*here->BJTarea; + pe=here->BJTtBEpot; + xme=model->BJTjunctionExpBE; + cdis=model->BJTbaseFractionBCcap; + ctot=here->BJTtBCcap*here->BJTarea; + czbc=ctot*cdis; + czbx=ctot-czbc; + pc=here->BJTtBCpot; + xmc=model->BJTjunctionExpBC; + fcpe=here->BJTtDepCap; + czcs=model->BJTcapCS*here->BJTarea; + ps=model->BJTpotentialSubstrate; + xms=model->BJTexponentialSubstrate; + xtf=model->BJTtransitTimeBiasCoeffF; + ovtf=model->BJTtransitTimeVBCFactor; + xjtf=model->BJTtransitTimeHighCurrentF*here->BJTarea; + if(tf != 0 && vbe >0) { + argtf=0; + arg2=0; + arg3=0; + if(xtf != 0){ + argtf=xtf; + if(ovtf != 0) { + argtf=argtf*exp(vbc*ovtf); + } + arg2=argtf; + if(xjtf != 0) { + temp=cbe/(cbe+xjtf); + argtf=argtf*temp*temp; + arg2=argtf*(3-temp-temp); + } + arg3=cbe*argtf*ovtf; + } + cbe=cbe*(1+argtf)/qb; + gbe=(gbe*(1+arg2)-cbe*dqbdve)/qb; + geqcb=tf*(arg3-cbe*dqbdvc)/qb; + } + if (vbe < fcpe) { + arg=1-vbe/pe; + sarg=exp(-xme*log(arg)); + *(ckt->CKTstate0 + here->BJTqbe)=tf*cbe+pe*czbe* + (1-arg*sarg)/(1-xme); + capbe=tf*gbe+czbe*sarg; + } else { + f1=here->BJTtf1; + f2=model->BJTf2; + f3=model->BJTf3; + czbef2=czbe/f2; + *(ckt->CKTstate0 + here->BJTqbe) = tf*cbe+czbe*f1+czbef2* + (f3*(vbe-fcpe) +(xme/(pe+pe))*(vbe*vbe-fcpe*fcpe)); + capbe=tf*gbe+czbef2*(f3+xme*vbe/pe); + } + fcpc=here->BJTtf4; + f1=here->BJTtf5; + f2=model->BJTf6; + f3=model->BJTf7; + if (vbc < fcpc) { + arg=1-vbc/pc; + sarg=exp(-xmc*log(arg)); + *(ckt->CKTstate0 + here->BJTqbc) = tr*cbc+pc*czbc*( + 1-arg*sarg)/(1-xmc); + capbc=tr*gbc+czbc*sarg; + } else { + czbcf2=czbc/f2; + *(ckt->CKTstate0 + here->BJTqbc) = tr*cbc+czbc*f1+czbcf2* + (f3*(vbc-fcpc) +(xmc/(pc+pc))*(vbc*vbc-fcpc*fcpc)); + capbc=tr*gbc+czbcf2*(f3+xmc*vbc/pc); + } + if(vbx < fcpc) { + arg=1-vbx/pc; + sarg=exp(-xmc*log(arg)); + *(ckt->CKTstate0 + here->BJTqbx)= + pc*czbx* (1-arg*sarg)/(1-xmc); + capbx=czbx*sarg; + } else { + czbxf2=czbx/f2; + *(ckt->CKTstate0 + here->BJTqbx)=czbx*f1+czbxf2* + (f3*(vbx-fcpc)+(xmc/(pc+pc))*(vbx*vbx-fcpc*fcpc)); + capbx=czbxf2*(f3+xmc*vbx/pc); + } + if(vcs < 0){ + arg=1-vcs/ps; + sarg=exp(-xms*log(arg)); + *(ckt->CKTstate0 + here->BJTqcs) = ps*czcs*(1-arg*sarg)/ + (1-xms); + capcs=czcs*sarg; + } else { + *(ckt->CKTstate0 + here->BJTqcs) = vcs*czcs*(1+xms*vcs/ + (2*ps)); + capcs=czcs*(1+xms*vcs/ps); + } + here->BJTcapbe = capbe; + here->BJTcapbc = capbc; + here->BJTcapcs = capcs; + here->BJTcapbx = capbx; + + /* + * store small-signal parameters + */ + if ( (!(ckt->CKTmode & MODETRANOP))|| + (!(ckt->CKTmode & MODEUIC)) ) { + if(ckt->CKTmode & MODEINITSMSIG) { + *(ckt->CKTstate0 + here->BJTcqbe) = capbe; + *(ckt->CKTstate0 + here->BJTcqbc) = capbc; + *(ckt->CKTstate0 + here->BJTcqcs) = capcs; + *(ckt->CKTstate0 + here->BJTcqbx) = capbx; + *(ckt->CKTstate0 + here->BJTcexbc) = geqcb; + if(SenCond){ + *(ckt->CKTstate0 + here->BJTcc) = cc; + *(ckt->CKTstate0 + here->BJTcb) = cb; + *(ckt->CKTstate0 + here->BJTgpi) = gpi; + *(ckt->CKTstate0 + here->BJTgmu) = gmu; + *(ckt->CKTstate0 + here->BJTgm) = gm; + *(ckt->CKTstate0 + here->BJTgo) = go; + *(ckt->CKTstate0 + here->BJTgx) = gx; + *(ckt->CKTstate0 + here->BJTgccs) = gccs; + *(ckt->CKTstate0 + here->BJTgeqbx) = geqbx; + } +#ifdef SENSDEBUG + printf("storing small signal parameters for op\n"); + printf("capbe = %.7e ,capbc = %.7e\n",capbe,capbc); + printf("capcs = %.7e ,capbx = %.7e\n",capcs,capbx); + printf("geqcb = %.7e ,gpi = %.7e\n",geqcb,gpi); + printf("gmu = %.7e ,gm = %.7e\n",gmu,gm); + printf("go = %.7e ,gx = %.7e\n",go,gx); + printf("gccs = %.7e ,geqbx = %.7e\n",gccs,geqbx); + printf("cc = %.7e ,cb = %.7e\n",cc,cb); +#endif /* SENSDEBUG */ + continue; /* go to 1000 */ + } + /* + * transient analysis + */ + if(SenCond && ckt->CKTsenInfo->SENmode == TRANSEN){ + *(ckt->CKTstate0 + here->BJTcc) = cc; + *(ckt->CKTstate0 + here->BJTcb) = cb; + *(ckt->CKTstate0 + here->BJTgx) = gx; + continue; + } + + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->BJTqbe) = + *(ckt->CKTstate0 + here->BJTqbe) ; + *(ckt->CKTstate1 + here->BJTqbc) = + *(ckt->CKTstate0 + here->BJTqbc) ; + *(ckt->CKTstate1 + here->BJTqbx) = + *(ckt->CKTstate0 + here->BJTqbx) ; + *(ckt->CKTstate1 + here->BJTqcs) = + *(ckt->CKTstate0 + here->BJTqcs) ; + } + error = NIintegrate(ckt,&geq,&ceq,capbe,here->BJTqbe); + if(error) return(error); + geqcb=geqcb*ckt->CKTag[0]; + gpi=gpi+geq; + cb=cb+*(ckt->CKTstate0 + here->BJTcqbe); + error = NIintegrate(ckt,&geq,&ceq,capbc,here->BJTqbc); + if(error) return(error); + gmu=gmu+geq; + cb=cb+*(ckt->CKTstate0 + here->BJTcqbc); + cc=cc-*(ckt->CKTstate0 + here->BJTcqbc); + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->BJTcqbe) = + *(ckt->CKTstate0 + here->BJTcqbe); + *(ckt->CKTstate1 + here->BJTcqbc) = + *(ckt->CKTstate0 + here->BJTcqbc); + } + } + } + + if(SenCond) goto next2; + + /* + * check convergence + */ + if ( (!(ckt->CKTmode & MODEINITFIX))||(!(here->BJToff))) { + if (icheck == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV + } else { + tol=ckt->CKTreltol*MAX(fabs(cchat),fabs(cc))+ckt->CKTabstol; + if (fabs(cchat-cc) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } else { + tol=ckt->CKTreltol*MAX(fabs(cbhat),fabs(cb))+ + ckt->CKTabstol; + if (fabs(cbhat-cb) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } +#endif /* NEWCONV */ + } + } + + /* + * charge storage for c-s and b-x junctions + */ + if(ckt->CKTmode & (MODETRAN | MODEAC)) { + error = NIintegrate(ckt,&gccs,&ceq,capcs,here->BJTqcs); + if(error) return(error); + error = NIintegrate(ckt,&geqbx,&ceq,capbx,here->BJTqbx); + if(error) return(error); + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->BJTcqbx) = + *(ckt->CKTstate0 + here->BJTcqbx); + *(ckt->CKTstate1 + here->BJTcqcs) = + *(ckt->CKTstate0 + here->BJTcqcs); + } + } +next2: + *(ckt->CKTstate0 + here->BJTvbe) = vbe; + *(ckt->CKTstate0 + here->BJTvbc) = vbc; + *(ckt->CKTstate0 + here->BJTcc) = cc; + *(ckt->CKTstate0 + here->BJTcb) = cb; + *(ckt->CKTstate0 + here->BJTgpi) = gpi; + *(ckt->CKTstate0 + here->BJTgmu) = gmu; + *(ckt->CKTstate0 + here->BJTgm) = gm; + *(ckt->CKTstate0 + here->BJTgo) = go; + *(ckt->CKTstate0 + here->BJTgx) = gx; + *(ckt->CKTstate0 + here->BJTgeqcb) = geqcb; + *(ckt->CKTstate0 + here->BJTgccs) = gccs; + *(ckt->CKTstate0 + here->BJTgeqbx) = geqbx; + + /* Do not load the Jacobian and the rhs if + perturbation is being carried out */ + + if(SenCond)continue; +load: + /* + * load current excitation vector + */ + ceqcs=model->BJTtype * (*(ckt->CKTstate0 + here->BJTcqcs) - + vcs * gccs); + ceqbx=model->BJTtype * (*(ckt->CKTstate0 + here->BJTcqbx) - + vbx * geqbx); + ceqbe=model->BJTtype * (cc + cb - vbe * (gm + go + gpi) + vbc * + (go - geqcb)); + ceqbc=model->BJTtype * (-cc + vbe * (gm + go) - vbc * (gmu + go)); + + *(ckt->CKTrhs + here->BJTbaseNode) += (-ceqbx); + *(ckt->CKTrhs + here->BJTcolPrimeNode) += + (ceqcs+ceqbx+ceqbc); + *(ckt->CKTrhs + here->BJTbasePrimeNode) += + (-ceqbe-ceqbc); + *(ckt->CKTrhs + here->BJTemitPrimeNode) += (ceqbe); + *(ckt->CKTrhs + here->BJTsubstNode) += (-ceqcs); + /* + * load y matrix + */ + *(here->BJTcolColPtr) += (gcpr); + *(here->BJTbaseBasePtr) += (gx+geqbx); + *(here->BJTemitEmitPtr) += (gepr); + *(here->BJTcolPrimeColPrimePtr) += (gmu+go+gcpr+gccs+geqbx); + *(here->BJTbasePrimeBasePrimePtr) += (gx +gpi+gmu+geqcb); + *(here->BJTemitPrimeEmitPrimePtr) += (gpi+gepr+gm+go); + *(here->BJTcolColPrimePtr) += (-gcpr); + *(here->BJTbaseBasePrimePtr) += (-gx); + *(here->BJTemitEmitPrimePtr) += (-gepr); + *(here->BJTcolPrimeColPtr) += (-gcpr); + *(here->BJTcolPrimeBasePrimePtr) += (-gmu+gm); + *(here->BJTcolPrimeEmitPrimePtr) += (-gm-go); + *(here->BJTbasePrimeBasePtr) += (-gx); + *(here->BJTbasePrimeColPrimePtr) += (-gmu-geqcb); + *(here->BJTbasePrimeEmitPrimePtr) += (-gpi); + *(here->BJTemitPrimeEmitPtr) += (-gepr); + *(here->BJTemitPrimeColPrimePtr) += (-go+geqcb); + *(here->BJTemitPrimeBasePrimePtr) += (-gpi-gm-geqcb); + *(here->BJTsubstSubstPtr) += (gccs); + *(here->BJTcolPrimeSubstPtr) += (-gccs); + *(here->BJTsubstColPrimePtr) += (-gccs); + *(here->BJTbaseColPrimePtr) += (-geqbx); + *(here->BJTcolPrimeBasePtr) += (-geqbx); + } + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtmask.c b/src/spicelib/devices/bjt/bjtmask.c new file mode 100644 index 000000000..6727a084b --- /dev/null +++ b/src/spicelib/devices/bjt/bjtmask.c @@ -0,0 +1,200 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +BJTmAsk(ckt,instPtr,which,value) + CKTcircuit *ckt; + GENmodel *instPtr; + int which; + IFvalue *value; +{ + BJTmodel *here = (BJTmodel*)instPtr; + + switch(which) { + case BJT_MOD_TNOM: + value->rValue = here->BJTtnom-CONSTCtoK; + return(OK); + case BJT_MOD_IS: + value->rValue = here->BJTsatCur; + return(OK); + case BJT_MOD_BF: + value->rValue = here->BJTbetaF; + return(OK); + case BJT_MOD_NF: + value->rValue = here->BJTemissionCoeffF; + return(OK); + case BJT_MOD_VAF: + value->rValue = here->BJTearlyVoltF; + return(OK); + case BJT_MOD_IKF: + value->rValue = here->BJTrollOffF; + return(OK); + case BJT_MOD_ISE: + value->rValue = here->BJTleakBEcurrent; + return(OK); + case BJT_MOD_C2: + value->rValue = here->BJTc2; + return(OK); + case BJT_MOD_NE: + value->rValue = here->BJTleakBEemissionCoeff; + return(OK); + case BJT_MOD_BR: + value->rValue = here->BJTbetaR; + return(OK); + case BJT_MOD_NR: + value->rValue = here->BJTemissionCoeffR; + return(OK); + case BJT_MOD_VAR: + value->rValue = here->BJTearlyVoltR; + return(OK); + case BJT_MOD_IKR: + value->rValue = here->BJTrollOffR; + return(OK); + case BJT_MOD_ISC: + value->rValue = here->BJTleakBCcurrent; + return(OK); + case BJT_MOD_C4: + value->rValue = here->BJTc4; + return(OK); + case BJT_MOD_NC: + value->rValue = here->BJTleakBCemissionCoeff; + return(OK); + case BJT_MOD_RB: + value->rValue = here->BJTbaseResist; + return(OK); + case BJT_MOD_IRB: + value->rValue = here->BJTbaseCurrentHalfResist; + return(OK); + case BJT_MOD_RBM: + value->rValue = here->BJTminBaseResist; + return(OK); + case BJT_MOD_RE: + value->rValue = here->BJTemitterResist; + return(OK); + case BJT_MOD_RC: + value->rValue = here->BJTcollectorResist; + return(OK); + case BJT_MOD_CJE: + value->rValue = here->BJTdepletionCapBE; + return(OK); + case BJT_MOD_VJE: + value->rValue = here->BJTpotentialBE; + return(OK); + case BJT_MOD_MJE: + value->rValue = here->BJTjunctionExpBE; + return(OK); + case BJT_MOD_TF: + value->rValue = here->BJTtransitTimeF; + return(OK); + case BJT_MOD_XTF: + value->rValue = here->BJTtransitTimeBiasCoeffF; + return(OK); + case BJT_MOD_VTF: + value->rValue = here->BJTtransitTimeFVBC; + return(OK); + case BJT_MOD_ITF: + value->rValue = here->BJTtransitTimeHighCurrentF; + return(OK); + case BJT_MOD_PTF: + value->rValue = here->BJTexcessPhase; + return(OK); + case BJT_MOD_CJC: + value->rValue = here->BJTdepletionCapBC; + return(OK); + case BJT_MOD_VJC: + value->rValue = here->BJTpotentialBC; + return(OK); + case BJT_MOD_MJC: + value->rValue = here->BJTjunctionExpBC; + return(OK); + case BJT_MOD_XCJC: + value->rValue = here->BJTbaseFractionBCcap; + return(OK); + case BJT_MOD_TR: + value->rValue = here->BJTtransitTimeR; + return(OK); + case BJT_MOD_CJS: + value->rValue = here->BJTcapCS; + return(OK); + case BJT_MOD_VJS: + value->rValue = here->BJTpotentialSubstrate; + return(OK); + case BJT_MOD_MJS: + value->rValue = here->BJTexponentialSubstrate; + return(OK); + case BJT_MOD_XTB: + value->rValue = here->BJTbetaExp; + return(OK); + case BJT_MOD_EG: + value->rValue = here->BJTenergyGap; + return(OK); + case BJT_MOD_XTI: + value->rValue = here->BJTtempExpIS; + return(OK); + case BJT_MOD_FC: + value->rValue = here->BJTdepletionCapCoeff; + return(OK); + case BJT_MOD_INVEARLYF: + value->rValue = here->BJTinvEarlyVoltF; + return(OK); + case BJT_MOD_INVEARLYR: + value->rValue = here->BJTinvEarlyVoltR; + return(OK); + case BJT_MOD_INVROLLOFFF: + value->rValue = here->BJTinvRollOffF; + return(OK); + case BJT_MOD_INVROLLOFFR: + value->rValue = here->BJTinvRollOffR; + return(OK); + case BJT_MOD_COLCONDUCT: + value->rValue = here->BJTcollectorConduct; + return(OK); + case BJT_MOD_EMITTERCONDUCT: + value->rValue = here->BJTemitterConduct; + return(OK); + case BJT_MOD_TRANSVBCFACT: + value->rValue = here->BJTtransitTimeVBCFactor; + return(OK); + case BJT_MOD_EXCESSPHASEFACTOR: + value->rValue = here->BJTexcessPhaseFactor; + return(OK); + case BJT_MOD_KF: + if (here->BJTfNcoefGiven) + value->rValue = here->BJTfNcoef; + else + value->rValue = 0.0; + return(OK); + case BJT_MOD_AF: + if (here->BJTfNexpGiven) + value->rValue = here->BJTfNexp; + else + value->rValue = 0.0; + return(OK); + case BJT_MOD_TYPE: + if (here->BJTtype == NPN) + value->sValue = "npn"; + else + value->sValue = "pnp"; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bjt/bjtmdel.c b/src/spicelib/devices/bjt/bjtmdel.c new file mode 100644 index 000000000..c57bf48c1 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtmdel.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine deletes a BJT model from the circuit and frees + * the storage it was using. + * returns an error if the model has instances + */ + +#include "ngspice.h" +#include +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BJTmDelete(inModels,modname,kill) + GENmodel **inModels; + IFuid modname; + GENmodel *kill; + +{ + BJTmodel **model = (BJTmodel**)inModels; + BJTmodel *modfast = (BJTmodel*)kill; + + BJTmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->BJTnextModel)) { + if( (*model)->BJTmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + if( (*model)->BJTinstances ) return(E_NOTEMPTY); + *oldmod = (*model)->BJTnextModel; /* cut deleted device out of list */ + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/bjt/bjtmpar.c b/src/spicelib/devices/bjt/bjtmpar.c new file mode 100644 index 000000000..5bd74ea45 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtmpar.c @@ -0,0 +1,217 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine sets model parameters for + * BJTs in the circuit. + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BJTmParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + BJTmodel *mods = (BJTmodel*)inModel; + + switch(param) { + case BJT_MOD_NPN: + if(value->iValue) { + mods->BJTtype = NPN; + } + break; + case BJT_MOD_PNP: + if(value->iValue) { + mods->BJTtype = PNP; + } + break; + case BJT_MOD_TNOM: + mods->BJTtnom = value->rValue+CONSTCtoK; + mods->BJTtnomGiven = TRUE; + break; + case BJT_MOD_IS: + mods->BJTsatCur = value->rValue; + mods->BJTsatCurGiven = TRUE; + break; + case BJT_MOD_BF: + mods->BJTbetaF = value->rValue; + mods->BJTbetaFGiven = TRUE; + break; + case BJT_MOD_NF: + mods->BJTemissionCoeffF = value->rValue; + mods->BJTemissionCoeffFGiven = TRUE; + break; + case BJT_MOD_VAF: + mods->BJTearlyVoltF = value->rValue; + mods->BJTearlyVoltFGiven = TRUE; + break; + case BJT_MOD_IKF: + mods->BJTrollOffF = value->rValue; + mods->BJTrollOffFGiven = TRUE; + break; + case BJT_MOD_ISE: + mods->BJTleakBEcurrent = value->rValue; + mods->BJTleakBEcurrentGiven = TRUE; + break; + case BJT_MOD_C2: + mods->BJTc2 = value->rValue; + mods->BJTc2Given=TRUE; + break; + case BJT_MOD_NE: + mods->BJTleakBEemissionCoeff = value->rValue; + mods->BJTleakBEemissionCoeffGiven = TRUE; + break; + case BJT_MOD_BR: + mods->BJTbetaR = value->rValue; + mods->BJTbetaRGiven = TRUE; + break; + case BJT_MOD_NR: + mods->BJTemissionCoeffR = value->rValue; + mods->BJTemissionCoeffRGiven = TRUE; + break; + case BJT_MOD_VAR: + mods->BJTearlyVoltR = value->rValue; + mods->BJTearlyVoltRGiven = TRUE; + break; + case BJT_MOD_IKR: + mods->BJTrollOffR = value->rValue; + mods->BJTrollOffRGiven = TRUE; + break; + case BJT_MOD_ISC: + mods->BJTleakBCcurrent = value->rValue; + mods->BJTleakBCcurrentGiven = TRUE; + break; + case BJT_MOD_C4: + mods->BJTc4 = value->rValue; + mods->BJTc4Given=TRUE; + break; + case BJT_MOD_NC: + mods->BJTleakBCemissionCoeff = value->rValue; + mods->BJTleakBCemissionCoeffGiven = TRUE; + break; + case BJT_MOD_RB: + mods->BJTbaseResist = value->rValue; + mods->BJTbaseResistGiven = TRUE; + break; + case BJT_MOD_IRB: + mods->BJTbaseCurrentHalfResist = value->rValue; + mods->BJTbaseCurrentHalfResistGiven = TRUE; + break; + case BJT_MOD_RBM: + mods->BJTminBaseResist = value->rValue; + mods->BJTminBaseResistGiven = TRUE; + break; + case BJT_MOD_RE: + mods->BJTemitterResist = value->rValue; + mods->BJTemitterResistGiven = TRUE; + break; + case BJT_MOD_RC: + mods->BJTcollectorResist = value->rValue; + mods->BJTcollectorResistGiven = TRUE; + break; + case BJT_MOD_CJE: + mods->BJTdepletionCapBE = value->rValue; + mods->BJTdepletionCapBEGiven = TRUE; + break; + case BJT_MOD_VJE: + mods->BJTpotentialBE = value->rValue; + mods->BJTpotentialBEGiven = TRUE; + break; + case BJT_MOD_MJE: + mods->BJTjunctionExpBE = value->rValue; + mods->BJTjunctionExpBEGiven = TRUE; + break; + case BJT_MOD_TF: + mods->BJTtransitTimeF = value->rValue; + mods->BJTtransitTimeFGiven = TRUE; + break; + case BJT_MOD_XTF: + mods->BJTtransitTimeBiasCoeffF = value->rValue; + mods->BJTtransitTimeBiasCoeffFGiven = TRUE; + break; + case BJT_MOD_VTF: + mods->BJTtransitTimeFVBC = value->rValue; + mods->BJTtransitTimeFVBCGiven = TRUE; + break; + case BJT_MOD_ITF: + mods->BJTtransitTimeHighCurrentF = value->rValue; + mods->BJTtransitTimeHighCurrentFGiven = TRUE; + break; + case BJT_MOD_PTF: + mods->BJTexcessPhase = value->rValue; + mods->BJTexcessPhaseGiven = TRUE; + break; + case BJT_MOD_CJC: + mods->BJTdepletionCapBC = value->rValue; + mods->BJTdepletionCapBCGiven = TRUE; + break; + case BJT_MOD_VJC: + mods->BJTpotentialBC = value->rValue; + mods->BJTpotentialBCGiven = TRUE; + break; + case BJT_MOD_MJC: + mods->BJTjunctionExpBC = value->rValue; + mods->BJTjunctionExpBCGiven = TRUE; + break; + case BJT_MOD_XCJC: + mods->BJTbaseFractionBCcap = value->rValue; + mods->BJTbaseFractionBCcapGiven = TRUE; + break; + case BJT_MOD_TR: + mods->BJTtransitTimeR = value->rValue; + mods->BJTtransitTimeRGiven = TRUE; + break; + case BJT_MOD_CJS: + mods->BJTcapCS = value->rValue; + mods->BJTcapCSGiven = TRUE; + break; + case BJT_MOD_VJS: + mods->BJTpotentialSubstrate = value->rValue; + mods->BJTpotentialSubstrateGiven = TRUE; + break; + case BJT_MOD_MJS: + mods->BJTexponentialSubstrate = value->rValue; + mods->BJTexponentialSubstrateGiven = TRUE; + break; + case BJT_MOD_XTB: + mods->BJTbetaExp = value->rValue; + mods->BJTbetaExpGiven = TRUE; + break; + case BJT_MOD_EG: + mods->BJTenergyGap = value->rValue; + mods->BJTenergyGapGiven = TRUE; + break; + case BJT_MOD_XTI: + mods->BJTtempExpIS = value->rValue; + mods->BJTtempExpISGiven = TRUE; + break; + case BJT_MOD_FC: + mods->BJTdepletionCapCoeff = value->rValue; + mods->BJTdepletionCapCoeffGiven = TRUE; + break; + case BJT_MOD_KF: + mods->BJTfNcoef = value->rValue; + mods->BJTfNcoefGiven = TRUE; + break; + case BJT_MOD_AF: + mods->BJTfNexp = value->rValue; + mods->BJTfNexpGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtnoise.c b/src/spicelib/devices/bjt/bjtnoise.c new file mode 100644 index 000000000..f9fe22301 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtnoise.c @@ -0,0 +1,236 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "bjtdefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * BJTnoise (mode, operation, firstModel, ckt, data, OnDens) + * + * This routine names and evaluates all of the noise sources + * associated with BJT's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the BJT's is summed with the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +BJTnoise (mode, operation, genmodel, ckt, data, OnDens) + GENmodel *genmodel; + int mode; + int operation; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + BJTmodel *firstModel = (BJTmodel *) genmodel; + register BJTmodel *model; + register BJTinstance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[BJTNSRCS]; + double lnNdens[BJTNSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *BJTnNames[BJTNSRCS] = { + /* Note that we have to keep the order consistent with the + strchr definitions in BJTdefs.h */ + "_rc", /* noise due to rc */ + "_rb", /* noise due to rb */ + "_re", /* noise due to re */ + "_ic", /* noise due to ic */ + "_ib", /* noise due to ib */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->BJTnextModel) { + for (inst=model->BJTinstances; inst != NULL; + inst=inst->BJTnextInstance) { + if (inst->BJTowner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < BJTNSRCS; i++) { + (void)sprintf(name,"onoise_%s%s", + inst->BJTname,BJTnNames[i]); + + + data->namelist = (IFuid *) + trealloc((char *)data->namelist, + (data->numPlots + 1)*sizeof(IFuid)); + if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + } + break; + + case INT_NOIZ: + for (i=0; i < BJTNSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s", + inst->BJTname,BJTnNames[i]); + + data->namelist = (IFuid *) + trealloc((char *)data->namelist, + (data->numPlots + 1)*sizeof(IFuid)); + if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + (void)sprintf(name,"inoise_total_%s%s", + inst->BJTname,BJTnNames[i]); + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[BJTRCNOIZ],&lnNdens[BJTRCNOIZ], + ckt,THERMNOISE,inst->BJTcolPrimeNode,inst->BJTcolNode, + model->BJTcollectorConduct * inst->BJTarea); + + NevalSrc(&noizDens[BJTRBNOIZ],&lnNdens[BJTRBNOIZ], + ckt,THERMNOISE,inst->BJTbasePrimeNode,inst->BJTbaseNode, + *(ckt->CKTstate0 + inst->BJTgx)); + + NevalSrc(&noizDens[BJT_RE_NOISE],&lnNdens[BJT_RE_NOISE], + ckt,THERMNOISE,inst->BJTemitPrimeNode,inst->BJTemitNode, + model->BJTemitterConduct * inst->BJTarea); + + NevalSrc(&noizDens[BJTICNOIZ],&lnNdens[BJTICNOIZ], + ckt,SHOTNOISE,inst->BJTcolPrimeNode, inst->BJTemitPrimeNode, + *(ckt->CKTstate0 + inst->BJTcc)); + + NevalSrc(&noizDens[BJTIBNOIZ],&lnNdens[BJTIBNOIZ], + ckt,SHOTNOISE,inst->BJTbasePrimeNode, inst->BJTemitPrimeNode, + *(ckt->CKTstate0 + inst->BJTcb)); + + NevalSrc(&noizDens[BJTFLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->BJTbasePrimeNode, inst->BJTemitPrimeNode, + (double)0.0); + noizDens[BJTFLNOIZ] *= model->BJTfNcoef * + exp(model->BJTfNexp * + log(MAX(fabs(*(ckt->CKTstate0 + inst->BJTcb)),N_MINLOG))) / + data->freq; + lnNdens[BJTFLNOIZ] = + log(MAX(noizDens[BJTFLNOIZ],N_MINLOG)); + + noizDens[BJTTOTNOIZ] = noizDens[BJTRCNOIZ] + + noizDens[BJTRBNOIZ] + + noizDens[BJT_RE_NOISE] + + noizDens[BJTICNOIZ] + + noizDens[BJTIBNOIZ] + + noizDens[BJTFLNOIZ]; + lnNdens[BJTTOTNOIZ] = + log(noizDens[BJTTOTNOIZ]); + + *OnDens += noizDens[BJTTOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < BJTNSRCS; i++) { + inst->BJTnVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < BJTNSRCS; i++) { + inst->BJTnVar[OUTNOIZ][i] = 0.0; + inst->BJTnVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + +/* In order to get the best curve fit, we have to integrate each component separately */ + + for (i=0; i < BJTNSRCS; i++) { + if (i != BJTTOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->BJTnVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->BJTnVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->BJTnVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->BJTnVar[OUTNOIZ][i] += tempOnoise; + inst->BJTnVar[OUTNOIZ][BJTTOTNOIZ] += tempOnoise; + inst->BJTnVar[INNOIZ][i] += tempInoise; + inst->BJTnVar[INNOIZ][BJTTOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < BJTNSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < BJTNSRCS; i++) { + data->outpVector[data->outNumber++] = inst->BJTnVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->BJTnVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} + + diff --git a/src/spicelib/devices/bjt/bjtparam.c b/src/spicelib/devices/bjt/bjtparam.c new file mode 100644 index 000000000..742a4e070 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtparam.c @@ -0,0 +1,72 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine sets instance parameters for + * BJTs in the circuit. + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +BJTparam(param,value,instPtr,select) + int param; + IFvalue *value; + GENinstance *instPtr; + IFvalue *select; +{ + register BJTinstance *here = (BJTinstance*)instPtr; + + switch(param) { + case BJT_AREA: + here->BJTarea = value->rValue; + here->BJTareaGiven = TRUE; + break; + case BJT_TEMP: + here->BJTtemp = value->rValue+CONSTCtoK; + here->BJTtempGiven = TRUE; + break; + case BJT_OFF: + here->BJToff = value->iValue; + break; + case BJT_IC_VBE: + here->BJTicVBE = value->rValue; + here->BJTicVBEGiven = TRUE; + break; + case BJT_IC_VCE: + here->BJTicVCE = value->rValue; + here->BJTicVCEGiven = TRUE; + break; + case BJT_AREA_SENS: + here->BJTsenParmNo = value->iValue; + break; + case BJT_IC : + switch(value->v.numValue) { + case 2: + here->BJTicVCE = *(value->v.vec.rVec+1); + here->BJTicVCEGiven = TRUE; + case 1: + here->BJTicVBE = *(value->v.vec.rVec); + here->BJTicVBEGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtpzld.c b/src/spicelib/devices/bjt/bjtpzld.c new file mode 100644 index 000000000..736817b19 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtpzld.c @@ -0,0 +1,117 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BJTpzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + register SPcomplex *s; + +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + double gcpr; + double gepr; + double gpi; + double gmu; + double go; + double xgm; + double gm; + double gx; + double xcpi; + double xcmu; + double xcbx; + double xccs; + double xcmcb; + + for( ; model != NULL; model = model->BJTnextModel) { + for( here = model->BJTinstances; here!= NULL; + here = here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + gcpr=model->BJTcollectorResist * here->BJTarea; + gepr=model->BJTemitterResist * here->BJTarea; + gpi= *(ckt->CKTstate0 + here->BJTgpi); + gmu= *(ckt->CKTstate0 + here->BJTgmu); + gm= *(ckt->CKTstate0 + here->BJTgm); + go= *(ckt->CKTstate0 + here->BJTgo); + xgm=0; + gx= *(ckt->CKTstate0 + here->BJTgx); + xcpi= *(ckt->CKTstate0 + here->BJTcqbe); + xcmu= *(ckt->CKTstate0 + here->BJTcqbc); + xcbx= *(ckt->CKTstate0 + here->BJTcqbx); + xccs= *(ckt->CKTstate0 + here->BJTcqcs); + xcmcb= *(ckt->CKTstate0 + here->BJTcexbc); + *(here->BJTcolColPtr) += (gcpr); + *(here->BJTbaseBasePtr) += (gx) + (xcbx) * (s->real); + *(here->BJTbaseBasePtr + 1) += (xcbx) * (s->imag); + *(here->BJTemitEmitPtr) += (gepr); + *(here->BJTcolPrimeColPrimePtr) += (gmu+go+gcpr) + + (xcmu+xccs+xcbx) * (s->real); + *(here->BJTcolPrimeColPrimePtr + 1) += (xcmu+xccs+xcbx) + * (s->imag); + *(here->BJTbasePrimeBasePrimePtr) += (gx+gpi+gmu) + + (xcpi+xcmu+xcmcb) * (s->real); + *(here->BJTbasePrimeBasePrimePtr + 1) += (xcpi+xcmu+xcmcb) + * (s->imag); + *(here->BJTemitPrimeEmitPrimePtr) += (gpi+gepr+gm+go) + + (xcpi+xgm) * (s->real); + *(here->BJTemitPrimeEmitPrimePtr + 1) += (xcpi+xgm) + * (s->imag); + *(here->BJTcolColPrimePtr) += (-gcpr); + *(here->BJTbaseBasePrimePtr) += (-gx); + *(here->BJTemitEmitPrimePtr) += (-gepr); + *(here->BJTcolPrimeColPtr) += (-gcpr); + *(here->BJTcolPrimeBasePrimePtr) += (-gmu+gm) + + (-xcmu+xgm) * (s->real); + *(here->BJTcolPrimeBasePrimePtr + 1) += (-xcmu+xgm) + * (s->imag); + *(here->BJTcolPrimeEmitPrimePtr) += (-gm-go) + + (-xgm) * (s->real); + *(here->BJTcolPrimeEmitPrimePtr + 1) += (-xgm) * + (s->imag); + *(here->BJTbasePrimeBasePtr) += (-gx); + *(here->BJTbasePrimeColPrimePtr) += (-gmu) + + (-xcmu-xcmcb) * (s->real); + *(here->BJTbasePrimeColPrimePtr + 1) += (-xcmu-xcmcb) + * (s->imag); + *(here->BJTbasePrimeEmitPrimePtr) += (-gpi) + + (-xcpi) * (s->real); + *(here->BJTbasePrimeEmitPrimePtr + 1) += (-xcpi) + * (s->imag); + *(here->BJTemitPrimeEmitPtr) += (-gepr); + *(here->BJTemitPrimeColPrimePtr) += (-go) + + (xcmcb) * (s->real); + *(here->BJTemitPrimeColPrimePtr + 1) += (xcmcb) + * (s->imag); + *(here->BJTemitPrimeBasePrimePtr) += (-gpi-gm) + + (-xcpi-xgm-xcmcb) * (s->real); + *(here->BJTemitPrimeBasePrimePtr + 1) += (-xcpi-xgm-xcmcb) + * (s->imag); + *(here->BJTsubstSubstPtr) += (xccs) * (s->real); + *(here->BJTsubstSubstPtr + 1) += (xccs) * (s->imag); + *(here->BJTcolPrimeSubstPtr) += (-xccs) * (s->real); + *(here->BJTcolPrimeSubstPtr + 1) += (-xccs) * (s->imag); + *(here->BJTsubstColPrimePtr) += (-xccs) * (s->real); + *(here->BJTsubstColPrimePtr + 1) += (-xccs) * (s->imag); + *(here->BJTbaseColPrimePtr) += (-xcbx) * (s->real); + *(here->BJTbaseColPrimePtr + 1) += (-xcbx) * (s->imag); + *(here->BJTcolPrimeBasePtr) += (-xcbx) * (s->real); + *(here->BJTcolPrimeBasePtr + 1) += (-xcbx) * (s->imag); + } + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtsacl.c b/src/spicelib/devices/bjt/bjtsacl.c new file mode 100644 index 000000000..0932e06d0 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtsacl.c @@ -0,0 +1,719 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + + +int +BJTsAcLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; + +{ + + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + double SaveState[25]; + int error; + int flag; + double vbeOp; + double vbcOp; + double A0; + double DELA; + double Apert; + double DELAinv; + double vte; + double gcpr; + double gepr; + double gpi; + double gmu; + double go; + double xgm; + double td; + double arg; + double gm; + double gx; + double xcpi; + double xcmu; + double xcbx; + double xccs; + double xcmcb; + double cx,icx; + double cbx,icbx; + double ccs,iccs; + double cbc,icbc; + double cbe,icbe; + double cce,icce; + double cb,icb; + double cbprm,icbprm; + double cc,icc; + double ccprm,iccprm; + double ce,ice; + double ceprm,iceprm; + double cs,ics; + double vcpr,ivcpr; + double vepr,ivepr; + double vx,ivx; + double vbx,ivbx; + double vcs,ivcs; + double vbc,ivbc; + double vbe,ivbe; + double vce,ivce; + double cb0,icb0; + double cbprm0,icbprm0; + double cc0,icc0; + double ccprm0,iccprm0; + double ce0,ice0; + double ceprm0,iceprm0; + double cs0,ics0; + double DvDp; + int iparmno,i; + SENstruct *info; + + +#ifdef SENSDEBUG + printf("BJTsenacload \n"); + printf("BJTsenacload \n"); +#endif /* SENSDEBUG */ + + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + + /* loop through all the models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 20; i++) { + *(SaveState + i) = *(ckt->CKTstate0 + here->BJTstate + i); + } + + vcpr = *(ckt->CKTrhsOld + here->BJTcolNode) + - *(ckt->CKTrhsOld + here->BJTcolPrimeNode) ; + ivcpr = *(ckt->CKTirhsOld + here->BJTcolNode) + - *(ckt->CKTirhsOld + here->BJTcolPrimeNode) ; + vepr = *(ckt->CKTrhsOld + here->BJTemitNode) + - *(ckt->CKTrhsOld + here->BJTemitPrimeNode) ; + ivepr = *(ckt->CKTirhsOld + here->BJTemitNode) + - *(ckt->CKTirhsOld + here->BJTemitPrimeNode) ; + vx = *(ckt->CKTrhsOld + here->BJTbaseNode) + - *(ckt->CKTrhsOld + here->BJTbasePrimeNode) ;/* vb_bprm */ + ivx = *(ckt->CKTirhsOld + here->BJTbaseNode) + - *(ckt->CKTirhsOld + here->BJTbasePrimeNode) ;/* ivb_bprm */ + vcs = *(ckt->CKTrhsOld + here->BJTcolPrimeNode) + - *(ckt->CKTrhsOld + here->BJTsubstNode) ; + ivcs = *(ckt->CKTirhsOld + here->BJTcolPrimeNode) + - *(ckt->CKTirhsOld + here->BJTsubstNode) ; + vbc = *(ckt->CKTrhsOld + here->BJTbasePrimeNode) + - *(ckt->CKTrhsOld + here->BJTcolPrimeNode) ;/* vbprm_cprm */ + ivbc = *(ckt->CKTirhsOld + here->BJTbasePrimeNode) + - *(ckt->CKTirhsOld + here->BJTcolPrimeNode) ;/* ivbprm_cprm */ + vbe = *(ckt->CKTrhsOld + here->BJTbasePrimeNode) + - *(ckt->CKTrhsOld + here->BJTemitPrimeNode) ;/* vbprm_eprm */ + ivbe = *(ckt->CKTirhsOld + here->BJTbasePrimeNode) + - *(ckt->CKTirhsOld + here->BJTemitPrimeNode) ;/* ivbprm_eprm */ + vce = vbe - vbc ; + ivce = ivbe - ivbc ; + vbx = vx + vbc ; + ivbx = ivx + ivbc ; + + + + vbeOp =model->BJTtype * ( *(ckt->CKTrhsOp + here->BJTbasePrimeNode) + - *(ckt->CKTrhsOp + here->BJTemitPrimeNode)); + vbcOp =model->BJTtype * ( *(ckt->CKTrhsOp + here->BJTbasePrimeNode) + - *(ckt->CKTrhsOp + here->BJTcolPrimeNode)); + +#ifdef SENSDEBUG + printf("\n without perturbation\n"); +#endif /* SENSDEBUG */ + /* without perturbation */ + A0 = here->BJTarea; + here->BJTsenPertFlag = ON; + *(ckt->CKTstate0 + here->BJTvbe) = vbeOp; + *(ckt->CKTstate0 + here->BJTvbc) = vbcOp; + /* info->SENacpertflag == 1 only for first frequency */ + + if(info->SENacpertflag == 1){ + + /* store the unperturbed values of small signal parameters */ + + if ((error = BJTload((GENmodel*)model,ckt))) + return(error); + + *(here->BJTsenGpi)= *(ckt->CKTstate0 + here->BJTgpi); + *(here->BJTsenGmu)= *(ckt->CKTstate0 + here->BJTgmu); + *(here->BJTsenGm)= *(ckt->CKTstate0 + here->BJTgm); + *(here->BJTsenGo)= *(ckt->CKTstate0 + here->BJTgo); + *(here->BJTsenGx)= *(ckt->CKTstate0 + here->BJTgx); + *(here->BJTsenCpi)= *(ckt->CKTstate0 + here->BJTcqbe); + *(here->BJTsenCmu)= *(ckt->CKTstate0 + here->BJTcqbc); + *(here->BJTsenCbx)= *(ckt->CKTstate0 + here->BJTcqbx); + *(here->BJTsenCcs)= *(ckt->CKTstate0 + here->BJTcqcs); + *(here->BJTsenCmcb)= *(ckt->CKTstate0 + here->BJTcexbc); + } + gcpr = model->BJTcollectorConduct * A0; + gepr = model->BJTemitterConduct * A0; + gpi= *(here->BJTsenGpi); + gmu= *(here->BJTsenGmu); + gm= *(here->BJTsenGm); + go= *(here->BJTsenGo); + gx= *(here->BJTsenGx); + xgm=0; + td=model->BJTexcessPhase; + if(td != 0) { + arg = td*ckt->CKTomega; + gm = gm+go; + xgm = -gm * sin(arg); + gm = gm * cos(arg)-go; + } + xcpi= *(here->BJTsenCpi) * ckt->CKTomega; + xcmu= *(here->BJTsenCmu) * ckt->CKTomega; + xcbx= *(here->BJTsenCbx) * ckt->CKTomega; + xccs= *(here->BJTsenCcs) * ckt->CKTomega; + xcmcb= *(here->BJTsenCmcb) * ckt->CKTomega; + + + cx=gx * vx ; + icx=gx * ivx; + cbx=( -xcbx * ivbx) ; + icbx= xcbx * vbx ; + ccs=( -xccs * ivcs) ; + iccs= xccs * vcs ; + cbc=(gmu * vbc -xcmu * ivbc) ; + icbc=xcmu * vbc + gmu * ivbc ; + cbe=gpi * vbe -xcpi * ivbe - xcmcb * ivbc ; + icbe=xcpi * vbe + gpi * ivbe + xcmcb * vbc; + cce= go * vce + gm * vbe - xgm * ivbe; + icce=go * ivce + gm * ivbe + xgm * vbe ; + + cc0=gcpr * vcpr ; + icc0=gcpr * ivcpr ; + ce0=gepr * vepr; + ice0=gepr * ivepr ; + cb0 = cx + cbx; + icb0 = icx + icbx; + if(here->BJTbaseNode != here->BJTbasePrimeNode){ + cbprm0 = (- cx + cbe + cbc); + icbprm0 = (- icx + icbe + icbc); + } + else{ + cbprm0 = ( cbx + cbe + cbc); + icbprm0 = (icbx + icbe + icbc); + } + ccprm0 = (- cbx - cc0 + ccs + cce - cbc); + iccprm0 = (- icbx - icc0 + iccs + icce - icbc); + ceprm0 = (- cbe - cce - ce0); + iceprm0 = (- icbe - icce - ice0); + cs0 = (- ccs) ; + ics0 = (- iccs) ; + +#ifdef SENSDEBUG + printf("gepr0 = %.7e , gcpr0 = %.7e , gmu0 = %.7e, gpi0 = %.7e\n", + gepr,gcpr,gmu,gpi); + printf("gm0 = %.7e , go0 = %.7e , gx0 = %.7e, xcpi0 = %.7e\n", + gm,go,gx,xcpi); + printf("xcmu0 = %.7e , xcbx0 = %.7e , xccs0 = %.7e, xcmcb0 = %.7e\n" + ,xcmu,xcbx,xccs,xcmcb); + printf("vepr = %.7e + j%.7e , vcpr = %.7e + j%.7e\n", + vepr,ivepr,vcpr,ivcpr); + printf("vbx = %.7e + j%.7e , vx = %.7e + j%.7e\n", + vbx,ivbx,vx,ivx); + printf("vbc = %.7e + j%.7e , vbe = %.7e + j%.7e\n", + vbc,ivbc,vbe,ivbe); + printf("vce = %.7e + j%.7e , vcs = %.7e + j%.7e\n", + vce,ivce,vcs,ivcs); + printf("cce0 = %.7e + j%.7e , cbe0 = %.7e + j%.7e\n", + cce,icce,cbe,icbe); + printf("cbc0 = %.7e + j%.7e\n", + cbc,icbc); + printf("cc0 = %.7e + j%.7e , ce0 = %.7e + j%.7e\n", + cc0,icc0,ce0,ice0); + printf("cb0 = %.7e + j%.7e , cs0 = %.7e + j%.7e\n", + cb0,icb0,cs0,ics0); + printf("cbprm0 = %.7e + j%.7e , ceprm0 = %.7e + j%.7e\n", + cbprm0,icbprm0,ceprm0,iceprm0); + printf("ccprm0 = %.7e + j%.7e \n", + ccprm0,iccprm0); + printf("\nPerturbation of Area\n"); +#endif /* SENSDEBUG */ + /* Perturbation of Area */ + if(here->BJTsenParmNo == 0){ + flag = 0; + goto next1; + } + + DELA = info->SENpertfac * A0; + Apert = A0 + DELA; + DELAinv = 1.0/DELA; + here->BJTarea = Apert; + + *(ckt->CKTstate0 + here->BJTvbe) = vbeOp; + *(ckt->CKTstate0 + here->BJTvbc) = vbcOp; + if(info->SENacpertflag == 1){ + + /* store the small signal parameters + * corresponding to perturbed area + */ + if ((error = BJTload((GENmodel*)model,ckt))) + return(error); + + *(here->BJTsenGpi + 1)= *(ckt->CKTstate0 + here->BJTgpi); + *(here->BJTsenGmu + 1)= *(ckt->CKTstate0 + here->BJTgmu); + *(here->BJTsenGm + 1)= *(ckt->CKTstate0 + here->BJTgm); + *(here->BJTsenGo + 1)= *(ckt->CKTstate0 + here->BJTgo); + *(here->BJTsenGx + 1)= *(ckt->CKTstate0 + here->BJTgx); + *(here->BJTsenCpi + 1)= *(ckt->CKTstate0 + here->BJTcqbe); + *(here->BJTsenCmu + 1)= *(ckt->CKTstate0 + here->BJTcqbc); + *(here->BJTsenCbx + 1)= *(ckt->CKTstate0 + here->BJTcqbx); + *(here->BJTsenCcs + 1)= *(ckt->CKTstate0 + here->BJTcqcs); + *(here->BJTsenCmcb + 1)= *(ckt->CKTstate0 + here->BJTcexbc); + } + + + flag = 0; + goto load; + + + +pertvbx: /* Perturbation of vbx */ +#ifdef SENSDEBUG + printf("\nPerturbation of vbx\n"); +#endif /* SENSDEBUG */ + here->BJTarea = A0; + A0 = model->BJTtype * (*(ckt->CKTrhsOp + here->BJTbaseNode) + - *(ckt->CKTrhsOp + here->BJTcolPrimeNode)); + DELA = info->SENpertfac * A0 + 1e-8; + Apert = A0 + DELA; + DELAinv = model->BJTtype * 1.0/DELA; + *(ckt->CKTrhsOp + here->BJTbaseNode) += DELA; + *(ckt->CKTstate0 + here->BJTvbe) = vbeOp; + *(ckt->CKTstate0 + here->BJTvbc) = vbcOp; + + if(info->SENacpertflag == 1){ + + /* store the small signal parameters + * corresponding to perturbed vbx + */ + if ((error = BJTload((GENmodel*)model,ckt))) + return(error); + + *(here->BJTsenGpi + 2)= *(ckt->CKTstate0 + here->BJTgpi); + *(here->BJTsenGmu + 2)= *(ckt->CKTstate0 + here->BJTgmu); + *(here->BJTsenGm + 2)= *(ckt->CKTstate0 + here->BJTgm); + *(here->BJTsenGo + 2)= *(ckt->CKTstate0 + here->BJTgo); + *(here->BJTsenGx + 2)= *(ckt->CKTstate0 + here->BJTgx); + *(here->BJTsenCpi + 2)= *(ckt->CKTstate0 + here->BJTcqbe); + *(here->BJTsenCmu + 2)= *(ckt->CKTstate0 + here->BJTcqbc); + *(here->BJTsenCbx + 2)= *(ckt->CKTstate0 + here->BJTcqbx); + *(here->BJTsenCcs + 2)= *(ckt->CKTstate0 + here->BJTcqcs); + *(here->BJTsenCmcb + 2)= *(ckt->CKTstate0 + here->BJTcexbc); + } + + + flag = 1; + goto load; + + +pertvbe: /* Perturbation of vbe */ +#ifdef SENSDEBUG + printf("\nPerturbation of vbe\n"); +#endif /* SENSDEBUG */ + if (*(here->BJTsenCbx) != 0){ + *(ckt->CKTrhsOp + here ->BJTbaseNode) -= DELA; + } + vte=model->BJTleakBEemissionCoeff*CONSTvt0; + A0 = vbeOp; + DELA = info->SENpertfac * vte ; + Apert = A0 + DELA; + DELAinv = 1.0/DELA; + *(ckt->CKTstate0 + here->BJTvbe) = Apert; + *(ckt->CKTstate0 + here->BJTvbc) = vbcOp; + + if(info->SENacpertflag == 1){ + + /* store the small signal parameters + * corresponding to perturbed vbe + */ + if ((error = BJTload((GENmodel*)model,ckt))) + return(error); + + *(here->BJTsenGpi + 3)= *(ckt->CKTstate0 + here->BJTgpi); + *(here->BJTsenGmu + 3)= *(ckt->CKTstate0 + here->BJTgmu); + *(here->BJTsenGm + 3)= *(ckt->CKTstate0 + here->BJTgm); + *(here->BJTsenGo + 3)= *(ckt->CKTstate0 + here->BJTgo); + *(here->BJTsenGx + 3)= *(ckt->CKTstate0 + here->BJTgx); + *(here->BJTsenCpi + 3)= *(ckt->CKTstate0 + here->BJTcqbe); + *(here->BJTsenCmu + 3)= *(ckt->CKTstate0 + here->BJTcqbc); + *(here->BJTsenCbx + 3)= *(ckt->CKTstate0 + here->BJTcqbx); + *(here->BJTsenCcs + 3)= *(ckt->CKTstate0 + here->BJTcqcs); + *(here->BJTsenCmcb + 3)= *(ckt->CKTstate0 + here->BJTcexbc); + } + + + flag = 2; + goto load; + + +pertvbc: /* Perturbation of vbc */ +#ifdef SENSDEBUG + printf("\nPerturbation of vbc\n"); +#endif /* SENSDEBUG */ + *(ckt->CKTstate0 + here->BJTvbe) = A0; + + A0 = vbcOp; + DELA = info->SENpertfac * vte ; + Apert = A0 + DELA; + DELAinv = 1.0/DELA; + + + *(ckt->CKTstate0 + here->BJTvbc) = Apert; + + *(ckt->CKTstate0 + here->BJTvbe) = vbeOp; + + + + if(info->SENacpertflag == 1){ + + /* store the small signal parameters + * corresponding to perturbed vbc + */ + if ((error = BJTload((GENmodel*)model,ckt))) + return(error); + *(here->BJTsenGpi + 4)= *(ckt->CKTstate0 + here->BJTgpi); + *(here->BJTsenGmu + 4)= *(ckt->CKTstate0 + here->BJTgmu); + *(here->BJTsenGm + 4)= *(ckt->CKTstate0 + here->BJTgm); + *(here->BJTsenGo + 4)= *(ckt->CKTstate0 + here->BJTgo); + *(here->BJTsenGx + 4)= *(ckt->CKTstate0 + here->BJTgx); + *(here->BJTsenCpi + 4)= *(ckt->CKTstate0 + here->BJTcqbe); + *(here->BJTsenCmu + 4)= *(ckt->CKTstate0 + here->BJTcqbc); + *(here->BJTsenCbx + 4)= *(ckt->CKTstate0 + here->BJTcqbx); + *(here->BJTsenCcs + 4)= *(ckt->CKTstate0 + here->BJTcqcs); + *(here->BJTsenCmcb + 4)= *(ckt->CKTstate0 + here->BJTcexbc); + + } + + + flag = 3; + goto load; + + + +pertvcs: /* Perturbation of vcs */ +#ifdef SENSDEBUG + printf("\nPerturbation of vcs\n"); +#endif /* SENSDEBUG */ + *(ckt->CKTstate0 + here->BJTvbc) = A0; + A0 = model->BJTtype * (*(ckt->CKTrhsOp + here->BJTsubstNode) + - *(ckt->CKTrhsOp + here->BJTcolPrimeNode)); + DELA = info->SENpertfac * A0 + 1e-8; + Apert = A0 + DELA; + DELAinv = model->BJTtype * 1.0/DELA; + *(ckt->CKTrhsOp + here->BJTsubstNode) += DELA; + *(ckt->CKTstate0 + here->BJTvbe) = vbeOp; + *(ckt->CKTstate0 + here->BJTvbc) = vbcOp; + + if(info->SENacpertflag == 1){ + + /* store the small signal parameters + * corresponding to perturbed vcs + */ + if ((error = BJTload((GENmodel*)model,ckt))) + return(error); + *(here->BJTsenCcs + 5)= *(ckt->CKTstate0 + here->BJTcqcs); + + } + + + flag = 4; + + *(ckt->CKTrhsOp + here->BJTsubstNode) -= DELA; + xccs= *(here->BJTsenCcs + 5) * ckt->CKTomega; + + ccs=( -xccs * ivcs) ; + iccs= xccs * vcs ; + cs = -ccs; + ics = -iccs; + ccprm = ccprm0 + cs0 - cs; + iccprm = iccprm0 + ics0 - ics; + cbprm = cbprm0; + icbprm = icbprm0; + ceprm = ceprm0; + iceprm = iceprm0; + cc = cc0; + icc = icc0; + ce = ce0; + ice = ice0; + cb = cb0; + icb = icb0; + goto next2; + +load: + gcpr=model->BJTcollectorConduct * here->BJTarea; + gepr=model->BJTemitterConduct * here->BJTarea; + gpi= *(here->BJTsenGpi + flag+1); + gmu= *(here->BJTsenGmu + flag+1); + gm= *(here->BJTsenGm + flag+1); + go= *(here->BJTsenGo + flag+1); + gx= *(here->BJTsenGx + flag+1); + xgm=0; + td=model->BJTexcessPhase; + if(td != 0) { + arg = td*ckt->CKTomega; + gm = gm+go; + xgm = -gm * sin(arg); + gm = gm * cos(arg)-go; + } + xcpi= *(here->BJTsenCpi + flag+1) * ckt->CKTomega; + xcmu= *(here->BJTsenCmu + flag+1) * ckt->CKTomega; + xcbx= *(here->BJTsenCbx + flag+1) * ckt->CKTomega; + xccs= *(here->BJTsenCcs + flag+1) * ckt->CKTomega; + xcmcb= *(here->BJTsenCmcb + flag+1) * ckt->CKTomega; + + + cc=gcpr * vcpr ; + icc=gcpr * ivcpr ; + ce=gepr * vepr; + ice=gepr * ivepr ; + cx=gx * vx ; + icx=gx * ivx; + cbx=( -xcbx * ivbx) ; + icbx= xcbx * vbx ; + ccs=( -xccs * ivcs) ; + iccs= xccs * vcs ; + cbc=(gmu * vbc -xcmu * ivbc) ; + icbc=xcmu * vbc + gmu * ivbc ; + cbe=gpi * vbe -xcpi * ivbe - xcmcb * ivbc ; + icbe=xcpi * vbe + gpi * ivbe + xcmcb * vbc; + cce= go * vce + gm * vbe - xgm * ivbe; + icce=go * ivce + gm * ivbe + xgm * vbe ; + + + cb= cx + cbx; + icb= icx + icbx; + if(here->BJTbaseNode != here->BJTbasePrimeNode){ + cbprm=(- cx + cbe + cbc); + icbprm=(- icx + icbe + icbc); + } + else{ + cbprm=( cbx + cbe + cbc); + icbprm=(icbx + icbe + icbc); + } + ccprm=(- cbx - cc + ccs + cce - cbc); + iccprm=(- icbx - icc + iccs + icce - icbc); + ceprm=(- cbe - cce - ce); + iceprm=(- icbe - icce - ice); + cs= (- ccs) ; + ics= (- iccs) ; + +#ifdef SENSDEBUG + printf("A0 = %.7e , Apert = %.7e , DELA = %.7e\n" + ,A0,Apert,DELA); + printf("gepr = %.7e , gcpr = %.7e , gmu = %.7e, gpi = %.7e\n" + ,gepr,gcpr,gmu,gpi); + printf("gm = %.7e , go = %.7e , gx = %.7e, xcpi = %.7e\n" + ,gm,go,gx,xcpi); + printf("xcmu = %.7e , xcbx = %.7e , xccs = %.7e, xcmcb = %.7e\n" + ,xcmu,xcbx,xccs,xcmcb); + + printf("cx = %.7e + j%.7e , cbx = %.7e + j%.7e\n" + ,cx,icx,cbx,icbx); + printf("ccs %.7e + j%.7e , cbc = %.7e + j%.7e" + ,ccs,iccs,cbc,icbc); + printf("cbe %.7e + j%.7e , cce = %.7e + j%.7e\n" + ,cbe,icbe,cce,icce); + + printf("cc = %.7e + j%.7e , ce = %.7e + j%.7e,", + ,cc,icc,ce,ice); + printf("ccprm = %.7e + j%.7e , ceprm = %.7e + j%.7e", + ccprm,iccprm,ceprm,iceprm); + printf("cb = %.7e + j%.7e , cbprm = %.7e + j%.7e , ", + cb,icb,cbprm,icbprm) + printf("cs = %.7e + j%.7e\n", + cs,ics); +#endif /* SENSDEBUG */ + + + /* load the RHS matrix */ +next2: + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + if( (!flag) && (iparmno != here->BJTsenParmNo) ) continue; + switch(flag){ + + case 0: + /* area : so no DC sensitivity term involved */ + DvDp = 1.0; + + break; + /* calculate the DC sensitivities of operating points */ + case 1: + DvDp = model->BJTtype * + (info->SEN_Sap[here->BJTbaseNode][iparmno] + - info->SEN_Sap[here->BJTcolPrimeNode][iparmno]); + break; + case 2: + DvDp = model->BJTtype * + (info->SEN_Sap[here->BJTbasePrimeNode][iparmno] + - info->SEN_Sap[here->BJTemitPrimeNode][iparmno]); + break; + case 3: + DvDp = model->BJTtype * + (info->SEN_Sap[here->BJTbasePrimeNode][iparmno] + - info->SEN_Sap[here->BJTcolPrimeNode][iparmno]); + break; + case 4: + DvDp = model->BJTtype * + (info->SEN_Sap[here->BJTsubstNode][iparmno] + - info->SEN_Sap[here->BJTcolPrimeNode][iparmno]); + break; + } +#ifdef SENSDEBUG + printf("before loading\n"); + printf("BJTtype = %d\n",model->BJTtype); + printf("DvDp = %.7e , flag = %d , iparmno = %d,senparmno = %d\n" + ,DvDp,flag,iparmno,here->BJTsenParmNo); + printf("senb = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTbaseNode] + iparmno), + *(info->SEN_iRHS[here->BJTbaseNode] + iparmno)); + printf("senbrm = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTbasePrimeNode] + iparmno), + *(info->SEN_iRHS[here->BJTbasePrimeNode] + iparmno)); + printf("senc = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTcolNode] + iparmno), + *(info->SEN_iRHS[here->BJTcolNode] + iparmno)); + printf("sencprm = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTcolPrimeNode] + iparmno), + *(info->SEN_iRHS[here->BJTcolPrimeNode] + iparmno)); + printf("sene = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTemitNode] + iparmno), + *(info->SEN_iRHS[here->BJTemitNode] + iparmno)); + printf("seneprm = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTemitPrimeNode] + iparmno), + *(info->SEN_iRHS[here->BJTemitPrimeNode] + iparmno)); + printf("sens = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTsubstNode] + iparmno), + *(info->SEN_iRHS[here->BJTsubstNode] + iparmno)); +#endif /* SENSDEBUG */ + + + if(here->BJTbaseNode != here->BJTbasePrimeNode){ + *(info->SEN_RHS[here->BJTbaseNode] + iparmno) -= + ( cb - cb0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->BJTbaseNode] + iparmno) -= + ( icb - icb0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->BJTbasePrimeNode] + iparmno) -= + ( cbprm - cbprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->BJTbasePrimeNode] + iparmno) -= + ( icbprm - icbprm0) * DELAinv * DvDp; + + if(here->BJTcolNode != here->BJTcolPrimeNode){ + *(info->SEN_RHS[here->BJTcolNode] + iparmno) -= + ( cc - cc0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->BJTcolNode] + iparmno) -= + ( icc - icc0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->BJTcolPrimeNode] + iparmno) -= + ( ccprm - ccprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->BJTcolPrimeNode] + iparmno) -= + ( iccprm - iccprm0) * DELAinv * DvDp; + + if(here->BJTemitNode != here->BJTemitPrimeNode){ + *(info->SEN_RHS[here->BJTemitNode] + iparmno) -= + ( ce - ce0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->BJTemitNode] + iparmno) -= + ( ice - ice0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->BJTemitPrimeNode] + iparmno) -= + ( ceprm - ceprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->BJTemitPrimeNode] + iparmno) -= + ( iceprm - iceprm0) * DELAinv * DvDp; + *(info->SEN_RHS[here->BJTsubstNode] + iparmno) -= + ( cs - cs0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->BJTsubstNode] + iparmno) -= + ( ics - ics0) * DELAinv * DvDp; +#ifdef SENSDEBUG + printf("after loading\n"); + + printf("senb = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTbaseNode] + iparmno), + *(info->SEN_iRHS[here->BJTbaseNode] + iparmno)); + printf("senbrm = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTbasePrimeNode] + iparmno), + *(info->SEN_iRHS[here->BJTbasePrimeNode] + iparmno)); + printf("senc = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTcolNode] + iparmno), + *(info->SEN_iRHS[here->BJTcolNode] + iparmno)); + printf("sencprm = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTcolPrimeNode] + iparmno), + *(info->SEN_iRHS[here->BJTcolPrimeNode] + iparmno)); + printf("sene = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTemitNode] + iparmno), + *(info->SEN_iRHS[here->BJTemitNode] + iparmno)); + printf("seneprm = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTemitPrimeNode] + iparmno), + *(info->SEN_iRHS[here->BJTemitPrimeNode] + iparmno)); + printf("sens = %.7e + j%.7e\n " + ,*(info->SEN_RHS[here->BJTsubstNode] + iparmno), + *(info->SEN_iRHS[here->BJTsubstNode] + iparmno)); +#endif /* SENSDEBUG */ + + } + + +next1: + switch(flag){ + case 0: + if (*(here->BJTsenCbx) == 0){ + here->BJTarea = A0; + goto pertvbe ; + } + else{ + goto pertvbx; + } + case 1: + goto pertvbe ; + case 2: + goto pertvbc ; + case 3: + goto pertvcs ; + case 4: + break; + } + + /* put the unperturbed values back into the state vector */ + for(i=0; i <= 20; i++) { + *(ckt->CKTstate0 + here->BJTstate + i) = *(SaveState + i); + } + here->BJTsenPertFlag = OFF; + } + + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("BJTsenacload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + diff --git a/src/spicelib/devices/bjt/bjtsetup.c b/src/spicelib/devices/bjt/bjtsetup.c new file mode 100644 index 000000000..061abf6f6 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtsetup.c @@ -0,0 +1,255 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* + * This routine should only be called when circuit topology + * changes, since its computations do not depend on most + * device or model parameters, only on topology (as + * affected by emitter, collector, and base resistances) + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + +int +BJTsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the BJT structure with those pointers needed later + * for fast matrix loading + */ + +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + if(model->BJTtype != NPN && model->BJTtype != PNP) { + model->BJTtype = NPN; + } + if(!model->BJTsatCurGiven) { + model->BJTsatCur = 1e-16; + } + if(!model->BJTbetaFGiven) { + model->BJTbetaF = 100; + } + if(!model->BJTemissionCoeffFGiven) { + model->BJTemissionCoeffF = 1; + } + if(!model->BJTleakBEemissionCoeffGiven) { + model->BJTleakBEemissionCoeff = 1.5; + } + if(!model->BJTbetaRGiven) { + model->BJTbetaR = 1; + } + if(!model->BJTemissionCoeffRGiven) { + model->BJTemissionCoeffR = 1; + } + if(!model->BJTleakBCemissionCoeffGiven) { + model->BJTleakBCemissionCoeff = 2; + } + if(!model->BJTbaseResistGiven) { + model->BJTbaseResist = 0; + } + if(!model->BJTemitterResistGiven) { + model->BJTemitterResist = 0; + } + if(!model->BJTcollectorResistGiven) { + model->BJTcollectorResist = 0; + } + if(!model->BJTdepletionCapBEGiven) { + model->BJTdepletionCapBE = 0; + } + if(!model->BJTpotentialBEGiven) { + model->BJTpotentialBE = .75; + } + if(!model->BJTjunctionExpBEGiven) { + model->BJTjunctionExpBE = .33; + } + if(!model->BJTtransitTimeFGiven) { + model->BJTtransitTimeF = 0; + } + if(!model->BJTtransitTimeBiasCoeffFGiven) { + model->BJTtransitTimeBiasCoeffF = 0; + } + if(!model->BJTtransitTimeHighCurrentFGiven) { + model->BJTtransitTimeHighCurrentF = 0; + } + if(!model->BJTexcessPhaseGiven) { + model->BJTexcessPhase = 0; + } + if(!model->BJTdepletionCapBCGiven) { + model->BJTdepletionCapBC = 0; + } + if(!model->BJTpotentialBCGiven) { + model->BJTpotentialBC = .75; + } + if(!model->BJTjunctionExpBCGiven) { + model->BJTjunctionExpBC = .33; + } + if(!model->BJTbaseFractionBCcapGiven) { + model->BJTbaseFractionBCcap = 1; + } + if(!model->BJTtransitTimeRGiven) { + model->BJTtransitTimeR = 0; + } + if(!model->BJTcapCSGiven) { + model->BJTcapCS = 0; + } + if(!model->BJTpotentialSubstrateGiven) { + model->BJTpotentialSubstrate = .75; + } + if(!model->BJTexponentialSubstrateGiven) { + model->BJTexponentialSubstrate = 0; + } + if(!model->BJTbetaExpGiven) { + model->BJTbetaExp = 0; + } + if(!model->BJTenergyGapGiven) { + model->BJTenergyGap = 1.11; + } + if(!model->BJTtempExpISGiven) { + model->BJTtempExpIS = 3; + } + if(!model->BJTfNcoefGiven) { + model->BJTfNcoef = 0; + } + if(!model->BJTfNexpGiven) { + model->BJTfNexp = 1; + } + +/* + * COMPATABILITY WARNING! + * special note: for backward compatability to much older models, spice 2G + * implemented a special case which checked if B-E leakage saturation + * current was >1, then it was instead a the B-E leakage saturation current + * divided by IS, and multiplied it by IS at this point. This was not + * handled correctly in the 2G code, and there is some question on its + * reasonability, since it is also undocumented, so it has been left out + * here. It could easily be added with 1 line. (The same applies to the B-C + * leakage saturation current). TQ 6/29/84 + */ + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) goto matrixpointers; + + if(!here->BJTareaGiven) { + here->BJTarea = 1; + } + here->BJTstate = *states; + *states += BJTnumStates; + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ + *states += 8 * (ckt->CKTsenInfo->SENparms); + } + +matrixpointers: + if(model->BJTcollectorResist == 0) { + here->BJTcolPrimeNode = here->BJTcolNode; + } else if(here->BJTcolPrimeNode == 0) { + error = CKTmkVolt(ckt,&tmp,here->BJTname,"collector"); + if(error) return(error); + here->BJTcolPrimeNode = tmp->number; + } + if(model->BJTbaseResist == 0) { + here->BJTbasePrimeNode = here->BJTbaseNode; + } else if(here->BJTbasePrimeNode == 0){ + error = CKTmkVolt(ckt,&tmp,here->BJTname, "base"); + if(error) return(error); + here->BJTbasePrimeNode = tmp->number; + } + if(model->BJTemitterResist == 0) { + here->BJTemitPrimeNode = here->BJTemitNode; + } else if(here->BJTemitPrimeNode == 0) { + error = CKTmkVolt(ckt,&tmp,here->BJTname, "emitter"); + if(error) return(error); + here->BJTemitPrimeNode = tmp->number; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + TSTALLOC(BJTcolColPrimePtr,BJTcolNode,BJTcolPrimeNode) + TSTALLOC(BJTbaseBasePrimePtr,BJTbaseNode,BJTbasePrimeNode) + TSTALLOC(BJTemitEmitPrimePtr,BJTemitNode,BJTemitPrimeNode) + TSTALLOC(BJTcolPrimeColPtr,BJTcolPrimeNode,BJTcolNode) + TSTALLOC(BJTcolPrimeBasePrimePtr,BJTcolPrimeNode,BJTbasePrimeNode) + TSTALLOC(BJTcolPrimeEmitPrimePtr,BJTcolPrimeNode,BJTemitPrimeNode) + TSTALLOC(BJTbasePrimeBasePtr,BJTbasePrimeNode,BJTbaseNode) + TSTALLOC(BJTbasePrimeColPrimePtr,BJTbasePrimeNode,BJTcolPrimeNode) + TSTALLOC(BJTbasePrimeEmitPrimePtr,BJTbasePrimeNode,BJTemitPrimeNode) + TSTALLOC(BJTemitPrimeEmitPtr,BJTemitPrimeNode,BJTemitNode) + TSTALLOC(BJTemitPrimeColPrimePtr,BJTemitPrimeNode,BJTcolPrimeNode) + TSTALLOC(BJTemitPrimeBasePrimePtr,BJTemitPrimeNode,BJTbasePrimeNode) + TSTALLOC(BJTcolColPtr,BJTcolNode,BJTcolNode) + TSTALLOC(BJTbaseBasePtr,BJTbaseNode,BJTbaseNode) + TSTALLOC(BJTemitEmitPtr,BJTemitNode,BJTemitNode) + TSTALLOC(BJTcolPrimeColPrimePtr,BJTcolPrimeNode,BJTcolPrimeNode) + TSTALLOC(BJTbasePrimeBasePrimePtr,BJTbasePrimeNode,BJTbasePrimeNode) + TSTALLOC(BJTemitPrimeEmitPrimePtr,BJTemitPrimeNode,BJTemitPrimeNode) + TSTALLOC(BJTsubstSubstPtr,BJTsubstNode,BJTsubstNode) + TSTALLOC(BJTcolPrimeSubstPtr,BJTcolPrimeNode,BJTsubstNode) + TSTALLOC(BJTsubstColPrimePtr,BJTsubstNode,BJTcolPrimeNode) + TSTALLOC(BJTbaseColPrimePtr,BJTbaseNode,BJTcolPrimeNode) + TSTALLOC(BJTcolPrimeBasePtr,BJTcolPrimeNode,BJTbaseNode) + } + } + return(OK); +} + +int +BJTunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + BJTmodel *model; + BJTinstance *here; + + for (model = (BJTmodel *)inModel; model != NULL; + model = model->BJTnextModel) + { + for (here = model->BJTinstances; here != NULL; + here=here->BJTnextInstance) + { + if (here->BJTcolPrimeNode + && here->BJTcolPrimeNode != here->BJTcolNode) + { + CKTdltNNum(ckt, here->BJTcolPrimeNode); + here->BJTcolPrimeNode = 0; + } + if (here->BJTbasePrimeNode + && here->BJTbasePrimeNode != here->BJTbaseNode) + { + CKTdltNNum(ckt, here->BJTbasePrimeNode); + here->BJTbasePrimeNode = 0; + } + if (here->BJTemitPrimeNode + && here->BJTemitPrimeNode != here->BJTemitNode) + { + CKTdltNNum(ckt, here->BJTemitPrimeNode); + here->BJTemitPrimeNode = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/bjt/bjtsload.c b/src/spicelib/devices/bjt/bjtsload.c new file mode 100644 index 000000000..c3a07ff05 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtsload.c @@ -0,0 +1,332 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + + +int +BJTsLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + double SaveState0[27]; + int i; + int iparmno; + int error; + double A0; + double DELA; + double Apert; + double DELAinv; + double cb0; + double cb; + double cc0; + double cc; + double cx0; + double ccpr0; + double cepr0; + double DcbDp; + double DccDp; + double DceDp; + double DccprDp; + double DceprDp; + double DcxDp; + double DbprmDp; + double DcprmDp; + double DeprmDp; + double gx; + double gx0; + double tag0; + double tag1; + double qbe0; + double qbe; + double qbc0; + double qbc; + double qcs0; + double qcs; + double qbx0; + double qbx; + double DqbeDp; + double DqbcDp; + double DqcsDp; + double DqbxDp; + double Osxpbe; + double Osxpbc; + double Osxpcs; + double Osxpbx; + SENstruct *info; + + tag0 = ckt->CKTag[0]; + tag1 = ckt->CKTag[1]; + if(ckt->CKTorder == 1){ + tag1 = 0; + } +#ifdef SENSDEBUG + printf("BJTsenload \n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); + printf("CKTorder = %.5e\n",ckt->CKTorder); + printf("tag0=%.7e,tag1=%.7e\n",tag0,tag1); +#endif /* SENSDEBUG */ + info = ckt->CKTsenInfo; + + info->SENstatus = PERTURBATION; + + /* loop through all the models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("base = %d , baseprm = %d ,col = %d, colprm = %d\n", + here->BJTbaseNode ,here->BJTbasePrimeNode, + here->BJTcolNode,here->BJTcolPrimeNode); + printf("emit = %d , emitprm = %d ,subst = %d, senparmno = %d\n", + here->BJTemitNode ,here->BJTemitPrimeNode, + here->BJTsubstNode,here->BJTsenParmNo); +#endif /* SENSDEBUG */ + + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 20; i++){ + *(SaveState0 + i) = *(ckt->CKTstate0 + here->BJTstate + i); + } + *(SaveState0 + 21) = *(ckt->CKTstate1 + here->BJTcexbc); + *(SaveState0 + 22) = *(ckt->CKTstate2 + here->BJTcexbc); + *(SaveState0 + 23) = here->BJTcapbe; + *(SaveState0 + 24) = here->BJTcapbc; + *(SaveState0 + 25) = here->BJTcapcs; + *(SaveState0 + 26) = here->BJTcapbx; + + if(here->BJTsenParmNo == 0) goto next; + + cx0 = model->BJTtype * *(ckt->CKTstate0 + here->BJTcb); + ccpr0 = model->BJTtype * *(ckt->CKTstate0 + here->BJTcc); + cepr0 = -cx0 - ccpr0; + + here->BJTsenPertFlag = ON; + error = BJTload((GENmodel*)model,ckt); + if(error) return(error); + + cb0 = model->BJTtype * *(ckt->CKTstate0 + here->BJTcb); + cc0 = model->BJTtype * *(ckt->CKTstate0 + here->BJTcc); + gx0 = *(ckt->CKTstate0 + here->BJTgx); + + qbe0 = *(ckt->CKTstate0 + here->BJTqbe); + qbc0 = *(ckt->CKTstate0 + here->BJTqbc); + qcs0 = *(ckt->CKTstate0 + here->BJTqcs); + qbx0 = *(ckt->CKTstate0 + here->BJTqbx); + + /* perturbation of area */ + + A0 = here->BJTarea; + DELA = info->SENpertfac * A0; + Apert = A0 + DELA; + DELAinv = 1.0/DELA; + here->BJTsenPertFlag = ON; + here->BJTarea = Apert; + error = BJTload((GENmodel*)model,ckt); + if(error) return(error); + here->BJTarea = A0; + here->BJTsenPertFlag = OFF; + + + cb = model->BJTtype * *(ckt->CKTstate0 + here->BJTcb); + cc = model->BJTtype * *(ckt->CKTstate0 + here->BJTcc); + gx = *(ckt->CKTstate0 + here->BJTgx); + + qbe = *(ckt->CKTstate0 + here->BJTqbe); + qbc = *(ckt->CKTstate0 + here->BJTqbc); + qcs = *(ckt->CKTstate0 + here->BJTqcs); + qbx = *(ckt->CKTstate0 + here->BJTqbx); + + /* compute the gradients of currents */ + DcbDp = (cb - cb0) * DELAinv; + DccDp = (cc - cc0) * DELAinv; + DceDp = DcbDp + DccDp; + + DccprDp = 0; + DceprDp = 0; + DcxDp = 0; + if(here->BJTcolNode != here->BJTcolPrimeNode) + DccprDp = ccpr0 * info->SENpertfac * DELAinv; + if(here->BJTemitNode != here->BJTemitPrimeNode) + DceprDp = cepr0 * info->SENpertfac * DELAinv; + if(here->BJTbaseNode != here->BJTbasePrimeNode){ + if(gx0) DcxDp = cx0 * DELAinv * (gx-gx0)/gx0; + } + DbprmDp = DcbDp - DcxDp; + DcprmDp = DccDp - DccprDp; + DeprmDp = - DceDp - DceprDp; + + DqbeDp = (qbe - qbe0)*DELAinv; + DqbcDp = (qbc - qbc0)*DELAinv; + DqcsDp = (qcs - qcs0)*DELAinv; + DqbxDp = (qbx - qbx0)*DELAinv; + + *(here->BJTdphibedp) = DqbeDp; + *(here->BJTdphibcdp) = DqbcDp; + *(here->BJTdphicsdp) = DqcsDp; + *(here->BJTdphibxdp) = DqbxDp; + +#ifdef SENSDEBUG + printf("cb0 = %.7e ,cb = %.7e,\n",cb0,cb); + printf("cc0 = %.7e ,cc = %.7e,\n",cc0,cc); + printf("ccpr0 = %.7e \n",ccpr0); + printf("cepr0 = %.7e \n",cepr0); + printf("cx0 = %.7e \n",cx0); + printf("qbe0 = %.7e ,qbe = %.7e,\n",qbe0,qbe); + printf("qbc0 = %.7e ,qbc = %.7e,\n",qbc0,qbc); + printf("qcs0 = %.7e ,qcs = %.7e,\n",qcs0,qcs); + printf("qbx0 = %.7e ,qbx = %.7e,\n",qbx0,qbx); + printf("\n"); + +#endif /* SENSDEBUG */ + + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) + goto restore; + + /* load the RHS matrix */ + + *(info->SEN_RHS[here->BJTbaseNode] + here->BJTsenParmNo) + -= DcxDp; + *(info->SEN_RHS[here->BJTbasePrimeNode] + here->BJTsenParmNo) + -= DbprmDp; + *(info->SEN_RHS[here->BJTcolNode] + here->BJTsenParmNo) + -= DccprDp; + *(info->SEN_RHS[here->BJTcolPrimeNode] + here->BJTsenParmNo) + -= DcprmDp; + *(info->SEN_RHS[here->BJTemitNode] + here->BJTsenParmNo) + -= DceprDp; + *(info->SEN_RHS[here->BJTemitPrimeNode] + here->BJTsenParmNo) + -= DeprmDp; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("DcxDp=%.7e\n", + *(info->SEN_RHS[here->BJTbaseNode] + here->BJTsenParmNo)); + printf("DcbprmDp=%.7e\n", + *(info->SEN_RHS[here->BJTbasePrimeNode] + + here->BJTsenParmNo)); + printf("DccprDp=%.7e\n", + *(info->SEN_RHS[here->BJTcolNode] + here->BJTsenParmNo)); + printf("DcprmDp=%.7e\n", + *(info->SEN_RHS[here->BJTcolPrimeNode] + + here->BJTsenParmNo)); + printf("DceprDp=%.7e\n", + *(info->SEN_RHS[here->BJTemitNode] + + here->BJTsenParmNo)); + printf("DceprmDp=%.7e\n", + *(info->SEN_RHS[here->BJTemitPrimeNode] + + here->BJTsenParmNo)); +#endif /* SENSDEBUG */ + +next: + if((info->SENmode == DCSEN)||(ckt->CKTmode&MODETRANOP))goto restore; + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) + goto restore; + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + Osxpbe = tag0 * *(ckt->CKTstate1 + here->BJTsensxpbe + + 8*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->BJTsensxpbe + + 8*(iparmno - 1) + 1); + + Osxpbc = tag0 * *(ckt->CKTstate1 + here->BJTsensxpbc + + 8*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->BJTsensxpbc + + 8*(iparmno - 1) + 1); + + Osxpcs = tag0 * *(ckt->CKTstate1 + here->BJTsensxpcs + + 8*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->BJTsensxpcs + + 8*(iparmno - 1) + 1); + + Osxpbx = tag0 * *(ckt->CKTstate1 + here->BJTsensxpbx + + 8*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->BJTsensxpbx + + 8*(iparmno - 1) + 1); +#ifdef SENSDEBUG + printf("iparmno=%d\n",iparmno); + printf("Osxpbe=%.7e,Osxpbc=%.7e\n",Osxpbe,Osxpbc); + printf("Osxpcs=%.7e,Osxpbx=%.7e\n",Osxpcs,Osxpbx); + printf("sxpbe=%.7e,sdbe=%.7e\n", + *(ckt->CKTstate1 + here->BJTsensxpbe + 8*(iparmno - 1)) + ,*(ckt->CKTstate1 + here->BJTsensxpbe + + 8*(iparmno - 1) + 1)); + printf("sxpbc=%.7e,sdbc=%.7e\n", + *(ckt->CKTstate1 + here->BJTsensxpbc + 8*(iparmno - 1)) + ,*(ckt->CKTstate1 + here->BJTsensxpbc + + 8*(iparmno - 1) + 1)); + printf("\n"); +#endif /* SENSDEBUG */ + + if(iparmno == here->BJTsenParmNo){ + Osxpbe = Osxpbe - tag0 * DqbeDp; + Osxpbc = Osxpbc - tag0 * DqbcDp; + Osxpcs = Osxpcs - tag0 * DqcsDp; + Osxpbx = Osxpbx - tag0 * DqbxDp; + } + +#ifdef SENSDEBUG + + printf("Osxpbe=%.7e,Osxpbc=%.7e\n",Osxpbe,Osxpbc); + printf("Osxpcs=%.7e,Osxpbx=%.7e\n",Osxpcs,Osxpbx); +#endif /* SENSDEBUG */ + + *(info->SEN_RHS[here->BJTbaseNode] + iparmno) + += model->BJTtype * Osxpbx; + + *(info->SEN_RHS[here->BJTbasePrimeNode] + iparmno) + += model->BJTtype * (Osxpbe + Osxpbc); + + *(info->SEN_RHS[here->BJTcolPrimeNode] + iparmno) + -= model->BJTtype * (Osxpbc + Osxpcs + Osxpbx ); + + *(info->SEN_RHS[here->BJTemitPrimeNode] + iparmno) + -= model->BJTtype * Osxpbe; + + *(info->SEN_RHS[here->BJTsubstNode] + iparmno) + += model->BJTtype * Osxpcs; + + } + + + /* put the unperturbed values back into the state vector */ +restore: + for(i=0; i <= 20; i++){ + *(ckt->CKTstate0 + here->BJTstate + i) = *(SaveState0 + i); + } + *(ckt->CKTstate1 + here->BJTcexbc) = *(SaveState0 + 21); + *(ckt->CKTstate1 + here->BJTcexbc) = *(SaveState0 + 21); + here->BJTcapbe = *(SaveState0 + 23) ; + here->BJTcapbc = *(SaveState0 + 24) ; + here->BJTcapcs = *(SaveState0 + 25) ; + here->BJTcapbx = *(SaveState0 + 26) ; + + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("BJTsenload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjtsprt.c b/src/spicelib/devices/bjt/bjtsprt.c new file mode 100644 index 000000000..fc06c6a44 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtsprt.c @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* Pretty print the sensitivity info for all + * the bjts in the circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + + +void +BJTsPrint(inModel,ckt) + +register CKTcircuit *ckt; +GENmodel *inModel; +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + + printf("BJTS-----------------\n"); + /* loop through all the BJT models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + printf("Model name:%s\n",model->BJTmodName); + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + ckt->CKTsenInfo->SEN_parmVal[here->BJTsenParmNo] = here->BJTarea; + + printf(" Instance name:%s\n",here->BJTname); + printf(" Collector, Base , Emitter nodes: %s, %s ,%s\n", + CKTnodName(ckt,here->BJTcolNode),CKTnodName(ckt,here->BJTbaseNode), + CKTnodName(ckt,here->BJTemitNode)); + + printf(" Area: %g ",here->BJTarea); + printf(here->BJTareaGiven ? "(specified)\n" : "(default)\n"); + printf(" BJTsenParmNo:%d\n",here->BJTsenParmNo); + + } + } +} + diff --git a/src/spicelib/devices/bjt/bjtsset.c b/src/spicelib/devices/bjt/bjtsset.c new file mode 100644 index 000000000..f02ac3497 --- /dev/null +++ b/src/spicelib/devices/bjt/bjtsset.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + + +int +BJTsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + +#ifdef STEPDEBUG + printf(" BJTsensetup \n"); +#endif /* STEPDEBUG */ + + /* loop through all the diode models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + if(here->BJTsenParmNo){ + here->BJTsenParmNo = ++(info->SENparms); + here->BJTsenPertFlag = OFF; + } + if((here->BJTsens = (double *)MALLOC(55*sizeof(double))) == + NULL) return(E_NOMEM); + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bjt/bjtsupd.c b/src/spicelib/devices/bjt/bjtsupd.c new file mode 100644 index 000000000..eb1cb344b --- /dev/null +++ b/src/spicelib/devices/bjt/bjtsupd.c @@ -0,0 +1,156 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* update the charge sensitivities and their derivatives */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + + +int +BJTsUpdate(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + int iparmno; + double sb; + double sbprm; + double scprm; + double seprm; + double ss; + double sxpbe; + double sxpbc; + double sxpcs; + double sxpbx; + double dummy1; + double dummy2; + SENstruct *info; + + info = ckt->CKTsenInfo; + if(ckt->CKTtime == 0) return(OK); +#ifdef SENSDEBUG + printf("BJTsenUpdate\n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); +#endif /* SENSDEBUG */ + /* loop through all the BJT models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + sxpbe = 0; + sxpbc = 0; + sxpcs = 0; + sxpbx = 0; +#ifdef SENSDEBUG + printf("senupdate Instance name: %s\n",here->BJTname); + printf("iparmno = %d,CKTag[0] = %.2e,CKTag[1] = %.2e\n", + iparmno,ckt->CKTag[0],ckt->CKTag[1]); + + printf("capbe = %.7e\n",here->BJTcapbe); + printf("capbc = %.7e\n",here->BJTcapbc); + printf("capcs = %.7e\n",here->BJTcapcs); + printf("capbx = %.7e\n",here->BJTcapbx); +#endif /* SENSDEBUG */ + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + sb = *(info->SEN_Sap[here->BJTbaseNode] + iparmno); + sbprm = *(info->SEN_Sap[here->BJTbasePrimeNode] + iparmno); + scprm = *(info->SEN_Sap[here->BJTcolPrimeNode] + iparmno); + seprm = *(info->SEN_Sap[here->BJTemitPrimeNode] + iparmno); + ss = *(info->SEN_Sap[here->BJTsubstNode] + iparmno); +#ifdef SENSDEBUG + printf("iparmno = %d \n",iparmno); + printf("sb = %.7e,sbprm = %.7e,scprm=%.7e\n",sb,sbprm,scprm); + printf("seprm = %.7e,ss = %.7e\n",seprm,ss); +#endif /* SENSDEBUG */ + + sxpbe = model ->BJTtype * (sbprm - seprm)*here->BJTcapbe; + + sxpbc = model ->BJTtype * (sbprm - scprm)*here->BJTcapbc ; + + sxpcs = model ->BJTtype * (ss - scprm)*here->BJTcapcs ; + + sxpbx = model ->BJTtype * (sb - scprm)*here->BJTcapbx ; + if(iparmno == here->BJTsenParmNo){ + sxpbe += *(here->BJTdphibedp); + sxpbc += *(here->BJTdphibcdp); + sxpcs += *(here->BJTdphicsdp); + sxpbx += *(here->BJTdphibxdp); + } + + + *(ckt->CKTstate0 + here->BJTsensxpbe + 8 * (iparmno - 1)) = + sxpbe; + NIintegrate(ckt,&dummy1,&dummy2,here->BJTcapbe, + here->BJTsensxpbe + 8*(iparmno -1)); + *(ckt->CKTstate0 + here->BJTsensxpbc + 8 * (iparmno - 1)) = + sxpbc; + NIintegrate(ckt,&dummy1,&dummy2,here->BJTcapbc, + here->BJTsensxpbc + 8*(iparmno -1)); + *(ckt->CKTstate0 + here->BJTsensxpcs + 8 * (iparmno - 1)) = + sxpcs; + NIintegrate(ckt,&dummy1,&dummy2,here->BJTcapcs, + here->BJTsensxpcs + 8*(iparmno -1)); + *(ckt->CKTstate0 + here->BJTsensxpbx + 8 * (iparmno - 1)) = + sxpbx; + NIintegrate(ckt,&dummy1,&dummy2,here->BJTcapbx, + here->BJTsensxpbx + 8*(iparmno -1)); + +#ifdef SENSDEBUG + printf("after loading\n"); + printf("sxpbe = %.7e,sdotxpbe = %.7e\n", + sxpbe,*(ckt->CKTstate0 + here->BJTsensxpbe + 8 * + (iparmno - 1) + 1)); + printf("sxpbc = %.7e,sdotxpbc = %.7e\n", + sxpbc,*(ckt->CKTstate0 + here->BJTsensxpbc + 8 * + (iparmno - 1) + 1)); + printf("sxpcs = %.7e,sdotxpsc = %.7e\n", + sxpcs,*(ckt->CKTstate0 + here->BJTsensxpcs + 8 * + (iparmno - 1) + 1)); + printf("sxpbx = %.7e,sdotxpbx = %.7e\n", + sxpbx,*(ckt->CKTstate0 + here->BJTsensxpbx + 8 * + (iparmno - 1) + 1)); + printf("\n"); +#endif /* SENSDEBUG */ + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->BJTsensxpbe + 8 * (iparmno - 1)) = + sxpbe; + *(ckt->CKTstate1 + here->BJTsensxpbc + 8 * (iparmno - 1)) = + sxpbc; + *(ckt->CKTstate1 + here->BJTsensxpcs + 8 * (iparmno - 1)) = + sxpcs; + *(ckt->CKTstate1 + here->BJTsensxpbx + 8 * (iparmno - 1)) = + sxpbx; + *(ckt->CKTstate1 + here->BJTsensxpbe + 8 * (iparmno - 1) + + 1) = 0; + *(ckt->CKTstate1 + here->BJTsensxpbc + 8 * (iparmno - 1) + + 1) = 0; + *(ckt->CKTstate1 + here->BJTsensxpcs + 8 * (iparmno - 1) + + 1) = 0; + *(ckt->CKTstate1 + here->BJTsensxpbx + 8 * (iparmno - 1) + + 1) = 0; + } + + } + } + } +#ifdef SENSDEBUG + printf("BJTsenUpdate end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + diff --git a/src/spicelib/devices/bjt/bjttemp.c b/src/spicelib/devices/bjt/bjttemp.c new file mode 100644 index 000000000..5a24553d5 --- /dev/null +++ b/src/spicelib/devices/bjt/bjttemp.c @@ -0,0 +1,193 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "smpdefs.h" +#include "bjtdefs.h" +#include "const.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +BJTtemp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* Pre-compute many useful parameters + */ + +{ + register BJTmodel *model = (BJTmodel *)inModel; + register BJTinstance *here; + double xfc; + double vt; + double ratlog; + double ratio1; + double factlog; + double bfactor; + double factor; + double fact1,fact2; + double pbo,pbfact; + double gmaold,gmanew; + double egfet; + double arg; + + /* loop through all the bipolar models */ + for( ; model != NULL; model = model->BJTnextModel ) { + + if(!model->BJTtnomGiven) model->BJTtnom = ckt->CKTnomTemp; + fact1 = model->BJTtnom/REFTEMP; + + if(!model->BJTleakBEcurrentGiven) { + if(model->BJTc2Given) { + model->BJTleakBEcurrent = model->BJTc2 * model->BJTsatCur; + } else { + model->BJTleakBEcurrent = 0; + } + } + if(!model->BJTleakBCcurrentGiven) { + if(model->BJTc4Given) { + model->BJTleakBCcurrent = model->BJTc4 * model->BJTsatCur; + } else { + model->BJTleakBCcurrent = 0; + } + } + if(!model->BJTminBaseResistGiven) { + model->BJTminBaseResist = model->BJTbaseResist; + } + +/* + * COMPATABILITY WARNING! + * special note: for backward compatability to much older models, spice 2G + * implemented a special case which checked if B-E leakage saturation + * current was >1, then it was instead a the B-E leakage saturation current + * divided by IS, and multiplied it by IS at this point. This was not + * handled correctly in the 2G code, and there is some question on its + * reasonability, since it is also undocumented, so it has been left out + * here. It could easily be added with 1 line. (The same applies to the B-C + * leakage saturation current). TQ 6/29/84 + */ + + if(model->BJTearlyVoltFGiven && model->BJTearlyVoltF != 0) { + model->BJTinvEarlyVoltF = 1/model->BJTearlyVoltF; + } else { + model->BJTinvEarlyVoltF = 0; + } + if(model->BJTrollOffFGiven && model->BJTrollOffF != 0) { + model->BJTinvRollOffF = 1/model->BJTrollOffF; + } else { + model->BJTinvRollOffF = 0; + } + if(model->BJTearlyVoltRGiven && model->BJTearlyVoltR != 0) { + model->BJTinvEarlyVoltR = 1/model->BJTearlyVoltR; + } else { + model->BJTinvEarlyVoltR = 0; + } + if(model->BJTrollOffRGiven && model->BJTrollOffR != 0) { + model->BJTinvRollOffR = 1/model->BJTrollOffR; + } else { + model->BJTinvRollOffR = 0; + } + if(model->BJTcollectorResistGiven && model->BJTcollectorResist != 0) { + model->BJTcollectorConduct = 1/model->BJTcollectorResist; + } else { + model->BJTcollectorConduct = 0; + } + if(model->BJTemitterResistGiven && model->BJTemitterResist != 0) { + model->BJTemitterConduct = 1/model->BJTemitterResist; + } else { + model->BJTemitterConduct = 0; + } + if(model->BJTtransitTimeFVBCGiven && model->BJTtransitTimeFVBC != 0) { + model->BJTtransitTimeVBCFactor =1/ (model->BJTtransitTimeFVBC*1.44); + } else { + model->BJTtransitTimeVBCFactor = 0; + } + model->BJTexcessPhaseFactor = (model->BJTexcessPhase/ + (180.0/M_PI)) * model->BJTtransitTimeF; + if(model->BJTdepletionCapCoeffGiven) { + if(model->BJTdepletionCapCoeff>.9999) { + model->BJTdepletionCapCoeff=.9999; + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "BJT model %s, parameter fc limited to 0.9999", + &(model->BJTmodName)); + } + } else { + model->BJTdepletionCapCoeff=.5; + } + xfc = log(1-model->BJTdepletionCapCoeff); + model->BJTf2 = exp((1 + model->BJTjunctionExpBE) * xfc); + model->BJTf3 = 1 - model->BJTdepletionCapCoeff * + (1 + model->BJTjunctionExpBE); + model->BJTf6 = exp((1+model->BJTjunctionExpBC)*xfc); + model->BJTf7 = 1 - model->BJTdepletionCapCoeff * + (1 + model->BJTjunctionExpBC); + + /* loop through all the instances of the model */ + for (here = model->BJTinstances; here != NULL ; + here=here->BJTnextInstance) { + if (here->BJTowner != ARCHme) continue; + + if(!here->BJTtempGiven) here->BJTtemp = ckt->CKTtemp; + vt = here->BJTtemp * CONSTKoverQ; + fact2 = here->BJTtemp/REFTEMP; + egfet = 1.16-(7.02e-4*here->BJTtemp*here->BJTtemp)/ + (here->BJTtemp+1108); + arg = -egfet/(2*CONSTboltz*here->BJTtemp)+ + 1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt*(1.5*log(fact2)+CHARGE*arg); + + ratlog = log(here->BJTtemp/model->BJTtnom); + ratio1 = here->BJTtemp/model->BJTtnom -1; + factlog = ratio1 * model->BJTenergyGap/vt + + model->BJTtempExpIS*ratlog; + factor = exp(factlog); + here->BJTtSatCur = model->BJTsatCur * factor; + bfactor = exp(ratlog*model->BJTbetaExp); + here->BJTtBetaF = model->BJTbetaF * bfactor; + here->BJTtBetaR = model->BJTbetaR * bfactor; + here->BJTtBEleakCur = model->BJTleakBEcurrent * + exp(factlog/model->BJTleakBEemissionCoeff)/bfactor; + here->BJTtBCleakCur = model->BJTleakBCcurrent * + exp(factlog/model->BJTleakBCemissionCoeff)/bfactor; + + pbo = (model->BJTpotentialBE-pbfact)/fact1; + gmaold = (model->BJTpotentialBE-pbo)/pbo; + here->BJTtBEcap = model->BJTdepletionCapBE/ + (1+model->BJTjunctionExpBE* + (4e-4*(model->BJTtnom-REFTEMP)-gmaold)); + here->BJTtBEpot = fact2 * pbo+pbfact; + gmanew = (here->BJTtBEpot-pbo)/pbo; + here->BJTtBEcap *= 1+model->BJTjunctionExpBE* + (4e-4*(here->BJTtemp-REFTEMP)-gmanew); + + pbo = (model->BJTpotentialBC-pbfact)/fact1; + gmaold = (model->BJTpotentialBC-pbo)/pbo; + here->BJTtBCcap = model->BJTdepletionCapBC/ + (1+model->BJTjunctionExpBC* + (4e-4*(model->BJTtnom-REFTEMP)-gmaold)); + here->BJTtBCpot = fact2 * pbo+pbfact; + gmanew = (here->BJTtBCpot-pbo)/pbo; + here->BJTtBCcap *= 1+model->BJTjunctionExpBC* + (4e-4*(here->BJTtemp-REFTEMP)-gmanew); + + here->BJTtDepCap = model->BJTdepletionCapCoeff * here->BJTtBEpot; + here->BJTtf1 = here->BJTtBEpot * (1 - exp((1 - + model->BJTjunctionExpBE) * xfc)) / + (1 - model->BJTjunctionExpBE); + here->BJTtf4 = model->BJTdepletionCapCoeff * here->BJTtBCpot; + here->BJTtf5 = here->BJTtBCpot * (1 - exp((1 - + model->BJTjunctionExpBC) * xfc)) / + (1 - model->BJTjunctionExpBC); + here->BJTtVcrit = vt * log(vt / (CONSTroot2*model->BJTsatCur)); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/bjt/bjttrunc.c b/src/spicelib/devices/bjt/bjttrunc.c new file mode 100644 index 000000000..443fbe84b --- /dev/null +++ b/src/spicelib/devices/bjt/bjttrunc.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine performs truncation error calculations for + * BJTs in the circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bjtdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BJTtrunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register BJTmodel *model = (BJTmodel*)inModel; + register BJTinstance *here; + + for( ; model != NULL; model = model->BJTnextModel) { + for(here=model->BJTinstances;here!=NULL;here = here->BJTnextInstance){ + if (here->BJTowner != ARCHme) continue; + + CKTterr(here->BJTqbe,ckt,timeStep); + CKTterr(here->BJTqbc,ckt,timeStep); + CKTterr(here->BJTqcs,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim1/ChangeLog b/src/spicelib/devices/bsim1/ChangeLog new file mode 100644 index 000000000..76bf4f2be --- /dev/null +++ b/src/spicelib/devices/bsim1/ChangeLog @@ -0,0 +1 @@ +22/11/1990 Modified b1mpar.c substituting iValue to rValue as discovered by Al Davis. diff --git a/src/spicelib/devices/bsim1/Makefile.am b/src/spicelib/devices/bsim1/Makefile.am new file mode 100644 index 000000000..6c1a35940 --- /dev/null +++ b/src/spicelib/devices/bsim1/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libbsim1.la + +libbsim1_la_SOURCES = \ + b1.c \ + b1acld.c \ + b1ask.c \ + b1cvtest.c \ + b1del.c \ + b1dest.c \ + b1disto.c \ + b1dset.c \ + b1eval.c \ + b1getic.c \ + b1ld.c \ + b1mask.c \ + b1mdel.c \ + b1moscap.c \ + b1mpar.c \ + b1par.c \ + b1pzld.c \ + b1set.c \ + b1temp.c \ + b1trunc.c \ + bsim1def.h \ + bsim1ext.h \ + bsim1itf.h + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/bsim1/b1.c b/src/spicelib/devices/bsim1/b1.c new file mode 100644 index 000000000..192561af3 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1.c @@ -0,0 +1,142 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "bsim1def.h" +#include "suffix.h" + +IFparm B1pTable[] = { /* parameters */ + IOP( "l", BSIM1_L, IF_REAL , "Length"), + IOP( "w", BSIM1_W, IF_REAL , "Width"), + IOP( "ad", BSIM1_AD, IF_REAL , "Drain area"), + IOP( "as", BSIM1_AS, IF_REAL , "Source area"), + IOP( "pd", BSIM1_PD, IF_REAL , "Drain perimeter"), + IOP( "ps", BSIM1_PS, IF_REAL , "Source perimeter"), + IOP( "nrd", BSIM1_NRD, IF_REAL , "Number of squares in drain"), + IOP( "nrs", BSIM1_NRS, IF_REAL , "Number of squares in source"), + IOP( "off", BSIM1_OFF, IF_FLAG , "Device is initially off"), + IOP( "vds", BSIM1_IC_VDS, IF_REAL , "Initial D-S voltage"), + IOP( "vgs", BSIM1_IC_VGS, IF_REAL , "Initial G-S voltage"), + IOP( "vbs", BSIM1_IC_VBS, IF_REAL , "Initial B-S voltage"), + IP( "ic", BSIM1_IC, IF_VECTOR , "Vector of DS,GS,BS initial voltages") +}; + +IFparm B1mPTable[] = { /* model parameters */ + IOP( "vfb", BSIM1_MOD_VFB0, IF_REAL,"Flat band voltage"), + IOP( "lvfb", BSIM1_MOD_VFBL, IF_REAL, "Length dependence of vfb"), + IOP( "wvfb", BSIM1_MOD_VFBW, IF_REAL, "Width dependence of vfb"), + IOP( "phi", BSIM1_MOD_PHI0, IF_REAL, + "Strong inversion surface potential "), + IOP( "lphi", BSIM1_MOD_PHIL, IF_REAL, "Length dependence of phi"), + IOP( "wphi", BSIM1_MOD_PHIW, IF_REAL, "Width dependence of phi"), + IOP( "k1", BSIM1_MOD_K10, IF_REAL, "Bulk effect coefficient 1"), + IOP( "lk1", BSIM1_MOD_K1L, IF_REAL, "Length dependence of k1"), + IOP( "wk1", BSIM1_MOD_K1W, IF_REAL, "Width dependence of k1"), + IOP( "k2", BSIM1_MOD_K20, IF_REAL, "Bulk effect coefficient 2"), + IOP( "lk2", BSIM1_MOD_K2L, IF_REAL, "Length dependence of k2"), + IOP( "wk2", BSIM1_MOD_K2W, IF_REAL, "Width dependence of k2"), + IOP( "eta", BSIM1_MOD_ETA0, IF_REAL, + "VDS dependence of threshold voltage"), + IOP( "leta", BSIM1_MOD_ETAL, IF_REAL, "Length dependence of eta"), + IOP( "weta", BSIM1_MOD_ETAW, IF_REAL, "Width dependence of eta"), + IOP( "x2e", BSIM1_MOD_ETAB0, IF_REAL, "VBS dependence of eta"), + IOP( "lx2e", BSIM1_MOD_ETABL, IF_REAL, "Length dependence of x2e"), + IOP( "wx2e", BSIM1_MOD_ETABW, IF_REAL, "Width dependence of x2e"), + IOP( "x3e", BSIM1_MOD_ETAD0, IF_REAL, "VDS dependence of eta"), + IOP( "lx3e", BSIM1_MOD_ETADL, IF_REAL, "Length dependence of x3e"), + IOP( "wx3e", BSIM1_MOD_ETADW, IF_REAL, "Width dependence of x3e"), + IOP( "dl", BSIM1_MOD_DELTAL, IF_REAL, "Channel length reduction in um"), + IOP( "dw", BSIM1_MOD_DELTAW, IF_REAL, "Channel width reduction in um"), + IOP( "muz", BSIM1_MOD_MOBZERO, IF_REAL, + "Zero field mobility at VDS=0 VGS=VTH"), + IOP( "x2mz", BSIM1_MOD_MOBZEROB0, IF_REAL, "VBS dependence of muz"), + IOP( "lx2mz", BSIM1_MOD_MOBZEROBL, IF_REAL, "Length dependence of x2mz"), + IOP( "wx2mz", BSIM1_MOD_MOBZEROBW, IF_REAL, "Width dependence of x2mz"), + IOP( "mus", BSIM1_MOD_MOBVDD0, IF_REAL, + "Mobility at VDS=VDD VGS=VTH, channel length modulation"), + IOP( "lmus", BSIM1_MOD_MOBVDDL, IF_REAL, "Length dependence of mus"), + IOP( "wmus", BSIM1_MOD_MOBVDDW, IF_REAL, "Width dependence of mus"), + IOP( "x2ms", BSIM1_MOD_MOBVDDB0, IF_REAL, "VBS dependence of mus"), + IOP( "lx2ms", BSIM1_MOD_MOBVDDBL, IF_REAL, "Length dependence of x2ms"), + IOP( "wx2ms", BSIM1_MOD_MOBVDDBW, IF_REAL, "Width dependence of x2ms"), + IOP( "x3ms", BSIM1_MOD_MOBVDDD0, IF_REAL, "VDS dependence of mus"), + IOP( "lx3ms", BSIM1_MOD_MOBVDDDL, IF_REAL, "Length dependence of x3ms"), + IOP( "wx3ms", BSIM1_MOD_MOBVDDDW, IF_REAL, "Width dependence of x3ms"), + IOP( "u0", BSIM1_MOD_UGS0, IF_REAL, "VGS dependence of mobility"), + IOP( "lu0", BSIM1_MOD_UGSL, IF_REAL, "Length dependence of u0"), + IOP( "wu0", BSIM1_MOD_UGSW, IF_REAL, "Width dependence of u0"), + IOP( "x2u0", BSIM1_MOD_UGSB0, IF_REAL, "VBS dependence of u0"), + IOP( "lx2u0", BSIM1_MOD_UGSBL, IF_REAL, "Length dependence of x2u0"), + IOP( "wx2u0", BSIM1_MOD_UGSBW, IF_REAL, "Width dependence of x2u0"), + IOP( "u1", BSIM1_MOD_UDS0, IF_REAL, + "VDS depence of mobility, velocity saturation"), + IOP( "lu1", BSIM1_MOD_UDSL, IF_REAL, "Length dependence of u1"), + IOP( "wu1", BSIM1_MOD_UDSW, IF_REAL, "Width dependence of u1"), + IOP( "x2u1", BSIM1_MOD_UDSB0, IF_REAL, "VBS depence of u1"), + IOP( "lx2u1", BSIM1_MOD_UDSBL, IF_REAL, "Length depence of x2u1"), + IOP( "wx2u1", BSIM1_MOD_UDSBW, IF_REAL, "Width depence of x2u1"), + IOP( "x3u1", BSIM1_MOD_UDSD0, IF_REAL, "VDS depence of u1"), + IOP( "lx3u1", BSIM1_MOD_UDSDL, IF_REAL, "Length dependence of x3u1"), + IOP( "wx3u1", BSIM1_MOD_UDSDW, IF_REAL, "Width depence of x3u1"), + IOP( "n0", BSIM1_MOD_N00, IF_REAL, "Subthreshold slope"), + IOP( "ln0", BSIM1_MOD_N0L, IF_REAL, "Length dependence of n0"), + IOP( "wn0", BSIM1_MOD_N0W, IF_REAL, "Width dependence of n0"), + IOP( "nb", BSIM1_MOD_NB0, IF_REAL, + "VBS dependence of subthreshold slope"), + IOP( "lnb", BSIM1_MOD_NBL, IF_REAL, "Length dependence of nb"), + IOP( "wnb", BSIM1_MOD_NBW, IF_REAL, "Width dependence of nb"), + IOP( "nd", BSIM1_MOD_ND0, IF_REAL, + "VDS dependence of subthreshold slope"), + IOP( "lnd", BSIM1_MOD_NDL, IF_REAL, "Length dependence of nd"), + IOP( "wnd", BSIM1_MOD_NDW, IF_REAL, "Width dependence of nd"), + IOP( "tox", BSIM1_MOD_TOX, IF_REAL, "Gate oxide thickness in um"), + IOP( "temp", BSIM1_MOD_TEMP, IF_REAL, "Temperature in degree Celcius"), + IOP( "vdd", BSIM1_MOD_VDD, IF_REAL, "Supply voltage to specify mus"), + IOPA( "cgso", BSIM1_MOD_CGSO, IF_REAL, + "Gate source overlap capacitance per unit channel width(m)"), + IOPA( "cgdo", BSIM1_MOD_CGDO, IF_REAL, + "Gate drain overlap capacitance per unit channel width(m)"), + IOPA( "cgbo", BSIM1_MOD_CGBO, IF_REAL, + "Gate bulk overlap capacitance per unit channel length(m)"), + IOP( "xpart", BSIM1_MOD_XPART, IF_REAL, + "Flag for channel charge partitioning"), + IOP( "rsh", BSIM1_MOD_RSH, IF_REAL, + "Source drain diffusion sheet resistance in ohm per square"), + IOP( "js", BSIM1_MOD_JS, IF_REAL, + "Source drain junction saturation current per unit area"), + IOP( "pb", BSIM1_MOD_PB, IF_REAL, + "Source drain junction built in potential"), + IOPA( "mj", BSIM1_MOD_MJ, IF_REAL, + "Source drain bottom junction capacitance grading coefficient"), + IOPA( "pbsw", BSIM1_MOD_PBSW, IF_REAL, + "Source drain side junction capacitance built in potential"), + IOPA( "mjsw", BSIM1_MOD_MJSW, IF_REAL, + "Source drain side junction capacitance grading coefficient"), + IOPA( "cj", BSIM1_MOD_CJ, IF_REAL, + "Source drain bottom junction capacitance per unit area"), + IOPA( "cjsw", BSIM1_MOD_CJSW, IF_REAL, + "Source drain side junction capacitance per unit area"), + IOP( "wdf", BSIM1_MOD_DEFWIDTH, IF_REAL, + "Default width of source drain diffusion in um"), + IOP( "dell", BSIM1_MOD_DELLENGTH, IF_REAL, + "Length reduction of source drain diffusion"), + IP( "nmos", BSIM1_MOD_NMOS, IF_FLAG, "Flag to indicate NMOS"), + IP( "pmos", BSIM1_MOD_PMOS, IF_FLAG, "Flag to indicate PMOS"), +}; + +char *B1names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int B1nSize = NUMELEMS(B1names); +int B1pTSize = NUMELEMS(B1pTable); +int B1mPTSize = NUMELEMS(B1mPTable); +int B1iSize = sizeof(B1instance); +int B1mSize = sizeof(B1model); diff --git a/src/spicelib/devices/bsim1/b1acld.c b/src/spicelib/devices/bsim1/b1acld.c new file mode 100644 index 000000000..138b428c1 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1acld.c @@ -0,0 +1,149 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "sperror.h" +#include "suffix.h" + + +int +B1acLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register B1model *model = (B1model*)inModel; + register B1instance *here; + int xnrm; + int xrev; + double gdpr; + double gspr; + double gm; + double gds; + double gmbs; + double gbd; + double gbs; + double capbd; + double capbs; + double xcggb; + double xcgdb; + double xcgsb; + double xcbgb; + double xcbdb; + double xcbsb; + double xcddb; + double xcssb; + double xcdgb; + double xcsgb; + double xcdsb; + double xcsdb; + double cggb; + double cgdb; + double cgsb; + double cbgb; + double cbdb; + double cbsb; + double cddb; + double cdgb; + double cdsb; + double omega; /* angular fequency of the signal */ + + omega = ckt->CKTomega; + for( ; model != NULL; model = model->B1nextModel) { + for(here = model->B1instances; here!= NULL; + here = here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + if (here->B1mode >= 0) { + xnrm=1; + xrev=0; + } else { + xnrm=0; + xrev=1; + } + gdpr=here->B1drainConductance; + gspr=here->B1sourceConductance; + gm= *(ckt->CKTstate0 + here->B1gm); + gds= *(ckt->CKTstate0 + here->B1gds); + gmbs= *(ckt->CKTstate0 + here->B1gmbs); + gbd= *(ckt->CKTstate0 + here->B1gbd); + gbs= *(ckt->CKTstate0 + here->B1gbs); + capbd= *(ckt->CKTstate0 + here->B1capbd); + capbs= *(ckt->CKTstate0 + here->B1capbs); + /* + * charge oriented model parameters + */ + + cggb = *(ckt->CKTstate0 + here->B1cggb); + cgsb = *(ckt->CKTstate0 + here->B1cgsb); + cgdb = *(ckt->CKTstate0 + here->B1cgdb); + + cbgb = *(ckt->CKTstate0 + here->B1cbgb); + cbsb = *(ckt->CKTstate0 + here->B1cbsb); + cbdb = *(ckt->CKTstate0 + here->B1cbdb); + + cdgb = *(ckt->CKTstate0 + here->B1cdgb); + cdsb = *(ckt->CKTstate0 + here->B1cdsb); + cddb = *(ckt->CKTstate0 + here->B1cddb); + + xcdgb = (cdgb - here->B1GDoverlapCap) * omega; + xcddb = (cddb + capbd + here->B1GDoverlapCap) * omega; + xcdsb = cdsb * omega; + xcsgb = -(cggb + cbgb + cdgb + here->B1GSoverlapCap ) * omega; + xcsdb = -(cgdb + cbdb + cddb) * omega; + xcssb = (capbs + here->B1GSoverlapCap - (cgsb+cbsb+cdsb)) * omega; + xcggb = (cggb + here->B1GDoverlapCap + here->B1GSoverlapCap + + here->B1GBoverlapCap) * omega; + xcgdb = (cgdb - here->B1GDoverlapCap ) * omega; + xcgsb = (cgsb - here->B1GSoverlapCap) * omega; + xcbgb = (cbgb - here->B1GBoverlapCap) * omega; + xcbdb = (cbdb - capbd ) * omega; + xcbsb = (cbsb - capbs ) * omega; + + + *(here->B1GgPtr +1) += xcggb; + *(here->B1BbPtr +1) += -xcbgb-xcbdb-xcbsb; + *(here->B1DPdpPtr +1) += xcddb; + *(here->B1SPspPtr +1) += xcssb; + *(here->B1GbPtr +1) += -xcggb-xcgdb-xcgsb; + *(here->B1GdpPtr +1) += xcgdb; + *(here->B1GspPtr +1) += xcgsb; + *(here->B1BgPtr +1) += xcbgb; + *(here->B1BdpPtr +1) += xcbdb; + *(here->B1BspPtr +1) += xcbsb; + *(here->B1DPgPtr +1) += xcdgb; + *(here->B1DPbPtr +1) += -xcdgb-xcddb-xcdsb; + *(here->B1DPspPtr +1) += xcdsb; + *(here->B1SPgPtr +1) += xcsgb; + *(here->B1SPbPtr +1) += -xcsgb-xcsdb-xcssb; + *(here->B1SPdpPtr +1) += xcsdb; + *(here->B1DdPtr) += gdpr; + *(here->B1SsPtr) += gspr; + *(here->B1BbPtr) += gbd+gbs; + *(here->B1DPdpPtr) += gdpr+gds+gbd+xrev*(gm+gmbs); + *(here->B1SPspPtr) += gspr+gds+gbs+xnrm*(gm+gmbs); + *(here->B1DdpPtr) -= gdpr; + *(here->B1SspPtr) -= gspr; + *(here->B1BdpPtr) -= gbd; + *(here->B1BspPtr) -= gbs; + *(here->B1DPdPtr) -= gdpr; + *(here->B1DPgPtr) += (xnrm-xrev)*gm; + *(here->B1DPbPtr) += -gbd+(xnrm-xrev)*gmbs; + *(here->B1DPspPtr) += -gds-xnrm*(gm+gmbs); + *(here->B1SPgPtr) += -(xnrm-xrev)*gm; + *(here->B1SPsPtr) -= gspr; + *(here->B1SPbPtr) += -gbs-(xnrm-xrev)*gmbs; + *(here->B1SPdpPtr) += -gds-xrev*(gm+gmbs); + + } + } +return(OK); +} + + diff --git a/src/spicelib/devices/bsim1/b1ask.c b/src/spicelib/devices/bsim1/b1ask.c new file mode 100644 index 000000000..ad4b2d3a8 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1ask.c @@ -0,0 +1,188 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Hong J. Park +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim1def.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +B1ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + B1instance *here = (B1instance*)inst; + + switch(which) { + case BSIM1_L: + value->rValue = here->B1l; + return(OK); + case BSIM1_W: + value->rValue = here->B1w; + return(OK); + case BSIM1_AS: + value->rValue = here->B1sourceArea; + return(OK); + case BSIM1_AD: + value->rValue = here->B1drainArea; + return(OK); + case BSIM1_PS: + value->rValue = here->B1sourcePerimeter; + return(OK); + case BSIM1_PD: + value->rValue = here->B1drainPerimeter; + return(OK); + case BSIM1_NRS: + value->rValue = here->B1sourceSquares; + return(OK); + case BSIM1_NRD: + value->rValue = here->B1drainSquares; + return(OK); + case BSIM1_OFF: + value->rValue = here->B1off; + return(OK); + case BSIM1_IC_VBS: + value->rValue = here->B1icVBS; + return(OK); + case BSIM1_IC_VDS: + value->rValue = here->B1icVDS; + return(OK); + case BSIM1_IC_VGS: + value->rValue = here->B1icVGS; + return(OK); + case BSIM1_DNODE: + value->iValue = here->B1dNode; + return(OK); + case BSIM1_GNODE: + value->iValue = here->B1gNode; + return(OK); + case BSIM1_SNODE: + value->iValue = here->B1sNode; + return(OK); + case BSIM1_BNODE: + value->iValue = here->B1bNode; + return(OK); + case BSIM1_DNODEPRIME: + value->iValue = here->B1dNodePrime; + return(OK); + case BSIM1_SNODEPRIME: + value->iValue = here->B1sNodePrime; + return(OK); + case BSIM1_SOURCECONDUCT: + value->rValue = here->B1sourceConductance; + return(OK); + case BSIM1_DRAINCONDUCT: + value->rValue = here->B1drainConductance; + return(OK); + case BSIM1_VBD: + value->rValue = *(ckt->CKTstate0 + here->B1vbd); + return(OK); + case BSIM1_VBS: + value->rValue = *(ckt->CKTstate0 + here->B1vbs); + return(OK); + case BSIM1_VGS: + value->rValue = *(ckt->CKTstate0 + here->B1vgs); + return(OK); + case BSIM1_VDS: + value->rValue = *(ckt->CKTstate0 + here->B1vds); + return(OK); + case BSIM1_CD: + value->rValue = *(ckt->CKTstate0 + here->B1cd); + return(OK); + case BSIM1_CBS: + value->rValue = *(ckt->CKTstate0 + here->B1cbs); + return(OK); + case BSIM1_CBD: + value->rValue = *(ckt->CKTstate0 + here->B1cbd); + return(OK); + case BSIM1_GM: + value->rValue = *(ckt->CKTstate0 + here->B1gm); + return(OK); + case BSIM1_GDS: + value->rValue = *(ckt->CKTstate0 + here->B1gds); + return(OK); + case BSIM1_GMBS: + value->rValue = *(ckt->CKTstate0 + here->B1gmbs); + return(OK); + case BSIM1_GBD: + value->rValue = *(ckt->CKTstate0 + here->B1gbd); + return(OK); + case BSIM1_GBS: + value->rValue = *(ckt->CKTstate0 + here->B1gbs); + return(OK); + case BSIM1_QB: + value->rValue = *(ckt->CKTstate0 + here->B1qb); + return(OK); + case BSIM1_CQB: + value->rValue = *(ckt->CKTstate0 + here->B1cqb); + return(OK); + case BSIM1_QG: + value->rValue = *(ckt->CKTstate0 + here->B1qg); + return(OK); + case BSIM1_CQG: + value->rValue = *(ckt->CKTstate0 + here->B1cqg); + return(OK); + case BSIM1_QD: + value->rValue = *(ckt->CKTstate0 + here->B1qd); + return(OK); + case BSIM1_CQD: + value->rValue = *(ckt->CKTstate0 + here->B1cqd); + return(OK); + case BSIM1_CGG: + value->rValue = *(ckt->CKTstate0 + here->B1cggb); + return(OK); + case BSIM1_CGD: + value->rValue = *(ckt->CKTstate0 + here->B1cgdb); + return(OK); + case BSIM1_CGS: + value->rValue = *(ckt->CKTstate0 + here->B1cgsb); + return(OK); + case BSIM1_CBG: + value->rValue = *(ckt->CKTstate0 + here->B1cbgb); + return(OK); + case BSIM1_CAPBD: + value->rValue = *(ckt->CKTstate0 + here->B1capbd); + return(OK); + case BSIM1_CQBD: + value->rValue = *(ckt->CKTstate0 + here->B1cqbd); + return(OK); + case BSIM1_CAPBS: + value->rValue = *(ckt->CKTstate0 + here->B1capbs); + return(OK); + case BSIM1_CQBS: + value->rValue = *(ckt->CKTstate0 + here->B1cqbs); + return(OK); + case BSIM1_CDG: + value->rValue = *(ckt->CKTstate0 + here->B1cdgb); + return(OK); + case BSIM1_CDD: + value->rValue = *(ckt->CKTstate0 + here->B1cddb); + return(OK); + case BSIM1_CDS: + value->rValue = *(ckt->CKTstate0 + here->B1cdsb); + return(OK); + case BSIM1_VON: + value->rValue = *(ckt->CKTstate0 + here->B1vono); + return(OK); + case BSIM1_QBS: + value->rValue = *(ckt->CKTstate0 + here->B1qbs); + return(OK); + case BSIM1_QBD: + value->rValue = *(ckt->CKTstate0 + here->B1qbd); + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bsim1/b1cvtest.c b/src/spicelib/devices/bsim1/b1cvtest.c new file mode 100644 index 000000000..d46835c60 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1cvtest.c @@ -0,0 +1,120 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "trandefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +B1convTest(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register B1model *model = (B1model*)inModel; + register B1instance *here; + double cbd; + double cbhat; + double cbs; + double cd; + double cdhat; + double delvbd; + double delvbs; + double delvds; + double delvgd; + double delvgs; + double tol; + double vbd; + double vbs; + double vds; + double vgd; + double vgdo; + double vgs; + + + /* loop through all the B1 device models */ + for( ; model != NULL; model = model->B1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->B1instances; here != NULL ; + here=here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + vbs = model->B1type * ( + *(ckt->CKTrhsOld+here->B1bNode) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + vgs = model->B1type * ( + *(ckt->CKTrhsOld+here->B1gNode) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + vds = model->B1type * ( + *(ckt->CKTrhsOld+here->B1dNodePrime) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->B1vgs) - + *(ckt->CKTstate0 + here->B1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->B1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->B1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->B1vgs); + delvds = vds - *(ckt->CKTstate0 + here->B1vds); + delvgd = vgd-vgdo; + + if (here->B1mode >= 0) { + cdhat= + *(ckt->CKTstate0 + here->B1cd) - + *(ckt->CKTstate0 + here->B1gbd) * delvbd + + *(ckt->CKTstate0 + here->B1gmbs) * delvbs + + *(ckt->CKTstate0 + here->B1gm) * delvgs + + *(ckt->CKTstate0 + here->B1gds) * delvds ; + } else { + cdhat= + *(ckt->CKTstate0 + here->B1cd) - + ( *(ckt->CKTstate0 + here->B1gbd) - + *(ckt->CKTstate0 + here->B1gmbs)) * delvbd - + *(ckt->CKTstate0 + here->B1gm) * delvgd + + *(ckt->CKTstate0 + here->B1gds) * delvds; + } + cbhat= + *(ckt->CKTstate0 + here->B1cbs) + + *(ckt->CKTstate0 + here->B1cbd) + + *(ckt->CKTstate0 + here->B1gbd) * delvbd + + *(ckt->CKTstate0 + here->B1gbs) * delvbs ; + + cd = *(ckt->CKTstate0 + here->B1cd); + cbs = *(ckt->CKTstate0 + here->B1cbs); + cbd = *(ckt->CKTstate0 + here->B1cbd); + /* + * check convergence + */ + if ( (here->B1off == 0) || (!(ckt->CKTmode & MODEINITFIX)) ){ + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol; + if (fabs(cdhat-cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); + } + tol=ckt->CKTreltol*MAX(fabs(cbhat),fabs(cbs+cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(cbs+cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); + } + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim1/b1del.c b/src/spicelib/devices/bsim1/b1del.c new file mode 100644 index 000000000..25a915f4b --- /dev/null +++ b/src/spicelib/devices/bsim1/b1del.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim1def.h" +#include "sperror.h" +#include "gendefs.h" +#include "suffix.h" + + +int +B1delete(inModel,name,inInst) + GENmodel *inModel; + IFuid name; + GENinstance **inInst; + +{ + + B1instance **fast = (B1instance**)inInst; + B1model *model = (B1model*)inModel; + B1instance **prev = NULL; + B1instance *here; + + for( ; model ; model = model->B1nextModel) { + prev = &(model->B1instances); + for(here = *prev; here ; here = *prev) { + if(here->B1name == name || (fast && here==*fast) ) { + *prev= here->B1nextInstance; + FREE(here); + return(OK); + } + prev = &(here->B1nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/bsim1/b1dest.c b/src/spicelib/devices/bsim1/b1dest.c new file mode 100644 index 000000000..577d272af --- /dev/null +++ b/src/spicelib/devices/bsim1/b1dest.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim1def.h" +#include "suffix.h" + + +void +B1destroy(inModel) + GENmodel **inModel; + +{ + + B1model **model = (B1model**)inModel; + B1instance *here; + B1instance *prev = NULL; + B1model *mod = *model; + B1model *oldmod = NULL; + + for( ; mod ; mod = mod->B1nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (B1instance *)NULL; + for(here = mod->B1instances ; here ; here = here->B1nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/bsim1/b1disto.c b/src/spicelib/devices/bsim1/b1disto.c new file mode 100644 index 000000000..de55d1d04 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1disto.c @@ -0,0 +1,1735 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +B1disto(mode,genmodel,ckt) + GENmodel *genmodel; + register CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + B1model *model = (B1model *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h1z, i1h1z; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1h2z, i1h2z; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r1hm2z, i1hm2z; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h11z, i2h11z; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double r2h1m2z, i2h1m2z; + double temp, itemp; + register B1instance *here; + +if (mode == D_SETUP) + return(B1dSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the B1 models */ +for( ; model != NULL; model = model->B1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->B1instances; here != NULL ; + here=here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* from now on, in the 3-var case, x=vgs,y=vbs,z=vds */ + + { + /* draincurrent term */ + r1h1x = *(job->r1H1ptr + here->B1gNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1gNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1y = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1y = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1z = *(job->r1H1ptr + here->B1dNodePrime) - + *(job->r1H1ptr + here->B1sNodePrime); + + i1h1z = *(job->i1H1ptr + here->B1dNodePrime) - + *(job->i1H1ptr + here->B1sNodePrime); + + /* draincurrent is a function of vgs,vbs,and vds; + * have got their linear kernels; now to call + * load functions + */ + + temp = DFn2F1(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = DFi2F1(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* draincurrent term loading over */ + + + + /* loading qg term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFi2F1(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = ckt->CKTomega * DFn2F1(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qg term over */ + + /* loading qb term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFi2F1(here->qb_x2, + here->qb_y2, + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = ckt->CKTomega * DFn2F1(here->qb_x2, + here->qb_y2, + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qb term over */ + + /* loading qd term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFi2F1(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = ckt->CKTomega * DFn2F1(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qd term over */ + + /* loading here->B1gbs term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + /* now r1h1x = vbs */ + + temp = D1n2F1(here->gbs2, + r1h1x, + i1h1x); + + itemp = D1i2F1(here->gbs2, + r1h1x, + i1h1x); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* here->B1gbs term over */ + + /* loading here->B1gbd term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1dNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1dNodePrime); + + /* now r1h1x = vbd */ + + temp = D1n2F1(here->gbd2, + r1h1x, + i1h1x); + + itemp = D1i2F1(here->gbd2, + r1h1x, + i1h1x); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1dNodePrime) += temp; + *(ckt->CKTirhs + here->B1dNodePrime) += itemp; + + /* here->B1gbd term over */ + + /* all done */ + } + + break; + + case D_THRF1: + /* from now on, in the 3-var case, x=vgs,y=vbs,z=vds */ + + { + /* draincurrent term */ + r1h1x = *(job->r1H1ptr + here->B1gNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1gNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1y = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1y = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1z = *(job->r1H1ptr + here->B1dNodePrime) - + *(job->r1H1ptr + here->B1sNodePrime); + + i1h1z = *(job->i1H1ptr + here->B1dNodePrime) - + *(job->i1H1ptr + here->B1sNodePrime); + + r2h11x = *(job->r2H11ptr + here->B1gNode) - + *(job->r2H11ptr + here->B1sNodePrime); + i2h11x = *(job->i2H11ptr + here->B1gNode) - + *(job->i2H11ptr + here->B1sNodePrime); + + r2h11y = *(job->r2H11ptr + here->B1bNode) - + *(job->r2H11ptr + here->B1sNodePrime); + i2h11y = *(job->i2H11ptr + here->B1bNode) - + *(job->i2H11ptr + here->B1sNodePrime); + + r2h11z = *(job->r2H11ptr + here->B1dNodePrime) - + *(job->r2H11ptr + here->B1sNodePrime); + + i2h11z = *(job->i2H11ptr + here->B1dNodePrime) - + *(job->i2H11ptr + here->B1sNodePrime); + + /* draincurrent is a function of vgs,vbs,and vds; + * have got their linear kernels; now to call + * load functions + */ + + temp = DFn3F1(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + here->DrC_x3, + here->DrC_y3, + here->DrC_z3, + here->DrC_x2y, + here->DrC_x2z, + here->DrC_xy2, + here->DrC_y2z, + here->DrC_xz2, + here->DrC_yz2, + here->DrC_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + itemp = DFi3F1(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + here->DrC_x3, + here->DrC_y3, + here->DrC_z3, + here->DrC_x2y, + here->DrC_x2z, + here->DrC_xy2, + here->DrC_y2z, + here->DrC_xz2, + here->DrC_yz2, + here->DrC_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* draincurrent term loading over */ + + + + /* loading qg term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFi3F1(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + here->qg_x3, + here->qg_y3, + here->qg_z3, + here->qg_x2y, + here->qg_x2z, + here->qg_xy2, + here->qg_y2z, + here->qg_xz2, + here->qg_yz2, + here->qg_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + itemp = ckt->CKTomega * DFn3F1(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + here->qg_x3, + here->qg_y3, + here->qg_z3, + here->qg_x2y, + here->qg_x2z, + here->qg_xy2, + here->qg_y2z, + here->qg_xz2, + here->qg_yz2, + here->qg_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qg term over */ + + /* loading qb term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFi3F1(here->qb_x2, + here->qb_y2, + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + here->qb_x3, + here->qb_y3, + here->qb_z3, + here->qb_x2y, + here->qb_x2z, + here->qb_xy2, + here->qb_y2z, + here->qb_xz2, + here->qb_yz2, + here->qb_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + itemp = ckt->CKTomega * DFn3F1(here->qb_x2, + here->qb_y2, + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + here->qb_x3, + here->qb_y3, + here->qb_z3, + here->qb_x2y, + here->qb_x2z, + here->qb_xy2, + here->qb_y2z, + here->qb_xz2, + here->qb_yz2, + here->qb_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qb term over */ + + /* loading qd term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFi3F1(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + here->qd_x3, + here->qd_y3, + here->qd_z3, + here->qd_x2y, + here->qd_x2z, + here->qd_xy2, + here->qd_y2z, + here->qd_xz2, + here->qd_yz2, + here->qd_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + itemp = ckt->CKTomega * DFn3F1(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + here->qd_x3, + here->qd_y3, + here->qd_z3, + here->qd_x2y, + here->qd_x2z, + here->qd_xy2, + here->qd_y2z, + here->qd_xz2, + here->qd_yz2, + here->qd_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qd term over */ + + /* loading here->B1gbs term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r2h11x = *(job->r2H11ptr + here->B1bNode) - + *(job->r2H11ptr + here->B1sNodePrime); + i2h11x = *(job->i2H11ptr + here->B1bNode) - + *(job->i2H11ptr + here->B1sNodePrime); + + /* now r1h1x = vbs */ + + temp = D1n3F1(here->gbs2, + here->gbs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = D1i3F1(here->gbs2, + here->gbs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* here->B1gbs term over */ + + /* loading here->B1gbd term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1dNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1dNodePrime); + + r2h11x = *(job->r2H11ptr + here->B1bNode) - + *(job->r2H11ptr + here->B1dNodePrime); + i2h11x = *(job->i2H11ptr + here->B1bNode) - + *(job->i2H11ptr + here->B1dNodePrime); + + /* now r1h1x = vbd */ + + temp = D1n3F1(here->gbd2, + here->gbd3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = D1i3F1(here->gbd2, + here->gbd3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1dNodePrime) += temp; + *(ckt->CKTirhs + here->B1dNodePrime) += itemp; + + /* here->B1gbd term over */ + + /* all done */ + } + + break; + case D_F1PF2: + /* from now on, in the 3-var case, x=vgs,y=vbs,z=vds */ + + { + /* draincurrent term */ + r1h1x = *(job->r1H1ptr + here->B1gNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1gNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1y = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1y = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1z = *(job->r1H1ptr + here->B1dNodePrime) - + *(job->r1H1ptr + here->B1sNodePrime); + + i1h1z = *(job->i1H1ptr + here->B1dNodePrime) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h2x = *(job->r1H2ptr + here->B1gNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1h2x = (*(job->i1H2ptr + here->B1gNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r1h2y = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1h2y = (*(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r1h2z = *(job->r1H2ptr + here->B1dNodePrime) - + *(job->r1H2ptr + here->B1sNodePrime); + + i1h2z = (*(job->i1H2ptr + here->B1dNodePrime) - + *(job->i1H2ptr + here->B1sNodePrime)); + + /* draincurrent is a function of vgs,vbs,and vds; + * have got their linear kernels; now to call + * load functions + */ + + temp = DFnF12(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = DFiF12(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* draincurrent term loading over */ + + + + /* loading qg term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFiF12(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = ckt->CKTomega * DFnF12(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qg term over */ + + /* loading qb term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFiF12(here->qb_x2, + here->qb_y2, /* XXX Bug fixed: fewer arguments passed than declared */ + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = ckt->CKTomega * DFnF12(here->qb_x2, + here->qb_y2, + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qb term over */ + + /* loading qd term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFiF12(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = ckt->CKTomega * DFnF12(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qd term over */ + + /* loading here->B1gbs term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h2x = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1h2x = *(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1sNodePrime); + + /* now r1h1x = vbs */ + + temp = D1nF12(here->gbs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = D1iF12(here->gbs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* here->B1gbs term over */ + + /* loading here->B1gbd term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1dNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1dNodePrime); + + r1h2x = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1dNodePrime); + i1h2x = *(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1dNodePrime); + + /* now r1h1x = vbd */ + + temp = D1nF12(here->gbd2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = D1iF12(here->gbd2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1dNodePrime) += temp; + *(ckt->CKTirhs + here->B1dNodePrime) += itemp; + + /* here->B1gbd term over */ + + /* all done */ + } + + break; + case D_F1MF2: + /* from now on, in the 3-var case, x=vgs,y=vbs,z=vds */ + + { + /* draincurrent term */ + r1h1x = *(job->r1H1ptr + here->B1gNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1gNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1y = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1y = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1z = *(job->r1H1ptr + here->B1dNodePrime) - + *(job->r1H1ptr + here->B1sNodePrime); + + i1h1z = *(job->i1H1ptr + here->B1dNodePrime) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1hm2x = *(job->r1H2ptr + here->B1gNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1hm2x = -(*(job->i1H2ptr + here->B1gNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r1hm2y = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1hm2y = -(*(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r1hm2z = *(job->r1H2ptr + here->B1dNodePrime) - + *(job->r1H2ptr + here->B1sNodePrime); + + i1hm2z = -(*(job->i1H2ptr + here->B1dNodePrime) - + *(job->i1H2ptr + here->B1sNodePrime)); + + /* draincurrent is a function of vgs,vbs,and vds; + * have got their linear kernels; now to call + * load functions + */ + + temp = DFnF12(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = DFiF12(here->DrC_x2, + here->DrC_y2, + here->DrC_z2, + here->DrC_xy, + here->DrC_yz, + here->DrC_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* draincurrent term loading over */ + + + + /* loading qg term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFiF12(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = ckt->CKTomega * DFnF12(here->qg_x2, + here->qg_y2, + here->qg_z2, + here->qg_xy, + here->qg_yz, + here->qg_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qg term over */ + + /* loading qb term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFiF12(here->qb_x2, + here->qb_y2, /* XXX Bug fixed: fewer arguments passed than declared */ + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = ckt->CKTomega * DFnF12(here->qb_x2, + here->qb_y2, + here->qb_z2, + here->qb_xy, + here->qb_yz, + here->qb_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qb term over */ + + /* loading qd term */ + + /* kernels for vgs,vbs and vds already set up */ + + temp = -ckt->CKTomega * DFiF12(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = ckt->CKTomega * DFnF12(here->qd_x2, + here->qd_y2, + here->qd_z2, + here->qd_xy, + here->qd_yz, + here->qd_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qd term over */ + + /* loading here->B1gbs term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1hm2x = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1hm2x = -(*(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + /* now r1h1x = vbs */ + + temp = D1nF12(here->gbs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = D1iF12(here->gbs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* here->B1gbs term over */ + + /* loading here->B1gbd term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1dNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1dNodePrime); + + r1hm2x = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1dNodePrime); + i1hm2x = -(*(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1dNodePrime)); + + /* now r1h1x = vbd */ + + temp = D1nF12(here->gbd2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = D1iF12(here->gbd2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1dNodePrime) += temp; + *(ckt->CKTirhs + here->B1dNodePrime) += itemp; + + /* here->B1gbd term over */ + + /* all done */ + } + + break; + case D_2F1MF2: + /* from now on, in the 3-var case, x=vgs,y=vbs,z=vds */ + + { + /* draincurrent term */ + r1h1x = *(job->r1H1ptr + here->B1gNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1gNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1y = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1y = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1h1z = *(job->r1H1ptr + here->B1dNodePrime) - + *(job->r1H1ptr + here->B1sNodePrime); + + i1h1z = *(job->i1H1ptr + here->B1dNodePrime) - + *(job->i1H1ptr + here->B1sNodePrime); + + r1hm2x = *(job->r1H2ptr + here->B1gNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1hm2x = -(*(job->i1H2ptr + here->B1gNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r1hm2y = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1hm2y = -(*(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r1hm2z = *(job->r1H2ptr + here->B1dNodePrime) - + *(job->r1H2ptr + here->B1sNodePrime); + + i1hm2z = -(*(job->i1H2ptr + here->B1dNodePrime) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r2h11x = *(job->r2H11ptr + here->B1gNode) - + *(job->r2H11ptr + here->B1sNodePrime); + i2h11x = *(job->i2H11ptr + here->B1gNode) - + *(job->i2H11ptr + here->B1sNodePrime); + + r2h11y = *(job->r2H11ptr + here->B1bNode) - + *(job->r2H11ptr + here->B1sNodePrime); + i2h11y = *(job->i2H11ptr + here->B1bNode) - + *(job->i2H11ptr + here->B1sNodePrime); + + r2h11z = *(job->r2H11ptr + here->B1dNodePrime) - + *(job->r2H11ptr + here->B1sNodePrime); + + i2h11z = *(job->i2H11ptr + here->B1dNodePrime) - + *(job->i2H11ptr + here->B1sNodePrime); + + r2h1m2x = *(job->r2H1m2ptr + here->B1gNode) - + *(job->r2H1m2ptr + here->B1sNodePrime); + i2h1m2x = *(job->i2H1m2ptr + here->B1gNode) - + *(job->i2H1m2ptr + here->B1sNodePrime); + + r2h1m2y = *(job->r2H1m2ptr + here->B1bNode) - + *(job->r2H1m2ptr + here->B1sNodePrime); + i2h1m2y = *(job->i2H1m2ptr + here->B1bNode) - + *(job->i2H1m2ptr + here->B1sNodePrime); + + r2h1m2z = *(job->r2H1m2ptr + here->B1dNodePrime) - + *(job->r2H1m2ptr + here->B1sNodePrime); + + i2h1m2z = *(job->i2H1m2ptr + here->B1dNodePrime) - + *(job->i2H1m2ptr + here->B1sNodePrime); + + /* draincurrent is a function of vgs,vbs,and vds; + * have got their linear kernels; now to call + * load functions + */ + + pass.cxx = here->DrC_x2; + pass.cyy = here->DrC_y2; + pass.czz = here->DrC_z2; + pass.cxy = here->DrC_xy; + pass.cyz = here->DrC_yz; + pass.cxz = here->DrC_xz; + pass.cxxx = here->DrC_x3; + pass.cyyy = here->DrC_y3; + pass.czzz = here->DrC_z3; + pass.cxxy = here->DrC_x2y; + pass.cxxz = here->DrC_x2z; + pass.cxyy = here->DrC_xy2; + pass.cyyz = here->DrC_y2z; + pass.cxzz = here->DrC_xz2; + pass.cyzz = here->DrC_yz2; + pass.cxyz = here->DrC_xyz; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = r1h1z; + pass.i1h1z = i1h1z; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = r1hm2z; + pass.i1h2z = i1hm2z; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = r2h11z; + pass.i2h11z = i2h11z; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = r2h1m2z; + pass.ih2f1f2z = i2h1m2z; + temp = DFn2F12(&pass); + itemp = DFi2F12(&pass); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* draincurrent term loading over */ + + + + /* loading qg term */ + + /* kernels for vgs,vbs and vds already set up */ + + pass.cxx = here->qg_x2; + pass.cyy = here->qg_y2; + pass.czz = here->qg_z2; + pass.cxy = here->qg_xy; + pass.cyz = here->qg_yz; + pass.cxz = here->qg_xz; + pass.cxxx = here->qg_x3; + pass.cyyy = here->qg_y3; + pass.czzz = here->qg_z3; + pass.cxxy = here->qg_x2y; + pass.cxxz = here->qg_x2z; + pass.cxyy = here->qg_xy2; + pass.cyyz = here->qg_y2z; + pass.cxzz = here->qg_xz2; + pass.cyzz = here->qg_yz2; + pass.cxyz = here->qg_xyz; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = r1h1z; + pass.i1h1z = i1h1z; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = r1hm2z; + pass.i1h2z = i1hm2z; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = r2h11z; + pass.i2h11z = i2h11z; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = r2h1m2z; + pass.ih2f1f2z = i2h1m2z; + temp = -ckt->CKTomega * DFi2F12(&pass); + + itemp = ckt->CKTomega * DFn2F12(&pass); + + *(ckt->CKTrhs + here->B1gNode) -= temp; + *(ckt->CKTirhs + here->B1gNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qg term over */ + + /* loading qb term */ + + /* kernels for vgs,vbs and vds already set up */ + + pass.cxx = here->qb_x2; + pass.cyy = here->qb_y2; + pass.czz = here->qb_z2; + pass.cxy = here->qb_xy; + pass.cyz = here->qb_yz; + pass.cxz = here->qb_xz; + pass.cxxx = here->qb_x3; + pass.cyyy = here->qb_y3; + pass.czzz = here->qb_z3; + pass.cxxy = here->qb_x2y; + pass.cxxz = here->qb_x2z; + pass.cxyy = here->qb_xy2; + pass.cyyz = here->qb_y2z; + pass.cxzz = here->qb_xz2; + pass.cyzz = here->qb_yz2; + pass.cxyz = here->qb_xyz; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = r1h1z; + pass.i1h1z = i1h1z; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = r1hm2z; + pass.i1h2z = i1hm2z; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = r2h11z; + pass.i2h11z = i2h11z; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = r2h1m2z; + pass.ih2f1f2z = i2h1m2z; + temp = -ckt->CKTomega * DFi2F12(&pass); + + itemp = ckt->CKTomega * DFn2F12(&pass); + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qb term over */ + + /* loading qd term */ + + /* kernels for vgs,vbs and vds already set up */ + + pass.cxx = here->qd_x2; + pass.cyy = here->qd_y2; + pass.czz = here->qd_z2; + pass.cxy = here->qd_xy; + pass.cyz = here->qd_yz; + pass.cxz = here->qd_xz; + pass.cxxx = here->qd_x3; + pass.cyyy = here->qd_y3; + pass.czzz = here->qd_z3; + pass.cxxy = here->qd_x2y; + pass.cxxz = here->qd_x2z; + pass.cxyy = here->qd_xy2; + pass.cyyz = here->qd_y2z; + pass.cxzz = here->qd_xz2; + pass.cyzz = here->qd_yz2; + pass.cxyz = here->qd_xyz; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = r1h1z; + pass.i1h1z = i1h1z; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = r1hm2z; + pass.i1h2z = i1hm2z; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = r2h11z; + pass.i2h11z = i2h11z; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = r2h1m2z; + pass.ih2f1f2z = i2h1m2z; + temp = -ckt->CKTomega * DFi2F12(&pass); + + itemp = ckt->CKTomega * DFn2F12(&pass); + + *(ckt->CKTrhs + here->B1dNodePrime) -= temp; + *(ckt->CKTirhs + here->B1dNodePrime) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* qd term over */ + + /* loading here->B1gbs term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1sNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1sNodePrime); + + r2h11x = *(job->r2H11ptr + here->B1bNode) - + *(job->r2H11ptr + here->B1sNodePrime); + i2h11x = *(job->i2H11ptr + here->B1bNode) - + *(job->i2H11ptr + here->B1sNodePrime); + + r1hm2x = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1sNodePrime); + i1hm2x = -(*(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1sNodePrime)); + + r2h1m2x = *(job->r2H1m2ptr + here->B1bNode) - + *(job->r2H1m2ptr + here->B1sNodePrime); + i2h1m2x = *(job->i2H1m2ptr + here->B1bNode) - + *(job->i2H1m2ptr + here->B1sNodePrime); + + /* now r1h1x = vbs */ + + temp = D1n2F12(here->gbs2, + here->gbs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = D1i2F12(here->gbs2, + here->gbs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1sNodePrime) += temp; + *(ckt->CKTirhs + here->B1sNodePrime) += itemp; + + /* here->B1gbs term over */ + + /* loading here->B1gbd term */ + + r1h1x = *(job->r1H1ptr + here->B1bNode) - + *(job->r1H1ptr + here->B1dNodePrime); + i1h1x = *(job->i1H1ptr + here->B1bNode) - + *(job->i1H1ptr + here->B1dNodePrime); + + r2h11x = *(job->r2H11ptr + here->B1bNode) - + *(job->r2H11ptr + here->B1dNodePrime); + i2h11x = *(job->i2H11ptr + here->B1bNode) - + *(job->i2H11ptr + here->B1dNodePrime); + + r1hm2x = *(job->r1H2ptr + here->B1bNode) - + *(job->r1H2ptr + here->B1dNodePrime); + i1hm2x = -(*(job->i1H2ptr + here->B1bNode) - + *(job->i1H2ptr + here->B1dNodePrime)); + + r2h1m2x = *(job->r2H1m2ptr + here->B1bNode) - + *(job->r2H1m2ptr + here->B1dNodePrime); + i2h1m2x = *(job->i2H1m2ptr + here->B1bNode) - + *(job->i2H1m2ptr + here->B1dNodePrime); + + /* now r1h1x = vbd */ + + temp = D1n2F12(here->gbd2, + here->gbd3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = D1i2F12(here->gbd2, + here->gbd3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + + *(ckt->CKTrhs + here->B1bNode) -= temp; + *(ckt->CKTirhs + here->B1bNode) -= itemp; + + *(ckt->CKTrhs + here->B1dNodePrime) += temp; + *(ckt->CKTirhs + here->B1dNodePrime) += itemp; + + /* here->B1gbd term over */ + + /* all done */ + } + + break; + default: +; + ; + } + } +} +return(OK); +} +else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/bsim1/b1dset.c b/src/spicelib/devices/bsim1/b1dset.c new file mode 100644 index 000000000..e6a410b40 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1dset.c @@ -0,0 +1,1301 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "trandefs.h" +#include "distodef.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" +#include "devdefs.h" + +int +B1dSetup(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + +{ + register B1model* model = (B1model*)inModel; + register B1instance *here; + double DrainSatCurrent; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double SourceSatCurrent; + double DrainArea; + double SourceArea; + double DrainPerimeter; + double SourcePerimeter; + double vt0; + double evbs; + double lgbs1, lgbs2, lgbs3; + double czbd, czbs, czbdsw, czbssw; + double PhiB, MJ, MJSW, PhiBSW; + double arg, argsw, sarg, sargsw; + double capbs1, capbs2, capbs3; + double capbd1, capbd2, capbd3; + double qg; + double qb; + double qd; + double Vfb; + double Phi; + double K1; + double K2; + double Vdd; + double Ugs; + double Uds; + double Leff; + double Eta; + double Vpb; + double SqrtVpb; + double Von; + double Vth; + double DrCur; + double G; + double A; + double Arg; + double Beta; + double Beta_Vds_0; + double BVdd; + double Beta0; + double VddSquare; + double C1; + double C2; + double VdsSat; + double Argl1; + double Argl2; + double Vc; + double Term1; + double K; + double Args1; + double Args2; + double Args3; + double Warg1; + double Vcut; + double N; + double N0; + double NB; + double ND; + double Warg2; + double Wds; + double Wgs; + double Ilimit; + double Iexp; + double Vth0; + double Arg1; + double Arg2; + double Arg3; + double Arg5; + double Ent; + double Vcom; + double Vgb; + double Vgb_Vfb; + double VdsPinchoff; + double EntSquare; + double Argl5; + double Argl6; + double Argl7; + double WLCox; + double Vtsquare; + int ChargeComputationNeeded; + double co4v15; + double VgsVth = 0.0; + double lgbd1, lgbd2, lgbd3, evbd; + double vbd = 0.0; + double vgd = 0.0; + double vgb = 0.0; + double vds = 0.0; + double vgs = 0.0; + double vbs = 0.0; + double dBVdddVds; + Dderivs d_Argl6; + Dderivs d_Vgb, d_Vgb_Vfb, d_EntSquare, d_Argl5, d_Argl7; + Dderivs d_Arg5, d_Ent, d_Vcom, d_VdsPinchoff; + Dderivs d_qb, d_qd, d_Vth0, d_Arg1, d_Arg2, d_Arg3; + Dderivs d_dummy, d_Vth, d_BVdd, d_Warg1, d_qg; + Dderivs d_N, d_Wds, d_Wgs, d_Iexp; + Dderivs d_Argl1, d_Argl2, d_Args1, d_Args2, d_Args3; + Dderivs d_Beta, d_Vc, d_Term1, d_K, d_VdsSat; + Dderivs d_Beta_Vds_0, d_C1, d_C2, d_Beta0; + Dderivs d_VgsVth, d_G, d_A, d_Arg, d_DrCur; + Dderivs d_Ugs, d_Uds, d_Eta, d_Vpb, d_SqrtVpb, d_Von; + Dderivs d_p, d_q, d_r, d_zero; + + + /* loop through all the B1 device models */ + for( ; model != NULL; model = model->B1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->B1instances; here != NULL ; + here=here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + EffectiveLength=here->B1l - model->B1deltaL * 1.e-6;/* m */ + DrainArea = here->B1drainArea; + SourceArea = here->B1sourceArea; + DrainPerimeter = here->B1drainPerimeter; + SourcePerimeter = here->B1sourcePerimeter; + if( (DrainSatCurrent=DrainArea*model->B1jctSatCurDensity) + < 1e-15){ + DrainSatCurrent = 1.0e-15; + } + if( (SourceSatCurrent=SourceArea*model->B1jctSatCurDensity) + <1.0e-15){ + SourceSatCurrent = 1.0e-15; + } + GateSourceOverlapCap = model->B1gateSourceOverlapCap *here->B1w; + GateDrainOverlapCap = model->B1gateDrainOverlapCap * here->B1w; + GateBulkOverlapCap = model->B1gateBulkOverlapCap *EffectiveLength; + vt0 = model->B1type * here->B1vt0; + + vbs = model->B1type * ( + *(ckt->CKTrhsOld+here->B1bNode) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + vgs = model->B1type * ( + *(ckt->CKTrhsOld+here->B1gNode) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + vds = model->B1type * ( + *(ckt->CKTrhsOld+here->B1dNodePrime) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + + if(vds >= 0) { + /* normal mode */ + here->B1mode = 1; + } else { + /* inverse mode */ + here->B1mode = -1; + vds = -vds; + vgs = vgs + vds; /* these are the local(fake) values now */ + vbs = vbs + vds; + } + + vgb = vgs - vbs; + vgd = vgs - vds; + vbd = vbs - vds; + + if(vbs <= 0.0 ) { + lgbs1 = SourceSatCurrent / CONSTvt0 + ckt->CKTgmin; + lgbs2 = lgbs3 = 0.0; + } else { + evbs = exp(vbs/CONSTvt0); + lgbs1 = SourceSatCurrent*evbs/CONSTvt0 + ckt->CKTgmin; + lgbs2 = (lgbs1 - ckt->CKTgmin)/(CONSTvt0*2); + lgbs3 = lgbs2/(CONSTvt0*3); + } + if(vbd <= 0.0) { + lgbd1 = DrainSatCurrent / CONSTvt0 + ckt->CKTgmin; + lgbd2 = lgbd3 = 0.0; + } else { + evbd = exp(vbd/CONSTvt0); + lgbd1 = DrainSatCurrent*evbd/CONSTvt0 +ckt->CKTgmin; + lgbd2 = (lgbd1 - ckt->CKTgmin)/(CONSTvt0*2); + lgbd3 = lgbd2/(CONSTvt0*3); + } + /* line 400 */ + /* call B1evaluate to calculate drain current and its + * derivatives and charge and capacitances related to gate + * drain, and bulk + */ + + /* check quadratic interpolation for beta0 ; line 360 */ + /* + * Copyright (c) 1985 Hong J. Park, Thomas L. Quarles + * modified 1988 Jaijeet Roychowdhury + */ + + /* This routine evaluates the drain current, its derivatives and the + * charges associated with the gate,bulk and drain terminal + * using the B1 (Berkeley Short-Channel IGFET Model) Equations. + */ + /* as usual p=vgs, q=vbs, r=vds */ + { + + ChargeComputationNeeded = 1; + + Vfb = here->B1vfb; + Phi = here->B1phi; + K1 = here->B1K1; + K2 = here->B1K2; + Vdd = model->B1vdd; + d_p.value = 0.0; + d_p.d1_p = 1.0; + d_p.d1_q = 0.0; + d_p.d1_r = 0.0; + d_p.d2_p2 = 0.0; + d_p.d2_q2 = 0.0; + d_p.d2_r2 = 0.0; + d_p.d2_pq = 0.0; + d_p.d2_qr = 0.0; + d_p.d2_pr = 0.0; + d_p.d3_p3 = 0.0; + d_p.d3_q3 = 0.0; + d_p.d3_r3 = 0.0; + d_p.d3_p2r = 0.0; + d_p.d3_p2q = 0.0; + d_p.d3_q2r = 0.0; + d_p.d3_pq2 = 0.0; + d_p.d3_pr2 = 0.0; + d_p.d3_qr2 = 0.0; + d_p.d3_pqr = 0.0; + EqualDeriv(&d_q,&d_p); + EqualDeriv(&d_r,&d_p); + EqualDeriv(&d_zero,&d_p); + d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0; + d_q.d1_q = d_r.d1_r = 1.0; + d_p.value = vgs; d_q.value = vbs; d_r.value = vds; + + if((Ugs = here->B1ugs + here->B1ugsB * vbs) <= 0 ) { + Ugs = 0; + EqualDeriv(&d_Ugs,&d_zero); + } else { + EqualDeriv(&d_Ugs,&d_q); + d_Ugs.value = Ugs; + d_Ugs.d1_q = here->B1ugsB; + } + if((Uds = here->B1uds + here->B1udsB * vbs + + here->B1udsD*(vds-Vdd)) <= 0 ) { + Uds = 0.0; + EqualDeriv(&d_Uds,&d_zero); + } else { + Leff = here->B1l * 1.e6 - model->B1deltaL; /* Leff in um */ + /*const*/ + Uds = Uds / Leff; + /* Uds = (here->B1uds + here->B1udsB * vbs here->B1udsD* + (vds-Vdd))/Leff */ + EqualDeriv(&d_Uds,&d_r); + d_Uds.value = Uds; + d_Uds.d1_r = here->B1udsD/Leff; + d_Uds.d1_q = here->B1udsB/Leff; + } + Eta = here->B1eta + here->B1etaB * vbs + here->B1etaD * + (vds - Vdd); + EqualDeriv(&d_Eta,&d_r); + d_Eta.value = Eta; + d_Eta.d1_r = here->B1etaD; + d_Eta.d1_q = here->B1etaB; + + if( Eta <= 0 ) { + Eta = 0; + EqualDeriv(&d_Eta,&d_zero); + } else if ( Eta > 1 ) { + Eta = 1; + EqualDeriv(&d_Eta,&d_zero); + d_Eta.value = 1.0; + } + if( vbs < 0 ) { + Vpb = Phi - vbs; + EqualDeriv(&d_Vpb,&d_q); + d_Vpb.value = Vpb; + d_Vpb.d1_q = -1; + } else { + Vpb = Phi; + EqualDeriv(&d_Vpb,&d_zero); + d_Vpb.value = Phi; + } + SqrtVpb = sqrt( Vpb ); + SqrtDeriv(&d_SqrtVpb,&d_Vpb); + Von = Vfb + Phi + K1 * SqrtVpb - K2 * Vpb - Eta * vds; + EqualDeriv(&d_dummy,&d_r); + d_dummy.value = -Eta*vds; + d_dummy.d1_r = -Eta; + TimesDeriv(&d_Von,&d_Vpb,-K2); + PlusDeriv(&d_Von,&d_Von,&d_dummy); + TimesDeriv(&d_dummy,&d_SqrtVpb,K1); + PlusDeriv(&d_Von,&d_dummy,&d_Von); + d_Von.value = Von; + Vth = Von; + EqualDeriv(&d_Vth,&d_Von); + VgsVth = vgs - Vth; + TimesDeriv(&d_VgsVth,&d_Vth,-1.0); + d_VgsVth.value = VgsVth; + d_VgsVth.d1_p += 1.0; + + G = 1./(1.744+0.8364 * Vpb); + TimesDeriv(&d_G,&d_Vpb,0.8364); + d_G.value += 1.744; + InvDeriv(&d_G,&d_G); + G = 1 - G; + TimesDeriv(&d_G,&d_G,-1.0); + d_G.value += 1.0; + A = G/SqrtVpb; + DivDeriv(&d_A,&d_G,&d_SqrtVpb); + A = 1.0 + 0.5*K1*A; + TimesDeriv(&d_A,&d_A,0.5*K1); + d_A.value += 1.0; + A = MAX( A, 1.0); /* Modified */ + if (A <= 1.0) { + EqualDeriv(&d_A,&d_zero); + d_A.value = 1.0; + } + Arg = MAX(( 1 + Ugs * VgsVth), 1.0); + MultDeriv(&d_dummy,&d_Ugs,&d_VgsVth); + d_dummy.value += 1.0; + if (d_dummy.value <= 1.0) { + EqualDeriv(&d_Arg,&d_zero); + d_Arg.value = 1.0; + } + else + EqualDeriv(&d_Arg,&d_dummy); + + if( VgsVth < 0 ) { + /* cutoff */ + DrCur = 0; + EqualDeriv(&d_DrCur,&d_zero); + goto SubthresholdComputation; + } + + /* Quadratic Interpolation for Beta0 (Beta at vgs = 0, vds=Vds) */ + + Beta_Vds_0 = (here->B1betaZero + here->B1betaZeroB * vbs); + EqualDeriv(&d_Beta_Vds_0,&d_q); + d_Beta_Vds_0.value = Beta_Vds_0; + d_Beta_Vds_0.d1_q = here->B1betaZeroB; + BVdd = (here->B1betaVdd + here->B1betaVddB * vbs); + EqualDeriv(&d_BVdd,&d_q); + d_BVdd.value = BVdd; + d_BVdd.d1_q = here->B1betaVddB; + dBVdddVds = MAX( here->B1betaVddD, 0.0); + + + /* is the above wrong ?!? */ + + + + if( vds > Vdd ) { + Beta0 = BVdd + dBVdddVds * (vds - Vdd); + EqualDeriv(&d_Beta0,&d_r); d_Beta0.value = vds - Vdd; + TimesDeriv(&d_Beta0,&d_Beta0,dBVdddVds); + PlusDeriv(&d_Beta0,&d_Beta0,&d_BVdd); + /* dBVdddVds = const */ + + + /* and this stuff here? */ + + } else { + VddSquare = Vdd * Vdd; /* const */ + C1 = ( -BVdd + Beta_Vds_0 + dBVdddVds * Vdd) / VddSquare; + TimesDeriv(&d_C1,&d_BVdd,-1.0); + PlusDeriv(&d_C1,&d_C1,&d_Beta_Vds_0); + d_C1.value += dBVdddVds * Vdd; + TimesDeriv(&d_C1,&d_C1,1/VddSquare); + + C2 = 2 * (BVdd - Beta_Vds_0) / Vdd - dBVdddVds; + TimesDeriv(&d_C2,&d_Beta_Vds_0,-1.0); + PlusDeriv(&d_C2,&d_C2,&d_BVdd); + TimesDeriv(&d_C2,&d_C2,2/Vdd); + d_C2.value -= dBVdddVds; + Beta0 = (C1 * vds + C2) * vds + Beta_Vds_0; + MultDeriv(&d_Beta0,&d_r,&d_C1); + PlusDeriv(&d_Beta0,&d_Beta0,&d_C2); + MultDeriv(&d_Beta0,&d_Beta0,&d_dummy); + PlusDeriv(&d_Beta0,&d_Beta0,&d_Beta_Vds_0); + + /* + dBeta0dVds = 2*C1*vds + C2; + dBeta0dVbs = dC1dVbs * vds * vds + dC2dVbs * vds + dBeta_Vds_0_dVbs; + maybe we'll need these later */ + } + + /*Beta = Beta0 / ( 1 + Ugs * VgsVth );*/ + + Beta = Beta0 / Arg ; + DivDeriv(&d_Beta,&d_Beta0,&d_Arg); + + /*VdsSat = MAX( VgsVth / ( A + Uds * VgsVth ), 0.0);*/ + + Vc = Uds * VgsVth / A; + DivDeriv(&d_Vc,&d_VgsVth,&d_A); + MultDeriv(&d_Vc,&d_Vc,&d_Uds); + + if(Vc < 0.0 ) { + EqualDeriv(&d_Vc,&d_zero); + Vc=0.0; + } + Term1 = sqrt( 1 + 2 * Vc ); + TimesDeriv(&d_Term1,&d_Vc,2.0); + d_Term1.value += 1.0; + SqrtDeriv(&d_Term1,&d_Term1); + K = 0.5 * ( 1 + Vc + Term1 ); + PlusDeriv(&d_K,&d_Vc,&d_Term1); + d_K.value += 1.0; + TimesDeriv(&d_K,&d_K,0.5); + VdsSat = VgsVth / ( A * sqrt(K)); + if (VdsSat < 0.0) { + EqualDeriv(&d_VdsSat,&d_zero); + VdsSat = 0.0; + } + else + { + SqrtDeriv(&d_VdsSat,&d_K); + MultDeriv(&d_VdsSat,&d_VdsSat,&d_A); + DivDeriv(&d_VdsSat,&d_VgsVth,&d_VdsSat); + } + + if( vds < VdsSat ) { + /* Triode Region */ + /*Argl1 = 1 + Uds * vds;*/ + Argl1 = 1 + Uds * vds; + if (Argl1 < 1.0) { + Argl1 = 1.0; + EqualDeriv(&d_Argl1,&d_zero); + d_Argl1.value = 1.0; + } + else + { + MultDeriv(&d_Argl1,&d_r,&d_Uds); + d_Argl1.value += 1.0; + } + + + Argl2 = VgsVth - 0.5 * A * vds; + MultDeriv(&d_Argl2,&d_r,&d_A); + TimesDeriv(&d_Argl2,&d_Argl2,-0.5); + PlusDeriv(&d_Argl2,&d_Argl2,&d_VgsVth); + DrCur = Beta * Argl2 * vds / Argl1; + DivDeriv(&d_DrCur,&d_r,&d_Argl1); + MultDeriv(&d_DrCur,&d_DrCur,&d_Argl2); + MultDeriv(&d_DrCur,&d_DrCur,&d_Beta); + } else { + /* Pinchoff (Saturation) Region */ + /* history + Args1 = 1.0 + 1. / Term1; + InvDeriv(&d_Args1,&d_Term1); + d_Args1.value += 1.0; + */ + /* dVcdVgs = Uds / A; + dVcdVds = VgsVth * dUdsdVds / A - dVcdVgs * dVthdVds; + dVcdVbs = ( VgsVth * dUdsdVbs - Uds * + (dVthdVbs + VgsVth * dAdVbs / A ))/ A; + dKdVc = 0.5* Args1; + dKdVgs = dKdVc * dVcdVgs; + dKdVds = dKdVc * dVcdVds; + dKdVbs = dKdVc * dVcdVbs; */ + Args2 = VgsVth / A / K; + MultDeriv(&d_Args2,&d_A,&d_K); + DivDeriv(&d_Args2,&d_VgsVth,&d_Args2); + Args3 = Args2 * VgsVth; + MultDeriv(&d_Args3,&d_Args2,&d_VgsVth); + DrCur = 0.5 * Beta * Args3; + MultDeriv(&d_DrCur,&d_Beta,&d_Args3); + TimesDeriv(&d_DrCur,&d_DrCur,0.5); + } + + SubthresholdComputation: + + N0 = here->B1subthSlope;/*const*/ + Vcut = - 40. * N0 * CONSTvt0 ;/*const*/ + if( (N0 >= 200) || (VgsVth < Vcut ) || (VgsVth > (-0.5*Vcut))) { + goto ChargeComputation; + } + + NB = here->B1subthSlopeB;/*const*/ + ND = here->B1subthSlopeD;/*const*/ + N = N0 + NB * vbs + ND * vds; /* subthreshold slope */ + EqualDeriv(&d_N,&d_r); + d_N.value = N; + d_N.d1_q = NB; + d_N.d1_r = ND; + if( N < 0.5 ){ N = 0.5; + d_N.value = 0.5; + d_N.d1_q = d_N.d1_r = 0.0; + } + Warg1 = exp( - vds / CONSTvt0 ); + TimesDeriv(&d_Warg1,&d_r,-1/CONSTvt0); + ExpDeriv(&d_Warg1,&d_Warg1); + Wds = 1 - Warg1; + TimesDeriv(&d_Wds,&d_Warg1,-1.0); + d_Wds.value += 1.0; + Wgs = exp( VgsVth / ( N * CONSTvt0 )); + DivDeriv(&d_Wgs,&d_VgsVth,&d_N); + TimesDeriv(&d_Wgs,&d_Wgs,1/CONSTvt0); + ExpDeriv(&d_Wgs,&d_Wgs); + Vtsquare = CONSTvt0 * CONSTvt0 ;/*const*/ + Warg2 = 6.04965 * Vtsquare * here->B1betaZero;/*const*/ + Ilimit = 4.5 * Vtsquare * here->B1betaZero;/*const*/ + Iexp = Warg2 * Wgs * Wds; + MultDeriv(&d_Iexp,&d_Wgs,&d_Wds); + TimesDeriv(&d_Iexp,&d_Iexp,Warg2); + DrCur = DrCur + Ilimit * Iexp / ( Ilimit + Iexp ); + EqualDeriv(&d_dummy,&d_Iexp); + d_dummy.value += Ilimit; + InvDeriv(&d_dummy,&d_dummy); + MultDeriv(&d_dummy,&d_dummy,&d_Iexp); + TimesDeriv(&d_dummy,&d_dummy,Ilimit); + PlusDeriv(&d_DrCur,&d_DrCur,&d_dummy); + + /* gds term has been modified to prevent blow up at Vds=0 */ + /* gds = gds + Temp3 * ( -Wds / N / CONSTvt0 * (dVthdVds + + VgsVth * ND / N ) + Warg1 / CONSTvt0 ); */ + + ChargeComputation: + + /* Some Limiting of DC Parameters */ + /* if(DrCur < 0.0) DrCur = 0.0; + if(gm < 0.0) gm = 0.0; + if(gds < 0.0) gds = 0.0; + if(gmbs < 0.0) gmbs = 0.0; + */ + + WLCox = model->B1Cox * + (here->B1l - model->B1deltaL * 1.e-6) * + (here->B1w - model->B1deltaW * 1.e-6) * 1.e4; /* F */ + + if( ! ChargeComputationNeeded ) { + qg = 0; + qd = 0; + qb = 0; + EqualDeriv(&d_qg,&d_zero); + EqualDeriv(&d_qb,&d_zero); + EqualDeriv(&d_qd,&d_zero); + goto finished; + } + G = 1.0 - 1./(1.744+0.8364 * Vpb); + TimesDeriv(&d_G,&d_Vpb,-0.8364); + d_G.value -= 1.744; + InvDeriv(&d_G,&d_G); + d_G.value += 1.0; + + A = 1.0 + 0.5*K1*G/SqrtVpb; + if (A < 1.0) { + A = 1.0; + EqualDeriv(&d_A,&d_zero); + d_A.value = 1.0; + } + else + { + DivDeriv(&d_A,&d_G,&d_SqrtVpb); + TimesDeriv(&d_A,&d_A,0.5*K1); + d_A.value += 1.0; + } + + /*Arg = 1 + Ugs * VgsVth;*/ + Phi = MAX( 0.1, Phi);/*const*/ + + if( model->B1channelChargePartitionFlag >= 1 ) { + + /*0/100 partitioning for drain/source chArges at the saturation region*/ + Vth0 = Vfb + Phi + K1 * SqrtVpb; + TimesDeriv(&d_Vth0,&d_SqrtVpb,K1); + d_Vth0.value += Vfb + Phi; + VgsVth = vgs - Vth0; + TimesDeriv(&d_VgsVth,&d_Vth0,-1.0); + PlusDeriv(&d_VgsVth,&d_VgsVth,&d_p); + Arg1 = A * vds; + MultDeriv(&d_Arg1,&d_A,&d_r); + Arg2 = VgsVth - 0.5 * Arg1; + TimesDeriv(&d_Arg2,&d_Arg1,-0.5); + PlusDeriv(&d_Arg2,&d_Arg2,&d_VgsVth); + Arg3 = vds - Arg1; + TimesDeriv(&d_Arg3,&d_Arg1,-1.0); + PlusDeriv(&d_Arg3,&d_Arg3,&d_r); + Arg5 = Arg1 * Arg1; + MultDeriv(&d_Arg5,&d_Arg1,&d_Arg1); + + Ent = MAX(Arg2,1.0e-8); + if (Arg2 < 1.0e-8) { + EqualDeriv(&d_Ent,&d_zero); + d_Ent.value = 1.0e-8; + } + else + { + EqualDeriv(&d_Ent,&d_Arg2); + } + + Vcom = VgsVth * VgsVth / 6.0 - 1.25e-1 * Arg1 * + VgsVth + 2.5e-2 * Arg5; + TimesDeriv(&d_dummy,&d_Arg1,-0.125); + TimesDeriv(&d_Vcom,&d_VgsVth,1/6.0); + PlusDeriv(&d_Vcom,&d_Vcom,&d_dummy); + MultDeriv(&d_Vcom,&d_Vcom,&d_VgsVth); + TimesDeriv(&d_dummy,&d_Arg5,2.5e-2); + PlusDeriv(&d_Vcom,&d_Vcom,&d_dummy); + VdsPinchoff = VgsVth / A; + if (VdsPinchoff < 0.0) { + VdsPinchoff = 0.0; + EqualDeriv(&d_VdsPinchoff,&d_zero); + } + else + { + DivDeriv(&d_VdsPinchoff,&d_VgsVth,&d_A); + } + Vgb = vgs - vbs ; + EqualDeriv(&d_Vgb,&d_p); + d_Vgb.value = Vgb; + d_Vgb.d1_q = -1.0; + Vgb_Vfb = Vgb - Vfb; + EqualDeriv(&d_Vgb_Vfb,&d_Vgb); + d_Vgb_Vfb.value -= Vfb; + + if( Vgb_Vfb < 0){ + /* Accumulation Region */ + qg = WLCox * Vgb_Vfb; + TimesDeriv(&d_qg,&d_Vgb_Vfb,WLCox); + qb = - qg; + TimesDeriv(&d_qb,&d_qg,-1.0); + qd = 0. ; + EqualDeriv(&d_qd,&d_zero); + goto finished; + } else if ( vgs < Vth0 ){ + /* Subthreshold Region */ + qg = 0.5 * WLCox * K1 * K1 * (-1 + + sqrt(1 + 4 * Vgb_Vfb / (K1 * K1))); + TimesDeriv(&d_qg,&d_Vgb_Vfb,4/(K1*K1)); + d_qg.value += 1.0; + SqrtDeriv(&d_qg,&d_qg); + d_qg.value -= 1.0; + TimesDeriv(&d_qg,&d_qg,0.5 * WLCox * K1 * K1); + qb = -qg; + TimesDeriv(&d_qb,&d_qg,-1.0); + qd = 0.; + EqualDeriv(&d_qd,&d_zero); + goto finished; + } else if( vds < VdsPinchoff ){ /* triode region */ + /*VgsVth2 = VgsVth*VgsVth;*/ + EntSquare = Ent * Ent; + MultDeriv(&d_EntSquare,&d_Ent,&d_Ent); + Argl1 = 1.2e1 * EntSquare; + TimesDeriv(&d_Argl1,&d_EntSquare,12.0); + Argl2 = 1.0 - A; + TimesDeriv(&d_Argl2,&d_A,-1.0); + d_Argl2.value += 1.0; + /* + Argl3 = Arg1 * vds; + MultDeriv(&d_Argl3,&d_Arg1,&d_r); + */ + /*Argl4 = Vcom/Ent/EntSquare;*/ + if (Ent > 1.0e-8) { + Argl5 = Arg1 / Ent; + DivDeriv(&d_Argl5,&d_Arg1,&d_Ent); + /*Argl6 = Vcom/EntSquare;*/ + } else { + Argl5 = 2.0; + EqualDeriv(&d_Argl5,&d_zero); + d_Argl5.value = 2.0; + Argl6 = 4.0 / 1.5e1;/*const*/ + } + Argl7 = Argl5 / 1.2e1; + TimesDeriv(&d_Argl7,&d_Argl5,1.0/12.0); + /* + Argl8 = 6.0 * Ent; + TimesDeriv(&d_Argl8,&d_Ent,6.0); + Argl9 = 0.125 * Argl5 * Argl5; + MultDeriv(&d_Argl9,&d_Argl5,&d_Argl5); + TimesDeriv(&d_Argl9,&d_Argl9,0.125); + */ + qg = WLCox * (vgs - Vfb - Phi - 0.5 * vds + vds * Argl7); + EqualDeriv(&d_qg,&d_Argl7); + d_qg.value -= 0.5; + MultDeriv(&d_qg,&d_qg,&d_r); + d_qg.value += vgs - Vfb - Phi; + d_qg.d1_p += 1.0; + TimesDeriv(&d_qg,&d_qg,WLCox); + qb = WLCox * ( - Vth0 + Vfb + Phi + 0.5 * Arg3 - Arg3 * Argl7); + TimesDeriv(&d_qb,&d_Argl7,-1.0); + d_qb.value += 0.5; + MultDeriv(&d_qb,&d_qb,&d_Arg3); + d_qb.value += Vfb + Phi; + TimesDeriv(&d_dummy,&d_Vth0,-1.0); + PlusDeriv(&d_qb,&d_qb,&d_dummy); + TimesDeriv(&d_qb,&d_qb,WLCox); + qd = - WLCox * (0.5 * VgsVth - 0.75 * Arg1 + + 0.125 * Arg1 * Argl5); + TimesDeriv(&d_qd,&d_Argl5,0.125); + d_qd.value -= 0.75; + MultDeriv(&d_qd,&d_qd,&d_Arg1); + TimesDeriv(&d_dummy,&d_VgsVth,0.5); + PlusDeriv(&d_qd,&d_qd,&d_dummy); + TimesDeriv(&d_qd,&d_qd, -WLCox); + goto finished; + } else if( vds >= VdsPinchoff ) { /* saturation region */ + Args1 = 1.0 / (3*A); + TimesDeriv(&d_Args1,&d_A,3.0); + InvDeriv(&d_Args1,&d_Args1); + qg = WLCox * (vgs - Vfb - Phi - VgsVth * Args1); + MultDeriv(&d_qg,&d_VgsVth,&d_Args1); + d_qg.value += Vfb + Phi - vgs; + d_qg.d1_p -= 1.0; + TimesDeriv(&d_qg,&d_qg,-WLCox); + qb = WLCox * (Vfb + Phi - Vth0 + (1.0 - A) * VgsVth * Args1); + TimesDeriv(&d_dummy,&d_A,-1.0); + d_dummy.value += 1.0; + MultDeriv(&d_qb,&d_VgsVth, &d_dummy); + MultDeriv(&d_qb,&d_qb,&d_Args1); + d_qb.value += Vfb + Phi; + TimesDeriv(&d_dummy,&d_Vth0,-1.0); + PlusDeriv(&d_qb,&d_qb,&d_dummy); + TimesDeriv(&d_qb,&d_qb,WLCox); + qd = 0.0; + EqualDeriv(&d_qd,&d_zero); + goto finished; + } + + goto finished; + + } else { + + /*0/100 partitioning for drain/source chArges at the saturation region*/ + co4v15 = 1./15.; + Vth0 = Vfb + Phi + K1 * SqrtVpb; + TimesDeriv(&d_Vth0,&d_SqrtVpb,K1); + d_Vth0.value += Vfb + Phi; + VgsVth = vgs - Vth0; + TimesDeriv(&d_VgsVth,&d_Vth0,-1.0); + d_VgsVth.value += vgs; + d_VgsVth.d1_p += 1.0; + Arg1 = A * vds; + MultDeriv(&d_Arg1,&d_A,&d_r); + Arg2 = VgsVth - 0.5 * Arg1; + TimesDeriv(&d_Arg2,&d_Arg1,-0.5); + PlusDeriv(&d_Arg2,&d_Arg2,&d_VgsVth); + Arg3 = vds - Arg1; + TimesDeriv(&d_Arg3,&d_Arg1,-1.0); + d_Arg3.value = Arg3; + d_Arg3.d1_r += 1.0; + Arg5 = Arg1 * Arg1; + MultDeriv(&d_Arg5,&d_Arg1,&d_Arg1); + Ent = MAX(Arg2,1.0e-8); + if (Arg2 < 1.0e-8) { + EqualDeriv(&d_Ent,&d_zero); + d_Ent.value = Ent; + } + else + { + EqualDeriv(&d_Ent,&d_Arg2); + } + + Vcom = VgsVth * VgsVth / 6.0 - 1.25e-1 * Arg1 * + VgsVth + 2.5e-2 * Arg5; + TimesDeriv(&d_dummy,&d_VgsVth,1/6.0); + TimesDeriv(&d_Vcom,&d_Arg1,-0.125); + PlusDeriv(&d_Vcom,&d_Vcom,&d_dummy); + MultDeriv(&d_Vcom,&d_Vcom,&d_VgsVth); + TimesDeriv(&d_dummy,&d_Arg5,2.5e-2); + PlusDeriv(&d_Vcom,&d_Vcom,&d_dummy); + VdsPinchoff = VgsVth / A; + if (VdsPinchoff < 0.0) { + VdsPinchoff = 0.0; + EqualDeriv(&d_VdsPinchoff,&d_zero); + } + else + { + DivDeriv(&d_VdsPinchoff,&d_VgsVth,&d_A); + } + + Vgb = vgs - vbs ; + EqualDeriv(&d_Vgb,&d_p); + d_Vgb.value = Vgb; + d_Vgb.d1_q = -1.0; + Vgb_Vfb = Vgb - Vfb; + EqualDeriv(&d_Vgb_Vfb,&d_Vgb); + d_Vgb_Vfb.value = Vgb_Vfb; + + if( Vgb_Vfb < 0){ + /* Accumulation Region */ + qg = WLCox * Vgb_Vfb; + TimesDeriv(&d_qg,&d_Vgb_Vfb,WLCox); + qb = - qg; + TimesDeriv(&d_qb,&d_qg,-1.0); + qd = 0. ; + EqualDeriv(&d_qd,&d_zero); + goto finished; + } else if ( vgs < Vth0 ){ + /* Subthreshold Region */ + qg = 0.5 * WLCox * K1 * K1 * (-1 + + sqrt(1 + 4 * Vgb_Vfb / (K1 * K1))); + TimesDeriv(&d_qg,&d_Vgb_Vfb,4/(K1*K1)); + d_qg.value += 1.0; + SqrtDeriv(&d_qg,&d_qg); + d_qg.value -= 1.0; + TimesDeriv(&d_qg,&d_qg,0.5 * WLCox * K1 * K1); + qb = -qg; + TimesDeriv(&d_qb,&d_qg,-1.0); + qd = 0.; + EqualDeriv(&d_qd,&d_zero); + goto finished; + } else if( vds < VdsPinchoff ){ /* triode region */ + /* + VgsVthSquare = VgsVth*VgsVth; + MultDeriv(&d_VgsVthSquare,&d_VgsVth,&d_VgsVth); + */ + EntSquare = Ent * Ent; + MultDeriv(&d_EntSquare,&d_Ent,&d_Ent); + Argl1 = 1.2e1 * EntSquare; + TimesDeriv(&d_Argl1,&d_EntSquare,12.0); + Argl2 = 1.0 - A; + TimesDeriv(&d_Argl2,&d_A,-1.0); + d_Argl2.value += 1.0; + /* + Argl3 = Arg1 * vds; + MultDeriv(&d_Argl3,&d_Arg1,&d_r); + Argl4 = Vcom/Ent/EntSquare; + MultDeriv(&d_Argl4,&d_Ent,&d_EntSquare); + DivDeriv(&d_Argl4,&d_Vcom,&d_Argl4); + */ + if (Ent > 1.0e-8) { + Argl5 = Arg1 / Ent; + DivDeriv(&d_Argl5,&d_Arg1,&d_Ent); + Argl6 = Vcom/EntSquare; + DivDeriv(&d_Argl6,&d_Vcom,&d_EntSquare); + } else { + Argl5 = 2.0; + EqualDeriv(&d_Argl5,&d_zero); + d_Argl5.value = Argl5; + Argl6 = 4.0 / 1.5e1; + EqualDeriv(&d_Argl6,&d_zero); + d_Argl6.value = Argl6; + } + Argl7 = Argl5 / 1.2e1; + TimesDeriv(&d_Argl7,&d_Argl5,1/12.0); + /* + Argl8 = 6.0 * Ent; + TimesDeriv(&d_Argl8,&d_Ent,6.0); + Argl9 = 0.125 * Argl5 * Argl5; + MultDeriv(&d_Argl9,&d_Argl5,&d_Argl5); + TimesDeriv(&d_Argl9,&d_Argl9,0.125); + */ + qg = WLCox * (vgs - Vfb - Phi - 0.5 * vds + vds * Argl7); + EqualDeriv(&d_qg,&d_Argl7); + d_qg.value -= 0.5; + MultDeriv(&d_qg,&d_qg,&d_r); + d_qg.value += vgs - Vfb - Phi; + d_qg.d1_p += 1.0; + TimesDeriv(&d_qg,&d_qg,WLCox); + qb = WLCox * ( - Vth0 + Vfb + Phi + 0.5 * Arg3 - Arg3 * Argl7); + TimesDeriv(&d_qb,&d_Argl7,-1.0); + d_qb.value += 0.5; + MultDeriv(&d_qb,&d_qb,&d_Arg3); + d_qb.value += Vfb + Phi; + TimesDeriv(&d_dummy,&d_Vth0,-1.0); + PlusDeriv(&d_qb,&d_qb,&d_dummy); + TimesDeriv(&d_qb,&d_qb,WLCox); + qd = - WLCox * (0.5 * (VgsVth - Arg1) + + Arg1 * Argl6); + MultDeriv(&d_dummy,&d_Arg1,&d_Argl6); + TimesDeriv(&d_qd,&d_Arg1,-1.0); + PlusDeriv(&d_qd,&d_qd,&d_VgsVth); + TimesDeriv(&d_qd,&d_qd,0.5); + PlusDeriv(&d_qd,&d_qd,&d_dummy); + TimesDeriv(&d_qd,&d_qd,-WLCox); + goto finished; + } else if( vds >= VdsPinchoff ) { /* saturation region */ + Args1 = 1.0 / (3*A); + TimesDeriv(&d_Args1,&d_A,3.0); + InvDeriv(&d_Args1,&d_Args1); + + qg = WLCox * (vgs - Vfb - Phi - VgsVth * Args1); + MultDeriv(&d_qg,&d_VgsVth,&d_Args1); + d_qg.value += Vfb + Phi - vgs; + d_qg.d1_p -= 1.0; + TimesDeriv(&d_qg,&d_qg,-WLCox); + qb = WLCox * (Vfb + Phi - Vth0 + (1.0 - A) * VgsVth * Args1); + TimesDeriv(&d_dummy,&d_A,-1.0); + d_dummy.value += 1.0; + MultDeriv(&d_qb,&d_VgsVth, &d_dummy); + MultDeriv(&d_qb,&d_qb,&d_Args1); + d_qb.value += Vfb + Phi; + TimesDeriv(&d_dummy,&d_Vth0,-1.0); + PlusDeriv(&d_qb,&d_qb,&d_dummy); + TimesDeriv(&d_qb,&d_qb,WLCox); + qd = -co4v15*WLCox*VgsVth; + TimesDeriv(&d_qd,&d_VgsVth,-co4v15*WLCox); + goto finished; + } + + + } + + } + finished: /* returning Values to Calling Routine */ + + + + + /* + * the above has set up (DrCur) and (the node q's) + * and (their derivatives upto third order wrt vgs, vbs, and + * vds) + */ + /* + * + */ + /* + * charge storage elements + * + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw:zero bias drain junction sidewall capacitance + * czbssw:zero bias source junction sidewall capacitance + */ + + czbd = model->B1unitAreaJctCap * DrainArea; + czbs = model->B1unitAreaJctCap * SourceArea; + czbdsw= model->B1unitLengthSidewallJctCap * DrainPerimeter; + czbssw= model->B1unitLengthSidewallJctCap * SourcePerimeter; + PhiB = model->B1bulkJctPotential; + PhiBSW = model->B1sidewallJctPotential; + MJ = model->B1bulkJctBotGradingCoeff; + MJSW = model->B1bulkJctSideGradingCoeff; + + /* Source Bulk Junction */ + if( vbs < 0 ) { + arg = 1 - vbs / PhiB; + argsw = 1 - vbs / PhiBSW; + sarg = exp(-MJ*log(arg)); + sargsw = exp(-MJSW*log(argsw)); + /* *(ckt->CKTstate0 + here->B1qbs) = + PhiB * czbs * (1-arg*sarg)/(1-MJ) + PhiBSW * + czbssw * (1-argsw*sargsw)/(1-MJSW); */ + capbs1 = czbs * sarg + czbssw * sargsw ; + capbs2 = (czbs * MJ * sarg / (PhiB*arg) + + czbssw * MJSW * sargsw /(PhiBSW*argsw))/2.0; + capbs3 = (czbs * (MJ) * (MJ + 1.) * sarg /((PhiB*arg)*(PhiB*arg)) + + czbssw * MJSW * (MJSW + 1.) * sargsw / (PhiBSW*argsw*PhiBSW*argsw))/6.0; + } else { + /* *(ckt->CKTstate0+here->B1qbs) = + vbs*(czbs+czbssw)+ vbs*vbs*(czbs*MJ*0.5/PhiB + + czbssw * MJSW * 0.5/PhiBSW); */ + capbs1 = czbs + czbssw + vbs *(czbs*MJ/PhiB+ + czbssw * MJSW / PhiBSW ); + capbs2 = (czbs*MJ/PhiB+czbssw * MJSW / PhiBSW )*0.5; + capbs3 = 0.0; + } + + /* Drain Bulk Junction */ + if( vbd < 0 ) { + arg = 1 - vbd / PhiB; + argsw = 1 - vbd / PhiBSW; + sarg = exp(-MJ*log(arg)); + sargsw = exp(-MJSW*log(argsw)); + /* *(ckt->CKTstate0 + here->B1qbd) = + PhiB * czbd * (1-arg*sarg)/(1-MJ) + PhiBSW * + czbdsw * (1-argsw*sargsw)/(1-MJSW); */ + capbd1 = czbd * sarg + czbdsw * sargsw ; + capbd2 = (czbd * MJ * sarg / (PhiB*arg) + + czbdsw * MJSW * sargsw /(PhiBSW*argsw))*0.5; + capbd3 = (czbd * (MJ) * (MJ + 1.) * sarg /((PhiB*arg)*(PhiB*arg)) + + czbdsw * MJSW * (MJSW + 1.) * sargsw / (PhiBSW*argsw*PhiBSW*argsw))/6.0; + } else { + /* *(ckt->CKTstate0+here->B1qbd) = + vbd*(czbd+czbdsw)+ vbd*vbd*(czbd*MJ*0.5/PhiB + + czbdsw * MJSW * 0.5/PhiBSW); */ + capbd1 = czbd + czbdsw + vbd *(czbd*MJ/PhiB+ + czbdsw * MJSW / PhiBSW ); + capbd2 = 0.5*(czbs*MJ/PhiB+czbssw * MJSW / PhiBSW ); + capbd3 = 0.0; + } + +#if 0 + qgd = GateDrainOverlapCap * (vgs - vds); + qgs = GateSourceOverlapCap * vgs; + qgb = GateBulkOverlapCap * (vgs -vbs); + *qGatePointer = *qGatePointer + qgd + qgs + qgb; + *qBulkPointer = *qBulkPointer - qgb; + *qDrainPointer = *qDrainPointer - qgd; + *qSourcePointer = -(*qGatePointer + *qBulkPointer + *qDrainPointer); +#endif + + d_qg.d1_p += GateDrainOverlapCap + GateSourceOverlapCap + GateBulkOverlapCap; + d_qg.d1_q += -GateBulkOverlapCap; + d_qg.d1_r += -GateDrainOverlapCap; + d_qb.d1_p += -GateBulkOverlapCap; + d_qb.d1_q += GateBulkOverlapCap + capbs1 + capbd1; + d_qb.d1_r += -capbd1; + d_qd.d1_p += - GateDrainOverlapCap; + d_qd.d1_q += -capbd1; + d_qd.d1_r += GateDrainOverlapCap + capbd1; + /* + d[23]_qg_d[vlgbds23] += 0.0; + d2_qb_dvgs2 += 0.0; + d3_qb_dvgs3 += 0.0 + d[23]_qb_dvgs[dvbds23] += 0.0 + */ + d_qb.d2_q2 += 2* ( capbd2 + capbs2); + d_qb.d3_q3 += 6*(capbd3 + capbs3); + d_qb.d2_qr += -2*capbd2; + d_qb.d3_q2r += -capbd3*6; + d_qb.d3_qr2 += capbd3*6; + d_qb.d2_r2 += 2*capbd2; + d_qb.d3_r3 += -6*capbd3; + /* + d[23]_qd_dp[dvbds23] += 0.0 + */ + d_qd.d2_q2 -= 2*capbd2; + d_qd.d3_q3 -= 6*capbd3; + d_qd.d2_r2 -= 2*capbd2; + d_qd.d3_r3 -= -6*capbd3; + d_qd.d2_qr -= -2*capbd2; + d_qd.d3_q2r -= -6*capbd3; + d_qd.d3_qr2 -= 6*capbd3; + + + /* get all the coefficients and adjust for mode and type */ + if (here->B1mode == 1) + { + /* normal mode - no source-drain interchange */ + here->qg_x = d_qg.d1_p; + here->qg_y = d_qg.d1_q; + here->qg_z = d_qg.d1_r; + here->qg_x2 = d_qg.d2_p2; + here->qg_y2 = d_qg.d2_q2; + here->qg_z2 = d_qg.d2_r2; + here->qg_xy = d_qg.d2_pq; + here->qg_yz = d_qg.d2_qr; + here->qg_xz = d_qg.d2_pr; + here->qg_x3 = d_qg.d3_p3; + here->qg_y3 = d_qg.d3_q3; + here->qg_z3 = d_qg.d3_r3; + here->qg_x2z = d_qg.d3_p2r; + here->qg_x2y = d_qg.d3_p2q; + here->qg_y2z = d_qg.d3_q2r; + here->qg_xy2 = d_qg.d3_pq2; + here->qg_xz2 = d_qg.d3_pr2; + here->qg_yz2 = d_qg.d3_qr2; + here->qg_xyz = d_qg.d3_pqr; + + here->qb_x = d_qb.d1_p; + here->qb_y = d_qb.d1_q; + here->qb_z = d_qb.d1_r; + here->qb_x2 = d_qb.d2_p2; + here->qb_y2 = d_qb.d2_q2; + here->qb_z2 = d_qb.d2_r2; + here->qb_xy = d_qb.d2_pq; + here->qb_yz = d_qb.d2_qr; + here->qb_xz = d_qb.d2_pr; + here->qb_x3 = d_qb.d3_p3; + here->qb_y3 = d_qb.d3_q3; + here->qb_z3 = d_qb.d3_r3; + here->qb_x2z = d_qb.d3_p2r; + here->qb_x2y = d_qb.d3_p2q; + here->qb_y2z = d_qb.d3_q2r; + here->qb_xy2 = d_qb.d3_pq2; + here->qb_xz2 = d_qb.d3_pr2; + here->qb_yz2 = d_qb.d3_qr2; + here->qb_xyz = d_qb.d3_pqr; + + here->qd_x = d_qd.d1_p; + here->qd_y = d_qd.d1_q; + here->qd_z = d_qd.d1_r; + here->qd_x2 = d_qd.d2_p2; + here->qd_y2 = d_qd.d2_q2; + here->qd_z2 = d_qd.d2_r2; + here->qd_xy = d_qd.d2_pq; + here->qd_yz = d_qd.d2_qr; + here->qd_xz = d_qd.d2_pr; + here->qd_x3 = d_qd.d3_p3; + here->qd_y3 = d_qd.d3_q3; + here->qd_z3 = d_qd.d3_r3; + here->qd_x2z = d_qd.d3_p2r; + here->qd_x2y = d_qd.d3_p2q; + here->qd_y2z = d_qd.d3_q2r; + here->qd_xy2 = d_qd.d3_pq2; + here->qd_xz2 = d_qd.d3_pr2; + here->qd_yz2 = d_qd.d3_qr2; + here->qd_xyz = d_qd.d3_pqr; + + here->DrC_x = d_DrCur.d1_p; + here->DrC_y = d_DrCur.d1_q; + here->DrC_z = d_DrCur.d1_r; + here->DrC_x2 = d_DrCur.d2_p2; + here->DrC_y2 = d_DrCur.d2_q2; + here->DrC_z2 = d_DrCur.d2_r2; + here->DrC_xy = d_DrCur.d2_pq; + here->DrC_yz = d_DrCur.d2_qr; + here->DrC_xz = d_DrCur.d2_pr; + here->DrC_x3 = d_DrCur.d3_p3; + here->DrC_y3 = d_DrCur.d3_q3; + here->DrC_z3 = d_DrCur.d3_r3; + here->DrC_x2z = d_DrCur.d3_p2r; + here->DrC_x2y = d_DrCur.d3_p2q; + here->DrC_y2z = d_DrCur.d3_q2r; + here->DrC_xy2 = d_DrCur.d3_pq2; + here->DrC_xz2 = d_DrCur.d3_pr2; + here->DrC_yz2 = d_DrCur.d3_qr2; + here->DrC_xyz = d_DrCur.d3_pqr; + + here->gbs1 = lgbs1; + here->gbs2 = lgbs2; + here->gbs3 = lgbs3; + + here->gbd1 = lgbd1; + here->gbd2 = lgbd2; + here->gbd3 = lgbd3; + + } else { + /* + * inverse mode - source and drain interchanged + * inversion equations for realqg and realqb are the + * same; a minus is added for the + * realDrCur equation; + * realqd = -(realqb + realqg + fakeqd) + */ + + here->qg_x = -(-d_qg.d1_p); + here->qg_y = -(-d_qg.d1_q); + here->qg_z = -(d_qg.d1_p + d_qg.d1_q + d_qg.d1_r); + here->qg_x2 = -(-d_qg.d2_p2); + here->qg_y2 = -(-d_qg.d2_q2); + here->qg_z2 = -(-(d_qg.d2_p2 + d_qg.d2_q2 + d_qg.d2_r2 + 2*(d_qg.d2_pq + d_qg.d2_pr + d_qg.d2_qr))); + here->qg_xy = -(-d_qg.d2_pq); + here->qg_yz = -(d_qg.d2_pq + d_qg.d2_q2 + d_qg.d2_qr); + here->qg_xz = -(d_qg.d2_p2 + d_qg.d2_pq + d_qg.d2_pr); + here->qg_x3 = -(-d_qg.d3_p3); + here->qg_y3 = -(-d_qg.d3_q3); + here->qg_z3 = -(d_qg.d3_p3 + d_qg.d3_q3 + d_qg.d3_r3 + 3*(d_qg.d3_p2q + d_qg.d3_p2r + d_qg.d3_pq2 + d_qg.d3_q2r + d_qg.d3_pr2 + d_qg.d3_qr2) + 6*d_qg.d3_pqr ); + here->qg_x2z = -(d_qg.d3_p3 + d_qg.d3_p2q + d_qg.d3_p2r); + here->qg_x2y = -(-d_qg.d3_p2q); + here->qg_y2z = -(d_qg.d3_pq2 + d_qg.d3_q3 + d_qg.d3_q2r); + here->qg_xy2 = -(-d_qg.d3_pq2); + here->qg_xz2 = -(-(d_qg.d3_p3 + 2*(d_qg.d3_p2q + d_qg.d3_p2r + d_qg.d3_pqr) + d_qg.d3_pq2 + d_qg.d3_pr2)); + here->qg_yz2 = -(-(d_qg.d3_q3 + 2*(d_qg.d3_pq2 + d_qg.d3_q2r + d_qg.d3_pqr) + d_qg.d3_p2q + d_qg.d3_qr2)); + here->qg_xyz = -(d_qg.d3_p2q + d_qg.d3_pq2 + d_qg.d3_pqr); + + here->qb_x = -(-d_qb.d1_p); + here->qb_y = -(-d_qb.d1_q); + here->qb_z = -(d_qb.d1_p + d_qb.d1_q + d_qb.d1_r); + here->qb_x2 = -(-d_qb.d2_p2); + here->qb_y2 = -(-d_qb.d2_q2); + here->qb_z2 = -(-(d_qb.d2_p2 + d_qb.d2_q2 + d_qb.d2_r2 + 2*(d_qb.d2_pq + d_qb.d2_pr + d_qb.d2_qr))); + here->qb_xy = -(-d_qb.d2_pq); + here->qb_yz = -(d_qb.d2_pq + d_qb.d2_q2 + d_qb.d2_qr); + here->qb_xz = -(d_qb.d2_p2 + d_qb.d2_pq + d_qb.d2_pr); + here->qb_x3 = -(-d_qb.d3_p3); + here->qb_y3 = -(-d_qb.d3_q3); + here->qb_z3 = -(d_qb.d3_p3 + d_qb.d3_q3 + d_qb.d3_r3 + 3*(d_qb.d3_p2q + d_qb.d3_p2r + d_qb.d3_pq2 + d_qb.d3_q2r + d_qb.d3_pr2 + d_qb.d3_qr2) + 6*d_qb.d3_pqr ); + here->qb_x2z = -(d_qb.d3_p3 + d_qb.d3_p2q + d_qb.d3_p2r); + here->qb_x2y = -(-d_qb.d3_p2q); + here->qb_y2z = -(d_qb.d3_pq2 + d_qb.d3_q3 + d_qb.d3_q2r); + here->qb_xy2 = -(-d_qb.d3_pq2); + here->qb_xz2 = -(-(d_qb.d3_p3 + 2*(d_qb.d3_p2q + d_qb.d3_p2r + d_qb.d3_pqr) + d_qb.d3_pq2 + d_qb.d3_pr2)); + here->qb_yz2 = -(-(d_qb.d3_q3 + 2*(d_qb.d3_pq2 + d_qb.d3_q2r + d_qb.d3_pqr) + d_qb.d3_p2q + d_qb.d3_qr2)); + here->qb_xyz = -(d_qb.d3_p2q + d_qb.d3_pq2 + d_qb.d3_pqr); + + here->qd_x= -here->qg_x - here->qb_x +(-d_qd.d1_p); + here->qd_y= -here->qg_y - here->qb_y +(-d_qd.d1_q); + here->qd_z= -here->qg_z - here->qb_z +(d_qd.d1_p + d_qd.d1_q + d_qd.d1_r); + here->qd_x2 = -here->qg_x2 - here->qb_x2 +(-d_qd.d2_p2); + here->qd_y2 = -here->qg_y2 - here->qb_y2 +(-d_qd.d2_q2); + here->qd_z2 = -here->qg_z2 - here->qb_z2 +(-(d_qd.d2_p2 + d_qd.d2_q2 + d_qd.d2_r2 + 2*(d_qd.d2_pq + d_qd.d2_pr + d_qd.d2_qr))); + here->qd_xy = -here->qg_xy - here->qb_xy +(-d_qd.d2_pq); + here->qd_yz = -here->qg_yz - here->qb_yz +(d_qd.d2_pq + d_qd.d2_q2 + d_qd.d2_qr); + here->qd_xz = -here->qg_xz - here->qb_xz +(d_qd.d2_p2 + d_qd.d2_pq + d_qd.d2_pr); + here->qd_x3 = -here->qg_x3 - here->qb_x3 +(-d_qd.d3_p3); + here->qd_y3 = -here->qg_y3 - here->qb_y3 +(-d_qd.d3_q3); + here->qd_z3 = -here->qg_z3 - here->qb_z3 +(d_qd.d3_p3 + d_qd.d3_q3 + d_qd.d3_r3 + 3*(d_qd.d3_p2q + d_qd.d3_p2r + d_qd.d3_pq2 + d_qd.d3_q2r + d_qd.d3_pr2 + d_qd.d3_qr2) + 6*d_qd.d3_pqr ); + here->qd_x2z = -here->qg_x2z - here->qb_x2z +(d_qd.d3_p3 + d_qd.d3_p2q + d_qd.d3_p2r); + here->qd_x2y = -here->qg_x2y - here->qb_x2y +(-d_qd.d3_p2q); + here->qd_y2z = -here->qg_y2z - here->qb_y2z +(d_qd.d3_pq2 + d_qd.d3_q3 + d_qd.d3_q2r); + here->qd_xy2 = -here->qg_xy2 - here->qb_xy2 +(-d_qd.d3_pq2); + here->qd_xz2 = -here->qg_xz2 - here->qb_xz2 +(-(d_qd.d3_p3 + 2*(d_qd.d3_p2q + d_qd.d3_p2r + d_qd.d3_pqr) + d_qd.d3_pq2 + d_qd.d3_pr2)); + here->qd_yz2 = -here->qg_yz2 - here->qb_yz2 +(-(d_qd.d3_q3 + 2*(d_qd.d3_pq2 + d_qd.d3_q2r + d_qd.d3_pqr) + d_qd.d3_p2q + d_qd.d3_qr2)); + here->qd_xyz = -here->qg_xyz - here->qb_xyz +(d_qd.d3_p2q + d_qd.d3_pq2 + d_qd.d3_pqr); + + here->DrC_x = -d_DrCur.d1_p; + here->DrC_y = -d_DrCur.d1_q; + here->DrC_z = d_DrCur.d1_p + d_DrCur.d1_q + d_DrCur.d1_r; + here->DrC_x2 = -d_DrCur.d2_p2; + here->DrC_y2 = -d_DrCur.d2_q2; + here->DrC_z2 = -(d_DrCur.d2_p2 + d_DrCur.d2_q2 + d_DrCur.d2_r2 + 2*(d_DrCur.d2_pq + d_DrCur.d2_pr + d_DrCur.d2_qr)); + here->DrC_xy = -d_DrCur.d2_pq; + here->DrC_yz = d_DrCur.d2_pq + d_DrCur.d2_q2 + d_DrCur.d2_qr; + here->DrC_xz = d_DrCur.d2_p2 + d_DrCur.d2_pq + d_DrCur.d2_pr; + here->DrC_x3 = -d_DrCur.d3_p3; + here->DrC_y3 = -d_DrCur.d3_q3; + here->DrC_z3 = d_DrCur.d3_p3 + d_DrCur.d3_q3 + d_DrCur.d3_r3 + 3*(d_DrCur.d3_p2q + d_DrCur.d3_p2r + d_DrCur.d3_pq2 + d_DrCur.d3_q2r + d_DrCur.d3_pr2 + d_DrCur.d3_qr2) + 6*d_DrCur.d3_pqr ; + here->DrC_x2z = d_DrCur.d3_p3 + d_DrCur.d3_p2q + d_DrCur.d3_p2r; + here->DrC_x2y = -d_DrCur.d3_p2q; + here->DrC_y2z = d_DrCur.d3_pq2 + d_DrCur.d3_q3 + d_DrCur.d3_q2r; + here->DrC_xy2 = -d_DrCur.d3_pq2; + here->DrC_xz2 = -(d_DrCur.d3_p3 + 2*(d_DrCur.d3_p2q + d_DrCur.d3_p2r + d_DrCur.d3_pqr) + d_DrCur.d3_pq2 + d_DrCur.d3_pr2); + here->DrC_yz2 = -(d_DrCur.d3_q3 + 2*(d_DrCur.d3_pq2 + d_DrCur.d3_q2r + d_DrCur.d3_pqr) + d_DrCur.d3_p2q + d_DrCur.d3_qr2); + here->DrC_xyz = d_DrCur.d3_p2q + d_DrCur.d3_pq2 + d_DrCur.d3_pqr; + + here->gbs1 = lgbd1; + here->gbs2 = lgbd2; + here->gbs3 = lgbd3; + + here->gbd1 = lgbs1; + here->gbd2 = lgbs2; + here->gbd3 = lgbs3; + } + + /* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ + + here->qg_x2 = 0.5*model->B1type*here->qg_x2; + here->qg_y2 = 0.5*model->B1type*here->qg_y2; + here->qg_z2 = 0.5*model->B1type*here->qg_z2; + here->qg_xy = model->B1type*here->qg_xy; + here->qg_yz = model->B1type*here->qg_yz; + here->qg_xz = model->B1type*here->qg_xz; + here->qg_x3 = here->qg_x3/6.; + here->qg_y3 = here->qg_y3/6.; + here->qg_z3 = here->qg_z3/6.; + here->qg_x2z = 0.5*here->qg_x2z; + here->qg_x2y = 0.5*here->qg_x2y; + here->qg_y2z = 0.5*here->qg_y2z; + here->qg_xy2 = 0.5*here->qg_xy2; + here->qg_xz2 = 0.5*here->qg_xz2; + here->qg_yz2 = 0.5*here->qg_yz2; + + here->qb_x2 = 0.5*model->B1type*here->qb_x2; + here->qb_y2 = 0.5*model->B1type*here->qb_y2; + here->qb_z2 = 0.5*model->B1type*here->qb_z2; + here->qb_xy = model->B1type*here->qb_xy; + here->qb_yz = model->B1type*here->qb_yz; + here->qb_xz = model->B1type*here->qb_xz; + here->qb_x3 = here->qb_x3/6.; + here->qb_y3 = here->qb_y3/6.; + here->qb_z3 = here->qb_z3/6.; + here->qb_x2z = 0.5*here->qb_x2z; + here->qb_x2y = 0.5*here->qb_x2y; + here->qb_y2z = 0.5*here->qb_y2z; + here->qb_xy2 = 0.5*here->qb_xy2; + here->qb_xz2 = 0.5*here->qb_xz2; + here->qb_yz2 = 0.5*here->qb_yz2; + + here->qd_x2 = 0.5*model->B1type*here->qd_x2; + here->qd_y2 = 0.5*model->B1type*here->qd_y2; + here->qd_z2 = 0.5*model->B1type*here->qd_z2; + here->qd_xy = model->B1type*here->qd_xy; + here->qd_yz = model->B1type*here->qd_yz; + here->qd_xz = model->B1type*here->qd_xz; + here->qd_x3 = here->qd_x3/6.; + here->qd_y3 = here->qd_y3/6.; + here->qd_z3 = here->qd_z3/6.; + here->qd_x2z = 0.5*here->qd_x2z; + here->qd_x2y = 0.5*here->qd_x2y; + here->qd_y2z = 0.5*here->qd_y2z; + here->qd_xy2 = 0.5*here->qd_xy2; + here->qd_xz2 = 0.5*here->qd_xz2; + here->qd_yz2 = 0.5*here->qd_yz2; + + here->DrC_x2 = 0.5*model->B1type*here->DrC_x2; + here->DrC_y2 = 0.5*model->B1type*here->DrC_y2; + here->DrC_z2 = 0.5*model->B1type*here->DrC_z2; + here->DrC_xy = model->B1type*here->DrC_xy; + here->DrC_yz = model->B1type*here->DrC_yz; + here->DrC_xz = model->B1type*here->DrC_xz; + here->DrC_x3 = here->DrC_x3/6.; + here->DrC_y3 = here->DrC_y3/6.; + here->DrC_z3 = here->DrC_z3/6.; + here->DrC_x2z = 0.5*here->DrC_x2z; + here->DrC_x2y = 0.5*here->DrC_x2y; + here->DrC_y2z = 0.5*here->DrC_y2z; + here->DrC_xy2 = 0.5*here->DrC_xy2; + here->DrC_xz2 = 0.5*here->DrC_xz2; + here->DrC_yz2 = 0.5*here->DrC_yz2; + + here->gbs2 = model->B1type*here->gbs2; + here->gbd2 = model->B1type*here->gbd2; + } /* End of Mosfet Instance */ + + } /* End of Model Instance */ + return(OK); +} diff --git a/src/spicelib/devices/bsim1/b1eval.c b/src/spicelib/devices/bsim1/b1eval.c new file mode 100644 index 000000000..b4779c07d --- /dev/null +++ b/src/spicelib/devices/bsim1/b1eval.c @@ -0,0 +1,623 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "trandefs.h" +#include "const.h" +#include "suffix.h" + +/* This routine evaluates the drain current, its derivatives and the + * charges associated with the gate,bulk and drain terminal + * using the B1 (Berkeley Short-Channel IGFET Model) Equations. + */ +void +B1evaluate(vds,vbs,vgs,here,model,gmPointer,gdsPointer,gmbsPointer, + qgPointer,qbPointer,qdPointer,cggbPointer,cgdbPointer,cgsbPointer, + cbgbPointer,cbdbPointer,cbsbPointer,cdgbPointer,cddbPointer, + cdsbPointer,cdrainPointer,vonPointer,vdsatPointer,ckt) + + register CKTcircuit *ckt; + register B1model *model; + register B1instance *here; + double vds; + double vbs; + double vgs; + double *gmPointer; + double *gdsPointer; + double *gmbsPointer; + double *qgPointer; + double *qbPointer; + double *qdPointer; + double *cggbPointer; + double *cgdbPointer; + double *cgsbPointer; + double *cbgbPointer; + double *cbdbPointer; + double *cbsbPointer; + double *cdgbPointer; + double *cddbPointer; + double *cdsbPointer; + double *cdrainPointer; + double *vonPointer; + double *vdsatPointer; + + { + double gm; + double gds; + double gmbs; + double qg; + double qb; + double qd; + double cggb; + double cgdb; + double cgsb; + double cbgb; + double cbdb; + double cbsb; + double cdgb; + double cddb; + double cdsb; + double Vfb; + double Phi; + double K1; + double K2; + double Vdd; + double Ugs; + double Uds; + double dUgsdVbs; + double Leff; + double dUdsdVbs; + double dUdsdVds; + double Eta; + double dEtadVds; + double dEtadVbs; + double Vpb; + double SqrtVpb; + double Von; + double Vth; + double dVthdVbs; + double dVthdVds; + double Vgs_Vth; + double DrainCurrent; + double G; + double A; + double Arg; + double dGdVbs; + double dAdVbs; + double Beta; + double Beta_Vds_0; + double BetaVdd; + double dBetaVdd_dVds; + double Beta0; + double dBeta0dVds; + double dBeta0dVbs; + double VddSquare; + double C1; + double C2; + double dBetaVdd_dVbs; + double dBeta_Vds_0_dVbs; + double dC1dVbs; + double dC2dVbs; + double dBetadVgs; + double dBetadVds; + double dBetadVbs; + double VdsSat; + double Argl1; + double Argl2; + double Vc; + double Term1; + double K; + double Args1; + double dVcdVgs; + double dVcdVds; + double dVcdVbs; + double dKdVc; + double dKdVgs; + double dKdVds; + double dKdVbs; + double Args2; + double Args3; + double Warg1; + double Vcut; + double N; + double N0; + double NB; + double ND; + double Warg2; + double Wds; + double Wgs; + double Ilimit; + double Iexp; + double Temp1; + double Vth0; + double Arg1; + double Arg2; + double Arg3; + double Arg5; + double Ent; + double Vcom; + double Vgb; + double Vgb_Vfb; + double VdsPinchoff; + double EntSquare; + double Vgs_VthSquare; + double Argl3; + double Argl4; + double Argl5; + double Argl6; + double Argl7; + double Argl8; + double Argl9; + double dEntdVds; + double dEntdVbs; + double cgbb; + double cdbb; + double cbbb; + double WLCox; + double Vtsquare; + double Temp3; + int ChargeComputationNeeded; + double co4v15; + + if (ckt->CKTmode & (MODEAC | MODETRAN)) { + ChargeComputationNeeded = 1; + } else if (ckt->CKTmode & MODEINITSMSIG) { + ChargeComputationNeeded = 1; + } else if ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) { + ChargeComputationNeeded = 1; + } else { + ChargeComputationNeeded = 0; + } + + Vfb = here->B1vfb; + Phi = here->B1phi; + K1 = here->B1K1; + K2 = here->B1K2; + Vdd = model->B1vdd; + if((Ugs = here->B1ugs + here->B1ugsB * vbs) <= 0 ) { + Ugs = 0; + dUgsdVbs = 0.0; + } else { + dUgsdVbs = here->B1ugsB; + } + if((Uds = here->B1uds + here->B1udsB * vbs + + here->B1udsD*(vds-Vdd)) <= 0 ) { + Uds = 0.0; + dUdsdVbs = dUdsdVds = 0.0; + } else { + Leff = here->B1l * 1.e6 - model->B1deltaL; /* Leff in um */ + Uds = Uds / Leff; + dUdsdVbs = here->B1udsB / Leff; + dUdsdVds = here->B1udsD / Leff; + } + Eta = here->B1eta + here->B1etaB * vbs + here->B1etaD * + (vds - Vdd); + if( Eta <= 0 ) { + Eta = 0; + dEtadVds = dEtadVbs = 0.0 ; + } else if ( Eta > 1 ) { + Eta = 1; + dEtadVds = dEtadVbs = 0; + } else { + dEtadVds = here->B1etaD; + dEtadVbs = here->B1etaB; + } + if( vbs < 0 ) { + Vpb = Phi - vbs; + } else { + Vpb = Phi; + } + SqrtVpb = sqrt( Vpb ); + Von = Vfb + Phi + K1 * SqrtVpb - K2 * Vpb - Eta * vds; + Vth = Von; + dVthdVds = - Eta - dEtadVds * vds; + dVthdVbs = K2 - 0.5 * K1 / SqrtVpb - dEtadVbs * vds; + Vgs_Vth = vgs - Vth; + + G = 1. - 1./(1.744+0.8364 * Vpb); + A = 1. + 0.5*G*K1/SqrtVpb; + A = MAX( A, 1.0); /* Modified */ + Arg = MAX(( 1 + Ugs * Vgs_Vth), 1.0); + dGdVbs = -0.8364 * (1-G) * (1-G); + dAdVbs = 0.25 * K1 / SqrtVpb *(2*dGdVbs + G/Vpb); + + if( Vgs_Vth < 0 ) { + /* cutoff */ + DrainCurrent = 0; + gm = 0; + gds = 0; + gmbs = 0; + goto SubthresholdComputation; + } + + /* Quadratic Interpolation for Beta0 (Beta at vgs = 0, vds=Vds) */ + + Beta_Vds_0 = (here->B1betaZero + here->B1betaZeroB * vbs); + BetaVdd = (here->B1betaVdd + here->B1betaVddB * vbs); + dBetaVdd_dVds = MAX( here->B1betaVddD, 0.0); /* Modified */ + if( vds > Vdd ) { + Beta0 = BetaVdd + dBetaVdd_dVds * (vds - Vdd); + dBeta0dVds = dBetaVdd_dVds; + dBeta0dVbs = here->B1betaVddB; + } else { + VddSquare = Vdd * Vdd; + C1 = ( -BetaVdd + Beta_Vds_0 + dBetaVdd_dVds * Vdd) / VddSquare; + C2 = 2 * (BetaVdd - Beta_Vds_0) / Vdd - dBetaVdd_dVds; + dBeta_Vds_0_dVbs = here->B1betaZeroB; + dBetaVdd_dVbs = here->B1betaVddB; + dC1dVbs = (dBeta_Vds_0_dVbs - dBetaVdd_dVbs) / VddSquare; + dC2dVbs = dC1dVbs * (-2) * Vdd; + Beta0 = (C1 * vds + C2) * vds + Beta_Vds_0; + dBeta0dVds = 2*C1*vds + C2; + dBeta0dVbs = dC1dVbs * vds * vds + dC2dVbs * vds + dBeta_Vds_0_dVbs; + } + + /*Beta = Beta0 / ( 1 + Ugs * Vgs_Vth );*/ + + Beta = Beta0 / Arg ; + dBetadVgs = - Beta * Ugs / Arg; + dBetadVds = dBeta0dVds / Arg - dBetadVgs * dVthdVds ; + dBetadVbs = dBeta0dVbs / Arg + Beta * Ugs * dVthdVbs / Arg - + Beta * Vgs_Vth * dUgsdVbs / Arg; + + /*VdsSat = MAX( Vgs_Vth / ( A + Uds * Vgs_Vth ), 0.0);*/ + + if((Vc = Uds * Vgs_Vth / A) < 0.0 ) Vc=0.0; + Term1 = sqrt( 1 + 2 * Vc ); + K = 0.5 * ( 1 + Vc + Term1 ); + VdsSat = MAX( Vgs_Vth / ( A * sqrt(K) ) , 0.0 ); + + if( vds < VdsSat ) { + /* Triode Region */ + /*Argl1 = 1 + Uds * vds;*/ + Argl1 = MAX( (1 + Uds * vds), 1.); + Argl2 = Vgs_Vth - 0.5 * A * vds; + DrainCurrent = Beta * Argl2 * vds / Argl1; + gm = (dBetadVgs * Argl2 * vds + Beta * vds) / Argl1; + gds = (dBetadVds * Argl2 * vds + Beta * + (Vgs_Vth - vds * dVthdVds - A * vds) - + DrainCurrent * (vds * dUdsdVds + Uds )) / Argl1; + gmbs = (dBetadVbs * Argl2 * vds + Beta * vds * + (- dVthdVbs - 0.5 * vds * dAdVbs ) - + DrainCurrent * vds * dUdsdVbs ) / Argl1; + } else { + /* Pinchoff (Saturation) Region */ + Args1 = 1. + 1. / Term1; + dVcdVgs = Uds / A; + dVcdVds = Vgs_Vth * dUdsdVds / A - dVcdVgs * dVthdVds; + dVcdVbs = ( Vgs_Vth * dUdsdVbs - Uds * + (dVthdVbs + Vgs_Vth * dAdVbs / A ))/ A; + dKdVc = 0.5* Args1; + dKdVgs = dKdVc * dVcdVgs; + dKdVds = dKdVc * dVcdVds; + dKdVbs = dKdVc * dVcdVbs; + Args2 = Vgs_Vth / A / K; + Args3 = Args2 * Vgs_Vth; + DrainCurrent = 0.5 * Beta * Args3; + gm = 0.5 * Args3 * dBetadVgs + Beta * Args2 - + DrainCurrent * dKdVgs / K; + gds = 0.5 * Args3 * dBetadVds - Beta * Args2 * dVthdVds - + DrainCurrent * dKdVds / K; + gmbs = 0.5 * dBetadVbs * Args3 - Beta * Args2 *dVthdVbs - + DrainCurrent * (dAdVbs / A + dKdVbs / K ); + } + +SubthresholdComputation: + + N0 = here->B1subthSlope; + Vcut = - 40. * N0 * CONSTvt0 ; + +/* The following 'if' statement has been modified so that subthreshold * + * current computation is always executed unless N0 >= 200. This should * + * get rid of the Ids kink seen on Ids-Vgs plots at low Vds. * + * Peter M. Lee * + * 6/8/90 * + * Old 'if' statement: * + * if( (N0 >= 200) || (Vgs_Vth < Vcut ) || (Vgs_Vth > (-0.5*Vcut))) */ + + if (N0 >= 200) { + goto ChargeComputation; + } + + NB = here->B1subthSlopeB; + ND = here->B1subthSlopeD; + N = N0 + NB * vbs + ND * vds; /* subthreshold slope */ + if( N < 0.5 ) N = 0.5; + Warg1 = exp( - vds / CONSTvt0 ); + Wds = 1 - Warg1; + Wgs = exp( Vgs_Vth / ( N * CONSTvt0 )); + Vtsquare = CONSTvt0 * CONSTvt0 ; + Warg2 = 6.04965 * Vtsquare * here->B1betaZero; + Ilimit = 4.5 * Vtsquare * here->B1betaZero; + Iexp = Warg2 * Wgs * Wds; + DrainCurrent = DrainCurrent + Ilimit * Iexp / ( Ilimit + Iexp ); + Temp1 = Ilimit / ( Ilimit + Iexp ); + Temp1 = Temp1 * Temp1; + Temp3 = Ilimit / ( Ilimit + Wgs * Warg2 ); + Temp3=Temp3 * Temp3 * Warg2 * Wgs; +/* if ( Temp3 > Ilimit ) Temp3=Ilimit;*/ + gm = gm + Temp1 * Iexp / ( N * CONSTvt0 ); + /* gds term has been modified to prevent blow up at Vds=0 */ + gds = gds + Temp3 * ( -Wds / N / CONSTvt0 * (dVthdVds + + Vgs_Vth * ND / N ) + Warg1 / CONSTvt0 ); + gmbs = gmbs - Temp1 * Iexp * (dVthdVbs + Vgs_Vth * NB / N ) / + ( N * CONSTvt0 ); + +ChargeComputation: + + /* Some Limiting of DC Parameters */ + if(DrainCurrent < 0.0) DrainCurrent = 0.0; + if(gm < 0.0) gm = 0.0; + if(gds < 0.0) gds = 0.0; + if(gmbs < 0.0) gmbs = 0.0; + + WLCox = model->B1Cox * + (here->B1l - model->B1deltaL * 1.e-6) * + (here->B1w - model->B1deltaW * 1.e-6) * 1.e4; /* F */ + + if( ! ChargeComputationNeeded ) { + qg = 0; + qd = 0; + qb = 0; + cggb = 0; + cgsb = 0; + cgdb = 0; + cdgb = 0; + cdsb = 0; + cddb = 0; + cbgb = 0; + cbsb = 0; + cbdb = 0; + goto finished; + } + G = 1. - 1./(1.744+0.8364 * Vpb); + A = 1. + 0.5*G*K1/SqrtVpb; + A = MAX( A, 1.0); /* Modified */ + /*Arg = 1 + Ugs * Vgs_Vth;*/ + dGdVbs = -0.8364 * (1-G) * (1-G); + dAdVbs = 0.25 * K1 / SqrtVpb *(2*dGdVbs + G/Vpb); + Phi = MAX( 0.1, Phi); + + if( model->B1channelChargePartitionFlag >= 1 ) { + +/*0/100 partitioning for drain/source chArges at the saturation region*/ + Vth0 = Vfb + Phi + K1 * SqrtVpb; + Vgs_Vth = vgs - Vth0; + Arg1 = A * vds; + Arg2 = Vgs_Vth - 0.5 * Arg1; + Arg3 = vds - Arg1; + Arg5 = Arg1 * Arg1; + dVthdVbs = - 0.5 * K1 / SqrtVpb; + dAdVbs = 0.5 * K1 * (0.5 * G / Vpb - 0.8364 * (1 -G) * (1 - G) ) / + SqrtVpb ; + Ent = MAX(Arg2,1.0e-8); + dEntdVds = - 0.5 * A; + dEntdVbs = - dVthdVbs - 0.5 * vds * dAdVbs; + Vcom = Vgs_Vth * Vgs_Vth / 6.0 - 1.25e-1 * Arg1 * + Vgs_Vth + 2.5e-2 * Arg5; + VdsPinchoff = MAX( Vgs_Vth / A, 0.0); + Vgb = vgs - vbs ; + Vgb_Vfb = Vgb - Vfb; + + if( Vgb_Vfb < 0){ + /* Accumulation Region */ + qg = WLCox * Vgb_Vfb; + qb = - qg; + qd = 0. ; + cggb = WLCox; + cgdb = 0.; + cgsb = 0.; + cbgb = -WLCox; + cbdb = 0.; + cbsb = 0.; + cdgb = 0.; + cddb = 0.; + cdsb = 0.; + goto finished; + } else if ( vgs < Vth0 ){ + /* Subthreshold Region */ + qg = 0.5 * WLCox * K1 * K1 * (-1 + + sqrt(1 + 4 * Vgb_Vfb / (K1 * K1))); + qb = -qg; + qd = 0.; + cggb = WLCox / sqrt(1 + 4 * Vgb_Vfb / (K1 * K1)); + cgdb = cgsb = 0.; + cbgb = -cggb; + cbdb = cbsb = cdgb = cddb = cdsb = 0.0; + goto finished; + } else if( vds < VdsPinchoff ){ /* triode region */ + /*Vgs_Vth2 = Vgs_Vth*Vgs_Vth;*/ + EntSquare = Ent * Ent; + Argl1 = 1.2e1 * EntSquare; + Argl2 = 1.0 - A; + Argl3 = Arg1 * vds; + /*Argl4 = Vcom/Ent/EntSquare;*/ + if (Ent > 1.0e-8) { + Argl5 = Arg1 / Ent; + /*Argl6 = Vcom/EntSquare;*/ + } else { + Argl5 = 2.0; + Argl6 = 4.0 / 1.5e1; + } + Argl7 = Argl5 / 1.2e1; + Argl8 = 6.0 * Ent; + Argl9 = 0.125 * Argl5 * Argl5; + qg = WLCox * (vgs - Vfb - Phi - 0.5 * vds + vds * Argl7); + qb = WLCox * ( - Vth0 + Vfb + Phi + 0.5 * Arg3 - Arg3 * Argl7); + qd = - WLCox * (0.5 * Vgs_Vth - 0.75 * Arg1 + + 0.125 * Arg1 * Argl5); + cggb = WLCox * (1.0 - Argl3 / Argl1); + cgdb = WLCox * ( - 0.5 + Arg1 / Argl8 - Argl3 * dEntdVds / + Argl1); + cgbb = WLCox * (vds * vds * dAdVbs * Ent - Argl3 * dEntdVbs) / + Argl1; + cgsb = - (cggb + cgdb + cgbb); + cbgb = WLCox * Argl3 * Argl2 / Argl1; + cbdb = WLCox * Argl2 * (0.5 - Arg1 / Argl8 + Argl3 * dEntdVds / + Argl1); + cbbb = - WLCox * (dVthdVbs + 0.5 * vds * dAdVbs + vds * + vds * ((1.0 - 2.0 * A) * dAdVbs * Ent - Argl2 * + A * dEntdVbs) / Argl1); + cbsb = - (cbgb + cbdb + cbbb); + cdgb = - WLCox * (0.5 - Argl9); + cddb = WLCox * (0.75 * A - 0.25 * A * Arg1 / Ent + + Argl9 * dEntdVds); + cdbb = WLCox * (0.5 * dVthdVbs + vds * dAdVbs * + (0.75 - 0.25 * Argl5 ) + Argl9 * dEntdVbs); + cdsb = - (cdgb + cddb + cdbb); + goto finished; + } else if( vds >= VdsPinchoff ) { /* saturation region */ + Args1 = 1.0 / (3.0 * A); + qg = WLCox * (vgs - Vfb - Phi - Vgs_Vth * Args1); + qb = WLCox * (Vfb + Phi - Vth0 + (1.0 - A) * Vgs_Vth * Args1); + qd = 0.0; + cggb = WLCox * (1.0 - Args1); + cgdb = 0.0; + cgbb = WLCox * Args1 * (dVthdVbs + Vgs_Vth * dAdVbs / A); + cgsb = - (cggb + cgdb + cgbb); + cbgb = WLCox * (Args1 - 1.0 / 3.0); + cbdb = 0.0; + cbbb = - WLCox * ((2.0 / 3.0 + Args1) * dVthdVbs + + Vgs_Vth * Args1 * dAdVbs / A); /* Modified */ + cbsb = - (cbgb + cbdb + cbbb); + cdgb = 0.0; + cddb = 0.0; + cdsb = 0.0; + goto finished; + } + + goto finished; + + } else { + /* ChannelChargePartionFlag < = 0 */ + +/*40/60 partitioning for drain/source chArges at the saturation region*/ + co4v15 = 4./15.; + Vth0 = Vfb+Phi+K1*SqrtVpb; + Vgs_Vth = vgs-Vth0; + Arg1 = A*vds; + Arg2 = Vgs_Vth-0.5*Arg1; + Arg3 = vds-Arg1; + Arg5 = Arg1*Arg1; + dVthdVbs = -0.5*K1/SqrtVpb; + dAdVbs = 0.5*K1*(0.5*G/Vpb-0.8364*(1-G)*(1-G))/SqrtVpb; + Ent = MAX(Arg2,1.0e-8); + dEntdVds = -0.5*A; + dEntdVbs = -dVthdVbs-0.5*vds*dAdVbs; + Vcom = Vgs_Vth*Vgs_Vth/6.0-1.25e-1*Arg1*Vgs_Vth+2.5e-2*Arg5; + VdsPinchoff = MAX( Vgs_Vth/A, 0.0); + Vgb = vgs - vbs ; + Vgb_Vfb = Vgb - Vfb; + + if( Vgb_Vfb < 0) { /* Accumulation Region */ + qg = WLCox * Vgb_Vfb; + qb = - qg; + qd = 0. ; + cggb = WLCox; + cgdb = 0.; + cgsb = 0.; + cbgb = -WLCox; + cbdb = 0.; + cbsb = 0.; + cdgb = 0.; + cddb = 0.; + cdsb = 0.; + goto finished; + } else if ( vgs < Vth0 ) { /* Subthreshold Region */ + qg = 0.5 * WLCox * K1 * K1 * (-1+sqrt(1+4*Vgb_Vfb/(K1*K1))); + qb = -qg; + qd = 0.; + cggb = WLCox/sqrt(1+4*Vgb_Vfb/(K1*K1)); + cgdb = cgsb = 0.; + cbgb = -cggb; + cbdb = cbsb = cdgb = cddb = cdsb = 0.0; + goto finished; + } else if ( vds < VdsPinchoff ) { /* triode region */ + + Vgs_VthSquare = Vgs_Vth*Vgs_Vth; + EntSquare = Ent*Ent; + Argl1 = 1.2e1*EntSquare; + Argl2 = 1.0-A; + Argl3 = Arg1*vds; + Argl4 = Vcom/Ent/EntSquare; + if (Ent > 1.0e-8) { + Argl5 = Arg1/Ent; + Argl6 = Vcom/EntSquare; + } else { + Argl5 = 2.0; + Argl6 = 4.0/1.5e1; + } + Argl7 = Argl5/1.2e1; + Argl8 = 6.0*Ent; + qg = WLCox*(vgs-Vfb-Phi-0.5*vds+vds*Argl7); + qb = WLCox*(-Vth0+Vfb+Phi+0.5*Arg3-Arg3*Argl7); + qd = -WLCox*(0.5*(Vgs_Vth-Arg1)+Arg1*Argl6); + cggb = WLCox*(1.0-Argl3/Argl1); + cgdb = WLCox*(-0.5+Arg1/Argl8-Argl3*dEntdVds/Argl1); + cgbb = WLCox*(vds*vds*dAdVbs*Ent-Argl3*dEntdVbs)/Argl1; + cgsb = -(cggb+cgdb+cgbb); + cbgb = WLCox*Argl3*Argl2/Argl1; + cbdb = WLCox*Argl2*(0.5-Arg1/Argl8+Argl3*dEntdVds/Argl1); + cbbb = -WLCox*(dVthdVbs+0.5*vds*dAdVbs+vds*vds*((1.0-2.0*A) + *dAdVbs*Ent-Argl2*A*dEntdVbs)/Argl1); + cbsb = -(cbgb+cbdb+cbbb); + cdgb = -WLCox*(0.5+Arg1*(4.0*Vgs_Vth-1.5*Arg1)/Argl1- + 2.0*Arg1*Argl4); + cddb = WLCox*(0.5*A+2.0*Arg1*dEntdVds*Argl4-A*(2.0*Vgs_VthSquare + -3.0*Arg1*Vgs_Vth+0.9*Arg5)/Argl1); + cdbb = WLCox*(0.5*dVthdVbs+0.5*vds*dAdVbs+2.0*Arg1*dEntdVbs + *Argl4-vds*(2.0*Vgs_VthSquare*dAdVbs-4.0*A*Vgs_Vth*dVthdVbs-3.0 + *Arg1*Vgs_Vth*dAdVbs+1.5*A*Arg1*dVthdVbs+0.9*Arg5*dAdVbs) + /Argl1); + cdsb = -(cdgb+cddb+cdbb); + goto finished; + } else if( vds >= VdsPinchoff ) { /* saturation region */ + + Args1 = 1.0/(3.0*A); + qg = WLCox*(vgs-Vfb-Phi-Vgs_Vth*Args1); + qb = WLCox*(Vfb+Phi-Vth0+(1.0-A)*Vgs_Vth*Args1); + qd = -co4v15*WLCox*Vgs_Vth; + cggb = WLCox*(1.0-Args1); + cgdb = 0.0; + cgbb = WLCox*Args1*(dVthdVbs+Vgs_Vth*dAdVbs/A); + cgsb = -(cggb+cgdb+cgbb); + cbgb = WLCox*(Args1-1.0/3.0); + cbdb = 0.0; + cbbb = -WLCox*((2.0/3.0+Args1)*dVthdVbs+Vgs_Vth*Args1*dAdVbs/A); + cbsb = -(cbgb+cbdb+cbbb); + cdgb = -co4v15*WLCox; + cddb = 0.0; + cdbb = co4v15*WLCox*dVthdVbs; + cdsb = -(cdgb+cddb+cdbb); + goto finished; + } + } + +finished: /* returning Values to Calling Routine */ + + *gmPointer = MAX(gm,0.0); + *gdsPointer = MAX( gds, 0.0); + *gmbsPointer = MAX(gmbs,0.0); + *qgPointer = qg; + *qbPointer = qb; + *qdPointer = qd; + *cggbPointer = cggb; + *cgdbPointer = cgdb; + *cgsbPointer = cgsb; + *cbgbPointer = cbgb; + *cbdbPointer = cbdb; + *cbsbPointer = cbsb; + *cdgbPointer = cdgb; + *cddbPointer = cddb; + *cdsbPointer = cdsb; + *cdrainPointer = MAX(DrainCurrent,0.0); + *vonPointer = Von; + *vdsatPointer = VdsSat; + +} + diff --git a/src/spicelib/devices/bsim1/b1getic.c b/src/spicelib/devices/bsim1/b1getic.c new file mode 100644 index 000000000..5ff7c92ff --- /dev/null +++ b/src/spicelib/devices/bsim1/b1getic.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "sperror.h" +#include "suffix.h" + + +int +B1getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + +{ + + B1model *model = (B1model*)inModel; + B1instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->B1nextModel) { + for(here = model->B1instances; here ; here = here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + if(!here->B1icVBSGiven) { + here->B1icVBS = + *(ckt->CKTrhs + here->B1bNode) - + *(ckt->CKTrhs + here->B1sNode); + } + if(!here->B1icVDSGiven) { + here->B1icVDS = + *(ckt->CKTrhs + here->B1dNode) - + *(ckt->CKTrhs + here->B1sNode); + } + if(!here->B1icVGSGiven) { + here->B1icVGS = + *(ckt->CKTrhs + here->B1gNode) - + *(ckt->CKTrhs + here->B1sNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim1/b1ld.c b/src/spicelib/devices/bsim1/b1ld.c new file mode 100644 index 000000000..a1cccab01 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1ld.c @@ -0,0 +1,744 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +B1load(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register B1model *model = (B1model*)inModel; + register B1instance *here; + double DrainSatCurrent = 0.0; + double EffectiveLength = 0.0; + double GateBulkOverlapCap = 0.0; + double GateDrainOverlapCap = 0.0; + double GateSourceOverlapCap = 0.0; + double SourceSatCurrent = 0.0; + double DrainArea = 0.0; + double SourceArea = 0.0; + double DrainPerimeter = 0.0; + double SourcePerimeter = 0.0; + double arg = 0.0; + double capbd = 0.0; + double capbs = 0.0; + double cbd = 0.0; + double cbhat = 0.0; + double cbs = 0.0; + double cd = 0.0; + double cdrain = 0.0; + double cdhat = 0.0; + double cdreq = 0.0; + double ceq = 0.0; + double ceqbd = 0.0; + double ceqbs = 0.0; + double ceqqb = 0.0; + double ceqqd = 0.0; + double ceqqg = 0.0; + double czbd = 0.0; + double czbdsw = 0.0; + double czbs = 0.0; + double czbssw = 0.0; + double delvbd = 0.0; + double delvbs = 0.0; + double delvds = 0.0; + double delvgd = 0.0; + double delvgs = 0.0; + double evbd = 0.0; + double evbs = 0.0; + double gbd = 0.0; + double gbs = 0.0; + double gcbdb = 0.0; + double gcbgb = 0.0; + double gcbsb = 0.0; + double gcddb = 0.0; + double gcdgb = 0.0; + double gcdsb = 0.0; + double gcgdb = 0.0; + double gcggb = 0.0; + double gcgsb = 0.0; + double gcsdb = 0.0; + double gcsgb = 0.0; + double gcssb = 0.0; + double gds = 0.0; + double geq = 0.0; + double gm = 0.0; + double gmbs = 0.0; + double sarg = 0.0; + double sargsw = 0.0; + double vbd = 0.0; + double vbs = 0.0; + double vcrit = 0.0; + double vds = 0.0; + double vdsat = 0.0; + double vgb = 0.0; + double vgd = 0.0; + double vgdo = 0.0; + double vgs = 0.0; + double von = 0.0; + double xfact = 0.0; + double xnrm = 0.0; + double xrev = 0.0; + int Check = 0; + double cgdb = 0.0; + double cgsb = 0.0; + double cbdb = 0.0; + double cdgb = 0.0; + double cddb = 0.0; + double cdsb = 0.0; + double cggb = 0.0; + double cbgb = 0.0; + double cbsb = 0.0; + double csgb = 0.0; + double cssb = 0.0; + double csdb = 0.0; + double PhiB = 0.0; + double PhiBSW = 0.0; + double MJ = 0.0; + double MJSW = 0.0; + double argsw = 0.0; + double qgate = 0.0; + double qbulk = 0.0; + double qdrn = 0.0; + double qsrc = 0.0; + double cqgate = 0.0; + double cqbulk = 0.0; + double cqdrn = 0.0; + double vt0 = 0.0; + double args[8]; + int ByPass = 0; +#ifndef NOBYPASS + double tempv = 0.0; +#endif /*NOBYPASS*/ + int error = 0; + + + /* loop through all the B1 device models */ + for( ; model != NULL; model = model->B1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->B1instances; here != NULL ; + here=here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + EffectiveLength=here->B1l - model->B1deltaL * 1.e-6;/* m */ + DrainArea = here->B1drainArea; + SourceArea = here->B1sourceArea; + DrainPerimeter = here->B1drainPerimeter; + SourcePerimeter = here->B1sourcePerimeter; + if( (DrainSatCurrent=DrainArea*model->B1jctSatCurDensity) + < 1e-15){ + DrainSatCurrent = 1.0e-15; + } + if( (SourceSatCurrent=SourceArea*model->B1jctSatCurDensity) + <1.0e-15){ + SourceSatCurrent = 1.0e-15; + } + GateSourceOverlapCap = model->B1gateSourceOverlapCap *here->B1w; + GateDrainOverlapCap = model->B1gateDrainOverlapCap * here->B1w; + GateBulkOverlapCap = model->B1gateBulkOverlapCap *EffectiveLength; + von = model->B1type * here->B1von; + vdsat = model->B1type * here->B1vdsat; + vt0 = model->B1type * here->B1vt0; + + Check=1; + ByPass = 0; + if((ckt->CKTmode & MODEINITSMSIG)) { + vbs= *(ckt->CKTstate0 + here->B1vbs); + vgs= *(ckt->CKTstate0 + here->B1vgs); + vds= *(ckt->CKTstate0 + here->B1vds); + } else if ((ckt->CKTmode & MODEINITTRAN)) { + vbs= *(ckt->CKTstate1 + here->B1vbs); + vgs= *(ckt->CKTstate1 + here->B1vgs); + vds= *(ckt->CKTstate1 + here->B1vds); + } else if((ckt->CKTmode & MODEINITJCT) && !here->B1off) { + vds= model->B1type * here->B1icVDS; + vgs= model->B1type * here->B1icVGS; + vbs= model->B1type * here->B1icVBS; + if((vds==0) && (vgs==0) && (vbs==0) && + ((ckt->CKTmode & + (MODETRAN|MODEAC|MODEDCOP|MODEDCTRANCURVE)) || + (!(ckt->CKTmode & MODEUIC)))) { + vbs = -1; + vgs = vt0; + vds = 0; + } + } else if((ckt->CKTmode & (MODEINITJCT | MODEINITFIX) ) && + (here->B1off)) { + vbs=vgs=vds=0; + } else { +#ifndef PREDICTOR + if((ckt->CKTmode & MODEINITPRED)) { + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->B1vbs) = + *(ckt->CKTstate1 + here->B1vbs); + vbs = (1+xfact)* (*(ckt->CKTstate1 + here->B1vbs)) + -(xfact * (*(ckt->CKTstate2 + here->B1vbs))); + *(ckt->CKTstate0 + here->B1vgs) = + *(ckt->CKTstate1 + here->B1vgs); + vgs = (1+xfact)* (*(ckt->CKTstate1 + here->B1vgs)) + -(xfact * (*(ckt->CKTstate2 + here->B1vgs))); + *(ckt->CKTstate0 + here->B1vds) = + *(ckt->CKTstate1 + here->B1vds); + vds = (1+xfact)* (*(ckt->CKTstate1 + here->B1vds)) + -(xfact * (*(ckt->CKTstate2 + here->B1vds))); + *(ckt->CKTstate0 + here->B1vbd) = + *(ckt->CKTstate0 + here->B1vbs)- + *(ckt->CKTstate0 + here->B1vds); + *(ckt->CKTstate0 + here->B1cd) = + *(ckt->CKTstate1 + here->B1cd); + *(ckt->CKTstate0 + here->B1cbs) = + *(ckt->CKTstate1 + here->B1cbs); + *(ckt->CKTstate0 + here->B1cbd) = + *(ckt->CKTstate1 + here->B1cbd); + *(ckt->CKTstate0 + here->B1gm) = + *(ckt->CKTstate1 + here->B1gm); + *(ckt->CKTstate0 + here->B1gds) = + *(ckt->CKTstate1 + here->B1gds); + *(ckt->CKTstate0 + here->B1gmbs) = + *(ckt->CKTstate1 + here->B1gmbs); + *(ckt->CKTstate0 + here->B1gbd) = + *(ckt->CKTstate1 + here->B1gbd); + *(ckt->CKTstate0 + here->B1gbs) = + *(ckt->CKTstate1 + here->B1gbs); + *(ckt->CKTstate0 + here->B1cggb) = + *(ckt->CKTstate1 + here->B1cggb); + *(ckt->CKTstate0 + here->B1cbgb) = + *(ckt->CKTstate1 + here->B1cbgb); + *(ckt->CKTstate0 + here->B1cbsb) = + *(ckt->CKTstate1 + here->B1cbsb); + *(ckt->CKTstate0 + here->B1cgdb) = + *(ckt->CKTstate1 + here->B1cgdb); + *(ckt->CKTstate0 + here->B1cgsb) = + *(ckt->CKTstate1 + here->B1cgsb); + *(ckt->CKTstate0 + here->B1cbdb) = + *(ckt->CKTstate1 + here->B1cbdb); + *(ckt->CKTstate0 + here->B1cdgb) = + *(ckt->CKTstate1 + here->B1cdgb); + *(ckt->CKTstate0 + here->B1cddb) = + *(ckt->CKTstate1 + here->B1cddb); + *(ckt->CKTstate0 + here->B1cdsb) = + *(ckt->CKTstate1 + here->B1cdsb); + } else { +#endif /* PREDICTOR */ + vbs = model->B1type * ( + *(ckt->CKTrhsOld+here->B1bNode) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + vgs = model->B1type * ( + *(ckt->CKTrhsOld+here->B1gNode) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); + vds = model->B1type * ( + *(ckt->CKTrhsOld+here->B1dNodePrime) - + *(ckt->CKTrhsOld+here->B1sNodePrime)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->B1vgs) - + *(ckt->CKTstate0 + here->B1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->B1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->B1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->B1vgs); + delvds = vds - *(ckt->CKTstate0 + here->B1vds); + delvgd = vgd-vgdo; + + if (here->B1mode >= 0) { + cdhat= + *(ckt->CKTstate0 + here->B1cd) - + *(ckt->CKTstate0 + here->B1gbd) * delvbd + + *(ckt->CKTstate0 + here->B1gmbs) * delvbs + + *(ckt->CKTstate0 + here->B1gm) * delvgs + + *(ckt->CKTstate0 + here->B1gds) * delvds ; + } else { + cdhat= + *(ckt->CKTstate0 + here->B1cd) - + ( *(ckt->CKTstate0 + here->B1gbd) - + *(ckt->CKTstate0 + here->B1gmbs)) * delvbd - + *(ckt->CKTstate0 + here->B1gm) * delvgd + + *(ckt->CKTstate0 + here->B1gds) * delvds; + } + cbhat= + *(ckt->CKTstate0 + here->B1cbs) + + *(ckt->CKTstate0 + here->B1cbd) + + *(ckt->CKTstate0 + here->B1gbd) * delvbd + + *(ckt->CKTstate0 + here->B1gbs) * delvbs ; + +#ifndef NOBYPASS + /* now lets see if we can bypass (ugh) */ + + /* following should be one big if connected by && all over + * the place, but some C compilers can't handle that, so + * we split it up here to let them digest it in stages + */ + tempv = MAX(fabs(cbhat),fabs(*(ckt->CKTstate0 + here->B1cbs) + + *(ckt->CKTstate0 + here->B1cbd)))+ckt->CKTabstol; + if((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass) ) + if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->B1vbs)))+ + ckt->CKTvoltTol)) ) + if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->B1vbd)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->B1vgs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->B1vds)))+ + ckt->CKTvoltTol)) ) + if( (fabs(cdhat- *(ckt->CKTstate0 + here->B1cd)) < + ckt->CKTreltol * MAX(fabs(cdhat),fabs(*(ckt->CKTstate0 + + here->B1cd))) + ckt->CKTabstol) ) + if ( (fabs(cbhat-(*(ckt->CKTstate0 + here->B1cbs) + + *(ckt->CKTstate0 + here->B1cbd))) < ckt->CKTreltol * + tempv)) { + /* bypass code */ + vbs = *(ckt->CKTstate0 + here->B1vbs); + vbd = *(ckt->CKTstate0 + here->B1vbd); + vgs = *(ckt->CKTstate0 + here->B1vgs); + vds = *(ckt->CKTstate0 + here->B1vds); + vgd = vgs - vds; + vgb = vgs - vbs; + cd = *(ckt->CKTstate0 + here->B1cd); + cbs = *(ckt->CKTstate0 + here->B1cbs); + cbd = *(ckt->CKTstate0 + here->B1cbd); + cdrain = here->B1mode * (cd + cbd); + gm = *(ckt->CKTstate0 + here->B1gm); + gds = *(ckt->CKTstate0 + here->B1gds); + gmbs = *(ckt->CKTstate0 + here->B1gmbs); + gbd = *(ckt->CKTstate0 + here->B1gbd); + gbs = *(ckt->CKTstate0 + here->B1gbs); + if((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC))) { + cggb = *(ckt->CKTstate0 + here->B1cggb); + cgdb = *(ckt->CKTstate0 + here->B1cgdb); + cgsb = *(ckt->CKTstate0 + here->B1cgsb); + cbgb = *(ckt->CKTstate0 + here->B1cbgb); + cbdb = *(ckt->CKTstate0 + here->B1cbdb); + cbsb = *(ckt->CKTstate0 + here->B1cbsb); + cdgb = *(ckt->CKTstate0 + here->B1cdgb); + cddb = *(ckt->CKTstate0 + here->B1cddb); + cdsb = *(ckt->CKTstate0 + here->B1cdsb); + capbs = *(ckt->CKTstate0 + here->B1capbs); + capbd = *(ckt->CKTstate0 + here->B1capbd); + ByPass = 1; + goto line755; + } else { + goto line850; + } + } +#endif /*NOBYPASS*/ + + von = model->B1type * here->B1von; + if(*(ckt->CKTstate0 + here->B1vds) >=0) { + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->B1vgs) + ,von); + vds = vgs - vgd; + vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->B1vds)); + vgd = vgs - vds; + } else { + vgd = DEVfetlim(vgd,vgdo,von); + vds = vgs - vgd; + vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + here->B1vds))); + vgs = vgd + vds; + } + if(vds >= 0) { + vcrit =CONSTvt0*log(CONSTvt0/(CONSTroot2*SourceSatCurrent)); + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->B1vbs), + CONSTvt0,vcrit,&Check); /* B1 test */ + vbd = vbs-vds; + } else { + vcrit = CONSTvt0*log(CONSTvt0/(CONSTroot2*DrainSatCurrent)); + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->B1vbd), + CONSTvt0,vcrit,&Check); /* B1 test*/ + vbs = vbd + vds; + } + } + + /* determine DC current and derivatives */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + + if(vbs <= 0.0 ) { + gbs = SourceSatCurrent / CONSTvt0 + ckt->CKTgmin; + cbs = gbs * vbs ; + } else { + evbs = exp(vbs/CONSTvt0); + gbs = SourceSatCurrent*evbs/CONSTvt0 + ckt->CKTgmin; + cbs = SourceSatCurrent * (evbs-1) + ckt->CKTgmin * vbs ; + } + if(vbd <= 0.0) { + gbd = DrainSatCurrent / CONSTvt0 + ckt->CKTgmin; + cbd = gbd * vbd ; + } else { + evbd = exp(vbd/CONSTvt0); + gbd = DrainSatCurrent*evbd/CONSTvt0 +ckt->CKTgmin; + cbd = DrainSatCurrent *(evbd-1)+ckt->CKTgmin*vbd; + } + /* line 400 */ + if(vds >= 0) { + /* normal mode */ + here->B1mode = 1; + } else { + /* inverse mode */ + here->B1mode = -1; + } + /* call B1evaluate to calculate drain current and its + * derivatives and charge and capacitances related to gate + * drain, and bulk + */ + if( vds >= 0 ) { + B1evaluate(vds,vbs,vgs,here,model,&gm,&gds,&gmbs,&qgate, + &qbulk,&qdrn,&cggb,&cgdb,&cgsb,&cbgb,&cbdb,&cbsb,&cdgb, + &cddb,&cdsb,&cdrain,&von,&vdsat,ckt); + } else { + B1evaluate(-vds,vbd,vgd,here,model,&gm,&gds,&gmbs,&qgate, + &qbulk,&qsrc,&cggb,&cgsb,&cgdb,&cbgb,&cbsb,&cbdb,&csgb, + &cssb,&csdb,&cdrain,&von,&vdsat,ckt); + } + + here->B1von = model->B1type * von; + here->B1vdsat = model->B1type * vdsat; + + + + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + cd=here->B1mode * cdrain - cbd; + if ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP ) && + (ckt->CKTmode & MODEUIC))) { + /* + * charge storage elements + * + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw:zero bias drain junction sidewall capacitance + * czbssw:zero bias source junction sidewall capacitance + */ + + czbd = model->B1unitAreaJctCap * DrainArea; + czbs = model->B1unitAreaJctCap * SourceArea; + czbdsw= model->B1unitLengthSidewallJctCap * DrainPerimeter; + czbssw= model->B1unitLengthSidewallJctCap * SourcePerimeter; + PhiB = model->B1bulkJctPotential; + PhiBSW = model->B1sidewallJctPotential; + MJ = model->B1bulkJctBotGradingCoeff; + MJSW = model->B1bulkJctSideGradingCoeff; + + /* Source Bulk Junction */ + if( vbs < 0 ) { + arg = 1 - vbs / PhiB; + argsw = 1 - vbs / PhiBSW; + sarg = exp(-MJ*log(arg)); + sargsw = exp(-MJSW*log(argsw)); + *(ckt->CKTstate0 + here->B1qbs) = + PhiB * czbs * (1-arg*sarg)/(1-MJ) + PhiBSW * + czbssw * (1-argsw*sargsw)/(1-MJSW); + capbs = czbs * sarg + czbssw * sargsw ; + } else { + *(ckt->CKTstate0+here->B1qbs) = + vbs*(czbs+czbssw)+ vbs*vbs*(czbs*MJ*0.5/PhiB + + czbssw * MJSW * 0.5/PhiBSW); + capbs = czbs + czbssw + vbs *(czbs*MJ/PhiB+ + czbssw * MJSW / PhiBSW ); + } + + /* Drain Bulk Junction */ + if( vbd < 0 ) { + arg = 1 - vbd / PhiB; + argsw = 1 - vbd / PhiBSW; + sarg = exp(-MJ*log(arg)); + sargsw = exp(-MJSW*log(argsw)); + *(ckt->CKTstate0 + here->B1qbd) = + PhiB * czbd * (1-arg*sarg)/(1-MJ) + PhiBSW * + czbdsw * (1-argsw*sargsw)/(1-MJSW); + capbd = czbd * sarg + czbdsw * sargsw ; + } else { + *(ckt->CKTstate0+here->B1qbd) = + vbd*(czbd+czbdsw)+ vbd*vbd*(czbd*MJ*0.5/PhiB + + czbdsw * MJSW * 0.5/PhiBSW); + capbd = czbd + czbdsw + vbd *(czbd*MJ/PhiB+ + czbdsw * MJSW / PhiBSW ); + } + + } + + + + + /* + * check convergence + */ + if ( (here->B1off == 0) || (!(ckt->CKTmode & MODEINITFIX)) ){ + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV + } else { + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol; + if (fabs(cdhat-cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } else { + tol=ckt->CKTreltol*MAX(fabs(cbhat),fabs(cbs+cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(cbs+cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } +#endif /* NEWCONV */ + } + } + *(ckt->CKTstate0 + here->B1vbs) = vbs; + *(ckt->CKTstate0 + here->B1vbd) = vbd; + *(ckt->CKTstate0 + here->B1vgs) = vgs; + *(ckt->CKTstate0 + here->B1vds) = vds; + *(ckt->CKTstate0 + here->B1cd) = cd; + *(ckt->CKTstate0 + here->B1cbs) = cbs; + *(ckt->CKTstate0 + here->B1cbd) = cbd; + *(ckt->CKTstate0 + here->B1gm) = gm; + *(ckt->CKTstate0 + here->B1gds) = gds; + *(ckt->CKTstate0 + here->B1gmbs) = gmbs; + *(ckt->CKTstate0 + here->B1gbd) = gbd; + *(ckt->CKTstate0 + here->B1gbs) = gbs; + + *(ckt->CKTstate0 + here->B1cggb) = cggb; + *(ckt->CKTstate0 + here->B1cgdb) = cgdb; + *(ckt->CKTstate0 + here->B1cgsb) = cgsb; + + *(ckt->CKTstate0 + here->B1cbgb) = cbgb; + *(ckt->CKTstate0 + here->B1cbdb) = cbdb; + *(ckt->CKTstate0 + here->B1cbsb) = cbsb; + + *(ckt->CKTstate0 + here->B1cdgb) = cdgb; + *(ckt->CKTstate0 + here->B1cddb) = cddb; + *(ckt->CKTstate0 + here->B1cdsb) = cdsb; + + *(ckt->CKTstate0 + here->B1capbs) = capbs; + *(ckt->CKTstate0 + here->B1capbd) = capbd; + + /* bulk and channel charge plus overlaps */ + + if((!(ckt->CKTmode & (MODETRAN | MODEAC))) && + ((!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC))) && (!(ckt->CKTmode + & MODEINITSMSIG))) goto line850; + +line755: + if( here->B1mode > 0 ) { + + args[0] = GateDrainOverlapCap; + args[1] = GateSourceOverlapCap; + args[2] = GateBulkOverlapCap; + args[3] = capbd; + args[4] = capbs; + args[5] = cggb; + args[6] = cgdb; + args[7] = cgsb; + + B1mosCap(ckt,vgd,vgs,vgb, + args, + /* + GateDrainOverlapCap, + GateSourceOverlapCap,GateBulkOverlapCap, + capbd,capbs, + cggb,cgdb,cgsb, + */ + cbgb,cbdb,cbsb, + cdgb,cddb,cdsb, + &gcggb,&gcgdb,&gcgsb, + &gcbgb,&gcbdb,&gcbsb, + &gcdgb,&gcddb,&gcdsb,&gcsgb,&gcsdb,&gcssb, + &qgate,&qbulk, + &qdrn,&qsrc); + } else { + + args[0] = GateSourceOverlapCap; + args[1] = GateDrainOverlapCap; + args[2] = GateBulkOverlapCap; + args[3] = capbs; + args[4] = capbd; + args[5] = cggb; + args[6] = cgsb; + args[7] = cgdb; + + B1mosCap(ckt,vgs,vgd,vgb, + args, + /* + GateSourceOverlapCap, + GateDrainOverlapCap,GateBulkOverlapCap, + capbs,capbd, + cggb,cgsb,cgdb, + */ + cbgb,cbsb,cbdb, + csgb,cssb,csdb, + &gcggb,&gcgsb,&gcgdb, + &gcbgb,&gcbsb,&gcbdb, + &gcsgb,&gcssb,&gcsdb,&gcdgb,&gcdsb,&gcddb, + &qgate,&qbulk, + &qsrc,&qdrn); + } + + if(ByPass) goto line860; + *(ckt->CKTstate0 + here->B1qg) = qgate; + *(ckt->CKTstate0 + here->B1qd) = qdrn - + *(ckt->CKTstate0 + here->B1qbd); + *(ckt->CKTstate0 + here->B1qb) = qbulk + + *(ckt->CKTstate0 + here->B1qbd) + + *(ckt->CKTstate0 + here->B1qbs); + + /* store small signal parameters */ + if((!(ckt->CKTmode & (MODEAC | MODETRAN))) && + (ckt->CKTmode & MODETRANOP ) && (ckt->CKTmode & + MODEUIC )) goto line850; + if(ckt->CKTmode & MODEINITSMSIG ) { + *(ckt->CKTstate0+here->B1cggb) = cggb; + *(ckt->CKTstate0+here->B1cgdb) = cgdb; + *(ckt->CKTstate0+here->B1cgsb) = cgsb; + *(ckt->CKTstate0+here->B1cbgb) = cbgb; + *(ckt->CKTstate0+here->B1cbdb) = cbdb; + *(ckt->CKTstate0+here->B1cbsb) = cbsb; + *(ckt->CKTstate0+here->B1cdgb) = cdgb; + *(ckt->CKTstate0+here->B1cddb) = cddb; + *(ckt->CKTstate0+here->B1cdsb) = cdsb; + *(ckt->CKTstate0+here->B1capbd) = capbd; + *(ckt->CKTstate0+here->B1capbs) = capbs; + + goto line1000; + } + + if(ckt->CKTmode & MODEINITTRAN ) { + *(ckt->CKTstate1+here->B1qb) = + *(ckt->CKTstate0+here->B1qb) ; + *(ckt->CKTstate1+here->B1qg) = + *(ckt->CKTstate0+here->B1qg) ; + *(ckt->CKTstate1+here->B1qd) = + *(ckt->CKTstate0+here->B1qd) ; + } + + + error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qb); + if(error) return(error); + error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qg); + if(error) return(error); + error = NIintegrate(ckt,&geq,&ceq,0.0,here->B1qd); + if(error) return(error); + + goto line860; + +line850: + /* initialize to zero charge conductance and current */ + ceqqg = ceqqb = ceqqd = 0.0; + gcdgb = gcddb = gcdsb = 0.0; + gcsgb = gcsdb = gcssb = 0.0; + gcggb = gcgdb = gcgsb = 0.0; + gcbgb = gcbdb = gcbsb = 0.0; + goto line900; + +line860: + /* evaluate equivalent charge current */ + cqgate = *(ckt->CKTstate0 + here->B1iqg); + cqbulk = *(ckt->CKTstate0 + here->B1iqb); + cqdrn = *(ckt->CKTstate0 + here->B1iqd); + ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; + ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs; + ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs; + + if(ckt->CKTmode & MODEINITTRAN ) { + *(ckt->CKTstate1 + here->B1iqb) = + *(ckt->CKTstate0 + here->B1iqb); + *(ckt->CKTstate1 + here->B1iqg) = + *(ckt->CKTstate0 + here->B1iqg); + *(ckt->CKTstate1 + here->B1iqd) = + *(ckt->CKTstate0 + here->B1iqd); + } + + /* + * load current vector + */ +line900: + + ceqbs = model->B1type * (cbs-(gbs-ckt->CKTgmin)*vbs); + ceqbd = model->B1type * (cbd-(gbd-ckt->CKTgmin)*vbd); + + ceqqg = model->B1type * ceqqg; + ceqqb = model->B1type * ceqqb; + ceqqd = model->B1type * ceqqd; + if (here->B1mode >= 0) { + xnrm=1; + xrev=0; + cdreq=model->B1type*(cdrain-gds*vds-gm*vgs-gmbs*vbs); + } else { + xnrm=0; + xrev=1; + cdreq = -(model->B1type)*(cdrain+gds*vds-gm*vgd-gmbs*vbd); + } + + *(ckt->CKTrhs + here->B1gNode) -= ceqqg; + *(ckt->CKTrhs + here->B1bNode) -=(ceqbs+ceqbd+ceqqb); + *(ckt->CKTrhs + here->B1dNodePrime) += + (ceqbd-cdreq-ceqqd); + *(ckt->CKTrhs + here->B1sNodePrime) += + (cdreq+ceqbs+ceqqg+ceqqb+ceqqd); + + /* + * load y matrix + */ + + *(here->B1DdPtr) += (here->B1drainConductance); + *(here->B1GgPtr) += (gcggb); + *(here->B1SsPtr) += (here->B1sourceConductance); + *(here->B1BbPtr) += (gbd+gbs-gcbgb-gcbdb-gcbsb); + *(here->B1DPdpPtr) += + (here->B1drainConductance+gds+gbd+xrev*(gm+gmbs)+gcddb); + *(here->B1SPspPtr) += + (here->B1sourceConductance+gds+gbs+xnrm*(gm+gmbs)+gcssb); + *(here->B1DdpPtr) += (-here->B1drainConductance); + *(here->B1GbPtr) += (-gcggb-gcgdb-gcgsb); + *(here->B1GdpPtr) += (gcgdb); + *(here->B1GspPtr) += (gcgsb); + *(here->B1SspPtr) += (-here->B1sourceConductance); + *(here->B1BgPtr) += (gcbgb); + *(here->B1BdpPtr) += (-gbd+gcbdb); + *(here->B1BspPtr) += (-gbs+gcbsb); + *(here->B1DPdPtr) += (-here->B1drainConductance); + *(here->B1DPgPtr) += ((xnrm-xrev)*gm+gcdgb); + *(here->B1DPbPtr) += (-gbd+(xnrm-xrev)*gmbs-gcdgb-gcddb-gcdsb); + *(here->B1DPspPtr) += (-gds-xnrm*(gm+gmbs)+gcdsb); + *(here->B1SPgPtr) += (-(xnrm-xrev)*gm+gcsgb); + *(here->B1SPsPtr) += (-here->B1sourceConductance); + *(here->B1SPbPtr) += (-gbs-(xnrm-xrev)*gmbs-gcsgb-gcsdb-gcssb); + *(here->B1SPdpPtr) += (-gds-xrev*(gm+gmbs)+gcsdb); + + +line1000: ; + + } /* End of Mosfet Instance */ + + } /* End of Model Instance */ + return(OK); +} + diff --git a/src/spicelib/devices/bsim1/b1mask.c b/src/spicelib/devices/bsim1/b1mask.c new file mode 100644 index 000000000..fc70b05e6 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1mask.c @@ -0,0 +1,264 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Hong J. Park +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim1def.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +B1mAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + B1model *model = (B1model *)inst; + switch(which) { + case BSIM1_MOD_VFB0: + value->rValue = model->B1vfb0; + return(OK); + case BSIM1_MOD_VFBL: + value->rValue = model->B1vfbL; + return(OK); + case BSIM1_MOD_VFBW: + value->rValue = model->B1vfbW; + return(OK); + case BSIM1_MOD_PHI0: + value->rValue = model->B1phi0; + return(OK); + case BSIM1_MOD_PHIL: + value->rValue = model->B1phiL; + return(OK); + case BSIM1_MOD_PHIW: + value->rValue = model->B1phiW; + return(OK); + case BSIM1_MOD_K10: + value->rValue = model->B1K10; + return(OK); + case BSIM1_MOD_K1L: + value->rValue = model->B1K1L; + return(OK); + case BSIM1_MOD_K1W: + value->rValue = model->B1K1W; + return(OK); + case BSIM1_MOD_K20: + value->rValue = model->B1K20; + return(OK); + case BSIM1_MOD_K2L: + value->rValue = model->B1K2L; + return(OK); + case BSIM1_MOD_K2W: + value->rValue = model->B1K2W; + return(OK); + case BSIM1_MOD_ETA0: + value->rValue = model->B1eta0; + return(OK); + case BSIM1_MOD_ETAL: + value->rValue = model->B1etaL; + return(OK); + case BSIM1_MOD_ETAW: + value->rValue = model->B1etaW; + return(OK); + case BSIM1_MOD_ETAB0: + value->rValue = model->B1etaB0; + return(OK); + case BSIM1_MOD_ETABL: + value->rValue = model->B1etaBl; + return(OK); + case BSIM1_MOD_ETABW: + value->rValue = model->B1etaBw; + return(OK); + case BSIM1_MOD_ETAD0: + value->rValue = model->B1etaD0; + return(OK); + case BSIM1_MOD_ETADL: + value->rValue = model->B1etaDl; + return(OK); + case BSIM1_MOD_ETADW: + value->rValue = model->B1etaDw; + return(OK); + case BSIM1_MOD_DELTAL: + value->rValue = model->B1deltaL; + return(OK); + case BSIM1_MOD_DELTAW: + value->rValue = model->B1deltaW; + return(OK); + case BSIM1_MOD_MOBZERO: + value->rValue = model->B1mobZero; + return(OK); + case BSIM1_MOD_MOBZEROB0: + value->rValue = model->B1mobZeroB0; + return(OK); + case BSIM1_MOD_MOBZEROBL: + value->rValue = model->B1mobZeroBl; + return(OK); + case BSIM1_MOD_MOBZEROBW: + value->rValue = model->B1mobZeroBw; + return(OK); + case BSIM1_MOD_MOBVDD0: + value->rValue = model->B1mobVdd0; + return(OK); + case BSIM1_MOD_MOBVDDL: + value->rValue = model->B1mobVddl; + return(OK); + case BSIM1_MOD_MOBVDDW: + value->rValue = model->B1mobVddw; + return(OK); + case BSIM1_MOD_MOBVDDB0: + value->rValue = model->B1mobVddB0; + return(OK); + case BSIM1_MOD_MOBVDDBL: + value->rValue = model->B1mobVddBl; + return(OK); + case BSIM1_MOD_MOBVDDBW: + value->rValue = model->B1mobVddBw; + return(OK); + case BSIM1_MOD_MOBVDDD0: + value->rValue = model->B1mobVddD0; + return(OK); + case BSIM1_MOD_MOBVDDDL: + value->rValue = model->B1mobVddDl; + return(OK); + case BSIM1_MOD_MOBVDDDW: + value->rValue = model->B1mobVddDw; + return(OK); + case BSIM1_MOD_UGS0: + value->rValue = model->B1ugs0; + return(OK); + case BSIM1_MOD_UGSL: + value->rValue = model->B1ugsL; + return(OK); + case BSIM1_MOD_UGSW: + value->rValue = model->B1ugsW; + return(OK); + case BSIM1_MOD_UGSB0: + value->rValue = model->B1ugsB0; + return(OK); + case BSIM1_MOD_UGSBL: + value->rValue = model->B1ugsBL; + return(OK); + case BSIM1_MOD_UGSBW: + value->rValue = model->B1ugsBW; + return(OK); + case BSIM1_MOD_UDS0: + value->rValue = model->B1uds0; + return(OK); + case BSIM1_MOD_UDSL: + value->rValue = model->B1udsL; + return(OK); + case BSIM1_MOD_UDSW: + value->rValue = model->B1udsW; + return(OK); + case BSIM1_MOD_UDSB0: + value->rValue = model->B1udsB0; + return(OK); + case BSIM1_MOD_UDSBL: + value->rValue = model->B1udsBL; + return(OK); + case BSIM1_MOD_UDSBW: + value->rValue = model->B1udsBW; + return(OK); + case BSIM1_MOD_UDSD0: + value->rValue = model->B1udsD0; + return(OK); + case BSIM1_MOD_UDSDL: + value->rValue = model->B1udsDL; + return(OK); + case BSIM1_MOD_UDSDW: + value->rValue = model->B1udsDW; + return(OK); + case BSIM1_MOD_N00: + value->rValue = model->B1subthSlope0; + return(OK); + case BSIM1_MOD_N0L: + value->rValue = model->B1subthSlopeL; + return(OK); + case BSIM1_MOD_N0W: + value->rValue = model->B1subthSlopeW; + return(OK); + case BSIM1_MOD_NB0: + value->rValue = model->B1subthSlopeB0; + return(OK); + case BSIM1_MOD_NBL: + value->rValue = model->B1subthSlopeBL; + return(OK); + case BSIM1_MOD_NBW: + value->rValue = model->B1subthSlopeBW; + return(OK); + case BSIM1_MOD_ND0: + value->rValue = model->B1subthSlopeD0; + return(OK); + case BSIM1_MOD_NDL: + value->rValue = model->B1subthSlopeDL; + return(OK); + case BSIM1_MOD_NDW: + value->rValue = model->B1subthSlopeDW; + return(OK); + case BSIM1_MOD_TOX: + value->rValue = model->B1oxideThickness; + return(OK); + case BSIM1_MOD_TEMP: + value->rValue = model->B1temp; + return(OK); + case BSIM1_MOD_VDD: + value->rValue = model->B1vdd; + return(OK); + case BSIM1_MOD_CGSO: + value->rValue = model->B1gateSourceOverlapCap; + return(OK); + case BSIM1_MOD_CGDO: + value->rValue = model->B1gateDrainOverlapCap; + return(OK); + case BSIM1_MOD_CGBO: + value->rValue = model->B1gateBulkOverlapCap; + return(OK); + case BSIM1_MOD_XPART: + value->iValue = model->B1channelChargePartitionFlag; + return(OK); + case BSIM1_MOD_RSH: + value->rValue = model->B1sheetResistance; + return(OK); + case BSIM1_MOD_JS: + value->rValue = model->B1jctSatCurDensity; + return(OK); + case BSIM1_MOD_PB: + value->rValue = model->B1bulkJctPotential; + return(OK); + case BSIM1_MOD_MJ: + value->rValue = model->B1bulkJctBotGradingCoeff; + return(OK); + case BSIM1_MOD_PBSW: + value->rValue = model->B1sidewallJctPotential; + return(OK); + case BSIM1_MOD_MJSW: + value->rValue = model->B1bulkJctSideGradingCoeff; + return(OK); + case BSIM1_MOD_CJ: + value->rValue = model->B1unitAreaJctCap; + return(OK); + case BSIM1_MOD_CJSW: + value->rValue = model->B1unitLengthSidewallJctCap; + return(OK); + case BSIM1_MOD_DEFWIDTH: + value->rValue = model->B1defaultWidth; + return(OK); + case BSIM1_MOD_DELLENGTH: + value->rValue = model->B1deltaLength; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bsim1/b1mdel.c b/src/spicelib/devices/bsim1/b1mdel.c new file mode 100644 index 000000000..e4cd68a57 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1mdel.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim1def.h" +#include "sperror.h" +#include "suffix.h" + + +int +B1mDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + B1model **model = (B1model**)inModel; + B1model *modfast = (B1model*)kill; + B1instance *here; + B1instance *prev = NULL; + B1model **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->B1nextModel)) { + if( (*model)->B1modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->B1nextModel; /* cut deleted device out of list */ + for(here = (*model)->B1instances ; here ; here = here->B1nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/bsim1/b1moscap.c b/src/spicelib/devices/bsim1/b1moscap.c new file mode 100644 index 000000000..dd69fc20c --- /dev/null +++ b/src/spicelib/devices/bsim1/b1moscap.c @@ -0,0 +1,101 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "suffix.h" + +/* routine to calculate equivalent conductance and total terminal + * charges + */ + +void +B1mosCap(ckt,vgd,vgs,vgb, + args, + /* + GateDrainOverlapCap,GateSourceOverlapCap, GateBulkOverlapCap, + capbd,capbs, + cggb,cgdb,cgsb, + */ + cbgb,cbdb,cbsb,cdgb,cddb,cdsb, + gcggbPointer,gcgdbPointer,gcgsbPointer,gcbgbPointer,gcbdbPointer, + gcbsbPointer,gcdgbPointer,gcddbPointer,gcdsbPointer, + gcsgbPointer,gcsdbPointer,gcssbPointer,qGatePointer,qBulkPointer, + qDrainPointer,qSourcePointer) + register CKTcircuit *ckt; + double vgd; + double vgs; + double vgb; + double args[8]; + /* + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double GateBulkOverlapCap; + double capbd; + double capbs; + double cggb; + double cgdb; + double cgsb; + */ + double cbgb; + double cbdb; + double cbsb; + double cdgb; + double cddb; + double cdsb; + double *gcggbPointer; + double *gcgdbPointer; + double *gcgsbPointer; + double *gcbgbPointer; + double *gcbdbPointer; + double *gcbsbPointer; + double *gcdgbPointer; + double *gcddbPointer; + double *gcdsbPointer; + double *gcsgbPointer; + double *gcsdbPointer; + double *gcssbPointer; + double *qGatePointer; + double *qBulkPointer; + double *qDrainPointer; + double *qSourcePointer; + +{ + double qgd; + double qgs; + double qgb; + double ag0; + + ag0 = ckt->CKTag[0]; + /* compute equivalent conductance */ + *gcdgbPointer = (cdgb - args[0]) * ag0; + *gcddbPointer = (cddb + args[3] + args[0]) * ag0; + *gcdsbPointer = cdsb * ag0; + *gcsgbPointer = -(args[5] + cbgb + cdgb + args[1]) * ag0; + *gcsdbPointer = -(args[6] + cbdb + cddb ) * ag0; + *gcssbPointer = (args[4] + args[1] - + (args[7] + cbsb + cdsb )) * ag0; + *gcggbPointer = (args[5] + args[0] + + args[1] + args[2] ) * ag0; + *gcgdbPointer = (args[6] - args[0]) * ag0; + *gcgsbPointer = (args[7] - args[1]) * ag0; + *gcbgbPointer = (cbgb - args[2]) * ag0; + *gcbdbPointer = (cbdb - args[3]) * ag0; + *gcbsbPointer = (cbsb - args[4]) * ag0; + + /* compute total terminal charge */ + qgd = args[0] * vgd; + qgs = args[1] * vgs; + qgb = args[2] * vgb; + *qGatePointer = *qGatePointer + qgd + qgs + qgb; + *qBulkPointer = *qBulkPointer - qgb; + *qDrainPointer = *qDrainPointer - qgd; + *qSourcePointer = -(*qGatePointer + *qBulkPointer + *qDrainPointer); + +} + + diff --git a/src/spicelib/devices/bsim1/b1mpar.c b/src/spicelib/devices/bsim1/b1mpar.c new file mode 100644 index 000000000..de6b1802b --- /dev/null +++ b/src/spicelib/devices/bsim1/b1mpar.c @@ -0,0 +1,350 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim1def.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +int +B1mParam(param,value,inMod) + int param; + IFvalue *value; + GENmodel *inMod; +{ + B1model *mod = (B1model*)inMod; + switch(param) { + case BSIM1_MOD_VFB0 : + mod->B1vfb0 = value->rValue; + mod->B1vfb0Given = TRUE; + break; + case BSIM1_MOD_VFBL : + mod->B1vfbL = value->rValue; + mod->B1vfbLGiven = TRUE; + break; + case BSIM1_MOD_VFBW : + mod->B1vfbW = value->rValue; + mod->B1vfbWGiven = TRUE; + break; + case BSIM1_MOD_PHI0 : + mod->B1phi0 = value->rValue; + mod->B1phi0Given = TRUE; + break; + case BSIM1_MOD_PHIL : + mod->B1phiL = value->rValue; + mod->B1phiLGiven = TRUE; + break; + case BSIM1_MOD_PHIW : + mod->B1phiW = value->rValue; + mod->B1phiWGiven = TRUE; + break; + case BSIM1_MOD_K10 : + mod->B1K10 = value->rValue; + mod->B1K10Given = TRUE; + break; + case BSIM1_MOD_K1L : + mod->B1K1L = value->rValue; + mod->B1K1LGiven = TRUE; + break; + case BSIM1_MOD_K1W : + mod->B1K1W = value->rValue; + mod->B1K1WGiven = TRUE; + break; + case BSIM1_MOD_K20 : + mod->B1K20 = value->rValue; + mod->B1K20Given = TRUE; + break; + case BSIM1_MOD_K2L : + mod->B1K2L = value->rValue; + mod->B1K2LGiven = TRUE; + break; + case BSIM1_MOD_K2W : + mod->B1K2W = value->rValue; + mod->B1K2WGiven = TRUE; + break; + case BSIM1_MOD_ETA0 : + mod->B1eta0 = value->rValue; + mod->B1eta0Given = TRUE; + break; + case BSIM1_MOD_ETAL : + mod->B1etaL = value->rValue; + mod->B1etaLGiven = TRUE; + break; + case BSIM1_MOD_ETAW : + mod->B1etaW = value->rValue; + mod->B1etaWGiven = TRUE; + break; + case BSIM1_MOD_ETAB0 : + mod->B1etaB0 = value->rValue; + mod->B1etaB0Given = TRUE; + break; + case BSIM1_MOD_ETABL : + mod->B1etaBl = value->rValue; + mod->B1etaBlGiven = TRUE; + break; + case BSIM1_MOD_ETABW : + mod->B1etaBw = value->rValue; + mod->B1etaBwGiven = TRUE; + break; + case BSIM1_MOD_ETAD0 : + mod->B1etaD0 = value->rValue; + mod->B1etaD0Given = TRUE; + break; + case BSIM1_MOD_ETADL : + mod->B1etaDl = value->rValue; + mod->B1etaDlGiven = TRUE; + break; + case BSIM1_MOD_ETADW : + mod->B1etaDw = value->rValue; + mod->B1etaDwGiven = TRUE; + break; + case BSIM1_MOD_DELTAL : + mod->B1deltaL = value->rValue; + mod->B1deltaLGiven = TRUE; + break; + case BSIM1_MOD_DELTAW : + mod->B1deltaW = value->rValue; + mod->B1deltaWGiven = TRUE; + break; + case BSIM1_MOD_MOBZERO : + mod->B1mobZero = value->rValue; + mod->B1mobZeroGiven = TRUE; + break; + case BSIM1_MOD_MOBZEROB0 : + mod->B1mobZeroB0 = value->rValue; + mod->B1mobZeroB0Given = TRUE; + break; + case BSIM1_MOD_MOBZEROBL : + mod->B1mobZeroBl = value->rValue; + mod->B1mobZeroBlGiven = TRUE; + break; + case BSIM1_MOD_MOBZEROBW : + mod->B1mobZeroBw = value->rValue; + mod->B1mobZeroBwGiven = TRUE; + break; + case BSIM1_MOD_MOBVDD0 : + mod->B1mobVdd0 = value->rValue; + mod->B1mobVdd0Given = TRUE; + break; + case BSIM1_MOD_MOBVDDL : + mod->B1mobVddl = value->rValue; + mod->B1mobVddlGiven = TRUE; + break; + case BSIM1_MOD_MOBVDDW : + mod->B1mobVddw = value->rValue; + mod->B1mobVddwGiven = TRUE; + break; + case BSIM1_MOD_MOBVDDB0 : + mod->B1mobVddB0 = value->rValue; + mod->B1mobVddB0Given = TRUE; + break; + case BSIM1_MOD_MOBVDDBL : + mod->B1mobVddBl = value->rValue; + mod->B1mobVddBlGiven = TRUE; + break; + case BSIM1_MOD_MOBVDDBW : + mod->B1mobVddBw = value->rValue; + mod->B1mobVddBwGiven = TRUE; + break; + case BSIM1_MOD_MOBVDDD0 : + mod->B1mobVddD0 = value->rValue; + mod->B1mobVddD0Given = TRUE; + break; + case BSIM1_MOD_MOBVDDDL : + mod->B1mobVddDl = value->rValue; + mod->B1mobVddDlGiven = TRUE; + break; + case BSIM1_MOD_MOBVDDDW : + mod->B1mobVddDw = value->rValue; + mod->B1mobVddDwGiven = TRUE; + break; + case BSIM1_MOD_UGS0 : + mod->B1ugs0 = value->rValue; + mod->B1ugs0Given = TRUE; + break; + case BSIM1_MOD_UGSL : + mod->B1ugsL = value->rValue; + mod->B1ugsLGiven = TRUE; + break; + case BSIM1_MOD_UGSW : + mod->B1ugsW = value->rValue; + mod->B1ugsWGiven = TRUE; + break; + case BSIM1_MOD_UGSB0 : + mod->B1ugsB0 = value->rValue; + mod->B1ugsB0Given = TRUE; + break; + case BSIM1_MOD_UGSBL : + mod->B1ugsBL = value->rValue; + mod->B1ugsBLGiven = TRUE; + break; + case BSIM1_MOD_UGSBW : + mod->B1ugsBW = value->rValue; + mod->B1ugsBWGiven = TRUE; + break; + case BSIM1_MOD_UDS0 : + mod->B1uds0 = value->rValue; + mod->B1uds0Given = TRUE; + break; + case BSIM1_MOD_UDSL : + mod->B1udsL = value->rValue; + mod->B1udsLGiven = TRUE; + break; + case BSIM1_MOD_UDSW : + mod->B1udsW = value->rValue; + mod->B1udsWGiven = TRUE; + break; + case BSIM1_MOD_UDSB0 : + mod->B1udsB0 = value->rValue; + mod->B1udsB0Given = TRUE; + break; + case BSIM1_MOD_UDSBL : + mod->B1udsBL = value->rValue; + mod->B1udsBLGiven = TRUE; + break; + case BSIM1_MOD_UDSBW : + mod->B1udsBW = value->rValue; + mod->B1udsBWGiven = TRUE; + break; + case BSIM1_MOD_UDSD0 : + mod->B1udsD0 = value->rValue; + mod->B1udsD0Given = TRUE; + break; + case BSIM1_MOD_UDSDL : + mod->B1udsDL = value->rValue; + mod->B1udsDLGiven = TRUE; + break; + case BSIM1_MOD_UDSDW : + mod->B1udsDW = value->rValue; + mod->B1udsDWGiven = TRUE; + break; + case BSIM1_MOD_N00 : + mod->B1subthSlope0 = value->rValue; + mod->B1subthSlope0Given = TRUE; + break; + case BSIM1_MOD_N0L : + mod->B1subthSlopeL = value->rValue; + mod->B1subthSlopeLGiven = TRUE; + break; + case BSIM1_MOD_N0W : + mod->B1subthSlopeW = value->rValue; + mod->B1subthSlopeWGiven = TRUE; + break; + case BSIM1_MOD_NB0 : + mod->B1subthSlopeB0 = value->rValue; + mod->B1subthSlopeB0Given = TRUE; + break; + case BSIM1_MOD_NBL : + mod->B1subthSlopeBL = value->rValue; + mod->B1subthSlopeBLGiven = TRUE; + break; + case BSIM1_MOD_NBW : + mod->B1subthSlopeBW = value->rValue; + mod->B1subthSlopeBWGiven = TRUE; + break; + case BSIM1_MOD_ND0 : + mod->B1subthSlopeD0 = value->rValue; + mod->B1subthSlopeD0Given = TRUE; + break; + case BSIM1_MOD_NDL : + mod->B1subthSlopeDL = value->rValue; + mod->B1subthSlopeDLGiven = TRUE; + break; + case BSIM1_MOD_NDW : + mod->B1subthSlopeDW = value->rValue; + mod->B1subthSlopeDWGiven = TRUE; + break; + case BSIM1_MOD_TOX : + mod->B1oxideThickness = value->rValue; + mod->B1oxideThicknessGiven = TRUE; + break; + case BSIM1_MOD_TEMP : + mod->B1temp = value->rValue; + mod->B1tempGiven = TRUE; + break; + case BSIM1_MOD_VDD : + mod->B1vdd = value->rValue; + mod->B1vddGiven = TRUE; + break; + case BSIM1_MOD_CGSO : + mod->B1gateSourceOverlapCap = value->rValue; + mod->B1gateSourceOverlapCapGiven = TRUE; + break; + case BSIM1_MOD_CGDO : + mod->B1gateDrainOverlapCap = value->rValue; + mod->B1gateDrainOverlapCapGiven = TRUE; + break; + case BSIM1_MOD_CGBO : + mod->B1gateBulkOverlapCap = value->rValue; + mod->B1gateBulkOverlapCapGiven = TRUE; + break; + case BSIM1_MOD_XPART : + mod->B1channelChargePartitionFlag = value->rValue; + mod->B1channelChargePartitionFlagGiven = TRUE; + break; + case BSIM1_MOD_RSH : + mod->B1sheetResistance = value->rValue; + mod->B1sheetResistanceGiven = TRUE; + break; + case BSIM1_MOD_JS : + mod->B1jctSatCurDensity = value->rValue; + mod->B1jctSatCurDensityGiven = TRUE; + break; + case BSIM1_MOD_PB : + mod->B1bulkJctPotential = value->rValue; + mod->B1bulkJctPotentialGiven = TRUE; + break; + case BSIM1_MOD_MJ : + mod->B1bulkJctBotGradingCoeff = value->rValue; + mod->B1bulkJctBotGradingCoeffGiven = TRUE; + break; + case BSIM1_MOD_PBSW : + mod->B1sidewallJctPotential = value->rValue; + mod->B1sidewallJctPotentialGiven = TRUE; + break; + case BSIM1_MOD_MJSW : + mod->B1bulkJctSideGradingCoeff = value->rValue; + mod->B1bulkJctSideGradingCoeffGiven = TRUE; + break; + case BSIM1_MOD_CJ : + mod->B1unitAreaJctCap = value->rValue; + mod->B1unitAreaJctCapGiven = TRUE; + break; + case BSIM1_MOD_CJSW : + mod->B1unitLengthSidewallJctCap = value->rValue; + mod->B1unitLengthSidewallJctCapGiven = TRUE; + break; + case BSIM1_MOD_DEFWIDTH : + mod->B1defaultWidth = value->rValue; + mod->B1defaultWidthGiven = TRUE; + break; + case BSIM1_MOD_DELLENGTH : + mod->B1deltaLength = value->rValue; + mod->B1deltaLengthGiven = TRUE; + break; + case BSIM1_MOD_NMOS : + if(value->iValue) { + mod->B1type = 1; + mod->B1typeGiven = TRUE; + } + break; + case BSIM1_MOD_PMOS : + if(value->iValue) { + mod->B1type = - 1; + mod->B1typeGiven = TRUE; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim1/b1par.c b/src/spicelib/devices/bsim1/b1par.c new file mode 100644 index 000000000..0e5f2a4f8 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1par.c @@ -0,0 +1,95 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "bsim1def.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +B1param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + B1instance *here = (B1instance*)inst; + switch(param) { + case BSIM1_W: + here->B1w = value->rValue; + here->B1wGiven = TRUE; + break; + case BSIM1_L: + here->B1l = value->rValue; + here->B1lGiven = TRUE; + break; + case BSIM1_AS: + here->B1sourceArea = value->rValue; + here->B1sourceAreaGiven = TRUE; + break; + case BSIM1_AD: + here->B1drainArea = value->rValue; + here->B1drainAreaGiven = TRUE; + break; + case BSIM1_PS: + here->B1sourcePerimeter = value->rValue; + here->B1sourcePerimeterGiven = TRUE; + break; + case BSIM1_PD: + here->B1drainPerimeter = value->rValue; + here->B1drainPerimeterGiven = TRUE; + break; + case BSIM1_NRS: + here->B1sourceSquares = value->rValue; + here->B1sourceSquaresGiven = TRUE; + break; + case BSIM1_NRD: + here->B1drainSquares = value->rValue; + here->B1drainSquaresGiven = TRUE; + break; + case BSIM1_OFF: + here->B1off = value->iValue; + break; + case BSIM1_IC_VBS: + here->B1icVBS = value->rValue; + here->B1icVBSGiven = TRUE; + break; + case BSIM1_IC_VDS: + here->B1icVDS = value->rValue; + here->B1icVDSGiven = TRUE; + break; + case BSIM1_IC_VGS: + here->B1icVGS = value->rValue; + here->B1icVGSGiven = TRUE; + break; + case BSIM1_IC: + switch(value->v.numValue){ + case 3: + here->B1icVBS = *(value->v.vec.rVec+2); + here->B1icVBSGiven = TRUE; + case 2: + here->B1icVGS = *(value->v.vec.rVec+1); + here->B1icVGSGiven = TRUE; + case 1: + here->B1icVDS = *(value->v.vec.rVec); + here->B1icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim1/b1pzld.c b/src/spicelib/devices/bsim1/b1pzld.c new file mode 100644 index 000000000..d1c47f8e3 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1pzld.c @@ -0,0 +1,163 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "bsim1def.h" +#include "suffix.h" + + +int +B1pzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + register SPcomplex *s; +{ + register B1model *model = (B1model*)inModel; + register B1instance *here; + int xnrm; + int xrev; + double gdpr; + double gspr; + double gm; + double gds; + double gmbs; + double gbd; + double gbs; + double capbd; + double capbs; + double xcggb; + double xcgdb; + double xcgsb; + double xcbgb; + double xcbdb; + double xcbsb; + double xcddb; + double xcssb; + double xcdgb; + double xcsgb; + double xcdsb; + double xcsdb; + double cggb; + double cgdb; + double cgsb; + double cbgb; + double cbdb; + double cbsb; + double cddb; + double cdgb; + double cdsb; + + for( ; model != NULL; model = model->B1nextModel) { + for(here = model->B1instances; here!= NULL; + here = here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + if (here->B1mode >= 0) { + xnrm=1; + xrev=0; + } else { + xnrm=0; + xrev=1; + } + gdpr=here->B1drainConductance; + gspr=here->B1sourceConductance; + gm= *(ckt->CKTstate0 + here->B1gm); + gds= *(ckt->CKTstate0 + here->B1gds); + gmbs= *(ckt->CKTstate0 + here->B1gmbs); + gbd= *(ckt->CKTstate0 + here->B1gbd); + gbs= *(ckt->CKTstate0 + here->B1gbs); + capbd= *(ckt->CKTstate0 + here->B1capbd); + capbs= *(ckt->CKTstate0 + here->B1capbs); + /* + * charge oriented model parameters + */ + + cggb = *(ckt->CKTstate0 + here->B1cggb); + cgsb = *(ckt->CKTstate0 + here->B1cgsb); + cgdb = *(ckt->CKTstate0 + here->B1cgdb); + + cbgb = *(ckt->CKTstate0 + here->B1cbgb); + cbsb = *(ckt->CKTstate0 + here->B1cbsb); + cbdb = *(ckt->CKTstate0 + here->B1cbdb); + + cdgb = *(ckt->CKTstate0 + here->B1cdgb); + cdsb = *(ckt->CKTstate0 + here->B1cdsb); + cddb = *(ckt->CKTstate0 + here->B1cddb); + + xcdgb = (cdgb - here->B1GDoverlapCap) ; + xcddb = (cddb + capbd + here->B1GDoverlapCap) ; + xcdsb = cdsb ; + xcsgb = -(cggb + cbgb + cdgb + here->B1GSoverlapCap ) ; + xcsdb = -(cgdb + cbdb + cddb) ; + xcssb = (capbs + here->B1GSoverlapCap - (cgsb+cbsb+cdsb)) ; + xcggb = (cggb + here->B1GDoverlapCap + here->B1GSoverlapCap + + here->B1GBoverlapCap) ; + xcgdb = (cgdb - here->B1GDoverlapCap ) ; + xcgsb = (cgsb - here->B1GSoverlapCap) ; + xcbgb = (cbgb - here->B1GBoverlapCap) ; + xcbdb = (cbdb - capbd ) ; + xcbsb = (cbsb - capbs ) ; + + + *(here->B1GgPtr ) += xcggb * s->real; + *(here->B1GgPtr +1) += xcggb * s->imag; + *(here->B1BbPtr ) += (-xcbgb-xcbdb-xcbsb) * s->real; + *(here->B1BbPtr +1) += (-xcbgb-xcbdb-xcbsb) * s->imag; + *(here->B1DPdpPtr ) += xcddb * s->real; + *(here->B1DPdpPtr +1) += xcddb * s->imag; + *(here->B1SPspPtr ) += xcssb * s->real; + *(here->B1SPspPtr +1) += xcssb * s->imag; + *(here->B1GbPtr ) += (-xcggb-xcgdb-xcgsb) * s->real; + *(here->B1GbPtr +1) += (-xcggb-xcgdb-xcgsb) * s->imag; + *(here->B1GdpPtr ) += xcgdb * s->real; + *(here->B1GdpPtr +1) += xcgdb * s->imag; + *(here->B1GspPtr ) += xcgsb * s->real; + *(here->B1GspPtr +1) += xcgsb * s->imag; + *(here->B1BgPtr ) += xcbgb * s->real; + *(here->B1BgPtr +1) += xcbgb * s->imag; + *(here->B1BdpPtr ) += xcbdb * s->real; + *(here->B1BdpPtr +1) += xcbdb * s->imag; + *(here->B1BspPtr ) += xcbsb * s->real; + *(here->B1BspPtr +1) += xcbsb * s->imag; + *(here->B1DPgPtr ) += xcdgb * s->real; + *(here->B1DPgPtr +1) += xcdgb * s->imag; + *(here->B1DPbPtr ) += (-xcdgb-xcddb-xcdsb) * s->real; + *(here->B1DPbPtr +1) += (-xcdgb-xcddb-xcdsb) * s->imag; + *(here->B1DPspPtr ) += xcdsb * s->real; + *(here->B1DPspPtr +1) += xcdsb * s->imag; + *(here->B1SPgPtr ) += xcsgb * s->real; + *(here->B1SPgPtr +1) += xcsgb * s->imag; + *(here->B1SPbPtr ) += (-xcsgb-xcsdb-xcssb) * s->real; + *(here->B1SPbPtr +1) += (-xcsgb-xcsdb-xcssb) * s->imag; + *(here->B1SPdpPtr ) += xcsdb * s->real; + *(here->B1SPdpPtr +1) += xcsdb * s->imag; + *(here->B1DdPtr) += gdpr; + *(here->B1SsPtr) += gspr; + *(here->B1BbPtr) += gbd+gbs; + *(here->B1DPdpPtr) += gdpr+gds+gbd+xrev*(gm+gmbs); + *(here->B1SPspPtr) += gspr+gds+gbs+xnrm*(gm+gmbs); + *(here->B1DdpPtr) -= gdpr; + *(here->B1SspPtr) -= gspr; + *(here->B1BdpPtr) -= gbd; + *(here->B1BspPtr) -= gbs; + *(here->B1DPdPtr) -= gdpr; + *(here->B1DPgPtr) += (xnrm-xrev)*gm; + *(here->B1DPbPtr) += -gbd+(xnrm-xrev)*gmbs; + *(here->B1DPspPtr) += -gds-xnrm*(gm+gmbs); + *(here->B1SPgPtr) += -(xnrm-xrev)*gm; + *(here->B1SPsPtr) -= gspr; + *(here->B1SPbPtr) += -gbs-(xnrm-xrev)*gmbs; + *(here->B1SPdpPtr) += -gds-xrev*(gm+gmbs); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim1/b1set.c b/src/spicelib/devices/bsim1/b1set.c new file mode 100644 index 000000000..4e4cc6210 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1set.c @@ -0,0 +1,412 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim1def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +B1setup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + register GENmodel *inModel; + register CKTcircuit *ckt; + int *states; + /* load the B1 device structure with those pointers needed later + * for fast matrix loading + */ + +{ + register B1model *model = (B1model*)inModel; + register B1instance *here; + int error; + CKTnode *tmp; + + /* loop through all the B1 device models */ + for( ; model != NULL; model = model->B1nextModel ) { + +/* Default value Processing for B1 MOSFET Models */ + if( ! model->B1typeGiven) { + model->B1type = NMOS; /* NMOS */ + } + if( ! model->B1vfb0Given) { + model->B1vfb0 = 0.0; + } + if( ! model->B1vfbLGiven) { + model->B1vfbL = 0.0; + } + if( ! model->B1vfbWGiven) { + model->B1vfbW = 0.0; + } + if( ! model->B1phi0Given) { + model->B1phi0 = 0.0; + } + if( ! model->B1phiLGiven) { + model->B1phiL = 0.0; + } + if( ! model->B1phiWGiven) { + model->B1phiW = 0.0; + } + if( ! model->B1K10Given) { + model->B1K10 = 0.0; + } + if( ! model->B1K1LGiven) { + model->B1K1L = 0.0; + } + if( ! model->B1K1WGiven) { + model->B1K1W = 0.0; + } + if( ! model->B1K20Given) { + model->B1K20 = 0.0; + } + if( ! model->B1K2LGiven) { + model->B1K2L = 0.0; + } + if( ! model->B1K2WGiven) { + model->B1K2W = 0.0; + } + if( ! model->B1eta0Given) { + model->B1eta0 = 0.0; + } + if( ! model->B1etaLGiven) { + model->B1etaL = 0.0; + } + if( ! model->B1etaWGiven) { + model->B1etaW = 0.0; + } + if( ! model->B1mobZeroGiven) { + model->B1mobZero = 0.0; + } + if( ! model->B1deltaLGiven) { + model->B1deltaL = 0.0; + } + if( ! model->B1deltaWGiven) { + model->B1deltaW = 0.0; + } + if( ! model->B1ugs0Given) { + model->B1ugs0 = 0.0; + } + if( ! model->B1ugsLGiven) { + model->B1ugsL = 0.0; + } + if( ! model->B1ugsWGiven) { + model->B1ugsW = 0.0; + } + if( ! model->B1uds0Given) { + model->B1uds0 = 0.0; + } + if( ! model->B1udsLGiven) { + model->B1udsL = 0.0; + } + if( ! model->B1udsWGiven) { + model->B1udsW = 0.0; + } + if( ! model->B1mobZeroB0Given) { + model->B1mobZeroB0 = 0.0; + } + if( ! model->B1mobZeroBlGiven) { + model->B1mobZeroBl = 0.0; + } + if( ! model->B1mobZeroBwGiven) { + model->B1mobZeroBw = 0.0; + } + if( ! model->B1etaB0Given) { + model->B1etaB0 = 0.0; + } + if( ! model->B1etaBlGiven) { + model->B1etaBl = 0.0; + } + if( ! model->B1etaBwGiven) { + model->B1etaBw = 0.0; + } + if( ! model->B1etaD0Given) { + model->B1etaD0 = 0.0; + } + if( ! model->B1etaDlGiven) { + model->B1etaDl = 0.0; + } + if( ! model->B1etaDwGiven) { + model->B1etaDw = 0.0; + } + if( ! model->B1ugsB0Given) { + model->B1ugsB0 = 0.0; + } + if( ! model->B1ugsBLGiven) { + model->B1ugsBL = 0.0; + } + if( ! model->B1ugsBWGiven) { + model->B1ugsBW = 0.0; + } + if( ! model->B1udsB0Given) { + model->B1udsB0 = 0.0; + } + if( ! model->B1udsBLGiven) { + model->B1udsBL = 0.0; + } + if( ! model->B1udsBWGiven) { + model->B1udsBW = 0.0; + } + if( ! model->B1mobVdd0Given) { + model->B1mobVdd0 = 0.0; + } + if( ! model->B1mobVddlGiven) { + model->B1mobVddl = 0.0; + } + if( ! model->B1mobVddwGiven) { + model->B1mobVddw = 0.0; + } + if( ! model->B1mobVddB0Given) { + model->B1mobVddB0 = 0.0; + } + if( ! model->B1mobVddBlGiven) { + model->B1mobVddBl = 0.0; + } + if( ! model->B1mobVddBwGiven) { + model->B1mobVddBw = 0.0; + } + if( ! model->B1mobVddD0Given) { + model->B1mobVddD0 = 0.0; + } + if( ! model->B1mobVddDlGiven) { + model->B1mobVddDl = 0.0; + } + if( ! model->B1mobVddDwGiven) { + model->B1mobVddDw = 0.0; + } + if( ! model->B1udsD0Given) { + model->B1udsD0 = 0.0; + } + if( ! model->B1udsDLGiven) { + model->B1udsDL = 0.0; + } + if( ! model->B1udsDWGiven) { + model->B1udsDW = 0.0; + } + if( ! model->B1oxideThicknessGiven) { + model->B1oxideThickness = 0.0; /* um */ + } + if( ! model->B1tempGiven) { + model->B1temp = 0.0; + } + if( ! model->B1vddGiven) { + model->B1vdd = 0.0; + } + if( ! model->B1gateDrainOverlapCapGiven) { + model->B1gateDrainOverlapCap = 0.0; + } + if( ! model->B1gateSourceOverlapCapGiven) { + model->B1gateSourceOverlapCap = 0.0; + } + if( ! model->B1gateBulkOverlapCapGiven) { + model->B1gateBulkOverlapCap = 0.0; + } + if( ! model->B1channelChargePartitionFlagGiven) { + model->B1channelChargePartitionFlag = 0; + } + if( ! model->B1subthSlope0Given) { + model->B1subthSlope0 = 0.0; + } + if( ! model->B1subthSlopeLGiven) { + model->B1subthSlopeL = 0.0; + } + if( ! model->B1subthSlopeWGiven) { + model->B1subthSlopeW = 0.0; + } + if( ! model->B1subthSlopeB0Given) { + model->B1subthSlopeB0 = 0.0; + } + if( ! model->B1subthSlopeBLGiven) { + model->B1subthSlopeBL = 0.0; + } + if( ! model->B1subthSlopeBWGiven) { + model->B1subthSlopeBW = 0.0; + } + if( ! model->B1subthSlopeD0Given) { + model->B1subthSlopeD0 = 0.0; + } + if( ! model->B1subthSlopeDLGiven) { + model->B1subthSlopeDL = 0.0; + } + if( ! model->B1subthSlopeDWGiven) { + model->B1subthSlopeDW = 0.0; + } + if( ! model->B1sheetResistanceGiven) { + model->B1sheetResistance = 0.0; + } + if( ! model->B1unitAreaJctCapGiven) { + model->B1unitAreaJctCap = 0.0; + } + if( ! model->B1unitLengthSidewallJctCapGiven) { + model->B1unitLengthSidewallJctCap = 0.0; + } + if( ! model->B1jctSatCurDensityGiven) { + model->B1jctSatCurDensity = 0.0; + } + if( ! model->B1bulkJctPotentialGiven) { + model->B1bulkJctPotential = 0.0; + } + if( ! model->B1sidewallJctPotentialGiven) { + model->B1sidewallJctPotential = 0.0; + } + if( ! model->B1bulkJctBotGradingCoeffGiven) { + model->B1bulkJctBotGradingCoeff = 0.0; + } + if( ! model->B1bulkJctSideGradingCoeffGiven) { + model->B1bulkJctSideGradingCoeff = 0.0; + } + if( ! model->B1defaultWidthGiven) { + model->B1defaultWidth = 0.0; + } + if( ! model->B1deltaLengthGiven) { + model->B1deltaLength = 0.0; + } + + /* loop through all the instances of the model */ + for (here = model->B1instances; here != NULL ; + here=here->B1nextInstance) { + + if (here->B1owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->B1states = *states; + *states += B1numStates; + } + + /* perform the parameter defaulting */ + if(!here->B1drainAreaGiven) { + here->B1drainArea = 0; + } + if(!here->B1drainPerimeterGiven) { + here->B1drainPerimeter = 0; + } + if(!here->B1drainSquaresGiven) { + here->B1drainSquares = 1; + } + if(!here->B1icVBSGiven) { + here->B1icVBS = 0; + } + if(!here->B1icVDSGiven) { + here->B1icVDS = 0; + } + if(!here->B1icVGSGiven) { + here->B1icVGS = 0; + } + if(!here->B1lGiven) { + here->B1l = 5e-6; + } + if(!here->B1sourceAreaGiven) { + here->B1sourceArea = 0; + } + if(!here->B1sourcePerimeterGiven) { + here->B1sourcePerimeter = 0; + } + if(!here->B1sourceSquaresGiven) { + here->B1sourceSquares = 1; + } + if(!here->B1vdsatGiven) { + here->B1vdsat = 0; + } + if(!here->B1vonGiven) { + here->B1von = 0; + } + if(!here->B1wGiven) { + here->B1w = 5e-6; + } + + /* process drain series resistance */ + if( (model->B1sheetResistance != 0) && + (here->B1drainSquares != 0.0 ) && + (here->B1dNodePrime == 0) ) { + error = CKTmkVolt(ckt,&tmp,here->B1name,"drain"); + if(error) return(error); + here->B1dNodePrime = tmp->number; + } else { + here->B1dNodePrime = here->B1dNode; + } + + /* process source series resistance */ + if( (model->B1sheetResistance != 0) && + (here->B1sourceSquares != 0.0 ) && + (here->B1sNodePrime == 0) ) { + if(here->B1sNodePrime == 0) { + error = CKTmkVolt(ckt,&tmp,here->B1name,"source"); + if(error) return(error); + here->B1sNodePrime = tmp->number; + } + } else { + here->B1sNodePrime = here->B1sNode; + } + + /* set Sparse Matrix Pointers */ + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(B1DdPtr, B1dNode, B1dNode) + TSTALLOC(B1GgPtr, B1gNode, B1gNode) + TSTALLOC(B1SsPtr, B1sNode, B1sNode) + TSTALLOC(B1BbPtr, B1bNode, B1bNode) + TSTALLOC(B1DPdpPtr, B1dNodePrime, B1dNodePrime) + TSTALLOC(B1SPspPtr, B1sNodePrime, B1sNodePrime) + TSTALLOC(B1DdpPtr, B1dNode, B1dNodePrime) + TSTALLOC(B1GbPtr, B1gNode, B1bNode) + TSTALLOC(B1GdpPtr, B1gNode, B1dNodePrime) + TSTALLOC(B1GspPtr, B1gNode, B1sNodePrime) + TSTALLOC(B1SspPtr, B1sNode, B1sNodePrime) + TSTALLOC(B1BdpPtr, B1bNode, B1dNodePrime) + TSTALLOC(B1BspPtr, B1bNode, B1sNodePrime) + TSTALLOC(B1DPspPtr, B1dNodePrime, B1sNodePrime) + TSTALLOC(B1DPdPtr, B1dNodePrime, B1dNode) + TSTALLOC(B1BgPtr, B1bNode, B1gNode) + TSTALLOC(B1DPgPtr, B1dNodePrime, B1gNode) + TSTALLOC(B1SPgPtr, B1sNodePrime, B1gNode) + TSTALLOC(B1SPsPtr, B1sNodePrime, B1sNode) + TSTALLOC(B1DPbPtr, B1dNodePrime, B1bNode) + TSTALLOC(B1SPbPtr, B1sNodePrime, B1bNode) + TSTALLOC(B1SPdpPtr, B1sNodePrime, B1dNodePrime) + + } + } + return(OK); +} + +int +B1unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + B1model *model; + B1instance *here; + + for (model = (B1model *)inModel; model != NULL; + model = model->B1nextModel) + { + for (here = model->B1instances; here != NULL; + here=here->B1nextInstance) + { + if (here->B1dNodePrime + && here->B1dNodePrime != here->B1dNode) + { + CKTdltNNum(ckt, here->B1dNodePrime); + here->B1dNodePrime = 0; + } + if (here->B1sNodePrime + && here->B1sNodePrime != here->B1sNode) + { + CKTdltNNum(ckt, here->B1sNodePrime); + here->B1sNodePrime = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/bsim1/b1temp.c b/src/spicelib/devices/bsim1/b1temp.c new file mode 100644 index 000000000..1d3d74be2 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1temp.c @@ -0,0 +1,154 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim1def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +B1temp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* load the B1 device structure with those pointers needed later + * for fast matrix loading + */ + +{ + register B1model *model = (B1model*) inModel; + register B1instance *here; + double EffChanLength; + double EffChanWidth; + double Cox; + double CoxWoverL ; + double Leff; /* effective channel length im micron */ + double Weff; /* effective channel width in micron */ + + /* loop through all the B1 device models */ + for( ; model != NULL; model = model->B1nextModel ) { + +/* Default value Processing for B1 MOSFET Models */ + /* Some Limiting for Model Parameters */ + if( model->B1bulkJctPotential < 0.1) { + model->B1bulkJctPotential = 0.1; + } + if( model->B1sidewallJctPotential < 0.1) { + model->B1sidewallJctPotential = 0.1; + } + + Cox = 3.453e-13/(model->B1oxideThickness * 1.0e-4);/*in F/cm**2 */ + model->B1Cox = Cox; /* unit: F/cm**2 */ + + /* loop through all the instances of the model */ + for (here = model->B1instances; here != NULL ; + here=here->B1nextInstance) { + if (here->B1owner != ARCHme) continue; + + if( (EffChanLength = here->B1l - model->B1deltaL *1e-6 )<=0) { + IFuid namarray[2]; + namarray[0] = model->B1modName; + namarray[1] = here->B1name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "B1: mosfet %s, model %s: Effective channel length <=0", + namarray); + return(E_BADPARM); + } + if( (EffChanWidth = here->B1w - model->B1deltaW *1e-6 ) <= 0 ) { + IFuid namarray[2]; + namarray[0] = model->B1modName; + namarray[1] = here->B1name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "B1: mosfet %s, model %s: Effective channel width <=0", + namarray); + return(E_BADPARM); + } + here->B1GDoverlapCap=EffChanWidth *model->B1gateDrainOverlapCap; + here->B1GSoverlapCap=EffChanWidth*model->B1gateSourceOverlapCap; + here->B1GBoverlapCap=here->B1l * model->B1gateBulkOverlapCap; + + /* process drain series resistance */ + if( (here->B1drainConductance=model->B1sheetResistance * + here->B1drainSquares) != 0.0 ) { + here->B1drainConductance = 1. / here->B1drainConductance ; + } + + /* process source series resistance */ + if( (here->B1sourceConductance=model->B1sheetResistance * + here->B1sourceSquares) != 0.0 ) { + here->B1sourceConductance = 1. / here->B1sourceConductance ; + } + + Leff = EffChanLength * 1.e6; /* convert into micron */ + Weff = EffChanWidth * 1.e6; /* convert into micron */ + CoxWoverL = Cox * Weff / Leff ; /* F/cm**2 */ + + here->B1vfb = model->B1vfb0 + + model->B1vfbL / Leff + model->B1vfbW / Weff; + here->B1phi = model->B1phi0 + + model->B1phiL / Leff + model->B1phiW / Weff; + here->B1K1 = model->B1K10 + + model->B1K1L / Leff + model->B1K1W / Weff; + here->B1K2 = model->B1K20 + + model->B1K2L / Leff + model->B1K2W / Weff; + here->B1eta = model->B1eta0 + + model->B1etaL / Leff + model->B1etaW / Weff; + here->B1etaB = model->B1etaB0 + + model->B1etaBl / Leff + model->B1etaBw / Weff; + here->B1etaD = model->B1etaD0 + + model->B1etaDl / Leff + model->B1etaDw / Weff; + here->B1betaZero = model->B1mobZero; + here->B1betaZeroB = model->B1mobZeroB0 + + model->B1mobZeroBl / Leff + model->B1mobZeroBw / Weff; + here->B1ugs = model->B1ugs0 + + model->B1ugsL / Leff + model->B1ugsW / Weff; + here->B1ugsB = model->B1ugsB0 + + model->B1ugsBL / Leff + model->B1ugsBW / Weff; + here->B1uds = model->B1uds0 + + model->B1udsL / Leff + model->B1udsW / Weff; + here->B1udsB = model->B1udsB0 + + model->B1udsBL / Leff + model->B1udsBW / Weff; + here->B1udsD = model->B1udsD0 + + model->B1udsDL / Leff + model->B1udsDW / Weff; + here->B1betaVdd = model->B1mobVdd0 + + model->B1mobVddl / Leff + model->B1mobVddw / Weff; + here->B1betaVddB = model->B1mobVddB0 + + model->B1mobVddBl / Leff + model->B1mobVddBw / Weff; + here->B1betaVddD = model->B1mobVddD0 + + model->B1mobVddDl / Leff + model->B1mobVddDw / Weff; + here->B1subthSlope = model->B1subthSlope0 + + model->B1subthSlopeL / Leff + model->B1subthSlopeW / Weff; + here->B1subthSlopeB = model->B1subthSlopeB0 + + model->B1subthSlopeBL / Leff + model->B1subthSlopeBW / Weff; + here->B1subthSlopeD = model->B1subthSlopeD0 + + model->B1subthSlopeDL / Leff + model->B1subthSlopeDW / Weff; + + if(here->B1phi < 0.1 ) here->B1phi = 0.1; + if(here->B1K1 < 0.0) here->B1K1 = 0.0; + if(here->B1K2 < 0.0) here->B1K2 = 0.0; + + here->B1vt0 = here->B1vfb + here->B1phi + here->B1K1 * + sqrt(here->B1phi) - here->B1K2 * here->B1phi; + + here->B1von = here->B1vt0; /* added for initialization*/ + + /* process Beta Parameters (unit: A/V**2) */ + + here->B1betaZero = here->B1betaZero * CoxWoverL; + here->B1betaZeroB = here->B1betaZeroB * CoxWoverL; + here->B1betaVdd = here->B1betaVdd * CoxWoverL; + here->B1betaVddB = here->B1betaVddB * CoxWoverL; + here->B1betaVddD = MAX(here->B1betaVddD * CoxWoverL,0.0); + + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim1/b1trunc.c b/src/spicelib/devices/bsim1/b1trunc.c new file mode 100644 index 000000000..f67b63701 --- /dev/null +++ b/src/spicelib/devices/bsim1/b1trunc.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim1def.h" +#include "sperror.h" +#include "suffix.h" + +int +B1trunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register B1model *model = (B1model*)inModel; + register B1instance *here; +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + + for( ; model != NULL; model = model->B1nextModel) { + for(here=model->B1instances;here!=NULL;here = here->B1nextInstance){ + if (here->B1owner != ARCHme) continue; + +#ifdef STEPDEBUG + debugtemp = *timeStep; +#endif /* STEPDEBUG */ + CKTterr(here->B1qb,ckt,timeStep); + CKTterr(here->B1qg,ckt,timeStep); + CKTterr(here->B1qd,ckt,timeStep); +#ifdef STEPDEBUG + if(debugtemp != *timeStep) { + printf("device %s reduces step from %g to %g\n", + here->B1name,debugtemp,*timeStep); + } +#endif /* STEPDEBUG */ + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim1/bsim1def.h b/src/spicelib/devices/bsim1/bsim1def.h new file mode 100644 index 000000000..5177d3158 --- /dev/null +++ b/src/spicelib/devices/bsim1/bsim1def.h @@ -0,0 +1,628 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong June Park, Thomas L. Quarles +**********/ + +#ifndef BSIM1 +#define BSIM1 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" + + /* declarations for B1 MOSFETs */ + +#define B1numStates 35 +#define B1NDCOEFFS 82 + +/* information needed for each instance */ + +typedef struct sBSIM1instance { + struct sBSIM1model *B1modPtr; /* pointer to model */ + struct sBSIM1instance *B1nextInstance; /* pointer to next instance of + *current model*/ + IFuid B1name; /* pointer to character string naming this instance */ + int B1owner; /* number of owner process */ + int B1states; /* index into state table for this device */ + + int B1dNode; /* number of the gate node of the mosfet */ + int B1gNode; /* number of the gate node of the mosfet */ + int B1sNode; /* number of the source node of the mosfet */ + int B1bNode; /* number of the bulk node of the mosfet */ + int B1dNodePrime; /* number of the internal drain node of the mosfet */ + int B1sNodePrime; /* number of the internal source node of the mosfet */ + + double B1l; /* the length of the channel region */ + double B1w; /* the width of the channel region */ + double B1drainArea; /* the area of the drain diffusion */ + double B1sourceArea; /* the area of the source diffusion */ + double B1drainSquares; /* the length of the drain in squares */ + double B1sourceSquares; /* the length of the source in squares */ + double B1drainPerimeter; + double B1sourcePerimeter; + double B1sourceConductance; /*conductance of source(or 0):set in setup*/ + double B1drainConductance; /*conductance of drain(or 0):set in setup*/ + + double B1icVBS; /* initial condition B-S voltage */ + double B1icVDS; /* initial condition D-S voltage */ + double B1icVGS; /* initial condition G-S voltage */ + double B1von; + double B1vdsat; + int B1off; /* non-zero to indicate device is off for dc analysis*/ + int B1mode; /* device mode : 1 = normal, -1 = inverse */ + + double B1vfb; /* flat band voltage at given L and W */ + double B1phi; /* surface potential at strong inversion */ + double B1K1; /* bulk effect coefficient 1 */ + double B1K2; /* bulk effect coefficient 2 */ + double B1eta; /* drain induced barrier lowering */ + double B1etaB; /* Vbs dependence of Eta */ + double B1etaD; /* Vds dependence of Eta */ + double B1betaZero; /* Beta at vds = 0 and vgs = Vth */ + double B1betaZeroB; /* Vbs dependence of BetaZero */ + double B1betaVdd; /* Beta at vds=Vdd and vgs=Vth */ + double B1betaVddB; /* Vbs dependence of BVdd */ + double B1betaVddD; /* Vds dependence of BVdd */ + double B1ugs; /* Mobility degradation due to gate field*/ + double B1ugsB; /* Vbs dependence of Ugs */ + double B1uds; /* Drift Velocity Saturation due to Vds */ + double B1udsB; /* Vbs dependence of Uds */ + double B1udsD; /* Vds dependence of Uds */ + double B1subthSlope; /* slope of subthreshold current with Vgs*/ + double B1subthSlopeB; /* Vbs dependence of Subthreshold Slope */ + double B1subthSlopeD; /* Vds dependence of Subthreshold Slope */ + double B1GDoverlapCap;/* Gate Drain Overlap Capacitance */ + double B1GSoverlapCap;/* Gate Source Overlap Capacitance */ + double B1GBoverlapCap;/* Gate Bulk Overlap Capacitance */ + double B1vt0; + double B1vdd; /* Supply Voltage */ + double B1temp; + double B1oxideThickness; + unsigned B1channelChargePartitionFlag :1; + unsigned B1lGiven :1; + unsigned B1wGiven :1; + unsigned B1drainAreaGiven :1; + unsigned B1sourceAreaGiven :1; + unsigned B1drainSquaresGiven :1; + unsigned B1sourceSquaresGiven :1; + unsigned B1drainPerimeterGiven :1; + unsigned B1sourcePerimeterGiven :1; + unsigned B1dNodePrimeSet :1; + unsigned B1sNodePrimeSet :1; + unsigned B1icVBSGiven :1; + unsigned B1icVDSGiven :1; + unsigned B1icVGSGiven :1; + unsigned B1vonGiven :1; + unsigned B1vdsatGiven :1; + + + double *B1DdPtr; /* pointer to sparse matrix element at + * (Drain node,drain node) */ + double *B1GgPtr; /* pointer to sparse matrix element at + * (gate node,gate node) */ + double *B1SsPtr; /* pointer to sparse matrix element at + * (source node,source node) */ + double *B1BbPtr; /* pointer to sparse matrix element at + * (bulk node,bulk node) */ + double *B1DPdpPtr; /* pointer to sparse matrix element at + * (drain prime node,drain prime node) */ + double *B1SPspPtr; /* pointer to sparse matrix element at + * (source prime node,source prime node) */ + double *B1DdpPtr; /* pointer to sparse matrix element at + * (drain node,drain prime node) */ + double *B1GbPtr; /* pointer to sparse matrix element at + * (gate node,bulk node) */ + double *B1GdpPtr; /* pointer to sparse matrix element at + * (gate node,drain prime node) */ + double *B1GspPtr; /* pointer to sparse matrix element at + * (gate node,source prime node) */ + double *B1SspPtr; /* pointer to sparse matrix element at + * (source node,source prime node) */ + double *B1BdpPtr; /* pointer to sparse matrix element at + * (bulk node,drain prime node) */ + double *B1BspPtr; /* pointer to sparse matrix element at + * (bulk node,source prime node) */ + double *B1DPspPtr; /* pointer to sparse matrix element at + * (drain prime node,source prime node) */ + double *B1DPdPtr; /* pointer to sparse matrix element at + * (drain prime node,drain node) */ + double *B1BgPtr; /* pointer to sparse matrix element at + * (bulk node,gate node) */ + double *B1DPgPtr; /* pointer to sparse matrix element at + * (drain prime node,gate node) */ + + double *B1SPgPtr; /* pointer to sparse matrix element at + * (source prime node,gate node) */ + double *B1SPsPtr; /* pointer to sparse matrix element at + * (source prime node,source node) */ + double *B1DPbPtr; /* pointer to sparse matrix element at + * (drain prime node,bulk node) */ + double *B1SPbPtr; /* pointer to sparse matrix element at + * (source prime node,bulk node) */ + double *B1SPdpPtr; /* pointer to sparse matrix element at + * (source prime node,drain prime node) */ + +#ifndef NODISTO + double B1dCoeffs[B1NDCOEFFS]; +#else /* NODISTO */ + double *B1dCoeffs; +#endif /* NODISTO */ + +} B1instance ; + +#ifndef CONFIG + +#define B1vbd B1states+ 0 +#define B1vbs B1states+ 1 +#define B1vgs B1states+ 2 +#define B1vds B1states+ 3 +#define B1cd B1states+ 4 +#define B1id B1states+ 4 +#define B1cbs B1states+ 5 +#define B1ibs B1states+ 5 +#define B1cbd B1states+ 6 +#define B1ibd B1states+ 6 +#define B1gm B1states+ 7 +#define B1gds B1states+ 8 +#define B1gmbs B1states+ 9 +#define B1gbd B1states+ 10 +#define B1gbs B1states+ 11 +#define B1qb B1states+ 12 +#define B1cqb B1states+ 13 +#define B1iqb B1states+ 13 +#define B1qg B1states+ 14 +#define B1cqg B1states+ 15 +#define B1iqg B1states+ 15 +#define B1qd B1states+ 16 +#define B1cqd B1states+ 17 +#define B1iqd B1states+ 17 +#define B1cggb B1states+ 18 +#define B1cgdb B1states+ 19 +#define B1cgsb B1states+ 20 +#define B1cbgb B1states+ 21 +#define B1cbdb B1states+ 22 +#define B1cbsb B1states+ 23 +#define B1capbd B1states+ 24 +#define B1iqbd B1states+ 25 +#define B1cqbd B1states+ 25 +#define B1capbs B1states+ 26 +#define B1iqbs B1states+ 27 +#define B1cqbs B1states+ 27 +#define B1cdgb B1states+ 28 +#define B1cddb B1states+ 29 +#define B1cdsb B1states+ 30 +#define B1vono B1states+ 31 +#define B1vdsato B1states+ 32 +#define B1qbs B1states+ 33 +#define B1qbd B1states+ 34 + +/* + * the following naming convention is used: + * x = vgs + * y = vbs + * z = vds + * DrC is the DrCur + * therefore qg_xyz stands for the coefficient of the vgs*vbs*vds + * term in the multidimensional Taylor expansion for qg; and DrC_x2y + * for the coeff. of the vgs*vgs*vbs term in the DrC expansion. + */ + +#define qg_x B1dCoeffs[0] +#define qg_y B1dCoeffs[1] +#define qg_z B1dCoeffs[2] +#define qg_x2 B1dCoeffs[3] +#define qg_y2 B1dCoeffs[4] +#define qg_z2 B1dCoeffs[5] +#define qg_xy B1dCoeffs[6] +#define qg_yz B1dCoeffs[7] +#define qg_xz B1dCoeffs[8] +#define qg_x3 B1dCoeffs[9] +#define qg_y3 B1dCoeffs[10] +#define qg_z3 B1dCoeffs[11] +#define qg_x2z B1dCoeffs[12] +#define qg_x2y B1dCoeffs[13] +#define qg_y2z B1dCoeffs[14] +#define qg_xy2 B1dCoeffs[15] +#define qg_xz2 B1dCoeffs[16] +#define qg_yz2 B1dCoeffs[17] +#define qg_xyz B1dCoeffs[18] +#define qb_x B1dCoeffs[19] +#define qb_y B1dCoeffs[20] +#define qb_z B1dCoeffs[21] +#define qb_x2 B1dCoeffs[22] +#define qb_y2 B1dCoeffs[23] +#define qb_z2 B1dCoeffs[24] +#define qb_xy B1dCoeffs[25] +#define qb_yz B1dCoeffs[26] +#define qb_xz B1dCoeffs[27] +#define qb_x3 B1dCoeffs[28] +#define qb_y3 B1dCoeffs[29] +#define qb_z3 B1dCoeffs[30] +#define qb_x2z B1dCoeffs[31] +#define qb_x2y B1dCoeffs[32] +#define qb_y2z B1dCoeffs[33] +#define qb_xy2 B1dCoeffs[34] +#define qb_xz2 B1dCoeffs[35] +#define qb_yz2 B1dCoeffs[36] +#define qb_xyz B1dCoeffs[37] +#define qd_x B1dCoeffs[38] +#define qd_y B1dCoeffs[39] +#define qd_z B1dCoeffs[40] +#define qd_x2 B1dCoeffs[41] +#define qd_y2 B1dCoeffs[42] +#define qd_z2 B1dCoeffs[43] +#define qd_xy B1dCoeffs[44] +#define qd_yz B1dCoeffs[45] +#define qd_xz B1dCoeffs[46] +#define qd_x3 B1dCoeffs[47] +#define qd_y3 B1dCoeffs[48] +#define qd_z3 B1dCoeffs[49] +#define qd_x2z B1dCoeffs[50] +#define qd_x2y B1dCoeffs[51] +#define qd_y2z B1dCoeffs[52] +#define qd_xy2 B1dCoeffs[53] +#define qd_xz2 B1dCoeffs[54] +#define qd_yz2 B1dCoeffs[55] +#define qd_xyz B1dCoeffs[56] +#define DrC_x B1dCoeffs[57] +#define DrC_y B1dCoeffs[58] +#define DrC_z B1dCoeffs[59] +#define DrC_x2 B1dCoeffs[60] +#define DrC_y2 B1dCoeffs[61] +#define DrC_z2 B1dCoeffs[62] +#define DrC_xy B1dCoeffs[63] +#define DrC_yz B1dCoeffs[64] +#define DrC_xz B1dCoeffs[65] +#define DrC_x3 B1dCoeffs[66] +#define DrC_y3 B1dCoeffs[67] +#define DrC_z3 B1dCoeffs[68] +#define DrC_x2z B1dCoeffs[69] +#define DrC_x2y B1dCoeffs[70] +#define DrC_y2z B1dCoeffs[71] +#define DrC_xy2 B1dCoeffs[72] +#define DrC_xz2 B1dCoeffs[73] +#define DrC_yz2 B1dCoeffs[74] +#define DrC_xyz B1dCoeffs[75] +#define gbs1 B1dCoeffs[76] +#define gbs2 B1dCoeffs[77] +#define gbs3 B1dCoeffs[78] +#define gbd1 B1dCoeffs[79] +#define gbd2 B1dCoeffs[80] +#define gbd3 B1dCoeffs[81] + +#endif + + +/* per model data */ + +typedef struct sBSIM1model { /* model structure for a resistor */ + int B1modType; /* type index of this device type */ + struct sBSIM1model *B1nextModel; /* pointer to next possible model + *in linked list */ + B1instance * B1instances; /* pointer to list of instances + * that have this model */ + IFuid B1modName; /* pointer to character string naming this model */ + int B1type; /* device type : 1 = nmos, -1 = pmos */ + + double B1vfb0; + double B1vfbL; + double B1vfbW; + double B1phi0; + double B1phiL; + double B1phiW; + double B1K10; + double B1K1L; + double B1K1W; + double B1K20; + double B1K2L; + double B1K2W; + double B1eta0; + double B1etaL; + double B1etaW; + double B1etaB0; + double B1etaBl; + double B1etaBw; + double B1etaD0; + double B1etaDl; + double B1etaDw; + double B1deltaL; + double B1deltaW; + double B1mobZero; + double B1mobZeroB0; + double B1mobZeroBl; + double B1mobZeroBw ; + double B1mobVdd0; + double B1mobVddl; + double B1mobVddw; + double B1mobVddB0; + double B1mobVddBl; + double B1mobVddBw; + double B1mobVddD0; + double B1mobVddDl; + double B1mobVddDw; + double B1ugs0; + double B1ugsL; + double B1ugsW; + double B1ugsB0; + double B1ugsBL; + double B1ugsBW; + double B1uds0; + double B1udsL; + double B1udsW; + double B1udsB0; + double B1udsBL; + double B1udsBW; + double B1udsD0; + double B1udsDL; + double B1udsDW; + double B1subthSlope0; + double B1subthSlopeL; + double B1subthSlopeW; + double B1subthSlopeB0; + double B1subthSlopeBL; + double B1subthSlopeBW; + double B1subthSlopeD0; + double B1subthSlopeDL; + double B1subthSlopeDW; + double B1oxideThickness; /* unit: micron */ + double B1Cox; /* unit: F/cm**2 */ + double B1temp; + double B1vdd; + double B1gateSourceOverlapCap; + double B1gateDrainOverlapCap; + double B1gateBulkOverlapCap; + double B1channelChargePartitionFlag; + + double B1sheetResistance; + double B1jctSatCurDensity; + double B1bulkJctPotential; + double B1bulkJctBotGradingCoeff; + double B1bulkJctSideGradingCoeff; + double B1sidewallJctPotential; + double B1unitAreaJctCap; + double B1unitLengthSidewallJctCap; + double B1defaultWidth; + double B1deltaLength; + + + unsigned B1vfb0Given :1; + unsigned B1vfbLGiven :1; + unsigned B1vfbWGiven :1; + unsigned B1phi0Given :1; + unsigned B1phiLGiven :1; + unsigned B1phiWGiven :1; + unsigned B1K10Given :1; + unsigned B1K1LGiven :1; + unsigned B1K1WGiven :1; + unsigned B1K20Given :1; + unsigned B1K2LGiven :1; + unsigned B1K2WGiven :1; + unsigned B1eta0Given :1; + unsigned B1etaLGiven :1; + unsigned B1etaWGiven :1; + unsigned B1etaB0Given :1; + unsigned B1etaBlGiven :1; + unsigned B1etaBwGiven :1; + unsigned B1etaD0Given :1; + unsigned B1etaDlGiven :1; + unsigned B1etaDwGiven :1; + unsigned B1deltaLGiven :1; + unsigned B1deltaWGiven :1; + unsigned B1mobZeroGiven :1; + unsigned B1mobZeroB0Given :1; + unsigned B1mobZeroBlGiven :1; + unsigned B1mobZeroBwGiven :1; + unsigned B1mobVdd0Given :1; + unsigned B1mobVddlGiven :1; + unsigned B1mobVddwGiven :1; + unsigned B1mobVddB0Given :1; + unsigned B1mobVddBlGiven :1; + unsigned B1mobVddBwGiven :1; + unsigned B1mobVddD0Given :1; + unsigned B1mobVddDlGiven :1; + unsigned B1mobVddDwGiven :1; + unsigned B1ugs0Given :1; + unsigned B1ugsLGiven :1; + unsigned B1ugsWGiven :1; + unsigned B1ugsB0Given :1; + unsigned B1ugsBLGiven :1; + unsigned B1ugsBWGiven :1; + unsigned B1uds0Given :1; + unsigned B1udsLGiven :1; + unsigned B1udsWGiven :1; + unsigned B1udsB0Given :1; + unsigned B1udsBLGiven :1; + unsigned B1udsBWGiven :1; + unsigned B1udsD0Given :1; + unsigned B1udsDLGiven :1; + unsigned B1udsDWGiven :1; + unsigned B1subthSlope0Given :1; + unsigned B1subthSlopeLGiven :1; + unsigned B1subthSlopeWGiven :1; + unsigned B1subthSlopeB0Given :1; + unsigned B1subthSlopeBLGiven :1; + unsigned B1subthSlopeBWGiven :1; + unsigned B1subthSlopeD0Given :1; + unsigned B1subthSlopeDLGiven :1; + unsigned B1subthSlopeDWGiven :1; + unsigned B1oxideThicknessGiven :1; + unsigned B1tempGiven :1; + unsigned B1vddGiven :1; + unsigned B1gateSourceOverlapCapGiven :1; + unsigned B1gateDrainOverlapCapGiven :1; + unsigned B1gateBulkOverlapCapGiven :1; + unsigned B1channelChargePartitionFlagGiven :1; + unsigned B1sheetResistanceGiven :1; + unsigned B1jctSatCurDensityGiven :1; + unsigned B1bulkJctPotentialGiven :1; + unsigned B1bulkJctBotGradingCoeffGiven :1; + unsigned B1sidewallJctPotentialGiven :1; + unsigned B1bulkJctSideGradingCoeffGiven :1; + unsigned B1unitAreaJctCapGiven :1; + unsigned B1unitLengthSidewallJctCapGiven :1; + unsigned B1defaultWidthGiven :1; + unsigned B1deltaLengthGiven :1; + unsigned B1typeGiven :1; + +} B1model; + + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + + +/* device parameters */ +#define BSIM1_W 1 +#define BSIM1_L 2 +#define BSIM1_AS 3 +#define BSIM1_AD 4 +#define BSIM1_PS 5 +#define BSIM1_PD 6 +#define BSIM1_NRS 7 +#define BSIM1_NRD 8 +#define BSIM1_OFF 9 +#define BSIM1_IC_VBS 10 +#define BSIM1_IC_VDS 11 +#define BSIM1_IC_VGS 12 +#define BSIM1_IC 13 + +/* model parameters */ +#define BSIM1_MOD_VFB0 101 +#define BSIM1_MOD_VFBL 102 +#define BSIM1_MOD_VFBW 103 +#define BSIM1_MOD_PHI0 104 +#define BSIM1_MOD_PHIL 105 +#define BSIM1_MOD_PHIW 106 +#define BSIM1_MOD_K10 107 +#define BSIM1_MOD_K1L 108 +#define BSIM1_MOD_K1W 109 +#define BSIM1_MOD_K20 110 +#define BSIM1_MOD_K2L 111 +#define BSIM1_MOD_K2W 112 +#define BSIM1_MOD_ETA0 113 +#define BSIM1_MOD_ETAL 114 +#define BSIM1_MOD_ETAW 115 +#define BSIM1_MOD_ETAB0 116 +#define BSIM1_MOD_ETABL 117 +#define BSIM1_MOD_ETABW 118 +#define BSIM1_MOD_ETAD0 119 +#define BSIM1_MOD_ETADL 120 +#define BSIM1_MOD_ETADW 121 +#define BSIM1_MOD_DELTAL 122 +#define BSIM1_MOD_DELTAW 123 +#define BSIM1_MOD_MOBZERO 124 +#define BSIM1_MOD_MOBZEROB0 125 +#define BSIM1_MOD_MOBZEROBL 126 +#define BSIM1_MOD_MOBZEROBW 127 +#define BSIM1_MOD_MOBVDD0 128 +#define BSIM1_MOD_MOBVDDL 129 +#define BSIM1_MOD_MOBVDDW 130 +#define BSIM1_MOD_MOBVDDB0 131 +#define BSIM1_MOD_MOBVDDBL 132 +#define BSIM1_MOD_MOBVDDBW 133 +#define BSIM1_MOD_MOBVDDD0 134 +#define BSIM1_MOD_MOBVDDDL 135 +#define BSIM1_MOD_MOBVDDDW 136 +#define BSIM1_MOD_UGS0 137 +#define BSIM1_MOD_UGSL 138 +#define BSIM1_MOD_UGSW 139 +#define BSIM1_MOD_UGSB0 140 +#define BSIM1_MOD_UGSBL 141 +#define BSIM1_MOD_UGSBW 142 +#define BSIM1_MOD_UDS0 143 +#define BSIM1_MOD_UDSL 144 +#define BSIM1_MOD_UDSW 145 +#define BSIM1_MOD_UDSB0 146 +#define BSIM1_MOD_UDSBL 147 +#define BSIM1_MOD_UDSBW 148 +#define BSIM1_MOD_UDSD0 149 +#define BSIM1_MOD_UDSDL 150 +#define BSIM1_MOD_UDSDW 151 +#define BSIM1_MOD_N00 152 +#define BSIM1_MOD_N0L 153 +#define BSIM1_MOD_N0W 154 +#define BSIM1_MOD_NB0 155 +#define BSIM1_MOD_NBL 156 +#define BSIM1_MOD_NBW 157 +#define BSIM1_MOD_ND0 158 +#define BSIM1_MOD_NDL 159 +#define BSIM1_MOD_NDW 160 +#define BSIM1_MOD_TOX 161 +#define BSIM1_MOD_TEMP 162 +#define BSIM1_MOD_VDD 163 +#define BSIM1_MOD_CGSO 164 +#define BSIM1_MOD_CGDO 165 +#define BSIM1_MOD_CGBO 166 +#define BSIM1_MOD_XPART 167 +#define BSIM1_MOD_RSH 168 +#define BSIM1_MOD_JS 169 +#define BSIM1_MOD_PB 170 +#define BSIM1_MOD_MJ 171 +#define BSIM1_MOD_PBSW 172 +#define BSIM1_MOD_MJSW 173 +#define BSIM1_MOD_CJ 174 +#define BSIM1_MOD_CJSW 175 +#define BSIM1_MOD_DEFWIDTH 176 +#define BSIM1_MOD_DELLENGTH 177 +#define BSIM1_MOD_NMOS 178 +#define BSIM1_MOD_PMOS 179 + +/* device questions */ +#define BSIM1_DNODE 201 +#define BSIM1_GNODE 202 +#define BSIM1_SNODE 203 +#define BSIM1_BNODE 204 +#define BSIM1_DNODEPRIME 205 +#define BSIM1_SNODEPRIME 206 +#define BSIM1_VBD 207 +#define BSIM1_VBS 208 +#define BSIM1_VGS 209 +#define BSIM1_VDS 210 +#define BSIM1_CD 211 +#define BSIM1_CBS 212 +#define BSIM1_CBD 213 +#define BSIM1_GM 214 +#define BSIM1_GDS 215 +#define BSIM1_GMBS 216 +#define BSIM1_GBD 217 +#define BSIM1_GBS 218 +#define BSIM1_QB 219 +#define BSIM1_CQB 220 +#define BSIM1_QG 221 +#define BSIM1_CQG 222 +#define BSIM1_QD 223 +#define BSIM1_CQD 224 +#define BSIM1_CGG 225 +#define BSIM1_CGD 226 +#define BSIM1_CGS 227 +#define BSIM1_CBG 228 +#define BSIM1_CAPBD 231 +#define BSIM1_CQBD 232 +#define BSIM1_CAPBS 233 +#define BSIM1_CQBS 234 +#define BSIM1_CDG 235 +#define BSIM1_CDD 236 +#define BSIM1_CDS 237 +#define BSIM1_VON 238 +#define BSIM1_QBS 239 +#define BSIM1_QBD 240 +#define BSIM1_SOURCECONDUCT 241 +#define BSIM1_DRAINCONDUCT 242 + +/* model questions */ + +#include "bsim1ext.h" + +#ifdef __STDC__ +extern void B1evaluate(double,double,double,B1instance*,B1model*, + double*,double*,double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, CKTcircuit*); +#else /* stdc */ +extern void B1evaluate(); +#endif /* stdc */ + +#endif /*B1*/ diff --git a/src/spicelib/devices/bsim1/bsim1ext.h b/src/spicelib/devices/bsim1/bsim1ext.h new file mode 100644 index 000000000..97a13b41c --- /dev/null +++ b/src/spicelib/devices/bsim1/bsim1ext.h @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong June Park, Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int B1acLoad(GENmodel *,CKTcircuit*); +extern int B1ask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int B1convTest(GENmodel *,CKTcircuit*); +extern int B1delete(GENmodel*,IFuid,GENinstance**); +extern void B1destroy(GENmodel**); +extern int B1getic(GENmodel*,CKTcircuit*); +extern int B1load(GENmodel*,CKTcircuit*); +extern int B1mAsk(CKTcircuit*,GENmodel *,int, IFvalue*); +extern int B1mDelete(GENmodel**,IFuid,GENmodel*); +extern int B1mParam(int,IFvalue*,GENmodel*); +extern void B1mosCap(CKTcircuit*, double, double, double, double*, + double, double, double, double, double, double, + double*, double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*); +extern int B1param(int,IFvalue*,GENinstance*,IFvalue*); +extern int B1pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int B1setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int B1unsetup(GENmodel*,CKTcircuit*); +extern int B1temp(GENmodel*,CKTcircuit*); +extern int B1trunc(GENmodel*,CKTcircuit*,double*); +extern int B1disto(int,GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int B1acLoad(); +extern int B1ask(); +extern int B1convTest(); +extern int B1delete(); +extern void B1destroy(); +extern int B1getic(); +extern int B1load(); +extern int B1mAsk(); +extern int B1mDelete(); +extern int B1mParam(); +extern void B1mosCap(); +extern int B1param(); +extern int B1pzLoad(); +extern int B1setup(); +extern int B1unsetup(); +extern int B1temp(); +extern int B1trunc(); +extern int B1disto(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/bsim1/bsim1itf.h b/src/spicelib/devices/bsim1/bsim1itf.h new file mode 100644 index 000000000..8f9bed9f9 --- /dev/null +++ b/src/spicelib/devices/bsim1/bsim1itf.h @@ -0,0 +1,86 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_bsim1 + +#ifndef DEV_BSIM1 +#define DEV_BSIM1 + +#include "bsim1ext.h" +extern IFparm B1pTable[ ]; +extern IFparm B1mPTable[ ]; +extern char *B1names[ ]; +extern int B1pTSize; +extern int B1mPTSize; +extern int B1nSize; +extern int B1iSize; +extern int B1mSize; + +SPICEdev B1info = { + { "BSIM1", + "Berkeley Short Channel IGFET Model", + + &B1nSize, + &B1nSize, + B1names, + + &B1pTSize, + B1pTable, + + &B1mPTSize, + B1mPTable, + DEV_DEFAULT + }, + + B1param, + B1mParam, + B1load, + B1setup, + B1unsetup, + B1setup, + B1temp, + B1trunc, + NULL, + B1acLoad, + NULL, + B1destroy, +#ifdef DELETES + B1mDelete, + B1delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + B1getic, + B1ask, + B1mAsk, +#ifdef AN_pz + B1pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + B1convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#ifdef AN_disto + B1disto, +#else + NULL, +#endif + NULL, /* NOISE */ + + &B1iSize, + &B1mSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/bsim2/ChangeLog b/src/spicelib/devices/bsim2/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/bsim2/Makefile.am b/src/spicelib/devices/bsim2/Makefile.am new file mode 100644 index 000000000..c1c39d0d1 --- /dev/null +++ b/src/spicelib/devices/bsim2/Makefile.am @@ -0,0 +1,32 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libbsim2.la + +libbsim2_la_SOURCES = \ + b2.c \ + b2acld.c \ + b2ask.c \ + b2cvtest.c \ + b2del.c \ + b2dest.c \ + b2eval.c \ + b2getic.c \ + b2ld.c \ + b2mask.c \ + b2mdel.c \ + b2moscap.c \ + b2mpar.c \ + b2par.c \ + b2pzld.c \ + b2set.c \ + b2temp.c \ + b2trunc.c \ + bsim2def.h \ + bsim2ext.h \ + bsim2itf.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/bsim2/b2.c b/src/spicelib/devices/bsim2/b2.c new file mode 100644 index 000000000..2db8b1906 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2.c @@ -0,0 +1,212 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Min-Chie Jeng, Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "bsim2def.h" +#include "suffix.h" + +IFparm B2pTable[] = { /* parameters */ + IOP( "l", BSIM2_L, IF_REAL , "Length"), + IOP( "w", BSIM2_W, IF_REAL , "Width"), + IOP( "ad", BSIM2_AD, IF_REAL , "Drain area"), + IOP( "as", BSIM2_AS, IF_REAL , "Source area"), + IOP( "pd", BSIM2_PD, IF_REAL , "Drain perimeter"), + IOP( "ps", BSIM2_PS, IF_REAL , "Source perimeter"), + IOP( "nrd", BSIM2_NRD, IF_REAL , "Number of squares in drain"), + IOP( "nrs", BSIM2_NRS, IF_REAL , "Number of squares in source"), + IOP( "off", BSIM2_OFF, IF_FLAG , "Device is initially off"), + IOP( "vds", BSIM2_IC_VDS, IF_REAL , "Initial D-S voltage"), + IOP( "vgs", BSIM2_IC_VGS, IF_REAL , "Initial G-S voltage"), + IOP( "vbs", BSIM2_IC_VBS, IF_REAL , "Initial B-S voltage"), + IP( "ic", BSIM2_IC, IF_VECTOR , "Vector of DS,GS,BS initial voltages") +}; + +IFparm B2mPTable[] = { /* model parameters */ + IOP( "vfb", BSIM2_MOD_VFB0, IF_REAL,"Flat band voltage"), + IOP( "lvfb", BSIM2_MOD_VFBL, IF_REAL, "Length dependence of vfb"), + IOP( "wvfb", BSIM2_MOD_VFBW, IF_REAL, "Width dependence of vfb"), + IOP( "phi", BSIM2_MOD_PHI0, IF_REAL, + "Strong inversion surface potential "), + IOP( "lphi", BSIM2_MOD_PHIL, IF_REAL, "Length dependence of phi"), + IOP( "wphi", BSIM2_MOD_PHIW, IF_REAL, "Width dependence of phi"), + IOP( "k1", BSIM2_MOD_K10, IF_REAL, "Bulk effect coefficient 1"), + IOP( "lk1", BSIM2_MOD_K1L, IF_REAL, "Length dependence of k1"), + IOP( "wk1", BSIM2_MOD_K1W, IF_REAL, "Width dependence of k1"), + IOP( "k2", BSIM2_MOD_K20, IF_REAL, "Bulk effect coefficient 2"), + IOP( "lk2", BSIM2_MOD_K2L, IF_REAL, "Length dependence of k2"), + IOP( "wk2", BSIM2_MOD_K2W, IF_REAL, "Width dependence of k2"), + IOP( "eta0", BSIM2_MOD_ETA00, IF_REAL, + "VDS dependence of threshold voltage at VDD=0"), + IOP( "leta0", BSIM2_MOD_ETA0L, IF_REAL, "Length dependence of eta0"), + IOP( "weta0", BSIM2_MOD_ETA0W, IF_REAL, "Width dependence of eta0"), + IOP( "etab", BSIM2_MOD_ETAB0, IF_REAL, "VBS dependence of eta"), + IOP( "letab", BSIM2_MOD_ETABL, IF_REAL, "Length dependence of etab"), + IOP( "wetab", BSIM2_MOD_ETABW, IF_REAL, "Width dependence of etab"), + IOP( "dl", BSIM2_MOD_DELTAL, IF_REAL, "Channel length reduction in um"), + IOP( "dw", BSIM2_MOD_DELTAW, IF_REAL, "Channel width reduction in um"), + IOP( "mu0", BSIM2_MOD_MOB00, IF_REAL, + "Low-field mobility, at VDS=0 VGS=VTH"), + IOP( "mu0b", BSIM2_MOD_MOB0B0, IF_REAL, + "VBS dependence of low-field mobility"), + IOP( "lmu0b", BSIM2_MOD_MOB0BL, IF_REAL, "Length dependence of mu0b"), + IOP( "wmu0b", BSIM2_MOD_MOB0BW, IF_REAL, "Width dependence of mu0b"), + IOP( "mus0", BSIM2_MOD_MOBS00, IF_REAL, "Mobility at VDS=VDD VGS=VTH"), + IOP( "lmus0", BSIM2_MOD_MOBS0L, IF_REAL, "Length dependence of mus0"), + IOP( "wmus0", BSIM2_MOD_MOBS0W, IF_REAL, "Width dependence of mus"), + IOP( "musb", BSIM2_MOD_MOBSB0, IF_REAL, "VBS dependence of mus"), + IOP( "lmusb", BSIM2_MOD_MOBSBL, IF_REAL, "Length dependence of musb"), + IOP( "wmusb", BSIM2_MOD_MOBSBW, IF_REAL, "Width dependence of musb"), + IOP( "mu20", BSIM2_MOD_MOB200, IF_REAL, + "VDS dependence of mu in tanh term"), + IOP( "lmu20", BSIM2_MOD_MOB20L, IF_REAL, "Length dependence of mu20"), + IOP( "wmu20", BSIM2_MOD_MOB20W, IF_REAL, "Width dependence of mu20"), + IOP( "mu2b", BSIM2_MOD_MOB2B0, IF_REAL, "VBS dependence of mu2"), + IOP( "lmu2b", BSIM2_MOD_MOB2BL, IF_REAL, "Length dependence of mu2b"), + IOP( "wmu2b", BSIM2_MOD_MOB2BW, IF_REAL, "Width dependence of mu2b"), + IOP( "mu2g", BSIM2_MOD_MOB2G0, IF_REAL, "VGS dependence of mu2"), + IOP( "lmu2g", BSIM2_MOD_MOB2GL, IF_REAL, "Length dependence of mu2g"), + IOP( "wmu2g", BSIM2_MOD_MOB2GW, IF_REAL, "Width dependence of mu2g"), + IOP( "mu30", BSIM2_MOD_MOB300, IF_REAL, + "VDS dependence of mu in linear term"), + IOP( "lmu30", BSIM2_MOD_MOB30L, IF_REAL, "Length dependence of mu30"), + IOP( "wmu30", BSIM2_MOD_MOB30W, IF_REAL, "Width dependence of mu30"), + IOP( "mu3b", BSIM2_MOD_MOB3B0, IF_REAL, "VBS dependence of mu3"), + IOP( "lmu3b", BSIM2_MOD_MOB3BL, IF_REAL, "Length dependence of mu3b"), + IOP( "wmu3b", BSIM2_MOD_MOB3BW, IF_REAL, "Width dependence of mu3b"), + IOP( "mu3g", BSIM2_MOD_MOB3G0, IF_REAL, "VGS dependence of mu3"), + IOP( "lmu3g", BSIM2_MOD_MOB3GL, IF_REAL, "Length dependence of mu3g"), + IOP( "wmu3g", BSIM2_MOD_MOB3GW, IF_REAL, "Width dependence of mu3g"), + IOP( "mu40", BSIM2_MOD_MOB400, IF_REAL, + "VDS dependence of mu in linear term"), + IOP( "lmu40", BSIM2_MOD_MOB40L, IF_REAL, "Length dependence of mu40"), + IOP( "wmu40", BSIM2_MOD_MOB40W, IF_REAL, "Width dependence of mu40"), + IOP( "mu4b", BSIM2_MOD_MOB4B0, IF_REAL, "VBS dependence of mu4"), + IOP( "lmu4b", BSIM2_MOD_MOB4BL, IF_REAL, "Length dependence of mu4b"), + IOP( "wmu4b", BSIM2_MOD_MOB4BW, IF_REAL, "Width dependence of mu4b"), + IOP( "mu4g", BSIM2_MOD_MOB4G0, IF_REAL, "VGS dependence of mu4"), + IOP( "lmu4g", BSIM2_MOD_MOB4GL, IF_REAL, "Length dependence of mu4g"), + IOP( "wmu4g", BSIM2_MOD_MOB4GW, IF_REAL, "Width dependence of mu4g"), + IOP( "ua0", BSIM2_MOD_UA00, IF_REAL, + "Linear VGS dependence of mobility"), + IOP( "lua0", BSIM2_MOD_UA0L, IF_REAL, "Length dependence of ua0"), + IOP( "wua0", BSIM2_MOD_UA0W, IF_REAL, "Width dependence of ua0"), + IOP( "uab", BSIM2_MOD_UAB0, IF_REAL, "VBS dependence of ua"), + IOP( "luab", BSIM2_MOD_UABL, IF_REAL, "Length dependence of uab"), + IOP( "wuab", BSIM2_MOD_UABW, IF_REAL, "Width dependence of uab"), + IOP( "ub0", BSIM2_MOD_UB00, IF_REAL, + "Quadratic VGS dependence of mobility"), + IOP( "lub0", BSIM2_MOD_UB0L, IF_REAL, "Length dependence of ub0"), + IOP( "wub0", BSIM2_MOD_UB0W, IF_REAL, "Width dependence of ub0"), + IOP( "ubb", BSIM2_MOD_UBB0, IF_REAL, "VBS dependence of ub"), + IOP( "lubb", BSIM2_MOD_UBBL, IF_REAL, "Length dependence of ubb"), + IOP( "wubb", BSIM2_MOD_UBBW, IF_REAL, "Width dependence of ubb"), + IOP( "u10", BSIM2_MOD_U100, IF_REAL, "VDS depence of mobility"), + IOP( "lu10", BSIM2_MOD_U10L, IF_REAL, "Length dependence of u10"), + IOP( "wu10", BSIM2_MOD_U10W, IF_REAL, "Width dependence of u10"), + IOP( "u1b", BSIM2_MOD_U1B0, IF_REAL, "VBS depence of u1"), + IOP( "lu1b", BSIM2_MOD_U1BL, IF_REAL, "Length depence of u1b"), + IOP( "wu1b", BSIM2_MOD_U1BW, IF_REAL, "Width depence of u1b"), + IOP( "u1d", BSIM2_MOD_U1D0, IF_REAL, "VDS depence of u1"), + IOP( "lu1d", BSIM2_MOD_U1DL, IF_REAL, "Length depence of u1d"), + IOP( "wu1d", BSIM2_MOD_U1DW, IF_REAL, "Width depence of u1d"), + IOP( "n0", BSIM2_MOD_N00, IF_REAL, + "Subthreshold slope at VDS=0 VBS=0"), + IOP( "ln0", BSIM2_MOD_N0L, IF_REAL, "Length dependence of n0"), + IOP( "wn0", BSIM2_MOD_N0W, IF_REAL, "Width dependence of n0"), + IOP( "nb", BSIM2_MOD_NB0, IF_REAL, "VBS dependence of n"), + IOP( "lnb", BSIM2_MOD_NBL, IF_REAL, "Length dependence of nb"), + IOP( "wnb", BSIM2_MOD_NBW, IF_REAL, "Width dependence of nb"), + IOP( "nd", BSIM2_MOD_ND0, IF_REAL, "VDS dependence of n"), + IOP( "lnd", BSIM2_MOD_NDL, IF_REAL, "Length dependence of nd"), + IOP( "wnd", BSIM2_MOD_NDW, IF_REAL, "Width dependence of nd"), + IOP( "vof0", BSIM2_MOD_VOF00, IF_REAL, + "Threshold voltage offset AT VDS=0 VBS=0"), + IOP( "lvof0", BSIM2_MOD_VOF0L, IF_REAL, "Length dependence of vof0"), + IOP( "wvof0", BSIM2_MOD_VOF0W, IF_REAL, "Width dependence of vof0"), + IOP( "vofb", BSIM2_MOD_VOFB0, IF_REAL, "VBS dependence of vof"), + IOP( "lvofb", BSIM2_MOD_VOFBL, IF_REAL, "Length dependence of vofb"), + IOP( "wvofb", BSIM2_MOD_VOFBW, IF_REAL, "Width dependence of vofb"), + IOP( "vofd", BSIM2_MOD_VOFD0, IF_REAL, "VDS dependence of vof"), + IOP( "lvofd", BSIM2_MOD_VOFDL, IF_REAL, "Length dependence of vofd"), + IOP( "wvofd", BSIM2_MOD_VOFDW, IF_REAL, "Width dependence of vofd"), + IOP( "ai0", BSIM2_MOD_AI00, IF_REAL, + "Pre-factor of hot-electron effect."), + IOP( "lai0", BSIM2_MOD_AI0L, IF_REAL, "Length dependence of ai0"), + IOP( "wai0", BSIM2_MOD_AI0W, IF_REAL, "Width dependence of ai0"), + IOP( "aib", BSIM2_MOD_AIB0, IF_REAL, "VBS dependence of ai"), + IOP( "laib", BSIM2_MOD_AIBL, IF_REAL, "Length dependence of aib"), + IOP( "waib", BSIM2_MOD_AIBW, IF_REAL, "Width dependence of aib"), + IOP( "bi0", BSIM2_MOD_BI00, IF_REAL, + "Exponential factor of hot-electron effect."), + IOP( "lbi0", BSIM2_MOD_BI0L, IF_REAL, "Length dependence of bi0"), + IOP( "wbi0", BSIM2_MOD_BI0W, IF_REAL, "Width dependence of bi0"), + IOP( "bib", BSIM2_MOD_BIB0, IF_REAL, "VBS dependence of bi"), + IOP( "lbib", BSIM2_MOD_BIBL, IF_REAL, "Length dependence of bib"), + IOP( "wbib", BSIM2_MOD_BIBW, IF_REAL, "Width dependence of bib"), + IOP( "vghigh", BSIM2_MOD_VGHIGH0, IF_REAL, + "Upper bound of the cubic spline function."), + IOP( "lvghigh", BSIM2_MOD_VGHIGHL, IF_REAL, + "Length dependence of vghigh"), + IOP( "wvghigh", BSIM2_MOD_VGHIGHW, IF_REAL, + "Width dependence of vghigh"), + IOP( "vglow", BSIM2_MOD_VGLOW0, IF_REAL, + "Lower bound of the cubic spline function."), + IOP( "lvglow", BSIM2_MOD_VGLOWL, IF_REAL, + "Length dependence of vglow"), + IOP( "wvglow", BSIM2_MOD_VGLOWW, IF_REAL, + "Width dependence of vglow"), + IOP( "tox", BSIM2_MOD_TOX, IF_REAL, "Gate oxide thickness in um"), + IOP( "temp", BSIM2_MOD_TEMP, IF_REAL, "Temperature in degree Celcius"), + IOP( "vdd", BSIM2_MOD_VDD, IF_REAL, "Maximum Vds "), + IOP( "vgg", BSIM2_MOD_VGG, IF_REAL, "Maximum Vgs "), + IOP( "vbb", BSIM2_MOD_VBB, IF_REAL, "Maximum Vbs "), + IOPA( "cgso", BSIM2_MOD_CGSO, IF_REAL, + "Gate source overlap capacitance per unit channel width(m)"), + IOPA( "cgdo", BSIM2_MOD_CGDO, IF_REAL, + "Gate drain overlap capacitance per unit channel width(m)"), + IOPA( "cgbo", BSIM2_MOD_CGBO, IF_REAL, + "Gate bulk overlap capacitance per unit channel length(m)"), + IOP( "xpart", BSIM2_MOD_XPART, IF_REAL, + "Flag for channel charge partitioning"), + IOP( "rsh", BSIM2_MOD_RSH, IF_REAL, + "Source drain diffusion sheet resistance in ohm per square"), + IOP( "js", BSIM2_MOD_JS, IF_REAL, + "Source drain junction saturation current per unit area"), + IOP( "pb", BSIM2_MOD_PB, IF_REAL, + "Source drain junction built in potential"), + IOPA( "mj", BSIM2_MOD_MJ, IF_REAL, + "Source drain bottom junction capacitance grading coefficient"), + IOPA( "pbsw", BSIM2_MOD_PBSW, IF_REAL, + "Source drain side junction capacitance built in potential"), + IOPA( "mjsw", BSIM2_MOD_MJSW, IF_REAL, + "Source drain side junction capacitance grading coefficient"), + IOPA( "cj", BSIM2_MOD_CJ, IF_REAL, + "Source drain bottom junction capacitance per unit area"), + IOPA( "cjsw", BSIM2_MOD_CJSW, IF_REAL, + "Source drain side junction capacitance per unit area"), + IOP( "wdf", BSIM2_MOD_DEFWIDTH, IF_REAL, + "Default width of source drain diffusion in um"), + IOP( "dell", BSIM2_MOD_DELLENGTH, IF_REAL, + "Length reduction of source drain diffusion"), + IP( "nmos", BSIM2_MOD_NMOS, IF_FLAG, + "Flag to indicate NMOS"), + IP( "pmos", BSIM2_MOD_PMOS, IF_FLAG, + "Flag to indicate PMOS"), +}; + +char *B2names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int B2nSize = NUMELEMS(B2names); +int B2pTSize = NUMELEMS(B2pTable); +int B2mPTSize = NUMELEMS(B2mPTable); +int B2iSize = sizeof(B2instance); +int B2mSize = sizeof(B2model); diff --git a/src/spicelib/devices/bsim2/b2acld.c b/src/spicelib/devices/bsim2/b2acld.c new file mode 100644 index 000000000..5ba9bc679 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2acld.c @@ -0,0 +1,153 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim2def.h" +#include "sperror.h" +#include "suffix.h" + + +int +B2acLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register B2model *model = (B2model*)inModel; + register B2instance *here; + int xnrm; + int xrev; + double gdpr; + double gspr; + double gm; + double gds; + double gmbs; + double gbd; + double gbs; + double capbd; + double capbs; + double xcggb; + double xcgdb; + double xcgsb; + double xcbgb; + double xcbdb; + double xcbsb; + double xcddb; + double xcssb; + double xcdgb; + double xcsgb; + double xcdsb; + double xcsdb; + double cggb; + double cgdb; + double cgsb; + double cbgb; + double cbdb; + double cbsb; + double cddb; + double cdgb; + double cdsb; + double omega; /* angular fequency of the signal */ + + omega = ckt->CKTomega; + for( ; model != NULL; model = model->B2nextModel) { + for(here = model->B2instances; here!= NULL; + here = here->B2nextInstance) { + if (here->B2owner != ARCHme) continue; + + if (here->B2mode >= 0) { + xnrm=1; + xrev=0; + } else { + xnrm=0; + xrev=1; + } + gdpr=here->B2drainConductance; + gspr=here->B2sourceConductance; + gm= *(ckt->CKTstate0 + here->B2gm); + gds= *(ckt->CKTstate0 + here->B2gds); + gmbs= *(ckt->CKTstate0 + here->B2gmbs); + gbd= *(ckt->CKTstate0 + here->B2gbd); + gbs= *(ckt->CKTstate0 + here->B2gbs); + capbd= *(ckt->CKTstate0 + here->B2capbd); + capbs= *(ckt->CKTstate0 + here->B2capbs); + /* + * charge oriented model parameters + */ + + cggb = *(ckt->CKTstate0 + here->B2cggb); + cgsb = *(ckt->CKTstate0 + here->B2cgsb); + cgdb = *(ckt->CKTstate0 + here->B2cgdb); + + cbgb = *(ckt->CKTstate0 + here->B2cbgb); + cbsb = *(ckt->CKTstate0 + here->B2cbsb); + cbdb = *(ckt->CKTstate0 + here->B2cbdb); + + cdgb = *(ckt->CKTstate0 + here->B2cdgb); + cdsb = *(ckt->CKTstate0 + here->B2cdsb); + cddb = *(ckt->CKTstate0 + here->B2cddb); + + xcdgb = (cdgb - here->pParam->B2GDoverlapCap) * omega; + xcddb = (cddb + capbd + here->pParam->B2GDoverlapCap) * omega; + xcdsb = cdsb * omega; + xcsgb = -(cggb + cbgb + cdgb + here->pParam->B2GSoverlapCap) + * omega; + xcsdb = -(cgdb + cbdb + cddb) * omega; + xcssb = (capbs + here->pParam->B2GSoverlapCap + - (cgsb+cbsb+cdsb)) * omega; + xcggb = (cggb + here->pParam->B2GDoverlapCap + + here->pParam->B2GSoverlapCap + + here->pParam->B2GBoverlapCap) * omega; + xcgdb = (cgdb - here->pParam->B2GDoverlapCap ) * omega; + xcgsb = (cgsb - here->pParam->B2GSoverlapCap) * omega; + xcbgb = (cbgb - here->pParam->B2GBoverlapCap) * omega; + xcbdb = (cbdb - capbd ) * omega; + xcbsb = (cbsb - capbs ) * omega; + + + *(here->B2GgPtr +1) += xcggb; + *(here->B2BbPtr +1) += -xcbgb-xcbdb-xcbsb; + *(here->B2DPdpPtr +1) += xcddb; + *(here->B2SPspPtr +1) += xcssb; + *(here->B2GbPtr +1) += -xcggb-xcgdb-xcgsb; + *(here->B2GdpPtr +1) += xcgdb; + *(here->B2GspPtr +1) += xcgsb; + *(here->B2BgPtr +1) += xcbgb; + *(here->B2BdpPtr +1) += xcbdb; + *(here->B2BspPtr +1) += xcbsb; + *(here->B2DPgPtr +1) += xcdgb; + *(here->B2DPbPtr +1) += -xcdgb-xcddb-xcdsb; + *(here->B2DPspPtr +1) += xcdsb; + *(here->B2SPgPtr +1) += xcsgb; + *(here->B2SPbPtr +1) += -xcsgb-xcsdb-xcssb; + *(here->B2SPdpPtr +1) += xcsdb; + *(here->B2DdPtr) += gdpr; + *(here->B2SsPtr) += gspr; + *(here->B2BbPtr) += gbd+gbs; + *(here->B2DPdpPtr) += gdpr+gds+gbd+xrev*(gm+gmbs); + *(here->B2SPspPtr) += gspr+gds+gbs+xnrm*(gm+gmbs); + *(here->B2DdpPtr) -= gdpr; + *(here->B2SspPtr) -= gspr; + *(here->B2BdpPtr) -= gbd; + *(here->B2BspPtr) -= gbs; + *(here->B2DPdPtr) -= gdpr; + *(here->B2DPgPtr) += (xnrm-xrev)*gm; + *(here->B2DPbPtr) += -gbd+(xnrm-xrev)*gmbs; + *(here->B2DPspPtr) += -gds-xnrm*(gm+gmbs); + *(here->B2SPgPtr) += -(xnrm-xrev)*gm; + *(here->B2SPsPtr) -= gspr; + *(here->B2SPbPtr) += -gbs-(xnrm-xrev)*gmbs; + *(here->B2SPdpPtr) += -gds-xrev*(gm+gmbs); + + } + } +return(OK); +} + + + diff --git a/src/spicelib/devices/bsim2/b2ask.c b/src/spicelib/devices/bsim2/b2ask.c new file mode 100644 index 000000000..3b36a5c74 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2ask.c @@ -0,0 +1,189 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Hong J. Park +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim2def.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +B2ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + B2instance *here = (B2instance*)inst; + + switch(which) { + case BSIM2_L: + value->rValue = here->B2l; + return(OK); + case BSIM2_W: + value->rValue = here->B2w; + return(OK); + case BSIM2_AS: + value->rValue = here->B2sourceArea; + return(OK); + case BSIM2_AD: + value->rValue = here->B2drainArea; + return(OK); + case BSIM2_PS: + value->rValue = here->B2sourcePerimeter; + return(OK); + case BSIM2_PD: + value->rValue = here->B2drainPerimeter; + return(OK); + case BSIM2_NRS: + value->rValue = here->B2sourceSquares; + return(OK); + case BSIM2_NRD: + value->rValue = here->B2drainSquares; + return(OK); + case BSIM2_OFF: + value->rValue = here->B2off; + return(OK); + case BSIM2_IC_VBS: + value->rValue = here->B2icVBS; + return(OK); + case BSIM2_IC_VDS: + value->rValue = here->B2icVDS; + return(OK); + case BSIM2_IC_VGS: + value->rValue = here->B2icVGS; + return(OK); + case BSIM2_DNODE: + value->iValue = here->B2dNode; + return(OK); + case BSIM2_GNODE: + value->iValue = here->B2gNode; + return(OK); + case BSIM2_SNODE: + value->iValue = here->B2sNode; + return(OK); + case BSIM2_BNODE: + value->iValue = here->B2bNode; + return(OK); + case BSIM2_DNODEPRIME: + value->iValue = here->B2dNodePrime; + return(OK); + case BSIM2_SNODEPRIME: + value->iValue = here->B2sNodePrime; + return(OK); + case BSIM2_SOURCECONDUCT: + value->rValue = here->B2sourceConductance; + return(OK); + case BSIM2_DRAINCONDUCT: + value->rValue = here->B2drainConductance; + return(OK); + case BSIM2_VBD: + value->rValue = *(ckt->CKTstate0 + here->B2vbd); + return(OK); + case BSIM2_VBS: + value->rValue = *(ckt->CKTstate0 + here->B2vbs); + return(OK); + case BSIM2_VGS: + value->rValue = *(ckt->CKTstate0 + here->B2vgs); + return(OK); + case BSIM2_VDS: + value->rValue = *(ckt->CKTstate0 + here->B2vds); + return(OK); + case BSIM2_CD: + value->rValue = *(ckt->CKTstate0 + here->B2cd); + return(OK); + case BSIM2_CBS: + value->rValue = *(ckt->CKTstate0 + here->B2cbs); + return(OK); + case BSIM2_CBD: + value->rValue = *(ckt->CKTstate0 + here->B2cbd); + return(OK); + case BSIM2_GM: + value->rValue = *(ckt->CKTstate0 + here->B2gm); + return(OK); + case BSIM2_GDS: + value->rValue = *(ckt->CKTstate0 + here->B2gds); + return(OK); + case BSIM2_GMBS: + value->rValue = *(ckt->CKTstate0 + here->B2gmbs); + return(OK); + case BSIM2_GBD: + value->rValue = *(ckt->CKTstate0 + here->B2gbd); + return(OK); + case BSIM2_GBS: + value->rValue = *(ckt->CKTstate0 + here->B2gbs); + return(OK); + case BSIM2_QB: + value->rValue = *(ckt->CKTstate0 + here->B2qb); + return(OK); + case BSIM2_CQB: + value->rValue = *(ckt->CKTstate0 + here->B2cqb); + return(OK); + case BSIM2_QG: + value->rValue = *(ckt->CKTstate0 + here->B2qg); + return(OK); + case BSIM2_CQG: + value->rValue = *(ckt->CKTstate0 + here->B2cqg); + return(OK); + case BSIM2_QD: + value->rValue = *(ckt->CKTstate0 + here->B2qd); + return(OK); + case BSIM2_CQD: + value->rValue = *(ckt->CKTstate0 + here->B2cqd); + return(OK); + case BSIM2_CGG: + value->rValue = *(ckt->CKTstate0 + here->B2cggb); + return(OK); + case BSIM2_CGD: + value->rValue = *(ckt->CKTstate0 + here->B2cgdb); + return(OK); + case BSIM2_CGS: + value->rValue = *(ckt->CKTstate0 + here->B2cgsb); + return(OK); + case BSIM2_CBG: + value->rValue = *(ckt->CKTstate0 + here->B2cbgb); + return(OK); + case BSIM2_CAPBD: + value->rValue = *(ckt->CKTstate0 + here->B2capbd); + return(OK); + case BSIM2_CQBD: + value->rValue = *(ckt->CKTstate0 + here->B2cqbd); + return(OK); + case BSIM2_CAPBS: + value->rValue = *(ckt->CKTstate0 + here->B2capbs); + return(OK); + case BSIM2_CQBS: + value->rValue = *(ckt->CKTstate0 + here->B2cqbs); + return(OK); + case BSIM2_CDG: + value->rValue = *(ckt->CKTstate0 + here->B2cdgb); + return(OK); + case BSIM2_CDD: + value->rValue = *(ckt->CKTstate0 + here->B2cddb); + return(OK); + case BSIM2_CDS: + value->rValue = *(ckt->CKTstate0 + here->B2cdsb); + return(OK); + case BSIM2_VON: + value->rValue = *(ckt->CKTstate0 + here->B2vono); + return(OK); + case BSIM2_QBS: + value->rValue = *(ckt->CKTstate0 + here->B2qbs); + return(OK); + case BSIM2_QBD: + value->rValue = *(ckt->CKTstate0 + here->B2qbd); + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + + diff --git a/src/spicelib/devices/bsim2/b2cvtest.c b/src/spicelib/devices/bsim2/b2cvtest.c new file mode 100644 index 000000000..81c561b7e --- /dev/null +++ b/src/spicelib/devices/bsim2/b2cvtest.c @@ -0,0 +1,120 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim2def.h" +#include "trandefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +B2convTest(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register B2model *model = (B2model*)inModel; + register B2instance *here; + double cbd; + double cbhat; + double cbs; + double cd; + double cdhat; + double delvbd; + double delvbs; + double delvds; + double delvgd; + double delvgs; + double tol; + double vbd; + double vbs; + double vds; + double vgd; + double vgdo; + double vgs; + + + /* loop through all the B2 device models */ + for( ; model != NULL; model = model->B2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->B2instances; here != NULL ; + here=here->B2nextInstance) { + if (here->B2owner != ARCHme) continue; + + vbs = model->B2type * ( + *(ckt->CKTrhsOld+here->B2bNode) - + *(ckt->CKTrhsOld+here->B2sNodePrime)); + vgs = model->B2type * ( + *(ckt->CKTrhsOld+here->B2gNode) - + *(ckt->CKTrhsOld+here->B2sNodePrime)); + vds = model->B2type * ( + *(ckt->CKTrhsOld+here->B2dNodePrime) - + *(ckt->CKTrhsOld+here->B2sNodePrime)); + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->B2vgs) - + *(ckt->CKTstate0 + here->B2vds); + delvbs = vbs - *(ckt->CKTstate0 + here->B2vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->B2vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->B2vgs); + delvds = vds - *(ckt->CKTstate0 + here->B2vds); + delvgd = vgd-vgdo; + + if (here->B2mode >= 0) { + cdhat= + *(ckt->CKTstate0 + here->B2cd) - + *(ckt->CKTstate0 + here->B2gbd) * delvbd + + *(ckt->CKTstate0 + here->B2gmbs) * delvbs + + *(ckt->CKTstate0 + here->B2gm) * delvgs + + *(ckt->CKTstate0 + here->B2gds) * delvds ; + } else { + cdhat= + *(ckt->CKTstate0 + here->B2cd) - + ( *(ckt->CKTstate0 + here->B2gbd) - + *(ckt->CKTstate0 + here->B2gmbs)) * delvbd - + *(ckt->CKTstate0 + here->B2gm) * delvgd + + *(ckt->CKTstate0 + here->B2gds) * delvds; + } + cbhat= + *(ckt->CKTstate0 + here->B2cbs) + + *(ckt->CKTstate0 + here->B2cbd) + + *(ckt->CKTstate0 + here->B2gbd) * delvbd + + *(ckt->CKTstate0 + here->B2gbs) * delvbs ; + + cd = *(ckt->CKTstate0 + here->B2cd); + cbs = *(ckt->CKTstate0 + here->B2cbs); + cbd = *(ckt->CKTstate0 + here->B2cbd); + /* + * check convergence + */ + if ( (here->B2off == 0) || (!(ckt->CKTmode & MODEINITFIX)) ){ + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol; + if (fabs(cdhat-cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); + } + tol=ckt->CKTreltol*MAX(fabs(cbhat),fabs(cbs+cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(cbs+cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); + } + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim2/b2del.c b/src/spicelib/devices/bsim2/b2del.c new file mode 100644 index 000000000..eb05ed125 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2del.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim2def.h" +#include "sperror.h" +#include "gendefs.h" +#include "suffix.h" + + +int +B2delete(inModel,name,inInst) + GENmodel *inModel; + IFuid name; + GENinstance **inInst; + +{ + + B2instance **fast = (B2instance**)inInst; + B2model *model = (B2model*)inModel; + B2instance **prev = NULL; + B2instance *here; + + for( ; model ; model = model->B2nextModel) { + prev = &(model->B2instances); + for(here = *prev; here ; here = *prev) { + if(here->B2name == name || (fast && here==*fast) ) { + *prev= here->B2nextInstance; + FREE(here); + return(OK); + } + prev = &(here->B2nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/bsim2/b2dest.c b/src/spicelib/devices/bsim2/b2dest.c new file mode 100644 index 000000000..465d5b60d --- /dev/null +++ b/src/spicelib/devices/bsim2/b2dest.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim2def.h" +#include "suffix.h" + + +void +B2destroy(inModel) + GENmodel **inModel; + +{ + + B2model **model = (B2model**)inModel; + B2instance *here; + B2instance *prev = NULL; + B2model *mod = *model; + B2model *oldmod = NULL; + + for( ; mod ; mod = mod->B2nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (B2instance *)NULL; + for(here = mod->B2instances ; here ; here = here->B2nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} + diff --git a/src/spicelib/devices/bsim2/b2eval.c b/src/spicelib/devices/bsim2/b2eval.c new file mode 100644 index 000000000..5b8963896 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2eval.c @@ -0,0 +1,625 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Min-Chie Jeng, Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim2def.h" +#include "trandefs.h" +#include "const.h" +#include "suffix.h" + +/* This routine evaluates the drain current, its derivatives and the + * charges associated with the gate,bulk and drain terminal + * using the B2 (Berkeley Short-Channel IGFET Model) Equations. + */ +void +B2evaluate(Vds,Vbs,Vgs,here,model,gm,gds,gmb,qg,qb,qd,cgg,cgd,cgs, + cbg,cbd,cbs,cdg,cdd,cds,Ids,von,vdsat,ckt) + + register CKTcircuit *ckt; + register B2model *model; + register B2instance *here; + double Vds,Vbs,Vgs; + double *gm,*gds,*gmb,*qg,*qb,*qd,*cgg,*cgd,*cgs,*cbg; + double *cbd,*cbs,*cdg,*cdd,*cds,*Ids,*von,*vdsat; + { + double Vth, Vdsat; + double Phisb, T1s, Eta, Gg, Aa, Inv_Aa, U1, U1s, Vc, Kk, SqrtKk; + double dPhisb_dVb, dT1s_dVb, dVth_dVb, dVth_dVd, dAa_dVb, dVc_dVd; + double dVc_dVg, dVc_dVb, dKk_dVc, dVdsat_dVd, dVdsat_dVg, dVdsat_dVb; + double dUvert_dVg, dUvert_dVd, dUvert_dVb, Inv_Kk; + double dUtot_dVd, dUtot_dVb, dUtot_dVg, Ai, Bi, Vghigh, Vglow, Vgeff, Vof; + double Vbseff, Vgst, Vgdt, Qbulk, Utot; + double T0, T1, T2, T3, T4, T5, Arg1, Arg2, Exp0; + double tmp, tmp1, tmp2, tmp3, Uvert, Beta1, Beta2, Beta0, dGg_dVb, Exp1; + double T6, T7, T8, T9, n, ExpArg, ExpArg1; + double Beta, dQbulk_dVb, dVgdt_dVg, dVgdt_dVd; + double dVbseff_dVb, Ua, Ub, dVgdt_dVb, dQbulk_dVd; + double Con1, Con3, Con4, SqrVghigh, SqrVglow, CubVghigh, CubVglow; + double delta, Coeffa, Coeffb, Coeffc, Coeffd, Inv_Uvert, Inv_Utot; + double Inv_Vdsat, tanh, Sqrsech, dBeta1_dVb, dU1_dVd, dU1_dVg, dU1_dVb; + double Betaeff, FR, dFR_dVd, dFR_dVg, dFR_dVb, Betas, Beta3, Beta4; + double dBeta_dVd, dBeta_dVg, dBeta_dVb, dVgeff_dVg, dVgeff_dVd, dVgeff_dVb; + double dCon3_dVd, dCon3_dVb, dCon4_dVd, dCon4_dVb, dCoeffa_dVd, dCoeffa_dVb; + double dCoeffb_dVd, dCoeffb_dVb, dCoeffc_dVd, dCoeffc_dVb; + double dCoeffd_dVd, dCoeffd_dVb; + int ChargeComputationNeeded; + int valuetypeflag; /* added 3/19/90 JSD */ + + if ((ckt->CKTmode & (MODEAC | MODETRAN)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) || + (ckt->CKTmode & MODEINITSMSIG) ) + { ChargeComputationNeeded = 1; + } + else + { ChargeComputationNeeded = 0; + } + + if (Vbs < model->B2vbb2) Vbs = model->B2vbb2; + if (Vgs > model->B2vgg2) Vgs = model->B2vgg2; + if (Vds > model->B2vdd2) Vds = model->B2vdd2; + +/* Threshold Voltage. */ + if (Vbs <= 0.0) + { Phisb = here->pParam->B2phi - Vbs; + dPhisb_dVb = -1.0; + T1s = sqrt(Phisb); + dT1s_dVb = -0.5 / T1s; + } + else + { tmp = here->pParam->B2phi / (here->pParam->B2phi + Vbs); + Phisb = here->pParam->B2phi * tmp; + dPhisb_dVb = -tmp * tmp; + T1s = here->pParam->Phis3 / (here->pParam->B2phi + 0.5 * Vbs); + dT1s_dVb = -0.5 * T1s * T1s / here->pParam->Phis3; + } + + Eta = here->pParam->B2eta0 + here->pParam->B2etaB * Vbs; + Ua = here->pParam->B2ua0 + here->pParam->B2uaB * Vbs; + Ub = here->pParam->B2ub0 + here->pParam->B2ubB * Vbs; + U1s = here->pParam->B2u10 + here->pParam->B2u1B * Vbs; + + Vth = here->pParam->B2vfb + here->pParam->B2phi + here->pParam->B2k1 + * T1s - here->pParam->B2k2 * Phisb - Eta * Vds; + dVth_dVd = -Eta; + dVth_dVb = here->pParam->B2k1 * dT1s_dVb + here->pParam->B2k2 + - here->pParam->B2etaB * Vds; + + Vgst = Vgs - Vth; + + tmp = 1.0 / (1.744 + 0.8364 * Phisb); + Gg = 1.0 - tmp; + dGg_dVb = 0.8364 * tmp * tmp * dPhisb_dVb; + T0 = Gg / T1s; + tmp1 = 0.5 * T0 * here->pParam->B2k1; + Aa = 1.0 + tmp1; + dAa_dVb = (Aa - 1.0) * (dGg_dVb / Gg - dT1s_dVb / T1s); + Inv_Aa = 1.0 / Aa; + + Vghigh = here->pParam->B2vghigh; + Vglow = here->pParam->B2vglow; + + if ((Vgst >= Vghigh) || (here->pParam->B2n0 == 0.0)) + { Vgeff = Vgst; + dVgeff_dVg = 1.0; + dVgeff_dVd = -dVth_dVd; + dVgeff_dVb = -dVth_dVb; + } + else + { Vof = here->pParam->B2vof0 + here->pParam->B2vofB * Vbs + + here->pParam->B2vofD * Vds; + n = here->pParam->B2n0 + here->pParam->B2nB / T1s + + here->pParam->B2nD * Vds; + tmp = 0.5 / (n * model->B2Vtm); + + ExpArg1 = -Vds / model->B2Vtm; + ExpArg1 = MAX(ExpArg1, -30.0); + Exp1 = exp(ExpArg1); + tmp1 = 1.0 - Exp1; + tmp1 = MAX(tmp1, 1.0e-18); + tmp2 = 2.0 * Aa * tmp1; + + if (Vgst <= Vglow) + { + ExpArg = Vgst * tmp; + ExpArg = MAX(ExpArg, -30.0); + Exp0 = exp(0.5 * Vof + ExpArg); + Vgeff = sqrt(tmp2) * model->B2Vtm * Exp0; + T0 = n * model->B2Vtm; + dVgeff_dVg = Vgeff * tmp; + dVgeff_dVd = dVgeff_dVg * (n / tmp1 * Exp1 - dVth_dVd - Vgst + * here->pParam->B2nD / n + T0 * here->pParam->B2vofD); + dVgeff_dVb = dVgeff_dVg * (here->pParam->B2vofB * T0 + - dVth_dVb + here->pParam->B2nB * Vgst + / (n * T1s * T1s) * dT1s_dVb + T0 * Inv_Aa * dAa_dVb); + } + else + { + ExpArg = Vglow * tmp; + ExpArg = MAX(ExpArg, -30.0); + Exp0 = exp(0.5 * Vof + ExpArg); + Vgeff = sqrt(2.0 * Aa * (1.0 - Exp1)) * model->B2Vtm * Exp0; + Con1 = Vghigh; + Con3 = Vgeff; + Con4 = Con3 * tmp; + SqrVghigh = Vghigh * Vghigh; + SqrVglow = Vglow * Vglow; + CubVghigh = Vghigh * SqrVghigh; + CubVglow = Vglow * SqrVglow; + T0 = 2.0 * Vghigh; + T1 = 2.0 * Vglow; + T2 = 3.0 * SqrVghigh; + T3 = 3.0 * SqrVglow; + T4 = Vghigh - Vglow; + T5 = SqrVghigh - SqrVglow; + T6 = CubVghigh - CubVglow; + T7 = Con1 - Con3; + delta = (T1 - T0) * T6 + (T2 - T3) * T5 + (T0 * T3 - T1 * T2) * T4; + delta = 1.0 / delta; + Coeffb = (T1 - Con4 * T0) * T6 + (Con4 * T2 - T3) * T5 + + (T0 * T3 - T1 * T2) * T7; + Coeffc = (Con4 - 1.0) * T6 + (T2 - T3) * T7 + (T3 - Con4 * T2) * T4; + Coeffd = (T1 - T0) * T7 + (1.0 - Con4) * T5 + (Con4 * T0 - T1) * T4; + Coeffa = SqrVghigh * (Coeffc + Coeffd * T0); + Vgeff = (Coeffa + Vgst * (Coeffb + Vgst * (Coeffc + Vgst * Coeffd))) + * delta; + dVgeff_dVg = (Coeffb + Vgst * (2.0 * Coeffc + 3.0 * Vgst * Coeffd)) + * delta; + T7 = Con3 * tmp; + T8 = dT1s_dVb * here->pParam->B2nB / (T1s * T1s * n); + T9 = n * model->B2Vtm; + dCon3_dVd = T7 * (n * Exp1 / tmp1 - Vglow * here->pParam->B2nD + / n + T9 * here->pParam->B2vofD); + dCon3_dVb = T7 * (T9 * Inv_Aa * dAa_dVb + Vglow * T8 + + T9 * here->pParam->B2vofB); + dCon4_dVd = tmp * dCon3_dVd - T7 * here->pParam->B2nD / n; + dCon4_dVb = tmp * dCon3_dVb + T7 * T8; + + dCoeffb_dVd = dCon4_dVd * (T2 * T5 - T0 * T6) + dCon3_dVd + * (T1 * T2 - T0 * T3); + dCoeffc_dVd = dCon4_dVd * (T6 - T2 * T4) + dCon3_dVd * (T3 - T2); + dCoeffd_dVd = dCon4_dVd * (T0 * T4 - T5) + dCon3_dVd * (T0 - T1); + dCoeffa_dVd = SqrVghigh * (dCoeffc_dVd + dCoeffd_dVd * T0); + + dVgeff_dVd = -dVgeff_dVg * dVth_dVd + (dCoeffa_dVd + Vgst + * (dCoeffb_dVd + Vgst * (dCoeffc_dVd + Vgst + * dCoeffd_dVd))) * delta; + + dCoeffb_dVb = dCon4_dVb * (T2 * T5 - T0 * T6) + dCon3_dVb + * (T1 * T2 - T0 * T3); + dCoeffc_dVb = dCon4_dVb * (T6 - T2 * T4) + dCon3_dVb * (T3 - T2); + dCoeffd_dVb = dCon4_dVb * (T0 * T4 - T5) + dCon3_dVb * (T0 - T1); + dCoeffa_dVb = SqrVghigh * (dCoeffc_dVb + dCoeffd_dVb * T0); + + dVgeff_dVb = -dVgeff_dVg * dVth_dVb + (dCoeffa_dVb + Vgst + * (dCoeffb_dVb + Vgst * (dCoeffc_dVb + Vgst + * dCoeffd_dVb))) * delta; + } + } + + if (Vgeff > 0.0) + { + Uvert = 1.0 + Vgeff * (Ua + Vgeff * Ub); + Uvert = MAX(Uvert, 0.2); + Inv_Uvert = 1.0 / Uvert; + T8 = Ua + 2.0 * Ub * Vgeff; + dUvert_dVg = T8 * dVgeff_dVg; + dUvert_dVd = T8 * dVgeff_dVd; + dUvert_dVb = T8 * dVgeff_dVb + Vgeff * (here->pParam->B2uaB + + Vgeff * here->pParam->B2ubB); + + T8 = U1s * Inv_Aa * Inv_Uvert; + Vc = T8 * Vgeff; + T9 = Vc * Inv_Uvert; + dVc_dVg = T8 * dVgeff_dVg - T9 * dUvert_dVg; + dVc_dVd = T8 * dVgeff_dVd - T9 * dUvert_dVd; + dVc_dVb = T8 * dVgeff_dVb + here->pParam->B2u1B * Vgeff * Inv_Aa + * Inv_Uvert - Vc * Inv_Aa * dAa_dVb - T9 * dUvert_dVb; + + + tmp2 = sqrt(1.0 + 2.0 * Vc); + Kk = 0.5 * (1.0 + Vc + tmp2); + Inv_Kk = 1.0 / Kk; + dKk_dVc = 0.5 + 0.5 / tmp2; + SqrtKk = sqrt(Kk); + + T8 = Inv_Aa / SqrtKk; + Vdsat = Vgeff * T8; + Vdsat = MAX(Vdsat, 1.0e-18); + Inv_Vdsat = 1.0 / Vdsat; + T9 = 0.5 * Vdsat * Inv_Kk * dKk_dVc; + dVdsat_dVd = T8 * dVgeff_dVd - T9 * dVc_dVd; + dVdsat_dVg = T8 * dVgeff_dVg - T9 * dVc_dVg; + dVdsat_dVb = T8 * dVgeff_dVb - T9 * dVc_dVb - Vdsat* Inv_Aa * dAa_dVb; + + Beta0 = here->pParam->B2beta0 + here->pParam->B2beta0B * Vbs; + Betas = here->pParam->B2betas0 + here->pParam->B2betasB * Vbs; + Beta2 = here->pParam->B2beta20 + here->pParam->B2beta2B * Vbs + + here->pParam->B2beta2G * Vgs; + Beta3 = here->pParam->B2beta30 + here->pParam->B2beta3B * Vbs + + here->pParam->B2beta3G * Vgs; + Beta4 = here->pParam->B2beta40 + here->pParam->B2beta4B * Vbs + + here->pParam->B2beta4G * Vgs; + Beta1 = Betas - (Beta0 + model->B2vdd * (Beta3 - model->B2vdd + * Beta4)); + + T0 = Vds * Beta2 * Inv_Vdsat; + T0 = MIN(T0, 30.0); + T1 = exp(T0); + T2 = T1 * T1; + T3 = T2 + 1.0; + tanh = (T2 - 1.0) / T3; + Sqrsech = 4.0 * T2 / (T3 * T3); + + Beta = Beta0 + Beta1 * tanh + Vds * (Beta3 - Beta4 * Vds); + T4 = Beta1 * Sqrsech * Inv_Vdsat; + T5 = model->B2vdd * tanh; + dBeta_dVd = Beta3 - 2.0 * Beta4 * Vds + T4 * (Beta2 - T0 * dVdsat_dVd); + dBeta_dVg = T4 * (here->pParam->B2beta2G * Vds - T0 * dVdsat_dVg) + + here->pParam->B2beta3G * (Vds - T5) + - here->pParam->B2beta4G * (Vds * Vds - model->B2vdd * T5); + dBeta1_dVb = here->pParam->Arg; + dBeta_dVb = here->pParam->B2beta0B + dBeta1_dVb * tanh + Vds + * (here->pParam->B2beta3B - Vds * here->pParam->B2beta4B) + + T4 * (here->pParam->B2beta2B * Vds - T0 * dVdsat_dVb); + + + if (Vgst > Vglow) + { + if (Vds <= Vdsat) /* triode region */ + { + T3 = Vds * Inv_Vdsat; + T4 = T3 - 1.0; + T2 = 1.0 - here->pParam->B2u1D * T4 * T4; + U1 = U1s * T2; + Utot = Uvert + U1 * Vds; + Utot = MAX(Utot, 0.5); + Inv_Utot = 1.0 / Utot; + T5 = 2.0 * U1s * here->pParam->B2u1D * Inv_Vdsat * T4; + dU1_dVd = T5 * (T3 * dVdsat_dVd - 1.0); + dU1_dVg = T5 * T3 * dVdsat_dVg; + dU1_dVb = T5 * T3 * dVdsat_dVb + here->pParam->B2u1B * T2; + dUtot_dVd = dUvert_dVd + U1 + Vds * dU1_dVd; + dUtot_dVg = dUvert_dVg + Vds * dU1_dVg; + dUtot_dVb = dUvert_dVb + Vds * dU1_dVb; + + tmp1 = (Vgeff - 0.5 * Aa * Vds); + tmp3 = tmp1 * Vds; + Betaeff = Beta * Inv_Utot; + *Ids = Betaeff * tmp3; + T6 = *Ids / Betaeff * Inv_Utot; + *gds = T6 * (dBeta_dVd - Betaeff * dUtot_dVd) + Betaeff * (tmp1 + + (dVgeff_dVd - 0.5 * Aa) * Vds); + *gm = T6 * (dBeta_dVg - Betaeff * dUtot_dVg) + Betaeff * Vds + * dVgeff_dVg; + *gmb = T6 * (dBeta_dVb - Betaeff * dUtot_dVb) + Betaeff * Vds + * (dVgeff_dVb - 0.5 * Vds * dAa_dVb); + } + else /* Saturation */ + { tmp1 = Vgeff * Inv_Aa * Inv_Kk; + tmp3 = 0.5 * Vgeff * tmp1; + Betaeff = Beta * Inv_Uvert; + *Ids = Betaeff * tmp3; + T0 = *Ids / Betaeff * Inv_Uvert; + T1 = Betaeff * Vgeff * Inv_Aa * Inv_Kk; + T2 = *Ids * Inv_Kk * dKk_dVc; + + if (here->pParam->B2ai0 != 0.0) + { + Ai = here->pParam->B2ai0 + here->pParam->B2aiB * Vbs; + Bi = here->pParam->B2bi0 + here->pParam->B2biB * Vbs; + T5 = Bi / (Vds - Vdsat); + T5 = MIN(T5, 30.0); + T6 = exp(-T5); + FR = 1.0 + Ai * T6; + T7 = T5 / (Vds - Vdsat); + T8 = (1.0 - FR) * T7; + dFR_dVd = T8 * (dVdsat_dVd - 1.0); + dFR_dVg = T8 * dVdsat_dVg; + dFR_dVb = T8 * dVdsat_dVb + T6 * (here->pParam->B2aiB - Ai + * here->pParam->B2biB / (Vds - Vdsat)); + + *gds = (T0 * (dBeta_dVd - Betaeff * dUvert_dVd) + T1 + * dVgeff_dVd - T2 * dVc_dVd) * FR + *Ids * dFR_dVd; + *gm = (T0 * (dBeta_dVg - Betaeff * dUvert_dVg) + + T1 * dVgeff_dVg - T2 * dVc_dVg) * FR + *Ids * dFR_dVg; + *gmb = (T0 * (dBeta_dVb - Betaeff * dUvert_dVb) + T1 + * dVgeff_dVb - T2 * dVc_dVb - *Ids * Inv_Aa * dAa_dVb) + * FR + *Ids * dFR_dVb; + *Ids *= FR; + } + else + { *gds = T0 * (dBeta_dVd - Betaeff * dUvert_dVd) + T1 + * dVgeff_dVd - T2 * dVc_dVd; + *gm = T0 * (dBeta_dVg - Betaeff * dUvert_dVg) + T1 * dVgeff_dVg + - T2 * dVc_dVg; + *gmb = T0 * (dBeta_dVb - Betaeff * dUvert_dVb) + T1 + * dVgeff_dVb - T2 * dVc_dVb - *Ids * Inv_Aa * dAa_dVb; + } + } /* end of Saturation */ + } + else + { T0 = Exp0 * Exp0; + T1 = Exp1; + *Ids = Beta * model->B2Vtm * model->B2Vtm * T0 * (1.0 - T1); + T2 = *Ids / Beta; + T4 = n * model->B2Vtm; + T3 = *Ids / T4; + if ((Vds > Vdsat) && here->pParam->B2ai0 != 0.0) + { Ai = here->pParam->B2ai0 + here->pParam->B2aiB * Vbs; + Bi = here->pParam->B2bi0 + here->pParam->B2biB * Vbs; + T5 = Bi / (Vds - Vdsat); + T5 = MIN(T5, 30.0); + T6 = exp(-T5); + FR = 1.0 + Ai * T6; + T7 = T5 / (Vds - Vdsat); + T8 = (1.0 - FR) * T7; + dFR_dVd = T8 * (dVdsat_dVd - 1.0); + dFR_dVg = T8 * dVdsat_dVg; + dFR_dVb = T8 * dVdsat_dVb + T6 * (here->pParam->B2aiB - Ai + * here->pParam->B2biB / (Vds - Vdsat)); + } + else + { FR = 1.0; + dFR_dVd = 0.0; + dFR_dVg = 0.0; + dFR_dVb = 0.0; + } + + *gds = (T2 * dBeta_dVd + T3 * (here->pParam->B2vofD * T4 - dVth_dVd + - here->pParam->B2nD * Vgst / n) + Beta * model->B2Vtm + * T0 * T1) * FR + *Ids * dFR_dVd; + *gm = (T2 * dBeta_dVg + T3) * FR + *Ids * dFR_dVg; + *gmb = (T2 * dBeta_dVb + T3 * (here->pParam->B2vofB * T4 - dVth_dVb + + here->pParam->B2nB * Vgst / (n * T1s * T1s) * dT1s_dVb)) * FR + + *Ids * dFR_dVb; + *Ids *= FR; + } + } + else + { *Ids = 0.0; + *gm = 0.0; + *gds = 0.0; + *gmb = 0.0; + } + + /* Some Limiting of DC Parameters */ + *gds = MAX(*gds,1.0e-20); + + + if ((model->B2channelChargePartitionFlag > 1) + || ((!ChargeComputationNeeded) && + (model->B2channelChargePartitionFlag > -5))) + { + *qg = 0.0; + *qd = 0.0; + *qb = 0.0; + *cgg = 0.0; + *cgs = 0.0; + *cgd = 0.0; + *cdg = 0.0; + *cds = 0.0; + *cdd = 0.0; + *cbg = 0.0; + *cbs = 0.0; + *cbd = 0.0; + goto finished; + } + else + { + if (Vbs < 0.0) + { Vbseff = Vbs; + dVbseff_dVb = 1.0; + } + else + { Vbseff = here->pParam->B2phi - Phisb; + dVbseff_dVb = -dPhisb_dVb; + } + Arg1 = Vgs - Vbseff - here->pParam->B2vfb; + Arg2 = Arg1 - Vgst; + Qbulk = here->pParam->One_Third_CoxWL * Arg2; + dQbulk_dVb = here->pParam->One_Third_CoxWL * (dVth_dVb - dVbseff_dVb); + dQbulk_dVd = here->pParam->One_Third_CoxWL * dVth_dVd; + if (Arg1 <= 0.0) + { + *qg = here->pParam->CoxWL * Arg1; + *qb = -(*qg); + *qd = 0.0; + + *cgg = here->pParam->CoxWL; + *cgd = 0.0; + *cgs = -*cgg * (1.0 - dVbseff_dVb); + + *cdg = 0.0; + *cdd = 0.0; + *cds = 0.0; + + *cbg = -here->pParam->CoxWL; + *cbd = 0.0; + *cbs = -*cgs; + } + else if (Vgst <= 0.0) + { T2 = Arg1 / Arg2; + T3 = T2 * T2 * (here->pParam->CoxWL - here->pParam->Two_Third_CoxWL + * T2); + + *qg = here->pParam->CoxWL * Arg1 * (1.0 - T2 * (1.0 - T2 / 3.0)); + *qb = -(*qg); + *qd = 0.0; + + *cgg = here->pParam->CoxWL * (1.0 - T2 * (2.0 - T2)); + tmp = T3 * dVth_dVb - (*cgg + T3) * dVbseff_dVb; + *cgd = T3 * dVth_dVd; + *cgs = -(*cgg + *cgd + tmp); + + *cdg = 0.0; + *cdd = 0.0; + *cds = 0.0; + + *cbg = -*cgg; + *cbd = -*cgd; + *cbs = -*cgs; + } + else + { if (Vgst < here->pParam->B2vghigh) + { Uvert = 1.0 + Vgst * (Ua + Vgst * Ub); + Uvert = MAX(Uvert, 0.2); + Inv_Uvert = 1.0 / Uvert; + dUvert_dVg = Ua + 2.0 * Ub * Vgst; + dUvert_dVd = -dUvert_dVg * dVth_dVd; + dUvert_dVb = -dUvert_dVg * dVth_dVb + Vgst + * (here->pParam->B2uaB + Vgst * here->pParam->B2ubB); + + T8 = U1s * Inv_Aa * Inv_Uvert; + Vc = T8 * Vgst; + T9 = Vc * Inv_Uvert; + dVc_dVg = T8 - T9 * dUvert_dVg; + dVc_dVd = -T8 * dVth_dVd - T9 * dUvert_dVd; + dVc_dVb = -T8 * dVth_dVb + here->pParam->B2u1B * Vgst * Inv_Aa + * Inv_Uvert - Vc * Inv_Aa * dAa_dVb - T9 * dUvert_dVb; + + tmp2 = sqrt(1.0 + 2.0 * Vc); + Kk = 0.5 * (1.0 + Vc + tmp2); + Inv_Kk = 1.0 / Kk; + dKk_dVc = 0.5 + 0.5 / tmp2; + SqrtKk = sqrt(Kk); + + T8 = Inv_Aa / SqrtKk; + Vdsat = Vgst * T8; + T9 = 0.5 * Vdsat * Inv_Kk * dKk_dVc; + dVdsat_dVd = -T8 * dVth_dVd - T9 * dVc_dVd; + dVdsat_dVg = T8 - T9 * dVc_dVg; + dVdsat_dVb = -T8 * dVth_dVb - T9 * dVc_dVb + - Vdsat* Inv_Aa * dAa_dVb; + } + if (Vds >= Vdsat) + { /* saturation region */ + *cgg = here->pParam->Two_Third_CoxWL; + *cgd = -*cgg * dVth_dVd + dQbulk_dVd; + tmp = -*cgg * dVth_dVb + dQbulk_dVb; + *cgs = -(*cgg + *cgd + tmp); + + *cbg = 0.0; + *cbd = -dQbulk_dVd; + *cbs = dQbulk_dVd + dQbulk_dVb; + + *cdg = -0.4 * *cgg; + tmp = -*cdg * dVth_dVb; + *cdd = -*cdg * dVth_dVd; + *cds = -(*cdg + *cdd + tmp); + + *qb = -Qbulk; + *qg = here->pParam->Two_Third_CoxWL * Vgst + Qbulk; + *qd = *cdg * Vgst; + } + else + { /* linear region */ + T7 = Vds / Vdsat; + T8 = Vgst / Vdsat; + T6 = T7 * T8; + T9 = 1.0 - T7; + Vgdt = Vgst * T9; + T0 = Vgst / (Vgst + Vgdt); + T1 = Vgdt / (Vgst + Vgdt); + T5 = T0 * T1; + T2 = 1.0 - T1 + T5; + T3 = 1.0 - T0 + T5; + + dVgdt_dVg = T9 + T6 * dVdsat_dVg; + dVgdt_dVd = T6 * dVdsat_dVd - T8 -T9 * dVth_dVd; + dVgdt_dVb = T6 * dVdsat_dVb -T9 * dVth_dVb; + + *qg = here->pParam->Two_Third_CoxWL * (Vgst + Vgdt + - Vgdt * T0) + Qbulk; + *qb = -Qbulk; + *qd = -here->pParam->One_Third_CoxWL * (0.2 * Vgdt + + 0.8 * Vgst + Vgdt * T1 + + 0.2 * T5 * (Vgdt - Vgst)); + + *cgg = here->pParam->Two_Third_CoxWL * (T2 + T3 * dVgdt_dVg); + tmp = dQbulk_dVb + here->pParam->Two_Third_CoxWL * (T3 * dVgdt_dVb + - T2 * dVth_dVb); + *cgd = here->pParam->Two_Third_CoxWL * (T3 * dVgdt_dVd + - T2 * dVth_dVd) + dQbulk_dVd; + *cgs = -(*cgg + *cgd + tmp); + + T2 = 0.8 - 0.4 * T1 * (2.0 * T1 + T0 + T0 * (T1 - T0)); + T3 = 0.2 + T1 + T0 * (1.0 - 0.4 * T0 * (T1 + 3.0 * T0)); + *cdg = -here->pParam->One_Third_CoxWL * (T2 + T3 * dVgdt_dVg); + tmp = here->pParam->One_Third_CoxWL * (T2 * dVth_dVb + - T3 * dVgdt_dVb); + *cdd = here->pParam->One_Third_CoxWL * (T2 * dVth_dVd + - T3 * dVgdt_dVd); + *cds = -(*cdg + tmp + *cdd); + + *cbg = 0.0; + *cbd = -dQbulk_dVd; + *cbs = dQbulk_dVd + dQbulk_dVb; + } + } + } + +finished: /* returning Values to Calling Routine */ + valuetypeflag = (int) model->B2channelChargePartitionFlag; + switch (valuetypeflag) + { + case 0: *Ids = MAX(*Ids,1e-50); + break; + case -1: *Ids = MAX(*Ids,1e-50); + break; + case -2: *Ids = *gm; + break; + case -3: *Ids = *gds; + break; + case -4: *Ids = 1.0 / *gds; + break; + case -5: *Ids = *gmb; + break; + case -6: *Ids = *qg / 1.0e-12; + break; + case -7: *Ids = *qb / 1.0e-12; + break; + case -8: *Ids = *qd / 1.0e-12; + break; + case -9: *Ids = -(*qb + *qg + *qd) / 1.0e-12; + break; + case -10: *Ids = *cgg / 1.0e-12; + break; + case -11: *Ids = *cgd / 1.0e-12; + break; + case -12: *Ids = *cgs / 1.0e-12; + break; + case -13: *Ids = -(*cgg + *cgd + *cgs) / 1.0e-12; + break; + case -14: *Ids = *cbg / 1.0e-12; + break; + case -15: *Ids = *cbd / 1.0e-12; + break; + case -16: *Ids = *cbs / 1.0e-12; + break; + case -17: *Ids = -(*cbg + *cbd + *cbs) / 1.0e-12; + break; + case -18: *Ids = *cdg / 1.0e-12; + break; + case -19: *Ids = *cdd / 1.0e-12; + break; + case -20: *Ids = *cds / 1.0e-12; + break; + case -21: *Ids = -(*cdg + *cdd + *cds) / 1.0e-12; + break; + case -22: *Ids = -(*cgg + *cdg + *cbg) / 1.0e-12; + break; + case -23: *Ids = -(*cgd + *cdd + *cbd) / 1.0e-12; + break; + case -24: *Ids = -(*cgs + *cds + *cbs) / 1.0e-12; + break; + default: *Ids = MAX(*Ids, 1.0e-50); + break; + } + *von = Vth; + *vdsat = Vdsat; +} + diff --git a/src/spicelib/devices/bsim2/b2getic.c b/src/spicelib/devices/bsim2/b2getic.c new file mode 100644 index 000000000..a932a26a8 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2getic.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim2def.h" +#include "sperror.h" +#include "suffix.h" + + +int +B2getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + +{ + + B2model *model = (B2model*)inModel; + B2instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->B2nextModel) { + for(here = model->B2instances; here ; here = here->B2nextInstance) { + if (here->B2owner != ARCHme) continue; + + if(!here->B2icVBSGiven) { + here->B2icVBS = + *(ckt->CKTrhs + here->B2bNode) - + *(ckt->CKTrhs + here->B2sNode); + } + if(!here->B2icVDSGiven) { + here->B2icVDS = + *(ckt->CKTrhs + here->B2dNode) - + *(ckt->CKTrhs + here->B2sNode); + } + if(!here->B2icVGSGiven) { + here->B2icVGS = + *(ckt->CKTrhs + here->B2gNode) - + *(ckt->CKTrhs + here->B2sNode); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim2/b2ld.c b/src/spicelib/devices/bsim2/b2ld.c new file mode 100644 index 000000000..ed6f3c885 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2ld.c @@ -0,0 +1,736 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim2def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +B2load(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register B2model *model = (B2model*)inModel; + register B2instance *here; + double DrainSatCurrent; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double SourceSatCurrent; + double DrainArea; + double SourceArea; + double DrainPerimeter; + double SourcePerimeter; + double arg; + double capbd; + double capbs; + double cbd; + double cbhat; + double cbs; + double cd; + double cdrain; + double cdhat; + double cdreq; + double ceq; + double ceqbd; + double ceqbs; + double ceqqb; + double ceqqd; + double ceqqg; + double czbd; + double czbdsw; + double czbs; + double czbssw; + double delvbd; + double delvbs; + double delvds; + double delvgd; + double delvgs; + double evbd; + double evbs; + double gbd; + double gbs; + double gcbdb; + double gcbgb; + double gcbsb; + double gcddb; + double gcdgb; + double gcdsb; + double gcgdb; + double gcggb; + double gcgsb; + double gcsdb; + double gcsgb; + double gcssb; + double gds; + double geq; + double gm; + double gmbs; + double sarg; + double sargsw; + double vbd; + double vbs; + double vcrit; + double vds; + double vdsat; + double vgb; + double vgd; + double vgdo; + double vgs; + double von; + double xfact; + double xnrm; + double xrev; + int Check; + double cgdb; + double cgsb; + double cbdb; + double cdgb; + double cddb; + double cdsb; + double cggb; + double cbgb; + double cbsb; + double csgb; + double cssb; + double csdb; + double PhiB; + double PhiBSW; + double MJ; + double MJSW; + double argsw; + double qgate; + double qbulk; + double qdrn; + double qsrc; + double cqgate; + double cqbulk; + double cqdrn; + double vt0; + double args[7]; + int ByPass; +#ifndef NOBYPASS + double tempv; +#endif /*NOBYPASS*/ + int error; + + + /* loop through all the B2 device models */ + for( ; model != NULL; model = model->B2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->B2instances; here != NULL ; + here=here->B2nextInstance) { + if (here->B2owner != ARCHme) continue; + + EffectiveLength=here->B2l - model->B2deltaL * 1.e-6;/* m */ + DrainArea = here->B2drainArea; + SourceArea = here->B2sourceArea; + DrainPerimeter = here->B2drainPerimeter; + SourcePerimeter = here->B2sourcePerimeter; + if( (DrainSatCurrent=DrainArea*model->B2jctSatCurDensity) + < 1e-15){ + DrainSatCurrent = 1.0e-15; + } + if( (SourceSatCurrent=SourceArea*model->B2jctSatCurDensity) + <1.0e-15){ + SourceSatCurrent = 1.0e-15; + } + GateSourceOverlapCap = model->B2gateSourceOverlapCap *here->B2w; + GateDrainOverlapCap = model->B2gateDrainOverlapCap * here->B2w; + GateBulkOverlapCap = model->B2gateBulkOverlapCap *EffectiveLength; + von = model->B2type * here->B2von; + vdsat = model->B2type * here->B2vdsat; + vt0 = model->B2type * here->pParam->B2vt0; + + Check=1; + ByPass = 0; + if((ckt->CKTmode & MODEINITSMSIG)) { + vbs= *(ckt->CKTstate0 + here->B2vbs); + vgs= *(ckt->CKTstate0 + here->B2vgs); + vds= *(ckt->CKTstate0 + here->B2vds); + } else if ((ckt->CKTmode & MODEINITTRAN)) { + vbs= *(ckt->CKTstate1 + here->B2vbs); + vgs= *(ckt->CKTstate1 + here->B2vgs); + vds= *(ckt->CKTstate1 + here->B2vds); + } else if((ckt->CKTmode & MODEINITJCT) && !here->B2off) { + vds= model->B2type * here->B2icVDS; + vgs= model->B2type * here->B2icVGS; + vbs= model->B2type * here->B2icVBS; + if((vds==0) && (vgs==0) && (vbs==0) && + ((ckt->CKTmode & + (MODETRAN|MODEAC|MODEDCOP|MODEDCTRANCURVE)) || + (!(ckt->CKTmode & MODEUIC)))) { + vbs = -1; + vgs = vt0; + vds = 0; + } + } else if((ckt->CKTmode & (MODEINITJCT | MODEINITFIX) ) && + (here->B2off)) { + vbs=vgs=vds=0; + } else { +#ifndef PREDICTOR + if((ckt->CKTmode & MODEINITPRED)) { + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->B2vbs) = + *(ckt->CKTstate1 + here->B2vbs); + vbs = (1+xfact)* (*(ckt->CKTstate1 + here->B2vbs)) + -(xfact * (*(ckt->CKTstate2 + here->B2vbs))); + *(ckt->CKTstate0 + here->B2vgs) = + *(ckt->CKTstate1 + here->B2vgs); + vgs = (1+xfact)* (*(ckt->CKTstate1 + here->B2vgs)) + -(xfact * (*(ckt->CKTstate2 + here->B2vgs))); + *(ckt->CKTstate0 + here->B2vds) = + *(ckt->CKTstate1 + here->B2vds); + vds = (1+xfact)* (*(ckt->CKTstate1 + here->B2vds)) + -(xfact * (*(ckt->CKTstate2 + here->B2vds))); + *(ckt->CKTstate0 + here->B2vbd) = + *(ckt->CKTstate0 + here->B2vbs)- + *(ckt->CKTstate0 + here->B2vds); + *(ckt->CKTstate0 + here->B2cd) = + *(ckt->CKTstate1 + here->B2cd); + *(ckt->CKTstate0 + here->B2cbs) = + *(ckt->CKTstate1 + here->B2cbs); + *(ckt->CKTstate0 + here->B2cbd) = + *(ckt->CKTstate1 + here->B2cbd); + *(ckt->CKTstate0 + here->B2gm) = + *(ckt->CKTstate1 + here->B2gm); + *(ckt->CKTstate0 + here->B2gds) = + *(ckt->CKTstate1 + here->B2gds); + *(ckt->CKTstate0 + here->B2gmbs) = + *(ckt->CKTstate1 + here->B2gmbs); + *(ckt->CKTstate0 + here->B2gbd) = + *(ckt->CKTstate1 + here->B2gbd); + *(ckt->CKTstate0 + here->B2gbs) = + *(ckt->CKTstate1 + here->B2gbs); + *(ckt->CKTstate0 + here->B2cggb) = + *(ckt->CKTstate1 + here->B2cggb); + *(ckt->CKTstate0 + here->B2cbgb) = + *(ckt->CKTstate1 + here->B2cbgb); + *(ckt->CKTstate0 + here->B2cbsb) = + *(ckt->CKTstate1 + here->B2cbsb); + *(ckt->CKTstate0 + here->B2cgdb) = + *(ckt->CKTstate1 + here->B2cgdb); + *(ckt->CKTstate0 + here->B2cgsb) = + *(ckt->CKTstate1 + here->B2cgsb); + *(ckt->CKTstate0 + here->B2cbdb) = + *(ckt->CKTstate1 + here->B2cbdb); + *(ckt->CKTstate0 + here->B2cdgb) = + *(ckt->CKTstate1 + here->B2cdgb); + *(ckt->CKTstate0 + here->B2cddb) = + *(ckt->CKTstate1 + here->B2cddb); + *(ckt->CKTstate0 + here->B2cdsb) = + *(ckt->CKTstate1 + here->B2cdsb); + } else { +#endif /* PREDICTOR */ + vbs = model->B2type * ( + *(ckt->CKTrhsOld+here->B2bNode) - + *(ckt->CKTrhsOld+here->B2sNodePrime)); + vgs = model->B2type * ( + *(ckt->CKTrhsOld+here->B2gNode) - + *(ckt->CKTrhsOld+here->B2sNodePrime)); + vds = model->B2type * ( + *(ckt->CKTrhsOld+here->B2dNodePrime) - + *(ckt->CKTrhsOld+here->B2sNodePrime)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->B2vgs) - + *(ckt->CKTstate0 + here->B2vds); + delvbs = vbs - *(ckt->CKTstate0 + here->B2vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->B2vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->B2vgs); + delvds = vds - *(ckt->CKTstate0 + here->B2vds); + delvgd = vgd-vgdo; + + if (here->B2mode >= 0) { + cdhat= + *(ckt->CKTstate0 + here->B2cd) - + *(ckt->CKTstate0 + here->B2gbd) * delvbd + + *(ckt->CKTstate0 + here->B2gmbs) * delvbs + + *(ckt->CKTstate0 + here->B2gm) * delvgs + + *(ckt->CKTstate0 + here->B2gds) * delvds ; + } else { + cdhat= + *(ckt->CKTstate0 + here->B2cd) - + ( *(ckt->CKTstate0 + here->B2gbd) - + *(ckt->CKTstate0 + here->B2gmbs)) * delvbd - + *(ckt->CKTstate0 + here->B2gm) * delvgd + + *(ckt->CKTstate0 + here->B2gds) * delvds; + } + cbhat= + *(ckt->CKTstate0 + here->B2cbs) + + *(ckt->CKTstate0 + here->B2cbd) + + *(ckt->CKTstate0 + here->B2gbd) * delvbd + + *(ckt->CKTstate0 + here->B2gbs) * delvbs ; + +#ifndef NOBYPASS + /* now lets see if we can bypass (ugh) */ + + /* following should be one big if connected by && all over + * the place, but some C compilers can't handle that, so + * we split it up here to let them digest it in stages + */ + tempv = MAX(fabs(cbhat),fabs(*(ckt->CKTstate0 + here->B2cbs) + + *(ckt->CKTstate0 + here->B2cbd)))+ckt->CKTabstol; + if((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass) ) + if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->B2vbs)))+ + ckt->CKTvoltTol)) ) + if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->B2vbd)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->B2vgs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->B2vds)))+ + ckt->CKTvoltTol)) ) + if( (fabs(cdhat- *(ckt->CKTstate0 + here->B2cd)) < + ckt->CKTreltol * MAX(fabs(cdhat),fabs(*(ckt->CKTstate0 + + here->B2cd))) + ckt->CKTabstol) ) + if ( (fabs(cbhat-(*(ckt->CKTstate0 + here->B2cbs) + + *(ckt->CKTstate0 + here->B2cbd))) < ckt->CKTreltol * + tempv)) { + /* bypass code */ + vbs = *(ckt->CKTstate0 + here->B2vbs); + vbd = *(ckt->CKTstate0 + here->B2vbd); + vgs = *(ckt->CKTstate0 + here->B2vgs); + vds = *(ckt->CKTstate0 + here->B2vds); + vgd = vgs - vds; + vgb = vgs - vbs; + cd = *(ckt->CKTstate0 + here->B2cd); + cbs = *(ckt->CKTstate0 + here->B2cbs); + cbd = *(ckt->CKTstate0 + here->B2cbd); + cdrain = here->B2mode * (cd + cbd); + gm = *(ckt->CKTstate0 + here->B2gm); + gds = *(ckt->CKTstate0 + here->B2gds); + gmbs = *(ckt->CKTstate0 + here->B2gmbs); + gbd = *(ckt->CKTstate0 + here->B2gbd); + gbs = *(ckt->CKTstate0 + here->B2gbs); + if((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC))) { + cggb = *(ckt->CKTstate0 + here->B2cggb); + cgdb = *(ckt->CKTstate0 + here->B2cgdb); + cgsb = *(ckt->CKTstate0 + here->B2cgsb); + cbgb = *(ckt->CKTstate0 + here->B2cbgb); + cbdb = *(ckt->CKTstate0 + here->B2cbdb); + cbsb = *(ckt->CKTstate0 + here->B2cbsb); + cdgb = *(ckt->CKTstate0 + here->B2cdgb); + cddb = *(ckt->CKTstate0 + here->B2cddb); + cdsb = *(ckt->CKTstate0 + here->B2cdsb); + capbs = *(ckt->CKTstate0 + here->B2capbs); + capbd = *(ckt->CKTstate0 + here->B2capbd); + ByPass = 1; + goto line755; + } else { + goto line850; + } + } +#endif /*NOBYPASS*/ + + von = model->B2type * here->B2von; + if(*(ckt->CKTstate0 + here->B2vds) >=0) { + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->B2vgs) + ,von); + vds = vgs - vgd; + vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->B2vds)); + vgd = vgs - vds; + } else { + vgd = DEVfetlim(vgd,vgdo,von); + vds = vgs - vgd; + vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + + here->B2vds))); + vgs = vgd + vds; + } + if(vds >= 0) { + vcrit = CONSTvt0 *log(CONSTvt0/(CONSTroot2*SourceSatCurrent)); + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->B2vbs), + CONSTvt0,vcrit,&Check); /* B2 test */ + vbd = vbs-vds; + } else { + vcrit = CONSTvt0 * log(CONSTvt0/(CONSTroot2*DrainSatCurrent)); + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->B2vbd), + CONSTvt0,vcrit,&Check); /* B2 test*/ + vbs = vbd + vds; + } + } + + /* determine DC current and derivatives */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + + if(vbs <= 0.0 ) { + gbs = SourceSatCurrent / CONSTvt0 + ckt->CKTgmin; + cbs = gbs * vbs ; + } else { + evbs = exp(vbs/CONSTvt0); + gbs = SourceSatCurrent*evbs/CONSTvt0 + ckt->CKTgmin; + cbs = SourceSatCurrent * (evbs-1) + ckt->CKTgmin * vbs ; + } + if(vbd <= 0.0) { + gbd = DrainSatCurrent / CONSTvt0 + ckt->CKTgmin; + cbd = gbd * vbd ; + } else { + evbd = exp(vbd/CONSTvt0); + gbd = DrainSatCurrent*evbd/CONSTvt0 +ckt->CKTgmin; + cbd = DrainSatCurrent *(evbd-1)+ckt->CKTgmin*vbd; + } + /* line 400 */ + if(vds >= 0) { + /* normal mode */ + here->B2mode = 1; + } else { + /* inverse mode */ + here->B2mode = -1; + } + /* call B2evaluate to calculate drain current and its + * derivatives and charge and capacitances related to gate + * drain, and bulk + */ + if( vds >= 0 ) { + B2evaluate(vds,vbs,vgs,here,model,&gm,&gds,&gmbs,&qgate, + &qbulk,&qdrn,&cggb,&cgdb,&cgsb,&cbgb,&cbdb,&cbsb,&cdgb, + &cddb,&cdsb,&cdrain,&von,&vdsat,ckt); + } else { + B2evaluate(-vds,vbd,vgd,here,model,&gm,&gds,&gmbs,&qgate, + &qbulk,&qsrc,&cggb,&cgsb,&cgdb,&cbgb,&cbsb,&cbdb,&csgb, + &cssb,&csdb,&cdrain,&von,&vdsat,ckt); + } + + here->B2von = model->B2type * von; + here->B2vdsat = model->B2type * vdsat; + + + + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + cd=here->B2mode * cdrain - cbd; + if ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP ) && + (ckt->CKTmode & MODEUIC))) { + /* + * charge storage elements + * + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw:zero bias drain junction sidewall capacitance + * czbssw:zero bias source junction sidewall capacitance + */ + + czbd = model->B2unitAreaJctCap * DrainArea; + czbs = model->B2unitAreaJctCap * SourceArea; + czbdsw= model->B2unitLengthSidewallJctCap * DrainPerimeter; + czbssw= model->B2unitLengthSidewallJctCap * SourcePerimeter; + PhiB = model->B2bulkJctPotential; + PhiBSW = model->B2sidewallJctPotential; + MJ = model->B2bulkJctBotGradingCoeff; + MJSW = model->B2bulkJctSideGradingCoeff; + + /* Source Bulk Junction */ + if( vbs < 0 ) { + arg = 1 - vbs / PhiB; + argsw = 1 - vbs / PhiBSW; + sarg = exp(-MJ*log(arg)); + sargsw = exp(-MJSW*log(argsw)); + *(ckt->CKTstate0 + here->B2qbs) = + PhiB * czbs * (1-arg*sarg)/(1-MJ) + PhiBSW * + czbssw * (1-argsw*sargsw)/(1-MJSW); + capbs = czbs * sarg + czbssw * sargsw ; + } else { + *(ckt->CKTstate0+here->B2qbs) = + vbs*(czbs+czbssw)+ vbs*vbs*(czbs*MJ*0.5/PhiB + + czbssw * MJSW * 0.5/PhiBSW); + capbs = czbs + czbssw + vbs *(czbs*MJ/PhiB+ + czbssw * MJSW / PhiBSW ); + } + + /* Drain Bulk Junction */ + if( vbd < 0 ) { + arg = 1 - vbd / PhiB; + argsw = 1 - vbd / PhiBSW; + sarg = exp(-MJ*log(arg)); + sargsw = exp(-MJSW*log(argsw)); + *(ckt->CKTstate0 + here->B2qbd) = + PhiB * czbd * (1-arg*sarg)/(1-MJ) + PhiBSW * + czbdsw * (1-argsw*sargsw)/(1-MJSW); + capbd = czbd * sarg + czbdsw * sargsw ; + } else { + *(ckt->CKTstate0+here->B2qbd) = + vbd*(czbd+czbdsw)+ vbd*vbd*(czbd*MJ*0.5/PhiB + + czbdsw * MJSW * 0.5/PhiBSW); + capbd = czbd + czbdsw + vbd *(czbd*MJ/PhiB+ + czbdsw * MJSW / PhiBSW ); + } + + } + + + + + /* + * check convergence + */ + if ( (here->B2off == 0) || (!(ckt->CKTmode & MODEINITFIX)) ){ + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV + } else { + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol; + if (fabs(cdhat-cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } else { + tol=ckt->CKTreltol*MAX(fabs(cbhat),fabs(cbs+cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(cbs+cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } +#endif /* NEWCONV */ + } + } + *(ckt->CKTstate0 + here->B2vbs) = vbs; + *(ckt->CKTstate0 + here->B2vbd) = vbd; + *(ckt->CKTstate0 + here->B2vgs) = vgs; + *(ckt->CKTstate0 + here->B2vds) = vds; + *(ckt->CKTstate0 + here->B2cd) = cd; + *(ckt->CKTstate0 + here->B2cbs) = cbs; + *(ckt->CKTstate0 + here->B2cbd) = cbd; + *(ckt->CKTstate0 + here->B2gm) = gm; + *(ckt->CKTstate0 + here->B2gds) = gds; + *(ckt->CKTstate0 + here->B2gmbs) = gmbs; + *(ckt->CKTstate0 + here->B2gbd) = gbd; + *(ckt->CKTstate0 + here->B2gbs) = gbs; + + *(ckt->CKTstate0 + here->B2cggb) = cggb; + *(ckt->CKTstate0 + here->B2cgdb) = cgdb; + *(ckt->CKTstate0 + here->B2cgsb) = cgsb; + + *(ckt->CKTstate0 + here->B2cbgb) = cbgb; + *(ckt->CKTstate0 + here->B2cbdb) = cbdb; + *(ckt->CKTstate0 + here->B2cbsb) = cbsb; + + *(ckt->CKTstate0 + here->B2cdgb) = cdgb; + *(ckt->CKTstate0 + here->B2cddb) = cddb; + *(ckt->CKTstate0 + here->B2cdsb) = cdsb; + + *(ckt->CKTstate0 + here->B2capbs) = capbs; + *(ckt->CKTstate0 + here->B2capbd) = capbd; + + /* bulk and channel charge plus overlaps */ + + if((!(ckt->CKTmode & (MODETRAN | MODEAC))) && + ((!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC))) && (!(ckt->CKTmode + & MODEINITSMSIG))) goto line850; + +line755: + if( here->B2mode > 0 ) { + + args[0] = GateDrainOverlapCap; + args[1] = GateSourceOverlapCap; + args[2] = GateBulkOverlapCap; + args[3] = capbd; + args[4] = capbs; + args[5] = cggb; + args[6] = cgdb; + args[7] = cgsb; + + B2mosCap(ckt,vgd,vgs,vgb, + args, + /* + GateDrainOverlapCap, + GateSourceOverlapCap,GateBulkOverlapCap, + capbd,capbs,cggb,cgdb,cgsb, + */ + cbgb,cbdb,cbsb,cdgb,cddb,cdsb + ,&gcggb,&gcgdb,&gcgsb,&gcbgb,&gcbdb,&gcbsb,&gcdgb + ,&gcddb,&gcdsb,&gcsgb,&gcsdb,&gcssb,&qgate,&qbulk + ,&qdrn,&qsrc); + } else { + + args[0] = GateSourceOverlapCap; + args[1] = GateDrainOverlapCap; + args[2] = GateBulkOverlapCap; + args[3] = capbs; + args[4] = capbd; + args[5] = cggb; + args[6] = cgsb; + args[7] = cgdb; + + B2mosCap(ckt,vgs,vgd,vgb,args, + /* + GateSourceOverlapCap, + GateDrainOverlapCap,GateBulkOverlapCap, + capbs,capbd,cggb,cgsb,cgdb, + */ + cbgb,cbsb,cbdb,csgb,cssb,csdb + ,&gcggb,&gcgsb,&gcgdb,&gcbgb,&gcbsb,&gcbdb,&gcsgb + ,&gcssb,&gcsdb,&gcdgb,&gcdsb,&gcddb,&qgate,&qbulk + ,&qsrc,&qdrn); + } + + if(ByPass) goto line860; + *(ckt->CKTstate0 + here->B2qg) = qgate; + *(ckt->CKTstate0 + here->B2qd) = qdrn - + *(ckt->CKTstate0 + here->B2qbd); + *(ckt->CKTstate0 + here->B2qb) = qbulk + + *(ckt->CKTstate0 + here->B2qbd) + + *(ckt->CKTstate0 + here->B2qbs); + + /* store small signal parameters */ + if((!(ckt->CKTmode & (MODEAC | MODETRAN))) && + (ckt->CKTmode & MODETRANOP ) && (ckt->CKTmode & + MODEUIC )) goto line850; + if(ckt->CKTmode & MODEINITSMSIG ) { + *(ckt->CKTstate0+here->B2cggb) = cggb; + *(ckt->CKTstate0+here->B2cgdb) = cgdb; + *(ckt->CKTstate0+here->B2cgsb) = cgsb; + *(ckt->CKTstate0+here->B2cbgb) = cbgb; + *(ckt->CKTstate0+here->B2cbdb) = cbdb; + *(ckt->CKTstate0+here->B2cbsb) = cbsb; + *(ckt->CKTstate0+here->B2cdgb) = cdgb; + *(ckt->CKTstate0+here->B2cddb) = cddb; + *(ckt->CKTstate0+here->B2cdsb) = cdsb; + *(ckt->CKTstate0+here->B2capbd) = capbd; + *(ckt->CKTstate0+here->B2capbs) = capbs; + + goto line1000; + } + + if(ckt->CKTmode & MODEINITTRAN ) { + *(ckt->CKTstate1+here->B2qb) = + *(ckt->CKTstate0+here->B2qb) ; + *(ckt->CKTstate1+here->B2qg) = + *(ckt->CKTstate0+here->B2qg) ; + *(ckt->CKTstate1+here->B2qd) = + *(ckt->CKTstate0+here->B2qd) ; + } + + + error = NIintegrate(ckt,&geq,&ceq,0.0,here->B2qb); + if(error) return(error); + error = NIintegrate(ckt,&geq,&ceq,0.0,here->B2qg); + if(error) return(error); + error = NIintegrate(ckt,&geq,&ceq,0.0,here->B2qd); + if(error) return(error); + + goto line860; + +line850: + /* initialize to zero charge conductance and current */ + ceqqg = ceqqb = ceqqd = 0.0; + gcdgb = gcddb = gcdsb = 0.0; + gcsgb = gcsdb = gcssb = 0.0; + gcggb = gcgdb = gcgsb = 0.0; + gcbgb = gcbdb = gcbsb = 0.0; + goto line900; + +line860: + /* evaluate equivalent charge current */ + cqgate = *(ckt->CKTstate0 + here->B2iqg); + cqbulk = *(ckt->CKTstate0 + here->B2iqb); + cqdrn = *(ckt->CKTstate0 + here->B2iqd); + ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; + ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs; + ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs; + + if(ckt->CKTmode & MODEINITTRAN ) { + *(ckt->CKTstate1 + here->B2iqb) = + *(ckt->CKTstate0 + here->B2iqb); + *(ckt->CKTstate1 + here->B2iqg) = + *(ckt->CKTstate0 + here->B2iqg); + *(ckt->CKTstate1 + here->B2iqd) = + *(ckt->CKTstate0 + here->B2iqd); + } + + /* + * load current vector + */ +line900: + + ceqbs = model->B2type * (cbs-(gbs-ckt->CKTgmin)*vbs); + ceqbd = model->B2type * (cbd-(gbd-ckt->CKTgmin)*vbd); + + ceqqg = model->B2type * ceqqg; + ceqqb = model->B2type * ceqqb; + ceqqd = model->B2type * ceqqd; + if (here->B2mode >= 0) { + xnrm=1; + xrev=0; + cdreq=model->B2type*(cdrain-gds*vds-gm*vgs-gmbs*vbs); + } else { + xnrm=0; + xrev=1; + cdreq = -(model->B2type)*(cdrain+gds*vds-gm*vgd-gmbs*vbd); + } + + *(ckt->CKTrhs + here->B2gNode) -= ceqqg; + *(ckt->CKTrhs + here->B2bNode) -=(ceqbs+ceqbd+ceqqb); + *(ckt->CKTrhs + here->B2dNodePrime) += + (ceqbd-cdreq-ceqqd); + *(ckt->CKTrhs + here->B2sNodePrime) += + (cdreq+ceqbs+ceqqg+ceqqb+ceqqd); + + /* + * load y matrix + */ + + *(here->B2DdPtr) += (here->B2drainConductance); + *(here->B2GgPtr) += (gcggb); + *(here->B2SsPtr) += (here->B2sourceConductance); + *(here->B2BbPtr) += (gbd+gbs-gcbgb-gcbdb-gcbsb); + *(here->B2DPdpPtr) += + (here->B2drainConductance+gds+gbd+xrev*(gm+gmbs)+gcddb); + *(here->B2SPspPtr) += + (here->B2sourceConductance+gds+gbs+xnrm*(gm+gmbs)+gcssb); + *(here->B2DdpPtr) += (-here->B2drainConductance); + *(here->B2GbPtr) += (-gcggb-gcgdb-gcgsb); + *(here->B2GdpPtr) += (gcgdb); + *(here->B2GspPtr) += (gcgsb); + *(here->B2SspPtr) += (-here->B2sourceConductance); + *(here->B2BgPtr) += (gcbgb); + *(here->B2BdpPtr) += (-gbd+gcbdb); + *(here->B2BspPtr) += (-gbs+gcbsb); + *(here->B2DPdPtr) += (-here->B2drainConductance); + *(here->B2DPgPtr) += ((xnrm-xrev)*gm+gcdgb); + *(here->B2DPbPtr) += (-gbd+(xnrm-xrev)*gmbs-gcdgb-gcddb-gcdsb); + *(here->B2DPspPtr) += (-gds-xnrm*(gm+gmbs)+gcdsb); + *(here->B2SPgPtr) += (-(xnrm-xrev)*gm+gcsgb); + *(here->B2SPsPtr) += (-here->B2sourceConductance); + *(here->B2SPbPtr) += (-gbs-(xnrm-xrev)*gmbs-gcsgb-gcsdb-gcssb); + *(here->B2SPdpPtr) += (-gds-xrev*(gm+gmbs)+gcsdb); + + +line1000: ; + + } /* End of Mosfet Instance */ + + } /* End of Model Instance */ + return(OK); +} + diff --git a/src/spicelib/devices/bsim2/b2mask.c b/src/spicelib/devices/bsim2/b2mask.c new file mode 100644 index 000000000..f2e8c2873 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2mask.c @@ -0,0 +1,433 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Hong J. Park +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim2def.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +B2mAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + B2model *model = (B2model *)inst; + switch(which) { + case BSIM2_MOD_VFB0: + value->rValue = model->B2vfb0; + return(OK); + case BSIM2_MOD_VFBL : + value->rValue = model->B2vfbL; + return(OK); + case BSIM2_MOD_VFBW : + value->rValue = model->B2vfbW; + return(OK); + case BSIM2_MOD_PHI0 : + value->rValue = model->B2phi0; + return(OK); + case BSIM2_MOD_PHIL : + value->rValue = model->B2phiL; + return(OK); + case BSIM2_MOD_PHIW : + value->rValue = model->B2phiW; + return(OK); + case BSIM2_MOD_K10 : + value->rValue = model->B2k10; + return(OK); + case BSIM2_MOD_K1L : + value->rValue = model->B2k1L; + return(OK); + case BSIM2_MOD_K1W : + value->rValue = model->B2k1W; + return(OK); + case BSIM2_MOD_K20 : + value->rValue = model->B2k20; + return(OK); + case BSIM2_MOD_K2L : + value->rValue = model->B2k2L; + return(OK); + case BSIM2_MOD_K2W : + value->rValue = model->B2k2W; + return(OK); + case BSIM2_MOD_ETA00 : + value->rValue = model->B2eta00; + return(OK); + case BSIM2_MOD_ETA0L : + value->rValue = model->B2eta0L; + return(OK); + case BSIM2_MOD_ETA0W : + value->rValue = model->B2eta0W; + return(OK); + case BSIM2_MOD_ETAB0 : + value->rValue = model->B2etaB0; + return(OK); + case BSIM2_MOD_ETABL : + value->rValue = model->B2etaBL; + return(OK); + case BSIM2_MOD_ETABW : + value->rValue = model->B2etaBW; + return(OK); + case BSIM2_MOD_DELTAL : + value->rValue = model->B2deltaL = value->rValue; + return(OK); + case BSIM2_MOD_DELTAW : + value->rValue = model->B2deltaW = value->rValue; + return(OK); + case BSIM2_MOD_MOB00 : + value->rValue = model->B2mob00; + return(OK); + case BSIM2_MOD_MOB0B0 : + value->rValue = model->B2mob0B0; + return(OK); + case BSIM2_MOD_MOB0BL : + value->rValue = model->B2mob0BL; + return(OK); + case BSIM2_MOD_MOB0BW : + value->rValue = model->B2mob0BW; + return(OK); + case BSIM2_MOD_MOBS00 : + value->rValue = model->B2mobs00; + return(OK); + case BSIM2_MOD_MOBS0L : + value->rValue = model->B2mobs0L; + return(OK); + case BSIM2_MOD_MOBS0W : + value->rValue = model->B2mobs0W; + return(OK); + case BSIM2_MOD_MOBSB0 : + value->rValue = model->B2mobsB0; + return(OK); + case BSIM2_MOD_MOBSBL : + value->rValue = model->B2mobsBL; + return(OK); + case BSIM2_MOD_MOBSBW : + value->rValue = model->B2mobsBW; + return(OK); + case BSIM2_MOD_MOB200 : + value->rValue = model->B2mob200; + return(OK); + case BSIM2_MOD_MOB20L : + value->rValue = model->B2mob20L; + return(OK); + case BSIM2_MOD_MOB20W : + value->rValue = model->B2mob20W; + return(OK); + case BSIM2_MOD_MOB2B0 : + value->rValue = model->B2mob2B0; + return(OK); + case BSIM2_MOD_MOB2BL : + value->rValue = model->B2mob2BL; + return(OK); + case BSIM2_MOD_MOB2BW : + value->rValue = model->B2mob2BW; + return(OK); + case BSIM2_MOD_MOB2G0 : + value->rValue = model->B2mob2G0; + return(OK); + case BSIM2_MOD_MOB2GL : + value->rValue = model->B2mob2GL; + return(OK); + case BSIM2_MOD_MOB2GW : + value->rValue = model->B2mob2GW; + return(OK); + case BSIM2_MOD_MOB300 : + value->rValue = model->B2mob300; + return(OK); + case BSIM2_MOD_MOB30L : + value->rValue = model->B2mob30L; + return(OK); + case BSIM2_MOD_MOB30W : + value->rValue = model->B2mob30W; + return(OK); + case BSIM2_MOD_MOB3B0 : + value->rValue = model->B2mob3B0; + return(OK); + case BSIM2_MOD_MOB3BL : + value->rValue = model->B2mob3BL; + return(OK); + case BSIM2_MOD_MOB3BW : + value->rValue = model->B2mob3BW; + return(OK); + case BSIM2_MOD_MOB3G0 : + value->rValue = model->B2mob3G0; + return(OK); + case BSIM2_MOD_MOB3GL : + value->rValue = model->B2mob3GL; + return(OK); + case BSIM2_MOD_MOB3GW : + value->rValue = model->B2mob3GW; + return(OK); + case BSIM2_MOD_MOB400 : + value->rValue = model->B2mob400; + return(OK); + case BSIM2_MOD_MOB40L : + value->rValue = model->B2mob40L; + return(OK); + case BSIM2_MOD_MOB40W : + value->rValue = model->B2mob40W; + return(OK); + case BSIM2_MOD_MOB4B0 : + value->rValue = model->B2mob4B0; + return(OK); + case BSIM2_MOD_MOB4BL : + value->rValue = model->B2mob4BL; + return(OK); + case BSIM2_MOD_MOB4BW : + value->rValue = model->B2mob4BW; + return(OK); + case BSIM2_MOD_MOB4G0 : + value->rValue = model->B2mob4G0; + return(OK); + case BSIM2_MOD_MOB4GL : + value->rValue = model->B2mob4GL; + return(OK); + case BSIM2_MOD_MOB4GW : + value->rValue = model->B2mob4GW; + return(OK); + case BSIM2_MOD_UA00 : + value->rValue = model->B2ua00; + return(OK); + case BSIM2_MOD_UA0L : + value->rValue = model->B2ua0L; + return(OK); + case BSIM2_MOD_UA0W : + value->rValue = model->B2ua0W; + return(OK); + case BSIM2_MOD_UAB0 : + value->rValue = model->B2uaB0; + return(OK); + case BSIM2_MOD_UABL : + value->rValue = model->B2uaBL; + return(OK); + case BSIM2_MOD_UABW : + value->rValue = model->B2uaBW; + return(OK); + case BSIM2_MOD_UB00 : + value->rValue = model->B2ub00; + return(OK); + case BSIM2_MOD_UB0L : + value->rValue = model->B2ub0L; + return(OK); + case BSIM2_MOD_UB0W : + value->rValue = model->B2ub0W; + return(OK); + case BSIM2_MOD_UBB0 : + value->rValue = model->B2ubB0; + return(OK); + case BSIM2_MOD_UBBL : + value->rValue = model->B2ubBL; + return(OK); + case BSIM2_MOD_UBBW : + value->rValue = model->B2ubBW; + return(OK); + case BSIM2_MOD_U100 : + value->rValue = model->B2u100; + return(OK); + case BSIM2_MOD_U10L : + value->rValue = model->B2u10L; + return(OK); + case BSIM2_MOD_U10W : + value->rValue = model->B2u10W; + return(OK); + case BSIM2_MOD_U1B0 : + value->rValue = model->B2u1B0; + return(OK); + case BSIM2_MOD_U1BL : + value->rValue = model->B2u1BL; + return(OK); + case BSIM2_MOD_U1BW : + value->rValue = model->B2u1BW; + return(OK); + case BSIM2_MOD_U1D0 : + value->rValue = model->B2u1D0; + return(OK); + case BSIM2_MOD_U1DL : + value->rValue = model->B2u1DL; + return(OK); + case BSIM2_MOD_U1DW : + value->rValue = model->B2u1DW; + return(OK); + case BSIM2_MOD_N00 : + value->rValue = model->B2n00; + return(OK); + case BSIM2_MOD_N0L : + value->rValue = model->B2n0L; + return(OK); + case BSIM2_MOD_N0W : + value->rValue = model->B2n0W; + return(OK); + case BSIM2_MOD_NB0 : + value->rValue = model->B2nB0; + return(OK); + case BSIM2_MOD_NBL : + value->rValue = model->B2nBL; + return(OK); + case BSIM2_MOD_NBW : + value->rValue = model->B2nBW; + return(OK); + case BSIM2_MOD_ND0 : + value->rValue = model->B2nD0; + return(OK); + case BSIM2_MOD_NDL : + value->rValue = model->B2nDL; + return(OK); + case BSIM2_MOD_NDW : + value->rValue = model->B2nDW; + return(OK); + case BSIM2_MOD_VOF00 : + value->rValue = model->B2vof00; + return(OK); + case BSIM2_MOD_VOF0L : + value->rValue = model->B2vof0L; + return(OK); + case BSIM2_MOD_VOF0W : + value->rValue = model->B2vof0W; + return(OK); + case BSIM2_MOD_VOFB0 : + value->rValue = model->B2vofB0; + return(OK); + case BSIM2_MOD_VOFBL : + value->rValue = model->B2vofBL; + return(OK); + case BSIM2_MOD_VOFBW : + value->rValue = model->B2vofBW; + return(OK); + case BSIM2_MOD_VOFD0 : + value->rValue = model->B2vofD0; + return(OK); + case BSIM2_MOD_VOFDL : + value->rValue = model->B2vofDL; + return(OK); + case BSIM2_MOD_VOFDW : + value->rValue = model->B2vofDW; + return(OK); + case BSIM2_MOD_AI00 : + value->rValue = model->B2ai00; + return(OK); + case BSIM2_MOD_AI0L : + value->rValue = model->B2ai0L; + return(OK); + case BSIM2_MOD_AI0W : + value->rValue = model->B2ai0W; + return(OK); + case BSIM2_MOD_AIB0 : + value->rValue = model->B2aiB0; + return(OK); + case BSIM2_MOD_AIBL : + value->rValue = model->B2aiBL; + return(OK); + case BSIM2_MOD_AIBW : + value->rValue = model->B2aiBW; + return(OK); + case BSIM2_MOD_BI00 : + value->rValue = model->B2bi00; + return(OK); + case BSIM2_MOD_BI0L : + value->rValue = model->B2bi0L; + return(OK); + case BSIM2_MOD_BI0W : + value->rValue = model->B2bi0W; + return(OK); + case BSIM2_MOD_BIB0 : + value->rValue = model->B2biB0; + return(OK); + case BSIM2_MOD_BIBL : + value->rValue = model->B2biBL; + return(OK); + case BSIM2_MOD_BIBW : + value->rValue = model->B2biBW; + return(OK); + case BSIM2_MOD_VGHIGH0 : + value->rValue = model->B2vghigh0; + return(OK); + case BSIM2_MOD_VGHIGHL : + value->rValue = model->B2vghighL; + return(OK); + case BSIM2_MOD_VGHIGHW : + value->rValue = model->B2vghighW; + return(OK); + case BSIM2_MOD_VGLOW0 : + value->rValue = model->B2vglow0; + return(OK); + case BSIM2_MOD_VGLOWL : + value->rValue = model->B2vglowL; + return(OK); + case BSIM2_MOD_VGLOWW : + value->rValue = model->B2vglowW; + return(OK); + case BSIM2_MOD_TOX : + value->rValue = model->B2tox; + return(OK); + case BSIM2_MOD_TEMP : + value->rValue = model->B2temp; + return(OK); + case BSIM2_MOD_VDD : + value->rValue = model->B2vdd; + return(OK); + case BSIM2_MOD_VGG : + value->rValue = model->B2vgg; + return(OK); + case BSIM2_MOD_VBB : + value->rValue = model->B2vbb; + return(OK); + case BSIM2_MOD_CGSO: + value->rValue = model->B2gateSourceOverlapCap; + return(OK); + case BSIM2_MOD_CGDO: + value->rValue = model->B2gateDrainOverlapCap; + return(OK); + case BSIM2_MOD_CGBO: + value->rValue = model->B2gateBulkOverlapCap; + return(OK); + case BSIM2_MOD_XPART: + value->iValue = model->B2channelChargePartitionFlag; + return(OK); + case BSIM2_MOD_RSH: + value->rValue = model->B2sheetResistance; + return(OK); + case BSIM2_MOD_JS: + value->rValue = model->B2jctSatCurDensity; + return(OK); + case BSIM2_MOD_PB: + value->rValue = model->B2bulkJctPotential; + return(OK); + case BSIM2_MOD_MJ: + value->rValue = model->B2bulkJctBotGradingCoeff; + return(OK); + case BSIM2_MOD_PBSW: + value->rValue = model->B2sidewallJctPotential; + return(OK); + case BSIM2_MOD_MJSW: + value->rValue = model->B2bulkJctSideGradingCoeff; + return(OK); + case BSIM2_MOD_CJ: + value->rValue = model->B2unitAreaJctCap; + return(OK); + case BSIM2_MOD_CJSW: + value->rValue = model->B2unitLengthSidewallJctCap; + return(OK); + case BSIM2_MOD_DEFWIDTH: + value->rValue = model->B2defaultWidth; + return(OK); + case BSIM2_MOD_DELLENGTH: + value->rValue = model->B2deltaLength; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + + diff --git a/src/spicelib/devices/bsim2/b2mdel.c b/src/spicelib/devices/bsim2/b2mdel.c new file mode 100644 index 000000000..69992b73a --- /dev/null +++ b/src/spicelib/devices/bsim2/b2mdel.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim2def.h" +#include "sperror.h" +#include "suffix.h" + + +int +B2mDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + B2model **model = (B2model**)inModel; + B2model *modfast = (B2model*)kill; + B2instance *here; + B2instance *prev = NULL; + B2model **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->B2nextModel)) { + if( (*model)->B2modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->B2nextModel; /* cut deleted device out of list */ + for(here = (*model)->B2instances ; here ; here = here->B2nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} + diff --git a/src/spicelib/devices/bsim2/b2moscap.c b/src/spicelib/devices/bsim2/b2moscap.c new file mode 100644 index 000000000..0071bbfb0 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2moscap.c @@ -0,0 +1,101 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim2def.h" +#include "suffix.h" + +/* routine to calculate equivalent conductance and total terminal + * charges + */ + +void +B2mosCap(ckt,vgd,vgs,vgb, + args, + /* + GateDrainOverlapCap,GateSourceOverlapCap, GateBulkOverlapCap, + capbd,capbs, + cggb,cgdb,cgsb, + */ + cbgb,cbdb,cbsb,cdgb,cddb,cdsb, + gcggbPointer,gcgdbPointer,gcgsbPointer,gcbgbPointer,gcbdbPointer, + gcbsbPointer,gcdgbPointer,gcddbPointer,gcdsbPointer, + gcsgbPointer,gcsdbPointer,gcssbPointer,qGatePointer,qBulkPointer, + qDrainPointer,qSourcePointer) + register CKTcircuit *ckt; + double vgd; + double vgs; + double vgb; + double args[8]; + /* + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double GateBulkOverlapCap; + double capbd; + double capbs; + double cggb; + double cgdb; + double cgsb; + */ + double cbgb; + double cbdb; + double cbsb; + double cdgb; + double cddb; + double cdsb; + double *gcggbPointer; + double *gcgdbPointer; + double *gcgsbPointer; + double *gcbgbPointer; + double *gcbdbPointer; + double *gcbsbPointer; + double *gcdgbPointer; + double *gcddbPointer; + double *gcdsbPointer; + double *gcsgbPointer; + double *gcsdbPointer; + double *gcssbPointer; + double *qGatePointer; + double *qBulkPointer; + double *qDrainPointer; + double *qSourcePointer; + +{ + double qgd; + double qgs; + double qgb; + double ag0; + + ag0 = ckt->CKTag[0]; + /* compute equivalent conductance */ + *gcdgbPointer = (cdgb - args[0]) * ag0; + *gcddbPointer = (cddb + args[3] + args[0]) * ag0; + *gcdsbPointer = cdsb * ag0; + *gcsgbPointer = -(args[5] + cbgb + cdgb + args[1]) * ag0; + *gcsdbPointer = -(args[6] + cbdb + cddb ) * ag0; + *gcssbPointer = (args[4] + args[1] - + (args[7] + cbsb + cdsb )) * ag0; + *gcggbPointer = (args[5] + args[0] + + args[1] + args[2] ) * ag0; + *gcgdbPointer = (args[6] - args[0]) * ag0; + *gcgsbPointer = (args[7] - args[1]) * ag0; + *gcbgbPointer = (cbgb - args[2]) * ag0; + *gcbdbPointer = (cbdb - args[3]) * ag0; + *gcbsbPointer = (cbsb - args[4]) * ag0; + + /* compute total terminal charge */ + qgd = args[0] * vgd; + qgs = args[1] * vgs; + qgb = args[2] * vgb; + *qGatePointer = *qGatePointer + qgd + qgs + qgb; + *qBulkPointer = *qBulkPointer - qgb; + *qDrainPointer = *qDrainPointer - qgd; + *qSourcePointer = -(*qGatePointer + *qBulkPointer + *qDrainPointer); + +} + + diff --git a/src/spicelib/devices/bsim2/b2mpar.c b/src/spicelib/devices/bsim2/b2mpar.c new file mode 100644 index 000000000..090885ba3 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2mpar.c @@ -0,0 +1,572 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Min-Chie Jeng, Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim2def.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +int +B2mParam(param,value,inMod) + int param; + IFvalue *value; + GENmodel *inMod; +{ + B2model *mod = (B2model*)inMod; + switch(param) { + case BSIM2_MOD_VFB0 : + mod->B2vfb0 = value->rValue; + mod->B2vfb0Given = TRUE; + break; + case BSIM2_MOD_VFBL : + mod->B2vfbL = value->rValue; + mod->B2vfbLGiven = TRUE; + break; + case BSIM2_MOD_VFBW : + mod->B2vfbW = value->rValue; + mod->B2vfbWGiven = TRUE; + break; + case BSIM2_MOD_PHI0 : + mod->B2phi0 = value->rValue; + mod->B2phi0Given = TRUE; + break; + case BSIM2_MOD_PHIL : + mod->B2phiL = value->rValue; + mod->B2phiLGiven = TRUE; + break; + case BSIM2_MOD_PHIW : + mod->B2phiW = value->rValue; + mod->B2phiWGiven = TRUE; + break; + case BSIM2_MOD_K10 : + mod->B2k10 = value->rValue; + mod->B2k10Given = TRUE; + break; + case BSIM2_MOD_K1L : + mod->B2k1L = value->rValue; + mod->B2k1LGiven = TRUE; + break; + case BSIM2_MOD_K1W : + mod->B2k1W = value->rValue; + mod->B2k1WGiven = TRUE; + break; + case BSIM2_MOD_K20 : + mod->B2k20 = value->rValue; + mod->B2k20Given = TRUE; + break; + case BSIM2_MOD_K2L : + mod->B2k2L = value->rValue; + mod->B2k2LGiven = TRUE; + break; + case BSIM2_MOD_K2W : + mod->B2k2W = value->rValue; + mod->B2k2WGiven = TRUE; + break; + case BSIM2_MOD_ETA00 : + mod->B2eta00 = value->rValue; + mod->B2eta00Given = TRUE; + break; + case BSIM2_MOD_ETA0L : + mod->B2eta0L = value->rValue; + mod->B2eta0LGiven = TRUE; + break; + case BSIM2_MOD_ETA0W : + mod->B2eta0W = value->rValue; + mod->B2eta0WGiven = TRUE; + break; + case BSIM2_MOD_ETAB0 : + mod->B2etaB0 = value->rValue; + mod->B2etaB0Given = TRUE; + break; + case BSIM2_MOD_ETABL : + mod->B2etaBL = value->rValue; + mod->B2etaBLGiven = TRUE; + break; + case BSIM2_MOD_ETABW : + mod->B2etaBW = value->rValue; + mod->B2etaBWGiven = TRUE; + break; + case BSIM2_MOD_DELTAL : + mod->B2deltaL = value->rValue; + mod->B2deltaLGiven = TRUE; + break; + case BSIM2_MOD_DELTAW : + mod->B2deltaW = value->rValue; + mod->B2deltaWGiven = TRUE; + break; + case BSIM2_MOD_MOB00 : + mod->B2mob00 = value->rValue; + mod->B2mob00Given = TRUE; + break; + case BSIM2_MOD_MOB0B0 : + mod->B2mob0B0 = value->rValue; + mod->B2mob0B0Given = TRUE; + break; + case BSIM2_MOD_MOB0BL : + mod->B2mob0BL = value->rValue; + mod->B2mob0BLGiven = TRUE; + break; + case BSIM2_MOD_MOB0BW : + mod->B2mob0BW = value->rValue; + mod->B2mob0BWGiven = TRUE; + break; + case BSIM2_MOD_MOBS00 : + mod->B2mobs00 = value->rValue; + mod->B2mobs00Given = TRUE; + break; + case BSIM2_MOD_MOBS0L : + mod->B2mobs0L = value->rValue; + mod->B2mobs0LGiven = TRUE; + break; + case BSIM2_MOD_MOBS0W : + mod->B2mobs0W = value->rValue; + mod->B2mobs0WGiven = TRUE; + break; + case BSIM2_MOD_MOBSB0 : + mod->B2mobsB0 = value->rValue; + mod->B2mobsB0Given = TRUE; + break; + case BSIM2_MOD_MOBSBL : + mod->B2mobsBL = value->rValue; + mod->B2mobsBLGiven = TRUE; + break; + case BSIM2_MOD_MOBSBW : + mod->B2mobsBW = value->rValue; + mod->B2mobsBWGiven = TRUE; + break; + case BSIM2_MOD_MOB200 : + mod->B2mob200 = value->rValue; + mod->B2mob200Given = TRUE; + break; + case BSIM2_MOD_MOB20L : + mod->B2mob20L = value->rValue; + mod->B2mob20LGiven = TRUE; + break; + case BSIM2_MOD_MOB20W : + mod->B2mob20W = value->rValue; + mod->B2mob20WGiven = TRUE; + break; + case BSIM2_MOD_MOB2B0 : + mod->B2mob2B0 = value->rValue; + mod->B2mob2B0Given = TRUE; + break; + case BSIM2_MOD_MOB2BL : + mod->B2mob2BL = value->rValue; + mod->B2mob2BLGiven = TRUE; + break; + case BSIM2_MOD_MOB2BW : + mod->B2mob2BW = value->rValue; + mod->B2mob2BWGiven = TRUE; + break; + case BSIM2_MOD_MOB2G0 : + mod->B2mob2G0 = value->rValue; + mod->B2mob2G0Given = TRUE; + break; + case BSIM2_MOD_MOB2GL : + mod->B2mob2GL = value->rValue; + mod->B2mob2GLGiven = TRUE; + break; + case BSIM2_MOD_MOB2GW : + mod->B2mob2GW = value->rValue; + mod->B2mob2GWGiven = TRUE; + break; + case BSIM2_MOD_MOB300 : + mod->B2mob300 = value->rValue; + mod->B2mob300Given = TRUE; + break; + case BSIM2_MOD_MOB30L : + mod->B2mob30L = value->rValue; + mod->B2mob30LGiven = TRUE; + break; + case BSIM2_MOD_MOB30W : + mod->B2mob30W = value->rValue; + mod->B2mob30WGiven = TRUE; + break; + case BSIM2_MOD_MOB3B0 : + mod->B2mob3B0 = value->rValue; + mod->B2mob3B0Given = TRUE; + break; + case BSIM2_MOD_MOB3BL : + mod->B2mob3BL = value->rValue; + mod->B2mob3BLGiven = TRUE; + break; + case BSIM2_MOD_MOB3BW : + mod->B2mob3BW = value->rValue; + mod->B2mob3BWGiven = TRUE; + break; + case BSIM2_MOD_MOB3G0 : + mod->B2mob3G0 = value->rValue; + mod->B2mob3G0Given = TRUE; + break; + case BSIM2_MOD_MOB3GL : + mod->B2mob3GL = value->rValue; + mod->B2mob3GLGiven = TRUE; + break; + case BSIM2_MOD_MOB3GW : + mod->B2mob3GW = value->rValue; + mod->B2mob3GWGiven = TRUE; + break; + case BSIM2_MOD_MOB400 : + mod->B2mob400 = value->rValue; + mod->B2mob400Given = TRUE; + break; + case BSIM2_MOD_MOB40L : + mod->B2mob40L = value->rValue; + mod->B2mob40LGiven = TRUE; + break; + case BSIM2_MOD_MOB40W : + mod->B2mob40W = value->rValue; + mod->B2mob40WGiven = TRUE; + break; + case BSIM2_MOD_MOB4B0 : + mod->B2mob4B0 = value->rValue; + mod->B2mob4B0Given = TRUE; + break; + case BSIM2_MOD_MOB4BL : + mod->B2mob4BL = value->rValue; + mod->B2mob4BLGiven = TRUE; + break; + case BSIM2_MOD_MOB4BW : + mod->B2mob4BW = value->rValue; + mod->B2mob4BWGiven = TRUE; + break; + case BSIM2_MOD_MOB4G0 : + mod->B2mob4G0 = value->rValue; + mod->B2mob4G0Given = TRUE; + break; + case BSIM2_MOD_MOB4GL : + mod->B2mob4GL = value->rValue; + mod->B2mob4GLGiven = TRUE; + break; + case BSIM2_MOD_MOB4GW : + mod->B2mob4GW = value->rValue; + mod->B2mob4GWGiven = TRUE; + break; + case BSIM2_MOD_UA00 : + mod->B2ua00 = value->rValue; + mod->B2ua00Given = TRUE; + break; + case BSIM2_MOD_UA0L : + mod->B2ua0L = value->rValue; + mod->B2ua0LGiven = TRUE; + break; + case BSIM2_MOD_UA0W : + mod->B2ua0W = value->rValue; + mod->B2ua0WGiven = TRUE; + break; + case BSIM2_MOD_UAB0 : + mod->B2uaB0 = value->rValue; + mod->B2uaB0Given = TRUE; + break; + case BSIM2_MOD_UABL : + mod->B2uaBL = value->rValue; + mod->B2uaBLGiven = TRUE; + break; + case BSIM2_MOD_UABW : + mod->B2uaBW = value->rValue; + mod->B2uaBWGiven = TRUE; + break; + case BSIM2_MOD_UB00 : + mod->B2ub00 = value->rValue; + mod->B2ub00Given = TRUE; + break; + case BSIM2_MOD_UB0L : + mod->B2ub0L = value->rValue; + mod->B2ub0LGiven = TRUE; + break; + case BSIM2_MOD_UB0W : + mod->B2ub0W = value->rValue; + mod->B2ub0WGiven = TRUE; + break; + case BSIM2_MOD_UBB0 : + mod->B2ubB0 = value->rValue; + mod->B2ubB0Given = TRUE; + break; + case BSIM2_MOD_UBBL : + mod->B2ubBL = value->rValue; + mod->B2ubBLGiven = TRUE; + break; + case BSIM2_MOD_UBBW : + mod->B2ubBW = value->rValue; + mod->B2ubBWGiven = TRUE; + break; + case BSIM2_MOD_U100 : + mod->B2u100 = value->rValue; + mod->B2u100Given = TRUE; + break; + case BSIM2_MOD_U10L : + mod->B2u10L = value->rValue; + mod->B2u10LGiven = TRUE; + break; + case BSIM2_MOD_U10W : + mod->B2u10W = value->rValue; + mod->B2u10WGiven = TRUE; + break; + case BSIM2_MOD_U1B0 : + mod->B2u1B0 = value->rValue; + mod->B2u1B0Given = TRUE; + break; + case BSIM2_MOD_U1BL : + mod->B2u1BL = value->rValue; + mod->B2u1BLGiven = TRUE; + break; + case BSIM2_MOD_U1BW : + mod->B2u1BW = value->rValue; + mod->B2u1BWGiven = TRUE; + break; + case BSIM2_MOD_U1D0 : + mod->B2u1D0 = value->rValue; + mod->B2u1D0Given = TRUE; + break; + case BSIM2_MOD_U1DL : + mod->B2u1DL = value->rValue; + mod->B2u1DLGiven = TRUE; + break; + case BSIM2_MOD_U1DW : + mod->B2u1DW = value->rValue; + mod->B2u1DWGiven = TRUE; + break; + case BSIM2_MOD_N00 : + mod->B2n00 = value->rValue; + mod->B2n00Given = TRUE; + break; + case BSIM2_MOD_N0L : + mod->B2n0L = value->rValue; + mod->B2n0LGiven = TRUE; + break; + case BSIM2_MOD_N0W : + mod->B2n0W = value->rValue; + mod->B2n0WGiven = TRUE; + break; + case BSIM2_MOD_NB0 : + mod->B2nB0 = value->rValue; + mod->B2nB0Given = TRUE; + break; + case BSIM2_MOD_NBL : + mod->B2nBL = value->rValue; + mod->B2nBLGiven = TRUE; + break; + case BSIM2_MOD_NBW : + mod->B2nBW = value->rValue; + mod->B2nBWGiven = TRUE; + break; + case BSIM2_MOD_ND0 : + mod->B2nD0 = value->rValue; + mod->B2nD0Given = TRUE; + break; + case BSIM2_MOD_NDL : + mod->B2nDL = value->rValue; + mod->B2nDLGiven = TRUE; + break; + case BSIM2_MOD_NDW : + mod->B2nDW = value->rValue; + mod->B2nDWGiven = TRUE; + break; + case BSIM2_MOD_VOF00 : + mod->B2vof00 = value->rValue; + mod->B2vof00Given = TRUE; + break; + case BSIM2_MOD_VOF0L : + mod->B2vof0L = value->rValue; + mod->B2vof0LGiven = TRUE; + break; + case BSIM2_MOD_VOF0W : + mod->B2vof0W = value->rValue; + mod->B2vof0WGiven = TRUE; + break; + case BSIM2_MOD_VOFB0 : + mod->B2vofB0 = value->rValue; + mod->B2vofB0Given = TRUE; + break; + case BSIM2_MOD_VOFBL : + mod->B2vofBL = value->rValue; + mod->B2vofBLGiven = TRUE; + break; + case BSIM2_MOD_VOFBW : + mod->B2vofBW = value->rValue; + mod->B2vofBWGiven = TRUE; + break; + case BSIM2_MOD_VOFD0 : + mod->B2vofD0 = value->rValue; + mod->B2vofD0Given = TRUE; + break; + case BSIM2_MOD_VOFDL : + mod->B2vofDL = value->rValue; + mod->B2vofDLGiven = TRUE; + break; + case BSIM2_MOD_VOFDW : + mod->B2vofDW = value->rValue; + mod->B2vofDWGiven = TRUE; + break; + case BSIM2_MOD_AI00 : + mod->B2ai00 = value->rValue; + mod->B2ai00Given = TRUE; + break; + case BSIM2_MOD_AI0L : + mod->B2ai0L = value->rValue; + mod->B2ai0LGiven = TRUE; + break; + case BSIM2_MOD_AI0W : + mod->B2ai0W = value->rValue; + mod->B2ai0WGiven = TRUE; + break; + case BSIM2_MOD_AIB0 : + mod->B2aiB0 = value->rValue; + mod->B2aiB0Given = TRUE; + break; + case BSIM2_MOD_AIBL : + mod->B2aiBL = value->rValue; + mod->B2aiBLGiven = TRUE; + break; + case BSIM2_MOD_AIBW : + mod->B2aiBW = value->rValue; + mod->B2aiBWGiven = TRUE; + break; + case BSIM2_MOD_BI00 : + mod->B2bi00 = value->rValue; + mod->B2bi00Given = TRUE; + break; + case BSIM2_MOD_BI0L : + mod->B2bi0L = value->rValue; + mod->B2bi0LGiven = TRUE; + break; + case BSIM2_MOD_BI0W : + mod->B2bi0W = value->rValue; + mod->B2bi0WGiven = TRUE; + break; + case BSIM2_MOD_BIB0 : + mod->B2biB0 = value->rValue; + mod->B2biB0Given = TRUE; + break; + case BSIM2_MOD_BIBL : + mod->B2biBL = value->rValue; + mod->B2biBLGiven = TRUE; + break; + case BSIM2_MOD_BIBW : + mod->B2biBW = value->rValue; + mod->B2biBWGiven = TRUE; + break; + case BSIM2_MOD_VGHIGH0 : + mod->B2vghigh0 = value->rValue; + mod->B2vghigh0Given = TRUE; + break; + case BSIM2_MOD_VGHIGHL : + mod->B2vghighL = value->rValue; + mod->B2vghighLGiven = TRUE; + break; + case BSIM2_MOD_VGHIGHW : + mod->B2vghighW = value->rValue; + mod->B2vghighWGiven = TRUE; + break; + case BSIM2_MOD_VGLOW0 : + mod->B2vglow0 = value->rValue; + mod->B2vglow0Given = TRUE; + break; + case BSIM2_MOD_VGLOWL : + mod->B2vglowL = value->rValue; + mod->B2vglowLGiven = TRUE; + break; + case BSIM2_MOD_VGLOWW : + mod->B2vglowW = value->rValue; + mod->B2vglowWGiven = TRUE; + break; + case BSIM2_MOD_TOX : + mod->B2tox = value->rValue; + mod->B2toxGiven = TRUE; + break; + case BSIM2_MOD_TEMP : + mod->B2temp = value->rValue; + mod->B2tempGiven = TRUE; + break; + case BSIM2_MOD_VDD : + mod->B2vdd = value->rValue; + mod->B2vddGiven = TRUE; + break; + case BSIM2_MOD_VGG : + mod->B2vgg = value->rValue; + mod->B2vggGiven = TRUE; + break; + case BSIM2_MOD_VBB : + mod->B2vbb = value->rValue; + mod->B2vbbGiven = TRUE; + break; + case BSIM2_MOD_CGSO : + mod->B2gateSourceOverlapCap = value->rValue; + mod->B2gateSourceOverlapCapGiven = TRUE; + break; + case BSIM2_MOD_CGDO : + mod->B2gateDrainOverlapCap = value->rValue; + mod->B2gateDrainOverlapCapGiven = TRUE; + break; + case BSIM2_MOD_CGBO : + mod->B2gateBulkOverlapCap = value->rValue; + mod->B2gateBulkOverlapCapGiven = TRUE; + break; + case BSIM2_MOD_XPART : + mod->B2channelChargePartitionFlag = value->iValue; + mod->B2channelChargePartitionFlagGiven = TRUE; + break; + case BSIM2_MOD_RSH : + mod->B2sheetResistance = value->rValue; + mod->B2sheetResistanceGiven = TRUE; + break; + case BSIM2_MOD_JS : + mod->B2jctSatCurDensity = value->rValue; + mod->B2jctSatCurDensityGiven = TRUE; + break; + case BSIM2_MOD_PB : + mod->B2bulkJctPotential = value->rValue; + mod->B2bulkJctPotentialGiven = TRUE; + break; + case BSIM2_MOD_MJ : + mod->B2bulkJctBotGradingCoeff = value->rValue; + mod->B2bulkJctBotGradingCoeffGiven = TRUE; + break; + case BSIM2_MOD_PBSW : + mod->B2sidewallJctPotential = value->rValue; + mod->B2sidewallJctPotentialGiven = TRUE; + break; + case BSIM2_MOD_MJSW : + mod->B2bulkJctSideGradingCoeff = value->rValue; + mod->B2bulkJctSideGradingCoeffGiven = TRUE; + break; + case BSIM2_MOD_CJ : + mod->B2unitAreaJctCap = value->rValue; + mod->B2unitAreaJctCapGiven = TRUE; + break; + case BSIM2_MOD_CJSW : + mod->B2unitLengthSidewallJctCap = value->rValue; + mod->B2unitLengthSidewallJctCapGiven = TRUE; + break; + case BSIM2_MOD_DEFWIDTH : + mod->B2defaultWidth = value->rValue; + mod->B2defaultWidthGiven = TRUE; + break; + case BSIM2_MOD_DELLENGTH : + mod->B2deltaLength = value->rValue; + mod->B2deltaLengthGiven = TRUE; + break; + case BSIM2_MOD_NMOS : + if(value->iValue) { + mod->B2type = 1; + mod->B2typeGiven = TRUE; + } + break; + case BSIM2_MOD_PMOS : + if(value->iValue) { + mod->B2type = - 1; + mod->B2typeGiven = TRUE; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/bsim2/b2par.c b/src/spicelib/devices/bsim2/b2par.c new file mode 100644 index 000000000..3414fc9fc --- /dev/null +++ b/src/spicelib/devices/bsim2/b2par.c @@ -0,0 +1,96 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "bsim2def.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +B2param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + B2instance *here = (B2instance*)inst; + switch(param) { + case BSIM2_W: + here->B2w = value->rValue; + here->B2wGiven = TRUE; + break; + case BSIM2_L: + here->B2l = value->rValue; + here->B2lGiven = TRUE; + break; + case BSIM2_AS: + here->B2sourceArea = value->rValue; + here->B2sourceAreaGiven = TRUE; + break; + case BSIM2_AD: + here->B2drainArea = value->rValue; + here->B2drainAreaGiven = TRUE; + break; + case BSIM2_PS: + here->B2sourcePerimeter = value->rValue; + here->B2sourcePerimeterGiven = TRUE; + break; + case BSIM2_PD: + here->B2drainPerimeter = value->rValue; + here->B2drainPerimeterGiven = TRUE; + break; + case BSIM2_NRS: + here->B2sourceSquares = value->rValue; + here->B2sourceSquaresGiven = TRUE; + break; + case BSIM2_NRD: + here->B2drainSquares = value->rValue; + here->B2drainSquaresGiven = TRUE; + break; + case BSIM2_OFF: + here->B2off = value->iValue; + break; + case BSIM2_IC_VBS: + here->B2icVBS = value->rValue; + here->B2icVBSGiven = TRUE; + break; + case BSIM2_IC_VDS: + here->B2icVDS = value->rValue; + here->B2icVDSGiven = TRUE; + break; + case BSIM2_IC_VGS: + here->B2icVGS = value->rValue; + here->B2icVGSGiven = TRUE; + break; + case BSIM2_IC: + switch(value->v.numValue){ + case 3: + here->B2icVBS = *(value->v.vec.rVec+2); + here->B2icVBSGiven = TRUE; + case 2: + here->B2icVGS = *(value->v.vec.rVec+1); + here->B2icVGSGiven = TRUE; + case 1: + here->B2icVDS = *(value->v.vec.rVec); + here->B2icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim2/b2pzld.c b/src/spicelib/devices/bsim2/b2pzld.c new file mode 100644 index 000000000..aa4bb91ce --- /dev/null +++ b/src/spicelib/devices/bsim2/b2pzld.c @@ -0,0 +1,165 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "bsim2def.h" +#include "suffix.h" + + +int +B2pzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + register SPcomplex *s; +{ + register B2model *model = (B2model*)inModel; + register B2instance *here; + int xnrm; + int xrev; + double gdpr; + double gspr; + double gm; + double gds; + double gmbs; + double gbd; + double gbs; + double capbd; + double capbs; + double xcggb; + double xcgdb; + double xcgsb; + double xcbgb; + double xcbdb; + double xcbsb; + double xcddb; + double xcssb; + double xcdgb; + double xcsgb; + double xcdsb; + double xcsdb; + double cggb; + double cgdb; + double cgsb; + double cbgb; + double cbdb; + double cbsb; + double cddb; + double cdgb; + double cdsb; + + for( ; model != NULL; model = model->B2nextModel) { + for(here = model->B2instances; here!= NULL; + here = here->B2nextInstance) { + if (here->B2owner != ARCHme) continue; + + if (here->B2mode >= 0) { + xnrm=1; + xrev=0; + } else { + xnrm=0; + xrev=1; + } + gdpr=here->B2drainConductance; + gspr=here->B2sourceConductance; + gm= *(ckt->CKTstate0 + here->B2gm); + gds= *(ckt->CKTstate0 + here->B2gds); + gmbs= *(ckt->CKTstate0 + here->B2gmbs); + gbd= *(ckt->CKTstate0 + here->B2gbd); + gbs= *(ckt->CKTstate0 + here->B2gbs); + capbd= *(ckt->CKTstate0 + here->B2capbd); + capbs= *(ckt->CKTstate0 + here->B2capbs); + /* + * charge oriented model parameters + */ + + cggb = *(ckt->CKTstate0 + here->B2cggb); + cgsb = *(ckt->CKTstate0 + here->B2cgsb); + cgdb = *(ckt->CKTstate0 + here->B2cgdb); + + cbgb = *(ckt->CKTstate0 + here->B2cbgb); + cbsb = *(ckt->CKTstate0 + here->B2cbsb); + cbdb = *(ckt->CKTstate0 + here->B2cbdb); + + cdgb = *(ckt->CKTstate0 + here->B2cdgb); + cdsb = *(ckt->CKTstate0 + here->B2cdsb); + cddb = *(ckt->CKTstate0 + here->B2cddb); + + xcdgb = (cdgb - here->pParam->B2GDoverlapCap) ; + xcddb = (cddb + capbd + here->pParam->B2GDoverlapCap) ; + xcdsb = cdsb ; + xcsgb = -(cggb + cbgb + cdgb + here->pParam->B2GSoverlapCap ) ; + xcsdb = -(cgdb + cbdb + cddb) ; + xcssb = (capbs + here->pParam->B2GSoverlapCap - (cgsb+cbsb+cdsb)) ; + xcggb = (cggb + here->pParam->B2GDoverlapCap + + here->pParam->B2GSoverlapCap + + here->pParam->B2GBoverlapCap) ; + xcgdb = (cgdb - here->pParam->B2GDoverlapCap ) ; + xcgsb = (cgsb - here->pParam->B2GSoverlapCap) ; + xcbgb = (cbgb - here->pParam->B2GBoverlapCap) ; + xcbdb = (cbdb - capbd ) ; + xcbsb = (cbsb - capbs ) ; + + + *(here->B2GgPtr ) += xcggb * s->real; + *(here->B2GgPtr +1) += xcggb * s->imag; + *(here->B2BbPtr ) += (-xcbgb-xcbdb-xcbsb) * s->real; + *(here->B2BbPtr +1) += (-xcbgb-xcbdb-xcbsb) * s->imag; + *(here->B2DPdpPtr ) += xcddb * s->real; + *(here->B2DPdpPtr +1) += xcddb * s->imag; + *(here->B2SPspPtr ) += xcssb * s->real; + *(here->B2SPspPtr +1) += xcssb * s->imag; + *(here->B2GbPtr ) += (-xcggb-xcgdb-xcgsb) * s->real; + *(here->B2GbPtr +1) += (-xcggb-xcgdb-xcgsb) * s->imag; + *(here->B2GdpPtr ) += xcgdb * s->real; + *(here->B2GdpPtr +1) += xcgdb * s->imag; + *(here->B2GspPtr ) += xcgsb * s->real; + *(here->B2GspPtr +1) += xcgsb * s->imag; + *(here->B2BgPtr ) += xcbgb * s->real; + *(here->B2BgPtr +1) += xcbgb * s->imag; + *(here->B2BdpPtr ) += xcbdb * s->real; + *(here->B2BdpPtr +1) += xcbdb * s->imag; + *(here->B2BspPtr ) += xcbsb * s->real; + *(here->B2BspPtr +1) += xcbsb * s->imag; + *(here->B2DPgPtr ) += xcdgb * s->real; + *(here->B2DPgPtr +1) += xcdgb * s->imag; + *(here->B2DPbPtr ) += (-xcdgb-xcddb-xcdsb) * s->real; + *(here->B2DPbPtr +1) += (-xcdgb-xcddb-xcdsb) * s->imag; + *(here->B2DPspPtr ) += xcdsb * s->real; + *(here->B2DPspPtr +1) += xcdsb * s->imag; + *(here->B2SPgPtr ) += xcsgb * s->real; + *(here->B2SPgPtr +1) += xcsgb * s->imag; + *(here->B2SPbPtr ) += (-xcsgb-xcsdb-xcssb) * s->real; + *(here->B2SPbPtr +1) += (-xcsgb-xcsdb-xcssb) * s->imag; + *(here->B2SPdpPtr ) += xcsdb * s->real; + *(here->B2SPdpPtr +1) += xcsdb * s->imag; + *(here->B2DdPtr) += gdpr; + *(here->B2SsPtr) += gspr; + *(here->B2BbPtr) += gbd+gbs; + *(here->B2DPdpPtr) += gdpr+gds+gbd+xrev*(gm+gmbs); + *(here->B2SPspPtr) += gspr+gds+gbs+xnrm*(gm+gmbs); + *(here->B2DdpPtr) -= gdpr; + *(here->B2SspPtr) -= gspr; + *(here->B2BdpPtr) -= gbd; + *(here->B2BspPtr) -= gbs; + *(here->B2DPdPtr) -= gdpr; + *(here->B2DPgPtr) += (xnrm-xrev)*gm; + *(here->B2DPbPtr) += -gbd+(xnrm-xrev)*gmbs; + *(here->B2DPspPtr) += -gds-xnrm*(gm+gmbs); + *(here->B2SPgPtr) += -(xnrm-xrev)*gm; + *(here->B2SPsPtr) -= gspr; + *(here->B2SPbPtr) += -gbs-(xnrm-xrev)*gmbs; + *(here->B2SPdpPtr) += -gds-xrev*(gm+gmbs); + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim2/b2set.c b/src/spicelib/devices/bsim2/b2set.c new file mode 100644 index 000000000..6722afcb4 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2set.c @@ -0,0 +1,582 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Min-Chie Jeng, Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim2def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +B2setup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + register GENmodel *inModel; + register CKTcircuit *ckt; + int *states; + /* load the B2 device structure with those pointers needed later + * for fast matrix loading + */ + +{ + register B2model *model = (B2model*)inModel; + register B2instance *here; + int error; + CKTnode *tmp; + + /* loop through all the B2 device models */ + for( ; model != NULL; model = model->B2nextModel ) { + +/* Default value Processing for B2 MOSFET Models */ + if( ! model->B2typeGiven) { + model->B2type = NMOS; /* NMOS */ + } + if( ! model->B2vfb0Given) { + model->B2vfb0 = -1.0; + } + if( ! model->B2vfbLGiven) { + model->B2vfbL = 0.0; + } + if( ! model->B2vfbWGiven) { + model->B2vfbW = 0.0; + } + if( ! model->B2phi0Given) { + model->B2phi0 = 0.75; + } + if( ! model->B2phiLGiven) { + model->B2phiL = 0.0; + } + if( ! model->B2phiWGiven) { + model->B2phiW = 0.0; + } + if( ! model->B2k10Given) { + model->B2k10 = 0.8; + } + if( ! model->B2k1LGiven) { + model->B2k1L = 0.0; + } + if( ! model->B2k1WGiven) { + model->B2k1W = 0.0; + } + if( ! model->B2k20Given) { + model->B2k20 = 0.0; + } + if( ! model->B2k2LGiven) { + model->B2k2L = 0.0; + } + if( ! model->B2k2WGiven) { + model->B2k2W = 0.0; + } + if( ! model->B2eta00Given) { + model->B2eta00 = 0.0; + } + if( ! model->B2eta0LGiven) { + model->B2eta0L = 0.0; + } + if( ! model->B2eta0WGiven) { + model->B2eta0W = 0.0; + } + if( ! model->B2etaB0Given) { + model->B2etaB0 = 0.0; + } + if( ! model->B2etaBLGiven) { + model->B2etaBL = 0.0; + } + if( ! model->B2etaBWGiven) { + model->B2etaBW = 0.0; + } + if( ! model->B2deltaLGiven) { + model->B2deltaL = 0.0; + } + if( ! model->B2deltaWGiven) { + model->B2deltaW = 0.0; + } + if( ! model->B2ua00Given) { + model->B2ua00 = 0.2; + } + if( ! model->B2ua0LGiven) { + model->B2ua0L = 0.0; + } + if( ! model->B2ua0WGiven) { + model->B2ua0W = 0.0; + } + if( ! model->B2uaB0Given) { + model->B2uaB0 = 0.0; + } + if( ! model->B2uaBLGiven) { + model->B2uaBL = 0.0; + } + if( ! model->B2uaBWGiven) { + model->B2uaBW = 0.0; + } + if( ! model->B2ub00Given) { + model->B2ub00 = 0.0; + } + if( ! model->B2ub0LGiven) { + model->B2ub0L = 0.0; + } + if( ! model->B2ub0WGiven) { + model->B2ub0W = 0.0; + } + if( ! model->B2ubB0Given) { + model->B2ubB0 = 0.0; + } + if( ! model->B2ubBLGiven) { + model->B2ubBL = 0.0; + } + if( ! model->B2ubBWGiven) { + model->B2ubBW = 0.0; + } + if( ! model->B2u100Given) { + model->B2u100 = 0.1; + } + if( ! model->B2u10LGiven) { + model->B2u10L = 0.0; + } + if( ! model->B2u10WGiven) { + model->B2u10W = 0.0; + } + if( ! model->B2u1B0Given) { + model->B2u1B0 = 0.0; + } + if( ! model->B2u1BLGiven) { + model->B2u1BL = 0.0; + } + if( ! model->B2u1BWGiven) { + model->B2u1BW = 0.0; + } + if( ! model->B2u1D0Given) { + model->B2u1D0 = 0.0; + } + if( ! model->B2u1DLGiven) { + model->B2u1DL = 0.0; + } + if( ! model->B2u1DWGiven) { + model->B2u1DW = 0.0; + } + if( ! model->B2mob00Given) { + model->B2mob00 = 400.0; + } + if( ! model->B2mob0B0Given) { + model->B2mob0B0 = 0.0; + } + if( ! model->B2mob0BLGiven) { + model->B2mob0BL = 0.0; + } + if( ! model->B2mob0BWGiven) { + model->B2mob0BW = 0.0; + } + if( ! model->B2mobs00Given) { + model->B2mobs00 = 500.0; + } + if( ! model->B2mobs0LGiven) { + model->B2mobs0L = 0.0; + } + if( ! model->B2mobs0WGiven) { + model->B2mobs0W = 0.0; + } + if( ! model->B2mobsB0Given) { + model->B2mobsB0 = 0.0; + } + if( ! model->B2mobsBLGiven) { + model->B2mobsBL = 0.0; + } + if( ! model->B2mobsBWGiven) { + model->B2mobsBW = 0.0; + } + if( ! model->B2mob200Given) { + model->B2mob200 = 1.5; + } + if( ! model->B2mob20LGiven) { + model->B2mob20L = 0.0; + } + if( ! model->B2mob20WGiven) { + model->B2mob20W = 0.0; + } + if( ! model->B2mob2B0Given) { + model->B2mob2B0 = 0.0; + } + if( ! model->B2mob2BLGiven) { + model->B2mob2BL = 0.0; + } + if( ! model->B2mob2BWGiven) { + model->B2mob2BW = 0.0; + } + if( ! model->B2mob2G0Given) { + model->B2mob2G0 = 0.0; + } + if( ! model->B2mob2GLGiven) { + model->B2mob2GL = 0.0; + } + if( ! model->B2mob2GWGiven) { + model->B2mob2GW = 0.0; + } + if( ! model->B2mob300Given) { + model->B2mob300 = 10; + } + if( ! model->B2mob30LGiven) { + model->B2mob30L = 0.0; + } + if( ! model->B2mob30WGiven) { + model->B2mob30W = 0.0; + } + if( ! model->B2mob3B0Given) { + model->B2mob3B0 = 0.0; + } + if( ! model->B2mob3BLGiven) { + model->B2mob3BL = 0.0; + } + if( ! model->B2mob3BWGiven) { + model->B2mob3BW = 0.0; + } + if( ! model->B2mob3G0Given) { + model->B2mob3G0 = 0.0; + } + if( ! model->B2mob3GLGiven) { + model->B2mob3GL = 0.0; + } + if( ! model->B2mob3GWGiven) { + model->B2mob3GW = 0.0; + } + if( ! model->B2mob400Given) { + model->B2mob400 = 0.0; + } + if( ! model->B2mob40LGiven) { + model->B2mob40L = 0.0; + } + if( ! model->B2mob40WGiven) { + model->B2mob40W = 0.0; + } + if( ! model->B2mob4B0Given) { + model->B2mob4B0 = 0.0; + } + if( ! model->B2mob4BLGiven) { + model->B2mob4BL = 0.0; + } + if( ! model->B2mob4BWGiven) { + model->B2mob4BW = 0.0; + } + if( ! model->B2mob4G0Given) { + model->B2mob4G0 = 0.0; + } + if( ! model->B2mob4GLGiven) { + model->B2mob4GL = 0.0; + } + if( ! model->B2mob4GWGiven) { + model->B2mob4GW = 0.0; + } + if( ! model->B2n00Given) { + model->B2n00 = 1.4; + } + if( ! model->B2n0LGiven) { + model->B2n0L = 0.0; + } + if( ! model->B2n0WGiven) { + model->B2n0W = 0.0; + } + if( ! model->B2nB0Given) { + model->B2nB0 = 0.5; + } + if( ! model->B2nBLGiven) { + model->B2nBL = 0.0; + } + if( ! model->B2nBWGiven) { + model->B2nBW = 0.0; + } + if( ! model->B2nD0Given) { + model->B2nD0 = 0.0; + } + if( ! model->B2nDLGiven) { + model->B2nDL = 0.0; + } + if( ! model->B2nDWGiven) { + model->B2nDW = 0.0; + } + if( ! model->B2vof00Given) { + model->B2vof00 = 1.8; + } + if( ! model->B2vof0LGiven) { + model->B2vof0L = 0.0; + } + if( ! model->B2vof0WGiven) { + model->B2vof0W = 0.0; + } + if( ! model->B2vofB0Given) { + model->B2vofB0 = 0.0; + } + if( ! model->B2vofBLGiven) { + model->B2vofBL = 0.0; + } + if( ! model->B2vofBWGiven) { + model->B2vofBW = 0.0; + } + if( ! model->B2vofD0Given) { + model->B2vofD0 = 0.0; + } + if( ! model->B2vofDLGiven) { + model->B2vofDL = 0.0; + } + if( ! model->B2vofDWGiven) { + model->B2vofDW = 0.0; + } + if( ! model->B2ai00Given) { + model->B2ai00 = 0.0; + } + if( ! model->B2ai0LGiven) { + model->B2ai0L = 0.0; + } + if( ! model->B2ai0WGiven) { + model->B2ai0W = 0.0; + } + if( ! model->B2aiB0Given) { + model->B2aiB0 = 0.0; + } + if( ! model->B2aiBLGiven) { + model->B2aiBL = 0.0; + } + if( ! model->B2aiBWGiven) { + model->B2aiBW = 0.0; + } + if( ! model->B2bi00Given) { + model->B2bi00 = 0.0; + } + if( ! model->B2bi0LGiven) { + model->B2bi0L = 0.0; + } + if( ! model->B2bi0WGiven) { + model->B2bi0W = 0.0; + } + if( ! model->B2biB0Given) { + model->B2biB0 = 0.0; + } + if( ! model->B2biBLGiven) { + model->B2biBL = 0.0; + } + if( ! model->B2biBWGiven) { + model->B2biBW = 0.0; + } + if( ! model->B2vghigh0Given) { + model->B2vghigh0 = 0.2; + } + if( ! model->B2vghighLGiven) { + model->B2vghighL = 0.0; + } + if( ! model->B2vghighWGiven) { + model->B2vghighW = 0.0; + } + if( ! model->B2vglow0Given) { + model->B2vglow0 = -0.15; + } + if( ! model->B2vglowLGiven) { + model->B2vglowL = 0.0; + } + if( ! model->B2vglowWGiven) { + model->B2vglowW = 0.0; + } + if( ! model->B2toxGiven) { + model->B2tox = 0.03; /* um */ + } + if( ! model->B2tempGiven) { + model->B2temp = 27.0; + } + if( ! model->B2vddGiven) { + model->B2vdd = 5.0; + } + if( ! model->B2vggGiven) { + model->B2vgg = 5.0; + } + if( ! model->B2vbbGiven) { + model->B2vbb = 5.0; + } + if( ! model->B2gateDrainOverlapCapGiven) { + model->B2gateDrainOverlapCap = 0.0; + } + if( ! model->B2gateSourceOverlapCapGiven) { + model->B2gateSourceOverlapCap = 0.0; + } + if( ! model->B2gateBulkOverlapCapGiven) { + model->B2gateBulkOverlapCap = 0.0; + } + if( ! model->B2channelChargePartitionFlagGiven) { + model->B2channelChargePartitionFlag = 0.0; + } + if( ! model->B2sheetResistanceGiven) { + model->B2sheetResistance = 0.0; + } + if( ! model->B2unitAreaJctCapGiven) { + model->B2unitAreaJctCap = 0.0; + } + if( ! model->B2unitLengthSidewallJctCapGiven) { + model->B2unitLengthSidewallJctCap = 0.0; + } + if( ! model->B2jctSatCurDensityGiven) { + model->B2jctSatCurDensity = 0.0; + } + if( ! model->B2bulkJctPotentialGiven) { + model->B2bulkJctPotential = 0.0; + } + if( ! model->B2sidewallJctPotentialGiven) { + model->B2sidewallJctPotential = 0.0; + } + if( ! model->B2bulkJctBotGradingCoeffGiven) { + model->B2bulkJctBotGradingCoeff = 0.0; + } + if( ! model->B2bulkJctSideGradingCoeffGiven) { + model->B2bulkJctSideGradingCoeff = 0.0; + } + if( ! model->B2defaultWidthGiven) { + model->B2defaultWidth = 10.0; + } + if( ! model->B2deltaLengthGiven) { + model->B2deltaLength = 0.0; + } + + /* loop through all the instances of the model */ + for (here = model->B2instances; here != NULL ; + here=here->B2nextInstance) { + + if (here->B2owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->B2states = *states; + *states += B2numStates; + } + + /* perform the parameter defaulting */ + + if(!here->B2drainAreaGiven) { + here->B2drainArea = 0; + } + if(!here->B2drainPerimeterGiven) { + here->B2drainPerimeter = 0; + } + if(!here->B2drainSquaresGiven) { + here->B2drainSquares = 1; + } + if(!here->B2icVBSGiven) { + here->B2icVBS = 0; + } + if(!here->B2icVDSGiven) { + here->B2icVDS = 0; + } + if(!here->B2icVGSGiven) { + here->B2icVGS = 0; + } + if(!here->B2lGiven) { + here->B2l = 5e-6; + } + if(!here->B2sourceAreaGiven) { + here->B2sourceArea = 0; + } + if(!here->B2sourcePerimeterGiven) { + here->B2sourcePerimeter = 0; + } + if(!here->B2sourceSquaresGiven) { + here->B2sourceSquares = 1; + } + if(!here->B2vdsatGiven) { + here->B2vdsat = 0; + } + if(!here->B2vonGiven) { + here->B2von = 0; + } + if(!here->B2wGiven) { + here->B2w = 5e-6; + } + + /* process drain series resistance */ + if( (model->B2sheetResistance != 0) && + (here->B2drainSquares != 0.0 ) && + (here->B2dNodePrime == 0) ) { + error = CKTmkVolt(ckt,&tmp,here->B2name,"drain"); + if(error) return(error); + here->B2dNodePrime = tmp->number; + } else { + here->B2dNodePrime = here->B2dNode; + } + + /* process source series resistance */ + if( (model->B2sheetResistance != 0) && + (here->B2sourceSquares != 0.0 ) && + (here->B2sNodePrime == 0) ) { + if(here->B2sNodePrime == 0) { + error = CKTmkVolt(ckt,&tmp,here->B2name,"source"); + if(error) return(error); + here->B2sNodePrime = tmp->number; + } + } else { + here->B2sNodePrime = here->B2sNode; + } + + + /* set Sparse Matrix Pointers */ + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(B2DdPtr, B2dNode, B2dNode) + TSTALLOC(B2GgPtr, B2gNode, B2gNode) + TSTALLOC(B2SsPtr, B2sNode, B2sNode) + TSTALLOC(B2BbPtr, B2bNode, B2bNode) + TSTALLOC(B2DPdpPtr, B2dNodePrime, B2dNodePrime) + TSTALLOC(B2SPspPtr, B2sNodePrime, B2sNodePrime) + TSTALLOC(B2DdpPtr, B2dNode, B2dNodePrime) + TSTALLOC(B2GbPtr, B2gNode, B2bNode) + TSTALLOC(B2GdpPtr, B2gNode, B2dNodePrime) + TSTALLOC(B2GspPtr, B2gNode, B2sNodePrime) + TSTALLOC(B2SspPtr, B2sNode, B2sNodePrime) + TSTALLOC(B2BdpPtr, B2bNode, B2dNodePrime) + TSTALLOC(B2BspPtr, B2bNode, B2sNodePrime) + TSTALLOC(B2DPspPtr, B2dNodePrime, B2sNodePrime) + TSTALLOC(B2DPdPtr, B2dNodePrime, B2dNode) + TSTALLOC(B2BgPtr, B2bNode, B2gNode) + TSTALLOC(B2DPgPtr, B2dNodePrime, B2gNode) + TSTALLOC(B2SPgPtr, B2sNodePrime, B2gNode) + TSTALLOC(B2SPsPtr, B2sNodePrime, B2sNode) + TSTALLOC(B2DPbPtr, B2dNodePrime, B2bNode) + TSTALLOC(B2SPbPtr, B2sNodePrime, B2bNode) + TSTALLOC(B2SPdpPtr, B2sNodePrime, B2dNodePrime) + + } + } + return(OK); +} + +int +B2unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + B2model *model; + B2instance *here; + + for (model = (B2model *)inModel; model != NULL; + model = model->B2nextModel) + { + for (here = model->B2instances; here != NULL; + here=here->B2nextInstance) + { + if (here->B2dNodePrime + && here->B2dNodePrime != here->B2dNode) + { + CKTdltNNum(ckt, here->B2dNodePrime); + here->B2dNodePrime = 0; + } + if (here->B2sNodePrime + && here->B2sNodePrime != here->B2sNode) + { + CKTdltNNum(ckt, here->B2sNodePrime); + here->B2sNodePrime = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/bsim2/b2temp.c b/src/spicelib/devices/bsim2/b2temp.c new file mode 100644 index 000000000..6a20742e2 --- /dev/null +++ b/src/spicelib/devices/bsim2/b2temp.c @@ -0,0 +1,273 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim2def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +B2temp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* load the B2 device structure with those pointers needed later + * for fast matrix loading + */ + +{ + register B2model *model = (B2model*) inModel; + register B2instance *here; + register struct bsim2SizeDependParam *pSizeDependParamKnot, *pLastKnot; + double EffectiveLength; + double EffectiveWidth; + double CoxWoverL, Inv_L, Inv_W, tmp; + int Size_Not_Found; + + /* loop through all the B2 device models */ + for( ; model != NULL; model = model->B2nextModel ) { + +/* Default value Processing for B2 MOSFET Models */ + /* Some Limiting for Model Parameters */ + if( model->B2bulkJctPotential < 0.1) { + model->B2bulkJctPotential = 0.1; + } + if( model->B2sidewallJctPotential < 0.1) { + model->B2sidewallJctPotential = 0.1; + } + + model->B2Cox = 3.453e-13/(model->B2tox * 1.0e-4);/*in F/cm**2 */ + model->B2vdd2 = 2.0 * model->B2vdd; + model->B2vgg2 = 2.0 * model->B2vgg; + model->B2vbb2 = 2.0 * model->B2vbb; + model->B2Vtm = 8.625e-5 * (model->B2temp + 273.0); + model->pSizeDependParamKnot = NULL; + pLastKnot = NULL; + + /* loop through all the instances of the model */ + for (here = model->B2instances; here != NULL ; + here=here->B2nextInstance) { + if (here->B2owner != ARCHme) continue; + + pSizeDependParamKnot = model->pSizeDependParamKnot; + Size_Not_Found = 1; + + while ((pSizeDependParamKnot != NULL) && Size_Not_Found) + { if ((here->B2l == pSizeDependParamKnot->Length) + && (here->B2w == pSizeDependParamKnot->Width)) + { Size_Not_Found = 0; + here->pParam = pSizeDependParamKnot; + } + else + { pLastKnot = pSizeDependParamKnot; + pSizeDependParamKnot = pSizeDependParamKnot->pNext; + } + } + + if (Size_Not_Found) + { here->pParam = (struct bsim2SizeDependParam *)malloc( + sizeof(struct bsim2SizeDependParam)); + if (pLastKnot == NULL) + model->pSizeDependParamKnot = here->pParam; + else + pLastKnot->pNext = here->pParam; + here->pParam->pNext = NULL; + + EffectiveLength = here->B2l - model->B2deltaL * 1.0e-6; + EffectiveWidth = here->B2w - model->B2deltaW * 1.0e-6; + + if(EffectiveLength<=0) + { IFuid namarray[2]; + namarray[0] = model->B2modName; + namarray[1] = here->B2name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "B2: mosfet %s, model %s: Effective channel length <=0", + namarray); + return(E_BADPARM); + } + + if(EffectiveWidth <= 0) + { IFuid namarray[2]; + namarray[0] = model->B2modName; + namarray[1] = here->B2name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "B2: mosfet %s, model %s: Effective channel width <=0", + namarray); + return(E_BADPARM); + } + + Inv_L = 1.0e-6 / EffectiveLength; + Inv_W = 1.0e-6 / EffectiveWidth; + here->pParam->Width = here->B2w; + here->pParam->Length = here->B2l; + here->pParam->B2vfb = model->B2vfb0 + model->B2vfbW * Inv_W + + model->B2vfbL * Inv_L; + here->pParam->B2phi = model->B2phi0 + model->B2phiW * Inv_W + + model->B2phiL * Inv_L; + here->pParam->B2k1 = model->B2k10 + model->B2k1W * Inv_W + + model->B2k1L * Inv_L; + here->pParam->B2k2 = model->B2k20 + model->B2k2W * Inv_W + + model->B2k2L * Inv_L; + here->pParam->B2eta0 = model->B2eta00 + + model->B2eta0W * Inv_W + + model->B2eta0L * Inv_L; + here->pParam->B2etaB = model->B2etaB0 + model->B2etaBW + * Inv_W + model->B2etaBL * Inv_L; + here->pParam->B2beta0 = model->B2mob00; + here->pParam->B2beta0B = model->B2mob0B0 + + model->B2mob0BW * Inv_W + + model->B2mob0BL * Inv_L; + here->pParam->B2betas0 = model->B2mobs00 + + model->B2mobs0W * Inv_W + + model->B2mobs0L * Inv_L; + if (here->pParam->B2betas0 < 1.01 * here->pParam->B2beta0) + here->pParam->B2betas0 = 1.01 * here->pParam->B2beta0; + here->pParam->B2betasB = model->B2mobsB0 + + model->B2mobsBW * Inv_W + + model->B2mobsBL * Inv_L; + tmp = (here->pParam->B2betas0 - here->pParam->B2beta0 + - here->pParam->B2beta0B * model->B2vbb); + if ((-here->pParam->B2betasB * model->B2vbb) > tmp) + here->pParam->B2betasB = -tmp / model->B2vbb; + here->pParam->B2beta20 = model->B2mob200 + + model->B2mob20W * Inv_W + + model->B2mob20L * Inv_L; + here->pParam->B2beta2B = model->B2mob2B0 + + model->B2mob2BW * Inv_W + + model->B2mob2BL * Inv_L; + here->pParam->B2beta2G = model->B2mob2G0 + + model->B2mob2GW * Inv_W + + model->B2mob2GL * Inv_L; + here->pParam->B2beta30 = model->B2mob300 + + model->B2mob30W * Inv_W + + model->B2mob30L * Inv_L; + here->pParam->B2beta3B = model->B2mob3B0 + + model->B2mob3BW * Inv_W + + model->B2mob3BL * Inv_L; + here->pParam->B2beta3G = model->B2mob3G0 + + model->B2mob3GW * Inv_W + + model->B2mob3GL * Inv_L; + here->pParam->B2beta40 = model->B2mob400 + + model->B2mob40W * Inv_W + + model->B2mob40L * Inv_L; + here->pParam->B2beta4B = model->B2mob4B0 + + model->B2mob4BW * Inv_W + + model->B2mob4BL * Inv_L; + here->pParam->B2beta4G = model->B2mob4G0 + + model->B2mob4GW * Inv_W + + model->B2mob4GL * Inv_L; + + CoxWoverL = model->B2Cox * EffectiveWidth / EffectiveLength; + + here->pParam->B2beta0 *= CoxWoverL; + here->pParam->B2beta0B *= CoxWoverL; + here->pParam->B2betas0 *= CoxWoverL; + here->pParam->B2betasB *= CoxWoverL; + here->pParam->B2beta30 *= CoxWoverL; + here->pParam->B2beta3B *= CoxWoverL; + here->pParam->B2beta3G *= CoxWoverL; + here->pParam->B2beta40 *= CoxWoverL; + here->pParam->B2beta4B *= CoxWoverL; + here->pParam->B2beta4G *= CoxWoverL; + + here->pParam->B2ua0 = model->B2ua00 + model->B2ua0W * Inv_W + + model->B2ua0L * Inv_L; + here->pParam->B2uaB = model->B2uaB0 + model->B2uaBW * Inv_W + + model->B2uaBL * Inv_L; + here->pParam->B2ub0 = model->B2ub00 + model->B2ub0W * Inv_W + + model->B2ub0L * Inv_L; + here->pParam->B2ubB = model->B2ubB0 + model->B2ubBW * Inv_W + + model->B2ubBL * Inv_L; + here->pParam->B2u10 = model->B2u100 + model->B2u10W * Inv_W + + model->B2u10L * Inv_L; + here->pParam->B2u1B = model->B2u1B0 + model->B2u1BW * Inv_W + + model->B2u1BL * Inv_L; + here->pParam->B2u1D = model->B2u1D0 + model->B2u1DW * Inv_W + + model->B2u1DL * Inv_L; + here->pParam->B2n0 = model->B2n00 + model->B2n0W * Inv_W + + model->B2n0L * Inv_L; + here->pParam->B2nB = model->B2nB0 + model->B2nBW * Inv_W + + model->B2nBL * Inv_L; + here->pParam->B2nD = model->B2nD0 + model->B2nDW * Inv_W + + model->B2nDL * Inv_L; + if (here->pParam->B2n0 < 0.0) + here->pParam->B2n0 = 0.0; + + here->pParam->B2vof0 = model->B2vof00 + + model->B2vof0W * Inv_W + + model->B2vof0L * Inv_L; + here->pParam->B2vofB = model->B2vofB0 + + model->B2vofBW * Inv_W + + model->B2vofBL * Inv_L; + here->pParam->B2vofD = model->B2vofD0 + + model->B2vofDW * Inv_W + + model->B2vofDL * Inv_L; + here->pParam->B2ai0 = model->B2ai00 + model->B2ai0W * Inv_W + + model->B2ai0L * Inv_L; + here->pParam->B2aiB = model->B2aiB0 + model->B2aiBW * Inv_W + + model->B2aiBL * Inv_L; + here->pParam->B2bi0 = model->B2bi00 + model->B2bi0W * Inv_W + + model->B2bi0L * Inv_L; + here->pParam->B2biB = model->B2biB0 + model->B2biBW * Inv_W + + model->B2biBL * Inv_L; + here->pParam->B2vghigh = model->B2vghigh0 + + model->B2vghighW * Inv_W + + model->B2vghighL * Inv_L; + here->pParam->B2vglow = model->B2vglow0 + + model->B2vglowW * Inv_W + + model->B2vglowL * Inv_L; + + here->pParam->CoxWL = model->B2Cox * EffectiveLength + * EffectiveWidth * 1.0e4; + here->pParam->One_Third_CoxWL = here->pParam->CoxWL / 3.0; + here->pParam->Two_Third_CoxWL = 2.0 + * here->pParam->One_Third_CoxWL; + here->pParam->B2GSoverlapCap = model->B2gateSourceOverlapCap + * EffectiveWidth; + here->pParam->B2GDoverlapCap = model->B2gateDrainOverlapCap + * EffectiveWidth; + here->pParam->B2GBoverlapCap = model->B2gateBulkOverlapCap + * EffectiveLength; + here->pParam->SqrtPhi = sqrt(here->pParam->B2phi); + here->pParam->Phis3 = here->pParam->SqrtPhi + * here->pParam->B2phi; + here->pParam->Arg = here->pParam->B2betasB + - here->pParam->B2beta0B - model->B2vdd + * (here->pParam->B2beta3B - model->B2vdd + * here->pParam->B2beta4B); + + + } + + + /* process drain series resistance */ + if( (here->B2drainConductance=model->B2sheetResistance * + here->B2drainSquares) != 0.0 ) { + here->B2drainConductance = 1. / here->B2drainConductance ; + } + + /* process source series resistance */ + if( (here->B2sourceConductance=model->B2sheetResistance * + here->B2sourceSquares) != 0.0 ) { + here->B2sourceConductance = 1. / here->B2sourceConductance ; + } + + + here->pParam->B2vt0 = here->pParam->B2vfb + + here->pParam->B2phi + + here->pParam->B2k1 * here->pParam->SqrtPhi + - here->pParam->B2k2 * here->pParam->B2phi; + here->B2von = here->pParam->B2vt0; /* added for initialization*/ + } + } + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim2/b2trunc.c b/src/spicelib/devices/bsim2/b2trunc.c new file mode 100644 index 000000000..e61d4b8cc --- /dev/null +++ b/src/spicelib/devices/bsim2/b2trunc.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Hong J. Park, Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim2def.h" +#include "sperror.h" +#include "suffix.h" + +int +B2trunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register B2model *model = (B2model*)inModel; + register B2instance *here; +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + + for( ; model != NULL; model = model->B2nextModel) { + for(here=model->B2instances;here!=NULL;here = here->B2nextInstance){ + if (here->B2owner != ARCHme) continue; + +#ifdef STEPDEBUG + debugtemp = *timeStep; +#endif /* STEPDEBUG */ + CKTterr(here->B2qb,ckt,timeStep); + CKTterr(here->B2qg,ckt,timeStep); + CKTterr(here->B2qd,ckt,timeStep); +#ifdef STEPDEBUG + if(debugtemp != *timeStep) { + printf("device %s reduces step from %g to %g\n", + here->B2name,debugtemp,*timeStep); + } +#endif /* STEPDEBUG */ + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim2/bsim2def.h b/src/spicelib/devices/bsim2/bsim2def.h new file mode 100644 index 000000000..d366e83d8 --- /dev/null +++ b/src/spicelib/devices/bsim2/bsim2def.h @@ -0,0 +1,729 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Min-Chie Jeng, Hong June Park, Thomas L. Quarles +**********/ + +#ifndef BSIM2 +#define BSIM2 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" + + /* declarations for B2 MOSFETs */ + +/* information needed for each instance */ + +typedef struct sBSIM2instance { + struct sBSIM2model *B2modPtr; /* pointer to model */ + struct sBSIM2instance *B2nextInstance; /* pointer to next instance of + *current model*/ + IFuid B2name; /* pointer to character string naming this instance */ + int B2owner; /* number of owner process */ + int B2states; /* index into state table for this device */ + + int B2dNode; /* number of the gate node of the mosfet */ + int B2gNode; /* number of the gate node of the mosfet */ + int B2sNode; /* number of the source node of the mosfet */ + int B2bNode; /* number of the bulk node of the mosfet */ + int B2dNodePrime; /* number of the internal drain node of the mosfet */ + int B2sNodePrime; /* number of the internal source node of the mosfet */ + + double B2l; /* the length of the channel region */ + double B2w; /* the width of the channel region */ + double B2drainArea; /* the area of the drain diffusion */ + double B2sourceArea; /* the area of the source diffusion */ + double B2drainSquares; /* the length of the drain in squares */ + double B2sourceSquares; /* the length of the source in squares */ + double B2drainPerimeter; + double B2sourcePerimeter; + double B2sourceConductance; /* cond. of source (or 0): set in setup */ + double B2drainConductance; /* cond. of drain (or 0): set in setup */ + + double B2icVBS; /* initial condition B-S voltage */ + double B2icVDS; /* initial condition D-S voltage */ + double B2icVGS; /* initial condition G-S voltage */ + double B2von; + double B2vdsat; + int B2off; /* non-zero to indicate device is off for dc analysis*/ + int B2mode; /* device mode : 1 = normal, -1 = inverse */ + + struct bsim2SizeDependParam *pParam; + + + unsigned B2lGiven :1; + unsigned B2wGiven :1; + unsigned B2drainAreaGiven :1; + unsigned B2sourceAreaGiven :1; + unsigned B2drainSquaresGiven :1; + unsigned B2sourceSquaresGiven :1; + unsigned B2drainPerimeterGiven :1; + unsigned B2sourcePerimeterGiven :1; + unsigned B2dNodePrimeSet :1; + unsigned B2sNodePrimeSet :1; + unsigned B2icVBSGiven :1; + unsigned B2icVDSGiven :1; + unsigned B2icVGSGiven :1; + unsigned B2vonGiven :1; + unsigned B2vdsatGiven :1; + + + double *B2DdPtr; /* pointer to sparse matrix element at + * (Drain node,drain node) */ + double *B2GgPtr; /* pointer to sparse matrix element at + * (gate node,gate node) */ + double *B2SsPtr; /* pointer to sparse matrix element at + * (source node,source node) */ + double *B2BbPtr; /* pointer to sparse matrix element at + * (bulk node,bulk node) */ + double *B2DPdpPtr; /* pointer to sparse matrix element at + * (drain prime node,drain prime node) */ + double *B2SPspPtr; /* pointer to sparse matrix element at + * (source prime node,source prime node) */ + double *B2DdpPtr; /* pointer to sparse matrix element at + * (drain node,drain prime node) */ + double *B2GbPtr; /* pointer to sparse matrix element at + * (gate node,bulk node) */ + double *B2GdpPtr; /* pointer to sparse matrix element at + * (gate node,drain prime node) */ + double *B2GspPtr; /* pointer to sparse matrix element at + * (gate node,source prime node) */ + double *B2SspPtr; /* pointer to sparse matrix element at + * (source node,source prime node) */ + double *B2BdpPtr; /* pointer to sparse matrix element at + * (bulk node,drain prime node) */ + double *B2BspPtr; /* pointer to sparse matrix element at + * (bulk node,source prime node) */ + double *B2DPspPtr; /* pointer to sparse matrix element at + * (drain prime node,source prime node) */ + double *B2DPdPtr; /* pointer to sparse matrix element at + * (drain prime node,drain node) */ + double *B2BgPtr; /* pointer to sparse matrix element at + * (bulk node,gate node) */ + double *B2DPgPtr; /* pointer to sparse matrix element at + * (drain prime node,gate node) */ + + double *B2SPgPtr; /* pointer to sparse matrix element at + * (source prime node,gate node) */ + double *B2SPsPtr; /* pointer to sparse matrix element at + * (source prime node,source node) */ + double *B2DPbPtr; /* pointer to sparse matrix element at + * (drain prime node,bulk node) */ + double *B2SPbPtr; /* pointer to sparse matrix element at + * (source prime node,bulk node) */ + double *B2SPdpPtr; /* pointer to sparse matrix element at + * (source prime node,drain prime node) */ + +#define B2vbd B2states+ 0 +#define B2vbs B2states+ 1 +#define B2vgs B2states+ 2 +#define B2vds B2states+ 3 +#define B2cd B2states+ 4 +#define B2id B2states+ 4 +#define B2cbs B2states+ 5 +#define B2ibs B2states+ 5 +#define B2cbd B2states+ 6 +#define B2ibd B2states+ 6 +#define B2gm B2states+ 7 +#define B2gds B2states+ 8 +#define B2gmbs B2states+ 9 +#define B2gbd B2states+ 10 +#define B2gbs B2states+ 11 +#define B2qb B2states+ 12 +#define B2cqb B2states+ 13 +#define B2iqb B2states+ 13 +#define B2qg B2states+ 14 +#define B2cqg B2states+ 15 +#define B2iqg B2states+ 15 +#define B2qd B2states+ 16 +#define B2cqd B2states+ 17 +#define B2iqd B2states+ 17 +#define B2cggb B2states+ 18 +#define B2cgdb B2states+ 19 +#define B2cgsb B2states+ 20 +#define B2cbgb B2states+ 21 +#define B2cbdb B2states+ 22 +#define B2cbsb B2states+ 23 +#define B2capbd B2states+ 24 +#define B2iqbd B2states+ 25 +#define B2cqbd B2states+ 25 +#define B2capbs B2states+ 26 +#define B2iqbs B2states+ 27 +#define B2cqbs B2states+ 27 +#define B2cdgb B2states+ 28 +#define B2cddb B2states+ 29 +#define B2cdsb B2states+ 30 +#define B2vono B2states+ 31 +#define B2vdsato B2states+ 32 +#define B2qbs B2states+ 33 +#define B2qbd B2states+ 34 + +#define B2numStates 35 + +} B2instance ; + +struct bsim2SizeDependParam +{ + double Width; + double Length; + double B2vfb; /* flat band voltage at given L and W */ + double B2phi; /* surface potential at strong inversion */ + double B2k1; /* bulk effect coefficient 1 */ + double B2k2; /* bulk effect coefficient 2 */ + double B2eta0; /* drain induced barrier lowering */ + double B2etaB; /* Vbs dependence of Eta */ + double B2beta0; /* Beta at Vds = 0 and Vgs = Vth */ + double B2beta0B; /* Vbs dependence of Beta0 */ + double B2betas0; /* Beta at Vds=Vdd and Vgs=Vth */ + double B2betasB; /* Vbs dependence of Betas */ + double B2beta20; /* Vds dependence of Beta in tanh term */ + double B2beta2B; /* Vbs dependence of Beta2 */ + double B2beta2G; /* Vgs dependence of Beta2 */ + double B2beta30; /* Vds dependence of Beta in linear term */ + double B2beta3B; /* Vbs dependence of Beta3 */ + double B2beta3G; /* Vgs dependence of Beta3 */ + double B2beta40; /* Vds dependence of Beta in quadra term */ + double B2beta4B; /* Vbs dependence of Beta4 */ + double B2beta4G; /* Vgs dependence of Beta4 */ + double B2ua0; /* Linear Vgs dependence of Mobility */ + double B2uaB; /* Vbs dependence of Ua */ + double B2ub0; /* Quadratic Vgs dependence of Mobility */ + double B2ubB; /* Vbs dependence of Ub */ + double B2u10; /* Drift Velocity Saturation due to Vds */ + double B2u1B; /* Vbs dependence of U1 */ + double B2u1D; /* Vds dependence of U1 */ + double B2n0; /* Subthreshold slope at Vds=0, Vbs=0 */ + double B2nB; /* Vbs dependence of n */ + double B2nD; /* Vds dependence of n */ + double B2vof0; /* Vth offset at Vds=0, Vbs=0 */ + double B2vofB; /* Vbs dependence of Vof */ + double B2vofD; /* Vds dependence of Vof */ + double B2ai0; /* Pre-factor in hot-electron effects */ + double B2aiB; /* Vbs dependence of Ai */ + double B2bi0; /* Exp-factor in hot-electron effects */ + double B2biB; /* Vbs dependence of Bi */ + double B2vghigh; /* Upper bound of cubic spline function */ + double B2vglow; /* Lower bound of cubic spline function */ + double B2GDoverlapCap;/* Gate Drain Overlap Capacitance */ + double B2GSoverlapCap;/* Gate Source Overlap Capacitance */ + double B2GBoverlapCap;/* Gate Bulk Overlap Capacitance */ + double SqrtPhi; + double Phis3; + double CoxWL; + double One_Third_CoxWL; + double Two_Third_CoxWL; + double Arg; + double B2vt0; + struct bsim2SizeDependParam *pNext; +}; + + +/* per model data */ + +typedef struct sBSIM2model { /* model structure for a resistor */ + int B2modType; /* type index of this device type */ + struct sBSIM2model *B2nextModel; /* pointer to next possible model + *in linked list */ + B2instance * B2instances; /* pointer to list of instances + * that have this model */ + IFuid B2modName; /* pointer to the name of this model */ + int B2type; /* device type: 1 = nmos, -1 = pmos */ + int pad; + + double B2vfb0; + double B2vfbL; + double B2vfbW; + double B2phi0; + double B2phiL; + double B2phiW; + double B2k10; + double B2k1L; + double B2k1W; + double B2k20; + double B2k2L; + double B2k2W; + double B2eta00; + double B2eta0L; + double B2eta0W; + double B2etaB0; + double B2etaBL; + double B2etaBW; + double B2deltaL; + double B2deltaW; + double B2mob00; + double B2mob0B0; + double B2mob0BL; + double B2mob0BW ; + double B2mobs00; + double B2mobs0L; + double B2mobs0W; + double B2mobsB0; + double B2mobsBL; + double B2mobsBW; + double B2mob200; + double B2mob20L; + double B2mob20W; + double B2mob2B0; + double B2mob2BL; + double B2mob2BW; + double B2mob2G0; + double B2mob2GL; + double B2mob2GW; + double B2mob300; + double B2mob30L; + double B2mob30W; + double B2mob3B0; + double B2mob3BL; + double B2mob3BW; + double B2mob3G0; + double B2mob3GL; + double B2mob3GW; + double B2mob400; + double B2mob40L; + double B2mob40W; + double B2mob4B0; + double B2mob4BL; + double B2mob4BW; + double B2mob4G0; + double B2mob4GL; + double B2mob4GW; + double B2ua00; + double B2ua0L; + double B2ua0W; + double B2uaB0; + double B2uaBL; + double B2uaBW; + double B2ub00; + double B2ub0L; + double B2ub0W; + double B2ubB0; + double B2ubBL; + double B2ubBW; + double B2u100; + double B2u10L; + double B2u10W; + double B2u1B0; + double B2u1BL; + double B2u1BW; + double B2u1D0; + double B2u1DL; + double B2u1DW; + double B2n00; + double B2n0L; + double B2n0W; + double B2nB0; + double B2nBL; + double B2nBW; + double B2nD0; + double B2nDL; + double B2nDW; + double B2vof00; + double B2vof0L; + double B2vof0W; + double B2vofB0; + double B2vofBL; + double B2vofBW; + double B2vofD0; + double B2vofDL; + double B2vofDW; + double B2ai00; + double B2ai0L; + double B2ai0W; + double B2aiB0; + double B2aiBL; + double B2aiBW; + double B2bi00; + double B2bi0L; + double B2bi0W; + double B2biB0; + double B2biBL; + double B2biBW; + double B2vghigh0; + double B2vghighL; + double B2vghighW; + double B2vglow0; + double B2vglowL; + double B2vglowW; + double B2tox; /* unit: micron */ + double B2Cox; /* unit: F/cm**2 */ + double B2temp; + double B2vdd; + double B2vdd2; + double B2vgg; + double B2vgg2; + double B2vbb; + double B2vbb2; + double B2gateSourceOverlapCap; + double B2gateDrainOverlapCap; + double B2gateBulkOverlapCap; + double B2Vtm; + + double B2sheetResistance; + double B2jctSatCurDensity; + double B2bulkJctPotential; + double B2bulkJctBotGradingCoeff; + double B2bulkJctSideGradingCoeff; + double B2sidewallJctPotential; + double B2unitAreaJctCap; + double B2unitLengthSidewallJctCap; + double B2defaultWidth; + double B2deltaLength; + + struct bsim2SizeDependParam *pSizeDependParamKnot; + + + unsigned B2channelChargePartitionFlag :1; + unsigned B2vfb0Given :1; + unsigned B2vfbLGiven :1; + unsigned B2vfbWGiven :1; + unsigned B2phi0Given :1; + unsigned B2phiLGiven :1; + unsigned B2phiWGiven :1; + unsigned B2k10Given :1; + unsigned B2k1LGiven :1; + unsigned B2k1WGiven :1; + unsigned B2k20Given :1; + unsigned B2k2LGiven :1; + unsigned B2k2WGiven :1; + unsigned B2eta00Given :1; + unsigned B2eta0LGiven :1; + unsigned B2eta0WGiven :1; + unsigned B2etaB0Given :1; + unsigned B2etaBLGiven :1; + unsigned B2etaBWGiven :1; + unsigned B2deltaLGiven :1; + unsigned B2deltaWGiven :1; + unsigned B2mob00Given :1; + unsigned B2mob0B0Given :1; + unsigned B2mob0BLGiven :1; + unsigned B2mob0BWGiven :1; + unsigned B2mobs00Given :1; + unsigned B2mobs0LGiven :1; + unsigned B2mobs0WGiven :1; + unsigned B2mobsB0Given :1; + unsigned B2mobsBLGiven :1; + unsigned B2mobsBWGiven :1; + unsigned B2mob200Given :1; + unsigned B2mob20LGiven :1; + unsigned B2mob20WGiven :1; + unsigned B2mob2B0Given :1; + unsigned B2mob2BLGiven :1; + unsigned B2mob2BWGiven :1; + unsigned B2mob2G0Given :1; + unsigned B2mob2GLGiven :1; + unsigned B2mob2GWGiven :1; + unsigned B2mob300Given :1; + unsigned B2mob30LGiven :1; + unsigned B2mob30WGiven :1; + unsigned B2mob3B0Given :1; + unsigned B2mob3BLGiven :1; + unsigned B2mob3BWGiven :1; + unsigned B2mob3G0Given :1; + unsigned B2mob3GLGiven :1; + unsigned B2mob3GWGiven :1; + unsigned B2mob400Given :1; + unsigned B2mob40LGiven :1; + unsigned B2mob40WGiven :1; + unsigned B2mob4B0Given :1; + unsigned B2mob4BLGiven :1; + unsigned B2mob4BWGiven :1; + unsigned B2mob4G0Given :1; + unsigned B2mob4GLGiven :1; + unsigned B2mob4GWGiven :1; + unsigned B2ua00Given :1; + unsigned B2ua0LGiven :1; + unsigned B2ua0WGiven :1; + unsigned B2uaB0Given :1; + unsigned B2uaBLGiven :1; + unsigned B2uaBWGiven :1; + unsigned B2ub00Given :1; + unsigned B2ub0LGiven :1; + unsigned B2ub0WGiven :1; + unsigned B2ubB0Given :1; + unsigned B2ubBLGiven :1; + unsigned B2ubBWGiven :1; + unsigned B2u100Given :1; + unsigned B2u10LGiven :1; + unsigned B2u10WGiven :1; + unsigned B2u1B0Given :1; + unsigned B2u1BLGiven :1; + unsigned B2u1BWGiven :1; + unsigned B2u1D0Given :1; + unsigned B2u1DLGiven :1; + unsigned B2u1DWGiven :1; + unsigned B2n00Given :1; + unsigned B2n0LGiven :1; + unsigned B2n0WGiven :1; + unsigned B2nB0Given :1; + unsigned B2nBLGiven :1; + unsigned B2nBWGiven :1; + unsigned B2nD0Given :1; + unsigned B2nDLGiven :1; + unsigned B2nDWGiven :1; + unsigned B2vof00Given :1; + unsigned B2vof0LGiven :1; + unsigned B2vof0WGiven :1; + unsigned B2vofB0Given :1; + unsigned B2vofBLGiven :1; + unsigned B2vofBWGiven :1; + unsigned B2vofD0Given :1; + unsigned B2vofDLGiven :1; + unsigned B2vofDWGiven :1; + unsigned B2ai00Given :1; + unsigned B2ai0LGiven :1; + unsigned B2ai0WGiven :1; + unsigned B2aiB0Given :1; + unsigned B2aiBLGiven :1; + unsigned B2aiBWGiven :1; + unsigned B2bi00Given :1; + unsigned B2bi0LGiven :1; + unsigned B2bi0WGiven :1; + unsigned B2biB0Given :1; + unsigned B2biBLGiven :1; + unsigned B2biBWGiven :1; + unsigned B2vghigh0Given :1; + unsigned B2vghighLGiven :1; + unsigned B2vghighWGiven :1; + unsigned B2vglow0Given :1; + unsigned B2vglowLGiven :1; + unsigned B2vglowWGiven :1; + unsigned B2toxGiven :1; + unsigned B2tempGiven :1; + unsigned B2vddGiven :1; + unsigned B2vggGiven :1; + unsigned B2vbbGiven :1; + unsigned B2gateSourceOverlapCapGiven :1; + unsigned B2gateDrainOverlapCapGiven :1; + unsigned B2gateBulkOverlapCapGiven :1; + unsigned B2channelChargePartitionFlagGiven :1; + unsigned B2sheetResistanceGiven :1; + unsigned B2jctSatCurDensityGiven :1; + unsigned B2bulkJctPotentialGiven :1; + unsigned B2bulkJctBotGradingCoeffGiven :1; + unsigned B2sidewallJctPotentialGiven :1; + unsigned B2bulkJctSideGradingCoeffGiven :1; + unsigned B2unitAreaJctCapGiven :1; + unsigned B2unitLengthSidewallJctCapGiven :1; + unsigned B2defaultWidthGiven :1; + unsigned B2deltaLengthGiven :1; + unsigned B2typeGiven :1; + +} B2model; + + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + + +/* device parameters */ +#define BSIM2_W 1 +#define BSIM2_L 2 +#define BSIM2_AS 3 +#define BSIM2_AD 4 +#define BSIM2_PS 5 +#define BSIM2_PD 6 +#define BSIM2_NRS 7 +#define BSIM2_NRD 8 +#define BSIM2_OFF 9 +#define BSIM2_IC_VBS 10 +#define BSIM2_IC_VDS 11 +#define BSIM2_IC_VGS 12 +#define BSIM2_IC 13 + +/* model parameters */ +#define BSIM2_MOD_VFB0 101 +#define BSIM2_MOD_VFBL 102 +#define BSIM2_MOD_VFBW 103 +#define BSIM2_MOD_PHI0 104 +#define BSIM2_MOD_PHIL 105 +#define BSIM2_MOD_PHIW 106 +#define BSIM2_MOD_K10 107 +#define BSIM2_MOD_K1L 108 +#define BSIM2_MOD_K1W 109 +#define BSIM2_MOD_K20 110 +#define BSIM2_MOD_K2L 111 +#define BSIM2_MOD_K2W 112 +#define BSIM2_MOD_ETA00 113 +#define BSIM2_MOD_ETA0L 114 +#define BSIM2_MOD_ETA0W 115 +#define BSIM2_MOD_ETAB0 116 +#define BSIM2_MOD_ETABL 117 +#define BSIM2_MOD_ETABW 118 +#define BSIM2_MOD_DELTAL 119 +#define BSIM2_MOD_DELTAW 120 +#define BSIM2_MOD_MOB00 121 +#define BSIM2_MOD_MOB0B0 122 +#define BSIM2_MOD_MOB0BL 123 +#define BSIM2_MOD_MOB0BW 124 +#define BSIM2_MOD_MOBS00 125 +#define BSIM2_MOD_MOBS0L 126 +#define BSIM2_MOD_MOBS0W 127 +#define BSIM2_MOD_MOBSB0 128 +#define BSIM2_MOD_MOBSBL 129 +#define BSIM2_MOD_MOBSBW 130 +#define BSIM2_MOD_MOB200 131 +#define BSIM2_MOD_MOB20L 132 +#define BSIM2_MOD_MOB20W 133 +#define BSIM2_MOD_MOB2B0 134 +#define BSIM2_MOD_MOB2BL 135 +#define BSIM2_MOD_MOB2BW 136 +#define BSIM2_MOD_MOB2G0 137 +#define BSIM2_MOD_MOB2GL 138 +#define BSIM2_MOD_MOB2GW 139 +#define BSIM2_MOD_MOB300 140 +#define BSIM2_MOD_MOB30L 141 +#define BSIM2_MOD_MOB30W 142 +#define BSIM2_MOD_MOB3B0 143 +#define BSIM2_MOD_MOB3BL 144 +#define BSIM2_MOD_MOB3BW 145 +#define BSIM2_MOD_MOB3G0 146 +#define BSIM2_MOD_MOB3GL 147 +#define BSIM2_MOD_MOB3GW 148 +#define BSIM2_MOD_MOB400 149 +#define BSIM2_MOD_MOB40L 150 +#define BSIM2_MOD_MOB40W 151 +#define BSIM2_MOD_MOB4B0 152 +#define BSIM2_MOD_MOB4BL 153 +#define BSIM2_MOD_MOB4BW 154 +#define BSIM2_MOD_MOB4G0 155 +#define BSIM2_MOD_MOB4GL 156 +#define BSIM2_MOD_MOB4GW 157 +#define BSIM2_MOD_UA00 158 +#define BSIM2_MOD_UA0L 159 +#define BSIM2_MOD_UA0W 160 +#define BSIM2_MOD_UAB0 161 +#define BSIM2_MOD_UABL 162 +#define BSIM2_MOD_UABW 163 +#define BSIM2_MOD_UB00 164 +#define BSIM2_MOD_UB0L 165 +#define BSIM2_MOD_UB0W 166 +#define BSIM2_MOD_UBB0 167 +#define BSIM2_MOD_UBBL 168 +#define BSIM2_MOD_UBBW 169 +#define BSIM2_MOD_U100 170 +#define BSIM2_MOD_U10L 171 +#define BSIM2_MOD_U10W 172 +#define BSIM2_MOD_U1B0 173 +#define BSIM2_MOD_U1BL 174 +#define BSIM2_MOD_U1BW 175 +#define BSIM2_MOD_U1D0 176 +#define BSIM2_MOD_U1DL 177 +#define BSIM2_MOD_U1DW 178 +#define BSIM2_MOD_N00 179 +#define BSIM2_MOD_N0L 180 +#define BSIM2_MOD_N0W 181 +#define BSIM2_MOD_NB0 182 +#define BSIM2_MOD_NBL 183 +#define BSIM2_MOD_NBW 184 +#define BSIM2_MOD_ND0 185 +#define BSIM2_MOD_NDL 186 +#define BSIM2_MOD_NDW 187 +#define BSIM2_MOD_VOF00 188 +#define BSIM2_MOD_VOF0L 189 +#define BSIM2_MOD_VOF0W 190 +#define BSIM2_MOD_VOFB0 191 +#define BSIM2_MOD_VOFBL 192 +#define BSIM2_MOD_VOFBW 193 +#define BSIM2_MOD_VOFD0 194 +#define BSIM2_MOD_VOFDL 195 +#define BSIM2_MOD_VOFDW 196 +#define BSIM2_MOD_AI00 197 +#define BSIM2_MOD_AI0L 198 +#define BSIM2_MOD_AI0W 199 +#define BSIM2_MOD_AIB0 200 +#define BSIM2_MOD_AIBL 201 +#define BSIM2_MOD_AIBW 202 +#define BSIM2_MOD_BI00 203 +#define BSIM2_MOD_BI0L 204 +#define BSIM2_MOD_BI0W 205 +#define BSIM2_MOD_BIB0 206 +#define BSIM2_MOD_BIBL 207 +#define BSIM2_MOD_BIBW 208 +#define BSIM2_MOD_VGHIGH0 209 +#define BSIM2_MOD_VGHIGHL 210 +#define BSIM2_MOD_VGHIGHW 211 +#define BSIM2_MOD_VGLOW0 212 +#define BSIM2_MOD_VGLOWL 213 +#define BSIM2_MOD_VGLOWW 214 +#define BSIM2_MOD_TOX 215 +#define BSIM2_MOD_TEMP 216 +#define BSIM2_MOD_VDD 217 +#define BSIM2_MOD_VGG 218 +#define BSIM2_MOD_VBB 219 +#define BSIM2_MOD_CGSO 220 +#define BSIM2_MOD_CGDO 221 +#define BSIM2_MOD_CGBO 222 +#define BSIM2_MOD_XPART 223 +#define BSIM2_MOD_RSH 224 +#define BSIM2_MOD_JS 225 +#define BSIM2_MOD_PB 226 +#define BSIM2_MOD_MJ 227 +#define BSIM2_MOD_PBSW 228 +#define BSIM2_MOD_MJSW 229 +#define BSIM2_MOD_CJ 230 +#define BSIM2_MOD_CJSW 231 +#define BSIM2_MOD_DEFWIDTH 232 +#define BSIM2_MOD_DELLENGTH 233 +#define BSIM2_MOD_NMOS 234 +#define BSIM2_MOD_PMOS 235 + +/* device questions */ +#define BSIM2_DNODE 241 +#define BSIM2_GNODE 242 +#define BSIM2_SNODE 243 +#define BSIM2_BNODE 244 +#define BSIM2_DNODEPRIME 245 +#define BSIM2_SNODEPRIME 246 +#define BSIM2_VBD 247 +#define BSIM2_VBS 248 +#define BSIM2_VGS 249 +#define BSIM2_VDS 250 +#define BSIM2_CD 251 +#define BSIM2_CBS 252 +#define BSIM2_CBD 253 +#define BSIM2_GM 254 +#define BSIM2_GDS 255 +#define BSIM2_GMBS 256 +#define BSIM2_GBD 257 +#define BSIM2_GBS 258 +#define BSIM2_QB 259 +#define BSIM2_CQB 260 +#define BSIM2_QG 261 +#define BSIM2_CQG 262 +#define BSIM2_QD 263 +#define BSIM2_CQD 264 +#define BSIM2_CGG 265 +#define BSIM2_CGD 266 +#define BSIM2_CGS 267 +#define BSIM2_CBG 268 +#define BSIM2_CAPBD 269 +#define BSIM2_CQBD 270 +#define BSIM2_CAPBS 271 +#define BSIM2_CQBS 272 +#define BSIM2_CDG 273 +#define BSIM2_CDD 274 +#define BSIM2_CDS 275 +#define BSIM2_VON 276 +#define BSIM2_QBS 277 +#define BSIM2_QBD 278 +#define BSIM2_SOURCECONDUCT 279 +#define BSIM2_DRAINCONDUCT 280 + +/* model questions */ + +#include "bsim2ext.h" + +#ifdef __STDC__ +extern void B2evaluate(double,double,double,B2instance*,B2model*, + double*,double*,double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, CKTcircuit*); +#else /* stdc */ +extern void B2evaluate(); +#endif /* stdc */ + +#endif /*B2*/ + diff --git a/src/spicelib/devices/bsim2/bsim2ext.h b/src/spicelib/devices/bsim2/bsim2ext.h new file mode 100644 index 000000000..ce9b16bb2 --- /dev/null +++ b/src/spicelib/devices/bsim2/bsim2ext.h @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Min-Chie Jeng, Hong June Park, Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int B2acLoad(GENmodel *,CKTcircuit*); +extern int B2ask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int B2convTest(GENmodel *,CKTcircuit*); +extern int B2delete(GENmodel*,IFuid,GENinstance**); +extern void B2destroy(GENmodel**); +extern int B2getic(GENmodel*,CKTcircuit*); +extern int B2load(GENmodel*,CKTcircuit*); +extern int B2mAsk(CKTcircuit*,GENmodel *,int, IFvalue*); +extern int B2mDelete(GENmodel**,IFuid,GENmodel*); +extern int B2mParam(int,IFvalue*,GENmodel*); +extern void B2mosCap(CKTcircuit*, double, double, double, double*, + double, double, double, double, double, double, + double*, double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*); +extern int B2param(int,IFvalue*,GENinstance*,IFvalue*); +extern int B2pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int B2setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int B2unsetup(GENmodel*,CKTcircuit*); +extern int B2temp(GENmodel*,CKTcircuit*); +extern int B2trunc(GENmodel*,CKTcircuit*,double*); +#else /* stdc */ +extern int B2acLoad(); +extern int B2delete(); +extern void B2destroy(); +extern int B2getic(); +extern int B2load(); +extern int B2mDelete(); +extern int B2ask(); +extern int B2mAsk(); +extern int B2convTest(); +extern int B2temp(); +extern int B2mParam(); +extern void B2mosCap(); +extern int B2param(); +extern int B2pzLoad(); +extern int B2setup(); +extern int B2unsetup(); +extern int B2trunc(); + +#endif /* stdc */ diff --git a/src/spicelib/devices/bsim2/bsim2itf.h b/src/spicelib/devices/bsim2/bsim2itf.h new file mode 100644 index 000000000..593233a9f --- /dev/null +++ b/src/spicelib/devices/bsim2/bsim2itf.h @@ -0,0 +1,83 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_bsim2 + +#ifndef DEV_BSIM2 +#define DEV_BSIM2 + +#include "bsim2ext.h" + +extern IFparm B2pTable[ ]; +extern IFparm B2mPTable[ ]; +extern char *B2names[ ]; +extern int B2pTSize; +extern int B2mPTSize; +extern int B2nSize; +extern int B2iSize; +extern int B2mSize; + +SPICEdev B2info = { + { "BSIM2", + "Berkeley Short Channel IGFET Model", + + &B2nSize, + &B2nSize, + B2names, + + &B2pTSize, + B2pTable, + + &B2mPTSize, + B2mPTable, + DEV_DEFAULT + }, + + B2param, + B2mParam, + B2load, + B2setup, + B2unsetup, + B2setup, + B2temp, + B2trunc, + NULL, + B2acLoad, + NULL, + B2destroy, +#ifdef DELETES + B2mDelete, + B2delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + B2getic, + B2ask, + B2mAsk, +#ifdef AN_pz + B2pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + B2convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + + &B2iSize, + &B2mSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/bsim3/ChangeLog b/src/spicelib/devices/bsim3/ChangeLog new file mode 100644 index 000000000..6d1ab39da --- /dev/null +++ b/src/spicelib/devices/bsim3/ChangeLog @@ -0,0 +1,4 @@ +1999-09-06 Arno Peters + + * b3ld.c: Removed unused variable. + diff --git a/src/spicelib/devices/bsim3/Makefile.am b/src/spicelib/devices/bsim3/Makefile.am new file mode 100644 index 000000000..0e9484e83 --- /dev/null +++ b/src/spicelib/devices/bsim3/Makefile.am @@ -0,0 +1,32 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libbsim3.la + +libbsim3_la_SOURCES = \ + b3.c \ + b3acld.c \ + b3ask.c \ + b3check.c \ + b3cvtest.c \ + b3del.c \ + b3dest.c \ + b3getic.c \ + b3ld.c \ + b3mask.c \ + b3mdel.c \ + b3mpar.c \ + b3noi.c \ + b3par.c \ + b3pzld.c \ + b3set.c \ + b3temp.c \ + b3trunc.c \ + bsim3def.h \ + bsim3ext.h \ + bsim3itf.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/bsim3/b3.c b/src/spicelib/devices/bsim3/b3.c new file mode 100644 index 000000000..b407910c2 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3.c @@ -0,0 +1,497 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3.c +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "bsim3def.h" +#include "suffix.h" + +IFparm BSIM3pTable[] = { /* parameters */ +IOP( "l", BSIM3_L, IF_REAL , "Length"), +IOP( "w", BSIM3_W, IF_REAL , "Width"), +IOP( "ad", BSIM3_AD, IF_REAL , "Drain area"), +IOP( "as", BSIM3_AS, IF_REAL , "Source area"), +IOP( "pd", BSIM3_PD, IF_REAL , "Drain perimeter"), +IOP( "ps", BSIM3_PS, IF_REAL , "Source perimeter"), +IOP( "nrd", BSIM3_NRD, IF_REAL , "Number of squares in drain"), +IOP( "nrs", BSIM3_NRS, IF_REAL , "Number of squares in source"), +IOP( "off", BSIM3_OFF, IF_FLAG , "Device is initially off"), +IOP( "nqsmod", BSIM3_NQSMOD, IF_INTEGER, "Non-quasi-static model selector"), +IP( "ic", BSIM3_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"), +OP( "gmbs", BSIM3_GMBS, IF_REAL, "Gmb"), +OP( "gm", BSIM3_GM, IF_REAL, "Gm"), +OP( "gds", BSIM3_GDS, IF_REAL, "Gds"), +OP( "vdsat", BSIM3_VDSAT, IF_REAL, "Vdsat"), +OP( "vth", BSIM3_VON, IF_REAL, "Vth"), +OP( "id", BSIM3_CD, IF_REAL, "Ids"), +OP( "vbs", BSIM3_VBS, IF_REAL, "Vbs"), +OP( "vgs", BSIM3_VGS, IF_REAL, "Vgs"), +OP( "vds", BSIM3_VDS, IF_REAL, "Vds"), +}; + +IFparm BSIM3mPTable[] = { /* model parameters */ +IOP( "capmod", BSIM3_MOD_CAPMOD, IF_INTEGER, "Capacitance model selector"), +IOP( "mobmod", BSIM3_MOD_MOBMOD, IF_INTEGER, "Mobility model selector"), +IOP( "noimod", BSIM3_MOD_NOIMOD, IF_INTEGER, "Noise model selector"), +IOP( "paramchk", BSIM3_MOD_PARAMCHK, IF_INTEGER, "Model parameter checking selector"), +IOP( "binunit", BSIM3_MOD_BINUNIT, IF_INTEGER, "Bin unit selector"), +IOP( "version", BSIM3_MOD_VERSION, IF_STRING, " parameter for model version"), +IOP( "tox", BSIM3_MOD_TOX, IF_REAL, "Gate oxide thickness in meters"), + +IOP( "toxm", BSIM3_MOD_TOXM, IF_REAL, "Gate oxide thickness used in extraction"), +IOP( "cdsc", BSIM3_MOD_CDSC, IF_REAL, "Drain/Source and channel coupling capacitance"), +IOP( "cdscb", BSIM3_MOD_CDSCB, IF_REAL, "Body-bias dependence of cdsc"), +IOP( "cdscd", BSIM3_MOD_CDSCD, IF_REAL, "Drain-bias dependence of cdsc"), +IOP( "cit", BSIM3_MOD_CIT, IF_REAL, "Interface state capacitance"), +IOP( "nfactor", BSIM3_MOD_NFACTOR, IF_REAL, "Subthreshold swing Coefficient"), +IOP( "xj", BSIM3_MOD_XJ, IF_REAL, "Junction depth in meters"), +IOP( "vsat", BSIM3_MOD_VSAT, IF_REAL, "Saturation velocity at tnom"), +IOP( "at", BSIM3_MOD_AT, IF_REAL, "Temperature coefficient of vsat"), +IOP( "a0", BSIM3_MOD_A0, IF_REAL, "Non-uniform depletion width effect coefficient."), +IOP( "ags", BSIM3_MOD_AGS, IF_REAL, "Gate bias coefficient of Abulk."), +IOP( "a1", BSIM3_MOD_A1, IF_REAL, "Non-saturation effect coefficient"), +IOP( "a2", BSIM3_MOD_A2, IF_REAL, "Non-saturation effect coefficient"), +IOP( "keta", BSIM3_MOD_KETA, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect."), +IOP( "nsub", BSIM3_MOD_NSUB, IF_REAL, "Substrate doping concentration"), +IOP( "nch", BSIM3_MOD_NPEAK, IF_REAL, "Channel doping concentration"), +IOP( "ngate", BSIM3_MOD_NGATE, IF_REAL, "Poly-gate doping concentration"), +IOP( "gamma1", BSIM3_MOD_GAMMA1, IF_REAL, "Vth body coefficient"), +IOP( "gamma2", BSIM3_MOD_GAMMA2, IF_REAL, "Vth body coefficient"), +IOP( "vbx", BSIM3_MOD_VBX, IF_REAL, "Vth transition body Voltage"), +IOP( "vbm", BSIM3_MOD_VBM, IF_REAL, "Maximum body voltage"), + +IOP( "xt", BSIM3_MOD_XT, IF_REAL, "Doping depth"), +IOP( "k1", BSIM3_MOD_K1, IF_REAL, "Bulk effect coefficient 1"), +IOP( "kt1", BSIM3_MOD_KT1, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt1l", BSIM3_MOD_KT1L, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt2", BSIM3_MOD_KT2, IF_REAL, "Body-coefficient of kt1"), +IOP( "k2", BSIM3_MOD_K2, IF_REAL, "Bulk effect coefficient 2"), +IOP( "k3", BSIM3_MOD_K3, IF_REAL, "Narrow width effect coefficient"), +IOP( "k3b", BSIM3_MOD_K3B, IF_REAL, "Body effect coefficient of k3"), +IOP( "w0", BSIM3_MOD_W0, IF_REAL, "Narrow width effect parameter"), +IOP( "nlx", BSIM3_MOD_NLX, IF_REAL, "Lateral non-uniform doping effect"), +IOP( "dvt0", BSIM3_MOD_DVT0, IF_REAL, "Short channel effect coeff. 0"), +IOP( "dvt1", BSIM3_MOD_DVT1, IF_REAL, "Short channel effect coeff. 1"), +IOP( "dvt2", BSIM3_MOD_DVT2, IF_REAL, "Short channel effect coeff. 2"), +IOP( "dvt0w", BSIM3_MOD_DVT0W, IF_REAL, "Narrow Width coeff. 0"), +IOP( "dvt1w", BSIM3_MOD_DVT1W, IF_REAL, "Narrow Width effect coeff. 1"), +IOP( "dvt2w", BSIM3_MOD_DVT2W, IF_REAL, "Narrow Width effect coeff. 2"), +IOP( "drout", BSIM3_MOD_DROUT, IF_REAL, "DIBL coefficient of output resistance"), +IOP( "dsub", BSIM3_MOD_DSUB, IF_REAL, "DIBL coefficient in the subthreshold region"), +IOP( "vth0", BSIM3_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "vtho", BSIM3_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "ua", BSIM3_MOD_UA, IF_REAL, "Linear gate dependence of mobility"), +IOP( "ua1", BSIM3_MOD_UA1, IF_REAL, "Temperature coefficient of ua"), +IOP( "ub", BSIM3_MOD_UB, IF_REAL, "Quadratic gate dependence of mobility"), +IOP( "ub1", BSIM3_MOD_UB1, IF_REAL, "Temperature coefficient of ub"), +IOP( "uc", BSIM3_MOD_UC, IF_REAL, "Body-bias dependence of mobility"), +IOP( "uc1", BSIM3_MOD_UC1, IF_REAL, "Temperature coefficient of uc"), +IOP( "u0", BSIM3_MOD_U0, IF_REAL, "Low-field mobility at Tnom"), +IOP( "ute", BSIM3_MOD_UTE, IF_REAL, "Temperature coefficient of mobility"), +IOP( "voff", BSIM3_MOD_VOFF, IF_REAL, "Threshold voltage offset"), +IOP( "tnom", BSIM3_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), +IOP( "cgso", BSIM3_MOD_CGSO, IF_REAL, "Gate-source overlap capacitance per width"), +IOP( "cgdo", BSIM3_MOD_CGDO, IF_REAL, "Gate-drain overlap capacitance per width"), +IOP( "cgbo", BSIM3_MOD_CGBO, IF_REAL, "Gate-bulk overlap capacitance per length"), +IOP( "xpart", BSIM3_MOD_XPART, IF_REAL, "Channel charge partitioning"), +IOP( "elm", BSIM3_MOD_ELM, IF_REAL, "Non-quasi-static Elmore Constant Parameter"), +IOP( "delta", BSIM3_MOD_DELTA, IF_REAL, "Effective Vds parameter"), +IOP( "rsh", BSIM3_MOD_RSH, IF_REAL, "Source-drain sheet resistance"), +IOP( "rdsw", BSIM3_MOD_RDSW, IF_REAL, "Source-drain resistance per width"), + +IOP( "prwg", BSIM3_MOD_PRWG, IF_REAL, "Gate-bias effect on parasitic resistance "), +IOP( "prwb", BSIM3_MOD_PRWB, IF_REAL, "Body-effect on parasitic resistance "), + +IOP( "prt", BSIM3_MOD_PRT, IF_REAL, "Temperature coefficient of parasitic resistance "), +IOP( "eta0", BSIM3_MOD_ETA0, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "etab", BSIM3_MOD_ETAB, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "pclm", BSIM3_MOD_PCLM, IF_REAL, "Channel length modulation Coefficient"), +IOP( "pdiblc1", BSIM3_MOD_PDIBL1, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblc2", BSIM3_MOD_PDIBL2, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblcb", BSIM3_MOD_PDIBLB, IF_REAL, "Body-effect on drain-induced barrier lowering"), +IOP( "pscbe1", BSIM3_MOD_PSCBE1, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pscbe2", BSIM3_MOD_PSCBE2, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pvag", BSIM3_MOD_PVAG, IF_REAL, "Gate dependence of output resistance parameter"), +IOP( "js", BSIM3_MOD_JS, IF_REAL, "Source/drain junction reverse saturation current density"), +IOP( "jsw", BSIM3_MOD_JSW, IF_REAL, "Sidewall junction reverse saturation current density"), +IOP( "pb", BSIM3_MOD_PB, IF_REAL, "Source/drain junction built-in potential"), +IOP( "nj", BSIM3_MOD_NJ, IF_REAL, "Source/drain junction emission coefficient"), +IOP( "xti", BSIM3_MOD_XTI, IF_REAL, "Junction current temperature exponent"), +IOP( "mj", BSIM3_MOD_MJ, IF_REAL, "Source/drain bottom junction capacitance grading coefficient"), +IOP( "pbsw", BSIM3_MOD_PBSW, IF_REAL, "Source/drain sidewall junction capacitance built in potential"), +IOP( "mjsw", BSIM3_MOD_MJSW, IF_REAL, "Source/drain sidewall junction capacitance grading coefficient"), +IOP( "pbswg", BSIM3_MOD_PBSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance built in potential"), +IOP( "mjswg", BSIM3_MOD_MJSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance grading coefficient"), +IOP( "cj", BSIM3_MOD_CJ, IF_REAL, "Source/drain bottom junction capacitance per unit area"), +IOP( "vfbcv", BSIM3_MOD_VFBCV, IF_REAL, "Flat Band Voltage parameter for capmod=0 only"), +IOP( "vfb", BSIM3_MOD_VFB, IF_REAL, "Flat Band Voltage"), +IOP( "cjsw", BSIM3_MOD_CJSW, IF_REAL, "Source/drain sidewall junction capacitance per unit periphery"), +IOP( "cjswg", BSIM3_MOD_CJSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance per unit width"), +IOP( "tpb", BSIM3_MOD_TPB, IF_REAL, "Temperature coefficient of pb"), +IOP( "tcj", BSIM3_MOD_TCJ, IF_REAL, "Temperature coefficient of cj"), +IOP( "tpbsw", BSIM3_MOD_TPBSW, IF_REAL, "Temperature coefficient of pbsw"), +IOP( "tcjsw", BSIM3_MOD_TCJSW, IF_REAL, "Temperature coefficient of cjsw"), +IOP( "tpbswg", BSIM3_MOD_TPBSWG, IF_REAL, "Temperature coefficient of pbswg"), +IOP( "tcjswg", BSIM3_MOD_TCJSWG, IF_REAL, "Temperature coefficient of cjswg"), +IOP( "acde", BSIM3_MOD_ACDE, IF_REAL, "Exponential coefficient for finite charge thickness"), +IOP( "moin", BSIM3_MOD_MOIN, IF_REAL, "Coefficient for gate-bias dependent surface potential"), +IOP( "noff", BSIM3_MOD_NOFF, IF_REAL, "C-V turn-on/off parameter"), +IOP( "voffcv", BSIM3_MOD_VOFFCV, IF_REAL, "C-V lateral-shift parameter"), +IOP( "lint", BSIM3_MOD_LINT, IF_REAL, "Length reduction parameter"), +IOP( "ll", BSIM3_MOD_LL, IF_REAL, "Length reduction parameter"), +IOP( "llc", BSIM3_MOD_LLC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lln", BSIM3_MOD_LLN, IF_REAL, "Length reduction parameter"), +IOP( "lw", BSIM3_MOD_LW, IF_REAL, "Length reduction parameter"), +IOP( "lwc", BSIM3_MOD_LWC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lwn", BSIM3_MOD_LWN, IF_REAL, "Length reduction parameter"), +IOP( "lwl", BSIM3_MOD_LWL, IF_REAL, "Length reduction parameter"), +IOP( "lwlc", BSIM3_MOD_LWLC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lmin", BSIM3_MOD_LMIN, IF_REAL, "Minimum length for the model"), +IOP( "lmax", BSIM3_MOD_LMAX, IF_REAL, "Maximum length for the model"), + +IOP( "wr", BSIM3_MOD_WR, IF_REAL, "Width dependence of rds"), +IOP( "wint", BSIM3_MOD_WINT, IF_REAL, "Width reduction parameter"), +IOP( "dwg", BSIM3_MOD_DWG, IF_REAL, "Width reduction parameter"), +IOP( "dwb", BSIM3_MOD_DWB, IF_REAL, "Width reduction parameter"), + +IOP( "wl", BSIM3_MOD_WL, IF_REAL, "Width reduction parameter"), +IOP( "wlc", BSIM3_MOD_WLC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wln", BSIM3_MOD_WLN, IF_REAL, "Width reduction parameter"), +IOP( "ww", BSIM3_MOD_WW, IF_REAL, "Width reduction parameter"), +IOP( "wwc", BSIM3_MOD_WWC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wwn", BSIM3_MOD_WWN, IF_REAL, "Width reduction parameter"), +IOP( "wwl", BSIM3_MOD_WWL, IF_REAL, "Width reduction parameter"), +IOP( "wwlc", BSIM3_MOD_WWLC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wmin", BSIM3_MOD_WMIN, IF_REAL, "Minimum width for the model"), +IOP( "wmax", BSIM3_MOD_WMAX, IF_REAL, "Maximum width for the model"), + +IOP( "b0", BSIM3_MOD_B0, IF_REAL, "Abulk narrow width parameter"), +IOP( "b1", BSIM3_MOD_B1, IF_REAL, "Abulk narrow width parameter"), + +IOP( "cgsl", BSIM3_MOD_CGSL, IF_REAL, "New C-V model parameter"), +IOP( "cgdl", BSIM3_MOD_CGDL, IF_REAL, "New C-V model parameter"), +IOP( "ckappa", BSIM3_MOD_CKAPPA, IF_REAL, "New C-V model parameter"), +IOP( "cf", BSIM3_MOD_CF, IF_REAL, "Fringe capacitance parameter"), +IOP( "clc", BSIM3_MOD_CLC, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "cle", BSIM3_MOD_CLE, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "dwc", BSIM3_MOD_DWC, IF_REAL, "Delta W for C-V model"), +IOP( "dlc", BSIM3_MOD_DLC, IF_REAL, "Delta L for C-V model"), + +IOP( "alpha0", BSIM3_MOD_ALPHA0, IF_REAL, "substrate current model parameter"), +IOP( "alpha1", BSIM3_MOD_ALPHA1, IF_REAL, "substrate current model parameter"), +IOP( "beta0", BSIM3_MOD_BETA0, IF_REAL, "substrate current model parameter"), +IOP( "ijth", BSIM3_MOD_IJTH, IF_REAL, "Diode limiting current"), + +IOP( "lcdsc", BSIM3_MOD_LCDSC, IF_REAL, "Length dependence of cdsc"), +IOP( "lcdscb", BSIM3_MOD_LCDSCB, IF_REAL, "Length dependence of cdscb"), +IOP( "lcdscd", BSIM3_MOD_LCDSCD, IF_REAL, "Length dependence of cdscd"), +IOP( "lcit", BSIM3_MOD_LCIT, IF_REAL, "Length dependence of cit"), +IOP( "lnfactor", BSIM3_MOD_LNFACTOR, IF_REAL, "Length dependence of nfactor"), +IOP( "lxj", BSIM3_MOD_LXJ, IF_REAL, "Length dependence of xj"), +IOP( "lvsat", BSIM3_MOD_LVSAT, IF_REAL, "Length dependence of vsat"), +IOP( "lat", BSIM3_MOD_LAT, IF_REAL, "Length dependence of at"), +IOP( "la0", BSIM3_MOD_LA0, IF_REAL, "Length dependence of a0"), +IOP( "lags", BSIM3_MOD_LAGS, IF_REAL, "Length dependence of ags"), +IOP( "la1", BSIM3_MOD_LA1, IF_REAL, "Length dependence of a1"), +IOP( "la2", BSIM3_MOD_LA2, IF_REAL, "Length dependence of a2"), +IOP( "lketa", BSIM3_MOD_LKETA, IF_REAL, "Length dependence of keta"), +IOP( "lnsub", BSIM3_MOD_LNSUB, IF_REAL, "Length dependence of nsub"), +IOP( "lnch", BSIM3_MOD_LNPEAK, IF_REAL, "Length dependence of nch"), +IOP( "lngate", BSIM3_MOD_LNGATE, IF_REAL, "Length dependence of ngate"), +IOP( "lgamma1", BSIM3_MOD_LGAMMA1, IF_REAL, "Length dependence of gamma1"), +IOP( "lgamma2", BSIM3_MOD_LGAMMA2, IF_REAL, "Length dependence of gamma2"), +IOP( "lvbx", BSIM3_MOD_LVBX, IF_REAL, "Length dependence of vbx"), +IOP( "lvbm", BSIM3_MOD_LVBM, IF_REAL, "Length dependence of vbm"), +IOP( "lxt", BSIM3_MOD_LXT, IF_REAL, "Length dependence of xt"), +IOP( "lk1", BSIM3_MOD_LK1, IF_REAL, "Length dependence of k1"), +IOP( "lkt1", BSIM3_MOD_LKT1, IF_REAL, "Length dependence of kt1"), +IOP( "lkt1l", BSIM3_MOD_LKT1L, IF_REAL, "Length dependence of kt1l"), +IOP( "lkt2", BSIM3_MOD_LKT2, IF_REAL, "Length dependence of kt2"), +IOP( "lk2", BSIM3_MOD_LK2, IF_REAL, "Length dependence of k2"), +IOP( "lk3", BSIM3_MOD_LK3, IF_REAL, "Length dependence of k3"), +IOP( "lk3b", BSIM3_MOD_LK3B, IF_REAL, "Length dependence of k3b"), +IOP( "lw0", BSIM3_MOD_LW0, IF_REAL, "Length dependence of w0"), +IOP( "lnlx", BSIM3_MOD_LNLX, IF_REAL, "Length dependence of nlx"), +IOP( "ldvt0", BSIM3_MOD_LDVT0, IF_REAL, "Length dependence of dvt0"), +IOP( "ldvt1", BSIM3_MOD_LDVT1, IF_REAL, "Length dependence of dvt1"), +IOP( "ldvt2", BSIM3_MOD_LDVT2, IF_REAL, "Length dependence of dvt2"), +IOP( "ldvt0w", BSIM3_MOD_LDVT0W, IF_REAL, "Length dependence of dvt0w"), +IOP( "ldvt1w", BSIM3_MOD_LDVT1W, IF_REAL, "Length dependence of dvt1w"), +IOP( "ldvt2w", BSIM3_MOD_LDVT2W, IF_REAL, "Length dependence of dvt2w"), +IOP( "ldrout", BSIM3_MOD_LDROUT, IF_REAL, "Length dependence of drout"), +IOP( "ldsub", BSIM3_MOD_LDSUB, IF_REAL, "Length dependence of dsub"), +IOP( "lvth0", BSIM3_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lvtho", BSIM3_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lua", BSIM3_MOD_LUA, IF_REAL, "Length dependence of ua"), +IOP( "lua1", BSIM3_MOD_LUA1, IF_REAL, "Length dependence of ua1"), +IOP( "lub", BSIM3_MOD_LUB, IF_REAL, "Length dependence of ub"), +IOP( "lub1", BSIM3_MOD_LUB1, IF_REAL, "Length dependence of ub1"), +IOP( "luc", BSIM3_MOD_LUC, IF_REAL, "Length dependence of uc"), +IOP( "luc1", BSIM3_MOD_LUC1, IF_REAL, "Length dependence of uc1"), +IOP( "lu0", BSIM3_MOD_LU0, IF_REAL, "Length dependence of u0"), +IOP( "lute", BSIM3_MOD_LUTE, IF_REAL, "Length dependence of ute"), +IOP( "lvoff", BSIM3_MOD_LVOFF, IF_REAL, "Length dependence of voff"), +IOP( "lelm", BSIM3_MOD_LELM, IF_REAL, "Length dependence of elm"), +IOP( "ldelta", BSIM3_MOD_LDELTA, IF_REAL, "Length dependence of delta"), +IOP( "lrdsw", BSIM3_MOD_LRDSW, IF_REAL, "Length dependence of rdsw "), + +IOP( "lprwg", BSIM3_MOD_LPRWG, IF_REAL, "Length dependence of prwg "), +IOP( "lprwb", BSIM3_MOD_LPRWB, IF_REAL, "Length dependence of prwb "), + +IOP( "lprt", BSIM3_MOD_LPRT, IF_REAL, "Length dependence of prt "), +IOP( "leta0", BSIM3_MOD_LETA0, IF_REAL, "Length dependence of eta0"), +IOP( "letab", BSIM3_MOD_LETAB, IF_REAL, "Length dependence of etab"), +IOP( "lpclm", BSIM3_MOD_LPCLM, IF_REAL, "Length dependence of pclm"), +IOP( "lpdiblc1", BSIM3_MOD_LPDIBL1, IF_REAL, "Length dependence of pdiblc1"), +IOP( "lpdiblc2", BSIM3_MOD_LPDIBL2, IF_REAL, "Length dependence of pdiblc2"), +IOP( "lpdiblcb", BSIM3_MOD_LPDIBLB, IF_REAL, "Length dependence of pdiblcb"), +IOP( "lpscbe1", BSIM3_MOD_LPSCBE1, IF_REAL, "Length dependence of pscbe1"), +IOP( "lpscbe2", BSIM3_MOD_LPSCBE2, IF_REAL, "Length dependence of pscbe2"), +IOP( "lpvag", BSIM3_MOD_LPVAG, IF_REAL, "Length dependence of pvag"), +IOP( "lwr", BSIM3_MOD_LWR, IF_REAL, "Length dependence of wr"), +IOP( "ldwg", BSIM3_MOD_LDWG, IF_REAL, "Length dependence of dwg"), +IOP( "ldwb", BSIM3_MOD_LDWB, IF_REAL, "Length dependence of dwb"), +IOP( "lb0", BSIM3_MOD_LB0, IF_REAL, "Length dependence of b0"), +IOP( "lb1", BSIM3_MOD_LB1, IF_REAL, "Length dependence of b1"), +IOP( "lcgsl", BSIM3_MOD_LCGSL, IF_REAL, "Length dependence of cgsl"), +IOP( "lcgdl", BSIM3_MOD_LCGDL, IF_REAL, "Length dependence of cgdl"), +IOP( "lckappa", BSIM3_MOD_LCKAPPA, IF_REAL, "Length dependence of ckappa"), +IOP( "lcf", BSIM3_MOD_LCF, IF_REAL, "Length dependence of cf"), +IOP( "lclc", BSIM3_MOD_LCLC, IF_REAL, "Length dependence of clc"), +IOP( "lcle", BSIM3_MOD_LCLE, IF_REAL, "Length dependence of cle"), +IOP( "lalpha0", BSIM3_MOD_LALPHA0, IF_REAL, "Length dependence of alpha0"), +IOP( "lalpha1", BSIM3_MOD_LALPHA1, IF_REAL, "Length dependence of alpha1"), +IOP( "lbeta0", BSIM3_MOD_LBETA0, IF_REAL, "Length dependence of beta0"), +IOP( "lvfbcv", BSIM3_MOD_LVFBCV, IF_REAL, "Length dependence of vfbcv"), +IOP( "lvfb", BSIM3_MOD_LVFB, IF_REAL, "Length dependence of vfb"), +IOP( "lacde", BSIM3_MOD_LACDE, IF_REAL, "Length dependence of acde"), +IOP( "lmoin", BSIM3_MOD_LMOIN, IF_REAL, "Length dependence of moin"), +IOP( "lnoff", BSIM3_MOD_LNOFF, IF_REAL, "Length dependence of noff"), +IOP( "lvoffcv", BSIM3_MOD_LVOFFCV, IF_REAL, "Length dependence of voffcv"), +IOP( "wcdsc", BSIM3_MOD_WCDSC, IF_REAL, "Width dependence of cdsc"), +IOP( "wcdscb", BSIM3_MOD_WCDSCB, IF_REAL, "Width dependence of cdscb"), +IOP( "wcdscd", BSIM3_MOD_WCDSCD, IF_REAL, "Width dependence of cdscd"), +IOP( "wcit", BSIM3_MOD_WCIT, IF_REAL, "Width dependence of cit"), +IOP( "wnfactor", BSIM3_MOD_WNFACTOR, IF_REAL, "Width dependence of nfactor"), +IOP( "wxj", BSIM3_MOD_WXJ, IF_REAL, "Width dependence of xj"), +IOP( "wvsat", BSIM3_MOD_WVSAT, IF_REAL, "Width dependence of vsat"), +IOP( "wat", BSIM3_MOD_WAT, IF_REAL, "Width dependence of at"), +IOP( "wa0", BSIM3_MOD_WA0, IF_REAL, "Width dependence of a0"), +IOP( "wags", BSIM3_MOD_WAGS, IF_REAL, "Width dependence of ags"), +IOP( "wa1", BSIM3_MOD_WA1, IF_REAL, "Width dependence of a1"), +IOP( "wa2", BSIM3_MOD_WA2, IF_REAL, "Width dependence of a2"), +IOP( "wketa", BSIM3_MOD_WKETA, IF_REAL, "Width dependence of keta"), +IOP( "wnsub", BSIM3_MOD_WNSUB, IF_REAL, "Width dependence of nsub"), +IOP( "wnch", BSIM3_MOD_WNPEAK, IF_REAL, "Width dependence of nch"), +IOP( "wngate", BSIM3_MOD_WNGATE, IF_REAL, "Width dependence of ngate"), +IOP( "wgamma1", BSIM3_MOD_WGAMMA1, IF_REAL, "Width dependence of gamma1"), +IOP( "wgamma2", BSIM3_MOD_WGAMMA2, IF_REAL, "Width dependence of gamma2"), +IOP( "wvbx", BSIM3_MOD_WVBX, IF_REAL, "Width dependence of vbx"), +IOP( "wvbm", BSIM3_MOD_WVBM, IF_REAL, "Width dependence of vbm"), +IOP( "wxt", BSIM3_MOD_WXT, IF_REAL, "Width dependence of xt"), +IOP( "wk1", BSIM3_MOD_WK1, IF_REAL, "Width dependence of k1"), +IOP( "wkt1", BSIM3_MOD_WKT1, IF_REAL, "Width dependence of kt1"), +IOP( "wkt1l", BSIM3_MOD_WKT1L, IF_REAL, "Width dependence of kt1l"), +IOP( "wkt2", BSIM3_MOD_WKT2, IF_REAL, "Width dependence of kt2"), +IOP( "wk2", BSIM3_MOD_WK2, IF_REAL, "Width dependence of k2"), +IOP( "wk3", BSIM3_MOD_WK3, IF_REAL, "Width dependence of k3"), +IOP( "wk3b", BSIM3_MOD_WK3B, IF_REAL, "Width dependence of k3b"), +IOP( "ww0", BSIM3_MOD_WW0, IF_REAL, "Width dependence of w0"), +IOP( "wnlx", BSIM3_MOD_WNLX, IF_REAL, "Width dependence of nlx"), +IOP( "wdvt0", BSIM3_MOD_WDVT0, IF_REAL, "Width dependence of dvt0"), +IOP( "wdvt1", BSIM3_MOD_WDVT1, IF_REAL, "Width dependence of dvt1"), +IOP( "wdvt2", BSIM3_MOD_WDVT2, IF_REAL, "Width dependence of dvt2"), +IOP( "wdvt0w", BSIM3_MOD_WDVT0W, IF_REAL, "Width dependence of dvt0w"), +IOP( "wdvt1w", BSIM3_MOD_WDVT1W, IF_REAL, "Width dependence of dvt1w"), +IOP( "wdvt2w", BSIM3_MOD_WDVT2W, IF_REAL, "Width dependence of dvt2w"), +IOP( "wdrout", BSIM3_MOD_WDROUT, IF_REAL, "Width dependence of drout"), +IOP( "wdsub", BSIM3_MOD_WDSUB, IF_REAL, "Width dependence of dsub"), +IOP( "wvth0", BSIM3_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wvtho", BSIM3_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wua", BSIM3_MOD_WUA, IF_REAL, "Width dependence of ua"), +IOP( "wua1", BSIM3_MOD_WUA1, IF_REAL, "Width dependence of ua1"), +IOP( "wub", BSIM3_MOD_WUB, IF_REAL, "Width dependence of ub"), +IOP( "wub1", BSIM3_MOD_WUB1, IF_REAL, "Width dependence of ub1"), +IOP( "wuc", BSIM3_MOD_WUC, IF_REAL, "Width dependence of uc"), +IOP( "wuc1", BSIM3_MOD_WUC1, IF_REAL, "Width dependence of uc1"), +IOP( "wu0", BSIM3_MOD_WU0, IF_REAL, "Width dependence of u0"), +IOP( "wute", BSIM3_MOD_WUTE, IF_REAL, "Width dependence of ute"), +IOP( "wvoff", BSIM3_MOD_WVOFF, IF_REAL, "Width dependence of voff"), +IOP( "welm", BSIM3_MOD_WELM, IF_REAL, "Width dependence of elm"), +IOP( "wdelta", BSIM3_MOD_WDELTA, IF_REAL, "Width dependence of delta"), +IOP( "wrdsw", BSIM3_MOD_WRDSW, IF_REAL, "Width dependence of rdsw "), + +IOP( "wprwg", BSIM3_MOD_WPRWG, IF_REAL, "Width dependence of prwg "), +IOP( "wprwb", BSIM3_MOD_WPRWB, IF_REAL, "Width dependence of prwb "), + +IOP( "wprt", BSIM3_MOD_WPRT, IF_REAL, "Width dependence of prt"), +IOP( "weta0", BSIM3_MOD_WETA0, IF_REAL, "Width dependence of eta0"), +IOP( "wetab", BSIM3_MOD_WETAB, IF_REAL, "Width dependence of etab"), +IOP( "wpclm", BSIM3_MOD_WPCLM, IF_REAL, "Width dependence of pclm"), +IOP( "wpdiblc1", BSIM3_MOD_WPDIBL1, IF_REAL, "Width dependence of pdiblc1"), +IOP( "wpdiblc2", BSIM3_MOD_WPDIBL2, IF_REAL, "Width dependence of pdiblc2"), +IOP( "wpdiblcb", BSIM3_MOD_WPDIBLB, IF_REAL, "Width dependence of pdiblcb"), +IOP( "wpscbe1", BSIM3_MOD_WPSCBE1, IF_REAL, "Width dependence of pscbe1"), +IOP( "wpscbe2", BSIM3_MOD_WPSCBE2, IF_REAL, "Width dependence of pscbe2"), +IOP( "wpvag", BSIM3_MOD_WPVAG, IF_REAL, "Width dependence of pvag"), +IOP( "wwr", BSIM3_MOD_WWR, IF_REAL, "Width dependence of wr"), +IOP( "wdwg", BSIM3_MOD_WDWG, IF_REAL, "Width dependence of dwg"), +IOP( "wdwb", BSIM3_MOD_WDWB, IF_REAL, "Width dependence of dwb"), +IOP( "wb0", BSIM3_MOD_WB0, IF_REAL, "Width dependence of b0"), +IOP( "wb1", BSIM3_MOD_WB1, IF_REAL, "Width dependence of b1"), +IOP( "wcgsl", BSIM3_MOD_WCGSL, IF_REAL, "Width dependence of cgsl"), +IOP( "wcgdl", BSIM3_MOD_WCGDL, IF_REAL, "Width dependence of cgdl"), +IOP( "wckappa", BSIM3_MOD_WCKAPPA, IF_REAL, "Width dependence of ckappa"), +IOP( "wcf", BSIM3_MOD_WCF, IF_REAL, "Width dependence of cf"), +IOP( "wclc", BSIM3_MOD_WCLC, IF_REAL, "Width dependence of clc"), +IOP( "wcle", BSIM3_MOD_WCLE, IF_REAL, "Width dependence of cle"), +IOP( "walpha0", BSIM3_MOD_WALPHA0, IF_REAL, "Width dependence of alpha0"), +IOP( "walpha1", BSIM3_MOD_WALPHA1, IF_REAL, "Width dependence of alpha1"), +IOP( "wbeta0", BSIM3_MOD_WBETA0, IF_REAL, "Width dependence of beta0"), +IOP( "wvfbcv", BSIM3_MOD_WVFBCV, IF_REAL, "Width dependence of vfbcv"), +IOP( "wvfb", BSIM3_MOD_WVFB, IF_REAL, "Width dependence of vfb"), +IOP( "wacde", BSIM3_MOD_WACDE, IF_REAL, "Width dependence of acde"), +IOP( "wmoin", BSIM3_MOD_WMOIN, IF_REAL, "Width dependence of moin"), +IOP( "wnoff", BSIM3_MOD_WNOFF, IF_REAL, "Width dependence of noff"), +IOP( "wvoffcv", BSIM3_MOD_WVOFFCV, IF_REAL, "Width dependence of voffcv"), + +IOP( "pcdsc", BSIM3_MOD_PCDSC, IF_REAL, "Cross-term dependence of cdsc"), +IOP( "pcdscb", BSIM3_MOD_PCDSCB, IF_REAL, "Cross-term dependence of cdscb"), +IOP( "pcdscd", BSIM3_MOD_PCDSCD, IF_REAL, "Cross-term dependence of cdscd"), +IOP( "pcit", BSIM3_MOD_PCIT, IF_REAL, "Cross-term dependence of cit"), +IOP( "pnfactor", BSIM3_MOD_PNFACTOR, IF_REAL, "Cross-term dependence of nfactor"), +IOP( "pxj", BSIM3_MOD_PXJ, IF_REAL, "Cross-term dependence of xj"), +IOP( "pvsat", BSIM3_MOD_PVSAT, IF_REAL, "Cross-term dependence of vsat"), +IOP( "pat", BSIM3_MOD_PAT, IF_REAL, "Cross-term dependence of at"), +IOP( "pa0", BSIM3_MOD_PA0, IF_REAL, "Cross-term dependence of a0"), +IOP( "pags", BSIM3_MOD_PAGS, IF_REAL, "Cross-term dependence of ags"), +IOP( "pa1", BSIM3_MOD_PA1, IF_REAL, "Cross-term dependence of a1"), +IOP( "pa2", BSIM3_MOD_PA2, IF_REAL, "Cross-term dependence of a2"), +IOP( "pketa", BSIM3_MOD_PKETA, IF_REAL, "Cross-term dependence of keta"), +IOP( "pnsub", BSIM3_MOD_PNSUB, IF_REAL, "Cross-term dependence of nsub"), +IOP( "pnch", BSIM3_MOD_PNPEAK, IF_REAL, "Cross-term dependence of nch"), +IOP( "pngate", BSIM3_MOD_PNGATE, IF_REAL, "Cross-term dependence of ngate"), +IOP( "pgamma1", BSIM3_MOD_PGAMMA1, IF_REAL, "Cross-term dependence of gamma1"), +IOP( "pgamma2", BSIM3_MOD_PGAMMA2, IF_REAL, "Cross-term dependence of gamma2"), +IOP( "pvbx", BSIM3_MOD_PVBX, IF_REAL, "Cross-term dependence of vbx"), +IOP( "pvbm", BSIM3_MOD_PVBM, IF_REAL, "Cross-term dependence of vbm"), +IOP( "pxt", BSIM3_MOD_PXT, IF_REAL, "Cross-term dependence of xt"), +IOP( "pk1", BSIM3_MOD_PK1, IF_REAL, "Cross-term dependence of k1"), +IOP( "pkt1", BSIM3_MOD_PKT1, IF_REAL, "Cross-term dependence of kt1"), +IOP( "pkt1l", BSIM3_MOD_PKT1L, IF_REAL, "Cross-term dependence of kt1l"), +IOP( "pkt2", BSIM3_MOD_PKT2, IF_REAL, "Cross-term dependence of kt2"), +IOP( "pk2", BSIM3_MOD_PK2, IF_REAL, "Cross-term dependence of k2"), +IOP( "pk3", BSIM3_MOD_PK3, IF_REAL, "Cross-term dependence of k3"), +IOP( "pk3b", BSIM3_MOD_PK3B, IF_REAL, "Cross-term dependence of k3b"), +IOP( "pw0", BSIM3_MOD_PW0, IF_REAL, "Cross-term dependence of w0"), +IOP( "pnlx", BSIM3_MOD_PNLX, IF_REAL, "Cross-term dependence of nlx"), +IOP( "pdvt0", BSIM3_MOD_PDVT0, IF_REAL, "Cross-term dependence of dvt0"), +IOP( "pdvt1", BSIM3_MOD_PDVT1, IF_REAL, "Cross-term dependence of dvt1"), +IOP( "pdvt2", BSIM3_MOD_PDVT2, IF_REAL, "Cross-term dependence of dvt2"), +IOP( "pdvt0w", BSIM3_MOD_PDVT0W, IF_REAL, "Cross-term dependence of dvt0w"), +IOP( "pdvt1w", BSIM3_MOD_PDVT1W, IF_REAL, "Cross-term dependence of dvt1w"), +IOP( "pdvt2w", BSIM3_MOD_PDVT2W, IF_REAL, "Cross-term dependence of dvt2w"), +IOP( "pdrout", BSIM3_MOD_PDROUT, IF_REAL, "Cross-term dependence of drout"), +IOP( "pdsub", BSIM3_MOD_PDSUB, IF_REAL, "Cross-term dependence of dsub"), +IOP( "pvth0", BSIM3_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pvtho", BSIM3_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pua", BSIM3_MOD_PUA, IF_REAL, "Cross-term dependence of ua"), +IOP( "pua1", BSIM3_MOD_PUA1, IF_REAL, "Cross-term dependence of ua1"), +IOP( "pub", BSIM3_MOD_PUB, IF_REAL, "Cross-term dependence of ub"), +IOP( "pub1", BSIM3_MOD_PUB1, IF_REAL, "Cross-term dependence of ub1"), +IOP( "puc", BSIM3_MOD_PUC, IF_REAL, "Cross-term dependence of uc"), +IOP( "puc1", BSIM3_MOD_PUC1, IF_REAL, "Cross-term dependence of uc1"), +IOP( "pu0", BSIM3_MOD_PU0, IF_REAL, "Cross-term dependence of u0"), +IOP( "pute", BSIM3_MOD_PUTE, IF_REAL, "Cross-term dependence of ute"), +IOP( "pvoff", BSIM3_MOD_PVOFF, IF_REAL, "Cross-term dependence of voff"), +IOP( "pelm", BSIM3_MOD_PELM, IF_REAL, "Cross-term dependence of elm"), +IOP( "pdelta", BSIM3_MOD_PDELTA, IF_REAL, "Cross-term dependence of delta"), +IOP( "prdsw", BSIM3_MOD_PRDSW, IF_REAL, "Cross-term dependence of rdsw "), + +IOP( "pprwg", BSIM3_MOD_PPRWG, IF_REAL, "Cross-term dependence of prwg "), +IOP( "pprwb", BSIM3_MOD_PPRWB, IF_REAL, "Cross-term dependence of prwb "), + +IOP( "pprt", BSIM3_MOD_PPRT, IF_REAL, "Cross-term dependence of prt "), +IOP( "peta0", BSIM3_MOD_PETA0, IF_REAL, "Cross-term dependence of eta0"), +IOP( "petab", BSIM3_MOD_PETAB, IF_REAL, "Cross-term dependence of etab"), +IOP( "ppclm", BSIM3_MOD_PPCLM, IF_REAL, "Cross-term dependence of pclm"), +IOP( "ppdiblc1", BSIM3_MOD_PPDIBL1, IF_REAL, "Cross-term dependence of pdiblc1"), +IOP( "ppdiblc2", BSIM3_MOD_PPDIBL2, IF_REAL, "Cross-term dependence of pdiblc2"), +IOP( "ppdiblcb", BSIM3_MOD_PPDIBLB, IF_REAL, "Cross-term dependence of pdiblcb"), +IOP( "ppscbe1", BSIM3_MOD_PPSCBE1, IF_REAL, "Cross-term dependence of pscbe1"), +IOP( "ppscbe2", BSIM3_MOD_PPSCBE2, IF_REAL, "Cross-term dependence of pscbe2"), +IOP( "ppvag", BSIM3_MOD_PPVAG, IF_REAL, "Cross-term dependence of pvag"), +IOP( "pwr", BSIM3_MOD_PWR, IF_REAL, "Cross-term dependence of wr"), +IOP( "pdwg", BSIM3_MOD_PDWG, IF_REAL, "Cross-term dependence of dwg"), +IOP( "pdwb", BSIM3_MOD_PDWB, IF_REAL, "Cross-term dependence of dwb"), +IOP( "pb0", BSIM3_MOD_PB0, IF_REAL, "Cross-term dependence of b0"), +IOP( "pb1", BSIM3_MOD_PB1, IF_REAL, "Cross-term dependence of b1"), +IOP( "pcgsl", BSIM3_MOD_PCGSL, IF_REAL, "Cross-term dependence of cgsl"), +IOP( "pcgdl", BSIM3_MOD_PCGDL, IF_REAL, "Cross-term dependence of cgdl"), +IOP( "pckappa", BSIM3_MOD_PCKAPPA, IF_REAL, "Cross-term dependence of ckappa"), +IOP( "pcf", BSIM3_MOD_PCF, IF_REAL, "Cross-term dependence of cf"), +IOP( "pclc", BSIM3_MOD_PCLC, IF_REAL, "Cross-term dependence of clc"), +IOP( "pcle", BSIM3_MOD_PCLE, IF_REAL, "Cross-term dependence of cle"), +IOP( "palpha0", BSIM3_MOD_PALPHA0, IF_REAL, "Cross-term dependence of alpha0"), +IOP( "palpha1", BSIM3_MOD_PALPHA1, IF_REAL, "Cross-term dependence of alpha1"), +IOP( "pbeta0", BSIM3_MOD_PBETA0, IF_REAL, "Cross-term dependence of beta0"), +IOP( "pvfbcv", BSIM3_MOD_PVFBCV, IF_REAL, "Cross-term dependence of vfbcv"), +IOP( "pvfb", BSIM3_MOD_PVFB, IF_REAL, "Cross-term dependence of vfb"), +IOP( "pacde", BSIM3_MOD_PACDE, IF_REAL, "Cross-term dependence of acde"), +IOP( "pmoin", BSIM3_MOD_PMOIN, IF_REAL, "Cross-term dependence of moin"), +IOP( "pnoff", BSIM3_MOD_PNOFF, IF_REAL, "Cross-term dependence of noff"), +IOP( "pvoffcv", BSIM3_MOD_PVOFFCV, IF_REAL, "Cross-term dependence of voffcv"), + +IOP( "noia", BSIM3_MOD_NOIA, IF_REAL, "Flicker noise parameter"), +IOP( "noib", BSIM3_MOD_NOIB, IF_REAL, "Flicker noise parameter"), +IOP( "noic", BSIM3_MOD_NOIC, IF_REAL, "Flicker noise parameter"), +IOP( "em", BSIM3_MOD_EM, IF_REAL, "Flicker noise parameter"), +IOP( "ef", BSIM3_MOD_EF, IF_REAL, "Flicker noise frequency exponent"), +IOP( "af", BSIM3_MOD_AF, IF_REAL, "Flicker noise exponent"), +IOP( "kf", BSIM3_MOD_KF, IF_REAL, "Flicker noise coefficient"), + +IP( "nmos", BSIM3_MOD_NMOS, IF_FLAG, "Flag to indicate NMOS"), +IP( "pmos", BSIM3_MOD_PMOS, IF_FLAG, "Flag to indicate PMOS"), +}; + +char *BSIM3names[] = { + "Drain", + "Gate", + "Source", + "Bulk", + "Charge" +}; + +int BSIM3nSize = NUMELEMS(BSIM3names); +int BSIM3pTSize = NUMELEMS(BSIM3pTable); +int BSIM3mPTSize = NUMELEMS(BSIM3mPTable); +int BSIM3iSize = sizeof(BSIM3instance); +int BSIM3mSize = sizeof(BSIM3model); + + + diff --git a/src/spicelib/devices/bsim3/b3acld.c b/src/spicelib/devices/bsim3/b3acld.c new file mode 100644 index 000000000..8c999e456 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3acld.c @@ -0,0 +1,360 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/23 18:14:39 manu + Added cleanup patch by Arno Peters - also added 'make check' to configure + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3acld.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim3def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3acLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3model *model = (BSIM3model*)inModel; +register BSIM3instance *here; +double xcggb, xcgdb, xcgsb, xcbgb, xcbdb, xcbsb, xcddb, xcssb, xcdgb; +double gdpr, gspr, gds, gbd, gbs, capbd, capbs, xcsgb, xcdsb, xcsdb; +double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb, omega; +double GSoverlapCap, GDoverlapCap, GBoverlapCap, FwdSum, RevSum, Gm, Gmbs; +double dxpart, sxpart, xgtg, xgtd, xgts, xgtb, xcqgb, xcqdb, xcqsb, xcqbb; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb; +double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; +double T1, CoxWL, qcheq, Cdg, Cdd, Cds, Csg, Csd, Css; +double ScalingFactor = 1.0e-9; + + omega = ckt->CKTomega; + for (; model != NULL; model = model->BSIM3nextModel) + { for (here = model->BSIM3instances; here!= NULL; + here = here->BSIM3nextInstance) { + if (here->BSIM3owner != ARCHme) continue; + if (here->BSIM3mode >= 0) + { Gm = here->BSIM3gm; + Gmbs = here->BSIM3gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + + gbbdp = -here->BSIM3gbds; + gbbsp = here->BSIM3gbds + here->BSIM3gbgs + here->BSIM3gbbs; + + gbdpg = here->BSIM3gbgs; + gbdpb = here->BSIM3gbbs; + gbdpdp = here->BSIM3gbds; + gbdpsp = -(gbdpg + gbdpb + gbdpdp); + + gbspdp = 0.0; + gbspg = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + if (here->BSIM3nqsMod == 0) + { cggb = here->BSIM3cggb; + cgsb = here->BSIM3cgsb; + cgdb = here->BSIM3cgdb; + + cbgb = here->BSIM3cbgb; + cbsb = here->BSIM3cbsb; + cbdb = here->BSIM3cbdb; + + cdgb = here->BSIM3cdgb; + cdsb = here->BSIM3cdsb; + cddb = here->BSIM3cddb; + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3gtg; + xgtd = here->BSIM3gtd; + xgts = here->BSIM3gts; + xgtb = here->BSIM3gtb; + + xcqgb = here->BSIM3cqgb * omega; + xcqdb = here->BSIM3cqdb * omega; + xcqsb = here->BSIM3cqsb * omega; + xcqbb = here->BSIM3cqbb * omega; + + CoxWL = model->BSIM3cox * here->pParam->BSIM3weffCV + * here->pParam->BSIM3leffCV; + qcheq = -(here->BSIM3qgate + here->BSIM3qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM3xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = here->BSIM3qdrn / qcheq; + Cdd = here->BSIM3cddb; + Csd = -(here->BSIM3cgdb + here->BSIM3cddb + + here->BSIM3cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM3cdgb; + Csg = -(here->BSIM3cggb + here->BSIM3cdgb + + here->BSIM3cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM3cdsb; + Css = -(here->BSIM3cgsb + here->BSIM3cdsb + + here->BSIM3cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + } + else + { Gm = -here->BSIM3gm; + Gmbs = -here->BSIM3gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + + gbbsp = -here->BSIM3gbds; + gbbdp = here->BSIM3gbds + here->BSIM3gbgs + here->BSIM3gbbs; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM3gbgs; + gbspsp = here->BSIM3gbds; + gbspb = here->BSIM3gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + + if (here->BSIM3nqsMod == 0) + { cggb = here->BSIM3cggb; + cgsb = here->BSIM3cgdb; + cgdb = here->BSIM3cgsb; + + cbgb = here->BSIM3cbgb; + cbsb = here->BSIM3cbdb; + cbdb = here->BSIM3cbsb; + + cdgb = -(here->BSIM3cdgb + cggb + cbgb); + cdsb = -(here->BSIM3cddb + cgsb + cbsb); + cddb = -(here->BSIM3cdsb + cgdb + cbdb); + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3gtg; + xgtd = here->BSIM3gts; + xgts = here->BSIM3gtd; + xgtb = here->BSIM3gtb; + + xcqgb = here->BSIM3cqgb * omega; + xcqdb = here->BSIM3cqsb * omega; + xcqsb = here->BSIM3cqdb * omega; + xcqbb = here->BSIM3cqbb * omega; + + CoxWL = model->BSIM3cox * here->pParam->BSIM3weffCV + * here->pParam->BSIM3leffCV; + qcheq = -(here->BSIM3qgate + here->BSIM3qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM3xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = here->BSIM3qdrn / qcheq; + Css = here->BSIM3cddb; + Cds = -(here->BSIM3cgdb + here->BSIM3cddb + + here->BSIM3cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM3cdgb; + Cdg = -(here->BSIM3cggb + here->BSIM3cdgb + + here->BSIM3cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM3cdsb; + Cdd = -(here->BSIM3cgsb + here->BSIM3cdsb + + here->BSIM3cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + } + + T1 = *(ckt->CKTstate0 + here->BSIM3qdef) * here->BSIM3gtau; + gdpr = here->BSIM3drainConductance; + gspr = here->BSIM3sourceConductance; + gds = here->BSIM3gds; + gbd = here->BSIM3gbd; + gbs = here->BSIM3gbs; + capbd = here->BSIM3capbd; + capbs = here->BSIM3capbs; + + GSoverlapCap = here->BSIM3cgso; + GDoverlapCap = here->BSIM3cgdo; + GBoverlapCap = here->pParam->BSIM3cgbo; + + xcdgb = (cdgb - GDoverlapCap) * omega; + xcddb = (cddb + capbd + GDoverlapCap) * omega; + xcdsb = cdsb * omega; + xcsgb = -(cggb + cbgb + cdgb + GSoverlapCap) * omega; + xcsdb = -(cgdb + cbdb + cddb) * omega; + xcssb = (capbs + GSoverlapCap - (cgsb + cbsb + cdsb)) * omega; + xcggb = (cggb + GDoverlapCap + GSoverlapCap + GBoverlapCap) + * omega; + xcgdb = (cgdb - GDoverlapCap ) * omega; + xcgsb = (cgsb - GSoverlapCap) * omega; + xcbgb = (cbgb - GBoverlapCap) * omega; + xcbdb = (cbdb - capbd ) * omega; + xcbsb = (cbsb - capbs ) * omega; + + *(here->BSIM3GgPtr +1) += xcggb; + *(here->BSIM3BbPtr +1) -= xcbgb + xcbdb + xcbsb; + *(here->BSIM3DPdpPtr +1) += xcddb; + *(here->BSIM3SPspPtr +1) += xcssb; + *(here->BSIM3GbPtr +1) -= xcggb + xcgdb + xcgsb; + *(here->BSIM3GdpPtr +1) += xcgdb; + *(here->BSIM3GspPtr +1) += xcgsb; + *(here->BSIM3BgPtr +1) += xcbgb; + *(here->BSIM3BdpPtr +1) += xcbdb; + *(here->BSIM3BspPtr +1) += xcbsb; + *(here->BSIM3DPgPtr +1) += xcdgb; + *(here->BSIM3DPbPtr +1) -= xcdgb + xcddb + xcdsb; + *(here->BSIM3DPspPtr +1) += xcdsb; + *(here->BSIM3SPgPtr +1) += xcsgb; + *(here->BSIM3SPbPtr +1) -= xcsgb + xcsdb + xcssb; + *(here->BSIM3SPdpPtr +1) += xcsdb; + + *(here->BSIM3DdPtr) += gdpr; + *(here->BSIM3SsPtr) += gspr; + *(here->BSIM3BbPtr) += gbd + gbs - here->BSIM3gbbs; + *(here->BSIM3DPdpPtr) += gdpr + gds + gbd + RevSum + + dxpart * xgtd + T1 * ddxpart_dVd + gbdpdp; + *(here->BSIM3SPspPtr) += gspr + gds + gbs + FwdSum + + sxpart * xgts + T1 * dsxpart_dVs + gbspsp; + + *(here->BSIM3DdpPtr) -= gdpr; + *(here->BSIM3SspPtr) -= gspr; + + *(here->BSIM3BgPtr) -= here->BSIM3gbgs; + *(here->BSIM3BdpPtr) -= gbd - gbbdp; + *(here->BSIM3BspPtr) -= gbs - gbbsp; + + *(here->BSIM3DPdPtr) -= gdpr; + *(here->BSIM3DPgPtr) += Gm + dxpart * xgtg + T1 * ddxpart_dVg + + gbdpg; + *(here->BSIM3DPbPtr) -= gbd - Gmbs - dxpart * xgtb + - T1 * ddxpart_dVb - gbdpb; + *(here->BSIM3DPspPtr) -= gds + FwdSum - dxpart * xgts + - T1 * ddxpart_dVs - gbdpsp; + + *(here->BSIM3SPgPtr) -= Gm - sxpart * xgtg - T1 * dsxpart_dVg + - gbspg; + *(here->BSIM3SPsPtr) -= gspr; + *(here->BSIM3SPbPtr) -= gbs + Gmbs - sxpart * xgtb + - T1 * dsxpart_dVb - gbspb; + *(here->BSIM3SPdpPtr) -= gds + RevSum - sxpart * xgtd + - T1 * dsxpart_dVd - gbspdp; + + *(here->BSIM3GgPtr) -= xgtg; + *(here->BSIM3GbPtr) -= xgtb; + *(here->BSIM3GdpPtr) -= xgtd; + *(here->BSIM3GspPtr) -= xgts; + + if (here->BSIM3nqsMod) + { *(here->BSIM3QqPtr +1) += omega * ScalingFactor; + *(here->BSIM3QgPtr +1) -= xcqgb; + *(here->BSIM3QdpPtr +1) -= xcqdb; + *(here->BSIM3QspPtr +1) -= xcqsb; + *(here->BSIM3QbPtr +1) -= xcqbb; + + *(here->BSIM3QqPtr) += here->BSIM3gtau; + + *(here->BSIM3DPqPtr) += dxpart * here->BSIM3gtau; + *(here->BSIM3SPqPtr) += sxpart * here->BSIM3gtau; + *(here->BSIM3GqPtr) -= here->BSIM3gtau; + + *(here->BSIM3QgPtr) += xgtg; + *(here->BSIM3QdpPtr) += xgtd; + *(here->BSIM3QspPtr) += xgts; + *(here->BSIM3QbPtr) += xgtb; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3/b3ask.c b/src/spicelib/devices/bsim3/b3ask.c new file mode 100644 index 000000000..961ace403 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3ask.c @@ -0,0 +1,219 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3ask.c +**********/ + +#include "ngspice.h" +#include +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim3def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3ask(ckt,inst,which,value,select) +CKTcircuit *ckt; +GENinstance *inst; +int which; +IFvalue *value; +IFvalue *select; +{ +BSIM3instance *here = (BSIM3instance*)inst; + + switch(which) + { case BSIM3_L: + value->rValue = here->BSIM3l; + return(OK); + case BSIM3_W: + value->rValue = here->BSIM3w; + return(OK); + case BSIM3_AS: + value->rValue = here->BSIM3sourceArea; + return(OK); + case BSIM3_AD: + value->rValue = here->BSIM3drainArea; + return(OK); + case BSIM3_PS: + value->rValue = here->BSIM3sourcePerimeter; + return(OK); + case BSIM3_PD: + value->rValue = here->BSIM3drainPerimeter; + return(OK); + case BSIM3_NRS: + value->rValue = here->BSIM3sourceSquares; + return(OK); + case BSIM3_NRD: + value->rValue = here->BSIM3drainSquares; + return(OK); + case BSIM3_OFF: + value->rValue = here->BSIM3off; + return(OK); + case BSIM3_NQSMOD: + value->iValue = here->BSIM3nqsMod; + return(OK); + case BSIM3_IC_VBS: + value->rValue = here->BSIM3icVBS; + return(OK); + case BSIM3_IC_VDS: + value->rValue = here->BSIM3icVDS; + return(OK); + case BSIM3_IC_VGS: + value->rValue = here->BSIM3icVGS; + return(OK); + case BSIM3_DNODE: + value->iValue = here->BSIM3dNode; + return(OK); + case BSIM3_GNODE: + value->iValue = here->BSIM3gNode; + return(OK); + case BSIM3_SNODE: + value->iValue = here->BSIM3sNode; + return(OK); + case BSIM3_BNODE: + value->iValue = here->BSIM3bNode; + return(OK); + case BSIM3_DNODEPRIME: + value->iValue = here->BSIM3dNodePrime; + return(OK); + case BSIM3_SNODEPRIME: + value->iValue = here->BSIM3sNodePrime; + return(OK); + case BSIM3_SOURCECONDUCT: + value->rValue = here->BSIM3sourceConductance; + return(OK); + case BSIM3_DRAINCONDUCT: + value->rValue = here->BSIM3drainConductance; + return(OK); + case BSIM3_VBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3vbd); + return(OK); + case BSIM3_VBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3vbs); + return(OK); + case BSIM3_VGS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3vgs); + return(OK); + case BSIM3_VDS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3vds); + return(OK); + case BSIM3_CD: + value->rValue = here->BSIM3cd; + return(OK); + case BSIM3_CBS: + value->rValue = here->BSIM3cbs; + return(OK); + case BSIM3_CBD: + value->rValue = here->BSIM3cbd; + return(OK); + case BSIM3_GM: + value->rValue = here->BSIM3gm; + return(OK); + case BSIM3_GDS: + value->rValue = here->BSIM3gds; + return(OK); + case BSIM3_GMBS: + value->rValue = here->BSIM3gmbs; + return(OK); + case BSIM3_GBD: + value->rValue = here->BSIM3gbd; + return(OK); + case BSIM3_GBS: + value->rValue = here->BSIM3gbs; + return(OK); + case BSIM3_QB: + value->rValue = *(ckt->CKTstate0 + here->BSIM3qb); + return(OK); + case BSIM3_CQB: + value->rValue = *(ckt->CKTstate0 + here->BSIM3cqb); + return(OK); + case BSIM3_QG: + value->rValue = *(ckt->CKTstate0 + here->BSIM3qg); + return(OK); + case BSIM3_CQG: + value->rValue = *(ckt->CKTstate0 + here->BSIM3cqg); + return(OK); + case BSIM3_QD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3qd); + return(OK); + case BSIM3_CQD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3cqd); + return(OK); + case BSIM3_CGG: + value->rValue = here->BSIM3cggb; + return(OK); + case BSIM3_CGD: + value->rValue = here->BSIM3cgdb; + return(OK); + case BSIM3_CGS: + value->rValue = here->BSIM3cgsb; + return(OK); + case BSIM3_CDG: + value->rValue = here->BSIM3cdgb; + return(OK); + case BSIM3_CDD: + value->rValue = here->BSIM3cddb; + return(OK); + case BSIM3_CDS: + value->rValue = here->BSIM3cdsb; + return(OK); + case BSIM3_CBG: + value->rValue = here->BSIM3cbgb; + return(OK); + case BSIM3_CBDB: + value->rValue = here->BSIM3cbdb; + return(OK); + case BSIM3_CBSB: + value->rValue = here->BSIM3cbsb; + return(OK); + case BSIM3_CAPBD: + value->rValue = here->BSIM3capbd; + return(OK); + case BSIM3_CAPBS: + value->rValue = here->BSIM3capbs; + return(OK); + case BSIM3_VON: + value->rValue = here->BSIM3von; + return(OK); + case BSIM3_VDSAT: + value->rValue = here->BSIM3vdsat; + return(OK); + case BSIM3_QBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3qbs); + return(OK); + case BSIM3_QBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3qbd); + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bsim3/b3check.c b/src/spicelib/devices/bsim3/b3check.c new file mode 100644 index 000000000..51cb4118c --- /dev/null +++ b/src/spicelib/devices/bsim3/b3check.c @@ -0,0 +1,453 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: Min-Chie Jeng. +Author: 1997-1999 Weidong Liu. +File: b3check.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +BSIM3checkModel(model, here, ckt) +register BSIM3model *model; +register BSIM3instance *here; +CKTcircuit *ckt; +{ +struct bsim3SizeDependParam *pParam; +int Fatal_Flag = 0; +FILE *fplog; + + if ((fplog = fopen("b3v3check.log", "w")) != NULL) + { pParam = here->pParam; + fprintf(fplog, "BSIM3v3.2.2 Parameter Checking.\n"); + if (strcmp(model->BSIM3version, "3.2.2")) + { fprintf(fplog, "Warning: This model is BSIM3v3.2.2; you specified a wrong version number.\n"); + printf("Warning: This model is BSIM3v3.2.2; you specified a wrong version number.\n"); + } + fprintf(fplog, "Model = %s\n", model->BSIM3modName); + + if (pParam->BSIM3nlx < -pParam->BSIM3leff) + { fprintf(fplog, "Fatal: Nlx = %g is less than -Leff.\n", + pParam->BSIM3nlx); + printf("Fatal: Nlx = %g is less than -Leff.\n", + pParam->BSIM3nlx); + Fatal_Flag = 1; + } + + if (model->BSIM3tox <= 0.0) + { fprintf(fplog, "Fatal: Tox = %g is not positive.\n", + model->BSIM3tox); + printf("Fatal: Tox = %g is not positive.\n", model->BSIM3tox); + Fatal_Flag = 1; + } + + if (model->BSIM3toxm <= 0.0) + { fprintf(fplog, "Fatal: Toxm = %g is not positive.\n", + model->BSIM3toxm); + printf("Fatal: Toxm = %g is not positive.\n", model->BSIM3toxm); + Fatal_Flag = 1; + } + + if (pParam->BSIM3npeak <= 0.0) + { fprintf(fplog, "Fatal: Nch = %g is not positive.\n", + pParam->BSIM3npeak); + printf("Fatal: Nch = %g is not positive.\n", + pParam->BSIM3npeak); + Fatal_Flag = 1; + } + if (pParam->BSIM3nsub <= 0.0) + { fprintf(fplog, "Fatal: Nsub = %g is not positive.\n", + pParam->BSIM3nsub); + printf("Fatal: Nsub = %g is not positive.\n", + pParam->BSIM3nsub); + Fatal_Flag = 1; + } + if (pParam->BSIM3ngate < 0.0) + { fprintf(fplog, "Fatal: Ngate = %g is not positive.\n", + pParam->BSIM3ngate); + printf("Fatal: Ngate = %g Ngate is not positive.\n", + pParam->BSIM3ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM3ngate > 1.e25) + { fprintf(fplog, "Fatal: Ngate = %g is too high.\n", + pParam->BSIM3ngate); + printf("Fatal: Ngate = %g Ngate is too high\n", + pParam->BSIM3ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM3xj <= 0.0) + { fprintf(fplog, "Fatal: Xj = %g is not positive.\n", + pParam->BSIM3xj); + printf("Fatal: Xj = %g is not positive.\n", pParam->BSIM3xj); + Fatal_Flag = 1; + } + + if (pParam->BSIM3dvt1 < 0.0) + { fprintf(fplog, "Fatal: Dvt1 = %g is negative.\n", + pParam->BSIM3dvt1); + printf("Fatal: Dvt1 = %g is negative.\n", pParam->BSIM3dvt1); + Fatal_Flag = 1; + } + + if (pParam->BSIM3dvt1w < 0.0) + { fprintf(fplog, "Fatal: Dvt1w = %g is negative.\n", + pParam->BSIM3dvt1w); + printf("Fatal: Dvt1w = %g is negative.\n", pParam->BSIM3dvt1w); + Fatal_Flag = 1; + } + + if (pParam->BSIM3w0 == -pParam->BSIM3weff) + { fprintf(fplog, "Fatal: (W0 + Weff) = 0 causing divided-by-zero.\n"); + printf("Fatal: (W0 + Weff) = 0 causing divided-by-zero.\n"); + Fatal_Flag = 1; + } + + if (pParam->BSIM3dsub < 0.0) + { fprintf(fplog, "Fatal: Dsub = %g is negative.\n", pParam->BSIM3dsub); + printf("Fatal: Dsub = %g is negative.\n", pParam->BSIM3dsub); + Fatal_Flag = 1; + } + if (pParam->BSIM3b1 == -pParam->BSIM3weff) + { fprintf(fplog, "Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + printf("Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + Fatal_Flag = 1; + } + if (pParam->BSIM3u0temp <= 0.0) + { fprintf(fplog, "Fatal: u0 at current temperature = %g is not positive.\n", pParam->BSIM3u0temp); + printf("Fatal: u0 at current temperature = %g is not positive.\n", + pParam->BSIM3u0temp); + Fatal_Flag = 1; + } + +/* Check delta parameter */ + if (pParam->BSIM3delta < 0.0) + { fprintf(fplog, "Fatal: Delta = %g is less than zero.\n", + pParam->BSIM3delta); + printf("Fatal: Delta = %g is less than zero.\n", pParam->BSIM3delta); + Fatal_Flag = 1; + } + + if (pParam->BSIM3vsattemp <= 0.0) + { fprintf(fplog, "Fatal: Vsat at current temperature = %g is not positive.\n", pParam->BSIM3vsattemp); + printf("Fatal: Vsat at current temperature = %g is not positive.\n", + pParam->BSIM3vsattemp); + Fatal_Flag = 1; + } +/* Check Rout parameters */ + if (pParam->BSIM3pclm <= 0.0) + { fprintf(fplog, "Fatal: Pclm = %g is not positive.\n", pParam->BSIM3pclm); + printf("Fatal: Pclm = %g is not positive.\n", pParam->BSIM3pclm); + Fatal_Flag = 1; + } + + if (pParam->BSIM3drout < 0.0) + { fprintf(fplog, "Fatal: Drout = %g is negative.\n", pParam->BSIM3drout); + printf("Fatal: Drout = %g is negative.\n", pParam->BSIM3drout); + Fatal_Flag = 1; + } + + if (pParam->BSIM3pscbe2 <= 0.0) + { fprintf(fplog, "Warning: Pscbe2 = %g is not positive.\n", + pParam->BSIM3pscbe2); + printf("Warning: Pscbe2 = %g is not positive.\n", pParam->BSIM3pscbe2); + } + + if (model->BSIM3unitLengthSidewallJctCap > 0.0 || + model->BSIM3unitLengthGateSidewallJctCap > 0.0) + { + if (here->BSIM3drainPerimeter < pParam->BSIM3weff) + { fprintf(fplog, "Warning: Pd = %g is less than W.\n", + here->BSIM3drainPerimeter); + printf("Warning: Pd = %g is less than W.\n", + here->BSIM3drainPerimeter); + } + if (here->BSIM3sourcePerimeter < pParam->BSIM3weff) + { fprintf(fplog, "Warning: Ps = %g is less than W.\n", + here->BSIM3sourcePerimeter); + printf("Warning: Ps = %g is less than W.\n", + here->BSIM3sourcePerimeter); + } + } + + if (pParam->BSIM3noff < 0.1) + { fprintf(fplog, "Warning: Noff = %g is too small.\n", + pParam->BSIM3noff); + printf("Warning: Noff = %g is too small.\n", pParam->BSIM3noff); + } + if (pParam->BSIM3noff > 4.0) + { fprintf(fplog, "Warning: Noff = %g is too large.\n", + pParam->BSIM3noff); + printf("Warning: Noff = %g is too large.\n", pParam->BSIM3noff); + } + + if (pParam->BSIM3voffcv < -0.5) + { fprintf(fplog, "Warning: Voffcv = %g is too small.\n", + pParam->BSIM3voffcv); + printf("Warning: Voffcv = %g is too small.\n", pParam->BSIM3voffcv); + } + if (pParam->BSIM3voffcv > 0.5) + { fprintf(fplog, "Warning: Voffcv = %g is too large.\n", + pParam->BSIM3voffcv); + printf("Warning: Voffcv = %g is too large.\n", pParam->BSIM3voffcv); + } + + if (model->BSIM3ijth < 0.0) + { fprintf(fplog, "Fatal: Ijth = %g cannot be negative.\n", + model->BSIM3ijth); + printf("Fatal: Ijth = %g cannot be negative.\n", model->BSIM3ijth); + Fatal_Flag = 1; + } + +/* Check capacitance parameters */ + if (pParam->BSIM3clc < 0.0) + { fprintf(fplog, "Fatal: Clc = %g is negative.\n", pParam->BSIM3clc); + printf("Fatal: Clc = %g is negative.\n", pParam->BSIM3clc); + Fatal_Flag = 1; + } + + if (pParam->BSIM3moin < 5.0) + { fprintf(fplog, "Warning: Moin = %g is too small.\n", + pParam->BSIM3moin); + printf("Warning: Moin = %g is too small.\n", pParam->BSIM3moin); + } + if (pParam->BSIM3moin > 25.0) + { fprintf(fplog, "Warning: Moin = %g is too large.\n", + pParam->BSIM3moin); + printf("Warning: Moin = %g is too large.\n", pParam->BSIM3moin); + } + + if (pParam->BSIM3acde < 0.4) + { fprintf(fplog, "Warning: Acde = %g is too small.\n", + pParam->BSIM3acde); + printf("Warning: Acde = %g is too small.\n", pParam->BSIM3acde); + } + if (pParam->BSIM3acde > 1.6) + { fprintf(fplog, "Warning: Acde = %g is too large.\n", + pParam->BSIM3acde); + printf("Warning: Acde = %g is too large.\n", pParam->BSIM3acde); + } + + if (model->BSIM3paramChk ==1) + { +/* Check L and W parameters */ + if (pParam->BSIM3leff <= 5.0e-8) + { fprintf(fplog, "Warning: Leff = %g may be too small.\n", + pParam->BSIM3leff); + printf("Warning: Leff = %g may be too small.\n", + pParam->BSIM3leff); + } + + if (pParam->BSIM3leffCV <= 5.0e-8) + { fprintf(fplog, "Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM3leffCV); + printf("Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM3leffCV); + } + + if (pParam->BSIM3weff <= 1.0e-7) + { fprintf(fplog, "Warning: Weff = %g may be too small.\n", + pParam->BSIM3weff); + printf("Warning: Weff = %g may be too small.\n", + pParam->BSIM3weff); + } + + if (pParam->BSIM3weffCV <= 1.0e-7) + { fprintf(fplog, "Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM3weffCV); + printf("Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM3weffCV); + } + +/* Check threshold voltage parameters */ + if (pParam->BSIM3nlx < 0.0) + { fprintf(fplog, "Warning: Nlx = %g is negative.\n", pParam->BSIM3nlx); + printf("Warning: Nlx = %g is negative.\n", pParam->BSIM3nlx); + } + if (model->BSIM3tox < 1.0e-9) + { fprintf(fplog, "Warning: Tox = %g is less than 10A.\n", + model->BSIM3tox); + printf("Warning: Tox = %g is less than 10A.\n", model->BSIM3tox); + } + + if (pParam->BSIM3npeak <= 1.0e15) + { fprintf(fplog, "Warning: Nch = %g may be too small.\n", + pParam->BSIM3npeak); + printf("Warning: Nch = %g may be too small.\n", + pParam->BSIM3npeak); + } + else if (pParam->BSIM3npeak >= 1.0e21) + { fprintf(fplog, "Warning: Nch = %g may be too large.\n", + pParam->BSIM3npeak); + printf("Warning: Nch = %g may be too large.\n", + pParam->BSIM3npeak); + } + + if (pParam->BSIM3nsub <= 1.0e14) + { fprintf(fplog, "Warning: Nsub = %g may be too small.\n", + pParam->BSIM3nsub); + printf("Warning: Nsub = %g may be too small.\n", + pParam->BSIM3nsub); + } + else if (pParam->BSIM3nsub >= 1.0e21) + { fprintf(fplog, "Warning: Nsub = %g may be too large.\n", + pParam->BSIM3nsub); + printf("Warning: Nsub = %g may be too large.\n", + pParam->BSIM3nsub); + } + + if ((pParam->BSIM3ngate > 0.0) && + (pParam->BSIM3ngate <= 1.e18)) + { fprintf(fplog, "Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM3ngate); + printf("Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM3ngate); + } + + if (pParam->BSIM3dvt0 < 0.0) + { fprintf(fplog, "Warning: Dvt0 = %g is negative.\n", + pParam->BSIM3dvt0); + printf("Warning: Dvt0 = %g is negative.\n", pParam->BSIM3dvt0); + } + + if (fabs(1.0e-6 / (pParam->BSIM3w0 + pParam->BSIM3weff)) > 10.0) + { fprintf(fplog, "Warning: (W0 + Weff) may be too small.\n"); + printf("Warning: (W0 + Weff) may be too small.\n"); + } + +/* Check subthreshold parameters */ + if (pParam->BSIM3nfactor < 0.0) + { fprintf(fplog, "Warning: Nfactor = %g is negative.\n", + pParam->BSIM3nfactor); + printf("Warning: Nfactor = %g is negative.\n", pParam->BSIM3nfactor); + } + if (pParam->BSIM3cdsc < 0.0) + { fprintf(fplog, "Warning: Cdsc = %g is negative.\n", + pParam->BSIM3cdsc); + printf("Warning: Cdsc = %g is negative.\n", pParam->BSIM3cdsc); + } + if (pParam->BSIM3cdscd < 0.0) + { fprintf(fplog, "Warning: Cdscd = %g is negative.\n", + pParam->BSIM3cdscd); + printf("Warning: Cdscd = %g is negative.\n", pParam->BSIM3cdscd); + } +/* Check DIBL parameters */ + if (pParam->BSIM3eta0 < 0.0) + { fprintf(fplog, "Warning: Eta0 = %g is negative.\n", + pParam->BSIM3eta0); + printf("Warning: Eta0 = %g is negative.\n", pParam->BSIM3eta0); + } + +/* Check Abulk parameters */ + if (fabs(1.0e-6 / (pParam->BSIM3b1 + pParam->BSIM3weff)) > 10.0) + { fprintf(fplog, "Warning: (B1 + Weff) may be too small.\n"); + printf("Warning: (B1 + Weff) may be too small.\n"); + } + + +/* Check Saturation parameters */ + if (pParam->BSIM3a2 < 0.01) + { fprintf(fplog, "Warning: A2 = %g is too small. Set to 0.01.\n", pParam->BSIM3a2); + printf("Warning: A2 = %g is too small. Set to 0.01.\n", + pParam->BSIM3a2); + pParam->BSIM3a2 = 0.01; + } + else if (pParam->BSIM3a2 > 1.0) + { fprintf(fplog, "Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM3a2); + printf("Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM3a2); + pParam->BSIM3a2 = 1.0; + pParam->BSIM3a1 = 0.0; + + } + + if (pParam->BSIM3rdsw < 0.0) + { fprintf(fplog, "Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM3rdsw); + printf("Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM3rdsw); + pParam->BSIM3rdsw = 0.0; + pParam->BSIM3rds0 = 0.0; + } + else if ((pParam->BSIM3rds0 > 0.0) && (pParam->BSIM3rds0 < 0.001)) + { fprintf(fplog, "Warning: Rds at current temperature = %g is less than 0.001 ohm. Set to zero.\n", + pParam->BSIM3rds0); + printf("Warning: Rds at current temperature = %g is less than 0.001 ohm. Set to zero.\n", + pParam->BSIM3rds0); + pParam->BSIM3rds0 = 0.0; + } + if (pParam->BSIM3vsattemp < 1.0e3) + { fprintf(fplog, "Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM3vsattemp); + printf("Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM3vsattemp); + } + + if (pParam->BSIM3pdibl1 < 0.0) + { fprintf(fplog, "Warning: Pdibl1 = %g is negative.\n", + pParam->BSIM3pdibl1); + printf("Warning: Pdibl1 = %g is negative.\n", pParam->BSIM3pdibl1); + } + if (pParam->BSIM3pdibl2 < 0.0) + { fprintf(fplog, "Warning: Pdibl2 = %g is negative.\n", + pParam->BSIM3pdibl2); + printf("Warning: Pdibl2 = %g is negative.\n", pParam->BSIM3pdibl2); + } +/* Check overlap capacitance parameters */ + if (model->BSIM3cgdo < 0.0) + { fprintf(fplog, "Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM3cgdo); + printf("Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM3cgdo); + model->BSIM3cgdo = 0.0; + } + if (model->BSIM3cgso < 0.0) + { fprintf(fplog, "Warning: cgso = %g is negative. Set to zero.\n", model->BSIM3cgso); + printf("Warning: cgso = %g is negative. Set to zero.\n", model->BSIM3cgso); + model->BSIM3cgso = 0.0; + } + if (model->BSIM3cgbo < 0.0) + { fprintf(fplog, "Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM3cgbo); + printf("Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM3cgbo); + model->BSIM3cgbo = 0.0; + } + + }/* loop for the parameter check for warning messages */ + fclose(fplog); + } + else + { fprintf(stderr, "Warning: Can't open log file. Parameter checking skipped.\n"); + } + + return(Fatal_Flag); +} + diff --git a/src/spicelib/devices/bsim3/b3cvtest.c b/src/spicelib/devices/bsim3/b3cvtest.c new file mode 100644 index 000000000..b15609a8e --- /dev/null +++ b/src/spicelib/devices/bsim3/b3cvtest.c @@ -0,0 +1,130 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3cvtest.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3def.h" +#include "trandefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3convTest(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3model *model = (BSIM3model*)inModel; +register BSIM3instance *here; +double delvbd, delvbs, delvds, delvgd, delvgs, vbd, vbs, vds; +double cbd, cbhat, cbs, cd, cdhat, tol, vgd, vgdo, vgs; + + /* loop through all the BSIM3 device models */ + for (; model != NULL; model = model->BSIM3nextModel) + { /* loop through all the instances of the model */ + for (here = model->BSIM3instances; here != NULL ; + here=here->BSIM3nextInstance) + { + if (here->BSIM3owner != ARCHme) continue; + vbs = model->BSIM3type + * (*(ckt->CKTrhsOld+here->BSIM3bNode) + - *(ckt->CKTrhsOld+here->BSIM3sNodePrime)); + vgs = model->BSIM3type + * (*(ckt->CKTrhsOld+here->BSIM3gNode) + - *(ckt->CKTrhsOld+here->BSIM3sNodePrime)); + vds = model->BSIM3type + * (*(ckt->CKTrhsOld+here->BSIM3dNodePrime) + - *(ckt->CKTrhsOld+here->BSIM3sNodePrime)); + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->BSIM3vgs) + - *(ckt->CKTstate0 + here->BSIM3vds); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM3vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM3vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM3vgs); + delvds = vds - *(ckt->CKTstate0 + here->BSIM3vds); + delvgd = vgd-vgdo; + + cd = here->BSIM3cd - here->BSIM3cbd; + if (here->BSIM3mode >= 0) + { cd += here->BSIM3csub; + cdhat = cd - here->BSIM3gbd * delvbd + + (here->BSIM3gmbs + here->BSIM3gbbs) * delvbs + + (here->BSIM3gm + here->BSIM3gbgs) * delvgs + + (here->BSIM3gds + here->BSIM3gbds) * delvds; + } + else + { cdhat = cd + (here->BSIM3gmbs - here->BSIM3gbd) * delvbd + + here->BSIM3gm * delvgd - here->BSIM3gds * delvds; + } + + /* + * check convergence + */ + if ((here->BSIM3off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(cd)) + + ckt->CKTabstol; + if (fabs(cdhat - cd) >= tol) + { ckt->CKTnoncon++; + return(OK); + } + cbs = here->BSIM3cbs; + cbd = here->BSIM3cbd; + if (here->BSIM3mode >= 0) + { cbhat = cbs + cbd - here->BSIM3csub + + here->BSIM3gbd * delvbd + + (here->BSIM3gbs - here->BSIM3gbbs) * delvbs + - here->BSIM3gbgs * delvgs + - here->BSIM3gbds * delvds; + } + else + { cbhat = cbs + cbd - here->BSIM3csub + + here->BSIM3gbs * delvbs + + (here->BSIM3gbd - here->BSIM3gbbs) * delvbd + - here->BSIM3gbgs * delvgd + + here->BSIM3gbds * delvds; + } + tol = ckt->CKTreltol * MAX(fabs(cbhat), + fabs(cbs + cbd - here->BSIM3csub)) + ckt->CKTabstol; + if (fabs(cbhat - (cbs + cbd - here->BSIM3csub)) > tol) + { ckt->CKTnoncon++; + return(OK); + } + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3/b3del.c b/src/spicelib/devices/bsim3/b3del.c new file mode 100644 index 000000000..b2dea97a4 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3del.c @@ -0,0 +1,66 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3del.c +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim3def.h" +#include "sperror.h" +#include "gendefs.h" +#include "suffix.h" + + +int +BSIM3delete(inModel,name,inInst) +GENmodel *inModel; +IFuid name; +GENinstance **inInst; +{ +BSIM3instance **fast = (BSIM3instance**)inInst; +BSIM3model *model = (BSIM3model*)inModel; +BSIM3instance **prev = NULL; +BSIM3instance *here; + + for (; model ; model = model->BSIM3nextModel) + { prev = &(model->BSIM3instances); + for (here = *prev; here ; here = *prev) + { if (here->BSIM3name == name || (fast && here==*fast)) + { *prev= here->BSIM3nextInstance; + FREE(here); + return(OK); + } + prev = &(here->BSIM3nextInstance); + } + } + return(E_NODEV); +} + + diff --git a/src/spicelib/devices/bsim3/b3dest.c b/src/spicelib/devices/bsim3/b3dest.c new file mode 100644 index 000000000..68e26ada7 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3dest.c @@ -0,0 +1,62 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3dest.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3def.h" +#include "suffix.h" + +void +BSIM3destroy(inModel) +GENmodel **inModel; +{ +BSIM3model **model = (BSIM3model**)inModel; +BSIM3instance *here; +BSIM3instance *prev = NULL; +BSIM3model *mod = *model; +BSIM3model *oldmod = NULL; + + for (; mod ; mod = mod->BSIM3nextModel) + { if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (BSIM3instance *)NULL; + for (here = mod->BSIM3instances; here; here = here->BSIM3nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; + return; +} + + + diff --git a/src/spicelib/devices/bsim3/b3getic.c b/src/spicelib/devices/bsim3/b3getic.c new file mode 100644 index 000000000..4d568cf5b --- /dev/null +++ b/src/spicelib/devices/bsim3/b3getic.c @@ -0,0 +1,65 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3getic.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim3def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3getic(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +BSIM3model *model = (BSIM3model*)inModel; +BSIM3instance *here; + + for (; model ; model = model->BSIM3nextModel) + { for (here = model->BSIM3instances; here; here = here->BSIM3nextInstance) + { + if (here->BSIM3owner != ARCHme) continue; + if(!here->BSIM3icVBSGiven) + { here->BSIM3icVBS = *(ckt->CKTrhs + here->BSIM3bNode) + - *(ckt->CKTrhs + here->BSIM3sNode); + } + if (!here->BSIM3icVDSGiven) + { here->BSIM3icVDS = *(ckt->CKTrhs + here->BSIM3dNode) + - *(ckt->CKTrhs + here->BSIM3sNode); + } + if (!here->BSIM3icVGSGiven) + { here->BSIM3icVGS = *(ckt->CKTrhs + here->BSIM3gNode) + - *(ckt->CKTrhs + here->BSIM3sNode); + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3/b3ld.c b/src/spicelib/devices/bsim3/b3ld.c new file mode 100644 index 000000000..e446eeda3 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3ld.c @@ -0,0 +1,2962 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.4 1999/09/06 16:10:27 manu + Added patch by Arno Peters + + Revision 1.3 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.2 1999/08/23 18:14:39 manu + Added cleanup patch by Arno Peters - also added 'make check' to configure + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +Modified by Mansun Chan (1995). +Author: 1997-1999 Weidong Liu. +File: b3ld.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define Charge_q 1.60219e-19 +#define DELTA_1 0.02 +#define DELTA_2 0.02 +#define DELTA_3 0.02 +#define DELTA_4 0.02 + + +int +BSIM3load(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3model *model = (BSIM3model*)inModel; +register BSIM3instance *here; +double SourceSatCurrent, DrainSatCurrent; +double ag0, qgd, qgs, qgb, von, cbhat, VgstNVt, ExpVgst; +double cdrain, cdhat, cdreq, ceqbd, ceqbs, ceqqb, ceqqd, ceqqg, ceq, geq; +double czbd, czbdsw, czbdswg, czbs, czbssw, czbsswg, evbd, evbs, arg, sarg; +double delvbd, delvbs, delvds, delvgd, delvgs; +double Vfbeff, dVfbeff_dVg, dVfbeff_dVb, V3, V4; +double gcbdb, gcbgb, gcbsb, gcddb, gcdgb, gcdsb, gcgdb, gcggb, gcgsb, gcsdb; +double gcsgb, gcssb, MJ, MJSW, MJSWG; +double vbd, vbs, vds, vgb, vgd, vgs, vgdo, xfact; +double qgate, qbulk, qdrn, qsrc, qinoi, cqgate, cqbulk, cqdrn; +double Vds, Vgs, Vbs, Gmbs, FwdSum, RevSum; +double Vgs_eff, Vfb; +double Phis, dPhis_dVb, sqrtPhis, dsqrtPhis_dVb, Vth, dVth_dVb, dVth_dVd; +double Vgst, dVgst_dVg, dVgst_dVb, dVgs_eff_dVg, Nvtm; +double Vtm; +double n, dn_dVb, dn_dVd, voffcv, noff, dnoff_dVd, dnoff_dVb; +double ExpArg, V0, CoxWLcen, QovCox, LINK; +double DeltaPhi, dDeltaPhi_dVg, dDeltaPhi_dVd, dDeltaPhi_dVb; +double Cox, Tox, Tcen, dTcen_dVg, dTcen_dVd, dTcen_dVb; +double Ccen, Coxeff, dCoxeff_dVg, dCoxeff_dVd, dCoxeff_dVb; +double Denomi, dDenomi_dVg, dDenomi_dVd, dDenomi_dVb; +double ueff, dueff_dVg, dueff_dVd, dueff_dVb; +double Esat, Vdsat; +double EsatL, dEsatL_dVg, dEsatL_dVd, dEsatL_dVb; +double dVdsat_dVg, dVdsat_dVb, dVdsat_dVd, Vasat, dAlphaz_dVg, dAlphaz_dVb; +double dVasat_dVg, dVasat_dVb, dVasat_dVd, Va, dVa_dVd, dVa_dVg, dVa_dVb; +double Vbseff, dVbseff_dVb, VbseffCV, dVbseffCV_dVb; +double Arg1, One_Third_CoxWL, Two_Third_CoxWL, Alphaz, CoxWL; +double T0, dT0_dVg, dT0_dVd, dT0_dVb; +double T1, dT1_dVg, dT1_dVd, dT1_dVb; +double T2, dT2_dVg, dT2_dVd, dT2_dVb; +double T3, dT3_dVg, dT3_dVd, dT3_dVb; + double T4; + double T5; + double T6; + double T7; + double T8; + double T9; + double T10; +double T11, T12; +double tmp, Abulk, dAbulk_dVb, Abulk0, dAbulk0_dVb; +double VACLM, dVACLM_dVg, dVACLM_dVd, dVACLM_dVb; +double VADIBL, dVADIBL_dVg, dVADIBL_dVd, dVADIBL_dVb; +double Xdep, dXdep_dVb, lt1, dlt1_dVb, ltw, dltw_dVb, Delt_vth, dDelt_vth_dVb; +double Theta0, dTheta0_dVb; +double TempRatio, tmp1, tmp2, tmp3, tmp4; +double DIBL_Sft, dDIBL_Sft_dVd, Lambda, dLambda_dVg; +double Idtot, Ibtot; +double tempv, a1, ScalingFactor; + +double Vgsteff, dVgsteff_dVg, dVgsteff_dVd, dVgsteff_dVb; +double Vdseff, dVdseff_dVg, dVdseff_dVd, dVdseff_dVb; +double VdseffCV, dVdseffCV_dVg, dVdseffCV_dVd, dVdseffCV_dVb; +double diffVds, dAbulk_dVg; +double beta, dbeta_dVg, dbeta_dVd, dbeta_dVb; +double gche, dgche_dVg, dgche_dVd, dgche_dVb; +double fgche1, dfgche1_dVg, dfgche1_dVd, dfgche1_dVb; +double fgche2, dfgche2_dVg, dfgche2_dVd, dfgche2_dVb; +double Idl, dIdl_dVg, dIdl_dVd, dIdl_dVb; +double Idsa, dIdsa_dVg, dIdsa_dVd, dIdsa_dVb; +double Ids, Gm, Gds, Gmb; +double Isub, Gbd, Gbg, Gbb; +double VASCBE, dVASCBE_dVg, dVASCBE_dVd, dVASCBE_dVb; +double CoxWovL; +double Rds, dRds_dVg, dRds_dVb, WVCox, WVCoxRds; +double Vgst2Vtm, VdsatCV, dVdsatCV_dVg, dVdsatCV_dVb; +double Leff, Weff, dWeff_dVg, dWeff_dVb; +double AbulkCV, dAbulkCV_dVb; +double qgdo, qgso, cgdo, cgso; + +double qcheq, qdef, gqdef, cqdef, cqcheq, gtau_diff, gtau_drift; +double gcqdb, gcqsb, gcqgb, gcqbb; +double dxpart, sxpart, ggtg, ggtd, ggts, ggtb; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; + +double gbspsp, gbbdp, gbbsp, gbspg, gbspb, gbspdp; +double gbdpdp, gbdpg, gbdpb, gbdpsp; +double Cgg, Cgd, Cgb, Cdg, Cdd, Cds; +double Csg, Csd, Css, Csb, Cbg, Cbd, Cbb; +double Cgg1, Cgb1, Cgd1, Cbg1, Cbb1, Cbd1, Qac0, Qsub0; +double dQac0_dVg, dQac0_dVb, dQsub0_dVg, dQsub0_dVd, dQsub0_dVb; + +struct bsim3SizeDependParam *pParam; +int ByPass, Check, ChargeComputationNeeded, error; + +ScalingFactor = 1.0e-9; +ChargeComputationNeeded = + ((ckt->CKTmode & (MODEAC | MODETRAN | MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) + ? 1 : 0; +for (; model != NULL; model = model->BSIM3nextModel) +{ for (here = model->BSIM3instances; here != NULL; + here = here->BSIM3nextInstance) + { + if (here->BSIM3owner != ARCHme) continue; + Check = 1; + ByPass = 0; + pParam = here->pParam; + if ((ckt->CKTmode & MODEINITSMSIG)) + { vbs = *(ckt->CKTstate0 + here->BSIM3vbs); + vgs = *(ckt->CKTstate0 + here->BSIM3vgs); + vds = *(ckt->CKTstate0 + here->BSIM3vds); + qdef = *(ckt->CKTstate0 + here->BSIM3qdef); + } + else if ((ckt->CKTmode & MODEINITTRAN)) + { vbs = *(ckt->CKTstate1 + here->BSIM3vbs); + vgs = *(ckt->CKTstate1 + here->BSIM3vgs); + vds = *(ckt->CKTstate1 + here->BSIM3vds); + qdef = *(ckt->CKTstate1 + here->BSIM3qdef); + } + else if ((ckt->CKTmode & MODEINITJCT) && !here->BSIM3off) + { vds = model->BSIM3type * here->BSIM3icVDS; + vgs = model->BSIM3type * here->BSIM3icVGS; + vbs = model->BSIM3type * here->BSIM3icVBS; + qdef = 0.0; + + if ((vds == 0.0) && (vgs == 0.0) && (vbs == 0.0) && + ((ckt->CKTmode & (MODETRAN | MODEAC|MODEDCOP | + MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) + { vbs = 0.0; + vgs = model->BSIM3type * pParam->BSIM3vth0 + 0.1; + vds = 0.1; + } + } + else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && + (here->BSIM3off)) + { qdef = vbs = vgs = vds = 0.0; + } + else + { +#ifndef PREDICTOR + if ((ckt->CKTmode & MODEINITPRED)) + { xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->BSIM3vbs) = + *(ckt->CKTstate1 + here->BSIM3vbs); + vbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3vbs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3vbs))); + *(ckt->CKTstate0 + here->BSIM3vgs) = + *(ckt->CKTstate1 + here->BSIM3vgs); + vgs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3vgs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3vgs))); + *(ckt->CKTstate0 + here->BSIM3vds) = + *(ckt->CKTstate1 + here->BSIM3vds); + vds = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3vds)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3vds))); + *(ckt->CKTstate0 + here->BSIM3vbd) = + *(ckt->CKTstate0 + here->BSIM3vbs) + - *(ckt->CKTstate0 + here->BSIM3vds); + *(ckt->CKTstate0 + here->BSIM3qdef) = + *(ckt->CKTstate1 + here->BSIM3qdef); + qdef = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3qdef)) + -(xfact * (*(ckt->CKTstate2 + here->BSIM3qdef))); + } + else + { +#endif /* PREDICTOR */ + vbs = model->BSIM3type + * (*(ckt->CKTrhsOld + here->BSIM3bNode) + - *(ckt->CKTrhsOld + here->BSIM3sNodePrime)); + vgs = model->BSIM3type + * (*(ckt->CKTrhsOld + here->BSIM3gNode) + - *(ckt->CKTrhsOld + here->BSIM3sNodePrime)); + vds = model->BSIM3type + * (*(ckt->CKTrhsOld + here->BSIM3dNodePrime) + - *(ckt->CKTrhsOld + here->BSIM3sNodePrime)); + qdef = model->BSIM3type + * (*(ckt->CKTrhsOld + here->BSIM3qNode)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->BSIM3vgs) + - *(ckt->CKTstate0 + here->BSIM3vds); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM3vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM3vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM3vgs); + delvds = vds - *(ckt->CKTstate0 + here->BSIM3vds); + delvgd = vgd - vgdo; + + if (here->BSIM3mode >= 0) + { Idtot = here->BSIM3cd + here->BSIM3csub - here->BSIM3cbd; + cdhat = Idtot - here->BSIM3gbd * delvbd + + (here->BSIM3gmbs + here->BSIM3gbbs) * delvbs + + (here->BSIM3gm + here->BSIM3gbgs) * delvgs + + (here->BSIM3gds + here->BSIM3gbds) * delvds; + Ibtot = here->BSIM3cbs + here->BSIM3cbd - here->BSIM3csub; + cbhat = Ibtot + here->BSIM3gbd * delvbd + + (here->BSIM3gbs - here->BSIM3gbbs) * delvbs + - here->BSIM3gbgs * delvgs + - here->BSIM3gbds * delvds; + } + else + { Idtot = here->BSIM3cd - here->BSIM3cbd; + cdhat = Idtot - (here->BSIM3gbd - here->BSIM3gmbs) * delvbd + + here->BSIM3gm * delvgd + - here->BSIM3gds * delvds; + Ibtot = here->BSIM3cbs + here->BSIM3cbd - here->BSIM3csub; + cbhat = Ibtot + here->BSIM3gbs * delvbs + + (here->BSIM3gbd - here->BSIM3gbbs) * delvbd + - here->BSIM3gbgs * delvgd + + here->BSIM3gbds * delvds; + } + +#ifndef NOBYPASS + /* following should be one big if connected by && all over + * the place, but some C compilers can't handle that, so + * we split it up here to let them digest it in stages + */ + + if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) + if ((fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->BSIM3vbs))) + ckt->CKTvoltTol))) + if ((fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->BSIM3vbd))) + ckt->CKTvoltTol))) + if ((fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->BSIM3vgs))) + ckt->CKTvoltTol))) + if ((fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->BSIM3vds))) + ckt->CKTvoltTol))) + if ((fabs(cdhat - Idtot) < ckt->CKTreltol + * MAX(fabs(cdhat),fabs(Idtot)) + ckt->CKTabstol)) + { tempv = MAX(fabs(cbhat),fabs(Ibtot)) + ckt->CKTabstol; + if ((fabs(cbhat - Ibtot)) < ckt->CKTreltol * tempv) + { /* bypass code */ + vbs = *(ckt->CKTstate0 + here->BSIM3vbs); + vbd = *(ckt->CKTstate0 + here->BSIM3vbd); + vgs = *(ckt->CKTstate0 + here->BSIM3vgs); + vds = *(ckt->CKTstate0 + here->BSIM3vds); + qdef = *(ckt->CKTstate0 + here->BSIM3qdef); + + vgd = vgs - vds; + vgb = vgs - vbs; + + cdrain = here->BSIM3cd; + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC))) + { ByPass = 1; + qgate = here->BSIM3qgate; + qbulk = here->BSIM3qbulk; + qdrn = here->BSIM3qdrn; + goto line755; + } + else + { goto line850; + } + } + } + +#endif /*NOBYPASS*/ + von = here->BSIM3von; + if (*(ckt->CKTstate0 + here->BSIM3vds) >= 0.0) + { vgs = DEVfetlim(vgs, *(ckt->CKTstate0+here->BSIM3vgs), von); + vds = vgs - vgd; + vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->BSIM3vds)); + vgd = vgs - vds; + + } + else + { vgd = DEVfetlim(vgd, vgdo, von); + vds = vgs - vgd; + vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0+here->BSIM3vds))); + vgs = vgd + vds; + } + + if (vds >= 0.0) + { vbs = DEVpnjlim(vbs, *(ckt->CKTstate0 + here->BSIM3vbs), + CONSTvt0, model->BSIM3vcrit, &Check); + vbd = vbs - vds; + + } + else + { vbd = DEVpnjlim(vbd, *(ckt->CKTstate0 + here->BSIM3vbd), + CONSTvt0, model->BSIM3vcrit, &Check); + vbs = vbd + vds; + } + } + + /* determine DC current and derivatives */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + /* Source/drain junction diode DC model begins */ + Nvtm = model->BSIM3vtm * model->BSIM3jctEmissionCoeff; + if ((here->BSIM3sourceArea <= 0.0) && (here->BSIM3sourcePerimeter <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } + else + { SourceSatCurrent = here->BSIM3sourceArea + * model->BSIM3jctTempSatCurDensity + + here->BSIM3sourcePerimeter + * model->BSIM3jctSidewallTempSatCurDensity; + } + if (SourceSatCurrent <= 0.0) + { here->BSIM3gbs = ckt->CKTgmin; + here->BSIM3cbs = here->BSIM3gbs * vbs; + } + else + { if (model->BSIM3ijth == 0.0) + { evbs = exp(vbs / Nvtm); + here->BSIM3gbs = SourceSatCurrent * evbs / Nvtm + ckt->CKTgmin; + here->BSIM3cbs = SourceSatCurrent * (evbs - 1.0) + + ckt->CKTgmin * vbs; + } + else + { if (vbs < here->BSIM3vjsm) + { evbs = exp(vbs / Nvtm); + here->BSIM3gbs = SourceSatCurrent * evbs / Nvtm + ckt->CKTgmin; + here->BSIM3cbs = SourceSatCurrent * (evbs - 1.0) + + ckt->CKTgmin * vbs; + } + else + { T0 = here->BSIM3IsEvjsm / Nvtm; + here->BSIM3gbs = T0 + ckt->CKTgmin; + here->BSIM3cbs = here->BSIM3IsEvjsm - SourceSatCurrent + + T0 * (vbs - here->BSIM3vjsm) + + ckt->CKTgmin * vbs; + } + } + } + + if ((here->BSIM3drainArea <= 0.0) && (here->BSIM3drainPerimeter <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } + else + { DrainSatCurrent = here->BSIM3drainArea + * model->BSIM3jctTempSatCurDensity + + here->BSIM3drainPerimeter + * model->BSIM3jctSidewallTempSatCurDensity; + } + if (DrainSatCurrent <= 0.0) + { here->BSIM3gbd = ckt->CKTgmin; + here->BSIM3cbd = here->BSIM3gbd * vbd; + } + else + { if (model->BSIM3ijth == 0.0) + { evbd = exp(vbd / Nvtm); + here->BSIM3gbd = DrainSatCurrent * evbd / Nvtm + ckt->CKTgmin; + here->BSIM3cbd = DrainSatCurrent * (evbd - 1.0) + + ckt->CKTgmin * vbd; + } + else + { if (vbd < here->BSIM3vjdm) + { evbd = exp(vbd / Nvtm); + here->BSIM3gbd = DrainSatCurrent * evbd / Nvtm + ckt->CKTgmin; + here->BSIM3cbd = DrainSatCurrent * (evbd - 1.0) + + ckt->CKTgmin * vbd; + } + else + { T0 = here->BSIM3IsEvjdm / Nvtm; + here->BSIM3gbd = T0 + ckt->CKTgmin; + here->BSIM3cbd = here->BSIM3IsEvjdm - DrainSatCurrent + + T0 * (vbd - here->BSIM3vjdm) + + ckt->CKTgmin * vbd; + } + } + } + /* End of diode DC model */ + + if (vds >= 0.0) + { /* normal mode */ + here->BSIM3mode = 1; + Vds = vds; + Vgs = vgs; + Vbs = vbs; + } + else + { /* inverse mode */ + here->BSIM3mode = -1; + Vds = -vds; + Vgs = vgd; + Vbs = vbd; + } + + T0 = Vbs - pParam->BSIM3vbsc - 0.001; + T1 = sqrt(T0 * T0 - 0.004 * pParam->BSIM3vbsc); + Vbseff = pParam->BSIM3vbsc + 0.5 * (T0 + T1); + dVbseff_dVb = 0.5 * (1.0 + T0 / T1); + if (Vbseff < Vbs) + { Vbseff = Vbs; + } + + if (Vbseff > 0.0) + { T0 = pParam->BSIM3phi / (pParam->BSIM3phi + Vbseff); + Phis = pParam->BSIM3phi * T0; + dPhis_dVb = -T0 * T0; + sqrtPhis = pParam->BSIM3phis3 / (pParam->BSIM3phi + 0.5 * Vbseff); + dsqrtPhis_dVb = -0.5 * sqrtPhis * sqrtPhis / pParam->BSIM3phis3; + } + else + { Phis = pParam->BSIM3phi - Vbseff; + dPhis_dVb = -1.0; + sqrtPhis = sqrt(Phis); + dsqrtPhis_dVb = -0.5 / sqrtPhis; + } + Xdep = pParam->BSIM3Xdep0 * sqrtPhis / pParam->BSIM3sqrtPhi; + dXdep_dVb = (pParam->BSIM3Xdep0 / pParam->BSIM3sqrtPhi) + * dsqrtPhis_dVb; + + Leff = pParam->BSIM3leff; + Vtm = model->BSIM3vtm; +/* Vth Calculation */ + T3 = sqrt(Xdep); + V0 = pParam->BSIM3vbi - pParam->BSIM3phi; + + T0 = pParam->BSIM3dvt2 * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM3dvt2; + } + else /* Added to avoid any discontinuity problems caused by dvt2 */ + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM3dvt2 * T4 * T4; + } + lt1 = model->BSIM3factor1 * T3 * T1; + dlt1_dVb = model->BSIM3factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = pParam->BSIM3dvt2w * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM3dvt2w; + } + else /* Added to avoid any discontinuity problems caused by dvt2w */ + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM3dvt2w * T4 * T4; + } + ltw = model->BSIM3factor1 * T3 * T1; + dltw_dVb = model->BSIM3factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = -0.5 * pParam->BSIM3dvt1 * Leff / lt1; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + Theta0 = T1 * (1.0 + 2.0 * T1); + dT1_dVb = -T0 / lt1 * T1 * dlt1_dVb; + dTheta0_dVb = (1.0 + 4.0 * T1) * dT1_dVb; + } + else + { T1 = MIN_EXP; + Theta0 = T1 * (1.0 + 2.0 * T1); + dTheta0_dVb = 0.0; + } + + here->BSIM3thetavth = pParam->BSIM3dvt0 * Theta0; + Delt_vth = here->BSIM3thetavth * V0; + dDelt_vth_dVb = pParam->BSIM3dvt0 * dTheta0_dVb * V0; + + T0 = -0.5 * pParam->BSIM3dvt1w * pParam->BSIM3weff * Leff / ltw; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 * (1.0 + 2.0 * T1); + dT1_dVb = -T0 / ltw * T1 * dltw_dVb; + dT2_dVb = (1.0 + 4.0 * T1) * dT1_dVb; + } + else + { T1 = MIN_EXP; + T2 = T1 * (1.0 + 2.0 * T1); + dT2_dVb = 0.0; + } + + T0 = pParam->BSIM3dvt0w * T2; + T2 = T0 * V0; + dT2_dVb = pParam->BSIM3dvt0w * dT2_dVb * V0; + + TempRatio = ckt->CKTtemp / model->BSIM3tnom - 1.0; + T0 = sqrt(1.0 + pParam->BSIM3nlx / Leff); + T1 = pParam->BSIM3k1ox * (T0 - 1.0) * pParam->BSIM3sqrtPhi + + (pParam->BSIM3kt1 + pParam->BSIM3kt1l / Leff + + pParam->BSIM3kt2 * Vbseff) * TempRatio; + tmp2 = model->BSIM3tox * pParam->BSIM3phi + / (pParam->BSIM3weff + pParam->BSIM3w0); + + T3 = pParam->BSIM3eta0 + pParam->BSIM3etab * Vbseff; + if (T3 < 1.0e-4) /* avoid discontinuity problems caused by etab */ + { T9 = 1.0 / (3.0 - 2.0e4 * T3); + T3 = (2.0e-4 - T3) * T9; + T4 = T9 * T9; + } + else + { T4 = 1.0; + } + dDIBL_Sft_dVd = T3 * pParam->BSIM3theta0vb0; + DIBL_Sft = dDIBL_Sft_dVd * Vds; + + Vth = model->BSIM3type * pParam->BSIM3vth0 - pParam->BSIM3k1 + * pParam->BSIM3sqrtPhi + pParam->BSIM3k1ox * sqrtPhis + - pParam->BSIM3k2ox * Vbseff - Delt_vth - T2 + (pParam->BSIM3k3 + + pParam->BSIM3k3b * Vbseff) * tmp2 + T1 - DIBL_Sft; + + here->BSIM3von = Vth; + + dVth_dVb = pParam->BSIM3k1ox * dsqrtPhis_dVb - pParam->BSIM3k2ox + - dDelt_vth_dVb - dT2_dVb + pParam->BSIM3k3b * tmp2 + - pParam->BSIM3etab * Vds * pParam->BSIM3theta0vb0 * T4 + + pParam->BSIM3kt2 * TempRatio; + dVth_dVd = -dDIBL_Sft_dVd; + +/* Calculate n */ + tmp2 = pParam->BSIM3nfactor * EPSSI / Xdep; + tmp3 = pParam->BSIM3cdsc + pParam->BSIM3cdscb * Vbseff + + pParam->BSIM3cdscd * Vds; + tmp4 = (tmp2 + tmp3 * Theta0 + pParam->BSIM3cit) / model->BSIM3cox; + if (tmp4 >= -0.5) + { n = 1.0 + tmp4; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM3cdscb * Theta0) / model->BSIM3cox; + dn_dVd = pParam->BSIM3cdscd * Theta0 / model->BSIM3cox; + } + else + /* avoid discontinuity problems caused by tmp4 */ + { T0 = 1.0 / (3.0 + 8.0 * tmp4); + n = (1.0 + 3.0 * tmp4) * T0; + T0 *= T0; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM3cdscb * Theta0) / model->BSIM3cox * T0; + dn_dVd = pParam->BSIM3cdscd * Theta0 / model->BSIM3cox * T0; + } + +/* Poly Gate Si Depletion Effect */ + T0 = pParam->BSIM3vfb + pParam->BSIM3phi; + if ((pParam->BSIM3ngate > 1.e18) && (pParam->BSIM3ngate < 1.e25) + && (Vgs > T0)) + /* added to avoid the problem caused by ngate */ + { T1 = 1.0e6 * Charge_q * EPSSI * pParam->BSIM3ngate + / (model->BSIM3cox * model->BSIM3cox); + T4 = sqrt(1.0 + 2.0 * (Vgs - T0) / T1); + T2 = T1 * (T4 - 1.0); + T3 = 0.5 * T2 * T2 / T1; /* T3 = Vpoly */ + T7 = 1.12 - T3 - 0.05; + T6 = sqrt(T7 * T7 + 0.224); + T5 = 1.12 - 0.5 * (T7 + T6); + Vgs_eff = Vgs - T5; + dVgs_eff_dVg = 1.0 - (0.5 - 0.5 / T4) * (1.0 + T7 / T6); + } + else + { Vgs_eff = Vgs; + dVgs_eff_dVg = 1.0; + } + Vgst = Vgs_eff - Vth; + +/* Effective Vgst (Vgsteff) Calculation */ + + T10 = 2.0 * n * Vtm; + VgstNVt = Vgst / T10; + ExpArg = (2.0 * pParam->BSIM3voff - Vgst) / T10; + + /* MCJ: Very small Vgst */ + if (VgstNVt > EXP_THRESHOLD) + { Vgsteff = Vgst; + dVgsteff_dVg = dVgs_eff_dVg; + dVgsteff_dVd = -dVth_dVd; + dVgsteff_dVb = -dVth_dVb; + } + else if (ExpArg > EXP_THRESHOLD) + { T0 = (Vgst - pParam->BSIM3voff) / (n * Vtm); + ExpVgst = exp(T0); + Vgsteff = Vtm * pParam->BSIM3cdep0 / model->BSIM3cox * ExpVgst; + dVgsteff_dVg = Vgsteff / (n * Vtm); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + T0 * Vtm * dn_dVd); + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + T0 * Vtm * dn_dVb); + dVgsteff_dVg *= dVgs_eff_dVg; + } + else + { ExpVgst = exp(VgstNVt); + T1 = T10 * log(1.0 + ExpVgst); + dT1_dVg = ExpVgst / (1.0 + ExpVgst); + dT1_dVb = -dT1_dVg * (dVth_dVb + Vgst / n * dn_dVb) + + T1 / n * dn_dVb; + dT1_dVd = -dT1_dVg * (dVth_dVd + Vgst / n * dn_dVd) + + T1 / n * dn_dVd; + + dT2_dVg = -model->BSIM3cox / (Vtm * pParam->BSIM3cdep0) + * exp(ExpArg); + T2 = 1.0 - T10 * dT2_dVg; + dT2_dVd = -dT2_dVg * (dVth_dVd - 2.0 * Vtm * ExpArg * dn_dVd) + + (T2 - 1.0) / n * dn_dVd; + dT2_dVb = -dT2_dVg * (dVth_dVb - 2.0 * Vtm * ExpArg * dn_dVb) + + (T2 - 1.0) / n * dn_dVb; + + Vgsteff = T1 / T2; + T3 = T2 * T2; + dVgsteff_dVg = (T2 * dT1_dVg - T1 * dT2_dVg) / T3 * dVgs_eff_dVg; + dVgsteff_dVd = (T2 * dT1_dVd - T1 * dT2_dVd) / T3; + dVgsteff_dVb = (T2 * dT1_dVb - T1 * dT2_dVb) / T3; + } + +/* Calculate Effective Channel Geometry */ + T9 = sqrtPhis - pParam->BSIM3sqrtPhi; + Weff = pParam->BSIM3weff - 2.0 * (pParam->BSIM3dwg * Vgsteff + + pParam->BSIM3dwb * T9); + dWeff_dVg = -2.0 * pParam->BSIM3dwg; + dWeff_dVb = -2.0 * pParam->BSIM3dwb * dsqrtPhis_dVb; + + if (Weff < 2.0e-8) /* to avoid the discontinuity problem due to Weff*/ + { T0 = 1.0 / (6.0e-8 - 2.0 * Weff); + Weff = 2.0e-8 * (4.0e-8 - Weff) * T0; + T0 *= T0 * 4.0e-16; + dWeff_dVg *= T0; + dWeff_dVb *= T0; + } + + T0 = pParam->BSIM3prwg * Vgsteff + pParam->BSIM3prwb * T9; + if (T0 >= -0.9) + { Rds = pParam->BSIM3rds0 * (1.0 + T0); + dRds_dVg = pParam->BSIM3rds0 * pParam->BSIM3prwg; + dRds_dVb = pParam->BSIM3rds0 * pParam->BSIM3prwb * dsqrtPhis_dVb; + } + else + /* to avoid the discontinuity problem due to prwg and prwb*/ + { T1 = 1.0 / (17.0 + 20.0 * T0); + Rds = pParam->BSIM3rds0 * (0.8 + T0) * T1; + T1 *= T1; + dRds_dVg = pParam->BSIM3rds0 * pParam->BSIM3prwg * T1; + dRds_dVb = pParam->BSIM3rds0 * pParam->BSIM3prwb * dsqrtPhis_dVb + * T1; + } + +/* Calculate Abulk */ + T1 = 0.5 * pParam->BSIM3k1ox / sqrtPhis; + dT1_dVb = -T1 / sqrtPhis * dsqrtPhis_dVb; + + T9 = sqrt(pParam->BSIM3xj * Xdep); + tmp1 = Leff + 2.0 * T9; + T5 = Leff / tmp1; + tmp2 = pParam->BSIM3a0 * T5; + tmp3 = pParam->BSIM3weff + pParam->BSIM3b1; + tmp4 = pParam->BSIM3b0 / tmp3; + T2 = tmp2 + tmp4; + dT2_dVb = -T9 / tmp1 / Xdep * dXdep_dVb; + T6 = T5 * T5; + T7 = T5 * T6; + + Abulk0 = 1.0 + T1 * T2; + dAbulk0_dVb = T1 * tmp2 * dT2_dVb + T2 * dT1_dVb; + + T8 = pParam->BSIM3ags * pParam->BSIM3a0 * T7; + dAbulk_dVg = -T1 * T8; + Abulk = Abulk0 + dAbulk_dVg * Vgsteff; + dAbulk_dVb = dAbulk0_dVb - T8 * Vgsteff * (dT1_dVb + + 3.0 * T1 * dT2_dVb); + + if (Abulk0 < 0.1) /* added to avoid the problems caused by Abulk0 */ + { T9 = 1.0 / (3.0 - 20.0 * Abulk0); + Abulk0 = (0.2 - Abulk0) * T9; + dAbulk0_dVb *= T9 * T9; + } + + if (Abulk < 0.1) + /* added to avoid the problems caused by Abulk */ + { T9 = 1.0 / (3.0 - 20.0 * Abulk); + Abulk = (0.2 - Abulk) * T9; + T10 = T9 * T9; + dAbulk_dVb *= T10; + dAbulk_dVg *= T10; + } + + T2 = pParam->BSIM3keta * Vbseff; + if (T2 >= -0.9) + { T0 = 1.0 / (1.0 + T2); + dT0_dVb = -pParam->BSIM3keta * T0 * T0; + } + else + /* added to avoid the problems caused by Keta */ + { T1 = 1.0 / (0.8 + T2); + T0 = (17.0 + 20.0 * T2) * T1; + dT0_dVb = -pParam->BSIM3keta * T1 * T1; + } + dAbulk_dVg *= T0; + dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb; + dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb; + Abulk *= T0; + Abulk0 *= T0; + + +/* Mobility calculation */ + if (model->BSIM3mobMod == 1) + { T0 = Vgsteff + Vth + Vth; + T2 = pParam->BSIM3ua + pParam->BSIM3uc * Vbseff; + T3 = T0 / model->BSIM3tox; + T5 = T3 * (T2 + pParam->BSIM3ub * T3); + dDenomi_dVg = (T2 + 2.0 * pParam->BSIM3ub * T3) / model->BSIM3tox; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM3uc * T3; + } + else if (model->BSIM3mobMod == 2) + { T5 = Vgsteff / model->BSIM3tox * (pParam->BSIM3ua + + pParam->BSIM3uc * Vbseff + pParam->BSIM3ub * Vgsteff + / model->BSIM3tox); + dDenomi_dVg = (pParam->BSIM3ua + pParam->BSIM3uc * Vbseff + + 2.0 * pParam->BSIM3ub * Vgsteff / model->BSIM3tox) + / model->BSIM3tox; + dDenomi_dVd = 0.0; + dDenomi_dVb = Vgsteff * pParam->BSIM3uc / model->BSIM3tox; + } + else + { T0 = Vgsteff + Vth + Vth; + T2 = 1.0 + pParam->BSIM3uc * Vbseff; + T3 = T0 / model->BSIM3tox; + T4 = T3 * (pParam->BSIM3ua + pParam->BSIM3ub * T3); + T5 = T4 * T2; + dDenomi_dVg = (pParam->BSIM3ua + 2.0 * pParam->BSIM3ub * T3) * T2 + / model->BSIM3tox; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM3uc * T4; + } + + if (T5 >= -0.8) + { Denomi = 1.0 + T5; + } + else /* Added to avoid the discontinuity problem caused by ua and ub*/ + { T9 = 1.0 / (7.0 + 10.0 * T5); + Denomi = (0.6 + T5) * T9; + T9 *= T9; + dDenomi_dVg *= T9; + dDenomi_dVd *= T9; + dDenomi_dVb *= T9; + } + + here->BSIM3ueff = ueff = pParam->BSIM3u0temp / Denomi; + T9 = -ueff / Denomi; + dueff_dVg = T9 * dDenomi_dVg; + dueff_dVd = T9 * dDenomi_dVd; + dueff_dVb = T9 * dDenomi_dVb; + +/* Saturation Drain Voltage Vdsat */ + WVCox = Weff * pParam->BSIM3vsattemp * model->BSIM3cox; + WVCoxRds = WVCox * Rds; + + Esat = 2.0 * pParam->BSIM3vsattemp / ueff; + EsatL = Esat * Leff; + T0 = -EsatL /ueff; + dEsatL_dVg = T0 * dueff_dVg; + dEsatL_dVd = T0 * dueff_dVd; + dEsatL_dVb = T0 * dueff_dVb; + + /* Sqrt() */ + a1 = pParam->BSIM3a1; + if (a1 == 0.0) + { Lambda = pParam->BSIM3a2; + dLambda_dVg = 0.0; + } + else if (a1 > 0.0) +/* Added to avoid the discontinuity problem + caused by a1 and a2 (Lambda) */ + { T0 = 1.0 - pParam->BSIM3a2; + T1 = T0 - pParam->BSIM3a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * T0); + Lambda = pParam->BSIM3a2 + T0 - 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM3a1 * (1.0 + T1 / T2); + } + else + { T1 = pParam->BSIM3a2 + pParam->BSIM3a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * pParam->BSIM3a2); + Lambda = 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM3a1 * (1.0 + T1 / T2); + } + + Vgst2Vtm = Vgsteff + 2.0 * Vtm; + if (Rds > 0) + { tmp2 = dRds_dVg / Rds + dWeff_dVg / Weff; + tmp3 = dRds_dVb / Rds + dWeff_dVb / Weff; + } + else + { tmp2 = dWeff_dVg / Weff; + tmp3 = dWeff_dVb / Weff; + } + if ((Rds == 0.0) && (Lambda == 1.0)) + { T0 = 1.0 / (Abulk * EsatL + Vgst2Vtm); + tmp1 = 0.0; + T1 = T0 * T0; + T2 = Vgst2Vtm * T0; + T3 = EsatL * Vgst2Vtm; + Vdsat = T3 * T0; + + dT0_dVg = -(Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 1.0) * T1; + dT0_dVd = -(Abulk * dEsatL_dVd) * T1; + dT0_dVb = -(Abulk * dEsatL_dVb + dAbulk_dVb * EsatL) * T1; + + dVdsat_dVg = T3 * dT0_dVg + T2 * dEsatL_dVg + EsatL * T0; + dVdsat_dVd = T3 * dT0_dVd + T2 * dEsatL_dVd; + dVdsat_dVb = T3 * dT0_dVb + T2 * dEsatL_dVb; + } + else + { tmp1 = dLambda_dVg / (Lambda * Lambda); + T9 = Abulk * WVCoxRds; + T8 = Abulk * T9; + T7 = Vgst2Vtm * T9; + T6 = Vgst2Vtm * WVCoxRds; + T0 = 2.0 * Abulk * (T9 - 1.0 + 1.0 / Lambda); + dT0_dVg = 2.0 * (T8 * tmp2 - Abulk * tmp1 + + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbulk_dVg); + + dT0_dVb = 2.0 * (T8 * (2.0 / Abulk * dAbulk_dVb + tmp3) + + (1.0 / Lambda - 1.0) * dAbulk_dVb); + dT0_dVd = 0.0; + T1 = Vgst2Vtm * (2.0 / Lambda - 1.0) + Abulk * EsatL + 3.0 * T7; + + dT1_dVg = (2.0 / Lambda - 1.0) - 2.0 * Vgst2Vtm * tmp1 + + Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 3.0 * (T9 + + T7 * tmp2 + T6 * dAbulk_dVg); + dT1_dVb = Abulk * dEsatL_dVb + EsatL * dAbulk_dVb + + 3.0 * (T6 * dAbulk_dVb + T7 * tmp3); + dT1_dVd = Abulk * dEsatL_dVd; + + T2 = Vgst2Vtm * (EsatL + 2.0 * T6); + dT2_dVg = EsatL + Vgst2Vtm * dEsatL_dVg + + T6 * (4.0 + 2.0 * Vgst2Vtm * tmp2); + dT2_dVb = Vgst2Vtm * (dEsatL_dVb + 2.0 * T6 * tmp3); + dT2_dVd = Vgst2Vtm * dEsatL_dVd; + + T3 = sqrt(T1 * T1 - 2.0 * T0 * T2); + Vdsat = (T1 - T3) / T0; + + dT3_dVg = (T1 * dT1_dVg - 2.0 * (T0 * dT2_dVg + T2 * dT0_dVg)) + / T3; + dT3_dVd = (T1 * dT1_dVd - 2.0 * (T0 * dT2_dVd + T2 * dT0_dVd)) + / T3; + dT3_dVb = (T1 * dT1_dVb - 2.0 * (T0 * dT2_dVb + T2 * dT0_dVb)) + / T3; + + dVdsat_dVg = (dT1_dVg - (T1 * dT1_dVg - dT0_dVg * T2 + - T0 * dT2_dVg) / T3 - Vdsat * dT0_dVg) / T0; + dVdsat_dVb = (dT1_dVb - (T1 * dT1_dVb - dT0_dVb * T2 + - T0 * dT2_dVb) / T3 - Vdsat * dT0_dVb) / T0; + dVdsat_dVd = (dT1_dVd - (T1 * dT1_dVd - T0 * dT2_dVd) / T3) / T0; + } + here->BSIM3vdsat = Vdsat; + +/* Effective Vds (Vdseff) Calculation */ + T1 = Vdsat - Vds - pParam->BSIM3delta; + dT1_dVg = dVdsat_dVg; + dT1_dVd = dVdsat_dVd - 1.0; + dT1_dVb = dVdsat_dVb; + + T2 = sqrt(T1 * T1 + 4.0 * pParam->BSIM3delta * Vdsat); + T0 = T1 / T2; + T3 = 2.0 * pParam->BSIM3delta / T2; + dT2_dVg = T0 * dT1_dVg + T3 * dVdsat_dVg; + dT2_dVd = T0 * dT1_dVd + T3 * dVdsat_dVd; + dT2_dVb = T0 * dT1_dVb + T3 * dVdsat_dVb; + + Vdseff = Vdsat - 0.5 * (T1 + T2); + dVdseff_dVg = dVdsat_dVg - 0.5 * (dT1_dVg + dT2_dVg); + dVdseff_dVd = dVdsat_dVd - 0.5 * (dT1_dVd + dT2_dVd); + dVdseff_dVb = dVdsat_dVb - 0.5 * (dT1_dVb + dT2_dVb); + /* Added to eliminate non-zero Vdseff at Vds=0.0 */ + if (Vds == 0.0) + { Vdseff = 0.0; + dVdseff_dVg = 0.0; + dVdseff_dVb = 0.0; + } + +/* Calculate VAsat */ + tmp4 = 1.0 - 0.5 * Abulk * Vdsat / Vgst2Vtm; + T9 = WVCoxRds * Vgsteff; + T8 = T9 / Vgst2Vtm; + T0 = EsatL + Vdsat + 2.0 * T9 * tmp4; + + T7 = 2.0 * WVCoxRds * tmp4; + dT0_dVg = dEsatL_dVg + dVdsat_dVg + T7 * (1.0 + tmp2 * Vgsteff) + - T8 * (Abulk * dVdsat_dVg - Abulk * Vdsat / Vgst2Vtm + + Vdsat * dAbulk_dVg); + + dT0_dVb = dEsatL_dVb + dVdsat_dVb + T7 * tmp3 * Vgsteff + - T8 * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = dEsatL_dVd + dVdsat_dVd - T8 * Abulk * dVdsat_dVd; + + T9 = WVCoxRds * Abulk; + T1 = 2.0 / Lambda - 1.0 + T9; + dT1_dVg = -2.0 * tmp1 + WVCoxRds * (Abulk * tmp2 + dAbulk_dVg); + dT1_dVb = dAbulk_dVb * WVCoxRds + T9 * tmp3; + + Vasat = T0 / T1; + dVasat_dVg = (dT0_dVg - Vasat * dT1_dVg) / T1; + dVasat_dVb = (dT0_dVb - Vasat * dT1_dVb) / T1; + dVasat_dVd = dT0_dVd / T1; + + if (Vdseff > Vds) + Vdseff = Vds; + diffVds = Vds - Vdseff; + +/* Calculate VACLM */ + if ((pParam->BSIM3pclm > 0.0) && (diffVds > 1.0e-10)) + { T0 = 1.0 / (pParam->BSIM3pclm * Abulk * pParam->BSIM3litl); + dT0_dVb = -T0 / Abulk * dAbulk_dVb; + dT0_dVg = -T0 / Abulk * dAbulk_dVg; + + T2 = Vgsteff / EsatL; + T1 = Leff * (Abulk + T2); + dT1_dVg = Leff * ((1.0 - T2 * dEsatL_dVg) / EsatL + dAbulk_dVg); + dT1_dVb = Leff * (dAbulk_dVb - T2 * dEsatL_dVb / EsatL); + dT1_dVd = -T2 * dEsatL_dVd / Esat; + + T9 = T0 * T1; + VACLM = T9 * diffVds; + dVACLM_dVg = T0 * dT1_dVg * diffVds - T9 * dVdseff_dVg + + T1 * diffVds * dT0_dVg; + dVACLM_dVb = (dT0_dVb * T1 + T0 * dT1_dVb) * diffVds + - T9 * dVdseff_dVb; + dVACLM_dVd = T0 * dT1_dVd * diffVds + T9 * (1.0 - dVdseff_dVd); + } + else + { VACLM = MAX_EXP; + dVACLM_dVd = dVACLM_dVg = dVACLM_dVb = 0.0; + } + +/* Calculate VADIBL */ + if (pParam->BSIM3thetaRout > 0.0) + { T8 = Abulk * Vdsat; + T0 = Vgst2Vtm * T8; + dT0_dVg = Vgst2Vtm * Abulk * dVdsat_dVg + T8 + + Vgst2Vtm * Vdsat * dAbulk_dVg; + dT0_dVb = Vgst2Vtm * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = Vgst2Vtm * Abulk * dVdsat_dVd; + + T1 = Vgst2Vtm + T8; + dT1_dVg = 1.0 + Abulk * dVdsat_dVg + Vdsat * dAbulk_dVg; + dT1_dVb = Abulk * dVdsat_dVb + dAbulk_dVb * Vdsat; + dT1_dVd = Abulk * dVdsat_dVd; + + T9 = T1 * T1; + T2 = pParam->BSIM3thetaRout; + VADIBL = (Vgst2Vtm - T0 / T1) / T2; + dVADIBL_dVg = (1.0 - dT0_dVg / T1 + T0 * dT1_dVg / T9) / T2; + dVADIBL_dVb = (-dT0_dVb / T1 + T0 * dT1_dVb / T9) / T2; + dVADIBL_dVd = (-dT0_dVd / T1 + T0 * dT1_dVd / T9) / T2; + + T7 = pParam->BSIM3pdiblb * Vbseff; + if (T7 >= -0.9) + { T3 = 1.0 / (1.0 + T7); + VADIBL *= T3; + dVADIBL_dVg *= T3; + dVADIBL_dVb = (dVADIBL_dVb - VADIBL * pParam->BSIM3pdiblb) + * T3; + dVADIBL_dVd *= T3; + } + else +/* Added to avoid the discontinuity problem caused by pdiblcb */ + { T4 = 1.0 / (0.8 + T7); + T3 = (17.0 + 20.0 * T7) * T4; + dVADIBL_dVg *= T3; + dVADIBL_dVb = dVADIBL_dVb * T3 + - VADIBL * pParam->BSIM3pdiblb * T4 * T4; + dVADIBL_dVd *= T3; + VADIBL *= T3; + } + } + else + { VADIBL = MAX_EXP; + dVADIBL_dVd = dVADIBL_dVg = dVADIBL_dVb = 0.0; + } + +/* Calculate VA */ + + T8 = pParam->BSIM3pvag / EsatL; + T9 = T8 * Vgsteff; + if (T9 > -0.9) + { T0 = 1.0 + T9; + dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL); + dT0_dVb = -T9 * dEsatL_dVb / EsatL; + dT0_dVd = -T9 * dEsatL_dVd / EsatL; + } + else /* Added to avoid the discontinuity problems caused by pvag */ + { T1 = 1.0 / (17.0 + 20.0 * T9); + T0 = (0.8 + T9) * T1; + T1 *= T1; + dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL) * T1; + + T9 *= T1 / EsatL; + dT0_dVb = -T9 * dEsatL_dVb; + dT0_dVd = -T9 * dEsatL_dVd; + } + + tmp1 = VACLM * VACLM; + tmp2 = VADIBL * VADIBL; + tmp3 = VACLM + VADIBL; + + T1 = VACLM * VADIBL / tmp3; + tmp3 *= tmp3; + dT1_dVg = (tmp1 * dVADIBL_dVg + tmp2 * dVACLM_dVg) / tmp3; + dT1_dVd = (tmp1 * dVADIBL_dVd + tmp2 * dVACLM_dVd) / tmp3; + dT1_dVb = (tmp1 * dVADIBL_dVb + tmp2 * dVACLM_dVb) / tmp3; + + Va = Vasat + T0 * T1; + dVa_dVg = dVasat_dVg + T1 * dT0_dVg + T0 * dT1_dVg; + dVa_dVd = dVasat_dVd + T1 * dT0_dVd + T0 * dT1_dVd; + dVa_dVb = dVasat_dVb + T1 * dT0_dVb + T0 * dT1_dVb; + +/* Calculate VASCBE */ + if (pParam->BSIM3pscbe2 > 0.0) + { if (diffVds > pParam->BSIM3pscbe1 * pParam->BSIM3litl + / EXP_THRESHOLD) + { T0 = pParam->BSIM3pscbe1 * pParam->BSIM3litl / diffVds; + VASCBE = Leff * exp(T0) / pParam->BSIM3pscbe2; + T1 = T0 * VASCBE / diffVds; + dVASCBE_dVg = T1 * dVdseff_dVg; + dVASCBE_dVd = -T1 * (1.0 - dVdseff_dVd); + dVASCBE_dVb = T1 * dVdseff_dVb; + } + else + { VASCBE = MAX_EXP * Leff/pParam->BSIM3pscbe2; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + } + else + { VASCBE = MAX_EXP; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + +/* Calculate Ids */ + CoxWovL = model->BSIM3cox * Weff / Leff; + beta = ueff * CoxWovL; + dbeta_dVg = CoxWovL * dueff_dVg + beta * dWeff_dVg / Weff; + dbeta_dVd = CoxWovL * dueff_dVd; + dbeta_dVb = CoxWovL * dueff_dVb + beta * dWeff_dVb / Weff; + + T0 = 1.0 - 0.5 * Abulk * Vdseff / Vgst2Vtm; + dT0_dVg = -0.5 * (Abulk * dVdseff_dVg + - Abulk * Vdseff / Vgst2Vtm + Vdseff * dAbulk_dVg) / Vgst2Vtm; + dT0_dVd = -0.5 * Abulk * dVdseff_dVd / Vgst2Vtm; + dT0_dVb = -0.5 * (Abulk * dVdseff_dVb + dAbulk_dVb * Vdseff) + / Vgst2Vtm; + + fgche1 = Vgsteff * T0; + dfgche1_dVg = Vgsteff * dT0_dVg + T0; + dfgche1_dVd = Vgsteff * dT0_dVd; + dfgche1_dVb = Vgsteff * dT0_dVb; + + T9 = Vdseff / EsatL; + fgche2 = 1.0 + T9; + dfgche2_dVg = (dVdseff_dVg - T9 * dEsatL_dVg) / EsatL; + dfgche2_dVd = (dVdseff_dVd - T9 * dEsatL_dVd) / EsatL; + dfgche2_dVb = (dVdseff_dVb - T9 * dEsatL_dVb) / EsatL; + + gche = beta * fgche1 / fgche2; + dgche_dVg = (beta * dfgche1_dVg + fgche1 * dbeta_dVg + - gche * dfgche2_dVg) / fgche2; + dgche_dVd = (beta * dfgche1_dVd + fgche1 * dbeta_dVd + - gche * dfgche2_dVd) / fgche2; + dgche_dVb = (beta * dfgche1_dVb + fgche1 * dbeta_dVb + - gche * dfgche2_dVb) / fgche2; + + T0 = 1.0 + gche * Rds; + T9 = Vdseff / T0; + Idl = gche * T9; + + dIdl_dVg = (gche * dVdseff_dVg + T9 * dgche_dVg) / T0 + - Idl * gche / T0 * dRds_dVg ; + + dIdl_dVd = (gche * dVdseff_dVd + T9 * dgche_dVd) / T0; + dIdl_dVb = (gche * dVdseff_dVb + T9 * dgche_dVb + - Idl * dRds_dVb * gche) / T0; + + T9 = diffVds / Va; + T0 = 1.0 + T9; + Idsa = Idl * T0; + dIdsa_dVg = T0 * dIdl_dVg - Idl * (dVdseff_dVg + T9 * dVa_dVg) / Va; + dIdsa_dVd = T0 * dIdl_dVd + Idl * (1.0 - dVdseff_dVd + - T9 * dVa_dVd) / Va; + dIdsa_dVb = T0 * dIdl_dVb - Idl * (dVdseff_dVb + T9 * dVa_dVb) / Va; + + T9 = diffVds / VASCBE; + T0 = 1.0 + T9; + Ids = Idsa * T0; + + Gm = T0 * dIdsa_dVg - Idsa * (dVdseff_dVg + T9 * dVASCBE_dVg) / VASCBE; + Gds = T0 * dIdsa_dVd + Idsa * (1.0 - dVdseff_dVd + - T9 * dVASCBE_dVd) / VASCBE; + Gmb = T0 * dIdsa_dVb - Idsa * (dVdseff_dVb + + T9 * dVASCBE_dVb) / VASCBE; + + Gds += Gm * dVgsteff_dVd; + Gmb += Gm * dVgsteff_dVb; + Gm *= dVgsteff_dVg; + Gmb *= dVbseff_dVb; + + /* Substrate current begins */ + tmp = pParam->BSIM3alpha0 + pParam->BSIM3alpha1 * Leff; + if ((tmp <= 0.0) || (pParam->BSIM3beta0 <= 0.0)) + { Isub = Gbd = Gbb = Gbg = 0.0; + } + else + { T2 = tmp / Leff; + if (diffVds > pParam->BSIM3beta0 / EXP_THRESHOLD) + { T0 = -pParam->BSIM3beta0 / diffVds; + T1 = T2 * diffVds * exp(T0); + T3 = T1 / diffVds * (T0 - 1.0); + dT1_dVg = T3 * dVdseff_dVg; + dT1_dVd = T3 * (dVdseff_dVd - 1.0); + dT1_dVb = T3 * dVdseff_dVb; + } + else + { T3 = T2 * MIN_EXP; + T1 = T3 * diffVds; + dT1_dVg = -T3 * dVdseff_dVg; + dT1_dVd = T3 * (1.0 - dVdseff_dVd); + dT1_dVb = -T3 * dVdseff_dVb; + } + Isub = T1 * Idsa; + Gbg = T1 * dIdsa_dVg + Idsa * dT1_dVg; + Gbd = T1 * dIdsa_dVd + Idsa * dT1_dVd; + Gbb = T1 * dIdsa_dVb + Idsa * dT1_dVb; + + Gbd += Gbg * dVgsteff_dVd; + Gbb += Gbg * dVgsteff_dVb; + Gbg *= dVgsteff_dVg; + Gbb *= dVbseff_dVb; /* bug fixing */ + } + + cdrain = Ids; + here->BSIM3gds = Gds; + here->BSIM3gm = Gm; + here->BSIM3gmbs = Gmb; + + here->BSIM3gbbs = Gbb; + here->BSIM3gbgs = Gbg; + here->BSIM3gbds = Gbd; + + here->BSIM3csub = Isub; + + /* BSIM3 thermal noise Qinv calculated from all capMod + * 0, 1, 2 & 3 stored in here->BSIM3qinv 1/1998 */ + + if ((model->BSIM3xpart < 0) || (!ChargeComputationNeeded)) + { qgate = qdrn = qsrc = qbulk = 0.0; + here->BSIM3cggb = here->BSIM3cgsb = here->BSIM3cgdb = 0.0; + here->BSIM3cdgb = here->BSIM3cdsb = here->BSIM3cddb = 0.0; + here->BSIM3cbgb = here->BSIM3cbsb = here->BSIM3cbdb = 0.0; + here->BSIM3cqdb = here->BSIM3cqsb = here->BSIM3cqgb + = here->BSIM3cqbb = 0.0; + here->BSIM3gtau = 0.0; + goto finished; + } + else if (model->BSIM3capMod == 0) + { + if (Vbseff < 0.0) + { Vbseff = Vbs; + dVbseff_dVb = 1.0; + } + else + { Vbseff = pParam->BSIM3phi - Phis; + dVbseff_dVb = -dPhis_dVb; + } + + Vfb = pParam->BSIM3vfbcv; + Vth = Vfb + pParam->BSIM3phi + pParam->BSIM3k1ox * sqrtPhis; + Vgst = Vgs_eff - Vth; + dVth_dVb = pParam->BSIM3k1ox * dsqrtPhis_dVb; + dVgst_dVb = -dVth_dVb; + dVgst_dVg = dVgs_eff_dVg; + + CoxWL = model->BSIM3cox * pParam->BSIM3weffCV + * pParam->BSIM3leffCV; + Arg1 = Vgs_eff - Vbseff - Vfb; + + if (Arg1 <= 0.0) + { qgate = CoxWL * Arg1; + qbulk = -qgate; + qdrn = 0.0; + + here->BSIM3cggb = CoxWL * dVgs_eff_dVg; + here->BSIM3cgdb = 0.0; + here->BSIM3cgsb = CoxWL * (dVbseff_dVb - dVgs_eff_dVg); + + here->BSIM3cdgb = 0.0; + here->BSIM3cddb = 0.0; + here->BSIM3cdsb = 0.0; + + here->BSIM3cbgb = -CoxWL * dVgs_eff_dVg; + here->BSIM3cbdb = 0.0; + here->BSIM3cbsb = -here->BSIM3cgsb; + here->BSIM3qinv = 0.0; + } + else if (Vgst <= 0.0) + { T1 = 0.5 * pParam->BSIM3k1ox; + T2 = sqrt(T1 * T1 + Arg1); + qgate = CoxWL * pParam->BSIM3k1ox * (T2 - T1); + qbulk = -qgate; + qdrn = 0.0; + + T0 = CoxWL * T1 / T2; + here->BSIM3cggb = T0 * dVgs_eff_dVg; + here->BSIM3cgdb = 0.0; + here->BSIM3cgsb = T0 * (dVbseff_dVb - dVgs_eff_dVg); + + here->BSIM3cdgb = 0.0; + here->BSIM3cddb = 0.0; + here->BSIM3cdsb = 0.0; + + here->BSIM3cbgb = -here->BSIM3cggb; + here->BSIM3cbdb = 0.0; + here->BSIM3cbsb = -here->BSIM3cgsb; + here->BSIM3qinv = 0.0; + } + else + { One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + + AbulkCV = Abulk0 * pParam->BSIM3abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3abulkCVfactor * dAbulk0_dVb; + Vdsat = Vgst / AbulkCV; + dVdsat_dVg = dVgs_eff_dVg / AbulkCV; + dVdsat_dVb = - (Vdsat * dAbulkCV_dVb + dVth_dVb)/ AbulkCV; + + if (model->BSIM3xpart > 0.5) + { /* 0/100 Charge partition model */ + if (Vdsat <= Vds) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.0; + + here->BSIM3cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3cgsb = -(here->BSIM3cggb + T2); + here->BSIM3cgdb = 0.0; + + here->BSIM3cdgb = 0.0; + here->BSIM3cddb = 0.0; + here->BSIM3cdsb = 0.0; + + here->BSIM3cbgb = -(here->BSIM3cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3cbsb = -(here->BSIM3cbgb + T3); + here->BSIM3cbdb = 0.0; + here->BSIM3qinv = -(qgate + qbulk); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + T7 = 2.0 * Vds - T1 - 3.0 * T3; + T8 = T3 - T1 - 2.0 * Vds; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3phi - 0.5 * (Vds - T3)); + T10 = T4 * T8; + qdrn = T4 * T7; + qbulk = -(qgate + qdrn + T10); + + T5 = T3 / T1; + here->BSIM3cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3cgsb = -(here->BSIM3cggb + T11 + + here->BSIM3cgdb); + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + T7 = T9 * T7; + T8 = T9 * T8; + T9 = 2.0 * T4 * (1.0 - 3.0 * T5); + here->BSIM3cdgb = (T7 * dAlphaz_dVg - T9 + * dVdsat_dVg) * dVgs_eff_dVg; + T12 = T7 * dAlphaz_dVb - T9 * dVdsat_dVb; + here->BSIM3cddb = T4 * (3.0 - 6.0 * T2 - 3.0 * T5); + here->BSIM3cdsb = -(here->BSIM3cdgb + T12 + + here->BSIM3cddb); + + T9 = 2.0 * T4 * (1.0 + T5); + T10 = (T8 * dAlphaz_dVg - T9 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = T8 * dAlphaz_dVb - T9 * dVdsat_dVb; + T12 = T4 * (2.0 * T2 + T5 - 1.0); + T0 = -(T10 + T11 + T12); + + here->BSIM3cbgb = -(here->BSIM3cggb + + here->BSIM3cdgb + T10); + here->BSIM3cbdb = -(here->BSIM3cgdb + + here->BSIM3cddb + T12); + here->BSIM3cbsb = -(here->BSIM3cgsb + + here->BSIM3cdsb + T0); + here->BSIM3qinv = -(qgate + qbulk); + } + } + else if (model->BSIM3xpart < 0.5) + { /* 40/60 Charge partition model */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.4 * T2; + + here->BSIM3cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3cgsb = -(here->BSIM3cggb + T2); + here->BSIM3cgdb = 0.0; + + T3 = 0.4 * Two_Third_CoxWL; + here->BSIM3cdgb = -T3 * dVgs_eff_dVg; + here->BSIM3cddb = 0.0; + T4 = T3 * dVth_dVb; + here->BSIM3cdsb = -(T4 + here->BSIM3cdgb); + + here->BSIM3cbgb = -(here->BSIM3cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3cbsb = -(here->BSIM3cbgb + T3); + here->BSIM3cbdb = 0.0; + here->BSIM3qinv = -(qgate + qbulk); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM3phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM3cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3cgsb = -(here->BSIM3cggb + + here->BSIM3cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T6 = 8.0 * Vdsat * Vdsat - 6.0 * Vdsat * Vds + + 1.2 * Vds * Vds; + T8 = T2 / T1; + T7 = Vds - T1 - T8 * T6; + qdrn = T4 * T7; + T7 *= T9; + tmp = T8 / T1; + tmp1 = T4 * (2.0 - 4.0 * tmp * T6 + + T8 * (16.0 * Vdsat - 6.0 * Vds)); + + here->BSIM3cdgb = (T7 * dAlphaz_dVg - tmp1 + * dVdsat_dVg) * dVgs_eff_dVg; + T10 = T7 * dAlphaz_dVb - tmp1 * dVdsat_dVb; + here->BSIM3cddb = T4 * (2.0 - (1.0 / (3.0 * T1 + * T1) + 2.0 * tmp) * T6 + T8 + * (6.0 * Vdsat - 2.4 * Vds)); + here->BSIM3cdsb = -(here->BSIM3cdgb + + T10 + here->BSIM3cddb); + + T7 = 2.0 * (T1 + T3); + qbulk = -(qgate - T4 * T7); + T7 *= T9; + T0 = 4.0 * T4 * (1.0 - T5); + T12 = (-T7 * dAlphaz_dVg - here->BSIM3cdgb + - T0 * dVdsat_dVg) * dVgs_eff_dVg; + T11 = -T7 * dAlphaz_dVb - T10 - T0 * dVdsat_dVb; + T10 = -4.0 * T4 * (T2 - 0.5 + 0.5 * T5) + - here->BSIM3cddb; + tmp = -(T10 + T11 + T12); + + here->BSIM3cbgb = -(here->BSIM3cggb + + here->BSIM3cdgb + T12); + here->BSIM3cbdb = -(here->BSIM3cgdb + + here->BSIM3cddb + T11); + here->BSIM3cbsb = -(here->BSIM3cgsb + + here->BSIM3cdsb + tmp); + here->BSIM3qinv = -(qgate + qbulk); + } + } + else + { /* 50/50 partitioning */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.5 * T2; + + here->BSIM3cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3cgsb = -(here->BSIM3cggb + T2); + here->BSIM3cgdb = 0.0; + + here->BSIM3cdgb = -One_Third_CoxWL * dVgs_eff_dVg; + here->BSIM3cddb = 0.0; + T4 = One_Third_CoxWL * dVth_dVb; + here->BSIM3cdsb = -(T4 + here->BSIM3cdgb); + + here->BSIM3cbgb = -(here->BSIM3cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3cbsb = -(here->BSIM3cbgb + T3); + here->BSIM3cbdb = 0.0; + here->BSIM3qinv = -(qgate + qbulk); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM3phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM3cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3cgsb = -(here->BSIM3cggb + + here->BSIM3cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T7 = T1 + T3; + qdrn = -T4 * T7; + qbulk = - (qgate + qdrn + qdrn); + T7 *= T9; + T0 = T4 * (2.0 * T5 - 2.0); + + here->BSIM3cdgb = (T0 * dVdsat_dVg - T7 + * dAlphaz_dVg) * dVgs_eff_dVg; + T12 = T0 * dVdsat_dVb - T7 * dAlphaz_dVb; + here->BSIM3cddb = T4 * (1.0 - 2.0 * T2 - T5); + here->BSIM3cdsb = -(here->BSIM3cdgb + T12 + + here->BSIM3cddb); + + here->BSIM3cbgb = -(here->BSIM3cggb + + 2.0 * here->BSIM3cdgb); + here->BSIM3cbdb = -(here->BSIM3cgdb + + 2.0 * here->BSIM3cddb); + here->BSIM3cbsb = -(here->BSIM3cgsb + + 2.0 * here->BSIM3cdsb); + here->BSIM3qinv = -(qgate + qbulk); + } + } + } + } + else + { if (Vbseff < 0.0) + { VbseffCV = Vbseff; + dVbseffCV_dVb = 1.0; + } + else + { VbseffCV = pParam->BSIM3phi - Phis; + dVbseffCV_dVb = -dPhis_dVb; + } + + CoxWL = model->BSIM3cox * pParam->BSIM3weffCV + * pParam->BSIM3leffCV; + + /* Seperate VgsteffCV with noff and voffcv */ + noff = n * pParam->BSIM3noff; + dnoff_dVd = pParam->BSIM3noff * dn_dVd; + dnoff_dVb = pParam->BSIM3noff * dn_dVb; + T0 = Vtm * noff; + voffcv = pParam->BSIM3voffcv; + VgstNVt = (Vgst - voffcv) / T0; + + if (VgstNVt > EXP_THRESHOLD) + { Vgsteff = Vgst - voffcv; + dVgsteff_dVg = dVgs_eff_dVg; + dVgsteff_dVd = -dVth_dVd; + dVgsteff_dVb = -dVth_dVb; + } + else if (VgstNVt < -EXP_THRESHOLD) + { Vgsteff = T0 * log(1.0 + MIN_EXP); + dVgsteff_dVg = 0.0; + dVgsteff_dVd = Vgsteff / noff; + dVgsteff_dVb = dVgsteff_dVd * dnoff_dVb; + dVgsteff_dVd *= dnoff_dVd; + } + else + { ExpVgst = exp(VgstNVt); + Vgsteff = T0 * log(1.0 + ExpVgst); + dVgsteff_dVg = ExpVgst / (1.0 + ExpVgst); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + (Vgst - voffcv) + / noff * dnoff_dVd) + Vgsteff / noff * dnoff_dVd; + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + (Vgst - voffcv) + / noff * dnoff_dVb) + Vgsteff / noff * dnoff_dVb; + dVgsteff_dVg *= dVgs_eff_dVg; + } /* End of VgsteffCV */ + + if (model->BSIM3capMod == 1) + { Vfb = pParam->BSIM3vfbzb; + Arg1 = Vgs_eff - VbseffCV - Vfb - Vgsteff; + + if (Arg1 <= 0.0) + { qgate = CoxWL * Arg1; + Cgg = CoxWL * (dVgs_eff_dVg - dVgsteff_dVg); + Cgd = -CoxWL * dVgsteff_dVd; + Cgb = -CoxWL * (dVbseffCV_dVb + dVgsteff_dVb); + } + else + { T0 = 0.5 * pParam->BSIM3k1ox; + T1 = sqrt(T0 * T0 + Arg1); + T2 = CoxWL * T0 / T1; + + qgate = CoxWL * pParam->BSIM3k1ox * (T1 - T0); + + Cgg = T2 * (dVgs_eff_dVg - dVgsteff_dVg); + Cgd = -T2 * dVgsteff_dVd; + Cgb = -T2 * (dVbseffCV_dVb + dVgsteff_dVb); + } + qbulk = -qgate; + Cbg = -Cgg; + Cbd = -Cgd; + Cbb = -Cgb; + + One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + AbulkCV = Abulk0 * pParam->BSIM3abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3abulkCVfactor * dAbulk0_dVb; + VdsatCV = Vgsteff / AbulkCV; + if (VdsatCV < Vds) + { dVdsatCV_dVg = 1.0 / AbulkCV; + dVdsatCV_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; + T0 = Vgsteff - VdsatCV / 3.0; + dT0_dVg = 1.0 - dVdsatCV_dVg / 3.0; + dT0_dVb = -dVdsatCV_dVb / 3.0; + qgate += CoxWL * T0; + Cgg1 = CoxWL * dT0_dVg; + Cgb1 = CoxWL * dT0_dVb + Cgg1 * dVgsteff_dVb; + Cgd1 = Cgg1 * dVgsteff_dVd; + Cgg1 *= dVgsteff_dVg; + Cgg += Cgg1; + Cgb += Cgb1; + Cgd += Cgd1; + + T0 = VdsatCV - Vgsteff; + dT0_dVg = dVdsatCV_dVg - 1.0; + dT0_dVb = dVdsatCV_dVb; + qbulk += One_Third_CoxWL * T0; + Cbg1 = One_Third_CoxWL * dT0_dVg; + Cbb1 = One_Third_CoxWL * dT0_dVb + Cbg1 * dVgsteff_dVb; + Cbd1 = Cbg1 * dVgsteff_dVd; + Cbg1 *= dVgsteff_dVg; + Cbg += Cbg1; + Cbb += Cbb1; + Cbd += Cbd1; + + if (model->BSIM3xpart > 0.5) + T0 = -Two_Third_CoxWL; + else if (model->BSIM3xpart < 0.5) + T0 = -0.4 * CoxWL; + else + T0 = -One_Third_CoxWL; + + qsrc = T0 * Vgsteff; + Csg = T0 * dVgsteff_dVg; + Csb = T0 * dVgsteff_dVb; + Csd = T0 * dVgsteff_dVd; + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + } + else + { T0 = AbulkCV * Vds; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1.e-20); + T2 = Vds / T1; + T3 = T0 * T2; + dT3_dVg = -12.0 * T2 * T2 * AbulkCV; + dT3_dVd = 6.0 * T0 * (4.0 * Vgsteff - T0) / T1 / T1 - 0.5; + dT3_dVb = 12.0 * T2 * T2 * dAbulkCV_dVb * Vgsteff; + + qgate += CoxWL * (Vgsteff - 0.5 * Vds + T3); + Cgg1 = CoxWL * (1.0 + dT3_dVg); + Cgb1 = CoxWL * dT3_dVb + Cgg1 * dVgsteff_dVb; + Cgd1 = CoxWL * dT3_dVd + Cgg1 * dVgsteff_dVd; + Cgg1 *= dVgsteff_dVg; + Cgg += Cgg1; + Cgb += Cgb1; + Cgd += Cgd1; + + qbulk += CoxWL * (1.0 - AbulkCV) * (0.5 * Vds - T3); + Cbg1 = -CoxWL * ((1.0 - AbulkCV) * dT3_dVg); + Cbb1 = -CoxWL * ((1.0 - AbulkCV) * dT3_dVb + + (0.5 * Vds - T3) * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbd1 = -CoxWL * (1.0 - AbulkCV) * dT3_dVd + + Cbg1 * dVgsteff_dVd; + Cbg1 *= dVgsteff_dVg; + Cbg += Cbg1; + Cbb += Cbb1; + Cbd += Cbd1; + + if (model->BSIM3xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + Csg = -CoxWL * (0.5 + 24.0 * T0 * Vds / T1 / T1 + * AbulkCV); + Csb = -CoxWL * (0.25 * Vds * dAbulkCV_dVb + - 12.0 * T0 * Vds / T1 / T1 * (4.0 * Vgsteff - T0) + * dAbulkCV_dVb) + Csg * dVgsteff_dVb; + Csd = -CoxWL * (0.25 * AbulkCV - 12.0 * AbulkCV * T0 + / T1 / T1 * (4.0 * Vgsteff - T0)) + + Csg * dVgsteff_dVd; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM3xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T4 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + Csg = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + Csb = (qsrc / T1 * Vds + T2 * T4 * Vds) * dAbulkCV_dVb + + Csg * dVgsteff_dVb; + Csd = (qsrc / T1 + T2 * T4) * AbulkCV + + Csg * dVgsteff_dVd; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + } + qdrn = -(qgate + qbulk + qsrc); + here->BSIM3cggb = Cgg; + here->BSIM3cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3cgdb = Cgd; + here->BSIM3cdgb = -(Cgg + Cbg + Csg); + here->BSIM3cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3cddb = -(Cgd + Cbd + Csd); + here->BSIM3cbgb = Cbg; + here->BSIM3cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3cbdb = Cbd; + here->BSIM3qinv = -(qgate + qbulk); + } + + else if (model->BSIM3capMod == 2) + { Vfb = pParam->BSIM3vfbzb; + V3 = Vfb - Vgs_eff + VbseffCV - DELTA_3; + if (Vfb <= 0.0) + { T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); + T2 = -DELTA_3 / T0; + } + else + { T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); + T2 = DELTA_3 / T0; + } + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = Vfb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1 * dVbseffCV_dVb; + Qac0 = CoxWL * (Vfbeff - Vfb); + dQac0_dVg = CoxWL * dVfbeff_dVg; + dQac0_dVb = CoxWL * dVfbeff_dVb; + + T0 = 0.5 * pParam->BSIM3k1ox; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + if (pParam->BSIM3k1ox == 0.0) + { T1 = 0.0; + T2 = 0.0; + } + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM3k1ox; + T2 = CoxWL; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = CoxWL * T0 / T1; + } + + Qsub0 = CoxWL * pParam->BSIM3k1ox * (T1 - T0); + + dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg); + dQsub0_dVd = -T2 * dVgsteff_dVd; + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + + dVgsteff_dVb); + + AbulkCV = Abulk0 * pParam->BSIM3abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3abulkCVfactor * dAbulk0_dVb; + VdsatCV = Vgsteff / AbulkCV; + + V4 = VdsatCV - Vds - DELTA_4; + T0 = sqrt(V4 * V4 + 4.0 * DELTA_4 * VdsatCV); + VdseffCV = VdsatCV - 0.5 * (V4 + T0); + T1 = 0.5 * (1.0 + V4 / T0); + T2 = DELTA_4 / T0; + T3 = (1.0 - T1 - T2) / AbulkCV; + dVdseffCV_dVg = T3; + dVdseffCV_dVd = T1; + dVdseffCV_dVb = -T3 * VdsatCV * dAbulkCV_dVb; + /* Added to eliminate non-zero VdseffCV at Vds=0.0 */ + if (Vds == 0.0) + { VdseffCV = 0.0; + dVdseffCV_dVg = 0.0; + dVdseffCV_dVb = 0.0; + } + + T0 = AbulkCV * VdseffCV; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1e-20); + T2 = VdseffCV / T1; + T3 = T0 * T2; + + T4 = (1.0 - 12.0 * T2 * T2 * AbulkCV); + T5 = (6.0 * T0 * (4.0 * Vgsteff - T0) / (T1 * T1) - 0.5); + T6 = 12.0 * T2 * T2 * Vgsteff; + + qinoi = -CoxWL * (Vgsteff - 0.5 * T0 + AbulkCV * T3); + qgate = CoxWL * (Vgsteff - 0.5 * VdseffCV + T3); + Cgg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cgd1 = CoxWL * T5 * dVdseffCV_dVd + Cgg1 * dVgsteff_dVd; + Cgb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb; + Cgg1 *= dVgsteff_dVg; + + T7 = 1.0 - AbulkCV; + qbulk = CoxWL * T7 * (0.5 * VdseffCV - T3); + T4 = -T7 * (T4 - 1.0); + T5 = -T7 * T5; + T6 = -(T7 * T6 + (0.5 * VdseffCV - T3)); + Cbg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cbd1 = CoxWL * T5 * dVdseffCV_dVd + Cbg1 * dVgsteff_dVd; + Cbb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbg1 *= dVgsteff_dVg; + + if (model->BSIM3xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + T7 = (4.0 * Vgsteff - T0) / (T1 * T1); + T4 = -(0.5 + 24.0 * T0 * T0 / (T1 * T1)); + T5 = -(0.25 * AbulkCV - 12.0 * AbulkCV * T0 * T7); + T6 = -(0.25 * VdseffCV - 12.0 * T0 * VdseffCV * T7); + Csg = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWL * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM3xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T7 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + T4 = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + T5 = (qsrc / T1 + T2 * T7) * AbulkCV; + T6 = (qsrc / T1 * VdseffCV + T2 * T7 * VdseffCV); + Csg = (T4 + T5 * dVdseffCV_dVg); + Csd = T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + + qgate += Qac0 + Qsub0; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cgg = dQac0_dVg + dQsub0_dVg + Cgg1; + Cgd = dQsub0_dVd + Cgd1; + Cgb = dQac0_dVb + dQsub0_dVb + Cgb1; + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM3cggb = Cgg; + here->BSIM3cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3cgdb = Cgd; + here->BSIM3cdgb = -(Cgg + Cbg + Csg); + here->BSIM3cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3cddb = -(Cgd + Cbd + Csd); + here->BSIM3cbgb = Cbg; + here->BSIM3cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3cbdb = Cbd; + here->BSIM3qinv = qinoi; + } + + /* New Charge-Thickness capMod (CTM) begins */ + else if (model->BSIM3capMod == 3) + { V3 = pParam->BSIM3vfbzb - Vgs_eff + VbseffCV - DELTA_3; + if (pParam->BSIM3vfbzb <= 0.0) + { T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * pParam->BSIM3vfbzb); + T2 = -DELTA_3 / T0; + } + else + { T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * pParam->BSIM3vfbzb); + T2 = DELTA_3 / T0; + } + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = pParam->BSIM3vfbzb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1 * dVbseffCV_dVb; + + Cox = model->BSIM3cox; + Tox = 1.0e8 * model->BSIM3tox; + T0 = (Vgs_eff - VbseffCV - pParam->BSIM3vfbzb) / Tox; + dT0_dVg = dVgs_eff_dVg / Tox; + dT0_dVb = -dVbseffCV_dVb / Tox; + + tmp = T0 * pParam->BSIM3acde; + if ((-EXP_THRESHOLD < tmp) && (tmp < EXP_THRESHOLD)) + { Tcen = pParam->BSIM3ldeb * exp(tmp); + dTcen_dVg = pParam->BSIM3acde * Tcen; + dTcen_dVb = dTcen_dVg * dT0_dVb; + dTcen_dVg *= dT0_dVg; + } + else if (tmp <= -EXP_THRESHOLD) + { Tcen = pParam->BSIM3ldeb * MIN_EXP; + dTcen_dVg = dTcen_dVb = 0.0; + } + else + { Tcen = pParam->BSIM3ldeb * MAX_EXP; + dTcen_dVg = dTcen_dVb = 0.0; + } + + LINK = 1.0e-3 * model->BSIM3tox; + V3 = pParam->BSIM3ldeb - Tcen - LINK; + V4 = sqrt(V3 * V3 + 4.0 * LINK * pParam->BSIM3ldeb); + Tcen = pParam->BSIM3ldeb - 0.5 * (V3 + V4); + T1 = 0.5 * (1.0 + V3 / V4); + dTcen_dVg *= T1; + dTcen_dVb *= T1; + + Ccen = EPSSI / Tcen; + T2 = Cox / (Cox + Ccen); + Coxeff = T2 * Ccen; + T3 = -Ccen / Tcen; + dCoxeff_dVg = T2 * T2 * T3; + dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; + dCoxeff_dVg *= dTcen_dVg; + CoxWLcen = CoxWL * Coxeff / Cox; + + Qac0 = CoxWLcen * (Vfbeff - pParam->BSIM3vfbzb); + QovCox = Qac0 / Coxeff; + dQac0_dVg = CoxWLcen * dVfbeff_dVg + + QovCox * dCoxeff_dVg; + dQac0_dVb = CoxWLcen * dVfbeff_dVb + + QovCox * dCoxeff_dVb; + + T0 = 0.5 * pParam->BSIM3k1ox; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + if (pParam->BSIM3k1ox == 0.0) + { T1 = 0.0; + T2 = 0.0; + } + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM3k1ox; + T2 = CoxWLcen; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = CoxWLcen * T0 / T1; + } + + Qsub0 = CoxWLcen * pParam->BSIM3k1ox * (T1 - T0); + QovCox = Qsub0 / Coxeff; + dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg) + + QovCox * dCoxeff_dVg; + dQsub0_dVd = -T2 * dVgsteff_dVd; + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + dVgsteff_dVb) + + QovCox * dCoxeff_dVb; + + /* Gate-bias dependent delta Phis begins */ + if (pParam->BSIM3k1ox <= 0.0) + { Denomi = 0.25 * pParam->BSIM3moin * Vtm; + T0 = 0.5 * pParam->BSIM3sqrtPhi; + } + else + { Denomi = pParam->BSIM3moin * Vtm + * pParam->BSIM3k1ox * pParam->BSIM3k1ox; + T0 = pParam->BSIM3k1ox * pParam->BSIM3sqrtPhi; + } + T1 = 2.0 * T0 + Vgsteff; + + DeltaPhi = Vtm * log(1.0 + T1 * Vgsteff / Denomi); + dDeltaPhi_dVg = 2.0 * Vtm * (T1 -T0) / (Denomi + T1 * Vgsteff); + dDeltaPhi_dVd = dDeltaPhi_dVg * dVgsteff_dVd; + dDeltaPhi_dVb = dDeltaPhi_dVg * dVgsteff_dVb; + /* End of delta Phis */ + + T3 = 4.0 * (Vth - pParam->BSIM3vfbzb - pParam->BSIM3phi); + Tox += Tox; + if (T3 >= 0.0) + { T0 = (Vgsteff + T3) / Tox; + dT0_dVd = (dVgsteff_dVd + 4.0 * dVth_dVd) / Tox; + dT0_dVb = (dVgsteff_dVb + 4.0 * dVth_dVb) / Tox; + } + else + { T0 = (Vgsteff + 1.0e-20) / Tox; + dT0_dVd = dVgsteff_dVd / Tox; + dT0_dVb = dVgsteff_dVb / Tox; + } + tmp = exp(0.7 * log(T0)); + T1 = 1.0 + tmp; + T2 = 0.7 * tmp / (T0 * Tox); + Tcen = 1.9e-9 / T1; + dTcen_dVg = -1.9e-9 * T2 / T1 /T1; + dTcen_dVd = Tox * dTcen_dVg; + dTcen_dVb = dTcen_dVd * dT0_dVb; + dTcen_dVd *= dT0_dVd; + dTcen_dVg *= dVgsteff_dVg; + + Ccen = EPSSI / Tcen; + T0 = Cox / (Cox + Ccen); + Coxeff = T0 * Ccen; + T1 = -Ccen / Tcen; + dCoxeff_dVg = T0 * T0 * T1; + dCoxeff_dVd = dCoxeff_dVg * dTcen_dVd; + dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; + dCoxeff_dVg *= dTcen_dVg; + CoxWLcen = CoxWL * Coxeff / Cox; + + AbulkCV = Abulk0 * pParam->BSIM3abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3abulkCVfactor * dAbulk0_dVb; + VdsatCV = (Vgsteff - DeltaPhi) / AbulkCV; + V4 = VdsatCV - Vds - DELTA_4; + T0 = sqrt(V4 * V4 + 4.0 * DELTA_4 * VdsatCV); + VdseffCV = VdsatCV - 0.5 * (V4 + T0); + T1 = 0.5 * (1.0 + V4 / T0); + T2 = DELTA_4 / T0; + T3 = (1.0 - T1 - T2) / AbulkCV; + T4 = T3 * ( 1.0 - dDeltaPhi_dVg); + dVdseffCV_dVg = T4; + dVdseffCV_dVd = T1; + dVdseffCV_dVb = -T3 * VdsatCV * dAbulkCV_dVb; + /* Added to eliminate non-zero VdseffCV at Vds=0.0 */ + if (Vds == 0.0) + { VdseffCV = 0.0; + dVdseffCV_dVg = 0.0; + dVdseffCV_dVb = 0.0; + } + + T0 = AbulkCV * VdseffCV; + T1 = Vgsteff - DeltaPhi; + T2 = 12.0 * (T1 - 0.5 * T0 + 1.0e-20); + T3 = T0 / T2; + T4 = 1.0 - 12.0 * T3 * T3; + T5 = AbulkCV * (6.0 * T0 * (4.0 * T1 - T0) / (T2 * T2) - 0.5); + T6 = T5 * VdseffCV / AbulkCV; + + qgate = qinoi = CoxWLcen * (T1 - T0 * (0.5 - T3)); + QovCox = qgate / Coxeff; + Cgg1 = CoxWLcen * (T4 * (1.0 - dDeltaPhi_dVg) + + T5 * dVdseffCV_dVg); + Cgd1 = CoxWLcen * T5 * dVdseffCV_dVd + Cgg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cgb1 = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cgg1 = Cgg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + + + T7 = 1.0 - AbulkCV; + T8 = T2 * T2; + T9 = 12.0 * T7 * T0 * T0 / (T8 * AbulkCV); + T10 = T9 * (1.0 - dDeltaPhi_dVg); + T11 = -T7 * T5 / AbulkCV; + T12 = -(T9 * T1 / AbulkCV + VdseffCV * (0.5 - T0 / T2)); + + qbulk = CoxWLcen * T7 * (0.5 * VdseffCV - T0 * VdseffCV / T2); + QovCox = qbulk / Coxeff; + Cbg1 = CoxWLcen * (T10 + T11 * dVdseffCV_dVg); + Cbd1 = CoxWLcen * T11 * dVdseffCV_dVd + Cbg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cbb1 = CoxWLcen * (T11 * dVdseffCV_dVb + T12 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cbg1 = Cbg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + + if (model->BSIM3xpart > 0.5) + { /* 0/100 partition */ + qsrc = -CoxWLcen * (T1 / 2.0 + T0 / 4.0 + - 0.5 * T0 * T0 / T2); + QovCox = qsrc / Coxeff; + T2 += T2; + T3 = T2 * T2; + T7 = -(0.25 - 12.0 * T0 * (4.0 * T1 - T0) / T3); + T4 = -(0.5 + 24.0 * T0 * T0 / T3) * (1.0 - dDeltaPhi_dVg); + T5 = T7 * AbulkCV; + T6 = T7 * VdseffCV; + + Csg = CoxWLcen * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWLcen * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd + + QovCox * dCoxeff_dVd; + Csb = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + } + else if (model->BSIM3xpart < 0.5) + { /* 40/60 partition */ + T2 = T2 / 12.0; + T3 = 0.5 * CoxWLcen / (T2 * T2); + T4 = T1 * (2.0 * T0 * T0 / 3.0 + T1 * (T1 - 4.0 + * T0 / 3.0)) - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T3 * T4; + QovCox = qsrc / Coxeff; + T8 = 4.0 / 3.0 * T1 * (T1 - T0) + 0.4 * T0 * T0; + T5 = -2.0 * qsrc / T2 - T3 * (T1 * (3.0 * T1 - 8.0 + * T0 / 3.0) + 2.0 * T0 * T0 / 3.0); + T6 = AbulkCV * (qsrc / T2 + T3 * T8); + T7 = T6 * VdseffCV / AbulkCV; + + Csg = T5 * (1.0 - dDeltaPhi_dVg) + T6 * dVdseffCV_dVg; + Csd = Csg * dVgsteff_dVd + T6 * dVdseffCV_dVd + + QovCox * dCoxeff_dVd; + Csb = Csg * dVgsteff_dVb + T6 * dVdseffCV_dVb + + T7 * dAbulkCV_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + } + else + { /* 50/50 partition */ + qsrc = -0.5 * qgate; + Csg = -0.5 * Cgg1; + Csd = -0.5 * Cgd1; + Csb = -0.5 * Cgb1; + } + + qgate += Qac0 + Qsub0 - qbulk; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgg = Cgg1 - Cbg; + Cgd = Cgd1 - Cbd; + Cgb = Cgb1 - Cbb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM3cggb = Cgg; + here->BSIM3cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3cgdb = Cgd; + here->BSIM3cdgb = -(Cgg + Cbg + Csg); + here->BSIM3cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3cddb = -(Cgd + Cbd + Csd); + here->BSIM3cbgb = Cbg; + here->BSIM3cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3cbdb = Cbd; + here->BSIM3qinv = -qinoi; + } /* End of CTM */ + } + +finished: + /* Returning Values to Calling Routine */ + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + + here->BSIM3qgate = qgate; + here->BSIM3qbulk = qbulk; + here->BSIM3qdrn = qdrn; + here->BSIM3cd = cdrain; + + if (ChargeComputationNeeded) + { /* charge storage elements + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw: zero bias drain junction sidewall capacitance + along field oxide + * czbssw: zero bias source junction sidewall capacitance + along field oxide + * czbdswg: zero bias drain junction sidewall capacitance + along gate side + * czbsswg: zero bias source junction sidewall capacitance + along gate side + */ + + czbd = model->BSIM3unitAreaJctCap * here->BSIM3drainArea; + czbs = model->BSIM3unitAreaJctCap * here->BSIM3sourceArea; + if (here->BSIM3drainPerimeter < pParam->BSIM3weff) + { + czbdswg = model->BSIM3unitLengthGateSidewallJctCap + * here->BSIM3drainPerimeter; + czbdsw = 0.0; + } + else + { + czbdsw = model->BSIM3unitLengthSidewallJctCap + * (here->BSIM3drainPerimeter - pParam->BSIM3weff); + czbdswg = model->BSIM3unitLengthGateSidewallJctCap + * pParam->BSIM3weff; + } + if (here->BSIM3sourcePerimeter < pParam->BSIM3weff) + { + czbssw = 0.0; + czbsswg = model->BSIM3unitLengthGateSidewallJctCap + * here->BSIM3sourcePerimeter; + } + else + { + czbssw = model->BSIM3unitLengthSidewallJctCap + * (here->BSIM3sourcePerimeter - pParam->BSIM3weff); + czbsswg = model->BSIM3unitLengthGateSidewallJctCap + * pParam->BSIM3weff; + } + + MJ = model->BSIM3bulkJctBotGradingCoeff; + MJSW = model->BSIM3bulkJctSideGradingCoeff; + MJSWG = model->BSIM3bulkJctGateSideGradingCoeff; + + /* Source Bulk Junction */ + if (vbs == 0.0) + { *(ckt->CKTstate0 + here->BSIM3qbs) = 0.0; + here->BSIM3capbs = czbs + czbssw + czbsswg; + } + else if (vbs < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - vbs / model->BSIM3PhiB; + if (MJ == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJ * log(arg)); + *(ckt->CKTstate0 + here->BSIM3qbs) = model->BSIM3PhiB * czbs + * (1.0 - arg * sarg) / (1.0 - MJ); + here->BSIM3capbs = czbs * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM3qbs) = 0.0; + here->BSIM3capbs = 0.0; + } + if (czbssw > 0.0) + { arg = 1.0 - vbs / model->BSIM3PhiBSW; + if (MJSW == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSW * log(arg)); + *(ckt->CKTstate0 + here->BSIM3qbs) += model->BSIM3PhiBSW * czbssw + * (1.0 - arg * sarg) / (1.0 - MJSW); + here->BSIM3capbs += czbssw * sarg; + } + if (czbsswg > 0.0) + { arg = 1.0 - vbs / model->BSIM3PhiBSWG; + if (MJSWG == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWG * log(arg)); + *(ckt->CKTstate0 + here->BSIM3qbs) += model->BSIM3PhiBSWG * czbsswg + * (1.0 - arg * sarg) / (1.0 - MJSWG); + here->BSIM3capbs += czbsswg * sarg; + } + + } + else + { T0 = czbs + czbssw + czbsswg; + T1 = vbs * (czbs * MJ / model->BSIM3PhiB + czbssw * MJSW + / model->BSIM3PhiBSW + czbsswg * MJSWG / model->BSIM3PhiBSWG); + *(ckt->CKTstate0 + here->BSIM3qbs) = vbs * (T0 + 0.5 * T1); + here->BSIM3capbs = T0 + T1; + } + + /* Drain Bulk Junction */ + if (vbd == 0.0) + { *(ckt->CKTstate0 + here->BSIM3qbd) = 0.0; + here->BSIM3capbd = czbd + czbdsw + czbdswg; + } + else if (vbd < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - vbd / model->BSIM3PhiB; + if (MJ == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJ * log(arg)); + *(ckt->CKTstate0 + here->BSIM3qbd) = model->BSIM3PhiB * czbd + * (1.0 - arg * sarg) / (1.0 - MJ); + here->BSIM3capbd = czbd * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM3qbd) = 0.0; + here->BSIM3capbd = 0.0; + } + if (czbdsw > 0.0) + { arg = 1.0 - vbd / model->BSIM3PhiBSW; + if (MJSW == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSW * log(arg)); + *(ckt->CKTstate0 + here->BSIM3qbd) += model->BSIM3PhiBSW * czbdsw + * (1.0 - arg * sarg) / (1.0 - MJSW); + here->BSIM3capbd += czbdsw * sarg; + } + if (czbdswg > 0.0) + { arg = 1.0 - vbd / model->BSIM3PhiBSWG; + if (MJSWG == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWG * log(arg)); + *(ckt->CKTstate0 + here->BSIM3qbd) += model->BSIM3PhiBSWG * czbdswg + * (1.0 - arg * sarg) / (1.0 - MJSWG); + here->BSIM3capbd += czbdswg * sarg; + } + } + else + { T0 = czbd + czbdsw + czbdswg; + T1 = vbd * (czbd * MJ / model->BSIM3PhiB + czbdsw * MJSW + / model->BSIM3PhiBSW + czbdswg * MJSWG / model->BSIM3PhiBSWG); + *(ckt->CKTstate0 + here->BSIM3qbd) = vbd * (T0 + 0.5 * T1); + here->BSIM3capbd = T0 + T1; + } + } + + /* + * check convergence + */ + if ((here->BSIM3off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { if (Check == 1) + { ckt->CKTnoncon++; +#ifndef NEWCONV + } + else + { if (here->BSIM3mode >= 0) + { Idtot = here->BSIM3cd + here->BSIM3csub - here->BSIM3cbd; + } + else + { Idtot = here->BSIM3cd - here->BSIM3cbd; + } + tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(Idtot)) + + ckt->CKTabstol; + if (fabs(cdhat - Idtot) >= tol) + { ckt->CKTnoncon++; + } + else + { Ibtot = here->BSIM3cbs + here->BSIM3cbd - here->BSIM3csub; + tol = ckt->CKTreltol * MAX(fabs(cbhat), fabs(Ibtot)) + + ckt->CKTabstol; + if (fabs(cbhat - Ibtot)) > tol) + { ckt->CKTnoncon++; + } + } +#endif /* NEWCONV */ + } + } + *(ckt->CKTstate0 + here->BSIM3vbs) = vbs; + *(ckt->CKTstate0 + here->BSIM3vbd) = vbd; + *(ckt->CKTstate0 + here->BSIM3vgs) = vgs; + *(ckt->CKTstate0 + here->BSIM3vds) = vds; + *(ckt->CKTstate0 + here->BSIM3qdef) = qdef; + + /* bulk and channel charge plus overlaps */ + + if (!ChargeComputationNeeded) + goto line850; + +line755: + /* NQS begins */ + if (here->BSIM3nqsMod) + { qcheq = -(qbulk + qgate); + + here->BSIM3cqgb = -(here->BSIM3cggb + here->BSIM3cbgb); + here->BSIM3cqdb = -(here->BSIM3cgdb + here->BSIM3cbdb); + here->BSIM3cqsb = -(here->BSIM3cgsb + here->BSIM3cbsb); + here->BSIM3cqbb = -(here->BSIM3cqgb + here->BSIM3cqdb + + here->BSIM3cqsb); + + gtau_drift = fabs(pParam->BSIM3tconst * qcheq) * ScalingFactor; + T0 = pParam->BSIM3leffCV * pParam->BSIM3leffCV; + gtau_diff = 16.0 * pParam->BSIM3u0temp * model->BSIM3vtm / T0 + * ScalingFactor; + here->BSIM3gtau = gtau_drift + gtau_diff; + } + + if (model->BSIM3capMod == 0) + { if (vgd < 0.0) + { + cgdo = pParam->BSIM3cgdo; + qgdo = pParam->BSIM3cgdo * vgd; + } + else + { cgdo = pParam->BSIM3cgdo; + qgdo = pParam->BSIM3cgdo * vgd; + } + + if (vgs < 0.0) + { + cgso = pParam->BSIM3cgso; + qgso = pParam->BSIM3cgso * vgs; + } + else + { cgso = pParam->BSIM3cgso; + qgso = pParam->BSIM3cgso * vgs; + } + } + else if (model->BSIM3capMod == 1) + { if (vgd < 0.0) + { T1 = sqrt(1.0 - 4.0 * vgd / pParam->BSIM3ckappa); + cgdo = pParam->BSIM3cgdo + pParam->BSIM3weffCV + * pParam->BSIM3cgdl / T1; + qgdo = pParam->BSIM3cgdo * vgd - pParam->BSIM3weffCV * 0.5 + * pParam->BSIM3cgdl * pParam->BSIM3ckappa * (T1 - 1.0); + } + else + { cgdo = pParam->BSIM3cgdo + pParam->BSIM3weffCV + * pParam->BSIM3cgdl; + qgdo = (pParam->BSIM3weffCV * pParam->BSIM3cgdl + + pParam->BSIM3cgdo) * vgd; + } + + if (vgs < 0.0) + { T1 = sqrt(1.0 - 4.0 * vgs / pParam->BSIM3ckappa); + cgso = pParam->BSIM3cgso + pParam->BSIM3weffCV + * pParam->BSIM3cgsl / T1; + qgso = pParam->BSIM3cgso * vgs - pParam->BSIM3weffCV * 0.5 + * pParam->BSIM3cgsl * pParam->BSIM3ckappa * (T1 - 1.0); + } + else + { cgso = pParam->BSIM3cgso + pParam->BSIM3weffCV + * pParam->BSIM3cgsl; + qgso = (pParam->BSIM3weffCV * pParam->BSIM3cgsl + + pParam->BSIM3cgso) * vgs; + } + } + else + { T0 = vgd + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + + T3 = pParam->BSIM3weffCV * pParam->BSIM3cgdl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM3ckappa); + cgdo = pParam->BSIM3cgdo + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgdo = (pParam->BSIM3cgdo + T3) * vgd - T3 * (T2 + + 0.5 * pParam->BSIM3ckappa * (T4 - 1.0)); + + T0 = vgs + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + T3 = pParam->BSIM3weffCV * pParam->BSIM3cgsl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM3ckappa); + cgso = pParam->BSIM3cgso + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgso = (pParam->BSIM3cgso + T3) * vgs - T3 * (T2 + + 0.5 * pParam->BSIM3ckappa * (T4 - 1.0)); + } + + here->BSIM3cgdo = cgdo; + here->BSIM3cgso = cgso; + + ag0 = ckt->CKTag[0]; + if (here->BSIM3mode > 0) + { if (here->BSIM3nqsMod == 0) + { gcggb = (here->BSIM3cggb + cgdo + cgso + + pParam->BSIM3cgbo ) * ag0; + gcgdb = (here->BSIM3cgdb - cgdo) * ag0; + gcgsb = (here->BSIM3cgsb - cgso) * ag0; + + gcdgb = (here->BSIM3cdgb - cgdo) * ag0; + gcddb = (here->BSIM3cddb + here->BSIM3capbd + cgdo) * ag0; + gcdsb = here->BSIM3cdsb * ag0; + + gcsgb = -(here->BSIM3cggb + here->BSIM3cbgb + + here->BSIM3cdgb + cgso) * ag0; + gcsdb = -(here->BSIM3cgdb + here->BSIM3cbdb + + here->BSIM3cddb) * ag0; + gcssb = (here->BSIM3capbs + cgso - (here->BSIM3cgsb + + here->BSIM3cbsb + here->BSIM3cdsb)) * ag0; + + gcbgb = (here->BSIM3cbgb - pParam->BSIM3cgbo) * ag0; + gcbdb = (here->BSIM3cbdb - here->BSIM3capbd) * ag0; + gcbsb = (here->BSIM3cbsb - here->BSIM3capbs) * ag0; + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qdrn -= qgd; + qsrc = -(qgate + qbulk + qdrn); + + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + } + else + { if (qcheq > 0.0) + T0 = pParam->BSIM3tconst * qdef * ScalingFactor; + else + T0 = -pParam->BSIM3tconst * qdef * ScalingFactor; + ggtg = here->BSIM3gtg = T0 * here->BSIM3cqgb; + ggtd = here->BSIM3gtd = T0 * here->BSIM3cqdb; + ggts = here->BSIM3gts = T0 * here->BSIM3cqsb; + ggtb = here->BSIM3gtb = T0 * here->BSIM3cqbb; + gqdef = ScalingFactor * ag0; + + gcqgb = here->BSIM3cqgb * ag0; + gcqdb = here->BSIM3cqdb * ag0; + gcqsb = here->BSIM3cqsb * ag0; + gcqbb = here->BSIM3cqbb * ag0; + + gcggb = (cgdo + cgso + pParam->BSIM3cgbo ) * ag0; + gcgdb = -cgdo * ag0; + gcgsb = -cgso * ag0; + + gcdgb = -cgdo * ag0; + gcddb = (here->BSIM3capbd + cgdo) * ag0; + gcdsb = 0.0; + + gcsgb = -cgso * ag0; + gcsdb = 0.0; + gcssb = (here->BSIM3capbs + cgso) * ag0; + + gcbgb = -pParam->BSIM3cgbo * ag0; + gcbdb = -here->BSIM3capbd * ag0; + gcbsb = -here->BSIM3capbs * ag0; + + CoxWL = model->BSIM3cox * pParam->BSIM3weffCV + * pParam->BSIM3leffCV; + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM3xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = qdrn / qcheq; + Cdd = here->BSIM3cddb; + Csd = -(here->BSIM3cgdb + here->BSIM3cddb + + here->BSIM3cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM3cdgb; + Csg = -(here->BSIM3cggb + here->BSIM3cdgb + + here->BSIM3cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM3cdsb; + Css = -(here->BSIM3cgsb + here->BSIM3cdsb + + here->BSIM3cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3cgbo * vgb; + qgate = qgd + qgs + qgb; + qbulk = -qgb; + qdrn = -qgd; + qsrc = -(qgate + qbulk + qdrn); + } + } + else + { if (here->BSIM3nqsMod == 0) + { gcggb = (here->BSIM3cggb + cgdo + cgso + + pParam->BSIM3cgbo ) * ag0; + gcgdb = (here->BSIM3cgsb - cgdo) * ag0; + gcgsb = (here->BSIM3cgdb - cgso) * ag0; + + gcdgb = -(here->BSIM3cggb + here->BSIM3cbgb + + here->BSIM3cdgb + cgdo) * ag0; + gcddb = (here->BSIM3capbd + cgdo - (here->BSIM3cgsb + + here->BSIM3cbsb + here->BSIM3cdsb)) * ag0; + gcdsb = -(here->BSIM3cgdb + here->BSIM3cbdb + + here->BSIM3cddb) * ag0; + + gcsgb = (here->BSIM3cdgb - cgso) * ag0; + gcsdb = here->BSIM3cdsb * ag0; + gcssb = (here->BSIM3cddb + here->BSIM3capbs + cgso) * ag0; + + gcbgb = (here->BSIM3cbgb - pParam->BSIM3cgbo) * ag0; + gcbdb = (here->BSIM3cbsb - here->BSIM3capbd) * ag0; + gcbsb = (here->BSIM3cbdb - here->BSIM3capbs) * ag0; + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qsrc = qdrn - qgs; + qdrn = -(qgate + qbulk + qsrc); + + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + } + else + { if (qcheq > 0.0) + T0 = pParam->BSIM3tconst * qdef * ScalingFactor; + else + T0 = -pParam->BSIM3tconst * qdef * ScalingFactor; + ggtg = here->BSIM3gtg = T0 * here->BSIM3cqgb; + ggts = here->BSIM3gtd = T0 * here->BSIM3cqdb; + ggtd = here->BSIM3gts = T0 * here->BSIM3cqsb; + ggtb = here->BSIM3gtb = T0 * here->BSIM3cqbb; + gqdef = ScalingFactor * ag0; + + gcqgb = here->BSIM3cqgb * ag0; + gcqdb = here->BSIM3cqsb * ag0; + gcqsb = here->BSIM3cqdb * ag0; + gcqbb = here->BSIM3cqbb * ag0; + + gcggb = (cgdo + cgso + pParam->BSIM3cgbo) * ag0; + gcgdb = -cgdo * ag0; + gcgsb = -cgso * ag0; + + gcdgb = -cgdo * ag0; + gcddb = (here->BSIM3capbd + cgdo) * ag0; + gcdsb = 0.0; + + gcsgb = -cgso * ag0; + gcsdb = 0.0; + gcssb = (here->BSIM3capbs + cgso) * ag0; + + gcbgb = -pParam->BSIM3cgbo * ag0; + gcbdb = -here->BSIM3capbd * ag0; + gcbsb = -here->BSIM3capbs * ag0; + + CoxWL = model->BSIM3cox * pParam->BSIM3weffCV + * pParam->BSIM3leffCV; + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM3xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = qdrn / qcheq; + Css = here->BSIM3cddb; + Cds = -(here->BSIM3cgdb + here->BSIM3cddb + + here->BSIM3cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM3cdgb; + Cdg = -(here->BSIM3cggb + here->BSIM3cdgb + + here->BSIM3cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM3cdsb; + Cdd = -(here->BSIM3cgsb + here->BSIM3cdsb + + here->BSIM3cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3cgbo * vgb; + qgate = qgd + qgs + qgb; + qbulk = -qgb; + qsrc = -qgs; + qdrn = -(qgate + qbulk + qsrc); + } + } + + cqdef = cqcheq = 0.0; + if (ByPass) goto line860; + + *(ckt->CKTstate0 + here->BSIM3qg) = qgate; + *(ckt->CKTstate0 + here->BSIM3qd) = qdrn + - *(ckt->CKTstate0 + here->BSIM3qbd); + *(ckt->CKTstate0 + here->BSIM3qb) = qbulk + + *(ckt->CKTstate0 + here->BSIM3qbd) + + *(ckt->CKTstate0 + here->BSIM3qbs); + + if (here->BSIM3nqsMod) + { *(ckt->CKTstate0 + here->BSIM3qcdump) = qdef * ScalingFactor; + *(ckt->CKTstate0 + here->BSIM3qcheq) = qcheq; + } + + /* store small signal parameters */ + if (ckt->CKTmode & MODEINITSMSIG) + { goto line1000; + } + if (!ChargeComputationNeeded) + goto line850; + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM3qb) = + *(ckt->CKTstate0 + here->BSIM3qb); + *(ckt->CKTstate1 + here->BSIM3qg) = + *(ckt->CKTstate0 + here->BSIM3qg); + *(ckt->CKTstate1 + here->BSIM3qd) = + *(ckt->CKTstate0 + here->BSIM3qd); + if (here->BSIM3nqsMod) + { *(ckt->CKTstate1 + here->BSIM3qcheq) = + *(ckt->CKTstate0 + here->BSIM3qcheq); + *(ckt->CKTstate1 + here->BSIM3qcdump) = + *(ckt->CKTstate0 + here->BSIM3qcdump); + } + } + + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3qb); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3qg); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3qd); + if (error) + return(error); + if (here->BSIM3nqsMod) + { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3qcdump); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3qcheq); + if (error) + return(error); + } + + goto line860; + +line850: + /* initialize to zero charge conductance and current */ + ceqqg = ceqqb = ceqqd = 0.0; + cqcheq = cqdef = 0.0; + + gcdgb = gcddb = gcdsb = 0.0; + gcsgb = gcsdb = gcssb = 0.0; + gcggb = gcgdb = gcgsb = 0.0; + gcbgb = gcbdb = gcbsb = 0.0; + + gqdef = gcqgb = gcqdb = gcqsb = gcqbb = 0.0; + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = (1.0 - (dxpart = (here->BSIM3mode > 0) ? 0.4 : 0.6)); + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + + if (here->BSIM3nqsMod) + here->BSIM3gtau = 16.0 * pParam->BSIM3u0temp * model->BSIM3vtm + / pParam->BSIM3leffCV / pParam->BSIM3leffCV + * ScalingFactor; + else + here->BSIM3gtau = 0.0; + + goto line900; + +line860: + /* evaluate equivalent charge current */ + + cqgate = *(ckt->CKTstate0 + here->BSIM3cqg); + cqbulk = *(ckt->CKTstate0 + here->BSIM3cqb); + cqdrn = *(ckt->CKTstate0 + here->BSIM3cqd); + + ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; + ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs; + ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs; + + if (here->BSIM3nqsMod) + { T0 = ggtg * vgb - ggtd * vbd - ggts * vbs; + ceqqg += T0; + T1 = qdef * here->BSIM3gtau; + ceqqd -= dxpart * T0 + T1 * (ddxpart_dVg * vgb - ddxpart_dVd + * vbd - ddxpart_dVs * vbs); + cqdef = *(ckt->CKTstate0 + here->BSIM3cqcdump) - gqdef * qdef; + cqcheq = *(ckt->CKTstate0 + here->BSIM3cqcheq) + - (gcqgb * vgb - gcqdb * vbd - gcqsb * vbs) + T0; + } + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM3cqb) = + *(ckt->CKTstate0 + here->BSIM3cqb); + *(ckt->CKTstate1 + here->BSIM3cqg) = + *(ckt->CKTstate0 + here->BSIM3cqg); + *(ckt->CKTstate1 + here->BSIM3cqd) = + *(ckt->CKTstate0 + here->BSIM3cqd); + + if (here->BSIM3nqsMod) + { *(ckt->CKTstate1 + here->BSIM3cqcheq) = + *(ckt->CKTstate0 + here->BSIM3cqcheq); + *(ckt->CKTstate1 + here->BSIM3cqcdump) = + *(ckt->CKTstate0 + here->BSIM3cqcdump); + } + } + + /* + * load current vector + */ +line900: + + if (here->BSIM3mode >= 0) + { Gm = here->BSIM3gm; + Gmbs = here->BSIM3gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + cdreq = model->BSIM3type * (cdrain - here->BSIM3gds * vds + - Gm * vgs - Gmbs * vbs); + + ceqbd = -model->BSIM3type * (here->BSIM3csub + - here->BSIM3gbds * vds - here->BSIM3gbgs * vgs + - here->BSIM3gbbs * vbs); + ceqbs = 0.0; + + gbbdp = -here->BSIM3gbds; + gbbsp = (here->BSIM3gbds + here->BSIM3gbgs + here->BSIM3gbbs); + + gbdpg = here->BSIM3gbgs; + gbdpdp = here->BSIM3gbds; + gbdpb = here->BSIM3gbbs; + gbdpsp = -(gbdpg + gbdpdp + gbdpb); + + gbspg = 0.0; + gbspdp = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + } + else + { Gm = -here->BSIM3gm; + Gmbs = -here->BSIM3gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + cdreq = -model->BSIM3type * (cdrain + here->BSIM3gds * vds + + Gm * vgd + Gmbs * vbd); + + ceqbs = -model->BSIM3type * (here->BSIM3csub + + here->BSIM3gbds * vds - here->BSIM3gbgs * vgd + - here->BSIM3gbbs * vbd); + ceqbd = 0.0; + + gbbsp = -here->BSIM3gbds; + gbbdp = (here->BSIM3gbds + here->BSIM3gbgs + here->BSIM3gbbs); + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM3gbgs; + gbspsp = here->BSIM3gbds; + gbspb = here->BSIM3gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + } + + if (model->BSIM3type > 0) + { ceqbs += (here->BSIM3cbs - here->BSIM3gbs * vbs); + ceqbd += (here->BSIM3cbd - here->BSIM3gbd * vbd); + /* + ceqqg = ceqqg; + ceqqb = ceqqb; + ceqqd = ceqqd; + cqdef = cqdef; + cqcheq = cqcheq; + */ + } + else + { ceqbs -= (here->BSIM3cbs - here->BSIM3gbs * vbs); + ceqbd -= (here->BSIM3cbd - here->BSIM3gbd * vbd); + ceqqg = -ceqqg; + ceqqb = -ceqqb; + ceqqd = -ceqqd; + cqdef = -cqdef; + cqcheq = -cqcheq; + } + + (*(ckt->CKTrhs + here->BSIM3gNode) -= ceqqg); + (*(ckt->CKTrhs + here->BSIM3bNode) -=(ceqbs + ceqbd + ceqqb)); + (*(ckt->CKTrhs + here->BSIM3dNodePrime) += (ceqbd - cdreq - ceqqd)); + (*(ckt->CKTrhs + here->BSIM3sNodePrime) += (cdreq + ceqbs + ceqqg + + ceqqb + ceqqd)); + if (here->BSIM3nqsMod) + *(ckt->CKTrhs + here->BSIM3qNode) += (cqcheq - cqdef); + + /* + * load y matrix + */ + + T1 = qdef * here->BSIM3gtau; + (*(here->BSIM3DdPtr) += here->BSIM3drainConductance); + (*(here->BSIM3GgPtr) += gcggb - ggtg); + (*(here->BSIM3SsPtr) += here->BSIM3sourceConductance); + (*(here->BSIM3BbPtr) += here->BSIM3gbd + here->BSIM3gbs + - gcbgb - gcbdb - gcbsb - here->BSIM3gbbs); + (*(here->BSIM3DPdpPtr) += here->BSIM3drainConductance + + here->BSIM3gds + here->BSIM3gbd + + RevSum + gcddb + dxpart * ggtd + + T1 * ddxpart_dVd + gbdpdp); + (*(here->BSIM3SPspPtr) += here->BSIM3sourceConductance + + here->BSIM3gds + here->BSIM3gbs + + FwdSum + gcssb + sxpart * ggts + + T1 * dsxpart_dVs + gbspsp); + (*(here->BSIM3DdpPtr) -= here->BSIM3drainConductance); + (*(here->BSIM3GbPtr) -= gcggb + gcgdb + gcgsb + ggtb); + (*(here->BSIM3GdpPtr) += gcgdb - ggtd); + (*(here->BSIM3GspPtr) += gcgsb - ggts); + (*(here->BSIM3SspPtr) -= here->BSIM3sourceConductance); + (*(here->BSIM3BgPtr) += gcbgb - here->BSIM3gbgs); + (*(here->BSIM3BdpPtr) += gcbdb - here->BSIM3gbd + gbbdp); + (*(here->BSIM3BspPtr) += gcbsb - here->BSIM3gbs + gbbsp); + (*(here->BSIM3DPdPtr) -= here->BSIM3drainConductance); + (*(here->BSIM3DPgPtr) += Gm + gcdgb + dxpart * ggtg + + T1 * ddxpart_dVg + gbdpg); + (*(here->BSIM3DPbPtr) -= here->BSIM3gbd - Gmbs + gcdgb + gcddb + + gcdsb - dxpart * ggtb + - T1 * ddxpart_dVb - gbdpb); + (*(here->BSIM3DPspPtr) -= here->BSIM3gds + FwdSum - gcdsb + - dxpart * ggts - T1 * ddxpart_dVs - gbdpsp); + (*(here->BSIM3SPgPtr) += gcsgb - Gm + sxpart * ggtg + + T1 * dsxpart_dVg + gbspg); + (*(here->BSIM3SPsPtr) -= here->BSIM3sourceConductance); + (*(here->BSIM3SPbPtr) -= here->BSIM3gbs + Gmbs + gcsgb + gcsdb + + gcssb - sxpart * ggtb + - T1 * dsxpart_dVb - gbspb); + (*(here->BSIM3SPdpPtr) -= here->BSIM3gds + RevSum - gcsdb + - sxpart * ggtd - T1 * dsxpart_dVd - gbspdp); + + if (here->BSIM3nqsMod) + { *(here->BSIM3QqPtr) += (gqdef + here->BSIM3gtau); + + *(here->BSIM3DPqPtr) += (dxpart * here->BSIM3gtau); + *(here->BSIM3SPqPtr) += (sxpart * here->BSIM3gtau); + *(here->BSIM3GqPtr) -= here->BSIM3gtau; + + *(here->BSIM3QgPtr) += (ggtg - gcqgb); + *(here->BSIM3QdpPtr) += (ggtd - gcqdb); + *(here->BSIM3QspPtr) += (ggts - gcqsb); + *(here->BSIM3QbPtr) += (ggtb - gcqbb); + } + +line1000: ; + + } /* End of Mosfet Instance */ +} /* End of Model Instance */ + +return(OK); +} + diff --git a/src/spicelib/devices/bsim3/b3mask.c b/src/spicelib/devices/bsim3/b3mask.c new file mode 100644 index 000000000..0776f1313 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3mask.c @@ -0,0 +1,1259 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3mask.c +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim3def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3mAsk(ckt,inst,which,value) +CKTcircuit *ckt; +GENmodel *inst; +int which; +IFvalue *value; +{ + BSIM3model *model = (BSIM3model *)inst; + switch(which) + { case BSIM3_MOD_MOBMOD: + value->iValue = model->BSIM3mobMod; + return(OK); + case BSIM3_MOD_PARAMCHK: + value->iValue = model->BSIM3paramChk; + return(OK); + case BSIM3_MOD_BINUNIT: + value->iValue = model->BSIM3binUnit; + return(OK); + case BSIM3_MOD_CAPMOD: + value->iValue = model->BSIM3capMod; + return(OK); + case BSIM3_MOD_NOIMOD: + value->iValue = model->BSIM3noiMod; + return(OK); + case BSIM3_MOD_VERSION : + value->sValue = model->BSIM3version; + return(OK); + case BSIM3_MOD_TOX : + value->rValue = model->BSIM3tox; + return(OK); + case BSIM3_MOD_TOXM : + value->rValue = model->BSIM3toxm; + return(OK); + case BSIM3_MOD_CDSC : + value->rValue = model->BSIM3cdsc; + return(OK); + case BSIM3_MOD_CDSCB : + value->rValue = model->BSIM3cdscb; + return(OK); + + case BSIM3_MOD_CDSCD : + value->rValue = model->BSIM3cdscd; + return(OK); + + case BSIM3_MOD_CIT : + value->rValue = model->BSIM3cit; + return(OK); + case BSIM3_MOD_NFACTOR : + value->rValue = model->BSIM3nfactor; + return(OK); + case BSIM3_MOD_XJ: + value->rValue = model->BSIM3xj; + return(OK); + case BSIM3_MOD_VSAT: + value->rValue = model->BSIM3vsat; + return(OK); + case BSIM3_MOD_AT: + value->rValue = model->BSIM3at; + return(OK); + case BSIM3_MOD_A0: + value->rValue = model->BSIM3a0; + return(OK); + + case BSIM3_MOD_AGS: + value->rValue = model->BSIM3ags; + return(OK); + + case BSIM3_MOD_A1: + value->rValue = model->BSIM3a1; + return(OK); + case BSIM3_MOD_A2: + value->rValue = model->BSIM3a2; + return(OK); + case BSIM3_MOD_KETA: + value->rValue = model->BSIM3keta; + return(OK); + case BSIM3_MOD_NSUB: + value->rValue = model->BSIM3nsub; + return(OK); + case BSIM3_MOD_NPEAK: + value->rValue = model->BSIM3npeak; + return(OK); + case BSIM3_MOD_NGATE: + value->rValue = model->BSIM3ngate; + return(OK); + case BSIM3_MOD_GAMMA1: + value->rValue = model->BSIM3gamma1; + return(OK); + case BSIM3_MOD_GAMMA2: + value->rValue = model->BSIM3gamma2; + return(OK); + case BSIM3_MOD_VBX: + value->rValue = model->BSIM3vbx; + return(OK); + case BSIM3_MOD_VBM: + value->rValue = model->BSIM3vbm; + return(OK); + case BSIM3_MOD_XT: + value->rValue = model->BSIM3xt; + return(OK); + case BSIM3_MOD_K1: + value->rValue = model->BSIM3k1; + return(OK); + case BSIM3_MOD_KT1: + value->rValue = model->BSIM3kt1; + return(OK); + case BSIM3_MOD_KT1L: + value->rValue = model->BSIM3kt1l; + return(OK); + case BSIM3_MOD_KT2 : + value->rValue = model->BSIM3kt2; + return(OK); + case BSIM3_MOD_K2 : + value->rValue = model->BSIM3k2; + return(OK); + case BSIM3_MOD_K3: + value->rValue = model->BSIM3k3; + return(OK); + case BSIM3_MOD_K3B: + value->rValue = model->BSIM3k3b; + return(OK); + case BSIM3_MOD_W0: + value->rValue = model->BSIM3w0; + return(OK); + case BSIM3_MOD_NLX: + value->rValue = model->BSIM3nlx; + return(OK); + case BSIM3_MOD_DVT0 : + value->rValue = model->BSIM3dvt0; + return(OK); + case BSIM3_MOD_DVT1 : + value->rValue = model->BSIM3dvt1; + return(OK); + case BSIM3_MOD_DVT2 : + value->rValue = model->BSIM3dvt2; + return(OK); + case BSIM3_MOD_DVT0W : + value->rValue = model->BSIM3dvt0w; + return(OK); + case BSIM3_MOD_DVT1W : + value->rValue = model->BSIM3dvt1w; + return(OK); + case BSIM3_MOD_DVT2W : + value->rValue = model->BSIM3dvt2w; + return(OK); + case BSIM3_MOD_DROUT : + value->rValue = model->BSIM3drout; + return(OK); + case BSIM3_MOD_DSUB : + value->rValue = model->BSIM3dsub; + return(OK); + case BSIM3_MOD_VTH0: + value->rValue = model->BSIM3vth0; + return(OK); + case BSIM3_MOD_UA: + value->rValue = model->BSIM3ua; + return(OK); + case BSIM3_MOD_UA1: + value->rValue = model->BSIM3ua1; + return(OK); + case BSIM3_MOD_UB: + value->rValue = model->BSIM3ub; + return(OK); + case BSIM3_MOD_UB1: + value->rValue = model->BSIM3ub1; + return(OK); + case BSIM3_MOD_UC: + value->rValue = model->BSIM3uc; + return(OK); + case BSIM3_MOD_UC1: + value->rValue = model->BSIM3uc1; + return(OK); + case BSIM3_MOD_U0: + value->rValue = model->BSIM3u0; + return(OK); + case BSIM3_MOD_UTE: + value->rValue = model->BSIM3ute; + return(OK); + case BSIM3_MOD_VOFF: + value->rValue = model->BSIM3voff; + return(OK); + case BSIM3_MOD_DELTA: + value->rValue = model->BSIM3delta; + return(OK); + case BSIM3_MOD_RDSW: + value->rValue = model->BSIM3rdsw; + return(OK); + case BSIM3_MOD_PRWG: + value->rValue = model->BSIM3prwg; + return(OK); + case BSIM3_MOD_PRWB: + value->rValue = model->BSIM3prwb; + return(OK); + case BSIM3_MOD_PRT: + value->rValue = model->BSIM3prt; + return(OK); + case BSIM3_MOD_ETA0: + value->rValue = model->BSIM3eta0; + return(OK); + case BSIM3_MOD_ETAB: + value->rValue = model->BSIM3etab; + return(OK); + case BSIM3_MOD_PCLM: + value->rValue = model->BSIM3pclm; + return(OK); + case BSIM3_MOD_PDIBL1: + value->rValue = model->BSIM3pdibl1; + return(OK); + case BSIM3_MOD_PDIBL2: + value->rValue = model->BSIM3pdibl2; + return(OK); + case BSIM3_MOD_PDIBLB: + value->rValue = model->BSIM3pdiblb; + return(OK); + case BSIM3_MOD_PSCBE1: + value->rValue = model->BSIM3pscbe1; + return(OK); + case BSIM3_MOD_PSCBE2: + value->rValue = model->BSIM3pscbe2; + return(OK); + case BSIM3_MOD_PVAG: + value->rValue = model->BSIM3pvag; + return(OK); + case BSIM3_MOD_WR: + value->rValue = model->BSIM3wr; + return(OK); + case BSIM3_MOD_DWG: + value->rValue = model->BSIM3dwg; + return(OK); + case BSIM3_MOD_DWB: + value->rValue = model->BSIM3dwb; + return(OK); + case BSIM3_MOD_B0: + value->rValue = model->BSIM3b0; + return(OK); + case BSIM3_MOD_B1: + value->rValue = model->BSIM3b1; + return(OK); + case BSIM3_MOD_ALPHA0: + value->rValue = model->BSIM3alpha0; + return(OK); + case BSIM3_MOD_ALPHA1: + value->rValue = model->BSIM3alpha1; + return(OK); + case BSIM3_MOD_BETA0: + value->rValue = model->BSIM3beta0; + return(OK); + case BSIM3_MOD_IJTH: + value->rValue = model->BSIM3ijth; + return(OK); + case BSIM3_MOD_VFB: + value->rValue = model->BSIM3vfb; + return(OK); + + case BSIM3_MOD_ELM: + value->rValue = model->BSIM3elm; + return(OK); + case BSIM3_MOD_CGSL: + value->rValue = model->BSIM3cgsl; + return(OK); + case BSIM3_MOD_CGDL: + value->rValue = model->BSIM3cgdl; + return(OK); + case BSIM3_MOD_CKAPPA: + value->rValue = model->BSIM3ckappa; + return(OK); + case BSIM3_MOD_CF: + value->rValue = model->BSIM3cf; + return(OK); + case BSIM3_MOD_CLC: + value->rValue = model->BSIM3clc; + return(OK); + case BSIM3_MOD_CLE: + value->rValue = model->BSIM3cle; + return(OK); + case BSIM3_MOD_DWC: + value->rValue = model->BSIM3dwc; + return(OK); + case BSIM3_MOD_DLC: + value->rValue = model->BSIM3dlc; + return(OK); + case BSIM3_MOD_VFBCV: + value->rValue = model->BSIM3vfbcv; + return(OK); + case BSIM3_MOD_ACDE: + value->rValue = model->BSIM3acde; + return(OK); + case BSIM3_MOD_MOIN: + value->rValue = model->BSIM3moin; + return(OK); + case BSIM3_MOD_NOFF: + value->rValue = model->BSIM3noff; + return(OK); + case BSIM3_MOD_VOFFCV: + value->rValue = model->BSIM3voffcv; + return(OK); + case BSIM3_MOD_TCJ: + value->rValue = model->BSIM3tcj; + return(OK); + case BSIM3_MOD_TPB: + value->rValue = model->BSIM3tpb; + return(OK); + case BSIM3_MOD_TCJSW: + value->rValue = model->BSIM3tcjsw; + return(OK); + case BSIM3_MOD_TPBSW: + value->rValue = model->BSIM3tpbsw; + return(OK); + case BSIM3_MOD_TCJSWG: + value->rValue = model->BSIM3tcjswg; + return(OK); + case BSIM3_MOD_TPBSWG: + value->rValue = model->BSIM3tpbswg; + return(OK); + + /* Length dependence */ + case BSIM3_MOD_LCDSC : + value->rValue = model->BSIM3lcdsc; + return(OK); + case BSIM3_MOD_LCDSCB : + value->rValue = model->BSIM3lcdscb; + return(OK); + case BSIM3_MOD_LCDSCD : + value->rValue = model->BSIM3lcdscd; + return(OK); + case BSIM3_MOD_LCIT : + value->rValue = model->BSIM3lcit; + return(OK); + case BSIM3_MOD_LNFACTOR : + value->rValue = model->BSIM3lnfactor; + return(OK); + case BSIM3_MOD_LXJ: + value->rValue = model->BSIM3lxj; + return(OK); + case BSIM3_MOD_LVSAT: + value->rValue = model->BSIM3lvsat; + return(OK); + case BSIM3_MOD_LAT: + value->rValue = model->BSIM3lat; + return(OK); + case BSIM3_MOD_LA0: + value->rValue = model->BSIM3la0; + return(OK); + case BSIM3_MOD_LAGS: + value->rValue = model->BSIM3lags; + return(OK); + case BSIM3_MOD_LA1: + value->rValue = model->BSIM3la1; + return(OK); + case BSIM3_MOD_LA2: + value->rValue = model->BSIM3la2; + return(OK); + case BSIM3_MOD_LKETA: + value->rValue = model->BSIM3lketa; + return(OK); + case BSIM3_MOD_LNSUB: + value->rValue = model->BSIM3lnsub; + return(OK); + case BSIM3_MOD_LNPEAK: + value->rValue = model->BSIM3lnpeak; + return(OK); + case BSIM3_MOD_LNGATE: + value->rValue = model->BSIM3lngate; + return(OK); + case BSIM3_MOD_LGAMMA1: + value->rValue = model->BSIM3lgamma1; + return(OK); + case BSIM3_MOD_LGAMMA2: + value->rValue = model->BSIM3lgamma2; + return(OK); + case BSIM3_MOD_LVBX: + value->rValue = model->BSIM3lvbx; + return(OK); + case BSIM3_MOD_LVBM: + value->rValue = model->BSIM3lvbm; + return(OK); + case BSIM3_MOD_LXT: + value->rValue = model->BSIM3lxt; + return(OK); + case BSIM3_MOD_LK1: + value->rValue = model->BSIM3lk1; + return(OK); + case BSIM3_MOD_LKT1: + value->rValue = model->BSIM3lkt1; + return(OK); + case BSIM3_MOD_LKT1L: + value->rValue = model->BSIM3lkt1l; + return(OK); + case BSIM3_MOD_LKT2 : + value->rValue = model->BSIM3lkt2; + return(OK); + case BSIM3_MOD_LK2 : + value->rValue = model->BSIM3lk2; + return(OK); + case BSIM3_MOD_LK3: + value->rValue = model->BSIM3lk3; + return(OK); + case BSIM3_MOD_LK3B: + value->rValue = model->BSIM3lk3b; + return(OK); + case BSIM3_MOD_LW0: + value->rValue = model->BSIM3lw0; + return(OK); + case BSIM3_MOD_LNLX: + value->rValue = model->BSIM3lnlx; + return(OK); + case BSIM3_MOD_LDVT0: + value->rValue = model->BSIM3ldvt0; + return(OK); + case BSIM3_MOD_LDVT1 : + value->rValue = model->BSIM3ldvt1; + return(OK); + case BSIM3_MOD_LDVT2 : + value->rValue = model->BSIM3ldvt2; + return(OK); + case BSIM3_MOD_LDVT0W : + value->rValue = model->BSIM3ldvt0w; + return(OK); + case BSIM3_MOD_LDVT1W : + value->rValue = model->BSIM3ldvt1w; + return(OK); + case BSIM3_MOD_LDVT2W : + value->rValue = model->BSIM3ldvt2w; + return(OK); + case BSIM3_MOD_LDROUT : + value->rValue = model->BSIM3ldrout; + return(OK); + case BSIM3_MOD_LDSUB : + value->rValue = model->BSIM3ldsub; + return(OK); + case BSIM3_MOD_LVTH0: + value->rValue = model->BSIM3lvth0; + return(OK); + case BSIM3_MOD_LUA: + value->rValue = model->BSIM3lua; + return(OK); + case BSIM3_MOD_LUA1: + value->rValue = model->BSIM3lua1; + return(OK); + case BSIM3_MOD_LUB: + value->rValue = model->BSIM3lub; + return(OK); + case BSIM3_MOD_LUB1: + value->rValue = model->BSIM3lub1; + return(OK); + case BSIM3_MOD_LUC: + value->rValue = model->BSIM3luc; + return(OK); + case BSIM3_MOD_LUC1: + value->rValue = model->BSIM3luc1; + return(OK); + case BSIM3_MOD_LU0: + value->rValue = model->BSIM3lu0; + return(OK); + case BSIM3_MOD_LUTE: + value->rValue = model->BSIM3lute; + return(OK); + case BSIM3_MOD_LVOFF: + value->rValue = model->BSIM3lvoff; + return(OK); + case BSIM3_MOD_LDELTA: + value->rValue = model->BSIM3ldelta; + return(OK); + case BSIM3_MOD_LRDSW: + value->rValue = model->BSIM3lrdsw; + return(OK); + case BSIM3_MOD_LPRWB: + value->rValue = model->BSIM3lprwb; + return(OK); + case BSIM3_MOD_LPRWG: + value->rValue = model->BSIM3lprwg; + return(OK); + case BSIM3_MOD_LPRT: + value->rValue = model->BSIM3lprt; + return(OK); + case BSIM3_MOD_LETA0: + value->rValue = model->BSIM3leta0; + return(OK); + case BSIM3_MOD_LETAB: + value->rValue = model->BSIM3letab; + return(OK); + case BSIM3_MOD_LPCLM: + value->rValue = model->BSIM3lpclm; + return(OK); + case BSIM3_MOD_LPDIBL1: + value->rValue = model->BSIM3lpdibl1; + return(OK); + case BSIM3_MOD_LPDIBL2: + value->rValue = model->BSIM3lpdibl2; + return(OK); + case BSIM3_MOD_LPDIBLB: + value->rValue = model->BSIM3lpdiblb; + return(OK); + case BSIM3_MOD_LPSCBE1: + value->rValue = model->BSIM3lpscbe1; + return(OK); + case BSIM3_MOD_LPSCBE2: + value->rValue = model->BSIM3lpscbe2; + return(OK); + case BSIM3_MOD_LPVAG: + value->rValue = model->BSIM3lpvag; + return(OK); + case BSIM3_MOD_LWR: + value->rValue = model->BSIM3lwr; + return(OK); + case BSIM3_MOD_LDWG: + value->rValue = model->BSIM3ldwg; + return(OK); + case BSIM3_MOD_LDWB: + value->rValue = model->BSIM3ldwb; + return(OK); + case BSIM3_MOD_LB0: + value->rValue = model->BSIM3lb0; + return(OK); + case BSIM3_MOD_LB1: + value->rValue = model->BSIM3lb1; + return(OK); + case BSIM3_MOD_LALPHA0: + value->rValue = model->BSIM3lalpha0; + return(OK); + case BSIM3_MOD_LALPHA1: + value->rValue = model->BSIM3lalpha1; + return(OK); + case BSIM3_MOD_LBETA0: + value->rValue = model->BSIM3lbeta0; + return(OK); + case BSIM3_MOD_LVFB: + value->rValue = model->BSIM3lvfb; + return(OK); + + case BSIM3_MOD_LELM: + value->rValue = model->BSIM3lelm; + return(OK); + case BSIM3_MOD_LCGSL: + value->rValue = model->BSIM3lcgsl; + return(OK); + case BSIM3_MOD_LCGDL: + value->rValue = model->BSIM3lcgdl; + return(OK); + case BSIM3_MOD_LCKAPPA: + value->rValue = model->BSIM3lckappa; + return(OK); + case BSIM3_MOD_LCF: + value->rValue = model->BSIM3lcf; + return(OK); + case BSIM3_MOD_LCLC: + value->rValue = model->BSIM3lclc; + return(OK); + case BSIM3_MOD_LCLE: + value->rValue = model->BSIM3lcle; + return(OK); + case BSIM3_MOD_LVFBCV: + value->rValue = model->BSIM3lvfbcv; + return(OK); + case BSIM3_MOD_LACDE: + value->rValue = model->BSIM3lacde; + return(OK); + case BSIM3_MOD_LMOIN: + value->rValue = model->BSIM3lmoin; + return(OK); + case BSIM3_MOD_LNOFF: + value->rValue = model->BSIM3lnoff; + return(OK); + case BSIM3_MOD_LVOFFCV: + value->rValue = model->BSIM3lvoffcv; + return(OK); + + /* Width dependence */ + case BSIM3_MOD_WCDSC : + value->rValue = model->BSIM3wcdsc; + return(OK); + case BSIM3_MOD_WCDSCB : + value->rValue = model->BSIM3wcdscb; + return(OK); + case BSIM3_MOD_WCDSCD : + value->rValue = model->BSIM3wcdscd; + return(OK); + case BSIM3_MOD_WCIT : + value->rValue = model->BSIM3wcit; + return(OK); + case BSIM3_MOD_WNFACTOR : + value->rValue = model->BSIM3wnfactor; + return(OK); + case BSIM3_MOD_WXJ: + value->rValue = model->BSIM3wxj; + return(OK); + case BSIM3_MOD_WVSAT: + value->rValue = model->BSIM3wvsat; + return(OK); + case BSIM3_MOD_WAT: + value->rValue = model->BSIM3wat; + return(OK); + case BSIM3_MOD_WA0: + value->rValue = model->BSIM3wa0; + return(OK); + case BSIM3_MOD_WAGS: + value->rValue = model->BSIM3wags; + return(OK); + case BSIM3_MOD_WA1: + value->rValue = model->BSIM3wa1; + return(OK); + case BSIM3_MOD_WA2: + value->rValue = model->BSIM3wa2; + return(OK); + case BSIM3_MOD_WKETA: + value->rValue = model->BSIM3wketa; + return(OK); + case BSIM3_MOD_WNSUB: + value->rValue = model->BSIM3wnsub; + return(OK); + case BSIM3_MOD_WNPEAK: + value->rValue = model->BSIM3wnpeak; + return(OK); + case BSIM3_MOD_WNGATE: + value->rValue = model->BSIM3wngate; + return(OK); + case BSIM3_MOD_WGAMMA1: + value->rValue = model->BSIM3wgamma1; + return(OK); + case BSIM3_MOD_WGAMMA2: + value->rValue = model->BSIM3wgamma2; + return(OK); + case BSIM3_MOD_WVBX: + value->rValue = model->BSIM3wvbx; + return(OK); + case BSIM3_MOD_WVBM: + value->rValue = model->BSIM3wvbm; + return(OK); + case BSIM3_MOD_WXT: + value->rValue = model->BSIM3wxt; + return(OK); + case BSIM3_MOD_WK1: + value->rValue = model->BSIM3wk1; + return(OK); + case BSIM3_MOD_WKT1: + value->rValue = model->BSIM3wkt1; + return(OK); + case BSIM3_MOD_WKT1L: + value->rValue = model->BSIM3wkt1l; + return(OK); + case BSIM3_MOD_WKT2 : + value->rValue = model->BSIM3wkt2; + return(OK); + case BSIM3_MOD_WK2 : + value->rValue = model->BSIM3wk2; + return(OK); + case BSIM3_MOD_WK3: + value->rValue = model->BSIM3wk3; + return(OK); + case BSIM3_MOD_WK3B: + value->rValue = model->BSIM3wk3b; + return(OK); + case BSIM3_MOD_WW0: + value->rValue = model->BSIM3ww0; + return(OK); + case BSIM3_MOD_WNLX: + value->rValue = model->BSIM3wnlx; + return(OK); + case BSIM3_MOD_WDVT0: + value->rValue = model->BSIM3wdvt0; + return(OK); + case BSIM3_MOD_WDVT1 : + value->rValue = model->BSIM3wdvt1; + return(OK); + case BSIM3_MOD_WDVT2 : + value->rValue = model->BSIM3wdvt2; + return(OK); + case BSIM3_MOD_WDVT0W : + value->rValue = model->BSIM3wdvt0w; + return(OK); + case BSIM3_MOD_WDVT1W : + value->rValue = model->BSIM3wdvt1w; + return(OK); + case BSIM3_MOD_WDVT2W : + value->rValue = model->BSIM3wdvt2w; + return(OK); + case BSIM3_MOD_WDROUT : + value->rValue = model->BSIM3wdrout; + return(OK); + case BSIM3_MOD_WDSUB : + value->rValue = model->BSIM3wdsub; + return(OK); + case BSIM3_MOD_WVTH0: + value->rValue = model->BSIM3wvth0; + return(OK); + case BSIM3_MOD_WUA: + value->rValue = model->BSIM3wua; + return(OK); + case BSIM3_MOD_WUA1: + value->rValue = model->BSIM3wua1; + return(OK); + case BSIM3_MOD_WUB: + value->rValue = model->BSIM3wub; + return(OK); + case BSIM3_MOD_WUB1: + value->rValue = model->BSIM3wub1; + return(OK); + case BSIM3_MOD_WUC: + value->rValue = model->BSIM3wuc; + return(OK); + case BSIM3_MOD_WUC1: + value->rValue = model->BSIM3wuc1; + return(OK); + case BSIM3_MOD_WU0: + value->rValue = model->BSIM3wu0; + return(OK); + case BSIM3_MOD_WUTE: + value->rValue = model->BSIM3wute; + return(OK); + case BSIM3_MOD_WVOFF: + value->rValue = model->BSIM3wvoff; + return(OK); + case BSIM3_MOD_WDELTA: + value->rValue = model->BSIM3wdelta; + return(OK); + case BSIM3_MOD_WRDSW: + value->rValue = model->BSIM3wrdsw; + return(OK); + case BSIM3_MOD_WPRWB: + value->rValue = model->BSIM3wprwb; + return(OK); + case BSIM3_MOD_WPRWG: + value->rValue = model->BSIM3wprwg; + return(OK); + case BSIM3_MOD_WPRT: + value->rValue = model->BSIM3wprt; + return(OK); + case BSIM3_MOD_WETA0: + value->rValue = model->BSIM3weta0; + return(OK); + case BSIM3_MOD_WETAB: + value->rValue = model->BSIM3wetab; + return(OK); + case BSIM3_MOD_WPCLM: + value->rValue = model->BSIM3wpclm; + return(OK); + case BSIM3_MOD_WPDIBL1: + value->rValue = model->BSIM3wpdibl1; + return(OK); + case BSIM3_MOD_WPDIBL2: + value->rValue = model->BSIM3wpdibl2; + return(OK); + case BSIM3_MOD_WPDIBLB: + value->rValue = model->BSIM3wpdiblb; + return(OK); + case BSIM3_MOD_WPSCBE1: + value->rValue = model->BSIM3wpscbe1; + return(OK); + case BSIM3_MOD_WPSCBE2: + value->rValue = model->BSIM3wpscbe2; + return(OK); + case BSIM3_MOD_WPVAG: + value->rValue = model->BSIM3wpvag; + return(OK); + case BSIM3_MOD_WWR: + value->rValue = model->BSIM3wwr; + return(OK); + case BSIM3_MOD_WDWG: + value->rValue = model->BSIM3wdwg; + return(OK); + case BSIM3_MOD_WDWB: + value->rValue = model->BSIM3wdwb; + return(OK); + case BSIM3_MOD_WB0: + value->rValue = model->BSIM3wb0; + return(OK); + case BSIM3_MOD_WB1: + value->rValue = model->BSIM3wb1; + return(OK); + case BSIM3_MOD_WALPHA0: + value->rValue = model->BSIM3walpha0; + return(OK); + case BSIM3_MOD_WALPHA1: + value->rValue = model->BSIM3walpha1; + return(OK); + case BSIM3_MOD_WBETA0: + value->rValue = model->BSIM3wbeta0; + return(OK); + case BSIM3_MOD_WVFB: + value->rValue = model->BSIM3wvfb; + return(OK); + + case BSIM3_MOD_WELM: + value->rValue = model->BSIM3welm; + return(OK); + case BSIM3_MOD_WCGSL: + value->rValue = model->BSIM3wcgsl; + return(OK); + case BSIM3_MOD_WCGDL: + value->rValue = model->BSIM3wcgdl; + return(OK); + case BSIM3_MOD_WCKAPPA: + value->rValue = model->BSIM3wckappa; + return(OK); + case BSIM3_MOD_WCF: + value->rValue = model->BSIM3wcf; + return(OK); + case BSIM3_MOD_WCLC: + value->rValue = model->BSIM3wclc; + return(OK); + case BSIM3_MOD_WCLE: + value->rValue = model->BSIM3wcle; + return(OK); + case BSIM3_MOD_WVFBCV: + value->rValue = model->BSIM3wvfbcv; + return(OK); + case BSIM3_MOD_WACDE: + value->rValue = model->BSIM3wacde; + return(OK); + case BSIM3_MOD_WMOIN: + value->rValue = model->BSIM3wmoin; + return(OK); + case BSIM3_MOD_WNOFF: + value->rValue = model->BSIM3wnoff; + return(OK); + case BSIM3_MOD_WVOFFCV: + value->rValue = model->BSIM3wvoffcv; + return(OK); + + /* Cross-term dependence */ + case BSIM3_MOD_PCDSC : + value->rValue = model->BSIM3pcdsc; + return(OK); + case BSIM3_MOD_PCDSCB : + value->rValue = model->BSIM3pcdscb; + return(OK); + case BSIM3_MOD_PCDSCD : + value->rValue = model->BSIM3pcdscd; + return(OK); + case BSIM3_MOD_PCIT : + value->rValue = model->BSIM3pcit; + return(OK); + case BSIM3_MOD_PNFACTOR : + value->rValue = model->BSIM3pnfactor; + return(OK); + case BSIM3_MOD_PXJ: + value->rValue = model->BSIM3pxj; + return(OK); + case BSIM3_MOD_PVSAT: + value->rValue = model->BSIM3pvsat; + return(OK); + case BSIM3_MOD_PAT: + value->rValue = model->BSIM3pat; + return(OK); + case BSIM3_MOD_PA0: + value->rValue = model->BSIM3pa0; + return(OK); + case BSIM3_MOD_PAGS: + value->rValue = model->BSIM3pags; + return(OK); + case BSIM3_MOD_PA1: + value->rValue = model->BSIM3pa1; + return(OK); + case BSIM3_MOD_PA2: + value->rValue = model->BSIM3pa2; + return(OK); + case BSIM3_MOD_PKETA: + value->rValue = model->BSIM3pketa; + return(OK); + case BSIM3_MOD_PNSUB: + value->rValue = model->BSIM3pnsub; + return(OK); + case BSIM3_MOD_PNPEAK: + value->rValue = model->BSIM3pnpeak; + return(OK); + case BSIM3_MOD_PNGATE: + value->rValue = model->BSIM3pngate; + return(OK); + case BSIM3_MOD_PGAMMA1: + value->rValue = model->BSIM3pgamma1; + return(OK); + case BSIM3_MOD_PGAMMA2: + value->rValue = model->BSIM3pgamma2; + return(OK); + case BSIM3_MOD_PVBX: + value->rValue = model->BSIM3pvbx; + return(OK); + case BSIM3_MOD_PVBM: + value->rValue = model->BSIM3pvbm; + return(OK); + case BSIM3_MOD_PXT: + value->rValue = model->BSIM3pxt; + return(OK); + case BSIM3_MOD_PK1: + value->rValue = model->BSIM3pk1; + return(OK); + case BSIM3_MOD_PKT1: + value->rValue = model->BSIM3pkt1; + return(OK); + case BSIM3_MOD_PKT1L: + value->rValue = model->BSIM3pkt1l; + return(OK); + case BSIM3_MOD_PKT2 : + value->rValue = model->BSIM3pkt2; + return(OK); + case BSIM3_MOD_PK2 : + value->rValue = model->BSIM3pk2; + return(OK); + case BSIM3_MOD_PK3: + value->rValue = model->BSIM3pk3; + return(OK); + case BSIM3_MOD_PK3B: + value->rValue = model->BSIM3pk3b; + return(OK); + case BSIM3_MOD_PW0: + value->rValue = model->BSIM3pw0; + return(OK); + case BSIM3_MOD_PNLX: + value->rValue = model->BSIM3pnlx; + return(OK); + case BSIM3_MOD_PDVT0 : + value->rValue = model->BSIM3pdvt0; + return(OK); + case BSIM3_MOD_PDVT1 : + value->rValue = model->BSIM3pdvt1; + return(OK); + case BSIM3_MOD_PDVT2 : + value->rValue = model->BSIM3pdvt2; + return(OK); + case BSIM3_MOD_PDVT0W : + value->rValue = model->BSIM3pdvt0w; + return(OK); + case BSIM3_MOD_PDVT1W : + value->rValue = model->BSIM3pdvt1w; + return(OK); + case BSIM3_MOD_PDVT2W : + value->rValue = model->BSIM3pdvt2w; + return(OK); + case BSIM3_MOD_PDROUT : + value->rValue = model->BSIM3pdrout; + return(OK); + case BSIM3_MOD_PDSUB : + value->rValue = model->BSIM3pdsub; + return(OK); + case BSIM3_MOD_PVTH0: + value->rValue = model->BSIM3pvth0; + return(OK); + case BSIM3_MOD_PUA: + value->rValue = model->BSIM3pua; + return(OK); + case BSIM3_MOD_PUA1: + value->rValue = model->BSIM3pua1; + return(OK); + case BSIM3_MOD_PUB: + value->rValue = model->BSIM3pub; + return(OK); + case BSIM3_MOD_PUB1: + value->rValue = model->BSIM3pub1; + return(OK); + case BSIM3_MOD_PUC: + value->rValue = model->BSIM3puc; + return(OK); + case BSIM3_MOD_PUC1: + value->rValue = model->BSIM3puc1; + return(OK); + case BSIM3_MOD_PU0: + value->rValue = model->BSIM3pu0; + return(OK); + case BSIM3_MOD_PUTE: + value->rValue = model->BSIM3pute; + return(OK); + case BSIM3_MOD_PVOFF: + value->rValue = model->BSIM3pvoff; + return(OK); + case BSIM3_MOD_PDELTA: + value->rValue = model->BSIM3pdelta; + return(OK); + case BSIM3_MOD_PRDSW: + value->rValue = model->BSIM3prdsw; + return(OK); + case BSIM3_MOD_PPRWB: + value->rValue = model->BSIM3pprwb; + return(OK); + case BSIM3_MOD_PPRWG: + value->rValue = model->BSIM3pprwg; + return(OK); + case BSIM3_MOD_PPRT: + value->rValue = model->BSIM3pprt; + return(OK); + case BSIM3_MOD_PETA0: + value->rValue = model->BSIM3peta0; + return(OK); + case BSIM3_MOD_PETAB: + value->rValue = model->BSIM3petab; + return(OK); + case BSIM3_MOD_PPCLM: + value->rValue = model->BSIM3ppclm; + return(OK); + case BSIM3_MOD_PPDIBL1: + value->rValue = model->BSIM3ppdibl1; + return(OK); + case BSIM3_MOD_PPDIBL2: + value->rValue = model->BSIM3ppdibl2; + return(OK); + case BSIM3_MOD_PPDIBLB: + value->rValue = model->BSIM3ppdiblb; + return(OK); + case BSIM3_MOD_PPSCBE1: + value->rValue = model->BSIM3ppscbe1; + return(OK); + case BSIM3_MOD_PPSCBE2: + value->rValue = model->BSIM3ppscbe2; + return(OK); + case BSIM3_MOD_PPVAG: + value->rValue = model->BSIM3ppvag; + return(OK); + case BSIM3_MOD_PWR: + value->rValue = model->BSIM3pwr; + return(OK); + case BSIM3_MOD_PDWG: + value->rValue = model->BSIM3pdwg; + return(OK); + case BSIM3_MOD_PDWB: + value->rValue = model->BSIM3pdwb; + return(OK); + case BSIM3_MOD_PB0: + value->rValue = model->BSIM3pb0; + return(OK); + case BSIM3_MOD_PB1: + value->rValue = model->BSIM3pb1; + return(OK); + case BSIM3_MOD_PALPHA0: + value->rValue = model->BSIM3palpha0; + return(OK); + case BSIM3_MOD_PALPHA1: + value->rValue = model->BSIM3palpha1; + return(OK); + case BSIM3_MOD_PBETA0: + value->rValue = model->BSIM3pbeta0; + return(OK); + case BSIM3_MOD_PVFB: + value->rValue = model->BSIM3pvfb; + return(OK); + + case BSIM3_MOD_PELM: + value->rValue = model->BSIM3pelm; + return(OK); + case BSIM3_MOD_PCGSL: + value->rValue = model->BSIM3pcgsl; + return(OK); + case BSIM3_MOD_PCGDL: + value->rValue = model->BSIM3pcgdl; + return(OK); + case BSIM3_MOD_PCKAPPA: + value->rValue = model->BSIM3pckappa; + return(OK); + case BSIM3_MOD_PCF: + value->rValue = model->BSIM3pcf; + return(OK); + case BSIM3_MOD_PCLC: + value->rValue = model->BSIM3pclc; + return(OK); + case BSIM3_MOD_PCLE: + value->rValue = model->BSIM3pcle; + return(OK); + case BSIM3_MOD_PVFBCV: + value->rValue = model->BSIM3pvfbcv; + return(OK); + case BSIM3_MOD_PACDE: + value->rValue = model->BSIM3pacde; + return(OK); + case BSIM3_MOD_PMOIN: + value->rValue = model->BSIM3pmoin; + return(OK); + case BSIM3_MOD_PNOFF: + value->rValue = model->BSIM3pnoff; + return(OK); + case BSIM3_MOD_PVOFFCV: + value->rValue = model->BSIM3pvoffcv; + return(OK); + + case BSIM3_MOD_TNOM : + value->rValue = model->BSIM3tnom; + return(OK); + case BSIM3_MOD_CGSO: + value->rValue = model->BSIM3cgso; + return(OK); + case BSIM3_MOD_CGDO: + value->rValue = model->BSIM3cgdo; + return(OK); + case BSIM3_MOD_CGBO: + value->rValue = model->BSIM3cgbo; + return(OK); + case BSIM3_MOD_XPART: + value->rValue = model->BSIM3xpart; + return(OK); + case BSIM3_MOD_RSH: + value->rValue = model->BSIM3sheetResistance; + return(OK); + case BSIM3_MOD_JS: + value->rValue = model->BSIM3jctSatCurDensity; + return(OK); + case BSIM3_MOD_JSW: + value->rValue = model->BSIM3jctSidewallSatCurDensity; + return(OK); + case BSIM3_MOD_PB: + value->rValue = model->BSIM3bulkJctPotential; + return(OK); + case BSIM3_MOD_MJ: + value->rValue = model->BSIM3bulkJctBotGradingCoeff; + return(OK); + case BSIM3_MOD_PBSW: + value->rValue = model->BSIM3sidewallJctPotential; + return(OK); + case BSIM3_MOD_MJSW: + value->rValue = model->BSIM3bulkJctSideGradingCoeff; + return(OK); + case BSIM3_MOD_CJ: + value->rValue = model->BSIM3unitAreaJctCap; + return(OK); + case BSIM3_MOD_CJSW: + value->rValue = model->BSIM3unitLengthSidewallJctCap; + return(OK); + case BSIM3_MOD_PBSWG: + value->rValue = model->BSIM3GatesidewallJctPotential; + return(OK); + case BSIM3_MOD_MJSWG: + value->rValue = model->BSIM3bulkJctGateSideGradingCoeff; + return(OK); + case BSIM3_MOD_CJSWG: + value->rValue = model->BSIM3unitLengthGateSidewallJctCap; + return(OK); + case BSIM3_MOD_NJ: + value->rValue = model->BSIM3jctEmissionCoeff; + return(OK); + case BSIM3_MOD_XTI: + value->rValue = model->BSIM3jctTempExponent; + return(OK); + case BSIM3_MOD_LINT: + value->rValue = model->BSIM3Lint; + return(OK); + case BSIM3_MOD_LL: + value->rValue = model->BSIM3Ll; + return(OK); + case BSIM3_MOD_LLC: + value->rValue = model->BSIM3Llc; + return(OK); + case BSIM3_MOD_LLN: + value->rValue = model->BSIM3Lln; + return(OK); + case BSIM3_MOD_LW: + value->rValue = model->BSIM3Lw; + return(OK); + case BSIM3_MOD_LWC: + value->rValue = model->BSIM3Lwc; + return(OK); + case BSIM3_MOD_LWN: + value->rValue = model->BSIM3Lwn; + return(OK); + case BSIM3_MOD_LWL: + value->rValue = model->BSIM3Lwl; + return(OK); + case BSIM3_MOD_LWLC: + value->rValue = model->BSIM3Lwlc; + return(OK); + case BSIM3_MOD_LMIN: + value->rValue = model->BSIM3Lmin; + return(OK); + case BSIM3_MOD_LMAX: + value->rValue = model->BSIM3Lmax; + return(OK); + case BSIM3_MOD_WINT: + value->rValue = model->BSIM3Wint; + return(OK); + case BSIM3_MOD_WL: + value->rValue = model->BSIM3Wl; + return(OK); + case BSIM3_MOD_WLC: + value->rValue = model->BSIM3Wlc; + return(OK); + case BSIM3_MOD_WLN: + value->rValue = model->BSIM3Wln; + return(OK); + case BSIM3_MOD_WW: + value->rValue = model->BSIM3Ww; + return(OK); + case BSIM3_MOD_WWC: + value->rValue = model->BSIM3Wwc; + return(OK); + case BSIM3_MOD_WWN: + value->rValue = model->BSIM3Wwn; + return(OK); + case BSIM3_MOD_WWL: + value->rValue = model->BSIM3Wwl; + return(OK); + case BSIM3_MOD_WWLC: + value->rValue = model->BSIM3Wwlc; + return(OK); + case BSIM3_MOD_WMIN: + value->rValue = model->BSIM3Wmin; + return(OK); + case BSIM3_MOD_WMAX: + value->rValue = model->BSIM3Wmax; + return(OK); + case BSIM3_MOD_NOIA: + value->rValue = model->BSIM3oxideTrapDensityA; + return(OK); + case BSIM3_MOD_NOIB: + value->rValue = model->BSIM3oxideTrapDensityB; + return(OK); + case BSIM3_MOD_NOIC: + value->rValue = model->BSIM3oxideTrapDensityC; + return(OK); + case BSIM3_MOD_EM: + value->rValue = model->BSIM3em; + return(OK); + case BSIM3_MOD_EF: + value->rValue = model->BSIM3ef; + return(OK); + case BSIM3_MOD_AF: + value->rValue = model->BSIM3af; + return(OK); + case BSIM3_MOD_KF: + value->rValue = model->BSIM3kf; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + + + diff --git a/src/spicelib/devices/bsim3/b3mdel.c b/src/spicelib/devices/bsim3/b3mdel.c new file mode 100644 index 000000000..3d4d535d1 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3mdel.c @@ -0,0 +1,70 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3mdel.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3mDelete(inModel,modname,kill) +GENmodel **inModel; +IFuid modname; +GENmodel *kill; +{ +BSIM3model **model = (BSIM3model**)inModel; +BSIM3model *modfast = (BSIM3model*)kill; +BSIM3instance *here; +BSIM3instance *prev = NULL; +BSIM3model **oldmod; + + oldmod = model; + for (; *model ; model = &((*model)->BSIM3nextModel)) + { if ((*model)->BSIM3modName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->BSIM3nextModel; /* cut deleted device out of list */ + for (here = (*model)->BSIM3instances; here; here = here->BSIM3nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3/b3mpar.c b/src/spicelib/devices/bsim3/b3mpar.c new file mode 100644 index 000000000..897a0dc7b --- /dev/null +++ b/src/spicelib/devices/bsim3/b3mpar.c @@ -0,0 +1,1698 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3mpar.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3def.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3mParam(param,value,inMod) +int param; +IFvalue *value; +GENmodel *inMod; +{ + BSIM3model *mod = (BSIM3model*)inMod; + switch(param) + { case BSIM3_MOD_MOBMOD : + mod->BSIM3mobMod = value->iValue; + mod->BSIM3mobModGiven = TRUE; + break; + case BSIM3_MOD_BINUNIT : + mod->BSIM3binUnit = value->iValue; + mod->BSIM3binUnitGiven = TRUE; + break; + case BSIM3_MOD_PARAMCHK : + mod->BSIM3paramChk = value->iValue; + mod->BSIM3paramChkGiven = TRUE; + break; + case BSIM3_MOD_CAPMOD : + mod->BSIM3capMod = value->iValue; + mod->BSIM3capModGiven = TRUE; + break; + case BSIM3_MOD_NOIMOD : + mod->BSIM3noiMod = value->iValue; + mod->BSIM3noiModGiven = TRUE; + break; + case BSIM3_MOD_VERSION : + mod->BSIM3version = value->sValue; + mod->BSIM3versionGiven = TRUE; + break; + case BSIM3_MOD_TOX : + mod->BSIM3tox = value->rValue; + mod->BSIM3toxGiven = TRUE; + break; + case BSIM3_MOD_TOXM : + mod->BSIM3toxm = value->rValue; + mod->BSIM3toxmGiven = TRUE; + break; + + case BSIM3_MOD_CDSC : + mod->BSIM3cdsc = value->rValue; + mod->BSIM3cdscGiven = TRUE; + break; + case BSIM3_MOD_CDSCB : + mod->BSIM3cdscb = value->rValue; + mod->BSIM3cdscbGiven = TRUE; + break; + + case BSIM3_MOD_CDSCD : + mod->BSIM3cdscd = value->rValue; + mod->BSIM3cdscdGiven = TRUE; + break; + + case BSIM3_MOD_CIT : + mod->BSIM3cit = value->rValue; + mod->BSIM3citGiven = TRUE; + break; + case BSIM3_MOD_NFACTOR : + mod->BSIM3nfactor = value->rValue; + mod->BSIM3nfactorGiven = TRUE; + break; + case BSIM3_MOD_XJ: + mod->BSIM3xj = value->rValue; + mod->BSIM3xjGiven = TRUE; + break; + case BSIM3_MOD_VSAT: + mod->BSIM3vsat = value->rValue; + mod->BSIM3vsatGiven = TRUE; + break; + case BSIM3_MOD_A0: + mod->BSIM3a0 = value->rValue; + mod->BSIM3a0Given = TRUE; + break; + + case BSIM3_MOD_AGS: + mod->BSIM3ags= value->rValue; + mod->BSIM3agsGiven = TRUE; + break; + + case BSIM3_MOD_A1: + mod->BSIM3a1 = value->rValue; + mod->BSIM3a1Given = TRUE; + break; + case BSIM3_MOD_A2: + mod->BSIM3a2 = value->rValue; + mod->BSIM3a2Given = TRUE; + break; + case BSIM3_MOD_AT: + mod->BSIM3at = value->rValue; + mod->BSIM3atGiven = TRUE; + break; + case BSIM3_MOD_KETA: + mod->BSIM3keta = value->rValue; + mod->BSIM3ketaGiven = TRUE; + break; + case BSIM3_MOD_NSUB: + mod->BSIM3nsub = value->rValue; + mod->BSIM3nsubGiven = TRUE; + break; + case BSIM3_MOD_NPEAK: + mod->BSIM3npeak = value->rValue; + mod->BSIM3npeakGiven = TRUE; + if (mod->BSIM3npeak > 1.0e20) + mod->BSIM3npeak *= 1.0e-6; + break; + case BSIM3_MOD_NGATE: + mod->BSIM3ngate = value->rValue; + mod->BSIM3ngateGiven = TRUE; + if (mod->BSIM3ngate > 1.0e23) + mod->BSIM3ngate *= 1.0e-6; + break; + case BSIM3_MOD_GAMMA1: + mod->BSIM3gamma1 = value->rValue; + mod->BSIM3gamma1Given = TRUE; + break; + case BSIM3_MOD_GAMMA2: + mod->BSIM3gamma2 = value->rValue; + mod->BSIM3gamma2Given = TRUE; + break; + case BSIM3_MOD_VBX: + mod->BSIM3vbx = value->rValue; + mod->BSIM3vbxGiven = TRUE; + break; + case BSIM3_MOD_VBM: + mod->BSIM3vbm = value->rValue; + mod->BSIM3vbmGiven = TRUE; + break; + case BSIM3_MOD_XT: + mod->BSIM3xt = value->rValue; + mod->BSIM3xtGiven = TRUE; + break; + case BSIM3_MOD_K1: + mod->BSIM3k1 = value->rValue; + mod->BSIM3k1Given = TRUE; + break; + case BSIM3_MOD_KT1: + mod->BSIM3kt1 = value->rValue; + mod->BSIM3kt1Given = TRUE; + break; + case BSIM3_MOD_KT1L: + mod->BSIM3kt1l = value->rValue; + mod->BSIM3kt1lGiven = TRUE; + break; + case BSIM3_MOD_KT2: + mod->BSIM3kt2 = value->rValue; + mod->BSIM3kt2Given = TRUE; + break; + case BSIM3_MOD_K2: + mod->BSIM3k2 = value->rValue; + mod->BSIM3k2Given = TRUE; + break; + case BSIM3_MOD_K3: + mod->BSIM3k3 = value->rValue; + mod->BSIM3k3Given = TRUE; + break; + case BSIM3_MOD_K3B: + mod->BSIM3k3b = value->rValue; + mod->BSIM3k3bGiven = TRUE; + break; + case BSIM3_MOD_NLX: + mod->BSIM3nlx = value->rValue; + mod->BSIM3nlxGiven = TRUE; + break; + case BSIM3_MOD_W0: + mod->BSIM3w0 = value->rValue; + mod->BSIM3w0Given = TRUE; + break; + case BSIM3_MOD_DVT0: + mod->BSIM3dvt0 = value->rValue; + mod->BSIM3dvt0Given = TRUE; + break; + case BSIM3_MOD_DVT1: + mod->BSIM3dvt1 = value->rValue; + mod->BSIM3dvt1Given = TRUE; + break; + case BSIM3_MOD_DVT2: + mod->BSIM3dvt2 = value->rValue; + mod->BSIM3dvt2Given = TRUE; + break; + case BSIM3_MOD_DVT0W: + mod->BSIM3dvt0w = value->rValue; + mod->BSIM3dvt0wGiven = TRUE; + break; + case BSIM3_MOD_DVT1W: + mod->BSIM3dvt1w = value->rValue; + mod->BSIM3dvt1wGiven = TRUE; + break; + case BSIM3_MOD_DVT2W: + mod->BSIM3dvt2w = value->rValue; + mod->BSIM3dvt2wGiven = TRUE; + break; + case BSIM3_MOD_DROUT: + mod->BSIM3drout = value->rValue; + mod->BSIM3droutGiven = TRUE; + break; + case BSIM3_MOD_DSUB: + mod->BSIM3dsub = value->rValue; + mod->BSIM3dsubGiven = TRUE; + break; + case BSIM3_MOD_VTH0: + mod->BSIM3vth0 = value->rValue; + mod->BSIM3vth0Given = TRUE; + break; + case BSIM3_MOD_UA: + mod->BSIM3ua = value->rValue; + mod->BSIM3uaGiven = TRUE; + break; + case BSIM3_MOD_UA1: + mod->BSIM3ua1 = value->rValue; + mod->BSIM3ua1Given = TRUE; + break; + case BSIM3_MOD_UB: + mod->BSIM3ub = value->rValue; + mod->BSIM3ubGiven = TRUE; + break; + case BSIM3_MOD_UB1: + mod->BSIM3ub1 = value->rValue; + mod->BSIM3ub1Given = TRUE; + break; + case BSIM3_MOD_UC: + mod->BSIM3uc = value->rValue; + mod->BSIM3ucGiven = TRUE; + break; + case BSIM3_MOD_UC1: + mod->BSIM3uc1 = value->rValue; + mod->BSIM3uc1Given = TRUE; + break; + case BSIM3_MOD_U0 : + mod->BSIM3u0 = value->rValue; + mod->BSIM3u0Given = TRUE; + break; + case BSIM3_MOD_UTE : + mod->BSIM3ute = value->rValue; + mod->BSIM3uteGiven = TRUE; + break; + case BSIM3_MOD_VOFF: + mod->BSIM3voff = value->rValue; + mod->BSIM3voffGiven = TRUE; + break; + case BSIM3_MOD_DELTA : + mod->BSIM3delta = value->rValue; + mod->BSIM3deltaGiven = TRUE; + break; + case BSIM3_MOD_RDSW: + mod->BSIM3rdsw = value->rValue; + mod->BSIM3rdswGiven = TRUE; + break; + case BSIM3_MOD_PRWG: + mod->BSIM3prwg = value->rValue; + mod->BSIM3prwgGiven = TRUE; + break; + case BSIM3_MOD_PRWB: + mod->BSIM3prwb = value->rValue; + mod->BSIM3prwbGiven = TRUE; + break; + case BSIM3_MOD_PRT: + mod->BSIM3prt = value->rValue; + mod->BSIM3prtGiven = TRUE; + break; + case BSIM3_MOD_ETA0: + mod->BSIM3eta0 = value->rValue; + mod->BSIM3eta0Given = TRUE; + break; + case BSIM3_MOD_ETAB: + mod->BSIM3etab = value->rValue; + mod->BSIM3etabGiven = TRUE; + break; + case BSIM3_MOD_PCLM: + mod->BSIM3pclm = value->rValue; + mod->BSIM3pclmGiven = TRUE; + break; + case BSIM3_MOD_PDIBL1: + mod->BSIM3pdibl1 = value->rValue; + mod->BSIM3pdibl1Given = TRUE; + break; + case BSIM3_MOD_PDIBL2: + mod->BSIM3pdibl2 = value->rValue; + mod->BSIM3pdibl2Given = TRUE; + break; + case BSIM3_MOD_PDIBLB: + mod->BSIM3pdiblb = value->rValue; + mod->BSIM3pdiblbGiven = TRUE; + break; + case BSIM3_MOD_PSCBE1: + mod->BSIM3pscbe1 = value->rValue; + mod->BSIM3pscbe1Given = TRUE; + break; + case BSIM3_MOD_PSCBE2: + mod->BSIM3pscbe2 = value->rValue; + mod->BSIM3pscbe2Given = TRUE; + break; + case BSIM3_MOD_PVAG: + mod->BSIM3pvag = value->rValue; + mod->BSIM3pvagGiven = TRUE; + break; + case BSIM3_MOD_WR : + mod->BSIM3wr = value->rValue; + mod->BSIM3wrGiven = TRUE; + break; + case BSIM3_MOD_DWG : + mod->BSIM3dwg = value->rValue; + mod->BSIM3dwgGiven = TRUE; + break; + case BSIM3_MOD_DWB : + mod->BSIM3dwb = value->rValue; + mod->BSIM3dwbGiven = TRUE; + break; + case BSIM3_MOD_B0 : + mod->BSIM3b0 = value->rValue; + mod->BSIM3b0Given = TRUE; + break; + case BSIM3_MOD_B1 : + mod->BSIM3b1 = value->rValue; + mod->BSIM3b1Given = TRUE; + break; + case BSIM3_MOD_ALPHA0 : + mod->BSIM3alpha0 = value->rValue; + mod->BSIM3alpha0Given = TRUE; + break; + case BSIM3_MOD_ALPHA1 : + mod->BSIM3alpha1 = value->rValue; + mod->BSIM3alpha1Given = TRUE; + break; + case BSIM3_MOD_BETA0 : + mod->BSIM3beta0 = value->rValue; + mod->BSIM3beta0Given = TRUE; + break; + case BSIM3_MOD_IJTH : + mod->BSIM3ijth = value->rValue; + mod->BSIM3ijthGiven = TRUE; + break; + case BSIM3_MOD_VFB : + mod->BSIM3vfb = value->rValue; + mod->BSIM3vfbGiven = TRUE; + break; + + case BSIM3_MOD_ELM : + mod->BSIM3elm = value->rValue; + mod->BSIM3elmGiven = TRUE; + break; + case BSIM3_MOD_CGSL : + mod->BSIM3cgsl = value->rValue; + mod->BSIM3cgslGiven = TRUE; + break; + case BSIM3_MOD_CGDL : + mod->BSIM3cgdl = value->rValue; + mod->BSIM3cgdlGiven = TRUE; + break; + case BSIM3_MOD_CKAPPA : + mod->BSIM3ckappa = value->rValue; + mod->BSIM3ckappaGiven = TRUE; + break; + case BSIM3_MOD_CF : + mod->BSIM3cf = value->rValue; + mod->BSIM3cfGiven = TRUE; + break; + case BSIM3_MOD_CLC : + mod->BSIM3clc = value->rValue; + mod->BSIM3clcGiven = TRUE; + break; + case BSIM3_MOD_CLE : + mod->BSIM3cle = value->rValue; + mod->BSIM3cleGiven = TRUE; + break; + case BSIM3_MOD_DWC : + mod->BSIM3dwc = value->rValue; + mod->BSIM3dwcGiven = TRUE; + break; + case BSIM3_MOD_DLC : + mod->BSIM3dlc = value->rValue; + mod->BSIM3dlcGiven = TRUE; + break; + case BSIM3_MOD_VFBCV : + mod->BSIM3vfbcv = value->rValue; + mod->BSIM3vfbcvGiven = TRUE; + break; + case BSIM3_MOD_ACDE : + mod->BSIM3acde = value->rValue; + mod->BSIM3acdeGiven = TRUE; + break; + case BSIM3_MOD_MOIN : + mod->BSIM3moin = value->rValue; + mod->BSIM3moinGiven = TRUE; + break; + case BSIM3_MOD_NOFF : + mod->BSIM3noff = value->rValue; + mod->BSIM3noffGiven = TRUE; + break; + case BSIM3_MOD_VOFFCV : + mod->BSIM3voffcv = value->rValue; + mod->BSIM3voffcvGiven = TRUE; + break; + case BSIM3_MOD_TCJ : + mod->BSIM3tcj = value->rValue; + mod->BSIM3tcjGiven = TRUE; + break; + case BSIM3_MOD_TPB : + mod->BSIM3tpb = value->rValue; + mod->BSIM3tpbGiven = TRUE; + break; + case BSIM3_MOD_TCJSW : + mod->BSIM3tcjsw = value->rValue; + mod->BSIM3tcjswGiven = TRUE; + break; + case BSIM3_MOD_TPBSW : + mod->BSIM3tpbsw = value->rValue; + mod->BSIM3tpbswGiven = TRUE; + break; + case BSIM3_MOD_TCJSWG : + mod->BSIM3tcjswg = value->rValue; + mod->BSIM3tcjswgGiven = TRUE; + break; + case BSIM3_MOD_TPBSWG : + mod->BSIM3tpbswg = value->rValue; + mod->BSIM3tpbswgGiven = TRUE; + break; + + /* Length dependence */ + case BSIM3_MOD_LCDSC : + mod->BSIM3lcdsc = value->rValue; + mod->BSIM3lcdscGiven = TRUE; + break; + + + case BSIM3_MOD_LCDSCB : + mod->BSIM3lcdscb = value->rValue; + mod->BSIM3lcdscbGiven = TRUE; + break; + case BSIM3_MOD_LCDSCD : + mod->BSIM3lcdscd = value->rValue; + mod->BSIM3lcdscdGiven = TRUE; + break; + case BSIM3_MOD_LCIT : + mod->BSIM3lcit = value->rValue; + mod->BSIM3lcitGiven = TRUE; + break; + case BSIM3_MOD_LNFACTOR : + mod->BSIM3lnfactor = value->rValue; + mod->BSIM3lnfactorGiven = TRUE; + break; + case BSIM3_MOD_LXJ: + mod->BSIM3lxj = value->rValue; + mod->BSIM3lxjGiven = TRUE; + break; + case BSIM3_MOD_LVSAT: + mod->BSIM3lvsat = value->rValue; + mod->BSIM3lvsatGiven = TRUE; + break; + + + case BSIM3_MOD_LA0: + mod->BSIM3la0 = value->rValue; + mod->BSIM3la0Given = TRUE; + break; + case BSIM3_MOD_LAGS: + mod->BSIM3lags = value->rValue; + mod->BSIM3lagsGiven = TRUE; + break; + case BSIM3_MOD_LA1: + mod->BSIM3la1 = value->rValue; + mod->BSIM3la1Given = TRUE; + break; + case BSIM3_MOD_LA2: + mod->BSIM3la2 = value->rValue; + mod->BSIM3la2Given = TRUE; + break; + case BSIM3_MOD_LAT: + mod->BSIM3lat = value->rValue; + mod->BSIM3latGiven = TRUE; + break; + case BSIM3_MOD_LKETA: + mod->BSIM3lketa = value->rValue; + mod->BSIM3lketaGiven = TRUE; + break; + case BSIM3_MOD_LNSUB: + mod->BSIM3lnsub = value->rValue; + mod->BSIM3lnsubGiven = TRUE; + break; + case BSIM3_MOD_LNPEAK: + mod->BSIM3lnpeak = value->rValue; + mod->BSIM3lnpeakGiven = TRUE; + if (mod->BSIM3lnpeak > 1.0e20) + mod->BSIM3lnpeak *= 1.0e-6; + break; + case BSIM3_MOD_LNGATE: + mod->BSIM3lngate = value->rValue; + mod->BSIM3lngateGiven = TRUE; + if (mod->BSIM3lngate > 1.0e23) + mod->BSIM3lngate *= 1.0e-6; + break; + case BSIM3_MOD_LGAMMA1: + mod->BSIM3lgamma1 = value->rValue; + mod->BSIM3lgamma1Given = TRUE; + break; + case BSIM3_MOD_LGAMMA2: + mod->BSIM3lgamma2 = value->rValue; + mod->BSIM3lgamma2Given = TRUE; + break; + case BSIM3_MOD_LVBX: + mod->BSIM3lvbx = value->rValue; + mod->BSIM3lvbxGiven = TRUE; + break; + case BSIM3_MOD_LVBM: + mod->BSIM3lvbm = value->rValue; + mod->BSIM3lvbmGiven = TRUE; + break; + case BSIM3_MOD_LXT: + mod->BSIM3lxt = value->rValue; + mod->BSIM3lxtGiven = TRUE; + break; + case BSIM3_MOD_LK1: + mod->BSIM3lk1 = value->rValue; + mod->BSIM3lk1Given = TRUE; + break; + case BSIM3_MOD_LKT1: + mod->BSIM3lkt1 = value->rValue; + mod->BSIM3lkt1Given = TRUE; + break; + case BSIM3_MOD_LKT1L: + mod->BSIM3lkt1l = value->rValue; + mod->BSIM3lkt1lGiven = TRUE; + break; + case BSIM3_MOD_LKT2: + mod->BSIM3lkt2 = value->rValue; + mod->BSIM3lkt2Given = TRUE; + break; + case BSIM3_MOD_LK2: + mod->BSIM3lk2 = value->rValue; + mod->BSIM3lk2Given = TRUE; + break; + case BSIM3_MOD_LK3: + mod->BSIM3lk3 = value->rValue; + mod->BSIM3lk3Given = TRUE; + break; + case BSIM3_MOD_LK3B: + mod->BSIM3lk3b = value->rValue; + mod->BSIM3lk3bGiven = TRUE; + break; + case BSIM3_MOD_LNLX: + mod->BSIM3lnlx = value->rValue; + mod->BSIM3lnlxGiven = TRUE; + break; + case BSIM3_MOD_LW0: + mod->BSIM3lw0 = value->rValue; + mod->BSIM3lw0Given = TRUE; + break; + case BSIM3_MOD_LDVT0: + mod->BSIM3ldvt0 = value->rValue; + mod->BSIM3ldvt0Given = TRUE; + break; + case BSIM3_MOD_LDVT1: + mod->BSIM3ldvt1 = value->rValue; + mod->BSIM3ldvt1Given = TRUE; + break; + case BSIM3_MOD_LDVT2: + mod->BSIM3ldvt2 = value->rValue; + mod->BSIM3ldvt2Given = TRUE; + break; + case BSIM3_MOD_LDVT0W: + mod->BSIM3ldvt0w = value->rValue; + mod->BSIM3ldvt0wGiven = TRUE; + break; + case BSIM3_MOD_LDVT1W: + mod->BSIM3ldvt1w = value->rValue; + mod->BSIM3ldvt1wGiven = TRUE; + break; + case BSIM3_MOD_LDVT2W: + mod->BSIM3ldvt2w = value->rValue; + mod->BSIM3ldvt2wGiven = TRUE; + break; + case BSIM3_MOD_LDROUT: + mod->BSIM3ldrout = value->rValue; + mod->BSIM3ldroutGiven = TRUE; + break; + case BSIM3_MOD_LDSUB: + mod->BSIM3ldsub = value->rValue; + mod->BSIM3ldsubGiven = TRUE; + break; + case BSIM3_MOD_LVTH0: + mod->BSIM3lvth0 = value->rValue; + mod->BSIM3lvth0Given = TRUE; + break; + case BSIM3_MOD_LUA: + mod->BSIM3lua = value->rValue; + mod->BSIM3luaGiven = TRUE; + break; + case BSIM3_MOD_LUA1: + mod->BSIM3lua1 = value->rValue; + mod->BSIM3lua1Given = TRUE; + break; + case BSIM3_MOD_LUB: + mod->BSIM3lub = value->rValue; + mod->BSIM3lubGiven = TRUE; + break; + case BSIM3_MOD_LUB1: + mod->BSIM3lub1 = value->rValue; + mod->BSIM3lub1Given = TRUE; + break; + case BSIM3_MOD_LUC: + mod->BSIM3luc = value->rValue; + mod->BSIM3lucGiven = TRUE; + break; + case BSIM3_MOD_LUC1: + mod->BSIM3luc1 = value->rValue; + mod->BSIM3luc1Given = TRUE; + break; + case BSIM3_MOD_LU0 : + mod->BSIM3lu0 = value->rValue; + mod->BSIM3lu0Given = TRUE; + break; + case BSIM3_MOD_LUTE : + mod->BSIM3lute = value->rValue; + mod->BSIM3luteGiven = TRUE; + break; + case BSIM3_MOD_LVOFF: + mod->BSIM3lvoff = value->rValue; + mod->BSIM3lvoffGiven = TRUE; + break; + case BSIM3_MOD_LDELTA : + mod->BSIM3ldelta = value->rValue; + mod->BSIM3ldeltaGiven = TRUE; + break; + case BSIM3_MOD_LRDSW: + mod->BSIM3lrdsw = value->rValue; + mod->BSIM3lrdswGiven = TRUE; + break; + case BSIM3_MOD_LPRWB: + mod->BSIM3lprwb = value->rValue; + mod->BSIM3lprwbGiven = TRUE; + break; + case BSIM3_MOD_LPRWG: + mod->BSIM3lprwg = value->rValue; + mod->BSIM3lprwgGiven = TRUE; + break; + case BSIM3_MOD_LPRT: + mod->BSIM3lprt = value->rValue; + mod->BSIM3lprtGiven = TRUE; + break; + case BSIM3_MOD_LETA0: + mod->BSIM3leta0 = value->rValue; + mod->BSIM3leta0Given = TRUE; + break; + case BSIM3_MOD_LETAB: + mod->BSIM3letab = value->rValue; + mod->BSIM3letabGiven = TRUE; + break; + case BSIM3_MOD_LPCLM: + mod->BSIM3lpclm = value->rValue; + mod->BSIM3lpclmGiven = TRUE; + break; + case BSIM3_MOD_LPDIBL1: + mod->BSIM3lpdibl1 = value->rValue; + mod->BSIM3lpdibl1Given = TRUE; + break; + case BSIM3_MOD_LPDIBL2: + mod->BSIM3lpdibl2 = value->rValue; + mod->BSIM3lpdibl2Given = TRUE; + break; + case BSIM3_MOD_LPDIBLB: + mod->BSIM3lpdiblb = value->rValue; + mod->BSIM3lpdiblbGiven = TRUE; + break; + case BSIM3_MOD_LPSCBE1: + mod->BSIM3lpscbe1 = value->rValue; + mod->BSIM3lpscbe1Given = TRUE; + break; + case BSIM3_MOD_LPSCBE2: + mod->BSIM3lpscbe2 = value->rValue; + mod->BSIM3lpscbe2Given = TRUE; + break; + case BSIM3_MOD_LPVAG: + mod->BSIM3lpvag = value->rValue; + mod->BSIM3lpvagGiven = TRUE; + break; + case BSIM3_MOD_LWR : + mod->BSIM3lwr = value->rValue; + mod->BSIM3lwrGiven = TRUE; + break; + case BSIM3_MOD_LDWG : + mod->BSIM3ldwg = value->rValue; + mod->BSIM3ldwgGiven = TRUE; + break; + case BSIM3_MOD_LDWB : + mod->BSIM3ldwb = value->rValue; + mod->BSIM3ldwbGiven = TRUE; + break; + case BSIM3_MOD_LB0 : + mod->BSIM3lb0 = value->rValue; + mod->BSIM3lb0Given = TRUE; + break; + case BSIM3_MOD_LB1 : + mod->BSIM3lb1 = value->rValue; + mod->BSIM3lb1Given = TRUE; + break; + case BSIM3_MOD_LALPHA0 : + mod->BSIM3lalpha0 = value->rValue; + mod->BSIM3lalpha0Given = TRUE; + break; + case BSIM3_MOD_LALPHA1 : + mod->BSIM3lalpha1 = value->rValue; + mod->BSIM3lalpha1Given = TRUE; + break; + case BSIM3_MOD_LBETA0 : + mod->BSIM3lbeta0 = value->rValue; + mod->BSIM3lbeta0Given = TRUE; + break; + case BSIM3_MOD_LVFB : + mod->BSIM3lvfb = value->rValue; + mod->BSIM3lvfbGiven = TRUE; + break; + + case BSIM3_MOD_LELM : + mod->BSIM3lelm = value->rValue; + mod->BSIM3lelmGiven = TRUE; + break; + case BSIM3_MOD_LCGSL : + mod->BSIM3lcgsl = value->rValue; + mod->BSIM3lcgslGiven = TRUE; + break; + case BSIM3_MOD_LCGDL : + mod->BSIM3lcgdl = value->rValue; + mod->BSIM3lcgdlGiven = TRUE; + break; + case BSIM3_MOD_LCKAPPA : + mod->BSIM3lckappa = value->rValue; + mod->BSIM3lckappaGiven = TRUE; + break; + case BSIM3_MOD_LCF : + mod->BSIM3lcf = value->rValue; + mod->BSIM3lcfGiven = TRUE; + break; + case BSIM3_MOD_LCLC : + mod->BSIM3lclc = value->rValue; + mod->BSIM3lclcGiven = TRUE; + break; + case BSIM3_MOD_LCLE : + mod->BSIM3lcle = value->rValue; + mod->BSIM3lcleGiven = TRUE; + break; + case BSIM3_MOD_LVFBCV : + mod->BSIM3lvfbcv = value->rValue; + mod->BSIM3lvfbcvGiven = TRUE; + break; + case BSIM3_MOD_LACDE : + mod->BSIM3lacde = value->rValue; + mod->BSIM3lacdeGiven = TRUE; + break; + case BSIM3_MOD_LMOIN : + mod->BSIM3lmoin = value->rValue; + mod->BSIM3lmoinGiven = TRUE; + break; + case BSIM3_MOD_LNOFF : + mod->BSIM3lnoff = value->rValue; + mod->BSIM3lnoffGiven = TRUE; + break; + case BSIM3_MOD_LVOFFCV : + mod->BSIM3lvoffcv = value->rValue; + mod->BSIM3lvoffcvGiven = TRUE; + break; + + /* Width dependence */ + case BSIM3_MOD_WCDSC : + mod->BSIM3wcdsc = value->rValue; + mod->BSIM3wcdscGiven = TRUE; + break; + + + case BSIM3_MOD_WCDSCB : + mod->BSIM3wcdscb = value->rValue; + mod->BSIM3wcdscbGiven = TRUE; + break; + case BSIM3_MOD_WCDSCD : + mod->BSIM3wcdscd = value->rValue; + mod->BSIM3wcdscdGiven = TRUE; + break; + case BSIM3_MOD_WCIT : + mod->BSIM3wcit = value->rValue; + mod->BSIM3wcitGiven = TRUE; + break; + case BSIM3_MOD_WNFACTOR : + mod->BSIM3wnfactor = value->rValue; + mod->BSIM3wnfactorGiven = TRUE; + break; + case BSIM3_MOD_WXJ: + mod->BSIM3wxj = value->rValue; + mod->BSIM3wxjGiven = TRUE; + break; + case BSIM3_MOD_WVSAT: + mod->BSIM3wvsat = value->rValue; + mod->BSIM3wvsatGiven = TRUE; + break; + + + case BSIM3_MOD_WA0: + mod->BSIM3wa0 = value->rValue; + mod->BSIM3wa0Given = TRUE; + break; + case BSIM3_MOD_WAGS: + mod->BSIM3wags = value->rValue; + mod->BSIM3wagsGiven = TRUE; + break; + case BSIM3_MOD_WA1: + mod->BSIM3wa1 = value->rValue; + mod->BSIM3wa1Given = TRUE; + break; + case BSIM3_MOD_WA2: + mod->BSIM3wa2 = value->rValue; + mod->BSIM3wa2Given = TRUE; + break; + case BSIM3_MOD_WAT: + mod->BSIM3wat = value->rValue; + mod->BSIM3watGiven = TRUE; + break; + case BSIM3_MOD_WKETA: + mod->BSIM3wketa = value->rValue; + mod->BSIM3wketaGiven = TRUE; + break; + case BSIM3_MOD_WNSUB: + mod->BSIM3wnsub = value->rValue; + mod->BSIM3wnsubGiven = TRUE; + break; + case BSIM3_MOD_WNPEAK: + mod->BSIM3wnpeak = value->rValue; + mod->BSIM3wnpeakGiven = TRUE; + if (mod->BSIM3wnpeak > 1.0e20) + mod->BSIM3wnpeak *= 1.0e-6; + break; + case BSIM3_MOD_WNGATE: + mod->BSIM3wngate = value->rValue; + mod->BSIM3wngateGiven = TRUE; + if (mod->BSIM3wngate > 1.0e23) + mod->BSIM3wngate *= 1.0e-6; + break; + case BSIM3_MOD_WGAMMA1: + mod->BSIM3wgamma1 = value->rValue; + mod->BSIM3wgamma1Given = TRUE; + break; + case BSIM3_MOD_WGAMMA2: + mod->BSIM3wgamma2 = value->rValue; + mod->BSIM3wgamma2Given = TRUE; + break; + case BSIM3_MOD_WVBX: + mod->BSIM3wvbx = value->rValue; + mod->BSIM3wvbxGiven = TRUE; + break; + case BSIM3_MOD_WVBM: + mod->BSIM3wvbm = value->rValue; + mod->BSIM3wvbmGiven = TRUE; + break; + case BSIM3_MOD_WXT: + mod->BSIM3wxt = value->rValue; + mod->BSIM3wxtGiven = TRUE; + break; + case BSIM3_MOD_WK1: + mod->BSIM3wk1 = value->rValue; + mod->BSIM3wk1Given = TRUE; + break; + case BSIM3_MOD_WKT1: + mod->BSIM3wkt1 = value->rValue; + mod->BSIM3wkt1Given = TRUE; + break; + case BSIM3_MOD_WKT1L: + mod->BSIM3wkt1l = value->rValue; + mod->BSIM3wkt1lGiven = TRUE; + break; + case BSIM3_MOD_WKT2: + mod->BSIM3wkt2 = value->rValue; + mod->BSIM3wkt2Given = TRUE; + break; + case BSIM3_MOD_WK2: + mod->BSIM3wk2 = value->rValue; + mod->BSIM3wk2Given = TRUE; + break; + case BSIM3_MOD_WK3: + mod->BSIM3wk3 = value->rValue; + mod->BSIM3wk3Given = TRUE; + break; + case BSIM3_MOD_WK3B: + mod->BSIM3wk3b = value->rValue; + mod->BSIM3wk3bGiven = TRUE; + break; + case BSIM3_MOD_WNLX: + mod->BSIM3wnlx = value->rValue; + mod->BSIM3wnlxGiven = TRUE; + break; + case BSIM3_MOD_WW0: + mod->BSIM3ww0 = value->rValue; + mod->BSIM3ww0Given = TRUE; + break; + case BSIM3_MOD_WDVT0: + mod->BSIM3wdvt0 = value->rValue; + mod->BSIM3wdvt0Given = TRUE; + break; + case BSIM3_MOD_WDVT1: + mod->BSIM3wdvt1 = value->rValue; + mod->BSIM3wdvt1Given = TRUE; + break; + case BSIM3_MOD_WDVT2: + mod->BSIM3wdvt2 = value->rValue; + mod->BSIM3wdvt2Given = TRUE; + break; + case BSIM3_MOD_WDVT0W: + mod->BSIM3wdvt0w = value->rValue; + mod->BSIM3wdvt0wGiven = TRUE; + break; + case BSIM3_MOD_WDVT1W: + mod->BSIM3wdvt1w = value->rValue; + mod->BSIM3wdvt1wGiven = TRUE; + break; + case BSIM3_MOD_WDVT2W: + mod->BSIM3wdvt2w = value->rValue; + mod->BSIM3wdvt2wGiven = TRUE; + break; + case BSIM3_MOD_WDROUT: + mod->BSIM3wdrout = value->rValue; + mod->BSIM3wdroutGiven = TRUE; + break; + case BSIM3_MOD_WDSUB: + mod->BSIM3wdsub = value->rValue; + mod->BSIM3wdsubGiven = TRUE; + break; + case BSIM3_MOD_WVTH0: + mod->BSIM3wvth0 = value->rValue; + mod->BSIM3wvth0Given = TRUE; + break; + case BSIM3_MOD_WUA: + mod->BSIM3wua = value->rValue; + mod->BSIM3wuaGiven = TRUE; + break; + case BSIM3_MOD_WUA1: + mod->BSIM3wua1 = value->rValue; + mod->BSIM3wua1Given = TRUE; + break; + case BSIM3_MOD_WUB: + mod->BSIM3wub = value->rValue; + mod->BSIM3wubGiven = TRUE; + break; + case BSIM3_MOD_WUB1: + mod->BSIM3wub1 = value->rValue; + mod->BSIM3wub1Given = TRUE; + break; + case BSIM3_MOD_WUC: + mod->BSIM3wuc = value->rValue; + mod->BSIM3wucGiven = TRUE; + break; + case BSIM3_MOD_WUC1: + mod->BSIM3wuc1 = value->rValue; + mod->BSIM3wuc1Given = TRUE; + break; + case BSIM3_MOD_WU0 : + mod->BSIM3wu0 = value->rValue; + mod->BSIM3wu0Given = TRUE; + break; + case BSIM3_MOD_WUTE : + mod->BSIM3wute = value->rValue; + mod->BSIM3wuteGiven = TRUE; + break; + case BSIM3_MOD_WVOFF: + mod->BSIM3wvoff = value->rValue; + mod->BSIM3wvoffGiven = TRUE; + break; + case BSIM3_MOD_WDELTA : + mod->BSIM3wdelta = value->rValue; + mod->BSIM3wdeltaGiven = TRUE; + break; + case BSIM3_MOD_WRDSW: + mod->BSIM3wrdsw = value->rValue; + mod->BSIM3wrdswGiven = TRUE; + break; + case BSIM3_MOD_WPRWB: + mod->BSIM3wprwb = value->rValue; + mod->BSIM3wprwbGiven = TRUE; + break; + case BSIM3_MOD_WPRWG: + mod->BSIM3wprwg = value->rValue; + mod->BSIM3wprwgGiven = TRUE; + break; + case BSIM3_MOD_WPRT: + mod->BSIM3wprt = value->rValue; + mod->BSIM3wprtGiven = TRUE; + break; + case BSIM3_MOD_WETA0: + mod->BSIM3weta0 = value->rValue; + mod->BSIM3weta0Given = TRUE; + break; + case BSIM3_MOD_WETAB: + mod->BSIM3wetab = value->rValue; + mod->BSIM3wetabGiven = TRUE; + break; + case BSIM3_MOD_WPCLM: + mod->BSIM3wpclm = value->rValue; + mod->BSIM3wpclmGiven = TRUE; + break; + case BSIM3_MOD_WPDIBL1: + mod->BSIM3wpdibl1 = value->rValue; + mod->BSIM3wpdibl1Given = TRUE; + break; + case BSIM3_MOD_WPDIBL2: + mod->BSIM3wpdibl2 = value->rValue; + mod->BSIM3wpdibl2Given = TRUE; + break; + case BSIM3_MOD_WPDIBLB: + mod->BSIM3wpdiblb = value->rValue; + mod->BSIM3wpdiblbGiven = TRUE; + break; + case BSIM3_MOD_WPSCBE1: + mod->BSIM3wpscbe1 = value->rValue; + mod->BSIM3wpscbe1Given = TRUE; + break; + case BSIM3_MOD_WPSCBE2: + mod->BSIM3wpscbe2 = value->rValue; + mod->BSIM3wpscbe2Given = TRUE; + break; + case BSIM3_MOD_WPVAG: + mod->BSIM3wpvag = value->rValue; + mod->BSIM3wpvagGiven = TRUE; + break; + case BSIM3_MOD_WWR : + mod->BSIM3wwr = value->rValue; + mod->BSIM3wwrGiven = TRUE; + break; + case BSIM3_MOD_WDWG : + mod->BSIM3wdwg = value->rValue; + mod->BSIM3wdwgGiven = TRUE; + break; + case BSIM3_MOD_WDWB : + mod->BSIM3wdwb = value->rValue; + mod->BSIM3wdwbGiven = TRUE; + break; + case BSIM3_MOD_WB0 : + mod->BSIM3wb0 = value->rValue; + mod->BSIM3wb0Given = TRUE; + break; + case BSIM3_MOD_WB1 : + mod->BSIM3wb1 = value->rValue; + mod->BSIM3wb1Given = TRUE; + break; + case BSIM3_MOD_WALPHA0 : + mod->BSIM3walpha0 = value->rValue; + mod->BSIM3walpha0Given = TRUE; + break; + case BSIM3_MOD_WALPHA1 : + mod->BSIM3walpha1 = value->rValue; + mod->BSIM3walpha1Given = TRUE; + break; + case BSIM3_MOD_WBETA0 : + mod->BSIM3wbeta0 = value->rValue; + mod->BSIM3wbeta0Given = TRUE; + break; + case BSIM3_MOD_WVFB : + mod->BSIM3wvfb = value->rValue; + mod->BSIM3wvfbGiven = TRUE; + break; + + case BSIM3_MOD_WELM : + mod->BSIM3welm = value->rValue; + mod->BSIM3welmGiven = TRUE; + break; + case BSIM3_MOD_WCGSL : + mod->BSIM3wcgsl = value->rValue; + mod->BSIM3wcgslGiven = TRUE; + break; + case BSIM3_MOD_WCGDL : + mod->BSIM3wcgdl = value->rValue; + mod->BSIM3wcgdlGiven = TRUE; + break; + case BSIM3_MOD_WCKAPPA : + mod->BSIM3wckappa = value->rValue; + mod->BSIM3wckappaGiven = TRUE; + break; + case BSIM3_MOD_WCF : + mod->BSIM3wcf = value->rValue; + mod->BSIM3wcfGiven = TRUE; + break; + case BSIM3_MOD_WCLC : + mod->BSIM3wclc = value->rValue; + mod->BSIM3wclcGiven = TRUE; + break; + case BSIM3_MOD_WCLE : + mod->BSIM3wcle = value->rValue; + mod->BSIM3wcleGiven = TRUE; + break; + case BSIM3_MOD_WVFBCV : + mod->BSIM3wvfbcv = value->rValue; + mod->BSIM3wvfbcvGiven = TRUE; + break; + case BSIM3_MOD_WACDE : + mod->BSIM3wacde = value->rValue; + mod->BSIM3wacdeGiven = TRUE; + break; + case BSIM3_MOD_WMOIN : + mod->BSIM3wmoin = value->rValue; + mod->BSIM3wmoinGiven = TRUE; + break; + case BSIM3_MOD_WNOFF : + mod->BSIM3wnoff = value->rValue; + mod->BSIM3wnoffGiven = TRUE; + break; + case BSIM3_MOD_WVOFFCV : + mod->BSIM3wvoffcv = value->rValue; + mod->BSIM3wvoffcvGiven = TRUE; + break; + + /* Cross-term dependence */ + case BSIM3_MOD_PCDSC : + mod->BSIM3pcdsc = value->rValue; + mod->BSIM3pcdscGiven = TRUE; + break; + + + case BSIM3_MOD_PCDSCB : + mod->BSIM3pcdscb = value->rValue; + mod->BSIM3pcdscbGiven = TRUE; + break; + case BSIM3_MOD_PCDSCD : + mod->BSIM3pcdscd = value->rValue; + mod->BSIM3pcdscdGiven = TRUE; + break; + case BSIM3_MOD_PCIT : + mod->BSIM3pcit = value->rValue; + mod->BSIM3pcitGiven = TRUE; + break; + case BSIM3_MOD_PNFACTOR : + mod->BSIM3pnfactor = value->rValue; + mod->BSIM3pnfactorGiven = TRUE; + break; + case BSIM3_MOD_PXJ: + mod->BSIM3pxj = value->rValue; + mod->BSIM3pxjGiven = TRUE; + break; + case BSIM3_MOD_PVSAT: + mod->BSIM3pvsat = value->rValue; + mod->BSIM3pvsatGiven = TRUE; + break; + + + case BSIM3_MOD_PA0: + mod->BSIM3pa0 = value->rValue; + mod->BSIM3pa0Given = TRUE; + break; + case BSIM3_MOD_PAGS: + mod->BSIM3pags = value->rValue; + mod->BSIM3pagsGiven = TRUE; + break; + case BSIM3_MOD_PA1: + mod->BSIM3pa1 = value->rValue; + mod->BSIM3pa1Given = TRUE; + break; + case BSIM3_MOD_PA2: + mod->BSIM3pa2 = value->rValue; + mod->BSIM3pa2Given = TRUE; + break; + case BSIM3_MOD_PAT: + mod->BSIM3pat = value->rValue; + mod->BSIM3patGiven = TRUE; + break; + case BSIM3_MOD_PKETA: + mod->BSIM3pketa = value->rValue; + mod->BSIM3pketaGiven = TRUE; + break; + case BSIM3_MOD_PNSUB: + mod->BSIM3pnsub = value->rValue; + mod->BSIM3pnsubGiven = TRUE; + break; + case BSIM3_MOD_PNPEAK: + mod->BSIM3pnpeak = value->rValue; + mod->BSIM3pnpeakGiven = TRUE; + if (mod->BSIM3pnpeak > 1.0e20) + mod->BSIM3pnpeak *= 1.0e-6; + break; + case BSIM3_MOD_PNGATE: + mod->BSIM3pngate = value->rValue; + mod->BSIM3pngateGiven = TRUE; + if (mod->BSIM3pngate > 1.0e23) + mod->BSIM3pngate *= 1.0e-6; + break; + case BSIM3_MOD_PGAMMA1: + mod->BSIM3pgamma1 = value->rValue; + mod->BSIM3pgamma1Given = TRUE; + break; + case BSIM3_MOD_PGAMMA2: + mod->BSIM3pgamma2 = value->rValue; + mod->BSIM3pgamma2Given = TRUE; + break; + case BSIM3_MOD_PVBX: + mod->BSIM3pvbx = value->rValue; + mod->BSIM3pvbxGiven = TRUE; + break; + case BSIM3_MOD_PVBM: + mod->BSIM3pvbm = value->rValue; + mod->BSIM3pvbmGiven = TRUE; + break; + case BSIM3_MOD_PXT: + mod->BSIM3pxt = value->rValue; + mod->BSIM3pxtGiven = TRUE; + break; + case BSIM3_MOD_PK1: + mod->BSIM3pk1 = value->rValue; + mod->BSIM3pk1Given = TRUE; + break; + case BSIM3_MOD_PKT1: + mod->BSIM3pkt1 = value->rValue; + mod->BSIM3pkt1Given = TRUE; + break; + case BSIM3_MOD_PKT1L: + mod->BSIM3pkt1l = value->rValue; + mod->BSIM3pkt1lGiven = TRUE; + break; + case BSIM3_MOD_PKT2: + mod->BSIM3pkt2 = value->rValue; + mod->BSIM3pkt2Given = TRUE; + break; + case BSIM3_MOD_PK2: + mod->BSIM3pk2 = value->rValue; + mod->BSIM3pk2Given = TRUE; + break; + case BSIM3_MOD_PK3: + mod->BSIM3pk3 = value->rValue; + mod->BSIM3pk3Given = TRUE; + break; + case BSIM3_MOD_PK3B: + mod->BSIM3pk3b = value->rValue; + mod->BSIM3pk3bGiven = TRUE; + break; + case BSIM3_MOD_PNLX: + mod->BSIM3pnlx = value->rValue; + mod->BSIM3pnlxGiven = TRUE; + break; + case BSIM3_MOD_PW0: + mod->BSIM3pw0 = value->rValue; + mod->BSIM3pw0Given = TRUE; + break; + case BSIM3_MOD_PDVT0: + mod->BSIM3pdvt0 = value->rValue; + mod->BSIM3pdvt0Given = TRUE; + break; + case BSIM3_MOD_PDVT1: + mod->BSIM3pdvt1 = value->rValue; + mod->BSIM3pdvt1Given = TRUE; + break; + case BSIM3_MOD_PDVT2: + mod->BSIM3pdvt2 = value->rValue; + mod->BSIM3pdvt2Given = TRUE; + break; + case BSIM3_MOD_PDVT0W: + mod->BSIM3pdvt0w = value->rValue; + mod->BSIM3pdvt0wGiven = TRUE; + break; + case BSIM3_MOD_PDVT1W: + mod->BSIM3pdvt1w = value->rValue; + mod->BSIM3pdvt1wGiven = TRUE; + break; + case BSIM3_MOD_PDVT2W: + mod->BSIM3pdvt2w = value->rValue; + mod->BSIM3pdvt2wGiven = TRUE; + break; + case BSIM3_MOD_PDROUT: + mod->BSIM3pdrout = value->rValue; + mod->BSIM3pdroutGiven = TRUE; + break; + case BSIM3_MOD_PDSUB: + mod->BSIM3pdsub = value->rValue; + mod->BSIM3pdsubGiven = TRUE; + break; + case BSIM3_MOD_PVTH0: + mod->BSIM3pvth0 = value->rValue; + mod->BSIM3pvth0Given = TRUE; + break; + case BSIM3_MOD_PUA: + mod->BSIM3pua = value->rValue; + mod->BSIM3puaGiven = TRUE; + break; + case BSIM3_MOD_PUA1: + mod->BSIM3pua1 = value->rValue; + mod->BSIM3pua1Given = TRUE; + break; + case BSIM3_MOD_PUB: + mod->BSIM3pub = value->rValue; + mod->BSIM3pubGiven = TRUE; + break; + case BSIM3_MOD_PUB1: + mod->BSIM3pub1 = value->rValue; + mod->BSIM3pub1Given = TRUE; + break; + case BSIM3_MOD_PUC: + mod->BSIM3puc = value->rValue; + mod->BSIM3pucGiven = TRUE; + break; + case BSIM3_MOD_PUC1: + mod->BSIM3puc1 = value->rValue; + mod->BSIM3puc1Given = TRUE; + break; + case BSIM3_MOD_PU0 : + mod->BSIM3pu0 = value->rValue; + mod->BSIM3pu0Given = TRUE; + break; + case BSIM3_MOD_PUTE : + mod->BSIM3pute = value->rValue; + mod->BSIM3puteGiven = TRUE; + break; + case BSIM3_MOD_PVOFF: + mod->BSIM3pvoff = value->rValue; + mod->BSIM3pvoffGiven = TRUE; + break; + case BSIM3_MOD_PDELTA : + mod->BSIM3pdelta = value->rValue; + mod->BSIM3pdeltaGiven = TRUE; + break; + case BSIM3_MOD_PRDSW: + mod->BSIM3prdsw = value->rValue; + mod->BSIM3prdswGiven = TRUE; + break; + case BSIM3_MOD_PPRWB: + mod->BSIM3pprwb = value->rValue; + mod->BSIM3pprwbGiven = TRUE; + break; + case BSIM3_MOD_PPRWG: + mod->BSIM3pprwg = value->rValue; + mod->BSIM3pprwgGiven = TRUE; + break; + case BSIM3_MOD_PPRT: + mod->BSIM3pprt = value->rValue; + mod->BSIM3pprtGiven = TRUE; + break; + case BSIM3_MOD_PETA0: + mod->BSIM3peta0 = value->rValue; + mod->BSIM3peta0Given = TRUE; + break; + case BSIM3_MOD_PETAB: + mod->BSIM3petab = value->rValue; + mod->BSIM3petabGiven = TRUE; + break; + case BSIM3_MOD_PPCLM: + mod->BSIM3ppclm = value->rValue; + mod->BSIM3ppclmGiven = TRUE; + break; + case BSIM3_MOD_PPDIBL1: + mod->BSIM3ppdibl1 = value->rValue; + mod->BSIM3ppdibl1Given = TRUE; + break; + case BSIM3_MOD_PPDIBL2: + mod->BSIM3ppdibl2 = value->rValue; + mod->BSIM3ppdibl2Given = TRUE; + break; + case BSIM3_MOD_PPDIBLB: + mod->BSIM3ppdiblb = value->rValue; + mod->BSIM3ppdiblbGiven = TRUE; + break; + case BSIM3_MOD_PPSCBE1: + mod->BSIM3ppscbe1 = value->rValue; + mod->BSIM3ppscbe1Given = TRUE; + break; + case BSIM3_MOD_PPSCBE2: + mod->BSIM3ppscbe2 = value->rValue; + mod->BSIM3ppscbe2Given = TRUE; + break; + case BSIM3_MOD_PPVAG: + mod->BSIM3ppvag = value->rValue; + mod->BSIM3ppvagGiven = TRUE; + break; + case BSIM3_MOD_PWR : + mod->BSIM3pwr = value->rValue; + mod->BSIM3pwrGiven = TRUE; + break; + case BSIM3_MOD_PDWG : + mod->BSIM3pdwg = value->rValue; + mod->BSIM3pdwgGiven = TRUE; + break; + case BSIM3_MOD_PDWB : + mod->BSIM3pdwb = value->rValue; + mod->BSIM3pdwbGiven = TRUE; + break; + case BSIM3_MOD_PB0 : + mod->BSIM3pb0 = value->rValue; + mod->BSIM3pb0Given = TRUE; + break; + case BSIM3_MOD_PB1 : + mod->BSIM3pb1 = value->rValue; + mod->BSIM3pb1Given = TRUE; + break; + case BSIM3_MOD_PALPHA0 : + mod->BSIM3palpha0 = value->rValue; + mod->BSIM3palpha0Given = TRUE; + break; + case BSIM3_MOD_PALPHA1 : + mod->BSIM3palpha1 = value->rValue; + mod->BSIM3palpha1Given = TRUE; + break; + case BSIM3_MOD_PBETA0 : + mod->BSIM3pbeta0 = value->rValue; + mod->BSIM3pbeta0Given = TRUE; + break; + case BSIM3_MOD_PVFB : + mod->BSIM3pvfb = value->rValue; + mod->BSIM3pvfbGiven = TRUE; + break; + + case BSIM3_MOD_PELM : + mod->BSIM3pelm = value->rValue; + mod->BSIM3pelmGiven = TRUE; + break; + case BSIM3_MOD_PCGSL : + mod->BSIM3pcgsl = value->rValue; + mod->BSIM3pcgslGiven = TRUE; + break; + case BSIM3_MOD_PCGDL : + mod->BSIM3pcgdl = value->rValue; + mod->BSIM3pcgdlGiven = TRUE; + break; + case BSIM3_MOD_PCKAPPA : + mod->BSIM3pckappa = value->rValue; + mod->BSIM3pckappaGiven = TRUE; + break; + case BSIM3_MOD_PCF : + mod->BSIM3pcf = value->rValue; + mod->BSIM3pcfGiven = TRUE; + break; + case BSIM3_MOD_PCLC : + mod->BSIM3pclc = value->rValue; + mod->BSIM3pclcGiven = TRUE; + break; + case BSIM3_MOD_PCLE : + mod->BSIM3pcle = value->rValue; + mod->BSIM3pcleGiven = TRUE; + break; + case BSIM3_MOD_PVFBCV : + mod->BSIM3pvfbcv = value->rValue; + mod->BSIM3pvfbcvGiven = TRUE; + break; + case BSIM3_MOD_PACDE : + mod->BSIM3pacde = value->rValue; + mod->BSIM3pacdeGiven = TRUE; + break; + case BSIM3_MOD_PMOIN : + mod->BSIM3pmoin = value->rValue; + mod->BSIM3pmoinGiven = TRUE; + break; + case BSIM3_MOD_PNOFF : + mod->BSIM3pnoff = value->rValue; + mod->BSIM3pnoffGiven = TRUE; + break; + case BSIM3_MOD_PVOFFCV : + mod->BSIM3pvoffcv = value->rValue; + mod->BSIM3pvoffcvGiven = TRUE; + break; + + case BSIM3_MOD_TNOM : + mod->BSIM3tnom = value->rValue; + mod->BSIM3tnomGiven = TRUE; + break; + case BSIM3_MOD_CGSO : + mod->BSIM3cgso = value->rValue; + mod->BSIM3cgsoGiven = TRUE; + break; + case BSIM3_MOD_CGDO : + mod->BSIM3cgdo = value->rValue; + mod->BSIM3cgdoGiven = TRUE; + break; + case BSIM3_MOD_CGBO : + mod->BSIM3cgbo = value->rValue; + mod->BSIM3cgboGiven = TRUE; + break; + case BSIM3_MOD_XPART : + mod->BSIM3xpart = value->rValue; + mod->BSIM3xpartGiven = TRUE; + break; + case BSIM3_MOD_RSH : + mod->BSIM3sheetResistance = value->rValue; + mod->BSIM3sheetResistanceGiven = TRUE; + break; + case BSIM3_MOD_JS : + mod->BSIM3jctSatCurDensity = value->rValue; + mod->BSIM3jctSatCurDensityGiven = TRUE; + break; + case BSIM3_MOD_JSW : + mod->BSIM3jctSidewallSatCurDensity = value->rValue; + mod->BSIM3jctSidewallSatCurDensityGiven = TRUE; + break; + case BSIM3_MOD_PB : + mod->BSIM3bulkJctPotential = value->rValue; + mod->BSIM3bulkJctPotentialGiven = TRUE; + break; + case BSIM3_MOD_MJ : + mod->BSIM3bulkJctBotGradingCoeff = value->rValue; + mod->BSIM3bulkJctBotGradingCoeffGiven = TRUE; + break; + case BSIM3_MOD_PBSW : + mod->BSIM3sidewallJctPotential = value->rValue; + mod->BSIM3sidewallJctPotentialGiven = TRUE; + break; + case BSIM3_MOD_MJSW : + mod->BSIM3bulkJctSideGradingCoeff = value->rValue; + mod->BSIM3bulkJctSideGradingCoeffGiven = TRUE; + break; + case BSIM3_MOD_CJ : + mod->BSIM3unitAreaJctCap = value->rValue; + mod->BSIM3unitAreaJctCapGiven = TRUE; + break; + case BSIM3_MOD_CJSW : + mod->BSIM3unitLengthSidewallJctCap = value->rValue; + mod->BSIM3unitLengthSidewallJctCapGiven = TRUE; + break; + case BSIM3_MOD_NJ : + mod->BSIM3jctEmissionCoeff = value->rValue; + mod->BSIM3jctEmissionCoeffGiven = TRUE; + break; + case BSIM3_MOD_PBSWG : + mod->BSIM3GatesidewallJctPotential = value->rValue; + mod->BSIM3GatesidewallJctPotentialGiven = TRUE; + break; + case BSIM3_MOD_MJSWG : + mod->BSIM3bulkJctGateSideGradingCoeff = value->rValue; + mod->BSIM3bulkJctGateSideGradingCoeffGiven = TRUE; + break; + case BSIM3_MOD_CJSWG : + mod->BSIM3unitLengthGateSidewallJctCap = value->rValue; + mod->BSIM3unitLengthGateSidewallJctCapGiven = TRUE; + break; + case BSIM3_MOD_XTI : + mod->BSIM3jctTempExponent = value->rValue; + mod->BSIM3jctTempExponentGiven = TRUE; + break; + case BSIM3_MOD_LINT : + mod->BSIM3Lint = value->rValue; + mod->BSIM3LintGiven = TRUE; + break; + case BSIM3_MOD_LL : + mod->BSIM3Ll = value->rValue; + mod->BSIM3LlGiven = TRUE; + break; + case BSIM3_MOD_LLC : + mod->BSIM3Llc = value->rValue; + mod->BSIM3LlcGiven = TRUE; + break; + case BSIM3_MOD_LLN : + mod->BSIM3Lln = value->rValue; + mod->BSIM3LlnGiven = TRUE; + break; + case BSIM3_MOD_LW : + mod->BSIM3Lw = value->rValue; + mod->BSIM3LwGiven = TRUE; + break; + case BSIM3_MOD_LWC : + mod->BSIM3Lwc = value->rValue; + mod->BSIM3LwcGiven = TRUE; + break; + case BSIM3_MOD_LWN : + mod->BSIM3Lwn = value->rValue; + mod->BSIM3LwnGiven = TRUE; + break; + case BSIM3_MOD_LWL : + mod->BSIM3Lwl = value->rValue; + mod->BSIM3LwlGiven = TRUE; + break; + case BSIM3_MOD_LWLC : + mod->BSIM3Lwlc = value->rValue; + mod->BSIM3LwlcGiven = TRUE; + break; + case BSIM3_MOD_LMIN : + mod->BSIM3Lmin = value->rValue; + mod->BSIM3LminGiven = TRUE; + break; + case BSIM3_MOD_LMAX : + mod->BSIM3Lmax = value->rValue; + mod->BSIM3LmaxGiven = TRUE; + break; + case BSIM3_MOD_WINT : + mod->BSIM3Wint = value->rValue; + mod->BSIM3WintGiven = TRUE; + break; + case BSIM3_MOD_WL : + mod->BSIM3Wl = value->rValue; + mod->BSIM3WlGiven = TRUE; + break; + case BSIM3_MOD_WLC : + mod->BSIM3Wlc = value->rValue; + mod->BSIM3WlcGiven = TRUE; + break; + case BSIM3_MOD_WLN : + mod->BSIM3Wln = value->rValue; + mod->BSIM3WlnGiven = TRUE; + break; + case BSIM3_MOD_WW : + mod->BSIM3Ww = value->rValue; + mod->BSIM3WwGiven = TRUE; + break; + case BSIM3_MOD_WWC : + mod->BSIM3Wwc = value->rValue; + mod->BSIM3WwcGiven = TRUE; + break; + case BSIM3_MOD_WWN : + mod->BSIM3Wwn = value->rValue; + mod->BSIM3WwnGiven = TRUE; + break; + case BSIM3_MOD_WWL : + mod->BSIM3Wwl = value->rValue; + mod->BSIM3WwlGiven = TRUE; + break; + case BSIM3_MOD_WWLC : + mod->BSIM3Wwlc = value->rValue; + mod->BSIM3WwlcGiven = TRUE; + break; + case BSIM3_MOD_WMIN : + mod->BSIM3Wmin = value->rValue; + mod->BSIM3WminGiven = TRUE; + break; + case BSIM3_MOD_WMAX : + mod->BSIM3Wmax = value->rValue; + mod->BSIM3WmaxGiven = TRUE; + break; + + case BSIM3_MOD_NOIA : + mod->BSIM3oxideTrapDensityA = value->rValue; + mod->BSIM3oxideTrapDensityAGiven = TRUE; + break; + case BSIM3_MOD_NOIB : + mod->BSIM3oxideTrapDensityB = value->rValue; + mod->BSIM3oxideTrapDensityBGiven = TRUE; + break; + case BSIM3_MOD_NOIC : + mod->BSIM3oxideTrapDensityC = value->rValue; + mod->BSIM3oxideTrapDensityCGiven = TRUE; + break; + case BSIM3_MOD_EM : + mod->BSIM3em = value->rValue; + mod->BSIM3emGiven = TRUE; + break; + case BSIM3_MOD_EF : + mod->BSIM3ef = value->rValue; + mod->BSIM3efGiven = TRUE; + break; + case BSIM3_MOD_AF : + mod->BSIM3af = value->rValue; + mod->BSIM3afGiven = TRUE; + break; + case BSIM3_MOD_KF : + mod->BSIM3kf = value->rValue; + mod->BSIM3kfGiven = TRUE; + break; + case BSIM3_MOD_NMOS : + if(value->iValue) { + mod->BSIM3type = 1; + mod->BSIM3typeGiven = TRUE; + } + break; + case BSIM3_MOD_PMOS : + if(value->iValue) { + mod->BSIM3type = - 1; + mod->BSIM3typeGiven = TRUE; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3/b3noi.c b/src/spicelib/devices/bsim3/b3noi.c new file mode 100644 index 000000000..29dc6bd00 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3noi.c @@ -0,0 +1,411 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.3 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.2 1999/08/23 18:14:39 manu + Added cleanup patch by Arno Peters - also added 'make check' to configure + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Gary W. Ng and Min-Chie Jeng. +Author: 1997-1999 Weidong Liu. +File: b3noi.c +**********/ + +#include "ngspice.h" +#include +#include +#include "bsim3def.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" +#include "const.h" /* jwan */ + +/* + * BSIM3noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MOSFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MOSFET's is summed with the variable "OnDens". + */ + +/* + Channel thermal and flicker noises are calculated based on the value + of model->BSIM3noiMod. + If model->BSIM3noiMod = 1, + Channel thermal noise = SPICE2 model + Flicker noise = SPICE2 model + If model->BSIM3noiMod = 2, + Channel thermal noise = BSIM3 model + Flicker noise = BSIM3 model + If model->BSIM3noiMod = 3, + Channel thermal noise = SPICE2 model + Flicker noise = BSIM3 model + If model->BSIM3noiMod = 4, + Channel thermal noise = BSIM3 model + Flicker noise = SPICE2 model + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +double +StrongInversionNoiseEval(vgs, vds, model, here, freq, temp) +double vgs, vds, freq, temp; +BSIM3model *model; +BSIM3instance *here; +{ +struct bsim3SizeDependParam *pParam; +double cd, esat, DelClm, EffFreq, N0, Nl, Vgst; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Ssi; + + pParam = here->pParam; + cd = fabs(here->BSIM3cd); + if (vds > here->BSIM3vdsat) + { esat = 2.0 * pParam->BSIM3vsattemp / here->BSIM3ueff; + T0 = ((((vds - here->BSIM3vdsat) / pParam->BSIM3litl) + model->BSIM3em) + / esat); + DelClm = pParam->BSIM3litl * log (MAX(T0, N_MINLOG)); + } + else + DelClm = 0.0; + EffFreq = pow(freq, model->BSIM3ef); + T1 = CHARGE * CHARGE * 8.62e-5 * cd * temp * here->BSIM3ueff; + T2 = 1.0e8 * EffFreq * model->BSIM3cox + * pParam->BSIM3leff * pParam->BSIM3leff; + Vgst = vgs - here->BSIM3von; + N0 = model->BSIM3cox * Vgst / CHARGE; + if (N0 < 0.0) + N0 = 0.0; + Nl = model->BSIM3cox * (Vgst - MIN(vds, here->BSIM3vdsat)) / CHARGE; + if (Nl < 0.0) + Nl = 0.0; + + T3 = model->BSIM3oxideTrapDensityA + * log(MAX(((N0 + 2.0e14) / (Nl + 2.0e14)), N_MINLOG)); + T4 = model->BSIM3oxideTrapDensityB * (N0 - Nl); + T5 = model->BSIM3oxideTrapDensityC * 0.5 * (N0 * N0 - Nl * Nl); + + T6 = 8.62e-5 * temp * cd * cd; + T7 = 1.0e8 * EffFreq * pParam->BSIM3leff + * pParam->BSIM3leff * pParam->BSIM3weff; + T8 = model->BSIM3oxideTrapDensityA + model->BSIM3oxideTrapDensityB * Nl + + model->BSIM3oxideTrapDensityC * Nl * Nl; + T9 = (Nl + 2.0e14) * (Nl + 2.0e14); + + Ssi = T1 / T2 * (T3 + T4 + T5) + T6 / T7 * DelClm * T8 / T9; + return Ssi; +} + +int +BSIM3noise (mode, operation, inModel, ckt, data, OnDens) +int mode, operation; +GENmodel *inModel; +CKTcircuit *ckt; +register Ndata *data; +double *OnDens; +{ +register BSIM3model *model = (BSIM3model *)inModel; +register BSIM3instance *here; +struct bsim3SizeDependParam *pParam; +char name[N_MXVLNTH]; +double tempOnoise; +double tempInoise; +double noizDens[BSIM3NSRCS]; +double lnNdens[BSIM3NSRCS]; + +double vgs, vds, Slimit; + double T1, T10, T11; +double Ssi, Swi; + +int i; + + /* define the names of the noise sources */ + static char *BSIM3nNames[BSIM3NSRCS] = + { /* Note that we have to keep the order */ + ".rd", /* noise due to rd */ + /* consistent with thestrchr definitions */ + ".rs", /* noise due to rs */ + /* in BSIM3defs.h */ + ".id", /* noise due to id */ + ".1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (; model != NULL; model = model->BSIM3nextModel) + { for (here = model->BSIM3instances; here != NULL; + here = here->BSIM3nextInstance) + { pParam = here->pParam; + switch (operation) + { case N_OPEN: + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { switch (mode) + { case N_DENS: + for (i = 0; i < BSIM3NSRCS; i++) + { (void) sprintf(name, "onoise.%s%s", + here->BSIM3name, + BSIM3nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + } + break; + case INT_NOIZ: + for (i = 0; i < BSIM3NSRCS; i++) + { (void) sprintf(name, "onoise_total.%s%s", + here->BSIM3name, + BSIM3nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + + (void) sprintf(name, "inoise_total.%s%s", + here->BSIM3name, + BSIM3nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **)NULL); + /* we've added one more plot */ + } + break; + } + } + break; + case N_CALC: + switch (mode) + { case N_DENS: + NevalSrc(&noizDens[BSIM3RDNOIZ], + &lnNdens[BSIM3RDNOIZ], ckt, THERMNOISE, + here->BSIM3dNodePrime, here->BSIM3dNode, + here->BSIM3drainConductance); + + NevalSrc(&noizDens[BSIM3RSNOIZ], + &lnNdens[BSIM3RSNOIZ], ckt, THERMNOISE, + here->BSIM3sNodePrime, here->BSIM3sNode, + here->BSIM3sourceConductance); + + switch( model->BSIM3noiMod ) + { case 1: + case 3: + NevalSrc(&noizDens[BSIM3IDNOIZ], + &lnNdens[BSIM3IDNOIZ], ckt, + THERMNOISE, here->BSIM3dNodePrime, + here->BSIM3sNodePrime, + (2.0 / 3.0 * fabs(here->BSIM3gm + + here->BSIM3gds + + here->BSIM3gmbs))); + break; + case 2: + case 4: + NevalSrc(&noizDens[BSIM3IDNOIZ], + &lnNdens[BSIM3IDNOIZ], ckt, + THERMNOISE, here->BSIM3dNodePrime, + here->BSIM3sNodePrime, + (here->BSIM3ueff + * fabs(here->BSIM3qinv + / (pParam->BSIM3leff + * pParam->BSIM3leff)))); + break; + } + NevalSrc(&noizDens[BSIM3FLNOIZ], (double*) NULL, + ckt, N_GAIN, here->BSIM3dNodePrime, + here->BSIM3sNodePrime, (double) 0.0); + + switch( model->BSIM3noiMod ) + { case 1: + case 4: + noizDens[BSIM3FLNOIZ] *= model->BSIM3kf + * exp(model->BSIM3af + * log(MAX(fabs(here->BSIM3cd), + N_MINLOG))) + / (pow(data->freq, model->BSIM3ef) + * pParam->BSIM3leff + * pParam->BSIM3leff + * model->BSIM3cox); + break; + case 2: + case 3: + vgs = *(ckt->CKTstates[0] + here->BSIM3vgs); + vds = *(ckt->CKTstates[0] + here->BSIM3vds); + if (vds < 0.0) + { vds = -vds; + vgs = vgs + vds; + } + if (vgs >= here->BSIM3von + 0.1) + { Ssi = StrongInversionNoiseEval(vgs, + vds, model, here, data->freq, + ckt->CKTtemp); + noizDens[BSIM3FLNOIZ] *= Ssi; + } + else + { pParam = here->pParam; + T10 = model->BSIM3oxideTrapDensityA + * 8.62e-5 * ckt->CKTtemp; + T11 = pParam->BSIM3weff + * pParam->BSIM3leff + * pow(data->freq, model->BSIM3ef) + * 4.0e36; + Swi = T10 / T11 * here->BSIM3cd + * here->BSIM3cd; + Slimit = StrongInversionNoiseEval( + here->BSIM3von + 0.1, vds, model, + here, data->freq, ckt->CKTtemp); + T1 = Swi + Slimit; + if (T1 > 0.0) + noizDens[BSIM3FLNOIZ] *= (Slimit + * Swi) / T1; + else + noizDens[BSIM3FLNOIZ] *= 0.0; + } + break; + } + + lnNdens[BSIM3FLNOIZ] = + log(MAX(noizDens[BSIM3FLNOIZ], N_MINLOG)); + + noizDens[BSIM3TOTNOIZ] = noizDens[BSIM3RDNOIZ] + + noizDens[BSIM3RSNOIZ] + + noizDens[BSIM3IDNOIZ] + + noizDens[BSIM3FLNOIZ]; + lnNdens[BSIM3TOTNOIZ] = + log(MAX(noizDens[BSIM3TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[BSIM3TOTNOIZ]; + + if (data->delFreq == 0.0) + { /* if we haven't done any previous + integration, we need to initialize our + "history" variables. + */ + + for (i = 0; i < BSIM3NSRCS; i++) + { here->BSIM3nVar[LNLSTDENS][i] = + lnNdens[i]; + } + + /* clear out our integration variables + if it's the first pass + */ + if (data->freq == + ((NOISEAN*) ckt->CKTcurJob)->NstartFreq) + { for (i = 0; i < BSIM3NSRCS; i++) + { here->BSIM3nVar[OUTNOIZ][i] = 0.0; + here->BSIM3nVar[INNOIZ][i] = 0.0; + } + } + } + else + { /* data->delFreq != 0.0, + we have to integrate. + */ + for (i = 0; i < BSIM3NSRCS; i++) + { if (i != BSIM3TOTNOIZ) + { tempOnoise = Nintegrate(noizDens[i], + lnNdens[i], + here->BSIM3nVar[LNLSTDENS][i], + data); + tempInoise = Nintegrate(noizDens[i] + * data->GainSqInv, lnNdens[i] + + data->lnGainInv, + here->BSIM3nVar[LNLSTDENS][i] + + data->lnGainInv, data); + here->BSIM3nVar[LNLSTDENS][i] = + lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*) + ckt->CKTcurJob)->NStpsSm != 0) + { here->BSIM3nVar[OUTNOIZ][i] + += tempOnoise; + here->BSIM3nVar[OUTNOIZ][BSIM3TOTNOIZ] + += tempOnoise; + here->BSIM3nVar[INNOIZ][i] + += tempInoise; + here->BSIM3nVar[INNOIZ][BSIM3TOTNOIZ] + += tempInoise; + } + } + } + } + if (data->prtSummary) + { for (i = 0; i < BSIM3NSRCS; i++) + { /* print a summary report */ + data->outpVector[data->outNumber++] + = noizDens[i]; + } + } + break; + case INT_NOIZ: + /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { for (i = 0; i < BSIM3NSRCS; i++) + { data->outpVector[data->outNumber++] + = here->BSIM3nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] + = here->BSIM3nVar[INNOIZ][i]; + } + } + break; + } + break; + case N_CLOSE: + /* do nothing, the main calling routine will close */ + return (OK); + break; /* the plots */ + } /* switch (operation) */ + } /* for here */ + } /* for model */ + + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3/b3par.c b/src/spicelib/devices/bsim3/b3par.c new file mode 100644 index 000000000..888664a72 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3par.c @@ -0,0 +1,121 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3par.c +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "bsim3def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3param(param,value,inst,select) +int param; +IFvalue *value; +GENinstance *inst; +IFvalue *select; +{ + BSIM3instance *here = (BSIM3instance*)inst; + switch(param) + { case BSIM3_W: + here->BSIM3w = value->rValue; + here->BSIM3wGiven = TRUE; + break; + case BSIM3_L: + here->BSIM3l = value->rValue; + here->BSIM3lGiven = TRUE; + break; + case BSIM3_AS: + here->BSIM3sourceArea = value->rValue; + here->BSIM3sourceAreaGiven = TRUE; + break; + case BSIM3_AD: + here->BSIM3drainArea = value->rValue; + here->BSIM3drainAreaGiven = TRUE; + break; + case BSIM3_PS: + here->BSIM3sourcePerimeter = value->rValue; + here->BSIM3sourcePerimeterGiven = TRUE; + break; + case BSIM3_PD: + here->BSIM3drainPerimeter = value->rValue; + here->BSIM3drainPerimeterGiven = TRUE; + break; + case BSIM3_NRS: + here->BSIM3sourceSquares = value->rValue; + here->BSIM3sourceSquaresGiven = TRUE; + break; + case BSIM3_NRD: + here->BSIM3drainSquares = value->rValue; + here->BSIM3drainSquaresGiven = TRUE; + break; + case BSIM3_OFF: + here->BSIM3off = value->iValue; + break; + case BSIM3_IC_VBS: + here->BSIM3icVBS = value->rValue; + here->BSIM3icVBSGiven = TRUE; + break; + case BSIM3_IC_VDS: + here->BSIM3icVDS = value->rValue; + here->BSIM3icVDSGiven = TRUE; + break; + case BSIM3_IC_VGS: + here->BSIM3icVGS = value->rValue; + here->BSIM3icVGSGiven = TRUE; + break; + case BSIM3_NQSMOD: + here->BSIM3nqsMod = value->iValue; + here->BSIM3nqsModGiven = TRUE; + break; + case BSIM3_IC: + switch(value->v.numValue){ + case 3: + here->BSIM3icVBS = *(value->v.vec.rVec+2); + here->BSIM3icVBSGiven = TRUE; + case 2: + here->BSIM3icVGS = *(value->v.vec.rVec+1); + here->BSIM3icVGSGiven = TRUE; + case 1: + here->BSIM3icVDS = *(value->v.vec.rVec); + here->BSIM3icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3/b3pzld.c b/src/spicelib/devices/bsim3/b3pzld.c new file mode 100644 index 000000000..cb5554309 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3pzld.c @@ -0,0 +1,390 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.2 1999/08/23 18:14:39 manu + Added cleanup patch by Arno Peters - also added 'make check' to configure + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3pzld.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "bsim3def.h" +#include "suffix.h" + +int +BSIM3pzLoad(inModel,ckt,s) +GENmodel *inModel; +register CKTcircuit *ckt; +register SPcomplex *s; +{ +register BSIM3model *model = (BSIM3model*)inModel; +register BSIM3instance *here; +double xcggb, xcgdb, xcgsb, xcgbb, xcbgb, xcbdb, xcbsb, xcbbb; +double xcdgb, xcddb, xcdsb, xcdbb, xcsgb, xcsdb, xcssb, xcsbb; +double gdpr, gspr, gds, gbd, gbs, capbd, capbs, FwdSum, RevSum, Gm, Gmbs; +double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb; +double GSoverlapCap, GDoverlapCap, GBoverlapCap; +double dxpart, sxpart, xgtg, xgtd, xgts, xgtb, xcqgb, xcqdb, xcqsb, xcqbb; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb; +double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; +double T1, CoxWL, qcheq, Cdg, Cdd, Cds, Csg, Csd, Css; +double ScalingFactor = 1.0e-9; + + for (; model != NULL; model = model->BSIM3nextModel) + { for (here = model->BSIM3instances; here!= NULL; + here = here->BSIM3nextInstance) + { + if (here->BSIM3owner != ARCHme) continue; + if (here->BSIM3mode >= 0) + { Gm = here->BSIM3gm; + Gmbs = here->BSIM3gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + + gbbdp = -here->BSIM3gbds; + gbbsp = here->BSIM3gbds + here->BSIM3gbgs + here->BSIM3gbbs; + + gbdpg = here->BSIM3gbgs; + gbdpdp = here->BSIM3gbds; + gbdpb = here->BSIM3gbbs; + gbdpsp = -(gbdpg + gbdpdp + gbdpb); + + gbspg = 0.0; + gbspdp = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + if (here->BSIM3nqsMod == 0) + { cggb = here->BSIM3cggb; + cgsb = here->BSIM3cgsb; + cgdb = here->BSIM3cgdb; + + cbgb = here->BSIM3cbgb; + cbsb = here->BSIM3cbsb; + cbdb = here->BSIM3cbdb; + + cdgb = here->BSIM3cdgb; + cdsb = here->BSIM3cdsb; + cddb = here->BSIM3cddb; + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3gtg; + xgtd = here->BSIM3gtd; + xgts = here->BSIM3gts; + xgtb = here->BSIM3gtb; + + xcqgb = here->BSIM3cqgb; + xcqdb = here->BSIM3cqdb; + xcqsb = here->BSIM3cqsb; + xcqbb = here->BSIM3cqbb; + + CoxWL = model->BSIM3cox * here->pParam->BSIM3weffCV + * here->pParam->BSIM3leffCV; + qcheq = -(here->BSIM3qgate + here->BSIM3qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM3xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = here->BSIM3qdrn / qcheq; + Cdd = here->BSIM3cddb; + Csd = -(here->BSIM3cgdb + here->BSIM3cddb + + here->BSIM3cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM3cdgb; + Csg = -(here->BSIM3cggb + here->BSIM3cdgb + + here->BSIM3cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM3cdsb; + Css = -(here->BSIM3cgsb + here->BSIM3cdsb + + here->BSIM3cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + } + else + { Gm = -here->BSIM3gm; + Gmbs = -here->BSIM3gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + + gbbsp = -here->BSIM3gbds; + gbbdp = here->BSIM3gbds + here->BSIM3gbgs + here->BSIM3gbbs; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM3gbgs; + gbspsp = here->BSIM3gbds; + gbspb = here->BSIM3gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + + if (here->BSIM3nqsMod == 0) + { cggb = here->BSIM3cggb; + cgsb = here->BSIM3cgdb; + cgdb = here->BSIM3cgsb; + + cbgb = here->BSIM3cbgb; + cbsb = here->BSIM3cbdb; + cbdb = here->BSIM3cbsb; + + cdgb = -(here->BSIM3cdgb + cggb + cbgb); + cdsb = -(here->BSIM3cddb + cgsb + cbsb); + cddb = -(here->BSIM3cdsb + cgdb + cbdb); + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3gtg; + xgtd = here->BSIM3gts; + xgts = here->BSIM3gtd; + xgtb = here->BSIM3gtb; + + xcqgb = here->BSIM3cqgb; + xcqdb = here->BSIM3cqsb; + xcqsb = here->BSIM3cqdb; + xcqbb = here->BSIM3cqbb; + + CoxWL = model->BSIM3cox * here->pParam->BSIM3weffCV + * here->pParam->BSIM3leffCV; + qcheq = -(here->BSIM3qgate + here->BSIM3qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM3xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = here->BSIM3qdrn / qcheq; + Css = here->BSIM3cddb; + Cds = -(here->BSIM3cgdb + here->BSIM3cddb + + here->BSIM3cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM3cdgb; + Cdg = -(here->BSIM3cggb + here->BSIM3cdgb + + here->BSIM3cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM3cdsb; + Cdd = -(here->BSIM3cgsb + here->BSIM3cdsb + + here->BSIM3cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + } + + + T1 = *(ckt->CKTstate0 + here->BSIM3qdef) * here->BSIM3gtau; + gdpr = here->BSIM3drainConductance; + gspr = here->BSIM3sourceConductance; + gds = here->BSIM3gds; + gbd = here->BSIM3gbd; + gbs = here->BSIM3gbs; + capbd = here->BSIM3capbd; + capbs = here->BSIM3capbs; + + GSoverlapCap = here->BSIM3cgso; + GDoverlapCap = here->BSIM3cgdo; + GBoverlapCap = here->pParam->BSIM3cgbo; + + xcdgb = (cdgb - GDoverlapCap); + xcddb = (cddb + capbd + GDoverlapCap); + xcdsb = cdsb; + xcdbb = -(xcdgb + xcddb + xcdsb); + xcsgb = -(cggb + cbgb + cdgb + GSoverlapCap); + xcsdb = -(cgdb + cbdb + cddb); + xcssb = (capbs + GSoverlapCap - (cgsb + cbsb + cdsb)); + xcsbb = -(xcsgb + xcsdb + xcssb); + xcggb = (cggb + GDoverlapCap + GSoverlapCap + GBoverlapCap); + xcgdb = (cgdb - GDoverlapCap); + xcgsb = (cgsb - GSoverlapCap); + xcgbb = -(xcggb + xcgdb + xcgsb); + xcbgb = (cbgb - GBoverlapCap); + xcbdb = (cbdb - capbd); + xcbsb = (cbsb - capbs); + xcbbb = -(xcbgb + xcbdb + xcbsb); + + *(here->BSIM3GgPtr ) += xcggb * s->real; + *(here->BSIM3GgPtr +1) += xcggb * s->imag; + *(here->BSIM3BbPtr ) += xcbbb * s->real; + *(here->BSIM3BbPtr +1) += xcbbb * s->imag; + *(here->BSIM3DPdpPtr ) += xcddb * s->real; + *(here->BSIM3DPdpPtr +1) += xcddb * s->imag; + *(here->BSIM3SPspPtr ) += xcssb * s->real; + *(here->BSIM3SPspPtr +1) += xcssb * s->imag; + + *(here->BSIM3GbPtr ) += xcgbb * s->real; + *(here->BSIM3GbPtr +1) += xcgbb * s->imag; + *(here->BSIM3GdpPtr ) += xcgdb * s->real; + *(here->BSIM3GdpPtr +1) += xcgdb * s->imag; + *(here->BSIM3GspPtr ) += xcgsb * s->real; + *(here->BSIM3GspPtr +1) += xcgsb * s->imag; + + *(here->BSIM3BgPtr ) += xcbgb * s->real; + *(here->BSIM3BgPtr +1) += xcbgb * s->imag; + *(here->BSIM3BdpPtr ) += xcbdb * s->real; + *(here->BSIM3BdpPtr +1) += xcbdb * s->imag; + *(here->BSIM3BspPtr ) += xcbsb * s->real; + *(here->BSIM3BspPtr +1) += xcbsb * s->imag; + + *(here->BSIM3DPgPtr ) += xcdgb * s->real; + *(here->BSIM3DPgPtr +1) += xcdgb * s->imag; + *(here->BSIM3DPbPtr ) += xcdbb * s->real; + *(here->BSIM3DPbPtr +1) += xcdbb * s->imag; + *(here->BSIM3DPspPtr ) += xcdsb * s->real; + *(here->BSIM3DPspPtr +1) += xcdsb * s->imag; + + *(here->BSIM3SPgPtr ) += xcsgb * s->real; + *(here->BSIM3SPgPtr +1) += xcsgb * s->imag; + *(here->BSIM3SPbPtr ) += xcsbb * s->real; + *(here->BSIM3SPbPtr +1) += xcsbb * s->imag; + *(here->BSIM3SPdpPtr ) += xcsdb * s->real; + *(here->BSIM3SPdpPtr +1) += xcsdb * s->imag; + + *(here->BSIM3DdPtr) += gdpr; + *(here->BSIM3DdpPtr) -= gdpr; + *(here->BSIM3DPdPtr) -= gdpr; + + *(here->BSIM3SsPtr) += gspr; + *(here->BSIM3SspPtr) -= gspr; + *(here->BSIM3SPsPtr) -= gspr; + + *(here->BSIM3BgPtr) -= here->BSIM3gbgs; + *(here->BSIM3BbPtr) += gbd + gbs - here->BSIM3gbbs; + *(here->BSIM3BdpPtr) -= gbd - gbbdp; + *(here->BSIM3BspPtr) -= gbs - gbbsp; + + *(here->BSIM3DPgPtr) += Gm + dxpart * xgtg + + T1 * ddxpart_dVg + gbdpg; + *(here->BSIM3DPdpPtr) += gdpr + gds + gbd + RevSum + + dxpart * xgtd + T1 * ddxpart_dVd + gbdpdp; + *(here->BSIM3DPspPtr) -= gds + FwdSum - dxpart * xgts + - T1 * ddxpart_dVs - gbdpsp; + *(here->BSIM3DPbPtr) -= gbd - Gmbs - dxpart * xgtb + - T1 * ddxpart_dVb - gbdpb; + + *(here->BSIM3SPgPtr) -= Gm - sxpart * xgtg + - T1 * dsxpart_dVg - gbspg; + *(here->BSIM3SPspPtr) += gspr + gds + gbs + FwdSum + + sxpart * xgts + T1 * dsxpart_dVs + gbspsp; + *(here->BSIM3SPbPtr) -= gbs + Gmbs - sxpart * xgtb + - T1 * dsxpart_dVb - gbspb; + *(here->BSIM3SPdpPtr) -= gds + RevSum - sxpart * xgtd + - T1 * dsxpart_dVd - gbspdp; + + *(here->BSIM3GgPtr) -= xgtg; + *(here->BSIM3GbPtr) -= xgtb; + *(here->BSIM3GdpPtr) -= xgtd; + *(here->BSIM3GspPtr) -= xgts; + + if (here->BSIM3nqsMod) + { *(here->BSIM3QqPtr ) += s->real * ScalingFactor; + *(here->BSIM3QqPtr +1) += s->imag * ScalingFactor; + *(here->BSIM3QgPtr ) -= xcqgb * s->real; + *(here->BSIM3QgPtr +1) -= xcqgb * s->imag; + *(here->BSIM3QdpPtr ) -= xcqdb * s->real; + *(here->BSIM3QdpPtr +1) -= xcqdb * s->imag; + *(here->BSIM3QbPtr ) -= xcqbb * s->real; + *(here->BSIM3QbPtr +1) -= xcqbb * s->imag; + *(here->BSIM3QspPtr ) -= xcqsb * s->real; + *(here->BSIM3QspPtr +1) -= xcqsb * s->imag; + + *(here->BSIM3GqPtr) -= here->BSIM3gtau; + *(here->BSIM3DPqPtr) += dxpart * here->BSIM3gtau; + *(here->BSIM3SPqPtr) += sxpart * here->BSIM3gtau; + + *(here->BSIM3QqPtr) += here->BSIM3gtau; + *(here->BSIM3QgPtr) += xgtg; + *(here->BSIM3QdpPtr) += xgtd; + *(here->BSIM3QbPtr) += xgtb; + *(here->BSIM3QspPtr) += xgts; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3/b3set.c b/src/spicelib/devices/bsim3/b3set.c new file mode 100644 index 000000000..0f17a2aa5 --- /dev/null +++ b/src/spicelib/devices/bsim3/b3set.c @@ -0,0 +1,1023 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.3 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.2 1999/08/23 18:14:39 manu + Added cleanup patch by Arno Peters - also added 'make check' to configure + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3set.c +**********/ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim3def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define SMOOTHFACTOR 0.1 +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define Charge_q 1.60219e-19 +#define Meter2Micron 1.0e6 + +int +BSIM3setup(matrix,inModel,ckt,states) +register SMPmatrix *matrix; +register GENmodel *inModel; +register CKTcircuit *ckt; +int *states; +{ +register BSIM3model *model = (BSIM3model*)inModel; +register BSIM3instance *here; +int error; +CKTnode *tmp; + + /* loop through all the BSIM3 device models */ + for( ; model != NULL; model = model->BSIM3nextModel ) + { +/* Default value Processing for BSIM3 MOSFET Models */ + if (!model->BSIM3typeGiven) + model->BSIM3type = NMOS; + if (!model->BSIM3mobModGiven) + model->BSIM3mobMod = 1; + if (!model->BSIM3binUnitGiven) + model->BSIM3binUnit = 1; + if (!model->BSIM3paramChkGiven) + model->BSIM3paramChk = 0; + if (!model->BSIM3capModGiven) + model->BSIM3capMod = 3; + if (!model->BSIM3noiModGiven) + model->BSIM3noiMod = 1; + if (!model->BSIM3versionGiven) + model->BSIM3version = "3.2.2"; + if (!model->BSIM3toxGiven) + model->BSIM3tox = 150.0e-10; + model->BSIM3cox = 3.453133e-11 / model->BSIM3tox; + if (!model->BSIM3toxmGiven) + model->BSIM3toxm = model->BSIM3tox; + + if (!model->BSIM3cdscGiven) + model->BSIM3cdsc = 2.4e-4; /* unit Q/V/m^2 */ + if (!model->BSIM3cdscbGiven) + model->BSIM3cdscb = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3cdscdGiven) + model->BSIM3cdscd = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3citGiven) + model->BSIM3cit = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3nfactorGiven) + model->BSIM3nfactor = 1; + if (!model->BSIM3xjGiven) + model->BSIM3xj = .15e-6; + if (!model->BSIM3vsatGiven) + model->BSIM3vsat = 8.0e4; /* unit m/s */ + if (!model->BSIM3atGiven) + model->BSIM3at = 3.3e4; /* unit m/s */ + if (!model->BSIM3a0Given) + model->BSIM3a0 = 1.0; + if (!model->BSIM3agsGiven) + model->BSIM3ags = 0.0; + if (!model->BSIM3a1Given) + model->BSIM3a1 = 0.0; + if (!model->BSIM3a2Given) + model->BSIM3a2 = 1.0; + if (!model->BSIM3ketaGiven) + model->BSIM3keta = -0.047; /* unit / V */ + if (!model->BSIM3nsubGiven) + model->BSIM3nsub = 6.0e16; /* unit 1/cm3 */ + if (!model->BSIM3npeakGiven) + model->BSIM3npeak = 1.7e17; /* unit 1/cm3 */ + if (!model->BSIM3ngateGiven) + model->BSIM3ngate = 0; /* unit 1/cm3 */ + if (!model->BSIM3vbmGiven) + model->BSIM3vbm = -3.0; + if (!model->BSIM3xtGiven) + model->BSIM3xt = 1.55e-7; + if (!model->BSIM3kt1Given) + model->BSIM3kt1 = -0.11; /* unit V */ + if (!model->BSIM3kt1lGiven) + model->BSIM3kt1l = 0.0; /* unit V*m */ + if (!model->BSIM3kt2Given) + model->BSIM3kt2 = 0.022; /* No unit */ + if (!model->BSIM3k3Given) + model->BSIM3k3 = 80.0; + if (!model->BSIM3k3bGiven) + model->BSIM3k3b = 0.0; + if (!model->BSIM3w0Given) + model->BSIM3w0 = 2.5e-6; + if (!model->BSIM3nlxGiven) + model->BSIM3nlx = 1.74e-7; + if (!model->BSIM3dvt0Given) + model->BSIM3dvt0 = 2.2; + if (!model->BSIM3dvt1Given) + model->BSIM3dvt1 = 0.53; + if (!model->BSIM3dvt2Given) + model->BSIM3dvt2 = -0.032; /* unit 1 / V */ + + if (!model->BSIM3dvt0wGiven) + model->BSIM3dvt0w = 0.0; + if (!model->BSIM3dvt1wGiven) + model->BSIM3dvt1w = 5.3e6; + if (!model->BSIM3dvt2wGiven) + model->BSIM3dvt2w = -0.032; + + if (!model->BSIM3droutGiven) + model->BSIM3drout = 0.56; + if (!model->BSIM3dsubGiven) + model->BSIM3dsub = model->BSIM3drout; + if (!model->BSIM3vth0Given) + model->BSIM3vth0 = (model->BSIM3type == NMOS) ? 0.7 : -0.7; + if (!model->BSIM3uaGiven) + model->BSIM3ua = 2.25e-9; /* unit m/V */ + if (!model->BSIM3ua1Given) + model->BSIM3ua1 = 4.31e-9; /* unit m/V */ + if (!model->BSIM3ubGiven) + model->BSIM3ub = 5.87e-19; /* unit (m/V)**2 */ + if (!model->BSIM3ub1Given) + model->BSIM3ub1 = -7.61e-18; /* unit (m/V)**2 */ + if (!model->BSIM3ucGiven) + model->BSIM3uc = (model->BSIM3mobMod == 3) ? -0.0465 : -0.0465e-9; + if (!model->BSIM3uc1Given) + model->BSIM3uc1 = (model->BSIM3mobMod == 3) ? -0.056 : -0.056e-9; + if (!model->BSIM3u0Given) + model->BSIM3u0 = (model->BSIM3type == NMOS) ? 0.067 : 0.025; + if (!model->BSIM3uteGiven) + model->BSIM3ute = -1.5; + if (!model->BSIM3voffGiven) + model->BSIM3voff = -0.08; + if (!model->BSIM3deltaGiven) + model->BSIM3delta = 0.01; + if (!model->BSIM3rdswGiven) + model->BSIM3rdsw = 0; + if (!model->BSIM3prwgGiven) + model->BSIM3prwg = 0.0; /* unit 1/V */ + if (!model->BSIM3prwbGiven) + model->BSIM3prwb = 0.0; + if (!model->BSIM3prtGiven) + if (!model->BSIM3prtGiven) + model->BSIM3prt = 0.0; + if (!model->BSIM3eta0Given) + model->BSIM3eta0 = 0.08; /* no unit */ + if (!model->BSIM3etabGiven) + model->BSIM3etab = -0.07; /* unit 1/V */ + if (!model->BSIM3pclmGiven) + model->BSIM3pclm = 1.3; /* no unit */ + if (!model->BSIM3pdibl1Given) + model->BSIM3pdibl1 = .39; /* no unit */ + if (!model->BSIM3pdibl2Given) + model->BSIM3pdibl2 = 0.0086; /* no unit */ + if (!model->BSIM3pdiblbGiven) + model->BSIM3pdiblb = 0.0; /* 1/V */ + if (!model->BSIM3pscbe1Given) + model->BSIM3pscbe1 = 4.24e8; + if (!model->BSIM3pscbe2Given) + model->BSIM3pscbe2 = 1.0e-5; + if (!model->BSIM3pvagGiven) + model->BSIM3pvag = 0.0; + if (!model->BSIM3wrGiven) + model->BSIM3wr = 1.0; + if (!model->BSIM3dwgGiven) + model->BSIM3dwg = 0.0; + if (!model->BSIM3dwbGiven) + model->BSIM3dwb = 0.0; + if (!model->BSIM3b0Given) + model->BSIM3b0 = 0.0; + if (!model->BSIM3b1Given) + model->BSIM3b1 = 0.0; + if (!model->BSIM3alpha0Given) + model->BSIM3alpha0 = 0.0; + if (!model->BSIM3alpha1Given) + model->BSIM3alpha1 = 0.0; + if (!model->BSIM3beta0Given) + model->BSIM3beta0 = 30.0; + if (!model->BSIM3ijthGiven) + model->BSIM3ijth = 0.1; /* unit A */ + + if (!model->BSIM3elmGiven) + model->BSIM3elm = 5.0; + if (!model->BSIM3cgslGiven) + model->BSIM3cgsl = 0.0; + if (!model->BSIM3cgdlGiven) + model->BSIM3cgdl = 0.0; + if (!model->BSIM3ckappaGiven) + model->BSIM3ckappa = 0.6; + if (!model->BSIM3clcGiven) + model->BSIM3clc = 0.1e-6; + if (!model->BSIM3cleGiven) + model->BSIM3cle = 0.6; + if (!model->BSIM3vfbcvGiven) + model->BSIM3vfbcv = -1.0; + if (!model->BSIM3acdeGiven) + model->BSIM3acde = 1.0; + if (!model->BSIM3moinGiven) + model->BSIM3moin = 15.0; + if (!model->BSIM3noffGiven) + model->BSIM3noff = 1.0; + if (!model->BSIM3voffcvGiven) + model->BSIM3voffcv = 0.0; + if (!model->BSIM3tcjGiven) + model->BSIM3tcj = 0.0; + if (!model->BSIM3tpbGiven) + model->BSIM3tpb = 0.0; + if (!model->BSIM3tcjswGiven) + model->BSIM3tcjsw = 0.0; + if (!model->BSIM3tpbswGiven) + model->BSIM3tpbsw = 0.0; + if (!model->BSIM3tcjswgGiven) + model->BSIM3tcjswg = 0.0; + if (!model->BSIM3tpbswgGiven) + model->BSIM3tpbswg = 0.0; + + /* Length dependence */ + if (!model->BSIM3lcdscGiven) + model->BSIM3lcdsc = 0.0; + if (!model->BSIM3lcdscbGiven) + model->BSIM3lcdscb = 0.0; + if (!model->BSIM3lcdscdGiven) + model->BSIM3lcdscd = 0.0; + if (!model->BSIM3lcitGiven) + model->BSIM3lcit = 0.0; + if (!model->BSIM3lnfactorGiven) + model->BSIM3lnfactor = 0.0; + if (!model->BSIM3lxjGiven) + model->BSIM3lxj = 0.0; + if (!model->BSIM3lvsatGiven) + model->BSIM3lvsat = 0.0; + if (!model->BSIM3latGiven) + model->BSIM3lat = 0.0; + if (!model->BSIM3la0Given) + model->BSIM3la0 = 0.0; + if (!model->BSIM3lagsGiven) + model->BSIM3lags = 0.0; + if (!model->BSIM3la1Given) + model->BSIM3la1 = 0.0; + if (!model->BSIM3la2Given) + model->BSIM3la2 = 0.0; + if (!model->BSIM3lketaGiven) + model->BSIM3lketa = 0.0; + if (!model->BSIM3lnsubGiven) + model->BSIM3lnsub = 0.0; + if (!model->BSIM3lnpeakGiven) + model->BSIM3lnpeak = 0.0; + if (!model->BSIM3lngateGiven) + model->BSIM3lngate = 0.0; + if (!model->BSIM3lvbmGiven) + model->BSIM3lvbm = 0.0; + if (!model->BSIM3lxtGiven) + model->BSIM3lxt = 0.0; + if (!model->BSIM3lkt1Given) + model->BSIM3lkt1 = 0.0; + if (!model->BSIM3lkt1lGiven) + model->BSIM3lkt1l = 0.0; + if (!model->BSIM3lkt2Given) + model->BSIM3lkt2 = 0.0; + if (!model->BSIM3lk3Given) + model->BSIM3lk3 = 0.0; + if (!model->BSIM3lk3bGiven) + model->BSIM3lk3b = 0.0; + if (!model->BSIM3lw0Given) + model->BSIM3lw0 = 0.0; + if (!model->BSIM3lnlxGiven) + model->BSIM3lnlx = 0.0; + if (!model->BSIM3ldvt0Given) + model->BSIM3ldvt0 = 0.0; + if (!model->BSIM3ldvt1Given) + model->BSIM3ldvt1 = 0.0; + if (!model->BSIM3ldvt2Given) + model->BSIM3ldvt2 = 0.0; + if (!model->BSIM3ldvt0wGiven) + model->BSIM3ldvt0w = 0.0; + if (!model->BSIM3ldvt1wGiven) + model->BSIM3ldvt1w = 0.0; + if (!model->BSIM3ldvt2wGiven) + model->BSIM3ldvt2w = 0.0; + if (!model->BSIM3ldroutGiven) + model->BSIM3ldrout = 0.0; + if (!model->BSIM3ldsubGiven) + model->BSIM3ldsub = 0.0; + if (!model->BSIM3lvth0Given) + model->BSIM3lvth0 = 0.0; + if (!model->BSIM3luaGiven) + model->BSIM3lua = 0.0; + if (!model->BSIM3lua1Given) + model->BSIM3lua1 = 0.0; + if (!model->BSIM3lubGiven) + model->BSIM3lub = 0.0; + if (!model->BSIM3lub1Given) + model->BSIM3lub1 = 0.0; + if (!model->BSIM3lucGiven) + model->BSIM3luc = 0.0; + if (!model->BSIM3luc1Given) + model->BSIM3luc1 = 0.0; + if (!model->BSIM3lu0Given) + model->BSIM3lu0 = 0.0; + if (!model->BSIM3luteGiven) + model->BSIM3lute = 0.0; + if (!model->BSIM3lvoffGiven) + model->BSIM3lvoff = 0.0; + if (!model->BSIM3ldeltaGiven) + model->BSIM3ldelta = 0.0; + if (!model->BSIM3lrdswGiven) + model->BSIM3lrdsw = 0.0; + if (!model->BSIM3lprwbGiven) + model->BSIM3lprwb = 0.0; + if (!model->BSIM3lprwgGiven) + model->BSIM3lprwg = 0.0; + if (!model->BSIM3lprtGiven) + model->BSIM3lprt = 0.0; + if (!model->BSIM3leta0Given) + model->BSIM3leta0 = 0.0; + if (!model->BSIM3letabGiven) + model->BSIM3letab = -0.0; + if (!model->BSIM3lpclmGiven) + model->BSIM3lpclm = 0.0; + if (!model->BSIM3lpdibl1Given) + model->BSIM3lpdibl1 = 0.0; + if (!model->BSIM3lpdibl2Given) + model->BSIM3lpdibl2 = 0.0; + if (!model->BSIM3lpdiblbGiven) + model->BSIM3lpdiblb = 0.0; + if (!model->BSIM3lpscbe1Given) + model->BSIM3lpscbe1 = 0.0; + if (!model->BSIM3lpscbe2Given) + model->BSIM3lpscbe2 = 0.0; + if (!model->BSIM3lpvagGiven) + model->BSIM3lpvag = 0.0; + if (!model->BSIM3lwrGiven) + model->BSIM3lwr = 0.0; + if (!model->BSIM3ldwgGiven) + model->BSIM3ldwg = 0.0; + if (!model->BSIM3ldwbGiven) + model->BSIM3ldwb = 0.0; + if (!model->BSIM3lb0Given) + model->BSIM3lb0 = 0.0; + if (!model->BSIM3lb1Given) + model->BSIM3lb1 = 0.0; + if (!model->BSIM3lalpha0Given) + model->BSIM3lalpha0 = 0.0; + if (!model->BSIM3lalpha1Given) + model->BSIM3lalpha1 = 0.0; + if (!model->BSIM3lbeta0Given) + model->BSIM3lbeta0 = 0.0; + if (!model->BSIM3lvfbGiven) + model->BSIM3lvfb = 0.0; + + if (!model->BSIM3lelmGiven) + model->BSIM3lelm = 0.0; + if (!model->BSIM3lcgslGiven) + model->BSIM3lcgsl = 0.0; + if (!model->BSIM3lcgdlGiven) + model->BSIM3lcgdl = 0.0; + if (!model->BSIM3lckappaGiven) + model->BSIM3lckappa = 0.0; + if (!model->BSIM3lclcGiven) + model->BSIM3lclc = 0.0; + if (!model->BSIM3lcleGiven) + model->BSIM3lcle = 0.0; + if (!model->BSIM3lcfGiven) + model->BSIM3lcf = 0.0; + if (!model->BSIM3lvfbcvGiven) + model->BSIM3lvfbcv = 0.0; + if (!model->BSIM3lacdeGiven) + model->BSIM3lacde = 0.0; + if (!model->BSIM3lmoinGiven) + model->BSIM3lmoin = 0.0; + if (!model->BSIM3lnoffGiven) + model->BSIM3lnoff = 0.0; + if (!model->BSIM3lvoffcvGiven) + model->BSIM3lvoffcv = 0.0; + + /* Width dependence */ + if (!model->BSIM3wcdscGiven) + model->BSIM3wcdsc = 0.0; + if (!model->BSIM3wcdscbGiven) + model->BSIM3wcdscb = 0.0; + if (!model->BSIM3wcdscdGiven) + model->BSIM3wcdscd = 0.0; + if (!model->BSIM3wcitGiven) + model->BSIM3wcit = 0.0; + if (!model->BSIM3wnfactorGiven) + model->BSIM3wnfactor = 0.0; + if (!model->BSIM3wxjGiven) + model->BSIM3wxj = 0.0; + if (!model->BSIM3wvsatGiven) + model->BSIM3wvsat = 0.0; + if (!model->BSIM3watGiven) + model->BSIM3wat = 0.0; + if (!model->BSIM3wa0Given) + model->BSIM3wa0 = 0.0; + if (!model->BSIM3wagsGiven) + model->BSIM3wags = 0.0; + if (!model->BSIM3wa1Given) + model->BSIM3wa1 = 0.0; + if (!model->BSIM3wa2Given) + model->BSIM3wa2 = 0.0; + if (!model->BSIM3wketaGiven) + model->BSIM3wketa = 0.0; + if (!model->BSIM3wnsubGiven) + model->BSIM3wnsub = 0.0; + if (!model->BSIM3wnpeakGiven) + model->BSIM3wnpeak = 0.0; + if (!model->BSIM3wngateGiven) + model->BSIM3wngate = 0.0; + if (!model->BSIM3wvbmGiven) + model->BSIM3wvbm = 0.0; + if (!model->BSIM3wxtGiven) + model->BSIM3wxt = 0.0; + if (!model->BSIM3wkt1Given) + model->BSIM3wkt1 = 0.0; + if (!model->BSIM3wkt1lGiven) + model->BSIM3wkt1l = 0.0; + if (!model->BSIM3wkt2Given) + model->BSIM3wkt2 = 0.0; + if (!model->BSIM3wk3Given) + model->BSIM3wk3 = 0.0; + if (!model->BSIM3wk3bGiven) + model->BSIM3wk3b = 0.0; + if (!model->BSIM3ww0Given) + model->BSIM3ww0 = 0.0; + if (!model->BSIM3wnlxGiven) + model->BSIM3wnlx = 0.0; + if (!model->BSIM3wdvt0Given) + model->BSIM3wdvt0 = 0.0; + if (!model->BSIM3wdvt1Given) + model->BSIM3wdvt1 = 0.0; + if (!model->BSIM3wdvt2Given) + model->BSIM3wdvt2 = 0.0; + if (!model->BSIM3wdvt0wGiven) + model->BSIM3wdvt0w = 0.0; + if (!model->BSIM3wdvt1wGiven) + model->BSIM3wdvt1w = 0.0; + if (!model->BSIM3wdvt2wGiven) + model->BSIM3wdvt2w = 0.0; + if (!model->BSIM3wdroutGiven) + model->BSIM3wdrout = 0.0; + if (!model->BSIM3wdsubGiven) + model->BSIM3wdsub = 0.0; + if (!model->BSIM3wvth0Given) + model->BSIM3wvth0 = 0.0; + if (!model->BSIM3wuaGiven) + model->BSIM3wua = 0.0; + if (!model->BSIM3wua1Given) + model->BSIM3wua1 = 0.0; + if (!model->BSIM3wubGiven) + model->BSIM3wub = 0.0; + if (!model->BSIM3wub1Given) + model->BSIM3wub1 = 0.0; + if (!model->BSIM3wucGiven) + model->BSIM3wuc = 0.0; + if (!model->BSIM3wuc1Given) + model->BSIM3wuc1 = 0.0; + if (!model->BSIM3wu0Given) + model->BSIM3wu0 = 0.0; + if (!model->BSIM3wuteGiven) + model->BSIM3wute = 0.0; + if (!model->BSIM3wvoffGiven) + model->BSIM3wvoff = 0.0; + if (!model->BSIM3wdeltaGiven) + model->BSIM3wdelta = 0.0; + if (!model->BSIM3wrdswGiven) + model->BSIM3wrdsw = 0.0; + if (!model->BSIM3wprwbGiven) + model->BSIM3wprwb = 0.0; + if (!model->BSIM3wprwgGiven) + model->BSIM3wprwg = 0.0; + if (!model->BSIM3wprtGiven) + model->BSIM3wprt = 0.0; + if (!model->BSIM3weta0Given) + model->BSIM3weta0 = 0.0; + if (!model->BSIM3wetabGiven) + model->BSIM3wetab = 0.0; + if (!model->BSIM3wpclmGiven) + model->BSIM3wpclm = 0.0; + if (!model->BSIM3wpdibl1Given) + model->BSIM3wpdibl1 = 0.0; + if (!model->BSIM3wpdibl2Given) + model->BSIM3wpdibl2 = 0.0; + if (!model->BSIM3wpdiblbGiven) + model->BSIM3wpdiblb = 0.0; + if (!model->BSIM3wpscbe1Given) + model->BSIM3wpscbe1 = 0.0; + if (!model->BSIM3wpscbe2Given) + model->BSIM3wpscbe2 = 0.0; + if (!model->BSIM3wpvagGiven) + model->BSIM3wpvag = 0.0; + if (!model->BSIM3wwrGiven) + model->BSIM3wwr = 0.0; + if (!model->BSIM3wdwgGiven) + model->BSIM3wdwg = 0.0; + if (!model->BSIM3wdwbGiven) + model->BSIM3wdwb = 0.0; + if (!model->BSIM3wb0Given) + model->BSIM3wb0 = 0.0; + if (!model->BSIM3wb1Given) + model->BSIM3wb1 = 0.0; + if (!model->BSIM3walpha0Given) + model->BSIM3walpha0 = 0.0; + if (!model->BSIM3walpha1Given) + model->BSIM3walpha1 = 0.0; + if (!model->BSIM3wbeta0Given) + model->BSIM3wbeta0 = 0.0; + if (!model->BSIM3wvfbGiven) + model->BSIM3wvfb = 0.0; + + if (!model->BSIM3welmGiven) + model->BSIM3welm = 0.0; + if (!model->BSIM3wcgslGiven) + model->BSIM3wcgsl = 0.0; + if (!model->BSIM3wcgdlGiven) + model->BSIM3wcgdl = 0.0; + if (!model->BSIM3wckappaGiven) + model->BSIM3wckappa = 0.0; + if (!model->BSIM3wcfGiven) + model->BSIM3wcf = 0.0; + if (!model->BSIM3wclcGiven) + model->BSIM3wclc = 0.0; + if (!model->BSIM3wcleGiven) + model->BSIM3wcle = 0.0; + if (!model->BSIM3wvfbcvGiven) + model->BSIM3wvfbcv = 0.0; + if (!model->BSIM3wacdeGiven) + model->BSIM3wacde = 0.0; + if (!model->BSIM3wmoinGiven) + model->BSIM3wmoin = 0.0; + if (!model->BSIM3wnoffGiven) + model->BSIM3wnoff = 0.0; + if (!model->BSIM3wvoffcvGiven) + model->BSIM3wvoffcv = 0.0; + + /* Cross-term dependence */ + if (!model->BSIM3pcdscGiven) + model->BSIM3pcdsc = 0.0; + if (!model->BSIM3pcdscbGiven) + model->BSIM3pcdscb = 0.0; + if (!model->BSIM3pcdscdGiven) + model->BSIM3pcdscd = 0.0; + if (!model->BSIM3pcitGiven) + model->BSIM3pcit = 0.0; + if (!model->BSIM3pnfactorGiven) + model->BSIM3pnfactor = 0.0; + if (!model->BSIM3pxjGiven) + model->BSIM3pxj = 0.0; + if (!model->BSIM3pvsatGiven) + model->BSIM3pvsat = 0.0; + if (!model->BSIM3patGiven) + model->BSIM3pat = 0.0; + if (!model->BSIM3pa0Given) + model->BSIM3pa0 = 0.0; + + if (!model->BSIM3pagsGiven) + model->BSIM3pags = 0.0; + if (!model->BSIM3pa1Given) + model->BSIM3pa1 = 0.0; + if (!model->BSIM3pa2Given) + model->BSIM3pa2 = 0.0; + if (!model->BSIM3pketaGiven) + model->BSIM3pketa = 0.0; + if (!model->BSIM3pnsubGiven) + model->BSIM3pnsub = 0.0; + if (!model->BSIM3pnpeakGiven) + model->BSIM3pnpeak = 0.0; + if (!model->BSIM3pngateGiven) + model->BSIM3pngate = 0.0; + if (!model->BSIM3pvbmGiven) + model->BSIM3pvbm = 0.0; + if (!model->BSIM3pxtGiven) + model->BSIM3pxt = 0.0; + if (!model->BSIM3pkt1Given) + model->BSIM3pkt1 = 0.0; + if (!model->BSIM3pkt1lGiven) + model->BSIM3pkt1l = 0.0; + if (!model->BSIM3pkt2Given) + model->BSIM3pkt2 = 0.0; + if (!model->BSIM3pk3Given) + model->BSIM3pk3 = 0.0; + if (!model->BSIM3pk3bGiven) + model->BSIM3pk3b = 0.0; + if (!model->BSIM3pw0Given) + model->BSIM3pw0 = 0.0; + if (!model->BSIM3pnlxGiven) + model->BSIM3pnlx = 0.0; + if (!model->BSIM3pdvt0Given) + model->BSIM3pdvt0 = 0.0; + if (!model->BSIM3pdvt1Given) + model->BSIM3pdvt1 = 0.0; + if (!model->BSIM3pdvt2Given) + model->BSIM3pdvt2 = 0.0; + if (!model->BSIM3pdvt0wGiven) + model->BSIM3pdvt0w = 0.0; + if (!model->BSIM3pdvt1wGiven) + model->BSIM3pdvt1w = 0.0; + if (!model->BSIM3pdvt2wGiven) + model->BSIM3pdvt2w = 0.0; + if (!model->BSIM3pdroutGiven) + model->BSIM3pdrout = 0.0; + if (!model->BSIM3pdsubGiven) + model->BSIM3pdsub = 0.0; + if (!model->BSIM3pvth0Given) + model->BSIM3pvth0 = 0.0; + if (!model->BSIM3puaGiven) + model->BSIM3pua = 0.0; + if (!model->BSIM3pua1Given) + model->BSIM3pua1 = 0.0; + if (!model->BSIM3pubGiven) + model->BSIM3pub = 0.0; + if (!model->BSIM3pub1Given) + model->BSIM3pub1 = 0.0; + if (!model->BSIM3pucGiven) + model->BSIM3puc = 0.0; + if (!model->BSIM3puc1Given) + model->BSIM3puc1 = 0.0; + if (!model->BSIM3pu0Given) + model->BSIM3pu0 = 0.0; + if (!model->BSIM3puteGiven) + model->BSIM3pute = 0.0; + if (!model->BSIM3pvoffGiven) + model->BSIM3pvoff = 0.0; + if (!model->BSIM3pdeltaGiven) + model->BSIM3pdelta = 0.0; + if (!model->BSIM3prdswGiven) + model->BSIM3prdsw = 0.0; + if (!model->BSIM3pprwbGiven) + model->BSIM3pprwb = 0.0; + if (!model->BSIM3pprwgGiven) + model->BSIM3pprwg = 0.0; + if (!model->BSIM3pprtGiven) + model->BSIM3pprt = 0.0; + if (!model->BSIM3peta0Given) + model->BSIM3peta0 = 0.0; + if (!model->BSIM3petabGiven) + model->BSIM3petab = 0.0; + if (!model->BSIM3ppclmGiven) + model->BSIM3ppclm = 0.0; + if (!model->BSIM3ppdibl1Given) + model->BSIM3ppdibl1 = 0.0; + if (!model->BSIM3ppdibl2Given) + model->BSIM3ppdibl2 = 0.0; + if (!model->BSIM3ppdiblbGiven) + model->BSIM3ppdiblb = 0.0; + if (!model->BSIM3ppscbe1Given) + model->BSIM3ppscbe1 = 0.0; + if (!model->BSIM3ppscbe2Given) + model->BSIM3ppscbe2 = 0.0; + if (!model->BSIM3ppvagGiven) + model->BSIM3ppvag = 0.0; + if (!model->BSIM3pwrGiven) + model->BSIM3pwr = 0.0; + if (!model->BSIM3pdwgGiven) + model->BSIM3pdwg = 0.0; + if (!model->BSIM3pdwbGiven) + model->BSIM3pdwb = 0.0; + if (!model->BSIM3pb0Given) + model->BSIM3pb0 = 0.0; + if (!model->BSIM3pb1Given) + model->BSIM3pb1 = 0.0; + if (!model->BSIM3palpha0Given) + model->BSIM3palpha0 = 0.0; + if (!model->BSIM3palpha1Given) + model->BSIM3palpha1 = 0.0; + if (!model->BSIM3pbeta0Given) + model->BSIM3pbeta0 = 0.0; + if (!model->BSIM3pvfbGiven) + model->BSIM3pvfb = 0.0; + + if (!model->BSIM3pelmGiven) + model->BSIM3pelm = 0.0; + if (!model->BSIM3pcgslGiven) + model->BSIM3pcgsl = 0.0; + if (!model->BSIM3pcgdlGiven) + model->BSIM3pcgdl = 0.0; + if (!model->BSIM3pckappaGiven) + model->BSIM3pckappa = 0.0; + if (!model->BSIM3pcfGiven) + model->BSIM3pcf = 0.0; + if (!model->BSIM3pclcGiven) + model->BSIM3pclc = 0.0; + if (!model->BSIM3pcleGiven) + model->BSIM3pcle = 0.0; + if (!model->BSIM3pvfbcvGiven) + model->BSIM3pvfbcv = 0.0; + if (!model->BSIM3pacdeGiven) + model->BSIM3pacde = 0.0; + if (!model->BSIM3pmoinGiven) + model->BSIM3pmoin = 0.0; + if (!model->BSIM3pnoffGiven) + model->BSIM3pnoff = 0.0; + if (!model->BSIM3pvoffcvGiven) + model->BSIM3pvoffcv = 0.0; + + /* unit degree celcius */ + if (!model->BSIM3tnomGiven) + model->BSIM3tnom = ckt->CKTnomTemp; + else + model->BSIM3tnom = model->BSIM3tnom + 273.15; + if (!model->BSIM3LintGiven) + model->BSIM3Lint = 0.0; + if (!model->BSIM3LlGiven) + model->BSIM3Ll = 0.0; + if (!model->BSIM3LlcGiven) + model->BSIM3Llc = model->BSIM3Ll; + if (!model->BSIM3LlnGiven) + model->BSIM3Lln = 1.0; + if (!model->BSIM3LwGiven) + model->BSIM3Lw = 0.0; + if (!model->BSIM3LwcGiven) + model->BSIM3Lwc = model->BSIM3Lw; + if (!model->BSIM3LwnGiven) + model->BSIM3Lwn = 1.0; + if (!model->BSIM3LwlGiven) + model->BSIM3Lwl = 0.0; + if (!model->BSIM3LwlcGiven) + model->BSIM3Lwlc = model->BSIM3Lwl; + if (!model->BSIM3LminGiven) + model->BSIM3Lmin = 0.0; + if (!model->BSIM3LmaxGiven) + model->BSIM3Lmax = 1.0; + if (!model->BSIM3WintGiven) + model->BSIM3Wint = 0.0; + if (!model->BSIM3WlGiven) + model->BSIM3Wl = 0.0; + if (!model->BSIM3WlcGiven) + model->BSIM3Wlc = model->BSIM3Wl; + if (!model->BSIM3WlnGiven) + model->BSIM3Wln = 1.0; + if (!model->BSIM3WwGiven) + model->BSIM3Ww = 0.0; + if (!model->BSIM3WwcGiven) + model->BSIM3Wwc = model->BSIM3Ww; + if (!model->BSIM3WwnGiven) + model->BSIM3Wwn = 1.0; + if (!model->BSIM3WwlGiven) + model->BSIM3Wwl = 0.0; + if (!model->BSIM3WwlcGiven) + model->BSIM3Wwlc = model->BSIM3Wwl; + if (!model->BSIM3WminGiven) + model->BSIM3Wmin = 0.0; + if (!model->BSIM3WmaxGiven) + model->BSIM3Wmax = 1.0; + if (!model->BSIM3dwcGiven) + model->BSIM3dwc = model->BSIM3Wint; + if (!model->BSIM3dlcGiven) + model->BSIM3dlc = model->BSIM3Lint; + if (!model->BSIM3cfGiven) + model->BSIM3cf = 2.0 * EPSOX / M_PI + * log(1.0 + 0.4e-6 / model->BSIM3tox); + if (!model->BSIM3cgdoGiven) + { if (model->BSIM3dlcGiven && (model->BSIM3dlc > 0.0)) + { model->BSIM3cgdo = model->BSIM3dlc * model->BSIM3cox + - model->BSIM3cgdl ; + } + else + model->BSIM3cgdo = 0.6 * model->BSIM3xj * model->BSIM3cox; + } + if (!model->BSIM3cgsoGiven) + { if (model->BSIM3dlcGiven && (model->BSIM3dlc > 0.0)) + { model->BSIM3cgso = model->BSIM3dlc * model->BSIM3cox + - model->BSIM3cgsl ; + } + else + model->BSIM3cgso = 0.6 * model->BSIM3xj * model->BSIM3cox; + } + + if (!model->BSIM3cgboGiven) + { model->BSIM3cgbo = 2.0 * model->BSIM3dwc * model->BSIM3cox; + } + if (!model->BSIM3xpartGiven) + model->BSIM3xpart = 0.0; + if (!model->BSIM3sheetResistanceGiven) + model->BSIM3sheetResistance = 0.0; + if (!model->BSIM3unitAreaJctCapGiven) + model->BSIM3unitAreaJctCap = 5.0E-4; + if (!model->BSIM3unitLengthSidewallJctCapGiven) + model->BSIM3unitLengthSidewallJctCap = 5.0E-10; + if (!model->BSIM3unitLengthGateSidewallJctCapGiven) + model->BSIM3unitLengthGateSidewallJctCap = model->BSIM3unitLengthSidewallJctCap ; + if (!model->BSIM3jctSatCurDensityGiven) + model->BSIM3jctSatCurDensity = 1.0E-4; + if (!model->BSIM3jctSidewallSatCurDensityGiven) + model->BSIM3jctSidewallSatCurDensity = 0.0; + if (!model->BSIM3bulkJctPotentialGiven) + model->BSIM3bulkJctPotential = 1.0; + if (!model->BSIM3sidewallJctPotentialGiven) + model->BSIM3sidewallJctPotential = 1.0; + if (!model->BSIM3GatesidewallJctPotentialGiven) + model->BSIM3GatesidewallJctPotential = model->BSIM3sidewallJctPotential; + if (!model->BSIM3bulkJctBotGradingCoeffGiven) + model->BSIM3bulkJctBotGradingCoeff = 0.5; + if (!model->BSIM3bulkJctSideGradingCoeffGiven) + model->BSIM3bulkJctSideGradingCoeff = 0.33; + if (!model->BSIM3bulkJctGateSideGradingCoeffGiven) + model->BSIM3bulkJctGateSideGradingCoeff = model->BSIM3bulkJctSideGradingCoeff; + if (!model->BSIM3jctEmissionCoeffGiven) + model->BSIM3jctEmissionCoeff = 1.0; + if (!model->BSIM3jctTempExponentGiven) + model->BSIM3jctTempExponent = 3.0; + if (!model->BSIM3oxideTrapDensityAGiven) + { if (model->BSIM3type == NMOS) + model->BSIM3oxideTrapDensityA = 1e20; + else + model->BSIM3oxideTrapDensityA=9.9e18; + } + if (!model->BSIM3oxideTrapDensityBGiven) + { if (model->BSIM3type == NMOS) + model->BSIM3oxideTrapDensityB = 5e4; + else + model->BSIM3oxideTrapDensityB = 2.4e3; + } + if (!model->BSIM3oxideTrapDensityCGiven) + { if (model->BSIM3type == NMOS) + model->BSIM3oxideTrapDensityC = -1.4e-12; + else + model->BSIM3oxideTrapDensityC = 1.4e-12; + + } + if (!model->BSIM3emGiven) + model->BSIM3em = 4.1e7; /* V/m */ + if (!model->BSIM3efGiven) + model->BSIM3ef = 1.0; + if (!model->BSIM3afGiven) + model->BSIM3af = 1.0; + if (!model->BSIM3kfGiven) + model->BSIM3kf = 0.0; + /* loop through all the instances of the model */ + for (here = model->BSIM3instances; here != NULL ; + here=here->BSIM3nextInstance) + { + if (here->BSIM3owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->BSIM3states = *states; + *states += BSIM3numStates; + } + + /* perform the parameter defaulting */ + if (!here->BSIM3drainAreaGiven) + here->BSIM3drainArea = 0.0; + if (!here->BSIM3drainPerimeterGiven) + here->BSIM3drainPerimeter = 0.0; + if (!here->BSIM3drainSquaresGiven) + here->BSIM3drainSquares = 1.0; + if (!here->BSIM3icVBSGiven) + here->BSIM3icVBS = 0.0; + if (!here->BSIM3icVDSGiven) + here->BSIM3icVDS = 0.0; + if (!here->BSIM3icVGSGiven) + here->BSIM3icVGS = 0.0; + if (!here->BSIM3lGiven) + here->BSIM3l = 5.0e-6; + if (!here->BSIM3sourceAreaGiven) + here->BSIM3sourceArea = 0.0; + if (!here->BSIM3sourcePerimeterGiven) + here->BSIM3sourcePerimeter = 0.0; + if (!here->BSIM3sourceSquaresGiven) + here->BSIM3sourceSquares = 1.0; + if (!here->BSIM3wGiven) + here->BSIM3w = 5.0e-6; + if (!here->BSIM3nqsModGiven) + here->BSIM3nqsMod = 0; + + /* process drain series resistance */ + if ((model->BSIM3sheetResistance > 0.0) && + (here->BSIM3drainSquares > 0.0 ) && + (here->BSIM3dNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3name,"drain"); + if(error) return(error); + here->BSIM3dNodePrime = tmp->number; + } + else + { here->BSIM3dNodePrime = here->BSIM3dNode; + } + + /* process source series resistance */ + if ((model->BSIM3sheetResistance > 0.0) && + (here->BSIM3sourceSquares > 0.0 ) && + (here->BSIM3sNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3name,"source"); + if(error) return(error); + here->BSIM3sNodePrime = tmp->number; + } + else + { here->BSIM3sNodePrime = here->BSIM3sNode; + } + + /* internal charge node */ + + if ((here->BSIM3nqsMod) && (here->BSIM3qNode == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3name,"charge"); + if(error) return(error); + here->BSIM3qNode = tmp->number; + } + else + { here->BSIM3qNode = 0; + } + + /* set Sparse Matrix Pointers */ + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(BSIM3DdPtr, BSIM3dNode, BSIM3dNode) + TSTALLOC(BSIM3GgPtr, BSIM3gNode, BSIM3gNode) + TSTALLOC(BSIM3SsPtr, BSIM3sNode, BSIM3sNode) + TSTALLOC(BSIM3BbPtr, BSIM3bNode, BSIM3bNode) + TSTALLOC(BSIM3DPdpPtr, BSIM3dNodePrime, BSIM3dNodePrime) + TSTALLOC(BSIM3SPspPtr, BSIM3sNodePrime, BSIM3sNodePrime) + TSTALLOC(BSIM3DdpPtr, BSIM3dNode, BSIM3dNodePrime) + TSTALLOC(BSIM3GbPtr, BSIM3gNode, BSIM3bNode) + TSTALLOC(BSIM3GdpPtr, BSIM3gNode, BSIM3dNodePrime) + TSTALLOC(BSIM3GspPtr, BSIM3gNode, BSIM3sNodePrime) + TSTALLOC(BSIM3SspPtr, BSIM3sNode, BSIM3sNodePrime) + TSTALLOC(BSIM3BdpPtr, BSIM3bNode, BSIM3dNodePrime) + TSTALLOC(BSIM3BspPtr, BSIM3bNode, BSIM3sNodePrime) + TSTALLOC(BSIM3DPspPtr, BSIM3dNodePrime, BSIM3sNodePrime) + TSTALLOC(BSIM3DPdPtr, BSIM3dNodePrime, BSIM3dNode) + TSTALLOC(BSIM3BgPtr, BSIM3bNode, BSIM3gNode) + TSTALLOC(BSIM3DPgPtr, BSIM3dNodePrime, BSIM3gNode) + TSTALLOC(BSIM3SPgPtr, BSIM3sNodePrime, BSIM3gNode) + TSTALLOC(BSIM3SPsPtr, BSIM3sNodePrime, BSIM3sNode) + TSTALLOC(BSIM3DPbPtr, BSIM3dNodePrime, BSIM3bNode) + TSTALLOC(BSIM3SPbPtr, BSIM3sNodePrime, BSIM3bNode) + TSTALLOC(BSIM3SPdpPtr, BSIM3sNodePrime, BSIM3dNodePrime) + + TSTALLOC(BSIM3QqPtr, BSIM3qNode, BSIM3qNode) + + TSTALLOC(BSIM3QdpPtr, BSIM3qNode, BSIM3dNodePrime) + TSTALLOC(BSIM3QspPtr, BSIM3qNode, BSIM3sNodePrime) + TSTALLOC(BSIM3QgPtr, BSIM3qNode, BSIM3gNode) + TSTALLOC(BSIM3QbPtr, BSIM3qNode, BSIM3bNode) + TSTALLOC(BSIM3DPqPtr, BSIM3dNodePrime, BSIM3qNode) + TSTALLOC(BSIM3SPqPtr, BSIM3sNodePrime, BSIM3qNode) + TSTALLOC(BSIM3GqPtr, BSIM3gNode, BSIM3qNode) + TSTALLOC(BSIM3BqPtr, BSIM3bNode, BSIM3qNode) + + } + } + return(OK); +} + + + +int +BSIM3unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + BSIM3model *model; + BSIM3instance *here; + + for (model = (BSIM3model *)inModel; model != NULL; + model = model->BSIM3nextModel) + { + for (here = model->BSIM3instances; here != NULL; + here=here->BSIM3nextInstance) + { + if (here->BSIM3dNodePrime + && here->BSIM3dNodePrime != here->BSIM3dNode) + { + CKTdltNNum(ckt, here->BSIM3dNodePrime); + here->BSIM3dNodePrime = 0; + } + if (here->BSIM3sNodePrime + && here->BSIM3sNodePrime != here->BSIM3sNode) + { + CKTdltNNum(ckt, here->BSIM3sNodePrime); + here->BSIM3sNodePrime = 0; + } + } + } +#endif + return OK; +} + diff --git a/src/spicelib/devices/bsim3/b3temp.c b/src/spicelib/devices/bsim3/b3temp.c new file mode 100644 index 000000000..9d48f0f0a --- /dev/null +++ b/src/spicelib/devices/bsim3/b3temp.c @@ -0,0 +1,875 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.3 1999/08/28 21:00:03 manu + Big commit - merged ngspice.h, misc.h and util.h - protoized fte + + Revision 1.2 1999/08/23 18:14:39 manu + Added cleanup patch by Arno Peters - also added 'make check' to configure + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/*********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3temp.c +**********/ +/* Lmin, Lmax, Wmin, Wmax */ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim3def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +#define Kb 1.3806226e-23 +#define KboQ 8.617087e-5 /* Kb / q where q = 1.60219e-19 */ +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +/* #define PI 3.141592654 */ +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define Charge_q 1.60219e-19 + + +/* ARGSUSED */ +int +BSIM3temp(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +register BSIM3model *model = (BSIM3model*) inModel; +register BSIM3instance *here; +struct bsim3SizeDependParam *pSizeDependParamKnot, *pLastKnot, *pParam; +double tmp, tmp1, tmp2, tmp3, Eg, Eg0, ni, T0, T1, T2, T3, T4, T5, Ldrn, Wdrn; +double delTemp, Temp, TRatio, Inv_L, Inv_W, Inv_LW, Vtm0, Tnom; +double Nvtm, SourceSatCurrent, DrainSatCurrent; +int Size_Not_Found; + + /* loop through all the BSIM3 device models */ + for (; model != NULL; model = model->BSIM3nextModel) + { Temp = ckt->CKTtemp; + if (model->BSIM3bulkJctPotential < 0.1) + { model->BSIM3bulkJctPotential = 0.1; + fprintf(stderr, "Given pb is less than 0.1. Pb is set to 0.1.\n"); + } + if (model->BSIM3sidewallJctPotential < 0.1) + { model->BSIM3sidewallJctPotential = 0.1; + fprintf(stderr, "Given pbsw is less than 0.1. Pbsw is set to 0.1.\n"); + } + if (model->BSIM3GatesidewallJctPotential < 0.1) + { model->BSIM3GatesidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswg is less than 0.1. Pbswg is set to 0.1.\n"); + } + model->pSizeDependParamKnot = NULL; + pLastKnot = NULL; + + Tnom = model->BSIM3tnom; + TRatio = Temp / Tnom; + + model->BSIM3vcrit = CONSTvt0 * log(CONSTvt0 / (CONSTroot2 * 1.0e-14)); + model->BSIM3factor1 = sqrt(EPSSI / EPSOX * model->BSIM3tox); + + Vtm0 = KboQ * Tnom; + Eg0 = 1.16 - 7.02e-4 * Tnom * Tnom / (Tnom + 1108.0); + ni = 1.45e10 * (Tnom / 300.15) * sqrt(Tnom / 300.15) + * exp(21.5565981 - Eg0 / (2.0 * Vtm0)); + + model->BSIM3vtm = KboQ * Temp; + Eg = 1.16 - 7.02e-4 * Temp * Temp / (Temp + 1108.0); + if (Temp != Tnom) + { T0 = Eg0 / Vtm0 - Eg / model->BSIM3vtm + model->BSIM3jctTempExponent + * log(Temp / Tnom); + T1 = exp(T0 / model->BSIM3jctEmissionCoeff); + model->BSIM3jctTempSatCurDensity = model->BSIM3jctSatCurDensity + * T1; + model->BSIM3jctSidewallTempSatCurDensity + = model->BSIM3jctSidewallSatCurDensity * T1; + } + else + { model->BSIM3jctTempSatCurDensity = model->BSIM3jctSatCurDensity; + model->BSIM3jctSidewallTempSatCurDensity + = model->BSIM3jctSidewallSatCurDensity; + } + + if (model->BSIM3jctTempSatCurDensity < 0.0) + model->BSIM3jctTempSatCurDensity = 0.0; + if (model->BSIM3jctSidewallTempSatCurDensity < 0.0) + model->BSIM3jctSidewallTempSatCurDensity = 0.0; + + /* Temperature dependence of D/B and S/B diode capacitance begins */ + delTemp = ckt->CKTtemp - model->BSIM3tnom; + T0 = model->BSIM3tcj * delTemp; + if (T0 >= -1.0) + { model->BSIM3unitAreaJctCap *= 1.0 + T0; + } + else if (model->BSIM3unitAreaJctCap > 0.0) + { model->BSIM3unitAreaJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cj to be negative. Cj is clamped to zero.\n"); + } + T0 = model->BSIM3tcjsw * delTemp; + if (T0 >= -1.0) + { model->BSIM3unitLengthSidewallJctCap *= 1.0 + T0; + } + else if (model->BSIM3unitLengthSidewallJctCap > 0.0) + { model->BSIM3unitLengthSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjsw to be negative. Cjsw is clamped to zero.\n"); + } + T0 = model->BSIM3tcjswg * delTemp; + if (T0 >= -1.0) + { model->BSIM3unitLengthGateSidewallJctCap *= 1.0 + T0; + } + else if (model->BSIM3unitLengthGateSidewallJctCap > 0.0) + { model->BSIM3unitLengthGateSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjswg to be negative. Cjswg is clamped to zero.\n"); + } + + model->BSIM3PhiB = model->BSIM3bulkJctPotential + - model->BSIM3tpb * delTemp; + if (model->BSIM3PhiB < 0.01) + { model->BSIM3PhiB = 0.01; + fprintf(stderr, "Temperature effect has caused pb to be less than 0.01. Pb is clamped to 0.01.\n"); + } + model->BSIM3PhiBSW = model->BSIM3sidewallJctPotential + - model->BSIM3tpbsw * delTemp; + if (model->BSIM3PhiBSW <= 0.01) + { model->BSIM3PhiBSW = 0.01; + fprintf(stderr, "Temperature effect has caused pbsw to be less than 0.01. Pbsw is clamped to 0.01.\n"); + } + model->BSIM3PhiBSWG = model->BSIM3GatesidewallJctPotential + - model->BSIM3tpbswg * delTemp; + if (model->BSIM3PhiBSWG <= 0.01) + { model->BSIM3PhiBSWG = 0.01; + fprintf(stderr, "Temperature effect has caused pbswg to be less than 0.01. Pbswg is clamped to 0.01.\n"); + } + /* End of junction capacitance */ + + /* loop through all the instances of the model */ + /* MCJ: Length and Width not initialized */ + for (here = model->BSIM3instances; here != NULL; + here = here->BSIM3nextInstance) + { + if (here->BSIM3owner != ARCHme) continue; + pSizeDependParamKnot = model->pSizeDependParamKnot; + Size_Not_Found = 1; + while ((pSizeDependParamKnot != NULL) && Size_Not_Found) + { if ((here->BSIM3l == pSizeDependParamKnot->Length) + && (here->BSIM3w == pSizeDependParamKnot->Width)) + { Size_Not_Found = 0; + here->pParam = pSizeDependParamKnot; + } + else + { pLastKnot = pSizeDependParamKnot; + pSizeDependParamKnot = pSizeDependParamKnot->pNext; + } + } + + if (Size_Not_Found) + { pParam = (struct bsim3SizeDependParam *)malloc( + sizeof(struct bsim3SizeDependParam)); + if (pLastKnot == NULL) + model->pSizeDependParamKnot = pParam; + else + pLastKnot->pNext = pParam; + pParam->pNext = NULL; + here->pParam = pParam; + + Ldrn = here->BSIM3l; + Wdrn = here->BSIM3w; + pParam->Length = Ldrn; + pParam->Width = Wdrn; + + T0 = pow(Ldrn, model->BSIM3Lln); + T1 = pow(Wdrn, model->BSIM3Lwn); + tmp1 = model->BSIM3Ll / T0 + model->BSIM3Lw / T1 + + model->BSIM3Lwl / (T0 * T1); + pParam->BSIM3dl = model->BSIM3Lint + tmp1; + tmp2 = model->BSIM3Llc / T0 + model->BSIM3Lwc / T1 + + model->BSIM3Lwlc / (T0 * T1); + pParam->BSIM3dlc = model->BSIM3dlc + tmp2; + + T2 = pow(Ldrn, model->BSIM3Wln); + T3 = pow(Wdrn, model->BSIM3Wwn); + tmp1 = model->BSIM3Wl / T2 + model->BSIM3Ww / T3 + + model->BSIM3Wwl / (T2 * T3); + pParam->BSIM3dw = model->BSIM3Wint + tmp1; + tmp2 = model->BSIM3Wlc / T2 + model->BSIM3Wwc / T3 + + model->BSIM3Wwlc / (T2 * T3); + pParam->BSIM3dwc = model->BSIM3dwc + tmp2; + + pParam->BSIM3leff = here->BSIM3l - 2.0 * pParam->BSIM3dl; + if (pParam->BSIM3leff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3modName; + namarray[1] = here->BSIM3name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3: mosfet %s, model %s: Effective channel length <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3weff = here->BSIM3w - 2.0 * pParam->BSIM3dw; + if (pParam->BSIM3weff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3modName; + namarray[1] = here->BSIM3name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3: mosfet %s, model %s: Effective channel width <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3leffCV = here->BSIM3l - 2.0 * pParam->BSIM3dlc; + if (pParam->BSIM3leffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3modName; + namarray[1] = here->BSIM3name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3: mosfet %s, model %s: Effective channel length for C-V <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3weffCV = here->BSIM3w - 2.0 * pParam->BSIM3dwc; + if (pParam->BSIM3weffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3modName; + namarray[1] = here->BSIM3name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3: mosfet %s, model %s: Effective channel width for C-V <= 0", + namarray); + return(E_BADPARM); + } + + + if (model->BSIM3binUnit == 1) + { Inv_L = 1.0e-6 / pParam->BSIM3leff; + Inv_W = 1.0e-6 / pParam->BSIM3weff; + Inv_LW = 1.0e-12 / (pParam->BSIM3leff + * pParam->BSIM3weff); + } + else + { Inv_L = 1.0 / pParam->BSIM3leff; + Inv_W = 1.0 / pParam->BSIM3weff; + Inv_LW = 1.0 / (pParam->BSIM3leff + * pParam->BSIM3weff); + } + pParam->BSIM3cdsc = model->BSIM3cdsc + + model->BSIM3lcdsc * Inv_L + + model->BSIM3wcdsc * Inv_W + + model->BSIM3pcdsc * Inv_LW; + pParam->BSIM3cdscb = model->BSIM3cdscb + + model->BSIM3lcdscb * Inv_L + + model->BSIM3wcdscb * Inv_W + + model->BSIM3pcdscb * Inv_LW; + + pParam->BSIM3cdscd = model->BSIM3cdscd + + model->BSIM3lcdscd * Inv_L + + model->BSIM3wcdscd * Inv_W + + model->BSIM3pcdscd * Inv_LW; + + pParam->BSIM3cit = model->BSIM3cit + + model->BSIM3lcit * Inv_L + + model->BSIM3wcit * Inv_W + + model->BSIM3pcit * Inv_LW; + pParam->BSIM3nfactor = model->BSIM3nfactor + + model->BSIM3lnfactor * Inv_L + + model->BSIM3wnfactor * Inv_W + + model->BSIM3pnfactor * Inv_LW; + pParam->BSIM3xj = model->BSIM3xj + + model->BSIM3lxj * Inv_L + + model->BSIM3wxj * Inv_W + + model->BSIM3pxj * Inv_LW; + pParam->BSIM3vsat = model->BSIM3vsat + + model->BSIM3lvsat * Inv_L + + model->BSIM3wvsat * Inv_W + + model->BSIM3pvsat * Inv_LW; + pParam->BSIM3at = model->BSIM3at + + model->BSIM3lat * Inv_L + + model->BSIM3wat * Inv_W + + model->BSIM3pat * Inv_LW; + pParam->BSIM3a0 = model->BSIM3a0 + + model->BSIM3la0 * Inv_L + + model->BSIM3wa0 * Inv_W + + model->BSIM3pa0 * Inv_LW; + + pParam->BSIM3ags = model->BSIM3ags + + model->BSIM3lags * Inv_L + + model->BSIM3wags * Inv_W + + model->BSIM3pags * Inv_LW; + + pParam->BSIM3a1 = model->BSIM3a1 + + model->BSIM3la1 * Inv_L + + model->BSIM3wa1 * Inv_W + + model->BSIM3pa1 * Inv_LW; + pParam->BSIM3a2 = model->BSIM3a2 + + model->BSIM3la2 * Inv_L + + model->BSIM3wa2 * Inv_W + + model->BSIM3pa2 * Inv_LW; + pParam->BSIM3keta = model->BSIM3keta + + model->BSIM3lketa * Inv_L + + model->BSIM3wketa * Inv_W + + model->BSIM3pketa * Inv_LW; + pParam->BSIM3nsub = model->BSIM3nsub + + model->BSIM3lnsub * Inv_L + + model->BSIM3wnsub * Inv_W + + model->BSIM3pnsub * Inv_LW; + pParam->BSIM3npeak = model->BSIM3npeak + + model->BSIM3lnpeak * Inv_L + + model->BSIM3wnpeak * Inv_W + + model->BSIM3pnpeak * Inv_LW; + pParam->BSIM3ngate = model->BSIM3ngate + + model->BSIM3lngate * Inv_L + + model->BSIM3wngate * Inv_W + + model->BSIM3pngate * Inv_LW; + pParam->BSIM3gamma1 = model->BSIM3gamma1 + + model->BSIM3lgamma1 * Inv_L + + model->BSIM3wgamma1 * Inv_W + + model->BSIM3pgamma1 * Inv_LW; + pParam->BSIM3gamma2 = model->BSIM3gamma2 + + model->BSIM3lgamma2 * Inv_L + + model->BSIM3wgamma2 * Inv_W + + model->BSIM3pgamma2 * Inv_LW; + pParam->BSIM3vbx = model->BSIM3vbx + + model->BSIM3lvbx * Inv_L + + model->BSIM3wvbx * Inv_W + + model->BSIM3pvbx * Inv_LW; + pParam->BSIM3vbm = model->BSIM3vbm + + model->BSIM3lvbm * Inv_L + + model->BSIM3wvbm * Inv_W + + model->BSIM3pvbm * Inv_LW; + pParam->BSIM3xt = model->BSIM3xt + + model->BSIM3lxt * Inv_L + + model->BSIM3wxt * Inv_W + + model->BSIM3pxt * Inv_LW; + pParam->BSIM3vfb = model->BSIM3vfb + + model->BSIM3lvfb * Inv_L + + model->BSIM3wvfb * Inv_W + + model->BSIM3pvfb * Inv_LW; + pParam->BSIM3k1 = model->BSIM3k1 + + model->BSIM3lk1 * Inv_L + + model->BSIM3wk1 * Inv_W + + model->BSIM3pk1 * Inv_LW; + pParam->BSIM3kt1 = model->BSIM3kt1 + + model->BSIM3lkt1 * Inv_L + + model->BSIM3wkt1 * Inv_W + + model->BSIM3pkt1 * Inv_LW; + pParam->BSIM3kt1l = model->BSIM3kt1l + + model->BSIM3lkt1l * Inv_L + + model->BSIM3wkt1l * Inv_W + + model->BSIM3pkt1l * Inv_LW; + pParam->BSIM3k2 = model->BSIM3k2 + + model->BSIM3lk2 * Inv_L + + model->BSIM3wk2 * Inv_W + + model->BSIM3pk2 * Inv_LW; + pParam->BSIM3kt2 = model->BSIM3kt2 + + model->BSIM3lkt2 * Inv_L + + model->BSIM3wkt2 * Inv_W + + model->BSIM3pkt2 * Inv_LW; + pParam->BSIM3k3 = model->BSIM3k3 + + model->BSIM3lk3 * Inv_L + + model->BSIM3wk3 * Inv_W + + model->BSIM3pk3 * Inv_LW; + pParam->BSIM3k3b = model->BSIM3k3b + + model->BSIM3lk3b * Inv_L + + model->BSIM3wk3b * Inv_W + + model->BSIM3pk3b * Inv_LW; + pParam->BSIM3w0 = model->BSIM3w0 + + model->BSIM3lw0 * Inv_L + + model->BSIM3ww0 * Inv_W + + model->BSIM3pw0 * Inv_LW; + pParam->BSIM3nlx = model->BSIM3nlx + + model->BSIM3lnlx * Inv_L + + model->BSIM3wnlx * Inv_W + + model->BSIM3pnlx * Inv_LW; + pParam->BSIM3dvt0 = model->BSIM3dvt0 + + model->BSIM3ldvt0 * Inv_L + + model->BSIM3wdvt0 * Inv_W + + model->BSIM3pdvt0 * Inv_LW; + pParam->BSIM3dvt1 = model->BSIM3dvt1 + + model->BSIM3ldvt1 * Inv_L + + model->BSIM3wdvt1 * Inv_W + + model->BSIM3pdvt1 * Inv_LW; + pParam->BSIM3dvt2 = model->BSIM3dvt2 + + model->BSIM3ldvt2 * Inv_L + + model->BSIM3wdvt2 * Inv_W + + model->BSIM3pdvt2 * Inv_LW; + pParam->BSIM3dvt0w = model->BSIM3dvt0w + + model->BSIM3ldvt0w * Inv_L + + model->BSIM3wdvt0w * Inv_W + + model->BSIM3pdvt0w * Inv_LW; + pParam->BSIM3dvt1w = model->BSIM3dvt1w + + model->BSIM3ldvt1w * Inv_L + + model->BSIM3wdvt1w * Inv_W + + model->BSIM3pdvt1w * Inv_LW; + pParam->BSIM3dvt2w = model->BSIM3dvt2w + + model->BSIM3ldvt2w * Inv_L + + model->BSIM3wdvt2w * Inv_W + + model->BSIM3pdvt2w * Inv_LW; + pParam->BSIM3drout = model->BSIM3drout + + model->BSIM3ldrout * Inv_L + + model->BSIM3wdrout * Inv_W + + model->BSIM3pdrout * Inv_LW; + pParam->BSIM3dsub = model->BSIM3dsub + + model->BSIM3ldsub * Inv_L + + model->BSIM3wdsub * Inv_W + + model->BSIM3pdsub * Inv_LW; + pParam->BSIM3vth0 = model->BSIM3vth0 + + model->BSIM3lvth0 * Inv_L + + model->BSIM3wvth0 * Inv_W + + model->BSIM3pvth0 * Inv_LW; + pParam->BSIM3ua = model->BSIM3ua + + model->BSIM3lua * Inv_L + + model->BSIM3wua * Inv_W + + model->BSIM3pua * Inv_LW; + pParam->BSIM3ua1 = model->BSIM3ua1 + + model->BSIM3lua1 * Inv_L + + model->BSIM3wua1 * Inv_W + + model->BSIM3pua1 * Inv_LW; + pParam->BSIM3ub = model->BSIM3ub + + model->BSIM3lub * Inv_L + + model->BSIM3wub * Inv_W + + model->BSIM3pub * Inv_LW; + pParam->BSIM3ub1 = model->BSIM3ub1 + + model->BSIM3lub1 * Inv_L + + model->BSIM3wub1 * Inv_W + + model->BSIM3pub1 * Inv_LW; + pParam->BSIM3uc = model->BSIM3uc + + model->BSIM3luc * Inv_L + + model->BSIM3wuc * Inv_W + + model->BSIM3puc * Inv_LW; + pParam->BSIM3uc1 = model->BSIM3uc1 + + model->BSIM3luc1 * Inv_L + + model->BSIM3wuc1 * Inv_W + + model->BSIM3puc1 * Inv_LW; + pParam->BSIM3u0 = model->BSIM3u0 + + model->BSIM3lu0 * Inv_L + + model->BSIM3wu0 * Inv_W + + model->BSIM3pu0 * Inv_LW; + pParam->BSIM3ute = model->BSIM3ute + + model->BSIM3lute * Inv_L + + model->BSIM3wute * Inv_W + + model->BSIM3pute * Inv_LW; + pParam->BSIM3voff = model->BSIM3voff + + model->BSIM3lvoff * Inv_L + + model->BSIM3wvoff * Inv_W + + model->BSIM3pvoff * Inv_LW; + pParam->BSIM3delta = model->BSIM3delta + + model->BSIM3ldelta * Inv_L + + model->BSIM3wdelta * Inv_W + + model->BSIM3pdelta * Inv_LW; + pParam->BSIM3rdsw = model->BSIM3rdsw + + model->BSIM3lrdsw * Inv_L + + model->BSIM3wrdsw * Inv_W + + model->BSIM3prdsw * Inv_LW; + pParam->BSIM3prwg = model->BSIM3prwg + + model->BSIM3lprwg * Inv_L + + model->BSIM3wprwg * Inv_W + + model->BSIM3pprwg * Inv_LW; + pParam->BSIM3prwb = model->BSIM3prwb + + model->BSIM3lprwb * Inv_L + + model->BSIM3wprwb * Inv_W + + model->BSIM3pprwb * Inv_LW; + pParam->BSIM3prt = model->BSIM3prt + + model->BSIM3lprt * Inv_L + + model->BSIM3wprt * Inv_W + + model->BSIM3pprt * Inv_LW; + pParam->BSIM3eta0 = model->BSIM3eta0 + + model->BSIM3leta0 * Inv_L + + model->BSIM3weta0 * Inv_W + + model->BSIM3peta0 * Inv_LW; + pParam->BSIM3etab = model->BSIM3etab + + model->BSIM3letab * Inv_L + + model->BSIM3wetab * Inv_W + + model->BSIM3petab * Inv_LW; + pParam->BSIM3pclm = model->BSIM3pclm + + model->BSIM3lpclm * Inv_L + + model->BSIM3wpclm * Inv_W + + model->BSIM3ppclm * Inv_LW; + pParam->BSIM3pdibl1 = model->BSIM3pdibl1 + + model->BSIM3lpdibl1 * Inv_L + + model->BSIM3wpdibl1 * Inv_W + + model->BSIM3ppdibl1 * Inv_LW; + pParam->BSIM3pdibl2 = model->BSIM3pdibl2 + + model->BSIM3lpdibl2 * Inv_L + + model->BSIM3wpdibl2 * Inv_W + + model->BSIM3ppdibl2 * Inv_LW; + pParam->BSIM3pdiblb = model->BSIM3pdiblb + + model->BSIM3lpdiblb * Inv_L + + model->BSIM3wpdiblb * Inv_W + + model->BSIM3ppdiblb * Inv_LW; + pParam->BSIM3pscbe1 = model->BSIM3pscbe1 + + model->BSIM3lpscbe1 * Inv_L + + model->BSIM3wpscbe1 * Inv_W + + model->BSIM3ppscbe1 * Inv_LW; + pParam->BSIM3pscbe2 = model->BSIM3pscbe2 + + model->BSIM3lpscbe2 * Inv_L + + model->BSIM3wpscbe2 * Inv_W + + model->BSIM3ppscbe2 * Inv_LW; + pParam->BSIM3pvag = model->BSIM3pvag + + model->BSIM3lpvag * Inv_L + + model->BSIM3wpvag * Inv_W + + model->BSIM3ppvag * Inv_LW; + pParam->BSIM3wr = model->BSIM3wr + + model->BSIM3lwr * Inv_L + + model->BSIM3wwr * Inv_W + + model->BSIM3pwr * Inv_LW; + pParam->BSIM3dwg = model->BSIM3dwg + + model->BSIM3ldwg * Inv_L + + model->BSIM3wdwg * Inv_W + + model->BSIM3pdwg * Inv_LW; + pParam->BSIM3dwb = model->BSIM3dwb + + model->BSIM3ldwb * Inv_L + + model->BSIM3wdwb * Inv_W + + model->BSIM3pdwb * Inv_LW; + pParam->BSIM3b0 = model->BSIM3b0 + + model->BSIM3lb0 * Inv_L + + model->BSIM3wb0 * Inv_W + + model->BSIM3pb0 * Inv_LW; + pParam->BSIM3b1 = model->BSIM3b1 + + model->BSIM3lb1 * Inv_L + + model->BSIM3wb1 * Inv_W + + model->BSIM3pb1 * Inv_LW; + pParam->BSIM3alpha0 = model->BSIM3alpha0 + + model->BSIM3lalpha0 * Inv_L + + model->BSIM3walpha0 * Inv_W + + model->BSIM3palpha0 * Inv_LW; + pParam->BSIM3alpha1 = model->BSIM3alpha1 + + model->BSIM3lalpha1 * Inv_L + + model->BSIM3walpha1 * Inv_W + + model->BSIM3palpha1 * Inv_LW; + pParam->BSIM3beta0 = model->BSIM3beta0 + + model->BSIM3lbeta0 * Inv_L + + model->BSIM3wbeta0 * Inv_W + + model->BSIM3pbeta0 * Inv_LW; + /* CV model */ + pParam->BSIM3elm = model->BSIM3elm + + model->BSIM3lelm * Inv_L + + model->BSIM3welm * Inv_W + + model->BSIM3pelm * Inv_LW; + pParam->BSIM3cgsl = model->BSIM3cgsl + + model->BSIM3lcgsl * Inv_L + + model->BSIM3wcgsl * Inv_W + + model->BSIM3pcgsl * Inv_LW; + pParam->BSIM3cgdl = model->BSIM3cgdl + + model->BSIM3lcgdl * Inv_L + + model->BSIM3wcgdl * Inv_W + + model->BSIM3pcgdl * Inv_LW; + pParam->BSIM3ckappa = model->BSIM3ckappa + + model->BSIM3lckappa * Inv_L + + model->BSIM3wckappa * Inv_W + + model->BSIM3pckappa * Inv_LW; + pParam->BSIM3cf = model->BSIM3cf + + model->BSIM3lcf * Inv_L + + model->BSIM3wcf * Inv_W + + model->BSIM3pcf * Inv_LW; + pParam->BSIM3clc = model->BSIM3clc + + model->BSIM3lclc * Inv_L + + model->BSIM3wclc * Inv_W + + model->BSIM3pclc * Inv_LW; + pParam->BSIM3cle = model->BSIM3cle + + model->BSIM3lcle * Inv_L + + model->BSIM3wcle * Inv_W + + model->BSIM3pcle * Inv_LW; + pParam->BSIM3vfbcv = model->BSIM3vfbcv + + model->BSIM3lvfbcv * Inv_L + + model->BSIM3wvfbcv * Inv_W + + model->BSIM3pvfbcv * Inv_LW; + pParam->BSIM3acde = model->BSIM3acde + + model->BSIM3lacde * Inv_L + + model->BSIM3wacde * Inv_W + + model->BSIM3pacde * Inv_LW; + pParam->BSIM3moin = model->BSIM3moin + + model->BSIM3lmoin * Inv_L + + model->BSIM3wmoin * Inv_W + + model->BSIM3pmoin * Inv_LW; + pParam->BSIM3noff = model->BSIM3noff + + model->BSIM3lnoff * Inv_L + + model->BSIM3wnoff * Inv_W + + model->BSIM3pnoff * Inv_LW; + pParam->BSIM3voffcv = model->BSIM3voffcv + + model->BSIM3lvoffcv * Inv_L + + model->BSIM3wvoffcv * Inv_W + + model->BSIM3pvoffcv * Inv_LW; + + pParam->BSIM3abulkCVfactor = 1.0 + pow((pParam->BSIM3clc + / pParam->BSIM3leffCV), + pParam->BSIM3cle); + + T0 = (TRatio - 1.0); + pParam->BSIM3ua = pParam->BSIM3ua + pParam->BSIM3ua1 * T0; + pParam->BSIM3ub = pParam->BSIM3ub + pParam->BSIM3ub1 * T0; + pParam->BSIM3uc = pParam->BSIM3uc + pParam->BSIM3uc1 * T0; + if (pParam->BSIM3u0 > 1.0) + pParam->BSIM3u0 = pParam->BSIM3u0 / 1.0e4; + + pParam->BSIM3u0temp = pParam->BSIM3u0 + * pow(TRatio, pParam->BSIM3ute); + pParam->BSIM3vsattemp = pParam->BSIM3vsat - pParam->BSIM3at + * T0; + pParam->BSIM3rds0 = (pParam->BSIM3rdsw + pParam->BSIM3prt * T0) + / pow(pParam->BSIM3weff * 1E6, pParam->BSIM3wr); + + if (BSIM3checkModel(model, here, ckt)) + { IFuid namarray[2]; + namarray[0] = model->BSIM3modName; + namarray[1] = here->BSIM3name; + (*(SPfrontEnd->IFerror)) (ERR_FATAL, "Fatal error(s) detected during BSIM3V3.2 parameter checking for %s in model %s", namarray); + return(E_BADPARM); + } + + pParam->BSIM3cgdo = (model->BSIM3cgdo + pParam->BSIM3cf) + * pParam->BSIM3weffCV; + pParam->BSIM3cgso = (model->BSIM3cgso + pParam->BSIM3cf) + * pParam->BSIM3weffCV; + pParam->BSIM3cgbo = model->BSIM3cgbo * pParam->BSIM3leffCV; + + T0 = pParam->BSIM3leffCV * pParam->BSIM3leffCV; + pParam->BSIM3tconst = pParam->BSIM3u0temp * pParam->BSIM3elm / (model->BSIM3cox + * pParam->BSIM3weffCV * pParam->BSIM3leffCV * T0); + + if (!model->BSIM3npeakGiven && model->BSIM3gamma1Given) + { T0 = pParam->BSIM3gamma1 * model->BSIM3cox; + pParam->BSIM3npeak = 3.021E22 * T0 * T0; + } + + pParam->BSIM3phi = 2.0 * Vtm0 + * log(pParam->BSIM3npeak / ni); + + pParam->BSIM3sqrtPhi = sqrt(pParam->BSIM3phi); + pParam->BSIM3phis3 = pParam->BSIM3sqrtPhi * pParam->BSIM3phi; + + pParam->BSIM3Xdep0 = sqrt(2.0 * EPSSI / (Charge_q + * pParam->BSIM3npeak * 1.0e6)) + * pParam->BSIM3sqrtPhi; + pParam->BSIM3sqrtXdep0 = sqrt(pParam->BSIM3Xdep0); + pParam->BSIM3litl = sqrt(3.0 * pParam->BSIM3xj + * model->BSIM3tox); + pParam->BSIM3vbi = Vtm0 * log(1.0e20 + * pParam->BSIM3npeak / (ni * ni)); + pParam->BSIM3cdep0 = sqrt(Charge_q * EPSSI + * pParam->BSIM3npeak * 1.0e6 / 2.0 + / pParam->BSIM3phi); + + pParam->BSIM3ldeb = sqrt(EPSSI * Vtm0 / (Charge_q + * pParam->BSIM3npeak * 1.0e6)) / 3.0; + pParam->BSIM3acde *= pow((pParam->BSIM3npeak / 2.0e16), -0.25); + + + if (model->BSIM3k1Given || model->BSIM3k2Given) + { if (!model->BSIM3k1Given) + { fprintf(stdout, "Warning: k1 should be specified with k2.\n"); + pParam->BSIM3k1 = 0.53; + } + if (!model->BSIM3k2Given) + { fprintf(stdout, "Warning: k2 should be specified with k1.\n"); + pParam->BSIM3k2 = -0.0186; + } + if (model->BSIM3nsubGiven) + fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n"); + if (model->BSIM3xtGiven) + fprintf(stdout, "Warning: xt is ignored because k1 or k2 is given.\n"); + if (model->BSIM3vbxGiven) + fprintf(stdout, "Warning: vbx is ignored because k1 or k2 is given.\n"); + if (model->BSIM3gamma1Given) + fprintf(stdout, "Warning: gamma1 is ignored because k1 or k2 is given.\n"); + if (model->BSIM3gamma2Given) + fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n"); + } + else + { if (!model->BSIM3vbxGiven) + pParam->BSIM3vbx = pParam->BSIM3phi - 7.7348e-4 + * pParam->BSIM3npeak + * pParam->BSIM3xt * pParam->BSIM3xt; + if (pParam->BSIM3vbx > 0.0) + pParam->BSIM3vbx = -pParam->BSIM3vbx; + if (pParam->BSIM3vbm > 0.0) + pParam->BSIM3vbm = -pParam->BSIM3vbm; + + if (!model->BSIM3gamma1Given) + pParam->BSIM3gamma1 = 5.753e-12 + * sqrt(pParam->BSIM3npeak) + / model->BSIM3cox; + if (!model->BSIM3gamma2Given) + pParam->BSIM3gamma2 = 5.753e-12 + * sqrt(pParam->BSIM3nsub) + / model->BSIM3cox; + + T0 = pParam->BSIM3gamma1 - pParam->BSIM3gamma2; + T1 = sqrt(pParam->BSIM3phi - pParam->BSIM3vbx) + - pParam->BSIM3sqrtPhi; + T2 = sqrt(pParam->BSIM3phi * (pParam->BSIM3phi + - pParam->BSIM3vbm)) - pParam->BSIM3phi; + pParam->BSIM3k2 = T0 * T1 / (2.0 * T2 + pParam->BSIM3vbm); + pParam->BSIM3k1 = pParam->BSIM3gamma2 - 2.0 + * pParam->BSIM3k2 * sqrt(pParam->BSIM3phi + - pParam->BSIM3vbm); + } + + if (pParam->BSIM3k2 < 0.0) + { T0 = 0.5 * pParam->BSIM3k1 / pParam->BSIM3k2; + pParam->BSIM3vbsc = 0.9 * (pParam->BSIM3phi - T0 * T0); + if (pParam->BSIM3vbsc > -3.0) + pParam->BSIM3vbsc = -3.0; + else if (pParam->BSIM3vbsc < -30.0) + pParam->BSIM3vbsc = -30.0; + } + else + { pParam->BSIM3vbsc = -30.0; + } + if (pParam->BSIM3vbsc > pParam->BSIM3vbm) + pParam->BSIM3vbsc = pParam->BSIM3vbm; + + if (!model->BSIM3vfbGiven) + { if (model->BSIM3vth0Given) + { pParam->BSIM3vfb = model->BSIM3type * pParam->BSIM3vth0 + - pParam->BSIM3phi - pParam->BSIM3k1 + * pParam->BSIM3sqrtPhi; + } + else + { pParam->BSIM3vfb = -1.0; + } + } + if (!model->BSIM3vth0Given) + { pParam->BSIM3vth0 = model->BSIM3type * (pParam->BSIM3vfb + + pParam->BSIM3phi + pParam->BSIM3k1 + * pParam->BSIM3sqrtPhi); + } + + pParam->BSIM3k1ox = pParam->BSIM3k1 * model->BSIM3tox + / model->BSIM3toxm; + pParam->BSIM3k2ox = pParam->BSIM3k2 * model->BSIM3tox + / model->BSIM3toxm; + + T1 = sqrt(EPSSI / EPSOX * model->BSIM3tox + * pParam->BSIM3Xdep0); + T0 = exp(-0.5 * pParam->BSIM3dsub * pParam->BSIM3leff / T1); + pParam->BSIM3theta0vb0 = (T0 + 2.0 * T0 * T0); + + T0 = exp(-0.5 * pParam->BSIM3drout * pParam->BSIM3leff / T1); + T2 = (T0 + 2.0 * T0 * T0); + pParam->BSIM3thetaRout = pParam->BSIM3pdibl1 * T2 + + pParam->BSIM3pdibl2; + + tmp = sqrt(pParam->BSIM3Xdep0); + tmp1 = pParam->BSIM3vbi - pParam->BSIM3phi; + tmp2 = model->BSIM3factor1 * tmp; + + T0 = -0.5 * pParam->BSIM3dvt1w * pParam->BSIM3weff + * pParam->BSIM3leff / tmp2; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 * (1.0 + 2.0 * T1); + } + else + { T1 = MIN_EXP; + T2 = T1 * (1.0 + 2.0 * T1); + } + T0 = pParam->BSIM3dvt0w * T2; + T2 = T0 * tmp1; + + T0 = -0.5 * pParam->BSIM3dvt1 * pParam->BSIM3leff / tmp2; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + T3 = T1 * (1.0 + 2.0 * T1); + } + else + { T1 = MIN_EXP; + T3 = T1 * (1.0 + 2.0 * T1); + } + T3 = pParam->BSIM3dvt0 * T3 * tmp1; + + T4 = model->BSIM3tox * pParam->BSIM3phi + / (pParam->BSIM3weff + pParam->BSIM3w0); + + T0 = sqrt(1.0 + pParam->BSIM3nlx / pParam->BSIM3leff); + T5 = pParam->BSIM3k1ox * (T0 - 1.0) * pParam->BSIM3sqrtPhi + + (pParam->BSIM3kt1 + pParam->BSIM3kt1l / pParam->BSIM3leff) + * (TRatio - 1.0); + + tmp3 = model->BSIM3type * pParam->BSIM3vth0 + - T2 - T3 + pParam->BSIM3k3 * T4 + T5; + pParam->BSIM3vfbzb = tmp3 - pParam->BSIM3phi - pParam->BSIM3k1 + * pParam->BSIM3sqrtPhi; + /* End of vfbzb */ + } + + /* process source/drain series resistance */ + here->BSIM3drainConductance = model->BSIM3sheetResistance + * here->BSIM3drainSquares; + if (here->BSIM3drainConductance > 0.0) + here->BSIM3drainConductance = 1.0 + / here->BSIM3drainConductance; + else + here->BSIM3drainConductance = 0.0; + + here->BSIM3sourceConductance = model->BSIM3sheetResistance + * here->BSIM3sourceSquares; + if (here->BSIM3sourceConductance > 0.0) + here->BSIM3sourceConductance = 1.0 + / here->BSIM3sourceConductance; + else + here->BSIM3sourceConductance = 0.0; + here->BSIM3cgso = pParam->BSIM3cgso; + here->BSIM3cgdo = pParam->BSIM3cgdo; + + Nvtm = model->BSIM3vtm * model->BSIM3jctEmissionCoeff; + if ((here->BSIM3sourceArea <= 0.0) && + (here->BSIM3sourcePerimeter <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } + else + { SourceSatCurrent = here->BSIM3sourceArea + * model->BSIM3jctTempSatCurDensity + + here->BSIM3sourcePerimeter + * model->BSIM3jctSidewallTempSatCurDensity; + } + if ((SourceSatCurrent > 0.0) && (model->BSIM3ijth > 0.0)) + { here->BSIM3vjsm = Nvtm * log(model->BSIM3ijth + / SourceSatCurrent + 1.0); + here->BSIM3IsEvjsm = SourceSatCurrent * exp(here->BSIM3vjsm + / Nvtm); + } + + if ((here->BSIM3drainArea <= 0.0) && + (here->BSIM3drainPerimeter <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } + else + { DrainSatCurrent = here->BSIM3drainArea + * model->BSIM3jctTempSatCurDensity + + here->BSIM3drainPerimeter + * model->BSIM3jctSidewallTempSatCurDensity; + } + if ((DrainSatCurrent > 0.0) && (model->BSIM3ijth > 0.0)) + { here->BSIM3vjdm = Nvtm * log(model->BSIM3ijth + / DrainSatCurrent + 1.0); + here->BSIM3IsEvjdm = DrainSatCurrent * exp(here->BSIM3vjdm + / Nvtm); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3/b3trunc.c b/src/spicelib/devices/bsim3/b3trunc.c new file mode 100644 index 000000000..4aa5588ce --- /dev/null +++ b/src/spicelib/devices/bsim3/b3trunc.c @@ -0,0 +1,73 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + Revision 1.1.1.1 1999/11/15 10:35:08 root + Rework imported sources + + Revision 1.1.1.1 1999/07/30 09:05:13 root + NG-Spice starting sources + + * Revision 3.2.2 1999/4/20 18:00:00 Weidong + * BSIM3v3.2.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: b3trunc.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3trunc(inModel,ckt,timeStep) +GENmodel *inModel; +register CKTcircuit *ckt; +double *timeStep; +{ +register BSIM3model *model = (BSIM3model*)inModel; +register BSIM3instance *here; + +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + + for (; model != NULL; model = model->BSIM3nextModel) + { for (here = model->BSIM3instances; here != NULL; + here = here->BSIM3nextInstance) + { + if (here->BSIM3owner != ARCHme) continue; +#ifdef STEPDEBUG + debugtemp = *timeStep; +#endif /* STEPDEBUG */ + CKTterr(here->BSIM3qb,ckt,timeStep); + CKTterr(here->BSIM3qg,ckt,timeStep); + CKTterr(here->BSIM3qd,ckt,timeStep); +#ifdef STEPDEBUG + if(debugtemp != *timeStep) + { printf("device %s reduces step from %g to %g\n", + here->BSIM3name,debugtemp,*timeStep); + } +#endif /* STEPDEBUG */ + } + } + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3/bsim3def.h b/src/spicelib/devices/bsim3/bsim3def.h new file mode 100644 index 000000000..8270edb91 --- /dev/null +++ b/src/spicelib/devices/bsim3/bsim3def.h @@ -0,0 +1,1757 @@ +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Author: 1997-1999 Weidong Liu. +File: bsim3def.h +**********/ + +#ifndef BSIM3 +#define BSIM3 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + +typedef struct sBSIM3instance +{ + struct sBSIM3model *BSIM3modPtr; + struct sBSIM3instance *BSIM3nextInstance; + IFuid BSIM3name; + int BSIM3owner; /* number of owner process */ + int BSIM3states; /* index into state table for this device */ + int BSIM3dNode; + int BSIM3gNode; + int BSIM3sNode; + int BSIM3bNode; + int BSIM3dNodePrime; + int BSIM3sNodePrime; + int BSIM3qNode; /* MCJ */ + + /* MCJ */ + double BSIM3ueff; + double BSIM3thetavth; + double BSIM3von; + double BSIM3vdsat; + double BSIM3cgdo; + double BSIM3cgso; + double BSIM3vjsm; + double BSIM3IsEvjsm; + double BSIM3vjdm; + double BSIM3IsEvjdm; + + double BSIM3l; + double BSIM3w; + double BSIM3drainArea; + double BSIM3sourceArea; + double BSIM3drainSquares; + double BSIM3sourceSquares; + double BSIM3drainPerimeter; + double BSIM3sourcePerimeter; + double BSIM3sourceConductance; + double BSIM3drainConductance; + + double BSIM3icVBS; + double BSIM3icVDS; + double BSIM3icVGS; + int BSIM3off; + int BSIM3mode; + int BSIM3nqsMod; + + /* OP point */ + double BSIM3qinv; + double BSIM3cd; + double BSIM3cbs; + double BSIM3cbd; + double BSIM3csub; + double BSIM3gm; + double BSIM3gds; + double BSIM3gmbs; + double BSIM3gbd; + double BSIM3gbs; + + double BSIM3gbbs; + double BSIM3gbgs; + double BSIM3gbds; + + double BSIM3cggb; + double BSIM3cgdb; + double BSIM3cgsb; + double BSIM3cbgb; + double BSIM3cbdb; + double BSIM3cbsb; + double BSIM3cdgb; + double BSIM3cddb; + double BSIM3cdsb; + double BSIM3capbd; + double BSIM3capbs; + + double BSIM3cqgb; + double BSIM3cqdb; + double BSIM3cqsb; + double BSIM3cqbb; + + double BSIM3qgate; + double BSIM3qbulk; + double BSIM3qdrn; + + double BSIM3gtau; + double BSIM3gtg; + double BSIM3gtd; + double BSIM3gts; + double BSIM3gtb; + + struct bsim3SizeDependParam *pParam; + + unsigned BSIM3lGiven :1; + unsigned BSIM3wGiven :1; + unsigned BSIM3drainAreaGiven :1; + unsigned BSIM3sourceAreaGiven :1; + unsigned BSIM3drainSquaresGiven :1; + unsigned BSIM3sourceSquaresGiven :1; + unsigned BSIM3drainPerimeterGiven :1; + unsigned BSIM3sourcePerimeterGiven :1; + unsigned BSIM3dNodePrimeSet :1; + unsigned BSIM3sNodePrimeSet :1; + unsigned BSIM3icVBSGiven :1; + unsigned BSIM3icVDSGiven :1; + unsigned BSIM3icVGSGiven :1; + unsigned BSIM3nqsModGiven :1; + + double *BSIM3DdPtr; + double *BSIM3GgPtr; + double *BSIM3SsPtr; + double *BSIM3BbPtr; + double *BSIM3DPdpPtr; + double *BSIM3SPspPtr; + double *BSIM3DdpPtr; + double *BSIM3GbPtr; + double *BSIM3GdpPtr; + double *BSIM3GspPtr; + double *BSIM3SspPtr; + double *BSIM3BdpPtr; + double *BSIM3BspPtr; + double *BSIM3DPspPtr; + double *BSIM3DPdPtr; + double *BSIM3BgPtr; + double *BSIM3DPgPtr; + double *BSIM3SPgPtr; + double *BSIM3SPsPtr; + double *BSIM3DPbPtr; + double *BSIM3SPbPtr; + double *BSIM3SPdpPtr; + + double *BSIM3QqPtr; + double *BSIM3QdpPtr; + double *BSIM3QgPtr; + double *BSIM3QspPtr; + double *BSIM3QbPtr; + double *BSIM3DPqPtr; + double *BSIM3GqPtr; + double *BSIM3SPqPtr; + double *BSIM3BqPtr; + + /* int BSIM3states; index into state table for this device */ +#define BSIM3vbd BSIM3states+ 0 +#define BSIM3vbs BSIM3states+ 1 +#define BSIM3vgs BSIM3states+ 2 +#define BSIM3vds BSIM3states+ 3 + +#define BSIM3qb BSIM3states+ 4 +#define BSIM3cqb BSIM3states+ 5 +#define BSIM3qg BSIM3states+ 6 +#define BSIM3cqg BSIM3states+ 7 +#define BSIM3qd BSIM3states+ 8 +#define BSIM3cqd BSIM3states+ 9 + +#define BSIM3qbs BSIM3states+ 10 +#define BSIM3qbd BSIM3states+ 11 + +#define BSIM3qcheq BSIM3states+ 12 +#define BSIM3cqcheq BSIM3states+ 13 +#define BSIM3qcdump BSIM3states+ 14 +#define BSIM3cqcdump BSIM3states+ 15 + +#define BSIM3qdef BSIM3states+ 16 + +#define BSIM3numStates 17 + + +/* indices to the array of BSIM3 NOISE SOURCES */ + +#define BSIM3RDNOIZ 0 +#define BSIM3RSNOIZ 1 +#define BSIM3IDNOIZ 2 +#define BSIM3FLNOIZ 3 +#define BSIM3TOTNOIZ 4 + +#define BSIM3NSRCS 5 /* the number of BSIM3 MOSFET noise sources */ + +#ifndef NONOISE + double BSIM3nVar[NSTATVARS][BSIM3NSRCS]; +#else /* NONOISE */ + double **BSIM3nVar; +#endif /* NONOISE */ + +} BSIM3instance ; + +struct bsim3SizeDependParam +{ + double Width; + double Length; + + double BSIM3cdsc; + double BSIM3cdscb; + double BSIM3cdscd; + double BSIM3cit; + double BSIM3nfactor; + double BSIM3xj; + double BSIM3vsat; + double BSIM3at; + double BSIM3a0; + double BSIM3ags; + double BSIM3a1; + double BSIM3a2; + double BSIM3keta; + double BSIM3nsub; + double BSIM3npeak; + double BSIM3ngate; + double BSIM3gamma1; + double BSIM3gamma2; + double BSIM3vbx; + double BSIM3vbi; + double BSIM3vbm; + double BSIM3vbsc; + double BSIM3xt; + double BSIM3phi; + double BSIM3litl; + double BSIM3k1; + double BSIM3kt1; + double BSIM3kt1l; + double BSIM3kt2; + double BSIM3k2; + double BSIM3k3; + double BSIM3k3b; + double BSIM3w0; + double BSIM3nlx; + double BSIM3dvt0; + double BSIM3dvt1; + double BSIM3dvt2; + double BSIM3dvt0w; + double BSIM3dvt1w; + double BSIM3dvt2w; + double BSIM3drout; + double BSIM3dsub; + double BSIM3vth0; + double BSIM3ua; + double BSIM3ua1; + double BSIM3ub; + double BSIM3ub1; + double BSIM3uc; + double BSIM3uc1; + double BSIM3u0; + double BSIM3ute; + double BSIM3voff; + double BSIM3vfb; + double BSIM3delta; + double BSIM3rdsw; + double BSIM3rds0; + double BSIM3prwg; + double BSIM3prwb; + double BSIM3prt; + double BSIM3eta0; + double BSIM3etab; + double BSIM3pclm; + double BSIM3pdibl1; + double BSIM3pdibl2; + double BSIM3pdiblb; + double BSIM3pscbe1; + double BSIM3pscbe2; + double BSIM3pvag; + double BSIM3wr; + double BSIM3dwg; + double BSIM3dwb; + double BSIM3b0; + double BSIM3b1; + double BSIM3alpha0; + double BSIM3alpha1; + double BSIM3beta0; + + + /* CV model */ + double BSIM3elm; + double BSIM3cgsl; + double BSIM3cgdl; + double BSIM3ckappa; + double BSIM3cf; + double BSIM3clc; + double BSIM3cle; + double BSIM3vfbcv; + double BSIM3noff; + double BSIM3voffcv; + double BSIM3acde; + double BSIM3moin; + + +/* Pre-calculated constants */ + + double BSIM3dw; + double BSIM3dl; + double BSIM3leff; + double BSIM3weff; + + double BSIM3dwc; + double BSIM3dlc; + double BSIM3leffCV; + double BSIM3weffCV; + double BSIM3abulkCVfactor; + double BSIM3cgso; + double BSIM3cgdo; + double BSIM3cgbo; + double BSIM3tconst; + + double BSIM3u0temp; + double BSIM3vsattemp; + double BSIM3sqrtPhi; + double BSIM3phis3; + double BSIM3Xdep0; + double BSIM3sqrtXdep0; + double BSIM3theta0vb0; + double BSIM3thetaRout; + + double BSIM3cof1; + double BSIM3cof2; + double BSIM3cof3; + double BSIM3cof4; + double BSIM3cdep0; + double BSIM3vfbzb; + double BSIM3ldeb; + double BSIM3k1ox; + double BSIM3k2ox; + + struct bsim3SizeDependParam *pNext; +}; + + +typedef struct sBSIM3model +{ + int BSIM3modType; + struct sBSIM3model *BSIM3nextModel; + BSIM3instance *BSIM3instances; + IFuid BSIM3modName; + int BSIM3type; + + int BSIM3mobMod; + int BSIM3capMod; + int BSIM3noiMod; + int BSIM3binUnit; + int BSIM3paramChk; + char *BSIM3version; + double BSIM3tox; + double BSIM3toxm; + double BSIM3cdsc; + double BSIM3cdscb; + double BSIM3cdscd; + double BSIM3cit; + double BSIM3nfactor; + double BSIM3xj; + double BSIM3vsat; + double BSIM3at; + double BSIM3a0; + double BSIM3ags; + double BSIM3a1; + double BSIM3a2; + double BSIM3keta; + double BSIM3nsub; + double BSIM3npeak; + double BSIM3ngate; + double BSIM3gamma1; + double BSIM3gamma2; + double BSIM3vbx; + double BSIM3vbm; + double BSIM3xt; + double BSIM3k1; + double BSIM3kt1; + double BSIM3kt1l; + double BSIM3kt2; + double BSIM3k2; + double BSIM3k3; + double BSIM3k3b; + double BSIM3w0; + double BSIM3nlx; + double BSIM3dvt0; + double BSIM3dvt1; + double BSIM3dvt2; + double BSIM3dvt0w; + double BSIM3dvt1w; + double BSIM3dvt2w; + double BSIM3drout; + double BSIM3dsub; + double BSIM3vth0; + double BSIM3ua; + double BSIM3ua1; + double BSIM3ub; + double BSIM3ub1; + double BSIM3uc; + double BSIM3uc1; + double BSIM3u0; + double BSIM3ute; + double BSIM3voff; + double BSIM3delta; + double BSIM3rdsw; + double BSIM3prwg; + double BSIM3prwb; + double BSIM3prt; + double BSIM3eta0; + double BSIM3etab; + double BSIM3pclm; + double BSIM3pdibl1; + double BSIM3pdibl2; + double BSIM3pdiblb; + double BSIM3pscbe1; + double BSIM3pscbe2; + double BSIM3pvag; + double BSIM3wr; + double BSIM3dwg; + double BSIM3dwb; + double BSIM3b0; + double BSIM3b1; + double BSIM3alpha0; + double BSIM3alpha1; + double BSIM3beta0; + double BSIM3ijth; + double BSIM3vfb; + + /* CV model */ + double BSIM3elm; + double BSIM3cgsl; + double BSIM3cgdl; + double BSIM3ckappa; + double BSIM3cf; + double BSIM3vfbcv; + double BSIM3clc; + double BSIM3cle; + double BSIM3dwc; + double BSIM3dlc; + double BSIM3noff; + double BSIM3voffcv; + double BSIM3acde; + double BSIM3moin; + double BSIM3tcj; + double BSIM3tcjsw; + double BSIM3tcjswg; + double BSIM3tpb; + double BSIM3tpbsw; + double BSIM3tpbswg; + + /* Length Dependence */ + double BSIM3lcdsc; + double BSIM3lcdscb; + double BSIM3lcdscd; + double BSIM3lcit; + double BSIM3lnfactor; + double BSIM3lxj; + double BSIM3lvsat; + double BSIM3lat; + double BSIM3la0; + double BSIM3lags; + double BSIM3la1; + double BSIM3la2; + double BSIM3lketa; + double BSIM3lnsub; + double BSIM3lnpeak; + double BSIM3lngate; + double BSIM3lgamma1; + double BSIM3lgamma2; + double BSIM3lvbx; + double BSIM3lvbm; + double BSIM3lxt; + double BSIM3lk1; + double BSIM3lkt1; + double BSIM3lkt1l; + double BSIM3lkt2; + double BSIM3lk2; + double BSIM3lk3; + double BSIM3lk3b; + double BSIM3lw0; + double BSIM3lnlx; + double BSIM3ldvt0; + double BSIM3ldvt1; + double BSIM3ldvt2; + double BSIM3ldvt0w; + double BSIM3ldvt1w; + double BSIM3ldvt2w; + double BSIM3ldrout; + double BSIM3ldsub; + double BSIM3lvth0; + double BSIM3lua; + double BSIM3lua1; + double BSIM3lub; + double BSIM3lub1; + double BSIM3luc; + double BSIM3luc1; + double BSIM3lu0; + double BSIM3lute; + double BSIM3lvoff; + double BSIM3ldelta; + double BSIM3lrdsw; + double BSIM3lprwg; + double BSIM3lprwb; + double BSIM3lprt; + double BSIM3leta0; + double BSIM3letab; + double BSIM3lpclm; + double BSIM3lpdibl1; + double BSIM3lpdibl2; + double BSIM3lpdiblb; + double BSIM3lpscbe1; + double BSIM3lpscbe2; + double BSIM3lpvag; + double BSIM3lwr; + double BSIM3ldwg; + double BSIM3ldwb; + double BSIM3lb0; + double BSIM3lb1; + double BSIM3lalpha0; + double BSIM3lalpha1; + double BSIM3lbeta0; + double BSIM3lvfb; + + /* CV model */ + double BSIM3lelm; + double BSIM3lcgsl; + double BSIM3lcgdl; + double BSIM3lckappa; + double BSIM3lcf; + double BSIM3lclc; + double BSIM3lcle; + double BSIM3lvfbcv; + double BSIM3lnoff; + double BSIM3lvoffcv; + double BSIM3lacde; + double BSIM3lmoin; + + /* Width Dependence */ + double BSIM3wcdsc; + double BSIM3wcdscb; + double BSIM3wcdscd; + double BSIM3wcit; + double BSIM3wnfactor; + double BSIM3wxj; + double BSIM3wvsat; + double BSIM3wat; + double BSIM3wa0; + double BSIM3wags; + double BSIM3wa1; + double BSIM3wa2; + double BSIM3wketa; + double BSIM3wnsub; + double BSIM3wnpeak; + double BSIM3wngate; + double BSIM3wgamma1; + double BSIM3wgamma2; + double BSIM3wvbx; + double BSIM3wvbm; + double BSIM3wxt; + double BSIM3wk1; + double BSIM3wkt1; + double BSIM3wkt1l; + double BSIM3wkt2; + double BSIM3wk2; + double BSIM3wk3; + double BSIM3wk3b; + double BSIM3ww0; + double BSIM3wnlx; + double BSIM3wdvt0; + double BSIM3wdvt1; + double BSIM3wdvt2; + double BSIM3wdvt0w; + double BSIM3wdvt1w; + double BSIM3wdvt2w; + double BSIM3wdrout; + double BSIM3wdsub; + double BSIM3wvth0; + double BSIM3wua; + double BSIM3wua1; + double BSIM3wub; + double BSIM3wub1; + double BSIM3wuc; + double BSIM3wuc1; + double BSIM3wu0; + double BSIM3wute; + double BSIM3wvoff; + double BSIM3wdelta; + double BSIM3wrdsw; + double BSIM3wprwg; + double BSIM3wprwb; + double BSIM3wprt; + double BSIM3weta0; + double BSIM3wetab; + double BSIM3wpclm; + double BSIM3wpdibl1; + double BSIM3wpdibl2; + double BSIM3wpdiblb; + double BSIM3wpscbe1; + double BSIM3wpscbe2; + double BSIM3wpvag; + double BSIM3wwr; + double BSIM3wdwg; + double BSIM3wdwb; + double BSIM3wb0; + double BSIM3wb1; + double BSIM3walpha0; + double BSIM3walpha1; + double BSIM3wbeta0; + double BSIM3wvfb; + + /* CV model */ + double BSIM3welm; + double BSIM3wcgsl; + double BSIM3wcgdl; + double BSIM3wckappa; + double BSIM3wcf; + double BSIM3wclc; + double BSIM3wcle; + double BSIM3wvfbcv; + double BSIM3wnoff; + double BSIM3wvoffcv; + double BSIM3wacde; + double BSIM3wmoin; + + /* Cross-term Dependence */ + double BSIM3pcdsc; + double BSIM3pcdscb; + double BSIM3pcdscd; + double BSIM3pcit; + double BSIM3pnfactor; + double BSIM3pxj; + double BSIM3pvsat; + double BSIM3pat; + double BSIM3pa0; + double BSIM3pags; + double BSIM3pa1; + double BSIM3pa2; + double BSIM3pketa; + double BSIM3pnsub; + double BSIM3pnpeak; + double BSIM3pngate; + double BSIM3pgamma1; + double BSIM3pgamma2; + double BSIM3pvbx; + double BSIM3pvbm; + double BSIM3pxt; + double BSIM3pk1; + double BSIM3pkt1; + double BSIM3pkt1l; + double BSIM3pkt2; + double BSIM3pk2; + double BSIM3pk3; + double BSIM3pk3b; + double BSIM3pw0; + double BSIM3pnlx; + double BSIM3pdvt0; + double BSIM3pdvt1; + double BSIM3pdvt2; + double BSIM3pdvt0w; + double BSIM3pdvt1w; + double BSIM3pdvt2w; + double BSIM3pdrout; + double BSIM3pdsub; + double BSIM3pvth0; + double BSIM3pua; + double BSIM3pua1; + double BSIM3pub; + double BSIM3pub1; + double BSIM3puc; + double BSIM3puc1; + double BSIM3pu0; + double BSIM3pute; + double BSIM3pvoff; + double BSIM3pdelta; + double BSIM3prdsw; + double BSIM3pprwg; + double BSIM3pprwb; + double BSIM3pprt; + double BSIM3peta0; + double BSIM3petab; + double BSIM3ppclm; + double BSIM3ppdibl1; + double BSIM3ppdibl2; + double BSIM3ppdiblb; + double BSIM3ppscbe1; + double BSIM3ppscbe2; + double BSIM3ppvag; + double BSIM3pwr; + double BSIM3pdwg; + double BSIM3pdwb; + double BSIM3pb0; + double BSIM3pb1; + double BSIM3palpha0; + double BSIM3palpha1; + double BSIM3pbeta0; + double BSIM3pvfb; + + /* CV model */ + double BSIM3pelm; + double BSIM3pcgsl; + double BSIM3pcgdl; + double BSIM3pckappa; + double BSIM3pcf; + double BSIM3pclc; + double BSIM3pcle; + double BSIM3pvfbcv; + double BSIM3pnoff; + double BSIM3pvoffcv; + double BSIM3pacde; + double BSIM3pmoin; + + double BSIM3tnom; + double BSIM3cgso; + double BSIM3cgdo; + double BSIM3cgbo; + double BSIM3xpart; + double BSIM3cFringOut; + double BSIM3cFringMax; + + double BSIM3sheetResistance; + double BSIM3jctSatCurDensity; + double BSIM3jctSidewallSatCurDensity; + double BSIM3bulkJctPotential; + double BSIM3bulkJctBotGradingCoeff; + double BSIM3bulkJctSideGradingCoeff; + double BSIM3bulkJctGateSideGradingCoeff; + double BSIM3sidewallJctPotential; + double BSIM3GatesidewallJctPotential; + double BSIM3unitAreaJctCap; + double BSIM3unitLengthSidewallJctCap; + double BSIM3unitLengthGateSidewallJctCap; + double BSIM3jctEmissionCoeff; + double BSIM3jctTempExponent; + + double BSIM3Lint; + double BSIM3Ll; + double BSIM3Llc; + double BSIM3Lln; + double BSIM3Lw; + double BSIM3Lwc; + double BSIM3Lwn; + double BSIM3Lwl; + double BSIM3Lwlc; + double BSIM3Lmin; + double BSIM3Lmax; + + double BSIM3Wint; + double BSIM3Wl; + double BSIM3Wlc; + double BSIM3Wln; + double BSIM3Ww; + double BSIM3Wwc; + double BSIM3Wwn; + double BSIM3Wwl; + double BSIM3Wwlc; + double BSIM3Wmin; + double BSIM3Wmax; + + +/* Pre-calculated constants */ + /* MCJ: move to size-dependent param. */ + double BSIM3vtm; + double BSIM3cox; + double BSIM3cof1; + double BSIM3cof2; + double BSIM3cof3; + double BSIM3cof4; + double BSIM3vcrit; + double BSIM3factor1; + double BSIM3PhiB; + double BSIM3PhiBSW; + double BSIM3PhiBSWG; + double BSIM3jctTempSatCurDensity; + double BSIM3jctSidewallTempSatCurDensity; + + double BSIM3oxideTrapDensityA; + double BSIM3oxideTrapDensityB; + double BSIM3oxideTrapDensityC; + double BSIM3em; + double BSIM3ef; + double BSIM3af; + double BSIM3kf; + + struct bsim3SizeDependParam *pSizeDependParamKnot; + + /* Flags */ + unsigned BSIM3mobModGiven :1; + unsigned BSIM3binUnitGiven :1; + unsigned BSIM3capModGiven :1; + unsigned BSIM3paramChkGiven :1; + unsigned BSIM3noiModGiven :1; + unsigned BSIM3typeGiven :1; + unsigned BSIM3toxGiven :1; + unsigned BSIM3versionGiven :1; + unsigned BSIM3toxmGiven :1; + unsigned BSIM3cdscGiven :1; + unsigned BSIM3cdscbGiven :1; + unsigned BSIM3cdscdGiven :1; + unsigned BSIM3citGiven :1; + unsigned BSIM3nfactorGiven :1; + unsigned BSIM3xjGiven :1; + unsigned BSIM3vsatGiven :1; + unsigned BSIM3atGiven :1; + unsigned BSIM3a0Given :1; + unsigned BSIM3agsGiven :1; + unsigned BSIM3a1Given :1; + unsigned BSIM3a2Given :1; + unsigned BSIM3ketaGiven :1; + unsigned BSIM3nsubGiven :1; + unsigned BSIM3npeakGiven :1; + unsigned BSIM3ngateGiven :1; + unsigned BSIM3gamma1Given :1; + unsigned BSIM3gamma2Given :1; + unsigned BSIM3vbxGiven :1; + unsigned BSIM3vbmGiven :1; + unsigned BSIM3xtGiven :1; + unsigned BSIM3k1Given :1; + unsigned BSIM3kt1Given :1; + unsigned BSIM3kt1lGiven :1; + unsigned BSIM3kt2Given :1; + unsigned BSIM3k2Given :1; + unsigned BSIM3k3Given :1; + unsigned BSIM3k3bGiven :1; + unsigned BSIM3w0Given :1; + unsigned BSIM3nlxGiven :1; + unsigned BSIM3dvt0Given :1; + unsigned BSIM3dvt1Given :1; + unsigned BSIM3dvt2Given :1; + unsigned BSIM3dvt0wGiven :1; + unsigned BSIM3dvt1wGiven :1; + unsigned BSIM3dvt2wGiven :1; + unsigned BSIM3droutGiven :1; + unsigned BSIM3dsubGiven :1; + unsigned BSIM3vth0Given :1; + unsigned BSIM3uaGiven :1; + unsigned BSIM3ua1Given :1; + unsigned BSIM3ubGiven :1; + unsigned BSIM3ub1Given :1; + unsigned BSIM3ucGiven :1; + unsigned BSIM3uc1Given :1; + unsigned BSIM3u0Given :1; + unsigned BSIM3uteGiven :1; + unsigned BSIM3voffGiven :1; + unsigned BSIM3rdswGiven :1; + unsigned BSIM3prwgGiven :1; + unsigned BSIM3prwbGiven :1; + unsigned BSIM3prtGiven :1; + unsigned BSIM3eta0Given :1; + unsigned BSIM3etabGiven :1; + unsigned BSIM3pclmGiven :1; + unsigned BSIM3pdibl1Given :1; + unsigned BSIM3pdibl2Given :1; + unsigned BSIM3pdiblbGiven :1; + unsigned BSIM3pscbe1Given :1; + unsigned BSIM3pscbe2Given :1; + unsigned BSIM3pvagGiven :1; + unsigned BSIM3deltaGiven :1; + unsigned BSIM3wrGiven :1; + unsigned BSIM3dwgGiven :1; + unsigned BSIM3dwbGiven :1; + unsigned BSIM3b0Given :1; + unsigned BSIM3b1Given :1; + unsigned BSIM3alpha0Given :1; + unsigned BSIM3alpha1Given :1; + unsigned BSIM3beta0Given :1; + unsigned BSIM3ijthGiven :1; + unsigned BSIM3vfbGiven :1; + + /* CV model */ + unsigned BSIM3elmGiven :1; + unsigned BSIM3cgslGiven :1; + unsigned BSIM3cgdlGiven :1; + unsigned BSIM3ckappaGiven :1; + unsigned BSIM3cfGiven :1; + unsigned BSIM3vfbcvGiven :1; + unsigned BSIM3clcGiven :1; + unsigned BSIM3cleGiven :1; + unsigned BSIM3dwcGiven :1; + unsigned BSIM3dlcGiven :1; + unsigned BSIM3noffGiven :1; + unsigned BSIM3voffcvGiven :1; + unsigned BSIM3acdeGiven :1; + unsigned BSIM3moinGiven :1; + unsigned BSIM3tcjGiven :1; + unsigned BSIM3tcjswGiven :1; + unsigned BSIM3tcjswgGiven :1; + unsigned BSIM3tpbGiven :1; + unsigned BSIM3tpbswGiven :1; + unsigned BSIM3tpbswgGiven :1; + + + /* Length dependence */ + unsigned BSIM3lcdscGiven :1; + unsigned BSIM3lcdscbGiven :1; + unsigned BSIM3lcdscdGiven :1; + unsigned BSIM3lcitGiven :1; + unsigned BSIM3lnfactorGiven :1; + unsigned BSIM3lxjGiven :1; + unsigned BSIM3lvsatGiven :1; + unsigned BSIM3latGiven :1; + unsigned BSIM3la0Given :1; + unsigned BSIM3lagsGiven :1; + unsigned BSIM3la1Given :1; + unsigned BSIM3la2Given :1; + unsigned BSIM3lketaGiven :1; + unsigned BSIM3lnsubGiven :1; + unsigned BSIM3lnpeakGiven :1; + unsigned BSIM3lngateGiven :1; + unsigned BSIM3lgamma1Given :1; + unsigned BSIM3lgamma2Given :1; + unsigned BSIM3lvbxGiven :1; + unsigned BSIM3lvbmGiven :1; + unsigned BSIM3lxtGiven :1; + unsigned BSIM3lk1Given :1; + unsigned BSIM3lkt1Given :1; + unsigned BSIM3lkt1lGiven :1; + unsigned BSIM3lkt2Given :1; + unsigned BSIM3lk2Given :1; + unsigned BSIM3lk3Given :1; + unsigned BSIM3lk3bGiven :1; + unsigned BSIM3lw0Given :1; + unsigned BSIM3lnlxGiven :1; + unsigned BSIM3ldvt0Given :1; + unsigned BSIM3ldvt1Given :1; + unsigned BSIM3ldvt2Given :1; + unsigned BSIM3ldvt0wGiven :1; + unsigned BSIM3ldvt1wGiven :1; + unsigned BSIM3ldvt2wGiven :1; + unsigned BSIM3ldroutGiven :1; + unsigned BSIM3ldsubGiven :1; + unsigned BSIM3lvth0Given :1; + unsigned BSIM3luaGiven :1; + unsigned BSIM3lua1Given :1; + unsigned BSIM3lubGiven :1; + unsigned BSIM3lub1Given :1; + unsigned BSIM3lucGiven :1; + unsigned BSIM3luc1Given :1; + unsigned BSIM3lu0Given :1; + unsigned BSIM3luteGiven :1; + unsigned BSIM3lvoffGiven :1; + unsigned BSIM3lrdswGiven :1; + unsigned BSIM3lprwgGiven :1; + unsigned BSIM3lprwbGiven :1; + unsigned BSIM3lprtGiven :1; + unsigned BSIM3leta0Given :1; + unsigned BSIM3letabGiven :1; + unsigned BSIM3lpclmGiven :1; + unsigned BSIM3lpdibl1Given :1; + unsigned BSIM3lpdibl2Given :1; + unsigned BSIM3lpdiblbGiven :1; + unsigned BSIM3lpscbe1Given :1; + unsigned BSIM3lpscbe2Given :1; + unsigned BSIM3lpvagGiven :1; + unsigned BSIM3ldeltaGiven :1; + unsigned BSIM3lwrGiven :1; + unsigned BSIM3ldwgGiven :1; + unsigned BSIM3ldwbGiven :1; + unsigned BSIM3lb0Given :1; + unsigned BSIM3lb1Given :1; + unsigned BSIM3lalpha0Given :1; + unsigned BSIM3lalpha1Given :1; + unsigned BSIM3lbeta0Given :1; + unsigned BSIM3lvfbGiven :1; + + /* CV model */ + unsigned BSIM3lelmGiven :1; + unsigned BSIM3lcgslGiven :1; + unsigned BSIM3lcgdlGiven :1; + unsigned BSIM3lckappaGiven :1; + unsigned BSIM3lcfGiven :1; + unsigned BSIM3lclcGiven :1; + unsigned BSIM3lcleGiven :1; + unsigned BSIM3lvfbcvGiven :1; + unsigned BSIM3lnoffGiven :1; + unsigned BSIM3lvoffcvGiven :1; + unsigned BSIM3lacdeGiven :1; + unsigned BSIM3lmoinGiven :1; + + /* Width dependence */ + unsigned BSIM3wcdscGiven :1; + unsigned BSIM3wcdscbGiven :1; + unsigned BSIM3wcdscdGiven :1; + unsigned BSIM3wcitGiven :1; + unsigned BSIM3wnfactorGiven :1; + unsigned BSIM3wxjGiven :1; + unsigned BSIM3wvsatGiven :1; + unsigned BSIM3watGiven :1; + unsigned BSIM3wa0Given :1; + unsigned BSIM3wagsGiven :1; + unsigned BSIM3wa1Given :1; + unsigned BSIM3wa2Given :1; + unsigned BSIM3wketaGiven :1; + unsigned BSIM3wnsubGiven :1; + unsigned BSIM3wnpeakGiven :1; + unsigned BSIM3wngateGiven :1; + unsigned BSIM3wgamma1Given :1; + unsigned BSIM3wgamma2Given :1; + unsigned BSIM3wvbxGiven :1; + unsigned BSIM3wvbmGiven :1; + unsigned BSIM3wxtGiven :1; + unsigned BSIM3wk1Given :1; + unsigned BSIM3wkt1Given :1; + unsigned BSIM3wkt1lGiven :1; + unsigned BSIM3wkt2Given :1; + unsigned BSIM3wk2Given :1; + unsigned BSIM3wk3Given :1; + unsigned BSIM3wk3bGiven :1; + unsigned BSIM3ww0Given :1; + unsigned BSIM3wnlxGiven :1; + unsigned BSIM3wdvt0Given :1; + unsigned BSIM3wdvt1Given :1; + unsigned BSIM3wdvt2Given :1; + unsigned BSIM3wdvt0wGiven :1; + unsigned BSIM3wdvt1wGiven :1; + unsigned BSIM3wdvt2wGiven :1; + unsigned BSIM3wdroutGiven :1; + unsigned BSIM3wdsubGiven :1; + unsigned BSIM3wvth0Given :1; + unsigned BSIM3wuaGiven :1; + unsigned BSIM3wua1Given :1; + unsigned BSIM3wubGiven :1; + unsigned BSIM3wub1Given :1; + unsigned BSIM3wucGiven :1; + unsigned BSIM3wuc1Given :1; + unsigned BSIM3wu0Given :1; + unsigned BSIM3wuteGiven :1; + unsigned BSIM3wvoffGiven :1; + unsigned BSIM3wrdswGiven :1; + unsigned BSIM3wprwgGiven :1; + unsigned BSIM3wprwbGiven :1; + unsigned BSIM3wprtGiven :1; + unsigned BSIM3weta0Given :1; + unsigned BSIM3wetabGiven :1; + unsigned BSIM3wpclmGiven :1; + unsigned BSIM3wpdibl1Given :1; + unsigned BSIM3wpdibl2Given :1; + unsigned BSIM3wpdiblbGiven :1; + unsigned BSIM3wpscbe1Given :1; + unsigned BSIM3wpscbe2Given :1; + unsigned BSIM3wpvagGiven :1; + unsigned BSIM3wdeltaGiven :1; + unsigned BSIM3wwrGiven :1; + unsigned BSIM3wdwgGiven :1; + unsigned BSIM3wdwbGiven :1; + unsigned BSIM3wb0Given :1; + unsigned BSIM3wb1Given :1; + unsigned BSIM3walpha0Given :1; + unsigned BSIM3walpha1Given :1; + unsigned BSIM3wbeta0Given :1; + unsigned BSIM3wvfbGiven :1; + + /* CV model */ + unsigned BSIM3welmGiven :1; + unsigned BSIM3wcgslGiven :1; + unsigned BSIM3wcgdlGiven :1; + unsigned BSIM3wckappaGiven :1; + unsigned BSIM3wcfGiven :1; + unsigned BSIM3wclcGiven :1; + unsigned BSIM3wcleGiven :1; + unsigned BSIM3wvfbcvGiven :1; + unsigned BSIM3wnoffGiven :1; + unsigned BSIM3wvoffcvGiven :1; + unsigned BSIM3wacdeGiven :1; + unsigned BSIM3wmoinGiven :1; + + /* Cross-term dependence */ + unsigned BSIM3pcdscGiven :1; + unsigned BSIM3pcdscbGiven :1; + unsigned BSIM3pcdscdGiven :1; + unsigned BSIM3pcitGiven :1; + unsigned BSIM3pnfactorGiven :1; + unsigned BSIM3pxjGiven :1; + unsigned BSIM3pvsatGiven :1; + unsigned BSIM3patGiven :1; + unsigned BSIM3pa0Given :1; + unsigned BSIM3pagsGiven :1; + unsigned BSIM3pa1Given :1; + unsigned BSIM3pa2Given :1; + unsigned BSIM3pketaGiven :1; + unsigned BSIM3pnsubGiven :1; + unsigned BSIM3pnpeakGiven :1; + unsigned BSIM3pngateGiven :1; + unsigned BSIM3pgamma1Given :1; + unsigned BSIM3pgamma2Given :1; + unsigned BSIM3pvbxGiven :1; + unsigned BSIM3pvbmGiven :1; + unsigned BSIM3pxtGiven :1; + unsigned BSIM3pk1Given :1; + unsigned BSIM3pkt1Given :1; + unsigned BSIM3pkt1lGiven :1; + unsigned BSIM3pkt2Given :1; + unsigned BSIM3pk2Given :1; + unsigned BSIM3pk3Given :1; + unsigned BSIM3pk3bGiven :1; + unsigned BSIM3pw0Given :1; + unsigned BSIM3pnlxGiven :1; + unsigned BSIM3pdvt0Given :1; + unsigned BSIM3pdvt1Given :1; + unsigned BSIM3pdvt2Given :1; + unsigned BSIM3pdvt0wGiven :1; + unsigned BSIM3pdvt1wGiven :1; + unsigned BSIM3pdvt2wGiven :1; + unsigned BSIM3pdroutGiven :1; + unsigned BSIM3pdsubGiven :1; + unsigned BSIM3pvth0Given :1; + unsigned BSIM3puaGiven :1; + unsigned BSIM3pua1Given :1; + unsigned BSIM3pubGiven :1; + unsigned BSIM3pub1Given :1; + unsigned BSIM3pucGiven :1; + unsigned BSIM3puc1Given :1; + unsigned BSIM3pu0Given :1; + unsigned BSIM3puteGiven :1; + unsigned BSIM3pvoffGiven :1; + unsigned BSIM3prdswGiven :1; + unsigned BSIM3pprwgGiven :1; + unsigned BSIM3pprwbGiven :1; + unsigned BSIM3pprtGiven :1; + unsigned BSIM3peta0Given :1; + unsigned BSIM3petabGiven :1; + unsigned BSIM3ppclmGiven :1; + unsigned BSIM3ppdibl1Given :1; + unsigned BSIM3ppdibl2Given :1; + unsigned BSIM3ppdiblbGiven :1; + unsigned BSIM3ppscbe1Given :1; + unsigned BSIM3ppscbe2Given :1; + unsigned BSIM3ppvagGiven :1; + unsigned BSIM3pdeltaGiven :1; + unsigned BSIM3pwrGiven :1; + unsigned BSIM3pdwgGiven :1; + unsigned BSIM3pdwbGiven :1; + unsigned BSIM3pb0Given :1; + unsigned BSIM3pb1Given :1; + unsigned BSIM3palpha0Given :1; + unsigned BSIM3palpha1Given :1; + unsigned BSIM3pbeta0Given :1; + unsigned BSIM3pvfbGiven :1; + + /* CV model */ + unsigned BSIM3pelmGiven :1; + unsigned BSIM3pcgslGiven :1; + unsigned BSIM3pcgdlGiven :1; + unsigned BSIM3pckappaGiven :1; + unsigned BSIM3pcfGiven :1; + unsigned BSIM3pclcGiven :1; + unsigned BSIM3pcleGiven :1; + unsigned BSIM3pvfbcvGiven :1; + unsigned BSIM3pnoffGiven :1; + unsigned BSIM3pvoffcvGiven :1; + unsigned BSIM3pacdeGiven :1; + unsigned BSIM3pmoinGiven :1; + + unsigned BSIM3useFringeGiven :1; + + unsigned BSIM3tnomGiven :1; + unsigned BSIM3cgsoGiven :1; + unsigned BSIM3cgdoGiven :1; + unsigned BSIM3cgboGiven :1; + unsigned BSIM3xpartGiven :1; + unsigned BSIM3sheetResistanceGiven :1; + unsigned BSIM3jctSatCurDensityGiven :1; + unsigned BSIM3jctSidewallSatCurDensityGiven :1; + unsigned BSIM3bulkJctPotentialGiven :1; + unsigned BSIM3bulkJctBotGradingCoeffGiven :1; + unsigned BSIM3sidewallJctPotentialGiven :1; + unsigned BSIM3GatesidewallJctPotentialGiven :1; + unsigned BSIM3bulkJctSideGradingCoeffGiven :1; + unsigned BSIM3unitAreaJctCapGiven :1; + unsigned BSIM3unitLengthSidewallJctCapGiven :1; + unsigned BSIM3bulkJctGateSideGradingCoeffGiven :1; + unsigned BSIM3unitLengthGateSidewallJctCapGiven :1; + unsigned BSIM3jctEmissionCoeffGiven :1; + unsigned BSIM3jctTempExponentGiven :1; + + unsigned BSIM3oxideTrapDensityAGiven :1; + unsigned BSIM3oxideTrapDensityBGiven :1; + unsigned BSIM3oxideTrapDensityCGiven :1; + unsigned BSIM3emGiven :1; + unsigned BSIM3efGiven :1; + unsigned BSIM3afGiven :1; + unsigned BSIM3kfGiven :1; + + unsigned BSIM3LintGiven :1; + unsigned BSIM3LlGiven :1; + unsigned BSIM3LlcGiven :1; + unsigned BSIM3LlnGiven :1; + unsigned BSIM3LwGiven :1; + unsigned BSIM3LwcGiven :1; + unsigned BSIM3LwnGiven :1; + unsigned BSIM3LwlGiven :1; + unsigned BSIM3LwlcGiven :1; + unsigned BSIM3LminGiven :1; + unsigned BSIM3LmaxGiven :1; + + unsigned BSIM3WintGiven :1; + unsigned BSIM3WlGiven :1; + unsigned BSIM3WlcGiven :1; + unsigned BSIM3WlnGiven :1; + unsigned BSIM3WwGiven :1; + unsigned BSIM3WwcGiven :1; + unsigned BSIM3WwnGiven :1; + unsigned BSIM3WwlGiven :1; + unsigned BSIM3WwlcGiven :1; + unsigned BSIM3WminGiven :1; + unsigned BSIM3WmaxGiven :1; + +} BSIM3model; + + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + + +/* device parameters */ +#define BSIM3_W 1 +#define BSIM3_L 2 +#define BSIM3_AS 3 +#define BSIM3_AD 4 +#define BSIM3_PS 5 +#define BSIM3_PD 6 +#define BSIM3_NRS 7 +#define BSIM3_NRD 8 +#define BSIM3_OFF 9 +#define BSIM3_IC_VBS 10 +#define BSIM3_IC_VDS 11 +#define BSIM3_IC_VGS 12 +#define BSIM3_IC 13 +#define BSIM3_NQSMOD 14 + +/* model parameters */ +#define BSIM3_MOD_CAPMOD 101 +#define BSIM3_MOD_MOBMOD 103 +#define BSIM3_MOD_NOIMOD 104 + +#define BSIM3_MOD_TOX 105 + +#define BSIM3_MOD_CDSC 106 +#define BSIM3_MOD_CDSCB 107 +#define BSIM3_MOD_CIT 108 +#define BSIM3_MOD_NFACTOR 109 +#define BSIM3_MOD_XJ 110 +#define BSIM3_MOD_VSAT 111 +#define BSIM3_MOD_AT 112 +#define BSIM3_MOD_A0 113 +#define BSIM3_MOD_A1 114 +#define BSIM3_MOD_A2 115 +#define BSIM3_MOD_KETA 116 +#define BSIM3_MOD_NSUB 117 +#define BSIM3_MOD_NPEAK 118 +#define BSIM3_MOD_NGATE 120 +#define BSIM3_MOD_GAMMA1 121 +#define BSIM3_MOD_GAMMA2 122 +#define BSIM3_MOD_VBX 123 +#define BSIM3_MOD_BINUNIT 124 + +#define BSIM3_MOD_VBM 125 + +#define BSIM3_MOD_XT 126 +#define BSIM3_MOD_K1 129 +#define BSIM3_MOD_KT1 130 +#define BSIM3_MOD_KT1L 131 +#define BSIM3_MOD_K2 132 +#define BSIM3_MOD_KT2 133 +#define BSIM3_MOD_K3 134 +#define BSIM3_MOD_K3B 135 +#define BSIM3_MOD_W0 136 +#define BSIM3_MOD_NLX 137 + +#define BSIM3_MOD_DVT0 138 +#define BSIM3_MOD_DVT1 139 +#define BSIM3_MOD_DVT2 140 + +#define BSIM3_MOD_DVT0W 141 +#define BSIM3_MOD_DVT1W 142 +#define BSIM3_MOD_DVT2W 143 + +#define BSIM3_MOD_DROUT 144 +#define BSIM3_MOD_DSUB 145 +#define BSIM3_MOD_VTH0 146 +#define BSIM3_MOD_UA 147 +#define BSIM3_MOD_UA1 148 +#define BSIM3_MOD_UB 149 +#define BSIM3_MOD_UB1 150 +#define BSIM3_MOD_UC 151 +#define BSIM3_MOD_UC1 152 +#define BSIM3_MOD_U0 153 +#define BSIM3_MOD_UTE 154 +#define BSIM3_MOD_VOFF 155 +#define BSIM3_MOD_DELTA 156 +#define BSIM3_MOD_RDSW 157 +#define BSIM3_MOD_PRT 158 +#define BSIM3_MOD_LDD 159 +#define BSIM3_MOD_ETA 160 +#define BSIM3_MOD_ETA0 161 +#define BSIM3_MOD_ETAB 162 +#define BSIM3_MOD_PCLM 163 +#define BSIM3_MOD_PDIBL1 164 +#define BSIM3_MOD_PDIBL2 165 +#define BSIM3_MOD_PSCBE1 166 +#define BSIM3_MOD_PSCBE2 167 +#define BSIM3_MOD_PVAG 168 +#define BSIM3_MOD_WR 169 +#define BSIM3_MOD_DWG 170 +#define BSIM3_MOD_DWB 171 +#define BSIM3_MOD_B0 172 +#define BSIM3_MOD_B1 173 +#define BSIM3_MOD_ALPHA0 174 +#define BSIM3_MOD_BETA0 175 +#define BSIM3_MOD_PDIBLB 178 + +#define BSIM3_MOD_PRWG 179 +#define BSIM3_MOD_PRWB 180 + +#define BSIM3_MOD_CDSCD 181 +#define BSIM3_MOD_AGS 182 + +#define BSIM3_MOD_FRINGE 184 +#define BSIM3_MOD_ELM 185 +#define BSIM3_MOD_CGSL 186 +#define BSIM3_MOD_CGDL 187 +#define BSIM3_MOD_CKAPPA 188 +#define BSIM3_MOD_CF 189 +#define BSIM3_MOD_CLC 190 +#define BSIM3_MOD_CLE 191 +#define BSIM3_MOD_PARAMCHK 192 +#define BSIM3_MOD_VERSION 193 +#define BSIM3_MOD_VFBCV 194 +#define BSIM3_MOD_ACDE 195 +#define BSIM3_MOD_MOIN 196 +#define BSIM3_MOD_NOFF 197 +#define BSIM3_MOD_IJTH 198 +#define BSIM3_MOD_ALPHA1 199 +#define BSIM3_MOD_VFB 200 +#define BSIM3_MOD_TOXM 201 +#define BSIM3_MOD_TCJ 202 +#define BSIM3_MOD_TCJSW 203 +#define BSIM3_MOD_TCJSWG 204 +#define BSIM3_MOD_TPB 205 +#define BSIM3_MOD_TPBSW 206 +#define BSIM3_MOD_TPBSWG 207 +#define BSIM3_MOD_VOFFCV 208 + +/* Length dependence */ +#define BSIM3_MOD_LCDSC 251 +#define BSIM3_MOD_LCDSCB 252 +#define BSIM3_MOD_LCIT 253 +#define BSIM3_MOD_LNFACTOR 254 +#define BSIM3_MOD_LXJ 255 +#define BSIM3_MOD_LVSAT 256 +#define BSIM3_MOD_LAT 257 +#define BSIM3_MOD_LA0 258 +#define BSIM3_MOD_LA1 259 +#define BSIM3_MOD_LA2 260 +#define BSIM3_MOD_LKETA 261 +#define BSIM3_MOD_LNSUB 262 +#define BSIM3_MOD_LNPEAK 263 +#define BSIM3_MOD_LNGATE 265 +#define BSIM3_MOD_LGAMMA1 266 +#define BSIM3_MOD_LGAMMA2 267 +#define BSIM3_MOD_LVBX 268 + +#define BSIM3_MOD_LVBM 270 + +#define BSIM3_MOD_LXT 272 +#define BSIM3_MOD_LK1 275 +#define BSIM3_MOD_LKT1 276 +#define BSIM3_MOD_LKT1L 277 +#define BSIM3_MOD_LK2 278 +#define BSIM3_MOD_LKT2 279 +#define BSIM3_MOD_LK3 280 +#define BSIM3_MOD_LK3B 281 +#define BSIM3_MOD_LW0 282 +#define BSIM3_MOD_LNLX 283 + +#define BSIM3_MOD_LDVT0 284 +#define BSIM3_MOD_LDVT1 285 +#define BSIM3_MOD_LDVT2 286 + +#define BSIM3_MOD_LDVT0W 287 +#define BSIM3_MOD_LDVT1W 288 +#define BSIM3_MOD_LDVT2W 289 + +#define BSIM3_MOD_LDROUT 290 +#define BSIM3_MOD_LDSUB 291 +#define BSIM3_MOD_LVTH0 292 +#define BSIM3_MOD_LUA 293 +#define BSIM3_MOD_LUA1 294 +#define BSIM3_MOD_LUB 295 +#define BSIM3_MOD_LUB1 296 +#define BSIM3_MOD_LUC 297 +#define BSIM3_MOD_LUC1 298 +#define BSIM3_MOD_LU0 299 +#define BSIM3_MOD_LUTE 300 +#define BSIM3_MOD_LVOFF 301 +#define BSIM3_MOD_LDELTA 302 +#define BSIM3_MOD_LRDSW 303 +#define BSIM3_MOD_LPRT 304 +#define BSIM3_MOD_LLDD 305 +#define BSIM3_MOD_LETA 306 +#define BSIM3_MOD_LETA0 307 +#define BSIM3_MOD_LETAB 308 +#define BSIM3_MOD_LPCLM 309 +#define BSIM3_MOD_LPDIBL1 310 +#define BSIM3_MOD_LPDIBL2 311 +#define BSIM3_MOD_LPSCBE1 312 +#define BSIM3_MOD_LPSCBE2 313 +#define BSIM3_MOD_LPVAG 314 +#define BSIM3_MOD_LWR 315 +#define BSIM3_MOD_LDWG 316 +#define BSIM3_MOD_LDWB 317 +#define BSIM3_MOD_LB0 318 +#define BSIM3_MOD_LB1 319 +#define BSIM3_MOD_LALPHA0 320 +#define BSIM3_MOD_LBETA0 321 +#define BSIM3_MOD_LPDIBLB 324 + +#define BSIM3_MOD_LPRWG 325 +#define BSIM3_MOD_LPRWB 326 + +#define BSIM3_MOD_LCDSCD 327 +#define BSIM3_MOD_LAGS 328 + + +#define BSIM3_MOD_LFRINGE 331 +#define BSIM3_MOD_LELM 332 +#define BSIM3_MOD_LCGSL 333 +#define BSIM3_MOD_LCGDL 334 +#define BSIM3_MOD_LCKAPPA 335 +#define BSIM3_MOD_LCF 336 +#define BSIM3_MOD_LCLC 337 +#define BSIM3_MOD_LCLE 338 +#define BSIM3_MOD_LVFBCV 339 +#define BSIM3_MOD_LACDE 340 +#define BSIM3_MOD_LMOIN 341 +#define BSIM3_MOD_LNOFF 342 +#define BSIM3_MOD_LALPHA1 344 +#define BSIM3_MOD_LVFB 345 +#define BSIM3_MOD_LVOFFCV 346 + +/* Width dependence */ +#define BSIM3_MOD_WCDSC 381 +#define BSIM3_MOD_WCDSCB 382 +#define BSIM3_MOD_WCIT 383 +#define BSIM3_MOD_WNFACTOR 384 +#define BSIM3_MOD_WXJ 385 +#define BSIM3_MOD_WVSAT 386 +#define BSIM3_MOD_WAT 387 +#define BSIM3_MOD_WA0 388 +#define BSIM3_MOD_WA1 389 +#define BSIM3_MOD_WA2 390 +#define BSIM3_MOD_WKETA 391 +#define BSIM3_MOD_WNSUB 392 +#define BSIM3_MOD_WNPEAK 393 +#define BSIM3_MOD_WNGATE 395 +#define BSIM3_MOD_WGAMMA1 396 +#define BSIM3_MOD_WGAMMA2 397 +#define BSIM3_MOD_WVBX 398 + +#define BSIM3_MOD_WVBM 400 + +#define BSIM3_MOD_WXT 402 +#define BSIM3_MOD_WK1 405 +#define BSIM3_MOD_WKT1 406 +#define BSIM3_MOD_WKT1L 407 +#define BSIM3_MOD_WK2 408 +#define BSIM3_MOD_WKT2 409 +#define BSIM3_MOD_WK3 410 +#define BSIM3_MOD_WK3B 411 +#define BSIM3_MOD_WW0 412 +#define BSIM3_MOD_WNLX 413 + +#define BSIM3_MOD_WDVT0 414 +#define BSIM3_MOD_WDVT1 415 +#define BSIM3_MOD_WDVT2 416 + +#define BSIM3_MOD_WDVT0W 417 +#define BSIM3_MOD_WDVT1W 418 +#define BSIM3_MOD_WDVT2W 419 + +#define BSIM3_MOD_WDROUT 420 +#define BSIM3_MOD_WDSUB 421 +#define BSIM3_MOD_WVTH0 422 +#define BSIM3_MOD_WUA 423 +#define BSIM3_MOD_WUA1 424 +#define BSIM3_MOD_WUB 425 +#define BSIM3_MOD_WUB1 426 +#define BSIM3_MOD_WUC 427 +#define BSIM3_MOD_WUC1 428 +#define BSIM3_MOD_WU0 429 +#define BSIM3_MOD_WUTE 430 +#define BSIM3_MOD_WVOFF 431 +#define BSIM3_MOD_WDELTA 432 +#define BSIM3_MOD_WRDSW 433 +#define BSIM3_MOD_WPRT 434 +#define BSIM3_MOD_WLDD 435 +#define BSIM3_MOD_WETA 436 +#define BSIM3_MOD_WETA0 437 +#define BSIM3_MOD_WETAB 438 +#define BSIM3_MOD_WPCLM 439 +#define BSIM3_MOD_WPDIBL1 440 +#define BSIM3_MOD_WPDIBL2 441 +#define BSIM3_MOD_WPSCBE1 442 +#define BSIM3_MOD_WPSCBE2 443 +#define BSIM3_MOD_WPVAG 444 +#define BSIM3_MOD_WWR 445 +#define BSIM3_MOD_WDWG 446 +#define BSIM3_MOD_WDWB 447 +#define BSIM3_MOD_WB0 448 +#define BSIM3_MOD_WB1 449 +#define BSIM3_MOD_WALPHA0 450 +#define BSIM3_MOD_WBETA0 451 +#define BSIM3_MOD_WPDIBLB 454 + +#define BSIM3_MOD_WPRWG 455 +#define BSIM3_MOD_WPRWB 456 + +#define BSIM3_MOD_WCDSCD 457 +#define BSIM3_MOD_WAGS 458 + + +#define BSIM3_MOD_WFRINGE 461 +#define BSIM3_MOD_WELM 462 +#define BSIM3_MOD_WCGSL 463 +#define BSIM3_MOD_WCGDL 464 +#define BSIM3_MOD_WCKAPPA 465 +#define BSIM3_MOD_WCF 466 +#define BSIM3_MOD_WCLC 467 +#define BSIM3_MOD_WCLE 468 +#define BSIM3_MOD_WVFBCV 469 +#define BSIM3_MOD_WACDE 470 +#define BSIM3_MOD_WMOIN 471 +#define BSIM3_MOD_WNOFF 472 +#define BSIM3_MOD_WALPHA1 474 +#define BSIM3_MOD_WVFB 475 +#define BSIM3_MOD_WVOFFCV 476 + +/* Cross-term dependence */ +#define BSIM3_MOD_PCDSC 511 +#define BSIM3_MOD_PCDSCB 512 +#define BSIM3_MOD_PCIT 513 +#define BSIM3_MOD_PNFACTOR 514 +#define BSIM3_MOD_PXJ 515 +#define BSIM3_MOD_PVSAT 516 +#define BSIM3_MOD_PAT 517 +#define BSIM3_MOD_PA0 518 +#define BSIM3_MOD_PA1 519 +#define BSIM3_MOD_PA2 520 +#define BSIM3_MOD_PKETA 521 +#define BSIM3_MOD_PNSUB 522 +#define BSIM3_MOD_PNPEAK 523 +#define BSIM3_MOD_PNGATE 525 +#define BSIM3_MOD_PGAMMA1 526 +#define BSIM3_MOD_PGAMMA2 527 +#define BSIM3_MOD_PVBX 528 + +#define BSIM3_MOD_PVBM 530 + +#define BSIM3_MOD_PXT 532 +#define BSIM3_MOD_PK1 535 +#define BSIM3_MOD_PKT1 536 +#define BSIM3_MOD_PKT1L 537 +#define BSIM3_MOD_PK2 538 +#define BSIM3_MOD_PKT2 539 +#define BSIM3_MOD_PK3 540 +#define BSIM3_MOD_PK3B 541 +#define BSIM3_MOD_PW0 542 +#define BSIM3_MOD_PNLX 543 + +#define BSIM3_MOD_PDVT0 544 +#define BSIM3_MOD_PDVT1 545 +#define BSIM3_MOD_PDVT2 546 + +#define BSIM3_MOD_PDVT0W 547 +#define BSIM3_MOD_PDVT1W 548 +#define BSIM3_MOD_PDVT2W 549 + +#define BSIM3_MOD_PDROUT 550 +#define BSIM3_MOD_PDSUB 551 +#define BSIM3_MOD_PVTH0 552 +#define BSIM3_MOD_PUA 553 +#define BSIM3_MOD_PUA1 554 +#define BSIM3_MOD_PUB 555 +#define BSIM3_MOD_PUB1 556 +#define BSIM3_MOD_PUC 557 +#define BSIM3_MOD_PUC1 558 +#define BSIM3_MOD_PU0 559 +#define BSIM3_MOD_PUTE 560 +#define BSIM3_MOD_PVOFF 561 +#define BSIM3_MOD_PDELTA 562 +#define BSIM3_MOD_PRDSW 563 +#define BSIM3_MOD_PPRT 564 +#define BSIM3_MOD_PLDD 565 +#define BSIM3_MOD_PETA 566 +#define BSIM3_MOD_PETA0 567 +#define BSIM3_MOD_PETAB 568 +#define BSIM3_MOD_PPCLM 569 +#define BSIM3_MOD_PPDIBL1 570 +#define BSIM3_MOD_PPDIBL2 571 +#define BSIM3_MOD_PPSCBE1 572 +#define BSIM3_MOD_PPSCBE2 573 +#define BSIM3_MOD_PPVAG 574 +#define BSIM3_MOD_PWR 575 +#define BSIM3_MOD_PDWG 576 +#define BSIM3_MOD_PDWB 577 +#define BSIM3_MOD_PB0 578 +#define BSIM3_MOD_PB1 579 +#define BSIM3_MOD_PALPHA0 580 +#define BSIM3_MOD_PBETA0 581 +#define BSIM3_MOD_PPDIBLB 584 + +#define BSIM3_MOD_PPRWG 585 +#define BSIM3_MOD_PPRWB 586 + +#define BSIM3_MOD_PCDSCD 587 +#define BSIM3_MOD_PAGS 588 + +#define BSIM3_MOD_PFRINGE 591 +#define BSIM3_MOD_PELM 592 +#define BSIM3_MOD_PCGSL 593 +#define BSIM3_MOD_PCGDL 594 +#define BSIM3_MOD_PCKAPPA 595 +#define BSIM3_MOD_PCF 596 +#define BSIM3_MOD_PCLC 597 +#define BSIM3_MOD_PCLE 598 +#define BSIM3_MOD_PVFBCV 599 +#define BSIM3_MOD_PACDE 600 +#define BSIM3_MOD_PMOIN 601 +#define BSIM3_MOD_PNOFF 602 +#define BSIM3_MOD_PALPHA1 604 +#define BSIM3_MOD_PVFB 605 +#define BSIM3_MOD_PVOFFCV 606 + +#define BSIM3_MOD_TNOM 651 +#define BSIM3_MOD_CGSO 652 +#define BSIM3_MOD_CGDO 653 +#define BSIM3_MOD_CGBO 654 +#define BSIM3_MOD_XPART 655 + +#define BSIM3_MOD_RSH 656 +#define BSIM3_MOD_JS 657 +#define BSIM3_MOD_PB 658 +#define BSIM3_MOD_MJ 659 +#define BSIM3_MOD_PBSW 660 +#define BSIM3_MOD_MJSW 661 +#define BSIM3_MOD_CJ 662 +#define BSIM3_MOD_CJSW 663 +#define BSIM3_MOD_NMOS 664 +#define BSIM3_MOD_PMOS 665 + +#define BSIM3_MOD_NOIA 666 +#define BSIM3_MOD_NOIB 667 +#define BSIM3_MOD_NOIC 668 + +#define BSIM3_MOD_LINT 669 +#define BSIM3_MOD_LL 670 +#define BSIM3_MOD_LLN 671 +#define BSIM3_MOD_LW 672 +#define BSIM3_MOD_LWN 673 +#define BSIM3_MOD_LWL 674 +#define BSIM3_MOD_LMIN 675 +#define BSIM3_MOD_LMAX 676 + +#define BSIM3_MOD_WINT 677 +#define BSIM3_MOD_WL 678 +#define BSIM3_MOD_WLN 679 +#define BSIM3_MOD_WW 680 +#define BSIM3_MOD_WWN 681 +#define BSIM3_MOD_WWL 682 +#define BSIM3_MOD_WMIN 683 +#define BSIM3_MOD_WMAX 684 + +#define BSIM3_MOD_DWC 685 +#define BSIM3_MOD_DLC 686 + +#define BSIM3_MOD_EM 687 +#define BSIM3_MOD_EF 688 +#define BSIM3_MOD_AF 689 +#define BSIM3_MOD_KF 690 + +#define BSIM3_MOD_NJ 691 +#define BSIM3_MOD_XTI 692 + +#define BSIM3_MOD_PBSWG 693 +#define BSIM3_MOD_MJSWG 694 +#define BSIM3_MOD_CJSWG 695 +#define BSIM3_MOD_JSW 696 + +#define BSIM3_MOD_LLC 697 +#define BSIM3_MOD_LWC 698 +#define BSIM3_MOD_LWLC 699 + +#define BSIM3_MOD_WLC 700 +#define BSIM3_MOD_WWC 701 +#define BSIM3_MOD_WWLC 702 + +/* device questions */ +#define BSIM3_DNODE 751 +#define BSIM3_GNODE 752 +#define BSIM3_SNODE 753 +#define BSIM3_BNODE 754 +#define BSIM3_DNODEPRIME 755 +#define BSIM3_SNODEPRIME 756 +#define BSIM3_VBD 757 +#define BSIM3_VBS 758 +#define BSIM3_VGS 759 +#define BSIM3_VDS 760 +#define BSIM3_CD 761 +#define BSIM3_CBS 762 +#define BSIM3_CBD 763 +#define BSIM3_GM 764 +#define BSIM3_GDS 765 +#define BSIM3_GMBS 766 +#define BSIM3_GBD 767 +#define BSIM3_GBS 768 +#define BSIM3_QB 769 +#define BSIM3_CQB 770 +#define BSIM3_QG 771 +#define BSIM3_CQG 772 +#define BSIM3_QD 773 +#define BSIM3_CQD 774 +#define BSIM3_CGG 775 +#define BSIM3_CGD 776 +#define BSIM3_CGS 777 +#define BSIM3_CBG 778 +#define BSIM3_CAPBD 779 +#define BSIM3_CQBD 780 +#define BSIM3_CAPBS 781 +#define BSIM3_CQBS 782 +#define BSIM3_CDG 783 +#define BSIM3_CDD 784 +#define BSIM3_CDS 785 +#define BSIM3_VON 786 +#define BSIM3_VDSAT 787 +#define BSIM3_QBS 788 +#define BSIM3_QBD 789 +#define BSIM3_SOURCECONDUCT 790 +#define BSIM3_DRAINCONDUCT 791 +#define BSIM3_CBDB 792 +#define BSIM3_CBSB 793 + + +#include "bsim3ext.h" + +#ifdef __STDC__ +extern void BSIM3evaluate(double,double,double,BSIM3instance*,BSIM3model*, + double*,double*,double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, CKTcircuit*); +extern int BSIM3debug(BSIM3model*, BSIM3instance*, CKTcircuit*, int); +extern int BSIM3checkModel(BSIM3model*, BSIM3instance*, CKTcircuit*); +#else /* stdc */ +extern void BSIM3evaluate(); +extern int BSIM3debug(); +extern int BSIM3checkModel(); +#endif /* stdc */ + +#endif /*BSIM3*/ + diff --git a/src/spicelib/devices/bsim3/bsim3ext.h b/src/spicelib/devices/bsim3/bsim3ext.h new file mode 100644 index 000000000..aa97f642b --- /dev/null +++ b/src/spicelib/devices/bsim3/bsim3ext.h @@ -0,0 +1,53 @@ +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +File: bsim3ext.h +**********/ + +#ifdef __STDC__ +extern int BSIM3acLoad(GENmodel *,CKTcircuit*); +extern int BSIM3ask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int BSIM3convTest(GENmodel *,CKTcircuit*); +extern int BSIM3delete(GENmodel*,IFuid,GENinstance**); +extern void BSIM3destroy(GENmodel**); +extern int BSIM3getic(GENmodel*,CKTcircuit*); +extern int BSIM3load(GENmodel*,CKTcircuit*); +extern int BSIM3mAsk(CKTcircuit*,GENmodel *,int, IFvalue*); +extern int BSIM3mDelete(GENmodel**,IFuid,GENmodel*); +extern int BSIM3mParam(int,IFvalue*,GENmodel*); +extern void BSIM3mosCap(CKTcircuit*, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*); +extern int BSIM3param(int,IFvalue*,GENinstance*,IFvalue*); +extern int BSIM3pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int BSIM3setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int BSIM3unsetup(GENmodel*, CKTcircuit*); +extern int BSIM3temp(GENmodel*,CKTcircuit*); +extern int BSIM3trunc(GENmodel*,CKTcircuit*,double*); +extern int BSIM3noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ +extern int BSIM3acLoad(); +extern int BSIM3delete(); +extern void BSIM3destroy(); +extern int BSIM3getic(); +extern int BSIM3load(); +extern int BSIM3mDelete(); +extern int BSIM3ask(); +extern int BSIM3mAsk(); +extern int BSIM3convTest(); +extern int BSIM3temp(); +extern int BSIM3mParam(); +extern void BSIM3mosCap(); +extern int BSIM3param(); +extern int BSIM3pzLoad(); +extern int BSIM3setup(); +extern int BSIM3unsetup(); +extern int BSIM3trunc(); +extern int BSIM3noise(); + +#endif /* stdc */ + diff --git a/src/spicelib/devices/bsim3/bsim3itf.h b/src/spicelib/devices/bsim3/bsim3itf.h new file mode 100644 index 000000000..518207ace --- /dev/null +++ b/src/spicelib/devices/bsim3/bsim3itf.h @@ -0,0 +1,90 @@ +/********** +Copyright 1999 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +File: bsim3itf.h +**********/ +#ifdef DEV_bsim3 + +#ifndef DEV_BSIM3 +#define DEV_BSIM3 + +#include "bsim3ext.h" + +extern IFparm BSIM3pTable[ ]; +extern IFparm BSIM3mPTable[ ]; +extern char *BSIM3names[ ]; +extern int BSIM3pTSize; +extern int BSIM3mPTSize; +extern int BSIM3nSize; +extern int BSIM3iSize; +extern int BSIM3mSize; + +SPICEdev BSIM3info = { + { "BSIM3", + "Berkeley Short Channel IGFET Model Version-3", + + &BSIM3nSize, + &BSIM3nSize, + BSIM3names, + + &BSIM3pTSize, + BSIM3pTable, + + &BSIM3mPTSize, + BSIM3mPTable, + DEV_DEFAULT + }, + + BSIM3param, + BSIM3mParam, + BSIM3load, + BSIM3setup, + BSIM3unsetup, + BSIM3setup, + BSIM3temp, + BSIM3trunc, + NULL, + BSIM3acLoad, + NULL, + BSIM3destroy, +#ifdef DELETES + BSIM3mDelete, + BSIM3delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + BSIM3getic, + BSIM3ask, + BSIM3mAsk, +#ifdef AN_pz + BSIM3pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + BSIM3convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + +#ifdef AN_noise + BSIM3noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &BSIM3iSize, + &BSIM3mSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/bsim3v1/ChangeLog b/src/spicelib/devices/bsim3v1/ChangeLog new file mode 100644 index 000000000..2c61d23a6 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/ChangeLog @@ -0,0 +1,7 @@ +27-01-2000 Paolo Nenzi + + * bsim3v1def.h: added BSIM3V1owner varialbe to the BSIM3V1instance + structure to support "parallel" processing with Cider. + + * b3v1acld.c, b3v1cvtest.c, b3v1getic.c, b3v1ld.c,b3v1pzld.c, b3v1set.c, b3v1temp.c, b3v1trunc.c: added the BSIM3V1owner check in these files. + diff --git a/src/spicelib/devices/bsim3v1/Makefile.am b/src/spicelib/devices/bsim3v1/Makefile.am new file mode 100644 index 000000000..b491d87ea --- /dev/null +++ b/src/spicelib/devices/bsim3v1/Makefile.am @@ -0,0 +1,32 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libbsim3v1.la + +libbsim3v1_la_SOURCES = \ + b3v1.c \ + b3v1acld.c \ + b3v1ask.c \ + b3v1check.c \ + b3v1cvtest.c \ + b3v1del.c \ + b3v1dest.c \ + b3v1getic.c \ + b3v1ld.c \ + b3v1mask.c \ + b3v1mdel.c \ + b3v1mpar.c \ + b3v1noi.c \ + b3v1par.c \ + b3v1pzld.c \ + b3v1set.c \ + b3v1temp.c \ + b3v1trunc.c \ + bsim3v1def.h \ + bsim3v1ext.h \ + bsim3v1itf.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/bsim3v1/b3v1.c b/src/spicelib/devices/bsim3v1/b3v1.c new file mode 100644 index 000000000..1517fd0b3 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1.c @@ -0,0 +1,457 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:48:03 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/**********************************/ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1.c +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "bsim3v1def.h" +#include "suffix.h" + +IFparm BSIM3V1pTable[] = { /* parameters */ +IOP( "l", BSIM3V1_L, IF_REAL , "Length"), +IOP( "w", BSIM3V1_W, IF_REAL , "Width"), +IOP( "ad", BSIM3V1_AD, IF_REAL , "Drain area"), +IOP( "as", BSIM3V1_AS, IF_REAL , "Source area"), +IOP( "pd", BSIM3V1_PD, IF_REAL , "Drain perimeter"), +IOP( "ps", BSIM3V1_PS, IF_REAL , "Source perimeter"), +IOP( "nrd", BSIM3V1_NRD, IF_REAL , "Number of squares in drain"), +IOP( "nrs", BSIM3V1_NRS, IF_REAL , "Number of squares in source"), +IOP( "off", BSIM3V1_OFF, IF_FLAG , "Device is initially off"), +IOP( "nqsmod", BSIM3V1_NQSMOD, IF_INTEGER, "Non-quasi-static model selector"), +IP( "ic", BSIM3V1_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"), +OP( "gmbs", BSIM3V1_GMBS, IF_REAL, "Gmb"), +OP( "gm", BSIM3V1_GM, IF_REAL, "Gm"), +OP( "gds", BSIM3V1_GDS, IF_REAL, "Gds"), +OP( "vdsat", BSIM3V1_VDSAT, IF_REAL, "Vdsat"), +OP( "vth", BSIM3V1_VON, IF_REAL, "Vth"), +OP( "id", BSIM3V1_CD, IF_REAL, "Ids"), +OP( "vbs", BSIM3V1_VBS, IF_REAL, "Vbs"), +OP( "vgs", BSIM3V1_VGS, IF_REAL, "Vgs"), +OP( "vds", BSIM3V1_VDS, IF_REAL, "Vds"), +/* serban */ +IOP( "m", BSIM3V1_M, IF_REAL , "Multiplication factor"), +}; + +IFparm BSIM3V1mPTable[] = { /* model parameters */ +IOP( "capmod", BSIM3V1_MOD_CAPMOD, IF_INTEGER, "Capacitance model selector"), +IOP( "nqsmod", BSIM3V1_MOD_NQSMOD, IF_INTEGER, "Non-quasi-static model selector"), +IOP( "mobmod", BSIM3V1_MOD_MOBMOD, IF_INTEGER, "Mobility model selector"), +IOP( "noimod", BSIM3V1_MOD_NOIMOD, IF_INTEGER, "Noise model selector"), +IOP( "paramchk", BSIM3V1_MOD_PARAMCHK, IF_INTEGER, "Model parameter checking selector"), +IOP( "binunit", BSIM3V1_MOD_BINUNIT, IF_INTEGER, "Bin unit selector"), +IOP( "version", BSIM3V1_MOD_VERSION, IF_REAL, " parameter for model version"), +IOP( "tox", BSIM3V1_MOD_TOX, IF_REAL, "Gate oxide thickness in meters"), + +IOP( "cdsc", BSIM3V1_MOD_CDSC, IF_REAL, "Drain/Source and channel coupling capacitance"), +IOP( "cdscb", BSIM3V1_MOD_CDSCB, IF_REAL, "Body-bias dependence of cdsc"), +IOP( "cdscd", BSIM3V1_MOD_CDSCD, IF_REAL, "Drain-bias dependence of cdsc"), +IOP( "cit", BSIM3V1_MOD_CIT, IF_REAL, "Interface state capacitance"), +IOP( "nfactor", BSIM3V1_MOD_NFACTOR, IF_REAL, "Subthreshold swing Coefficient"), +IOP( "xj", BSIM3V1_MOD_XJ, IF_REAL, "Junction depth in meters"), +IOP( "vsat", BSIM3V1_MOD_VSAT, IF_REAL, "Saturation velocity at tnom"), +IOP( "at", BSIM3V1_MOD_AT, IF_REAL, "Temperature coefficient of vsat"), +IOP( "a0", BSIM3V1_MOD_A0, IF_REAL, "Non-uniform depletion width effect coefficient."), +IOP( "ags", BSIM3V1_MOD_AGS, IF_REAL, "Gate bias coefficient of Abulk."), +IOP( "a1", BSIM3V1_MOD_A1, IF_REAL, "Non-saturation effect coefficient"), +IOP( "a2", BSIM3V1_MOD_A2, IF_REAL, "Non-saturation effect coefficient"), +IOP( "keta", BSIM3V1_MOD_KETA, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect."), +IOP( "nsub", BSIM3V1_MOD_NSUB, IF_REAL, "Substrate doping concentration"), +IOP( "nch", BSIM3V1_MOD_NPEAK, IF_REAL, "Channel doping concentration"), +IOP( "ngate", BSIM3V1_MOD_NGATE, IF_REAL, "Poly-gate doping concentration"), +IOP( "gamma1", BSIM3V1_MOD_GAMMA1, IF_REAL, "Vth body coefficient"), +IOP( "gamma2", BSIM3V1_MOD_GAMMA2, IF_REAL, "Vth body coefficient"), +IOP( "vbx", BSIM3V1_MOD_VBX, IF_REAL, "Vth transition body Voltage"), +IOP( "vbm", BSIM3V1_MOD_VBM, IF_REAL, "Maximum body voltage"), + +IOP( "xt", BSIM3V1_MOD_XT, IF_REAL, "Doping depth"), +IOP( "k1", BSIM3V1_MOD_K1, IF_REAL, "Bulk effect coefficient 1"), +IOP( "kt1", BSIM3V1_MOD_KT1, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt1l", BSIM3V1_MOD_KT1L, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt2", BSIM3V1_MOD_KT2, IF_REAL, "Body-coefficient of kt1"), +IOP( "k2", BSIM3V1_MOD_K2, IF_REAL, "Bulk effect coefficient 2"), +IOP( "k3", BSIM3V1_MOD_K3, IF_REAL, "Narrow width effect coefficient"), +IOP( "k3b", BSIM3V1_MOD_K3B, IF_REAL, "Body effect coefficient of k3"), +IOP( "w0", BSIM3V1_MOD_W0, IF_REAL, "Narrow width effect parameter"), +IOP( "nlx", BSIM3V1_MOD_NLX, IF_REAL, "Lateral non-uniform doping effect"), +IOP( "dvt0", BSIM3V1_MOD_DVT0, IF_REAL, "Short channel effect coeff. 0"), +IOP( "dvt1", BSIM3V1_MOD_DVT1, IF_REAL, "Short channel effect coeff. 1"), +IOP( "dvt2", BSIM3V1_MOD_DVT2, IF_REAL, "Short channel effect coeff. 2"), +IOP( "dvt0w", BSIM3V1_MOD_DVT0W, IF_REAL, "Narrow Width coeff. 0"), +IOP( "dvt1w", BSIM3V1_MOD_DVT1W, IF_REAL, "Narrow Width effect coeff. 1"), +IOP( "dvt2w", BSIM3V1_MOD_DVT2W, IF_REAL, "Narrow Width effect coeff. 2"), +IOP( "drout", BSIM3V1_MOD_DROUT, IF_REAL, "DIBL coefficient of output resistance"), +IOP( "dsub", BSIM3V1_MOD_DSUB, IF_REAL, "DIBL coefficient in the subthreshold region"), +IOP( "vth0", BSIM3V1_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "vtho", BSIM3V1_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "ua", BSIM3V1_MOD_UA, IF_REAL, "Linear gate dependence of mobility"), +IOP( "ua1", BSIM3V1_MOD_UA1, IF_REAL, "Temperature coefficient of ua"), +IOP( "ub", BSIM3V1_MOD_UB, IF_REAL, "Quadratic gate dependence of mobility"), +IOP( "ub1", BSIM3V1_MOD_UB1, IF_REAL, "Temperature coefficient of ub"), +IOP( "uc", BSIM3V1_MOD_UC, IF_REAL, "Body-bias dependence of mobility"), +IOP( "uc1", BSIM3V1_MOD_UC1, IF_REAL, "Temperature coefficient of uc"), +IOP( "u0", BSIM3V1_MOD_U0, IF_REAL, "Low-field mobility at Tnom"), +IOP( "ute", BSIM3V1_MOD_UTE, IF_REAL, "Temperature coefficient of mobility"), +IOP( "voff", BSIM3V1_MOD_VOFF, IF_REAL, "Threshold voltage offset"), +IOP( "tnom", BSIM3V1_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), +IOP( "cgso", BSIM3V1_MOD_CGSO, IF_REAL, "Gate-source overlap capacitance per width"), +IOP( "cgdo", BSIM3V1_MOD_CGDO, IF_REAL, "Gate-drain overlap capacitance per width"), +IOP( "cgbo", BSIM3V1_MOD_CGBO, IF_REAL, "Gate-bulk overlap capacitance per length"), +IOP( "xpart", BSIM3V1_MOD_XPART, IF_REAL, "Channel charge partitioning"), +IOP( "elm", BSIM3V1_MOD_ELM, IF_REAL, "Non-quasi-static Elmore Constant Parameter"), +IOP( "delta", BSIM3V1_MOD_DELTA, IF_REAL, "Effective Vds parameter"), +IOP( "rsh", BSIM3V1_MOD_RSH, IF_REAL, "Source-drain sheet resistance"), +IOP( "rdsw", BSIM3V1_MOD_RDSW, IF_REAL, "Source-drain resistance per width"), + +IOP( "prwg", BSIM3V1_MOD_PRWG, IF_REAL, "Gate-bias effect on parasitic resistance "), +IOP( "prwb", BSIM3V1_MOD_PRWB, IF_REAL, "Body-effect on parasitic resistance "), + +IOP( "prt", BSIM3V1_MOD_PRT, IF_REAL, "Temperature coefficient of parasitic resistance "), +IOP( "eta0", BSIM3V1_MOD_ETA0, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "etab", BSIM3V1_MOD_ETAB, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "pclm", BSIM3V1_MOD_PCLM, IF_REAL, "Channel length modulation Coefficient"), +IOP( "pdiblc1", BSIM3V1_MOD_PDIBL1, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblc2", BSIM3V1_MOD_PDIBL2, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblcb", BSIM3V1_MOD_PDIBLB, IF_REAL, "Body-effect on drain-induced barrier lowering"), +IOP( "pscbe1", BSIM3V1_MOD_PSCBE1, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pscbe2", BSIM3V1_MOD_PSCBE2, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pvag", BSIM3V1_MOD_PVAG, IF_REAL, "Gate dependence of output resistance parameter"), +IOP( "js", BSIM3V1_MOD_JS, IF_REAL, "Source/drain junction reverse saturation current density"), +IOP( "jsw", BSIM3V1_MOD_JSW, IF_REAL, "Sidewall junction reverse saturation current density"), +IOP( "pb", BSIM3V1_MOD_PB, IF_REAL, "Source/drain junction built-in potential"), +IOP( "nj", BSIM3V1_MOD_NJ, IF_REAL, "Source/drain junction emission coefficient"), +IOP( "xti", BSIM3V1_MOD_XTI, IF_REAL, "Junction current temperature exponent"), +IOP( "mj", BSIM3V1_MOD_MJ, IF_REAL, "Source/drain bottom junction capacitance grading coefficient"), +IOP( "pbsw", BSIM3V1_MOD_PBSW, IF_REAL, "Source/drain sidewall junction capacitance built in potential"), +IOP( "mjsw", BSIM3V1_MOD_MJSW, IF_REAL, "Source/drain sidewall junction capacitance grading coefficient"), +IOP( "pbswg", BSIM3V1_MOD_PBSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance built in potential"), +IOP( "mjswg", BSIM3V1_MOD_MJSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance grading coefficient"), +IOP( "cj", BSIM3V1_MOD_CJ, IF_REAL, "Source/drain bottom junction capacitance per unit area"), +IOP( "vfbcv", BSIM3V1_MOD_VFBCV, IF_REAL, "Flat Band Voltage parameter for capmod=0 only"), +IOP( "cjsw", BSIM3V1_MOD_CJSW, IF_REAL, "Source/drain sidewall junction capacitance per unit periphery"), + +IOP( "cjswg", BSIM3V1_MOD_CJSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance per unit width"), +IOP( "lint", BSIM3V1_MOD_LINT, IF_REAL, "Length reduction parameter"), +IOP( "ll", BSIM3V1_MOD_LL, IF_REAL, "Length reduction parameter"), +IOP( "lln", BSIM3V1_MOD_LLN, IF_REAL, "Length reduction parameter"), +IOP( "lw", BSIM3V1_MOD_LW, IF_REAL, "Length reduction parameter"), +IOP( "lwn", BSIM3V1_MOD_LWN, IF_REAL, "Length reduction parameter"), +IOP( "lwl", BSIM3V1_MOD_LWL, IF_REAL, "Length reduction parameter"), +IOP( "lmin", BSIM3V1_MOD_LMIN, IF_REAL, "Minimum length for the model"), +IOP( "lmax", BSIM3V1_MOD_LMAX, IF_REAL, "Maximum length for the model"), + +IOP( "wr", BSIM3V1_MOD_WR, IF_REAL, "Width dependence of rds"), +IOP( "wint", BSIM3V1_MOD_WINT, IF_REAL, "Width reduction parameter"), +IOP( "dwg", BSIM3V1_MOD_DWG, IF_REAL, "Width reduction parameter"), +IOP( "dwb", BSIM3V1_MOD_DWB, IF_REAL, "Width reduction parameter"), + +IOP( "wl", BSIM3V1_MOD_WL, IF_REAL, "Width reduction parameter"), +IOP( "wln", BSIM3V1_MOD_WLN, IF_REAL, "Width reduction parameter"), +IOP( "ww", BSIM3V1_MOD_WW, IF_REAL, "Width reduction parameter"), +IOP( "wwn", BSIM3V1_MOD_WWN, IF_REAL, "Width reduction parameter"), +IOP( "wwl", BSIM3V1_MOD_WWL, IF_REAL, "Width reduction parameter"), +IOP( "wmin", BSIM3V1_MOD_WMIN, IF_REAL, "Minimum width for the model"), +IOP( "wmax", BSIM3V1_MOD_WMAX, IF_REAL, "Maximum width for the model"), + +IOP( "b0", BSIM3V1_MOD_B0, IF_REAL, "Abulk narrow width parameter"), +IOP( "b1", BSIM3V1_MOD_B1, IF_REAL, "Abulk narrow width parameter"), + +IOP( "cgsl", BSIM3V1_MOD_CGSL, IF_REAL, "New C-V model parameter"), +IOP( "cgdl", BSIM3V1_MOD_CGDL, IF_REAL, "New C-V model parameter"), +IOP( "ckappa", BSIM3V1_MOD_CKAPPA, IF_REAL, "New C-V model parameter"), +IOP( "cf", BSIM3V1_MOD_CF, IF_REAL, "Fringe capacitance parameter"), +IOP( "clc", BSIM3V1_MOD_CLC, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "cle", BSIM3V1_MOD_CLE, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "dwc", BSIM3V1_MOD_DWC, IF_REAL, "Delta W for C-V model"), +IOP( "dlc", BSIM3V1_MOD_DLC, IF_REAL, "Delta L for C-V model"), + +IOP( "alpha0", BSIM3V1_MOD_ALPHA0, IF_REAL, "substrate current model parameter"), +IOP( "beta0", BSIM3V1_MOD_BETA0, IF_REAL, "substrate current model parameter"), + +IOP( "lcdsc", BSIM3V1_MOD_LCDSC, IF_REAL, "Length dependence of cdsc"), +IOP( "lcdscb", BSIM3V1_MOD_LCDSCB, IF_REAL, "Length dependence of cdscb"), +IOP( "lcdscd", BSIM3V1_MOD_LCDSCD, IF_REAL, "Length dependence of cdscd"), +IOP( "lcit", BSIM3V1_MOD_LCIT, IF_REAL, "Length dependence of cit"), +IOP( "lnfactor", BSIM3V1_MOD_LNFACTOR, IF_REAL, "Length dependence of nfactor"), +IOP( "lxj", BSIM3V1_MOD_LXJ, IF_REAL, "Length dependence of xj"), +IOP( "lvsat", BSIM3V1_MOD_LVSAT, IF_REAL, "Length dependence of vsat"), +IOP( "lat", BSIM3V1_MOD_LAT, IF_REAL, "Length dependence of at"), +IOP( "la0", BSIM3V1_MOD_LA0, IF_REAL, "Length dependence of a0"), +IOP( "lags", BSIM3V1_MOD_LAGS, IF_REAL, "Length dependence of ags"), +IOP( "la1", BSIM3V1_MOD_LA1, IF_REAL, "Length dependence of a1"), +IOP( "la2", BSIM3V1_MOD_LA2, IF_REAL, "Length dependence of a2"), +IOP( "lketa", BSIM3V1_MOD_LKETA, IF_REAL, "Length dependence of keta"), +IOP( "lnsub", BSIM3V1_MOD_LNSUB, IF_REAL, "Length dependence of nsub"), +IOP( "lnch", BSIM3V1_MOD_LNPEAK, IF_REAL, "Length dependence of nch"), +IOP( "lngate", BSIM3V1_MOD_LNGATE, IF_REAL, "Length dependence of ngate"), +IOP( "lgamma1", BSIM3V1_MOD_LGAMMA1, IF_REAL, "Length dependence of gamma1"), +IOP( "lgamma2", BSIM3V1_MOD_LGAMMA2, IF_REAL, "Length dependence of gamma2"), +IOP( "lvbx", BSIM3V1_MOD_LVBX, IF_REAL, "Length dependence of vbx"), +IOP( "lvbm", BSIM3V1_MOD_LVBM, IF_REAL, "Length dependence of vbm"), +IOP( "lxt", BSIM3V1_MOD_LXT, IF_REAL, "Length dependence of xt"), +IOP( "lk1", BSIM3V1_MOD_LK1, IF_REAL, "Length dependence of k1"), +IOP( "lkt1", BSIM3V1_MOD_LKT1, IF_REAL, "Length dependence of kt1"), +IOP( "lkt1l", BSIM3V1_MOD_LKT1L, IF_REAL, "Length dependence of kt1l"), +IOP( "lkt2", BSIM3V1_MOD_LKT2, IF_REAL, "Length dependence of kt2"), +IOP( "lk2", BSIM3V1_MOD_LK2, IF_REAL, "Length dependence of k2"), +IOP( "lk3", BSIM3V1_MOD_LK3, IF_REAL, "Length dependence of k3"), +IOP( "lk3b", BSIM3V1_MOD_LK3B, IF_REAL, "Length dependence of k3b"), +IOP( "lw0", BSIM3V1_MOD_LW0, IF_REAL, "Length dependence of w0"), +IOP( "lnlx", BSIM3V1_MOD_LNLX, IF_REAL, "Length dependence of nlx"), +IOP( "ldvt0", BSIM3V1_MOD_LDVT0, IF_REAL, "Length dependence of dvt0"), +IOP( "ldvt1", BSIM3V1_MOD_LDVT1, IF_REAL, "Length dependence of dvt1"), +IOP( "ldvt2", BSIM3V1_MOD_LDVT2, IF_REAL, "Length dependence of dvt2"), +IOP( "ldvt0w", BSIM3V1_MOD_LDVT0W, IF_REAL, "Length dependence of dvt0w"), +IOP( "ldvt1w", BSIM3V1_MOD_LDVT1W, IF_REAL, "Length dependence of dvt1w"), +IOP( "ldvt2w", BSIM3V1_MOD_LDVT2W, IF_REAL, "Length dependence of dvt2w"), +IOP( "ldrout", BSIM3V1_MOD_LDROUT, IF_REAL, "Length dependence of drout"), +IOP( "ldsub", BSIM3V1_MOD_LDSUB, IF_REAL, "Length dependence of dsub"), +IOP( "lvth0", BSIM3V1_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lvtho", BSIM3V1_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lua", BSIM3V1_MOD_LUA, IF_REAL, "Length dependence of ua"), +IOP( "lua1", BSIM3V1_MOD_LUA1, IF_REAL, "Length dependence of ua1"), +IOP( "lub", BSIM3V1_MOD_LUB, IF_REAL, "Length dependence of ub"), +IOP( "lub1", BSIM3V1_MOD_LUB1, IF_REAL, "Length dependence of ub1"), +IOP( "luc", BSIM3V1_MOD_LUC, IF_REAL, "Length dependence of uc"), +IOP( "luc1", BSIM3V1_MOD_LUC1, IF_REAL, "Length dependence of uc1"), +IOP( "lu0", BSIM3V1_MOD_LU0, IF_REAL, "Length dependence of u0"), +IOP( "lute", BSIM3V1_MOD_LUTE, IF_REAL, "Length dependence of ute"), +IOP( "lvoff", BSIM3V1_MOD_LVOFF, IF_REAL, "Length dependence of voff"), +IOP( "lelm", BSIM3V1_MOD_LELM, IF_REAL, "Length dependence of elm"), +IOP( "ldelta", BSIM3V1_MOD_LDELTA, IF_REAL, "Length dependence of delta"), +IOP( "lrdsw", BSIM3V1_MOD_LRDSW, IF_REAL, "Length dependence of rdsw "), + +IOP( "lprwg", BSIM3V1_MOD_LPRWG, IF_REAL, "Length dependence of prwg "), +IOP( "lprwb", BSIM3V1_MOD_LPRWB, IF_REAL, "Length dependence of prwb "), + +IOP( "lprt", BSIM3V1_MOD_LPRT, IF_REAL, "Length dependence of prt "), +IOP( "leta0", BSIM3V1_MOD_LETA0, IF_REAL, "Length dependence of eta0"), +IOP( "letab", BSIM3V1_MOD_LETAB, IF_REAL, "Length dependence of etab"), +IOP( "lpclm", BSIM3V1_MOD_LPCLM, IF_REAL, "Length dependence of pclm"), +IOP( "lpdiblc1", BSIM3V1_MOD_LPDIBL1, IF_REAL, "Length dependence of pdiblc1"), +IOP( "lpdiblc2", BSIM3V1_MOD_LPDIBL2, IF_REAL, "Length dependence of pdiblc2"), +IOP( "lpdiblcb", BSIM3V1_MOD_LPDIBLB, IF_REAL, "Length dependence of pdiblcb"), +IOP( "lpscbe1", BSIM3V1_MOD_LPSCBE1, IF_REAL, "Length dependence of pscbe1"), +IOP( "lpscbe2", BSIM3V1_MOD_LPSCBE2, IF_REAL, "Length dependence of pscbe2"), +IOP( "lpvag", BSIM3V1_MOD_LPVAG, IF_REAL, "Length dependence of pvag"), +IOP( "lwr", BSIM3V1_MOD_LWR, IF_REAL, "Length dependence of wr"), +IOP( "ldwg", BSIM3V1_MOD_LDWG, IF_REAL, "Length dependence of dwg"), +IOP( "ldwb", BSIM3V1_MOD_LDWB, IF_REAL, "Length dependence of dwb"), +IOP( "lb0", BSIM3V1_MOD_LB0, IF_REAL, "Length dependence of b0"), +IOP( "lb1", BSIM3V1_MOD_LB1, IF_REAL, "Length dependence of b1"), +IOP( "lcgsl", BSIM3V1_MOD_LCGSL, IF_REAL, "Length dependence of cgsl"), +IOP( "lcgdl", BSIM3V1_MOD_LCGDL, IF_REAL, "Length dependence of cgdl"), +IOP( "lckappa", BSIM3V1_MOD_LCKAPPA, IF_REAL, "Length dependence of ckappa"), +IOP( "lcf", BSIM3V1_MOD_LCF, IF_REAL, "Length dependence of cf"), +IOP( "lclc", BSIM3V1_MOD_LCLC, IF_REAL, "Length dependence of clc"), +IOP( "lcle", BSIM3V1_MOD_LCLE, IF_REAL, "Length dependence of cle"), +IOP( "lalpha0", BSIM3V1_MOD_LALPHA0, IF_REAL, "Length dependence of alpha0"), +IOP( "lbeta0", BSIM3V1_MOD_LBETA0, IF_REAL, "Length dependence of beta0"), +IOP( "lvfbcv", BSIM3V1_MOD_LVFBCV, IF_REAL, "Length dependence of vfbcv"), +IOP( "wcdsc", BSIM3V1_MOD_WCDSC, IF_REAL, "Width dependence of cdsc"), +IOP( "wcdscb", BSIM3V1_MOD_WCDSCB, IF_REAL, "Width dependence of cdscb"), +IOP( "wcdscd", BSIM3V1_MOD_WCDSCD, IF_REAL, "Width dependence of cdscd"), +IOP( "wcit", BSIM3V1_MOD_WCIT, IF_REAL, "Width dependence of cit"), +IOP( "wnfactor", BSIM3V1_MOD_WNFACTOR, IF_REAL, "Width dependence of nfactor"), +IOP( "wxj", BSIM3V1_MOD_WXJ, IF_REAL, "Width dependence of xj"), +IOP( "wvsat", BSIM3V1_MOD_WVSAT, IF_REAL, "Width dependence of vsat"), +IOP( "wat", BSIM3V1_MOD_WAT, IF_REAL, "Width dependence of at"), +IOP( "wa0", BSIM3V1_MOD_WA0, IF_REAL, "Width dependence of a0"), +IOP( "wags", BSIM3V1_MOD_WAGS, IF_REAL, "Width dependence of ags"), +IOP( "wa1", BSIM3V1_MOD_WA1, IF_REAL, "Width dependence of a1"), +IOP( "wa2", BSIM3V1_MOD_WA2, IF_REAL, "Width dependence of a2"), +IOP( "wketa", BSIM3V1_MOD_WKETA, IF_REAL, "Width dependence of keta"), +IOP( "wnsub", BSIM3V1_MOD_WNSUB, IF_REAL, "Width dependence of nsub"), +IOP( "wnch", BSIM3V1_MOD_WNPEAK, IF_REAL, "Width dependence of nch"), +IOP( "wngate", BSIM3V1_MOD_WNGATE, IF_REAL, "Width dependence of ngate"), +IOP( "wgamma1", BSIM3V1_MOD_WGAMMA1, IF_REAL, "Width dependence of gamma1"), +IOP( "wgamma2", BSIM3V1_MOD_WGAMMA2, IF_REAL, "Width dependence of gamma2"), +IOP( "wvbx", BSIM3V1_MOD_WVBX, IF_REAL, "Width dependence of vbx"), +IOP( "wvbm", BSIM3V1_MOD_WVBM, IF_REAL, "Width dependence of vbm"), +IOP( "wxt", BSIM3V1_MOD_WXT, IF_REAL, "Width dependence of xt"), +IOP( "wk1", BSIM3V1_MOD_WK1, IF_REAL, "Width dependence of k1"), +IOP( "wkt1", BSIM3V1_MOD_WKT1, IF_REAL, "Width dependence of kt1"), +IOP( "wkt1l", BSIM3V1_MOD_WKT1L, IF_REAL, "Width dependence of kt1l"), +IOP( "wkt2", BSIM3V1_MOD_WKT2, IF_REAL, "Width dependence of kt2"), +IOP( "wk2", BSIM3V1_MOD_WK2, IF_REAL, "Width dependence of k2"), +IOP( "wk3", BSIM3V1_MOD_WK3, IF_REAL, "Width dependence of k3"), +IOP( "wk3b", BSIM3V1_MOD_WK3B, IF_REAL, "Width dependence of k3b"), +IOP( "ww0", BSIM3V1_MOD_WW0, IF_REAL, "Width dependence of w0"), +IOP( "wnlx", BSIM3V1_MOD_WNLX, IF_REAL, "Width dependence of nlx"), +IOP( "wdvt0", BSIM3V1_MOD_WDVT0, IF_REAL, "Width dependence of dvt0"), +IOP( "wdvt1", BSIM3V1_MOD_WDVT1, IF_REAL, "Width dependence of dvt1"), +IOP( "wdvt2", BSIM3V1_MOD_WDVT2, IF_REAL, "Width dependence of dvt2"), +IOP( "wdvt0w", BSIM3V1_MOD_WDVT0W, IF_REAL, "Width dependence of dvt0w"), +IOP( "wdvt1w", BSIM3V1_MOD_WDVT1W, IF_REAL, "Width dependence of dvt1w"), +IOP( "wdvt2w", BSIM3V1_MOD_WDVT2W, IF_REAL, "Width dependence of dvt2w"), +IOP( "wdrout", BSIM3V1_MOD_WDROUT, IF_REAL, "Width dependence of drout"), +IOP( "wdsub", BSIM3V1_MOD_WDSUB, IF_REAL, "Width dependence of dsub"), +IOP( "wvth0", BSIM3V1_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wvtho", BSIM3V1_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wua", BSIM3V1_MOD_WUA, IF_REAL, "Width dependence of ua"), +IOP( "wua1", BSIM3V1_MOD_WUA1, IF_REAL, "Width dependence of ua1"), +IOP( "wub", BSIM3V1_MOD_WUB, IF_REAL, "Width dependence of ub"), +IOP( "wub1", BSIM3V1_MOD_WUB1, IF_REAL, "Width dependence of ub1"), +IOP( "wuc", BSIM3V1_MOD_WUC, IF_REAL, "Width dependence of uc"), +IOP( "wuc1", BSIM3V1_MOD_WUC1, IF_REAL, "Width dependence of uc1"), +IOP( "wu0", BSIM3V1_MOD_WU0, IF_REAL, "Width dependence of u0"), +IOP( "wute", BSIM3V1_MOD_WUTE, IF_REAL, "Width dependence of ute"), +IOP( "wvoff", BSIM3V1_MOD_WVOFF, IF_REAL, "Width dependence of voff"), +IOP( "welm", BSIM3V1_MOD_WELM, IF_REAL, "Width dependence of elm"), +IOP( "wdelta", BSIM3V1_MOD_WDELTA, IF_REAL, "Width dependence of delta"), +IOP( "wrdsw", BSIM3V1_MOD_WRDSW, IF_REAL, "Width dependence of rdsw "), + +IOP( "wprwg", BSIM3V1_MOD_WPRWG, IF_REAL, "Width dependence of prwg "), +IOP( "wprwb", BSIM3V1_MOD_WPRWB, IF_REAL, "Width dependence of prwb "), + +IOP( "wprt", BSIM3V1_MOD_WPRT, IF_REAL, "Width dependence of prt"), +IOP( "weta0", BSIM3V1_MOD_WETA0, IF_REAL, "Width dependence of eta0"), +IOP( "wetab", BSIM3V1_MOD_WETAB, IF_REAL, "Width dependence of etab"), +IOP( "wpclm", BSIM3V1_MOD_WPCLM, IF_REAL, "Width dependence of pclm"), +IOP( "wpdiblc1", BSIM3V1_MOD_WPDIBL1, IF_REAL, "Width dependence of pdiblc1"), +IOP( "wpdiblc2", BSIM3V1_MOD_WPDIBL2, IF_REAL, "Width dependence of pdiblc2"), +IOP( "wpdiblcb", BSIM3V1_MOD_WPDIBLB, IF_REAL, "Width dependence of pdiblcb"), +IOP( "wpscbe1", BSIM3V1_MOD_WPSCBE1, IF_REAL, "Width dependence of pscbe1"), +IOP( "wpscbe2", BSIM3V1_MOD_WPSCBE2, IF_REAL, "Width dependence of pscbe2"), +IOP( "wpvag", BSIM3V1_MOD_WPVAG, IF_REAL, "Width dependence of pvag"), +IOP( "wwr", BSIM3V1_MOD_WWR, IF_REAL, "Width dependence of wr"), +IOP( "wdwg", BSIM3V1_MOD_WDWG, IF_REAL, "Width dependence of dwg"), +IOP( "wdwb", BSIM3V1_MOD_WDWB, IF_REAL, "Width dependence of dwb"), +IOP( "wb0", BSIM3V1_MOD_WB0, IF_REAL, "Width dependence of b0"), +IOP( "wb1", BSIM3V1_MOD_WB1, IF_REAL, "Width dependence of b1"), +IOP( "wcgsl", BSIM3V1_MOD_WCGSL, IF_REAL, "Width dependence of cgsl"), +IOP( "wcgdl", BSIM3V1_MOD_WCGDL, IF_REAL, "Width dependence of cgdl"), +IOP( "wckappa", BSIM3V1_MOD_WCKAPPA, IF_REAL, "Width dependence of ckappa"), +IOP( "wcf", BSIM3V1_MOD_WCF, IF_REAL, "Width dependence of cf"), +IOP( "wclc", BSIM3V1_MOD_WCLC, IF_REAL, "Width dependence of clc"), +IOP( "wcle", BSIM3V1_MOD_WCLE, IF_REAL, "Width dependence of cle"), +IOP( "walpha0", BSIM3V1_MOD_WALPHA0, IF_REAL, "Width dependence of alpha0"), +IOP( "wbeta0", BSIM3V1_MOD_WBETA0, IF_REAL, "Width dependence of beta0"), +IOP( "wvfbcv", BSIM3V1_MOD_WVFBCV, IF_REAL, "Width dependence of vfbcv"), + +IOP( "pcdsc", BSIM3V1_MOD_PCDSC, IF_REAL, "Cross-term dependence of cdsc"), +IOP( "pcdscb", BSIM3V1_MOD_PCDSCB, IF_REAL, "Cross-term dependence of cdscb"), +IOP( "pcdscd", BSIM3V1_MOD_PCDSCD, IF_REAL, "Cross-term dependence of cdscd"), +IOP( "pcit", BSIM3V1_MOD_PCIT, IF_REAL, "Cross-term dependence of cit"), +IOP( "pnfactor", BSIM3V1_MOD_PNFACTOR, IF_REAL, "Cross-term dependence of nfactor"), +IOP( "pxj", BSIM3V1_MOD_PXJ, IF_REAL, "Cross-term dependence of xj"), +IOP( "pvsat", BSIM3V1_MOD_PVSAT, IF_REAL, "Cross-term dependence of vsat"), +IOP( "pat", BSIM3V1_MOD_PAT, IF_REAL, "Cross-term dependence of at"), +IOP( "pa0", BSIM3V1_MOD_PA0, IF_REAL, "Cross-term dependence of a0"), +IOP( "pags", BSIM3V1_MOD_PAGS, IF_REAL, "Cross-term dependence of ags"), +IOP( "pa1", BSIM3V1_MOD_PA1, IF_REAL, "Cross-term dependence of a1"), +IOP( "pa2", BSIM3V1_MOD_PA2, IF_REAL, "Cross-term dependence of a2"), +IOP( "pketa", BSIM3V1_MOD_PKETA, IF_REAL, "Cross-term dependence of keta"), +IOP( "pnsub", BSIM3V1_MOD_PNSUB, IF_REAL, "Cross-term dependence of nsub"), +IOP( "pnch", BSIM3V1_MOD_PNPEAK, IF_REAL, "Cross-term dependence of nch"), +IOP( "pngate", BSIM3V1_MOD_PNGATE, IF_REAL, "Cross-term dependence of ngate"), +IOP( "pgamma1", BSIM3V1_MOD_PGAMMA1, IF_REAL, "Cross-term dependence of gamma1"), +IOP( "pgamma2", BSIM3V1_MOD_PGAMMA2, IF_REAL, "Cross-term dependence of gamma2"), +IOP( "pvbx", BSIM3V1_MOD_PVBX, IF_REAL, "Cross-term dependence of vbx"), +IOP( "pvbm", BSIM3V1_MOD_PVBM, IF_REAL, "Cross-term dependence of vbm"), +IOP( "pxt", BSIM3V1_MOD_PXT, IF_REAL, "Cross-term dependence of xt"), +IOP( "pk1", BSIM3V1_MOD_PK1, IF_REAL, "Cross-term dependence of k1"), +IOP( "pkt1", BSIM3V1_MOD_PKT1, IF_REAL, "Cross-term dependence of kt1"), +IOP( "pkt1l", BSIM3V1_MOD_PKT1L, IF_REAL, "Cross-term dependence of kt1l"), +IOP( "pkt2", BSIM3V1_MOD_PKT2, IF_REAL, "Cross-term dependence of kt2"), +IOP( "pk2", BSIM3V1_MOD_PK2, IF_REAL, "Cross-term dependence of k2"), +IOP( "pk3", BSIM3V1_MOD_PK3, IF_REAL, "Cross-term dependence of k3"), +IOP( "pk3b", BSIM3V1_MOD_PK3B, IF_REAL, "Cross-term dependence of k3b"), +IOP( "pw0", BSIM3V1_MOD_PW0, IF_REAL, "Cross-term dependence of w0"), +IOP( "pnlx", BSIM3V1_MOD_PNLX, IF_REAL, "Cross-term dependence of nlx"), +IOP( "pdvt0", BSIM3V1_MOD_PDVT0, IF_REAL, "Cross-term dependence of dvt0"), +IOP( "pdvt1", BSIM3V1_MOD_PDVT1, IF_REAL, "Cross-term dependence of dvt1"), +IOP( "pdvt2", BSIM3V1_MOD_PDVT2, IF_REAL, "Cross-term dependence of dvt2"), +IOP( "pdvt0w", BSIM3V1_MOD_PDVT0W, IF_REAL, "Cross-term dependence of dvt0w"), +IOP( "pdvt1w", BSIM3V1_MOD_PDVT1W, IF_REAL, "Cross-term dependence of dvt1w"), +IOP( "pdvt2w", BSIM3V1_MOD_PDVT2W, IF_REAL, "Cross-term dependence of dvt2w"), +IOP( "pdrout", BSIM3V1_MOD_PDROUT, IF_REAL, "Cross-term dependence of drout"), +IOP( "pdsub", BSIM3V1_MOD_PDSUB, IF_REAL, "Cross-term dependence of dsub"), +IOP( "pvth0", BSIM3V1_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pvtho", BSIM3V1_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pua", BSIM3V1_MOD_PUA, IF_REAL, "Cross-term dependence of ua"), +IOP( "pua1", BSIM3V1_MOD_PUA1, IF_REAL, "Cross-term dependence of ua1"), +IOP( "pub", BSIM3V1_MOD_PUB, IF_REAL, "Cross-term dependence of ub"), +IOP( "pub1", BSIM3V1_MOD_PUB1, IF_REAL, "Cross-term dependence of ub1"), +IOP( "puc", BSIM3V1_MOD_PUC, IF_REAL, "Cross-term dependence of uc"), +IOP( "puc1", BSIM3V1_MOD_PUC1, IF_REAL, "Cross-term dependence of uc1"), +IOP( "pu0", BSIM3V1_MOD_PU0, IF_REAL, "Cross-term dependence of u0"), +IOP( "pute", BSIM3V1_MOD_PUTE, IF_REAL, "Cross-term dependence of ute"), +IOP( "pvoff", BSIM3V1_MOD_PVOFF, IF_REAL, "Cross-term dependence of voff"), +IOP( "pelm", BSIM3V1_MOD_PELM, IF_REAL, "Cross-term dependence of elm"), +IOP( "pdelta", BSIM3V1_MOD_PDELTA, IF_REAL, "Cross-term dependence of delta"), +IOP( "prdsw", BSIM3V1_MOD_PRDSW, IF_REAL, "Cross-term dependence of rdsw "), + +IOP( "pprwg", BSIM3V1_MOD_PPRWG, IF_REAL, "Cross-term dependence of prwg "), +IOP( "pprwb", BSIM3V1_MOD_PPRWB, IF_REAL, "Cross-term dependence of prwb "), + +IOP( "pprt", BSIM3V1_MOD_PPRT, IF_REAL, "Cross-term dependence of prt "), +IOP( "peta0", BSIM3V1_MOD_PETA0, IF_REAL, "Cross-term dependence of eta0"), +IOP( "petab", BSIM3V1_MOD_PETAB, IF_REAL, "Cross-term dependence of etab"), +IOP( "ppclm", BSIM3V1_MOD_PPCLM, IF_REAL, "Cross-term dependence of pclm"), +IOP( "ppdiblc1", BSIM3V1_MOD_PPDIBL1, IF_REAL, "Cross-term dependence of pdiblc1"), +IOP( "ppdiblc2", BSIM3V1_MOD_PPDIBL2, IF_REAL, "Cross-term dependence of pdiblc2"), +IOP( "ppdiblcb", BSIM3V1_MOD_PPDIBLB, IF_REAL, "Cross-term dependence of pdiblcb"), +IOP( "ppscbe1", BSIM3V1_MOD_PPSCBE1, IF_REAL, "Cross-term dependence of pscbe1"), +IOP( "ppscbe2", BSIM3V1_MOD_PPSCBE2, IF_REAL, "Cross-term dependence of pscbe2"), +IOP( "ppvag", BSIM3V1_MOD_PPVAG, IF_REAL, "Cross-term dependence of pvag"), +IOP( "pwr", BSIM3V1_MOD_PWR, IF_REAL, "Cross-term dependence of wr"), +IOP( "pdwg", BSIM3V1_MOD_PDWG, IF_REAL, "Cross-term dependence of dwg"), +IOP( "pdwb", BSIM3V1_MOD_PDWB, IF_REAL, "Cross-term dependence of dwb"), +IOP( "pb0", BSIM3V1_MOD_PB0, IF_REAL, "Cross-term dependence of b0"), +IOP( "pb1", BSIM3V1_MOD_PB1, IF_REAL, "Cross-term dependence of b1"), +IOP( "pcgsl", BSIM3V1_MOD_PCGSL, IF_REAL, "Cross-term dependence of cgsl"), +IOP( "pcgdl", BSIM3V1_MOD_PCGDL, IF_REAL, "Cross-term dependence of cgdl"), +IOP( "pckappa", BSIM3V1_MOD_PCKAPPA, IF_REAL, "Cross-term dependence of ckappa"), +IOP( "pcf", BSIM3V1_MOD_PCF, IF_REAL, "Cross-term dependence of cf"), +IOP( "pclc", BSIM3V1_MOD_PCLC, IF_REAL, "Cross-term dependence of clc"), +IOP( "pcle", BSIM3V1_MOD_PCLE, IF_REAL, "Cross-term dependence of cle"), +IOP( "palpha0", BSIM3V1_MOD_PALPHA0, IF_REAL, "Cross-term dependence of alpha0"), +IOP( "pbeta0", BSIM3V1_MOD_PBETA0, IF_REAL, "Cross-term dependence of beta0"), +IOP( "pvfbcv", BSIM3V1_MOD_PVFBCV, IF_REAL, "Cross-term dependence of vfbcv"), + +IOP( "noia", BSIM3V1_MOD_NOIA, IF_REAL, "Flicker noise parameter"), +IOP( "noib", BSIM3V1_MOD_NOIB, IF_REAL, "Flicker noise parameter"), +IOP( "noic", BSIM3V1_MOD_NOIC, IF_REAL, "Flicker noise parameter"), +IOP( "em", BSIM3V1_MOD_EM, IF_REAL, "Flicker noise parameter"), +IOP( "ef", BSIM3V1_MOD_EF, IF_REAL, "Flicker noise frequency exponent"), +IOP( "af", BSIM3V1_MOD_AF, IF_REAL, "Flicker noise exponent"), +IOP( "kf", BSIM3V1_MOD_KF, IF_REAL, "Flicker noise coefficient"), + +IP( "nmos", BSIM3V1_MOD_NMOS, IF_FLAG, "Flag to indicate NMOS"), +IP( "pmos", BSIM3V1_MOD_PMOS, IF_FLAG, "Flag to indicate PMOS"), +/* serban */ +IOP( "hdif", BSIM3V1_MOD_HDIF, IF_REAL, "S/D junction extension (HSPICE style)"), +}; + +char *BSIM3V1names[] = { + "Drain", + "Gate", + "Source", + "Bulk", + "Charge" +}; + +int BSIM3V1nSize = NUMELEMS(BSIM3V1names); +int BSIM3V1pTSize = NUMELEMS(BSIM3V1pTable); +int BSIM3V1mPTSize = NUMELEMS(BSIM3V1mPTable); +int BSIM3V1iSize = sizeof(BSIM3V1instance); +int BSIM3V1mSize = sizeof(BSIM3V1model); + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1acld.c b/src/spicelib/devices/bsim3v1/b3v1acld.c new file mode 100644 index 000000000..91dc95c9d --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1acld.c @@ -0,0 +1,194 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:51:00 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1acld.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V1acLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3V1model *model = (BSIM3V1model*)inModel; +register BSIM3V1instance *here; +double xcggb, xcgdb, xcgsb, xcbgb, xcbdb, xcbsb, xcddb, xcssb, xcdgb; +double gdpr, gspr, gds, gbd, gbs, capbd, capbs, xcsgb, xcdsb, xcsdb; +double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb, omega; +double GSoverlapCap, GDoverlapCap, GBoverlapCap, FwdSum, RevSum, Gm, Gmbs; + +double dxpart, sxpart, cqgb, cqdb, cqsb, cqbb, xcqgb, xcqdb, xcqsb, xcqbb; + + omega = ckt->CKTomega; + for (; model != NULL; model = model->BSIM3V1nextModel) + { + + + for (here = model->BSIM3V1instances; here!= NULL; + here = here->BSIM3V1nextInstance) + { + if (here->BSIM3V1owner != ARCHme) continue; + if (here->BSIM3V1mode >= 0) + { Gm = here->BSIM3V1gm; + Gmbs = here->BSIM3V1gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + cggb = here->BSIM3V1cggb; + cgsb = here->BSIM3V1cgsb; + cgdb = here->BSIM3V1cgdb; + + cbgb = here->BSIM3V1cbgb; + cbsb = here->BSIM3V1cbsb; + cbdb = here->BSIM3V1cbdb; + + cdgb = here->BSIM3V1cdgb; + cdsb = here->BSIM3V1cdsb; + cddb = here->BSIM3V1cddb; + + cqgb = here->BSIM3V1cqgb; + cqdb = here->BSIM3V1cqdb; + cqsb = here->BSIM3V1cqsb; + cqbb = here->BSIM3V1cqbb; + sxpart = 0.6; + dxpart = 0.4; + + } + else + { Gm = -here->BSIM3V1gm; + Gmbs = -here->BSIM3V1gmbs; + FwdSum = 0.0; + RevSum = -Gm - Gmbs; + cggb = here->BSIM3V1cggb; + cgsb = here->BSIM3V1cgdb; + cgdb = here->BSIM3V1cgsb; + + cbgb = here->BSIM3V1cbgb; + cbsb = here->BSIM3V1cbdb; + cbdb = here->BSIM3V1cbsb; + + cdgb = -(here->BSIM3V1cdgb + cggb + cbgb); + cdsb = -(here->BSIM3V1cddb + cgsb + cbsb); + cddb = -(here->BSIM3V1cdsb + cgdb + cbdb); + + cqgb = here->BSIM3V1cqgb; + cqdb = here->BSIM3V1cqsb; + cqsb = here->BSIM3V1cqdb; + cqbb = here->BSIM3V1cqbb; + sxpart = 0.4; + dxpart = 0.6; + } + + gdpr=here->BSIM3V1drainConductance; + gspr=here->BSIM3V1sourceConductance; + gds= here->BSIM3V1gds; + gbd= here->BSIM3V1gbd; + gbs= here->BSIM3V1gbs; + capbd= here->BSIM3V1capbd; + capbs= here->BSIM3V1capbs; + + GSoverlapCap = here->BSIM3V1cgso; + GDoverlapCap = here->BSIM3V1cgdo; + GBoverlapCap = here->pParam->BSIM3V1cgbo; + + xcdgb = (cdgb - GDoverlapCap) * omega; + xcddb = (cddb + capbd + GDoverlapCap) * omega; + xcdsb = cdsb * omega; + xcsgb = -(cggb + cbgb + cdgb + GSoverlapCap) * omega; + xcsdb = -(cgdb + cbdb + cddb) * omega; + xcssb = (capbs + GSoverlapCap - (cgsb + cbsb + cdsb)) * omega; + xcggb = (cggb + GDoverlapCap + GSoverlapCap + GBoverlapCap) + * omega; + xcgdb = (cgdb - GDoverlapCap ) * omega; + xcgsb = (cgsb - GSoverlapCap) * omega; + xcbgb = (cbgb - GBoverlapCap) * omega; + xcbdb = (cbdb - capbd ) * omega; + xcbsb = (cbsb - capbs ) * omega; + xcqgb = cqgb * omega; + xcqdb = cqdb * omega; + xcqsb = cqsb * omega; + xcqbb = cqbb * omega; + + *(here->BSIM3V1GgPtr +1) += xcggb; + *(here->BSIM3V1BbPtr +1) -= xcbgb + xcbdb + xcbsb; + *(here->BSIM3V1DPdpPtr +1) += xcddb; + *(here->BSIM3V1SPspPtr +1) += xcssb; + *(here->BSIM3V1GbPtr +1) -= xcggb + xcgdb + xcgsb; + *(here->BSIM3V1GdpPtr +1) += xcgdb; + *(here->BSIM3V1GspPtr +1) += xcgsb; + *(here->BSIM3V1BgPtr +1) += xcbgb; + *(here->BSIM3V1BdpPtr +1) += xcbdb; + *(here->BSIM3V1BspPtr +1) += xcbsb; + *(here->BSIM3V1DPgPtr +1) += xcdgb; + *(here->BSIM3V1DPbPtr +1) -= xcdgb + xcddb + xcdsb; + *(here->BSIM3V1DPspPtr +1) += xcdsb; + *(here->BSIM3V1SPgPtr +1) += xcsgb; + *(here->BSIM3V1SPbPtr +1) -= xcsgb + xcsdb + xcssb; + *(here->BSIM3V1SPdpPtr +1) += xcsdb; + + *(here->BSIM3V1QqPtr +1) += omega; + + *(here->BSIM3V1QgPtr +1) -= xcqgb; + *(here->BSIM3V1QdpPtr +1) -= xcqdb; + *(here->BSIM3V1QspPtr +1) -= xcqsb; + *(here->BSIM3V1QbPtr +1) -= xcqbb; + + + *(here->BSIM3V1DdPtr) += gdpr; + *(here->BSIM3V1SsPtr) += gspr; + *(here->BSIM3V1BbPtr) += gbd + gbs; + *(here->BSIM3V1DPdpPtr) += gdpr + gds + gbd + RevSum + dxpart*here->BSIM3V1gtd; + *(here->BSIM3V1SPspPtr) += gspr + gds + gbs + FwdSum + sxpart*here->BSIM3V1gts; + *(here->BSIM3V1DdpPtr) -= gdpr; + *(here->BSIM3V1SspPtr) -= gspr; + *(here->BSIM3V1BdpPtr) -= gbd; + *(here->BSIM3V1BspPtr) -= gbs; + *(here->BSIM3V1DPdPtr) -= gdpr; + *(here->BSIM3V1DPgPtr) += Gm + dxpart * here->BSIM3V1gtg; + *(here->BSIM3V1DPbPtr) -= gbd - Gmbs - dxpart * here->BSIM3V1gtb; + *(here->BSIM3V1DPspPtr) -= gds + FwdSum - dxpart * here->BSIM3V1gts; + *(here->BSIM3V1SPgPtr) -= Gm - sxpart * here->BSIM3V1gtg; + *(here->BSIM3V1SPsPtr) -= gspr; + *(here->BSIM3V1SPbPtr) -= gbs + Gmbs - sxpart * here->BSIM3V1gtg; + *(here->BSIM3V1SPdpPtr) -= gds + RevSum - sxpart * here->BSIM3V1gtd; + *(here->BSIM3V1GgPtr) -= here->BSIM3V1gtg; + *(here->BSIM3V1GbPtr) -= here->BSIM3V1gtb; + *(here->BSIM3V1GdpPtr) -= here->BSIM3V1gtd; + *(here->BSIM3V1GspPtr) -= here->BSIM3V1gts; + + *(here->BSIM3V1QqPtr) += here->BSIM3V1gtau; + + *(here->BSIM3V1DPqPtr) += dxpart * here->BSIM3V1gtau; + *(here->BSIM3V1SPqPtr) += sxpart * here->BSIM3V1gtau; + *(here->BSIM3V1GqPtr) -= here->BSIM3V1gtau; + + *(here->BSIM3V1QgPtr) += here->BSIM3V1gtg; + *(here->BSIM3V1QdpPtr) += here->BSIM3V1gtd; + *(here->BSIM3V1QspPtr) += here->BSIM3V1gts; + *(here->BSIM3V1QbPtr) += here->BSIM3V1gtb; + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3v1/b3v1ask.c b/src/spicelib/devices/bsim3v1/b3v1ask.c new file mode 100644 index 000000000..7db286aaf --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1ask.c @@ -0,0 +1,212 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:51:33 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1ask.c +**********/ + +#include "ngspice.h" +#include +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim3v1def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V1ask(ckt,inst,which,value,select) +CKTcircuit *ckt; +GENinstance *inst; +int which; +IFvalue *value; +IFvalue *select; +{ +BSIM3V1instance *here = (BSIM3V1instance*)inst; + + switch(which) + { case BSIM3V1_L: + value->rValue = here->BSIM3V1l; + return(OK); + case BSIM3V1_W: + value->rValue = here->BSIM3V1w; + return(OK); + case BSIM3V1_AS: + value->rValue = here->BSIM3V1sourceArea; + return(OK); + case BSIM3V1_AD: + value->rValue = here->BSIM3V1drainArea; + return(OK); + case BSIM3V1_PS: + value->rValue = here->BSIM3V1sourcePerimeter; + return(OK); + case BSIM3V1_PD: + value->rValue = here->BSIM3V1drainPerimeter; + return(OK); + case BSIM3V1_NRS: + value->rValue = here->BSIM3V1sourceSquares; + return(OK); + case BSIM3V1_NRD: + value->rValue = here->BSIM3V1drainSquares; + return(OK); + case BSIM3V1_OFF: + value->rValue = here->BSIM3V1off; + return(OK); + case BSIM3V1_NQSMOD: + value->iValue = here->BSIM3V1nqsMod; + return(OK); + case BSIM3V1_M: + value->rValue = here->BSIM3V1m; + return(OK); + case BSIM3V1_IC_VBS: + value->rValue = here->BSIM3V1icVBS; + return(OK); + case BSIM3V1_IC_VDS: + value->rValue = here->BSIM3V1icVDS; + return(OK); + case BSIM3V1_IC_VGS: + value->rValue = here->BSIM3V1icVGS; + return(OK); + case BSIM3V1_DNODE: + value->iValue = here->BSIM3V1dNode; + return(OK); + case BSIM3V1_GNODE: + value->iValue = here->BSIM3V1gNode; + return(OK); + case BSIM3V1_SNODE: + value->iValue = here->BSIM3V1sNode; + return(OK); + case BSIM3V1_BNODE: + value->iValue = here->BSIM3V1bNode; + return(OK); + case BSIM3V1_DNODEPRIME: + value->iValue = here->BSIM3V1dNodePrime; + return(OK); + case BSIM3V1_SNODEPRIME: + value->iValue = here->BSIM3V1sNodePrime; + return(OK); + case BSIM3V1_SOURCECONDUCT: + value->rValue = here->BSIM3V1sourceConductance; + return(OK); + case BSIM3V1_DRAINCONDUCT: + value->rValue = here->BSIM3V1drainConductance; + return(OK); + case BSIM3V1_VBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1vbd); + return(OK); + case BSIM3V1_VBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1vbs); + return(OK); + case BSIM3V1_VGS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1vgs); + return(OK); + case BSIM3V1_VDS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1vds); + return(OK); + case BSIM3V1_CD: + value->rValue = here->BSIM3V1cd; + return(OK); + case BSIM3V1_CBS: + value->rValue = here->BSIM3V1cbs; + return(OK); + case BSIM3V1_CBD: + value->rValue = here->BSIM3V1cbd; + return(OK); + case BSIM3V1_GM: + value->rValue = here->BSIM3V1gm; + return(OK); + case BSIM3V1_GDS: + value->rValue = here->BSIM3V1gds; + return(OK); + case BSIM3V1_GMBS: + value->rValue = here->BSIM3V1gmbs; + return(OK); + case BSIM3V1_GBD: + value->rValue = here->BSIM3V1gbd; + return(OK); + case BSIM3V1_GBS: + value->rValue = here->BSIM3V1gbs; + return(OK); + case BSIM3V1_QB: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1qb); + return(OK); + case BSIM3V1_CQB: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1cqb); + return(OK); + case BSIM3V1_QG: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1qg); + return(OK); + case BSIM3V1_CQG: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1cqg); + return(OK); + case BSIM3V1_QD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1qd); + return(OK); + case BSIM3V1_CQD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1cqd); + return(OK); + case BSIM3V1_CGG: + value->rValue = here->BSIM3V1cggb; + return(OK); + case BSIM3V1_CGD: + value->rValue = here->BSIM3V1cgdb; + return(OK); + case BSIM3V1_CGS: + value->rValue = here->BSIM3V1cgsb; + return(OK); + case BSIM3V1_CDG: + value->rValue = here->BSIM3V1cdgb; + return(OK); + case BSIM3V1_CDD: + value->rValue = here->BSIM3V1cddb; + return(OK); + case BSIM3V1_CDS: + value->rValue = here->BSIM3V1cdsb; + return(OK); + case BSIM3V1_CBG: + value->rValue = here->BSIM3V1cbgb; + return(OK); + case BSIM3V1_CBDB: + value->rValue = here->BSIM3V1cbdb; + return(OK); + case BSIM3V1_CBSB: + value->rValue = here->BSIM3V1cbsb; + return(OK); + case BSIM3V1_CAPBD: + value->rValue = here->BSIM3V1capbd; + return(OK); + case BSIM3V1_CAPBS: + value->rValue = here->BSIM3V1capbs; + return(OK); + case BSIM3V1_VON: + value->rValue = here->BSIM3V1von; + return(OK); + case BSIM3V1_VDSAT: + value->rValue = here->BSIM3V1vdsat; + return(OK); + case BSIM3V1_QBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1qbs); + return(OK); + case BSIM3V1_QBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V1qbd); + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bsim3v1/b3v1check.c b/src/spicelib/devices/bsim3v1/b3v1check.c new file mode 100644 index 000000000..ac708ccc6 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1check.c @@ -0,0 +1,376 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:52:18 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: Min-Chie Jeng. +File: b3v1check.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +BSIM3V1checkModel(model, here, ckt) +register BSIM3V1model *model; +register BSIM3V1instance *here; +CKTcircuit *ckt; +{ +struct bsim3v1SizeDependParam *pParam; +int Fatal_Flag = 0; +FILE *fplog; + + if ((fplog = fopen("BSIM3V3_1_check.log", "w")) != NULL) + { pParam = here->pParam; + fprintf(fplog, "BSIM3V3.1 Parameter Check\n"); + fprintf(fplog, "Model = %s\n", model->BSIM3V1modName); + fprintf(fplog, "W = %g, L = %g\n", here->BSIM3V1w, here->BSIM3V1l); + + + if (pParam->BSIM3V1nlx < -pParam->BSIM3V1leff) + { fprintf(fplog, "Fatal: Nlx = %g is less than -Leff.\n", + pParam->BSIM3V1nlx); + printf("Fatal: Nlx = %g is less than -Leff.\n", + pParam->BSIM3V1nlx); + Fatal_Flag = 1; + } + + if (model->BSIM3V1tox <= 0.0) + { fprintf(fplog, "Fatal: Tox = %g is not positive.\n", + model->BSIM3V1tox); + printf("Fatal: Tox = %g is not positive.\n", model->BSIM3V1tox); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V1npeak <= 0.0) + { fprintf(fplog, "Fatal: Nch = %g is not positive.\n", + pParam->BSIM3V1npeak); + printf("Fatal: Nch = %g is not positive.\n", + pParam->BSIM3V1npeak); + Fatal_Flag = 1; + } + if (pParam->BSIM3V1nsub <= 0.0) + { fprintf(fplog, "Fatal: Nsub = %g is not positive.\n", + pParam->BSIM3V1nsub); + printf("Fatal: Nsub = %g is not positive.\n", + pParam->BSIM3V1nsub); + Fatal_Flag = 1; + } + if (pParam->BSIM3V1ngate < 0.0) + { fprintf(fplog, "Fatal: Ngate = %g is not positive.\n", + pParam->BSIM3V1ngate); + printf("Fatal: Ngate = %g Ngate is not positive.\n", + pParam->BSIM3V1ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM3V1ngate > 1.e25) + { fprintf(fplog, "Fatal: Ngate = %g is too high.\n", + pParam->BSIM3V1ngate); + printf("Fatal: Ngate = %g Ngate is too high\n", + pParam->BSIM3V1ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM3V1xj <= 0.0) + { fprintf(fplog, "Fatal: Xj = %g is not positive.\n", + pParam->BSIM3V1xj); + printf("Fatal: Xj = %g is not positive.\n", pParam->BSIM3V1xj); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V1dvt1 < 0.0) + { fprintf(fplog, "Fatal: Dvt1 = %g is negative.\n", + pParam->BSIM3V1dvt1); + printf("Fatal: Dvt1 = %g is negative.\n", pParam->BSIM3V1dvt1); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V1dvt1w < 0.0) + { fprintf(fplog, "Fatal: Dvt1w = %g is negative.\n", + pParam->BSIM3V1dvt1w); + printf("Fatal: Dvt1w = %g is negative.\n", pParam->BSIM3V1dvt1w); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V1w0 == -pParam->BSIM3V1weff) + { fprintf(fplog, "Fatal: (W0 + Weff) = 0 cauing divided-by-zero.\n"); + printf("Fatal: (W0 + Weff) = 0 cauing divided-by-zero.\n"); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V1dsub < 0.0) + { fprintf(fplog, "Fatal: Dsub = %g is negative.\n", pParam->BSIM3V1dsub); + printf("Fatal: Dsub = %g is negative.\n", pParam->BSIM3V1dsub); + Fatal_Flag = 1; + } + if (pParam->BSIM3V1b1 == -pParam->BSIM3V1weff) + { fprintf(fplog, "Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + printf("Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + Fatal_Flag = 1; + } + if (pParam->BSIM3V1u0temp <= 0.0) + { fprintf(fplog, "Fatal: u0 at current temperature = %g is not positive.\n", pParam->BSIM3V1u0temp); + printf("Fatal: u0 at current temperature = %g is not positive.\n", + pParam->BSIM3V1u0temp); + Fatal_Flag = 1; + } + +/* Check delta parameter */ + if (pParam->BSIM3V1delta < 0.0) + { fprintf(fplog, "Fatal: Delta = %g is less than zero.\n", + pParam->BSIM3V1delta); + printf("Fatal: Delta = %g is less than zero.\n", pParam->BSIM3V1delta); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V1vsattemp <= 0.0) + { fprintf(fplog, "Fatal: Vsat at current temperature = %g is not positive.\n", pParam->BSIM3V1vsattemp); + printf("Fatal: Vsat at current temperature = %g is not positive.\n", + pParam->BSIM3V1vsattemp); + Fatal_Flag = 1; + } +/* Check Rout parameters */ + if (pParam->BSIM3V1pclm <= 0.0) + { fprintf(fplog, "Fatal: Pclm = %g is not positive.\n", pParam->BSIM3V1pclm); + printf("Fatal: Pclm = %g is not positive.\n", pParam->BSIM3V1pclm); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V1drout < 0.0) + { fprintf(fplog, "Fatal: Drout = %g is negative.\n", pParam->BSIM3V1drout); + printf("Fatal: Drout = %g is negative.\n", pParam->BSIM3V1drout); + Fatal_Flag = 1; + } + if (model->BSIM3V1unitLengthSidewallJctCap > 0.0 || + model->BSIM3V1unitLengthGateSidewallJctCap > 0.0) + { + if (here->BSIM3V1drainPerimeter < pParam->BSIM3V1weff) + { fprintf(fplog, "Warning: Pd = %g is less than W.\n", + here->BSIM3V1drainPerimeter); + printf("Warning: Pd = %g is less than W.\n", + here->BSIM3V1drainPerimeter); + here->BSIM3V1drainPerimeter =pParam->BSIM3V1weff; + } + if (here->BSIM3V1sourcePerimeter < pParam->BSIM3V1weff) + { fprintf(fplog, "Warning: Ps = %g is less than W.\n", + here->BSIM3V1sourcePerimeter); + printf("Warning: Ps = %g is less than W.\n", + here->BSIM3V1sourcePerimeter); + here->BSIM3V1sourcePerimeter =pParam->BSIM3V1weff; + } + } +/* Check capacitance parameters */ + if (pParam->BSIM3V1clc < 0.0) + { fprintf(fplog, "Fatal: Clc = %g is negative.\n", pParam->BSIM3V1clc); + printf("Fatal: Clc = %g is negative.\n", pParam->BSIM3V1clc); + Fatal_Flag = 1; + } + if (model->BSIM3V1paramChk ==1) + { +/* Check L and W parameters */ + if (pParam->BSIM3V1leff <= 5.0e-8) + { fprintf(fplog, "Warning: Leff = %g may be too small.\n", + pParam->BSIM3V1leff); + printf("Warning: Leff = %g may be too small.\n", + pParam->BSIM3V1leff); + } + + if (pParam->BSIM3V1leffCV <= 5.0e-8) + { fprintf(fplog, "Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM3V1leffCV); + printf("Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM3V1leffCV); + } + + if (pParam->BSIM3V1weff <= 1.0e-7) + { fprintf(fplog, "Warning: Weff = %g may be too small.\n", + pParam->BSIM3V1weff); + printf("Warning: Weff = %g may be too small.\n", + pParam->BSIM3V1weff); + } + + if (pParam->BSIM3V1weffCV <= 1.0e-7) + { fprintf(fplog, "Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM3V1weffCV); + printf("Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM3V1weffCV); + } + +/* Check threshold voltage parameters */ + if (pParam->BSIM3V1nlx < 0.0) + { fprintf(fplog, "Warning: Nlx = %g is negative.\n", pParam->BSIM3V1nlx); + printf("Warning: Nlx = %g is negative.\n", pParam->BSIM3V1nlx); + } + if (model->BSIM3V1tox < 1.0e-9) + { fprintf(fplog, "Warning: Tox = %g is less than 10A.\n", + model->BSIM3V1tox); + printf("Warning: Tox = %g is less than 10A.\n", model->BSIM3V1tox); + } + + if (pParam->BSIM3V1npeak <= 1.0e15) + { fprintf(fplog, "Warning: Nch = %g may be too small.\n", + pParam->BSIM3V1npeak); + printf("Warning: Nch = %g may be too small.\n", + pParam->BSIM3V1npeak); + } + else if (pParam->BSIM3V1npeak >= 1.0e21) + { fprintf(fplog, "Warning: Nch = %g may be too large.\n", + pParam->BSIM3V1npeak); + printf("Warning: Nch = %g may be too large.\n", + pParam->BSIM3V1npeak); + } + + if (pParam->BSIM3V1nsub <= 1.0e14) + { fprintf(fplog, "Warning: Nsub = %g may be too small.\n", + pParam->BSIM3V1nsub); + printf("Warning: Nsub = %g may be too small.\n", + pParam->BSIM3V1nsub); + } + else if (pParam->BSIM3V1nsub >= 1.0e21) + { fprintf(fplog, "Warning: Nsub = %g may be too large.\n", + pParam->BSIM3V1nsub); + printf("Warning: Nsub = %g may be too large.\n", + pParam->BSIM3V1nsub); + } + + if ((pParam->BSIM3V1ngate > 0.0) && + (pParam->BSIM3V1ngate <= 1.e18)) + { fprintf(fplog, "Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM3V1ngate); + printf("Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM3V1ngate); + } + + if (pParam->BSIM3V1dvt0 < 0.0) + { fprintf(fplog, "Warning: Dvt0 = %g is negative.\n", + pParam->BSIM3V1dvt0); + printf("Warning: Dvt0 = %g is negative.\n", pParam->BSIM3V1dvt0); + } + + if (fabs(1.0e-6 / (pParam->BSIM3V1w0 + pParam->BSIM3V1weff)) > 10.0) + { fprintf(fplog, "Warning: (W0 + Weff) may be too small.\n"); + printf("Warning: (W0 + Weff) may be too small.\n"); + } + +/* Check subthreshold parameters */ + if (pParam->BSIM3V1nfactor < 0.0) + { fprintf(fplog, "Warning: Nfactor = %g is negative.\n", + pParam->BSIM3V1nfactor); + printf("Warning: Nfactor = %g is negative.\n", pParam->BSIM3V1nfactor); + } + if (pParam->BSIM3V1cdsc < 0.0) + { fprintf(fplog, "Warning: Cdsc = %g is negative.\n", + pParam->BSIM3V1cdsc); + printf("Warning: Cdsc = %g is negative.\n", pParam->BSIM3V1cdsc); + } + if (pParam->BSIM3V1cdscd < 0.0) + { fprintf(fplog, "Warning: Cdscd = %g is negative.\n", + pParam->BSIM3V1cdscd); + printf("Warning: Cdscd = %g is negative.\n", pParam->BSIM3V1cdscd); + } +/* Check DIBL parameters */ + if (pParam->BSIM3V1eta0 < 0.0) + { fprintf(fplog, "Warning: Eta0 = %g is negative.\n", + pParam->BSIM3V1eta0); + printf("Warning: Eta0 = %g is negative.\n", pParam->BSIM3V1eta0); + } + +/* Check Abulk parameters */ + if (fabs(1.0e-6 / (pParam->BSIM3V1b1 + pParam->BSIM3V1weff)) > 10.0) + { fprintf(fplog, "Warning: (B1 + Weff) may be too small.\n"); + printf("Warning: (B1 + Weff) may be too small.\n"); + } + + +/* Check Saturation parameters */ + if (pParam->BSIM3V1a2 < 0.01) + { fprintf(fplog, "Warning: A2 = %g is too small. Set to 0.01.\n", pParam->BSIM3V1a2); + printf("Warning: A2 = %g is too small. Set to 0.01.\n", + pParam->BSIM3V1a2); + pParam->BSIM3V1a2 = 0.01; + } + else if (pParam->BSIM3V1a2 > 1.0) + { fprintf(fplog, "Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM3V1a2); + printf("Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM3V1a2); + pParam->BSIM3V1a2 = 1.0; + pParam->BSIM3V1a1 = 0.0; + + } + + if (pParam->BSIM3V1rdsw < 0.0) + { fprintf(fplog, "Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM3V1rdsw); + printf("Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM3V1rdsw); + pParam->BSIM3V1rdsw = 0.0; + pParam->BSIM3V1rds0 = 0.0; + } + else if ((pParam->BSIM3V1rds0 > 0.0) && (pParam->BSIM3V1rds0 < 0.001)) + { fprintf(fplog, "Warning: Rds at current temperature = %g is less than 0.001 ohm. Set to zero.\n", + pParam->BSIM3V1rds0); + printf("Warning: Rds at current temperature = %g is less than 0.001 ohm. Set to zero.\n", + pParam->BSIM3V1rds0); + pParam->BSIM3V1rds0 = 0.0; + } + if (pParam->BSIM3V1vsattemp < 1.0e3) + { fprintf(fplog, "Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM3V1vsattemp); + printf("Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM3V1vsattemp); + } + + if (pParam->BSIM3V1pdibl1 < 0.0) + { fprintf(fplog, "Warning: Pdibl1 = %g is negative.\n", + pParam->BSIM3V1pdibl1); + printf("Warning: Pdibl1 = %g is negative.\n", pParam->BSIM3V1pdibl1); + } + if (pParam->BSIM3V1pdibl2 < 0.0) + { fprintf(fplog, "Warning: Pdibl2 = %g is negative.\n", + pParam->BSIM3V1pdibl2); + printf("Warning: Pdibl2 = %g is negative.\n", pParam->BSIM3V1pdibl2); + } +/* Check overlap capacitance parameters */ + if (model->BSIM3V1cgdo < 0.0) + { fprintf(fplog, "Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM3V1cgdo); + printf("Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM3V1cgdo); + model->BSIM3V1cgdo = 0.0; + } + if (model->BSIM3V1cgso < 0.0) + { fprintf(fplog, "Warning: cgso = %g is negative. Set to zero.\n", model->BSIM3V1cgso); + printf("Warning: cgso = %g is negative. Set to zero.\n", model->BSIM3V1cgso); + model->BSIM3V1cgso = 0.0; + } + if (model->BSIM3V1cgbo < 0.0) + { fprintf(fplog, "Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM3V1cgbo); + printf("Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM3V1cgbo); + model->BSIM3V1cgbo = 0.0; + } + + }/* loop for the parameter check for warning messages */ + fclose(fplog); + } + else + { fprintf(stderr, "Warning: Can't open log file. Parameter checking skipped.\n"); + } + + return(Fatal_Flag); +} + diff --git a/src/spicelib/devices/bsim3v1/b3v1cvtest.c b/src/spicelib/devices/bsim3v1/b3v1cvtest.c new file mode 100644 index 000000000..c603642f5 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1cvtest.c @@ -0,0 +1,127 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:53:26 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1cvtest.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "trandefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V1convTest(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3V1model *model = (BSIM3V1model*)inModel; +register BSIM3V1instance *here; +double delvbd, delvbs, delvds, delvgd, delvgs, vbd, vbs, vds; +double cbd, cbhat, cbs, cd, cdhat, tol, vgd, vgdo, vgs; + + /* loop through all the BSIM3V1 device models */ + for (; model != NULL; model = model->BSIM3V1nextModel) + { /* loop through all the instances of the model */ + for (here = model->BSIM3V1instances; here != NULL ; + here=here->BSIM3V1nextInstance) + { + if (here->BSIM3V1owner != ARCHme) continue; + vbs = model->BSIM3V1type + * (*(ckt->CKTrhsOld+here->BSIM3V1bNode) + - *(ckt->CKTrhsOld+here->BSIM3V1sNodePrime)); + vgs = model->BSIM3V1type + * (*(ckt->CKTrhsOld+here->BSIM3V1gNode) + - *(ckt->CKTrhsOld+here->BSIM3V1sNodePrime)); + vds = model->BSIM3V1type + * (*(ckt->CKTrhsOld+here->BSIM3V1dNodePrime) + - *(ckt->CKTrhsOld+here->BSIM3V1sNodePrime)); + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->BSIM3V1vgs) + - *(ckt->CKTstate0 + here->BSIM3V1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM3V1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM3V1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM3V1vgs); + delvds = vds - *(ckt->CKTstate0 + here->BSIM3V1vds); + delvgd = vgd-vgdo; + + cd = here->BSIM3V1cd; + if (here->BSIM3V1mode >= 0) + { cdhat = cd - here->BSIM3V1gbd * delvbd + + here->BSIM3V1gmbs * delvbs + here->BSIM3V1gm * delvgs + + here->BSIM3V1gds * delvds; + } + else + { cdhat = cd - (here->BSIM3V1gbd - here->BSIM3V1gmbs) * delvbd + - here->BSIM3V1gm * delvgd + here->BSIM3V1gds * delvds; + } + + /* + * check convergence + */ + if ((here->BSIM3V1off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(cd)) + + ckt->CKTabstol; + if (fabs(cdhat - cd) >= tol) { + +#ifdef STRANGE_PATCH +/* gtri - begin - wbk - report conv prob */ + if(ckt->enh->conv_debug.report_conv_probs) { + ENHreport_conv_prob(ENH_ANALOG_INSTANCE, + (char *) here->BSIM3V1name, + ""); + } +/* gtri - end - wbk - report conv prob */ +#endif /* STRANGE_PATCH */ + + + ckt->CKTnoncon++; + return(OK); + } + cbs = here->BSIM3V1cbs; + cbd = here->BSIM3V1cbd; + cbhat = cbs + cbd + here->BSIM3V1gbd * delvbd + + here->BSIM3V1gbs * delvbs; + tol = ckt->CKTreltol * MAX(fabs(cbhat), fabs(cbs + cbd)) + + ckt->CKTabstol; + if (fabs(cbhat - (cbs + cbd)) > tol) { +#ifdef STRANGE_PATCH +/* gtri - begin - wbk - report conv prob */ + if(ckt->enh->conv_debug.report_conv_probs) { + ENHreport_conv_prob(ENH_ANALOG_INSTANCE, + (char *) here->BSIM3V1name, + ""); + } +/* gtri - end - wbk - report conv prob */ +#endif /* STRANGE_PATCH */ + + ckt->CKTnoncon++; + return(OK); + } + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3v1/b3v1del.c b/src/spicelib/devices/bsim3v1/b3v1del.c new file mode 100644 index 000000000..4f2754016 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1del.c @@ -0,0 +1,56 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:53:53 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1del.c +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim3v1def.h" +#include "sperror.h" +#include "gendefs.h" +#include "suffix.h" + + +int +BSIM3V1delete(inModel,name,inInst) +GENmodel *inModel; +IFuid name; +GENinstance **inInst; +{ +BSIM3V1instance **fast = (BSIM3V1instance**)inInst; +BSIM3V1model *model = (BSIM3V1model*)inModel; +BSIM3V1instance **prev = NULL; +BSIM3V1instance *here; + + for (; model ; model = model->BSIM3V1nextModel) + { prev = &(model->BSIM3V1instances); + for (here = *prev; here ; here = *prev) + { if (here->BSIM3V1name == name || (fast && here==*fast)) + { *prev= here->BSIM3V1nextInstance; + FREE(here); + return(OK); + } + prev = &(here->BSIM3V1nextInstance); + } + } + return(E_NODEV); +} + + diff --git a/src/spicelib/devices/bsim3v1/b3v1dest.c b/src/spicelib/devices/bsim3v1/b3v1dest.c new file mode 100644 index 000000000..5fb0cb475 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1dest.c @@ -0,0 +1,52 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:54:27 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1dest.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3v1def.h" +#include "suffix.h" + +void +BSIM3V1destroy(inModel) +GENmodel **inModel; +{ +BSIM3V1model **model = (BSIM3V1model**)inModel; +BSIM3V1instance *here; +BSIM3V1instance *prev = NULL; +BSIM3V1model *mod = *model; +BSIM3V1model *oldmod = NULL; + + for (; mod ; mod = mod->BSIM3V1nextModel) + { if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (BSIM3V1instance *)NULL; + for (here = mod->BSIM3V1instances; here; here = here->BSIM3V1nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; + return; +} + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1getic.c b/src/spicelib/devices/bsim3v1/b3v1getic.c new file mode 100644 index 000000000..c71a7fc88 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1getic.c @@ -0,0 +1,59 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:54:55 yuhua + * BSIM3v3.1 + * release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1getic.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V1getic(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +BSIM3V1model *model = (BSIM3V1model*)inModel; +BSIM3V1instance *here; + + for (; model ; model = model->BSIM3V1nextModel) + { for (here = model->BSIM3V1instances; here; here = here->BSIM3V1nextInstance) + { + if (here->BSIM3V1owner != ARCHme) continue; + if(!here->BSIM3V1icVBSGiven) + { here->BSIM3V1icVBS = *(ckt->CKTrhs + here->BSIM3V1bNode) + - *(ckt->CKTrhs + here->BSIM3V1sNode); + } + if (!here->BSIM3V1icVDSGiven) + { here->BSIM3V1icVDS = *(ckt->CKTrhs + here->BSIM3V1dNode) + - *(ckt->CKTrhs + here->BSIM3V1sNode); + } + if (!here->BSIM3V1icVGSGiven) + { here->BSIM3V1icVGS = *(ckt->CKTrhs + here->BSIM3V1gNode) + - *(ckt->CKTrhs + here->BSIM3V1sNode); + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3v1/b3v1ld.c b/src/spicelib/devices/bsim3v1/b3v1ld.c new file mode 100644 index 000000000..6e7044c2f --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1ld.c @@ -0,0 +1,2485 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:55:29 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +File: b3v1ld.c 1/3/92 +Modified by Mansun Chan (1995) +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define Charge_q 1.60219e-19 +#define DELTA_1 0.02 +#define DELTA_2 0.02 +#define DELTA_3 0.02 +#define DELTA_4 0.02 + + +int +BSIM3V1load(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3V1model *model = (BSIM3V1model*)inModel; +register BSIM3V1instance *here; +double SourceSatCurrent, DrainSatCurrent; +double ag0, qgd, qgs, qgb, von, cbhat, VgstNVt, ExpVgst; +double cdrain, cdhat, cdreq, ceqbd, ceqbs, ceqqb, ceqqd, ceqqg, ceq, geq; +double czbd, czbdsw, czbdswg, czbs, czbssw, czbsswg, evbd, evbs, arg, sarg; +double delvbd, delvbs, delvds, delvgd, delvgs; +double Vfbeff, dVfbeff_dVg, dVfbeff_dVd, dVfbeff_dVb, V3, V4; +double gcbdb, gcbgb, gcbsb, gcddb, gcdgb, gcdsb, gcgdb, gcggb, gcgsb, gcsdb; +double gcsgb, gcssb, tol, PhiB, PhiBSW, MJ, MJSW, PhiBSWG, MJSWG; +double vbd, vbs, vds, vgb, vgd, vgs, vgdo, xfact; +double qgate=0.0, qbulk=0.0, qdrn=0.0, qsrc=0.0, cqgate=0.0, cqbulk=0.0, cqdrn=0.0; +double Vds, Vgs, Vbs, Gmbs, FwdSum, RevSum; +double Vgs_eff, Vfb, dVfb_dVb, dVfb_dVd, dVbs_dVb; +double Phis, dPhis_dVb, sqrtPhis, dsqrtPhis_dVb, Vth, dVth_dVb, dVth_dVd; +double Vgst, dVgst_dVg, dVgst_dVb, dVgs_eff_dVg, Nvtm; +double Vgdt, Vgsaddvth, Vgsaddvth2, Vgsaddvth1o3, n, dn_dVb, Vtm; +double ExpArg, ExpArg1, V0; +double Denomi, dDenomi_dVg, dDenomi_dVd, dDenomi_dVb; +double ueff, dueff_dVg, dueff_dVd, dueff_dVb; +double Esat, dEsat_dVg, dEsat_dVd, dEsat_dVb, Vdsat, Vdsat0; +double EsatL, dEsatL_dVg, dEsatL_dVd, dEsatL_dVb; +double Ilimit, Iexp, dIexp_dVg, dIexp_dVd, dIexp_dVb; +double dVdsat_dVg, dVdsat_dVb, dVdsat_dVd, Vasat, dAlphaz_dVg, dAlphaz_dVb; +double dVasat_dVg, dVasat_dVb, dVasat_dVd, Va, Va2, dVa_dVd, dVa_dVg, dVa_dVb; +double Vbseff, dVbseff_dVb, VbseffCV, dVbseffCV_dVb; +double Arg1, Arg2, One_Third_CoxWL, Two_Third_CoxWL, Alphaz, CoxWL; +double dqbulk_dVb, dVgdt_dVg, dVgdt_dVd, dVgdt_dVb; +double T0, dT0_dVg, dT0_dVd, dT0_dVb; +double T1, dT1_dVg, dT1_dVd, dT1_dVb; +double T2, dT2_dVg, dT2_dVd, dT2_dVb; +double T3, dT3_dVg, dT3_dVd, dT3_dVb; +double T4, dT4_dVg, dT4_dVd, dT4_dVb; +double T5, dT5_dVg, dT5_dVd, dT5_dVb; +double T6, dT6_dVg, dT6_dVd, dT6_dVb; +double T7, dT7_dVg, dT7_dVd, dT7_dVb; +double T8, dT8_dVg, dT8_dVd, dT8_dVb; +double T9, dT9_dVg, dT9_dVd, dT9_dVb; +double T10, dT10_dVg, dT10_dVb, dT10_dVd; +double T11, T12; +double tmp, Abulk, dAbulk_dVb, Abulk0, dAbulk0_dVb; +double T100, T101; +double VACLM, dVACLM_dVg, dVACLM_dVd, dVACLM_dVb; +double VADIBL, dVADIBL_dVg, dVADIBL_dVd, dVADIBL_dVb; +double VAHCE, dVAHCE_dVg, dVAHCE_dVd, dVAHCE_dVb; +double Xdep, dXdep_dVb, lt1, dlt1_dVb, ltw, dltw_dVb, Delt_vth, dDelt_vth_dVb; +double Theta0, dTheta0_dVb, Theta1, dTheta1_dVb; +double Thetarout, dThetarout_dVb, TempRatio, tmp1, tmp2, tmp3, tmp4; +double DIBL_Sft, dDIBL_Sft_dVd, DIBL_fact, Lambda, dLambda_dVg; +double Rout_Vgs_factor, dRout_Vgs_factor_dVg, dRout_Vgs_factor_dVb; +double dRout_Vgs_factor_dVd; +double tempv, a1; + +double Vgsteff, dVgsteff_dVg, dVgsteff_dVd, dVgsteff_dVb; +double Vdseff, dVdseff_dVg, dVdseff_dVd, dVdseff_dVb; +double VdseffCV, dVdseffCV_dVg, dVdseffCV_dVd, dVdseffCV_dVb; +double diffVds, diffVdsCV; +double dAbulk_dVg, dn_dVd ; +double beta, dbeta_dVg, dbeta_dVd, dbeta_dVb; +double gche, dgche_dVg, dgche_dVd, dgche_dVb; +double fgche1, dfgche1_dVg, dfgche1_dVd, dfgche1_dVb; +double fgche2, dfgche2_dVg, dfgche2_dVd, dfgche2_dVb; +double Idl, dIdl_dVg, dIdl_dVd, dIdl_dVb; +double Idsa, dIdsa_dVg, dIdsa_dVd, dIdsa_dVb; +double Ids, Gm, Gds, Gmb; +double Isub, Isubd, Isubs, Gbd, Gbg, Gbb; +double VASCBE, dVASCBE_dVg, dVASCBE_dVd, dVASCBE_dVb; +double CoxWovL; +double Rds, dRds_dVg, dRds_dVb, WVCox, WVCoxRds; +double Vgst2Vtm, VdsatCV, dVdsatCV_dVd, dVdsatCV_dVg, dVdsatCV_dVb; +double Leff, Weff, dWeff_dVg, dWeff_dVb; +double AbulkCV, dAbulkCV_dVb; +double qgdo, qgso, cgdo, cgso; + +double qcheq, qdef, gqdef, cqdef, cqcheq, gtau_diff, gtau_drift, csreq; +double gcqdb,gcqsb,gcqgb,gcqbb,vss; +double dxpart, sxpart; + +double gbspsp, gbbdp, gbbsp, gbspg, gbspb, gbspdp; +double gbdpdp, gbdpg, gbdpb, gbdpsp; +double Cgg, Cgd, Cgs, Cgb, Cdg, Cdd, Cds, Cdb, Qg, Qd; +double Csg, Csd, Css, Csb, Cbg, Cbd, Cbs, Cbb, Qs, Qb; +double Cgg1, Cgb1, Cgd1, Cbg1, Cbb1, Cbd1, Csg1, Csd1, Csb1, Qac0, Qsub0; +double dQac0_dVg, dQac0_dVd, dQac0_dVb, dQsub0_dVg, dQsub0_dVd, dQsub0_dVb; + +struct bsim3v1SizeDependParam *pParam; +int ByPass, Check, ChargeComputationNeeded, J, error, I; +double junk[50]; + +for (; model != NULL; model = model->BSIM3V1nextModel) +{ for (here = model->BSIM3V1instances; here != NULL; + here = here->BSIM3V1nextInstance) + { + if (here->BSIM3V1owner != ARCHme) continue; + Check = 1; + ByPass = 0; + pParam = here->pParam; + if ((ckt->CKTmode & MODEINITSMSIG)) + { vbs = *(ckt->CKTstate0 + here->BSIM3V1vbs); + vgs = *(ckt->CKTstate0 + here->BSIM3V1vgs); + vds = *(ckt->CKTstate0 + here->BSIM3V1vds); + qdef = *(ckt->CKTstate0 + here->BSIM3V1qcdump); + } + else if ((ckt->CKTmode & MODEINITTRAN)) + { vbs = *(ckt->CKTstate1 + here->BSIM3V1vbs); + vgs = *(ckt->CKTstate1 + here->BSIM3V1vgs); + vds = *(ckt->CKTstate1 + here->BSIM3V1vds); + qdef = *(ckt->CKTstate1 + here->BSIM3V1qcdump); + } + else if ((ckt->CKTmode & MODEINITJCT) && !here->BSIM3V1off) + { vds = model->BSIM3V1type * here->BSIM3V1icVDS; + vgs = model->BSIM3V1type * here->BSIM3V1icVGS; + vbs = model->BSIM3V1type * here->BSIM3V1icVBS; + qdef = 0.0; + + if ((vds == 0.0) && (vgs == 0.0) && (vbs == 0.0) && + ((ckt->CKTmode & (MODETRAN | MODEAC|MODEDCOP | + MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) + { + vgs = pParam->BSIM3V1vth0 + 0.1; + if (here->BSIM3V1gNode == here->BSIM3V1dNode) + vds = vgs; + else + vds = 0.1; + if ((here->BSIM3V1bNode != here->BSIM3V1sNode) + && (here->BSIM3V1bNode != here->BSIM3V1dNode)) + vbs = -0.1; + else + vbs = 0.0; + } + } + else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && + (here->BSIM3V1off)) + { qdef = vbs = vgs = vds = 0.0; + } + else + { +#ifndef PREDICTOR + if ((ckt->CKTmode & MODEINITPRED)) + { xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->BSIM3V1vbs) = + *(ckt->CKTstate1 + here->BSIM3V1vbs); + vbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V1vbs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3V1vbs))); + *(ckt->CKTstate0 + here->BSIM3V1vgs) = + *(ckt->CKTstate1 + here->BSIM3V1vgs); + vgs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V1vgs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3V1vgs))); + *(ckt->CKTstate0 + here->BSIM3V1vds) = + *(ckt->CKTstate1 + here->BSIM3V1vds); + vds = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V1vds)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3V1vds))); + *(ckt->CKTstate0 + here->BSIM3V1vbd) = + *(ckt->CKTstate0 + here->BSIM3V1vbs) + - *(ckt->CKTstate0 + here->BSIM3V1vds); + qdef = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V1qcdump)) + -(xfact * (*(ckt->CKTstate2 + here->BSIM3V1qcdump))); + } + else + { +#endif /* PREDICTOR */ + vbs = model->BSIM3V1type + * (*(ckt->CKTrhsOld + here->BSIM3V1bNode) + - *(ckt->CKTrhsOld + here->BSIM3V1sNodePrime)); + vgs = model->BSIM3V1type + * (*(ckt->CKTrhsOld + here->BSIM3V1gNode) + - *(ckt->CKTrhsOld + here->BSIM3V1sNodePrime)); + vds = model->BSIM3V1type + * (*(ckt->CKTrhsOld + here->BSIM3V1dNodePrime) + - *(ckt->CKTrhsOld + here->BSIM3V1sNodePrime)); + qdef = *(ckt->CKTrhsOld + here->BSIM3V1qNode); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->BSIM3V1vgs) + - *(ckt->CKTstate0 + here->BSIM3V1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM3V1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM3V1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM3V1vgs); + delvds = vds - *(ckt->CKTstate0 + here->BSIM3V1vds); + delvgd = vgd - vgdo; + + if (here->BSIM3V1mode >= 0) + { cdhat = here->BSIM3V1cd - here->BSIM3V1gbd * delvbd + + here->BSIM3V1gmbs * delvbs + here->BSIM3V1gm * delvgs + + here->BSIM3V1gds * delvds; + } + else + { cdhat = here->BSIM3V1cd - (here->BSIM3V1gbd - here->BSIM3V1gmbs) + * delvbd - here->BSIM3V1gm * delvgd + + here->BSIM3V1gds * delvds; + + } + cbhat = here->BSIM3V1cbs + here->BSIM3V1cbd + here->BSIM3V1gbd + * delvbd + here->BSIM3V1gbs * delvbs; + +#ifndef NOBYPASS + /* following should be one big if connected by && all over + * the place, but some C compilers can't handle that, so + * we split it up here to let them digest it in stages + */ + + if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) + if ((fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->BSIM3V1vbs))) + ckt->CKTvoltTol))) + if ((fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->BSIM3V1vbd))) + ckt->CKTvoltTol))) + if ((fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->BSIM3V1vgs))) + ckt->CKTvoltTol))) + if ((fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->BSIM3V1vds))) + ckt->CKTvoltTol))) + if ((fabs(cdhat - here->BSIM3V1cd) < ckt->CKTreltol + * MAX(fabs(cdhat),fabs(here->BSIM3V1cd)) + ckt->CKTabstol)) + { tempv = MAX(fabs(cbhat),fabs(here->BSIM3V1cbs + + here->BSIM3V1cbd)) + ckt->CKTabstol; + if ((fabs(cbhat - (here->BSIM3V1cbs + here->BSIM3V1cbd)) + < ckt->CKTreltol * tempv)) + { /* bypass code */ + vbs = *(ckt->CKTstate0 + here->BSIM3V1vbs); + vbd = *(ckt->CKTstate0 + here->BSIM3V1vbd); + vgs = *(ckt->CKTstate0 + here->BSIM3V1vgs); + vds = *(ckt->CKTstate0 + here->BSIM3V1vds); + qcheq = *(ckt->CKTstate0 + here->BSIM3V1qcheq); + + vgd = vgs - vds; + vgb = vgs - vbs; + + cdrain = here->BSIM3V1mode * (here->BSIM3V1cd + + here->BSIM3V1cbd); + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC))) + { ByPass = 1; + goto line755; + } + else + { goto line850; + } + } + } + +#endif /*NOBYPASS*/ + von = here->BSIM3V1von; + if (*(ckt->CKTstate0 + here->BSIM3V1vds) >= 0.0) + { vgs = DEVfetlim(vgs, *(ckt->CKTstate0+here->BSIM3V1vgs), von); + vds = vgs - vgd; + vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->BSIM3V1vds)); + vgd = vgs - vds; + + } + else + { vgd = DEVfetlim(vgd, vgdo, von); + vds = vgs - vgd; + vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0+here->BSIM3V1vds))); + vgs = vgd + vds; + } + + if (vds >= 0.0) + { vbs = DEVpnjlim(vbs, *(ckt->CKTstate0 + here->BSIM3V1vbs), + CONSTvt0, model->BSIM3V1vcrit, &Check); + vbd = vbs - vds; + + } + else + { vbd = DEVpnjlim(vbd, *(ckt->CKTstate0 + here->BSIM3V1vbd), + CONSTvt0, model->BSIM3V1vcrit, &Check); + vbs = vbd + vds; + } + } + + /* determine DC current and derivatives */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; +/* the following code has been changed for the calculation of S/B and D/B diodes*/ + + if ((here->BSIM3V1sourceArea <= 0.0) && + (here->BSIM3V1sourcePerimeter <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } + else + { SourceSatCurrent = here->BSIM3V1sourceArea + * model->BSIM3V1jctTempSatCurDensity + + here->BSIM3V1sourcePerimeter + * model->BSIM3V1jctSidewallTempSatCurDensity; + } + + Nvtm = model->BSIM3V1vtm * model->BSIM3V1jctEmissionCoeff; + if (SourceSatCurrent <= 0.0) + { here->BSIM3V1gbs = ckt->CKTgmin; + here->BSIM3V1cbs = here->BSIM3V1gbs * vbs; + } + else if (vbs < 0.5) + { evbs = exp(vbs / Nvtm); + here->BSIM3V1gbs = SourceSatCurrent * evbs / Nvtm + ckt->CKTgmin; + here->BSIM3V1cbs = SourceSatCurrent * (evbs - 1.0) + + ckt->CKTgmin * vbs; + } + else + { evbs = exp(0.5 / Nvtm); + T0 = SourceSatCurrent * evbs / Nvtm; + here->BSIM3V1gbs = T0 + ckt->CKTgmin; + here->BSIM3V1cbs = SourceSatCurrent * (evbs - 1.0) + + T0 * (vbs - 0.5) + ckt->CKTgmin * vbs; + } + + if ((here->BSIM3V1drainArea <= 0.0) && + (here->BSIM3V1drainPerimeter <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } + else + { DrainSatCurrent = here->BSIM3V1drainArea + * model->BSIM3V1jctTempSatCurDensity + + here->BSIM3V1drainPerimeter + * model->BSIM3V1jctSidewallTempSatCurDensity; + } + + if (DrainSatCurrent <= 0.0) + { here->BSIM3V1gbd = ckt->CKTgmin; + here->BSIM3V1cbd = here->BSIM3V1gbd * vbd; + } + else if (vbd < 0.5) + { evbd = exp(vbd / Nvtm); + here->BSIM3V1gbd = DrainSatCurrent * evbd / Nvtm + ckt->CKTgmin; + here->BSIM3V1cbd = DrainSatCurrent * (evbd - 1.0) + + ckt->CKTgmin * vbd; + } + else + { evbd = exp(0.5 / Nvtm); + T0 = DrainSatCurrent * evbd / Nvtm; + here->BSIM3V1gbd = T0 + ckt->CKTgmin; + here->BSIM3V1cbd = DrainSatCurrent * (evbd - 1.0) + + T0 * (vbd - 0.5) + ckt->CKTgmin * vbd; + } +/* S/B and D/B diodes code change ends */ + + if (vds >= 0.0) + { /* normal mode */ + here->BSIM3V1mode = 1; + Vds = vds; + Vgs = vgs; + Vbs = vbs; + } + else + { /* inverse mode */ + here->BSIM3V1mode = -1; + Vds = -vds; + Vgs = vgd; + Vbs = vbd; + } + + ChargeComputationNeeded = + ((ckt->CKTmode & (MODEAC | MODETRAN | MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) + ? 1 : 0; + T0 = Vbs - pParam->BSIM3V1vbsc - 0.001; + T1 = sqrt(T0 * T0 - 0.004 * pParam->BSIM3V1vbsc); + Vbseff = pParam->BSIM3V1vbsc + 0.5 * (T0 + T1); + dVbseff_dVb = 0.5 * (1.0 + T0 / T1); + if (Vbseff < Vbs) + { Vbseff = Vbs; + } /* Added to avoid the possible numerical problems due to computer accuracy. See comments for diffVds */ + + if (Vbseff > 0.0) + { T0 = pParam->BSIM3V1phi / (pParam->BSIM3V1phi + Vbseff); + Phis = pParam->BSIM3V1phi * T0; + dPhis_dVb = -T0 * T0; + sqrtPhis = pParam->BSIM3V1phis3 / (pParam->BSIM3V1phi + 0.5 * Vbseff); + dsqrtPhis_dVb = -0.5 * sqrtPhis * sqrtPhis / pParam->BSIM3V1phis3; + } + else + { Phis = pParam->BSIM3V1phi - Vbseff; + dPhis_dVb = -1.0; + sqrtPhis = sqrt(Phis); + dsqrtPhis_dVb = -0.5 / sqrtPhis; + } + Xdep = pParam->BSIM3V1Xdep0 * sqrtPhis / pParam->BSIM3V1sqrtPhi; + dXdep_dVb = (pParam->BSIM3V1Xdep0 / pParam->BSIM3V1sqrtPhi) + * dsqrtPhis_dVb; + + Leff = pParam->BSIM3V1leff; + Vtm = model->BSIM3V1vtm; +/* Vth Calculation */ + T3 = sqrt(Xdep); + V0 = pParam->BSIM3V1vbi - pParam->BSIM3V1phi; + + T0 = pParam->BSIM3V1dvt2 * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM3V1dvt2; + } + else /* Added to avoid any discontinuity problems caused by dvt2 */ + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM3V1dvt2 * T4 * T4; + } + lt1 = model->BSIM3V1factor1 * T3 * T1; + dlt1_dVb = model->BSIM3V1factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = pParam->BSIM3V1dvt2w * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM3V1dvt2w; + } + else /* Added to avoid any discontinuity problems caused by dvt2w */ + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM3V1dvt2w * T4 * T4; + } + ltw = model->BSIM3V1factor1 * T3 * T1; + dltw_dVb = model->BSIM3V1factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = -0.5 * pParam->BSIM3V1dvt1 * Leff / lt1; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + Theta0 = T1 * (1.0 + 2.0 * T1); + dT1_dVb = -T0 / lt1 * T1 * dlt1_dVb; + dTheta0_dVb = (1.0 + 4.0 * T1) * dT1_dVb; + } + else + { T1 = MIN_EXP; + Theta0 = T1 * (1.0 + 2.0 * T1); + dTheta0_dVb = 0.0; + } + + here->BSIM3V1thetavth = pParam->BSIM3V1dvt0 * Theta0; + Delt_vth = here->BSIM3V1thetavth * V0; + dDelt_vth_dVb = pParam->BSIM3V1dvt0 * dTheta0_dVb * V0; + + T0 = -0.5 * pParam->BSIM3V1dvt1w * pParam->BSIM3V1weff * Leff / ltw; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 * (1.0 + 2.0 * T1); + dT1_dVb = -T0 / ltw * T1 * dltw_dVb; + dT2_dVb = (1.0 + 4.0 * T1) * dT1_dVb; + } + else + { T1 = MIN_EXP; + T2 = T1 * (1.0 + 2.0 * T1); + dT2_dVb = 0.0; + } + + T0 = pParam->BSIM3V1dvt0w * T2; + T2 = T0 * V0; + dT2_dVb = pParam->BSIM3V1dvt0w * dT2_dVb * V0; + + TempRatio = ckt->CKTtemp / model->BSIM3V1tnom - 1.0; + T0 = sqrt(1.0 + pParam->BSIM3V1nlx / Leff); + T1 = pParam->BSIM3V1k1 * (T0 - 1.0) * pParam->BSIM3V1sqrtPhi + + (pParam->BSIM3V1kt1 + pParam->BSIM3V1kt1l / Leff + + pParam->BSIM3V1kt2 * Vbseff) * TempRatio; + tmp2 = model->BSIM3V1tox * pParam->BSIM3V1phi + / (pParam->BSIM3V1weff + pParam->BSIM3V1w0); + + T3 = pParam->BSIM3V1eta0 + pParam->BSIM3V1etab * Vbseff; + if (T3 < 1.0e-4) /* avoid discontinuity problems caused by etab */ + { T9 = 1.0 / (3.0 - 2.0e4 * T3); + T3 = (2.0e-4 - T3) * T9; + T4 = T9 * T9; + } + else + { T4 = 1.0; + } + dDIBL_Sft_dVd = T3 * pParam->BSIM3V1theta0vb0; + DIBL_Sft = dDIBL_Sft_dVd * Vds; + + Vth = model->BSIM3V1type * pParam->BSIM3V1vth0 + pParam->BSIM3V1k1 + * (sqrtPhis - pParam->BSIM3V1sqrtPhi) - pParam->BSIM3V1k2 + * Vbseff - Delt_vth - T2 + (pParam->BSIM3V1k3 + pParam->BSIM3V1k3b + * Vbseff) * tmp2 + T1 - DIBL_Sft; + + here->BSIM3V1von = Vth; + + dVth_dVb = pParam->BSIM3V1k1 * dsqrtPhis_dVb - pParam->BSIM3V1k2 + - dDelt_vth_dVb - dT2_dVb + pParam->BSIM3V1k3b * tmp2 + - pParam->BSIM3V1etab * Vds * pParam->BSIM3V1theta0vb0 * T4 + + pParam->BSIM3V1kt2 * TempRatio; + dVth_dVd = -dDIBL_Sft_dVd; + +/* Calculate n */ + tmp2 = pParam->BSIM3V1nfactor * EPSSI / Xdep; + tmp3 = pParam->BSIM3V1cdsc + pParam->BSIM3V1cdscb * Vbseff + + pParam->BSIM3V1cdscd * Vds; + tmp4 = (tmp2 + tmp3 * Theta0 + pParam->BSIM3V1cit) / model->BSIM3V1cox; + if (tmp4 >= -0.5) + { n = 1.0 + tmp4; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM3V1cdscb * Theta0) / model->BSIM3V1cox; + dn_dVd = pParam->BSIM3V1cdscd * Theta0 / model->BSIM3V1cox; + } + else + /* avoid discontinuity problems caused by tmp4 */ + { T0 = 1.0 / (3.0 + 8.0 * tmp4); + n = (1.0 + 3.0 * tmp4) * T0; + T0 *= T0; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM3V1cdscb * Theta0) / model->BSIM3V1cox * T0; + dn_dVd = pParam->BSIM3V1cdscd * Theta0 / model->BSIM3V1cox * T0; + } + +/* Poly Gate Si Depletion Effect */ + T0 = pParam->BSIM3V1vfb + pParam->BSIM3V1phi; + if ((pParam->BSIM3V1ngate > 1.e18) && (pParam->BSIM3V1ngate < 1.e25) + && (Vgs > T0)) + /* added to avoid the problem caused by ngate */ + { T1 = 1.0e6 * Charge_q * EPSSI * pParam->BSIM3V1ngate + / (model->BSIM3V1cox * model->BSIM3V1cox); + T4 = sqrt(1.0 + 2.0 * (Vgs - T0) / T1); + T2 = T1 * (T4 - 1.0); + T3 = 0.5 * T2 * T2 / T1; /* T3 = Vpoly */ + T7 = 1.12 - T3 - 0.05; + T6 = sqrt(T7 * T7 + 0.224); + T5 = 1.12 - 0.5 * (T7 + T6); + Vgs_eff = Vgs - T5; + dVgs_eff_dVg = 1.0 - (0.5 - 0.5 / T4) * (1.0 + T7 / T6); + } + else + { Vgs_eff = Vgs; + dVgs_eff_dVg = 1.0; + } + Vgst = Vgs_eff - Vth; + +/* Effective Vgst (Vgsteff) Calculation */ + + T10 = 2.0 * n * Vtm; + VgstNVt = Vgst / T10; + ExpArg = (2.0 * pParam->BSIM3V1voff - Vgst) / T10; + + /* MCJ: Very small Vgst */ + if (VgstNVt > EXP_THRESHOLD) + { Vgsteff = Vgst; + dVgsteff_dVg = dVgs_eff_dVg; + dVgsteff_dVd = -dVth_dVd; + dVgsteff_dVb = -dVth_dVb; + } + else if (ExpArg > EXP_THRESHOLD) + { T0 = (Vgst - pParam->BSIM3V1voff) / (n * Vtm); + ExpVgst = exp(T0); + Vgsteff = Vtm * pParam->BSIM3V1cdep0 / model->BSIM3V1cox * ExpVgst; + dVgsteff_dVg = Vgsteff / (n * Vtm); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + T0 * Vtm * dn_dVd); + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + T0 * Vtm * dn_dVb); + dVgsteff_dVg *= dVgs_eff_dVg; + } + else + { ExpVgst = exp(VgstNVt); + T1 = T10 * log(1.0 + ExpVgst); + dT1_dVg = ExpVgst / (1.0 + ExpVgst); + dT1_dVb = -dT1_dVg * (dVth_dVb + Vgst / n * dn_dVb) + + T1 / n * dn_dVb; + dT1_dVd = -dT1_dVg * (dVth_dVd + Vgst / n * dn_dVd) + + T1 / n * dn_dVd; + + dT2_dVg = -model->BSIM3V1cox / (Vtm * pParam->BSIM3V1cdep0) + * exp(ExpArg); + T2 = 1.0 - T10 * dT2_dVg; + dT2_dVd = -dT2_dVg * (dVth_dVd - 2.0 * Vtm * ExpArg * dn_dVd) + + (T2 - 1.0) / n * dn_dVd; + dT2_dVb = -dT2_dVg * (dVth_dVb - 2.0 * Vtm * ExpArg * dn_dVb) + + (T2 - 1.0) / n * dn_dVb; + + Vgsteff = T1 / T2; + T3 = T2 * T2; + dVgsteff_dVg = (T2 * dT1_dVg - T1 * dT2_dVg) / T3 * dVgs_eff_dVg; + dVgsteff_dVd = (T2 * dT1_dVd - T1 * dT2_dVd) / T3; + dVgsteff_dVb = (T2 * dT1_dVb - T1 * dT2_dVb) / T3; + } + +/* Calculate Effective Channel Geometry */ + T9 = sqrtPhis - pParam->BSIM3V1sqrtPhi; + Weff = pParam->BSIM3V1weff - 2.0 * (pParam->BSIM3V1dwg * Vgsteff + + pParam->BSIM3V1dwb * T9); + dWeff_dVg = -2.0 * pParam->BSIM3V1dwg; + dWeff_dVb = -2.0 * pParam->BSIM3V1dwb * dsqrtPhis_dVb; + + if (Weff < 2.0e-8) /* to avoid the discontinuity problem due to Weff*/ + { T0 = 1.0 / (6.0e-8 - 2.0 * Weff); + Weff = 2.0e-8 * (4.0e-8 - Weff) * T0; + T0 *= T0 * 4.0e-16; + dWeff_dVg *= T0; + dWeff_dVb *= T0; + } + + T0 = pParam->BSIM3V1prwg * Vgsteff + pParam->BSIM3V1prwb * T9; + if (T0 >= -0.9) + { Rds = pParam->BSIM3V1rds0 * (1.0 + T0); + dRds_dVg = pParam->BSIM3V1rds0 * pParam->BSIM3V1prwg; + dRds_dVb = pParam->BSIM3V1rds0 * pParam->BSIM3V1prwb * dsqrtPhis_dVb; + } + else + /* to avoid the discontinuity problem due to prwg and prwb*/ + { T1 = 1.0 / (17.0 + 20.0 * T0); + Rds = pParam->BSIM3V1rds0 * (0.8 + T0) * T1; + T1 *= T1; + dRds_dVg = pParam->BSIM3V1rds0 * pParam->BSIM3V1prwg * T1; + dRds_dVb = pParam->BSIM3V1rds0 * pParam->BSIM3V1prwb * dsqrtPhis_dVb + * T1; + } + +/* Calculate Abulk */ + T1 = 0.5 * pParam->BSIM3V1k1 / sqrtPhis; + dT1_dVb = -T1 / sqrtPhis * dsqrtPhis_dVb; + + T9 = sqrt(pParam->BSIM3V1xj * Xdep); + tmp1 = Leff + 2.0 * T9; + T5 = Leff / tmp1; + tmp2 = pParam->BSIM3V1a0 * T5; + tmp3 = pParam->BSIM3V1weff + pParam->BSIM3V1b1; + tmp4 = pParam->BSIM3V1b0 / tmp3; + T2 = tmp2 + tmp4; + dT2_dVb = -T9 / tmp1 / Xdep * dXdep_dVb; + T6 = T5 * T5; + T7 = T5 * T6; + + Abulk0 = 1.0 + T1 * T2; + dAbulk0_dVb = T1 * tmp2 * dT2_dVb + T2 * dT1_dVb; + + T8 = pParam->BSIM3V1ags * pParam->BSIM3V1a0 * T7; + dAbulk_dVg = -T1 * T8; + Abulk = Abulk0 + dAbulk_dVg * Vgsteff; + dAbulk_dVb = dAbulk0_dVb - T8 * Vgsteff * (dT1_dVb + + 3.0 * T1 * dT2_dVb); + + if (Abulk0 < 0.1) /* added to avoid the problems caused by Abulk0 */ + { T9 = 1.0 / (3.0 - 20.0 * Abulk0); + Abulk0 = (0.2 - Abulk0) * T9; + dAbulk0_dVb *= T9 * T9; + } + + if (Abulk < 0.1) + /* added to avoid the problems caused by Abulk */ + { T9 = 1.0 / (3.0 - 20.0 * Abulk); + Abulk = (0.2 - Abulk) * T9; + dAbulk_dVb *= T9 * T9; + } + + T2 = pParam->BSIM3V1keta * Vbseff; + if (T2 >= -0.9) + { T0 = 1.0 / (1.0 + T2); + dT0_dVb = -pParam->BSIM3V1keta * T0 * T0; + } + else + /* added to avoid the problems caused by Keta */ + { T1 = 1.0 / (0.8 + T2); + T0 = (17.0 + 20.0 * T2) * T1; + dT0_dVb = -pParam->BSIM3V1keta * T1 * T1; + } + dAbulk_dVg *= T0; + dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb; + dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb; + Abulk *= T0; + Abulk0 *= T0; + + +/* Mobility calculation */ + if (model->BSIM3V1mobMod == 1) + { T0 = Vgsteff + Vth + Vth; + T2 = pParam->BSIM3V1ua + pParam->BSIM3V1uc * Vbseff; + T3 = T0 / model->BSIM3V1tox; + T5 = T3 * (T2 + pParam->BSIM3V1ub * T3); + dDenomi_dVg = (T2 + 2.0 * pParam->BSIM3V1ub * T3) / model->BSIM3V1tox; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM3V1uc * T3; + } + else if (model->BSIM3V1mobMod == 2) + { T5 = Vgsteff / model->BSIM3V1tox * (pParam->BSIM3V1ua + + pParam->BSIM3V1uc * Vbseff + pParam->BSIM3V1ub * Vgsteff + / model->BSIM3V1tox); + dDenomi_dVg = (pParam->BSIM3V1ua + pParam->BSIM3V1uc * Vbseff + + 2.0 * pParam->BSIM3V1ub * Vgsteff / model->BSIM3V1tox) + / model->BSIM3V1tox; + dDenomi_dVd = 0.0; + dDenomi_dVb = Vgsteff * pParam->BSIM3V1uc / model->BSIM3V1tox; + } + else + { T0 = Vgsteff + Vth + Vth; + T2 = 1.0 + pParam->BSIM3V1uc * Vbseff; + T3 = T0 / model->BSIM3V1tox; + T4 = T3 * (pParam->BSIM3V1ua + pParam->BSIM3V1ub * T3); + T5 = T4 * T2; + dDenomi_dVg = (pParam->BSIM3V1ua + 2.0 * pParam->BSIM3V1ub * T3) * T2 + / model->BSIM3V1tox; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM3V1uc * T4; + } + + if (T5 >= -0.8) + { Denomi = 1.0 + T5; + } + else /* Added to avoid the discontinuity problem caused by ua and ub*/ + { T9 = 1.0 / (7.0 + 10.0 * T5); + Denomi = (0.6 + T5) * T9; + T9 *= T9; + dDenomi_dVg *= T9; + dDenomi_dVd *= T9; + dDenomi_dVb *= T9; + } + + here->BSIM3V1ueff = ueff = pParam->BSIM3V1u0temp / Denomi; + T9 = -ueff / Denomi; + dueff_dVg = T9 * dDenomi_dVg; + dueff_dVd = T9 * dDenomi_dVd; + dueff_dVb = T9 * dDenomi_dVb; + +/* Saturation Drain Voltage Vdsat */ + WVCox = Weff * pParam->BSIM3V1vsattemp * model->BSIM3V1cox; + WVCoxRds = WVCox * Rds; + + Esat = 2.0 * pParam->BSIM3V1vsattemp / ueff; + EsatL = Esat * Leff; + T0 = -EsatL /ueff; + dEsatL_dVg = T0 * dueff_dVg; + dEsatL_dVd = T0 * dueff_dVd; + dEsatL_dVb = T0 * dueff_dVb; + + /* Sqrt() */ + a1 = pParam->BSIM3V1a1; + if (a1 == 0.0) + { Lambda = pParam->BSIM3V1a2; + dLambda_dVg = 0.0; + } + else if (a1 > 0.0) +/* Added to avoid the discontinuity problem + caused by a1 and a2 (Lambda) */ + { T0 = 1.0 - pParam->BSIM3V1a2; + T1 = T0 - pParam->BSIM3V1a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * T0); + Lambda = pParam->BSIM3V1a2 + T0 - 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM3V1a1 * (1.0 + T1 / T2); + } + else + { T1 = pParam->BSIM3V1a2 + pParam->BSIM3V1a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * pParam->BSIM3V1a2); + Lambda = 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM3V1a1 * (1.0 + T1 / T2); + } + + Vgst2Vtm = Vgsteff + 2.0 * Vtm; + if (Rds > 0) + { tmp2 = dRds_dVg / Rds + dWeff_dVg / Weff; + tmp3 = dRds_dVb / Rds + dWeff_dVb / Weff; + } + else + { tmp2 = dWeff_dVg / Weff; + tmp3 = dWeff_dVb / Weff; + } + if ((Rds == 0.0) && (Lambda == 1.0)) + { T0 = 1.0 / (Abulk * EsatL + Vgst2Vtm); + tmp1 = 0.0; + T1 = T0 * T0; + T2 = Vgst2Vtm * T0; + T3 = EsatL * Vgst2Vtm; + Vdsat = T3 * T0; + + dT0_dVg = -(Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 1.0) * T1; + dT0_dVd = -(Abulk * dEsatL_dVd) * T1; + dT0_dVb = -(Abulk * dEsatL_dVb + dAbulk_dVb * EsatL) * T1; + + dVdsat_dVg = T3 * dT0_dVg + T2 * dEsatL_dVg + EsatL * T0; + dVdsat_dVd = T3 * dT0_dVd + T2 * dEsatL_dVd; + dVdsat_dVb = T3 * dT0_dVb + T2 * dEsatL_dVb; + } + else + { tmp1 = dLambda_dVg / (Lambda * Lambda); + T9 = Abulk * WVCoxRds; + T8 = Abulk * T9; + T7 = Vgst2Vtm * T9; + T6 = Vgst2Vtm * WVCoxRds; + T0 = 2.0 * Abulk * (T9 - 1.0 + 1.0 / Lambda); + dT0_dVg = 2.0 * (T8 * tmp2 - Abulk * tmp1 + + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbulk_dVg); + + dT0_dVb = 2.0 * (T8 * (2.0 / Abulk * dAbulk_dVb + tmp3) + + (1.0 / Lambda - 1.0) * dAbulk_dVb); + dT0_dVd = 0.0; + T1 = Vgst2Vtm * (2.0 / Lambda - 1.0) + Abulk * EsatL + 3.0 * T7; + + dT1_dVg = (2.0 / Lambda - 1.0) - 2.0 * Vgst2Vtm * tmp1 + + Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 3.0 * (T9 + + T7 * tmp2 + T6 * dAbulk_dVg); + dT1_dVb = Abulk * dEsatL_dVb + EsatL * dAbulk_dVb + + 3.0 * (T6 * dAbulk_dVb + T7 * tmp3); + dT1_dVd = Abulk * dEsatL_dVd; + + T2 = Vgst2Vtm * (EsatL + 2.0 * T6); + dT2_dVg = EsatL + Vgst2Vtm * dEsatL_dVg + + T6 * (4.0 + 2.0 * Vgst2Vtm * tmp2); + dT2_dVb = Vgst2Vtm * (dEsatL_dVb + 2.0 * T6 * tmp3); + dT2_dVd = Vgst2Vtm * dEsatL_dVd; + + T3 = sqrt(T1 * T1 - 2.0 * T0 * T2); + Vdsat = (T1 - T3) / T0; + + dT3_dVg = (T1 * dT1_dVg - 2.0 * (T0 * dT2_dVg + T2 * dT0_dVg)) + / T3; + dT3_dVd = (T1 * dT1_dVd - 2.0 * (T0 * dT2_dVd + T2 * dT0_dVd)) + / T3; + dT3_dVb = (T1 * dT1_dVb - 2.0 * (T0 * dT2_dVb + T2 * dT0_dVb)) + / T3; + + dVdsat_dVg = (dT1_dVg - (T1 * dT1_dVg - dT0_dVg * T2 + - T0 * dT2_dVg) / T3 - Vdsat * dT0_dVg) / T0; + dVdsat_dVb = (dT1_dVb - (T1 * dT1_dVb - dT0_dVb * T2 + - T0 * dT2_dVb) / T3 - Vdsat * dT0_dVb) / T0; + dVdsat_dVd = (dT1_dVd - (T1 * dT1_dVd - T0 * dT2_dVd) / T3) / T0; + } + here->BSIM3V1vdsat = Vdsat; + +/* Effective Vds (Vdseff) Calculation */ + T1 = Vdsat - Vds - pParam->BSIM3V1delta; + dT1_dVg = dVdsat_dVg; + dT1_dVd = dVdsat_dVd - 1.0; + dT1_dVb = dVdsat_dVb; + + T2 = sqrt(T1 * T1 + 4.0 * pParam->BSIM3V1delta * Vdsat); + T0 = T1 / T2; + T3 = 2.0 * pParam->BSIM3V1delta / T2; + dT2_dVg = T0 * dT1_dVg + T3 * dVdsat_dVg; + dT2_dVd = T0 * dT1_dVd + T3 * dVdsat_dVd; + dT2_dVb = T0 * dT1_dVb + T3 * dVdsat_dVb; + + Vdseff = Vdsat - 0.5 * (T1 + T2); + dVdseff_dVg = dVdsat_dVg - 0.5 * (dT1_dVg + dT2_dVg); + dVdseff_dVd = dVdsat_dVd - 0.5 * (dT1_dVd + dT2_dVd); + dVdseff_dVb = dVdsat_dVb - 0.5 * (dT1_dVb + dT2_dVb); + +/* Calculate VAsat */ + tmp4 = 1.0 - 0.5 * Abulk * Vdsat / Vgst2Vtm; + T9 = WVCoxRds * Vgsteff; + T8 = T9 / Vgst2Vtm; + T0 = EsatL + Vdsat + 2.0 * T9 * tmp4; + + T7 = 2.0 * WVCoxRds * tmp4; + dT0_dVg = dEsatL_dVg + dVdsat_dVg + T7 * (1.0 + tmp2 * Vgsteff) + - T8 * (Abulk * dVdsat_dVg - Abulk * Vdsat / Vgst2Vtm + + Vdsat * dAbulk_dVg); + + dT0_dVb = dEsatL_dVb + dVdsat_dVb + T7 * tmp3 * Vgsteff + - T8 * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = dEsatL_dVd + dVdsat_dVd - T8 * Abulk * dVdsat_dVd; + + T9 = WVCoxRds * Abulk; + T1 = 2.0 / Lambda - 1.0 + T9; + dT1_dVg = -2.0 * tmp1 + WVCoxRds * (Abulk * tmp2 + dAbulk_dVg); + dT1_dVb = dAbulk_dVb * WVCoxRds + T9 * tmp3; + + Vasat = T0 / T1; + dVasat_dVg = (dT0_dVg - Vasat * dT1_dVg) / T1; + dVasat_dVb = (dT0_dVb - Vasat * dT1_dVb) / T1; + dVasat_dVd = dT0_dVd / T1; + + if (Vdseff > Vds) + Vdseff = Vds; /* This code is added to fixed the problem + caused by computer precision when + Vds is very close to Vdseff. */ + diffVds = Vds - Vdseff; +/* Calculate VACLM */ + if ((pParam->BSIM3V1pclm > 0.0) && (diffVds > 1.0e-10)) + { T0 = 1.0 / (pParam->BSIM3V1pclm * Abulk * pParam->BSIM3V1litl); + dT0_dVb = -T0 / Abulk * dAbulk_dVb; + dT0_dVg = -T0 / Abulk * dAbulk_dVg; + + T2 = Vgsteff / EsatL; + T1 = Leff * (Abulk + T2); + dT1_dVg = Leff * ((1.0 - T2 * dEsatL_dVg) / EsatL + dAbulk_dVg); + dT1_dVb = Leff * (dAbulk_dVb - T2 * dEsatL_dVb / EsatL); + dT1_dVd = -T2 * dEsatL_dVd / Esat; + + T9 = T0 * T1; + VACLM = T9 * diffVds; + dVACLM_dVg = T0 * dT1_dVg * diffVds - T9 * dVdseff_dVg + + T1 * diffVds * dT0_dVg; + dVACLM_dVb = (dT0_dVb * T1 + T0 * dT1_dVb) * diffVds + - T9 * dVdseff_dVb; + dVACLM_dVd = T0 * dT1_dVd * diffVds + T9 * (1.0 - dVdseff_dVd); + } + else + { VACLM = MAX_EXP; + dVACLM_dVd = dVACLM_dVg = dVACLM_dVb = 0.0; + } + +/* Calculate VADIBL */ + if (pParam->BSIM3V1thetaRout > 0.0) + { T8 = Abulk * Vdsat; + T0 = Vgst2Vtm * T8; + dT0_dVg = Vgst2Vtm * Abulk * dVdsat_dVg + T8 + + Vgst2Vtm * Vdsat * dAbulk_dVg; + dT0_dVb = Vgst2Vtm * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = Vgst2Vtm * Abulk * dVdsat_dVd; + + T1 = Vgst2Vtm + T8; + dT1_dVg = 1.0 + Abulk * dVdsat_dVg + Vdsat * dAbulk_dVg; + dT1_dVb = Abulk * dVdsat_dVb + dAbulk_dVb * Vdsat; + dT1_dVd = Abulk * dVdsat_dVd; + + T9 = T1 * T1; + T2 = pParam->BSIM3V1thetaRout; + VADIBL = (Vgst2Vtm - T0 / T1) / T2; + dVADIBL_dVg = (1.0 - dT0_dVg / T1 + T0 * dT1_dVg / T9) / T2; + dVADIBL_dVb = (-dT0_dVb / T1 + T0 * dT1_dVb / T9) / T2; + dVADIBL_dVd = (-dT0_dVd / T1 + T0 * dT1_dVd / T9) / T2; + + T7 = pParam->BSIM3V1pdiblb * Vbseff; + if (T7 >= -0.9) + { T3 = 1.0 / (1.0 + T7); + VADIBL *= T3; + dVADIBL_dVg *= T3; + dVADIBL_dVb = (dVADIBL_dVb - VADIBL * pParam->BSIM3V1pdiblb) + * T3; + dVADIBL_dVd *= T3; + } + else +/* Added to avoid the discontinuity problem caused by pdiblcb */ + { T4 = 1.0 / (0.8 + T7); + T3 = (17.0 + 20.0 * T7) * T4; + dVADIBL_dVg *= T3; + dVADIBL_dVb = dVADIBL_dVb * T3 + - VADIBL * pParam->BSIM3V1pdiblb * T4 * T4; + dVADIBL_dVd *= T3; + VADIBL *= T3; + } + } + else + { VADIBL = MAX_EXP; + dVADIBL_dVd = dVADIBL_dVg = dVADIBL_dVb = 0.0; + } + +/* Calculate VA */ + + T8 = pParam->BSIM3V1pvag / EsatL; + T9 = T8 * Vgsteff; + if (T9 > -0.9) + { T0 = 1.0 + T9; + dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL); + dT0_dVb = -T9 * dEsatL_dVb / EsatL; + dT0_dVd = -T9 * dEsatL_dVd / EsatL; + } + else /* Added to avoid the discontinuity problems caused by pvag */ + { T1 = 1.0 / (17.0 + 20.0 * T9); + T0 = (0.8 + T9) * T1; + T1 *= T1; + dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL) * T1; + + T9 *= T1 / EsatL; + dT0_dVb = -T9 * dEsatL_dVb; + dT0_dVd = -T9 * dEsatL_dVd; + } + + tmp1 = VACLM * VACLM; + tmp2 = VADIBL * VADIBL; + tmp3 = VACLM + VADIBL; + + T1 = VACLM * VADIBL / tmp3; + tmp3 *= tmp3; + dT1_dVg = (tmp1 * dVADIBL_dVg + tmp2 * dVACLM_dVg) / tmp3; + dT1_dVd = (tmp1 * dVADIBL_dVd + tmp2 * dVACLM_dVd) / tmp3; + dT1_dVb = (tmp1 * dVADIBL_dVb + tmp2 * dVACLM_dVb) / tmp3; + + Va = Vasat + T0 * T1; + dVa_dVg = dVasat_dVg + T1 * dT0_dVg + T0 * dT1_dVg; + dVa_dVd = dVasat_dVd + T1 * dT0_dVd + T0 * dT1_dVd; + dVa_dVb = dVasat_dVb + T1 * dT0_dVb + T0 * dT1_dVb; + +/* Calculate VASCBE */ + if (pParam->BSIM3V1pscbe2 > 0.0) + { if (diffVds > pParam->BSIM3V1pscbe1 * pParam->BSIM3V1litl + / EXP_THRESHOLD) + { T0 = pParam->BSIM3V1pscbe1 * pParam->BSIM3V1litl / diffVds; + VASCBE = Leff * exp(T0) / pParam->BSIM3V1pscbe2; + T1 = T0 * VASCBE / diffVds; + dVASCBE_dVg = T1 * dVdseff_dVg; + dVASCBE_dVd = -T1 * (1.0 - dVdseff_dVd); + dVASCBE_dVb = T1 * dVdseff_dVb; + } + else + { VASCBE = MAX_EXP * Leff/pParam->BSIM3V1pscbe2; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + } + else + { VASCBE = MAX_EXP; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + +/* Calculate Ids */ + CoxWovL = model->BSIM3V1cox * Weff / Leff; + beta = ueff * CoxWovL; + dbeta_dVg = CoxWovL * dueff_dVg + beta * dWeff_dVg / Weff; + dbeta_dVd = CoxWovL * dueff_dVd; + dbeta_dVb = CoxWovL * dueff_dVb + beta * dWeff_dVb / Weff; + + T0 = 1.0 - 0.5 * Abulk * Vdseff / Vgst2Vtm; + dT0_dVg = -0.5 * (Abulk * dVdseff_dVg + - Abulk * Vdseff / Vgst2Vtm + Vdseff * dAbulk_dVg) / Vgst2Vtm; + dT0_dVd = -0.5 * Abulk * dVdseff_dVd / Vgst2Vtm; + dT0_dVb = -0.5 * (Abulk * dVdseff_dVb + dAbulk_dVb * Vdseff) + / Vgst2Vtm; + + fgche1 = Vgsteff * T0; + dfgche1_dVg = Vgsteff * dT0_dVg + T0; + dfgche1_dVd = Vgsteff * dT0_dVd; + dfgche1_dVb = Vgsteff * dT0_dVb; + + T9 = Vdseff / EsatL; + fgche2 = 1.0 + T9; + dfgche2_dVg = (dVdseff_dVg - T9 * dEsatL_dVg) / EsatL; + dfgche2_dVd = (dVdseff_dVd - T9 * dEsatL_dVd) / EsatL; + dfgche2_dVb = (dVdseff_dVb - T9 * dEsatL_dVb) / EsatL; + + gche = beta * fgche1 / fgche2; + dgche_dVg = (beta * dfgche1_dVg + fgche1 * dbeta_dVg + - gche * dfgche2_dVg) / fgche2; + dgche_dVd = (beta * dfgche1_dVd + fgche1 * dbeta_dVd + - gche * dfgche2_dVd) / fgche2; + dgche_dVb = (beta * dfgche1_dVb + fgche1 * dbeta_dVb + - gche * dfgche2_dVb) / fgche2; + + T0 = 1.0 + gche * Rds; + T9 = Vdseff / T0; + Idl = gche * T9; + + dIdl_dVg = (gche * dVdseff_dVg + T9 * dgche_dVg) / T0 + - Idl * gche / T0 * dRds_dVg ; + + dIdl_dVd = (gche * dVdseff_dVd + T9 * dgche_dVd) / T0; + dIdl_dVb = (gche * dVdseff_dVb + T9 * dgche_dVb + - Idl * dRds_dVb * gche) / T0; + + T9 = diffVds / Va; + T0 = 1.0 + T9; + Idsa = Idl * T0; + dIdsa_dVg = T0 * dIdl_dVg - Idl * (dVdseff_dVg + T9 * dVa_dVg) / Va; + dIdsa_dVd = T0 * dIdl_dVd + Idl * (1.0 - dVdseff_dVd + - T9 * dVa_dVd) / Va; + dIdsa_dVb = T0 * dIdl_dVb - Idl * (dVdseff_dVb + T9 * dVa_dVb) / Va; + + T9 = diffVds / VASCBE; + T0 = 1.0 + T9; + Ids = Idsa * T0; + + Gm = T0 * dIdsa_dVg - Idsa * (dVdseff_dVg + T9 * dVASCBE_dVg) / VASCBE; + Gds = T0 * dIdsa_dVd + Idsa * (1.0 - dVdseff_dVd + - T9 * dVASCBE_dVd) / VASCBE; + Gmb = T0 * dIdsa_dVb - Idsa * (dVdseff_dVb + + T9 * dVASCBE_dVb) / VASCBE; + + Gds += Gm * dVgsteff_dVd; + Gmb += Gm * dVgsteff_dVb; + Gm *= dVgsteff_dVg; + Gmb *= dVbseff_dVb; + +/* calculate substrate current Isub */ + if ((pParam->BSIM3V1alpha0 <= 0.0) || (pParam->BSIM3V1beta0 <= 0.0)) + { Isub = Gbd = Gbb = Gbg = 0.0; + } + else + { T2 = pParam->BSIM3V1alpha0 / Leff; + if (diffVds > pParam->BSIM3V1beta0 / EXP_THRESHOLD) + { T0 = -pParam->BSIM3V1beta0 / diffVds; + T1 = T2 * diffVds * exp(T0); + T3 = T1 / diffVds * (T0 - 1.0); + dT1_dVg = T3 * dVdseff_dVg; + dT1_dVd = -T3 * (1.0 - dVdseff_dVd); + dT1_dVb = T3 * dVdseff_dVb; + } + else + { T3 = T2 * MIN_EXP; + T1 = T3 * diffVds; + dT1_dVg = -T3 * dVdseff_dVg; + dT1_dVd = T3 * (1.0 - dVdseff_dVd); + dT1_dVb = -T3 * dVdseff_dVb; + } + Isub = T1 * Idsa; + Gbg = T1 * dIdsa_dVg + Idsa * dT1_dVg; + Gbd = T1 * dIdsa_dVd + Idsa * dT1_dVd; + Gbb = T1 * dIdsa_dVb + Idsa * dT1_dVb; + + Gbd += Gbg * dVgsteff_dVd; + Gbb += Gbg * dVgsteff_dVb; + Gbg *= dVgsteff_dVg; + Gbb *= dVbseff_dVb; /* bug fixing */ + } + + if (Gmb < -1e-12 || Gds < 0 || Gm < -1e-12) printf("@ vds=%g vgs=%g vbs=%g Id=%g\n",Vds, Vgs, Vbs, Ids); + if (Gds < 0) + { + printf("WARNING: negative Gds = %g for %s %s\n",Gds, + model->BSIM3V1type == 1 ? "nfet" : "pfet", here->BSIM3V1name); + /* Gds = 1e-15;*/ + } + if (Gm < -1e-12) + { + printf("WARNING: negative Gm = %g for %s %s\n",Gm, + model->BSIM3V1type == 1 ? "nfet" : "pfet", here->BSIM3V1name); + /* Gm = 1e-15; */ + } + if (Gmb < -1e-12) + { + printf("WARNING: negative Gmb = %g for %s %s\n",Gmb, + model->BSIM3V1type == 1 ? "nfet" : "pfet", here->BSIM3V1name); + /* Gmb = 0; */ + } + + cdrain = Ids; + here->BSIM3V1gds = Gds; + here->BSIM3V1gm = Gm; + here->BSIM3V1gmbs = Gmb; + + here->BSIM3V1gbbs = Gbb; + here->BSIM3V1gbgs = Gbg; + here->BSIM3V1gbds = Gbd; + + here->BSIM3V1csub = Isub - (Gbb * Vbseff + Gbd * Vds + Gbg * Vgs); + +/* Calculate Qinv for Noise analysis */ + + T1 = Vgsteff * (1.0 - 0.5 * Abulk * Vdseff / Vgst2Vtm); + here->BSIM3V1qinv = -model->BSIM3V1cox * Weff * Leff * T1; + + if ((model->BSIM3V1xpart < 0) || (!ChargeComputationNeeded)) + { qgate = qdrn = qsrc = qbulk = 0.0; + here->BSIM3V1cggb = here->BSIM3V1cgsb = here->BSIM3V1cgdb = 0.0; + here->BSIM3V1cdgb = here->BSIM3V1cdsb = here->BSIM3V1cddb = 0.0; + here->BSIM3V1cbgb = here->BSIM3V1cbsb = here->BSIM3V1cbdb = 0.0; + here->BSIM3V1cqdb = here->BSIM3V1cqsb = here->BSIM3V1cqgb + = here->BSIM3V1cqbb = 0.0; + here->BSIM3V1gtau = 0.0; + goto finished; + } + else if (model->BSIM3V1capMod == 0) + { + if (Vbseff < 0.0) + { Vbseff = Vbs; + dVbseff_dVb = 1.0; + } + else + { Vbseff = pParam->BSIM3V1phi - Phis; + dVbseff_dVb = -dPhis_dVb; + } + + Vfb = pParam->BSIM3V1vfbcv; + Vth = Vfb + pParam->BSIM3V1phi + pParam->BSIM3V1k1 * sqrtPhis; + Vgst = Vgs_eff - Vth; + dVth_dVb = pParam->BSIM3V1k1 * dsqrtPhis_dVb; + dVgst_dVb = -dVth_dVb; + dVgst_dVg = dVgs_eff_dVg; + + CoxWL = model->BSIM3V1cox * pParam->BSIM3V1weffCV + * pParam->BSIM3V1leffCV; + Arg1 = Vgs_eff - Vbseff - Vfb; + if (Arg1 <= 0.0) + { qgate = CoxWL * Arg1; + qbulk = -qgate; + qdrn = 0.0; + + here->BSIM3V1cggb = CoxWL * dVgs_eff_dVg; + here->BSIM3V1cgdb = 0.0; + here->BSIM3V1cgsb = CoxWL * (dVbseff_dVb + - dVgs_eff_dVg); + + here->BSIM3V1cdgb = 0.0; + here->BSIM3V1cddb = 0.0; + here->BSIM3V1cdsb = 0.0; + + here->BSIM3V1cbgb = -CoxWL * dVgs_eff_dVg; + here->BSIM3V1cbdb = 0.0; + here->BSIM3V1cbsb = -here->BSIM3V1cgsb; + + } + else if (Vgst <= 0.0) + { T1 = 0.5 * pParam->BSIM3V1k1; + T2 = sqrt(T1 * T1 + Arg1); + qgate = CoxWL * pParam->BSIM3V1k1 * (T2 - T1); + qbulk = -qgate; + qdrn = 0.0; + + T0 = CoxWL * T1 / T2; + here->BSIM3V1cggb = T0 * dVgs_eff_dVg; + here->BSIM3V1cgdb = 0.0; + here->BSIM3V1cgsb = T0 * (dVbseff_dVb + - dVgs_eff_dVg); + + here->BSIM3V1cdgb = 0.0; + here->BSIM3V1cddb = 0.0; + here->BSIM3V1cdsb = 0.0; + + here->BSIM3V1cbgb = -here->BSIM3V1cggb; + here->BSIM3V1cbdb = 0.0; + here->BSIM3V1cbsb = -here->BSIM3V1cgsb; + } + else + { One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + + AbulkCV = Abulk0 * pParam->BSIM3V1abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3V1abulkCVfactor * dAbulk0_dVb; + Vdsat = Vgst / AbulkCV; + dVdsat_dVg = dVgs_eff_dVg / AbulkCV; + dVdsat_dVb = - (Vdsat * dAbulkCV_dVb + dVth_dVb)/ AbulkCV; + + if (model->BSIM3V1xpart > 0.5) + { /* 0/100 Charge petition model */ + if (Vdsat <= Vds) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V1phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.0; + + here->BSIM3V1cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3V1cgsb = -(here->BSIM3V1cggb + T2); + here->BSIM3V1cgdb = 0.0; + + here->BSIM3V1cdgb = 0.0; + here->BSIM3V1cddb = 0.0; + here->BSIM3V1cdsb = 0.0; + + here->BSIM3V1cbgb = -(here->BSIM3V1cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3V1cbsb = -(here->BSIM3V1cbgb + T3); + here->BSIM3V1cbdb = 0.0; + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + T7 = 2.0 * Vds - T1 - 3.0 * T3; + T8 = T3 - T1 - 2.0 * Vds; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V1phi - 0.5 * (Vds - T3)); + T10 = T4 * T8; + qdrn = T4 * T7; + qbulk = -(qgate + qdrn + T10); + + T5 = T3 / T1; + here->BSIM3V1cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3V1cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3V1cgsb = -(here->BSIM3V1cggb + T11 + + here->BSIM3V1cgdb); + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + T7 = T9 * T7; + T8 = T9 * T8; + T9 = 2.0 * T4 * (1.0 - 3.0 * T5); + here->BSIM3V1cdgb = (T7 * dAlphaz_dVg - T9 + * dVdsat_dVg) * dVgs_eff_dVg; + T12 = T7 * dAlphaz_dVb - T9 * dVdsat_dVb; + here->BSIM3V1cddb = T4 * (3.0 - 6.0 * T2 - 3.0 * T5); + here->BSIM3V1cdsb = -(here->BSIM3V1cdgb + T12 + + here->BSIM3V1cddb); + + T9 = 2.0 * T4 * (1.0 + T5); + T10 = (T8 * dAlphaz_dVg - T9 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = T8 * dAlphaz_dVb - T9 * dVdsat_dVb; + T12 = T4 * (2.0 * T2 + T5 - 1.0); + T0 = -(T10 + T11 + T12); + + here->BSIM3V1cbgb = -(here->BSIM3V1cggb + + here->BSIM3V1cdgb + T10); + here->BSIM3V1cbdb = -(here->BSIM3V1cgdb + + here->BSIM3V1cddb + T12); + here->BSIM3V1cbsb = -(here->BSIM3V1cgsb + + here->BSIM3V1cdsb + T0); + } + } + else if (model->BSIM3V1xpart < 0.5) + { /* 40/60 Charge petition model */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V1phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.4 * T2; + + here->BSIM3V1cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3V1cgsb = -(here->BSIM3V1cggb + T2); + here->BSIM3V1cgdb = 0.0; + + T3 = 0.4 * Two_Third_CoxWL; + here->BSIM3V1cdgb = -T3 * dVgs_eff_dVg; + here->BSIM3V1cddb = 0.0; + T4 = T3 * dVth_dVb; + here->BSIM3V1cdsb = -(T4 + here->BSIM3V1cdgb); + + here->BSIM3V1cbgb = -(here->BSIM3V1cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3V1cbsb = -(here->BSIM3V1cbgb + T3); + here->BSIM3V1cbdb = 0.0; + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM3V1phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM3V1cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3V1cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3V1cgsb = -(here->BSIM3V1cggb + + here->BSIM3V1cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T6 = 8.0 * Vdsat * Vdsat - 6.0 * Vdsat * Vds + + 1.2 * Vds * Vds; + T8 = T2 / T1; + T7 = Vds - T1 - T8 * T6; + qdrn = T4 * T7; + T7 *= T9; + tmp = T8 / T1; + tmp1 = T4 * (2.0 - 4.0 * tmp * T6 + + T8 * (16.0 * Vdsat - 6.0 * Vds)); + + here->BSIM3V1cdgb = (T7 * dAlphaz_dVg - tmp1 + * dVdsat_dVg) * dVgs_eff_dVg; + T10 = T7 * dAlphaz_dVb - tmp1 * dVdsat_dVb; + here->BSIM3V1cddb = T4 * (2.0 - (1.0 / (3.0 * T1 + * T1) + 2.0 * tmp) * T6 + T8 + * (6.0 * Vdsat - 2.4 * Vds)); + here->BSIM3V1cdsb = -(here->BSIM3V1cdgb + + T10 + here->BSIM3V1cddb); + + T7 = 2.0 * (T1 + T3); + qbulk = -(qgate - T4 * T7); + T7 *= T9; + T0 = 4.0 * T4 * (1.0 - T5); + T12 = (-T7 * dAlphaz_dVg - here->BSIM3V1cdgb + - T0 * dVdsat_dVg) * dVgs_eff_dVg; + T11 = -T7 * dAlphaz_dVb - T10 - T0 * dVdsat_dVb; + T10 = -4.0 * T4 * (T2 - 0.5 + 0.5 * T5) + - here->BSIM3V1cddb; + tmp = -(T10 + T11 + T12); + + here->BSIM3V1cbgb = -(here->BSIM3V1cggb + + here->BSIM3V1cdgb + T12); + here->BSIM3V1cbdb = -(here->BSIM3V1cgdb + + here->BSIM3V1cddb + T11); + here->BSIM3V1cbsb = -(here->BSIM3V1cgsb + + here->BSIM3V1cdsb + tmp); + } + } + else + { /* 50/50 partitioning */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V1phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.5 * T2; + + here->BSIM3V1cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3V1cgsb = -(here->BSIM3V1cggb + T2); + here->BSIM3V1cgdb = 0.0; + + here->BSIM3V1cdgb = -One_Third_CoxWL * dVgs_eff_dVg; + here->BSIM3V1cddb = 0.0; + T4 = One_Third_CoxWL * dVth_dVb; + here->BSIM3V1cdsb = -(T4 + here->BSIM3V1cdgb); + + here->BSIM3V1cbgb = -(here->BSIM3V1cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3V1cbsb = -(here->BSIM3V1cbgb + T3); + here->BSIM3V1cbdb = 0.0; + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM3V1phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM3V1cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3V1cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3V1cgsb = -(here->BSIM3V1cggb + + here->BSIM3V1cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T7 = T1 + T3; + qdrn = -T4 * T7; + qbulk = - (qgate + qdrn + qdrn); + T7 *= T9; + T0 = T4 * (2.0 * T5 - 2.0); + + here->BSIM3V1cdgb = (T0 * dVdsat_dVg - T7 + * dAlphaz_dVg) * dVgs_eff_dVg; + T12 = T0 * dVdsat_dVb - T7 * dAlphaz_dVb; + here->BSIM3V1cddb = T4 * (1.0 - 2.0 * T2 - T5); + here->BSIM3V1cdsb = -(here->BSIM3V1cdgb + T12 + + here->BSIM3V1cddb); + + here->BSIM3V1cbgb = -(here->BSIM3V1cggb + + 2.0 * here->BSIM3V1cdgb); + here->BSIM3V1cbdb = -(here->BSIM3V1cgdb + + 2.0 * here->BSIM3V1cddb); + here->BSIM3V1cbsb = -(here->BSIM3V1cgsb + + 2.0 * here->BSIM3V1cdsb); + } + } + } + + } + else + { if (Vbseff < 0.0) + { VbseffCV = Vbseff; + dVbseffCV_dVb = 1.0; + } + else + { VbseffCV = pParam->BSIM3V1phi - Phis; + dVbseffCV_dVb = -dPhis_dVb; + } + + CoxWL = model->BSIM3V1cox * pParam->BSIM3V1weffCV + * pParam->BSIM3V1leffCV; + Vfb = Vth - pParam->BSIM3V1phi - pParam->BSIM3V1k1 * sqrtPhis; + + dVfb_dVb = dVth_dVb - pParam->BSIM3V1k1 * dsqrtPhis_dVb; + dVfb_dVd = dVth_dVd; + + if ((VgstNVt > -EXP_THRESHOLD) && (VgstNVt < EXP_THRESHOLD)) + { ExpVgst *= ExpVgst; + Vgsteff = n * Vtm * log(1.0 + ExpVgst); + dVgsteff_dVg = ExpVgst / (1.0 + ExpVgst); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + (Vgs_eff - Vth) + / n * dn_dVd) + Vgsteff / n * dn_dVd; + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + (Vgs_eff - Vth) + / n * dn_dVb) + Vgsteff / n * dn_dVb; + dVgsteff_dVg *= dVgs_eff_dVg; + } + + if (model->BSIM3V1capMod == 1) + { Arg1 = Vgs_eff - VbseffCV - Vfb - Vgsteff; + + if (Arg1 <= 0.0) + { qgate = CoxWL * Arg1; + Cgg = CoxWL * (dVgs_eff_dVg - dVgsteff_dVg); + Cgd = -CoxWL * (dVfb_dVd + dVgsteff_dVd); + Cgb = -CoxWL * (dVfb_dVb + dVbseffCV_dVb + dVgsteff_dVb); + } + else + { T0 = 0.5 * pParam->BSIM3V1k1; + T1 = sqrt(T0 * T0 + Arg1); + T2 = CoxWL * T0 / T1; + + qgate = CoxWL * pParam->BSIM3V1k1 * (T1 - T0); + + Cgg = T2 * (dVgs_eff_dVg - dVgsteff_dVg); + Cgd = -T2 * (dVfb_dVd + dVgsteff_dVd); + Cgb = -T2 * (dVfb_dVb + dVbseffCV_dVb + dVgsteff_dVb); + } + qbulk = -qgate; + Cbg = -Cgg; + Cbd = -Cgd; + Cbb = -Cgb; + + One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + AbulkCV = Abulk0 * pParam->BSIM3V1abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3V1abulkCVfactor * dAbulk0_dVb; + VdsatCV = Vgsteff / AbulkCV; + if (VdsatCV < Vds) + { dVdsatCV_dVg = 1.0 / AbulkCV; + dVdsatCV_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; + T0 = Vgsteff - VdsatCV / 3.0; + dT0_dVg = 1.0 - dVdsatCV_dVg / 3.0; + dT0_dVb = -dVdsatCV_dVb / 3.0; + qgate += CoxWL * T0; + Cgg1 = CoxWL * dT0_dVg; + Cgb1 = CoxWL * dT0_dVb + Cgg1 * dVgsteff_dVb; + Cgd1 = Cgg1 * dVgsteff_dVd; + Cgg1 *= dVgsteff_dVg; + Cgg += Cgg1; + Cgb += Cgb1; + Cgd += Cgd1; + + T0 = VdsatCV - Vgsteff; + dT0_dVg = dVdsatCV_dVg - 1.0; + dT0_dVb = dVdsatCV_dVb; + qbulk += One_Third_CoxWL * T0; + Cbg1 = One_Third_CoxWL * dT0_dVg; + Cbb1 = One_Third_CoxWL * dT0_dVb + Cbg1 * dVgsteff_dVb; + Cbd1 = Cbg1 * dVgsteff_dVd; + Cbg1 *= dVgsteff_dVg; + Cbg += Cbg1; + Cbb += Cbb1; + Cbd += Cbd1; + + if (model->BSIM3V1xpart > 0.5) + T0 = -Two_Third_CoxWL; + else if (model->BSIM3V1xpart < 0.5) + T0 = -0.4 * CoxWL; + else + T0 = -One_Third_CoxWL; + + qsrc = T0 * Vgsteff; + Csg = T0 * dVgsteff_dVg; + Csb = T0 * dVgsteff_dVb; + Csd = T0 * dVgsteff_dVd; + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + } + else + { T0 = AbulkCV * Vds; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1.e-20); + T2 = Vds / T1; + T3 = T0 * T2; + dT3_dVg = -12.0 * T2 * T2 * AbulkCV; + dT3_dVd = 6.0 * T0 * (4.0 * Vgsteff - T0) / T1 / T1 - 0.5; + dT3_dVb = 12.0 * T2 * T2 * dAbulkCV_dVb * Vgsteff; + + qgate += CoxWL * (Vgsteff - 0.5 * Vds + T3); + Cgg1 = CoxWL * (1.0 + dT3_dVg); + Cgb1 = CoxWL * dT3_dVb + Cgg1 * dVgsteff_dVb; + Cgd1 = CoxWL * dT3_dVd + Cgg1 * dVgsteff_dVd; + Cgg1 *= dVgsteff_dVg; + Cgg += Cgg1; + Cgb += Cgb1; + Cgd += Cgd1; + + qbulk += CoxWL * (1.0 - AbulkCV) * (0.5 * Vds - T3); + Cbg1 = -CoxWL * ((1.0 - AbulkCV) * dT3_dVg); + Cbb1 = -CoxWL * ((1.0 - AbulkCV) * dT3_dVb + + (0.5 * Vds - T3) * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbd1 = -CoxWL * (1.0 - AbulkCV) * dT3_dVd + + Cbg1 * dVgsteff_dVd; + Cbg1 *= dVgsteff_dVg; + Cbg += Cbg1; + Cbb += Cbb1; + Cbd += Cbd1; + + if (model->BSIM3V1xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + Csg = -CoxWL * (0.5 + 24.0 * T0 * Vds / T1 / T1 + * AbulkCV); + Csb = -CoxWL * (0.25 * Vds * dAbulkCV_dVb + - 12.0 * T0 * Vds / T1 / T1 * (4.0 * Vgsteff - T0) + * dAbulkCV_dVb) + Csg * dVgsteff_dVb; + Csd = -CoxWL * (0.25 * AbulkCV - 12.0 * AbulkCV * T0 + / T1 / T1 * (4.0 * Vgsteff - T0)) + + Csg * dVgsteff_dVd; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM3V1xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T4 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + Csg = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + Csb = (qsrc / T1 * Vds + T2 * T4 * Vds) * dAbulkCV_dVb + + Csg * dVgsteff_dVb; + Csd = (qsrc / T1 + T2 * T4) * AbulkCV + + Csg * dVgsteff_dVd; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + } + qdrn = -(qgate + qbulk + qsrc); + here->BSIM3V1cggb = Cgg; + here->BSIM3V1cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3V1cgdb = Cgd; + here->BSIM3V1cdgb = -(Cgg + Cbg + Csg); + here->BSIM3V1cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3V1cddb = -(Cgd + Cbd + Csd); + here->BSIM3V1cbgb = Cbg; + here->BSIM3V1cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3V1cbdb = Cbd; + } + else if (model->BSIM3V1capMod == 2) + + { V3 = Vfb - Vgs_eff + VbseffCV - DELTA_3; + if (Vfb <= 0.0) + { T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); + T2 = -DELTA_3 / T0; + } + else + { T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); + T2 = DELTA_3 / T0; + } + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = Vfb - 0.5 * (V3 + T0); + dVfbeff_dVd = (1.0 - T1 - T2) * dVfb_dVd; + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = (1.0 - T1 - T2) * dVfb_dVb + - T1 * dVbseffCV_dVb; + Qac0 = CoxWL * (Vfbeff - Vfb); + dQac0_dVg = CoxWL * dVfbeff_dVg; + dQac0_dVd = CoxWL * (dVfbeff_dVd - dVfb_dVd); + dQac0_dVb = CoxWL * (dVfbeff_dVb - dVfb_dVb); + + T0 = 0.5 * pParam->BSIM3V1k1; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + if (pParam->BSIM3V1k1 == 0.0) + { T1 = 0.0; + T2 = 0.0; + } + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM3V1k1; + T2 = CoxWL; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = CoxWL * T0 / T1; + } + + Qsub0 = CoxWL * pParam->BSIM3V1k1 * (T1 - T0); + + dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg); + dQsub0_dVd = -T2 * (dVfbeff_dVd + dVgsteff_dVd); + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + + dVgsteff_dVb); + + One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + AbulkCV = Abulk0 * pParam->BSIM3V1abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3V1abulkCVfactor * dAbulk0_dVb; + VdsatCV = Vgsteff / AbulkCV; + + V4 = VdsatCV - Vds - DELTA_4; + T0 = sqrt(V4 * V4 + 4.0 * DELTA_4 * VdsatCV); + VdseffCV = VdsatCV - 0.5 * (V4 + T0); + T1 = 0.5 * (1.0 + V4 / T0); + T2 = DELTA_4 / T0; + T3 = (1.0 - T1 - T2) / AbulkCV; + dVdseffCV_dVg = T3; + dVdseffCV_dVd = T1; + dVdseffCV_dVb = -T3 * VdsatCV * dAbulkCV_dVb; + + T0 = AbulkCV * VdseffCV; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1e-20); + T2 = VdseffCV / T1; + T3 = T0 * T2; + + T4 = (1.0 - 12.0 * T2 * T2 * AbulkCV); + T5 = (6.0 * T0 * (4.0 * Vgsteff - T0) / (T1 * T1) - 0.5); + T6 = 12.0 * T2 * T2 * Vgsteff; + + qgate = CoxWL * (Vgsteff - 0.5 * VdseffCV + T3); + Cgg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cgd1 = CoxWL * T5 * dVdseffCV_dVd + Cgg1 * dVgsteff_dVd; + Cgb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb; + Cgg1 *= dVgsteff_dVg; + + T7 = 1.0 - AbulkCV; + qbulk = CoxWL * T7 * (0.5 * VdseffCV - T3); + T4 = -T7 * (T4 - 1.0); + T5 = -T7 * T5; + T6 = -(T7 * T6 + (0.5 * VdseffCV - T3)); + Cbg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cbd1 = CoxWL * T5 * dVdseffCV_dVd + Cbg1 * dVgsteff_dVd; + Cbb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbg1 *= dVgsteff_dVg; + + if (model->BSIM3V1xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + T7 = (4.0 * Vgsteff - T0) / (T1 * T1); + T4 = -(0.5 + 24.0 * T0 * T0 / (T1 * T1)); + T5 = -(0.25 * AbulkCV - 12.0 * AbulkCV * T0 * T7); + T6 = -(0.25 * VdseffCV - 12.0 * T0 * VdseffCV * T7); + Csg = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWL * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM3V1xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T7 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + T4 = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + T5 = (qsrc / T1 + T2 * T7) * AbulkCV; + T6 = (qsrc / T1 * VdseffCV + T2 * T7 * VdseffCV); + Csg = (T4 + T5 * dVdseffCV_dVg); + Csd = T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + + qgate += Qac0 + Qsub0; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cgg = dQac0_dVg + dQsub0_dVg + Cgg1; + Cgd = dQac0_dVd + dQsub0_dVd + Cgd1; + Cgb = dQac0_dVb + dQsub0_dVb + Cgb1; + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQac0_dVd - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM3V1cggb = Cgg; + here->BSIM3V1cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3V1cgdb = Cgd; + here->BSIM3V1cdgb = -(Cgg + Cbg + Csg); + here->BSIM3V1cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3V1cddb = -(Cgd + Cbd + Csd); + here->BSIM3V1cbgb = Cbg; + here->BSIM3V1cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3V1cbdb = Cbd; + + } +/* Non-quasi-static Model */ + + if (here->BSIM3V1nqsMod) + { + qcheq = -qbulk - qgate; + qbulk = qgate = qdrn = qsrc = 0.0; + + here->BSIM3V1cqgb = -(here->BSIM3V1cggb + here->BSIM3V1cbgb); + here->BSIM3V1cqdb = -(here->BSIM3V1cgdb + here->BSIM3V1cbdb); + here->BSIM3V1cqsb = -(here->BSIM3V1cgsb + here->BSIM3V1cbsb); + here->BSIM3V1cqbb = here->BSIM3V1cggb + here->BSIM3V1cgdb + + here->BSIM3V1cgsb + here->BSIM3V1cbgb + + here->BSIM3V1cbdb + here->BSIM3V1cbsb; + + here->BSIM3V1cggb = here->BSIM3V1cgsb = here->BSIM3V1cgdb = 0.0; + here->BSIM3V1cdgb = here->BSIM3V1cdsb = here->BSIM3V1cddb = 0.0; + here->BSIM3V1cbgb = here->BSIM3V1cbsb = here->BSIM3V1cbdb = 0.0; + + T0 = pParam->BSIM3V1leffCV * pParam->BSIM3V1leffCV; + here->BSIM3V1tconst = pParam->BSIM3V1u0temp * pParam->BSIM3V1elm + / CoxWL / T0; + + if (qcheq == 0.0) + here->BSIM3V1tconst = 0.0; + else if (qcheq < 0.0) + here->BSIM3V1tconst = -here->BSIM3V1tconst; + + gtau_drift = fabs(here->BSIM3V1tconst * qcheq); + gtau_diff = 16.0 * pParam->BSIM3V1u0temp * model->BSIM3V1vtm / T0; + + here->BSIM3V1gtau = gtau_drift + gtau_diff; + + *(ckt->CKTstate0 + here->BSIM3V1qcheq) = qcheq; + + if (ckt->CKTmode & MODEINITTRAN) + *(ckt->CKTstate1 + here->BSIM3V1qcheq) = + *(ckt->CKTstate0 + here->BSIM3V1qcheq); + + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V1qcheq); + if (error) return (error); + } + else + { here->BSIM3V1cqgb = here->BSIM3V1cqdb = here->BSIM3V1cqsb + = here->BSIM3V1cqbb = 0.0; + here->BSIM3V1gtau = 0.0; + } + } + +finished: /* returning Values to Calling Routine */ + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + here->BSIM3V1cd = here->BSIM3V1mode * cdrain - here->BSIM3V1cbd; + if (ChargeComputationNeeded) + { /* charge storage elements + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw: zero bias drain junction sidewall capacitance + along field oxide + * czbssw: zero bias source junction sidewall capacitance + along field oxide + * czbdswg: zero bias drain junction sidewall capacitance + along gate side + * czbsswg: zero bias source junction sidewall capacitance + along gate side + */ + + czbd = model->BSIM3V1unitAreaJctCap * here->BSIM3V1drainArea; + czbs = model->BSIM3V1unitAreaJctCap * here->BSIM3V1sourceArea; + if (here->BSIM3V1drainPerimeter < pParam->BSIM3V1weff) + { + czbdswg = model->BSIM3V1unitLengthGateSidewallJctCap + * here->BSIM3V1drainPerimeter; + czbdsw = 0.0; + } + else + { + czbdsw = model->BSIM3V1unitLengthSidewallJctCap + * (here->BSIM3V1drainPerimeter - pParam->BSIM3V1weff); + czbdswg = model->BSIM3V1unitLengthGateSidewallJctCap + * pParam->BSIM3V1weff; + } + if (here->BSIM3V1sourcePerimeter < pParam->BSIM3V1weff) + { + czbssw = 0.0; + czbsswg = model->BSIM3V1unitLengthGateSidewallJctCap + * here->BSIM3V1sourcePerimeter; + } + else + { + czbssw = model->BSIM3V1unitLengthSidewallJctCap + * (here->BSIM3V1sourcePerimeter - pParam->BSIM3V1weff); + czbsswg = model->BSIM3V1unitLengthGateSidewallJctCap + * pParam->BSIM3V1weff; + } + PhiB = model->BSIM3V1bulkJctPotential; + PhiBSW = model->BSIM3V1sidewallJctPotential; + PhiBSWG = model->BSIM3V1GatesidewallJctPotential; + MJ = model->BSIM3V1bulkJctBotGradingCoeff; + MJSW = model->BSIM3V1bulkJctSideGradingCoeff; + MJSWG = model->BSIM3V1bulkJctGateSideGradingCoeff; + + /* Source Bulk Junction */ + if (vbs == 0.0) + { *(ckt->CKTstate0 + here->BSIM3V1qbs) = 0.0; + here->BSIM3V1capbs = czbs + czbssw + czbsswg; + } + else if (vbs < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - vbs / PhiB; + if (MJ == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJ * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V1qbs) = PhiB * czbs + * (1.0 - arg * sarg) / (1.0 - MJ); + here->BSIM3V1capbs = czbs * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM3V1qbs) = 0.0; + here->BSIM3V1capbs = 0.0; + } + if (czbssw > 0.0) + { arg = 1.0 - vbs / PhiBSW; + if (MJSW == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSW * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V1qbs) += PhiBSW * czbssw + * (1.0 - arg * sarg) / (1.0 - MJSW); + here->BSIM3V1capbs += czbssw * sarg; + } + if (czbsswg > 0.0) + { arg = 1.0 - vbs / PhiBSWG; + if (MJSWG == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWG * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V1qbs) += PhiBSWG * czbsswg + * (1.0 - arg * sarg) / (1.0 - MJSWG); + here->BSIM3V1capbs += czbsswg * sarg; + } + + } + else + { *(ckt->CKTstate0+here->BSIM3V1qbs) = vbs * (czbs + czbssw + + czbsswg) + vbs * vbs * (czbs * MJ * 0.5 / PhiB + + czbssw * MJSW * 0.5 / PhiBSW + + czbsswg * MJSWG * 0.5 / PhiBSWG); + here->BSIM3V1capbs = czbs + czbssw + czbsswg + vbs * (czbs * MJ /PhiB + czbssw * MJSW / PhiBSW + czbsswg * MJSWG / PhiBSWG); + } + + /* Drain Bulk Junction */ + if (vbd == 0.0) + { *(ckt->CKTstate0 + here->BSIM3V1qbd) = 0.0; + here->BSIM3V1capbd = czbd + czbdsw + czbdswg; + } + else if (vbd < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - vbd / PhiB; + if (MJ == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJ * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V1qbd) = PhiB * czbd + * (1.0 - arg * sarg) / (1.0 - MJ); + here->BSIM3V1capbd = czbd * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM3V1qbd) = 0.0; + here->BSIM3V1capbd = 0.0; + } + if (czbdsw > 0.0) + { arg = 1.0 - vbd / PhiBSW; + if (MJSW == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSW * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V1qbd) += PhiBSW * czbdsw + * (1.0 - arg * sarg) / (1.0 - MJSW); + here->BSIM3V1capbd += czbdsw * sarg; + } + if (czbdswg > 0.0) + { arg = 1.0 - vbd / PhiBSWG; + if (MJSWG == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWG * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V1qbd) += PhiBSWG * czbdswg + * (1.0 - arg * sarg) / (1.0 - MJSWG); + here->BSIM3V1capbd += czbdswg * sarg; + } + } + else + { *(ckt->CKTstate0+here->BSIM3V1qbd) = vbd * (czbd + czbdsw + + czbdswg) + vbd * vbd * (czbd * MJ * 0.5 / PhiB + + czbdsw * MJSW * 0.5 / PhiBSW + + czbdswg * MJSWG * 0.5 / PhiBSWG); + here->BSIM3V1capbd = czbd + czbdsw + czbdswg + vbd * (czbd * MJ / PhiB + czbdsw * MJSW / PhiBSW + czbdswg * MJSWG / PhiBSWG); + } + } + + /* + * check convergence + */ + if ((here->BSIM3V1off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { if (Check == 1) + { ckt->CKTnoncon++; +#ifndef NEWCONV + } + else + { tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(here->BSIM3V1cd)) + + ckt->CKTabstol; + if (fabs(cdhat - here->BSIM3V1cd) >= tol) + { ckt->CKTnoncon++; + } + else + { tol = ckt->CKTreltol * MAX(fabs(cbhat), + fabs(here->BSIM3V1cbs + here->BSIM3V1cbd)) + + ckt->CKTabstol; + if (fabs(cbhat - (here->BSIM3V1cbs + here->BSIM3V1cbd)) + > tol) + { ckt->CKTnoncon++; + } + } +#endif /* NEWCONV */ + } + } + *(ckt->CKTstate0 + here->BSIM3V1vbs) = vbs; + *(ckt->CKTstate0 + here->BSIM3V1vbd) = vbd; + *(ckt->CKTstate0 + here->BSIM3V1vgs) = vgs; + *(ckt->CKTstate0 + here->BSIM3V1vds) = vds; + + /* bulk and channel charge plus overlaps */ + + if (!ChargeComputationNeeded) + goto line850; + +line755: + ag0 = ckt->CKTag[0]; + + if (model->BSIM3V1capMod == 0) + { if (vgd < 0.0) + { + cgdo = pParam->BSIM3V1cgdo; + qgdo = pParam->BSIM3V1cgdo * vgd; + } + else + { cgdo = pParam->BSIM3V1cgdo; + qgdo = pParam->BSIM3V1cgdo * vgd; + } + + if (vgs < 0.0) + { + cgso = pParam->BSIM3V1cgso; + qgso = pParam->BSIM3V1cgso * vgs; + } + else + { cgso = pParam->BSIM3V1cgso; + qgso = pParam->BSIM3V1cgso * vgs; + } + } + else if (model->BSIM3V1capMod == 1) + { if (vgd < 0.0) + { T1 = sqrt(1.0 - 4.0 * vgd / pParam->BSIM3V1ckappa); + cgdo = pParam->BSIM3V1cgdo + pParam->BSIM3V1weffCV + * pParam->BSIM3V1cgdl / T1; + qgdo = pParam->BSIM3V1cgdo * vgd - pParam->BSIM3V1weffCV * 0.5 + * pParam->BSIM3V1cgdl * pParam->BSIM3V1ckappa * (T1 - 1.0); + } + else + { cgdo = pParam->BSIM3V1cgdo + pParam->BSIM3V1weffCV + * pParam->BSIM3V1cgdl; + qgdo = (pParam->BSIM3V1weffCV * pParam->BSIM3V1cgdl + + pParam->BSIM3V1cgdo) * vgd; + } + + + if (vgs < 0.0) + { T1 = sqrt(1.0 - 4.0 * vgs / pParam->BSIM3V1ckappa); + cgso = pParam->BSIM3V1cgso + pParam->BSIM3V1weffCV + * pParam->BSIM3V1cgsl / T1; + qgso = pParam->BSIM3V1cgso * vgs - pParam->BSIM3V1weffCV * 0.5 + * pParam->BSIM3V1cgsl * pParam->BSIM3V1ckappa * (T1 - 1.0); + } + else + { cgso = pParam->BSIM3V1cgso + pParam->BSIM3V1weffCV + * pParam->BSIM3V1cgsl; + qgso = (pParam->BSIM3V1weffCV * pParam->BSIM3V1cgsl + + pParam->BSIM3V1cgso) * vgs; + } + } + else + { T0 = vgd + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + + T3 = pParam->BSIM3V1weffCV * pParam->BSIM3V1cgdl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM3V1ckappa); + cgdo = pParam->BSIM3V1cgdo + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgdo = (pParam->BSIM3V1cgdo + T3) * vgd - T3 * (T2 + + 0.5 * pParam->BSIM3V1ckappa * (T4 - 1.0)); + + T0 = vgs + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + T3 = pParam->BSIM3V1weffCV * pParam->BSIM3V1cgsl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM3V1ckappa); + cgso = pParam->BSIM3V1cgso + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgso = (pParam->BSIM3V1cgso + T3) * vgs - T3 * (T2 + + 0.5 * pParam->BSIM3V1ckappa * (T4 - 1.0)); + } + + if (here->BSIM3V1mode > 0) + { gcdgb = (here->BSIM3V1cdgb - cgdo) * ag0; + gcddb = (here->BSIM3V1cddb + here->BSIM3V1capbd + cgdo) * ag0; + gcdsb = here->BSIM3V1cdsb * ag0; + gcsgb = -(here->BSIM3V1cggb + here->BSIM3V1cbgb + here->BSIM3V1cdgb + + cgso) * ag0; + gcsdb = -(here->BSIM3V1cgdb + here->BSIM3V1cbdb + here->BSIM3V1cddb) + * ag0; + gcssb = (here->BSIM3V1capbs + cgso - (here->BSIM3V1cgsb + + here->BSIM3V1cbsb + here->BSIM3V1cdsb)) * ag0; + gcggb = (here->BSIM3V1cggb + cgdo + cgso + pParam->BSIM3V1cgbo ) * ag0; + gcgdb = (here->BSIM3V1cgdb - cgdo) * ag0; + gcgsb = (here->BSIM3V1cgsb - cgso) * ag0; + gcbgb = (here->BSIM3V1cbgb - pParam->BSIM3V1cgbo) * ag0; + gcbdb = (here->BSIM3V1cbdb - here->BSIM3V1capbd) * ag0; + gcbsb = (here->BSIM3V1cbsb - here->BSIM3V1capbs) * ag0; + + gcqgb = here->BSIM3V1cqgb * ag0; + gcqdb = here->BSIM3V1cqdb * ag0; + gcqsb = here->BSIM3V1cqsb * ag0; + gcqbb = here->BSIM3V1cqbb * ag0; + + T0 = here->BSIM3V1tconst * qdef; + here->BSIM3V1gtg = T0 * here->BSIM3V1cqgb; + here->BSIM3V1gtb = T0 * here->BSIM3V1cqbb; + here->BSIM3V1gtd = T0 * here->BSIM3V1cqdb; + here->BSIM3V1gts = T0 * here->BSIM3V1cqsb; + + sxpart = 0.6; + dxpart = 0.4; + + /* compute total terminal charge */ + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3V1cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qdrn -= qgd; + qsrc = -(qgate + qbulk + qdrn); + } + else + { gcsgb = (here->BSIM3V1cdgb - cgso) * ag0; + gcsdb = here->BSIM3V1cdsb * ag0; + gcssb = (here->BSIM3V1cddb + here->BSIM3V1capbs + cgso) * ag0; + + gcdgb = -(here->BSIM3V1cggb + here->BSIM3V1cbgb + here->BSIM3V1cdgb + + cgdo) * ag0; + gcdsb = -(here->BSIM3V1cgdb + here->BSIM3V1cbdb + here->BSIM3V1cddb) + * ag0; + gcddb = (here->BSIM3V1capbd + cgdo - (here->BSIM3V1cgsb + + here->BSIM3V1cbsb + here->BSIM3V1cdsb)) * ag0; + gcggb = (here->BSIM3V1cggb + cgdo + cgso + pParam->BSIM3V1cgbo ) * ag0; + gcgdb = (here->BSIM3V1cgsb - cgdo) * ag0; + gcgsb = (here->BSIM3V1cgdb - cgso) * ag0; + gcbgb = (here->BSIM3V1cbgb - pParam->BSIM3V1cgbo) * ag0; + gcbdb = (here->BSIM3V1cbsb - here->BSIM3V1capbd) * ag0; + gcbsb = (here->BSIM3V1cbdb - here->BSIM3V1capbs) * ag0; + + gcqgb = here->BSIM3V1cqgb * ag0; + gcqdb = here->BSIM3V1cqsb * ag0; + gcqsb = here->BSIM3V1cqdb * ag0; + gcqbb = here->BSIM3V1cqbb * ag0; + + T0 = here->BSIM3V1tconst * qdef; + here->BSIM3V1gtg = T0 * here->BSIM3V1cqgb; + here->BSIM3V1gtb = T0 * here->BSIM3V1cqbb; + here->BSIM3V1gtd = T0 * here->BSIM3V1cqdb; + here->BSIM3V1gts = T0 * here->BSIM3V1cqsb; + + dxpart = 0.6; + sxpart = 0.4; + + /* compute total terminal charge */ + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3V1cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qsrc = qdrn - qgs; + qdrn = -(qgate + qbulk + qsrc); + } + + here->BSIM3V1cgdo = cgdo; + here->BSIM3V1cgso = cgso; + +/* added by Mansun 11/1/93 */ + + + if (here->BSIM3V1nqsMod) + { *(ckt->CKTstate0 + here->BSIM3V1qcdump) = qdef; + + if (ckt->CKTmode & MODEINITTRAN) + *(ckt->CKTstate1 + here->BSIM3V1qcdump) = + *(ckt->CKTstate0 + here->BSIM3V1qcdump); + + error = NIintegrate(ckt, &gqdef, &cqdef, 1.0, here->BSIM3V1qcdump); + if (error) return (error); + } + else + { gqdef = cqdef = 0.0; + } + + if (ByPass) goto line860; + +/* End added by Mansun 11/1/93 */ + + *(ckt->CKTstate0 + here->BSIM3V1qg) = qgate; + *(ckt->CKTstate0 + here->BSIM3V1qd) = qdrn + - *(ckt->CKTstate0 + here->BSIM3V1qbd); + *(ckt->CKTstate0 + here->BSIM3V1qb) = qbulk + + *(ckt->CKTstate0 + here->BSIM3V1qbd) + + *(ckt->CKTstate0 + here->BSIM3V1qbs); + + /* store small signal parameters */ + if (ckt->CKTmode & MODEINITSMSIG) + { goto line1000; + } + if (!ChargeComputationNeeded) + goto line850; + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM3V1qb) = + *(ckt->CKTstate0 + here->BSIM3V1qb); + *(ckt->CKTstate1 + here->BSIM3V1qg) = + *(ckt->CKTstate0 + here->BSIM3V1qg); + *(ckt->CKTstate1 + here->BSIM3V1qd) = + *(ckt->CKTstate0 + here->BSIM3V1qd); + } + + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V1qb); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V1qg); + if (error) + return(error); + error = NIintegrate(ckt,&geq, &ceq, 0.0, here->BSIM3V1qd); + if (error) + return(error); + + goto line860; + +line850: + /* initialize to zero charge conductance and current */ + ceqqg = ceqqb = ceqqd = 0.0; + + cqcheq = cqdef = 0.0; + + gcdgb = gcddb = gcdsb = 0.0; + gcsgb = gcsdb = gcssb = 0.0; + gcggb = gcgdb = gcgsb = 0.0; + gcbgb = gcbdb = gcbsb = 0.0; + + gcqgb = gcqdb = gcqsb = gcqbb = 0.0; + here->BSIM3V1gtg = here->BSIM3V1gtd = here->BSIM3V1gts = here->BSIM3V1gtb = 0.0; + gqdef = 0.0; + sxpart = (1.0 - (dxpart = (here->BSIM3V1mode > 0) ? 0.4 : 0.6)); + if (here->BSIM3V1nqsMod) + here->BSIM3V1gtau = 16.0 * pParam->BSIM3V1u0temp * model->BSIM3V1vtm + / Leff / Leff; + else + here->BSIM3V1gtau = 0.0; + + goto line900; + +line860: + /* evaluate equivalent charge current */ + + cqgate = *(ckt->CKTstate0 + here->BSIM3V1cqg); + cqbulk = *(ckt->CKTstate0 + here->BSIM3V1cqb); + cqdrn = *(ckt->CKTstate0 + here->BSIM3V1cqd); + + ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs + + (here->BSIM3V1gtg * vgb - here->BSIM3V1gtd * vbd - here->BSIM3V1gts * vbs); + ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs; + ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs + - dxpart * (here->BSIM3V1gtg * vgb - here->BSIM3V1gtd * vbd + - here->BSIM3V1gts * vbs); + + cqcheq = *(ckt->CKTstate0 + here->BSIM3V1cqcheq) + - (gcqgb * vgb - gcqdb * vbd - gcqsb * vbs) + + (here->BSIM3V1gtg * vgb - here->BSIM3V1gtd * vbd - here->BSIM3V1gts * vbs); + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM3V1cqb) = + *(ckt->CKTstate0 + here->BSIM3V1cqb); + *(ckt->CKTstate1 + here->BSIM3V1cqg) = + *(ckt->CKTstate0 + here->BSIM3V1cqg); + *(ckt->CKTstate1 + here->BSIM3V1cqd) = + *(ckt->CKTstate0 + here->BSIM3V1cqd); + *(ckt->CKTstate1 + here->BSIM3V1cqcheq) = + *(ckt->CKTstate0 + here->BSIM3V1cqcheq); + *(ckt->CKTstate1 + here->BSIM3V1cqcdump) = + *(ckt->CKTstate0 + here->BSIM3V1cqcdump); + } + + /* + * load current vector + */ +line900: + + if (here->BSIM3V1mode >= 0) + { Gm = here->BSIM3V1gm; + Gmbs = here->BSIM3V1gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + cdreq = model->BSIM3V1type * (cdrain - here->BSIM3V1gds * vds + - Gm * vgs - Gmbs * vbs); + ceqbs = -here->BSIM3V1csub; + ceqbd = 0.0; + + gbspsp = -here->BSIM3V1gbds - here->BSIM3V1gbgs - here->BSIM3V1gbbs; + gbbdp = -here->BSIM3V1gbds; + gbbsp = here->BSIM3V1gbds + here->BSIM3V1gbgs + here->BSIM3V1gbbs; + gbspg = here->BSIM3V1gbgs; + gbspb = here->BSIM3V1gbbs; + gbspdp = here->BSIM3V1gbds; + gbdpdp = 0.0; + gbdpg = 0.0; + gbdpb = 0.0; + gbdpsp = 0.0; + } + else + { Gm = -here->BSIM3V1gm; + Gmbs = -here->BSIM3V1gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + cdreq = -model->BSIM3V1type * (cdrain + here->BSIM3V1gds * vds + + Gm * vgd + Gmbs * vbd); + ceqbs = 0.0; + ceqbd = -here->BSIM3V1csub; + + gbspsp = 0.0; + gbbdp = here->BSIM3V1gbds + here->BSIM3V1gbgs + here->BSIM3V1gbbs; + gbbsp = -here->BSIM3V1gbds; + gbspg = 0.0; + gbspb = 0.0; + gbspdp = 0.0; + gbdpdp = -here->BSIM3V1gbds - here->BSIM3V1gbgs - here->BSIM3V1gbbs; + gbdpg = here->BSIM3V1gbgs; + gbdpb = here->BSIM3V1gbbs; + gbdpsp = here->BSIM3V1gbds; + } + + if (model->BSIM3V1type > 0) + { ceqbs += (here->BSIM3V1cbs - (here->BSIM3V1gbs - ckt->CKTgmin) * vbs); + ceqbd += (here->BSIM3V1cbd - (here->BSIM3V1gbd - ckt->CKTgmin) * vbd); + ceqqg = ceqqg; + ceqqb = ceqqb; + ceqqd = ceqqd; + cqcheq = cqcheq; + } + else + { ceqbs = -ceqbs - (here->BSIM3V1cbs - (here->BSIM3V1gbs + - ckt->CKTgmin) * vbs); + ceqbd = -ceqbd - (here->BSIM3V1cbd - (here->BSIM3V1gbd + - ckt->CKTgmin) * vbd); + ceqqg = -ceqqg; + ceqqb = -ceqqb; + ceqqd = -ceqqd; + cqcheq = -cqcheq; + } + + (*(ckt->CKTrhs + here->BSIM3V1gNode) -= ceqqg); + (*(ckt->CKTrhs + here->BSIM3V1bNode) -=(ceqbs + ceqbd + ceqqb)); + (*(ckt->CKTrhs + here->BSIM3V1dNodePrime) += (ceqbd - cdreq - ceqqd)); + (*(ckt->CKTrhs + here->BSIM3V1sNodePrime) += (cdreq + ceqbs + ceqqg + + ceqqb + ceqqd)); + + *(ckt->CKTrhs + here->BSIM3V1qNode) += (cqcheq - cqdef); + + /* + * load y matrix + */ + + (*(here->BSIM3V1DdPtr) += here->BSIM3V1drainConductance); + (*(here->BSIM3V1GgPtr) += gcggb - here->BSIM3V1gtg); + (*(here->BSIM3V1SsPtr) += here->BSIM3V1sourceConductance); + (*(here->BSIM3V1BbPtr) += (here->BSIM3V1gbd + here->BSIM3V1gbs + - gcbgb - gcbdb - gcbsb) - here->BSIM3V1gbbs); + (*(here->BSIM3V1DPdpPtr) += (here->BSIM3V1drainConductance + + here->BSIM3V1gds + here->BSIM3V1gbd + + RevSum + gcddb) + dxpart * here->BSIM3V1gtd + gbdpdp); + (*(here->BSIM3V1SPspPtr) += (here->BSIM3V1sourceConductance + + here->BSIM3V1gds + here->BSIM3V1gbs + + FwdSum + gcssb) + sxpart * here->BSIM3V1gts + gbspsp); + (*(here->BSIM3V1DdpPtr) -= here->BSIM3V1drainConductance); + (*(here->BSIM3V1GbPtr) -= gcggb + gcgdb + gcgsb + here->BSIM3V1gtb); + (*(here->BSIM3V1GdpPtr) += gcgdb - here->BSIM3V1gtd); + (*(here->BSIM3V1GspPtr) += gcgsb - here->BSIM3V1gts); + (*(here->BSIM3V1SspPtr) -= here->BSIM3V1sourceConductance); + (*(here->BSIM3V1BgPtr) += gcbgb - here->BSIM3V1gbgs); + (*(here->BSIM3V1BdpPtr) += gcbdb - here->BSIM3V1gbd + gbbdp); + (*(here->BSIM3V1BspPtr) += gcbsb - here->BSIM3V1gbs + gbbsp); + (*(here->BSIM3V1DPdPtr) -= here->BSIM3V1drainConductance); + (*(here->BSIM3V1DPgPtr) += (Gm + gcdgb) + dxpart * here->BSIM3V1gtg + gbdpg); + (*(here->BSIM3V1DPbPtr) -= (here->BSIM3V1gbd - Gmbs + gcdgb + gcddb + + gcdsb - dxpart * here->BSIM3V1gtb) - gbdpb); + (*(here->BSIM3V1DPspPtr) -= (here->BSIM3V1gds + FwdSum - gcdsb + - dxpart * here->BSIM3V1gts) - gbdpsp); + (*(here->BSIM3V1SPgPtr) += gcsgb - Gm + sxpart * here->BSIM3V1gtg + gbspg); + (*(here->BSIM3V1SPsPtr) -= here->BSIM3V1sourceConductance); + (*(here->BSIM3V1SPbPtr) -= (here->BSIM3V1gbs + Gmbs + gcsgb + gcsdb + + gcssb - sxpart * here->BSIM3V1gtb) - gbspb); + (*(here->BSIM3V1SPdpPtr) -= (here->BSIM3V1gds + RevSum - gcsdb + - sxpart * here->BSIM3V1gtd - here->BSIM3V1gbd) - gbspdp); + + *(here->BSIM3V1QqPtr) += (gqdef + here->BSIM3V1gtau); + + *(here->BSIM3V1DPqPtr) += (dxpart * here->BSIM3V1gtau); + *(here->BSIM3V1SPqPtr) += (sxpart * here->BSIM3V1gtau); + *(here->BSIM3V1GqPtr) -= here->BSIM3V1gtau; + + *(here->BSIM3V1QgPtr) += (-gcqgb + here->BSIM3V1gtg); + *(here->BSIM3V1QdpPtr) += (-gcqdb + here->BSIM3V1gtd); + *(here->BSIM3V1QspPtr) += (-gcqsb + here->BSIM3V1gts); + *(here->BSIM3V1QbPtr) += (-gcqbb + here->BSIM3V1gtb); + +line1000: ; + + } /* End of Mosfet Instance */ +} /* End of Model Instance */ + +return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1mask.c b/src/spicelib/devices/bsim3v1/b3v1mask.c new file mode 100644 index 000000000..76bdaa19d --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1mask.c @@ -0,0 +1,1141 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:55:50 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1mask.c +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim3v1def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V1mAsk(ckt,inst,which,value) +CKTcircuit *ckt; +GENmodel *inst; +int which; +IFvalue *value; +{ + BSIM3V1model *model = (BSIM3V1model *)inst; + switch(which) + { case BSIM3V1_MOD_MOBMOD: + value->iValue = model->BSIM3V1mobMod; + return(OK); + case BSIM3V1_MOD_PARAMCHK: + value->iValue = model->BSIM3V1paramChk; + return(OK); + case BSIM3V1_MOD_BINUNIT: + value->iValue = model->BSIM3V1binUnit; + return(OK); + case BSIM3V1_MOD_CAPMOD: + value->iValue = model->BSIM3V1capMod; + return(OK); + case BSIM3V1_MOD_NQSMOD: + value->iValue = model->BSIM3V1nqsMod; + return(OK); + case BSIM3V1_MOD_NOIMOD: + value->iValue = model->BSIM3V1noiMod; + return(OK); + case BSIM3V1_MOD_VERSION : + value->rValue = model->BSIM3V1version; + return(OK); + case BSIM3V1_MOD_TOX : + value->rValue = model->BSIM3V1tox; + return(OK); + case BSIM3V1_MOD_CDSC : + value->rValue = model->BSIM3V1cdsc; + return(OK); + case BSIM3V1_MOD_CDSCB : + value->rValue = model->BSIM3V1cdscb; + return(OK); + + case BSIM3V1_MOD_CDSCD : + value->rValue = model->BSIM3V1cdscd; + return(OK); + + case BSIM3V1_MOD_CIT : + value->rValue = model->BSIM3V1cit; + return(OK); + case BSIM3V1_MOD_NFACTOR : + value->rValue = model->BSIM3V1nfactor; + return(OK); + case BSIM3V1_MOD_XJ: + value->rValue = model->BSIM3V1xj; + return(OK); + case BSIM3V1_MOD_VSAT: + value->rValue = model->BSIM3V1vsat; + return(OK); + case BSIM3V1_MOD_AT: + value->rValue = model->BSIM3V1at; + return(OK); + case BSIM3V1_MOD_A0: + value->rValue = model->BSIM3V1a0; + return(OK); + + case BSIM3V1_MOD_AGS: + value->rValue = model->BSIM3V1ags; + return(OK); + + case BSIM3V1_MOD_A1: + value->rValue = model->BSIM3V1a1; + return(OK); + case BSIM3V1_MOD_A2: + value->rValue = model->BSIM3V1a2; + return(OK); + case BSIM3V1_MOD_KETA: + value->rValue = model->BSIM3V1keta; + return(OK); + case BSIM3V1_MOD_NSUB: + value->rValue = model->BSIM3V1nsub; + return(OK); + case BSIM3V1_MOD_NPEAK: + value->rValue = model->BSIM3V1npeak; + return(OK); + case BSIM3V1_MOD_NGATE: + value->rValue = model->BSIM3V1ngate; + return(OK); + case BSIM3V1_MOD_GAMMA1: + value->rValue = model->BSIM3V1gamma1; + return(OK); + case BSIM3V1_MOD_GAMMA2: + value->rValue = model->BSIM3V1gamma2; + return(OK); + case BSIM3V1_MOD_VBX: + value->rValue = model->BSIM3V1vbx; + return(OK); + case BSIM3V1_MOD_VBM: + value->rValue = model->BSIM3V1vbm; + return(OK); + case BSIM3V1_MOD_XT: + value->rValue = model->BSIM3V1xt; + return(OK); + case BSIM3V1_MOD_K1: + value->rValue = model->BSIM3V1k1; + return(OK); + case BSIM3V1_MOD_KT1: + value->rValue = model->BSIM3V1kt1; + return(OK); + case BSIM3V1_MOD_KT1L: + value->rValue = model->BSIM3V1kt1l; + return(OK); + case BSIM3V1_MOD_KT2 : + value->rValue = model->BSIM3V1kt2; + return(OK); + case BSIM3V1_MOD_K2 : + value->rValue = model->BSIM3V1k2; + return(OK); + case BSIM3V1_MOD_K3: + value->rValue = model->BSIM3V1k3; + return(OK); + case BSIM3V1_MOD_K3B: + value->rValue = model->BSIM3V1k3b; + return(OK); + case BSIM3V1_MOD_W0: + value->rValue = model->BSIM3V1w0; + return(OK); + case BSIM3V1_MOD_NLX: + value->rValue = model->BSIM3V1nlx; + return(OK); + case BSIM3V1_MOD_DVT0 : + value->rValue = model->BSIM3V1dvt0; + return(OK); + case BSIM3V1_MOD_DVT1 : + value->rValue = model->BSIM3V1dvt1; + return(OK); + case BSIM3V1_MOD_DVT2 : + value->rValue = model->BSIM3V1dvt2; + return(OK); + case BSIM3V1_MOD_DVT0W : + value->rValue = model->BSIM3V1dvt0w; + return(OK); + case BSIM3V1_MOD_DVT1W : + value->rValue = model->BSIM3V1dvt1w; + return(OK); + case BSIM3V1_MOD_DVT2W : + value->rValue = model->BSIM3V1dvt2w; + return(OK); + case BSIM3V1_MOD_DROUT : + value->rValue = model->BSIM3V1drout; + return(OK); + case BSIM3V1_MOD_DSUB : + value->rValue = model->BSIM3V1dsub; + return(OK); + case BSIM3V1_MOD_VTH0: + value->rValue = model->BSIM3V1vth0; + return(OK); + case BSIM3V1_MOD_UA: + value->rValue = model->BSIM3V1ua; + return(OK); + case BSIM3V1_MOD_UA1: + value->rValue = model->BSIM3V1ua1; + return(OK); + case BSIM3V1_MOD_UB: + value->rValue = model->BSIM3V1ub; + return(OK); + case BSIM3V1_MOD_UB1: + value->rValue = model->BSIM3V1ub1; + return(OK); + case BSIM3V1_MOD_UC: + value->rValue = model->BSIM3V1uc; + return(OK); + case BSIM3V1_MOD_UC1: + value->rValue = model->BSIM3V1uc1; + return(OK); + case BSIM3V1_MOD_U0: + value->rValue = model->BSIM3V1u0; + return(OK); + case BSIM3V1_MOD_UTE: + value->rValue = model->BSIM3V1ute; + return(OK); + case BSIM3V1_MOD_VOFF: + value->rValue = model->BSIM3V1voff; + return(OK); + case BSIM3V1_MOD_DELTA: + value->rValue = model->BSIM3V1delta; + return(OK); + case BSIM3V1_MOD_RDSW: + value->rValue = model->BSIM3V1rdsw; + return(OK); + case BSIM3V1_MOD_PRWG: + value->rValue = model->BSIM3V1prwg; + return(OK); + case BSIM3V1_MOD_PRWB: + value->rValue = model->BSIM3V1prwb; + return(OK); + case BSIM3V1_MOD_PRT: + value->rValue = model->BSIM3V1prt; + return(OK); + case BSIM3V1_MOD_ETA0: + value->rValue = model->BSIM3V1eta0; + return(OK); + case BSIM3V1_MOD_ETAB: + value->rValue = model->BSIM3V1etab; + return(OK); + case BSIM3V1_MOD_PCLM: + value->rValue = model->BSIM3V1pclm; + return(OK); + case BSIM3V1_MOD_PDIBL1: + value->rValue = model->BSIM3V1pdibl1; + return(OK); + case BSIM3V1_MOD_PDIBL2: + value->rValue = model->BSIM3V1pdibl2; + return(OK); + case BSIM3V1_MOD_PDIBLB: + value->rValue = model->BSIM3V1pdiblb; + return(OK); + case BSIM3V1_MOD_PSCBE1: + value->rValue = model->BSIM3V1pscbe1; + return(OK); + case BSIM3V1_MOD_PSCBE2: + value->rValue = model->BSIM3V1pscbe2; + return(OK); + case BSIM3V1_MOD_PVAG: + value->rValue = model->BSIM3V1pvag; + return(OK); + case BSIM3V1_MOD_WR: + value->rValue = model->BSIM3V1wr; + return(OK); + case BSIM3V1_MOD_DWG: + value->rValue = model->BSIM3V1dwg; + return(OK); + case BSIM3V1_MOD_DWB: + value->rValue = model->BSIM3V1dwb; + return(OK); + case BSIM3V1_MOD_B0: + value->rValue = model->BSIM3V1b0; + return(OK); + case BSIM3V1_MOD_B1: + value->rValue = model->BSIM3V1b1; + return(OK); + case BSIM3V1_MOD_ALPHA0: + value->rValue = model->BSIM3V1alpha0; + return(OK); + case BSIM3V1_MOD_BETA0: + value->rValue = model->BSIM3V1beta0; + return(OK); + + case BSIM3V1_MOD_ELM: + value->rValue = model->BSIM3V1elm; + return(OK); + case BSIM3V1_MOD_CGSL: + value->rValue = model->BSIM3V1cgsl; + return(OK); + case BSIM3V1_MOD_CGDL: + value->rValue = model->BSIM3V1cgdl; + return(OK); + case BSIM3V1_MOD_CKAPPA: + value->rValue = model->BSIM3V1ckappa; + return(OK); + case BSIM3V1_MOD_CF: + value->rValue = model->BSIM3V1cf; + return(OK); + case BSIM3V1_MOD_CLC: + value->rValue = model->BSIM3V1clc; + return(OK); + case BSIM3V1_MOD_CLE: + value->rValue = model->BSIM3V1cle; + return(OK); + case BSIM3V1_MOD_DWC: + value->rValue = model->BSIM3V1dwc; + return(OK); + case BSIM3V1_MOD_DLC: + value->rValue = model->BSIM3V1dlc; + return(OK); + case BSIM3V1_MOD_VFBCV: + value->rValue = model->BSIM3V1vfbcv; + return(OK); + + /* Length dependence */ + case BSIM3V1_MOD_LCDSC : + value->rValue = model->BSIM3V1lcdsc; + return(OK); + case BSIM3V1_MOD_LCDSCB : + value->rValue = model->BSIM3V1lcdscb; + return(OK); + case BSIM3V1_MOD_LCDSCD : + value->rValue = model->BSIM3V1lcdscd; + return(OK); + case BSIM3V1_MOD_LCIT : + value->rValue = model->BSIM3V1lcit; + return(OK); + case BSIM3V1_MOD_LNFACTOR : + value->rValue = model->BSIM3V1lnfactor; + return(OK); + case BSIM3V1_MOD_LXJ: + value->rValue = model->BSIM3V1lxj; + return(OK); + case BSIM3V1_MOD_LVSAT: + value->rValue = model->BSIM3V1lvsat; + return(OK); + case BSIM3V1_MOD_LAT: + value->rValue = model->BSIM3V1lat; + return(OK); + case BSIM3V1_MOD_LA0: + value->rValue = model->BSIM3V1la0; + return(OK); + case BSIM3V1_MOD_LAGS: + value->rValue = model->BSIM3V1lags; + return(OK); + case BSIM3V1_MOD_LA1: + value->rValue = model->BSIM3V1la1; + return(OK); + case BSIM3V1_MOD_LA2: + value->rValue = model->BSIM3V1la2; + return(OK); + case BSIM3V1_MOD_LKETA: + value->rValue = model->BSIM3V1lketa; + return(OK); + case BSIM3V1_MOD_LNSUB: + value->rValue = model->BSIM3V1lnsub; + return(OK); + case BSIM3V1_MOD_LNPEAK: + value->rValue = model->BSIM3V1lnpeak; + return(OK); + case BSIM3V1_MOD_LNGATE: + value->rValue = model->BSIM3V1lngate; + return(OK); + case BSIM3V1_MOD_LGAMMA1: + value->rValue = model->BSIM3V1lgamma1; + return(OK); + case BSIM3V1_MOD_LGAMMA2: + value->rValue = model->BSIM3V1lgamma2; + return(OK); + case BSIM3V1_MOD_LVBX: + value->rValue = model->BSIM3V1lvbx; + return(OK); + case BSIM3V1_MOD_LVBM: + value->rValue = model->BSIM3V1lvbm; + return(OK); + case BSIM3V1_MOD_LXT: + value->rValue = model->BSIM3V1lxt; + return(OK); + case BSIM3V1_MOD_LK1: + value->rValue = model->BSIM3V1lk1; + return(OK); + case BSIM3V1_MOD_LKT1: + value->rValue = model->BSIM3V1lkt1; + return(OK); + case BSIM3V1_MOD_LKT1L: + value->rValue = model->BSIM3V1lkt1l; + return(OK); + case BSIM3V1_MOD_LKT2 : + value->rValue = model->BSIM3V1lkt2; + return(OK); + case BSIM3V1_MOD_LK2 : + value->rValue = model->BSIM3V1lk2; + return(OK); + case BSIM3V1_MOD_LK3: + value->rValue = model->BSIM3V1lk3; + return(OK); + case BSIM3V1_MOD_LK3B: + value->rValue = model->BSIM3V1lk3b; + return(OK); + case BSIM3V1_MOD_LW0: + value->rValue = model->BSIM3V1lw0; + return(OK); + case BSIM3V1_MOD_LNLX: + value->rValue = model->BSIM3V1lnlx; + return(OK); + case BSIM3V1_MOD_LDVT0: + value->rValue = model->BSIM3V1ldvt0; + return(OK); + case BSIM3V1_MOD_LDVT1 : + value->rValue = model->BSIM3V1ldvt1; + return(OK); + case BSIM3V1_MOD_LDVT2 : + value->rValue = model->BSIM3V1ldvt2; + return(OK); + case BSIM3V1_MOD_LDVT0W : + value->rValue = model->BSIM3V1ldvt0w; + return(OK); + case BSIM3V1_MOD_LDVT1W : + value->rValue = model->BSIM3V1ldvt1w; + return(OK); + case BSIM3V1_MOD_LDVT2W : + value->rValue = model->BSIM3V1ldvt2w; + return(OK); + case BSIM3V1_MOD_LDROUT : + value->rValue = model->BSIM3V1ldrout; + return(OK); + case BSIM3V1_MOD_LDSUB : + value->rValue = model->BSIM3V1ldsub; + return(OK); + case BSIM3V1_MOD_LVTH0: + value->rValue = model->BSIM3V1lvth0; + return(OK); + case BSIM3V1_MOD_LUA: + value->rValue = model->BSIM3V1lua; + return(OK); + case BSIM3V1_MOD_LUA1: + value->rValue = model->BSIM3V1lua1; + return(OK); + case BSIM3V1_MOD_LUB: + value->rValue = model->BSIM3V1lub; + return(OK); + case BSIM3V1_MOD_LUB1: + value->rValue = model->BSIM3V1lub1; + return(OK); + case BSIM3V1_MOD_LUC: + value->rValue = model->BSIM3V1luc; + return(OK); + case BSIM3V1_MOD_LUC1: + value->rValue = model->BSIM3V1luc1; + return(OK); + case BSIM3V1_MOD_LU0: + value->rValue = model->BSIM3V1lu0; + return(OK); + case BSIM3V1_MOD_LUTE: + value->rValue = model->BSIM3V1lute; + return(OK); + case BSIM3V1_MOD_LVOFF: + value->rValue = model->BSIM3V1lvoff; + return(OK); + case BSIM3V1_MOD_LDELTA: + value->rValue = model->BSIM3V1ldelta; + return(OK); + case BSIM3V1_MOD_LRDSW: + value->rValue = model->BSIM3V1lrdsw; + return(OK); + case BSIM3V1_MOD_LPRWB: + value->rValue = model->BSIM3V1lprwb; + return(OK); + case BSIM3V1_MOD_LPRWG: + value->rValue = model->BSIM3V1lprwg; + return(OK); + case BSIM3V1_MOD_LPRT: + value->rValue = model->BSIM3V1lprt; + return(OK); + case BSIM3V1_MOD_LETA0: + value->rValue = model->BSIM3V1leta0; + return(OK); + case BSIM3V1_MOD_LETAB: + value->rValue = model->BSIM3V1letab; + return(OK); + case BSIM3V1_MOD_LPCLM: + value->rValue = model->BSIM3V1lpclm; + return(OK); + case BSIM3V1_MOD_LPDIBL1: + value->rValue = model->BSIM3V1lpdibl1; + return(OK); + case BSIM3V1_MOD_LPDIBL2: + value->rValue = model->BSIM3V1lpdibl2; + return(OK); + case BSIM3V1_MOD_LPDIBLB: + value->rValue = model->BSIM3V1lpdiblb; + return(OK); + case BSIM3V1_MOD_LPSCBE1: + value->rValue = model->BSIM3V1lpscbe1; + return(OK); + case BSIM3V1_MOD_LPSCBE2: + value->rValue = model->BSIM3V1lpscbe2; + return(OK); + case BSIM3V1_MOD_LPVAG: + value->rValue = model->BSIM3V1lpvag; + return(OK); + case BSIM3V1_MOD_LWR: + value->rValue = model->BSIM3V1lwr; + return(OK); + case BSIM3V1_MOD_LDWG: + value->rValue = model->BSIM3V1ldwg; + return(OK); + case BSIM3V1_MOD_LDWB: + value->rValue = model->BSIM3V1ldwb; + return(OK); + case BSIM3V1_MOD_LB0: + value->rValue = model->BSIM3V1lb0; + return(OK); + case BSIM3V1_MOD_LB1: + value->rValue = model->BSIM3V1lb1; + return(OK); + case BSIM3V1_MOD_LALPHA0: + value->rValue = model->BSIM3V1lalpha0; + return(OK); + case BSIM3V1_MOD_LBETA0: + value->rValue = model->BSIM3V1lbeta0; + return(OK); + + case BSIM3V1_MOD_LELM: + value->rValue = model->BSIM3V1lelm; + return(OK); + case BSIM3V1_MOD_LCGSL: + value->rValue = model->BSIM3V1lcgsl; + return(OK); + case BSIM3V1_MOD_LCGDL: + value->rValue = model->BSIM3V1lcgdl; + return(OK); + case BSIM3V1_MOD_LCKAPPA: + value->rValue = model->BSIM3V1lckappa; + return(OK); + case BSIM3V1_MOD_LCF: + value->rValue = model->BSIM3V1lcf; + return(OK); + case BSIM3V1_MOD_LCLC: + value->rValue = model->BSIM3V1lclc; + return(OK); + case BSIM3V1_MOD_LCLE: + value->rValue = model->BSIM3V1lcle; + return(OK); + case BSIM3V1_MOD_LVFBCV: + value->rValue = model->BSIM3V1lvfbcv; + return(OK); + + /* Width dependence */ + case BSIM3V1_MOD_WCDSC : + value->rValue = model->BSIM3V1wcdsc; + return(OK); + case BSIM3V1_MOD_WCDSCB : + value->rValue = model->BSIM3V1wcdscb; + return(OK); + case BSIM3V1_MOD_WCDSCD : + value->rValue = model->BSIM3V1wcdscd; + return(OK); + case BSIM3V1_MOD_WCIT : + value->rValue = model->BSIM3V1wcit; + return(OK); + case BSIM3V1_MOD_WNFACTOR : + value->rValue = model->BSIM3V1wnfactor; + return(OK); + case BSIM3V1_MOD_WXJ: + value->rValue = model->BSIM3V1wxj; + return(OK); + case BSIM3V1_MOD_WVSAT: + value->rValue = model->BSIM3V1wvsat; + return(OK); + case BSIM3V1_MOD_WAT: + value->rValue = model->BSIM3V1wat; + return(OK); + case BSIM3V1_MOD_WA0: + value->rValue = model->BSIM3V1wa0; + return(OK); + case BSIM3V1_MOD_WAGS: + value->rValue = model->BSIM3V1wags; + return(OK); + case BSIM3V1_MOD_WA1: + value->rValue = model->BSIM3V1wa1; + return(OK); + case BSIM3V1_MOD_WA2: + value->rValue = model->BSIM3V1wa2; + return(OK); + case BSIM3V1_MOD_WKETA: + value->rValue = model->BSIM3V1wketa; + return(OK); + case BSIM3V1_MOD_WNSUB: + value->rValue = model->BSIM3V1wnsub; + return(OK); + case BSIM3V1_MOD_WNPEAK: + value->rValue = model->BSIM3V1wnpeak; + return(OK); + case BSIM3V1_MOD_WNGATE: + value->rValue = model->BSIM3V1wngate; + return(OK); + case BSIM3V1_MOD_WGAMMA1: + value->rValue = model->BSIM3V1wgamma1; + return(OK); + case BSIM3V1_MOD_WGAMMA2: + value->rValue = model->BSIM3V1wgamma2; + return(OK); + case BSIM3V1_MOD_WVBX: + value->rValue = model->BSIM3V1wvbx; + return(OK); + case BSIM3V1_MOD_WVBM: + value->rValue = model->BSIM3V1wvbm; + return(OK); + case BSIM3V1_MOD_WXT: + value->rValue = model->BSIM3V1wxt; + return(OK); + case BSIM3V1_MOD_WK1: + value->rValue = model->BSIM3V1wk1; + return(OK); + case BSIM3V1_MOD_WKT1: + value->rValue = model->BSIM3V1wkt1; + return(OK); + case BSIM3V1_MOD_WKT1L: + value->rValue = model->BSIM3V1wkt1l; + return(OK); + case BSIM3V1_MOD_WKT2 : + value->rValue = model->BSIM3V1wkt2; + return(OK); + case BSIM3V1_MOD_WK2 : + value->rValue = model->BSIM3V1wk2; + return(OK); + case BSIM3V1_MOD_WK3: + value->rValue = model->BSIM3V1wk3; + return(OK); + case BSIM3V1_MOD_WK3B: + value->rValue = model->BSIM3V1wk3b; + return(OK); + case BSIM3V1_MOD_WW0: + value->rValue = model->BSIM3V1ww0; + return(OK); + case BSIM3V1_MOD_WNLX: + value->rValue = model->BSIM3V1wnlx; + return(OK); + case BSIM3V1_MOD_WDVT0: + value->rValue = model->BSIM3V1wdvt0; + return(OK); + case BSIM3V1_MOD_WDVT1 : + value->rValue = model->BSIM3V1wdvt1; + return(OK); + case BSIM3V1_MOD_WDVT2 : + value->rValue = model->BSIM3V1wdvt2; + return(OK); + case BSIM3V1_MOD_WDVT0W : + value->rValue = model->BSIM3V1wdvt0w; + return(OK); + case BSIM3V1_MOD_WDVT1W : + value->rValue = model->BSIM3V1wdvt1w; + return(OK); + case BSIM3V1_MOD_WDVT2W : + value->rValue = model->BSIM3V1wdvt2w; + return(OK); + case BSIM3V1_MOD_WDROUT : + value->rValue = model->BSIM3V1wdrout; + return(OK); + case BSIM3V1_MOD_WDSUB : + value->rValue = model->BSIM3V1wdsub; + return(OK); + case BSIM3V1_MOD_WVTH0: + value->rValue = model->BSIM3V1wvth0; + return(OK); + case BSIM3V1_MOD_WUA: + value->rValue = model->BSIM3V1wua; + return(OK); + case BSIM3V1_MOD_WUA1: + value->rValue = model->BSIM3V1wua1; + return(OK); + case BSIM3V1_MOD_WUB: + value->rValue = model->BSIM3V1wub; + return(OK); + case BSIM3V1_MOD_WUB1: + value->rValue = model->BSIM3V1wub1; + return(OK); + case BSIM3V1_MOD_WUC: + value->rValue = model->BSIM3V1wuc; + return(OK); + case BSIM3V1_MOD_WUC1: + value->rValue = model->BSIM3V1wuc1; + return(OK); + case BSIM3V1_MOD_WU0: + value->rValue = model->BSIM3V1wu0; + return(OK); + case BSIM3V1_MOD_WUTE: + value->rValue = model->BSIM3V1wute; + return(OK); + case BSIM3V1_MOD_WVOFF: + value->rValue = model->BSIM3V1wvoff; + return(OK); + case BSIM3V1_MOD_WDELTA: + value->rValue = model->BSIM3V1wdelta; + return(OK); + case BSIM3V1_MOD_WRDSW: + value->rValue = model->BSIM3V1wrdsw; + return(OK); + case BSIM3V1_MOD_WPRWB: + value->rValue = model->BSIM3V1wprwb; + return(OK); + case BSIM3V1_MOD_WPRWG: + value->rValue = model->BSIM3V1wprwg; + return(OK); + case BSIM3V1_MOD_WPRT: + value->rValue = model->BSIM3V1wprt; + return(OK); + case BSIM3V1_MOD_WETA0: + value->rValue = model->BSIM3V1weta0; + return(OK); + case BSIM3V1_MOD_WETAB: + value->rValue = model->BSIM3V1wetab; + return(OK); + case BSIM3V1_MOD_WPCLM: + value->rValue = model->BSIM3V1wpclm; + return(OK); + case BSIM3V1_MOD_WPDIBL1: + value->rValue = model->BSIM3V1wpdibl1; + return(OK); + case BSIM3V1_MOD_WPDIBL2: + value->rValue = model->BSIM3V1wpdibl2; + return(OK); + case BSIM3V1_MOD_WPDIBLB: + value->rValue = model->BSIM3V1wpdiblb; + return(OK); + case BSIM3V1_MOD_WPSCBE1: + value->rValue = model->BSIM3V1wpscbe1; + return(OK); + case BSIM3V1_MOD_WPSCBE2: + value->rValue = model->BSIM3V1wpscbe2; + return(OK); + case BSIM3V1_MOD_WPVAG: + value->rValue = model->BSIM3V1wpvag; + return(OK); + case BSIM3V1_MOD_WWR: + value->rValue = model->BSIM3V1wwr; + return(OK); + case BSIM3V1_MOD_WDWG: + value->rValue = model->BSIM3V1wdwg; + return(OK); + case BSIM3V1_MOD_WDWB: + value->rValue = model->BSIM3V1wdwb; + return(OK); + case BSIM3V1_MOD_WB0: + value->rValue = model->BSIM3V1wb0; + return(OK); + case BSIM3V1_MOD_WB1: + value->rValue = model->BSIM3V1wb1; + return(OK); + case BSIM3V1_MOD_WALPHA0: + value->rValue = model->BSIM3V1walpha0; + return(OK); + case BSIM3V1_MOD_WBETA0: + value->rValue = model->BSIM3V1wbeta0; + return(OK); + + case BSIM3V1_MOD_WELM: + value->rValue = model->BSIM3V1welm; + return(OK); + case BSIM3V1_MOD_WCGSL: + value->rValue = model->BSIM3V1wcgsl; + return(OK); + case BSIM3V1_MOD_WCGDL: + value->rValue = model->BSIM3V1wcgdl; + return(OK); + case BSIM3V1_MOD_WCKAPPA: + value->rValue = model->BSIM3V1wckappa; + return(OK); + case BSIM3V1_MOD_WCF: + value->rValue = model->BSIM3V1wcf; + return(OK); + case BSIM3V1_MOD_WCLC: + value->rValue = model->BSIM3V1wclc; + return(OK); + case BSIM3V1_MOD_WCLE: + value->rValue = model->BSIM3V1wcle; + return(OK); + case BSIM3V1_MOD_WVFBCV: + value->rValue = model->BSIM3V1wvfbcv; + return(OK); + + /* Cross-term dependence */ + case BSIM3V1_MOD_PCDSC : + value->rValue = model->BSIM3V1pcdsc; + return(OK); + case BSIM3V1_MOD_PCDSCB : + value->rValue = model->BSIM3V1pcdscb; + return(OK); + case BSIM3V1_MOD_PCDSCD : + value->rValue = model->BSIM3V1pcdscd; + return(OK); + case BSIM3V1_MOD_PCIT : + value->rValue = model->BSIM3V1pcit; + return(OK); + case BSIM3V1_MOD_PNFACTOR : + value->rValue = model->BSIM3V1pnfactor; + return(OK); + case BSIM3V1_MOD_PXJ: + value->rValue = model->BSIM3V1pxj; + return(OK); + case BSIM3V1_MOD_PVSAT: + value->rValue = model->BSIM3V1pvsat; + return(OK); + case BSIM3V1_MOD_PAT: + value->rValue = model->BSIM3V1pat; + return(OK); + case BSIM3V1_MOD_PA0: + value->rValue = model->BSIM3V1pa0; + return(OK); + case BSIM3V1_MOD_PAGS: + value->rValue = model->BSIM3V1pags; + return(OK); + case BSIM3V1_MOD_PA1: + value->rValue = model->BSIM3V1pa1; + return(OK); + case BSIM3V1_MOD_PA2: + value->rValue = model->BSIM3V1pa2; + return(OK); + case BSIM3V1_MOD_PKETA: + value->rValue = model->BSIM3V1pketa; + return(OK); + case BSIM3V1_MOD_PNSUB: + value->rValue = model->BSIM3V1pnsub; + return(OK); + case BSIM3V1_MOD_PNPEAK: + value->rValue = model->BSIM3V1pnpeak; + return(OK); + case BSIM3V1_MOD_PNGATE: + value->rValue = model->BSIM3V1pngate; + return(OK); + case BSIM3V1_MOD_PGAMMA1: + value->rValue = model->BSIM3V1pgamma1; + return(OK); + case BSIM3V1_MOD_PGAMMA2: + value->rValue = model->BSIM3V1pgamma2; + return(OK); + case BSIM3V1_MOD_PVBX: + value->rValue = model->BSIM3V1pvbx; + return(OK); + case BSIM3V1_MOD_PVBM: + value->rValue = model->BSIM3V1pvbm; + return(OK); + case BSIM3V1_MOD_PXT: + value->rValue = model->BSIM3V1pxt; + return(OK); + case BSIM3V1_MOD_PK1: + value->rValue = model->BSIM3V1pk1; + return(OK); + case BSIM3V1_MOD_PKT1: + value->rValue = model->BSIM3V1pkt1; + return(OK); + case BSIM3V1_MOD_PKT1L: + value->rValue = model->BSIM3V1pkt1l; + return(OK); + case BSIM3V1_MOD_PKT2 : + value->rValue = model->BSIM3V1pkt2; + return(OK); + case BSIM3V1_MOD_PK2 : + value->rValue = model->BSIM3V1pk2; + return(OK); + case BSIM3V1_MOD_PK3: + value->rValue = model->BSIM3V1pk3; + return(OK); + case BSIM3V1_MOD_PK3B: + value->rValue = model->BSIM3V1pk3b; + return(OK); + case BSIM3V1_MOD_PW0: + value->rValue = model->BSIM3V1pw0; + return(OK); + case BSIM3V1_MOD_PNLX: + value->rValue = model->BSIM3V1pnlx; + return(OK); + case BSIM3V1_MOD_PDVT0 : + value->rValue = model->BSIM3V1pdvt0; + return(OK); + case BSIM3V1_MOD_PDVT1 : + value->rValue = model->BSIM3V1pdvt1; + return(OK); + case BSIM3V1_MOD_PDVT2 : + value->rValue = model->BSIM3V1pdvt2; + return(OK); + case BSIM3V1_MOD_PDVT0W : + value->rValue = model->BSIM3V1pdvt0w; + return(OK); + case BSIM3V1_MOD_PDVT1W : + value->rValue = model->BSIM3V1pdvt1w; + return(OK); + case BSIM3V1_MOD_PDVT2W : + value->rValue = model->BSIM3V1pdvt2w; + return(OK); + case BSIM3V1_MOD_PDROUT : + value->rValue = model->BSIM3V1pdrout; + return(OK); + case BSIM3V1_MOD_PDSUB : + value->rValue = model->BSIM3V1pdsub; + return(OK); + case BSIM3V1_MOD_PVTH0: + value->rValue = model->BSIM3V1pvth0; + return(OK); + case BSIM3V1_MOD_PUA: + value->rValue = model->BSIM3V1pua; + return(OK); + case BSIM3V1_MOD_PUA1: + value->rValue = model->BSIM3V1pua1; + return(OK); + case BSIM3V1_MOD_PUB: + value->rValue = model->BSIM3V1pub; + return(OK); + case BSIM3V1_MOD_PUB1: + value->rValue = model->BSIM3V1pub1; + return(OK); + case BSIM3V1_MOD_PUC: + value->rValue = model->BSIM3V1puc; + return(OK); + case BSIM3V1_MOD_PUC1: + value->rValue = model->BSIM3V1puc1; + return(OK); + case BSIM3V1_MOD_PU0: + value->rValue = model->BSIM3V1pu0; + return(OK); + case BSIM3V1_MOD_PUTE: + value->rValue = model->BSIM3V1pute; + return(OK); + case BSIM3V1_MOD_PVOFF: + value->rValue = model->BSIM3V1pvoff; + return(OK); + case BSIM3V1_MOD_PDELTA: + value->rValue = model->BSIM3V1pdelta; + return(OK); + case BSIM3V1_MOD_PRDSW: + value->rValue = model->BSIM3V1prdsw; + return(OK); + case BSIM3V1_MOD_PPRWB: + value->rValue = model->BSIM3V1pprwb; + return(OK); + case BSIM3V1_MOD_PPRWG: + value->rValue = model->BSIM3V1pprwg; + return(OK); + case BSIM3V1_MOD_PPRT: + value->rValue = model->BSIM3V1pprt; + return(OK); + case BSIM3V1_MOD_PETA0: + value->rValue = model->BSIM3V1peta0; + return(OK); + case BSIM3V1_MOD_PETAB: + value->rValue = model->BSIM3V1petab; + return(OK); + case BSIM3V1_MOD_PPCLM: + value->rValue = model->BSIM3V1ppclm; + return(OK); + case BSIM3V1_MOD_PPDIBL1: + value->rValue = model->BSIM3V1ppdibl1; + return(OK); + case BSIM3V1_MOD_PPDIBL2: + value->rValue = model->BSIM3V1ppdibl2; + return(OK); + case BSIM3V1_MOD_PPDIBLB: + value->rValue = model->BSIM3V1ppdiblb; + return(OK); + case BSIM3V1_MOD_PPSCBE1: + value->rValue = model->BSIM3V1ppscbe1; + return(OK); + case BSIM3V1_MOD_PPSCBE2: + value->rValue = model->BSIM3V1ppscbe2; + return(OK); + case BSIM3V1_MOD_PPVAG: + value->rValue = model->BSIM3V1ppvag; + return(OK); + case BSIM3V1_MOD_PWR: + value->rValue = model->BSIM3V1pwr; + return(OK); + case BSIM3V1_MOD_PDWG: + value->rValue = model->BSIM3V1pdwg; + return(OK); + case BSIM3V1_MOD_PDWB: + value->rValue = model->BSIM3V1pdwb; + return(OK); + case BSIM3V1_MOD_PB0: + value->rValue = model->BSIM3V1pb0; + return(OK); + case BSIM3V1_MOD_PB1: + value->rValue = model->BSIM3V1pb1; + return(OK); + case BSIM3V1_MOD_PALPHA0: + value->rValue = model->BSIM3V1palpha0; + return(OK); + case BSIM3V1_MOD_PBETA0: + value->rValue = model->BSIM3V1pbeta0; + return(OK); + + case BSIM3V1_MOD_PELM: + value->rValue = model->BSIM3V1pelm; + return(OK); + case BSIM3V1_MOD_PCGSL: + value->rValue = model->BSIM3V1pcgsl; + return(OK); + case BSIM3V1_MOD_PCGDL: + value->rValue = model->BSIM3V1pcgdl; + return(OK); + case BSIM3V1_MOD_PCKAPPA: + value->rValue = model->BSIM3V1pckappa; + return(OK); + case BSIM3V1_MOD_PCF: + value->rValue = model->BSIM3V1pcf; + return(OK); + case BSIM3V1_MOD_PCLC: + value->rValue = model->BSIM3V1pclc; + return(OK); + case BSIM3V1_MOD_PCLE: + value->rValue = model->BSIM3V1pcle; + return(OK); + case BSIM3V1_MOD_PVFBCV: + value->rValue = model->BSIM3V1pvfbcv; + return(OK); + + case BSIM3V1_MOD_TNOM : + value->rValue = model->BSIM3V1tnom; + return(OK); + case BSIM3V1_MOD_CGSO: + value->rValue = model->BSIM3V1cgso; + return(OK); + case BSIM3V1_MOD_CGDO: + value->rValue = model->BSIM3V1cgdo; + return(OK); + case BSIM3V1_MOD_CGBO: + value->rValue = model->BSIM3V1cgbo; + return(OK); + case BSIM3V1_MOD_XPART: + value->rValue = model->BSIM3V1xpart; + return(OK); + case BSIM3V1_MOD_RSH: + value->rValue = model->BSIM3V1sheetResistance; + return(OK); + case BSIM3V1_MOD_JS: + value->rValue = model->BSIM3V1jctSatCurDensity; + return(OK); + case BSIM3V1_MOD_JSW: + value->rValue = model->BSIM3V1jctSidewallSatCurDensity; + return(OK); + case BSIM3V1_MOD_PB: + value->rValue = model->BSIM3V1bulkJctPotential; + return(OK); + case BSIM3V1_MOD_MJ: + value->rValue = model->BSIM3V1bulkJctBotGradingCoeff; + return(OK); + case BSIM3V1_MOD_PBSW: + value->rValue = model->BSIM3V1sidewallJctPotential; + return(OK); + case BSIM3V1_MOD_MJSW: + value->rValue = model->BSIM3V1bulkJctSideGradingCoeff; + return(OK); + case BSIM3V1_MOD_CJ: + value->rValue = model->BSIM3V1unitAreaJctCap; + return(OK); + case BSIM3V1_MOD_CJSW: + value->rValue = model->BSIM3V1unitLengthSidewallJctCap; + return(OK); + case BSIM3V1_MOD_PBSWG: + value->rValue = model->BSIM3V1GatesidewallJctPotential; + return(OK); + case BSIM3V1_MOD_MJSWG: + value->rValue = model->BSIM3V1bulkJctGateSideGradingCoeff; + return(OK); + case BSIM3V1_MOD_CJSWG: + value->rValue = model->BSIM3V1unitLengthGateSidewallJctCap; + return(OK); + case BSIM3V1_MOD_NJ: + value->rValue = model->BSIM3V1jctEmissionCoeff; + return(OK); + case BSIM3V1_MOD_XTI: + value->rValue = model->BSIM3V1jctTempExponent; + return(OK); + case BSIM3V1_MOD_LINT: + value->rValue = model->BSIM3V1Lint; + return(OK); + case BSIM3V1_MOD_LL: + value->rValue = model->BSIM3V1Ll; + return(OK); + case BSIM3V1_MOD_LLN: + value->rValue = model->BSIM3V1Lln; + return(OK); + case BSIM3V1_MOD_LW: + value->rValue = model->BSIM3V1Lw; + return(OK); + case BSIM3V1_MOD_LWN: + value->rValue = model->BSIM3V1Lwn; + return(OK); + case BSIM3V1_MOD_LWL: + value->rValue = model->BSIM3V1Lwl; + return(OK); + case BSIM3V1_MOD_LMIN: + value->rValue = model->BSIM3V1Lmin; + return(OK); + case BSIM3V1_MOD_LMAX: + value->rValue = model->BSIM3V1Lmax; + return(OK); + case BSIM3V1_MOD_WINT: + value->rValue = model->BSIM3V1Wint; + return(OK); + case BSIM3V1_MOD_WL: + value->rValue = model->BSIM3V1Wl; + return(OK); + case BSIM3V1_MOD_WLN: + value->rValue = model->BSIM3V1Wln; + return(OK); + case BSIM3V1_MOD_WW: + value->rValue = model->BSIM3V1Ww; + return(OK); + case BSIM3V1_MOD_WWN: + value->rValue = model->BSIM3V1Wwn; + return(OK); + case BSIM3V1_MOD_WWL: + value->rValue = model->BSIM3V1Wwl; + return(OK); + case BSIM3V1_MOD_WMIN: + value->rValue = model->BSIM3V1Wmin; + return(OK); + case BSIM3V1_MOD_WMAX: + value->rValue = model->BSIM3V1Wmax; + return(OK); + case BSIM3V1_MOD_NOIA: + value->rValue = model->BSIM3V1oxideTrapDensityA; + return(OK); + case BSIM3V1_MOD_NOIB: + value->rValue = model->BSIM3V1oxideTrapDensityB; + return(OK); + case BSIM3V1_MOD_NOIC: + value->rValue = model->BSIM3V1oxideTrapDensityC; + return(OK); + case BSIM3V1_MOD_EM: + value->rValue = model->BSIM3V1em; + return(OK); + case BSIM3V1_MOD_EF: + value->rValue = model->BSIM3V1ef; + return(OK); + case BSIM3V1_MOD_AF: + value->rValue = model->BSIM3V1af; + return(OK); + case BSIM3V1_MOD_KF: + value->rValue = model->BSIM3V1kf; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1mdel.c b/src/spicelib/devices/bsim3v1/b3v1mdel.c new file mode 100644 index 000000000..94a8b1bb7 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1mdel.c @@ -0,0 +1,60 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:56:18 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1mdel.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3v1def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V1mDelete(inModel,modname,kill) +GENmodel **inModel; +IFuid modname; +GENmodel *kill; +{ +BSIM3V1model **model = (BSIM3V1model**)inModel; +BSIM3V1model *modfast = (BSIM3V1model*)kill; +BSIM3V1instance *here; +BSIM3V1instance *prev = NULL; +BSIM3V1model **oldmod; + + oldmod = model; + for (; *model ; model = &((*model)->BSIM3V1nextModel)) + { if ((*model)->BSIM3V1modName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->BSIM3V1nextModel; /* cut deleted device out of list */ + for (here = (*model)->BSIM3V1instances; here; here = here->BSIM3V1nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1mpar.c b/src/spicelib/devices/bsim3v1/b3v1mpar.c new file mode 100644 index 000000000..60ad98aab --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1mpar.c @@ -0,0 +1,1546 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:56:49 yuhua + *  + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1mpar.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3v1def.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V1mParam(param,value,inMod) +int param; +IFvalue *value; +GENmodel *inMod; +{ + BSIM3V1model *mod = (BSIM3V1model*)inMod; + switch(param) + { case BSIM3V1_MOD_MOBMOD : + mod->BSIM3V1mobMod = value->iValue; + mod->BSIM3V1mobModGiven = TRUE; + break; + case BSIM3V1_MOD_BINUNIT : + mod->BSIM3V1binUnit = value->iValue; + mod->BSIM3V1binUnitGiven = TRUE; + break; + case BSIM3V1_MOD_PARAMCHK : + mod->BSIM3V1paramChk = value->iValue; + mod->BSIM3V1paramChkGiven = TRUE; + break; + case BSIM3V1_MOD_CAPMOD : + mod->BSIM3V1capMod = value->iValue; + mod->BSIM3V1capModGiven = TRUE; + break; + case BSIM3V1_MOD_NQSMOD : + mod->BSIM3V1nqsMod = value->iValue; + mod->BSIM3V1nqsModGiven = TRUE; + break; + case BSIM3V1_MOD_NOIMOD : + mod->BSIM3V1noiMod = value->iValue; + mod->BSIM3V1noiModGiven = TRUE; + break; + case BSIM3V1_MOD_VERSION : + mod->BSIM3V1version = value->rValue; + mod->BSIM3V1versionGiven = TRUE; + break; + case BSIM3V1_MOD_TOX : + mod->BSIM3V1tox = value->rValue; + mod->BSIM3V1toxGiven = TRUE; + break; + + case BSIM3V1_MOD_CDSC : + mod->BSIM3V1cdsc = value->rValue; + mod->BSIM3V1cdscGiven = TRUE; + break; + case BSIM3V1_MOD_CDSCB : + mod->BSIM3V1cdscb = value->rValue; + mod->BSIM3V1cdscbGiven = TRUE; + break; + + case BSIM3V1_MOD_CDSCD : + mod->BSIM3V1cdscd = value->rValue; + mod->BSIM3V1cdscdGiven = TRUE; + break; + + case BSIM3V1_MOD_CIT : + mod->BSIM3V1cit = value->rValue; + mod->BSIM3V1citGiven = TRUE; + break; + case BSIM3V1_MOD_NFACTOR : + mod->BSIM3V1nfactor = value->rValue; + mod->BSIM3V1nfactorGiven = TRUE; + break; + case BSIM3V1_MOD_XJ: + mod->BSIM3V1xj = value->rValue; + mod->BSIM3V1xjGiven = TRUE; + break; + case BSIM3V1_MOD_VSAT: + mod->BSIM3V1vsat = value->rValue; + mod->BSIM3V1vsatGiven = TRUE; + break; + case BSIM3V1_MOD_A0: + mod->BSIM3V1a0 = value->rValue; + mod->BSIM3V1a0Given = TRUE; + break; + + case BSIM3V1_MOD_AGS: + mod->BSIM3V1ags= value->rValue; + mod->BSIM3V1agsGiven = TRUE; + break; + + case BSIM3V1_MOD_A1: + mod->BSIM3V1a1 = value->rValue; + mod->BSIM3V1a1Given = TRUE; + break; + case BSIM3V1_MOD_A2: + mod->BSIM3V1a2 = value->rValue; + mod->BSIM3V1a2Given = TRUE; + break; + case BSIM3V1_MOD_AT: + mod->BSIM3V1at = value->rValue; + mod->BSIM3V1atGiven = TRUE; + break; + case BSIM3V1_MOD_KETA: + mod->BSIM3V1keta = value->rValue; + mod->BSIM3V1ketaGiven = TRUE; + break; + case BSIM3V1_MOD_NSUB: + mod->BSIM3V1nsub = value->rValue; + mod->BSIM3V1nsubGiven = TRUE; + break; + case BSIM3V1_MOD_NPEAK: + mod->BSIM3V1npeak = value->rValue; + mod->BSIM3V1npeakGiven = TRUE; + if (mod->BSIM3V1npeak > 1.0e20) + mod->BSIM3V1npeak *= 1.0e-6; + break; + case BSIM3V1_MOD_NGATE: + mod->BSIM3V1ngate = value->rValue; + mod->BSIM3V1ngateGiven = TRUE; + if (mod->BSIM3V1ngate > 1.0e23) + mod->BSIM3V1ngate *= 1.0e-6; + break; + case BSIM3V1_MOD_GAMMA1: + mod->BSIM3V1gamma1 = value->rValue; + mod->BSIM3V1gamma1Given = TRUE; + break; + case BSIM3V1_MOD_GAMMA2: + mod->BSIM3V1gamma2 = value->rValue; + mod->BSIM3V1gamma2Given = TRUE; + break; + case BSIM3V1_MOD_VBX: + mod->BSIM3V1vbx = value->rValue; + mod->BSIM3V1vbxGiven = TRUE; + break; + case BSIM3V1_MOD_VBM: + mod->BSIM3V1vbm = value->rValue; + mod->BSIM3V1vbmGiven = TRUE; + break; + case BSIM3V1_MOD_XT: + mod->BSIM3V1xt = value->rValue; + mod->BSIM3V1xtGiven = TRUE; + break; + case BSIM3V1_MOD_K1: + mod->BSIM3V1k1 = value->rValue; + mod->BSIM3V1k1Given = TRUE; + break; + case BSIM3V1_MOD_KT1: + mod->BSIM3V1kt1 = value->rValue; + mod->BSIM3V1kt1Given = TRUE; + break; + case BSIM3V1_MOD_KT1L: + mod->BSIM3V1kt1l = value->rValue; + mod->BSIM3V1kt1lGiven = TRUE; + break; + case BSIM3V1_MOD_KT2: + mod->BSIM3V1kt2 = value->rValue; + mod->BSIM3V1kt2Given = TRUE; + break; + case BSIM3V1_MOD_K2: + mod->BSIM3V1k2 = value->rValue; + mod->BSIM3V1k2Given = TRUE; + break; + case BSIM3V1_MOD_K3: + mod->BSIM3V1k3 = value->rValue; + mod->BSIM3V1k3Given = TRUE; + break; + case BSIM3V1_MOD_K3B: + mod->BSIM3V1k3b = value->rValue; + mod->BSIM3V1k3bGiven = TRUE; + break; + case BSIM3V1_MOD_NLX: + mod->BSIM3V1nlx = value->rValue; + mod->BSIM3V1nlxGiven = TRUE; + break; + case BSIM3V1_MOD_W0: + mod->BSIM3V1w0 = value->rValue; + mod->BSIM3V1w0Given = TRUE; + break; + case BSIM3V1_MOD_DVT0: + mod->BSIM3V1dvt0 = value->rValue; + mod->BSIM3V1dvt0Given = TRUE; + break; + case BSIM3V1_MOD_DVT1: + mod->BSIM3V1dvt1 = value->rValue; + mod->BSIM3V1dvt1Given = TRUE; + break; + case BSIM3V1_MOD_DVT2: + mod->BSIM3V1dvt2 = value->rValue; + mod->BSIM3V1dvt2Given = TRUE; + break; + case BSIM3V1_MOD_DVT0W: + mod->BSIM3V1dvt0w = value->rValue; + mod->BSIM3V1dvt0wGiven = TRUE; + break; + case BSIM3V1_MOD_DVT1W: + mod->BSIM3V1dvt1w = value->rValue; + mod->BSIM3V1dvt1wGiven = TRUE; + break; + case BSIM3V1_MOD_DVT2W: + mod->BSIM3V1dvt2w = value->rValue; + mod->BSIM3V1dvt2wGiven = TRUE; + break; + case BSIM3V1_MOD_DROUT: + mod->BSIM3V1drout = value->rValue; + mod->BSIM3V1droutGiven = TRUE; + break; + case BSIM3V1_MOD_DSUB: + mod->BSIM3V1dsub = value->rValue; + mod->BSIM3V1dsubGiven = TRUE; + break; + case BSIM3V1_MOD_VTH0: + mod->BSIM3V1vth0 = value->rValue; + mod->BSIM3V1vth0Given = TRUE; + break; + case BSIM3V1_MOD_UA: + mod->BSIM3V1ua = value->rValue; + mod->BSIM3V1uaGiven = TRUE; + break; + case BSIM3V1_MOD_UA1: + mod->BSIM3V1ua1 = value->rValue; + mod->BSIM3V1ua1Given = TRUE; + break; + case BSIM3V1_MOD_UB: + mod->BSIM3V1ub = value->rValue; + mod->BSIM3V1ubGiven = TRUE; + break; + case BSIM3V1_MOD_UB1: + mod->BSIM3V1ub1 = value->rValue; + mod->BSIM3V1ub1Given = TRUE; + break; + case BSIM3V1_MOD_UC: + mod->BSIM3V1uc = value->rValue; + mod->BSIM3V1ucGiven = TRUE; + break; + case BSIM3V1_MOD_UC1: + mod->BSIM3V1uc1 = value->rValue; + mod->BSIM3V1uc1Given = TRUE; + break; + case BSIM3V1_MOD_U0 : + mod->BSIM3V1u0 = value->rValue; + mod->BSIM3V1u0Given = TRUE; + break; + case BSIM3V1_MOD_UTE : + mod->BSIM3V1ute = value->rValue; + mod->BSIM3V1uteGiven = TRUE; + break; + case BSIM3V1_MOD_VOFF: + mod->BSIM3V1voff = value->rValue; + mod->BSIM3V1voffGiven = TRUE; + break; + case BSIM3V1_MOD_DELTA : + mod->BSIM3V1delta = value->rValue; + mod->BSIM3V1deltaGiven = TRUE; + break; + case BSIM3V1_MOD_RDSW: + mod->BSIM3V1rdsw = value->rValue; + mod->BSIM3V1rdswGiven = TRUE; + break; + case BSIM3V1_MOD_PRWG: + mod->BSIM3V1prwg = value->rValue; + mod->BSIM3V1prwgGiven = TRUE; + break; + case BSIM3V1_MOD_PRWB: + mod->BSIM3V1prwb = value->rValue; + mod->BSIM3V1prwbGiven = TRUE; + break; + case BSIM3V1_MOD_PRT: + mod->BSIM3V1prt = value->rValue; + mod->BSIM3V1prtGiven = TRUE; + break; + case BSIM3V1_MOD_ETA0: + mod->BSIM3V1eta0 = value->rValue; + mod->BSIM3V1eta0Given = TRUE; + break; + case BSIM3V1_MOD_ETAB: + mod->BSIM3V1etab = value->rValue; + mod->BSIM3V1etabGiven = TRUE; + break; + case BSIM3V1_MOD_PCLM: + mod->BSIM3V1pclm = value->rValue; + mod->BSIM3V1pclmGiven = TRUE; + break; + case BSIM3V1_MOD_PDIBL1: + mod->BSIM3V1pdibl1 = value->rValue; + mod->BSIM3V1pdibl1Given = TRUE; + break; + case BSIM3V1_MOD_PDIBL2: + mod->BSIM3V1pdibl2 = value->rValue; + mod->BSIM3V1pdibl2Given = TRUE; + break; + case BSIM3V1_MOD_PDIBLB: + mod->BSIM3V1pdiblb = value->rValue; + mod->BSIM3V1pdiblbGiven = TRUE; + break; + case BSIM3V1_MOD_PSCBE1: + mod->BSIM3V1pscbe1 = value->rValue; + mod->BSIM3V1pscbe1Given = TRUE; + break; + case BSIM3V1_MOD_PSCBE2: + mod->BSIM3V1pscbe2 = value->rValue; + mod->BSIM3V1pscbe2Given = TRUE; + break; + case BSIM3V1_MOD_PVAG: + mod->BSIM3V1pvag = value->rValue; + mod->BSIM3V1pvagGiven = TRUE; + break; + case BSIM3V1_MOD_WR : + mod->BSIM3V1wr = value->rValue; + mod->BSIM3V1wrGiven = TRUE; + break; + case BSIM3V1_MOD_DWG : + mod->BSIM3V1dwg = value->rValue; + mod->BSIM3V1dwgGiven = TRUE; + break; + case BSIM3V1_MOD_DWB : + mod->BSIM3V1dwb = value->rValue; + mod->BSIM3V1dwbGiven = TRUE; + break; + case BSIM3V1_MOD_B0 : + mod->BSIM3V1b0 = value->rValue; + mod->BSIM3V1b0Given = TRUE; + break; + case BSIM3V1_MOD_B1 : + mod->BSIM3V1b1 = value->rValue; + mod->BSIM3V1b1Given = TRUE; + break; + case BSIM3V1_MOD_ALPHA0 : + mod->BSIM3V1alpha0 = value->rValue; + mod->BSIM3V1alpha0Given = TRUE; + break; + case BSIM3V1_MOD_BETA0 : + mod->BSIM3V1beta0 = value->rValue; + mod->BSIM3V1beta0Given = TRUE; + break; + + case BSIM3V1_MOD_ELM : + mod->BSIM3V1elm = value->rValue; + mod->BSIM3V1elmGiven = TRUE; + break; + case BSIM3V1_MOD_CGSL : + mod->BSIM3V1cgsl = value->rValue; + mod->BSIM3V1cgslGiven = TRUE; + break; + case BSIM3V1_MOD_CGDL : + mod->BSIM3V1cgdl = value->rValue; + mod->BSIM3V1cgdlGiven = TRUE; + break; + case BSIM3V1_MOD_CKAPPA : + mod->BSIM3V1ckappa = value->rValue; + mod->BSIM3V1ckappaGiven = TRUE; + break; + case BSIM3V1_MOD_CF : + mod->BSIM3V1cf = value->rValue; + mod->BSIM3V1cfGiven = TRUE; + break; + case BSIM3V1_MOD_CLC : + mod->BSIM3V1clc = value->rValue; + mod->BSIM3V1clcGiven = TRUE; + break; + case BSIM3V1_MOD_CLE : + mod->BSIM3V1cle = value->rValue; + mod->BSIM3V1cleGiven = TRUE; + break; + case BSIM3V1_MOD_DWC : + mod->BSIM3V1dwc = value->rValue; + mod->BSIM3V1dwcGiven = TRUE; + break; + case BSIM3V1_MOD_DLC : + mod->BSIM3V1dlc = value->rValue; + mod->BSIM3V1dlcGiven = TRUE; + break; + case BSIM3V1_MOD_VFBCV : + mod->BSIM3V1vfbcv = value->rValue; + mod->BSIM3V1vfbcvGiven = TRUE; + break; + + /* Length dependence */ + case BSIM3V1_MOD_LCDSC : + mod->BSIM3V1lcdsc = value->rValue; + mod->BSIM3V1lcdscGiven = TRUE; + break; + + + case BSIM3V1_MOD_LCDSCB : + mod->BSIM3V1lcdscb = value->rValue; + mod->BSIM3V1lcdscbGiven = TRUE; + break; + case BSIM3V1_MOD_LCDSCD : + mod->BSIM3V1lcdscd = value->rValue; + mod->BSIM3V1lcdscdGiven = TRUE; + break; + case BSIM3V1_MOD_LCIT : + mod->BSIM3V1lcit = value->rValue; + mod->BSIM3V1lcitGiven = TRUE; + break; + case BSIM3V1_MOD_LNFACTOR : + mod->BSIM3V1lnfactor = value->rValue; + mod->BSIM3V1lnfactorGiven = TRUE; + break; + case BSIM3V1_MOD_LXJ: + mod->BSIM3V1lxj = value->rValue; + mod->BSIM3V1lxjGiven = TRUE; + break; + case BSIM3V1_MOD_LVSAT: + mod->BSIM3V1lvsat = value->rValue; + mod->BSIM3V1lvsatGiven = TRUE; + break; + + + case BSIM3V1_MOD_LA0: + mod->BSIM3V1la0 = value->rValue; + mod->BSIM3V1la0Given = TRUE; + break; + case BSIM3V1_MOD_LAGS: + mod->BSIM3V1lags = value->rValue; + mod->BSIM3V1lagsGiven = TRUE; + break; + case BSIM3V1_MOD_LA1: + mod->BSIM3V1la1 = value->rValue; + mod->BSIM3V1la1Given = TRUE; + break; + case BSIM3V1_MOD_LA2: + mod->BSIM3V1la2 = value->rValue; + mod->BSIM3V1la2Given = TRUE; + break; + case BSIM3V1_MOD_LAT: + mod->BSIM3V1lat = value->rValue; + mod->BSIM3V1latGiven = TRUE; + break; + case BSIM3V1_MOD_LKETA: + mod->BSIM3V1lketa = value->rValue; + mod->BSIM3V1lketaGiven = TRUE; + break; + case BSIM3V1_MOD_LNSUB: + mod->BSIM3V1lnsub = value->rValue; + mod->BSIM3V1lnsubGiven = TRUE; + break; + case BSIM3V1_MOD_LNPEAK: + mod->BSIM3V1lnpeak = value->rValue; + mod->BSIM3V1lnpeakGiven = TRUE; + if (mod->BSIM3V1lnpeak > 1.0e20) + mod->BSIM3V1lnpeak *= 1.0e-6; + break; + case BSIM3V1_MOD_LNGATE: + mod->BSIM3V1lngate = value->rValue; + mod->BSIM3V1lngateGiven = TRUE; + if (mod->BSIM3V1lngate > 1.0e23) + mod->BSIM3V1lngate *= 1.0e-6; + break; + case BSIM3V1_MOD_LGAMMA1: + mod->BSIM3V1lgamma1 = value->rValue; + mod->BSIM3V1lgamma1Given = TRUE; + break; + case BSIM3V1_MOD_LGAMMA2: + mod->BSIM3V1lgamma2 = value->rValue; + mod->BSIM3V1lgamma2Given = TRUE; + break; + case BSIM3V1_MOD_LVBX: + mod->BSIM3V1lvbx = value->rValue; + mod->BSIM3V1lvbxGiven = TRUE; + break; + case BSIM3V1_MOD_LVBM: + mod->BSIM3V1lvbm = value->rValue; + mod->BSIM3V1lvbmGiven = TRUE; + break; + case BSIM3V1_MOD_LXT: + mod->BSIM3V1lxt = value->rValue; + mod->BSIM3V1lxtGiven = TRUE; + break; + case BSIM3V1_MOD_LK1: + mod->BSIM3V1lk1 = value->rValue; + mod->BSIM3V1lk1Given = TRUE; + break; + case BSIM3V1_MOD_LKT1: + mod->BSIM3V1lkt1 = value->rValue; + mod->BSIM3V1lkt1Given = TRUE; + break; + case BSIM3V1_MOD_LKT1L: + mod->BSIM3V1lkt1l = value->rValue; + mod->BSIM3V1lkt1lGiven = TRUE; + break; + case BSIM3V1_MOD_LKT2: + mod->BSIM3V1lkt2 = value->rValue; + mod->BSIM3V1lkt2Given = TRUE; + break; + case BSIM3V1_MOD_LK2: + mod->BSIM3V1lk2 = value->rValue; + mod->BSIM3V1lk2Given = TRUE; + break; + case BSIM3V1_MOD_LK3: + mod->BSIM3V1lk3 = value->rValue; + mod->BSIM3V1lk3Given = TRUE; + break; + case BSIM3V1_MOD_LK3B: + mod->BSIM3V1lk3b = value->rValue; + mod->BSIM3V1lk3bGiven = TRUE; + break; + case BSIM3V1_MOD_LNLX: + mod->BSIM3V1lnlx = value->rValue; + mod->BSIM3V1lnlxGiven = TRUE; + break; + case BSIM3V1_MOD_LW0: + mod->BSIM3V1lw0 = value->rValue; + mod->BSIM3V1lw0Given = TRUE; + break; + case BSIM3V1_MOD_LDVT0: + mod->BSIM3V1ldvt0 = value->rValue; + mod->BSIM3V1ldvt0Given = TRUE; + break; + case BSIM3V1_MOD_LDVT1: + mod->BSIM3V1ldvt1 = value->rValue; + mod->BSIM3V1ldvt1Given = TRUE; + break; + case BSIM3V1_MOD_LDVT2: + mod->BSIM3V1ldvt2 = value->rValue; + mod->BSIM3V1ldvt2Given = TRUE; + break; + case BSIM3V1_MOD_LDVT0W: + mod->BSIM3V1ldvt0w = value->rValue; + mod->BSIM3V1ldvt0Given = TRUE; + break; + case BSIM3V1_MOD_LDVT1W: + mod->BSIM3V1ldvt1w = value->rValue; + mod->BSIM3V1ldvt1wGiven = TRUE; + break; + case BSIM3V1_MOD_LDVT2W: + mod->BSIM3V1ldvt2w = value->rValue; + mod->BSIM3V1ldvt2wGiven = TRUE; + break; + case BSIM3V1_MOD_LDROUT: + mod->BSIM3V1ldrout = value->rValue; + mod->BSIM3V1ldroutGiven = TRUE; + break; + case BSIM3V1_MOD_LDSUB: + mod->BSIM3V1ldsub = value->rValue; + mod->BSIM3V1ldsubGiven = TRUE; + break; + case BSIM3V1_MOD_LVTH0: + mod->BSIM3V1lvth0 = value->rValue; + mod->BSIM3V1lvth0Given = TRUE; + break; + case BSIM3V1_MOD_LUA: + mod->BSIM3V1lua = value->rValue; + mod->BSIM3V1luaGiven = TRUE; + break; + case BSIM3V1_MOD_LUA1: + mod->BSIM3V1lua1 = value->rValue; + mod->BSIM3V1lua1Given = TRUE; + break; + case BSIM3V1_MOD_LUB: + mod->BSIM3V1lub = value->rValue; + mod->BSIM3V1lubGiven = TRUE; + break; + case BSIM3V1_MOD_LUB1: + mod->BSIM3V1lub1 = value->rValue; + mod->BSIM3V1lub1Given = TRUE; + break; + case BSIM3V1_MOD_LUC: + mod->BSIM3V1luc = value->rValue; + mod->BSIM3V1lucGiven = TRUE; + break; + case BSIM3V1_MOD_LUC1: + mod->BSIM3V1luc1 = value->rValue; + mod->BSIM3V1luc1Given = TRUE; + break; + case BSIM3V1_MOD_LU0 : + mod->BSIM3V1lu0 = value->rValue; + mod->BSIM3V1lu0Given = TRUE; + break; + case BSIM3V1_MOD_LUTE : + mod->BSIM3V1lute = value->rValue; + mod->BSIM3V1luteGiven = TRUE; + break; + case BSIM3V1_MOD_LVOFF: + mod->BSIM3V1lvoff = value->rValue; + mod->BSIM3V1lvoffGiven = TRUE; + break; + case BSIM3V1_MOD_LDELTA : + mod->BSIM3V1ldelta = value->rValue; + mod->BSIM3V1ldeltaGiven = TRUE; + break; + case BSIM3V1_MOD_LRDSW: + mod->BSIM3V1lrdsw = value->rValue; + mod->BSIM3V1lrdswGiven = TRUE; + break; + case BSIM3V1_MOD_LPRWB: + mod->BSIM3V1lprwb = value->rValue; + mod->BSIM3V1lprwbGiven = TRUE; + break; + case BSIM3V1_MOD_LPRWG: + mod->BSIM3V1lprwg = value->rValue; + mod->BSIM3V1lprwgGiven = TRUE; + break; + case BSIM3V1_MOD_LPRT: + mod->BSIM3V1lprt = value->rValue; + mod->BSIM3V1lprtGiven = TRUE; + break; + case BSIM3V1_MOD_LETA0: + mod->BSIM3V1leta0 = value->rValue; + mod->BSIM3V1leta0Given = TRUE; + break; + case BSIM3V1_MOD_LETAB: + mod->BSIM3V1letab = value->rValue; + mod->BSIM3V1letabGiven = TRUE; + break; + case BSIM3V1_MOD_LPCLM: + mod->BSIM3V1lpclm = value->rValue; + mod->BSIM3V1lpclmGiven = TRUE; + break; + case BSIM3V1_MOD_LPDIBL1: + mod->BSIM3V1lpdibl1 = value->rValue; + mod->BSIM3V1lpdibl1Given = TRUE; + break; + case BSIM3V1_MOD_LPDIBL2: + mod->BSIM3V1lpdibl2 = value->rValue; + mod->BSIM3V1lpdibl2Given = TRUE; + break; + case BSIM3V1_MOD_LPDIBLB: + mod->BSIM3V1lpdiblb = value->rValue; + mod->BSIM3V1lpdiblbGiven = TRUE; + break; + case BSIM3V1_MOD_LPSCBE1: + mod->BSIM3V1lpscbe1 = value->rValue; + mod->BSIM3V1lpscbe1Given = TRUE; + break; + case BSIM3V1_MOD_LPSCBE2: + mod->BSIM3V1lpscbe2 = value->rValue; + mod->BSIM3V1lpscbe2Given = TRUE; + break; + case BSIM3V1_MOD_LPVAG: + mod->BSIM3V1lpvag = value->rValue; + mod->BSIM3V1lpvagGiven = TRUE; + break; + case BSIM3V1_MOD_LWR : + mod->BSIM3V1lwr = value->rValue; + mod->BSIM3V1lwrGiven = TRUE; + break; + case BSIM3V1_MOD_LDWG : + mod->BSIM3V1ldwg = value->rValue; + mod->BSIM3V1ldwgGiven = TRUE; + break; + case BSIM3V1_MOD_LDWB : + mod->BSIM3V1ldwb = value->rValue; + mod->BSIM3V1ldwbGiven = TRUE; + break; + case BSIM3V1_MOD_LB0 : + mod->BSIM3V1lb0 = value->rValue; + mod->BSIM3V1lb0Given = TRUE; + break; + case BSIM3V1_MOD_LB1 : + mod->BSIM3V1lb1 = value->rValue; + mod->BSIM3V1lb1Given = TRUE; + break; + case BSIM3V1_MOD_LALPHA0 : + mod->BSIM3V1lalpha0 = value->rValue; + mod->BSIM3V1lalpha0Given = TRUE; + break; + case BSIM3V1_MOD_LBETA0 : + mod->BSIM3V1lbeta0 = value->rValue; + mod->BSIM3V1lbeta0Given = TRUE; + break; + + case BSIM3V1_MOD_LELM : + mod->BSIM3V1lelm = value->rValue; + mod->BSIM3V1lelmGiven = TRUE; + break; + case BSIM3V1_MOD_LCGSL : + mod->BSIM3V1lcgsl = value->rValue; + mod->BSIM3V1lcgslGiven = TRUE; + break; + case BSIM3V1_MOD_LCGDL : + mod->BSIM3V1lcgdl = value->rValue; + mod->BSIM3V1lcgdlGiven = TRUE; + break; + case BSIM3V1_MOD_LCKAPPA : + mod->BSIM3V1lckappa = value->rValue; + mod->BSIM3V1lckappaGiven = TRUE; + break; + case BSIM3V1_MOD_LCF : + mod->BSIM3V1lcf = value->rValue; + mod->BSIM3V1lcfGiven = TRUE; + break; + case BSIM3V1_MOD_LCLC : + mod->BSIM3V1lclc = value->rValue; + mod->BSIM3V1lclcGiven = TRUE; + break; + case BSIM3V1_MOD_LCLE : + mod->BSIM3V1lcle = value->rValue; + mod->BSIM3V1lcleGiven = TRUE; + break; + case BSIM3V1_MOD_LVFBCV : + mod->BSIM3V1lvfbcv = value->rValue; + mod->BSIM3V1lvfbcvGiven = TRUE; + break; + + /* Width dependence */ + case BSIM3V1_MOD_WCDSC : + mod->BSIM3V1wcdsc = value->rValue; + mod->BSIM3V1wcdscGiven = TRUE; + break; + + + case BSIM3V1_MOD_WCDSCB : + mod->BSIM3V1wcdscb = value->rValue; + mod->BSIM3V1wcdscbGiven = TRUE; + break; + case BSIM3V1_MOD_WCDSCD : + mod->BSIM3V1wcdscd = value->rValue; + mod->BSIM3V1wcdscdGiven = TRUE; + break; + case BSIM3V1_MOD_WCIT : + mod->BSIM3V1wcit = value->rValue; + mod->BSIM3V1wcitGiven = TRUE; + break; + case BSIM3V1_MOD_WNFACTOR : + mod->BSIM3V1wnfactor = value->rValue; + mod->BSIM3V1wnfactorGiven = TRUE; + break; + case BSIM3V1_MOD_WXJ: + mod->BSIM3V1wxj = value->rValue; + mod->BSIM3V1wxjGiven = TRUE; + break; + case BSIM3V1_MOD_WVSAT: + mod->BSIM3V1wvsat = value->rValue; + mod->BSIM3V1wvsatGiven = TRUE; + break; + + + case BSIM3V1_MOD_WA0: + mod->BSIM3V1wa0 = value->rValue; + mod->BSIM3V1wa0Given = TRUE; + break; + case BSIM3V1_MOD_WAGS: + mod->BSIM3V1wags = value->rValue; + mod->BSIM3V1wagsGiven = TRUE; + break; + case BSIM3V1_MOD_WA1: + mod->BSIM3V1wa1 = value->rValue; + mod->BSIM3V1wa1Given = TRUE; + break; + case BSIM3V1_MOD_WA2: + mod->BSIM3V1wa2 = value->rValue; + mod->BSIM3V1wa2Given = TRUE; + break; + case BSIM3V1_MOD_WAT: + mod->BSIM3V1wat = value->rValue; + mod->BSIM3V1watGiven = TRUE; + break; + case BSIM3V1_MOD_WKETA: + mod->BSIM3V1wketa = value->rValue; + mod->BSIM3V1wketaGiven = TRUE; + break; + case BSIM3V1_MOD_WNSUB: + mod->BSIM3V1wnsub = value->rValue; + mod->BSIM3V1wnsubGiven = TRUE; + break; + case BSIM3V1_MOD_WNPEAK: + mod->BSIM3V1wnpeak = value->rValue; + mod->BSIM3V1wnpeakGiven = TRUE; + if (mod->BSIM3V1wnpeak > 1.0e20) + mod->BSIM3V1wnpeak *= 1.0e-6; + break; + case BSIM3V1_MOD_WNGATE: + mod->BSIM3V1wngate = value->rValue; + mod->BSIM3V1wngateGiven = TRUE; + if (mod->BSIM3V1wngate > 1.0e23) + mod->BSIM3V1wngate *= 1.0e-6; + break; + case BSIM3V1_MOD_WGAMMA1: + mod->BSIM3V1wgamma1 = value->rValue; + mod->BSIM3V1wgamma1Given = TRUE; + break; + case BSIM3V1_MOD_WGAMMA2: + mod->BSIM3V1wgamma2 = value->rValue; + mod->BSIM3V1wgamma2Given = TRUE; + break; + case BSIM3V1_MOD_WVBX: + mod->BSIM3V1wvbx = value->rValue; + mod->BSIM3V1wvbxGiven = TRUE; + break; + case BSIM3V1_MOD_WVBM: + mod->BSIM3V1wvbm = value->rValue; + mod->BSIM3V1wvbmGiven = TRUE; + break; + case BSIM3V1_MOD_WXT: + mod->BSIM3V1wxt = value->rValue; + mod->BSIM3V1wxtGiven = TRUE; + break; + case BSIM3V1_MOD_WK1: + mod->BSIM3V1wk1 = value->rValue; + mod->BSIM3V1wk1Given = TRUE; + break; + case BSIM3V1_MOD_WKT1: + mod->BSIM3V1wkt1 = value->rValue; + mod->BSIM3V1wkt1Given = TRUE; + break; + case BSIM3V1_MOD_WKT1L: + mod->BSIM3V1wkt1l = value->rValue; + mod->BSIM3V1wkt1lGiven = TRUE; + break; + case BSIM3V1_MOD_WKT2: + mod->BSIM3V1wkt2 = value->rValue; + mod->BSIM3V1wkt2Given = TRUE; + break; + case BSIM3V1_MOD_WK2: + mod->BSIM3V1wk2 = value->rValue; + mod->BSIM3V1wk2Given = TRUE; + break; + case BSIM3V1_MOD_WK3: + mod->BSIM3V1wk3 = value->rValue; + mod->BSIM3V1wk3Given = TRUE; + break; + case BSIM3V1_MOD_WK3B: + mod->BSIM3V1wk3b = value->rValue; + mod->BSIM3V1wk3bGiven = TRUE; + break; + case BSIM3V1_MOD_WNLX: + mod->BSIM3V1wnlx = value->rValue; + mod->BSIM3V1wnlxGiven = TRUE; + break; + case BSIM3V1_MOD_WW0: + mod->BSIM3V1ww0 = value->rValue; + mod->BSIM3V1ww0Given = TRUE; + break; + case BSIM3V1_MOD_WDVT0: + mod->BSIM3V1wdvt0 = value->rValue; + mod->BSIM3V1wdvt0Given = TRUE; + break; + case BSIM3V1_MOD_WDVT1: + mod->BSIM3V1wdvt1 = value->rValue; + mod->BSIM3V1wdvt1Given = TRUE; + break; + case BSIM3V1_MOD_WDVT2: + mod->BSIM3V1wdvt2 = value->rValue; + mod->BSIM3V1wdvt2Given = TRUE; + break; + case BSIM3V1_MOD_WDVT0W: + mod->BSIM3V1wdvt0w = value->rValue; + mod->BSIM3V1wdvt0wGiven = TRUE; + break; + case BSIM3V1_MOD_WDVT1W: + mod->BSIM3V1wdvt1w = value->rValue; + mod->BSIM3V1wdvt1wGiven = TRUE; + break; + case BSIM3V1_MOD_WDVT2W: + mod->BSIM3V1wdvt2w = value->rValue; + mod->BSIM3V1wdvt2wGiven = TRUE; + break; + case BSIM3V1_MOD_WDROUT: + mod->BSIM3V1wdrout = value->rValue; + mod->BSIM3V1wdroutGiven = TRUE; + break; + case BSIM3V1_MOD_WDSUB: + mod->BSIM3V1wdsub = value->rValue; + mod->BSIM3V1wdsubGiven = TRUE; + break; + case BSIM3V1_MOD_WVTH0: + mod->BSIM3V1wvth0 = value->rValue; + mod->BSIM3V1wvth0Given = TRUE; + break; + case BSIM3V1_MOD_WUA: + mod->BSIM3V1wua = value->rValue; + mod->BSIM3V1wuaGiven = TRUE; + break; + case BSIM3V1_MOD_WUA1: + mod->BSIM3V1wua1 = value->rValue; + mod->BSIM3V1wua1Given = TRUE; + break; + case BSIM3V1_MOD_WUB: + mod->BSIM3V1wub = value->rValue; + mod->BSIM3V1wubGiven = TRUE; + break; + case BSIM3V1_MOD_WUB1: + mod->BSIM3V1wub1 = value->rValue; + mod->BSIM3V1wub1Given = TRUE; + break; + case BSIM3V1_MOD_WUC: + mod->BSIM3V1wuc = value->rValue; + mod->BSIM3V1wucGiven = TRUE; + break; + case BSIM3V1_MOD_WUC1: + mod->BSIM3V1wuc1 = value->rValue; + mod->BSIM3V1wuc1Given = TRUE; + break; + case BSIM3V1_MOD_WU0 : + mod->BSIM3V1wu0 = value->rValue; + mod->BSIM3V1wu0Given = TRUE; + break; + case BSIM3V1_MOD_WUTE : + mod->BSIM3V1wute = value->rValue; + mod->BSIM3V1wuteGiven = TRUE; + break; + case BSIM3V1_MOD_WVOFF: + mod->BSIM3V1wvoff = value->rValue; + mod->BSIM3V1wvoffGiven = TRUE; + break; + case BSIM3V1_MOD_WDELTA : + mod->BSIM3V1wdelta = value->rValue; + mod->BSIM3V1wdeltaGiven = TRUE; + break; + case BSIM3V1_MOD_WRDSW: + mod->BSIM3V1wrdsw = value->rValue; + mod->BSIM3V1wrdswGiven = TRUE; + break; + case BSIM3V1_MOD_WPRWB: + mod->BSIM3V1wprwb = value->rValue; + mod->BSIM3V1wprwbGiven = TRUE; + break; + case BSIM3V1_MOD_WPRWG: + mod->BSIM3V1wprwg = value->rValue; + mod->BSIM3V1wprwgGiven = TRUE; + break; + case BSIM3V1_MOD_WPRT: + mod->BSIM3V1wprt = value->rValue; + mod->BSIM3V1wprtGiven = TRUE; + break; + case BSIM3V1_MOD_WETA0: + mod->BSIM3V1weta0 = value->rValue; + mod->BSIM3V1weta0Given = TRUE; + break; + case BSIM3V1_MOD_WETAB: + mod->BSIM3V1wetab = value->rValue; + mod->BSIM3V1wetabGiven = TRUE; + break; + case BSIM3V1_MOD_WPCLM: + mod->BSIM3V1wpclm = value->rValue; + mod->BSIM3V1wpclmGiven = TRUE; + break; + case BSIM3V1_MOD_WPDIBL1: + mod->BSIM3V1wpdibl1 = value->rValue; + mod->BSIM3V1wpdibl1Given = TRUE; + break; + case BSIM3V1_MOD_WPDIBL2: + mod->BSIM3V1wpdibl2 = value->rValue; + mod->BSIM3V1wpdibl2Given = TRUE; + break; + case BSIM3V1_MOD_WPDIBLB: + mod->BSIM3V1wpdiblb = value->rValue; + mod->BSIM3V1wpdiblbGiven = TRUE; + break; + case BSIM3V1_MOD_WPSCBE1: + mod->BSIM3V1wpscbe1 = value->rValue; + mod->BSIM3V1wpscbe1Given = TRUE; + break; + case BSIM3V1_MOD_WPSCBE2: + mod->BSIM3V1wpscbe2 = value->rValue; + mod->BSIM3V1wpscbe2Given = TRUE; + break; + case BSIM3V1_MOD_WPVAG: + mod->BSIM3V1wpvag = value->rValue; + mod->BSIM3V1wpvagGiven = TRUE; + break; + case BSIM3V1_MOD_WWR : + mod->BSIM3V1wwr = value->rValue; + mod->BSIM3V1wwrGiven = TRUE; + break; + case BSIM3V1_MOD_WDWG : + mod->BSIM3V1wdwg = value->rValue; + mod->BSIM3V1wdwgGiven = TRUE; + break; + case BSIM3V1_MOD_WDWB : + mod->BSIM3V1wdwb = value->rValue; + mod->BSIM3V1wdwbGiven = TRUE; + break; + case BSIM3V1_MOD_WB0 : + mod->BSIM3V1wb0 = value->rValue; + mod->BSIM3V1wb0Given = TRUE; + break; + case BSIM3V1_MOD_WB1 : + mod->BSIM3V1wb1 = value->rValue; + mod->BSIM3V1wb1Given = TRUE; + break; + case BSIM3V1_MOD_WALPHA0 : + mod->BSIM3V1walpha0 = value->rValue; + mod->BSIM3V1walpha0Given = TRUE; + break; + case BSIM3V1_MOD_WBETA0 : + mod->BSIM3V1wbeta0 = value->rValue; + mod->BSIM3V1wbeta0Given = TRUE; + break; + + case BSIM3V1_MOD_WELM : + mod->BSIM3V1welm = value->rValue; + mod->BSIM3V1welmGiven = TRUE; + break; + case BSIM3V1_MOD_WCGSL : + mod->BSIM3V1wcgsl = value->rValue; + mod->BSIM3V1wcgslGiven = TRUE; + break; + case BSIM3V1_MOD_WCGDL : + mod->BSIM3V1wcgdl = value->rValue; + mod->BSIM3V1wcgdlGiven = TRUE; + break; + case BSIM3V1_MOD_WCKAPPA : + mod->BSIM3V1wckappa = value->rValue; + mod->BSIM3V1wckappaGiven = TRUE; + break; + case BSIM3V1_MOD_WCF : + mod->BSIM3V1wcf = value->rValue; + mod->BSIM3V1wcfGiven = TRUE; + break; + case BSIM3V1_MOD_WCLC : + mod->BSIM3V1wclc = value->rValue; + mod->BSIM3V1wclcGiven = TRUE; + break; + case BSIM3V1_MOD_WCLE : + mod->BSIM3V1wcle = value->rValue; + mod->BSIM3V1wcleGiven = TRUE; + break; + case BSIM3V1_MOD_WVFBCV : + mod->BSIM3V1wvfbcv = value->rValue; + mod->BSIM3V1wvfbcvGiven = TRUE; + break; + + /* Cross-term dependence */ + case BSIM3V1_MOD_PCDSC : + mod->BSIM3V1pcdsc = value->rValue; + mod->BSIM3V1pcdscGiven = TRUE; + break; + + + case BSIM3V1_MOD_PCDSCB : + mod->BSIM3V1pcdscb = value->rValue; + mod->BSIM3V1pcdscbGiven = TRUE; + break; + case BSIM3V1_MOD_PCDSCD : + mod->BSIM3V1pcdscd = value->rValue; + mod->BSIM3V1pcdscdGiven = TRUE; + break; + case BSIM3V1_MOD_PCIT : + mod->BSIM3V1pcit = value->rValue; + mod->BSIM3V1pcitGiven = TRUE; + break; + case BSIM3V1_MOD_PNFACTOR : + mod->BSIM3V1pnfactor = value->rValue; + mod->BSIM3V1pnfactorGiven = TRUE; + break; + case BSIM3V1_MOD_PXJ: + mod->BSIM3V1pxj = value->rValue; + mod->BSIM3V1pxjGiven = TRUE; + break; + case BSIM3V1_MOD_PVSAT: + mod->BSIM3V1pvsat = value->rValue; + mod->BSIM3V1pvsatGiven = TRUE; + break; + + + case BSIM3V1_MOD_PA0: + mod->BSIM3V1pa0 = value->rValue; + mod->BSIM3V1pa0Given = TRUE; + break; + case BSIM3V1_MOD_PAGS: + mod->BSIM3V1pags = value->rValue; + mod->BSIM3V1pagsGiven = TRUE; + break; + case BSIM3V1_MOD_PA1: + mod->BSIM3V1pa1 = value->rValue; + mod->BSIM3V1pa1Given = TRUE; + break; + case BSIM3V1_MOD_PA2: + mod->BSIM3V1pa2 = value->rValue; + mod->BSIM3V1pa2Given = TRUE; + break; + case BSIM3V1_MOD_PAT: + mod->BSIM3V1pat = value->rValue; + mod->BSIM3V1patGiven = TRUE; + break; + case BSIM3V1_MOD_PKETA: + mod->BSIM3V1pketa = value->rValue; + mod->BSIM3V1pketaGiven = TRUE; + break; + case BSIM3V1_MOD_PNSUB: + mod->BSIM3V1pnsub = value->rValue; + mod->BSIM3V1pnsubGiven = TRUE; + break; + case BSIM3V1_MOD_PNPEAK: + mod->BSIM3V1pnpeak = value->rValue; + mod->BSIM3V1pnpeakGiven = TRUE; + if (mod->BSIM3V1pnpeak > 1.0e20) + mod->BSIM3V1pnpeak *= 1.0e-6; + break; + case BSIM3V1_MOD_PNGATE: + mod->BSIM3V1pngate = value->rValue; + mod->BSIM3V1pngateGiven = TRUE; + if (mod->BSIM3V1pngate > 1.0e23) + mod->BSIM3V1pngate *= 1.0e-6; + break; + case BSIM3V1_MOD_PGAMMA1: + mod->BSIM3V1pgamma1 = value->rValue; + mod->BSIM3V1pgamma1Given = TRUE; + break; + case BSIM3V1_MOD_PGAMMA2: + mod->BSIM3V1pgamma2 = value->rValue; + mod->BSIM3V1pgamma2Given = TRUE; + break; + case BSIM3V1_MOD_PVBX: + mod->BSIM3V1pvbx = value->rValue; + mod->BSIM3V1pvbxGiven = TRUE; + break; + case BSIM3V1_MOD_PVBM: + mod->BSIM3V1pvbm = value->rValue; + mod->BSIM3V1pvbmGiven = TRUE; + break; + case BSIM3V1_MOD_PXT: + mod->BSIM3V1pxt = value->rValue; + mod->BSIM3V1pxtGiven = TRUE; + break; + case BSIM3V1_MOD_PK1: + mod->BSIM3V1pk1 = value->rValue; + mod->BSIM3V1pk1Given = TRUE; + break; + case BSIM3V1_MOD_PKT1: + mod->BSIM3V1pkt1 = value->rValue; + mod->BSIM3V1pkt1Given = TRUE; + break; + case BSIM3V1_MOD_PKT1L: + mod->BSIM3V1pkt1l = value->rValue; + mod->BSIM3V1pkt1lGiven = TRUE; + break; + case BSIM3V1_MOD_PKT2: + mod->BSIM3V1pkt2 = value->rValue; + mod->BSIM3V1pkt2Given = TRUE; + break; + case BSIM3V1_MOD_PK2: + mod->BSIM3V1pk2 = value->rValue; + mod->BSIM3V1pk2Given = TRUE; + break; + case BSIM3V1_MOD_PK3: + mod->BSIM3V1pk3 = value->rValue; + mod->BSIM3V1pk3Given = TRUE; + break; + case BSIM3V1_MOD_PK3B: + mod->BSIM3V1pk3b = value->rValue; + mod->BSIM3V1pk3bGiven = TRUE; + break; + case BSIM3V1_MOD_PNLX: + mod->BSIM3V1pnlx = value->rValue; + mod->BSIM3V1pnlxGiven = TRUE; + break; + case BSIM3V1_MOD_PW0: + mod->BSIM3V1pw0 = value->rValue; + mod->BSIM3V1pw0Given = TRUE; + break; + case BSIM3V1_MOD_PDVT0: + mod->BSIM3V1pdvt0 = value->rValue; + mod->BSIM3V1pdvt0Given = TRUE; + break; + case BSIM3V1_MOD_PDVT1: + mod->BSIM3V1pdvt1 = value->rValue; + mod->BSIM3V1pdvt1Given = TRUE; + break; + case BSIM3V1_MOD_PDVT2: + mod->BSIM3V1pdvt2 = value->rValue; + mod->BSIM3V1pdvt2Given = TRUE; + break; + case BSIM3V1_MOD_PDVT0W: + mod->BSIM3V1pdvt0w = value->rValue; + mod->BSIM3V1pdvt0wGiven = TRUE; + break; + case BSIM3V1_MOD_PDVT1W: + mod->BSIM3V1pdvt1w = value->rValue; + mod->BSIM3V1pdvt1wGiven = TRUE; + break; + case BSIM3V1_MOD_PDVT2W: + mod->BSIM3V1pdvt2w = value->rValue; + mod->BSIM3V1pdvt2wGiven = TRUE; + break; + case BSIM3V1_MOD_PDROUT: + mod->BSIM3V1pdrout = value->rValue; + mod->BSIM3V1pdroutGiven = TRUE; + break; + case BSIM3V1_MOD_PDSUB: + mod->BSIM3V1pdsub = value->rValue; + mod->BSIM3V1pdsubGiven = TRUE; + break; + case BSIM3V1_MOD_PVTH0: + mod->BSIM3V1pvth0 = value->rValue; + mod->BSIM3V1pvth0Given = TRUE; + break; + case BSIM3V1_MOD_PUA: + mod->BSIM3V1pua = value->rValue; + mod->BSIM3V1puaGiven = TRUE; + break; + case BSIM3V1_MOD_PUA1: + mod->BSIM3V1pua1 = value->rValue; + mod->BSIM3V1pua1Given = TRUE; + break; + case BSIM3V1_MOD_PUB: + mod->BSIM3V1pub = value->rValue; + mod->BSIM3V1pubGiven = TRUE; + break; + case BSIM3V1_MOD_PUB1: + mod->BSIM3V1pub1 = value->rValue; + mod->BSIM3V1pub1Given = TRUE; + break; + case BSIM3V1_MOD_PUC: + mod->BSIM3V1puc = value->rValue; + mod->BSIM3V1pucGiven = TRUE; + break; + case BSIM3V1_MOD_PUC1: + mod->BSIM3V1puc1 = value->rValue; + mod->BSIM3V1puc1Given = TRUE; + break; + case BSIM3V1_MOD_PU0 : + mod->BSIM3V1pu0 = value->rValue; + mod->BSIM3V1pu0Given = TRUE; + break; + case BSIM3V1_MOD_PUTE : + mod->BSIM3V1pute = value->rValue; + mod->BSIM3V1puteGiven = TRUE; + break; + case BSIM3V1_MOD_PVOFF: + mod->BSIM3V1pvoff = value->rValue; + mod->BSIM3V1pvoffGiven = TRUE; + break; + case BSIM3V1_MOD_PDELTA : + mod->BSIM3V1pdelta = value->rValue; + mod->BSIM3V1pdeltaGiven = TRUE; + break; + case BSIM3V1_MOD_PRDSW: + mod->BSIM3V1prdsw = value->rValue; + mod->BSIM3V1prdswGiven = TRUE; + break; + case BSIM3V1_MOD_PPRWB: + mod->BSIM3V1pprwb = value->rValue; + mod->BSIM3V1pprwbGiven = TRUE; + break; + case BSIM3V1_MOD_PPRWG: + mod->BSIM3V1pprwg = value->rValue; + mod->BSIM3V1pprwgGiven = TRUE; + break; + case BSIM3V1_MOD_PPRT: + mod->BSIM3V1pprt = value->rValue; + mod->BSIM3V1pprtGiven = TRUE; + break; + case BSIM3V1_MOD_PETA0: + mod->BSIM3V1peta0 = value->rValue; + mod->BSIM3V1peta0Given = TRUE; + break; + case BSIM3V1_MOD_PETAB: + mod->BSIM3V1petab = value->rValue; + mod->BSIM3V1petabGiven = TRUE; + break; + case BSIM3V1_MOD_PPCLM: + mod->BSIM3V1ppclm = value->rValue; + mod->BSIM3V1ppclmGiven = TRUE; + break; + case BSIM3V1_MOD_PPDIBL1: + mod->BSIM3V1ppdibl1 = value->rValue; + mod->BSIM3V1ppdibl1Given = TRUE; + break; + case BSIM3V1_MOD_PPDIBL2: + mod->BSIM3V1ppdibl2 = value->rValue; + mod->BSIM3V1ppdibl2Given = TRUE; + break; + case BSIM3V1_MOD_PPDIBLB: + mod->BSIM3V1ppdiblb = value->rValue; + mod->BSIM3V1ppdiblbGiven = TRUE; + break; + case BSIM3V1_MOD_PPSCBE1: + mod->BSIM3V1ppscbe1 = value->rValue; + mod->BSIM3V1ppscbe1Given = TRUE; + break; + case BSIM3V1_MOD_PPSCBE2: + mod->BSIM3V1ppscbe2 = value->rValue; + mod->BSIM3V1ppscbe2Given = TRUE; + break; + case BSIM3V1_MOD_PPVAG: + mod->BSIM3V1ppvag = value->rValue; + mod->BSIM3V1ppvagGiven = TRUE; + break; + case BSIM3V1_MOD_PWR : + mod->BSIM3V1pwr = value->rValue; + mod->BSIM3V1pwrGiven = TRUE; + break; + case BSIM3V1_MOD_PDWG : + mod->BSIM3V1pdwg = value->rValue; + mod->BSIM3V1pdwgGiven = TRUE; + break; + case BSIM3V1_MOD_PDWB : + mod->BSIM3V1pdwb = value->rValue; + mod->BSIM3V1pdwbGiven = TRUE; + break; + case BSIM3V1_MOD_PB0 : + mod->BSIM3V1pb0 = value->rValue; + mod->BSIM3V1pb0Given = TRUE; + break; + case BSIM3V1_MOD_PB1 : + mod->BSIM3V1pb1 = value->rValue; + mod->BSIM3V1pb1Given = TRUE; + break; + case BSIM3V1_MOD_PALPHA0 : + mod->BSIM3V1palpha0 = value->rValue; + mod->BSIM3V1palpha0Given = TRUE; + break; + case BSIM3V1_MOD_PBETA0 : + mod->BSIM3V1pbeta0 = value->rValue; + mod->BSIM3V1pbeta0Given = TRUE; + break; + + case BSIM3V1_MOD_PELM : + mod->BSIM3V1pelm = value->rValue; + mod->BSIM3V1pelmGiven = TRUE; + break; + case BSIM3V1_MOD_PCGSL : + mod->BSIM3V1pcgsl = value->rValue; + mod->BSIM3V1pcgslGiven = TRUE; + break; + case BSIM3V1_MOD_PCGDL : + mod->BSIM3V1pcgdl = value->rValue; + mod->BSIM3V1pcgdlGiven = TRUE; + break; + case BSIM3V1_MOD_PCKAPPA : + mod->BSIM3V1pckappa = value->rValue; + mod->BSIM3V1pckappaGiven = TRUE; + break; + case BSIM3V1_MOD_PCF : + mod->BSIM3V1pcf = value->rValue; + mod->BSIM3V1pcfGiven = TRUE; + break; + case BSIM3V1_MOD_PCLC : + mod->BSIM3V1pclc = value->rValue; + mod->BSIM3V1pclcGiven = TRUE; + break; + case BSIM3V1_MOD_PCLE : + mod->BSIM3V1pcle = value->rValue; + mod->BSIM3V1pcleGiven = TRUE; + break; + case BSIM3V1_MOD_PVFBCV : + mod->BSIM3V1pvfbcv = value->rValue; + mod->BSIM3V1pvfbcvGiven = TRUE; + break; + + case BSIM3V1_MOD_TNOM : + mod->BSIM3V1tnom = value->rValue + 273.15; + mod->BSIM3V1tnomGiven = TRUE; + break; + case BSIM3V1_MOD_CGSO : + mod->BSIM3V1cgso = value->rValue; + mod->BSIM3V1cgsoGiven = TRUE; + break; + case BSIM3V1_MOD_CGDO : + mod->BSIM3V1cgdo = value->rValue; + mod->BSIM3V1cgdoGiven = TRUE; + break; + case BSIM3V1_MOD_CGBO : + mod->BSIM3V1cgbo = value->rValue; + mod->BSIM3V1cgboGiven = TRUE; + break; + case BSIM3V1_MOD_XPART : + mod->BSIM3V1xpart = value->rValue; + mod->BSIM3V1xpartGiven = TRUE; + break; + case BSIM3V1_MOD_RSH : + mod->BSIM3V1sheetResistance = value->rValue; + mod->BSIM3V1sheetResistanceGiven = TRUE; + break; + case BSIM3V1_MOD_JS : + mod->BSIM3V1jctSatCurDensity = value->rValue; + mod->BSIM3V1jctSatCurDensityGiven = TRUE; + break; + case BSIM3V1_MOD_JSW : + mod->BSIM3V1jctSidewallSatCurDensity = value->rValue; + mod->BSIM3V1jctSidewallSatCurDensityGiven = TRUE; + break; + case BSIM3V1_MOD_PB : + mod->BSIM3V1bulkJctPotential = value->rValue; + mod->BSIM3V1bulkJctPotentialGiven = TRUE; + break; + case BSIM3V1_MOD_MJ : + mod->BSIM3V1bulkJctBotGradingCoeff = value->rValue; + mod->BSIM3V1bulkJctBotGradingCoeffGiven = TRUE; + break; + case BSIM3V1_MOD_PBSW : + mod->BSIM3V1sidewallJctPotential = value->rValue; + mod->BSIM3V1sidewallJctPotentialGiven = TRUE; + break; + case BSIM3V1_MOD_MJSW : + mod->BSIM3V1bulkJctSideGradingCoeff = value->rValue; + mod->BSIM3V1bulkJctSideGradingCoeffGiven = TRUE; + break; + case BSIM3V1_MOD_CJ : + mod->BSIM3V1unitAreaJctCap = value->rValue; + mod->BSIM3V1unitAreaJctCapGiven = TRUE; + break; + case BSIM3V1_MOD_CJSW : + mod->BSIM3V1unitLengthSidewallJctCap = value->rValue; + mod->BSIM3V1unitLengthSidewallJctCapGiven = TRUE; + break; + case BSIM3V1_MOD_NJ : + mod->BSIM3V1jctEmissionCoeff = value->rValue; + mod->BSIM3V1jctEmissionCoeffGiven = TRUE; + break; + case BSIM3V1_MOD_PBSWG : + mod->BSIM3V1GatesidewallJctPotential = value->rValue; + mod->BSIM3V1GatesidewallJctPotentialGiven = TRUE; + break; + case BSIM3V1_MOD_MJSWG : + mod->BSIM3V1bulkJctGateSideGradingCoeff = value->rValue; + mod->BSIM3V1bulkJctGateSideGradingCoeffGiven = TRUE; + break; + case BSIM3V1_MOD_CJSWG : + mod->BSIM3V1unitLengthGateSidewallJctCap = value->rValue; + mod->BSIM3V1unitLengthGateSidewallJctCapGiven = TRUE; + break; + case BSIM3V1_MOD_XTI : + mod->BSIM3V1jctTempExponent = value->rValue; + mod->BSIM3V1jctTempExponentGiven = TRUE; + break; + case BSIM3V1_MOD_LINT : + mod->BSIM3V1Lint = value->rValue; + mod->BSIM3V1LintGiven = TRUE; + break; + case BSIM3V1_MOD_LL : + mod->BSIM3V1Ll = value->rValue; + mod->BSIM3V1LlGiven = TRUE; + break; + case BSIM3V1_MOD_LLN : + mod->BSIM3V1Lln = value->rValue; + mod->BSIM3V1LlnGiven = TRUE; + break; + case BSIM3V1_MOD_LW : + mod->BSIM3V1Lw = value->rValue; + mod->BSIM3V1LwGiven = TRUE; + break; + case BSIM3V1_MOD_LWN : + mod->BSIM3V1Lwn = value->rValue; + mod->BSIM3V1LwnGiven = TRUE; + break; + case BSIM3V1_MOD_LWL : + mod->BSIM3V1Lwl = value->rValue; + mod->BSIM3V1LwlGiven = TRUE; + break; + case BSIM3V1_MOD_LMIN : + mod->BSIM3V1Lmin = value->rValue; + mod->BSIM3V1LminGiven = TRUE; + break; + case BSIM3V1_MOD_LMAX : + mod->BSIM3V1Lmax = value->rValue; + mod->BSIM3V1LmaxGiven = TRUE; + break; + case BSIM3V1_MOD_WINT : + mod->BSIM3V1Wint = value->rValue; + mod->BSIM3V1WintGiven = TRUE; + break; + case BSIM3V1_MOD_WL : + mod->BSIM3V1Wl = value->rValue; + mod->BSIM3V1WlGiven = TRUE; + break; + case BSIM3V1_MOD_WLN : + mod->BSIM3V1Wln = value->rValue; + mod->BSIM3V1WlnGiven = TRUE; + break; + case BSIM3V1_MOD_WW : + mod->BSIM3V1Ww = value->rValue; + mod->BSIM3V1WwGiven = TRUE; + break; + case BSIM3V1_MOD_WWN : + mod->BSIM3V1Wwn = value->rValue; + mod->BSIM3V1WwnGiven = TRUE; + break; + case BSIM3V1_MOD_WWL : + mod->BSIM3V1Wwl = value->rValue; + mod->BSIM3V1WwlGiven = TRUE; + break; + case BSIM3V1_MOD_WMIN : + mod->BSIM3V1Wmin = value->rValue; + mod->BSIM3V1WminGiven = TRUE; + break; + case BSIM3V1_MOD_WMAX : + mod->BSIM3V1Wmax = value->rValue; + mod->BSIM3V1WmaxGiven = TRUE; + break; + + case BSIM3V1_MOD_NOIA : + mod->BSIM3V1oxideTrapDensityA = value->rValue; + mod->BSIM3V1oxideTrapDensityAGiven = TRUE; + break; + case BSIM3V1_MOD_NOIB : + mod->BSIM3V1oxideTrapDensityB = value->rValue; + mod->BSIM3V1oxideTrapDensityBGiven = TRUE; + break; + case BSIM3V1_MOD_NOIC : + mod->BSIM3V1oxideTrapDensityC = value->rValue; + mod->BSIM3V1oxideTrapDensityCGiven = TRUE; + break; + case BSIM3V1_MOD_EM : + mod->BSIM3V1em = value->rValue; + mod->BSIM3V1emGiven = TRUE; + break; + case BSIM3V1_MOD_EF : + mod->BSIM3V1ef = value->rValue; + mod->BSIM3V1efGiven = TRUE; + break; + case BSIM3V1_MOD_AF : + mod->BSIM3V1af = value->rValue; + mod->BSIM3V1afGiven = TRUE; + break; + case BSIM3V1_MOD_KF : + mod->BSIM3V1kf = value->rValue; + mod->BSIM3V1kfGiven = TRUE; + break; + case BSIM3V1_MOD_NMOS : + if(value->iValue) { + mod->BSIM3V1type = 1; + mod->BSIM3V1typeGiven = TRUE; + } + break; + case BSIM3V1_MOD_PMOS : + if(value->iValue) { + mod->BSIM3V1type = - 1; + mod->BSIM3V1typeGiven = TRUE; + } + break; +/* serban */ + case BSIM3V1_MOD_HDIF : + mod->BSIM3V1hdif = value->rValue; + mod->BSIM3V1hdifGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3v1/b3v1noi.c b/src/spicelib/devices/bsim3v1/b3v1noi.c new file mode 100644 index 000000000..0f93a8f39 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1noi.c @@ -0,0 +1,399 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:57:51 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Gary W. Ng and Min-Chie Jeng. +File: b3v1noi.c +**********/ + +#include "ngspice.h" +#include +#include +#include "bsim3v1def.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" +#include "const.h" /* jwan */ + +/* + * BSIM3V1noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MOSFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MOSFET's is summed with the variable "OnDens". + */ + +/* + Channel thermal and flicker noises are calculated based on the value + of model->BSIM3V1noiMod. + If model->BSIM3V1noiMod = 1, + Channel thermal noise = SPICE2 model + Flicker noise = SPICE2 model + If model->BSIM3V1noiMod = 2, + Channel thermal noise = BSIM3V1 model + Flicker noise = BSIM3V1 model + If model->BSIM3V1noiMod = 3, + Channel thermal noise = SPICE2 model + Flicker noise = BSIM3V1 model + If model->BSIM3V1noiMod = 4, + Channel thermal noise = BSIM3V1 model + Flicker noise = SPICE2 model + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +double +StrongInversionNoiseEval(vgs, vds, model, here, freq, temp) +double vgs, vds, freq, temp; +BSIM3V1model *model; +BSIM3V1instance *here; +{ +struct bsim3v1SizeDependParam *pParam; +double cd, esat, DelClm, EffFreq, N0, Nl, Vgst; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, Ssi; + + pParam = here->pParam; + cd = fabs(here->BSIM3V1cd); + if (vds > here->BSIM3V1vdsat) + { esat = 2.0 * pParam->BSIM3V1vsattemp / here->BSIM3V1ueff; + T0 = ((((vds - here->BSIM3V1vdsat) / pParam->BSIM3V1litl) + model->BSIM3V1em) + / esat); + DelClm = pParam->BSIM3V1litl * log (MAX(T0, N_MINLOG)); + } + else + DelClm = 0.0; + EffFreq = pow(freq, model->BSIM3V1ef); + T1 = CHARGE * CHARGE * 8.62e-5 * cd * temp * here->BSIM3V1ueff; + T2 = 1.0e8 * EffFreq * model->BSIM3V1cox + * pParam->BSIM3V1leff * pParam->BSIM3V1leff; + Vgst = vgs - here->BSIM3V1von; + N0 = model->BSIM3V1cox * Vgst / CHARGE; + if (N0 < 0.0) + N0 = 0.0; + Nl = model->BSIM3V1cox * (Vgst - MIN(vds, here->BSIM3V1vdsat)) / CHARGE; + if (Nl < 0.0) + Nl = 0.0; + + T3 = model->BSIM3V1oxideTrapDensityA + * log(MAX(((N0 + 2.0e14) / (Nl + 2.0e14)), N_MINLOG)); + T4 = model->BSIM3V1oxideTrapDensityB * (N0 - Nl); + T5 = model->BSIM3V1oxideTrapDensityC * 0.5 * (N0 * N0 - Nl * Nl); + + T6 = 8.62e-5 * temp * cd * cd; + T7 = 1.0e8 * EffFreq * pParam->BSIM3V1leff + * pParam->BSIM3V1leff * pParam->BSIM3V1weff; + T8 = model->BSIM3V1oxideTrapDensityA + model->BSIM3V1oxideTrapDensityB * Nl + + model->BSIM3V1oxideTrapDensityC * Nl * Nl; + T9 = (Nl + 2.0e14) * (Nl + 2.0e14); + + Ssi = T1 / T2 * (T3 + T4 + T5) + T6 / T7 * DelClm * T8 / T9; + return Ssi; +} + +int +BSIM3V1noise (mode, operation, inModel, ckt, data, OnDens) +int mode, operation; +GENmodel *inModel; +CKTcircuit *ckt; +register Ndata *data; +double *OnDens; +{ +register BSIM3V1model *model = (BSIM3V1model *)inModel; +register BSIM3V1instance *here; +struct bsim3v1SizeDependParam *pParam; +char name[N_MXVLNTH]; +double tempOnoise; +double tempInoise; +double noizDens[BSIM3V1NSRCS]; +double lnNdens[BSIM3V1NSRCS]; + +double vgs, vds, Slimit; +double N0, Nl; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13; +double n, ExpArg, Ssi, Swi; + +int error, i; + + /* define the names of the noise sources */ + static char *BSIM3V1nNames[BSIM3V1NSRCS] = + { /* Note that we have to keep the order */ + ".rd", /* noise due to rd */ + /* consistent with the index definitions */ + ".rs", /* noise due to rs */ + /* in BSIM3V1defs.h */ + ".id", /* noise due to id */ + ".1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (; model != NULL; model = model->BSIM3V1nextModel) + { for (here = model->BSIM3V1instances; here != NULL; + here = here->BSIM3V1nextInstance) + { pParam = here->pParam; + switch (operation) + { case N_OPEN: + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { switch (mode) + { case N_DENS: + for (i = 0; i < BSIM3V1NSRCS; i++) + { (void) sprintf(name, "onoise.%s%s", + here->BSIM3V1name, + BSIM3V1nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + } + break; + case INT_NOIZ: + for (i = 0; i < BSIM3V1NSRCS; i++) + { (void) sprintf(name, "onoise_total.%s%s", + here->BSIM3V1name, + BSIM3V1nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + + (void) sprintf(name, "inoise_total.%s%s", + here->BSIM3V1name, + BSIM3V1nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **)NULL); + /* we've added one more plot */ + } + break; + } + } + break; + case N_CALC: + switch (mode) + { case N_DENS: + NevalSrc(&noizDens[BSIM3V1RDNOIZ], + &lnNdens[BSIM3V1RDNOIZ], ckt, THERMNOISE, + here->BSIM3V1dNodePrime, here->BSIM3V1dNode, + here->BSIM3V1drainConductance); + + NevalSrc(&noizDens[BSIM3V1RSNOIZ], + &lnNdens[BSIM3V1RSNOIZ], ckt, THERMNOISE, + here->BSIM3V1sNodePrime, here->BSIM3V1sNode, + here->BSIM3V1sourceConductance); + + switch( model->BSIM3V1noiMod ) + { case 1: + case 3: + NevalSrc(&noizDens[BSIM3V1IDNOIZ], + &lnNdens[BSIM3V1IDNOIZ], ckt, + THERMNOISE, here->BSIM3V1dNodePrime, + here->BSIM3V1sNodePrime, + (2.0 / 3.0 * fabs(here->BSIM3V1gm + + here->BSIM3V1gds + + here->BSIM3V1gmbs))); + break; + case 2: + case 4: + NevalSrc(&noizDens[BSIM3V1IDNOIZ], + &lnNdens[BSIM3V1IDNOIZ], ckt, + THERMNOISE, here->BSIM3V1dNodePrime, + here->BSIM3V1sNodePrime, + (here->BSIM3V1ueff + * fabs(here->BSIM3V1qinv + / (pParam->BSIM3V1leff + * pParam->BSIM3V1leff)))); + break; + } + NevalSrc(&noizDens[BSIM3V1FLNOIZ], (double*) NULL, + ckt, N_GAIN, here->BSIM3V1dNodePrime, + here->BSIM3V1sNodePrime, (double) 0.0); + + switch( model->BSIM3V1noiMod ) + { case 1: + case 4: + noizDens[BSIM3V1FLNOIZ] *= model->BSIM3V1kf + * exp(model->BSIM3V1af + * log(MAX(fabs(here->BSIM3V1cd), + N_MINLOG))) + / (pow(data->freq, model->BSIM3V1ef) + * pParam->BSIM3V1leff + * pParam->BSIM3V1leff + * model->BSIM3V1cox); + break; + case 2: + case 3: + vgs = *(ckt->CKTstates[0] + here->BSIM3V1vgs); + vds = *(ckt->CKTstates[0] + here->BSIM3V1vds); + if (vds < 0.0) + { vds = -vds; + vgs = vgs + vds; + } + if (vgs >= here->BSIM3V1von + 0.1) + { Ssi = StrongInversionNoiseEval(vgs, + vds, model, here, data->freq, + ckt->CKTtemp); + noizDens[BSIM3V1FLNOIZ] *= Ssi; + } + else + { pParam = here->pParam; + T10 = model->BSIM3V1oxideTrapDensityA + * 8.62e-5 * ckt->CKTtemp; + T11 = pParam->BSIM3V1weff + * pParam->BSIM3V1leff + * pow(data->freq, model->BSIM3V1ef) + * 4.0e36; + Swi = T10 / T11 * here->BSIM3V1cd + * here->BSIM3V1cd; + Slimit = StrongInversionNoiseEval( + here->BSIM3V1von + 0.1, vds, model, + here, data->freq, ckt->CKTtemp); + T1 = Swi + Slimit; + if (T1 > 0.0) + noizDens[BSIM3V1FLNOIZ] *= (Slimit + * Swi) / T1; + else + noizDens[BSIM3V1FLNOIZ] *= 0.0; + } + break; + } + + lnNdens[BSIM3V1FLNOIZ] = + log(MAX(noizDens[BSIM3V1FLNOIZ], N_MINLOG)); + + noizDens[BSIM3V1TOTNOIZ] = noizDens[BSIM3V1RDNOIZ] + + noizDens[BSIM3V1RSNOIZ] + + noizDens[BSIM3V1IDNOIZ] + + noizDens[BSIM3V1FLNOIZ]; + lnNdens[BSIM3V1TOTNOIZ] = + log(MAX(noizDens[BSIM3V1TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[BSIM3V1TOTNOIZ]; + + if (data->delFreq == 0.0) + { /* if we haven't done any previous + integration, we need to initialize our + "history" variables. + */ + + for (i = 0; i < BSIM3V1NSRCS; i++) + { here->BSIM3V1nVar[LNLSTDENS][i] = + lnNdens[i]; + } + + /* clear out our integration variables + if it's the first pass + */ + if (data->freq == + ((NOISEAN*) ckt->CKTcurJob)->NstartFreq) + { for (i = 0; i < BSIM3V1NSRCS; i++) + { here->BSIM3V1nVar[OUTNOIZ][i] = 0.0; + here->BSIM3V1nVar[INNOIZ][i] = 0.0; + } + } + } + else + { /* data->delFreq != 0.0, + we have to integrate. + */ + for (i = 0; i < BSIM3V1NSRCS; i++) + { if (i != BSIM3V1TOTNOIZ) + { tempOnoise = Nintegrate(noizDens[i], + lnNdens[i], + here->BSIM3V1nVar[LNLSTDENS][i], + data); + tempInoise = Nintegrate(noizDens[i] + * data->GainSqInv, lnNdens[i] + + data->lnGainInv, + here->BSIM3V1nVar[LNLSTDENS][i] + + data->lnGainInv, data); + here->BSIM3V1nVar[LNLSTDENS][i] = + lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*) + ckt->CKTcurJob)->NStpsSm != 0) + { here->BSIM3V1nVar[OUTNOIZ][i] + += tempOnoise; + here->BSIM3V1nVar[OUTNOIZ][BSIM3V1TOTNOIZ] + += tempOnoise; + here->BSIM3V1nVar[INNOIZ][i] + += tempInoise; + here->BSIM3V1nVar[INNOIZ][BSIM3V1TOTNOIZ] + += tempInoise; + } + } + } + } + if (data->prtSummary) + { for (i = 0; i < BSIM3V1NSRCS; i++) + { /* print a summary report */ + data->outpVector[data->outNumber++] + = noizDens[i]; + } + } + break; + case INT_NOIZ: + /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { for (i = 0; i < BSIM3V1NSRCS; i++) + { data->outpVector[data->outNumber++] + = here->BSIM3V1nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] + = here->BSIM3V1nVar[INNOIZ][i]; + } + } + break; + } + break; + case N_CLOSE: + /* do nothing, the main calling routine will close */ + return (OK); + break; /* the plots */ + } /* switch (operation) */ + } /* for here */ + } /* for model */ + + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1par.c b/src/spicelib/devices/bsim3v1/b3v1par.c new file mode 100644 index 000000000..9aa0be00d --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1par.c @@ -0,0 +1,114 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:58:18 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1par.c +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "bsim3v1def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V1param(param,value,inst,select) +int param; +IFvalue *value; +GENinstance *inst; +IFvalue *select; +{ + BSIM3V1instance *here = (BSIM3V1instance*)inst; + switch(param) + { case BSIM3V1_W: + here->BSIM3V1w = value->rValue; + here->BSIM3V1wGiven = TRUE; + break; + case BSIM3V1_L: + here->BSIM3V1l = value->rValue; + here->BSIM3V1lGiven = TRUE; + break; + case BSIM3V1_AS: + here->BSIM3V1sourceArea = value->rValue; + here->BSIM3V1sourceAreaGiven = TRUE; + break; + case BSIM3V1_AD: + here->BSIM3V1drainArea = value->rValue; + here->BSIM3V1drainAreaGiven = TRUE; + break; + case BSIM3V1_PS: + here->BSIM3V1sourcePerimeter = value->rValue; + here->BSIM3V1sourcePerimeterGiven = TRUE; + break; + case BSIM3V1_PD: + here->BSIM3V1drainPerimeter = value->rValue; + here->BSIM3V1drainPerimeterGiven = TRUE; + break; + case BSIM3V1_NRS: + here->BSIM3V1sourceSquares = value->rValue; + here->BSIM3V1sourceSquaresGiven = TRUE; + break; + case BSIM3V1_NRD: + here->BSIM3V1drainSquares = value->rValue; + here->BSIM3V1drainSquaresGiven = TRUE; + break; + case BSIM3V1_OFF: + here->BSIM3V1off = value->iValue; + break; + case BSIM3V1_M: + here->BSIM3V1m = value->rValue; + break; + case BSIM3V1_IC_VBS: + here->BSIM3V1icVBS = value->rValue; + here->BSIM3V1icVBSGiven = TRUE; + break; + case BSIM3V1_IC_VDS: + here->BSIM3V1icVDS = value->rValue; + here->BSIM3V1icVDSGiven = TRUE; + break; + case BSIM3V1_IC_VGS: + here->BSIM3V1icVGS = value->rValue; + here->BSIM3V1icVGSGiven = TRUE; + break; + case BSIM3V1_NQSMOD: + here->BSIM3V1nqsMod = value->iValue; + here->BSIM3V1nqsModGiven = TRUE; + break; + case BSIM3V1_IC: + switch(value->v.numValue){ + case 3: + here->BSIM3V1icVBS = *(value->v.vec.rVec+2); + here->BSIM3V1icVBSGiven = TRUE; + case 2: + here->BSIM3V1icVGS = *(value->v.vec.rVec+1); + here->BSIM3V1icVGSGiven = TRUE; + case 1: + here->BSIM3V1icVDS = *(value->v.vec.rVec); + here->BSIM3V1icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1pzld.c b/src/spicelib/devices/bsim3v1/b3v1pzld.c new file mode 100644 index 000000000..79a8b0252 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1pzld.c @@ -0,0 +1,162 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:58:46 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1pzld.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "bsim3v1def.h" +#include "suffix.h" + +int +BSIM3V1pzLoad(inModel,ckt,s) +GENmodel *inModel; +register CKTcircuit *ckt; +register SPcomplex *s; +{ +register BSIM3V1model *model = (BSIM3V1model*)inModel; +register BSIM3V1instance *here; +double xcggb, xcgdb, xcgsb, xcbgb, xcbdb, xcbsb, xcddb, xcssb, xcdgb; +double gdpr, gspr, gds, gbd, gbs, capbd, capbs, xcsgb, xcdsb, xcsdb; +double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb; +double GSoverlapCap, GDoverlapCap, GBoverlapCap; +double FwdSum, RevSum, Gm, Gmbs; + + for (; model != NULL; model = model->BSIM3V1nextModel) + { for (here = model->BSIM3V1instances; here!= NULL; + here = here->BSIM3V1nextInstance) + { + if (here->BSIM3V1owner != ARCHme) continue; + if (here->BSIM3V1mode >= 0) + { Gm = here->BSIM3V1gm; + Gmbs = here->BSIM3V1gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + cggb = here->BSIM3V1cggb; + cgsb = here->BSIM3V1cgsb; + cgdb = here->BSIM3V1cgdb; + + cbgb = here->BSIM3V1cbgb; + cbsb = here->BSIM3V1cbsb; + cbdb = here->BSIM3V1cbdb; + + cdgb = here->BSIM3V1cdgb; + cdsb = here->BSIM3V1cdsb; + cddb = here->BSIM3V1cddb; + } + else + { Gm = -here->BSIM3V1gm; + Gmbs = -here->BSIM3V1gmbs; + FwdSum = 0.0; + RevSum = -Gm - Gmbs; + cggb = here->BSIM3V1cggb; + cgsb = here->BSIM3V1cgdb; + cgdb = here->BSIM3V1cgsb; + + cbgb = here->BSIM3V1cbgb; + cbsb = here->BSIM3V1cbdb; + cbdb = here->BSIM3V1cbsb; + + cdgb = -(here->BSIM3V1cdgb + cggb + cbgb); + cdsb = -(here->BSIM3V1cddb + cgsb + cbsb); + cddb = -(here->BSIM3V1cdsb + cgdb + cbdb); + } + gdpr=here->BSIM3V1drainConductance; + gspr=here->BSIM3V1sourceConductance; + gds= here->BSIM3V1gds; + gbd= here->BSIM3V1gbd; + gbs= here->BSIM3V1gbs; + capbd= here->BSIM3V1capbd; + capbs= here->BSIM3V1capbs; + GSoverlapCap = here->BSIM3V1cgso; + GDoverlapCap = here->BSIM3V1cgdo; + GBoverlapCap = here->pParam->BSIM3V1cgbo; + + xcdgb = (cdgb - GDoverlapCap); + xcddb = (cddb + capbd + GDoverlapCap); + xcdsb = cdsb; + xcsgb = -(cggb + cbgb + cdgb + GSoverlapCap); + xcsdb = -(cgdb + cbdb + cddb); + xcssb = (capbs + GSoverlapCap - (cgsb+cbsb+cdsb)); + xcggb = (cggb + GDoverlapCap + GSoverlapCap + GBoverlapCap); + xcgdb = (cgdb - GDoverlapCap); + xcgsb = (cgsb - GSoverlapCap); + xcbgb = (cbgb - GBoverlapCap); + xcbdb = (cbdb - capbd); + xcbsb = (cbsb - capbs); + + + *(here->BSIM3V1GgPtr ) += xcggb * s->real; + *(here->BSIM3V1GgPtr +1) += xcggb * s->imag; + *(here->BSIM3V1BbPtr ) += (-xcbgb-xcbdb-xcbsb) * s->real; + *(here->BSIM3V1BbPtr +1) += (-xcbgb-xcbdb-xcbsb) * s->imag; + *(here->BSIM3V1DPdpPtr ) += xcddb * s->real; + *(here->BSIM3V1DPdpPtr +1) += xcddb * s->imag; + *(here->BSIM3V1SPspPtr ) += xcssb * s->real; + *(here->BSIM3V1SPspPtr +1) += xcssb * s->imag; + *(here->BSIM3V1GbPtr ) += (-xcggb-xcgdb-xcgsb) * s->real; + *(here->BSIM3V1GbPtr +1) += (-xcggb-xcgdb-xcgsb) * s->imag; + *(here->BSIM3V1GdpPtr ) += xcgdb * s->real; + *(here->BSIM3V1GdpPtr +1) += xcgdb * s->imag; + *(here->BSIM3V1GspPtr ) += xcgsb * s->real; + *(here->BSIM3V1GspPtr +1) += xcgsb * s->imag; + *(here->BSIM3V1BgPtr ) += xcbgb * s->real; + *(here->BSIM3V1BgPtr +1) += xcbgb * s->imag; + *(here->BSIM3V1BdpPtr ) += xcbdb * s->real; + *(here->BSIM3V1BdpPtr +1) += xcbdb * s->imag; + *(here->BSIM3V1BspPtr ) += xcbsb * s->real; + *(here->BSIM3V1BspPtr +1) += xcbsb * s->imag; + *(here->BSIM3V1DPgPtr ) += xcdgb * s->real; + *(here->BSIM3V1DPgPtr +1) += xcdgb * s->imag; + *(here->BSIM3V1DPbPtr ) += (-xcdgb-xcddb-xcdsb) * s->real; + *(here->BSIM3V1DPbPtr +1) += (-xcdgb-xcddb-xcdsb) * s->imag; + *(here->BSIM3V1DPspPtr ) += xcdsb * s->real; + *(here->BSIM3V1DPspPtr +1) += xcdsb * s->imag; + *(here->BSIM3V1SPgPtr ) += xcsgb * s->real; + *(here->BSIM3V1SPgPtr +1) += xcsgb * s->imag; + *(here->BSIM3V1SPbPtr ) += (-xcsgb-xcsdb-xcssb) * s->real; + *(here->BSIM3V1SPbPtr +1) += (-xcsgb-xcsdb-xcssb) * s->imag; + *(here->BSIM3V1SPdpPtr ) += xcsdb * s->real; + *(here->BSIM3V1SPdpPtr +1) += xcsdb * s->imag; + *(here->BSIM3V1DdPtr) += gdpr; + *(here->BSIM3V1SsPtr) += gspr; + *(here->BSIM3V1BbPtr) += gbd+gbs; + *(here->BSIM3V1DPdpPtr) += gdpr+gds+gbd+RevSum; + *(here->BSIM3V1SPspPtr) += gspr+gds+gbs+FwdSum; + *(here->BSIM3V1DdpPtr) -= gdpr; + *(here->BSIM3V1SspPtr) -= gspr; + *(here->BSIM3V1BdpPtr) -= gbd; + *(here->BSIM3V1BspPtr) -= gbs; + *(here->BSIM3V1DPdPtr) -= gdpr; + *(here->BSIM3V1DPgPtr) += Gm; + *(here->BSIM3V1DPbPtr) -= gbd - Gmbs; + *(here->BSIM3V1DPspPtr) -= gds + FwdSum; + *(here->BSIM3V1SPgPtr) -= Gm; + *(here->BSIM3V1SPsPtr) -= gspr; + *(here->BSIM3V1SPbPtr) -= gbs + Gmbs; + *(here->BSIM3V1SPdpPtr) -= gds + RevSum; + + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3v1/b3v1set.c b/src/spicelib/devices/bsim3v1/b3v1set.c new file mode 100644 index 000000000..c03093d9d --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1set.c @@ -0,0 +1,948 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:59:17 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1set.c +**********/ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define SMOOTHFACTOR 0.1 +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define PI 3.141592654 +#define Charge_q 1.60219e-19 +#define Meter2Micron 1.0e6 + +int +BSIM3V1setup(matrix,inModel,ckt,states) +register SMPmatrix *matrix; +register GENmodel *inModel; +register CKTcircuit *ckt; +int *states; +{ +register BSIM3V1model *model = (BSIM3V1model*)inModel; +register BSIM3V1instance *here; +int error; +CKTnode *tmp; + +double tmp1, tmp2; + + /* loop through all the BSIM3V1 device models */ + for( ; model != NULL; model = model->BSIM3V1nextModel ) + { +/* Default value Processing for BSIM3V1 MOSFET Models */ + if (!model->BSIM3V1typeGiven) + model->BSIM3V1type = NMOS; + if (!model->BSIM3V1mobModGiven) + model->BSIM3V1mobMod = 1; + if (!model->BSIM3V1binUnitGiven) + model->BSIM3V1binUnit = 1; + if (!model->BSIM3V1paramChkGiven) + model->BSIM3V1paramChk = 0; + if (!model->BSIM3V1capModGiven) + model->BSIM3V1capMod = 2; + if (!model->BSIM3V1nqsModGiven) + model->BSIM3V1nqsMod = 0; + if (!model->BSIM3V1noiModGiven) + model->BSIM3V1noiMod = 1; + if (!model->BSIM3V1versionGiven) + model->BSIM3V1version = 3.1; + if (!model->BSIM3V1toxGiven) + model->BSIM3V1tox = 150.0e-10; + model->BSIM3V1cox = 3.453133e-11 / model->BSIM3V1tox; + + if (!model->BSIM3V1cdscGiven) + model->BSIM3V1cdsc = 2.4e-4; /* unit Q/V/m^2 */ + if (!model->BSIM3V1cdscbGiven) + model->BSIM3V1cdscb = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3V1cdscdGiven) + model->BSIM3V1cdscd = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3V1citGiven) + model->BSIM3V1cit = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3V1nfactorGiven) + model->BSIM3V1nfactor = 1; + if (!model->BSIM3V1xjGiven) + model->BSIM3V1xj = .15e-6; + if (!model->BSIM3V1vsatGiven) + model->BSIM3V1vsat = 8.0e4; /* unit m/s */ + if (!model->BSIM3V1atGiven) + model->BSIM3V1at = 3.3e4; /* unit m/s */ + if (!model->BSIM3V1a0Given) + model->BSIM3V1a0 = 1.0; + if (!model->BSIM3V1agsGiven) + model->BSIM3V1ags = 0.0; + if (!model->BSIM3V1a1Given) + model->BSIM3V1a1 = 0.0; + if (!model->BSIM3V1a2Given) + model->BSIM3V1a2 = 1.0; + if (!model->BSIM3V1ketaGiven) + model->BSIM3V1keta = -0.047; /* unit / V */ + if (!model->BSIM3V1nsubGiven) + model->BSIM3V1nsub = 6.0e16; /* unit 1/cm3 */ + if (!model->BSIM3V1npeakGiven) + model->BSIM3V1npeak = 1.7e17; /* unit 1/cm3 */ + if (!model->BSIM3V1ngateGiven) + model->BSIM3V1ngate = 0; /* unit 1/cm3 */ + if (!model->BSIM3V1vbmGiven) + model->BSIM3V1vbm = -3.0; + if (!model->BSIM3V1xtGiven) + model->BSIM3V1xt = 1.55e-7; + if (!model->BSIM3V1kt1Given) + model->BSIM3V1kt1 = -0.11; /* unit V */ + if (!model->BSIM3V1kt1lGiven) + model->BSIM3V1kt1l = 0.0; /* unit V*m */ + if (!model->BSIM3V1kt2Given) + model->BSIM3V1kt2 = 0.022; /* No unit */ + if (!model->BSIM3V1k3Given) + model->BSIM3V1k3 = 80.0; + if (!model->BSIM3V1k3bGiven) + model->BSIM3V1k3b = 0.0; + if (!model->BSIM3V1w0Given) + model->BSIM3V1w0 = 2.5e-6; + if (!model->BSIM3V1nlxGiven) + model->BSIM3V1nlx = 1.74e-7; + if (!model->BSIM3V1dvt0Given) + model->BSIM3V1dvt0 = 2.2; + if (!model->BSIM3V1dvt1Given) + model->BSIM3V1dvt1 = 0.53; + if (!model->BSIM3V1dvt2Given) + model->BSIM3V1dvt2 = -0.032; /* unit 1 / V */ + + if (!model->BSIM3V1dvt0wGiven) + model->BSIM3V1dvt0w = 0.0; + if (!model->BSIM3V1dvt1wGiven) + model->BSIM3V1dvt1w = 5.3e6; + if (!model->BSIM3V1dvt2wGiven) + model->BSIM3V1dvt2w = -0.032; + + if (!model->BSIM3V1droutGiven) + model->BSIM3V1drout = 0.56; + if (!model->BSIM3V1dsubGiven) + model->BSIM3V1dsub = model->BSIM3V1drout; + if (!model->BSIM3V1vth0Given) + model->BSIM3V1vth0 = (model->BSIM3V1type == NMOS) ? 0.7 : -0.7; + if (!model->BSIM3V1uaGiven) + model->BSIM3V1ua = 2.25e-9; /* unit m/V */ + if (!model->BSIM3V1ua1Given) + model->BSIM3V1ua1 = 4.31e-9; /* unit m/V */ + if (!model->BSIM3V1ubGiven) + model->BSIM3V1ub = 5.87e-19; /* unit (m/V)**2 */ + if (!model->BSIM3V1ub1Given) + model->BSIM3V1ub1 = -7.61e-18; /* unit (m/V)**2 */ + if (!model->BSIM3V1ucGiven) + model->BSIM3V1uc = (model->BSIM3V1mobMod == 3) ? -0.0465 : -0.0465e-9; + if (!model->BSIM3V1uc1Given) + model->BSIM3V1uc1 = (model->BSIM3V1mobMod == 3) ? -0.056 : -0.056e-9; + if (!model->BSIM3V1u0Given) + model->BSIM3V1u0 = (model->BSIM3V1type == NMOS) ? 0.067 : 0.025; + if (!model->BSIM3V1uteGiven) + model->BSIM3V1ute = -1.5; + if (!model->BSIM3V1voffGiven) + model->BSIM3V1voff = -0.08; + if (!model->BSIM3V1deltaGiven) + model->BSIM3V1delta = 0.01; + if (!model->BSIM3V1rdswGiven) + model->BSIM3V1rdsw = 0; + if (!model->BSIM3V1prwgGiven) + model->BSIM3V1prwg = 0.0; /* unit 1/V */ + if (!model->BSIM3V1prwbGiven) + model->BSIM3V1prwb = 0.0; + if (!model->BSIM3V1prtGiven) + if (!model->BSIM3V1prtGiven) + model->BSIM3V1prt = 0.0; + if (!model->BSIM3V1eta0Given) + model->BSIM3V1eta0 = 0.08; /* no unit */ + if (!model->BSIM3V1etabGiven) + model->BSIM3V1etab = -0.07; /* unit 1/V */ + if (!model->BSIM3V1pclmGiven) + model->BSIM3V1pclm = 1.3; /* no unit */ + if (!model->BSIM3V1pdibl1Given) + model->BSIM3V1pdibl1 = .39; /* no unit */ + if (!model->BSIM3V1pdibl2Given) + model->BSIM3V1pdibl2 = 0.0086; /* no unit */ + if (!model->BSIM3V1pdiblbGiven) + model->BSIM3V1pdiblb = 0.0; /* 1/V */ + if (!model->BSIM3V1pscbe1Given) + model->BSIM3V1pscbe1 = 4.24e8; + if (!model->BSIM3V1pscbe2Given) + model->BSIM3V1pscbe2 = 1.0e-5; + if (!model->BSIM3V1pvagGiven) + model->BSIM3V1pvag = 0.0; + if (!model->BSIM3V1wrGiven) + model->BSIM3V1wr = 1.0; + if (!model->BSIM3V1dwgGiven) + model->BSIM3V1dwg = 0.0; + if (!model->BSIM3V1dwbGiven) + model->BSIM3V1dwb = 0.0; + if (!model->BSIM3V1b0Given) + model->BSIM3V1b0 = 0.0; + if (!model->BSIM3V1b1Given) + model->BSIM3V1b1 = 0.0; + if (!model->BSIM3V1alpha0Given) + model->BSIM3V1alpha0 = 0.0; + if (!model->BSIM3V1beta0Given) + model->BSIM3V1beta0 = 30.0; + + if (!model->BSIM3V1elmGiven) + model->BSIM3V1elm = 5.0; + if (!model->BSIM3V1cgslGiven) + model->BSIM3V1cgsl = 0.0; + if (!model->BSIM3V1cgdlGiven) + model->BSIM3V1cgdl = 0.0; + if (!model->BSIM3V1ckappaGiven) + model->BSIM3V1ckappa = 0.6; + if (!model->BSIM3V1clcGiven) + model->BSIM3V1clc = 0.1e-6; + if (!model->BSIM3V1cleGiven) + model->BSIM3V1cle = 0.6; + if (!model->BSIM3V1vfbcvGiven) + model->BSIM3V1vfbcv = -1.0; + + /* Length dependence */ + if (!model->BSIM3V1lcdscGiven) + model->BSIM3V1lcdsc = 0.0; + if (!model->BSIM3V1lcdscbGiven) + model->BSIM3V1lcdscb = 0.0; + if (!model->BSIM3V1lcdscdGiven) + model->BSIM3V1lcdscd = 0.0; + if (!model->BSIM3V1lcitGiven) + model->BSIM3V1lcit = 0.0; + if (!model->BSIM3V1lnfactorGiven) + model->BSIM3V1lnfactor = 0.0; + if (!model->BSIM3V1lxjGiven) + model->BSIM3V1lxj = 0.0; + if (!model->BSIM3V1lvsatGiven) + model->BSIM3V1lvsat = 0.0; + if (!model->BSIM3V1latGiven) + model->BSIM3V1lat = 0.0; + if (!model->BSIM3V1la0Given) + model->BSIM3V1la0 = 0.0; + if (!model->BSIM3V1lagsGiven) + model->BSIM3V1lags = 0.0; + if (!model->BSIM3V1la1Given) + model->BSIM3V1la1 = 0.0; + if (!model->BSIM3V1la2Given) + model->BSIM3V1la2 = 0.0; + if (!model->BSIM3V1lketaGiven) + model->BSIM3V1lketa = 0.0; + if (!model->BSIM3V1lnsubGiven) + model->BSIM3V1lnsub = 0.0; + if (!model->BSIM3V1lnpeakGiven) + model->BSIM3V1lnpeak = 0.0; + if (!model->BSIM3V1lngateGiven) + model->BSIM3V1lngate = 0.0; + if (!model->BSIM3V1lvbmGiven) + model->BSIM3V1lvbm = 0.0; + if (!model->BSIM3V1lxtGiven) + model->BSIM3V1lxt = 0.0; + if (!model->BSIM3V1lkt1Given) + model->BSIM3V1lkt1 = 0.0; + if (!model->BSIM3V1lkt1lGiven) + model->BSIM3V1lkt1l = 0.0; + if (!model->BSIM3V1lkt2Given) + model->BSIM3V1lkt2 = 0.0; + if (!model->BSIM3V1lk3Given) + model->BSIM3V1lk3 = 0.0; + if (!model->BSIM3V1lk3bGiven) + model->BSIM3V1lk3b = 0.0; + if (!model->BSIM3V1lw0Given) + model->BSIM3V1lw0 = 0.0; + if (!model->BSIM3V1lnlxGiven) + model->BSIM3V1lnlx = 0.0; + if (!model->BSIM3V1ldvt0Given) + model->BSIM3V1ldvt0 = 0.0; + if (!model->BSIM3V1ldvt1Given) + model->BSIM3V1ldvt1 = 0.0; + if (!model->BSIM3V1ldvt2Given) + model->BSIM3V1ldvt2 = 0.0; + if (!model->BSIM3V1ldvt0wGiven) + model->BSIM3V1ldvt0w = 0.0; + if (!model->BSIM3V1ldvt1wGiven) + model->BSIM3V1ldvt1w = 0.0; + if (!model->BSIM3V1ldvt2wGiven) + model->BSIM3V1ldvt2w = 0.0; + if (!model->BSIM3V1ldroutGiven) + model->BSIM3V1ldrout = 0.0; + if (!model->BSIM3V1ldsubGiven) + model->BSIM3V1ldsub = 0.0; + if (!model->BSIM3V1lvth0Given) + model->BSIM3V1lvth0 = 0.0; + if (!model->BSIM3V1luaGiven) + model->BSIM3V1lua = 0.0; + if (!model->BSIM3V1lua1Given) + model->BSIM3V1lua1 = 0.0; + if (!model->BSIM3V1lubGiven) + model->BSIM3V1lub = 0.0; + if (!model->BSIM3V1lub1Given) + model->BSIM3V1lub1 = 0.0; + if (!model->BSIM3V1lucGiven) + model->BSIM3V1luc = 0.0; + if (!model->BSIM3V1luc1Given) + model->BSIM3V1luc1 = 0.0; + if (!model->BSIM3V1lu0Given) + model->BSIM3V1lu0 = 0.0; + if (!model->BSIM3V1luteGiven) + model->BSIM3V1lute = 0.0; + if (!model->BSIM3V1lvoffGiven) + model->BSIM3V1lvoff = 0.0; + if (!model->BSIM3V1ldeltaGiven) + model->BSIM3V1ldelta = 0.0; + if (!model->BSIM3V1lrdswGiven) + model->BSIM3V1lrdsw = 0.0; + if (!model->BSIM3V1lprwbGiven) + model->BSIM3V1lprwb = 0.0; + if (!model->BSIM3V1lprwgGiven) + model->BSIM3V1lprwg = 0.0; + if (!model->BSIM3V1lprtGiven) + if (!model->BSIM3V1lprtGiven) + model->BSIM3V1lprt = 0.0; + if (!model->BSIM3V1leta0Given) + model->BSIM3V1leta0 = 0.0; + if (!model->BSIM3V1letabGiven) + model->BSIM3V1letab = -0.0; + if (!model->BSIM3V1lpclmGiven) + model->BSIM3V1lpclm = 0.0; + if (!model->BSIM3V1lpdibl1Given) + model->BSIM3V1lpdibl1 = 0.0; + if (!model->BSIM3V1lpdibl2Given) + model->BSIM3V1lpdibl2 = 0.0; + if (!model->BSIM3V1lpdiblbGiven) + model->BSIM3V1lpdiblb = 0.0; + if (!model->BSIM3V1lpscbe1Given) + model->BSIM3V1lpscbe1 = 0.0; + if (!model->BSIM3V1lpscbe2Given) + model->BSIM3V1lpscbe2 = 0.0; + if (!model->BSIM3V1lpvagGiven) + model->BSIM3V1lpvag = 0.0; + if (!model->BSIM3V1lwrGiven) + model->BSIM3V1lwr = 0.0; + if (!model->BSIM3V1ldwgGiven) + model->BSIM3V1ldwg = 0.0; + if (!model->BSIM3V1ldwbGiven) + model->BSIM3V1ldwb = 0.0; + if (!model->BSIM3V1lb0Given) + model->BSIM3V1lb0 = 0.0; + if (!model->BSIM3V1lb1Given) + model->BSIM3V1lb1 = 0.0; + if (!model->BSIM3V1lalpha0Given) + model->BSIM3V1lalpha0 = 0.0; + if (!model->BSIM3V1lbeta0Given) + model->BSIM3V1lbeta0 = 0.0; + + if (!model->BSIM3V1lelmGiven) + model->BSIM3V1lelm = 0.0; + if (!model->BSIM3V1lcgslGiven) + model->BSIM3V1lcgsl = 0.0; + if (!model->BSIM3V1lcgdlGiven) + model->BSIM3V1lcgdl = 0.0; + if (!model->BSIM3V1lckappaGiven) + model->BSIM3V1lckappa = 0.0; + if (!model->BSIM3V1lclcGiven) + model->BSIM3V1lclc = 0.0; + if (!model->BSIM3V1lcleGiven) + model->BSIM3V1lcle = 0.0; + if (!model->BSIM3V1lcfGiven) + model->BSIM3V1lcf = 0.0; + if (!model->BSIM3V1lvfbcvGiven) + model->BSIM3V1lvfbcv = 0.0; + + /* Width dependence */ + if (!model->BSIM3V1wcdscGiven) + model->BSIM3V1wcdsc = 0.0; + if (!model->BSIM3V1wcdscbGiven) + model->BSIM3V1wcdscb = 0.0; + if (!model->BSIM3V1wcdscdGiven) + model->BSIM3V1wcdscd = 0.0; + if (!model->BSIM3V1wcitGiven) + model->BSIM3V1wcit = 0.0; + if (!model->BSIM3V1wnfactorGiven) + model->BSIM3V1wnfactor = 0.0; + if (!model->BSIM3V1wxjGiven) + model->BSIM3V1wxj = 0.0; + if (!model->BSIM3V1wvsatGiven) + model->BSIM3V1wvsat = 0.0; + if (!model->BSIM3V1watGiven) + model->BSIM3V1wat = 0.0; + if (!model->BSIM3V1wa0Given) + model->BSIM3V1wa0 = 0.0; + if (!model->BSIM3V1wagsGiven) + model->BSIM3V1wags = 0.0; + if (!model->BSIM3V1wa1Given) + model->BSIM3V1wa1 = 0.0; + if (!model->BSIM3V1wa2Given) + model->BSIM3V1wa2 = 0.0; + if (!model->BSIM3V1wketaGiven) + model->BSIM3V1wketa = 0.0; + if (!model->BSIM3V1wnsubGiven) + model->BSIM3V1wnsub = 0.0; + if (!model->BSIM3V1wnpeakGiven) + model->BSIM3V1wnpeak = 0.0; + if (!model->BSIM3V1wngateGiven) + model->BSIM3V1wngate = 0.0; + if (!model->BSIM3V1wvbmGiven) + model->BSIM3V1wvbm = 0.0; + if (!model->BSIM3V1wxtGiven) + model->BSIM3V1wxt = 0.0; + if (!model->BSIM3V1wkt1Given) + model->BSIM3V1wkt1 = 0.0; + if (!model->BSIM3V1wkt1lGiven) + model->BSIM3V1wkt1l = 0.0; + if (!model->BSIM3V1wkt2Given) + model->BSIM3V1wkt2 = 0.0; + if (!model->BSIM3V1wk3Given) + model->BSIM3V1wk3 = 0.0; + if (!model->BSIM3V1wk3bGiven) + model->BSIM3V1wk3b = 0.0; + if (!model->BSIM3V1ww0Given) + model->BSIM3V1ww0 = 0.0; + if (!model->BSIM3V1wnlxGiven) + model->BSIM3V1wnlx = 0.0; + if (!model->BSIM3V1wdvt0Given) + model->BSIM3V1wdvt0 = 0.0; + if (!model->BSIM3V1wdvt1Given) + model->BSIM3V1wdvt1 = 0.0; + if (!model->BSIM3V1wdvt2Given) + model->BSIM3V1wdvt2 = 0.0; + if (!model->BSIM3V1wdvt0wGiven) + model->BSIM3V1wdvt0w = 0.0; + if (!model->BSIM3V1wdvt1wGiven) + model->BSIM3V1wdvt1w = 0.0; + if (!model->BSIM3V1wdvt2wGiven) + model->BSIM3V1wdvt2w = 0.0; + if (!model->BSIM3V1wdroutGiven) + model->BSIM3V1wdrout = 0.0; + if (!model->BSIM3V1wdsubGiven) + model->BSIM3V1wdsub = 0.0; + if (!model->BSIM3V1wvth0Given) + model->BSIM3V1wvth0 = 0.0; + if (!model->BSIM3V1wuaGiven) + model->BSIM3V1wua = 0.0; + if (!model->BSIM3V1wua1Given) + model->BSIM3V1wua1 = 0.0; + if (!model->BSIM3V1wubGiven) + model->BSIM3V1wub = 0.0; + if (!model->BSIM3V1wub1Given) + model->BSIM3V1wub1 = 0.0; + if (!model->BSIM3V1wucGiven) + model->BSIM3V1wuc = 0.0; + if (!model->BSIM3V1wuc1Given) + model->BSIM3V1wuc1 = 0.0; + if (!model->BSIM3V1wu0Given) + model->BSIM3V1wu0 = 0.0; + if (!model->BSIM3V1wuteGiven) + model->BSIM3V1wute = 0.0; + if (!model->BSIM3V1wvoffGiven) + model->BSIM3V1wvoff = 0.0; + if (!model->BSIM3V1wdeltaGiven) + model->BSIM3V1wdelta = 0.0; + if (!model->BSIM3V1wrdswGiven) + model->BSIM3V1wrdsw = 0.0; + if (!model->BSIM3V1wprwbGiven) + model->BSIM3V1wprwb = 0.0; + if (!model->BSIM3V1wprwgGiven) + model->BSIM3V1wprwg = 0.0; + if (!model->BSIM3V1wprtGiven) + model->BSIM3V1wprt = 0.0; + if (!model->BSIM3V1weta0Given) + model->BSIM3V1weta0 = 0.0; + if (!model->BSIM3V1wetabGiven) + model->BSIM3V1wetab = 0.0; + if (!model->BSIM3V1wpclmGiven) + model->BSIM3V1wpclm = 0.0; + if (!model->BSIM3V1wpdibl1Given) + model->BSIM3V1wpdibl1 = 0.0; + if (!model->BSIM3V1wpdibl2Given) + model->BSIM3V1wpdibl2 = 0.0; + if (!model->BSIM3V1wpdiblbGiven) + model->BSIM3V1wpdiblb = 0.0; + if (!model->BSIM3V1wpscbe1Given) + model->BSIM3V1wpscbe1 = 0.0; + if (!model->BSIM3V1wpscbe2Given) + model->BSIM3V1wpscbe2 = 0.0; + if (!model->BSIM3V1wpvagGiven) + model->BSIM3V1wpvag = 0.0; + if (!model->BSIM3V1wwrGiven) + model->BSIM3V1wwr = 0.0; + if (!model->BSIM3V1wdwgGiven) + model->BSIM3V1wdwg = 0.0; + if (!model->BSIM3V1wdwbGiven) + model->BSIM3V1wdwb = 0.0; + if (!model->BSIM3V1wb0Given) + model->BSIM3V1wb0 = 0.0; + if (!model->BSIM3V1wb1Given) + model->BSIM3V1wb1 = 0.0; + if (!model->BSIM3V1walpha0Given) + model->BSIM3V1walpha0 = 0.0; + if (!model->BSIM3V1wbeta0Given) + model->BSIM3V1wbeta0 = 0.0; + + if (!model->BSIM3V1welmGiven) + model->BSIM3V1welm = 0.0; + if (!model->BSIM3V1wcgslGiven) + model->BSIM3V1wcgsl = 0.0; + if (!model->BSIM3V1wcgdlGiven) + model->BSIM3V1wcgdl = 0.0; + if (!model->BSIM3V1wckappaGiven) + model->BSIM3V1wckappa = 0.0; + if (!model->BSIM3V1wcfGiven) + model->BSIM3V1wcf = 0.0; + if (!model->BSIM3V1wclcGiven) + model->BSIM3V1wclc = 0.0; + if (!model->BSIM3V1wcleGiven) + model->BSIM3V1wcle = 0.0; + if (!model->BSIM3V1wvfbcvGiven) + model->BSIM3V1wvfbcv = 0.0; + + /* Cross-term dependence */ + if (!model->BSIM3V1pcdscGiven) + model->BSIM3V1pcdsc = 0.0; + if (!model->BSIM3V1pcdscbGiven) + model->BSIM3V1pcdscb = 0.0; + if (!model->BSIM3V1pcdscdGiven) + model->BSIM3V1pcdscd = 0.0; + if (!model->BSIM3V1pcitGiven) + model->BSIM3V1pcit = 0.0; + if (!model->BSIM3V1pnfactorGiven) + model->BSIM3V1pnfactor = 0.0; + if (!model->BSIM3V1pxjGiven) + model->BSIM3V1pxj = 0.0; + if (!model->BSIM3V1pvsatGiven) + model->BSIM3V1pvsat = 0.0; + if (!model->BSIM3V1patGiven) + model->BSIM3V1pat = 0.0; + if (!model->BSIM3V1pa0Given) + model->BSIM3V1pa0 = 0.0; + + if (!model->BSIM3V1pagsGiven) + model->BSIM3V1pags = 0.0; + if (!model->BSIM3V1pa1Given) + model->BSIM3V1pa1 = 0.0; + if (!model->BSIM3V1pa2Given) + model->BSIM3V1pa2 = 0.0; + if (!model->BSIM3V1pketaGiven) + model->BSIM3V1pketa = 0.0; + if (!model->BSIM3V1pnsubGiven) + model->BSIM3V1pnsub = 0.0; + if (!model->BSIM3V1pnpeakGiven) + model->BSIM3V1pnpeak = 0.0; + if (!model->BSIM3V1pngateGiven) + model->BSIM3V1pngate = 0.0; + if (!model->BSIM3V1pvbmGiven) + model->BSIM3V1pvbm = 0.0; + if (!model->BSIM3V1pxtGiven) + model->BSIM3V1pxt = 0.0; + if (!model->BSIM3V1pkt1Given) + model->BSIM3V1pkt1 = 0.0; + if (!model->BSIM3V1pkt1lGiven) + model->BSIM3V1pkt1l = 0.0; + if (!model->BSIM3V1pkt2Given) + model->BSIM3V1pkt2 = 0.0; + if (!model->BSIM3V1pk3Given) + model->BSIM3V1pk3 = 0.0; + if (!model->BSIM3V1pk3bGiven) + model->BSIM3V1pk3b = 0.0; + if (!model->BSIM3V1pw0Given) + model->BSIM3V1pw0 = 0.0; + if (!model->BSIM3V1pnlxGiven) + model->BSIM3V1pnlx = 0.0; + if (!model->BSIM3V1pdvt0Given) + model->BSIM3V1pdvt0 = 0.0; + if (!model->BSIM3V1pdvt1Given) + model->BSIM3V1pdvt1 = 0.0; + if (!model->BSIM3V1pdvt2Given) + model->BSIM3V1pdvt2 = 0.0; + if (!model->BSIM3V1pdvt0wGiven) + model->BSIM3V1pdvt0w = 0.0; + if (!model->BSIM3V1pdvt1wGiven) + model->BSIM3V1pdvt1w = 0.0; + if (!model->BSIM3V1pdvt2wGiven) + model->BSIM3V1pdvt2w = 0.0; + if (!model->BSIM3V1pdroutGiven) + model->BSIM3V1pdrout = 0.0; + if (!model->BSIM3V1pdsubGiven) + model->BSIM3V1pdsub = 0.0; + if (!model->BSIM3V1pvth0Given) + model->BSIM3V1pvth0 = 0.0; + if (!model->BSIM3V1puaGiven) + model->BSIM3V1pua = 0.0; + if (!model->BSIM3V1pua1Given) + model->BSIM3V1pua1 = 0.0; + if (!model->BSIM3V1pubGiven) + model->BSIM3V1pub = 0.0; + if (!model->BSIM3V1pub1Given) + model->BSIM3V1pub1 = 0.0; + if (!model->BSIM3V1pucGiven) + model->BSIM3V1puc = 0.0; + if (!model->BSIM3V1puc1Given) + model->BSIM3V1puc1 = 0.0; + if (!model->BSIM3V1pu0Given) + model->BSIM3V1pu0 = 0.0; + if (!model->BSIM3V1puteGiven) + model->BSIM3V1pute = 0.0; + if (!model->BSIM3V1pvoffGiven) + model->BSIM3V1pvoff = 0.0; + if (!model->BSIM3V1pdeltaGiven) + model->BSIM3V1pdelta = 0.0; + if (!model->BSIM3V1prdswGiven) + model->BSIM3V1prdsw = 0.0; + if (!model->BSIM3V1pprwbGiven) + model->BSIM3V1pprwb = 0.0; + if (!model->BSIM3V1pprwgGiven) + model->BSIM3V1pprwg = 0.0; + if (!model->BSIM3V1pprtGiven) + model->BSIM3V1pprt = 0.0; + if (!model->BSIM3V1peta0Given) + model->BSIM3V1peta0 = 0.0; + if (!model->BSIM3V1petabGiven) + model->BSIM3V1petab = 0.0; + if (!model->BSIM3V1ppclmGiven) + model->BSIM3V1ppclm = 0.0; + if (!model->BSIM3V1ppdibl1Given) + model->BSIM3V1ppdibl1 = 0.0; + if (!model->BSIM3V1ppdibl2Given) + model->BSIM3V1ppdibl2 = 0.0; + if (!model->BSIM3V1ppdiblbGiven) + model->BSIM3V1ppdiblb = 0.0; + if (!model->BSIM3V1ppscbe1Given) + model->BSIM3V1ppscbe1 = 0.0; + if (!model->BSIM3V1ppscbe2Given) + model->BSIM3V1ppscbe2 = 0.0; + if (!model->BSIM3V1ppvagGiven) + model->BSIM3V1ppvag = 0.0; + if (!model->BSIM3V1pwrGiven) + model->BSIM3V1pwr = 0.0; + if (!model->BSIM3V1pdwgGiven) + model->BSIM3V1pdwg = 0.0; + if (!model->BSIM3V1pdwbGiven) + model->BSIM3V1pdwb = 0.0; + if (!model->BSIM3V1pb0Given) + model->BSIM3V1pb0 = 0.0; + if (!model->BSIM3V1pb1Given) + model->BSIM3V1pb1 = 0.0; + if (!model->BSIM3V1palpha0Given) + model->BSIM3V1palpha0 = 0.0; + if (!model->BSIM3V1pbeta0Given) + model->BSIM3V1pbeta0 = 0.0; + + if (!model->BSIM3V1pelmGiven) + model->BSIM3V1pelm = 0.0; + if (!model->BSIM3V1pcgslGiven) + model->BSIM3V1pcgsl = 0.0; + if (!model->BSIM3V1pcgdlGiven) + model->BSIM3V1pcgdl = 0.0; + if (!model->BSIM3V1pckappaGiven) + model->BSIM3V1pckappa = 0.0; + if (!model->BSIM3V1pcfGiven) + model->BSIM3V1pcf = 0.0; + if (!model->BSIM3V1pclcGiven) + model->BSIM3V1pclc = 0.0; + if (!model->BSIM3V1pcleGiven) + model->BSIM3V1pcle = 0.0; + if (!model->BSIM3V1pvfbcvGiven) + model->BSIM3V1pvfbcv = 0.0; + + /* unit degree celcius */ + if (!model->BSIM3V1tnomGiven) + model->BSIM3V1tnom = ckt->CKTnomTemp; + if (!model->BSIM3V1LintGiven) + model->BSIM3V1Lint = 0.0; + if (!model->BSIM3V1LlGiven) + model->BSIM3V1Ll = 0.0; + if (!model->BSIM3V1LlnGiven) + model->BSIM3V1Lln = 1.0; + if (!model->BSIM3V1LwGiven) + model->BSIM3V1Lw = 0.0; + if (!model->BSIM3V1LwnGiven) + model->BSIM3V1Lwn = 1.0; + if (!model->BSIM3V1LwlGiven) + model->BSIM3V1Lwl = 0.0; + if (!model->BSIM3V1LminGiven) + model->BSIM3V1Lmin = 0.0; + if (!model->BSIM3V1LmaxGiven) + model->BSIM3V1Lmax = 1.0; + if (!model->BSIM3V1WintGiven) + model->BSIM3V1Wint = 0.0; + if (!model->BSIM3V1WlGiven) + model->BSIM3V1Wl = 0.0; + if (!model->BSIM3V1WlnGiven) + model->BSIM3V1Wln = 1.0; + if (!model->BSIM3V1WwGiven) + model->BSIM3V1Ww = 0.0; + if (!model->BSIM3V1WwnGiven) + model->BSIM3V1Wwn = 1.0; + if (!model->BSIM3V1WwlGiven) + model->BSIM3V1Wwl = 0.0; + if (!model->BSIM3V1WminGiven) + model->BSIM3V1Wmin = 0.0; + if (!model->BSIM3V1WmaxGiven) + model->BSIM3V1Wmax = 1.0; + if (!model->BSIM3V1dwcGiven) + model->BSIM3V1dwc = model->BSIM3V1Wint; + if (!model->BSIM3V1dlcGiven) + model->BSIM3V1dlc = model->BSIM3V1Lint; + if (!model->BSIM3V1cfGiven) + model->BSIM3V1cf = 2.0 * EPSOX / PI + * log(1.0 + 0.4e-6 / model->BSIM3V1tox); + if (!model->BSIM3V1cgdoGiven) + { if (model->BSIM3V1dlcGiven && (model->BSIM3V1dlc > 0.0)) + { model->BSIM3V1cgdo = model->BSIM3V1dlc * model->BSIM3V1cox + - model->BSIM3V1cgdl ; + } + else + model->BSIM3V1cgdo = 0.6 * model->BSIM3V1xj * model->BSIM3V1cox; + } + if (!model->BSIM3V1cgsoGiven) + { if (model->BSIM3V1dlcGiven && (model->BSIM3V1dlc > 0.0)) + { model->BSIM3V1cgso = model->BSIM3V1dlc * model->BSIM3V1cox + - model->BSIM3V1cgsl ; + } + else + model->BSIM3V1cgso = 0.6 * model->BSIM3V1xj * model->BSIM3V1cox; + } + + if (!model->BSIM3V1cgboGiven) + { model->BSIM3V1cgbo = 2.0 * model->BSIM3V1dwc * model->BSIM3V1cox; + } + if (!model->BSIM3V1xpartGiven) + model->BSIM3V1xpart = 0.0; + if (!model->BSIM3V1sheetResistanceGiven) + model->BSIM3V1sheetResistance = 0.0; + if (!model->BSIM3V1unitAreaJctCapGiven) + model->BSIM3V1unitAreaJctCap = 5.0E-4; + if (!model->BSIM3V1unitLengthSidewallJctCapGiven) + model->BSIM3V1unitLengthSidewallJctCap = 5.0E-10; + if (!model->BSIM3V1unitLengthGateSidewallJctCapGiven) + model->BSIM3V1unitLengthGateSidewallJctCap = model->BSIM3V1unitLengthSidewallJctCap ; + if (!model->BSIM3V1jctSatCurDensityGiven) + model->BSIM3V1jctSatCurDensity = 1.0E-4; + if (!model->BSIM3V1jctSidewallSatCurDensityGiven) + model->BSIM3V1jctSidewallSatCurDensity = 0.0; + if (!model->BSIM3V1bulkJctPotentialGiven) + model->BSIM3V1bulkJctPotential = 1.0; + if (!model->BSIM3V1sidewallJctPotentialGiven) + model->BSIM3V1sidewallJctPotential = 1.0; + if (!model->BSIM3V1GatesidewallJctPotentialGiven) + model->BSIM3V1GatesidewallJctPotential = model->BSIM3V1sidewallJctPotential; + if (!model->BSIM3V1bulkJctBotGradingCoeffGiven) + model->BSIM3V1bulkJctBotGradingCoeff = 0.5; + if (!model->BSIM3V1bulkJctSideGradingCoeffGiven) + model->BSIM3V1bulkJctSideGradingCoeff = 0.33; + if (!model->BSIM3V1bulkJctGateSideGradingCoeffGiven) + model->BSIM3V1bulkJctGateSideGradingCoeff = model->BSIM3V1bulkJctSideGradingCoeff; + if (!model->BSIM3V1jctEmissionCoeffGiven) + model->BSIM3V1jctEmissionCoeff = 1.0; + if (!model->BSIM3V1jctTempExponentGiven) + model->BSIM3V1jctTempExponent = 3.0; + if (!model->BSIM3V1oxideTrapDensityAGiven) + if (!model->BSIM3V1oxideTrapDensityAGiven) + { if (model->BSIM3V1type == NMOS) + model->BSIM3V1oxideTrapDensityA = 1e20; + else + model->BSIM3V1oxideTrapDensityA=9.9e18; + } + if (!model->BSIM3V1oxideTrapDensityBGiven) + { if (model->BSIM3V1type == NMOS) + model->BSIM3V1oxideTrapDensityB = 5e4; + else + model->BSIM3V1oxideTrapDensityB = 2.4e3; + } + if (!model->BSIM3V1oxideTrapDensityCGiven) + { if (model->BSIM3V1type == NMOS) + model->BSIM3V1oxideTrapDensityC = -1.4e-12; + else + model->BSIM3V1oxideTrapDensityC = 1.4e-12; + + } + if (!model->BSIM3V1emGiven) + model->BSIM3V1em = 4.1e7; /* V/m */ + if (!model->BSIM3V1efGiven) + model->BSIM3V1ef = 1.0; + if (!model->BSIM3V1afGiven) + model->BSIM3V1af = 1.0; + if (!model->BSIM3V1kfGiven) + model->BSIM3V1kf = 0.0; + /* loop through all the instances of the model */ + for (here = model->BSIM3V1instances; here != NULL ; + here=here->BSIM3V1nextInstance) + + { + if (here->BSIM3V1owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->BSIM3V1states = *states; + *states += BSIM3V1numStates; + } + /* perform the parameter defaulting */ + if(here->BSIM3V1m == 0.0) + here->BSIM3V1m = 1.0; + fprintf(stderr, "M = %.2f\n", here->BSIM3V1m); + if (!here->BSIM3V1wGiven) + here->BSIM3V1w = 5e-6; + here->BSIM3V1w *= here->BSIM3V1m; + + if (!here->BSIM3V1drainAreaGiven) + { + if(model->BSIM3V1hdifGiven) + here->BSIM3V1drainArea = here->BSIM3V1w * 2 * model->BSIM3V1hdif; + else + here->BSIM3V1drainArea = 0.0; + } + here->BSIM3V1drainArea *= here->BSIM3V1m; + if (!here->BSIM3V1drainPerimeterGiven) + { + if(model->BSIM3V1hdifGiven) + here->BSIM3V1drainPerimeter = + 2 * here->BSIM3V1w + 4 * model->BSIM3V1hdif; + else + here->BSIM3V1drainPerimeter = 0.0; + } + here->BSIM3V1drainPerimeter *= here->BSIM3V1m; + + if (!here->BSIM3V1drainSquaresGiven) + here->BSIM3V1drainSquares = 1.0; + here->BSIM3V1drainSquares /= here->BSIM3V1m; + + if (!here->BSIM3V1icVBSGiven) + here->BSIM3V1icVBS = 0; + if (!here->BSIM3V1icVDSGiven) + here->BSIM3V1icVDS = 0; + if (!here->BSIM3V1icVGSGiven) + here->BSIM3V1icVGS = 0; + if (!here->BSIM3V1lGiven) + here->BSIM3V1l = 5e-6; + if (!here->BSIM3V1sourceAreaGiven) + { + if(model->BSIM3V1hdifGiven) + here->BSIM3V1sourceArea = here->BSIM3V1w * 2 * model->BSIM3V1hdif; + else + here->BSIM3V1sourceArea = 0.0; + } + here->BSIM3V1sourceArea *= here->BSIM3V1m; + + if (!here->BSIM3V1sourcePerimeterGiven) + { + if(model->BSIM3V1hdifGiven) + here->BSIM3V1sourcePerimeter = + 2 * here->BSIM3V1w + 4 * model->BSIM3V1hdif; + else + here->BSIM3V1sourcePerimeter = 0.0; + } + here->BSIM3V1sourcePerimeter *= here->BSIM3V1m; + + if (!here->BSIM3V1sourceSquaresGiven) + here->BSIM3V1sourceSquares = 1.0; + here->BSIM3V1sourceSquares /= here->BSIM3V1m; + + if (!here->BSIM3V1nqsModGiven) + here->BSIM3V1nqsMod = model->BSIM3V1nqsMod; + + /* process drain series resistance */ + if ((model->BSIM3V1sheetResistance > 0.0) && + (here->BSIM3V1drainSquares > 0.0 ) && + (here->BSIM3V1dNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3V1name,"drain"); + if(error) return(error); + here->BSIM3V1dNodePrime = tmp->number; + } + else + { here->BSIM3V1dNodePrime = here->BSIM3V1dNode; + } + + /* process source series resistance */ + if ((model->BSIM3V1sheetResistance > 0.0) && + (here->BSIM3V1sourceSquares > 0.0 ) && + (here->BSIM3V1sNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3V1name,"source"); + if(error) return(error); + here->BSIM3V1sNodePrime = tmp->number; + } + else + { here->BSIM3V1sNodePrime = here->BSIM3V1sNode; + } + + /* internal charge node */ + + if ((here->BSIM3V1nqsMod) && (here->BSIM3V1qNode == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3V1name,"charge"); + if(error) return(error); + here->BSIM3V1qNode = tmp->number; + } + else + { here->BSIM3V1qNode = 0; + } + + /* set Sparse Matrix Pointers */ + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(BSIM3V1DdPtr, BSIM3V1dNode, BSIM3V1dNode) + TSTALLOC(BSIM3V1GgPtr, BSIM3V1gNode, BSIM3V1gNode) + TSTALLOC(BSIM3V1SsPtr, BSIM3V1sNode, BSIM3V1sNode) + TSTALLOC(BSIM3V1BbPtr, BSIM3V1bNode, BSIM3V1bNode) + TSTALLOC(BSIM3V1DPdpPtr, BSIM3V1dNodePrime, BSIM3V1dNodePrime) + TSTALLOC(BSIM3V1SPspPtr, BSIM3V1sNodePrime, BSIM3V1sNodePrime) + TSTALLOC(BSIM3V1DdpPtr, BSIM3V1dNode, BSIM3V1dNodePrime) + TSTALLOC(BSIM3V1GbPtr, BSIM3V1gNode, BSIM3V1bNode) + TSTALLOC(BSIM3V1GdpPtr, BSIM3V1gNode, BSIM3V1dNodePrime) + TSTALLOC(BSIM3V1GspPtr, BSIM3V1gNode, BSIM3V1sNodePrime) + TSTALLOC(BSIM3V1SspPtr, BSIM3V1sNode, BSIM3V1sNodePrime) + TSTALLOC(BSIM3V1BdpPtr, BSIM3V1bNode, BSIM3V1dNodePrime) + TSTALLOC(BSIM3V1BspPtr, BSIM3V1bNode, BSIM3V1sNodePrime) + TSTALLOC(BSIM3V1DPspPtr, BSIM3V1dNodePrime, BSIM3V1sNodePrime) + TSTALLOC(BSIM3V1DPdPtr, BSIM3V1dNodePrime, BSIM3V1dNode) + TSTALLOC(BSIM3V1BgPtr, BSIM3V1bNode, BSIM3V1gNode) + TSTALLOC(BSIM3V1DPgPtr, BSIM3V1dNodePrime, BSIM3V1gNode) + TSTALLOC(BSIM3V1SPgPtr, BSIM3V1sNodePrime, BSIM3V1gNode) + TSTALLOC(BSIM3V1SPsPtr, BSIM3V1sNodePrime, BSIM3V1sNode) + TSTALLOC(BSIM3V1DPbPtr, BSIM3V1dNodePrime, BSIM3V1bNode) + TSTALLOC(BSIM3V1SPbPtr, BSIM3V1sNodePrime, BSIM3V1bNode) + TSTALLOC(BSIM3V1SPdpPtr, BSIM3V1sNodePrime, BSIM3V1dNodePrime) + + TSTALLOC(BSIM3V1QqPtr, BSIM3V1qNode, BSIM3V1qNode) + + TSTALLOC(BSIM3V1QdpPtr, BSIM3V1qNode, BSIM3V1dNodePrime) + TSTALLOC(BSIM3V1QspPtr, BSIM3V1qNode, BSIM3V1sNodePrime) + TSTALLOC(BSIM3V1QgPtr, BSIM3V1qNode, BSIM3V1gNode) + TSTALLOC(BSIM3V1QbPtr, BSIM3V1qNode, BSIM3V1bNode) + TSTALLOC(BSIM3V1DPqPtr, BSIM3V1dNodePrime, BSIM3V1qNode) + TSTALLOC(BSIM3V1SPqPtr, BSIM3V1sNodePrime, BSIM3V1qNode) + TSTALLOC(BSIM3V1GqPtr, BSIM3V1gNode, BSIM3V1qNode) + TSTALLOC(BSIM3V1BqPtr, BSIM3V1bNode, BSIM3V1qNode) + + } + } + return(OK); +} + + + + + diff --git a/src/spicelib/devices/bsim3v1/b3v1temp.c b/src/spicelib/devices/bsim3v1/b3v1temp.c new file mode 100644 index 000000000..938b7e26d --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1temp.c @@ -0,0 +1,685 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 19:59:49 yuhua + * BSIM3v3.1 release + + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/*********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1temp.c +**********/ +/* Lmin, Lmax, Wmin, Wmax */ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +#define Kb 1.3806226e-23 +#define KboQ 8.617087e-5 /* Kb / q where q = 1.60219e-19 */ +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define PI 3.141592654 +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define Charge_q 1.60219e-19 + + +/* ARGSUSED */ +int +BSIM3V1temp(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +register BSIM3V1model *model = (BSIM3V1model*) inModel; +register BSIM3V1instance *here; +struct bsim3v1SizeDependParam *pSizeDependParamKnot, *pLastKnot, *pParam; +double tmp, tmp1, tmp2, Eg, Eg0, ni, T0, T1, T2, T3, T4, T5, Ldrn, Wdrn; +double Temp, TRatio, Inv_L, Inv_W, Inv_LW, Dw, Dl, Vtm0, Tnom; +int Size_Not_Found; + + /* loop through all the BSIM3V1 device models */ + for (; model != NULL; model = model->BSIM3V1nextModel) + { Temp = ckt->CKTtemp; + if (model->BSIM3V1bulkJctPotential < 0.1) + model->BSIM3V1bulkJctPotential = 0.1; + if (model->BSIM3V1sidewallJctPotential < 0.1) + model->BSIM3V1sidewallJctPotential = 0.1; + if (model->BSIM3V1GatesidewallJctPotential < 0.1) + model->BSIM3V1GatesidewallJctPotential = 0.1; + model->pSizeDependParamKnot = NULL; + pLastKnot = NULL; + + Tnom = model->BSIM3V1tnom; + TRatio = Temp / Tnom; + + model->BSIM3V1vcrit = CONSTvt0 * log(CONSTvt0 / (CONSTroot2 * 1.0e-14)); + model->BSIM3V1factor1 = sqrt(EPSSI / EPSOX * model->BSIM3V1tox); + + Vtm0 = KboQ * Tnom; + Eg0 = 1.16 - 7.02e-4 * Tnom * Tnom / (Tnom + 1108.0); + ni = 1.45e10 * (Tnom / 300.15) * sqrt(Tnom / 300.15) + * exp(21.5565981 - Eg0 / (2.0 * Vtm0)); + + model->BSIM3V1vtm = KboQ * Temp; + Eg = 1.16 - 7.02e-4 * Temp * Temp / (Temp + 1108.0); + if (Temp != Tnom) + { T0 = Eg0 / Vtm0 - Eg / model->BSIM3V1vtm + model->BSIM3V1jctTempExponent + * log(Temp / Tnom); + T1 = exp(T0 / model->BSIM3V1jctEmissionCoeff); + model->BSIM3V1jctTempSatCurDensity = model->BSIM3V1jctSatCurDensity + * T1; + model->BSIM3V1jctSidewallTempSatCurDensity + = model->BSIM3V1jctSidewallSatCurDensity * T1; + } + else + { model->BSIM3V1jctTempSatCurDensity = model->BSIM3V1jctSatCurDensity; + model->BSIM3V1jctSidewallTempSatCurDensity + = model->BSIM3V1jctSidewallSatCurDensity; + } + + if (model->BSIM3V1jctTempSatCurDensity < 0.0) + model->BSIM3V1jctTempSatCurDensity = 0.0; + if (model->BSIM3V1jctSidewallTempSatCurDensity < 0.0) + model->BSIM3V1jctSidewallTempSatCurDensity = 0.0; + + /* loop through all the instances of the model */ + /* MCJ: Length and Width not initialized */ + for (here = model->BSIM3V1instances; here != NULL; + here = here->BSIM3V1nextInstance) + { + if (here->BSIM3V1owner != ARCHme) continue; + pSizeDependParamKnot = model->pSizeDependParamKnot; + Size_Not_Found = 1; + while ((pSizeDependParamKnot != NULL) && Size_Not_Found) + { if ((here->BSIM3V1l == pSizeDependParamKnot->Length) + && (here->BSIM3V1w == pSizeDependParamKnot->Width)) + { Size_Not_Found = 0; + here->pParam = pSizeDependParamKnot; + } + else + { pLastKnot = pSizeDependParamKnot; + pSizeDependParamKnot = pSizeDependParamKnot->pNext; + } + } + + if (Size_Not_Found) + { pParam = (struct bsim3v1SizeDependParam *)malloc( + sizeof(struct bsim3v1SizeDependParam)); + if (pLastKnot == NULL) + model->pSizeDependParamKnot = pParam; + else + pLastKnot->pNext = pParam; + pParam->pNext = NULL; + here->pParam = pParam; + + Ldrn = here->BSIM3V1l; + Wdrn = here->BSIM3V1w; + pParam->Length = Ldrn; + pParam->Width = Wdrn; + + T0 = pow(Ldrn, model->BSIM3V1Lln); + T1 = pow(Wdrn, model->BSIM3V1Lwn); + tmp1 = model->BSIM3V1Ll / T0 + model->BSIM3V1Lw / T1 + + model->BSIM3V1Lwl / (T0 * T1); + pParam->BSIM3V1dl = model->BSIM3V1Lint + tmp1; + pParam->BSIM3V1dlc = model->BSIM3V1dlc + tmp1; + + T2 = pow(Ldrn, model->BSIM3V1Wln); + T3 = pow(Wdrn, model->BSIM3V1Wwn); + tmp2 = model->BSIM3V1Wl / T2 + model->BSIM3V1Ww / T3 + + model->BSIM3V1Wwl / (T2 * T3); + pParam->BSIM3V1dw = model->BSIM3V1Wint + tmp2; + pParam->BSIM3V1dwc = model->BSIM3V1dwc + tmp2; + + pParam->BSIM3V1leff = here->BSIM3V1l - 2.0 * pParam->BSIM3V1dl; + if (pParam->BSIM3V1leff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V1modName; + namarray[1] = here->BSIM3V1name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V1: mosfet %s, model %s: Effective channel length <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3V1weff = here->BSIM3V1w - 2.0 * pParam->BSIM3V1dw; + if (pParam->BSIM3V1weff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V1modName; + namarray[1] = here->BSIM3V1name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V1: mosfet %s, model %s: Effective channel width <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3V1leffCV = here->BSIM3V1l - 2.0 * pParam->BSIM3V1dlc; + if (pParam->BSIM3V1leffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V1modName; + namarray[1] = here->BSIM3V1name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V1: mosfet %s, model %s: Effective channel length for C-V <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3V1weffCV = here->BSIM3V1w - 2.0 * pParam->BSIM3V1dwc; + if (pParam->BSIM3V1weffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V1modName; + namarray[1] = here->BSIM3V1name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V1: mosfet %s, model %s: Effective channel width for C-V <= 0", + namarray); + return(E_BADPARM); + } + + + if (model->BSIM3V1binUnit == 1) + { Inv_L = 1.0e-6 / pParam->BSIM3V1leff; + Inv_W = 1.0e-6 / pParam->BSIM3V1weff; + Inv_LW = 1.0e-12 / (pParam->BSIM3V1leff + * pParam->BSIM3V1weff); + } + else + { Inv_L = 1.0 / pParam->BSIM3V1leff; + Inv_W = 1.0 / pParam->BSIM3V1weff; + Inv_LW = 1.0 / (pParam->BSIM3V1leff + * pParam->BSIM3V1weff); + } + pParam->BSIM3V1cdsc = model->BSIM3V1cdsc + + model->BSIM3V1lcdsc * Inv_L + + model->BSIM3V1wcdsc * Inv_W + + model->BSIM3V1pcdsc * Inv_LW; + pParam->BSIM3V1cdscb = model->BSIM3V1cdscb + + model->BSIM3V1lcdscb * Inv_L + + model->BSIM3V1wcdscb * Inv_W + + model->BSIM3V1pcdscb * Inv_LW; + + pParam->BSIM3V1cdscd = model->BSIM3V1cdscd + + model->BSIM3V1lcdscd * Inv_L + + model->BSIM3V1wcdscd * Inv_W + + model->BSIM3V1pcdscd * Inv_LW; + + pParam->BSIM3V1cit = model->BSIM3V1cit + + model->BSIM3V1lcit * Inv_L + + model->BSIM3V1wcit * Inv_W + + model->BSIM3V1pcit * Inv_LW; + pParam->BSIM3V1nfactor = model->BSIM3V1nfactor + + model->BSIM3V1lnfactor * Inv_L + + model->BSIM3V1wnfactor * Inv_W + + model->BSIM3V1pnfactor * Inv_LW; + pParam->BSIM3V1xj = model->BSIM3V1xj + + model->BSIM3V1lxj * Inv_L + + model->BSIM3V1wxj * Inv_W + + model->BSIM3V1pxj * Inv_LW; + pParam->BSIM3V1vsat = model->BSIM3V1vsat + + model->BSIM3V1lvsat * Inv_L + + model->BSIM3V1wvsat * Inv_W + + model->BSIM3V1pvsat * Inv_LW; + pParam->BSIM3V1at = model->BSIM3V1at + + model->BSIM3V1lat * Inv_L + + model->BSIM3V1wat * Inv_W + + model->BSIM3V1pat * Inv_LW; + pParam->BSIM3V1a0 = model->BSIM3V1a0 + + model->BSIM3V1la0 * Inv_L + + model->BSIM3V1wa0 * Inv_W + + model->BSIM3V1pa0 * Inv_LW; + + pParam->BSIM3V1ags = model->BSIM3V1ags + + model->BSIM3V1lags * Inv_L + + model->BSIM3V1wags * Inv_W + + model->BSIM3V1pags * Inv_LW; + + pParam->BSIM3V1a1 = model->BSIM3V1a1 + + model->BSIM3V1la1 * Inv_L + + model->BSIM3V1wa1 * Inv_W + + model->BSIM3V1pa1 * Inv_LW; + pParam->BSIM3V1a2 = model->BSIM3V1a2 + + model->BSIM3V1la2 * Inv_L + + model->BSIM3V1wa2 * Inv_W + + model->BSIM3V1pa2 * Inv_LW; + pParam->BSIM3V1keta = model->BSIM3V1keta + + model->BSIM3V1lketa * Inv_L + + model->BSIM3V1wketa * Inv_W + + model->BSIM3V1pketa * Inv_LW; + pParam->BSIM3V1nsub = model->BSIM3V1nsub + + model->BSIM3V1lnsub * Inv_L + + model->BSIM3V1wnsub * Inv_W + + model->BSIM3V1pnsub * Inv_LW; + pParam->BSIM3V1npeak = model->BSIM3V1npeak + + model->BSIM3V1lnpeak * Inv_L + + model->BSIM3V1wnpeak * Inv_W + + model->BSIM3V1pnpeak * Inv_LW; + pParam->BSIM3V1ngate = model->BSIM3V1ngate + + model->BSIM3V1lngate * Inv_L + + model->BSIM3V1wngate * Inv_W + + model->BSIM3V1pngate * Inv_LW; + pParam->BSIM3V1gamma1 = model->BSIM3V1gamma1 + + model->BSIM3V1lgamma1 * Inv_L + + model->BSIM3V1wgamma1 * Inv_W + + model->BSIM3V1pgamma1 * Inv_LW; + pParam->BSIM3V1gamma2 = model->BSIM3V1gamma2 + + model->BSIM3V1lgamma2 * Inv_L + + model->BSIM3V1wgamma2 * Inv_W + + model->BSIM3V1pgamma2 * Inv_LW; + pParam->BSIM3V1vbx = model->BSIM3V1vbx + + model->BSIM3V1lvbx * Inv_L + + model->BSIM3V1wvbx * Inv_W + + model->BSIM3V1pvbx * Inv_LW; + pParam->BSIM3V1vbm = model->BSIM3V1vbm + + model->BSIM3V1lvbm * Inv_L + + model->BSIM3V1wvbm * Inv_W + + model->BSIM3V1pvbm * Inv_LW; + pParam->BSIM3V1xt = model->BSIM3V1xt + + model->BSIM3V1lxt * Inv_L + + model->BSIM3V1wxt * Inv_W + + model->BSIM3V1pxt * Inv_LW; + pParam->BSIM3V1k1 = model->BSIM3V1k1 + + model->BSIM3V1lk1 * Inv_L + + model->BSIM3V1wk1 * Inv_W + + model->BSIM3V1pk1 * Inv_LW; + pParam->BSIM3V1kt1 = model->BSIM3V1kt1 + + model->BSIM3V1lkt1 * Inv_L + + model->BSIM3V1wkt1 * Inv_W + + model->BSIM3V1pkt1 * Inv_LW; + pParam->BSIM3V1kt1l = model->BSIM3V1kt1l + + model->BSIM3V1lkt1l * Inv_L + + model->BSIM3V1wkt1l * Inv_W + + model->BSIM3V1pkt1l * Inv_LW; + pParam->BSIM3V1k2 = model->BSIM3V1k2 + + model->BSIM3V1lk2 * Inv_L + + model->BSIM3V1wk2 * Inv_W + + model->BSIM3V1pk2 * Inv_LW; + pParam->BSIM3V1kt2 = model->BSIM3V1kt2 + + model->BSIM3V1lkt2 * Inv_L + + model->BSIM3V1wkt2 * Inv_W + + model->BSIM3V1pkt2 * Inv_LW; + pParam->BSIM3V1k3 = model->BSIM3V1k3 + + model->BSIM3V1lk3 * Inv_L + + model->BSIM3V1wk3 * Inv_W + + model->BSIM3V1pk3 * Inv_LW; + pParam->BSIM3V1k3b = model->BSIM3V1k3b + + model->BSIM3V1lk3b * Inv_L + + model->BSIM3V1wk3b * Inv_W + + model->BSIM3V1pk3b * Inv_LW; + pParam->BSIM3V1w0 = model->BSIM3V1w0 + + model->BSIM3V1lw0 * Inv_L + + model->BSIM3V1ww0 * Inv_W + + model->BSIM3V1pw0 * Inv_LW; + pParam->BSIM3V1nlx = model->BSIM3V1nlx + + model->BSIM3V1lnlx * Inv_L + + model->BSIM3V1wnlx * Inv_W + + model->BSIM3V1pnlx * Inv_LW; + pParam->BSIM3V1dvt0 = model->BSIM3V1dvt0 + + model->BSIM3V1ldvt0 * Inv_L + + model->BSIM3V1wdvt0 * Inv_W + + model->BSIM3V1pdvt0 * Inv_LW; + pParam->BSIM3V1dvt1 = model->BSIM3V1dvt1 + + model->BSIM3V1ldvt1 * Inv_L + + model->BSIM3V1wdvt1 * Inv_W + + model->BSIM3V1pdvt1 * Inv_LW; + pParam->BSIM3V1dvt2 = model->BSIM3V1dvt2 + + model->BSIM3V1ldvt2 * Inv_L + + model->BSIM3V1wdvt2 * Inv_W + + model->BSIM3V1pdvt2 * Inv_LW; + pParam->BSIM3V1dvt0w = model->BSIM3V1dvt0w + + model->BSIM3V1ldvt0w * Inv_L + + model->BSIM3V1wdvt0w * Inv_W + + model->BSIM3V1pdvt0w * Inv_LW; + pParam->BSIM3V1dvt1w = model->BSIM3V1dvt1w + + model->BSIM3V1ldvt1w * Inv_L + + model->BSIM3V1wdvt1w * Inv_W + + model->BSIM3V1pdvt1w * Inv_LW; + pParam->BSIM3V1dvt2w = model->BSIM3V1dvt2w + + model->BSIM3V1ldvt2w * Inv_L + + model->BSIM3V1wdvt2w * Inv_W + + model->BSIM3V1pdvt2w * Inv_LW; + pParam->BSIM3V1drout = model->BSIM3V1drout + + model->BSIM3V1ldrout * Inv_L + + model->BSIM3V1wdrout * Inv_W + + model->BSIM3V1pdrout * Inv_LW; + pParam->BSIM3V1dsub = model->BSIM3V1dsub + + model->BSIM3V1ldsub * Inv_L + + model->BSIM3V1wdsub * Inv_W + + model->BSIM3V1pdsub * Inv_LW; + pParam->BSIM3V1vth0 = model->BSIM3V1vth0 + + model->BSIM3V1lvth0 * Inv_L + + model->BSIM3V1wvth0 * Inv_W + + model->BSIM3V1pvth0 * Inv_LW; + pParam->BSIM3V1ua = model->BSIM3V1ua + + model->BSIM3V1lua * Inv_L + + model->BSIM3V1wua * Inv_W + + model->BSIM3V1pua * Inv_LW; + pParam->BSIM3V1ua1 = model->BSIM3V1ua1 + + model->BSIM3V1lua1 * Inv_L + + model->BSIM3V1wua1 * Inv_W + + model->BSIM3V1pua1 * Inv_LW; + pParam->BSIM3V1ub = model->BSIM3V1ub + + model->BSIM3V1lub * Inv_L + + model->BSIM3V1wub * Inv_W + + model->BSIM3V1pub * Inv_LW; + pParam->BSIM3V1ub1 = model->BSIM3V1ub1 + + model->BSIM3V1lub1 * Inv_L + + model->BSIM3V1wub1 * Inv_W + + model->BSIM3V1pub1 * Inv_LW; + pParam->BSIM3V1uc = model->BSIM3V1uc + + model->BSIM3V1luc * Inv_L + + model->BSIM3V1wuc * Inv_W + + model->BSIM3V1puc * Inv_LW; + pParam->BSIM3V1uc1 = model->BSIM3V1uc1 + + model->BSIM3V1luc1 * Inv_L + + model->BSIM3V1wuc1 * Inv_W + + model->BSIM3V1puc1 * Inv_LW; + pParam->BSIM3V1u0 = model->BSIM3V1u0 + + model->BSIM3V1lu0 * Inv_L + + model->BSIM3V1wu0 * Inv_W + + model->BSIM3V1pu0 * Inv_LW; + pParam->BSIM3V1ute = model->BSIM3V1ute + + model->BSIM3V1lute * Inv_L + + model->BSIM3V1wute * Inv_W + + model->BSIM3V1pute * Inv_LW; + pParam->BSIM3V1voff = model->BSIM3V1voff + + model->BSIM3V1lvoff * Inv_L + + model->BSIM3V1wvoff * Inv_W + + model->BSIM3V1pvoff * Inv_LW; + pParam->BSIM3V1delta = model->BSIM3V1delta + + model->BSIM3V1ldelta * Inv_L + + model->BSIM3V1wdelta * Inv_W + + model->BSIM3V1pdelta * Inv_LW; + pParam->BSIM3V1rdsw = model->BSIM3V1rdsw + + model->BSIM3V1lrdsw * Inv_L + + model->BSIM3V1wrdsw * Inv_W + + model->BSIM3V1prdsw * Inv_LW; + pParam->BSIM3V1prwg = model->BSIM3V1prwg + + model->BSIM3V1lprwg * Inv_L + + model->BSIM3V1wprwg * Inv_W + + model->BSIM3V1pprwg * Inv_LW; + pParam->BSIM3V1prwb = model->BSIM3V1prwb + + model->BSIM3V1lprwb * Inv_L + + model->BSIM3V1wprwb * Inv_W + + model->BSIM3V1pprwb * Inv_LW; + pParam->BSIM3V1prt = model->BSIM3V1prt + + model->BSIM3V1lprt * Inv_L + + model->BSIM3V1wprt * Inv_W + + model->BSIM3V1pprt * Inv_LW; + pParam->BSIM3V1eta0 = model->BSIM3V1eta0 + + model->BSIM3V1leta0 * Inv_L + + model->BSIM3V1weta0 * Inv_W + + model->BSIM3V1peta0 * Inv_LW; + pParam->BSIM3V1etab = model->BSIM3V1etab + + model->BSIM3V1letab * Inv_L + + model->BSIM3V1wetab * Inv_W + + model->BSIM3V1petab * Inv_LW; + pParam->BSIM3V1pclm = model->BSIM3V1pclm + + model->BSIM3V1lpclm * Inv_L + + model->BSIM3V1wpclm * Inv_W + + model->BSIM3V1ppclm * Inv_LW; + pParam->BSIM3V1pdibl1 = model->BSIM3V1pdibl1 + + model->BSIM3V1lpdibl1 * Inv_L + + model->BSIM3V1wpdibl1 * Inv_W + + model->BSIM3V1ppdibl1 * Inv_LW; + pParam->BSIM3V1pdibl2 = model->BSIM3V1pdibl2 + + model->BSIM3V1lpdibl2 * Inv_L + + model->BSIM3V1wpdibl2 * Inv_W + + model->BSIM3V1ppdibl2 * Inv_LW; + pParam->BSIM3V1pdiblb = model->BSIM3V1pdiblb + + model->BSIM3V1lpdiblb * Inv_L + + model->BSIM3V1wpdiblb * Inv_W + + model->BSIM3V1ppdiblb * Inv_LW; + pParam->BSIM3V1pscbe1 = model->BSIM3V1pscbe1 + + model->BSIM3V1lpscbe1 * Inv_L + + model->BSIM3V1wpscbe1 * Inv_W + + model->BSIM3V1ppscbe1 * Inv_LW; + pParam->BSIM3V1pscbe2 = model->BSIM3V1pscbe2 + + model->BSIM3V1lpscbe2 * Inv_L + + model->BSIM3V1wpscbe2 * Inv_W + + model->BSIM3V1ppscbe2 * Inv_LW; + pParam->BSIM3V1pvag = model->BSIM3V1pvag + + model->BSIM3V1lpvag * Inv_L + + model->BSIM3V1wpvag * Inv_W + + model->BSIM3V1ppvag * Inv_LW; + pParam->BSIM3V1wr = model->BSIM3V1wr + + model->BSIM3V1lwr * Inv_L + + model->BSIM3V1wwr * Inv_W + + model->BSIM3V1pwr * Inv_LW; + pParam->BSIM3V1dwg = model->BSIM3V1dwg + + model->BSIM3V1ldwg * Inv_L + + model->BSIM3V1wdwg * Inv_W + + model->BSIM3V1pdwg * Inv_LW; + pParam->BSIM3V1dwb = model->BSIM3V1dwb + + model->BSIM3V1ldwb * Inv_L + + model->BSIM3V1wdwb * Inv_W + + model->BSIM3V1pdwb * Inv_LW; + pParam->BSIM3V1b0 = model->BSIM3V1b0 + + model->BSIM3V1lb0 * Inv_L + + model->BSIM3V1wb0 * Inv_W + + model->BSIM3V1pb0 * Inv_LW; + pParam->BSIM3V1b1 = model->BSIM3V1b1 + + model->BSIM3V1lb1 * Inv_L + + model->BSIM3V1wb1 * Inv_W + + model->BSIM3V1pb1 * Inv_LW; + pParam->BSIM3V1alpha0 = model->BSIM3V1alpha0 + + model->BSIM3V1lalpha0 * Inv_L + + model->BSIM3V1walpha0 * Inv_W + + model->BSIM3V1palpha0 * Inv_LW; + pParam->BSIM3V1beta0 = model->BSIM3V1beta0 + + model->BSIM3V1lbeta0 * Inv_L + + model->BSIM3V1wbeta0 * Inv_W + + model->BSIM3V1pbeta0 * Inv_LW; + /* CV model */ + pParam->BSIM3V1elm = model->BSIM3V1elm + + model->BSIM3V1lelm * Inv_L + + model->BSIM3V1welm * Inv_W + + model->BSIM3V1pelm * Inv_LW; + pParam->BSIM3V1cgsl = model->BSIM3V1cgsl + + model->BSIM3V1lcgsl * Inv_L + + model->BSIM3V1wcgsl * Inv_W + + model->BSIM3V1pcgsl * Inv_LW; + pParam->BSIM3V1cgdl = model->BSIM3V1cgdl + + model->BSIM3V1lcgdl * Inv_L + + model->BSIM3V1wcgdl * Inv_W + + model->BSIM3V1pcgdl * Inv_LW; + pParam->BSIM3V1ckappa = model->BSIM3V1ckappa + + model->BSIM3V1lckappa * Inv_L + + model->BSIM3V1wckappa * Inv_W + + model->BSIM3V1pckappa * Inv_LW; + pParam->BSIM3V1cf = model->BSIM3V1cf + + model->BSIM3V1lcf * Inv_L + + model->BSIM3V1wcf * Inv_W + + model->BSIM3V1pcf * Inv_LW; + pParam->BSIM3V1clc = model->BSIM3V1clc + + model->BSIM3V1lclc * Inv_L + + model->BSIM3V1wclc * Inv_W + + model->BSIM3V1pclc * Inv_LW; + pParam->BSIM3V1cle = model->BSIM3V1cle + + model->BSIM3V1lcle * Inv_L + + model->BSIM3V1wcle * Inv_W + + model->BSIM3V1pcle * Inv_LW; + pParam->BSIM3V1vfbcv = model->BSIM3V1vfbcv + + model->BSIM3V1lvfbcv * Inv_L + + model->BSIM3V1wvfbcv * Inv_W + + model->BSIM3V1pvfbcv * Inv_LW; + pParam->BSIM3V1abulkCVfactor = 1.0 + pow((pParam->BSIM3V1clc + / pParam->BSIM3V1leff), + pParam->BSIM3V1cle); + + T0 = (TRatio - 1.0); + pParam->BSIM3V1ua = pParam->BSIM3V1ua + pParam->BSIM3V1ua1 * T0; + pParam->BSIM3V1ub = pParam->BSIM3V1ub + pParam->BSIM3V1ub1 * T0; + pParam->BSIM3V1uc = pParam->BSIM3V1uc + pParam->BSIM3V1uc1 * T0; + if (pParam->BSIM3V1u0 > 1.0) + pParam->BSIM3V1u0 = pParam->BSIM3V1u0 / 1.0e4; + + pParam->BSIM3V1u0temp = pParam->BSIM3V1u0 + * pow(TRatio, pParam->BSIM3V1ute); + pParam->BSIM3V1vsattemp = pParam->BSIM3V1vsat - pParam->BSIM3V1at + * T0; + pParam->BSIM3V1rds0 = (pParam->BSIM3V1rdsw + pParam->BSIM3V1prt * T0) + / pow(pParam->BSIM3V1weff * 1E6, pParam->BSIM3V1wr); + + if (BSIM3V1checkModel(model, here, ckt)) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V1modName; + namarray[1] = here->BSIM3V1name; + (*(SPfrontEnd->IFerror)) (ERR_FATAL, "Fatal error(s) detected during BSIM3V1V3 parameter checking for %s in model %s", namarray); + return(E_BADPARM); + } + + pParam->BSIM3V1cgdo = (model->BSIM3V1cgdo + pParam->BSIM3V1cf) + * pParam->BSIM3V1weffCV; + pParam->BSIM3V1cgso = (model->BSIM3V1cgso + pParam->BSIM3V1cf) + * pParam->BSIM3V1weffCV; + pParam->BSIM3V1cgbo = model->BSIM3V1cgbo * pParam->BSIM3V1leffCV; + + if (!model->BSIM3V1npeakGiven && model->BSIM3V1gamma1Given) + { T0 = pParam->BSIM3V1gamma1 * model->BSIM3V1cox; + pParam->BSIM3V1npeak = 3.021E22 * T0 * T0; + } + + pParam->BSIM3V1phi = 2.0 * Vtm0 + * log(pParam->BSIM3V1npeak / ni); + + pParam->BSIM3V1sqrtPhi = sqrt(pParam->BSIM3V1phi); + pParam->BSIM3V1phis3 = pParam->BSIM3V1sqrtPhi * pParam->BSIM3V1phi; + + pParam->BSIM3V1Xdep0 = sqrt(2.0 * EPSSI / (Charge_q + * pParam->BSIM3V1npeak * 1.0e6)) + * pParam->BSIM3V1sqrtPhi; + pParam->BSIM3V1sqrtXdep0 = sqrt(pParam->BSIM3V1Xdep0); + pParam->BSIM3V1litl = sqrt(3.0 * pParam->BSIM3V1xj + * model->BSIM3V1tox); + pParam->BSIM3V1vbi = Vtm0 * log(1.0e20 + * pParam->BSIM3V1npeak / (ni * ni)); + pParam->BSIM3V1cdep0 = sqrt(Charge_q * EPSSI + * pParam->BSIM3V1npeak * 1.0e6 / 2.0 + / pParam->BSIM3V1phi); + + if (model->BSIM3V1k1Given || model->BSIM3V1k2Given) + { if (!model->BSIM3V1k1Given) + { fprintf(stdout, "Warning: k1 should be specified with k2.\n"); + pParam->BSIM3V1k1 = 0.53; + } + if (!model->BSIM3V1k2Given) + { fprintf(stdout, "Warning: k2 should be specified with k1.\n"); + pParam->BSIM3V1k2 = -0.0186; + } + if (model->BSIM3V1nsubGiven) + fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V1xtGiven) + fprintf(stdout, "Warning: xt is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V1vbxGiven) + fprintf(stdout, "Warning: vbx is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V1vbmGiven) + fprintf(stdout, "Warning: vbm is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V1gamma1Given) + fprintf(stdout, "Warning: gamma1 is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V1gamma2Given) + fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n"); + } + else + { if (!model->BSIM3V1vbxGiven) + pParam->BSIM3V1vbx = pParam->BSIM3V1phi - 7.7348e-4 + * pParam->BSIM3V1npeak + * pParam->BSIM3V1xt * pParam->BSIM3V1xt; + if (pParam->BSIM3V1vbx > 0.0) + pParam->BSIM3V1vbx = -pParam->BSIM3V1vbx; + if (pParam->BSIM3V1vbm > 0.0) + pParam->BSIM3V1vbm = -pParam->BSIM3V1vbm; + + if (!model->BSIM3V1gamma1Given) + pParam->BSIM3V1gamma1 = 5.753e-12 + * sqrt(pParam->BSIM3V1npeak) + / model->BSIM3V1cox; + if (!model->BSIM3V1gamma2Given) + pParam->BSIM3V1gamma2 = 5.753e-12 + * sqrt(pParam->BSIM3V1nsub) + / model->BSIM3V1cox; + + T0 = pParam->BSIM3V1gamma1 - pParam->BSIM3V1gamma2; + T1 = sqrt(pParam->BSIM3V1phi - pParam->BSIM3V1vbx) + - pParam->BSIM3V1sqrtPhi; + T2 = sqrt(pParam->BSIM3V1phi * (pParam->BSIM3V1phi + - pParam->BSIM3V1vbm)) - pParam->BSIM3V1phi; + pParam->BSIM3V1k2 = T0 * T1 / (2.0 * T2 + pParam->BSIM3V1vbm); + pParam->BSIM3V1k1 = pParam->BSIM3V1gamma2 - 2.0 + * pParam->BSIM3V1k2 * sqrt(pParam->BSIM3V1phi + - pParam->BSIM3V1vbm); + } + + if (pParam->BSIM3V1k2 < 0.0) + { T0 = 0.5 * pParam->BSIM3V1k1 / pParam->BSIM3V1k2; + pParam->BSIM3V1vbsc = 0.9 * (pParam->BSIM3V1phi - T0 * T0); + if (pParam->BSIM3V1vbsc > -3.0) + pParam->BSIM3V1vbsc = -3.0; + else if (pParam->BSIM3V1vbsc < -30.0) + pParam->BSIM3V1vbsc = -30.0; + } + else + { pParam->BSIM3V1vbsc = -30.0; + } + if (pParam->BSIM3V1vbsc > pParam->BSIM3V1vbm) + pParam->BSIM3V1vbsc = pParam->BSIM3V1vbm; + + if (model->BSIM3V1vth0Given) + { pParam->BSIM3V1vfb = model->BSIM3V1type * pParam->BSIM3V1vth0 + - pParam->BSIM3V1phi - pParam->BSIM3V1k1 + * pParam->BSIM3V1sqrtPhi; + } + else + { pParam->BSIM3V1vfb = -1.0; + pParam->BSIM3V1vth0 = model->BSIM3V1type * (pParam->BSIM3V1vfb + + pParam->BSIM3V1phi + pParam->BSIM3V1k1 + * pParam->BSIM3V1sqrtPhi); + } + T1 = sqrt(EPSSI / EPSOX * model->BSIM3V1tox + * pParam->BSIM3V1Xdep0); + T0 = exp(-0.5 * pParam->BSIM3V1dsub * pParam->BSIM3V1leff / T1); + pParam->BSIM3V1theta0vb0 = (T0 + 2.0 * T0 * T0); + + T0 = exp(-0.5 * pParam->BSIM3V1drout * pParam->BSIM3V1leff / T1); + T2 = (T0 + 2.0 * T0 * T0); + pParam->BSIM3V1thetaRout = pParam->BSIM3V1pdibl1 * T2 + + pParam->BSIM3V1pdibl2; + } + + /* process source/drain series resistance */ + here->BSIM3V1drainConductance = model->BSIM3V1sheetResistance + * here->BSIM3V1drainSquares; + if (here->BSIM3V1drainConductance > 0.0) + here->BSIM3V1drainConductance = 1.0 + / here->BSIM3V1drainConductance; + else + here->BSIM3V1drainConductance = 0.0; + + here->BSIM3V1sourceConductance = model->BSIM3V1sheetResistance + * here->BSIM3V1sourceSquares; + if (here->BSIM3V1sourceConductance > 0.0) + here->BSIM3V1sourceConductance = 1.0 + / here->BSIM3V1sourceConductance; + else + here->BSIM3V1sourceConductance = 0.0; + here->BSIM3V1cgso = pParam->BSIM3V1cgso; + here->BSIM3V1cgdo = pParam->BSIM3V1cgdo; + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim3v1/b3v1trunc.c b/src/spicelib/devices/bsim3v1/b3v1trunc.c new file mode 100644 index 000000000..ec86d0d3d --- /dev/null +++ b/src/spicelib/devices/bsim3v1/b3v1trunc.c @@ -0,0 +1,64 @@ +/* $Id$ */ +/* +$Log$ +Revision 1.1 2000-04-27 20:03:59 pnenzi +Initial revision + + * Revision 3.1 96/12/08 20:00:16 yuhua + * BSIM3v3.1 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v1trunc.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v1def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V1trunc(inModel,ckt,timeStep) +GENmodel *inModel; +register CKTcircuit *ckt; +double *timeStep; +{ +register BSIM3V1model *model = (BSIM3V1model*)inModel; +register BSIM3V1instance *here; + +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + + for (; model != NULL; model = model->BSIM3V1nextModel) + { for (here = model->BSIM3V1instances; here != NULL; + here = here->BSIM3V1nextInstance) + { + if (here->BSIM3V1owner != ARCHme) continue; +#ifdef STEPDEBUG + debugtemp = *timeStep; +#endif /* STEPDEBUG */ + CKTterr(here->BSIM3V1qb,ckt,timeStep); + CKTterr(here->BSIM3V1qg,ckt,timeStep); + CKTterr(here->BSIM3V1qd,ckt,timeStep); +#ifdef STEPDEBUG + if(debugtemp != *timeStep) + { printf("device %s reduces step from %g to %g\n", + here->BSIM3V1name,debugtemp,*timeStep); + } +#endif /* STEPDEBUG */ + + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim3v1/bsim3v1def.h b/src/spicelib/devices/bsim3v1/bsim3v1def.h new file mode 100644 index 000000000..0bf8a46a5 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/bsim3v1def.h @@ -0,0 +1,1633 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan +File: bsim3v1def.h +**********/ + +#ifndef BSIM3V1 +#define BSIM3V1 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + +typedef struct sBSIM3V1instance +{ + struct sBSIM3V1model *BSIM3V1modPtr; + struct sBSIM3V1instance *BSIM3V1nextInstance; + IFuid BSIM3V1name; + int BSIM3V1owner; /* number of owner process */ + int BSIM3V1states; /* index into state table for this device */ + + int BSIM3V1dNode; + int BSIM3V1gNode; + int BSIM3V1sNode; + int BSIM3V1bNode; + int BSIM3V1dNodePrime; + int BSIM3V1sNodePrime; + int BSIM3V1qNode; /* MCJ */ + + /* MCJ */ + double BSIM3V1ueff; + double BSIM3V1thetavth; + double BSIM3V1von; + double BSIM3V1vdsat; + double BSIM3V1cgdo; + double BSIM3V1cgso; + + double BSIM3V1l; + double BSIM3V1w; + double BSIM3V1drainArea; + double BSIM3V1sourceArea; + double BSIM3V1drainSquares; + double BSIM3V1sourceSquares; + double BSIM3V1drainPerimeter; + double BSIM3V1sourcePerimeter; + double BSIM3V1sourceConductance; + double BSIM3V1drainConductance; + double BSIM3V1m; + + double BSIM3V1icVBS; + double BSIM3V1icVDS; + double BSIM3V1icVGS; + int BSIM3V1off; + int BSIM3V1mode; + int BSIM3V1nqsMod; + + /* OP point */ + double BSIM3V1qinv; + double BSIM3V1cd; + double BSIM3V1cbs; + double BSIM3V1cbd; + double BSIM3V1csub; + double BSIM3V1gm; + double BSIM3V1gds; + double BSIM3V1gmbs; + double BSIM3V1gbd; + double BSIM3V1gbs; + + double BSIM3V1gbbs; + double BSIM3V1gbgs; + double BSIM3V1gbds; + + double BSIM3V1cggb; + double BSIM3V1cgdb; + double BSIM3V1cgsb; + double BSIM3V1cbgb; + double BSIM3V1cbdb; + double BSIM3V1cbsb; + double BSIM3V1cdgb; + double BSIM3V1cddb; + double BSIM3V1cdsb; + double BSIM3V1capbd; + double BSIM3V1capbs; + + double BSIM3V1cqgb; + double BSIM3V1cqdb; + double BSIM3V1cqsb; + double BSIM3V1cqbb; + + double BSIM3V1gtau; + double BSIM3V1gtg; + double BSIM3V1gtd; + double BSIM3V1gts; + double BSIM3V1gtb; + double BSIM3V1tconst; + + struct bsim3v1SizeDependParam *pParam; + + unsigned BSIM3V1lGiven :1; + unsigned BSIM3V1wGiven :1; + unsigned BSIM3V1drainAreaGiven :1; + unsigned BSIM3V1sourceAreaGiven :1; + unsigned BSIM3V1drainSquaresGiven :1; + unsigned BSIM3V1sourceSquaresGiven :1; + unsigned BSIM3V1drainPerimeterGiven :1; + unsigned BSIM3V1sourcePerimeterGiven :1; + unsigned BSIM3V1dNodePrimeSet :1; + unsigned BSIM3V1sNodePrimeSet :1; + unsigned BSIM3V1icVBSGiven :1; + unsigned BSIM3V1icVDSGiven :1; + unsigned BSIM3V1icVGSGiven :1; + unsigned BSIM3V1nqsModGiven :1; + + double *BSIM3V1DdPtr; + double *BSIM3V1GgPtr; + double *BSIM3V1SsPtr; + double *BSIM3V1BbPtr; + double *BSIM3V1DPdpPtr; + double *BSIM3V1SPspPtr; + double *BSIM3V1DdpPtr; + double *BSIM3V1GbPtr; + double *BSIM3V1GdpPtr; + double *BSIM3V1GspPtr; + double *BSIM3V1SspPtr; + double *BSIM3V1BdpPtr; + double *BSIM3V1BspPtr; + double *BSIM3V1DPspPtr; + double *BSIM3V1DPdPtr; + double *BSIM3V1BgPtr; + double *BSIM3V1DPgPtr; + double *BSIM3V1SPgPtr; + double *BSIM3V1SPsPtr; + double *BSIM3V1DPbPtr; + double *BSIM3V1SPbPtr; + double *BSIM3V1SPdpPtr; + + double *BSIM3V1QqPtr; + double *BSIM3V1QdpPtr; + double *BSIM3V1QgPtr; + double *BSIM3V1QspPtr; + double *BSIM3V1QbPtr; + double *BSIM3V1DPqPtr; + double *BSIM3V1GqPtr; + double *BSIM3V1SPqPtr; + double *BSIM3V1BqPtr; + +#define BSIM3V1vbd BSIM3V1states+ 0 +#define BSIM3V1vbs BSIM3V1states+ 1 +#define BSIM3V1vgs BSIM3V1states+ 2 +#define BSIM3V1vds BSIM3V1states+ 3 + +#define BSIM3V1qb BSIM3V1states+ 4 +#define BSIM3V1cqb BSIM3V1states+ 5 +#define BSIM3V1qg BSIM3V1states+ 6 +#define BSIM3V1cqg BSIM3V1states+ 7 +#define BSIM3V1qd BSIM3V1states+ 8 +#define BSIM3V1cqd BSIM3V1states+ 9 + +#define BSIM3V1qbs BSIM3V1states+ 10 +#define BSIM3V1qbd BSIM3V1states+ 11 + +#define BSIM3V1qcheq BSIM3V1states+ 12 +#define BSIM3V1cqcheq BSIM3V1states+ 13 +#define BSIM3V1qcdump BSIM3V1states+ 14 +#define BSIM3V1cqcdump BSIM3V1states+ 15 + +#define BSIM3V1tau BSIM3V1states+ 16 +#define BSIM3V1qdef BSIM3V1states+ 17 + +#define BSIM3V1numStates 18 + + +/* indices to the array of BSIM3V1 NOISE SOURCES */ + +#define BSIM3V1RDNOIZ 0 +#define BSIM3V1RSNOIZ 1 +#define BSIM3V1IDNOIZ 2 +#define BSIM3V1FLNOIZ 3 +#define BSIM3V1TOTNOIZ 4 + +#define BSIM3V1NSRCS 5 /* the number of MOSFET(3) noise sources */ + +#ifndef NONOISE + double BSIM3V1nVar[NSTATVARS][BSIM3V1NSRCS]; +#else /* NONOISE */ + double **BSIM3V1nVar; +#endif /* NONOISE */ + +} BSIM3V1instance ; + +struct bsim3v1SizeDependParam +{ + double Width; + double Length; + + double BSIM3V1cdsc; + double BSIM3V1cdscb; + double BSIM3V1cdscd; + double BSIM3V1cit; + double BSIM3V1nfactor; + double BSIM3V1xj; + double BSIM3V1vsat; + double BSIM3V1at; + double BSIM3V1a0; + double BSIM3V1ags; + double BSIM3V1a1; + double BSIM3V1a2; + double BSIM3V1keta; + double BSIM3V1nsub; + double BSIM3V1npeak; + double BSIM3V1ngate; + double BSIM3V1gamma1; + double BSIM3V1gamma2; + double BSIM3V1vbx; + double BSIM3V1vbi; + double BSIM3V1vbm; + double BSIM3V1vbsc; + double BSIM3V1xt; + double BSIM3V1phi; + double BSIM3V1litl; + double BSIM3V1k1; + double BSIM3V1kt1; + double BSIM3V1kt1l; + double BSIM3V1kt2; + double BSIM3V1k2; + double BSIM3V1k3; + double BSIM3V1k3b; + double BSIM3V1w0; + double BSIM3V1nlx; + double BSIM3V1dvt0; + double BSIM3V1dvt1; + double BSIM3V1dvt2; + double BSIM3V1dvt0w; + double BSIM3V1dvt1w; + double BSIM3V1dvt2w; + double BSIM3V1drout; + double BSIM3V1dsub; + double BSIM3V1vth0; + double BSIM3V1ua; + double BSIM3V1ua1; + double BSIM3V1ub; + double BSIM3V1ub1; + double BSIM3V1uc; + double BSIM3V1uc1; + double BSIM3V1u0; + double BSIM3V1ute; + double BSIM3V1voff; + double BSIM3V1vfb; + double BSIM3V1delta; + double BSIM3V1rdsw; + double BSIM3V1rds0; + double BSIM3V1prwg; + double BSIM3V1prwb; + double BSIM3V1prt; + double BSIM3V1eta0; + double BSIM3V1etab; + double BSIM3V1pclm; + double BSIM3V1pdibl1; + double BSIM3V1pdibl2; + double BSIM3V1pdiblb; + double BSIM3V1pscbe1; + double BSIM3V1pscbe2; + double BSIM3V1pvag; + double BSIM3V1wr; + double BSIM3V1dwg; + double BSIM3V1dwb; + double BSIM3V1b0; + double BSIM3V1b1; + double BSIM3V1alpha0; + double BSIM3V1beta0; + + + /* CV model */ + double BSIM3V1elm; + double BSIM3V1cgsl; + double BSIM3V1cgdl; + double BSIM3V1ckappa; + double BSIM3V1cf; + double BSIM3V1clc; + double BSIM3V1cle; + double BSIM3V1vfbcv; + + +/* Pre-calculated constants */ + + double BSIM3V1dw; + double BSIM3V1dl; + double BSIM3V1leff; + double BSIM3V1weff; + + double BSIM3V1dwc; + double BSIM3V1dlc; + double BSIM3V1leffCV; + double BSIM3V1weffCV; + double BSIM3V1abulkCVfactor; + double BSIM3V1cgso; + double BSIM3V1cgdo; + double BSIM3V1cgbo; + + double BSIM3V1u0temp; + double BSIM3V1vsattemp; + double BSIM3V1sqrtPhi; + double BSIM3V1phis3; + double BSIM3V1Xdep0; + double BSIM3V1sqrtXdep0; + double BSIM3V1theta0vb0; + double BSIM3V1thetaRout; + + double BSIM3V1cof1; + double BSIM3V1cof2; + double BSIM3V1cof3; + double BSIM3V1cof4; + double BSIM3V1cdep0; + struct bsim3v1SizeDependParam *pNext; +}; + + +typedef struct sBSIM3V1model +{ + int BSIM3V1modType; + struct sBSIM3V1model *BSIM3V1nextModel; + BSIM3V1instance *BSIM3V1instances; + IFuid BSIM3V1modName; + int BSIM3V1type; + + int BSIM3V1mobMod; + int BSIM3V1capMod; + int BSIM3V1nqsMod; + int BSIM3V1noiMod; + int BSIM3V1binUnit; + int BSIM3V1paramChk; + double BSIM3V1version; + double BSIM3V1tox; + double BSIM3V1cdsc; + double BSIM3V1cdscb; + double BSIM3V1cdscd; + double BSIM3V1cit; + double BSIM3V1nfactor; + double BSIM3V1xj; + double BSIM3V1vsat; + double BSIM3V1at; + double BSIM3V1a0; + double BSIM3V1ags; + double BSIM3V1a1; + double BSIM3V1a2; + double BSIM3V1keta; + double BSIM3V1nsub; + double BSIM3V1npeak; + double BSIM3V1ngate; + double BSIM3V1gamma1; + double BSIM3V1gamma2; + double BSIM3V1vbx; + double BSIM3V1vbm; + double BSIM3V1xt; + double BSIM3V1k1; + double BSIM3V1kt1; + double BSIM3V1kt1l; + double BSIM3V1kt2; + double BSIM3V1k2; + double BSIM3V1k3; + double BSIM3V1k3b; + double BSIM3V1w0; + double BSIM3V1nlx; + double BSIM3V1dvt0; + double BSIM3V1dvt1; + double BSIM3V1dvt2; + double BSIM3V1dvt0w; + double BSIM3V1dvt1w; + double BSIM3V1dvt2w; + double BSIM3V1drout; + double BSIM3V1dsub; + double BSIM3V1vth0; + double BSIM3V1ua; + double BSIM3V1ua1; + double BSIM3V1ub; + double BSIM3V1ub1; + double BSIM3V1uc; + double BSIM3V1uc1; + double BSIM3V1u0; + double BSIM3V1ute; + double BSIM3V1voff; + double BSIM3V1delta; + double BSIM3V1rdsw; + double BSIM3V1prwg; + double BSIM3V1prwb; + double BSIM3V1prt; + double BSIM3V1eta0; + double BSIM3V1etab; + double BSIM3V1pclm; + double BSIM3V1pdibl1; + double BSIM3V1pdibl2; + double BSIM3V1pdiblb; + double BSIM3V1pscbe1; + double BSIM3V1pscbe2; + double BSIM3V1pvag; + double BSIM3V1wr; + double BSIM3V1dwg; + double BSIM3V1dwb; + double BSIM3V1b0; + double BSIM3V1b1; + double BSIM3V1alpha0; + double BSIM3V1beta0; +/* serban */ + double BSIM3V1hdif; + + /* CV model */ + double BSIM3V1elm; + double BSIM3V1cgsl; + double BSIM3V1cgdl; + double BSIM3V1ckappa; + double BSIM3V1cf; + double BSIM3V1vfbcv; + double BSIM3V1clc; + double BSIM3V1cle; + double BSIM3V1dwc; + double BSIM3V1dlc; + + /* Length Dependence */ + double BSIM3V1lcdsc; + double BSIM3V1lcdscb; + double BSIM3V1lcdscd; + double BSIM3V1lcit; + double BSIM3V1lnfactor; + double BSIM3V1lxj; + double BSIM3V1lvsat; + double BSIM3V1lat; + double BSIM3V1la0; + double BSIM3V1lags; + double BSIM3V1la1; + double BSIM3V1la2; + double BSIM3V1lketa; + double BSIM3V1lnsub; + double BSIM3V1lnpeak; + double BSIM3V1lngate; + double BSIM3V1lgamma1; + double BSIM3V1lgamma2; + double BSIM3V1lvbx; + double BSIM3V1lvbm; + double BSIM3V1lxt; + double BSIM3V1lk1; + double BSIM3V1lkt1; + double BSIM3V1lkt1l; + double BSIM3V1lkt2; + double BSIM3V1lk2; + double BSIM3V1lk3; + double BSIM3V1lk3b; + double BSIM3V1lw0; + double BSIM3V1lnlx; + double BSIM3V1ldvt0; + double BSIM3V1ldvt1; + double BSIM3V1ldvt2; + double BSIM3V1ldvt0w; + double BSIM3V1ldvt1w; + double BSIM3V1ldvt2w; + double BSIM3V1ldrout; + double BSIM3V1ldsub; + double BSIM3V1lvth0; + double BSIM3V1lua; + double BSIM3V1lua1; + double BSIM3V1lub; + double BSIM3V1lub1; + double BSIM3V1luc; + double BSIM3V1luc1; + double BSIM3V1lu0; + double BSIM3V1lute; + double BSIM3V1lvoff; + double BSIM3V1ldelta; + double BSIM3V1lrdsw; + double BSIM3V1lprwg; + double BSIM3V1lprwb; + double BSIM3V1lprt; + double BSIM3V1leta0; + double BSIM3V1letab; + double BSIM3V1lpclm; + double BSIM3V1lpdibl1; + double BSIM3V1lpdibl2; + double BSIM3V1lpdiblb; + double BSIM3V1lpscbe1; + double BSIM3V1lpscbe2; + double BSIM3V1lpvag; + double BSIM3V1lwr; + double BSIM3V1ldwg; + double BSIM3V1ldwb; + double BSIM3V1lb0; + double BSIM3V1lb1; + double BSIM3V1lalpha0; + double BSIM3V1lbeta0; + + /* CV model */ + double BSIM3V1lelm; + double BSIM3V1lcgsl; + double BSIM3V1lcgdl; + double BSIM3V1lckappa; + double BSIM3V1lcf; + double BSIM3V1lclc; + double BSIM3V1lcle; + double BSIM3V1lvfbcv; + + /* Width Dependence */ + double BSIM3V1wcdsc; + double BSIM3V1wcdscb; + double BSIM3V1wcdscd; + double BSIM3V1wcit; + double BSIM3V1wnfactor; + double BSIM3V1wxj; + double BSIM3V1wvsat; + double BSIM3V1wat; + double BSIM3V1wa0; + double BSIM3V1wags; + double BSIM3V1wa1; + double BSIM3V1wa2; + double BSIM3V1wketa; + double BSIM3V1wnsub; + double BSIM3V1wnpeak; + double BSIM3V1wngate; + double BSIM3V1wgamma1; + double BSIM3V1wgamma2; + double BSIM3V1wvbx; + double BSIM3V1wvbm; + double BSIM3V1wxt; + double BSIM3V1wk1; + double BSIM3V1wkt1; + double BSIM3V1wkt1l; + double BSIM3V1wkt2; + double BSIM3V1wk2; + double BSIM3V1wk3; + double BSIM3V1wk3b; + double BSIM3V1ww0; + double BSIM3V1wnlx; + double BSIM3V1wdvt0; + double BSIM3V1wdvt1; + double BSIM3V1wdvt2; + double BSIM3V1wdvt0w; + double BSIM3V1wdvt1w; + double BSIM3V1wdvt2w; + double BSIM3V1wdrout; + double BSIM3V1wdsub; + double BSIM3V1wvth0; + double BSIM3V1wua; + double BSIM3V1wua1; + double BSIM3V1wub; + double BSIM3V1wub1; + double BSIM3V1wuc; + double BSIM3V1wuc1; + double BSIM3V1wu0; + double BSIM3V1wute; + double BSIM3V1wvoff; + double BSIM3V1wdelta; + double BSIM3V1wrdsw; + double BSIM3V1wprwg; + double BSIM3V1wprwb; + double BSIM3V1wprt; + double BSIM3V1weta0; + double BSIM3V1wetab; + double BSIM3V1wpclm; + double BSIM3V1wpdibl1; + double BSIM3V1wpdibl2; + double BSIM3V1wpdiblb; + double BSIM3V1wpscbe1; + double BSIM3V1wpscbe2; + double BSIM3V1wpvag; + double BSIM3V1wwr; + double BSIM3V1wdwg; + double BSIM3V1wdwb; + double BSIM3V1wb0; + double BSIM3V1wb1; + double BSIM3V1walpha0; + double BSIM3V1wbeta0; + + /* CV model */ + double BSIM3V1welm; + double BSIM3V1wcgsl; + double BSIM3V1wcgdl; + double BSIM3V1wckappa; + double BSIM3V1wcf; + double BSIM3V1wclc; + double BSIM3V1wcle; + double BSIM3V1wvfbcv; + + /* Cross-term Dependence */ + double BSIM3V1pcdsc; + double BSIM3V1pcdscb; + double BSIM3V1pcdscd; + double BSIM3V1pcit; + double BSIM3V1pnfactor; + double BSIM3V1pxj; + double BSIM3V1pvsat; + double BSIM3V1pat; + double BSIM3V1pa0; + double BSIM3V1pags; + double BSIM3V1pa1; + double BSIM3V1pa2; + double BSIM3V1pketa; + double BSIM3V1pnsub; + double BSIM3V1pnpeak; + double BSIM3V1pngate; + double BSIM3V1pgamma1; + double BSIM3V1pgamma2; + double BSIM3V1pvbx; + double BSIM3V1pvbm; + double BSIM3V1pxt; + double BSIM3V1pk1; + double BSIM3V1pkt1; + double BSIM3V1pkt1l; + double BSIM3V1pkt2; + double BSIM3V1pk2; + double BSIM3V1pk3; + double BSIM3V1pk3b; + double BSIM3V1pw0; + double BSIM3V1pnlx; + double BSIM3V1pdvt0; + double BSIM3V1pdvt1; + double BSIM3V1pdvt2; + double BSIM3V1pdvt0w; + double BSIM3V1pdvt1w; + double BSIM3V1pdvt2w; + double BSIM3V1pdrout; + double BSIM3V1pdsub; + double BSIM3V1pvth0; + double BSIM3V1pua; + double BSIM3V1pua1; + double BSIM3V1pub; + double BSIM3V1pub1; + double BSIM3V1puc; + double BSIM3V1puc1; + double BSIM3V1pu0; + double BSIM3V1pute; + double BSIM3V1pvoff; + double BSIM3V1pdelta; + double BSIM3V1prdsw; + double BSIM3V1pprwg; + double BSIM3V1pprwb; + double BSIM3V1pprt; + double BSIM3V1peta0; + double BSIM3V1petab; + double BSIM3V1ppclm; + double BSIM3V1ppdibl1; + double BSIM3V1ppdibl2; + double BSIM3V1ppdiblb; + double BSIM3V1ppscbe1; + double BSIM3V1ppscbe2; + double BSIM3V1ppvag; + double BSIM3V1pwr; + double BSIM3V1pdwg; + double BSIM3V1pdwb; + double BSIM3V1pb0; + double BSIM3V1pb1; + double BSIM3V1palpha0; + double BSIM3V1pbeta0; + + /* CV model */ + double BSIM3V1pelm; + double BSIM3V1pcgsl; + double BSIM3V1pcgdl; + double BSIM3V1pckappa; + double BSIM3V1pcf; + double BSIM3V1pclc; + double BSIM3V1pcle; + double BSIM3V1pvfbcv; + + double BSIM3V1tnom; + double BSIM3V1cgso; + double BSIM3V1cgdo; + double BSIM3V1cgbo; + double BSIM3V1xpart; + double BSIM3V1cFringOut; + double BSIM3V1cFringMax; + + double BSIM3V1sheetResistance; + double BSIM3V1jctSatCurDensity; + double BSIM3V1jctSidewallSatCurDensity; + double BSIM3V1bulkJctPotential; + double BSIM3V1bulkJctBotGradingCoeff; + double BSIM3V1bulkJctSideGradingCoeff; + double BSIM3V1bulkJctGateSideGradingCoeff; + double BSIM3V1sidewallJctPotential; + double BSIM3V1GatesidewallJctPotential; + double BSIM3V1unitAreaJctCap; + double BSIM3V1unitLengthSidewallJctCap; + double BSIM3V1unitLengthGateSidewallJctCap; + double BSIM3V1jctEmissionCoeff; + double BSIM3V1jctTempExponent; + + double BSIM3V1Lint; + double BSIM3V1Ll; + double BSIM3V1Lln; + double BSIM3V1Lw; + double BSIM3V1Lwn; + double BSIM3V1Lwl; + double BSIM3V1Lmin; + double BSIM3V1Lmax; + + double BSIM3V1Wint; + double BSIM3V1Wl; + double BSIM3V1Wln; + double BSIM3V1Ww; + double BSIM3V1Wwn; + double BSIM3V1Wwl; + double BSIM3V1Wmin; + double BSIM3V1Wmax; + + +/* Pre-calculated constants */ + /* MCJ: move to size-dependent param. */ + double BSIM3V1vtm; + double BSIM3V1cox; + double BSIM3V1cof1; + double BSIM3V1cof2; + double BSIM3V1cof3; + double BSIM3V1cof4; + double BSIM3V1vcrit; + double BSIM3V1factor1; + double BSIM3V1jctTempSatCurDensity; + double BSIM3V1jctSidewallTempSatCurDensity; + + double BSIM3V1oxideTrapDensityA; + double BSIM3V1oxideTrapDensityB; + double BSIM3V1oxideTrapDensityC; + double BSIM3V1em; + double BSIM3V1ef; + double BSIM3V1af; + double BSIM3V1kf; + + struct bsim3v1SizeDependParam *pSizeDependParamKnot; + + /* Flags */ + unsigned BSIM3V1mobModGiven :1; + unsigned BSIM3V1binUnitGiven :1; + unsigned BSIM3V1capModGiven :1; + unsigned BSIM3V1paramChkGiven :1; + unsigned BSIM3V1nqsModGiven :1; + unsigned BSIM3V1noiModGiven :1; + unsigned BSIM3V1typeGiven :1; + unsigned BSIM3V1toxGiven :1; + unsigned BSIM3V1versionGiven :1; + + unsigned BSIM3V1cdscGiven :1; + unsigned BSIM3V1cdscbGiven :1; + unsigned BSIM3V1cdscdGiven :1; + unsigned BSIM3V1citGiven :1; + unsigned BSIM3V1nfactorGiven :1; + unsigned BSIM3V1xjGiven :1; + unsigned BSIM3V1vsatGiven :1; + unsigned BSIM3V1atGiven :1; + unsigned BSIM3V1a0Given :1; + unsigned BSIM3V1agsGiven :1; + unsigned BSIM3V1a1Given :1; + unsigned BSIM3V1a2Given :1; + unsigned BSIM3V1ketaGiven :1; + unsigned BSIM3V1nsubGiven :1; + unsigned BSIM3V1npeakGiven :1; + unsigned BSIM3V1ngateGiven :1; + unsigned BSIM3V1gamma1Given :1; + unsigned BSIM3V1gamma2Given :1; + unsigned BSIM3V1vbxGiven :1; + unsigned BSIM3V1vbmGiven :1; + unsigned BSIM3V1xtGiven :1; + unsigned BSIM3V1k1Given :1; + unsigned BSIM3V1kt1Given :1; + unsigned BSIM3V1kt1lGiven :1; + unsigned BSIM3V1kt2Given :1; + unsigned BSIM3V1k2Given :1; + unsigned BSIM3V1k3Given :1; + unsigned BSIM3V1k3bGiven :1; + unsigned BSIM3V1w0Given :1; + unsigned BSIM3V1nlxGiven :1; + unsigned BSIM3V1dvt0Given :1; + unsigned BSIM3V1dvt1Given :1; + unsigned BSIM3V1dvt2Given :1; + unsigned BSIM3V1dvt0wGiven :1; + unsigned BSIM3V1dvt1wGiven :1; + unsigned BSIM3V1dvt2wGiven :1; + unsigned BSIM3V1droutGiven :1; + unsigned BSIM3V1dsubGiven :1; + unsigned BSIM3V1vth0Given :1; + unsigned BSIM3V1uaGiven :1; + unsigned BSIM3V1ua1Given :1; + unsigned BSIM3V1ubGiven :1; + unsigned BSIM3V1ub1Given :1; + unsigned BSIM3V1ucGiven :1; + unsigned BSIM3V1uc1Given :1; + unsigned BSIM3V1u0Given :1; + unsigned BSIM3V1uteGiven :1; + unsigned BSIM3V1voffGiven :1; + unsigned BSIM3V1rdswGiven :1; + unsigned BSIM3V1prwgGiven :1; + unsigned BSIM3V1prwbGiven :1; + unsigned BSIM3V1prtGiven :1; + unsigned BSIM3V1eta0Given :1; + unsigned BSIM3V1etabGiven :1; + unsigned BSIM3V1pclmGiven :1; + unsigned BSIM3V1pdibl1Given :1; + unsigned BSIM3V1pdibl2Given :1; + unsigned BSIM3V1pdiblbGiven :1; + unsigned BSIM3V1pscbe1Given :1; + unsigned BSIM3V1pscbe2Given :1; + unsigned BSIM3V1pvagGiven :1; + unsigned BSIM3V1deltaGiven :1; + unsigned BSIM3V1wrGiven :1; + unsigned BSIM3V1dwgGiven :1; + unsigned BSIM3V1dwbGiven :1; + unsigned BSIM3V1b0Given :1; + unsigned BSIM3V1b1Given :1; + unsigned BSIM3V1alpha0Given :1; + unsigned BSIM3V1beta0Given :1; + unsigned BSIM3V1hdifGiven :1; + + /* CV model */ + unsigned BSIM3V1elmGiven :1; + unsigned BSIM3V1cgslGiven :1; + unsigned BSIM3V1cgdlGiven :1; + unsigned BSIM3V1ckappaGiven :1; + unsigned BSIM3V1cfGiven :1; + unsigned BSIM3V1vfbcvGiven :1; + unsigned BSIM3V1clcGiven :1; + unsigned BSIM3V1cleGiven :1; + unsigned BSIM3V1dwcGiven :1; + unsigned BSIM3V1dlcGiven :1; + + + /* Length dependence */ + unsigned BSIM3V1lcdscGiven :1; + unsigned BSIM3V1lcdscbGiven :1; + unsigned BSIM3V1lcdscdGiven :1; + unsigned BSIM3V1lcitGiven :1; + unsigned BSIM3V1lnfactorGiven :1; + unsigned BSIM3V1lxjGiven :1; + unsigned BSIM3V1lvsatGiven :1; + unsigned BSIM3V1latGiven :1; + unsigned BSIM3V1la0Given :1; + unsigned BSIM3V1lagsGiven :1; + unsigned BSIM3V1la1Given :1; + unsigned BSIM3V1la2Given :1; + unsigned BSIM3V1lketaGiven :1; + unsigned BSIM3V1lnsubGiven :1; + unsigned BSIM3V1lnpeakGiven :1; + unsigned BSIM3V1lngateGiven :1; + unsigned BSIM3V1lgamma1Given :1; + unsigned BSIM3V1lgamma2Given :1; + unsigned BSIM3V1lvbxGiven :1; + unsigned BSIM3V1lvbmGiven :1; + unsigned BSIM3V1lxtGiven :1; + unsigned BSIM3V1lk1Given :1; + unsigned BSIM3V1lkt1Given :1; + unsigned BSIM3V1lkt1lGiven :1; + unsigned BSIM3V1lkt2Given :1; + unsigned BSIM3V1lk2Given :1; + unsigned BSIM3V1lk3Given :1; + unsigned BSIM3V1lk3bGiven :1; + unsigned BSIM3V1lw0Given :1; + unsigned BSIM3V1lnlxGiven :1; + unsigned BSIM3V1ldvt0Given :1; + unsigned BSIM3V1ldvt1Given :1; + unsigned BSIM3V1ldvt2Given :1; + unsigned BSIM3V1ldvt0wGiven :1; + unsigned BSIM3V1ldvt1wGiven :1; + unsigned BSIM3V1ldvt2wGiven :1; + unsigned BSIM3V1ldroutGiven :1; + unsigned BSIM3V1ldsubGiven :1; + unsigned BSIM3V1lvth0Given :1; + unsigned BSIM3V1luaGiven :1; + unsigned BSIM3V1lua1Given :1; + unsigned BSIM3V1lubGiven :1; + unsigned BSIM3V1lub1Given :1; + unsigned BSIM3V1lucGiven :1; + unsigned BSIM3V1luc1Given :1; + unsigned BSIM3V1lu0Given :1; + unsigned BSIM3V1luteGiven :1; + unsigned BSIM3V1lvoffGiven :1; + unsigned BSIM3V1lrdswGiven :1; + unsigned BSIM3V1lprwgGiven :1; + unsigned BSIM3V1lprwbGiven :1; + unsigned BSIM3V1lprtGiven :1; + unsigned BSIM3V1leta0Given :1; + unsigned BSIM3V1letabGiven :1; + unsigned BSIM3V1lpclmGiven :1; + unsigned BSIM3V1lpdibl1Given :1; + unsigned BSIM3V1lpdibl2Given :1; + unsigned BSIM3V1lpdiblbGiven :1; + unsigned BSIM3V1lpscbe1Given :1; + unsigned BSIM3V1lpscbe2Given :1; + unsigned BSIM3V1lpvagGiven :1; + unsigned BSIM3V1ldeltaGiven :1; + unsigned BSIM3V1lwrGiven :1; + unsigned BSIM3V1ldwgGiven :1; + unsigned BSIM3V1ldwbGiven :1; + unsigned BSIM3V1lb0Given :1; + unsigned BSIM3V1lb1Given :1; + unsigned BSIM3V1lalpha0Given :1; + unsigned BSIM3V1lbeta0Given :1; + + /* CV model */ + unsigned BSIM3V1lelmGiven :1; + unsigned BSIM3V1lcgslGiven :1; + unsigned BSIM3V1lcgdlGiven :1; + unsigned BSIM3V1lckappaGiven :1; + unsigned BSIM3V1lcfGiven :1; + unsigned BSIM3V1lclcGiven :1; + unsigned BSIM3V1lcleGiven :1; + unsigned BSIM3V1lvfbcvGiven :1; + + /* Width dependence */ + unsigned BSIM3V1wcdscGiven :1; + unsigned BSIM3V1wcdscbGiven :1; + unsigned BSIM3V1wcdscdGiven :1; + unsigned BSIM3V1wcitGiven :1; + unsigned BSIM3V1wnfactorGiven :1; + unsigned BSIM3V1wxjGiven :1; + unsigned BSIM3V1wvsatGiven :1; + unsigned BSIM3V1watGiven :1; + unsigned BSIM3V1wa0Given :1; + unsigned BSIM3V1wagsGiven :1; + unsigned BSIM3V1wa1Given :1; + unsigned BSIM3V1wa2Given :1; + unsigned BSIM3V1wketaGiven :1; + unsigned BSIM3V1wnsubGiven :1; + unsigned BSIM3V1wnpeakGiven :1; + unsigned BSIM3V1wngateGiven :1; + unsigned BSIM3V1wgamma1Given :1; + unsigned BSIM3V1wgamma2Given :1; + unsigned BSIM3V1wvbxGiven :1; + unsigned BSIM3V1wvbmGiven :1; + unsigned BSIM3V1wxtGiven :1; + unsigned BSIM3V1wk1Given :1; + unsigned BSIM3V1wkt1Given :1; + unsigned BSIM3V1wkt1lGiven :1; + unsigned BSIM3V1wkt2Given :1; + unsigned BSIM3V1wk2Given :1; + unsigned BSIM3V1wk3Given :1; + unsigned BSIM3V1wk3bGiven :1; + unsigned BSIM3V1ww0Given :1; + unsigned BSIM3V1wnlxGiven :1; + unsigned BSIM3V1wdvt0Given :1; + unsigned BSIM3V1wdvt1Given :1; + unsigned BSIM3V1wdvt2Given :1; + unsigned BSIM3V1wdvt0wGiven :1; + unsigned BSIM3V1wdvt1wGiven :1; + unsigned BSIM3V1wdvt2wGiven :1; + unsigned BSIM3V1wdroutGiven :1; + unsigned BSIM3V1wdsubGiven :1; + unsigned BSIM3V1wvth0Given :1; + unsigned BSIM3V1wuaGiven :1; + unsigned BSIM3V1wua1Given :1; + unsigned BSIM3V1wubGiven :1; + unsigned BSIM3V1wub1Given :1; + unsigned BSIM3V1wucGiven :1; + unsigned BSIM3V1wuc1Given :1; + unsigned BSIM3V1wu0Given :1; + unsigned BSIM3V1wuteGiven :1; + unsigned BSIM3V1wvoffGiven :1; + unsigned BSIM3V1wrdswGiven :1; + unsigned BSIM3V1wprwgGiven :1; + unsigned BSIM3V1wprwbGiven :1; + unsigned BSIM3V1wprtGiven :1; + unsigned BSIM3V1weta0Given :1; + unsigned BSIM3V1wetabGiven :1; + unsigned BSIM3V1wpclmGiven :1; + unsigned BSIM3V1wpdibl1Given :1; + unsigned BSIM3V1wpdibl2Given :1; + unsigned BSIM3V1wpdiblbGiven :1; + unsigned BSIM3V1wpscbe1Given :1; + unsigned BSIM3V1wpscbe2Given :1; + unsigned BSIM3V1wpvagGiven :1; + unsigned BSIM3V1wdeltaGiven :1; + unsigned BSIM3V1wwrGiven :1; + unsigned BSIM3V1wdwgGiven :1; + unsigned BSIM3V1wdwbGiven :1; + unsigned BSIM3V1wb0Given :1; + unsigned BSIM3V1wb1Given :1; + unsigned BSIM3V1walpha0Given :1; + unsigned BSIM3V1wbeta0Given :1; + + /* CV model */ + unsigned BSIM3V1welmGiven :1; + unsigned BSIM3V1wcgslGiven :1; + unsigned BSIM3V1wcgdlGiven :1; + unsigned BSIM3V1wckappaGiven :1; + unsigned BSIM3V1wcfGiven :1; + unsigned BSIM3V1wclcGiven :1; + unsigned BSIM3V1wcleGiven :1; + unsigned BSIM3V1wvfbcvGiven :1; + + /* Cross-term dependence */ + unsigned BSIM3V1pcdscGiven :1; + unsigned BSIM3V1pcdscbGiven :1; + unsigned BSIM3V1pcdscdGiven :1; + unsigned BSIM3V1pcitGiven :1; + unsigned BSIM3V1pnfactorGiven :1; + unsigned BSIM3V1pxjGiven :1; + unsigned BSIM3V1pvsatGiven :1; + unsigned BSIM3V1patGiven :1; + unsigned BSIM3V1pa0Given :1; + unsigned BSIM3V1pagsGiven :1; + unsigned BSIM3V1pa1Given :1; + unsigned BSIM3V1pa2Given :1; + unsigned BSIM3V1pketaGiven :1; + unsigned BSIM3V1pnsubGiven :1; + unsigned BSIM3V1pnpeakGiven :1; + unsigned BSIM3V1pngateGiven :1; + unsigned BSIM3V1pgamma1Given :1; + unsigned BSIM3V1pgamma2Given :1; + unsigned BSIM3V1pvbxGiven :1; + unsigned BSIM3V1pvbmGiven :1; + unsigned BSIM3V1pxtGiven :1; + unsigned BSIM3V1pk1Given :1; + unsigned BSIM3V1pkt1Given :1; + unsigned BSIM3V1pkt1lGiven :1; + unsigned BSIM3V1pkt2Given :1; + unsigned BSIM3V1pk2Given :1; + unsigned BSIM3V1pk3Given :1; + unsigned BSIM3V1pk3bGiven :1; + unsigned BSIM3V1pw0Given :1; + unsigned BSIM3V1pnlxGiven :1; + unsigned BSIM3V1pdvt0Given :1; + unsigned BSIM3V1pdvt1Given :1; + unsigned BSIM3V1pdvt2Given :1; + unsigned BSIM3V1pdvt0wGiven :1; + unsigned BSIM3V1pdvt1wGiven :1; + unsigned BSIM3V1pdvt2wGiven :1; + unsigned BSIM3V1pdroutGiven :1; + unsigned BSIM3V1pdsubGiven :1; + unsigned BSIM3V1pvth0Given :1; + unsigned BSIM3V1puaGiven :1; + unsigned BSIM3V1pua1Given :1; + unsigned BSIM3V1pubGiven :1; + unsigned BSIM3V1pub1Given :1; + unsigned BSIM3V1pucGiven :1; + unsigned BSIM3V1puc1Given :1; + unsigned BSIM3V1pu0Given :1; + unsigned BSIM3V1puteGiven :1; + unsigned BSIM3V1pvoffGiven :1; + unsigned BSIM3V1prdswGiven :1; + unsigned BSIM3V1pprwgGiven :1; + unsigned BSIM3V1pprwbGiven :1; + unsigned BSIM3V1pprtGiven :1; + unsigned BSIM3V1peta0Given :1; + unsigned BSIM3V1petabGiven :1; + unsigned BSIM3V1ppclmGiven :1; + unsigned BSIM3V1ppdibl1Given :1; + unsigned BSIM3V1ppdibl2Given :1; + unsigned BSIM3V1ppdiblbGiven :1; + unsigned BSIM3V1ppscbe1Given :1; + unsigned BSIM3V1ppscbe2Given :1; + unsigned BSIM3V1ppvagGiven :1; + unsigned BSIM3V1pdeltaGiven :1; + unsigned BSIM3V1pwrGiven :1; + unsigned BSIM3V1pdwgGiven :1; + unsigned BSIM3V1pdwbGiven :1; + unsigned BSIM3V1pb0Given :1; + unsigned BSIM3V1pb1Given :1; + unsigned BSIM3V1palpha0Given :1; + unsigned BSIM3V1pbeta0Given :1; + + /* CV model */ + unsigned BSIM3V1pelmGiven :1; + unsigned BSIM3V1pcgslGiven :1; + unsigned BSIM3V1pcgdlGiven :1; + unsigned BSIM3V1pckappaGiven :1; + unsigned BSIM3V1pcfGiven :1; + unsigned BSIM3V1pclcGiven :1; + unsigned BSIM3V1pcleGiven :1; + unsigned BSIM3V1pvfbcvGiven :1; + + unsigned BSIM3V1useFringeGiven :1; + + unsigned BSIM3V1tnomGiven :1; + unsigned BSIM3V1cgsoGiven :1; + unsigned BSIM3V1cgdoGiven :1; + unsigned BSIM3V1cgboGiven :1; + unsigned BSIM3V1xpartGiven :1; + unsigned BSIM3V1sheetResistanceGiven :1; + unsigned BSIM3V1jctSatCurDensityGiven :1; + unsigned BSIM3V1jctSidewallSatCurDensityGiven :1; + unsigned BSIM3V1bulkJctPotentialGiven :1; + unsigned BSIM3V1bulkJctBotGradingCoeffGiven :1; + unsigned BSIM3V1sidewallJctPotentialGiven :1; + unsigned BSIM3V1GatesidewallJctPotentialGiven :1; + unsigned BSIM3V1bulkJctSideGradingCoeffGiven :1; + unsigned BSIM3V1unitAreaJctCapGiven :1; + unsigned BSIM3V1unitLengthSidewallJctCapGiven :1; + unsigned BSIM3V1bulkJctGateSideGradingCoeffGiven :1; + unsigned BSIM3V1unitLengthGateSidewallJctCapGiven :1; + unsigned BSIM3V1jctEmissionCoeffGiven :1; + unsigned BSIM3V1jctTempExponentGiven :1; + + unsigned BSIM3V1oxideTrapDensityAGiven :1; + unsigned BSIM3V1oxideTrapDensityBGiven :1; + unsigned BSIM3V1oxideTrapDensityCGiven :1; + unsigned BSIM3V1emGiven :1; + unsigned BSIM3V1efGiven :1; + unsigned BSIM3V1afGiven :1; + unsigned BSIM3V1kfGiven :1; + + unsigned BSIM3V1LintGiven :1; + unsigned BSIM3V1LlGiven :1; + unsigned BSIM3V1LlnGiven :1; + unsigned BSIM3V1LwGiven :1; + unsigned BSIM3V1LwnGiven :1; + unsigned BSIM3V1LwlGiven :1; + unsigned BSIM3V1LminGiven :1; + unsigned BSIM3V1LmaxGiven :1; + + unsigned BSIM3V1WintGiven :1; + unsigned BSIM3V1WlGiven :1; + unsigned BSIM3V1WlnGiven :1; + unsigned BSIM3V1WwGiven :1; + unsigned BSIM3V1WwnGiven :1; + unsigned BSIM3V1WwlGiven :1; + unsigned BSIM3V1WminGiven :1; + unsigned BSIM3V1WmaxGiven :1; + +} BSIM3V1model; + + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + + +/* device parameters */ +#define BSIM3V1_W 1 +#define BSIM3V1_L 2 +#define BSIM3V1_AS 3 +#define BSIM3V1_AD 4 +#define BSIM3V1_PS 5 +#define BSIM3V1_PD 6 +#define BSIM3V1_NRS 7 +#define BSIM3V1_NRD 8 +#define BSIM3V1_OFF 9 +#define BSIM3V1_IC_VBS 10 +#define BSIM3V1_IC_VDS 11 +#define BSIM3V1_IC_VGS 12 +#define BSIM3V1_IC 13 +#define BSIM3V1_NQSMOD 14 +#define BSIM3V1_M 20 + +/* model parameters */ +#define BSIM3V1_MOD_CAPMOD 101 +#define BSIM3V1_MOD_NQSMOD 102 +#define BSIM3V1_MOD_MOBMOD 103 +#define BSIM3V1_MOD_NOIMOD 104 + +#define BSIM3V1_MOD_TOX 105 + +#define BSIM3V1_MOD_CDSC 106 +#define BSIM3V1_MOD_CDSCB 107 +#define BSIM3V1_MOD_CIT 108 +#define BSIM3V1_MOD_NFACTOR 109 +#define BSIM3V1_MOD_XJ 110 +#define BSIM3V1_MOD_VSAT 111 +#define BSIM3V1_MOD_AT 112 +#define BSIM3V1_MOD_A0 113 +#define BSIM3V1_MOD_A1 114 +#define BSIM3V1_MOD_A2 115 +#define BSIM3V1_MOD_KETA 116 +#define BSIM3V1_MOD_NSUB 117 +#define BSIM3V1_MOD_NPEAK 118 +#define BSIM3V1_MOD_NGATE 120 +#define BSIM3V1_MOD_GAMMA1 121 +#define BSIM3V1_MOD_GAMMA2 122 +#define BSIM3V1_MOD_VBX 123 +#define BSIM3V1_MOD_BINUNIT 124 + +#define BSIM3V1_MOD_VBM 125 + +#define BSIM3V1_MOD_XT 126 +#define BSIM3V1_MOD_K1 129 +#define BSIM3V1_MOD_KT1 130 +#define BSIM3V1_MOD_KT1L 131 +#define BSIM3V1_MOD_K2 132 +#define BSIM3V1_MOD_KT2 133 +#define BSIM3V1_MOD_K3 134 +#define BSIM3V1_MOD_K3B 135 +#define BSIM3V1_MOD_W0 136 +#define BSIM3V1_MOD_NLX 137 + +#define BSIM3V1_MOD_DVT0 138 +#define BSIM3V1_MOD_DVT1 139 +#define BSIM3V1_MOD_DVT2 140 + +#define BSIM3V1_MOD_DVT0W 141 +#define BSIM3V1_MOD_DVT1W 142 +#define BSIM3V1_MOD_DVT2W 143 + +#define BSIM3V1_MOD_DROUT 144 +#define BSIM3V1_MOD_DSUB 145 +#define BSIM3V1_MOD_VTH0 146 +#define BSIM3V1_MOD_UA 147 +#define BSIM3V1_MOD_UA1 148 +#define BSIM3V1_MOD_UB 149 +#define BSIM3V1_MOD_UB1 150 +#define BSIM3V1_MOD_UC 151 +#define BSIM3V1_MOD_UC1 152 +#define BSIM3V1_MOD_U0 153 +#define BSIM3V1_MOD_UTE 154 +#define BSIM3V1_MOD_VOFF 155 +#define BSIM3V1_MOD_DELTA 156 +#define BSIM3V1_MOD_RDSW 157 +#define BSIM3V1_MOD_PRT 158 +#define BSIM3V1_MOD_LDD 159 +#define BSIM3V1_MOD_ETA 160 +#define BSIM3V1_MOD_ETA0 161 +#define BSIM3V1_MOD_ETAB 162 +#define BSIM3V1_MOD_PCLM 163 +#define BSIM3V1_MOD_PDIBL1 164 +#define BSIM3V1_MOD_PDIBL2 165 +#define BSIM3V1_MOD_PSCBE1 166 +#define BSIM3V1_MOD_PSCBE2 167 +#define BSIM3V1_MOD_PVAG 168 +#define BSIM3V1_MOD_WR 169 +#define BSIM3V1_MOD_DWG 170 +#define BSIM3V1_MOD_DWB 171 +#define BSIM3V1_MOD_B0 172 +#define BSIM3V1_MOD_B1 173 +#define BSIM3V1_MOD_ALPHA0 174 +#define BSIM3V1_MOD_BETA0 175 +#define BSIM3V1_MOD_PDIBLB 178 + +#define BSIM3V1_MOD_PRWG 179 +#define BSIM3V1_MOD_PRWB 180 + +#define BSIM3V1_MOD_CDSCD 181 +#define BSIM3V1_MOD_AGS 182 + +#define BSIM3V1_MOD_FRINGE 184 +#define BSIM3V1_MOD_ELM 185 +#define BSIM3V1_MOD_CGSL 186 +#define BSIM3V1_MOD_CGDL 187 +#define BSIM3V1_MOD_CKAPPA 188 +#define BSIM3V1_MOD_CF 189 +#define BSIM3V1_MOD_CLC 190 +#define BSIM3V1_MOD_CLE 191 +#define BSIM3V1_MOD_PARAMCHK 192 +#define BSIM3V1_MOD_VERSION 193 +#define BSIM3V1_MOD_VFBCV 194 + +#define BSIM3V1_MOD_HDIF 198 + +/* Length dependence */ +#define BSIM3V1_MOD_LCDSC 201 +#define BSIM3V1_MOD_LCDSCB 202 +#define BSIM3V1_MOD_LCIT 203 +#define BSIM3V1_MOD_LNFACTOR 204 +#define BSIM3V1_MOD_LXJ 205 +#define BSIM3V1_MOD_LVSAT 206 +#define BSIM3V1_MOD_LAT 207 +#define BSIM3V1_MOD_LA0 208 +#define BSIM3V1_MOD_LA1 209 +#define BSIM3V1_MOD_LA2 210 +#define BSIM3V1_MOD_LKETA 211 +#define BSIM3V1_MOD_LNSUB 212 +#define BSIM3V1_MOD_LNPEAK 213 +#define BSIM3V1_MOD_LNGATE 215 +#define BSIM3V1_MOD_LGAMMA1 216 +#define BSIM3V1_MOD_LGAMMA2 217 +#define BSIM3V1_MOD_LVBX 218 + +#define BSIM3V1_MOD_LVBM 220 + +#define BSIM3V1_MOD_LXT 222 +#define BSIM3V1_MOD_LK1 225 +#define BSIM3V1_MOD_LKT1 226 +#define BSIM3V1_MOD_LKT1L 227 +#define BSIM3V1_MOD_LK2 228 +#define BSIM3V1_MOD_LKT2 229 +#define BSIM3V1_MOD_LK3 230 +#define BSIM3V1_MOD_LK3B 231 +#define BSIM3V1_MOD_LW0 232 +#define BSIM3V1_MOD_LNLX 233 + +#define BSIM3V1_MOD_LDVT0 234 +#define BSIM3V1_MOD_LDVT1 235 +#define BSIM3V1_MOD_LDVT2 236 + +#define BSIM3V1_MOD_LDVT0W 237 +#define BSIM3V1_MOD_LDVT1W 238 +#define BSIM3V1_MOD_LDVT2W 239 + +#define BSIM3V1_MOD_LDROUT 240 +#define BSIM3V1_MOD_LDSUB 241 +#define BSIM3V1_MOD_LVTH0 242 +#define BSIM3V1_MOD_LUA 243 +#define BSIM3V1_MOD_LUA1 244 +#define BSIM3V1_MOD_LUB 245 +#define BSIM3V1_MOD_LUB1 246 +#define BSIM3V1_MOD_LUC 247 +#define BSIM3V1_MOD_LUC1 248 +#define BSIM3V1_MOD_LU0 249 +#define BSIM3V1_MOD_LUTE 250 +#define BSIM3V1_MOD_LVOFF 251 +#define BSIM3V1_MOD_LDELTA 252 +#define BSIM3V1_MOD_LRDSW 253 +#define BSIM3V1_MOD_LPRT 254 +#define BSIM3V1_MOD_LLDD 255 +#define BSIM3V1_MOD_LETA 256 +#define BSIM3V1_MOD_LETA0 257 +#define BSIM3V1_MOD_LETAB 258 +#define BSIM3V1_MOD_LPCLM 259 +#define BSIM3V1_MOD_LPDIBL1 260 +#define BSIM3V1_MOD_LPDIBL2 261 +#define BSIM3V1_MOD_LPSCBE1 262 +#define BSIM3V1_MOD_LPSCBE2 263 +#define BSIM3V1_MOD_LPVAG 264 +#define BSIM3V1_MOD_LWR 265 +#define BSIM3V1_MOD_LDWG 266 +#define BSIM3V1_MOD_LDWB 267 +#define BSIM3V1_MOD_LB0 268 +#define BSIM3V1_MOD_LB1 269 +#define BSIM3V1_MOD_LALPHA0 270 +#define BSIM3V1_MOD_LBETA0 271 +#define BSIM3V1_MOD_LPDIBLB 274 + +#define BSIM3V1_MOD_LPRWG 275 +#define BSIM3V1_MOD_LPRWB 276 + +#define BSIM3V1_MOD_LCDSCD 277 +#define BSIM3V1_MOD_LAGS 278 + + +#define BSIM3V1_MOD_LFRINGE 281 +#define BSIM3V1_MOD_LELM 282 +#define BSIM3V1_MOD_LCGSL 283 +#define BSIM3V1_MOD_LCGDL 284 +#define BSIM3V1_MOD_LCKAPPA 285 +#define BSIM3V1_MOD_LCF 286 +#define BSIM3V1_MOD_LCLC 287 +#define BSIM3V1_MOD_LCLE 288 +#define BSIM3V1_MOD_LVFBCV 289 + +/* Width dependence */ +#define BSIM3V1_MOD_WCDSC 301 +#define BSIM3V1_MOD_WCDSCB 302 +#define BSIM3V1_MOD_WCIT 303 +#define BSIM3V1_MOD_WNFACTOR 304 +#define BSIM3V1_MOD_WXJ 305 +#define BSIM3V1_MOD_WVSAT 306 +#define BSIM3V1_MOD_WAT 307 +#define BSIM3V1_MOD_WA0 308 +#define BSIM3V1_MOD_WA1 309 +#define BSIM3V1_MOD_WA2 310 +#define BSIM3V1_MOD_WKETA 311 +#define BSIM3V1_MOD_WNSUB 312 +#define BSIM3V1_MOD_WNPEAK 313 +#define BSIM3V1_MOD_WNGATE 315 +#define BSIM3V1_MOD_WGAMMA1 316 +#define BSIM3V1_MOD_WGAMMA2 317 +#define BSIM3V1_MOD_WVBX 318 + +#define BSIM3V1_MOD_WVBM 320 + +#define BSIM3V1_MOD_WXT 322 +#define BSIM3V1_MOD_WK1 325 +#define BSIM3V1_MOD_WKT1 326 +#define BSIM3V1_MOD_WKT1L 327 +#define BSIM3V1_MOD_WK2 328 +#define BSIM3V1_MOD_WKT2 329 +#define BSIM3V1_MOD_WK3 330 +#define BSIM3V1_MOD_WK3B 331 +#define BSIM3V1_MOD_WW0 332 +#define BSIM3V1_MOD_WNLX 333 + +#define BSIM3V1_MOD_WDVT0 334 +#define BSIM3V1_MOD_WDVT1 335 +#define BSIM3V1_MOD_WDVT2 336 + +#define BSIM3V1_MOD_WDVT0W 337 +#define BSIM3V1_MOD_WDVT1W 338 +#define BSIM3V1_MOD_WDVT2W 339 + +#define BSIM3V1_MOD_WDROUT 340 +#define BSIM3V1_MOD_WDSUB 341 +#define BSIM3V1_MOD_WVTH0 342 +#define BSIM3V1_MOD_WUA 343 +#define BSIM3V1_MOD_WUA1 344 +#define BSIM3V1_MOD_WUB 345 +#define BSIM3V1_MOD_WUB1 346 +#define BSIM3V1_MOD_WUC 347 +#define BSIM3V1_MOD_WUC1 348 +#define BSIM3V1_MOD_WU0 349 +#define BSIM3V1_MOD_WUTE 350 +#define BSIM3V1_MOD_WVOFF 351 +#define BSIM3V1_MOD_WDELTA 352 +#define BSIM3V1_MOD_WRDSW 353 +#define BSIM3V1_MOD_WPRT 354 +#define BSIM3V1_MOD_WLDD 355 +#define BSIM3V1_MOD_WETA 356 +#define BSIM3V1_MOD_WETA0 357 +#define BSIM3V1_MOD_WETAB 358 +#define BSIM3V1_MOD_WPCLM 359 +#define BSIM3V1_MOD_WPDIBL1 360 +#define BSIM3V1_MOD_WPDIBL2 361 +#define BSIM3V1_MOD_WPSCBE1 362 +#define BSIM3V1_MOD_WPSCBE2 363 +#define BSIM3V1_MOD_WPVAG 364 +#define BSIM3V1_MOD_WWR 365 +#define BSIM3V1_MOD_WDWG 366 +#define BSIM3V1_MOD_WDWB 367 +#define BSIM3V1_MOD_WB0 368 +#define BSIM3V1_MOD_WB1 369 +#define BSIM3V1_MOD_WALPHA0 370 +#define BSIM3V1_MOD_WBETA0 371 +#define BSIM3V1_MOD_WPDIBLB 374 + +#define BSIM3V1_MOD_WPRWG 375 +#define BSIM3V1_MOD_WPRWB 376 + +#define BSIM3V1_MOD_WCDSCD 377 +#define BSIM3V1_MOD_WAGS 378 + + +#define BSIM3V1_MOD_WFRINGE 381 +#define BSIM3V1_MOD_WELM 382 +#define BSIM3V1_MOD_WCGSL 383 +#define BSIM3V1_MOD_WCGDL 384 +#define BSIM3V1_MOD_WCKAPPA 385 +#define BSIM3V1_MOD_WCF 386 +#define BSIM3V1_MOD_WCLC 387 +#define BSIM3V1_MOD_WCLE 388 +#define BSIM3V1_MOD_WVFBCV 389 + +/* Cross-term dependence */ +#define BSIM3V1_MOD_PCDSC 401 +#define BSIM3V1_MOD_PCDSCB 402 +#define BSIM3V1_MOD_PCIT 403 +#define BSIM3V1_MOD_PNFACTOR 404 +#define BSIM3V1_MOD_PXJ 405 +#define BSIM3V1_MOD_PVSAT 406 +#define BSIM3V1_MOD_PAT 407 +#define BSIM3V1_MOD_PA0 408 +#define BSIM3V1_MOD_PA1 409 +#define BSIM3V1_MOD_PA2 410 +#define BSIM3V1_MOD_PKETA 411 +#define BSIM3V1_MOD_PNSUB 412 +#define BSIM3V1_MOD_PNPEAK 413 +#define BSIM3V1_MOD_PNGATE 415 +#define BSIM3V1_MOD_PGAMMA1 416 +#define BSIM3V1_MOD_PGAMMA2 417 +#define BSIM3V1_MOD_PVBX 418 + +#define BSIM3V1_MOD_PVBM 420 + +#define BSIM3V1_MOD_PXT 422 +#define BSIM3V1_MOD_PK1 425 +#define BSIM3V1_MOD_PKT1 426 +#define BSIM3V1_MOD_PKT1L 427 +#define BSIM3V1_MOD_PK2 428 +#define BSIM3V1_MOD_PKT2 429 +#define BSIM3V1_MOD_PK3 430 +#define BSIM3V1_MOD_PK3B 431 +#define BSIM3V1_MOD_PW0 432 +#define BSIM3V1_MOD_PNLX 433 + +#define BSIM3V1_MOD_PDVT0 434 +#define BSIM3V1_MOD_PDVT1 435 +#define BSIM3V1_MOD_PDVT2 436 + +#define BSIM3V1_MOD_PDVT0W 437 +#define BSIM3V1_MOD_PDVT1W 438 +#define BSIM3V1_MOD_PDVT2W 439 + +#define BSIM3V1_MOD_PDROUT 440 +#define BSIM3V1_MOD_PDSUB 441 +#define BSIM3V1_MOD_PVTH0 442 +#define BSIM3V1_MOD_PUA 443 +#define BSIM3V1_MOD_PUA1 444 +#define BSIM3V1_MOD_PUB 445 +#define BSIM3V1_MOD_PUB1 446 +#define BSIM3V1_MOD_PUC 447 +#define BSIM3V1_MOD_PUC1 448 +#define BSIM3V1_MOD_PU0 449 +#define BSIM3V1_MOD_PUTE 450 +#define BSIM3V1_MOD_PVOFF 451 +#define BSIM3V1_MOD_PDELTA 452 +#define BSIM3V1_MOD_PRDSW 453 +#define BSIM3V1_MOD_PPRT 454 +#define BSIM3V1_MOD_PLDD 455 +#define BSIM3V1_MOD_PETA 456 +#define BSIM3V1_MOD_PETA0 457 +#define BSIM3V1_MOD_PETAB 458 +#define BSIM3V1_MOD_PPCLM 459 +#define BSIM3V1_MOD_PPDIBL1 460 +#define BSIM3V1_MOD_PPDIBL2 461 +#define BSIM3V1_MOD_PPSCBE1 462 +#define BSIM3V1_MOD_PPSCBE2 463 +#define BSIM3V1_MOD_PPVAG 464 +#define BSIM3V1_MOD_PWR 465 +#define BSIM3V1_MOD_PDWG 466 +#define BSIM3V1_MOD_PDWB 467 +#define BSIM3V1_MOD_PB0 468 +#define BSIM3V1_MOD_PB1 469 +#define BSIM3V1_MOD_PALPHA0 470 +#define BSIM3V1_MOD_PBETA0 471 +#define BSIM3V1_MOD_PPDIBLB 474 + +#define BSIM3V1_MOD_PPRWG 475 +#define BSIM3V1_MOD_PPRWB 476 + +#define BSIM3V1_MOD_PCDSCD 477 +#define BSIM3V1_MOD_PAGS 478 + +#define BSIM3V1_MOD_PFRINGE 481 +#define BSIM3V1_MOD_PELM 482 +#define BSIM3V1_MOD_PCGSL 483 +#define BSIM3V1_MOD_PCGDL 484 +#define BSIM3V1_MOD_PCKAPPA 485 +#define BSIM3V1_MOD_PCF 486 +#define BSIM3V1_MOD_PCLC 487 +#define BSIM3V1_MOD_PCLE 488 +#define BSIM3V1_MOD_PVFBCV 489 + +#define BSIM3V1_MOD_TNOM 501 +#define BSIM3V1_MOD_CGSO 502 +#define BSIM3V1_MOD_CGDO 503 +#define BSIM3V1_MOD_CGBO 504 +#define BSIM3V1_MOD_XPART 505 + +#define BSIM3V1_MOD_RSH 506 +#define BSIM3V1_MOD_JS 507 +#define BSIM3V1_MOD_PB 508 +#define BSIM3V1_MOD_MJ 509 +#define BSIM3V1_MOD_PBSW 510 +#define BSIM3V1_MOD_MJSW 511 +#define BSIM3V1_MOD_CJ 512 +#define BSIM3V1_MOD_CJSW 513 +#define BSIM3V1_MOD_NMOS 514 +#define BSIM3V1_MOD_PMOS 515 + +#define BSIM3V1_MOD_NOIA 516 +#define BSIM3V1_MOD_NOIB 517 +#define BSIM3V1_MOD_NOIC 518 + +#define BSIM3V1_MOD_LINT 519 +#define BSIM3V1_MOD_LL 520 +#define BSIM3V1_MOD_LLN 521 +#define BSIM3V1_MOD_LW 522 +#define BSIM3V1_MOD_LWN 523 +#define BSIM3V1_MOD_LWL 524 +#define BSIM3V1_MOD_LMIN 525 +#define BSIM3V1_MOD_LMAX 526 + +#define BSIM3V1_MOD_WINT 527 +#define BSIM3V1_MOD_WL 528 +#define BSIM3V1_MOD_WLN 529 +#define BSIM3V1_MOD_WW 530 +#define BSIM3V1_MOD_WWN 531 +#define BSIM3V1_MOD_WWL 532 +#define BSIM3V1_MOD_WMIN 533 +#define BSIM3V1_MOD_WMAX 534 + +#define BSIM3V1_MOD_DWC 535 +#define BSIM3V1_MOD_DLC 536 + +#define BSIM3V1_MOD_EM 537 +#define BSIM3V1_MOD_EF 538 +#define BSIM3V1_MOD_AF 539 +#define BSIM3V1_MOD_KF 540 + +#define BSIM3V1_MOD_NJ 541 +#define BSIM3V1_MOD_XTI 542 + +#define BSIM3V1_MOD_PBSWG 543 +#define BSIM3V1_MOD_MJSWG 544 +#define BSIM3V1_MOD_CJSWG 545 +#define BSIM3V1_MOD_JSW 546 + +/* device questions */ +#define BSIM3V1_DNODE 601 +#define BSIM3V1_GNODE 602 +#define BSIM3V1_SNODE 603 +#define BSIM3V1_BNODE 604 +#define BSIM3V1_DNODEPRIME 605 +#define BSIM3V1_SNODEPRIME 606 +#define BSIM3V1_VBD 607 +#define BSIM3V1_VBS 608 +#define BSIM3V1_VGS 609 +#define BSIM3V1_VDS 610 +#define BSIM3V1_CD 611 +#define BSIM3V1_CBS 612 +#define BSIM3V1_CBD 613 +#define BSIM3V1_GM 614 +#define BSIM3V1_GDS 615 +#define BSIM3V1_GMBS 616 +#define BSIM3V1_GBD 617 +#define BSIM3V1_GBS 618 +#define BSIM3V1_QB 619 +#define BSIM3V1_CQB 620 +#define BSIM3V1_QG 621 +#define BSIM3V1_CQG 622 +#define BSIM3V1_QD 623 +#define BSIM3V1_CQD 624 +#define BSIM3V1_CGG 625 +#define BSIM3V1_CGD 626 +#define BSIM3V1_CGS 627 +#define BSIM3V1_CBG 628 +#define BSIM3V1_CAPBD 629 +#define BSIM3V1_CQBD 630 +#define BSIM3V1_CAPBS 631 +#define BSIM3V1_CQBS 632 +#define BSIM3V1_CDG 633 +#define BSIM3V1_CDD 634 +#define BSIM3V1_CDS 635 +#define BSIM3V1_VON 636 +#define BSIM3V1_VDSAT 637 +#define BSIM3V1_QBS 638 +#define BSIM3V1_QBD 639 +#define BSIM3V1_SOURCECONDUCT 640 +#define BSIM3V1_DRAINCONDUCT 641 +#define BSIM3V1_CBDB 642 +#define BSIM3V1_CBSB 643 + +#include "bsim3v1ext.h" + +#ifdef __STDC__ +extern void BSIM3V1evaluate(double,double,double,BSIM3V1instance*,BSIM3V1model*, + double*,double*,double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, CKTcircuit*); +extern int BSIM3V1debug(BSIM3V1model*, BSIM3V1instance*, CKTcircuit*, int); +extern int BSIM3V1checkModel(BSIM3V1model*, BSIM3V1instance*, CKTcircuit*); +#else /* stdc */ +extern void BSIM3V1evaluate(); +extern int BSIM3V1debug(); +extern int BSIM3V1checkModel(); +#endif /* stdc */ + +#endif /*BSIM3V1*/ + + + + diff --git a/src/spicelib/devices/bsim3v1/bsim3v1ext.h b/src/spicelib/devices/bsim3v1/bsim3v1ext.h new file mode 100644 index 000000000..b8a752f71 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/bsim3v1ext.h @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +File: bsim3v1ext.h +**********/ + +#ifdef __STDC__ +extern int BSIM3V1acLoad(GENmodel *,CKTcircuit*); +extern int BSIM3V1ask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int BSIM3V1convTest(GENmodel *,CKTcircuit*); +extern int BSIM3V1delete(GENmodel*,IFuid,GENinstance**); +extern void BSIM3V1destroy(GENmodel**); +extern int BSIM3V1getic(GENmodel*,CKTcircuit*); +extern int BSIM3V1load(GENmodel*,CKTcircuit*); +extern int BSIM3V1mAsk(CKTcircuit*,GENmodel *,int, IFvalue*); +extern int BSIM3V1mDelete(GENmodel**,IFuid,GENmodel*); +extern int BSIM3V1mParam(int,IFvalue*,GENmodel*); +extern void BSIM3V1mosCap(CKTcircuit*, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*); +extern int BSIM3V1param(int,IFvalue*,GENinstance*,IFvalue*); +extern int BSIM3V1pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int BSIM3V1setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int BSIM3V1temp(GENmodel*,CKTcircuit*); +extern int BSIM3V1trunc(GENmodel*,CKTcircuit*,double*); +extern int BSIM3V1noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ +extern int BSIM3V1acLoad(); +extern int BSIM3V1delete(); +extern void BSIM3V1destroy(); +extern int BSIM3V1getic(); +extern int BSIM3V1load(); +extern int BSIM3V1mDelete(); +extern int BSIM3V1ask(); +extern int BSIM3V1mAsk(); +extern int BSIM3V1convTest(); +extern int BSIM3V1temp(); +extern int BSIM3V1mParam(); +extern void BSIM3V1mosCap(); +extern int BSIM3V1param(); +extern int BSIM3V1pzLoad(); +extern int BSIM3V1setup(); +extern int BSIM3V1trunc(); +extern int BSIM3V1noise(); + +#endif /* stdc */ + diff --git a/src/spicelib/devices/bsim3v1/bsim3v1itf.h b/src/spicelib/devices/bsim3v1/bsim3v1itf.h new file mode 100644 index 000000000..2c1d50386 --- /dev/null +++ b/src/spicelib/devices/bsim3v1/bsim3v1itf.h @@ -0,0 +1,92 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +File: bsim3v1itf.h +**********/ +#ifdef DEV_bsim3v1 + +#ifndef DEV_BSIM3V1 +#define DEV_BSIM3V1 + +#include "bsim3v1ext.h" + +extern IFparm BSIM3V1pTable[ ]; +extern IFparm BSIM3V1mPTable[ ]; +extern char *BSIM3V1names[ ]; +extern int BSIM3V1pTSize; +extern int BSIM3V1mPTSize; +extern int BSIM3V1nSize; +extern int BSIM3V1iSize; +extern int BSIM3V1mSize; + +SPICEdev BSIM3V1info = { + { "BSIM3V1", + "Berkeley Short Channel IGFET Model Version-3 (3v3.1)", + + &BSIM3V1nSize, + &BSIM3V1nSize, + BSIM3V1names, + + &BSIM3V1pTSize, + BSIM3V1pTable, + + &BSIM3V1mPTSize, + BSIM3V1mPTable, + DEV_DEFAULT, + + }, + + BSIM3V1param, + BSIM3V1mParam, + BSIM3V1load, + BSIM3V1setup, + NULL, + BSIM3V1setup, + BSIM3V1temp, + BSIM3V1trunc, + NULL, + BSIM3V1acLoad, + NULL, + BSIM3V1destroy, +#ifdef DELETES + BSIM3V1mDelete, + BSIM3V1delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + BSIM3V1getic, + BSIM3V1ask, + BSIM3V1mAsk, +#ifdef AN_pz + BSIM3V1pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + BSIM3V1convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + +#ifdef AN_noise + BSIM3V1noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &BSIM3V1iSize, + &BSIM3V1mSize + +}; + +#endif +#endif + diff --git a/src/spicelib/devices/bsim3v2/ChangeLog b/src/spicelib/devices/bsim3v2/ChangeLog new file mode 100644 index 000000000..097f34cde --- /dev/null +++ b/src/spicelib/devices/bsim3v2/ChangeLog @@ -0,0 +1,17 @@ +2000-01-29 Paolo Nenzi + * bsim3v2def.h : Added BSIM3V2owner to the BSIM3V2instance structure + for compatibility with Cider. This spice uses a modificed version of + devices, as desscribed in the CIDer package, for a "parallel" + processing support. + + * b3v2{acld,cvtest,getic,ld,pzld,set,temp,trunc}.c: + added the check if the current instance is a task of this + processor. This is part of the "parallel" support of Cider. + +2000-01-16 Emmanuel Rouat + + * *.c : replaced all FABS macros by the 'fabs' function + + * *.c : had to rename structure bsim3SizeDependParam into + BSIM3V2SizeDependParam for consistency + diff --git a/src/spicelib/devices/bsim3v2/Makefile.am b/src/spicelib/devices/bsim3v2/Makefile.am new file mode 100644 index 000000000..539e76857 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/Makefile.am @@ -0,0 +1,32 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libbsim3v2.la + +libbsim3v2_la_SOURCES = \ + b3v2.c \ + b3v2acld.c \ + b3v2ask.c \ + b3v2check.c \ + b3v2cvtest.c \ + b3v2del.c \ + b3v2dest.c \ + b3v2getic.c \ + b3v2ld.c \ + b3v2mask.c \ + b3v2mdel.c \ + b3v2mpar.c \ + b3v2noi.c \ + b3v2par.c \ + b3v2pzld.c \ + b3v2set.c \ + b3v2temp.c \ + b3v2trunc.c \ + bsim3v2def.h \ + bsim3v2ext.h \ + bsim3v2itf.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/bsim3v2/b3v2.c b/src/spicelib/devices/bsim3v2/b3v2.c new file mode 100644 index 000000000..55b5528ea --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2.c @@ -0,0 +1,491 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: b3v2.c +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "bsim3v2def.h" +#include "suffix.h" + +IFparm BSIM3V2pTable[] = { /* parameters */ +IOP( "l", BSIM3V2_L, IF_REAL , "Length"), +IOP( "w", BSIM3V2_W, IF_REAL , "Width"), +IOP( "ad", BSIM3V2_AD, IF_REAL , "Drain area"), +IOP( "as", BSIM3V2_AS, IF_REAL , "Source area"), +IOP( "pd", BSIM3V2_PD, IF_REAL , "Drain perimeter"), +IOP( "ps", BSIM3V2_PS, IF_REAL , "Source perimeter"), +IOP( "nrd", BSIM3V2_NRD, IF_REAL , "Number of squares in drain"), +IOP( "nrs", BSIM3V2_NRS, IF_REAL , "Number of squares in source"), +IOP( "off", BSIM3V2_OFF, IF_FLAG , "Device is initially off"), +IOP( "nqsmod", BSIM3V2_NQSMOD, IF_INTEGER, "Non-quasi-static model selector"), +IP( "ic", BSIM3V2_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"), +OP( "gmbs", BSIM3V2_GMBS, IF_REAL, "Gmb"), +OP( "gm", BSIM3V2_GM, IF_REAL, "Gm"), +OP( "gds", BSIM3V2_GDS, IF_REAL, "Gds"), +OP( "vdsat", BSIM3V2_VDSAT, IF_REAL, "Vdsat"), +OP( "vth", BSIM3V2_VON, IF_REAL, "Vth"), +OP( "id", BSIM3V2_CD, IF_REAL, "Ids"), +OP( "vbs", BSIM3V2_VBS, IF_REAL, "Vbs"), +OP( "vgs", BSIM3V2_VGS, IF_REAL, "Vgs"), +OP( "vds", BSIM3V2_VDS, IF_REAL, "Vds"), +}; + +IFparm BSIM3V2mPTable[] = { /* model parameters */ +IOP( "capmod", BSIM3V2_MOD_CAPMOD, IF_INTEGER, "Capacitance model selector"), +IOP( "mobmod", BSIM3V2_MOD_MOBMOD, IF_INTEGER, "Mobility model selector"), +IOP( "noimod", BSIM3V2_MOD_NOIMOD, IF_INTEGER, "Noise model selector"), +IOP( "paramchk", BSIM3V2_MOD_PARAMCHK, IF_INTEGER, "Model parameter checking selector"), +IOP( "binunit", BSIM3V2_MOD_BINUNIT, IF_INTEGER, "Bin unit selector"), +IOP( "version", BSIM3V2_MOD_VERSION, IF_REAL, " parameter for model version"), +IOP( "tox", BSIM3V2_MOD_TOX, IF_REAL, "Gate oxide thickness in meters"), + +IOP( "toxm", BSIM3V2_MOD_TOXM, IF_REAL, "Gate oxide thickness used in extraction"), +IOP( "cdsc", BSIM3V2_MOD_CDSC, IF_REAL, "Drain/Source and channel coupling capacitance"), +IOP( "cdscb", BSIM3V2_MOD_CDSCB, IF_REAL, "Body-bias dependence of cdsc"), +IOP( "cdscd", BSIM3V2_MOD_CDSCD, IF_REAL, "Drain-bias dependence of cdsc"), +IOP( "cit", BSIM3V2_MOD_CIT, IF_REAL, "Interface state capacitance"), +IOP( "nfactor", BSIM3V2_MOD_NFACTOR, IF_REAL, "Subthreshold swing Coefficient"), +IOP( "xj", BSIM3V2_MOD_XJ, IF_REAL, "Junction depth in meters"), +IOP( "vsat", BSIM3V2_MOD_VSAT, IF_REAL, "Saturation velocity at tnom"), +IOP( "at", BSIM3V2_MOD_AT, IF_REAL, "Temperature coefficient of vsat"), +IOP( "a0", BSIM3V2_MOD_A0, IF_REAL, "Non-uniform depletion width effect coefficient."), +IOP( "ags", BSIM3V2_MOD_AGS, IF_REAL, "Gate bias coefficient of Abulk."), +IOP( "a1", BSIM3V2_MOD_A1, IF_REAL, "Non-saturation effect coefficient"), +IOP( "a2", BSIM3V2_MOD_A2, IF_REAL, "Non-saturation effect coefficient"), +IOP( "keta", BSIM3V2_MOD_KETA, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect."), +IOP( "nsub", BSIM3V2_MOD_NSUB, IF_REAL, "Substrate doping concentration"), +IOP( "nch", BSIM3V2_MOD_NPEAK, IF_REAL, "Channel doping concentration"), +IOP( "ngate", BSIM3V2_MOD_NGATE, IF_REAL, "Poly-gate doping concentration"), +IOP( "gamma1", BSIM3V2_MOD_GAMMA1, IF_REAL, "Vth body coefficient"), +IOP( "gamma2", BSIM3V2_MOD_GAMMA2, IF_REAL, "Vth body coefficient"), +IOP( "vbx", BSIM3V2_MOD_VBX, IF_REAL, "Vth transition body Voltage"), +IOP( "vbm", BSIM3V2_MOD_VBM, IF_REAL, "Maximum body voltage"), + +IOP( "xt", BSIM3V2_MOD_XT, IF_REAL, "Doping depth"), +IOP( "k1", BSIM3V2_MOD_K1, IF_REAL, "Bulk effect coefficient 1"), +IOP( "kt1", BSIM3V2_MOD_KT1, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt1l", BSIM3V2_MOD_KT1L, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt2", BSIM3V2_MOD_KT2, IF_REAL, "Body-coefficient of kt1"), +IOP( "k2", BSIM3V2_MOD_K2, IF_REAL, "Bulk effect coefficient 2"), +IOP( "k3", BSIM3V2_MOD_K3, IF_REAL, "Narrow width effect coefficient"), +IOP( "k3b", BSIM3V2_MOD_K3B, IF_REAL, "Body effect coefficient of k3"), +IOP( "w0", BSIM3V2_MOD_W0, IF_REAL, "Narrow width effect parameter"), +IOP( "nlx", BSIM3V2_MOD_NLX, IF_REAL, "Lateral non-uniform doping effect"), +IOP( "dvt0", BSIM3V2_MOD_DVT0, IF_REAL, "Short channel effect coeff. 0"), +IOP( "dvt1", BSIM3V2_MOD_DVT1, IF_REAL, "Short channel effect coeff. 1"), +IOP( "dvt2", BSIM3V2_MOD_DVT2, IF_REAL, "Short channel effect coeff. 2"), +IOP( "dvt0w", BSIM3V2_MOD_DVT0W, IF_REAL, "Narrow Width coeff. 0"), +IOP( "dvt1w", BSIM3V2_MOD_DVT1W, IF_REAL, "Narrow Width effect coeff. 1"), +IOP( "dvt2w", BSIM3V2_MOD_DVT2W, IF_REAL, "Narrow Width effect coeff. 2"), +IOP( "drout", BSIM3V2_MOD_DROUT, IF_REAL, "DIBL coefficient of output resistance"), +IOP( "dsub", BSIM3V2_MOD_DSUB, IF_REAL, "DIBL coefficient in the subthreshold region"), +IOP( "vth0", BSIM3V2_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "vtho", BSIM3V2_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "ua", BSIM3V2_MOD_UA, IF_REAL, "Linear gate dependence of mobility"), +IOP( "ua1", BSIM3V2_MOD_UA1, IF_REAL, "Temperature coefficient of ua"), +IOP( "ub", BSIM3V2_MOD_UB, IF_REAL, "Quadratic gate dependence of mobility"), +IOP( "ub1", BSIM3V2_MOD_UB1, IF_REAL, "Temperature coefficient of ub"), +IOP( "uc", BSIM3V2_MOD_UC, IF_REAL, "Body-bias dependence of mobility"), +IOP( "uc1", BSIM3V2_MOD_UC1, IF_REAL, "Temperature coefficient of uc"), +IOP( "u0", BSIM3V2_MOD_U0, IF_REAL, "Low-field mobility at Tnom"), +IOP( "ute", BSIM3V2_MOD_UTE, IF_REAL, "Temperature coefficient of mobility"), +IOP( "voff", BSIM3V2_MOD_VOFF, IF_REAL, "Threshold voltage offset"), +IOP( "tnom", BSIM3V2_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), +IOP( "cgso", BSIM3V2_MOD_CGSO, IF_REAL, "Gate-source overlap capacitance per width"), +IOP( "cgdo", BSIM3V2_MOD_CGDO, IF_REAL, "Gate-drain overlap capacitance per width"), +IOP( "cgbo", BSIM3V2_MOD_CGBO, IF_REAL, "Gate-bulk overlap capacitance per length"), +IOP( "xpart", BSIM3V2_MOD_XPART, IF_REAL, "Channel charge partitioning"), +IOP( "elm", BSIM3V2_MOD_ELM, IF_REAL, "Non-quasi-static Elmore Constant Parameter"), +IOP( "delta", BSIM3V2_MOD_DELTA, IF_REAL, "Effective Vds parameter"), +IOP( "rsh", BSIM3V2_MOD_RSH, IF_REAL, "Source-drain sheet resistance"), +IOP( "rdsw", BSIM3V2_MOD_RDSW, IF_REAL, "Source-drain resistance per width"), + +IOP( "prwg", BSIM3V2_MOD_PRWG, IF_REAL, "Gate-bias effect on parasitic resistance "), +IOP( "prwb", BSIM3V2_MOD_PRWB, IF_REAL, "Body-effect on parasitic resistance "), + +IOP( "prt", BSIM3V2_MOD_PRT, IF_REAL, "Temperature coefficient of parasitic resistance "), +IOP( "eta0", BSIM3V2_MOD_ETA0, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "etab", BSIM3V2_MOD_ETAB, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "pclm", BSIM3V2_MOD_PCLM, IF_REAL, "Channel length modulation Coefficient"), +IOP( "pdiblc1", BSIM3V2_MOD_PDIBL1, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblc2", BSIM3V2_MOD_PDIBL2, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblcb", BSIM3V2_MOD_PDIBLB, IF_REAL, "Body-effect on drain-induced barrier lowering"), +IOP( "pscbe1", BSIM3V2_MOD_PSCBE1, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pscbe2", BSIM3V2_MOD_PSCBE2, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pvag", BSIM3V2_MOD_PVAG, IF_REAL, "Gate dependence of output resistance parameter"), +IOP( "js", BSIM3V2_MOD_JS, IF_REAL, "Source/drain junction reverse saturation current density"), +IOP( "jsw", BSIM3V2_MOD_JSW, IF_REAL, "Sidewall junction reverse saturation current density"), +IOP( "pb", BSIM3V2_MOD_PB, IF_REAL, "Source/drain junction built-in potential"), +IOP( "nj", BSIM3V2_MOD_NJ, IF_REAL, "Source/drain junction emission coefficient"), +IOP( "xti", BSIM3V2_MOD_XTI, IF_REAL, "Junction current temperature exponent"), +IOP( "mj", BSIM3V2_MOD_MJ, IF_REAL, "Source/drain bottom junction capacitance grading coefficient"), +IOP( "pbsw", BSIM3V2_MOD_PBSW, IF_REAL, "Source/drain sidewall junction capacitance built in potential"), +IOP( "mjsw", BSIM3V2_MOD_MJSW, IF_REAL, "Source/drain sidewall junction capacitance grading coefficient"), +IOP( "pbswg", BSIM3V2_MOD_PBSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance built in potential"), +IOP( "mjswg", BSIM3V2_MOD_MJSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance grading coefficient"), +IOP( "cj", BSIM3V2_MOD_CJ, IF_REAL, "Source/drain bottom junction capacitance per unit area"), +IOP( "vfbcv", BSIM3V2_MOD_VFBCV, IF_REAL, "Flat Band Voltage parameter for capmod=0 only"), +IOP( "vfb", BSIM3V2_MOD_VFB, IF_REAL, "Flat Band Voltage"), +IOP( "cjsw", BSIM3V2_MOD_CJSW, IF_REAL, "Source/drain sidewall junction capacitance per unit periphery"), +IOP( "cjswg", BSIM3V2_MOD_CJSWG, IF_REAL, "Source/drain (gate side) sidewall junction capacitance per unit width"), +IOP( "tpb", BSIM3V2_MOD_TPB, IF_REAL, "Temperature coefficient of pb"), +IOP( "tcj", BSIM3V2_MOD_TCJ, IF_REAL, "Temperature coefficient of cj"), +IOP( "tpbsw", BSIM3V2_MOD_TPBSW, IF_REAL, "Temperature coefficient of pbsw"), +IOP( "tcjsw", BSIM3V2_MOD_TCJSW, IF_REAL, "Temperature coefficient of cjsw"), +IOP( "tpbswg", BSIM3V2_MOD_TPBSWG, IF_REAL, "Temperature coefficient of pbswg"), +IOP( "tcjswg", BSIM3V2_MOD_TCJSWG, IF_REAL, "Temperature coefficient of cjswg"), +IOP( "acde", BSIM3V2_MOD_ACDE, IF_REAL, "Exponential coefficient for finite charge thickness"), +IOP( "moin", BSIM3V2_MOD_MOIN, IF_REAL, "Coefficient for gate-bias dependent surface potential"), +IOP( "noff", BSIM3V2_MOD_NOFF, IF_REAL, "C-V turn-on/off parameter"), +IOP( "voffcv", BSIM3V2_MOD_VOFFCV, IF_REAL, "C-V lateral-shift parameter"), +IOP( "lint", BSIM3V2_MOD_LINT, IF_REAL, "Length reduction parameter"), +IOP( "ll", BSIM3V2_MOD_LL, IF_REAL, "Length reduction parameter"), +IOP( "llc", BSIM3V2_MOD_LLC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lln", BSIM3V2_MOD_LLN, IF_REAL, "Length reduction parameter"), +IOP( "lw", BSIM3V2_MOD_LW, IF_REAL, "Length reduction parameter"), +IOP( "lwc", BSIM3V2_MOD_LWC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lwn", BSIM3V2_MOD_LWN, IF_REAL, "Length reduction parameter"), +IOP( "lwl", BSIM3V2_MOD_LWL, IF_REAL, "Length reduction parameter"), +IOP( "lwlc", BSIM3V2_MOD_LWLC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lmin", BSIM3V2_MOD_LMIN, IF_REAL, "Minimum length for the model"), +IOP( "lmax", BSIM3V2_MOD_LMAX, IF_REAL, "Maximum length for the model"), + +IOP( "wr", BSIM3V2_MOD_WR, IF_REAL, "Width dependence of rds"), +IOP( "wint", BSIM3V2_MOD_WINT, IF_REAL, "Width reduction parameter"), +IOP( "dwg", BSIM3V2_MOD_DWG, IF_REAL, "Width reduction parameter"), +IOP( "dwb", BSIM3V2_MOD_DWB, IF_REAL, "Width reduction parameter"), + +IOP( "wl", BSIM3V2_MOD_WL, IF_REAL, "Width reduction parameter"), +IOP( "wlc", BSIM3V2_MOD_WLC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wln", BSIM3V2_MOD_WLN, IF_REAL, "Width reduction parameter"), +IOP( "ww", BSIM3V2_MOD_WW, IF_REAL, "Width reduction parameter"), +IOP( "wwc", BSIM3V2_MOD_WWC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wwn", BSIM3V2_MOD_WWN, IF_REAL, "Width reduction parameter"), +IOP( "wwl", BSIM3V2_MOD_WWL, IF_REAL, "Width reduction parameter"), +IOP( "wwlc", BSIM3V2_MOD_WWLC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wmin", BSIM3V2_MOD_WMIN, IF_REAL, "Minimum width for the model"), +IOP( "wmax", BSIM3V2_MOD_WMAX, IF_REAL, "Maximum width for the model"), + +IOP( "b0", BSIM3V2_MOD_B0, IF_REAL, "Abulk narrow width parameter"), +IOP( "b1", BSIM3V2_MOD_B1, IF_REAL, "Abulk narrow width parameter"), + +IOP( "cgsl", BSIM3V2_MOD_CGSL, IF_REAL, "New C-V model parameter"), +IOP( "cgdl", BSIM3V2_MOD_CGDL, IF_REAL, "New C-V model parameter"), +IOP( "ckappa", BSIM3V2_MOD_CKAPPA, IF_REAL, "New C-V model parameter"), +IOP( "cf", BSIM3V2_MOD_CF, IF_REAL, "Fringe capacitance parameter"), +IOP( "clc", BSIM3V2_MOD_CLC, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "cle", BSIM3V2_MOD_CLE, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "dwc", BSIM3V2_MOD_DWC, IF_REAL, "Delta W for C-V model"), +IOP( "dlc", BSIM3V2_MOD_DLC, IF_REAL, "Delta L for C-V model"), + +IOP( "alpha0", BSIM3V2_MOD_ALPHA0, IF_REAL, "substrate current model parameter"), +IOP( "alpha1", BSIM3V2_MOD_ALPHA1, IF_REAL, "substrate current model parameter"), +IOP( "beta0", BSIM3V2_MOD_BETA0, IF_REAL, "substrate current model parameter"), +IOP( "ijth", BSIM3V2_MOD_IJTH, IF_REAL, "Diode limiting current"), + +IOP( "lcdsc", BSIM3V2_MOD_LCDSC, IF_REAL, "Length dependence of cdsc"), +IOP( "lcdscb", BSIM3V2_MOD_LCDSCB, IF_REAL, "Length dependence of cdscb"), +IOP( "lcdscd", BSIM3V2_MOD_LCDSCD, IF_REAL, "Length dependence of cdscd"), +IOP( "lcit", BSIM3V2_MOD_LCIT, IF_REAL, "Length dependence of cit"), +IOP( "lnfactor", BSIM3V2_MOD_LNFACTOR, IF_REAL, "Length dependence of nfactor"), +IOP( "lxj", BSIM3V2_MOD_LXJ, IF_REAL, "Length dependence of xj"), +IOP( "lvsat", BSIM3V2_MOD_LVSAT, IF_REAL, "Length dependence of vsat"), +IOP( "lat", BSIM3V2_MOD_LAT, IF_REAL, "Length dependence of at"), +IOP( "la0", BSIM3V2_MOD_LA0, IF_REAL, "Length dependence of a0"), +IOP( "lags", BSIM3V2_MOD_LAGS, IF_REAL, "Length dependence of ags"), +IOP( "la1", BSIM3V2_MOD_LA1, IF_REAL, "Length dependence of a1"), +IOP( "la2", BSIM3V2_MOD_LA2, IF_REAL, "Length dependence of a2"), +IOP( "lketa", BSIM3V2_MOD_LKETA, IF_REAL, "Length dependence of keta"), +IOP( "lnsub", BSIM3V2_MOD_LNSUB, IF_REAL, "Length dependence of nsub"), +IOP( "lnch", BSIM3V2_MOD_LNPEAK, IF_REAL, "Length dependence of nch"), +IOP( "lngate", BSIM3V2_MOD_LNGATE, IF_REAL, "Length dependence of ngate"), +IOP( "lgamma1", BSIM3V2_MOD_LGAMMA1, IF_REAL, "Length dependence of gamma1"), +IOP( "lgamma2", BSIM3V2_MOD_LGAMMA2, IF_REAL, "Length dependence of gamma2"), +IOP( "lvbx", BSIM3V2_MOD_LVBX, IF_REAL, "Length dependence of vbx"), +IOP( "lvbm", BSIM3V2_MOD_LVBM, IF_REAL, "Length dependence of vbm"), +IOP( "lxt", BSIM3V2_MOD_LXT, IF_REAL, "Length dependence of xt"), +IOP( "lk1", BSIM3V2_MOD_LK1, IF_REAL, "Length dependence of k1"), +IOP( "lkt1", BSIM3V2_MOD_LKT1, IF_REAL, "Length dependence of kt1"), +IOP( "lkt1l", BSIM3V2_MOD_LKT1L, IF_REAL, "Length dependence of kt1l"), +IOP( "lkt2", BSIM3V2_MOD_LKT2, IF_REAL, "Length dependence of kt2"), +IOP( "lk2", BSIM3V2_MOD_LK2, IF_REAL, "Length dependence of k2"), +IOP( "lk3", BSIM3V2_MOD_LK3, IF_REAL, "Length dependence of k3"), +IOP( "lk3b", BSIM3V2_MOD_LK3B, IF_REAL, "Length dependence of k3b"), +IOP( "lw0", BSIM3V2_MOD_LW0, IF_REAL, "Length dependence of w0"), +IOP( "lnlx", BSIM3V2_MOD_LNLX, IF_REAL, "Length dependence of nlx"), +IOP( "ldvt0", BSIM3V2_MOD_LDVT0, IF_REAL, "Length dependence of dvt0"), +IOP( "ldvt1", BSIM3V2_MOD_LDVT1, IF_REAL, "Length dependence of dvt1"), +IOP( "ldvt2", BSIM3V2_MOD_LDVT2, IF_REAL, "Length dependence of dvt2"), +IOP( "ldvt0w", BSIM3V2_MOD_LDVT0W, IF_REAL, "Length dependence of dvt0w"), +IOP( "ldvt1w", BSIM3V2_MOD_LDVT1W, IF_REAL, "Length dependence of dvt1w"), +IOP( "ldvt2w", BSIM3V2_MOD_LDVT2W, IF_REAL, "Length dependence of dvt2w"), +IOP( "ldrout", BSIM3V2_MOD_LDROUT, IF_REAL, "Length dependence of drout"), +IOP( "ldsub", BSIM3V2_MOD_LDSUB, IF_REAL, "Length dependence of dsub"), +IOP( "lvth0", BSIM3V2_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lvtho", BSIM3V2_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lua", BSIM3V2_MOD_LUA, IF_REAL, "Length dependence of ua"), +IOP( "lua1", BSIM3V2_MOD_LUA1, IF_REAL, "Length dependence of ua1"), +IOP( "lub", BSIM3V2_MOD_LUB, IF_REAL, "Length dependence of ub"), +IOP( "lub1", BSIM3V2_MOD_LUB1, IF_REAL, "Length dependence of ub1"), +IOP( "luc", BSIM3V2_MOD_LUC, IF_REAL, "Length dependence of uc"), +IOP( "luc1", BSIM3V2_MOD_LUC1, IF_REAL, "Length dependence of uc1"), +IOP( "lu0", BSIM3V2_MOD_LU0, IF_REAL, "Length dependence of u0"), +IOP( "lute", BSIM3V2_MOD_LUTE, IF_REAL, "Length dependence of ute"), +IOP( "lvoff", BSIM3V2_MOD_LVOFF, IF_REAL, "Length dependence of voff"), +IOP( "lelm", BSIM3V2_MOD_LELM, IF_REAL, "Length dependence of elm"), +IOP( "ldelta", BSIM3V2_MOD_LDELTA, IF_REAL, "Length dependence of delta"), +IOP( "lrdsw", BSIM3V2_MOD_LRDSW, IF_REAL, "Length dependence of rdsw "), + +IOP( "lprwg", BSIM3V2_MOD_LPRWG, IF_REAL, "Length dependence of prwg "), +IOP( "lprwb", BSIM3V2_MOD_LPRWB, IF_REAL, "Length dependence of prwb "), + +IOP( "lprt", BSIM3V2_MOD_LPRT, IF_REAL, "Length dependence of prt "), +IOP( "leta0", BSIM3V2_MOD_LETA0, IF_REAL, "Length dependence of eta0"), +IOP( "letab", BSIM3V2_MOD_LETAB, IF_REAL, "Length dependence of etab"), +IOP( "lpclm", BSIM3V2_MOD_LPCLM, IF_REAL, "Length dependence of pclm"), +IOP( "lpdiblc1", BSIM3V2_MOD_LPDIBL1, IF_REAL, "Length dependence of pdiblc1"), +IOP( "lpdiblc2", BSIM3V2_MOD_LPDIBL2, IF_REAL, "Length dependence of pdiblc2"), +IOP( "lpdiblcb", BSIM3V2_MOD_LPDIBLB, IF_REAL, "Length dependence of pdiblcb"), +IOP( "lpscbe1", BSIM3V2_MOD_LPSCBE1, IF_REAL, "Length dependence of pscbe1"), +IOP( "lpscbe2", BSIM3V2_MOD_LPSCBE2, IF_REAL, "Length dependence of pscbe2"), +IOP( "lpvag", BSIM3V2_MOD_LPVAG, IF_REAL, "Length dependence of pvag"), +IOP( "lwr", BSIM3V2_MOD_LWR, IF_REAL, "Length dependence of wr"), +IOP( "ldwg", BSIM3V2_MOD_LDWG, IF_REAL, "Length dependence of dwg"), +IOP( "ldwb", BSIM3V2_MOD_LDWB, IF_REAL, "Length dependence of dwb"), +IOP( "lb0", BSIM3V2_MOD_LB0, IF_REAL, "Length dependence of b0"), +IOP( "lb1", BSIM3V2_MOD_LB1, IF_REAL, "Length dependence of b1"), +IOP( "lcgsl", BSIM3V2_MOD_LCGSL, IF_REAL, "Length dependence of cgsl"), +IOP( "lcgdl", BSIM3V2_MOD_LCGDL, IF_REAL, "Length dependence of cgdl"), +IOP( "lckappa", BSIM3V2_MOD_LCKAPPA, IF_REAL, "Length dependence of ckappa"), +IOP( "lcf", BSIM3V2_MOD_LCF, IF_REAL, "Length dependence of cf"), +IOP( "lclc", BSIM3V2_MOD_LCLC, IF_REAL, "Length dependence of clc"), +IOP( "lcle", BSIM3V2_MOD_LCLE, IF_REAL, "Length dependence of cle"), +IOP( "lalpha0", BSIM3V2_MOD_LALPHA0, IF_REAL, "Length dependence of alpha0"), +IOP( "lalpha1", BSIM3V2_MOD_LALPHA1, IF_REAL, "Length dependence of alpha1"), +IOP( "lbeta0", BSIM3V2_MOD_LBETA0, IF_REAL, "Length dependence of beta0"), +IOP( "lvfbcv", BSIM3V2_MOD_LVFBCV, IF_REAL, "Length dependence of vfbcv"), +IOP( "lvfb", BSIM3V2_MOD_LVFB, IF_REAL, "Length dependence of vfb"), +IOP( "lacde", BSIM3V2_MOD_LACDE, IF_REAL, "Length dependence of acde"), +IOP( "lmoin", BSIM3V2_MOD_LMOIN, IF_REAL, "Length dependence of moin"), +IOP( "lnoff", BSIM3V2_MOD_LNOFF, IF_REAL, "Length dependence of noff"), +IOP( "lvoffcv", BSIM3V2_MOD_LVOFFCV, IF_REAL, "Length dependence of voffcv"), +IOP( "wcdsc", BSIM3V2_MOD_WCDSC, IF_REAL, "Width dependence of cdsc"), +IOP( "wcdscb", BSIM3V2_MOD_WCDSCB, IF_REAL, "Width dependence of cdscb"), +IOP( "wcdscd", BSIM3V2_MOD_WCDSCD, IF_REAL, "Width dependence of cdscd"), +IOP( "wcit", BSIM3V2_MOD_WCIT, IF_REAL, "Width dependence of cit"), +IOP( "wnfactor", BSIM3V2_MOD_WNFACTOR, IF_REAL, "Width dependence of nfactor"), +IOP( "wxj", BSIM3V2_MOD_WXJ, IF_REAL, "Width dependence of xj"), +IOP( "wvsat", BSIM3V2_MOD_WVSAT, IF_REAL, "Width dependence of vsat"), +IOP( "wat", BSIM3V2_MOD_WAT, IF_REAL, "Width dependence of at"), +IOP( "wa0", BSIM3V2_MOD_WA0, IF_REAL, "Width dependence of a0"), +IOP( "wags", BSIM3V2_MOD_WAGS, IF_REAL, "Width dependence of ags"), +IOP( "wa1", BSIM3V2_MOD_WA1, IF_REAL, "Width dependence of a1"), +IOP( "wa2", BSIM3V2_MOD_WA2, IF_REAL, "Width dependence of a2"), +IOP( "wketa", BSIM3V2_MOD_WKETA, IF_REAL, "Width dependence of keta"), +IOP( "wnsub", BSIM3V2_MOD_WNSUB, IF_REAL, "Width dependence of nsub"), +IOP( "wnch", BSIM3V2_MOD_WNPEAK, IF_REAL, "Width dependence of nch"), +IOP( "wngate", BSIM3V2_MOD_WNGATE, IF_REAL, "Width dependence of ngate"), +IOP( "wgamma1", BSIM3V2_MOD_WGAMMA1, IF_REAL, "Width dependence of gamma1"), +IOP( "wgamma2", BSIM3V2_MOD_WGAMMA2, IF_REAL, "Width dependence of gamma2"), +IOP( "wvbx", BSIM3V2_MOD_WVBX, IF_REAL, "Width dependence of vbx"), +IOP( "wvbm", BSIM3V2_MOD_WVBM, IF_REAL, "Width dependence of vbm"), +IOP( "wxt", BSIM3V2_MOD_WXT, IF_REAL, "Width dependence of xt"), +IOP( "wk1", BSIM3V2_MOD_WK1, IF_REAL, "Width dependence of k1"), +IOP( "wkt1", BSIM3V2_MOD_WKT1, IF_REAL, "Width dependence of kt1"), +IOP( "wkt1l", BSIM3V2_MOD_WKT1L, IF_REAL, "Width dependence of kt1l"), +IOP( "wkt2", BSIM3V2_MOD_WKT2, IF_REAL, "Width dependence of kt2"), +IOP( "wk2", BSIM3V2_MOD_WK2, IF_REAL, "Width dependence of k2"), +IOP( "wk3", BSIM3V2_MOD_WK3, IF_REAL, "Width dependence of k3"), +IOP( "wk3b", BSIM3V2_MOD_WK3B, IF_REAL, "Width dependence of k3b"), +IOP( "ww0", BSIM3V2_MOD_WW0, IF_REAL, "Width dependence of w0"), +IOP( "wnlx", BSIM3V2_MOD_WNLX, IF_REAL, "Width dependence of nlx"), +IOP( "wdvt0", BSIM3V2_MOD_WDVT0, IF_REAL, "Width dependence of dvt0"), +IOP( "wdvt1", BSIM3V2_MOD_WDVT1, IF_REAL, "Width dependence of dvt1"), +IOP( "wdvt2", BSIM3V2_MOD_WDVT2, IF_REAL, "Width dependence of dvt2"), +IOP( "wdvt0w", BSIM3V2_MOD_WDVT0W, IF_REAL, "Width dependence of dvt0w"), +IOP( "wdvt1w", BSIM3V2_MOD_WDVT1W, IF_REAL, "Width dependence of dvt1w"), +IOP( "wdvt2w", BSIM3V2_MOD_WDVT2W, IF_REAL, "Width dependence of dvt2w"), +IOP( "wdrout", BSIM3V2_MOD_WDROUT, IF_REAL, "Width dependence of drout"), +IOP( "wdsub", BSIM3V2_MOD_WDSUB, IF_REAL, "Width dependence of dsub"), +IOP( "wvth0", BSIM3V2_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wvtho", BSIM3V2_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wua", BSIM3V2_MOD_WUA, IF_REAL, "Width dependence of ua"), +IOP( "wua1", BSIM3V2_MOD_WUA1, IF_REAL, "Width dependence of ua1"), +IOP( "wub", BSIM3V2_MOD_WUB, IF_REAL, "Width dependence of ub"), +IOP( "wub1", BSIM3V2_MOD_WUB1, IF_REAL, "Width dependence of ub1"), +IOP( "wuc", BSIM3V2_MOD_WUC, IF_REAL, "Width dependence of uc"), +IOP( "wuc1", BSIM3V2_MOD_WUC1, IF_REAL, "Width dependence of uc1"), +IOP( "wu0", BSIM3V2_MOD_WU0, IF_REAL, "Width dependence of u0"), +IOP( "wute", BSIM3V2_MOD_WUTE, IF_REAL, "Width dependence of ute"), +IOP( "wvoff", BSIM3V2_MOD_WVOFF, IF_REAL, "Width dependence of voff"), +IOP( "welm", BSIM3V2_MOD_WELM, IF_REAL, "Width dependence of elm"), +IOP( "wdelta", BSIM3V2_MOD_WDELTA, IF_REAL, "Width dependence of delta"), +IOP( "wrdsw", BSIM3V2_MOD_WRDSW, IF_REAL, "Width dependence of rdsw "), + +IOP( "wprwg", BSIM3V2_MOD_WPRWG, IF_REAL, "Width dependence of prwg "), +IOP( "wprwb", BSIM3V2_MOD_WPRWB, IF_REAL, "Width dependence of prwb "), + +IOP( "wprt", BSIM3V2_MOD_WPRT, IF_REAL, "Width dependence of prt"), +IOP( "weta0", BSIM3V2_MOD_WETA0, IF_REAL, "Width dependence of eta0"), +IOP( "wetab", BSIM3V2_MOD_WETAB, IF_REAL, "Width dependence of etab"), +IOP( "wpclm", BSIM3V2_MOD_WPCLM, IF_REAL, "Width dependence of pclm"), +IOP( "wpdiblc1", BSIM3V2_MOD_WPDIBL1, IF_REAL, "Width dependence of pdiblc1"), +IOP( "wpdiblc2", BSIM3V2_MOD_WPDIBL2, IF_REAL, "Width dependence of pdiblc2"), +IOP( "wpdiblcb", BSIM3V2_MOD_WPDIBLB, IF_REAL, "Width dependence of pdiblcb"), +IOP( "wpscbe1", BSIM3V2_MOD_WPSCBE1, IF_REAL, "Width dependence of pscbe1"), +IOP( "wpscbe2", BSIM3V2_MOD_WPSCBE2, IF_REAL, "Width dependence of pscbe2"), +IOP( "wpvag", BSIM3V2_MOD_WPVAG, IF_REAL, "Width dependence of pvag"), +IOP( "wwr", BSIM3V2_MOD_WWR, IF_REAL, "Width dependence of wr"), +IOP( "wdwg", BSIM3V2_MOD_WDWG, IF_REAL, "Width dependence of dwg"), +IOP( "wdwb", BSIM3V2_MOD_WDWB, IF_REAL, "Width dependence of dwb"), +IOP( "wb0", BSIM3V2_MOD_WB0, IF_REAL, "Width dependence of b0"), +IOP( "wb1", BSIM3V2_MOD_WB1, IF_REAL, "Width dependence of b1"), +IOP( "wcgsl", BSIM3V2_MOD_WCGSL, IF_REAL, "Width dependence of cgsl"), +IOP( "wcgdl", BSIM3V2_MOD_WCGDL, IF_REAL, "Width dependence of cgdl"), +IOP( "wckappa", BSIM3V2_MOD_WCKAPPA, IF_REAL, "Width dependence of ckappa"), +IOP( "wcf", BSIM3V2_MOD_WCF, IF_REAL, "Width dependence of cf"), +IOP( "wclc", BSIM3V2_MOD_WCLC, IF_REAL, "Width dependence of clc"), +IOP( "wcle", BSIM3V2_MOD_WCLE, IF_REAL, "Width dependence of cle"), +IOP( "walpha0", BSIM3V2_MOD_WALPHA0, IF_REAL, "Width dependence of alpha0"), +IOP( "walpha1", BSIM3V2_MOD_WALPHA1, IF_REAL, "Width dependence of alpha1"), +IOP( "wbeta0", BSIM3V2_MOD_WBETA0, IF_REAL, "Width dependence of beta0"), +IOP( "wvfbcv", BSIM3V2_MOD_WVFBCV, IF_REAL, "Width dependence of vfbcv"), +IOP( "wvfb", BSIM3V2_MOD_WVFB, IF_REAL, "Width dependence of vfb"), +IOP( "wacde", BSIM3V2_MOD_WACDE, IF_REAL, "Width dependence of acde"), +IOP( "wmoin", BSIM3V2_MOD_WMOIN, IF_REAL, "Width dependence of moin"), +IOP( "wnoff", BSIM3V2_MOD_WNOFF, IF_REAL, "Width dependence of noff"), +IOP( "wvoffcv", BSIM3V2_MOD_WVOFFCV, IF_REAL, "Width dependence of voffcv"), + +IOP( "pcdsc", BSIM3V2_MOD_PCDSC, IF_REAL, "Cross-term dependence of cdsc"), +IOP( "pcdscb", BSIM3V2_MOD_PCDSCB, IF_REAL, "Cross-term dependence of cdscb"), +IOP( "pcdscd", BSIM3V2_MOD_PCDSCD, IF_REAL, "Cross-term dependence of cdscd"), +IOP( "pcit", BSIM3V2_MOD_PCIT, IF_REAL, "Cross-term dependence of cit"), +IOP( "pnfactor", BSIM3V2_MOD_PNFACTOR, IF_REAL, "Cross-term dependence of nfactor"), +IOP( "pxj", BSIM3V2_MOD_PXJ, IF_REAL, "Cross-term dependence of xj"), +IOP( "pvsat", BSIM3V2_MOD_PVSAT, IF_REAL, "Cross-term dependence of vsat"), +IOP( "pat", BSIM3V2_MOD_PAT, IF_REAL, "Cross-term dependence of at"), +IOP( "pa0", BSIM3V2_MOD_PA0, IF_REAL, "Cross-term dependence of a0"), +IOP( "pags", BSIM3V2_MOD_PAGS, IF_REAL, "Cross-term dependence of ags"), +IOP( "pa1", BSIM3V2_MOD_PA1, IF_REAL, "Cross-term dependence of a1"), +IOP( "pa2", BSIM3V2_MOD_PA2, IF_REAL, "Cross-term dependence of a2"), +IOP( "pketa", BSIM3V2_MOD_PKETA, IF_REAL, "Cross-term dependence of keta"), +IOP( "pnsub", BSIM3V2_MOD_PNSUB, IF_REAL, "Cross-term dependence of nsub"), +IOP( "pnch", BSIM3V2_MOD_PNPEAK, IF_REAL, "Cross-term dependence of nch"), +IOP( "pngate", BSIM3V2_MOD_PNGATE, IF_REAL, "Cross-term dependence of ngate"), +IOP( "pgamma1", BSIM3V2_MOD_PGAMMA1, IF_REAL, "Cross-term dependence of gamma1"), +IOP( "pgamma2", BSIM3V2_MOD_PGAMMA2, IF_REAL, "Cross-term dependence of gamma2"), +IOP( "pvbx", BSIM3V2_MOD_PVBX, IF_REAL, "Cross-term dependence of vbx"), +IOP( "pvbm", BSIM3V2_MOD_PVBM, IF_REAL, "Cross-term dependence of vbm"), +IOP( "pxt", BSIM3V2_MOD_PXT, IF_REAL, "Cross-term dependence of xt"), +IOP( "pk1", BSIM3V2_MOD_PK1, IF_REAL, "Cross-term dependence of k1"), +IOP( "pkt1", BSIM3V2_MOD_PKT1, IF_REAL, "Cross-term dependence of kt1"), +IOP( "pkt1l", BSIM3V2_MOD_PKT1L, IF_REAL, "Cross-term dependence of kt1l"), +IOP( "pkt2", BSIM3V2_MOD_PKT2, IF_REAL, "Cross-term dependence of kt2"), +IOP( "pk2", BSIM3V2_MOD_PK2, IF_REAL, "Cross-term dependence of k2"), +IOP( "pk3", BSIM3V2_MOD_PK3, IF_REAL, "Cross-term dependence of k3"), +IOP( "pk3b", BSIM3V2_MOD_PK3B, IF_REAL, "Cross-term dependence of k3b"), +IOP( "pw0", BSIM3V2_MOD_PW0, IF_REAL, "Cross-term dependence of w0"), +IOP( "pnlx", BSIM3V2_MOD_PNLX, IF_REAL, "Cross-term dependence of nlx"), +IOP( "pdvt0", BSIM3V2_MOD_PDVT0, IF_REAL, "Cross-term dependence of dvt0"), +IOP( "pdvt1", BSIM3V2_MOD_PDVT1, IF_REAL, "Cross-term dependence of dvt1"), +IOP( "pdvt2", BSIM3V2_MOD_PDVT2, IF_REAL, "Cross-term dependence of dvt2"), +IOP( "pdvt0w", BSIM3V2_MOD_PDVT0W, IF_REAL, "Cross-term dependence of dvt0w"), +IOP( "pdvt1w", BSIM3V2_MOD_PDVT1W, IF_REAL, "Cross-term dependence of dvt1w"), +IOP( "pdvt2w", BSIM3V2_MOD_PDVT2W, IF_REAL, "Cross-term dependence of dvt2w"), +IOP( "pdrout", BSIM3V2_MOD_PDROUT, IF_REAL, "Cross-term dependence of drout"), +IOP( "pdsub", BSIM3V2_MOD_PDSUB, IF_REAL, "Cross-term dependence of dsub"), +IOP( "pvth0", BSIM3V2_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pvtho", BSIM3V2_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pua", BSIM3V2_MOD_PUA, IF_REAL, "Cross-term dependence of ua"), +IOP( "pua1", BSIM3V2_MOD_PUA1, IF_REAL, "Cross-term dependence of ua1"), +IOP( "pub", BSIM3V2_MOD_PUB, IF_REAL, "Cross-term dependence of ub"), +IOP( "pub1", BSIM3V2_MOD_PUB1, IF_REAL, "Cross-term dependence of ub1"), +IOP( "puc", BSIM3V2_MOD_PUC, IF_REAL, "Cross-term dependence of uc"), +IOP( "puc1", BSIM3V2_MOD_PUC1, IF_REAL, "Cross-term dependence of uc1"), +IOP( "pu0", BSIM3V2_MOD_PU0, IF_REAL, "Cross-term dependence of u0"), +IOP( "pute", BSIM3V2_MOD_PUTE, IF_REAL, "Cross-term dependence of ute"), +IOP( "pvoff", BSIM3V2_MOD_PVOFF, IF_REAL, "Cross-term dependence of voff"), +IOP( "pelm", BSIM3V2_MOD_PELM, IF_REAL, "Cross-term dependence of elm"), +IOP( "pdelta", BSIM3V2_MOD_PDELTA, IF_REAL, "Cross-term dependence of delta"), +IOP( "prdsw", BSIM3V2_MOD_PRDSW, IF_REAL, "Cross-term dependence of rdsw "), + +IOP( "pprwg", BSIM3V2_MOD_PPRWG, IF_REAL, "Cross-term dependence of prwg "), +IOP( "pprwb", BSIM3V2_MOD_PPRWB, IF_REAL, "Cross-term dependence of prwb "), + +IOP( "pprt", BSIM3V2_MOD_PPRT, IF_REAL, "Cross-term dependence of prt "), +IOP( "peta0", BSIM3V2_MOD_PETA0, IF_REAL, "Cross-term dependence of eta0"), +IOP( "petab", BSIM3V2_MOD_PETAB, IF_REAL, "Cross-term dependence of etab"), +IOP( "ppclm", BSIM3V2_MOD_PPCLM, IF_REAL, "Cross-term dependence of pclm"), +IOP( "ppdiblc1", BSIM3V2_MOD_PPDIBL1, IF_REAL, "Cross-term dependence of pdiblc1"), +IOP( "ppdiblc2", BSIM3V2_MOD_PPDIBL2, IF_REAL, "Cross-term dependence of pdiblc2"), +IOP( "ppdiblcb", BSIM3V2_MOD_PPDIBLB, IF_REAL, "Cross-term dependence of pdiblcb"), +IOP( "ppscbe1", BSIM3V2_MOD_PPSCBE1, IF_REAL, "Cross-term dependence of pscbe1"), +IOP( "ppscbe2", BSIM3V2_MOD_PPSCBE2, IF_REAL, "Cross-term dependence of pscbe2"), +IOP( "ppvag", BSIM3V2_MOD_PPVAG, IF_REAL, "Cross-term dependence of pvag"), +IOP( "pwr", BSIM3V2_MOD_PWR, IF_REAL, "Cross-term dependence of wr"), +IOP( "pdwg", BSIM3V2_MOD_PDWG, IF_REAL, "Cross-term dependence of dwg"), +IOP( "pdwb", BSIM3V2_MOD_PDWB, IF_REAL, "Cross-term dependence of dwb"), +IOP( "pb0", BSIM3V2_MOD_PB0, IF_REAL, "Cross-term dependence of b0"), +IOP( "pb1", BSIM3V2_MOD_PB1, IF_REAL, "Cross-term dependence of b1"), +IOP( "pcgsl", BSIM3V2_MOD_PCGSL, IF_REAL, "Cross-term dependence of cgsl"), +IOP( "pcgdl", BSIM3V2_MOD_PCGDL, IF_REAL, "Cross-term dependence of cgdl"), +IOP( "pckappa", BSIM3V2_MOD_PCKAPPA, IF_REAL, "Cross-term dependence of ckappa"), +IOP( "pcf", BSIM3V2_MOD_PCF, IF_REAL, "Cross-term dependence of cf"), +IOP( "pclc", BSIM3V2_MOD_PCLC, IF_REAL, "Cross-term dependence of clc"), +IOP( "pcle", BSIM3V2_MOD_PCLE, IF_REAL, "Cross-term dependence of cle"), +IOP( "palpha0", BSIM3V2_MOD_PALPHA0, IF_REAL, "Cross-term dependence of alpha0"), +IOP( "palpha1", BSIM3V2_MOD_PALPHA1, IF_REAL, "Cross-term dependence of alpha1"), +IOP( "pbeta0", BSIM3V2_MOD_PBETA0, IF_REAL, "Cross-term dependence of beta0"), +IOP( "pvfbcv", BSIM3V2_MOD_PVFBCV, IF_REAL, "Cross-term dependence of vfbcv"), +IOP( "pvfb", BSIM3V2_MOD_PVFB, IF_REAL, "Cross-term dependence of vfb"), +IOP( "pacde", BSIM3V2_MOD_PACDE, IF_REAL, "Cross-term dependence of acde"), +IOP( "pmoin", BSIM3V2_MOD_PMOIN, IF_REAL, "Cross-term dependence of moin"), +IOP( "pnoff", BSIM3V2_MOD_PNOFF, IF_REAL, "Cross-term dependence of noff"), +IOP( "pvoffcv", BSIM3V2_MOD_PVOFFCV, IF_REAL, "Cross-term dependence of voffcv"), + +IOP( "noia", BSIM3V2_MOD_NOIA, IF_REAL, "Flicker noise parameter"), +IOP( "noib", BSIM3V2_MOD_NOIB, IF_REAL, "Flicker noise parameter"), +IOP( "noic", BSIM3V2_MOD_NOIC, IF_REAL, "Flicker noise parameter"), +IOP( "em", BSIM3V2_MOD_EM, IF_REAL, "Flicker noise parameter"), +IOP( "ef", BSIM3V2_MOD_EF, IF_REAL, "Flicker noise frequency exponent"), +IOP( "af", BSIM3V2_MOD_AF, IF_REAL, "Flicker noise exponent"), +IOP( "kf", BSIM3V2_MOD_KF, IF_REAL, "Flicker noise coefficient"), + +IP( "nmos", BSIM3V2_MOD_NMOS, IF_FLAG, "Flag to indicate NMOS"), +IP( "pmos", BSIM3V2_MOD_PMOS, IF_FLAG, "Flag to indicate PMOS"), +}; + +char *BSIM3V2names[] = { + "Drain", + "Gate", + "Source", + "Bulk", + "Charge" +}; + +int BSIM3V2nSize = NUMELEMS(BSIM3V2names); +int BSIM3V2pTSize = NUMELEMS(BSIM3V2pTable); +int BSIM3V2mPTSize = NUMELEMS(BSIM3V2mPTable); +int BSIM3V2iSize = sizeof(BSIM3V2instance); +int BSIM3V2mSize = sizeof(BSIM3V2model); + + + diff --git a/src/spicelib/devices/bsim3v2/b3v2acld.c b/src/spicelib/devices/bsim3v2/b3v2acld.c new file mode 100644 index 000000000..b47860030 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2acld.c @@ -0,0 +1,351 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: b3acld.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V2acLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3V2model *model = (BSIM3V2model*)inModel; +register BSIM3V2instance *here; +double xcggb, xcgdb, xcgsb, xcbgb, xcbdb, xcbsb, xcddb, xcssb, xcdgb; +double gdpr, gspr, gds, gbd, gbs, capbd, capbs, xcsgb, xcdsb, xcsdb; +double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb, omega; +double GSoverlapCap, GDoverlapCap, GBoverlapCap, FwdSum, RevSum, Gm, Gmbs; +double dxpart, sxpart, xgtg, xgtd, xgts, xgtb, xcqgb, xcqdb, xcqsb, xcqbb; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb; +double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; +double T1, CoxWL, qcheq, Cdg, Cdd, Cds, Cdb, Csg, Csd, Css, Csb; + + omega = ckt->CKTomega; + for (; model != NULL; model = model->BSIM3V2nextModel) + { for (here = model->BSIM3V2instances; here!= NULL; + here = here->BSIM3V2nextInstance) + + { if (here->BSIM3V2owner != ARCHme) continue; + if (here->BSIM3V2mode >= 0) + { Gm = here->BSIM3V2gm; + Gmbs = here->BSIM3V2gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + + gbbdp = -here->BSIM3V2gbds; + gbbsp = here->BSIM3V2gbds + here->BSIM3V2gbgs + here->BSIM3V2gbbs; + + gbdpg = here->BSIM3V2gbgs; + gbdpb = here->BSIM3V2gbbs; + gbdpdp = here->BSIM3V2gbds; + gbdpsp = -(gbdpg + gbdpb + gbdpdp); + + gbspdp = 0.0; + gbspg = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + if (here->BSIM3V2nqsMod == 0) + { cggb = here->BSIM3V2cggb; + cgsb = here->BSIM3V2cgsb; + cgdb = here->BSIM3V2cgdb; + + cbgb = here->BSIM3V2cbgb; + cbsb = here->BSIM3V2cbsb; + cbdb = here->BSIM3V2cbdb; + + cdgb = here->BSIM3V2cdgb; + cdsb = here->BSIM3V2cdsb; + cddb = here->BSIM3V2cddb; + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3V2gtg; + xgtd = here->BSIM3V2gtd; + xgts = here->BSIM3V2gts; + xgtb = here->BSIM3V2gtb; + + xcqgb = here->BSIM3V2cqgb * omega; + xcqdb = here->BSIM3V2cqdb * omega; + xcqsb = here->BSIM3V2cqsb * omega; + xcqbb = here->BSIM3V2cqbb * omega; + + CoxWL = model->BSIM3V2cox * here->pParam->BSIM3V2weffCV + * here->pParam->BSIM3V2leffCV; + qcheq = -(here->BSIM3V2qgate + here->BSIM3V2qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3V2xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM3V2xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = here->BSIM3V2qdrn / qcheq; + Cdd = here->BSIM3V2cddb; + Csd = -(here->BSIM3V2cgdb + here->BSIM3V2cddb + + here->BSIM3V2cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM3V2cdgb; + Csg = -(here->BSIM3V2cggb + here->BSIM3V2cdgb + + here->BSIM3V2cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM3V2cdsb; + Css = -(here->BSIM3V2cgsb + here->BSIM3V2cdsb + + here->BSIM3V2cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + } + else + { Gm = -here->BSIM3V2gm; + Gmbs = -here->BSIM3V2gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + + gbbsp = -here->BSIM3V2gbds; + gbbdp = here->BSIM3V2gbds + here->BSIM3V2gbgs + here->BSIM3V2gbbs; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM3V2gbgs; + gbspsp = here->BSIM3V2gbds; + gbspb = here->BSIM3V2gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + + if (here->BSIM3V2nqsMod == 0) + { cggb = here->BSIM3V2cggb; + cgsb = here->BSIM3V2cgdb; + cgdb = here->BSIM3V2cgsb; + + cbgb = here->BSIM3V2cbgb; + cbsb = here->BSIM3V2cbdb; + cbdb = here->BSIM3V2cbsb; + + cdgb = -(here->BSIM3V2cdgb + cggb + cbgb); + cdsb = -(here->BSIM3V2cddb + cgsb + cbsb); + cddb = -(here->BSIM3V2cdsb + cgdb + cbdb); + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3V2gtg; + xgtd = here->BSIM3V2gts; + xgts = here->BSIM3V2gtd; + xgtb = here->BSIM3V2gtb; + + xcqgb = here->BSIM3V2cqgb * omega; + xcqdb = here->BSIM3V2cqsb * omega; + xcqsb = here->BSIM3V2cqdb * omega; + xcqbb = here->BSIM3V2cqbb * omega; + + CoxWL = model->BSIM3V2cox * here->pParam->BSIM3V2weffCV + * here->pParam->BSIM3V2leffCV; + qcheq = -(here->BSIM3V2qgate + here->BSIM3V2qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3V2xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM3V2xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = here->BSIM3V2qdrn / qcheq; + Css = here->BSIM3V2cddb; + Cds = -(here->BSIM3V2cgdb + here->BSIM3V2cddb + + here->BSIM3V2cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM3V2cdgb; + Cdg = -(here->BSIM3V2cggb + here->BSIM3V2cdgb + + here->BSIM3V2cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM3V2cdsb; + Cdd = -(here->BSIM3V2cgsb + here->BSIM3V2cdsb + + here->BSIM3V2cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + } + + T1 = *(ckt->CKTstate0 + here->BSIM3V2qdef) * here->BSIM3V2gtau; + gdpr = here->BSIM3V2drainConductance; + gspr = here->BSIM3V2sourceConductance; + gds = here->BSIM3V2gds; + gbd = here->BSIM3V2gbd; + gbs = here->BSIM3V2gbs; + capbd = here->BSIM3V2capbd; + capbs = here->BSIM3V2capbs; + + GSoverlapCap = here->BSIM3V2cgso; + GDoverlapCap = here->BSIM3V2cgdo; + GBoverlapCap = here->pParam->BSIM3V2cgbo; + + xcdgb = (cdgb - GDoverlapCap) * omega; + xcddb = (cddb + capbd + GDoverlapCap) * omega; + xcdsb = cdsb * omega; + xcsgb = -(cggb + cbgb + cdgb + GSoverlapCap) * omega; + xcsdb = -(cgdb + cbdb + cddb) * omega; + xcssb = (capbs + GSoverlapCap - (cgsb + cbsb + cdsb)) * omega; + xcggb = (cggb + GDoverlapCap + GSoverlapCap + GBoverlapCap) + * omega; + xcgdb = (cgdb - GDoverlapCap ) * omega; + xcgsb = (cgsb - GSoverlapCap) * omega; + xcbgb = (cbgb - GBoverlapCap) * omega; + xcbdb = (cbdb - capbd ) * omega; + xcbsb = (cbsb - capbs ) * omega; + + *(here->BSIM3V2GgPtr +1) += xcggb; + *(here->BSIM3V2BbPtr +1) -= xcbgb + xcbdb + xcbsb; + *(here->BSIM3V2DPdpPtr +1) += xcddb; + *(here->BSIM3V2SPspPtr +1) += xcssb; + *(here->BSIM3V2GbPtr +1) -= xcggb + xcgdb + xcgsb; + *(here->BSIM3V2GdpPtr +1) += xcgdb; + *(here->BSIM3V2GspPtr +1) += xcgsb; + *(here->BSIM3V2BgPtr +1) += xcbgb; + *(here->BSIM3V2BdpPtr +1) += xcbdb; + *(here->BSIM3V2BspPtr +1) += xcbsb; + *(here->BSIM3V2DPgPtr +1) += xcdgb; + *(here->BSIM3V2DPbPtr +1) -= xcdgb + xcddb + xcdsb; + *(here->BSIM3V2DPspPtr +1) += xcdsb; + *(here->BSIM3V2SPgPtr +1) += xcsgb; + *(here->BSIM3V2SPbPtr +1) -= xcsgb + xcsdb + xcssb; + *(here->BSIM3V2SPdpPtr +1) += xcsdb; + + *(here->BSIM3V2DdPtr) += gdpr; + *(here->BSIM3V2SsPtr) += gspr; + *(here->BSIM3V2BbPtr) += gbd + gbs - here->BSIM3V2gbbs; + *(here->BSIM3V2DPdpPtr) += gdpr + gds + gbd + RevSum + + dxpart * xgtd + T1 * ddxpart_dVd + gbdpdp; + *(here->BSIM3V2SPspPtr) += gspr + gds + gbs + FwdSum + + sxpart * xgts + T1 * dsxpart_dVs + gbspsp; + + *(here->BSIM3V2DdpPtr) -= gdpr; + *(here->BSIM3V2SspPtr) -= gspr; + + *(here->BSIM3V2BgPtr) -= here->BSIM3V2gbgs; + *(here->BSIM3V2BdpPtr) -= gbd - gbbdp; + *(here->BSIM3V2BspPtr) -= gbs - gbbsp; + + *(here->BSIM3V2DPdPtr) -= gdpr; + *(here->BSIM3V2DPgPtr) += Gm + dxpart * xgtg + T1 * ddxpart_dVg + + gbdpg; + *(here->BSIM3V2DPbPtr) -= gbd - Gmbs - dxpart * xgtb + - T1 * ddxpart_dVb - gbdpb; + *(here->BSIM3V2DPspPtr) -= gds + FwdSum - dxpart * xgts + - T1 * ddxpart_dVs - gbdpsp; + + *(here->BSIM3V2SPgPtr) -= Gm - sxpart * xgtg - T1 * dsxpart_dVg + - gbspg; + *(here->BSIM3V2SPsPtr) -= gspr; + *(here->BSIM3V2SPbPtr) -= gbs + Gmbs - sxpart * xgtb + - T1 * dsxpart_dVb - gbspb; + *(here->BSIM3V2SPdpPtr) -= gds + RevSum - sxpart * xgtd + - T1 * dsxpart_dVd - gbspdp; + + *(here->BSIM3V2GgPtr) -= xgtg; + *(here->BSIM3V2GbPtr) -= xgtb; + *(here->BSIM3V2GdpPtr) -= xgtd; + *(here->BSIM3V2GspPtr) -= xgts; + + if (here->BSIM3V2nqsMod) + { *(here->BSIM3V2QqPtr +1) += omega; + *(here->BSIM3V2QgPtr +1) -= xcqgb; + *(here->BSIM3V2QdpPtr +1) -= xcqdb; + *(here->BSIM3V2QspPtr +1) -= xcqsb; + *(here->BSIM3V2QbPtr +1) -= xcqbb; + + *(here->BSIM3V2QqPtr) += here->BSIM3V2gtau; + + *(here->BSIM3V2DPqPtr) += dxpart * here->BSIM3V2gtau; + *(here->BSIM3V2SPqPtr) += sxpart * here->BSIM3V2gtau; + *(here->BSIM3V2GqPtr) -= here->BSIM3V2gtau; + + *(here->BSIM3V2QgPtr) += xgtg; + *(here->BSIM3V2QdpPtr) += xgtd; + *(here->BSIM3V2QspPtr) += xgts; + *(here->BSIM3V2QbPtr) += xgtb; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3v2/b3v2ask.c b/src/spicelib/devices/bsim3v2/b3v2ask.c new file mode 100644 index 000000000..cc1325dfd --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2ask.c @@ -0,0 +1,209 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2ask.c +**********/ + +#include "ngspice.h" +#include +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim3v2def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V2ask(ckt,inst,which,value,select) +CKTcircuit *ckt; +GENinstance *inst; +int which; +IFvalue *value; +IFvalue *select; +{ +BSIM3V2instance *here = (BSIM3V2instance*)inst; + + switch(which) + { case BSIM3V2_L: + value->rValue = here->BSIM3V2l; + return(OK); + case BSIM3V2_W: + value->rValue = here->BSIM3V2w; + return(OK); + case BSIM3V2_AS: + value->rValue = here->BSIM3V2sourceArea; + return(OK); + case BSIM3V2_AD: + value->rValue = here->BSIM3V2drainArea; + return(OK); + case BSIM3V2_PS: + value->rValue = here->BSIM3V2sourcePerimeter; + return(OK); + case BSIM3V2_PD: + value->rValue = here->BSIM3V2drainPerimeter; + return(OK); + case BSIM3V2_NRS: + value->rValue = here->BSIM3V2sourceSquares; + return(OK); + case BSIM3V2_NRD: + value->rValue = here->BSIM3V2drainSquares; + return(OK); + case BSIM3V2_OFF: + value->rValue = here->BSIM3V2off; + return(OK); + case BSIM3V2_NQSMOD: + value->iValue = here->BSIM3V2nqsMod; + return(OK); + case BSIM3V2_IC_VBS: + value->rValue = here->BSIM3V2icVBS; + return(OK); + case BSIM3V2_IC_VDS: + value->rValue = here->BSIM3V2icVDS; + return(OK); + case BSIM3V2_IC_VGS: + value->rValue = here->BSIM3V2icVGS; + return(OK); + case BSIM3V2_DNODE: + value->iValue = here->BSIM3V2dNode; + return(OK); + case BSIM3V2_GNODE: + value->iValue = here->BSIM3V2gNode; + return(OK); + case BSIM3V2_SNODE: + value->iValue = here->BSIM3V2sNode; + return(OK); + case BSIM3V2_BNODE: + value->iValue = here->BSIM3V2bNode; + return(OK); + case BSIM3V2_DNODEPRIME: + value->iValue = here->BSIM3V2dNodePrime; + return(OK); + case BSIM3V2_SNODEPRIME: + value->iValue = here->BSIM3V2sNodePrime; + return(OK); + case BSIM3V2_SOURCECONDUCT: + value->rValue = here->BSIM3V2sourceConductance; + return(OK); + case BSIM3V2_DRAINCONDUCT: + value->rValue = here->BSIM3V2drainConductance; + return(OK); + case BSIM3V2_VBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2vbd); + return(OK); + case BSIM3V2_VBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2vbs); + return(OK); + case BSIM3V2_VGS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2vgs); + return(OK); + case BSIM3V2_VDS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2vds); + return(OK); + case BSIM3V2_CD: + value->rValue = here->BSIM3V2cd; + return(OK); + case BSIM3V2_CBS: + value->rValue = here->BSIM3V2cbs; + return(OK); + case BSIM3V2_CBD: + value->rValue = here->BSIM3V2cbd; + return(OK); + case BSIM3V2_GM: + value->rValue = here->BSIM3V2gm; + return(OK); + case BSIM3V2_GDS: + value->rValue = here->BSIM3V2gds; + return(OK); + case BSIM3V2_GMBS: + value->rValue = here->BSIM3V2gmbs; + return(OK); + case BSIM3V2_GBD: + value->rValue = here->BSIM3V2gbd; + return(OK); + case BSIM3V2_GBS: + value->rValue = here->BSIM3V2gbs; + return(OK); + case BSIM3V2_QB: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2qb); + return(OK); + case BSIM3V2_CQB: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2cqb); + return(OK); + case BSIM3V2_QG: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2qg); + return(OK); + case BSIM3V2_CQG: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2cqg); + return(OK); + case BSIM3V2_QD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2qd); + return(OK); + case BSIM3V2_CQD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2cqd); + return(OK); + case BSIM3V2_CGG: + value->rValue = here->BSIM3V2cggb; + return(OK); + case BSIM3V2_CGD: + value->rValue = here->BSIM3V2cgdb; + return(OK); + case BSIM3V2_CGS: + value->rValue = here->BSIM3V2cgsb; + return(OK); + case BSIM3V2_CDG: + value->rValue = here->BSIM3V2cdgb; + return(OK); + case BSIM3V2_CDD: + value->rValue = here->BSIM3V2cddb; + return(OK); + case BSIM3V2_CDS: + value->rValue = here->BSIM3V2cdsb; + return(OK); + case BSIM3V2_CBG: + value->rValue = here->BSIM3V2cbgb; + return(OK); + case BSIM3V2_CBDB: + value->rValue = here->BSIM3V2cbdb; + return(OK); + case BSIM3V2_CBSB: + value->rValue = here->BSIM3V2cbsb; + return(OK); + case BSIM3V2_CAPBD: + value->rValue = here->BSIM3V2capbd; + return(OK); + case BSIM3V2_CAPBS: + value->rValue = here->BSIM3V2capbs; + return(OK); + case BSIM3V2_VON: + value->rValue = here->BSIM3V2von; + return(OK); + case BSIM3V2_VDSAT: + value->rValue = here->BSIM3V2vdsat; + return(OK); + case BSIM3V2_QBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2qbs); + return(OK); + case BSIM3V2_QBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM3V2qbd); + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bsim3v2/b3v2check.c b/src/spicelib/devices/bsim3v2/b3v2check.c new file mode 100644 index 000000000..2f270b7ea --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2check.c @@ -0,0 +1,442 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: Min-Chie Jeng. +Modified by Weidong Liu (1997-1998). +File: b3v2check.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +BSIM3V2checkModel(model, here, ckt) +register BSIM3V2model *model; +register BSIM3V2instance *here; +CKTcircuit *ckt; +{ +struct BSIM3V2SizeDependParam *pParam; +int Fatal_Flag = 0; +FILE *fplog; + + if ((fplog = fopen("b3v3check.log", "w")) != NULL) + { pParam = here->pParam; + fprintf(fplog, "BSIM3V3.2 Parameter Check\n"); + fprintf(fplog, "Model = %s\n", model->BSIM3V2modName); + fprintf(fplog, "W = %g, L = %g\n", here->BSIM3V2w, here->BSIM3V2l); + + + if (pParam->BSIM3V2nlx < -pParam->BSIM3V2leff) + { fprintf(fplog, "Fatal: Nlx = %g is less than -Leff.\n", + pParam->BSIM3V2nlx); + printf("Fatal: Nlx = %g is less than -Leff.\n", + pParam->BSIM3V2nlx); + Fatal_Flag = 1; + } + + if (model->BSIM3V2tox <= 0.0) + { fprintf(fplog, "Fatal: Tox = %g is not positive.\n", + model->BSIM3V2tox); + printf("Fatal: Tox = %g is not positive.\n", model->BSIM3V2tox); + Fatal_Flag = 1; + } + + if (model->BSIM3V2toxm <= 0.0) + { fprintf(fplog, "Fatal: Toxm = %g is not positive.\n", + model->BSIM3V2toxm); + printf("Fatal: Toxm = %g is not positive.\n", model->BSIM3V2toxm); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2npeak <= 0.0) + { fprintf(fplog, "Fatal: Nch = %g is not positive.\n", + pParam->BSIM3V2npeak); + printf("Fatal: Nch = %g is not positive.\n", + pParam->BSIM3V2npeak); + Fatal_Flag = 1; + } + if (pParam->BSIM3V2nsub <= 0.0) + { fprintf(fplog, "Fatal: Nsub = %g is not positive.\n", + pParam->BSIM3V2nsub); + printf("Fatal: Nsub = %g is not positive.\n", + pParam->BSIM3V2nsub); + Fatal_Flag = 1; + } + if (pParam->BSIM3V2ngate < 0.0) + { fprintf(fplog, "Fatal: Ngate = %g is not positive.\n", + pParam->BSIM3V2ngate); + printf("Fatal: Ngate = %g Ngate is not positive.\n", + pParam->BSIM3V2ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM3V2ngate > 1.e25) + { fprintf(fplog, "Fatal: Ngate = %g is too high.\n", + pParam->BSIM3V2ngate); + printf("Fatal: Ngate = %g Ngate is too high\n", + pParam->BSIM3V2ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM3V2xj <= 0.0) + { fprintf(fplog, "Fatal: Xj = %g is not positive.\n", + pParam->BSIM3V2xj); + printf("Fatal: Xj = %g is not positive.\n", pParam->BSIM3V2xj); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2dvt1 < 0.0) + { fprintf(fplog, "Fatal: Dvt1 = %g is negative.\n", + pParam->BSIM3V2dvt1); + printf("Fatal: Dvt1 = %g is negative.\n", pParam->BSIM3V2dvt1); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2dvt1w < 0.0) + { fprintf(fplog, "Fatal: Dvt1w = %g is negative.\n", + pParam->BSIM3V2dvt1w); + printf("Fatal: Dvt1w = %g is negative.\n", pParam->BSIM3V2dvt1w); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2w0 == -pParam->BSIM3V2weff) + { fprintf(fplog, "Fatal: (W0 + Weff) = 0 causing divided-by-zero.\n"); + printf("Fatal: (W0 + Weff) = 0 causing divided-by-zero.\n"); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2dsub < 0.0) + { fprintf(fplog, "Fatal: Dsub = %g is negative.\n", pParam->BSIM3V2dsub); + printf("Fatal: Dsub = %g is negative.\n", pParam->BSIM3V2dsub); + Fatal_Flag = 1; + } + if (pParam->BSIM3V2b1 == -pParam->BSIM3V2weff) + { fprintf(fplog, "Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + printf("Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + Fatal_Flag = 1; + } + if (pParam->BSIM3V2u0temp <= 0.0) + { fprintf(fplog, "Fatal: u0 at current temperature = %g is not positive.\n", pParam->BSIM3V2u0temp); + printf("Fatal: u0 at current temperature = %g is not positive.\n", + pParam->BSIM3V2u0temp); + Fatal_Flag = 1; + } + +/* Check delta parameter */ + if (pParam->BSIM3V2delta < 0.0) + { fprintf(fplog, "Fatal: Delta = %g is less than zero.\n", + pParam->BSIM3V2delta); + printf("Fatal: Delta = %g is less than zero.\n", pParam->BSIM3V2delta); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2vsattemp <= 0.0) + { fprintf(fplog, "Fatal: Vsat at current temperature = %g is not positive.\n", pParam->BSIM3V2vsattemp); + printf("Fatal: Vsat at current temperature = %g is not positive.\n", + pParam->BSIM3V2vsattemp); + Fatal_Flag = 1; + } +/* Check Rout parameters */ + if (pParam->BSIM3V2pclm <= 0.0) + { fprintf(fplog, "Fatal: Pclm = %g is not positive.\n", pParam->BSIM3V2pclm); + printf("Fatal: Pclm = %g is not positive.\n", pParam->BSIM3V2pclm); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2drout < 0.0) + { fprintf(fplog, "Fatal: Drout = %g is negative.\n", pParam->BSIM3V2drout); + printf("Fatal: Drout = %g is negative.\n", pParam->BSIM3V2drout); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2pscbe2 <= 0.0) + { fprintf(fplog, "Warning: Pscbe2 = %g is not positive.\n", + pParam->BSIM3V2pscbe2); + printf("Warning: Pscbe2 = %g is not positive.\n", pParam->BSIM3V2pscbe2); + } + + if (model->BSIM3V2unitLengthSidewallJctCap > 0.0 || + model->BSIM3V2unitLengthGateSidewallJctCap > 0.0) + { + if (here->BSIM3V2drainPerimeter < pParam->BSIM3V2weff) + { fprintf(fplog, "Warning: Pd = %g is less than W.\n", + here->BSIM3V2drainPerimeter); + printf("Warning: Pd = %g is less than W.\n", + here->BSIM3V2drainPerimeter); + } + if (here->BSIM3V2sourcePerimeter < pParam->BSIM3V2weff) + { fprintf(fplog, "Warning: Ps = %g is less than W.\n", + here->BSIM3V2sourcePerimeter); + printf("Warning: Ps = %g is less than W.\n", + here->BSIM3V2sourcePerimeter); + } + } + + if (pParam->BSIM3V2noff < 0.1) + { fprintf(fplog, "Warning: Noff = %g is too small.\n", + pParam->BSIM3V2noff); + printf("Warning: Noff = %g is too small.\n", pParam->BSIM3V2noff); + } + if (pParam->BSIM3V2noff > 4.0) + { fprintf(fplog, "Warning: Noff = %g is too large.\n", + pParam->BSIM3V2noff); + printf("Warning: Noff = %g is too large.\n", pParam->BSIM3V2noff); + } + + if (pParam->BSIM3V2voffcv < -0.5) + { fprintf(fplog, "Warning: Voffcv = %g is too small.\n", + pParam->BSIM3V2voffcv); + printf("Warning: Voffcv = %g is too small.\n", pParam->BSIM3V2voffcv); + } + if (pParam->BSIM3V2voffcv > 0.5) + { fprintf(fplog, "Warning: Voffcv = %g is too large.\n", + pParam->BSIM3V2voffcv); + printf("Warning: Voffcv = %g is too large.\n", pParam->BSIM3V2voffcv); + } + + if (model->BSIM3V2ijth < 0.0) + { fprintf(fplog, "Fatal: Ijth = %g cannot be negative.\n", + model->BSIM3V2ijth); + printf("Fatal: Ijth = %g cannot be negative.\n", model->BSIM3V2ijth); + Fatal_Flag = 1; + } + +/* Check capacitance parameters */ + if (pParam->BSIM3V2clc < 0.0) + { fprintf(fplog, "Fatal: Clc = %g is negative.\n", pParam->BSIM3V2clc); + printf("Fatal: Clc = %g is negative.\n", pParam->BSIM3V2clc); + Fatal_Flag = 1; + } + + if (pParam->BSIM3V2moin < 5.0) + { fprintf(fplog, "Warning: Moin = %g is too small.\n", + pParam->BSIM3V2moin); + printf("Warning: Moin = %g is too small.\n", pParam->BSIM3V2moin); + } + if (pParam->BSIM3V2moin > 25.0) + { fprintf(fplog, "Warning: Moin = %g is too large.\n", + pParam->BSIM3V2moin); + printf("Warning: Moin = %g is too large.\n", pParam->BSIM3V2moin); + } + + if (pParam->BSIM3V2acde < 0.4) + { fprintf(fplog, "Warning: Acde = %g is too small.\n", + pParam->BSIM3V2acde); + printf("Warning: Acde = %g is too small.\n", pParam->BSIM3V2acde); + } + if (pParam->BSIM3V2acde > 1.6) + { fprintf(fplog, "Warning: Acde = %g is too large.\n", + pParam->BSIM3V2acde); + printf("Warning: Acde = %g is too large.\n", pParam->BSIM3V2acde); + } + + if (model->BSIM3V2paramChk ==1) + { +/* Check L and W parameters */ + if (pParam->BSIM3V2leff <= 5.0e-8) + { fprintf(fplog, "Warning: Leff = %g may be too small.\n", + pParam->BSIM3V2leff); + printf("Warning: Leff = %g may be too small.\n", + pParam->BSIM3V2leff); + } + + if (pParam->BSIM3V2leffCV <= 5.0e-8) + { fprintf(fplog, "Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM3V2leffCV); + printf("Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM3V2leffCV); + } + + if (pParam->BSIM3V2weff <= 1.0e-7) + { fprintf(fplog, "Warning: Weff = %g may be too small.\n", + pParam->BSIM3V2weff); + printf("Warning: Weff = %g may be too small.\n", + pParam->BSIM3V2weff); + } + + if (pParam->BSIM3V2weffCV <= 1.0e-7) + { fprintf(fplog, "Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM3V2weffCV); + printf("Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM3V2weffCV); + } + +/* Check threshold voltage parameters */ + if (pParam->BSIM3V2nlx < 0.0) + { fprintf(fplog, "Warning: Nlx = %g is negative.\n", pParam->BSIM3V2nlx); + printf("Warning: Nlx = %g is negative.\n", pParam->BSIM3V2nlx); + } + if (model->BSIM3V2tox < 1.0e-9) + { fprintf(fplog, "Warning: Tox = %g is less than 10A.\n", + model->BSIM3V2tox); + printf("Warning: Tox = %g is less than 10A.\n", model->BSIM3V2tox); + } + + if (pParam->BSIM3V2npeak <= 1.0e15) + { fprintf(fplog, "Warning: Nch = %g may be too small.\n", + pParam->BSIM3V2npeak); + printf("Warning: Nch = %g may be too small.\n", + pParam->BSIM3V2npeak); + } + else if (pParam->BSIM3V2npeak >= 1.0e21) + { fprintf(fplog, "Warning: Nch = %g may be too large.\n", + pParam->BSIM3V2npeak); + printf("Warning: Nch = %g may be too large.\n", + pParam->BSIM3V2npeak); + } + + if (pParam->BSIM3V2nsub <= 1.0e14) + { fprintf(fplog, "Warning: Nsub = %g may be too small.\n", + pParam->BSIM3V2nsub); + printf("Warning: Nsub = %g may be too small.\n", + pParam->BSIM3V2nsub); + } + else if (pParam->BSIM3V2nsub >= 1.0e21) + { fprintf(fplog, "Warning: Nsub = %g may be too large.\n", + pParam->BSIM3V2nsub); + printf("Warning: Nsub = %g may be too large.\n", + pParam->BSIM3V2nsub); + } + + if ((pParam->BSIM3V2ngate > 0.0) && + (pParam->BSIM3V2ngate <= 1.e18)) + { fprintf(fplog, "Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM3V2ngate); + printf("Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM3V2ngate); + } + + if (pParam->BSIM3V2dvt0 < 0.0) + { fprintf(fplog, "Warning: Dvt0 = %g is negative.\n", + pParam->BSIM3V2dvt0); + printf("Warning: Dvt0 = %g is negative.\n", pParam->BSIM3V2dvt0); + } + + if (fabs(1.0e-6 / (pParam->BSIM3V2w0 + pParam->BSIM3V2weff)) > 10.0) + { fprintf(fplog, "Warning: (W0 + Weff) may be too small.\n"); + printf("Warning: (W0 + Weff) may be too small.\n"); + } + +/* Check subthreshold parameters */ + if (pParam->BSIM3V2nfactor < 0.0) + { fprintf(fplog, "Warning: Nfactor = %g is negative.\n", + pParam->BSIM3V2nfactor); + printf("Warning: Nfactor = %g is negative.\n", pParam->BSIM3V2nfactor); + } + if (pParam->BSIM3V2cdsc < 0.0) + { fprintf(fplog, "Warning: Cdsc = %g is negative.\n", + pParam->BSIM3V2cdsc); + printf("Warning: Cdsc = %g is negative.\n", pParam->BSIM3V2cdsc); + } + if (pParam->BSIM3V2cdscd < 0.0) + { fprintf(fplog, "Warning: Cdscd = %g is negative.\n", + pParam->BSIM3V2cdscd); + printf("Warning: Cdscd = %g is negative.\n", pParam->BSIM3V2cdscd); + } +/* Check DIBL parameters */ + if (pParam->BSIM3V2eta0 < 0.0) + { fprintf(fplog, "Warning: Eta0 = %g is negative.\n", + pParam->BSIM3V2eta0); + printf("Warning: Eta0 = %g is negative.\n", pParam->BSIM3V2eta0); + } + +/* Check Abulk parameters */ + if (fabs(1.0e-6 / (pParam->BSIM3V2b1 + pParam->BSIM3V2weff)) > 10.0) + { fprintf(fplog, "Warning: (B1 + Weff) may be too small.\n"); + printf("Warning: (B1 + Weff) may be too small.\n"); + } + + +/* Check Saturation parameters */ + if (pParam->BSIM3V2a2 < 0.01) + { fprintf(fplog, "Warning: A2 = %g is too small. Set to 0.01.\n", pParam->BSIM3V2a2); + printf("Warning: A2 = %g is too small. Set to 0.01.\n", + pParam->BSIM3V2a2); + pParam->BSIM3V2a2 = 0.01; + } + else if (pParam->BSIM3V2a2 > 1.0) + { fprintf(fplog, "Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM3V2a2); + printf("Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM3V2a2); + pParam->BSIM3V2a2 = 1.0; + pParam->BSIM3V2a1 = 0.0; + + } + + if (pParam->BSIM3V2rdsw < 0.0) + { fprintf(fplog, "Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM3V2rdsw); + printf("Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM3V2rdsw); + pParam->BSIM3V2rdsw = 0.0; + pParam->BSIM3V2rds0 = 0.0; + } + else if ((pParam->BSIM3V2rds0 > 0.0) && (pParam->BSIM3V2rds0 < 0.001)) + { fprintf(fplog, "Warning: Rds at current temperature = %g is less than 0.001 ohm. Set to zero.\n", + pParam->BSIM3V2rds0); + printf("Warning: Rds at current temperature = %g is less than 0.001 ohm. Set to zero.\n", + pParam->BSIM3V2rds0); + pParam->BSIM3V2rds0 = 0.0; + } + if (pParam->BSIM3V2vsattemp < 1.0e3) + { fprintf(fplog, "Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM3V2vsattemp); + printf("Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM3V2vsattemp); + } + + if (pParam->BSIM3V2pdibl1 < 0.0) + { fprintf(fplog, "Warning: Pdibl1 = %g is negative.\n", + pParam->BSIM3V2pdibl1); + printf("Warning: Pdibl1 = %g is negative.\n", pParam->BSIM3V2pdibl1); + } + if (pParam->BSIM3V2pdibl2 < 0.0) + { fprintf(fplog, "Warning: Pdibl2 = %g is negative.\n", + pParam->BSIM3V2pdibl2); + printf("Warning: Pdibl2 = %g is negative.\n", pParam->BSIM3V2pdibl2); + } +/* Check overlap capacitance parameters */ + if (model->BSIM3V2cgdo < 0.0) + { fprintf(fplog, "Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM3V2cgdo); + printf("Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM3V2cgdo); + model->BSIM3V2cgdo = 0.0; + } + if (model->BSIM3V2cgso < 0.0) + { fprintf(fplog, "Warning: cgso = %g is negative. Set to zero.\n", model->BSIM3V2cgso); + printf("Warning: cgso = %g is negative. Set to zero.\n", model->BSIM3V2cgso); + model->BSIM3V2cgso = 0.0; + } + if (model->BSIM3V2cgbo < 0.0) + { fprintf(fplog, "Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM3V2cgbo); + printf("Warning: cgbo = %g is negative. Set to zero.\n", model->BSIM3V2cgbo); + model->BSIM3V2cgbo = 0.0; + } + + }/* loop for the parameter check for warning messages */ + fclose(fplog); + } + else + { fprintf(stderr, "Warning: Can't open log file. Parameter checking skipped.\n"); + } + + return(Fatal_Flag); +} + diff --git a/src/spicelib/devices/bsim3v2/b3v2cvtest.c b/src/spicelib/devices/bsim3v2/b3v2cvtest.c new file mode 100644 index 000000000..2f59d3781 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2cvtest.c @@ -0,0 +1,120 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2cvtest.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "trandefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V2convTest(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3V2model *model = (BSIM3V2model*)inModel; +register BSIM3V2instance *here; +double delvbd, delvbs, delvds, delvgd, delvgs, vbd, vbs, vds; +double cbd, cbhat, cbs, cd, cdhat, tol, vgd, vgdo, vgs; + + /* loop through all the BSIM3V2 device models */ + for (; model != NULL; model = model->BSIM3V2nextModel) + { /* loop through all the instances of the model */ + for (here = model->BSIM3V2instances; here != NULL ; + here=here->BSIM3V2nextInstance) + { + if (here->BSIM3V2owner != ARCHme) continue; + vbs = model->BSIM3V2type + * (*(ckt->CKTrhsOld+here->BSIM3V2bNode) + - *(ckt->CKTrhsOld+here->BSIM3V2sNodePrime)); + vgs = model->BSIM3V2type + * (*(ckt->CKTrhsOld+here->BSIM3V2gNode) + - *(ckt->CKTrhsOld+here->BSIM3V2sNodePrime)); + vds = model->BSIM3V2type + * (*(ckt->CKTrhsOld+here->BSIM3V2dNodePrime) + - *(ckt->CKTrhsOld+here->BSIM3V2sNodePrime)); + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->BSIM3V2vgs) + - *(ckt->CKTstate0 + here->BSIM3V2vds); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM3V2vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM3V2vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM3V2vgs); + delvds = vds - *(ckt->CKTstate0 + here->BSIM3V2vds); + delvgd = vgd-vgdo; + + cd = here->BSIM3V2cd - here->BSIM3V2cbd; + if (here->BSIM3V2mode >= 0) + { cd += here->BSIM3V2csub; + cdhat = cd - here->BSIM3V2gbd * delvbd + + (here->BSIM3V2gmbs + here->BSIM3V2gbbs) * delvbs + + (here->BSIM3V2gm + here->BSIM3V2gbgs) * delvgs + + (here->BSIM3V2gds + here->BSIM3V2gbds) * delvds; + } + else + { cdhat = cd + (here->BSIM3V2gmbs - here->BSIM3V2gbd) * delvbd + + here->BSIM3V2gm * delvgd - here->BSIM3V2gds * delvds; + } + + /* + * check convergence + */ + if ((here->BSIM3V2off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(cd)) + + ckt->CKTabstol; + if (fabs(cdhat - cd) >= tol) + { ckt->CKTnoncon++; + return(OK); + } + cbs = here->BSIM3V2cbs; + cbd = here->BSIM3V2cbd; + if (here->BSIM3V2mode >= 0) + { cbhat = cbs + cbd - here->BSIM3V2csub + + here->BSIM3V2gbd * delvbd + + (here->BSIM3V2gbs - here->BSIM3V2gbbs) * delvbs + - here->BSIM3V2gbgs * delvgs + - here->BSIM3V2gbds * delvds; + } + else + { cbhat = cbs + cbd - here->BSIM3V2csub + + here->BSIM3V2gbs * delvbs + + (here->BSIM3V2gbd - here->BSIM3V2gbbs) * delvbd + - here->BSIM3V2gbgs * delvgd + + here->BSIM3V2gbds * delvds; + } + tol = ckt->CKTreltol * MAX(fabs(cbhat), + fabs(cbs + cbd - here->BSIM3V2csub)) + ckt->CKTabstol; + if (fabs(cbhat - (cbs + cbd - here->BSIM3V2csub)) > tol) + { ckt->CKTnoncon++; + return(OK); + } + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3v2/b3v2del.c b/src/spicelib/devices/bsim3v2/b3v2del.c new file mode 100644 index 000000000..f935a5b4e --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2del.c @@ -0,0 +1,56 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2del.c +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "bsim3v2def.h" +#include "sperror.h" +#include "gendefs.h" +#include "suffix.h" + + +int +BSIM3V2delete(inModel,name,inInst) +GENmodel *inModel; +IFuid name; +GENinstance **inInst; +{ +BSIM3V2instance **fast = (BSIM3V2instance**)inInst; +BSIM3V2model *model = (BSIM3V2model*)inModel; +BSIM3V2instance **prev = NULL; +BSIM3V2instance *here; + + for (; model ; model = model->BSIM3V2nextModel) + { prev = &(model->BSIM3V2instances); + for (here = *prev; here ; here = *prev) + { if (here->BSIM3V2name == name || (fast && here==*fast)) + { *prev= here->BSIM3V2nextInstance; + FREE(here); + return(OK); + } + prev = &(here->BSIM3V2nextInstance); + } + } + return(E_NODEV); +} + + diff --git a/src/spicelib/devices/bsim3v2/b3v2dest.c b/src/spicelib/devices/bsim3v2/b3v2dest.c new file mode 100644 index 000000000..50380f4ab --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2dest.c @@ -0,0 +1,52 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2dest.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3v2def.h" +#include "suffix.h" + +void +BSIM3V2destroy(inModel) +GENmodel **inModel; +{ +BSIM3V2model **model = (BSIM3V2model**)inModel; +BSIM3V2instance *here; +BSIM3V2instance *prev = NULL; +BSIM3V2model *mod = *model; +BSIM3V2model *oldmod = NULL; + + for (; mod ; mod = mod->BSIM3V2nextModel) + { if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (BSIM3V2instance *)NULL; + for (here = mod->BSIM3V2instances; here; here = here->BSIM3V2nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; + return; +} + + + diff --git a/src/spicelib/devices/bsim3v2/b3v2getic.c b/src/spicelib/devices/bsim3v2/b3v2getic.c new file mode 100644 index 000000000..ba732b358 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2getic.c @@ -0,0 +1,58 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2getic.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V2getic(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +BSIM3V2model *model = (BSIM3V2model*)inModel; +BSIM3V2instance *here; + + for (; model ; model = model->BSIM3V2nextModel) + { for (here = model->BSIM3V2instances; here; here = here->BSIM3V2nextInstance) + { + if (here->BSIM3V2owner != ARCHme) continue; + if(!here->BSIM3V2icVBSGiven) + { here->BSIM3V2icVBS = *(ckt->CKTrhs + here->BSIM3V2bNode) + - *(ckt->CKTrhs + here->BSIM3V2sNode); + } + if (!here->BSIM3V2icVDSGiven) + { here->BSIM3V2icVDS = *(ckt->CKTrhs + here->BSIM3V2dNode) + - *(ckt->CKTrhs + here->BSIM3V2sNode); + } + if (!here->BSIM3V2icVGSGiven) + { here->BSIM3V2icVGS = *(ckt->CKTrhs + here->BSIM3V2gNode) + - *(ckt->CKTrhs + here->BSIM3V2sNode); + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3v2/b3v2ld.c b/src/spicelib/devices/bsim3v2/b3v2ld.c new file mode 100644 index 000000000..6b315712a --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2ld.c @@ -0,0 +1,2946 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +Modified by Mansun Chan (1995). +Modified by Weidong Liu (1997-1998). +File: b3ld.c 1/3/92 +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define Charge_q 1.60219e-19 +#define DELTA_1 0.02 +#define DELTA_2 0.02 +#define DELTA_3 0.02 +#define DELTA_4 0.02 + + +int +BSIM3V2load(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM3V2model *model = (BSIM3V2model*)inModel; +register BSIM3V2instance *here; +double SourceSatCurrent, DrainSatCurrent; +double ag0, qgd, qgs, qgb, von, cbhat, VgstNVt, ExpVgst; +double cdrain, cdhat, cdreq, ceqbd, ceqbs, ceqqb, ceqqd, ceqqg, ceq, geq; +double czbd, czbdsw, czbdswg, czbs, czbssw, czbsswg, evbd, evbs, arg, sarg; +double delvbd, delvbs, delvds, delvgd, delvgs; +double Vfbeff, dVfbeff_dVg, dVfbeff_dVd, dVfbeff_dVb, V3, V4; +double gcbdb, gcbgb, gcbsb, gcddb, gcdgb, gcdsb, gcgdb, gcggb, gcgsb, gcsdb; +double gcsgb, gcssb, tol, MJ, MJSW, MJSWG; +double vbd, vbs, vds, vgb, vgd, vgs, vgdo, xfact; +double qgate, qbulk, qdrn, qsrc, qinoi, cqgate, cqbulk, cqdrn; +double Vds, Vgs, Vbs, Gmbs, FwdSum, RevSum; +double Vgs_eff, Vfb, dVfb_dVb, dVfb_dVd, dVbs_dVb; +double Phis, dPhis_dVb, sqrtPhis, dsqrtPhis_dVb, Vth, dVth_dVb, dVth_dVd; +double Vgst, dVgst_dVg, dVgst_dVb, dVgs_eff_dVg, Nvtm; +double Vgdt, Vgsaddvth, Vgsaddvth2, Vgsaddvth1o3, Vtm; +double n, dn_dVb, dn_dVd, voffcv, noff, dnoff_dVd, dnoff_dVb; +double ExpArg, ExpArg1, V0, CoxWLcen, QovCox, LINK; +double DeltaPhi, dDeltaPhi_dVg, dDeltaPhi_dVd, dDeltaPhi_dVb; +double Cox, Tox, Tcen, dTcen_dVg, dTcen_dVd, dTcen_dVb; +double Ccen, Coxeff, dCoxeff_dVg, dCoxeff_dVd, dCoxeff_dVb; +double Denomi, dDenomi_dVg, dDenomi_dVd, dDenomi_dVb; +double ueff, dueff_dVg, dueff_dVd, dueff_dVb; +double Esat, dEsat_dVg, dEsat_dVd, dEsat_dVb, Vdsat, Vdsat0; +double EsatL, dEsatL_dVg, dEsatL_dVd, dEsatL_dVb; +double Ilimit, Iexp, dIexp_dVg, dIexp_dVd, dIexp_dVb; +double dVdsat_dVg, dVdsat_dVb, dVdsat_dVd, Vasat, dAlphaz_dVg, dAlphaz_dVb; +double dVasat_dVg, dVasat_dVb, dVasat_dVd, Va, Va2, dVa_dVd, dVa_dVg, dVa_dVb; +double Vbseff, dVbseff_dVb, VbseffCV, dVbseffCV_dVb; +double Arg1, Arg2, One_Third_CoxWL, Two_Third_CoxWL, Alphaz, CoxWL; +double dqbulk_dVb, dVgdt_dVg, dVgdt_dVd, dVgdt_dVb; +double T0, dT0_dVg, dT0_dVd, dT0_dVb; +double T1, dT1_dVg, dT1_dVd, dT1_dVb; +double T2, dT2_dVg, dT2_dVd, dT2_dVb; +double T3, dT3_dVg, dT3_dVd, dT3_dVb; +double T4, dT4_dVg, dT4_dVd, dT4_dVb; +double T5, dT5_dVg, dT5_dVd, dT5_dVb; +double T6, dT6_dVg, dT6_dVd, dT6_dVb; +double T7, dT7_dVg, dT7_dVd, dT7_dVb; +double T8, dT8_dVg, dT8_dVd, dT8_dVb; +double T9, dT9_dVg, dT9_dVd, dT9_dVb; +double T10, dT10_dVg, dT10_dVb, dT10_dVd; +double T11, T12; +double tmp, Abulk, dAbulk_dVb, Abulk0, dAbulk0_dVb; +double T100, T101; +double VACLM, dVACLM_dVg, dVACLM_dVd, dVACLM_dVb; +double VADIBL, dVADIBL_dVg, dVADIBL_dVd, dVADIBL_dVb; +double VAHCE, dVAHCE_dVg, dVAHCE_dVd, dVAHCE_dVb; +double Xdep, dXdep_dVb, lt1, dlt1_dVb, ltw, dltw_dVb, Delt_vth, dDelt_vth_dVb; +double Theta0, dTheta0_dVb, Theta1, dTheta1_dVb; +double Thetarout, dThetarout_dVb, TempRatio, tmp1, tmp2, tmp3, tmp4; +double DIBL_Sft, dDIBL_Sft_dVd, DIBL_fact, Lambda, dLambda_dVg; +double Rout_Vgs_factor, dRout_Vgs_factor_dVg, dRout_Vgs_factor_dVb; +double dRout_Vgs_factor_dVd, Idtot, Ibtot; +double tempv, a1, ScalingFactor; + +double Vgsteff, dVgsteff_dVg, dVgsteff_dVd, dVgsteff_dVb; +double Vdseff, dVdseff_dVg, dVdseff_dVd, dVdseff_dVb; +double VdseffCV, dVdseffCV_dVg, dVdseffCV_dVd, dVdseffCV_dVb; +double diffVds, diffVdsCV, dAbulk_dVg; +double beta, dbeta_dVg, dbeta_dVd, dbeta_dVb; +double gche, dgche_dVg, dgche_dVd, dgche_dVb; +double fgche1, dfgche1_dVg, dfgche1_dVd, dfgche1_dVb; +double fgche2, dfgche2_dVg, dfgche2_dVd, dfgche2_dVb; +double Idl, dIdl_dVg, dIdl_dVd, dIdl_dVb; +double Idsa, dIdsa_dVg, dIdsa_dVd, dIdsa_dVb; +double Ids, Gm, Gds, Gmb; +double Isub, Isubd, Isubs, Gbd, Gbg, Gbb; +double VASCBE, dVASCBE_dVg, dVASCBE_dVd, dVASCBE_dVb; +double CoxWovL; +double Rds, dRds_dVg, dRds_dVb, WVCox, WVCoxRds; +double Vgst2Vtm, VdsatCV, dVdsatCV_dVd, dVdsatCV_dVg, dVdsatCV_dVb; +double Leff, Weff, dWeff_dVg, dWeff_dVb; +double AbulkCV, dAbulkCV_dVb; +double qgdo, qgso, cgdo, cgso; + +double qcheq, qdef, gqdef, cqdef, cqcheq, gtau_diff, gtau_drift, csreq; +double gcqdb,gcqsb,gcqgb,gcqbb,vss; +double dxpart, sxpart, ggtg, ggtd, ggts, ggtb; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; + +double gbspsp, gbbdp, gbbsp, gbspg, gbspb, gbspdp; +double gbdpdp, gbdpg, gbdpb, gbdpsp; +double Cgg, Cgd, Cgs, Cgb, Cdg, Cdd, Cds, Cdb, Qg, Qd; +double Csg, Csd, Css, Csb, Cbg, Cbd, Cbs, Cbb, Qs, Qb; +double Cgg1, Cgb1, Cgd1, Cbg1, Cbb1, Cbd1, Csg1, Csd1, Csb1, Qac0, Qsub0; +double dQac0_dVg, dQac0_dVd, dQac0_dVb, dQsub0_dVg, dQsub0_dVd, dQsub0_dVb; + +struct BSIM3V2SizeDependParam *pParam; +int ByPass, Check, ChargeComputationNeeded, J, error, I; +double junk[50]; + +ScalingFactor = 1.0e-9; +ChargeComputationNeeded = + ((ckt->CKTmode & (MODEAC | MODETRAN | MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) + ? 1 : 0; +for (; model != NULL; model = model->BSIM3V2nextModel) +{ for (here = model->BSIM3V2instances; here != NULL; + here = here->BSIM3V2nextInstance) + { + if (here->BSIM3V2owner != ARCHme) continue; + Check = 1; + ByPass = 0; + pParam = here->pParam; + if ((ckt->CKTmode & MODEINITSMSIG)) + { vbs = *(ckt->CKTstate0 + here->BSIM3V2vbs); + vgs = *(ckt->CKTstate0 + here->BSIM3V2vgs); + vds = *(ckt->CKTstate0 + here->BSIM3V2vds); + qdef = *(ckt->CKTstate0 + here->BSIM3V2qdef); + } + else if ((ckt->CKTmode & MODEINITTRAN)) + { vbs = *(ckt->CKTstate1 + here->BSIM3V2vbs); + vgs = *(ckt->CKTstate1 + here->BSIM3V2vgs); + vds = *(ckt->CKTstate1 + here->BSIM3V2vds); + qdef = *(ckt->CKTstate1 + here->BSIM3V2qdef); + } + else if ((ckt->CKTmode & MODEINITJCT) && !here->BSIM3V2off) + { vds = model->BSIM3V2type * here->BSIM3V2icVDS; + vgs = model->BSIM3V2type * here->BSIM3V2icVGS; + vbs = model->BSIM3V2type * here->BSIM3V2icVBS; + qdef = 0.0; + + if ((vds == 0.0) && (vgs == 0.0) && (vbs == 0.0) && + ((ckt->CKTmode & (MODETRAN | MODEAC|MODEDCOP | + MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) + { vbs = 0.0; + vgs = model->BSIM3V2type * pParam->BSIM3V2vth0 + 0.1; + vds = 0.1; + } + } + else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && + (here->BSIM3V2off)) + { qdef = vbs = vgs = vds = 0.0; + } + else + { +#ifndef PREDICTOR + if ((ckt->CKTmode & MODEINITPRED)) + { xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->BSIM3V2vbs) = + *(ckt->CKTstate1 + here->BSIM3V2vbs); + vbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V2vbs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3V2vbs))); + *(ckt->CKTstate0 + here->BSIM3V2vgs) = + *(ckt->CKTstate1 + here->BSIM3V2vgs); + vgs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V2vgs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3V2vgs))); + *(ckt->CKTstate0 + here->BSIM3V2vds) = + *(ckt->CKTstate1 + here->BSIM3V2vds); + vds = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V2vds)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM3V2vds))); + *(ckt->CKTstate0 + here->BSIM3V2vbd) = + *(ckt->CKTstate0 + here->BSIM3V2vbs) + - *(ckt->CKTstate0 + here->BSIM3V2vds); + *(ckt->CKTstate0 + here->BSIM3V2qdef) = + *(ckt->CKTstate1 + here->BSIM3V2qdef); + qdef = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM3V2qdef)) + -(xfact * (*(ckt->CKTstate2 + here->BSIM3V2qdef))); + } + else + { +#endif /* PREDICTOR */ + vbs = model->BSIM3V2type + * (*(ckt->CKTrhsOld + here->BSIM3V2bNode) + - *(ckt->CKTrhsOld + here->BSIM3V2sNodePrime)); + vgs = model->BSIM3V2type + * (*(ckt->CKTrhsOld + here->BSIM3V2gNode) + - *(ckt->CKTrhsOld + here->BSIM3V2sNodePrime)); + vds = model->BSIM3V2type + * (*(ckt->CKTrhsOld + here->BSIM3V2dNodePrime) + - *(ckt->CKTrhsOld + here->BSIM3V2sNodePrime)); + qdef = model->BSIM3V2type + * (*(ckt->CKTrhsOld + here->BSIM3V2qNode)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + + vbd = vbs - vds; + vgd = vgs - vds; + vgdo = *(ckt->CKTstate0 + here->BSIM3V2vgs) + - *(ckt->CKTstate0 + here->BSIM3V2vds); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM3V2vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM3V2vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM3V2vgs); + delvds = vds - *(ckt->CKTstate0 + here->BSIM3V2vds); + delvgd = vgd - vgdo; + + if (here->BSIM3V2mode >= 0) + { Idtot = here->BSIM3V2cd + here->BSIM3V2csub - here->BSIM3V2cbd; + cdhat = Idtot - here->BSIM3V2gbd * delvbd + + (here->BSIM3V2gmbs + here->BSIM3V2gbbs) * delvbs + + (here->BSIM3V2gm + here->BSIM3V2gbgs) * delvgs + + (here->BSIM3V2gds + here->BSIM3V2gbds) * delvds; + Ibtot = here->BSIM3V2cbs + here->BSIM3V2cbd - here->BSIM3V2csub; + cbhat = Ibtot + here->BSIM3V2gbd * delvbd + + (here->BSIM3V2gbs - here->BSIM3V2gbbs) * delvbs + - here->BSIM3V2gbgs * delvgs + - here->BSIM3V2gbds * delvds; + } + else + { Idtot = here->BSIM3V2cd - here->BSIM3V2cbd; + cdhat = Idtot - (here->BSIM3V2gbd - here->BSIM3V2gmbs) * delvbd + + here->BSIM3V2gm * delvgd + - here->BSIM3V2gds * delvds; + Ibtot = here->BSIM3V2cbs + here->BSIM3V2cbd - here->BSIM3V2csub; + cbhat = Ibtot + here->BSIM3V2gbs * delvbs + + (here->BSIM3V2gbd - here->BSIM3V2gbbs) * delvbd + - here->BSIM3V2gbgs * delvgd + + here->BSIM3V2gbds * delvds; + } + +#ifndef NOBYPASS + /* following should be one big if connected by && all over + * the place, but some C compilers can't handle that, so + * we split it up here to let them digest it in stages + */ + + if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) + if ((fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->BSIM3V2vbs))) + ckt->CKTvoltTol))) + if ((fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->BSIM3V2vbd))) + ckt->CKTvoltTol))) + if ((fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->BSIM3V2vgs))) + ckt->CKTvoltTol))) + if ((fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->BSIM3V2vds))) + ckt->CKTvoltTol))) + if ((fabs(cdhat - Idtot) < ckt->CKTreltol + * MAX(fabs(cdhat),fabs(Idtot)) + ckt->CKTabstol)) + { tempv = MAX(fabs(cbhat),fabs(Ibtot)) + ckt->CKTabstol; + if ((fabs(cbhat - Ibtot)) < ckt->CKTreltol * tempv) + { /* bypass code */ + vbs = *(ckt->CKTstate0 + here->BSIM3V2vbs); + vbd = *(ckt->CKTstate0 + here->BSIM3V2vbd); + vgs = *(ckt->CKTstate0 + here->BSIM3V2vgs); + vds = *(ckt->CKTstate0 + here->BSIM3V2vds); + qdef = *(ckt->CKTstate0 + here->BSIM3V2qdef); + + vgd = vgs - vds; + vgb = vgs - vbs; + + cdrain = here->BSIM3V2cd; + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC))) + { ByPass = 1; + qgate = here->BSIM3V2qgate; + qbulk = here->BSIM3V2qbulk; + qdrn = here->BSIM3V2qdrn; + goto line755; + } + else + { goto line850; + } + } + } + +#endif /*NOBYPASS*/ + von = here->BSIM3V2von; + if (*(ckt->CKTstate0 + here->BSIM3V2vds) >= 0.0) + { vgs = DEVfetlim(vgs, *(ckt->CKTstate0+here->BSIM3V2vgs), von); + vds = vgs - vgd; + vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->BSIM3V2vds)); + vgd = vgs - vds; + + } + else + { vgd = DEVfetlim(vgd, vgdo, von); + vds = vgs - vgd; + vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0+here->BSIM3V2vds))); + vgs = vgd + vds; + } + + if (vds >= 0.0) + { vbs = DEVpnjlim(vbs, *(ckt->CKTstate0 + here->BSIM3V2vbs), + CONSTvt0, model->BSIM3V2vcrit, &Check); + vbd = vbs - vds; + + } + else + { vbd = DEVpnjlim(vbd, *(ckt->CKTstate0 + here->BSIM3V2vbd), + CONSTvt0, model->BSIM3V2vcrit, &Check); + vbs = vbd + vds; + } + } + + /* determine DC current and derivatives */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + /* Source/drain junction diode DC model begins */ + Nvtm = model->BSIM3V2vtm * model->BSIM3V2jctEmissionCoeff; + if ((here->BSIM3V2sourceArea <= 0.0) && (here->BSIM3V2sourcePerimeter <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } + else + { SourceSatCurrent = here->BSIM3V2sourceArea + * model->BSIM3V2jctTempSatCurDensity + + here->BSIM3V2sourcePerimeter + * model->BSIM3V2jctSidewallTempSatCurDensity; + } + if (SourceSatCurrent <= 0.0) + { here->BSIM3V2gbs = ckt->CKTgmin; + here->BSIM3V2cbs = here->BSIM3V2gbs * vbs; + } + else + { if (model->BSIM3V2ijth == 0.0) + { evbs = exp(vbs / Nvtm); + here->BSIM3V2gbs = SourceSatCurrent * evbs / Nvtm + ckt->CKTgmin; + here->BSIM3V2cbs = SourceSatCurrent * (evbs - 1.0) + + ckt->CKTgmin * vbs; + } + else + { if (vbs < here->BSIM3V2vjsm) + { evbs = exp(vbs / Nvtm); + here->BSIM3V2gbs = SourceSatCurrent * evbs / Nvtm + ckt->CKTgmin; + here->BSIM3V2cbs = SourceSatCurrent * (evbs - 1.0) + + ckt->CKTgmin * vbs; + } + else + { T0 = (SourceSatCurrent + model->BSIM3V2ijth) / Nvtm; + here->BSIM3V2gbs = T0 + ckt->CKTgmin; + here->BSIM3V2cbs = model->BSIM3V2ijth + ckt->CKTgmin * vbs + + T0 * (vbs - here->BSIM3V2vjsm); + } + } + } + + if ((here->BSIM3V2drainArea <= 0.0) && (here->BSIM3V2drainPerimeter <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } + else + { DrainSatCurrent = here->BSIM3V2drainArea + * model->BSIM3V2jctTempSatCurDensity + + here->BSIM3V2drainPerimeter + * model->BSIM3V2jctSidewallTempSatCurDensity; + } + if (DrainSatCurrent <= 0.0) + { here->BSIM3V2gbd = ckt->CKTgmin; + here->BSIM3V2cbd = here->BSIM3V2gbd * vbd; + } + else + { if (model->BSIM3V2ijth == 0.0) + { evbd = exp(vbd / Nvtm); + here->BSIM3V2gbd = DrainSatCurrent * evbd / Nvtm + ckt->CKTgmin; + here->BSIM3V2cbd = DrainSatCurrent * (evbd - 1.0) + + ckt->CKTgmin * vbd; + } + else + { if (vbd < here->BSIM3V2vjdm) + { evbd = exp(vbd / Nvtm); + here->BSIM3V2gbd = DrainSatCurrent * evbd / Nvtm + ckt->CKTgmin; + here->BSIM3V2cbd = DrainSatCurrent * (evbd - 1.0) + + ckt->CKTgmin * vbd; + } + else + { T0 = (DrainSatCurrent + model->BSIM3V2ijth) / Nvtm; + here->BSIM3V2gbd = T0 + ckt->CKTgmin; + here->BSIM3V2cbd = model->BSIM3V2ijth + ckt->CKTgmin * vbd + + T0 * (vbd - here->BSIM3V2vjdm); + } + } + } + /* End of diode DC model */ + + if (vds >= 0.0) + { /* normal mode */ + here->BSIM3V2mode = 1; + Vds = vds; + Vgs = vgs; + Vbs = vbs; + } + else + { /* inverse mode */ + here->BSIM3V2mode = -1; + Vds = -vds; + Vgs = vgd; + Vbs = vbd; + } + + T0 = Vbs - pParam->BSIM3V2vbsc - 0.001; + T1 = sqrt(T0 * T0 - 0.004 * pParam->BSIM3V2vbsc); + Vbseff = pParam->BSIM3V2vbsc + 0.5 * (T0 + T1); + dVbseff_dVb = 0.5 * (1.0 + T0 / T1); + if (Vbseff < Vbs) + { Vbseff = Vbs; + } /* Added to avoid the possible numerical problems due to computer accuracy. See comments for diffVds */ + + if (Vbseff > 0.0) + { T0 = pParam->BSIM3V2phi / (pParam->BSIM3V2phi + Vbseff); + Phis = pParam->BSIM3V2phi * T0; + dPhis_dVb = -T0 * T0; + sqrtPhis = pParam->BSIM3V2phis3 / (pParam->BSIM3V2phi + 0.5 * Vbseff); + dsqrtPhis_dVb = -0.5 * sqrtPhis * sqrtPhis / pParam->BSIM3V2phis3; + } + else + { Phis = pParam->BSIM3V2phi - Vbseff; + dPhis_dVb = -1.0; + sqrtPhis = sqrt(Phis); + dsqrtPhis_dVb = -0.5 / sqrtPhis; + } + Xdep = pParam->BSIM3V2Xdep0 * sqrtPhis / pParam->BSIM3V2sqrtPhi; + dXdep_dVb = (pParam->BSIM3V2Xdep0 / pParam->BSIM3V2sqrtPhi) + * dsqrtPhis_dVb; + + Leff = pParam->BSIM3V2leff; + Vtm = model->BSIM3V2vtm; +/* Vth Calculation */ + T3 = sqrt(Xdep); + V0 = pParam->BSIM3V2vbi - pParam->BSIM3V2phi; + + T0 = pParam->BSIM3V2dvt2 * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM3V2dvt2; + } + else /* Added to avoid any discontinuity problems caused by dvt2 */ + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM3V2dvt2 * T4 * T4; + } + lt1 = model->BSIM3V2factor1 * T3 * T1; + dlt1_dVb = model->BSIM3V2factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = pParam->BSIM3V2dvt2w * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM3V2dvt2w; + } + else /* Added to avoid any discontinuity problems caused by dvt2w */ + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM3V2dvt2w * T4 * T4; + } + ltw = model->BSIM3V2factor1 * T3 * T1; + dltw_dVb = model->BSIM3V2factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = -0.5 * pParam->BSIM3V2dvt1 * Leff / lt1; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + Theta0 = T1 * (1.0 + 2.0 * T1); + dT1_dVb = -T0 / lt1 * T1 * dlt1_dVb; + dTheta0_dVb = (1.0 + 4.0 * T1) * dT1_dVb; + } + else + { T1 = MIN_EXP; + Theta0 = T1 * (1.0 + 2.0 * T1); + dTheta0_dVb = 0.0; + } + + here->BSIM3V2thetavth = pParam->BSIM3V2dvt0 * Theta0; + Delt_vth = here->BSIM3V2thetavth * V0; + dDelt_vth_dVb = pParam->BSIM3V2dvt0 * dTheta0_dVb * V0; + + T0 = -0.5 * pParam->BSIM3V2dvt1w * pParam->BSIM3V2weff * Leff / ltw; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 * (1.0 + 2.0 * T1); + dT1_dVb = -T0 / ltw * T1 * dltw_dVb; + dT2_dVb = (1.0 + 4.0 * T1) * dT1_dVb; + } + else + { T1 = MIN_EXP; + T2 = T1 * (1.0 + 2.0 * T1); + dT2_dVb = 0.0; + } + + T0 = pParam->BSIM3V2dvt0w * T2; + T2 = T0 * V0; + dT2_dVb = pParam->BSIM3V2dvt0w * dT2_dVb * V0; + + TempRatio = ckt->CKTtemp / model->BSIM3V2tnom - 1.0; + T0 = sqrt(1.0 + pParam->BSIM3V2nlx / Leff); + T1 = pParam->BSIM3V2k1ox * (T0 - 1.0) * pParam->BSIM3V2sqrtPhi + + (pParam->BSIM3V2kt1 + pParam->BSIM3V2kt1l / Leff + + pParam->BSIM3V2kt2 * Vbseff) * TempRatio; + tmp2 = model->BSIM3V2tox * pParam->BSIM3V2phi + / (pParam->BSIM3V2weff + pParam->BSIM3V2w0); + + T3 = pParam->BSIM3V2eta0 + pParam->BSIM3V2etab * Vbseff; + if (T3 < 1.0e-4) /* avoid discontinuity problems caused by etab */ + { T9 = 1.0 / (3.0 - 2.0e4 * T3); + T3 = (2.0e-4 - T3) * T9; + T4 = T9 * T9; + } + else + { T4 = 1.0; + } + dDIBL_Sft_dVd = T3 * pParam->BSIM3V2theta0vb0; + DIBL_Sft = dDIBL_Sft_dVd * Vds; + + Vth = model->BSIM3V2type * pParam->BSIM3V2vth0 - pParam->BSIM3V2k1 + * pParam->BSIM3V2sqrtPhi + pParam->BSIM3V2k1ox * sqrtPhis + - pParam->BSIM3V2k2ox * Vbseff - Delt_vth - T2 + (pParam->BSIM3V2k3 + + pParam->BSIM3V2k3b * Vbseff) * tmp2 + T1 - DIBL_Sft; + + here->BSIM3V2von = Vth; + + dVth_dVb = pParam->BSIM3V2k1ox * dsqrtPhis_dVb - pParam->BSIM3V2k2ox + - dDelt_vth_dVb - dT2_dVb + pParam->BSIM3V2k3b * tmp2 + - pParam->BSIM3V2etab * Vds * pParam->BSIM3V2theta0vb0 * T4 + + pParam->BSIM3V2kt2 * TempRatio; + dVth_dVd = -dDIBL_Sft_dVd; + +/* Calculate n */ + tmp2 = pParam->BSIM3V2nfactor * EPSSI / Xdep; + tmp3 = pParam->BSIM3V2cdsc + pParam->BSIM3V2cdscb * Vbseff + + pParam->BSIM3V2cdscd * Vds; + tmp4 = (tmp2 + tmp3 * Theta0 + pParam->BSIM3V2cit) / model->BSIM3V2cox; + if (tmp4 >= -0.5) + { n = 1.0 + tmp4; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM3V2cdscb * Theta0) / model->BSIM3V2cox; + dn_dVd = pParam->BSIM3V2cdscd * Theta0 / model->BSIM3V2cox; + } + else + /* avoid discontinuity problems caused by tmp4 */ + { T0 = 1.0 / (3.0 + 8.0 * tmp4); + n = (1.0 + 3.0 * tmp4) * T0; + T0 *= T0; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM3V2cdscb * Theta0) / model->BSIM3V2cox * T0; + dn_dVd = pParam->BSIM3V2cdscd * Theta0 / model->BSIM3V2cox * T0; + } + +/* Poly Gate Si Depletion Effect */ + T0 = pParam->BSIM3V2vfb + pParam->BSIM3V2phi; + if ((pParam->BSIM3V2ngate > 1.e18) && (pParam->BSIM3V2ngate < 1.e25) + && (Vgs > T0)) + /* added to avoid the problem caused by ngate */ + { T1 = 1.0e6 * Charge_q * EPSSI * pParam->BSIM3V2ngate + / (model->BSIM3V2cox * model->BSIM3V2cox); + T4 = sqrt(1.0 + 2.0 * (Vgs - T0) / T1); + T2 = T1 * (T4 - 1.0); + T3 = 0.5 * T2 * T2 / T1; /* T3 = Vpoly */ + T7 = 1.12 - T3 - 0.05; + T6 = sqrt(T7 * T7 + 0.224); + T5 = 1.12 - 0.5 * (T7 + T6); + Vgs_eff = Vgs - T5; + dVgs_eff_dVg = 1.0 - (0.5 - 0.5 / T4) * (1.0 + T7 / T6); + } + else + { Vgs_eff = Vgs; + dVgs_eff_dVg = 1.0; + } + Vgst = Vgs_eff - Vth; + +/* Effective Vgst (Vgsteff) Calculation */ + + T10 = 2.0 * n * Vtm; + VgstNVt = Vgst / T10; + ExpArg = (2.0 * pParam->BSIM3V2voff - Vgst) / T10; + + /* MCJ: Very small Vgst */ + if (VgstNVt > EXP_THRESHOLD) + { Vgsteff = Vgst; + dVgsteff_dVg = dVgs_eff_dVg; + dVgsteff_dVd = -dVth_dVd; + dVgsteff_dVb = -dVth_dVb; + } + else if (ExpArg > EXP_THRESHOLD) + { T0 = (Vgst - pParam->BSIM3V2voff) / (n * Vtm); + ExpVgst = exp(T0); + Vgsteff = Vtm * pParam->BSIM3V2cdep0 / model->BSIM3V2cox * ExpVgst; + dVgsteff_dVg = Vgsteff / (n * Vtm); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + T0 * Vtm * dn_dVd); + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + T0 * Vtm * dn_dVb); + dVgsteff_dVg *= dVgs_eff_dVg; + } + else + { ExpVgst = exp(VgstNVt); + T1 = T10 * log(1.0 + ExpVgst); + dT1_dVg = ExpVgst / (1.0 + ExpVgst); + dT1_dVb = -dT1_dVg * (dVth_dVb + Vgst / n * dn_dVb) + + T1 / n * dn_dVb; + dT1_dVd = -dT1_dVg * (dVth_dVd + Vgst / n * dn_dVd) + + T1 / n * dn_dVd; + + dT2_dVg = -model->BSIM3V2cox / (Vtm * pParam->BSIM3V2cdep0) + * exp(ExpArg); + T2 = 1.0 - T10 * dT2_dVg; + dT2_dVd = -dT2_dVg * (dVth_dVd - 2.0 * Vtm * ExpArg * dn_dVd) + + (T2 - 1.0) / n * dn_dVd; + dT2_dVb = -dT2_dVg * (dVth_dVb - 2.0 * Vtm * ExpArg * dn_dVb) + + (T2 - 1.0) / n * dn_dVb; + + Vgsteff = T1 / T2; + T3 = T2 * T2; + dVgsteff_dVg = (T2 * dT1_dVg - T1 * dT2_dVg) / T3 * dVgs_eff_dVg; + dVgsteff_dVd = (T2 * dT1_dVd - T1 * dT2_dVd) / T3; + dVgsteff_dVb = (T2 * dT1_dVb - T1 * dT2_dVb) / T3; + } + +/* Calculate Effective Channel Geometry */ + T9 = sqrtPhis - pParam->BSIM3V2sqrtPhi; + Weff = pParam->BSIM3V2weff - 2.0 * (pParam->BSIM3V2dwg * Vgsteff + + pParam->BSIM3V2dwb * T9); + dWeff_dVg = -2.0 * pParam->BSIM3V2dwg; + dWeff_dVb = -2.0 * pParam->BSIM3V2dwb * dsqrtPhis_dVb; + + if (Weff < 2.0e-8) /* to avoid the discontinuity problem due to Weff*/ + { T0 = 1.0 / (6.0e-8 - 2.0 * Weff); + Weff = 2.0e-8 * (4.0e-8 - Weff) * T0; + T0 *= T0 * 4.0e-16; + dWeff_dVg *= T0; + dWeff_dVb *= T0; + } + + T0 = pParam->BSIM3V2prwg * Vgsteff + pParam->BSIM3V2prwb * T9; + if (T0 >= -0.9) + { Rds = pParam->BSIM3V2rds0 * (1.0 + T0); + dRds_dVg = pParam->BSIM3V2rds0 * pParam->BSIM3V2prwg; + dRds_dVb = pParam->BSIM3V2rds0 * pParam->BSIM3V2prwb * dsqrtPhis_dVb; + } + else + /* to avoid the discontinuity problem due to prwg and prwb*/ + { T1 = 1.0 / (17.0 + 20.0 * T0); + Rds = pParam->BSIM3V2rds0 * (0.8 + T0) * T1; + T1 *= T1; + dRds_dVg = pParam->BSIM3V2rds0 * pParam->BSIM3V2prwg * T1; + dRds_dVb = pParam->BSIM3V2rds0 * pParam->BSIM3V2prwb * dsqrtPhis_dVb + * T1; + } + +/* Calculate Abulk */ + T1 = 0.5 * pParam->BSIM3V2k1ox / sqrtPhis; + dT1_dVb = -T1 / sqrtPhis * dsqrtPhis_dVb; + + T9 = sqrt(pParam->BSIM3V2xj * Xdep); + tmp1 = Leff + 2.0 * T9; + T5 = Leff / tmp1; + tmp2 = pParam->BSIM3V2a0 * T5; + tmp3 = pParam->BSIM3V2weff + pParam->BSIM3V2b1; + tmp4 = pParam->BSIM3V2b0 / tmp3; + T2 = tmp2 + tmp4; + dT2_dVb = -T9 / tmp1 / Xdep * dXdep_dVb; + T6 = T5 * T5; + T7 = T5 * T6; + + Abulk0 = 1.0 + T1 * T2; + dAbulk0_dVb = T1 * tmp2 * dT2_dVb + T2 * dT1_dVb; + + T8 = pParam->BSIM3V2ags * pParam->BSIM3V2a0 * T7; + dAbulk_dVg = -T1 * T8; + Abulk = Abulk0 + dAbulk_dVg * Vgsteff; + dAbulk_dVb = dAbulk0_dVb - T8 * Vgsteff * (dT1_dVb + + 3.0 * T1 * dT2_dVb); + + if (Abulk0 < 0.1) /* added to avoid the problems caused by Abulk0 */ + { T9 = 1.0 / (3.0 - 20.0 * Abulk0); + Abulk0 = (0.2 - Abulk0) * T9; + dAbulk0_dVb *= T9 * T9; + } + + if (Abulk < 0.1) + /* added to avoid the problems caused by Abulk */ + { T9 = 1.0 / (3.0 - 20.0 * Abulk); + Abulk = (0.2 - Abulk) * T9; + dAbulk_dVb *= T9 * T9; + } + + T2 = pParam->BSIM3V2keta * Vbseff; + if (T2 >= -0.9) + { T0 = 1.0 / (1.0 + T2); + dT0_dVb = -pParam->BSIM3V2keta * T0 * T0; + } + else + /* added to avoid the problems caused by Keta */ + { T1 = 1.0 / (0.8 + T2); + T0 = (17.0 + 20.0 * T2) * T1; + dT0_dVb = -pParam->BSIM3V2keta * T1 * T1; + } + dAbulk_dVg *= T0; + dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb; + dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb; + Abulk *= T0; + Abulk0 *= T0; + + +/* Mobility calculation */ + if (model->BSIM3V2mobMod == 1) + { T0 = Vgsteff + Vth + Vth; + T2 = pParam->BSIM3V2ua + pParam->BSIM3V2uc * Vbseff; + T3 = T0 / model->BSIM3V2tox; + T5 = T3 * (T2 + pParam->BSIM3V2ub * T3); + dDenomi_dVg = (T2 + 2.0 * pParam->BSIM3V2ub * T3) / model->BSIM3V2tox; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM3V2uc * T3; + } + else if (model->BSIM3V2mobMod == 2) + { T5 = Vgsteff / model->BSIM3V2tox * (pParam->BSIM3V2ua + + pParam->BSIM3V2uc * Vbseff + pParam->BSIM3V2ub * Vgsteff + / model->BSIM3V2tox); + dDenomi_dVg = (pParam->BSIM3V2ua + pParam->BSIM3V2uc * Vbseff + + 2.0 * pParam->BSIM3V2ub * Vgsteff / model->BSIM3V2tox) + / model->BSIM3V2tox; + dDenomi_dVd = 0.0; + dDenomi_dVb = Vgsteff * pParam->BSIM3V2uc / model->BSIM3V2tox; + } + else + { T0 = Vgsteff + Vth + Vth; + T2 = 1.0 + pParam->BSIM3V2uc * Vbseff; + T3 = T0 / model->BSIM3V2tox; + T4 = T3 * (pParam->BSIM3V2ua + pParam->BSIM3V2ub * T3); + T5 = T4 * T2; + dDenomi_dVg = (pParam->BSIM3V2ua + 2.0 * pParam->BSIM3V2ub * T3) * T2 + / model->BSIM3V2tox; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM3V2uc * T4; + } + + if (T5 >= -0.8) + { Denomi = 1.0 + T5; + } + else /* Added to avoid the discontinuity problem caused by ua and ub*/ + { T9 = 1.0 / (7.0 + 10.0 * T5); + Denomi = (0.6 + T5) * T9; + T9 *= T9; + dDenomi_dVg *= T9; + dDenomi_dVd *= T9; + dDenomi_dVb *= T9; + } + + here->BSIM3V2ueff = ueff = pParam->BSIM3V2u0temp / Denomi; + T9 = -ueff / Denomi; + dueff_dVg = T9 * dDenomi_dVg; + dueff_dVd = T9 * dDenomi_dVd; + dueff_dVb = T9 * dDenomi_dVb; + +/* Saturation Drain Voltage Vdsat */ + WVCox = Weff * pParam->BSIM3V2vsattemp * model->BSIM3V2cox; + WVCoxRds = WVCox * Rds; + + Esat = 2.0 * pParam->BSIM3V2vsattemp / ueff; + EsatL = Esat * Leff; + T0 = -EsatL /ueff; + dEsatL_dVg = T0 * dueff_dVg; + dEsatL_dVd = T0 * dueff_dVd; + dEsatL_dVb = T0 * dueff_dVb; + + /* Sqrt() */ + a1 = pParam->BSIM3V2a1; + if (a1 == 0.0) + { Lambda = pParam->BSIM3V2a2; + dLambda_dVg = 0.0; + } + else if (a1 > 0.0) +/* Added to avoid the discontinuity problem + caused by a1 and a2 (Lambda) */ + { T0 = 1.0 - pParam->BSIM3V2a2; + T1 = T0 - pParam->BSIM3V2a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * T0); + Lambda = pParam->BSIM3V2a2 + T0 - 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM3V2a1 * (1.0 + T1 / T2); + } + else + { T1 = pParam->BSIM3V2a2 + pParam->BSIM3V2a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * pParam->BSIM3V2a2); + Lambda = 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM3V2a1 * (1.0 + T1 / T2); + } + + Vgst2Vtm = Vgsteff + 2.0 * Vtm; + if (Rds > 0) + { tmp2 = dRds_dVg / Rds + dWeff_dVg / Weff; + tmp3 = dRds_dVb / Rds + dWeff_dVb / Weff; + } + else + { tmp2 = dWeff_dVg / Weff; + tmp3 = dWeff_dVb / Weff; + } + if ((Rds == 0.0) && (Lambda == 1.0)) + { T0 = 1.0 / (Abulk * EsatL + Vgst2Vtm); + tmp1 = 0.0; + T1 = T0 * T0; + T2 = Vgst2Vtm * T0; + T3 = EsatL * Vgst2Vtm; + Vdsat = T3 * T0; + + dT0_dVg = -(Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 1.0) * T1; + dT0_dVd = -(Abulk * dEsatL_dVd) * T1; + dT0_dVb = -(Abulk * dEsatL_dVb + dAbulk_dVb * EsatL) * T1; + + dVdsat_dVg = T3 * dT0_dVg + T2 * dEsatL_dVg + EsatL * T0; + dVdsat_dVd = T3 * dT0_dVd + T2 * dEsatL_dVd; + dVdsat_dVb = T3 * dT0_dVb + T2 * dEsatL_dVb; + } + else + { tmp1 = dLambda_dVg / (Lambda * Lambda); + T9 = Abulk * WVCoxRds; + T8 = Abulk * T9; + T7 = Vgst2Vtm * T9; + T6 = Vgst2Vtm * WVCoxRds; + T0 = 2.0 * Abulk * (T9 - 1.0 + 1.0 / Lambda); + dT0_dVg = 2.0 * (T8 * tmp2 - Abulk * tmp1 + + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbulk_dVg); + + dT0_dVb = 2.0 * (T8 * (2.0 / Abulk * dAbulk_dVb + tmp3) + + (1.0 / Lambda - 1.0) * dAbulk_dVb); + dT0_dVd = 0.0; + T1 = Vgst2Vtm * (2.0 / Lambda - 1.0) + Abulk * EsatL + 3.0 * T7; + + dT1_dVg = (2.0 / Lambda - 1.0) - 2.0 * Vgst2Vtm * tmp1 + + Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 3.0 * (T9 + + T7 * tmp2 + T6 * dAbulk_dVg); + dT1_dVb = Abulk * dEsatL_dVb + EsatL * dAbulk_dVb + + 3.0 * (T6 * dAbulk_dVb + T7 * tmp3); + dT1_dVd = Abulk * dEsatL_dVd; + + T2 = Vgst2Vtm * (EsatL + 2.0 * T6); + dT2_dVg = EsatL + Vgst2Vtm * dEsatL_dVg + + T6 * (4.0 + 2.0 * Vgst2Vtm * tmp2); + dT2_dVb = Vgst2Vtm * (dEsatL_dVb + 2.0 * T6 * tmp3); + dT2_dVd = Vgst2Vtm * dEsatL_dVd; + + T3 = sqrt(T1 * T1 - 2.0 * T0 * T2); + Vdsat = (T1 - T3) / T0; + + dT3_dVg = (T1 * dT1_dVg - 2.0 * (T0 * dT2_dVg + T2 * dT0_dVg)) + / T3; + dT3_dVd = (T1 * dT1_dVd - 2.0 * (T0 * dT2_dVd + T2 * dT0_dVd)) + / T3; + dT3_dVb = (T1 * dT1_dVb - 2.0 * (T0 * dT2_dVb + T2 * dT0_dVb)) + / T3; + + dVdsat_dVg = (dT1_dVg - (T1 * dT1_dVg - dT0_dVg * T2 + - T0 * dT2_dVg) / T3 - Vdsat * dT0_dVg) / T0; + dVdsat_dVb = (dT1_dVb - (T1 * dT1_dVb - dT0_dVb * T2 + - T0 * dT2_dVb) / T3 - Vdsat * dT0_dVb) / T0; + dVdsat_dVd = (dT1_dVd - (T1 * dT1_dVd - T0 * dT2_dVd) / T3) / T0; + } + here->BSIM3V2vdsat = Vdsat; + +/* Effective Vds (Vdseff) Calculation */ + T1 = Vdsat - Vds - pParam->BSIM3V2delta; + dT1_dVg = dVdsat_dVg; + dT1_dVd = dVdsat_dVd - 1.0; + dT1_dVb = dVdsat_dVb; + + T2 = sqrt(T1 * T1 + 4.0 * pParam->BSIM3V2delta * Vdsat); + T0 = T1 / T2; + T3 = 2.0 * pParam->BSIM3V2delta / T2; + dT2_dVg = T0 * dT1_dVg + T3 * dVdsat_dVg; + dT2_dVd = T0 * dT1_dVd + T3 * dVdsat_dVd; + dT2_dVb = T0 * dT1_dVb + T3 * dVdsat_dVb; + + Vdseff = Vdsat - 0.5 * (T1 + T2); + dVdseff_dVg = dVdsat_dVg - 0.5 * (dT1_dVg + dT2_dVg); + dVdseff_dVd = dVdsat_dVd - 0.5 * (dT1_dVd + dT2_dVd); + dVdseff_dVb = dVdsat_dVb - 0.5 * (dT1_dVb + dT2_dVb); + +/* Calculate VAsat */ + tmp4 = 1.0 - 0.5 * Abulk * Vdsat / Vgst2Vtm; + T9 = WVCoxRds * Vgsteff; + T8 = T9 / Vgst2Vtm; + T0 = EsatL + Vdsat + 2.0 * T9 * tmp4; + + T7 = 2.0 * WVCoxRds * tmp4; + dT0_dVg = dEsatL_dVg + dVdsat_dVg + T7 * (1.0 + tmp2 * Vgsteff) + - T8 * (Abulk * dVdsat_dVg - Abulk * Vdsat / Vgst2Vtm + + Vdsat * dAbulk_dVg); + + dT0_dVb = dEsatL_dVb + dVdsat_dVb + T7 * tmp3 * Vgsteff + - T8 * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = dEsatL_dVd + dVdsat_dVd - T8 * Abulk * dVdsat_dVd; + + T9 = WVCoxRds * Abulk; + T1 = 2.0 / Lambda - 1.0 + T9; + dT1_dVg = -2.0 * tmp1 + WVCoxRds * (Abulk * tmp2 + dAbulk_dVg); + dT1_dVb = dAbulk_dVb * WVCoxRds + T9 * tmp3; + + Vasat = T0 / T1; + dVasat_dVg = (dT0_dVg - Vasat * dT1_dVg) / T1; + dVasat_dVb = (dT0_dVb - Vasat * dT1_dVb) / T1; + dVasat_dVd = dT0_dVd / T1; + + if (Vdseff > Vds) + Vdseff = Vds; /* This code is added to fixed the problem + caused by computer precision when + Vds is very close to Vdseff. */ + diffVds = Vds - Vdseff; +/* Calculate VACLM */ + if ((pParam->BSIM3V2pclm > 0.0) && (diffVds > 1.0e-10)) + { T0 = 1.0 / (pParam->BSIM3V2pclm * Abulk * pParam->BSIM3V2litl); + dT0_dVb = -T0 / Abulk * dAbulk_dVb; + dT0_dVg = -T0 / Abulk * dAbulk_dVg; + + T2 = Vgsteff / EsatL; + T1 = Leff * (Abulk + T2); + dT1_dVg = Leff * ((1.0 - T2 * dEsatL_dVg) / EsatL + dAbulk_dVg); + dT1_dVb = Leff * (dAbulk_dVb - T2 * dEsatL_dVb / EsatL); + dT1_dVd = -T2 * dEsatL_dVd / Esat; + + T9 = T0 * T1; + VACLM = T9 * diffVds; + dVACLM_dVg = T0 * dT1_dVg * diffVds - T9 * dVdseff_dVg + + T1 * diffVds * dT0_dVg; + dVACLM_dVb = (dT0_dVb * T1 + T0 * dT1_dVb) * diffVds + - T9 * dVdseff_dVb; + dVACLM_dVd = T0 * dT1_dVd * diffVds + T9 * (1.0 - dVdseff_dVd); + } + else + { VACLM = MAX_EXP; + dVACLM_dVd = dVACLM_dVg = dVACLM_dVb = 0.0; + } + +/* Calculate VADIBL */ + if (pParam->BSIM3V2thetaRout > 0.0) + { T8 = Abulk * Vdsat; + T0 = Vgst2Vtm * T8; + dT0_dVg = Vgst2Vtm * Abulk * dVdsat_dVg + T8 + + Vgst2Vtm * Vdsat * dAbulk_dVg; + dT0_dVb = Vgst2Vtm * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = Vgst2Vtm * Abulk * dVdsat_dVd; + + T1 = Vgst2Vtm + T8; + dT1_dVg = 1.0 + Abulk * dVdsat_dVg + Vdsat * dAbulk_dVg; + dT1_dVb = Abulk * dVdsat_dVb + dAbulk_dVb * Vdsat; + dT1_dVd = Abulk * dVdsat_dVd; + + T9 = T1 * T1; + T2 = pParam->BSIM3V2thetaRout; + VADIBL = (Vgst2Vtm - T0 / T1) / T2; + dVADIBL_dVg = (1.0 - dT0_dVg / T1 + T0 * dT1_dVg / T9) / T2; + dVADIBL_dVb = (-dT0_dVb / T1 + T0 * dT1_dVb / T9) / T2; + dVADIBL_dVd = (-dT0_dVd / T1 + T0 * dT1_dVd / T9) / T2; + + T7 = pParam->BSIM3V2pdiblb * Vbseff; + if (T7 >= -0.9) + { T3 = 1.0 / (1.0 + T7); + VADIBL *= T3; + dVADIBL_dVg *= T3; + dVADIBL_dVb = (dVADIBL_dVb - VADIBL * pParam->BSIM3V2pdiblb) + * T3; + dVADIBL_dVd *= T3; + } + else +/* Added to avoid the discontinuity problem caused by pdiblcb */ + { T4 = 1.0 / (0.8 + T7); + T3 = (17.0 + 20.0 * T7) * T4; + dVADIBL_dVg *= T3; + dVADIBL_dVb = dVADIBL_dVb * T3 + - VADIBL * pParam->BSIM3V2pdiblb * T4 * T4; + dVADIBL_dVd *= T3; + VADIBL *= T3; + } + } + else + { VADIBL = MAX_EXP; + dVADIBL_dVd = dVADIBL_dVg = dVADIBL_dVb = 0.0; + } + +/* Calculate VA */ + + T8 = pParam->BSIM3V2pvag / EsatL; + T9 = T8 * Vgsteff; + if (T9 > -0.9) + { T0 = 1.0 + T9; + dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL); + dT0_dVb = -T9 * dEsatL_dVb / EsatL; + dT0_dVd = -T9 * dEsatL_dVd / EsatL; + } + else /* Added to avoid the discontinuity problems caused by pvag */ + { T1 = 1.0 / (17.0 + 20.0 * T9); + T0 = (0.8 + T9) * T1; + T1 *= T1; + dT0_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL) * T1; + + T9 *= T1 / EsatL; + dT0_dVb = -T9 * dEsatL_dVb; + dT0_dVd = -T9 * dEsatL_dVd; + } + + tmp1 = VACLM * VACLM; + tmp2 = VADIBL * VADIBL; + tmp3 = VACLM + VADIBL; + + T1 = VACLM * VADIBL / tmp3; + tmp3 *= tmp3; + dT1_dVg = (tmp1 * dVADIBL_dVg + tmp2 * dVACLM_dVg) / tmp3; + dT1_dVd = (tmp1 * dVADIBL_dVd + tmp2 * dVACLM_dVd) / tmp3; + dT1_dVb = (tmp1 * dVADIBL_dVb + tmp2 * dVACLM_dVb) / tmp3; + + Va = Vasat + T0 * T1; + dVa_dVg = dVasat_dVg + T1 * dT0_dVg + T0 * dT1_dVg; + dVa_dVd = dVasat_dVd + T1 * dT0_dVd + T0 * dT1_dVd; + dVa_dVb = dVasat_dVb + T1 * dT0_dVb + T0 * dT1_dVb; + +/* Calculate VASCBE */ + if (pParam->BSIM3V2pscbe2 > 0.0) + { if (diffVds > pParam->BSIM3V2pscbe1 * pParam->BSIM3V2litl + / EXP_THRESHOLD) + { T0 = pParam->BSIM3V2pscbe1 * pParam->BSIM3V2litl / diffVds; + VASCBE = Leff * exp(T0) / pParam->BSIM3V2pscbe2; + T1 = T0 * VASCBE / diffVds; + dVASCBE_dVg = T1 * dVdseff_dVg; + dVASCBE_dVd = -T1 * (1.0 - dVdseff_dVd); + dVASCBE_dVb = T1 * dVdseff_dVb; + } + else + { VASCBE = MAX_EXP * Leff/pParam->BSIM3V2pscbe2; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + } + else + { VASCBE = MAX_EXP; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + +/* Calculate Ids */ + CoxWovL = model->BSIM3V2cox * Weff / Leff; + beta = ueff * CoxWovL; + dbeta_dVg = CoxWovL * dueff_dVg + beta * dWeff_dVg / Weff; + dbeta_dVd = CoxWovL * dueff_dVd; + dbeta_dVb = CoxWovL * dueff_dVb + beta * dWeff_dVb / Weff; + + T0 = 1.0 - 0.5 * Abulk * Vdseff / Vgst2Vtm; + dT0_dVg = -0.5 * (Abulk * dVdseff_dVg + - Abulk * Vdseff / Vgst2Vtm + Vdseff * dAbulk_dVg) / Vgst2Vtm; + dT0_dVd = -0.5 * Abulk * dVdseff_dVd / Vgst2Vtm; + dT0_dVb = -0.5 * (Abulk * dVdseff_dVb + dAbulk_dVb * Vdseff) + / Vgst2Vtm; + + fgche1 = Vgsteff * T0; + dfgche1_dVg = Vgsteff * dT0_dVg + T0; + dfgche1_dVd = Vgsteff * dT0_dVd; + dfgche1_dVb = Vgsteff * dT0_dVb; + + T9 = Vdseff / EsatL; + fgche2 = 1.0 + T9; + dfgche2_dVg = (dVdseff_dVg - T9 * dEsatL_dVg) / EsatL; + dfgche2_dVd = (dVdseff_dVd - T9 * dEsatL_dVd) / EsatL; + dfgche2_dVb = (dVdseff_dVb - T9 * dEsatL_dVb) / EsatL; + + gche = beta * fgche1 / fgche2; + dgche_dVg = (beta * dfgche1_dVg + fgche1 * dbeta_dVg + - gche * dfgche2_dVg) / fgche2; + dgche_dVd = (beta * dfgche1_dVd + fgche1 * dbeta_dVd + - gche * dfgche2_dVd) / fgche2; + dgche_dVb = (beta * dfgche1_dVb + fgche1 * dbeta_dVb + - gche * dfgche2_dVb) / fgche2; + + T0 = 1.0 + gche * Rds; + T9 = Vdseff / T0; + Idl = gche * T9; + + dIdl_dVg = (gche * dVdseff_dVg + T9 * dgche_dVg) / T0 + - Idl * gche / T0 * dRds_dVg ; + + dIdl_dVd = (gche * dVdseff_dVd + T9 * dgche_dVd) / T0; + dIdl_dVb = (gche * dVdseff_dVb + T9 * dgche_dVb + - Idl * dRds_dVb * gche) / T0; + + T9 = diffVds / Va; + T0 = 1.0 + T9; + Idsa = Idl * T0; + dIdsa_dVg = T0 * dIdl_dVg - Idl * (dVdseff_dVg + T9 * dVa_dVg) / Va; + dIdsa_dVd = T0 * dIdl_dVd + Idl * (1.0 - dVdseff_dVd + - T9 * dVa_dVd) / Va; + dIdsa_dVb = T0 * dIdl_dVb - Idl * (dVdseff_dVb + T9 * dVa_dVb) / Va; + + T9 = diffVds / VASCBE; + T0 = 1.0 + T9; + Ids = Idsa * T0; + + Gm = T0 * dIdsa_dVg - Idsa * (dVdseff_dVg + T9 * dVASCBE_dVg) / VASCBE; + Gds = T0 * dIdsa_dVd + Idsa * (1.0 - dVdseff_dVd + - T9 * dVASCBE_dVd) / VASCBE; + Gmb = T0 * dIdsa_dVb - Idsa * (dVdseff_dVb + + T9 * dVASCBE_dVb) / VASCBE; + + Gds += Gm * dVgsteff_dVd; + Gmb += Gm * dVgsteff_dVb; + Gm *= dVgsteff_dVg; + Gmb *= dVbseff_dVb; + + /* Substrate current begins */ + tmp = pParam->BSIM3V2alpha0 + pParam->BSIM3V2alpha1 * Leff; + if ((tmp <= 0.0) || (pParam->BSIM3V2beta0 <= 0.0)) + { Isub = Gbd = Gbb = Gbg = 0.0; + } + else + { T2 = tmp / Leff; + if (diffVds > pParam->BSIM3V2beta0 / EXP_THRESHOLD) + { T0 = -pParam->BSIM3V2beta0 / diffVds; + T1 = T2 * diffVds * exp(T0); + T3 = T1 / diffVds * (T0 - 1.0); + dT1_dVg = T3 * dVdseff_dVg; + dT1_dVd = T3 * (dVdseff_dVd - 1.0); + dT1_dVb = T3 * dVdseff_dVb; + } + else + { T3 = T2 * MIN_EXP; + T1 = T3 * diffVds; + dT1_dVg = -T3 * dVdseff_dVg; + dT1_dVd = T3 * (1.0 - dVdseff_dVd); + dT1_dVb = -T3 * dVdseff_dVb; + } + Isub = T1 * Idsa; + Gbg = T1 * dIdsa_dVg + Idsa * dT1_dVg; + Gbd = T1 * dIdsa_dVd + Idsa * dT1_dVd; + Gbb = T1 * dIdsa_dVb + Idsa * dT1_dVb; + + Gbd += Gbg * dVgsteff_dVd; + Gbb += Gbg * dVgsteff_dVb; + Gbg *= dVgsteff_dVg; + Gbb *= dVbseff_dVb; /* bug fixing */ + } + + cdrain = Ids; + here->BSIM3V2gds = Gds; + here->BSIM3V2gm = Gm; + here->BSIM3V2gmbs = Gmb; + + here->BSIM3V2gbbs = Gbb; + here->BSIM3V2gbgs = Gbg; + here->BSIM3V2gbds = Gbd; + + here->BSIM3V2csub = Isub; + + /* BSIM3V2 thermal noise Qinv calculated from all capMod + * 0, 1, 2 & 3 stored in here->BSIM3V2qinv 1/1998 */ + + if ((model->BSIM3V2xpart < 0) || (!ChargeComputationNeeded)) + { qgate = qdrn = qsrc = qbulk = 0.0; + here->BSIM3V2cggb = here->BSIM3V2cgsb = here->BSIM3V2cgdb = 0.0; + here->BSIM3V2cdgb = here->BSIM3V2cdsb = here->BSIM3V2cddb = 0.0; + here->BSIM3V2cbgb = here->BSIM3V2cbsb = here->BSIM3V2cbdb = 0.0; + here->BSIM3V2cqdb = here->BSIM3V2cqsb = here->BSIM3V2cqgb + = here->BSIM3V2cqbb = 0.0; + here->BSIM3V2gtau = 0.0; + goto finished; + } + else if (model->BSIM3V2capMod == 0) + { + if (Vbseff < 0.0) + { Vbseff = Vbs; + dVbseff_dVb = 1.0; + } + else + { Vbseff = pParam->BSIM3V2phi - Phis; + dVbseff_dVb = -dPhis_dVb; + } + + Vfb = pParam->BSIM3V2vfbcv; + Vth = Vfb + pParam->BSIM3V2phi + pParam->BSIM3V2k1ox * sqrtPhis; + Vgst = Vgs_eff - Vth; + dVth_dVb = pParam->BSIM3V2k1ox * dsqrtPhis_dVb; + dVgst_dVb = -dVth_dVb; + dVgst_dVg = dVgs_eff_dVg; + + CoxWL = model->BSIM3V2cox * pParam->BSIM3V2weffCV + * pParam->BSIM3V2leffCV; + Arg1 = Vgs_eff - Vbseff - Vfb; + + if (Arg1 <= 0.0) + { qgate = CoxWL * Arg1; + qbulk = -qgate; + qdrn = 0.0; + + here->BSIM3V2cggb = CoxWL * dVgs_eff_dVg; + here->BSIM3V2cgdb = 0.0; + here->BSIM3V2cgsb = CoxWL * (dVbseff_dVb - dVgs_eff_dVg); + + here->BSIM3V2cdgb = 0.0; + here->BSIM3V2cddb = 0.0; + here->BSIM3V2cdsb = 0.0; + + here->BSIM3V2cbgb = -CoxWL * dVgs_eff_dVg; + here->BSIM3V2cbdb = 0.0; + here->BSIM3V2cbsb = -here->BSIM3V2cgsb; + here->BSIM3V2qinv = 0.0; + } + else if (Vgst <= 0.0) + { T1 = 0.5 * pParam->BSIM3V2k1ox; + T2 = sqrt(T1 * T1 + Arg1); + qgate = CoxWL * pParam->BSIM3V2k1ox * (T2 - T1); + qbulk = -qgate; + qdrn = 0.0; + + T0 = CoxWL * T1 / T2; + here->BSIM3V2cggb = T0 * dVgs_eff_dVg; + here->BSIM3V2cgdb = 0.0; + here->BSIM3V2cgsb = T0 * (dVbseff_dVb - dVgs_eff_dVg); + + here->BSIM3V2cdgb = 0.0; + here->BSIM3V2cddb = 0.0; + here->BSIM3V2cdsb = 0.0; + + here->BSIM3V2cbgb = -here->BSIM3V2cggb; + here->BSIM3V2cbdb = 0.0; + here->BSIM3V2cbsb = -here->BSIM3V2cgsb; + here->BSIM3V2qinv = 0.0; + } + else + { One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + + AbulkCV = Abulk0 * pParam->BSIM3V2abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3V2abulkCVfactor * dAbulk0_dVb; + Vdsat = Vgst / AbulkCV; + dVdsat_dVg = dVgs_eff_dVg / AbulkCV; + dVdsat_dVb = - (Vdsat * dAbulkCV_dVb + dVth_dVb)/ AbulkCV; + + if (model->BSIM3V2xpart > 0.5) + { /* 0/100 Charge partition model */ + if (Vdsat <= Vds) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V2phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.0; + + here->BSIM3V2cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3V2cgsb = -(here->BSIM3V2cggb + T2); + here->BSIM3V2cgdb = 0.0; + + here->BSIM3V2cdgb = 0.0; + here->BSIM3V2cddb = 0.0; + here->BSIM3V2cdsb = 0.0; + + here->BSIM3V2cbgb = -(here->BSIM3V2cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3V2cbsb = -(here->BSIM3V2cbgb + T3); + here->BSIM3V2cbdb = 0.0; + here->BSIM3V2qinv = -(qgate + qbulk); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + T7 = 2.0 * Vds - T1 - 3.0 * T3; + T8 = T3 - T1 - 2.0 * Vds; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V2phi - 0.5 * (Vds - T3)); + T10 = T4 * T8; + qdrn = T4 * T7; + qbulk = -(qgate + qdrn + T10); + + T5 = T3 / T1; + here->BSIM3V2cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3V2cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3V2cgsb = -(here->BSIM3V2cggb + T11 + + here->BSIM3V2cgdb); + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + T7 = T9 * T7; + T8 = T9 * T8; + T9 = 2.0 * T4 * (1.0 - 3.0 * T5); + here->BSIM3V2cdgb = (T7 * dAlphaz_dVg - T9 + * dVdsat_dVg) * dVgs_eff_dVg; + T12 = T7 * dAlphaz_dVb - T9 * dVdsat_dVb; + here->BSIM3V2cddb = T4 * (3.0 - 6.0 * T2 - 3.0 * T5); + here->BSIM3V2cdsb = -(here->BSIM3V2cdgb + T12 + + here->BSIM3V2cddb); + + T9 = 2.0 * T4 * (1.0 + T5); + T10 = (T8 * dAlphaz_dVg - T9 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = T8 * dAlphaz_dVb - T9 * dVdsat_dVb; + T12 = T4 * (2.0 * T2 + T5 - 1.0); + T0 = -(T10 + T11 + T12); + + here->BSIM3V2cbgb = -(here->BSIM3V2cggb + + here->BSIM3V2cdgb + T10); + here->BSIM3V2cbdb = -(here->BSIM3V2cgdb + + here->BSIM3V2cddb + T12); + here->BSIM3V2cbsb = -(here->BSIM3V2cgsb + + here->BSIM3V2cdsb + T0); + here->BSIM3V2qinv = -(qgate + qbulk); + } + } + else if (model->BSIM3V2xpart < 0.5) + { /* 40/60 Charge partition model */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V2phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.4 * T2; + + here->BSIM3V2cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3V2cgsb = -(here->BSIM3V2cggb + T2); + here->BSIM3V2cgdb = 0.0; + + T3 = 0.4 * Two_Third_CoxWL; + here->BSIM3V2cdgb = -T3 * dVgs_eff_dVg; + here->BSIM3V2cddb = 0.0; + T4 = T3 * dVth_dVb; + here->BSIM3V2cdsb = -(T4 + here->BSIM3V2cdgb); + + here->BSIM3V2cbgb = -(here->BSIM3V2cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3V2cbsb = -(here->BSIM3V2cbgb + T3); + here->BSIM3V2cbdb = 0.0; + here->BSIM3V2qinv = -(qgate + qbulk); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM3V2phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM3V2cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3V2cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3V2cgsb = -(here->BSIM3V2cggb + + here->BSIM3V2cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T6 = 8.0 * Vdsat * Vdsat - 6.0 * Vdsat * Vds + + 1.2 * Vds * Vds; + T8 = T2 / T1; + T7 = Vds - T1 - T8 * T6; + qdrn = T4 * T7; + T7 *= T9; + tmp = T8 / T1; + tmp1 = T4 * (2.0 - 4.0 * tmp * T6 + + T8 * (16.0 * Vdsat - 6.0 * Vds)); + + here->BSIM3V2cdgb = (T7 * dAlphaz_dVg - tmp1 + * dVdsat_dVg) * dVgs_eff_dVg; + T10 = T7 * dAlphaz_dVb - tmp1 * dVdsat_dVb; + here->BSIM3V2cddb = T4 * (2.0 - (1.0 / (3.0 * T1 + * T1) + 2.0 * tmp) * T6 + T8 + * (6.0 * Vdsat - 2.4 * Vds)); + here->BSIM3V2cdsb = -(here->BSIM3V2cdgb + + T10 + here->BSIM3V2cddb); + + T7 = 2.0 * (T1 + T3); + qbulk = -(qgate - T4 * T7); + T7 *= T9; + T0 = 4.0 * T4 * (1.0 - T5); + T12 = (-T7 * dAlphaz_dVg - here->BSIM3V2cdgb + - T0 * dVdsat_dVg) * dVgs_eff_dVg; + T11 = -T7 * dAlphaz_dVb - T10 - T0 * dVdsat_dVb; + T10 = -4.0 * T4 * (T2 - 0.5 + 0.5 * T5) + - here->BSIM3V2cddb; + tmp = -(T10 + T11 + T12); + + here->BSIM3V2cbgb = -(here->BSIM3V2cggb + + here->BSIM3V2cdgb + T12); + here->BSIM3V2cbdb = -(here->BSIM3V2cgdb + + here->BSIM3V2cddb + T11); + here->BSIM3V2cbsb = -(here->BSIM3V2cgsb + + here->BSIM3V2cdsb + tmp); + here->BSIM3V2qinv = -(qgate + qbulk); + } + } + else + { /* 50/50 partitioning */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM3V2phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.5 * T2; + + here->BSIM3V2cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM3V2cgsb = -(here->BSIM3V2cggb + T2); + here->BSIM3V2cgdb = 0.0; + + here->BSIM3V2cdgb = -One_Third_CoxWL * dVgs_eff_dVg; + here->BSIM3V2cddb = 0.0; + T4 = One_Third_CoxWL * dVth_dVb; + here->BSIM3V2cdsb = -(T4 + here->BSIM3V2cdgb); + + here->BSIM3V2cbgb = -(here->BSIM3V2cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM3V2cbsb = -(here->BSIM3V2cbgb + T3); + here->BSIM3V2cbdb = 0.0; + here->BSIM3V2qinv = -(qgate + qbulk); + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM3V2phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM3V2cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM3V2cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM3V2cgsb = -(here->BSIM3V2cggb + + here->BSIM3V2cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T7 = T1 + T3; + qdrn = -T4 * T7; + qbulk = - (qgate + qdrn + qdrn); + T7 *= T9; + T0 = T4 * (2.0 * T5 - 2.0); + + here->BSIM3V2cdgb = (T0 * dVdsat_dVg - T7 + * dAlphaz_dVg) * dVgs_eff_dVg; + T12 = T0 * dVdsat_dVb - T7 * dAlphaz_dVb; + here->BSIM3V2cddb = T4 * (1.0 - 2.0 * T2 - T5); + here->BSIM3V2cdsb = -(here->BSIM3V2cdgb + T12 + + here->BSIM3V2cddb); + + here->BSIM3V2cbgb = -(here->BSIM3V2cggb + + 2.0 * here->BSIM3V2cdgb); + here->BSIM3V2cbdb = -(here->BSIM3V2cgdb + + 2.0 * here->BSIM3V2cddb); + here->BSIM3V2cbsb = -(here->BSIM3V2cgsb + + 2.0 * here->BSIM3V2cdsb); + here->BSIM3V2qinv = -(qgate + qbulk); + } + } + } + } + else + { if (Vbseff < 0.0) + { VbseffCV = Vbseff; + dVbseffCV_dVb = 1.0; + } + else + { VbseffCV = pParam->BSIM3V2phi - Phis; + dVbseffCV_dVb = -dPhis_dVb; + } + + CoxWL = model->BSIM3V2cox * pParam->BSIM3V2weffCV + * pParam->BSIM3V2leffCV; + + /* Seperate VgsteffCV with noff and voffcv */ + noff = n * pParam->BSIM3V2noff; + dnoff_dVd = pParam->BSIM3V2noff * dn_dVd; + dnoff_dVb = pParam->BSIM3V2noff * dn_dVb; + T0 = Vtm * noff; + voffcv = pParam->BSIM3V2voffcv; + VgstNVt = (Vgst - voffcv) / T0; + + if (VgstNVt > EXP_THRESHOLD) + { Vgsteff = Vgst - voffcv; + dVgsteff_dVg = dVgs_eff_dVg; + dVgsteff_dVd = -dVth_dVd; + dVgsteff_dVb = -dVth_dVb; + } + else if (VgstNVt < -EXP_THRESHOLD) + { Vgsteff = T0 * log(1.0 + MIN_EXP); + dVgsteff_dVg = 0.0; + dVgsteff_dVd = Vgsteff / noff; + dVgsteff_dVb = dVgsteff_dVd * dnoff_dVb; + dVgsteff_dVd *= dnoff_dVd; + } + else + { ExpVgst = exp(VgstNVt); + Vgsteff = T0 * log(1.0 + ExpVgst); + dVgsteff_dVg = ExpVgst / (1.0 + ExpVgst); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + (Vgst - voffcv) + / noff * dnoff_dVd) + Vgsteff / noff * dnoff_dVd; + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + (Vgst - voffcv) + / noff * dnoff_dVb) + Vgsteff / noff * dnoff_dVb; + dVgsteff_dVg *= dVgs_eff_dVg; + } /* End of VgsteffCV - Weidong 5/1998 */ + + if (model->BSIM3V2capMod == 1) + { if (model->BSIM3V2version < 3.2) + { Vfb = Vth - pParam->BSIM3V2phi - pParam->BSIM3V2k1ox * sqrtPhis; + dVfb_dVb = dVth_dVb - pParam->BSIM3V2k1ox * dsqrtPhis_dVb; + dVfb_dVd = dVth_dVd; + } + else + { Vfb = pParam->BSIM3V2vfbzb; + dVfb_dVb = dVfb_dVd = 0.0; + } + + Arg1 = Vgs_eff - VbseffCV - Vfb - Vgsteff; + + if (Arg1 <= 0.0) + { qgate = CoxWL * Arg1; + Cgg = CoxWL * (dVgs_eff_dVg - dVgsteff_dVg); + Cgd = -CoxWL * (dVfb_dVd + dVgsteff_dVd); + Cgb = -CoxWL * (dVfb_dVb + dVbseffCV_dVb + dVgsteff_dVb); + } + else + { T0 = 0.5 * pParam->BSIM3V2k1ox; + T1 = sqrt(T0 * T0 + Arg1); + T2 = CoxWL * T0 / T1; + + qgate = CoxWL * pParam->BSIM3V2k1ox * (T1 - T0); + + Cgg = T2 * (dVgs_eff_dVg - dVgsteff_dVg); + Cgd = -T2 * (dVfb_dVd + dVgsteff_dVd); + Cgb = -T2 * (dVfb_dVb + dVbseffCV_dVb + dVgsteff_dVb); + } + qbulk = -qgate; + Cbg = -Cgg; + Cbd = -Cgd; + Cbb = -Cgb; + + One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + AbulkCV = Abulk0 * pParam->BSIM3V2abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3V2abulkCVfactor * dAbulk0_dVb; + VdsatCV = Vgsteff / AbulkCV; + if (VdsatCV < Vds) + { dVdsatCV_dVg = 1.0 / AbulkCV; + dVdsatCV_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; + T0 = Vgsteff - VdsatCV / 3.0; + dT0_dVg = 1.0 - dVdsatCV_dVg / 3.0; + dT0_dVb = -dVdsatCV_dVb / 3.0; + qgate += CoxWL * T0; + Cgg1 = CoxWL * dT0_dVg; + Cgb1 = CoxWL * dT0_dVb + Cgg1 * dVgsteff_dVb; + Cgd1 = Cgg1 * dVgsteff_dVd; + Cgg1 *= dVgsteff_dVg; + Cgg += Cgg1; + Cgb += Cgb1; + Cgd += Cgd1; + + T0 = VdsatCV - Vgsteff; + dT0_dVg = dVdsatCV_dVg - 1.0; + dT0_dVb = dVdsatCV_dVb; + qbulk += One_Third_CoxWL * T0; + Cbg1 = One_Third_CoxWL * dT0_dVg; + Cbb1 = One_Third_CoxWL * dT0_dVb + Cbg1 * dVgsteff_dVb; + Cbd1 = Cbg1 * dVgsteff_dVd; + Cbg1 *= dVgsteff_dVg; + Cbg += Cbg1; + Cbb += Cbb1; + Cbd += Cbd1; + + if (model->BSIM3V2xpart > 0.5) + T0 = -Two_Third_CoxWL; + else if (model->BSIM3V2xpart < 0.5) + T0 = -0.4 * CoxWL; + else + T0 = -One_Third_CoxWL; + + qsrc = T0 * Vgsteff; + Csg = T0 * dVgsteff_dVg; + Csb = T0 * dVgsteff_dVb; + Csd = T0 * dVgsteff_dVd; + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + } + else + { T0 = AbulkCV * Vds; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1.e-20); + T2 = Vds / T1; + T3 = T0 * T2; + dT3_dVg = -12.0 * T2 * T2 * AbulkCV; + dT3_dVd = 6.0 * T0 * (4.0 * Vgsteff - T0) / T1 / T1 - 0.5; + dT3_dVb = 12.0 * T2 * T2 * dAbulkCV_dVb * Vgsteff; + + qgate += CoxWL * (Vgsteff - 0.5 * Vds + T3); + Cgg1 = CoxWL * (1.0 + dT3_dVg); + Cgb1 = CoxWL * dT3_dVb + Cgg1 * dVgsteff_dVb; + Cgd1 = CoxWL * dT3_dVd + Cgg1 * dVgsteff_dVd; + Cgg1 *= dVgsteff_dVg; + Cgg += Cgg1; + Cgb += Cgb1; + Cgd += Cgd1; + + qbulk += CoxWL * (1.0 - AbulkCV) * (0.5 * Vds - T3); + Cbg1 = -CoxWL * ((1.0 - AbulkCV) * dT3_dVg); + Cbb1 = -CoxWL * ((1.0 - AbulkCV) * dT3_dVb + + (0.5 * Vds - T3) * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbd1 = -CoxWL * (1.0 - AbulkCV) * dT3_dVd + + Cbg1 * dVgsteff_dVd; + Cbg1 *= dVgsteff_dVg; + Cbg += Cbg1; + Cbb += Cbb1; + Cbd += Cbd1; + + if (model->BSIM3V2xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + Csg = -CoxWL * (0.5 + 24.0 * T0 * Vds / T1 / T1 + * AbulkCV); + Csb = -CoxWL * (0.25 * Vds * dAbulkCV_dVb + - 12.0 * T0 * Vds / T1 / T1 * (4.0 * Vgsteff - T0) + * dAbulkCV_dVb) + Csg * dVgsteff_dVb; + Csd = -CoxWL * (0.25 * AbulkCV - 12.0 * AbulkCV * T0 + / T1 / T1 * (4.0 * Vgsteff - T0)) + + Csg * dVgsteff_dVd; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM3V2xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T4 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + Csg = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + Csb = (qsrc / T1 * Vds + T2 * T4 * Vds) * dAbulkCV_dVb + + Csg * dVgsteff_dVb; + Csd = (qsrc / T1 + T2 * T4) * AbulkCV + + Csg * dVgsteff_dVd; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + } + qdrn = -(qgate + qbulk + qsrc); + here->BSIM3V2cggb = Cgg; + here->BSIM3V2cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3V2cgdb = Cgd; + here->BSIM3V2cdgb = -(Cgg + Cbg + Csg); + here->BSIM3V2cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3V2cddb = -(Cgd + Cbd + Csd); + here->BSIM3V2cbgb = Cbg; + here->BSIM3V2cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3V2cbdb = Cbd; + here->BSIM3V2qinv = -(qgate + qbulk); + } + + else if (model->BSIM3V2capMod == 2) + { if (model->BSIM3V2version < 3.2) + { Vfb = Vth - pParam->BSIM3V2phi - pParam->BSIM3V2k1ox * sqrtPhis; + dVfb_dVb = dVth_dVb - pParam->BSIM3V2k1ox * dsqrtPhis_dVb; + dVfb_dVd = dVth_dVd; + } + else + { Vfb = pParam->BSIM3V2vfbzb; + dVfb_dVb = dVfb_dVd = 0.0; + } + + V3 = Vfb - Vgs_eff + VbseffCV - DELTA_3; + if (Vfb <= 0.0) + { T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); + T2 = -DELTA_3 / T0; + } + else + { T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); + T2 = DELTA_3 / T0; + } + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = Vfb - 0.5 * (V3 + T0); + dVfbeff_dVd = (1.0 - T1 - T2) * dVfb_dVd; + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = (1.0 - T1 - T2) * dVfb_dVb + - T1 * dVbseffCV_dVb; + Qac0 = CoxWL * (Vfbeff - Vfb); + dQac0_dVg = CoxWL * dVfbeff_dVg; + dQac0_dVd = CoxWL * (dVfbeff_dVd - dVfb_dVd); + dQac0_dVb = CoxWL * (dVfbeff_dVb - dVfb_dVb); + + T0 = 0.5 * pParam->BSIM3V2k1ox; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + if (pParam->BSIM3V2k1ox == 0.0) + { T1 = 0.0; + T2 = 0.0; + } + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM3V2k1ox; + T2 = CoxWL; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = CoxWL * T0 / T1; + } + + Qsub0 = CoxWL * pParam->BSIM3V2k1ox * (T1 - T0); + + dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg); + dQsub0_dVd = -T2 * (dVfbeff_dVd + dVgsteff_dVd); + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + + dVgsteff_dVb); + + AbulkCV = Abulk0 * pParam->BSIM3V2abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3V2abulkCVfactor * dAbulk0_dVb; + VdsatCV = Vgsteff / AbulkCV; + + V4 = VdsatCV - Vds - DELTA_4; + T0 = sqrt(V4 * V4 + 4.0 * DELTA_4 * VdsatCV); + VdseffCV = VdsatCV - 0.5 * (V4 + T0); + T1 = 0.5 * (1.0 + V4 / T0); + T2 = DELTA_4 / T0; + T3 = (1.0 - T1 - T2) / AbulkCV; + dVdseffCV_dVg = T3; + dVdseffCV_dVd = T1; + dVdseffCV_dVb = -T3 * VdsatCV * dAbulkCV_dVb; + + T0 = AbulkCV * VdseffCV; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1e-20); + T2 = VdseffCV / T1; + T3 = T0 * T2; + + T4 = (1.0 - 12.0 * T2 * T2 * AbulkCV); + T5 = (6.0 * T0 * (4.0 * Vgsteff - T0) / (T1 * T1) - 0.5); + T6 = 12.0 * T2 * T2 * Vgsteff; + + qinoi = -CoxWL * (Vgsteff - 0.5 * T0 + AbulkCV * T3); + qgate = CoxWL * (Vgsteff - 0.5 * VdseffCV + T3); + Cgg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cgd1 = CoxWL * T5 * dVdseffCV_dVd + Cgg1 * dVgsteff_dVd; + Cgb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb; + Cgg1 *= dVgsteff_dVg; + + T7 = 1.0 - AbulkCV; + qbulk = CoxWL * T7 * (0.5 * VdseffCV - T3); + T4 = -T7 * (T4 - 1.0); + T5 = -T7 * T5; + T6 = -(T7 * T6 + (0.5 * VdseffCV - T3)); + Cbg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cbd1 = CoxWL * T5 * dVdseffCV_dVd + Cbg1 * dVgsteff_dVd; + Cbb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbg1 *= dVgsteff_dVg; + + if (model->BSIM3V2xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + T7 = (4.0 * Vgsteff - T0) / (T1 * T1); + T4 = -(0.5 + 24.0 * T0 * T0 / (T1 * T1)); + T5 = -(0.25 * AbulkCV - 12.0 * AbulkCV * T0 * T7); + T6 = -(0.25 * VdseffCV - 12.0 * T0 * VdseffCV * T7); + Csg = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWL * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM3V2xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T7 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + T4 = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + T5 = (qsrc / T1 + T2 * T7) * AbulkCV; + T6 = (qsrc / T1 * VdseffCV + T2 * T7 * VdseffCV); + Csg = (T4 + T5 * dVdseffCV_dVg); + Csd = T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + + qgate += Qac0 + Qsub0; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cgg = dQac0_dVg + dQsub0_dVg + Cgg1; + Cgd = dQac0_dVd + dQsub0_dVd + Cgd1; + Cgb = dQac0_dVb + dQsub0_dVb + Cgb1; + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQac0_dVd - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM3V2cggb = Cgg; + here->BSIM3V2cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3V2cgdb = Cgd; + here->BSIM3V2cdgb = -(Cgg + Cbg + Csg); + here->BSIM3V2cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3V2cddb = -(Cgd + Cbd + Csd); + here->BSIM3V2cbgb = Cbg; + here->BSIM3V2cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3V2cbdb = Cbd; + here->BSIM3V2qinv = qinoi; + } + + /* New Charge-Thickness capMod (CTM) begins - Weidong 7/1997 */ + else if (model->BSIM3V2capMod == 3) + { V3 = pParam->BSIM3V2vfbzb - Vgs_eff + VbseffCV - DELTA_3; + if (pParam->BSIM3V2vfbzb <= 0.0) + { T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * pParam->BSIM3V2vfbzb); + T2 = -DELTA_3 / T0; + } + else + { T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * pParam->BSIM3V2vfbzb); + T2 = DELTA_3 / T0; + } + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = pParam->BSIM3V2vfbzb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1 * dVbseffCV_dVb; + + Cox = model->BSIM3V2cox; + Tox = 1.0e8 * model->BSIM3V2tox; + T0 = (Vgs_eff - VbseffCV - pParam->BSIM3V2vfbzb) / Tox; + dT0_dVg = dVgs_eff_dVg / Tox; + dT0_dVb = -dVbseffCV_dVb / Tox; + + tmp = T0 * pParam->BSIM3V2acde; + if ((-EXP_THRESHOLD < tmp) && (tmp < EXP_THRESHOLD)) + { Tcen = pParam->BSIM3V2ldeb * exp(tmp); + dTcen_dVg = pParam->BSIM3V2acde * Tcen; + dTcen_dVb = dTcen_dVg * dT0_dVb; + dTcen_dVg *= dT0_dVg; + } + else if (tmp <= -EXP_THRESHOLD) + { Tcen = pParam->BSIM3V2ldeb * MIN_EXP; + dTcen_dVg = dTcen_dVb = 0.0; + } + else + { Tcen = pParam->BSIM3V2ldeb * MAX_EXP; + dTcen_dVg = dTcen_dVb = 0.0; + } + + LINK = 1.0e-3 * model->BSIM3V2tox; + V3 = pParam->BSIM3V2ldeb - Tcen - LINK; + V4 = sqrt(V3 * V3 + 4.0 * LINK * pParam->BSIM3V2ldeb); + Tcen = pParam->BSIM3V2ldeb - 0.5 * (V3 + V4); + T1 = 0.5 * (1.0 + V3 / V4); + dTcen_dVg *= T1; + dTcen_dVb *= T1; + + Ccen = EPSSI / Tcen; + T2 = Cox / (Cox + Ccen); + Coxeff = T2 * Ccen; + T3 = -Ccen / Tcen; + dCoxeff_dVg = T2 * T2 * T3; + dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; + dCoxeff_dVg *= dTcen_dVg; + CoxWLcen = CoxWL * Coxeff / Cox; + + Qac0 = CoxWLcen * (Vfbeff - pParam->BSIM3V2vfbzb); + QovCox = Qac0 / Coxeff; + dQac0_dVg = CoxWLcen * dVfbeff_dVg + + QovCox * dCoxeff_dVg; + dQac0_dVb = CoxWLcen * dVfbeff_dVb + + QovCox * dCoxeff_dVb; + + T0 = 0.5 * pParam->BSIM3V2k1ox; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + if (pParam->BSIM3V2k1ox == 0.0) + { T1 = 0.0; + T2 = 0.0; + } + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM3V2k1ox; + T2 = CoxWLcen; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = CoxWLcen * T0 / T1; + } + + Qsub0 = CoxWLcen * pParam->BSIM3V2k1ox * (T1 - T0); + QovCox = Qsub0 / Coxeff; + dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg) + + QovCox * dCoxeff_dVg; + dQsub0_dVd = -T2 * dVgsteff_dVd; + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + dVgsteff_dVb) + + QovCox * dCoxeff_dVb; + + /* Gate-bias dependent delta Phis begins */ + if (pParam->BSIM3V2k1ox <= 0.0) + { Denomi = 0.25 * pParam->BSIM3V2moin * Vtm; + T0 = 0.5 * pParam->BSIM3V2sqrtPhi; + } + else + { Denomi = pParam->BSIM3V2moin * Vtm + * pParam->BSIM3V2k1ox * pParam->BSIM3V2k1ox; + T0 = pParam->BSIM3V2k1ox * pParam->BSIM3V2sqrtPhi; + } + T1 = 2.0 * T0 + Vgsteff; + + DeltaPhi = Vtm * log(1.0 + T1 * Vgsteff / Denomi); + dDeltaPhi_dVg = 2.0 * Vtm * (T1 -T0) / (Denomi + T1 * Vgsteff); + dDeltaPhi_dVd = dDeltaPhi_dVg * dVgsteff_dVd; + dDeltaPhi_dVb = dDeltaPhi_dVg * dVgsteff_dVb; + /* End of delta Phis */ + + T3 = 4.0 * (Vth - pParam->BSIM3V2vfbzb - pParam->BSIM3V2phi); + Tox += Tox; + if (T3 >= 0.0) + T0 = (Vgsteff + T3) / Tox; + else + T0 = (Vgsteff + 1.0e-20) / Tox; + tmp = exp(0.7 * log(T0)); + T1 = 1.0 + tmp; + T2 = 0.7 * tmp / (T0 * Tox); + Tcen = 1.9e-9 / T1; + dTcen_dVg = -1.9e-9 * T2 / T1 /T1; + dTcen_dVd = dTcen_dVg * (4.0 * dVth_dVd + dVgsteff_dVd); + dTcen_dVb = dTcen_dVg * (4.0 * dVth_dVb + dVgsteff_dVb); + dTcen_dVg *= dVgsteff_dVg; + + Ccen = EPSSI / Tcen; + T0 = Cox / (Cox + Ccen); + Coxeff = T0 * Ccen; + T1 = -Ccen / Tcen; + dCoxeff_dVg = T0 * T0 * T1; + dCoxeff_dVd = dCoxeff_dVg * dTcen_dVd; + dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; + dCoxeff_dVg *= dTcen_dVg; + CoxWLcen = CoxWL * Coxeff / Cox; + + AbulkCV = Abulk0 * pParam->BSIM3V2abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM3V2abulkCVfactor * dAbulk0_dVb; + VdsatCV = (Vgsteff - DeltaPhi) / AbulkCV; + V4 = VdsatCV - Vds - DELTA_4; + T0 = sqrt(V4 * V4 + 4.0 * DELTA_4 * VdsatCV); + VdseffCV = VdsatCV - 0.5 * (V4 + T0); + T1 = 0.5 * (1.0 + V4 / T0); + T2 = DELTA_4 / T0; + T3 = (1.0 - T1 - T2) / AbulkCV; + T4 = T3 * ( 1.0 - dDeltaPhi_dVg); + dVdseffCV_dVg = T4; + dVdseffCV_dVd = T1; + dVdseffCV_dVb = -T3 * VdsatCV * dAbulkCV_dVb; + + T0 = AbulkCV * VdseffCV; + T1 = Vgsteff - DeltaPhi; + T2 = 12.0 * (T1 - 0.5 * T0 + 1.0e-20); + T3 = T0 / T2; + T4 = 1.0 - 12.0 * T3 * T3; + T5 = AbulkCV * (6.0 * T0 * (4.0 * T1 - T0) / (T2 * T2) - 0.5); + T6 = T5 * VdseffCV / AbulkCV; + + qgate = qinoi = CoxWLcen * (T1 - T0 * (0.5 - T3)); + QovCox = qgate / Coxeff; + Cgg1 = CoxWLcen * (T4 * (1.0 - dDeltaPhi_dVg) + + T5 * dVdseffCV_dVg); + Cgd1 = CoxWLcen * T5 * dVdseffCV_dVd + Cgg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cgb1 = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cgg1 = Cgg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + + + T7 = 1.0 - AbulkCV; + T8 = T2 * T2; + T9 = 12.0 * T7 * T0 * T0 / (T8 * AbulkCV); + T10 = T9 * (1.0 - dDeltaPhi_dVg); + T11 = -T7 * T5 / AbulkCV; + T12 = -(T9 * T1 / AbulkCV + VdseffCV * (0.5 - T0 / T2)); + + qbulk = CoxWLcen * T7 * (0.5 * VdseffCV - T0 * VdseffCV / T2); + QovCox = qbulk / Coxeff; + Cbg1 = CoxWLcen * (T10 + T11 * dVdseffCV_dVg); + Cbd1 = CoxWLcen * T11 * dVdseffCV_dVd + Cbg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cbb1 = CoxWLcen * (T11 * dVdseffCV_dVb + T12 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cbg1 = Cbg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + + if (model->BSIM3V2xpart > 0.5) + { /* 0/100 partition */ + qsrc = -CoxWLcen * (T1 / 2.0 + T0 / 4.0 + - 0.5 * T0 * T0 / T2); + QovCox = qsrc / Coxeff; + T2 += T2; + T3 = T2 * T2; + T7 = -(0.25 - 12.0 * T0 * (4.0 * T1 - T0) / T3); + T4 = -(0.5 + 24.0 * T0 * T0 / T3) * (1.0 - dDeltaPhi_dVg); + T5 = T7 * AbulkCV; + T6 = T7 * VdseffCV; + + Csg = CoxWLcen * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWLcen * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd + + QovCox * dCoxeff_dVd; + Csb = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + } + else if (model->BSIM3V2xpart < 0.5) + { /* 40/60 partition */ + T2 = T2 / 12.0; + T3 = 0.5 * CoxWLcen / (T2 * T2); + T4 = T1 * (2.0 * T0 * T0 / 3.0 + T1 * (T1 - 4.0 + * T0 / 3.0)) - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T3 * T4; + QovCox = qsrc / Coxeff; + T8 = 4.0 / 3.0 * T1 * (T1 - T0) + 0.4 * T0 * T0; + T5 = -2.0 * qsrc / T2 - T3 * (T1 * (3.0 * T1 - 8.0 + * T0 / 3.0) + 2.0 * T0 * T0 / 3.0); + T6 = AbulkCV * (qsrc / T2 + T3 * T8); + T7 = T6 * VdseffCV / AbulkCV; + + Csg = T5 * (1.0 - dDeltaPhi_dVg) + T6 * dVdseffCV_dVg; + Csd = Csg * dVgsteff_dVd + T6 * dVdseffCV_dVd + + QovCox * dCoxeff_dVd; + Csb = Csg * dVgsteff_dVb + T6 * dVdseffCV_dVb + + T7 * dAbulkCV_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + } + else + { /* 50/50 partition */ + qsrc = -0.5 * qgate; + Csg = -0.5 * Cgg1; + Csd = -0.5 * Cgd1; + Csb = -0.5 * Cgb1; + } + + qgate += Qac0 + Qsub0 - qbulk; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgg = Cgg1 - Cbg; + Cgd = Cgd1 - Cbd; + Cgb = Cgb1 - Cbb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM3V2cggb = Cgg; + here->BSIM3V2cgsb = -(Cgg + Cgd + Cgb); + here->BSIM3V2cgdb = Cgd; + here->BSIM3V2cdgb = -(Cgg + Cbg + Csg); + here->BSIM3V2cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM3V2cddb = -(Cgd + Cbd + Csd); + here->BSIM3V2cbgb = Cbg; + here->BSIM3V2cbsb = -(Cbg + Cbd + Cbb); + here->BSIM3V2cbdb = Cbd; + here->BSIM3V2qinv = -qinoi; + } /* End of CTM */ + } + +finished: + /* Returning Values to Calling Routine */ + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + + here->BSIM3V2qgate = qgate; + here->BSIM3V2qbulk = qbulk; + here->BSIM3V2qdrn = qdrn; + here->BSIM3V2cd = cdrain; + + if (ChargeComputationNeeded) + { /* charge storage elements + * bulk-drain and bulk-source depletion capacitances + * czbd : zero bias drain junction capacitance + * czbs : zero bias source junction capacitance + * czbdsw: zero bias drain junction sidewall capacitance + along field oxide + * czbssw: zero bias source junction sidewall capacitance + along field oxide + * czbdswg: zero bias drain junction sidewall capacitance + along gate side + * czbsswg: zero bias source junction sidewall capacitance + along gate side + */ + + czbd = model->BSIM3V2unitAreaJctCap * here->BSIM3V2drainArea; + czbs = model->BSIM3V2unitAreaJctCap * here->BSIM3V2sourceArea; + if (here->BSIM3V2drainPerimeter < pParam->BSIM3V2weff) + { + czbdswg = model->BSIM3V2unitLengthGateSidewallJctCap + * here->BSIM3V2drainPerimeter; + czbdsw = 0.0; + } + else + { + czbdsw = model->BSIM3V2unitLengthSidewallJctCap + * (here->BSIM3V2drainPerimeter - pParam->BSIM3V2weff); + czbdswg = model->BSIM3V2unitLengthGateSidewallJctCap + * pParam->BSIM3V2weff; + } + if (here->BSIM3V2sourcePerimeter < pParam->BSIM3V2weff) + { + czbssw = 0.0; + czbsswg = model->BSIM3V2unitLengthGateSidewallJctCap + * here->BSIM3V2sourcePerimeter; + } + else + { + czbssw = model->BSIM3V2unitLengthSidewallJctCap + * (here->BSIM3V2sourcePerimeter - pParam->BSIM3V2weff); + czbsswg = model->BSIM3V2unitLengthGateSidewallJctCap + * pParam->BSIM3V2weff; + } + + MJ = model->BSIM3V2bulkJctBotGradingCoeff; + MJSW = model->BSIM3V2bulkJctSideGradingCoeff; + MJSWG = model->BSIM3V2bulkJctGateSideGradingCoeff; + + /* Source Bulk Junction */ + if (vbs == 0.0) + { *(ckt->CKTstate0 + here->BSIM3V2qbs) = 0.0; + here->BSIM3V2capbs = czbs + czbssw + czbsswg; + } + else if (vbs < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - vbs / model->BSIM3V2PhiB; + if (MJ == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJ * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V2qbs) = model->BSIM3V2PhiB * czbs + * (1.0 - arg * sarg) / (1.0 - MJ); + here->BSIM3V2capbs = czbs * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM3V2qbs) = 0.0; + here->BSIM3V2capbs = 0.0; + } + if (czbssw > 0.0) + { arg = 1.0 - vbs / model->BSIM3V2PhiBSW; + if (MJSW == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSW * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V2qbs) += model->BSIM3V2PhiBSW * czbssw + * (1.0 - arg * sarg) / (1.0 - MJSW); + here->BSIM3V2capbs += czbssw * sarg; + } + if (czbsswg > 0.0) + { arg = 1.0 - vbs / model->BSIM3V2PhiBSWG; + if (MJSWG == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWG * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V2qbs) += model->BSIM3V2PhiBSWG * czbsswg + * (1.0 - arg * sarg) / (1.0 - MJSWG); + here->BSIM3V2capbs += czbsswg * sarg; + } + + } + else + { T0 = czbs + czbssw + czbsswg; + T1 = vbs * (czbs * MJ / model->BSIM3V2PhiB + czbssw * MJSW + / model->BSIM3V2PhiBSW + czbsswg * MJSWG / model->BSIM3V2PhiBSWG); + *(ckt->CKTstate0 + here->BSIM3V2qbs) = vbs * (T0 + 0.5 * T1); + here->BSIM3V2capbs = T0 + T1; + } + + /* Drain Bulk Junction */ + if (vbd == 0.0) + { *(ckt->CKTstate0 + here->BSIM3V2qbd) = 0.0; + here->BSIM3V2capbd = czbd + czbdsw + czbdswg; + } + else if (vbd < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - vbd / model->BSIM3V2PhiB; + if (MJ == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJ * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V2qbd) = model->BSIM3V2PhiB * czbd + * (1.0 - arg * sarg) / (1.0 - MJ); + here->BSIM3V2capbd = czbd * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM3V2qbd) = 0.0; + here->BSIM3V2capbd = 0.0; + } + if (czbdsw > 0.0) + { arg = 1.0 - vbd / model->BSIM3V2PhiBSW; + if (MJSW == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSW * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V2qbd) += model->BSIM3V2PhiBSW * czbdsw + * (1.0 - arg * sarg) / (1.0 - MJSW); + here->BSIM3V2capbd += czbdsw * sarg; + } + if (czbdswg > 0.0) + { arg = 1.0 - vbd / model->BSIM3V2PhiBSWG; + if (MJSWG == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWG * log(arg)); + *(ckt->CKTstate0 + here->BSIM3V2qbd) += model->BSIM3V2PhiBSWG * czbdswg + * (1.0 - arg * sarg) / (1.0 - MJSWG); + here->BSIM3V2capbd += czbdswg * sarg; + } + } + else + { T0 = czbd + czbdsw + czbdswg; + T1 = vbd * (czbd * MJ / model->BSIM3V2PhiB + czbdsw * MJSW + / model->BSIM3V2PhiBSW + czbdswg * MJSWG / model->BSIM3V2PhiBSWG); + *(ckt->CKTstate0 + here->BSIM3V2qbd) = vbd * (T0 + 0.5 * T1); + here->BSIM3V2capbd = T0 + T1; + } + } + + /* + * check convergence + */ + if ((here->BSIM3V2off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { if (Check == 1) + { ckt->CKTnoncon++; +#ifndef NEWCONV + } + else + { if (here->BSIM3V2mode >= 0) + { Idtot = here->BSIM3V2cd + here->BSIM3V2csub - here->BSIM3V2cbd; + } + else + { Idtot = here->BSIM3V2cd - here->BSIM3V2cbd; + } + tol = ckt->CKTreltol * MAX(fabs(cdhat), fabs(Idtot)) + + ckt->CKTabstol; + if (fabs(cdhat - Idtot) >= tol) + { ckt->CKTnoncon++; + } + else + { Ibtot = here->BSIM3V2cbs + here->BSIM3V2cbd - here->BSIM3V2csub; + tol = ckt->CKTreltol * MAX(fabs(cbhat), fabs(Ibtot)) + + ckt->CKTabstol; + if (fabs(cbhat - Ibtot)) > tol) + { ckt->CKTnoncon++; + } + } +#endif /* NEWCONV */ + } + } + *(ckt->CKTstate0 + here->BSIM3V2vbs) = vbs; + *(ckt->CKTstate0 + here->BSIM3V2vbd) = vbd; + *(ckt->CKTstate0 + here->BSIM3V2vgs) = vgs; + *(ckt->CKTstate0 + here->BSIM3V2vds) = vds; + *(ckt->CKTstate0 + here->BSIM3V2qdef) = qdef; + + /* bulk and channel charge plus overlaps */ + + if (!ChargeComputationNeeded) + goto line850; + +line755: + /* NQS (Mansun 11/1993) modified by Weidong & Min-Chie 1997-1998 */ + if (here->BSIM3V2nqsMod) + { qcheq = -(qbulk + qgate); + + here->BSIM3V2cqgb = -(here->BSIM3V2cggb + here->BSIM3V2cbgb); + here->BSIM3V2cqdb = -(here->BSIM3V2cgdb + here->BSIM3V2cbdb); + here->BSIM3V2cqsb = -(here->BSIM3V2cgsb + here->BSIM3V2cbsb); + here->BSIM3V2cqbb = -(here->BSIM3V2cqgb + here->BSIM3V2cqdb + + here->BSIM3V2cqsb); + + gtau_drift = fabs(pParam->BSIM3V2tconst * qcheq) * ScalingFactor; + T0 = pParam->BSIM3V2leffCV * pParam->BSIM3V2leffCV; + gtau_diff = 16.0 * pParam->BSIM3V2u0temp * model->BSIM3V2vtm / T0 + * ScalingFactor; + here->BSIM3V2gtau = gtau_drift + gtau_diff; + } + + if (model->BSIM3V2capMod == 0) + { if (vgd < 0.0) + { + cgdo = pParam->BSIM3V2cgdo; + qgdo = pParam->BSIM3V2cgdo * vgd; + } + else + { cgdo = pParam->BSIM3V2cgdo; + qgdo = pParam->BSIM3V2cgdo * vgd; + } + + if (vgs < 0.0) + { + cgso = pParam->BSIM3V2cgso; + qgso = pParam->BSIM3V2cgso * vgs; + } + else + { cgso = pParam->BSIM3V2cgso; + qgso = pParam->BSIM3V2cgso * vgs; + } + } + else if (model->BSIM3V2capMod == 1) + { if (vgd < 0.0) + { T1 = sqrt(1.0 - 4.0 * vgd / pParam->BSIM3V2ckappa); + cgdo = pParam->BSIM3V2cgdo + pParam->BSIM3V2weffCV + * pParam->BSIM3V2cgdl / T1; + qgdo = pParam->BSIM3V2cgdo * vgd - pParam->BSIM3V2weffCV * 0.5 + * pParam->BSIM3V2cgdl * pParam->BSIM3V2ckappa * (T1 - 1.0); + } + else + { cgdo = pParam->BSIM3V2cgdo + pParam->BSIM3V2weffCV + * pParam->BSIM3V2cgdl; + qgdo = (pParam->BSIM3V2weffCV * pParam->BSIM3V2cgdl + + pParam->BSIM3V2cgdo) * vgd; + } + + if (vgs < 0.0) + { T1 = sqrt(1.0 - 4.0 * vgs / pParam->BSIM3V2ckappa); + cgso = pParam->BSIM3V2cgso + pParam->BSIM3V2weffCV + * pParam->BSIM3V2cgsl / T1; + qgso = pParam->BSIM3V2cgso * vgs - pParam->BSIM3V2weffCV * 0.5 + * pParam->BSIM3V2cgsl * pParam->BSIM3V2ckappa * (T1 - 1.0); + } + else + { cgso = pParam->BSIM3V2cgso + pParam->BSIM3V2weffCV + * pParam->BSIM3V2cgsl; + qgso = (pParam->BSIM3V2weffCV * pParam->BSIM3V2cgsl + + pParam->BSIM3V2cgso) * vgs; + } + } + else + { T0 = vgd + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + + T3 = pParam->BSIM3V2weffCV * pParam->BSIM3V2cgdl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM3V2ckappa); + cgdo = pParam->BSIM3V2cgdo + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgdo = (pParam->BSIM3V2cgdo + T3) * vgd - T3 * (T2 + + 0.5 * pParam->BSIM3V2ckappa * (T4 - 1.0)); + + T0 = vgs + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + T3 = pParam->BSIM3V2weffCV * pParam->BSIM3V2cgsl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM3V2ckappa); + cgso = pParam->BSIM3V2cgso + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgso = (pParam->BSIM3V2cgso + T3) * vgs - T3 * (T2 + + 0.5 * pParam->BSIM3V2ckappa * (T4 - 1.0)); + } + + here->BSIM3V2cgdo = cgdo; + here->BSIM3V2cgso = cgso; + + ag0 = ckt->CKTag[0]; + if (here->BSIM3V2mode > 0) + { if (here->BSIM3V2nqsMod == 0) + { gcggb = (here->BSIM3V2cggb + cgdo + cgso + + pParam->BSIM3V2cgbo ) * ag0; + gcgdb = (here->BSIM3V2cgdb - cgdo) * ag0; + gcgsb = (here->BSIM3V2cgsb - cgso) * ag0; + + gcdgb = (here->BSIM3V2cdgb - cgdo) * ag0; + gcddb = (here->BSIM3V2cddb + here->BSIM3V2capbd + cgdo) * ag0; + gcdsb = here->BSIM3V2cdsb * ag0; + + gcsgb = -(here->BSIM3V2cggb + here->BSIM3V2cbgb + + here->BSIM3V2cdgb + cgso) * ag0; + gcsdb = -(here->BSIM3V2cgdb + here->BSIM3V2cbdb + + here->BSIM3V2cddb) * ag0; + gcssb = (here->BSIM3V2capbs + cgso - (here->BSIM3V2cgsb + + here->BSIM3V2cbsb + here->BSIM3V2cdsb)) * ag0; + + gcbgb = (here->BSIM3V2cbgb - pParam->BSIM3V2cgbo) * ag0; + gcbdb = (here->BSIM3V2cbdb - here->BSIM3V2capbd) * ag0; + gcbsb = (here->BSIM3V2cbsb - here->BSIM3V2capbs) * ag0; + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3V2cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qdrn -= qgd; + qsrc = -(qgate + qbulk + qdrn); + + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + } + else + { if (qcheq > 0.0) + T0 = pParam->BSIM3V2tconst * qdef * ScalingFactor; + else + T0 = -pParam->BSIM3V2tconst * qdef * ScalingFactor; + ggtg = here->BSIM3V2gtg = T0 * here->BSIM3V2cqgb; + ggtd = here->BSIM3V2gtd = T0 * here->BSIM3V2cqdb; + ggts = here->BSIM3V2gts = T0 * here->BSIM3V2cqsb; + ggtb = here->BSIM3V2gtb = T0 * here->BSIM3V2cqbb; + gqdef = ScalingFactor * ag0; + + gcqgb = here->BSIM3V2cqgb * ag0; + gcqdb = here->BSIM3V2cqdb * ag0; + gcqsb = here->BSIM3V2cqsb * ag0; + gcqbb = here->BSIM3V2cqbb * ag0; + + gcggb = (cgdo + cgso + pParam->BSIM3V2cgbo ) * ag0; + gcgdb = -cgdo * ag0; + gcgsb = -cgso * ag0; + + gcdgb = -cgdo * ag0; + gcddb = (here->BSIM3V2capbd + cgdo) * ag0; + gcdsb = 0.0; + + gcsgb = -cgso * ag0; + gcsdb = 0.0; + gcssb = (here->BSIM3V2capbs + cgso) * ag0; + + gcbgb = -pParam->BSIM3V2cgbo * ag0; + gcbdb = -here->BSIM3V2capbd * ag0; + gcbsb = -here->BSIM3V2capbs * ag0; + + CoxWL = model->BSIM3V2cox * pParam->BSIM3V2weffCV + * pParam->BSIM3V2leffCV; + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3V2xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM3V2xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = qdrn / qcheq; + Cdd = here->BSIM3V2cddb; + Csd = -(here->BSIM3V2cgdb + here->BSIM3V2cddb + + here->BSIM3V2cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM3V2cdgb; + Csg = -(here->BSIM3V2cggb + here->BSIM3V2cdgb + + here->BSIM3V2cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM3V2cdsb; + Css = -(here->BSIM3V2cgsb + here->BSIM3V2cdsb + + here->BSIM3V2cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3V2cgbo * vgb; + qgate = qgd + qgs + qgb; + qbulk = -qgb; + qdrn = -qgd; + qsrc = -(qgate + qbulk + qdrn); + } + } + else + { if (here->BSIM3V2nqsMod == 0) + { gcggb = (here->BSIM3V2cggb + cgdo + cgso + + pParam->BSIM3V2cgbo ) * ag0; + gcgdb = (here->BSIM3V2cgsb - cgdo) * ag0; + gcgsb = (here->BSIM3V2cgdb - cgso) * ag0; + + gcdgb = -(here->BSIM3V2cggb + here->BSIM3V2cbgb + + here->BSIM3V2cdgb + cgdo) * ag0; + gcddb = (here->BSIM3V2capbd + cgdo - (here->BSIM3V2cgsb + + here->BSIM3V2cbsb + here->BSIM3V2cdsb)) * ag0; + gcdsb = -(here->BSIM3V2cgdb + here->BSIM3V2cbdb + + here->BSIM3V2cddb) * ag0; + + gcsgb = (here->BSIM3V2cdgb - cgso) * ag0; + gcsdb = here->BSIM3V2cdsb * ag0; + gcssb = (here->BSIM3V2cddb + here->BSIM3V2capbs + cgso) * ag0; + + gcbgb = (here->BSIM3V2cbgb - pParam->BSIM3V2cgbo) * ag0; + gcbdb = (here->BSIM3V2cbsb - here->BSIM3V2capbd) * ag0; + gcbsb = (here->BSIM3V2cbdb - here->BSIM3V2capbs) * ag0; + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3V2cgbo * vgb; + qgate += qgd + qgs + qgb; + qbulk -= qgb; + qsrc = qdrn - qgs; + qdrn = -(qgate + qbulk + qsrc); + + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + } + else + { if (qcheq > 0.0) + T0 = pParam->BSIM3V2tconst * qdef * ScalingFactor; + else + T0 = -pParam->BSIM3V2tconst * qdef * ScalingFactor; + ggtg = here->BSIM3V2gtg = T0 * here->BSIM3V2cqgb; + ggts = here->BSIM3V2gtd = T0 * here->BSIM3V2cqdb; + ggtd = here->BSIM3V2gts = T0 * here->BSIM3V2cqsb; + ggtb = here->BSIM3V2gtb = T0 * here->BSIM3V2cqbb; + gqdef = ScalingFactor * ag0; + + gcqgb = here->BSIM3V2cqgb * ag0; + gcqdb = here->BSIM3V2cqsb * ag0; + gcqsb = here->BSIM3V2cqdb * ag0; + gcqbb = here->BSIM3V2cqbb * ag0; + + gcggb = (cgdo + cgso + pParam->BSIM3V2cgbo) * ag0; + gcgdb = -cgdo * ag0; + gcgsb = -cgso * ag0; + + gcdgb = -cgdo * ag0; + gcddb = (here->BSIM3V2capbd + cgdo) * ag0; + gcdsb = 0.0; + + gcsgb = -cgso * ag0; + gcsdb = 0.0; + gcssb = (here->BSIM3V2capbs + cgso) * ag0; + + gcbgb = -pParam->BSIM3V2cgbo * ag0; + gcbdb = -here->BSIM3V2capbd * ag0; + gcbsb = -here->BSIM3V2capbs * ag0; + + CoxWL = model->BSIM3V2cox * pParam->BSIM3V2weffCV + * pParam->BSIM3V2leffCV; + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3V2xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM3V2xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = qdrn / qcheq; + Css = here->BSIM3V2cddb; + Cds = -(here->BSIM3V2cgdb + here->BSIM3V2cddb + + here->BSIM3V2cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM3V2cdgb; + Cdg = -(here->BSIM3V2cggb + here->BSIM3V2cdgb + + here->BSIM3V2cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM3V2cdsb; + Cdd = -(here->BSIM3V2cgsb + here->BSIM3V2cdsb + + here->BSIM3V2cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + + qgd = qgdo; + qgs = qgso; + qgb = pParam->BSIM3V2cgbo * vgb; + qgate = qgd + qgs + qgb; + qbulk = -qgb; + qsrc = -qgs; + qdrn = -(qgate + qbulk + qsrc); + } + } + + cqdef = cqcheq = 0.0; + if (ByPass) goto line860; + + *(ckt->CKTstate0 + here->BSIM3V2qg) = qgate; + *(ckt->CKTstate0 + here->BSIM3V2qd) = qdrn + - *(ckt->CKTstate0 + here->BSIM3V2qbd); + *(ckt->CKTstate0 + here->BSIM3V2qb) = qbulk + + *(ckt->CKTstate0 + here->BSIM3V2qbd) + + *(ckt->CKTstate0 + here->BSIM3V2qbs); + + if (here->BSIM3V2nqsMod) + { *(ckt->CKTstate0 + here->BSIM3V2qcdump) = qdef * ScalingFactor; + *(ckt->CKTstate0 + here->BSIM3V2qcheq) = qcheq; + } + + /* store small signal parameters */ + if (ckt->CKTmode & MODEINITSMSIG) + { goto line1000; + } + if (!ChargeComputationNeeded) + goto line850; + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM3V2qb) = + *(ckt->CKTstate0 + here->BSIM3V2qb); + *(ckt->CKTstate1 + here->BSIM3V2qg) = + *(ckt->CKTstate0 + here->BSIM3V2qg); + *(ckt->CKTstate1 + here->BSIM3V2qd) = + *(ckt->CKTstate0 + here->BSIM3V2qd); + if (here->BSIM3V2nqsMod) + { *(ckt->CKTstate1 + here->BSIM3V2qcheq) = + *(ckt->CKTstate0 + here->BSIM3V2qcheq); + *(ckt->CKTstate1 + here->BSIM3V2qcdump) = + *(ckt->CKTstate0 + here->BSIM3V2qcdump); + } + } + + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V2qb); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V2qg); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V2qd); + if (error) + return(error); + if (here->BSIM3V2nqsMod) + { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V2qcdump); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM3V2qcheq); + if (error) + return(error); + } + + goto line860; + +line850: + /* initialize to zero charge conductance and current */ + ceqqg = ceqqb = ceqqd = 0.0; + cqcheq = cqdef = 0.0; + + gcdgb = gcddb = gcdsb = 0.0; + gcsgb = gcsdb = gcssb = 0.0; + gcggb = gcgdb = gcgsb = 0.0; + gcbgb = gcbdb = gcbsb = 0.0; + + gqdef = gcqgb = gcqdb = gcqsb = gcqbb = 0.0; + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = (1.0 - (dxpart = (here->BSIM3V2mode > 0) ? 0.4 : 0.6)); + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + + if (here->BSIM3V2nqsMod) + here->BSIM3V2gtau = 16.0 * pParam->BSIM3V2u0temp * model->BSIM3V2vtm + / pParam->BSIM3V2leffCV / pParam->BSIM3V2leffCV + * ScalingFactor; + else + here->BSIM3V2gtau = 0.0; + + goto line900; + +line860: + /* evaluate equivalent charge current */ + + cqgate = *(ckt->CKTstate0 + here->BSIM3V2cqg); + cqbulk = *(ckt->CKTstate0 + here->BSIM3V2cqb); + cqdrn = *(ckt->CKTstate0 + here->BSIM3V2cqd); + + ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; + ceqqb = cqbulk - gcbgb * vgb + gcbdb * vbd + gcbsb * vbs; + ceqqd = cqdrn - gcdgb * vgb + gcddb * vbd + gcdsb * vbs; + + if (here->BSIM3V2nqsMod) + { T0 = ggtg * vgb - ggtd * vbd - ggts * vbs; + ceqqg += T0; + T1 = qdef * here->BSIM3V2gtau; + ceqqd -= dxpart * T0 + T1 * (ddxpart_dVg * vgb - ddxpart_dVd + * vbd - ddxpart_dVs * vbs); + cqdef = *(ckt->CKTstate0 + here->BSIM3V2cqcdump) - gqdef * qdef; + cqcheq = *(ckt->CKTstate0 + here->BSIM3V2cqcheq) + - (gcqgb * vgb - gcqdb * vbd - gcqsb * vbs) + T0; + } + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM3V2cqb) = + *(ckt->CKTstate0 + here->BSIM3V2cqb); + *(ckt->CKTstate1 + here->BSIM3V2cqg) = + *(ckt->CKTstate0 + here->BSIM3V2cqg); + *(ckt->CKTstate1 + here->BSIM3V2cqd) = + *(ckt->CKTstate0 + here->BSIM3V2cqd); + + if (here->BSIM3V2nqsMod) + { *(ckt->CKTstate1 + here->BSIM3V2cqcheq) = + *(ckt->CKTstate0 + here->BSIM3V2cqcheq); + *(ckt->CKTstate1 + here->BSIM3V2cqcdump) = + *(ckt->CKTstate0 + here->BSIM3V2cqcdump); + } + } + + /* + * load current vector + */ +line900: + + if (here->BSIM3V2mode >= 0) + { Gm = here->BSIM3V2gm; + Gmbs = here->BSIM3V2gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + cdreq = model->BSIM3V2type * (cdrain - here->BSIM3V2gds * vds + - Gm * vgs - Gmbs * vbs); + + ceqbd = -model->BSIM3V2type * (here->BSIM3V2csub + - here->BSIM3V2gbds * vds - here->BSIM3V2gbgs * vgs + - here->BSIM3V2gbbs * vbs); + ceqbs = 0.0; + + gbbdp = -here->BSIM3V2gbds; + gbbsp = (here->BSIM3V2gbds + here->BSIM3V2gbgs + here->BSIM3V2gbbs); + + gbdpg = here->BSIM3V2gbgs; + gbdpdp = here->BSIM3V2gbds; + gbdpb = here->BSIM3V2gbbs; + gbdpsp = -(gbdpg + gbdpdp + gbdpb); + + gbspg = 0.0; + gbspdp = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + } + else + { Gm = -here->BSIM3V2gm; + Gmbs = -here->BSIM3V2gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + cdreq = -model->BSIM3V2type * (cdrain + here->BSIM3V2gds * vds + + Gm * vgd + Gmbs * vbd); + + ceqbs = -model->BSIM3V2type * (here->BSIM3V2csub + + here->BSIM3V2gbds * vds - here->BSIM3V2gbgs * vgd + - here->BSIM3V2gbbs * vbd); + ceqbd = 0.0; + + gbbsp = -here->BSIM3V2gbds; + gbbdp = (here->BSIM3V2gbds + here->BSIM3V2gbgs + here->BSIM3V2gbbs); + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM3V2gbgs; + gbspsp = here->BSIM3V2gbds; + gbspb = here->BSIM3V2gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + } + + if (model->BSIM3V2type > 0) + { ceqbs += (here->BSIM3V2cbs - here->BSIM3V2gbs * vbs); + ceqbd += (here->BSIM3V2cbd - here->BSIM3V2gbd * vbd); + /* + ceqqg = ceqqg; + ceqqb = ceqqb; + ceqqd = ceqqd; + cqdef = cqdef; + cqcheq = cqcheq; + */ + } + else + { ceqbs -= (here->BSIM3V2cbs - here->BSIM3V2gbs * vbs); + ceqbd -= (here->BSIM3V2cbd - here->BSIM3V2gbd * vbd); + ceqqg = -ceqqg; + ceqqb = -ceqqb; + ceqqd = -ceqqd; + cqdef = -cqdef; + cqcheq = -cqcheq; + } + + (*(ckt->CKTrhs + here->BSIM3V2gNode) -= ceqqg); + (*(ckt->CKTrhs + here->BSIM3V2bNode) -=(ceqbs + ceqbd + ceqqb)); + (*(ckt->CKTrhs + here->BSIM3V2dNodePrime) += (ceqbd - cdreq - ceqqd)); + (*(ckt->CKTrhs + here->BSIM3V2sNodePrime) += (cdreq + ceqbs + ceqqg + + ceqqb + ceqqd)); + if (here->BSIM3V2nqsMod) + *(ckt->CKTrhs + here->BSIM3V2qNode) += (cqcheq - cqdef); + + /* + * load y matrix + */ + + T1 = qdef * here->BSIM3V2gtau; + (*(here->BSIM3V2DdPtr) += here->BSIM3V2drainConductance); + (*(here->BSIM3V2GgPtr) += gcggb - ggtg); + (*(here->BSIM3V2SsPtr) += here->BSIM3V2sourceConductance); + (*(here->BSIM3V2BbPtr) += here->BSIM3V2gbd + here->BSIM3V2gbs + - gcbgb - gcbdb - gcbsb - here->BSIM3V2gbbs); + (*(here->BSIM3V2DPdpPtr) += here->BSIM3V2drainConductance + + here->BSIM3V2gds + here->BSIM3V2gbd + + RevSum + gcddb + dxpart * ggtd + + T1 * ddxpart_dVd + gbdpdp); + (*(here->BSIM3V2SPspPtr) += here->BSIM3V2sourceConductance + + here->BSIM3V2gds + here->BSIM3V2gbs + + FwdSum + gcssb + sxpart * ggts + + T1 * dsxpart_dVs + gbspsp); + (*(here->BSIM3V2DdpPtr) -= here->BSIM3V2drainConductance); + (*(here->BSIM3V2GbPtr) -= gcggb + gcgdb + gcgsb + ggtb); + (*(here->BSIM3V2GdpPtr) += gcgdb - ggtd); + (*(here->BSIM3V2GspPtr) += gcgsb - ggts); + (*(here->BSIM3V2SspPtr) -= here->BSIM3V2sourceConductance); + (*(here->BSIM3V2BgPtr) += gcbgb - here->BSIM3V2gbgs); + (*(here->BSIM3V2BdpPtr) += gcbdb - here->BSIM3V2gbd + gbbdp); + (*(here->BSIM3V2BspPtr) += gcbsb - here->BSIM3V2gbs + gbbsp); + (*(here->BSIM3V2DPdPtr) -= here->BSIM3V2drainConductance); + (*(here->BSIM3V2DPgPtr) += Gm + gcdgb + dxpart * ggtg + + T1 * ddxpart_dVg + gbdpg); + (*(here->BSIM3V2DPbPtr) -= here->BSIM3V2gbd - Gmbs + gcdgb + gcddb + + gcdsb - dxpart * ggtb + - T1 * ddxpart_dVb - gbdpb); + (*(here->BSIM3V2DPspPtr) -= here->BSIM3V2gds + FwdSum - gcdsb + - dxpart * ggts - T1 * ddxpart_dVs - gbdpsp); + (*(here->BSIM3V2SPgPtr) += gcsgb - Gm + sxpart * ggtg + + T1 * dsxpart_dVg + gbspg); + (*(here->BSIM3V2SPsPtr) -= here->BSIM3V2sourceConductance); + (*(here->BSIM3V2SPbPtr) -= here->BSIM3V2gbs + Gmbs + gcsgb + gcsdb + + gcssb - sxpart * ggtb + - T1 * dsxpart_dVb - gbspb); + (*(here->BSIM3V2SPdpPtr) -= here->BSIM3V2gds + RevSum - gcsdb + - sxpart * ggtd - T1 * dsxpart_dVd - gbspdp); + + if (here->BSIM3V2nqsMod) + { *(here->BSIM3V2QqPtr) += (gqdef + here->BSIM3V2gtau); + + *(here->BSIM3V2DPqPtr) += (dxpart * here->BSIM3V2gtau); + *(here->BSIM3V2SPqPtr) += (sxpart * here->BSIM3V2gtau); + *(here->BSIM3V2GqPtr) -= here->BSIM3V2gtau; + + *(here->BSIM3V2QgPtr) += (ggtg - gcqgb); + *(here->BSIM3V2QdpPtr) += (ggtd - gcqdb); + *(here->BSIM3V2QspPtr) += (ggts - gcqsb); + *(here->BSIM3V2QbPtr) += (ggtb - gcqbb); + } + +line1000: ; + + } /* End of Mosfet Instance */ +} /* End of Model Instance */ + +return(OK); +} + diff --git a/src/spicelib/devices/bsim3v2/b3v2mask.c b/src/spicelib/devices/bsim3v2/b3v2mask.c new file mode 100644 index 000000000..e5366c337 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2mask.c @@ -0,0 +1,1253 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: b3v2mask.c +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim3v2def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V2mAsk(ckt,inst,which,value) +CKTcircuit *ckt; +GENmodel *inst; +int which; +IFvalue *value; +{ + BSIM3V2model *model = (BSIM3V2model *)inst; + switch(which) + { case BSIM3V2_MOD_MOBMOD: + value->iValue = model->BSIM3V2mobMod; + return(OK); + case BSIM3V2_MOD_PARAMCHK: + value->iValue = model->BSIM3V2paramChk; + return(OK); + case BSIM3V2_MOD_BINUNIT: + value->iValue = model->BSIM3V2binUnit; + return(OK); + case BSIM3V2_MOD_CAPMOD: + value->iValue = model->BSIM3V2capMod; + return(OK); + case BSIM3V2_MOD_NOIMOD: + value->iValue = model->BSIM3V2noiMod; + return(OK); + case BSIM3V2_MOD_VERSION : + value->rValue = model->BSIM3V2version; + return(OK); + case BSIM3V2_MOD_TOX : + value->rValue = model->BSIM3V2tox; + return(OK); + case BSIM3V2_MOD_TOXM : + value->rValue = model->BSIM3V2toxm; + return(OK); + case BSIM3V2_MOD_CDSC : + value->rValue = model->BSIM3V2cdsc; + return(OK); + case BSIM3V2_MOD_CDSCB : + value->rValue = model->BSIM3V2cdscb; + return(OK); + + case BSIM3V2_MOD_CDSCD : + value->rValue = model->BSIM3V2cdscd; + return(OK); + + case BSIM3V2_MOD_CIT : + value->rValue = model->BSIM3V2cit; + return(OK); + case BSIM3V2_MOD_NFACTOR : + value->rValue = model->BSIM3V2nfactor; + return(OK); + case BSIM3V2_MOD_XJ: + value->rValue = model->BSIM3V2xj; + return(OK); + case BSIM3V2_MOD_VSAT: + value->rValue = model->BSIM3V2vsat; + return(OK); + case BSIM3V2_MOD_AT: + value->rValue = model->BSIM3V2at; + return(OK); + case BSIM3V2_MOD_A0: + value->rValue = model->BSIM3V2a0; + return(OK); + + case BSIM3V2_MOD_AGS: + value->rValue = model->BSIM3V2ags; + return(OK); + + case BSIM3V2_MOD_A1: + value->rValue = model->BSIM3V2a1; + return(OK); + case BSIM3V2_MOD_A2: + value->rValue = model->BSIM3V2a2; + return(OK); + case BSIM3V2_MOD_KETA: + value->rValue = model->BSIM3V2keta; + return(OK); + case BSIM3V2_MOD_NSUB: + value->rValue = model->BSIM3V2nsub; + return(OK); + case BSIM3V2_MOD_NPEAK: + value->rValue = model->BSIM3V2npeak; + return(OK); + case BSIM3V2_MOD_NGATE: + value->rValue = model->BSIM3V2ngate; + return(OK); + case BSIM3V2_MOD_GAMMA1: + value->rValue = model->BSIM3V2gamma1; + return(OK); + case BSIM3V2_MOD_GAMMA2: + value->rValue = model->BSIM3V2gamma2; + return(OK); + case BSIM3V2_MOD_VBX: + value->rValue = model->BSIM3V2vbx; + return(OK); + case BSIM3V2_MOD_VBM: + value->rValue = model->BSIM3V2vbm; + return(OK); + case BSIM3V2_MOD_XT: + value->rValue = model->BSIM3V2xt; + return(OK); + case BSIM3V2_MOD_K1: + value->rValue = model->BSIM3V2k1; + return(OK); + case BSIM3V2_MOD_KT1: + value->rValue = model->BSIM3V2kt1; + return(OK); + case BSIM3V2_MOD_KT1L: + value->rValue = model->BSIM3V2kt1l; + return(OK); + case BSIM3V2_MOD_KT2 : + value->rValue = model->BSIM3V2kt2; + return(OK); + case BSIM3V2_MOD_K2 : + value->rValue = model->BSIM3V2k2; + return(OK); + case BSIM3V2_MOD_K3: + value->rValue = model->BSIM3V2k3; + return(OK); + case BSIM3V2_MOD_K3B: + value->rValue = model->BSIM3V2k3b; + return(OK); + case BSIM3V2_MOD_W0: + value->rValue = model->BSIM3V2w0; + return(OK); + case BSIM3V2_MOD_NLX: + value->rValue = model->BSIM3V2nlx; + return(OK); + case BSIM3V2_MOD_DVT0 : + value->rValue = model->BSIM3V2dvt0; + return(OK); + case BSIM3V2_MOD_DVT1 : + value->rValue = model->BSIM3V2dvt1; + return(OK); + case BSIM3V2_MOD_DVT2 : + value->rValue = model->BSIM3V2dvt2; + return(OK); + case BSIM3V2_MOD_DVT0W : + value->rValue = model->BSIM3V2dvt0w; + return(OK); + case BSIM3V2_MOD_DVT1W : + value->rValue = model->BSIM3V2dvt1w; + return(OK); + case BSIM3V2_MOD_DVT2W : + value->rValue = model->BSIM3V2dvt2w; + return(OK); + case BSIM3V2_MOD_DROUT : + value->rValue = model->BSIM3V2drout; + return(OK); + case BSIM3V2_MOD_DSUB : + value->rValue = model->BSIM3V2dsub; + return(OK); + case BSIM3V2_MOD_VTH0: + value->rValue = model->BSIM3V2vth0; + return(OK); + case BSIM3V2_MOD_UA: + value->rValue = model->BSIM3V2ua; + return(OK); + case BSIM3V2_MOD_UA1: + value->rValue = model->BSIM3V2ua1; + return(OK); + case BSIM3V2_MOD_UB: + value->rValue = model->BSIM3V2ub; + return(OK); + case BSIM3V2_MOD_UB1: + value->rValue = model->BSIM3V2ub1; + return(OK); + case BSIM3V2_MOD_UC: + value->rValue = model->BSIM3V2uc; + return(OK); + case BSIM3V2_MOD_UC1: + value->rValue = model->BSIM3V2uc1; + return(OK); + case BSIM3V2_MOD_U0: + value->rValue = model->BSIM3V2u0; + return(OK); + case BSIM3V2_MOD_UTE: + value->rValue = model->BSIM3V2ute; + return(OK); + case BSIM3V2_MOD_VOFF: + value->rValue = model->BSIM3V2voff; + return(OK); + case BSIM3V2_MOD_DELTA: + value->rValue = model->BSIM3V2delta; + return(OK); + case BSIM3V2_MOD_RDSW: + value->rValue = model->BSIM3V2rdsw; + return(OK); + case BSIM3V2_MOD_PRWG: + value->rValue = model->BSIM3V2prwg; + return(OK); + case BSIM3V2_MOD_PRWB: + value->rValue = model->BSIM3V2prwb; + return(OK); + case BSIM3V2_MOD_PRT: + value->rValue = model->BSIM3V2prt; + return(OK); + case BSIM3V2_MOD_ETA0: + value->rValue = model->BSIM3V2eta0; + return(OK); + case BSIM3V2_MOD_ETAB: + value->rValue = model->BSIM3V2etab; + return(OK); + case BSIM3V2_MOD_PCLM: + value->rValue = model->BSIM3V2pclm; + return(OK); + case BSIM3V2_MOD_PDIBL1: + value->rValue = model->BSIM3V2pdibl1; + return(OK); + case BSIM3V2_MOD_PDIBL2: + value->rValue = model->BSIM3V2pdibl2; + return(OK); + case BSIM3V2_MOD_PDIBLB: + value->rValue = model->BSIM3V2pdiblb; + return(OK); + case BSIM3V2_MOD_PSCBE1: + value->rValue = model->BSIM3V2pscbe1; + return(OK); + case BSIM3V2_MOD_PSCBE2: + value->rValue = model->BSIM3V2pscbe2; + return(OK); + case BSIM3V2_MOD_PVAG: + value->rValue = model->BSIM3V2pvag; + return(OK); + case BSIM3V2_MOD_WR: + value->rValue = model->BSIM3V2wr; + return(OK); + case BSIM3V2_MOD_DWG: + value->rValue = model->BSIM3V2dwg; + return(OK); + case BSIM3V2_MOD_DWB: + value->rValue = model->BSIM3V2dwb; + return(OK); + case BSIM3V2_MOD_B0: + value->rValue = model->BSIM3V2b0; + return(OK); + case BSIM3V2_MOD_B1: + value->rValue = model->BSIM3V2b1; + return(OK); + case BSIM3V2_MOD_ALPHA0: + value->rValue = model->BSIM3V2alpha0; + return(OK); + case BSIM3V2_MOD_ALPHA1: + value->rValue = model->BSIM3V2alpha1; + return(OK); + case BSIM3V2_MOD_BETA0: + value->rValue = model->BSIM3V2beta0; + return(OK); + case BSIM3V2_MOD_IJTH: + value->rValue = model->BSIM3V2ijth; + return(OK); + case BSIM3V2_MOD_VFB: + value->rValue = model->BSIM3V2vfb; + return(OK); + + case BSIM3V2_MOD_ELM: + value->rValue = model->BSIM3V2elm; + return(OK); + case BSIM3V2_MOD_CGSL: + value->rValue = model->BSIM3V2cgsl; + return(OK); + case BSIM3V2_MOD_CGDL: + value->rValue = model->BSIM3V2cgdl; + return(OK); + case BSIM3V2_MOD_CKAPPA: + value->rValue = model->BSIM3V2ckappa; + return(OK); + case BSIM3V2_MOD_CF: + value->rValue = model->BSIM3V2cf; + return(OK); + case BSIM3V2_MOD_CLC: + value->rValue = model->BSIM3V2clc; + return(OK); + case BSIM3V2_MOD_CLE: + value->rValue = model->BSIM3V2cle; + return(OK); + case BSIM3V2_MOD_DWC: + value->rValue = model->BSIM3V2dwc; + return(OK); + case BSIM3V2_MOD_DLC: + value->rValue = model->BSIM3V2dlc; + return(OK); + case BSIM3V2_MOD_VFBCV: + value->rValue = model->BSIM3V2vfbcv; + return(OK); + case BSIM3V2_MOD_ACDE: + value->rValue = model->BSIM3V2acde; + return(OK); + case BSIM3V2_MOD_MOIN: + value->rValue = model->BSIM3V2moin; + return(OK); + case BSIM3V2_MOD_NOFF: + value->rValue = model->BSIM3V2noff; + return(OK); + case BSIM3V2_MOD_VOFFCV: + value->rValue = model->BSIM3V2voffcv; + return(OK); + case BSIM3V2_MOD_TCJ: + value->rValue = model->BSIM3V2tcj; + return(OK); + case BSIM3V2_MOD_TPB: + value->rValue = model->BSIM3V2tpb; + return(OK); + case BSIM3V2_MOD_TCJSW: + value->rValue = model->BSIM3V2tcjsw; + return(OK); + case BSIM3V2_MOD_TPBSW: + value->rValue = model->BSIM3V2tpbsw; + return(OK); + case BSIM3V2_MOD_TCJSWG: + value->rValue = model->BSIM3V2tcjswg; + return(OK); + case BSIM3V2_MOD_TPBSWG: + value->rValue = model->BSIM3V2tpbswg; + return(OK); + + /* Length dependence */ + case BSIM3V2_MOD_LCDSC : + value->rValue = model->BSIM3V2lcdsc; + return(OK); + case BSIM3V2_MOD_LCDSCB : + value->rValue = model->BSIM3V2lcdscb; + return(OK); + case BSIM3V2_MOD_LCDSCD : + value->rValue = model->BSIM3V2lcdscd; + return(OK); + case BSIM3V2_MOD_LCIT : + value->rValue = model->BSIM3V2lcit; + return(OK); + case BSIM3V2_MOD_LNFACTOR : + value->rValue = model->BSIM3V2lnfactor; + return(OK); + case BSIM3V2_MOD_LXJ: + value->rValue = model->BSIM3V2lxj; + return(OK); + case BSIM3V2_MOD_LVSAT: + value->rValue = model->BSIM3V2lvsat; + return(OK); + case BSIM3V2_MOD_LAT: + value->rValue = model->BSIM3V2lat; + return(OK); + case BSIM3V2_MOD_LA0: + value->rValue = model->BSIM3V2la0; + return(OK); + case BSIM3V2_MOD_LAGS: + value->rValue = model->BSIM3V2lags; + return(OK); + case BSIM3V2_MOD_LA1: + value->rValue = model->BSIM3V2la1; + return(OK); + case BSIM3V2_MOD_LA2: + value->rValue = model->BSIM3V2la2; + return(OK); + case BSIM3V2_MOD_LKETA: + value->rValue = model->BSIM3V2lketa; + return(OK); + case BSIM3V2_MOD_LNSUB: + value->rValue = model->BSIM3V2lnsub; + return(OK); + case BSIM3V2_MOD_LNPEAK: + value->rValue = model->BSIM3V2lnpeak; + return(OK); + case BSIM3V2_MOD_LNGATE: + value->rValue = model->BSIM3V2lngate; + return(OK); + case BSIM3V2_MOD_LGAMMA1: + value->rValue = model->BSIM3V2lgamma1; + return(OK); + case BSIM3V2_MOD_LGAMMA2: + value->rValue = model->BSIM3V2lgamma2; + return(OK); + case BSIM3V2_MOD_LVBX: + value->rValue = model->BSIM3V2lvbx; + return(OK); + case BSIM3V2_MOD_LVBM: + value->rValue = model->BSIM3V2lvbm; + return(OK); + case BSIM3V2_MOD_LXT: + value->rValue = model->BSIM3V2lxt; + return(OK); + case BSIM3V2_MOD_LK1: + value->rValue = model->BSIM3V2lk1; + return(OK); + case BSIM3V2_MOD_LKT1: + value->rValue = model->BSIM3V2lkt1; + return(OK); + case BSIM3V2_MOD_LKT1L: + value->rValue = model->BSIM3V2lkt1l; + return(OK); + case BSIM3V2_MOD_LKT2 : + value->rValue = model->BSIM3V2lkt2; + return(OK); + case BSIM3V2_MOD_LK2 : + value->rValue = model->BSIM3V2lk2; + return(OK); + case BSIM3V2_MOD_LK3: + value->rValue = model->BSIM3V2lk3; + return(OK); + case BSIM3V2_MOD_LK3B: + value->rValue = model->BSIM3V2lk3b; + return(OK); + case BSIM3V2_MOD_LW0: + value->rValue = model->BSIM3V2lw0; + return(OK); + case BSIM3V2_MOD_LNLX: + value->rValue = model->BSIM3V2lnlx; + return(OK); + case BSIM3V2_MOD_LDVT0: + value->rValue = model->BSIM3V2ldvt0; + return(OK); + case BSIM3V2_MOD_LDVT1 : + value->rValue = model->BSIM3V2ldvt1; + return(OK); + case BSIM3V2_MOD_LDVT2 : + value->rValue = model->BSIM3V2ldvt2; + return(OK); + case BSIM3V2_MOD_LDVT0W : + value->rValue = model->BSIM3V2ldvt0w; + return(OK); + case BSIM3V2_MOD_LDVT1W : + value->rValue = model->BSIM3V2ldvt1w; + return(OK); + case BSIM3V2_MOD_LDVT2W : + value->rValue = model->BSIM3V2ldvt2w; + return(OK); + case BSIM3V2_MOD_LDROUT : + value->rValue = model->BSIM3V2ldrout; + return(OK); + case BSIM3V2_MOD_LDSUB : + value->rValue = model->BSIM3V2ldsub; + return(OK); + case BSIM3V2_MOD_LVTH0: + value->rValue = model->BSIM3V2lvth0; + return(OK); + case BSIM3V2_MOD_LUA: + value->rValue = model->BSIM3V2lua; + return(OK); + case BSIM3V2_MOD_LUA1: + value->rValue = model->BSIM3V2lua1; + return(OK); + case BSIM3V2_MOD_LUB: + value->rValue = model->BSIM3V2lub; + return(OK); + case BSIM3V2_MOD_LUB1: + value->rValue = model->BSIM3V2lub1; + return(OK); + case BSIM3V2_MOD_LUC: + value->rValue = model->BSIM3V2luc; + return(OK); + case BSIM3V2_MOD_LUC1: + value->rValue = model->BSIM3V2luc1; + return(OK); + case BSIM3V2_MOD_LU0: + value->rValue = model->BSIM3V2lu0; + return(OK); + case BSIM3V2_MOD_LUTE: + value->rValue = model->BSIM3V2lute; + return(OK); + case BSIM3V2_MOD_LVOFF: + value->rValue = model->BSIM3V2lvoff; + return(OK); + case BSIM3V2_MOD_LDELTA: + value->rValue = model->BSIM3V2ldelta; + return(OK); + case BSIM3V2_MOD_LRDSW: + value->rValue = model->BSIM3V2lrdsw; + return(OK); + case BSIM3V2_MOD_LPRWB: + value->rValue = model->BSIM3V2lprwb; + return(OK); + case BSIM3V2_MOD_LPRWG: + value->rValue = model->BSIM3V2lprwg; + return(OK); + case BSIM3V2_MOD_LPRT: + value->rValue = model->BSIM3V2lprt; + return(OK); + case BSIM3V2_MOD_LETA0: + value->rValue = model->BSIM3V2leta0; + return(OK); + case BSIM3V2_MOD_LETAB: + value->rValue = model->BSIM3V2letab; + return(OK); + case BSIM3V2_MOD_LPCLM: + value->rValue = model->BSIM3V2lpclm; + return(OK); + case BSIM3V2_MOD_LPDIBL1: + value->rValue = model->BSIM3V2lpdibl1; + return(OK); + case BSIM3V2_MOD_LPDIBL2: + value->rValue = model->BSIM3V2lpdibl2; + return(OK); + case BSIM3V2_MOD_LPDIBLB: + value->rValue = model->BSIM3V2lpdiblb; + return(OK); + case BSIM3V2_MOD_LPSCBE1: + value->rValue = model->BSIM3V2lpscbe1; + return(OK); + case BSIM3V2_MOD_LPSCBE2: + value->rValue = model->BSIM3V2lpscbe2; + return(OK); + case BSIM3V2_MOD_LPVAG: + value->rValue = model->BSIM3V2lpvag; + return(OK); + case BSIM3V2_MOD_LWR: + value->rValue = model->BSIM3V2lwr; + return(OK); + case BSIM3V2_MOD_LDWG: + value->rValue = model->BSIM3V2ldwg; + return(OK); + case BSIM3V2_MOD_LDWB: + value->rValue = model->BSIM3V2ldwb; + return(OK); + case BSIM3V2_MOD_LB0: + value->rValue = model->BSIM3V2lb0; + return(OK); + case BSIM3V2_MOD_LB1: + value->rValue = model->BSIM3V2lb1; + return(OK); + case BSIM3V2_MOD_LALPHA0: + value->rValue = model->BSIM3V2lalpha0; + return(OK); + case BSIM3V2_MOD_LALPHA1: + value->rValue = model->BSIM3V2lalpha1; + return(OK); + case BSIM3V2_MOD_LBETA0: + value->rValue = model->BSIM3V2lbeta0; + return(OK); + case BSIM3V2_MOD_LVFB: + value->rValue = model->BSIM3V2lvfb; + return(OK); + + case BSIM3V2_MOD_LELM: + value->rValue = model->BSIM3V2lelm; + return(OK); + case BSIM3V2_MOD_LCGSL: + value->rValue = model->BSIM3V2lcgsl; + return(OK); + case BSIM3V2_MOD_LCGDL: + value->rValue = model->BSIM3V2lcgdl; + return(OK); + case BSIM3V2_MOD_LCKAPPA: + value->rValue = model->BSIM3V2lckappa; + return(OK); + case BSIM3V2_MOD_LCF: + value->rValue = model->BSIM3V2lcf; + return(OK); + case BSIM3V2_MOD_LCLC: + value->rValue = model->BSIM3V2lclc; + return(OK); + case BSIM3V2_MOD_LCLE: + value->rValue = model->BSIM3V2lcle; + return(OK); + case BSIM3V2_MOD_LVFBCV: + value->rValue = model->BSIM3V2lvfbcv; + return(OK); + case BSIM3V2_MOD_LACDE: + value->rValue = model->BSIM3V2lacde; + return(OK); + case BSIM3V2_MOD_LMOIN: + value->rValue = model->BSIM3V2lmoin; + return(OK); + case BSIM3V2_MOD_LNOFF: + value->rValue = model->BSIM3V2lnoff; + return(OK); + case BSIM3V2_MOD_LVOFFCV: + value->rValue = model->BSIM3V2lvoffcv; + return(OK); + + /* Width dependence */ + case BSIM3V2_MOD_WCDSC : + value->rValue = model->BSIM3V2wcdsc; + return(OK); + case BSIM3V2_MOD_WCDSCB : + value->rValue = model->BSIM3V2wcdscb; + return(OK); + case BSIM3V2_MOD_WCDSCD : + value->rValue = model->BSIM3V2wcdscd; + return(OK); + case BSIM3V2_MOD_WCIT : + value->rValue = model->BSIM3V2wcit; + return(OK); + case BSIM3V2_MOD_WNFACTOR : + value->rValue = model->BSIM3V2wnfactor; + return(OK); + case BSIM3V2_MOD_WXJ: + value->rValue = model->BSIM3V2wxj; + return(OK); + case BSIM3V2_MOD_WVSAT: + value->rValue = model->BSIM3V2wvsat; + return(OK); + case BSIM3V2_MOD_WAT: + value->rValue = model->BSIM3V2wat; + return(OK); + case BSIM3V2_MOD_WA0: + value->rValue = model->BSIM3V2wa0; + return(OK); + case BSIM3V2_MOD_WAGS: + value->rValue = model->BSIM3V2wags; + return(OK); + case BSIM3V2_MOD_WA1: + value->rValue = model->BSIM3V2wa1; + return(OK); + case BSIM3V2_MOD_WA2: + value->rValue = model->BSIM3V2wa2; + return(OK); + case BSIM3V2_MOD_WKETA: + value->rValue = model->BSIM3V2wketa; + return(OK); + case BSIM3V2_MOD_WNSUB: + value->rValue = model->BSIM3V2wnsub; + return(OK); + case BSIM3V2_MOD_WNPEAK: + value->rValue = model->BSIM3V2wnpeak; + return(OK); + case BSIM3V2_MOD_WNGATE: + value->rValue = model->BSIM3V2wngate; + return(OK); + case BSIM3V2_MOD_WGAMMA1: + value->rValue = model->BSIM3V2wgamma1; + return(OK); + case BSIM3V2_MOD_WGAMMA2: + value->rValue = model->BSIM3V2wgamma2; + return(OK); + case BSIM3V2_MOD_WVBX: + value->rValue = model->BSIM3V2wvbx; + return(OK); + case BSIM3V2_MOD_WVBM: + value->rValue = model->BSIM3V2wvbm; + return(OK); + case BSIM3V2_MOD_WXT: + value->rValue = model->BSIM3V2wxt; + return(OK); + case BSIM3V2_MOD_WK1: + value->rValue = model->BSIM3V2wk1; + return(OK); + case BSIM3V2_MOD_WKT1: + value->rValue = model->BSIM3V2wkt1; + return(OK); + case BSIM3V2_MOD_WKT1L: + value->rValue = model->BSIM3V2wkt1l; + return(OK); + case BSIM3V2_MOD_WKT2 : + value->rValue = model->BSIM3V2wkt2; + return(OK); + case BSIM3V2_MOD_WK2 : + value->rValue = model->BSIM3V2wk2; + return(OK); + case BSIM3V2_MOD_WK3: + value->rValue = model->BSIM3V2wk3; + return(OK); + case BSIM3V2_MOD_WK3B: + value->rValue = model->BSIM3V2wk3b; + return(OK); + case BSIM3V2_MOD_WW0: + value->rValue = model->BSIM3V2ww0; + return(OK); + case BSIM3V2_MOD_WNLX: + value->rValue = model->BSIM3V2wnlx; + return(OK); + case BSIM3V2_MOD_WDVT0: + value->rValue = model->BSIM3V2wdvt0; + return(OK); + case BSIM3V2_MOD_WDVT1 : + value->rValue = model->BSIM3V2wdvt1; + return(OK); + case BSIM3V2_MOD_WDVT2 : + value->rValue = model->BSIM3V2wdvt2; + return(OK); + case BSIM3V2_MOD_WDVT0W : + value->rValue = model->BSIM3V2wdvt0w; + return(OK); + case BSIM3V2_MOD_WDVT1W : + value->rValue = model->BSIM3V2wdvt1w; + return(OK); + case BSIM3V2_MOD_WDVT2W : + value->rValue = model->BSIM3V2wdvt2w; + return(OK); + case BSIM3V2_MOD_WDROUT : + value->rValue = model->BSIM3V2wdrout; + return(OK); + case BSIM3V2_MOD_WDSUB : + value->rValue = model->BSIM3V2wdsub; + return(OK); + case BSIM3V2_MOD_WVTH0: + value->rValue = model->BSIM3V2wvth0; + return(OK); + case BSIM3V2_MOD_WUA: + value->rValue = model->BSIM3V2wua; + return(OK); + case BSIM3V2_MOD_WUA1: + value->rValue = model->BSIM3V2wua1; + return(OK); + case BSIM3V2_MOD_WUB: + value->rValue = model->BSIM3V2wub; + return(OK); + case BSIM3V2_MOD_WUB1: + value->rValue = model->BSIM3V2wub1; + return(OK); + case BSIM3V2_MOD_WUC: + value->rValue = model->BSIM3V2wuc; + return(OK); + case BSIM3V2_MOD_WUC1: + value->rValue = model->BSIM3V2wuc1; + return(OK); + case BSIM3V2_MOD_WU0: + value->rValue = model->BSIM3V2wu0; + return(OK); + case BSIM3V2_MOD_WUTE: + value->rValue = model->BSIM3V2wute; + return(OK); + case BSIM3V2_MOD_WVOFF: + value->rValue = model->BSIM3V2wvoff; + return(OK); + case BSIM3V2_MOD_WDELTA: + value->rValue = model->BSIM3V2wdelta; + return(OK); + case BSIM3V2_MOD_WRDSW: + value->rValue = model->BSIM3V2wrdsw; + return(OK); + case BSIM3V2_MOD_WPRWB: + value->rValue = model->BSIM3V2wprwb; + return(OK); + case BSIM3V2_MOD_WPRWG: + value->rValue = model->BSIM3V2wprwg; + return(OK); + case BSIM3V2_MOD_WPRT: + value->rValue = model->BSIM3V2wprt; + return(OK); + case BSIM3V2_MOD_WETA0: + value->rValue = model->BSIM3V2weta0; + return(OK); + case BSIM3V2_MOD_WETAB: + value->rValue = model->BSIM3V2wetab; + return(OK); + case BSIM3V2_MOD_WPCLM: + value->rValue = model->BSIM3V2wpclm; + return(OK); + case BSIM3V2_MOD_WPDIBL1: + value->rValue = model->BSIM3V2wpdibl1; + return(OK); + case BSIM3V2_MOD_WPDIBL2: + value->rValue = model->BSIM3V2wpdibl2; + return(OK); + case BSIM3V2_MOD_WPDIBLB: + value->rValue = model->BSIM3V2wpdiblb; + return(OK); + case BSIM3V2_MOD_WPSCBE1: + value->rValue = model->BSIM3V2wpscbe1; + return(OK); + case BSIM3V2_MOD_WPSCBE2: + value->rValue = model->BSIM3V2wpscbe2; + return(OK); + case BSIM3V2_MOD_WPVAG: + value->rValue = model->BSIM3V2wpvag; + return(OK); + case BSIM3V2_MOD_WWR: + value->rValue = model->BSIM3V2wwr; + return(OK); + case BSIM3V2_MOD_WDWG: + value->rValue = model->BSIM3V2wdwg; + return(OK); + case BSIM3V2_MOD_WDWB: + value->rValue = model->BSIM3V2wdwb; + return(OK); + case BSIM3V2_MOD_WB0: + value->rValue = model->BSIM3V2wb0; + return(OK); + case BSIM3V2_MOD_WB1: + value->rValue = model->BSIM3V2wb1; + return(OK); + case BSIM3V2_MOD_WALPHA0: + value->rValue = model->BSIM3V2walpha0; + return(OK); + case BSIM3V2_MOD_WALPHA1: + value->rValue = model->BSIM3V2walpha1; + return(OK); + case BSIM3V2_MOD_WBETA0: + value->rValue = model->BSIM3V2wbeta0; + return(OK); + case BSIM3V2_MOD_WVFB: + value->rValue = model->BSIM3V2wvfb; + return(OK); + + case BSIM3V2_MOD_WELM: + value->rValue = model->BSIM3V2welm; + return(OK); + case BSIM3V2_MOD_WCGSL: + value->rValue = model->BSIM3V2wcgsl; + return(OK); + case BSIM3V2_MOD_WCGDL: + value->rValue = model->BSIM3V2wcgdl; + return(OK); + case BSIM3V2_MOD_WCKAPPA: + value->rValue = model->BSIM3V2wckappa; + return(OK); + case BSIM3V2_MOD_WCF: + value->rValue = model->BSIM3V2wcf; + return(OK); + case BSIM3V2_MOD_WCLC: + value->rValue = model->BSIM3V2wclc; + return(OK); + case BSIM3V2_MOD_WCLE: + value->rValue = model->BSIM3V2wcle; + return(OK); + case BSIM3V2_MOD_WVFBCV: + value->rValue = model->BSIM3V2wvfbcv; + return(OK); + case BSIM3V2_MOD_WACDE: + value->rValue = model->BSIM3V2wacde; + return(OK); + case BSIM3V2_MOD_WMOIN: + value->rValue = model->BSIM3V2wmoin; + return(OK); + case BSIM3V2_MOD_WNOFF: + value->rValue = model->BSIM3V2wnoff; + return(OK); + case BSIM3V2_MOD_WVOFFCV: + value->rValue = model->BSIM3V2wvoffcv; + return(OK); + + /* Cross-term dependence */ + case BSIM3V2_MOD_PCDSC : + value->rValue = model->BSIM3V2pcdsc; + return(OK); + case BSIM3V2_MOD_PCDSCB : + value->rValue = model->BSIM3V2pcdscb; + return(OK); + case BSIM3V2_MOD_PCDSCD : + value->rValue = model->BSIM3V2pcdscd; + return(OK); + case BSIM3V2_MOD_PCIT : + value->rValue = model->BSIM3V2pcit; + return(OK); + case BSIM3V2_MOD_PNFACTOR : + value->rValue = model->BSIM3V2pnfactor; + return(OK); + case BSIM3V2_MOD_PXJ: + value->rValue = model->BSIM3V2pxj; + return(OK); + case BSIM3V2_MOD_PVSAT: + value->rValue = model->BSIM3V2pvsat; + return(OK); + case BSIM3V2_MOD_PAT: + value->rValue = model->BSIM3V2pat; + return(OK); + case BSIM3V2_MOD_PA0: + value->rValue = model->BSIM3V2pa0; + return(OK); + case BSIM3V2_MOD_PAGS: + value->rValue = model->BSIM3V2pags; + return(OK); + case BSIM3V2_MOD_PA1: + value->rValue = model->BSIM3V2pa1; + return(OK); + case BSIM3V2_MOD_PA2: + value->rValue = model->BSIM3V2pa2; + return(OK); + case BSIM3V2_MOD_PKETA: + value->rValue = model->BSIM3V2pketa; + return(OK); + case BSIM3V2_MOD_PNSUB: + value->rValue = model->BSIM3V2pnsub; + return(OK); + case BSIM3V2_MOD_PNPEAK: + value->rValue = model->BSIM3V2pnpeak; + return(OK); + case BSIM3V2_MOD_PNGATE: + value->rValue = model->BSIM3V2pngate; + return(OK); + case BSIM3V2_MOD_PGAMMA1: + value->rValue = model->BSIM3V2pgamma1; + return(OK); + case BSIM3V2_MOD_PGAMMA2: + value->rValue = model->BSIM3V2pgamma2; + return(OK); + case BSIM3V2_MOD_PVBX: + value->rValue = model->BSIM3V2pvbx; + return(OK); + case BSIM3V2_MOD_PVBM: + value->rValue = model->BSIM3V2pvbm; + return(OK); + case BSIM3V2_MOD_PXT: + value->rValue = model->BSIM3V2pxt; + return(OK); + case BSIM3V2_MOD_PK1: + value->rValue = model->BSIM3V2pk1; + return(OK); + case BSIM3V2_MOD_PKT1: + value->rValue = model->BSIM3V2pkt1; + return(OK); + case BSIM3V2_MOD_PKT1L: + value->rValue = model->BSIM3V2pkt1l; + return(OK); + case BSIM3V2_MOD_PKT2 : + value->rValue = model->BSIM3V2pkt2; + return(OK); + case BSIM3V2_MOD_PK2 : + value->rValue = model->BSIM3V2pk2; + return(OK); + case BSIM3V2_MOD_PK3: + value->rValue = model->BSIM3V2pk3; + return(OK); + case BSIM3V2_MOD_PK3B: + value->rValue = model->BSIM3V2pk3b; + return(OK); + case BSIM3V2_MOD_PW0: + value->rValue = model->BSIM3V2pw0; + return(OK); + case BSIM3V2_MOD_PNLX: + value->rValue = model->BSIM3V2pnlx; + return(OK); + case BSIM3V2_MOD_PDVT0 : + value->rValue = model->BSIM3V2pdvt0; + return(OK); + case BSIM3V2_MOD_PDVT1 : + value->rValue = model->BSIM3V2pdvt1; + return(OK); + case BSIM3V2_MOD_PDVT2 : + value->rValue = model->BSIM3V2pdvt2; + return(OK); + case BSIM3V2_MOD_PDVT0W : + value->rValue = model->BSIM3V2pdvt0w; + return(OK); + case BSIM3V2_MOD_PDVT1W : + value->rValue = model->BSIM3V2pdvt1w; + return(OK); + case BSIM3V2_MOD_PDVT2W : + value->rValue = model->BSIM3V2pdvt2w; + return(OK); + case BSIM3V2_MOD_PDROUT : + value->rValue = model->BSIM3V2pdrout; + return(OK); + case BSIM3V2_MOD_PDSUB : + value->rValue = model->BSIM3V2pdsub; + return(OK); + case BSIM3V2_MOD_PVTH0: + value->rValue = model->BSIM3V2pvth0; + return(OK); + case BSIM3V2_MOD_PUA: + value->rValue = model->BSIM3V2pua; + return(OK); + case BSIM3V2_MOD_PUA1: + value->rValue = model->BSIM3V2pua1; + return(OK); + case BSIM3V2_MOD_PUB: + value->rValue = model->BSIM3V2pub; + return(OK); + case BSIM3V2_MOD_PUB1: + value->rValue = model->BSIM3V2pub1; + return(OK); + case BSIM3V2_MOD_PUC: + value->rValue = model->BSIM3V2puc; + return(OK); + case BSIM3V2_MOD_PUC1: + value->rValue = model->BSIM3V2puc1; + return(OK); + case BSIM3V2_MOD_PU0: + value->rValue = model->BSIM3V2pu0; + return(OK); + case BSIM3V2_MOD_PUTE: + value->rValue = model->BSIM3V2pute; + return(OK); + case BSIM3V2_MOD_PVOFF: + value->rValue = model->BSIM3V2pvoff; + return(OK); + case BSIM3V2_MOD_PDELTA: + value->rValue = model->BSIM3V2pdelta; + return(OK); + case BSIM3V2_MOD_PRDSW: + value->rValue = model->BSIM3V2prdsw; + return(OK); + case BSIM3V2_MOD_PPRWB: + value->rValue = model->BSIM3V2pprwb; + return(OK); + case BSIM3V2_MOD_PPRWG: + value->rValue = model->BSIM3V2pprwg; + return(OK); + case BSIM3V2_MOD_PPRT: + value->rValue = model->BSIM3V2pprt; + return(OK); + case BSIM3V2_MOD_PETA0: + value->rValue = model->BSIM3V2peta0; + return(OK); + case BSIM3V2_MOD_PETAB: + value->rValue = model->BSIM3V2petab; + return(OK); + case BSIM3V2_MOD_PPCLM: + value->rValue = model->BSIM3V2ppclm; + return(OK); + case BSIM3V2_MOD_PPDIBL1: + value->rValue = model->BSIM3V2ppdibl1; + return(OK); + case BSIM3V2_MOD_PPDIBL2: + value->rValue = model->BSIM3V2ppdibl2; + return(OK); + case BSIM3V2_MOD_PPDIBLB: + value->rValue = model->BSIM3V2ppdiblb; + return(OK); + case BSIM3V2_MOD_PPSCBE1: + value->rValue = model->BSIM3V2ppscbe1; + return(OK); + case BSIM3V2_MOD_PPSCBE2: + value->rValue = model->BSIM3V2ppscbe2; + return(OK); + case BSIM3V2_MOD_PPVAG: + value->rValue = model->BSIM3V2ppvag; + return(OK); + case BSIM3V2_MOD_PWR: + value->rValue = model->BSIM3V2pwr; + return(OK); + case BSIM3V2_MOD_PDWG: + value->rValue = model->BSIM3V2pdwg; + return(OK); + case BSIM3V2_MOD_PDWB: + value->rValue = model->BSIM3V2pdwb; + return(OK); + case BSIM3V2_MOD_PB0: + value->rValue = model->BSIM3V2pb0; + return(OK); + case BSIM3V2_MOD_PB1: + value->rValue = model->BSIM3V2pb1; + return(OK); + case BSIM3V2_MOD_PALPHA0: + value->rValue = model->BSIM3V2palpha0; + return(OK); + case BSIM3V2_MOD_PALPHA1: + value->rValue = model->BSIM3V2palpha1; + return(OK); + case BSIM3V2_MOD_PBETA0: + value->rValue = model->BSIM3V2pbeta0; + return(OK); + case BSIM3V2_MOD_PVFB: + value->rValue = model->BSIM3V2pvfb; + return(OK); + + case BSIM3V2_MOD_PELM: + value->rValue = model->BSIM3V2pelm; + return(OK); + case BSIM3V2_MOD_PCGSL: + value->rValue = model->BSIM3V2pcgsl; + return(OK); + case BSIM3V2_MOD_PCGDL: + value->rValue = model->BSIM3V2pcgdl; + return(OK); + case BSIM3V2_MOD_PCKAPPA: + value->rValue = model->BSIM3V2pckappa; + return(OK); + case BSIM3V2_MOD_PCF: + value->rValue = model->BSIM3V2pcf; + return(OK); + case BSIM3V2_MOD_PCLC: + value->rValue = model->BSIM3V2pclc; + return(OK); + case BSIM3V2_MOD_PCLE: + value->rValue = model->BSIM3V2pcle; + return(OK); + case BSIM3V2_MOD_PVFBCV: + value->rValue = model->BSIM3V2pvfbcv; + return(OK); + case BSIM3V2_MOD_PACDE: + value->rValue = model->BSIM3V2pacde; + return(OK); + case BSIM3V2_MOD_PMOIN: + value->rValue = model->BSIM3V2pmoin; + return(OK); + case BSIM3V2_MOD_PNOFF: + value->rValue = model->BSIM3V2pnoff; + return(OK); + case BSIM3V2_MOD_PVOFFCV: + value->rValue = model->BSIM3V2pvoffcv; + return(OK); + + case BSIM3V2_MOD_TNOM : + value->rValue = model->BSIM3V2tnom; + return(OK); + case BSIM3V2_MOD_CGSO: + value->rValue = model->BSIM3V2cgso; + return(OK); + case BSIM3V2_MOD_CGDO: + value->rValue = model->BSIM3V2cgdo; + return(OK); + case BSIM3V2_MOD_CGBO: + value->rValue = model->BSIM3V2cgbo; + return(OK); + case BSIM3V2_MOD_XPART: + value->rValue = model->BSIM3V2xpart; + return(OK); + case BSIM3V2_MOD_RSH: + value->rValue = model->BSIM3V2sheetResistance; + return(OK); + case BSIM3V2_MOD_JS: + value->rValue = model->BSIM3V2jctSatCurDensity; + return(OK); + case BSIM3V2_MOD_JSW: + value->rValue = model->BSIM3V2jctSidewallSatCurDensity; + return(OK); + case BSIM3V2_MOD_PB: + value->rValue = model->BSIM3V2bulkJctPotential; + return(OK); + case BSIM3V2_MOD_MJ: + value->rValue = model->BSIM3V2bulkJctBotGradingCoeff; + return(OK); + case BSIM3V2_MOD_PBSW: + value->rValue = model->BSIM3V2sidewallJctPotential; + return(OK); + case BSIM3V2_MOD_MJSW: + value->rValue = model->BSIM3V2bulkJctSideGradingCoeff; + return(OK); + case BSIM3V2_MOD_CJ: + value->rValue = model->BSIM3V2unitAreaJctCap; + return(OK); + case BSIM3V2_MOD_CJSW: + value->rValue = model->BSIM3V2unitLengthSidewallJctCap; + return(OK); + case BSIM3V2_MOD_PBSWG: + value->rValue = model->BSIM3V2GatesidewallJctPotential; + return(OK); + case BSIM3V2_MOD_MJSWG: + value->rValue = model->BSIM3V2bulkJctGateSideGradingCoeff; + return(OK); + case BSIM3V2_MOD_CJSWG: + value->rValue = model->BSIM3V2unitLengthGateSidewallJctCap; + return(OK); + case BSIM3V2_MOD_NJ: + value->rValue = model->BSIM3V2jctEmissionCoeff; + return(OK); + case BSIM3V2_MOD_XTI: + value->rValue = model->BSIM3V2jctTempExponent; + return(OK); + case BSIM3V2_MOD_LINT: + value->rValue = model->BSIM3V2Lint; + return(OK); + case BSIM3V2_MOD_LL: + value->rValue = model->BSIM3V2Ll; + return(OK); + case BSIM3V2_MOD_LLC: + value->rValue = model->BSIM3V2Llc; + return(OK); + case BSIM3V2_MOD_LLN: + value->rValue = model->BSIM3V2Lln; + return(OK); + case BSIM3V2_MOD_LW: + value->rValue = model->BSIM3V2Lw; + return(OK); + case BSIM3V2_MOD_LWC: + value->rValue = model->BSIM3V2Lwc; + return(OK); + case BSIM3V2_MOD_LWN: + value->rValue = model->BSIM3V2Lwn; + return(OK); + case BSIM3V2_MOD_LWL: + value->rValue = model->BSIM3V2Lwl; + return(OK); + case BSIM3V2_MOD_LWLC: + value->rValue = model->BSIM3V2Lwlc; + return(OK); + case BSIM3V2_MOD_LMIN: + value->rValue = model->BSIM3V2Lmin; + return(OK); + case BSIM3V2_MOD_LMAX: + value->rValue = model->BSIM3V2Lmax; + return(OK); + case BSIM3V2_MOD_WINT: + value->rValue = model->BSIM3V2Wint; + return(OK); + case BSIM3V2_MOD_WL: + value->rValue = model->BSIM3V2Wl; + return(OK); + case BSIM3V2_MOD_WLC: + value->rValue = model->BSIM3V2Wlc; + return(OK); + case BSIM3V2_MOD_WLN: + value->rValue = model->BSIM3V2Wln; + return(OK); + case BSIM3V2_MOD_WW: + value->rValue = model->BSIM3V2Ww; + return(OK); + case BSIM3V2_MOD_WWC: + value->rValue = model->BSIM3V2Wwc; + return(OK); + case BSIM3V2_MOD_WWN: + value->rValue = model->BSIM3V2Wwn; + return(OK); + case BSIM3V2_MOD_WWL: + value->rValue = model->BSIM3V2Wwl; + return(OK); + case BSIM3V2_MOD_WWLC: + value->rValue = model->BSIM3V2Wwlc; + return(OK); + case BSIM3V2_MOD_WMIN: + value->rValue = model->BSIM3V2Wmin; + return(OK); + case BSIM3V2_MOD_WMAX: + value->rValue = model->BSIM3V2Wmax; + return(OK); + case BSIM3V2_MOD_NOIA: + value->rValue = model->BSIM3V2oxideTrapDensityA; + return(OK); + case BSIM3V2_MOD_NOIB: + value->rValue = model->BSIM3V2oxideTrapDensityB; + return(OK); + case BSIM3V2_MOD_NOIC: + value->rValue = model->BSIM3V2oxideTrapDensityC; + return(OK); + case BSIM3V2_MOD_EM: + value->rValue = model->BSIM3V2em; + return(OK); + case BSIM3V2_MOD_EF: + value->rValue = model->BSIM3V2ef; + return(OK); + case BSIM3V2_MOD_AF: + value->rValue = model->BSIM3V2af; + return(OK); + case BSIM3V2_MOD_KF: + value->rValue = model->BSIM3V2kf; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + + + diff --git a/src/spicelib/devices/bsim3v2/b3v2mdel.c b/src/spicelib/devices/bsim3v2/b3v2mdel.c new file mode 100644 index 000000000..4c19c47fd --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2mdel.c @@ -0,0 +1,60 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2mdel.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3v2def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V2mDelete(inModel,modname,kill) +GENmodel **inModel; +IFuid modname; +GENmodel *kill; +{ +BSIM3V2model **model = (BSIM3V2model**)inModel; +BSIM3V2model *modfast = (BSIM3V2model*)kill; +BSIM3V2instance *here; +BSIM3V2instance *prev = NULL; +BSIM3V2model **oldmod; + + oldmod = model; + for (; *model ; model = &((*model)->BSIM3V2nextModel)) + { if ((*model)->BSIM3V2modName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->BSIM3V2nextModel; /* cut deleted device out of list */ + for (here = (*model)->BSIM3V2instances; here; here = here->BSIM3V2nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v2/b3v2mpar.c b/src/spicelib/devices/bsim3v2/b3v2mpar.c new file mode 100644 index 000000000..e485959b5 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2mpar.c @@ -0,0 +1,1689 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: b3v2mpar.c +**********/ + +#include "ngspice.h" +#include +#include "bsim3v2def.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V2mParam(param,value,inMod) +int param; +IFvalue *value; +GENmodel *inMod; +{ + BSIM3V2model *mod = (BSIM3V2model*)inMod; + switch(param) + { case BSIM3V2_MOD_MOBMOD : + mod->BSIM3V2mobMod = value->iValue; + mod->BSIM3V2mobModGiven = TRUE; + break; + case BSIM3V2_MOD_BINUNIT : + mod->BSIM3V2binUnit = value->iValue; + mod->BSIM3V2binUnitGiven = TRUE; + break; + case BSIM3V2_MOD_PARAMCHK : + mod->BSIM3V2paramChk = value->iValue; + mod->BSIM3V2paramChkGiven = TRUE; + break; + case BSIM3V2_MOD_CAPMOD : + mod->BSIM3V2capMod = value->iValue; + mod->BSIM3V2capModGiven = TRUE; + break; + case BSIM3V2_MOD_NOIMOD : + mod->BSIM3V2noiMod = value->iValue; + mod->BSIM3V2noiModGiven = TRUE; + break; + case BSIM3V2_MOD_VERSION : + mod->BSIM3V2version = value->rValue; + mod->BSIM3V2versionGiven = TRUE; + break; + case BSIM3V2_MOD_TOX : + mod->BSIM3V2tox = value->rValue; + mod->BSIM3V2toxGiven = TRUE; + break; + case BSIM3V2_MOD_TOXM : + mod->BSIM3V2toxm = value->rValue; + mod->BSIM3V2toxmGiven = TRUE; + break; + + case BSIM3V2_MOD_CDSC : + mod->BSIM3V2cdsc = value->rValue; + mod->BSIM3V2cdscGiven = TRUE; + break; + case BSIM3V2_MOD_CDSCB : + mod->BSIM3V2cdscb = value->rValue; + mod->BSIM3V2cdscbGiven = TRUE; + break; + + case BSIM3V2_MOD_CDSCD : + mod->BSIM3V2cdscd = value->rValue; + mod->BSIM3V2cdscdGiven = TRUE; + break; + + case BSIM3V2_MOD_CIT : + mod->BSIM3V2cit = value->rValue; + mod->BSIM3V2citGiven = TRUE; + break; + case BSIM3V2_MOD_NFACTOR : + mod->BSIM3V2nfactor = value->rValue; + mod->BSIM3V2nfactorGiven = TRUE; + break; + case BSIM3V2_MOD_XJ: + mod->BSIM3V2xj = value->rValue; + mod->BSIM3V2xjGiven = TRUE; + break; + case BSIM3V2_MOD_VSAT: + mod->BSIM3V2vsat = value->rValue; + mod->BSIM3V2vsatGiven = TRUE; + break; + case BSIM3V2_MOD_A0: + mod->BSIM3V2a0 = value->rValue; + mod->BSIM3V2a0Given = TRUE; + break; + + case BSIM3V2_MOD_AGS: + mod->BSIM3V2ags= value->rValue; + mod->BSIM3V2agsGiven = TRUE; + break; + + case BSIM3V2_MOD_A1: + mod->BSIM3V2a1 = value->rValue; + mod->BSIM3V2a1Given = TRUE; + break; + case BSIM3V2_MOD_A2: + mod->BSIM3V2a2 = value->rValue; + mod->BSIM3V2a2Given = TRUE; + break; + case BSIM3V2_MOD_AT: + mod->BSIM3V2at = value->rValue; + mod->BSIM3V2atGiven = TRUE; + break; + case BSIM3V2_MOD_KETA: + mod->BSIM3V2keta = value->rValue; + mod->BSIM3V2ketaGiven = TRUE; + break; + case BSIM3V2_MOD_NSUB: + mod->BSIM3V2nsub = value->rValue; + mod->BSIM3V2nsubGiven = TRUE; + break; + case BSIM3V2_MOD_NPEAK: + mod->BSIM3V2npeak = value->rValue; + mod->BSIM3V2npeakGiven = TRUE; + if (mod->BSIM3V2npeak > 1.0e20) + mod->BSIM3V2npeak *= 1.0e-6; + break; + case BSIM3V2_MOD_NGATE: + mod->BSIM3V2ngate = value->rValue; + mod->BSIM3V2ngateGiven = TRUE; + if (mod->BSIM3V2ngate > 1.0e23) + mod->BSIM3V2ngate *= 1.0e-6; + break; + case BSIM3V2_MOD_GAMMA1: + mod->BSIM3V2gamma1 = value->rValue; + mod->BSIM3V2gamma1Given = TRUE; + break; + case BSIM3V2_MOD_GAMMA2: + mod->BSIM3V2gamma2 = value->rValue; + mod->BSIM3V2gamma2Given = TRUE; + break; + case BSIM3V2_MOD_VBX: + mod->BSIM3V2vbx = value->rValue; + mod->BSIM3V2vbxGiven = TRUE; + break; + case BSIM3V2_MOD_VBM: + mod->BSIM3V2vbm = value->rValue; + mod->BSIM3V2vbmGiven = TRUE; + break; + case BSIM3V2_MOD_XT: + mod->BSIM3V2xt = value->rValue; + mod->BSIM3V2xtGiven = TRUE; + break; + case BSIM3V2_MOD_K1: + mod->BSIM3V2k1 = value->rValue; + mod->BSIM3V2k1Given = TRUE; + break; + case BSIM3V2_MOD_KT1: + mod->BSIM3V2kt1 = value->rValue; + mod->BSIM3V2kt1Given = TRUE; + break; + case BSIM3V2_MOD_KT1L: + mod->BSIM3V2kt1l = value->rValue; + mod->BSIM3V2kt1lGiven = TRUE; + break; + case BSIM3V2_MOD_KT2: + mod->BSIM3V2kt2 = value->rValue; + mod->BSIM3V2kt2Given = TRUE; + break; + case BSIM3V2_MOD_K2: + mod->BSIM3V2k2 = value->rValue; + mod->BSIM3V2k2Given = TRUE; + break; + case BSIM3V2_MOD_K3: + mod->BSIM3V2k3 = value->rValue; + mod->BSIM3V2k3Given = TRUE; + break; + case BSIM3V2_MOD_K3B: + mod->BSIM3V2k3b = value->rValue; + mod->BSIM3V2k3bGiven = TRUE; + break; + case BSIM3V2_MOD_NLX: + mod->BSIM3V2nlx = value->rValue; + mod->BSIM3V2nlxGiven = TRUE; + break; + case BSIM3V2_MOD_W0: + mod->BSIM3V2w0 = value->rValue; + mod->BSIM3V2w0Given = TRUE; + break; + case BSIM3V2_MOD_DVT0: + mod->BSIM3V2dvt0 = value->rValue; + mod->BSIM3V2dvt0Given = TRUE; + break; + case BSIM3V2_MOD_DVT1: + mod->BSIM3V2dvt1 = value->rValue; + mod->BSIM3V2dvt1Given = TRUE; + break; + case BSIM3V2_MOD_DVT2: + mod->BSIM3V2dvt2 = value->rValue; + mod->BSIM3V2dvt2Given = TRUE; + break; + case BSIM3V2_MOD_DVT0W: + mod->BSIM3V2dvt0w = value->rValue; + mod->BSIM3V2dvt0wGiven = TRUE; + break; + case BSIM3V2_MOD_DVT1W: + mod->BSIM3V2dvt1w = value->rValue; + mod->BSIM3V2dvt1wGiven = TRUE; + break; + case BSIM3V2_MOD_DVT2W: + mod->BSIM3V2dvt2w = value->rValue; + mod->BSIM3V2dvt2wGiven = TRUE; + break; + case BSIM3V2_MOD_DROUT: + mod->BSIM3V2drout = value->rValue; + mod->BSIM3V2droutGiven = TRUE; + break; + case BSIM3V2_MOD_DSUB: + mod->BSIM3V2dsub = value->rValue; + mod->BSIM3V2dsubGiven = TRUE; + break; + case BSIM3V2_MOD_VTH0: + mod->BSIM3V2vth0 = value->rValue; + mod->BSIM3V2vth0Given = TRUE; + break; + case BSIM3V2_MOD_UA: + mod->BSIM3V2ua = value->rValue; + mod->BSIM3V2uaGiven = TRUE; + break; + case BSIM3V2_MOD_UA1: + mod->BSIM3V2ua1 = value->rValue; + mod->BSIM3V2ua1Given = TRUE; + break; + case BSIM3V2_MOD_UB: + mod->BSIM3V2ub = value->rValue; + mod->BSIM3V2ubGiven = TRUE; + break; + case BSIM3V2_MOD_UB1: + mod->BSIM3V2ub1 = value->rValue; + mod->BSIM3V2ub1Given = TRUE; + break; + case BSIM3V2_MOD_UC: + mod->BSIM3V2uc = value->rValue; + mod->BSIM3V2ucGiven = TRUE; + break; + case BSIM3V2_MOD_UC1: + mod->BSIM3V2uc1 = value->rValue; + mod->BSIM3V2uc1Given = TRUE; + break; + case BSIM3V2_MOD_U0 : + mod->BSIM3V2u0 = value->rValue; + mod->BSIM3V2u0Given = TRUE; + break; + case BSIM3V2_MOD_UTE : + mod->BSIM3V2ute = value->rValue; + mod->BSIM3V2uteGiven = TRUE; + break; + case BSIM3V2_MOD_VOFF: + mod->BSIM3V2voff = value->rValue; + mod->BSIM3V2voffGiven = TRUE; + break; + case BSIM3V2_MOD_DELTA : + mod->BSIM3V2delta = value->rValue; + mod->BSIM3V2deltaGiven = TRUE; + break; + case BSIM3V2_MOD_RDSW: + mod->BSIM3V2rdsw = value->rValue; + mod->BSIM3V2rdswGiven = TRUE; + break; + case BSIM3V2_MOD_PRWG: + mod->BSIM3V2prwg = value->rValue; + mod->BSIM3V2prwgGiven = TRUE; + break; + case BSIM3V2_MOD_PRWB: + mod->BSIM3V2prwb = value->rValue; + mod->BSIM3V2prwbGiven = TRUE; + break; + case BSIM3V2_MOD_PRT: + mod->BSIM3V2prt = value->rValue; + mod->BSIM3V2prtGiven = TRUE; + break; + case BSIM3V2_MOD_ETA0: + mod->BSIM3V2eta0 = value->rValue; + mod->BSIM3V2eta0Given = TRUE; + break; + case BSIM3V2_MOD_ETAB: + mod->BSIM3V2etab = value->rValue; + mod->BSIM3V2etabGiven = TRUE; + break; + case BSIM3V2_MOD_PCLM: + mod->BSIM3V2pclm = value->rValue; + mod->BSIM3V2pclmGiven = TRUE; + break; + case BSIM3V2_MOD_PDIBL1: + mod->BSIM3V2pdibl1 = value->rValue; + mod->BSIM3V2pdibl1Given = TRUE; + break; + case BSIM3V2_MOD_PDIBL2: + mod->BSIM3V2pdibl2 = value->rValue; + mod->BSIM3V2pdibl2Given = TRUE; + break; + case BSIM3V2_MOD_PDIBLB: + mod->BSIM3V2pdiblb = value->rValue; + mod->BSIM3V2pdiblbGiven = TRUE; + break; + case BSIM3V2_MOD_PSCBE1: + mod->BSIM3V2pscbe1 = value->rValue; + mod->BSIM3V2pscbe1Given = TRUE; + break; + case BSIM3V2_MOD_PSCBE2: + mod->BSIM3V2pscbe2 = value->rValue; + mod->BSIM3V2pscbe2Given = TRUE; + break; + case BSIM3V2_MOD_PVAG: + mod->BSIM3V2pvag = value->rValue; + mod->BSIM3V2pvagGiven = TRUE; + break; + case BSIM3V2_MOD_WR : + mod->BSIM3V2wr = value->rValue; + mod->BSIM3V2wrGiven = TRUE; + break; + case BSIM3V2_MOD_DWG : + mod->BSIM3V2dwg = value->rValue; + mod->BSIM3V2dwgGiven = TRUE; + break; + case BSIM3V2_MOD_DWB : + mod->BSIM3V2dwb = value->rValue; + mod->BSIM3V2dwbGiven = TRUE; + break; + case BSIM3V2_MOD_B0 : + mod->BSIM3V2b0 = value->rValue; + mod->BSIM3V2b0Given = TRUE; + break; + case BSIM3V2_MOD_B1 : + mod->BSIM3V2b1 = value->rValue; + mod->BSIM3V2b1Given = TRUE; + break; + case BSIM3V2_MOD_ALPHA0 : + mod->BSIM3V2alpha0 = value->rValue; + mod->BSIM3V2alpha0Given = TRUE; + break; + case BSIM3V2_MOD_ALPHA1 : + mod->BSIM3V2alpha1 = value->rValue; + mod->BSIM3V2alpha1Given = TRUE; + break; + case BSIM3V2_MOD_BETA0 : + mod->BSIM3V2beta0 = value->rValue; + mod->BSIM3V2beta0Given = TRUE; + break; + case BSIM3V2_MOD_IJTH : + mod->BSIM3V2ijth = value->rValue; + mod->BSIM3V2ijthGiven = TRUE; + break; + case BSIM3V2_MOD_VFB : + mod->BSIM3V2vfb = value->rValue; + mod->BSIM3V2vfbGiven = TRUE; + break; + + case BSIM3V2_MOD_ELM : + mod->BSIM3V2elm = value->rValue; + mod->BSIM3V2elmGiven = TRUE; + break; + case BSIM3V2_MOD_CGSL : + mod->BSIM3V2cgsl = value->rValue; + mod->BSIM3V2cgslGiven = TRUE; + break; + case BSIM3V2_MOD_CGDL : + mod->BSIM3V2cgdl = value->rValue; + mod->BSIM3V2cgdlGiven = TRUE; + break; + case BSIM3V2_MOD_CKAPPA : + mod->BSIM3V2ckappa = value->rValue; + mod->BSIM3V2ckappaGiven = TRUE; + break; + case BSIM3V2_MOD_CF : + mod->BSIM3V2cf = value->rValue; + mod->BSIM3V2cfGiven = TRUE; + break; + case BSIM3V2_MOD_CLC : + mod->BSIM3V2clc = value->rValue; + mod->BSIM3V2clcGiven = TRUE; + break; + case BSIM3V2_MOD_CLE : + mod->BSIM3V2cle = value->rValue; + mod->BSIM3V2cleGiven = TRUE; + break; + case BSIM3V2_MOD_DWC : + mod->BSIM3V2dwc = value->rValue; + mod->BSIM3V2dwcGiven = TRUE; + break; + case BSIM3V2_MOD_DLC : + mod->BSIM3V2dlc = value->rValue; + mod->BSIM3V2dlcGiven = TRUE; + break; + case BSIM3V2_MOD_VFBCV : + mod->BSIM3V2vfbcv = value->rValue; + mod->BSIM3V2vfbcvGiven = TRUE; + break; + case BSIM3V2_MOD_ACDE : + mod->BSIM3V2acde = value->rValue; + mod->BSIM3V2acdeGiven = TRUE; + break; + case BSIM3V2_MOD_MOIN : + mod->BSIM3V2moin = value->rValue; + mod->BSIM3V2moinGiven = TRUE; + break; + case BSIM3V2_MOD_NOFF : + mod->BSIM3V2noff = value->rValue; + mod->BSIM3V2noffGiven = TRUE; + break; + case BSIM3V2_MOD_VOFFCV : + mod->BSIM3V2voffcv = value->rValue; + mod->BSIM3V2voffcvGiven = TRUE; + break; + case BSIM3V2_MOD_TCJ : + mod->BSIM3V2tcj = value->rValue; + mod->BSIM3V2tcjGiven = TRUE; + break; + case BSIM3V2_MOD_TPB : + mod->BSIM3V2tpb = value->rValue; + mod->BSIM3V2tpbGiven = TRUE; + break; + case BSIM3V2_MOD_TCJSW : + mod->BSIM3V2tcjsw = value->rValue; + mod->BSIM3V2tcjswGiven = TRUE; + break; + case BSIM3V2_MOD_TPBSW : + mod->BSIM3V2tpbsw = value->rValue; + mod->BSIM3V2tpbswGiven = TRUE; + break; + case BSIM3V2_MOD_TCJSWG : + mod->BSIM3V2tcjswg = value->rValue; + mod->BSIM3V2tcjswgGiven = TRUE; + break; + case BSIM3V2_MOD_TPBSWG : + mod->BSIM3V2tpbswg = value->rValue; + mod->BSIM3V2tpbswgGiven = TRUE; + break; + + /* Length dependence */ + case BSIM3V2_MOD_LCDSC : + mod->BSIM3V2lcdsc = value->rValue; + mod->BSIM3V2lcdscGiven = TRUE; + break; + + + case BSIM3V2_MOD_LCDSCB : + mod->BSIM3V2lcdscb = value->rValue; + mod->BSIM3V2lcdscbGiven = TRUE; + break; + case BSIM3V2_MOD_LCDSCD : + mod->BSIM3V2lcdscd = value->rValue; + mod->BSIM3V2lcdscdGiven = TRUE; + break; + case BSIM3V2_MOD_LCIT : + mod->BSIM3V2lcit = value->rValue; + mod->BSIM3V2lcitGiven = TRUE; + break; + case BSIM3V2_MOD_LNFACTOR : + mod->BSIM3V2lnfactor = value->rValue; + mod->BSIM3V2lnfactorGiven = TRUE; + break; + case BSIM3V2_MOD_LXJ: + mod->BSIM3V2lxj = value->rValue; + mod->BSIM3V2lxjGiven = TRUE; + break; + case BSIM3V2_MOD_LVSAT: + mod->BSIM3V2lvsat = value->rValue; + mod->BSIM3V2lvsatGiven = TRUE; + break; + + + case BSIM3V2_MOD_LA0: + mod->BSIM3V2la0 = value->rValue; + mod->BSIM3V2la0Given = TRUE; + break; + case BSIM3V2_MOD_LAGS: + mod->BSIM3V2lags = value->rValue; + mod->BSIM3V2lagsGiven = TRUE; + break; + case BSIM3V2_MOD_LA1: + mod->BSIM3V2la1 = value->rValue; + mod->BSIM3V2la1Given = TRUE; + break; + case BSIM3V2_MOD_LA2: + mod->BSIM3V2la2 = value->rValue; + mod->BSIM3V2la2Given = TRUE; + break; + case BSIM3V2_MOD_LAT: + mod->BSIM3V2lat = value->rValue; + mod->BSIM3V2latGiven = TRUE; + break; + case BSIM3V2_MOD_LKETA: + mod->BSIM3V2lketa = value->rValue; + mod->BSIM3V2lketaGiven = TRUE; + break; + case BSIM3V2_MOD_LNSUB: + mod->BSIM3V2lnsub = value->rValue; + mod->BSIM3V2lnsubGiven = TRUE; + break; + case BSIM3V2_MOD_LNPEAK: + mod->BSIM3V2lnpeak = value->rValue; + mod->BSIM3V2lnpeakGiven = TRUE; + if (mod->BSIM3V2lnpeak > 1.0e20) + mod->BSIM3V2lnpeak *= 1.0e-6; + break; + case BSIM3V2_MOD_LNGATE: + mod->BSIM3V2lngate = value->rValue; + mod->BSIM3V2lngateGiven = TRUE; + if (mod->BSIM3V2lngate > 1.0e23) + mod->BSIM3V2lngate *= 1.0e-6; + break; + case BSIM3V2_MOD_LGAMMA1: + mod->BSIM3V2lgamma1 = value->rValue; + mod->BSIM3V2lgamma1Given = TRUE; + break; + case BSIM3V2_MOD_LGAMMA2: + mod->BSIM3V2lgamma2 = value->rValue; + mod->BSIM3V2lgamma2Given = TRUE; + break; + case BSIM3V2_MOD_LVBX: + mod->BSIM3V2lvbx = value->rValue; + mod->BSIM3V2lvbxGiven = TRUE; + break; + case BSIM3V2_MOD_LVBM: + mod->BSIM3V2lvbm = value->rValue; + mod->BSIM3V2lvbmGiven = TRUE; + break; + case BSIM3V2_MOD_LXT: + mod->BSIM3V2lxt = value->rValue; + mod->BSIM3V2lxtGiven = TRUE; + break; + case BSIM3V2_MOD_LK1: + mod->BSIM3V2lk1 = value->rValue; + mod->BSIM3V2lk1Given = TRUE; + break; + case BSIM3V2_MOD_LKT1: + mod->BSIM3V2lkt1 = value->rValue; + mod->BSIM3V2lkt1Given = TRUE; + break; + case BSIM3V2_MOD_LKT1L: + mod->BSIM3V2lkt1l = value->rValue; + mod->BSIM3V2lkt1lGiven = TRUE; + break; + case BSIM3V2_MOD_LKT2: + mod->BSIM3V2lkt2 = value->rValue; + mod->BSIM3V2lkt2Given = TRUE; + break; + case BSIM3V2_MOD_LK2: + mod->BSIM3V2lk2 = value->rValue; + mod->BSIM3V2lk2Given = TRUE; + break; + case BSIM3V2_MOD_LK3: + mod->BSIM3V2lk3 = value->rValue; + mod->BSIM3V2lk3Given = TRUE; + break; + case BSIM3V2_MOD_LK3B: + mod->BSIM3V2lk3b = value->rValue; + mod->BSIM3V2lk3bGiven = TRUE; + break; + case BSIM3V2_MOD_LNLX: + mod->BSIM3V2lnlx = value->rValue; + mod->BSIM3V2lnlxGiven = TRUE; + break; + case BSIM3V2_MOD_LW0: + mod->BSIM3V2lw0 = value->rValue; + mod->BSIM3V2lw0Given = TRUE; + break; + case BSIM3V2_MOD_LDVT0: + mod->BSIM3V2ldvt0 = value->rValue; + mod->BSIM3V2ldvt0Given = TRUE; + break; + case BSIM3V2_MOD_LDVT1: + mod->BSIM3V2ldvt1 = value->rValue; + mod->BSIM3V2ldvt1Given = TRUE; + break; + case BSIM3V2_MOD_LDVT2: + mod->BSIM3V2ldvt2 = value->rValue; + mod->BSIM3V2ldvt2Given = TRUE; + break; + case BSIM3V2_MOD_LDVT0W: + mod->BSIM3V2ldvt0w = value->rValue; + mod->BSIM3V2ldvt0wGiven = TRUE; + break; + case BSIM3V2_MOD_LDVT1W: + mod->BSIM3V2ldvt1w = value->rValue; + mod->BSIM3V2ldvt1wGiven = TRUE; + break; + case BSIM3V2_MOD_LDVT2W: + mod->BSIM3V2ldvt2w = value->rValue; + mod->BSIM3V2ldvt2wGiven = TRUE; + break; + case BSIM3V2_MOD_LDROUT: + mod->BSIM3V2ldrout = value->rValue; + mod->BSIM3V2ldroutGiven = TRUE; + break; + case BSIM3V2_MOD_LDSUB: + mod->BSIM3V2ldsub = value->rValue; + mod->BSIM3V2ldsubGiven = TRUE; + break; + case BSIM3V2_MOD_LVTH0: + mod->BSIM3V2lvth0 = value->rValue; + mod->BSIM3V2lvth0Given = TRUE; + break; + case BSIM3V2_MOD_LUA: + mod->BSIM3V2lua = value->rValue; + mod->BSIM3V2luaGiven = TRUE; + break; + case BSIM3V2_MOD_LUA1: + mod->BSIM3V2lua1 = value->rValue; + mod->BSIM3V2lua1Given = TRUE; + break; + case BSIM3V2_MOD_LUB: + mod->BSIM3V2lub = value->rValue; + mod->BSIM3V2lubGiven = TRUE; + break; + case BSIM3V2_MOD_LUB1: + mod->BSIM3V2lub1 = value->rValue; + mod->BSIM3V2lub1Given = TRUE; + break; + case BSIM3V2_MOD_LUC: + mod->BSIM3V2luc = value->rValue; + mod->BSIM3V2lucGiven = TRUE; + break; + case BSIM3V2_MOD_LUC1: + mod->BSIM3V2luc1 = value->rValue; + mod->BSIM3V2luc1Given = TRUE; + break; + case BSIM3V2_MOD_LU0 : + mod->BSIM3V2lu0 = value->rValue; + mod->BSIM3V2lu0Given = TRUE; + break; + case BSIM3V2_MOD_LUTE : + mod->BSIM3V2lute = value->rValue; + mod->BSIM3V2luteGiven = TRUE; + break; + case BSIM3V2_MOD_LVOFF: + mod->BSIM3V2lvoff = value->rValue; + mod->BSIM3V2lvoffGiven = TRUE; + break; + case BSIM3V2_MOD_LDELTA : + mod->BSIM3V2ldelta = value->rValue; + mod->BSIM3V2ldeltaGiven = TRUE; + break; + case BSIM3V2_MOD_LRDSW: + mod->BSIM3V2lrdsw = value->rValue; + mod->BSIM3V2lrdswGiven = TRUE; + break; + case BSIM3V2_MOD_LPRWB: + mod->BSIM3V2lprwb = value->rValue; + mod->BSIM3V2lprwbGiven = TRUE; + break; + case BSIM3V2_MOD_LPRWG: + mod->BSIM3V2lprwg = value->rValue; + mod->BSIM3V2lprwgGiven = TRUE; + break; + case BSIM3V2_MOD_LPRT: + mod->BSIM3V2lprt = value->rValue; + mod->BSIM3V2lprtGiven = TRUE; + break; + case BSIM3V2_MOD_LETA0: + mod->BSIM3V2leta0 = value->rValue; + mod->BSIM3V2leta0Given = TRUE; + break; + case BSIM3V2_MOD_LETAB: + mod->BSIM3V2letab = value->rValue; + mod->BSIM3V2letabGiven = TRUE; + break; + case BSIM3V2_MOD_LPCLM: + mod->BSIM3V2lpclm = value->rValue; + mod->BSIM3V2lpclmGiven = TRUE; + break; + case BSIM3V2_MOD_LPDIBL1: + mod->BSIM3V2lpdibl1 = value->rValue; + mod->BSIM3V2lpdibl1Given = TRUE; + break; + case BSIM3V2_MOD_LPDIBL2: + mod->BSIM3V2lpdibl2 = value->rValue; + mod->BSIM3V2lpdibl2Given = TRUE; + break; + case BSIM3V2_MOD_LPDIBLB: + mod->BSIM3V2lpdiblb = value->rValue; + mod->BSIM3V2lpdiblbGiven = TRUE; + break; + case BSIM3V2_MOD_LPSCBE1: + mod->BSIM3V2lpscbe1 = value->rValue; + mod->BSIM3V2lpscbe1Given = TRUE; + break; + case BSIM3V2_MOD_LPSCBE2: + mod->BSIM3V2lpscbe2 = value->rValue; + mod->BSIM3V2lpscbe2Given = TRUE; + break; + case BSIM3V2_MOD_LPVAG: + mod->BSIM3V2lpvag = value->rValue; + mod->BSIM3V2lpvagGiven = TRUE; + break; + case BSIM3V2_MOD_LWR : + mod->BSIM3V2lwr = value->rValue; + mod->BSIM3V2lwrGiven = TRUE; + break; + case BSIM3V2_MOD_LDWG : + mod->BSIM3V2ldwg = value->rValue; + mod->BSIM3V2ldwgGiven = TRUE; + break; + case BSIM3V2_MOD_LDWB : + mod->BSIM3V2ldwb = value->rValue; + mod->BSIM3V2ldwbGiven = TRUE; + break; + case BSIM3V2_MOD_LB0 : + mod->BSIM3V2lb0 = value->rValue; + mod->BSIM3V2lb0Given = TRUE; + break; + case BSIM3V2_MOD_LB1 : + mod->BSIM3V2lb1 = value->rValue; + mod->BSIM3V2lb1Given = TRUE; + break; + case BSIM3V2_MOD_LALPHA0 : + mod->BSIM3V2lalpha0 = value->rValue; + mod->BSIM3V2lalpha0Given = TRUE; + break; + case BSIM3V2_MOD_LALPHA1 : + mod->BSIM3V2lalpha1 = value->rValue; + mod->BSIM3V2lalpha1Given = TRUE; + break; + case BSIM3V2_MOD_LBETA0 : + mod->BSIM3V2lbeta0 = value->rValue; + mod->BSIM3V2lbeta0Given = TRUE; + break; + case BSIM3V2_MOD_LVFB : + mod->BSIM3V2lvfb = value->rValue; + mod->BSIM3V2lvfbGiven = TRUE; + break; + + case BSIM3V2_MOD_LELM : + mod->BSIM3V2lelm = value->rValue; + mod->BSIM3V2lelmGiven = TRUE; + break; + case BSIM3V2_MOD_LCGSL : + mod->BSIM3V2lcgsl = value->rValue; + mod->BSIM3V2lcgslGiven = TRUE; + break; + case BSIM3V2_MOD_LCGDL : + mod->BSIM3V2lcgdl = value->rValue; + mod->BSIM3V2lcgdlGiven = TRUE; + break; + case BSIM3V2_MOD_LCKAPPA : + mod->BSIM3V2lckappa = value->rValue; + mod->BSIM3V2lckappaGiven = TRUE; + break; + case BSIM3V2_MOD_LCF : + mod->BSIM3V2lcf = value->rValue; + mod->BSIM3V2lcfGiven = TRUE; + break; + case BSIM3V2_MOD_LCLC : + mod->BSIM3V2lclc = value->rValue; + mod->BSIM3V2lclcGiven = TRUE; + break; + case BSIM3V2_MOD_LCLE : + mod->BSIM3V2lcle = value->rValue; + mod->BSIM3V2lcleGiven = TRUE; + break; + case BSIM3V2_MOD_LVFBCV : + mod->BSIM3V2lvfbcv = value->rValue; + mod->BSIM3V2lvfbcvGiven = TRUE; + break; + case BSIM3V2_MOD_LACDE : + mod->BSIM3V2lacde = value->rValue; + mod->BSIM3V2lacdeGiven = TRUE; + break; + case BSIM3V2_MOD_LMOIN : + mod->BSIM3V2lmoin = value->rValue; + mod->BSIM3V2lmoinGiven = TRUE; + break; + case BSIM3V2_MOD_LNOFF : + mod->BSIM3V2lnoff = value->rValue; + mod->BSIM3V2lnoffGiven = TRUE; + break; + case BSIM3V2_MOD_LVOFFCV : + mod->BSIM3V2lvoffcv = value->rValue; + mod->BSIM3V2lvoffcvGiven = TRUE; + break; + + /* Width dependence */ + case BSIM3V2_MOD_WCDSC : + mod->BSIM3V2wcdsc = value->rValue; + mod->BSIM3V2wcdscGiven = TRUE; + break; + + + case BSIM3V2_MOD_WCDSCB : + mod->BSIM3V2wcdscb = value->rValue; + mod->BSIM3V2wcdscbGiven = TRUE; + break; + case BSIM3V2_MOD_WCDSCD : + mod->BSIM3V2wcdscd = value->rValue; + mod->BSIM3V2wcdscdGiven = TRUE; + break; + case BSIM3V2_MOD_WCIT : + mod->BSIM3V2wcit = value->rValue; + mod->BSIM3V2wcitGiven = TRUE; + break; + case BSIM3V2_MOD_WNFACTOR : + mod->BSIM3V2wnfactor = value->rValue; + mod->BSIM3V2wnfactorGiven = TRUE; + break; + case BSIM3V2_MOD_WXJ: + mod->BSIM3V2wxj = value->rValue; + mod->BSIM3V2wxjGiven = TRUE; + break; + case BSIM3V2_MOD_WVSAT: + mod->BSIM3V2wvsat = value->rValue; + mod->BSIM3V2wvsatGiven = TRUE; + break; + + + case BSIM3V2_MOD_WA0: + mod->BSIM3V2wa0 = value->rValue; + mod->BSIM3V2wa0Given = TRUE; + break; + case BSIM3V2_MOD_WAGS: + mod->BSIM3V2wags = value->rValue; + mod->BSIM3V2wagsGiven = TRUE; + break; + case BSIM3V2_MOD_WA1: + mod->BSIM3V2wa1 = value->rValue; + mod->BSIM3V2wa1Given = TRUE; + break; + case BSIM3V2_MOD_WA2: + mod->BSIM3V2wa2 = value->rValue; + mod->BSIM3V2wa2Given = TRUE; + break; + case BSIM3V2_MOD_WAT: + mod->BSIM3V2wat = value->rValue; + mod->BSIM3V2watGiven = TRUE; + break; + case BSIM3V2_MOD_WKETA: + mod->BSIM3V2wketa = value->rValue; + mod->BSIM3V2wketaGiven = TRUE; + break; + case BSIM3V2_MOD_WNSUB: + mod->BSIM3V2wnsub = value->rValue; + mod->BSIM3V2wnsubGiven = TRUE; + break; + case BSIM3V2_MOD_WNPEAK: + mod->BSIM3V2wnpeak = value->rValue; + mod->BSIM3V2wnpeakGiven = TRUE; + if (mod->BSIM3V2wnpeak > 1.0e20) + mod->BSIM3V2wnpeak *= 1.0e-6; + break; + case BSIM3V2_MOD_WNGATE: + mod->BSIM3V2wngate = value->rValue; + mod->BSIM3V2wngateGiven = TRUE; + if (mod->BSIM3V2wngate > 1.0e23) + mod->BSIM3V2wngate *= 1.0e-6; + break; + case BSIM3V2_MOD_WGAMMA1: + mod->BSIM3V2wgamma1 = value->rValue; + mod->BSIM3V2wgamma1Given = TRUE; + break; + case BSIM3V2_MOD_WGAMMA2: + mod->BSIM3V2wgamma2 = value->rValue; + mod->BSIM3V2wgamma2Given = TRUE; + break; + case BSIM3V2_MOD_WVBX: + mod->BSIM3V2wvbx = value->rValue; + mod->BSIM3V2wvbxGiven = TRUE; + break; + case BSIM3V2_MOD_WVBM: + mod->BSIM3V2wvbm = value->rValue; + mod->BSIM3V2wvbmGiven = TRUE; + break; + case BSIM3V2_MOD_WXT: + mod->BSIM3V2wxt = value->rValue; + mod->BSIM3V2wxtGiven = TRUE; + break; + case BSIM3V2_MOD_WK1: + mod->BSIM3V2wk1 = value->rValue; + mod->BSIM3V2wk1Given = TRUE; + break; + case BSIM3V2_MOD_WKT1: + mod->BSIM3V2wkt1 = value->rValue; + mod->BSIM3V2wkt1Given = TRUE; + break; + case BSIM3V2_MOD_WKT1L: + mod->BSIM3V2wkt1l = value->rValue; + mod->BSIM3V2wkt1lGiven = TRUE; + break; + case BSIM3V2_MOD_WKT2: + mod->BSIM3V2wkt2 = value->rValue; + mod->BSIM3V2wkt2Given = TRUE; + break; + case BSIM3V2_MOD_WK2: + mod->BSIM3V2wk2 = value->rValue; + mod->BSIM3V2wk2Given = TRUE; + break; + case BSIM3V2_MOD_WK3: + mod->BSIM3V2wk3 = value->rValue; + mod->BSIM3V2wk3Given = TRUE; + break; + case BSIM3V2_MOD_WK3B: + mod->BSIM3V2wk3b = value->rValue; + mod->BSIM3V2wk3bGiven = TRUE; + break; + case BSIM3V2_MOD_WNLX: + mod->BSIM3V2wnlx = value->rValue; + mod->BSIM3V2wnlxGiven = TRUE; + break; + case BSIM3V2_MOD_WW0: + mod->BSIM3V2ww0 = value->rValue; + mod->BSIM3V2ww0Given = TRUE; + break; + case BSIM3V2_MOD_WDVT0: + mod->BSIM3V2wdvt0 = value->rValue; + mod->BSIM3V2wdvt0Given = TRUE; + break; + case BSIM3V2_MOD_WDVT1: + mod->BSIM3V2wdvt1 = value->rValue; + mod->BSIM3V2wdvt1Given = TRUE; + break; + case BSIM3V2_MOD_WDVT2: + mod->BSIM3V2wdvt2 = value->rValue; + mod->BSIM3V2wdvt2Given = TRUE; + break; + case BSIM3V2_MOD_WDVT0W: + mod->BSIM3V2wdvt0w = value->rValue; + mod->BSIM3V2wdvt0wGiven = TRUE; + break; + case BSIM3V2_MOD_WDVT1W: + mod->BSIM3V2wdvt1w = value->rValue; + mod->BSIM3V2wdvt1wGiven = TRUE; + break; + case BSIM3V2_MOD_WDVT2W: + mod->BSIM3V2wdvt2w = value->rValue; + mod->BSIM3V2wdvt2wGiven = TRUE; + break; + case BSIM3V2_MOD_WDROUT: + mod->BSIM3V2wdrout = value->rValue; + mod->BSIM3V2wdroutGiven = TRUE; + break; + case BSIM3V2_MOD_WDSUB: + mod->BSIM3V2wdsub = value->rValue; + mod->BSIM3V2wdsubGiven = TRUE; + break; + case BSIM3V2_MOD_WVTH0: + mod->BSIM3V2wvth0 = value->rValue; + mod->BSIM3V2wvth0Given = TRUE; + break; + case BSIM3V2_MOD_WUA: + mod->BSIM3V2wua = value->rValue; + mod->BSIM3V2wuaGiven = TRUE; + break; + case BSIM3V2_MOD_WUA1: + mod->BSIM3V2wua1 = value->rValue; + mod->BSIM3V2wua1Given = TRUE; + break; + case BSIM3V2_MOD_WUB: + mod->BSIM3V2wub = value->rValue; + mod->BSIM3V2wubGiven = TRUE; + break; + case BSIM3V2_MOD_WUB1: + mod->BSIM3V2wub1 = value->rValue; + mod->BSIM3V2wub1Given = TRUE; + break; + case BSIM3V2_MOD_WUC: + mod->BSIM3V2wuc = value->rValue; + mod->BSIM3V2wucGiven = TRUE; + break; + case BSIM3V2_MOD_WUC1: + mod->BSIM3V2wuc1 = value->rValue; + mod->BSIM3V2wuc1Given = TRUE; + break; + case BSIM3V2_MOD_WU0 : + mod->BSIM3V2wu0 = value->rValue; + mod->BSIM3V2wu0Given = TRUE; + break; + case BSIM3V2_MOD_WUTE : + mod->BSIM3V2wute = value->rValue; + mod->BSIM3V2wuteGiven = TRUE; + break; + case BSIM3V2_MOD_WVOFF: + mod->BSIM3V2wvoff = value->rValue; + mod->BSIM3V2wvoffGiven = TRUE; + break; + case BSIM3V2_MOD_WDELTA : + mod->BSIM3V2wdelta = value->rValue; + mod->BSIM3V2wdeltaGiven = TRUE; + break; + case BSIM3V2_MOD_WRDSW: + mod->BSIM3V2wrdsw = value->rValue; + mod->BSIM3V2wrdswGiven = TRUE; + break; + case BSIM3V2_MOD_WPRWB: + mod->BSIM3V2wprwb = value->rValue; + mod->BSIM3V2wprwbGiven = TRUE; + break; + case BSIM3V2_MOD_WPRWG: + mod->BSIM3V2wprwg = value->rValue; + mod->BSIM3V2wprwgGiven = TRUE; + break; + case BSIM3V2_MOD_WPRT: + mod->BSIM3V2wprt = value->rValue; + mod->BSIM3V2wprtGiven = TRUE; + break; + case BSIM3V2_MOD_WETA0: + mod->BSIM3V2weta0 = value->rValue; + mod->BSIM3V2weta0Given = TRUE; + break; + case BSIM3V2_MOD_WETAB: + mod->BSIM3V2wetab = value->rValue; + mod->BSIM3V2wetabGiven = TRUE; + break; + case BSIM3V2_MOD_WPCLM: + mod->BSIM3V2wpclm = value->rValue; + mod->BSIM3V2wpclmGiven = TRUE; + break; + case BSIM3V2_MOD_WPDIBL1: + mod->BSIM3V2wpdibl1 = value->rValue; + mod->BSIM3V2wpdibl1Given = TRUE; + break; + case BSIM3V2_MOD_WPDIBL2: + mod->BSIM3V2wpdibl2 = value->rValue; + mod->BSIM3V2wpdibl2Given = TRUE; + break; + case BSIM3V2_MOD_WPDIBLB: + mod->BSIM3V2wpdiblb = value->rValue; + mod->BSIM3V2wpdiblbGiven = TRUE; + break; + case BSIM3V2_MOD_WPSCBE1: + mod->BSIM3V2wpscbe1 = value->rValue; + mod->BSIM3V2wpscbe1Given = TRUE; + break; + case BSIM3V2_MOD_WPSCBE2: + mod->BSIM3V2wpscbe2 = value->rValue; + mod->BSIM3V2wpscbe2Given = TRUE; + break; + case BSIM3V2_MOD_WPVAG: + mod->BSIM3V2wpvag = value->rValue; + mod->BSIM3V2wpvagGiven = TRUE; + break; + case BSIM3V2_MOD_WWR : + mod->BSIM3V2wwr = value->rValue; + mod->BSIM3V2wwrGiven = TRUE; + break; + case BSIM3V2_MOD_WDWG : + mod->BSIM3V2wdwg = value->rValue; + mod->BSIM3V2wdwgGiven = TRUE; + break; + case BSIM3V2_MOD_WDWB : + mod->BSIM3V2wdwb = value->rValue; + mod->BSIM3V2wdwbGiven = TRUE; + break; + case BSIM3V2_MOD_WB0 : + mod->BSIM3V2wb0 = value->rValue; + mod->BSIM3V2wb0Given = TRUE; + break; + case BSIM3V2_MOD_WB1 : + mod->BSIM3V2wb1 = value->rValue; + mod->BSIM3V2wb1Given = TRUE; + break; + case BSIM3V2_MOD_WALPHA0 : + mod->BSIM3V2walpha0 = value->rValue; + mod->BSIM3V2walpha0Given = TRUE; + break; + case BSIM3V2_MOD_WALPHA1 : + mod->BSIM3V2walpha1 = value->rValue; + mod->BSIM3V2walpha1Given = TRUE; + break; + case BSIM3V2_MOD_WBETA0 : + mod->BSIM3V2wbeta0 = value->rValue; + mod->BSIM3V2wbeta0Given = TRUE; + break; + case BSIM3V2_MOD_WVFB : + mod->BSIM3V2wvfb = value->rValue; + mod->BSIM3V2wvfbGiven = TRUE; + break; + + case BSIM3V2_MOD_WELM : + mod->BSIM3V2welm = value->rValue; + mod->BSIM3V2welmGiven = TRUE; + break; + case BSIM3V2_MOD_WCGSL : + mod->BSIM3V2wcgsl = value->rValue; + mod->BSIM3V2wcgslGiven = TRUE; + break; + case BSIM3V2_MOD_WCGDL : + mod->BSIM3V2wcgdl = value->rValue; + mod->BSIM3V2wcgdlGiven = TRUE; + break; + case BSIM3V2_MOD_WCKAPPA : + mod->BSIM3V2wckappa = value->rValue; + mod->BSIM3V2wckappaGiven = TRUE; + break; + case BSIM3V2_MOD_WCF : + mod->BSIM3V2wcf = value->rValue; + mod->BSIM3V2wcfGiven = TRUE; + break; + case BSIM3V2_MOD_WCLC : + mod->BSIM3V2wclc = value->rValue; + mod->BSIM3V2wclcGiven = TRUE; + break; + case BSIM3V2_MOD_WCLE : + mod->BSIM3V2wcle = value->rValue; + mod->BSIM3V2wcleGiven = TRUE; + break; + case BSIM3V2_MOD_WVFBCV : + mod->BSIM3V2wvfbcv = value->rValue; + mod->BSIM3V2wvfbcvGiven = TRUE; + break; + case BSIM3V2_MOD_WACDE : + mod->BSIM3V2wacde = value->rValue; + mod->BSIM3V2wacdeGiven = TRUE; + break; + case BSIM3V2_MOD_WMOIN : + mod->BSIM3V2wmoin = value->rValue; + mod->BSIM3V2wmoinGiven = TRUE; + break; + case BSIM3V2_MOD_WNOFF : + mod->BSIM3V2wnoff = value->rValue; + mod->BSIM3V2wnoffGiven = TRUE; + break; + case BSIM3V2_MOD_WVOFFCV : + mod->BSIM3V2wvoffcv = value->rValue; + mod->BSIM3V2wvoffcvGiven = TRUE; + break; + + /* Cross-term dependence */ + case BSIM3V2_MOD_PCDSC : + mod->BSIM3V2pcdsc = value->rValue; + mod->BSIM3V2pcdscGiven = TRUE; + break; + + + case BSIM3V2_MOD_PCDSCB : + mod->BSIM3V2pcdscb = value->rValue; + mod->BSIM3V2pcdscbGiven = TRUE; + break; + case BSIM3V2_MOD_PCDSCD : + mod->BSIM3V2pcdscd = value->rValue; + mod->BSIM3V2pcdscdGiven = TRUE; + break; + case BSIM3V2_MOD_PCIT : + mod->BSIM3V2pcit = value->rValue; + mod->BSIM3V2pcitGiven = TRUE; + break; + case BSIM3V2_MOD_PNFACTOR : + mod->BSIM3V2pnfactor = value->rValue; + mod->BSIM3V2pnfactorGiven = TRUE; + break; + case BSIM3V2_MOD_PXJ: + mod->BSIM3V2pxj = value->rValue; + mod->BSIM3V2pxjGiven = TRUE; + break; + case BSIM3V2_MOD_PVSAT: + mod->BSIM3V2pvsat = value->rValue; + mod->BSIM3V2pvsatGiven = TRUE; + break; + + + case BSIM3V2_MOD_PA0: + mod->BSIM3V2pa0 = value->rValue; + mod->BSIM3V2pa0Given = TRUE; + break; + case BSIM3V2_MOD_PAGS: + mod->BSIM3V2pags = value->rValue; + mod->BSIM3V2pagsGiven = TRUE; + break; + case BSIM3V2_MOD_PA1: + mod->BSIM3V2pa1 = value->rValue; + mod->BSIM3V2pa1Given = TRUE; + break; + case BSIM3V2_MOD_PA2: + mod->BSIM3V2pa2 = value->rValue; + mod->BSIM3V2pa2Given = TRUE; + break; + case BSIM3V2_MOD_PAT: + mod->BSIM3V2pat = value->rValue; + mod->BSIM3V2patGiven = TRUE; + break; + case BSIM3V2_MOD_PKETA: + mod->BSIM3V2pketa = value->rValue; + mod->BSIM3V2pketaGiven = TRUE; + break; + case BSIM3V2_MOD_PNSUB: + mod->BSIM3V2pnsub = value->rValue; + mod->BSIM3V2pnsubGiven = TRUE; + break; + case BSIM3V2_MOD_PNPEAK: + mod->BSIM3V2pnpeak = value->rValue; + mod->BSIM3V2pnpeakGiven = TRUE; + if (mod->BSIM3V2pnpeak > 1.0e20) + mod->BSIM3V2pnpeak *= 1.0e-6; + break; + case BSIM3V2_MOD_PNGATE: + mod->BSIM3V2pngate = value->rValue; + mod->BSIM3V2pngateGiven = TRUE; + if (mod->BSIM3V2pngate > 1.0e23) + mod->BSIM3V2pngate *= 1.0e-6; + break; + case BSIM3V2_MOD_PGAMMA1: + mod->BSIM3V2pgamma1 = value->rValue; + mod->BSIM3V2pgamma1Given = TRUE; + break; + case BSIM3V2_MOD_PGAMMA2: + mod->BSIM3V2pgamma2 = value->rValue; + mod->BSIM3V2pgamma2Given = TRUE; + break; + case BSIM3V2_MOD_PVBX: + mod->BSIM3V2pvbx = value->rValue; + mod->BSIM3V2pvbxGiven = TRUE; + break; + case BSIM3V2_MOD_PVBM: + mod->BSIM3V2pvbm = value->rValue; + mod->BSIM3V2pvbmGiven = TRUE; + break; + case BSIM3V2_MOD_PXT: + mod->BSIM3V2pxt = value->rValue; + mod->BSIM3V2pxtGiven = TRUE; + break; + case BSIM3V2_MOD_PK1: + mod->BSIM3V2pk1 = value->rValue; + mod->BSIM3V2pk1Given = TRUE; + break; + case BSIM3V2_MOD_PKT1: + mod->BSIM3V2pkt1 = value->rValue; + mod->BSIM3V2pkt1Given = TRUE; + break; + case BSIM3V2_MOD_PKT1L: + mod->BSIM3V2pkt1l = value->rValue; + mod->BSIM3V2pkt1lGiven = TRUE; + break; + case BSIM3V2_MOD_PKT2: + mod->BSIM3V2pkt2 = value->rValue; + mod->BSIM3V2pkt2Given = TRUE; + break; + case BSIM3V2_MOD_PK2: + mod->BSIM3V2pk2 = value->rValue; + mod->BSIM3V2pk2Given = TRUE; + break; + case BSIM3V2_MOD_PK3: + mod->BSIM3V2pk3 = value->rValue; + mod->BSIM3V2pk3Given = TRUE; + break; + case BSIM3V2_MOD_PK3B: + mod->BSIM3V2pk3b = value->rValue; + mod->BSIM3V2pk3bGiven = TRUE; + break; + case BSIM3V2_MOD_PNLX: + mod->BSIM3V2pnlx = value->rValue; + mod->BSIM3V2pnlxGiven = TRUE; + break; + case BSIM3V2_MOD_PW0: + mod->BSIM3V2pw0 = value->rValue; + mod->BSIM3V2pw0Given = TRUE; + break; + case BSIM3V2_MOD_PDVT0: + mod->BSIM3V2pdvt0 = value->rValue; + mod->BSIM3V2pdvt0Given = TRUE; + break; + case BSIM3V2_MOD_PDVT1: + mod->BSIM3V2pdvt1 = value->rValue; + mod->BSIM3V2pdvt1Given = TRUE; + break; + case BSIM3V2_MOD_PDVT2: + mod->BSIM3V2pdvt2 = value->rValue; + mod->BSIM3V2pdvt2Given = TRUE; + break; + case BSIM3V2_MOD_PDVT0W: + mod->BSIM3V2pdvt0w = value->rValue; + mod->BSIM3V2pdvt0wGiven = TRUE; + break; + case BSIM3V2_MOD_PDVT1W: + mod->BSIM3V2pdvt1w = value->rValue; + mod->BSIM3V2pdvt1wGiven = TRUE; + break; + case BSIM3V2_MOD_PDVT2W: + mod->BSIM3V2pdvt2w = value->rValue; + mod->BSIM3V2pdvt2wGiven = TRUE; + break; + case BSIM3V2_MOD_PDROUT: + mod->BSIM3V2pdrout = value->rValue; + mod->BSIM3V2pdroutGiven = TRUE; + break; + case BSIM3V2_MOD_PDSUB: + mod->BSIM3V2pdsub = value->rValue; + mod->BSIM3V2pdsubGiven = TRUE; + break; + case BSIM3V2_MOD_PVTH0: + mod->BSIM3V2pvth0 = value->rValue; + mod->BSIM3V2pvth0Given = TRUE; + break; + case BSIM3V2_MOD_PUA: + mod->BSIM3V2pua = value->rValue; + mod->BSIM3V2puaGiven = TRUE; + break; + case BSIM3V2_MOD_PUA1: + mod->BSIM3V2pua1 = value->rValue; + mod->BSIM3V2pua1Given = TRUE; + break; + case BSIM3V2_MOD_PUB: + mod->BSIM3V2pub = value->rValue; + mod->BSIM3V2pubGiven = TRUE; + break; + case BSIM3V2_MOD_PUB1: + mod->BSIM3V2pub1 = value->rValue; + mod->BSIM3V2pub1Given = TRUE; + break; + case BSIM3V2_MOD_PUC: + mod->BSIM3V2puc = value->rValue; + mod->BSIM3V2pucGiven = TRUE; + break; + case BSIM3V2_MOD_PUC1: + mod->BSIM3V2puc1 = value->rValue; + mod->BSIM3V2puc1Given = TRUE; + break; + case BSIM3V2_MOD_PU0 : + mod->BSIM3V2pu0 = value->rValue; + mod->BSIM3V2pu0Given = TRUE; + break; + case BSIM3V2_MOD_PUTE : + mod->BSIM3V2pute = value->rValue; + mod->BSIM3V2puteGiven = TRUE; + break; + case BSIM3V2_MOD_PVOFF: + mod->BSIM3V2pvoff = value->rValue; + mod->BSIM3V2pvoffGiven = TRUE; + break; + case BSIM3V2_MOD_PDELTA : + mod->BSIM3V2pdelta = value->rValue; + mod->BSIM3V2pdeltaGiven = TRUE; + break; + case BSIM3V2_MOD_PRDSW: + mod->BSIM3V2prdsw = value->rValue; + mod->BSIM3V2prdswGiven = TRUE; + break; + case BSIM3V2_MOD_PPRWB: + mod->BSIM3V2pprwb = value->rValue; + mod->BSIM3V2pprwbGiven = TRUE; + break; + case BSIM3V2_MOD_PPRWG: + mod->BSIM3V2pprwg = value->rValue; + mod->BSIM3V2pprwgGiven = TRUE; + break; + case BSIM3V2_MOD_PPRT: + mod->BSIM3V2pprt = value->rValue; + mod->BSIM3V2pprtGiven = TRUE; + break; + case BSIM3V2_MOD_PETA0: + mod->BSIM3V2peta0 = value->rValue; + mod->BSIM3V2peta0Given = TRUE; + break; + case BSIM3V2_MOD_PETAB: + mod->BSIM3V2petab = value->rValue; + mod->BSIM3V2petabGiven = TRUE; + break; + case BSIM3V2_MOD_PPCLM: + mod->BSIM3V2ppclm = value->rValue; + mod->BSIM3V2ppclmGiven = TRUE; + break; + case BSIM3V2_MOD_PPDIBL1: + mod->BSIM3V2ppdibl1 = value->rValue; + mod->BSIM3V2ppdibl1Given = TRUE; + break; + case BSIM3V2_MOD_PPDIBL2: + mod->BSIM3V2ppdibl2 = value->rValue; + mod->BSIM3V2ppdibl2Given = TRUE; + break; + case BSIM3V2_MOD_PPDIBLB: + mod->BSIM3V2ppdiblb = value->rValue; + mod->BSIM3V2ppdiblbGiven = TRUE; + break; + case BSIM3V2_MOD_PPSCBE1: + mod->BSIM3V2ppscbe1 = value->rValue; + mod->BSIM3V2ppscbe1Given = TRUE; + break; + case BSIM3V2_MOD_PPSCBE2: + mod->BSIM3V2ppscbe2 = value->rValue; + mod->BSIM3V2ppscbe2Given = TRUE; + break; + case BSIM3V2_MOD_PPVAG: + mod->BSIM3V2ppvag = value->rValue; + mod->BSIM3V2ppvagGiven = TRUE; + break; + case BSIM3V2_MOD_PWR : + mod->BSIM3V2pwr = value->rValue; + mod->BSIM3V2pwrGiven = TRUE; + break; + case BSIM3V2_MOD_PDWG : + mod->BSIM3V2pdwg = value->rValue; + mod->BSIM3V2pdwgGiven = TRUE; + break; + case BSIM3V2_MOD_PDWB : + mod->BSIM3V2pdwb = value->rValue; + mod->BSIM3V2pdwbGiven = TRUE; + break; + case BSIM3V2_MOD_PB0 : + mod->BSIM3V2pb0 = value->rValue; + mod->BSIM3V2pb0Given = TRUE; + break; + case BSIM3V2_MOD_PB1 : + mod->BSIM3V2pb1 = value->rValue; + mod->BSIM3V2pb1Given = TRUE; + break; + case BSIM3V2_MOD_PALPHA0 : + mod->BSIM3V2palpha0 = value->rValue; + mod->BSIM3V2palpha0Given = TRUE; + break; + case BSIM3V2_MOD_PALPHA1 : + mod->BSIM3V2palpha1 = value->rValue; + mod->BSIM3V2palpha1Given = TRUE; + break; + case BSIM3V2_MOD_PBETA0 : + mod->BSIM3V2pbeta0 = value->rValue; + mod->BSIM3V2pbeta0Given = TRUE; + break; + case BSIM3V2_MOD_PVFB : + mod->BSIM3V2pvfb = value->rValue; + mod->BSIM3V2pvfbGiven = TRUE; + break; + + case BSIM3V2_MOD_PELM : + mod->BSIM3V2pelm = value->rValue; + mod->BSIM3V2pelmGiven = TRUE; + break; + case BSIM3V2_MOD_PCGSL : + mod->BSIM3V2pcgsl = value->rValue; + mod->BSIM3V2pcgslGiven = TRUE; + break; + case BSIM3V2_MOD_PCGDL : + mod->BSIM3V2pcgdl = value->rValue; + mod->BSIM3V2pcgdlGiven = TRUE; + break; + case BSIM3V2_MOD_PCKAPPA : + mod->BSIM3V2pckappa = value->rValue; + mod->BSIM3V2pckappaGiven = TRUE; + break; + case BSIM3V2_MOD_PCF : + mod->BSIM3V2pcf = value->rValue; + mod->BSIM3V2pcfGiven = TRUE; + break; + case BSIM3V2_MOD_PCLC : + mod->BSIM3V2pclc = value->rValue; + mod->BSIM3V2pclcGiven = TRUE; + break; + case BSIM3V2_MOD_PCLE : + mod->BSIM3V2pcle = value->rValue; + mod->BSIM3V2pcleGiven = TRUE; + break; + case BSIM3V2_MOD_PVFBCV : + mod->BSIM3V2pvfbcv = value->rValue; + mod->BSIM3V2pvfbcvGiven = TRUE; + break; + case BSIM3V2_MOD_PACDE : + mod->BSIM3V2pacde = value->rValue; + mod->BSIM3V2pacdeGiven = TRUE; + break; + case BSIM3V2_MOD_PMOIN : + mod->BSIM3V2pmoin = value->rValue; + mod->BSIM3V2pmoinGiven = TRUE; + break; + case BSIM3V2_MOD_PNOFF : + mod->BSIM3V2pnoff = value->rValue; + mod->BSIM3V2pnoffGiven = TRUE; + break; + case BSIM3V2_MOD_PVOFFCV : + mod->BSIM3V2pvoffcv = value->rValue; + mod->BSIM3V2pvoffcvGiven = TRUE; + break; + + case BSIM3V2_MOD_TNOM : + mod->BSIM3V2tnom = value->rValue + 273.15; + mod->BSIM3V2tnomGiven = TRUE; + break; + case BSIM3V2_MOD_CGSO : + mod->BSIM3V2cgso = value->rValue; + mod->BSIM3V2cgsoGiven = TRUE; + break; + case BSIM3V2_MOD_CGDO : + mod->BSIM3V2cgdo = value->rValue; + mod->BSIM3V2cgdoGiven = TRUE; + break; + case BSIM3V2_MOD_CGBO : + mod->BSIM3V2cgbo = value->rValue; + mod->BSIM3V2cgboGiven = TRUE; + break; + case BSIM3V2_MOD_XPART : + mod->BSIM3V2xpart = value->rValue; + mod->BSIM3V2xpartGiven = TRUE; + break; + case BSIM3V2_MOD_RSH : + mod->BSIM3V2sheetResistance = value->rValue; + mod->BSIM3V2sheetResistanceGiven = TRUE; + break; + case BSIM3V2_MOD_JS : + mod->BSIM3V2jctSatCurDensity = value->rValue; + mod->BSIM3V2jctSatCurDensityGiven = TRUE; + break; + case BSIM3V2_MOD_JSW : + mod->BSIM3V2jctSidewallSatCurDensity = value->rValue; + mod->BSIM3V2jctSidewallSatCurDensityGiven = TRUE; + break; + case BSIM3V2_MOD_PB : + mod->BSIM3V2bulkJctPotential = value->rValue; + mod->BSIM3V2bulkJctPotentialGiven = TRUE; + break; + case BSIM3V2_MOD_MJ : + mod->BSIM3V2bulkJctBotGradingCoeff = value->rValue; + mod->BSIM3V2bulkJctBotGradingCoeffGiven = TRUE; + break; + case BSIM3V2_MOD_PBSW : + mod->BSIM3V2sidewallJctPotential = value->rValue; + mod->BSIM3V2sidewallJctPotentialGiven = TRUE; + break; + case BSIM3V2_MOD_MJSW : + mod->BSIM3V2bulkJctSideGradingCoeff = value->rValue; + mod->BSIM3V2bulkJctSideGradingCoeffGiven = TRUE; + break; + case BSIM3V2_MOD_CJ : + mod->BSIM3V2unitAreaJctCap = value->rValue; + mod->BSIM3V2unitAreaJctCapGiven = TRUE; + break; + case BSIM3V2_MOD_CJSW : + mod->BSIM3V2unitLengthSidewallJctCap = value->rValue; + mod->BSIM3V2unitLengthSidewallJctCapGiven = TRUE; + break; + case BSIM3V2_MOD_NJ : + mod->BSIM3V2jctEmissionCoeff = value->rValue; + mod->BSIM3V2jctEmissionCoeffGiven = TRUE; + break; + case BSIM3V2_MOD_PBSWG : + mod->BSIM3V2GatesidewallJctPotential = value->rValue; + mod->BSIM3V2GatesidewallJctPotentialGiven = TRUE; + break; + case BSIM3V2_MOD_MJSWG : + mod->BSIM3V2bulkJctGateSideGradingCoeff = value->rValue; + mod->BSIM3V2bulkJctGateSideGradingCoeffGiven = TRUE; + break; + case BSIM3V2_MOD_CJSWG : + mod->BSIM3V2unitLengthGateSidewallJctCap = value->rValue; + mod->BSIM3V2unitLengthGateSidewallJctCapGiven = TRUE; + break; + case BSIM3V2_MOD_XTI : + mod->BSIM3V2jctTempExponent = value->rValue; + mod->BSIM3V2jctTempExponentGiven = TRUE; + break; + case BSIM3V2_MOD_LINT : + mod->BSIM3V2Lint = value->rValue; + mod->BSIM3V2LintGiven = TRUE; + break; + case BSIM3V2_MOD_LL : + mod->BSIM3V2Ll = value->rValue; + mod->BSIM3V2LlGiven = TRUE; + break; + case BSIM3V2_MOD_LLC : + mod->BSIM3V2Llc = value->rValue; + mod->BSIM3V2LlcGiven = TRUE; + break; + case BSIM3V2_MOD_LLN : + mod->BSIM3V2Lln = value->rValue; + mod->BSIM3V2LlnGiven = TRUE; + break; + case BSIM3V2_MOD_LW : + mod->BSIM3V2Lw = value->rValue; + mod->BSIM3V2LwGiven = TRUE; + break; + case BSIM3V2_MOD_LWC : + mod->BSIM3V2Lwc = value->rValue; + mod->BSIM3V2LwcGiven = TRUE; + break; + case BSIM3V2_MOD_LWN : + mod->BSIM3V2Lwn = value->rValue; + mod->BSIM3V2LwnGiven = TRUE; + break; + case BSIM3V2_MOD_LWL : + mod->BSIM3V2Lwl = value->rValue; + mod->BSIM3V2LwlGiven = TRUE; + break; + case BSIM3V2_MOD_LWLC : + mod->BSIM3V2Lwlc = value->rValue; + mod->BSIM3V2LwlcGiven = TRUE; + break; + case BSIM3V2_MOD_LMIN : + mod->BSIM3V2Lmin = value->rValue; + mod->BSIM3V2LminGiven = TRUE; + break; + case BSIM3V2_MOD_LMAX : + mod->BSIM3V2Lmax = value->rValue; + mod->BSIM3V2LmaxGiven = TRUE; + break; + case BSIM3V2_MOD_WINT : + mod->BSIM3V2Wint = value->rValue; + mod->BSIM3V2WintGiven = TRUE; + break; + case BSIM3V2_MOD_WL : + mod->BSIM3V2Wl = value->rValue; + mod->BSIM3V2WlGiven = TRUE; + break; + case BSIM3V2_MOD_WLC : + mod->BSIM3V2Wlc = value->rValue; + mod->BSIM3V2WlcGiven = TRUE; + break; + case BSIM3V2_MOD_WLN : + mod->BSIM3V2Wln = value->rValue; + mod->BSIM3V2WlnGiven = TRUE; + break; + case BSIM3V2_MOD_WW : + mod->BSIM3V2Ww = value->rValue; + mod->BSIM3V2WwGiven = TRUE; + break; + case BSIM3V2_MOD_WWC : + mod->BSIM3V2Wwc = value->rValue; + mod->BSIM3V2WwcGiven = TRUE; + break; + case BSIM3V2_MOD_WWN : + mod->BSIM3V2Wwn = value->rValue; + mod->BSIM3V2WwnGiven = TRUE; + break; + case BSIM3V2_MOD_WWL : + mod->BSIM3V2Wwl = value->rValue; + mod->BSIM3V2WwlGiven = TRUE; + break; + case BSIM3V2_MOD_WWLC : + mod->BSIM3V2Wwlc = value->rValue; + mod->BSIM3V2WwlcGiven = TRUE; + break; + case BSIM3V2_MOD_WMIN : + mod->BSIM3V2Wmin = value->rValue; + mod->BSIM3V2WminGiven = TRUE; + break; + case BSIM3V2_MOD_WMAX : + mod->BSIM3V2Wmax = value->rValue; + mod->BSIM3V2WmaxGiven = TRUE; + break; + + case BSIM3V2_MOD_NOIA : + mod->BSIM3V2oxideTrapDensityA = value->rValue; + mod->BSIM3V2oxideTrapDensityAGiven = TRUE; + break; + case BSIM3V2_MOD_NOIB : + mod->BSIM3V2oxideTrapDensityB = value->rValue; + mod->BSIM3V2oxideTrapDensityBGiven = TRUE; + break; + case BSIM3V2_MOD_NOIC : + mod->BSIM3V2oxideTrapDensityC = value->rValue; + mod->BSIM3V2oxideTrapDensityCGiven = TRUE; + break; + case BSIM3V2_MOD_EM : + mod->BSIM3V2em = value->rValue; + mod->BSIM3V2emGiven = TRUE; + break; + case BSIM3V2_MOD_EF : + mod->BSIM3V2ef = value->rValue; + mod->BSIM3V2efGiven = TRUE; + break; + case BSIM3V2_MOD_AF : + mod->BSIM3V2af = value->rValue; + mod->BSIM3V2afGiven = TRUE; + break; + case BSIM3V2_MOD_KF : + mod->BSIM3V2kf = value->rValue; + mod->BSIM3V2kfGiven = TRUE; + break; + case BSIM3V2_MOD_NMOS : + if(value->iValue) { + mod->BSIM3V2type = 1; + mod->BSIM3V2typeGiven = TRUE; + } + break; + case BSIM3V2_MOD_PMOS : + if(value->iValue) { + mod->BSIM3V2type = - 1; + mod->BSIM3V2typeGiven = TRUE; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim3v2/b3v2noi.c b/src/spicelib/devices/bsim3v2/b3v2noi.c new file mode 100644 index 000000000..7e4b09b3e --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2noi.c @@ -0,0 +1,399 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Gary W. Ng and Min-Chie Jeng. +File: b3v2noi.c +**********/ + +#include "ngspice.h" +#include +#include +#include "bsim3v2def.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" +#include "const.h" /* jwan */ + +/* + * BSIM3V2noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MOSFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MOSFET's is summed with the variable "OnDens". + */ + +/* + Channel thermal and flicker noises are calculated based on the value + of model->BSIM3V2noiMod. + If model->BSIM3V2noiMod = 1, + Channel thermal noise = SPICE2 model + Flicker noise = SPICE2 model + If model->BSIM3V2noiMod = 2, + Channel thermal noise = BSIM3V2 model + Flicker noise = BSIM3V2 model + If model->BSIM3V2noiMod = 3, + Channel thermal noise = SPICE2 model + Flicker noise = BSIM3V2 model + If model->BSIM3V2noiMod = 4, + Channel thermal noise = BSIM3V2 model + Flicker noise = SPICE2 model + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +double +StrongInversionNoiseEval(vgs, vds, model, here, freq, temp) +double vgs, vds, freq, temp; +BSIM3V2model *model; +BSIM3V2instance *here; +{ +struct BSIM3V2SizeDependParam *pParam; +double cd, esat, DelClm, EffFreq, N0, Nl, Vgst; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, Ssi; + + pParam = here->pParam; + cd = fabs(here->BSIM3V2cd); + if (vds > here->BSIM3V2vdsat) + { esat = 2.0 * pParam->BSIM3V2vsattemp / here->BSIM3V2ueff; + T0 = ((((vds - here->BSIM3V2vdsat) / pParam->BSIM3V2litl) + model->BSIM3V2em) + / esat); + DelClm = pParam->BSIM3V2litl * log (MAX(T0, N_MINLOG)); + } + else + DelClm = 0.0; + EffFreq = pow(freq, model->BSIM3V2ef); + T1 = CHARGE * CHARGE * 8.62e-5 * cd * temp * here->BSIM3V2ueff; + T2 = 1.0e8 * EffFreq * model->BSIM3V2cox + * pParam->BSIM3V2leff * pParam->BSIM3V2leff; + Vgst = vgs - here->BSIM3V2von; + N0 = model->BSIM3V2cox * Vgst / CHARGE; + if (N0 < 0.0) + N0 = 0.0; + Nl = model->BSIM3V2cox * (Vgst - MIN(vds, here->BSIM3V2vdsat)) / CHARGE; + if (Nl < 0.0) + Nl = 0.0; + + T3 = model->BSIM3V2oxideTrapDensityA + * log(MAX(((N0 + 2.0e14) / (Nl + 2.0e14)), N_MINLOG)); + T4 = model->BSIM3V2oxideTrapDensityB * (N0 - Nl); + T5 = model->BSIM3V2oxideTrapDensityC * 0.5 * (N0 * N0 - Nl * Nl); + + T6 = 8.62e-5 * temp * cd * cd; + T7 = 1.0e8 * EffFreq * pParam->BSIM3V2leff + * pParam->BSIM3V2leff * pParam->BSIM3V2weff; + T8 = model->BSIM3V2oxideTrapDensityA + model->BSIM3V2oxideTrapDensityB * Nl + + model->BSIM3V2oxideTrapDensityC * Nl * Nl; + T9 = (Nl + 2.0e14) * (Nl + 2.0e14); + + Ssi = T1 / T2 * (T3 + T4 + T5) + T6 / T7 * DelClm * T8 / T9; + return Ssi; +} + +int +BSIM3V2noise (mode, operation, inModel, ckt, data, OnDens) +int mode, operation; +GENmodel *inModel; +CKTcircuit *ckt; +register Ndata *data; +double *OnDens; +{ +register BSIM3V2model *model = (BSIM3V2model *)inModel; +register BSIM3V2instance *here; +struct BSIM3V2SizeDependParam *pParam; +char name[N_MXVLNTH]; +double tempOnoise; +double tempInoise; +double noizDens[BSIM3V2NSRCS]; +double lnNdens[BSIM3V2NSRCS]; + +double vgs, vds, Slimit; +double N0, Nl; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13; +double n, ExpArg, Ssi, Swi; + +int error, i; + + /* define the names of the noise sources */ + static char *BSIM3V2nNames[BSIM3V2NSRCS] = + { /* Note that we have to keep the order */ + ".rd", /* noise due to rd */ + /* consistent with the index definitions */ + ".rs", /* noise due to rs */ + /* in BSIM3V2defs.h */ + ".id", /* noise due to id */ + ".1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (; model != NULL; model = model->BSIM3V2nextModel) + { for (here = model->BSIM3V2instances; here != NULL; + here = here->BSIM3V2nextInstance) + { pParam = here->pParam; + switch (operation) + { case N_OPEN: + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { switch (mode) + { case N_DENS: + for (i = 0; i < BSIM3V2NSRCS; i++) + { (void) sprintf(name, "onoise.%s%s", + here->BSIM3V2name, + BSIM3V2nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + } + break; + case INT_NOIZ: + for (i = 0; i < BSIM3V2NSRCS; i++) + { (void) sprintf(name, "onoise_total.%s%s", + here->BSIM3V2name, + BSIM3V2nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + + (void) sprintf(name, "inoise_total.%s%s", + here->BSIM3V2name, + BSIM3V2nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **)NULL); + /* we've added one more plot */ + } + break; + } + } + break; + case N_CALC: + switch (mode) + { case N_DENS: + NevalSrc(&noizDens[BSIM3V2RDNOIZ], + &lnNdens[BSIM3V2RDNOIZ], ckt, THERMNOISE, + here->BSIM3V2dNodePrime, here->BSIM3V2dNode, + here->BSIM3V2drainConductance); + + NevalSrc(&noizDens[BSIM3V2RSNOIZ], + &lnNdens[BSIM3V2RSNOIZ], ckt, THERMNOISE, + here->BSIM3V2sNodePrime, here->BSIM3V2sNode, + here->BSIM3V2sourceConductance); + + switch( model->BSIM3V2noiMod ) + { case 1: + case 3: + NevalSrc(&noizDens[BSIM3V2IDNOIZ], + &lnNdens[BSIM3V2IDNOIZ], ckt, + THERMNOISE, here->BSIM3V2dNodePrime, + here->BSIM3V2sNodePrime, + (2.0 / 3.0 * fabs(here->BSIM3V2gm + + here->BSIM3V2gds + + here->BSIM3V2gmbs))); + break; + case 2: + case 4: + NevalSrc(&noizDens[BSIM3V2IDNOIZ], + &lnNdens[BSIM3V2IDNOIZ], ckt, + THERMNOISE, here->BSIM3V2dNodePrime, + here->BSIM3V2sNodePrime, + (here->BSIM3V2ueff + * fabs(here->BSIM3V2qinv + / (pParam->BSIM3V2leff + * pParam->BSIM3V2leff)))); + break; + } + NevalSrc(&noizDens[BSIM3V2FLNOIZ], (double*) NULL, + ckt, N_GAIN, here->BSIM3V2dNodePrime, + here->BSIM3V2sNodePrime, (double) 0.0); + + switch( model->BSIM3V2noiMod ) + { case 1: + case 4: + noizDens[BSIM3V2FLNOIZ] *= model->BSIM3V2kf + * exp(model->BSIM3V2af + * log(MAX(fabs(here->BSIM3V2cd), + N_MINLOG))) + / (pow(data->freq, model->BSIM3V2ef) + * pParam->BSIM3V2leff + * pParam->BSIM3V2leff + * model->BSIM3V2cox); + break; + case 2: + case 3: + vgs = *(ckt->CKTstates[0] + here->BSIM3V2vgs); + vds = *(ckt->CKTstates[0] + here->BSIM3V2vds); + if (vds < 0.0) + { vds = -vds; + vgs = vgs + vds; + } + if (vgs >= here->BSIM3V2von + 0.1) + { Ssi = StrongInversionNoiseEval(vgs, + vds, model, here, data->freq, + ckt->CKTtemp); + noizDens[BSIM3V2FLNOIZ] *= Ssi; + } + else + { pParam = here->pParam; + T10 = model->BSIM3V2oxideTrapDensityA + * 8.62e-5 * ckt->CKTtemp; + T11 = pParam->BSIM3V2weff + * pParam->BSIM3V2leff + * pow(data->freq, model->BSIM3V2ef) + * 4.0e36; + Swi = T10 / T11 * here->BSIM3V2cd + * here->BSIM3V2cd; + Slimit = StrongInversionNoiseEval( + here->BSIM3V2von + 0.1, vds, model, + here, data->freq, ckt->CKTtemp); + T1 = Swi + Slimit; + if (T1 > 0.0) + noizDens[BSIM3V2FLNOIZ] *= (Slimit + * Swi) / T1; + else + noizDens[BSIM3V2FLNOIZ] *= 0.0; + } + break; + } + + lnNdens[BSIM3V2FLNOIZ] = + log(MAX(noizDens[BSIM3V2FLNOIZ], N_MINLOG)); + + noizDens[BSIM3V2TOTNOIZ] = noizDens[BSIM3V2RDNOIZ] + + noizDens[BSIM3V2RSNOIZ] + + noizDens[BSIM3V2IDNOIZ] + + noizDens[BSIM3V2FLNOIZ]; + lnNdens[BSIM3V2TOTNOIZ] = + log(MAX(noizDens[BSIM3V2TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[BSIM3V2TOTNOIZ]; + + if (data->delFreq == 0.0) + { /* if we haven't done any previous + integration, we need to initialize our + "history" variables. + */ + + for (i = 0; i < BSIM3V2NSRCS; i++) + { here->BSIM3V2nVar[LNLSTDENS][i] = + lnNdens[i]; + } + + /* clear out our integration variables + if it's the first pass + */ + if (data->freq == + ((NOISEAN*) ckt->CKTcurJob)->NstartFreq) + { for (i = 0; i < BSIM3V2NSRCS; i++) + { here->BSIM3V2nVar[OUTNOIZ][i] = 0.0; + here->BSIM3V2nVar[INNOIZ][i] = 0.0; + } + } + } + else + { /* data->delFreq != 0.0, + we have to integrate. + */ + for (i = 0; i < BSIM3V2NSRCS; i++) + { if (i != BSIM3V2TOTNOIZ) + { tempOnoise = Nintegrate(noizDens[i], + lnNdens[i], + here->BSIM3V2nVar[LNLSTDENS][i], + data); + tempInoise = Nintegrate(noizDens[i] + * data->GainSqInv, lnNdens[i] + + data->lnGainInv, + here->BSIM3V2nVar[LNLSTDENS][i] + + data->lnGainInv, data); + here->BSIM3V2nVar[LNLSTDENS][i] = + lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*) + ckt->CKTcurJob)->NStpsSm != 0) + { here->BSIM3V2nVar[OUTNOIZ][i] + += tempOnoise; + here->BSIM3V2nVar[OUTNOIZ][BSIM3V2TOTNOIZ] + += tempOnoise; + here->BSIM3V2nVar[INNOIZ][i] + += tempInoise; + here->BSIM3V2nVar[INNOIZ][BSIM3V2TOTNOIZ] + += tempInoise; + } + } + } + } + if (data->prtSummary) + { for (i = 0; i < BSIM3V2NSRCS; i++) + { /* print a summary report */ + data->outpVector[data->outNumber++] + = noizDens[i]; + } + } + break; + case INT_NOIZ: + /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { for (i = 0; i < BSIM3V2NSRCS; i++) + { data->outpVector[data->outNumber++] + = here->BSIM3V2nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] + = here->BSIM3V2nVar[INNOIZ][i]; + } + } + break; + } + break; + case N_CLOSE: + /* do nothing, the main calling routine will close */ + return (OK); + break; /* the plots */ + } /* switch (operation) */ + } /* for here */ + } /* for model */ + + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v2/b3v2par.c b/src/spicelib/devices/bsim3v2/b3v2par.c new file mode 100644 index 000000000..e5d3985a7 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2par.c @@ -0,0 +1,111 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2par.c +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "bsim3v2def.h" +#include "sperror.h" +#include "suffix.h" + +int +BSIM3V2param(param,value,inst,select) +int param; +IFvalue *value; +GENinstance *inst; +IFvalue *select; +{ + BSIM3V2instance *here = (BSIM3V2instance*)inst; + switch(param) + { case BSIM3V2_W: + here->BSIM3V2w = value->rValue; + here->BSIM3V2wGiven = TRUE; + break; + case BSIM3V2_L: + here->BSIM3V2l = value->rValue; + here->BSIM3V2lGiven = TRUE; + break; + case BSIM3V2_AS: + here->BSIM3V2sourceArea = value->rValue; + here->BSIM3V2sourceAreaGiven = TRUE; + break; + case BSIM3V2_AD: + here->BSIM3V2drainArea = value->rValue; + here->BSIM3V2drainAreaGiven = TRUE; + break; + case BSIM3V2_PS: + here->BSIM3V2sourcePerimeter = value->rValue; + here->BSIM3V2sourcePerimeterGiven = TRUE; + break; + case BSIM3V2_PD: + here->BSIM3V2drainPerimeter = value->rValue; + here->BSIM3V2drainPerimeterGiven = TRUE; + break; + case BSIM3V2_NRS: + here->BSIM3V2sourceSquares = value->rValue; + here->BSIM3V2sourceSquaresGiven = TRUE; + break; + case BSIM3V2_NRD: + here->BSIM3V2drainSquares = value->rValue; + here->BSIM3V2drainSquaresGiven = TRUE; + break; + case BSIM3V2_OFF: + here->BSIM3V2off = value->iValue; + break; + case BSIM3V2_IC_VBS: + here->BSIM3V2icVBS = value->rValue; + here->BSIM3V2icVBSGiven = TRUE; + break; + case BSIM3V2_IC_VDS: + here->BSIM3V2icVDS = value->rValue; + here->BSIM3V2icVDSGiven = TRUE; + break; + case BSIM3V2_IC_VGS: + here->BSIM3V2icVGS = value->rValue; + here->BSIM3V2icVGSGiven = TRUE; + break; + case BSIM3V2_NQSMOD: + here->BSIM3V2nqsMod = value->iValue; + here->BSIM3V2nqsModGiven = TRUE; + break; + case BSIM3V2_IC: + switch(value->v.numValue){ + case 3: + here->BSIM3V2icVBS = *(value->v.vec.rVec+2); + here->BSIM3V2icVBSGiven = TRUE; + case 2: + here->BSIM3V2icVGS = *(value->v.vec.rVec+1); + here->BSIM3V2icVGSGiven = TRUE; + case 1: + here->BSIM3V2icVDS = *(value->v.vec.rVec); + here->BSIM3V2icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v2/b3v2pzld.c b/src/spicelib/devices/bsim3v2/b3v2pzld.c new file mode 100644 index 000000000..255c2d127 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2pzld.c @@ -0,0 +1,380 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: b3v2pzld.c +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "bsim3v2def.h" +#include "suffix.h" + +int +BSIM3V2pzLoad(inModel,ckt,s) +GENmodel *inModel; +register CKTcircuit *ckt; +register SPcomplex *s; +{ +register BSIM3V2model *model = (BSIM3V2model*)inModel; +register BSIM3V2instance *here; +double xcggb, xcgdb, xcgsb, xcgbb, xcbgb, xcbdb, xcbsb, xcbbb; +double xcdgb, xcddb, xcdsb, xcdbb, xcsgb, xcsdb, xcssb, xcsbb; +double gdpr, gspr, gds, gbd, gbs, capbd, capbs, FwdSum, RevSum, Gm, Gmbs; +double cggb, cgdb, cgsb, cbgb, cbdb, cbsb, cddb, cdgb, cdsb; +double GSoverlapCap, GDoverlapCap, GBoverlapCap; +double dxpart, sxpart, xgtg, xgtd, xgts, xgtb, xcqgb, xcqdb, xcqsb, xcqbb; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb; +double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; +double T1, CoxWL, qcheq, Cdg, Cdd, Cds, Cdb, Csg, Csd, Css, Csb; + + for (; model != NULL; model = model->BSIM3V2nextModel) + { for (here = model->BSIM3V2instances; here!= NULL; + here = here->BSIM3V2nextInstance) + { + if (here->BSIM3V2owner != ARCHme) continue; + if (here->BSIM3V2mode >= 0) + { Gm = here->BSIM3V2gm; + Gmbs = here->BSIM3V2gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + + gbbdp = -here->BSIM3V2gbds; + gbbsp = here->BSIM3V2gbds + here->BSIM3V2gbgs + here->BSIM3V2gbbs; + + gbdpg = here->BSIM3V2gbgs; + gbdpdp = here->BSIM3V2gbds; + gbdpb = here->BSIM3V2gbbs; + gbdpsp = -(gbdpg + gbdpdp + gbdpb); + + gbspg = 0.0; + gbspdp = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + if (here->BSIM3V2nqsMod == 0) + { cggb = here->BSIM3V2cggb; + cgsb = here->BSIM3V2cgsb; + cgdb = here->BSIM3V2cgdb; + + cbgb = here->BSIM3V2cbgb; + cbsb = here->BSIM3V2cbsb; + cbdb = here->BSIM3V2cbdb; + + cdgb = here->BSIM3V2cdgb; + cdsb = here->BSIM3V2cdsb; + cddb = here->BSIM3V2cddb; + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3V2gtg; + xgtd = here->BSIM3V2gtd; + xgts = here->BSIM3V2gts; + xgtb = here->BSIM3V2gtb; + + xcqgb = here->BSIM3V2cqgb; + xcqdb = here->BSIM3V2cqdb; + xcqsb = here->BSIM3V2cqsb; + xcqbb = here->BSIM3V2cqbb; + + CoxWL = model->BSIM3V2cox * here->pParam->BSIM3V2weffCV + * here->pParam->BSIM3V2leffCV; + qcheq = -(here->BSIM3V2qgate + here->BSIM3V2qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3V2xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM3V2xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = here->BSIM3V2qdrn / qcheq; + Cdd = here->BSIM3V2cddb; + Csd = -(here->BSIM3V2cgdb + here->BSIM3V2cddb + + here->BSIM3V2cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM3V2cdgb; + Csg = -(here->BSIM3V2cggb + here->BSIM3V2cdgb + + here->BSIM3V2cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM3V2cdsb; + Css = -(here->BSIM3V2cgsb + here->BSIM3V2cdsb + + here->BSIM3V2cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + } + else + { Gm = -here->BSIM3V2gm; + Gmbs = -here->BSIM3V2gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + + gbbsp = -here->BSIM3V2gbds; + gbbdp = here->BSIM3V2gbds + here->BSIM3V2gbgs + here->BSIM3V2gbbs; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM3V2gbgs; + gbspsp = here->BSIM3V2gbds; + gbspb = here->BSIM3V2gbbs; + gbspdp = -(gbspg + gbspsp + gbspb); + + if (here->BSIM3V2nqsMod == 0) + { cggb = here->BSIM3V2cggb; + cgsb = here->BSIM3V2cgdb; + cgdb = here->BSIM3V2cgsb; + + cbgb = here->BSIM3V2cbgb; + cbsb = here->BSIM3V2cbdb; + cbdb = here->BSIM3V2cbsb; + + cdgb = -(here->BSIM3V2cdgb + cggb + cbgb); + cdsb = -(here->BSIM3V2cddb + cgsb + cbsb); + cddb = -(here->BSIM3V2cdsb + cgdb + cbdb); + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { cggb = cgdb = cgsb = 0.0; + cbgb = cbdb = cbsb = 0.0; + cdgb = cddb = cdsb = 0.0; + + xgtg = here->BSIM3V2gtg; + xgtd = here->BSIM3V2gts; + xgts = here->BSIM3V2gtd; + xgtb = here->BSIM3V2gtb; + + xcqgb = here->BSIM3V2cqgb; + xcqdb = here->BSIM3V2cqsb; + xcqsb = here->BSIM3V2cqdb; + xcqbb = here->BSIM3V2cqbb; + + CoxWL = model->BSIM3V2cox * here->pParam->BSIM3V2weffCV + * here->pParam->BSIM3V2leffCV; + qcheq = -(here->BSIM3V2qgate + here->BSIM3V2qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM3V2xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM3V2xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = here->BSIM3V2qdrn / qcheq; + Css = here->BSIM3V2cddb; + Cds = -(here->BSIM3V2cgdb + here->BSIM3V2cddb + + here->BSIM3V2cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM3V2cdgb; + Cdg = -(here->BSIM3V2cggb + here->BSIM3V2cdgb + + here->BSIM3V2cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM3V2cdsb; + Cdd = -(here->BSIM3V2cgsb + here->BSIM3V2cdsb + + here->BSIM3V2cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + } + + + T1 = *(ckt->CKTstate0 + here->BSIM3V2qdef) * here->BSIM3V2gtau; + gdpr = here->BSIM3V2drainConductance; + gspr = here->BSIM3V2sourceConductance; + gds = here->BSIM3V2gds; + gbd = here->BSIM3V2gbd; + gbs = here->BSIM3V2gbs; + capbd = here->BSIM3V2capbd; + capbs = here->BSIM3V2capbs; + + GSoverlapCap = here->BSIM3V2cgso; + GDoverlapCap = here->BSIM3V2cgdo; + GBoverlapCap = here->pParam->BSIM3V2cgbo; + + xcdgb = (cdgb - GDoverlapCap); + xcddb = (cddb + capbd + GDoverlapCap); + xcdsb = cdsb; + xcdbb = -(xcdgb + xcddb + xcdsb); + xcsgb = -(cggb + cbgb + cdgb + GSoverlapCap); + xcsdb = -(cgdb + cbdb + cddb); + xcssb = (capbs + GSoverlapCap - (cgsb + cbsb + cdsb)); + xcsbb = -(xcsgb + xcsdb + xcssb); + xcggb = (cggb + GDoverlapCap + GSoverlapCap + GBoverlapCap); + xcgdb = (cgdb - GDoverlapCap); + xcgsb = (cgsb - GSoverlapCap); + xcgbb = -(xcggb + xcgdb + xcgsb); + xcbgb = (cbgb - GBoverlapCap); + xcbdb = (cbdb - capbd); + xcbsb = (cbsb - capbs); + xcbbb = -(xcbgb + xcbdb + xcbsb); + + *(here->BSIM3V2GgPtr ) += xcggb * s->real; + *(here->BSIM3V2GgPtr +1) += xcggb * s->imag; + *(here->BSIM3V2BbPtr ) += xcbbb * s->real; + *(here->BSIM3V2BbPtr +1) += xcbbb * s->imag; + *(here->BSIM3V2DPdpPtr ) += xcddb * s->real; + *(here->BSIM3V2DPdpPtr +1) += xcddb * s->imag; + *(here->BSIM3V2SPspPtr ) += xcssb * s->real; + *(here->BSIM3V2SPspPtr +1) += xcssb * s->imag; + + *(here->BSIM3V2GbPtr ) += xcgbb * s->real; + *(here->BSIM3V2GbPtr +1) += xcgbb * s->imag; + *(here->BSIM3V2GdpPtr ) += xcgdb * s->real; + *(here->BSIM3V2GdpPtr +1) += xcgdb * s->imag; + *(here->BSIM3V2GspPtr ) += xcgsb * s->real; + *(here->BSIM3V2GspPtr +1) += xcgsb * s->imag; + + *(here->BSIM3V2BgPtr ) += xcbgb * s->real; + *(here->BSIM3V2BgPtr +1) += xcbgb * s->imag; + *(here->BSIM3V2BdpPtr ) += xcbdb * s->real; + *(here->BSIM3V2BdpPtr +1) += xcbdb * s->imag; + *(here->BSIM3V2BspPtr ) += xcbsb * s->real; + *(here->BSIM3V2BspPtr +1) += xcbsb * s->imag; + + *(here->BSIM3V2DPgPtr ) += xcdgb * s->real; + *(here->BSIM3V2DPgPtr +1) += xcdgb * s->imag; + *(here->BSIM3V2DPbPtr ) += xcdbb * s->real; + *(here->BSIM3V2DPbPtr +1) += xcdbb * s->imag; + *(here->BSIM3V2DPspPtr ) += xcdsb * s->real; + *(here->BSIM3V2DPspPtr +1) += xcdsb * s->imag; + + *(here->BSIM3V2SPgPtr ) += xcsgb * s->real; + *(here->BSIM3V2SPgPtr +1) += xcsgb * s->imag; + *(here->BSIM3V2SPbPtr ) += xcsbb * s->real; + *(here->BSIM3V2SPbPtr +1) += xcsbb * s->imag; + *(here->BSIM3V2SPdpPtr ) += xcsdb * s->real; + *(here->BSIM3V2SPdpPtr +1) += xcsdb * s->imag; + + *(here->BSIM3V2DdPtr) += gdpr; + *(here->BSIM3V2DdpPtr) -= gdpr; + *(here->BSIM3V2DPdPtr) -= gdpr; + + *(here->BSIM3V2SsPtr) += gspr; + *(here->BSIM3V2SspPtr) -= gspr; + *(here->BSIM3V2SPsPtr) -= gspr; + + *(here->BSIM3V2BgPtr) -= here->BSIM3V2gbgs; + *(here->BSIM3V2BbPtr) += gbd + gbs - here->BSIM3V2gbbs; + *(here->BSIM3V2BdpPtr) -= gbd - gbbdp; + *(here->BSIM3V2BspPtr) -= gbs - gbbsp; + + *(here->BSIM3V2DPgPtr) += Gm + dxpart * xgtg + + T1 * ddxpart_dVg + gbdpg; + *(here->BSIM3V2DPdpPtr) += gdpr + gds + gbd + RevSum + + dxpart * xgtd + T1 * ddxpart_dVd + gbdpdp; + *(here->BSIM3V2DPspPtr) -= gds + FwdSum - dxpart * xgts + - T1 * ddxpart_dVs - gbdpsp; + *(here->BSIM3V2DPbPtr) -= gbd - Gmbs - dxpart * xgtb + - T1 * ddxpart_dVb - gbdpb; + + *(here->BSIM3V2SPgPtr) -= Gm - sxpart * xgtg + - T1 * dsxpart_dVg - gbspg; + *(here->BSIM3V2SPspPtr) += gspr + gds + gbs + FwdSum + + sxpart * xgts + T1 * dsxpart_dVs + gbspsp; + *(here->BSIM3V2SPbPtr) -= gbs + Gmbs - sxpart * xgtb + - T1 * dsxpart_dVb - gbspb; + *(here->BSIM3V2SPdpPtr) -= gds + RevSum - sxpart * xgtd + - T1 * dsxpart_dVd - gbspdp; + + *(here->BSIM3V2GgPtr) -= xgtg; + *(here->BSIM3V2GbPtr) -= xgtb; + *(here->BSIM3V2GdpPtr) -= xgtd; + *(here->BSIM3V2GspPtr) -= xgts; + + if (here->BSIM3V2nqsMod) + { *(here->BSIM3V2QqPtr ) += s->real; + *(here->BSIM3V2QqPtr +1) += s->imag; + *(here->BSIM3V2QgPtr ) -= xcqgb * s->real; + *(here->BSIM3V2QgPtr +1) -= xcqgb * s->imag; + *(here->BSIM3V2QdpPtr ) -= xcqdb * s->real; + *(here->BSIM3V2QdpPtr +1) -= xcqdb * s->imag; + *(here->BSIM3V2QbPtr ) -= xcqbb * s->real; + *(here->BSIM3V2QbPtr +1) -= xcqbb * s->imag; + *(here->BSIM3V2QspPtr ) -= xcqsb * s->real; + *(here->BSIM3V2QspPtr +1) -= xcqsb * s->imag; + + *(here->BSIM3V2GqPtr) -= here->BSIM3V2gtau; + *(here->BSIM3V2DPqPtr) += dxpart * here->BSIM3V2gtau; + *(here->BSIM3V2SPqPtr) += sxpart * here->BSIM3V2gtau; + + *(here->BSIM3V2QqPtr) += here->BSIM3V2gtau; + *(here->BSIM3V2QgPtr) += xgtg; + *(here->BSIM3V2QdpPtr) += xgtd; + *(here->BSIM3V2QbPtr) += xgtb; + *(here->BSIM3V2QspPtr) += xgts; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3v2/b3v2set.c b/src/spicelib/devices/bsim3v2/b3v2set.c new file mode 100644 index 000000000..529d60867 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2set.c @@ -0,0 +1,1011 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: b3v2set.c +**********/ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define SMOOTHFACTOR 0.1 +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define PI 3.141592654 +#define Charge_q 1.60219e-19 +#define Meter2Micron 1.0e6 + +int +BSIM3V2setup(matrix,inModel,ckt,states) +register SMPmatrix *matrix; +register GENmodel *inModel; +register CKTcircuit *ckt; +int *states; +{ +register BSIM3V2model *model = (BSIM3V2model*)inModel; +register BSIM3V2instance *here; +int error; +CKTnode *tmp; + +double tmp1, tmp2; + + /* loop through all the BSIM3V2 device models */ + for( ; model != NULL; model = model->BSIM3V2nextModel ) + { +/* Default value Processing for BSIM3V2 MOSFET Models */ + if (!model->BSIM3V2typeGiven) + model->BSIM3V2type = NMOS; + if (!model->BSIM3V2mobModGiven) + model->BSIM3V2mobMod = 1; + if (!model->BSIM3V2binUnitGiven) + model->BSIM3V2binUnit = 1; + if (!model->BSIM3V2paramChkGiven) + model->BSIM3V2paramChk = 0; + if (!model->BSIM3V2capModGiven) + model->BSIM3V2capMod = 3; + if (!model->BSIM3V2noiModGiven) + model->BSIM3V2noiMod = 1; + if (!model->BSIM3V2versionGiven) + model->BSIM3V2version = 3.2; + if (!model->BSIM3V2toxGiven) + model->BSIM3V2tox = 150.0e-10; + model->BSIM3V2cox = 3.453133e-11 / model->BSIM3V2tox; + if (!model->BSIM3V2toxmGiven) + model->BSIM3V2toxm = model->BSIM3V2tox; + + if (!model->BSIM3V2cdscGiven) + model->BSIM3V2cdsc = 2.4e-4; /* unit Q/V/m^2 */ + if (!model->BSIM3V2cdscbGiven) + model->BSIM3V2cdscb = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3V2cdscdGiven) + model->BSIM3V2cdscd = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3V2citGiven) + model->BSIM3V2cit = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM3V2nfactorGiven) + model->BSIM3V2nfactor = 1; + if (!model->BSIM3V2xjGiven) + model->BSIM3V2xj = .15e-6; + if (!model->BSIM3V2vsatGiven) + model->BSIM3V2vsat = 8.0e4; /* unit m/s */ + if (!model->BSIM3V2atGiven) + model->BSIM3V2at = 3.3e4; /* unit m/s */ + if (!model->BSIM3V2a0Given) + model->BSIM3V2a0 = 1.0; + if (!model->BSIM3V2agsGiven) + model->BSIM3V2ags = 0.0; + if (!model->BSIM3V2a1Given) + model->BSIM3V2a1 = 0.0; + if (!model->BSIM3V2a2Given) + model->BSIM3V2a2 = 1.0; + if (!model->BSIM3V2ketaGiven) + model->BSIM3V2keta = -0.047; /* unit / V */ + if (!model->BSIM3V2nsubGiven) + model->BSIM3V2nsub = 6.0e16; /* unit 1/cm3 */ + if (!model->BSIM3V2npeakGiven) + model->BSIM3V2npeak = 1.7e17; /* unit 1/cm3 */ + if (!model->BSIM3V2ngateGiven) + model->BSIM3V2ngate = 0; /* unit 1/cm3 */ + if (!model->BSIM3V2vbmGiven) + model->BSIM3V2vbm = -3.0; + if (!model->BSIM3V2xtGiven) + model->BSIM3V2xt = 1.55e-7; + if (!model->BSIM3V2kt1Given) + model->BSIM3V2kt1 = -0.11; /* unit V */ + if (!model->BSIM3V2kt1lGiven) + model->BSIM3V2kt1l = 0.0; /* unit V*m */ + if (!model->BSIM3V2kt2Given) + model->BSIM3V2kt2 = 0.022; /* No unit */ + if (!model->BSIM3V2k3Given) + model->BSIM3V2k3 = 80.0; + if (!model->BSIM3V2k3bGiven) + model->BSIM3V2k3b = 0.0; + if (!model->BSIM3V2w0Given) + model->BSIM3V2w0 = 2.5e-6; + if (!model->BSIM3V2nlxGiven) + model->BSIM3V2nlx = 1.74e-7; + if (!model->BSIM3V2dvt0Given) + model->BSIM3V2dvt0 = 2.2; + if (!model->BSIM3V2dvt1Given) + model->BSIM3V2dvt1 = 0.53; + if (!model->BSIM3V2dvt2Given) + model->BSIM3V2dvt2 = -0.032; /* unit 1 / V */ + + if (!model->BSIM3V2dvt0wGiven) + model->BSIM3V2dvt0w = 0.0; + if (!model->BSIM3V2dvt1wGiven) + model->BSIM3V2dvt1w = 5.3e6; + if (!model->BSIM3V2dvt2wGiven) + model->BSIM3V2dvt2w = -0.032; + + if (!model->BSIM3V2droutGiven) + model->BSIM3V2drout = 0.56; + if (!model->BSIM3V2dsubGiven) + model->BSIM3V2dsub = model->BSIM3V2drout; + if (!model->BSIM3V2vth0Given) + model->BSIM3V2vth0 = (model->BSIM3V2type == NMOS) ? 0.7 : -0.7; + if (!model->BSIM3V2uaGiven) + model->BSIM3V2ua = 2.25e-9; /* unit m/V */ + if (!model->BSIM3V2ua1Given) + model->BSIM3V2ua1 = 4.31e-9; /* unit m/V */ + if (!model->BSIM3V2ubGiven) + model->BSIM3V2ub = 5.87e-19; /* unit (m/V)**2 */ + if (!model->BSIM3V2ub1Given) + model->BSIM3V2ub1 = -7.61e-18; /* unit (m/V)**2 */ + if (!model->BSIM3V2ucGiven) + model->BSIM3V2uc = (model->BSIM3V2mobMod == 3) ? -0.0465 : -0.0465e-9; + if (!model->BSIM3V2uc1Given) + model->BSIM3V2uc1 = (model->BSIM3V2mobMod == 3) ? -0.056 : -0.056e-9; + if (!model->BSIM3V2u0Given) + model->BSIM3V2u0 = (model->BSIM3V2type == NMOS) ? 0.067 : 0.025; + if (!model->BSIM3V2uteGiven) + model->BSIM3V2ute = -1.5; + if (!model->BSIM3V2voffGiven) + model->BSIM3V2voff = -0.08; + if (!model->BSIM3V2deltaGiven) + model->BSIM3V2delta = 0.01; + if (!model->BSIM3V2rdswGiven) + model->BSIM3V2rdsw = 0; + if (!model->BSIM3V2prwgGiven) + model->BSIM3V2prwg = 0.0; /* unit 1/V */ + if (!model->BSIM3V2prwbGiven) + model->BSIM3V2prwb = 0.0; + if (!model->BSIM3V2prtGiven) + if (!model->BSIM3V2prtGiven) + model->BSIM3V2prt = 0.0; + if (!model->BSIM3V2eta0Given) + model->BSIM3V2eta0 = 0.08; /* no unit */ + if (!model->BSIM3V2etabGiven) + model->BSIM3V2etab = -0.07; /* unit 1/V */ + if (!model->BSIM3V2pclmGiven) + model->BSIM3V2pclm = 1.3; /* no unit */ + if (!model->BSIM3V2pdibl1Given) + model->BSIM3V2pdibl1 = .39; /* no unit */ + if (!model->BSIM3V2pdibl2Given) + model->BSIM3V2pdibl2 = 0.0086; /* no unit */ + if (!model->BSIM3V2pdiblbGiven) + model->BSIM3V2pdiblb = 0.0; /* 1/V */ + if (!model->BSIM3V2pscbe1Given) + model->BSIM3V2pscbe1 = 4.24e8; + if (!model->BSIM3V2pscbe2Given) + model->BSIM3V2pscbe2 = 1.0e-5; + if (!model->BSIM3V2pvagGiven) + model->BSIM3V2pvag = 0.0; + if (!model->BSIM3V2wrGiven) + model->BSIM3V2wr = 1.0; + if (!model->BSIM3V2dwgGiven) + model->BSIM3V2dwg = 0.0; + if (!model->BSIM3V2dwbGiven) + model->BSIM3V2dwb = 0.0; + if (!model->BSIM3V2b0Given) + model->BSIM3V2b0 = 0.0; + if (!model->BSIM3V2b1Given) + model->BSIM3V2b1 = 0.0; + if (!model->BSIM3V2alpha0Given) + model->BSIM3V2alpha0 = 0.0; + if (!model->BSIM3V2alpha1Given) + model->BSIM3V2alpha1 = 0.0; + if (!model->BSIM3V2beta0Given) + model->BSIM3V2beta0 = 30.0; + if (!model->BSIM3V2ijthGiven) + model->BSIM3V2ijth = 0.1; /* unit A */ + + if (!model->BSIM3V2elmGiven) + model->BSIM3V2elm = 5.0; + if (!model->BSIM3V2cgslGiven) + model->BSIM3V2cgsl = 0.0; + if (!model->BSIM3V2cgdlGiven) + model->BSIM3V2cgdl = 0.0; + if (!model->BSIM3V2ckappaGiven) + model->BSIM3V2ckappa = 0.6; + if (!model->BSIM3V2clcGiven) + model->BSIM3V2clc = 0.1e-6; + if (!model->BSIM3V2cleGiven) + model->BSIM3V2cle = 0.6; + if (!model->BSIM3V2vfbcvGiven) + model->BSIM3V2vfbcv = -1.0; + if (!model->BSIM3V2acdeGiven) + model->BSIM3V2acde = 1.0; + if (!model->BSIM3V2moinGiven) + model->BSIM3V2moin = 15.0; + if (!model->BSIM3V2noffGiven) + model->BSIM3V2noff = 1.0; + if (!model->BSIM3V2voffcvGiven) + model->BSIM3V2voffcv = 0.0; + if (!model->BSIM3V2tcjGiven) + model->BSIM3V2tcj = 0.0; + if (!model->BSIM3V2tpbGiven) + model->BSIM3V2tpb = 0.0; + if (!model->BSIM3V2tcjswGiven) + model->BSIM3V2tcjsw = 0.0; + if (!model->BSIM3V2tpbswGiven) + model->BSIM3V2tpbsw = 0.0; + if (!model->BSIM3V2tcjswgGiven) + model->BSIM3V2tcjswg = 0.0; + if (!model->BSIM3V2tpbswgGiven) + model->BSIM3V2tpbswg = 0.0; + + /* Length dependence */ + if (!model->BSIM3V2lcdscGiven) + model->BSIM3V2lcdsc = 0.0; + if (!model->BSIM3V2lcdscbGiven) + model->BSIM3V2lcdscb = 0.0; + if (!model->BSIM3V2lcdscdGiven) + model->BSIM3V2lcdscd = 0.0; + if (!model->BSIM3V2lcitGiven) + model->BSIM3V2lcit = 0.0; + if (!model->BSIM3V2lnfactorGiven) + model->BSIM3V2lnfactor = 0.0; + if (!model->BSIM3V2lxjGiven) + model->BSIM3V2lxj = 0.0; + if (!model->BSIM3V2lvsatGiven) + model->BSIM3V2lvsat = 0.0; + if (!model->BSIM3V2latGiven) + model->BSIM3V2lat = 0.0; + if (!model->BSIM3V2la0Given) + model->BSIM3V2la0 = 0.0; + if (!model->BSIM3V2lagsGiven) + model->BSIM3V2lags = 0.0; + if (!model->BSIM3V2la1Given) + model->BSIM3V2la1 = 0.0; + if (!model->BSIM3V2la2Given) + model->BSIM3V2la2 = 0.0; + if (!model->BSIM3V2lketaGiven) + model->BSIM3V2lketa = 0.0; + if (!model->BSIM3V2lnsubGiven) + model->BSIM3V2lnsub = 0.0; + if (!model->BSIM3V2lnpeakGiven) + model->BSIM3V2lnpeak = 0.0; + if (!model->BSIM3V2lngateGiven) + model->BSIM3V2lngate = 0.0; + if (!model->BSIM3V2lvbmGiven) + model->BSIM3V2lvbm = 0.0; + if (!model->BSIM3V2lxtGiven) + model->BSIM3V2lxt = 0.0; + if (!model->BSIM3V2lkt1Given) + model->BSIM3V2lkt1 = 0.0; + if (!model->BSIM3V2lkt1lGiven) + model->BSIM3V2lkt1l = 0.0; + if (!model->BSIM3V2lkt2Given) + model->BSIM3V2lkt2 = 0.0; + if (!model->BSIM3V2lk3Given) + model->BSIM3V2lk3 = 0.0; + if (!model->BSIM3V2lk3bGiven) + model->BSIM3V2lk3b = 0.0; + if (!model->BSIM3V2lw0Given) + model->BSIM3V2lw0 = 0.0; + if (!model->BSIM3V2lnlxGiven) + model->BSIM3V2lnlx = 0.0; + if (!model->BSIM3V2ldvt0Given) + model->BSIM3V2ldvt0 = 0.0; + if (!model->BSIM3V2ldvt1Given) + model->BSIM3V2ldvt1 = 0.0; + if (!model->BSIM3V2ldvt2Given) + model->BSIM3V2ldvt2 = 0.0; + if (!model->BSIM3V2ldvt0wGiven) + model->BSIM3V2ldvt0w = 0.0; + if (!model->BSIM3V2ldvt1wGiven) + model->BSIM3V2ldvt1w = 0.0; + if (!model->BSIM3V2ldvt2wGiven) + model->BSIM3V2ldvt2w = 0.0; + if (!model->BSIM3V2ldroutGiven) + model->BSIM3V2ldrout = 0.0; + if (!model->BSIM3V2ldsubGiven) + model->BSIM3V2ldsub = 0.0; + if (!model->BSIM3V2lvth0Given) + model->BSIM3V2lvth0 = 0.0; + if (!model->BSIM3V2luaGiven) + model->BSIM3V2lua = 0.0; + if (!model->BSIM3V2lua1Given) + model->BSIM3V2lua1 = 0.0; + if (!model->BSIM3V2lubGiven) + model->BSIM3V2lub = 0.0; + if (!model->BSIM3V2lub1Given) + model->BSIM3V2lub1 = 0.0; + if (!model->BSIM3V2lucGiven) + model->BSIM3V2luc = 0.0; + if (!model->BSIM3V2luc1Given) + model->BSIM3V2luc1 = 0.0; + if (!model->BSIM3V2lu0Given) + model->BSIM3V2lu0 = 0.0; + if (!model->BSIM3V2luteGiven) + model->BSIM3V2lute = 0.0; + if (!model->BSIM3V2lvoffGiven) + model->BSIM3V2lvoff = 0.0; + if (!model->BSIM3V2ldeltaGiven) + model->BSIM3V2ldelta = 0.0; + if (!model->BSIM3V2lrdswGiven) + model->BSIM3V2lrdsw = 0.0; + if (!model->BSIM3V2lprwbGiven) + model->BSIM3V2lprwb = 0.0; + if (!model->BSIM3V2lprwgGiven) + model->BSIM3V2lprwg = 0.0; + if (!model->BSIM3V2lprtGiven) + model->BSIM3V2lprt = 0.0; + if (!model->BSIM3V2leta0Given) + model->BSIM3V2leta0 = 0.0; + if (!model->BSIM3V2letabGiven) + model->BSIM3V2letab = -0.0; + if (!model->BSIM3V2lpclmGiven) + model->BSIM3V2lpclm = 0.0; + if (!model->BSIM3V2lpdibl1Given) + model->BSIM3V2lpdibl1 = 0.0; + if (!model->BSIM3V2lpdibl2Given) + model->BSIM3V2lpdibl2 = 0.0; + if (!model->BSIM3V2lpdiblbGiven) + model->BSIM3V2lpdiblb = 0.0; + if (!model->BSIM3V2lpscbe1Given) + model->BSIM3V2lpscbe1 = 0.0; + if (!model->BSIM3V2lpscbe2Given) + model->BSIM3V2lpscbe2 = 0.0; + if (!model->BSIM3V2lpvagGiven) + model->BSIM3V2lpvag = 0.0; + if (!model->BSIM3V2lwrGiven) + model->BSIM3V2lwr = 0.0; + if (!model->BSIM3V2ldwgGiven) + model->BSIM3V2ldwg = 0.0; + if (!model->BSIM3V2ldwbGiven) + model->BSIM3V2ldwb = 0.0; + if (!model->BSIM3V2lb0Given) + model->BSIM3V2lb0 = 0.0; + if (!model->BSIM3V2lb1Given) + model->BSIM3V2lb1 = 0.0; + if (!model->BSIM3V2lalpha0Given) + model->BSIM3V2lalpha0 = 0.0; + if (!model->BSIM3V2lalpha1Given) + model->BSIM3V2lalpha1 = 0.0; + if (!model->BSIM3V2lbeta0Given) + model->BSIM3V2lbeta0 = 0.0; + if (!model->BSIM3V2lvfbGiven) + model->BSIM3V2lvfb = 0.0; + + if (!model->BSIM3V2lelmGiven) + model->BSIM3V2lelm = 0.0; + if (!model->BSIM3V2lcgslGiven) + model->BSIM3V2lcgsl = 0.0; + if (!model->BSIM3V2lcgdlGiven) + model->BSIM3V2lcgdl = 0.0; + if (!model->BSIM3V2lckappaGiven) + model->BSIM3V2lckappa = 0.0; + if (!model->BSIM3V2lclcGiven) + model->BSIM3V2lclc = 0.0; + if (!model->BSIM3V2lcleGiven) + model->BSIM3V2lcle = 0.0; + if (!model->BSIM3V2lcfGiven) + model->BSIM3V2lcf = 0.0; + if (!model->BSIM3V2lvfbcvGiven) + model->BSIM3V2lvfbcv = 0.0; + if (!model->BSIM3V2lacdeGiven) + model->BSIM3V2lacde = 0.0; + if (!model->BSIM3V2lmoinGiven) + model->BSIM3V2lmoin = 0.0; + if (!model->BSIM3V2lnoffGiven) + model->BSIM3V2lnoff = 0.0; + if (!model->BSIM3V2lvoffcvGiven) + model->BSIM3V2lvoffcv = 0.0; + + /* Width dependence */ + if (!model->BSIM3V2wcdscGiven) + model->BSIM3V2wcdsc = 0.0; + if (!model->BSIM3V2wcdscbGiven) + model->BSIM3V2wcdscb = 0.0; + if (!model->BSIM3V2wcdscdGiven) + model->BSIM3V2wcdscd = 0.0; + if (!model->BSIM3V2wcitGiven) + model->BSIM3V2wcit = 0.0; + if (!model->BSIM3V2wnfactorGiven) + model->BSIM3V2wnfactor = 0.0; + if (!model->BSIM3V2wxjGiven) + model->BSIM3V2wxj = 0.0; + if (!model->BSIM3V2wvsatGiven) + model->BSIM3V2wvsat = 0.0; + if (!model->BSIM3V2watGiven) + model->BSIM3V2wat = 0.0; + if (!model->BSIM3V2wa0Given) + model->BSIM3V2wa0 = 0.0; + if (!model->BSIM3V2wagsGiven) + model->BSIM3V2wags = 0.0; + if (!model->BSIM3V2wa1Given) + model->BSIM3V2wa1 = 0.0; + if (!model->BSIM3V2wa2Given) + model->BSIM3V2wa2 = 0.0; + if (!model->BSIM3V2wketaGiven) + model->BSIM3V2wketa = 0.0; + if (!model->BSIM3V2wnsubGiven) + model->BSIM3V2wnsub = 0.0; + if (!model->BSIM3V2wnpeakGiven) + model->BSIM3V2wnpeak = 0.0; + if (!model->BSIM3V2wngateGiven) + model->BSIM3V2wngate = 0.0; + if (!model->BSIM3V2wvbmGiven) + model->BSIM3V2wvbm = 0.0; + if (!model->BSIM3V2wxtGiven) + model->BSIM3V2wxt = 0.0; + if (!model->BSIM3V2wkt1Given) + model->BSIM3V2wkt1 = 0.0; + if (!model->BSIM3V2wkt1lGiven) + model->BSIM3V2wkt1l = 0.0; + if (!model->BSIM3V2wkt2Given) + model->BSIM3V2wkt2 = 0.0; + if (!model->BSIM3V2wk3Given) + model->BSIM3V2wk3 = 0.0; + if (!model->BSIM3V2wk3bGiven) + model->BSIM3V2wk3b = 0.0; + if (!model->BSIM3V2ww0Given) + model->BSIM3V2ww0 = 0.0; + if (!model->BSIM3V2wnlxGiven) + model->BSIM3V2wnlx = 0.0; + if (!model->BSIM3V2wdvt0Given) + model->BSIM3V2wdvt0 = 0.0; + if (!model->BSIM3V2wdvt1Given) + model->BSIM3V2wdvt1 = 0.0; + if (!model->BSIM3V2wdvt2Given) + model->BSIM3V2wdvt2 = 0.0; + if (!model->BSIM3V2wdvt0wGiven) + model->BSIM3V2wdvt0w = 0.0; + if (!model->BSIM3V2wdvt1wGiven) + model->BSIM3V2wdvt1w = 0.0; + if (!model->BSIM3V2wdvt2wGiven) + model->BSIM3V2wdvt2w = 0.0; + if (!model->BSIM3V2wdroutGiven) + model->BSIM3V2wdrout = 0.0; + if (!model->BSIM3V2wdsubGiven) + model->BSIM3V2wdsub = 0.0; + if (!model->BSIM3V2wvth0Given) + model->BSIM3V2wvth0 = 0.0; + if (!model->BSIM3V2wuaGiven) + model->BSIM3V2wua = 0.0; + if (!model->BSIM3V2wua1Given) + model->BSIM3V2wua1 = 0.0; + if (!model->BSIM3V2wubGiven) + model->BSIM3V2wub = 0.0; + if (!model->BSIM3V2wub1Given) + model->BSIM3V2wub1 = 0.0; + if (!model->BSIM3V2wucGiven) + model->BSIM3V2wuc = 0.0; + if (!model->BSIM3V2wuc1Given) + model->BSIM3V2wuc1 = 0.0; + if (!model->BSIM3V2wu0Given) + model->BSIM3V2wu0 = 0.0; + if (!model->BSIM3V2wuteGiven) + model->BSIM3V2wute = 0.0; + if (!model->BSIM3V2wvoffGiven) + model->BSIM3V2wvoff = 0.0; + if (!model->BSIM3V2wdeltaGiven) + model->BSIM3V2wdelta = 0.0; + if (!model->BSIM3V2wrdswGiven) + model->BSIM3V2wrdsw = 0.0; + if (!model->BSIM3V2wprwbGiven) + model->BSIM3V2wprwb = 0.0; + if (!model->BSIM3V2wprwgGiven) + model->BSIM3V2wprwg = 0.0; + if (!model->BSIM3V2wprtGiven) + model->BSIM3V2wprt = 0.0; + if (!model->BSIM3V2weta0Given) + model->BSIM3V2weta0 = 0.0; + if (!model->BSIM3V2wetabGiven) + model->BSIM3V2wetab = 0.0; + if (!model->BSIM3V2wpclmGiven) + model->BSIM3V2wpclm = 0.0; + if (!model->BSIM3V2wpdibl1Given) + model->BSIM3V2wpdibl1 = 0.0; + if (!model->BSIM3V2wpdibl2Given) + model->BSIM3V2wpdibl2 = 0.0; + if (!model->BSIM3V2wpdiblbGiven) + model->BSIM3V2wpdiblb = 0.0; + if (!model->BSIM3V2wpscbe1Given) + model->BSIM3V2wpscbe1 = 0.0; + if (!model->BSIM3V2wpscbe2Given) + model->BSIM3V2wpscbe2 = 0.0; + if (!model->BSIM3V2wpvagGiven) + model->BSIM3V2wpvag = 0.0; + if (!model->BSIM3V2wwrGiven) + model->BSIM3V2wwr = 0.0; + if (!model->BSIM3V2wdwgGiven) + model->BSIM3V2wdwg = 0.0; + if (!model->BSIM3V2wdwbGiven) + model->BSIM3V2wdwb = 0.0; + if (!model->BSIM3V2wb0Given) + model->BSIM3V2wb0 = 0.0; + if (!model->BSIM3V2wb1Given) + model->BSIM3V2wb1 = 0.0; + if (!model->BSIM3V2walpha0Given) + model->BSIM3V2walpha0 = 0.0; + if (!model->BSIM3V2walpha1Given) + model->BSIM3V2walpha1 = 0.0; + if (!model->BSIM3V2wbeta0Given) + model->BSIM3V2wbeta0 = 0.0; + if (!model->BSIM3V2wvfbGiven) + model->BSIM3V2wvfb = 0.0; + + if (!model->BSIM3V2welmGiven) + model->BSIM3V2welm = 0.0; + if (!model->BSIM3V2wcgslGiven) + model->BSIM3V2wcgsl = 0.0; + if (!model->BSIM3V2wcgdlGiven) + model->BSIM3V2wcgdl = 0.0; + if (!model->BSIM3V2wckappaGiven) + model->BSIM3V2wckappa = 0.0; + if (!model->BSIM3V2wcfGiven) + model->BSIM3V2wcf = 0.0; + if (!model->BSIM3V2wclcGiven) + model->BSIM3V2wclc = 0.0; + if (!model->BSIM3V2wcleGiven) + model->BSIM3V2wcle = 0.0; + if (!model->BSIM3V2wvfbcvGiven) + model->BSIM3V2wvfbcv = 0.0; + if (!model->BSIM3V2wacdeGiven) + model->BSIM3V2wacde = 0.0; + if (!model->BSIM3V2wmoinGiven) + model->BSIM3V2wmoin = 0.0; + if (!model->BSIM3V2wnoffGiven) + model->BSIM3V2wnoff = 0.0; + if (!model->BSIM3V2wvoffcvGiven) + model->BSIM3V2wvoffcv = 0.0; + + /* Cross-term dependence */ + if (!model->BSIM3V2pcdscGiven) + model->BSIM3V2pcdsc = 0.0; + if (!model->BSIM3V2pcdscbGiven) + model->BSIM3V2pcdscb = 0.0; + if (!model->BSIM3V2pcdscdGiven) + model->BSIM3V2pcdscd = 0.0; + if (!model->BSIM3V2pcitGiven) + model->BSIM3V2pcit = 0.0; + if (!model->BSIM3V2pnfactorGiven) + model->BSIM3V2pnfactor = 0.0; + if (!model->BSIM3V2pxjGiven) + model->BSIM3V2pxj = 0.0; + if (!model->BSIM3V2pvsatGiven) + model->BSIM3V2pvsat = 0.0; + if (!model->BSIM3V2patGiven) + model->BSIM3V2pat = 0.0; + if (!model->BSIM3V2pa0Given) + model->BSIM3V2pa0 = 0.0; + + if (!model->BSIM3V2pagsGiven) + model->BSIM3V2pags = 0.0; + if (!model->BSIM3V2pa1Given) + model->BSIM3V2pa1 = 0.0; + if (!model->BSIM3V2pa2Given) + model->BSIM3V2pa2 = 0.0; + if (!model->BSIM3V2pketaGiven) + model->BSIM3V2pketa = 0.0; + if (!model->BSIM3V2pnsubGiven) + model->BSIM3V2pnsub = 0.0; + if (!model->BSIM3V2pnpeakGiven) + model->BSIM3V2pnpeak = 0.0; + if (!model->BSIM3V2pngateGiven) + model->BSIM3V2pngate = 0.0; + if (!model->BSIM3V2pvbmGiven) + model->BSIM3V2pvbm = 0.0; + if (!model->BSIM3V2pxtGiven) + model->BSIM3V2pxt = 0.0; + if (!model->BSIM3V2pkt1Given) + model->BSIM3V2pkt1 = 0.0; + if (!model->BSIM3V2pkt1lGiven) + model->BSIM3V2pkt1l = 0.0; + if (!model->BSIM3V2pkt2Given) + model->BSIM3V2pkt2 = 0.0; + if (!model->BSIM3V2pk3Given) + model->BSIM3V2pk3 = 0.0; + if (!model->BSIM3V2pk3bGiven) + model->BSIM3V2pk3b = 0.0; + if (!model->BSIM3V2pw0Given) + model->BSIM3V2pw0 = 0.0; + if (!model->BSIM3V2pnlxGiven) + model->BSIM3V2pnlx = 0.0; + if (!model->BSIM3V2pdvt0Given) + model->BSIM3V2pdvt0 = 0.0; + if (!model->BSIM3V2pdvt1Given) + model->BSIM3V2pdvt1 = 0.0; + if (!model->BSIM3V2pdvt2Given) + model->BSIM3V2pdvt2 = 0.0; + if (!model->BSIM3V2pdvt0wGiven) + model->BSIM3V2pdvt0w = 0.0; + if (!model->BSIM3V2pdvt1wGiven) + model->BSIM3V2pdvt1w = 0.0; + if (!model->BSIM3V2pdvt2wGiven) + model->BSIM3V2pdvt2w = 0.0; + if (!model->BSIM3V2pdroutGiven) + model->BSIM3V2pdrout = 0.0; + if (!model->BSIM3V2pdsubGiven) + model->BSIM3V2pdsub = 0.0; + if (!model->BSIM3V2pvth0Given) + model->BSIM3V2pvth0 = 0.0; + if (!model->BSIM3V2puaGiven) + model->BSIM3V2pua = 0.0; + if (!model->BSIM3V2pua1Given) + model->BSIM3V2pua1 = 0.0; + if (!model->BSIM3V2pubGiven) + model->BSIM3V2pub = 0.0; + if (!model->BSIM3V2pub1Given) + model->BSIM3V2pub1 = 0.0; + if (!model->BSIM3V2pucGiven) + model->BSIM3V2puc = 0.0; + if (!model->BSIM3V2puc1Given) + model->BSIM3V2puc1 = 0.0; + if (!model->BSIM3V2pu0Given) + model->BSIM3V2pu0 = 0.0; + if (!model->BSIM3V2puteGiven) + model->BSIM3V2pute = 0.0; + if (!model->BSIM3V2pvoffGiven) + model->BSIM3V2pvoff = 0.0; + if (!model->BSIM3V2pdeltaGiven) + model->BSIM3V2pdelta = 0.0; + if (!model->BSIM3V2prdswGiven) + model->BSIM3V2prdsw = 0.0; + if (!model->BSIM3V2pprwbGiven) + model->BSIM3V2pprwb = 0.0; + if (!model->BSIM3V2pprwgGiven) + model->BSIM3V2pprwg = 0.0; + if (!model->BSIM3V2pprtGiven) + model->BSIM3V2pprt = 0.0; + if (!model->BSIM3V2peta0Given) + model->BSIM3V2peta0 = 0.0; + if (!model->BSIM3V2petabGiven) + model->BSIM3V2petab = 0.0; + if (!model->BSIM3V2ppclmGiven) + model->BSIM3V2ppclm = 0.0; + if (!model->BSIM3V2ppdibl1Given) + model->BSIM3V2ppdibl1 = 0.0; + if (!model->BSIM3V2ppdibl2Given) + model->BSIM3V2ppdibl2 = 0.0; + if (!model->BSIM3V2ppdiblbGiven) + model->BSIM3V2ppdiblb = 0.0; + if (!model->BSIM3V2ppscbe1Given) + model->BSIM3V2ppscbe1 = 0.0; + if (!model->BSIM3V2ppscbe2Given) + model->BSIM3V2ppscbe2 = 0.0; + if (!model->BSIM3V2ppvagGiven) + model->BSIM3V2ppvag = 0.0; + if (!model->BSIM3V2pwrGiven) + model->BSIM3V2pwr = 0.0; + if (!model->BSIM3V2pdwgGiven) + model->BSIM3V2pdwg = 0.0; + if (!model->BSIM3V2pdwbGiven) + model->BSIM3V2pdwb = 0.0; + if (!model->BSIM3V2pb0Given) + model->BSIM3V2pb0 = 0.0; + if (!model->BSIM3V2pb1Given) + model->BSIM3V2pb1 = 0.0; + if (!model->BSIM3V2palpha0Given) + model->BSIM3V2palpha0 = 0.0; + if (!model->BSIM3V2palpha1Given) + model->BSIM3V2palpha1 = 0.0; + if (!model->BSIM3V2pbeta0Given) + model->BSIM3V2pbeta0 = 0.0; + if (!model->BSIM3V2pvfbGiven) + model->BSIM3V2pvfb = 0.0; + + if (!model->BSIM3V2pelmGiven) + model->BSIM3V2pelm = 0.0; + if (!model->BSIM3V2pcgslGiven) + model->BSIM3V2pcgsl = 0.0; + if (!model->BSIM3V2pcgdlGiven) + model->BSIM3V2pcgdl = 0.0; + if (!model->BSIM3V2pckappaGiven) + model->BSIM3V2pckappa = 0.0; + if (!model->BSIM3V2pcfGiven) + model->BSIM3V2pcf = 0.0; + if (!model->BSIM3V2pclcGiven) + model->BSIM3V2pclc = 0.0; + if (!model->BSIM3V2pcleGiven) + model->BSIM3V2pcle = 0.0; + if (!model->BSIM3V2pvfbcvGiven) + model->BSIM3V2pvfbcv = 0.0; + if (!model->BSIM3V2pacdeGiven) + model->BSIM3V2pacde = 0.0; + if (!model->BSIM3V2pmoinGiven) + model->BSIM3V2pmoin = 0.0; + if (!model->BSIM3V2pnoffGiven) + model->BSIM3V2pnoff = 0.0; + if (!model->BSIM3V2pvoffcvGiven) + model->BSIM3V2pvoffcv = 0.0; + + /* unit degree celcius */ + if (!model->BSIM3V2tnomGiven) + model->BSIM3V2tnom = ckt->CKTnomTemp; + /* else + model->BSIM3V2tnom = model->BSIM3V2tnom + 273.15; */ + if (!model->BSIM3V2LintGiven) + model->BSIM3V2Lint = 0.0; + if (!model->BSIM3V2LlGiven) + model->BSIM3V2Ll = 0.0; + if (!model->BSIM3V2LlcGiven) + model->BSIM3V2Llc = model->BSIM3V2Ll; + if (!model->BSIM3V2LlnGiven) + model->BSIM3V2Lln = 1.0; + if (!model->BSIM3V2LwGiven) + model->BSIM3V2Lw = 0.0; + if (!model->BSIM3V2LwcGiven) + model->BSIM3V2Lwc = model->BSIM3V2Lw; + if (!model->BSIM3V2LwnGiven) + model->BSIM3V2Lwn = 1.0; + if (!model->BSIM3V2LwlGiven) + model->BSIM3V2Lwl = 0.0; + if (!model->BSIM3V2LwlcGiven) + model->BSIM3V2Lwlc = model->BSIM3V2Lwl; + if (!model->BSIM3V2LminGiven) + model->BSIM3V2Lmin = 0.0; + if (!model->BSIM3V2LmaxGiven) + model->BSIM3V2Lmax = 1.0; + if (!model->BSIM3V2WintGiven) + model->BSIM3V2Wint = 0.0; + if (!model->BSIM3V2WlGiven) + model->BSIM3V2Wl = 0.0; + if (!model->BSIM3V2WlcGiven) + model->BSIM3V2Wlc = model->BSIM3V2Wl; + if (!model->BSIM3V2WlnGiven) + model->BSIM3V2Wln = 1.0; + if (!model->BSIM3V2WwGiven) + model->BSIM3V2Ww = 0.0; + if (!model->BSIM3V2WwcGiven) + model->BSIM3V2Wwc = model->BSIM3V2Ww; + if (!model->BSIM3V2WwnGiven) + model->BSIM3V2Wwn = 1.0; + if (!model->BSIM3V2WwlGiven) + model->BSIM3V2Wwl = 0.0; + if (!model->BSIM3V2WwlcGiven) + model->BSIM3V2Wwlc = model->BSIM3V2Wwl; + if (!model->BSIM3V2WminGiven) + model->BSIM3V2Wmin = 0.0; + if (!model->BSIM3V2WmaxGiven) + model->BSIM3V2Wmax = 1.0; + if (!model->BSIM3V2dwcGiven) + model->BSIM3V2dwc = model->BSIM3V2Wint; + if (!model->BSIM3V2dlcGiven) + model->BSIM3V2dlc = model->BSIM3V2Lint; + if (!model->BSIM3V2cfGiven) + model->BSIM3V2cf = 2.0 * EPSOX / PI + * log(1.0 + 0.4e-6 / model->BSIM3V2tox); + if (!model->BSIM3V2cgdoGiven) + { if (model->BSIM3V2dlcGiven && (model->BSIM3V2dlc > 0.0)) + { model->BSIM3V2cgdo = model->BSIM3V2dlc * model->BSIM3V2cox + - model->BSIM3V2cgdl ; + } + else + model->BSIM3V2cgdo = 0.6 * model->BSIM3V2xj * model->BSIM3V2cox; + } + if (!model->BSIM3V2cgsoGiven) + { if (model->BSIM3V2dlcGiven && (model->BSIM3V2dlc > 0.0)) + { model->BSIM3V2cgso = model->BSIM3V2dlc * model->BSIM3V2cox + - model->BSIM3V2cgsl ; + } + else + model->BSIM3V2cgso = 0.6 * model->BSIM3V2xj * model->BSIM3V2cox; + } + + if (!model->BSIM3V2cgboGiven) + { model->BSIM3V2cgbo = 2.0 * model->BSIM3V2dwc * model->BSIM3V2cox; + } + if (!model->BSIM3V2xpartGiven) + model->BSIM3V2xpart = 0.0; + if (!model->BSIM3V2sheetResistanceGiven) + model->BSIM3V2sheetResistance = 0.0; + if (!model->BSIM3V2unitAreaJctCapGiven) + model->BSIM3V2unitAreaJctCap = 5.0E-4; + if (!model->BSIM3V2unitLengthSidewallJctCapGiven) + model->BSIM3V2unitLengthSidewallJctCap = 5.0E-10; + if (!model->BSIM3V2unitLengthGateSidewallJctCapGiven) + model->BSIM3V2unitLengthGateSidewallJctCap = model->BSIM3V2unitLengthSidewallJctCap ; + if (!model->BSIM3V2jctSatCurDensityGiven) + model->BSIM3V2jctSatCurDensity = 1.0E-4; + if (!model->BSIM3V2jctSidewallSatCurDensityGiven) + model->BSIM3V2jctSidewallSatCurDensity = 0.0; + if (!model->BSIM3V2bulkJctPotentialGiven) + model->BSIM3V2bulkJctPotential = 1.0; + if (!model->BSIM3V2sidewallJctPotentialGiven) + model->BSIM3V2sidewallJctPotential = 1.0; + if (!model->BSIM3V2GatesidewallJctPotentialGiven) + model->BSIM3V2GatesidewallJctPotential = model->BSIM3V2sidewallJctPotential; + if (!model->BSIM3V2bulkJctBotGradingCoeffGiven) + model->BSIM3V2bulkJctBotGradingCoeff = 0.5; + if (!model->BSIM3V2bulkJctSideGradingCoeffGiven) + model->BSIM3V2bulkJctSideGradingCoeff = 0.33; + if (!model->BSIM3V2bulkJctGateSideGradingCoeffGiven) + model->BSIM3V2bulkJctGateSideGradingCoeff = model->BSIM3V2bulkJctSideGradingCoeff; + if (!model->BSIM3V2jctEmissionCoeffGiven) + model->BSIM3V2jctEmissionCoeff = 1.0; + if (!model->BSIM3V2jctTempExponentGiven) + model->BSIM3V2jctTempExponent = 3.0; + if (!model->BSIM3V2oxideTrapDensityAGiven) + { if (model->BSIM3V2type == NMOS) + model->BSIM3V2oxideTrapDensityA = 1e20; + else + model->BSIM3V2oxideTrapDensityA=9.9e18; + } + if (!model->BSIM3V2oxideTrapDensityBGiven) + { if (model->BSIM3V2type == NMOS) + model->BSIM3V2oxideTrapDensityB = 5e4; + else + model->BSIM3V2oxideTrapDensityB = 2.4e3; + } + if (!model->BSIM3V2oxideTrapDensityCGiven) + { if (model->BSIM3V2type == NMOS) + model->BSIM3V2oxideTrapDensityC = -1.4e-12; + else + model->BSIM3V2oxideTrapDensityC = 1.4e-12; + + } + if (!model->BSIM3V2emGiven) + model->BSIM3V2em = 4.1e7; /* V/m */ + if (!model->BSIM3V2efGiven) + model->BSIM3V2ef = 1.0; + if (!model->BSIM3V2afGiven) + model->BSIM3V2af = 1.0; + if (!model->BSIM3V2kfGiven) + model->BSIM3V2kf = 0.0; + /* loop through all the instances of the model */ + for (here = model->BSIM3V2instances; here != NULL ; + here=here->BSIM3V2nextInstance) + { + if (here->BSIM3V2owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->BSIM3V2states = *states; + *states += BSIM3V2numStates; + } + /* perform the parameter defaulting */ + if (!here->BSIM3V2drainAreaGiven) + here->BSIM3V2drainArea = 0.0; + if (!here->BSIM3V2drainPerimeterGiven) + here->BSIM3V2drainPerimeter = 0.0; + if (!here->BSIM3V2drainSquaresGiven) + here->BSIM3V2drainSquares = 1.0; + if (!here->BSIM3V2icVBSGiven) + here->BSIM3V2icVBS = 0.0; + if (!here->BSIM3V2icVDSGiven) + here->BSIM3V2icVDS = 0.0; + if (!here->BSIM3V2icVGSGiven) + here->BSIM3V2icVGS = 0.0; + if (!here->BSIM3V2lGiven) + here->BSIM3V2l = 5.0e-6; + if (!here->BSIM3V2sourceAreaGiven) + here->BSIM3V2sourceArea = 0.0; + if (!here->BSIM3V2sourcePerimeterGiven) + here->BSIM3V2sourcePerimeter = 0.0; + if (!here->BSIM3V2sourceSquaresGiven) + here->BSIM3V2sourceSquares = 1.0; + if (!here->BSIM3V2wGiven) + here->BSIM3V2w = 5.0e-6; + if (!here->BSIM3V2nqsModGiven) + here->BSIM3V2nqsMod = 0; + + /* process drain series resistance */ + if ((model->BSIM3V2sheetResistance > 0.0) && + (here->BSIM3V2drainSquares > 0.0 ) && + (here->BSIM3V2dNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3V2name,"drain"); + if(error) return(error); + here->BSIM3V2dNodePrime = tmp->number; + } + else + { here->BSIM3V2dNodePrime = here->BSIM3V2dNode; + } + + /* process source series resistance */ + if ((model->BSIM3V2sheetResistance > 0.0) && + (here->BSIM3V2sourceSquares > 0.0 ) && + (here->BSIM3V2sNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3V2name,"source"); + if(error) return(error); + here->BSIM3V2sNodePrime = tmp->number; + } + else + { here->BSIM3V2sNodePrime = here->BSIM3V2sNode; + } + + /* internal charge node */ + + if ((here->BSIM3V2nqsMod) && (here->BSIM3V2qNode == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM3V2name,"charge"); + if(error) return(error); + here->BSIM3V2qNode = tmp->number; + } + else + { here->BSIM3V2qNode = 0; + } + + /* set Sparse Matrix Pointers */ + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(BSIM3V2DdPtr, BSIM3V2dNode, BSIM3V2dNode) + TSTALLOC(BSIM3V2GgPtr, BSIM3V2gNode, BSIM3V2gNode) + TSTALLOC(BSIM3V2SsPtr, BSIM3V2sNode, BSIM3V2sNode) + TSTALLOC(BSIM3V2BbPtr, BSIM3V2bNode, BSIM3V2bNode) + TSTALLOC(BSIM3V2DPdpPtr, BSIM3V2dNodePrime, BSIM3V2dNodePrime) + TSTALLOC(BSIM3V2SPspPtr, BSIM3V2sNodePrime, BSIM3V2sNodePrime) + TSTALLOC(BSIM3V2DdpPtr, BSIM3V2dNode, BSIM3V2dNodePrime) + TSTALLOC(BSIM3V2GbPtr, BSIM3V2gNode, BSIM3V2bNode) + TSTALLOC(BSIM3V2GdpPtr, BSIM3V2gNode, BSIM3V2dNodePrime) + TSTALLOC(BSIM3V2GspPtr, BSIM3V2gNode, BSIM3V2sNodePrime) + TSTALLOC(BSIM3V2SspPtr, BSIM3V2sNode, BSIM3V2sNodePrime) + TSTALLOC(BSIM3V2BdpPtr, BSIM3V2bNode, BSIM3V2dNodePrime) + TSTALLOC(BSIM3V2BspPtr, BSIM3V2bNode, BSIM3V2sNodePrime) + TSTALLOC(BSIM3V2DPspPtr, BSIM3V2dNodePrime, BSIM3V2sNodePrime) + TSTALLOC(BSIM3V2DPdPtr, BSIM3V2dNodePrime, BSIM3V2dNode) + TSTALLOC(BSIM3V2BgPtr, BSIM3V2bNode, BSIM3V2gNode) + TSTALLOC(BSIM3V2DPgPtr, BSIM3V2dNodePrime, BSIM3V2gNode) + TSTALLOC(BSIM3V2SPgPtr, BSIM3V2sNodePrime, BSIM3V2gNode) + TSTALLOC(BSIM3V2SPsPtr, BSIM3V2sNodePrime, BSIM3V2sNode) + TSTALLOC(BSIM3V2DPbPtr, BSIM3V2dNodePrime, BSIM3V2bNode) + TSTALLOC(BSIM3V2SPbPtr, BSIM3V2sNodePrime, BSIM3V2bNode) + TSTALLOC(BSIM3V2SPdpPtr, BSIM3V2sNodePrime, BSIM3V2dNodePrime) + + TSTALLOC(BSIM3V2QqPtr, BSIM3V2qNode, BSIM3V2qNode) + + TSTALLOC(BSIM3V2QdpPtr, BSIM3V2qNode, BSIM3V2dNodePrime) + TSTALLOC(BSIM3V2QspPtr, BSIM3V2qNode, BSIM3V2sNodePrime) + TSTALLOC(BSIM3V2QgPtr, BSIM3V2qNode, BSIM3V2gNode) + TSTALLOC(BSIM3V2QbPtr, BSIM3V2qNode, BSIM3V2bNode) + TSTALLOC(BSIM3V2DPqPtr, BSIM3V2dNodePrime, BSIM3V2qNode) + TSTALLOC(BSIM3V2SPqPtr, BSIM3V2sNodePrime, BSIM3V2qNode) + TSTALLOC(BSIM3V2GqPtr, BSIM3V2gNode, BSIM3V2qNode) + TSTALLOC(BSIM3V2BqPtr, BSIM3V2bNode, BSIM3V2qNode) + + } + } + return(OK); +} + + +int +BSIM3V2unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + BSIM3V2model *model; + BSIM3V2instance *here; + + for (model = (BSIM3V2model *)inModel; model != NULL; + model = model->BSIM3V2nextModel) + { + for (here = model->BSIM3V2instances; here != NULL; + here=here->BSIM3V2nextInstance) + { + if (here->BSIM3V2dNodePrime + && here->BSIM3V2dNodePrime != here->BSIM3V2dNode) + { + CKTdltNNum(ckt, here->BSIM3V2dNodePrime); + here->BSIM3V2dNodePrime = 0; + } + if (here->BSIM3V2sNodePrime + && here->BSIM3V2sNodePrime != here->BSIM3V2sNode) + { + CKTdltNNum(ckt, here->BSIM3V2sNodePrime); + here->BSIM3V2sNodePrime = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/bsim3v2/b3v2temp.c b/src/spicelib/devices/bsim3v2/b3v2temp.c new file mode 100644 index 000000000..f6c4ee0b5 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2temp.c @@ -0,0 +1,860 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/*********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: b3v2temp.c +**********/ +/* Lmin, Lmax, Wmin, Wmax */ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +#define Kb 1.3806226e-23 +#define KboQ 8.617087e-5 /* Kb / q where q = 1.60219e-19 */ +#define EPSOX 3.453133e-11 +#define EPSSI 1.03594e-10 +#define PI 3.141592654 +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define Charge_q 1.60219e-19 + + +/* ARGSUSED */ +int +BSIM3V2temp(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +register BSIM3V2model *model = (BSIM3V2model*) inModel; +register BSIM3V2instance *here; +struct BSIM3V2SizeDependParam *pSizeDependParamKnot, *pLastKnot, *pParam; +double tmp, tmp1, tmp2, tmp3, Eg, Eg0, ni, T0, T1, T2, T3, T4, T5, Ldrn, Wdrn; +double delTemp, Temp, TRatio, Inv_L, Inv_W, Inv_LW, Dw, Dl, Vtm0, Tnom; +double Nvtm, SourceSatCurrent, DrainSatCurrent; +int Size_Not_Found; + + /* loop through all the BSIM3V2 device models */ + for (; model != NULL; model = model->BSIM3V2nextModel) + { Temp = ckt->CKTtemp; + if (model->BSIM3V2bulkJctPotential < 0.1) + { model->BSIM3V2bulkJctPotential = 0.1; + fprintf(stderr, "Given pb is less than 0.1. Pb is set to 0.1.\n"); + } + if (model->BSIM3V2sidewallJctPotential < 0.1) + { model->BSIM3V2sidewallJctPotential = 0.1; + fprintf(stderr, "Given pbsw is less than 0.1. Pbsw is set to 0.1.\n"); + } + if (model->BSIM3V2GatesidewallJctPotential < 0.1) + { model->BSIM3V2GatesidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswg is less than 0.1. Pbswg is set to 0.1.\n"); + } + model->pSizeDependParamKnot = NULL; + pLastKnot = NULL; + + Tnom = model->BSIM3V2tnom; + TRatio = Temp / Tnom; + + model->BSIM3V2vcrit = CONSTvt0 * log(CONSTvt0 / (CONSTroot2 * 1.0e-14)); + model->BSIM3V2factor1 = sqrt(EPSSI / EPSOX * model->BSIM3V2tox); + + Vtm0 = KboQ * Tnom; + Eg0 = 1.16 - 7.02e-4 * Tnom * Tnom / (Tnom + 1108.0); + ni = 1.45e10 * (Tnom / 300.15) * sqrt(Tnom / 300.15) + * exp(21.5565981 - Eg0 / (2.0 * Vtm0)); + + model->BSIM3V2vtm = KboQ * Temp; + Eg = 1.16 - 7.02e-4 * Temp * Temp / (Temp + 1108.0); + if (Temp != Tnom) + { T0 = Eg0 / Vtm0 - Eg / model->BSIM3V2vtm + model->BSIM3V2jctTempExponent + * log(Temp / Tnom); + T1 = exp(T0 / model->BSIM3V2jctEmissionCoeff); + model->BSIM3V2jctTempSatCurDensity = model->BSIM3V2jctSatCurDensity + * T1; + model->BSIM3V2jctSidewallTempSatCurDensity + = model->BSIM3V2jctSidewallSatCurDensity * T1; + } + else + { model->BSIM3V2jctTempSatCurDensity = model->BSIM3V2jctSatCurDensity; + model->BSIM3V2jctSidewallTempSatCurDensity + = model->BSIM3V2jctSidewallSatCurDensity; + } + + if (model->BSIM3V2jctTempSatCurDensity < 0.0) + model->BSIM3V2jctTempSatCurDensity = 0.0; + if (model->BSIM3V2jctSidewallTempSatCurDensity < 0.0) + model->BSIM3V2jctSidewallTempSatCurDensity = 0.0; + + /* Temperature dependence of D/B and S/B diode capacitance begins */ + delTemp = ckt->CKTtemp - model->BSIM3V2tnom; + T0 = model->BSIM3V2tcj * delTemp; + if (T0 >= -1.0) + { model->BSIM3V2unitAreaJctCap *= 1.0 + T0; + } + else if (model->BSIM3V2unitAreaJctCap > 0.0) + { model->BSIM3V2unitAreaJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cj to be negative. Cj is clamped to zero.\n"); + } + T0 = model->BSIM3V2tcjsw * delTemp; + if (T0 >= -1.0) + { model->BSIM3V2unitLengthSidewallJctCap *= 1.0 + T0; + } + else if (model->BSIM3V2unitLengthSidewallJctCap > 0.0) + { model->BSIM3V2unitLengthSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjsw to be negative. Cjsw is clamped to zero.\n"); + } + T0 = model->BSIM3V2tcjswg * delTemp; + if (T0 >= -1.0) + { model->BSIM3V2unitLengthGateSidewallJctCap *= 1.0 + T0; + } + else if (model->BSIM3V2unitLengthGateSidewallJctCap > 0.0) + { model->BSIM3V2unitLengthGateSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjswg to be negative. Cjswg is clamped to zero.\n"); + } + + model->BSIM3V2PhiB = model->BSIM3V2bulkJctPotential + - model->BSIM3V2tpb * delTemp; + if (model->BSIM3V2PhiB < 0.01) + { model->BSIM3V2PhiB = 0.01; + fprintf(stderr, "Temperature effect has caused pb to be less than 0.01. Pb is clamped to 0.01.\n"); + } + model->BSIM3V2PhiBSW = model->BSIM3V2sidewallJctPotential + - model->BSIM3V2tpbsw * delTemp; + if (model->BSIM3V2PhiBSW <= 0.01) + { model->BSIM3V2PhiBSW = 0.01; + fprintf(stderr, "Temperature effect has caused pbsw to be less than 0.01. Pbsw is clamped to 0.01.\n"); + } + model->BSIM3V2PhiBSWG = model->BSIM3V2GatesidewallJctPotential + - model->BSIM3V2tpbswg * delTemp; + if (model->BSIM3V2PhiBSWG <= 0.01) + { model->BSIM3V2PhiBSWG = 0.01; + fprintf(stderr, "Temperature effect has caused pbswg to be less than 0.01. Pbswg is clamped to 0.01.\n"); + } + /* End of junction capacitance - Weidong & Min-Chie 5/1998 */ + + /* loop through all the instances of the model */ + /* MCJ: Length and Width not initialized */ + for (here = model->BSIM3V2instances; here != NULL; + here = here->BSIM3V2nextInstance) + { + if (here->BSIM3V2owner != ARCHme) continue; + pSizeDependParamKnot = model->pSizeDependParamKnot; + Size_Not_Found = 1; + while ((pSizeDependParamKnot != NULL) && Size_Not_Found) + { if ((here->BSIM3V2l == pSizeDependParamKnot->Length) + && (here->BSIM3V2w == pSizeDependParamKnot->Width)) + { Size_Not_Found = 0; + here->pParam = pSizeDependParamKnot; + } + else + { pLastKnot = pSizeDependParamKnot; + pSizeDependParamKnot = pSizeDependParamKnot->pNext; + } + } + + if (Size_Not_Found) + { pParam = (struct BSIM3V2SizeDependParam *)malloc( + sizeof(struct BSIM3V2SizeDependParam)); + if (pLastKnot == NULL) + model->pSizeDependParamKnot = pParam; + else + pLastKnot->pNext = pParam; + pParam->pNext = NULL; + here->pParam = pParam; + + Ldrn = here->BSIM3V2l; + Wdrn = here->BSIM3V2w; + pParam->Length = Ldrn; + pParam->Width = Wdrn; + + T0 = pow(Ldrn, model->BSIM3V2Lln); + T1 = pow(Wdrn, model->BSIM3V2Lwn); + tmp1 = model->BSIM3V2Ll / T0 + model->BSIM3V2Lw / T1 + + model->BSIM3V2Lwl / (T0 * T1); + pParam->BSIM3V2dl = model->BSIM3V2Lint + tmp1; + tmp2 = model->BSIM3V2Llc / T0 + model->BSIM3V2Lwc / T1 + + model->BSIM3V2Lwlc / (T0 * T1); + pParam->BSIM3V2dlc = model->BSIM3V2dlc + tmp2; + + T2 = pow(Ldrn, model->BSIM3V2Wln); + T3 = pow(Wdrn, model->BSIM3V2Wwn); + tmp1 = model->BSIM3V2Wl / T2 + model->BSIM3V2Ww / T3 + + model->BSIM3V2Wwl / (T2 * T3); + pParam->BSIM3V2dw = model->BSIM3V2Wint + tmp1; + tmp2 = model->BSIM3V2Wlc / T2 + model->BSIM3V2Wwc / T3 + + model->BSIM3V2Wwlc / (T2 * T3); + pParam->BSIM3V2dwc = model->BSIM3V2dwc + tmp2; + + pParam->BSIM3V2leff = here->BSIM3V2l - 2.0 * pParam->BSIM3V2dl; + if (pParam->BSIM3V2leff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V2modName; + namarray[1] = here->BSIM3V2name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V2: mosfet %s, model %s: Effective channel length <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3V2weff = here->BSIM3V2w - 2.0 * pParam->BSIM3V2dw; + if (pParam->BSIM3V2weff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V2modName; + namarray[1] = here->BSIM3V2name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V2: mosfet %s, model %s: Effective channel width <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3V2leffCV = here->BSIM3V2l - 2.0 * pParam->BSIM3V2dlc; + if (pParam->BSIM3V2leffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V2modName; + namarray[1] = here->BSIM3V2name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V2: mosfet %s, model %s: Effective channel length for C-V <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM3V2weffCV = here->BSIM3V2w - 2.0 * pParam->BSIM3V2dwc; + if (pParam->BSIM3V2weffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V2modName; + namarray[1] = here->BSIM3V2name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM3V2: mosfet %s, model %s: Effective channel width for C-V <= 0", + namarray); + return(E_BADPARM); + } + + + if (model->BSIM3V2binUnit == 1) + { Inv_L = 1.0e-6 / pParam->BSIM3V2leff; + Inv_W = 1.0e-6 / pParam->BSIM3V2weff; + Inv_LW = 1.0e-12 / (pParam->BSIM3V2leff + * pParam->BSIM3V2weff); + } + else + { Inv_L = 1.0 / pParam->BSIM3V2leff; + Inv_W = 1.0 / pParam->BSIM3V2weff; + Inv_LW = 1.0 / (pParam->BSIM3V2leff + * pParam->BSIM3V2weff); + } + pParam->BSIM3V2cdsc = model->BSIM3V2cdsc + + model->BSIM3V2lcdsc * Inv_L + + model->BSIM3V2wcdsc * Inv_W + + model->BSIM3V2pcdsc * Inv_LW; + pParam->BSIM3V2cdscb = model->BSIM3V2cdscb + + model->BSIM3V2lcdscb * Inv_L + + model->BSIM3V2wcdscb * Inv_W + + model->BSIM3V2pcdscb * Inv_LW; + + pParam->BSIM3V2cdscd = model->BSIM3V2cdscd + + model->BSIM3V2lcdscd * Inv_L + + model->BSIM3V2wcdscd * Inv_W + + model->BSIM3V2pcdscd * Inv_LW; + + pParam->BSIM3V2cit = model->BSIM3V2cit + + model->BSIM3V2lcit * Inv_L + + model->BSIM3V2wcit * Inv_W + + model->BSIM3V2pcit * Inv_LW; + pParam->BSIM3V2nfactor = model->BSIM3V2nfactor + + model->BSIM3V2lnfactor * Inv_L + + model->BSIM3V2wnfactor * Inv_W + + model->BSIM3V2pnfactor * Inv_LW; + pParam->BSIM3V2xj = model->BSIM3V2xj + + model->BSIM3V2lxj * Inv_L + + model->BSIM3V2wxj * Inv_W + + model->BSIM3V2pxj * Inv_LW; + pParam->BSIM3V2vsat = model->BSIM3V2vsat + + model->BSIM3V2lvsat * Inv_L + + model->BSIM3V2wvsat * Inv_W + + model->BSIM3V2pvsat * Inv_LW; + pParam->BSIM3V2at = model->BSIM3V2at + + model->BSIM3V2lat * Inv_L + + model->BSIM3V2wat * Inv_W + + model->BSIM3V2pat * Inv_LW; + pParam->BSIM3V2a0 = model->BSIM3V2a0 + + model->BSIM3V2la0 * Inv_L + + model->BSIM3V2wa0 * Inv_W + + model->BSIM3V2pa0 * Inv_LW; + + pParam->BSIM3V2ags = model->BSIM3V2ags + + model->BSIM3V2lags * Inv_L + + model->BSIM3V2wags * Inv_W + + model->BSIM3V2pags * Inv_LW; + + pParam->BSIM3V2a1 = model->BSIM3V2a1 + + model->BSIM3V2la1 * Inv_L + + model->BSIM3V2wa1 * Inv_W + + model->BSIM3V2pa1 * Inv_LW; + pParam->BSIM3V2a2 = model->BSIM3V2a2 + + model->BSIM3V2la2 * Inv_L + + model->BSIM3V2wa2 * Inv_W + + model->BSIM3V2pa2 * Inv_LW; + pParam->BSIM3V2keta = model->BSIM3V2keta + + model->BSIM3V2lketa * Inv_L + + model->BSIM3V2wketa * Inv_W + + model->BSIM3V2pketa * Inv_LW; + pParam->BSIM3V2nsub = model->BSIM3V2nsub + + model->BSIM3V2lnsub * Inv_L + + model->BSIM3V2wnsub * Inv_W + + model->BSIM3V2pnsub * Inv_LW; + pParam->BSIM3V2npeak = model->BSIM3V2npeak + + model->BSIM3V2lnpeak * Inv_L + + model->BSIM3V2wnpeak * Inv_W + + model->BSIM3V2pnpeak * Inv_LW; + pParam->BSIM3V2ngate = model->BSIM3V2ngate + + model->BSIM3V2lngate * Inv_L + + model->BSIM3V2wngate * Inv_W + + model->BSIM3V2pngate * Inv_LW; + pParam->BSIM3V2gamma1 = model->BSIM3V2gamma1 + + model->BSIM3V2lgamma1 * Inv_L + + model->BSIM3V2wgamma1 * Inv_W + + model->BSIM3V2pgamma1 * Inv_LW; + pParam->BSIM3V2gamma2 = model->BSIM3V2gamma2 + + model->BSIM3V2lgamma2 * Inv_L + + model->BSIM3V2wgamma2 * Inv_W + + model->BSIM3V2pgamma2 * Inv_LW; + pParam->BSIM3V2vbx = model->BSIM3V2vbx + + model->BSIM3V2lvbx * Inv_L + + model->BSIM3V2wvbx * Inv_W + + model->BSIM3V2pvbx * Inv_LW; + pParam->BSIM3V2vbm = model->BSIM3V2vbm + + model->BSIM3V2lvbm * Inv_L + + model->BSIM3V2wvbm * Inv_W + + model->BSIM3V2pvbm * Inv_LW; + pParam->BSIM3V2xt = model->BSIM3V2xt + + model->BSIM3V2lxt * Inv_L + + model->BSIM3V2wxt * Inv_W + + model->BSIM3V2pxt * Inv_LW; + pParam->BSIM3V2vfb = model->BSIM3V2vfb + + model->BSIM3V2lvfb * Inv_L + + model->BSIM3V2wvfb * Inv_W + + model->BSIM3V2pvfb * Inv_LW; + pParam->BSIM3V2k1 = model->BSIM3V2k1 + + model->BSIM3V2lk1 * Inv_L + + model->BSIM3V2wk1 * Inv_W + + model->BSIM3V2pk1 * Inv_LW; + pParam->BSIM3V2kt1 = model->BSIM3V2kt1 + + model->BSIM3V2lkt1 * Inv_L + + model->BSIM3V2wkt1 * Inv_W + + model->BSIM3V2pkt1 * Inv_LW; + pParam->BSIM3V2kt1l = model->BSIM3V2kt1l + + model->BSIM3V2lkt1l * Inv_L + + model->BSIM3V2wkt1l * Inv_W + + model->BSIM3V2pkt1l * Inv_LW; + pParam->BSIM3V2k2 = model->BSIM3V2k2 + + model->BSIM3V2lk2 * Inv_L + + model->BSIM3V2wk2 * Inv_W + + model->BSIM3V2pk2 * Inv_LW; + pParam->BSIM3V2kt2 = model->BSIM3V2kt2 + + model->BSIM3V2lkt2 * Inv_L + + model->BSIM3V2wkt2 * Inv_W + + model->BSIM3V2pkt2 * Inv_LW; + pParam->BSIM3V2k3 = model->BSIM3V2k3 + + model->BSIM3V2lk3 * Inv_L + + model->BSIM3V2wk3 * Inv_W + + model->BSIM3V2pk3 * Inv_LW; + pParam->BSIM3V2k3b = model->BSIM3V2k3b + + model->BSIM3V2lk3b * Inv_L + + model->BSIM3V2wk3b * Inv_W + + model->BSIM3V2pk3b * Inv_LW; + pParam->BSIM3V2w0 = model->BSIM3V2w0 + + model->BSIM3V2lw0 * Inv_L + + model->BSIM3V2ww0 * Inv_W + + model->BSIM3V2pw0 * Inv_LW; + pParam->BSIM3V2nlx = model->BSIM3V2nlx + + model->BSIM3V2lnlx * Inv_L + + model->BSIM3V2wnlx * Inv_W + + model->BSIM3V2pnlx * Inv_LW; + pParam->BSIM3V2dvt0 = model->BSIM3V2dvt0 + + model->BSIM3V2ldvt0 * Inv_L + + model->BSIM3V2wdvt0 * Inv_W + + model->BSIM3V2pdvt0 * Inv_LW; + pParam->BSIM3V2dvt1 = model->BSIM3V2dvt1 + + model->BSIM3V2ldvt1 * Inv_L + + model->BSIM3V2wdvt1 * Inv_W + + model->BSIM3V2pdvt1 * Inv_LW; + pParam->BSIM3V2dvt2 = model->BSIM3V2dvt2 + + model->BSIM3V2ldvt2 * Inv_L + + model->BSIM3V2wdvt2 * Inv_W + + model->BSIM3V2pdvt2 * Inv_LW; + pParam->BSIM3V2dvt0w = model->BSIM3V2dvt0w + + model->BSIM3V2ldvt0w * Inv_L + + model->BSIM3V2wdvt0w * Inv_W + + model->BSIM3V2pdvt0w * Inv_LW; + pParam->BSIM3V2dvt1w = model->BSIM3V2dvt1w + + model->BSIM3V2ldvt1w * Inv_L + + model->BSIM3V2wdvt1w * Inv_W + + model->BSIM3V2pdvt1w * Inv_LW; + pParam->BSIM3V2dvt2w = model->BSIM3V2dvt2w + + model->BSIM3V2ldvt2w * Inv_L + + model->BSIM3V2wdvt2w * Inv_W + + model->BSIM3V2pdvt2w * Inv_LW; + pParam->BSIM3V2drout = model->BSIM3V2drout + + model->BSIM3V2ldrout * Inv_L + + model->BSIM3V2wdrout * Inv_W + + model->BSIM3V2pdrout * Inv_LW; + pParam->BSIM3V2dsub = model->BSIM3V2dsub + + model->BSIM3V2ldsub * Inv_L + + model->BSIM3V2wdsub * Inv_W + + model->BSIM3V2pdsub * Inv_LW; + pParam->BSIM3V2vth0 = model->BSIM3V2vth0 + + model->BSIM3V2lvth0 * Inv_L + + model->BSIM3V2wvth0 * Inv_W + + model->BSIM3V2pvth0 * Inv_LW; + pParam->BSIM3V2ua = model->BSIM3V2ua + + model->BSIM3V2lua * Inv_L + + model->BSIM3V2wua * Inv_W + + model->BSIM3V2pua * Inv_LW; + pParam->BSIM3V2ua1 = model->BSIM3V2ua1 + + model->BSIM3V2lua1 * Inv_L + + model->BSIM3V2wua1 * Inv_W + + model->BSIM3V2pua1 * Inv_LW; + pParam->BSIM3V2ub = model->BSIM3V2ub + + model->BSIM3V2lub * Inv_L + + model->BSIM3V2wub * Inv_W + + model->BSIM3V2pub * Inv_LW; + pParam->BSIM3V2ub1 = model->BSIM3V2ub1 + + model->BSIM3V2lub1 * Inv_L + + model->BSIM3V2wub1 * Inv_W + + model->BSIM3V2pub1 * Inv_LW; + pParam->BSIM3V2uc = model->BSIM3V2uc + + model->BSIM3V2luc * Inv_L + + model->BSIM3V2wuc * Inv_W + + model->BSIM3V2puc * Inv_LW; + pParam->BSIM3V2uc1 = model->BSIM3V2uc1 + + model->BSIM3V2luc1 * Inv_L + + model->BSIM3V2wuc1 * Inv_W + + model->BSIM3V2puc1 * Inv_LW; + pParam->BSIM3V2u0 = model->BSIM3V2u0 + + model->BSIM3V2lu0 * Inv_L + + model->BSIM3V2wu0 * Inv_W + + model->BSIM3V2pu0 * Inv_LW; + pParam->BSIM3V2ute = model->BSIM3V2ute + + model->BSIM3V2lute * Inv_L + + model->BSIM3V2wute * Inv_W + + model->BSIM3V2pute * Inv_LW; + pParam->BSIM3V2voff = model->BSIM3V2voff + + model->BSIM3V2lvoff * Inv_L + + model->BSIM3V2wvoff * Inv_W + + model->BSIM3V2pvoff * Inv_LW; + pParam->BSIM3V2delta = model->BSIM3V2delta + + model->BSIM3V2ldelta * Inv_L + + model->BSIM3V2wdelta * Inv_W + + model->BSIM3V2pdelta * Inv_LW; + pParam->BSIM3V2rdsw = model->BSIM3V2rdsw + + model->BSIM3V2lrdsw * Inv_L + + model->BSIM3V2wrdsw * Inv_W + + model->BSIM3V2prdsw * Inv_LW; + pParam->BSIM3V2prwg = model->BSIM3V2prwg + + model->BSIM3V2lprwg * Inv_L + + model->BSIM3V2wprwg * Inv_W + + model->BSIM3V2pprwg * Inv_LW; + pParam->BSIM3V2prwb = model->BSIM3V2prwb + + model->BSIM3V2lprwb * Inv_L + + model->BSIM3V2wprwb * Inv_W + + model->BSIM3V2pprwb * Inv_LW; + pParam->BSIM3V2prt = model->BSIM3V2prt + + model->BSIM3V2lprt * Inv_L + + model->BSIM3V2wprt * Inv_W + + model->BSIM3V2pprt * Inv_LW; + pParam->BSIM3V2eta0 = model->BSIM3V2eta0 + + model->BSIM3V2leta0 * Inv_L + + model->BSIM3V2weta0 * Inv_W + + model->BSIM3V2peta0 * Inv_LW; + pParam->BSIM3V2etab = model->BSIM3V2etab + + model->BSIM3V2letab * Inv_L + + model->BSIM3V2wetab * Inv_W + + model->BSIM3V2petab * Inv_LW; + pParam->BSIM3V2pclm = model->BSIM3V2pclm + + model->BSIM3V2lpclm * Inv_L + + model->BSIM3V2wpclm * Inv_W + + model->BSIM3V2ppclm * Inv_LW; + pParam->BSIM3V2pdibl1 = model->BSIM3V2pdibl1 + + model->BSIM3V2lpdibl1 * Inv_L + + model->BSIM3V2wpdibl1 * Inv_W + + model->BSIM3V2ppdibl1 * Inv_LW; + pParam->BSIM3V2pdibl2 = model->BSIM3V2pdibl2 + + model->BSIM3V2lpdibl2 * Inv_L + + model->BSIM3V2wpdibl2 * Inv_W + + model->BSIM3V2ppdibl2 * Inv_LW; + pParam->BSIM3V2pdiblb = model->BSIM3V2pdiblb + + model->BSIM3V2lpdiblb * Inv_L + + model->BSIM3V2wpdiblb * Inv_W + + model->BSIM3V2ppdiblb * Inv_LW; + pParam->BSIM3V2pscbe1 = model->BSIM3V2pscbe1 + + model->BSIM3V2lpscbe1 * Inv_L + + model->BSIM3V2wpscbe1 * Inv_W + + model->BSIM3V2ppscbe1 * Inv_LW; + pParam->BSIM3V2pscbe2 = model->BSIM3V2pscbe2 + + model->BSIM3V2lpscbe2 * Inv_L + + model->BSIM3V2wpscbe2 * Inv_W + + model->BSIM3V2ppscbe2 * Inv_LW; + pParam->BSIM3V2pvag = model->BSIM3V2pvag + + model->BSIM3V2lpvag * Inv_L + + model->BSIM3V2wpvag * Inv_W + + model->BSIM3V2ppvag * Inv_LW; + pParam->BSIM3V2wr = model->BSIM3V2wr + + model->BSIM3V2lwr * Inv_L + + model->BSIM3V2wwr * Inv_W + + model->BSIM3V2pwr * Inv_LW; + pParam->BSIM3V2dwg = model->BSIM3V2dwg + + model->BSIM3V2ldwg * Inv_L + + model->BSIM3V2wdwg * Inv_W + + model->BSIM3V2pdwg * Inv_LW; + pParam->BSIM3V2dwb = model->BSIM3V2dwb + + model->BSIM3V2ldwb * Inv_L + + model->BSIM3V2wdwb * Inv_W + + model->BSIM3V2pdwb * Inv_LW; + pParam->BSIM3V2b0 = model->BSIM3V2b0 + + model->BSIM3V2lb0 * Inv_L + + model->BSIM3V2wb0 * Inv_W + + model->BSIM3V2pb0 * Inv_LW; + pParam->BSIM3V2b1 = model->BSIM3V2b1 + + model->BSIM3V2lb1 * Inv_L + + model->BSIM3V2wb1 * Inv_W + + model->BSIM3V2pb1 * Inv_LW; + pParam->BSIM3V2alpha0 = model->BSIM3V2alpha0 + + model->BSIM3V2lalpha0 * Inv_L + + model->BSIM3V2walpha0 * Inv_W + + model->BSIM3V2palpha0 * Inv_LW; + pParam->BSIM3V2alpha1 = model->BSIM3V2alpha1 + + model->BSIM3V2lalpha1 * Inv_L + + model->BSIM3V2walpha1 * Inv_W + + model->BSIM3V2palpha1 * Inv_LW; + pParam->BSIM3V2beta0 = model->BSIM3V2beta0 + + model->BSIM3V2lbeta0 * Inv_L + + model->BSIM3V2wbeta0 * Inv_W + + model->BSIM3V2pbeta0 * Inv_LW; + /* CV model */ + pParam->BSIM3V2elm = model->BSIM3V2elm + + model->BSIM3V2lelm * Inv_L + + model->BSIM3V2welm * Inv_W + + model->BSIM3V2pelm * Inv_LW; + pParam->BSIM3V2cgsl = model->BSIM3V2cgsl + + model->BSIM3V2lcgsl * Inv_L + + model->BSIM3V2wcgsl * Inv_W + + model->BSIM3V2pcgsl * Inv_LW; + pParam->BSIM3V2cgdl = model->BSIM3V2cgdl + + model->BSIM3V2lcgdl * Inv_L + + model->BSIM3V2wcgdl * Inv_W + + model->BSIM3V2pcgdl * Inv_LW; + pParam->BSIM3V2ckappa = model->BSIM3V2ckappa + + model->BSIM3V2lckappa * Inv_L + + model->BSIM3V2wckappa * Inv_W + + model->BSIM3V2pckappa * Inv_LW; + pParam->BSIM3V2cf = model->BSIM3V2cf + + model->BSIM3V2lcf * Inv_L + + model->BSIM3V2wcf * Inv_W + + model->BSIM3V2pcf * Inv_LW; + pParam->BSIM3V2clc = model->BSIM3V2clc + + model->BSIM3V2lclc * Inv_L + + model->BSIM3V2wclc * Inv_W + + model->BSIM3V2pclc * Inv_LW; + pParam->BSIM3V2cle = model->BSIM3V2cle + + model->BSIM3V2lcle * Inv_L + + model->BSIM3V2wcle * Inv_W + + model->BSIM3V2pcle * Inv_LW; + pParam->BSIM3V2vfbcv = model->BSIM3V2vfbcv + + model->BSIM3V2lvfbcv * Inv_L + + model->BSIM3V2wvfbcv * Inv_W + + model->BSIM3V2pvfbcv * Inv_LW; + pParam->BSIM3V2acde = model->BSIM3V2acde + + model->BSIM3V2lacde * Inv_L + + model->BSIM3V2wacde * Inv_W + + model->BSIM3V2pacde * Inv_LW; + pParam->BSIM3V2moin = model->BSIM3V2moin + + model->BSIM3V2lmoin * Inv_L + + model->BSIM3V2wmoin * Inv_W + + model->BSIM3V2pmoin * Inv_LW; + pParam->BSIM3V2noff = model->BSIM3V2noff + + model->BSIM3V2lnoff * Inv_L + + model->BSIM3V2wnoff * Inv_W + + model->BSIM3V2pnoff * Inv_LW; + pParam->BSIM3V2voffcv = model->BSIM3V2voffcv + + model->BSIM3V2lvoffcv * Inv_L + + model->BSIM3V2wvoffcv * Inv_W + + model->BSIM3V2pvoffcv * Inv_LW; + + pParam->BSIM3V2abulkCVfactor = 1.0 + pow((pParam->BSIM3V2clc + / pParam->BSIM3V2leffCV), + pParam->BSIM3V2cle); + + T0 = (TRatio - 1.0); + pParam->BSIM3V2ua = pParam->BSIM3V2ua + pParam->BSIM3V2ua1 * T0; + pParam->BSIM3V2ub = pParam->BSIM3V2ub + pParam->BSIM3V2ub1 * T0; + pParam->BSIM3V2uc = pParam->BSIM3V2uc + pParam->BSIM3V2uc1 * T0; + if (pParam->BSIM3V2u0 > 1.0) + pParam->BSIM3V2u0 = pParam->BSIM3V2u0 / 1.0e4; + + pParam->BSIM3V2u0temp = pParam->BSIM3V2u0 + * pow(TRatio, pParam->BSIM3V2ute); + pParam->BSIM3V2vsattemp = pParam->BSIM3V2vsat - pParam->BSIM3V2at + * T0; + pParam->BSIM3V2rds0 = (pParam->BSIM3V2rdsw + pParam->BSIM3V2prt * T0) + / pow(pParam->BSIM3V2weff * 1E6, pParam->BSIM3V2wr); + + if (BSIM3V2checkModel(model, here, ckt)) + { IFuid namarray[2]; + namarray[0] = model->BSIM3V2modName; + namarray[1] = here->BSIM3V2name; + (*(SPfrontEnd->IFerror)) (ERR_FATAL, "Fatal error(s) detected during BSIM3V2V3.2 parameter checking for %s in model %s", namarray); + return(E_BADPARM); + } + + pParam->BSIM3V2cgdo = (model->BSIM3V2cgdo + pParam->BSIM3V2cf) + * pParam->BSIM3V2weffCV; + pParam->BSIM3V2cgso = (model->BSIM3V2cgso + pParam->BSIM3V2cf) + * pParam->BSIM3V2weffCV; + pParam->BSIM3V2cgbo = model->BSIM3V2cgbo * pParam->BSIM3V2leffCV; + + T0 = pParam->BSIM3V2leffCV * pParam->BSIM3V2leffCV; + pParam->BSIM3V2tconst = pParam->BSIM3V2u0temp * pParam->BSIM3V2elm / (model->BSIM3V2cox + * pParam->BSIM3V2weffCV * pParam->BSIM3V2leffCV * T0); + + if (!model->BSIM3V2npeakGiven && model->BSIM3V2gamma1Given) + { T0 = pParam->BSIM3V2gamma1 * model->BSIM3V2cox; + pParam->BSIM3V2npeak = 3.021E22 * T0 * T0; + } + + pParam->BSIM3V2phi = 2.0 * Vtm0 + * log(pParam->BSIM3V2npeak / ni); + + pParam->BSIM3V2sqrtPhi = sqrt(pParam->BSIM3V2phi); + pParam->BSIM3V2phis3 = pParam->BSIM3V2sqrtPhi * pParam->BSIM3V2phi; + + pParam->BSIM3V2Xdep0 = sqrt(2.0 * EPSSI / (Charge_q + * pParam->BSIM3V2npeak * 1.0e6)) + * pParam->BSIM3V2sqrtPhi; + pParam->BSIM3V2sqrtXdep0 = sqrt(pParam->BSIM3V2Xdep0); + pParam->BSIM3V2litl = sqrt(3.0 * pParam->BSIM3V2xj + * model->BSIM3V2tox); + pParam->BSIM3V2vbi = Vtm0 * log(1.0e20 + * pParam->BSIM3V2npeak / (ni * ni)); + pParam->BSIM3V2cdep0 = sqrt(Charge_q * EPSSI + * pParam->BSIM3V2npeak * 1.0e6 / 2.0 + / pParam->BSIM3V2phi); + + pParam->BSIM3V2ldeb = sqrt(EPSSI * Vtm0 / (Charge_q + * pParam->BSIM3V2npeak * 1.0e6)) / 3.0; + pParam->BSIM3V2acde *= pow((pParam->BSIM3V2npeak / 2.0e16), -0.25); + + + if (model->BSIM3V2k1Given || model->BSIM3V2k2Given) + { if (!model->BSIM3V2k1Given) + { fprintf(stdout, "Warning: k1 should be specified with k2.\n"); + pParam->BSIM3V2k1 = 0.53; + } + if (!model->BSIM3V2k2Given) + { fprintf(stdout, "Warning: k2 should be specified with k1.\n"); + pParam->BSIM3V2k2 = -0.0186; + } + if (model->BSIM3V2nsubGiven) + fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V2xtGiven) + fprintf(stdout, "Warning: xt is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V2vbxGiven) + fprintf(stdout, "Warning: vbx is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V2gamma1Given) + fprintf(stdout, "Warning: gamma1 is ignored because k1 or k2 is given.\n"); + if (model->BSIM3V2gamma2Given) + fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n"); + } + else + { if (!model->BSIM3V2vbxGiven) + pParam->BSIM3V2vbx = pParam->BSIM3V2phi - 7.7348e-4 + * pParam->BSIM3V2npeak + * pParam->BSIM3V2xt * pParam->BSIM3V2xt; + if (pParam->BSIM3V2vbx > 0.0) + pParam->BSIM3V2vbx = -pParam->BSIM3V2vbx; + if (pParam->BSIM3V2vbm > 0.0) + pParam->BSIM3V2vbm = -pParam->BSIM3V2vbm; + + if (!model->BSIM3V2gamma1Given) + pParam->BSIM3V2gamma1 = 5.753e-12 + * sqrt(pParam->BSIM3V2npeak) + / model->BSIM3V2cox; + if (!model->BSIM3V2gamma2Given) + pParam->BSIM3V2gamma2 = 5.753e-12 + * sqrt(pParam->BSIM3V2nsub) + / model->BSIM3V2cox; + + T0 = pParam->BSIM3V2gamma1 - pParam->BSIM3V2gamma2; + T1 = sqrt(pParam->BSIM3V2phi - pParam->BSIM3V2vbx) + - pParam->BSIM3V2sqrtPhi; + T2 = sqrt(pParam->BSIM3V2phi * (pParam->BSIM3V2phi + - pParam->BSIM3V2vbm)) - pParam->BSIM3V2phi; + pParam->BSIM3V2k2 = T0 * T1 / (2.0 * T2 + pParam->BSIM3V2vbm); + pParam->BSIM3V2k1 = pParam->BSIM3V2gamma2 - 2.0 + * pParam->BSIM3V2k2 * sqrt(pParam->BSIM3V2phi + - pParam->BSIM3V2vbm); + } + + if (pParam->BSIM3V2k2 < 0.0) + { T0 = 0.5 * pParam->BSIM3V2k1 / pParam->BSIM3V2k2; + pParam->BSIM3V2vbsc = 0.9 * (pParam->BSIM3V2phi - T0 * T0); + if (pParam->BSIM3V2vbsc > -3.0) + pParam->BSIM3V2vbsc = -3.0; + else if (pParam->BSIM3V2vbsc < -30.0) + pParam->BSIM3V2vbsc = -30.0; + } + else + { pParam->BSIM3V2vbsc = -30.0; + } + if (pParam->BSIM3V2vbsc > pParam->BSIM3V2vbm) + pParam->BSIM3V2vbsc = pParam->BSIM3V2vbm; + + if (!model->BSIM3V2vfbGiven) + { if (model->BSIM3V2vth0Given) + { pParam->BSIM3V2vfb = model->BSIM3V2type * pParam->BSIM3V2vth0 + - pParam->BSIM3V2phi - pParam->BSIM3V2k1 + * pParam->BSIM3V2sqrtPhi; + } + else + { pParam->BSIM3V2vfb = -1.0; + } + } + if (!model->BSIM3V2vth0Given) + { pParam->BSIM3V2vth0 = model->BSIM3V2type * (pParam->BSIM3V2vfb + + pParam->BSIM3V2phi + pParam->BSIM3V2k1 + * pParam->BSIM3V2sqrtPhi); + } + + pParam->BSIM3V2k1ox = pParam->BSIM3V2k1 * model->BSIM3V2tox + / model->BSIM3V2toxm; + pParam->BSIM3V2k2ox = pParam->BSIM3V2k2 * model->BSIM3V2tox + / model->BSIM3V2toxm; + + T1 = sqrt(EPSSI / EPSOX * model->BSIM3V2tox + * pParam->BSIM3V2Xdep0); + T0 = exp(-0.5 * pParam->BSIM3V2dsub * pParam->BSIM3V2leff / T1); + pParam->BSIM3V2theta0vb0 = (T0 + 2.0 * T0 * T0); + + T0 = exp(-0.5 * pParam->BSIM3V2drout * pParam->BSIM3V2leff / T1); + T2 = (T0 + 2.0 * T0 * T0); + pParam->BSIM3V2thetaRout = pParam->BSIM3V2pdibl1 * T2 + + pParam->BSIM3V2pdibl2; + + /* vfbzb for capMod 1, 2 & 3 - Weidong 4/1997 */ + tmp = sqrt(pParam->BSIM3V2Xdep0); + tmp1 = pParam->BSIM3V2vbi - pParam->BSIM3V2phi; + tmp2 = model->BSIM3V2factor1 * tmp; + + T0 = -0.5 * pParam->BSIM3V2dvt1w * pParam->BSIM3V2weff + * pParam->BSIM3V2leff / tmp2; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 * (1.0 + 2.0 * T1); + } + else + { T1 = MIN_EXP; + T2 = T1 * (1.0 + 2.0 * T1); + } + T0 = pParam->BSIM3V2dvt0w * T2; + T2 = T0 * tmp1; + + T0 = -0.5 * pParam->BSIM3V2dvt1 * pParam->BSIM3V2leff / tmp2; + if (T0 > -EXP_THRESHOLD) + { T1 = exp(T0); + T3 = T1 * (1.0 + 2.0 * T1); + } + else + { T1 = MIN_EXP; + T3 = T1 * (1.0 + 2.0 * T1); + } + T3 = pParam->BSIM3V2dvt0 * T3 * tmp1; + + T4 = model->BSIM3V2tox * pParam->BSIM3V2phi + / (pParam->BSIM3V2weff + pParam->BSIM3V2w0); + + T0 = sqrt(1.0 + pParam->BSIM3V2nlx / pParam->BSIM3V2leff); + T5 = pParam->BSIM3V2k1ox * (T0 - 1.0) * pParam->BSIM3V2sqrtPhi + + (pParam->BSIM3V2kt1 + pParam->BSIM3V2kt1l / pParam->BSIM3V2leff) + * (TRatio - 1.0); + + tmp3 = model->BSIM3V2type * pParam->BSIM3V2vth0 + - T2 - T3 + pParam->BSIM3V2k3 * T4 + T5; + pParam->BSIM3V2vfbzb = tmp3 - pParam->BSIM3V2phi - pParam->BSIM3V2k1 + * pParam->BSIM3V2sqrtPhi; + /* End of vfbzb */ + } + + /* process source/drain series resistance */ + here->BSIM3V2drainConductance = model->BSIM3V2sheetResistance + * here->BSIM3V2drainSquares; + if (here->BSIM3V2drainConductance > 0.0) + here->BSIM3V2drainConductance = 1.0 + / here->BSIM3V2drainConductance; + else + here->BSIM3V2drainConductance = 0.0; + + here->BSIM3V2sourceConductance = model->BSIM3V2sheetResistance + * here->BSIM3V2sourceSquares; + if (here->BSIM3V2sourceConductance > 0.0) + here->BSIM3V2sourceConductance = 1.0 + / here->BSIM3V2sourceConductance; + else + here->BSIM3V2sourceConductance = 0.0; + here->BSIM3V2cgso = pParam->BSIM3V2cgso; + here->BSIM3V2cgdo = pParam->BSIM3V2cgdo; + + Nvtm = model->BSIM3V2vtm * model->BSIM3V2jctEmissionCoeff; + if ((here->BSIM3V2sourceArea <= 0.0) && + (here->BSIM3V2sourcePerimeter <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } + else + { SourceSatCurrent = here->BSIM3V2sourceArea + * model->BSIM3V2jctTempSatCurDensity + + here->BSIM3V2sourcePerimeter + * model->BSIM3V2jctSidewallTempSatCurDensity; + } + if ((SourceSatCurrent > 0.0) && (model->BSIM3V2ijth > 0.0)) + { here->BSIM3V2vjsm = Nvtm * log(model->BSIM3V2ijth + / SourceSatCurrent + 1.0); + } + + if ((here->BSIM3V2drainArea <= 0.0) && + (here->BSIM3V2drainPerimeter <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } + else + { DrainSatCurrent = here->BSIM3V2drainArea + * model->BSIM3V2jctTempSatCurDensity + + here->BSIM3V2drainPerimeter + * model->BSIM3V2jctSidewallTempSatCurDensity; + } + if ((DrainSatCurrent > 0.0) && (model->BSIM3V2ijth > 0.0)) + { here->BSIM3V2vjdm = Nvtm * log(model->BSIM3V2ijth + / DrainSatCurrent + 1.0); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/bsim3v2/b3v2trunc.c b/src/spicelib/devices/bsim3v2/b3v2trunc.c new file mode 100644 index 000000000..38f20e7db --- /dev/null +++ b/src/spicelib/devices/bsim3v2/b3v2trunc.c @@ -0,0 +1,66 @@ +/* $Id$ */ +/* + $Log$ + Revision 1.1 2000-04-27 20:03:59 pnenzi + Initial revision + + * Revision 3.2 1998/6/16 18:00:00 Weidong + * BSIM3v3.2 release + * +*/ +static char rcsid[] = "$Id$"; + +/*************************************/ + +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +File: b3v2trunc.c +**********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim3v2def.h" +#include "sperror.h" +#include "suffix.h" + + +int +BSIM3V2trunc(inModel,ckt,timeStep) +GENmodel *inModel; +register CKTcircuit *ckt; +double *timeStep; +{ +register BSIM3V2model *model = (BSIM3V2model*)inModel; +register BSIM3V2instance *here; + +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + + for (; model != NULL; model = model->BSIM3V2nextModel) + { for (here = model->BSIM3V2instances; here != NULL; + here = here->BSIM3V2nextInstance) + { + if (here->BSIM3V2owner != ARCHme) continue; +#ifdef STEPDEBUG + debugtemp = *timeStep; +#endif /* STEPDEBUG */ + CKTterr(here->BSIM3V2qb,ckt,timeStep); + CKTterr(here->BSIM3V2qg,ckt,timeStep); + CKTterr(here->BSIM3V2qd,ckt,timeStep); +#ifdef STEPDEBUG + if(debugtemp != *timeStep) + { printf("device %s reduces step from %g to %g\n", + here->BSIM3V2name,debugtemp,*timeStep); + } +#endif /* STEPDEBUG */ + } + } + return(OK); +} + + + diff --git a/src/spicelib/devices/bsim3v2/bsim3v2def.h b/src/spicelib/devices/bsim3v2/bsim3v2def.h new file mode 100644 index 000000000..5268f2594 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/bsim3v2def.h @@ -0,0 +1,1756 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1995 Min-Chie Jeng and Mansun Chan. +Modified by Weidong Liu (1997-1998). +File: bsim3v2def.h +**********/ + +#ifndef BSIM3V2 +#define BSIM3V2 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + +typedef struct sBSIM3V2instance +{ + struct sBSIM3V2model *BSIM3V2modPtr; + struct sBSIM3V2instance *BSIM3V2nextInstance; + IFuid BSIM3V2name; + int BSIM3V2owner; /* number of owner process */ + int BSIM3V2states; /* index into state table for this device */ + + int BSIM3V2dNode; + int BSIM3V2gNode; + int BSIM3V2sNode; + int BSIM3V2bNode; + int BSIM3V2dNodePrime; + int BSIM3V2sNodePrime; + int BSIM3V2qNode; /* MCJ */ + + /* MCJ */ + double BSIM3V2ueff; + double BSIM3V2thetavth; + double BSIM3V2von; + double BSIM3V2vdsat; + double BSIM3V2cgdo; + double BSIM3V2cgso; + double BSIM3V2vjsm; + double BSIM3V2vjdm; + + double BSIM3V2l; + double BSIM3V2w; + double BSIM3V2drainArea; + double BSIM3V2sourceArea; + double BSIM3V2drainSquares; + double BSIM3V2sourceSquares; + double BSIM3V2drainPerimeter; + double BSIM3V2sourcePerimeter; + double BSIM3V2sourceConductance; + double BSIM3V2drainConductance; + + double BSIM3V2icVBS; + double BSIM3V2icVDS; + double BSIM3V2icVGS; + int BSIM3V2off; + int BSIM3V2mode; + int BSIM3V2nqsMod; + + /* OP point */ + double BSIM3V2qinv; + double BSIM3V2cd; + double BSIM3V2cbs; + double BSIM3V2cbd; + double BSIM3V2csub; + double BSIM3V2gm; + double BSIM3V2gds; + double BSIM3V2gmbs; + double BSIM3V2gbd; + double BSIM3V2gbs; + + double BSIM3V2gbbs; + double BSIM3V2gbgs; + double BSIM3V2gbds; + + double BSIM3V2cggb; + double BSIM3V2cgdb; + double BSIM3V2cgsb; + double BSIM3V2cbgb; + double BSIM3V2cbdb; + double BSIM3V2cbsb; + double BSIM3V2cdgb; + double BSIM3V2cddb; + double BSIM3V2cdsb; + double BSIM3V2capbd; + double BSIM3V2capbs; + + double BSIM3V2cqgb; + double BSIM3V2cqdb; + double BSIM3V2cqsb; + double BSIM3V2cqbb; + + double BSIM3V2qgate; + double BSIM3V2qbulk; + double BSIM3V2qdrn; + + double BSIM3V2gtau; + double BSIM3V2gtg; + double BSIM3V2gtd; + double BSIM3V2gts; + double BSIM3V2gtb; + + struct BSIM3V2SizeDependParam *pParam; + + unsigned BSIM3V2lGiven :1; + unsigned BSIM3V2wGiven :1; + unsigned BSIM3V2drainAreaGiven :1; + unsigned BSIM3V2sourceAreaGiven :1; + unsigned BSIM3V2drainSquaresGiven :1; + unsigned BSIM3V2sourceSquaresGiven :1; + unsigned BSIM3V2drainPerimeterGiven :1; + unsigned BSIM3V2sourcePerimeterGiven :1; + unsigned BSIM3V2dNodePrimeSet :1; + unsigned BSIM3V2sNodePrimeSet :1; + unsigned BSIM3V2icVBSGiven :1; + unsigned BSIM3V2icVDSGiven :1; + unsigned BSIM3V2icVGSGiven :1; + unsigned BSIM3V2nqsModGiven :1; + + double *BSIM3V2DdPtr; + double *BSIM3V2GgPtr; + double *BSIM3V2SsPtr; + double *BSIM3V2BbPtr; + double *BSIM3V2DPdpPtr; + double *BSIM3V2SPspPtr; + double *BSIM3V2DdpPtr; + double *BSIM3V2GbPtr; + double *BSIM3V2GdpPtr; + double *BSIM3V2GspPtr; + double *BSIM3V2SspPtr; + double *BSIM3V2BdpPtr; + double *BSIM3V2BspPtr; + double *BSIM3V2DPspPtr; + double *BSIM3V2DPdPtr; + double *BSIM3V2BgPtr; + double *BSIM3V2DPgPtr; + double *BSIM3V2SPgPtr; + double *BSIM3V2SPsPtr; + double *BSIM3V2DPbPtr; + double *BSIM3V2SPbPtr; + double *BSIM3V2SPdpPtr; + + double *BSIM3V2QqPtr; + double *BSIM3V2QdpPtr; + double *BSIM3V2QgPtr; + double *BSIM3V2QspPtr; + double *BSIM3V2QbPtr; + double *BSIM3V2DPqPtr; + double *BSIM3V2GqPtr; + double *BSIM3V2SPqPtr; + double *BSIM3V2BqPtr; + + /* int BSIM3V2states; */ /* index into state table for this device */ +#define BSIM3V2vbd BSIM3V2states+ 0 +#define BSIM3V2vbs BSIM3V2states+ 1 +#define BSIM3V2vgs BSIM3V2states+ 2 +#define BSIM3V2vds BSIM3V2states+ 3 + +#define BSIM3V2qb BSIM3V2states+ 4 +#define BSIM3V2cqb BSIM3V2states+ 5 +#define BSIM3V2qg BSIM3V2states+ 6 +#define BSIM3V2cqg BSIM3V2states+ 7 +#define BSIM3V2qd BSIM3V2states+ 8 +#define BSIM3V2cqd BSIM3V2states+ 9 + +#define BSIM3V2qbs BSIM3V2states+ 10 +#define BSIM3V2qbd BSIM3V2states+ 11 + +#define BSIM3V2qcheq BSIM3V2states+ 12 +#define BSIM3V2cqcheq BSIM3V2states+ 13 +#define BSIM3V2qcdump BSIM3V2states+ 14 +#define BSIM3V2cqcdump BSIM3V2states+ 15 + +#define BSIM3V2qdef BSIM3V2states+ 16 + +#define BSIM3V2numStates 17 + + +/* indices to the array of BSIM3V2 NOISE SOURCES */ + +#define BSIM3V2RDNOIZ 0 +#define BSIM3V2RSNOIZ 1 +#define BSIM3V2IDNOIZ 2 +#define BSIM3V2FLNOIZ 3 +#define BSIM3V2TOTNOIZ 4 + +#define BSIM3V2NSRCS 5 /* the number of BSIM3V2 MOSFET noise sources */ + +#ifndef NONOISE + double BSIM3V2nVar[NSTATVARS][BSIM3V2NSRCS]; +#else /* NONOISE */ + double **BSIM3V2nVar; +#endif /* NONOISE */ + +} BSIM3V2instance ; + +struct BSIM3V2SizeDependParam +{ + double Width; + double Length; + + double BSIM3V2cdsc; + double BSIM3V2cdscb; + double BSIM3V2cdscd; + double BSIM3V2cit; + double BSIM3V2nfactor; + double BSIM3V2xj; + double BSIM3V2vsat; + double BSIM3V2at; + double BSIM3V2a0; + double BSIM3V2ags; + double BSIM3V2a1; + double BSIM3V2a2; + double BSIM3V2keta; + double BSIM3V2nsub; + double BSIM3V2npeak; + double BSIM3V2ngate; + double BSIM3V2gamma1; + double BSIM3V2gamma2; + double BSIM3V2vbx; + double BSIM3V2vbi; + double BSIM3V2vbm; + double BSIM3V2vbsc; + double BSIM3V2xt; + double BSIM3V2phi; + double BSIM3V2litl; + double BSIM3V2k1; + double BSIM3V2kt1; + double BSIM3V2kt1l; + double BSIM3V2kt2; + double BSIM3V2k2; + double BSIM3V2k3; + double BSIM3V2k3b; + double BSIM3V2w0; + double BSIM3V2nlx; + double BSIM3V2dvt0; + double BSIM3V2dvt1; + double BSIM3V2dvt2; + double BSIM3V2dvt0w; + double BSIM3V2dvt1w; + double BSIM3V2dvt2w; + double BSIM3V2drout; + double BSIM3V2dsub; + double BSIM3V2vth0; + double BSIM3V2ua; + double BSIM3V2ua1; + double BSIM3V2ub; + double BSIM3V2ub1; + double BSIM3V2uc; + double BSIM3V2uc1; + double BSIM3V2u0; + double BSIM3V2ute; + double BSIM3V2voff; + double BSIM3V2vfb; + double BSIM3V2delta; + double BSIM3V2rdsw; + double BSIM3V2rds0; + double BSIM3V2prwg; + double BSIM3V2prwb; + double BSIM3V2prt; + double BSIM3V2eta0; + double BSIM3V2etab; + double BSIM3V2pclm; + double BSIM3V2pdibl1; + double BSIM3V2pdibl2; + double BSIM3V2pdiblb; + double BSIM3V2pscbe1; + double BSIM3V2pscbe2; + double BSIM3V2pvag; + double BSIM3V2wr; + double BSIM3V2dwg; + double BSIM3V2dwb; + double BSIM3V2b0; + double BSIM3V2b1; + double BSIM3V2alpha0; + double BSIM3V2alpha1; + double BSIM3V2beta0; + + + /* CV model */ + double BSIM3V2elm; + double BSIM3V2cgsl; + double BSIM3V2cgdl; + double BSIM3V2ckappa; + double BSIM3V2cf; + double BSIM3V2clc; + double BSIM3V2cle; + double BSIM3V2vfbcv; + double BSIM3V2noff; + double BSIM3V2voffcv; + double BSIM3V2acde; + double BSIM3V2moin; + + +/* Pre-calculated constants */ + + double BSIM3V2dw; + double BSIM3V2dl; + double BSIM3V2leff; + double BSIM3V2weff; + + double BSIM3V2dwc; + double BSIM3V2dlc; + double BSIM3V2leffCV; + double BSIM3V2weffCV; + double BSIM3V2abulkCVfactor; + double BSIM3V2cgso; + double BSIM3V2cgdo; + double BSIM3V2cgbo; + double BSIM3V2tconst; + + double BSIM3V2u0temp; + double BSIM3V2vsattemp; + double BSIM3V2sqrtPhi; + double BSIM3V2phis3; + double BSIM3V2Xdep0; + double BSIM3V2sqrtXdep0; + double BSIM3V2theta0vb0; + double BSIM3V2thetaRout; + + double BSIM3V2cof1; + double BSIM3V2cof2; + double BSIM3V2cof3; + double BSIM3V2cof4; + double BSIM3V2cdep0; + double BSIM3V2vfbzb; + double BSIM3V2ldeb; + double BSIM3V2k1ox; + double BSIM3V2k2ox; + + struct BSIM3V2SizeDependParam *pNext; +}; + + +typedef struct sBSIM3V2model +{ + int BSIM3V2modType; + struct sBSIM3V2model *BSIM3V2nextModel; + BSIM3V2instance *BSIM3V2instances; + IFuid BSIM3V2modName; + int BSIM3V2type; + + int BSIM3V2mobMod; + int BSIM3V2capMod; + int BSIM3V2noiMod; + int BSIM3V2binUnit; + int BSIM3V2paramChk; + double BSIM3V2version; + double BSIM3V2tox; + double BSIM3V2toxm; + double BSIM3V2cdsc; + double BSIM3V2cdscb; + double BSIM3V2cdscd; + double BSIM3V2cit; + double BSIM3V2nfactor; + double BSIM3V2xj; + double BSIM3V2vsat; + double BSIM3V2at; + double BSIM3V2a0; + double BSIM3V2ags; + double BSIM3V2a1; + double BSIM3V2a2; + double BSIM3V2keta; + double BSIM3V2nsub; + double BSIM3V2npeak; + double BSIM3V2ngate; + double BSIM3V2gamma1; + double BSIM3V2gamma2; + double BSIM3V2vbx; + double BSIM3V2vbm; + double BSIM3V2xt; + double BSIM3V2k1; + double BSIM3V2kt1; + double BSIM3V2kt1l; + double BSIM3V2kt2; + double BSIM3V2k2; + double BSIM3V2k3; + double BSIM3V2k3b; + double BSIM3V2w0; + double BSIM3V2nlx; + double BSIM3V2dvt0; + double BSIM3V2dvt1; + double BSIM3V2dvt2; + double BSIM3V2dvt0w; + double BSIM3V2dvt1w; + double BSIM3V2dvt2w; + double BSIM3V2drout; + double BSIM3V2dsub; + double BSIM3V2vth0; + double BSIM3V2ua; + double BSIM3V2ua1; + double BSIM3V2ub; + double BSIM3V2ub1; + double BSIM3V2uc; + double BSIM3V2uc1; + double BSIM3V2u0; + double BSIM3V2ute; + double BSIM3V2voff; + double BSIM3V2delta; + double BSIM3V2rdsw; + double BSIM3V2prwg; + double BSIM3V2prwb; + double BSIM3V2prt; + double BSIM3V2eta0; + double BSIM3V2etab; + double BSIM3V2pclm; + double BSIM3V2pdibl1; + double BSIM3V2pdibl2; + double BSIM3V2pdiblb; + double BSIM3V2pscbe1; + double BSIM3V2pscbe2; + double BSIM3V2pvag; + double BSIM3V2wr; + double BSIM3V2dwg; + double BSIM3V2dwb; + double BSIM3V2b0; + double BSIM3V2b1; + double BSIM3V2alpha0; + double BSIM3V2alpha1; + double BSIM3V2beta0; + double BSIM3V2ijth; + double BSIM3V2vfb; + + /* CV model */ + double BSIM3V2elm; + double BSIM3V2cgsl; + double BSIM3V2cgdl; + double BSIM3V2ckappa; + double BSIM3V2cf; + double BSIM3V2vfbcv; + double BSIM3V2clc; + double BSIM3V2cle; + double BSIM3V2dwc; + double BSIM3V2dlc; + double BSIM3V2noff; + double BSIM3V2voffcv; + double BSIM3V2acde; + double BSIM3V2moin; + double BSIM3V2tcj; + double BSIM3V2tcjsw; + double BSIM3V2tcjswg; + double BSIM3V2tpb; + double BSIM3V2tpbsw; + double BSIM3V2tpbswg; + + /* Length Dependence */ + double BSIM3V2lcdsc; + double BSIM3V2lcdscb; + double BSIM3V2lcdscd; + double BSIM3V2lcit; + double BSIM3V2lnfactor; + double BSIM3V2lxj; + double BSIM3V2lvsat; + double BSIM3V2lat; + double BSIM3V2la0; + double BSIM3V2lags; + double BSIM3V2la1; + double BSIM3V2la2; + double BSIM3V2lketa; + double BSIM3V2lnsub; + double BSIM3V2lnpeak; + double BSIM3V2lngate; + double BSIM3V2lgamma1; + double BSIM3V2lgamma2; + double BSIM3V2lvbx; + double BSIM3V2lvbm; + double BSIM3V2lxt; + double BSIM3V2lk1; + double BSIM3V2lkt1; + double BSIM3V2lkt1l; + double BSIM3V2lkt2; + double BSIM3V2lk2; + double BSIM3V2lk3; + double BSIM3V2lk3b; + double BSIM3V2lw0; + double BSIM3V2lnlx; + double BSIM3V2ldvt0; + double BSIM3V2ldvt1; + double BSIM3V2ldvt2; + double BSIM3V2ldvt0w; + double BSIM3V2ldvt1w; + double BSIM3V2ldvt2w; + double BSIM3V2ldrout; + double BSIM3V2ldsub; + double BSIM3V2lvth0; + double BSIM3V2lua; + double BSIM3V2lua1; + double BSIM3V2lub; + double BSIM3V2lub1; + double BSIM3V2luc; + double BSIM3V2luc1; + double BSIM3V2lu0; + double BSIM3V2lute; + double BSIM3V2lvoff; + double BSIM3V2ldelta; + double BSIM3V2lrdsw; + double BSIM3V2lprwg; + double BSIM3V2lprwb; + double BSIM3V2lprt; + double BSIM3V2leta0; + double BSIM3V2letab; + double BSIM3V2lpclm; + double BSIM3V2lpdibl1; + double BSIM3V2lpdibl2; + double BSIM3V2lpdiblb; + double BSIM3V2lpscbe1; + double BSIM3V2lpscbe2; + double BSIM3V2lpvag; + double BSIM3V2lwr; + double BSIM3V2ldwg; + double BSIM3V2ldwb; + double BSIM3V2lb0; + double BSIM3V2lb1; + double BSIM3V2lalpha0; + double BSIM3V2lalpha1; + double BSIM3V2lbeta0; + double BSIM3V2lvfb; + + /* CV model */ + double BSIM3V2lelm; + double BSIM3V2lcgsl; + double BSIM3V2lcgdl; + double BSIM3V2lckappa; + double BSIM3V2lcf; + double BSIM3V2lclc; + double BSIM3V2lcle; + double BSIM3V2lvfbcv; + double BSIM3V2lnoff; + double BSIM3V2lvoffcv; + double BSIM3V2lacde; + double BSIM3V2lmoin; + + /* Width Dependence */ + double BSIM3V2wcdsc; + double BSIM3V2wcdscb; + double BSIM3V2wcdscd; + double BSIM3V2wcit; + double BSIM3V2wnfactor; + double BSIM3V2wxj; + double BSIM3V2wvsat; + double BSIM3V2wat; + double BSIM3V2wa0; + double BSIM3V2wags; + double BSIM3V2wa1; + double BSIM3V2wa2; + double BSIM3V2wketa; + double BSIM3V2wnsub; + double BSIM3V2wnpeak; + double BSIM3V2wngate; + double BSIM3V2wgamma1; + double BSIM3V2wgamma2; + double BSIM3V2wvbx; + double BSIM3V2wvbm; + double BSIM3V2wxt; + double BSIM3V2wk1; + double BSIM3V2wkt1; + double BSIM3V2wkt1l; + double BSIM3V2wkt2; + double BSIM3V2wk2; + double BSIM3V2wk3; + double BSIM3V2wk3b; + double BSIM3V2ww0; + double BSIM3V2wnlx; + double BSIM3V2wdvt0; + double BSIM3V2wdvt1; + double BSIM3V2wdvt2; + double BSIM3V2wdvt0w; + double BSIM3V2wdvt1w; + double BSIM3V2wdvt2w; + double BSIM3V2wdrout; + double BSIM3V2wdsub; + double BSIM3V2wvth0; + double BSIM3V2wua; + double BSIM3V2wua1; + double BSIM3V2wub; + double BSIM3V2wub1; + double BSIM3V2wuc; + double BSIM3V2wuc1; + double BSIM3V2wu0; + double BSIM3V2wute; + double BSIM3V2wvoff; + double BSIM3V2wdelta; + double BSIM3V2wrdsw; + double BSIM3V2wprwg; + double BSIM3V2wprwb; + double BSIM3V2wprt; + double BSIM3V2weta0; + double BSIM3V2wetab; + double BSIM3V2wpclm; + double BSIM3V2wpdibl1; + double BSIM3V2wpdibl2; + double BSIM3V2wpdiblb; + double BSIM3V2wpscbe1; + double BSIM3V2wpscbe2; + double BSIM3V2wpvag; + double BSIM3V2wwr; + double BSIM3V2wdwg; + double BSIM3V2wdwb; + double BSIM3V2wb0; + double BSIM3V2wb1; + double BSIM3V2walpha0; + double BSIM3V2walpha1; + double BSIM3V2wbeta0; + double BSIM3V2wvfb; + + /* CV model */ + double BSIM3V2welm; + double BSIM3V2wcgsl; + double BSIM3V2wcgdl; + double BSIM3V2wckappa; + double BSIM3V2wcf; + double BSIM3V2wclc; + double BSIM3V2wcle; + double BSIM3V2wvfbcv; + double BSIM3V2wnoff; + double BSIM3V2wvoffcv; + double BSIM3V2wacde; + double BSIM3V2wmoin; + + /* Cross-term Dependence */ + double BSIM3V2pcdsc; + double BSIM3V2pcdscb; + double BSIM3V2pcdscd; + double BSIM3V2pcit; + double BSIM3V2pnfactor; + double BSIM3V2pxj; + double BSIM3V2pvsat; + double BSIM3V2pat; + double BSIM3V2pa0; + double BSIM3V2pags; + double BSIM3V2pa1; + double BSIM3V2pa2; + double BSIM3V2pketa; + double BSIM3V2pnsub; + double BSIM3V2pnpeak; + double BSIM3V2pngate; + double BSIM3V2pgamma1; + double BSIM3V2pgamma2; + double BSIM3V2pvbx; + double BSIM3V2pvbm; + double BSIM3V2pxt; + double BSIM3V2pk1; + double BSIM3V2pkt1; + double BSIM3V2pkt1l; + double BSIM3V2pkt2; + double BSIM3V2pk2; + double BSIM3V2pk3; + double BSIM3V2pk3b; + double BSIM3V2pw0; + double BSIM3V2pnlx; + double BSIM3V2pdvt0; + double BSIM3V2pdvt1; + double BSIM3V2pdvt2; + double BSIM3V2pdvt0w; + double BSIM3V2pdvt1w; + double BSIM3V2pdvt2w; + double BSIM3V2pdrout; + double BSIM3V2pdsub; + double BSIM3V2pvth0; + double BSIM3V2pua; + double BSIM3V2pua1; + double BSIM3V2pub; + double BSIM3V2pub1; + double BSIM3V2puc; + double BSIM3V2puc1; + double BSIM3V2pu0; + double BSIM3V2pute; + double BSIM3V2pvoff; + double BSIM3V2pdelta; + double BSIM3V2prdsw; + double BSIM3V2pprwg; + double BSIM3V2pprwb; + double BSIM3V2pprt; + double BSIM3V2peta0; + double BSIM3V2petab; + double BSIM3V2ppclm; + double BSIM3V2ppdibl1; + double BSIM3V2ppdibl2; + double BSIM3V2ppdiblb; + double BSIM3V2ppscbe1; + double BSIM3V2ppscbe2; + double BSIM3V2ppvag; + double BSIM3V2pwr; + double BSIM3V2pdwg; + double BSIM3V2pdwb; + double BSIM3V2pb0; + double BSIM3V2pb1; + double BSIM3V2palpha0; + double BSIM3V2palpha1; + double BSIM3V2pbeta0; + double BSIM3V2pvfb; + + /* CV model */ + double BSIM3V2pelm; + double BSIM3V2pcgsl; + double BSIM3V2pcgdl; + double BSIM3V2pckappa; + double BSIM3V2pcf; + double BSIM3V2pclc; + double BSIM3V2pcle; + double BSIM3V2pvfbcv; + double BSIM3V2pnoff; + double BSIM3V2pvoffcv; + double BSIM3V2pacde; + double BSIM3V2pmoin; + + double BSIM3V2tnom; + double BSIM3V2cgso; + double BSIM3V2cgdo; + double BSIM3V2cgbo; + double BSIM3V2xpart; + double BSIM3V2cFringOut; + double BSIM3V2cFringMax; + + double BSIM3V2sheetResistance; + double BSIM3V2jctSatCurDensity; + double BSIM3V2jctSidewallSatCurDensity; + double BSIM3V2bulkJctPotential; + double BSIM3V2bulkJctBotGradingCoeff; + double BSIM3V2bulkJctSideGradingCoeff; + double BSIM3V2bulkJctGateSideGradingCoeff; + double BSIM3V2sidewallJctPotential; + double BSIM3V2GatesidewallJctPotential; + double BSIM3V2unitAreaJctCap; + double BSIM3V2unitLengthSidewallJctCap; + double BSIM3V2unitLengthGateSidewallJctCap; + double BSIM3V2jctEmissionCoeff; + double BSIM3V2jctTempExponent; + + double BSIM3V2Lint; + double BSIM3V2Ll; + double BSIM3V2Llc; + double BSIM3V2Lln; + double BSIM3V2Lw; + double BSIM3V2Lwc; + double BSIM3V2Lwn; + double BSIM3V2Lwl; + double BSIM3V2Lwlc; + double BSIM3V2Lmin; + double BSIM3V2Lmax; + + double BSIM3V2Wint; + double BSIM3V2Wl; + double BSIM3V2Wlc; + double BSIM3V2Wln; + double BSIM3V2Ww; + double BSIM3V2Wwc; + double BSIM3V2Wwn; + double BSIM3V2Wwl; + double BSIM3V2Wwlc; + double BSIM3V2Wmin; + double BSIM3V2Wmax; + + +/* Pre-calculated constants */ + /* MCJ: move to size-dependent param. */ + double BSIM3V2vtm; + double BSIM3V2cox; + double BSIM3V2cof1; + double BSIM3V2cof2; + double BSIM3V2cof3; + double BSIM3V2cof4; + double BSIM3V2vcrit; + double BSIM3V2factor1; + double BSIM3V2PhiB; + double BSIM3V2PhiBSW; + double BSIM3V2PhiBSWG; + double BSIM3V2jctTempSatCurDensity; + double BSIM3V2jctSidewallTempSatCurDensity; + + double BSIM3V2oxideTrapDensityA; + double BSIM3V2oxideTrapDensityB; + double BSIM3V2oxideTrapDensityC; + double BSIM3V2em; + double BSIM3V2ef; + double BSIM3V2af; + double BSIM3V2kf; + + struct BSIM3V2SizeDependParam *pSizeDependParamKnot; + + /* Flags */ + unsigned BSIM3V2mobModGiven :1; + unsigned BSIM3V2binUnitGiven :1; + unsigned BSIM3V2capModGiven :1; + unsigned BSIM3V2paramChkGiven :1; + unsigned BSIM3V2noiModGiven :1; + unsigned BSIM3V2typeGiven :1; + unsigned BSIM3V2toxGiven :1; + unsigned BSIM3V2versionGiven :1; + unsigned BSIM3V2toxmGiven :1; + unsigned BSIM3V2cdscGiven :1; + unsigned BSIM3V2cdscbGiven :1; + unsigned BSIM3V2cdscdGiven :1; + unsigned BSIM3V2citGiven :1; + unsigned BSIM3V2nfactorGiven :1; + unsigned BSIM3V2xjGiven :1; + unsigned BSIM3V2vsatGiven :1; + unsigned BSIM3V2atGiven :1; + unsigned BSIM3V2a0Given :1; + unsigned BSIM3V2agsGiven :1; + unsigned BSIM3V2a1Given :1; + unsigned BSIM3V2a2Given :1; + unsigned BSIM3V2ketaGiven :1; + unsigned BSIM3V2nsubGiven :1; + unsigned BSIM3V2npeakGiven :1; + unsigned BSIM3V2ngateGiven :1; + unsigned BSIM3V2gamma1Given :1; + unsigned BSIM3V2gamma2Given :1; + unsigned BSIM3V2vbxGiven :1; + unsigned BSIM3V2vbmGiven :1; + unsigned BSIM3V2xtGiven :1; + unsigned BSIM3V2k1Given :1; + unsigned BSIM3V2kt1Given :1; + unsigned BSIM3V2kt1lGiven :1; + unsigned BSIM3V2kt2Given :1; + unsigned BSIM3V2k2Given :1; + unsigned BSIM3V2k3Given :1; + unsigned BSIM3V2k3bGiven :1; + unsigned BSIM3V2w0Given :1; + unsigned BSIM3V2nlxGiven :1; + unsigned BSIM3V2dvt0Given :1; + unsigned BSIM3V2dvt1Given :1; + unsigned BSIM3V2dvt2Given :1; + unsigned BSIM3V2dvt0wGiven :1; + unsigned BSIM3V2dvt1wGiven :1; + unsigned BSIM3V2dvt2wGiven :1; + unsigned BSIM3V2droutGiven :1; + unsigned BSIM3V2dsubGiven :1; + unsigned BSIM3V2vth0Given :1; + unsigned BSIM3V2uaGiven :1; + unsigned BSIM3V2ua1Given :1; + unsigned BSIM3V2ubGiven :1; + unsigned BSIM3V2ub1Given :1; + unsigned BSIM3V2ucGiven :1; + unsigned BSIM3V2uc1Given :1; + unsigned BSIM3V2u0Given :1; + unsigned BSIM3V2uteGiven :1; + unsigned BSIM3V2voffGiven :1; + unsigned BSIM3V2rdswGiven :1; + unsigned BSIM3V2prwgGiven :1; + unsigned BSIM3V2prwbGiven :1; + unsigned BSIM3V2prtGiven :1; + unsigned BSIM3V2eta0Given :1; + unsigned BSIM3V2etabGiven :1; + unsigned BSIM3V2pclmGiven :1; + unsigned BSIM3V2pdibl1Given :1; + unsigned BSIM3V2pdibl2Given :1; + unsigned BSIM3V2pdiblbGiven :1; + unsigned BSIM3V2pscbe1Given :1; + unsigned BSIM3V2pscbe2Given :1; + unsigned BSIM3V2pvagGiven :1; + unsigned BSIM3V2deltaGiven :1; + unsigned BSIM3V2wrGiven :1; + unsigned BSIM3V2dwgGiven :1; + unsigned BSIM3V2dwbGiven :1; + unsigned BSIM3V2b0Given :1; + unsigned BSIM3V2b1Given :1; + unsigned BSIM3V2alpha0Given :1; + unsigned BSIM3V2alpha1Given :1; + unsigned BSIM3V2beta0Given :1; + unsigned BSIM3V2ijthGiven :1; + unsigned BSIM3V2vfbGiven :1; + + /* CV model */ + unsigned BSIM3V2elmGiven :1; + unsigned BSIM3V2cgslGiven :1; + unsigned BSIM3V2cgdlGiven :1; + unsigned BSIM3V2ckappaGiven :1; + unsigned BSIM3V2cfGiven :1; + unsigned BSIM3V2vfbcvGiven :1; + unsigned BSIM3V2clcGiven :1; + unsigned BSIM3V2cleGiven :1; + unsigned BSIM3V2dwcGiven :1; + unsigned BSIM3V2dlcGiven :1; + unsigned BSIM3V2noffGiven :1; + unsigned BSIM3V2voffcvGiven :1; + unsigned BSIM3V2acdeGiven :1; + unsigned BSIM3V2moinGiven :1; + unsigned BSIM3V2tcjGiven :1; + unsigned BSIM3V2tcjswGiven :1; + unsigned BSIM3V2tcjswgGiven :1; + unsigned BSIM3V2tpbGiven :1; + unsigned BSIM3V2tpbswGiven :1; + unsigned BSIM3V2tpbswgGiven :1; + + + /* Length dependence */ + unsigned BSIM3V2lcdscGiven :1; + unsigned BSIM3V2lcdscbGiven :1; + unsigned BSIM3V2lcdscdGiven :1; + unsigned BSIM3V2lcitGiven :1; + unsigned BSIM3V2lnfactorGiven :1; + unsigned BSIM3V2lxjGiven :1; + unsigned BSIM3V2lvsatGiven :1; + unsigned BSIM3V2latGiven :1; + unsigned BSIM3V2la0Given :1; + unsigned BSIM3V2lagsGiven :1; + unsigned BSIM3V2la1Given :1; + unsigned BSIM3V2la2Given :1; + unsigned BSIM3V2lketaGiven :1; + unsigned BSIM3V2lnsubGiven :1; + unsigned BSIM3V2lnpeakGiven :1; + unsigned BSIM3V2lngateGiven :1; + unsigned BSIM3V2lgamma1Given :1; + unsigned BSIM3V2lgamma2Given :1; + unsigned BSIM3V2lvbxGiven :1; + unsigned BSIM3V2lvbmGiven :1; + unsigned BSIM3V2lxtGiven :1; + unsigned BSIM3V2lk1Given :1; + unsigned BSIM3V2lkt1Given :1; + unsigned BSIM3V2lkt1lGiven :1; + unsigned BSIM3V2lkt2Given :1; + unsigned BSIM3V2lk2Given :1; + unsigned BSIM3V2lk3Given :1; + unsigned BSIM3V2lk3bGiven :1; + unsigned BSIM3V2lw0Given :1; + unsigned BSIM3V2lnlxGiven :1; + unsigned BSIM3V2ldvt0Given :1; + unsigned BSIM3V2ldvt1Given :1; + unsigned BSIM3V2ldvt2Given :1; + unsigned BSIM3V2ldvt0wGiven :1; + unsigned BSIM3V2ldvt1wGiven :1; + unsigned BSIM3V2ldvt2wGiven :1; + unsigned BSIM3V2ldroutGiven :1; + unsigned BSIM3V2ldsubGiven :1; + unsigned BSIM3V2lvth0Given :1; + unsigned BSIM3V2luaGiven :1; + unsigned BSIM3V2lua1Given :1; + unsigned BSIM3V2lubGiven :1; + unsigned BSIM3V2lub1Given :1; + unsigned BSIM3V2lucGiven :1; + unsigned BSIM3V2luc1Given :1; + unsigned BSIM3V2lu0Given :1; + unsigned BSIM3V2luteGiven :1; + unsigned BSIM3V2lvoffGiven :1; + unsigned BSIM3V2lrdswGiven :1; + unsigned BSIM3V2lprwgGiven :1; + unsigned BSIM3V2lprwbGiven :1; + unsigned BSIM3V2lprtGiven :1; + unsigned BSIM3V2leta0Given :1; + unsigned BSIM3V2letabGiven :1; + unsigned BSIM3V2lpclmGiven :1; + unsigned BSIM3V2lpdibl1Given :1; + unsigned BSIM3V2lpdibl2Given :1; + unsigned BSIM3V2lpdiblbGiven :1; + unsigned BSIM3V2lpscbe1Given :1; + unsigned BSIM3V2lpscbe2Given :1; + unsigned BSIM3V2lpvagGiven :1; + unsigned BSIM3V2ldeltaGiven :1; + unsigned BSIM3V2lwrGiven :1; + unsigned BSIM3V2ldwgGiven :1; + unsigned BSIM3V2ldwbGiven :1; + unsigned BSIM3V2lb0Given :1; + unsigned BSIM3V2lb1Given :1; + unsigned BSIM3V2lalpha0Given :1; + unsigned BSIM3V2lalpha1Given :1; + unsigned BSIM3V2lbeta0Given :1; + unsigned BSIM3V2lvfbGiven :1; + + /* CV model */ + unsigned BSIM3V2lelmGiven :1; + unsigned BSIM3V2lcgslGiven :1; + unsigned BSIM3V2lcgdlGiven :1; + unsigned BSIM3V2lckappaGiven :1; + unsigned BSIM3V2lcfGiven :1; + unsigned BSIM3V2lclcGiven :1; + unsigned BSIM3V2lcleGiven :1; + unsigned BSIM3V2lvfbcvGiven :1; + unsigned BSIM3V2lnoffGiven :1; + unsigned BSIM3V2lvoffcvGiven :1; + unsigned BSIM3V2lacdeGiven :1; + unsigned BSIM3V2lmoinGiven :1; + + /* Width dependence */ + unsigned BSIM3V2wcdscGiven :1; + unsigned BSIM3V2wcdscbGiven :1; + unsigned BSIM3V2wcdscdGiven :1; + unsigned BSIM3V2wcitGiven :1; + unsigned BSIM3V2wnfactorGiven :1; + unsigned BSIM3V2wxjGiven :1; + unsigned BSIM3V2wvsatGiven :1; + unsigned BSIM3V2watGiven :1; + unsigned BSIM3V2wa0Given :1; + unsigned BSIM3V2wagsGiven :1; + unsigned BSIM3V2wa1Given :1; + unsigned BSIM3V2wa2Given :1; + unsigned BSIM3V2wketaGiven :1; + unsigned BSIM3V2wnsubGiven :1; + unsigned BSIM3V2wnpeakGiven :1; + unsigned BSIM3V2wngateGiven :1; + unsigned BSIM3V2wgamma1Given :1; + unsigned BSIM3V2wgamma2Given :1; + unsigned BSIM3V2wvbxGiven :1; + unsigned BSIM3V2wvbmGiven :1; + unsigned BSIM3V2wxtGiven :1; + unsigned BSIM3V2wk1Given :1; + unsigned BSIM3V2wkt1Given :1; + unsigned BSIM3V2wkt1lGiven :1; + unsigned BSIM3V2wkt2Given :1; + unsigned BSIM3V2wk2Given :1; + unsigned BSIM3V2wk3Given :1; + unsigned BSIM3V2wk3bGiven :1; + unsigned BSIM3V2ww0Given :1; + unsigned BSIM3V2wnlxGiven :1; + unsigned BSIM3V2wdvt0Given :1; + unsigned BSIM3V2wdvt1Given :1; + unsigned BSIM3V2wdvt2Given :1; + unsigned BSIM3V2wdvt0wGiven :1; + unsigned BSIM3V2wdvt1wGiven :1; + unsigned BSIM3V2wdvt2wGiven :1; + unsigned BSIM3V2wdroutGiven :1; + unsigned BSIM3V2wdsubGiven :1; + unsigned BSIM3V2wvth0Given :1; + unsigned BSIM3V2wuaGiven :1; + unsigned BSIM3V2wua1Given :1; + unsigned BSIM3V2wubGiven :1; + unsigned BSIM3V2wub1Given :1; + unsigned BSIM3V2wucGiven :1; + unsigned BSIM3V2wuc1Given :1; + unsigned BSIM3V2wu0Given :1; + unsigned BSIM3V2wuteGiven :1; + unsigned BSIM3V2wvoffGiven :1; + unsigned BSIM3V2wrdswGiven :1; + unsigned BSIM3V2wprwgGiven :1; + unsigned BSIM3V2wprwbGiven :1; + unsigned BSIM3V2wprtGiven :1; + unsigned BSIM3V2weta0Given :1; + unsigned BSIM3V2wetabGiven :1; + unsigned BSIM3V2wpclmGiven :1; + unsigned BSIM3V2wpdibl1Given :1; + unsigned BSIM3V2wpdibl2Given :1; + unsigned BSIM3V2wpdiblbGiven :1; + unsigned BSIM3V2wpscbe1Given :1; + unsigned BSIM3V2wpscbe2Given :1; + unsigned BSIM3V2wpvagGiven :1; + unsigned BSIM3V2wdeltaGiven :1; + unsigned BSIM3V2wwrGiven :1; + unsigned BSIM3V2wdwgGiven :1; + unsigned BSIM3V2wdwbGiven :1; + unsigned BSIM3V2wb0Given :1; + unsigned BSIM3V2wb1Given :1; + unsigned BSIM3V2walpha0Given :1; + unsigned BSIM3V2walpha1Given :1; + unsigned BSIM3V2wbeta0Given :1; + unsigned BSIM3V2wvfbGiven :1; + + /* CV model */ + unsigned BSIM3V2welmGiven :1; + unsigned BSIM3V2wcgslGiven :1; + unsigned BSIM3V2wcgdlGiven :1; + unsigned BSIM3V2wckappaGiven :1; + unsigned BSIM3V2wcfGiven :1; + unsigned BSIM3V2wclcGiven :1; + unsigned BSIM3V2wcleGiven :1; + unsigned BSIM3V2wvfbcvGiven :1; + unsigned BSIM3V2wnoffGiven :1; + unsigned BSIM3V2wvoffcvGiven :1; + unsigned BSIM3V2wacdeGiven :1; + unsigned BSIM3V2wmoinGiven :1; + + /* Cross-term dependence */ + unsigned BSIM3V2pcdscGiven :1; + unsigned BSIM3V2pcdscbGiven :1; + unsigned BSIM3V2pcdscdGiven :1; + unsigned BSIM3V2pcitGiven :1; + unsigned BSIM3V2pnfactorGiven :1; + unsigned BSIM3V2pxjGiven :1; + unsigned BSIM3V2pvsatGiven :1; + unsigned BSIM3V2patGiven :1; + unsigned BSIM3V2pa0Given :1; + unsigned BSIM3V2pagsGiven :1; + unsigned BSIM3V2pa1Given :1; + unsigned BSIM3V2pa2Given :1; + unsigned BSIM3V2pketaGiven :1; + unsigned BSIM3V2pnsubGiven :1; + unsigned BSIM3V2pnpeakGiven :1; + unsigned BSIM3V2pngateGiven :1; + unsigned BSIM3V2pgamma1Given :1; + unsigned BSIM3V2pgamma2Given :1; + unsigned BSIM3V2pvbxGiven :1; + unsigned BSIM3V2pvbmGiven :1; + unsigned BSIM3V2pxtGiven :1; + unsigned BSIM3V2pk1Given :1; + unsigned BSIM3V2pkt1Given :1; + unsigned BSIM3V2pkt1lGiven :1; + unsigned BSIM3V2pkt2Given :1; + unsigned BSIM3V2pk2Given :1; + unsigned BSIM3V2pk3Given :1; + unsigned BSIM3V2pk3bGiven :1; + unsigned BSIM3V2pw0Given :1; + unsigned BSIM3V2pnlxGiven :1; + unsigned BSIM3V2pdvt0Given :1; + unsigned BSIM3V2pdvt1Given :1; + unsigned BSIM3V2pdvt2Given :1; + unsigned BSIM3V2pdvt0wGiven :1; + unsigned BSIM3V2pdvt1wGiven :1; + unsigned BSIM3V2pdvt2wGiven :1; + unsigned BSIM3V2pdroutGiven :1; + unsigned BSIM3V2pdsubGiven :1; + unsigned BSIM3V2pvth0Given :1; + unsigned BSIM3V2puaGiven :1; + unsigned BSIM3V2pua1Given :1; + unsigned BSIM3V2pubGiven :1; + unsigned BSIM3V2pub1Given :1; + unsigned BSIM3V2pucGiven :1; + unsigned BSIM3V2puc1Given :1; + unsigned BSIM3V2pu0Given :1; + unsigned BSIM3V2puteGiven :1; + unsigned BSIM3V2pvoffGiven :1; + unsigned BSIM3V2prdswGiven :1; + unsigned BSIM3V2pprwgGiven :1; + unsigned BSIM3V2pprwbGiven :1; + unsigned BSIM3V2pprtGiven :1; + unsigned BSIM3V2peta0Given :1; + unsigned BSIM3V2petabGiven :1; + unsigned BSIM3V2ppclmGiven :1; + unsigned BSIM3V2ppdibl1Given :1; + unsigned BSIM3V2ppdibl2Given :1; + unsigned BSIM3V2ppdiblbGiven :1; + unsigned BSIM3V2ppscbe1Given :1; + unsigned BSIM3V2ppscbe2Given :1; + unsigned BSIM3V2ppvagGiven :1; + unsigned BSIM3V2pdeltaGiven :1; + unsigned BSIM3V2pwrGiven :1; + unsigned BSIM3V2pdwgGiven :1; + unsigned BSIM3V2pdwbGiven :1; + unsigned BSIM3V2pb0Given :1; + unsigned BSIM3V2pb1Given :1; + unsigned BSIM3V2palpha0Given :1; + unsigned BSIM3V2palpha1Given :1; + unsigned BSIM3V2pbeta0Given :1; + unsigned BSIM3V2pvfbGiven :1; + + /* CV model */ + unsigned BSIM3V2pelmGiven :1; + unsigned BSIM3V2pcgslGiven :1; + unsigned BSIM3V2pcgdlGiven :1; + unsigned BSIM3V2pckappaGiven :1; + unsigned BSIM3V2pcfGiven :1; + unsigned BSIM3V2pclcGiven :1; + unsigned BSIM3V2pcleGiven :1; + unsigned BSIM3V2pvfbcvGiven :1; + unsigned BSIM3V2pnoffGiven :1; + unsigned BSIM3V2pvoffcvGiven :1; + unsigned BSIM3V2pacdeGiven :1; + unsigned BSIM3V2pmoinGiven :1; + + unsigned BSIM3V2useFringeGiven :1; + + unsigned BSIM3V2tnomGiven :1; + unsigned BSIM3V2cgsoGiven :1; + unsigned BSIM3V2cgdoGiven :1; + unsigned BSIM3V2cgboGiven :1; + unsigned BSIM3V2xpartGiven :1; + unsigned BSIM3V2sheetResistanceGiven :1; + unsigned BSIM3V2jctSatCurDensityGiven :1; + unsigned BSIM3V2jctSidewallSatCurDensityGiven :1; + unsigned BSIM3V2bulkJctPotentialGiven :1; + unsigned BSIM3V2bulkJctBotGradingCoeffGiven :1; + unsigned BSIM3V2sidewallJctPotentialGiven :1; + unsigned BSIM3V2GatesidewallJctPotentialGiven :1; + unsigned BSIM3V2bulkJctSideGradingCoeffGiven :1; + unsigned BSIM3V2unitAreaJctCapGiven :1; + unsigned BSIM3V2unitLengthSidewallJctCapGiven :1; + unsigned BSIM3V2bulkJctGateSideGradingCoeffGiven :1; + unsigned BSIM3V2unitLengthGateSidewallJctCapGiven :1; + unsigned BSIM3V2jctEmissionCoeffGiven :1; + unsigned BSIM3V2jctTempExponentGiven :1; + + unsigned BSIM3V2oxideTrapDensityAGiven :1; + unsigned BSIM3V2oxideTrapDensityBGiven :1; + unsigned BSIM3V2oxideTrapDensityCGiven :1; + unsigned BSIM3V2emGiven :1; + unsigned BSIM3V2efGiven :1; + unsigned BSIM3V2afGiven :1; + unsigned BSIM3V2kfGiven :1; + + unsigned BSIM3V2LintGiven :1; + unsigned BSIM3V2LlGiven :1; + unsigned BSIM3V2LlcGiven :1; + unsigned BSIM3V2LlnGiven :1; + unsigned BSIM3V2LwGiven :1; + unsigned BSIM3V2LwcGiven :1; + unsigned BSIM3V2LwnGiven :1; + unsigned BSIM3V2LwlGiven :1; + unsigned BSIM3V2LwlcGiven :1; + unsigned BSIM3V2LminGiven :1; + unsigned BSIM3V2LmaxGiven :1; + + unsigned BSIM3V2WintGiven :1; + unsigned BSIM3V2WlGiven :1; + unsigned BSIM3V2WlcGiven :1; + unsigned BSIM3V2WlnGiven :1; + unsigned BSIM3V2WwGiven :1; + unsigned BSIM3V2WwcGiven :1; + unsigned BSIM3V2WwnGiven :1; + unsigned BSIM3V2WwlGiven :1; + unsigned BSIM3V2WwlcGiven :1; + unsigned BSIM3V2WminGiven :1; + unsigned BSIM3V2WmaxGiven :1; + +} BSIM3V2model; + + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + + +/* device parameters */ +#define BSIM3V2_W 1 +#define BSIM3V2_L 2 +#define BSIM3V2_AS 3 +#define BSIM3V2_AD 4 +#define BSIM3V2_PS 5 +#define BSIM3V2_PD 6 +#define BSIM3V2_NRS 7 +#define BSIM3V2_NRD 8 +#define BSIM3V2_OFF 9 +#define BSIM3V2_IC_VBS 10 +#define BSIM3V2_IC_VDS 11 +#define BSIM3V2_IC_VGS 12 +#define BSIM3V2_IC 13 +#define BSIM3V2_NQSMOD 14 + +/* model parameters */ +#define BSIM3V2_MOD_CAPMOD 101 +#define BSIM3V2_MOD_MOBMOD 103 +#define BSIM3V2_MOD_NOIMOD 104 + +#define BSIM3V2_MOD_TOX 105 + +#define BSIM3V2_MOD_CDSC 106 +#define BSIM3V2_MOD_CDSCB 107 +#define BSIM3V2_MOD_CIT 108 +#define BSIM3V2_MOD_NFACTOR 109 +#define BSIM3V2_MOD_XJ 110 +#define BSIM3V2_MOD_VSAT 111 +#define BSIM3V2_MOD_AT 112 +#define BSIM3V2_MOD_A0 113 +#define BSIM3V2_MOD_A1 114 +#define BSIM3V2_MOD_A2 115 +#define BSIM3V2_MOD_KETA 116 +#define BSIM3V2_MOD_NSUB 117 +#define BSIM3V2_MOD_NPEAK 118 +#define BSIM3V2_MOD_NGATE 120 +#define BSIM3V2_MOD_GAMMA1 121 +#define BSIM3V2_MOD_GAMMA2 122 +#define BSIM3V2_MOD_VBX 123 +#define BSIM3V2_MOD_BINUNIT 124 + +#define BSIM3V2_MOD_VBM 125 + +#define BSIM3V2_MOD_XT 126 +#define BSIM3V2_MOD_K1 129 +#define BSIM3V2_MOD_KT1 130 +#define BSIM3V2_MOD_KT1L 131 +#define BSIM3V2_MOD_K2 132 +#define BSIM3V2_MOD_KT2 133 +#define BSIM3V2_MOD_K3 134 +#define BSIM3V2_MOD_K3B 135 +#define BSIM3V2_MOD_W0 136 +#define BSIM3V2_MOD_NLX 137 + +#define BSIM3V2_MOD_DVT0 138 +#define BSIM3V2_MOD_DVT1 139 +#define BSIM3V2_MOD_DVT2 140 + +#define BSIM3V2_MOD_DVT0W 141 +#define BSIM3V2_MOD_DVT1W 142 +#define BSIM3V2_MOD_DVT2W 143 + +#define BSIM3V2_MOD_DROUT 144 +#define BSIM3V2_MOD_DSUB 145 +#define BSIM3V2_MOD_VTH0 146 +#define BSIM3V2_MOD_UA 147 +#define BSIM3V2_MOD_UA1 148 +#define BSIM3V2_MOD_UB 149 +#define BSIM3V2_MOD_UB1 150 +#define BSIM3V2_MOD_UC 151 +#define BSIM3V2_MOD_UC1 152 +#define BSIM3V2_MOD_U0 153 +#define BSIM3V2_MOD_UTE 154 +#define BSIM3V2_MOD_VOFF 155 +#define BSIM3V2_MOD_DELTA 156 +#define BSIM3V2_MOD_RDSW 157 +#define BSIM3V2_MOD_PRT 158 +#define BSIM3V2_MOD_LDD 159 +#define BSIM3V2_MOD_ETA 160 +#define BSIM3V2_MOD_ETA0 161 +#define BSIM3V2_MOD_ETAB 162 +#define BSIM3V2_MOD_PCLM 163 +#define BSIM3V2_MOD_PDIBL1 164 +#define BSIM3V2_MOD_PDIBL2 165 +#define BSIM3V2_MOD_PSCBE1 166 +#define BSIM3V2_MOD_PSCBE2 167 +#define BSIM3V2_MOD_PVAG 168 +#define BSIM3V2_MOD_WR 169 +#define BSIM3V2_MOD_DWG 170 +#define BSIM3V2_MOD_DWB 171 +#define BSIM3V2_MOD_B0 172 +#define BSIM3V2_MOD_B1 173 +#define BSIM3V2_MOD_ALPHA0 174 +#define BSIM3V2_MOD_BETA0 175 +#define BSIM3V2_MOD_PDIBLB 178 + +#define BSIM3V2_MOD_PRWG 179 +#define BSIM3V2_MOD_PRWB 180 + +#define BSIM3V2_MOD_CDSCD 181 +#define BSIM3V2_MOD_AGS 182 + +#define BSIM3V2_MOD_FRINGE 184 +#define BSIM3V2_MOD_ELM 185 +#define BSIM3V2_MOD_CGSL 186 +#define BSIM3V2_MOD_CGDL 187 +#define BSIM3V2_MOD_CKAPPA 188 +#define BSIM3V2_MOD_CF 189 +#define BSIM3V2_MOD_CLC 190 +#define BSIM3V2_MOD_CLE 191 +#define BSIM3V2_MOD_PARAMCHK 192 +#define BSIM3V2_MOD_VERSION 193 +#define BSIM3V2_MOD_VFBCV 194 +#define BSIM3V2_MOD_ACDE 195 +#define BSIM3V2_MOD_MOIN 196 +#define BSIM3V2_MOD_NOFF 197 +#define BSIM3V2_MOD_IJTH 198 +#define BSIM3V2_MOD_ALPHA1 199 +#define BSIM3V2_MOD_VFB 200 +#define BSIM3V2_MOD_TOXM 201 +#define BSIM3V2_MOD_TCJ 202 +#define BSIM3V2_MOD_TCJSW 203 +#define BSIM3V2_MOD_TCJSWG 204 +#define BSIM3V2_MOD_TPB 205 +#define BSIM3V2_MOD_TPBSW 206 +#define BSIM3V2_MOD_TPBSWG 207 +#define BSIM3V2_MOD_VOFFCV 208 + +/* Length dependence */ +#define BSIM3V2_MOD_LCDSC 251 +#define BSIM3V2_MOD_LCDSCB 252 +#define BSIM3V2_MOD_LCIT 253 +#define BSIM3V2_MOD_LNFACTOR 254 +#define BSIM3V2_MOD_LXJ 255 +#define BSIM3V2_MOD_LVSAT 256 +#define BSIM3V2_MOD_LAT 257 +#define BSIM3V2_MOD_LA0 258 +#define BSIM3V2_MOD_LA1 259 +#define BSIM3V2_MOD_LA2 260 +#define BSIM3V2_MOD_LKETA 261 +#define BSIM3V2_MOD_LNSUB 262 +#define BSIM3V2_MOD_LNPEAK 263 +#define BSIM3V2_MOD_LNGATE 265 +#define BSIM3V2_MOD_LGAMMA1 266 +#define BSIM3V2_MOD_LGAMMA2 267 +#define BSIM3V2_MOD_LVBX 268 + +#define BSIM3V2_MOD_LVBM 270 + +#define BSIM3V2_MOD_LXT 272 +#define BSIM3V2_MOD_LK1 275 +#define BSIM3V2_MOD_LKT1 276 +#define BSIM3V2_MOD_LKT1L 277 +#define BSIM3V2_MOD_LK2 278 +#define BSIM3V2_MOD_LKT2 279 +#define BSIM3V2_MOD_LK3 280 +#define BSIM3V2_MOD_LK3B 281 +#define BSIM3V2_MOD_LW0 282 +#define BSIM3V2_MOD_LNLX 283 + +#define BSIM3V2_MOD_LDVT0 284 +#define BSIM3V2_MOD_LDVT1 285 +#define BSIM3V2_MOD_LDVT2 286 + +#define BSIM3V2_MOD_LDVT0W 287 +#define BSIM3V2_MOD_LDVT1W 288 +#define BSIM3V2_MOD_LDVT2W 289 + +#define BSIM3V2_MOD_LDROUT 290 +#define BSIM3V2_MOD_LDSUB 291 +#define BSIM3V2_MOD_LVTH0 292 +#define BSIM3V2_MOD_LUA 293 +#define BSIM3V2_MOD_LUA1 294 +#define BSIM3V2_MOD_LUB 295 +#define BSIM3V2_MOD_LUB1 296 +#define BSIM3V2_MOD_LUC 297 +#define BSIM3V2_MOD_LUC1 298 +#define BSIM3V2_MOD_LU0 299 +#define BSIM3V2_MOD_LUTE 300 +#define BSIM3V2_MOD_LVOFF 301 +#define BSIM3V2_MOD_LDELTA 302 +#define BSIM3V2_MOD_LRDSW 303 +#define BSIM3V2_MOD_LPRT 304 +#define BSIM3V2_MOD_LLDD 305 +#define BSIM3V2_MOD_LETA 306 +#define BSIM3V2_MOD_LETA0 307 +#define BSIM3V2_MOD_LETAB 308 +#define BSIM3V2_MOD_LPCLM 309 +#define BSIM3V2_MOD_LPDIBL1 310 +#define BSIM3V2_MOD_LPDIBL2 311 +#define BSIM3V2_MOD_LPSCBE1 312 +#define BSIM3V2_MOD_LPSCBE2 313 +#define BSIM3V2_MOD_LPVAG 314 +#define BSIM3V2_MOD_LWR 315 +#define BSIM3V2_MOD_LDWG 316 +#define BSIM3V2_MOD_LDWB 317 +#define BSIM3V2_MOD_LB0 318 +#define BSIM3V2_MOD_LB1 319 +#define BSIM3V2_MOD_LALPHA0 320 +#define BSIM3V2_MOD_LBETA0 321 +#define BSIM3V2_MOD_LPDIBLB 324 + +#define BSIM3V2_MOD_LPRWG 325 +#define BSIM3V2_MOD_LPRWB 326 + +#define BSIM3V2_MOD_LCDSCD 327 +#define BSIM3V2_MOD_LAGS 328 + + +#define BSIM3V2_MOD_LFRINGE 331 +#define BSIM3V2_MOD_LELM 332 +#define BSIM3V2_MOD_LCGSL 333 +#define BSIM3V2_MOD_LCGDL 334 +#define BSIM3V2_MOD_LCKAPPA 335 +#define BSIM3V2_MOD_LCF 336 +#define BSIM3V2_MOD_LCLC 337 +#define BSIM3V2_MOD_LCLE 338 +#define BSIM3V2_MOD_LVFBCV 339 +#define BSIM3V2_MOD_LACDE 340 +#define BSIM3V2_MOD_LMOIN 341 +#define BSIM3V2_MOD_LNOFF 342 +#define BSIM3V2_MOD_LALPHA1 344 +#define BSIM3V2_MOD_LVFB 345 +#define BSIM3V2_MOD_LVOFFCV 346 + +/* Width dependence */ +#define BSIM3V2_MOD_WCDSC 381 +#define BSIM3V2_MOD_WCDSCB 382 +#define BSIM3V2_MOD_WCIT 383 +#define BSIM3V2_MOD_WNFACTOR 384 +#define BSIM3V2_MOD_WXJ 385 +#define BSIM3V2_MOD_WVSAT 386 +#define BSIM3V2_MOD_WAT 387 +#define BSIM3V2_MOD_WA0 388 +#define BSIM3V2_MOD_WA1 389 +#define BSIM3V2_MOD_WA2 390 +#define BSIM3V2_MOD_WKETA 391 +#define BSIM3V2_MOD_WNSUB 392 +#define BSIM3V2_MOD_WNPEAK 393 +#define BSIM3V2_MOD_WNGATE 395 +#define BSIM3V2_MOD_WGAMMA1 396 +#define BSIM3V2_MOD_WGAMMA2 397 +#define BSIM3V2_MOD_WVBX 398 + +#define BSIM3V2_MOD_WVBM 400 + +#define BSIM3V2_MOD_WXT 402 +#define BSIM3V2_MOD_WK1 405 +#define BSIM3V2_MOD_WKT1 406 +#define BSIM3V2_MOD_WKT1L 407 +#define BSIM3V2_MOD_WK2 408 +#define BSIM3V2_MOD_WKT2 409 +#define BSIM3V2_MOD_WK3 410 +#define BSIM3V2_MOD_WK3B 411 +#define BSIM3V2_MOD_WW0 412 +#define BSIM3V2_MOD_WNLX 413 + +#define BSIM3V2_MOD_WDVT0 414 +#define BSIM3V2_MOD_WDVT1 415 +#define BSIM3V2_MOD_WDVT2 416 + +#define BSIM3V2_MOD_WDVT0W 417 +#define BSIM3V2_MOD_WDVT1W 418 +#define BSIM3V2_MOD_WDVT2W 419 + +#define BSIM3V2_MOD_WDROUT 420 +#define BSIM3V2_MOD_WDSUB 421 +#define BSIM3V2_MOD_WVTH0 422 +#define BSIM3V2_MOD_WUA 423 +#define BSIM3V2_MOD_WUA1 424 +#define BSIM3V2_MOD_WUB 425 +#define BSIM3V2_MOD_WUB1 426 +#define BSIM3V2_MOD_WUC 427 +#define BSIM3V2_MOD_WUC1 428 +#define BSIM3V2_MOD_WU0 429 +#define BSIM3V2_MOD_WUTE 430 +#define BSIM3V2_MOD_WVOFF 431 +#define BSIM3V2_MOD_WDELTA 432 +#define BSIM3V2_MOD_WRDSW 433 +#define BSIM3V2_MOD_WPRT 434 +#define BSIM3V2_MOD_WLDD 435 +#define BSIM3V2_MOD_WETA 436 +#define BSIM3V2_MOD_WETA0 437 +#define BSIM3V2_MOD_WETAB 438 +#define BSIM3V2_MOD_WPCLM 439 +#define BSIM3V2_MOD_WPDIBL1 440 +#define BSIM3V2_MOD_WPDIBL2 441 +#define BSIM3V2_MOD_WPSCBE1 442 +#define BSIM3V2_MOD_WPSCBE2 443 +#define BSIM3V2_MOD_WPVAG 444 +#define BSIM3V2_MOD_WWR 445 +#define BSIM3V2_MOD_WDWG 446 +#define BSIM3V2_MOD_WDWB 447 +#define BSIM3V2_MOD_WB0 448 +#define BSIM3V2_MOD_WB1 449 +#define BSIM3V2_MOD_WALPHA0 450 +#define BSIM3V2_MOD_WBETA0 451 +#define BSIM3V2_MOD_WPDIBLB 454 + +#define BSIM3V2_MOD_WPRWG 455 +#define BSIM3V2_MOD_WPRWB 456 + +#define BSIM3V2_MOD_WCDSCD 457 +#define BSIM3V2_MOD_WAGS 458 + + +#define BSIM3V2_MOD_WFRINGE 461 +#define BSIM3V2_MOD_WELM 462 +#define BSIM3V2_MOD_WCGSL 463 +#define BSIM3V2_MOD_WCGDL 464 +#define BSIM3V2_MOD_WCKAPPA 465 +#define BSIM3V2_MOD_WCF 466 +#define BSIM3V2_MOD_WCLC 467 +#define BSIM3V2_MOD_WCLE 468 +#define BSIM3V2_MOD_WVFBCV 469 +#define BSIM3V2_MOD_WACDE 470 +#define BSIM3V2_MOD_WMOIN 471 +#define BSIM3V2_MOD_WNOFF 472 +#define BSIM3V2_MOD_WALPHA1 474 +#define BSIM3V2_MOD_WVFB 475 +#define BSIM3V2_MOD_WVOFFCV 476 + +/* Cross-term dependence */ +#define BSIM3V2_MOD_PCDSC 511 +#define BSIM3V2_MOD_PCDSCB 512 +#define BSIM3V2_MOD_PCIT 513 +#define BSIM3V2_MOD_PNFACTOR 514 +#define BSIM3V2_MOD_PXJ 515 +#define BSIM3V2_MOD_PVSAT 516 +#define BSIM3V2_MOD_PAT 517 +#define BSIM3V2_MOD_PA0 518 +#define BSIM3V2_MOD_PA1 519 +#define BSIM3V2_MOD_PA2 520 +#define BSIM3V2_MOD_PKETA 521 +#define BSIM3V2_MOD_PNSUB 522 +#define BSIM3V2_MOD_PNPEAK 523 +#define BSIM3V2_MOD_PNGATE 525 +#define BSIM3V2_MOD_PGAMMA1 526 +#define BSIM3V2_MOD_PGAMMA2 527 +#define BSIM3V2_MOD_PVBX 528 + +#define BSIM3V2_MOD_PVBM 530 + +#define BSIM3V2_MOD_PXT 532 +#define BSIM3V2_MOD_PK1 535 +#define BSIM3V2_MOD_PKT1 536 +#define BSIM3V2_MOD_PKT1L 537 +#define BSIM3V2_MOD_PK2 538 +#define BSIM3V2_MOD_PKT2 539 +#define BSIM3V2_MOD_PK3 540 +#define BSIM3V2_MOD_PK3B 541 +#define BSIM3V2_MOD_PW0 542 +#define BSIM3V2_MOD_PNLX 543 + +#define BSIM3V2_MOD_PDVT0 544 +#define BSIM3V2_MOD_PDVT1 545 +#define BSIM3V2_MOD_PDVT2 546 + +#define BSIM3V2_MOD_PDVT0W 547 +#define BSIM3V2_MOD_PDVT1W 548 +#define BSIM3V2_MOD_PDVT2W 549 + +#define BSIM3V2_MOD_PDROUT 550 +#define BSIM3V2_MOD_PDSUB 551 +#define BSIM3V2_MOD_PVTH0 552 +#define BSIM3V2_MOD_PUA 553 +#define BSIM3V2_MOD_PUA1 554 +#define BSIM3V2_MOD_PUB 555 +#define BSIM3V2_MOD_PUB1 556 +#define BSIM3V2_MOD_PUC 557 +#define BSIM3V2_MOD_PUC1 558 +#define BSIM3V2_MOD_PU0 559 +#define BSIM3V2_MOD_PUTE 560 +#define BSIM3V2_MOD_PVOFF 561 +#define BSIM3V2_MOD_PDELTA 562 +#define BSIM3V2_MOD_PRDSW 563 +#define BSIM3V2_MOD_PPRT 564 +#define BSIM3V2_MOD_PLDD 565 +#define BSIM3V2_MOD_PETA 566 +#define BSIM3V2_MOD_PETA0 567 +#define BSIM3V2_MOD_PETAB 568 +#define BSIM3V2_MOD_PPCLM 569 +#define BSIM3V2_MOD_PPDIBL1 570 +#define BSIM3V2_MOD_PPDIBL2 571 +#define BSIM3V2_MOD_PPSCBE1 572 +#define BSIM3V2_MOD_PPSCBE2 573 +#define BSIM3V2_MOD_PPVAG 574 +#define BSIM3V2_MOD_PWR 575 +#define BSIM3V2_MOD_PDWG 576 +#define BSIM3V2_MOD_PDWB 577 +#define BSIM3V2_MOD_PB0 578 +#define BSIM3V2_MOD_PB1 579 +#define BSIM3V2_MOD_PALPHA0 580 +#define BSIM3V2_MOD_PBETA0 581 +#define BSIM3V2_MOD_PPDIBLB 584 + +#define BSIM3V2_MOD_PPRWG 585 +#define BSIM3V2_MOD_PPRWB 586 + +#define BSIM3V2_MOD_PCDSCD 587 +#define BSIM3V2_MOD_PAGS 588 + +#define BSIM3V2_MOD_PFRINGE 591 +#define BSIM3V2_MOD_PELM 592 +#define BSIM3V2_MOD_PCGSL 593 +#define BSIM3V2_MOD_PCGDL 594 +#define BSIM3V2_MOD_PCKAPPA 595 +#define BSIM3V2_MOD_PCF 596 +#define BSIM3V2_MOD_PCLC 597 +#define BSIM3V2_MOD_PCLE 598 +#define BSIM3V2_MOD_PVFBCV 599 +#define BSIM3V2_MOD_PACDE 600 +#define BSIM3V2_MOD_PMOIN 601 +#define BSIM3V2_MOD_PNOFF 602 +#define BSIM3V2_MOD_PALPHA1 604 +#define BSIM3V2_MOD_PVFB 605 +#define BSIM3V2_MOD_PVOFFCV 606 + +#define BSIM3V2_MOD_TNOM 651 +#define BSIM3V2_MOD_CGSO 652 +#define BSIM3V2_MOD_CGDO 653 +#define BSIM3V2_MOD_CGBO 654 +#define BSIM3V2_MOD_XPART 655 + +#define BSIM3V2_MOD_RSH 656 +#define BSIM3V2_MOD_JS 657 +#define BSIM3V2_MOD_PB 658 +#define BSIM3V2_MOD_MJ 659 +#define BSIM3V2_MOD_PBSW 660 +#define BSIM3V2_MOD_MJSW 661 +#define BSIM3V2_MOD_CJ 662 +#define BSIM3V2_MOD_CJSW 663 +#define BSIM3V2_MOD_NMOS 664 +#define BSIM3V2_MOD_PMOS 665 + +#define BSIM3V2_MOD_NOIA 666 +#define BSIM3V2_MOD_NOIB 667 +#define BSIM3V2_MOD_NOIC 668 + +#define BSIM3V2_MOD_LINT 669 +#define BSIM3V2_MOD_LL 670 +#define BSIM3V2_MOD_LLN 671 +#define BSIM3V2_MOD_LW 672 +#define BSIM3V2_MOD_LWN 673 +#define BSIM3V2_MOD_LWL 674 +#define BSIM3V2_MOD_LMIN 675 +#define BSIM3V2_MOD_LMAX 676 + +#define BSIM3V2_MOD_WINT 677 +#define BSIM3V2_MOD_WL 678 +#define BSIM3V2_MOD_WLN 679 +#define BSIM3V2_MOD_WW 680 +#define BSIM3V2_MOD_WWN 681 +#define BSIM3V2_MOD_WWL 682 +#define BSIM3V2_MOD_WMIN 683 +#define BSIM3V2_MOD_WMAX 684 + +#define BSIM3V2_MOD_DWC 685 +#define BSIM3V2_MOD_DLC 686 + +#define BSIM3V2_MOD_EM 687 +#define BSIM3V2_MOD_EF 688 +#define BSIM3V2_MOD_AF 689 +#define BSIM3V2_MOD_KF 690 + +#define BSIM3V2_MOD_NJ 691 +#define BSIM3V2_MOD_XTI 692 + +#define BSIM3V2_MOD_PBSWG 693 +#define BSIM3V2_MOD_MJSWG 694 +#define BSIM3V2_MOD_CJSWG 695 +#define BSIM3V2_MOD_JSW 696 + +#define BSIM3V2_MOD_LLC 697 +#define BSIM3V2_MOD_LWC 698 +#define BSIM3V2_MOD_LWLC 699 + +#define BSIM3V2_MOD_WLC 700 +#define BSIM3V2_MOD_WWC 701 +#define BSIM3V2_MOD_WWLC 702 + +/* device questions */ +#define BSIM3V2_DNODE 751 +#define BSIM3V2_GNODE 752 +#define BSIM3V2_SNODE 753 +#define BSIM3V2_BNODE 754 +#define BSIM3V2_DNODEPRIME 755 +#define BSIM3V2_SNODEPRIME 756 +#define BSIM3V2_VBD 757 +#define BSIM3V2_VBS 758 +#define BSIM3V2_VGS 759 +#define BSIM3V2_VDS 760 +#define BSIM3V2_CD 761 +#define BSIM3V2_CBS 762 +#define BSIM3V2_CBD 763 +#define BSIM3V2_GM 764 +#define BSIM3V2_GDS 765 +#define BSIM3V2_GMBS 766 +#define BSIM3V2_GBD 767 +#define BSIM3V2_GBS 768 +#define BSIM3V2_QB 769 +#define BSIM3V2_CQB 770 +#define BSIM3V2_QG 771 +#define BSIM3V2_CQG 772 +#define BSIM3V2_QD 773 +#define BSIM3V2_CQD 774 +#define BSIM3V2_CGG 775 +#define BSIM3V2_CGD 776 +#define BSIM3V2_CGS 777 +#define BSIM3V2_CBG 778 +#define BSIM3V2_CAPBD 779 +#define BSIM3V2_CQBD 780 +#define BSIM3V2_CAPBS 781 +#define BSIM3V2_CQBS 782 +#define BSIM3V2_CDG 783 +#define BSIM3V2_CDD 784 +#define BSIM3V2_CDS 785 +#define BSIM3V2_VON 786 +#define BSIM3V2_VDSAT 787 +#define BSIM3V2_QBS 788 +#define BSIM3V2_QBD 789 +#define BSIM3V2_SOURCECONDUCT 790 +#define BSIM3V2_DRAINCONDUCT 791 +#define BSIM3V2_CBDB 792 +#define BSIM3V2_CBSB 793 + + +#include "bsim3v2ext.h" + +#ifdef __STDC__ +extern void BSIM3V2evaluate(double,double,double,BSIM3V2instance*,BSIM3V2model*, + double*,double*,double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, CKTcircuit*); +extern int BSIM3V2debug(BSIM3V2model*, BSIM3V2instance*, CKTcircuit*, int); +extern int BSIM3V2checkModel(BSIM3V2model*, BSIM3V2instance*, CKTcircuit*); +#else /* stdc */ +extern void BSIM3V2evaluate(); +extern int BSIM3V2debug(); +extern int BSIM3V2checkModel(); +#endif /* stdc */ + +#endif /*BSIM3V2*/ + diff --git a/src/spicelib/devices/bsim3v2/bsim3v2ext.h b/src/spicelib/devices/bsim3v2/bsim3v2ext.h new file mode 100644 index 000000000..65c1c5b9d --- /dev/null +++ b/src/spicelib/devices/bsim3v2/bsim3v2ext.h @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +File: bsim3v2ext.h +**********/ + +#ifdef __STDC__ +extern int BSIM3V2acLoad(GENmodel *,CKTcircuit*); +extern int BSIM3V2ask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int BSIM3V2convTest(GENmodel *,CKTcircuit*); +extern int BSIM3V2delete(GENmodel*,IFuid,GENinstance**); +extern void BSIM3V2destroy(GENmodel**); +extern int BSIM3V2getic(GENmodel*,CKTcircuit*); +extern int BSIM3V2load(GENmodel*,CKTcircuit*); +extern int BSIM3V2mAsk(CKTcircuit*,GENmodel *,int, IFvalue*); +extern int BSIM3V2mDelete(GENmodel**,IFuid,GENmodel*); +extern int BSIM3V2mParam(int,IFvalue*,GENmodel*); +extern void BSIM3V2mosCap(CKTcircuit*, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*); +extern int BSIM3V2param(int,IFvalue*,GENinstance*,IFvalue*); +extern int BSIM3V2pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int BSIM3V2setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int BSIM3V2unsetup(GENmodel*,CKTcircuit*); +extern int BSIM3V2temp(GENmodel*,CKTcircuit*); +extern int BSIM3V2trunc(GENmodel*,CKTcircuit*,double*); +extern int BSIM3V2noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ +extern int BSIM3V2acLoad(); +extern int BSIM3V2delete(); +extern void BSIM3V2destroy(); +extern int BSIM3V2getic(); +extern int BSIM3V2load(); +extern int BSIM3V2mDelete(); +extern int BSIM3V2ask(); +extern int BSIM3V2mAsk(); +extern int BSIM3V2convTest(); +extern int BSIM3V2temp(); +extern int BSIM3V2mParam(); +extern void BSIM3V2mosCap(); +extern int BSIM3V2param(); +extern int BSIM3V2pzLoad(); +extern int BSIM3V2setup(); +extern int BSIM3V2unsetup(); +extern int BSIM3V2trunc(); +extern int BSIM3V2noise(); + +#endif /* stdc */ + diff --git a/src/spicelib/devices/bsim3v2/bsim3v2itf.h b/src/spicelib/devices/bsim3v2/bsim3v2itf.h new file mode 100644 index 000000000..df8fcbd47 --- /dev/null +++ b/src/spicelib/devices/bsim3v2/bsim3v2itf.h @@ -0,0 +1,91 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1991 JianHui Huang and Min-Chie Jeng. +File: bsim3v2itf.h +**********/ +#ifdef DEV_bsim3v2 + +#ifndef DEV_BSIM3V2 +#define DEV_BSIM3V2 + +#include "bsim3v2ext.h" + +extern IFparm BSIM3V2pTable[ ]; +extern IFparm BSIM3V2mPTable[ ]; +extern char *BSIM3V2names[ ]; +extern int BSIM3V2pTSize; +extern int BSIM3V2mPTSize; +extern int BSIM3V2nSize; +extern int BSIM3V2iSize; +extern int BSIM3V2mSize; + +SPICEdev BSIM3V2info = { + { "BSIM3V2", + "Berkeley Short Channel IGFET Model Version-3 (3v3.2)", + + &BSIM3V2nSize, + &BSIM3V2nSize, + BSIM3V2names, + + &BSIM3V2pTSize, + BSIM3V2pTable, + + &BSIM3V2mPTSize, + BSIM3V2mPTable, + DEV_DEFAULT + }, + + BSIM3V2param, + BSIM3V2mParam, + BSIM3V2load, + BSIM3V2setup, + BSIM3V2unsetup, + BSIM3V2setup, + BSIM3V2temp, + BSIM3V2trunc, + NULL, + BSIM3V2acLoad, + NULL, + BSIM3V2destroy, +#ifdef DELETES + BSIM3V2mDelete, + BSIM3V2delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + BSIM3V2getic, + BSIM3V2ask, + BSIM3V2mAsk, +#ifdef AN_pz + BSIM3V2pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + BSIM3V2convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + +#ifdef AN_noise + BSIM3V2noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &BSIM3V2iSize, + &BSIM3V2mSize + +}; + +#endif +#endif + diff --git a/src/spicelib/devices/bsim4/B4TERMS_OF_USE b/src/spicelib/devices/bsim4/B4TERMS_OF_USE new file mode 100644 index 000000000..5cc4023bb --- /dev/null +++ b/src/spicelib/devices/bsim4/B4TERMS_OF_USE @@ -0,0 +1,33 @@ + +The terms under which the software is provided are as the following. + +Software is distributed as is, completely without warranty or service +support. The University of California and its employees are not liable +for the condition or performance of the software. + +The University owns the copyright but shall not be liable for any +infringement of copyright or other proprietary rights brought by third +parties against the users of the software. + +The University of California hereby disclaims all implied warranties. + +The University of California grants the users the right to modify, copy, +and redistribute the software and documentation, both within the user's +organization and externally, subject to the following restrictions: + +1. The users agree not to charge for the University of California code + itself but may charge for additions, extensions, or support. + +2. In any product based on the software, the users agree to acknowledge + the UC Berkeley BSIM Research Group that developed the software. This + acknowledgment shall appear in the product documentation. + +3. The users agree to obey all U.S. Government restrictions governing + redistribution or export of the software. + +4. The users agree to reproduce any copyright notice which appears on + the software on any copy or modification of such made available + to others. + +Chenming Hu, and Weidong Liu +Mar. 2000 diff --git a/src/spicelib/devices/bsim4/ChangeLog b/src/spicelib/devices/bsim4/ChangeLog new file mode 100644 index 000000000..1a877696d --- /dev/null +++ b/src/spicelib/devices/bsim4/ChangeLog @@ -0,0 +1,6 @@ +2000-04-04 Paolo Nenzi + + * *.c, *.h: Initial bsim4 support. Modified all files to conform + to ngspice headers and added paraller architecture + support (please do not use this, it is not supported, + it is included for developers only). diff --git a/src/spicelib/devices/bsim4/Makefile.am b/src/spicelib/devices/bsim4/Makefile.am new file mode 100644 index 000000000..dc5028300 --- /dev/null +++ b/src/spicelib/devices/bsim4/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libbsim4.la + +libbsim4_la_SOURCES = \ + b4.c \ + b4acld.c \ + b4ask.c \ + b4check.c \ + b4cvtest.c \ + b4del.c \ + b4dest.c \ + b4geo.c \ + b4getic.c \ + b4ld.c \ + b4mask.c \ + b4mdel.c \ + b4mpar.c \ + b4noi.c \ + b4par.c \ + b4pzld.c \ + b4set.c \ + b4temp.c \ + b4trunc.c \ + bsim4def.h \ + bsim4ext.h \ + bsim4itf.h + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/bsim4/b4.c b/src/spicelib/devices/bsim4/b4.c new file mode 100644 index 000000000..b210f5425 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4.c @@ -0,0 +1,705 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "bsim4def.h" + +IFparm BSIM4pTable[] = { /* parameters */ +IOP( "l", BSIM4_L, IF_REAL , "Length"), +IOP( "w", BSIM4_W, IF_REAL , "Width"), +IOP( "nf", BSIM4_NF, IF_REAL , "Number of fingers"), +IOP( "min", BSIM4_MIN, IF_INTEGER , "Minimize either D or S"), +IOP( "ad", BSIM4_AD, IF_REAL , "Drain area"), +IOP( "as", BSIM4_AS, IF_REAL , "Source area"), +IOP( "pd", BSIM4_PD, IF_REAL , "Drain perimeter"), +IOP( "ps", BSIM4_PS, IF_REAL , "Source perimeter"), +IOP( "nrd", BSIM4_NRD, IF_REAL , "Number of squares in drain"), +IOP( "nrs", BSIM4_NRS, IF_REAL , "Number of squares in source"), +IOP( "off", BSIM4_OFF, IF_FLAG , "Device is initially off"), +IOP( "rbdb", BSIM4_RBDB, IF_REAL , "Body resistance"), +IOP( "rbsb", BSIM4_RBSB, IF_REAL , "Body resistance"), +IOP( "rbpb", BSIM4_RBPB, IF_REAL , "Body resistance"), +IOP( "rbps", BSIM4_RBPS, IF_REAL , "Body resistance"), +IOP( "rbpd", BSIM4_RBPD, IF_REAL , "Body resistance"), + +IOP( "trnqsmod", BSIM4_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"), +IOP( "acnqsmod", BSIM4_ACNQSMOD, IF_INTEGER, "AC NQS model selector"), +IOP( "rbodymod", BSIM4_RBODYMOD, IF_INTEGER, "Distributed body R model selector"), +IOP( "rgatemod", BSIM4_RGATEMOD, IF_INTEGER, "Gate resistance model selector"), +IOP( "geomod", BSIM4_GEOMOD, IF_INTEGER, "Geometry dependent parasitics model selector"), +IOP( "rgeomod", BSIM4_RGEOMOD, IF_INTEGER, "S/D resistance and contact model selector"), +IP( "ic", BSIM4_IC, IF_REALVEC , "Vector of DS,GS,BS initial voltages"), +OP( "gmbs", BSIM4_GMBS, IF_REAL, "Gmb"), +OP( "gm", BSIM4_GM, IF_REAL, "Gm"), +OP( "gds", BSIM4_GDS, IF_REAL, "Gds"), +OP( "vdsat", BSIM4_VDSAT, IF_REAL, "Vdsat"), +OP( "vth", BSIM4_VON, IF_REAL, "Vth"), +OP( "id", BSIM4_CD, IF_REAL, "Ids"), +OP( "vbs", BSIM4_VBS, IF_REAL, "Vbs"), +OP( "vgs", BSIM4_VGS, IF_REAL, "Vgs"), +OP( "vds", BSIM4_VDS, IF_REAL, "Vds"), +}; + +IFparm BSIM4mPTable[] = { /* model parameters */ +IOP( "capmod", BSIM4_MOD_CAPMOD, IF_INTEGER, "Capacitance model selector"), +IOP( "diomod", BSIM4_MOD_DIOMOD, IF_INTEGER, "Diode IV model selector"), +IOP( "rdsmod", BSIM4_MOD_RDSMOD, IF_INTEGER, "Bias-dependent S/D resistance model selector"), +IOP( "trnqsmod", BSIM4_MOD_TRNQSMOD, IF_INTEGER, "Transient NQS model selector"), +IOP( "acnqsmod", BSIM4_MOD_ACNQSMOD, IF_INTEGER, "AC NQS model selector"), +IOP( "mobmod", BSIM4_MOD_MOBMOD, IF_INTEGER, "Mobility model selector"), +IOP( "rbodymod", BSIM4_MOD_RBODYMOD, IF_INTEGER, "Distributed body R model selector"), +IOP( "rgatemod", BSIM4_MOD_RGATEMOD, IF_INTEGER, "Gate R model selector"), +IOP( "permod", BSIM4_MOD_PERMOD, IF_INTEGER, "Pd and Ps model selector"), +IOP( "geomod", BSIM4_MOD_GEOMOD, IF_INTEGER, "Geometry dependent parasitics model selector"), +IOP( "fnoimod", BSIM4_MOD_FNOIMOD, IF_INTEGER, "Flicker noise model selector"), +IOP( "tnoimod", BSIM4_MOD_TNOIMOD, IF_INTEGER, "Thermal noise model selector"), +IOP( "igcmod", BSIM4_MOD_IGCMOD, IF_INTEGER, "Gate-to-channel Ig model selector"), +IOP( "igbmod", BSIM4_MOD_IGBMOD, IF_INTEGER, "Gate-to-body Ig model selector"), +IOP( "paramchk", BSIM4_MOD_PARAMCHK, IF_INTEGER, "Model parameter checking selector"), +IOP( "binunit", BSIM4_MOD_BINUNIT, IF_INTEGER, "Bin unit selector"), +IOP( "version", BSIM4_MOD_VERSION, IF_STRING, "parameter for model version"), +IOP( "toxe", BSIM4_MOD_TOXE, IF_REAL, "Electrical gate oxide thickness in meters"), +IOP( "toxp", BSIM4_MOD_TOXP, IF_REAL, "Physical gate oxide thickness in meters"), +IOP( "toxm", BSIM4_MOD_TOXM, IF_REAL, "Gate oxide thickness at which parameters are extracted"), +IOP( "toxref", BSIM4_MOD_TOXREF, IF_REAL, "Target tox value"), +IOP( "dtox", BSIM4_MOD_DTOX, IF_REAL, "Defined as (toxe - toxp) "), +IOP( "epsrox", BSIM4_MOD_EPSROX, IF_REAL, "Dielectric constant of the gate oxide relative to vacuum"), +IOP( "cdsc", BSIM4_MOD_CDSC, IF_REAL, "Drain/Source and channel coupling capacitance"), +IOP( "cdscb", BSIM4_MOD_CDSCB, IF_REAL, "Body-bias dependence of cdsc"), +IOP( "cdscd", BSIM4_MOD_CDSCD, IF_REAL, "Drain-bias dependence of cdsc"), +IOP( "cit", BSIM4_MOD_CIT, IF_REAL, "Interface state capacitance"), +IOP( "nfactor", BSIM4_MOD_NFACTOR, IF_REAL, "Subthreshold swing Coefficient"), +IOP( "xj", BSIM4_MOD_XJ, IF_REAL, "Junction depth in meters"), +IOP( "vsat", BSIM4_MOD_VSAT, IF_REAL, "Saturation velocity at tnom"), +IOP( "at", BSIM4_MOD_AT, IF_REAL, "Temperature coefficient of vsat"), +IOP( "a0", BSIM4_MOD_A0, IF_REAL, "Non-uniform depletion width effect coefficient."), +IOP( "ags", BSIM4_MOD_AGS, IF_REAL, "Gate bias coefficient of Abulk."), +IOP( "a1", BSIM4_MOD_A1, IF_REAL, "Non-saturation effect coefficient"), +IOP( "a2", BSIM4_MOD_A2, IF_REAL, "Non-saturation effect coefficient"), +IOP( "keta", BSIM4_MOD_KETA, IF_REAL, "Body-bias coefficient of non-uniform depletion width effect."), +IOP( "nsub", BSIM4_MOD_NSUB, IF_REAL, "Substrate doping concentration"), +IOP( "ndep", BSIM4_MOD_NDEP, IF_REAL, "Channel doping concentration at the depletion edge"), +IOP( "nsd", BSIM4_MOD_NSD, IF_REAL, "S/D doping concentration"), +IOP( "phin", BSIM4_MOD_PHIN, IF_REAL, "Adjusting parameter for surface potential due to non-uniform vertical doping"), +IOP( "ngate", BSIM4_MOD_NGATE, IF_REAL, "Poly-gate doping concentration"), +IOP( "gamma1", BSIM4_MOD_GAMMA1, IF_REAL, "Vth body coefficient"), +IOP( "gamma2", BSIM4_MOD_GAMMA2, IF_REAL, "Vth body coefficient"), +IOP( "vbx", BSIM4_MOD_VBX, IF_REAL, "Vth transition body Voltage"), +IOP( "vbm", BSIM4_MOD_VBM, IF_REAL, "Maximum body voltage"), + +IOP( "xt", BSIM4_MOD_XT, IF_REAL, "Doping depth"), +IOP( "k1", BSIM4_MOD_K1, IF_REAL, "Bulk effect coefficient 1"), +IOP( "kt1", BSIM4_MOD_KT1, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt1l", BSIM4_MOD_KT1L, IF_REAL, "Temperature coefficient of Vth"), +IOP( "kt2", BSIM4_MOD_KT2, IF_REAL, "Body-coefficient of kt1"), +IOP( "k2", BSIM4_MOD_K2, IF_REAL, "Bulk effect coefficient 2"), +IOP( "k3", BSIM4_MOD_K3, IF_REAL, "Narrow width effect coefficient"), +IOP( "k3b", BSIM4_MOD_K3B, IF_REAL, "Body effect coefficient of k3"), +IOP( "w0", BSIM4_MOD_W0, IF_REAL, "Narrow width effect parameter"), +IOP( "dvtp0", BSIM4_MOD_DVTP0, IF_REAL, "First parameter for Vth shift due to pocket"), +IOP( "dvtp1", BSIM4_MOD_DVTP1, IF_REAL, "Second parameter for Vth shift due to pocket"), +IOP( "lpe0", BSIM4_MOD_LPE0, IF_REAL, "Equivalent length of pocket region at zero bias"), +IOP( "lpeb", BSIM4_MOD_LPEB, IF_REAL, "Equivalent length of pocket region accounting for body bias"), +IOP( "dvt0", BSIM4_MOD_DVT0, IF_REAL, "Short channel effect coeff. 0"), +IOP( "dvt1", BSIM4_MOD_DVT1, IF_REAL, "Short channel effect coeff. 1"), +IOP( "dvt2", BSIM4_MOD_DVT2, IF_REAL, "Short channel effect coeff. 2"), +IOP( "dvt0w", BSIM4_MOD_DVT0W, IF_REAL, "Narrow Width coeff. 0"), +IOP( "dvt1w", BSIM4_MOD_DVT1W, IF_REAL, "Narrow Width effect coeff. 1"), +IOP( "dvt2w", BSIM4_MOD_DVT2W, IF_REAL, "Narrow Width effect coeff. 2"), +IOP( "drout", BSIM4_MOD_DROUT, IF_REAL, "DIBL coefficient of output resistance"), +IOP( "dsub", BSIM4_MOD_DSUB, IF_REAL, "DIBL coefficient in the subthreshold region"), +IOP( "vth0", BSIM4_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "vtho", BSIM4_MOD_VTH0, IF_REAL,"Threshold voltage"), +IOP( "ua", BSIM4_MOD_UA, IF_REAL, "Linear gate dependence of mobility"), +IOP( "ua1", BSIM4_MOD_UA1, IF_REAL, "Temperature coefficient of ua"), +IOP( "ub", BSIM4_MOD_UB, IF_REAL, "Quadratic gate dependence of mobility"), +IOP( "ub1", BSIM4_MOD_UB1, IF_REAL, "Temperature coefficient of ub"), +IOP( "uc", BSIM4_MOD_UC, IF_REAL, "Body-bias dependence of mobility"), +IOP( "uc1", BSIM4_MOD_UC1, IF_REAL, "Temperature coefficient of uc"), +IOP( "u0", BSIM4_MOD_U0, IF_REAL, "Low-field mobility at Tnom"), +IOP( "eu", BSIM4_MOD_EU, IF_REAL, "Mobility exponent"), +IOP( "ute", BSIM4_MOD_UTE, IF_REAL, "Temperature coefficient of mobility"), +IOP( "voff", BSIM4_MOD_VOFF, IF_REAL, "Threshold voltage offset"), +IOP( "minv", BSIM4_MOD_MINV, IF_REAL, "Fitting parameter for moderate invversion in Vgsteff"), +IOP( "voffl", BSIM4_MOD_VOFFL, IF_REAL, "Length dependence parameter for Vth offset"), +IOP( "tnom", BSIM4_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), +IOP( "cgso", BSIM4_MOD_CGSO, IF_REAL, "Gate-source overlap capacitance per width"), +IOP( "cgdo", BSIM4_MOD_CGDO, IF_REAL, "Gate-drain overlap capacitance per width"), +IOP( "cgbo", BSIM4_MOD_CGBO, IF_REAL, "Gate-bulk overlap capacitance per length"), +IOP( "xpart", BSIM4_MOD_XPART, IF_REAL, "Channel charge partitioning"), +IOP( "delta", BSIM4_MOD_DELTA, IF_REAL, "Effective Vds parameter"), +IOP( "rsh", BSIM4_MOD_RSH, IF_REAL, "Source-drain sheet resistance"), +IOP( "rdsw", BSIM4_MOD_RDSW, IF_REAL, "Source-drain resistance per width"), +IOP( "rdswmin", BSIM4_MOD_RDSWMIN, IF_REAL, "Source-drain resistance per width at high Vg"), +IOP( "rsw", BSIM4_MOD_RSW, IF_REAL, "Source resistance per width"), +IOP( "rdw", BSIM4_MOD_RDW, IF_REAL, "Drain resistance per width"), +IOP( "rdwmin", BSIM4_MOD_RDWMIN, IF_REAL, "Drain resistance per width at high Vg"), +IOP( "rswmin", BSIM4_MOD_RSWMIN, IF_REAL, "Source resistance per width at high Vg"), + +IOP( "prwg", BSIM4_MOD_PRWG, IF_REAL, "Gate-bias effect on parasitic resistance "), +IOP( "prwb", BSIM4_MOD_PRWB, IF_REAL, "Body-effect on parasitic resistance "), + +IOP( "prt", BSIM4_MOD_PRT, IF_REAL, "Temperature coefficient of parasitic resistance "), +IOP( "eta0", BSIM4_MOD_ETA0, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "etab", BSIM4_MOD_ETAB, IF_REAL, "Subthreshold region DIBL coefficient"), +IOP( "pclm", BSIM4_MOD_PCLM, IF_REAL, "Channel length modulation Coefficient"), +IOP( "pdiblc1", BSIM4_MOD_PDIBL1, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblc2", BSIM4_MOD_PDIBL2, IF_REAL, "Drain-induced barrier lowering coefficient"), +IOP( "pdiblcb", BSIM4_MOD_PDIBLB, IF_REAL, "Body-effect on drain-induced barrier lowering"), +IOP( "fprout", BSIM4_MOD_FPROUT, IF_REAL, "Rout degradation coefficient for pocket devices"), +IOP( "pdits", BSIM4_MOD_PDITS, IF_REAL, "Coefficient for drain-induced Vth shifts"), +IOP( "pditsl", BSIM4_MOD_PDITSL, IF_REAL, "Length dependence of drain-induced Vth shifts"), +IOP( "pditsd", BSIM4_MOD_PDITSD, IF_REAL, "Vds dependence of drain-induced Vth shifts"), +IOP( "pscbe1", BSIM4_MOD_PSCBE1, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pscbe2", BSIM4_MOD_PSCBE2, IF_REAL, "Substrate current body-effect coefficient"), +IOP( "pvag", BSIM4_MOD_PVAG, IF_REAL, "Gate dependence of output resistance parameter"), + +IOP( "jss", BSIM4_MOD_JSS, IF_REAL, "Bottom source junction reverse saturation current density"), +IOP( "jsws", BSIM4_MOD_JSWS, IF_REAL, "Isolation edge sidewall source junction reverse saturation current density"), +IOP( "jswgs", BSIM4_MOD_JSWGS, IF_REAL, "Gate edge source junction reverse saturation current density"), +IOP( "pbs", BSIM4_MOD_PBS, IF_REAL, "Source junction built-in potential"), +IOP( "njs", BSIM4_MOD_NJS, IF_REAL, "Source junction emission coefficient"), +IOP( "xtis", BSIM4_MOD_XTIS, IF_REAL, "Source junction current temperature exponent"), +IOP( "mjs", BSIM4_MOD_MJS, IF_REAL, "Source bottom junction capacitance grading coefficient"), +IOP( "pbsws", BSIM4_MOD_PBSWS, IF_REAL, "Source sidewall junction capacitance built in potential"), +IOP( "mjsws", BSIM4_MOD_MJSWS, IF_REAL, "Source sidewall junction capacitance grading coefficient"), +IOP( "pbswgs", BSIM4_MOD_PBSWGS, IF_REAL, "Source (gate side) sidewall junction capacitance built in potential"), +IOP( "mjswgs", BSIM4_MOD_MJSWGS, IF_REAL, "Source (gate side) sidewall junction capacitance grading coefficient"), +IOP( "cjs", BSIM4_MOD_CJS, IF_REAL, "Source bottom junction capacitance per unit area"), +IOP( "cjsws", BSIM4_MOD_CJSWS, IF_REAL, "Source sidewall junction capacitance per unit periphery"), +IOP( "cjswgs", BSIM4_MOD_CJSWGS, IF_REAL, "Source (gate side) sidewall junction capacitance per unit width"), + +IOP( "jsd", BSIM4_MOD_JSD, IF_REAL, "Bottom drain junction reverse saturation current density"), +IOP( "jswd", BSIM4_MOD_JSWD, IF_REAL, "Isolation edge sidewall drain junction reverse saturation current density"), +IOP( "jswgd", BSIM4_MOD_JSWGD, IF_REAL, "Gate edge drain junction reverse saturation current density"), +IOP( "pbd", BSIM4_MOD_PBD, IF_REAL, "Drain junction built-in potential"), +IOP( "njd", BSIM4_MOD_NJD, IF_REAL, "Drain junction emission coefficient"), +IOP( "xtid", BSIM4_MOD_XTID, IF_REAL, "Drainjunction current temperature exponent"), +IOP( "mjd", BSIM4_MOD_MJD, IF_REAL, "Drain bottom junction capacitance grading coefficient"), +IOP( "pbswd", BSIM4_MOD_PBSWD, IF_REAL, "Drain sidewall junction capacitance built in potential"), +IOP( "mjswd", BSIM4_MOD_MJSWD, IF_REAL, "Drain sidewall junction capacitance grading coefficient"), +IOP( "pbswgd", BSIM4_MOD_PBSWGD, IF_REAL, "Drain (gate side) sidewall junction capacitance built in potential"), +IOP( "mjswgd", BSIM4_MOD_MJSWGD, IF_REAL, "Drain (gate side) sidewall junction capacitance grading coefficient"), +IOP( "cjd", BSIM4_MOD_CJD, IF_REAL, "Drain bottom junction capacitance per unit area"), +IOP( "cjswd", BSIM4_MOD_CJSWD, IF_REAL, "Drain sidewall junction capacitance per unit periphery"), +IOP( "cjswgd", BSIM4_MOD_CJSWGD, IF_REAL, "Drain (gate side) sidewall junction capacitance per unit width"), + +IOP( "vfbcv", BSIM4_MOD_VFBCV, IF_REAL, "Flat Band Voltage parameter for capmod=0 only"), +IOP( "vfb", BSIM4_MOD_VFB, IF_REAL, "Flat Band Voltage"), +IOP( "tpb", BSIM4_MOD_TPB, IF_REAL, "Temperature coefficient of pb"), +IOP( "tcj", BSIM4_MOD_TCJ, IF_REAL, "Temperature coefficient of cj"), +IOP( "tpbsw", BSIM4_MOD_TPBSW, IF_REAL, "Temperature coefficient of pbsw"), +IOP( "tcjsw", BSIM4_MOD_TCJSW, IF_REAL, "Temperature coefficient of cjsw"), +IOP( "tpbswg", BSIM4_MOD_TPBSWG, IF_REAL, "Temperature coefficient of pbswg"), +IOP( "tcjswg", BSIM4_MOD_TCJSWG, IF_REAL, "Temperature coefficient of cjswg"), +IOP( "acde", BSIM4_MOD_ACDE, IF_REAL, "Exponential coefficient for finite charge thickness"), +IOP( "moin", BSIM4_MOD_MOIN, IF_REAL, "Coefficient for gate-bias dependent surface potential"), +IOP( "noff", BSIM4_MOD_NOFF, IF_REAL, "C-V turn-on/off parameter"), +IOP( "voffcv", BSIM4_MOD_VOFFCV, IF_REAL, "C-V lateral-shift parameter"), +IOP( "dmcg", BSIM4_MOD_DMCG, IF_REAL, "Distance of Mid-Contact to Gate edge"), +IOP( "dmci", BSIM4_MOD_DMCI, IF_REAL, "Distance of Mid-Contact to Isolation"), +IOP( "dmdg", BSIM4_MOD_DMDG, IF_REAL, "Distance of Mid-Diffusion to Gate edge"), +IOP( "dmcgt", BSIM4_MOD_DMCGT, IF_REAL, "Distance of Mid-Contact to Gate edge in Test structures"), +IOP( "xgw", BSIM4_MOD_XGW, IF_REAL, "Distance from gate contact center to device edge"), +IOP( "xgl", BSIM4_MOD_XGL, IF_REAL, "Variation in Ldrawn"), +IOP( "rshg", BSIM4_MOD_RSHG, IF_REAL, "Gate sheet resistance"), +IOP( "ngcon", BSIM4_MOD_NGCON, IF_REAL, "Number of gate contacts"), +IOP( "xrcrg1", BSIM4_MOD_XRCRG1, IF_REAL, "First fitting parameter the bias-dependent Rg"), +IOP( "xrcrg2", BSIM4_MOD_XRCRG2, IF_REAL, "Second fitting parameter the bias-dependent Rg"), +IOP( "lint", BSIM4_MOD_LINT, IF_REAL, "Length reduction parameter"), +IOP( "ll", BSIM4_MOD_LL, IF_REAL, "Length reduction parameter"), +IOP( "llc", BSIM4_MOD_LLC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lln", BSIM4_MOD_LLN, IF_REAL, "Length reduction parameter"), +IOP( "lw", BSIM4_MOD_LW, IF_REAL, "Length reduction parameter"), +IOP( "lwc", BSIM4_MOD_LWC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lwn", BSIM4_MOD_LWN, IF_REAL, "Length reduction parameter"), +IOP( "lwl", BSIM4_MOD_LWL, IF_REAL, "Length reduction parameter"), +IOP( "lwlc", BSIM4_MOD_LWLC, IF_REAL, "Length reduction parameter for CV"), +IOP( "lmin", BSIM4_MOD_LMIN, IF_REAL, "Minimum length for the model"), +IOP( "lmax", BSIM4_MOD_LMAX, IF_REAL, "Maximum length for the model"), + +IOP( "wr", BSIM4_MOD_WR, IF_REAL, "Width dependence of rds"), +IOP( "wint", BSIM4_MOD_WINT, IF_REAL, "Width reduction parameter"), +IOP( "dwg", BSIM4_MOD_DWG, IF_REAL, "Width reduction parameter"), +IOP( "dwb", BSIM4_MOD_DWB, IF_REAL, "Width reduction parameter"), + +IOP( "wl", BSIM4_MOD_WL, IF_REAL, "Width reduction parameter"), +IOP( "wlc", BSIM4_MOD_WLC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wln", BSIM4_MOD_WLN, IF_REAL, "Width reduction parameter"), +IOP( "ww", BSIM4_MOD_WW, IF_REAL, "Width reduction parameter"), +IOP( "wwc", BSIM4_MOD_WWC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wwn", BSIM4_MOD_WWN, IF_REAL, "Width reduction parameter"), +IOP( "wwl", BSIM4_MOD_WWL, IF_REAL, "Width reduction parameter"), +IOP( "wwlc", BSIM4_MOD_WWLC, IF_REAL, "Width reduction parameter for CV"), +IOP( "wmin", BSIM4_MOD_WMIN, IF_REAL, "Minimum width for the model"), +IOP( "wmax", BSIM4_MOD_WMAX, IF_REAL, "Maximum width for the model"), + +IOP( "b0", BSIM4_MOD_B0, IF_REAL, "Abulk narrow width parameter"), +IOP( "b1", BSIM4_MOD_B1, IF_REAL, "Abulk narrow width parameter"), + +IOP( "cgsl", BSIM4_MOD_CGSL, IF_REAL, "New C-V model parameter"), +IOP( "cgdl", BSIM4_MOD_CGDL, IF_REAL, "New C-V model parameter"), +IOP( "ckappas", BSIM4_MOD_CKAPPAS, IF_REAL, "S/G overlap C-V parameter "), +IOP( "ckappad", BSIM4_MOD_CKAPPAD, IF_REAL, "D/G overlap C-V parameter"), +IOP( "cf", BSIM4_MOD_CF, IF_REAL, "Fringe capacitance parameter"), +IOP( "clc", BSIM4_MOD_CLC, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "cle", BSIM4_MOD_CLE, IF_REAL, "Vdsat parameter for C-V model"), +IOP( "dwc", BSIM4_MOD_DWC, IF_REAL, "Delta W for C-V model"), +IOP( "dlc", BSIM4_MOD_DLC, IF_REAL, "Delta L for C-V model"), +IOP( "dlcig", BSIM4_MOD_DLCIG, IF_REAL, "Delta L for Ig model"), +IOP( "dwj", BSIM4_MOD_DWJ, IF_REAL, "Delta W for S/D junctions"), + +IOP( "alpha0", BSIM4_MOD_ALPHA0, IF_REAL, "substrate current model parameter"), +IOP( "alpha1", BSIM4_MOD_ALPHA1, IF_REAL, "substrate current model parameter"), +IOP( "beta0", BSIM4_MOD_BETA0, IF_REAL, "substrate current model parameter"), +IOP( "agidl", BSIM4_MOD_AGIDL, IF_REAL, "Pre-exponential constant for GIDL"), +IOP( "bgidl", BSIM4_MOD_BGIDL, IF_REAL, "Exponential constant for GIDL"), +IOP( "cgidl", BSIM4_MOD_CGIDL, IF_REAL, "Parameter for body-bias dependence of GIDL"), +IOP( "egidl", BSIM4_MOD_EGIDL, IF_REAL, "Fitting parameter for Bandbending"), +IOP( "aigc", BSIM4_MOD_AIGC, IF_REAL, "Parameter for Igc"), +IOP( "bigc", BSIM4_MOD_BIGC, IF_REAL, "Parameter for Igc"), +IOP( "cigc", BSIM4_MOD_CIGC, IF_REAL, "Parameter for Igc"), +IOP( "aigsd", BSIM4_MOD_AIGSD, IF_REAL, "Parameter for Igs,d"), +IOP( "bigsd", BSIM4_MOD_BIGSD, IF_REAL, "Parameter for Igs,d"), +IOP( "cigsd", BSIM4_MOD_CIGSD, IF_REAL, "Parameter for Igs,d"), +IOP( "aigbacc", BSIM4_MOD_AIGBACC, IF_REAL, "Parameter for Igb"), +IOP( "bigbacc", BSIM4_MOD_BIGBACC, IF_REAL, "Parameter for Igb"), +IOP( "cigbacc", BSIM4_MOD_CIGBACC, IF_REAL, "Parameter for Igb"), +IOP( "aigbinv", BSIM4_MOD_AIGBINV, IF_REAL, "Parameter for Igb"), +IOP( "bigbinv", BSIM4_MOD_BIGBINV, IF_REAL, "Parameter for Igb"), +IOP( "cigbinv", BSIM4_MOD_CIGBINV, IF_REAL, "Parameter for Igb"), +IOP( "nigc", BSIM4_MOD_NIGC, IF_REAL, "Parameter for Igc slope"), +IOP( "nigbinv", BSIM4_MOD_NIGBINV, IF_REAL, "Parameter for Igbinv slope"), +IOP( "nigbacc", BSIM4_MOD_NIGBACC, IF_REAL, "Parameter for Igbacc slope"), +IOP( "ntox", BSIM4_MOD_NTOX, IF_REAL, "Exponent for Tox ratio"), +IOP( "eigbinv", BSIM4_MOD_EIGBINV, IF_REAL, "Parameter for the Si bandgap for Igbinv"), +IOP( "pigcd", BSIM4_MOD_PIGCD, IF_REAL, "Parameter for Igc partition"), +IOP( "poxedge", BSIM4_MOD_POXEDGE, IF_REAL, "Factor for the gate edge Tox"), + +IOP( "ijthdfwd", BSIM4_MOD_IJTHDFWD, IF_REAL, "Forward drain diode forward limiting current"), +IOP( "ijthsfwd", BSIM4_MOD_IJTHSFWD, IF_REAL, "Forward source diode forward limiting current"), +IOP( "ijthdrev", BSIM4_MOD_IJTHDREV, IF_REAL, "Reverse drain diode forward limiting current"), +IOP( "ijthsrev", BSIM4_MOD_IJTHSREV, IF_REAL, "Reverse source diode forward limiting current"), +IOP( "xjbvd", BSIM4_MOD_XJBVD, IF_REAL, "Fitting parameter for drain diode breakdown current"), +IOP( "xjbvs", BSIM4_MOD_XJBVS, IF_REAL, "Fitting parameter for source diode breakdown current"), +IOP( "bvd", BSIM4_MOD_BVD, IF_REAL, "Drain diode breakdown voltage"), +IOP( "bvs", BSIM4_MOD_BVS, IF_REAL, "Source diode breakdown voltage"), + +IOP( "gbmin", BSIM4_MOD_GBMIN, IF_REAL, "Minimum body conductance"), +IOP( "rbdb", BSIM4_MOD_RBDB, IF_REAL, "Resistance between bNode and dbNode"), +IOP( "rbpb", BSIM4_MOD_RBPB, IF_REAL, "Resistance between bNodePrime and bNode"), +IOP( "rbsb", BSIM4_MOD_RBSB, IF_REAL, "Resistance between bNode and sbNode"), +IOP( "rbps", BSIM4_MOD_RBPS, IF_REAL, "Resistance between bNodePrime and sbNode"), +IOP( "rbpd", BSIM4_MOD_RBPD, IF_REAL, "Resistance between bNodePrime and bNode"), + +IOP( "lcdsc", BSIM4_MOD_LCDSC, IF_REAL, "Length dependence of cdsc"), +IOP( "lcdscb", BSIM4_MOD_LCDSCB, IF_REAL, "Length dependence of cdscb"), +IOP( "lcdscd", BSIM4_MOD_LCDSCD, IF_REAL, "Length dependence of cdscd"), +IOP( "lcit", BSIM4_MOD_LCIT, IF_REAL, "Length dependence of cit"), +IOP( "lnfactor", BSIM4_MOD_LNFACTOR, IF_REAL, "Length dependence of nfactor"), +IOP( "lxj", BSIM4_MOD_LXJ, IF_REAL, "Length dependence of xj"), +IOP( "lvsat", BSIM4_MOD_LVSAT, IF_REAL, "Length dependence of vsat"), +IOP( "lat", BSIM4_MOD_LAT, IF_REAL, "Length dependence of at"), +IOP( "la0", BSIM4_MOD_LA0, IF_REAL, "Length dependence of a0"), +IOP( "lags", BSIM4_MOD_LAGS, IF_REAL, "Length dependence of ags"), +IOP( "la1", BSIM4_MOD_LA1, IF_REAL, "Length dependence of a1"), +IOP( "la2", BSIM4_MOD_LA2, IF_REAL, "Length dependence of a2"), +IOP( "lketa", BSIM4_MOD_LKETA, IF_REAL, "Length dependence of keta"), +IOP( "lnsub", BSIM4_MOD_LNSUB, IF_REAL, "Length dependence of nsub"), +IOP( "lndep", BSIM4_MOD_LNDEP, IF_REAL, "Length dependence of ndep"), +IOP( "lnsd", BSIM4_MOD_LNSD, IF_REAL, "Length dependence of nsd"), +IOP( "lphin", BSIM4_MOD_LPHIN, IF_REAL, "Length dependence of phin"), +IOP( "lngate", BSIM4_MOD_LNGATE, IF_REAL, "Length dependence of ngate"), +IOP( "lgamma1", BSIM4_MOD_LGAMMA1, IF_REAL, "Length dependence of gamma1"), +IOP( "lgamma2", BSIM4_MOD_LGAMMA2, IF_REAL, "Length dependence of gamma2"), +IOP( "lvbx", BSIM4_MOD_LVBX, IF_REAL, "Length dependence of vbx"), +IOP( "lvbm", BSIM4_MOD_LVBM, IF_REAL, "Length dependence of vbm"), +IOP( "lxt", BSIM4_MOD_LXT, IF_REAL, "Length dependence of xt"), +IOP( "lk1", BSIM4_MOD_LK1, IF_REAL, "Length dependence of k1"), +IOP( "lkt1", BSIM4_MOD_LKT1, IF_REAL, "Length dependence of kt1"), +IOP( "lkt1l", BSIM4_MOD_LKT1L, IF_REAL, "Length dependence of kt1l"), +IOP( "lkt2", BSIM4_MOD_LKT2, IF_REAL, "Length dependence of kt2"), +IOP( "lk2", BSIM4_MOD_LK2, IF_REAL, "Length dependence of k2"), +IOP( "lk3", BSIM4_MOD_LK3, IF_REAL, "Length dependence of k3"), +IOP( "lk3b", BSIM4_MOD_LK3B, IF_REAL, "Length dependence of k3b"), +IOP( "lw0", BSIM4_MOD_LW0, IF_REAL, "Length dependence of w0"), +IOP( "ldvtp0", BSIM4_MOD_LDVTP0, IF_REAL, "Length dependence of dvtp0"), +IOP( "ldvtp1", BSIM4_MOD_LDVTP1, IF_REAL, "Length dependence of dvtp1"), +IOP( "llpe0", BSIM4_MOD_LLPE0, IF_REAL, "Length dependence of lpe0"), +IOP( "llpeb", BSIM4_MOD_LLPEB, IF_REAL, "Length dependence of lpeb"), +IOP( "ldvt0", BSIM4_MOD_LDVT0, IF_REAL, "Length dependence of dvt0"), +IOP( "ldvt1", BSIM4_MOD_LDVT1, IF_REAL, "Length dependence of dvt1"), +IOP( "ldvt2", BSIM4_MOD_LDVT2, IF_REAL, "Length dependence of dvt2"), +IOP( "ldvt0w", BSIM4_MOD_LDVT0W, IF_REAL, "Length dependence of dvt0w"), +IOP( "ldvt1w", BSIM4_MOD_LDVT1W, IF_REAL, "Length dependence of dvt1w"), +IOP( "ldvt2w", BSIM4_MOD_LDVT2W, IF_REAL, "Length dependence of dvt2w"), +IOP( "ldrout", BSIM4_MOD_LDROUT, IF_REAL, "Length dependence of drout"), +IOP( "ldsub", BSIM4_MOD_LDSUB, IF_REAL, "Length dependence of dsub"), +IOP( "lvth0", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lvtho", BSIM4_MOD_LVTH0, IF_REAL,"Length dependence of vto"), +IOP( "lua", BSIM4_MOD_LUA, IF_REAL, "Length dependence of ua"), +IOP( "lua1", BSIM4_MOD_LUA1, IF_REAL, "Length dependence of ua1"), +IOP( "lub", BSIM4_MOD_LUB, IF_REAL, "Length dependence of ub"), +IOP( "lub1", BSIM4_MOD_LUB1, IF_REAL, "Length dependence of ub1"), +IOP( "luc", BSIM4_MOD_LUC, IF_REAL, "Length dependence of uc"), +IOP( "luc1", BSIM4_MOD_LUC1, IF_REAL, "Length dependence of uc1"), +IOP( "lu0", BSIM4_MOD_LU0, IF_REAL, "Length dependence of u0"), +IOP( "lute", BSIM4_MOD_LUTE, IF_REAL, "Length dependence of ute"), +IOP( "lvoff", BSIM4_MOD_LVOFF, IF_REAL, "Length dependence of voff"), +IOP( "lminv", BSIM4_MOD_LMINV, IF_REAL, "Length dependence of minv"), +IOP( "ldelta", BSIM4_MOD_LDELTA, IF_REAL, "Length dependence of delta"), +IOP( "lrdsw", BSIM4_MOD_LRDSW, IF_REAL, "Length dependence of rdsw "), +IOP( "lrsw", BSIM4_MOD_LRSW, IF_REAL, "Length dependence of rsw"), +IOP( "lrdw", BSIM4_MOD_LRDW, IF_REAL, "Length dependence of rdw"), + +IOP( "lprwg", BSIM4_MOD_LPRWG, IF_REAL, "Length dependence of prwg "), +IOP( "lprwb", BSIM4_MOD_LPRWB, IF_REAL, "Length dependence of prwb "), + +IOP( "lprt", BSIM4_MOD_LPRT, IF_REAL, "Length dependence of prt "), +IOP( "leta0", BSIM4_MOD_LETA0, IF_REAL, "Length dependence of eta0"), +IOP( "letab", BSIM4_MOD_LETAB, IF_REAL, "Length dependence of etab"), +IOP( "lpclm", BSIM4_MOD_LPCLM, IF_REAL, "Length dependence of pclm"), +IOP( "lpdiblc1", BSIM4_MOD_LPDIBL1, IF_REAL, "Length dependence of pdiblc1"), +IOP( "lpdiblc2", BSIM4_MOD_LPDIBL2, IF_REAL, "Length dependence of pdiblc2"), +IOP( "lpdiblcb", BSIM4_MOD_LPDIBLB, IF_REAL, "Length dependence of pdiblcb"), +IOP( "lfprout", BSIM4_MOD_LFPROUT, IF_REAL, "Length dependence of pdiblcb"), +IOP( "lpdits", BSIM4_MOD_LPDITS, IF_REAL, "Length dependence of pdits"), +IOP( "lpditsd", BSIM4_MOD_LPDITSD, IF_REAL, "Length dependence of pditsd"), +IOP( "lpscbe1", BSIM4_MOD_LPSCBE1, IF_REAL, "Length dependence of pscbe1"), +IOP( "lpscbe2", BSIM4_MOD_LPSCBE2, IF_REAL, "Length dependence of pscbe2"), +IOP( "lpvag", BSIM4_MOD_LPVAG, IF_REAL, "Length dependence of pvag"), +IOP( "lwr", BSIM4_MOD_LWR, IF_REAL, "Length dependence of wr"), +IOP( "ldwg", BSIM4_MOD_LDWG, IF_REAL, "Length dependence of dwg"), +IOP( "ldwb", BSIM4_MOD_LDWB, IF_REAL, "Length dependence of dwb"), +IOP( "lb0", BSIM4_MOD_LB0, IF_REAL, "Length dependence of b0"), +IOP( "lb1", BSIM4_MOD_LB1, IF_REAL, "Length dependence of b1"), +IOP( "lcgsl", BSIM4_MOD_LCGSL, IF_REAL, "Length dependence of cgsl"), +IOP( "lcgdl", BSIM4_MOD_LCGDL, IF_REAL, "Length dependence of cgdl"), +IOP( "lckappas", BSIM4_MOD_LCKAPPAS, IF_REAL, "Length dependence of ckappas"), +IOP( "lckappad", BSIM4_MOD_LCKAPPAD, IF_REAL, "Length dependence of ckappad"), +IOP( "lcf", BSIM4_MOD_LCF, IF_REAL, "Length dependence of cf"), +IOP( "lclc", BSIM4_MOD_LCLC, IF_REAL, "Length dependence of clc"), +IOP( "lcle", BSIM4_MOD_LCLE, IF_REAL, "Length dependence of cle"), +IOP( "lalpha0", BSIM4_MOD_LALPHA0, IF_REAL, "Length dependence of alpha0"), +IOP( "lalpha1", BSIM4_MOD_LALPHA1, IF_REAL, "Length dependence of alpha1"), +IOP( "lbeta0", BSIM4_MOD_LBETA0, IF_REAL, "Length dependence of beta0"), +IOP( "lagidl", BSIM4_MOD_LAGIDL, IF_REAL, "Length dependence of agidl"), +IOP( "lbgidl", BSIM4_MOD_LBGIDL, IF_REAL, "Length dependence of bgidl"), +IOP( "lcgidl", BSIM4_MOD_LCGIDL, IF_REAL, "Length dependence of cgidl"), +IOP( "legidl", BSIM4_MOD_LEGIDL, IF_REAL, "Length dependence of egidl"), +IOP( "laigc", BSIM4_MOD_LAIGC, IF_REAL, "Length dependence of aigc"), +IOP( "lbigc", BSIM4_MOD_LBIGC, IF_REAL, "Length dependence of bigc"), +IOP( "lcigc", BSIM4_MOD_LCIGC, IF_REAL, "Length dependence of cigc"), +IOP( "laigsd", BSIM4_MOD_LAIGSD, IF_REAL, "Length dependence of aigsd"), +IOP( "lbigsd", BSIM4_MOD_LBIGSD, IF_REAL, "Length dependence of bigsd"), +IOP( "lcigsd", BSIM4_MOD_LCIGSD, IF_REAL, "Length dependence of cigsd"), +IOP( "laigbacc", BSIM4_MOD_LAIGBACC, IF_REAL, "Length dependence of aigbacc"), +IOP( "lbigbacc", BSIM4_MOD_LBIGBACC, IF_REAL, "Length dependence of bigbacc"), +IOP( "lcigbacc", BSIM4_MOD_LCIGBACC, IF_REAL, "Length dependence of cigbacc"), +IOP( "laigbinv", BSIM4_MOD_LAIGBINV, IF_REAL, "Length dependence of aigbinv"), +IOP( "lbigbinv", BSIM4_MOD_LBIGBINV, IF_REAL, "Length dependence of bigbinv"), +IOP( "lcigbinv", BSIM4_MOD_LCIGBINV, IF_REAL, "Length dependence of cigbinv"), +IOP( "lnigc", BSIM4_MOD_LNIGC, IF_REAL, "Length dependence of nigc"), +IOP( "lnigbinv", BSIM4_MOD_LNIGBINV, IF_REAL, "Length dependence of nigbinv"), +IOP( "lnigbacc", BSIM4_MOD_LNIGBACC, IF_REAL, "Length dependence of nigbacc"), +IOP( "lntox", BSIM4_MOD_LNTOX, IF_REAL, "Length dependence of ntox"), +IOP( "leigbinv", BSIM4_MOD_LEIGBINV, IF_REAL, "Length dependence for eigbinv"), +IOP( "lpigcd", BSIM4_MOD_LPIGCD, IF_REAL, "Length dependence for pigcd"), +IOP( "lpoxedge", BSIM4_MOD_LPOXEDGE, IF_REAL, "Length dependence for poxedge"), + +IOP( "lvfbcv", BSIM4_MOD_LVFBCV, IF_REAL, "Length dependence of vfbcv"), +IOP( "lvfb", BSIM4_MOD_LVFB, IF_REAL, "Length dependence of vfb"), +IOP( "lacde", BSIM4_MOD_LACDE, IF_REAL, "Length dependence of acde"), +IOP( "lmoin", BSIM4_MOD_LMOIN, IF_REAL, "Length dependence of moin"), +IOP( "lnoff", BSIM4_MOD_LNOFF, IF_REAL, "Length dependence of noff"), +IOP( "lvoffcv", BSIM4_MOD_LVOFFCV, IF_REAL, "Length dependence of voffcv"), +IOP( "lxrcrg1", BSIM4_MOD_LXRCRG1, IF_REAL, "Length dependence of xrcrg1"), +IOP( "lxrcrg2", BSIM4_MOD_LXRCRG2, IF_REAL, "Length dependence of xrcrg2"), +IOP( "leu", BSIM4_MOD_LEU, IF_REAL, "Length dependence of eu"), +IOP( "wcdsc", BSIM4_MOD_WCDSC, IF_REAL, "Width dependence of cdsc"), +IOP( "wcdscb", BSIM4_MOD_WCDSCB, IF_REAL, "Width dependence of cdscb"), +IOP( "wcdscd", BSIM4_MOD_WCDSCD, IF_REAL, "Width dependence of cdscd"), +IOP( "wcit", BSIM4_MOD_WCIT, IF_REAL, "Width dependence of cit"), +IOP( "wnfactor", BSIM4_MOD_WNFACTOR, IF_REAL, "Width dependence of nfactor"), +IOP( "wxj", BSIM4_MOD_WXJ, IF_REAL, "Width dependence of xj"), +IOP( "wvsat", BSIM4_MOD_WVSAT, IF_REAL, "Width dependence of vsat"), +IOP( "wat", BSIM4_MOD_WAT, IF_REAL, "Width dependence of at"), +IOP( "wa0", BSIM4_MOD_WA0, IF_REAL, "Width dependence of a0"), +IOP( "wags", BSIM4_MOD_WAGS, IF_REAL, "Width dependence of ags"), +IOP( "wa1", BSIM4_MOD_WA1, IF_REAL, "Width dependence of a1"), +IOP( "wa2", BSIM4_MOD_WA2, IF_REAL, "Width dependence of a2"), +IOP( "wketa", BSIM4_MOD_WKETA, IF_REAL, "Width dependence of keta"), +IOP( "wnsub", BSIM4_MOD_WNSUB, IF_REAL, "Width dependence of nsub"), +IOP( "wndep", BSIM4_MOD_WNDEP, IF_REAL, "Width dependence of ndep"), +IOP( "wnsd", BSIM4_MOD_WNSD, IF_REAL, "Width dependence of nsd"), +IOP( "wphin", BSIM4_MOD_WPHIN, IF_REAL, "Width dependence of phin"), +IOP( "wngate", BSIM4_MOD_WNGATE, IF_REAL, "Width dependence of ngate"), +IOP( "wgamma1", BSIM4_MOD_WGAMMA1, IF_REAL, "Width dependence of gamma1"), +IOP( "wgamma2", BSIM4_MOD_WGAMMA2, IF_REAL, "Width dependence of gamma2"), +IOP( "wvbx", BSIM4_MOD_WVBX, IF_REAL, "Width dependence of vbx"), +IOP( "wvbm", BSIM4_MOD_WVBM, IF_REAL, "Width dependence of vbm"), +IOP( "wxt", BSIM4_MOD_WXT, IF_REAL, "Width dependence of xt"), +IOP( "wk1", BSIM4_MOD_WK1, IF_REAL, "Width dependence of k1"), +IOP( "wkt1", BSIM4_MOD_WKT1, IF_REAL, "Width dependence of kt1"), +IOP( "wkt1l", BSIM4_MOD_WKT1L, IF_REAL, "Width dependence of kt1l"), +IOP( "wkt2", BSIM4_MOD_WKT2, IF_REAL, "Width dependence of kt2"), +IOP( "wk2", BSIM4_MOD_WK2, IF_REAL, "Width dependence of k2"), +IOP( "wk3", BSIM4_MOD_WK3, IF_REAL, "Width dependence of k3"), +IOP( "wk3b", BSIM4_MOD_WK3B, IF_REAL, "Width dependence of k3b"), +IOP( "ww0", BSIM4_MOD_WW0, IF_REAL, "Width dependence of w0"), +IOP( "wdvtp0", BSIM4_MOD_WDVTP0, IF_REAL, "Width dependence of dvtp0"), +IOP( "wdvtp1", BSIM4_MOD_WDVTP1, IF_REAL, "Width dependence of dvtp1"), +IOP( "wlpe0", BSIM4_MOD_WLPE0, IF_REAL, "Width dependence of lpe0"), +IOP( "wlpeb", BSIM4_MOD_WLPEB, IF_REAL, "Width dependence of lpeb"), +IOP( "wdvt0", BSIM4_MOD_WDVT0, IF_REAL, "Width dependence of dvt0"), +IOP( "wdvt1", BSIM4_MOD_WDVT1, IF_REAL, "Width dependence of dvt1"), +IOP( "wdvt2", BSIM4_MOD_WDVT2, IF_REAL, "Width dependence of dvt2"), +IOP( "wdvt0w", BSIM4_MOD_WDVT0W, IF_REAL, "Width dependence of dvt0w"), +IOP( "wdvt1w", BSIM4_MOD_WDVT1W, IF_REAL, "Width dependence of dvt1w"), +IOP( "wdvt2w", BSIM4_MOD_WDVT2W, IF_REAL, "Width dependence of dvt2w"), +IOP( "wdrout", BSIM4_MOD_WDROUT, IF_REAL, "Width dependence of drout"), +IOP( "wdsub", BSIM4_MOD_WDSUB, IF_REAL, "Width dependence of dsub"), +IOP( "wvth0", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wvtho", BSIM4_MOD_WVTH0, IF_REAL,"Width dependence of vto"), +IOP( "wua", BSIM4_MOD_WUA, IF_REAL, "Width dependence of ua"), +IOP( "wua1", BSIM4_MOD_WUA1, IF_REAL, "Width dependence of ua1"), +IOP( "wub", BSIM4_MOD_WUB, IF_REAL, "Width dependence of ub"), +IOP( "wub1", BSIM4_MOD_WUB1, IF_REAL, "Width dependence of ub1"), +IOP( "wuc", BSIM4_MOD_WUC, IF_REAL, "Width dependence of uc"), +IOP( "wuc1", BSIM4_MOD_WUC1, IF_REAL, "Width dependence of uc1"), +IOP( "wu0", BSIM4_MOD_WU0, IF_REAL, "Width dependence of u0"), +IOP( "wute", BSIM4_MOD_WUTE, IF_REAL, "Width dependence of ute"), +IOP( "wvoff", BSIM4_MOD_WVOFF, IF_REAL, "Width dependence of voff"), +IOP( "wminv", BSIM4_MOD_WMINV, IF_REAL, "Width dependence of minv"), +IOP( "wdelta", BSIM4_MOD_WDELTA, IF_REAL, "Width dependence of delta"), +IOP( "wrdsw", BSIM4_MOD_WRDSW, IF_REAL, "Width dependence of rdsw "), +IOP( "wrsw", BSIM4_MOD_WRSW, IF_REAL, "Width dependence of rsw"), +IOP( "wrdw", BSIM4_MOD_WRDW, IF_REAL, "Width dependence of rdw"), + +IOP( "wprwg", BSIM4_MOD_WPRWG, IF_REAL, "Width dependence of prwg "), +IOP( "wprwb", BSIM4_MOD_WPRWB, IF_REAL, "Width dependence of prwb "), + +IOP( "wprt", BSIM4_MOD_WPRT, IF_REAL, "Width dependence of prt"), +IOP( "weta0", BSIM4_MOD_WETA0, IF_REAL, "Width dependence of eta0"), +IOP( "wetab", BSIM4_MOD_WETAB, IF_REAL, "Width dependence of etab"), +IOP( "wpclm", BSIM4_MOD_WPCLM, IF_REAL, "Width dependence of pclm"), +IOP( "wpdiblc1", BSIM4_MOD_WPDIBL1, IF_REAL, "Width dependence of pdiblc1"), +IOP( "wpdiblc2", BSIM4_MOD_WPDIBL2, IF_REAL, "Width dependence of pdiblc2"), +IOP( "wpdiblcb", BSIM4_MOD_WPDIBLB, IF_REAL, "Width dependence of pdiblcb"), +IOP( "wfprout", BSIM4_MOD_WFPROUT, IF_REAL, "Width dependence of pdiblcb"), +IOP( "wpdits", BSIM4_MOD_WPDITS, IF_REAL, "Width dependence of pdits"), +IOP( "wpditsd", BSIM4_MOD_WPDITSD, IF_REAL, "Width dependence of pditsd"), +IOP( "wpscbe1", BSIM4_MOD_WPSCBE1, IF_REAL, "Width dependence of pscbe1"), +IOP( "wpscbe2", BSIM4_MOD_WPSCBE2, IF_REAL, "Width dependence of pscbe2"), +IOP( "wpvag", BSIM4_MOD_WPVAG, IF_REAL, "Width dependence of pvag"), +IOP( "wwr", BSIM4_MOD_WWR, IF_REAL, "Width dependence of wr"), +IOP( "wdwg", BSIM4_MOD_WDWG, IF_REAL, "Width dependence of dwg"), +IOP( "wdwb", BSIM4_MOD_WDWB, IF_REAL, "Width dependence of dwb"), +IOP( "wb0", BSIM4_MOD_WB0, IF_REAL, "Width dependence of b0"), +IOP( "wb1", BSIM4_MOD_WB1, IF_REAL, "Width dependence of b1"), +IOP( "wcgsl", BSIM4_MOD_WCGSL, IF_REAL, "Width dependence of cgsl"), +IOP( "wcgdl", BSIM4_MOD_WCGDL, IF_REAL, "Width dependence of cgdl"), +IOP( "wckappas", BSIM4_MOD_WCKAPPAS, IF_REAL, "Width dependence of ckappas"), +IOP( "wckappad", BSIM4_MOD_WCKAPPAD, IF_REAL, "Width dependence of ckappad"), +IOP( "wcf", BSIM4_MOD_WCF, IF_REAL, "Width dependence of cf"), +IOP( "wclc", BSIM4_MOD_WCLC, IF_REAL, "Width dependence of clc"), +IOP( "wcle", BSIM4_MOD_WCLE, IF_REAL, "Width dependence of cle"), +IOP( "walpha0", BSIM4_MOD_WALPHA0, IF_REAL, "Width dependence of alpha0"), +IOP( "walpha1", BSIM4_MOD_WALPHA1, IF_REAL, "Width dependence of alpha1"), +IOP( "wbeta0", BSIM4_MOD_WBETA0, IF_REAL, "Width dependence of beta0"), +IOP( "wagidl", BSIM4_MOD_WAGIDL, IF_REAL, "Width dependence of agidl"), +IOP( "wbgidl", BSIM4_MOD_WBGIDL, IF_REAL, "Width dependence of bgidl"), +IOP( "wcgidl", BSIM4_MOD_WCGIDL, IF_REAL, "Width dependence of cgidl"), +IOP( "wegidl", BSIM4_MOD_WEGIDL, IF_REAL, "Width dependence of egidl"), +IOP( "waigc", BSIM4_MOD_WAIGC, IF_REAL, "Width dependence of aigc"), +IOP( "wbigc", BSIM4_MOD_WBIGC, IF_REAL, "Width dependence of bigc"), +IOP( "wcigc", BSIM4_MOD_WCIGC, IF_REAL, "Width dependence of cigc"), +IOP( "waigsd", BSIM4_MOD_WAIGSD, IF_REAL, "Width dependence of aigsd"), +IOP( "wbigsd", BSIM4_MOD_WBIGSD, IF_REAL, "Width dependence of bigsd"), +IOP( "wcigsd", BSIM4_MOD_WCIGSD, IF_REAL, "Width dependence of cigsd"), +IOP( "waigbacc", BSIM4_MOD_WAIGBACC, IF_REAL, "Width dependence of aigbacc"), +IOP( "wbigbacc", BSIM4_MOD_WBIGBACC, IF_REAL, "Width dependence of bigbacc"), +IOP( "wcigbacc", BSIM4_MOD_WCIGBACC, IF_REAL, "Width dependence of cigbacc"), +IOP( "waigbinv", BSIM4_MOD_WAIGBINV, IF_REAL, "Width dependence of aigbinv"), +IOP( "wbigbinv", BSIM4_MOD_WBIGBINV, IF_REAL, "Width dependence of bigbinv"), +IOP( "wcigbinv", BSIM4_MOD_WCIGBINV, IF_REAL, "Width dependence of cigbinv"), +IOP( "wnigc", BSIM4_MOD_WNIGC, IF_REAL, "Width dependence of nigc"), +IOP( "wnigbinv", BSIM4_MOD_WNIGBINV, IF_REAL, "Width dependence of nigbinv"), +IOP( "wnigbacc", BSIM4_MOD_WNIGBACC, IF_REAL, "Width dependence of nigbacc"), +IOP( "wntox", BSIM4_MOD_WNTOX, IF_REAL, "Width dependence of ntox"), +IOP( "weigbinv", BSIM4_MOD_WEIGBINV, IF_REAL, "Width dependence for eigbinv"), +IOP( "wpigcd", BSIM4_MOD_WPIGCD, IF_REAL, "Width dependence for pigcd"), +IOP( "wpoxedge", BSIM4_MOD_WPOXEDGE, IF_REAL, "Width dependence for poxedge"), +IOP( "wvfbcv", BSIM4_MOD_WVFBCV, IF_REAL, "Width dependence of vfbcv"), +IOP( "wvfb", BSIM4_MOD_WVFB, IF_REAL, "Width dependence of vfb"), +IOP( "wacde", BSIM4_MOD_WACDE, IF_REAL, "Width dependence of acde"), +IOP( "wmoin", BSIM4_MOD_WMOIN, IF_REAL, "Width dependence of moin"), +IOP( "wnoff", BSIM4_MOD_WNOFF, IF_REAL, "Width dependence of noff"), +IOP( "wvoffcv", BSIM4_MOD_WVOFFCV, IF_REAL, "Width dependence of voffcv"), +IOP( "wxrcrg1", BSIM4_MOD_WXRCRG1, IF_REAL, "Width dependence of xrcrg1"), +IOP( "wxrcrg2", BSIM4_MOD_WXRCRG2, IF_REAL, "Width dependence of xrcrg2"), +IOP( "weu", BSIM4_MOD_WEU, IF_REAL, "Width dependence of eu"), + +IOP( "pcdsc", BSIM4_MOD_PCDSC, IF_REAL, "Cross-term dependence of cdsc"), +IOP( "pcdscb", BSIM4_MOD_PCDSCB, IF_REAL, "Cross-term dependence of cdscb"), +IOP( "pcdscd", BSIM4_MOD_PCDSCD, IF_REAL, "Cross-term dependence of cdscd"), +IOP( "pcit", BSIM4_MOD_PCIT, IF_REAL, "Cross-term dependence of cit"), +IOP( "pnfactor", BSIM4_MOD_PNFACTOR, IF_REAL, "Cross-term dependence of nfactor"), +IOP( "pxj", BSIM4_MOD_PXJ, IF_REAL, "Cross-term dependence of xj"), +IOP( "pvsat", BSIM4_MOD_PVSAT, IF_REAL, "Cross-term dependence of vsat"), +IOP( "pat", BSIM4_MOD_PAT, IF_REAL, "Cross-term dependence of at"), +IOP( "pa0", BSIM4_MOD_PA0, IF_REAL, "Cross-term dependence of a0"), +IOP( "pags", BSIM4_MOD_PAGS, IF_REAL, "Cross-term dependence of ags"), +IOP( "pa1", BSIM4_MOD_PA1, IF_REAL, "Cross-term dependence of a1"), +IOP( "pa2", BSIM4_MOD_PA2, IF_REAL, "Cross-term dependence of a2"), +IOP( "pketa", BSIM4_MOD_PKETA, IF_REAL, "Cross-term dependence of keta"), +IOP( "pnsub", BSIM4_MOD_PNSUB, IF_REAL, "Cross-term dependence of nsub"), +IOP( "pndep", BSIM4_MOD_PNDEP, IF_REAL, "Cross-term dependence of ndep"), +IOP( "pnsd", BSIM4_MOD_PNSD, IF_REAL, "Cross-term dependence of nsd"), +IOP( "pphin", BSIM4_MOD_PPHIN, IF_REAL, "Cross-term dependence of phin"), +IOP( "pngate", BSIM4_MOD_PNGATE, IF_REAL, "Cross-term dependence of ngate"), +IOP( "pgamma1", BSIM4_MOD_PGAMMA1, IF_REAL, "Cross-term dependence of gamma1"), +IOP( "pgamma2", BSIM4_MOD_PGAMMA2, IF_REAL, "Cross-term dependence of gamma2"), +IOP( "pvbx", BSIM4_MOD_PVBX, IF_REAL, "Cross-term dependence of vbx"), +IOP( "pvbm", BSIM4_MOD_PVBM, IF_REAL, "Cross-term dependence of vbm"), +IOP( "pxt", BSIM4_MOD_PXT, IF_REAL, "Cross-term dependence of xt"), +IOP( "pk1", BSIM4_MOD_PK1, IF_REAL, "Cross-term dependence of k1"), +IOP( "pkt1", BSIM4_MOD_PKT1, IF_REAL, "Cross-term dependence of kt1"), +IOP( "pkt1l", BSIM4_MOD_PKT1L, IF_REAL, "Cross-term dependence of kt1l"), +IOP( "pkt2", BSIM4_MOD_PKT2, IF_REAL, "Cross-term dependence of kt2"), +IOP( "pk2", BSIM4_MOD_PK2, IF_REAL, "Cross-term dependence of k2"), +IOP( "pk3", BSIM4_MOD_PK3, IF_REAL, "Cross-term dependence of k3"), +IOP( "pk3b", BSIM4_MOD_PK3B, IF_REAL, "Cross-term dependence of k3b"), +IOP( "pw0", BSIM4_MOD_PW0, IF_REAL, "Cross-term dependence of w0"), +IOP( "pdvtp0", BSIM4_MOD_PDVTP0, IF_REAL, "Cross-term dependence of dvtp0"), +IOP( "pdvtp1", BSIM4_MOD_PDVTP1, IF_REAL, "Cross-term dependence of dvtp1"), +IOP( "plpe0", BSIM4_MOD_PLPE0, IF_REAL, "Cross-term dependence of lpe0"), +IOP( "plpeb", BSIM4_MOD_PLPEB, IF_REAL, "Cross-term dependence of lpeb"), +IOP( "pdvt0", BSIM4_MOD_PDVT0, IF_REAL, "Cross-term dependence of dvt0"), +IOP( "pdvt1", BSIM4_MOD_PDVT1, IF_REAL, "Cross-term dependence of dvt1"), +IOP( "pdvt2", BSIM4_MOD_PDVT2, IF_REAL, "Cross-term dependence of dvt2"), +IOP( "pdvt0w", BSIM4_MOD_PDVT0W, IF_REAL, "Cross-term dependence of dvt0w"), +IOP( "pdvt1w", BSIM4_MOD_PDVT1W, IF_REAL, "Cross-term dependence of dvt1w"), +IOP( "pdvt2w", BSIM4_MOD_PDVT2W, IF_REAL, "Cross-term dependence of dvt2w"), +IOP( "pdrout", BSIM4_MOD_PDROUT, IF_REAL, "Cross-term dependence of drout"), +IOP( "pdsub", BSIM4_MOD_PDSUB, IF_REAL, "Cross-term dependence of dsub"), +IOP( "pvth0", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pvtho", BSIM4_MOD_PVTH0, IF_REAL,"Cross-term dependence of vto"), +IOP( "pua", BSIM4_MOD_PUA, IF_REAL, "Cross-term dependence of ua"), +IOP( "pua1", BSIM4_MOD_PUA1, IF_REAL, "Cross-term dependence of ua1"), +IOP( "pub", BSIM4_MOD_PUB, IF_REAL, "Cross-term dependence of ub"), +IOP( "pub1", BSIM4_MOD_PUB1, IF_REAL, "Cross-term dependence of ub1"), +IOP( "puc", BSIM4_MOD_PUC, IF_REAL, "Cross-term dependence of uc"), +IOP( "puc1", BSIM4_MOD_PUC1, IF_REAL, "Cross-term dependence of uc1"), +IOP( "pu0", BSIM4_MOD_PU0, IF_REAL, "Cross-term dependence of u0"), +IOP( "pute", BSIM4_MOD_PUTE, IF_REAL, "Cross-term dependence of ute"), +IOP( "pvoff", BSIM4_MOD_PVOFF, IF_REAL, "Cross-term dependence of voff"), +IOP( "pminv", BSIM4_MOD_PMINV, IF_REAL, "Cross-term dependence of minv"), +IOP( "pdelta", BSIM4_MOD_PDELTA, IF_REAL, "Cross-term dependence of delta"), +IOP( "prdsw", BSIM4_MOD_PRDSW, IF_REAL, "Cross-term dependence of rdsw "), +IOP( "prsw", BSIM4_MOD_PRSW, IF_REAL, "Cross-term dependence of rsw"), +IOP( "prdw", BSIM4_MOD_PRDW, IF_REAL, "Cross-term dependence of rdw"), + +IOP( "pprwg", BSIM4_MOD_PPRWG, IF_REAL, "Cross-term dependence of prwg "), +IOP( "pprwb", BSIM4_MOD_PPRWB, IF_REAL, "Cross-term dependence of prwb "), + +IOP( "pprt", BSIM4_MOD_PPRT, IF_REAL, "Cross-term dependence of prt "), +IOP( "peta0", BSIM4_MOD_PETA0, IF_REAL, "Cross-term dependence of eta0"), +IOP( "petab", BSIM4_MOD_PETAB, IF_REAL, "Cross-term dependence of etab"), +IOP( "ppclm", BSIM4_MOD_PPCLM, IF_REAL, "Cross-term dependence of pclm"), +IOP( "ppdiblc1", BSIM4_MOD_PPDIBL1, IF_REAL, "Cross-term dependence of pdiblc1"), +IOP( "ppdiblc2", BSIM4_MOD_PPDIBL2, IF_REAL, "Cross-term dependence of pdiblc2"), +IOP( "ppdiblcb", BSIM4_MOD_PPDIBLB, IF_REAL, "Cross-term dependence of pdiblcb"), +IOP( "pfprout", BSIM4_MOD_PFPROUT, IF_REAL, "Cross-term dependence of pdiblcb"), +IOP( "ppdits", BSIM4_MOD_PPDITS, IF_REAL, "Cross-term dependence of pdits"), +IOP( "ppditsd", BSIM4_MOD_PPDITSD, IF_REAL, "Cross-term dependence of pditsd"), +IOP( "ppscbe1", BSIM4_MOD_PPSCBE1, IF_REAL, "Cross-term dependence of pscbe1"), +IOP( "ppscbe2", BSIM4_MOD_PPSCBE2, IF_REAL, "Cross-term dependence of pscbe2"), +IOP( "ppvag", BSIM4_MOD_PPVAG, IF_REAL, "Cross-term dependence of pvag"), +IOP( "pwr", BSIM4_MOD_PWR, IF_REAL, "Cross-term dependence of wr"), +IOP( "pdwg", BSIM4_MOD_PDWG, IF_REAL, "Cross-term dependence of dwg"), +IOP( "pdwb", BSIM4_MOD_PDWB, IF_REAL, "Cross-term dependence of dwb"), +IOP( "pb0", BSIM4_MOD_PB0, IF_REAL, "Cross-term dependence of b0"), +IOP( "pb1", BSIM4_MOD_PB1, IF_REAL, "Cross-term dependence of b1"), +IOP( "pcgsl", BSIM4_MOD_PCGSL, IF_REAL, "Cross-term dependence of cgsl"), +IOP( "pcgdl", BSIM4_MOD_PCGDL, IF_REAL, "Cross-term dependence of cgdl"), +IOP( "pckappas", BSIM4_MOD_PCKAPPAS, IF_REAL, "Cross-term dependence of ckappas"), +IOP( "pckappad", BSIM4_MOD_PCKAPPAD, IF_REAL, "Cross-term dependence of ckappad"), +IOP( "pcf", BSIM4_MOD_PCF, IF_REAL, "Cross-term dependence of cf"), +IOP( "pclc", BSIM4_MOD_PCLC, IF_REAL, "Cross-term dependence of clc"), +IOP( "pcle", BSIM4_MOD_PCLE, IF_REAL, "Cross-term dependence of cle"), +IOP( "palpha0", BSIM4_MOD_PALPHA0, IF_REAL, "Cross-term dependence of alpha0"), +IOP( "palpha1", BSIM4_MOD_PALPHA1, IF_REAL, "Cross-term dependence of alpha1"), +IOP( "pbeta0", BSIM4_MOD_PBETA0, IF_REAL, "Cross-term dependence of beta0"), +IOP( "pagidl", BSIM4_MOD_PAGIDL, IF_REAL, "Cross-term dependence of agidl"), +IOP( "pbgidl", BSIM4_MOD_PBGIDL, IF_REAL, "Cross-term dependence of bgidl"), +IOP( "pcgidl", BSIM4_MOD_PCGIDL, IF_REAL, "Cross-term dependence of cgidl"), +IOP( "pegidl", BSIM4_MOD_PEGIDL, IF_REAL, "Cross-term dependence of egidl"), +IOP( "paigc", BSIM4_MOD_PAIGC, IF_REAL, "Cross-term dependence of aigc"), +IOP( "pbigc", BSIM4_MOD_PBIGC, IF_REAL, "Cross-term dependence of bigc"), +IOP( "pcigc", BSIM4_MOD_PCIGC, IF_REAL, "Cross-term dependence of cigc"), +IOP( "paigsd", BSIM4_MOD_PAIGSD, IF_REAL, "Cross-term dependence of aigsd"), +IOP( "pbigsd", BSIM4_MOD_PBIGSD, IF_REAL, "Cross-term dependence of bigsd"), +IOP( "pcigsd", BSIM4_MOD_PCIGSD, IF_REAL, "Cross-term dependence of cigsd"), +IOP( "paigbacc", BSIM4_MOD_PAIGBACC, IF_REAL, "Cross-term dependence of aigbacc"), +IOP( "pbigbacc", BSIM4_MOD_PBIGBACC, IF_REAL, "Cross-term dependence of bigbacc"), +IOP( "pcigbacc", BSIM4_MOD_PCIGBACC, IF_REAL, "Cross-term dependence of cigbacc"), +IOP( "paigbinv", BSIM4_MOD_PAIGBINV, IF_REAL, "Cross-term dependence of aigbinv"), +IOP( "pbigbinv", BSIM4_MOD_PBIGBINV, IF_REAL, "Cross-term dependence of bigbinv"), +IOP( "pcigbinv", BSIM4_MOD_PCIGBINV, IF_REAL, "Cross-term dependence of cigbinv"), +IOP( "pnigc", BSIM4_MOD_PNIGC, IF_REAL, "Cross-term dependence of nigc"), +IOP( "pnigbinv", BSIM4_MOD_PNIGBINV, IF_REAL, "Cross-term dependence of nigbinv"), +IOP( "pnigbacc", BSIM4_MOD_PNIGBACC, IF_REAL, "Cross-term dependence of nigbacc"), +IOP( "pntox", BSIM4_MOD_PNTOX, IF_REAL, "Cross-term dependence of ntox"), +IOP( "peigbinv", BSIM4_MOD_PEIGBINV, IF_REAL, "Cross-term dependence for eigbinv"), +IOP( "ppigcd", BSIM4_MOD_PPIGCD, IF_REAL, "Cross-term dependence for pigcd"), +IOP( "ppoxedge", BSIM4_MOD_PPOXEDGE, IF_REAL, "Cross-term dependence for poxedge"), +IOP( "pvfbcv", BSIM4_MOD_PVFBCV, IF_REAL, "Cross-term dependence of vfbcv"), +IOP( "pvfb", BSIM4_MOD_PVFB, IF_REAL, "Cross-term dependence of vfb"), +IOP( "pacde", BSIM4_MOD_PACDE, IF_REAL, "Cross-term dependence of acde"), +IOP( "pmoin", BSIM4_MOD_PMOIN, IF_REAL, "Cross-term dependence of moin"), +IOP( "pnoff", BSIM4_MOD_PNOFF, IF_REAL, "Cross-term dependence of noff"), +IOP( "pvoffcv", BSIM4_MOD_PVOFFCV, IF_REAL, "Cross-term dependence of voffcv"), +IOP( "pxrcrg1", BSIM4_MOD_PXRCRG1, IF_REAL, "Cross-term dependence of xrcrg1"), +IOP( "pxrcrg2", BSIM4_MOD_PXRCRG2, IF_REAL, "Cross-term dependence of xrcrg2"), +IOP( "peu", BSIM4_MOD_PEU, IF_REAL, "Cross-term dependence of eu"), + +IOP( "noia", BSIM4_MOD_NOIA, IF_REAL, "Flicker noise parameter"), +IOP( "noib", BSIM4_MOD_NOIB, IF_REAL, "Flicker noise parameter"), +IOP( "noic", BSIM4_MOD_NOIC, IF_REAL, "Flicker noise parameter"), +IOP( "tnoia", BSIM4_MOD_TNOIA, IF_REAL, "Thermal noise parameter"), +IOP( "tnoib", BSIM4_MOD_TNOIB, IF_REAL, "Thermal noise parameter"), +IOP( "ntnoi", BSIM4_MOD_NTNOI, IF_REAL, "Thermal noise parameter"), +IOP( "em", BSIM4_MOD_EM, IF_REAL, "Flicker noise parameter"), +IOP( "ef", BSIM4_MOD_EF, IF_REAL, "Flicker noise frequency exponent"), +IOP( "af", BSIM4_MOD_AF, IF_REAL, "Flicker noise exponent"), +IOP( "kf", BSIM4_MOD_KF, IF_REAL, "Flicker noise coefficient"), + +IP( "nmos", BSIM4_MOD_NMOS, IF_FLAG, "Flag to indicate NMOS"), +IP( "pmos", BSIM4_MOD_PMOS, IF_FLAG, "Flag to indicate PMOS"), +}; + +char *BSIM4names[] = { + "Drain", + "Gate", + "Source", + "Bulk", + "Charge" +}; + +int BSIM4nSize = NUMELEMS(BSIM4names); +int BSIM4pTSize = NUMELEMS(BSIM4pTable); +int BSIM4mPTSize = NUMELEMS(BSIM4mPTable); +int BSIM4iSize = sizeof(BSIM4instance); +int BSIM4mSize = sizeof(BSIM4model); + + + diff --git a/src/spicelib/devices/bsim4/b4acld.c b/src/spicelib/devices/bsim4/b4acld.c new file mode 100644 index 000000000..b722958f7 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4acld.c @@ -0,0 +1,642 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4acld.c of BSIM4.0.0. + * Authors: Weidong Liu, Xiaodong Jin, Kanyu M. Cao, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim4def.h" +#include "sperror.h" + + +int +BSIM4acLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM4model *model = (BSIM4model*)inModel; +register BSIM4instance *here; + +double gjbd, gjbs, geltd, gcrg, gcrgg, gcrgd, gcrgs, gcrgb; +double xcbgb, xcbdb, xcbsb, xcbbb; +double xcggbr, xcgdbr, xcgsbr, xcgbbr, xcggbi, xcgdbi, xcgsbi, xcgbbi; +double Cggr, Cgdr, Cgsr, Cgbr, Cggi, Cgdi, Cgsi, Cgbi; +double xcddbr, xcdgbr, xcdsbr, xcdbbr, xcsdbr, xcsgbr, xcssbr, xcsbbr; +double xcddbi, xcdgbi, xcdsbi, xcdbbi, xcsdbi, xcsgbi, xcssbi, xcsbbi; +double xcdbdb, xcsbsb, xcgmgmb, xcgmdb, xcgmsb, xcdgmb, xcsgmb; +double xcgmbb, xcbgmb; +double capbd, capbs, omega; +double gstot, gstotd, gstotg, gstots, gstotb, gspr; +double gdtot, gdtotd, gdtotg, gdtots, gdtotb, gdpr; +double gIstotg, gIstotd, gIstots, gIstotb; +double gIdtotg, gIdtotd, gIdtots, gIdtotb; +double gIbtotg, gIbtotd, gIbtots, gIbtotb; +double gIgtotg, gIgtotd, gIgtots, gIgtotb; +double cgso, cgdo, cgbo; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb; +double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11; +double Csg, Csd, Css, Csb; +double Cdgr, Cddr, Cdsr, Cdbr, Csgr, Csdr, Cssr, Csbr; +double Cdgi, Cddi, Cdsi, Cdbi, Csgi, Csdi, Cssi, Csbi; +double gmr, gmi, gmbsr, gmbsi, gdsr, gdsi; +double FwdSumr, RevSumr, Gmr, Gmbsr, Gdsr; +double FwdSumi, RevSumi, Gmi, Gmbsi, Gdsi; +struct bsim4SizeDependParam *pParam; + + omega = ckt->CKTomega; + for (; model != NULL; model = model->BSIM4nextModel) + { for (here = model->BSIM4instances; here!= NULL; + here = here->BSIM4nextInstance) + { if (here->BSIM4owner != ARCHme) continue; + pParam = here->pParam; + capbd = here->BSIM4capbd; + capbs = here->BSIM4capbs; + cgso = here->BSIM4cgso; + cgdo = here->BSIM4cgdo; + cgbo = pParam->BSIM4cgbo; + + Csd = -(here->BSIM4cddb + here->BSIM4cgdb + here->BSIM4cbdb); + Csg = -(here->BSIM4cdgb + here->BSIM4cggb + here->BSIM4cbgb); + Css = -(here->BSIM4cdsb + here->BSIM4cgsb + here->BSIM4cbsb); + + if (here->BSIM4acnqsMod) + { T0 = omega * here->BSIM4taunet; + T1 = T0 * T0; + T2 = 1.0 / (1.0 + T1); + T3 = T0 * T2; + + gmr = here->BSIM4gm * T2; + gmbsr = here->BSIM4gmbs * T2; + gdsr = here->BSIM4gds * T2; + + gmi = -here->BSIM4gm * T3; + gmbsi = -here->BSIM4gmbs * T3; + gdsi = -here->BSIM4gds * T3; + + Cddr = here->BSIM4cddb * T2; + Cdgr = here->BSIM4cdgb * T2; + Cdsr = here->BSIM4cdsb * T2; + Cdbr = -(Cddr + Cdgr + Cdsr); + + /* WDLiu: Cxyi mulitplied by jomega below, and actually to be of conductance */ + Cddi = here->BSIM4cddb * T3 * omega; + Cdgi = here->BSIM4cdgb * T3 * omega; + Cdsi = here->BSIM4cdsb * T3 * omega; + Cdbi = -(Cddi + Cdgi + Cdsi); + + Csdr = Csd * T2; + Csgr = Csg * T2; + Cssr = Css * T2; + Csbr = -(Csdr + Csgr + Cssr); + + Csdi = Csd * T3 * omega; + Csgi = Csg * T3 * omega; + Cssi = Css * T3 * omega; + Csbi = -(Csdi + Csgi + Cssi); + + Cgdr = -(Cddr + Csdr + here->BSIM4cbdb); + Cggr = -(Cdgr + Csgr + here->BSIM4cbgb); + Cgsr = -(Cdsr + Cssr + here->BSIM4cbsb); + Cgbr = -(Cgdr + Cggr + Cgsr); + + Cgdi = -(Cddi + Csdi); + Cggi = -(Cdgi + Csgi); + Cgsi = -(Cdsi + Cssi); + Cgbi = -(Cgdi + Cggi + Cgsi); + } + else /* QS */ + { gmr = here->BSIM4gm; + gmbsr = here->BSIM4gmbs; + gdsr = here->BSIM4gds; + gmi = gmbsi = gdsi = 0.0; + + Cddr = here->BSIM4cddb; + Cdgr = here->BSIM4cdgb; + Cdsr = here->BSIM4cdsb; + Cdbr = -(Cddr + Cdgr + Cdsr); + Cddi = Cdgi = Cdsi = Cdbi = 0.0; + + Csdr = Csd; + Csgr = Csg; + Cssr = Css; + Csbr = -(Csdr + Csgr + Cssr); + Csdi = Csgi = Cssi = Csbi = 0.0; + + Cgdr = here->BSIM4cgdb; + Cggr = here->BSIM4cggb; + Cgsr = here->BSIM4cgsb; + Cgbr = -(Cgdr + Cggr + Cgsr); + Cgdi = Cggi = Cgsi = Cgbi = 0.0; + } + + + if (here->BSIM4mode >= 0) + { Gmr = gmr; + Gmbsr = gmbsr; + FwdSumr = Gmr + Gmbsr; + RevSumr = 0.0; + Gmi = gmi; + Gmbsi = gmbsi; + FwdSumi = Gmi + Gmbsi; + RevSumi = 0.0; + + gbbdp = -(here->BSIM4gbds + here->BSIM4ggidld); + gbbsp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs + - here->BSIM4ggidls; + gbdpg = here->BSIM4gbgs + here->BSIM4ggidlg; + gbdpdp = here->BSIM4gbds + here->BSIM4ggidld; + gbdpb = here->BSIM4gbbs + here->BSIM4ggidlb; + gbdpsp = -(gbdpg + gbdpdp + gbdpb) + here->BSIM4ggidls; + + gbspdp = 0.0; + gbspg = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + if (model->BSIM4igcMod) + { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcsg; + gIstotd = here->BSIM4gIgcsd; + gIstots = here->BSIM4gIgss + here->BSIM4gIgcss; + gIstotb = here->BSIM4gIgcsb; + + gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcdg; + gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcdd; + gIdtots = here->BSIM4gIgcds; + gIdtotb = here->BSIM4gIgcdb; + } + else + { gIstotg = gIstotd = gIstots = gIstotb = 0.0; + gIdtotg = gIdtotd = gIdtots = gIdtotb = 0.0; + } + + if (model->BSIM4igbMod) + { gIbtotg = here->BSIM4gIgbg; + gIbtotd = here->BSIM4gIgbd; + gIbtots = here->BSIM4gIgbs; + gIbtotb = here->BSIM4gIgbb; + } + else + gIbtotg = gIbtotd = gIbtots = gIbtotb = 0.0; + + if ((model->BSIM4igcMod != 0) || (model->BSIM4igbMod != 0)) + { gIgtotg = gIstotg + gIdtotg + gIbtotg; + gIgtotd = gIstotd + gIdtotd + gIbtotd ; + gIgtots = gIstots + gIdtots + gIbtots; + gIgtotb = gIstotb + gIdtotb + gIbtotb; + } + else + gIgtotg = gIgtotd = gIgtots = gIgtotb = 0.0; + + if (here->BSIM4rgateMod == 2) + T0 = *(ckt->CKTstates[0] + here->BSIM4vges) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + else if (here->BSIM4rgateMod == 3) + T0 = *(ckt->CKTstates[0] + here->BSIM4vgms) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + if (here->BSIM4rgateMod > 1) + { gcrgd = here->BSIM4gcrgd * T0; + gcrgg = here->BSIM4gcrgg * T0; + gcrgs = here->BSIM4gcrgs * T0; + gcrgb = here->BSIM4gcrgb * T0; + gcrgg -= here->BSIM4gcrg; + gcrg = here->BSIM4gcrg; + } + else + gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + + if (here->BSIM4rgateMod == 3) + { xcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * omega; + xcgmdb = -cgdo * omega; + xcgmsb = -cgso * omega; + xcgmbb = -pParam->BSIM4cgbo * omega; + + xcdgmb = xcgmdb; + xcsgmb = xcgmsb; + xcbgmb = xcgmbb; + + xcggbr = Cggr * omega; + xcgdbr = Cgdr * omega; + xcgsbr = Cgsr * omega; + xcgbbr = -(xcggbr + xcgdbr + xcgsbr); + + xcdgbr = Cdgr * omega; + xcsgbr = Csgr * omega; + xcbgb = here->BSIM4cbgb * omega; + } + else + { xcggbr = (Cggr + cgdo + cgso + pParam->BSIM4cgbo ) * omega; + xcgdbr = (Cgdr - cgdo) * omega; + xcgsbr = (Cgsr - cgso) * omega; + xcgbbr = -(xcggbr + xcgdbr + xcgsbr); + + xcdgbr = (Cdgr - cgdo) * omega; + xcsgbr = (Csgr - cgso) * omega; + xcbgb = (here->BSIM4cbgb - pParam->BSIM4cgbo) * omega; + + xcdgmb = xcsgmb = xcbgmb = 0.0; + } + xcddbr = (Cddr + here->BSIM4capbd + cgdo) * omega; + xcdsbr = Cdsr * omega; + xcsdbr = Csdr * omega; + xcssbr = (here->BSIM4capbs + cgso + Cssr) * omega; + + if (!here->BSIM4rbodyMod) + { xcdbbr = -(xcdgbr + xcddbr + xcdsbr + xcdgmb); + xcsbbr = -(xcsgbr + xcsdbr + xcssbr + xcsgmb); + + xcbdb = (here->BSIM4cbdb - here->BSIM4capbd) * omega; + xcbsb = (here->BSIM4cbsb - here->BSIM4capbs) * omega; + xcdbdb = 0.0; + } + else + { xcdbbr = Cdbr * omega; + xcsbbr = -(xcsgbr + xcsdbr + xcssbr + xcsgmb) + + here->BSIM4capbs * omega; + + xcbdb = here->BSIM4cbdb * omega; + xcbsb = here->BSIM4cbsb * omega; + + xcdbdb = -here->BSIM4capbd * omega; + xcsbsb = -here->BSIM4capbs * omega; + } + xcbbb = -(xcbdb + xcbgb + xcbsb + xcbgmb); + + xcdgbi = Cdgi; + xcsgbi = Csgi; + xcddbi = Cddi; + xcdsbi = Cdsi; + xcsdbi = Csdi; + xcssbi = Cssi; + xcdbbi = Cdbi; + xcsbbi = Csbi; + xcggbi = Cggi; + xcgdbi = Cgdi; + xcgsbi = Cgsi; + xcgbbi = Cgbi; + } + else /* Reverse mode */ + { Gmr = -gmr; + Gmbsr = -gmbsr; + FwdSumr = 0.0; + RevSumr = -(Gmr + Gmbsr); + Gmi = -gmi; + Gmbsi = -gmbsi; + FwdSumi = 0.0; + RevSumi = -(Gmi + Gmbsi); + + gbbsp = -(here->BSIM4gbds + here->BSIM4ggidld); + gbbdp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs + - here->BSIM4ggidls; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM4gbgs + here->BSIM4ggidlg; + gbspsp = here->BSIM4gbds + here->BSIM4ggidld; + gbspb = here->BSIM4gbbs + here->BSIM4ggidlb; + gbspdp = -(gbspg + gbspsp + gbspb) + here->BSIM4ggidls; + + if (model->BSIM4igcMod) + { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcdg; + gIstotd = here->BSIM4gIgcds; + gIstots = here->BSIM4gIgss + here->BSIM4gIgcdd; + gIstotb = here->BSIM4gIgcdb; + + gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcsg; + gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcss; + gIdtots = here->BSIM4gIgcsd; + gIdtotb = here->BSIM4gIgcsb; + } + else + { gIstotg = gIstotd = gIstots = gIstotb = 0.0; + gIdtotg = gIdtotd = gIdtots = gIdtotb = 0.0; + } + + if (model->BSIM4igbMod) + { gIbtotg = here->BSIM4gIgbg; + gIbtotd = here->BSIM4gIgbs; + gIbtots = here->BSIM4gIgbd; + gIbtotb = here->BSIM4gIgbb; + } + else + gIbtotg = gIbtotd = gIbtots = gIbtotb = 0.0; + + if ((model->BSIM4igcMod != 0) || (model->BSIM4igbMod != 0)) + { gIgtotg = gIstotg + gIdtotg + gIbtotg; + gIgtotd = gIstotd + gIdtotd + gIbtotd ; + gIgtots = gIstots + gIdtots + gIbtots; + gIgtotb = gIstotb + gIdtotb + gIbtotb; + } + else + gIgtotg = gIgtotd = gIgtots = gIgtotb = 0.0; + + if (here->BSIM4rgateMod == 2) + T0 = *(ckt->CKTstates[0] + here->BSIM4vges) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + else if (here->BSIM4rgateMod == 3) + T0 = *(ckt->CKTstates[0] + here->BSIM4vgms) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + if (here->BSIM4rgateMod > 1) + { gcrgd = here->BSIM4gcrgs * T0; + gcrgg = here->BSIM4gcrgg * T0; + gcrgs = here->BSIM4gcrgd * T0; + gcrgb = here->BSIM4gcrgb * T0; + gcrgg -= here->BSIM4gcrg; + gcrg = here->BSIM4gcrg; + } + else + gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + + if (here->BSIM4rgateMod == 3) + { xcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * omega; + xcgmdb = -cgdo * omega; + xcgmsb = -cgso * omega; + xcgmbb = -pParam->BSIM4cgbo * omega; + + xcdgmb = xcgmdb; + xcsgmb = xcgmsb; + xcbgmb = xcgmbb; + + xcggbr = Cggr * omega; + xcgdbr = Cgsr * omega; + xcgsbr = Cgdr * omega; + xcgbbr = -(xcggbr + xcgdbr + xcgsbr); + + xcdgbr = Csgr * omega; + xcsgbr = Cdgr * omega; + xcbgb = here->BSIM4cbgb * omega; + } + else + { xcggbr = (Cggr + cgdo + cgso + pParam->BSIM4cgbo ) * omega; + xcgdbr = (Cgsr - cgdo) * omega; + xcgsbr = (Cgdr - cgso) * omega; + xcgbbr = -(xcggbr + xcgdbr + xcgsbr); + + xcdgbr = (Csgr - cgdo) * omega; + xcsgbr = (Cdgr - cgso) * omega; + xcbgb = (here->BSIM4cbgb - pParam->BSIM4cgbo) * omega; + + xcdgmb = xcsgmb = xcbgmb = 0.0; + } + xcddbr = (here->BSIM4capbd + cgdo + Cssr) * omega; + xcdsbr = Csdr * omega; + xcsdbr = Cdsr * omega; + xcssbr = (Cddr + here->BSIM4capbs + cgso) * omega; + + if (!here->BSIM4rbodyMod) + { xcdbbr = -(xcdgbr + xcddbr + xcdsbr + xcdgmb); + xcsbbr = -(xcsgbr + xcsdbr + xcssbr + xcsgmb); + + xcbdb = (here->BSIM4cbsb - here->BSIM4capbd) * omega; + xcbsb = (here->BSIM4cbdb - here->BSIM4capbs) * omega; + xcdbdb = 0.0; + } + else + { xcdbbr = -(xcdgbr + xcddbr + xcdsbr + xcdgmb) + + here->BSIM4capbd * omega; + xcsbbr = Cdbr * omega; + + xcbdb = here->BSIM4cbsb * omega; + xcbsb = here->BSIM4cbdb * omega; + xcdbdb = -here->BSIM4capbd * omega; + xcsbsb = -here->BSIM4capbs * omega; + } + xcbbb = -(xcbgb + xcbdb + xcbsb + xcbgmb); + + xcdgbi = Csgi; + xcsgbi = Cdgi; + xcddbi = Cssi; + xcdsbi = Csdi; + xcsdbi = Cdsi; + xcssbi = Cddi; + xcdbbi = Csbi; + xcsbbi = Cdbi; + xcggbi = Cggi; + xcgdbi = Cgsi; + xcgsbi = Cgdi; + xcgbbi = Cgbi; + } + + if (model->BSIM4rdsMod == 1) + { gstot = here->BSIM4gstot; + gstotd = here->BSIM4gstotd; + gstotg = here->BSIM4gstotg; + gstots = here->BSIM4gstots - gstot; + gstotb = here->BSIM4gstotb; + + gdtot = here->BSIM4gdtot; + gdtotd = here->BSIM4gdtotd - gdtot; + gdtotg = here->BSIM4gdtotg; + gdtots = here->BSIM4gdtots; + gdtotb = here->BSIM4gdtotb; + } + else + { gstot = gstotd = gstotg = gstots = gstotb = 0.0; + gdtot = gdtotd = gdtotg = gdtots = gdtotb = 0.0; + } + + + /* + * Loading AC matrix + */ + + if (!model->BSIM4rdsMod) + { gdpr = here->BSIM4drainConductance; + gspr = here->BSIM4sourceConductance; + } + else + gdpr = gspr = 0.0; + + if (!here->BSIM4rbodyMod) + { gjbd = here->BSIM4gbd; + gjbs = here->BSIM4gbs; + } + else + gjbd = gjbs = 0.0; + + geltd = here->BSIM4grgeltd; + + if (here->BSIM4rgateMod == 1) + { *(here->BSIM4GEgePtr) += geltd; + *(here->BSIM4GPgePtr) -= geltd; + *(here->BSIM4GEgpPtr) -= geltd; + + *(here->BSIM4GPgpPtr +1) += xcggbr; + *(here->BSIM4GPgpPtr) += geltd + xcggbi + gIgtotg; + *(here->BSIM4GPdpPtr +1) += xcgdbr; + *(here->BSIM4GPdpPtr) += xcgdbi + gIgtotd; + *(here->BSIM4GPspPtr +1) += xcgsbr; + *(here->BSIM4GPspPtr) += xcgsbi + gIgtots; + *(here->BSIM4GPbpPtr +1) += xcgbbr; + *(here->BSIM4GPbpPtr) += xcgbbi + gIgtotb; + } /* WDLiu: gcrg already subtracted from all gcrgg below */ + else if (here->BSIM4rgateMod == 2) + { *(here->BSIM4GEgePtr) += gcrg; + *(here->BSIM4GEgpPtr) += gcrgg; + *(here->BSIM4GEdpPtr) += gcrgd; + *(here->BSIM4GEspPtr) += gcrgs; + *(here->BSIM4GEbpPtr) += gcrgb; + + *(here->BSIM4GPgePtr) -= gcrg; + *(here->BSIM4GPgpPtr +1) += xcggbr; + *(here->BSIM4GPgpPtr) -= gcrgg - xcggbi - gIgtotg; + *(here->BSIM4GPdpPtr +1) += xcgdbr; + *(here->BSIM4GPdpPtr) -= gcrgd - xcgdbi - gIgtotd; + *(here->BSIM4GPspPtr +1) += xcgsbr; + *(here->BSIM4GPspPtr) -= gcrgs - xcgsbi - gIgtots; + *(here->BSIM4GPbpPtr +1) += xcgbbr; + *(here->BSIM4GPbpPtr) -= gcrgb - xcgbbi - gIgtotb; + } + else if (here->BSIM4rgateMod == 3) + { *(here->BSIM4GEgePtr) += geltd; + *(here->BSIM4GEgmPtr) -= geltd; + *(here->BSIM4GMgePtr) -= geltd; + *(here->BSIM4GMgmPtr) += geltd + gcrg; + *(here->BSIM4GMgmPtr +1) += xcgmgmb; + + *(here->BSIM4GMdpPtr) += gcrgd; + *(here->BSIM4GMdpPtr +1) += xcgmdb; + *(here->BSIM4GMgpPtr) += gcrgg; + *(here->BSIM4GMspPtr) += gcrgs; + *(here->BSIM4GMspPtr +1) += xcgmsb; + *(here->BSIM4GMbpPtr) += gcrgb; + *(here->BSIM4GMbpPtr +1) += xcgmbb; + + *(here->BSIM4DPgmPtr +1) += xcdgmb; + *(here->BSIM4GPgmPtr) -= gcrg; + *(here->BSIM4SPgmPtr +1) += xcsgmb; + *(here->BSIM4BPgmPtr +1) += xcbgmb; + + *(here->BSIM4GPgpPtr) -= gcrgg - xcggbi - gIgtotg; + *(here->BSIM4GPgpPtr +1) += xcggbr; + *(here->BSIM4GPdpPtr) -= gcrgd - xcgdbi - gIgtotd; + *(here->BSIM4GPdpPtr +1) += xcgdbr; + *(here->BSIM4GPspPtr) -= gcrgs - xcgsbi - gIgtots; + *(here->BSIM4GPspPtr +1) += xcgsbr; + *(here->BSIM4GPbpPtr) -= gcrgb - xcgbbi - gIgtotb; + *(here->BSIM4GPbpPtr +1) += xcgbbr; + } + else + { *(here->BSIM4GPgpPtr +1) += xcggbr; + *(here->BSIM4GPgpPtr) += xcggbi + gIgtotg; + *(here->BSIM4GPdpPtr +1) += xcgdbr; + *(here->BSIM4GPdpPtr) += xcgdbi + gIgtotd; + *(here->BSIM4GPspPtr +1) += xcgsbr; + *(here->BSIM4GPspPtr) += xcgsbi + gIgtots; + *(here->BSIM4GPbpPtr +1) += xcgbbr; + *(here->BSIM4GPbpPtr) += xcgbbi + gIgtotb; + } + + if (model->BSIM4rdsMod) + { (*(here->BSIM4DgpPtr) += gdtotg); + (*(here->BSIM4DspPtr) += gdtots); + (*(here->BSIM4DbpPtr) += gdtotb); + (*(here->BSIM4SdpPtr) += gstotd); + (*(here->BSIM4SgpPtr) += gstotg); + (*(here->BSIM4SbpPtr) += gstotb); + } + + *(here->BSIM4DPdpPtr +1) += xcddbr + gdsi + RevSumi; + *(here->BSIM4DPdpPtr) += gdpr + xcddbi + gdsr + here->BSIM4gbd + - gdtotd + RevSumr + gbdpdp - gIdtotd; + *(here->BSIM4DPdPtr) -= gdpr + gdtot; + *(here->BSIM4DPgpPtr +1) += xcdgbr + Gmi; + *(here->BSIM4DPgpPtr) += Gmr + xcdgbi - gdtotg + gbdpg - gIdtotg; + *(here->BSIM4DPspPtr +1) += xcdsbr - gdsi - FwdSumi; + *(here->BSIM4DPspPtr) -= gdsr - xcdsbi + FwdSumr + gdtots - gbdpsp + gIdtots; + *(here->BSIM4DPbpPtr +1) += xcdbbr + Gmbsi; + *(here->BSIM4DPbpPtr) -= gjbd + gdtotb - xcdbbi - Gmbsr - gbdpb + gIdtotb; + + *(here->BSIM4DdpPtr) -= gdpr - gdtotd; + *(here->BSIM4DdPtr) += gdpr + gdtot; + + *(here->BSIM4SPdpPtr +1) += xcsdbr - gdsi - RevSumi; + *(here->BSIM4SPdpPtr) -= gdsr - xcsdbi + gstotd + RevSumr - gbspdp + gIstotd; + *(here->BSIM4SPgpPtr +1) += xcsgbr - Gmi; + *(here->BSIM4SPgpPtr) -= Gmr - xcsgbi + gstotg - gbspg + gIstotg; + *(here->BSIM4SPspPtr +1) += xcssbr + gdsi + FwdSumi; + *(here->BSIM4SPspPtr) += gspr + xcssbi + gdsr + here->BSIM4gbs + - gstots + FwdSumr + gbspsp - gIstots; + *(here->BSIM4SPsPtr) -= gspr + gstot; + *(here->BSIM4SPbpPtr +1) += xcsbbr - Gmbsi; + *(here->BSIM4SPbpPtr) -= gjbs + gstotb - xcsbbi + Gmbsr - gbspb + gIstotb; + + *(here->BSIM4SspPtr) -= gspr - gstots; + *(here->BSIM4SsPtr) += gspr + gstot; + + *(here->BSIM4BPdpPtr +1) += xcbdb; + *(here->BSIM4BPdpPtr) -= gjbd - gbbdp + gIbtotd; + *(here->BSIM4BPgpPtr +1) += xcbgb; + *(here->BSIM4BPgpPtr) -= here->BSIM4gbgs + here->BSIM4ggidlg + gIbtotg; + *(here->BSIM4BPspPtr +1) += xcbsb; + *(here->BSIM4BPspPtr) -= gjbs - gbbsp + gIbtots; + *(here->BSIM4BPbpPtr +1) += xcbbb; + *(here->BSIM4BPbpPtr) += gjbd + gjbs - here->BSIM4gbbs + - here->BSIM4ggidlb - gIbtotb; + + if (here->BSIM4rbodyMod) + { (*(here->BSIM4DPdbPtr +1) += xcdbdb); + (*(here->BSIM4DPdbPtr) -= here->BSIM4gbd); + (*(here->BSIM4SPsbPtr +1) += xcsbsb); + (*(here->BSIM4SPsbPtr) -= here->BSIM4gbs); + + (*(here->BSIM4DBdpPtr +1) += xcdbdb); + (*(here->BSIM4DBdpPtr) -= here->BSIM4gbd); + (*(here->BSIM4DBdbPtr +1) -= xcdbdb); + (*(here->BSIM4DBdbPtr) += here->BSIM4gbd + here->BSIM4grbpd + + here->BSIM4grbdb); + (*(here->BSIM4DBbpPtr) -= here->BSIM4grbpd); + (*(here->BSIM4DBbPtr) -= here->BSIM4grbdb); + + (*(here->BSIM4BPdbPtr) -= here->BSIM4grbpd); + (*(here->BSIM4BPbPtr) -= here->BSIM4grbpb); + (*(here->BSIM4BPsbPtr) -= here->BSIM4grbps); + (*(here->BSIM4BPbpPtr) += here->BSIM4grbpd + here->BSIM4grbps + + here->BSIM4grbpb); + /* WDLiu: (-here->BSIM4gbbs) already added to BPbpPtr */ + + (*(here->BSIM4SBspPtr +1) += xcsbsb); + (*(here->BSIM4SBspPtr) -= here->BSIM4gbs); + (*(here->BSIM4SBbpPtr) -= here->BSIM4grbps); + (*(here->BSIM4SBbPtr) -= here->BSIM4grbsb); + (*(here->BSIM4SBsbPtr +1) -= xcsbsb); + (*(here->BSIM4SBsbPtr) += here->BSIM4gbs + + here->BSIM4grbps + here->BSIM4grbsb); + + (*(here->BSIM4BdbPtr) -= here->BSIM4grbdb); + (*(here->BSIM4BbpPtr) -= here->BSIM4grbpb); + (*(here->BSIM4BsbPtr) -= here->BSIM4grbsb); + (*(here->BSIM4BbPtr) += here->BSIM4grbsb + here->BSIM4grbdb + + here->BSIM4grbpb); + } + + + /* + * WDLiu: The internal charge node generated for transient NQS is not needed for + * AC NQS. The following is not doing a real job, but we have to keep it; + * otherwise a singular AC NQS matrix may occur if the transient NQS is on. + * The charge node is isolated from the instance. + */ + if (here->BSIM4trnqsMod) + { (*(here->BSIM4QqPtr) += 1.0); + (*(here->BSIM4QgpPtr) += 0.0); + (*(here->BSIM4QdpPtr) += 0.0); + (*(here->BSIM4QspPtr) += 0.0); + (*(here->BSIM4QbpPtr) += 0.0); + + (*(here->BSIM4DPqPtr) += 0.0); + (*(here->BSIM4SPqPtr) += 0.0); + (*(here->BSIM4GPqPtr) += 0.0); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4ask.c b/src/spicelib/devices/bsim4/b4ask.c new file mode 100644 index 000000000..9449eff48 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4ask.c @@ -0,0 +1,248 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4ask.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim4def.h" +#include "sperror.h" + +int +BSIM4ask(ckt,inst,which,value,select) +CKTcircuit *ckt; +GENinstance *inst; +int which; +IFvalue *value; +IFvalue *select; +{ +BSIM4instance *here = (BSIM4instance*)inst; + + switch(which) + { case BSIM4_L: + value->rValue = here->BSIM4l; + return(OK); + case BSIM4_W: + value->rValue = here->BSIM4w; + return(OK); + case BSIM4_NF: + value->rValue = here->BSIM4nf; + return(OK); + case BSIM4_MIN: + value->iValue = here->BSIM4min; + return(OK); + case BSIM4_AS: + value->rValue = here->BSIM4sourceArea; + return(OK); + case BSIM4_AD: + value->rValue = here->BSIM4drainArea; + return(OK); + case BSIM4_PS: + value->rValue = here->BSIM4sourcePerimeter; + return(OK); + case BSIM4_PD: + value->rValue = here->BSIM4drainPerimeter; + return(OK); + case BSIM4_NRS: + value->rValue = here->BSIM4sourceSquares; + return(OK); + case BSIM4_NRD: + value->rValue = here->BSIM4drainSquares; + return(OK); + case BSIM4_OFF: + value->rValue = here->BSIM4off; + return(OK); + case BSIM4_RBSB: + value->rValue = here->BSIM4rbsb; + return(OK); + case BSIM4_RBDB: + value->rValue = here->BSIM4rbdb; + return(OK); + case BSIM4_RBPB: + value->rValue = here->BSIM4rbpb; + return(OK); + case BSIM4_RBPS: + value->rValue = here->BSIM4rbps; + return(OK); + case BSIM4_RBPD: + value->rValue = here->BSIM4rbpd; + return(OK); + case BSIM4_TRNQSMOD: + value->iValue = here->BSIM4trnqsMod; + return(OK); + case BSIM4_ACNQSMOD: + value->iValue = here->BSIM4acnqsMod; + return(OK); + case BSIM4_RBODYMOD: + value->iValue = here->BSIM4rbodyMod; + return(OK); + case BSIM4_RGATEMOD: + value->iValue = here->BSIM4rgateMod; + return(OK); + case BSIM4_GEOMOD: + value->iValue = here->BSIM4geoMod; + return(OK); + case BSIM4_RGEOMOD: + value->iValue = here->BSIM4rgeoMod; + return(OK); + case BSIM4_IC_VDS: + value->rValue = here->BSIM4icVDS; + return(OK); + case BSIM4_IC_VGS: + value->rValue = here->BSIM4icVGS; + return(OK); + case BSIM4_IC_VBS: + value->rValue = here->BSIM4icVBS; + return(OK); + case BSIM4_DNODE: + value->iValue = here->BSIM4dNode; + return(OK); + case BSIM4_GNODEEXT: + value->iValue = here->BSIM4gNodeExt; + return(OK); + case BSIM4_SNODE: + value->iValue = here->BSIM4sNode; + return(OK); + case BSIM4_BNODE: + value->iValue = here->BSIM4bNode; + return(OK); + case BSIM4_DNODEPRIME: + value->iValue = here->BSIM4dNodePrime; + return(OK); + case BSIM4_GNODEPRIME: + value->iValue = here->BSIM4gNodePrime; + return(OK); + case BSIM4_GNODEMID: + value->iValue = here->BSIM4gNodeMid; + return(OK); + case BSIM4_SNODEPRIME: + value->iValue = here->BSIM4sNodePrime; + return(OK); + case BSIM4_DBNODE: + value->iValue = here->BSIM4dbNode; + return(OK); + case BSIM4_BNODEPRIME: + value->iValue = here->BSIM4bNodePrime; + return(OK); + case BSIM4_SBNODE: + value->iValue = here->BSIM4sbNode; + return(OK); + case BSIM4_SOURCECONDUCT: + value->rValue = here->BSIM4sourceConductance; + return(OK); + case BSIM4_DRAINCONDUCT: + value->rValue = here->BSIM4drainConductance; + return(OK); + case BSIM4_VBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM4vbd); + return(OK); + case BSIM4_VBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM4vbs); + return(OK); + case BSIM4_VGS: + value->rValue = *(ckt->CKTstate0 + here->BSIM4vgs); + return(OK); + case BSIM4_VDS: + value->rValue = *(ckt->CKTstate0 + here->BSIM4vds); + return(OK); + case BSIM4_CD: + value->rValue = here->BSIM4cd; + return(OK); + case BSIM4_CBS: + value->rValue = here->BSIM4cbs; + return(OK); + case BSIM4_CBD: + value->rValue = here->BSIM4cbd; + return(OK); + case BSIM4_GM: + value->rValue = here->BSIM4gm; + return(OK); + case BSIM4_GDS: + value->rValue = here->BSIM4gds; + return(OK); + case BSIM4_GMBS: + value->rValue = here->BSIM4gmbs; + return(OK); + case BSIM4_GBD: + value->rValue = here->BSIM4gbd; + return(OK); + case BSIM4_GBS: + value->rValue = here->BSIM4gbs; + return(OK); + case BSIM4_QB: + value->rValue = *(ckt->CKTstate0 + here->BSIM4qb); + return(OK); + case BSIM4_CQB: + value->rValue = *(ckt->CKTstate0 + here->BSIM4cqb); + return(OK); + case BSIM4_QG: + value->rValue = *(ckt->CKTstate0 + here->BSIM4qg); + return(OK); + case BSIM4_CQG: + value->rValue = *(ckt->CKTstate0 + here->BSIM4cqg); + return(OK); + case BSIM4_QD: + value->rValue = *(ckt->CKTstate0 + here->BSIM4qd); + return(OK); + case BSIM4_CQD: + value->rValue = *(ckt->CKTstate0 + here->BSIM4cqd); + return(OK); + case BSIM4_CGG: + value->rValue = here->BSIM4cggb; + return(OK); + case BSIM4_CGD: + value->rValue = here->BSIM4cgdb; + return(OK); + case BSIM4_CGS: + value->rValue = here->BSIM4cgsb; + return(OK); + case BSIM4_CDG: + value->rValue = here->BSIM4cdgb; + return(OK); + case BSIM4_CDD: + value->rValue = here->BSIM4cddb; + return(OK); + case BSIM4_CDS: + value->rValue = here->BSIM4cdsb; + return(OK); + case BSIM4_CBG: + value->rValue = here->BSIM4cbgb; + return(OK); + case BSIM4_CBDB: + value->rValue = here->BSIM4cbdb; + return(OK); + case BSIM4_CBSB: + value->rValue = here->BSIM4cbsb; + return(OK); + case BSIM4_CAPBD: + value->rValue = here->BSIM4capbd; + return(OK); + case BSIM4_CAPBS: + value->rValue = here->BSIM4capbs; + return(OK); + case BSIM4_VON: + value->rValue = here->BSIM4von; + return(OK); + case BSIM4_VDSAT: + value->rValue = here->BSIM4vdsat; + return(OK); + case BSIM4_QBS: + value->rValue = *(ckt->CKTstate0 + here->BSIM4qbs); + return(OK); + case BSIM4_QBD: + value->rValue = *(ckt->CKTstate0 + here->BSIM4qbd); + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/bsim4/b4check.c b/src/spicelib/devices/bsim4/b4check.c new file mode 100644 index 000000000..362e9204c --- /dev/null +++ b/src/spicelib/devices/bsim4/b4check.c @@ -0,0 +1,565 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4check.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim4def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" + + +int +BSIM4checkModel(model, here, ckt) +register BSIM4model *model; +register BSIM4instance *here; +CKTcircuit *ckt; +{ +struct bsim4SizeDependParam *pParam; +int Fatal_Flag = 0; +FILE *fplog; + + if ((fplog = fopen("bsim4.out", "w")) != NULL) + { pParam = here->pParam; + fprintf(fplog, "BSIM4: Berkeley Short Channel IGFET Model-4\n"); + fprintf(fplog, "Developed by Dr. Weidong Liu, Xiaodong Jin, Kanyu M. Cao and Prof. Chenming Hu in 2000.\n"); + fprintf(fplog, "\n"); + fprintf(fplog, "++++++++++ BSIM4 PARAMETER CHECKING BELOW ++++++++++\n"); + + if (strcmp(model->BSIM4version, "4.0.0") != 0) + { fprintf(fplog, "Warning: This model is BSIM4.0.0; you specified a wrong version number.\n"); + printf("Warning: This model is BSIM4.0.0; you specified a wrong version number.\n"); + } + fprintf(fplog, "Model = %s\n", model->BSIM4modName); + + + if ((here->BSIM4rgateMod == 2) || (here->BSIM4rgateMod == 3)) + { if ((here->BSIM4trnqsMod == 1) || (here->BSIM4acnqsMod == 1)) + fprintf(fplog, "Warning: You've selected both Rg and charge deficit NQS; select one only.\n"); + printf("Warning: You've selected both Rg and charge deficit NQS; select one only.\n"); + } + + + if (model->BSIM4toxe <= 0.0) + { fprintf(fplog, "Fatal: Toxe = %g is not positive.\n", + model->BSIM4toxe); + printf("Fatal: Toxe = %g is not positive.\n", model->BSIM4toxe); + Fatal_Flag = 1; + } + if (model->BSIM4toxp <= 0.0) + { fprintf(fplog, "Fatal: Toxp = %g is not positive.\n", + model->BSIM4toxp); + printf("Fatal: Toxp = %g is not positive.\n", model->BSIM4toxp); + Fatal_Flag = 1; + } + + if (model->BSIM4toxm <= 0.0) + { fprintf(fplog, "Fatal: Toxm = %g is not positive.\n", + model->BSIM4toxm); + printf("Fatal: Toxm = %g is not positive.\n", model->BSIM4toxm); + Fatal_Flag = 1; + } + + if (model->BSIM4toxref <= 0.0) + { fprintf(fplog, "Fatal: Toxref = %g is not positive.\n", + model->BSIM4toxref); + printf("Fatal: Toxref = %g is not positive.\n", model->BSIM4toxref); + Fatal_Flag = 1; + } + + if (pParam->BSIM4lpe0 < -pParam->BSIM4leff) + { fprintf(fplog, "Fatal: Lpe0 = %g is less than -Leff.\n", + pParam->BSIM4lpe0); + printf("Fatal: Lpe0 = %g is less than -Leff.\n", + pParam->BSIM4lpe0); + Fatal_Flag = 1; + } + if (pParam->BSIM4lpeb < -pParam->BSIM4leff) + { fprintf(fplog, "Fatal: Lpeb = %g is less than -Leff.\n", + pParam->BSIM4lpeb); + printf("Fatal: Lpeb = %g is less than -Leff.\n", + pParam->BSIM4lpeb); + Fatal_Flag = 1; + } + + if (pParam->BSIM4phin < -0.4) + { fprintf(fplog, "Fatal: Phin = %g is less than -0.4.\n", + pParam->BSIM4phin); + printf("Fatal: Phin = %g is less than -0.4.\n", + pParam->BSIM4phin); + Fatal_Flag = 1; + } + if (pParam->BSIM4ndep <= 0.0) + { fprintf(fplog, "Fatal: Ndep = %g is not positive.\n", + pParam->BSIM4ndep); + printf("Fatal: Ndep = %g is not positive.\n", + pParam->BSIM4ndep); + Fatal_Flag = 1; + } + if (pParam->BSIM4nsub <= 0.0) + { fprintf(fplog, "Fatal: Nsub = %g is not positive.\n", + pParam->BSIM4nsub); + printf("Fatal: Nsub = %g is not positive.\n", + pParam->BSIM4nsub); + Fatal_Flag = 1; + } + if (pParam->BSIM4ngate < 0.0) + { fprintf(fplog, "Fatal: Ngate = %g is not positive.\n", + pParam->BSIM4ngate); + printf("Fatal: Ngate = %g Ngate is not positive.\n", + pParam->BSIM4ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM4ngate > 1.e25) + { fprintf(fplog, "Fatal: Ngate = %g is too high.\n", + pParam->BSIM4ngate); + printf("Fatal: Ngate = %g Ngate is too high\n", + pParam->BSIM4ngate); + Fatal_Flag = 1; + } + if (pParam->BSIM4xj <= 0.0) + { fprintf(fplog, "Fatal: Xj = %g is not positive.\n", + pParam->BSIM4xj); + printf("Fatal: Xj = %g is not positive.\n", pParam->BSIM4xj); + Fatal_Flag = 1; + } + + if (pParam->BSIM4dvt1 < 0.0) + { fprintf(fplog, "Fatal: Dvt1 = %g is negative.\n", + pParam->BSIM4dvt1); + printf("Fatal: Dvt1 = %g is negative.\n", pParam->BSIM4dvt1); + Fatal_Flag = 1; + } + + if (pParam->BSIM4dvt1w < 0.0) + { fprintf(fplog, "Fatal: Dvt1w = %g is negative.\n", + pParam->BSIM4dvt1w); + printf("Fatal: Dvt1w = %g is negative.\n", pParam->BSIM4dvt1w); + Fatal_Flag = 1; + } + + if (pParam->BSIM4w0 == -pParam->BSIM4weff) + { fprintf(fplog, "Fatal: (W0 + Weff) = 0 causing divided-by-zero.\n"); + printf("Fatal: (W0 + Weff) = 0 causing divided-by-zero.\n"); + Fatal_Flag = 1; + } + + if (pParam->BSIM4dsub < 0.0) + { fprintf(fplog, "Fatal: Dsub = %g is negative.\n", pParam->BSIM4dsub); + printf("Fatal: Dsub = %g is negative.\n", pParam->BSIM4dsub); + Fatal_Flag = 1; + } + if (pParam->BSIM4b1 == -pParam->BSIM4weff) + { fprintf(fplog, "Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + printf("Fatal: (B1 + Weff) = 0 causing divided-by-zero.\n"); + Fatal_Flag = 1; + } + if (pParam->BSIM4u0temp <= 0.0) + { fprintf(fplog, "Fatal: u0 at current temperature = %g is not positive.\n", pParam->BSIM4u0temp); + printf("Fatal: u0 at current temperature = %g is not positive.\n", + pParam->BSIM4u0temp); + Fatal_Flag = 1; + } + + if (pParam->BSIM4delta < 0.0) + { fprintf(fplog, "Fatal: Delta = %g is less than zero.\n", + pParam->BSIM4delta); + printf("Fatal: Delta = %g is less than zero.\n", pParam->BSIM4delta); + Fatal_Flag = 1; + } + + if (pParam->BSIM4vsattemp <= 0.0) + { fprintf(fplog, "Fatal: Vsat at current temperature = %g is not positive.\n", pParam->BSIM4vsattemp); + printf("Fatal: Vsat at current temperature = %g is not positive.\n", + pParam->BSIM4vsattemp); + Fatal_Flag = 1; + } + + if (pParam->BSIM4pclm <= 0.0) + { fprintf(fplog, "Fatal: Pclm = %g is not positive.\n", pParam->BSIM4pclm); + printf("Fatal: Pclm = %g is not positive.\n", pParam->BSIM4pclm); + Fatal_Flag = 1; + } + + if (pParam->BSIM4drout < 0.0) + { fprintf(fplog, "Fatal: Drout = %g is negative.\n", pParam->BSIM4drout); + printf("Fatal: Drout = %g is negative.\n", pParam->BSIM4drout); + Fatal_Flag = 1; + } + + if (pParam->BSIM4pscbe2 <= 0.0) + { fprintf(fplog, "Warning: Pscbe2 = %g is not positive.\n", + pParam->BSIM4pscbe2); + printf("Warning: Pscbe2 = %g is not positive.\n", pParam->BSIM4pscbe2); + } + + if (here->BSIM4nf < 1.0) + { fprintf(fplog, "Fatal: Number of finger = %g is smaller than one.\n", here->BSIM4nf); + printf("Fatal: Number of finger = %g is smaller than one.\n", here->BSIM4nf); + Fatal_Flag = 1; + } + if (here->BSIM4nf > 500.0) + { here->BSIM4nf = 20.0; + fprintf(fplog, "Warning: Nf = %g is too large; reset to 20.0.\n", here->BSIM4nf); + printf("Warning: Nf = %g is too large; reset to 20.0.\n", here->BSIM4nf); + } + + if (here->BSIM4l <= model->BSIM4xgl) + { fprintf(fplog, "Fatal: The parameter xgl must be smaller than Ldrawn.\n"); + printf("Fatal: The parameter xgl must be smaller than Ldrawn.\n"); + Fatal_Flag = 1; + } + if (model->BSIM4ngcon < 1.0) + { fprintf(fplog, "Fatal: The parameter ngcon cannot be smaller than one.\n"); + printf("Fatal: The parameter ngcon cannot be smaller than one.\n"); + Fatal_Flag = 1; + } + if ((model->BSIM4ngcon != 1.0) && (model->BSIM4ngcon != 2.0)) + { model->BSIM4ngcon = 1.0; + fprintf(fplog, "Warning: Ngcon must be equal to one or two; reset to 1.0.\n"); + printf("Warning: Ngcon must be equal to one or two; reset to 1.0.\n"); + } + + if (model->BSIM4gbmin < 1.0e-20) + { fprintf(fplog, "Warning: Gbmin = %g is too small.\n", + model->BSIM4gbmin); + printf("Warning: Gbmin = %g is too small.\n", model->BSIM4gbmin); + } + + if (pParam->BSIM4noff < 0.1) + { fprintf(fplog, "Warning: Noff = %g is too small.\n", + pParam->BSIM4noff); + printf("Warning: Noff = %g is too small.\n", pParam->BSIM4noff); + } + if (pParam->BSIM4noff > 4.0) + { fprintf(fplog, "Warning: Noff = %g is too large.\n", + pParam->BSIM4noff); + printf("Warning: Noff = %g is too large.\n", pParam->BSIM4noff); + } + + if (pParam->BSIM4voffcv < -0.5) + { fprintf(fplog, "Warning: Voffcv = %g is too small.\n", + pParam->BSIM4voffcv); + printf("Warning: Voffcv = %g is too small.\n", pParam->BSIM4voffcv); + } + if (pParam->BSIM4voffcv > 0.5) + { fprintf(fplog, "Warning: Voffcv = %g is too large.\n", + pParam->BSIM4voffcv); + printf("Warning: Voffcv = %g is too large.\n", pParam->BSIM4voffcv); + } + + /* Check capacitance parameters */ + if (pParam->BSIM4clc < 0.0) + { fprintf(fplog, "Fatal: Clc = %g is negative.\n", pParam->BSIM4clc); + printf("Fatal: Clc = %g is negative.\n", pParam->BSIM4clc); + Fatal_Flag = 1; + } + + if (pParam->BSIM4moin < 5.0) + { fprintf(fplog, "Warning: Moin = %g is too small.\n", + pParam->BSIM4moin); + printf("Warning: Moin = %g is too small.\n", pParam->BSIM4moin); + } + if (pParam->BSIM4moin > 25.0) + { fprintf(fplog, "Warning: Moin = %g is too large.\n", + pParam->BSIM4moin); + printf("Warning: Moin = %g is too large.\n", pParam->BSIM4moin); + } + + if (pParam->BSIM4acde < 0.4) + { fprintf(fplog, "Warning: Acde = %g is too small.\n", + pParam->BSIM4acde); + printf("Warning: Acde = %g is too small.\n", pParam->BSIM4acde); + } + if (pParam->BSIM4acde > 1.6) + { fprintf(fplog, "Warning: Acde = %g is too large.\n", + pParam->BSIM4acde); + printf("Warning: Acde = %g is too large.\n", pParam->BSIM4acde); + } + + if (model->BSIM4paramChk ==1) + { +/* Check L and W parameters */ + if (pParam->BSIM4leff <= 5.0e-8) + { fprintf(fplog, "Warning: Leff = %g may be too small.\n", + pParam->BSIM4leff); + printf("Warning: Leff = %g may be too small.\n", + pParam->BSIM4leff); + } + + if (pParam->BSIM4leffCV <= 5.0e-8) + { fprintf(fplog, "Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM4leffCV); + printf("Warning: Leff for CV = %g may be too small.\n", + pParam->BSIM4leffCV); + } + + if (pParam->BSIM4weff <= 1.0e-7) + { fprintf(fplog, "Warning: Weff = %g may be too small.\n", + pParam->BSIM4weff); + printf("Warning: Weff = %g may be too small.\n", + pParam->BSIM4weff); + } + + if (pParam->BSIM4weffCV <= 1.0e-7) + { fprintf(fplog, "Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM4weffCV); + printf("Warning: Weff for CV = %g may be too small.\n", + pParam->BSIM4weffCV); + } + + /* Check threshold voltage parameters */ + if (model->BSIM4toxe < 1.0e-9) + { fprintf(fplog, "Warning: Toxe = %g is less than 10A.\n", + model->BSIM4toxe); + printf("Warning: Toxe = %g is less than 10A.\n", model->BSIM4toxe); + } + if (model->BSIM4toxp < 1.0e-9) + { fprintf(fplog, "Warning: Toxp = %g is less than 10A.\n", + model->BSIM4toxp); + printf("Warning: Toxp = %g is less than 10A.\n", model->BSIM4toxp); + } + if (model->BSIM4toxm < 1.0e-9) + { fprintf(fplog, "Warning: Toxm = %g is less than 10A.\n", + model->BSIM4toxm); + printf("Warning: Toxm = %g is less than 10A.\n", model->BSIM4toxm); + } + + if (pParam->BSIM4ndep <= 1.0e12) + { fprintf(fplog, "Warning: Ndep = %g may be too small.\n", + pParam->BSIM4ndep); + printf("Warning: Ndep = %g may be too small.\n", + pParam->BSIM4ndep); + } + else if (pParam->BSIM4ndep >= 1.0e21) + { fprintf(fplog, "Warning: Ndep = %g may be too large.\n", + pParam->BSIM4ndep); + printf("Warning: Ndep = %g may be too large.\n", + pParam->BSIM4ndep); + } + + if (pParam->BSIM4nsub <= 1.0e14) + { fprintf(fplog, "Warning: Nsub = %g may be too small.\n", + pParam->BSIM4nsub); + printf("Warning: Nsub = %g may be too small.\n", + pParam->BSIM4nsub); + } + else if (pParam->BSIM4nsub >= 1.0e21) + { fprintf(fplog, "Warning: Nsub = %g may be too large.\n", + pParam->BSIM4nsub); + printf("Warning: Nsub = %g may be too large.\n", + pParam->BSIM4nsub); + } + + if ((pParam->BSIM4ngate > 0.0) && + (pParam->BSIM4ngate <= 1.e18)) + { fprintf(fplog, "Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM4ngate); + printf("Warning: Ngate = %g is less than 1.E18cm^-3.\n", + pParam->BSIM4ngate); + } + + if (pParam->BSIM4dvt0 < 0.0) + { fprintf(fplog, "Warning: Dvt0 = %g is negative.\n", + pParam->BSIM4dvt0); + printf("Warning: Dvt0 = %g is negative.\n", pParam->BSIM4dvt0); + } + + if (fabs(1.0e-6 / (pParam->BSIM4w0 + pParam->BSIM4weff)) > 10.0) + { fprintf(fplog, "Warning: (W0 + Weff) may be too small.\n"); + printf("Warning: (W0 + Weff) may be too small.\n"); + } + +/* Check subthreshold parameters */ + if (pParam->BSIM4nfactor < 0.0) + { fprintf(fplog, "Warning: Nfactor = %g is negative.\n", + pParam->BSIM4nfactor); + printf("Warning: Nfactor = %g is negative.\n", pParam->BSIM4nfactor); + } + if (pParam->BSIM4cdsc < 0.0) + { fprintf(fplog, "Warning: Cdsc = %g is negative.\n", + pParam->BSIM4cdsc); + printf("Warning: Cdsc = %g is negative.\n", pParam->BSIM4cdsc); + } + if (pParam->BSIM4cdscd < 0.0) + { fprintf(fplog, "Warning: Cdscd = %g is negative.\n", + pParam->BSIM4cdscd); + printf("Warning: Cdscd = %g is negative.\n", pParam->BSIM4cdscd); + } +/* Check DIBL parameters */ + if (pParam->BSIM4eta0 < 0.0) + { fprintf(fplog, "Warning: Eta0 = %g is negative.\n", + pParam->BSIM4eta0); + printf("Warning: Eta0 = %g is negative.\n", pParam->BSIM4eta0); + } + +/* Check Abulk parameters */ + if (fabs(1.0e-6 / (pParam->BSIM4b1 + pParam->BSIM4weff)) > 10.0) + { fprintf(fplog, "Warning: (B1 + Weff) may be too small.\n"); + printf("Warning: (B1 + Weff) may be too small.\n"); + } + + +/* Check Saturation parameters */ + if (pParam->BSIM4a2 < 0.01) + { fprintf(fplog, "Warning: A2 = %g is too small. Set to 0.01.\n", pParam->BSIM4a2); + printf("Warning: A2 = %g is too small. Set to 0.01.\n", + pParam->BSIM4a2); + pParam->BSIM4a2 = 0.01; + } + else if (pParam->BSIM4a2 > 1.0) + { fprintf(fplog, "Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM4a2); + printf("Warning: A2 = %g is larger than 1. A2 is set to 1 and A1 is set to 0.\n", + pParam->BSIM4a2); + pParam->BSIM4a2 = 1.0; + pParam->BSIM4a1 = 0.0; + + } + + if (pParam->BSIM4prwg < 0.0) + { fprintf(fplog, "Warning: Prwg = %g is negative. Set to zero.\n", + pParam->BSIM4prwg); + printf("Warning: Prwg = %g is negative. Set to zero.\n", + pParam->BSIM4prwg); + pParam->BSIM4prwg = 0.0; + } + if (pParam->BSIM4rdsw < 0.0) + { fprintf(fplog, "Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM4rdsw); + printf("Warning: Rdsw = %g is negative. Set to zero.\n", + pParam->BSIM4rdsw); + pParam->BSIM4rdsw = 0.0; + pParam->BSIM4rds0 = 0.0; + } + if (pParam->BSIM4rds0 < 0.0) + { fprintf(fplog, "Warning: Rds at current temperature = %g is negative. Set to zero.\n", + pParam->BSIM4rds0); + printf("Warning: Rds at current temperature = %g is negative. Set to zero.\n", + pParam->BSIM4rds0); + pParam->BSIM4rds0 = 0.0; + } + + if (pParam->BSIM4rdswmin < 0.0) + { fprintf(fplog, "Warning: Rdswmin at current temperature = %g is negative. Set to zero.\n", + pParam->BSIM4rdswmin); + printf("Warning: Rdswmin at current temperature = %g is negative. Set to zero.\n", + pParam->BSIM4rdswmin); + pParam->BSIM4rdswmin = 0.0; + } + + if (pParam->BSIM4vsattemp < 1.0e3) + { fprintf(fplog, "Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM4vsattemp); + printf("Warning: Vsat at current temperature = %g may be too small.\n", pParam->BSIM4vsattemp); + } + + if (pParam->BSIM4fprout < 0.0) + { fprintf(fplog, "Fatal: fprout = %g is negative.\n", + pParam->BSIM4fprout); + printf("Fatal: fprout = %g is negative.\n", pParam->BSIM4fprout); + Fatal_Flag = 1; + } + if (pParam->BSIM4pdits < 0.0) + { fprintf(fplog, "Fatal: pdits = %g is negative.\n", + pParam->BSIM4pdits); + printf("Fatal: pdits = %g is negative.\n", pParam->BSIM4pdits); + Fatal_Flag = 1; + } + if (model->BSIM4pditsl < 0.0) + { fprintf(fplog, "Fatal: pditsl = %g is negative.\n", + model->BSIM4pditsl); + printf("Fatal: pditsl = %g is negative.\n", model->BSIM4pditsl); + Fatal_Flag = 1; + } + + if (pParam->BSIM4pdibl1 < 0.0) + { fprintf(fplog, "Warning: Pdibl1 = %g is negative.\n", + pParam->BSIM4pdibl1); + printf("Warning: Pdibl1 = %g is negative.\n", pParam->BSIM4pdibl1); + } + if (pParam->BSIM4pdibl2 < 0.0) + { fprintf(fplog, "Warning: Pdibl2 = %g is negative.\n", + pParam->BSIM4pdibl2); + printf("Warning: Pdibl2 = %g is negative.\n", pParam->BSIM4pdibl2); + } + + if (pParam->BSIM4nigbinv <= 0.0) + { fprintf(fplog, "Fatal: nigbinv = %g is non-positive.\n", + pParam->BSIM4nigbinv); + printf("Fatal: nigbinv = %g is non-positive.\n", pParam->BSIM4nigbinv); + Fatal_Flag = 1; + } + if (pParam->BSIM4nigbacc <= 0.0) + { fprintf(fplog, "Fatal: nigbacc = %g is non-positive.\n", + pParam->BSIM4nigbacc); + printf("Fatal: nigbacc = %g is non-positive.\n", pParam->BSIM4nigbacc); + Fatal_Flag = 1; + } + if (pParam->BSIM4nigc <= 0.0) + { fprintf(fplog, "Fatal: nigc = %g is non-positive.\n", + pParam->BSIM4nigc); + printf("Fatal: nigc = %g is non-positive.\n", pParam->BSIM4nigc); + Fatal_Flag = 1; + } + if (pParam->BSIM4poxedge <= 0.0) + { fprintf(fplog, "Fatal: poxedge = %g is non-positive.\n", + pParam->BSIM4poxedge); + printf("Fatal: poxedge = %g is non-positive.\n", pParam->BSIM4poxedge); + Fatal_Flag = 1; + } + if (pParam->BSIM4pigcd <= 0.0) + { fprintf(fplog, "Fatal: pigcd = %g is non-positive.\n", + pParam->BSIM4pigcd); + printf("Fatal: pigcd = %g is non-positive.\n", pParam->BSIM4pigcd); + Fatal_Flag = 1; + } + + +/* Check overlap capacitance parameters */ + if (model->BSIM4cgdo < 0.0) + { fprintf(fplog, "Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM4cgdo); + printf("Warning: cgdo = %g is negative. Set to zero.\n", model->BSIM4cgdo); + model->BSIM4cgdo = 0.0; + } + if (model->BSIM4cgso < 0.0) + { fprintf(fplog, "Warning: cgso = %g is negative. Set to zero.\n", model->BSIM4cgso); + printf("Warning: cgso = %g is negative. Set to zero.\n", model->BSIM4cgso); + model->BSIM4cgso = 0.0; + } + + if (model->BSIM4tnoia < 0.0) + { fprintf(fplog, "Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia); + printf("Warning: tnoia = %g is negative. Set to zero.\n", model->BSIM4tnoia); + model->BSIM4tnoia = 0.0; + } + if (model->BSIM4tnoib < 0.0) + { fprintf(fplog, "Warning: tnoib = %g is negative. Set to zero.\n", model->BSIM4tnoib); + printf("Warning: tnoib = %g is negative. Set to zero.\n", model->BSIM4tnoib); + model->BSIM4tnoib = 0.0; + } + + if (model->BSIM4ntnoi < 0.0) + { fprintf(fplog, "Warning: ntnoi = %g is negative. Set to zero.\n", model->BSIM4ntnoi); + printf("Warning: ntnoi = %g is negative. Set to zero.\n", model->BSIM4ntnoi); + model->BSIM4ntnoi = 0.0; + } + + }/* loop for the parameter check for warning messages */ + fclose(fplog); + } + else + { fprintf(stderr, "Warning: Can't open log file. Parameter checking skipped.\n"); + } + + return(Fatal_Flag); +} + diff --git a/src/spicelib/devices/bsim4/b4cvtest.c b/src/spicelib/devices/bsim4/b4cvtest.c new file mode 100644 index 000000000..512c9e1bd --- /dev/null +++ b/src/spicelib/devices/bsim4/b4cvtest.c @@ -0,0 +1,193 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4cvtest.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim4def.h" +#include "trandefs.h" +#include "const.h" +#include "devdefs.h" +#include "sperror.h" + + +int +BSIM4convTest(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM4model *model = (BSIM4model*)inModel; +register BSIM4instance *here; +double delvbd, delvbs, delvds, delvgd, delvgs; +double delvdbd, delvsbs; +double delvbd_jct, delvbs_jct; +double vds, vgs, vgd, vgdo, vbs, vbd; +double vdbd, vdbs, vsbs; +double cbhat, cdhat, Idtot, Ibtot; +double vses, vdes, vdedo, delvses, delvded, delvdes; +double Isestot, cseshat, Idedtot, cdedhat; +double Igstot, cgshat, Igdtot, cgdhat, Igbtot, cgbhat; +double tol0, tol1, tol2, tol3, tol4, tol5, tol6; + + for (; model != NULL; model = model->BSIM4nextModel) + { for (here = model->BSIM4instances; here != NULL ; + here=here->BSIM4nextInstance) + { + if (here->BSIM4owner != ARCHme) continue; + vds = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4dNodePrime) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vgs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4gNodePrime) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vbs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4bNodePrime) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vdbs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4dbNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vsbs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4sbNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vses = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4sNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vdes = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4dNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + + vgdo = *(ckt->CKTstate0 + here->BSIM4vgs) + - *(ckt->CKTstate0 + here->BSIM4vds); + vbd = vbs - vds; + vdbd = vdbs - vds; + vgd = vgs - vds; + + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM4vbd); + delvdbd = vdbd - *(ckt->CKTstate0 + here->BSIM4vdbd); + delvgd = vgd - vgdo; + + delvds = vds - *(ckt->CKTstate0 + here->BSIM4vds); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM4vgs); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM4vbs); + delvsbs = vsbs - *(ckt->CKTstate0 + here->BSIM4vsbs); + + delvses = vses - (*(ckt->CKTstate0 + here->BSIM4vses)); + vdedo = *(ckt->CKTstate0 + here->BSIM4vdes) + - *(ckt->CKTstate0 + here->BSIM4vds); + delvdes = vdes - *(ckt->CKTstate0 + here->BSIM4vdes); + delvded = vdes - vds - vdedo; + + delvbd_jct = (!here->BSIM4rbodyMod) ? delvbd : delvdbd; + delvbs_jct = (!here->BSIM4rbodyMod) ? delvbs : delvsbs; + + if (here->BSIM4mode >= 0) + { Idtot = here->BSIM4cd + here->BSIM4csub - here->BSIM4cbd + + here->BSIM4Igidl; + cdhat = Idtot - here->BSIM4gbd * delvbd_jct + + (here->BSIM4gmbs + here->BSIM4gbbs + here->BSIM4ggidlb) * delvbs + + (here->BSIM4gm + here->BSIM4gbgs + here->BSIM4ggidlg) * delvgs + + (here->BSIM4gds + here->BSIM4gbds + here->BSIM4ggidld) * delvds; + + Igstot = here->BSIM4Igs + here->BSIM4Igcs; + cgshat = Igstot + (here->BSIM4gIgsg + here->BSIM4gIgcsg) * delvgs + + here->BSIM4gIgcsd * delvds + here->BSIM4gIgcsb * delvbs; + + Igdtot = here->BSIM4Igd + here->BSIM4Igcd; + cgdhat = Igdtot + here->BSIM4gIgdg * delvgd + here->BSIM4gIgcdg * delvgs + + here->BSIM4gIgcdd * delvds + here->BSIM4gIgcdb * delvbs; + + Igbtot = here->BSIM4Igb; + cgbhat = here->BSIM4Igb + here->BSIM4gIgbg * delvgs + here->BSIM4gIgbd + * delvds + here->BSIM4gIgbb * delvbs; + } + else + { Idtot = here->BSIM4cd + here->BSIM4cbd; + cdhat = Idtot + here->BSIM4gbd * delvbd_jct + here->BSIM4gmbs + * delvbd + here->BSIM4gm * delvgd + - here->BSIM4gds * delvds; + + Igstot = here->BSIM4Igs + here->BSIM4Igcd; + cgshat = Igstot + here->BSIM4gIgsg * delvgs + here->BSIM4gIgcdg * delvgd + - here->BSIM4gIgcdd * delvds + here->BSIM4gIgcdb * delvbd; + + Igdtot = here->BSIM4Igd + here->BSIM4Igcs; + cgdhat = Igdtot + (here->BSIM4gIgdg + here->BSIM4gIgcsg) * delvgd + - here->BSIM4gIgcsd * delvds + here->BSIM4gIgcsb * delvbd; + + Igbtot = here->BSIM4Igb; + cgbhat = here->BSIM4Igb + here->BSIM4gIgbg * delvgd - here->BSIM4gIgbd + * delvds + here->BSIM4gIgbb * delvbd; + } + + Isestot = here->BSIM4gstot * (*(ckt->CKTstate0 + here->BSIM4vses)); + cseshat = Isestot + here->BSIM4gstot * delvses + + here->BSIM4gstotd * delvds + here->BSIM4gstotg * delvgs + + here->BSIM4gstotb * delvbs; + + Idedtot = here->BSIM4gdtot * vdedo; + cdedhat = Idedtot + here->BSIM4gdtot * delvded + + here->BSIM4gdtotd * delvds + here->BSIM4gdtotg * delvgs + + here->BSIM4gdtotb * delvbs; + + /* + * Check convergence + */ + + if ((here->BSIM4off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { tol0 = ckt->CKTreltol * MAX(fabs(cdhat), fabs(Idtot)) + + ckt->CKTabstol; + tol1 = ckt->CKTreltol * MAX(fabs(cseshat), fabs(Isestot)) + + ckt->CKTabstol; + tol2 = ckt->CKTreltol * MAX(fabs(cdedhat), fabs(Idedtot)) + + ckt->CKTabstol; + tol3 = ckt->CKTreltol * MAX(fabs(cgshat), fabs(Igstot)) + + ckt->CKTabstol; + tol4 = ckt->CKTreltol * MAX(fabs(cgdhat), fabs(Igdtot)) + + ckt->CKTabstol; + tol5 = ckt->CKTreltol * MAX(fabs(cgbhat), fabs(Igbtot)) + + ckt->CKTabstol; + + if ((fabs(cdhat - Idtot) >= tol0) || (fabs(cseshat - Isestot) >= tol1) + || (fabs(cdedhat - Idedtot) >= tol2)) + { ckt->CKTnoncon++; + return(OK); + } + + if ((fabs(cgshat - Igstot) >= tol3) || (fabs(cgdhat - Igdtot) >= tol4) + || (fabs(cgbhat - Igbtot) >= tol5)) + { ckt->CKTnoncon++; + return(OK); + } + + Ibtot = here->BSIM4cbs + here->BSIM4cbd + - here->BSIM4Igidl - here->BSIM4csub; + if (here->BSIM4mode >= 0) + { cbhat = Ibtot + here->BSIM4gbd * delvbd_jct + + here->BSIM4gbs * delvbs_jct - (here->BSIM4gbbs + here->BSIM4ggidlb) + * delvbs - (here->BSIM4gbgs + here->BSIM4ggidlg) * delvgs + - (here->BSIM4gbds + here->BSIM4ggidld) * delvds; + } + else + { cbhat = Ibtot + here->BSIM4gbs * delvbs_jct + here->BSIM4gbd + * delvbd_jct - (here->BSIM4gbbs + here->BSIM4ggidlb) * delvbd + - (here->BSIM4gbgs + here->BSIM4ggidlg) * delvgd + + (here->BSIM4gbds + here->BSIM4ggidld) * delvds; + } + tol6 = ckt->CKTreltol * MAX(fabs(cbhat), + fabs(Ibtot)) + ckt->CKTabstol; + if (fabs(cbhat - Ibtot) > tol6) + { ckt->CKTnoncon++; + return(OK); + } + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4del.c b/src/spicelib/devices/bsim4/b4del.c new file mode 100644 index 000000000..ef326a86d --- /dev/null +++ b/src/spicelib/devices/bsim4/b4del.c @@ -0,0 +1,40 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4del.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "bsim4def.h" +#include "sperror.h" +#include "gendefs.h" + + +int +BSIM4delete(inModel,name,inInst) +GENmodel *inModel; +IFuid name; +GENinstance **inInst; +{ +BSIM4instance **fast = (BSIM4instance**)inInst; +BSIM4model *model = (BSIM4model*)inModel; +BSIM4instance **prev = NULL; +BSIM4instance *here; + + for (; model ; model = model->BSIM4nextModel) + { prev = &(model->BSIM4instances); + for (here = *prev; here ; here = *prev) + { if (here->BSIM4name == name || (fast && here==*fast)) + { *prev= here->BSIM4nextInstance; + FREE(here); + return(OK); + } + prev = &(here->BSIM4nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/bsim4/b4dest.c b/src/spicelib/devices/bsim4/b4dest.c new file mode 100644 index 000000000..ae96f883f --- /dev/null +++ b/src/spicelib/devices/bsim4/b4dest.c @@ -0,0 +1,37 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4dest.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "bsim4def.h" + +void +BSIM4destroy(inModel) +GENmodel **inModel; +{ +BSIM4model **model = (BSIM4model**)inModel; +BSIM4instance *here; +BSIM4instance *prev = NULL; +BSIM4model *mod = *model; +BSIM4model *oldmod = NULL; + + for (; mod ; mod = mod->BSIM4nextModel) + { if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (BSIM4instance *)NULL; + for (here = mod->BSIM4instances; here; here = here->BSIM4nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; + return; +} diff --git a/src/spicelib/devices/bsim4/b4geo.c b/src/spicelib/devices/bsim4/b4geo.c new file mode 100644 index 000000000..6f1122471 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4geo.c @@ -0,0 +1,380 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4geo.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include + +/* + * WDLiu: + * This subrutine is a special module to process the geometry dependent + * parasitics for BSIM4, which calculates Ps, Pd, As, Ad, and Rs and Rd + * for multi-fingers and varous GEO and RGEO options. + */ + +int +BSIM4NumFingerDiff(nf, minSD, nuIntD, nuEndD, nuIntS, nuEndS) +int minSD; +double nf, *nuIntD, *nuEndD, *nuIntS, *nuEndS; +{ +int NF; + NF = (int)nf; + if ((NF%2) != 0) + { *nuEndD = *nuEndS = 1.0; + *nuIntD = *nuIntS = 2.0 * MAX((nf - 1.0) / 2.0, 0.0); + } + else + { if (minSD == 1) /* minimize # of source */ + { *nuEndD = 2.0; + *nuIntD = 2.0 * MAX((nf / 2.0 - 1.0), 0.0); + *nuEndS = 0.0; + *nuIntS = nf; + } + else + { *nuEndD = 0.0; + *nuIntD = nf; + *nuEndS = 2.0; + *nuIntS = 2.0 * MAX((nf / 2.0 - 1.0), 0.0); + } + } +return 0; +} + + +int +BSIM4PAeffGeo(nf, geo, minSD, Weffcj, DMCG, DMCI, DMDG, Ps, Pd, As, Ad) +int geo, minSD; +double Weffcj, DMCG, DMCI, DMDG; +double nf, *Ps, *Pd, *As, *Ad; +{ +double T0, T1, T2; +double ADiso, ADsha, ADmer, ASiso, ASsha, ASmer; +double PDiso, PDsha, PDmer, PSiso, PSsha, PSmer; +double nuIntD = 0.0, nuEndD = 0.0, nuIntS = 0.0, nuEndS = 0.0; + + if (geo < 9) /* For geo = 9 and 10, the numbers of S/D diffusions already known */ + BSIM4NumFingerDiff(nf, minSD, &nuIntD, &nuEndD, &nuIntS, &nuEndS); + + T0 = DMCG + DMCI; + T1 = DMCG + DMCG; + T2 = DMDG + DMDG; + + PSiso = PDiso = T0 + T0 + Weffcj; + PSsha = PDsha = T1; + PSmer = PDmer = T2; + + ASiso = ADiso = T0 * Weffcj; + ASsha = ADsha = DMCG * Weffcj; + ASmer = ADmer = DMDG * Weffcj; + + switch(geo) + { case 0: + *Ps = nuEndS * PSiso + nuIntS * PSsha; + *Pd = nuEndD * PDiso + nuIntD * PDsha; + *As = nuEndS * ASiso + nuIntS * ASsha; + *Ad = nuEndD * ADiso + nuIntD * ADsha; + break; + case 1: + *Ps = nuEndS * PSiso + nuIntS * PSsha; + *Pd = (nuEndD + nuIntD) * PDsha; + *As = nuEndS * ASiso + nuIntS * ASsha; + *Ad = (nuEndD + nuIntD) * ADsha; + break; + case 2: + *Ps = (nuEndS + nuIntS) * PSsha; + *Pd = nuEndD * PDiso + nuIntD * PDsha; + *As = (nuEndS + nuIntS) * ASsha; + *Ad = nuEndD * ADiso + nuIntD * ADsha; + break; + case 3: + *Ps = (nuEndS + nuIntS) * PSsha; + *Pd = (nuEndD + nuIntD) * PDsha; + *As = (nuEndS + nuIntS) * ASsha; + *Ad = (nuEndD + nuIntD) * ADsha; + break; + case 4: + *Ps = nuEndS * PSiso + nuIntS * PSsha; + *Pd = nuEndD * PDmer + nuIntD * PDsha; + *As = nuEndS * ASiso + nuIntS * ASsha; + *Ad = nuEndD * ADmer + nuIntD * ADsha; + break; + case 5: + *Ps = (nuEndS + nuIntS) * PSsha; + *Pd = nuEndD * PDmer + nuIntD * PDsha; + *As = (nuEndS + nuIntS) * ASsha; + *Ad = nuEndD * ADmer + nuIntD * ADsha; + break; + case 6: + *Ps = nuEndS * PSmer + nuIntS * PSsha; + *Pd = nuEndD * PDiso + nuIntD * PDsha; + *As = nuEndS * ASmer + nuIntS * ASsha; + *Ad = nuEndD * ADiso + nuIntD * ADsha; + break; + case 7: + *Ps = nuEndS * PSmer + nuIntS * PSsha; + *Pd = (nuEndD + nuIntD) * PDsha; + *As = nuEndS * ASmer + nuIntS * ASsha; + *Ad = (nuEndD + nuIntD) * ADsha; + break; + case 8: + *Ps = nuEndS * PSmer + nuIntS * PSsha; + *Pd = nuEndD * PDmer + nuIntD * PDsha; + *As = nuEndS * ASmer + nuIntS * ASsha; + *Ad = nuEndD * ADmer + nuIntD * ADsha; + break; + case 9: /* geo = 9 and 10 happen only when nf = even */ + *Ps = PSiso + (nf - 1.0) * PSsha; + *Pd = nf * PDsha; + *As = ASiso + (nf - 1.0) * ASsha; + *Ad = nf * ADsha; + break; + case 10: + *Ps = nf * PSsha; + *Pd = PDiso + (nf - 1.0) * PDsha; + *As = nf * ASsha; + *Ad = ADiso + (nf - 1.0) * ADsha; + break; + default: + printf("Warning: Specified GEO = %d not matched\n", geo); + } +return 0; +} + + +int +BSIM4RdseffGeo(nf, geo, rgeo, minSD, Weffcj, Rsh, DMCG, DMCI, DMDG, Type, Rtot) +int geo, rgeo, minSD, Type; +double nf, Weffcj, Rsh, DMCG, DMCI, DMDG; +double *Rtot; +{ +double Rint, Rend = 0.0; +double nuIntD = 0.0, nuEndD = 0.0, nuIntS = 0.0, nuEndS = 0.0; + + if (geo < 9) /* since geo = 9 and 10 only happen when nf = even */ + { BSIM4NumFingerDiff(nf, minSD, &nuIntD, &nuEndD, &nuIntS, &nuEndS); + + /* Internal S/D resistance -- assume shared S or D and all wide contacts */ + if (Type == 1) + { if (nuIntS == 0.0) + Rint = 0.0; + else + Rint = Rsh * DMCG / ( Weffcj * nuIntS); + } + else + { if (nuIntD == 0.0) + Rint = 0.0; + else + Rint = Rsh * DMCG / ( Weffcj * nuIntD); + } + } + + /* End S/D resistance -- geo dependent */ + switch(geo) + { case 0: + if (Type == 1) BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndS, rgeo, 1, &Rend); + else BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndD, rgeo, 0, &Rend); + break; + case 1: + if (Type == 1) BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndS, rgeo, 1, &Rend); + else BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndD, rgeo, 0, &Rend); + break; + case 2: + if (Type == 1) BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndS, rgeo, 1, &Rend); + else BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndD, rgeo, 0, &Rend); + break; + case 3: + if (Type == 1) BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndS, rgeo, 1, &Rend); + else BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndD, rgeo, 0, &Rend); + break; + case 4: + if (Type == 1) BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndS, rgeo, 1, &Rend); + else Rend = Rsh * DMDG / Weffcj; + break; + case 5: + if (Type == 1) BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndS, rgeo, 1, &Rend); + else Rend = Rsh * DMDG / (Weffcj * nuEndD); + break; + case 6: + if (Type == 1) Rend = Rsh * DMDG / Weffcj; + else BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndD, rgeo, 0, &Rend); + break; + case 7: + if (Type == 1) Rend = Rsh * DMDG / (Weffcj * nuEndS); + else BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, + nuEndD, rgeo, 0, &Rend); + break; + case 8: + Rend = Rsh * DMDG / Weffcj; + break; + case 9: /* all wide contacts assumed for geo = 9 and 10 */ + if (Type == 1) + { Rend = 0.5 * Rsh * DMCG / Weffcj; + if (nf == 2.0) + Rint = 0.0; + else + Rint = Rsh * DMCG / (Weffcj * (nf - 2.0)); + } + else + { Rend = 0.0; + Rint = Rsh * DMCG / (Weffcj * nf); + } + break; + case 10: + if (Type == 1) + { Rend = 0.0; + Rint = Rsh * DMCG / (Weffcj * nf); + } + else + { Rend = 0.5 * Rsh * DMCG / Weffcj;; + if (nf == 2.0) + Rint = 0.0; + else + Rint = Rsh * DMCG / (Weffcj * (nf - 2.0)); + } + break; + default: + printf("Warning: Specified GEO = %d not matched\n", geo); + } + + if (Rint <= 0.0) + *Rtot = Rend; + else if (Rend <= 0.0) + *Rtot = Rint; + else + *Rtot = Rint * Rend / (Rint + Rend); + +return 0; +} + + +int +BSIM4RdsEndIso(Weffcj, Rsh, DMCG, DMCI, DMDG, nuEnd, rgeo, Type, Rend) +double Weffcj, Rsh, DMCG, DMCI, DMDG; +int rgeo, Type; +double nuEnd, *Rend; +{ + if (Type == 1) + { switch(rgeo) + { case 1: + case 2: + case 5: + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * DMCG / (Weffcj * nuEnd); + break; + case 3: + case 4: + case 6: + if ((DMCG + DMCI) == 0.0) + printf("(DMCG + DMCI) can not be equal to zero\n"); + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * Weffcj / (3.0 * nuEnd * (DMCG + DMCI)); + break; + default: + printf("Warning: Specified RGEO = %d not matched\n", rgeo); + } + } + else + { switch(rgeo) + { case 1: + case 3: + case 7: + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * DMCG / (Weffcj * nuEnd); + break; + case 2: + case 4: + case 8: + if ((DMCG + DMCI) == 0.0) + printf("(DMCG + DMCI) can not be equal to zero\n"); + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * Weffcj / (3.0 * nuEnd * (DMCG + DMCI)); + break; + default: + printf("Warning: Specified RGEO = %d not matched\n", rgeo); + } + } +return 0; +} + + +int +BSIM4RdsEndSha(Weffcj, Rsh, DMCG, DMCI, DMDG, nuEnd, rgeo, Type, Rend) +double Weffcj, Rsh, DMCG, DMCI, DMDG; +int rgeo, Type; +double nuEnd, *Rend; +{ + if (Type == 1) + { switch(rgeo) + { case 1: + case 2: + case 5: + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * DMCG / (Weffcj * nuEnd); + break; + case 3: + case 4: + case 6: + if (DMCG == 0.0) + printf("DMCG can not be equal to zero\n"); + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * Weffcj / (6.0 * nuEnd * DMCG); + break; + default: + printf("Warning: Specified RGEO = %d not matched\n", rgeo); + } + } + else + { switch(rgeo) + { case 1: + case 3: + case 7: + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * DMCG / (Weffcj * nuEnd); + break; + case 2: + case 4: + case 8: + if (DMCG == 0.0) + printf("DMCG can not be equal to zero\n"); + if (nuEnd == 0.0) + *Rend = 0.0; + else + *Rend = Rsh * Weffcj / (6.0 * nuEnd * DMCG); + break; + default: + printf("Warning: Specified RGEO = %d not matched\n", rgeo); + } + } +return 0; +} diff --git a/src/spicelib/devices/bsim4/b4getic.c b/src/spicelib/devices/bsim4/b4getic.c new file mode 100644 index 000000000..2f9e9688c --- /dev/null +++ b/src/spicelib/devices/bsim4/b4getic.c @@ -0,0 +1,44 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4getic.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "bsim4def.h" +#include "sperror.h" + + + +int +BSIM4getic(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +BSIM4model *model = (BSIM4model*)inModel; +BSIM4instance *here; + + for (; model ; model = model->BSIM4nextModel) + { for (here = model->BSIM4instances; here; here = here->BSIM4nextInstance) + { if (here->BSIM4owner != ARCHme) continue; + if (!here->BSIM4icVDSGiven) + { here->BSIM4icVDS = *(ckt->CKTrhs + here->BSIM4dNode) + - *(ckt->CKTrhs + here->BSIM4sNode); + } + if (!here->BSIM4icVGSGiven) + { here->BSIM4icVGS = *(ckt->CKTrhs + here->BSIM4gNodeExt) + - *(ckt->CKTrhs + here->BSIM4sNode); + } + if(!here->BSIM4icVBSGiven) + { here->BSIM4icVBS = *(ckt->CKTrhs + here->BSIM4bNode) + - *(ckt->CKTrhs + here->BSIM4sNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4ld.c b/src/spicelib/devices/bsim4/b4ld.c new file mode 100644 index 000000000..30f81e433 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4ld.c @@ -0,0 +1,4364 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4ld.c of BSIM4.0.0. + * Author: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + ******/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim4def.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "devdefs.h" + + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define EPSSI 1.03594e-10 +#define Charge_q 1.60219e-19 +#define DELTA_1 0.02 +#define DELTA_2 0.02 +#define DELTA_3 0.02 +#define DELTA_4 0.02 + + +int +BSIM4load(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ +register BSIM4model *model = (BSIM4model*)inModel; +register BSIM4instance *here; + +double ceqgstot, dgstot_dvd, dgstot_dvg, dgstot_dvs, dgstot_dvb; +double ceqgdtot, dgdtot_dvd, dgdtot_dvg, dgdtot_dvs, dgdtot_dvb; +double gstot, gstotd, gstotg, gstots, gstotb, gspr, Rs, Rd; +double gdtot, gdtotd, gdtotg, gdtots, gdtotb, gdpr; +double vgs_eff, vgd_eff, dvgs_eff_dvg, dvgd_eff_dvg; +double dRs_dvg, dRd_dvg, dRs_dvb, dRd_dvb; +double dT0_dvg, dT1_dvb, dT3_dvg, dT3_dvb; +double vses, vdes, vdedo, delvses, delvded, delvdes; +double Isestot, cseshat, Idedtot, cdedhat; +double tol0, tol1, tol2, tol3, tol4, tol5, tol6; + +double geltd, gcrg, gcrgg, gcrgd, gcrgs, gcrgb, ceqgcrg; +double vges, vgms, vgedo, vgmdo, vged, vgmd, delvged, delvgmd; +double delvges, delvgms, vgmb; +double gcgmgmb, gcgmdb, gcgmsb, gcdgmb, gcsgmb; +double gcgmbb, gcbgmb, qgmb, qgmid, ceqqgmid; + +double vbd, vbs, vds, vgb, vgd, vgs, vgdo, xfact; +double vdbs, vdbd, vsbs, vsbdo, vsbd; +double delvdbs, delvdbd, delvsbs; +double delvbd_jct, delvbs_jct, vbs_jct, vbd_jct; + +double SourceSatCurrent, DrainSatCurrent; +double ag0, qgd, qgs, qgb, von, cbhat, VgstNVt, ExpVgst; +double ceqqb, ceqqd, ceqqg, ceqqjd, ceqqjs, ceq, geq; +double cdrain, cdhat, ceqdrn, ceqbd, ceqbs, ceqjd, ceqjs, gjbd, gjbs; +double czbd, czbdsw, czbdswg, czbs, czbssw, czbsswg, evbd, evbs, arg, sarg; +double delvbd, delvbs, delvds, delvgd, delvgs; +double Vfbeff, dVfbeff_dVg, dVfbeff_dVb, V3, V4; +double gcbdb, gcbgb, gcbsb, gcddb, gcdgb, gcdsb, gcgdb, gcggb, gcgsb, gcsdb; +double gcgbb, gcdbb, gcsbb, gcbbb; +double gcdbdb, gcsbsb; +double gcsgb, gcssb, MJD, MJSWD, MJSWGD, MJS, MJSWS, MJSWGS; +double qgate, qbulk, qdrn, qsrc, cqgate, cqbody, cqdrn; +double Vdb, Vds, Vgs, Vbs, Gmbs, FwdSum, RevSum; +double Igidl, Ggidld, Ggidlg, Ggidlb; +double Voxacc, dVoxacc_dVg, dVoxacc_dVb; +double Voxdepinv, dVoxdepinv_dVg, dVoxdepinv_dVd, dVoxdepinv_dVb; +double VxNVt, ExpVxNVt, Vaux, dVaux_dVg, dVaux_dVd, dVaux_dVb; +double Igc, dIgc_dVg, dIgc_dVd, dIgc_dVb; +double Igcs, dIgcs_dVg, dIgcs_dVd, dIgcs_dVb; +double Igcd, dIgcd_dVg, dIgcd_dVd, dIgcd_dVb; +double Igs, dIgs_dVg, dIgs_dVs, Igd, dIgd_dVg, dIgd_dVd; +double Igbacc, dIgbacc_dVg, dIgbacc_dVd, dIgbacc_dVb; +double Igbinv, dIgbinv_dVg, dIgbinv_dVd, dIgbinv_dVb; +double Igb, dIgb_dVg, dIgb_dVd, dIgb_dVb; +double Istoteq, gIstotg, gIstotd, gIstots, gIstotb; +double Idtoteq, gIdtotg, gIdtotd, gIdtots, gIdtotb; +double Ibtoteq, gIbtotg, gIbtotd, gIbtots, gIbtotb; +double Igtoteq, gIgtotg, gIgtotd, gIgtots, gIgtotb; +double Igstot, cgshat, Igdtot, cgdhat, Igbtot, cgbhat; +double Vgs_eff, Vfb, dVbs_dVb, Vth_NarrowW; +double Phis, dPhis_dVb, sqrtPhis, dsqrtPhis_dVb, Vth, dVth_dVb, dVth_dVd; +double Vgst, dVgst_dVg, dVgst_dVb, dVgs_eff_dVg, Nvtms, Nvtmd; +double Vgdt, Vgsaddvth, Vgsaddvth2, Vgsaddvth1o3, Vtm; +double n, dn_dVb, dn_dVd, voffcv, noff, dnoff_dVd, dnoff_dVb; +double ExpArg, ExpArg1, V0, CoxWLcen, QovCox, LINK; +double DeltaPhi, dDeltaPhi_dVg; +double Cox, Tox, Tcen, dTcen_dVg, dTcen_dVd, dTcen_dVb; +double Ccen, Coxeff, dCoxeff_dVd, dCoxeff_dVg, dCoxeff_dVb; +double Denomi, dDenomi_dVg, dDenomi_dVd, dDenomi_dVb; +double ueff, dueff_dVg, dueff_dVd, dueff_dVb; +double Esat, dEsat_dVg, dEsat_dVd, dEsat_dVb, Vdsat, Vdsat0; +double EsatL, dEsatL_dVg, dEsatL_dVd, dEsatL_dVb; +double Ilimit, Iexp, dIexp_dVg, dIexp_dVd, dIexp_dVb; +double dVdsat_dVg, dVdsat_dVb, dVdsat_dVd, Vasat, dAlphaz_dVg, dAlphaz_dVb; +double dVasat_dVg, dVasat_dVb, dVasat_dVd, Va, Va2, dVa_dVd, dVa_dVg, dVa_dVb; +double Vbseff, dVbseff_dVb, VbseffCV, dVbseffCV_dVb; +double Arg1, Arg2, One_Third_CoxWL, Two_Third_CoxWL, Alphaz, CoxWL; +double T0, dT0_dVg, dT0_dVd, dT0_dVb; +double T1, dT1_dVg, dT1_dVd, dT1_dVb; +double T2, dT2_dVg, dT2_dVd, dT2_dVb; +double T3, dT3_dVg, dT3_dVd, dT3_dVb; +double T4, dT4_dVg, dT4_dVd, dT4_dVb; +double T5, dT5_dVg, dT5_dVd, dT5_dVb; +double T6, dT6_dVg, dT6_dVd, dT6_dVb; +double T7, dT7_dVg, dT7_dVd, dT7_dVb; +double T8, dT8_dVg, dT8_dVd, dT8_dVb; +double T9, dT9_dVg, dT9_dVd, dT9_dVb; +double T10, dT10_dVg, dT10_dVb, dT10_dVd; +double T11, T12; +double tmp, Abulk, dAbulk_dVb, Abulk0, dAbulk0_dVb; +double Cclm, dCclm_dVg, dCclm_dVd, dCclm_dVb; +double FP, dFP_dVg, PvagTerm, dPvagTerm_dVg, dPvagTerm_dVd, dPvagTerm_dVb; +double VADITS, dVADITS_dVg, dVADITS_dVd; +double Lpe_Vb, DITS_Sft, dDITS_Sft_dVb, dDITS_Sft_dVd; +double VACLM, dVACLM_dVg, dVACLM_dVd, dVACLM_dVb; +double VADIBL, dVADIBL_dVg, dVADIBL_dVd, dVADIBL_dVb; +double Xdep, dXdep_dVb, lt1, dlt1_dVb, ltw, dltw_dVb, Delt_vth, dDelt_vth_dVb; +double Theta0, dTheta0_dVb, Theta1, dTheta1_dVb; +double Thetarout, dThetarout_dVb, TempRatio, tmp1, tmp2, tmp3, tmp4; +double DIBL_Sft, dDIBL_Sft_dVd, DIBL_fact, Lambda, dLambda_dVg; +double Idtot, Ibtot, a1, ScalingFactor; + +double Vgsteff, dVgsteff_dVg, dVgsteff_dVd, dVgsteff_dVb; +double Vdseff, dVdseff_dVg, dVdseff_dVd, dVdseff_dVb; +double VdseffCV, dVdseffCV_dVg, dVdseffCV_dVd, dVdseffCV_dVb; +double diffVds, diffVdsCV, dAbulk_dVg; +double beta, dbeta_dVg, dbeta_dVd, dbeta_dVb; +double gche, dgche_dVg, dgche_dVd, dgche_dVb; +double fgche1, dfgche1_dVg, dfgche1_dVd, dfgche1_dVb; +double fgche2, dfgche2_dVg, dfgche2_dVd, dfgche2_dVb; +double Idl, dIdl_dVg, dIdl_dVd, dIdl_dVb; +double Idsa, dIdsa_dVg, dIdsa_dVd, dIdsa_dVb; +double Ids, Gm, Gds, Gmb, devbs_dvb, devbd_dvb; +double Isub, Gbd, Gbg, Gbb; +double VASCBE, dVASCBE_dVg, dVASCBE_dVd, dVASCBE_dVb; +double CoxeffWovL; +double Rds, dRds_dVg, dRds_dVb, WVCox, WVCoxRds; +double Vgst2Vtm, VdsatCV, dVdsatCV_dVd, dVdsatCV_dVg, dVdsatCV_dVb; +double Leff, Weff, dWeff_dVg, dWeff_dVb; +double AbulkCV, dAbulkCV_dVb; +double qcheq, qdef, gqdef, cqdef, cqcheq; +double gcqdb, gcqsb, gcqgb, gcqbb; +double dxpart, sxpart, ggtg, ggtd, ggts, ggtb; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb, gbspdp; +double gbdpdp, gbdpg, gbdpb, gbdpsp; +double qgdo, qgso, cgdo, cgso, cqbs, cqbd; +double Cgg, Cgd, Cgs, Cgb, Cdg, Cdd, Cds, Cdb, Qg, Qd; +double Csg, Csd, Css, Csb, Cbg, Cbd, Cbs, Cbb, Qs, Qb; +double Cgg1, Cgb1, Cgd1, Cbg1, Cbb1, Cbd1, Csg1, Csd1, Csb1, Qac0, Qsub0; +double dQac0_dVg, dQac0_dVb, dQsub0_dVg, dQsub0_dVd, dQsub0_dVb; + +struct bsim4SizeDependParam *pParam; +int ByPass, ChargeComputationNeeded, error, Check, Check1, Check2; + +ScalingFactor = 1.0e-9; +ChargeComputationNeeded = + ((ckt->CKTmode & (MODEAC | MODETRAN | MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC))) + ? 1 : 0; + + +for (; model != NULL; model = model->BSIM4nextModel) +{ for (here = model->BSIM4instances; here != NULL; + here = here->BSIM4nextInstance) + { + if (here->BSIM4owner != ARCHme) continue; + Check = Check1 = Check2 = 1; + ByPass = 0; + pParam = here->pParam; + + if ((ckt->CKTmode & MODEINITSMSIG)) + { vds = *(ckt->CKTstate0 + here->BSIM4vds); + vgs = *(ckt->CKTstate0 + here->BSIM4vgs); + vbs = *(ckt->CKTstate0 + here->BSIM4vbs); + vges = *(ckt->CKTstate0 + here->BSIM4vges); + vgms = *(ckt->CKTstate0 + here->BSIM4vgms); + vdbs = *(ckt->CKTstate0 + here->BSIM4vdbs); + vsbs = *(ckt->CKTstate0 + here->BSIM4vsbs); + vses = *(ckt->CKTstate0 + here->BSIM4vses); + vdes = *(ckt->CKTstate0 + here->BSIM4vdes); + + qdef = *(ckt->CKTstate0 + here->BSIM4qdef); + } + else if ((ckt->CKTmode & MODEINITTRAN)) + { vds = *(ckt->CKTstate1 + here->BSIM4vds); + vgs = *(ckt->CKTstate1 + here->BSIM4vgs); + vbs = *(ckt->CKTstate1 + here->BSIM4vbs); + vges = *(ckt->CKTstate1 + here->BSIM4vges); + vgms = *(ckt->CKTstate1 + here->BSIM4vgms); + vdbs = *(ckt->CKTstate1 + here->BSIM4vdbs); + vsbs = *(ckt->CKTstate1 + here->BSIM4vsbs); + vses = *(ckt->CKTstate1 + here->BSIM4vses); + vdes = *(ckt->CKTstate1 + here->BSIM4vdes); + + qdef = *(ckt->CKTstate1 + here->BSIM4qdef); + } + else if ((ckt->CKTmode & MODEINITJCT) && !here->BSIM4off) + { vds = model->BSIM4type * here->BSIM4icVDS; + vgs = vges = vgms = model->BSIM4type * here->BSIM4icVGS; + vbs = vdbs = vsbs = model->BSIM4type * here->BSIM4icVBS; + if (vds > 0.0) + { vdes = vds + 0.01; + vses = -0.01; + } + else if (vds < 0.0) + { vdes = vds - 0.01; + vses = 0.01; + } + else + vdes = vses = 0.0; + + qdef = 0.0; + + if ((vds == 0.0) && (vgs == 0.0) && (vbs == 0.0) && + ((ckt->CKTmode & (MODETRAN | MODEAC|MODEDCOP | + MODEDCTRANCURVE)) || (!(ckt->CKTmode & MODEUIC)))) + { vds = 0.1; + vdes = 0.11; + vses = -0.01; + vgs = vges = vgms = model->BSIM4type + * pParam->BSIM4vth0 + 0.1; + vbs = vdbs = vsbs = 0.0; + } + } + else if ((ckt->CKTmode & (MODEINITJCT | MODEINITFIX)) && + (here->BSIM4off)) + { vds = vgs = vbs = vges = vgms = 0.0; + vdbs = vsbs = vdes = vses = qdef = 0.0; + } + else + { +#ifndef PREDICTOR + if ((ckt->CKTmode & MODEINITPRED)) + { xfact = ckt->CKTdelta / ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->BSIM4vds) = + *(ckt->CKTstate1 + here->BSIM4vds); + vds = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vds)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vds))); + *(ckt->CKTstate0 + here->BSIM4vgs) = + *(ckt->CKTstate1 + here->BSIM4vgs); + vgs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vgs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vgs))); + *(ckt->CKTstate0 + here->BSIM4vges) = + *(ckt->CKTstate1 + here->BSIM4vges); + vges = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vges)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vges))); + *(ckt->CKTstate0 + here->BSIM4vgms) = + *(ckt->CKTstate1 + here->BSIM4vgms); + vgms = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vgms)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vgms))); + *(ckt->CKTstate0 + here->BSIM4vbs) = + *(ckt->CKTstate1 + here->BSIM4vbs); + vbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vbs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vbs))); + *(ckt->CKTstate0 + here->BSIM4vbd) = + *(ckt->CKTstate0 + here->BSIM4vbs) + - *(ckt->CKTstate0 + here->BSIM4vds); + *(ckt->CKTstate0 + here->BSIM4vdbs) = + *(ckt->CKTstate1 + here->BSIM4vdbs); + vdbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vdbs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vdbs))); + *(ckt->CKTstate0 + here->BSIM4vdbd) = + *(ckt->CKTstate0 + here->BSIM4vdbs) + - *(ckt->CKTstate0 + here->BSIM4vds); + *(ckt->CKTstate0 + here->BSIM4vsbs) = + *(ckt->CKTstate1 + here->BSIM4vsbs); + vsbs = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vsbs)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vsbs))); + *(ckt->CKTstate0 + here->BSIM4vses) = + *(ckt->CKTstate1 + here->BSIM4vses); + vses = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vses)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vses))); + *(ckt->CKTstate0 + here->BSIM4vdes) = + *(ckt->CKTstate1 + here->BSIM4vdes); + vdes = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4vdes)) + - (xfact * (*(ckt->CKTstate2 + here->BSIM4vdes))); + + *(ckt->CKTstate0 + here->BSIM4qdef) = + *(ckt->CKTstate1 + here->BSIM4qdef); + qdef = (1.0 + xfact)* (*(ckt->CKTstate1 + here->BSIM4qdef)) + -(xfact * (*(ckt->CKTstate2 + here->BSIM4qdef))); + } + else + { +#endif /* PREDICTOR */ + vds = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4dNodePrime) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vgs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4gNodePrime) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vbs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4bNodePrime) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vges = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4gNodeExt) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vgms = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4gNodeMid) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vdbs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4dbNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vsbs = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4sbNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vses = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4sNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + vdes = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4dNode) + - *(ckt->CKTrhsOld + here->BSIM4sNodePrime)); + qdef = model->BSIM4type + * (*(ckt->CKTrhsOld + here->BSIM4qNode)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + + vgdo = *(ckt->CKTstate0 + here->BSIM4vgs) + - *(ckt->CKTstate0 + here->BSIM4vds); + vgedo = *(ckt->CKTstate0 + here->BSIM4vges) + - *(ckt->CKTstate0 + here->BSIM4vds); + vgmdo = *(ckt->CKTstate0 + here->BSIM4vgms) + - *(ckt->CKTstate0 + here->BSIM4vds); + + vbd = vbs - vds; + vdbd = vdbs - vds; + vgd = vgs - vds; + vged = vges - vds; + vgmd = vgms - vds; + + delvbd = vbd - *(ckt->CKTstate0 + here->BSIM4vbd); + delvdbd = vdbd - *(ckt->CKTstate0 + here->BSIM4vdbd); + delvgd = vgd - vgdo; + delvged = vged - vgedo; + delvgmd = vgmd - vgmdo; + + delvds = vds - *(ckt->CKTstate0 + here->BSIM4vds); + delvgs = vgs - *(ckt->CKTstate0 + here->BSIM4vgs); + delvges = vges - *(ckt->CKTstate0 + here->BSIM4vges); + delvgms = vgms - *(ckt->CKTstate0 + here->BSIM4vgms); + delvbs = vbs - *(ckt->CKTstate0 + here->BSIM4vbs); + delvdbs = vdbs - *(ckt->CKTstate0 + here->BSIM4vdbs); + delvsbs = vsbs - *(ckt->CKTstate0 + here->BSIM4vsbs); + + delvses = vses - (*(ckt->CKTstate0 + here->BSIM4vses)); + vdedo = *(ckt->CKTstate0 + here->BSIM4vdes) + - *(ckt->CKTstate0 + here->BSIM4vds); + delvdes = vdes - *(ckt->CKTstate0 + here->BSIM4vdes); + delvded = vdes - vds - vdedo; + + delvbd_jct = (!here->BSIM4rbodyMod) ? delvbd : delvdbd; + delvbs_jct = (!here->BSIM4rbodyMod) ? delvbs : delvsbs; + if (here->BSIM4mode >= 0) + { Idtot = here->BSIM4cd + here->BSIM4csub - here->BSIM4cbd + + here->BSIM4Igidl; + cdhat = Idtot - here->BSIM4gbd * delvbd_jct + + (here->BSIM4gmbs + here->BSIM4gbbs + here->BSIM4ggidlb) * delvbs + + (here->BSIM4gm + here->BSIM4gbgs + here->BSIM4ggidlg) * delvgs + + (here->BSIM4gds + here->BSIM4gbds + here->BSIM4ggidld) * delvds; + Ibtot = here->BSIM4cbs + here->BSIM4cbd + - here->BSIM4Igidl - here->BSIM4csub; + cbhat = Ibtot + here->BSIM4gbd * delvbd_jct + + here->BSIM4gbs * delvbs_jct - (here->BSIM4gbbs + here->BSIM4ggidlb) + * delvbs - (here->BSIM4gbgs + here->BSIM4ggidlg) * delvgs + - (here->BSIM4gbds + here->BSIM4ggidld) * delvds; + + Igstot = here->BSIM4Igs + here->BSIM4Igcs; + cgshat = Igstot + (here->BSIM4gIgsg + here->BSIM4gIgcsg) * delvgs + + here->BSIM4gIgcsd * delvds + here->BSIM4gIgcsb * delvbs; + + Igdtot = here->BSIM4Igd + here->BSIM4Igcd; + cgdhat = Igdtot + here->BSIM4gIgdg * delvgd + here->BSIM4gIgcdg * delvgs + + here->BSIM4gIgcdd * delvds + here->BSIM4gIgcdb * delvbs; + + Igbtot = here->BSIM4Igb; + cgbhat = here->BSIM4Igb + here->BSIM4gIgbg * delvgs + here->BSIM4gIgbd + * delvds + here->BSIM4gIgbb * delvbs; + } + else + { Idtot = here->BSIM4cd + here->BSIM4cbd; + cdhat = Idtot + here->BSIM4gbd * delvbd_jct + here->BSIM4gmbs + * delvbd + here->BSIM4gm * delvgd + - here->BSIM4gds * delvds; + Ibtot = here->BSIM4cbs + here->BSIM4cbd + - here->BSIM4Igidl - here->BSIM4csub; + cbhat = Ibtot + here->BSIM4gbs * delvbs_jct + here->BSIM4gbd + * delvbd_jct - (here->BSIM4gbbs + here->BSIM4ggidlb) * delvbd + - (here->BSIM4gbgs + here->BSIM4ggidlg) * delvgd + + (here->BSIM4gbds + here->BSIM4ggidld) * delvds; + + Igstot = here->BSIM4Igs + here->BSIM4Igcd; + cgshat = Igstot + here->BSIM4gIgsg * delvgs + here->BSIM4gIgcdg * delvgd + - here->BSIM4gIgcdd * delvds + here->BSIM4gIgcdb * delvbd; + + Igdtot = here->BSIM4Igd + here->BSIM4Igcs; + cgdhat = Igdtot + (here->BSIM4gIgdg + here->BSIM4gIgcsg) * delvgd + - here->BSIM4gIgcsd * delvds + here->BSIM4gIgcsb * delvbd; + + Igbtot = here->BSIM4Igb; + cgbhat = here->BSIM4Igb + here->BSIM4gIgbg * delvgd - here->BSIM4gIgbd + * delvds + here->BSIM4gIgbb * delvbd; + } + + Isestot = here->BSIM4gstot * (*(ckt->CKTstate0 + here->BSIM4vses)); + cseshat = Isestot + here->BSIM4gstot * delvses + + here->BSIM4gstotd * delvds + here->BSIM4gstotg * delvgs + + here->BSIM4gstotb * delvbs; + + Idedtot = here->BSIM4gdtot * vdedo; + cdedhat = Idedtot + here->BSIM4gdtot * delvded + + here->BSIM4gdtotd * delvds + here->BSIM4gdtotg * delvgs + + here->BSIM4gdtotb * delvbs; + + +#ifndef NOBYPASS + /* Following should be one IF statement, but some C compilers + * can't handle that all at once, so we split it into several + * successive IF's */ + + if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) + if ((fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0 + here->BSIM4vds))) + ckt->CKTvoltTol))) + if ((fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0 + here->BSIM4vgs))) + ckt->CKTvoltTol))) + if ((fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0 + here->BSIM4vbs))) + ckt->CKTvoltTol))) + if ((fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0 + here->BSIM4vbd))) + ckt->CKTvoltTol))) + if ((here->BSIM4rgateMod == 0) || (here->BSIM4rgateMod == 1) + || (fabs(delvges) < (ckt->CKTreltol * MAX(fabs(vges), + fabs(*(ckt->CKTstate0 + here->BSIM4vges))) + ckt->CKTvoltTol))) + if ((here->BSIM4rgateMod != 3) || (fabs(delvgms) < (ckt->CKTreltol + * MAX(fabs(vgms), fabs(*(ckt->CKTstate0 + here->BSIM4vgms))) + + ckt->CKTvoltTol))) + if ((!here->BSIM4rbodyMod) || (fabs(delvdbs) < (ckt->CKTreltol + * MAX(fabs(vdbs), fabs(*(ckt->CKTstate0 + here->BSIM4vdbs))) + + ckt->CKTvoltTol))) + if ((!here->BSIM4rbodyMod) || (fabs(delvdbd) < (ckt->CKTreltol + * MAX(fabs(vdbd), fabs(*(ckt->CKTstate0 + here->BSIM4vdbd))) + + ckt->CKTvoltTol))) + if ((!here->BSIM4rbodyMod) || (fabs(delvsbs) < (ckt->CKTreltol + * MAX(fabs(vsbs), fabs(*(ckt->CKTstate0 + here->BSIM4vsbs))) + + ckt->CKTvoltTol))) + if ((!model->BSIM4rdsMod) || (fabs(delvses) < (ckt->CKTreltol + * MAX(fabs(vses), fabs(*(ckt->CKTstate0 + here->BSIM4vses))) + + ckt->CKTvoltTol))) + if ((!model->BSIM4rdsMod) || (fabs(delvdes) < (ckt->CKTreltol + * MAX(fabs(vdes), fabs(*(ckt->CKTstate0 + here->BSIM4vdes))) + + ckt->CKTvoltTol))) + if ((fabs(cdhat - Idtot) < ckt->CKTreltol + * MAX(fabs(cdhat), fabs(Idtot)) + ckt->CKTabstol)) + if ((fabs(cbhat - Ibtot) < ckt->CKTreltol + * MAX(fabs(cbhat), fabs(Ibtot)) + ckt->CKTabstol)) + if ((!model->BSIM4igcMod) || ((fabs(cgshat - Igstot) < ckt->CKTreltol + * MAX(fabs(cgshat), fabs(Igstot)) + ckt->CKTabstol))) + if ((!model->BSIM4igcMod) || ((fabs(cgdhat - Igdtot) < ckt->CKTreltol + * MAX(fabs(cgdhat), fabs(Igdtot)) + ckt->CKTabstol))) + if ((!model->BSIM4igbMod) || ((fabs(cgbhat - Igbtot) < ckt->CKTreltol + * MAX(fabs(cgbhat), fabs(Igbtot)) + ckt->CKTabstol))) + if ((!model->BSIM4rdsMod) || ((fabs(cseshat - Isestot) < ckt->CKTreltol + * MAX(fabs(cseshat), fabs(Isestot)) + ckt->CKTabstol))) + if ((!model->BSIM4rdsMod) || ((fabs(cdedhat - Idedtot) < ckt->CKTreltol + * MAX(fabs(cdedhat), fabs(Idedtot)) + ckt->CKTabstol))) + { vds = *(ckt->CKTstate0 + here->BSIM4vds); + vgs = *(ckt->CKTstate0 + here->BSIM4vgs); + vbs = *(ckt->CKTstate0 + here->BSIM4vbs); + vges = *(ckt->CKTstate0 + here->BSIM4vges); + vgms = *(ckt->CKTstate0 + here->BSIM4vgms); + + vbd = *(ckt->CKTstate0 + here->BSIM4vbd); + vdbs = *(ckt->CKTstate0 + here->BSIM4vdbs); + vdbd = *(ckt->CKTstate0 + here->BSIM4vdbd); + vsbs = *(ckt->CKTstate0 + here->BSIM4vsbs); + vses = *(ckt->CKTstate0 + here->BSIM4vses); + vdes = *(ckt->CKTstate0 + here->BSIM4vdes); + + vgd = vgs - vds; + vgb = vgs - vbs; + vged = vges - vds; + vgmd = vgms - vds; + vgmb = vgms - vbs; + + vbs_jct = (!here->BSIM4rbodyMod) ? vbs : vsbs; + vbd_jct = (!here->BSIM4rbodyMod) ? vbd : vdbd; + + qdef = *(ckt->CKTstate0 + here->BSIM4qdef); + cdrain = here->BSIM4cd; + + if ((ckt->CKTmode & (MODETRAN | MODEAC)) || + ((ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC))) + { ByPass = 1; + + qgate = here->BSIM4qgate; + qbulk = here->BSIM4qbulk; + qdrn = here->BSIM4qdrn; + cgdo = here->BSIM4cgdo; + qgdo = here->BSIM4qgdo; + cgso = here->BSIM4cgso; + qgso = here->BSIM4qgso; + + goto line755; + } + else + goto line850; + } +#endif /*NOBYPASS*/ + + von = here->BSIM4von; + if (*(ckt->CKTstate0 + here->BSIM4vds) >= 0.0) + { vgs = DEVfetlim(vgs, *(ckt->CKTstate0 + here->BSIM4vgs), von); + vds = vgs - vgd; + vds = DEVlimvds(vds, *(ckt->CKTstate0 + here->BSIM4vds)); + vgd = vgs - vds; + if (here->BSIM4rgateMod == 3) + { vges = DEVfetlim(vges, *(ckt->CKTstate0 + here->BSIM4vges), von); + vgms = DEVfetlim(vgms, *(ckt->CKTstate0 + here->BSIM4vgms), von); + vged = vges - vds; + vgmd = vgms - vds; + } + else if ((here->BSIM4rgateMod == 1) || (here->BSIM4rgateMod == 2)) + { vges = DEVfetlim(vges, *(ckt->CKTstate0 + here->BSIM4vges), von); + vged = vges - vds; + } + + if (model->BSIM4rdsMod) + { vdes = DEVlimvds(vdes, *(ckt->CKTstate0 + here->BSIM4vdes)); + vses = -DEVlimvds(-vses, -(*(ckt->CKTstate0 + here->BSIM4vses))); + } + + } + else + { vgd = DEVfetlim(vgd, vgdo, von); + vds = vgs - vgd; + vds = -DEVlimvds(-vds, -(*(ckt->CKTstate0 + here->BSIM4vds))); + vgs = vgd + vds; + + if (here->BSIM4rgateMod == 3) + { vged = DEVfetlim(vged, vgedo, von); + vges = vged + vds; + vgmd = DEVfetlim(vgmd, vgmdo, von); + vgms = vgmd + vds; + } + if ((here->BSIM4rgateMod == 1) || (here->BSIM4rgateMod == 2)) + { vged = DEVfetlim(vged, vgedo, von); + vges = vged + vds; + } + + if (model->BSIM4rdsMod) + { vdes = -DEVlimvds(-vdes, -(*(ckt->CKTstate0 + here->BSIM4vdes))); + vses = DEVlimvds(vses, *(ckt->CKTstate0 + here->BSIM4vses)); + } + } + + if (vds >= 0.0) + { vbs = DEVpnjlim(vbs, *(ckt->CKTstate0 + here->BSIM4vbs), + CONSTvt0, model->BSIM4vcrit, &Check); + vbd = vbs - vds; + if (here->BSIM4rbodyMod) + { vdbs = DEVpnjlim(vdbs, *(ckt->CKTstate0 + here->BSIM4vdbs), + CONSTvt0, model->BSIM4vcrit, &Check1); + vdbd = vdbs - vds; + vsbs = DEVpnjlim(vsbs, *(ckt->CKTstate0 + here->BSIM4vsbs), + CONSTvt0, model->BSIM4vcrit, &Check2); + if ((Check1 == 0) && (Check2 == 0)) + Check = 0; + else + Check = 1; + } + } + else + { vbd = DEVpnjlim(vbd, *(ckt->CKTstate0 + here->BSIM4vbd), + CONSTvt0, model->BSIM4vcrit, &Check); + vbs = vbd + vds; + if (here->BSIM4rbodyMod) + { vdbd = DEVpnjlim(vdbd, *(ckt->CKTstate0 + here->BSIM4vdbd), + CONSTvt0, model->BSIM4vcrit, &Check1); + vdbs = vdbd + vds; + vsbdo = *(ckt->CKTstate0 + here->BSIM4vsbs) + - *(ckt->CKTstate0 + here->BSIM4vds); + vsbd = vsbs - vds; + vsbd = DEVpnjlim(vsbd, vsbdo, CONSTvt0, model->BSIM4vcrit, &Check2); + vsbs = vsbd + vds; + if ((Check1 == 0) && (Check2 == 0)) + Check = 0; + else + Check = 1; + } + } + } + + /* Calculate DC currents and their derivatives */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + vged = vges - vds; + vgmd = vgms - vds; + vgmb = vgms - vbs; + vdbd = vdbs - vds; + + vbs_jct = (!here->BSIM4rbodyMod) ? vbs : vsbs; + vbd_jct = (!here->BSIM4rbodyMod) ? vbd : vdbd; + + /* Source/drain junction diode DC model begins */ + Nvtms = model->BSIM4vtm * model->BSIM4SjctEmissionCoeff; + if ((here->BSIM4Aseff <= 0.0) && (here->BSIM4Pseff <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } + else + { SourceSatCurrent = here->BSIM4Aseff * model->BSIM4SjctTempSatCurDensity + + here->BSIM4Pseff * model->BSIM4SjctSidewallTempSatCurDensity + + pParam->BSIM4weffCJ * here->BSIM4nf + * model->BSIM4SjctGateSidewallTempSatCurDensity; + } + + if (SourceSatCurrent <= 0.0) + { here->BSIM4gbs = ckt->CKTgmin; + here->BSIM4cbs = here->BSIM4gbs * vbs_jct; + } + else + { switch(model->BSIM4dioMod) + { case 0: + evbs = exp(vbs_jct / Nvtms); + T1 = model->BSIM4xjbvs * exp(-(model->BSIM4bvs + vbs_jct) / Nvtms); + /* WDLiu: Magic T1 in this form; different from BSIM4 beta. */ + here->BSIM4gbs = SourceSatCurrent * (evbs + T1) / Nvtms + ckt->CKTgmin; + here->BSIM4cbs = SourceSatCurrent * (evbs + here->BSIM4XExpBVS + - T1 - 1.0) + ckt->CKTgmin * vbs_jct; + break; + case 1: + T2 = vbs_jct / Nvtms; + if (T2 < -EXP_THRESHOLD) + { here->BSIM4gbs = ckt->CKTgmin; + here->BSIM4cbs = SourceSatCurrent * (MIN_EXP - 1.0) + + ckt->CKTgmin * vbs_jct; + } + else if (vbs_jct <= here->BSIM4vjsmFwd) + { evbs = exp(T2); + here->BSIM4gbs = SourceSatCurrent * evbs / Nvtms + ckt->CKTgmin; + here->BSIM4cbs = SourceSatCurrent * (evbs - 1.0) + + ckt->CKTgmin * vbs_jct; + } + else + { T0 = here->BSIM4IVjsmFwd / Nvtms; + here->BSIM4gbs = T0 + ckt->CKTgmin; + here->BSIM4cbs = here->BSIM4IVjsmFwd - SourceSatCurrent + T0 + * (vbs_jct - here->BSIM4vjsmFwd) + ckt->CKTgmin * vbs_jct; + } + break; + case 2: + if (vbs_jct < here->BSIM4vjsmRev) + { T0 = vbs_jct / Nvtms; + if (T0 < -EXP_THRESHOLD) + { evbs = MIN_EXP; + devbs_dvb = 0.0; + } + else + { evbs = exp(T0); + devbs_dvb = evbs / Nvtms; + } + + T1 = evbs - 1.0; + T2 = here->BSIM4IVjsmRev + here->BSIM4SslpRev + * (vbs_jct - here->BSIM4vjsmRev); + here->BSIM4gbs = devbs_dvb * T2 + T1 * here->BSIM4SslpRev + ckt->CKTgmin; + here->BSIM4cbs = T1 * T2 + ckt->CKTgmin * vbs_jct; + } + else if (vbs_jct <= here->BSIM4vjsmFwd) + { T0 = vbs_jct / Nvtms; + if (T0 < -EXP_THRESHOLD) + { evbs = MIN_EXP; + devbs_dvb = 0.0; + } + else + { evbs = exp(T0); + devbs_dvb = evbs / Nvtms; + } + + T1 = (model->BSIM4bvs + vbs_jct) / Nvtms; + if (T1 > EXP_THRESHOLD) + { T2 = MIN_EXP; + T3 = 0.0; + } + else + { T2 = exp(-T1); + T3 = -T2 /Nvtms; + } + here->BSIM4gbs = SourceSatCurrent * (devbs_dvb - model->BSIM4xjbvs * T3) + + ckt->CKTgmin; + here->BSIM4cbs = SourceSatCurrent * (evbs + here->BSIM4XExpBVS - 1.0 + - model->BSIM4xjbvs * T2) + ckt->CKTgmin * vbs_jct; + } + else + { here->BSIM4gbs = here->BSIM4SslpFwd + ckt->CKTgmin; + here->BSIM4cbs = here->BSIM4IVjsmFwd + here->BSIM4SslpFwd * (vbs_jct + - here->BSIM4vjsmFwd) + ckt->CKTgmin * vbs_jct; + } + break; + default: break; + } + } + + Nvtmd = model->BSIM4vtm * model->BSIM4DjctEmissionCoeff; + if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } + else + { DrainSatCurrent = here->BSIM4Adeff * model->BSIM4DjctTempSatCurDensity + + here->BSIM4Pdeff * model->BSIM4DjctSidewallTempSatCurDensity + + pParam->BSIM4weffCJ * here->BSIM4nf + * model->BSIM4DjctGateSidewallTempSatCurDensity; + } + + if (DrainSatCurrent <= 0.0) + { here->BSIM4gbd = ckt->CKTgmin; + here->BSIM4cbd = here->BSIM4gbd * vbd_jct; + } + else + { switch(model->BSIM4dioMod) + { case 0: + evbd = exp(vbd_jct / Nvtmd); + T1 = model->BSIM4xjbvd * exp(-(model->BSIM4bvd + vbd_jct) / Nvtmd); + /* WDLiu: Magic T1 in this form; different from BSIM4 beta. */ + here->BSIM4gbd = DrainSatCurrent * (evbd + T1) / Nvtmd + ckt->CKTgmin; + here->BSIM4cbd = DrainSatCurrent * (evbd + here->BSIM4XExpBVD + - T1 - 1.0) + ckt->CKTgmin * vbd_jct; + break; + case 1: + T2 = vbd_jct / Nvtmd; + if (T2 < -EXP_THRESHOLD) + { here->BSIM4gbd = ckt->CKTgmin; + here->BSIM4cbd = DrainSatCurrent * (MIN_EXP - 1.0) + + ckt->CKTgmin * vbd_jct; + } + else if (vbd_jct <= here->BSIM4vjdmFwd) + { evbd = exp(T2); + here->BSIM4gbd = DrainSatCurrent * evbd / Nvtmd + ckt->CKTgmin; + here->BSIM4cbd = DrainSatCurrent * (evbd - 1.0) + + ckt->CKTgmin * vbd_jct; + } + else + { T0 = here->BSIM4IVjdmFwd / Nvtmd; + here->BSIM4gbd = T0 + ckt->CKTgmin; + here->BSIM4cbd = here->BSIM4IVjdmFwd - DrainSatCurrent + T0 + * (vbd_jct - here->BSIM4vjdmFwd) + ckt->CKTgmin * vbd_jct; + } + break; + case 2: + if (vbd_jct < here->BSIM4vjdmRev) + { T0 = vbd_jct / Nvtmd; + if (T0 < -EXP_THRESHOLD) + { evbd = MIN_EXP; + devbd_dvb = 0.0; + } + else + { evbd = exp(T0); + devbd_dvb = evbd / Nvtmd; + } + + T1 = evbd - 1.0; + T2 = here->BSIM4IVjdmRev + here->BSIM4DslpRev + * (vbd_jct - here->BSIM4vjdmRev); + here->BSIM4gbd = devbd_dvb * T2 + T1 * here->BSIM4DslpRev + ckt->CKTgmin; + here->BSIM4cbd = T1 * T2 + ckt->CKTgmin * vbd_jct; + } + else if (vbd_jct <= here->BSIM4vjdmFwd) + { T0 = vbd_jct / Nvtmd; + if (T0 < -EXP_THRESHOLD) + { evbd = MIN_EXP; + devbd_dvb = 0.0; + } + else + { evbd = exp(T0); + devbd_dvb = evbd / Nvtmd; + } + + T1 = (model->BSIM4bvd + vbd_jct) / Nvtmd; + if (T1 > EXP_THRESHOLD) + { T2 = MIN_EXP; + T3 = 0.0; + } + else + { T2 = exp(-T1); + T3 = -T2 /Nvtmd; + } + here->BSIM4gbd = DrainSatCurrent * (devbd_dvb - model->BSIM4xjbvd * T3) + + ckt->CKTgmin; + here->BSIM4cbd = DrainSatCurrent * (evbd + here->BSIM4XExpBVS - 1.0 + - model->BSIM4xjbvd * T2) + ckt->CKTgmin * vbd_jct; + } + else + { here->BSIM4gbd = here->BSIM4DslpFwd + ckt->CKTgmin; + here->BSIM4cbd = here->BSIM4IVjdmFwd + here->BSIM4DslpFwd * (vbd_jct + - here->BSIM4vjdmFwd) + ckt->CKTgmin * vbd_jct; + } + break; + default: break; + } + } /* End of diode DC model */ + + if (vds >= 0.0) + { here->BSIM4mode = 1; + Vds = vds; + Vgs = vgs; + Vbs = vbs; + Vdb = vds - vbs; /* WDLiu: for GIDL */ + } + else + { here->BSIM4mode = -1; + Vds = -vds; + Vgs = vgd; + Vbs = vbd; + Vdb = -vbs; + } + + T0 = Vbs - pParam->BSIM4vbsc - 0.001; + T1 = sqrt(T0 * T0 - 0.004 * pParam->BSIM4vbsc); + if (T0 >= 0.0) + { Vbseff = pParam->BSIM4vbsc + 0.5 * (T0 + T1); + dVbseff_dVb = 0.5 * (1.0 + T0 / T1); + } + else + { T2 = -0.002 / (T1 - T0); + Vbseff = pParam->BSIM4vbsc * (1.0 + T2); + dVbseff_dVb = T2 * pParam->BSIM4vbsc / T1; + } + if (Vbseff < Vbs) + { Vbseff = Vbs; + } + + if (Vbseff > 0.0) + { T0 = pParam->BSIM4phi / (pParam->BSIM4phi + Vbseff); + Phis = pParam->BSIM4phi * T0; + dPhis_dVb = -T0 * T0; + sqrtPhis = pParam->BSIM4phis3 / (pParam->BSIM4phi + 0.5 * Vbseff); + dsqrtPhis_dVb = -0.5 * sqrtPhis * sqrtPhis / pParam->BSIM4phis3; + } + else + { Phis = pParam->BSIM4phi - Vbseff; + dPhis_dVb = -1.0; + sqrtPhis = sqrt(Phis); + dsqrtPhis_dVb = -0.5 / sqrtPhis; + } + Xdep = pParam->BSIM4Xdep0 * sqrtPhis / pParam->BSIM4sqrtPhi; + dXdep_dVb = (pParam->BSIM4Xdep0 / pParam->BSIM4sqrtPhi) + * dsqrtPhis_dVb; + + Leff = pParam->BSIM4leff; + Vtm = model->BSIM4vtm; + + /* Vth Calculation */ + T3 = sqrt(Xdep); + V0 = pParam->BSIM4vbi - pParam->BSIM4phi; + + T0 = pParam->BSIM4dvt2 * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM4dvt2; + } + else + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM4dvt2 * T4 * T4; + } + lt1 = model->BSIM4factor1 * T3 * T1; + dlt1_dVb = model->BSIM4factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = pParam->BSIM4dvt2w * Vbseff; + if (T0 >= - 0.5) + { T1 = 1.0 + T0; + T2 = pParam->BSIM4dvt2w; + } + else + { T4 = 1.0 / (3.0 + 8.0 * T0); + T1 = (1.0 + 3.0 * T0) * T4; + T2 = pParam->BSIM4dvt2w * T4 * T4; + } + ltw = model->BSIM4factor1 * T3 * T1; + dltw_dVb = model->BSIM4factor1 * (0.5 / T3 * T1 * dXdep_dVb + T3 * T2); + + T0 = pParam->BSIM4dvt1 * Leff / lt1; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + Theta0 = T1 / T4; + dT1_dVb = -T0 * T1 * dlt1_dVb / lt1; + dTheta0_dVb = dT1_dVb * (T4 - 2.0 * T1 * (T2 + MIN_EXP)) / T4 / T4; + } + else + { Theta0 = 1.0 / (MAX_EXP - 2.0); /* 3.0 * MIN_EXP omitted */ + dTheta0_dVb = 0.0; + } + here->BSIM4thetavth = pParam->BSIM4dvt0 * Theta0; + Delt_vth = here->BSIM4thetavth * V0; + dDelt_vth_dVb = pParam->BSIM4dvt0 * dTheta0_dVb * V0; + + T0 = pParam->BSIM4dvt1w * pParam->BSIM4weff * Leff / ltw; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + T5 = T1 / T4; + dT1_dVb = -T0 * T1 * dlt1_dVb / lt1; + dT5_dVb = dT1_dVb * (T4 - 2.0 * T1 * (T2 + MIN_EXP)) / T4 / T4; + } + else + { T5 = 1.0 / (MAX_EXP - 2.0); /* 3.0 * MIN_EXP omitted */ + dT5_dVb = 0.0; + } + T0 = pParam->BSIM4dvt0w * T5; + T2 = T0 * V0; + dT2_dVb = pParam->BSIM4dvt0w * dT5_dVb * V0; + + TempRatio = ckt->CKTtemp / model->BSIM4tnom - 1.0; + T0 = sqrt(1.0 + pParam->BSIM4lpe0 / Leff); + T1 = pParam->BSIM4k1ox * (T0 - 1.0) * pParam->BSIM4sqrtPhi + + (pParam->BSIM4kt1 + pParam->BSIM4kt1l / Leff + + pParam->BSIM4kt2 * Vbseff) * TempRatio; + Vth_NarrowW = model->BSIM4toxe * pParam->BSIM4phi + / (pParam->BSIM4weff + pParam->BSIM4w0); + + T3 = pParam->BSIM4eta0 + pParam->BSIM4etab * Vbseff; + if (T3 < 1.0e-4) + { T9 = 1.0 / (3.0 - 2.0e4 * T3); + T3 = (2.0e-4 - T3) * T9; + T4 = T9 * T9; + } + else + { T4 = 1.0; + } + dDIBL_Sft_dVd = T3 * pParam->BSIM4theta0vb0; + DIBL_Sft = dDIBL_Sft_dVd * Vds; + + Lpe_Vb = sqrt(1.0 + pParam->BSIM4lpeb / Leff); + + Vth = model->BSIM4type * pParam->BSIM4vth0 + (pParam->BSIM4k1ox * sqrtPhis + - pParam->BSIM4k1 * pParam->BSIM4sqrtPhi) * Lpe_Vb + - pParam->BSIM4k2ox * Vbseff - Delt_vth - T2 + (pParam->BSIM4k3 + + pParam->BSIM4k3b * Vbseff) * Vth_NarrowW + T1 - DIBL_Sft; + + dVth_dVb = Lpe_Vb * pParam->BSIM4k1ox * dsqrtPhis_dVb - pParam->BSIM4k2ox + - dDelt_vth_dVb - dT2_dVb + pParam->BSIM4k3b * Vth_NarrowW + - pParam->BSIM4etab * Vds * pParam->BSIM4theta0vb0 * T4 + + pParam->BSIM4kt2 * TempRatio; + dVth_dVd = -dDIBL_Sft_dVd; + + + /* Calculate n */ + tmp1 = EPSSI / Xdep; + here->BSIM4nstar = model->BSIM4vtm / Charge_q * (model->BSIM4coxe + + tmp1 + pParam->BSIM4cit); + tmp2 = pParam->BSIM4nfactor * tmp1; + tmp3 = pParam->BSIM4cdsc + pParam->BSIM4cdscb * Vbseff + + pParam->BSIM4cdscd * Vds; + tmp4 = (tmp2 + tmp3 * Theta0 + pParam->BSIM4cit) / model->BSIM4coxe; + if (tmp4 >= -0.5) + { n = 1.0 + tmp4; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM4cdscb * Theta0) / model->BSIM4coxe; + dn_dVd = pParam->BSIM4cdscd * Theta0 / model->BSIM4coxe; + } + else + { T0 = 1.0 / (3.0 + 8.0 * tmp4); + n = (1.0 + 3.0 * tmp4) * T0; + T0 *= T0; + dn_dVb = (-tmp2 / Xdep * dXdep_dVb + tmp3 * dTheta0_dVb + + pParam->BSIM4cdscb * Theta0) / model->BSIM4coxe * T0; + dn_dVd = pParam->BSIM4cdscd * Theta0 / model->BSIM4coxe * T0; + } + + + /* Vth correction for Pocket implant */ + if (pParam->BSIM4dvtp0 > 0.0) + { T0 = -pParam->BSIM4dvtp1 * Vds; + if (T0 < -EXP_THRESHOLD) + { T2 = MIN_EXP; + dT2_dVd = 0.0; + } + else + { T2 = exp(T0); + dT2_dVd = -pParam->BSIM4dvtp1 * T2; + } + + T3 = Leff + pParam->BSIM4dvtp0 * (1.0 + T2); + dT3_dVd = pParam->BSIM4dvtp0 * dT2_dVd; + T4 = Vtm * log(Leff / T3); + dT4_dVd = -Vtm * dT3_dVd / T3; + dDITS_Sft_dVd = dn_dVd * T4 + n * dT4_dVd; + dDITS_Sft_dVb = T4 * dn_dVb; + + Vth -= n * T4; + dVth_dVd -= dDITS_Sft_dVd; + dVth_dVb -= dDITS_Sft_dVb; + } + here->BSIM4von = Vth; + + + /* Poly Gate Si Depletion Effect */ + T0 = pParam->BSIM4vfb + pParam->BSIM4phi; + if ((pParam->BSIM4ngate > 1.0e18) + && (pParam->BSIM4ngate < 1.0e25) && (Vgs > T0)) + { T1 = 1.0e6 * Charge_q * EPSSI * pParam->BSIM4ngate + / (model->BSIM4coxe * model->BSIM4coxe); + T8 = Vgs - T0; + T4 = sqrt(1.0 + 2.0 * T8 / T1); + T2 = 2.0 * T8 / (T4 + 1.0); + T3 = 0.5 * T2 * T2 / T1; /* T3 = Vpoly */ + T7 = 1.12 - T3 - 0.05; + T6 = sqrt(T7 * T7 + 0.224); + T5 = 1.12 - 0.5 * (T7 + T6); + Vgs_eff = Vgs - T5; + dVgs_eff_dVg = 1.0 - (0.5 - 0.5 / T4) * (1.0 + T7 / T6); + } + else + { Vgs_eff = Vgs; + dVgs_eff_dVg = 1.0; + } + Vgst = Vgs_eff - Vth; + + /* Calculate Vgsteff */ + T0 = n * Vtm; + T1 = pParam->BSIM4mstar * Vgst; + T2 = T1 / T0; + if (T2 > EXP_THRESHOLD) + { T10 = T1; + dT10_dVg = pParam->BSIM4mstar * dVgs_eff_dVg; + dT10_dVd = -dVth_dVd * pParam->BSIM4mstar; + dT10_dVb = -dVth_dVb * pParam->BSIM4mstar; + } + else if (T2 < -EXP_THRESHOLD) + { T10 = Vtm * log(1.0 + MIN_EXP); + dT10_dVg = 0.0; + dT10_dVd = T10 * dn_dVd; + dT10_dVb = T10 * dn_dVb; + T10 *= n; + } + else + { ExpVgst = exp(T2); + T3 = Vtm * log(1.0 + ExpVgst); + T10 = n * T3; + dT10_dVg = pParam->BSIM4mstar * ExpVgst / (1.0 + ExpVgst); + dT10_dVb = T3 * dn_dVb - dT10_dVg * (dVth_dVb + Vgst * dn_dVb / n); + dT10_dVd = T3 * dn_dVd - dT10_dVg * (dVth_dVd + Vgst * dn_dVd / n); + dT10_dVg *= dVgs_eff_dVg; + } + + T1 = pParam->BSIM4voffcbn - (1.0 - pParam->BSIM4mstar) * Vgst; + T2 = T1 / T0; + if (T2 < -EXP_THRESHOLD) + { T3 = model->BSIM4coxe * MIN_EXP / pParam->BSIM4cdep0; + T9 = pParam->BSIM4mstar + T3 * n; + dT9_dVg = 0.0; + dT9_dVd = dn_dVd * T3; + dT9_dVb = dn_dVb * T3; + } + else if (T2 > EXP_THRESHOLD) + { T3 = model->BSIM4coxe * MAX_EXP / pParam->BSIM4cdep0; + T9 = pParam->BSIM4mstar + T3 * n; + dT9_dVg = 0.0; + dT9_dVd = dn_dVd * T3; + dT9_dVb = dn_dVb * T3; + } + else + { ExpVgst = exp(T2); + T3 = model->BSIM4coxe / pParam->BSIM4cdep0; + T4 = T3 * ExpVgst; + T5 = T1 * T4 / T0; + T9 = pParam->BSIM4mstar + n * T4; + dT9_dVg = T3 * (pParam->BSIM4mstar - 1.0) * ExpVgst / Vtm; + dT9_dVb = T4 * dn_dVb - dT9_dVg * dVth_dVb - T5 * dn_dVb; + dT9_dVd = T4 * dn_dVd - dT9_dVg * dVth_dVd - T5 * dn_dVd; + dT9_dVg *= dVgs_eff_dVg; + } + + here->BSIM4Vgsteff = Vgsteff = T10 / T9; + T11 = T9 * T9; + dVgsteff_dVg = (T9 * dT10_dVg - T10 * dT9_dVg) / T11; + dVgsteff_dVd = (T9 * dT10_dVd - T10 * dT9_dVd) / T11; + dVgsteff_dVb = (T9 * dT10_dVb - T10 * dT9_dVb) / T11; + + /* Calculate Effective Channel Geometry */ + T9 = sqrtPhis - pParam->BSIM4sqrtPhi; + Weff = pParam->BSIM4weff - 2.0 * (pParam->BSIM4dwg * Vgsteff + + pParam->BSIM4dwb * T9); + dWeff_dVg = -2.0 * pParam->BSIM4dwg; + dWeff_dVb = -2.0 * pParam->BSIM4dwb * dsqrtPhis_dVb; + + if (Weff < 2.0e-8) /* to avoid the discontinuity problem due to Weff*/ + { T0 = 1.0 / (6.0e-8 - 2.0 * Weff); + Weff = 2.0e-8 * (4.0e-8 - Weff) * T0; + T0 *= T0 * 4.0e-16; + dWeff_dVg *= T0; + dWeff_dVb *= T0; + } + + if (model->BSIM4rdsMod == 1) + Rds = dRds_dVg = dRds_dVb = 0.0; + else + { T0 = 1.0 + pParam->BSIM4prwg * Vgsteff; + dT0_dVg = -pParam->BSIM4prwg / T0 / T0; + T1 = pParam->BSIM4prwb * T9; + dT1_dVb = pParam->BSIM4prwb * dsqrtPhis_dVb; + + T2 = 1.0 / T0 + T1; + T3 = T2 + sqrt(T2 * T2 + 0.01); /* 0.01 = 4.0 * 0.05 * 0.05 */ + dT3_dVg = 1.0 + T2 / (T3 - T2); + dT3_dVb = dT3_dVg * dT1_dVb; + dT3_dVg *= dT0_dVg; + + T4 = pParam->BSIM4rds0 * 0.5; + Rds = pParam->BSIM4rdswmin + T3 * T4; + dRds_dVg = T4 * dT3_dVg; + dRds_dVb = T4 * dT3_dVb; + + if (Rds > 0.0) + here->BSIM4grdsw = 1.0 / Rds; + else + here->BSIM4grdsw = 0.0; + } + + /* Calculate Abulk */ + T9 = 0.5 * pParam->BSIM4k1ox * Lpe_Vb / sqrtPhis; + T1 = T9 + pParam->BSIM4k2ox - pParam->BSIM4k3b * Vth_NarrowW; + dT1_dVb = -T9 / sqrtPhis * dsqrtPhis_dVb; + + T9 = sqrt(pParam->BSIM4xj * Xdep); + tmp1 = Leff + 2.0 * T9; + T5 = Leff / tmp1; + tmp2 = pParam->BSIM4a0 * T5; + tmp3 = pParam->BSIM4weff + pParam->BSIM4b1; + tmp4 = pParam->BSIM4b0 / tmp3; + T2 = tmp2 + tmp4; + dT2_dVb = -T9 / tmp1 / Xdep * dXdep_dVb; + T6 = T5 * T5; + T7 = T5 * T6; + + Abulk0 = 1.0 + T1 * T2; + dAbulk0_dVb = T1 * tmp2 * dT2_dVb + T2 * dT1_dVb; + + T8 = pParam->BSIM4ags * pParam->BSIM4a0 * T7; + dAbulk_dVg = -T1 * T8; + Abulk = Abulk0 + dAbulk_dVg * Vgsteff; + dAbulk_dVb = dAbulk0_dVb - T8 * Vgsteff * (dT1_dVb + + 3.0 * T1 * dT2_dVb); + + if (Abulk0 < 0.1) /* added to avoid the problems caused by Abulk0 */ + { T9 = 1.0 / (3.0 - 20.0 * Abulk0); + Abulk0 = (0.2 - Abulk0) * T9; + dAbulk0_dVb *= T9 * T9; + } + + if (Abulk < 0.1) + { T9 = 1.0 / (3.0 - 20.0 * Abulk); + Abulk = (0.2 - Abulk) * T9; + T10 = T9 * T9; + dAbulk_dVb *= T10; + dAbulk_dVg *= T10; + } + here->BSIM4Abulk = Abulk; + + T2 = pParam->BSIM4keta * Vbseff; + if (T2 >= -0.9) + { T0 = 1.0 / (1.0 + T2); + dT0_dVb = -pParam->BSIM4keta * T0 * T0; + } + else + { T1 = 1.0 / (0.8 + T2); + T0 = (17.0 + 20.0 * T2) * T1; + dT0_dVb = -pParam->BSIM4keta * T1 * T1; + } + dAbulk_dVg *= T0; + dAbulk_dVb = dAbulk_dVb * T0 + Abulk * dT0_dVb; + dAbulk0_dVb = dAbulk0_dVb * T0 + Abulk0 * dT0_dVb; + Abulk *= T0; + Abulk0 *= T0; + + /* Mobility calculation */ + if (model->BSIM4mobMod == 0) + { T0 = Vgsteff + Vth + Vth; + T2 = pParam->BSIM4ua + pParam->BSIM4uc * Vbseff; + T3 = T0 / model->BSIM4toxe; + T5 = T3 * (T2 + pParam->BSIM4ub * T3); + dDenomi_dVg = (T2 + 2.0 * pParam->BSIM4ub * T3) / model->BSIM4toxe; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM4uc * T3; + } + else if (model->BSIM4mobMod == 1) + { T0 = Vgsteff + Vth + Vth; + T2 = 1.0 + pParam->BSIM4uc * Vbseff; + T3 = T0 / model->BSIM4toxe; + T4 = T3 * (pParam->BSIM4ua + pParam->BSIM4ub * T3); + T5 = T4 * T2; + dDenomi_dVg = (pParam->BSIM4ua + 2.0 * pParam->BSIM4ub * T3) * T2 + / model->BSIM4toxe; + dDenomi_dVd = dDenomi_dVg * 2.0 * dVth_dVd; + dDenomi_dVb = dDenomi_dVg * 2.0 * dVth_dVb + pParam->BSIM4uc * T4; + } + else + { T0 = (Vgsteff + pParam->BSIM4vtfbphi1) / model->BSIM4toxe; + T1 = exp(pParam->BSIM4eu * log(T0)); + dT1_dVg = T1 * pParam->BSIM4eu / T0 / model->BSIM4toxe; + T2 = pParam->BSIM4ua + pParam->BSIM4uc * Vbseff; + T5 = T1 * T2; + dDenomi_dVg = T2 * dT1_dVg; + dDenomi_dVd = 0.0; + dDenomi_dVb = T1 * pParam->BSIM4uc; + } + + if (T5 >= -0.8) + { Denomi = 1.0 + T5; + } + else + { T9 = 1.0 / (7.0 + 10.0 * T5); + Denomi = (0.6 + T5) * T9; + T9 *= T9; + dDenomi_dVg *= T9; + dDenomi_dVd *= T9; + dDenomi_dVb *= T9; + } + + here->BSIM4ueff = ueff = pParam->BSIM4u0temp / Denomi; + T9 = -ueff / Denomi; + dueff_dVg = T9 * dDenomi_dVg; + dueff_dVd = T9 * dDenomi_dVd; + dueff_dVb = T9 * dDenomi_dVb; + + /* Saturation Drain Voltage Vdsat */ + WVCox = Weff * pParam->BSIM4vsattemp * model->BSIM4coxe; + WVCoxRds = WVCox * Rds; + + Esat = 2.0 * pParam->BSIM4vsattemp / ueff; + here->BSIM4EsatL = EsatL = Esat * Leff; + T0 = -EsatL /ueff; + dEsatL_dVg = T0 * dueff_dVg; + dEsatL_dVd = T0 * dueff_dVd; + dEsatL_dVb = T0 * dueff_dVb; + + /* Sqrt() */ + a1 = pParam->BSIM4a1; + if (a1 == 0.0) + { Lambda = pParam->BSIM4a2; + dLambda_dVg = 0.0; + } + else if (a1 > 0.0) + { T0 = 1.0 - pParam->BSIM4a2; + T1 = T0 - pParam->BSIM4a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * T0); + Lambda = pParam->BSIM4a2 + T0 - 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM4a1 * (1.0 + T1 / T2); + } + else + { T1 = pParam->BSIM4a2 + pParam->BSIM4a1 * Vgsteff - 0.0001; + T2 = sqrt(T1 * T1 + 0.0004 * pParam->BSIM4a2); + Lambda = 0.5 * (T1 + T2); + dLambda_dVg = 0.5 * pParam->BSIM4a1 * (1.0 + T1 / T2); + } + + Vgst2Vtm = Vgsteff + 2.0 * Vtm; + if (Rds > 0) + { tmp2 = dRds_dVg / Rds + dWeff_dVg / Weff; + tmp3 = dRds_dVb / Rds + dWeff_dVb / Weff; + } + else + { tmp2 = dWeff_dVg / Weff; + tmp3 = dWeff_dVb / Weff; + } + if ((Rds == 0.0) && (Lambda == 1.0)) + { T0 = 1.0 / (Abulk * EsatL + Vgst2Vtm); + tmp1 = 0.0; + T1 = T0 * T0; + T2 = Vgst2Vtm * T0; + T3 = EsatL * Vgst2Vtm; + Vdsat = T3 * T0; + + dT0_dVg = -(Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 1.0) * T1; + dT0_dVd = -(Abulk * dEsatL_dVd) * T1; + dT0_dVb = -(Abulk * dEsatL_dVb + dAbulk_dVb * EsatL) * T1; + + dVdsat_dVg = T3 * dT0_dVg + T2 * dEsatL_dVg + EsatL * T0; + dVdsat_dVd = T3 * dT0_dVd + T2 * dEsatL_dVd; + dVdsat_dVb = T3 * dT0_dVb + T2 * dEsatL_dVb; + } + else + { tmp1 = dLambda_dVg / (Lambda * Lambda); + T9 = Abulk * WVCoxRds; + T8 = Abulk * T9; + T7 = Vgst2Vtm * T9; + T6 = Vgst2Vtm * WVCoxRds; + T0 = 2.0 * Abulk * (T9 - 1.0 + 1.0 / Lambda); + dT0_dVg = 2.0 * (T8 * tmp2 - Abulk * tmp1 + + (2.0 * T9 + 1.0 / Lambda - 1.0) * dAbulk_dVg); + + dT0_dVb = 2.0 * (T8 * (2.0 / Abulk * dAbulk_dVb + tmp3) + + (1.0 / Lambda - 1.0) * dAbulk_dVb); + dT0_dVd = 0.0; + T1 = Vgst2Vtm * (2.0 / Lambda - 1.0) + Abulk * EsatL + 3.0 * T7; + + dT1_dVg = (2.0 / Lambda - 1.0) - 2.0 * Vgst2Vtm * tmp1 + + Abulk * dEsatL_dVg + EsatL * dAbulk_dVg + 3.0 * (T9 + + T7 * tmp2 + T6 * dAbulk_dVg); + dT1_dVb = Abulk * dEsatL_dVb + EsatL * dAbulk_dVb + + 3.0 * (T6 * dAbulk_dVb + T7 * tmp3); + dT1_dVd = Abulk * dEsatL_dVd; + + T2 = Vgst2Vtm * (EsatL + 2.0 * T6); + dT2_dVg = EsatL + Vgst2Vtm * dEsatL_dVg + + T6 * (4.0 + 2.0 * Vgst2Vtm * tmp2); + dT2_dVb = Vgst2Vtm * (dEsatL_dVb + 2.0 * T6 * tmp3); + dT2_dVd = Vgst2Vtm * dEsatL_dVd; + + T3 = sqrt(T1 * T1 - 2.0 * T0 * T2); + Vdsat = (T1 - T3) / T0; + + dT3_dVg = (T1 * dT1_dVg - 2.0 * (T0 * dT2_dVg + T2 * dT0_dVg)) + / T3; + dT3_dVd = (T1 * dT1_dVd - 2.0 * (T0 * dT2_dVd + T2 * dT0_dVd)) + / T3; + dT3_dVb = (T1 * dT1_dVb - 2.0 * (T0 * dT2_dVb + T2 * dT0_dVb)) + / T3; + + dVdsat_dVg = (dT1_dVg - (T1 * dT1_dVg - dT0_dVg * T2 + - T0 * dT2_dVg) / T3 - Vdsat * dT0_dVg) / T0; + dVdsat_dVb = (dT1_dVb - (T1 * dT1_dVb - dT0_dVb * T2 + - T0 * dT2_dVb) / T3 - Vdsat * dT0_dVb) / T0; + dVdsat_dVd = (dT1_dVd - (T1 * dT1_dVd - T0 * dT2_dVd) / T3) / T0; + } + here->BSIM4vdsat = Vdsat; + + /* Calculate Vdseff */ + T1 = Vdsat - Vds - pParam->BSIM4delta; + dT1_dVg = dVdsat_dVg; + dT1_dVd = dVdsat_dVd - 1.0; + dT1_dVb = dVdsat_dVb; + + T2 = sqrt(T1 * T1 + 4.0 * pParam->BSIM4delta * Vdsat); + T0 = T1 / T2; + T9 = 2.0 * pParam->BSIM4delta; + T3 = T9 / T2; + dT2_dVg = T0 * dT1_dVg + T3 * dVdsat_dVg; + dT2_dVd = T0 * dT1_dVd + T3 * dVdsat_dVd; + dT2_dVb = T0 * dT1_dVb + T3 * dVdsat_dVb; + + if (T1 >= 0.0) + { Vdseff = Vdsat - 0.5 * (T1 + T2); + dVdseff_dVg = dVdsat_dVg - 0.5 * (dT1_dVg + dT2_dVg); + dVdseff_dVd = dVdsat_dVd - 0.5 * (dT1_dVd + dT2_dVd); + dVdseff_dVb = dVdsat_dVb - 0.5 * (dT1_dVb + dT2_dVb); + } + else + { T4 = T9 / (T2 - T1); + T5 = 1.0 - T4; + T6 = Vdsat * T4 / (T2 - T1); + Vdseff = Vdsat * T5; + dVdseff_dVg = dVdsat_dVg * T5 + T6 * (dT2_dVg - dT1_dVg); + dVdseff_dVd = dVdsat_dVd * T5 + T6 * (dT2_dVd - dT1_dVd); + dVdseff_dVb = dVdsat_dVb * T5 + T6 * (dT2_dVb - dT1_dVb); + } + + if (Vds == 0.0) + { Vdseff = 0.0; + dVdseff_dVg = 0.0; + dVdseff_dVb = 0.0; + } + + if (Vdseff > Vds) + Vdseff = Vds; + diffVds = Vds - Vdseff; + here->BSIM4Vdseff = Vdseff; + + /* Calculate Vasat */ + tmp4 = 1.0 - 0.5 * Abulk * Vdsat / Vgst2Vtm; + T9 = WVCoxRds * Vgsteff; + T8 = T9 / Vgst2Vtm; + T0 = EsatL + Vdsat + 2.0 * T9 * tmp4; + + T7 = 2.0 * WVCoxRds * tmp4; + dT0_dVg = dEsatL_dVg + dVdsat_dVg + T7 * (1.0 + tmp2 * Vgsteff) + - T8 * (Abulk * dVdsat_dVg - Abulk * Vdsat / Vgst2Vtm + + Vdsat * dAbulk_dVg); + + dT0_dVb = dEsatL_dVb + dVdsat_dVb + T7 * tmp3 * Vgsteff + - T8 * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = dEsatL_dVd + dVdsat_dVd - T8 * Abulk * dVdsat_dVd; + + T9 = WVCoxRds * Abulk; + T1 = 2.0 / Lambda - 1.0 + T9; + dT1_dVg = -2.0 * tmp1 + WVCoxRds * (Abulk * tmp2 + dAbulk_dVg); + dT1_dVb = dAbulk_dVb * WVCoxRds + T9 * tmp3; + + Vasat = T0 / T1; + dVasat_dVg = (dT0_dVg - Vasat * dT1_dVg) / T1; + dVasat_dVb = (dT0_dVb - Vasat * dT1_dVb) / T1; + dVasat_dVd = dT0_dVd / T1; + + /* Calculate Idl first */ + tmp1 = pParam->BSIM4vtfbphi2; + tmp2 = 2.0e8 * model->BSIM4toxp; + dT0_dVg = 1.0 / tmp2; + T0 = (Vgsteff + tmp1) * dT0_dVg; + + tmp3 = exp(0.7 * log(T0)); + T1 = 1.0 + tmp3; + T2 = 0.7 * tmp3 / T0; + Tcen = 1.9e-9 / T1; + dTcen_dVg = -Tcen * T2 * dT0_dVg / T1; + + Coxeff = EPSSI * model->BSIM4coxp + / (EPSSI + model->BSIM4coxp * Tcen); + dCoxeff_dVg = -Coxeff * Coxeff * dTcen_dVg / EPSSI; + + CoxeffWovL = Coxeff * Weff / Leff; + beta = ueff * CoxeffWovL; + T3 = ueff / Leff; + dbeta_dVg = CoxeffWovL * dueff_dVg + T3 + * (Weff * dCoxeff_dVg + Coxeff * dWeff_dVg); + dbeta_dVd = CoxeffWovL * dueff_dVd; + dbeta_dVb = CoxeffWovL * dueff_dVb + T3 * Coxeff * dWeff_dVb; + + here->BSIM4AbovVgst2Vtm = Abulk / Vgst2Vtm; + T0 = 1.0 - 0.5 * Vdseff * here->BSIM4AbovVgst2Vtm; + dT0_dVg = -0.5 * (Abulk * dVdseff_dVg + - Abulk * Vdseff / Vgst2Vtm + Vdseff * dAbulk_dVg) / Vgst2Vtm; + dT0_dVd = -0.5 * Abulk * dVdseff_dVd / Vgst2Vtm; + dT0_dVb = -0.5 * (Abulk * dVdseff_dVb + dAbulk_dVb * Vdseff) + / Vgst2Vtm; + + fgche1 = Vgsteff * T0; + dfgche1_dVg = Vgsteff * dT0_dVg + T0; + dfgche1_dVd = Vgsteff * dT0_dVd; + dfgche1_dVb = Vgsteff * dT0_dVb; + + T9 = Vdseff / EsatL; + fgche2 = 1.0 + T9; + dfgche2_dVg = (dVdseff_dVg - T9 * dEsatL_dVg) / EsatL; + dfgche2_dVd = (dVdseff_dVd - T9 * dEsatL_dVd) / EsatL; + dfgche2_dVb = (dVdseff_dVb - T9 * dEsatL_dVb) / EsatL; + + gche = beta * fgche1 / fgche2; + dgche_dVg = (beta * dfgche1_dVg + fgche1 * dbeta_dVg + - gche * dfgche2_dVg) / fgche2; + dgche_dVd = (beta * dfgche1_dVd + fgche1 * dbeta_dVd + - gche * dfgche2_dVd) / fgche2; + dgche_dVb = (beta * dfgche1_dVb + fgche1 * dbeta_dVb + - gche * dfgche2_dVb) / fgche2; + + T0 = 1.0 + gche * Rds; + Idl = gche / T0; + T1 = (1.0 - Idl * Rds) / T0; + T2 = Idl * Idl; + dIdl_dVg = T1 * dgche_dVg - T2 * dRds_dVg; + dIdl_dVd = T1 * dgche_dVd; + dIdl_dVb = T1 * dgche_dVb - T2 * dRds_dVb; + + /* Calculate degradation factor due to pocket implant */ + + if (pParam->BSIM4fprout <= 0.0) + { FP = 1.0; + dFP_dVg = 0.0; + } + else + { T9 = pParam->BSIM4fprout * sqrt(Leff) / Vgst2Vtm; + FP = 1.0 / (1.0 + T9); + dFP_dVg = FP * FP * T9 / Vgst2Vtm; + } + + /* Calculate VACLM */ + T8 = pParam->BSIM4pvag / EsatL; + T9 = T8 * Vgsteff; + if (T9 > -0.9) + { PvagTerm = 1.0 + T9; + dPvagTerm_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL); + dPvagTerm_dVb = -T9 * dEsatL_dVb / EsatL; + dPvagTerm_dVd = -T9 * dEsatL_dVd / EsatL; + } + else + { T4 = 1.0 / (17.0 + 20.0 * T9); + PvagTerm = (0.8 + T9) * T4; + T4 *= T4; + dPvagTerm_dVg = T8 * (1.0 - Vgsteff * dEsatL_dVg / EsatL) * T4; + T9 *= T4 / EsatL; + dPvagTerm_dVb = -T9 * dEsatL_dVb; + dPvagTerm_dVd = -T9 * dEsatL_dVd; + } + + if ((pParam->BSIM4pclm > 0.0) && (diffVds > 1.0e-10)) + { T0 = 1.0 + Rds * Idl; + dT0_dVg = dRds_dVg * Idl + Rds * dIdl_dVg; + dT0_dVd = Rds * dIdl_dVd; + dT0_dVb = dRds_dVb * Idl + Rds * dIdl_dVb; + + T2 = Vdsat / Esat; + T1 = Leff + T2; + dT1_dVg = (dVdsat_dVg - T2 * dEsatL_dVg / Leff) / Esat; + dT1_dVd = (dVdsat_dVd - T2 * dEsatL_dVd / Leff) / Esat; + dT1_dVb = (dVdsat_dVb - T2 * dEsatL_dVb / Leff) / Esat; + + Cclm = FP * PvagTerm * T0 * T1 / (pParam->BSIM4pclm * pParam->BSIM4litl); + dCclm_dVg = Cclm * (dFP_dVg / FP + dPvagTerm_dVg / PvagTerm + + dT0_dVg / T0 + dT1_dVg / T1); + dCclm_dVb = Cclm * (dPvagTerm_dVb / PvagTerm + dT0_dVb / T0 + + dT1_dVb / T1); + dCclm_dVd = Cclm * (dPvagTerm_dVd / PvagTerm + dT0_dVd / T0 + + dT1_dVd / T1); + VACLM = Cclm * diffVds; + + dVACLM_dVg = dCclm_dVg * diffVds - dVdseff_dVg * Cclm; + dVACLM_dVb = dCclm_dVb * diffVds - dVdseff_dVb * Cclm; + dVACLM_dVd = dCclm_dVd * diffVds + (1.0 - dVdseff_dVd) * Cclm; + } + else + { VACLM = Cclm = MAX_EXP; + dVACLM_dVd = dVACLM_dVg = dVACLM_dVb = 0.0; + dCclm_dVd = dCclm_dVg = dCclm_dVb = 0.0; + } + + /* Calculate VADIBL */ + if (pParam->BSIM4thetaRout > 0.0) + { T8 = Abulk * Vdsat; + T0 = Vgst2Vtm * T8; + dT0_dVg = Vgst2Vtm * Abulk * dVdsat_dVg + T8 + + Vgst2Vtm * Vdsat * dAbulk_dVg; + dT0_dVb = Vgst2Vtm * (dAbulk_dVb * Vdsat + Abulk * dVdsat_dVb); + dT0_dVd = Vgst2Vtm * Abulk * dVdsat_dVd; + + T1 = Vgst2Vtm + T8; + dT1_dVg = 1.0 + Abulk * dVdsat_dVg + Vdsat * dAbulk_dVg; + dT1_dVb = Abulk * dVdsat_dVb + dAbulk_dVb * Vdsat; + dT1_dVd = Abulk * dVdsat_dVd; + + T9 = T1 * T1; + T2 = pParam->BSIM4thetaRout; + VADIBL = (Vgst2Vtm - T0 / T1) / T2; + dVADIBL_dVg = (1.0 - dT0_dVg / T1 + T0 * dT1_dVg / T9) / T2; + dVADIBL_dVb = (-dT0_dVb / T1 + T0 * dT1_dVb / T9) / T2; + dVADIBL_dVd = (-dT0_dVd / T1 + T0 * dT1_dVd / T9) / T2; + + T7 = pParam->BSIM4pdiblb * Vbseff; + if (T7 >= -0.9) + { T3 = 1.0 / (1.0 + T7); + VADIBL *= T3; + dVADIBL_dVg *= T3; + dVADIBL_dVb = (dVADIBL_dVb - VADIBL * pParam->BSIM4pdiblb) + * T3; + dVADIBL_dVd *= T3; + } + else + { T4 = 1.0 / (0.8 + T7); + T3 = (17.0 + 20.0 * T7) * T4; + dVADIBL_dVg *= T3; + dVADIBL_dVb = dVADIBL_dVb * T3 + - VADIBL * pParam->BSIM4pdiblb * T4 * T4; + dVADIBL_dVd *= T3; + VADIBL *= T3; + } + + dVADIBL_dVg = dVADIBL_dVg * PvagTerm + VADIBL * dPvagTerm_dVg; + dVADIBL_dVb = dVADIBL_dVb * PvagTerm + VADIBL * dPvagTerm_dVb; + dVADIBL_dVd = dVADIBL_dVd * PvagTerm + VADIBL * dPvagTerm_dVd; + VADIBL *= PvagTerm; + } + else + { VADIBL = MAX_EXP; + dVADIBL_dVd = dVADIBL_dVg = dVADIBL_dVb = 0.0; + } + + /* Calculate Va */ + Va = Vasat + VACLM; + dVa_dVg = dVasat_dVg + dVACLM_dVg; + dVa_dVb = dVasat_dVb + dVACLM_dVb; + dVa_dVd = dVasat_dVd + dVACLM_dVd; + + /* Calculate VADITS */ + T0 = pParam->BSIM4pditsd * Vds; + if (T0 > EXP_THRESHOLD) + { T1 = MAX_EXP; + dT1_dVd = 0; + } + else + { T1 = exp(T0); + dT1_dVd = T1 * pParam->BSIM4pditsd; + } + + if (pParam->BSIM4pdits > 0.0) + { T2 = 1.0 + model->BSIM4pditsl * Leff; + VADITS = (1.0 + T2 * T1) / pParam->BSIM4pdits; + dVADITS_dVg = VADITS * dFP_dVg; + dVADITS_dVd = FP * T2 * dT1_dVd / pParam->BSIM4pdits; + VADITS *= FP; + } + else + { VADITS = MAX_EXP; + dVADITS_dVg = dVADITS_dVd = 0; + } + + /* Calculate VASCBE */ + if (pParam->BSIM4pscbe2 > 0.0) + { if (diffVds > pParam->BSIM4pscbe1 * pParam->BSIM4litl + / EXP_THRESHOLD) + { T0 = pParam->BSIM4pscbe1 * pParam->BSIM4litl / diffVds; + VASCBE = Leff * exp(T0) / pParam->BSIM4pscbe2; + T1 = T0 * VASCBE / diffVds; + dVASCBE_dVg = T1 * dVdseff_dVg; + dVASCBE_dVd = -T1 * (1.0 - dVdseff_dVd); + dVASCBE_dVb = T1 * dVdseff_dVb; + } + else + { VASCBE = MAX_EXP * Leff/pParam->BSIM4pscbe2; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + } + else + { VASCBE = MAX_EXP; + dVASCBE_dVg = dVASCBE_dVd = dVASCBE_dVb = 0.0; + } + + /* Add DIBL to Ids */ + T9 = diffVds / VADIBL; + T0 = 1.0 + T9; + Idsa = Idl * T0; + dIdsa_dVg = T0 * dIdl_dVg - Idl * (dVdseff_dVg + T9 * dVADIBL_dVg) / VADIBL; + dIdsa_dVd = T0 * dIdl_dVd + Idl + * (1.0 - dVdseff_dVd - T9 * dVADIBL_dVd) / VADIBL; + dIdsa_dVb = T0 * dIdl_dVb - Idl * (dVdseff_dVb + T9 * dVADIBL_dVb) / VADIBL; + + /* Add DITS to Ids */ + T9 = diffVds / VADITS; + T0 = 1.0 + T9; + dIdsa_dVg = T0 * dIdsa_dVg - Idsa * (dVdseff_dVg + T9 * dVADITS_dVg) / VADITS; + dIdsa_dVd = T0 * dIdsa_dVd + Idsa + * (1.0 - dVdseff_dVd - T9 * dVADITS_dVd) / VADITS; + dIdsa_dVb = T0 * dIdsa_dVb - Idsa * dVdseff_dVb / VADITS; + Idsa *= T0; + + /* Add CLM to Ids */ + T0 = log(Va / Vasat); + dT0_dVg = dVa_dVg / Va - dVasat_dVg / Vasat; + dT0_dVb = dVa_dVb / Va - dVasat_dVb / Vasat; + dT0_dVd = dVa_dVd / Va - dVasat_dVd / Vasat; + T1 = T0 / Cclm; + T9 = 1.0 + T1; + dT9_dVg = (dT0_dVg - T1 * dCclm_dVg) / Cclm; + dT9_dVb = (dT0_dVb - T1 * dCclm_dVb) / Cclm; + dT9_dVd = (dT0_dVd - T1 * dCclm_dVd) / Cclm; + + dIdsa_dVg = dIdsa_dVg * T9 + Idsa * dT9_dVg; + dIdsa_dVb = dIdsa_dVb * T9 + Idsa * dT9_dVb; + dIdsa_dVd = dIdsa_dVd * T9 + Idsa * dT9_dVd; + Idsa *= T9; + + /* Substrate current begins */ + tmp = pParam->BSIM4alpha0 + pParam->BSIM4alpha1 * Leff; + if ((tmp <= 0.0) || (pParam->BSIM4beta0 <= 0.0)) + { Isub = Gbd = Gbb = Gbg = 0.0; + } + else + { T2 = tmp / Leff; + if (diffVds > pParam->BSIM4beta0 / EXP_THRESHOLD) + { T0 = -pParam->BSIM4beta0 / diffVds; + T1 = T2 * diffVds * exp(T0); + T3 = T1 / diffVds * (T0 - 1.0); + dT1_dVg = T3 * dVdseff_dVg; + dT1_dVd = T3 * (dVdseff_dVd - 1.0); + dT1_dVb = T3 * dVdseff_dVb; + } + else + { T3 = T2 * MIN_EXP; + T1 = T3 * diffVds; + dT1_dVg = -T3 * dVdseff_dVg; + dT1_dVd = T3 * (1.0 - dVdseff_dVd); + dT1_dVb = -T3 * dVdseff_dVb; + } + T4 = Idsa * Vdseff; + Isub = T1 * T4; + Gbg = T1 * (dIdsa_dVg * Vdseff + Idsa * dVdseff_dVg) + + T4 * dT1_dVg; + Gbd = T1 * (dIdsa_dVd * Vdseff + Idsa * dVdseff_dVd) + + T4 * dT1_dVd; + Gbb = T1 * (dIdsa_dVb * Vdseff + Idsa * dVdseff_dVb) + + T4 * dT1_dVb; + + Gbd += Gbg * dVgsteff_dVd; + Gbb += Gbg * dVgsteff_dVb; + Gbg *= dVgsteff_dVg; + Gbb *= dVbseff_dVb; + } + here->BSIM4csub = Isub; + here->BSIM4gbbs = Gbb; + here->BSIM4gbgs = Gbg; + here->BSIM4gbds = Gbd; + + /* Add SCBE to Ids */ + T9 = diffVds / VASCBE; + T0 = 1.0 + T9; + Ids = Idsa * T0; + + Gm = T0 * dIdsa_dVg - Idsa + * (dVdseff_dVg + T9 * dVASCBE_dVg) / VASCBE; + Gds = T0 * dIdsa_dVd + Idsa + * (1.0 - dVdseff_dVd - T9 * dVASCBE_dVd) / VASCBE; + Gmb = T0 * dIdsa_dVb - Idsa + * (dVdseff_dVb + T9 * dVASCBE_dVb) / VASCBE; + + tmp1 = Gds + Gm * dVgsteff_dVd; + tmp2 = Gmb + Gm * dVgsteff_dVb; + tmp3 = Gm; + + Gm = (Ids * dVdseff_dVg + Vdseff * tmp3) * dVgsteff_dVg; + Gds = Ids * (dVdseff_dVd + dVdseff_dVg * dVgsteff_dVd) + + Vdseff * tmp1; + Gmb = (Ids * (dVdseff_dVb + dVdseff_dVg * dVgsteff_dVb) + + Vdseff * tmp2) * dVbseff_dVb; + + cdrain = Ids * Vdseff; + here->BSIM4gds = Gds; + here->BSIM4gm = Gm; + here->BSIM4gmbs = Gmb; + here->BSIM4IdovVds = Ids; + + /* Calculate Rg */ + if ((here->BSIM4rgateMod > 1) || + (here->BSIM4trnqsMod != 0) || (here->BSIM4acnqsMod != 0)) + { T9 = pParam->BSIM4xrcrg2 * model->BSIM4vtm; + T0 = T9 * beta; + dT0_dVd = (dbeta_dVd + dbeta_dVg * dVgsteff_dVd) * T9; + dT0_dVb = (dbeta_dVb + dbeta_dVg * dVgsteff_dVb) * T9; + dT0_dVg = dbeta_dVg * T9; + + here->BSIM4gcrg = pParam->BSIM4xrcrg1 * ( T0 + Ids); + here->BSIM4gcrgd = pParam->BSIM4xrcrg1 * (dT0_dVd + tmp1); + here->BSIM4gcrgb = pParam->BSIM4xrcrg1 * (dT0_dVb + tmp2) + * dVbseff_dVb; + here->BSIM4gcrgg = pParam->BSIM4xrcrg1 * (dT0_dVg + tmp3) + * dVgsteff_dVg; + + if (here->BSIM4nf != 1.0) + { here->BSIM4gcrg *= here->BSIM4nf; + here->BSIM4gcrgg *= here->BSIM4nf; + here->BSIM4gcrgd *= here->BSIM4nf; + here->BSIM4gcrgb *= here->BSIM4nf; + } + + if (here->BSIM4rgateMod == 2) + { T10 = here->BSIM4grgeltd * here->BSIM4grgeltd; + T11 = here->BSIM4grgeltd + here->BSIM4gcrg; + here->BSIM4gcrg = here->BSIM4grgeltd * here->BSIM4gcrg / T11; + T12 = T10 / T11 / T11; + here->BSIM4gcrgg *= T12; + here->BSIM4gcrgd *= T12; + here->BSIM4gcrgb *= T12; + } + here->BSIM4gcrgs = -(here->BSIM4gcrgg + here->BSIM4gcrgd + + here->BSIM4gcrgb); + } + + + /* Calculate bias-dependent external S/D resistance */ + if (model->BSIM4rdsMod) + { /* Rs(V) */ + T0 = vgs - pParam->BSIM4vfbsd; + T1 = sqrt(T0 * T0 + 1.0e-4); + vgs_eff = 0.5 * (T0 + T1); + dvgs_eff_dvg = vgs_eff / T1; + + T0 = 1.0 + pParam->BSIM4prwg * vgs_eff; + dT0_dvg = -pParam->BSIM4prwg / T0 / T0 * dvgs_eff_dvg; + T1 = -pParam->BSIM4prwb * vbs; + dT1_dvb = -pParam->BSIM4prwb; + + T2 = 1.0 / T0 + T1; + T3 = T2 + sqrt(T2 * T2 + 0.01); + dT3_dvg = T3 / (T3 - T2); + dT3_dvb = dT3_dvg * dT1_dvb; + dT3_dvg *= dT0_dvg; + + T4 = pParam->BSIM4rs0 * 0.5; + Rs = pParam->BSIM4rswmin + T3 * T4; + dRs_dvg = T4 * dT3_dvg; + dRs_dvb = T4 * dT3_dvb; + + T0 = 1.0 + here->BSIM4sourceConductance * Rs; + here->BSIM4gstot = here->BSIM4sourceConductance / T0; + T0 = -here->BSIM4gstot * here->BSIM4gstot; + dgstot_dvd = 0.0; /* place holder */ + dgstot_dvg = T0 * dRs_dvg; + dgstot_dvb = T0 * dRs_dvb; + dgstot_dvs = -(dgstot_dvg + dgstot_dvb + dgstot_dvd); + + /* Rd(V) */ + T0 = vgd - pParam->BSIM4vfbsd; + T1 = sqrt(T0 * T0 + 1.0e-4); + vgd_eff = 0.5 * (T0 + T1); + dvgd_eff_dvg = vgd_eff / T1; + + T0 = 1.0 + pParam->BSIM4prwg * vgd_eff; + dT0_dvg = -pParam->BSIM4prwg / T0 / T0 * dvgd_eff_dvg; + T1 = -pParam->BSIM4prwb * vbd; + dT1_dvb = -pParam->BSIM4prwb; + + T2 = 1.0 / T0 + T1; + T3 = T2 + sqrt(T2 * T2 + 0.01); + dT3_dvg = T3 / (T3 - T2); + dT3_dvb = dT3_dvg * dT1_dvb; + dT3_dvg *= dT0_dvg; + + T4 = pParam->BSIM4rd0 * 0.5; + Rd = pParam->BSIM4rdwmin + T3 * T4; + dRd_dvg = T4 * dT3_dvg; + dRd_dvb = T4 * dT3_dvb; + + T0 = 1.0 + here->BSIM4drainConductance * Rd; + here->BSIM4gdtot = here->BSIM4drainConductance / T0; + T0 = -here->BSIM4gdtot * here->BSIM4gdtot; + dgdtot_dvs = 0.0; + dgdtot_dvg = T0 * dRd_dvg; + dgdtot_dvb = T0 * dRd_dvb; + dgdtot_dvd = -(dgdtot_dvg + dgdtot_dvb + dgdtot_dvs); + + here->BSIM4gstotd = vses * dgstot_dvd; + here->BSIM4gstotg = vses * dgstot_dvg; + here->BSIM4gstots = vses * dgstot_dvs; + here->BSIM4gstotb = vses * dgstot_dvb; + + T2 = vdes - vds; + here->BSIM4gdtotd = T2 * dgdtot_dvd; + here->BSIM4gdtotg = T2 * dgdtot_dvg; + here->BSIM4gdtots = T2 * dgdtot_dvs; + here->BSIM4gdtotb = T2 * dgdtot_dvb; + } + else /* WDLiu: for bypass */ + { here->BSIM4gstot = here->BSIM4gstotd = here->BSIM4gstotg = 0.0; + here->BSIM4gstots = here->BSIM4gstotb = 0.0; + here->BSIM4gdtot = here->BSIM4gdtotd = here->BSIM4gdtotg = 0.0; + here->BSIM4gdtots = here->BSIM4gdtotb = 0.0; + } + + /* Calculate GIDL current */ + T0 = 3.0 * model->BSIM4toxe; + T1 = (Vds - Vgs_eff - pParam->BSIM4egidl) / T0; + if ((pParam->BSIM4agidl <= 0.0) || (pParam->BSIM4bgidl <= 0.0) || (T1 < 0.0) + || (pParam->BSIM4cgidl <= 0.0) || (Vdb < 0.0)) + Igidl = Ggidld = Ggidlg = Ggidlb = 0.0; + else + { dT1_dVd = 1.0 / T0; + dT1_dVg = -dVgs_eff_dVg * dT1_dVd; + T2 = pParam->BSIM4bgidl / T1; + if (T2 < 100.0) + { Igidl = pParam->BSIM4agidl * pParam->BSIM4weffCJ * T1 * exp(-T2); + T3 = Igidl * (1.0 + T2) / T1; + Ggidld = T3 * dT1_dVd; + Ggidlg = T3 * dT1_dVg; + } + else + { Igidl = pParam->BSIM4agidl * pParam->BSIM4weffCJ * 3.720075976e-44; + Ggidld = Igidl * dT1_dVd; + Ggidlg = Igidl * dT1_dVg; + Igidl *= T1; + } + + T4 = Vdb * Vdb; + T5 = Vdb * T4; + T6 = pParam->BSIM4cgidl + T5; + T7 = T5 / T6; + T8 = 3.0 * pParam->BSIM4cgidl * T4 / T6 / T6; + Ggidld = Ggidld * T7 + Igidl * T8; + Ggidlg = Ggidlg * T7; + Ggidlb = -Igidl * T8; + Igidl *= T7; + } + here->BSIM4Igidl = Igidl; + here->BSIM4ggidld = Ggidld; + here->BSIM4ggidlg = Ggidlg; + here->BSIM4ggidlb = Ggidlb; + + + /* Calculate gate tunneling current */ + if ((model->BSIM4igcMod != 0) || (model->BSIM4igbMod != 0)) + { Vfb = pParam->BSIM4vfbzb; + V3 = Vfb - Vgs_eff + Vbseff - DELTA_3; + if (Vfb <= 0.0) + T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); + else + T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = Vfb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1; /* WDLiu: -No surprise? No. -Good! */ + + Voxacc = Vfb - Vfbeff; + dVoxacc_dVg = -dVfbeff_dVg; + dVoxacc_dVb = -dVfbeff_dVb; + if (Voxacc < 0.0) /* WDLiu: Avoiding numerical instability. */ + Voxacc = dVoxacc_dVg = dVoxacc_dVb = 0.0; + + T0 = 0.5 * pParam->BSIM4k1ox; + T3 = Vgs_eff - Vfbeff - Vbseff - Vgsteff; + if (pParam->BSIM4k1ox == 0.0) + Voxdepinv = dVoxdepinv_dVg = dVoxdepinv_dVd + = dVoxdepinv_dVb = 0.0; + else if (T3 < 0.0) + { Voxdepinv = -T3; + dVoxdepinv_dVg = -dVgs_eff_dVg + dVfbeff_dVg + + dVgsteff_dVg; + dVoxdepinv_dVd = dVgsteff_dVd; + dVoxdepinv_dVb = dVfbeff_dVb + 1.0 + dVgsteff_dVb; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = T0 / T1; + Voxdepinv = pParam->BSIM4k1ox * (T1 - T0); + dVoxdepinv_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg + - dVgsteff_dVg); + dVoxdepinv_dVd = -T2 * dVgsteff_dVd; + dVoxdepinv_dVb = -T2 * (dVfbeff_dVb + 1.0 + dVgsteff_dVb); + } + + Voxdepinv += Vgsteff; + dVoxdepinv_dVg += dVgsteff_dVg; + dVoxdepinv_dVd += dVgsteff_dVd; + dVoxdepinv_dVb += dVgsteff_dVb; + } + + if (model->BSIM4igcMod) + { T0 = Vtm * pParam->BSIM4nigc; + VxNVt = (Vgs_eff - model->BSIM4type * pParam->BSIM4vth0) / T0; /* Vth instead of Vth0 may be used */ + if (VxNVt > EXP_THRESHOLD) + { Vaux = Vgs_eff - model->BSIM4type * pParam->BSIM4vth0; + dVaux_dVg = dVgs_eff_dVg; + dVaux_dVd = 0.0; + dVaux_dVb = 0.0; + } + else if (VxNVt < -EXP_THRESHOLD) + { Vaux = T0 * log(1.0 + MIN_EXP); + dVaux_dVg = dVaux_dVd = dVaux_dVb = 0.0; + } + else + { ExpVxNVt = exp(VxNVt); + Vaux = T0 * log(1.0 + ExpVxNVt); + dVaux_dVg = ExpVxNVt / (1.0 + ExpVxNVt); + dVaux_dVd = -dVaux_dVg * 0.0; + dVaux_dVb = -dVaux_dVg * 0.0; + dVaux_dVg *= dVgs_eff_dVg; + } + + T2 = Vgs_eff * Vaux; + dT2_dVg = dVgs_eff_dVg * Vaux + Vgs_eff * dVaux_dVg; + dT2_dVd = Vgs_eff * dVaux_dVd; + dT2_dVb = Vgs_eff * dVaux_dVb; + + T11 = pParam->BSIM4Aechvb; + T12 = pParam->BSIM4Bechvb; + T3 = pParam->BSIM4aigc * pParam->BSIM4cigc + - pParam->BSIM4bigc; + T4 = pParam->BSIM4bigc * pParam->BSIM4cigc; + T5 = T12 * (pParam->BSIM4aigc + T3 * Voxdepinv + - T4 * Voxdepinv * Voxdepinv); + + if (T5 > EXP_THRESHOLD) + { T6 = MAX_EXP; + dT6_dVg = dT6_dVd = dT6_dVb = 0.0; + } + else if (T5 < -EXP_THRESHOLD) + { T6 = MIN_EXP; + dT6_dVg = dT6_dVd = dT6_dVb = 0.0; + } + else + { T6 = exp(T5); + dT6_dVg = T6 * T12 * (T3 - 2.0 * T4 * Voxdepinv); + dT6_dVd = dT6_dVg * dVoxdepinv_dVd; + dT6_dVb = dT6_dVg * dVoxdepinv_dVb; + dT6_dVg *= dVoxdepinv_dVg; + } + + Igc = T11 * T2 * T6; + dIgc_dVg = T11 * (T2 * dT6_dVg + T6 * dT2_dVg); + dIgc_dVd = T11 * (T2 * dT6_dVd + T6 * dT2_dVd); + dIgc_dVb = T11 * (T2 * dT6_dVb + T6 * dT2_dVb); + + T7 = -pParam->BSIM4pigcd * Vds; + T8 = T7 * T7 + 2.0e-4; + dT8_dVd = -2.0 * pParam->BSIM4pigcd * T7; + if (T7 > EXP_THRESHOLD) + { T9 = MAX_EXP; + dT9_dVd = 0.0; + } + else if (T7 < -EXP_THRESHOLD) + { T9 = MIN_EXP; + dT9_dVd = 0.0; + } + else + { T9 = exp(T7); + dT9_dVd = -T9 * pParam->BSIM4pigcd; + } + + T0 = T8 * T8; + T1 = T9 - 1.0 + 1.0e-4; + T10 = (T1 - T7) / T8; + dT10_dVd = ((pParam->BSIM4pigcd + dT9_dVd) * T8 + - (T1 - T7) * dT8_dVd) / T0; + Igcs = Igc * T10; + dIgcs_dVg = dIgc_dVg * T10; + dIgcs_dVd = dIgc_dVd * T10 + Igc * dT10_dVd; + dIgcs_dVb = dIgc_dVb * T10; + + T1 = T9 - 1.0 - 1.0e-4; + T10 = (T7 * T9 - T1) / T8; + dT10_dVd = (-pParam->BSIM4pigcd * T9 + (T7 - 1.0) + * dT9_dVd - T10 * dT8_dVd) / T8; + Igcd = Igc * T10; + dIgcd_dVg = dIgc_dVg * T10; + dIgcd_dVd = dIgc_dVd * T10 + Igc * dT10_dVd; + dIgcd_dVb = dIgc_dVb * T10; + + here->BSIM4Igcs = Igcs; + here->BSIM4gIgcsg = dIgcs_dVg; + here->BSIM4gIgcsd = dIgcs_dVd; + here->BSIM4gIgcsb = dIgcs_dVb * dVbseff_dVb; + here->BSIM4Igcd = Igcd; + here->BSIM4gIgcdg = dIgcd_dVg; + here->BSIM4gIgcdd = dIgcd_dVd; + here->BSIM4gIgcdb = dIgcd_dVb * dVbseff_dVb; + + + T0 = vgs - pParam->BSIM4vfbsd; + vgs_eff = sqrt(T0 * T0 + 1.0e-4); + dvgs_eff_dvg = T0 / vgs_eff; + + T2 = vgs * vgs_eff; + dT2_dVg = vgs * dvgs_eff_dvg + vgs_eff; + T11 = pParam->BSIM4AechvbEdge; + T12 = pParam->BSIM4BechvbEdge; + T3 = pParam->BSIM4aigsd * pParam->BSIM4cigsd + - pParam->BSIM4bigsd; + T4 = pParam->BSIM4bigsd * pParam->BSIM4cigsd; + T5 = T12 * (pParam->BSIM4aigsd + T3 * vgs_eff + - T4 * vgs_eff * vgs_eff); + if (T5 > EXP_THRESHOLD) + { T6 = MAX_EXP; + dT6_dVg = 0.0; + } + else if (T5 < -EXP_THRESHOLD) + { T6 = MIN_EXP; + dT6_dVg = 0.0; + } + else + { T6 = exp(T5); + dT6_dVg = T6 * T12 * (T3 - 2.0 * T4 * vgs_eff) + * dvgs_eff_dvg; + } + Igs = T11 * T2 * T6; + dIgs_dVg = T11 * (T2 * dT6_dVg + T6 * dT2_dVg); + dIgs_dVs = -dIgs_dVg; + + + T0 = vgd - pParam->BSIM4vfbsd; + vgd_eff = sqrt(T0 * T0 + 1.0e-4); + dvgd_eff_dvg = T0 / vgd_eff; + + T2 = vgd * vgd_eff; + dT2_dVg = vgd * dvgd_eff_dvg + vgd_eff; + T5 = T12 * (pParam->BSIM4aigsd + T3 * vgd_eff + - T4 * vgd_eff * vgd_eff); + if (T5 > EXP_THRESHOLD) + { T6 = MAX_EXP; + dT6_dVg = 0.0; + } + else if (T5 < -EXP_THRESHOLD) + { T6 = MIN_EXP; + dT6_dVg = 0.0; + } + else + { T6 = exp(T5); + dT6_dVg = T6 * T12 * (T3 - 2.0 * T4 * vgd_eff) + * dvgd_eff_dvg; + } + Igd = T11 * T2 * T6; + dIgd_dVg = T11 * (T2 * dT6_dVg + T6 * dT2_dVg); + dIgd_dVd = -dIgd_dVg; + + here->BSIM4Igs = Igs; + here->BSIM4gIgsg = dIgs_dVg; + here->BSIM4gIgss = dIgs_dVs; + here->BSIM4Igd = Igd; + here->BSIM4gIgdg = dIgd_dVg; + here->BSIM4gIgdd = dIgd_dVd; + } + else + { here->BSIM4Igcs = here->BSIM4gIgcsg = here->BSIM4gIgcsd + = here->BSIM4gIgcsb = 0.0; + here->BSIM4Igcd = here->BSIM4gIgcdg = here->BSIM4gIgcdd + = here->BSIM4gIgcdb = 0.0; + here->BSIM4Igs = here->BSIM4gIgsg = here->BSIM4gIgss = 0.0; + here->BSIM4Igd = here->BSIM4gIgdg = here->BSIM4gIgdd = 0.0; + } + + if (model->BSIM4igbMod) + { T0 = Vtm * pParam->BSIM4nigbacc; + T1 = -Vgs_eff + Vbseff + Vfb; + VxNVt = T1 / T0; + if (VxNVt > EXP_THRESHOLD) + { Vaux = T1; + dVaux_dVg = -dVgs_eff_dVg; + dVaux_dVb = 1.0; + } + else if (VxNVt < -EXP_THRESHOLD) + { Vaux = T0 * log(1.0 + MIN_EXP); + dVaux_dVg = dVaux_dVb = 0.0; + } + else + { ExpVxNVt = exp(VxNVt); + Vaux = T0 * log(1.0 + ExpVxNVt); + dVaux_dVb = ExpVxNVt / (1.0 + ExpVxNVt); + dVaux_dVg = -dVaux_dVb * dVgs_eff_dVg; + } + + T2 = (Vgs_eff - Vbseff) * Vaux; + dT2_dVg = dVgs_eff_dVg * Vaux + (Vgs_eff - Vbseff) * dVaux_dVg; + dT2_dVb = -Vaux + (Vgs_eff - Vbseff) * dVaux_dVb; + + T11 = 4.97232e-7 * pParam->BSIM4weff + * pParam->BSIM4leff * pParam->BSIM4ToxRatio; + T12 = -7.45669e11 * model->BSIM4toxe; + T3 = pParam->BSIM4aigbacc * pParam->BSIM4cigbacc + - pParam->BSIM4bigbacc; + T4 = pParam->BSIM4bigbacc * pParam->BSIM4cigbacc; + T5 = T12 * (pParam->BSIM4aigbacc + T3 * Voxacc + - T4 * Voxacc * Voxacc); + + if (T5 > EXP_THRESHOLD) + { T6 = MAX_EXP; + dT6_dVg = dT6_dVb = 0.0; + } + else if (T5 < -EXP_THRESHOLD) + { T6 = MIN_EXP; + dT6_dVg = dT6_dVb = 0.0; + } + else + { T6 = exp(T5); + dT6_dVg = T6 * T12 * (T3 - 2.0 * T4 * Voxacc); + dT6_dVb = dT6_dVg * dVoxacc_dVb; + dT6_dVg *= dVoxacc_dVg; + } + + Igbacc = T11 * T2 * T6; + dIgbacc_dVg = T11 * (T2 * dT6_dVg + T6 * dT2_dVg); + dIgbacc_dVb = T11 * (T2 * dT6_dVb + T6 * dT2_dVb); + + + T0 = Vtm * pParam->BSIM4nigbinv; + T1 = Voxdepinv - pParam->BSIM4eigbinv; + VxNVt = T1 / T0; + if (VxNVt > EXP_THRESHOLD) + { Vaux = T1; + dVaux_dVg = dVoxdepinv_dVg; + dVaux_dVd = dVoxdepinv_dVd; + dVaux_dVb = dVoxdepinv_dVb; + } + else if (VxNVt < -EXP_THRESHOLD) + { Vaux = T0 * log(1.0 + MIN_EXP); + dVaux_dVg = dVaux_dVd = dVaux_dVb = 0.0; + } + else + { ExpVxNVt = exp(VxNVt); + Vaux = T0 * log(1.0 + ExpVxNVt); + dVaux_dVg = ExpVxNVt / (1.0 + ExpVxNVt); + dVaux_dVd = dVaux_dVg * dVoxdepinv_dVd; + dVaux_dVb = dVaux_dVg * dVoxdepinv_dVb; + dVaux_dVg *= dVoxdepinv_dVg; + } + + T2 = (Vgs_eff - Vbseff) * Vaux; + dT2_dVg = dVgs_eff_dVg * Vaux + (Vgs_eff - Vbseff) * dVaux_dVg; + dT2_dVd = (Vgs_eff - Vbseff) * dVaux_dVd; + dT2_dVb = -Vaux + (Vgs_eff - Vbseff) * dVaux_dVb; + + T11 *= 0.75610; + T12 *= 1.31724; + T3 = pParam->BSIM4aigbinv * pParam->BSIM4cigbinv + - pParam->BSIM4bigbinv; + T4 = pParam->BSIM4bigbinv * pParam->BSIM4cigbinv; + T5 = T12 * (pParam->BSIM4aigbinv + T3 * Voxdepinv + - T4 * Voxdepinv * Voxdepinv); + + if (T5 > EXP_THRESHOLD) + { T6 = MAX_EXP; + dT6_dVg = dT6_dVd = dT6_dVb = 0.0; + } + else if (T5 < -EXP_THRESHOLD) + { T6 = MIN_EXP; + dT6_dVg = dT6_dVd = dT6_dVb = 0.0; + } + else + { T6 = exp(T5); + dT6_dVg = T6 * T12 * (T3 - 2.0 * T4 * Voxdepinv); + dT6_dVd = dT6_dVg * dVoxdepinv_dVd; + dT6_dVb = dT6_dVg * dVoxdepinv_dVb; + dT6_dVg *= dVoxdepinv_dVg; + } + + Igbinv = T11 * T2 * T6; + dIgbinv_dVg = T11 * (T2 * dT6_dVg + T6 * dT2_dVg); + dIgbinv_dVd = T11 * (T2 * dT6_dVd + T6 * dT2_dVd); + dIgbinv_dVb = T11 * (T2 * dT6_dVb + T6 * dT2_dVb); + + here->BSIM4Igb = Igbinv + Igbacc; + here->BSIM4gIgbg = dIgbinv_dVg + dIgbacc_dVg; + here->BSIM4gIgbd = dIgbinv_dVd; + here->BSIM4gIgbb = (dIgbinv_dVb + dIgbacc_dVb) * dVbseff_dVb; + } + else + { here->BSIM4Igb = here->BSIM4gIgbg = here->BSIM4gIgbd + = here->BSIM4gIgbs = here->BSIM4gIgbb = 0.0; + } /* End of Gate current */ + + if (here->BSIM4nf != 1.0) + { cdrain *= here->BSIM4nf; + here->BSIM4gds *= here->BSIM4nf; + here->BSIM4gm *= here->BSIM4nf; + here->BSIM4gmbs *= here->BSIM4nf; + here->BSIM4IdovVds *= here->BSIM4nf; + + here->BSIM4gbbs *= here->BSIM4nf; + here->BSIM4gbgs *= here->BSIM4nf; + here->BSIM4gbds *= here->BSIM4nf; + here->BSIM4csub *= here->BSIM4nf; + + here->BSIM4Igidl *= here->BSIM4nf; + here->BSIM4ggidld *= here->BSIM4nf; + here->BSIM4ggidlg *= here->BSIM4nf; + here->BSIM4ggidlb *= here->BSIM4nf; + + here->BSIM4Igcs *= here->BSIM4nf; + here->BSIM4gIgcsg *= here->BSIM4nf; + here->BSIM4gIgcsd *= here->BSIM4nf; + here->BSIM4gIgcsb *= here->BSIM4nf; + here->BSIM4Igcd *= here->BSIM4nf; + here->BSIM4gIgcdg *= here->BSIM4nf; + here->BSIM4gIgcdd *= here->BSIM4nf; + here->BSIM4gIgcdb *= here->BSIM4nf; + + here->BSIM4Igs *= here->BSIM4nf; + here->BSIM4gIgsg *= here->BSIM4nf; + here->BSIM4gIgss *= here->BSIM4nf; + here->BSIM4Igd *= here->BSIM4nf; + here->BSIM4gIgdg *= here->BSIM4nf; + here->BSIM4gIgdd *= here->BSIM4nf; + + here->BSIM4Igb *= here->BSIM4nf; + here->BSIM4gIgbg *= here->BSIM4nf; + here->BSIM4gIgbd *= here->BSIM4nf; + here->BSIM4gIgbb *= here->BSIM4nf; + } + + here->BSIM4ggidls = -(here->BSIM4ggidld + here->BSIM4ggidlg + + here->BSIM4ggidlb); + here->BSIM4gIgbs = -(here->BSIM4gIgbg + here->BSIM4gIgbd + + here->BSIM4gIgbb); + here->BSIM4gIgcss = -(here->BSIM4gIgcsg + here->BSIM4gIgcsd + + here->BSIM4gIgcsb); + here->BSIM4gIgcds = -(here->BSIM4gIgcdg + here->BSIM4gIgcdd + + here->BSIM4gIgcdb); + here->BSIM4cd = cdrain; + + + if (model->BSIM4tnoiMod == 0) + { T0 = Abulk * Vdseff; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1.0e-20); + T2 = Vdseff / T1; + T3 = T0 * T2; + here->BSIM4qinv = Coxeff * pParam->BSIM4weffCV * here->BSIM4nf + * pParam->BSIM4leffCV + * (Vgsteff - 0.5 * T0 + Abulk * T3); + } + + /* + * BSIM4 C-V begins + */ + + if ((model->BSIM4xpart < 0) || (!ChargeComputationNeeded)) + { qgate = qdrn = qsrc = qbulk = 0.0; + here->BSIM4cggb = here->BSIM4cgsb = here->BSIM4cgdb = 0.0; + here->BSIM4cdgb = here->BSIM4cdsb = here->BSIM4cddb = 0.0; + here->BSIM4cbgb = here->BSIM4cbsb = here->BSIM4cbdb = 0.0; + here->BSIM4cqdb = here->BSIM4cqsb = here->BSIM4cqgb + = here->BSIM4cqbb = 0.0; + here->BSIM4gtau = 0.0; + goto finished; + } + else if (model->BSIM4capMod == 0) + { + if (Vbseff < 0.0) + { Vbseff = Vbs; + dVbseff_dVb = 1.0; + } + else + { Vbseff = pParam->BSIM4phi - Phis; + dVbseff_dVb = -dPhis_dVb; + } + + Vfb = pParam->BSIM4vfbcv; + Vth = Vfb + pParam->BSIM4phi + pParam->BSIM4k1ox * sqrtPhis; + Vgst = Vgs_eff - Vth; + dVth_dVb = pParam->BSIM4k1ox * dsqrtPhis_dVb; + dVgst_dVb = -dVth_dVb; + dVgst_dVg = dVgs_eff_dVg; + + CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV + * pParam->BSIM4leffCV * here->BSIM4nf; + Arg1 = Vgs_eff - Vbseff - Vfb; + + if (Arg1 <= 0.0) + { qgate = CoxWL * Arg1; + qbulk = -qgate; + qdrn = 0.0; + + here->BSIM4cggb = CoxWL * dVgs_eff_dVg; + here->BSIM4cgdb = 0.0; + here->BSIM4cgsb = CoxWL * (dVbseff_dVb - dVgs_eff_dVg); + + here->BSIM4cdgb = 0.0; + here->BSIM4cddb = 0.0; + here->BSIM4cdsb = 0.0; + + here->BSIM4cbgb = -CoxWL * dVgs_eff_dVg; + here->BSIM4cbdb = 0.0; + here->BSIM4cbsb = -here->BSIM4cgsb; + } /* Arg1 <= 0.0, end of accumulation */ + else if (Vgst <= 0.0) + { T1 = 0.5 * pParam->BSIM4k1ox; + T2 = sqrt(T1 * T1 + Arg1); + qgate = CoxWL * pParam->BSIM4k1ox * (T2 - T1); + qbulk = -qgate; + qdrn = 0.0; + + T0 = CoxWL * T1 / T2; + here->BSIM4cggb = T0 * dVgs_eff_dVg; + here->BSIM4cgdb = 0.0; + here->BSIM4cgsb = T0 * (dVbseff_dVb - dVgs_eff_dVg); + + here->BSIM4cdgb = 0.0; + here->BSIM4cddb = 0.0; + here->BSIM4cdsb = 0.0; + + here->BSIM4cbgb = -here->BSIM4cggb; + here->BSIM4cbdb = 0.0; + here->BSIM4cbsb = -here->BSIM4cgsb; + } /* Vgst <= 0.0, end of depletion */ + else + { One_Third_CoxWL = CoxWL / 3.0; + Two_Third_CoxWL = 2.0 * One_Third_CoxWL; + + AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb; + Vdsat = Vgst / AbulkCV; + dVdsat_dVg = dVgs_eff_dVg / AbulkCV; + dVdsat_dVb = - (Vdsat * dAbulkCV_dVb + dVth_dVb)/ AbulkCV; + + if (model->BSIM4xpart > 0.5) + { /* 0/100 Charge partition model */ + if (Vdsat <= Vds) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.0; + + here->BSIM4cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM4cgsb = -(here->BSIM4cggb + T2); + here->BSIM4cgdb = 0.0; + + here->BSIM4cdgb = 0.0; + here->BSIM4cddb = 0.0; + here->BSIM4cdsb = 0.0; + + here->BSIM4cbgb = -(here->BSIM4cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM4cbsb = -(here->BSIM4cbgb + T3); + here->BSIM4cbdb = 0.0; + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + T7 = 2.0 * Vds - T1 - 3.0 * T3; + T8 = T3 - T1 - 2.0 * Vds; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - 0.5 * (Vds - T3)); + T10 = T4 * T8; + qdrn = T4 * T7; + qbulk = -(qgate + qdrn + T10); + + T5 = T3 / T1; + here->BSIM4cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = -CoxWL * T5 * dVdsat_dVb; + here->BSIM4cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM4cgsb = -(here->BSIM4cggb + T11 + + here->BSIM4cgdb); + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + T7 = T9 * T7; + T8 = T9 * T8; + T9 = 2.0 * T4 * (1.0 - 3.0 * T5); + here->BSIM4cdgb = (T7 * dAlphaz_dVg - T9 + * dVdsat_dVg) * dVgs_eff_dVg; + T12 = T7 * dAlphaz_dVb - T9 * dVdsat_dVb; + here->BSIM4cddb = T4 * (3.0 - 6.0 * T2 - 3.0 * T5); + here->BSIM4cdsb = -(here->BSIM4cdgb + T12 + + here->BSIM4cddb); + + T9 = 2.0 * T4 * (1.0 + T5); + T10 = (T8 * dAlphaz_dVg - T9 * dVdsat_dVg) + * dVgs_eff_dVg; + T11 = T8 * dAlphaz_dVb - T9 * dVdsat_dVb; + T12 = T4 * (2.0 * T2 + T5 - 1.0); + T0 = -(T10 + T11 + T12); + + here->BSIM4cbgb = -(here->BSIM4cggb + + here->BSIM4cdgb + T10); + here->BSIM4cbdb = -(here->BSIM4cgdb + + here->BSIM4cddb + T12); + here->BSIM4cbsb = -(here->BSIM4cgsb + + here->BSIM4cdsb + T0); + } + } + else if (model->BSIM4xpart < 0.5) + { /* 40/60 Charge partition model */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.4 * T2; + + here->BSIM4cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM4cgsb = -(here->BSIM4cggb + T2); + here->BSIM4cgdb = 0.0; + + T3 = 0.4 * Two_Third_CoxWL; + here->BSIM4cdgb = -T3 * dVgs_eff_dVg; + here->BSIM4cddb = 0.0; + T4 = T3 * dVth_dVb; + here->BSIM4cdsb = -(T4 + here->BSIM4cdgb); + + here->BSIM4cbgb = -(here->BSIM4cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM4cbsb = -(here->BSIM4cbgb + T3); + here->BSIM4cbdb = 0.0; + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM4phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM4cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM4cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM4cgsb = -(here->BSIM4cggb + + here->BSIM4cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T6 = 8.0 * Vdsat * Vdsat - 6.0 * Vdsat * Vds + + 1.2 * Vds * Vds; + T8 = T2 / T1; + T7 = Vds - T1 - T8 * T6; + qdrn = T4 * T7; + T7 *= T9; + tmp = T8 / T1; + tmp1 = T4 * (2.0 - 4.0 * tmp * T6 + + T8 * (16.0 * Vdsat - 6.0 * Vds)); + + here->BSIM4cdgb = (T7 * dAlphaz_dVg - tmp1 + * dVdsat_dVg) * dVgs_eff_dVg; + T10 = T7 * dAlphaz_dVb - tmp1 * dVdsat_dVb; + here->BSIM4cddb = T4 * (2.0 - (1.0 / (3.0 * T1 + * T1) + 2.0 * tmp) * T6 + T8 + * (6.0 * Vdsat - 2.4 * Vds)); + here->BSIM4cdsb = -(here->BSIM4cdgb + + T10 + here->BSIM4cddb); + + T7 = 2.0 * (T1 + T3); + qbulk = -(qgate - T4 * T7); + T7 *= T9; + T0 = 4.0 * T4 * (1.0 - T5); + T12 = (-T7 * dAlphaz_dVg - here->BSIM4cdgb + - T0 * dVdsat_dVg) * dVgs_eff_dVg; + T11 = -T7 * dAlphaz_dVb - T10 - T0 * dVdsat_dVb; + T10 = -4.0 * T4 * (T2 - 0.5 + 0.5 * T5) + - here->BSIM4cddb; + tmp = -(T10 + T11 + T12); + + here->BSIM4cbgb = -(here->BSIM4cggb + + here->BSIM4cdgb + T12); + here->BSIM4cbdb = -(here->BSIM4cgdb + + here->BSIM4cddb + T11); + here->BSIM4cbsb = -(here->BSIM4cgsb + + here->BSIM4cdsb + tmp); + } + } + else + { /* 50/50 partitioning */ + if (Vds >= Vdsat) + { /* saturation region */ + T1 = Vdsat / 3.0; + qgate = CoxWL * (Vgs_eff - Vfb + - pParam->BSIM4phi - T1); + T2 = -Two_Third_CoxWL * Vgst; + qbulk = -(qgate + T2); + qdrn = 0.5 * T2; + + here->BSIM4cggb = One_Third_CoxWL * (3.0 + - dVdsat_dVg) * dVgs_eff_dVg; + T2 = -One_Third_CoxWL * dVdsat_dVb; + here->BSIM4cgsb = -(here->BSIM4cggb + T2); + here->BSIM4cgdb = 0.0; + + here->BSIM4cdgb = -One_Third_CoxWL * dVgs_eff_dVg; + here->BSIM4cddb = 0.0; + T4 = One_Third_CoxWL * dVth_dVb; + here->BSIM4cdsb = -(T4 + here->BSIM4cdgb); + + here->BSIM4cbgb = -(here->BSIM4cggb + - Two_Third_CoxWL * dVgs_eff_dVg); + T3 = -(T2 + Two_Third_CoxWL * dVth_dVb); + here->BSIM4cbsb = -(here->BSIM4cbgb + T3); + here->BSIM4cbdb = 0.0; + } + else + { /* linear region */ + Alphaz = Vgst / Vdsat; + T1 = 2.0 * Vdsat - Vds; + T2 = Vds / (3.0 * T1); + T3 = T2 * Vds; + T9 = 0.25 * CoxWL; + T4 = T9 * Alphaz; + qgate = CoxWL * (Vgs_eff - Vfb - pParam->BSIM4phi + - 0.5 * (Vds - T3)); + + T5 = T3 / T1; + here->BSIM4cggb = CoxWL * (1.0 - T5 * dVdsat_dVg) + * dVgs_eff_dVg; + tmp = -CoxWL * T5 * dVdsat_dVb; + here->BSIM4cgdb = CoxWL * (T2 - 0.5 + 0.5 * T5); + here->BSIM4cgsb = -(here->BSIM4cggb + + here->BSIM4cgdb + tmp); + + T6 = 1.0 / Vdsat; + dAlphaz_dVg = T6 * (1.0 - Alphaz * dVdsat_dVg); + dAlphaz_dVb = -T6 * (dVth_dVb + Alphaz * dVdsat_dVb); + + T7 = T1 + T3; + qdrn = -T4 * T7; + qbulk = - (qgate + qdrn + qdrn); + T7 *= T9; + T0 = T4 * (2.0 * T5 - 2.0); + + here->BSIM4cdgb = (T0 * dVdsat_dVg - T7 + * dAlphaz_dVg) * dVgs_eff_dVg; + T12 = T0 * dVdsat_dVb - T7 * dAlphaz_dVb; + here->BSIM4cddb = T4 * (1.0 - 2.0 * T2 - T5); + here->BSIM4cdsb = -(here->BSIM4cdgb + T12 + + here->BSIM4cddb); + + here->BSIM4cbgb = -(here->BSIM4cggb + + 2.0 * here->BSIM4cdgb); + here->BSIM4cbdb = -(here->BSIM4cgdb + + 2.0 * here->BSIM4cddb); + here->BSIM4cbsb = -(here->BSIM4cgsb + + 2.0 * here->BSIM4cdsb); + } /* end of linear region */ + } /* end of 50/50 partition */ + } /* end of inversion */ + } /* end of capMod=0 */ + else + { if (Vbseff < 0.0) + { VbseffCV = Vbseff; + dVbseffCV_dVb = 1.0; + } + else + { VbseffCV = pParam->BSIM4phi - Phis; + dVbseffCV_dVb = -dPhis_dVb; + } + + CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV + * pParam->BSIM4leffCV * here->BSIM4nf; + + /* Seperate VgsteffCV with noff and voffcv */ + noff = n * pParam->BSIM4noff; + dnoff_dVd = pParam->BSIM4noff * dn_dVd; + dnoff_dVb = pParam->BSIM4noff * dn_dVb; + T0 = Vtm * noff; + voffcv = pParam->BSIM4voffcv; + VgstNVt = (Vgst - voffcv) / T0; + + if (VgstNVt > EXP_THRESHOLD) + { Vgsteff = Vgst - voffcv; + dVgsteff_dVg = dVgs_eff_dVg; + dVgsteff_dVd = -dVth_dVd; + dVgsteff_dVb = -dVth_dVb; + } + else if (VgstNVt < -EXP_THRESHOLD) + { Vgsteff = T0 * log(1.0 + MIN_EXP); + dVgsteff_dVg = 0.0; + dVgsteff_dVd = Vgsteff / noff; + dVgsteff_dVb = dVgsteff_dVd * dnoff_dVb; + dVgsteff_dVd *= dnoff_dVd; + } + else + { ExpVgst = exp(VgstNVt); + Vgsteff = T0 * log(1.0 + ExpVgst); + dVgsteff_dVg = ExpVgst / (1.0 + ExpVgst); + dVgsteff_dVd = -dVgsteff_dVg * (dVth_dVd + (Vgst - voffcv) + / noff * dnoff_dVd) + Vgsteff / noff * dnoff_dVd; + dVgsteff_dVb = -dVgsteff_dVg * (dVth_dVb + (Vgst - voffcv) + / noff * dnoff_dVb) + Vgsteff / noff * dnoff_dVb; + dVgsteff_dVg *= dVgs_eff_dVg; + } /* End of VgsteffCV */ + + + if (model->BSIM4capMod == 1) + { Vfb = pParam->BSIM4vfbzb; + V3 = Vfb - Vgs_eff + VbseffCV - DELTA_3; + if (Vfb <= 0.0) + T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * Vfb); + else + T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * Vfb); + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = Vfb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1 * dVbseffCV_dVb; + Qac0 = CoxWL * (Vfbeff - Vfb); + dQac0_dVg = CoxWL * dVfbeff_dVg; + dQac0_dVb = CoxWL * dVfbeff_dVb; + + T0 = 0.5 * pParam->BSIM4k1ox; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + if (pParam->BSIM4k1ox == 0.0) + { T1 = 0.0; + T2 = 0.0; + } + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM4k1ox; + T2 = CoxWL; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = CoxWL * T0 / T1; + } + + Qsub0 = CoxWL * pParam->BSIM4k1ox * (T1 - T0); + + dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg); + dQsub0_dVd = -T2 * dVgsteff_dVd; + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + + dVgsteff_dVb); + + AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb; + VdsatCV = Vgsteff / AbulkCV; + + T0 = VdsatCV - Vds - DELTA_4; + dT0_dVg = 1.0 / AbulkCV; + dT0_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_4 * VdsatCV); + dT1_dVg = (T0 + DELTA_4 + DELTA_4) / T1; + dT1_dVd = -T0 / T1; + dT1_dVb = dT1_dVg * dT0_dVb; + dT1_dVg *= dT0_dVg; + if (T0 >= 0.0) + { VdseffCV = VdsatCV - 0.5 * (T0 + T1); + dVdseffCV_dVg = 0.5 * (dT0_dVg - dT1_dVg); + dVdseffCV_dVd = 0.5 * (1.0 - dT1_dVd); + dVdseffCV_dVb = 0.5 * (dT0_dVb - dT1_dVb); + } + else + { T3 = (DELTA_4 + DELTA_4) / (T1 - T0); + T4 = 1.0 - T3; + T5 = VdsatCV * T3 / (T1 - T0); + VdseffCV = VdsatCV * T4; + dVdseffCV_dVg = dT0_dVg * T4 + T5 * (dT1_dVg - dT0_dVg); + dVdseffCV_dVd = T5 * (dT1_dVd + 1.0); + dVdseffCV_dVb = dT0_dVb * (1.0 - T5) + T5 * dT1_dVb; + } + + if (Vds == 0.0) + { VdseffCV = 0.0; + dVdseffCV_dVg = 0.0; + dVdseffCV_dVb = 0.0; + } + + T0 = AbulkCV * VdseffCV; + T1 = 12.0 * (Vgsteff - 0.5 * T0 + 1.0e-20); + T2 = VdseffCV / T1; + T3 = T0 * T2; + + T4 = (1.0 - 12.0 * T2 * T2 * AbulkCV); + T5 = (6.0 * T0 * (4.0 * Vgsteff - T0) / (T1 * T1) - 0.5); + T6 = 12.0 * T2 * T2 * Vgsteff; + + qgate = CoxWL * (Vgsteff - 0.5 * VdseffCV + T3); + Cgg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cgd1 = CoxWL * T5 * dVdseffCV_dVd + Cgg1 * dVgsteff_dVd; + Cgb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb; + Cgg1 *= dVgsteff_dVg; + + T7 = 1.0 - AbulkCV; + qbulk = CoxWL * T7 * (0.5 * VdseffCV - T3); + T4 = -T7 * (T4 - 1.0); + T5 = -T7 * T5; + T6 = -(T7 * T6 + (0.5 * VdseffCV - T3)); + Cbg1 = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Cbd1 = CoxWL * T5 * dVdseffCV_dVd + Cbg1 * dVgsteff_dVd; + Cbb1 = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb; + Cbg1 *= dVgsteff_dVg; + + if (model->BSIM4xpart > 0.5) + { /* 0/100 Charge petition model */ + T1 = T1 + T1; + qsrc = -CoxWL * (0.5 * Vgsteff + 0.25 * T0 + - T0 * T0 / T1); + T7 = (4.0 * Vgsteff - T0) / (T1 * T1); + T4 = -(0.5 + 24.0 * T0 * T0 / (T1 * T1)); + T5 = -(0.25 * AbulkCV - 12.0 * AbulkCV * T0 * T7); + T6 = -(0.25 * VdseffCV - 12.0 * T0 * VdseffCV * T7); + Csg = CoxWL * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWL * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = CoxWL * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else if (model->BSIM4xpart < 0.5) + { /* 40/60 Charge petition model */ + T1 = T1 / 12.0; + T2 = 0.5 * CoxWL / (T1 * T1); + T3 = Vgsteff * (2.0 * T0 * T0 / 3.0 + Vgsteff + * (Vgsteff - 4.0 * T0 / 3.0)) + - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T2 * T3; + T7 = 4.0 / 3.0 * Vgsteff * (Vgsteff - T0) + + 0.4 * T0 * T0; + T4 = -2.0 * qsrc / T1 - T2 * (Vgsteff * (3.0 + * Vgsteff - 8.0 * T0 / 3.0) + + 2.0 * T0 * T0 / 3.0); + T5 = (qsrc / T1 + T2 * T7) * AbulkCV; + T6 = (qsrc / T1 * VdseffCV + T2 * T7 * VdseffCV); + Csg = (T4 + T5 * dVdseffCV_dVg); + Csd = T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd; + Csb = (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb; + Csg *= dVgsteff_dVg; + } + else + { /* 50/50 Charge petition model */ + qsrc = -0.5 * (qgate + qbulk); + Csg = -0.5 * (Cgg1 + Cbg1); + Csb = -0.5 * (Cgb1 + Cbb1); + Csd = -0.5 * (Cgd1 + Cbd1); + } + + qgate += Qac0 + Qsub0; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cgg = dQac0_dVg + dQsub0_dVg + Cgg1; + Cgd = dQsub0_dVd + Cgd1; + Cgb = dQac0_dVb + dQsub0_dVb + Cgb1; + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM4cggb = Cgg; + here->BSIM4cgsb = -(Cgg + Cgd + Cgb); + here->BSIM4cgdb = Cgd; + here->BSIM4cdgb = -(Cgg + Cbg + Csg); + here->BSIM4cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM4cddb = -(Cgd + Cbd + Csd); + here->BSIM4cbgb = Cbg; + here->BSIM4cbsb = -(Cbg + Cbd + Cbb); + here->BSIM4cbdb = Cbd; + } + + /* New Charge-Thickness capMod (CTM) begins */ + else if (model->BSIM4capMod == 2) + { V3 = pParam->BSIM4vfbzb - Vgs_eff + VbseffCV - DELTA_3; + if (pParam->BSIM4vfbzb <= 0.0) + T0 = sqrt(V3 * V3 - 4.0 * DELTA_3 * pParam->BSIM4vfbzb); + else + T0 = sqrt(V3 * V3 + 4.0 * DELTA_3 * pParam->BSIM4vfbzb); + + T1 = 0.5 * (1.0 + V3 / T0); + Vfbeff = pParam->BSIM4vfbzb - 0.5 * (V3 + T0); + dVfbeff_dVg = T1 * dVgs_eff_dVg; + dVfbeff_dVb = -T1 * dVbseffCV_dVb; + + Cox = model->BSIM4coxp; + Tox = 1.0e8 * model->BSIM4toxp; + T0 = (Vgs_eff - VbseffCV - pParam->BSIM4vfbzb) / Tox; + dT0_dVg = dVgs_eff_dVg / Tox; + dT0_dVb = -dVbseffCV_dVb / Tox; + + tmp = T0 * pParam->BSIM4acde; + if ((-EXP_THRESHOLD < tmp) && (tmp < EXP_THRESHOLD)) + { Tcen = pParam->BSIM4ldeb * exp(tmp); + dTcen_dVg = pParam->BSIM4acde * Tcen; + dTcen_dVb = dTcen_dVg * dT0_dVb; + dTcen_dVg *= dT0_dVg; + } + else if (tmp <= -EXP_THRESHOLD) + { Tcen = pParam->BSIM4ldeb * MIN_EXP; + dTcen_dVg = dTcen_dVb = 0.0; + } + else + { Tcen = pParam->BSIM4ldeb * MAX_EXP; + dTcen_dVg = dTcen_dVb = 0.0; + } + + LINK = 1.0e-3 * model->BSIM4toxp; + V3 = pParam->BSIM4ldeb - Tcen - LINK; + V4 = sqrt(V3 * V3 + 4.0 * LINK * pParam->BSIM4ldeb); + Tcen = pParam->BSIM4ldeb - 0.5 * (V3 + V4); + T1 = 0.5 * (1.0 + V3 / V4); + dTcen_dVg *= T1; + dTcen_dVb *= T1; + + Ccen = EPSSI / Tcen; + T2 = Cox / (Cox + Ccen); + Coxeff = T2 * Ccen; + T3 = -Ccen / Tcen; + dCoxeff_dVg = T2 * T2 * T3; + dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; + dCoxeff_dVg *= dTcen_dVg; + CoxWLcen = CoxWL * Coxeff / model->BSIM4coxe; + + Qac0 = CoxWLcen * (Vfbeff - pParam->BSIM4vfbzb); + QovCox = Qac0 / Coxeff; + dQac0_dVg = CoxWLcen * dVfbeff_dVg + + QovCox * dCoxeff_dVg; + dQac0_dVb = CoxWLcen * dVfbeff_dVb + + QovCox * dCoxeff_dVb; + + T0 = 0.5 * pParam->BSIM4k1ox; + T3 = Vgs_eff - Vfbeff - VbseffCV - Vgsteff; + if (pParam->BSIM4k1ox == 0.0) + { T1 = 0.0; + T2 = 0.0; + } + else if (T3 < 0.0) + { T1 = T0 + T3 / pParam->BSIM4k1ox; + T2 = CoxWLcen; + } + else + { T1 = sqrt(T0 * T0 + T3); + T2 = CoxWLcen * T0 / T1; + } + + Qsub0 = CoxWLcen * pParam->BSIM4k1ox * (T1 - T0); + QovCox = Qsub0 / Coxeff; + dQsub0_dVg = T2 * (dVgs_eff_dVg - dVfbeff_dVg - dVgsteff_dVg) + + QovCox * dCoxeff_dVg; + dQsub0_dVd = -T2 * dVgsteff_dVd; + dQsub0_dVb = -T2 * (dVfbeff_dVb + dVbseffCV_dVb + dVgsteff_dVb) + + QovCox * dCoxeff_dVb; + + /* Gate-bias dependent delta Phis begins */ + if (pParam->BSIM4k1ox <= 0.0) + { Denomi = 0.25 * pParam->BSIM4moin * Vtm; + T0 = 0.5 * pParam->BSIM4sqrtPhi; + } + else + { Denomi = pParam->BSIM4moin * Vtm + * pParam->BSIM4k1ox * pParam->BSIM4k1ox; + T0 = pParam->BSIM4k1ox * pParam->BSIM4sqrtPhi; + } + T1 = 2.0 * T0 + Vgsteff; + + DeltaPhi = Vtm * log(1.0 + T1 * Vgsteff / Denomi); + dDeltaPhi_dVg = 2.0 * Vtm * (T1 -T0) / (Denomi + T1 * Vgsteff); + /* End of delta Phis */ + + Tox += Tox; /* WDLiu: Tcen reevaluated below due to different Vgsteff */ + T0 = (Vgsteff + pParam->BSIM4vtfbphi2) / Tox; + tmp = exp(0.7 * log(T0)); + T1 = 1.0 + tmp; + T2 = 0.7 * tmp / (T0 * Tox); + Tcen = 1.9e-9 / T1; + dTcen_dVg = -Tcen * T2 / T1; + dTcen_dVd = dTcen_dVg * dVgsteff_dVd; + dTcen_dVb = dTcen_dVg * dVgsteff_dVb; + dTcen_dVg *= dVgsteff_dVg; + + Ccen = EPSSI / Tcen; + T0 = Cox / (Cox + Ccen); + Coxeff = T0 * Ccen; + T1 = -Ccen / Tcen; + dCoxeff_dVg = T0 * T0 * T1; + dCoxeff_dVd = dCoxeff_dVg * dTcen_dVd; + dCoxeff_dVb = dCoxeff_dVg * dTcen_dVb; + dCoxeff_dVg *= dTcen_dVg; + CoxWLcen = CoxWL * Coxeff / model->BSIM4coxe; + + AbulkCV = Abulk0 * pParam->BSIM4abulkCVfactor; + dAbulkCV_dVb = pParam->BSIM4abulkCVfactor * dAbulk0_dVb; + VdsatCV = (Vgsteff - DeltaPhi) / AbulkCV; + + T0 = VdsatCV - Vds - DELTA_4; + dT0_dVg = (1.0 - dDeltaPhi_dVg) / AbulkCV; + dT0_dVb = -VdsatCV * dAbulkCV_dVb / AbulkCV; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_4 * VdsatCV); + dT1_dVg = (T0 + DELTA_4 + DELTA_4) / T1; + dT1_dVd = -T0 / T1; + dT1_dVb = dT1_dVg * dT0_dVb; + dT1_dVg *= dT0_dVg; + if (T0 >= 0.0) + { VdseffCV = VdsatCV - 0.5 * (T0 + T1); + dVdseffCV_dVg = 0.5 * (dT0_dVg - dT1_dVg); + dVdseffCV_dVd = 0.5 * (1.0 - dT1_dVd); + dVdseffCV_dVb = 0.5 * (dT0_dVb - dT1_dVb); + } + else + { T3 = (DELTA_4 + DELTA_4) / (T1 - T0); + T4 = 1.0 - T3; + T5 = VdsatCV * T3 / (T1 - T0); + VdseffCV = VdsatCV * T4; + dVdseffCV_dVg = dT0_dVg * T4 + T5 * (dT1_dVg - dT0_dVg); + dVdseffCV_dVd = T5 * (dT1_dVd + 1.0); + dVdseffCV_dVb = dT0_dVb * (1.0 - T5) + T5 * dT1_dVb; + } + + if (Vds == 0.0) + { VdseffCV = 0.0; + dVdseffCV_dVg = 0.0; + dVdseffCV_dVb = 0.0; + } + + T0 = AbulkCV * VdseffCV; + T1 = Vgsteff - DeltaPhi; + T2 = 12.0 * (T1 - 0.5 * T0 + 1.0e-20); + T3 = T0 / T2; + T4 = 1.0 - 12.0 * T3 * T3; + T5 = AbulkCV * (6.0 * T0 * (4.0 * T1 - T0) / (T2 * T2) - 0.5); + T6 = T5 * VdseffCV / AbulkCV; + + qgate = CoxWLcen * (T1 - T0 * (0.5 - T3)); + QovCox = qgate / Coxeff; + Cgg1 = CoxWLcen * (T4 * (1.0 - dDeltaPhi_dVg) + + T5 * dVdseffCV_dVg); + Cgd1 = CoxWLcen * T5 * dVdseffCV_dVd + Cgg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cgb1 = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Cgg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cgg1 = Cgg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + + + T7 = 1.0 - AbulkCV; + T8 = T2 * T2; + T9 = 12.0 * T7 * T0 * T0 / (T8 * AbulkCV); + T10 = T9 * (1.0 - dDeltaPhi_dVg); + T11 = -T7 * T5 / AbulkCV; + T12 = -(T9 * T1 / AbulkCV + VdseffCV * (0.5 - T0 / T2)); + + qbulk = CoxWLcen * T7 * (0.5 * VdseffCV - T0 * VdseffCV / T2); + QovCox = qbulk / Coxeff; + Cbg1 = CoxWLcen * (T10 + T11 * dVdseffCV_dVg); + Cbd1 = CoxWLcen * T11 * dVdseffCV_dVd + Cbg1 + * dVgsteff_dVd + QovCox * dCoxeff_dVd; + Cbb1 = CoxWLcen * (T11 * dVdseffCV_dVb + T12 * dAbulkCV_dVb) + + Cbg1 * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Cbg1 = Cbg1 * dVgsteff_dVg + QovCox * dCoxeff_dVg; + + if (model->BSIM4xpart > 0.5) + { /* 0/100 partition */ + qsrc = -CoxWLcen * (T1 / 2.0 + T0 / 4.0 + - 0.5 * T0 * T0 / T2); + QovCox = qsrc / Coxeff; + T2 += T2; + T3 = T2 * T2; + T7 = -(0.25 - 12.0 * T0 * (4.0 * T1 - T0) / T3); + T4 = -(0.5 + 24.0 * T0 * T0 / T3) * (1.0 - dDeltaPhi_dVg); + T5 = T7 * AbulkCV; + T6 = T7 * VdseffCV; + + Csg = CoxWLcen * (T4 + T5 * dVdseffCV_dVg); + Csd = CoxWLcen * T5 * dVdseffCV_dVd + Csg * dVgsteff_dVd + + QovCox * dCoxeff_dVd; + Csb = CoxWLcen * (T5 * dVdseffCV_dVb + T6 * dAbulkCV_dVb) + + Csg * dVgsteff_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + } + else if (model->BSIM4xpart < 0.5) + { /* 40/60 partition */ + T2 = T2 / 12.0; + T3 = 0.5 * CoxWLcen / (T2 * T2); + T4 = T1 * (2.0 * T0 * T0 / 3.0 + T1 * (T1 - 4.0 + * T0 / 3.0)) - 2.0 * T0 * T0 * T0 / 15.0; + qsrc = -T3 * T4; + QovCox = qsrc / Coxeff; + T8 = 4.0 / 3.0 * T1 * (T1 - T0) + 0.4 * T0 * T0; + T5 = -2.0 * qsrc / T2 - T3 * (T1 * (3.0 * T1 - 8.0 + * T0 / 3.0) + 2.0 * T0 * T0 / 3.0); + T6 = AbulkCV * (qsrc / T2 + T3 * T8); + T7 = T6 * VdseffCV / AbulkCV; + + Csg = T5 * (1.0 - dDeltaPhi_dVg) + T6 * dVdseffCV_dVg; + Csd = Csg * dVgsteff_dVd + T6 * dVdseffCV_dVd + + QovCox * dCoxeff_dVd; + Csb = Csg * dVgsteff_dVb + T6 * dVdseffCV_dVb + + T7 * dAbulkCV_dVb + QovCox * dCoxeff_dVb; + Csg = Csg * dVgsteff_dVg + QovCox * dCoxeff_dVg; + } + else + { /* 50/50 partition */ + qsrc = -0.5 * qgate; + Csg = -0.5 * Cgg1; + Csd = -0.5 * Cgd1; + Csb = -0.5 * Cgb1; + } + + qgate += Qac0 + Qsub0 - qbulk; + qbulk -= (Qac0 + Qsub0); + qdrn = -(qgate + qbulk + qsrc); + + Cbg = Cbg1 - dQac0_dVg - dQsub0_dVg; + Cbd = Cbd1 - dQsub0_dVd; + Cbb = Cbb1 - dQac0_dVb - dQsub0_dVb; + + Cgg = Cgg1 - Cbg; + Cgd = Cgd1 - Cbd; + Cgb = Cgb1 - Cbb; + + Cgb *= dVbseff_dVb; + Cbb *= dVbseff_dVb; + Csb *= dVbseff_dVb; + + here->BSIM4cggb = Cgg; + here->BSIM4cgsb = -(Cgg + Cgd + Cgb); + here->BSIM4cgdb = Cgd; + here->BSIM4cdgb = -(Cgg + Cbg + Csg); + here->BSIM4cdsb = (Cgg + Cgd + Cgb + Cbg + Cbd + Cbb + + Csg + Csd + Csb); + here->BSIM4cddb = -(Cgd + Cbd + Csd); + here->BSIM4cbgb = Cbg; + here->BSIM4cbsb = -(Cbg + Cbd + Cbb); + here->BSIM4cbdb = Cbd; + } /* End of CTM */ + } + + here->BSIM4qgate = qgate; + here->BSIM4qbulk = qbulk; + here->BSIM4qdrn = qdrn; + + /* NQS begins */ + if ((here->BSIM4trnqsMod) || (here->BSIM4acnqsMod)) + { here->BSIM4qchqs = qcheq = -(qbulk + qgate); + here->BSIM4cqgb = -(here->BSIM4cggb + here->BSIM4cbgb); + here->BSIM4cqdb = -(here->BSIM4cgdb + here->BSIM4cbdb); + here->BSIM4cqsb = -(here->BSIM4cgsb + here->BSIM4cbsb); + here->BSIM4cqbb = -(here->BSIM4cqgb + here->BSIM4cqdb + + here->BSIM4cqsb); + + CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV * here->BSIM4nf + * pParam->BSIM4leffCV; + T1 = here->BSIM4gcrg / CoxWL; /* 1 / tau */ + here->BSIM4gtau = T1 * ScalingFactor; + + if (here->BSIM4acnqsMod) + here->BSIM4taunet = 1.0 / T1; + + *(ckt->CKTstate0 + here->BSIM4qcheq) = qcheq; + if (ckt->CKTmode & MODEINITTRAN) + *(ckt->CKTstate1 + here->BSIM4qcheq) = + *(ckt->CKTstate0 + here->BSIM4qcheq); + if (here->BSIM4trnqsMod) + { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qcheq); + if (error) + return(error); + } + } + + +finished: + + /* Calculate junction C-V */ + if (ChargeComputationNeeded) + { czbd = model->BSIM4DunitAreaJctCap * here->BSIM4Adeff; + czbs = model->BSIM4SunitAreaJctCap * here->BSIM4Aseff; + czbdsw = model->BSIM4DunitLengthSidewallJctCap * here->BSIM4Pdeff; + czbdswg = model->BSIM4DunitLengthGateSidewallJctCap + * pParam->BSIM4weffCJ * here->BSIM4nf; + czbssw = model->BSIM4SunitLengthSidewallJctCap * here->BSIM4Pseff; + czbsswg = model->BSIM4SunitLengthGateSidewallJctCap + * pParam->BSIM4weffCJ * here->BSIM4nf; + + MJS = model->BSIM4SbulkJctBotGradingCoeff; + MJSWS = model->BSIM4SbulkJctSideGradingCoeff; + MJSWGS = model->BSIM4SbulkJctGateSideGradingCoeff; + + MJD = model->BSIM4DbulkJctBotGradingCoeff; + MJSWD = model->BSIM4DbulkJctSideGradingCoeff; + MJSWGD = model->BSIM4DbulkJctGateSideGradingCoeff; + + /* Source Bulk Junction */ + if (vbs_jct == 0.0) + { *(ckt->CKTstate0 + here->BSIM4qbs) = 0.0; + here->BSIM4capbs = czbs + czbssw + czbsswg; + } + else if (vbs_jct < 0.0) + { if (czbs > 0.0) + { arg = 1.0 - vbs_jct / model->BSIM4PhiBS; + if (MJS == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJS * log(arg)); + *(ckt->CKTstate0 + here->BSIM4qbs) = model->BSIM4PhiBS * czbs + * (1.0 - arg * sarg) / (1.0 - MJS); + here->BSIM4capbs = czbs * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM4qbs) = 0.0; + here->BSIM4capbs = 0.0; + } + if (czbssw > 0.0) + { arg = 1.0 - vbs_jct / model->BSIM4PhiBSWS; + if (MJSWS == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWS * log(arg)); + *(ckt->CKTstate0 + here->BSIM4qbs) += model->BSIM4PhiBSWS * czbssw + * (1.0 - arg * sarg) / (1.0 - MJSWS); + here->BSIM4capbs += czbssw * sarg; + } + if (czbsswg > 0.0) + { arg = 1.0 - vbs_jct / model->BSIM4PhiBSWGS; + if (MJSWGS == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWGS * log(arg)); + *(ckt->CKTstate0 + here->BSIM4qbs) += model->BSIM4PhiBSWGS * czbsswg + * (1.0 - arg * sarg) / (1.0 - MJSWGS); + here->BSIM4capbs += czbsswg * sarg; + } + + } + else + { T0 = czbs + czbssw + czbsswg; + T1 = vbs_jct * (czbs * MJS / model->BSIM4PhiBS + czbssw * MJSWS + / model->BSIM4PhiBSWS + czbsswg * MJSWGS / model->BSIM4PhiBSWGS); + *(ckt->CKTstate0 + here->BSIM4qbs) = vbs_jct * (T0 + 0.5 * T1); + here->BSIM4capbs = T0 + T1; + } + + /* Drain Bulk Junction */ + if (vbd_jct == 0.0) + { *(ckt->CKTstate0 + here->BSIM4qbd) = 0.0; + here->BSIM4capbd = czbd + czbdsw + czbdswg; + } + else if (vbd_jct < 0.0) + { if (czbd > 0.0) + { arg = 1.0 - vbd_jct / model->BSIM4PhiBD; + if (MJD == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJD * log(arg)); + *(ckt->CKTstate0 + here->BSIM4qbd) = model->BSIM4PhiBD* czbd + * (1.0 - arg * sarg) / (1.0 - MJD); + here->BSIM4capbd = czbd * sarg; + } + else + { *(ckt->CKTstate0 + here->BSIM4qbd) = 0.0; + here->BSIM4capbd = 0.0; + } + if (czbdsw > 0.0) + { arg = 1.0 - vbd_jct / model->BSIM4PhiBSWD; + if (MJSWD == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWD * log(arg)); + *(ckt->CKTstate0 + here->BSIM4qbd) += model->BSIM4PhiBSWD * czbdsw + * (1.0 - arg * sarg) / (1.0 - MJSWD); + here->BSIM4capbd += czbdsw * sarg; + } + if (czbdswg > 0.0) + { arg = 1.0 - vbd_jct / model->BSIM4PhiBSWGD; + if (MJSWGD == 0.5) + sarg = 1.0 / sqrt(arg); + else + sarg = exp(-MJSWGD * log(arg)); + *(ckt->CKTstate0 + here->BSIM4qbd) += model->BSIM4PhiBSWGD * czbdswg + * (1.0 - arg * sarg) / (1.0 - MJSWGD); + here->BSIM4capbd += czbdswg * sarg; + } + } + else + { T0 = czbd + czbdsw + czbdswg; + T1 = vbd_jct * (czbd * MJD / model->BSIM4PhiBD + czbdsw * MJSWD + / model->BSIM4PhiBSWD + czbdswg * MJSWGD / model->BSIM4PhiBSWGD); + *(ckt->CKTstate0 + here->BSIM4qbd) = vbd_jct * (T0 + 0.5 * T1); + here->BSIM4capbd = T0 + T1; + } + } + + + /* + * check convergence + */ + + if ((here->BSIM4off == 0) || (!(ckt->CKTmode & MODEINITFIX))) + { if (Check == 1) + { ckt->CKTnoncon++; +#ifndef NEWCONV + } + else + { if (here->BSIM4mode >= 0) + { Idtot = here->BSIM4cd + here->BSIM4csub + + here->BSIM4Igidl - here->BSIM4cbd; + } + else + { Idtot = here->BSIM4cd + here->BSIM4cbd; + } + tol0 = ckt->CKTreltol * MAX(fabs(cdhat), fabs(Idtot)) + + ckt->CKTabstol; + tol1 = ckt->CKTreltol * MAX(fabs(cseshat), fabs(Isestot)) + + ckt->CKTabstol; + tol2 = ckt->CKTreltol * MAX(fabs(cdedhat), fabs(Idedtot)) + + ckt->CKTabstol; + tol3 = ckt->CKTreltol * MAX(fabs(cgshat), fabs(Igstot)) + + ckt->CKTabstol; + tol4 = ckt->CKTreltol * MAX(fabs(cgdhat), fabs(Igdtot)) + + ckt->CKTabstol; + tol5 = ckt->CKTreltol * MAX(fabs(cgbhat), fabs(Igbtot)) + + ckt->CKTabstol; + if ((fabs(cdhat - Idtot) >= tol0) || (fabs(cseshat - Isestot) >= tol1) + || (fabs(cdedhat - Idedtot) >= tol2)) + { ckt->CKTnoncon++; + } + else if ((fabs(cgshat - Igstot) >= tol3) || (fabs(cgdhat - Igdtot) >= tol4) + || (fabs(cgbhat - Igbtot) >= tol5)) + { ckt->CKTnoncon++; + } + else + { Ibtot = here->BSIM4cbs + here->BSIM4cbd + - here->BSIM4Igidl - here->BSIM4csub; + tol6 = ckt->CKTreltol * MAX(fabs(cbhat), fabs(Ibtot)) + + ckt->CKTabstol; + if (fabs(cbhat - Ibtot) > tol6) + { ckt->CKTnoncon++; + } + } +#endif /* NEWCONV */ + } + } + *(ckt->CKTstate0 + here->BSIM4vds) = vds; + *(ckt->CKTstate0 + here->BSIM4vgs) = vgs; + *(ckt->CKTstate0 + here->BSIM4vbs) = vbs; + *(ckt->CKTstate0 + here->BSIM4vbd) = vbd; + *(ckt->CKTstate0 + here->BSIM4vges) = vges; + *(ckt->CKTstate0 + here->BSIM4vgms) = vgms; + *(ckt->CKTstate0 + here->BSIM4vdbs) = vdbs; + *(ckt->CKTstate0 + here->BSIM4vdbd) = vdbd; + *(ckt->CKTstate0 + here->BSIM4vsbs) = vsbs; + *(ckt->CKTstate0 + here->BSIM4vses) = vses; + *(ckt->CKTstate0 + here->BSIM4vdes) = vdes; + *(ckt->CKTstate0 + here->BSIM4qdef) = qdef; + + + if (!ChargeComputationNeeded) + goto line850; + + if (model->BSIM4capMod == 0) + { if (vgd < 0.0) + { cgdo = pParam->BSIM4cgdo; + qgdo = pParam->BSIM4cgdo * vgd; + } + else + { cgdo = pParam->BSIM4cgdo; + qgdo = pParam->BSIM4cgdo * vgd; + } + + if (vgs < 0.0) + { cgso = pParam->BSIM4cgso; + qgso = pParam->BSIM4cgso * vgs; + } + else + { cgso = pParam->BSIM4cgso; + qgso = pParam->BSIM4cgso * vgs; + } + } + else /* For both capMod == 1 and 2 */ + { T0 = vgd + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + + T3 = pParam->BSIM4weffCV * pParam->BSIM4cgdl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM4ckappad); + cgdo = pParam->BSIM4cgdo + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgdo = (pParam->BSIM4cgdo + T3) * vgd - T3 * (T2 + + 0.5 * pParam->BSIM4ckappad * (T4 - 1.0)); + + T0 = vgs + DELTA_1; + T1 = sqrt(T0 * T0 + 4.0 * DELTA_1); + T2 = 0.5 * (T0 - T1); + T3 = pParam->BSIM4weffCV * pParam->BSIM4cgsl; + T4 = sqrt(1.0 - 4.0 * T2 / pParam->BSIM4ckappas); + cgso = pParam->BSIM4cgso + T3 - T3 * (1.0 - 1.0 / T4) + * (0.5 - 0.5 * T0 / T1); + qgso = (pParam->BSIM4cgso + T3) * vgs - T3 * (T2 + + 0.5 * pParam->BSIM4ckappas * (T4 - 1.0)); + } + + if (here->BSIM4nf != 1.0) + { cgdo *= here->BSIM4nf; + cgso *= here->BSIM4nf; + qgdo *= here->BSIM4nf; + qgso *= here->BSIM4nf; + } + here->BSIM4cgdo = cgdo; + here->BSIM4qgdo = qgdo; + here->BSIM4cgso = cgso; + here->BSIM4qgso = qgso; + + +line755: + ag0 = ckt->CKTag[0]; + if (here->BSIM4mode > 0) + { if (here->BSIM4trnqsMod == 0) + { qdrn -= qgdo; + if (here->BSIM4rgateMod == 3) + { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; + gcgmdb = -cgdo * ag0; + gcgmsb = -cgso * ag0; + gcgmbb = -pParam->BSIM4cgbo * ag0; + + gcdgmb = gcgmdb; + gcsgmb = gcgmsb; + gcbgmb = gcgmbb; + + gcggb = here->BSIM4cggb * ag0; + gcgdb = here->BSIM4cgdb * ag0; + gcgsb = here->BSIM4cgsb * ag0; + gcgbb = -(gcggb + gcgdb + gcgsb); + + gcdgb = here->BSIM4cdgb * ag0; + gcsgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb) * ag0; + gcbgb = here->BSIM4cbgb * ag0; + + qgmb = pParam->BSIM4cgbo * vgmb; + qgmid = qgdo + qgso + qgmb; + qbulk -= qgmb; + qsrc = -(qgate + qgmid + qbulk + qdrn); + } + else + { gcggb = (here->BSIM4cggb + cgdo + cgso + + pParam->BSIM4cgbo ) * ag0; + gcgdb = (here->BSIM4cgdb - cgdo) * ag0; + gcgsb = (here->BSIM4cgsb - cgso) * ag0; + gcgbb = -(gcggb + gcgdb + gcgsb); + + gcdgb = (here->BSIM4cdgb - cgdo) * ag0; + gcsgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb + cgso) * ag0; + gcbgb = (here->BSIM4cbgb - pParam->BSIM4cgbo) * ag0; + + gcdgmb = gcsgmb = gcbgmb = 0.0; + + qgb = pParam->BSIM4cgbo * vgb; + qgate += qgdo + qgso + qgb; + qbulk -= qgb; + qsrc = -(qgate + qbulk + qdrn); + } + gcddb = (here->BSIM4cddb + here->BSIM4capbd + cgdo) * ag0; + gcdsb = here->BSIM4cdsb * ag0; + + gcsdb = -(here->BSIM4cgdb + here->BSIM4cbdb + + here->BSIM4cddb) * ag0; + gcssb = (here->BSIM4capbs + cgso - (here->BSIM4cgsb + + here->BSIM4cbsb + here->BSIM4cdsb)) * ag0; + + if (!here->BSIM4rbodyMod) + { gcdbb = -(gcdgb + gcddb + gcdsb + gcdgmb); + gcsbb = -(gcsgb + gcsdb + gcssb + gcsgmb); + gcbdb = (here->BSIM4cbdb - here->BSIM4capbd) * ag0; + gcbsb = (here->BSIM4cbsb - here->BSIM4capbs) * ag0; + gcdbdb = 0.0; + } + else + { gcdbb = -(here->BSIM4cddb + here->BSIM4cdgb + + here->BSIM4cdsb) * ag0; + gcsbb = -(gcsgb + gcsdb + gcssb + gcsgmb) + + here->BSIM4capbs * ag0; + gcbdb = here->BSIM4cbdb * ag0; + gcbsb = here->BSIM4cbsb * ag0; + + gcdbdb = -here->BSIM4capbd * ag0; + gcsbsb = -here->BSIM4capbs * ag0; + } + gcbbb = -(gcbdb + gcbgb + gcbsb + gcbgmb); + + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + } + else + { qcheq = here->BSIM4qchqs; + CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV * here->BSIM4nf + * pParam->BSIM4leffCV; + T0 = qdef * ScalingFactor / CoxWL; + + ggtg = here->BSIM4gtg = T0 * here->BSIM4gcrgg; + ggtd = here->BSIM4gtd = T0 * here->BSIM4gcrgd; + ggts = here->BSIM4gts = T0 * here->BSIM4gcrgs; + ggtb = here->BSIM4gtb = T0 * here->BSIM4gcrgb; + gqdef = ScalingFactor * ag0; + + gcqgb = here->BSIM4cqgb * ag0; + gcqdb = here->BSIM4cqdb * ag0; + gcqsb = here->BSIM4cqsb * ag0; + gcqbb = here->BSIM4cqbb * ag0; + + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM4xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM4xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = qdrn / qcheq; + Cdd = here->BSIM4cddb; + Csd = -(here->BSIM4cgdb + here->BSIM4cddb + + here->BSIM4cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM4cdgb; + Csg = -(here->BSIM4cggb + here->BSIM4cdgb + + here->BSIM4cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM4cdsb; + Css = -(here->BSIM4cgsb + here->BSIM4cdsb + + here->BSIM4cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + + if (here->BSIM4rgateMod == 3) + { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; + gcgmdb = -cgdo * ag0; + gcgmsb = -cgso * ag0; + gcgmbb = -pParam->BSIM4cgbo * ag0; + + gcdgmb = gcgmdb; + gcsgmb = gcgmsb; + gcbgmb = gcgmbb; + + gcdgb = gcsgb = gcbgb = 0.0; + gcggb = gcgdb = gcgsb = gcgbb = 0.0; + + qgmb = pParam->BSIM4cgbo * vgmb; + qgmid = qgdo + qgso + qgmb; + qgate = 0.0; + qbulk = -qgmb; + qdrn = -qgdo; + qsrc = -(qgmid + qbulk + qdrn); + } + else + { gcggb = (cgdo + cgso + pParam->BSIM4cgbo ) * ag0; + gcgdb = -cgdo * ag0; + gcgsb = -cgso * ag0; + gcgbb = -pParam->BSIM4cgbo * ag0; + + gcdgb = gcgdb; + gcsgb = gcgsb; + gcbgb = gcgbb; + gcdgmb = gcsgmb = gcbgmb = 0.0; + + qgb = pParam->BSIM4cgbo * vgb; + qgate = qgdo + qgso + qgb; + qbulk = -qgb; + qdrn = -qgdo; + qsrc = -(qgate + qbulk + qdrn); + } + + gcddb = (here->BSIM4capbd + cgdo) * ag0; + gcdsb = gcsdb = 0.0; + gcssb = (here->BSIM4capbs + cgso) * ag0; + + if (!here->BSIM4rbodyMod) + { gcdbb = -(gcdgb + gcddb + gcdgmb); + gcsbb = -(gcsgb + gcssb + gcsgmb); + gcbdb = -here->BSIM4capbd * ag0; + gcbsb = -here->BSIM4capbs * ag0; + gcdbdb = 0.0; + } + else + { gcdbb = gcsbb = gcbdb = gcbsb = 0.0; + gcdbdb = -here->BSIM4capbd * ag0; + gcsbsb = -here->BSIM4capbs * ag0; + } + gcbbb = -(gcbdb + gcbgb + gcbsb + gcbgmb); + } + } + else + { if (here->BSIM4trnqsMod == 0) + { qsrc = qdrn - qgso; + if (here->BSIM4rgateMod == 3) + { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; + gcgmdb = -cgdo * ag0; + gcgmsb = -cgso * ag0; + gcgmbb = -pParam->BSIM4cgbo * ag0; + + gcdgmb = gcgmdb; + gcsgmb = gcgmsb; + gcbgmb = gcgmbb; + + gcggb = here->BSIM4cggb * ag0; + gcgdb = here->BSIM4cgsb * ag0; + gcgsb = here->BSIM4cgdb * ag0; + gcgbb = -(gcggb + gcgdb + gcgsb); + + gcdgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb) * ag0; + gcsgb = here->BSIM4cdgb * ag0; + gcbgb = here->BSIM4cbgb * ag0; + + qgmb = pParam->BSIM4cgbo * vgmb; + qgmid = qgdo + qgso + qgmb; + qbulk -= qgmb; + qdrn = -(qgate + qgmid + qbulk + qsrc); + } + else + { gcggb = (here->BSIM4cggb + cgdo + cgso + + pParam->BSIM4cgbo ) * ag0; + gcgdb = (here->BSIM4cgsb - cgdo) * ag0; + gcgsb = (here->BSIM4cgdb - cgso) * ag0; + gcgbb = -(gcggb + gcgdb + gcgsb); + + gcdgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb + cgdo) * ag0; + gcsgb = (here->BSIM4cdgb - cgso) * ag0; + gcbgb = (here->BSIM4cbgb - pParam->BSIM4cgbo) * ag0; + + gcdgmb = gcsgmb = gcbgmb = 0.0; + + qgb = pParam->BSIM4cgbo * vgb; + qgate += qgdo + qgso + qgb; + qbulk -= qgb; + qdrn = -(qgate + qbulk + qsrc); + } + gcddb = (here->BSIM4capbd + cgdo - (here->BSIM4cgsb + + here->BSIM4cbsb + here->BSIM4cdsb)) * ag0; + gcdsb = -(here->BSIM4cgdb + here->BSIM4cbdb + + here->BSIM4cddb) * ag0; + + gcsdb = here->BSIM4cdsb * ag0; + gcssb = (here->BSIM4cddb + here->BSIM4capbs + cgso) * ag0; + + if (!here->BSIM4rbodyMod) + { gcdbb = -(gcdgb + gcddb + gcdsb + gcdgmb); + gcsbb = -(gcsgb + gcsdb + gcssb + gcsgmb); + gcbdb = (here->BSIM4cbsb - here->BSIM4capbd) * ag0; + gcbsb = (here->BSIM4cbdb - here->BSIM4capbs) * ag0; + gcdbdb = 0.0; + } + else + { gcdbb = -(gcdgb + gcddb + gcdsb + gcdgmb) + + here->BSIM4capbd * ag0; + gcsbb = -(here->BSIM4cddb + here->BSIM4cdgb + + here->BSIM4cdsb) * ag0; + gcbdb = here->BSIM4cbsb * ag0; + gcbsb = here->BSIM4cbdb * ag0; + gcdbdb = -here->BSIM4capbd * ag0; + gcsbsb = -here->BSIM4capbs * ag0; + } + gcbbb = -(gcbgb + gcbdb + gcbsb + gcbgmb); + + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + } + else + { qcheq = here->BSIM4qchqs; + CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV * here->BSIM4nf + * pParam->BSIM4leffCV; + T0 = qdef * ScalingFactor / CoxWL; + ggtg = here->BSIM4gtg = T0 * here->BSIM4gcrgg; + ggts = here->BSIM4gtd = T0 * here->BSIM4gcrgs; + ggtd = here->BSIM4gts = T0 * here->BSIM4gcrgd; + ggtb = here->BSIM4gtb = T0 * here->BSIM4gcrgb; + gqdef = ScalingFactor * ag0; + + gcqgb = here->BSIM4cqgb * ag0; + gcqdb = here->BSIM4cqsb * ag0; + gcqsb = here->BSIM4cqdb * ag0; + gcqbb = here->BSIM4cqbb * ag0; + + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM4xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM4xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = qdrn / qcheq; + Css = here->BSIM4cddb; + Cds = -(here->BSIM4cgdb + here->BSIM4cddb + + here->BSIM4cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM4cdgb; + Cdg = -(here->BSIM4cggb + here->BSIM4cdgb + + here->BSIM4cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM4cdsb; + Cdd = -(here->BSIM4cgsb + here->BSIM4cdsb + + here->BSIM4cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + + if (here->BSIM4rgateMod == 3) + { gcgmgmb = (cgdo + cgso + pParam->BSIM4cgbo) * ag0; + gcgmdb = -cgdo * ag0; + gcgmsb = -cgso * ag0; + gcgmbb = -pParam->BSIM4cgbo * ag0; + + gcdgmb = gcgmdb; + gcsgmb = gcgmsb; + gcbgmb = gcgmbb; + + gcdgb = gcsgb = gcbgb = 0.0; + gcggb = gcgdb = gcgsb = gcgbb = 0.0; + + qgmb = pParam->BSIM4cgbo * vgmb; + qgmid = qgdo + qgso + qgmb; + qgate = 0.0; + qbulk = -qgmb; + qdrn = -qgdo; + qsrc = -qgso; + } + else + { gcggb = (cgdo + cgso + pParam->BSIM4cgbo ) * ag0; + gcgdb = -cgdo * ag0; + gcgsb = -cgso * ag0; + gcgbb = -pParam->BSIM4cgbo * ag0; + + gcdgb = gcgdb; + gcsgb = gcgsb; + gcbgb = gcgbb; + gcdgmb = gcsgmb = gcbgmb = 0.0; + + qgb = pParam->BSIM4cgbo * vgb; + qgate = qgdo + qgso + qgb; + qbulk = -qgb; + qdrn = -qgdo; + qsrc = -qgso; + } + + gcddb = (here->BSIM4capbd + cgdo) * ag0; + gcdsb = gcsdb = 0.0; + gcssb = (here->BSIM4capbs + cgso) * ag0; + if (!here->BSIM4rbodyMod) + { gcdbb = -(gcdgb + gcddb + gcdgmb); + gcsbb = -(gcsgb + gcssb + gcsgmb); + gcbdb = -here->BSIM4capbd * ag0; + gcbsb = -here->BSIM4capbs * ag0; + gcdbdb = 0.0; + } + else + { gcdbb = gcsbb = gcbdb = gcbsb = 0.0; + gcdbdb = -here->BSIM4capbd * ag0; + gcsbsb = -here->BSIM4capbs * ag0; + } + gcbbb = -(gcbdb + gcbgb + gcbsb + gcbgmb); + } + } + + + if (here->BSIM4trnqsMod) + { *(ckt->CKTstate0 + here->BSIM4qcdump) = qdef * ScalingFactor; + if (ckt->CKTmode & MODEINITTRAN) + *(ckt->CKTstate1 + here->BSIM4qcdump) = + *(ckt->CKTstate0 + here->BSIM4qcdump); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qcdump); + if (error) + return(error); + } + + if (ByPass) goto line860; + + *(ckt->CKTstate0 + here->BSIM4qg) = qgate; + *(ckt->CKTstate0 + here->BSIM4qd) = qdrn + - *(ckt->CKTstate0 + here->BSIM4qbd); + if (here->BSIM4rgateMod == 3) + *(ckt->CKTstate0 + here->BSIM4qgmid) = qgmid; + + if (!here->BSIM4rbodyMod) + { *(ckt->CKTstate0 + here->BSIM4qb) = qbulk + + *(ckt->CKTstate0 + here->BSIM4qbd) + + *(ckt->CKTstate0 + here->BSIM4qbs); + } + else + *(ckt->CKTstate0 + here->BSIM4qb) = qbulk; + + + /* Store small signal parameters */ + if (ckt->CKTmode & MODEINITSMSIG) + { goto line1000; + } + + if (!ChargeComputationNeeded) + goto line850; + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM4qb) = + *(ckt->CKTstate0 + here->BSIM4qb); + *(ckt->CKTstate1 + here->BSIM4qg) = + *(ckt->CKTstate0 + here->BSIM4qg); + *(ckt->CKTstate1 + here->BSIM4qd) = + *(ckt->CKTstate0 + here->BSIM4qd); + if (here->BSIM4rgateMod == 3) + *(ckt->CKTstate1 + here->BSIM4qgmid) = + *(ckt->CKTstate0 + here->BSIM4qgmid); + if (here->BSIM4rbodyMod) + { *(ckt->CKTstate1 + here->BSIM4qbs) = + *(ckt->CKTstate0 + here->BSIM4qbs); + *(ckt->CKTstate1 + here->BSIM4qbd) = + *(ckt->CKTstate0 + here->BSIM4qbd); + } + } + + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qb); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qg); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qd); + if (error) + return(error); + + if (here->BSIM4rgateMod == 3) + { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qgmid); + if (error) return(error); + } + + if (here->BSIM4rbodyMod) + { error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qbs); + if (error) + return(error); + error = NIintegrate(ckt, &geq, &ceq, 0.0, here->BSIM4qbd); + if (error) + return(error); + } + + goto line860; + + +line850: + /* Zero gcap and ceqcap if (!ChargeComputationNeeded) */ + ceqqg = ceqqb = ceqqd = 0.0; + ceqqjd = ceqqjs = 0.0; + cqcheq = cqdef = 0.0; + + gcdgb = gcddb = gcdsb = gcdbb = 0.0; + gcsgb = gcsdb = gcssb = gcsbb = 0.0; + gcggb = gcgdb = gcgsb = gcgbb = 0.0; + gcbdb = gcbgb = gcbsb = gcbbb = 0.0; + + gcgmgmb = gcgmdb = gcgmsb = gcgmbb = 0.0; + gcdgmb = gcsgmb = gcbgmb = ceqqgmid = 0.0; + gcdbdb = gcsbsb = 0.0; + + gqdef = gcqgb = gcqdb = gcqsb = gcqbb = 0.0; + ggtg = ggtd = ggtb = ggts = 0.0; + sxpart = (1.0 - (dxpart = (here->BSIM4mode > 0) ? 0.4 : 0.6)); + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb = dsxpart_dVs = 0.0; + + if (here->BSIM4trnqsMod) + { CoxWL = model->BSIM4coxe * pParam->BSIM4weffCV * here->BSIM4nf + * pParam->BSIM4leffCV; + T1 = here->BSIM4gcrg / CoxWL; + here->BSIM4gtau = T1 * ScalingFactor; + } + else + here->BSIM4gtau = 0.0; + + goto line900; + + +line860: + /* Calculate equivalent charge current */ + + cqgate = *(ckt->CKTstate0 + here->BSIM4cqg); + cqbody = *(ckt->CKTstate0 + here->BSIM4cqb); + cqdrn = *(ckt->CKTstate0 + here->BSIM4cqd); + + ceqqg = cqgate - gcggb * vgb + gcgdb * vbd + gcgsb * vbs; + ceqqd = cqdrn - gcdgb * vgb - gcdgmb * vgmb + (gcddb + gcdbdb) + * vbd - gcdbdb * vbd_jct + gcdsb * vbs; + ceqqb = cqbody - gcbgb * vgb - gcbgmb * vgmb + + gcbdb * vbd + gcbsb * vbs; + + + if (here->BSIM4rgateMod == 3) + ceqqgmid = *(ckt->CKTstate0 + here->BSIM4cqgmid) + + gcgmdb * vbd + gcgmsb * vbs - gcgmgmb * vgmb; + else + ceqqgmid = 0.0; + + if (here->BSIM4rbodyMod) + { ceqqjs = *(ckt->CKTstate0 + here->BSIM4cqbs) + gcsbsb * vbs_jct; + ceqqjd = *(ckt->CKTstate0 + here->BSIM4cqbd) + gcdbdb * vbd_jct; + } + + if (here->BSIM4trnqsMod) + { T0 = ggtg * vgb - ggtd * vbd - ggts * vbs; + ceqqg += T0; + T1 = qdef * here->BSIM4gtau; + ceqqd -= dxpart * T0 + T1 * (ddxpart_dVg * vgb - ddxpart_dVd + * vbd - ddxpart_dVs * vbs); + cqdef = *(ckt->CKTstate0 + here->BSIM4cqcdump) - gqdef * qdef; + cqcheq = *(ckt->CKTstate0 + here->BSIM4cqcheq) + - (gcqgb * vgb - gcqdb * vbd - gcqsb * vbs) + T0; + } + + if (ckt->CKTmode & MODEINITTRAN) + { *(ckt->CKTstate1 + here->BSIM4cqb) = + *(ckt->CKTstate0 + here->BSIM4cqb); + *(ckt->CKTstate1 + here->BSIM4cqg) = + *(ckt->CKTstate0 + here->BSIM4cqg); + *(ckt->CKTstate1 + here->BSIM4cqd) = + *(ckt->CKTstate0 + here->BSIM4cqd); + + if (here->BSIM4rgateMod == 3) + *(ckt->CKTstate1 + here->BSIM4cqgmid) = + *(ckt->CKTstate0 + here->BSIM4cqgmid); + + if (here->BSIM4rbodyMod) + { *(ckt->CKTstate1 + here->BSIM4cqbs) = + *(ckt->CKTstate0 + here->BSIM4cqbs); + *(ckt->CKTstate1 + here->BSIM4cqbd) = + *(ckt->CKTstate0 + here->BSIM4cqbd); + } + } + + + /* + * Load current vector + */ + +line900: + if (here->BSIM4mode >= 0) + { Gm = here->BSIM4gm; + Gmbs = here->BSIM4gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + + ceqdrn = model->BSIM4type * (cdrain - here->BSIM4gds * vds + - Gm * vgs - Gmbs * vbs); + ceqbd = model->BSIM4type * (here->BSIM4csub + here->BSIM4Igidl + - (here->BSIM4gbds + here->BSIM4ggidld) * vds + - (here->BSIM4gbgs + here->BSIM4ggidlg) * vgs + - (here->BSIM4gbbs + here->BSIM4ggidlb) * vbs); + ceqbs = 0.0; + + gbbdp = -(here->BSIM4gbds + here->BSIM4ggidld); + gbbsp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs + - here->BSIM4ggidls; + + gbdpg = here->BSIM4gbgs + here->BSIM4ggidlg; + gbdpdp = here->BSIM4gbds + here->BSIM4ggidld; + gbdpb = here->BSIM4gbbs + here->BSIM4ggidlb; + gbdpsp = -(gbdpg + gbdpdp + gbdpb) + here->BSIM4ggidls; + + gbspg = 0.0; + gbspdp = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + if (model->BSIM4igcMod) + { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcsg; + gIstotd = here->BSIM4gIgcsd; + gIstots = here->BSIM4gIgss + here->BSIM4gIgcss; + gIstotb = here->BSIM4gIgcsb; + Istoteq = model->BSIM4type * (here->BSIM4Igs + here->BSIM4Igcs + - gIstotg * vgs - here->BSIM4gIgcsd * vds + - here->BSIM4gIgcsb * vbs); + + gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcdg; + gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcdd; + gIdtots = here->BSIM4gIgcds; + gIdtotb = here->BSIM4gIgcdb; + Idtoteq = model->BSIM4type * (here->BSIM4Igd + here->BSIM4Igcd + - here->BSIM4gIgdg * vgd - here->BSIM4gIgcdg * vgs + - here->BSIM4gIgcdd * vds - here->BSIM4gIgcdb * vbs); + } + else + { gIstotg = gIstotd = gIstots = gIstotb = Istoteq = 0.0; + gIdtotg = gIdtotd = gIdtots = gIdtotb = Idtoteq = 0.0; + } + + if (model->BSIM4igbMod) + { gIbtotg = here->BSIM4gIgbg; + gIbtotd = here->BSIM4gIgbd; + gIbtots = here->BSIM4gIgbs; + gIbtotb = here->BSIM4gIgbb; + Ibtoteq = model->BSIM4type * (here->BSIM4Igb + - here->BSIM4gIgbg * vgs - here->BSIM4gIgbd * vds + - here->BSIM4gIgbb * vbs); + } + else + gIbtotg = gIbtotd = gIbtots = gIbtotb = Ibtoteq = 0.0; + + if ((model->BSIM4igcMod != 0) || (model->BSIM4igbMod != 0)) + { gIgtotg = gIstotg + gIdtotg + gIbtotg; + gIgtotd = gIstotd + gIdtotd + gIbtotd ; + gIgtots = gIstots + gIdtots + gIbtots; + gIgtotb = gIstotb + gIdtotb + gIbtotb; + Igtoteq = Istoteq + Idtoteq + Ibtoteq; + } + else + gIgtotg = gIgtotd = gIgtots = gIgtotb = Igtoteq = 0.0; + + + if (here->BSIM4rgateMod == 2) + T0 = vges - vgs; + else if (here->BSIM4rgateMod == 3) + T0 = vgms - vgs; + if (here->BSIM4rgateMod > 1) + { gcrgd = here->BSIM4gcrgd * T0; + gcrgg = here->BSIM4gcrgg * T0; + gcrgs = here->BSIM4gcrgs * T0; + gcrgb = here->BSIM4gcrgb * T0; + ceqgcrg = -(gcrgd * vds + gcrgg * vgs + + gcrgb * vbs); + gcrgg -= here->BSIM4gcrg; + gcrg = here->BSIM4gcrg; + } + else + ceqgcrg = gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + } + else + { Gm = -here->BSIM4gm; + Gmbs = -here->BSIM4gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + + ceqdrn = -model->BSIM4type * (cdrain + here->BSIM4gds * vds + + Gm * vgd + Gmbs * vbd); + + ceqbs = model->BSIM4type * (here->BSIM4csub + here->BSIM4Igidl + + (here->BSIM4gbds + here->BSIM4ggidld) * vds + - (here->BSIM4gbgs + here->BSIM4ggidlg) * vgd + - (here->BSIM4gbbs + here->BSIM4ggidlb) * vbd); + ceqbd = 0.0; + + gbbsp = -(here->BSIM4gbds + here->BSIM4ggidld); + gbbdp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs + - here->BSIM4ggidls; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM4gbgs + here->BSIM4ggidlg; + gbspsp = here->BSIM4gbds + here->BSIM4ggidld; + gbspb = here->BSIM4gbbs + here->BSIM4ggidlb; + gbspdp = -(gbspg + gbspsp + gbspb) + here->BSIM4ggidls; + + if (model->BSIM4igcMod) + { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcdg; + gIstotd = here->BSIM4gIgcds; + gIstots = here->BSIM4gIgss + here->BSIM4gIgcdd; + gIstotb = here->BSIM4gIgcdb; + Istoteq = model->BSIM4type * (here->BSIM4Igs + here->BSIM4Igcd + - here->BSIM4gIgsg * vgs - here->BSIM4gIgcdg * vgd + + here->BSIM4gIgcdd * vds - here->BSIM4gIgcdb * vbd); + + gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcsg; + gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcss; + gIdtots = here->BSIM4gIgcsd; + gIdtotb = here->BSIM4gIgcsb; + Idtoteq = model->BSIM4type * (here->BSIM4Igd + here->BSIM4Igcs + - (here->BSIM4gIgdg + here->BSIM4gIgcsg) * vgd + + here->BSIM4gIgcsd * vds - here->BSIM4gIgcsb * vbd); + } + else + { gIstotg = gIstotd = gIstots = gIstotb = Istoteq = 0.0; + gIdtotg = gIdtotd = gIdtots = gIdtotb = Idtoteq = 0.0; + } + + if (model->BSIM4igbMod) + { gIbtotg = here->BSIM4gIgbg; + gIbtotd = here->BSIM4gIgbs; + gIbtots = here->BSIM4gIgbd; + gIbtotb = here->BSIM4gIgbb; + Ibtoteq = model->BSIM4type * (here->BSIM4Igb + - here->BSIM4gIgbg * vgd + here->BSIM4gIgbd * vds + - here->BSIM4gIgbb * vbd); + } + else + gIbtotg = gIbtotd = gIbtots = gIbtotb = Ibtoteq = 0.0; + + if ((model->BSIM4igcMod != 0) || (model->BSIM4igbMod != 0)) + { gIgtotg = gIstotg + gIdtotg + gIbtotg; + gIgtotd = gIstotd + gIdtotd + gIbtotd ; + gIgtots = gIstots + gIdtots + gIbtots; + gIgtotb = gIstotb + gIdtotb + gIbtotb; + Igtoteq = Istoteq + Idtoteq + Ibtoteq; + } + else + gIgtotg = gIgtotd = gIgtots = gIgtotb = Igtoteq = 0.0; + + + if (here->BSIM4rgateMod == 2) + T0 = vges - vgs; + else if (here->BSIM4rgateMod == 3) + T0 = vgms - vgs; + if (here->BSIM4rgateMod > 1) + { gcrgd = here->BSIM4gcrgs * T0; + gcrgg = here->BSIM4gcrgg * T0; + gcrgs = here->BSIM4gcrgd * T0; + gcrgb = here->BSIM4gcrgb * T0; + ceqgcrg = -(gcrgg * vgd - gcrgs * vds + + gcrgb * vbd); + gcrgg -= here->BSIM4gcrg; + gcrg = here->BSIM4gcrg; + } + else + ceqgcrg = gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + } + + if (model->BSIM4rdsMod == 1) + { ceqgstot = model->BSIM4type * (here->BSIM4gstotd * vds + + here->BSIM4gstotg * vgs + here->BSIM4gstotb * vbs); + /* WDLiu: ceqgstot flowing away from sNodePrime */ + gstot = here->BSIM4gstot; + gstotd = here->BSIM4gstotd; + gstotg = here->BSIM4gstotg; + gstots = here->BSIM4gstots - gstot; + gstotb = here->BSIM4gstotb; + + ceqgdtot = -model->BSIM4type * (here->BSIM4gdtotd * vds + + here->BSIM4gdtotg * vgs + here->BSIM4gdtotb * vbs); + /* WDLiu: ceqgdtot defined as flowing into dNodePrime */ + gdtot = here->BSIM4gdtot; + gdtotd = here->BSIM4gdtotd - gdtot; + gdtotg = here->BSIM4gdtotg; + gdtots = here->BSIM4gdtots; + gdtotb = here->BSIM4gdtotb; + } + else + { gstot = gstotd = gstotg = gstots = gstotb = ceqgstot = 0.0; + gdtot = gdtotd = gdtotg = gdtots = gdtotb = ceqgdtot = 0.0; + } + + if (model->BSIM4type > 0) + { ceqjs = (here->BSIM4cbs - here->BSIM4gbs * vbs_jct); + ceqjd = (here->BSIM4cbd - here->BSIM4gbd * vbd_jct); + } + else + { ceqjs = -(here->BSIM4cbs - here->BSIM4gbs * vbs_jct); + ceqjd = -(here->BSIM4cbd - here->BSIM4gbd * vbd_jct); + ceqqg = -ceqqg; + ceqqd = -ceqqd; + ceqqb = -ceqqb; + ceqgcrg = -ceqgcrg; + + if (here->BSIM4trnqsMod) + { cqdef = -cqdef; + cqcheq = -cqcheq; + } + + if (here->BSIM4rbodyMod) + { ceqqjs = -ceqqjs; + ceqqjd = -ceqqjd; + } + + if (here->BSIM4rgateMod == 3) + ceqqgmid = -ceqqgmid; + } + + + /* + * Loading RHS + */ + + + (*(ckt->CKTrhs + here->BSIM4dNodePrime) += (ceqjd - ceqbd + ceqgdtot + - ceqdrn - ceqqd + Idtoteq)); + (*(ckt->CKTrhs + here->BSIM4gNodePrime) -= ceqqg - ceqgcrg + Igtoteq); + + if (here->BSIM4rgateMod == 2) + (*(ckt->CKTrhs + here->BSIM4gNodeExt) -= ceqgcrg); + else if (here->BSIM4rgateMod == 3) + (*(ckt->CKTrhs + here->BSIM4gNodeMid) -= ceqqgmid + ceqgcrg); + + if (!here->BSIM4rbodyMod) + { (*(ckt->CKTrhs + here->BSIM4bNodePrime) += (ceqbd + ceqbs - ceqjd + - ceqjs - ceqqb + Ibtoteq)); + (*(ckt->CKTrhs + here->BSIM4sNodePrime) += (ceqdrn - ceqbs + ceqjs + + ceqqg + ceqqb + ceqqd + ceqqgmid - ceqgstot + Istoteq)); + } + else + { (*(ckt->CKTrhs + here->BSIM4dbNode) -= (ceqjd + ceqqjd)); + (*(ckt->CKTrhs + here->BSIM4bNodePrime) += (ceqbd + ceqbs - ceqqb + Ibtoteq)); + (*(ckt->CKTrhs + here->BSIM4sbNode) -= (ceqjs + ceqqjs)); + (*(ckt->CKTrhs + here->BSIM4sNodePrime) += (ceqdrn - ceqbs + ceqjs + ceqqd + + ceqqg + ceqqb + ceqqjd + ceqqjs + ceqqgmid - ceqgstot + Istoteq)); + } + + if (model->BSIM4rdsMod) + { (*(ckt->CKTrhs + here->BSIM4dNode) -= ceqgdtot); + (*(ckt->CKTrhs + here->BSIM4sNode) += ceqgstot); + } + + if (here->BSIM4trnqsMod) + *(ckt->CKTrhs + here->BSIM4qNode) += (cqcheq - cqdef); + + + /* + * Loading matrix + */ + + if (!here->BSIM4rbodyMod) + { gjbd = here->BSIM4gbd; + gjbs = here->BSIM4gbs; + } + else + gjbd = gjbs = 0.0; + + if (!model->BSIM4rdsMod) + { gdpr = here->BSIM4drainConductance; + gspr = here->BSIM4sourceConductance; + } + else + gdpr = gspr = 0.0; + + geltd = here->BSIM4grgeltd; + + T1 = qdef * here->BSIM4gtau; + + if (here->BSIM4rgateMod == 1) + { (*(here->BSIM4GEgePtr) += geltd); + (*(here->BSIM4GPgePtr) -= geltd); + (*(here->BSIM4GEgpPtr) -= geltd); + (*(here->BSIM4GPgpPtr) += gcggb + geltd - ggtg + gIgtotg); + (*(here->BSIM4GPdpPtr) += gcgdb - ggtd + gIgtotd); + (*(here->BSIM4GPspPtr) += gcgsb - ggts + gIgtots); + (*(here->BSIM4GPbpPtr) += gcgbb - ggtb + gIgtotb); + } /* WDLiu: gcrg already subtracted from all gcrgg below */ + else if (here->BSIM4rgateMod == 2) + { (*(here->BSIM4GEgePtr) += gcrg); + (*(here->BSIM4GEgpPtr) += gcrgg); + (*(here->BSIM4GEdpPtr) += gcrgd); + (*(here->BSIM4GEspPtr) += gcrgs); + (*(here->BSIM4GEbpPtr) += gcrgb); + + (*(here->BSIM4GPgePtr) -= gcrg); + (*(here->BSIM4GPgpPtr) += gcggb - gcrgg - ggtg + gIgtotg); + (*(here->BSIM4GPdpPtr) += gcgdb - gcrgd - ggtd + gIgtotd); + (*(here->BSIM4GPspPtr) += gcgsb - gcrgs - ggts + gIgtots); + (*(here->BSIM4GPbpPtr) += gcgbb - gcrgb - ggtb + gIgtotb); + } + else if (here->BSIM4rgateMod == 3) + { (*(here->BSIM4GEgePtr) += geltd); + (*(here->BSIM4GEgmPtr) -= geltd); + (*(here->BSIM4GMgePtr) -= geltd); + (*(here->BSIM4GMgmPtr) += geltd + gcrg + gcgmgmb); + + (*(here->BSIM4GMdpPtr) += gcrgd + gcgmdb); + (*(here->BSIM4GMgpPtr) += gcrgg); + (*(here->BSIM4GMspPtr) += gcrgs + gcgmsb); + (*(here->BSIM4GMbpPtr) += gcrgb + gcgmbb); + + (*(here->BSIM4DPgmPtr) += gcdgmb); + (*(here->BSIM4GPgmPtr) -= gcrg); + (*(here->BSIM4SPgmPtr) += gcsgmb); + (*(here->BSIM4BPgmPtr) += gcbgmb); + + (*(here->BSIM4GPgpPtr) += gcggb - gcrgg - ggtg + gIgtotg); + (*(here->BSIM4GPdpPtr) += gcgdb - gcrgd - ggtd + gIgtotd); + (*(here->BSIM4GPspPtr) += gcgsb - gcrgs - ggts + gIgtots); + (*(here->BSIM4GPbpPtr) += gcgbb - gcrgb - ggtb + gIgtotb); + } + else + { (*(here->BSIM4GPgpPtr) += gcggb - ggtg + gIgtotg); + (*(here->BSIM4GPdpPtr) += gcgdb - ggtd + gIgtotd); + (*(here->BSIM4GPspPtr) += gcgsb - ggts + gIgtots); + (*(here->BSIM4GPbpPtr) += gcgbb - ggtb + gIgtotb); + } + + if (model->BSIM4rdsMod) + { (*(here->BSIM4DgpPtr) += gdtotg); + (*(here->BSIM4DspPtr) += gdtots); + (*(here->BSIM4DbpPtr) += gdtotb); + (*(here->BSIM4SdpPtr) += gstotd); + (*(here->BSIM4SgpPtr) += gstotg); + (*(here->BSIM4SbpPtr) += gstotb); + } + + (*(here->BSIM4DPdpPtr) += gdpr + here->BSIM4gds + here->BSIM4gbd + T1 * ddxpart_dVd + - gdtotd + RevSum + gcddb + gbdpdp + dxpart * ggtd - gIdtotd); + (*(here->BSIM4DPdPtr) -= gdpr + gdtot); + (*(here->BSIM4DPgpPtr) += Gm + gcdgb - gdtotg + gbdpg - gIdtotg + + dxpart * ggtg + T1 * ddxpart_dVg); + (*(here->BSIM4DPspPtr) -= here->BSIM4gds + gdtots - dxpart * ggts + gIdtots + - T1 * ddxpart_dVs + FwdSum - gcdsb - gbdpsp); + (*(here->BSIM4DPbpPtr) -= gjbd + gdtotb - Gmbs - gcdbb - gbdpb + gIdtotb + - T1 * ddxpart_dVb - dxpart * ggtb); + + (*(here->BSIM4DdpPtr) -= gdpr - gdtotd); + (*(here->BSIM4DdPtr) += gdpr + gdtot); + + (*(here->BSIM4SPdpPtr) -= here->BSIM4gds + gstotd + RevSum - gcsdb - gbspdp + - T1 * dsxpart_dVd - sxpart * ggtd + gIstotd); + (*(here->BSIM4SPgpPtr) += gcsgb - Gm - gstotg + gbspg + sxpart * ggtg + + T1 * dsxpart_dVg - gIstotg); + (*(here->BSIM4SPspPtr) += gspr + here->BSIM4gds + here->BSIM4gbs + T1 * dsxpart_dVs + - gstots + FwdSum + gcssb + gbspsp + sxpart * ggts - gIstots); + (*(here->BSIM4SPsPtr) -= gspr + gstot); + (*(here->BSIM4SPbpPtr) -= gjbs + gstotb + Gmbs - gcsbb - gbspb - sxpart * ggtb + - T1 * dsxpart_dVb) + gIstotb; + + (*(here->BSIM4SspPtr) -= gspr - gstots); + (*(here->BSIM4SsPtr) += gspr + gstot); + + (*(here->BSIM4BPdpPtr) += gcbdb - gjbd + gbbdp - gIbtotd); + (*(here->BSIM4BPgpPtr) += gcbgb - here->BSIM4gbgs - here->BSIM4ggidlg - gIbtotg); + (*(here->BSIM4BPspPtr) += gcbsb - gjbs + gbbsp - gIbtots); + (*(here->BSIM4BPbpPtr) += gjbd + gjbs + gcbbb - here->BSIM4gbbs + - here->BSIM4ggidlb - gIbtotb); + + if (here->BSIM4rbodyMod) + { (*(here->BSIM4DPdbPtr) += gcdbdb - here->BSIM4gbd); + (*(here->BSIM4SPsbPtr) -= here->BSIM4gbs - gcsbsb); + + (*(here->BSIM4DBdpPtr) += gcdbdb - here->BSIM4gbd); + (*(here->BSIM4DBdbPtr) += here->BSIM4gbd - gcdbdb + + here->BSIM4grbpd + here->BSIM4grbdb); + (*(here->BSIM4DBbpPtr) -= here->BSIM4grbpd); + (*(here->BSIM4DBbPtr) -= here->BSIM4grbdb); + + (*(here->BSIM4BPdbPtr) -= here->BSIM4grbpd); + (*(here->BSIM4BPbPtr) -= here->BSIM4grbpb); + (*(here->BSIM4BPsbPtr) -= here->BSIM4grbps); + (*(here->BSIM4BPbpPtr) += here->BSIM4grbpd + here->BSIM4grbps + + here->BSIM4grbpb); + /* WDLiu: (gcbbb - here->BSIM4gbbs) already added to BPbpPtr */ + + (*(here->BSIM4SBspPtr) += gcsbsb - here->BSIM4gbs); + (*(here->BSIM4SBbpPtr) -= here->BSIM4grbps); + (*(here->BSIM4SBbPtr) -= here->BSIM4grbsb); + (*(here->BSIM4SBsbPtr) += here->BSIM4gbs - gcsbsb + + here->BSIM4grbps + here->BSIM4grbsb); + + (*(here->BSIM4BdbPtr) -= here->BSIM4grbdb); + (*(here->BSIM4BbpPtr) -= here->BSIM4grbpb); + (*(here->BSIM4BsbPtr) -= here->BSIM4grbsb); + (*(here->BSIM4BbPtr) += here->BSIM4grbsb + here->BSIM4grbdb + + here->BSIM4grbpb); + } + + if (here->BSIM4trnqsMod) + { (*(here->BSIM4QqPtr) += gqdef + here->BSIM4gtau); + (*(here->BSIM4QgpPtr) += ggtg - gcqgb); + (*(here->BSIM4QdpPtr) += ggtd - gcqdb); + (*(here->BSIM4QspPtr) += ggts - gcqsb); + (*(here->BSIM4QbpPtr) += ggtb - gcqbb); + + (*(here->BSIM4DPqPtr) += dxpart * here->BSIM4gtau); + (*(here->BSIM4SPqPtr) += sxpart * here->BSIM4gtau); + (*(here->BSIM4GPqPtr) -= here->BSIM4gtau); + } + +line1000: ; + + } /* End of MOSFET Instance */ +} /* End of Model Instance */ + +return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4mask.c b/src/spicelib/devices/bsim4/b4mask.c new file mode 100644 index 000000000..909e5b2e8 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4mask.c @@ -0,0 +1,1869 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4mask.c of BSIM4.0.0. + * Authors: Weidong Liu, Xiaodong Jin, Kanyu M. Cao, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "bsim4def.h" +#include "sperror.h" + + +int +BSIM4mAsk(ckt,inst,which,value) +CKTcircuit *ckt; +GENmodel *inst; +int which; +IFvalue *value; +{ + BSIM4model *model = (BSIM4model *)inst; + switch(which) + { case BSIM4_MOD_MOBMOD : + value->iValue = model->BSIM4mobMod; + return(OK); + case BSIM4_MOD_PARAMCHK : + value->iValue = model->BSIM4paramChk; + return(OK); + case BSIM4_MOD_BINUNIT : + value->iValue = model->BSIM4binUnit; + return(OK); + case BSIM4_MOD_CAPMOD : + value->iValue = model->BSIM4capMod; + return(OK); + case BSIM4_MOD_DIOMOD : + value->iValue = model->BSIM4dioMod; + return(OK); + case BSIM4_MOD_TRNQSMOD : + value->iValue = model->BSIM4trnqsMod; + return(OK); + case BSIM4_MOD_ACNQSMOD : + value->iValue = model->BSIM4acnqsMod; + return(OK); + case BSIM4_MOD_FNOIMOD : + value->iValue = model->BSIM4fnoiMod; + return(OK); + case BSIM4_MOD_TNOIMOD : + value->iValue = model->BSIM4tnoiMod; + return(OK); + case BSIM4_MOD_RDSMOD : + value->iValue = model->BSIM4rdsMod; + return(OK); + case BSIM4_MOD_RBODYMOD : + value->iValue = model->BSIM4rbodyMod; + return(OK); + case BSIM4_MOD_RGATEMOD : + value->iValue = model->BSIM4rgateMod; + return(OK); + case BSIM4_MOD_PERMOD : + value->iValue = model->BSIM4perMod; + return(OK); + case BSIM4_MOD_GEOMOD : + value->iValue = model->BSIM4geoMod; + return(OK); + case BSIM4_MOD_IGCMOD : + value->iValue = model->BSIM4igcMod; + return(OK); + case BSIM4_MOD_IGBMOD : + value->iValue = model->BSIM4igbMod; + return(OK); + case BSIM4_MOD_VERSION : + value->sValue = model->BSIM4version; + return(OK); + case BSIM4_MOD_TOXREF : + value->rValue = model->BSIM4toxref; + return(OK); + case BSIM4_MOD_TOXE : + value->rValue = model->BSIM4toxe; + return(OK); + case BSIM4_MOD_TOXP : + value->rValue = model->BSIM4toxp; + return(OK); + case BSIM4_MOD_TOXM : + value->rValue = model->BSIM4toxm; + return(OK); + case BSIM4_MOD_DTOX : + value->rValue = model->BSIM4dtox; + return(OK); + case BSIM4_MOD_EPSROX : + value->rValue = model->BSIM4epsrox; + return(OK); + case BSIM4_MOD_CDSC : + value->rValue = model->BSIM4cdsc; + return(OK); + case BSIM4_MOD_CDSCB : + value->rValue = model->BSIM4cdscb; + return(OK); + + case BSIM4_MOD_CDSCD : + value->rValue = model->BSIM4cdscd; + return(OK); + + case BSIM4_MOD_CIT : + value->rValue = model->BSIM4cit; + return(OK); + case BSIM4_MOD_NFACTOR : + value->rValue = model->BSIM4nfactor; + return(OK); + case BSIM4_MOD_XJ: + value->rValue = model->BSIM4xj; + return(OK); + case BSIM4_MOD_VSAT: + value->rValue = model->BSIM4vsat; + return(OK); + case BSIM4_MOD_AT: + value->rValue = model->BSIM4at; + return(OK); + case BSIM4_MOD_A0: + value->rValue = model->BSIM4a0; + return(OK); + + case BSIM4_MOD_AGS: + value->rValue = model->BSIM4ags; + return(OK); + + case BSIM4_MOD_A1: + value->rValue = model->BSIM4a1; + return(OK); + case BSIM4_MOD_A2: + value->rValue = model->BSIM4a2; + return(OK); + case BSIM4_MOD_KETA: + value->rValue = model->BSIM4keta; + return(OK); + case BSIM4_MOD_NSUB: + value->rValue = model->BSIM4nsub; + return(OK); + case BSIM4_MOD_NDEP: + value->rValue = model->BSIM4ndep; + return(OK); + case BSIM4_MOD_NSD: + value->rValue = model->BSIM4nsd; + return(OK); + case BSIM4_MOD_NGATE: + value->rValue = model->BSIM4ngate; + return(OK); + case BSIM4_MOD_GAMMA1: + value->rValue = model->BSIM4gamma1; + return(OK); + case BSIM4_MOD_GAMMA2: + value->rValue = model->BSIM4gamma2; + return(OK); + case BSIM4_MOD_VBX: + value->rValue = model->BSIM4vbx; + return(OK); + case BSIM4_MOD_VBM: + value->rValue = model->BSIM4vbm; + return(OK); + case BSIM4_MOD_XT: + value->rValue = model->BSIM4xt; + return(OK); + case BSIM4_MOD_K1: + value->rValue = model->BSIM4k1; + return(OK); + case BSIM4_MOD_KT1: + value->rValue = model->BSIM4kt1; + return(OK); + case BSIM4_MOD_KT1L: + value->rValue = model->BSIM4kt1l; + return(OK); + case BSIM4_MOD_KT2 : + value->rValue = model->BSIM4kt2; + return(OK); + case BSIM4_MOD_K2 : + value->rValue = model->BSIM4k2; + return(OK); + case BSIM4_MOD_K3: + value->rValue = model->BSIM4k3; + return(OK); + case BSIM4_MOD_K3B: + value->rValue = model->BSIM4k3b; + return(OK); + case BSIM4_MOD_W0: + value->rValue = model->BSIM4w0; + return(OK); + case BSIM4_MOD_LPE0: + value->rValue = model->BSIM4lpe0; + return(OK); + case BSIM4_MOD_LPEB: + value->rValue = model->BSIM4lpeb; + return(OK); + case BSIM4_MOD_DVTP0: + value->rValue = model->BSIM4dvtp0; + return(OK); + case BSIM4_MOD_DVTP1: + value->rValue = model->BSIM4dvtp1; + return(OK); + case BSIM4_MOD_DVT0 : + value->rValue = model->BSIM4dvt0; + return(OK); + case BSIM4_MOD_DVT1 : + value->rValue = model->BSIM4dvt1; + return(OK); + case BSIM4_MOD_DVT2 : + value->rValue = model->BSIM4dvt2; + return(OK); + case BSIM4_MOD_DVT0W : + value->rValue = model->BSIM4dvt0w; + return(OK); + case BSIM4_MOD_DVT1W : + value->rValue = model->BSIM4dvt1w; + return(OK); + case BSIM4_MOD_DVT2W : + value->rValue = model->BSIM4dvt2w; + return(OK); + case BSIM4_MOD_DROUT : + value->rValue = model->BSIM4drout; + return(OK); + case BSIM4_MOD_DSUB : + value->rValue = model->BSIM4dsub; + return(OK); + case BSIM4_MOD_VTH0: + value->rValue = model->BSIM4vth0; + return(OK); + case BSIM4_MOD_EU: + value->rValue = model->BSIM4eu; + return(OK); + case BSIM4_MOD_UA: + value->rValue = model->BSIM4ua; + return(OK); + case BSIM4_MOD_UA1: + value->rValue = model->BSIM4ua1; + return(OK); + case BSIM4_MOD_UB: + value->rValue = model->BSIM4ub; + return(OK); + case BSIM4_MOD_UB1: + value->rValue = model->BSIM4ub1; + return(OK); + case BSIM4_MOD_UC: + value->rValue = model->BSIM4uc; + return(OK); + case BSIM4_MOD_UC1: + value->rValue = model->BSIM4uc1; + return(OK); + case BSIM4_MOD_U0: + value->rValue = model->BSIM4u0; + return(OK); + case BSIM4_MOD_UTE: + value->rValue = model->BSIM4ute; + return(OK); + case BSIM4_MOD_VOFF: + value->rValue = model->BSIM4voff; + return(OK); + case BSIM4_MOD_VOFFL: + value->rValue = model->BSIM4voffl; + return(OK); + case BSIM4_MOD_MINV: + value->rValue = model->BSIM4minv; + return(OK); + case BSIM4_MOD_FPROUT: + value->rValue = model->BSIM4fprout; + return(OK); + case BSIM4_MOD_PDITS: + value->rValue = model->BSIM4pdits; + return(OK); + case BSIM4_MOD_PDITSD: + value->rValue = model->BSIM4pditsd; + return(OK); + case BSIM4_MOD_PDITSL: + value->rValue = model->BSIM4pditsl; + return(OK); + case BSIM4_MOD_DELTA: + value->rValue = model->BSIM4delta; + return(OK); + case BSIM4_MOD_RDSW: + value->rValue = model->BSIM4rdsw; + return(OK); + case BSIM4_MOD_RDSWMIN: + value->rValue = model->BSIM4rdswmin; + return(OK); + case BSIM4_MOD_RDWMIN: + value->rValue = model->BSIM4rdwmin; + return(OK); + case BSIM4_MOD_RSWMIN: + value->rValue = model->BSIM4rswmin; + return(OK); + case BSIM4_MOD_RDW: + value->rValue = model->BSIM4rdw; + return(OK); + case BSIM4_MOD_RSW: + value->rValue = model->BSIM4rsw; + return(OK); + case BSIM4_MOD_PRWG: + value->rValue = model->BSIM4prwg; + return(OK); + case BSIM4_MOD_PRWB: + value->rValue = model->BSIM4prwb; + return(OK); + case BSIM4_MOD_PRT: + value->rValue = model->BSIM4prt; + return(OK); + case BSIM4_MOD_ETA0: + value->rValue = model->BSIM4eta0; + return(OK); + case BSIM4_MOD_ETAB: + value->rValue = model->BSIM4etab; + return(OK); + case BSIM4_MOD_PCLM: + value->rValue = model->BSIM4pclm; + return(OK); + case BSIM4_MOD_PDIBL1: + value->rValue = model->BSIM4pdibl1; + return(OK); + case BSIM4_MOD_PDIBL2: + value->rValue = model->BSIM4pdibl2; + return(OK); + case BSIM4_MOD_PDIBLB: + value->rValue = model->BSIM4pdiblb; + return(OK); + case BSIM4_MOD_PSCBE1: + value->rValue = model->BSIM4pscbe1; + return(OK); + case BSIM4_MOD_PSCBE2: + value->rValue = model->BSIM4pscbe2; + return(OK); + case BSIM4_MOD_PVAG: + value->rValue = model->BSIM4pvag; + return(OK); + case BSIM4_MOD_WR: + value->rValue = model->BSIM4wr; + return(OK); + case BSIM4_MOD_DWG: + value->rValue = model->BSIM4dwg; + return(OK); + case BSIM4_MOD_DWB: + value->rValue = model->BSIM4dwb; + return(OK); + case BSIM4_MOD_B0: + value->rValue = model->BSIM4b0; + return(OK); + case BSIM4_MOD_B1: + value->rValue = model->BSIM4b1; + return(OK); + case BSIM4_MOD_ALPHA0: + value->rValue = model->BSIM4alpha0; + return(OK); + case BSIM4_MOD_ALPHA1: + value->rValue = model->BSIM4alpha1; + return(OK); + case BSIM4_MOD_BETA0: + value->rValue = model->BSIM4beta0; + return(OK); + case BSIM4_MOD_AGIDL: + value->rValue = model->BSIM4agidl; + return(OK); + case BSIM4_MOD_BGIDL: + value->rValue = model->BSIM4bgidl; + return(OK); + case BSIM4_MOD_CGIDL: + value->rValue = model->BSIM4cgidl; + return(OK); + case BSIM4_MOD_EGIDL: + value->rValue = model->BSIM4egidl; + return(OK); + case BSIM4_MOD_AIGC: + value->rValue = model->BSIM4aigc; + return(OK); + case BSIM4_MOD_BIGC: + value->rValue = model->BSIM4bigc; + return(OK); + case BSIM4_MOD_CIGC: + value->rValue = model->BSIM4cigc; + return(OK); + case BSIM4_MOD_AIGSD: + value->rValue = model->BSIM4aigsd; + return(OK); + case BSIM4_MOD_BIGSD: + value->rValue = model->BSIM4bigsd; + return(OK); + case BSIM4_MOD_CIGSD: + value->rValue = model->BSIM4cigsd; + return(OK); + case BSIM4_MOD_AIGBACC: + value->rValue = model->BSIM4aigbacc; + return(OK); + case BSIM4_MOD_BIGBACC: + value->rValue = model->BSIM4bigbacc; + return(OK); + case BSIM4_MOD_CIGBACC: + value->rValue = model->BSIM4cigbacc; + return(OK); + case BSIM4_MOD_AIGBINV: + value->rValue = model->BSIM4aigbinv; + return(OK); + case BSIM4_MOD_BIGBINV: + value->rValue = model->BSIM4bigbinv; + return(OK); + case BSIM4_MOD_CIGBINV: + value->rValue = model->BSIM4cigbinv; + return(OK); + case BSIM4_MOD_NIGC: + value->rValue = model->BSIM4nigc; + return(OK); + case BSIM4_MOD_NIGBACC: + value->rValue = model->BSIM4nigbacc; + return(OK); + case BSIM4_MOD_NIGBINV: + value->rValue = model->BSIM4nigbinv; + return(OK); + case BSIM4_MOD_NTOX: + value->rValue = model->BSIM4ntox; + return(OK); + case BSIM4_MOD_EIGBINV: + value->rValue = model->BSIM4eigbinv; + return(OK); + case BSIM4_MOD_PIGCD: + value->rValue = model->BSIM4pigcd; + return(OK); + case BSIM4_MOD_POXEDGE: + value->rValue = model->BSIM4poxedge; + return(OK); + case BSIM4_MOD_PHIN: + value->rValue = model->BSIM4phin; + return(OK); + case BSIM4_MOD_XRCRG1: + value->rValue = model->BSIM4xrcrg1; + return(OK); + case BSIM4_MOD_XRCRG2: + value->rValue = model->BSIM4xrcrg2; + return(OK); + case BSIM4_MOD_TNOIA: + value->rValue = model->BSIM4tnoia; + return(OK); + case BSIM4_MOD_TNOIB: + value->rValue = model->BSIM4tnoib; + return(OK); + case BSIM4_MOD_NTNOI: + value->rValue = model->BSIM4ntnoi; + return(OK); + case BSIM4_MOD_IJTHDFWD: + value->rValue = model->BSIM4ijthdfwd; + return(OK); + case BSIM4_MOD_IJTHSFWD: + value->rValue = model->BSIM4ijthsfwd; + return(OK); + case BSIM4_MOD_IJTHDREV: + value->rValue = model->BSIM4ijthdrev; + return(OK); + case BSIM4_MOD_IJTHSREV: + value->rValue = model->BSIM4ijthsrev; + return(OK); + case BSIM4_MOD_XJBVD: + value->rValue = model->BSIM4xjbvd; + return(OK); + case BSIM4_MOD_XJBVS: + value->rValue = model->BSIM4xjbvs; + return(OK); + case BSIM4_MOD_BVD: + value->rValue = model->BSIM4bvd; + return(OK); + case BSIM4_MOD_BVS: + value->rValue = model->BSIM4bvs; + return(OK); + case BSIM4_MOD_VFB: + value->rValue = model->BSIM4vfb; + return(OK); + + case BSIM4_MOD_GBMIN: + value->rValue = model->BSIM4gbmin; + return(OK); + case BSIM4_MOD_RBDB: + value->rValue = model->BSIM4rbdb; + return(OK); + case BSIM4_MOD_RBPB: + value->rValue = model->BSIM4rbpb; + return(OK); + case BSIM4_MOD_RBSB: + value->rValue = model->BSIM4rbsb; + return(OK); + case BSIM4_MOD_RBPS: + value->rValue = model->BSIM4rbps; + return(OK); + case BSIM4_MOD_RBPD: + value->rValue = model->BSIM4rbpd; + return(OK); + + case BSIM4_MOD_CGSL: + value->rValue = model->BSIM4cgsl; + return(OK); + case BSIM4_MOD_CGDL: + value->rValue = model->BSIM4cgdl; + return(OK); + case BSIM4_MOD_CKAPPAS: + value->rValue = model->BSIM4ckappas; + return(OK); + case BSIM4_MOD_CKAPPAD: + value->rValue = model->BSIM4ckappad; + return(OK); + case BSIM4_MOD_CF: + value->rValue = model->BSIM4cf; + return(OK); + case BSIM4_MOD_CLC: + value->rValue = model->BSIM4clc; + return(OK); + case BSIM4_MOD_CLE: + value->rValue = model->BSIM4cle; + return(OK); + case BSIM4_MOD_DWC: + value->rValue = model->BSIM4dwc; + return(OK); + case BSIM4_MOD_DLC: + value->rValue = model->BSIM4dlc; + return(OK); + case BSIM4_MOD_DLCIG: + value->rValue = model->BSIM4dlcig; + return(OK); + case BSIM4_MOD_DWJ: + value->rValue = model->BSIM4dwj; + return(OK); + case BSIM4_MOD_VFBCV: + value->rValue = model->BSIM4vfbcv; + return(OK); + case BSIM4_MOD_ACDE: + value->rValue = model->BSIM4acde; + return(OK); + case BSIM4_MOD_MOIN: + value->rValue = model->BSIM4moin; + return(OK); + case BSIM4_MOD_NOFF: + value->rValue = model->BSIM4noff; + return(OK); + case BSIM4_MOD_VOFFCV: + value->rValue = model->BSIM4voffcv; + return(OK); + case BSIM4_MOD_DMCG: + value->rValue = model->BSIM4dmcg; + return(OK); + case BSIM4_MOD_DMCI: + value->rValue = model->BSIM4dmci; + return(OK); + case BSIM4_MOD_DMDG: + value->rValue = model->BSIM4dmdg; + return(OK); + case BSIM4_MOD_DMCGT: + value->rValue = model->BSIM4dmcgt; + return(OK); + case BSIM4_MOD_XGW: + value->rValue = model->BSIM4xgw; + return(OK); + case BSIM4_MOD_XGL: + value->rValue = model->BSIM4xgl; + return(OK); + case BSIM4_MOD_RSHG: + value->rValue = model->BSIM4rshg; + return(OK); + case BSIM4_MOD_NGCON: + value->rValue = model->BSIM4ngcon; + return(OK); + case BSIM4_MOD_TCJ: + value->rValue = model->BSIM4tcj; + return(OK); + case BSIM4_MOD_TPB: + value->rValue = model->BSIM4tpb; + return(OK); + case BSIM4_MOD_TCJSW: + value->rValue = model->BSIM4tcjsw; + return(OK); + case BSIM4_MOD_TPBSW: + value->rValue = model->BSIM4tpbsw; + return(OK); + case BSIM4_MOD_TCJSWG: + value->rValue = model->BSIM4tcjswg; + return(OK); + case BSIM4_MOD_TPBSWG: + value->rValue = model->BSIM4tpbswg; + return(OK); + + /* Length dependence */ + case BSIM4_MOD_LCDSC : + value->rValue = model->BSIM4lcdsc; + return(OK); + case BSIM4_MOD_LCDSCB : + value->rValue = model->BSIM4lcdscb; + return(OK); + case BSIM4_MOD_LCDSCD : + value->rValue = model->BSIM4lcdscd; + return(OK); + case BSIM4_MOD_LCIT : + value->rValue = model->BSIM4lcit; + return(OK); + case BSIM4_MOD_LNFACTOR : + value->rValue = model->BSIM4lnfactor; + return(OK); + case BSIM4_MOD_LXJ: + value->rValue = model->BSIM4lxj; + return(OK); + case BSIM4_MOD_LVSAT: + value->rValue = model->BSIM4lvsat; + return(OK); + case BSIM4_MOD_LAT: + value->rValue = model->BSIM4lat; + return(OK); + case BSIM4_MOD_LA0: + value->rValue = model->BSIM4la0; + return(OK); + case BSIM4_MOD_LAGS: + value->rValue = model->BSIM4lags; + return(OK); + case BSIM4_MOD_LA1: + value->rValue = model->BSIM4la1; + return(OK); + case BSIM4_MOD_LA2: + value->rValue = model->BSIM4la2; + return(OK); + case BSIM4_MOD_LKETA: + value->rValue = model->BSIM4lketa; + return(OK); + case BSIM4_MOD_LNSUB: + value->rValue = model->BSIM4lnsub; + return(OK); + case BSIM4_MOD_LNDEP: + value->rValue = model->BSIM4lndep; + return(OK); + case BSIM4_MOD_LNSD: + value->rValue = model->BSIM4lnsd; + return(OK); + case BSIM4_MOD_LNGATE: + value->rValue = model->BSIM4lngate; + return(OK); + case BSIM4_MOD_LGAMMA1: + value->rValue = model->BSIM4lgamma1; + return(OK); + case BSIM4_MOD_LGAMMA2: + value->rValue = model->BSIM4lgamma2; + return(OK); + case BSIM4_MOD_LVBX: + value->rValue = model->BSIM4lvbx; + return(OK); + case BSIM4_MOD_LVBM: + value->rValue = model->BSIM4lvbm; + return(OK); + case BSIM4_MOD_LXT: + value->rValue = model->BSIM4lxt; + return(OK); + case BSIM4_MOD_LK1: + value->rValue = model->BSIM4lk1; + return(OK); + case BSIM4_MOD_LKT1: + value->rValue = model->BSIM4lkt1; + return(OK); + case BSIM4_MOD_LKT1L: + value->rValue = model->BSIM4lkt1l; + return(OK); + case BSIM4_MOD_LKT2 : + value->rValue = model->BSIM4lkt2; + return(OK); + case BSIM4_MOD_LK2 : + value->rValue = model->BSIM4lk2; + return(OK); + case BSIM4_MOD_LK3: + value->rValue = model->BSIM4lk3; + return(OK); + case BSIM4_MOD_LK3B: + value->rValue = model->BSIM4lk3b; + return(OK); + case BSIM4_MOD_LW0: + value->rValue = model->BSIM4lw0; + return(OK); + case BSIM4_MOD_LLPE0: + value->rValue = model->BSIM4llpe0; + return(OK); + case BSIM4_MOD_LLPEB: + value->rValue = model->BSIM4llpeb; + return(OK); + case BSIM4_MOD_LDVTP0: + value->rValue = model->BSIM4ldvtp0; + return(OK); + case BSIM4_MOD_LDVTP1: + value->rValue = model->BSIM4ldvtp1; + return(OK); + case BSIM4_MOD_LDVT0: + value->rValue = model->BSIM4ldvt0; + return(OK); + case BSIM4_MOD_LDVT1 : + value->rValue = model->BSIM4ldvt1; + return(OK); + case BSIM4_MOD_LDVT2 : + value->rValue = model->BSIM4ldvt2; + return(OK); + case BSIM4_MOD_LDVT0W : + value->rValue = model->BSIM4ldvt0w; + return(OK); + case BSIM4_MOD_LDVT1W : + value->rValue = model->BSIM4ldvt1w; + return(OK); + case BSIM4_MOD_LDVT2W : + value->rValue = model->BSIM4ldvt2w; + return(OK); + case BSIM4_MOD_LDROUT : + value->rValue = model->BSIM4ldrout; + return(OK); + case BSIM4_MOD_LDSUB : + value->rValue = model->BSIM4ldsub; + return(OK); + case BSIM4_MOD_LVTH0: + value->rValue = model->BSIM4lvth0; + return(OK); + case BSIM4_MOD_LUA: + value->rValue = model->BSIM4lua; + return(OK); + case BSIM4_MOD_LUA1: + value->rValue = model->BSIM4lua1; + return(OK); + case BSIM4_MOD_LUB: + value->rValue = model->BSIM4lub; + return(OK); + case BSIM4_MOD_LUB1: + value->rValue = model->BSIM4lub1; + return(OK); + case BSIM4_MOD_LUC: + value->rValue = model->BSIM4luc; + return(OK); + case BSIM4_MOD_LUC1: + value->rValue = model->BSIM4luc1; + return(OK); + case BSIM4_MOD_LU0: + value->rValue = model->BSIM4lu0; + return(OK); + case BSIM4_MOD_LUTE: + value->rValue = model->BSIM4lute; + return(OK); + case BSIM4_MOD_LVOFF: + value->rValue = model->BSIM4lvoff; + return(OK); + case BSIM4_MOD_LMINV: + value->rValue = model->BSIM4lminv; + return(OK); + case BSIM4_MOD_LFPROUT: + value->rValue = model->BSIM4lfprout; + return(OK); + case BSIM4_MOD_LPDITS: + value->rValue = model->BSIM4lpdits; + return(OK); + case BSIM4_MOD_LPDITSD: + value->rValue = model->BSIM4lpditsd; + return(OK); + case BSIM4_MOD_LDELTA: + value->rValue = model->BSIM4ldelta; + return(OK); + case BSIM4_MOD_LRDSW: + value->rValue = model->BSIM4lrdsw; + return(OK); + case BSIM4_MOD_LRDW: + value->rValue = model->BSIM4lrdw; + return(OK); + case BSIM4_MOD_LRSW: + value->rValue = model->BSIM4lrsw; + return(OK); + case BSIM4_MOD_LPRWB: + value->rValue = model->BSIM4lprwb; + return(OK); + case BSIM4_MOD_LPRWG: + value->rValue = model->BSIM4lprwg; + return(OK); + case BSIM4_MOD_LPRT: + value->rValue = model->BSIM4lprt; + return(OK); + case BSIM4_MOD_LETA0: + value->rValue = model->BSIM4leta0; + return(OK); + case BSIM4_MOD_LETAB: + value->rValue = model->BSIM4letab; + return(OK); + case BSIM4_MOD_LPCLM: + value->rValue = model->BSIM4lpclm; + return(OK); + case BSIM4_MOD_LPDIBL1: + value->rValue = model->BSIM4lpdibl1; + return(OK); + case BSIM4_MOD_LPDIBL2: + value->rValue = model->BSIM4lpdibl2; + return(OK); + case BSIM4_MOD_LPDIBLB: + value->rValue = model->BSIM4lpdiblb; + return(OK); + case BSIM4_MOD_LPSCBE1: + value->rValue = model->BSIM4lpscbe1; + return(OK); + case BSIM4_MOD_LPSCBE2: + value->rValue = model->BSIM4lpscbe2; + return(OK); + case BSIM4_MOD_LPVAG: + value->rValue = model->BSIM4lpvag; + return(OK); + case BSIM4_MOD_LWR: + value->rValue = model->BSIM4lwr; + return(OK); + case BSIM4_MOD_LDWG: + value->rValue = model->BSIM4ldwg; + return(OK); + case BSIM4_MOD_LDWB: + value->rValue = model->BSIM4ldwb; + return(OK); + case BSIM4_MOD_LB0: + value->rValue = model->BSIM4lb0; + return(OK); + case BSIM4_MOD_LB1: + value->rValue = model->BSIM4lb1; + return(OK); + case BSIM4_MOD_LALPHA0: + value->rValue = model->BSIM4lalpha0; + return(OK); + case BSIM4_MOD_LALPHA1: + value->rValue = model->BSIM4lalpha1; + return(OK); + case BSIM4_MOD_LBETA0: + value->rValue = model->BSIM4lbeta0; + return(OK); + case BSIM4_MOD_LAGIDL: + value->rValue = model->BSIM4lagidl; + return(OK); + case BSIM4_MOD_LBGIDL: + value->rValue = model->BSIM4lbgidl; + return(OK); + case BSIM4_MOD_LCGIDL: + value->rValue = model->BSIM4lcgidl; + return(OK); + case BSIM4_MOD_LEGIDL: + value->rValue = model->BSIM4legidl; + return(OK); + case BSIM4_MOD_LAIGC: + value->rValue = model->BSIM4laigc; + return(OK); + case BSIM4_MOD_LBIGC: + value->rValue = model->BSIM4lbigc; + return(OK); + case BSIM4_MOD_LCIGC: + value->rValue = model->BSIM4lcigc; + return(OK); + case BSIM4_MOD_LAIGSD: + value->rValue = model->BSIM4laigsd; + return(OK); + case BSIM4_MOD_LBIGSD: + value->rValue = model->BSIM4lbigsd; + return(OK); + case BSIM4_MOD_LCIGSD: + value->rValue = model->BSIM4lcigsd; + return(OK); + case BSIM4_MOD_LAIGBACC: + value->rValue = model->BSIM4laigbacc; + return(OK); + case BSIM4_MOD_LBIGBACC: + value->rValue = model->BSIM4lbigbacc; + return(OK); + case BSIM4_MOD_LCIGBACC: + value->rValue = model->BSIM4lcigbacc; + return(OK); + case BSIM4_MOD_LAIGBINV: + value->rValue = model->BSIM4laigbinv; + return(OK); + case BSIM4_MOD_LBIGBINV: + value->rValue = model->BSIM4lbigbinv; + return(OK); + case BSIM4_MOD_LCIGBINV: + value->rValue = model->BSIM4lcigbinv; + return(OK); + case BSIM4_MOD_LNIGC: + value->rValue = model->BSIM4lnigc; + return(OK); + case BSIM4_MOD_LNIGBACC: + value->rValue = model->BSIM4lnigbacc; + return(OK); + case BSIM4_MOD_LNIGBINV: + value->rValue = model->BSIM4lnigbinv; + return(OK); + case BSIM4_MOD_LNTOX: + value->rValue = model->BSIM4lntox; + return(OK); + case BSIM4_MOD_LEIGBINV: + value->rValue = model->BSIM4leigbinv; + return(OK); + case BSIM4_MOD_LPIGCD: + value->rValue = model->BSIM4lpigcd; + return(OK); + case BSIM4_MOD_LPOXEDGE: + value->rValue = model->BSIM4lpoxedge; + return(OK); + case BSIM4_MOD_LPHIN: + value->rValue = model->BSIM4lphin; + return(OK); + case BSIM4_MOD_LXRCRG1: + value->rValue = model->BSIM4lxrcrg1; + return(OK); + case BSIM4_MOD_LXRCRG2: + value->rValue = model->BSIM4lxrcrg2; + return(OK); + case BSIM4_MOD_LEU: + value->rValue = model->BSIM4leu; + return(OK); + case BSIM4_MOD_LVFB: + value->rValue = model->BSIM4lvfb; + return(OK); + + case BSIM4_MOD_LCGSL: + value->rValue = model->BSIM4lcgsl; + return(OK); + case BSIM4_MOD_LCGDL: + value->rValue = model->BSIM4lcgdl; + return(OK); + case BSIM4_MOD_LCKAPPAS: + value->rValue = model->BSIM4lckappas; + return(OK); + case BSIM4_MOD_LCKAPPAD: + value->rValue = model->BSIM4lckappad; + return(OK); + case BSIM4_MOD_LCF: + value->rValue = model->BSIM4lcf; + return(OK); + case BSIM4_MOD_LCLC: + value->rValue = model->BSIM4lclc; + return(OK); + case BSIM4_MOD_LCLE: + value->rValue = model->BSIM4lcle; + return(OK); + case BSIM4_MOD_LVFBCV: + value->rValue = model->BSIM4lvfbcv; + return(OK); + case BSIM4_MOD_LACDE: + value->rValue = model->BSIM4lacde; + return(OK); + case BSIM4_MOD_LMOIN: + value->rValue = model->BSIM4lmoin; + return(OK); + case BSIM4_MOD_LNOFF: + value->rValue = model->BSIM4lnoff; + return(OK); + case BSIM4_MOD_LVOFFCV: + value->rValue = model->BSIM4lvoffcv; + return(OK); + + /* Width dependence */ + case BSIM4_MOD_WCDSC : + value->rValue = model->BSIM4wcdsc; + return(OK); + case BSIM4_MOD_WCDSCB : + value->rValue = model->BSIM4wcdscb; + return(OK); + case BSIM4_MOD_WCDSCD : + value->rValue = model->BSIM4wcdscd; + return(OK); + case BSIM4_MOD_WCIT : + value->rValue = model->BSIM4wcit; + return(OK); + case BSIM4_MOD_WNFACTOR : + value->rValue = model->BSIM4wnfactor; + return(OK); + case BSIM4_MOD_WXJ: + value->rValue = model->BSIM4wxj; + return(OK); + case BSIM4_MOD_WVSAT: + value->rValue = model->BSIM4wvsat; + return(OK); + case BSIM4_MOD_WAT: + value->rValue = model->BSIM4wat; + return(OK); + case BSIM4_MOD_WA0: + value->rValue = model->BSIM4wa0; + return(OK); + case BSIM4_MOD_WAGS: + value->rValue = model->BSIM4wags; + return(OK); + case BSIM4_MOD_WA1: + value->rValue = model->BSIM4wa1; + return(OK); + case BSIM4_MOD_WA2: + value->rValue = model->BSIM4wa2; + return(OK); + case BSIM4_MOD_WKETA: + value->rValue = model->BSIM4wketa; + return(OK); + case BSIM4_MOD_WNSUB: + value->rValue = model->BSIM4wnsub; + return(OK); + case BSIM4_MOD_WNDEP: + value->rValue = model->BSIM4wndep; + return(OK); + case BSIM4_MOD_WNSD: + value->rValue = model->BSIM4wnsd; + return(OK); + case BSIM4_MOD_WNGATE: + value->rValue = model->BSIM4wngate; + return(OK); + case BSIM4_MOD_WGAMMA1: + value->rValue = model->BSIM4wgamma1; + return(OK); + case BSIM4_MOD_WGAMMA2: + value->rValue = model->BSIM4wgamma2; + return(OK); + case BSIM4_MOD_WVBX: + value->rValue = model->BSIM4wvbx; + return(OK); + case BSIM4_MOD_WVBM: + value->rValue = model->BSIM4wvbm; + return(OK); + case BSIM4_MOD_WXT: + value->rValue = model->BSIM4wxt; + return(OK); + case BSIM4_MOD_WK1: + value->rValue = model->BSIM4wk1; + return(OK); + case BSIM4_MOD_WKT1: + value->rValue = model->BSIM4wkt1; + return(OK); + case BSIM4_MOD_WKT1L: + value->rValue = model->BSIM4wkt1l; + return(OK); + case BSIM4_MOD_WKT2 : + value->rValue = model->BSIM4wkt2; + return(OK); + case BSIM4_MOD_WK2 : + value->rValue = model->BSIM4wk2; + return(OK); + case BSIM4_MOD_WK3: + value->rValue = model->BSIM4wk3; + return(OK); + case BSIM4_MOD_WK3B: + value->rValue = model->BSIM4wk3b; + return(OK); + case BSIM4_MOD_WW0: + value->rValue = model->BSIM4ww0; + return(OK); + case BSIM4_MOD_WLPE0: + value->rValue = model->BSIM4wlpe0; + return(OK); + case BSIM4_MOD_WDVTP0: + value->rValue = model->BSIM4wdvtp0; + return(OK); + case BSIM4_MOD_WDVTP1: + value->rValue = model->BSIM4wdvtp1; + return(OK); + case BSIM4_MOD_WLPEB: + value->rValue = model->BSIM4wlpeb; + return(OK); + case BSIM4_MOD_WDVT0: + value->rValue = model->BSIM4wdvt0; + return(OK); + case BSIM4_MOD_WDVT1 : + value->rValue = model->BSIM4wdvt1; + return(OK); + case BSIM4_MOD_WDVT2 : + value->rValue = model->BSIM4wdvt2; + return(OK); + case BSIM4_MOD_WDVT0W : + value->rValue = model->BSIM4wdvt0w; + return(OK); + case BSIM4_MOD_WDVT1W : + value->rValue = model->BSIM4wdvt1w; + return(OK); + case BSIM4_MOD_WDVT2W : + value->rValue = model->BSIM4wdvt2w; + return(OK); + case BSIM4_MOD_WDROUT : + value->rValue = model->BSIM4wdrout; + return(OK); + case BSIM4_MOD_WDSUB : + value->rValue = model->BSIM4wdsub; + return(OK); + case BSIM4_MOD_WVTH0: + value->rValue = model->BSIM4wvth0; + return(OK); + case BSIM4_MOD_WUA: + value->rValue = model->BSIM4wua; + return(OK); + case BSIM4_MOD_WUA1: + value->rValue = model->BSIM4wua1; + return(OK); + case BSIM4_MOD_WUB: + value->rValue = model->BSIM4wub; + return(OK); + case BSIM4_MOD_WUB1: + value->rValue = model->BSIM4wub1; + return(OK); + case BSIM4_MOD_WUC: + value->rValue = model->BSIM4wuc; + return(OK); + case BSIM4_MOD_WUC1: + value->rValue = model->BSIM4wuc1; + return(OK); + case BSIM4_MOD_WU0: + value->rValue = model->BSIM4wu0; + return(OK); + case BSIM4_MOD_WUTE: + value->rValue = model->BSIM4wute; + return(OK); + case BSIM4_MOD_WVOFF: + value->rValue = model->BSIM4wvoff; + return(OK); + case BSIM4_MOD_WMINV: + value->rValue = model->BSIM4wminv; + return(OK); + case BSIM4_MOD_WFPROUT: + value->rValue = model->BSIM4wfprout; + return(OK); + case BSIM4_MOD_WPDITS: + value->rValue = model->BSIM4wpdits; + return(OK); + case BSIM4_MOD_WPDITSD: + value->rValue = model->BSIM4wpditsd; + return(OK); + case BSIM4_MOD_WDELTA: + value->rValue = model->BSIM4wdelta; + return(OK); + case BSIM4_MOD_WRDSW: + value->rValue = model->BSIM4wrdsw; + return(OK); + case BSIM4_MOD_WRDW: + value->rValue = model->BSIM4wrdw; + return(OK); + case BSIM4_MOD_WRSW: + value->rValue = model->BSIM4wrsw; + return(OK); + case BSIM4_MOD_WPRWB: + value->rValue = model->BSIM4wprwb; + return(OK); + case BSIM4_MOD_WPRWG: + value->rValue = model->BSIM4wprwg; + return(OK); + case BSIM4_MOD_WPRT: + value->rValue = model->BSIM4wprt; + return(OK); + case BSIM4_MOD_WETA0: + value->rValue = model->BSIM4weta0; + return(OK); + case BSIM4_MOD_WETAB: + value->rValue = model->BSIM4wetab; + return(OK); + case BSIM4_MOD_WPCLM: + value->rValue = model->BSIM4wpclm; + return(OK); + case BSIM4_MOD_WPDIBL1: + value->rValue = model->BSIM4wpdibl1; + return(OK); + case BSIM4_MOD_WPDIBL2: + value->rValue = model->BSIM4wpdibl2; + return(OK); + case BSIM4_MOD_WPDIBLB: + value->rValue = model->BSIM4wpdiblb; + return(OK); + case BSIM4_MOD_WPSCBE1: + value->rValue = model->BSIM4wpscbe1; + return(OK); + case BSIM4_MOD_WPSCBE2: + value->rValue = model->BSIM4wpscbe2; + return(OK); + case BSIM4_MOD_WPVAG: + value->rValue = model->BSIM4wpvag; + return(OK); + case BSIM4_MOD_WWR: + value->rValue = model->BSIM4wwr; + return(OK); + case BSIM4_MOD_WDWG: + value->rValue = model->BSIM4wdwg; + return(OK); + case BSIM4_MOD_WDWB: + value->rValue = model->BSIM4wdwb; + return(OK); + case BSIM4_MOD_WB0: + value->rValue = model->BSIM4wb0; + return(OK); + case BSIM4_MOD_WB1: + value->rValue = model->BSIM4wb1; + return(OK); + case BSIM4_MOD_WALPHA0: + value->rValue = model->BSIM4walpha0; + return(OK); + case BSIM4_MOD_WALPHA1: + value->rValue = model->BSIM4walpha1; + return(OK); + case BSIM4_MOD_WBETA0: + value->rValue = model->BSIM4wbeta0; + return(OK); + case BSIM4_MOD_WAGIDL: + value->rValue = model->BSIM4wagidl; + return(OK); + case BSIM4_MOD_WBGIDL: + value->rValue = model->BSIM4wbgidl; + return(OK); + case BSIM4_MOD_WCGIDL: + value->rValue = model->BSIM4wcgidl; + return(OK); + case BSIM4_MOD_WEGIDL: + value->rValue = model->BSIM4wegidl; + return(OK); + case BSIM4_MOD_WAIGC: + value->rValue = model->BSIM4waigc; + return(OK); + case BSIM4_MOD_WBIGC: + value->rValue = model->BSIM4wbigc; + return(OK); + case BSIM4_MOD_WCIGC: + value->rValue = model->BSIM4wcigc; + return(OK); + case BSIM4_MOD_WAIGSD: + value->rValue = model->BSIM4waigsd; + return(OK); + case BSIM4_MOD_WBIGSD: + value->rValue = model->BSIM4wbigsd; + return(OK); + case BSIM4_MOD_WCIGSD: + value->rValue = model->BSIM4wcigsd; + return(OK); + case BSIM4_MOD_WAIGBACC: + value->rValue = model->BSIM4waigbacc; + return(OK); + case BSIM4_MOD_WBIGBACC: + value->rValue = model->BSIM4wbigbacc; + return(OK); + case BSIM4_MOD_WCIGBACC: + value->rValue = model->BSIM4wcigbacc; + return(OK); + case BSIM4_MOD_WAIGBINV: + value->rValue = model->BSIM4waigbinv; + return(OK); + case BSIM4_MOD_WBIGBINV: + value->rValue = model->BSIM4wbigbinv; + return(OK); + case BSIM4_MOD_WCIGBINV: + value->rValue = model->BSIM4wcigbinv; + return(OK); + case BSIM4_MOD_WNIGC: + value->rValue = model->BSIM4wnigc; + return(OK); + case BSIM4_MOD_WNIGBACC: + value->rValue = model->BSIM4wnigbacc; + return(OK); + case BSIM4_MOD_WNIGBINV: + value->rValue = model->BSIM4wnigbinv; + return(OK); + case BSIM4_MOD_WNTOX: + value->rValue = model->BSIM4wntox; + return(OK); + case BSIM4_MOD_WEIGBINV: + value->rValue = model->BSIM4weigbinv; + return(OK); + case BSIM4_MOD_WPIGCD: + value->rValue = model->BSIM4wpigcd; + return(OK); + case BSIM4_MOD_WPOXEDGE: + value->rValue = model->BSIM4wpoxedge; + return(OK); + case BSIM4_MOD_WPHIN: + value->rValue = model->BSIM4wphin; + return(OK); + case BSIM4_MOD_WXRCRG1: + value->rValue = model->BSIM4wxrcrg1; + return(OK); + case BSIM4_MOD_WXRCRG2: + value->rValue = model->BSIM4wxrcrg2; + return(OK); + case BSIM4_MOD_WEU: + value->rValue = model->BSIM4weu; + return(OK); + case BSIM4_MOD_WVFB: + value->rValue = model->BSIM4wvfb; + return(OK); + + case BSIM4_MOD_WCGSL: + value->rValue = model->BSIM4wcgsl; + return(OK); + case BSIM4_MOD_WCGDL: + value->rValue = model->BSIM4wcgdl; + return(OK); + case BSIM4_MOD_WCKAPPAS: + value->rValue = model->BSIM4wckappas; + return(OK); + case BSIM4_MOD_WCKAPPAD: + value->rValue = model->BSIM4wckappad; + return(OK); + case BSIM4_MOD_WCF: + value->rValue = model->BSIM4wcf; + return(OK); + case BSIM4_MOD_WCLC: + value->rValue = model->BSIM4wclc; + return(OK); + case BSIM4_MOD_WCLE: + value->rValue = model->BSIM4wcle; + return(OK); + case BSIM4_MOD_WVFBCV: + value->rValue = model->BSIM4wvfbcv; + return(OK); + case BSIM4_MOD_WACDE: + value->rValue = model->BSIM4wacde; + return(OK); + case BSIM4_MOD_WMOIN: + value->rValue = model->BSIM4wmoin; + return(OK); + case BSIM4_MOD_WNOFF: + value->rValue = model->BSIM4wnoff; + return(OK); + case BSIM4_MOD_WVOFFCV: + value->rValue = model->BSIM4wvoffcv; + return(OK); + + /* Cross-term dependence */ + case BSIM4_MOD_PCDSC : + value->rValue = model->BSIM4pcdsc; + return(OK); + case BSIM4_MOD_PCDSCB : + value->rValue = model->BSIM4pcdscb; + return(OK); + case BSIM4_MOD_PCDSCD : + value->rValue = model->BSIM4pcdscd; + return(OK); + case BSIM4_MOD_PCIT : + value->rValue = model->BSIM4pcit; + return(OK); + case BSIM4_MOD_PNFACTOR : + value->rValue = model->BSIM4pnfactor; + return(OK); + case BSIM4_MOD_PXJ: + value->rValue = model->BSIM4pxj; + return(OK); + case BSIM4_MOD_PVSAT: + value->rValue = model->BSIM4pvsat; + return(OK); + case BSIM4_MOD_PAT: + value->rValue = model->BSIM4pat; + return(OK); + case BSIM4_MOD_PA0: + value->rValue = model->BSIM4pa0; + return(OK); + case BSIM4_MOD_PAGS: + value->rValue = model->BSIM4pags; + return(OK); + case BSIM4_MOD_PA1: + value->rValue = model->BSIM4pa1; + return(OK); + case BSIM4_MOD_PA2: + value->rValue = model->BSIM4pa2; + return(OK); + case BSIM4_MOD_PKETA: + value->rValue = model->BSIM4pketa; + return(OK); + case BSIM4_MOD_PNSUB: + value->rValue = model->BSIM4pnsub; + return(OK); + case BSIM4_MOD_PNDEP: + value->rValue = model->BSIM4pndep; + return(OK); + case BSIM4_MOD_PNSD: + value->rValue = model->BSIM4pnsd; + return(OK); + case BSIM4_MOD_PNGATE: + value->rValue = model->BSIM4pngate; + return(OK); + case BSIM4_MOD_PGAMMA1: + value->rValue = model->BSIM4pgamma1; + return(OK); + case BSIM4_MOD_PGAMMA2: + value->rValue = model->BSIM4pgamma2; + return(OK); + case BSIM4_MOD_PVBX: + value->rValue = model->BSIM4pvbx; + return(OK); + case BSIM4_MOD_PVBM: + value->rValue = model->BSIM4pvbm; + return(OK); + case BSIM4_MOD_PXT: + value->rValue = model->BSIM4pxt; + return(OK); + case BSIM4_MOD_PK1: + value->rValue = model->BSIM4pk1; + return(OK); + case BSIM4_MOD_PKT1: + value->rValue = model->BSIM4pkt1; + return(OK); + case BSIM4_MOD_PKT1L: + value->rValue = model->BSIM4pkt1l; + return(OK); + case BSIM4_MOD_PKT2 : + value->rValue = model->BSIM4pkt2; + return(OK); + case BSIM4_MOD_PK2 : + value->rValue = model->BSIM4pk2; + return(OK); + case BSIM4_MOD_PK3: + value->rValue = model->BSIM4pk3; + return(OK); + case BSIM4_MOD_PK3B: + value->rValue = model->BSIM4pk3b; + return(OK); + case BSIM4_MOD_PW0: + value->rValue = model->BSIM4pw0; + return(OK); + case BSIM4_MOD_PLPE0: + value->rValue = model->BSIM4plpe0; + return(OK); + case BSIM4_MOD_PLPEB: + value->rValue = model->BSIM4plpeb; + return(OK); + case BSIM4_MOD_PDVTP0: + value->rValue = model->BSIM4pdvtp0; + return(OK); + case BSIM4_MOD_PDVTP1: + value->rValue = model->BSIM4pdvtp1; + return(OK); + case BSIM4_MOD_PDVT0 : + value->rValue = model->BSIM4pdvt0; + return(OK); + case BSIM4_MOD_PDVT1 : + value->rValue = model->BSIM4pdvt1; + return(OK); + case BSIM4_MOD_PDVT2 : + value->rValue = model->BSIM4pdvt2; + return(OK); + case BSIM4_MOD_PDVT0W : + value->rValue = model->BSIM4pdvt0w; + return(OK); + case BSIM4_MOD_PDVT1W : + value->rValue = model->BSIM4pdvt1w; + return(OK); + case BSIM4_MOD_PDVT2W : + value->rValue = model->BSIM4pdvt2w; + return(OK); + case BSIM4_MOD_PDROUT : + value->rValue = model->BSIM4pdrout; + return(OK); + case BSIM4_MOD_PDSUB : + value->rValue = model->BSIM4pdsub; + return(OK); + case BSIM4_MOD_PVTH0: + value->rValue = model->BSIM4pvth0; + return(OK); + case BSIM4_MOD_PUA: + value->rValue = model->BSIM4pua; + return(OK); + case BSIM4_MOD_PUA1: + value->rValue = model->BSIM4pua1; + return(OK); + case BSIM4_MOD_PUB: + value->rValue = model->BSIM4pub; + return(OK); + case BSIM4_MOD_PUB1: + value->rValue = model->BSIM4pub1; + return(OK); + case BSIM4_MOD_PUC: + value->rValue = model->BSIM4puc; + return(OK); + case BSIM4_MOD_PUC1: + value->rValue = model->BSIM4puc1; + return(OK); + case BSIM4_MOD_PU0: + value->rValue = model->BSIM4pu0; + return(OK); + case BSIM4_MOD_PUTE: + value->rValue = model->BSIM4pute; + return(OK); + case BSIM4_MOD_PVOFF: + value->rValue = model->BSIM4pvoff; + return(OK); + case BSIM4_MOD_PMINV: + value->rValue = model->BSIM4pminv; + return(OK); + case BSIM4_MOD_PFPROUT: + value->rValue = model->BSIM4pfprout; + return(OK); + case BSIM4_MOD_PPDITS: + value->rValue = model->BSIM4ppdits; + return(OK); + case BSIM4_MOD_PPDITSD: + value->rValue = model->BSIM4ppditsd; + return(OK); + case BSIM4_MOD_PDELTA: + value->rValue = model->BSIM4pdelta; + return(OK); + case BSIM4_MOD_PRDSW: + value->rValue = model->BSIM4prdsw; + return(OK); + case BSIM4_MOD_PRDW: + value->rValue = model->BSIM4prdw; + return(OK); + case BSIM4_MOD_PRSW: + value->rValue = model->BSIM4prsw; + return(OK); + case BSIM4_MOD_PPRWB: + value->rValue = model->BSIM4pprwb; + return(OK); + case BSIM4_MOD_PPRWG: + value->rValue = model->BSIM4pprwg; + return(OK); + case BSIM4_MOD_PPRT: + value->rValue = model->BSIM4pprt; + return(OK); + case BSIM4_MOD_PETA0: + value->rValue = model->BSIM4peta0; + return(OK); + case BSIM4_MOD_PETAB: + value->rValue = model->BSIM4petab; + return(OK); + case BSIM4_MOD_PPCLM: + value->rValue = model->BSIM4ppclm; + return(OK); + case BSIM4_MOD_PPDIBL1: + value->rValue = model->BSIM4ppdibl1; + return(OK); + case BSIM4_MOD_PPDIBL2: + value->rValue = model->BSIM4ppdibl2; + return(OK); + case BSIM4_MOD_PPDIBLB: + value->rValue = model->BSIM4ppdiblb; + return(OK); + case BSIM4_MOD_PPSCBE1: + value->rValue = model->BSIM4ppscbe1; + return(OK); + case BSIM4_MOD_PPSCBE2: + value->rValue = model->BSIM4ppscbe2; + return(OK); + case BSIM4_MOD_PPVAG: + value->rValue = model->BSIM4ppvag; + return(OK); + case BSIM4_MOD_PWR: + value->rValue = model->BSIM4pwr; + return(OK); + case BSIM4_MOD_PDWG: + value->rValue = model->BSIM4pdwg; + return(OK); + case BSIM4_MOD_PDWB: + value->rValue = model->BSIM4pdwb; + return(OK); + case BSIM4_MOD_PB0: + value->rValue = model->BSIM4pb0; + return(OK); + case BSIM4_MOD_PB1: + value->rValue = model->BSIM4pb1; + return(OK); + case BSIM4_MOD_PALPHA0: + value->rValue = model->BSIM4palpha0; + return(OK); + case BSIM4_MOD_PALPHA1: + value->rValue = model->BSIM4palpha1; + return(OK); + case BSIM4_MOD_PBETA0: + value->rValue = model->BSIM4pbeta0; + return(OK); + case BSIM4_MOD_PAGIDL: + value->rValue = model->BSIM4pagidl; + return(OK); + case BSIM4_MOD_PBGIDL: + value->rValue = model->BSIM4pbgidl; + return(OK); + case BSIM4_MOD_PCGIDL: + value->rValue = model->BSIM4pcgidl; + return(OK); + case BSIM4_MOD_PEGIDL: + value->rValue = model->BSIM4pegidl; + return(OK); + case BSIM4_MOD_PAIGC: + value->rValue = model->BSIM4paigc; + return(OK); + case BSIM4_MOD_PBIGC: + value->rValue = model->BSIM4pbigc; + return(OK); + case BSIM4_MOD_PCIGC: + value->rValue = model->BSIM4pcigc; + return(OK); + case BSIM4_MOD_PAIGSD: + value->rValue = model->BSIM4paigsd; + return(OK); + case BSIM4_MOD_PBIGSD: + value->rValue = model->BSIM4pbigsd; + return(OK); + case BSIM4_MOD_PCIGSD: + value->rValue = model->BSIM4pcigsd; + return(OK); + case BSIM4_MOD_PAIGBACC: + value->rValue = model->BSIM4paigbacc; + return(OK); + case BSIM4_MOD_PBIGBACC: + value->rValue = model->BSIM4pbigbacc; + return(OK); + case BSIM4_MOD_PCIGBACC: + value->rValue = model->BSIM4pcigbacc; + return(OK); + case BSIM4_MOD_PAIGBINV: + value->rValue = model->BSIM4paigbinv; + return(OK); + case BSIM4_MOD_PBIGBINV: + value->rValue = model->BSIM4pbigbinv; + return(OK); + case BSIM4_MOD_PCIGBINV: + value->rValue = model->BSIM4pcigbinv; + return(OK); + case BSIM4_MOD_PNIGC: + value->rValue = model->BSIM4pnigc; + return(OK); + case BSIM4_MOD_PNIGBACC: + value->rValue = model->BSIM4pnigbacc; + return(OK); + case BSIM4_MOD_PNIGBINV: + value->rValue = model->BSIM4pnigbinv; + return(OK); + case BSIM4_MOD_PNTOX: + value->rValue = model->BSIM4pntox; + return(OK); + case BSIM4_MOD_PEIGBINV: + value->rValue = model->BSIM4peigbinv; + return(OK); + case BSIM4_MOD_PPIGCD: + value->rValue = model->BSIM4ppigcd; + return(OK); + case BSIM4_MOD_PPOXEDGE: + value->rValue = model->BSIM4ppoxedge; + return(OK); + case BSIM4_MOD_PPHIN: + value->rValue = model->BSIM4pphin; + return(OK); + case BSIM4_MOD_PXRCRG1: + value->rValue = model->BSIM4pxrcrg1; + return(OK); + case BSIM4_MOD_PXRCRG2: + value->rValue = model->BSIM4pxrcrg2; + return(OK); + case BSIM4_MOD_PEU: + value->rValue = model->BSIM4peu; + return(OK); + case BSIM4_MOD_PVFB: + value->rValue = model->BSIM4pvfb; + return(OK); + + case BSIM4_MOD_PCGSL: + value->rValue = model->BSIM4pcgsl; + return(OK); + case BSIM4_MOD_PCGDL: + value->rValue = model->BSIM4pcgdl; + return(OK); + case BSIM4_MOD_PCKAPPAS: + value->rValue = model->BSIM4pckappas; + return(OK); + case BSIM4_MOD_PCKAPPAD: + value->rValue = model->BSIM4pckappad; + return(OK); + case BSIM4_MOD_PCF: + value->rValue = model->BSIM4pcf; + return(OK); + case BSIM4_MOD_PCLC: + value->rValue = model->BSIM4pclc; + return(OK); + case BSIM4_MOD_PCLE: + value->rValue = model->BSIM4pcle; + return(OK); + case BSIM4_MOD_PVFBCV: + value->rValue = model->BSIM4pvfbcv; + return(OK); + case BSIM4_MOD_PACDE: + value->rValue = model->BSIM4pacde; + return(OK); + case BSIM4_MOD_PMOIN: + value->rValue = model->BSIM4pmoin; + return(OK); + case BSIM4_MOD_PNOFF: + value->rValue = model->BSIM4pnoff; + return(OK); + case BSIM4_MOD_PVOFFCV: + value->rValue = model->BSIM4pvoffcv; + return(OK); + + case BSIM4_MOD_TNOM : + value->rValue = model->BSIM4tnom; + return(OK); + case BSIM4_MOD_CGSO: + value->rValue = model->BSIM4cgso; + return(OK); + case BSIM4_MOD_CGDO: + value->rValue = model->BSIM4cgdo; + return(OK); + case BSIM4_MOD_CGBO: + value->rValue = model->BSIM4cgbo; + return(OK); + case BSIM4_MOD_XPART: + value->rValue = model->BSIM4xpart; + return(OK); + case BSIM4_MOD_RSH: + value->rValue = model->BSIM4sheetResistance; + return(OK); + case BSIM4_MOD_JSS: + value->rValue = model->BSIM4SjctSatCurDensity; + return(OK); + case BSIM4_MOD_JSWS: + value->rValue = model->BSIM4SjctSidewallSatCurDensity; + return(OK); + case BSIM4_MOD_JSWGS: + value->rValue = model->BSIM4SjctGateSidewallSatCurDensity; + return(OK); + case BSIM4_MOD_PBS: + value->rValue = model->BSIM4SbulkJctPotential; + return(OK); + case BSIM4_MOD_MJS: + value->rValue = model->BSIM4SbulkJctBotGradingCoeff; + return(OK); + case BSIM4_MOD_PBSWS: + value->rValue = model->BSIM4SsidewallJctPotential; + return(OK); + case BSIM4_MOD_MJSWS: + value->rValue = model->BSIM4SbulkJctSideGradingCoeff; + return(OK); + case BSIM4_MOD_CJS: + value->rValue = model->BSIM4SunitAreaJctCap; + return(OK); + case BSIM4_MOD_CJSWS: + value->rValue = model->BSIM4SunitLengthSidewallJctCap; + return(OK); + case BSIM4_MOD_PBSWGS: + value->rValue = model->BSIM4SGatesidewallJctPotential; + return(OK); + case BSIM4_MOD_MJSWGS: + value->rValue = model->BSIM4SbulkJctGateSideGradingCoeff; + return(OK); + case BSIM4_MOD_CJSWGS: + value->rValue = model->BSIM4SunitLengthGateSidewallJctCap; + return(OK); + case BSIM4_MOD_NJS: + value->rValue = model->BSIM4SjctEmissionCoeff; + return(OK); + case BSIM4_MOD_XTIS: + value->rValue = model->BSIM4SjctTempExponent; + return(OK); + case BSIM4_MOD_JSD: + value->rValue = model->BSIM4DjctSatCurDensity; + return(OK); + case BSIM4_MOD_JSWD: + value->rValue = model->BSIM4DjctSidewallSatCurDensity; + return(OK); + case BSIM4_MOD_JSWGD: + value->rValue = model->BSIM4DjctGateSidewallSatCurDensity; + return(OK); + case BSIM4_MOD_PBD: + value->rValue = model->BSIM4DbulkJctPotential; + return(OK); + case BSIM4_MOD_MJD: + value->rValue = model->BSIM4DbulkJctBotGradingCoeff; + return(OK); + case BSIM4_MOD_PBSWD: + value->rValue = model->BSIM4DsidewallJctPotential; + return(OK); + case BSIM4_MOD_MJSWD: + value->rValue = model->BSIM4DbulkJctSideGradingCoeff; + return(OK); + case BSIM4_MOD_CJD: + value->rValue = model->BSIM4DunitAreaJctCap; + return(OK); + case BSIM4_MOD_CJSWD: + value->rValue = model->BSIM4DunitLengthSidewallJctCap; + return(OK); + case BSIM4_MOD_PBSWGD: + value->rValue = model->BSIM4DGatesidewallJctPotential; + return(OK); + case BSIM4_MOD_MJSWGD: + value->rValue = model->BSIM4DbulkJctGateSideGradingCoeff; + return(OK); + case BSIM4_MOD_CJSWGD: + value->rValue = model->BSIM4DunitLengthGateSidewallJctCap; + return(OK); + case BSIM4_MOD_NJD: + value->rValue = model->BSIM4DjctEmissionCoeff; + return(OK); + case BSIM4_MOD_XTID: + value->rValue = model->BSIM4DjctTempExponent; + return(OK); + case BSIM4_MOD_LINT: + value->rValue = model->BSIM4Lint; + return(OK); + case BSIM4_MOD_LL: + value->rValue = model->BSIM4Ll; + return(OK); + case BSIM4_MOD_LLC: + value->rValue = model->BSIM4Llc; + return(OK); + case BSIM4_MOD_LLN: + value->rValue = model->BSIM4Lln; + return(OK); + case BSIM4_MOD_LW: + value->rValue = model->BSIM4Lw; + return(OK); + case BSIM4_MOD_LWC: + value->rValue = model->BSIM4Lwc; + return(OK); + case BSIM4_MOD_LWN: + value->rValue = model->BSIM4Lwn; + return(OK); + case BSIM4_MOD_LWL: + value->rValue = model->BSIM4Lwl; + return(OK); + case BSIM4_MOD_LWLC: + value->rValue = model->BSIM4Lwlc; + return(OK); + case BSIM4_MOD_LMIN: + value->rValue = model->BSIM4Lmin; + return(OK); + case BSIM4_MOD_LMAX: + value->rValue = model->BSIM4Lmax; + return(OK); + case BSIM4_MOD_WINT: + value->rValue = model->BSIM4Wint; + return(OK); + case BSIM4_MOD_WL: + value->rValue = model->BSIM4Wl; + return(OK); + case BSIM4_MOD_WLC: + value->rValue = model->BSIM4Wlc; + return(OK); + case BSIM4_MOD_WLN: + value->rValue = model->BSIM4Wln; + return(OK); + case BSIM4_MOD_WW: + value->rValue = model->BSIM4Ww; + return(OK); + case BSIM4_MOD_WWC: + value->rValue = model->BSIM4Wwc; + return(OK); + case BSIM4_MOD_WWN: + value->rValue = model->BSIM4Wwn; + return(OK); + case BSIM4_MOD_WWL: + value->rValue = model->BSIM4Wwl; + return(OK); + case BSIM4_MOD_WWLC: + value->rValue = model->BSIM4Wwlc; + return(OK); + case BSIM4_MOD_WMIN: + value->rValue = model->BSIM4Wmin; + return(OK); + case BSIM4_MOD_WMAX: + value->rValue = model->BSIM4Wmax; + return(OK); + case BSIM4_MOD_NOIA: + value->rValue = model->BSIM4oxideTrapDensityA; + return(OK); + case BSIM4_MOD_NOIB: + value->rValue = model->BSIM4oxideTrapDensityB; + return(OK); + case BSIM4_MOD_NOIC: + value->rValue = model->BSIM4oxideTrapDensityC; + return(OK); + case BSIM4_MOD_EM: + value->rValue = model->BSIM4em; + return(OK); + case BSIM4_MOD_EF: + value->rValue = model->BSIM4ef; + return(OK); + case BSIM4_MOD_AF: + value->rValue = model->BSIM4af; + return(OK); + case BSIM4_MOD_KF: + value->rValue = model->BSIM4kf; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + + + diff --git a/src/spicelib/devices/bsim4/b4mdel.c b/src/spicelib/devices/bsim4/b4mdel.c new file mode 100644 index 000000000..cf1b072d9 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4mdel.c @@ -0,0 +1,45 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4mdel.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "bsim4def.h" +#include "sperror.h" + +int +BSIM4mDelete(inModel,modname,kill) +GENmodel **inModel; +IFuid modname; +GENmodel *kill; +{ +BSIM4model **model = (BSIM4model**)inModel; +BSIM4model *modfast = (BSIM4model*)kill; +BSIM4instance *here; +BSIM4instance *prev = NULL; +BSIM4model **oldmod; + + oldmod = model; + for (; *model ; model = &((*model)->BSIM4nextModel)) + { if ((*model)->BSIM4modName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->BSIM4nextModel; /* cut deleted device out of list */ + for (here = (*model)->BSIM4instances; here; here = here->BSIM4nextInstance) + { if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4mpar.c b/src/spicelib/devices/bsim4/b4mpar.c new file mode 100644 index 000000000..f75555628 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4mpar.c @@ -0,0 +1,2521 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4mpar.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "bsim4def.h" +#include "ifsim.h" +#include "sperror.h" +#include "const.h" + +int +BSIM4mParam(param,value,inMod) +int param; +IFvalue *value; +GENmodel *inMod; +{ + BSIM4model *mod = (BSIM4model*)inMod; + switch(param) + { case BSIM4_MOD_MOBMOD : + mod->BSIM4mobMod = value->iValue; + mod->BSIM4mobModGiven = TRUE; + break; + case BSIM4_MOD_BINUNIT : + mod->BSIM4binUnit = value->iValue; + mod->BSIM4binUnitGiven = TRUE; + break; + case BSIM4_MOD_PARAMCHK : + mod->BSIM4paramChk = value->iValue; + mod->BSIM4paramChkGiven = TRUE; + break; + case BSIM4_MOD_CAPMOD : + mod->BSIM4capMod = value->iValue; + mod->BSIM4capModGiven = TRUE; + break; + case BSIM4_MOD_DIOMOD : + mod->BSIM4dioMod = value->iValue; + mod->BSIM4dioModGiven = TRUE; + break; + case BSIM4_MOD_RDSMOD : + mod->BSIM4rdsMod = value->iValue; + mod->BSIM4rdsModGiven = TRUE; + break; + case BSIM4_MOD_TRNQSMOD : + mod->BSIM4trnqsMod = value->iValue; + mod->BSIM4trnqsModGiven = TRUE; + break; + case BSIM4_MOD_ACNQSMOD : + mod->BSIM4acnqsMod = value->iValue; + mod->BSIM4acnqsModGiven = TRUE; + break; + case BSIM4_MOD_RBODYMOD : + mod->BSIM4rbodyMod = value->iValue; + mod->BSIM4rbodyModGiven = TRUE; + break; + case BSIM4_MOD_RGATEMOD : + mod->BSIM4rgateMod = value->iValue; + mod->BSIM4rgateModGiven = TRUE; + break; + case BSIM4_MOD_PERMOD : + mod->BSIM4perMod = value->iValue; + mod->BSIM4perModGiven = TRUE; + break; + case BSIM4_MOD_GEOMOD : + mod->BSIM4geoMod = value->iValue; + mod->BSIM4geoModGiven = TRUE; + break; + case BSIM4_MOD_FNOIMOD : + mod->BSIM4fnoiMod = value->iValue; + mod->BSIM4fnoiModGiven = TRUE; + break; + case BSIM4_MOD_TNOIMOD : + mod->BSIM4tnoiMod = value->iValue; + mod->BSIM4tnoiModGiven = TRUE; + break; + case BSIM4_MOD_IGCMOD : + mod->BSIM4igcMod = value->iValue; + mod->BSIM4igcModGiven = TRUE; + break; + case BSIM4_MOD_IGBMOD : + mod->BSIM4igbMod = value->iValue; + mod->BSIM4igbModGiven = TRUE; + break; + case BSIM4_MOD_VERSION : + mod->BSIM4version = value->sValue; + mod->BSIM4versionGiven = TRUE; + break; + case BSIM4_MOD_TOXREF : + mod->BSIM4toxref = value->rValue; + mod->BSIM4toxrefGiven = TRUE; + break; + case BSIM4_MOD_TOXE : + mod->BSIM4toxe = value->rValue; + mod->BSIM4toxeGiven = TRUE; + break; + case BSIM4_MOD_TOXP : + mod->BSIM4toxp = value->rValue; + mod->BSIM4toxpGiven = TRUE; + break; + case BSIM4_MOD_TOXM : + mod->BSIM4toxm = value->rValue; + mod->BSIM4toxmGiven = TRUE; + break; + case BSIM4_MOD_DTOX : + mod->BSIM4dtox = value->rValue; + mod->BSIM4dtoxGiven = TRUE; + break; + case BSIM4_MOD_EPSROX : + mod->BSIM4epsrox = value->rValue; + mod->BSIM4epsroxGiven = TRUE; + break; + + case BSIM4_MOD_CDSC : + mod->BSIM4cdsc = value->rValue; + mod->BSIM4cdscGiven = TRUE; + break; + case BSIM4_MOD_CDSCB : + mod->BSIM4cdscb = value->rValue; + mod->BSIM4cdscbGiven = TRUE; + break; + + case BSIM4_MOD_CDSCD : + mod->BSIM4cdscd = value->rValue; + mod->BSIM4cdscdGiven = TRUE; + break; + + case BSIM4_MOD_CIT : + mod->BSIM4cit = value->rValue; + mod->BSIM4citGiven = TRUE; + break; + case BSIM4_MOD_NFACTOR : + mod->BSIM4nfactor = value->rValue; + mod->BSIM4nfactorGiven = TRUE; + break; + case BSIM4_MOD_XJ: + mod->BSIM4xj = value->rValue; + mod->BSIM4xjGiven = TRUE; + break; + case BSIM4_MOD_VSAT: + mod->BSIM4vsat = value->rValue; + mod->BSIM4vsatGiven = TRUE; + break; + case BSIM4_MOD_A0: + mod->BSIM4a0 = value->rValue; + mod->BSIM4a0Given = TRUE; + break; + + case BSIM4_MOD_AGS: + mod->BSIM4ags= value->rValue; + mod->BSIM4agsGiven = TRUE; + break; + + case BSIM4_MOD_A1: + mod->BSIM4a1 = value->rValue; + mod->BSIM4a1Given = TRUE; + break; + case BSIM4_MOD_A2: + mod->BSIM4a2 = value->rValue; + mod->BSIM4a2Given = TRUE; + break; + case BSIM4_MOD_AT: + mod->BSIM4at = value->rValue; + mod->BSIM4atGiven = TRUE; + break; + case BSIM4_MOD_KETA: + mod->BSIM4keta = value->rValue; + mod->BSIM4ketaGiven = TRUE; + break; + case BSIM4_MOD_NSUB: + mod->BSIM4nsub = value->rValue; + mod->BSIM4nsubGiven = TRUE; + break; + case BSIM4_MOD_NDEP: + mod->BSIM4ndep = value->rValue; + mod->BSIM4ndepGiven = TRUE; + if (mod->BSIM4ndep > 1.0e20) + mod->BSIM4ndep *= 1.0e-6; + break; + case BSIM4_MOD_NSD: + mod->BSIM4nsd = value->rValue; + mod->BSIM4nsdGiven = TRUE; + if (mod->BSIM4nsd > 1.0e23) + mod->BSIM4nsd *= 1.0e-6; + break; + case BSIM4_MOD_NGATE: + mod->BSIM4ngate = value->rValue; + mod->BSIM4ngateGiven = TRUE; + if (mod->BSIM4ngate > 1.0e23) + mod->BSIM4ngate *= 1.0e-6; + break; + case BSIM4_MOD_GAMMA1: + mod->BSIM4gamma1 = value->rValue; + mod->BSIM4gamma1Given = TRUE; + break; + case BSIM4_MOD_GAMMA2: + mod->BSIM4gamma2 = value->rValue; + mod->BSIM4gamma2Given = TRUE; + break; + case BSIM4_MOD_VBX: + mod->BSIM4vbx = value->rValue; + mod->BSIM4vbxGiven = TRUE; + break; + case BSIM4_MOD_VBM: + mod->BSIM4vbm = value->rValue; + mod->BSIM4vbmGiven = TRUE; + break; + case BSIM4_MOD_XT: + mod->BSIM4xt = value->rValue; + mod->BSIM4xtGiven = TRUE; + break; + case BSIM4_MOD_K1: + mod->BSIM4k1 = value->rValue; + mod->BSIM4k1Given = TRUE; + break; + case BSIM4_MOD_KT1: + mod->BSIM4kt1 = value->rValue; + mod->BSIM4kt1Given = TRUE; + break; + case BSIM4_MOD_KT1L: + mod->BSIM4kt1l = value->rValue; + mod->BSIM4kt1lGiven = TRUE; + break; + case BSIM4_MOD_KT2: + mod->BSIM4kt2 = value->rValue; + mod->BSIM4kt2Given = TRUE; + break; + case BSIM4_MOD_K2: + mod->BSIM4k2 = value->rValue; + mod->BSIM4k2Given = TRUE; + break; + case BSIM4_MOD_K3: + mod->BSIM4k3 = value->rValue; + mod->BSIM4k3Given = TRUE; + break; + case BSIM4_MOD_K3B: + mod->BSIM4k3b = value->rValue; + mod->BSIM4k3bGiven = TRUE; + break; + case BSIM4_MOD_LPE0: + mod->BSIM4lpe0 = value->rValue; + mod->BSIM4lpe0Given = TRUE; + break; + case BSIM4_MOD_LPEB: + mod->BSIM4lpeb = value->rValue; + mod->BSIM4lpebGiven = TRUE; + break; + case BSIM4_MOD_DVTP0: + mod->BSIM4dvtp0 = value->rValue; + mod->BSIM4dvtp0Given = TRUE; + break; + case BSIM4_MOD_DVTP1: + mod->BSIM4dvtp1 = value->rValue; + mod->BSIM4dvtp1Given = TRUE; + break; + case BSIM4_MOD_W0: + mod->BSIM4w0 = value->rValue; + mod->BSIM4w0Given = TRUE; + break; + case BSIM4_MOD_DVT0: + mod->BSIM4dvt0 = value->rValue; + mod->BSIM4dvt0Given = TRUE; + break; + case BSIM4_MOD_DVT1: + mod->BSIM4dvt1 = value->rValue; + mod->BSIM4dvt1Given = TRUE; + break; + case BSIM4_MOD_DVT2: + mod->BSIM4dvt2 = value->rValue; + mod->BSIM4dvt2Given = TRUE; + break; + case BSIM4_MOD_DVT0W: + mod->BSIM4dvt0w = value->rValue; + mod->BSIM4dvt0wGiven = TRUE; + break; + case BSIM4_MOD_DVT1W: + mod->BSIM4dvt1w = value->rValue; + mod->BSIM4dvt1wGiven = TRUE; + break; + case BSIM4_MOD_DVT2W: + mod->BSIM4dvt2w = value->rValue; + mod->BSIM4dvt2wGiven = TRUE; + break; + case BSIM4_MOD_DROUT: + mod->BSIM4drout = value->rValue; + mod->BSIM4droutGiven = TRUE; + break; + case BSIM4_MOD_DSUB: + mod->BSIM4dsub = value->rValue; + mod->BSIM4dsubGiven = TRUE; + break; + case BSIM4_MOD_VTH0: + mod->BSIM4vth0 = value->rValue; + mod->BSIM4vth0Given = TRUE; + break; + case BSIM4_MOD_EU: + mod->BSIM4eu = value->rValue; + mod->BSIM4euGiven = TRUE; + break; + case BSIM4_MOD_UA: + mod->BSIM4ua = value->rValue; + mod->BSIM4uaGiven = TRUE; + break; + case BSIM4_MOD_UA1: + mod->BSIM4ua1 = value->rValue; + mod->BSIM4ua1Given = TRUE; + break; + case BSIM4_MOD_UB: + mod->BSIM4ub = value->rValue; + mod->BSIM4ubGiven = TRUE; + break; + case BSIM4_MOD_UB1: + mod->BSIM4ub1 = value->rValue; + mod->BSIM4ub1Given = TRUE; + break; + case BSIM4_MOD_UC: + mod->BSIM4uc = value->rValue; + mod->BSIM4ucGiven = TRUE; + break; + case BSIM4_MOD_UC1: + mod->BSIM4uc1 = value->rValue; + mod->BSIM4uc1Given = TRUE; + break; + case BSIM4_MOD_U0 : + mod->BSIM4u0 = value->rValue; + mod->BSIM4u0Given = TRUE; + break; + case BSIM4_MOD_UTE : + mod->BSIM4ute = value->rValue; + mod->BSIM4uteGiven = TRUE; + break; + case BSIM4_MOD_VOFF: + mod->BSIM4voff = value->rValue; + mod->BSIM4voffGiven = TRUE; + break; + case BSIM4_MOD_VOFFL: + mod->BSIM4voffl = value->rValue; + mod->BSIM4vofflGiven = TRUE; + break; + case BSIM4_MOD_MINV: + mod->BSIM4minv = value->rValue; + mod->BSIM4minvGiven = TRUE; + break; + case BSIM4_MOD_FPROUT: + mod->BSIM4fprout = value->rValue; + mod->BSIM4fproutGiven = TRUE; + break; + case BSIM4_MOD_PDITS: + mod->BSIM4pdits = value->rValue; + mod->BSIM4pditsGiven = TRUE; + break; + case BSIM4_MOD_PDITSD: + mod->BSIM4pditsd = value->rValue; + mod->BSIM4pditsdGiven = TRUE; + break; + case BSIM4_MOD_PDITSL: + mod->BSIM4pditsl = value->rValue; + mod->BSIM4pditslGiven = TRUE; + break; + case BSIM4_MOD_DELTA : + mod->BSIM4delta = value->rValue; + mod->BSIM4deltaGiven = TRUE; + break; + case BSIM4_MOD_RDSW: + mod->BSIM4rdsw = value->rValue; + mod->BSIM4rdswGiven = TRUE; + break; + case BSIM4_MOD_RDSWMIN: + mod->BSIM4rdswmin = value->rValue; + mod->BSIM4rdswminGiven = TRUE; + break; + case BSIM4_MOD_RDWMIN: + mod->BSIM4rdwmin = value->rValue; + mod->BSIM4rdwminGiven = TRUE; + break; + case BSIM4_MOD_RSWMIN: + mod->BSIM4rswmin = value->rValue; + mod->BSIM4rswminGiven = TRUE; + break; + case BSIM4_MOD_RDW: + mod->BSIM4rdw = value->rValue; + mod->BSIM4rdwGiven = TRUE; + break; + case BSIM4_MOD_RSW: + mod->BSIM4rsw = value->rValue; + mod->BSIM4rswGiven = TRUE; + break; + case BSIM4_MOD_PRWG: + mod->BSIM4prwg = value->rValue; + mod->BSIM4prwgGiven = TRUE; + break; + case BSIM4_MOD_PRWB: + mod->BSIM4prwb = value->rValue; + mod->BSIM4prwbGiven = TRUE; + break; + case BSIM4_MOD_PRT: + mod->BSIM4prt = value->rValue; + mod->BSIM4prtGiven = TRUE; + break; + case BSIM4_MOD_ETA0: + mod->BSIM4eta0 = value->rValue; + mod->BSIM4eta0Given = TRUE; + break; + case BSIM4_MOD_ETAB: + mod->BSIM4etab = value->rValue; + mod->BSIM4etabGiven = TRUE; + break; + case BSIM4_MOD_PCLM: + mod->BSIM4pclm = value->rValue; + mod->BSIM4pclmGiven = TRUE; + break; + case BSIM4_MOD_PDIBL1: + mod->BSIM4pdibl1 = value->rValue; + mod->BSIM4pdibl1Given = TRUE; + break; + case BSIM4_MOD_PDIBL2: + mod->BSIM4pdibl2 = value->rValue; + mod->BSIM4pdibl2Given = TRUE; + break; + case BSIM4_MOD_PDIBLB: + mod->BSIM4pdiblb = value->rValue; + mod->BSIM4pdiblbGiven = TRUE; + break; + case BSIM4_MOD_PSCBE1: + mod->BSIM4pscbe1 = value->rValue; + mod->BSIM4pscbe1Given = TRUE; + break; + case BSIM4_MOD_PSCBE2: + mod->BSIM4pscbe2 = value->rValue; + mod->BSIM4pscbe2Given = TRUE; + break; + case BSIM4_MOD_PVAG: + mod->BSIM4pvag = value->rValue; + mod->BSIM4pvagGiven = TRUE; + break; + case BSIM4_MOD_WR : + mod->BSIM4wr = value->rValue; + mod->BSIM4wrGiven = TRUE; + break; + case BSIM4_MOD_DWG : + mod->BSIM4dwg = value->rValue; + mod->BSIM4dwgGiven = TRUE; + break; + case BSIM4_MOD_DWB : + mod->BSIM4dwb = value->rValue; + mod->BSIM4dwbGiven = TRUE; + break; + case BSIM4_MOD_B0 : + mod->BSIM4b0 = value->rValue; + mod->BSIM4b0Given = TRUE; + break; + case BSIM4_MOD_B1 : + mod->BSIM4b1 = value->rValue; + mod->BSIM4b1Given = TRUE; + break; + case BSIM4_MOD_ALPHA0 : + mod->BSIM4alpha0 = value->rValue; + mod->BSIM4alpha0Given = TRUE; + break; + case BSIM4_MOD_ALPHA1 : + mod->BSIM4alpha1 = value->rValue; + mod->BSIM4alpha1Given = TRUE; + break; + case BSIM4_MOD_AGIDL : + mod->BSIM4agidl = value->rValue; + mod->BSIM4agidlGiven = TRUE; + break; + case BSIM4_MOD_BGIDL : + mod->BSIM4bgidl = value->rValue; + mod->BSIM4bgidlGiven = TRUE; + break; + case BSIM4_MOD_CGIDL : + mod->BSIM4cgidl = value->rValue; + mod->BSIM4cgidlGiven = TRUE; + break; + case BSIM4_MOD_PHIN : + mod->BSIM4phin = value->rValue; + mod->BSIM4phinGiven = TRUE; + break; + case BSIM4_MOD_EGIDL : + mod->BSIM4egidl = value->rValue; + mod->BSIM4egidlGiven = TRUE; + break; + case BSIM4_MOD_AIGC : + mod->BSIM4aigc = value->rValue; + mod->BSIM4aigcGiven = TRUE; + break; + case BSIM4_MOD_BIGC : + mod->BSIM4bigc = value->rValue; + mod->BSIM4bigcGiven = TRUE; + break; + case BSIM4_MOD_CIGC : + mod->BSIM4cigc = value->rValue; + mod->BSIM4cigcGiven = TRUE; + break; + case BSIM4_MOD_AIGSD : + mod->BSIM4aigsd = value->rValue; + mod->BSIM4aigsdGiven = TRUE; + break; + case BSIM4_MOD_BIGSD : + mod->BSIM4bigsd = value->rValue; + mod->BSIM4bigsdGiven = TRUE; + break; + case BSIM4_MOD_CIGSD : + mod->BSIM4cigsd = value->rValue; + mod->BSIM4cigsdGiven = TRUE; + break; + case BSIM4_MOD_AIGBACC : + mod->BSIM4aigbacc = value->rValue; + mod->BSIM4aigbaccGiven = TRUE; + break; + case BSIM4_MOD_BIGBACC : + mod->BSIM4bigbacc = value->rValue; + mod->BSIM4bigbaccGiven = TRUE; + break; + case BSIM4_MOD_CIGBACC : + mod->BSIM4cigbacc = value->rValue; + mod->BSIM4cigbaccGiven = TRUE; + break; + case BSIM4_MOD_AIGBINV : + mod->BSIM4aigbinv = value->rValue; + mod->BSIM4aigbinvGiven = TRUE; + break; + case BSIM4_MOD_BIGBINV : + mod->BSIM4bigbinv = value->rValue; + mod->BSIM4bigbinvGiven = TRUE; + break; + case BSIM4_MOD_CIGBINV : + mod->BSIM4cigbinv = value->rValue; + mod->BSIM4cigbinvGiven = TRUE; + break; + case BSIM4_MOD_NIGC : + mod->BSIM4nigc = value->rValue; + mod->BSIM4nigcGiven = TRUE; + break; + case BSIM4_MOD_NIGBINV : + mod->BSIM4nigbinv = value->rValue; + mod->BSIM4nigbinvGiven = TRUE; + break; + case BSIM4_MOD_NIGBACC : + mod->BSIM4nigbacc = value->rValue; + mod->BSIM4nigbaccGiven = TRUE; + break; + case BSIM4_MOD_NTOX : + mod->BSIM4ntox = value->rValue; + mod->BSIM4ntoxGiven = TRUE; + break; + case BSIM4_MOD_EIGBINV : + mod->BSIM4eigbinv = value->rValue; + mod->BSIM4eigbinvGiven = TRUE; + break; + case BSIM4_MOD_PIGCD : + mod->BSIM4pigcd = value->rValue; + mod->BSIM4pigcdGiven = TRUE; + break; + case BSIM4_MOD_POXEDGE : + mod->BSIM4poxedge = value->rValue; + mod->BSIM4poxedgeGiven = TRUE; + break; + case BSIM4_MOD_XRCRG1 : + mod->BSIM4xrcrg1 = value->rValue; + mod->BSIM4xrcrg1Given = TRUE; + break; + case BSIM4_MOD_TNOIA : + mod->BSIM4tnoia = value->rValue; + mod->BSIM4tnoiaGiven = TRUE; + break; + case BSIM4_MOD_TNOIB : + mod->BSIM4tnoib = value->rValue; + mod->BSIM4tnoibGiven = TRUE; + break; + case BSIM4_MOD_NTNOI : + mod->BSIM4ntnoi = value->rValue; + mod->BSIM4ntnoiGiven = TRUE; + break; + case BSIM4_MOD_XRCRG2 : + mod->BSIM4xrcrg2 = value->rValue; + mod->BSIM4xrcrg2Given = TRUE; + break; + case BSIM4_MOD_BETA0 : + mod->BSIM4beta0 = value->rValue; + mod->BSIM4beta0Given = TRUE; + break; + case BSIM4_MOD_IJTHDFWD : + mod->BSIM4ijthdfwd = value->rValue; + mod->BSIM4ijthdfwdGiven = TRUE; + break; + case BSIM4_MOD_IJTHSFWD : + mod->BSIM4ijthsfwd = value->rValue; + mod->BSIM4ijthsfwdGiven = TRUE; + break; + case BSIM4_MOD_IJTHDREV : + mod->BSIM4ijthdrev = value->rValue; + mod->BSIM4ijthdrevGiven = TRUE; + break; + case BSIM4_MOD_IJTHSREV : + mod->BSIM4ijthsrev = value->rValue; + mod->BSIM4ijthsrevGiven = TRUE; + break; + case BSIM4_MOD_XJBVD : + mod->BSIM4xjbvd = value->rValue; + mod->BSIM4xjbvdGiven = TRUE; + break; + case BSIM4_MOD_XJBVS : + mod->BSIM4xjbvs = value->rValue; + mod->BSIM4xjbvsGiven = TRUE; + break; + case BSIM4_MOD_BVD : + mod->BSIM4bvd = value->rValue; + mod->BSIM4bvdGiven = TRUE; + break; + case BSIM4_MOD_BVS : + mod->BSIM4bvs = value->rValue; + mod->BSIM4bvsGiven = TRUE; + break; + case BSIM4_MOD_VFB : + mod->BSIM4vfb = value->rValue; + mod->BSIM4vfbGiven = TRUE; + break; + + case BSIM4_MOD_GBMIN : + mod->BSIM4gbmin = value->rValue; + mod->BSIM4gbminGiven = TRUE; + break; + case BSIM4_MOD_RBDB : + mod->BSIM4rbdb = value->rValue; + mod->BSIM4rbdbGiven = TRUE; + break; + case BSIM4_MOD_RBPB : + mod->BSIM4rbpb = value->rValue; + mod->BSIM4rbpbGiven = TRUE; + break; + case BSIM4_MOD_RBSB : + mod->BSIM4rbsb = value->rValue; + mod->BSIM4rbsbGiven = TRUE; + break; + case BSIM4_MOD_RBPS : + mod->BSIM4rbps = value->rValue; + mod->BSIM4rbpsGiven = TRUE; + break; + case BSIM4_MOD_RBPD : + mod->BSIM4rbpd = value->rValue; + mod->BSIM4rbpdGiven = TRUE; + break; + + case BSIM4_MOD_CGSL : + mod->BSIM4cgsl = value->rValue; + mod->BSIM4cgslGiven = TRUE; + break; + case BSIM4_MOD_CGDL : + mod->BSIM4cgdl = value->rValue; + mod->BSIM4cgdlGiven = TRUE; + break; + case BSIM4_MOD_CKAPPAS : + mod->BSIM4ckappas = value->rValue; + mod->BSIM4ckappasGiven = TRUE; + break; + case BSIM4_MOD_CKAPPAD : + mod->BSIM4ckappad = value->rValue; + mod->BSIM4ckappadGiven = TRUE; + break; + case BSIM4_MOD_CF : + mod->BSIM4cf = value->rValue; + mod->BSIM4cfGiven = TRUE; + break; + case BSIM4_MOD_CLC : + mod->BSIM4clc = value->rValue; + mod->BSIM4clcGiven = TRUE; + break; + case BSIM4_MOD_CLE : + mod->BSIM4cle = value->rValue; + mod->BSIM4cleGiven = TRUE; + break; + case BSIM4_MOD_DWC : + mod->BSIM4dwc = value->rValue; + mod->BSIM4dwcGiven = TRUE; + break; + case BSIM4_MOD_DLC : + mod->BSIM4dlc = value->rValue; + mod->BSIM4dlcGiven = TRUE; + break; + case BSIM4_MOD_DLCIG : + mod->BSIM4dlcig = value->rValue; + mod->BSIM4dlcigGiven = TRUE; + break; + case BSIM4_MOD_DWJ : + mod->BSIM4dwj = value->rValue; + mod->BSIM4dwjGiven = TRUE; + break; + case BSIM4_MOD_VFBCV : + mod->BSIM4vfbcv = value->rValue; + mod->BSIM4vfbcvGiven = TRUE; + break; + case BSIM4_MOD_ACDE : + mod->BSIM4acde = value->rValue; + mod->BSIM4acdeGiven = TRUE; + break; + case BSIM4_MOD_MOIN : + mod->BSIM4moin = value->rValue; + mod->BSIM4moinGiven = TRUE; + break; + case BSIM4_MOD_NOFF : + mod->BSIM4noff = value->rValue; + mod->BSIM4noffGiven = TRUE; + break; + case BSIM4_MOD_VOFFCV : + mod->BSIM4voffcv = value->rValue; + mod->BSIM4voffcvGiven = TRUE; + break; + case BSIM4_MOD_DMCG : + mod->BSIM4dmcg = value->rValue; + mod->BSIM4dmcgGiven = TRUE; + break; + case BSIM4_MOD_DMCI : + mod->BSIM4dmci = value->rValue; + mod->BSIM4dmciGiven = TRUE; + break; + case BSIM4_MOD_DMDG : + mod->BSIM4dmdg = value->rValue; + mod->BSIM4dmdgGiven = TRUE; + break; + case BSIM4_MOD_DMCGT : + mod->BSIM4dmcgt = value->rValue; + mod->BSIM4dmcgtGiven = TRUE; + break; + case BSIM4_MOD_XGW : + mod->BSIM4xgw = value->rValue; + mod->BSIM4xgwGiven = TRUE; + break; + case BSIM4_MOD_XGL : + mod->BSIM4xgl = value->rValue; + mod->BSIM4xglGiven = TRUE; + break; + case BSIM4_MOD_RSHG : + mod->BSIM4rshg = value->rValue; + mod->BSIM4rshgGiven = TRUE; + break; + case BSIM4_MOD_NGCON : + mod->BSIM4ngcon = value->rValue; + mod->BSIM4ngconGiven = TRUE; + break; + case BSIM4_MOD_TCJ : + mod->BSIM4tcj = value->rValue; + mod->BSIM4tcjGiven = TRUE; + break; + case BSIM4_MOD_TPB : + mod->BSIM4tpb = value->rValue; + mod->BSIM4tpbGiven = TRUE; + break; + case BSIM4_MOD_TCJSW : + mod->BSIM4tcjsw = value->rValue; + mod->BSIM4tcjswGiven = TRUE; + break; + case BSIM4_MOD_TPBSW : + mod->BSIM4tpbsw = value->rValue; + mod->BSIM4tpbswGiven = TRUE; + break; + case BSIM4_MOD_TCJSWG : + mod->BSIM4tcjswg = value->rValue; + mod->BSIM4tcjswgGiven = TRUE; + break; + case BSIM4_MOD_TPBSWG : + mod->BSIM4tpbswg = value->rValue; + mod->BSIM4tpbswgGiven = TRUE; + break; + + /* Length dependence */ + case BSIM4_MOD_LCDSC : + mod->BSIM4lcdsc = value->rValue; + mod->BSIM4lcdscGiven = TRUE; + break; + + + case BSIM4_MOD_LCDSCB : + mod->BSIM4lcdscb = value->rValue; + mod->BSIM4lcdscbGiven = TRUE; + break; + case BSIM4_MOD_LCDSCD : + mod->BSIM4lcdscd = value->rValue; + mod->BSIM4lcdscdGiven = TRUE; + break; + case BSIM4_MOD_LCIT : + mod->BSIM4lcit = value->rValue; + mod->BSIM4lcitGiven = TRUE; + break; + case BSIM4_MOD_LNFACTOR : + mod->BSIM4lnfactor = value->rValue; + mod->BSIM4lnfactorGiven = TRUE; + break; + case BSIM4_MOD_LXJ: + mod->BSIM4lxj = value->rValue; + mod->BSIM4lxjGiven = TRUE; + break; + case BSIM4_MOD_LVSAT: + mod->BSIM4lvsat = value->rValue; + mod->BSIM4lvsatGiven = TRUE; + break; + + + case BSIM4_MOD_LA0: + mod->BSIM4la0 = value->rValue; + mod->BSIM4la0Given = TRUE; + break; + case BSIM4_MOD_LAGS: + mod->BSIM4lags = value->rValue; + mod->BSIM4lagsGiven = TRUE; + break; + case BSIM4_MOD_LA1: + mod->BSIM4la1 = value->rValue; + mod->BSIM4la1Given = TRUE; + break; + case BSIM4_MOD_LA2: + mod->BSIM4la2 = value->rValue; + mod->BSIM4la2Given = TRUE; + break; + case BSIM4_MOD_LAT: + mod->BSIM4lat = value->rValue; + mod->BSIM4latGiven = TRUE; + break; + case BSIM4_MOD_LKETA: + mod->BSIM4lketa = value->rValue; + mod->BSIM4lketaGiven = TRUE; + break; + case BSIM4_MOD_LNSUB: + mod->BSIM4lnsub = value->rValue; + mod->BSIM4lnsubGiven = TRUE; + break; + case BSIM4_MOD_LNDEP: + mod->BSIM4lndep = value->rValue; + mod->BSIM4lndepGiven = TRUE; + if (mod->BSIM4lndep > 1.0e20) + mod->BSIM4lndep *= 1.0e-6; + break; + case BSIM4_MOD_LNSD: + mod->BSIM4lnsd = value->rValue; + mod->BSIM4lnsdGiven = TRUE; + if (mod->BSIM4lnsd > 1.0e23) + mod->BSIM4lnsd *= 1.0e-6; + break; + case BSIM4_MOD_LNGATE: + mod->BSIM4lngate = value->rValue; + mod->BSIM4lngateGiven = TRUE; + if (mod->BSIM4lngate > 1.0e23) + mod->BSIM4lngate *= 1.0e-6; + break; + case BSIM4_MOD_LGAMMA1: + mod->BSIM4lgamma1 = value->rValue; + mod->BSIM4lgamma1Given = TRUE; + break; + case BSIM4_MOD_LGAMMA2: + mod->BSIM4lgamma2 = value->rValue; + mod->BSIM4lgamma2Given = TRUE; + break; + case BSIM4_MOD_LVBX: + mod->BSIM4lvbx = value->rValue; + mod->BSIM4lvbxGiven = TRUE; + break; + case BSIM4_MOD_LVBM: + mod->BSIM4lvbm = value->rValue; + mod->BSIM4lvbmGiven = TRUE; + break; + case BSIM4_MOD_LXT: + mod->BSIM4lxt = value->rValue; + mod->BSIM4lxtGiven = TRUE; + break; + case BSIM4_MOD_LK1: + mod->BSIM4lk1 = value->rValue; + mod->BSIM4lk1Given = TRUE; + break; + case BSIM4_MOD_LKT1: + mod->BSIM4lkt1 = value->rValue; + mod->BSIM4lkt1Given = TRUE; + break; + case BSIM4_MOD_LKT1L: + mod->BSIM4lkt1l = value->rValue; + mod->BSIM4lkt1lGiven = TRUE; + break; + case BSIM4_MOD_LKT2: + mod->BSIM4lkt2 = value->rValue; + mod->BSIM4lkt2Given = TRUE; + break; + case BSIM4_MOD_LK2: + mod->BSIM4lk2 = value->rValue; + mod->BSIM4lk2Given = TRUE; + break; + case BSIM4_MOD_LK3: + mod->BSIM4lk3 = value->rValue; + mod->BSIM4lk3Given = TRUE; + break; + case BSIM4_MOD_LK3B: + mod->BSIM4lk3b = value->rValue; + mod->BSIM4lk3bGiven = TRUE; + break; + case BSIM4_MOD_LLPE0: + mod->BSIM4llpe0 = value->rValue; + mod->BSIM4llpe0Given = TRUE; + break; + case BSIM4_MOD_LLPEB: + mod->BSIM4llpeb = value->rValue; + mod->BSIM4llpebGiven = TRUE; + break; + case BSIM4_MOD_LDVTP0: + mod->BSIM4ldvtp0 = value->rValue; + mod->BSIM4ldvtp0Given = TRUE; + break; + case BSIM4_MOD_LDVTP1: + mod->BSIM4ldvtp1 = value->rValue; + mod->BSIM4ldvtp1Given = TRUE; + break; + case BSIM4_MOD_LW0: + mod->BSIM4lw0 = value->rValue; + mod->BSIM4lw0Given = TRUE; + break; + case BSIM4_MOD_LDVT0: + mod->BSIM4ldvt0 = value->rValue; + mod->BSIM4ldvt0Given = TRUE; + break; + case BSIM4_MOD_LDVT1: + mod->BSIM4ldvt1 = value->rValue; + mod->BSIM4ldvt1Given = TRUE; + break; + case BSIM4_MOD_LDVT2: + mod->BSIM4ldvt2 = value->rValue; + mod->BSIM4ldvt2Given = TRUE; + break; + case BSIM4_MOD_LDVT0W: + mod->BSIM4ldvt0w = value->rValue; + mod->BSIM4ldvt0wGiven = TRUE; + break; + case BSIM4_MOD_LDVT1W: + mod->BSIM4ldvt1w = value->rValue; + mod->BSIM4ldvt1wGiven = TRUE; + break; + case BSIM4_MOD_LDVT2W: + mod->BSIM4ldvt2w = value->rValue; + mod->BSIM4ldvt2wGiven = TRUE; + break; + case BSIM4_MOD_LDROUT: + mod->BSIM4ldrout = value->rValue; + mod->BSIM4ldroutGiven = TRUE; + break; + case BSIM4_MOD_LDSUB: + mod->BSIM4ldsub = value->rValue; + mod->BSIM4ldsubGiven = TRUE; + break; + case BSIM4_MOD_LVTH0: + mod->BSIM4lvth0 = value->rValue; + mod->BSIM4lvth0Given = TRUE; + break; + case BSIM4_MOD_LUA: + mod->BSIM4lua = value->rValue; + mod->BSIM4luaGiven = TRUE; + break; + case BSIM4_MOD_LUA1: + mod->BSIM4lua1 = value->rValue; + mod->BSIM4lua1Given = TRUE; + break; + case BSIM4_MOD_LUB: + mod->BSIM4lub = value->rValue; + mod->BSIM4lubGiven = TRUE; + break; + case BSIM4_MOD_LUB1: + mod->BSIM4lub1 = value->rValue; + mod->BSIM4lub1Given = TRUE; + break; + case BSIM4_MOD_LUC: + mod->BSIM4luc = value->rValue; + mod->BSIM4lucGiven = TRUE; + break; + case BSIM4_MOD_LUC1: + mod->BSIM4luc1 = value->rValue; + mod->BSIM4luc1Given = TRUE; + break; + case BSIM4_MOD_LU0 : + mod->BSIM4lu0 = value->rValue; + mod->BSIM4lu0Given = TRUE; + break; + case BSIM4_MOD_LUTE : + mod->BSIM4lute = value->rValue; + mod->BSIM4luteGiven = TRUE; + break; + case BSIM4_MOD_LVOFF: + mod->BSIM4lvoff = value->rValue; + mod->BSIM4lvoffGiven = TRUE; + break; + case BSIM4_MOD_LMINV: + mod->BSIM4lminv = value->rValue; + mod->BSIM4lminvGiven = TRUE; + break; + case BSIM4_MOD_LFPROUT: + mod->BSIM4lfprout = value->rValue; + mod->BSIM4lfproutGiven = TRUE; + break; + case BSIM4_MOD_LPDITS: + mod->BSIM4lpdits = value->rValue; + mod->BSIM4lpditsGiven = TRUE; + break; + case BSIM4_MOD_LPDITSD: + mod->BSIM4lpditsd = value->rValue; + mod->BSIM4lpditsdGiven = TRUE; + break; + case BSIM4_MOD_LDELTA : + mod->BSIM4ldelta = value->rValue; + mod->BSIM4ldeltaGiven = TRUE; + break; + case BSIM4_MOD_LRDSW: + mod->BSIM4lrdsw = value->rValue; + mod->BSIM4lrdswGiven = TRUE; + break; + case BSIM4_MOD_LRDW: + mod->BSIM4lrdw = value->rValue; + mod->BSIM4lrdwGiven = TRUE; + break; + case BSIM4_MOD_LRSW: + mod->BSIM4lrsw = value->rValue; + mod->BSIM4lrswGiven = TRUE; + break; + case BSIM4_MOD_LPRWB: + mod->BSIM4lprwb = value->rValue; + mod->BSIM4lprwbGiven = TRUE; + break; + case BSIM4_MOD_LPRWG: + mod->BSIM4lprwg = value->rValue; + mod->BSIM4lprwgGiven = TRUE; + break; + case BSIM4_MOD_LPRT: + mod->BSIM4lprt = value->rValue; + mod->BSIM4lprtGiven = TRUE; + break; + case BSIM4_MOD_LETA0: + mod->BSIM4leta0 = value->rValue; + mod->BSIM4leta0Given = TRUE; + break; + case BSIM4_MOD_LETAB: + mod->BSIM4letab = value->rValue; + mod->BSIM4letabGiven = TRUE; + break; + case BSIM4_MOD_LPCLM: + mod->BSIM4lpclm = value->rValue; + mod->BSIM4lpclmGiven = TRUE; + break; + case BSIM4_MOD_LPDIBL1: + mod->BSIM4lpdibl1 = value->rValue; + mod->BSIM4lpdibl1Given = TRUE; + break; + case BSIM4_MOD_LPDIBL2: + mod->BSIM4lpdibl2 = value->rValue; + mod->BSIM4lpdibl2Given = TRUE; + break; + case BSIM4_MOD_LPDIBLB: + mod->BSIM4lpdiblb = value->rValue; + mod->BSIM4lpdiblbGiven = TRUE; + break; + case BSIM4_MOD_LPSCBE1: + mod->BSIM4lpscbe1 = value->rValue; + mod->BSIM4lpscbe1Given = TRUE; + break; + case BSIM4_MOD_LPSCBE2: + mod->BSIM4lpscbe2 = value->rValue; + mod->BSIM4lpscbe2Given = TRUE; + break; + case BSIM4_MOD_LPVAG: + mod->BSIM4lpvag = value->rValue; + mod->BSIM4lpvagGiven = TRUE; + break; + case BSIM4_MOD_LWR : + mod->BSIM4lwr = value->rValue; + mod->BSIM4lwrGiven = TRUE; + break; + case BSIM4_MOD_LDWG : + mod->BSIM4ldwg = value->rValue; + mod->BSIM4ldwgGiven = TRUE; + break; + case BSIM4_MOD_LDWB : + mod->BSIM4ldwb = value->rValue; + mod->BSIM4ldwbGiven = TRUE; + break; + case BSIM4_MOD_LB0 : + mod->BSIM4lb0 = value->rValue; + mod->BSIM4lb0Given = TRUE; + break; + case BSIM4_MOD_LB1 : + mod->BSIM4lb1 = value->rValue; + mod->BSIM4lb1Given = TRUE; + break; + case BSIM4_MOD_LALPHA0 : + mod->BSIM4lalpha0 = value->rValue; + mod->BSIM4lalpha0Given = TRUE; + break; + case BSIM4_MOD_LALPHA1 : + mod->BSIM4lalpha1 = value->rValue; + mod->BSIM4lalpha1Given = TRUE; + break; + case BSIM4_MOD_LBETA0 : + mod->BSIM4lbeta0 = value->rValue; + mod->BSIM4lbeta0Given = TRUE; + break; + case BSIM4_MOD_LAGIDL : + mod->BSIM4lagidl = value->rValue; + mod->BSIM4lagidlGiven = TRUE; + break; + case BSIM4_MOD_LBGIDL : + mod->BSIM4lbgidl = value->rValue; + mod->BSIM4lbgidlGiven = TRUE; + break; + case BSIM4_MOD_LCGIDL : + mod->BSIM4lcgidl = value->rValue; + mod->BSIM4lcgidlGiven = TRUE; + break; + case BSIM4_MOD_LPHIN : + mod->BSIM4lphin = value->rValue; + mod->BSIM4lphinGiven = TRUE; + break; + case BSIM4_MOD_LEGIDL : + mod->BSIM4legidl = value->rValue; + mod->BSIM4legidlGiven = TRUE; + break; + case BSIM4_MOD_LAIGC : + mod->BSIM4laigc = value->rValue; + mod->BSIM4laigcGiven = TRUE; + break; + case BSIM4_MOD_LBIGC : + mod->BSIM4lbigc = value->rValue; + mod->BSIM4lbigcGiven = TRUE; + break; + case BSIM4_MOD_LCIGC : + mod->BSIM4lcigc = value->rValue; + mod->BSIM4lcigcGiven = TRUE; + break; + case BSIM4_MOD_LAIGSD : + mod->BSIM4laigsd = value->rValue; + mod->BSIM4laigsdGiven = TRUE; + break; + case BSIM4_MOD_LBIGSD : + mod->BSIM4lbigsd = value->rValue; + mod->BSIM4lbigsdGiven = TRUE; + break; + case BSIM4_MOD_LCIGSD : + mod->BSIM4lcigsd = value->rValue; + mod->BSIM4lcigsdGiven = TRUE; + break; + case BSIM4_MOD_LAIGBACC : + mod->BSIM4laigbacc = value->rValue; + mod->BSIM4laigbaccGiven = TRUE; + break; + case BSIM4_MOD_LBIGBACC : + mod->BSIM4lbigbacc = value->rValue; + mod->BSIM4lbigbaccGiven = TRUE; + break; + case BSIM4_MOD_LCIGBACC : + mod->BSIM4lcigbacc = value->rValue; + mod->BSIM4lcigbaccGiven = TRUE; + break; + case BSIM4_MOD_LAIGBINV : + mod->BSIM4laigbinv = value->rValue; + mod->BSIM4laigbinvGiven = TRUE; + break; + case BSIM4_MOD_LBIGBINV : + mod->BSIM4lbigbinv = value->rValue; + mod->BSIM4lbigbinvGiven = TRUE; + break; + case BSIM4_MOD_LCIGBINV : + mod->BSIM4lcigbinv = value->rValue; + mod->BSIM4lcigbinvGiven = TRUE; + break; + case BSIM4_MOD_LNIGC : + mod->BSIM4lnigc = value->rValue; + mod->BSIM4lnigcGiven = TRUE; + break; + case BSIM4_MOD_LNIGBINV : + mod->BSIM4lnigbinv = value->rValue; + mod->BSIM4lnigbinvGiven = TRUE; + break; + case BSIM4_MOD_LNIGBACC : + mod->BSIM4lnigbacc = value->rValue; + mod->BSIM4lnigbaccGiven = TRUE; + break; + case BSIM4_MOD_LNTOX : + mod->BSIM4lntox = value->rValue; + mod->BSIM4lntoxGiven = TRUE; + break; + case BSIM4_MOD_LEIGBINV : + mod->BSIM4leigbinv = value->rValue; + mod->BSIM4leigbinvGiven = TRUE; + break; + case BSIM4_MOD_LPIGCD : + mod->BSIM4lpigcd = value->rValue; + mod->BSIM4lpigcdGiven = TRUE; + break; + case BSIM4_MOD_LPOXEDGE : + mod->BSIM4lpoxedge = value->rValue; + mod->BSIM4lpoxedgeGiven = TRUE; + break; + case BSIM4_MOD_LXRCRG1 : + mod->BSIM4lxrcrg1 = value->rValue; + mod->BSIM4lxrcrg1Given = TRUE; + break; + case BSIM4_MOD_LXRCRG2 : + mod->BSIM4lxrcrg2 = value->rValue; + mod->BSIM4lxrcrg2Given = TRUE; + break; + case BSIM4_MOD_LEU : + mod->BSIM4leu = value->rValue; + mod->BSIM4leuGiven = TRUE; + break; + case BSIM4_MOD_LVFB : + mod->BSIM4lvfb = value->rValue; + mod->BSIM4lvfbGiven = TRUE; + break; + + case BSIM4_MOD_LCGSL : + mod->BSIM4lcgsl = value->rValue; + mod->BSIM4lcgslGiven = TRUE; + break; + case BSIM4_MOD_LCGDL : + mod->BSIM4lcgdl = value->rValue; + mod->BSIM4lcgdlGiven = TRUE; + break; + case BSIM4_MOD_LCKAPPAS : + mod->BSIM4lckappas = value->rValue; + mod->BSIM4lckappasGiven = TRUE; + break; + case BSIM4_MOD_LCKAPPAD : + mod->BSIM4lckappad = value->rValue; + mod->BSIM4lckappadGiven = TRUE; + break; + case BSIM4_MOD_LCF : + mod->BSIM4lcf = value->rValue; + mod->BSIM4lcfGiven = TRUE; + break; + case BSIM4_MOD_LCLC : + mod->BSIM4lclc = value->rValue; + mod->BSIM4lclcGiven = TRUE; + break; + case BSIM4_MOD_LCLE : + mod->BSIM4lcle = value->rValue; + mod->BSIM4lcleGiven = TRUE; + break; + case BSIM4_MOD_LVFBCV : + mod->BSIM4lvfbcv = value->rValue; + mod->BSIM4lvfbcvGiven = TRUE; + break; + case BSIM4_MOD_LACDE : + mod->BSIM4lacde = value->rValue; + mod->BSIM4lacdeGiven = TRUE; + break; + case BSIM4_MOD_LMOIN : + mod->BSIM4lmoin = value->rValue; + mod->BSIM4lmoinGiven = TRUE; + break; + case BSIM4_MOD_LNOFF : + mod->BSIM4lnoff = value->rValue; + mod->BSIM4lnoffGiven = TRUE; + break; + case BSIM4_MOD_LVOFFCV : + mod->BSIM4lvoffcv = value->rValue; + mod->BSIM4lvoffcvGiven = TRUE; + break; + + /* Width dependence */ + case BSIM4_MOD_WCDSC : + mod->BSIM4wcdsc = value->rValue; + mod->BSIM4wcdscGiven = TRUE; + break; + + + case BSIM4_MOD_WCDSCB : + mod->BSIM4wcdscb = value->rValue; + mod->BSIM4wcdscbGiven = TRUE; + break; + case BSIM4_MOD_WCDSCD : + mod->BSIM4wcdscd = value->rValue; + mod->BSIM4wcdscdGiven = TRUE; + break; + case BSIM4_MOD_WCIT : + mod->BSIM4wcit = value->rValue; + mod->BSIM4wcitGiven = TRUE; + break; + case BSIM4_MOD_WNFACTOR : + mod->BSIM4wnfactor = value->rValue; + mod->BSIM4wnfactorGiven = TRUE; + break; + case BSIM4_MOD_WXJ: + mod->BSIM4wxj = value->rValue; + mod->BSIM4wxjGiven = TRUE; + break; + case BSIM4_MOD_WVSAT: + mod->BSIM4wvsat = value->rValue; + mod->BSIM4wvsatGiven = TRUE; + break; + + + case BSIM4_MOD_WA0: + mod->BSIM4wa0 = value->rValue; + mod->BSIM4wa0Given = TRUE; + break; + case BSIM4_MOD_WAGS: + mod->BSIM4wags = value->rValue; + mod->BSIM4wagsGiven = TRUE; + break; + case BSIM4_MOD_WA1: + mod->BSIM4wa1 = value->rValue; + mod->BSIM4wa1Given = TRUE; + break; + case BSIM4_MOD_WA2: + mod->BSIM4wa2 = value->rValue; + mod->BSIM4wa2Given = TRUE; + break; + case BSIM4_MOD_WAT: + mod->BSIM4wat = value->rValue; + mod->BSIM4watGiven = TRUE; + break; + case BSIM4_MOD_WKETA: + mod->BSIM4wketa = value->rValue; + mod->BSIM4wketaGiven = TRUE; + break; + case BSIM4_MOD_WNSUB: + mod->BSIM4wnsub = value->rValue; + mod->BSIM4wnsubGiven = TRUE; + break; + case BSIM4_MOD_WNDEP: + mod->BSIM4wndep = value->rValue; + mod->BSIM4wndepGiven = TRUE; + if (mod->BSIM4wndep > 1.0e20) + mod->BSIM4wndep *= 1.0e-6; + break; + case BSIM4_MOD_WNSD: + mod->BSIM4wnsd = value->rValue; + mod->BSIM4wnsdGiven = TRUE; + if (mod->BSIM4wnsd > 1.0e23) + mod->BSIM4wnsd *= 1.0e-6; + break; + case BSIM4_MOD_WNGATE: + mod->BSIM4wngate = value->rValue; + mod->BSIM4wngateGiven = TRUE; + if (mod->BSIM4wngate > 1.0e23) + mod->BSIM4wngate *= 1.0e-6; + break; + case BSIM4_MOD_WGAMMA1: + mod->BSIM4wgamma1 = value->rValue; + mod->BSIM4wgamma1Given = TRUE; + break; + case BSIM4_MOD_WGAMMA2: + mod->BSIM4wgamma2 = value->rValue; + mod->BSIM4wgamma2Given = TRUE; + break; + case BSIM4_MOD_WVBX: + mod->BSIM4wvbx = value->rValue; + mod->BSIM4wvbxGiven = TRUE; + break; + case BSIM4_MOD_WVBM: + mod->BSIM4wvbm = value->rValue; + mod->BSIM4wvbmGiven = TRUE; + break; + case BSIM4_MOD_WXT: + mod->BSIM4wxt = value->rValue; + mod->BSIM4wxtGiven = TRUE; + break; + case BSIM4_MOD_WK1: + mod->BSIM4wk1 = value->rValue; + mod->BSIM4wk1Given = TRUE; + break; + case BSIM4_MOD_WKT1: + mod->BSIM4wkt1 = value->rValue; + mod->BSIM4wkt1Given = TRUE; + break; + case BSIM4_MOD_WKT1L: + mod->BSIM4wkt1l = value->rValue; + mod->BSIM4wkt1lGiven = TRUE; + break; + case BSIM4_MOD_WKT2: + mod->BSIM4wkt2 = value->rValue; + mod->BSIM4wkt2Given = TRUE; + break; + case BSIM4_MOD_WK2: + mod->BSIM4wk2 = value->rValue; + mod->BSIM4wk2Given = TRUE; + break; + case BSIM4_MOD_WK3: + mod->BSIM4wk3 = value->rValue; + mod->BSIM4wk3Given = TRUE; + break; + case BSIM4_MOD_WK3B: + mod->BSIM4wk3b = value->rValue; + mod->BSIM4wk3bGiven = TRUE; + break; + case BSIM4_MOD_WLPE0: + mod->BSIM4wlpe0 = value->rValue; + mod->BSIM4wlpe0Given = TRUE; + break; + case BSIM4_MOD_WLPEB: + mod->BSIM4wlpeb = value->rValue; + mod->BSIM4wlpebGiven = TRUE; + break; + case BSIM4_MOD_WDVTP0: + mod->BSIM4wdvtp0 = value->rValue; + mod->BSIM4wdvtp0Given = TRUE; + break; + case BSIM4_MOD_WDVTP1: + mod->BSIM4wdvtp1 = value->rValue; + mod->BSIM4wdvtp1Given = TRUE; + break; + case BSIM4_MOD_WW0: + mod->BSIM4ww0 = value->rValue; + mod->BSIM4ww0Given = TRUE; + break; + case BSIM4_MOD_WDVT0: + mod->BSIM4wdvt0 = value->rValue; + mod->BSIM4wdvt0Given = TRUE; + break; + case BSIM4_MOD_WDVT1: + mod->BSIM4wdvt1 = value->rValue; + mod->BSIM4wdvt1Given = TRUE; + break; + case BSIM4_MOD_WDVT2: + mod->BSIM4wdvt2 = value->rValue; + mod->BSIM4wdvt2Given = TRUE; + break; + case BSIM4_MOD_WDVT0W: + mod->BSIM4wdvt0w = value->rValue; + mod->BSIM4wdvt0wGiven = TRUE; + break; + case BSIM4_MOD_WDVT1W: + mod->BSIM4wdvt1w = value->rValue; + mod->BSIM4wdvt1wGiven = TRUE; + break; + case BSIM4_MOD_WDVT2W: + mod->BSIM4wdvt2w = value->rValue; + mod->BSIM4wdvt2wGiven = TRUE; + break; + case BSIM4_MOD_WDROUT: + mod->BSIM4wdrout = value->rValue; + mod->BSIM4wdroutGiven = TRUE; + break; + case BSIM4_MOD_WDSUB: + mod->BSIM4wdsub = value->rValue; + mod->BSIM4wdsubGiven = TRUE; + break; + case BSIM4_MOD_WVTH0: + mod->BSIM4wvth0 = value->rValue; + mod->BSIM4wvth0Given = TRUE; + break; + case BSIM4_MOD_WUA: + mod->BSIM4wua = value->rValue; + mod->BSIM4wuaGiven = TRUE; + break; + case BSIM4_MOD_WUA1: + mod->BSIM4wua1 = value->rValue; + mod->BSIM4wua1Given = TRUE; + break; + case BSIM4_MOD_WUB: + mod->BSIM4wub = value->rValue; + mod->BSIM4wubGiven = TRUE; + break; + case BSIM4_MOD_WUB1: + mod->BSIM4wub1 = value->rValue; + mod->BSIM4wub1Given = TRUE; + break; + case BSIM4_MOD_WUC: + mod->BSIM4wuc = value->rValue; + mod->BSIM4wucGiven = TRUE; + break; + case BSIM4_MOD_WUC1: + mod->BSIM4wuc1 = value->rValue; + mod->BSIM4wuc1Given = TRUE; + break; + case BSIM4_MOD_WU0 : + mod->BSIM4wu0 = value->rValue; + mod->BSIM4wu0Given = TRUE; + break; + case BSIM4_MOD_WUTE : + mod->BSIM4wute = value->rValue; + mod->BSIM4wuteGiven = TRUE; + break; + case BSIM4_MOD_WVOFF: + mod->BSIM4wvoff = value->rValue; + mod->BSIM4wvoffGiven = TRUE; + break; + case BSIM4_MOD_WMINV: + mod->BSIM4wminv = value->rValue; + mod->BSIM4wminvGiven = TRUE; + break; + case BSIM4_MOD_WFPROUT: + mod->BSIM4wfprout = value->rValue; + mod->BSIM4wfproutGiven = TRUE; + break; + case BSIM4_MOD_WPDITS: + mod->BSIM4wpdits = value->rValue; + mod->BSIM4wpditsGiven = TRUE; + break; + case BSIM4_MOD_WPDITSD: + mod->BSIM4wpditsd = value->rValue; + mod->BSIM4wpditsdGiven = TRUE; + break; + case BSIM4_MOD_WDELTA : + mod->BSIM4wdelta = value->rValue; + mod->BSIM4wdeltaGiven = TRUE; + break; + case BSIM4_MOD_WRDSW: + mod->BSIM4wrdsw = value->rValue; + mod->BSIM4wrdswGiven = TRUE; + break; + case BSIM4_MOD_WRDW: + mod->BSIM4wrdw = value->rValue; + mod->BSIM4wrdwGiven = TRUE; + break; + case BSIM4_MOD_WRSW: + mod->BSIM4wrsw = value->rValue; + mod->BSIM4wrswGiven = TRUE; + break; + case BSIM4_MOD_WPRWB: + mod->BSIM4wprwb = value->rValue; + mod->BSIM4wprwbGiven = TRUE; + break; + case BSIM4_MOD_WPRWG: + mod->BSIM4wprwg = value->rValue; + mod->BSIM4wprwgGiven = TRUE; + break; + case BSIM4_MOD_WPRT: + mod->BSIM4wprt = value->rValue; + mod->BSIM4wprtGiven = TRUE; + break; + case BSIM4_MOD_WETA0: + mod->BSIM4weta0 = value->rValue; + mod->BSIM4weta0Given = TRUE; + break; + case BSIM4_MOD_WETAB: + mod->BSIM4wetab = value->rValue; + mod->BSIM4wetabGiven = TRUE; + break; + case BSIM4_MOD_WPCLM: + mod->BSIM4wpclm = value->rValue; + mod->BSIM4wpclmGiven = TRUE; + break; + case BSIM4_MOD_WPDIBL1: + mod->BSIM4wpdibl1 = value->rValue; + mod->BSIM4wpdibl1Given = TRUE; + break; + case BSIM4_MOD_WPDIBL2: + mod->BSIM4wpdibl2 = value->rValue; + mod->BSIM4wpdibl2Given = TRUE; + break; + case BSIM4_MOD_WPDIBLB: + mod->BSIM4wpdiblb = value->rValue; + mod->BSIM4wpdiblbGiven = TRUE; + break; + case BSIM4_MOD_WPSCBE1: + mod->BSIM4wpscbe1 = value->rValue; + mod->BSIM4wpscbe1Given = TRUE; + break; + case BSIM4_MOD_WPSCBE2: + mod->BSIM4wpscbe2 = value->rValue; + mod->BSIM4wpscbe2Given = TRUE; + break; + case BSIM4_MOD_WPVAG: + mod->BSIM4wpvag = value->rValue; + mod->BSIM4wpvagGiven = TRUE; + break; + case BSIM4_MOD_WWR : + mod->BSIM4wwr = value->rValue; + mod->BSIM4wwrGiven = TRUE; + break; + case BSIM4_MOD_WDWG : + mod->BSIM4wdwg = value->rValue; + mod->BSIM4wdwgGiven = TRUE; + break; + case BSIM4_MOD_WDWB : + mod->BSIM4wdwb = value->rValue; + mod->BSIM4wdwbGiven = TRUE; + break; + case BSIM4_MOD_WB0 : + mod->BSIM4wb0 = value->rValue; + mod->BSIM4wb0Given = TRUE; + break; + case BSIM4_MOD_WB1 : + mod->BSIM4wb1 = value->rValue; + mod->BSIM4wb1Given = TRUE; + break; + case BSIM4_MOD_WALPHA0 : + mod->BSIM4walpha0 = value->rValue; + mod->BSIM4walpha0Given = TRUE; + break; + case BSIM4_MOD_WALPHA1 : + mod->BSIM4walpha1 = value->rValue; + mod->BSIM4walpha1Given = TRUE; + break; + case BSIM4_MOD_WBETA0 : + mod->BSIM4wbeta0 = value->rValue; + mod->BSIM4wbeta0Given = TRUE; + break; + case BSIM4_MOD_WAGIDL : + mod->BSIM4wagidl = value->rValue; + mod->BSIM4wagidlGiven = TRUE; + break; + case BSIM4_MOD_WBGIDL : + mod->BSIM4wbgidl = value->rValue; + mod->BSIM4wbgidlGiven = TRUE; + break; + case BSIM4_MOD_WCGIDL : + mod->BSIM4wcgidl = value->rValue; + mod->BSIM4wcgidlGiven = TRUE; + break; + case BSIM4_MOD_WPHIN : + mod->BSIM4wphin = value->rValue; + mod->BSIM4wphinGiven = TRUE; + break; + case BSIM4_MOD_WEGIDL : + mod->BSIM4wegidl = value->rValue; + mod->BSIM4wegidlGiven = TRUE; + break; + case BSIM4_MOD_WAIGC : + mod->BSIM4waigc = value->rValue; + mod->BSIM4waigcGiven = TRUE; + break; + case BSIM4_MOD_WBIGC : + mod->BSIM4wbigc = value->rValue; + mod->BSIM4wbigcGiven = TRUE; + break; + case BSIM4_MOD_WCIGC : + mod->BSIM4wcigc = value->rValue; + mod->BSIM4wcigcGiven = TRUE; + break; + case BSIM4_MOD_WAIGSD : + mod->BSIM4waigsd = value->rValue; + mod->BSIM4waigsdGiven = TRUE; + break; + case BSIM4_MOD_WBIGSD : + mod->BSIM4wbigsd = value->rValue; + mod->BSIM4wbigsdGiven = TRUE; + break; + case BSIM4_MOD_WCIGSD : + mod->BSIM4wcigsd = value->rValue; + mod->BSIM4wcigsdGiven = TRUE; + break; + case BSIM4_MOD_WAIGBACC : + mod->BSIM4waigbacc = value->rValue; + mod->BSIM4waigbaccGiven = TRUE; + break; + case BSIM4_MOD_WBIGBACC : + mod->BSIM4wbigbacc = value->rValue; + mod->BSIM4wbigbaccGiven = TRUE; + break; + case BSIM4_MOD_WCIGBACC : + mod->BSIM4wcigbacc = value->rValue; + mod->BSIM4wcigbaccGiven = TRUE; + break; + case BSIM4_MOD_WAIGBINV : + mod->BSIM4waigbinv = value->rValue; + mod->BSIM4waigbinvGiven = TRUE; + break; + case BSIM4_MOD_WBIGBINV : + mod->BSIM4wbigbinv = value->rValue; + mod->BSIM4wbigbinvGiven = TRUE; + break; + case BSIM4_MOD_WCIGBINV : + mod->BSIM4wcigbinv = value->rValue; + mod->BSIM4wcigbinvGiven = TRUE; + break; + case BSIM4_MOD_WNIGC : + mod->BSIM4wnigc = value->rValue; + mod->BSIM4wnigcGiven = TRUE; + break; + case BSIM4_MOD_WNIGBINV : + mod->BSIM4wnigbinv = value->rValue; + mod->BSIM4wnigbinvGiven = TRUE; + break; + case BSIM4_MOD_WNIGBACC : + mod->BSIM4wnigbacc = value->rValue; + mod->BSIM4wnigbaccGiven = TRUE; + break; + case BSIM4_MOD_WNTOX : + mod->BSIM4wntox = value->rValue; + mod->BSIM4wntoxGiven = TRUE; + break; + case BSIM4_MOD_WEIGBINV : + mod->BSIM4weigbinv = value->rValue; + mod->BSIM4weigbinvGiven = TRUE; + break; + case BSIM4_MOD_WPIGCD : + mod->BSIM4wpigcd = value->rValue; + mod->BSIM4wpigcdGiven = TRUE; + break; + case BSIM4_MOD_WPOXEDGE : + mod->BSIM4wpoxedge = value->rValue; + mod->BSIM4wpoxedgeGiven = TRUE; + break; + case BSIM4_MOD_WXRCRG1 : + mod->BSIM4wxrcrg1 = value->rValue; + mod->BSIM4wxrcrg1Given = TRUE; + break; + case BSIM4_MOD_WXRCRG2 : + mod->BSIM4wxrcrg2 = value->rValue; + mod->BSIM4wxrcrg2Given = TRUE; + break; + case BSIM4_MOD_WEU : + mod->BSIM4weu = value->rValue; + mod->BSIM4weuGiven = TRUE; + break; + case BSIM4_MOD_WVFB : + mod->BSIM4wvfb = value->rValue; + mod->BSIM4wvfbGiven = TRUE; + break; + + case BSIM4_MOD_WCGSL : + mod->BSIM4wcgsl = value->rValue; + mod->BSIM4wcgslGiven = TRUE; + break; + case BSIM4_MOD_WCGDL : + mod->BSIM4wcgdl = value->rValue; + mod->BSIM4wcgdlGiven = TRUE; + break; + case BSIM4_MOD_WCKAPPAS : + mod->BSIM4wckappas = value->rValue; + mod->BSIM4wckappasGiven = TRUE; + break; + case BSIM4_MOD_WCKAPPAD : + mod->BSIM4wckappad = value->rValue; + mod->BSIM4wckappadGiven = TRUE; + break; + case BSIM4_MOD_WCF : + mod->BSIM4wcf = value->rValue; + mod->BSIM4wcfGiven = TRUE; + break; + case BSIM4_MOD_WCLC : + mod->BSIM4wclc = value->rValue; + mod->BSIM4wclcGiven = TRUE; + break; + case BSIM4_MOD_WCLE : + mod->BSIM4wcle = value->rValue; + mod->BSIM4wcleGiven = TRUE; + break; + case BSIM4_MOD_WVFBCV : + mod->BSIM4wvfbcv = value->rValue; + mod->BSIM4wvfbcvGiven = TRUE; + break; + case BSIM4_MOD_WACDE : + mod->BSIM4wacde = value->rValue; + mod->BSIM4wacdeGiven = TRUE; + break; + case BSIM4_MOD_WMOIN : + mod->BSIM4wmoin = value->rValue; + mod->BSIM4wmoinGiven = TRUE; + break; + case BSIM4_MOD_WNOFF : + mod->BSIM4wnoff = value->rValue; + mod->BSIM4wnoffGiven = TRUE; + break; + case BSIM4_MOD_WVOFFCV : + mod->BSIM4wvoffcv = value->rValue; + mod->BSIM4wvoffcvGiven = TRUE; + break; + + /* Cross-term dependence */ + case BSIM4_MOD_PCDSC : + mod->BSIM4pcdsc = value->rValue; + mod->BSIM4pcdscGiven = TRUE; + break; + + + case BSIM4_MOD_PCDSCB : + mod->BSIM4pcdscb = value->rValue; + mod->BSIM4pcdscbGiven = TRUE; + break; + case BSIM4_MOD_PCDSCD : + mod->BSIM4pcdscd = value->rValue; + mod->BSIM4pcdscdGiven = TRUE; + break; + case BSIM4_MOD_PCIT : + mod->BSIM4pcit = value->rValue; + mod->BSIM4pcitGiven = TRUE; + break; + case BSIM4_MOD_PNFACTOR : + mod->BSIM4pnfactor = value->rValue; + mod->BSIM4pnfactorGiven = TRUE; + break; + case BSIM4_MOD_PXJ: + mod->BSIM4pxj = value->rValue; + mod->BSIM4pxjGiven = TRUE; + break; + case BSIM4_MOD_PVSAT: + mod->BSIM4pvsat = value->rValue; + mod->BSIM4pvsatGiven = TRUE; + break; + + + case BSIM4_MOD_PA0: + mod->BSIM4pa0 = value->rValue; + mod->BSIM4pa0Given = TRUE; + break; + case BSIM4_MOD_PAGS: + mod->BSIM4pags = value->rValue; + mod->BSIM4pagsGiven = TRUE; + break; + case BSIM4_MOD_PA1: + mod->BSIM4pa1 = value->rValue; + mod->BSIM4pa1Given = TRUE; + break; + case BSIM4_MOD_PA2: + mod->BSIM4pa2 = value->rValue; + mod->BSIM4pa2Given = TRUE; + break; + case BSIM4_MOD_PAT: + mod->BSIM4pat = value->rValue; + mod->BSIM4patGiven = TRUE; + break; + case BSIM4_MOD_PKETA: + mod->BSIM4pketa = value->rValue; + mod->BSIM4pketaGiven = TRUE; + break; + case BSIM4_MOD_PNSUB: + mod->BSIM4pnsub = value->rValue; + mod->BSIM4pnsubGiven = TRUE; + break; + case BSIM4_MOD_PNDEP: + mod->BSIM4pndep = value->rValue; + mod->BSIM4pndepGiven = TRUE; + if (mod->BSIM4pndep > 1.0e20) + mod->BSIM4pndep *= 1.0e-6; + break; + case BSIM4_MOD_PNSD: + mod->BSIM4pnsd = value->rValue; + mod->BSIM4pnsdGiven = TRUE; + if (mod->BSIM4pnsd > 1.0e23) + mod->BSIM4pnsd *= 1.0e-6; + break; + case BSIM4_MOD_PNGATE: + mod->BSIM4pngate = value->rValue; + mod->BSIM4pngateGiven = TRUE; + if (mod->BSIM4pngate > 1.0e23) + mod->BSIM4pngate *= 1.0e-6; + break; + case BSIM4_MOD_PGAMMA1: + mod->BSIM4pgamma1 = value->rValue; + mod->BSIM4pgamma1Given = TRUE; + break; + case BSIM4_MOD_PGAMMA2: + mod->BSIM4pgamma2 = value->rValue; + mod->BSIM4pgamma2Given = TRUE; + break; + case BSIM4_MOD_PVBX: + mod->BSIM4pvbx = value->rValue; + mod->BSIM4pvbxGiven = TRUE; + break; + case BSIM4_MOD_PVBM: + mod->BSIM4pvbm = value->rValue; + mod->BSIM4pvbmGiven = TRUE; + break; + case BSIM4_MOD_PXT: + mod->BSIM4pxt = value->rValue; + mod->BSIM4pxtGiven = TRUE; + break; + case BSIM4_MOD_PK1: + mod->BSIM4pk1 = value->rValue; + mod->BSIM4pk1Given = TRUE; + break; + case BSIM4_MOD_PKT1: + mod->BSIM4pkt1 = value->rValue; + mod->BSIM4pkt1Given = TRUE; + break; + case BSIM4_MOD_PKT1L: + mod->BSIM4pkt1l = value->rValue; + mod->BSIM4pkt1lGiven = TRUE; + break; + case BSIM4_MOD_PKT2: + mod->BSIM4pkt2 = value->rValue; + mod->BSIM4pkt2Given = TRUE; + break; + case BSIM4_MOD_PK2: + mod->BSIM4pk2 = value->rValue; + mod->BSIM4pk2Given = TRUE; + break; + case BSIM4_MOD_PK3: + mod->BSIM4pk3 = value->rValue; + mod->BSIM4pk3Given = TRUE; + break; + case BSIM4_MOD_PK3B: + mod->BSIM4pk3b = value->rValue; + mod->BSIM4pk3bGiven = TRUE; + break; + case BSIM4_MOD_PLPE0: + mod->BSIM4plpe0 = value->rValue; + mod->BSIM4plpe0Given = TRUE; + break; + case BSIM4_MOD_PLPEB: + mod->BSIM4plpeb = value->rValue; + mod->BSIM4plpebGiven = TRUE; + break; + case BSIM4_MOD_PDVTP0: + mod->BSIM4pdvtp0 = value->rValue; + mod->BSIM4pdvtp0Given = TRUE; + break; + case BSIM4_MOD_PDVTP1: + mod->BSIM4pdvtp1 = value->rValue; + mod->BSIM4pdvtp1Given = TRUE; + break; + case BSIM4_MOD_PW0: + mod->BSIM4pw0 = value->rValue; + mod->BSIM4pw0Given = TRUE; + break; + case BSIM4_MOD_PDVT0: + mod->BSIM4pdvt0 = value->rValue; + mod->BSIM4pdvt0Given = TRUE; + break; + case BSIM4_MOD_PDVT1: + mod->BSIM4pdvt1 = value->rValue; + mod->BSIM4pdvt1Given = TRUE; + break; + case BSIM4_MOD_PDVT2: + mod->BSIM4pdvt2 = value->rValue; + mod->BSIM4pdvt2Given = TRUE; + break; + case BSIM4_MOD_PDVT0W: + mod->BSIM4pdvt0w = value->rValue; + mod->BSIM4pdvt0wGiven = TRUE; + break; + case BSIM4_MOD_PDVT1W: + mod->BSIM4pdvt1w = value->rValue; + mod->BSIM4pdvt1wGiven = TRUE; + break; + case BSIM4_MOD_PDVT2W: + mod->BSIM4pdvt2w = value->rValue; + mod->BSIM4pdvt2wGiven = TRUE; + break; + case BSIM4_MOD_PDROUT: + mod->BSIM4pdrout = value->rValue; + mod->BSIM4pdroutGiven = TRUE; + break; + case BSIM4_MOD_PDSUB: + mod->BSIM4pdsub = value->rValue; + mod->BSIM4pdsubGiven = TRUE; + break; + case BSIM4_MOD_PVTH0: + mod->BSIM4pvth0 = value->rValue; + mod->BSIM4pvth0Given = TRUE; + break; + case BSIM4_MOD_PUA: + mod->BSIM4pua = value->rValue; + mod->BSIM4puaGiven = TRUE; + break; + case BSIM4_MOD_PUA1: + mod->BSIM4pua1 = value->rValue; + mod->BSIM4pua1Given = TRUE; + break; + case BSIM4_MOD_PUB: + mod->BSIM4pub = value->rValue; + mod->BSIM4pubGiven = TRUE; + break; + case BSIM4_MOD_PUB1: + mod->BSIM4pub1 = value->rValue; + mod->BSIM4pub1Given = TRUE; + break; + case BSIM4_MOD_PUC: + mod->BSIM4puc = value->rValue; + mod->BSIM4pucGiven = TRUE; + break; + case BSIM4_MOD_PUC1: + mod->BSIM4puc1 = value->rValue; + mod->BSIM4puc1Given = TRUE; + break; + case BSIM4_MOD_PU0 : + mod->BSIM4pu0 = value->rValue; + mod->BSIM4pu0Given = TRUE; + break; + case BSIM4_MOD_PUTE : + mod->BSIM4pute = value->rValue; + mod->BSIM4puteGiven = TRUE; + break; + case BSIM4_MOD_PVOFF: + mod->BSIM4pvoff = value->rValue; + mod->BSIM4pvoffGiven = TRUE; + break; + case BSIM4_MOD_PMINV: + mod->BSIM4pminv = value->rValue; + mod->BSIM4pminvGiven = TRUE; + break; + case BSIM4_MOD_PFPROUT: + mod->BSIM4pfprout = value->rValue; + mod->BSIM4pfproutGiven = TRUE; + break; + case BSIM4_MOD_PPDITS: + mod->BSIM4ppdits = value->rValue; + mod->BSIM4ppditsGiven = TRUE; + break; + case BSIM4_MOD_PPDITSD: + mod->BSIM4ppditsd = value->rValue; + mod->BSIM4ppditsdGiven = TRUE; + break; + case BSIM4_MOD_PDELTA : + mod->BSIM4pdelta = value->rValue; + mod->BSIM4pdeltaGiven = TRUE; + break; + case BSIM4_MOD_PRDSW: + mod->BSIM4prdsw = value->rValue; + mod->BSIM4prdswGiven = TRUE; + break; + case BSIM4_MOD_PRDW: + mod->BSIM4prdw = value->rValue; + mod->BSIM4prdwGiven = TRUE; + break; + case BSIM4_MOD_PRSW: + mod->BSIM4prsw = value->rValue; + mod->BSIM4prswGiven = TRUE; + break; + case BSIM4_MOD_PPRWB: + mod->BSIM4pprwb = value->rValue; + mod->BSIM4pprwbGiven = TRUE; + break; + case BSIM4_MOD_PPRWG: + mod->BSIM4pprwg = value->rValue; + mod->BSIM4pprwgGiven = TRUE; + break; + case BSIM4_MOD_PPRT: + mod->BSIM4pprt = value->rValue; + mod->BSIM4pprtGiven = TRUE; + break; + case BSIM4_MOD_PETA0: + mod->BSIM4peta0 = value->rValue; + mod->BSIM4peta0Given = TRUE; + break; + case BSIM4_MOD_PETAB: + mod->BSIM4petab = value->rValue; + mod->BSIM4petabGiven = TRUE; + break; + case BSIM4_MOD_PPCLM: + mod->BSIM4ppclm = value->rValue; + mod->BSIM4ppclmGiven = TRUE; + break; + case BSIM4_MOD_PPDIBL1: + mod->BSIM4ppdibl1 = value->rValue; + mod->BSIM4ppdibl1Given = TRUE; + break; + case BSIM4_MOD_PPDIBL2: + mod->BSIM4ppdibl2 = value->rValue; + mod->BSIM4ppdibl2Given = TRUE; + break; + case BSIM4_MOD_PPDIBLB: + mod->BSIM4ppdiblb = value->rValue; + mod->BSIM4ppdiblbGiven = TRUE; + break; + case BSIM4_MOD_PPSCBE1: + mod->BSIM4ppscbe1 = value->rValue; + mod->BSIM4ppscbe1Given = TRUE; + break; + case BSIM4_MOD_PPSCBE2: + mod->BSIM4ppscbe2 = value->rValue; + mod->BSIM4ppscbe2Given = TRUE; + break; + case BSIM4_MOD_PPVAG: + mod->BSIM4ppvag = value->rValue; + mod->BSIM4ppvagGiven = TRUE; + break; + case BSIM4_MOD_PWR : + mod->BSIM4pwr = value->rValue; + mod->BSIM4pwrGiven = TRUE; + break; + case BSIM4_MOD_PDWG : + mod->BSIM4pdwg = value->rValue; + mod->BSIM4pdwgGiven = TRUE; + break; + case BSIM4_MOD_PDWB : + mod->BSIM4pdwb = value->rValue; + mod->BSIM4pdwbGiven = TRUE; + break; + case BSIM4_MOD_PB0 : + mod->BSIM4pb0 = value->rValue; + mod->BSIM4pb0Given = TRUE; + break; + case BSIM4_MOD_PB1 : + mod->BSIM4pb1 = value->rValue; + mod->BSIM4pb1Given = TRUE; + break; + case BSIM4_MOD_PALPHA0 : + mod->BSIM4palpha0 = value->rValue; + mod->BSIM4palpha0Given = TRUE; + break; + case BSIM4_MOD_PALPHA1 : + mod->BSIM4palpha1 = value->rValue; + mod->BSIM4palpha1Given = TRUE; + break; + case BSIM4_MOD_PBETA0 : + mod->BSIM4pbeta0 = value->rValue; + mod->BSIM4pbeta0Given = TRUE; + break; + case BSIM4_MOD_PAGIDL : + mod->BSIM4pagidl = value->rValue; + mod->BSIM4pagidlGiven = TRUE; + break; + case BSIM4_MOD_PBGIDL : + mod->BSIM4pbgidl = value->rValue; + mod->BSIM4pbgidlGiven = TRUE; + break; + case BSIM4_MOD_PCGIDL : + mod->BSIM4pcgidl = value->rValue; + mod->BSIM4pcgidlGiven = TRUE; + break; + case BSIM4_MOD_PPHIN : + mod->BSIM4pphin = value->rValue; + mod->BSIM4pphinGiven = TRUE; + break; + case BSIM4_MOD_PEGIDL : + mod->BSIM4pegidl = value->rValue; + mod->BSIM4pegidlGiven = TRUE; + break; + case BSIM4_MOD_PAIGC : + mod->BSIM4paigc = value->rValue; + mod->BSIM4paigcGiven = TRUE; + break; + case BSIM4_MOD_PBIGC : + mod->BSIM4pbigc = value->rValue; + mod->BSIM4pbigcGiven = TRUE; + break; + case BSIM4_MOD_PCIGC : + mod->BSIM4pcigc = value->rValue; + mod->BSIM4pcigcGiven = TRUE; + break; + case BSIM4_MOD_PAIGSD : + mod->BSIM4paigsd = value->rValue; + mod->BSIM4paigsdGiven = TRUE; + break; + case BSIM4_MOD_PBIGSD : + mod->BSIM4pbigsd = value->rValue; + mod->BSIM4pbigsdGiven = TRUE; + break; + case BSIM4_MOD_PCIGSD : + mod->BSIM4pcigsd = value->rValue; + mod->BSIM4pcigsdGiven = TRUE; + break; + case BSIM4_MOD_PAIGBACC : + mod->BSIM4paigbacc = value->rValue; + mod->BSIM4paigbaccGiven = TRUE; + break; + case BSIM4_MOD_PBIGBACC : + mod->BSIM4pbigbacc = value->rValue; + mod->BSIM4pbigbaccGiven = TRUE; + break; + case BSIM4_MOD_PCIGBACC : + mod->BSIM4pcigbacc = value->rValue; + mod->BSIM4pcigbaccGiven = TRUE; + break; + case BSIM4_MOD_PAIGBINV : + mod->BSIM4paigbinv = value->rValue; + mod->BSIM4paigbinvGiven = TRUE; + break; + case BSIM4_MOD_PBIGBINV : + mod->BSIM4pbigbinv = value->rValue; + mod->BSIM4pbigbinvGiven = TRUE; + break; + case BSIM4_MOD_PCIGBINV : + mod->BSIM4pcigbinv = value->rValue; + mod->BSIM4pcigbinvGiven = TRUE; + break; + case BSIM4_MOD_PNIGC : + mod->BSIM4pnigc = value->rValue; + mod->BSIM4pnigcGiven = TRUE; + break; + case BSIM4_MOD_PNIGBINV : + mod->BSIM4pnigbinv = value->rValue; + mod->BSIM4pnigbinvGiven = TRUE; + break; + case BSIM4_MOD_PNIGBACC : + mod->BSIM4pnigbacc = value->rValue; + mod->BSIM4pnigbaccGiven = TRUE; + break; + case BSIM4_MOD_PNTOX : + mod->BSIM4pntox = value->rValue; + mod->BSIM4pntoxGiven = TRUE; + break; + case BSIM4_MOD_PEIGBINV : + mod->BSIM4peigbinv = value->rValue; + mod->BSIM4peigbinvGiven = TRUE; + break; + case BSIM4_MOD_PPIGCD : + mod->BSIM4ppigcd = value->rValue; + mod->BSIM4ppigcdGiven = TRUE; + break; + case BSIM4_MOD_PPOXEDGE : + mod->BSIM4ppoxedge = value->rValue; + mod->BSIM4ppoxedgeGiven = TRUE; + break; + case BSIM4_MOD_PXRCRG1 : + mod->BSIM4pxrcrg1 = value->rValue; + mod->BSIM4pxrcrg1Given = TRUE; + break; + case BSIM4_MOD_PXRCRG2 : + mod->BSIM4pxrcrg2 = value->rValue; + mod->BSIM4pxrcrg2Given = TRUE; + break; + case BSIM4_MOD_PEU : + mod->BSIM4peu = value->rValue; + mod->BSIM4peuGiven = TRUE; + break; + case BSIM4_MOD_PVFB : + mod->BSIM4pvfb = value->rValue; + mod->BSIM4pvfbGiven = TRUE; + break; + + case BSIM4_MOD_PCGSL : + mod->BSIM4pcgsl = value->rValue; + mod->BSIM4pcgslGiven = TRUE; + break; + case BSIM4_MOD_PCGDL : + mod->BSIM4pcgdl = value->rValue; + mod->BSIM4pcgdlGiven = TRUE; + break; + case BSIM4_MOD_PCKAPPAS : + mod->BSIM4pckappas = value->rValue; + mod->BSIM4pckappasGiven = TRUE; + break; + case BSIM4_MOD_PCKAPPAD : + mod->BSIM4pckappad = value->rValue; + mod->BSIM4pckappadGiven = TRUE; + break; + case BSIM4_MOD_PCF : + mod->BSIM4pcf = value->rValue; + mod->BSIM4pcfGiven = TRUE; + break; + case BSIM4_MOD_PCLC : + mod->BSIM4pclc = value->rValue; + mod->BSIM4pclcGiven = TRUE; + break; + case BSIM4_MOD_PCLE : + mod->BSIM4pcle = value->rValue; + mod->BSIM4pcleGiven = TRUE; + break; + case BSIM4_MOD_PVFBCV : + mod->BSIM4pvfbcv = value->rValue; + mod->BSIM4pvfbcvGiven = TRUE; + break; + case BSIM4_MOD_PACDE : + mod->BSIM4pacde = value->rValue; + mod->BSIM4pacdeGiven = TRUE; + break; + case BSIM4_MOD_PMOIN : + mod->BSIM4pmoin = value->rValue; + mod->BSIM4pmoinGiven = TRUE; + break; + case BSIM4_MOD_PNOFF : + mod->BSIM4pnoff = value->rValue; + mod->BSIM4pnoffGiven = TRUE; + break; + case BSIM4_MOD_PVOFFCV : + mod->BSIM4pvoffcv = value->rValue; + mod->BSIM4pvoffcvGiven = TRUE; + break; + + case BSIM4_MOD_TNOM : + mod->BSIM4tnom = value->rValue + CONSTCtoK; + mod->BSIM4tnomGiven = TRUE; + break; + case BSIM4_MOD_CGSO : + mod->BSIM4cgso = value->rValue; + mod->BSIM4cgsoGiven = TRUE; + break; + case BSIM4_MOD_CGDO : + mod->BSIM4cgdo = value->rValue; + mod->BSIM4cgdoGiven = TRUE; + break; + case BSIM4_MOD_CGBO : + mod->BSIM4cgbo = value->rValue; + mod->BSIM4cgboGiven = TRUE; + break; + case BSIM4_MOD_XPART : + mod->BSIM4xpart = value->rValue; + mod->BSIM4xpartGiven = TRUE; + break; + case BSIM4_MOD_RSH : + mod->BSIM4sheetResistance = value->rValue; + mod->BSIM4sheetResistanceGiven = TRUE; + break; + case BSIM4_MOD_JSS : + mod->BSIM4SjctSatCurDensity = value->rValue; + mod->BSIM4SjctSatCurDensityGiven = TRUE; + break; + case BSIM4_MOD_JSWS : + mod->BSIM4SjctSidewallSatCurDensity = value->rValue; + mod->BSIM4SjctSidewallSatCurDensityGiven = TRUE; + break; + case BSIM4_MOD_JSWGS : + mod->BSIM4SjctGateSidewallSatCurDensity = value->rValue; + mod->BSIM4SjctGateSidewallSatCurDensityGiven = TRUE; + break; + case BSIM4_MOD_PBS : + mod->BSIM4SbulkJctPotential = value->rValue; + mod->BSIM4SbulkJctPotentialGiven = TRUE; + break; + case BSIM4_MOD_MJS : + mod->BSIM4SbulkJctBotGradingCoeff = value->rValue; + mod->BSIM4SbulkJctBotGradingCoeffGiven = TRUE; + break; + case BSIM4_MOD_PBSWS : + mod->BSIM4SsidewallJctPotential = value->rValue; + mod->BSIM4SsidewallJctPotentialGiven = TRUE; + break; + case BSIM4_MOD_MJSWS : + mod->BSIM4SbulkJctSideGradingCoeff = value->rValue; + mod->BSIM4SbulkJctSideGradingCoeffGiven = TRUE; + break; + case BSIM4_MOD_CJS : + mod->BSIM4SunitAreaJctCap = value->rValue; + mod->BSIM4SunitAreaJctCapGiven = TRUE; + break; + case BSIM4_MOD_CJSWS : + mod->BSIM4SunitLengthSidewallJctCap = value->rValue; + mod->BSIM4SunitLengthSidewallJctCapGiven = TRUE; + break; + case BSIM4_MOD_NJS : + mod->BSIM4SjctEmissionCoeff = value->rValue; + mod->BSIM4SjctEmissionCoeffGiven = TRUE; + break; + case BSIM4_MOD_PBSWGS : + mod->BSIM4SGatesidewallJctPotential = value->rValue; + mod->BSIM4SGatesidewallJctPotentialGiven = TRUE; + break; + case BSIM4_MOD_MJSWGS : + mod->BSIM4SbulkJctGateSideGradingCoeff = value->rValue; + mod->BSIM4SbulkJctGateSideGradingCoeffGiven = TRUE; + break; + case BSIM4_MOD_CJSWGS : + mod->BSIM4SunitLengthGateSidewallJctCap = value->rValue; + mod->BSIM4SunitLengthGateSidewallJctCapGiven = TRUE; + break; + case BSIM4_MOD_XTIS : + mod->BSIM4SjctTempExponent = value->rValue; + mod->BSIM4SjctTempExponentGiven = TRUE; + break; + case BSIM4_MOD_JSD : + mod->BSIM4DjctSatCurDensity = value->rValue; + mod->BSIM4DjctSatCurDensityGiven = TRUE; + break; + case BSIM4_MOD_JSWD : + mod->BSIM4DjctSidewallSatCurDensity = value->rValue; + mod->BSIM4DjctSidewallSatCurDensityGiven = TRUE; + break; + case BSIM4_MOD_JSWGD : + mod->BSIM4DjctGateSidewallSatCurDensity = value->rValue; + mod->BSIM4DjctGateSidewallSatCurDensityGiven = TRUE; + break; + case BSIM4_MOD_PBD : + mod->BSIM4DbulkJctPotential = value->rValue; + mod->BSIM4DbulkJctPotentialGiven = TRUE; + break; + case BSIM4_MOD_MJD : + mod->BSIM4DbulkJctBotGradingCoeff = value->rValue; + mod->BSIM4DbulkJctBotGradingCoeffGiven = TRUE; + break; + case BSIM4_MOD_PBSWD : + mod->BSIM4DsidewallJctPotential = value->rValue; + mod->BSIM4DsidewallJctPotentialGiven = TRUE; + break; + case BSIM4_MOD_MJSWD : + mod->BSIM4DbulkJctSideGradingCoeff = value->rValue; + mod->BSIM4DbulkJctSideGradingCoeffGiven = TRUE; + break; + case BSIM4_MOD_CJD : + mod->BSIM4DunitAreaJctCap = value->rValue; + mod->BSIM4DunitAreaJctCapGiven = TRUE; + break; + case BSIM4_MOD_CJSWD : + mod->BSIM4DunitLengthSidewallJctCap = value->rValue; + mod->BSIM4DunitLengthSidewallJctCapGiven = TRUE; + break; + case BSIM4_MOD_NJD : + mod->BSIM4DjctEmissionCoeff = value->rValue; + mod->BSIM4DjctEmissionCoeffGiven = TRUE; + break; + case BSIM4_MOD_PBSWGD : + mod->BSIM4DGatesidewallJctPotential = value->rValue; + mod->BSIM4DGatesidewallJctPotentialGiven = TRUE; + break; + case BSIM4_MOD_MJSWGD : + mod->BSIM4DbulkJctGateSideGradingCoeff = value->rValue; + mod->BSIM4DbulkJctGateSideGradingCoeffGiven = TRUE; + break; + case BSIM4_MOD_CJSWGD : + mod->BSIM4DunitLengthGateSidewallJctCap = value->rValue; + mod->BSIM4DunitLengthGateSidewallJctCapGiven = TRUE; + break; + case BSIM4_MOD_XTID : + mod->BSIM4DjctTempExponent = value->rValue; + mod->BSIM4DjctTempExponentGiven = TRUE; + break; + case BSIM4_MOD_LINT : + mod->BSIM4Lint = value->rValue; + mod->BSIM4LintGiven = TRUE; + break; + case BSIM4_MOD_LL : + mod->BSIM4Ll = value->rValue; + mod->BSIM4LlGiven = TRUE; + break; + case BSIM4_MOD_LLC : + mod->BSIM4Llc = value->rValue; + mod->BSIM4LlcGiven = TRUE; + break; + case BSIM4_MOD_LLN : + mod->BSIM4Lln = value->rValue; + mod->BSIM4LlnGiven = TRUE; + break; + case BSIM4_MOD_LW : + mod->BSIM4Lw = value->rValue; + mod->BSIM4LwGiven = TRUE; + break; + case BSIM4_MOD_LWC : + mod->BSIM4Lwc = value->rValue; + mod->BSIM4LwcGiven = TRUE; + break; + case BSIM4_MOD_LWN : + mod->BSIM4Lwn = value->rValue; + mod->BSIM4LwnGiven = TRUE; + break; + case BSIM4_MOD_LWL : + mod->BSIM4Lwl = value->rValue; + mod->BSIM4LwlGiven = TRUE; + break; + case BSIM4_MOD_LWLC : + mod->BSIM4Lwlc = value->rValue; + mod->BSIM4LwlcGiven = TRUE; + break; + case BSIM4_MOD_LMIN : + mod->BSIM4Lmin = value->rValue; + mod->BSIM4LminGiven = TRUE; + break; + case BSIM4_MOD_LMAX : + mod->BSIM4Lmax = value->rValue; + mod->BSIM4LmaxGiven = TRUE; + break; + case BSIM4_MOD_WINT : + mod->BSIM4Wint = value->rValue; + mod->BSIM4WintGiven = TRUE; + break; + case BSIM4_MOD_WL : + mod->BSIM4Wl = value->rValue; + mod->BSIM4WlGiven = TRUE; + break; + case BSIM4_MOD_WLC : + mod->BSIM4Wlc = value->rValue; + mod->BSIM4WlcGiven = TRUE; + break; + case BSIM4_MOD_WLN : + mod->BSIM4Wln = value->rValue; + mod->BSIM4WlnGiven = TRUE; + break; + case BSIM4_MOD_WW : + mod->BSIM4Ww = value->rValue; + mod->BSIM4WwGiven = TRUE; + break; + case BSIM4_MOD_WWC : + mod->BSIM4Wwc = value->rValue; + mod->BSIM4WwcGiven = TRUE; + break; + case BSIM4_MOD_WWN : + mod->BSIM4Wwn = value->rValue; + mod->BSIM4WwnGiven = TRUE; + break; + case BSIM4_MOD_WWL : + mod->BSIM4Wwl = value->rValue; + mod->BSIM4WwlGiven = TRUE; + break; + case BSIM4_MOD_WWLC : + mod->BSIM4Wwlc = value->rValue; + mod->BSIM4WwlcGiven = TRUE; + break; + case BSIM4_MOD_WMIN : + mod->BSIM4Wmin = value->rValue; + mod->BSIM4WminGiven = TRUE; + break; + case BSIM4_MOD_WMAX : + mod->BSIM4Wmax = value->rValue; + mod->BSIM4WmaxGiven = TRUE; + break; + + case BSIM4_MOD_NOIA : + mod->BSIM4oxideTrapDensityA = value->rValue; + mod->BSIM4oxideTrapDensityAGiven = TRUE; + break; + case BSIM4_MOD_NOIB : + mod->BSIM4oxideTrapDensityB = value->rValue; + mod->BSIM4oxideTrapDensityBGiven = TRUE; + break; + case BSIM4_MOD_NOIC : + mod->BSIM4oxideTrapDensityC = value->rValue; + mod->BSIM4oxideTrapDensityCGiven = TRUE; + break; + case BSIM4_MOD_EM : + mod->BSIM4em = value->rValue; + mod->BSIM4emGiven = TRUE; + break; + case BSIM4_MOD_EF : + mod->BSIM4ef = value->rValue; + mod->BSIM4efGiven = TRUE; + break; + case BSIM4_MOD_AF : + mod->BSIM4af = value->rValue; + mod->BSIM4afGiven = TRUE; + break; + case BSIM4_MOD_KF : + mod->BSIM4kf = value->rValue; + mod->BSIM4kfGiven = TRUE; + break; + case BSIM4_MOD_NMOS : + if(value->iValue) { + mod->BSIM4type = 1; + mod->BSIM4typeGiven = TRUE; + } + break; + case BSIM4_MOD_PMOS : + if(value->iValue) { + mod->BSIM4type = - 1; + mod->BSIM4typeGiven = TRUE; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} + + diff --git a/src/spicelib/devices/bsim4/b4noi.c b/src/spicelib/devices/bsim4/b4noi.c new file mode 100644 index 000000000..e7e8b5159 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4noi.c @@ -0,0 +1,469 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4noi.c of BSIM4.0.0. + * Authors: Weidong Liu, Xiaodong Jin, Kanyu M. Cao, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include +#include "bsim4def.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "const.h" + + +extern void NevalSrc(); +extern double Nintegrate(); + +/* + * WDL: 1/f noise model has been smoothed out and enhanced with + * bulk charge effect as well as physical N* equ. and necessary + * conversion into the SI unit system. + */ + +double +Eval1ovFNoise(Vds, model, here, freq, temp) +double Vds, freq, temp; +BSIM4model *model; +BSIM4instance *here; +{ +struct bsim4SizeDependParam *pParam; +double cd, esat, DelClm, EffFreq, N0, Nl; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, Ssi; + + pParam = here->pParam; + cd = fabs(here->BSIM4cd); + esat = 2.0 * pParam->BSIM4vsattemp / here->BSIM4ueff; + T0 = ((((Vds - here->BSIM4Vdseff) / pParam->BSIM4litl) + + model->BSIM4em) / esat); + DelClm = pParam->BSIM4litl * log (MAX(T0, N_MINLOG)); + EffFreq = pow(freq, model->BSIM4ef); + T1 = CHARGE * CHARGE * CONSTboltz * cd * temp * here->BSIM4ueff; + T2 = 1.0e10 * EffFreq * here->BSIM4Abulk * model->BSIM4coxe + * pParam->BSIM4leff * pParam->BSIM4leff; + N0 = model->BSIM4coxe * here->BSIM4Vgsteff / CHARGE; + Nl = model->BSIM4coxe * here->BSIM4Vgsteff + * (1.0 - here->BSIM4AbovVgst2Vtm * here->BSIM4Vdseff) / CHARGE; + + T3 = model->BSIM4oxideTrapDensityA + * log(MAX(((N0 + here->BSIM4nstar) / (Nl + here->BSIM4nstar)), N_MINLOG)); + T4 = model->BSIM4oxideTrapDensityB * (N0 - Nl); + T5 = model->BSIM4oxideTrapDensityC * 0.5 * (N0 * N0 - Nl * Nl); + + T6 = CONSTboltz * temp * cd * cd; + T7 = 1.0e10 * EffFreq * pParam->BSIM4leff + * pParam->BSIM4leff * pParam->BSIM4weff; + T8 = model->BSIM4oxideTrapDensityA + model->BSIM4oxideTrapDensityB * Nl + + model->BSIM4oxideTrapDensityC * Nl * Nl; + T9 = (Nl + here->BSIM4nstar) * (Nl + here->BSIM4nstar); + Ssi = T1 / T2 * (T3 + T4 + T5) + T6 / T7 * DelClm * T8 / T9; + return Ssi; +} + + +int +BSIM4noise (mode, operation, inModel, ckt, data, OnDens) +int mode, operation; +GENmodel *inModel; +CKTcircuit *ckt; +register Ndata *data; +double *OnDens; +{ +register BSIM4model *model = (BSIM4model *)inModel; +register BSIM4instance *here; +struct bsim4SizeDependParam *pParam; +char name[N_MXVLNTH]; +double tempOnoise; +double tempInoise; +double noizDens[BSIM4NSRCS]; +double lnNdens[BSIM4NSRCS]; + +double N0, Nl; +double T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13; +double Vds, n, ExpArg, Ssi, Swi; +double tmp, gdpr, gspr, npart_theta, npart_beta, igsquare; + +int error, i; + + /* define the names of the noise sources */ + static char *BSIM4nNames[BSIM4NSRCS] = + { /* Note that we have to keep the order */ + ".rd", /* noise due to rd */ + ".rs", /* noise due to rs */ + ".rg", /* noise due to rgeltd */ + ".rbps", /* noise due to rbps */ + ".rbpd", /* noise due to rbpd */ + ".rbpb", /* noise due to rbpb */ + ".rbsb", /* noise due to rbsb */ + ".rbdb", /* noise due to rbdb */ + ".id", /* noise due to id */ + ".1overf", /* flicker (1/f) noise */ + ".igs", /* shot noise due to IGS */ + ".igd", /* shot noise due to IGD */ + ".igb", /* shot noise due to IGB */ + "" /* total transistor noise */ + }; + + for (; model != NULL; model = model->BSIM4nextModel) + { for (here = model->BSIM4instances; here != NULL; + here = here->BSIM4nextInstance) + { pParam = here->pParam; + switch (operation) + { case N_OPEN: + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { switch (mode) + { case N_DENS: + for (i = 0; i < BSIM4NSRCS; i++) + { (void) sprintf(name, "onoise.%s%s", + here->BSIM4name, + BSIM4nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + } + break; + case INT_NOIZ: + for (i = 0; i < BSIM4NSRCS; i++) + { (void) sprintf(name, "onoise_total.%s%s", + here->BSIM4name, + BSIM4nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **) NULL); + /* we've added one more plot */ + + (void) sprintf(name, "inoise_total.%s%s", + here->BSIM4name, + BSIM4nNames[i]); + data->namelist = (IFuid *) trealloc( + (char *) data->namelist, + (data->numPlots + 1) + * sizeof(IFuid)); + if (!data->namelist) + return(E_NOMEM); + (*(SPfrontEnd->IFnewUid)) (ckt, + &(data->namelist[data->numPlots++]), + (IFuid) NULL, name, UID_OTHER, + (void **)NULL); + /* we've added one more plot */ + } + break; + } + } + break; + case N_CALC: + switch (mode) + { case N_DENS: + if (model->BSIM4tnoiMod == 0) + { if (model->BSIM4rdsMod == 0) + { gspr = here->BSIM4sourceConductance; + gdpr = here->BSIM4drainConductance; + if (here->BSIM4grdsw > 0.0) + tmp = 1.0 / here->BSIM4grdsw; /* tmp used below */ + else + tmp = 0.0; + } + else + { gspr = here->BSIM4gstot; + gdpr = here->BSIM4gdtot; + tmp = 0.0; + } + } + else + { T5 = here->BSIM4Vgsteff / here->BSIM4EsatL; + T5 *= T5; + npart_beta = 0.577 * (1.0 + T5 + * model->BSIM4tnoia * pParam->BSIM4leff); + npart_theta = 0.37 * (1.0 + T5 + * model->BSIM4tnoib * pParam->BSIM4leff); + + if (model->BSIM4rdsMod == 0) + { gspr = here->BSIM4sourceConductance; + gdpr = here->BSIM4drainConductance; + } + else + { gspr = here->BSIM4gstot; + gdpr = here->BSIM4gdtot; + } + + if ((*(ckt->CKTstates[0] + here->BSIM4vds)) >= 0.0) + gspr = gspr * (1.0 + npart_theta * npart_theta * gspr + / here->BSIM4IdovVds); + else + gdpr = gdpr * (1.0 + npart_theta * npart_theta * gdpr + / here->BSIM4IdovVds); + } + + NevalSrc(&noizDens[BSIM4RDNOIZ], + &lnNdens[BSIM4RDNOIZ], ckt, THERMNOISE, + here->BSIM4dNodePrime, here->BSIM4dNode, + gdpr); + + NevalSrc(&noizDens[BSIM4RSNOIZ], + &lnNdens[BSIM4RSNOIZ], ckt, THERMNOISE, + here->BSIM4sNodePrime, here->BSIM4sNode, + gspr); + + + if ((here->BSIM4rgateMod == 1) || (here->BSIM4rgateMod == 2)) + { NevalSrc(&noizDens[BSIM4RGNOIZ], + &lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE, + here->BSIM4gNodePrime, here->BSIM4gNodeExt, + here->BSIM4grgeltd); + } + else if (here->BSIM4rgateMod == 3) + { NevalSrc(&noizDens[BSIM4RGNOIZ], + &lnNdens[BSIM4RGNOIZ], ckt, THERMNOISE, + here->BSIM4gNodeMid, here->BSIM4gNodeExt, + here->BSIM4grgeltd); + } + else + { noizDens[BSIM4RGNOIZ] = 0.0; + lnNdens[BSIM4RGNOIZ] = + log(MAX(noizDens[BSIM4RGNOIZ], N_MINLOG)); + } + + + if (here->BSIM4rbodyMod) + { NevalSrc(&noizDens[BSIM4RBPSNOIZ], + &lnNdens[BSIM4RBPSNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4sbNode, + here->BSIM4grbps); + NevalSrc(&noizDens[BSIM4RBPDNOIZ], + &lnNdens[BSIM4RBPDNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4dbNode, + here->BSIM4grbpd); + NevalSrc(&noizDens[BSIM4RBPBNOIZ], + &lnNdens[BSIM4RBPBNOIZ], ckt, THERMNOISE, + here->BSIM4bNodePrime, here->BSIM4bNode, + here->BSIM4grbpb); + NevalSrc(&noizDens[BSIM4RBSBNOIZ], + &lnNdens[BSIM4RBSBNOIZ], ckt, THERMNOISE, + here->BSIM4bNode, here->BSIM4sbNode, + here->BSIM4grbsb); + NevalSrc(&noizDens[BSIM4RBDBNOIZ], + &lnNdens[BSIM4RBDBNOIZ], ckt, THERMNOISE, + here->BSIM4bNode, here->BSIM4dbNode, + here->BSIM4grbdb); + } + else + { noizDens[BSIM4RBPSNOIZ] = noizDens[BSIM4RBPDNOIZ] = 0.0; + noizDens[BSIM4RBPBNOIZ] = 0.0; + noizDens[BSIM4RBSBNOIZ] = noizDens[BSIM4RBDBNOIZ] = 0.0; + lnNdens[BSIM4RBPSNOIZ] = + log(MAX(noizDens[BSIM4RBPSNOIZ], N_MINLOG)); + lnNdens[BSIM4RBPDNOIZ] = + log(MAX(noizDens[BSIM4RBPDNOIZ], N_MINLOG)); + lnNdens[BSIM4RBPBNOIZ] = + log(MAX(noizDens[BSIM4RBPBNOIZ], N_MINLOG)); + lnNdens[BSIM4RBSBNOIZ] = + log(MAX(noizDens[BSIM4RBSBNOIZ], N_MINLOG)); + lnNdens[BSIM4RBDBNOIZ] = + log(MAX(noizDens[BSIM4RBDBNOIZ], N_MINLOG)); + } + + + switch(model->BSIM4tnoiMod) + { case 0: + T0 = here->BSIM4ueff * fabs(here->BSIM4qinv); + T1 = T0 * tmp + pParam->BSIM4leff + * pParam->BSIM4leff; + NevalSrc(&noizDens[BSIM4IDNOIZ], + &lnNdens[BSIM4IDNOIZ], ckt, + THERMNOISE, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, + (T0 / T1) * model->BSIM4ntnoi); + break; + case 1: + T0 = here->BSIM4gm + here->BSIM4gmbs + here->BSIM4gds; + T0 *= T0; + igsquare = npart_theta * npart_theta * T0 / here->BSIM4IdovVds; + T1 = npart_beta * (here->BSIM4gm + + here->BSIM4gmbs) + here->BSIM4gds; + T2 = T1 * T1 / here->BSIM4IdovVds; + NevalSrc(&noizDens[BSIM4IDNOIZ], + &lnNdens[BSIM4IDNOIZ], ckt, + THERMNOISE, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, (T2 - igsquare)); + break; + } + + NevalSrc(&noizDens[BSIM4FLNOIZ], (double*) NULL, + ckt, N_GAIN, here->BSIM4dNodePrime, + here->BSIM4sNodePrime, (double) 0.0); + + switch(model->BSIM4fnoiMod) + { case 0: + noizDens[BSIM4FLNOIZ] *= model->BSIM4kf + * exp(model->BSIM4af + * log(MAX(fabs(here->BSIM4cd), + N_MINLOG))) + / (pow(data->freq, model->BSIM4ef) + * pParam->BSIM4leff + * pParam->BSIM4leff + * model->BSIM4coxe); + break; + case 1: + Vds = *(ckt->CKTstates[0] + here->BSIM4vds); + if (Vds < 0.0) + Vds = -Vds; + + Ssi = Eval1ovFNoise(Vds, model, here, + data->freq, ckt->CKTtemp); + T10 = model->BSIM4oxideTrapDensityA + * CONSTboltz * ckt->CKTtemp; + T11 = pParam->BSIM4weff * pParam->BSIM4leff + * pow(data->freq, model->BSIM4ef) * 1.0e10 + * here->BSIM4nstar * here->BSIM4nstar; + Swi = T10 / T11 * here->BSIM4cd + * here->BSIM4cd; + T1 = Swi + Ssi; + if (T1 > 0.0) + noizDens[BSIM4FLNOIZ] *= (Ssi * Swi) / T1; + else + noizDens[BSIM4FLNOIZ] *= 0.0; + break; + } + + lnNdens[BSIM4FLNOIZ] = + log(MAX(noizDens[BSIM4FLNOIZ], N_MINLOG)); + + + NevalSrc(&noizDens[BSIM4IGSNOIZ], + &lnNdens[BSIM4IGSNOIZ], ckt, SHOTNOISE, + here->BSIM4gNodePrime, here->BSIM4sNodePrime, + (here->BSIM4Igs + here->BSIM4Igcs)); + NevalSrc(&noizDens[BSIM4IGDNOIZ], + &lnNdens[BSIM4IGDNOIZ], ckt, SHOTNOISE, + here->BSIM4gNodePrime, here->BSIM4dNodePrime, + (here->BSIM4Igd + here->BSIM4Igcd)); + + NevalSrc(&noizDens[BSIM4IGBNOIZ], + &lnNdens[BSIM4IGBNOIZ], ckt, SHOTNOISE, + here->BSIM4gNodePrime, here->BSIM4bNodePrime, + here->BSIM4Igb); + + + noizDens[BSIM4TOTNOIZ] = noizDens[BSIM4RDNOIZ] + + noizDens[BSIM4RSNOIZ] + noizDens[BSIM4RGNOIZ] + + noizDens[BSIM4RBPSNOIZ] + noizDens[BSIM4RBPDNOIZ] + + noizDens[BSIM4RBPBNOIZ] + + noizDens[BSIM4RBSBNOIZ] + noizDens[BSIM4RBDBNOIZ] + + noizDens[BSIM4IDNOIZ] + noizDens[BSIM4FLNOIZ] + + noizDens[BSIM4IGSNOIZ] + noizDens[BSIM4IGDNOIZ] + + noizDens[BSIM4IGBNOIZ]; + lnNdens[BSIM4TOTNOIZ] = + log(MAX(noizDens[BSIM4TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[BSIM4TOTNOIZ]; + + if (data->delFreq == 0.0) + { /* if we haven't done any previous + integration, we need to initialize our + "history" variables. + */ + + for (i = 0; i < BSIM4NSRCS; i++) + { here->BSIM4nVar[LNLSTDENS][i] = + lnNdens[i]; + } + + /* clear out our integration variables + if it's the first pass + */ + if (data->freq == + ((NOISEAN*) ckt->CKTcurJob)->NstartFreq) + { for (i = 0; i < BSIM4NSRCS; i++) + { here->BSIM4nVar[OUTNOIZ][i] = 0.0; + here->BSIM4nVar[INNOIZ][i] = 0.0; + } + } + } + else + { /* data->delFreq != 0.0, + we have to integrate. + */ + for (i = 0; i < BSIM4NSRCS; i++) + { if (i != BSIM4TOTNOIZ) + { tempOnoise = Nintegrate(noizDens[i], + lnNdens[i], + here->BSIM4nVar[LNLSTDENS][i], + data); + tempInoise = Nintegrate(noizDens[i] + * data->GainSqInv, lnNdens[i] + + data->lnGainInv, + here->BSIM4nVar[LNLSTDENS][i] + + data->lnGainInv, data); + here->BSIM4nVar[LNLSTDENS][i] = + lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*) + ckt->CKTcurJob)->NStpsSm != 0) + { here->BSIM4nVar[OUTNOIZ][i] + += tempOnoise; + here->BSIM4nVar[OUTNOIZ][BSIM4TOTNOIZ] + += tempOnoise; + here->BSIM4nVar[INNOIZ][i] + += tempInoise; + here->BSIM4nVar[INNOIZ][BSIM4TOTNOIZ] + += tempInoise; + } + } + } + } + if (data->prtSummary) + { for (i = 0; i < BSIM4NSRCS; i++) + { /* print a summary report */ + data->outpVector[data->outNumber++] + = noizDens[i]; + } + } + break; + case INT_NOIZ: + /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) + { for (i = 0; i < BSIM4NSRCS; i++) + { data->outpVector[data->outNumber++] + = here->BSIM4nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] + = here->BSIM4nVar[INNOIZ][i]; + } + } + break; + } + break; + case N_CLOSE: + /* do nothing, the main calling routine will close */ + return (OK); + break; /* the plots */ + } /* switch (operation) */ + } /* for here */ + } /* for model */ + + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4par.c b/src/spicelib/devices/bsim4/b4par.c new file mode 100644 index 000000000..486a5c2b8 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4par.c @@ -0,0 +1,145 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4par.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "bsim4def.h" +#include "sperror.h" + + +int +BSIM4param(param,value,inst,select) +int param; +IFvalue *value; +GENinstance *inst; +IFvalue *select; +{ + BSIM4instance *here = (BSIM4instance*)inst; + switch(param) + { case BSIM4_W: + here->BSIM4w = value->rValue; + here->BSIM4wGiven = TRUE; + break; + case BSIM4_L: + here->BSIM4l = value->rValue; + here->BSIM4lGiven = TRUE; + break; + case BSIM4_NF: + here->BSIM4nf = value->rValue; + here->BSIM4nfGiven = TRUE; + break; + case BSIM4_MIN: + here->BSIM4min = value->iValue; + here->BSIM4minGiven = TRUE; + break; + case BSIM4_AS: + here->BSIM4sourceArea = value->rValue; + here->BSIM4sourceAreaGiven = TRUE; + break; + case BSIM4_AD: + here->BSIM4drainArea = value->rValue; + here->BSIM4drainAreaGiven = TRUE; + break; + case BSIM4_PS: + here->BSIM4sourcePerimeter = value->rValue; + here->BSIM4sourcePerimeterGiven = TRUE; + break; + case BSIM4_PD: + here->BSIM4drainPerimeter = value->rValue; + here->BSIM4drainPerimeterGiven = TRUE; + break; + case BSIM4_NRS: + here->BSIM4sourceSquares = value->rValue; + here->BSIM4sourceSquaresGiven = TRUE; + break; + case BSIM4_NRD: + here->BSIM4drainSquares = value->rValue; + here->BSIM4drainSquaresGiven = TRUE; + break; + case BSIM4_OFF: + here->BSIM4off = value->iValue; + break; + case BSIM4_RBSB: + here->BSIM4rbsb = value->rValue; + here->BSIM4rbsbGiven = TRUE; + break; + case BSIM4_RBDB: + here->BSIM4rbdb = value->rValue; + here->BSIM4rbdbGiven = TRUE; + break; + case BSIM4_RBPB: + here->BSIM4rbpb = value->rValue; + here->BSIM4rbpbGiven = TRUE; + break; + case BSIM4_RBPS: + here->BSIM4rbps = value->rValue; + here->BSIM4rbpsGiven = TRUE; + break; + case BSIM4_RBPD: + here->BSIM4rbpd = value->rValue; + here->BSIM4rbpdGiven = TRUE; + break; + case BSIM4_TRNQSMOD: + here->BSIM4trnqsMod = value->iValue; + here->BSIM4trnqsModGiven = TRUE; + break; + case BSIM4_ACNQSMOD: + here->BSIM4acnqsMod = value->iValue; + here->BSIM4acnqsModGiven = TRUE; + break; + case BSIM4_RBODYMOD: + here->BSIM4rbodyMod = value->iValue; + here->BSIM4rbodyModGiven = TRUE; + break; + case BSIM4_RGATEMOD: + here->BSIM4rgateMod = value->iValue; + here->BSIM4rgateModGiven = TRUE; + break; + case BSIM4_GEOMOD: + here->BSIM4geoMod = value->iValue; + here->BSIM4geoModGiven = TRUE; + break; + case BSIM4_RGEOMOD: + here->BSIM4rgeoMod = value->iValue; + here->BSIM4rgeoModGiven = TRUE; + break; + case BSIM4_IC_VDS: + here->BSIM4icVDS = value->rValue; + here->BSIM4icVDSGiven = TRUE; + break; + case BSIM4_IC_VGS: + here->BSIM4icVGS = value->rValue; + here->BSIM4icVGSGiven = TRUE; + break; + case BSIM4_IC_VBS: + here->BSIM4icVBS = value->rValue; + here->BSIM4icVBSGiven = TRUE; + break; + case BSIM4_IC: + switch(value->v.numValue) + { case 3: + here->BSIM4icVBS = *(value->v.vec.rVec+2); + here->BSIM4icVBSGiven = TRUE; + case 2: + here->BSIM4icVGS = *(value->v.vec.rVec+1); + here->BSIM4icVGSGiven = TRUE; + case 1: + here->BSIM4icVDS = *(value->v.vec.rVec); + here->BSIM4icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4pzld.c b/src/spicelib/devices/bsim4/b4pzld.c new file mode 100644 index 000000000..3b6495a19 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4pzld.c @@ -0,0 +1,729 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4pzld.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "bsim4def.h" + + +int +BSIM4pzLoad(inModel,ckt,s) +GENmodel *inModel; +register CKTcircuit *ckt; +register SPcomplex *s; +{ +register BSIM4model *model = (BSIM4model*)inModel; +register BSIM4instance *here; + +double gjbd, gjbs, geltd, gcrg, gcrgg, gcrgd, gcrgs, gcrgb; +double xcggb, xcgdb, xcgsb, xcgbb, xcbgb, xcbdb, xcbsb, xcbbb; +double xcdgb, xcddb, xcdsb, xcdbb, xcsgb, xcsdb, xcssb, xcsbb; +double gds, gbd, gbs, capbd, capbs, FwdSum, RevSum, Gm, Gmbs; +double gstot, gstotd, gstotg, gstots, gstotb, gspr; +double gdtot, gdtotd, gdtotg, gdtots, gdtotb, gdpr; +double gIstotg, gIstotd, gIstots, gIstotb; +double gIdtotg, gIdtotd, gIdtots, gIdtotb; +double gIbtotg, gIbtotd, gIbtots, gIbtotb; +double gIgtotg, gIgtotd, gIgtots, gIgtotb; +double cgso, cgdo, cgbo; +double xcdbdb, xcsbsb, xcgmgmb, xcgmdb, xcgmsb, xcdgmb, xcsgmb; +double xcgmbb, xcbgmb; +double dxpart, sxpart, xgtg, xgtd, xgts, xgtb, xcqgb, xcqdb, xcqsb, xcqbb; +double gbspsp, gbbdp, gbbsp, gbspg, gbspb; +double gbspdp, gbdpdp, gbdpg, gbdpb, gbdpsp; +double ddxpart_dVd, ddxpart_dVg, ddxpart_dVb, ddxpart_dVs; +double dsxpart_dVd, dsxpart_dVg, dsxpart_dVb, dsxpart_dVs; +double T0, T1, CoxWL, qcheq, Cdg, Cdd, Cds, Cdb, Csg, Csd, Css, Csb; +double ScalingFactor = 1.0e-9; +struct bsim4SizeDependParam *pParam; + + for (; model != NULL; model = model->BSIM4nextModel) + { for (here = model->BSIM4instances; here!= NULL; + here = here->BSIM4nextInstance) + { if (here->BSIM4owner != ARCHme) continue; + pParam = here->pParam; + capbd = here->BSIM4capbd; + capbs = here->BSIM4capbs; + cgso = here->BSIM4cgso; + cgdo = here->BSIM4cgdo; + cgbo = pParam->BSIM4cgbo; + + if (here->BSIM4mode >= 0) + { Gm = here->BSIM4gm; + Gmbs = here->BSIM4gmbs; + FwdSum = Gm + Gmbs; + RevSum = 0.0; + + gbbdp = -(here->BSIM4gbds + here->BSIM4ggidld); + gbbsp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs + - here->BSIM4ggidls; + gbdpg = here->BSIM4gbgs + here->BSIM4ggidlg; + gbdpdp = here->BSIM4gbds + here->BSIM4ggidld; + gbdpb = here->BSIM4gbbs + here->BSIM4ggidlb; + gbdpsp = -(gbdpg + gbdpdp + gbdpb) + here->BSIM4ggidls; + + gbspdp = 0.0; + gbspg = 0.0; + gbspb = 0.0; + gbspsp = 0.0; + + if (model->BSIM4igcMod) + { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcsg; + gIstotd = here->BSIM4gIgcsd; + gIstots = here->BSIM4gIgss + here->BSIM4gIgcss; + gIstotb = here->BSIM4gIgcsb; + + gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcdg; + gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcdd; + gIdtots = here->BSIM4gIgcds; + gIdtotb = here->BSIM4gIgcdb; + } + else + { gIstotg = gIstotd = gIstots = gIstotb = 0.0; + gIdtotg = gIdtotd = gIdtots = gIdtotb = 0.0; + } + + if (model->BSIM4igbMod) + { gIbtotg = here->BSIM4gIgbg; + gIbtotd = here->BSIM4gIgbd; + gIbtots = here->BSIM4gIgbs; + gIbtotb = here->BSIM4gIgbb; + } + else + gIbtotg = gIbtotd = gIbtots = gIbtotb = 0.0; + + if ((model->BSIM4igcMod != 0) || (model->BSIM4igbMod != 0)) + { gIgtotg = gIstotg + gIdtotg + gIbtotg; + gIgtotd = gIstotd + gIdtotd + gIbtotd ; + gIgtots = gIstots + gIdtots + gIbtots; + gIgtotb = gIstotb + gIdtotb + gIbtotb; + } + else + gIgtotg = gIgtotd = gIgtots = gIgtotb = 0.0; + + if (here->BSIM4rgateMod == 2) + T0 = *(ckt->CKTstates[0] + here->BSIM4vges) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + else if (here->BSIM4rgateMod == 3) + T0 = *(ckt->CKTstates[0] + here->BSIM4vgms) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + if (here->BSIM4rgateMod > 1) + { gcrgd = here->BSIM4gcrgd * T0; + gcrgg = here->BSIM4gcrgg * T0; + gcrgs = here->BSIM4gcrgs * T0; + gcrgb = here->BSIM4gcrgb * T0; + gcrgg -= here->BSIM4gcrg; + gcrg = here->BSIM4gcrg; + } + else + gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + + if (here->BSIM4acnqsMod == 0) + { if (here->BSIM4rgateMod == 3) + { xcgmgmb = cgdo + cgso + pParam->BSIM4cgbo; + xcgmdb = -cgdo; + xcgmsb = -cgso; + xcgmbb = -pParam->BSIM4cgbo; + + xcdgmb = xcgmdb; + xcsgmb = xcgmsb; + xcbgmb = xcgmbb; + + xcggb = here->BSIM4cggb; + xcgdb = here->BSIM4cgdb; + xcgsb = here->BSIM4cgsb; + xcgbb = -(xcggb + xcgdb + xcgsb); + + xcdgb = here->BSIM4cdgb; + xcsgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb); + xcbgb = here->BSIM4cbgb; + } + else + { xcggb = here->BSIM4cggb + cgdo + cgso + + pParam->BSIM4cgbo; + xcgdb = here->BSIM4cgdb - cgdo; + xcgsb = here->BSIM4cgsb - cgso; + xcgbb = -(xcggb + xcgdb + xcgsb); + + xcdgb = here->BSIM4cdgb - cgdo; + xcsgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb + cgso); + xcbgb = here->BSIM4cbgb - pParam->BSIM4cgbo; + + xcdgmb = xcsgmb = xcbgmb = 0.0; + } + xcddb = here->BSIM4cddb + here->BSIM4capbd + cgdo; + xcdsb = here->BSIM4cdsb; + + xcsdb = -(here->BSIM4cgdb + here->BSIM4cbdb + + here->BSIM4cddb); + xcssb = here->BSIM4capbs + cgso - (here->BSIM4cgsb + + here->BSIM4cbsb + here->BSIM4cdsb); + + if (!here->BSIM4rbodyMod) + { xcdbb = -(xcdgb + xcddb + xcdsb + xcdgmb); + xcsbb = -(xcsgb + xcsdb + xcssb + xcsgmb); + xcbdb = here->BSIM4cbdb - here->BSIM4capbd; + xcbsb = here->BSIM4cbsb - here->BSIM4capbs; + xcdbdb = 0.0; + } + else + { xcdbb = -(here->BSIM4cddb + here->BSIM4cdgb + + here->BSIM4cdsb); + xcsbb = -(xcsgb + xcsdb + xcssb + xcsgmb) + + here->BSIM4capbs; + xcbdb = here->BSIM4cbdb; + xcbsb = here->BSIM4cbsb; + + xcdbdb = -here->BSIM4capbd; + xcsbsb = -here->BSIM4capbs; + } + xcbbb = -(xcbdb + xcbgb + xcbsb + xcbgmb); + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.6; + dxpart = 0.4; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { xcggb = xcgdb = xcgsb = xcgbb = 0.0; + xcbgb = xcbdb = xcbsb = xcbbb = 0.0; + xcdgb = xcddb = xcdsb = xcdbb = 0.0; + xcsgb = xcsdb = xcssb = xcsbb = 0.0; + + xgtg = here->BSIM4gtg; + xgtd = here->BSIM4gtd; + xgts = here->BSIM4gts; + xgtb = here->BSIM4gtb; + + xcqgb = here->BSIM4cqgb; + xcqdb = here->BSIM4cqdb; + xcqsb = here->BSIM4cqsb; + xcqbb = here->BSIM4cqbb; + + CoxWL = model->BSIM4coxe * here->pParam->BSIM4weffCV + * here->BSIM4nf * here->pParam->BSIM4leffCV; + qcheq = -(here->BSIM4qgate + here->BSIM4qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM4xpart < 0.5) + { dxpart = 0.4; + } + else if (model->BSIM4xpart > 0.5) + { dxpart = 0.0; + } + else + { dxpart = 0.5; + } + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + } + else + { dxpart = here->BSIM4qdrn / qcheq; + Cdd = here->BSIM4cddb; + Csd = -(here->BSIM4cgdb + here->BSIM4cddb + + here->BSIM4cbdb); + ddxpart_dVd = (Cdd - dxpart * (Cdd + Csd)) / qcheq; + Cdg = here->BSIM4cdgb; + Csg = -(here->BSIM4cggb + here->BSIM4cdgb + + here->BSIM4cbgb); + ddxpart_dVg = (Cdg - dxpart * (Cdg + Csg)) / qcheq; + + Cds = here->BSIM4cdsb; + Css = -(here->BSIM4cgsb + here->BSIM4cdsb + + here->BSIM4cbsb); + ddxpart_dVs = (Cds - dxpart * (Cds + Css)) / qcheq; + + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + + ddxpart_dVs); + } + sxpart = 1.0 - dxpart; + dsxpart_dVd = -ddxpart_dVd; + dsxpart_dVg = -ddxpart_dVg; + dsxpart_dVs = -ddxpart_dVs; + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + dsxpart_dVs); + } + } + else + { Gm = -here->BSIM4gm; + Gmbs = -here->BSIM4gmbs; + FwdSum = 0.0; + RevSum = -(Gm + Gmbs); + + gbbsp = -(here->BSIM4gbds + here->BSIM4ggidld); + gbbdp = here->BSIM4gbds + here->BSIM4gbgs + here->BSIM4gbbs + - here->BSIM4ggidls; + + gbdpg = 0.0; + gbdpsp = 0.0; + gbdpb = 0.0; + gbdpdp = 0.0; + + gbspg = here->BSIM4gbgs + here->BSIM4ggidlg; + gbspsp = here->BSIM4gbds + here->BSIM4ggidld; + gbspb = here->BSIM4gbbs + here->BSIM4ggidlb; + gbspdp = -(gbspg + gbspsp + gbspb) + here->BSIM4ggidls; + + if (model->BSIM4igcMod) + { gIstotg = here->BSIM4gIgsg + here->BSIM4gIgcdg; + gIstotd = here->BSIM4gIgcds; + gIstots = here->BSIM4gIgss + here->BSIM4gIgcdd; + gIstotb = here->BSIM4gIgcdb; + + gIdtotg = here->BSIM4gIgdg + here->BSIM4gIgcsg; + gIdtotd = here->BSIM4gIgdd + here->BSIM4gIgcss; + gIdtots = here->BSIM4gIgcsd; + gIdtotb = here->BSIM4gIgcsb; + } + else + { gIstotg = gIstotd = gIstots = gIstotb = 0.0; + gIdtotg = gIdtotd = gIdtots = gIdtotb = 0.0; + } + + if (model->BSIM4igbMod) + { gIbtotg = here->BSIM4gIgbg; + gIbtotd = here->BSIM4gIgbs; + gIbtots = here->BSIM4gIgbd; + gIbtotb = here->BSIM4gIgbb; + } + else + gIbtotg = gIbtotd = gIbtots = gIbtotb = 0.0; + + if ((model->BSIM4igcMod != 0) || (model->BSIM4igbMod != 0)) + { gIgtotg = gIstotg + gIdtotg + gIbtotg; + gIgtotd = gIstotd + gIdtotd + gIbtotd ; + gIgtots = gIstots + gIdtots + gIbtots; + gIgtotb = gIstotb + gIdtotb + gIbtotb; + } + else + gIgtotg = gIgtotd = gIgtots = gIgtotb = 0.0; + + if (here->BSIM4rgateMod == 2) + T0 = *(ckt->CKTstates[0] + here->BSIM4vges) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + else if (here->BSIM4rgateMod == 3) + T0 = *(ckt->CKTstates[0] + here->BSIM4vgms) + - *(ckt->CKTstates[0] + here->BSIM4vgs); + if (here->BSIM4rgateMod > 1) + { gcrgd = here->BSIM4gcrgs * T0; + gcrgg = here->BSIM4gcrgg * T0; + gcrgs = here->BSIM4gcrgd * T0; + gcrgb = here->BSIM4gcrgb * T0; + gcrgg -= here->BSIM4gcrg; + gcrg = here->BSIM4gcrg; + } + else + gcrg = gcrgd = gcrgg = gcrgs = gcrgb = 0.0; + + if (here->BSIM4acnqsMod == 0) + { if (here->BSIM4rgateMod == 3) + { xcgmgmb = cgdo + cgso + pParam->BSIM4cgbo; + xcgmdb = -cgdo; + xcgmsb = -cgso; + xcgmbb = -pParam->BSIM4cgbo; + + xcdgmb = xcgmdb; + xcsgmb = xcgmsb; + xcbgmb = xcgmbb; + + xcggb = here->BSIM4cggb; + xcgdb = here->BSIM4cgsb; + xcgsb = here->BSIM4cgdb; + xcgbb = -(xcggb + xcgdb + xcgsb); + + xcdgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb); + xcsgb = here->BSIM4cdgb; + xcbgb = here->BSIM4cbgb; + } + else + { xcggb = here->BSIM4cggb + cgdo + cgso + + pParam->BSIM4cgbo; + xcgdb = here->BSIM4cgsb - cgdo; + xcgsb = here->BSIM4cgdb - cgso; + xcgbb = -(xcggb + xcgdb + xcgsb); + + xcdgb = -(here->BSIM4cggb + here->BSIM4cbgb + + here->BSIM4cdgb + cgdo); + xcsgb = here->BSIM4cdgb - cgso; + xcbgb = here->BSIM4cbgb - pParam->BSIM4cgbo; + + xcdgmb = xcsgmb = xcbgmb = 0.0; + } + xcddb = here->BSIM4capbd + cgdo - (here->BSIM4cgsb + + here->BSIM4cbsb + here->BSIM4cdsb); + xcdsb = -(here->BSIM4cgdb + here->BSIM4cbdb + + here->BSIM4cddb); + + xcsdb = here->BSIM4cdsb; + xcssb = here->BSIM4cddb + here->BSIM4capbs + cgso; + + if (!here->BSIM4rbodyMod) + { xcdbb = -(xcdgb + xcddb + xcdsb + xcdgmb); + xcsbb = -(xcsgb + xcsdb + xcssb + xcsgmb); + xcbdb = here->BSIM4cbsb - here->BSIM4capbd; + xcbsb = here->BSIM4cbdb - here->BSIM4capbs; + xcdbdb = 0.0; + } + else + { xcdbb = -(xcdgb + xcddb + xcdsb + xcdgmb) + + here->BSIM4capbd; + xcsbb = -(here->BSIM4cddb + here->BSIM4cdgb + + here->BSIM4cdsb); + xcbdb = here->BSIM4cbsb; + xcbsb = here->BSIM4cbdb; + xcdbdb = -here->BSIM4capbd; + xcsbsb = -here->BSIM4capbs; + } + xcbbb = -(xcbgb + xcbdb + xcbsb + xcbgmb); + + xgtg = xgtd = xgts = xgtb = 0.0; + sxpart = 0.4; + dxpart = 0.6; + ddxpart_dVd = ddxpart_dVg = ddxpart_dVb + = ddxpart_dVs = 0.0; + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { xcggb = xcgdb = xcgsb = xcgbb = 0.0; + xcbgb = xcbdb = xcbsb = xcbbb = 0.0; + xcdgb = xcddb = xcdsb = xcdbb = 0.0; + xcsgb = xcsdb = xcssb = xcsbb = 0.0; + + xgtg = here->BSIM4gtg; + xgtd = here->BSIM4gts; + xgts = here->BSIM4gtd; + xgtb = here->BSIM4gtb; + + xcqgb = here->BSIM4cqgb; + xcqdb = here->BSIM4cqsb; + xcqsb = here->BSIM4cqdb; + xcqbb = here->BSIM4cqbb; + + CoxWL = model->BSIM4coxe * here->pParam->BSIM4weffCV + * here->BSIM4nf * here->pParam->BSIM4leffCV; + qcheq = -(here->BSIM4qgate + here->BSIM4qbulk); + if (fabs(qcheq) <= 1.0e-5 * CoxWL) + { if (model->BSIM4xpart < 0.5) + { sxpart = 0.4; + } + else if (model->BSIM4xpart > 0.5) + { sxpart = 0.0; + } + else + { sxpart = 0.5; + } + dsxpart_dVd = dsxpart_dVg = dsxpart_dVb + = dsxpart_dVs = 0.0; + } + else + { sxpart = here->BSIM4qdrn / qcheq; + Css = here->BSIM4cddb; + Cds = -(here->BSIM4cgdb + here->BSIM4cddb + + here->BSIM4cbdb); + dsxpart_dVs = (Css - sxpart * (Css + Cds)) / qcheq; + Csg = here->BSIM4cdgb; + Cdg = -(here->BSIM4cggb + here->BSIM4cdgb + + here->BSIM4cbgb); + dsxpart_dVg = (Csg - sxpart * (Csg + Cdg)) / qcheq; + + Csd = here->BSIM4cdsb; + Cdd = -(here->BSIM4cgsb + here->BSIM4cdsb + + here->BSIM4cbsb); + dsxpart_dVd = (Csd - sxpart * (Csd + Cdd)) / qcheq; + + dsxpart_dVb = -(dsxpart_dVd + dsxpart_dVg + + dsxpart_dVs); + } + dxpart = 1.0 - sxpart; + ddxpart_dVd = -dsxpart_dVd; + ddxpart_dVg = -dsxpart_dVg; + ddxpart_dVs = -dsxpart_dVs; + ddxpart_dVb = -(ddxpart_dVd + ddxpart_dVg + ddxpart_dVs); + } + } + + if (model->BSIM4rdsMod == 1) + { gstot = here->BSIM4gstot; + gstotd = here->BSIM4gstotd; + gstotg = here->BSIM4gstotg; + gstots = here->BSIM4gstots - gstot; + gstotb = here->BSIM4gstotb; + + gdtot = here->BSIM4gdtot; + gdtotd = here->BSIM4gdtotd - gdtot; + gdtotg = here->BSIM4gdtotg; + gdtots = here->BSIM4gdtots; + gdtotb = here->BSIM4gdtotb; + } + else + { gstot = gstotd = gstotg = gstots = gstotb = 0.0; + gdtot = gdtotd = gdtotg = gdtots = gdtotb = 0.0; + } + + + T1 = *(ckt->CKTstate0 + here->BSIM4qdef) * here->BSIM4gtau; + gds = here->BSIM4gds; + + /* + * Loading PZ matrix + */ + + if (!model->BSIM4rdsMod) + { gdpr = here->BSIM4drainConductance; + gspr = here->BSIM4sourceConductance; + } + else + gdpr = gspr = 0.0; + + if (!here->BSIM4rbodyMod) + { gjbd = here->BSIM4gbd; + gjbs = here->BSIM4gbs; + } + else + gjbd = gjbs = 0.0; + + geltd = here->BSIM4grgeltd; + + if (here->BSIM4rgateMod == 1) + { *(here->BSIM4GEgePtr) += geltd; + *(here->BSIM4GPgePtr) -= geltd; + *(here->BSIM4GEgpPtr) -= geltd; + + *(here->BSIM4GPgpPtr ) += xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += xcggb * s->imag; + *(here->BSIM4GPgpPtr) += geltd - xgtg + gIgtotg; + *(here->BSIM4GPdpPtr ) += xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += xcgdb * s->imag; + *(here->BSIM4GPdpPtr) -= xgtd - gIgtotd; + *(here->BSIM4GPspPtr ) += xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += xcgsb * s->imag; + *(here->BSIM4GPspPtr) -= xgts - gIgtots; + *(here->BSIM4GPbpPtr ) += xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += xcgbb * s->imag; + *(here->BSIM4GPbpPtr) -= xgtb - gIgtotb; + } + else if (here->BSIM4rgateMod == 2) + { *(here->BSIM4GEgePtr) += gcrg; + *(here->BSIM4GEgpPtr) += gcrgg; + *(here->BSIM4GEdpPtr) += gcrgd; + *(here->BSIM4GEspPtr) += gcrgs; + *(here->BSIM4GEbpPtr) += gcrgb; + + *(here->BSIM4GPgePtr) -= gcrg; + *(here->BSIM4GPgpPtr ) += xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += xcggb * s->imag; + *(here->BSIM4GPgpPtr) -= gcrgg + xgtg - gIgtotg; + *(here->BSIM4GPdpPtr ) += xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += xcgdb * s->imag; + *(here->BSIM4GPdpPtr) -= gcrgd + xgtd - gIgtotd; + *(here->BSIM4GPspPtr ) += xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += xcgsb * s->imag; + *(here->BSIM4GPspPtr) -= gcrgs + xgts - gIgtots; + *(here->BSIM4GPbpPtr ) += xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += xcgbb * s->imag; + *(here->BSIM4GPbpPtr) -= gcrgb + xgtb - gIgtotb; + } + else if (here->BSIM4rgateMod == 3) + { *(here->BSIM4GEgePtr) += geltd; + *(here->BSIM4GEgmPtr) -= geltd; + *(here->BSIM4GMgePtr) -= geltd; + *(here->BSIM4GMgmPtr) += geltd + gcrg; + *(here->BSIM4GMgmPtr ) += xcgmgmb * s->real; + *(here->BSIM4GMgmPtr +1) += xcgmgmb * s->imag; + + *(here->BSIM4GMdpPtr) += gcrgd; + *(here->BSIM4GMdpPtr ) += xcgmdb * s->real; + *(here->BSIM4GMdpPtr +1) += xcgmdb * s->imag; + *(here->BSIM4GMgpPtr) += gcrgg; + *(here->BSIM4GMspPtr) += gcrgs; + *(here->BSIM4GMspPtr ) += xcgmsb * s->real; + *(here->BSIM4GMspPtr +1) += xcgmsb * s->imag; + *(here->BSIM4GMbpPtr) += gcrgb; + *(here->BSIM4GMbpPtr ) += xcgmbb * s->real; + *(here->BSIM4GMbpPtr +1) += xcgmbb * s->imag; + + *(here->BSIM4DPgmPtr ) += xcdgmb * s->real; + *(here->BSIM4DPgmPtr +1) += xcdgmb * s->imag; + *(here->BSIM4GPgmPtr) -= gcrg; + *(here->BSIM4SPgmPtr ) += xcsgmb * s->real; + *(here->BSIM4SPgmPtr +1) += xcsgmb * s->imag; + *(here->BSIM4BPgmPtr ) += xcbgmb * s->real; + *(here->BSIM4BPgmPtr +1) += xcbgmb * s->imag; + + *(here->BSIM4GPgpPtr) -= gcrgg + xgtg - gIgtotg; + *(here->BSIM4GPgpPtr ) += xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += xcggb * s->imag; + *(here->BSIM4GPdpPtr) -= gcrgd + xgtd - gIgtotd; + *(here->BSIM4GPdpPtr ) += xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += xcgdb * s->imag; + *(here->BSIM4GPspPtr) -= gcrgs + xgts - gIgtots; + *(here->BSIM4GPspPtr ) += xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += xcgsb * s->imag; + *(here->BSIM4GPbpPtr) -= gcrgb + xgtb - gIgtotb; + *(here->BSIM4GPbpPtr ) += xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += xcgbb * s->imag; + } + else + { *(here->BSIM4GPdpPtr ) += xcgdb * s->real; + *(here->BSIM4GPdpPtr +1) += xcgdb * s->imag; + *(here->BSIM4GPdpPtr) -= xgtd - gIgtotd; + *(here->BSIM4GPgpPtr ) += xcggb * s->real; + *(here->BSIM4GPgpPtr +1) += xcggb * s->imag; + *(here->BSIM4GPgpPtr) -= xgtg - gIgtotg; + *(here->BSIM4GPspPtr ) += xcgsb * s->real; + *(here->BSIM4GPspPtr +1) += xcgsb * s->imag; + *(here->BSIM4GPspPtr) -= xgts - gIgtots; + *(here->BSIM4GPbpPtr ) += xcgbb * s->real; + *(here->BSIM4GPbpPtr +1) += xcgbb * s->imag; + *(here->BSIM4GPbpPtr) -= xgtb - gIgtotb; + } + + if (model->BSIM4rdsMod) + { (*(here->BSIM4DgpPtr) += gdtotg); + (*(here->BSIM4DspPtr) += gdtots); + (*(here->BSIM4DbpPtr) += gdtotb); + (*(here->BSIM4SdpPtr) += gstotd); + (*(here->BSIM4SgpPtr) += gstotg); + (*(here->BSIM4SbpPtr) += gstotb); + } + + *(here->BSIM4DPdpPtr ) += xcddb * s->real; + *(here->BSIM4DPdpPtr +1) += xcddb * s->imag; + *(here->BSIM4DPdpPtr) += gdpr + gds + here->BSIM4gbd + - gdtotd + RevSum + gbdpdp - gIdtotd + + dxpart * xgtd + T1 * ddxpart_dVd; + *(here->BSIM4DPdPtr) -= gdpr + gdtot; + *(here->BSIM4DPgpPtr ) += xcdgb * s->real; + *(here->BSIM4DPgpPtr +1) += xcdgb * s->imag; + *(here->BSIM4DPgpPtr) += Gm - gdtotg + gbdpg - gIdtotg + + T1 * ddxpart_dVg + dxpart * xgtg; + *(here->BSIM4DPspPtr ) += xcdsb * s->real; + *(here->BSIM4DPspPtr +1) += xcdsb * s->imag; + *(here->BSIM4DPspPtr) -= gds + FwdSum + gdtots - gbdpsp + gIdtots + - T1 * ddxpart_dVs - dxpart * xgts; + *(here->BSIM4DPbpPtr ) += xcdbb * s->real; + *(here->BSIM4DPbpPtr +1) += xcdbb * s->imag; + *(here->BSIM4DPbpPtr) -= gjbd + gdtotb - Gmbs - gbdpb + gIdtotb + - T1 * ddxpart_dVb - dxpart * xgtb; + + *(here->BSIM4DdpPtr) -= gdpr - gdtotd; + *(here->BSIM4DdPtr) += gdpr + gdtot; + + *(here->BSIM4SPdpPtr ) += xcsdb * s->real; + *(here->BSIM4SPdpPtr +1) += xcsdb * s->imag; + *(here->BSIM4SPdpPtr) -= gds + gstotd + RevSum - gbspdp + gIstotd + - T1 * dsxpart_dVd - sxpart * xgtd; + *(here->BSIM4SPgpPtr ) += xcsgb * s->real; + *(here->BSIM4SPgpPtr +1) += xcsgb * s->imag; + *(here->BSIM4SPgpPtr) -= Gm + gstotg - gbspg + gIstotg + - T1 * dsxpart_dVg - sxpart * xgtg; + *(here->BSIM4SPspPtr ) += xcssb * s->real; + *(here->BSIM4SPspPtr +1) += xcssb * s->imag; + *(here->BSIM4SPspPtr) += gspr + gds + here->BSIM4gbs - gIstots + - gstots + FwdSum + gbspsp + + sxpart * xgts + T1 * dsxpart_dVs; + *(here->BSIM4SPsPtr) -= gspr + gstot; + *(here->BSIM4SPbpPtr ) += xcsbb * s->real; + *(here->BSIM4SPbpPtr +1) += xcsbb * s->imag; + *(here->BSIM4SPbpPtr) -= gjbs + gstotb + Gmbs - gbspb + gIstotb + - T1 * dsxpart_dVb - sxpart * xgtb; + + *(here->BSIM4SspPtr) -= gspr - gstots; + *(here->BSIM4SsPtr) += gspr + gstot; + + *(here->BSIM4BPdpPtr ) += xcbdb * s->real; + *(here->BSIM4BPdpPtr +1) += xcbdb * s->imag; + *(here->BSIM4BPdpPtr) -= gjbd - gbbdp + gIbtotd; + *(here->BSIM4BPgpPtr ) += xcbgb * s->real; + *(here->BSIM4BPgpPtr +1) += xcbgb * s->imag; + *(here->BSIM4BPgpPtr) -= here->BSIM4gbgs + here->BSIM4ggidlg + gIbtotg; + *(here->BSIM4BPspPtr ) += xcbsb * s->real; + *(here->BSIM4BPspPtr +1) += xcbsb * s->imag; + *(here->BSIM4BPspPtr) -= gjbs - gbbsp + gIbtots; + *(here->BSIM4BPbpPtr ) += xcbbb * s->real; + *(here->BSIM4BPbpPtr +1) += xcbbb * s->imag; + *(here->BSIM4BPbpPtr) += gjbd + gjbs - here->BSIM4gbbs + - gIbtotb - here->BSIM4ggidlb; + + if (here->BSIM4rbodyMod) + { (*(here->BSIM4DPdbPtr ) += xcdbdb * s->real); + (*(here->BSIM4DPdbPtr +1) += xcdbdb * s->imag); + (*(here->BSIM4DPdbPtr) -= here->BSIM4gbd); + (*(here->BSIM4SPsbPtr ) += xcsbsb * s->real); + (*(here->BSIM4SPsbPtr +1) += xcsbsb * s->imag); + (*(here->BSIM4SPsbPtr) -= here->BSIM4gbs); + + (*(here->BSIM4DBdpPtr ) += xcdbdb * s->real); + (*(here->BSIM4DBdpPtr +1) += xcdbdb * s->imag); + (*(here->BSIM4DBdpPtr) -= here->BSIM4gbd); + (*(here->BSIM4DBdbPtr ) -= xcdbdb * s->real); + (*(here->BSIM4DBdbPtr +1) -= xcdbdb * s->imag); + (*(here->BSIM4DBdbPtr) += here->BSIM4gbd + here->BSIM4grbpd + + here->BSIM4grbdb); + (*(here->BSIM4DBbpPtr) -= here->BSIM4grbpd); + (*(here->BSIM4DBbPtr) -= here->BSIM4grbdb); + + (*(here->BSIM4BPdbPtr) -= here->BSIM4grbpd); + (*(here->BSIM4BPbPtr) -= here->BSIM4grbpb); + (*(here->BSIM4BPsbPtr) -= here->BSIM4grbps); + (*(here->BSIM4BPbpPtr) += here->BSIM4grbpd + here->BSIM4grbps + + here->BSIM4grbpb); + /* WDL: (-here->BSIM4gbbs) already added to BPbpPtr */ + + (*(here->BSIM4SBspPtr ) += xcsbsb * s->real); + (*(here->BSIM4SBspPtr +1) += xcsbsb * s->imag); + (*(here->BSIM4SBspPtr) -= here->BSIM4gbs); + (*(here->BSIM4SBbpPtr) -= here->BSIM4grbps); + (*(here->BSIM4SBbPtr) -= here->BSIM4grbsb); + (*(here->BSIM4SBsbPtr ) -= xcsbsb * s->real); + (*(here->BSIM4SBsbPtr +1) -= xcsbsb * s->imag); + (*(here->BSIM4SBsbPtr) += here->BSIM4gbs + + here->BSIM4grbps + here->BSIM4grbsb); + + (*(here->BSIM4BdbPtr) -= here->BSIM4grbdb); + (*(here->BSIM4BbpPtr) -= here->BSIM4grbpb); + (*(here->BSIM4BsbPtr) -= here->BSIM4grbsb); + (*(here->BSIM4BbPtr) += here->BSIM4grbsb + here->BSIM4grbdb + + here->BSIM4grbpb); + } + + if (here->BSIM4acnqsMod) + { *(here->BSIM4QqPtr ) += s->real * ScalingFactor; + *(here->BSIM4QqPtr +1) += s->imag * ScalingFactor; + *(here->BSIM4QgpPtr ) -= xcqgb * s->real; + *(here->BSIM4QgpPtr +1) -= xcqgb * s->imag; + *(here->BSIM4QdpPtr ) -= xcqdb * s->real; + *(here->BSIM4QdpPtr +1) -= xcqdb * s->imag; + *(here->BSIM4QbpPtr ) -= xcqbb * s->real; + *(here->BSIM4QbpPtr +1) -= xcqbb * s->imag; + *(here->BSIM4QspPtr ) -= xcqsb * s->real; + *(here->BSIM4QspPtr +1) -= xcqsb * s->imag; + + *(here->BSIM4GPqPtr) -= here->BSIM4gtau; + *(here->BSIM4DPqPtr) += dxpart * here->BSIM4gtau; + *(here->BSIM4SPqPtr) += sxpart * here->BSIM4gtau; + + *(here->BSIM4QqPtr) += here->BSIM4gtau; + *(here->BSIM4QgpPtr) += xgtg; + *(here->BSIM4QdpPtr) += xgtd; + *(here->BSIM4QbpPtr) += xgtb; + *(here->BSIM4QspPtr) += xgts; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4set.c b/src/spicelib/devices/bsim4/b4set.c new file mode 100644 index 000000000..3141dc46c --- /dev/null +++ b/src/spicelib/devices/bsim4/b4set.c @@ -0,0 +1,1616 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4set.c of BSIM4.0.0. + * Authors: Weidong Liu, Xiaodong Jin, Kanyu M. Cao, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim4def.h" +#include "const.h" +#include "sperror.h" + + +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define EPS0 8.85418e-12 +#define EPSSI 1.03594e-10 +#define PI 3.141592654 +#define Charge_q 1.60219e-19 + +int +BSIM4setup(matrix,inModel,ckt,states) +register SMPmatrix *matrix; +register GENmodel *inModel; +register CKTcircuit *ckt; +int *states; +{ +register BSIM4model *model = (BSIM4model*)inModel; +register BSIM4instance *here; +int error; +CKTnode *tmp; + +double tmp1, tmp2; + + /* loop through all the BSIM4 device models */ + for( ; model != NULL; model = model->BSIM4nextModel ) + { /* process defaults of model parameters */ + if (!model->BSIM4typeGiven) + model->BSIM4type = NMOS; + + if (!model->BSIM4mobModGiven) + model->BSIM4mobMod = 0; + else if ((model->BSIM4mobMod != 0) && (model->BSIM4mobMod != 1) + && (model->BSIM4mobMod != 2)) + { model->BSIM4mobMod = 0; + printf("Warning: mobMod has been set to its default value: 0.\n"); + } + + if (!model->BSIM4binUnitGiven) + model->BSIM4binUnit = 1; + if (!model->BSIM4paramChkGiven) + model->BSIM4paramChk = 1; + + if (!model->BSIM4dioModGiven) + model->BSIM4dioMod = 1; + else if ((model->BSIM4dioMod != 0) && (model->BSIM4dioMod != 1) + && (model->BSIM4dioMod != 2)) + { model->BSIM4dioMod = 1; + printf("Warning: dioMod has been set to its default value: 1.\n"); + } + + if (!model->BSIM4capModGiven) + model->BSIM4capMod = 2; + else if ((model->BSIM4capMod != 0) && (model->BSIM4capMod != 1) + && (model->BSIM4capMod != 2)) + { model->BSIM4capMod = 2; + printf("Warning: capMod has been set to its default value: 2.\n"); + } + + if (!model->BSIM4rdsModGiven) + model->BSIM4rdsMod = 0; + else if ((model->BSIM4rdsMod != 0) && (model->BSIM4rdsMod != 1)) + { model->BSIM4rdsMod = 0; + printf("Warning: rdsMod has been set to its default value: 0.\n"); + } + if (!model->BSIM4rbodyModGiven) + model->BSIM4rbodyMod = 0; + else if ((model->BSIM4rbodyMod != 0) && (model->BSIM4rbodyMod != 1)) + { model->BSIM4rbodyMod = 0; + printf("Warning: rbodyMod has been set to its default value: 0.\n"); + } + + if (!model->BSIM4rgateModGiven) + model->BSIM4rgateMod = 0; + else if ((model->BSIM4rgateMod != 0) && (model->BSIM4rgateMod != 1) + && (model->BSIM4rgateMod != 2) && (model->BSIM4rgateMod != 3)) + { model->BSIM4rgateMod = 0; + printf("Warning: rgateMod has been set to its default value: 0.\n"); + } + + if (!model->BSIM4perModGiven) + model->BSIM4perMod = 1; + else if ((model->BSIM4perMod != 0) && (model->BSIM4perMod != 1)) + { model->BSIM4perMod = 1; + printf("Warning: perMod has been set to its default value: 1.\n"); + } + + if (!model->BSIM4geoModGiven) + model->BSIM4geoMod = 0; + + if (!model->BSIM4fnoiModGiven) + model->BSIM4fnoiMod = 1; + else if ((model->BSIM4fnoiMod != 0) && (model->BSIM4fnoiMod != 1)) + { model->BSIM4fnoiMod = 1; + printf("Warning: fnoiMod has been set to its default value: 1.\n"); + } + if (!model->BSIM4tnoiModGiven) + model->BSIM4tnoiMod = 0; /* WDLiu: tnoiMod=1 needs to set internal S/D nodes */ + else if ((model->BSIM4tnoiMod != 0) && (model->BSIM4tnoiMod != 1)) + { model->BSIM4tnoiMod = 0; + printf("Warning: tnoiMod has been set to its default value: 0.\n"); + } + + if (!model->BSIM4trnqsModGiven) + model->BSIM4trnqsMod = 0; + else if ((model->BSIM4trnqsMod != 0) && (model->BSIM4trnqsMod != 1)) + { model->BSIM4trnqsMod = 0; + printf("Warning: trnqsMod has been set to its default value: 0.\n"); + } + if (!model->BSIM4acnqsModGiven) + model->BSIM4acnqsMod = 0; + else if ((model->BSIM4acnqsMod != 0) && (model->BSIM4acnqsMod != 1)) + { model->BSIM4acnqsMod = 0; + printf("Warning: acnqsMod has been set to its default value: 0.\n"); + } + + if (!model->BSIM4igcModGiven) + model->BSIM4igcMod = 0; + else if ((model->BSIM4igcMod != 0) && (model->BSIM4igcMod != 1)) + { model->BSIM4igcMod = 0; + printf("Warning: igcMod has been set to its default value: 0.\n"); + } + if (!model->BSIM4igbModGiven) + model->BSIM4igbMod = 0; + else if ((model->BSIM4igbMod != 0) && (model->BSIM4igbMod != 1)) + { model->BSIM4igbMod = 0; + printf("Warning: igbMod has been set to its default value: 0.\n"); + } + + if (!model->BSIM4versionGiven) + model->BSIM4version = "4.0.0"; + if (!model->BSIM4toxrefGiven) + model->BSIM4toxref = 30.0e-10; + if (!model->BSIM4toxeGiven) + model->BSIM4toxe = 30.0e-10; + if (!model->BSIM4toxpGiven) + model->BSIM4toxp = model->BSIM4toxe; + if (!model->BSIM4toxmGiven) + model->BSIM4toxm = model->BSIM4toxe; + if (!model->BSIM4dtoxGiven) + model->BSIM4dtox = 0.0; + if (!model->BSIM4epsroxGiven) + model->BSIM4epsrox = 3.9; + + if (!model->BSIM4cdscGiven) + model->BSIM4cdsc = 2.4e-4; /* unit Q/V/m^2 */ + if (!model->BSIM4cdscbGiven) + model->BSIM4cdscb = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM4cdscdGiven) + model->BSIM4cdscd = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM4citGiven) + model->BSIM4cit = 0.0; /* unit Q/V/m^2 */ + if (!model->BSIM4nfactorGiven) + model->BSIM4nfactor = 1.0; + if (!model->BSIM4xjGiven) + model->BSIM4xj = .15e-6; + if (!model->BSIM4vsatGiven) + model->BSIM4vsat = 8.0e4; /* unit m/s */ + if (!model->BSIM4atGiven) + model->BSIM4at = 3.3e4; /* unit m/s */ + if (!model->BSIM4a0Given) + model->BSIM4a0 = 1.0; + if (!model->BSIM4agsGiven) + model->BSIM4ags = 0.0; + if (!model->BSIM4a1Given) + model->BSIM4a1 = 0.0; + if (!model->BSIM4a2Given) + model->BSIM4a2 = 1.0; + if (!model->BSIM4ketaGiven) + model->BSIM4keta = -0.047; /* unit / V */ + if (!model->BSIM4nsubGiven) + model->BSIM4nsub = 6.0e16; /* unit 1/cm3 */ + if (!model->BSIM4ndepGiven) + model->BSIM4ndep = 1.7e17; /* unit 1/cm3 */ + if (!model->BSIM4nsdGiven) + model->BSIM4nsd = 1.0e20; /* unit 1/cm3 */ + if (!model->BSIM4phinGiven) + model->BSIM4phin = 0.0; /* unit V */ + if (!model->BSIM4ngateGiven) + model->BSIM4ngate = 0; /* unit 1/cm3 */ + if (!model->BSIM4vbmGiven) + model->BSIM4vbm = -3.0; + if (!model->BSIM4xtGiven) + model->BSIM4xt = 1.55e-7; + if (!model->BSIM4kt1Given) + model->BSIM4kt1 = -0.11; /* unit V */ + if (!model->BSIM4kt1lGiven) + model->BSIM4kt1l = 0.0; /* unit V*m */ + if (!model->BSIM4kt2Given) + model->BSIM4kt2 = 0.022; /* No unit */ + if (!model->BSIM4k3Given) + model->BSIM4k3 = 80.0; + if (!model->BSIM4k3bGiven) + model->BSIM4k3b = 0.0; + if (!model->BSIM4w0Given) + model->BSIM4w0 = 2.5e-6; + if (!model->BSIM4lpe0Given) + model->BSIM4lpe0 = 1.74e-7; + if (!model->BSIM4lpebGiven) + model->BSIM4lpeb = 0.0; + if (!model->BSIM4dvtp0Given) + model->BSIM4dvtp0 = 0.0; + if (!model->BSIM4dvtp1Given) + model->BSIM4dvtp1 = 0.0; + if (!model->BSIM4dvt0Given) + model->BSIM4dvt0 = 2.2; + if (!model->BSIM4dvt1Given) + model->BSIM4dvt1 = 0.53; + if (!model->BSIM4dvt2Given) + model->BSIM4dvt2 = -0.032; /* unit 1 / V */ + + if (!model->BSIM4dvt0wGiven) + model->BSIM4dvt0w = 0.0; + if (!model->BSIM4dvt1wGiven) + model->BSIM4dvt1w = 5.3e6; + if (!model->BSIM4dvt2wGiven) + model->BSIM4dvt2w = -0.032; + + if (!model->BSIM4droutGiven) + model->BSIM4drout = 0.56; + if (!model->BSIM4dsubGiven) + model->BSIM4dsub = model->BSIM4drout; + if (!model->BSIM4vth0Given) + model->BSIM4vth0 = (model->BSIM4type == NMOS) ? 0.7 : -0.7; + if (!model->BSIM4euGiven) + model->BSIM4eu = (model->BSIM4type == NMOS) ? 1.67 : 1.0;; + if (!model->BSIM4uaGiven) + model->BSIM4ua = (model->BSIM4mobMod == 2) ? 1.0e-15 : 1.0e-9; /* unit m/V */ + if (!model->BSIM4ua1Given) + model->BSIM4ua1 = 1.0e-9; /* unit m/V */ + if (!model->BSIM4ubGiven) + model->BSIM4ub = 1.0e-19; /* unit (m/V)**2 */ + if (!model->BSIM4ub1Given) + model->BSIM4ub1 = -1.0e-18; /* unit (m/V)**2 */ + if (!model->BSIM4ucGiven) + model->BSIM4uc = (model->BSIM4mobMod == 1) ? -0.0465 : -0.0465e-9; + if (!model->BSIM4uc1Given) + model->BSIM4uc1 = (model->BSIM4mobMod == 1) ? -0.056 : -0.056e-9; + if (!model->BSIM4u0Given) + model->BSIM4u0 = (model->BSIM4type == NMOS) ? 0.067 : 0.025; + if (!model->BSIM4uteGiven) + model->BSIM4ute = -1.5; + if (!model->BSIM4voffGiven) + model->BSIM4voff = -0.08; + if (!model->BSIM4vofflGiven) + model->BSIM4voffl = 0.0; + if (!model->BSIM4minvGiven) + model->BSIM4minv = 0.0; + if (!model->BSIM4fproutGiven) + model->BSIM4fprout = 0.0; + if (!model->BSIM4pditsGiven) + model->BSIM4pdits = 0.0; + if (!model->BSIM4pditsdGiven) + model->BSIM4pditsd = 0.0; + if (!model->BSIM4pditslGiven) + model->BSIM4pditsl = 0.0; + if (!model->BSIM4deltaGiven) + model->BSIM4delta = 0.01; + if (!model->BSIM4rdswminGiven) + model->BSIM4rdswmin = 0.0; + if (!model->BSIM4rdwminGiven) + model->BSIM4rdwmin = 0.0; + if (!model->BSIM4rswminGiven) + model->BSIM4rswmin = 0.0; + if (!model->BSIM4rdswGiven) + model->BSIM4rdsw = 200.0; /* in ohm*um */ + if (!model->BSIM4rdwGiven) + model->BSIM4rdw = 100.0; + if (!model->BSIM4rswGiven) + model->BSIM4rsw = 100.0; + if (!model->BSIM4prwgGiven) + model->BSIM4prwg = 1.0; /* in 1/V */ + if (!model->BSIM4prwbGiven) + model->BSIM4prwb = 0.0; + if (!model->BSIM4prtGiven) + if (!model->BSIM4prtGiven) + model->BSIM4prt = 0.0; + if (!model->BSIM4eta0Given) + model->BSIM4eta0 = 0.08; /* no unit */ + if (!model->BSIM4etabGiven) + model->BSIM4etab = -0.07; /* unit 1/V */ + if (!model->BSIM4pclmGiven) + model->BSIM4pclm = 1.3; /* no unit */ + if (!model->BSIM4pdibl1Given) + model->BSIM4pdibl1 = 0.39; /* no unit */ + if (!model->BSIM4pdibl2Given) + model->BSIM4pdibl2 = 0.0086; /* no unit */ + if (!model->BSIM4pdiblbGiven) + model->BSIM4pdiblb = 0.0; /* 1/V */ + if (!model->BSIM4pscbe1Given) + model->BSIM4pscbe1 = 4.24e8; + if (!model->BSIM4pscbe2Given) + model->BSIM4pscbe2 = 1.0e-5; + if (!model->BSIM4pvagGiven) + model->BSIM4pvag = 0.0; + if (!model->BSIM4wrGiven) + model->BSIM4wr = 1.0; + if (!model->BSIM4dwgGiven) + model->BSIM4dwg = 0.0; + if (!model->BSIM4dwbGiven) + model->BSIM4dwb = 0.0; + if (!model->BSIM4b0Given) + model->BSIM4b0 = 0.0; + if (!model->BSIM4b1Given) + model->BSIM4b1 = 0.0; + if (!model->BSIM4alpha0Given) + model->BSIM4alpha0 = 0.0; + if (!model->BSIM4alpha1Given) + model->BSIM4alpha1 = 0.0; + if (!model->BSIM4beta0Given) + model->BSIM4beta0 = 30.0; + if (!model->BSIM4agidlGiven) + model->BSIM4agidl = 0.0; + if (!model->BSIM4bgidlGiven) + model->BSIM4bgidl = 2.3e9; /* V/m */ + if (!model->BSIM4cgidlGiven) + model->BSIM4cgidl = 0.5; /* V^3 */ + if (!model->BSIM4egidlGiven) + model->BSIM4egidl = 0.8; /* V */ + if (!model->BSIM4aigcGiven) + model->BSIM4aigc = (model->BSIM4type == NMOS) ? 0.43 : 0.31; + if (!model->BSIM4bigcGiven) + model->BSIM4bigc = (model->BSIM4type == NMOS) ? 0.054 : 0.024; + if (!model->BSIM4cigcGiven) + model->BSIM4cigc = (model->BSIM4type == NMOS) ? 0.075 : 0.03; + if (!model->BSIM4aigsdGiven) + model->BSIM4aigsd = (model->BSIM4type == NMOS) ? 0.43 : 0.31; + if (!model->BSIM4bigsdGiven) + model->BSIM4bigsd = (model->BSIM4type == NMOS) ? 0.054 : 0.024; + if (!model->BSIM4cigsdGiven) + model->BSIM4cigsd = (model->BSIM4type == NMOS) ? 0.075 : 0.03; + if (!model->BSIM4aigbaccGiven) + model->BSIM4aigbacc = 0.43; + if (!model->BSIM4bigbaccGiven) + model->BSIM4bigbacc = 0.054; + if (!model->BSIM4cigbaccGiven) + model->BSIM4cigbacc = 0.075; + if (!model->BSIM4aigbinvGiven) + model->BSIM4aigbinv = 0.35; + if (!model->BSIM4bigbinvGiven) + model->BSIM4bigbinv = 0.03; + if (!model->BSIM4cigbinvGiven) + model->BSIM4cigbinv = 0.006; + if (!model->BSIM4nigcGiven) + model->BSIM4nigc = 1.0; + if (!model->BSIM4nigbinvGiven) + model->BSIM4nigbinv = 3.0; + if (!model->BSIM4nigbaccGiven) + model->BSIM4nigbacc = 1.0; + if (!model->BSIM4ntoxGiven) + model->BSIM4ntox = 1.0; + if (!model->BSIM4eigbinvGiven) + model->BSIM4eigbinv = 1.1; + if (!model->BSIM4pigcdGiven) + model->BSIM4pigcd = 1.0; + if (!model->BSIM4poxedgeGiven) + model->BSIM4poxedge = 1.0; + if (!model->BSIM4xrcrg1Given) + model->BSIM4xrcrg1 = 12.0; + if (!model->BSIM4xrcrg2Given) + model->BSIM4xrcrg2 = 1.0; + if (!model->BSIM4ijthsfwdGiven) + model->BSIM4ijthsfwd = 0.1; /* unit A */ + if (!model->BSIM4ijthdfwdGiven) + model->BSIM4ijthdfwd = model->BSIM4ijthsfwd; + if (!model->BSIM4ijthsrevGiven) + model->BSIM4ijthsrev = 0.1; /* unit A */ + if (!model->BSIM4ijthdrevGiven) + model->BSIM4ijthdrev = model->BSIM4ijthsrev; + if (!model->BSIM4tnoiaGiven) + model->BSIM4tnoia = 1.5; + if (!model->BSIM4tnoibGiven) + model->BSIM4tnoib = 3.5; + if (!model->BSIM4ntnoiGiven) + model->BSIM4ntnoi = 1.0; + + if (!model->BSIM4xjbvsGiven) + model->BSIM4xjbvs = 1.0; /* no unit */ + if (!model->BSIM4xjbvdGiven) + model->BSIM4xjbvd = model->BSIM4xjbvs; + if (!model->BSIM4bvsGiven) + model->BSIM4bvs = 10.0; /* V */ + if (!model->BSIM4bvdGiven) + model->BSIM4bvd = model->BSIM4bvs; + if (!model->BSIM4gbminGiven) + model->BSIM4gbmin = 1.0e-12; /* in mho */ + if (!model->BSIM4rbdbGiven) + model->BSIM4rbdb = 50.0; /* in ohm */ + if (!model->BSIM4rbpbGiven) + model->BSIM4rbpb = 50.0; + if (!model->BSIM4rbsbGiven) + model->BSIM4rbsb = 50.0; + if (!model->BSIM4rbpsGiven) + model->BSIM4rbps = 50.0; + if (!model->BSIM4rbpdGiven) + model->BSIM4rbpd = 50.0; + + if (!model->BSIM4cgslGiven) + model->BSIM4cgsl = 0.0; + if (!model->BSIM4cgdlGiven) + model->BSIM4cgdl = 0.0; + if (!model->BSIM4ckappasGiven) + model->BSIM4ckappas = 0.6; + if (!model->BSIM4ckappadGiven) + model->BSIM4ckappad = model->BSIM4ckappas; + if (!model->BSIM4clcGiven) + model->BSIM4clc = 0.1e-6; + if (!model->BSIM4cleGiven) + model->BSIM4cle = 0.6; + if (!model->BSIM4vfbcvGiven) + model->BSIM4vfbcv = -1.0; + if (!model->BSIM4acdeGiven) + model->BSIM4acde = 1.0; + if (!model->BSIM4moinGiven) + model->BSIM4moin = 15.0; + if (!model->BSIM4noffGiven) + model->BSIM4noff = 1.0; + if (!model->BSIM4voffcvGiven) + model->BSIM4voffcv = 0.0; + if (!model->BSIM4dmcgGiven) + model->BSIM4dmcg = 0.0; + if (!model->BSIM4dmciGiven) + model->BSIM4dmci = model->BSIM4dmcg; + if (!model->BSIM4dmdgGiven) + model->BSIM4dmdg = 0.0; + if (!model->BSIM4dmcgtGiven) + model->BSIM4dmcgt = 0.0; + if (!model->BSIM4xgwGiven) + model->BSIM4xgw = 0.0; + if (!model->BSIM4xglGiven) + model->BSIM4xgl = 0.0; + if (!model->BSIM4rshgGiven) + model->BSIM4rshg = 0.1; + if (!model->BSIM4ngconGiven) + model->BSIM4ngcon = 1.0; + if (!model->BSIM4tcjGiven) + model->BSIM4tcj = 0.0; + if (!model->BSIM4tpbGiven) + model->BSIM4tpb = 0.0; + if (!model->BSIM4tcjswGiven) + model->BSIM4tcjsw = 0.0; + if (!model->BSIM4tpbswGiven) + model->BSIM4tpbsw = 0.0; + if (!model->BSIM4tcjswgGiven) + model->BSIM4tcjswg = 0.0; + if (!model->BSIM4tpbswgGiven) + model->BSIM4tpbswg = 0.0; + + /* Length dependence */ + if (!model->BSIM4lcdscGiven) + model->BSIM4lcdsc = 0.0; + if (!model->BSIM4lcdscbGiven) + model->BSIM4lcdscb = 0.0; + if (!model->BSIM4lcdscdGiven) + model->BSIM4lcdscd = 0.0; + if (!model->BSIM4lcitGiven) + model->BSIM4lcit = 0.0; + if (!model->BSIM4lnfactorGiven) + model->BSIM4lnfactor = 0.0; + if (!model->BSIM4lxjGiven) + model->BSIM4lxj = 0.0; + if (!model->BSIM4lvsatGiven) + model->BSIM4lvsat = 0.0; + if (!model->BSIM4latGiven) + model->BSIM4lat = 0.0; + if (!model->BSIM4la0Given) + model->BSIM4la0 = 0.0; + if (!model->BSIM4lagsGiven) + model->BSIM4lags = 0.0; + if (!model->BSIM4la1Given) + model->BSIM4la1 = 0.0; + if (!model->BSIM4la2Given) + model->BSIM4la2 = 0.0; + if (!model->BSIM4lketaGiven) + model->BSIM4lketa = 0.0; + if (!model->BSIM4lnsubGiven) + model->BSIM4lnsub = 0.0; + if (!model->BSIM4lndepGiven) + model->BSIM4lndep = 0.0; + if (!model->BSIM4lnsdGiven) + model->BSIM4lnsd = 0.0; + if (!model->BSIM4lphinGiven) + model->BSIM4lphin = 0.0; + if (!model->BSIM4lngateGiven) + model->BSIM4lngate = 0.0; + if (!model->BSIM4lvbmGiven) + model->BSIM4lvbm = 0.0; + if (!model->BSIM4lxtGiven) + model->BSIM4lxt = 0.0; + if (!model->BSIM4lkt1Given) + model->BSIM4lkt1 = 0.0; + if (!model->BSIM4lkt1lGiven) + model->BSIM4lkt1l = 0.0; + if (!model->BSIM4lkt2Given) + model->BSIM4lkt2 = 0.0; + if (!model->BSIM4lk3Given) + model->BSIM4lk3 = 0.0; + if (!model->BSIM4lk3bGiven) + model->BSIM4lk3b = 0.0; + if (!model->BSIM4lw0Given) + model->BSIM4lw0 = 0.0; + if (!model->BSIM4llpe0Given) + model->BSIM4llpe0 = 0.0; + if (!model->BSIM4llpebGiven) + model->BSIM4llpeb = model->BSIM4llpe0; + if (!model->BSIM4ldvtp0Given) + model->BSIM4ldvtp0 = 0.0; + if (!model->BSIM4ldvtp1Given) + model->BSIM4ldvtp1 = 0.0; + if (!model->BSIM4ldvt0Given) + model->BSIM4ldvt0 = 0.0; + if (!model->BSIM4ldvt1Given) + model->BSIM4ldvt1 = 0.0; + if (!model->BSIM4ldvt2Given) + model->BSIM4ldvt2 = 0.0; + if (!model->BSIM4ldvt0wGiven) + model->BSIM4ldvt0w = 0.0; + if (!model->BSIM4ldvt1wGiven) + model->BSIM4ldvt1w = 0.0; + if (!model->BSIM4ldvt2wGiven) + model->BSIM4ldvt2w = 0.0; + if (!model->BSIM4ldroutGiven) + model->BSIM4ldrout = 0.0; + if (!model->BSIM4ldsubGiven) + model->BSIM4ldsub = 0.0; + if (!model->BSIM4lvth0Given) + model->BSIM4lvth0 = 0.0; + if (!model->BSIM4luaGiven) + model->BSIM4lua = 0.0; + if (!model->BSIM4lua1Given) + model->BSIM4lua1 = 0.0; + if (!model->BSIM4lubGiven) + model->BSIM4lub = 0.0; + if (!model->BSIM4lub1Given) + model->BSIM4lub1 = 0.0; + if (!model->BSIM4lucGiven) + model->BSIM4luc = 0.0; + if (!model->BSIM4luc1Given) + model->BSIM4luc1 = 0.0; + if (!model->BSIM4lu0Given) + model->BSIM4lu0 = 0.0; + if (!model->BSIM4luteGiven) + model->BSIM4lute = 0.0; + if (!model->BSIM4lvoffGiven) + model->BSIM4lvoff = 0.0; + if (!model->BSIM4lminvGiven) + model->BSIM4lminv = 0.0; + if (!model->BSIM4lfproutGiven) + model->BSIM4lfprout = 0.0; + if (!model->BSIM4lpditsGiven) + model->BSIM4lpdits = 0.0; + if (!model->BSIM4lpditsdGiven) + model->BSIM4lpditsd = 0.0; + if (!model->BSIM4ldeltaGiven) + model->BSIM4ldelta = 0.0; + if (!model->BSIM4lrdswGiven) + model->BSIM4lrdsw = 0.0; + if (!model->BSIM4lrdwGiven) + model->BSIM4lrdw = 0.0; + if (!model->BSIM4lrswGiven) + model->BSIM4lrsw = 0.0; + if (!model->BSIM4lprwbGiven) + model->BSIM4lprwb = 0.0; + if (!model->BSIM4lprwgGiven) + model->BSIM4lprwg = 0.0; + if (!model->BSIM4lprtGiven) + model->BSIM4lprt = 0.0; + if (!model->BSIM4leta0Given) + model->BSIM4leta0 = 0.0; + if (!model->BSIM4letabGiven) + model->BSIM4letab = -0.0; + if (!model->BSIM4lpclmGiven) + model->BSIM4lpclm = 0.0; + if (!model->BSIM4lpdibl1Given) + model->BSIM4lpdibl1 = 0.0; + if (!model->BSIM4lpdibl2Given) + model->BSIM4lpdibl2 = 0.0; + if (!model->BSIM4lpdiblbGiven) + model->BSIM4lpdiblb = 0.0; + if (!model->BSIM4lpscbe1Given) + model->BSIM4lpscbe1 = 0.0; + if (!model->BSIM4lpscbe2Given) + model->BSIM4lpscbe2 = 0.0; + if (!model->BSIM4lpvagGiven) + model->BSIM4lpvag = 0.0; + if (!model->BSIM4lwrGiven) + model->BSIM4lwr = 0.0; + if (!model->BSIM4ldwgGiven) + model->BSIM4ldwg = 0.0; + if (!model->BSIM4ldwbGiven) + model->BSIM4ldwb = 0.0; + if (!model->BSIM4lb0Given) + model->BSIM4lb0 = 0.0; + if (!model->BSIM4lb1Given) + model->BSIM4lb1 = 0.0; + if (!model->BSIM4lalpha0Given) + model->BSIM4lalpha0 = 0.0; + if (!model->BSIM4lalpha1Given) + model->BSIM4lalpha1 = 0.0; + if (!model->BSIM4lbeta0Given) + model->BSIM4lbeta0 = 0.0; + if (!model->BSIM4lagidlGiven) + model->BSIM4lagidl = 0.0; + if (!model->BSIM4lbgidlGiven) + model->BSIM4lbgidl = 0.0; + if (!model->BSIM4lcgidlGiven) + model->BSIM4lcgidl = 0.0; + if (!model->BSIM4legidlGiven) + model->BSIM4legidl = 0.0; + if (!model->BSIM4laigcGiven) + model->BSIM4laigc = 0.0; + if (!model->BSIM4lbigcGiven) + model->BSIM4lbigc = 0.0; + if (!model->BSIM4lcigcGiven) + model->BSIM4lcigc = 0.0; + if (!model->BSIM4laigsdGiven) + model->BSIM4laigsd = 0.0; + if (!model->BSIM4lbigsdGiven) + model->BSIM4lbigsd = 0.0; + if (!model->BSIM4lcigsdGiven) + model->BSIM4lcigsd = 0.0; + if (!model->BSIM4laigbaccGiven) + model->BSIM4laigbacc = 0.0; + if (!model->BSIM4lbigbaccGiven) + model->BSIM4lbigbacc = 0.0; + if (!model->BSIM4lcigbaccGiven) + model->BSIM4lcigbacc = 0.0; + if (!model->BSIM4laigbinvGiven) + model->BSIM4laigbinv = 0.0; + if (!model->BSIM4lbigbinvGiven) + model->BSIM4lbigbinv = 0.0; + if (!model->BSIM4lcigbinvGiven) + model->BSIM4lcigbinv = 0.0; + if (!model->BSIM4lnigcGiven) + model->BSIM4lnigc = 0.0; + if (!model->BSIM4lnigbinvGiven) + model->BSIM4lnigbinv = 0.0; + if (!model->BSIM4lnigbaccGiven) + model->BSIM4lnigbacc = 0.0; + if (!model->BSIM4lntoxGiven) + model->BSIM4lntox = 0.0; + if (!model->BSIM4leigbinvGiven) + model->BSIM4leigbinv = 0.0; + if (!model->BSIM4lpigcdGiven) + model->BSIM4lpigcd = 0.0; + if (!model->BSIM4lpoxedgeGiven) + model->BSIM4lpoxedge = 0.0; + if (!model->BSIM4lxrcrg1Given) + model->BSIM4lxrcrg1 = 0.0; + if (!model->BSIM4lxrcrg2Given) + model->BSIM4lxrcrg2 = 0.0; + if (!model->BSIM4leuGiven) + model->BSIM4leu = 0.0; + if (!model->BSIM4lvfbGiven) + model->BSIM4lvfb = 0.0; + + if (!model->BSIM4lcgslGiven) + model->BSIM4lcgsl = 0.0; + if (!model->BSIM4lcgdlGiven) + model->BSIM4lcgdl = 0.0; + if (!model->BSIM4lckappasGiven) + model->BSIM4lckappas = 0.0; + if (!model->BSIM4lckappadGiven) + model->BSIM4lckappad = 0.0; + if (!model->BSIM4lclcGiven) + model->BSIM4lclc = 0.0; + if (!model->BSIM4lcleGiven) + model->BSIM4lcle = 0.0; + if (!model->BSIM4lcfGiven) + model->BSIM4lcf = 0.0; + if (!model->BSIM4lvfbcvGiven) + model->BSIM4lvfbcv = 0.0; + if (!model->BSIM4lacdeGiven) + model->BSIM4lacde = 0.0; + if (!model->BSIM4lmoinGiven) + model->BSIM4lmoin = 0.0; + if (!model->BSIM4lnoffGiven) + model->BSIM4lnoff = 0.0; + if (!model->BSIM4lvoffcvGiven) + model->BSIM4lvoffcv = 0.0; + + /* Width dependence */ + if (!model->BSIM4wcdscGiven) + model->BSIM4wcdsc = 0.0; + if (!model->BSIM4wcdscbGiven) + model->BSIM4wcdscb = 0.0; + if (!model->BSIM4wcdscdGiven) + model->BSIM4wcdscd = 0.0; + if (!model->BSIM4wcitGiven) + model->BSIM4wcit = 0.0; + if (!model->BSIM4wnfactorGiven) + model->BSIM4wnfactor = 0.0; + if (!model->BSIM4wxjGiven) + model->BSIM4wxj = 0.0; + if (!model->BSIM4wvsatGiven) + model->BSIM4wvsat = 0.0; + if (!model->BSIM4watGiven) + model->BSIM4wat = 0.0; + if (!model->BSIM4wa0Given) + model->BSIM4wa0 = 0.0; + if (!model->BSIM4wagsGiven) + model->BSIM4wags = 0.0; + if (!model->BSIM4wa1Given) + model->BSIM4wa1 = 0.0; + if (!model->BSIM4wa2Given) + model->BSIM4wa2 = 0.0; + if (!model->BSIM4wketaGiven) + model->BSIM4wketa = 0.0; + if (!model->BSIM4wnsubGiven) + model->BSIM4wnsub = 0.0; + if (!model->BSIM4wndepGiven) + model->BSIM4wndep = 0.0; + if (!model->BSIM4wnsdGiven) + model->BSIM4wnsd = 0.0; + if (!model->BSIM4wphinGiven) + model->BSIM4wphin = 0.0; + if (!model->BSIM4wngateGiven) + model->BSIM4wngate = 0.0; + if (!model->BSIM4wvbmGiven) + model->BSIM4wvbm = 0.0; + if (!model->BSIM4wxtGiven) + model->BSIM4wxt = 0.0; + if (!model->BSIM4wkt1Given) + model->BSIM4wkt1 = 0.0; + if (!model->BSIM4wkt1lGiven) + model->BSIM4wkt1l = 0.0; + if (!model->BSIM4wkt2Given) + model->BSIM4wkt2 = 0.0; + if (!model->BSIM4wk3Given) + model->BSIM4wk3 = 0.0; + if (!model->BSIM4wk3bGiven) + model->BSIM4wk3b = 0.0; + if (!model->BSIM4ww0Given) + model->BSIM4ww0 = 0.0; + if (!model->BSIM4wlpe0Given) + model->BSIM4wlpe0 = 0.0; + if (!model->BSIM4wlpebGiven) + model->BSIM4wlpeb = model->BSIM4wlpe0; + if (!model->BSIM4wdvtp0Given) + model->BSIM4wdvtp0 = 0.0; + if (!model->BSIM4wdvtp1Given) + model->BSIM4wdvtp1 = 0.0; + if (!model->BSIM4wdvt0Given) + model->BSIM4wdvt0 = 0.0; + if (!model->BSIM4wdvt1Given) + model->BSIM4wdvt1 = 0.0; + if (!model->BSIM4wdvt2Given) + model->BSIM4wdvt2 = 0.0; + if (!model->BSIM4wdvt0wGiven) + model->BSIM4wdvt0w = 0.0; + if (!model->BSIM4wdvt1wGiven) + model->BSIM4wdvt1w = 0.0; + if (!model->BSIM4wdvt2wGiven) + model->BSIM4wdvt2w = 0.0; + if (!model->BSIM4wdroutGiven) + model->BSIM4wdrout = 0.0; + if (!model->BSIM4wdsubGiven) + model->BSIM4wdsub = 0.0; + if (!model->BSIM4wvth0Given) + model->BSIM4wvth0 = 0.0; + if (!model->BSIM4wuaGiven) + model->BSIM4wua = 0.0; + if (!model->BSIM4wua1Given) + model->BSIM4wua1 = 0.0; + if (!model->BSIM4wubGiven) + model->BSIM4wub = 0.0; + if (!model->BSIM4wub1Given) + model->BSIM4wub1 = 0.0; + if (!model->BSIM4wucGiven) + model->BSIM4wuc = 0.0; + if (!model->BSIM4wuc1Given) + model->BSIM4wuc1 = 0.0; + if (!model->BSIM4wu0Given) + model->BSIM4wu0 = 0.0; + if (!model->BSIM4wuteGiven) + model->BSIM4wute = 0.0; + if (!model->BSIM4wvoffGiven) + model->BSIM4wvoff = 0.0; + if (!model->BSIM4wminvGiven) + model->BSIM4wminv = 0.0; + if (!model->BSIM4wfproutGiven) + model->BSIM4wfprout = 0.0; + if (!model->BSIM4wpditsGiven) + model->BSIM4wpdits = 0.0; + if (!model->BSIM4wpditsdGiven) + model->BSIM4wpditsd = 0.0; + if (!model->BSIM4wdeltaGiven) + model->BSIM4wdelta = 0.0; + if (!model->BSIM4wrdswGiven) + model->BSIM4wrdsw = 0.0; + if (!model->BSIM4wrdwGiven) + model->BSIM4wrdw = 0.0; + if (!model->BSIM4wrswGiven) + model->BSIM4wrsw = 0.0; + if (!model->BSIM4wprwbGiven) + model->BSIM4wprwb = 0.0; + if (!model->BSIM4wprwgGiven) + model->BSIM4wprwg = 0.0; + if (!model->BSIM4wprtGiven) + model->BSIM4wprt = 0.0; + if (!model->BSIM4weta0Given) + model->BSIM4weta0 = 0.0; + if (!model->BSIM4wetabGiven) + model->BSIM4wetab = 0.0; + if (!model->BSIM4wpclmGiven) + model->BSIM4wpclm = 0.0; + if (!model->BSIM4wpdibl1Given) + model->BSIM4wpdibl1 = 0.0; + if (!model->BSIM4wpdibl2Given) + model->BSIM4wpdibl2 = 0.0; + if (!model->BSIM4wpdiblbGiven) + model->BSIM4wpdiblb = 0.0; + if (!model->BSIM4wpscbe1Given) + model->BSIM4wpscbe1 = 0.0; + if (!model->BSIM4wpscbe2Given) + model->BSIM4wpscbe2 = 0.0; + if (!model->BSIM4wpvagGiven) + model->BSIM4wpvag = 0.0; + if (!model->BSIM4wwrGiven) + model->BSIM4wwr = 0.0; + if (!model->BSIM4wdwgGiven) + model->BSIM4wdwg = 0.0; + if (!model->BSIM4wdwbGiven) + model->BSIM4wdwb = 0.0; + if (!model->BSIM4wb0Given) + model->BSIM4wb0 = 0.0; + if (!model->BSIM4wb1Given) + model->BSIM4wb1 = 0.0; + if (!model->BSIM4walpha0Given) + model->BSIM4walpha0 = 0.0; + if (!model->BSIM4walpha1Given) + model->BSIM4walpha1 = 0.0; + if (!model->BSIM4wbeta0Given) + model->BSIM4wbeta0 = 0.0; + if (!model->BSIM4wagidlGiven) + model->BSIM4wagidl = 0.0; + if (!model->BSIM4wbgidlGiven) + model->BSIM4wbgidl = 0.0; + if (!model->BSIM4wcgidlGiven) + model->BSIM4wcgidl = 0.0; + if (!model->BSIM4wegidlGiven) + model->BSIM4wegidl = 0.0; + if (!model->BSIM4waigcGiven) + model->BSIM4waigc = 0.0; + if (!model->BSIM4wbigcGiven) + model->BSIM4wbigc = 0.0; + if (!model->BSIM4wcigcGiven) + model->BSIM4wcigc = 0.0; + if (!model->BSIM4waigsdGiven) + model->BSIM4waigsd = 0.0; + if (!model->BSIM4wbigsdGiven) + model->BSIM4wbigsd = 0.0; + if (!model->BSIM4wcigsdGiven) + model->BSIM4wcigsd = 0.0; + if (!model->BSIM4waigbaccGiven) + model->BSIM4waigbacc = 0.0; + if (!model->BSIM4wbigbaccGiven) + model->BSIM4wbigbacc = 0.0; + if (!model->BSIM4wcigbaccGiven) + model->BSIM4wcigbacc = 0.0; + if (!model->BSIM4waigbinvGiven) + model->BSIM4waigbinv = 0.0; + if (!model->BSIM4wbigbinvGiven) + model->BSIM4wbigbinv = 0.0; + if (!model->BSIM4wcigbinvGiven) + model->BSIM4wcigbinv = 0.0; + if (!model->BSIM4wnigcGiven) + model->BSIM4wnigc = 0.0; + if (!model->BSIM4wnigbinvGiven) + model->BSIM4wnigbinv = 0.0; + if (!model->BSIM4wnigbaccGiven) + model->BSIM4wnigbacc = 0.0; + if (!model->BSIM4wntoxGiven) + model->BSIM4wntox = 0.0; + if (!model->BSIM4weigbinvGiven) + model->BSIM4weigbinv = 0.0; + if (!model->BSIM4wpigcdGiven) + model->BSIM4wpigcd = 0.0; + if (!model->BSIM4wpoxedgeGiven) + model->BSIM4wpoxedge = 0.0; + if (!model->BSIM4wxrcrg1Given) + model->BSIM4wxrcrg1 = 0.0; + if (!model->BSIM4wxrcrg2Given) + model->BSIM4wxrcrg2 = 0.0; + if (!model->BSIM4weuGiven) + model->BSIM4weu = 0.0; + if (!model->BSIM4wvfbGiven) + model->BSIM4wvfb = 0.0; + + if (!model->BSIM4wcgslGiven) + model->BSIM4wcgsl = 0.0; + if (!model->BSIM4wcgdlGiven) + model->BSIM4wcgdl = 0.0; + if (!model->BSIM4wckappasGiven) + model->BSIM4wckappas = 0.0; + if (!model->BSIM4wckappadGiven) + model->BSIM4wckappad = 0.0; + if (!model->BSIM4wcfGiven) + model->BSIM4wcf = 0.0; + if (!model->BSIM4wclcGiven) + model->BSIM4wclc = 0.0; + if (!model->BSIM4wcleGiven) + model->BSIM4wcle = 0.0; + if (!model->BSIM4wvfbcvGiven) + model->BSIM4wvfbcv = 0.0; + if (!model->BSIM4wacdeGiven) + model->BSIM4wacde = 0.0; + if (!model->BSIM4wmoinGiven) + model->BSIM4wmoin = 0.0; + if (!model->BSIM4wnoffGiven) + model->BSIM4wnoff = 0.0; + if (!model->BSIM4wvoffcvGiven) + model->BSIM4wvoffcv = 0.0; + + /* Cross-term dependence */ + if (!model->BSIM4pcdscGiven) + model->BSIM4pcdsc = 0.0; + if (!model->BSIM4pcdscbGiven) + model->BSIM4pcdscb = 0.0; + if (!model->BSIM4pcdscdGiven) + model->BSIM4pcdscd = 0.0; + if (!model->BSIM4pcitGiven) + model->BSIM4pcit = 0.0; + if (!model->BSIM4pnfactorGiven) + model->BSIM4pnfactor = 0.0; + if (!model->BSIM4pxjGiven) + model->BSIM4pxj = 0.0; + if (!model->BSIM4pvsatGiven) + model->BSIM4pvsat = 0.0; + if (!model->BSIM4patGiven) + model->BSIM4pat = 0.0; + if (!model->BSIM4pa0Given) + model->BSIM4pa0 = 0.0; + + if (!model->BSIM4pagsGiven) + model->BSIM4pags = 0.0; + if (!model->BSIM4pa1Given) + model->BSIM4pa1 = 0.0; + if (!model->BSIM4pa2Given) + model->BSIM4pa2 = 0.0; + if (!model->BSIM4pketaGiven) + model->BSIM4pketa = 0.0; + if (!model->BSIM4pnsubGiven) + model->BSIM4pnsub = 0.0; + if (!model->BSIM4pndepGiven) + model->BSIM4pndep = 0.0; + if (!model->BSIM4pnsdGiven) + model->BSIM4pnsd = 0.0; + if (!model->BSIM4pphinGiven) + model->BSIM4pphin = 0.0; + if (!model->BSIM4pngateGiven) + model->BSIM4pngate = 0.0; + if (!model->BSIM4pvbmGiven) + model->BSIM4pvbm = 0.0; + if (!model->BSIM4pxtGiven) + model->BSIM4pxt = 0.0; + if (!model->BSIM4pkt1Given) + model->BSIM4pkt1 = 0.0; + if (!model->BSIM4pkt1lGiven) + model->BSIM4pkt1l = 0.0; + if (!model->BSIM4pkt2Given) + model->BSIM4pkt2 = 0.0; + if (!model->BSIM4pk3Given) + model->BSIM4pk3 = 0.0; + if (!model->BSIM4pk3bGiven) + model->BSIM4pk3b = 0.0; + if (!model->BSIM4pw0Given) + model->BSIM4pw0 = 0.0; + if (!model->BSIM4plpe0Given) + model->BSIM4plpe0 = 0.0; + if (!model->BSIM4plpebGiven) + model->BSIM4plpeb = model->BSIM4plpe0; + if (!model->BSIM4pdvtp0Given) + model->BSIM4pdvtp0 = 0.0; + if (!model->BSIM4pdvtp1Given) + model->BSIM4pdvtp1 = 0.0; + if (!model->BSIM4pdvt0Given) + model->BSIM4pdvt0 = 0.0; + if (!model->BSIM4pdvt1Given) + model->BSIM4pdvt1 = 0.0; + if (!model->BSIM4pdvt2Given) + model->BSIM4pdvt2 = 0.0; + if (!model->BSIM4pdvt0wGiven) + model->BSIM4pdvt0w = 0.0; + if (!model->BSIM4pdvt1wGiven) + model->BSIM4pdvt1w = 0.0; + if (!model->BSIM4pdvt2wGiven) + model->BSIM4pdvt2w = 0.0; + if (!model->BSIM4pdroutGiven) + model->BSIM4pdrout = 0.0; + if (!model->BSIM4pdsubGiven) + model->BSIM4pdsub = 0.0; + if (!model->BSIM4pvth0Given) + model->BSIM4pvth0 = 0.0; + if (!model->BSIM4puaGiven) + model->BSIM4pua = 0.0; + if (!model->BSIM4pua1Given) + model->BSIM4pua1 = 0.0; + if (!model->BSIM4pubGiven) + model->BSIM4pub = 0.0; + if (!model->BSIM4pub1Given) + model->BSIM4pub1 = 0.0; + if (!model->BSIM4pucGiven) + model->BSIM4puc = 0.0; + if (!model->BSIM4puc1Given) + model->BSIM4puc1 = 0.0; + if (!model->BSIM4pu0Given) + model->BSIM4pu0 = 0.0; + if (!model->BSIM4puteGiven) + model->BSIM4pute = 0.0; + if (!model->BSIM4pvoffGiven) + model->BSIM4pvoff = 0.0; + if (!model->BSIM4pminvGiven) + model->BSIM4pminv = 0.0; + if (!model->BSIM4pfproutGiven) + model->BSIM4pfprout = 0.0; + if (!model->BSIM4ppditsGiven) + model->BSIM4ppdits = 0.0; + if (!model->BSIM4ppditsdGiven) + model->BSIM4ppditsd = 0.0; + if (!model->BSIM4pdeltaGiven) + model->BSIM4pdelta = 0.0; + if (!model->BSIM4prdswGiven) + model->BSIM4prdsw = 0.0; + if (!model->BSIM4prdwGiven) + model->BSIM4prdw = 0.0; + if (!model->BSIM4prswGiven) + model->BSIM4prsw = 0.0; + if (!model->BSIM4pprwbGiven) + model->BSIM4pprwb = 0.0; + if (!model->BSIM4pprwgGiven) + model->BSIM4pprwg = 0.0; + if (!model->BSIM4pprtGiven) + model->BSIM4pprt = 0.0; + if (!model->BSIM4peta0Given) + model->BSIM4peta0 = 0.0; + if (!model->BSIM4petabGiven) + model->BSIM4petab = 0.0; + if (!model->BSIM4ppclmGiven) + model->BSIM4ppclm = 0.0; + if (!model->BSIM4ppdibl1Given) + model->BSIM4ppdibl1 = 0.0; + if (!model->BSIM4ppdibl2Given) + model->BSIM4ppdibl2 = 0.0; + if (!model->BSIM4ppdiblbGiven) + model->BSIM4ppdiblb = 0.0; + if (!model->BSIM4ppscbe1Given) + model->BSIM4ppscbe1 = 0.0; + if (!model->BSIM4ppscbe2Given) + model->BSIM4ppscbe2 = 0.0; + if (!model->BSIM4ppvagGiven) + model->BSIM4ppvag = 0.0; + if (!model->BSIM4pwrGiven) + model->BSIM4pwr = 0.0; + if (!model->BSIM4pdwgGiven) + model->BSIM4pdwg = 0.0; + if (!model->BSIM4pdwbGiven) + model->BSIM4pdwb = 0.0; + if (!model->BSIM4pb0Given) + model->BSIM4pb0 = 0.0; + if (!model->BSIM4pb1Given) + model->BSIM4pb1 = 0.0; + if (!model->BSIM4palpha0Given) + model->BSIM4palpha0 = 0.0; + if (!model->BSIM4palpha1Given) + model->BSIM4palpha1 = 0.0; + if (!model->BSIM4pbeta0Given) + model->BSIM4pbeta0 = 0.0; + if (!model->BSIM4pagidlGiven) + model->BSIM4pagidl = 0.0; + if (!model->BSIM4pbgidlGiven) + model->BSIM4pbgidl = 0.0; + if (!model->BSIM4pcgidlGiven) + model->BSIM4pcgidl = 0.0; + if (!model->BSIM4pegidlGiven) + model->BSIM4pegidl = 0.0; + if (!model->BSIM4paigcGiven) + model->BSIM4paigc = 0.0; + if (!model->BSIM4pbigcGiven) + model->BSIM4pbigc = 0.0; + if (!model->BSIM4pcigcGiven) + model->BSIM4pcigc = 0.0; + if (!model->BSIM4paigsdGiven) + model->BSIM4paigsd = 0.0; + if (!model->BSIM4pbigsdGiven) + model->BSIM4pbigsd = 0.0; + if (!model->BSIM4pcigsdGiven) + model->BSIM4pcigsd = 0.0; + if (!model->BSIM4paigbaccGiven) + model->BSIM4paigbacc = 0.0; + if (!model->BSIM4pbigbaccGiven) + model->BSIM4pbigbacc = 0.0; + if (!model->BSIM4pcigbaccGiven) + model->BSIM4pcigbacc = 0.0; + if (!model->BSIM4paigbinvGiven) + model->BSIM4paigbinv = 0.0; + if (!model->BSIM4pbigbinvGiven) + model->BSIM4pbigbinv = 0.0; + if (!model->BSIM4pcigbinvGiven) + model->BSIM4pcigbinv = 0.0; + if (!model->BSIM4pnigcGiven) + model->BSIM4pnigc = 0.0; + if (!model->BSIM4pnigbinvGiven) + model->BSIM4pnigbinv = 0.0; + if (!model->BSIM4pnigbaccGiven) + model->BSIM4pnigbacc = 0.0; + if (!model->BSIM4pntoxGiven) + model->BSIM4pntox = 0.0; + if (!model->BSIM4peigbinvGiven) + model->BSIM4peigbinv = 0.0; + if (!model->BSIM4ppigcdGiven) + model->BSIM4ppigcd = 0.0; + if (!model->BSIM4ppoxedgeGiven) + model->BSIM4ppoxedge = 0.0; + if (!model->BSIM4pxrcrg1Given) + model->BSIM4pxrcrg1 = 0.0; + if (!model->BSIM4pxrcrg2Given) + model->BSIM4pxrcrg2 = 0.0; + if (!model->BSIM4peuGiven) + model->BSIM4peu = 0.0; + if (!model->BSIM4pvfbGiven) + model->BSIM4pvfb = 0.0; + + if (!model->BSIM4pcgslGiven) + model->BSIM4pcgsl = 0.0; + if (!model->BSIM4pcgdlGiven) + model->BSIM4pcgdl = 0.0; + if (!model->BSIM4pckappasGiven) + model->BSIM4pckappas = 0.0; + if (!model->BSIM4pckappadGiven) + model->BSIM4pckappad = 0.0; + if (!model->BSIM4pcfGiven) + model->BSIM4pcf = 0.0; + if (!model->BSIM4pclcGiven) + model->BSIM4pclc = 0.0; + if (!model->BSIM4pcleGiven) + model->BSIM4pcle = 0.0; + if (!model->BSIM4pvfbcvGiven) + model->BSIM4pvfbcv = 0.0; + if (!model->BSIM4pacdeGiven) + model->BSIM4pacde = 0.0; + if (!model->BSIM4pmoinGiven) + model->BSIM4pmoin = 0.0; + if (!model->BSIM4pnoffGiven) + model->BSIM4pnoff = 0.0; + if (!model->BSIM4pvoffcvGiven) + model->BSIM4pvoffcv = 0.0; + + /* unit degree celcius */ + if (!model->BSIM4tnomGiven) + model->BSIM4tnom = ckt->CKTnomTemp; + if (!model->BSIM4LintGiven) + model->BSIM4Lint = 0.0; + if (!model->BSIM4LlGiven) + model->BSIM4Ll = 0.0; + if (!model->BSIM4LlcGiven) + model->BSIM4Llc = model->BSIM4Ll; + if (!model->BSIM4LlnGiven) + model->BSIM4Lln = 1.0; + if (!model->BSIM4LwGiven) + model->BSIM4Lw = 0.0; + if (!model->BSIM4LwcGiven) + model->BSIM4Lwc = model->BSIM4Lw; + if (!model->BSIM4LwnGiven) + model->BSIM4Lwn = 1.0; + if (!model->BSIM4LwlGiven) + model->BSIM4Lwl = 0.0; + if (!model->BSIM4LwlcGiven) + model->BSIM4Lwlc = model->BSIM4Lwl; + if (!model->BSIM4LminGiven) + model->BSIM4Lmin = 0.0; + if (!model->BSIM4LmaxGiven) + model->BSIM4Lmax = 1.0; + if (!model->BSIM4WintGiven) + model->BSIM4Wint = 0.0; + if (!model->BSIM4WlGiven) + model->BSIM4Wl = 0.0; + if (!model->BSIM4WlcGiven) + model->BSIM4Wlc = model->BSIM4Wl; + if (!model->BSIM4WlnGiven) + model->BSIM4Wln = 1.0; + if (!model->BSIM4WwGiven) + model->BSIM4Ww = 0.0; + if (!model->BSIM4WwcGiven) + model->BSIM4Wwc = model->BSIM4Ww; + if (!model->BSIM4WwnGiven) + model->BSIM4Wwn = 1.0; + if (!model->BSIM4WwlGiven) + model->BSIM4Wwl = 0.0; + if (!model->BSIM4WwlcGiven) + model->BSIM4Wwlc = model->BSIM4Wwl; + if (!model->BSIM4WminGiven) + model->BSIM4Wmin = 0.0; + if (!model->BSIM4WmaxGiven) + model->BSIM4Wmax = 1.0; + if (!model->BSIM4dwcGiven) + model->BSIM4dwc = model->BSIM4Wint; + if (!model->BSIM4dlcGiven) + model->BSIM4dlc = model->BSIM4Lint; + if (!model->BSIM4dlcigGiven) + model->BSIM4dlcig = model->BSIM4Lint; + if (!model->BSIM4dwjGiven) + model->BSIM4dwj = model->BSIM4dwc; + if (!model->BSIM4cfGiven) + model->BSIM4cf = 2.0 * model->BSIM4epsrox * EPS0 / PI + * log(1.0 + 0.4e-6 / model->BSIM4toxe); + + if (!model->BSIM4xpartGiven) + model->BSIM4xpart = 0.0; + if (!model->BSIM4sheetResistanceGiven) + model->BSIM4sheetResistance = 0.0; + + if (!model->BSIM4SunitAreaJctCapGiven) + model->BSIM4SunitAreaJctCap = 5.0E-4; + if (!model->BSIM4DunitAreaJctCapGiven) + model->BSIM4DunitAreaJctCap = model->BSIM4SunitAreaJctCap; + if (!model->BSIM4SunitLengthSidewallJctCapGiven) + model->BSIM4SunitLengthSidewallJctCap = 5.0E-10; + if (!model->BSIM4DunitLengthSidewallJctCapGiven) + model->BSIM4DunitLengthSidewallJctCap = model->BSIM4SunitLengthSidewallJctCap; + if (!model->BSIM4SunitLengthGateSidewallJctCapGiven) + model->BSIM4SunitLengthGateSidewallJctCap = model->BSIM4SunitLengthSidewallJctCap ; + if (!model->BSIM4DunitLengthGateSidewallJctCapGiven) + model->BSIM4DunitLengthGateSidewallJctCap = model->BSIM4SunitLengthGateSidewallJctCap; + if (!model->BSIM4SjctSatCurDensityGiven) + model->BSIM4SjctSatCurDensity = 1.0E-4; + if (!model->BSIM4DjctSatCurDensityGiven) + model->BSIM4DjctSatCurDensity = model->BSIM4SjctSatCurDensity; + if (!model->BSIM4SjctSidewallSatCurDensityGiven) + model->BSIM4SjctSidewallSatCurDensity = 0.0; + if (!model->BSIM4DjctSidewallSatCurDensityGiven) + model->BSIM4DjctSidewallSatCurDensity = model->BSIM4SjctSidewallSatCurDensity; + if (!model->BSIM4SjctGateSidewallSatCurDensityGiven) + model->BSIM4SjctGateSidewallSatCurDensity = 0.0; + if (!model->BSIM4DjctGateSidewallSatCurDensityGiven) + model->BSIM4DjctGateSidewallSatCurDensity = model->BSIM4SjctGateSidewallSatCurDensity; + if (!model->BSIM4SbulkJctPotentialGiven) + model->BSIM4SbulkJctPotential = 1.0; + if (!model->BSIM4DbulkJctPotentialGiven) + model->BSIM4DbulkJctPotential = model->BSIM4SbulkJctPotential; + if (!model->BSIM4SsidewallJctPotentialGiven) + model->BSIM4SsidewallJctPotential = 1.0; + if (!model->BSIM4DsidewallJctPotentialGiven) + model->BSIM4DsidewallJctPotential = model->BSIM4SsidewallJctPotential; + if (!model->BSIM4SGatesidewallJctPotentialGiven) + model->BSIM4SGatesidewallJctPotential = model->BSIM4SsidewallJctPotential; + if (!model->BSIM4DGatesidewallJctPotentialGiven) + model->BSIM4DGatesidewallJctPotential = model->BSIM4SGatesidewallJctPotential; + if (!model->BSIM4SbulkJctBotGradingCoeffGiven) + model->BSIM4SbulkJctBotGradingCoeff = 0.5; + if (!model->BSIM4DbulkJctBotGradingCoeffGiven) + model->BSIM4DbulkJctBotGradingCoeff = model->BSIM4SbulkJctBotGradingCoeff; + if (!model->BSIM4SbulkJctSideGradingCoeffGiven) + model->BSIM4SbulkJctSideGradingCoeff = 0.33; + if (!model->BSIM4DbulkJctSideGradingCoeffGiven) + model->BSIM4DbulkJctSideGradingCoeff = model->BSIM4SbulkJctSideGradingCoeff; + if (!model->BSIM4SbulkJctGateSideGradingCoeffGiven) + model->BSIM4SbulkJctGateSideGradingCoeff = model->BSIM4SbulkJctSideGradingCoeff; + if (!model->BSIM4DbulkJctGateSideGradingCoeffGiven) + model->BSIM4DbulkJctGateSideGradingCoeff = model->BSIM4SbulkJctGateSideGradingCoeff; + if (!model->BSIM4SjctEmissionCoeffGiven) + model->BSIM4SjctEmissionCoeff = 1.0; + if (!model->BSIM4DjctEmissionCoeffGiven) + model->BSIM4DjctEmissionCoeff = model->BSIM4SjctEmissionCoeff; + if (!model->BSIM4SjctTempExponentGiven) + model->BSIM4SjctTempExponent = 3.0; + if (!model->BSIM4DjctTempExponentGiven) + model->BSIM4DjctTempExponent = model->BSIM4SjctTempExponent; + + if (!model->BSIM4oxideTrapDensityAGiven) + { if (model->BSIM4type == NMOS) + model->BSIM4oxideTrapDensityA = 6.25e41; + else + model->BSIM4oxideTrapDensityA= 6.188e40; + } + if (!model->BSIM4oxideTrapDensityBGiven) + { if (model->BSIM4type == NMOS) + model->BSIM4oxideTrapDensityB = 3.125e26; + else + model->BSIM4oxideTrapDensityB = 1.5e25; + } + if (!model->BSIM4oxideTrapDensityCGiven) + model->BSIM4oxideTrapDensityC = 8.75e9; + if (!model->BSIM4emGiven) + model->BSIM4em = 4.1e7; /* V/m */ + if (!model->BSIM4efGiven) + model->BSIM4ef = 1.0; + if (!model->BSIM4afGiven) + model->BSIM4af = 1.0; + if (!model->BSIM4kfGiven) + model->BSIM4kf = 0.0; + + /* + * End processing models and begin to loop + * through all the instances of the model + */ + + for (here = model->BSIM4instances; here != NULL ; + here=here->BSIM4nextInstance) + { + if (here->BSIM4owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->BSIM4states = *states; + *states += BSIM4numStates; + } + /* perform the parameter defaulting */ + if (!here->BSIM4lGiven) + here->BSIM4l = 5.0e-6; + if (!here->BSIM4wGiven) + here->BSIM4w = 5.0e-6; + if (!here->BSIM4nfGiven) + here->BSIM4nf = 1.0; + if (!here->BSIM4minGiven) + here->BSIM4min = 0; /* integer */ + if (!here->BSIM4icVDSGiven) + here->BSIM4icVDS = 0.0; + if (!here->BSIM4icVGSGiven) + here->BSIM4icVGS = 0.0; + if (!here->BSIM4icVBSGiven) + here->BSIM4icVBS = 0.0; + if (!here->BSIM4drainAreaGiven) + here->BSIM4drainArea = 0.0; + if (!here->BSIM4drainPerimeterGiven) + here->BSIM4drainPerimeter = 0.0; + if (!here->BSIM4drainSquaresGiven) + here->BSIM4drainSquares = 1.0; + if (!here->BSIM4sourceAreaGiven) + here->BSIM4sourceArea = 0.0; + if (!here->BSIM4sourcePerimeterGiven) + here->BSIM4sourcePerimeter = 0.0; + if (!here->BSIM4sourceSquaresGiven) + here->BSIM4sourceSquares = 1.0; + + if (!here->BSIM4rbdbGiven) + here->BSIM4rbdb = model->BSIM4rbdb; /* in ohm */ + if (!here->BSIM4rbsbGiven) + here->BSIM4rbsb = model->BSIM4rbsb; + if (!here->BSIM4rbpbGiven) + here->BSIM4rbpb = model->BSIM4rbpb; + if (!here->BSIM4rbpsGiven) + here->BSIM4rbps = model->BSIM4rbps; + if (!here->BSIM4rbpdGiven) + here->BSIM4rbpd = model->BSIM4rbpd; + + + /* Process instance model selectors, some + * may override their global counterparts + */ + if (!here->BSIM4rbodyModGiven) + here->BSIM4rbodyMod = model->BSIM4rbodyMod; + else if ((here->BSIM4rbodyMod != 0) && (here->BSIM4rbodyMod != 1)) + { here->BSIM4rbodyMod = model->BSIM4rbodyMod; + printf("Warning: rbodyMod has been set to its global value %d.\n", + model->BSIM4rbodyMod); + } + + if (!here->BSIM4rgateModGiven) + here->BSIM4rgateMod = model->BSIM4rgateMod; + else if ((here->BSIM4rgateMod != 0) && (here->BSIM4rgateMod != 1) + && (here->BSIM4rgateMod != 2) && (here->BSIM4rgateMod != 3)) + { here->BSIM4rgateMod = model->BSIM4rgateMod; + printf("Warning: rgateMod has been set to its global value %d.\n", + model->BSIM4rgateMod); + } + + if (!here->BSIM4geoModGiven) + here->BSIM4geoMod = model->BSIM4geoMod; + if (!here->BSIM4rgeoModGiven) + here->BSIM4rgeoMod = 0.0; + if (!here->BSIM4trnqsModGiven) + here->BSIM4trnqsMod = model->BSIM4trnqsMod; + else if ((here->BSIM4trnqsMod != 0) && (here->BSIM4trnqsMod != 1)) + { here->BSIM4trnqsMod = model->BSIM4trnqsMod; + printf("Warning: trnqsMod has been set to its global value %d.\n", + model->BSIM4trnqsMod); + } + + if (!here->BSIM4acnqsModGiven) + here->BSIM4acnqsMod = model->BSIM4acnqsMod; + else if ((here->BSIM4acnqsMod != 0) && (here->BSIM4acnqsMod != 1)) + { here->BSIM4acnqsMod = model->BSIM4acnqsMod; + printf("Warning: acnqsMod has been set to its global value %d.\n", + model->BSIM4acnqsMod); + } + + /* process drain series resistance */ + if (((here->BSIM4rgeoMod != 0) || (model->BSIM4rdsMod != 0) + || (model->BSIM4tnoiMod != 0)) && (here->BSIM4dNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"drain"); + if(error) return(error); + here->BSIM4dNodePrime = tmp->number; + } + else + { here->BSIM4dNodePrime = here->BSIM4dNode; + } + /* process source series resistance */ + if (((here->BSIM4rgeoMod != 0) || (model->BSIM4rdsMod != 0) + || (model->BSIM4tnoiMod != 0)) && (here->BSIM4sNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"source"); + if(error) return(error); + here->BSIM4sNodePrime = tmp->number; + } + else + here->BSIM4sNodePrime = here->BSIM4sNode; + + + if ((here->BSIM4rgateMod > 0) && (here->BSIM4gNodePrime == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"gate"); + if(error) return(error); + here->BSIM4gNodePrime = tmp->number; + if (here->BSIM4rgateMod == 1) + { if (model->BSIM4rshg <= 0.0) + printf("Warning: rshg should be positive for rgateMod = 1.\n"); + } + else if (here->BSIM4rgateMod == 2) + { if (model->BSIM4rshg <= 0.0) + printf("Warning: rshg <= 0.0 for rgateMod = 2!!!\n"); + else if (model->BSIM4xrcrg1 <= 0.0) + printf("Warning: xrcrg1 <= 0.0 for rgateMod = 2!!!\n"); + } + } + else + here->BSIM4gNodePrime = here->BSIM4gNodeExt; + + if ((here->BSIM4rgateMod == 3) && (here->BSIM4gNodeMid == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"midgate"); + if(error) return(error); + here->BSIM4gNodeMid = tmp->number; + if (model->BSIM4rshg <= 0.0) + printf("Warning: rshg should be positive for rgateMod = 3.\n"); + else if (model->BSIM4xrcrg1 <= 0.0) + printf("Warning: xrcrg1 should be positive for rgateMod = 3.\n"); + } + else + here->BSIM4gNodeMid = here->BSIM4gNodeExt; + + + /* internal body nodes for body resistance model */ + if (here->BSIM4rbodyMod) + { if (here->BSIM4dbNode == 0) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"dbody"); + if(error) return(error); + here->BSIM4dbNode = tmp->number; + } + if (here->BSIM4bNodePrime == 0) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"body"); + if(error) return(error); + here->BSIM4bNodePrime = tmp->number; + } + if (here->BSIM4sbNode == 0) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"sbody"); + if(error) return(error); + here->BSIM4sbNode = tmp->number; + } + } + else + here->BSIM4dbNode = here->BSIM4bNodePrime = here->BSIM4sbNode + = here->BSIM4bNode; + + /* NQS node */ + if ((here->BSIM4trnqsMod) && (here->BSIM4qNode == 0)) + { error = CKTmkVolt(ckt,&tmp,here->BSIM4name,"charge"); + if(error) return(error); + here->BSIM4qNode = tmp->number; + } + else + here->BSIM4qNode = 0; + +/* set Sparse Matrix Pointers + * macro to make elements with built-in out-of-memory test */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(BSIM4DPbpPtr, BSIM4dNodePrime, BSIM4bNodePrime) + TSTALLOC(BSIM4GPbpPtr, BSIM4gNodePrime, BSIM4bNodePrime) + TSTALLOC(BSIM4SPbpPtr, BSIM4sNodePrime, BSIM4bNodePrime) + + TSTALLOC(BSIM4BPdpPtr, BSIM4bNodePrime, BSIM4dNodePrime) + TSTALLOC(BSIM4BPgpPtr, BSIM4bNodePrime, BSIM4gNodePrime) + TSTALLOC(BSIM4BPspPtr, BSIM4bNodePrime, BSIM4sNodePrime) + TSTALLOC(BSIM4BPbpPtr, BSIM4bNodePrime, BSIM4bNodePrime) + + TSTALLOC(BSIM4DdPtr, BSIM4dNode, BSIM4dNode) + TSTALLOC(BSIM4GPgpPtr, BSIM4gNodePrime, BSIM4gNodePrime) + TSTALLOC(BSIM4SsPtr, BSIM4sNode, BSIM4sNode) + TSTALLOC(BSIM4DPdpPtr, BSIM4dNodePrime, BSIM4dNodePrime) + TSTALLOC(BSIM4SPspPtr, BSIM4sNodePrime, BSIM4sNodePrime) + TSTALLOC(BSIM4DdpPtr, BSIM4dNode, BSIM4dNodePrime) + TSTALLOC(BSIM4GPdpPtr, BSIM4gNodePrime, BSIM4dNodePrime) + TSTALLOC(BSIM4GPspPtr, BSIM4gNodePrime, BSIM4sNodePrime) + TSTALLOC(BSIM4SspPtr, BSIM4sNode, BSIM4sNodePrime) + TSTALLOC(BSIM4DPspPtr, BSIM4dNodePrime, BSIM4sNodePrime) + TSTALLOC(BSIM4DPdPtr, BSIM4dNodePrime, BSIM4dNode) + TSTALLOC(BSIM4DPgpPtr, BSIM4dNodePrime, BSIM4gNodePrime) + TSTALLOC(BSIM4SPgpPtr, BSIM4sNodePrime, BSIM4gNodePrime) + TSTALLOC(BSIM4SPsPtr, BSIM4sNodePrime, BSIM4sNode) + TSTALLOC(BSIM4SPdpPtr, BSIM4sNodePrime, BSIM4dNodePrime) + + TSTALLOC(BSIM4QqPtr, BSIM4qNode, BSIM4qNode) + TSTALLOC(BSIM4QbpPtr, BSIM4qNode, BSIM4bNodePrime) + TSTALLOC(BSIM4QdpPtr, BSIM4qNode, BSIM4dNodePrime) + TSTALLOC(BSIM4QspPtr, BSIM4qNode, BSIM4sNodePrime) + TSTALLOC(BSIM4QgpPtr, BSIM4qNode, BSIM4gNodePrime) + TSTALLOC(BSIM4DPqPtr, BSIM4dNodePrime, BSIM4qNode) + TSTALLOC(BSIM4SPqPtr, BSIM4sNodePrime, BSIM4qNode) + TSTALLOC(BSIM4GPqPtr, BSIM4gNodePrime, BSIM4qNode) + + if (here->BSIM4rgateMod != 0) + { TSTALLOC(BSIM4GEgePtr, BSIM4gNodeExt, BSIM4gNodeExt) + TSTALLOC(BSIM4GEgpPtr, BSIM4gNodeExt, BSIM4gNodePrime) + TSTALLOC(BSIM4GPgePtr, BSIM4gNodePrime, BSIM4gNodeExt) + TSTALLOC(BSIM4GEdpPtr, BSIM4gNodeExt, BSIM4dNodePrime) + TSTALLOC(BSIM4GEspPtr, BSIM4gNodeExt, BSIM4sNodePrime) + TSTALLOC(BSIM4GEbpPtr, BSIM4gNodeExt, BSIM4bNodePrime) + + TSTALLOC(BSIM4GMdpPtr, BSIM4gNodeMid, BSIM4dNodePrime) + TSTALLOC(BSIM4GMgpPtr, BSIM4gNodeMid, BSIM4gNodePrime) + TSTALLOC(BSIM4GMgmPtr, BSIM4gNodeMid, BSIM4gNodeMid) + TSTALLOC(BSIM4GMgePtr, BSIM4gNodeMid, BSIM4gNodeExt) + TSTALLOC(BSIM4GMspPtr, BSIM4gNodeMid, BSIM4sNodePrime) + TSTALLOC(BSIM4GMbpPtr, BSIM4gNodeMid, BSIM4bNodePrime) + TSTALLOC(BSIM4DPgmPtr, BSIM4dNodePrime, BSIM4gNodeMid) + TSTALLOC(BSIM4GPgmPtr, BSIM4gNodePrime, BSIM4gNodeMid) + TSTALLOC(BSIM4GEgmPtr, BSIM4gNodeExt, BSIM4gNodeMid) + TSTALLOC(BSIM4SPgmPtr, BSIM4sNodePrime, BSIM4gNodeMid) + TSTALLOC(BSIM4BPgmPtr, BSIM4bNodePrime, BSIM4gNodeMid) + } + + if (here->BSIM4rbodyMod) + { TSTALLOC(BSIM4DPdbPtr, BSIM4dNodePrime, BSIM4dbNode) + TSTALLOC(BSIM4SPsbPtr, BSIM4sNodePrime, BSIM4sbNode) + + TSTALLOC(BSIM4DBdpPtr, BSIM4dbNode, BSIM4dNodePrime) + TSTALLOC(BSIM4DBdbPtr, BSIM4dbNode, BSIM4dbNode) + TSTALLOC(BSIM4DBbpPtr, BSIM4dbNode, BSIM4bNodePrime) + TSTALLOC(BSIM4DBbPtr, BSIM4dbNode, BSIM4bNode) + + TSTALLOC(BSIM4BPdbPtr, BSIM4bNodePrime, BSIM4dbNode) + TSTALLOC(BSIM4BPbPtr, BSIM4bNodePrime, BSIM4bNode) + TSTALLOC(BSIM4BPsbPtr, BSIM4bNodePrime, BSIM4sbNode) + + TSTALLOC(BSIM4SBspPtr, BSIM4sbNode, BSIM4sNodePrime) + TSTALLOC(BSIM4SBbpPtr, BSIM4sbNode, BSIM4bNodePrime) + TSTALLOC(BSIM4SBbPtr, BSIM4sbNode, BSIM4bNode) + TSTALLOC(BSIM4SBsbPtr, BSIM4sbNode, BSIM4sbNode) + + TSTALLOC(BSIM4BdbPtr, BSIM4bNode, BSIM4dbNode) + TSTALLOC(BSIM4BbpPtr, BSIM4bNode, BSIM4bNodePrime) + TSTALLOC(BSIM4BsbPtr, BSIM4bNode, BSIM4sbNode) + TSTALLOC(BSIM4BbPtr, BSIM4bNode, BSIM4bNode) + } + + if (model->BSIM4rdsMod) + { TSTALLOC(BSIM4DgpPtr, BSIM4dNode, BSIM4gNodePrime) + TSTALLOC(BSIM4DspPtr, BSIM4dNode, BSIM4sNodePrime) + TSTALLOC(BSIM4DbpPtr, BSIM4dNode, BSIM4bNodePrime) + TSTALLOC(BSIM4SdpPtr, BSIM4sNode, BSIM4dNodePrime) + TSTALLOC(BSIM4SgpPtr, BSIM4sNode, BSIM4gNodePrime) + TSTALLOC(BSIM4SbpPtr, BSIM4sNode, BSIM4bNodePrime) + } + } + } + return(OK); +} + +int +BSIM4unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + BSIM4model *model; + BSIM4instance *here; + + for (model = (BSIM4model *)inModel; model != NULL; + model = model->BSIM4nextModel) + { + for (here = model->BSIM4instances; here != NULL; + here=here->BSIM4nextInstance) + { + if (here->BSIM4dNodePrime + && here->BSIM4dNodePrime != here->BSIM4dNode) + { + CKTdltNNum(ckt, here->BSIM4dNodePrime); + here->BSIM4dNodePrime = 0; + } + if (here->BSIM4sNodePrime + && here->BSIM4sNodePrime != here->BSIM4sNode) + { + CKTdltNNum(ckt, here->BSIM4sNodePrime); + here->BSIM4sNodePrime = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/bsim4/b4temp.c b/src/spicelib/devices/bsim4/b4temp.c new file mode 100644 index 000000000..2c6f270ad --- /dev/null +++ b/src/spicelib/devices/bsim4/b4temp.c @@ -0,0 +1,1474 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4temp.c of BSIM4.0.0. + * Authors: Weidong Liu, Xiaodong Jin, Kanyu M. Cao, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "bsim4def.h" +#include "const.h" +#include "sperror.h" + +#define Kb 1.3806226e-23 +#define KboQ 8.617087e-5 +#define EPS0 8.85418e-12 +#define EPSSI 1.03594e-10 +#define PI 3.141592654 +#define MAX_EXP 5.834617425e14 +#define MIN_EXP 1.713908431e-15 +#define EXP_THRESHOLD 34.0 +#define Charge_q 1.60219e-19 + +int +BSIM4DioIjthVjmEval(Nvtm, Ijth, Isb, XExpBV, Vjm) +double Nvtm, Ijth, Isb, XExpBV; +double *Vjm; +{ +double Tb, Tc, EVjmovNv; + + Tc = XExpBV; + Tb = 1.0 + Ijth / Isb - Tc; + EVjmovNv = 0.5 * (Tb + sqrt(Tb * Tb + 4.0 * Tc)); + *Vjm = Nvtm * log(EVjmovNv); + +return 0; +} + + +int +BSIM4temp(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ +register BSIM4model *model = (BSIM4model*) inModel; +register BSIM4instance *here; +struct bsim4SizeDependParam *pSizeDependParamKnot, *pLastKnot, *pParam; +double tmp, tmp1, tmp2, tmp3, Eg, Eg0, ni; +double T0, T1, T2, T3, T4, T5, T8, T9, Ldrn, Wdrn; +double delTemp, Temp, TRatio, Inv_L, Inv_W, Inv_LW, Dw, Dl, Vtm0, Tnom; +double dumPs, dumPd, dumAs, dumAd, PowWeffWr; +double DMCGeff, DMCIeff, DMDGeff; +double Nvtms, Nvtmd, SourceSatCurrent, DrainSatCurrent; +int Size_Not_Found; + + /* loop through all the BSIM4 device models */ + for (; model != NULL; model = model->BSIM4nextModel) + { Temp = ckt->CKTtemp; + if (model->BSIM4SbulkJctPotential < 0.1) + { model->BSIM4SbulkJctPotential = 0.1; + fprintf(stderr, "Given pbs is less than 0.1. Pbs is set to 0.1.\n"); + } + if (model->BSIM4SsidewallJctPotential < 0.1) + { model->BSIM4SsidewallJctPotential = 0.1; + fprintf(stderr, "Given pbsws is less than 0.1. Pbsws is set to 0.1.\n"); + } + if (model->BSIM4SGatesidewallJctPotential < 0.1) + { model->BSIM4SGatesidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswgs is less than 0.1. Pbswgs is set to 0.1.\n"); + } + + if (model->BSIM4DbulkJctPotential < 0.1) + { model->BSIM4DbulkJctPotential = 0.1; + fprintf(stderr, "Given pbd is less than 0.1. Pbd is set to 0.1.\n"); + } + if (model->BSIM4DsidewallJctPotential < 0.1) + { model->BSIM4DsidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswd is less than 0.1. Pbswd is set to 0.1.\n"); + } + if (model->BSIM4DGatesidewallJctPotential < 0.1) + { model->BSIM4DGatesidewallJctPotential = 0.1; + fprintf(stderr, "Given pbswgd is less than 0.1. Pbswgd is set to 0.1.\n"); + } + + if ((model->BSIM4toxeGiven) && (model->BSIM4toxpGiven) && (model->BSIM4dtoxGiven) + && (model->BSIM4toxe != (model->BSIM4toxp + model->BSIM4dtox))) + printf("Warning: toxe, toxp and dtox all given and toxe != toxp + dtox; dtox ignored.\n"); + else if ((model->BSIM4toxeGiven) && (!model->BSIM4toxpGiven)) + model->BSIM4toxp = model->BSIM4toxe - model->BSIM4dtox; + else if ((!model->BSIM4toxeGiven) && (model->BSIM4toxpGiven)) + model->BSIM4toxe = model->BSIM4toxp + model->BSIM4dtox; + + model->BSIM4coxe = model->BSIM4epsrox * EPS0 / model->BSIM4toxe; + model->BSIM4coxp = model->BSIM4epsrox * EPS0 / model->BSIM4toxp; + + if (!model->BSIM4cgdoGiven) + { if (model->BSIM4dlcGiven && (model->BSIM4dlc > 0.0)) + model->BSIM4cgdo = model->BSIM4dlc * model->BSIM4coxe + - model->BSIM4cgdl ; + else + model->BSIM4cgdo = 0.6 * model->BSIM4xj * model->BSIM4coxe; + } + if (!model->BSIM4cgsoGiven) + { if (model->BSIM4dlcGiven && (model->BSIM4dlc > 0.0)) + model->BSIM4cgso = model->BSIM4dlc * model->BSIM4coxe + - model->BSIM4cgsl ; + else + model->BSIM4cgso = 0.6 * model->BSIM4xj * model->BSIM4coxe; + } + if (!model->BSIM4cgboGiven) + model->BSIM4cgbo = 2.0 * model->BSIM4dwc * model->BSIM4coxe; + + model->pSizeDependParamKnot = NULL; + pLastKnot = NULL; + + Tnom = model->BSIM4tnom; + TRatio = Temp / Tnom; + + model->BSIM4vcrit = CONSTvt0 * log(CONSTvt0 / (CONSTroot2 * 1.0e-14)); + model->BSIM4factor1 = sqrt(EPSSI / (model->BSIM4epsrox * EPS0) + * model->BSIM4toxe); + + Vtm0 = KboQ * Tnom; + Eg0 = 1.16 - 7.02e-4 * Tnom * Tnom / (Tnom + 1108.0); + ni = 1.45e10 * (Tnom / 300.15) * sqrt(Tnom / 300.15) + * exp(21.5565981 - Eg0 / (2.0 * Vtm0)); + + model->BSIM4vtm = KboQ * Temp; + Eg = 1.16 - 7.02e-4 * Temp * Temp / (Temp + 1108.0); + if (Temp != Tnom) + { T0 = Eg0 / Vtm0 - Eg / model->BSIM4vtm; + T1 = log(Temp / Tnom); + T2 = T0 + model->BSIM4SjctTempExponent * T1; + T3 = exp(T2 / model->BSIM4SjctEmissionCoeff); + model->BSIM4SjctTempSatCurDensity = model->BSIM4SjctSatCurDensity + * T3; + model->BSIM4SjctSidewallTempSatCurDensity + = model->BSIM4SjctSidewallSatCurDensity * T3; + model->BSIM4SjctGateSidewallTempSatCurDensity + = model->BSIM4SjctGateSidewallSatCurDensity * T3; + + T2 = T0 + model->BSIM4DjctTempExponent * T1; + T3 = exp(T2 / model->BSIM4DjctEmissionCoeff); + model->BSIM4DjctTempSatCurDensity = model->BSIM4DjctSatCurDensity + * T3; + model->BSIM4DjctSidewallTempSatCurDensity + = model->BSIM4DjctSidewallSatCurDensity * T3; + model->BSIM4DjctGateSidewallTempSatCurDensity + = model->BSIM4DjctGateSidewallSatCurDensity * T3; + } + else + { model->BSIM4SjctTempSatCurDensity = model->BSIM4SjctSatCurDensity; + model->BSIM4SjctSidewallTempSatCurDensity + = model->BSIM4SjctSidewallSatCurDensity; + model->BSIM4SjctGateSidewallTempSatCurDensity + = model->BSIM4SjctGateSidewallSatCurDensity; + model->BSIM4DjctTempSatCurDensity = model->BSIM4DjctSatCurDensity; + model->BSIM4DjctSidewallTempSatCurDensity + = model->BSIM4DjctSidewallSatCurDensity; + model->BSIM4DjctGateSidewallTempSatCurDensity + = model->BSIM4DjctGateSidewallSatCurDensity; + } + + if (model->BSIM4SjctTempSatCurDensity < 0.0) + model->BSIM4SjctTempSatCurDensity = 0.0; + if (model->BSIM4SjctSidewallTempSatCurDensity < 0.0) + model->BSIM4SjctSidewallTempSatCurDensity = 0.0; + if (model->BSIM4SjctGateSidewallTempSatCurDensity < 0.0) + model->BSIM4SjctGateSidewallTempSatCurDensity = 0.0; + + if (model->BSIM4DjctTempSatCurDensity < 0.0) + model->BSIM4DjctTempSatCurDensity = 0.0; + if (model->BSIM4DjctSidewallTempSatCurDensity < 0.0) + model->BSIM4DjctSidewallTempSatCurDensity = 0.0; + if (model->BSIM4DjctGateSidewallTempSatCurDensity < 0.0) + model->BSIM4DjctGateSidewallTempSatCurDensity = 0.0; + + /* Temperature dependence of D/B and S/B diode capacitance begins */ + delTemp = ckt->CKTtemp - model->BSIM4tnom; + T0 = model->BSIM4tcj * delTemp; + if (T0 >= -1.0) + { model->BSIM4SunitAreaJctCap *= 1.0 + T0; + model->BSIM4DunitAreaJctCap *= 1.0 + T0; + } + else + { if (model->BSIM4SunitAreaJctCap > 0.0) + { model->BSIM4SunitAreaJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjs to be negative. Cjs is clamped to zero.\n"); + } + if (model->BSIM4DunitAreaJctCap > 0.0) + { model->BSIM4DunitAreaJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjd to be negative. Cjd is clamped to zero.\n"); + } + } + T0 = model->BSIM4tcjsw * delTemp; + if (T0 >= -1.0) + { model->BSIM4SunitLengthSidewallJctCap *= 1.0 + T0; + model->BSIM4DunitLengthSidewallJctCap *= 1.0 + T0; + } + else + { if (model->BSIM4SunitLengthSidewallJctCap > 0.0) + { model->BSIM4SunitLengthSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjsws to be negative. Cjsws is clamped to zero.\n"); + } + if (model->BSIM4DunitLengthSidewallJctCap > 0.0) + { model->BSIM4DunitLengthSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjswd to be negative. Cjswd is clamped to zero.\n"); + } + } + T0 = model->BSIM4tcjswg * delTemp; + if (T0 >= -1.0) + { model->BSIM4SunitLengthGateSidewallJctCap *= 1.0 + T0; + model->BSIM4DunitLengthGateSidewallJctCap *= 1.0 + T0; + } + else + { if (model->BSIM4SunitLengthGateSidewallJctCap > 0.0) + { model->BSIM4SunitLengthGateSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjswgs to be negative. Cjswgs is clamped to zero.\n"); + } + if (model->BSIM4DunitLengthGateSidewallJctCap > 0.0) + { model->BSIM4DunitLengthGateSidewallJctCap = 0.0; + fprintf(stderr, "Temperature effect has caused cjswgd to be negative. Cjswgd is clamped to zero.\n"); + } + } + + model->BSIM4PhiBS = model->BSIM4SbulkJctPotential + - model->BSIM4tpb * delTemp; + if (model->BSIM4PhiBS < 0.01) + { model->BSIM4PhiBS = 0.01; + fprintf(stderr, "Temperature effect has caused pbs to be less than 0.01. Pbs is clamped to 0.01.\n"); + } + model->BSIM4PhiBD = model->BSIM4DbulkJctPotential + - model->BSIM4tpb * delTemp; + if (model->BSIM4PhiBD < 0.01) + { model->BSIM4PhiBD = 0.01; + fprintf(stderr, "Temperature effect has caused pbd to be less than 0.01. Pbd is clamped to 0.01.\n"); + } + + model->BSIM4PhiBSWS = model->BSIM4SsidewallJctPotential + - model->BSIM4tpbsw * delTemp; + if (model->BSIM4PhiBSWS <= 0.01) + { model->BSIM4PhiBSWS = 0.01; + fprintf(stderr, "Temperature effect has caused pbsws to be less than 0.01. Pbsws is clamped to 0.01.\n"); + } + model->BSIM4PhiBSWD = model->BSIM4DsidewallJctPotential + - model->BSIM4tpbsw * delTemp; + if (model->BSIM4PhiBSWD <= 0.01) + { model->BSIM4PhiBSWD = 0.01; + fprintf(stderr, "Temperature effect has caused pbswd to be less than 0.01. Pbswd is clamped to 0.01.\n"); + } + + model->BSIM4PhiBSWGS = model->BSIM4SGatesidewallJctPotential + - model->BSIM4tpbswg * delTemp; + if (model->BSIM4PhiBSWGS <= 0.01) + { model->BSIM4PhiBSWGS = 0.01; + fprintf(stderr, "Temperature effect has caused pbswgs to be less than 0.01. Pbswgs is clamped to 0.01.\n"); + } + model->BSIM4PhiBSWGD = model->BSIM4DGatesidewallJctPotential + - model->BSIM4tpbswg * delTemp; + if (model->BSIM4PhiBSWGD <= 0.01) + { model->BSIM4PhiBSWGD = 0.01; + fprintf(stderr, "Temperature effect has caused pbswgd to be less than 0.01. Pbswgd is clamped to 0.01.\n"); + } /* End of junction capacitance */ + + + if (model->BSIM4ijthdfwd <= 0.0) + { model->BSIM4ijthdfwd = 0.1; + fprintf(stderr, "Ijthdfwd reset to %g.\n", model->BSIM4ijthdfwd); + } + if (model->BSIM4ijthsfwd <= 0.0) + { model->BSIM4ijthsfwd = 0.1; + fprintf(stderr, "Ijthsfwd reset to %g.\n", model->BSIM4ijthsfwd); + } + if (model->BSIM4ijthdrev <= 0.0) + { model->BSIM4ijthdrev = 0.1; + fprintf(stderr, "Ijthdrev reset to %g.\n", model->BSIM4ijthdrev); + } + if (model->BSIM4ijthsrev <= 0.0) + { model->BSIM4ijthsrev = 0.1; + fprintf(stderr, "Ijthsrev reset to %g.\n", model->BSIM4ijthsrev); + } + + if ((model->BSIM4xjbvd <= 0.0) && (model->BSIM4dioMod == 2)) + { model->BSIM4xjbvd = 1.0; + fprintf(stderr, "Xjbvd reset to %g.\n", model->BSIM4xjbvd); + } + else if ((model->BSIM4xjbvd < 0.0) && (model->BSIM4dioMod == 0)) + { model->BSIM4xjbvd = 1.0; + fprintf(stderr, "Xjbvd reset to %g.\n", model->BSIM4xjbvd); + } + + if (model->BSIM4bvd <= 0.0) + { model->BSIM4bvd = 10.0; + fprintf(stderr, "BVD reset to %g.\n", model->BSIM4bvd); + } + + if ((model->BSIM4xjbvs <= 0.0) && (model->BSIM4dioMod == 2)) + { model->BSIM4xjbvs = 1.0; + fprintf(stderr, "Xjbvs reset to %g.\n", model->BSIM4xjbvs); + } + else if ((model->BSIM4xjbvs < 0.0) && (model->BSIM4dioMod == 0)) + { model->BSIM4xjbvs = 1.0; + fprintf(stderr, "Xjbvs reset to %g.\n", model->BSIM4xjbvs); + } + + if (model->BSIM4bvs <= 0.0) + { model->BSIM4bvs = 10.0; + fprintf(stderr, "BVS reset to %g.\n", model->BSIM4bvs); + } + + + /* loop through all the instances of the model */ + for (here = model->BSIM4instances; here != NULL; + here = here->BSIM4nextInstance) + { if (here->BSIM4owner != ARCHme) continue; + pSizeDependParamKnot = model->pSizeDependParamKnot; + Size_Not_Found = 1; + while ((pSizeDependParamKnot != NULL) && Size_Not_Found) + { if ((here->BSIM4l == pSizeDependParamKnot->Length) + && (here->BSIM4w == pSizeDependParamKnot->Width) + && (here->BSIM4nf == pSizeDependParamKnot->NFinger)) + { Size_Not_Found = 0; + here->pParam = pSizeDependParamKnot; + } + else + { pLastKnot = pSizeDependParamKnot; + pSizeDependParamKnot = pSizeDependParamKnot->pNext; + } + } + + if (Size_Not_Found) + { pParam = (struct bsim4SizeDependParam *)malloc( + sizeof(struct bsim4SizeDependParam)); + if (pLastKnot == NULL) + model->pSizeDependParamKnot = pParam; + else + pLastKnot->pNext = pParam; + pParam->pNext = NULL; + here->pParam = pParam; + + pParam->Length = here->BSIM4l; + pParam->Width = here->BSIM4w; + pParam->NFinger = here->BSIM4nf; + Ldrn = here->BSIM4l; + Wdrn = here->BSIM4w / here->BSIM4nf; + + T0 = pow(Ldrn, model->BSIM4Lln); + T1 = pow(Wdrn, model->BSIM4Lwn); + tmp1 = model->BSIM4Ll / T0 + model->BSIM4Lw / T1 + + model->BSIM4Lwl / (T0 * T1); + pParam->BSIM4dl = model->BSIM4Lint + tmp1; + tmp2 = model->BSIM4Llc / T0 + model->BSIM4Lwc / T1 + + model->BSIM4Lwlc / (T0 * T1); + pParam->BSIM4dlc = model->BSIM4dlc + tmp2; + pParam->BSIM4dlcig = model->BSIM4dlcig + tmp2; + + T2 = pow(Ldrn, model->BSIM4Wln); + T3 = pow(Wdrn, model->BSIM4Wwn); + tmp1 = model->BSIM4Wl / T2 + model->BSIM4Ww / T3 + + model->BSIM4Wwl / (T2 * T3); + pParam->BSIM4dw = model->BSIM4Wint + tmp1; + tmp2 = model->BSIM4Wlc / T2 + model->BSIM4Wwc / T3 + + model->BSIM4Wwlc / (T2 * T3); + pParam->BSIM4dwc = model->BSIM4dwc + tmp2; + pParam->BSIM4dwj = model->BSIM4dwj + tmp2; + + pParam->BSIM4leff = here->BSIM4l - 2.0 * pParam->BSIM4dl; + if (pParam->BSIM4leff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM4: mosfet %s, model %s: Effective channel length <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM4weff = here->BSIM4w / here->BSIM4nf + - 2.0 * pParam->BSIM4dw; + if (pParam->BSIM4weff <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM4: mosfet %s, model %s: Effective channel width <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM4leffCV = here->BSIM4l - 2.0 * pParam->BSIM4dlc; + if (pParam->BSIM4leffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM4: mosfet %s, model %s: Effective channel length for C-V <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM4weffCV = here->BSIM4w / here->BSIM4nf + - 2.0 * pParam->BSIM4dwc; + if (pParam->BSIM4weffCV <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM4: mosfet %s, model %s: Effective channel width for C-V <= 0", + namarray); + return(E_BADPARM); + } + + pParam->BSIM4weffCJ = here->BSIM4w / here->BSIM4nf + - 2.0 * pParam->BSIM4dwj; + if (pParam->BSIM4weffCJ <= 0.0) + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "BSIM4: mosfet %s, model %s: Effective channel width for S/D junctions <= 0", + namarray); + return(E_BADPARM); + } + + + if (model->BSIM4binUnit == 1) + { Inv_L = 1.0e-6 / pParam->BSIM4leff; + Inv_W = 1.0e-6 / pParam->BSIM4weff; + Inv_LW = 1.0e-12 / (pParam->BSIM4leff + * pParam->BSIM4weff); + } + else + { Inv_L = 1.0 / pParam->BSIM4leff; + Inv_W = 1.0 / pParam->BSIM4weff; + Inv_LW = 1.0 / (pParam->BSIM4leff + * pParam->BSIM4weff); + } + pParam->BSIM4cdsc = model->BSIM4cdsc + + model->BSIM4lcdsc * Inv_L + + model->BSIM4wcdsc * Inv_W + + model->BSIM4pcdsc * Inv_LW; + pParam->BSIM4cdscb = model->BSIM4cdscb + + model->BSIM4lcdscb * Inv_L + + model->BSIM4wcdscb * Inv_W + + model->BSIM4pcdscb * Inv_LW; + + pParam->BSIM4cdscd = model->BSIM4cdscd + + model->BSIM4lcdscd * Inv_L + + model->BSIM4wcdscd * Inv_W + + model->BSIM4pcdscd * Inv_LW; + + pParam->BSIM4cit = model->BSIM4cit + + model->BSIM4lcit * Inv_L + + model->BSIM4wcit * Inv_W + + model->BSIM4pcit * Inv_LW; + pParam->BSIM4nfactor = model->BSIM4nfactor + + model->BSIM4lnfactor * Inv_L + + model->BSIM4wnfactor * Inv_W + + model->BSIM4pnfactor * Inv_LW; + pParam->BSIM4xj = model->BSIM4xj + + model->BSIM4lxj * Inv_L + + model->BSIM4wxj * Inv_W + + model->BSIM4pxj * Inv_LW; + pParam->BSIM4vsat = model->BSIM4vsat + + model->BSIM4lvsat * Inv_L + + model->BSIM4wvsat * Inv_W + + model->BSIM4pvsat * Inv_LW; + pParam->BSIM4at = model->BSIM4at + + model->BSIM4lat * Inv_L + + model->BSIM4wat * Inv_W + + model->BSIM4pat * Inv_LW; + pParam->BSIM4a0 = model->BSIM4a0 + + model->BSIM4la0 * Inv_L + + model->BSIM4wa0 * Inv_W + + model->BSIM4pa0 * Inv_LW; + + pParam->BSIM4ags = model->BSIM4ags + + model->BSIM4lags * Inv_L + + model->BSIM4wags * Inv_W + + model->BSIM4pags * Inv_LW; + + pParam->BSIM4a1 = model->BSIM4a1 + + model->BSIM4la1 * Inv_L + + model->BSIM4wa1 * Inv_W + + model->BSIM4pa1 * Inv_LW; + pParam->BSIM4a2 = model->BSIM4a2 + + model->BSIM4la2 * Inv_L + + model->BSIM4wa2 * Inv_W + + model->BSIM4pa2 * Inv_LW; + pParam->BSIM4keta = model->BSIM4keta + + model->BSIM4lketa * Inv_L + + model->BSIM4wketa * Inv_W + + model->BSIM4pketa * Inv_LW; + pParam->BSIM4nsub = model->BSIM4nsub + + model->BSIM4lnsub * Inv_L + + model->BSIM4wnsub * Inv_W + + model->BSIM4pnsub * Inv_LW; + pParam->BSIM4ndep = model->BSIM4ndep + + model->BSIM4lndep * Inv_L + + model->BSIM4wndep * Inv_W + + model->BSIM4pndep * Inv_LW; + pParam->BSIM4nsd = model->BSIM4nsd + + model->BSIM4lnsd * Inv_L + + model->BSIM4wnsd * Inv_W + + model->BSIM4pnsd * Inv_LW; + pParam->BSIM4phin = model->BSIM4phin + + model->BSIM4lphin * Inv_L + + model->BSIM4wphin * Inv_W + + model->BSIM4pphin * Inv_LW; + pParam->BSIM4ngate = model->BSIM4ngate + + model->BSIM4lngate * Inv_L + + model->BSIM4wngate * Inv_W + + model->BSIM4pngate * Inv_LW; + pParam->BSIM4gamma1 = model->BSIM4gamma1 + + model->BSIM4lgamma1 * Inv_L + + model->BSIM4wgamma1 * Inv_W + + model->BSIM4pgamma1 * Inv_LW; + pParam->BSIM4gamma2 = model->BSIM4gamma2 + + model->BSIM4lgamma2 * Inv_L + + model->BSIM4wgamma2 * Inv_W + + model->BSIM4pgamma2 * Inv_LW; + pParam->BSIM4vbx = model->BSIM4vbx + + model->BSIM4lvbx * Inv_L + + model->BSIM4wvbx * Inv_W + + model->BSIM4pvbx * Inv_LW; + pParam->BSIM4vbm = model->BSIM4vbm + + model->BSIM4lvbm * Inv_L + + model->BSIM4wvbm * Inv_W + + model->BSIM4pvbm * Inv_LW; + pParam->BSIM4xt = model->BSIM4xt + + model->BSIM4lxt * Inv_L + + model->BSIM4wxt * Inv_W + + model->BSIM4pxt * Inv_LW; + pParam->BSIM4vfb = model->BSIM4vfb + + model->BSIM4lvfb * Inv_L + + model->BSIM4wvfb * Inv_W + + model->BSIM4pvfb * Inv_LW; + pParam->BSIM4k1 = model->BSIM4k1 + + model->BSIM4lk1 * Inv_L + + model->BSIM4wk1 * Inv_W + + model->BSIM4pk1 * Inv_LW; + pParam->BSIM4kt1 = model->BSIM4kt1 + + model->BSIM4lkt1 * Inv_L + + model->BSIM4wkt1 * Inv_W + + model->BSIM4pkt1 * Inv_LW; + pParam->BSIM4kt1l = model->BSIM4kt1l + + model->BSIM4lkt1l * Inv_L + + model->BSIM4wkt1l * Inv_W + + model->BSIM4pkt1l * Inv_LW; + pParam->BSIM4k2 = model->BSIM4k2 + + model->BSIM4lk2 * Inv_L + + model->BSIM4wk2 * Inv_W + + model->BSIM4pk2 * Inv_LW; + pParam->BSIM4kt2 = model->BSIM4kt2 + + model->BSIM4lkt2 * Inv_L + + model->BSIM4wkt2 * Inv_W + + model->BSIM4pkt2 * Inv_LW; + pParam->BSIM4k3 = model->BSIM4k3 + + model->BSIM4lk3 * Inv_L + + model->BSIM4wk3 * Inv_W + + model->BSIM4pk3 * Inv_LW; + pParam->BSIM4k3b = model->BSIM4k3b + + model->BSIM4lk3b * Inv_L + + model->BSIM4wk3b * Inv_W + + model->BSIM4pk3b * Inv_LW; + pParam->BSIM4w0 = model->BSIM4w0 + + model->BSIM4lw0 * Inv_L + + model->BSIM4ww0 * Inv_W + + model->BSIM4pw0 * Inv_LW; + pParam->BSIM4lpe0 = model->BSIM4lpe0 + + model->BSIM4llpe0 * Inv_L + + model->BSIM4wlpe0 * Inv_W + + model->BSIM4plpe0 * Inv_LW; + pParam->BSIM4lpeb = model->BSIM4lpeb + + model->BSIM4llpeb * Inv_L + + model->BSIM4wlpeb * Inv_W + + model->BSIM4plpeb * Inv_LW; + pParam->BSIM4dvtp0 = model->BSIM4dvtp0 + + model->BSIM4ldvtp0 * Inv_L + + model->BSIM4wdvtp0 * Inv_W + + model->BSIM4pdvtp0 * Inv_LW; + pParam->BSIM4dvtp1 = model->BSIM4dvtp1 + + model->BSIM4ldvtp1 * Inv_L + + model->BSIM4wdvtp1 * Inv_W + + model->BSIM4pdvtp1 * Inv_LW; + pParam->BSIM4dvt0 = model->BSIM4dvt0 + + model->BSIM4ldvt0 * Inv_L + + model->BSIM4wdvt0 * Inv_W + + model->BSIM4pdvt0 * Inv_LW; + pParam->BSIM4dvt1 = model->BSIM4dvt1 + + model->BSIM4ldvt1 * Inv_L + + model->BSIM4wdvt1 * Inv_W + + model->BSIM4pdvt1 * Inv_LW; + pParam->BSIM4dvt2 = model->BSIM4dvt2 + + model->BSIM4ldvt2 * Inv_L + + model->BSIM4wdvt2 * Inv_W + + model->BSIM4pdvt2 * Inv_LW; + pParam->BSIM4dvt0w = model->BSIM4dvt0w + + model->BSIM4ldvt0w * Inv_L + + model->BSIM4wdvt0w * Inv_W + + model->BSIM4pdvt0w * Inv_LW; + pParam->BSIM4dvt1w = model->BSIM4dvt1w + + model->BSIM4ldvt1w * Inv_L + + model->BSIM4wdvt1w * Inv_W + + model->BSIM4pdvt1w * Inv_LW; + pParam->BSIM4dvt2w = model->BSIM4dvt2w + + model->BSIM4ldvt2w * Inv_L + + model->BSIM4wdvt2w * Inv_W + + model->BSIM4pdvt2w * Inv_LW; + pParam->BSIM4drout = model->BSIM4drout + + model->BSIM4ldrout * Inv_L + + model->BSIM4wdrout * Inv_W + + model->BSIM4pdrout * Inv_LW; + pParam->BSIM4dsub = model->BSIM4dsub + + model->BSIM4ldsub * Inv_L + + model->BSIM4wdsub * Inv_W + + model->BSIM4pdsub * Inv_LW; + pParam->BSIM4vth0 = model->BSIM4vth0 + + model->BSIM4lvth0 * Inv_L + + model->BSIM4wvth0 * Inv_W + + model->BSIM4pvth0 * Inv_LW; + pParam->BSIM4ua = model->BSIM4ua + + model->BSIM4lua * Inv_L + + model->BSIM4wua * Inv_W + + model->BSIM4pua * Inv_LW; + pParam->BSIM4ua1 = model->BSIM4ua1 + + model->BSIM4lua1 * Inv_L + + model->BSIM4wua1 * Inv_W + + model->BSIM4pua1 * Inv_LW; + pParam->BSIM4ub = model->BSIM4ub + + model->BSIM4lub * Inv_L + + model->BSIM4wub * Inv_W + + model->BSIM4pub * Inv_LW; + pParam->BSIM4ub1 = model->BSIM4ub1 + + model->BSIM4lub1 * Inv_L + + model->BSIM4wub1 * Inv_W + + model->BSIM4pub1 * Inv_LW; + pParam->BSIM4uc = model->BSIM4uc + + model->BSIM4luc * Inv_L + + model->BSIM4wuc * Inv_W + + model->BSIM4puc * Inv_LW; + pParam->BSIM4uc1 = model->BSIM4uc1 + + model->BSIM4luc1 * Inv_L + + model->BSIM4wuc1 * Inv_W + + model->BSIM4puc1 * Inv_LW; + pParam->BSIM4eu = model->BSIM4eu + + model->BSIM4leu * Inv_L + + model->BSIM4weu * Inv_W + + model->BSIM4peu * Inv_LW; + pParam->BSIM4u0 = model->BSIM4u0 + + model->BSIM4lu0 * Inv_L + + model->BSIM4wu0 * Inv_W + + model->BSIM4pu0 * Inv_LW; + pParam->BSIM4ute = model->BSIM4ute + + model->BSIM4lute * Inv_L + + model->BSIM4wute * Inv_W + + model->BSIM4pute * Inv_LW; + pParam->BSIM4voff = model->BSIM4voff + + model->BSIM4lvoff * Inv_L + + model->BSIM4wvoff * Inv_W + + model->BSIM4pvoff * Inv_LW; + pParam->BSIM4minv = model->BSIM4minv + + model->BSIM4lminv * Inv_L + + model->BSIM4wminv * Inv_W + + model->BSIM4pminv * Inv_LW; + pParam->BSIM4fprout = model->BSIM4fprout + + model->BSIM4lfprout * Inv_L + + model->BSIM4wfprout * Inv_W + + model->BSIM4pfprout * Inv_LW; + pParam->BSIM4pdits = model->BSIM4pdits + + model->BSIM4lpdits * Inv_L + + model->BSIM4wpdits * Inv_W + + model->BSIM4ppdits * Inv_LW; + pParam->BSIM4pditsd = model->BSIM4pditsd + + model->BSIM4lpditsd * Inv_L + + model->BSIM4wpditsd * Inv_W + + model->BSIM4ppditsd * Inv_LW; + pParam->BSIM4delta = model->BSIM4delta + + model->BSIM4ldelta * Inv_L + + model->BSIM4wdelta * Inv_W + + model->BSIM4pdelta * Inv_LW; + pParam->BSIM4rdsw = model->BSIM4rdsw + + model->BSIM4lrdsw * Inv_L + + model->BSIM4wrdsw * Inv_W + + model->BSIM4prdsw * Inv_LW; + pParam->BSIM4rdw = model->BSIM4rdw + + model->BSIM4lrdw * Inv_L + + model->BSIM4wrdw * Inv_W + + model->BSIM4prdw * Inv_LW; + pParam->BSIM4rsw = model->BSIM4rsw + + model->BSIM4lrsw * Inv_L + + model->BSIM4wrsw * Inv_W + + model->BSIM4prsw * Inv_LW; + pParam->BSIM4prwg = model->BSIM4prwg + + model->BSIM4lprwg * Inv_L + + model->BSIM4wprwg * Inv_W + + model->BSIM4pprwg * Inv_LW; + pParam->BSIM4prwb = model->BSIM4prwb + + model->BSIM4lprwb * Inv_L + + model->BSIM4wprwb * Inv_W + + model->BSIM4pprwb * Inv_LW; + pParam->BSIM4prt = model->BSIM4prt + + model->BSIM4lprt * Inv_L + + model->BSIM4wprt * Inv_W + + model->BSIM4pprt * Inv_LW; + pParam->BSIM4eta0 = model->BSIM4eta0 + + model->BSIM4leta0 * Inv_L + + model->BSIM4weta0 * Inv_W + + model->BSIM4peta0 * Inv_LW; + pParam->BSIM4etab = model->BSIM4etab + + model->BSIM4letab * Inv_L + + model->BSIM4wetab * Inv_W + + model->BSIM4petab * Inv_LW; + pParam->BSIM4pclm = model->BSIM4pclm + + model->BSIM4lpclm * Inv_L + + model->BSIM4wpclm * Inv_W + + model->BSIM4ppclm * Inv_LW; + pParam->BSIM4pdibl1 = model->BSIM4pdibl1 + + model->BSIM4lpdibl1 * Inv_L + + model->BSIM4wpdibl1 * Inv_W + + model->BSIM4ppdibl1 * Inv_LW; + pParam->BSIM4pdibl2 = model->BSIM4pdibl2 + + model->BSIM4lpdibl2 * Inv_L + + model->BSIM4wpdibl2 * Inv_W + + model->BSIM4ppdibl2 * Inv_LW; + pParam->BSIM4pdiblb = model->BSIM4pdiblb + + model->BSIM4lpdiblb * Inv_L + + model->BSIM4wpdiblb * Inv_W + + model->BSIM4ppdiblb * Inv_LW; + pParam->BSIM4pscbe1 = model->BSIM4pscbe1 + + model->BSIM4lpscbe1 * Inv_L + + model->BSIM4wpscbe1 * Inv_W + + model->BSIM4ppscbe1 * Inv_LW; + pParam->BSIM4pscbe2 = model->BSIM4pscbe2 + + model->BSIM4lpscbe2 * Inv_L + + model->BSIM4wpscbe2 * Inv_W + + model->BSIM4ppscbe2 * Inv_LW; + pParam->BSIM4pvag = model->BSIM4pvag + + model->BSIM4lpvag * Inv_L + + model->BSIM4wpvag * Inv_W + + model->BSIM4ppvag * Inv_LW; + pParam->BSIM4wr = model->BSIM4wr + + model->BSIM4lwr * Inv_L + + model->BSIM4wwr * Inv_W + + model->BSIM4pwr * Inv_LW; + pParam->BSIM4dwg = model->BSIM4dwg + + model->BSIM4ldwg * Inv_L + + model->BSIM4wdwg * Inv_W + + model->BSIM4pdwg * Inv_LW; + pParam->BSIM4dwb = model->BSIM4dwb + + model->BSIM4ldwb * Inv_L + + model->BSIM4wdwb * Inv_W + + model->BSIM4pdwb * Inv_LW; + pParam->BSIM4b0 = model->BSIM4b0 + + model->BSIM4lb0 * Inv_L + + model->BSIM4wb0 * Inv_W + + model->BSIM4pb0 * Inv_LW; + pParam->BSIM4b1 = model->BSIM4b1 + + model->BSIM4lb1 * Inv_L + + model->BSIM4wb1 * Inv_W + + model->BSIM4pb1 * Inv_LW; + pParam->BSIM4alpha0 = model->BSIM4alpha0 + + model->BSIM4lalpha0 * Inv_L + + model->BSIM4walpha0 * Inv_W + + model->BSIM4palpha0 * Inv_LW; + pParam->BSIM4alpha1 = model->BSIM4alpha1 + + model->BSIM4lalpha1 * Inv_L + + model->BSIM4walpha1 * Inv_W + + model->BSIM4palpha1 * Inv_LW; + pParam->BSIM4beta0 = model->BSIM4beta0 + + model->BSIM4lbeta0 * Inv_L + + model->BSIM4wbeta0 * Inv_W + + model->BSIM4pbeta0 * Inv_LW; + pParam->BSIM4agidl = model->BSIM4agidl + + model->BSIM4lagidl * Inv_L + + model->BSIM4wagidl * Inv_W + + model->BSIM4pagidl * Inv_LW; + pParam->BSIM4bgidl = model->BSIM4bgidl + + model->BSIM4lbgidl * Inv_L + + model->BSIM4wbgidl * Inv_W + + model->BSIM4pbgidl * Inv_LW; + pParam->BSIM4cgidl = model->BSIM4cgidl + + model->BSIM4lcgidl * Inv_L + + model->BSIM4wcgidl * Inv_W + + model->BSIM4pcgidl * Inv_LW; + pParam->BSIM4egidl = model->BSIM4egidl + + model->BSIM4legidl * Inv_L + + model->BSIM4wegidl * Inv_W + + model->BSIM4pegidl * Inv_LW; + pParam->BSIM4aigc = model->BSIM4aigc + + model->BSIM4laigc * Inv_L + + model->BSIM4waigc * Inv_W + + model->BSIM4paigc * Inv_LW; + pParam->BSIM4bigc = model->BSIM4bigc + + model->BSIM4lbigc * Inv_L + + model->BSIM4wbigc * Inv_W + + model->BSIM4pbigc * Inv_LW; + pParam->BSIM4cigc = model->BSIM4cigc + + model->BSIM4lcigc * Inv_L + + model->BSIM4wcigc * Inv_W + + model->BSIM4pcigc * Inv_LW; + pParam->BSIM4aigsd = model->BSIM4aigsd + + model->BSIM4laigsd * Inv_L + + model->BSIM4waigsd * Inv_W + + model->BSIM4paigsd * Inv_LW; + pParam->BSIM4bigsd = model->BSIM4bigsd + + model->BSIM4lbigsd * Inv_L + + model->BSIM4wbigsd * Inv_W + + model->BSIM4pbigsd * Inv_LW; + pParam->BSIM4cigsd = model->BSIM4cigsd + + model->BSIM4lcigsd * Inv_L + + model->BSIM4wcigsd * Inv_W + + model->BSIM4pcigsd * Inv_LW; + pParam->BSIM4aigbacc = model->BSIM4aigbacc + + model->BSIM4laigbacc * Inv_L + + model->BSIM4waigbacc * Inv_W + + model->BSIM4paigbacc * Inv_LW; + pParam->BSIM4bigbacc = model->BSIM4bigbacc + + model->BSIM4lbigbacc * Inv_L + + model->BSIM4wbigbacc * Inv_W + + model->BSIM4pbigbacc * Inv_LW; + pParam->BSIM4cigbacc = model->BSIM4cigbacc + + model->BSIM4lcigbacc * Inv_L + + model->BSIM4wcigbacc * Inv_W + + model->BSIM4pcigbacc * Inv_LW; + pParam->BSIM4aigbinv = model->BSIM4aigbinv + + model->BSIM4laigbinv * Inv_L + + model->BSIM4waigbinv * Inv_W + + model->BSIM4paigbinv * Inv_LW; + pParam->BSIM4bigbinv = model->BSIM4bigbinv + + model->BSIM4lbigbinv * Inv_L + + model->BSIM4wbigbinv * Inv_W + + model->BSIM4pbigbinv * Inv_LW; + pParam->BSIM4cigbinv = model->BSIM4cigbinv + + model->BSIM4lcigbinv * Inv_L + + model->BSIM4wcigbinv * Inv_W + + model->BSIM4pcigbinv * Inv_LW; + pParam->BSIM4nigc = model->BSIM4nigc + + model->BSIM4lnigc * Inv_L + + model->BSIM4wnigc * Inv_W + + model->BSIM4pnigc * Inv_LW; + pParam->BSIM4nigbacc = model->BSIM4nigbacc + + model->BSIM4lnigbacc * Inv_L + + model->BSIM4wnigbacc * Inv_W + + model->BSIM4pnigbacc * Inv_LW; + pParam->BSIM4nigbinv = model->BSIM4nigbinv + + model->BSIM4lnigbinv * Inv_L + + model->BSIM4wnigbinv * Inv_W + + model->BSIM4pnigbinv * Inv_LW; + pParam->BSIM4ntox = model->BSIM4ntox + + model->BSIM4lntox * Inv_L + + model->BSIM4wntox * Inv_W + + model->BSIM4pntox * Inv_LW; + pParam->BSIM4eigbinv = model->BSIM4eigbinv + + model->BSIM4leigbinv * Inv_L + + model->BSIM4weigbinv * Inv_W + + model->BSIM4peigbinv * Inv_LW; + pParam->BSIM4pigcd = model->BSIM4pigcd + + model->BSIM4lpigcd * Inv_L + + model->BSIM4wpigcd * Inv_W + + model->BSIM4ppigcd * Inv_LW; + pParam->BSIM4poxedge = model->BSIM4poxedge + + model->BSIM4lpoxedge * Inv_L + + model->BSIM4wpoxedge * Inv_W + + model->BSIM4ppoxedge * Inv_LW; + pParam->BSIM4xrcrg1 = model->BSIM4xrcrg1 + + model->BSIM4lxrcrg1 * Inv_L + + model->BSIM4wxrcrg1 * Inv_W + + model->BSIM4pxrcrg1 * Inv_LW; + pParam->BSIM4xrcrg2 = model->BSIM4xrcrg2 + + model->BSIM4lxrcrg2 * Inv_L + + model->BSIM4wxrcrg2 * Inv_W + + model->BSIM4pxrcrg2 * Inv_LW; + + pParam->BSIM4cgsl = model->BSIM4cgsl + + model->BSIM4lcgsl * Inv_L + + model->BSIM4wcgsl * Inv_W + + model->BSIM4pcgsl * Inv_LW; + pParam->BSIM4cgdl = model->BSIM4cgdl + + model->BSIM4lcgdl * Inv_L + + model->BSIM4wcgdl * Inv_W + + model->BSIM4pcgdl * Inv_LW; + pParam->BSIM4ckappas = model->BSIM4ckappas + + model->BSIM4lckappas * Inv_L + + model->BSIM4wckappas * Inv_W + + model->BSIM4pckappas * Inv_LW; + pParam->BSIM4ckappad = model->BSIM4ckappad + + model->BSIM4lckappad * Inv_L + + model->BSIM4wckappad * Inv_W + + model->BSIM4pckappad * Inv_LW; + pParam->BSIM4cf = model->BSIM4cf + + model->BSIM4lcf * Inv_L + + model->BSIM4wcf * Inv_W + + model->BSIM4pcf * Inv_LW; + pParam->BSIM4clc = model->BSIM4clc + + model->BSIM4lclc * Inv_L + + model->BSIM4wclc * Inv_W + + model->BSIM4pclc * Inv_LW; + pParam->BSIM4cle = model->BSIM4cle + + model->BSIM4lcle * Inv_L + + model->BSIM4wcle * Inv_W + + model->BSIM4pcle * Inv_LW; + pParam->BSIM4vfbcv = model->BSIM4vfbcv + + model->BSIM4lvfbcv * Inv_L + + model->BSIM4wvfbcv * Inv_W + + model->BSIM4pvfbcv * Inv_LW; + pParam->BSIM4acde = model->BSIM4acde + + model->BSIM4lacde * Inv_L + + model->BSIM4wacde * Inv_W + + model->BSIM4pacde * Inv_LW; + pParam->BSIM4moin = model->BSIM4moin + + model->BSIM4lmoin * Inv_L + + model->BSIM4wmoin * Inv_W + + model->BSIM4pmoin * Inv_LW; + pParam->BSIM4noff = model->BSIM4noff + + model->BSIM4lnoff * Inv_L + + model->BSIM4wnoff * Inv_W + + model->BSIM4pnoff * Inv_LW; + pParam->BSIM4voffcv = model->BSIM4voffcv + + model->BSIM4lvoffcv * Inv_L + + model->BSIM4wvoffcv * Inv_W + + model->BSIM4pvoffcv * Inv_LW; + + pParam->BSIM4abulkCVfactor = 1.0 + pow((pParam->BSIM4clc + / pParam->BSIM4leffCV), + pParam->BSIM4cle); + + T0 = (TRatio - 1.0); + pParam->BSIM4ua = pParam->BSIM4ua + pParam->BSIM4ua1 * T0; + pParam->BSIM4ub = pParam->BSIM4ub + pParam->BSIM4ub1 * T0; + pParam->BSIM4uc = pParam->BSIM4uc + pParam->BSIM4uc1 * T0; + if (pParam->BSIM4u0 > 1.0) + pParam->BSIM4u0 = pParam->BSIM4u0 / 1.0e4; + + pParam->BSIM4u0temp = pParam->BSIM4u0 + * pow(TRatio, pParam->BSIM4ute); + pParam->BSIM4vsattemp = pParam->BSIM4vsat - pParam->BSIM4at + * T0; + if (pParam->BSIM4eu < 0.0) + { pParam->BSIM4eu = 0.0; + printf("Warning: eu has been negative; reset to 0.0.\n"); + } + + + PowWeffWr = pow(pParam->BSIM4weffCJ * 1.0e6, pParam->BSIM4wr) * here->BSIM4nf; + /* External Rd(V) */ + T1 = pParam->BSIM4rdw + pParam->BSIM4prt * T0; + if (T1 < 0.0) + { T1 = 0.0; + printf("Warning: Rdw at current temperature is negative; set to 0.\n"); + } + T2 = model->BSIM4rdwmin + pParam->BSIM4prt * T0; + if (T2 < 0.0) + { T2 = 0.0; + printf("Warning: Rdwmin at current temperature is negative; set to 0.\n"); + } + pParam->BSIM4rd0 = T1 / PowWeffWr; + pParam->BSIM4rdwmin = T2 / PowWeffWr; + + + /* External Rs(V) */ + T1 = pParam->BSIM4rsw + pParam->BSIM4prt * T0; + if (T1 < 0.0) + { T1 = 0.0; + printf("Warning: Rsw at current temperature is negative; set to 0.\n"); + } + T2 = model->BSIM4rswmin + pParam->BSIM4prt * T0; + if (T2 < 0.0) + { T2 = 0.0; + printf("Warning: Rswmin at current temperature is negative; set to 0.\n"); + } + pParam->BSIM4rs0 = T1 / PowWeffWr; + pParam->BSIM4rswmin = T2 / PowWeffWr; + + /* Internal Rds(V) in IV */ + pParam->BSIM4rds0 = (pParam->BSIM4rdsw + pParam->BSIM4prt * T0) + * here->BSIM4nf / PowWeffWr; + pParam->BSIM4rdswmin = (model->BSIM4rdswmin + pParam->BSIM4prt * T0) + * here->BSIM4nf / PowWeffWr; + + pParam->BSIM4cgdo = (model->BSIM4cgdo + pParam->BSIM4cf) + * pParam->BSIM4weffCV; + pParam->BSIM4cgso = (model->BSIM4cgso + pParam->BSIM4cf) + * pParam->BSIM4weffCV; + pParam->BSIM4cgbo = model->BSIM4cgbo * pParam->BSIM4leffCV * here->BSIM4nf; + + if (!model->BSIM4ndepGiven && model->BSIM4gamma1Given) + { T0 = pParam->BSIM4gamma1 * model->BSIM4coxe; + pParam->BSIM4ndep = 3.01248e22 * T0 * T0; + } + + pParam->BSIM4phi = Vtm0 * log(pParam->BSIM4ndep / ni) + + pParam->BSIM4phin + 0.4; + + pParam->BSIM4sqrtPhi = sqrt(pParam->BSIM4phi); + pParam->BSIM4phis3 = pParam->BSIM4sqrtPhi * pParam->BSIM4phi; + + pParam->BSIM4Xdep0 = sqrt(2.0 * EPSSI / (Charge_q + * pParam->BSIM4ndep * 1.0e6)) + * pParam->BSIM4sqrtPhi; + pParam->BSIM4sqrtXdep0 = sqrt(pParam->BSIM4Xdep0); + pParam->BSIM4litl = sqrt(3.0 * pParam->BSIM4xj + * model->BSIM4toxe); + pParam->BSIM4vbi = Vtm0 * log(pParam->BSIM4nsd + * pParam->BSIM4ndep / (ni * ni)); + + if (pParam->BSIM4ngate > 0.0) + { pParam->BSIM4vfbsd = Vtm0 * log(pParam->BSIM4ngate + / pParam->BSIM4nsd); + } + else + pParam->BSIM4vfbsd = 0.0; + + pParam->BSIM4cdep0 = sqrt(Charge_q * EPSSI + * pParam->BSIM4ndep * 1.0e6 / 2.0 + / pParam->BSIM4phi); + + pParam->BSIM4ToxRatio = exp(pParam->BSIM4ntox + * log(model->BSIM4toxref / model->BSIM4toxe)) + / model->BSIM4toxe / model->BSIM4toxe; + pParam->BSIM4ToxRatioEdge = exp(pParam->BSIM4ntox + * log(model->BSIM4toxref + / (model->BSIM4toxe * pParam->BSIM4poxedge))) + / model->BSIM4toxe / model->BSIM4toxe + / pParam->BSIM4poxedge / pParam->BSIM4poxedge; + pParam->BSIM4Aechvb = (model->BSIM4type == NMOS) ? 4.97232e-7 : 3.42537e-7; + pParam->BSIM4Bechvb = (model->BSIM4type == NMOS) ? 7.45669e11 : 1.16645e12; + pParam->BSIM4AechvbEdge = pParam->BSIM4Aechvb * pParam->BSIM4weff + * pParam->BSIM4dlcig * pParam->BSIM4ToxRatioEdge; + pParam->BSIM4BechvbEdge = -pParam->BSIM4Bechvb + * model->BSIM4toxe * pParam->BSIM4poxedge; + pParam->BSIM4Aechvb *= pParam->BSIM4weff * pParam->BSIM4leff + * pParam->BSIM4ToxRatio; + pParam->BSIM4Bechvb *= -model->BSIM4toxe; + + + pParam->BSIM4mstar = 0.5 + atan(pParam->BSIM4minv) / PI; + pParam->BSIM4voffcbn = pParam->BSIM4voff + model->BSIM4voffl / pParam->BSIM4leff; + + pParam->BSIM4ldeb = sqrt(EPSSI * Vtm0 / (Charge_q + * pParam->BSIM4ndep * 1.0e6)) / 3.0; + pParam->BSIM4acde *= pow((pParam->BSIM4ndep / 2.0e16), -0.25); + + + if (model->BSIM4k1Given || model->BSIM4k2Given) + { if (!model->BSIM4k1Given) + { fprintf(stdout, "Warning: k1 should be specified with k2.\n"); + pParam->BSIM4k1 = 0.53; + } + if (!model->BSIM4k2Given) + { fprintf(stdout, "Warning: k2 should be specified with k1.\n"); + pParam->BSIM4k2 = -0.0186; + } + if (model->BSIM4nsubGiven) + fprintf(stdout, "Warning: nsub is ignored because k1 or k2 is given.\n"); + if (model->BSIM4xtGiven) + fprintf(stdout, "Warning: xt is ignored because k1 or k2 is given.\n"); + if (model->BSIM4vbxGiven) + fprintf(stdout, "Warning: vbx is ignored because k1 or k2 is given.\n"); + if (model->BSIM4gamma1Given) + fprintf(stdout, "Warning: gamma1 is ignored because k1 or k2 is given.\n"); + if (model->BSIM4gamma2Given) + fprintf(stdout, "Warning: gamma2 is ignored because k1 or k2 is given.\n"); + } + else + { if (!model->BSIM4vbxGiven) + pParam->BSIM4vbx = pParam->BSIM4phi - 7.7348e-4 + * pParam->BSIM4ndep + * pParam->BSIM4xt * pParam->BSIM4xt; + if (pParam->BSIM4vbx > 0.0) + pParam->BSIM4vbx = -pParam->BSIM4vbx; + if (pParam->BSIM4vbm > 0.0) + pParam->BSIM4vbm = -pParam->BSIM4vbm; + + if (!model->BSIM4gamma1Given) + pParam->BSIM4gamma1 = 5.753e-12 + * sqrt(pParam->BSIM4ndep) + / model->BSIM4coxe; + if (!model->BSIM4gamma2Given) + pParam->BSIM4gamma2 = 5.753e-12 + * sqrt(pParam->BSIM4nsub) + / model->BSIM4coxe; + + T0 = pParam->BSIM4gamma1 - pParam->BSIM4gamma2; + T1 = sqrt(pParam->BSIM4phi - pParam->BSIM4vbx) + - pParam->BSIM4sqrtPhi; + T2 = sqrt(pParam->BSIM4phi * (pParam->BSIM4phi + - pParam->BSIM4vbm)) - pParam->BSIM4phi; + pParam->BSIM4k2 = T0 * T1 / (2.0 * T2 + pParam->BSIM4vbm); + pParam->BSIM4k1 = pParam->BSIM4gamma2 - 2.0 + * pParam->BSIM4k2 * sqrt(pParam->BSIM4phi + - pParam->BSIM4vbm); + } + + if (pParam->BSIM4k2 < 0.0) + { T0 = 0.5 * pParam->BSIM4k1 / pParam->BSIM4k2; + pParam->BSIM4vbsc = 0.9 * (pParam->BSIM4phi - T0 * T0); + if (pParam->BSIM4vbsc > -3.0) + pParam->BSIM4vbsc = -3.0; + else if (pParam->BSIM4vbsc < -30.0) + pParam->BSIM4vbsc = -30.0; + } + else + { pParam->BSIM4vbsc = -30.0; + } + if (pParam->BSIM4vbsc > pParam->BSIM4vbm) + pParam->BSIM4vbsc = pParam->BSIM4vbm; + + if (!model->BSIM4vfbGiven) + { if (model->BSIM4vth0Given) + { pParam->BSIM4vfb = model->BSIM4type * pParam->BSIM4vth0 + - pParam->BSIM4phi - pParam->BSIM4k1 + * pParam->BSIM4sqrtPhi; + } + else + { pParam->BSIM4vfb = -1.0; + } + } + if (!model->BSIM4vth0Given) + { pParam->BSIM4vth0 = model->BSIM4type * (pParam->BSIM4vfb + + pParam->BSIM4phi + pParam->BSIM4k1 + * pParam->BSIM4sqrtPhi); + } + + pParam->BSIM4k1ox = pParam->BSIM4k1 * model->BSIM4toxe + / model->BSIM4toxm; + pParam->BSIM4k2ox = pParam->BSIM4k2 * model->BSIM4toxe + / model->BSIM4toxm; + + T3 = model->BSIM4type * pParam->BSIM4vth0 + - pParam->BSIM4vfb - pParam->BSIM4phi; + T4 = T3 + T3; + T5 = 2.5 * T3; + pParam->BSIM4vtfbphi1 = (model->BSIM4type == NMOS) ? T4 : T5; + if (pParam->BSIM4vtfbphi1 < 0.0) + pParam->BSIM4vtfbphi1 = 0.0; + + pParam->BSIM4vtfbphi2 = 4.0 * T3; + if (pParam->BSIM4vtfbphi2 < 0.0) + pParam->BSIM4vtfbphi2 = 0.0; + + tmp = sqrt(EPSSI / (model->BSIM4epsrox * EPS0) + * model->BSIM4toxe * pParam->BSIM4Xdep0); + T0 = pParam->BSIM4dsub * pParam->BSIM4leff / tmp; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + pParam->BSIM4theta0vb0 = T1 / T4; + } + else + pParam->BSIM4theta0vb0 = 1.0 / (MAX_EXP - 2.0); + + T0 = pParam->BSIM4drout * pParam->BSIM4leff / tmp; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + T5 = T1 / T4; + } + else + T5 = 1.0 / (MAX_EXP - 2.0); /* 3.0 * MIN_EXP omitted */ + pParam->BSIM4thetaRout = pParam->BSIM4pdibl1 * T5 + + pParam->BSIM4pdibl2; + + tmp = sqrt(pParam->BSIM4Xdep0); + tmp1 = pParam->BSIM4vbi - pParam->BSIM4phi; + tmp2 = model->BSIM4factor1 * tmp; + + T0 = pParam->BSIM4dvt1w * pParam->BSIM4weff + * pParam->BSIM4leff / tmp2; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + T8 = T1 / T4; + } + else + T8 = 1.0 / (MAX_EXP - 2.0); + T0 = pParam->BSIM4dvt0w * T8; + T8 = T0 * tmp1; + + T0 = pParam->BSIM4dvt1 * pParam->BSIM4leff / tmp2; + if (T0 < EXP_THRESHOLD) + { T1 = exp(T0); + T2 = T1 - 1.0; + T3 = T2 * T2; + T4 = T3 + 2.0 * T1 * MIN_EXP; + T9 = T1 / T4; + } + else + T9 = 1.0 / (MAX_EXP - 2.0); + T9 = pParam->BSIM4dvt0 * T9 * tmp1; + + T4 = model->BSIM4toxe * pParam->BSIM4phi + / (pParam->BSIM4weff + pParam->BSIM4w0); + + T0 = sqrt(1.0 + pParam->BSIM4lpe0 / pParam->BSIM4leff); + T5 = pParam->BSIM4k1ox * (T0 - 1.0) * pParam->BSIM4sqrtPhi + + (pParam->BSIM4kt1 + pParam->BSIM4kt1l / pParam->BSIM4leff) + * (TRatio - 1.0); + + tmp3 = model->BSIM4type * pParam->BSIM4vth0 + - T8 - T9 + pParam->BSIM4k3 * T4 + T5; + pParam->BSIM4vfbzb = tmp3 - pParam->BSIM4phi - pParam->BSIM4k1 + * pParam->BSIM4sqrtPhi; /* End of vfbzb */ + } /* End of SizeNotFound */ + + here->BSIM4cgso = pParam->BSIM4cgso; + here->BSIM4cgdo = pParam->BSIM4cgdo; + + if (here->BSIM4rbodyMod) + { if (here->BSIM4rbdb < 1.0e-3) + here->BSIM4grbdb = 1.0e3; /* in mho */ + else + here->BSIM4grbdb = model->BSIM4gbmin + 1.0 / here->BSIM4rbdb; + if (here->BSIM4rbpb < 1.0e-3) + here->BSIM4grbpb = 1.0e3; + else + here->BSIM4grbpb = model->BSIM4gbmin + 1.0 / here->BSIM4rbpb; + if (here->BSIM4rbps < 1.0e-3) + here->BSIM4grbps = 1.0e3; + else + here->BSIM4grbps = model->BSIM4gbmin + 1.0 / here->BSIM4rbps; + if (here->BSIM4rbsb < 1.0e-3) + here->BSIM4grbsb = 1.0e3; + else + here->BSIM4grbsb = model->BSIM4gbmin + 1.0 / here->BSIM4rbsb; + if (here->BSIM4rbpd < 1.0e-3) + here->BSIM4grbpd = 1.0e3; + else + here->BSIM4grbpd = model->BSIM4gbmin + 1.0 / here->BSIM4rbpd; + } + + + /* + * Process geomertry dependent parasitics + */ + + here->BSIM4grgeltd = model->BSIM4rshg * (model->BSIM4xgw + + pParam->BSIM4weffCJ / 3.0 / model->BSIM4ngcon) / + (model->BSIM4ngcon * here->BSIM4nf * + (here->BSIM4l - model->BSIM4xgl)); + if (here->BSIM4grgeltd > 0.0) + here->BSIM4grgeltd = 1.0 / here->BSIM4grgeltd; + else + { here->BSIM4grgeltd = 1.0e3; /* mho */ + if (here->BSIM4rgateMod != 0) + printf("Warning: The gate conductance reset to 1.0e3 mho.\n"); + } + + DMCGeff = model->BSIM4dmcg - model->BSIM4dmcgt; + DMCIeff = model->BSIM4dmci; + DMDGeff = model->BSIM4dmdg - model->BSIM4dmcgt; + + if (here->BSIM4sourcePerimeterGiven) + { if (model->BSIM4perMod == 0) + here->BSIM4Pseff = here->BSIM4sourcePerimeter; + else + here->BSIM4Pseff = here->BSIM4sourcePerimeter + - pParam->BSIM4weffCJ * here->BSIM4nf; + } + else + BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, + pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, + &(here->BSIM4Pseff), &dumPd, &dumAs, &dumAd); + + if (here->BSIM4drainPerimeterGiven) + { if (model->BSIM4perMod == 0) + here->BSIM4Pdeff = here->BSIM4drainPerimeter; + else + here->BSIM4Pdeff = here->BSIM4drainPerimeter + - pParam->BSIM4weffCJ * here->BSIM4nf; + } + else + BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, + pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, + &dumPs, &(here->BSIM4Pdeff), &dumAs, &dumAd); + + if (here->BSIM4sourceAreaGiven) + here->BSIM4Aseff = here->BSIM4sourceArea; + else + BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, + pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, + &dumPs, &dumPd, &(here->BSIM4Aseff), &dumAd); + + if (here->BSIM4drainAreaGiven) + here->BSIM4Adeff = here->BSIM4drainArea; + else + BSIM4PAeffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4min, + pParam->BSIM4weffCJ, DMCGeff, DMCIeff, DMDGeff, + &dumPs, &dumPd, &dumAs, &(here->BSIM4Adeff)); + + /* Processing S/D resistance and conductance below */ + if (here->BSIM4rgeoMod == 0) + here->BSIM4sourceConductance = 0.0; + else if (here->BSIM4sourceSquaresGiven) + here->BSIM4sourceConductance = model->BSIM4sheetResistance + * here->BSIM4sourceSquares; + else + BSIM4RdseffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4rgeoMod, here->BSIM4min, + pParam->BSIM4weffCJ, model->BSIM4sheetResistance, + DMCGeff, DMCIeff, DMDGeff, 1, &(here->BSIM4sourceConductance)); + + if (here->BSIM4rgeoMod == 0) + here->BSIM4drainConductance = 0.0; + else if (here->BSIM4drainSquaresGiven) + here->BSIM4drainConductance = model->BSIM4sheetResistance + * here->BSIM4drainSquares; + else + BSIM4RdseffGeo(here->BSIM4nf, here->BSIM4geoMod, here->BSIM4rgeoMod, here->BSIM4min, + pParam->BSIM4weffCJ, model->BSIM4sheetResistance, + DMCGeff, DMCIeff, DMDGeff, 0, &(here->BSIM4drainConductance)); + + if (here->BSIM4drainConductance > 0.0) + here->BSIM4drainConductance = 1.0 / here->BSIM4drainConductance; + else + here->BSIM4drainConductance = 0.0; + + if (here->BSIM4sourceConductance > 0.0) + here->BSIM4sourceConductance = 1.0 / here->BSIM4sourceConductance; + else + here->BSIM4sourceConductance = 0.0; + + + if (((here->BSIM4rgeoMod != 0) || (model->BSIM4rdsMod != 0) + || (model->BSIM4tnoiMod != 0)) && (here->BSIM4sourceConductance == 0.0)) + { here->BSIM4sourceConductance = 1.0e3; /* mho */ + printf("Warning: Source conductance reset to 1.0e3 mho.\n"); + } + if (((here->BSIM4rgeoMod != 0) || (model->BSIM4rdsMod != 0) + || (model->BSIM4tnoiMod != 0)) && (here->BSIM4drainConductance == 0.0)) + { here->BSIM4drainConductance = 1.0e3; /* mho */ + printf("Warning: Drain conductance reset to 1.0e3 mho.\n"); + } /* End of Rsd processing */ + + + Nvtms = model->BSIM4vtm * model->BSIM4SjctEmissionCoeff; + if ((here->BSIM4Aseff <= 0.0) && (here->BSIM4Pseff <= 0.0)) + { SourceSatCurrent = 1.0e-14; + } + else + { SourceSatCurrent = here->BSIM4Aseff * model->BSIM4SjctTempSatCurDensity + + here->BSIM4Pseff * model->BSIM4SjctSidewallTempSatCurDensity + + pParam->BSIM4weffCJ * here->BSIM4nf + * model->BSIM4SjctGateSidewallTempSatCurDensity; + } + if (SourceSatCurrent > 0.0) + { switch(model->BSIM4dioMod) + { case 0: + if ((model->BSIM4bvs / Nvtms) > EXP_THRESHOLD) + here->BSIM4XExpBVS = model->BSIM4xjbvs * MIN_EXP; + else + here->BSIM4XExpBVS = model->BSIM4xjbvs * exp(-model->BSIM4bvs / Nvtms); + break; + case 1: + BSIM4DioIjthVjmEval(Nvtms, model->BSIM4ijthsfwd, SourceSatCurrent, + 0.0, &(here->BSIM4vjsmFwd)); + here->BSIM4IVjsmFwd = SourceSatCurrent * exp(here->BSIM4vjsmFwd / Nvtms); + break; + case 2: + if ((model->BSIM4bvs / Nvtms) > EXP_THRESHOLD) + { here->BSIM4XExpBVS = model->BSIM4xjbvs * MIN_EXP; + tmp = MIN_EXP; + } + else + { here->BSIM4XExpBVS = exp(-model->BSIM4bvs / Nvtms); + tmp = here->BSIM4XExpBVS; + here->BSIM4XExpBVS *= model->BSIM4xjbvs; + } + + BSIM4DioIjthVjmEval(Nvtms, model->BSIM4ijthsfwd, SourceSatCurrent, + here->BSIM4XExpBVS, &(here->BSIM4vjsmFwd)); + T0 = exp(here->BSIM4vjsmFwd / Nvtms); + here->BSIM4IVjsmFwd = SourceSatCurrent * (T0 - here->BSIM4XExpBVS / T0 + + here->BSIM4XExpBVS - 1.0); + here->BSIM4SslpFwd = SourceSatCurrent + * (T0 + here->BSIM4XExpBVS / T0) / Nvtms; + + T2 = model->BSIM4ijthsrev / SourceSatCurrent; + if (T2 < 1.0) + { T2 = 10.0; + fprintf(stderr, "Warning: ijthsrev too small and set to 10 times IsbSat.\n"); + } + here->BSIM4vjsmRev = -model->BSIM4bvs + - Nvtms * log((T2 - 1.0) / model->BSIM4xjbvs); + T1 = model->BSIM4xjbvs * exp(-(model->BSIM4bvs + + here->BSIM4vjsmRev) / Nvtms); + here->BSIM4IVjsmRev = SourceSatCurrent * (1.0 + T1); + here->BSIM4SslpRev = -SourceSatCurrent * T1 / Nvtms; + break; + default: + printf("Specified dioMod = %d not matched\n", model->BSIM4dioMod); + } + } + + Nvtmd = model->BSIM4vtm * model->BSIM4DjctEmissionCoeff; + if ((here->BSIM4Adeff <= 0.0) && (here->BSIM4Pdeff <= 0.0)) + { DrainSatCurrent = 1.0e-14; + } + else + { DrainSatCurrent = here->BSIM4Adeff * model->BSIM4DjctTempSatCurDensity + + here->BSIM4Pdeff * model->BSIM4DjctSidewallTempSatCurDensity + + pParam->BSIM4weffCJ * here->BSIM4nf + * model->BSIM4DjctGateSidewallTempSatCurDensity; + } + if (DrainSatCurrent > 0.0) + { switch(model->BSIM4dioMod) + { case 0: + if ((model->BSIM4bvd / Nvtmd) > EXP_THRESHOLD) + here->BSIM4XExpBVD = model->BSIM4xjbvd * MIN_EXP; + else + here->BSIM4XExpBVD = model->BSIM4xjbvd * exp(-model->BSIM4bvd / Nvtmd); + break; + case 1: + BSIM4DioIjthVjmEval(Nvtmd, model->BSIM4ijthdfwd, DrainSatCurrent, + 0.0, &(here->BSIM4vjdmFwd)); + here->BSIM4IVjdmFwd = DrainSatCurrent * exp(here->BSIM4vjdmFwd / Nvtmd); + break; + case 2: + if ((model->BSIM4bvd / Nvtmd) > EXP_THRESHOLD) + { here->BSIM4XExpBVD = model->BSIM4xjbvd * MIN_EXP; + tmp = MIN_EXP; + } + else + { here->BSIM4XExpBVD = exp(-model->BSIM4bvd / Nvtmd); + tmp = here->BSIM4XExpBVD; + here->BSIM4XExpBVD *= model->BSIM4xjbvd; + } + + BSIM4DioIjthVjmEval(Nvtmd, model->BSIM4ijthdfwd, DrainSatCurrent, + here->BSIM4XExpBVD, &(here->BSIM4vjdmFwd)); + T0 = exp(here->BSIM4vjdmFwd / Nvtmd); + here->BSIM4IVjdmFwd = DrainSatCurrent * (T0 - here->BSIM4XExpBVD / T0 + + here->BSIM4XExpBVD - 1.0); + here->BSIM4DslpFwd = DrainSatCurrent + * (T0 + here->BSIM4XExpBVD / T0) / Nvtmd; + + T2 = model->BSIM4ijthdrev / DrainSatCurrent; + if (T2 < 1.0) + { T2 = 10.0; + fprintf(stderr, "Warning: ijthdrev too small and set to 10 times IdbSat.\n"); + } + here->BSIM4vjdmRev = -model->BSIM4bvd + - Nvtms * log((T2 - 1.0) / model->BSIM4xjbvd); + T1 = model->BSIM4xjbvd * exp(-(model->BSIM4bvd + + here->BSIM4vjdmRev) / Nvtmd); + here->BSIM4IVjdmRev = DrainSatCurrent * (1.0 + T1); + here->BSIM4DslpRev = -DrainSatCurrent * T1 / Nvtmd; + break; + default: + printf("Specified dioMod = %d not matched\n", model->BSIM4dioMod); + } + } + + if (BSIM4checkModel(model, here, ckt)) + { IFuid namarray[2]; + namarray[0] = model->BSIM4modName; + namarray[1] = here->BSIM4name; + (*(SPfrontEnd->IFerror)) (ERR_FATAL, "Fatal error(s) detected during BSIM4.0.0 parameter checking for %s in model %s", namarray); + return(E_BADPARM); + } + } /* End instance */ + } + return(OK); +} diff --git a/src/spicelib/devices/bsim4/b4trunc.c b/src/spicelib/devices/bsim4/b4trunc.c new file mode 100644 index 000000000..bb39b7901 --- /dev/null +++ b/src/spicelib/devices/bsim4/b4trunc.c @@ -0,0 +1,59 @@ +/**** BSIM4.0.0, Released by Weidong Liu 3/24/2000 ****/ + +/********** + * Copyright 2000 Regents of the University of California. All rights reserved. + * File: b4trunc.c of BSIM4.0.0. + * Authors: Weidong Liu, Kanyu M. Cao, Xiaodong Jin, Chenming Hu. + * Project Director: Prof. Chenming Hu. + **********/ + +#include "ngspice.h" +#include +#include +#include "cktdefs.h" +#include "bsim4def.h" +#include "sperror.h" + + +int +BSIM4trunc(inModel,ckt,timeStep) +GENmodel *inModel; +register CKTcircuit *ckt; +double *timeStep; +{ +register BSIM4model *model = (BSIM4model*)inModel; +register BSIM4instance *here; + +#ifdef STEPDEBUG + double debugtemp; +#endif /* STEPDEBUG */ + + for (; model != NULL; model = model->BSIM4nextModel) + { for (here = model->BSIM4instances; here != NULL; + here = here->BSIM4nextInstance) + { + if (here->BSIM4owner != ARCHme) continue; +#ifdef STEPDEBUG + debugtemp = *timeStep; +#endif /* STEPDEBUG */ + CKTterr(here->BSIM4qb,ckt,timeStep); + CKTterr(here->BSIM4qg,ckt,timeStep); + CKTterr(here->BSIM4qd,ckt,timeStep); + if (here->BSIM4trnqsMod) + CKTterr(here->BSIM4qcdump,ckt,timeStep); + if (here->BSIM4rbodyMod) + { CKTterr(here->BSIM4qbs,ckt,timeStep); + CKTterr(here->BSIM4qbd,ckt,timeStep); + } + if (here->BSIM4rgateMod == 3) + CKTterr(here->BSIM4qgmid,ckt,timeStep); +#ifdef STEPDEBUG + if(debugtemp != *timeStep) + { printf("device %s reduces step from %g to %g\n", + here->BSIM4name,debugtemp,*timeStep); + } +#endif /* STEPDEBUG */ + } + } + return(OK); +} diff --git a/src/spicelib/devices/bsim4/bsim4def.h b/src/spicelib/devices/bsim4/bsim4def.h new file mode 100644 index 000000000..0450ad2cf --- /dev/null +++ b/src/spicelib/devices/bsim4/bsim4def.h @@ -0,0 +1,2612 @@ +/********** +Copyright 2000 Regents of the University of California. All rights reserved. +Author: 2000 Weidong Liu. +File: bsim4def.h +**********/ + +#ifndef BSIM4 +#define BSIM4 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + +typedef struct sBSIM4instance +{ + struct sBSIM4model *BSIM4modPtr; + struct sBSIM4instance *BSIM4nextInstance; + IFuid BSIM4name; + int BSIM4owner; /* Number of owner process */ + int BSIM4states; /* index into state table for this device */ + int BSIM4dNode; + int BSIM4gNodeExt; + int BSIM4sNode; + int BSIM4bNode; + int BSIM4dNodePrime; + int BSIM4gNodePrime; + int BSIM4gNodeMid; + int BSIM4sNodePrime; + int BSIM4bNodePrime; + int BSIM4dbNode; + int BSIM4sbNode; + int BSIM4qNode; + + double BSIM4ueff; + double BSIM4thetavth; + double BSIM4von; + double BSIM4vdsat; + double BSIM4cgdo; + double BSIM4qgdo; + double BSIM4cgso; + double BSIM4qgso; + double BSIM4grbsb; + double BSIM4grbdb; + double BSIM4grbpb; + double BSIM4grbps; + double BSIM4grbpd; + + double BSIM4vjsmFwd; + double BSIM4vjsmRev; + double BSIM4vjdmFwd; + double BSIM4vjdmRev; + double BSIM4XExpBVS; + double BSIM4XExpBVD; + double BSIM4SslpFwd; + double BSIM4SslpRev; + double BSIM4DslpFwd; + double BSIM4DslpRev; + double BSIM4IVjsmFwd; + double BSIM4IVjsmRev; + double BSIM4IVjdmFwd; + double BSIM4IVjdmRev; + + double BSIM4grgeltd; + double BSIM4Pseff; + double BSIM4Pdeff; + double BSIM4Aseff; + double BSIM4Adeff; + + double BSIM4l; + double BSIM4w; + double BSIM4drainArea; + double BSIM4sourceArea; + double BSIM4drainSquares; + double BSIM4sourceSquares; + double BSIM4drainPerimeter; + double BSIM4sourcePerimeter; + double BSIM4sourceConductance; + double BSIM4drainConductance; + double BSIM4rbdb; + double BSIM4rbsb; + double BSIM4rbpb; + double BSIM4rbps; + double BSIM4rbpd; + + double BSIM4icVDS; + double BSIM4icVGS; + double BSIM4icVBS; + double BSIM4nf; + int BSIM4off; + int BSIM4mode; + int BSIM4trnqsMod; + int BSIM4acnqsMod; + int BSIM4rbodyMod; + int BSIM4rgateMod; + int BSIM4geoMod; + int BSIM4rgeoMod; + int BSIM4min; + + /* OP point */ + double BSIM4Vgsteff; + double BSIM4Vdseff; + double BSIM4nstar; + double BSIM4Abulk; + double BSIM4EsatL; + double BSIM4AbovVgst2Vtm; + double BSIM4qinv; + double BSIM4cd; + double BSIM4cbs; + double BSIM4cbd; + double BSIM4csub; + double BSIM4Igidl; + double BSIM4gm; + double BSIM4gds; + double BSIM4gmbs; + double BSIM4gbd; + double BSIM4gbs; + + double BSIM4gbbs; + double BSIM4gbgs; + double BSIM4gbds; + double BSIM4ggidld; + double BSIM4ggidlg; + double BSIM4ggidls; + double BSIM4ggidlb; + + double BSIM4Igcs; + double BSIM4gIgcsg; + double BSIM4gIgcsd; + double BSIM4gIgcss; + double BSIM4gIgcsb; + double BSIM4Igcd; + double BSIM4gIgcdg; + double BSIM4gIgcdd; + double BSIM4gIgcds; + double BSIM4gIgcdb; + + double BSIM4Igs; + double BSIM4gIgsg; + double BSIM4gIgss; + double BSIM4Igd; + double BSIM4gIgdg; + double BSIM4gIgdd; + + double BSIM4Igb; + double BSIM4gIgbg; + double BSIM4gIgbd; + double BSIM4gIgbs; + double BSIM4gIgbb; + + double BSIM4grdsw; + double BSIM4IdovVds; + double BSIM4gcrg; + double BSIM4gcrgd; + double BSIM4gcrgg; + double BSIM4gcrgs; + double BSIM4gcrgb; + + double BSIM4gstot; + double BSIM4gstotd; + double BSIM4gstotg; + double BSIM4gstots; + double BSIM4gstotb; + + double BSIM4gdtot; + double BSIM4gdtotd; + double BSIM4gdtotg; + double BSIM4gdtots; + double BSIM4gdtotb; + + double BSIM4cggb; + double BSIM4cgdb; + double BSIM4cgsb; + double BSIM4cbgb; + double BSIM4cbdb; + double BSIM4cbsb; + double BSIM4cdgb; + double BSIM4cddb; + double BSIM4cdsb; + double BSIM4capbd; + double BSIM4capbs; + + double BSIM4cqgb; + double BSIM4cqdb; + double BSIM4cqsb; + double BSIM4cqbb; + + double BSIM4qgate; + double BSIM4qbulk; + double BSIM4qdrn; + + double BSIM4qchqs; + double BSIM4taunet; + double BSIM4gtau; + double BSIM4gtg; + double BSIM4gtd; + double BSIM4gts; + double BSIM4gtb; + + struct bsim4SizeDependParam *pParam; + + unsigned BSIM4lGiven :1; + unsigned BSIM4wGiven :1; + unsigned BSIM4nfGiven :1; + unsigned BSIM4minGiven :1; + unsigned BSIM4drainAreaGiven :1; + unsigned BSIM4sourceAreaGiven :1; + unsigned BSIM4drainSquaresGiven :1; + unsigned BSIM4sourceSquaresGiven :1; + unsigned BSIM4drainPerimeterGiven :1; + unsigned BSIM4sourcePerimeterGiven :1; + unsigned BSIM4rbdbGiven :1; + unsigned BSIM4rbsbGiven :1; + unsigned BSIM4rbpbGiven :1; + unsigned BSIM4rbpdGiven :1; + unsigned BSIM4rbpsGiven :1; + unsigned BSIM4icVDSGiven :1; + unsigned BSIM4icVGSGiven :1; + unsigned BSIM4icVBSGiven :1; + unsigned BSIM4trnqsModGiven :1; + unsigned BSIM4acnqsModGiven :1; + unsigned BSIM4rbodyModGiven :1; + unsigned BSIM4rgateModGiven :1; + unsigned BSIM4geoModGiven :1; + unsigned BSIM4rgeoModGiven :1; + + double *BSIM4DPdPtr; + double *BSIM4DPdpPtr; + double *BSIM4DPgpPtr; + double *BSIM4DPgmPtr; + double *BSIM4DPspPtr; + double *BSIM4DPbpPtr; + double *BSIM4DPdbPtr; + + double *BSIM4DdPtr; + double *BSIM4DdpPtr; + + double *BSIM4GPdpPtr; + double *BSIM4GPgpPtr; + double *BSIM4GPgmPtr; + double *BSIM4GPgePtr; + double *BSIM4GPspPtr; + double *BSIM4GPbpPtr; + + double *BSIM4GMdpPtr; + double *BSIM4GMgpPtr; + double *BSIM4GMgmPtr; + double *BSIM4GMgePtr; + double *BSIM4GMspPtr; + double *BSIM4GMbpPtr; + + double *BSIM4GEdpPtr; + double *BSIM4GEgpPtr; + double *BSIM4GEgmPtr; + double *BSIM4GEgePtr; + double *BSIM4GEspPtr; + double *BSIM4GEbpPtr; + + double *BSIM4SPdpPtr; + double *BSIM4SPgpPtr; + double *BSIM4SPgmPtr; + double *BSIM4SPsPtr; + double *BSIM4SPspPtr; + double *BSIM4SPbpPtr; + double *BSIM4SPsbPtr; + + double *BSIM4SspPtr; + double *BSIM4SsPtr; + + double *BSIM4BPdpPtr; + double *BSIM4BPgpPtr; + double *BSIM4BPgmPtr; + double *BSIM4BPspPtr; + double *BSIM4BPdbPtr; + double *BSIM4BPbPtr; + double *BSIM4BPsbPtr; + double *BSIM4BPbpPtr; + + double *BSIM4DBdpPtr; + double *BSIM4DBdbPtr; + double *BSIM4DBbpPtr; + double *BSIM4DBbPtr; + + double *BSIM4SBspPtr; + double *BSIM4SBbpPtr; + double *BSIM4SBbPtr; + double *BSIM4SBsbPtr; + + double *BSIM4BdbPtr; + double *BSIM4BbpPtr; + double *BSIM4BsbPtr; + double *BSIM4BbPtr; + + double *BSIM4DgpPtr; + double *BSIM4DspPtr; + double *BSIM4DbpPtr; + double *BSIM4SdpPtr; + double *BSIM4SgpPtr; + double *BSIM4SbpPtr; + + double *BSIM4QdpPtr; + double *BSIM4QgpPtr; + double *BSIM4QspPtr; + double *BSIM4QbpPtr; + double *BSIM4QqPtr; + double *BSIM4DPqPtr; + double *BSIM4GPqPtr; + double *BSIM4SPqPtr; + +#define BSIM4vbd BSIM4states+ 0 +#define BSIM4vbs BSIM4states+ 1 +#define BSIM4vgs BSIM4states+ 2 +#define BSIM4vds BSIM4states+ 3 +#define BSIM4vdbs BSIM4states+ 4 +#define BSIM4vdbd BSIM4states+ 5 +#define BSIM4vsbs BSIM4states+ 6 +#define BSIM4vges BSIM4states+ 7 +#define BSIM4vgms BSIM4states+ 8 +#define BSIM4vses BSIM4states+ 9 +#define BSIM4vdes BSIM4states+ 10 + +#define BSIM4qb BSIM4states+ 11 +#define BSIM4cqb BSIM4states+ 12 +#define BSIM4qg BSIM4states+ 13 +#define BSIM4cqg BSIM4states+ 14 +#define BSIM4qd BSIM4states+ 15 +#define BSIM4cqd BSIM4states+ 16 +#define BSIM4qgmid BSIM4states+ 17 +#define BSIM4cqgmid BSIM4states+ 18 + +#define BSIM4qbs BSIM4states+ 19 +#define BSIM4cqbs BSIM4states+ 20 +#define BSIM4qbd BSIM4states+ 21 +#define BSIM4cqbd BSIM4states+ 22 + +#define BSIM4qcheq BSIM4states+ 23 +#define BSIM4cqcheq BSIM4states+ 24 +#define BSIM4qcdump BSIM4states+ 25 +#define BSIM4cqcdump BSIM4states+ 26 +#define BSIM4qdef BSIM4states+ 27 + +#define BSIM4numStates 28 + + +/* indices to the array of BSIM4 NOISE SOURCES */ + +#define BSIM4RDNOIZ 0 +#define BSIM4RSNOIZ 1 +#define BSIM4RGNOIZ 2 +#define BSIM4RBPSNOIZ 3 +#define BSIM4RBPDNOIZ 4 +#define BSIM4RBPBNOIZ 5 +#define BSIM4RBSBNOIZ 6 +#define BSIM4RBDBNOIZ 7 +#define BSIM4IDNOIZ 8 +#define BSIM4FLNOIZ 9 +#define BSIM4IGSNOIZ 10 +#define BSIM4IGDNOIZ 11 +#define BSIM4IGBNOIZ 12 +#define BSIM4TOTNOIZ 13 + +#define BSIM4NSRCS 14 /* Number of BSIM4 noise sources */ + +#ifndef NONOISE + double BSIM4nVar[NSTATVARS][BSIM4NSRCS]; +#else /* NONOISE */ + double **BSIM4nVar; +#endif /* NONOISE */ + +} BSIM4instance ; + +struct bsim4SizeDependParam +{ + double Width; + double Length; + double NFinger; + + double BSIM4cdsc; + double BSIM4cdscb; + double BSIM4cdscd; + double BSIM4cit; + double BSIM4nfactor; + double BSIM4xj; + double BSIM4vsat; + double BSIM4at; + double BSIM4a0; + double BSIM4ags; + double BSIM4a1; + double BSIM4a2; + double BSIM4keta; + double BSIM4nsub; + double BSIM4ndep; + double BSIM4nsd; + double BSIM4phin; + double BSIM4ngate; + double BSIM4gamma1; + double BSIM4gamma2; + double BSIM4vbx; + double BSIM4vbi; + double BSIM4vbm; + double BSIM4vbsc; + double BSIM4xt; + double BSIM4phi; + double BSIM4litl; + double BSIM4k1; + double BSIM4kt1; + double BSIM4kt1l; + double BSIM4kt2; + double BSIM4k2; + double BSIM4k3; + double BSIM4k3b; + double BSIM4w0; + double BSIM4dvtp0; + double BSIM4dvtp1; + double BSIM4lpe0; + double BSIM4lpeb; + double BSIM4dvt0; + double BSIM4dvt1; + double BSIM4dvt2; + double BSIM4dvt0w; + double BSIM4dvt1w; + double BSIM4dvt2w; + double BSIM4drout; + double BSIM4dsub; + double BSIM4vth0; + double BSIM4ua; + double BSIM4ua1; + double BSIM4ub; + double BSIM4ub1; + double BSIM4uc; + double BSIM4uc1; + double BSIM4u0; + double BSIM4eu; + double BSIM4ute; + double BSIM4voff; + double BSIM4minv; + double BSIM4vfb; + double BSIM4delta; + double BSIM4rdsw; + double BSIM4rds0; + double BSIM4rs0; + double BSIM4rd0; + double BSIM4rsw; + double BSIM4rdw; + double BSIM4prwg; + double BSIM4prwb; + double BSIM4prt; + double BSIM4eta0; + double BSIM4etab; + double BSIM4pclm; + double BSIM4pdibl1; + double BSIM4pdibl2; + double BSIM4pdiblb; + double BSIM4fprout; + double BSIM4pdits; + double BSIM4pditsd; + double BSIM4pscbe1; + double BSIM4pscbe2; + double BSIM4pvag; + double BSIM4wr; + double BSIM4dwg; + double BSIM4dwb; + double BSIM4b0; + double BSIM4b1; + double BSIM4alpha0; + double BSIM4alpha1; + double BSIM4beta0; + double BSIM4agidl; + double BSIM4bgidl; + double BSIM4cgidl; + double BSIM4egidl; + double BSIM4aigc; + double BSIM4bigc; + double BSIM4cigc; + double BSIM4aigsd; + double BSIM4bigsd; + double BSIM4cigsd; + double BSIM4aigbacc; + double BSIM4bigbacc; + double BSIM4cigbacc; + double BSIM4aigbinv; + double BSIM4bigbinv; + double BSIM4cigbinv; + double BSIM4nigc; + double BSIM4nigbacc; + double BSIM4nigbinv; + double BSIM4ntox; + double BSIM4eigbinv; + double BSIM4pigcd; + double BSIM4poxedge; + double BSIM4xrcrg1; + double BSIM4xrcrg2; + double BSIM4fpkt; + double BSIM4plcr; + double BSIM4plcrl; + double BSIM4plcrd; + + + /* CV model */ + double BSIM4cgsl; + double BSIM4cgdl; + double BSIM4ckappas; + double BSIM4ckappad; + double BSIM4cf; + double BSIM4clc; + double BSIM4cle; + double BSIM4vfbcv; + double BSIM4noff; + double BSIM4voffcv; + double BSIM4acde; + double BSIM4moin; + +/* Pre-calculated constants */ + + double BSIM4dw; + double BSIM4dl; + double BSIM4leff; + double BSIM4weff; + + double BSIM4dwc; + double BSIM4dlc; + double BSIM4dlcig; + double BSIM4dwj; + double BSIM4leffCV; + double BSIM4weffCV; + double BSIM4weffCJ; + double BSIM4abulkCVfactor; + double BSIM4cgso; + double BSIM4cgdo; + double BSIM4cgbo; + + double BSIM4u0temp; + double BSIM4vsattemp; + double BSIM4sqrtPhi; + double BSIM4phis3; + double BSIM4Xdep0; + double BSIM4sqrtXdep0; + double BSIM4theta0vb0; + double BSIM4thetaRout; + double BSIM4mstar; + double BSIM4voffcbn; + double BSIM4rdswmin; + double BSIM4rdwmin; + double BSIM4rswmin; + double BSIM4vfbsd; + + double BSIM4cof1; + double BSIM4cof2; + double BSIM4cof3; + double BSIM4cof4; + double BSIM4cdep0; + double BSIM4vfbzb; + double BSIM4vtfbphi1; + double BSIM4vtfbphi2; + double BSIM4ToxRatio; + double BSIM4Aechvb; + double BSIM4Bechvb; + double BSIM4ToxRatioEdge; + double BSIM4AechvbEdge; + double BSIM4BechvbEdge; + double BSIM4ldeb; + double BSIM4k1ox; + double BSIM4k2ox; + + struct bsim4SizeDependParam *pNext; +}; + + +typedef struct sBSIM4model +{ + int BSIM4modType; + struct sBSIM4model *BSIM4nextModel; + BSIM4instance *BSIM4instances; + IFuid BSIM4modName; + int BSIM4type; + + int BSIM4mobMod; + int BSIM4capMod; + int BSIM4dioMod; + int BSIM4trnqsMod; + int BSIM4acnqsMod; + int BSIM4fnoiMod; + int BSIM4tnoiMod; + int BSIM4rdsMod; + int BSIM4rbodyMod; + int BSIM4rgateMod; + int BSIM4perMod; + int BSIM4geoMod; + int BSIM4igcMod; + int BSIM4igbMod; + int BSIM4binUnit; + int BSIM4paramChk; + char *BSIM4version; + double BSIM4toxe; + double BSIM4toxp; + double BSIM4toxm; + double BSIM4dtox; + double BSIM4epsrox; + double BSIM4cdsc; + double BSIM4cdscb; + double BSIM4cdscd; + double BSIM4cit; + double BSIM4nfactor; + double BSIM4xj; + double BSIM4vsat; + double BSIM4at; + double BSIM4a0; + double BSIM4ags; + double BSIM4a1; + double BSIM4a2; + double BSIM4keta; + double BSIM4nsub; + double BSIM4ndep; + double BSIM4nsd; + double BSIM4phin; + double BSIM4ngate; + double BSIM4gamma1; + double BSIM4gamma2; + double BSIM4vbx; + double BSIM4vbm; + double BSIM4xt; + double BSIM4k1; + double BSIM4kt1; + double BSIM4kt1l; + double BSIM4kt2; + double BSIM4k2; + double BSIM4k3; + double BSIM4k3b; + double BSIM4w0; + double BSIM4dvtp0; + double BSIM4dvtp1; + double BSIM4lpe0; + double BSIM4lpeb; + double BSIM4dvt0; + double BSIM4dvt1; + double BSIM4dvt2; + double BSIM4dvt0w; + double BSIM4dvt1w; + double BSIM4dvt2w; + double BSIM4drout; + double BSIM4dsub; + double BSIM4vth0; + double BSIM4eu; + double BSIM4ua; + double BSIM4ua1; + double BSIM4ub; + double BSIM4ub1; + double BSIM4uc; + double BSIM4uc1; + double BSIM4u0; + double BSIM4ute; + double BSIM4voff; + double BSIM4minv; + double BSIM4voffl; + double BSIM4delta; + double BSIM4rdsw; + double BSIM4rdswmin; + double BSIM4rdwmin; + double BSIM4rswmin; + double BSIM4rsw; + double BSIM4rdw; + double BSIM4prwg; + double BSIM4prwb; + double BSIM4prt; + double BSIM4eta0; + double BSIM4etab; + double BSIM4pclm; + double BSIM4pdibl1; + double BSIM4pdibl2; + double BSIM4pdiblb; + double BSIM4fprout; + double BSIM4pdits; + double BSIM4pditsd; + double BSIM4pditsl; + double BSIM4pscbe1; + double BSIM4pscbe2; + double BSIM4pvag; + double BSIM4wr; + double BSIM4dwg; + double BSIM4dwb; + double BSIM4b0; + double BSIM4b1; + double BSIM4alpha0; + double BSIM4alpha1; + double BSIM4beta0; + double BSIM4agidl; + double BSIM4bgidl; + double BSIM4cgidl; + double BSIM4egidl; + double BSIM4aigc; + double BSIM4bigc; + double BSIM4cigc; + double BSIM4aigsd; + double BSIM4bigsd; + double BSIM4cigsd; + double BSIM4aigbacc; + double BSIM4bigbacc; + double BSIM4cigbacc; + double BSIM4aigbinv; + double BSIM4bigbinv; + double BSIM4cigbinv; + double BSIM4nigc; + double BSIM4nigbacc; + double BSIM4nigbinv; + double BSIM4ntox; + double BSIM4eigbinv; + double BSIM4pigcd; + double BSIM4poxedge; + double BSIM4toxref; + double BSIM4ijthdfwd; + double BSIM4ijthsfwd; + double BSIM4ijthdrev; + double BSIM4ijthsrev; + double BSIM4xjbvd; + double BSIM4xjbvs; + double BSIM4bvd; + double BSIM4bvs; + double BSIM4xrcrg1; + double BSIM4xrcrg2; + + double BSIM4vfb; + double BSIM4gbmin; + double BSIM4rbdb; + double BSIM4rbsb; + double BSIM4rbpb; + double BSIM4rbps; + double BSIM4rbpd; + double BSIM4tnoia; + double BSIM4tnoib; + double BSIM4ntnoi; + + /* CV model and Parasitics */ + double BSIM4cgsl; + double BSIM4cgdl; + double BSIM4ckappas; + double BSIM4ckappad; + double BSIM4cf; + double BSIM4vfbcv; + double BSIM4clc; + double BSIM4cle; + double BSIM4dwc; + double BSIM4dlc; + double BSIM4dlcig; + double BSIM4dwj; + double BSIM4noff; + double BSIM4voffcv; + double BSIM4acde; + double BSIM4moin; + double BSIM4tcj; + double BSIM4tcjsw; + double BSIM4tcjswg; + double BSIM4tpb; + double BSIM4tpbsw; + double BSIM4tpbswg; + double BSIM4dmcg; + double BSIM4dmci; + double BSIM4dmdg; + double BSIM4dmcgt; + double BSIM4xgw; + double BSIM4xgl; + double BSIM4rshg; + double BSIM4ngcon; + + /* Length Dependence */ + double BSIM4lcdsc; + double BSIM4lcdscb; + double BSIM4lcdscd; + double BSIM4lcit; + double BSIM4lnfactor; + double BSIM4lxj; + double BSIM4lvsat; + double BSIM4lat; + double BSIM4la0; + double BSIM4lags; + double BSIM4la1; + double BSIM4la2; + double BSIM4lketa; + double BSIM4lnsub; + double BSIM4lndep; + double BSIM4lnsd; + double BSIM4lphin; + double BSIM4lngate; + double BSIM4lgamma1; + double BSIM4lgamma2; + double BSIM4lvbx; + double BSIM4lvbm; + double BSIM4lxt; + double BSIM4lk1; + double BSIM4lkt1; + double BSIM4lkt1l; + double BSIM4lkt2; + double BSIM4lk2; + double BSIM4lk3; + double BSIM4lk3b; + double BSIM4lw0; + double BSIM4ldvtp0; + double BSIM4ldvtp1; + double BSIM4llpe0; + double BSIM4llpeb; + double BSIM4ldvt0; + double BSIM4ldvt1; + double BSIM4ldvt2; + double BSIM4ldvt0w; + double BSIM4ldvt1w; + double BSIM4ldvt2w; + double BSIM4ldrout; + double BSIM4ldsub; + double BSIM4lvth0; + double BSIM4lua; + double BSIM4lua1; + double BSIM4lub; + double BSIM4lub1; + double BSIM4luc; + double BSIM4luc1; + double BSIM4lu0; + double BSIM4leu; + double BSIM4lute; + double BSIM4lvoff; + double BSIM4lminv; + double BSIM4ldelta; + double BSIM4lrdsw; + double BSIM4lrsw; + double BSIM4lrdw; + double BSIM4lprwg; + double BSIM4lprwb; + double BSIM4lprt; + double BSIM4leta0; + double BSIM4letab; + double BSIM4lpclm; + double BSIM4lpdibl1; + double BSIM4lpdibl2; + double BSIM4lpdiblb; + double BSIM4lfprout; + double BSIM4lpdits; + double BSIM4lpditsd; + double BSIM4lpscbe1; + double BSIM4lpscbe2; + double BSIM4lpvag; + double BSIM4lwr; + double BSIM4ldwg; + double BSIM4ldwb; + double BSIM4lb0; + double BSIM4lb1; + double BSIM4lalpha0; + double BSIM4lalpha1; + double BSIM4lbeta0; + double BSIM4lvfb; + double BSIM4lagidl; + double BSIM4lbgidl; + double BSIM4lcgidl; + double BSIM4legidl; + double BSIM4laigc; + double BSIM4lbigc; + double BSIM4lcigc; + double BSIM4laigsd; + double BSIM4lbigsd; + double BSIM4lcigsd; + double BSIM4laigbacc; + double BSIM4lbigbacc; + double BSIM4lcigbacc; + double BSIM4laigbinv; + double BSIM4lbigbinv; + double BSIM4lcigbinv; + double BSIM4lnigc; + double BSIM4lnigbacc; + double BSIM4lnigbinv; + double BSIM4lntox; + double BSIM4leigbinv; + double BSIM4lpigcd; + double BSIM4lpoxedge; + double BSIM4lxrcrg1; + double BSIM4lxrcrg2; + + /* CV model */ + double BSIM4lcgsl; + double BSIM4lcgdl; + double BSIM4lckappas; + double BSIM4lckappad; + double BSIM4lcf; + double BSIM4lclc; + double BSIM4lcle; + double BSIM4lvfbcv; + double BSIM4lnoff; + double BSIM4lvoffcv; + double BSIM4lacde; + double BSIM4lmoin; + + /* Width Dependence */ + double BSIM4wcdsc; + double BSIM4wcdscb; + double BSIM4wcdscd; + double BSIM4wcit; + double BSIM4wnfactor; + double BSIM4wxj; + double BSIM4wvsat; + double BSIM4wat; + double BSIM4wa0; + double BSIM4wags; + double BSIM4wa1; + double BSIM4wa2; + double BSIM4wketa; + double BSIM4wnsub; + double BSIM4wndep; + double BSIM4wnsd; + double BSIM4wphin; + double BSIM4wngate; + double BSIM4wgamma1; + double BSIM4wgamma2; + double BSIM4wvbx; + double BSIM4wvbm; + double BSIM4wxt; + double BSIM4wk1; + double BSIM4wkt1; + double BSIM4wkt1l; + double BSIM4wkt2; + double BSIM4wk2; + double BSIM4wk3; + double BSIM4wk3b; + double BSIM4ww0; + double BSIM4wdvtp0; + double BSIM4wdvtp1; + double BSIM4wlpe0; + double BSIM4wlpeb; + double BSIM4wdvt0; + double BSIM4wdvt1; + double BSIM4wdvt2; + double BSIM4wdvt0w; + double BSIM4wdvt1w; + double BSIM4wdvt2w; + double BSIM4wdrout; + double BSIM4wdsub; + double BSIM4wvth0; + double BSIM4wua; + double BSIM4wua1; + double BSIM4wub; + double BSIM4wub1; + double BSIM4wuc; + double BSIM4wuc1; + double BSIM4wu0; + double BSIM4weu; + double BSIM4wute; + double BSIM4wvoff; + double BSIM4wminv; + double BSIM4wdelta; + double BSIM4wrdsw; + double BSIM4wrsw; + double BSIM4wrdw; + double BSIM4wprwg; + double BSIM4wprwb; + double BSIM4wprt; + double BSIM4weta0; + double BSIM4wetab; + double BSIM4wpclm; + double BSIM4wpdibl1; + double BSIM4wpdibl2; + double BSIM4wpdiblb; + double BSIM4wfprout; + double BSIM4wpdits; + double BSIM4wpditsd; + double BSIM4wpscbe1; + double BSIM4wpscbe2; + double BSIM4wpvag; + double BSIM4wwr; + double BSIM4wdwg; + double BSIM4wdwb; + double BSIM4wb0; + double BSIM4wb1; + double BSIM4walpha0; + double BSIM4walpha1; + double BSIM4wbeta0; + double BSIM4wvfb; + double BSIM4wagidl; + double BSIM4wbgidl; + double BSIM4wcgidl; + double BSIM4wegidl; + double BSIM4waigc; + double BSIM4wbigc; + double BSIM4wcigc; + double BSIM4waigsd; + double BSIM4wbigsd; + double BSIM4wcigsd; + double BSIM4waigbacc; + double BSIM4wbigbacc; + double BSIM4wcigbacc; + double BSIM4waigbinv; + double BSIM4wbigbinv; + double BSIM4wcigbinv; + double BSIM4wnigc; + double BSIM4wnigbacc; + double BSIM4wnigbinv; + double BSIM4wntox; + double BSIM4weigbinv; + double BSIM4wpigcd; + double BSIM4wpoxedge; + double BSIM4wxrcrg1; + double BSIM4wxrcrg2; + + /* CV model */ + double BSIM4wcgsl; + double BSIM4wcgdl; + double BSIM4wckappas; + double BSIM4wckappad; + double BSIM4wcf; + double BSIM4wclc; + double BSIM4wcle; + double BSIM4wvfbcv; + double BSIM4wnoff; + double BSIM4wvoffcv; + double BSIM4wacde; + double BSIM4wmoin; + + /* Cross-term Dependence */ + double BSIM4pcdsc; + double BSIM4pcdscb; + double BSIM4pcdscd; + double BSIM4pcit; + double BSIM4pnfactor; + double BSIM4pxj; + double BSIM4pvsat; + double BSIM4pat; + double BSIM4pa0; + double BSIM4pags; + double BSIM4pa1; + double BSIM4pa2; + double BSIM4pketa; + double BSIM4pnsub; + double BSIM4pndep; + double BSIM4pnsd; + double BSIM4pphin; + double BSIM4pngate; + double BSIM4pgamma1; + double BSIM4pgamma2; + double BSIM4pvbx; + double BSIM4pvbm; + double BSIM4pxt; + double BSIM4pk1; + double BSIM4pkt1; + double BSIM4pkt1l; + double BSIM4pkt2; + double BSIM4pk2; + double BSIM4pk3; + double BSIM4pk3b; + double BSIM4pw0; + double BSIM4pdvtp0; + double BSIM4pdvtp1; + double BSIM4plpe0; + double BSIM4plpeb; + double BSIM4pdvt0; + double BSIM4pdvt1; + double BSIM4pdvt2; + double BSIM4pdvt0w; + double BSIM4pdvt1w; + double BSIM4pdvt2w; + double BSIM4pdrout; + double BSIM4pdsub; + double BSIM4pvth0; + double BSIM4pua; + double BSIM4pua1; + double BSIM4pub; + double BSIM4pub1; + double BSIM4puc; + double BSIM4puc1; + double BSIM4pu0; + double BSIM4peu; + double BSIM4pute; + double BSIM4pvoff; + double BSIM4pminv; + double BSIM4pdelta; + double BSIM4prdsw; + double BSIM4prsw; + double BSIM4prdw; + double BSIM4pprwg; + double BSIM4pprwb; + double BSIM4pprt; + double BSIM4peta0; + double BSIM4petab; + double BSIM4ppclm; + double BSIM4ppdibl1; + double BSIM4ppdibl2; + double BSIM4ppdiblb; + double BSIM4pfprout; + double BSIM4ppdits; + double BSIM4ppditsd; + double BSIM4ppscbe1; + double BSIM4ppscbe2; + double BSIM4ppvag; + double BSIM4pwr; + double BSIM4pdwg; + double BSIM4pdwb; + double BSIM4pb0; + double BSIM4pb1; + double BSIM4palpha0; + double BSIM4palpha1; + double BSIM4pbeta0; + double BSIM4pvfb; + double BSIM4pagidl; + double BSIM4pbgidl; + double BSIM4pcgidl; + double BSIM4pegidl; + double BSIM4paigc; + double BSIM4pbigc; + double BSIM4pcigc; + double BSIM4paigsd; + double BSIM4pbigsd; + double BSIM4pcigsd; + double BSIM4paigbacc; + double BSIM4pbigbacc; + double BSIM4pcigbacc; + double BSIM4paigbinv; + double BSIM4pbigbinv; + double BSIM4pcigbinv; + double BSIM4pnigc; + double BSIM4pnigbacc; + double BSIM4pnigbinv; + double BSIM4pntox; + double BSIM4peigbinv; + double BSIM4ppigcd; + double BSIM4ppoxedge; + double BSIM4pxrcrg1; + double BSIM4pxrcrg2; + + /* CV model */ + double BSIM4pcgsl; + double BSIM4pcgdl; + double BSIM4pckappas; + double BSIM4pckappad; + double BSIM4pcf; + double BSIM4pclc; + double BSIM4pcle; + double BSIM4pvfbcv; + double BSIM4pnoff; + double BSIM4pvoffcv; + double BSIM4pacde; + double BSIM4pmoin; + + double BSIM4tnom; + double BSIM4cgso; + double BSIM4cgdo; + double BSIM4cgbo; + double BSIM4xpart; + double BSIM4cFringOut; + double BSIM4cFringMax; + + double BSIM4sheetResistance; + double BSIM4SjctSatCurDensity; + double BSIM4DjctSatCurDensity; + double BSIM4SjctSidewallSatCurDensity; + double BSIM4DjctSidewallSatCurDensity; + double BSIM4SjctGateSidewallSatCurDensity; + double BSIM4DjctGateSidewallSatCurDensity; + double BSIM4SbulkJctPotential; + double BSIM4DbulkJctPotential; + double BSIM4SbulkJctBotGradingCoeff; + double BSIM4DbulkJctBotGradingCoeff; + double BSIM4SbulkJctSideGradingCoeff; + double BSIM4DbulkJctSideGradingCoeff; + double BSIM4SbulkJctGateSideGradingCoeff; + double BSIM4DbulkJctGateSideGradingCoeff; + double BSIM4SsidewallJctPotential; + double BSIM4DsidewallJctPotential; + double BSIM4SGatesidewallJctPotential; + double BSIM4DGatesidewallJctPotential; + double BSIM4SunitAreaJctCap; + double BSIM4DunitAreaJctCap; + double BSIM4SunitLengthSidewallJctCap; + double BSIM4DunitLengthSidewallJctCap; + double BSIM4SunitLengthGateSidewallJctCap; + double BSIM4DunitLengthGateSidewallJctCap; + double BSIM4SjctEmissionCoeff; + double BSIM4DjctEmissionCoeff; + double BSIM4SjctTempExponent; + double BSIM4DjctTempExponent; + + double BSIM4Lint; + double BSIM4Ll; + double BSIM4Llc; + double BSIM4Lln; + double BSIM4Lw; + double BSIM4Lwc; + double BSIM4Lwn; + double BSIM4Lwl; + double BSIM4Lwlc; + double BSIM4Lmin; + double BSIM4Lmax; + + double BSIM4Wint; + double BSIM4Wl; + double BSIM4Wlc; + double BSIM4Wln; + double BSIM4Ww; + double BSIM4Wwc; + double BSIM4Wwn; + double BSIM4Wwl; + double BSIM4Wwlc; + double BSIM4Wmin; + double BSIM4Wmax; + + +/* Pre-calculated constants + * move to size-dependent param */ + double BSIM4vtm; + double BSIM4coxe; + double BSIM4coxp; + double BSIM4cof1; + double BSIM4cof2; + double BSIM4cof3; + double BSIM4cof4; + double BSIM4vcrit; + double BSIM4factor1; + double BSIM4PhiBS; + double BSIM4PhiBSWS; + double BSIM4PhiBSWGS; + double BSIM4SjctTempSatCurDensity; + double BSIM4SjctSidewallTempSatCurDensity; + double BSIM4SjctGateSidewallTempSatCurDensity; + double BSIM4PhiBD; + double BSIM4PhiBSWD; + double BSIM4PhiBSWGD; + double BSIM4DjctTempSatCurDensity; + double BSIM4DjctSidewallTempSatCurDensity; + double BSIM4DjctGateSidewallTempSatCurDensity; + + double BSIM4oxideTrapDensityA; + double BSIM4oxideTrapDensityB; + double BSIM4oxideTrapDensityC; + double BSIM4em; + double BSIM4ef; + double BSIM4af; + double BSIM4kf; + + struct bsim4SizeDependParam *pSizeDependParamKnot; + + /* Flags */ + unsigned BSIM4mobModGiven :1; + unsigned BSIM4binUnitGiven :1; + unsigned BSIM4capModGiven :1; + unsigned BSIM4dioModGiven :1; + unsigned BSIM4rdsModGiven :1; + unsigned BSIM4rbodyModGiven :1; + unsigned BSIM4rgateModGiven :1; + unsigned BSIM4perModGiven :1; + unsigned BSIM4geoModGiven :1; + unsigned BSIM4paramChkGiven :1; + unsigned BSIM4trnqsModGiven :1; + unsigned BSIM4acnqsModGiven :1; + unsigned BSIM4fnoiModGiven :1; + unsigned BSIM4tnoiModGiven :1; + unsigned BSIM4igcModGiven :1; + unsigned BSIM4igbModGiven :1; + unsigned BSIM4typeGiven :1; + unsigned BSIM4toxrefGiven :1; + unsigned BSIM4toxeGiven :1; + unsigned BSIM4toxpGiven :1; + unsigned BSIM4toxmGiven :1; + unsigned BSIM4dtoxGiven :1; + unsigned BSIM4epsroxGiven :1; + unsigned BSIM4versionGiven :1; + unsigned BSIM4cdscGiven :1; + unsigned BSIM4cdscbGiven :1; + unsigned BSIM4cdscdGiven :1; + unsigned BSIM4citGiven :1; + unsigned BSIM4nfactorGiven :1; + unsigned BSIM4xjGiven :1; + unsigned BSIM4vsatGiven :1; + unsigned BSIM4atGiven :1; + unsigned BSIM4a0Given :1; + unsigned BSIM4agsGiven :1; + unsigned BSIM4a1Given :1; + unsigned BSIM4a2Given :1; + unsigned BSIM4ketaGiven :1; + unsigned BSIM4nsubGiven :1; + unsigned BSIM4ndepGiven :1; + unsigned BSIM4nsdGiven :1; + unsigned BSIM4phinGiven :1; + unsigned BSIM4ngateGiven :1; + unsigned BSIM4gamma1Given :1; + unsigned BSIM4gamma2Given :1; + unsigned BSIM4vbxGiven :1; + unsigned BSIM4vbmGiven :1; + unsigned BSIM4xtGiven :1; + unsigned BSIM4k1Given :1; + unsigned BSIM4kt1Given :1; + unsigned BSIM4kt1lGiven :1; + unsigned BSIM4kt2Given :1; + unsigned BSIM4k2Given :1; + unsigned BSIM4k3Given :1; + unsigned BSIM4k3bGiven :1; + unsigned BSIM4w0Given :1; + unsigned BSIM4dvtp0Given :1; + unsigned BSIM4dvtp1Given :1; + unsigned BSIM4lpe0Given :1; + unsigned BSIM4lpebGiven :1; + unsigned BSIM4dvt0Given :1; + unsigned BSIM4dvt1Given :1; + unsigned BSIM4dvt2Given :1; + unsigned BSIM4dvt0wGiven :1; + unsigned BSIM4dvt1wGiven :1; + unsigned BSIM4dvt2wGiven :1; + unsigned BSIM4droutGiven :1; + unsigned BSIM4dsubGiven :1; + unsigned BSIM4vth0Given :1; + unsigned BSIM4euGiven :1; + unsigned BSIM4uaGiven :1; + unsigned BSIM4ua1Given :1; + unsigned BSIM4ubGiven :1; + unsigned BSIM4ub1Given :1; + unsigned BSIM4ucGiven :1; + unsigned BSIM4uc1Given :1; + unsigned BSIM4u0Given :1; + unsigned BSIM4uteGiven :1; + unsigned BSIM4voffGiven :1; + unsigned BSIM4vofflGiven :1; + unsigned BSIM4minvGiven :1; + unsigned BSIM4rdswGiven :1; + unsigned BSIM4rdswminGiven :1; + unsigned BSIM4rdwminGiven :1; + unsigned BSIM4rswminGiven :1; + unsigned BSIM4rswGiven :1; + unsigned BSIM4rdwGiven :1; + unsigned BSIM4prwgGiven :1; + unsigned BSIM4prwbGiven :1; + unsigned BSIM4prtGiven :1; + unsigned BSIM4eta0Given :1; + unsigned BSIM4etabGiven :1; + unsigned BSIM4pclmGiven :1; + unsigned BSIM4pdibl1Given :1; + unsigned BSIM4pdibl2Given :1; + unsigned BSIM4pdiblbGiven :1; + unsigned BSIM4fproutGiven :1; + unsigned BSIM4pditsGiven :1; + unsigned BSIM4pditsdGiven :1; + unsigned BSIM4pditslGiven :1; + unsigned BSIM4pscbe1Given :1; + unsigned BSIM4pscbe2Given :1; + unsigned BSIM4pvagGiven :1; + unsigned BSIM4deltaGiven :1; + unsigned BSIM4wrGiven :1; + unsigned BSIM4dwgGiven :1; + unsigned BSIM4dwbGiven :1; + unsigned BSIM4b0Given :1; + unsigned BSIM4b1Given :1; + unsigned BSIM4alpha0Given :1; + unsigned BSIM4alpha1Given :1; + unsigned BSIM4beta0Given :1; + unsigned BSIM4agidlGiven :1; + unsigned BSIM4bgidlGiven :1; + unsigned BSIM4cgidlGiven :1; + unsigned BSIM4egidlGiven :1; + unsigned BSIM4aigcGiven :1; + unsigned BSIM4bigcGiven :1; + unsigned BSIM4cigcGiven :1; + unsigned BSIM4aigsdGiven :1; + unsigned BSIM4bigsdGiven :1; + unsigned BSIM4cigsdGiven :1; + unsigned BSIM4aigbaccGiven :1; + unsigned BSIM4bigbaccGiven :1; + unsigned BSIM4cigbaccGiven :1; + unsigned BSIM4aigbinvGiven :1; + unsigned BSIM4bigbinvGiven :1; + unsigned BSIM4cigbinvGiven :1; + unsigned BSIM4nigcGiven :1; + unsigned BSIM4nigbinvGiven :1; + unsigned BSIM4nigbaccGiven :1; + unsigned BSIM4ntoxGiven :1; + unsigned BSIM4eigbinvGiven :1; + unsigned BSIM4pigcdGiven :1; + unsigned BSIM4poxedgeGiven :1; + unsigned BSIM4ijthdfwdGiven :1; + unsigned BSIM4ijthsfwdGiven :1; + unsigned BSIM4ijthdrevGiven :1; + unsigned BSIM4ijthsrevGiven :1; + unsigned BSIM4xjbvdGiven :1; + unsigned BSIM4xjbvsGiven :1; + unsigned BSIM4bvdGiven :1; + unsigned BSIM4bvsGiven :1; + unsigned BSIM4vfbGiven :1; + unsigned BSIM4gbminGiven :1; + unsigned BSIM4rbdbGiven :1; + unsigned BSIM4rbsbGiven :1; + unsigned BSIM4rbpsGiven :1; + unsigned BSIM4rbpdGiven :1; + unsigned BSIM4rbpbGiven :1; + unsigned BSIM4xrcrg1Given :1; + unsigned BSIM4xrcrg2Given :1; + unsigned BSIM4tnoiaGiven :1; + unsigned BSIM4tnoibGiven :1; + unsigned BSIM4ntnoiGiven :1; + + /* CV model and parasitics */ + unsigned BSIM4cgslGiven :1; + unsigned BSIM4cgdlGiven :1; + unsigned BSIM4ckappasGiven :1; + unsigned BSIM4ckappadGiven :1; + unsigned BSIM4cfGiven :1; + unsigned BSIM4vfbcvGiven :1; + unsigned BSIM4clcGiven :1; + unsigned BSIM4cleGiven :1; + unsigned BSIM4dwcGiven :1; + unsigned BSIM4dlcGiven :1; + unsigned BSIM4dlcigGiven :1; + unsigned BSIM4dwjGiven :1; + unsigned BSIM4noffGiven :1; + unsigned BSIM4voffcvGiven :1; + unsigned BSIM4acdeGiven :1; + unsigned BSIM4moinGiven :1; + unsigned BSIM4tcjGiven :1; + unsigned BSIM4tcjswGiven :1; + unsigned BSIM4tcjswgGiven :1; + unsigned BSIM4tpbGiven :1; + unsigned BSIM4tpbswGiven :1; + unsigned BSIM4tpbswgGiven :1; + unsigned BSIM4dmcgGiven :1; + unsigned BSIM4dmciGiven :1; + unsigned BSIM4dmdgGiven :1; + unsigned BSIM4dmcgtGiven :1; + unsigned BSIM4xgwGiven :1; + unsigned BSIM4xglGiven :1; + unsigned BSIM4rshgGiven :1; + unsigned BSIM4ngconGiven :1; + + + /* Length dependence */ + unsigned BSIM4lcdscGiven :1; + unsigned BSIM4lcdscbGiven :1; + unsigned BSIM4lcdscdGiven :1; + unsigned BSIM4lcitGiven :1; + unsigned BSIM4lnfactorGiven :1; + unsigned BSIM4lxjGiven :1; + unsigned BSIM4lvsatGiven :1; + unsigned BSIM4latGiven :1; + unsigned BSIM4la0Given :1; + unsigned BSIM4lagsGiven :1; + unsigned BSIM4la1Given :1; + unsigned BSIM4la2Given :1; + unsigned BSIM4lketaGiven :1; + unsigned BSIM4lnsubGiven :1; + unsigned BSIM4lndepGiven :1; + unsigned BSIM4lnsdGiven :1; + unsigned BSIM4lphinGiven :1; + unsigned BSIM4lngateGiven :1; + unsigned BSIM4lgamma1Given :1; + unsigned BSIM4lgamma2Given :1; + unsigned BSIM4lvbxGiven :1; + unsigned BSIM4lvbmGiven :1; + unsigned BSIM4lxtGiven :1; + unsigned BSIM4lk1Given :1; + unsigned BSIM4lkt1Given :1; + unsigned BSIM4lkt1lGiven :1; + unsigned BSIM4lkt2Given :1; + unsigned BSIM4lk2Given :1; + unsigned BSIM4lk3Given :1; + unsigned BSIM4lk3bGiven :1; + unsigned BSIM4lw0Given :1; + unsigned BSIM4ldvtp0Given :1; + unsigned BSIM4ldvtp1Given :1; + unsigned BSIM4llpe0Given :1; + unsigned BSIM4llpebGiven :1; + unsigned BSIM4ldvt0Given :1; + unsigned BSIM4ldvt1Given :1; + unsigned BSIM4ldvt2Given :1; + unsigned BSIM4ldvt0wGiven :1; + unsigned BSIM4ldvt1wGiven :1; + unsigned BSIM4ldvt2wGiven :1; + unsigned BSIM4ldroutGiven :1; + unsigned BSIM4ldsubGiven :1; + unsigned BSIM4lvth0Given :1; + unsigned BSIM4luaGiven :1; + unsigned BSIM4lua1Given :1; + unsigned BSIM4lubGiven :1; + unsigned BSIM4lub1Given :1; + unsigned BSIM4lucGiven :1; + unsigned BSIM4luc1Given :1; + unsigned BSIM4lu0Given :1; + unsigned BSIM4leuGiven :1; + unsigned BSIM4luteGiven :1; + unsigned BSIM4lvoffGiven :1; + unsigned BSIM4lminvGiven :1; + unsigned BSIM4lrdswGiven :1; + unsigned BSIM4lrswGiven :1; + unsigned BSIM4lrdwGiven :1; + unsigned BSIM4lprwgGiven :1; + unsigned BSIM4lprwbGiven :1; + unsigned BSIM4lprtGiven :1; + unsigned BSIM4leta0Given :1; + unsigned BSIM4letabGiven :1; + unsigned BSIM4lpclmGiven :1; + unsigned BSIM4lpdibl1Given :1; + unsigned BSIM4lpdibl2Given :1; + unsigned BSIM4lpdiblbGiven :1; + unsigned BSIM4lfproutGiven :1; + unsigned BSIM4lpditsGiven :1; + unsigned BSIM4lpditsdGiven :1; + unsigned BSIM4lpscbe1Given :1; + unsigned BSIM4lpscbe2Given :1; + unsigned BSIM4lpvagGiven :1; + unsigned BSIM4ldeltaGiven :1; + unsigned BSIM4lwrGiven :1; + unsigned BSIM4ldwgGiven :1; + unsigned BSIM4ldwbGiven :1; + unsigned BSIM4lb0Given :1; + unsigned BSIM4lb1Given :1; + unsigned BSIM4lalpha0Given :1; + unsigned BSIM4lalpha1Given :1; + unsigned BSIM4lbeta0Given :1; + unsigned BSIM4lvfbGiven :1; + unsigned BSIM4lagidlGiven :1; + unsigned BSIM4lbgidlGiven :1; + unsigned BSIM4lcgidlGiven :1; + unsigned BSIM4legidlGiven :1; + unsigned BSIM4laigcGiven :1; + unsigned BSIM4lbigcGiven :1; + unsigned BSIM4lcigcGiven :1; + unsigned BSIM4laigsdGiven :1; + unsigned BSIM4lbigsdGiven :1; + unsigned BSIM4lcigsdGiven :1; + unsigned BSIM4laigbaccGiven :1; + unsigned BSIM4lbigbaccGiven :1; + unsigned BSIM4lcigbaccGiven :1; + unsigned BSIM4laigbinvGiven :1; + unsigned BSIM4lbigbinvGiven :1; + unsigned BSIM4lcigbinvGiven :1; + unsigned BSIM4lnigcGiven :1; + unsigned BSIM4lnigbinvGiven :1; + unsigned BSIM4lnigbaccGiven :1; + unsigned BSIM4lntoxGiven :1; + unsigned BSIM4leigbinvGiven :1; + unsigned BSIM4lpigcdGiven :1; + unsigned BSIM4lpoxedgeGiven :1; + unsigned BSIM4lxrcrg1Given :1; + unsigned BSIM4lxrcrg2Given :1; + + /* CV model */ + unsigned BSIM4lcgslGiven :1; + unsigned BSIM4lcgdlGiven :1; + unsigned BSIM4lckappasGiven :1; + unsigned BSIM4lckappadGiven :1; + unsigned BSIM4lcfGiven :1; + unsigned BSIM4lclcGiven :1; + unsigned BSIM4lcleGiven :1; + unsigned BSIM4lvfbcvGiven :1; + unsigned BSIM4lnoffGiven :1; + unsigned BSIM4lvoffcvGiven :1; + unsigned BSIM4lacdeGiven :1; + unsigned BSIM4lmoinGiven :1; + + /* Width dependence */ + unsigned BSIM4wcdscGiven :1; + unsigned BSIM4wcdscbGiven :1; + unsigned BSIM4wcdscdGiven :1; + unsigned BSIM4wcitGiven :1; + unsigned BSIM4wnfactorGiven :1; + unsigned BSIM4wxjGiven :1; + unsigned BSIM4wvsatGiven :1; + unsigned BSIM4watGiven :1; + unsigned BSIM4wa0Given :1; + unsigned BSIM4wagsGiven :1; + unsigned BSIM4wa1Given :1; + unsigned BSIM4wa2Given :1; + unsigned BSIM4wketaGiven :1; + unsigned BSIM4wnsubGiven :1; + unsigned BSIM4wndepGiven :1; + unsigned BSIM4wnsdGiven :1; + unsigned BSIM4wphinGiven :1; + unsigned BSIM4wngateGiven :1; + unsigned BSIM4wgamma1Given :1; + unsigned BSIM4wgamma2Given :1; + unsigned BSIM4wvbxGiven :1; + unsigned BSIM4wvbmGiven :1; + unsigned BSIM4wxtGiven :1; + unsigned BSIM4wk1Given :1; + unsigned BSIM4wkt1Given :1; + unsigned BSIM4wkt1lGiven :1; + unsigned BSIM4wkt2Given :1; + unsigned BSIM4wk2Given :1; + unsigned BSIM4wk3Given :1; + unsigned BSIM4wk3bGiven :1; + unsigned BSIM4ww0Given :1; + unsigned BSIM4wdvtp0Given :1; + unsigned BSIM4wdvtp1Given :1; + unsigned BSIM4wlpe0Given :1; + unsigned BSIM4wlpebGiven :1; + unsigned BSIM4wdvt0Given :1; + unsigned BSIM4wdvt1Given :1; + unsigned BSIM4wdvt2Given :1; + unsigned BSIM4wdvt0wGiven :1; + unsigned BSIM4wdvt1wGiven :1; + unsigned BSIM4wdvt2wGiven :1; + unsigned BSIM4wdroutGiven :1; + unsigned BSIM4wdsubGiven :1; + unsigned BSIM4wvth0Given :1; + unsigned BSIM4wuaGiven :1; + unsigned BSIM4wua1Given :1; + unsigned BSIM4wubGiven :1; + unsigned BSIM4wub1Given :1; + unsigned BSIM4wucGiven :1; + unsigned BSIM4wuc1Given :1; + unsigned BSIM4wu0Given :1; + unsigned BSIM4weuGiven :1; + unsigned BSIM4wuteGiven :1; + unsigned BSIM4wvoffGiven :1; + unsigned BSIM4wminvGiven :1; + unsigned BSIM4wrdswGiven :1; + unsigned BSIM4wrswGiven :1; + unsigned BSIM4wrdwGiven :1; + unsigned BSIM4wprwgGiven :1; + unsigned BSIM4wprwbGiven :1; + unsigned BSIM4wprtGiven :1; + unsigned BSIM4weta0Given :1; + unsigned BSIM4wetabGiven :1; + unsigned BSIM4wpclmGiven :1; + unsigned BSIM4wpdibl1Given :1; + unsigned BSIM4wpdibl2Given :1; + unsigned BSIM4wpdiblbGiven :1; + unsigned BSIM4wfproutGiven :1; + unsigned BSIM4wpditsGiven :1; + unsigned BSIM4wpditsdGiven :1; + unsigned BSIM4wpscbe1Given :1; + unsigned BSIM4wpscbe2Given :1; + unsigned BSIM4wpvagGiven :1; + unsigned BSIM4wdeltaGiven :1; + unsigned BSIM4wwrGiven :1; + unsigned BSIM4wdwgGiven :1; + unsigned BSIM4wdwbGiven :1; + unsigned BSIM4wb0Given :1; + unsigned BSIM4wb1Given :1; + unsigned BSIM4walpha0Given :1; + unsigned BSIM4walpha1Given :1; + unsigned BSIM4wbeta0Given :1; + unsigned BSIM4wvfbGiven :1; + unsigned BSIM4wagidlGiven :1; + unsigned BSIM4wbgidlGiven :1; + unsigned BSIM4wcgidlGiven :1; + unsigned BSIM4wegidlGiven :1; + unsigned BSIM4waigcGiven :1; + unsigned BSIM4wbigcGiven :1; + unsigned BSIM4wcigcGiven :1; + unsigned BSIM4waigsdGiven :1; + unsigned BSIM4wbigsdGiven :1; + unsigned BSIM4wcigsdGiven :1; + unsigned BSIM4waigbaccGiven :1; + unsigned BSIM4wbigbaccGiven :1; + unsigned BSIM4wcigbaccGiven :1; + unsigned BSIM4waigbinvGiven :1; + unsigned BSIM4wbigbinvGiven :1; + unsigned BSIM4wcigbinvGiven :1; + unsigned BSIM4wnigcGiven :1; + unsigned BSIM4wnigbinvGiven :1; + unsigned BSIM4wnigbaccGiven :1; + unsigned BSIM4wntoxGiven :1; + unsigned BSIM4weigbinvGiven :1; + unsigned BSIM4wpigcdGiven :1; + unsigned BSIM4wpoxedgeGiven :1; + unsigned BSIM4wxrcrg1Given :1; + unsigned BSIM4wxrcrg2Given :1; + + /* CV model */ + unsigned BSIM4wcgslGiven :1; + unsigned BSIM4wcgdlGiven :1; + unsigned BSIM4wckappasGiven :1; + unsigned BSIM4wckappadGiven :1; + unsigned BSIM4wcfGiven :1; + unsigned BSIM4wclcGiven :1; + unsigned BSIM4wcleGiven :1; + unsigned BSIM4wvfbcvGiven :1; + unsigned BSIM4wnoffGiven :1; + unsigned BSIM4wvoffcvGiven :1; + unsigned BSIM4wacdeGiven :1; + unsigned BSIM4wmoinGiven :1; + + /* Cross-term dependence */ + unsigned BSIM4pcdscGiven :1; + unsigned BSIM4pcdscbGiven :1; + unsigned BSIM4pcdscdGiven :1; + unsigned BSIM4pcitGiven :1; + unsigned BSIM4pnfactorGiven :1; + unsigned BSIM4pxjGiven :1; + unsigned BSIM4pvsatGiven :1; + unsigned BSIM4patGiven :1; + unsigned BSIM4pa0Given :1; + unsigned BSIM4pagsGiven :1; + unsigned BSIM4pa1Given :1; + unsigned BSIM4pa2Given :1; + unsigned BSIM4pketaGiven :1; + unsigned BSIM4pnsubGiven :1; + unsigned BSIM4pndepGiven :1; + unsigned BSIM4pnsdGiven :1; + unsigned BSIM4pphinGiven :1; + unsigned BSIM4pngateGiven :1; + unsigned BSIM4pgamma1Given :1; + unsigned BSIM4pgamma2Given :1; + unsigned BSIM4pvbxGiven :1; + unsigned BSIM4pvbmGiven :1; + unsigned BSIM4pxtGiven :1; + unsigned BSIM4pk1Given :1; + unsigned BSIM4pkt1Given :1; + unsigned BSIM4pkt1lGiven :1; + unsigned BSIM4pkt2Given :1; + unsigned BSIM4pk2Given :1; + unsigned BSIM4pk3Given :1; + unsigned BSIM4pk3bGiven :1; + unsigned BSIM4pw0Given :1; + unsigned BSIM4pdvtp0Given :1; + unsigned BSIM4pdvtp1Given :1; + unsigned BSIM4plpe0Given :1; + unsigned BSIM4plpebGiven :1; + unsigned BSIM4pdvt0Given :1; + unsigned BSIM4pdvt1Given :1; + unsigned BSIM4pdvt2Given :1; + unsigned BSIM4pdvt0wGiven :1; + unsigned BSIM4pdvt1wGiven :1; + unsigned BSIM4pdvt2wGiven :1; + unsigned BSIM4pdroutGiven :1; + unsigned BSIM4pdsubGiven :1; + unsigned BSIM4pvth0Given :1; + unsigned BSIM4puaGiven :1; + unsigned BSIM4pua1Given :1; + unsigned BSIM4pubGiven :1; + unsigned BSIM4pub1Given :1; + unsigned BSIM4pucGiven :1; + unsigned BSIM4puc1Given :1; + unsigned BSIM4pu0Given :1; + unsigned BSIM4peuGiven :1; + unsigned BSIM4puteGiven :1; + unsigned BSIM4pvoffGiven :1; + unsigned BSIM4pminvGiven :1; + unsigned BSIM4prdswGiven :1; + unsigned BSIM4prswGiven :1; + unsigned BSIM4prdwGiven :1; + unsigned BSIM4pprwgGiven :1; + unsigned BSIM4pprwbGiven :1; + unsigned BSIM4pprtGiven :1; + unsigned BSIM4peta0Given :1; + unsigned BSIM4petabGiven :1; + unsigned BSIM4ppclmGiven :1; + unsigned BSIM4ppdibl1Given :1; + unsigned BSIM4ppdibl2Given :1; + unsigned BSIM4ppdiblbGiven :1; + unsigned BSIM4pfproutGiven :1; + unsigned BSIM4ppditsGiven :1; + unsigned BSIM4ppditsdGiven :1; + unsigned BSIM4ppscbe1Given :1; + unsigned BSIM4ppscbe2Given :1; + unsigned BSIM4ppvagGiven :1; + unsigned BSIM4pdeltaGiven :1; + unsigned BSIM4pwrGiven :1; + unsigned BSIM4pdwgGiven :1; + unsigned BSIM4pdwbGiven :1; + unsigned BSIM4pb0Given :1; + unsigned BSIM4pb1Given :1; + unsigned BSIM4palpha0Given :1; + unsigned BSIM4palpha1Given :1; + unsigned BSIM4pbeta0Given :1; + unsigned BSIM4pvfbGiven :1; + unsigned BSIM4pagidlGiven :1; + unsigned BSIM4pbgidlGiven :1; + unsigned BSIM4pcgidlGiven :1; + unsigned BSIM4pegidlGiven :1; + unsigned BSIM4paigcGiven :1; + unsigned BSIM4pbigcGiven :1; + unsigned BSIM4pcigcGiven :1; + unsigned BSIM4paigsdGiven :1; + unsigned BSIM4pbigsdGiven :1; + unsigned BSIM4pcigsdGiven :1; + unsigned BSIM4paigbaccGiven :1; + unsigned BSIM4pbigbaccGiven :1; + unsigned BSIM4pcigbaccGiven :1; + unsigned BSIM4paigbinvGiven :1; + unsigned BSIM4pbigbinvGiven :1; + unsigned BSIM4pcigbinvGiven :1; + unsigned BSIM4pnigcGiven :1; + unsigned BSIM4pnigbinvGiven :1; + unsigned BSIM4pnigbaccGiven :1; + unsigned BSIM4pntoxGiven :1; + unsigned BSIM4peigbinvGiven :1; + unsigned BSIM4ppigcdGiven :1; + unsigned BSIM4ppoxedgeGiven :1; + unsigned BSIM4pxrcrg1Given :1; + unsigned BSIM4pxrcrg2Given :1; + + /* CV model */ + unsigned BSIM4pcgslGiven :1; + unsigned BSIM4pcgdlGiven :1; + unsigned BSIM4pckappasGiven :1; + unsigned BSIM4pckappadGiven :1; + unsigned BSIM4pcfGiven :1; + unsigned BSIM4pclcGiven :1; + unsigned BSIM4pcleGiven :1; + unsigned BSIM4pvfbcvGiven :1; + unsigned BSIM4pnoffGiven :1; + unsigned BSIM4pvoffcvGiven :1; + unsigned BSIM4pacdeGiven :1; + unsigned BSIM4pmoinGiven :1; + + unsigned BSIM4useFringeGiven :1; + + unsigned BSIM4tnomGiven :1; + unsigned BSIM4cgsoGiven :1; + unsigned BSIM4cgdoGiven :1; + unsigned BSIM4cgboGiven :1; + unsigned BSIM4xpartGiven :1; + unsigned BSIM4sheetResistanceGiven :1; + + unsigned BSIM4SjctSatCurDensityGiven :1; + unsigned BSIM4SjctSidewallSatCurDensityGiven :1; + unsigned BSIM4SjctGateSidewallSatCurDensityGiven :1; + unsigned BSIM4SbulkJctPotentialGiven :1; + unsigned BSIM4SbulkJctBotGradingCoeffGiven :1; + unsigned BSIM4SsidewallJctPotentialGiven :1; + unsigned BSIM4SGatesidewallJctPotentialGiven :1; + unsigned BSIM4SbulkJctSideGradingCoeffGiven :1; + unsigned BSIM4SunitAreaJctCapGiven :1; + unsigned BSIM4SunitLengthSidewallJctCapGiven :1; + unsigned BSIM4SbulkJctGateSideGradingCoeffGiven :1; + unsigned BSIM4SunitLengthGateSidewallJctCapGiven :1; + unsigned BSIM4SjctEmissionCoeffGiven :1; + unsigned BSIM4SjctTempExponentGiven :1; + + unsigned BSIM4DjctSatCurDensityGiven :1; + unsigned BSIM4DjctSidewallSatCurDensityGiven :1; + unsigned BSIM4DjctGateSidewallSatCurDensityGiven :1; + unsigned BSIM4DbulkJctPotentialGiven :1; + unsigned BSIM4DbulkJctBotGradingCoeffGiven :1; + unsigned BSIM4DsidewallJctPotentialGiven :1; + unsigned BSIM4DGatesidewallJctPotentialGiven :1; + unsigned BSIM4DbulkJctSideGradingCoeffGiven :1; + unsigned BSIM4DunitAreaJctCapGiven :1; + unsigned BSIM4DunitLengthSidewallJctCapGiven :1; + unsigned BSIM4DbulkJctGateSideGradingCoeffGiven :1; + unsigned BSIM4DunitLengthGateSidewallJctCapGiven :1; + unsigned BSIM4DjctEmissionCoeffGiven :1; + unsigned BSIM4DjctTempExponentGiven :1; + + unsigned BSIM4oxideTrapDensityAGiven :1; + unsigned BSIM4oxideTrapDensityBGiven :1; + unsigned BSIM4oxideTrapDensityCGiven :1; + unsigned BSIM4emGiven :1; + unsigned BSIM4efGiven :1; + unsigned BSIM4afGiven :1; + unsigned BSIM4kfGiven :1; + + unsigned BSIM4LintGiven :1; + unsigned BSIM4LlGiven :1; + unsigned BSIM4LlcGiven :1; + unsigned BSIM4LlnGiven :1; + unsigned BSIM4LwGiven :1; + unsigned BSIM4LwcGiven :1; + unsigned BSIM4LwnGiven :1; + unsigned BSIM4LwlGiven :1; + unsigned BSIM4LwlcGiven :1; + unsigned BSIM4LminGiven :1; + unsigned BSIM4LmaxGiven :1; + + unsigned BSIM4WintGiven :1; + unsigned BSIM4WlGiven :1; + unsigned BSIM4WlcGiven :1; + unsigned BSIM4WlnGiven :1; + unsigned BSIM4WwGiven :1; + unsigned BSIM4WwcGiven :1; + unsigned BSIM4WwnGiven :1; + unsigned BSIM4WwlGiven :1; + unsigned BSIM4WwlcGiven :1; + unsigned BSIM4WminGiven :1; + unsigned BSIM4WmaxGiven :1; + +} BSIM4model; + + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + + +/* Instance parameters */ +#define BSIM4_W 1 +#define BSIM4_L 2 +#define BSIM4_AS 3 +#define BSIM4_AD 4 +#define BSIM4_PS 5 +#define BSIM4_PD 6 +#define BSIM4_NRS 7 +#define BSIM4_NRD 8 +#define BSIM4_OFF 9 +#define BSIM4_IC 10 +#define BSIM4_IC_VDS 11 +#define BSIM4_IC_VGS 12 +#define BSIM4_IC_VBS 13 +#define BSIM4_TRNQSMOD 14 +#define BSIM4_RBODYMOD 15 +#define BSIM4_RGATEMOD 16 +#define BSIM4_GEOMOD 17 +#define BSIM4_RGEOMOD 18 +#define BSIM4_NF 19 +#define BSIM4_MIN 20 +#define BSIM4_ACNQSMOD 22 +#define BSIM4_RBDB 23 +#define BSIM4_RBSB 24 +#define BSIM4_RBPB 25 +#define BSIM4_RBPS 26 +#define BSIM4_RBPD 27 + + +/* Global parameters */ +#define BSIM4_MOD_IGCMOD 90 +#define BSIM4_MOD_IGBMOD 91 +#define BSIM4_MOD_ACNQSMOD 92 +#define BSIM4_MOD_FNOIMOD 93 +#define BSIM4_MOD_RDSMOD 94 +#define BSIM4_MOD_DIOMOD 96 +#define BSIM4_MOD_PERMOD 97 +#define BSIM4_MOD_GEOMOD 98 +#define BSIM4_MOD_RGATEMOD 99 +#define BSIM4_MOD_RBODYMOD 100 +#define BSIM4_MOD_CAPMOD 101 +#define BSIM4_MOD_TRNQSMOD 102 +#define BSIM4_MOD_MOBMOD 103 +#define BSIM4_MOD_TNOIMOD 104 +#define BSIM4_MOD_TOXE 105 +#define BSIM4_MOD_CDSC 106 +#define BSIM4_MOD_CDSCB 107 +#define BSIM4_MOD_CIT 108 +#define BSIM4_MOD_NFACTOR 109 +#define BSIM4_MOD_XJ 110 +#define BSIM4_MOD_VSAT 111 +#define BSIM4_MOD_AT 112 +#define BSIM4_MOD_A0 113 +#define BSIM4_MOD_A1 114 +#define BSIM4_MOD_A2 115 +#define BSIM4_MOD_KETA 116 +#define BSIM4_MOD_NSUB 117 +#define BSIM4_MOD_NDEP 118 +#define BSIM4_MOD_NGATE 120 +#define BSIM4_MOD_GAMMA1 121 +#define BSIM4_MOD_GAMMA2 122 +#define BSIM4_MOD_VBX 123 +#define BSIM4_MOD_BINUNIT 124 +#define BSIM4_MOD_VBM 125 +#define BSIM4_MOD_XT 126 +#define BSIM4_MOD_K1 129 +#define BSIM4_MOD_KT1 130 +#define BSIM4_MOD_KT1L 131 +#define BSIM4_MOD_K2 132 +#define BSIM4_MOD_KT2 133 +#define BSIM4_MOD_K3 134 +#define BSIM4_MOD_K3B 135 +#define BSIM4_MOD_W0 136 +#define BSIM4_MOD_LPE0 137 +#define BSIM4_MOD_DVT0 138 +#define BSIM4_MOD_DVT1 139 +#define BSIM4_MOD_DVT2 140 +#define BSIM4_MOD_DVT0W 141 +#define BSIM4_MOD_DVT1W 142 +#define BSIM4_MOD_DVT2W 143 +#define BSIM4_MOD_DROUT 144 +#define BSIM4_MOD_DSUB 145 +#define BSIM4_MOD_VTH0 146 +#define BSIM4_MOD_UA 147 +#define BSIM4_MOD_UA1 148 +#define BSIM4_MOD_UB 149 +#define BSIM4_MOD_UB1 150 +#define BSIM4_MOD_UC 151 +#define BSIM4_MOD_UC1 152 +#define BSIM4_MOD_U0 153 +#define BSIM4_MOD_UTE 154 +#define BSIM4_MOD_VOFF 155 +#define BSIM4_MOD_DELTA 156 +#define BSIM4_MOD_RDSW 157 +#define BSIM4_MOD_PRT 158 +#define BSIM4_MOD_LDD 159 +#define BSIM4_MOD_ETA 160 +#define BSIM4_MOD_ETA0 161 +#define BSIM4_MOD_ETAB 162 +#define BSIM4_MOD_PCLM 163 +#define BSIM4_MOD_PDIBL1 164 +#define BSIM4_MOD_PDIBL2 165 +#define BSIM4_MOD_PSCBE1 166 +#define BSIM4_MOD_PSCBE2 167 +#define BSIM4_MOD_PVAG 168 +#define BSIM4_MOD_WR 169 +#define BSIM4_MOD_DWG 170 +#define BSIM4_MOD_DWB 171 +#define BSIM4_MOD_B0 172 +#define BSIM4_MOD_B1 173 +#define BSIM4_MOD_ALPHA0 174 +#define BSIM4_MOD_BETA0 175 +#define BSIM4_MOD_PDIBLB 178 +#define BSIM4_MOD_PRWG 179 +#define BSIM4_MOD_PRWB 180 +#define BSIM4_MOD_CDSCD 181 +#define BSIM4_MOD_AGS 182 +#define BSIM4_MOD_FRINGE 184 +#define BSIM4_MOD_CGSL 186 +#define BSIM4_MOD_CGDL 187 +#define BSIM4_MOD_CKAPPAS 188 +#define BSIM4_MOD_CF 189 +#define BSIM4_MOD_CLC 190 +#define BSIM4_MOD_CLE 191 +#define BSIM4_MOD_PARAMCHK 192 +#define BSIM4_MOD_VERSION 193 +#define BSIM4_MOD_VFBCV 194 +#define BSIM4_MOD_ACDE 195 +#define BSIM4_MOD_MOIN 196 +#define BSIM4_MOD_NOFF 197 +#define BSIM4_MOD_IJTHDFWD 198 +#define BSIM4_MOD_ALPHA1 199 +#define BSIM4_MOD_VFB 200 +#define BSIM4_MOD_TOXM 201 +#define BSIM4_MOD_TCJ 202 +#define BSIM4_MOD_TCJSW 203 +#define BSIM4_MOD_TCJSWG 204 +#define BSIM4_MOD_TPB 205 +#define BSIM4_MOD_TPBSW 206 +#define BSIM4_MOD_TPBSWG 207 +#define BSIM4_MOD_VOFFCV 208 +#define BSIM4_MOD_GBMIN 209 +#define BSIM4_MOD_RBDB 210 +#define BSIM4_MOD_RBSB 211 +#define BSIM4_MOD_RBPB 212 +#define BSIM4_MOD_RBPS 213 +#define BSIM4_MOD_RBPD 214 +#define BSIM4_MOD_DMCG 215 +#define BSIM4_MOD_DMCI 216 +#define BSIM4_MOD_DMDG 217 +#define BSIM4_MOD_XGW 218 +#define BSIM4_MOD_XGL 219 +#define BSIM4_MOD_RSHG 220 +#define BSIM4_MOD_NGCON 221 +#define BSIM4_MOD_AGIDL 222 +#define BSIM4_MOD_BGIDL 223 +#define BSIM4_MOD_EGIDL 224 +#define BSIM4_MOD_IJTHSFWD 225 +#define BSIM4_MOD_XJBVD 226 +#define BSIM4_MOD_XJBVS 227 +#define BSIM4_MOD_BVD 228 +#define BSIM4_MOD_BVS 229 +#define BSIM4_MOD_TOXP 230 +#define BSIM4_MOD_DTOX 231 +#define BSIM4_MOD_XRCRG1 232 +#define BSIM4_MOD_XRCRG2 233 +#define BSIM4_MOD_EU 234 +#define BSIM4_MOD_IJTHSREV 235 +#define BSIM4_MOD_IJTHDREV 236 +#define BSIM4_MOD_MINV 237 +#define BSIM4_MOD_VOFFL 238 +#define BSIM4_MOD_PDITS 239 +#define BSIM4_MOD_PDITSD 240 +#define BSIM4_MOD_PDITSL 241 +#define BSIM4_MOD_TNOIA 242 +#define BSIM4_MOD_TNOIB 243 +#define BSIM4_MOD_NTNOI 244 +#define BSIM4_MOD_FPROUT 245 +#define BSIM4_MOD_LPEB 246 +#define BSIM4_MOD_DVTP0 247 +#define BSIM4_MOD_DVTP1 248 +#define BSIM4_MOD_CGIDL 249 +#define BSIM4_MOD_PHIN 250 +#define BSIM4_MOD_RDSWMIN 251 +#define BSIM4_MOD_RSW 252 +#define BSIM4_MOD_RDW 253 +#define BSIM4_MOD_RDWMIN 254 +#define BSIM4_MOD_RSWMIN 255 +#define BSIM4_MOD_NSD 256 +#define BSIM4_MOD_CKAPPAD 257 +#define BSIM4_MOD_DMCGT 258 +#define BSIM4_MOD_AIGC 259 +#define BSIM4_MOD_BIGC 260 +#define BSIM4_MOD_CIGC 261 +#define BSIM4_MOD_AIGBACC 262 +#define BSIM4_MOD_BIGBACC 263 +#define BSIM4_MOD_CIGBACC 264 +#define BSIM4_MOD_AIGBINV 265 +#define BSIM4_MOD_BIGBINV 266 +#define BSIM4_MOD_CIGBINV 267 +#define BSIM4_MOD_NIGC 268 +#define BSIM4_MOD_NIGBACC 269 +#define BSIM4_MOD_NIGBINV 270 +#define BSIM4_MOD_NTOX 271 +#define BSIM4_MOD_TOXREF 272 +#define BSIM4_MOD_EIGBINV 273 +#define BSIM4_MOD_PIGCD 274 +#define BSIM4_MOD_POXEDGE 275 +#define BSIM4_MOD_EPSROX 276 +#define BSIM4_MOD_AIGSD 277 +#define BSIM4_MOD_BIGSD 278 +#define BSIM4_MOD_CIGSD 279 +#define BSIM4_MOD_JSWGS 280 +#define BSIM4_MOD_JSWGD 281 + + +/* Length dependence */ +#define BSIM4_MOD_LCDSC 301 +#define BSIM4_MOD_LCDSCB 302 +#define BSIM4_MOD_LCIT 303 +#define BSIM4_MOD_LNFACTOR 304 +#define BSIM4_MOD_LXJ 305 +#define BSIM4_MOD_LVSAT 306 +#define BSIM4_MOD_LAT 307 +#define BSIM4_MOD_LA0 308 +#define BSIM4_MOD_LA1 309 +#define BSIM4_MOD_LA2 310 +#define BSIM4_MOD_LKETA 311 +#define BSIM4_MOD_LNSUB 312 +#define BSIM4_MOD_LNDEP 313 +#define BSIM4_MOD_LNGATE 315 +#define BSIM4_MOD_LGAMMA1 316 +#define BSIM4_MOD_LGAMMA2 317 +#define BSIM4_MOD_LVBX 318 +#define BSIM4_MOD_LVBM 320 +#define BSIM4_MOD_LXT 322 +#define BSIM4_MOD_LK1 325 +#define BSIM4_MOD_LKT1 326 +#define BSIM4_MOD_LKT1L 327 +#define BSIM4_MOD_LK2 328 +#define BSIM4_MOD_LKT2 329 +#define BSIM4_MOD_LK3 330 +#define BSIM4_MOD_LK3B 331 +#define BSIM4_MOD_LW0 332 +#define BSIM4_MOD_LLPE0 333 +#define BSIM4_MOD_LDVT0 334 +#define BSIM4_MOD_LDVT1 335 +#define BSIM4_MOD_LDVT2 336 +#define BSIM4_MOD_LDVT0W 337 +#define BSIM4_MOD_LDVT1W 338 +#define BSIM4_MOD_LDVT2W 339 +#define BSIM4_MOD_LDROUT 340 +#define BSIM4_MOD_LDSUB 341 +#define BSIM4_MOD_LVTH0 342 +#define BSIM4_MOD_LUA 343 +#define BSIM4_MOD_LUA1 344 +#define BSIM4_MOD_LUB 345 +#define BSIM4_MOD_LUB1 346 +#define BSIM4_MOD_LUC 347 +#define BSIM4_MOD_LUC1 348 +#define BSIM4_MOD_LU0 349 +#define BSIM4_MOD_LUTE 350 +#define BSIM4_MOD_LVOFF 351 +#define BSIM4_MOD_LDELTA 352 +#define BSIM4_MOD_LRDSW 353 +#define BSIM4_MOD_LPRT 354 +#define BSIM4_MOD_LLDD 355 +#define BSIM4_MOD_LETA 356 +#define BSIM4_MOD_LETA0 357 +#define BSIM4_MOD_LETAB 358 +#define BSIM4_MOD_LPCLM 359 +#define BSIM4_MOD_LPDIBL1 360 +#define BSIM4_MOD_LPDIBL2 361 +#define BSIM4_MOD_LPSCBE1 362 +#define BSIM4_MOD_LPSCBE2 363 +#define BSIM4_MOD_LPVAG 364 +#define BSIM4_MOD_LWR 365 +#define BSIM4_MOD_LDWG 366 +#define BSIM4_MOD_LDWB 367 +#define BSIM4_MOD_LB0 368 +#define BSIM4_MOD_LB1 369 +#define BSIM4_MOD_LALPHA0 370 +#define BSIM4_MOD_LBETA0 371 +#define BSIM4_MOD_LPDIBLB 374 +#define BSIM4_MOD_LPRWG 375 +#define BSIM4_MOD_LPRWB 376 +#define BSIM4_MOD_LCDSCD 377 +#define BSIM4_MOD_LAGS 378 + +#define BSIM4_MOD_LFRINGE 381 +#define BSIM4_MOD_LCGSL 383 +#define BSIM4_MOD_LCGDL 384 +#define BSIM4_MOD_LCKAPPAS 385 +#define BSIM4_MOD_LCF 386 +#define BSIM4_MOD_LCLC 387 +#define BSIM4_MOD_LCLE 388 +#define BSIM4_MOD_LVFBCV 389 +#define BSIM4_MOD_LACDE 390 +#define BSIM4_MOD_LMOIN 391 +#define BSIM4_MOD_LNOFF 392 +#define BSIM4_MOD_LALPHA1 394 +#define BSIM4_MOD_LVFB 395 +#define BSIM4_MOD_LVOFFCV 396 +#define BSIM4_MOD_LAGIDL 397 +#define BSIM4_MOD_LBGIDL 398 +#define BSIM4_MOD_LEGIDL 399 +#define BSIM4_MOD_LXRCRG1 400 +#define BSIM4_MOD_LXRCRG2 401 +#define BSIM4_MOD_LEU 402 +#define BSIM4_MOD_LMINV 403 +#define BSIM4_MOD_LPDITS 404 +#define BSIM4_MOD_LPDITSD 405 +#define BSIM4_MOD_LFPROUT 406 +#define BSIM4_MOD_LLPEB 407 +#define BSIM4_MOD_LDVTP0 408 +#define BSIM4_MOD_LDVTP1 409 +#define BSIM4_MOD_LCGIDL 410 +#define BSIM4_MOD_LPHIN 411 +#define BSIM4_MOD_LRSW 412 +#define BSIM4_MOD_LRDW 413 +#define BSIM4_MOD_LNSD 414 +#define BSIM4_MOD_LCKAPPAD 415 +#define BSIM4_MOD_LAIGC 416 +#define BSIM4_MOD_LBIGC 417 +#define BSIM4_MOD_LCIGC 418 +#define BSIM4_MOD_LAIGBACC 419 +#define BSIM4_MOD_LBIGBACC 420 +#define BSIM4_MOD_LCIGBACC 421 +#define BSIM4_MOD_LAIGBINV 422 +#define BSIM4_MOD_LBIGBINV 423 +#define BSIM4_MOD_LCIGBINV 424 +#define BSIM4_MOD_LNIGC 425 +#define BSIM4_MOD_LNIGBACC 426 +#define BSIM4_MOD_LNIGBINV 427 +#define BSIM4_MOD_LNTOX 428 +#define BSIM4_MOD_LEIGBINV 429 +#define BSIM4_MOD_LPIGCD 430 +#define BSIM4_MOD_LPOXEDGE 431 +#define BSIM4_MOD_LAIGSD 432 +#define BSIM4_MOD_LBIGSD 433 +#define BSIM4_MOD_LCIGSD 434 + + +/* Width dependence */ +#define BSIM4_MOD_WCDSC 481 +#define BSIM4_MOD_WCDSCB 482 +#define BSIM4_MOD_WCIT 483 +#define BSIM4_MOD_WNFACTOR 484 +#define BSIM4_MOD_WXJ 485 +#define BSIM4_MOD_WVSAT 486 +#define BSIM4_MOD_WAT 487 +#define BSIM4_MOD_WA0 488 +#define BSIM4_MOD_WA1 489 +#define BSIM4_MOD_WA2 490 +#define BSIM4_MOD_WKETA 491 +#define BSIM4_MOD_WNSUB 492 +#define BSIM4_MOD_WNDEP 493 +#define BSIM4_MOD_WNGATE 495 +#define BSIM4_MOD_WGAMMA1 496 +#define BSIM4_MOD_WGAMMA2 497 +#define BSIM4_MOD_WVBX 498 +#define BSIM4_MOD_WVBM 500 +#define BSIM4_MOD_WXT 502 +#define BSIM4_MOD_WK1 505 +#define BSIM4_MOD_WKT1 506 +#define BSIM4_MOD_WKT1L 507 +#define BSIM4_MOD_WK2 508 +#define BSIM4_MOD_WKT2 509 +#define BSIM4_MOD_WK3 510 +#define BSIM4_MOD_WK3B 511 +#define BSIM4_MOD_WW0 512 +#define BSIM4_MOD_WLPE0 513 +#define BSIM4_MOD_WDVT0 514 +#define BSIM4_MOD_WDVT1 515 +#define BSIM4_MOD_WDVT2 516 +#define BSIM4_MOD_WDVT0W 517 +#define BSIM4_MOD_WDVT1W 518 +#define BSIM4_MOD_WDVT2W 519 +#define BSIM4_MOD_WDROUT 520 +#define BSIM4_MOD_WDSUB 521 +#define BSIM4_MOD_WVTH0 522 +#define BSIM4_MOD_WUA 523 +#define BSIM4_MOD_WUA1 524 +#define BSIM4_MOD_WUB 525 +#define BSIM4_MOD_WUB1 526 +#define BSIM4_MOD_WUC 527 +#define BSIM4_MOD_WUC1 528 +#define BSIM4_MOD_WU0 529 +#define BSIM4_MOD_WUTE 530 +#define BSIM4_MOD_WVOFF 531 +#define BSIM4_MOD_WDELTA 532 +#define BSIM4_MOD_WRDSW 533 +#define BSIM4_MOD_WPRT 534 +#define BSIM4_MOD_WLDD 535 +#define BSIM4_MOD_WETA 536 +#define BSIM4_MOD_WETA0 537 +#define BSIM4_MOD_WETAB 538 +#define BSIM4_MOD_WPCLM 539 +#define BSIM4_MOD_WPDIBL1 540 +#define BSIM4_MOD_WPDIBL2 541 +#define BSIM4_MOD_WPSCBE1 542 +#define BSIM4_MOD_WPSCBE2 543 +#define BSIM4_MOD_WPVAG 544 +#define BSIM4_MOD_WWR 545 +#define BSIM4_MOD_WDWG 546 +#define BSIM4_MOD_WDWB 547 +#define BSIM4_MOD_WB0 548 +#define BSIM4_MOD_WB1 549 +#define BSIM4_MOD_WALPHA0 550 +#define BSIM4_MOD_WBETA0 551 +#define BSIM4_MOD_WPDIBLB 554 +#define BSIM4_MOD_WPRWG 555 +#define BSIM4_MOD_WPRWB 556 +#define BSIM4_MOD_WCDSCD 557 +#define BSIM4_MOD_WAGS 558 + +#define BSIM4_MOD_WFRINGE 561 +#define BSIM4_MOD_WCGSL 563 +#define BSIM4_MOD_WCGDL 564 +#define BSIM4_MOD_WCKAPPAS 565 +#define BSIM4_MOD_WCF 566 +#define BSIM4_MOD_WCLC 567 +#define BSIM4_MOD_WCLE 568 +#define BSIM4_MOD_WVFBCV 569 +#define BSIM4_MOD_WACDE 570 +#define BSIM4_MOD_WMOIN 571 +#define BSIM4_MOD_WNOFF 572 +#define BSIM4_MOD_WALPHA1 574 +#define BSIM4_MOD_WVFB 575 +#define BSIM4_MOD_WVOFFCV 576 +#define BSIM4_MOD_WAGIDL 577 +#define BSIM4_MOD_WBGIDL 578 +#define BSIM4_MOD_WEGIDL 579 +#define BSIM4_MOD_WXRCRG1 580 +#define BSIM4_MOD_WXRCRG2 581 +#define BSIM4_MOD_WEU 582 +#define BSIM4_MOD_WMINV 583 +#define BSIM4_MOD_WPDITS 584 +#define BSIM4_MOD_WPDITSD 585 +#define BSIM4_MOD_WFPROUT 586 +#define BSIM4_MOD_WLPEB 587 +#define BSIM4_MOD_WDVTP0 588 +#define BSIM4_MOD_WDVTP1 589 +#define BSIM4_MOD_WCGIDL 590 +#define BSIM4_MOD_WPHIN 591 +#define BSIM4_MOD_WRSW 592 +#define BSIM4_MOD_WRDW 593 +#define BSIM4_MOD_WNSD 594 +#define BSIM4_MOD_WCKAPPAD 595 +#define BSIM4_MOD_WAIGC 596 +#define BSIM4_MOD_WBIGC 597 +#define BSIM4_MOD_WCIGC 598 +#define BSIM4_MOD_WAIGBACC 599 +#define BSIM4_MOD_WBIGBACC 600 +#define BSIM4_MOD_WCIGBACC 601 +#define BSIM4_MOD_WAIGBINV 602 +#define BSIM4_MOD_WBIGBINV 603 +#define BSIM4_MOD_WCIGBINV 604 +#define BSIM4_MOD_WNIGC 605 +#define BSIM4_MOD_WNIGBACC 606 +#define BSIM4_MOD_WNIGBINV 607 +#define BSIM4_MOD_WNTOX 608 +#define BSIM4_MOD_WEIGBINV 609 +#define BSIM4_MOD_WPIGCD 610 +#define BSIM4_MOD_WPOXEDGE 611 +#define BSIM4_MOD_WAIGSD 612 +#define BSIM4_MOD_WBIGSD 613 +#define BSIM4_MOD_WCIGSD 614 + + +/* Cross-term dependence */ +#define BSIM4_MOD_PCDSC 661 +#define BSIM4_MOD_PCDSCB 662 +#define BSIM4_MOD_PCIT 663 +#define BSIM4_MOD_PNFACTOR 664 +#define BSIM4_MOD_PXJ 665 +#define BSIM4_MOD_PVSAT 666 +#define BSIM4_MOD_PAT 667 +#define BSIM4_MOD_PA0 668 +#define BSIM4_MOD_PA1 669 +#define BSIM4_MOD_PA2 670 +#define BSIM4_MOD_PKETA 671 +#define BSIM4_MOD_PNSUB 672 +#define BSIM4_MOD_PNDEP 673 +#define BSIM4_MOD_PNGATE 675 +#define BSIM4_MOD_PGAMMA1 676 +#define BSIM4_MOD_PGAMMA2 677 +#define BSIM4_MOD_PVBX 678 + +#define BSIM4_MOD_PVBM 680 + +#define BSIM4_MOD_PXT 682 +#define BSIM4_MOD_PK1 685 +#define BSIM4_MOD_PKT1 686 +#define BSIM4_MOD_PKT1L 687 +#define BSIM4_MOD_PK2 688 +#define BSIM4_MOD_PKT2 689 +#define BSIM4_MOD_PK3 690 +#define BSIM4_MOD_PK3B 691 +#define BSIM4_MOD_PW0 692 +#define BSIM4_MOD_PLPE0 693 + +#define BSIM4_MOD_PDVT0 694 +#define BSIM4_MOD_PDVT1 695 +#define BSIM4_MOD_PDVT2 696 + +#define BSIM4_MOD_PDVT0W 697 +#define BSIM4_MOD_PDVT1W 698 +#define BSIM4_MOD_PDVT2W 699 + +#define BSIM4_MOD_PDROUT 700 +#define BSIM4_MOD_PDSUB 701 +#define BSIM4_MOD_PVTH0 702 +#define BSIM4_MOD_PUA 703 +#define BSIM4_MOD_PUA1 704 +#define BSIM4_MOD_PUB 705 +#define BSIM4_MOD_PUB1 706 +#define BSIM4_MOD_PUC 707 +#define BSIM4_MOD_PUC1 708 +#define BSIM4_MOD_PU0 709 +#define BSIM4_MOD_PUTE 710 +#define BSIM4_MOD_PVOFF 711 +#define BSIM4_MOD_PDELTA 712 +#define BSIM4_MOD_PRDSW 713 +#define BSIM4_MOD_PPRT 714 +#define BSIM4_MOD_PLDD 715 +#define BSIM4_MOD_PETA 716 +#define BSIM4_MOD_PETA0 717 +#define BSIM4_MOD_PETAB 718 +#define BSIM4_MOD_PPCLM 719 +#define BSIM4_MOD_PPDIBL1 720 +#define BSIM4_MOD_PPDIBL2 721 +#define BSIM4_MOD_PPSCBE1 722 +#define BSIM4_MOD_PPSCBE2 723 +#define BSIM4_MOD_PPVAG 724 +#define BSIM4_MOD_PWR 725 +#define BSIM4_MOD_PDWG 726 +#define BSIM4_MOD_PDWB 727 +#define BSIM4_MOD_PB0 728 +#define BSIM4_MOD_PB1 729 +#define BSIM4_MOD_PALPHA0 730 +#define BSIM4_MOD_PBETA0 731 +#define BSIM4_MOD_PPDIBLB 734 + +#define BSIM4_MOD_PPRWG 735 +#define BSIM4_MOD_PPRWB 736 + +#define BSIM4_MOD_PCDSCD 737 +#define BSIM4_MOD_PAGS 738 + +#define BSIM4_MOD_PFRINGE 741 +#define BSIM4_MOD_PCGSL 743 +#define BSIM4_MOD_PCGDL 744 +#define BSIM4_MOD_PCKAPPAS 745 +#define BSIM4_MOD_PCF 746 +#define BSIM4_MOD_PCLC 747 +#define BSIM4_MOD_PCLE 748 +#define BSIM4_MOD_PVFBCV 749 +#define BSIM4_MOD_PACDE 750 +#define BSIM4_MOD_PMOIN 751 +#define BSIM4_MOD_PNOFF 752 +#define BSIM4_MOD_PALPHA1 754 +#define BSIM4_MOD_PVFB 755 +#define BSIM4_MOD_PVOFFCV 756 +#define BSIM4_MOD_PAGIDL 757 +#define BSIM4_MOD_PBGIDL 758 +#define BSIM4_MOD_PEGIDL 759 +#define BSIM4_MOD_PXRCRG1 760 +#define BSIM4_MOD_PXRCRG2 761 +#define BSIM4_MOD_PEU 762 +#define BSIM4_MOD_PMINV 763 +#define BSIM4_MOD_PPDITS 764 +#define BSIM4_MOD_PPDITSD 765 +#define BSIM4_MOD_PFPROUT 766 +#define BSIM4_MOD_PLPEB 767 +#define BSIM4_MOD_PDVTP0 768 +#define BSIM4_MOD_PDVTP1 769 +#define BSIM4_MOD_PCGIDL 770 +#define BSIM4_MOD_PPHIN 771 +#define BSIM4_MOD_PRSW 772 +#define BSIM4_MOD_PRDW 773 +#define BSIM4_MOD_PNSD 774 +#define BSIM4_MOD_PCKAPPAD 775 +#define BSIM4_MOD_PAIGC 776 +#define BSIM4_MOD_PBIGC 777 +#define BSIM4_MOD_PCIGC 778 +#define BSIM4_MOD_PAIGBACC 779 +#define BSIM4_MOD_PBIGBACC 780 +#define BSIM4_MOD_PCIGBACC 781 +#define BSIM4_MOD_PAIGBINV 782 +#define BSIM4_MOD_PBIGBINV 783 +#define BSIM4_MOD_PCIGBINV 784 +#define BSIM4_MOD_PNIGC 785 +#define BSIM4_MOD_PNIGBACC 786 +#define BSIM4_MOD_PNIGBINV 787 +#define BSIM4_MOD_PNTOX 788 +#define BSIM4_MOD_PEIGBINV 789 +#define BSIM4_MOD_PPIGCD 790 +#define BSIM4_MOD_PPOXEDGE 791 +#define BSIM4_MOD_PAIGSD 792 +#define BSIM4_MOD_PBIGSD 793 +#define BSIM4_MOD_PCIGSD 794 + +#define BSIM4_MOD_TNOM 831 +#define BSIM4_MOD_CGSO 832 +#define BSIM4_MOD_CGDO 833 +#define BSIM4_MOD_CGBO 834 +#define BSIM4_MOD_XPART 835 +#define BSIM4_MOD_RSH 836 +#define BSIM4_MOD_JSS 837 +#define BSIM4_MOD_PBS 838 +#define BSIM4_MOD_MJS 839 +#define BSIM4_MOD_PBSWS 840 +#define BSIM4_MOD_MJSWS 841 +#define BSIM4_MOD_CJS 842 +#define BSIM4_MOD_CJSWS 843 +#define BSIM4_MOD_NMOS 844 +#define BSIM4_MOD_PMOS 845 +#define BSIM4_MOD_NOIA 846 +#define BSIM4_MOD_NOIB 847 +#define BSIM4_MOD_NOIC 848 +#define BSIM4_MOD_LINT 849 +#define BSIM4_MOD_LL 850 +#define BSIM4_MOD_LLN 851 +#define BSIM4_MOD_LW 852 +#define BSIM4_MOD_LWN 853 +#define BSIM4_MOD_LWL 854 +#define BSIM4_MOD_LMIN 855 +#define BSIM4_MOD_LMAX 856 +#define BSIM4_MOD_WINT 857 +#define BSIM4_MOD_WL 858 +#define BSIM4_MOD_WLN 859 +#define BSIM4_MOD_WW 860 +#define BSIM4_MOD_WWN 861 +#define BSIM4_MOD_WWL 862 +#define BSIM4_MOD_WMIN 863 +#define BSIM4_MOD_WMAX 864 +#define BSIM4_MOD_DWC 865 +#define BSIM4_MOD_DLC 866 +#define BSIM4_MOD_EM 867 +#define BSIM4_MOD_EF 868 +#define BSIM4_MOD_AF 869 +#define BSIM4_MOD_KF 870 +#define BSIM4_MOD_NJS 871 +#define BSIM4_MOD_XTIS 872 +#define BSIM4_MOD_PBSWGS 873 +#define BSIM4_MOD_MJSWGS 874 +#define BSIM4_MOD_CJSWGS 875 +#define BSIM4_MOD_JSWS 876 +#define BSIM4_MOD_LLC 877 +#define BSIM4_MOD_LWC 878 +#define BSIM4_MOD_LWLC 879 +#define BSIM4_MOD_WLC 880 +#define BSIM4_MOD_WWC 881 +#define BSIM4_MOD_WWLC 882 +#define BSIM4_MOD_DWJ 883 +#define BSIM4_MOD_JSD 884 +#define BSIM4_MOD_PBD 885 +#define BSIM4_MOD_MJD 886 +#define BSIM4_MOD_PBSWD 887 +#define BSIM4_MOD_MJSWD 888 +#define BSIM4_MOD_CJD 889 +#define BSIM4_MOD_CJSWD 890 +#define BSIM4_MOD_NJD 891 +#define BSIM4_MOD_XTID 892 +#define BSIM4_MOD_PBSWGD 893 +#define BSIM4_MOD_MJSWGD 894 +#define BSIM4_MOD_CJSWGD 895 +#define BSIM4_MOD_JSWD 896 +#define BSIM4_MOD_DLCIG 897 + +/* device questions */ +#define BSIM4_DNODE 945 +#define BSIM4_GNODEEXT 946 +#define BSIM4_SNODE 947 +#define BSIM4_BNODE 948 +#define BSIM4_DNODEPRIME 949 +#define BSIM4_GNODEPRIME 950 +#define BSIM4_GNODEMIDE 951 +#define BSIM4_GNODEMID 952 +#define BSIM4_SNODEPRIME 953 +#define BSIM4_BNODEPRIME 954 +#define BSIM4_DBNODE 955 +#define BSIM4_SBNODE 956 +#define BSIM4_VBD 957 +#define BSIM4_VBS 958 +#define BSIM4_VGS 959 +#define BSIM4_VDS 960 +#define BSIM4_CD 961 +#define BSIM4_CBS 962 +#define BSIM4_CBD 963 +#define BSIM4_GM 964 +#define BSIM4_GDS 965 +#define BSIM4_GMBS 966 +#define BSIM4_GBD 967 +#define BSIM4_GBS 968 +#define BSIM4_QB 969 +#define BSIM4_CQB 970 +#define BSIM4_QG 971 +#define BSIM4_CQG 972 +#define BSIM4_QD 973 +#define BSIM4_CQD 974 +#define BSIM4_CGG 975 +#define BSIM4_CGD 976 +#define BSIM4_CGS 977 +#define BSIM4_CBG 978 +#define BSIM4_CAPBD 979 +#define BSIM4_CQBD 980 +#define BSIM4_CAPBS 981 +#define BSIM4_CQBS 982 +#define BSIM4_CDG 983 +#define BSIM4_CDD 984 +#define BSIM4_CDS 985 +#define BSIM4_VON 986 +#define BSIM4_VDSAT 987 +#define BSIM4_QBS 988 +#define BSIM4_QBD 989 +#define BSIM4_SOURCECONDUCT 990 +#define BSIM4_DRAINCONDUCT 991 +#define BSIM4_CBDB 992 +#define BSIM4_CBSB 993 + +#include "bsim4ext.h" + +#ifdef __STDC__ +extern void BSIM4evaluate(double,double,double,BSIM4instance*,BSIM4model*, + double*,double*,double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, CKTcircuit*); +extern int BSIM4debug(BSIM4model*, BSIM4instance*, CKTcircuit*, int); +extern int BSIM4checkModel(BSIM4model*, BSIM4instance*, CKTcircuit*); +#else /* stdc */ +extern void BSIM4evaluate(); +extern int BSIM4debug(); +extern int BSIM4checkModel(); +#endif /* stdc */ + +#endif /*BSIM4*/ diff --git a/src/spicelib/devices/bsim4/bsim4ext.h b/src/spicelib/devices/bsim4/bsim4ext.h new file mode 100644 index 000000000..4cc7979c2 --- /dev/null +++ b/src/spicelib/devices/bsim4/bsim4ext.h @@ -0,0 +1,53 @@ +/********** +Copyright 2000 Regents of the University of California. All rights reserved. +Author: 2000 Weidong Liu. +File: bsim4ext.h +**********/ + +#ifdef __STDC__ +extern int BSIM4acLoad(GENmodel *,CKTcircuit*); +extern int BSIM4ask(CKTcircuit *,GENinstance*,int,IFvalue*,IFvalue*); +extern int BSIM4convTest(GENmodel *,CKTcircuit*); +extern int BSIM4delete(GENmodel*,IFuid,GENinstance**); +extern void BSIM4destroy(GENmodel**); +extern int BSIM4getic(GENmodel*,CKTcircuit*); +extern int BSIM4load(GENmodel*,CKTcircuit*); +extern int BSIM4mAsk(CKTcircuit*,GENmodel *,int, IFvalue*); +extern int BSIM4mDelete(GENmodel**,IFuid,GENmodel*); +extern int BSIM4mParam(int,IFvalue*,GENmodel*); +extern void BSIM4mosCap(CKTcircuit*, double, double, double, double, + double, double, double, double, double, double, double, + double, double, double, double, double, double, double*, + double*, double*, double*, double*, double*, double*, double*, + double*, double*, double*, double*, double*, double*, double*, + double*); +extern int BSIM4param(int,IFvalue*,GENinstance*,IFvalue*); +extern int BSIM4pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int BSIM4setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int BSIM4temp(GENmodel*,CKTcircuit*); +extern int BSIM4trunc(GENmodel*,CKTcircuit*,double*); +extern int BSIM4noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); +extern int BSIM4unsetup(GENmodel*,CKTcircuit*); + +#else /* stdc */ +extern int BSIM4acLoad(); +extern int BSIM4delete(); +extern void BSIM4destroy(); +extern int BSIM4getic(); +extern int BSIM4load(); +extern int BSIM4mDelete(); +extern int BSIM4ask(); +extern int BSIM4mAsk(); +extern int BSIM4convTest(); +extern int BSIM4temp(); +extern int BSIM4mParam(); +extern void BSIM4mosCap(); +extern int BSIM4param(); +extern int BSIM4pzLoad(); +extern int BSIM4setup(); +extern int BSIM4trunc(); +extern int BSIM4noise(); +extern int BSIM4unsetup(); + +#endif /* stdc */ + diff --git a/src/spicelib/devices/bsim4/bsim4itf.h b/src/spicelib/devices/bsim4/bsim4itf.h new file mode 100644 index 000000000..403f05c8b --- /dev/null +++ b/src/spicelib/devices/bsim4/bsim4itf.h @@ -0,0 +1,88 @@ +/********** +Copyright 2000 Regents of the University of California. All rights reserved. +Author: 2000 Weidong Liu. +File: bsim4itf.h +**********/ +#ifdef DEV_bsim4 + +#ifndef DEV_BSIM4 +#define DEV_BSIM4 + +#include "bsim4ext.h" + +extern IFparm BSIM4pTable[ ]; +extern IFparm BSIM4mPTable[ ]; +extern char *BSIM4names[ ]; +extern int BSIM4pTSize; +extern int BSIM4mPTSize; +extern int BSIM4nSize; +extern int BSIM4iSize; +extern int BSIM4mSize; + +SPICEdev B4info = { + { "BSIM4", + "Berkeley Short Channel IGFET Model-4", + + &BSIM4nSize, + &BSIM4nSize, + BSIM4names, + + &BSIM4pTSize, + BSIM4pTable, + + &BSIM4mPTSize, + BSIM4mPTable, + DEV_DEFAULT + }, + BSIM4param, + BSIM4mParam, + BSIM4load, + BSIM4setup, + BSIM4unsetup, + BSIM4setup, + BSIM4temp, + BSIM4trunc, + NULL, + BSIM4acLoad, + NULL, + BSIM4destroy, +#ifdef DELETES + BSIM4mDelete, + BSIM4delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + BSIM4getic, + BSIM4ask, + BSIM4mAsk, +#ifdef AN_pz + BSIM4pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + BSIM4convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + +#ifdef AN_noise + BSIM4noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &BSIM4iSize, + &BSIM4mSize +}; + +#endif +#endif diff --git a/src/spicelib/devices/cap/ChangeLog b/src/spicelib/devices/cap/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/cap/Makefile.am b/src/spicelib/devices/cap/Makefile.am new file mode 100644 index 000000000..f24c04913 --- /dev/null +++ b/src/spicelib/devices/cap/Makefile.am @@ -0,0 +1,34 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libcap.la + +libcap_la_SOURCES = \ + cap.c \ + capacld.c \ + capask.c \ + capdefs.h \ + capdel.c \ + capdest.c \ + capext.h \ + capgetic.c \ + capitf.h \ + capload.c \ + capmask.c \ + capmdel.c \ + capmpar.c \ + capparam.c \ + cappzld.c \ + capsacl.c \ + capsetup.c \ + capsload.c \ + capsprt.c \ + capsset.c \ + capsupd.c \ + captemp.c \ + captrunc.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/cap/cap.c b/src/spicelib/devices/cap/cap.c new file mode 100644 index 000000000..ba0a49f23 --- /dev/null +++ b/src/spicelib/devices/cap/cap.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "capdefs.h" +#include "suffix.h" + +IFparm CAPpTable[] = { /* parameters */ + IOPAP("capacitance", CAP_CAP, IF_REAL, "Device capacitance"), + IOPAU("ic", CAP_IC, IF_REAL, "Initial capacitor voltage"), + IOPAU("w", CAP_WIDTH, IF_REAL, "Device width"), + IOPAU("l", CAP_LENGTH, IF_REAL, "Device length"), + IP("sens_cap", CAP_CAP_SENS, IF_FLAG, "flag to request sens. WRT cap."), + OP("i", CAP_CURRENT,IF_REAL, "Device current"), + OP("p", CAP_POWER, IF_REAL, "Instantaneous device power"), + OPU("sens_dc", CAP_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU("sens_real", CAP_QUEST_SENS_REAL, IF_REAL, "real part of ac sensitivity"), + OPU("sens_imag",CAP_QUEST_SENS_IMAG,IF_REAL, + "dc sens. & imag part of ac sens."), + OPU("sens_mag", CAP_QUEST_SENS_MAG, IF_REAL, "sensitivity of ac magnitude"), + OPU("sens_ph", CAP_QUEST_SENS_PH, IF_REAL, "sensitivity of ac phase"), + OPU("sens_cplx", CAP_QUEST_SENS_CPLX, IF_COMPLEX, "ac sensitivity") +}; + +IFparm CAPmPTable[] = { /* names of model parameters */ + IOPA( "cj", CAP_MOD_CJ, IF_REAL, "Bottom Capacitance per area"), + IOPA( "cjsw", CAP_MOD_CJSW, IF_REAL, "Sidewall capacitance per meter"), + IOPX( "defw", CAP_MOD_DEFWIDTH,IF_REAL, "Default width"), + IP( "c", CAP_MOD_C, IF_FLAG, "Capacitor model"), + IOPA( "narrow", CAP_MOD_NARROW, IF_REAL, "width correction factor") +}; + +char *CAPnames[] = { + "C+", + "C-" +}; + + +int CAPnSize = NUMELEMS(CAPnames); +int CAPpTSize = NUMELEMS(CAPpTable); +int CAPmPTSize = NUMELEMS(CAPmPTable); +int CAPiSize = sizeof(CAPinstance); +int CAPmSize = sizeof(CAPmodel); diff --git a/src/spicelib/devices/cap/capacld.c b/src/spicelib/devices/cap/capacld.c new file mode 100644 index 000000000..f1990eab7 --- /dev/null +++ b/src/spicelib/devices/cap/capacld.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + +{ + register CAPmodel *model = (CAPmodel*)inModel; + double val; + register CAPinstance *here; + + for( ; model != NULL; model = model->CAPnextModel) { + for( here = model->CAPinstances;here != NULL; + here = here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + val = ckt->CKTomega * here->CAPcapac; + *(here->CAPposPosptr +1) += val; + *(here->CAPnegNegptr +1) += val; + *(here->CAPposNegptr +1) -= val; + *(here->CAPnegPosptr +1) -= val; + } + } + return(OK); + +} + diff --git a/src/spicelib/devices/cap/capask.c b/src/spicelib/devices/cap/capask.c new file mode 100644 index 000000000..d1b7b81d7 --- /dev/null +++ b/src/spicelib/devices/cap/capask.c @@ -0,0 +1,146 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "capdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +CAPask(ckt,inst, which, value, select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + CAPinstance *here = (CAPinstance *)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + + switch(which) { + case CAP_CAP: + value->rValue=here->CAPcapac; + return(OK); + case CAP_IC: + value->rValue = here->CAPinitCond; + return(OK); + case CAP_WIDTH: + value->rValue = here->CAPwidth; + return(OK); + case CAP_LENGTH: + value->rValue = here->CAPlength; + return(OK); + case CAP_CURRENT: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CAPask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { + value->rValue = 0; + } else if (ckt->CKTcurrentAnalysis & DOING_TRAN) { + if (ckt->CKTmode & MODETRANOP) { + value->rValue = 0; + } else { + value->rValue = *(ckt->CKTstate0 + here->CAPccap); + } + } + return(OK); + case CAP_POWER: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CAPask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { + value->rValue = 0; + } else if (ckt->CKTcurrentAnalysis & DOING_TRAN) { + if (ckt->CKTmode & MODETRANOP) { + value->rValue = 0; + } else { + value->rValue = *(ckt->CKTstate0 + here->CAPccap) * + (*(ckt->CKTrhsOld + here->CAPposNode) - + *(ckt->CKTrhsOld + here->CAPnegNode)); + } + } + return(OK); + case CAP_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->CAPsenParmNo); + } + return(OK); + case CAP_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CAPsenParmNo); + } + return(OK); + case CAP_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CAPsenParmNo); + } + return(OK); + case CAP_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CAPsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CAPsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case CAP_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CAPsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CAPsenParmNo); + + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + + case CAP_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CAPsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CAPsenParmNo); + } + return(OK); + + default: + return(E_BADPARM); + } +} + diff --git a/src/spicelib/devices/cap/capdefs.h b/src/spicelib/devices/cap/capdefs.h new file mode 100644 index 000000000..0ac039fce --- /dev/null +++ b/src/spicelib/devices/cap/capdefs.h @@ -0,0 +1,104 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef CAP +#define CAP + + +#include "ifsim.h" +#include "complex.h" +#include "gendefs.h" +#include "cktdefs.h" + + /* structures used to describe capacitors */ + + +/* information to describe each instance */ + +typedef struct sCAPinstance { + struct sCAPmodel *CAPmodPtr; /* backpointer to model */ + struct sCAPinstance *CAPnextInstance; /* pointer to next instance of + * current model*/ + IFuid CAPname; /* pointer to character string naming this instance */ + int CAPowner; /* number of owner process */ + int CAPstate; /* pointer to start of capacitor state vector */ + + int CAPposNode; /* number of positive node of capacitor */ + int CAPnegNode; /* number of negative node of capacitor */ + double CAPcapac; /* capacitance */ + double CAPinitCond; /* initial capacitor voltage if specified */ + double CAPwidth; /* width of the capacitor */ + double CAPlength; /* length of the capacitor */ + + double *CAPposPosptr; /* pointer to sparse matrix diagonal at + * (positive,positive) */ + double *CAPnegNegptr; /* pointer to sparse matrix diagonal at + * (negative,negative) */ + double *CAPposNegptr; /* pointer to sparse matrix offdiagonal at + * (positive,negative) */ + double *CAPnegPosptr; /* pointer to sparse matrix offdiagonal at + * (negative,positive) */ + unsigned CAPcapGiven : 1; /* flag to indicate capacitance was specified */ + unsigned CAPicGiven : 1; /* flag to indicate init. cond. was specified */ + unsigned CAPwidthGiven : 1; /* flag to indicate capacitor width given */ + unsigned CAPlengthGiven : 1; /* flag to indicate capacitor length given*/ + int CAPsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + +} CAPinstance ; + +#define CAPqcap CAPstate /* charge on the capacitor */ +#define CAPccap CAPstate+1 /* current through the capacitor */ +#define CAPsensxp CAPstate+2 /* charge sensitivities and their derivatives. + +3 for the derivatives - pointer to the + beginning of the array */ + + +/* data per model */ + +typedef struct sCAPmodel { /* model structure for a capacitor */ + int CAPmodType; /* type index of this device type */ + struct sCAPmodel *CAPnextModel; /* pointer to next possible model in + * linked list */ + CAPinstance * CAPinstances; /* pointer to list of instances that have this + * model */ + IFuid CAPmodName; /* pointer to character string naming this model */ + double CAPcj; /* Unit Area Capacitance ( F/ M**2 ) */ + double CAPcjsw; /* Unit Length Sidewall Capacitance ( F / M ) */ + double CAPdefWidth; /* the default width of a capacitor */ + double CAPnarrow; /* amount by which length/width are less than drawn */ + unsigned CAPcjGiven : 1; /* Unit Area Capacitance ( F/ M**2 ) */ + unsigned CAPcjswGiven : 1; /* Unit Length Sidewall Capacitance( F/M )*/ + unsigned CAPdefWidthGiven : 1; /* flag indicates default width given*/ + unsigned CAPnarrowGiven : 1; /* flag indicates narrowing factor given */ +} CAPmodel; + +/* device parameters */ +#define CAP_CAP 1 +#define CAP_IC 2 +#define CAP_WIDTH 3 +#define CAP_LENGTH 4 +#define CAP_CAP_SENS 5 +#define CAP_CURRENT 6 +#define CAP_POWER 7 + +/* model parameters */ +#define CAP_MOD_CJ 101 +#define CAP_MOD_CJSW 102 +#define CAP_MOD_DEFWIDTH 103 +#define CAP_MOD_C 104 +#define CAP_MOD_NARROW 105 + +/* device questions */ +#define CAP_QUEST_SENS_REAL 201 +#define CAP_QUEST_SENS_IMAG 202 +#define CAP_QUEST_SENS_MAG 203 +#define CAP_QUEST_SENS_PH 204 +#define CAP_QUEST_SENS_CPLX 205 +#define CAP_QUEST_SENS_DC 206 + +#include "capext.h" + +#endif /*CAP*/ diff --git a/src/spicelib/devices/cap/capdel.c b/src/spicelib/devices/cap/capdel.c new file mode 100644 index 000000000..c2c44f0d3 --- /dev/null +++ b/src/spicelib/devices/cap/capdel.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; + +{ + + CAPinstance **fast = (CAPinstance**)inst; + CAPmodel *model = (CAPmodel*)inModel; + CAPinstance **prev = NULL; + CAPinstance *here; + + for( ; model ; model = model->CAPnextModel) { + prev = &(model->CAPinstances); + for(here = *prev; here ; here = *prev) { + if(here->CAPname == name || (fast && here==*fast) ) { + *prev= here->CAPnextInstance; + FREE(here); + return(OK); + } + prev = &(here->CAPnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/cap/capdest.c b/src/spicelib/devices/cap/capdest.c new file mode 100644 index 000000000..d65c7155e --- /dev/null +++ b/src/spicelib/devices/cap/capdest.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "capdefs.h" +#include "suffix.h" + + +void +CAPdestroy(inModel) + GENmodel **inModel; + +{ + + CAPmodel **model = (CAPmodel**)inModel; + CAPinstance *here; + CAPinstance *prev = NULL; + CAPmodel *mod = *model; + CAPmodel *oldmod = NULL; + + for( ; mod ; mod = mod->CAPnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (CAPinstance *)NULL; + for(here = mod->CAPinstances ; here ; here = here->CAPnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/cap/capext.h b/src/spicelib/devices/cap/capext.h new file mode 100644 index 000000000..fc66a6da5 --- /dev/null +++ b/src/spicelib/devices/cap/capext.h @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int CAPacLoad(GENmodel*,CKTcircuit*); +extern int CAPask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int CAPdelete(GENmodel*,IFuid,GENinstance**); +extern void CAPdestroy(GENmodel**); +extern int CAPgetic(GENmodel*,CKTcircuit*); +extern int CAPload(GENmodel*,CKTcircuit*); +extern int CAPmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int CAPmDelete(GENmodel**,IFuid,GENmodel*); +extern int CAPmParam(int,IFvalue*,GENmodel*); +extern int CAPparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int CAPpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int CAPsAcLoad(GENmodel*,CKTcircuit*); +extern int CAPsLoad(GENmodel*,CKTcircuit*); +extern void CAPsPrint(GENmodel*,CKTcircuit*); +extern int CAPsSetup(SENstruct *,GENmodel*); +extern int CAPsUpdate(GENmodel*,CKTcircuit*); +extern int CAPsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int CAPtemp(GENmodel*,CKTcircuit*); +extern int CAPtrunc(GENmodel*,CKTcircuit*,double*); +#else /* stdc */ +extern int CAPacLoad(); +extern int CAPask(); +extern int CAPdelete(); +extern void CAPdestroy(); +extern int CAPgetic(); +extern int CAPload(); +extern int CAPmAsk(); +extern int CAPmDelete(); +extern int CAPmParam(); +extern int CAPparam(); +extern int CAPpzLoad(); +extern int CAPsAcLoad(); +extern int CAPsLoad(); +extern void CAPsPrint(); +extern int CAPsSetup(); +extern int CAPsUpdate(); +extern int CAPsetup(); +extern int CAPtemp(); +extern int CAPtrunc(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/cap/capgetic.c b/src/spicelib/devices/cap/capgetic.c new file mode 100644 index 000000000..307b11947 --- /dev/null +++ b/src/spicelib/devices/cap/capgetic.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +CAPgetic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + +{ + + CAPmodel *model = (CAPmodel*)inModel; + CAPinstance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->CAPnextModel) { + for(here = model->CAPinstances; here ; here = here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + if(!here->CAPicGiven) { + here->CAPinitCond = + *(ckt->CKTrhs + here->CAPposNode) - + *(ckt->CKTrhs + here->CAPnegNode); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/capitf.h b/src/spicelib/devices/cap/capitf.h new file mode 100644 index 000000000..5ce8503cb --- /dev/null +++ b/src/spicelib/devices/cap/capitf.h @@ -0,0 +1,88 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_cap + +#ifndef DEV_CAP +#define DEV_CAP + +#include "capext.h" +extern IFparm CAPpTable[ ]; +extern IFparm CAPmPTable[ ]; +extern char *CAPnames[ ]; +extern int CAPpTSize; +extern int CAPmPTSize; +extern int CAPnSize; +extern int CAPiSize; +extern int CAPmSize; + +SPICEdev CAPinfo = { + { "Capacitor", + "Fixed capacitor", + + &CAPnSize, + &CAPnSize, + CAPnames, + + &CAPpTSize, + CAPpTable, + + &CAPmPTSize, + CAPmPTable, + 0 + }, + + CAPparam, + CAPmParam, + CAPload, + CAPsetup, + NULL, + CAPsetup, + CAPtemp, + CAPtrunc, + NULL, + CAPacLoad, + NULL, + CAPdestroy, +#ifdef DELETES + CAPmDelete, + CAPdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + CAPgetic, + CAPask, + CAPmAsk, +#ifdef AN_pz + CAPpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense2 + CAPsSetup, + CAPsLoad, + CAPsUpdate, + CAPsAcLoad, + CAPsPrint, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ + NULL, + NULL, /* DISTO */ + NULL, /* NOISE */ + + &CAPiSize, + &CAPmSize + + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/cap/capload.c b/src/spicelib/devices/cap/capload.c new file mode 100644 index 000000000..849233866 --- /dev/null +++ b/src/spicelib/devices/cap/capload.c @@ -0,0 +1,88 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +CAPload(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current capacitance value into the + * sparse matrix previously provided + */ +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + register int cond1; + double vcap; + double geq; + double ceq; + int error; + + /* check if capacitors are in the circuit or are open circuited */ + if(ckt->CKTmode & (MODETRAN|MODEAC|MODETRANOP) ) { + /* evaluate device independent analysis conditions */ + cond1= + ( ( (ckt->CKTmode & MODEDC) && + (ckt->CKTmode & MODEINITJCT) ) + || ( ( ckt->CKTmode & MODEUIC) && + ( ckt->CKTmode & MODEINITTRAN) ) ) ; + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + if(cond1) { + vcap = here->CAPinitCond; + } else { + vcap = *(ckt->CKTrhsOld+here->CAPposNode) - + *(ckt->CKTrhsOld+here->CAPnegNode) ; + } + if(ckt->CKTmode & (MODETRAN | MODEAC)) { +#ifndef PREDICTOR + if(ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0+here->CAPqcap) = + *(ckt->CKTstate1+here->CAPqcap); + } else { /* only const caps - no poly's */ +#endif /* PREDICTOR */ + *(ckt->CKTstate0+here->CAPqcap) = here->CAPcapac * vcap; + if((ckt->CKTmode & MODEINITTRAN)) { + *(ckt->CKTstate1+here->CAPqcap) = + *(ckt->CKTstate0+here->CAPqcap); + } +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + error = NIintegrate(ckt,&geq,&ceq,here->CAPcapac, + here->CAPqcap); + if(error) return(error); + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1+here->CAPccap) = + *(ckt->CKTstate0+here->CAPccap); + } + *(here->CAPposPosptr) += geq; + *(here->CAPnegNegptr) += geq; + *(here->CAPposNegptr) -= geq; + *(here->CAPnegPosptr) -= geq; + *(ckt->CKTrhs+here->CAPposNode) -= ceq; + *(ckt->CKTrhs+here->CAPnegNode) += ceq; + } else + *(ckt->CKTstate0+here->CAPqcap) = here->CAPcapac * vcap; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/capmask.c b/src/spicelib/devices/cap/capmask.c new file mode 100644 index 000000000..7e41cd7e8 --- /dev/null +++ b/src/spicelib/devices/cap/capmask.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "capdefs.h" +#include "sperror.h" +#include "ifsim.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CAPmAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + CAPmodel *here = (CAPmodel*)inst; + switch(which) { + case CAP_MOD_CJ: + value->rValue = here->CAPcj; + return(OK); + case CAP_MOD_CJSW: + value->rValue = here->CAPcjsw; + return(OK); + case CAP_MOD_DEFWIDTH: + value->rValue = here->CAPdefWidth; + return(OK); + case CAP_MOD_NARROW: + value->rValue = here->CAPnarrow; + return(OK); + default: + return(E_BADPARM); + } +} diff --git a/src/spicelib/devices/cap/capmdel.c b/src/spicelib/devices/cap/capmdel.c new file mode 100644 index 000000000..ba21d092c --- /dev/null +++ b/src/spicelib/devices/cap/capmdel.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + + CAPmodel *modfast = (CAPmodel*)kill; + CAPmodel **model = (CAPmodel**)inModel; + CAPinstance *here; + CAPinstance *prev = NULL; + CAPmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->CAPnextModel)) { + if( (*model)->CAPmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->CAPnextModel; /* cut deleted device out of list */ + for(here = (*model)->CAPinstances ; here ; here = here->CAPnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} + diff --git a/src/spicelib/devices/cap/capmpar.c b/src/spicelib/devices/cap/capmpar.c new file mode 100644 index 000000000..2f8b47589 --- /dev/null +++ b/src/spicelib/devices/cap/capmpar.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPmParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + CAPmodel *mod = (CAPmodel*)inModel; + switch(param) { + case CAP_MOD_CJ : + mod->CAPcj = value->rValue; + mod->CAPcjGiven = TRUE; + break; + case CAP_MOD_CJSW : + mod->CAPcjsw = value->rValue; + mod->CAPcjswGiven = TRUE; + break; + case CAP_MOD_DEFWIDTH: + mod->CAPdefWidth = value->rValue; + mod->CAPdefWidthGiven = TRUE; + break; + case CAP_MOD_NARROW: + mod->CAPnarrow = value->rValue; + mod->CAPnarrowGiven = TRUE; + break; + case CAP_MOD_C: + /* just being reassured by the user that we are a capacitor */ + /* no-op */ + break; + default: + return(E_BADPARM); + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/capparam.c b/src/spicelib/devices/cap/capparam.c new file mode 100644 index 000000000..0f6646c8a --- /dev/null +++ b/src/spicelib/devices/cap/capparam.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CAPparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + CAPinstance *here = (CAPinstance*)inst; + switch(param) { + case CAP_CAP: + here->CAPcapac = value->rValue; + here->CAPcapGiven = TRUE; + break; + case CAP_IC: + here->CAPinitCond = value->rValue; + here->CAPicGiven = TRUE; + break; + case CAP_WIDTH: + here->CAPwidth = value->rValue; + here->CAPwidthGiven = TRUE; + break; + case CAP_LENGTH: + here->CAPlength = value->rValue; + here->CAPlengthGiven = TRUE; + break; + case CAP_CAP_SENS: + here->CAPsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/cap/cappzld.c b/src/spicelib/devices/cap/cappzld.c new file mode 100644 index 000000000..6f646dd0a --- /dev/null +++ b/src/spicelib/devices/cap/cappzld.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "capdefs.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CAPpzLoad(inModel,ckt,s) + GENmodel *inModel; + CKTcircuit *ckt; + register SPcomplex *s; + +{ + register CAPmodel *model = (CAPmodel*)inModel; + double val; + register CAPinstance *here; + + for( ; model != NULL; model = model->CAPnextModel) { + for( here = model->CAPinstances;here != NULL; + here = here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + val = here->CAPcapac; + *(here->CAPposPosptr ) += val * s->real; + *(here->CAPposPosptr +1) += val * s->imag; + *(here->CAPnegNegptr ) += val * s->real; + *(here->CAPnegNegptr +1) += val * s->imag; + *(here->CAPposNegptr ) -= val * s->real; + *(here->CAPposNegptr +1) -= val * s->imag; + *(here->CAPnegPosptr ) -= val * s->real; + *(here->CAPnegPosptr +1) -= val * s->imag; + } + } + return(OK); + +} diff --git a/src/spicelib/devices/cap/capsacl.c b/src/spicelib/devices/cap/capsacl.c new file mode 100644 index 000000000..1109b4e2d --- /dev/null +++ b/src/spicelib/devices/cap/capsacl.c @@ -0,0 +1,67 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPsAcLoad(inModel,ckt) + +GENmodel *inModel; +register CKTcircuit *ckt; + +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + double vcap; + double ivcap; + double val; + double ival; + + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + if(here->CAPsenParmNo){ + vcap = *(ckt->CKTrhsOld+here->CAPposNode) - + *(ckt->CKTrhsOld+here->CAPnegNode); + ivcap = *(ckt->CKTirhsOld+here->CAPposNode) - + *(ckt->CKTirhsOld+here->CAPnegNode); + + val = ckt->CKTomega * ivcap; + ival = ckt->CKTomega * vcap; + + /* load the RHS matrix */ + + *(ckt->CKTsenInfo->SEN_RHS[here->CAPposNode] + + here->CAPsenParmNo) += val; + *(ckt->CKTsenInfo->SEN_iRHS[here->CAPposNode] + + here->CAPsenParmNo) -= ival; + *(ckt->CKTsenInfo->SEN_RHS[here->CAPnegNode] + + here->CAPsenParmNo) -= val; + *(ckt->CKTsenInfo->SEN_iRHS[here->CAPnegNode] + + here->CAPsenParmNo) += ival; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/capsetup.c b/src/spicelib/devices/cap/capsetup.c new file mode 100644 index 000000000..bc2abc389 --- /dev/null +++ b/src/spicelib/devices/cap/capsetup.c @@ -0,0 +1,79 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +CAPsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the capacitor structure with those pointers needed later + * for fast matrix loading + */ + +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + /*Default Value Processing for Model Parameters */ + if (!model->CAPcjGiven) { + model->CAPcj = 0; + } + if (!model->CAPcjswGiven){ + model->CAPcjsw = 0; + } + if (!model->CAPdefWidthGiven) { + model->CAPdefWidth = 10.e-6; + } + if (!model->CAPnarrowGiven) { + model->CAPnarrow = 0; + } + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) goto matrixpointers; + + /* Default Value Processing for Capacitor Instance */ + if (!here->CAPlengthGiven) { + here->CAPlength = 0; + } + + here->CAPqcap = *states; + *states += 2; + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ + *states += 2 * (ckt->CKTsenInfo->SENparms); + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + +matrixpointers: + TSTALLOC(CAPposPosptr,CAPposNode,CAPposNode) + TSTALLOC(CAPnegNegptr,CAPnegNode,CAPnegNode) + TSTALLOC(CAPposNegptr,CAPposNode,CAPnegNode) + TSTALLOC(CAPnegPosptr,CAPnegNode,CAPposNode) + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/capsload.c b/src/spicelib/devices/cap/capsload.c new file mode 100644 index 000000000..028f7927b --- /dev/null +++ b/src/spicelib/devices/cap/capsload.c @@ -0,0 +1,99 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPsLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + int iparmno; + double vcap; + double Osxp; + double tag0; + double tag1; + SENstruct *info; + + info = ckt->CKTsenInfo; + if((info->SENmode == DCSEN) || (ckt->CKTmode&MODETRANOP)) + return( OK ); + if((info->SENmode == TRANSEN) && (ckt->CKTmode & MODEINITTRAN)) + return(OK); + + +#ifdef SENSDEBUG + printf("CKTtime = %.5e\n",ckt->CKTtime); + printf("CAPsenload \n"); +#endif /* SENSDEBUG */ + + tag0 = ckt->CKTag[0]; + tag1 = ckt->CKTag[1]; + if(ckt->CKTorder == 1){ + /* Euler Method */ + tag1 = 0; /* we treat tag1 as beta */ + } + + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + +#ifdef SENSDEBUG + printf("senload instance name %s\n",here->CAPname); + printf("pos = %d , neg = %d \n",here->CAPposNode ,here->CAPnegNode); +#endif /* SENSDEBUG */ + + vcap = *(ckt->CKTrhsOld+here->CAPposNode) + - *(ckt->CKTrhsOld+here->CAPnegNode) ; + + for(iparmno=1;iparmno<=info->SENparms;iparmno++){ + Osxp = tag0 * *(ckt->CKTstate1 + here->CAPsensxp + + 2*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->CAPsensxp + + 2*(iparmno - 1) + 1); +#ifdef SENSDEBUG + printf("iparmno = %d\n",iparmno); + printf("sxp = %.5e\n" + ,*(ckt->CKTstate1 + here->CAPsensxp + 2*(iparmno-1))); + printf("sdotxp = %.5e\n", + *(ckt->CKTstate1 + here->CAPsensxp + 2*(iparmno-1)+1)); + printf("Osxp = %.5e\n",Osxp); +#endif /* SENSDEBUG */ + + if(iparmno == here->CAPsenParmNo) + Osxp = Osxp - tag0 * vcap; +#ifdef SENSDEBUG + printf("Osxp = %.5e\n",Osxp); +#endif /* SENSDEBUG */ + + *(info->SEN_RHS[here->CAPposNode] + iparmno) += Osxp; + *(info->SEN_RHS[here->CAPnegNode] + iparmno) -= Osxp; + + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/capsprt.c b/src/spicelib/devices/cap/capsprt.c new file mode 100644 index 000000000..541a4922b --- /dev/null +++ b/src/spicelib/devices/cap/capsprt.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* Pretty print the sensitivity info for all + * the capacitors in the circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + + +void +CAPsPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + + printf("CAPACITORS-----------------\n"); + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + printf("Model name:%s\n",model->CAPmodName); + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + + printf(" Instance name:%s\n",here->CAPname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->CAPposNode),CKTnodName(ckt,here->CAPnegNode)); + printf(" Capacitance: %e",here->CAPcapac); + printf(here->CAPcapGiven ? "(specified)\n" : "(default)\n"); + printf(" CAPsenParmNo:%d\n",here->CAPsenParmNo); + + } + } +} + diff --git a/src/spicelib/devices/cap/capsset.c b/src/spicelib/devices/cap/capsset.c new file mode 100644 index 000000000..8de7c4d6d --- /dev/null +++ b/src/spicelib/devices/cap/capsset.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; + +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + if(here->CAPsenParmNo){ + here->CAPsenParmNo = ++(info->SENparms); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/capsupd.c b/src/spicelib/devices/cap/capsupd.c new file mode 100644 index 000000000..cf47d6a04 --- /dev/null +++ b/src/spicelib/devices/cap/capsupd.c @@ -0,0 +1,88 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* update the charge sensitivities and their derivatives */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPsUpdate(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + int iparmno; + double s1; + double s2; + double sxp; + double vcap; + double dummy1; + double dummy2; + SENstruct *info; + + info = ckt->CKTsenInfo; + if((info->SENmode == TRANSEN) && (ckt->CKTmode & MODEINITTRAN)) + return(OK); + +#ifdef SENSDEBUG + printf("CAPsenUpdate\n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); +#endif /* SENSDEBUG */ + + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + vcap = *(ckt->CKTrhsOld+here->CAPposNode) - + *(ckt->CKTrhsOld+here->CAPnegNode) ; + + + for(iparmno=1;iparmno<=info->SENparms;iparmno++){ + + s1 = *(info->SEN_Sap[here->CAPposNode] + iparmno); + s2 = *(info->SEN_Sap[here->CAPnegNode] + iparmno); + sxp = here->CAPcapac * (s1 - s2); + + if(iparmno == here->CAPsenParmNo) sxp += vcap; + + *(ckt->CKTstate0 + here->CAPsensxp + 2*(iparmno - 1)) = sxp; + + if(ckt->CKTtime == 0){ + *(ckt->CKTstate0 + here->CAPsensxp + 2*(iparmno - 1) + 1)=0; + } + else{ + NIintegrate(ckt,&dummy1,&dummy2,here->CAPcapac, + (here->CAPsensxp + 2 * (iparmno -1 ))); + } +#ifdef SENSDEBUG + printf("after loading\n"); + printf("iparmno = %d\n",iparmno); + printf("s1 = %.7e,s2 = %.7e\n",s1,s2); + printf("sxp = %.7e,sdotxp = %.7e\n", + sxp,*(ckt->CKTstate0 + here->CAPsensxp + + 2*(iparmno - 1) + 1)); + printf("\n"); +#endif /* SENSDEBUG */ + + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/captemp.c b/src/spicelib/devices/cap/captemp.c new file mode 100644 index 000000000..2c90695bc --- /dev/null +++ b/src/spicelib/devices/cap/captemp.c @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* load the capacitor structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +CAPtemp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + + /* loop through all the capacitor models */ + for( ; model != NULL; model = model->CAPnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CAPinstances; here != NULL ; + here=here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + /* Default Value Processing for Capacitor Instance */ + if (!here->CAPwidthGiven) { + here->CAPwidth = model->CAPdefWidth; + } + if (!here->CAPcapGiven) { + here->CAPcapac = + model->CAPcj * + (here->CAPwidth - model->CAPnarrow) * + (here->CAPlength - model->CAPnarrow) + + model->CAPcjsw * 2 * ( + (here->CAPlength - model->CAPnarrow) + + (here->CAPwidth - model->CAPnarrow) ); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cap/captrunc.c b/src/spicelib/devices/cap/captrunc.c new file mode 100644 index 000000000..b7b6a15ee --- /dev/null +++ b/src/spicelib/devices/cap/captrunc.c @@ -0,0 +1,34 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "capdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CAPtrunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + register double *timeStep; +{ + register CAPmodel *model = (CAPmodel*)inModel; + register CAPinstance *here; + + for( ; model!= NULL; model = model->CAPnextModel) { + for(here = model->CAPinstances ; here != NULL ; + here = here->CAPnextInstance) { + if (here->CAPowner != ARCHme) continue; + + CKTterr(here->CAPqcap,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/cccs/ChangeLog b/src/spicelib/devices/cccs/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/cccs/Makefile.am b/src/spicelib/devices/cccs/Makefile.am new file mode 100644 index 000000000..c909f2ace --- /dev/null +++ b/src/spicelib/devices/cccs/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libcccs.la + +libcccs_la_SOURCES = \ + cccs.c \ + cccsask.c \ + cccsdefs.h \ + cccsdel.c \ + cccsdest.c \ + cccsext.h \ + cccsitf.h \ + cccsload.c \ + cccsmdel.c \ + cccspar.c \ + cccspzld.c \ + cccssacl.c \ + cccsset.c \ + cccssld.c \ + cccssprt.c \ + cccssset.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/cccs/cccs.c b/src/spicelib/devices/cccs/cccs.c new file mode 100644 index 000000000..e85bc345f --- /dev/null +++ b/src/spicelib/devices/cccs/cccs.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "cccsdefs.h" +#include "suffix.h" + +IFparm CCCSpTable[] = { /* parameters */ + IOPU("gain", CCCS_GAIN, IF_REAL ,"Gain of source"), + IOPU("control", CCCS_CONTROL, IF_INSTANCE,"Name of controlling source"), + IP("sens_gain",CCCS_GAIN_SENS,IF_FLAG, "flag to request sensitivity WRT gain"), + OPU("neg_node", CCCS_NEG_NODE,IF_INTEGER, "Negative node of source"), + OPU("pos_node", CCCS_POS_NODE,IF_INTEGER, "Positive node of source"), + OP("i", CCCS_CURRENT, IF_REAL, "CCCS output current"), + OP("v", CCCS_VOLTS, IF_REAL, "CCCS voltage at output"), + OP("p", CCCS_POWER, IF_REAL, "CCCS power"), + OPU("sens_dc", CCCS_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU("sens_real",CCCS_QUEST_SENS_REAL,IF_REAL, "real part of ac sensitivity"), + OPU("sens_imag",CCCS_QUEST_SENS_IMAG,IF_REAL, "imag part of ac sensitivity"), + OPU("sens_mag", CCCS_QUEST_SENS_MAG, IF_REAL, "sensitivity of ac magnitude"), + OPU("sens_ph", CCCS_QUEST_SENS_PH, IF_REAL, "sensitivity of ac phase"), + OPU("sens_cplx",CCCS_QUEST_SENS_CPLX,IF_COMPLEX, "ac sensitivity") +}; + +#if 0 +static IFparm CCCSmPTable[] = { + /* model parameters */ +}; +#endif + +char *CCCSnames[] = { + "F+", + "F-" +}; + +int CCCSnSize = NUMELEMS(CCCSnames); +int CCCSpTSize = NUMELEMS(CCCSpTable); +int CCCSmPTSize = 0; +int CCCSiSize = sizeof(CCCSinstance); +int CCCSmSize = sizeof(CCCSmodel); diff --git a/src/spicelib/devices/cccs/cccsask.c b/src/spicelib/devices/cccs/cccsask.c new file mode 100644 index 000000000..314ab850f --- /dev/null +++ b/src/spicelib/devices/cccs/cccsask.c @@ -0,0 +1,146 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 +**********/ + +/* + * This routine gives access to the internal device parameters + * of Current Controlled Current Source + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CCCSask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + CCCSinstance *here = (CCCSinstance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + + switch(which) { + case CCCS_GAIN: + value->rValue = here->CCCScoeff; + return (OK); + case CCCS_CONTROL: + value->uValue = here->CCCScontName; + return (OK); + case CCCS_POS_NODE: + value->iValue = here->CCCSposNode; + return (OK); + case CCCS_NEG_NODE: + value->iValue = here->CCCSnegNode; + return (OK); + case CCCS_CONT_BR: + value->iValue = here->CCCScontBranch; + return (OK); + case CCCS_CURRENT : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CCCSask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = *(ckt->CKTrhsOld + + here->CCCScontBranch) * here->CCCScoeff; + } + return(OK); + case CCCS_VOLTS : + value->rValue = (*(ckt->CKTrhsOld + here->CCCSposNode) - + *(ckt->CKTrhsOld + here->CCCSnegNode)); + return(OK); + case CCCS_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CCCSask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTrhsOld + + here->CCCScontBranch) * here->CCCScoeff * + (*(ckt->CKTrhsOld + here->CCCSposNode) - + *(ckt->CKTrhsOld + here->CCCSnegNode)); + } + return(OK); + case CCCS_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->CCCSsenParmNo); + } + return(OK); + case CCCS_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCCSsenParmNo); + } + return(OK); + case CCCS_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCCSsenParmNo); + } + return(OK); + case CCCS_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCCSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCCSsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case CCCS_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCCSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCCSsenParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case CCCS_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCCSsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCCSsenParmNo); + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/cccs/cccsdefs.h b/src/spicelib/devices/cccs/cccsdefs.h new file mode 100644 index 000000000..878c8b2b7 --- /dev/null +++ b/src/spicelib/devices/cccs/cccsdefs.h @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef CCCS +#define CCCS + +#include "ifsim.h" +#include "gendefs.h" +#include "complex.h" +#include "cktdefs.h" + + /* structures used to describe Current Controlled Current Sources */ + +/* information needed for each instance */ + +typedef struct sCCCSinstance { + struct sCCCSmodel *CCCSmodPtr; /* backpointer to model */ + struct sCCCSinstance *CCCSnextInstance; /* pointer to next instance of + *current model*/ + IFuid CCCSname; /* pointer to character string naming this instance */ + int CCCSowner; /* number of owner process */ + int CCCSstate; /* not used */ + + int CCCSposNode; /* number of positive node of source */ + int CCCSnegNode; /* number of negative node of source */ + int CCCScontBranch; /* number of branch eq of controlling source */ + + char *CCCScontName; /* pointer to name of controlling instance */ + + double CCCScoeff; /* coefficient */ + + double *CCCSposContBrptr; /* pointer to sparse matrix element at + *(positive node, control branch eq)*/ + double *CCCSnegContBrptr; /* pointer to sparse matrix element at + *(negative node, control branch eq)*/ + unsigned CCCScoeffGiven :1 ; /* flag to indicate coeff given */ + + int CCCSsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + +} CCCSinstance ; + +/* per model data */ + +typedef struct sCCCSmodel { /* model structure for a source */ + int CCCSmodType; /* type index of this device type */ + struct sCCCSmodel *CCCSnextModel; /* pointer to next possible model + *in linked list */ + CCCSinstance * CCCSinstances; /* pointer to list of instances + that have this model */ + IFuid CCCSmodName; /* pointer to character string naming this model */ +} CCCSmodel; + +/* device parameters */ +#define CCCS_GAIN 1 +#define CCCS_CONTROL 2 +#define CCCS_POS_NODE 3 +#define CCCS_NEG_NODE 4 +#define CCCS_CONT_BR 5 +#define CCCS_GAIN_SENS 6 +#define CCCS_CURRENT 7 +#define CCCS_POWER 8 +#define CCCS_VOLTS 9 + +/* model parameters */ + +/* device questions */ +#define CCCS_QUEST_SENS_REAL 201 +#define CCCS_QUEST_SENS_IMAG 202 +#define CCCS_QUEST_SENS_MAG 203 +#define CCCS_QUEST_SENS_PH 204 +#define CCCS_QUEST_SENS_CPLX 205 +#define CCCS_QUEST_SENS_DC 206 + +/* model questions */ + +#include "cccsext.h" + +#endif /*CCCS*/ diff --git a/src/spicelib/devices/cccs/cccsdel.c b/src/spicelib/devices/cccs/cccsdel.c new file mode 100644 index 000000000..d3cdd1099 --- /dev/null +++ b/src/spicelib/devices/cccs/cccsdel.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCCSdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; + +{ + + CCCSmodel *model = (CCCSmodel*)inModel; + CCCSinstance **fast = (CCCSinstance**)inst; + CCCSinstance **prev = NULL; + CCCSinstance *here; + + for( ; model ; model = model->CCCSnextModel) { + prev = &(model->CCCSinstances); + for(here = *prev; here ; here = *prev) { + if(here->CCCSname == name || (fast && here==*fast) ) { + *prev= here->CCCSnextInstance; + FREE(here); + return(OK); + } + prev = &(here->CCCSnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/cccs/cccsdest.c b/src/spicelib/devices/cccs/cccsdest.c new file mode 100644 index 000000000..799f7d2d9 --- /dev/null +++ b/src/spicelib/devices/cccs/cccsdest.c @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cccsdefs.h" +#include "suffix.h" + + +void +CCCSdestroy(inModel) + GENmodel **inModel; + +{ + CCCSmodel **model = (CCCSmodel**)inModel; + CCCSinstance *here; + CCCSinstance *prev = NULL; + CCCSmodel *mod = *model; + CCCSmodel *oldmod = NULL; + + for( ; mod ; mod = mod->CCCSnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (CCCSinstance *)NULL; + for(here = mod->CCCSinstances ; here ; here = here->CCCSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/cccs/cccsext.h b/src/spicelib/devices/cccs/cccsext.h new file mode 100644 index 000000000..003cd0bf8 --- /dev/null +++ b/src/spicelib/devices/cccs/cccsext.h @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int CCCSask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int CCCSdelete(GENmodel*,IFuid,GENinstance**); +extern void CCCSdestroy(GENmodel**); +extern int CCCSload(GENmodel*,CKTcircuit*); +extern int CCCSmDelete(GENmodel**,IFuid,GENmodel*); +extern int CCCSparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int CCCSpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int CCCSsAcLoad(GENmodel*,CKTcircuit*); +extern int CCCSsLoad(GENmodel*,CKTcircuit*); +extern void CCCSsPrint(GENmodel*,CKTcircuit*); +extern int CCCSsSetup(SENstruct*,GENmodel*); +extern int CCCSsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +#else /* stdc */ +extern int CCCSask(); +extern int CCCSdelete(); +extern void CCCSdestroy(); +extern int CCCSload(); +extern int CCCSmDelete(); +extern int CCCSparam(); +extern int CCCSpzLoad(); +extern int CCCSsAcLoad(); +extern int CCCSsLoad(); +extern void CCCSsPrint(); +extern int CCCSsSetup(); +extern int CCCSsetup(); +#endif /* stdc */ diff --git a/src/spicelib/devices/cccs/cccsitf.h b/src/spicelib/devices/cccs/cccsitf.h new file mode 100644 index 000000000..4a0eabf2a --- /dev/null +++ b/src/spicelib/devices/cccs/cccsitf.h @@ -0,0 +1,85 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_cccs + +#ifndef DEV_CCCS +#define DEV_CCCS + +#include "cccsext.h" +extern IFparm CCCSpTable[ ]; +extern char *CCCSnames[ ]; +extern int CCCSpTSize; +extern int CCCSnSize; +extern int CCCSiSize; +extern int CCCSmSize; + +SPICEdev CCCSinfo = { + { "CCCS", + "Current controlled current source", + + &CCCSnSize, + &CCCSnSize, + CCCSnames, + + &CCCSpTSize, + CCCSpTable, + + 0, + NULL, + DEV_DEFAULT + }, + + CCCSparam, + NULL, + CCCSload, + CCCSsetup, + NULL, + CCCSsetup, + NULL, + NULL, + NULL, + CCCSload, + NULL, + CCCSdestroy, +#ifdef DELETES + CCCSmDelete, + CCCSdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + CCCSask, + NULL, +#ifdef AN_pz + CCCSpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense2 + CCCSsSetup, + CCCSsLoad, + NULL, + CCCSsAcLoad, + CCCSsPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ + NULL, /* DISTO */ + NULL, /* NOISE */ + + &CCCSiSize, + &CCCSmSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/cccs/cccsload.c b/src/spicelib/devices/cccs/cccsload.c new file mode 100644 index 000000000..f6576f625 --- /dev/null +++ b/src/spicelib/devices/cccs/cccsload.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +CCCSload(inModel,ckt) + + GENmodel *inModel; + CKTcircuit *ckt; + + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register CCCSmodel *model = (CCCSmodel*)inModel; + register CCCSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCCSinstances; here != NULL ; + here=here->CCCSnextInstance) { + if (here->CCCSowner != ARCHme) continue; + + *(here->CCCSposContBrptr) += here->CCCScoeff ; + *(here->CCCSnegContBrptr) -= here->CCCScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/cccs/cccsmdel.c b/src/spicelib/devices/cccs/cccsmdel.c new file mode 100644 index 000000000..a0648cf79 --- /dev/null +++ b/src/spicelib/devices/cccs/cccsmdel.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCCSmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; + +{ + + CCCSmodel **model = (CCCSmodel**)inModel; + CCCSmodel *modfast = (CCCSmodel*)kill; + CCCSinstance *here; + CCCSinstance *prev = NULL; + CCCSmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->CCCSnextModel)) { + if( (*model)->CCCSmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->CCCSnextModel; /* cut deleted device out of list */ + for(here = (*model)->CCCSinstances ; here ; here = here->CCCSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/cccs/cccspar.c b/src/spicelib/devices/cccs/cccspar.c new file mode 100644 index 000000000..8047eee87 --- /dev/null +++ b/src/spicelib/devices/cccs/cccspar.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CCCSparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + CCCSinstance *here = (CCCSinstance*)inst; + switch(param) { + case CCCS_GAIN: + here->CCCScoeff = value->rValue; + here->CCCScoeffGiven = TRUE; + break; + case CCCS_CONTROL: + here->CCCScontName = value->uValue; + break; + case CCCS_GAIN_SENS: + here->CCCSsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/cccs/cccspzld.c b/src/spicelib/devices/cccs/cccspzld.c new file mode 100644 index 000000000..8b1269722 --- /dev/null +++ b/src/spicelib/devices/cccs/cccspzld.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "cccsdefs.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +CCCSpzLoad(inModel,ckt,s) + + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; + + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register CCCSmodel *model = (CCCSmodel*)inModel; + register CCCSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCCSinstances; here != NULL ; + here=here->CCCSnextInstance) { + if (here->CCCSowner != ARCHme) continue; + + *(here->CCCSposContBrptr) += here->CCCScoeff ; + *(here->CCCSnegContBrptr) -= here->CCCScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/cccs/cccssacl.c b/src/spicelib/devices/cccs/cccssacl.c new file mode 100644 index 000000000..488b16b91 --- /dev/null +++ b/src/spicelib/devices/cccs/cccssacl.c @@ -0,0 +1,56 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current ac sensitivity information + * into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCCSsAcLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register CCCSmodel *model = (CCCSmodel*)inModel; + register CCCSinstance *here; + double ic; + double i_ic; + + /* loop through all the CCCS models */ + for( ; model != NULL; model = model->CCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCCSinstances; here != NULL ; + here=here->CCCSnextInstance) { + if (here->CCCSowner != ARCHme) continue; + + if(here->CCCSsenParmNo){ + + ic = *(ckt->CKTrhsOld + here->CCCScontBranch); + i_ic = *(ckt->CKTirhsOld + here->CCCScontBranch); + *(ckt->CKTsenInfo->SEN_RHS[here->CCCSposNode] + + here->CCCSsenParmNo) -= ic; + *(ckt->CKTsenInfo->SEN_iRHS[here->CCCSposNode] + + here->CCCSsenParmNo) -= i_ic; + *(ckt->CKTsenInfo->SEN_RHS[here->CCCSnegNode] + + here->CCCSsenParmNo) += ic; + *(ckt->CKTsenInfo->SEN_iRHS[here->CCCSnegNode] + + here->CCCSsenParmNo) += i_ic; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cccs/cccsset.c b/src/spicelib/devices/cccs/cccsset.c new file mode 100644 index 000000000..4fb9946cc --- /dev/null +++ b/src/spicelib/devices/cccs/cccsset.c @@ -0,0 +1,60 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* load the voltage source structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +CCCSsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; +{ + register CCCSmodel *model = (CCCSmodel*)inModel; + register CCCSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCCSinstances; here != NULL ; + here=here->CCCSnextInstance) { + + here->CCCScontBranch = CKTfndBranch(ckt,here->CCCScontName); + if(here->CCCScontBranch == 0) { + IFuid namarray[2]; + namarray[0] = here->CCCSname; + namarray[1] = here->CCCScontName; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: unknown controlling source %s",namarray); + return(E_BADPARM); + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(CCCSposContBrptr,CCCSposNode,CCCScontBranch) + TSTALLOC(CCCSnegContBrptr,CCCSnegNode,CCCScontBranch) + } + } + return(OK); +} diff --git a/src/spicelib/devices/cccs/cccssld.c b/src/spicelib/devices/cccs/cccssld.c new file mode 100644 index 000000000..190605d91 --- /dev/null +++ b/src/spicelib/devices/cccs/cccssld.c @@ -0,0 +1,48 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current sensitivity information + * into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCCSsLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register CCCSmodel *model = (CCCSmodel*)inModel; + register CCCSinstance *here; + double ic ; + + /* loop through all the CCCS models */ + for( ; model != NULL; model = model->CCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCCSinstances; here != NULL ; + here=here->CCCSnextInstance) { + if(here->CCCSsenParmNo){ + + ic = *(ckt->CKTrhsOld + here->CCCScontBranch); + *(ckt->CKTsenInfo->SEN_RHS[here->CCCSposNode] + + here->CCCSsenParmNo) -= ic; + *(ckt->CKTsenInfo->SEN_RHS[here->CCCSnegNode] + + here->CCCSsenParmNo) += ic; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/cccs/cccssprt.c b/src/spicelib/devices/cccs/cccssprt.c new file mode 100644 index 000000000..2a733b672 --- /dev/null +++ b/src/spicelib/devices/cccs/cccssprt.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* Pretty print the sensitivity info for all + * the CCCS in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +void +CCCSsPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register CCCSmodel *model = (CCCSmodel*)inModel; + register CCCSinstance *here; + + printf("CURRENT CONTROLLED CURRENT SOURCES-----------------\n"); + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCCSnextModel ) { + + printf("Model name:%s\n",model->CCCSmodName); + + /* loop through all the instances of the model */ + for (here = model->CCCSinstances; here != NULL ; + here=here->CCCSnextInstance) { + if (here->CCCSowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->CCCSname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->CCCSposNode), + CKTnodName(ckt,here->CCCSnegNode)); + printf(" Controlling source name: %s\n", + here->CCCScontName); + printf(" Controlling Branch equation number: %s\n", + CKTnodName(ckt,here->CCCScontBranch)); + printf(" Coefficient: %f\n",here->CCCScoeff); + printf(" CCCSsenParmNo:%d\n",here->CCCSsenParmNo); + + } + } +} diff --git a/src/spicelib/devices/cccs/cccssset.c b/src/spicelib/devices/cccs/cccssset.c new file mode 100644 index 000000000..7bd7e58f6 --- /dev/null +++ b/src/spicelib/devices/cccs/cccssset.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "cccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCCSsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register CCCSmodel *model = (CCCSmodel*)inModel; + register CCCSinstance *here; + + /* loop through all the CCCS models */ + for( ; model != NULL; model = model->CCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCCSinstances; here != NULL ; + here=here->CCCSnextInstance) { + if (here->CCCSowner != ARCHme) continue; + + if(here->CCCSsenParmNo){ + here->CCCSsenParmNo = ++(info->SENparms); + } + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/ccvs/ChangeLog b/src/spicelib/devices/ccvs/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/ccvs/Makefile.am b/src/spicelib/devices/ccvs/Makefile.am new file mode 100644 index 000000000..580d2f186 --- /dev/null +++ b/src/spicelib/devices/ccvs/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libccvs.la + +libccvs_la_SOURCES = \ + ccvs.c \ + ccvsask.c \ + ccvsdefs.h \ + ccvsdel.c \ + ccvsdest.c \ + ccvsext.h \ + ccvsfbr.c \ + ccvsitf.h \ + ccvsload.c \ + ccvsmdel.c \ + ccvspar.c \ + ccvspzld.c \ + ccvssacl.c \ + ccvsset.c \ + ccvssld.c \ + ccvssprt.c \ + ccvssset.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/ccvs/ccvs.c b/src/spicelib/devices/ccvs/ccvs.c new file mode 100644 index 000000000..b0253d18d --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvs.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "ccvsdefs.h" +#include "suffix.h" + +/* current controlled voltage source */ +IFparm CCVSpTable[] = { /* parameters */ + IOPU("gain", CCVS_TRANS, IF_REAL ,"Transresistance (gain)"), + IOPU("control", CCVS_CONTROL, IF_INSTANCE,"Controlling voltage source"), + IP("sens_trans",CCVS_TRANS_SENS,IF_FLAG, + "flag to request sens. WRT transimpedance"), + OPU("pos_node", CCVS_POS_NODE,IF_INTEGER, "Positive node of source"), + OPU("neg_node", CCVS_NEG_NODE,IF_INTEGER, "Negative node of source"), + OP("i", CCVS_CURRENT, IF_REAL, "CCVS output current"), + OP("v", CCVS_VOLTS, IF_REAL, "CCVS output voltage"), + OP("p", CCVS_POWER, IF_REAL, "CCVS power"), + OPU("sens_dc", CCVS_QUEST_SENS_DC, IF_REAL,"dc sensitivity "), + OPU("sens_real", CCVS_QUEST_SENS_REAL,IF_REAL,"real part of ac sensitivity"), + OPU("sens_imag", CCVS_QUEST_SENS_IMAG,IF_REAL,"imag part of ac sensitivity"), + OPU("sens_mag", CCVS_QUEST_SENS_MAG, IF_REAL,"sensitivity of ac magnitude"), + OPU("sens_ph", CCVS_QUEST_SENS_PH, IF_REAL, "sensitivity of ac phase"), + OPU("sens_cplx", CCVS_QUEST_SENS_CPLX,IF_COMPLEX,"ac sensitivity") +}; + +char *CCVSnames[] = { + "H+", + "H-" +}; + +int CCVSnSize = NUMELEMS(CCVSnames); +int CCVSpTSize = NUMELEMS(CCVSpTable); +int CCVSmPTSize = 0; +int CCVSiSize = sizeof(CCVSinstance); +int CCVSmSize = sizeof(CCVSmodel); diff --git a/src/spicelib/devices/ccvs/ccvsask.c b/src/spicelib/devices/ccvs/ccvsask.c new file mode 100644 index 000000000..b63ef57ab --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsask.c @@ -0,0 +1,145 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +/* + * This routine gives access to the internal device parameters + * of Current Controlled Voltage Source + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +CCVSask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + CCVSinstance *here = (CCVSinstance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case CCVS_TRANS: + value->rValue = here->CCVScoeff; + return (OK); + case CCVS_CONTROL: + value->uValue = here->CCVScontName; + return (OK); + case CCVS_POS_NODE: + value->iValue = here->CCVSposNode; + return (OK); + case CCVS_NEG_NODE: + value->iValue = here->CCVSnegNode; + return (OK); + case CCVS_BR: + value->iValue = here->CCVSbranch; + return (OK); + case CCVS_CONT_BR: + value->iValue = here->CCVScontBranch; + return (OK); + case CCVS_CURRENT : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CCVSask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = *(ckt->CKTrhsOld+here->CCVSbranch); + } + return(OK); + case CCVS_VOLTS : + value->rValue = (*(ckt->CKTrhsOld + here->CCVSposNode) - + *(ckt->CKTrhsOld + here->CCVSnegNode)); + return(OK); + case CCVS_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CCVSask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTrhsOld + here->CCVSbranch) + * (*(ckt->CKTrhsOld + here->CCVSposNode) - + *(ckt->CKTrhsOld + here->CCVSnegNode)); + } + return(OK); + case CCVS_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->CCVSsenParmNo); + } + return(OK); + case CCVS_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCVSsenParmNo); + } + return(OK); + case CCVS_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCVSsenParmNo); + } + return(OK); + case CCVS_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCVSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCVSsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case CCVS_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCVSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCVSsenParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case CCVS_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->CCVSsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->CCVSsenParmNo); + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/ccvs/ccvsdefs.h b/src/spicelib/devices/ccvs/ccvsdefs.h new file mode 100644 index 000000000..52b9c4d5d --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsdefs.h @@ -0,0 +1,89 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef CCVS +#define CCVS + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + + /* structures used to describe current controlled voltage sources */ + +/* information used to describe a single instance */ + +typedef struct sCCVSinstance { + struct sCCVSmodel *CCVSmodPtr; /* backpointer to model */ + struct sCCVSinstance *CCVSnextInstance; /* pointer to next instance of + *current model*/ + IFuid CCVSname; /* pointer to character string naming this instance */ + int CCVSowner; /* number of owner process */ + int CCVSstate; /* not used */ + + int CCVSposNode; /* number of positive node of source */ + int CCVSnegNode; /* number of negative node of source */ + + IFuid CCVScontName; /* pointer to name of controlling instance */ + int CCVSbranch; /* equation number of branch equation added for v source */ + int CCVScontBranch; /* number of branch eq of controlling source */ + + double CCVScoeff; /* coefficient */ + + double *CCVSposIbrptr; /* pointer to sparse matrix element at + * (positive node, branch equation) */ + double *CCVSnegIbrptr; /* pointer to sparse matrix element at + * (negative node, branch equation) */ + double *CCVSibrPosptr; /* pointer to sparse matrix element at + * (branch equation, positive node) */ + double *CCVSibrNegptr; /* pointer to sparse matrix element at + * (branch equation, negative node) */ + double *CCVSibrContBrptr; /* pointer to sparse matrix element at + *(branch equation, control branch eq)*/ + unsigned CCVScoeffGiven :1 ; /* flag to indicate coeff given */ + + int CCVSsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + +} CCVSinstance ; + +/* per model data */ + +typedef struct sCCVSmodel { /* model structure for a CCVsource */ + int CCVSmodType; /* type index of this device type */ + struct sCCVSmodel *CCVSnextModel; /* pointer to next possible model + *in linked list */ + CCVSinstance * CCVSinstances; /* pointer to list of instances + that have this model */ + IFuid CCVSmodName; /* pointer to character string naming this model */ +} CCVSmodel; + +/* device parameters */ +#define CCVS_TRANS 1 +#define CCVS_CONTROL 2 +#define CCVS_POS_NODE 3 +#define CCVS_NEG_NODE 4 +#define CCVS_BR 5 +#define CCVS_CONT_BR 6 +#define CCVS_TRANS_SENS 7 +#define CCVS_CURRENT 8 +#define CCVS_POWER 9 +#define CCVS_VOLTS 10 + +/* model parameters */ + +/* device questions */ +#define CCVS_QUEST_SENS_REAL 201 +#define CCVS_QUEST_SENS_IMAG 202 +#define CCVS_QUEST_SENS_MAG 203 +#define CCVS_QUEST_SENS_PH 204 +#define CCVS_QUEST_SENS_CPLX 205 +#define CCVS_QUEST_SENS_DC 206 + +/* model questions */ + +#include "ccvsext.h" + +#endif /*CCVS*/ diff --git a/src/spicelib/devices/ccvs/ccvsdel.c b/src/spicelib/devices/ccvs/ccvsdel.c new file mode 100644 index 000000000..6823a9fd5 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsdel.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCVSdelete(inModel,name,kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; + +{ + CCVSmodel *model = (CCVSmodel*)inModel; + CCVSinstance **fast = (CCVSinstance**)kill; + CCVSinstance **prev = NULL; + CCVSinstance *here; + + for( ; model ; model = model->CCVSnextModel) { + prev = &(model->CCVSinstances); + for(here = *prev; here ; here = *prev) { + if(here->CCVSname == name || (fast && here==*fast) ) { + *prev= here->CCVSnextInstance; + FREE(here); + return(OK); + } + prev = &(here->CCVSnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/ccvs/ccvsdest.c b/src/spicelib/devices/ccvs/ccvsdest.c new file mode 100644 index 000000000..0b5b3efa9 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ccvsdefs.h" +#include "suffix.h" + + +void +CCVSdestroy(inModel) + GENmodel **inModel; +{ + CCVSmodel **model = (CCVSmodel**)inModel; + CCVSinstance *here; + CCVSinstance *prev = NULL; + CCVSmodel *mod = *model; + CCVSmodel *oldmod = NULL; + + for( ; mod ; mod = mod->CCVSnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (CCVSinstance *)NULL; + for(here = mod->CCVSinstances ; here ; here = here->CCVSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/ccvs/ccvsext.h b/src/spicelib/devices/ccvs/ccvsext.h new file mode 100644 index 000000000..1765bf882 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsext.h @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int CCVSask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int CCVSdelete(GENmodel*,IFuid,GENinstance**); +extern void CCVSdestroy(GENmodel**); +extern int CCVSfindBr(CKTcircuit*,GENmodel*,IFuid); +extern int CCVSload(GENmodel*,CKTcircuit*); +extern int CCVSmDelete(GENmodel**,IFuid,GENmodel*); +extern int CCVSparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int CCVSpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int CCVSsAcLoad(GENmodel*,CKTcircuit*); +extern int CCVSsLoad(GENmodel*,CKTcircuit*); +extern void CCVSsPrint(GENmodel*,CKTcircuit*); +extern int CCVSsSetup(SENstruct*,GENmodel*); +extern int CCVSsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int CCVSunsetup(GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int CCVSask(); +extern int CCVSdelete(); +extern void CCVSdestroy(); +extern int CCVSfindBr(); +extern int CCVSload(); +extern int CCVSmDelete(); +extern int CCVSparam(); +extern int CCVSpzLoad(); +extern int CCVSsAcLoad(); +extern int CCVSsLoad(); +extern void CCVSsPrint(); +extern int CCVSsSetup(); +extern int CCVSsetup(); +extern int CCVSunsetup(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/ccvs/ccvsfbr.c b/src/spicelib/devices/ccvs/ccvsfbr.c new file mode 100644 index 000000000..f5f2c6335 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsfbr.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCVSfindBr(ckt,inModel,name) + register CKTcircuit *ckt; + GENmodel *inModel; + register IFuid name; +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + int error; + CKTnode *tmp; + + for( ; model != NULL; model = model->CCVSnextModel) { + for (here = model->CCVSinstances; here != NULL; + here = here->CCVSnextInstance) { + if(here->CCVSname == name) { + if(here->CCVSbranch == 0) { + error = CKTmkCur(ckt,&tmp, here->CCVSname,"branch"); + if(error) return(error); + here->CCVSbranch = tmp->number; + } + return(here->CCVSbranch); + } + } + } + return(0); +} diff --git a/src/spicelib/devices/ccvs/ccvsitf.h b/src/spicelib/devices/ccvs/ccvsitf.h new file mode 100644 index 000000000..869c0e541 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsitf.h @@ -0,0 +1,86 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_ccvs + +#ifndef DEV_CCVS +#define DEV_CCVS + +#include "ccvsext.h" +extern IFparm CCVSpTable[ ]; +extern char *CCVSnames[ ]; +extern int CCVSpTSize; +extern int CCVSnSize; +extern int CCVSiSize; +extern int CCVSmSize; + +SPICEdev CCVSinfo = { + { + "CCVS", + "Linear current controlled current source", + + &CCVSnSize, + &CCVSnSize, + CCVSnames, + + &CCVSpTSize, + CCVSpTable, + + 0, + NULL, + DEV_DEFAULT + }, + + CCVSparam, + NULL, + CCVSload, + CCVSsetup, + CCVSunsetup, + CCVSsetup, + NULL, + NULL, + CCVSfindBr, + CCVSload, /* ac and normal load functions identical */ + NULL, + CCVSdestroy, +#ifdef DELETES + CCVSmDelete, + CCVSdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + CCVSask, + NULL, +#ifdef AN_pz + CCVSpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense2 + CCVSsSetup, + CCVSsLoad, + NULL, + CCVSsAcLoad, + CCVSsPrint, + NULL, +#else /* NOSENS */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* NOSENS */ + NULL, /* DISTO */ + NULL, /* NOISE */ + + &CCVSiSize, + &CCVSmSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/ccvs/ccvsload.c b/src/spicelib/devices/ccvs/ccvsload.c new file mode 100644 index 000000000..a4f0a8387 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsload.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +CCVSload(inModel,ckt) + + GENmodel *inModel; + CKTcircuit *ckt; + + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCVSinstances; here != NULL ; + here=here->CCVSnextInstance) { + if (here->CCVSowner != ARCHme) continue; + + *(here->CCVSposIbrptr) += 1.0 ; + *(here->CCVSnegIbrptr) -= 1.0 ; + *(here->CCVSibrPosptr) += 1.0 ; + *(here->CCVSibrNegptr) -= 1.0 ; + *(here->CCVSibrContBrptr) -= here->CCVScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/ccvs/ccvsmdel.c b/src/spicelib/devices/ccvs/ccvsmdel.c new file mode 100644 index 000000000..e9eb31c3e --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCVSmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + CCVSmodel **model = (CCVSmodel**)inModel; + CCVSmodel *modfast = (CCVSmodel*)kill; + CCVSinstance *here; + CCVSinstance *prev = NULL; + CCVSmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->CCVSnextModel)) { + if( (*model)->CCVSmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->CCVSnextModel; /* cut deleted device out of list */ + for(here = (*model)->CCVSinstances ; here ; here = here->CCVSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/ccvs/ccvspar.c b/src/spicelib/devices/ccvs/ccvspar.c new file mode 100644 index 000000000..76007b0b2 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvspar.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CCVSparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + CCVSinstance *here = (CCVSinstance*)inst; + switch(param) { + case CCVS_TRANS: + here->CCVScoeff = value->rValue; + here->CCVScoeffGiven = TRUE; + break; + case CCVS_CONTROL: + here->CCVScontName = value->uValue; + break; + case CCVS_TRANS_SENS: + here->CCVSsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/ccvs/ccvspzld.c b/src/spicelib/devices/ccvs/ccvspzld.c new file mode 100644 index 000000000..ee8b9c0b1 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvspzld.c @@ -0,0 +1,48 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "ccvsdefs.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +CCVSpzLoad(inModel,ckt,s) + + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; + + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCVSinstances; here != NULL ; + here=here->CCVSnextInstance) { + if (here->CCVSowner != ARCHme) continue; + + *(here->CCVSposIbrptr) += 1.0 ; + *(here->CCVSnegIbrptr) -= 1.0 ; + *(here->CCVSibrPosptr) += 1.0 ; + *(here->CCVSibrNegptr) -= 1.0 ; + *(here->CCVSibrContBrptr) += here->CCVScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/ccvs/ccvssacl.c b/src/spicelib/devices/ccvs/ccvssacl.c new file mode 100644 index 000000000..43887ab5c --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvssacl.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current ac sensitivity information + * into the array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCVSsAcLoad(inModel,ckt) + + GENmodel *inModel; + CKTcircuit *ckt; +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + double ic,i_ic; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCVSinstances; here != NULL ; + here=here->CCVSnextInstance) { + if (here->CCVSowner != ARCHme) continue; + + if(here->CCVSsenParmNo){ + ic = *(ckt->CKTrhsOld + here->CCVScontBranch); + i_ic = *(ckt->CKTirhsOld + here->CCVScontBranch); + + *(ckt->CKTsenInfo->SEN_RHS[here->CCVSbranch] + + here->CCVSsenParmNo) -= ic; + *(ckt->CKTsenInfo->SEN_iRHS[here->CCVSbranch] + + here->CCVSsenParmNo) -= i_ic; + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/ccvs/ccvsset.c b/src/spicelib/devices/ccvs/ccvsset.c new file mode 100644 index 000000000..21438e73f --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvsset.c @@ -0,0 +1,91 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* load the voltage source structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +CCVSsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCVSinstances; here != NULL ; + here=here->CCVSnextInstance) { + + if(here->CCVSbranch==0) { + error = CKTmkCur(ckt,&tmp,here->CCVSname, "branch"); + if(error) return(error); + here->CCVSbranch = tmp->number; + } + here->CCVScontBranch = CKTfndBranch(ckt,here->CCVScontName); + if(here->CCVScontBranch == 0) { + IFuid namarray[2]; + namarray[0] = here->CCVSname; + namarray[1] = here->CCVScontName; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: unknown controlling source %s",namarray); + return(E_BADPARM); + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(CCVSposIbrptr, CCVSposNode, CCVSbranch) + TSTALLOC(CCVSnegIbrptr, CCVSnegNode, CCVSbranch) + TSTALLOC(CCVSibrNegptr, CCVSbranch, CCVSnegNode) + TSTALLOC(CCVSibrPosptr, CCVSbranch, CCVSposNode) + TSTALLOC(CCVSibrContBrptr, CCVSbranch, CCVScontBranch) + } + } + return(OK); +} + +int +CCVSunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + CCVSmodel *model; + CCVSinstance *here; + + for (model = (CCVSmodel *)inModel; model != NULL; + model = model->CCVSnextModel) + { + for (here = model->CCVSinstances; here != NULL; + here=here->CCVSnextInstance) + { + if (here->CCVSbranch) { + CKTdltNNum(ckt, here->CCVSbranch); + here->CCVSbranch = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/ccvs/ccvssld.c b/src/spicelib/devices/ccvs/ccvssld.c new file mode 100644 index 000000000..82688cb7d --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvssld.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current sensitivity information + * into the array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCVSsLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + double ic; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCVSinstances; here != NULL ; + here=here->CCVSnextInstance) { + if (here->CCVSowner != ARCHme) continue; + + if(here->CCVSsenParmNo){ + ic = *(ckt->CKTrhsOld + here->CCVScontBranch); + *(ckt->CKTsenInfo->SEN_RHS[here->CCVSbranch] + + here->CCVSsenParmNo) -= ic; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/ccvs/ccvssprt.c b/src/spicelib/devices/ccvs/ccvssprt.c new file mode 100644 index 000000000..dc8eb2625 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvssprt.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* Pretty print the sensitivity info for all + * the CCVS in the circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +void +CCVSsPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + + printf("CURRENT CONTROLLED VOLTAGE SOURCES-----------------\n"); + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCVSnextModel ) { + + printf("Model name:%s\n",model->CCVSmodName); + + /* loop through all the instances of the model */ + for (here = model->CCVSinstances; here != NULL ; + here=here->CCVSnextInstance) { + if (here->CCVSowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->CCVSname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->CCVSposNode), + CKTnodName(ckt,here->CCVSnegNode)); + printf(" Controlling source name: %s\n", + here->CCVScontName); + printf(" Branch equation number: %s\n", + CKTnodName(ckt,here->CCVSbranch)); + printf(" Controlling Branch equation number: %s\n", + CKTnodName(ckt,here->CCVScontBranch)); + printf(" Coefficient: %f\n",here->CCVScoeff); + printf(" CCVSsenParmNo:%d\n",here->CCVSsenParmNo); + } + } +} + diff --git a/src/spicelib/devices/ccvs/ccvssset.c b/src/spicelib/devices/ccvs/ccvssset.c new file mode 100644 index 000000000..101554984 --- /dev/null +++ b/src/spicelib/devices/ccvs/ccvssset.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ccvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CCVSsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; + +{ + register CCVSmodel *model = (CCVSmodel*)inModel; + register CCVSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->CCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CCVSinstances; here != NULL ; + here=here->CCVSnextInstance) { + if (here->CCVSowner != ARCHme) continue; + + if(here->CCVSsenParmNo){ + here->CCVSsenParmNo = ++(info->SENparms); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/csw/ChangeLog b/src/spicelib/devices/csw/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/csw/Makefile.am b/src/spicelib/devices/csw/Makefile.am new file mode 100644 index 000000000..aea784875 --- /dev/null +++ b/src/spicelib/devices/csw/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libcsw.la + +libcsw_la_SOURCES = \ + csw.c \ + cswacld.c \ + cswask.c \ + cswdefs.h \ + cswdel.c \ + cswdest.c \ + cswext.h \ + cswitf.h \ + cswload.c \ + cswmask.c \ + cswmdel.c \ + cswmpar.c \ + cswnoise.c \ + cswparam.c \ + cswpzld.c \ + cswsetup.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/csw/csw.c b/src/spicelib/devices/csw/csw.c new file mode 100644 index 000000000..4d3fb598a --- /dev/null +++ b/src/spicelib/devices/csw/csw.c @@ -0,0 +1,42 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "cswdefs.h" +#include "suffix.h" + +IFparm CSWpTable[] = { /* parameters */ + IOP( "control",CSW_CONTROL, IF_INSTANCE, "Name of controlling source"), + IP( "on", CSW_IC_ON, IF_FLAG , "Initially closed"), + IP( "off", CSW_IC_OFF, IF_FLAG , "Initially open"), + OPU( "pos_node",CSW_POS_NODE,IF_INTEGER, "Positive node of switch"), + OPU( "neg_node",CSW_NEG_NODE,IF_INTEGER, "Negative node of switch"), + OP( "i" ,CSW_CURRENT, IF_REAL, "Switch current"), + OP( "p" ,CSW_POWER, IF_REAL, "Instantaneous power") +}; + +IFparm CSWmPTable[] = { /* model parameters */ + IOPU( "csw", CSW_CSW, IF_FLAG, "Current controlled switch model"), + IOPU( "it", CSW_ITH, IF_REAL, "Threshold current"), + IOPU( "ih", CSW_IHYS, IF_REAL, "Hysterisis current"), + IOPU( "ron", CSW_RON, IF_REAL, "Closed resistance"), + IOPU( "roff", CSW_ROFF, IF_REAL, "Open resistance"), + OPU( "gon", CSW_GON, IF_REAL, "Closed conductance"), + OPU( "goff", CSW_GOFF, IF_REAL, "Open conductance") +}; + +char *CSWnames[] = { + "W+", + "W-" +}; + +int CSWnSize = NUMELEMS(CSWnames); +int CSWpTSize = NUMELEMS(CSWpTable); +int CSWmPTSize = NUMELEMS(CSWmPTable); +int CSWiSize = sizeof(CSWinstance); +int CSWmSize = sizeof(CSWmodel); diff --git a/src/spicelib/devices/csw/cswacld.c b/src/spicelib/devices/csw/cswacld.c new file mode 100644 index 000000000..47da954a2 --- /dev/null +++ b/src/spicelib/devices/csw/cswacld.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "cswdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CSWacLoad(inModel,ckt) + + GENmodel *inModel; + register CKTcircuit *ckt; + + /* load the current values into the + * sparse matrix previously provided + * during AC analysis + */ +{ + register CSWmodel *model = (CSWmodel*)inModel; + register CSWinstance *here; + double g_now; + int current_state; + + /* loop through all the switch models */ + for( ; model != NULL; model = model->CSWnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CSWinstances; here != NULL ; + here=here->CSWnextInstance) { + if (here->CSWowner != ARCHme) continue; + + current_state = *(ckt->CKTstate0 + here->CSWstate); + + g_now = current_state?(model->CSWonConduct):(model->CSWoffConduct); + + *(here->CSWposPosptr) += g_now; + *(here->CSWposNegptr) -= g_now; + *(here->CSWnegPosptr) -= g_now; + *(here->CSWnegNegptr) += g_now; + } + } + return(OK); +} diff --git a/src/spicelib/devices/csw/cswask.c b/src/spicelib/devices/csw/cswask.c new file mode 100644 index 000000000..fdf01f2f5 --- /dev/null +++ b/src/spicelib/devices/csw/cswask.c @@ -0,0 +1,74 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal device parameters + * of Current controlled SWitch + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "cswdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CSWask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + CSWinstance *here = (CSWinstance*)inst; + static char *msg = "Current and power not available in ac analysis"; + switch(which) { + case CSW_CONTROL: + value->uValue = here->CSWcontName; + return (OK); + case CSW_POS_NODE: + value->iValue = here->CSWposNode; + return (OK); + case CSW_NEG_NODE: + value->iValue = here->CSWnegNode; + return (OK); + case CSW_CURRENT: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CSWask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = (*(ckt->CKTrhsOld+here->CSWposNode) + - *(ckt->CKTrhsOld + here->CSWnegNode)) * + here->CSWcond; + } + return(OK); + case CSW_POWER: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "CSWask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = (*(ckt->CKTrhsOld+here->CSWposNode) + - *(ckt->CKTrhsOld + here->CSWnegNode)) * + (*(ckt->CKTrhsOld + here->CSWposNode) + - *(ckt->CKTrhsOld + here->CSWnegNode)) * + here->CSWcond; + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/csw/cswdefs.h b/src/spicelib/devices/csw/cswdefs.h new file mode 100644 index 000000000..4d288160c --- /dev/null +++ b/src/spicelib/devices/csw/cswdefs.h @@ -0,0 +1,104 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon M. Jacobs +**********/ + +#ifndef CSW +#define CSW + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "noisedef.h" +#include "complex.h" + + /* structures used to describe current controlled switches */ + + +/* information to describe each instance */ + +typedef struct sCSWinstance { + struct sCSWmodel *CSWmodPtr; /* backpointer to model */ + struct sCSWinstance *CSWnextInstance; /* pointer to next instance of + * current model*/ + IFuid CSWname; /* pointer to character string naming this instance */ + int CSWowner; /* number of owner process */ + int CSWstate; /* pointer to start of switch's section of state vector */ + + int CSWposNode; /* number of positive node of switch */ + int CSWnegNode; /* number of negative node of switch */ + int CSWcontBranch; /* number of branch of controlling current */ + + IFuid CSWcontName; /* name of controlling source */ + + double *CSWposPosptr; /* pointer to sparse matrix diagonal at + (positive,positive) for switch conductance */ + double *CSWnegPosptr; /* pointer to sparse matrix offdiagonal at + (neagtive,positive) for switch conductance */ + double *CSWposNegptr; /* pointer to sparse matrix offdiagonal at + (positive,neagtive) for switch conductance */ + double *CSWnegNegptr; /* pointer to sparse matrix diagonal at + (neagtive,neagtive) for switch conductance */ + + double CSWcond; /* current conductance of switch */ + + unsigned CSWzero_stateGiven : 1; /* flag to indicate initial state */ +#ifndef NONOISE + double CSWnVar[NSTATVARS]; +#else /* NONOISE */ + double *CSWnVar; +#endif /* NONOISE */ +} CSWinstance ; + +/* data per model */ + +#define CSW_ON_CONDUCTANCE 1.0 /* default on conductance = 1 mho */ +#define CSW_OFF_CONDUCTANCE ckt->CKTgmin /* default off conductance */ +#define CSW_NUM_STATES 1 + +typedef struct sCSWmodel { /* model structure for a switch */ + int CSWmodType; /* type index of this device type */ + struct sCSWmodel *CSWnextModel; /* pointer to next possible model in + * linked list */ + CSWinstance *CSWinstances; /* pointer to list of instances that have this + * model */ + IFuid CSWmodName; /* pointer to character string naming this model */ + + double CSWonResistance; /* switch "on" resistance */ + double CSWoffResistance; /* switch "off" resistance */ + double CSWiThreshold; /* switching threshold current */ + double CSWiHysteresis; /* switching hysteresis current */ + double CSWonConduct; /* switch "on" conductance */ + double CSWoffConduct; /* switch "off" conductance */ + + unsigned CSWonGiven : 1; /* flag to indicate on-resistance was specified */ + unsigned CSWoffGiven : 1;/* flag to indicate off-resistance was " */ + unsigned CSWthreshGiven : 1;/* flag to indicate threshold volt was given */ + unsigned CSWhystGiven : 1; /* flag to indicate hysteresis volt was given */ +} CSWmodel; + +/* device parameters */ +#define CSW_CONTROL 1 +#define CSW_IC_ON 2 +#define CSW_IC_OFF 3 +#define CSW_POS_NODE 4 +#define CSW_NEG_NODE 5 +#define CSW_CURRENT 6 +#define CSW_POWER 7 + +/* model parameters */ +#define CSW_CSW 101 +#define CSW_RON 102 +#define CSW_ROFF 103 +#define CSW_ITH 104 +#define CSW_IHYS 105 +#define CSW_GON 106 +#define CSW_GOFF 107 + +/* device questions */ + +/* model questions */ + +#include "cswext.h" + +#endif /*CSW*/ diff --git a/src/spicelib/devices/csw/cswdel.c b/src/spicelib/devices/csw/cswdel.c new file mode 100644 index 000000000..710493eba --- /dev/null +++ b/src/spicelib/devices/csw/cswdel.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cswdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CSWdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; + +{ + CSWmodel *model = (CSWmodel*)inModel; + CSWinstance **fast = (CSWinstance**)inst; + CSWinstance **prev = NULL; + CSWinstance *here; + + for( ; model ; model = model->CSWnextModel) { + prev = &(model->CSWinstances); + for(here = *prev; here ; here = *prev) { + if(here->CSWname == name || (fast && here==*fast) ) { + *prev= here->CSWnextInstance; + FREE(here); + return(OK); + } + prev = &(here->CSWnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/csw/cswdest.c b/src/spicelib/devices/csw/cswdest.c new file mode 100644 index 000000000..b10c53e80 --- /dev/null +++ b/src/spicelib/devices/csw/cswdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cswdefs.h" +#include "suffix.h" + + +void +CSWdestroy(inModel) + GENmodel **inModel; +{ + CSWmodel **model = (CSWmodel**)inModel; + CSWinstance *here; + CSWinstance *prev = NULL; + CSWmodel *mod = *model; + CSWmodel *oldmod = NULL; + + for( ; mod ; mod = mod->CSWnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (CSWinstance *)NULL; + for(here = mod->CSWinstances ; here ; here = here->CSWnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/csw/cswext.h b/src/spicelib/devices/csw/cswext.h new file mode 100644 index 000000000..0f3f50dea --- /dev/null +++ b/src/spicelib/devices/csw/cswext.h @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon M. Jacobs +**********/ + +#ifdef __STDC__ +extern int CSWask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int CSWacLoad(GENmodel*,CKTcircuit*); +extern int CSWdelete(GENmodel*,IFuid,GENinstance**); +extern void CSWdestroy(GENmodel**); +extern int CSWload(GENmodel*,CKTcircuit*); +extern int CSWmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int CSWmDelete(GENmodel**,IFuid,GENmodel*); +extern int CSWmParam(int,IFvalue*,GENmodel*); +extern int CSWparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int CSWpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int CSWsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int CSWnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); +#else /* stdc */ +extern int CSWask(); +extern int CSWacLoad(); +extern int CSWdelete(); +extern void CSWdestroy(); +extern int CSWload(); +extern int CSWmAsk(); +extern int CSWmDelete(); +extern int CSWmParam(); +extern int CSWparam(); +extern int CSWpzLoad(); +extern int CSWsetup(); +extern int CSWnoise(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/csw/cswitf.h b/src/spicelib/devices/csw/cswitf.h new file mode 100644 index 000000000..83e40397c --- /dev/null +++ b/src/spicelib/devices/csw/cswitf.h @@ -0,0 +1,83 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_csw + +#ifndef DEV_CSW +#define DEV_CSW + +#include "cswext.h" +extern IFparm CSWpTable[ ]; +extern IFparm CSWmPTable[ ]; +extern char *CSWnames[ ]; +extern int CSWpTSize; +extern int CSWmPTSize; +extern int CSWnSize; +extern int CSWiSize; +extern int CSWmSize; + +SPICEdev CSWinfo = { + { "CSwitch", + "Current controlled ideal switch", + + &CSWnSize, + &CSWnSize, + CSWnames, + + &CSWpTSize, + CSWpTable, + + &CSWmPTSize, + CSWmPTable, + 0 + }, + + CSWparam, + CSWmParam, + CSWload, + CSWsetup, + NULL, + CSWsetup, + NULL, + NULL, + NULL, + CSWacLoad, + NULL, + CSWdestroy, +#ifdef DELETES + CSWmDelete, + CSWdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + CSWask, + CSWmAsk, +#ifdef AN_pz + CSWpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* DISTO */ +#ifdef AN_noise + CSWnoise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &CSWiSize, + &CSWmSize + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/csw/cswload.c b/src/spicelib/devices/csw/cswload.c new file mode 100644 index 000000000..4103852b7 --- /dev/null +++ b/src/spicelib/devices/csw/cswload.c @@ -0,0 +1,111 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "cswdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +CSWload(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + + /* actually load the current values into the + * sparse matrix previously provided + */ +{ + register CSWmodel *model = (CSWmodel*)inModel; + register CSWinstance *here; + double g_now; + double i_ctrl; + double previous_state; + double current_state; + + /* loop through all the switch models */ + for( ; model != NULL; model = model->CSWnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CSWinstances; here != NULL ; + here=here->CSWnextInstance) { + if (here->CSWowner != ARCHme) continue; + + /* decide the state of the switch */ + + if(ckt->CKTmode & (MODEINITFIX|MODEINITJCT)) { + + if(here->CSWzero_stateGiven) { + /* switch specified "on" */ + *(ckt->CKTstate0 + here->CSWstate) = 1.0; + current_state = 1.0; + } else { + *(ckt->CKTstate0 + here->CSWstate) = 0.0; + current_state = 0.0; + } + } else if (ckt->CKTmode & (MODEINITSMSIG)) { + + previous_state = *(ckt->CKTstate0 + here->CSWstate); + current_state = previous_state; + + } else if (ckt->CKTmode & (MODEINITFLOAT)) { + /* use state0 since INITTRAN or INITPRED already called */ + previous_state = *(ckt->CKTstate0 + here->CSWstate); + i_ctrl = *(ckt->CKTrhsOld + + here->CSWcontBranch); + if(i_ctrl > (model->CSWiThreshold+model->CSWiHysteresis)) { + *(ckt->CKTstate0 + here->CSWstate) = 1.0; + current_state = 1.0; + } + else if(i_ctrl < (model->CSWiThreshold - + model->CSWiHysteresis)) { + *(ckt->CKTstate0 + here->CSWstate) = 0.0; + current_state = 0.0; + } + else { + current_state = previous_state; + } + + if(current_state != previous_state) { + ckt->CKTnoncon++; /* ensure one more iteration */ + ckt->CKTtroubleElt = (GENinstance *) here; + } + + } else if (ckt->CKTmode & (MODEINITTRAN|MODEINITPRED)) { + + previous_state = *(ckt->CKTstate1 + here->CSWstate); + i_ctrl = *(ckt->CKTrhsOld + + here->CSWcontBranch); + + if(i_ctrl > (model->CSWiThreshold+model->CSWiHysteresis)) { + current_state = 1; + } else if(i_ctrl < (model->CSWiThreshold - + model->CSWiHysteresis)) { + current_state = 0; + } else { + current_state = previous_state; + } + + if(current_state == 0) { + *(ckt->CKTstate0 + here->CSWstate) = 0.0; + } else { + *(ckt->CKTstate0 + here->CSWstate) = 1.0; + } + + } + + g_now = current_state?(model->CSWonConduct):(model->CSWoffConduct); + here->CSWcond = g_now; + + *(here->CSWposPosptr) += g_now; + *(here->CSWposNegptr) -= g_now; + *(here->CSWnegPosptr) -= g_now; + *(here->CSWnegNegptr) += g_now; + } + } + return(OK); +} diff --git a/src/spicelib/devices/csw/cswmask.c b/src/spicelib/devices/csw/cswmask.c new file mode 100644 index 000000000..1a210c8a7 --- /dev/null +++ b/src/spicelib/devices/csw/cswmask.c @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal model parameters + * of Current controlled SWitch + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "cswdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CSWmAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + CSWmodel *here = (CSWmodel*)inst; + switch(which) { + case CSW_RON: + value->rValue = here->CSWonResistance; + return (OK); + case CSW_ROFF: + value->rValue = here->CSWoffResistance; + return (OK); + case CSW_ITH: + value->rValue = here->CSWiThreshold; + return (OK); + case CSW_IHYS: + value->rValue = here->CSWiHysteresis; + return (OK); + case CSW_GON: + value->rValue = here->CSWonConduct; + return (OK); + case CSW_GOFF: + value->rValue = here->CSWoffConduct; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/csw/cswmdel.c b/src/spicelib/devices/csw/cswmdel.c new file mode 100644 index 000000000..6d4975df3 --- /dev/null +++ b/src/spicelib/devices/csw/cswmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cswdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CSWmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + CSWmodel **model = (CSWmodel**)inModel; + CSWmodel *modfast = (CSWmodel*)kill; + CSWinstance *here; + CSWinstance *prev = NULL; + CSWmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->CSWnextModel)) { + if( (*model)->CSWmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->CSWnextModel; /* cut deleted device out of list */ + for(here = (*model)->CSWinstances ; here ; here = here->CSWnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/csw/cswmpar.c b/src/spicelib/devices/csw/cswmpar.c new file mode 100644 index 000000000..5b4573c76 --- /dev/null +++ b/src/spicelib/devices/csw/cswmpar.c @@ -0,0 +1,50 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "cswdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CSWmParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + CSWmodel *model = (CSWmodel*)inModel; + switch(param) { + case CSW_CSW: + /* just says that this is a switch */ + break; + case CSW_RON: + model->CSWonResistance = value->rValue; + model->CSWonConduct = 1.0/(value->rValue); + model->CSWonGiven = TRUE; + break; + case CSW_ROFF: + model->CSWoffResistance = value->rValue; + model->CSWoffConduct = 1.0/(value->rValue); + model->CSWoffGiven = TRUE; + break; + case CSW_ITH: + model->CSWiThreshold = value->rValue; + model->CSWthreshGiven = TRUE; + break; + case CSW_IHYS: + /* take absolute value of hysteresis voltage */ + model->CSWiHysteresis = fabs(value->rValue); + model->CSWhystGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/csw/cswnoise.c b/src/spicelib/devices/csw/cswnoise.c new file mode 100644 index 000000000..34282a7aa --- /dev/null +++ b/src/spicelib/devices/csw/cswnoise.c @@ -0,0 +1,160 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "cswdefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * CSWnoise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with current- controlled switches. It starts with the + * model *firstModel and traverses all of its instances. It then + * proceeds to any other models on the linked list. The total output + * noise density generated by the CSW's is summed in the variable + * "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +CSWnoise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + CSWmodel *firstModel = (CSWmodel *) genmodel; + register CSWmodel *model; + register CSWinstance *inst; + char name[N_MXVLNTH]; + double tempOutNoise; + double tempInNoise; + double noizDens; + double lnNdens; + int current_state; + + + for (model=firstModel; model != NULL; model=model->CSWnextModel) { + for (inst=model->CSWinstances; inst != NULL; inst=inst->CSWnextInstance) { + if (inst->CSWowner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name the noise generator */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + (void)sprintf(name,"onoise_%s",inst->CSWname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + break; + + case INT_NOIZ: + (void)sprintf(name,"onoise_total_%s",inst->CSWname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + (void)sprintf(name,"inoise_total_%s",inst->CSWname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + current_state = *(ckt->CKTstate0 + inst->CSWstate); + NevalSrc(&noizDens,&lnNdens,ckt,THERMNOISE, + inst->CSWposNode,inst->CSWnegNode, + current_state?(model->CSWonConduct):(model->CSWoffConduct)); + + *OnDens += noizDens; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + inst->CSWnVar[LNLSTDENS] = lnNdens; + + /* clear out our integration variable if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + inst->CSWnVar[OUTNOIZ] = 0.0; + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + tempOutNoise = Nintegrate(noizDens, lnNdens, + inst->CSWnVar[LNLSTDENS], data); + tempInNoise = Nintegrate(noizDens * + data->GainSqInv ,lnNdens + data->lnGainInv, + inst->CSWnVar[LNLSTDENS] + data->lnGainInv, + data); + inst->CSWnVar[OUTNOIZ] += tempOutNoise; + inst->CSWnVar[INNOIZ] += tempInNoise; + data->outNoiz += tempOutNoise; + data->inNoise += tempInNoise; + inst->CSWnVar[LNLSTDENS] = lnNdens; + } + if (data->prtSummary) { + data->outpVector[data->outNumber++] = noizDens; + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + data->outpVector[data->outNumber++] = inst->CSWnVar[OUTNOIZ]; + data->outpVector[data->outNumber++] = inst->CSWnVar[INNOIZ]; + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} + + diff --git a/src/spicelib/devices/csw/cswparam.c b/src/spicelib/devices/csw/cswparam.c new file mode 100644 index 000000000..f7a6e740a --- /dev/null +++ b/src/spicelib/devices/csw/cswparam.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cswdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CSWparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + CSWinstance *here = (CSWinstance*)inst; + switch(param) { + case CSW_CONTROL: + here->CSWcontName = value->uValue; + break; + case CSW_IC_ON: + if(value->iValue) { + here->CSWzero_stateGiven = TRUE; + } + break; + case CSW_IC_OFF: + if(value->iValue) { + here->CSWzero_stateGiven = FALSE; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/csw/cswpzld.c b/src/spicelib/devices/csw/cswpzld.c new file mode 100644 index 000000000..fa588402b --- /dev/null +++ b/src/spicelib/devices/csw/cswpzld.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "cswdefs.h" +#include "sperror.h" +#include "complex.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +CSWpzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; + + /* load the current values into the + * sparse matrix previously provided + * during AC analysis + */ +{ + register CSWmodel *model = (CSWmodel*)inModel; + register CSWinstance *here; + double g_now; + int current_state; + + /* loop through all the switch models */ + for( ; model != NULL; model = model->CSWnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->CSWinstances; here != NULL ; + here=here->CSWnextInstance) { + if (here->CSWowner != ARCHme) continue; + + current_state = *(ckt->CKTstate0 + here->CSWstate); + + g_now = current_state?(model->CSWonConduct):(model->CSWoffConduct); + + *(here->CSWposPosptr) += g_now; + *(here->CSWposNegptr) -= g_now; + *(here->CSWnegPosptr) -= g_now; + *(here->CSWnegNegptr) += g_now; + } + } + return(OK); +} diff --git a/src/spicelib/devices/csw/cswsetup.c b/src/spicelib/devices/csw/cswsetup.c new file mode 100644 index 000000000..79d84cb9e --- /dev/null +++ b/src/spicelib/devices/csw/cswsetup.c @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "cswdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +CSWsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the switch conductance with those pointers needed later + * for fast matrix loading + */ + +{ + register CSWmodel *model = (CSWmodel*)inModel; + register CSWinstance *here; + + /* loop through all the current source models */ + for( ; model != NULL; model = model->CSWnextModel ) { + /* Default Value Processing for Switch Model */ + if (!model->CSWthreshGiven) { + model->CSWiThreshold = 0; + } + if (!model->CSWhystGiven) { + model->CSWiHysteresis = 0; + } + if (!model->CSWonGiven) { + model->CSWonConduct = CSW_ON_CONDUCTANCE; + model->CSWonResistance = 1.0/model->CSWonConduct; + } + if (!model->CSWoffGiven) { + model->CSWoffConduct = CSW_OFF_CONDUCTANCE; + model->CSWoffResistance = 1.0/model->CSWoffConduct; + } + + /* loop through all the instances of the model */ + for (here = model->CSWinstances; here != NULL ; + here=here->CSWnextInstance) { + if (here->CSWowner != ARCHme) goto matrixpointers; + + /* Default Value Processing for Switch Instance */ + here->CSWstate = *states; + *states += CSW_NUM_STATES; + +matrixpointers: + here->CSWcontBranch = CKTfndBranch(ckt,here->CSWcontName); + if(here->CSWcontBranch == 0) { + IFuid namarray[2]; + namarray[0] = here->CSWname; + namarray[1] = here->CSWcontName; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: unknown controlling source %s",namarray); + return(E_BADPARM); + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(CSWposPosptr, CSWposNode, CSWposNode) + TSTALLOC(CSWposNegptr, CSWposNode, CSWnegNode) + TSTALLOC(CSWnegPosptr, CSWnegNode, CSWposNode) + TSTALLOC(CSWnegNegptr, CSWnegNode, CSWnegNode) + } + } + return(OK); +} diff --git a/src/spicelib/devices/devsup/ChangeLog b/src/spicelib/devices/devsup/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/devsup/Makefile.am b/src/spicelib/devices/devsup/Makefile.am new file mode 100644 index 000000000..9c2b5051a --- /dev/null +++ b/src/spicelib/devices/devsup/Makefile.am @@ -0,0 +1,10 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libdevsup.la + +libdevsup_la_SOURCES = devsup.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/devsup/devsup.c b/src/spicelib/devices/devsup/devsup.c new file mode 100644 index 000000000..f01dab3ab --- /dev/null +++ b/src/spicelib/devices/devsup/devsup.c @@ -0,0 +1,427 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* support routines for device models */ + +#include "ngspice.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "suffix.h" + + /* DEVlimvds(vnew,vold) + * limit the per-iteration change of VDS + */ + +double +DEVlimvds(vnew,vold) + double vnew; + double vold; + +{ + + if(vold >= 3.5) { + if(vnew > vold) { + vnew = MIN(vnew,(3 * vold) +2); + } else { + if (vnew < 3.5) { + vnew = MAX(vnew,2); + } + } + } else { + if(vnew > vold) { + vnew = MIN(vnew,4); + } else { + vnew = MAX(vnew,-.5); + } + } + return(vnew); +} + + + /* DEVpnjlim(vnew,vold,vt,vcrit,icheck) + * limit the per-iteration change of PN junction voltages + */ + + +double +DEVpnjlim(vnew,vold,vt,vcrit,icheck) + + double vnew; + double vold; + double vt; + double vcrit; + int *icheck; + +{ + double arg; + + if((vnew > vcrit) && (fabs(vnew - vold) > (vt + vt))) { + if(vold > 0) { + arg = 1 + (vnew - vold) / vt; + if(arg > 0) { + vnew = vold + vt * log(arg); + } else { + vnew = vcrit; + } + } else { + vnew = vt *log(vnew/vt); + } + *icheck = 1; + } else { + *icheck = 0; + } + return(vnew); +} + + /* + * DEVfetlim(vnew,vold.vto) + * + * limit the per-iteration change of FET voltages + */ + +double +DEVfetlim(vnew,vold,vto) + double vnew; + double vold; + double vto; + +{ + double vtsthi; + double vtstlo; + double vtox; + double delv; + double vtemp; + + vtsthi = fabs(2*(vold-vto))+2; + vtstlo = vtsthi/2 +2; + vtox = vto + 3.5; + delv = vnew-vold; + + if (vold >= vto) { + if(vold >= vtox) { + if(delv <= 0) { + /* going off */ + if(vnew >= vtox) { + if(-delv >vtstlo) { + vnew = vold - vtstlo; + } + } else { + vnew = MAX(vnew,vto+2); + } + } else { + /* staying on */ + if(delv >= vtsthi) { + vnew = vold + vtsthi; + } + } + } else { + /* middle region */ + if(delv <= 0) { + /* decreasing */ + vnew = MAX(vnew,vto-.5); + } else { + /* increasing */ + vnew = MIN(vnew,vto+4); + } + } + } else { + /* off */ + if(delv <= 0) { + if(-delv >vtsthi) { + vnew = vold - vtsthi; + } + } else { + vtemp = vto + .5; + if(vnew <= vtemp) { + if(delv >vtstlo) { + vnew = vold + vtstlo; + } + } else { + vnew = vtemp; + } + } + } + return(vnew); +} + + + /* + * DEVcmeyer(vgs0,vgd0,vgb0,von0,vdsat0, + * vgs1,vgd1,vgb1,covlgs,covlgd,covlgb, + * cgs0,cgd0,cgb0, + * von,vdsat) + * + * Compute the MOS overlap capacitances as functions of the + * device terminal voltages + */ + +void +DEVcmeyer(vgs0,vgd0,vgb0,von0,vdsat0, + vgs1,vgd1,vgb1,covlgs,covlgd,covlgb, + cgs,cgd,cgb, + phi,cox,von,vdsat) +double vgs0; /* initial voltage gate-source */ +double vgd0; /* initial voltage gate-drain */ +double vgb0; /* initial voltage gate-bulk */ +double von0; +double vdsat0; +double vgs1; /* final voltage gate-source */ +double vgd1; /* final voltage gate-drain */ +double vgb1; /* final voltage gate-bulk */ +double covlgs; /* overlap capacitance gate-source */ +double covlgd; /* overlap capacitance gate-drain */ +double covlgb; /* overlap capacitance gate-bulk */ +register double *cgs; +register double *cgd; +register double *cgb; +double phi; +double cox; +double von; +double vdsat; + +{ + + + double vdb; + double vdbsat; + double vddif; + double vddif1; + double vddif2; + double vgbt; + + *cgs = 0; + *cgd = 0; + *cgb = 0; + + vgbt = vgs1-von; + if (vgbt <= -phi) { + *cgb = cox; + } else if (vgbt <= -phi/2) { + *cgb = -vgbt*cox/phi; + } else if (vgbt <= 0) { + *cgb = -vgbt*cox/phi; + *cgs = cox/(7.5e-1*phi)*vgbt+cox/1.5; + } else { + vdbsat = vdsat-(vgs1-vgb1); + vdb = vgb1-vgd1; + if (vdbsat <= vdb) { + *cgs = cox/1.5; + } else { + vddif = 2.0*vdbsat-vdb; + vddif1 = vdbsat-vdb-1.0e-12; + vddif2 = vddif*vddif; + *cgd = cox*(1.0-vdbsat*vdbsat/vddif2)/1.5; + *cgs = cox*(1.0-vddif1*vddif1/vddif2)/1.5; + } + } + + vgbt = vgs0-von0; + if (vgbt <= -phi) { + *cgb += cox; + } else if (vgbt <= -phi/2) { + *cgb += -vgbt*cox/phi; + } else if (vgbt <= 0) { + *cgb += -vgbt*cox/phi; + *cgs += cox/(7.5e-1*phi)*vgbt+cox/1.5; + } else { + vdbsat = vdsat0-(vgs0-vgb0); + vdb = vgb0-vgd0; + if (vdbsat <= vdb) { + *cgs += cox/1.5; + } else { + vddif = 2.0*vdbsat-vdb; + vddif1 = vdbsat-vdb-1.0e-12; + vddif2 = vddif*vddif; + *cgd += cox*(1.0-vdbsat*vdbsat/vddif2)/1.5; + *cgs += cox*(1.0-vddif1*vddif1/vddif2)/1.5; + } + } + + *cgs = *cgs *.5 + covlgs; + *cgd = *cgd *.5 + covlgd; + *cgb = *cgb *.5 + covlgb; +} + + + /* + * DEVqmeyer(vgs,vgd,vgb,von,vdsat,capgs,capgd,capgb,phi,cox) + * + * + * + * Compute the MOS overlap capacitances as functions of the + * device terminal voltages + */ + +/* ARGSUSED */ /* because vgb is no longer used */ +void +DEVqmeyer(vgs,vgd,vgb,von,vdsat,capgs,capgd,capgb,phi,cox) +double vgs; /* initial voltage gate-source */ +double vgd; /* initial voltage gate-drain */ +double vgb; /* initial voltage gate-bulk */ +double von; +double vdsat; +double *capgs; /* non-constant portion of g-s overlap capacitance */ +double *capgd; /* non-constant portion of g-d overlap capacitance */ +double *capgb; /* non-constant portion of g-b overlap capacitance */ +double phi; +double cox; /* oxide capactiance */ + +{ + + + double vds; + double vddif; + double vddif1; + double vddif2; + double vgst; + + + vgst = vgs-von; + if (vgst <= -phi) { + *capgb = cox/2; + *capgs = 0; + *capgd = 0; + } else if (vgst <= -phi/2) { + *capgb = -vgst*cox/(2*phi); + *capgs = 0; + *capgd = 0; + } else if (vgst <= 0) { + *capgb = -vgst*cox/(2*phi); + *capgs = vgst*cox/(1.5*phi)+cox/3; + *capgd = 0; + } else { + vds = vgs-vgd; + if (vdsat <= vds) { + *capgs = cox/3; + *capgd = 0; + *capgb = 0; + } else { + vddif = 2.0*vdsat-vds; + vddif1 = vdsat-vds/*-1.0e-12*/; + vddif2 = vddif*vddif; + *capgd = cox*(1.0-vdsat*vdsat/vddif2)/3; + *capgs = cox*(1.0-vddif1*vddif1/vddif2)/3; + *capgb = 0; + } + } + +} + +#ifdef notdef +/* XXX This is no longer used, apparently */ +void +DEVcap(ckt,vgd,vgs,vgb,covlgd,covlgs,covlgb, + capbd,capbs,cggb,cgdb,cgsb,cbgb,cbdb,cbsb, + gcggb,gcgdb,gcgsb,gcbgb,gcbdb,gcbsb, + gcdgb,gcddb,gcdsb,gcsgb,gcsdb,gcssb, + qgate,qchan,qbulk,qdrn,qsrc,xqc) + +register CKTcircuit *ckt; + double vgd; + double vgs; + double vgb; + double covlgd; + double covlgs; + double covlgb; + double capbd; + double capbs; + double cggb; + double cgdb; + double cgsb; + double cbgb; + double cbdb; + double cbsb; + double *gcggb; + double *gcgdb; + double *gcgsb; + double *gcbgb; + double *gcbdb; + double *gcbsb; + double *gcdgb; + double *gcddb; + double *gcdsb; + double *gcsgb; + double *gcsdb; + double *gcssb; + double qgate; + double qchan; + double qbulk; + double *qdrn; + double *qsrc; + double xqc; + + /* + * compute equivalent conductances + * divide up the channel charge (1-xqc)/xqc to source and drain + */ +{ + + double gcd; + double gcdxd; + double gcdxs; + double gcg; + double gcgxd; + double gcgxs; + double gcs; + double gcsxd; + double gcsxs; + double qgb; + double qgd; + double qgs; + + gcg = (cggb+cbgb)*ckt->CKTag[1]; + gcd = (cgdb+cbdb)*ckt->CKTag[1]; + gcs = (cgsb+cbsb)*ckt->CKTag[1]; + gcgxd = -xqc*gcg; + gcgxs = -(1-xqc)*gcg; + gcdxd = -xqc*gcd; + gcdxs = -(1-xqc)*gcd; + gcsxd = -xqc*gcs; + gcsxs = -(1-xqc)*gcs; + *gcdgb = gcgxd-covlgd*ckt->CKTag[1]; + *gcddb = gcdxd+(capbd+covlgd)*ckt->CKTag[1]; + *gcdsb = gcsxd; + *gcsgb = gcgxs-covlgs*ckt->CKTag[1]; + *gcsdb = gcdxs; + *gcssb = gcsxs+(capbs+covlgs)*ckt->CKTag[1]; + *gcggb = (cggb+covlgd+covlgs+covlgb)*ckt->CKTag[1]; + *gcgdb = (cgdb-covlgd)*ckt->CKTag[1]; + *gcgsb = (cgsb-covlgs)*ckt->CKTag[1]; + *gcbgb = (cbgb-covlgb)*ckt->CKTag[1]; + *gcbdb = (cbdb-capbd)*ckt->CKTag[1]; + *gcbsb = (cbsb-capbs)*ckt->CKTag[1]; + /* + * compute total terminal charges + */ + qgd = covlgd*vgd; + qgs = covlgs*vgs; + qgb = covlgb*vgb; + qgate = qgate+qgd+qgs+qgb; + qbulk = qbulk-qgb; + *qdrn = xqc*qchan-qgd; + *qsrc = (1-xqc)*qchan-qgs; + /* + * finished + */ +} +#endif + +double DEVpred(ckt,loct) + CKTcircuit *ckt; + int loct; +{ + + /* predict a value for the capacitor at loct by + * extrapolating from previous values + */ + +#ifndef NEWTRUNC + double xfact; + xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1]; + return( ( (1+xfact) * *(ckt->CKTstate1+loct) ) - + ( xfact * *(ckt->CKTstate2+loct) ) ); +#endif /*NEWTRUNC*/ + +} diff --git a/src/spicelib/devices/dio/ChangeLog b/src/spicelib/devices/dio/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/dio/Makefile.am b/src/spicelib/devices/dio/Makefile.am new file mode 100644 index 000000000..600e63d84 --- /dev/null +++ b/src/spicelib/devices/dio/Makefile.am @@ -0,0 +1,36 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libdio.la + +libdio_la_SOURCES = \ + dio.c \ + dioacld.c \ + dioask.c \ + dioconv.c \ + diodefs.h \ + diodel.c \ + diodest.c \ + diodisto.c \ + diodset.c \ + dioext.h \ + diogetic.c \ + dioitf.h \ + dioload.c \ + diomask.c \ + diomdel.c \ + diompar.c \ + dionoise.c \ + dioparam.c \ + diopzld.c \ + diosacl.c \ + diosetup.c \ + diosload.c \ + diosprt.c \ + diosset.c \ + diosupd.c \ + diotemp.c \ + diotrunc.c + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/dio/dio.c b/src/spicelib/devices/dio/dio.c new file mode 100644 index 000000000..e396fd10c --- /dev/null +++ b/src/spicelib/devices/dio/dio.c @@ -0,0 +1,65 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "diodefs.h" +#include "suffix.h" + +IFparm DIOpTable[] = { /* parameters */ + IOPU("off", DIO_OFF, IF_FLAG, "Initially off"), + IOPU("temp", DIO_TEMP, IF_REAL, "Instance temperature"), + IOPAU("ic", DIO_IC, IF_REAL, "Initial device voltage"), + IOPU("area", DIO_AREA, IF_REAL, "Area factor"), + IP("sens_area",DIO_AREA_SENS,IF_FLAG,"flag to request sensitivity WRT area"), + OP("vd",DIO_VOLTAGE,IF_REAL, "Diode voltage"), + OP("id", DIO_CURRENT,IF_REAL, "Diode current"), + OPR("c", DIO_CURRENT,IF_REAL, "Diode current"), + OP("gd", DIO_CONDUCT,IF_REAL, "Diode conductance"), + OP("cd", DIO_CAP, IF_REAL, "Diode capacitance"), + OPU("charge", DIO_CHARGE, IF_REAL, "Diode capacitor charge"), + OPU("capcur", DIO_CAPCUR, IF_REAL, "Diode capacitor current"), + OPU("p", DIO_POWER, IF_REAL, "Diode power"), + OPU("sens_dc",DIO_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU("sens_real", DIO_QUEST_SENS_REAL,IF_REAL, + "dc sens. and real part of ac sensitivity"), + OPU("sens_imag", DIO_QUEST_SENS_IMAG,IF_REAL, "imag part of ac sensitivity "), + OPU("sens_mag", DIO_QUEST_SENS_MAG, IF_REAL, "sensitivity of ac magnitude"), + OPU("sens_ph", DIO_QUEST_SENS_PH, IF_REAL, "sensitivity of ac phase"), + OPU("sens_cplx", DIO_QUEST_SENS_CPLX,IF_COMPLEX,"ac sensitivity") +}; + +IFparm DIOmPTable[] = { /* model parameters */ + IOP( "is", DIO_MOD_IS, IF_REAL, "Saturation current"), + IOPU( "tnom",DIO_MOD_TNOM,IF_REAL, "Parameter measurement temperature"), + IOP( "rs", DIO_MOD_RS, IF_REAL, "Ohmic resistance"), + IOP( "n", DIO_MOD_N, IF_REAL, "Emission Coefficient"), + IOPA( "tt", DIO_MOD_TT, IF_REAL, "Transit Time"), + IOPA( "cjo", DIO_MOD_CJO, IF_REAL, "Junction capacitance"), + IOPR( "cj0", DIO_MOD_CJO, IF_REAL, "Junction capacitance"), + IOP( "vj", DIO_MOD_VJ, IF_REAL, "Junction potential"), + IOP( "m", DIO_MOD_M, IF_REAL, "Grading coefficient"), + IOP( "eg", DIO_MOD_EG, IF_REAL, "Activation energy"), + IOP( "xti", DIO_MOD_XTI, IF_REAL, "Saturation current temperature exp."), + IOP( "kf", DIO_MOD_KF, IF_REAL, "flicker noise coefficient"), + IOP( "af", DIO_MOD_AF, IF_REAL, "flicker noise exponent"), + IOP( "fc", DIO_MOD_FC, IF_REAL, "Forward bias junction fit parameter"), + IOP( "bv", DIO_MOD_BV, IF_REAL, "Reverse breakdown voltage"), + IOP( "ibv", DIO_MOD_IBV, IF_REAL, "Current at reverse breakdown voltage"), + OPU( "cond", DIO_MOD_COND,IF_REAL, "Ohmic conductance"), + IP( "d", DIO_MOD_D, IF_FLAG, "Diode model") +}; + +char *DIOnames[] = { + "D+", + "D-" +}; + +int DIOnSize = NUMELEMS(DIOnames); +int DIOpTSize = NUMELEMS(DIOpTable); +int DIOmPTSize = NUMELEMS(DIOmPTable); +int DIOiSize = sizeof(DIOinstance); +int DIOmSize = sizeof(DIOmodel); diff --git a/src/spicelib/devices/dio/dioacld.c b/src/spicelib/devices/dio/dioacld.c new file mode 100644 index 000000000..d04911bfa --- /dev/null +++ b/src/spicelib/devices/dio/dioacld.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + +{ + register DIOmodel *model = (DIOmodel*)inModel; + double gspr; + double geq; + double xceq; + register DIOinstance *here; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + gspr=model->DIOconductance*here->DIOarea; + geq= *(ckt->CKTstate0 + here->DIOconduct); + xceq= *(ckt->CKTstate0 + here->DIOcapCurrent) * ckt->CKTomega; + *(here->DIOposPosPtr ) += gspr; + *(here->DIOnegNegPtr ) += geq; + *(here->DIOnegNegPtr +1 ) += xceq; + *(here->DIOposPrimePosPrimePtr ) += geq+gspr; + *(here->DIOposPrimePosPrimePtr +1 ) += xceq; + *(here->DIOposPosPrimePtr ) -= gspr; + *(here->DIOnegPosPrimePtr ) -= geq; + *(here->DIOnegPosPrimePtr +1 ) -= xceq; + *(here->DIOposPrimePosPtr ) -= gspr; + *(here->DIOposPrimeNegPtr ) -= geq; + *(here->DIOposPrimeNegPtr +1 ) -= xceq; + } + } + return(OK); + +} diff --git a/src/spicelib/devices/dio/dioask.c b/src/spicelib/devices/dio/dioask.c new file mode 100644 index 000000000..17e7cd594 --- /dev/null +++ b/src/spicelib/devices/dio/dioask.c @@ -0,0 +1,140 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "devdefs.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +DIOask (ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + DIOinstance *here = (DIOinstance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + + switch (which) { + case DIO_OFF: + value->iValue = here->DIOoff; + return(OK); + case DIO_IC: + value->rValue = here->DIOinitCond; + return(OK); + case DIO_AREA: + value->rValue = here->DIOarea; + return(OK); + case DIO_TEMP: + value->rValue = here->DIOtemp-CONSTCtoK; + return(OK); + case DIO_VOLTAGE: + value->rValue = *(ckt->CKTstate0+here->DIOvoltage); + return(OK); + case DIO_CURRENT: + value->rValue = *(ckt->CKTstate0+here->DIOcurrent); + return(OK); + case DIO_CAP: + value->rValue = here->DIOcap; + return(OK); + case DIO_CHARGE: + value->rValue = *(ckt->CKTstate0+here->DIOcapCharge); + return(OK); + case DIO_CAPCUR: + value->rValue = *(ckt->CKTstate0+here->DIOcapCurrent); + return(OK); + case DIO_CONDUCT: + value->rValue = *(ckt->CKTstate0+here->DIOconduct); + return(OK); + case DIO_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "DIOask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTstate0 + here->DIOcurrent) * + *(ckt->CKTstate0 + here->DIOvoltage); + } + return(OK); + case DIO_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->DIOsenParmNo); + } + return(OK); + case DIO_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->DIOsenParmNo); + } + return(OK); + case DIO_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->DIOsenParmNo); + } + return(OK); + case DIO_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->DIOsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->DIOsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case DIO_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->DIOsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->DIOsenParmNo); + + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case DIO_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->DIOsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->DIOsenParmNo); + } + return(OK); + default: + return(E_BADPARM); + } +} + diff --git a/src/spicelib/devices/dio/dioconv.c b/src/spicelib/devices/dio/dioconv.c new file mode 100644 index 000000000..dac6f6b17 --- /dev/null +++ b/src/spicelib/devices/dio/dioconv.c @@ -0,0 +1,61 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include +#include "ngspice.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "const.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +DIOconvTest(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* Check the devices for convergence + */ +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + double delvd,vd,cdhat,cd; + double tol; + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + /* + * initialization + */ + + vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)- + *(ckt->CKTrhsOld + here->DIOnegNode); + + delvd=vd- *(ckt->CKTstate0 + here->DIOvoltage); + cdhat= *(ckt->CKTstate0 + here->DIOcurrent) + + *(ckt->CKTstate0 + here->DIOconduct) * delvd; + + cd= *(ckt->CKTstate0 + here->DIOcurrent); + + /* + * check convergence + */ + tol=ckt->CKTreltol* + MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol; + if (fabs(cdhat-cd) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* don't need to check any more device */ + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/dio/diodefs.h b/src/spicelib/devices/dio/diodefs.h new file mode 100644 index 000000000..01c473f17 --- /dev/null +++ b/src/spicelib/devices/dio/diodefs.h @@ -0,0 +1,219 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +#ifndef DIO +#define DIO + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + + /* data structures used to describe diodes */ + + +/* information needed per instance */ + +typedef struct sDIOinstance { + struct sDIOmodel *DIOmodPtr; /* backpointer to model */ + struct sDIOinstance *DIOnextInstance; /* pointer to next instance of + * current model*/ + IFuid DIOname; /* pointer to character string naming this instance */ + int DIOowner; /* number of owner process */ + int DIOstate; /* pointer to start of state vector for diode */ + int DIOposNode; /* number of positive node of diode */ + int DIOnegNode; /* number of negative node of diode */ + int DIOposPrimeNode; /* number of positive prime node of diode */ + + double *DIOposPosPrimePtr; /* pointer to sparse matrix at + * (positive,positive prime) */ + double *DIOnegPosPrimePtr; /* pointer to sparse matrix at + * (negative,positive prime) */ + double *DIOposPrimePosPtr; /* pointer to sparse matrix at + * (positive prime,positive) */ + double *DIOposPrimeNegPtr; /* pointer to sparse matrix at + * (positive prime,negative) */ + double *DIOposPosPtr; /* pointer to sparse matrix at + * (positive,positive) */ + double *DIOnegNegPtr; /* pointer to sparse matrix at + * (negative,negative) */ + double *DIOposPrimePosPrimePtr; /* pointer to sparse matrix at + * (positive prime,positive prime) */ + + double DIOcap; /* stores the diode capacitance */ + + double *DIOsens; /* stores the perturbed values of geq and ceq in ac + sensitivity analyis */ + + int DIOsenParmNo ; /* parameter # for sensitivity use; + * set equal to 0 if not a design parameter*/ + + unsigned DIOoff : 1; /* 'off' flag for diode */ + unsigned DIOareaGiven : 1; /* flag to indicate area was specified */ + unsigned DIOinitCondGiven : 1; /* flag to indicate ic was specified */ + unsigned DIOsenPertFlag :1; /* indictes whether the the parameter of + the particular instance is to be perturbed */ + unsigned DIOtempGiven : 1; /* flag to indicate temperature was specified */ + + + double DIOarea; /* area factor for the diode */ + double DIOinitCond; /* initial condition */ + double DIOtemp; /* temperature of the instance */ + double DIOtJctPot; /* temperature adjusted junction potential */ + double DIOtJctCap; /* temperature adjusted junction capacitance */ + double DIOtDepCap; /* temperature adjusted transition point in */ + /* the curve matching (Fc * Vj ) */ + double DIOtSatCur; /* temperature adjusted saturation current */ + double DIOtVcrit; /* temperature adjusted V crit */ + double DIOtF1; /* temperature adjusted f1 */ + double DIOtBrkdwnV; /* temperature adjusted breakdown voltage */ + +/* + * naming convention: + * x = vdiode + */ + +/* the following are relevant to s.s. sinusoidal distortion analysis */ + +#define DIONDCOEFFS 6 + +#ifndef NODISTO + double DIOdCoeffs[DIONDCOEFFS]; +#else /* NODISTO */ + double *DIOdCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define id_x2 DIOdCoeffs[0] +#define id_x3 DIOdCoeffs[1] +#define cdif_x2 DIOdCoeffs[2] +#define cdif_x3 DIOdCoeffs[3] +#define cjnc_x2 DIOdCoeffs[4] +#define cjnc_x3 DIOdCoeffs[5] + +#endif + +/* indices to array of diode noise sources */ + +#define DIORSNOIZ 0 +#define DIOIDNOIZ 1 +#define DIOFLNOIZ 2 +#define DIOTOTNOIZ 3 + +#define DIONSRCS 4 + +#ifndef NONOISE + double DIOnVar[NSTATVARS][DIONSRCS]; +#else /* NONOISE */ + double **DIOnVar; +#endif /* NONOISE */ + +} DIOinstance ; + +#define DIOsenGeq DIOsens /* stores the perturbed values of geq */ +#define DIOsenCeq DIOsens + 3 /* stores the perturbed values of ceq */ +#define DIOdphidp DIOsens + 6 + + +#define DIOvoltage DIOstate +#define DIOcurrent DIOstate+1 +#define DIOconduct DIOstate+2 +#define DIOcapCharge DIOstate+3 +#define DIOcapCurrent DIOstate+4 +#define DIOsensxp DIOstate+5 /* charge sensitivities and their derivatives. + * +6 for the derivatives - pointer to the + * beginning of the array */ + + +/* per model data */ + +typedef struct sDIOmodel { /* model structure for a diode */ + int DIOmodType; /* type index of this device type */ + struct sDIOmodel *DIOnextModel; /* pointer to next possible model in + * linked list */ + DIOinstance * DIOinstances; /* pointer to list of instances + * that have this model */ + IFuid DIOmodName; /* pointer to character string naming this model */ + + unsigned DIOsatCurGiven : 1; + unsigned DIOresistGiven : 1; + unsigned DIOemissionCoeffGiven : 1; + unsigned DIOtransitTimeGiven : 1; + unsigned DIOjunctionCapGiven : 1; + unsigned DIOjunctionPotGiven : 1; + unsigned DIOgradingCoeffGiven : 1; + unsigned DIOactivationEnergyGiven : 1; + unsigned DIOsaturationCurrentExpGiven : 1; + unsigned DIOdepletionCapCoeffGiven : 1; + unsigned DIObreakdownVoltageGiven : 1; + unsigned DIObreakdownCurrentGiven : 1; + unsigned DIOnomTempGiven : 1; + unsigned DIOfNcoefGiven : 1; + unsigned DIOfNexpGiven : 1; + + double DIOsatCur; /* saturation current */ + double DIOresist; /* ohmic series resistance */ + double DIOconductance; /* conductance corresponding to ohmic R */ + double DIOemissionCoeff; /* emission coefficient (N) */ + double DIOtransitTime; /* transit time (TT) */ + double DIOjunctionCap; /* Junction Capacitance (Cj0) */ + double DIOjunctionPot; /* Junction Potential (Vj) or (PB) */ + double DIOgradingCoeff; /* grading coefficient (m) */ + double DIOactivationEnergy; /* activation energy (EG) */ + double DIOsaturationCurrentExp; /* Saturation current exponential (XTI) */ + double DIOdepletionCapCoeff; /* Depletion Cap fraction coefficient (FC)*/ + double DIObreakdownVoltage; /* Voltage at reverse breakdown */ + double DIObreakdownCurrent; /* Current at above voltage */ + double DIOf2; /* coefficient for capacitance equation precomputation */ + double DIOf3; /* coefficient for capacitance equation precomputation */ + double DIOnomTemp; /* nominal temperature (temp at which parms measured */ + double DIOfNcoef; + double DIOfNexp; + + +} DIOmodel; + +/* device parameters */ +#define DIO_AREA 1 +#define DIO_IC 2 +#define DIO_OFF 3 +#define DIO_CURRENT 4 +#define DIO_VOLTAGE 5 +#define DIO_CHARGE 6 +#define DIO_CAPCUR 7 +#define DIO_CONDUCT 8 +#define DIO_AREA_SENS 9 +#define DIO_POWER 10 +#define DIO_TEMP 11 +#define DIO_QUEST_SENS_REAL 12 +#define DIO_QUEST_SENS_IMAG 13 +#define DIO_QUEST_SENS_MAG 14 +#define DIO_QUEST_SENS_PH 15 +#define DIO_QUEST_SENS_CPLX 16 +#define DIO_QUEST_SENS_DC 17 +#define DIO_CAP 18 + +/* model parameters */ +#define DIO_MOD_IS 101 +#define DIO_MOD_RS 102 +#define DIO_MOD_N 103 +#define DIO_MOD_TT 104 +#define DIO_MOD_CJO 105 +#define DIO_MOD_VJ 106 +#define DIO_MOD_M 107 +#define DIO_MOD_EG 108 +#define DIO_MOD_XTI 109 +#define DIO_MOD_FC 110 +#define DIO_MOD_BV 111 +#define DIO_MOD_IBV 112 +#define DIO_MOD_D 113 +#define DIO_MOD_COND 114 +#define DIO_MOD_TNOM 115 +#define DIO_MOD_KF 116 +#define DIO_MOD_AF 117 + +#include "dioext.h" +#endif /*DIO*/ diff --git a/src/spicelib/devices/dio/diodel.c b/src/spicelib/devices/dio/diodel.c new file mode 100644 index 000000000..bac91e0e1 --- /dev/null +++ b/src/spicelib/devices/dio/diodel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOdelete(inModel,name,kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; +{ + DIOmodel *model = (DIOmodel*)inModel; + DIOinstance **fast = (DIOinstance**)kill; + DIOinstance **prev = NULL; + DIOinstance *here; + + for( ; model ; model = model->DIOnextModel) { + prev = &(model->DIOinstances); + for(here = *prev; here ; here = *prev) { + if(here->DIOname == name || (fast && here==*fast) ) { + *prev= here->DIOnextInstance; + FREE(here); + return(OK); + } + prev = &(here->DIOnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/dio/diodest.c b/src/spicelib/devices/dio/diodest.c new file mode 100644 index 000000000..b92cef28a --- /dev/null +++ b/src/spicelib/devices/dio/diodest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "diodefs.h" +#include "suffix.h" + + +void +DIOdestroy(inModel) + GENmodel **inModel; +{ + DIOmodel **model = (DIOmodel**)inModel; + DIOinstance *here; + DIOinstance *prev = NULL; + DIOmodel *mod = *model; + DIOmodel *oldmod = NULL; + + for( ; mod ; mod = mod->DIOnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (DIOinstance *)NULL; + for(here = mod->DIOinstances ; here ; here = here->DIOnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/dio/diodisto.c b/src/spicelib/devices/dio/diodisto.c new file mode 100644 index 000000000..2f7385722 --- /dev/null +++ b/src/spicelib/devices/dio/diodisto.c @@ -0,0 +1,308 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +DIOdisto(mode,genmodel,ckt) + GENmodel *genmodel; + register CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + DIOmodel *model = (DIOmodel *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + double g2,g3; + double cdiff2,cdiff3; + double cjunc2,cjunc3; + double r1h1x,i1h1x; + double r1h2x, i1h2x; + double i1hm2x; + double r2h11x,i2h11x; + double r2h1m2x,i2h1m2x; + double temp, itemp; + register DIOinstance *here; + +if (mode == D_SETUP) + return(DIOdSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the DIO models */ +for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + g2=here->id_x2; + + cdiff2=here->cdif_x2; + + cjunc2=here->cjnc_x2; + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->DIOposPrimeNode)) - + *(job->r1H1ptr + (here->DIOnegNode)); + i1h1x = *(job->i1H1ptr + (here->DIOposPrimeNode)) - + *(job->i1H1ptr + (here->DIOnegNode)); + + /* formulae start here */ + + temp = D1n2F1(g2,r1h1x,i1h1x); + itemp = D1i2F1(g2,r1h1x,i1h1x); + + /* the above are for the memoryless nonlinearity */ + + if ((cdiff2 + cjunc2) != 0.0) { + temp += - ckt->CKTomega * D1i2F1 + (cdiff2+cjunc2,r1h1x,i1h1x); + itemp += ckt->CKTomega * D1n2F1 + ((cdiff2 + cjunc2),r1h1x,i1h1x); + } + + *(ckt->CKTrhs + (here->DIOposPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->DIOposPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->DIOnegNode)) += temp; + *(ckt->CKTirhs + (here->DIOnegNode)) += itemp; + break; + + case D_THRF1: + g2=here->id_x2; + g3=here->id_x3; + + cdiff2=here->cdif_x2; + cdiff3=here->cdif_x3; + + cjunc2=here->cjnc_x2; + cjunc3=here->cjnc_x3; + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->DIOposPrimeNode)) - + *(job->r1H1ptr + (here->DIOnegNode)); + i1h1x = *(job->i1H1ptr + (here->DIOposPrimeNode)) - + *(job->i1H1ptr + (here->DIOnegNode)); + + /* getting second order kernel at (F1_F1) */ + r2h11x = *(job->r2H11ptr + (here->DIOposPrimeNode)) - + *(job->r2H11ptr + (here->DIOnegNode)); + i2h11x = *(job->i2H11ptr + (here->DIOposPrimeNode)) - + *(job->i2H11ptr + (here->DIOnegNode)); + + /* formulae start here */ + + temp = D1n3F1(g2,g3,r1h1x,i1h1x,r2h11x, + i2h11x); + itemp = D1i3F1(g2,g3,r1h1x,i1h1x,r2h11x, + i2h11x); + + /* the above are for the memoryless nonlinearity */ + /* the following are for the capacitors */ + + if ((cdiff2 + cjunc2) != 0.0) { + temp += -ckt->CKTomega * D1i3F1 + (cdiff2+cjunc2,cdiff3+cjunc3,r1h1x, + i1h1x,r2h11x,i2h11x); + + itemp += ckt->CKTomega * D1n3F1 + (cdiff2+cjunc2,cdiff3+cjunc3,r1h1x, + i1h1x,r2h11x,i2h11x); + } + + /* end of formulae */ + + *(ckt->CKTrhs + (here->DIOposPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->DIOposPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->DIOnegNode)) += temp; + *(ckt->CKTirhs + (here->DIOnegNode)) += itemp; + + + break; + case D_F1PF2: + g2=here->id_x2; + g3=here->id_x3; + + cdiff2=here->cdif_x2; + cdiff3=here->cdif_x3; + + cjunc2=here->cjnc_x2; + cjunc3=here->cjnc_x3; + + /* getting first order (linear) Volterra kernel for F1*/ + r1h1x = *(job->r1H1ptr + (here->DIOposPrimeNode)) - + *(job->r1H1ptr + (here->DIOnegNode)); + i1h1x = *(job->i1H1ptr + (here->DIOposPrimeNode)) - + *(job->i1H1ptr + (here->DIOnegNode)); + + /* getting first order (linear) Volterra kernel for F2*/ + r1h2x = *(job->r1H2ptr + (here->DIOposPrimeNode)) - + *(job->r1H2ptr + (here->DIOnegNode)); + i1h2x = *(job->i1H2ptr + (here->DIOposPrimeNode)) - + *(job->i1H2ptr + (here->DIOnegNode)); + + /* formulae start here */ + + temp = D1nF12(g2,r1h1x,i1h1x,r1h2x,i1h2x); + itemp = D1iF12(g2,r1h1x,i1h1x,r1h2x,i1h2x); + + /* the above are for the memoryless nonlinearity */ + /* the following are for the capacitors */ + + if ((cdiff2 + cjunc2) != 0.0) { + temp += - ckt->CKTomega * D1iF12 + (cdiff2+cjunc2,r1h1x,i1h1x,r1h2x,i1h2x); + itemp += ckt->CKTomega * D1nF12 + (cdiff2+cjunc2,r1h1x,i1h1x,r1h2x,i1h2x); + } + + /* end of formulae */ + + *(ckt->CKTrhs + (here->DIOposPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->DIOposPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->DIOnegNode)) += temp; + *(ckt->CKTirhs + (here->DIOnegNode)) += itemp; + + + break; + case D_F1MF2: + g2=here->id_x2; + g3=here->id_x3; + + cdiff2=here->cdif_x2; + cdiff3=here->cdif_x3; + + cjunc2=here->cjnc_x2; + cjunc3=here->cjnc_x3; + + /* getting first order (linear) Volterra kernel for F1*/ + r1h1x = *(job->r1H1ptr + (here->DIOposPrimeNode)) - + *(job->r1H1ptr + (here->DIOnegNode)); + i1h1x = *(job->i1H1ptr + (here->DIOposPrimeNode)) - + *(job->i1H1ptr + (here->DIOnegNode)); + + /* getting first order (linear) Volterra kernel for F2*/ + r1h2x = *(job->r1H2ptr + (here->DIOposPrimeNode)) - + *(job->r1H2ptr + (here->DIOnegNode)); + i1hm2x = -(*(job->i1H2ptr + (here->DIOposPrimeNode)) - + *(job->i1H2ptr + (here->DIOnegNode))); + + /* formulae start here */ + + temp = D1nF12(g2,r1h1x,i1h1x,r1h2x,i1hm2x); + itemp = D1iF12(g2,r1h1x,i1h1x,r1h2x,i1hm2x); + + /* the above are for the memoryless nonlinearity */ + /* the following are for the capacitors */ + + if ((cdiff2 + cjunc2) != 0.0) { + temp += - ckt->CKTomega * D1iF12 + (cdiff2+cjunc2,r1h1x,i1h1x,r1h2x,i1hm2x); + itemp += ckt->CKTomega * D1nF12 + (cdiff2+cjunc2,r1h1x,i1h1x,r1h2x,i1hm2x); + } + + /* end of formulae */ + + *(ckt->CKTrhs + (here->DIOposPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->DIOposPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->DIOnegNode)) += temp; + *(ckt->CKTirhs + (here->DIOnegNode)) += itemp; + + + break; + case D_2F1MF2: + g2=here->id_x2; + g3=here->id_x3; + + cdiff2=here->cdif_x2; + cdiff3=here->cdif_x3; + + cjunc2=here->cjnc_x2; + cjunc3=here->cjnc_x3; + + /* getting first order (linear) Volterra kernel at F1*/ + r1h1x = *(job->r1H1ptr + (here->DIOposPrimeNode)) - + *(job->r1H1ptr + (here->DIOnegNode)); + i1h1x = *(job->i1H1ptr + (here->DIOposPrimeNode)) - + *(job->i1H1ptr + (here->DIOnegNode)); + + /* getting first order (linear) Volterra kernel at minusF2*/ + r1h2x = *(job->r1H2ptr + (here->DIOposPrimeNode)) - + *(job->r1H2ptr + (here->DIOnegNode)); + i1hm2x = -(*(job->i1H2ptr + (here->DIOposPrimeNode)) - + *(job->i1H2ptr + (here->DIOnegNode))); + + /* getting second order kernel at (F1_F1) */ + r2h11x = *(job->r2H11ptr + (here->DIOposPrimeNode)) - + *(job->r2H11ptr + (here->DIOnegNode)); + i2h11x = *(job->i2H11ptr + (here->DIOposPrimeNode)) - + *(job->i2H11ptr + (here->DIOnegNode)); + + /* getting second order kernel at (F1_minusF2) */ + r2h1m2x = *(job->r2H1m2ptr + (here->DIOposPrimeNode)) - + *(job->r2H1m2ptr + (here->DIOnegNode)); + i2h1m2x = *(job->i2H1m2ptr + (here->DIOposPrimeNode)) - + *(job->i2H1m2ptr + (here->DIOnegNode)); + + /* formulae start here */ + + temp = D1n2F12(g2,g3,r1h1x,i1h1x,r1h2x, + i1hm2x,r2h11x,i2h11x, + r2h1m2x,i2h1m2x); + itemp = D1i2F12(g2,g3,r1h1x,i1h1x, + r1h2x,i1hm2x,r2h11x,i2h11x, + r2h1m2x,i2h1m2x); + + + /* the above are for the memoryless nonlinearity */ + /* the following are for the capacitors */ + + if ((cdiff2 + cjunc2) != 0.0) { + temp += -ckt->CKTomega * + D1i2F12(cdiff2+cjunc2,cdiff3+cjunc3, + r1h1x,i1h1x,r1h2x,i1hm2x,r2h11x, + i2h11x,r2h1m2x,i2h1m2x); + itemp += ckt->CKTomega * + D1n2F12(cdiff2+cjunc2,cdiff3+cjunc3, + r1h1x,i1h1x,r1h2x,i1hm2x,r2h11x, + i2h11x,r2h1m2x,i2h1m2x); + } + + + /* end of formulae */ + + *(ckt->CKTrhs + (here->DIOposPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->DIOposPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->DIOnegNode)) += temp; + *(ckt->CKTirhs + (here->DIOnegNode)) += itemp; + + + break; + default: +; + } + } +} +return(OK); +} + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/dio/diodset.c b/src/spicelib/devices/dio/diodset.c new file mode 100644 index 000000000..d1dc69670 --- /dev/null +++ b/src/spicelib/devices/dio/diodset.c @@ -0,0 +1,137 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "diodefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +DIOdSetup(model,ckt) + +register DIOmodel *model; +CKTcircuit *ckt; +/* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register DIOinstance *here; + double arg; + double csat; /* area-scaled saturation current */ + double czero; + double czof2; + double evd; + double evrev; + double gd; + double sarg; + double vd; /* current diode voltage */ + double vt; /* K t / Q */ + double vte; + double g2,g3; + double cdiff2,cdiff3; + double cjunc1,cjunc2,cjunc3; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + /* + * this routine loads diodes for dc and transient analyses. + */ + + + + + csat=here->DIOtSatCur*here->DIOarea; + vt = CONSTKoverQ * here->DIOtemp; + vte=model->DIOemissionCoeff * vt; + vd = *(ckt->CKTrhsOld + (here->DIOposPrimeNode)) - + *(ckt->CKTrhsOld + (here->DIOnegNode)); + + /* + * compute derivatives + */ + if (vd >= -5*vte) { + evd = exp(vd/vte); + gd = csat*evd/vte+ckt->CKTgmin; + g2 = 0.5*(gd-ckt->CKTgmin)/vte; + cdiff2 = g2*model->DIOtransitTime; + g3 = g2/3/vte; + cdiff3 = g3*model->DIOtransitTime; + } + else if((!(here->DIOtBrkdwnV))|| + (vd >= -here->DIOtBrkdwnV)) { + gd = -csat/vd+ckt->CKTgmin; + g2=g3=cdiff2=cdiff3=0.0; + /* off */ + } + else { + /* reverse breakdown */ + /* why using csat instead of breakdowncurrent? */ + evrev=exp(-(here->DIOtBrkdwnV+vd)/vt); + /* + cd = -csat*(evrev-1+here->DIOtBrkdwnV/vt); + */ + /* should there be a minus here above? */ + gd=csat*evrev/vt; + g2 = -gd/2/vt; + g3 = -g2/3/vt; + cdiff3 = cdiff2 = 0; + } + /* + * junction charge storage elements + */ + czero=here->DIOtJctCap*here->DIOarea; + if (czero != 0.0) { + if (vd < here->DIOtDepCap){ + arg=1-vd/model->DIOjunctionPot; + sarg=exp(-model->DIOgradingCoeff*log(arg)); + /* the expression for depletion charge + model->DIOjunctionPot*czero* + (1-arg*sarg)/(1-model->DIOgradingCoeff); + */ + cjunc1 = czero*sarg; + cjunc2 = cjunc1/2/model->DIOjunctionPot*model->DIOgradingCoeff/arg; + cjunc3 = cjunc2/3/model->DIOjunctionPot/arg*(model->DIOgradingCoeff + 1); + } + else { + czof2=czero/model->DIOf2; + /* depletion charge equation + czero*here->DIOtF1+czof2* + (model->DIOf3*(vd-here->DIOtDepCap)+ + (model->DIOgradingCoeff/(model->DIOjunctionPot+ + model->DIOjunctionPot))*(vd*vd-here->DIOtDepCap* + here->DIOtDepCap)); + */ + cjunc2 = czof2/2/model->DIOjunctionPot*model->DIOgradingCoeff; + cjunc3 =0.0; + } + } + else + { + cjunc1 = cjunc2 = cjunc3 = 0.0; + } + + /* + * store small-signal parameters + */ + + here->id_x2 = g2; + here->id_x3 = g3; + here->cdif_x2 = cdiff2; + here->cdif_x3 = cdiff3; + here->cjnc_x2 = cjunc2; + here->cjnc_x3 = cjunc3; + } + } + return(OK); +} diff --git a/src/spicelib/devices/dio/dioext.h b/src/spicelib/devices/dio/dioext.h new file mode 100644 index 000000000..eb2f91926 --- /dev/null +++ b/src/spicelib/devices/dio/dioext.h @@ -0,0 +1,58 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ + +extern int DIOacLoad(GENmodel*,CKTcircuit*); +extern int DIOask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int DIOconvTest(GENmodel *,CKTcircuit*); +extern int DIOdelete(GENmodel*,IFuid,GENinstance**); +extern void DIOdestroy(GENmodel**); +extern int DIOgetic(GENmodel*,CKTcircuit*); +extern int DIOload(GENmodel*,CKTcircuit*); +extern int DIOmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int DIOmDelete(GENmodel**,IFuid,GENmodel*); +extern int DIOmParam(int,IFvalue*,GENmodel*); +extern int DIOparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int DIOpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int DIOsAcLoad(GENmodel*,CKTcircuit*); +extern int DIOsLoad(GENmodel*,CKTcircuit*); +extern int DIOsSetup(SENstruct*,GENmodel*); +extern void DIOsPrint(GENmodel*,CKTcircuit*); +extern int DIOsUpdate(GENmodel*,CKTcircuit*); +extern int DIOsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int DIOunsetup(GENmodel*,CKTcircuit*); +extern int DIOtemp(GENmodel*,CKTcircuit*); +extern int DIOtrunc(GENmodel*,CKTcircuit*,double*); +extern int DIOdisto(int,GENmodel*,CKTcircuit*); +extern int DIOnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ + +extern int DIOacLoad(); +extern int DIOask(); +extern int DIOconvTest(); +extern int DIOdelete(); +extern void DIOdestroy(); +extern int DIOgetic(); +extern int DIOload(); +extern int DIOmAsk(); +extern int DIOmDelete(); +extern int DIOmParam(); +extern int DIOparam(); +extern int DIOpzLoad(); +extern int DIOsAcLoad(); +extern int DIOsLoad(); +extern int DIOsSetup(); +extern void DIOsPrint(); +extern int DIOsUpdate(); +extern int DIOsetup(); +extern int DIOunsetup(); +extern int DIOtemp(); +extern int DIOtrunc(); +extern int DIOdisto(); +extern int DIOnoise(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/dio/diogetic.c b/src/spicelib/devices/dio/diogetic.c new file mode 100644 index 000000000..ccf539e5e --- /dev/null +++ b/src/spicelib/devices/dio/diogetic.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOgetic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + DIOmodel *model = (DIOmodel*)inModel; + DIOinstance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->DIOnextModel) { + for(here = model->DIOinstances; here ; here = here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + if(!here->DIOinitCondGiven) { + here->DIOinitCond = + *(ckt->CKTrhs + here->DIOposNode) - + *(ckt->CKTrhs + here->DIOnegNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/dio/dioitf.h b/src/spicelib/devices/dio/dioitf.h new file mode 100644 index 000000000..b3f083ff2 --- /dev/null +++ b/src/spicelib/devices/dio/dioitf.h @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_dio + +#ifndef DEV_DIO +#define DEV_DIO + +#include "dioext.h" +extern IFparm DIOpTable[ ]; +extern IFparm DIOmPTable[ ]; +extern char *DIOnames[ ]; +extern int DIOpTSize; +extern int DIOmPTSize; +extern int DIOnSize; +extern int DIOiSize; +extern int DIOmSize; + +SPICEdev DIOinfo = { + { + "Diode", + "Junction Diode model", + + &DIOnSize, + &DIOnSize, + DIOnames, + + &DIOpTSize, + DIOpTable, + + &DIOmPTSize, + DIOmPTable, + DEV_DEFAULT + }, + + DIOparam, + DIOmParam, + DIOload, + DIOsetup, + DIOunsetup, + DIOsetup, + DIOtemp, + DIOtrunc, + NULL, + DIOacLoad, + NULL, + DIOdestroy, +#ifdef DELETES + DIOmDelete, + DIOdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + DIOgetic, + DIOask, + DIOmAsk, +#ifdef AN_pz + DIOpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + DIOconvTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + +#ifdef AN_sense2 + DIOsSetup, + DIOsLoad, + DIOsUpdate, + DIOsAcLoad, + DIOsPrint, + NULL, +#else /* AN_sense */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense */ +#ifdef AN_disto + DIOdisto, +#else /* AN_disto */ + NULL, +#endif /* AN_disto */ +#ifdef AN_noise + DIOnoise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &DIOiSize, + &DIOmSize + + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/dio/dioload.c b/src/spicelib/devices/dio/dioload.c new file mode 100644 index 000000000..497dc30c0 --- /dev/null +++ b/src/spicelib/devices/dio/dioload.c @@ -0,0 +1,314 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "const.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +DIOload(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + double arg; + double capd; + double cd; + double cdeq; + double cdhat; + double ceq; + double csat; /* area-scaled saturation current */ + double czero; + double czof2; + double delvd; /* change in diode voltage temporary */ + double evd; + double evrev; + double gd; + double geq; + double gspr; /* area-scaled conductance */ + double sarg; + double tol; /* temporary for tolerence calculations */ + double vd; /* current diode voltage */ + double vdtemp; + double vt; /* K t / Q */ + double vte; + int Check; + int error; + int SenCond=0; /* sensitivity condition */ + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + /* + * this routine loads diodes for dc and transient analyses. + */ + + + if(ckt->CKTsenInfo){ + if((ckt->CKTsenInfo->SENstatus == PERTURBATION) + && (here->DIOsenPertFlag == OFF))continue; + SenCond = here->DIOsenPertFlag; + +#ifdef SENSDEBUG + printf("DIOload \n"); +#endif /* SENSDEBUG */ + + } + + csat=here->DIOtSatCur*here->DIOarea; + gspr=model->DIOconductance*here->DIOarea; + vt = CONSTKoverQ * here->DIOtemp; + vte=model->DIOemissionCoeff * vt; + /* + * initialization + */ + + if(SenCond){ + +#ifdef SENSDEBUG + printf("DIOsenPertFlag = ON \n"); +#endif /* SENSDEBUG */ + + if((ckt->CKTsenInfo->SENmode == TRANSEN)&& + (ckt->CKTmode & MODEINITTRAN)) { + vd = *(ckt->CKTstate1 + here->DIOvoltage); + } else{ + vd = *(ckt->CKTstate0 + here->DIOvoltage); + } + +#ifdef SENSDEBUG + printf("vd = %.7e \n",vd); +#endif /* SENSDEBUG */ + goto next1; + } + + Check=1; + if(ckt->CKTmode & MODEINITSMSIG) { + vd= *(ckt->CKTstate0 + here->DIOvoltage); + } else if (ckt->CKTmode & MODEINITTRAN) { + vd= *(ckt->CKTstate1 + here->DIOvoltage); + } else if ( (ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC) ) { + vd=here->DIOinitCond; + } else if ( (ckt->CKTmode & MODEINITJCT) && here->DIOoff) { + vd=0; + } else if ( ckt->CKTmode & MODEINITJCT) { + vd=here->DIOtVcrit; + } else if ( ckt->CKTmode & MODEINITFIX && here->DIOoff) { + vd=0; + } else { +#ifndef PREDICTOR + if (ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0 + here->DIOvoltage) = + *(ckt->CKTstate1 + here->DIOvoltage); + vd = DEVpred(ckt,here->DIOvoltage); + *(ckt->CKTstate0 + here->DIOcurrent) = + *(ckt->CKTstate1 + here->DIOcurrent); + *(ckt->CKTstate0 + here->DIOconduct) = + *(ckt->CKTstate1 + here->DIOconduct); + } else { +#endif /* PREDICTOR */ + vd = *(ckt->CKTrhsOld+here->DIOposPrimeNode)- + *(ckt->CKTrhsOld + here->DIOnegNode); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + delvd=vd- *(ckt->CKTstate0 + here->DIOvoltage); + cdhat= *(ckt->CKTstate0 + here->DIOcurrent) + + *(ckt->CKTstate0 + here->DIOconduct) * delvd; + /* + * bypass if solution has not changed + */ +#ifndef NOBYPASS + if ((!(ckt->CKTmode & MODEINITPRED)) && (ckt->CKTbypass)) { + tol=ckt->CKTvoltTol + ckt->CKTreltol* + MAX(fabs(vd),fabs(*(ckt->CKTstate0 +here->DIOvoltage))); + if (fabs(delvd) < tol){ + tol=ckt->CKTreltol* MAX(fabs(cdhat), + fabs(*(ckt->CKTstate0 + here->DIOcurrent)))+ + ckt->CKTabstol; + if (fabs(cdhat- *(ckt->CKTstate0 + here->DIOcurrent)) + < tol) { + vd= *(ckt->CKTstate0 + here->DIOvoltage); + cd= *(ckt->CKTstate0 + here->DIOcurrent); + gd= *(ckt->CKTstate0 + here->DIOconduct); + goto load; + } + } + } +#endif /* NOBYPASS */ + /* + * limit new junction voltage + */ + if ( (model->DIObreakdownVoltageGiven) && + (vd < MIN(0,-here->DIOtBrkdwnV+10*vte))) { + vdtemp = -(vd+here->DIOtBrkdwnV); + vdtemp = DEVpnjlim(vdtemp, + -(*(ckt->CKTstate0 + here->DIOvoltage) + + here->DIOtBrkdwnV),vte, + here->DIOtVcrit,&Check); + vd = -(vdtemp+here->DIOtBrkdwnV); + } else { + vd = DEVpnjlim(vd,*(ckt->CKTstate0 + here->DIOvoltage), + vte,here->DIOtVcrit,&Check); + } + } + /* + * compute dc current and derivitives + */ +next1: if (vd >= -3*vte) { + evd = exp(vd/vte); + cd = csat*(evd-1)+ckt->CKTgmin*vd; + gd = csat*evd/vte+ckt->CKTgmin; + } else if((!(here->DIOtBrkdwnV))|| + vd >= -here->DIOtBrkdwnV) { + arg=3*vte/(vd*CONSTe); + arg = arg * arg * arg; + cd = -csat*(1+arg)+ckt->CKTgmin*vd; + gd = csat*3*arg/vd+ckt->CKTgmin; + } else { + evrev=exp(-(here->DIOtBrkdwnV+vd)/vte); + cd = -csat*evrev+ckt->CKTgmin*vd; + gd=csat*evrev/vte + ckt->CKTgmin; + } + if( ((ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG)) || + (ckt->CKTmode & MODETRANOP)) && (ckt->CKTmode & MODEUIC) ) { + /* + * charge storage elements + */ + czero=here->DIOtJctCap*here->DIOarea; + if (vd < here->DIOtDepCap){ + arg=1-vd/model->DIOjunctionPot; + sarg=exp(-model->DIOgradingCoeff*log(arg)); + *(ckt->CKTstate0 + here->DIOcapCharge) = + model->DIOtransitTime*cd+model->DIOjunctionPot* + czero* (1-arg*sarg)/(1-model->DIOgradingCoeff); + capd=model->DIOtransitTime*gd+czero*sarg; + } else { + czof2=czero/model->DIOf2; + *(ckt->CKTstate0 + here->DIOcapCharge) = + model->DIOtransitTime*cd+czero*here->DIOtF1+czof2* + (model->DIOf3*(vd-here->DIOtDepCap)+ + (model->DIOgradingCoeff/(model->DIOjunctionPot+ + model->DIOjunctionPot))*(vd*vd-here->DIOtDepCap* + here->DIOtDepCap)); + capd=model->DIOtransitTime*gd+czof2*(model->DIOf3+ + model->DIOgradingCoeff*vd/model->DIOjunctionPot); + } + here->DIOcap = capd; + + /* + * store small-signal parameters + */ + if( (!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC)) ) { + if (ckt->CKTmode & MODEINITSMSIG){ + *(ckt->CKTstate0 + here->DIOcapCurrent) = capd; + + if(SenCond){ + *(ckt->CKTstate0 + here->DIOcurrent) = cd; + *(ckt->CKTstate0 + here->DIOconduct) = gd; +#ifdef SENSDEBUG + printf("storing small signal parameters\n"); + printf("cd = %.7e,vd = %.7e\n",cd,vd); + printf("capd = %.7e ,gd = %.7e \n",capd,gd); +#endif /* SENSDEBUG */ + } + continue; + } + + /* + * transient analysis + */ + if(SenCond && (ckt->CKTsenInfo->SENmode == TRANSEN)){ + *(ckt->CKTstate0 + here->DIOcurrent) = cd; +#ifdef SENSDEBUG + printf("storing parameters for transient sensitivity\n" + ); + printf("qd = %.7e, capd = %.7e,cd = %.7e\n", + *(ckt->CKTstate0 + here->DIOcapCharge),capd,cd); +#endif /* SENSDEBUG */ + continue; + } + + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->DIOcapCharge) = + *(ckt->CKTstate0 + here->DIOcapCharge); + } + error = NIintegrate(ckt,&geq,&ceq,capd,here->DIOcapCharge); + if(error) return(error); + gd=gd+geq; + cd=cd+*(ckt->CKTstate0 + here->DIOcapCurrent); + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->DIOcapCurrent) = + *(ckt->CKTstate0 + here->DIOcapCurrent); + } + } + } + + if(SenCond) goto next2; + + /* + * check convergence + */ + if ( (!(ckt->CKTmode & MODEINITFIX)) || (!(here->DIOoff)) ) { + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV + } else { + tol=ckt->CKTreltol* + MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol; + if (fabs(cdhat-cd) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } +#endif /* NEWCONV */ + } + } +next2: *(ckt->CKTstate0 + here->DIOvoltage) = vd; + *(ckt->CKTstate0 + here->DIOcurrent) = cd; + *(ckt->CKTstate0 + here->DIOconduct) = gd; + + if(SenCond) continue; + + + load: + + /* + * load current vector + */ + cdeq=cd-gd*vd; + *(ckt->CKTrhs + here->DIOnegNode) += cdeq; + *(ckt->CKTrhs + here->DIOposPrimeNode) -= cdeq; + /* + * load matrix + */ + *(here->DIOposPosPtr) += gspr; + *(here->DIOnegNegPtr) += gd; + *(here->DIOposPrimePosPrimePtr) += (gd + gspr); + *(here->DIOposPosPrimePtr) -= gspr; + *(here->DIOnegPosPrimePtr) -= gd; + *(here->DIOposPrimePosPtr) -= gspr; + *(here->DIOposPrimeNegPtr) -= gd; + } + } + return(OK); +} diff --git a/src/spicelib/devices/dio/diomask.c b/src/spicelib/devices/dio/diomask.c new file mode 100644 index 000000000..51410ed35 --- /dev/null +++ b/src/spicelib/devices/dio/diomask.c @@ -0,0 +1,80 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "cktdefs.h" +#include "ifsim.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +DIOmAsk (ckt,inModel,which, value) + CKTcircuit *ckt; + int which; + IFvalue *value; + GENmodel *inModel; +{ + DIOmodel *model = (DIOmodel*)inModel; + switch (which) { + case DIO_MOD_IS: + value->rValue = model->DIOsatCur; + return(OK); + case DIO_MOD_TNOM: + value->rValue = model->DIOnomTemp-CONSTCtoK; + return(OK); + case DIO_MOD_RS: + value->rValue = model->DIOresist; + return(OK); + case DIO_MOD_N: + value->rValue = model->DIOemissionCoeff; + return(OK); + case DIO_MOD_TT: + value->rValue = model->DIOtransitTime; + return(OK); + case DIO_MOD_CJO: + value->rValue = model->DIOjunctionCap; + return(OK); + case DIO_MOD_VJ: + value->rValue = model->DIOjunctionPot; + return(OK); + case DIO_MOD_M: + value->rValue = model->DIOgradingCoeff; + return(OK); + case DIO_MOD_EG: + value->rValue = model->DIOactivationEnergy; + return (OK); + case DIO_MOD_XTI: + value->rValue = model->DIOsaturationCurrentExp; + return(OK); + case DIO_MOD_FC: + value->rValue = model->DIOdepletionCapCoeff; + return(OK); + case DIO_MOD_KF: + value->rValue = model->DIOfNcoef; + return(OK); + case DIO_MOD_AF: + value->rValue = model->DIOfNexp; + return(OK); + case DIO_MOD_BV: + value->rValue = model->DIObreakdownVoltage; + return(OK); + case DIO_MOD_IBV: + value->rValue = model->DIObreakdownCurrent; + return(OK); + case DIO_MOD_COND: + value->rValue = model->DIOconductance; + return(OK); + default: + return(E_BADPARM); + } +} + diff --git a/src/spicelib/devices/dio/diomdel.c b/src/spicelib/devices/dio/diomdel.c new file mode 100644 index 000000000..0ab248dc8 --- /dev/null +++ b/src/spicelib/devices/dio/diomdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + DIOmodel **model = (DIOmodel**)inModel; + DIOmodel *modfast = (DIOmodel*)kill; + DIOinstance *here; + DIOinstance *prev = NULL; + DIOmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->DIOnextModel)) { + if( (*model)->DIOmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->DIOnextModel; /* cut deleted device out of list */ + for(here = (*model)->DIOinstances ; here ; here = here->DIOnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/dio/diompar.c b/src/spicelib/devices/dio/diompar.c new file mode 100644 index 000000000..e8cf88f96 --- /dev/null +++ b/src/spicelib/devices/dio/diompar.c @@ -0,0 +1,93 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOmParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + DIOmodel *model = (DIOmodel*)inModel; + switch(param) { + case DIO_MOD_IS: + model->DIOsatCur = value->rValue; + model->DIOsatCurGiven = TRUE; + break; + case DIO_MOD_TNOM: + model->DIOnomTemp = value->rValue+CONSTCtoK; + model->DIOnomTempGiven = TRUE; + break; + case DIO_MOD_RS: + model->DIOresist = value->rValue; + model->DIOresistGiven = TRUE; + break; + case DIO_MOD_N: + model->DIOemissionCoeff = value->rValue; + model->DIOemissionCoeffGiven = TRUE; + break; + case DIO_MOD_TT: + model->DIOtransitTime = value->rValue; + model->DIOtransitTimeGiven = TRUE; + break; + case DIO_MOD_CJO: + model->DIOjunctionCap = value->rValue; + model->DIOjunctionCapGiven = TRUE; + break; + case DIO_MOD_VJ: + model->DIOjunctionPot = value->rValue; + model->DIOjunctionPotGiven = TRUE; + break; + case DIO_MOD_M: + model->DIOgradingCoeff = value->rValue; + model->DIOgradingCoeffGiven = TRUE; + break; + case DIO_MOD_EG: + model->DIOactivationEnergy = value->rValue; + model->DIOactivationEnergyGiven = TRUE; + break; + case DIO_MOD_XTI: + model->DIOsaturationCurrentExp = value->rValue; + model->DIOsaturationCurrentExpGiven = TRUE; + break; + case DIO_MOD_FC: + model->DIOdepletionCapCoeff = value->rValue; + model->DIOdepletionCapCoeffGiven = TRUE; + break; + case DIO_MOD_BV: + model->DIObreakdownVoltage = value->rValue; + model->DIObreakdownVoltageGiven = TRUE; + break; + case DIO_MOD_IBV: + model->DIObreakdownCurrent = value->rValue; + model->DIObreakdownCurrentGiven = TRUE; + break; + case DIO_MOD_D: + /* no action - we already know we are a diode, but this */ + /* makes life easier for spice-2 like parsers */ + break; + case DIO_MOD_KF: + model->DIOfNcoef = value->rValue; + model->DIOfNcoefGiven = TRUE; + break; + case DIO_MOD_AF: + model->DIOfNexp = value->rValue; + model->DIOfNexpGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/dio/dionoise.c b/src/spicelib/devices/dio/dionoise.c new file mode 100644 index 000000000..83a3dafae --- /dev/null +++ b/src/spicelib/devices/dio/dionoise.c @@ -0,0 +1,214 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "diodefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * DIOnoise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with diodes. It starts with the model *firstModel and + * traverses all of its instancess. It then proceeds to any other + * models on the linked list. The total output noise density + * generated by all of the diodes is summed with the variable + * "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +DIOnoise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + DIOmodel *firstModel = (DIOmodel *) genmodel; + register DIOmodel *model; + register DIOinstance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[DIONSRCS]; + double lnNdens[DIONSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *DIOnNames[DIONSRCS] = { /* Note that we have to keep the order */ + "_rs", /* noise due to rs */ /* consistent with thestrchr definitions */ + "_id", /* noise due to id */ /* in DIOdefs.h */ + "_1overf", /* flicker (1/f) noise */ + "" /* total diode noise */ + }; + + for (model=firstModel; model != NULL; model=model->DIOnextModel) { + for (inst=model->DIOinstances; inst != NULL; inst=inst->DIOnextInstance) { + if (inst->DIOowner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < DIONSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->DIOname,DIOnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + } + break; + + case INT_NOIZ: + for (i=0; i < DIONSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->DIOname,DIOnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->DIOname,DIOnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[DIORSNOIZ],&lnNdens[DIORSNOIZ], + ckt,THERMNOISE,inst->DIOposPrimeNode,inst->DIOposNode, + model->DIOconductance * inst->DIOarea); + + NevalSrc(&noizDens[DIOIDNOIZ],&lnNdens[DIOIDNOIZ], + ckt,SHOTNOISE,inst->DIOposPrimeNode, inst->DIOnegNode, + *(ckt->CKTstate0 + inst->DIOcurrent)); + + NevalSrc(&noizDens[DIOFLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->DIOposPrimeNode, inst->DIOnegNode, + (double)0.0); + noizDens[DIOFLNOIZ] *= model->DIOfNcoef * + exp(model->DIOfNexp * + log(MAX(fabs(*(ckt->CKTstate0 + inst->DIOcurrent)),N_MINLOG))) / + data->freq; + lnNdens[DIOFLNOIZ] = + log(MAX(noizDens[DIOFLNOIZ],N_MINLOG)); + + noizDens[DIOTOTNOIZ] = noizDens[DIORSNOIZ] + + noizDens[DIOIDNOIZ] + + noizDens[DIOFLNOIZ]; + lnNdens[DIOTOTNOIZ] = + log(MAX(noizDens[DIOTOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[DIOTOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < DIONSRCS; i++) { + inst->DIOnVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < DIONSRCS; i++) { + inst->DIOnVar[OUTNOIZ][i] = 0.0; + inst->DIOnVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + +/* To insure accurracy, we have to integrate each component separately */ + + for (i=0; i < DIONSRCS; i++) { + if (i != DIOTOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->DIOnVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->DIOnVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->DIOnVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->DIOnVar[OUTNOIZ][i] += tempOnoise; + inst->DIOnVar[OUTNOIZ][DIOTOTNOIZ] += tempOnoise; + inst->DIOnVar[INNOIZ][i] += tempInoise; + inst->DIOnVar[INNOIZ][DIOTOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < DIONSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < DIONSRCS; i++) { + data->outpVector[data->outNumber++] = inst->DIOnVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->DIOnVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} + + diff --git a/src/spicelib/devices/dio/dioparam.c b/src/spicelib/devices/dio/dioparam.c new file mode 100644 index 000000000..a34222efd --- /dev/null +++ b/src/spicelib/devices/dio/dioparam.c @@ -0,0 +1,48 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +DIOparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + DIOinstance *here = (DIOinstance*)inst; + switch(param) { + case DIO_AREA: + here->DIOarea = value->rValue; + here->DIOareaGiven = TRUE; + break; + case DIO_TEMP: + here->DIOtemp = value->rValue+CONSTCtoK; + here->DIOtempGiven = TRUE; + break; + case DIO_OFF: + here->DIOoff = value->iValue; + break; + case DIO_IC: + here->DIOinitCond = value->rValue; + break; + case DIO_AREA_SENS: + here->DIOsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/dio/diopzld.c b/src/spicelib/devices/dio/diopzld.c new file mode 100644 index 000000000..1a9f4a6e9 --- /dev/null +++ b/src/spicelib/devices/dio/diopzld.c @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "diodefs.h" +#include "suffix.h" + + +int +DIOpzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; +{ + register DIOmodel *model = (DIOmodel*)inModel; + double gspr; + double geq; + double xceq; + register DIOinstance *here; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + gspr=model->DIOresist*here->DIOarea; + geq= *(ckt->CKTstate0 + here->DIOconduct); + xceq= *(ckt->CKTstate0 + here->DIOcapCurrent); + *(here->DIOposPosPtr ) += gspr; + *(here->DIOnegNegPtr ) += geq + xceq * s->real; + *(here->DIOnegNegPtr +1 ) += xceq * s->imag; + *(here->DIOposPrimePosPrimePtr ) += geq + gspr + xceq * s->real; + *(here->DIOposPrimePosPrimePtr +1 ) += xceq * s->imag; + *(here->DIOposPosPrimePtr ) -= gspr; + *(here->DIOnegPosPrimePtr ) -= geq + xceq * s->real; + *(here->DIOnegPosPrimePtr +1 ) -= xceq * s->imag; + *(here->DIOposPrimePosPtr ) -= gspr; + *(here->DIOposPrimeNegPtr ) -= geq + xceq * s->real; + *(here->DIOposPrimeNegPtr +1 ) -= xceq * s->imag; + } + } + return(OK); + +} diff --git a/src/spicelib/devices/dio/diosacl.c b/src/spicelib/devices/dio/diosacl.c new file mode 100644 index 000000000..cef623b93 --- /dev/null +++ b/src/spicelib/devices/dio/diosacl.c @@ -0,0 +1,284 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "const.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOsAcLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + double SaveState[5]; + int error; + int i; + int iparmno; + int flag; + double A0; + double DELA; + double Apert; + double DELAinv; + double vte; + double gspr0; + double geq0; + double xceq0; + double vspr; + double ivspr; + double vd; + double ivd; + double vdOp; + double gspr; + double geq; + double xceq; + double cspr; + double icspr; + double cd; + double icd; + double cpos0; + double icpos0; + double cpos; + double icpos; + double cposprm0; + double icposprm0; + double cposprm; + double icposprm; + double cneg0; + double icneg0; + double cneg; + double icneg; + double DvdDp; + SENstruct *info; + +#ifdef SENSDEBUG + printf("DIOsenacload\n"); +#endif /* SENSDEBUG */ + + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + /* loop through all the models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 4; i++) { + *(SaveState + i) = *(ckt->CKTstate0 + here->DIOstate + i); + } + vspr = *(ckt->CKTrhsOld + here->DIOposNode) + - *(ckt->CKTrhsOld + here->DIOposPrimeNode) ; + ivspr = *(ckt->CKTirhsOld + here->DIOposNode) + - *(ckt->CKTirhsOld + here->DIOposPrimeNode) ; + vd = *(ckt->CKTrhsOld + here->DIOposPrimeNode) + - *(ckt->CKTrhsOld + here->DIOnegNode) ; + ivd = *(ckt->CKTirhsOld + here->DIOposPrimeNode) + - *(ckt->CKTirhsOld + here->DIOnegNode) ; + vdOp = *(ckt->CKTrhsOp + here->DIOposPrimeNode) + - *(ckt->CKTrhsOp + here->DIOnegNode); + + /* without perturbation */ +#ifdef SENSDEBUG + printf("without perturbation \n"); +#endif /* SENSDEBUG */ + *(ckt->CKTstate0 + here->DIOvoltage) = vdOp; + + here->DIOsenPertFlag = ON; + if(info->SENacpertflag == 1){ + if ((error = DIOload((GENmodel*)model,ckt))) + return(error); + + *(here->DIOsenGeq) = *(ckt->CKTstate0 + here->DIOconduct); + *(here->DIOsenCeq) = *(ckt->CKTstate0 + here->DIOcapCurrent); + } + geq0 = *(here->DIOsenGeq); + xceq0 = *(here->DIOsenCeq) * ckt->CKTomega; + A0 = here->DIOarea; + gspr0=model->DIOconductance*A0; + cpos0 = gspr0 * vspr; + icpos0 = gspr0 * ivspr; + cposprm0 = geq0 * vd - xceq0 * ivd - cpos0; + icposprm0 = geq0 * ivd + xceq0 * vd - icpos0; + cneg0 = - geq0 * vd + xceq0 * ivd; + icneg0 = - geq0 * ivd - xceq0 * vd; + + +#ifdef SENSDEBUG + printf("gspr0 = %.7e , geq0 = %.7e ,xceq0 = %.7e\n", + gspr0 ,geq0,xceq0); + printf("cpos0 = %.7e + j%.7e , cneg0 = %.7e + j%.7e\n", + cpos0,icpos0,cneg0,icneg0); +#endif /* SENSDEBUG */ + /* Perturbation of Area */ + +#ifdef SENSDEBUG + printf("Perturbation of Area\n"); +#endif /* SENSDEBUG */ + if(here->DIOsenParmNo == 0) goto pertvd; + + DELA = info->SENpertfac * A0; + Apert = A0 + DELA; + DELAinv = 1.0/DELA; + if(info->SENacpertflag == 1){ + here->DIOarea = Apert; + *(ckt->CKTstate0 + here->DIOvoltage) = vdOp; + if ((error = DIOload((GENmodel*)model,ckt))) + return(error); + + *(here->DIOsenGeq + 1) = *(ckt->CKTstate0 + here->DIOconduct); + *(here->DIOsenCeq + 1)= *(ckt->CKTstate0 + here->DIOcapCurrent); + here->DIOarea = A0; + } + gspr=model->DIOconductance*Apert; + geq = *(here->DIOsenGeq + 1); + xceq = *(here->DIOsenCeq + 1) * ckt->CKTomega; + flag = 0; + goto load; + +pertvd: /* Perturbation of Diode Voltage */ +#ifdef SENSDEBUG + printf("Perturbation of vd\n"); +#endif /* SENSDEBUG */ + + vte=model->DIOemissionCoeff * CONSTKoverQ * here->DIOtemp; + A0 = vdOp; + DELA = info->SENpertfac * vte; + Apert = A0 + DELA; + DELAinv = 1.0/DELA; + + + if(info->SENacpertflag == 1){ + *(ckt->CKTstate0 + here->DIOvoltage) = Apert; + if ((error = DIOload((GENmodel*)model,ckt))) + return(error); + + *(here->DIOsenGeq + 2) = *(ckt->CKTstate0 + here->DIOconduct); + *(here->DIOsenCeq + 2)= *(ckt->CKTstate0 + here->DIOcapCurrent); + *(ckt->CKTstate0 + here->DIOvoltage) = A0; + } + gspr=model->DIOconductance*here->DIOarea; + geq = *(here->DIOsenGeq + 2); + xceq = *(here->DIOsenCeq + 2) * ckt->CKTomega; + + + flag = 1; + +load: + + cspr = gspr * vspr; + icspr = gspr * ivspr; + cd = geq * vd - xceq * ivd; + icd = geq * ivd + xceq * vd; + + cpos = cspr; + icpos = icspr; + cposprm = ( - cspr + cd ); + icposprm = ( - icspr + icd ); + cneg = ( - cd ); + icneg = ( - icd ); + +#ifdef SENSDEBUG + printf("gspr = %.7e , geq = %.7e , xceq = %.7e\n", + gspr,geq,xceq); + printf("cspr = %.7e + j%.7e , cd = %.7e + j%.7e\n", + cspr,icspr,cd,icd); + printf("cpos = %.7e + j%.7e , cposprm = %.7e + j%.7e", + cpos,icpos,cposprm,icposprm); + printf(", cneg = %.7e + %.7e\n",cneg,icneg); + printf("senpprm = %.7e " + ,info->SEN_Sap[here->DIOposPrimeNode][here->DIOsenParmNo]); + printf("senneg = %.7e \n", + info->SEN_Sap[here->DIOnegNode][here->DIOsenParmNo]); + printf("A0 = %.7e , Apert = %.7e ,factor = %.7e\n,vte = %.7e", + A0 ,Apert,DELAinv,vte); +#endif /* SENSDEBUG */ + + + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + /* calculate the DC sensitivities of operating points */ + DvdDp = info->SEN_Sap[here->DIOposPrimeNode][iparmno] + - info->SEN_Sap[here->DIOnegNode][iparmno]; + if(flag == 0){ + if (here->DIOsenParmNo != iparmno) continue; + /* area : so no DC sensitivity term involved */ + DvdDp =1; + } + /* load the RHS matrix */ + + if(here->DIOposNode != here->DIOposPrimeNode){ + /* DcposDp */ + *(info->SEN_RHS[here->DIOposNode] + iparmno) -= + (cpos - cpos0) * DELAinv * DvdDp ; + /* DicposDp */ + *(info->SEN_iRHS[here->DIOposNode] + iparmno) -= + (icpos - icpos0) * DELAinv * DvdDp ; + } + + + + /* DcposprmDp */ + *(info->SEN_RHS[here->DIOposPrimeNode] + iparmno) -= + (cposprm - cposprm0) * DELAinv * DvdDp ; + /* DicposprmDp */ + *(info->SEN_iRHS[here->DIOposPrimeNode] + iparmno) -= + (icposprm - icposprm0) * DELAinv * DvdDp ; + /* DcnegDp */ + *(info->SEN_RHS[here->DIOnegNode] + iparmno) -= + (cneg - cneg0) * DELAinv * DvdDp ; + /* DicnegDp */ + *(info->SEN_iRHS[here->DIOnegNode] + iparmno) -= + (icneg - icneg0) * DELAinv * DvdDp ; + +#ifdef SENSDEBUG + + printf("senpos = %.7e + j%.7e ", + *(info->SEN_RHS[here->DIOposNode] + iparmno), + *(info->SEN_iRHS[here->DIOposNode] + iparmno)); + printf("senposprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->DIOposPrimeNode] + iparmno), + *(info->SEN_iRHS[here->DIOposPrimeNode] + iparmno)); + printf("senneg = %.7e + j%.7e ", + *(info->SEN_RHS[here->DIOnegNode] + iparmno), + *(info->SEN_iRHS[here->DIOnegNode] + iparmno)); + printf("flag = %d ,DvdDp = %.7e ,iparmno = %d,senparmno = %d\n" + ,flag,DvdDp,iparmno,here->DIOsenParmNo); + +#endif /* SENSDEBUG */ + } + + if(!flag) goto pertvd; + + /* put the unperturbed values back into the state vector */ + for(i=0; i <= 4; i++) { + *(ckt->CKTstate0 + here->DIOstate + i) = *(SaveState + i); + } + here->DIOsenPertFlag = OFF; + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("DIOsenacload end \n"); +#endif /* SENSDEBUG */ + + return(OK); +} + diff --git a/src/spicelib/devices/dio/diosetup.c b/src/spicelib/devices/dio/diosetup.c new file mode 100644 index 000000000..6d201853e --- /dev/null +++ b/src/spicelib/devices/dio/diosetup.c @@ -0,0 +1,138 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* load the diode structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + +int +DIOsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + if(!model->DIOemissionCoeffGiven) { + model->DIOemissionCoeff = 1; + } + if(!model->DIOsatCurGiven) { + model->DIOsatCur = 1e-14; + } + if(!model->DIObreakdownCurrentGiven) { + model->DIObreakdownCurrent = 1e-3; + } + if(!model->DIOjunctionPotGiven){ + model->DIOjunctionPot = 1; + } + if(!model->DIOgradingCoeffGiven) { + model->DIOgradingCoeff = .5; + } + if(!model->DIOdepletionCapCoeffGiven) { + model->DIOdepletionCapCoeff = .5; + } + if(!model->DIOtransitTimeGiven) { + model->DIOtransitTime = 0; + } + if(!model->DIOjunctionCapGiven) { + model->DIOjunctionCap = 0; + } + if(!model->DIOactivationEnergyGiven) { + model->DIOactivationEnergy = 1.11; + } + if(!model->DIOsaturationCurrentExpGiven) { + model->DIOsaturationCurrentExp = 3; + } + if(!model->DIOfNcoefGiven) { + model->DIOfNcoef = 0.0; + } + if(!model->DIOfNexpGiven) { + model->DIOfNexp = 1.0; + } + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) goto matrixpointers; + + if(!here->DIOareaGiven) { + here->DIOarea = 1; + } + + here->DIOstate = *states; + *states += 5; + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ + *states += 2 * (ckt->CKTsenInfo->SENparms); + } + +matrixpointers: + if(model->DIOresist == 0) { + here->DIOposPrimeNode = here->DIOposNode; + } else if(here->DIOposPrimeNode == 0) { + error = CKTmkVolt(ckt,&tmp,here->DIOname,"internal"); + if(error) return(error); + here->DIOposPrimeNode = tmp->number; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(DIOposPosPrimePtr,DIOposNode,DIOposPrimeNode) + TSTALLOC(DIOnegPosPrimePtr,DIOnegNode,DIOposPrimeNode) + TSTALLOC(DIOposPrimePosPtr,DIOposPrimeNode,DIOposNode) + TSTALLOC(DIOposPrimeNegPtr,DIOposPrimeNode,DIOnegNode) + TSTALLOC(DIOposPosPtr,DIOposNode,DIOposNode) + TSTALLOC(DIOnegNegPtr,DIOnegNode,DIOnegNode) + TSTALLOC(DIOposPrimePosPrimePtr,DIOposPrimeNode,DIOposPrimeNode) + } + } + return(OK); +} + +int +DIOunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + DIOmodel *model; + DIOinstance *here; + + for (model = (DIOmodel *)inModel; model != NULL; + model = model->DIOnextModel) + { + for (here = model->DIOinstances; here != NULL; + here=here->DIOnextInstance) + { + + if (here->DIOposPrimeNode + && here->DIOposPrimeNode != here->DIOposNode) + { + CKTdltNNum(ckt, here->DIOposPrimeNode); + here->DIOposPrimeNode = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/dio/diosload.c b/src/spicelib/devices/dio/diosload.c new file mode 100644 index 000000000..937ae39be --- /dev/null +++ b/src/spicelib/devices/dio/diosload.c @@ -0,0 +1,182 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOsLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + int iparmno; + int error; + int i; + double SaveState[6]; + double A0; + double Apert; + double DELA; + double DELAinv; + double cspr0; + double cd0; + double cd; + double qd0; + double qd; + double DcsprDp; + double DcdDp; + double DqdDp; + double tag0; + double tag1; + double Osxp; + SENstruct *info; + + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + + tag0 = ckt->CKTag[0]; + tag1 = ckt->CKTag[1]; + if(ckt->CKTorder == 1){ + tag1 = 0; + } + +#ifdef SENSDEBUG + printf("DIOsenload\n"); + fprintf(file,"DIOsenload\n"); + fprintf(file,"CKTtime = %.5e\n",ckt->CKTtime); + fprintf(file,"CKTorder = %.5e\n",ckt->CKTorder); + fprintf(file,"tag0 = %.5e tag1 = %.5e\n",tag0,tag1); +#endif /* SENSDEBUG */ + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + +#ifdef SENSDEBUG + fprintf(file,"pos = %d , posprm = %d ,neg = %d, senparmno = %d\n", + here->DIOposNode ,here->DIOposPrimeNode,here->DIOnegNode, + here->DIOsenParmNo); +#endif /* SENSDEBUG */ + + + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 4; i++) { + *(SaveState + i) = *(ckt->CKTstate0 + here->DIOstate + i); + } + *(SaveState + 5) = here->DIOcap; + + if(here->DIOsenParmNo == 0) goto next; + + + cspr0 = *(ckt->CKTstate0 + here->DIOcurrent); + here->DIOsenPertFlag = ON; + error = DIOload((GENmodel*)model,ckt); + cd0 = *(ckt->CKTstate0 + here->DIOcurrent); + qd0 = *(ckt->CKTstate0 + here->DIOcapCharge ); + + +#ifdef SENSDEBUG + fprintf(file,"cd0 = %.7e \n",cd0); +#endif /* SENSDEBUG */ + + A0 = here->DIOarea; + DELA = info->SENpertfac * A0; + Apert = A0 + DELA; + DELAinv = 1.0/DELA; + here->DIOarea = Apert; + error = DIOload((GENmodel*)model,ckt); + if(error) return(error); + here->DIOarea = A0; + here->DIOsenPertFlag = OFF; + + cd = *(ckt->CKTstate0 + here->DIOcurrent) ; + qd = *(ckt->CKTstate0 + here->DIOcapCharge); + + DcdDp = (cd -cd0) * DELAinv; + DcsprDp = 0; + if(here->DIOposNode != here->DIOposPrimeNode) { + DcsprDp = cspr0 * info->SENpertfac * DELAinv; + } + DqdDp = (qd - qd0)*DELAinv; + + *(here->DIOdphidp) = DqdDp; + +#ifdef SENSDEBUG + fprintf(file,"cd0 = %.7e ,cd = %.7e,DcdDp=%.7e\n", cd0,cd,DcdDp); + fprintf(file,"cspr0 = %.7e ,DcsprDp=%.7e\n", cspr0,DcsprDp); + fprintf(file,"qd0 = %.7e ,qd = %.7e,DqdDp=%.7e\n", qd0,qd,DqdDp); +#endif /* SENSDEBUG */ + + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)){ + goto restore; + } + + /* + * load RHS matrices + */ + *(info->SEN_RHS[here->DIOposNode] + here->DIOsenParmNo) -= DcsprDp; + *(info->SEN_RHS[here->DIOposPrimeNode] + here->DIOsenParmNo) += + DcsprDp - DcdDp ; + + *(info->SEN_RHS[here->DIOnegNode] + here->DIOsenParmNo) += DcdDp ; +next: + if((info->SENmode == DCSEN)||(ckt->CKTmode&MODETRANOP))goto restore; + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)){ + goto restore; + } + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + Osxp = tag0 * *(ckt->CKTstate1 + here->DIOsensxp + + 2*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->DIOsensxp + + 2*(iparmno - 1) + 1); + +#ifdef SENSDEBUG + fprintf(file,"\n iparmno=%d,Osxp=%.7e\n",iparmno,Osxp); +#endif /* SENSDEBUG */ + + if(iparmno == here->DIOsenParmNo) Osxp = Osxp - tag0 * DqdDp; +#ifdef SENSDEBUG + fprintf(file,"Osxp=%.7e\n",Osxp); +#endif /* SENSDEBUG */ + + *(info->SEN_RHS[here->DIOposPrimeNode] + iparmno) += Osxp; + *(info->SEN_RHS[here->DIOnegNode] + iparmno) -= Osxp; + } + /* put the unperturbed values back into the state vector */ +restore: + for(i=0; i <= 4; i++) { + *(ckt->CKTstate0 + here->DIOstate + i) = *(SaveState + i); + } + here->DIOcap = *(SaveState + 5); + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("DIOsenload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + diff --git a/src/spicelib/devices/dio/diosprt.c b/src/spicelib/devices/dio/diosprt.c new file mode 100644 index 000000000..1db6b8937 --- /dev/null +++ b/src/spicelib/devices/dio/diosprt.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* Pretty print the sensitivity info for all + * the diodes in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +void +DIOsPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + + printf("DIOS-----------------\n"); + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + printf("Model name:%s\n",model->DIOmodName); + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->DIOname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->DIOposNode),CKTnodName(ckt,here->DIOnegNode)); + printf(" Area: %g ",here->DIOarea); + printf(here->DIOareaGiven ? "(specified)\n" : "(default)\n"); + printf(" DIOsenParmNo:%d\n",here->DIOsenParmNo); + + } + } +} diff --git a/src/spicelib/devices/dio/diosset.c b/src/spicelib/devices/dio/diosset.c new file mode 100644 index 000000000..9e6bdaefd --- /dev/null +++ b/src/spicelib/devices/dio/diosset.c @@ -0,0 +1,48 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + + if(here->DIOsenParmNo){ + here->DIOsenParmNo = ++(info->SENparms); + here->DIOsenPertFlag = OFF; + } + if((here->DIOsens = (double *)MALLOC(7*sizeof(double))) + == NULL) return(E_NOMEM); + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/dio/diosupd.c b/src/spicelib/devices/dio/diosupd.c new file mode 100644 index 000000000..9e939408c --- /dev/null +++ b/src/spicelib/devices/dio/diosupd.c @@ -0,0 +1,83 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* update the charge sensitivities and their derivatives */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOsUpdate(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + int iparmno; + double sposprm; + double sneg; + double sxp; + double dummy1; + double dummy2; + SENstruct *info; + + info = ckt->CKTsenInfo; + if(ckt->CKTtime == 0) return(OK); + dummy1=0; + dummy2=0; + +#ifdef SENSDEBUG + printf("DIOsenUpdate\n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); + printf("CKTorder = %.5e\n",ckt->CKTorder); +#endif /* SENSDEBUG */ + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->DIOinstances; here != NULL ; + here=here->DIOnextInstance) { + if (here->DIOowner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("capd = %.7e \n",here->DIOcap); +#endif /* SENSDEBUG */ + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + + sposprm = *(info->SEN_Sap[here->DIOposPrimeNode] + iparmno); + sneg = *(info->SEN_Sap[here->DIOnegNode] + iparmno); + sxp = (sposprm - sneg) * here->DIOcap; + if(iparmno == here->DIOsenParmNo) sxp += *(here->DIOdphidp); + *(ckt->CKTstate0 + here->DIOsensxp + 2 * (iparmno - 1)) = sxp; + NIintegrate(ckt,&dummy1,&dummy2,here->DIOcap, + (here->DIOsensxp + 2 * (iparmno -1 ))); + + if(ckt->CKTmode & MODEINITTRAN){ + *(ckt->CKTstate1 + here->DIOsensxp + 2*(iparmno - 1)) = sxp; + *(ckt->CKTstate1 + here->DIOsensxp + 2*(iparmno - 1)+1) = 0; + } +#ifdef SENSDEBUG + printf("iparmno = %d\n",iparmno); + printf("sposprm = %.7e,sneg = %.7e\n",sposprm,sneg); + printf("sxp = %.7e,sdotxp = %.7e\n", + sxp,*(ckt->CKTstate0 + here->DIOsensxp + + 2*(iparmno - 1) + 1)); +#endif /* SENSDEBUG */ + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/dio/diotemp.c b/src/spicelib/devices/dio/diotemp.c new file mode 100644 index 000000000..d93a90186 --- /dev/null +++ b/src/spicelib/devices/dio/diotemp.c @@ -0,0 +1,160 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* perform the temperature update to the diode */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "diodefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +DIOtemp(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register DIOmodel *model = (DIOmodel*)inModel; + double xfc; + double vte; + double cbv; + double xbv; + double xcbv; + double tol; + double vt; + double vtnom; + register DIOinstance *here; + register int iter; + char *emsg; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->DIOnextModel ) { + if(!model->DIOnomTempGiven) { + model->DIOnomTemp = ckt->CKTnomTemp; + } + vtnom = CONSTKoverQ * model->DIOnomTemp; + /* limit grading coeff to max of .9 */ + if(model->DIOgradingCoeff>.9) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: grading coefficient too large, limited to 0.9", + &(model->DIOmodName)); + model->DIOgradingCoeff=.9; + } + /* limit activation energy to min of .1 */ + if(model->DIOactivationEnergy<.1) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: activation energy too small, limited to 0.1", + &(model->DIOmodName)); + model->DIOactivationEnergy=.1; + } + /* limit depletion cap coeff to max of .95 */ + if(model->DIOdepletionCapCoeff>.95) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: coefficient Fc too large, limited to 0.95", + &(model->DIOmodName)); + model->DIOdepletionCapCoeff=.95; + } + if(!model->DIOresistGiven || model->DIOresist==0) { + model->DIOconductance = 0; + } else { + model->DIOconductance = 1/model->DIOresist; + } + xfc=log(1-model->DIOdepletionCapCoeff); + for(here=model->DIOinstances;here;here=here->DIOnextInstance) { + double egfet1,arg1,fact1,pbfact1,pbo,gmaold; + double fact2,pbfact,arg,egfet,gmanew; + if (here->DIOowner != ARCHme) continue; + + /* loop through all the instances */ + if(!here->DIOtempGiven) here->DIOtemp = ckt->CKTtemp; + vt = CONSTKoverQ * here->DIOtemp; + /* this part gets really ugly - I won't even try to + * explain these equations */ + fact2 = here->DIOtemp/REFTEMP; + egfet = 1.16-(7.02e-4*here->DIOtemp*here->DIOtemp)/ + (here->DIOtemp+1108); + arg = -egfet/(2*CONSTboltz*here->DIOtemp) + + 1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt*(1.5*log(fact2)+CHARGE*arg); + egfet1 = 1.16 - (7.02e-4*model->DIOnomTemp*model->DIOnomTemp)/ + (model->DIOnomTemp+1108); + arg1 = -egfet1/(CONSTboltz*2*model->DIOnomTemp) + + 1.1150877/(2*CONSTboltz*REFTEMP); + fact1 = model->DIOnomTemp/REFTEMP; + pbfact1 = -2 * vtnom*(1.5*log(fact1)+CHARGE*arg1); + pbo = (model->DIOjunctionPot-pbfact1)/fact1; + gmaold = (model->DIOjunctionPot -pbo)/pbo; + here->DIOtJctCap = model->DIOjunctionCap/ + (1+model->DIOgradingCoeff* + (400e-6*(model->DIOnomTemp-REFTEMP)-gmaold) ); + here->DIOtJctPot = pbfact+fact2*pbo; + gmanew = (here->DIOtJctPot-pbo)/pbo; + here->DIOtJctCap *= 1+model->DIOgradingCoeff* + (400e-6*(here->DIOtemp-REFTEMP)-gmanew); + + here->DIOtSatCur = model->DIOsatCur * exp( + ((here->DIOtemp/model->DIOnomTemp)-1) * + model->DIOactivationEnergy/(model->DIOemissionCoeff*vt) + + model->DIOsaturationCurrentExp/model->DIOemissionCoeff* + log(here->DIOtemp/model->DIOnomTemp) ); + /* the defintion of f1, just recompute after temperature adjusting + * all the variables used in it */ + here->DIOtF1=here->DIOtJctPot* + (1-exp((1-model->DIOgradingCoeff)*xfc))/ + (1-model->DIOgradingCoeff); + /* same for Depletion Capacitance */ + here->DIOtDepCap=model->DIOdepletionCapCoeff* + here->DIOtJctPot; + /* and Vcrit */ + vte=model->DIOemissionCoeff*vt; + here->DIOtVcrit=vte*log(vte/(CONSTroot2*here->DIOtSatCur)); + /* and now to copute the breakdown voltage, again, using + * temperature adjusted basic parameters */ + if (model->DIObreakdownVoltageGiven){ + cbv=model->DIObreakdownCurrent; + if (cbv < here->DIOtSatCur*model->DIObreakdownVoltage/vt){ + cbv=here->DIOtSatCur*model->DIObreakdownVoltage/vt; + emsg = MALLOC(100); + if(emsg == (char *)NULL) return(E_NOMEM); + (void)sprintf(emsg, + "%%s: breakdown current increased to %g to resolve incompatability", + cbv); + (*(SPfrontEnd->IFerror))(ERR_WARNING,emsg,&(here->DIOname)); + FREE(emsg); + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "with specified saturation current",(IFuid*)NULL); + xbv=model->DIObreakdownVoltage; + } else { + tol=ckt->CKTreltol*cbv; + xbv=model->DIObreakdownVoltage-vt*log(1+cbv/ + here->DIOtSatCur); + iter=0; + for(iter=0 ; iter < 25 ; iter++) { + xbv=model->DIObreakdownVoltage-vt*log(cbv/ + here->DIOtSatCur+1-xbv/vt); + xcbv=here->DIOtSatCur*(exp((model->DIObreakdownVoltage + -xbv)/vt)-1+xbv/vt); + if (fabs(xcbv-cbv) <= tol) goto matched; + } + emsg = MALLOC(100); + if(emsg == (char *)NULL) return(E_NOMEM); + (void)sprintf(emsg, +"%%s: unable to match forward and reverse diode regions: bv = %g, ibv = %g", + xbv,xcbv); + (*(SPfrontEnd->IFerror))(ERR_WARNING,emsg,&here->DIOname); + FREE(emsg); + } + matched: + here->DIOtBrkdwnV = xbv; + } + } + model->DIOf2=exp((1+model->DIOgradingCoeff)*xfc); + model->DIOf3=1-model->DIOdepletionCapCoeff* + (1+model->DIOgradingCoeff); + } + return(OK); +} diff --git a/src/spicelib/devices/dio/diotrunc.c b/src/spicelib/devices/dio/diotrunc.c new file mode 100644 index 000000000..2e165d78f --- /dev/null +++ b/src/spicelib/devices/dio/diotrunc.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "diodefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +DIOtrunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register DIOmodel *model = (DIOmodel*)inModel; + register DIOinstance *here; + + for( ; model != NULL; model = model->DIOnextModel) { + for(here=model->DIOinstances;here!=NULL;here = here->DIOnextInstance){ + if (here->DIOowner != ARCHme) continue; + CKTterr(here->DIOcapCharge,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/disto/ChangeLog b/src/spicelib/devices/disto/ChangeLog new file mode 100644 index 000000000..b553d15b2 --- /dev/null +++ b/src/spicelib/devices/disto/ChangeLog @@ -0,0 +1,4 @@ +1999-09-08 Arno + + * *.c: reformatted; put prototypes in distodef.h; protoized. + diff --git a/src/spicelib/devices/disto/Makefile.am b/src/spicelib/devices/disto/Makefile.am new file mode 100644 index 000000000..4ee2e40dd --- /dev/null +++ b/src/spicelib/devices/disto/Makefile.am @@ -0,0 +1,23 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libdisto.la + +libdisto_la_SOURCES = \ + atander.c \ + cosderiv.c \ + cubeder.c \ + divderiv.c \ + equalder.c \ + expderiv.c \ + invderiv.c \ + multder.c \ + plusder.c \ + powderiv.c \ + sqrtder.c \ + tanderiv.c \ + timesder.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/disto/atander.c b/src/spicelib/devices/disto/atander.c new file mode 100644 index 000000000..e850004c2 --- /dev/null +++ b/src/spicelib/devices/disto/atander.c @@ -0,0 +1,80 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * AtanDeriv computes the partial derivatives of the arctangent + * function where the argument to the atan function is itself a + * function of three variables p, q, and r. + */ + +void AtanDeriv(Dderivs *new, Dderivs *old) +{ + + Dderivs temp; + + EqualDeriv(&temp, old); + + new->value = atan( temp.value); + new->d1_p = temp.d1_p / (1 + temp.value * temp.value); + new->d1_q = temp.d1_q / (1 + temp.value * temp.value); + new->d1_r = temp.d1_r / (1 + temp.value * temp.value); + new->d2_p2 = temp.d2_p2 / (1 + temp.value * temp.value) - 2 * + temp.value * new->d1_p * new->d1_p; + new->d2_q2 = temp.d2_q2 / (1 + temp.value * temp.value) - 2 * + temp.value * new->d1_q * new->d1_q; + new->d2_r2 = temp.d2_r2 / (1 + temp.value * temp.value) - 2 * + temp.value * new->d1_r * new->d1_r; + new->d2_pq = temp.d2_pq / (1 + temp.value * temp.value) - 2 * + temp.value * new->d1_p * new->d1_q; + new->d2_qr = temp.d2_qr / (1 + temp.value * temp.value) - 2 * + temp.value * new->d1_q * new->d1_r; + new->d2_pr = temp.d2_pr / (1 + temp.value * temp.value) - 2 * + temp.value * new->d1_p * new->d1_r; + new->d3_p3 = (temp.d3_p3 - temp.d2_p2 * new->d1_p * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_p * new->d1_p * temp.d1_p + temp.value * + ( new->d2_p2 * new->d1_p + new->d2_p2 * new->d1_p)); + + new->d3_q3 = (temp.d3_q3 - temp.d2_q2 * new->d1_q * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_q * new->d1_q * temp.d1_q + temp.value * + ( new->d2_q2 * new->d1_q + new->d2_q2 * new->d1_q)); + new->d3_r3 = (temp.d3_r3 - temp.d2_r2 * new->d1_r * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_r * new->d1_r * temp.d1_r + temp.value * + ( new->d2_r2 * new->d1_r + new->d2_r2 * new->d1_r)); + new->d3_p2r = (temp.d3_p2r - temp.d2_p2 * new->d1_r * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_p * new->d1_p * temp.d1_r + temp.value * + ( new->d2_pr * new->d1_p + new->d2_pr * new->d1_p)); + new->d3_p2q = (temp.d3_p2q - temp.d2_p2 * new->d1_q * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_p * new->d1_p * temp.d1_q + temp.value * + ( new->d2_pq * new->d1_p + new->d2_pq * new->d1_p)); + new->d3_q2r = (temp.d3_q2r - temp.d2_q2 * new->d1_r * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_q * new->d1_q * temp.d1_r + temp.value * + ( new->d2_qr * new->d1_q + new->d2_qr * new->d1_q)); + new->d3_pq2 = (temp.d3_pq2 - temp.d2_q2 * new->d1_p * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_q * new->d1_q * temp.d1_p + temp.value * + ( new->d2_pq * new->d1_q + new->d2_pq * new->d1_q)); + new->d3_pr2 = (temp.d3_pr2 - temp.d2_r2 * new->d1_p * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_r * new->d1_r * temp.d1_p + temp.value * + ( new->d2_pr * new->d1_r + new->d2_pr * new->d1_r)); + new->d3_qr2 = (temp.d3_qr2 - temp.d2_r2 * new->d1_q * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_r * new->d1_r * temp.d1_q + temp.value * + ( new->d2_qr * new->d1_r + new->d2_qr * new->d1_r)); + new->d3_pqr = (temp.d3_pqr - temp.d2_pq * new->d1_r * 2 * + temp.value) / (1 + temp.value * temp.value) - 2 * + (new->d1_p * new->d1_q * temp.d1_r + temp.value * + ( new->d2_pr * new->d1_q + new->d2_qr * new->d1_p)); +} diff --git a/src/spicelib/devices/disto/cosderiv.c b/src/spicelib/devices/disto/cosderiv.c new file mode 100644 index 000000000..1c9752619 --- /dev/null +++ b/src/spicelib/devices/disto/cosderiv.c @@ -0,0 +1,87 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * CosDeriv computes the partial derivatives of the cosine + * function where the argument to the function is itself a + * function of three variables p, q, and r. + */ + +void +CosDeriv(Dderivs *new, Dderivs *old) +{ + + Dderivs temp; + + EqualDeriv(&temp, old); + + new->value = cos (temp.value); + new->d1_p = - sin(temp.value)*temp.d1_p; + new->d1_q = - sin(temp.value)*temp.d1_q; + new->d1_r = - sin(temp.value)*temp.d1_r; + new->d2_p2 = -(cos(temp.value)*temp.d1_p*temp.d1_p + + sin(temp.value)*temp.d2_p2); + new->d2_q2 = -(cos(temp.value)*temp.d1_q*temp.d1_q + + sin(temp.value)*temp.d2_q2); + new->d2_r2 = -(cos(temp.value)*temp.d1_r*temp.d1_r + + sin(temp.value)*temp.d2_r2); + new->d2_pq = -(cos(temp.value)*temp.d1_p*temp.d1_q + + sin(temp.value)*temp.d2_pq); + new->d2_qr = -(cos(temp.value)*temp.d1_q*temp.d1_r + + sin(temp.value)*temp.d2_qr); + new->d2_pr = -(cos(temp.value)*temp.d1_p*temp.d1_r + + sin(temp.value)*temp.d2_pr); + new->d3_p3 = -(sin(temp.value)*(temp.d3_p3 - temp.d1_p*temp.d1_p*temp.d1_p) + + cos(temp.value)*(temp.d1_p*temp.d2_p2 + + temp.d1_p*temp.d2_p2 + + temp.d1_p*temp.d2_p2)); + new->d3_q3 = -(sin(temp.value)*(temp.d3_q3 - temp.d1_q*temp.d1_q*temp.d1_q) + + cos(temp.value)*(temp.d1_q*temp.d2_q2 + + temp.d1_q*temp.d2_q2 + + temp.d1_q*temp.d2_q2)); + new->d3_r3 = -(sin(temp.value)*(temp.d3_r3 - temp.d1_r*temp.d1_r*temp.d1_r) + + cos(temp.value)*(temp.d1_r*temp.d2_r2 + + temp.d1_r*temp.d2_r2 + + temp.d1_r*temp.d2_r2)); + new->d3_p2r = -(sin(temp.value)*(temp.d3_p2r - + temp.d1_r*temp.d1_p*temp.d1_p) + + cos(temp.value)*(temp.d1_p*temp.d2_pr + + temp.d1_p*temp.d2_pr + + temp.d1_r*temp.d2_p2)); + new->d3_p2q = -(sin(temp.value)*(temp.d3_p2q - + temp.d1_q*temp.d1_p*temp.d1_p) + + cos(temp.value)*(temp.d1_p*temp.d2_pq + + temp.d1_p*temp.d2_pq + + temp.d1_q*temp.d2_p2)); + new->d3_q2r = -(sin(temp.value)*(temp.d3_q2r - + temp.d1_r*temp.d1_q*temp.d1_q) + + cos(temp.value)*(temp.d1_q*temp.d2_qr + + temp.d1_q*temp.d2_qr + + temp.d1_r*temp.d2_q2)); + new->d3_pq2 = -(sin(temp.value)*(temp.d3_pq2 - + temp.d1_p*temp.d1_q*temp.d1_q) + + cos(temp.value)*(temp.d1_q*temp.d2_pq + + temp.d1_q*temp.d2_pq + + temp.d1_p*temp.d2_q2)); + new->d3_pr2 = -(sin(temp.value)*(temp.d3_pr2 - + temp.d1_p*temp.d1_r*temp.d1_r) + + cos(temp.value)*(temp.d1_r*temp.d2_pr + + temp.d1_r*temp.d2_pr + + temp.d1_p*temp.d2_r2)); + new->d3_qr2 = -(sin(temp.value)*(temp.d3_qr2 - + temp.d1_q*temp.d1_r*temp.d1_r) + + cos(temp.value)*(temp.d1_r*temp.d2_qr + + temp.d1_r*temp.d2_qr + + temp.d1_q*temp.d2_r2)); + new->d3_pqr = -(sin(temp.value)*(temp.d3_pqr - + temp.d1_r*temp.d1_p*temp.d1_q) + + cos(temp.value)*(temp.d1_q*temp.d2_pr + + temp.d1_p*temp.d2_qr + + temp.d1_r*temp.d2_pq)); +} diff --git a/src/spicelib/devices/disto/cubeder.c b/src/spicelib/devices/disto/cubeder.c new file mode 100644 index 000000000..97c35fb3d --- /dev/null +++ b/src/spicelib/devices/disto/cubeder.c @@ -0,0 +1,89 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * CubeDeriv computes the partial derivatives of the cube + * function where the argument to the function is itself a + * function of three variables p, q, and r. + */ + +void +CubeDeriv(Dderivs *new, Dderivs *old) +{ + Dderivs temp; + + EqualDeriv(&temp, old); + + new->value = temp.value * temp.value * temp.value; + new->d1_p = 3*temp.value*temp.value*temp.d1_p; + new->d1_q = 3*temp.value*temp.value*temp.d1_q; + new->d1_r = 3*temp.value*temp.value*temp.d1_r; + new->d2_p2 = 3*(2*temp.value*temp.d1_p*temp.d1_p + + temp.value*temp.value*temp.d2_p2); + new->d2_q2 = 3*(2*temp.value*temp.d1_q*temp.d1_q + + temp.value*temp.value*temp.d2_q2); + new->d2_r2 = 3*(2*temp.value*temp.d1_r*temp.d1_r + + temp.value*temp.value*temp.d2_r2); + new->d2_pq = 3*(2*temp.value*temp.d1_p*temp.d1_q + + temp.value*temp.value*temp.d2_pq); + new->d2_qr = 3*(2*temp.value*temp.d1_q*temp.d1_r + + temp.value*temp.value*temp.d2_qr); + new->d2_pr = 3*(2*temp.value*temp.d1_p*temp.d1_r + + temp.value*temp.value*temp.d2_pr); + new->d3_p3 = 3*(2*(temp.d1_p*temp.d1_p*temp.d1_p + + temp.value*(temp.d2_p2*temp.d1_p + + temp.d2_p2*temp.d1_p + + temp.d2_p2*temp.d1_p)) + + temp.value*temp.value*temp.d3_p3); + new->d3_q3 = 3*(2*(temp.d1_q*temp.d1_q*temp.d1_q + + temp.value*(temp.d2_q2*temp.d1_q + + temp.d2_q2*temp.d1_q + + temp.d2_q2*temp.d1_q)) + + temp.value*temp.value*temp.d3_q3); + new->d3_r3 = 3*(2*(temp.d1_r*temp.d1_r*temp.d1_r + + temp.value*(temp.d2_r2*temp.d1_r + + temp.d2_r2*temp.d1_r + + temp.d2_r2*temp.d1_r)) + + temp.value*temp.value*temp.d3_r3); + new->d3_p2r = 3*(2*(temp.d1_p*temp.d1_p*temp.d1_r + + temp.value*(temp.d2_p2*temp.d1_r + + temp.d2_pr*temp.d1_p + + temp.d2_pr*temp.d1_p)) + + temp.value*temp.value*temp.d3_p2r); + new->d3_p2q = 3*(2*(temp.d1_p*temp.d1_p*temp.d1_q + + temp.value*(temp.d2_p2*temp.d1_q + + temp.d2_pq*temp.d1_p + + temp.d2_pq*temp.d1_p)) + + temp.value*temp.value*temp.d3_p2q); + new->d3_q2r = 3*(2*(temp.d1_q*temp.d1_q*temp.d1_r + + temp.value*(temp.d2_q2*temp.d1_r + + temp.d2_qr*temp.d1_q + + temp.d2_qr*temp.d1_q)) + + temp.value*temp.value*temp.d3_q2r); + new->d3_pq2 = 3*(2*(temp.d1_q*temp.d1_q*temp.d1_p + + temp.value*(temp.d2_q2*temp.d1_p + + temp.d2_pq*temp.d1_q + + temp.d2_pq*temp.d1_q)) + + temp.value*temp.value*temp.d3_pq2); + new->d3_pr2 = 3*(2*(temp.d1_r*temp.d1_r*temp.d1_p + + temp.value*(temp.d2_r2*temp.d1_p + + temp.d2_pr*temp.d1_r + + temp.d2_pr*temp.d1_r)) + + temp.value*temp.value*temp.d3_pr2); + new->d3_qr2 = 3*(2*(temp.d1_r*temp.d1_r*temp.d1_q + + temp.value*(temp.d2_r2*temp.d1_q + + temp.d2_qr*temp.d1_r + + temp.d2_qr*temp.d1_r)) + + temp.value*temp.value*temp.d3_qr2); + new->d3_pqr = 3*(2*(temp.d1_p*temp.d1_q*temp.d1_r + + temp.value*(temp.d2_pq*temp.d1_r + + temp.d2_qr*temp.d1_p + + temp.d2_pr*temp.d1_q)) + + temp.value*temp.value*temp.d3_pqr); +} diff --git a/src/spicelib/devices/disto/divderiv.c b/src/spicelib/devices/disto/divderiv.c new file mode 100644 index 000000000..bf1f394db --- /dev/null +++ b/src/spicelib/devices/disto/divderiv.c @@ -0,0 +1,134 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * DivDeriv computes the partial derivatives of the division + * function where the arguments to the function are + * functions of three variables p, q, and r. + */ + +void +DivDeriv(Dderivs *new, Dderivs *old1, Dderivs *old2) +{ + + Dderivs num, den; + + EqualDeriv(&num, old1); + EqualDeriv(&den, old2); + + new->value = num.value / den.value; + new->d1_p = (num.d1_p - num.value * den.d1_p / den.value) / den.value; + new->d1_q = (num.d1_q - num.value * den.d1_q / den.value) / den.value; + new->d1_r = (num.d1_r - num.value * den.d1_r / den.value) / den.value; + new->d2_p2 = (num.d2_p2 - den.d1_p * new->d1_p + - new->value * den.d2_p2 + + (den.d1_p * (new->value * den.d1_p - num.d1_p) + / den.value)) / den.value; + new->d2_q2 = (num.d2_q2 - den.d1_q * new->d1_q + - new->value * den.d2_q2 + + (den.d1_q * (new->value * den.d1_q - num.d1_q) + / den.value)) / den.value; + new->d2_r2 = (num.d2_r2 - den.d1_r * new->d1_r - new->value * + den.d2_r2 + den.d1_r * (new->value * den.d1_r - + num.d1_r) / den.value) / + den.value; + new->d2_pq = (num.d2_pq - den.d1_q * new->d1_p - new->value * + den.d2_pq + den.d1_p * (new->value * den.d1_q - + num.d1_q) / den.value) / + den.value; + new->d2_qr = (num.d2_qr - den.d1_r * new->d1_q - new->value * + den.d2_qr + den.d1_q * (new->value * den.d1_r - + num.d1_r) / den.value) / + den.value; + new->d2_pr = (num.d2_pr - den.d1_r * new->d1_p - new->value * + den.d2_pr + den.d1_p * (new->value * den.d1_r - + num.d1_r) / den.value) / + den.value; + new->d3_p3 = (-den.d1_p * new->d2_p2 + num.d3_p3 -den.d2_p2 * + new->d1_p - den.d1_p * new->d2_p2 - new->d1_p * + den.d2_p2 - new->value * den.d3_p3 + + (den.d1_p * (new->d1_p * den.d1_p + + new->value * den.d2_p2 - + num.d2_p2) + + (new->value * den.d1_p - num.d1_p) * + (den.d2_p2 - den.d1_p * den.d1_p / den.value)) + / den.value) / den.value; + new->d3_q3 = (-den.d1_q * new->d2_q2 + num.d3_q3 -den.d2_q2 * + new->d1_q - den.d1_q * new->d2_q2 - new->d1_q * + den.d2_q2 - new->value * den.d3_q3 + + (den.d1_q * (new->d1_q * den.d1_q + new->value * + den.d2_q2 - num.d2_q2) + + (new->value * den.d1_q - num.d1_q) * + (den.d2_q2 - den.d1_q * den.d1_q / den.value)) / + den.value) / den.value; + new->d3_r3 = (-den.d1_r * new->d2_r2 + num.d3_r3 -den.d2_r2 * + new->d1_r - den.d1_r * new->d2_r2 - new->d1_r * + den.d2_r2 - new->value * den.d3_r3 + + (den.d1_r * (new->d1_r * den.d1_r + new->value * + den.d2_r2 - num.d2_r2) + + (new->value * den.d1_r - num.d1_r) * + (den.d2_r2 - den.d1_r * den.d1_r / den.value)) / + den.value) / den.value; + new->d3_p2r = (-den.d1_r * new->d2_p2 + num.d3_p2r -den.d2_pr * + new->d1_p - den.d1_p * new->d2_pr - new->d1_r * + den.d2_p2 - new->value * den.d3_p2r + + (den.d1_p * (new->d1_r * den.d1_p + new->value * + den.d2_pr - num.d2_pr) + + (new->value * den.d1_p - num.d1_p) * + (den.d2_pr - den.d1_p * den.d1_r / den.value)) + / den.value) / den.value; + new->d3_p2q = (-den.d1_q * new->d2_p2 + num.d3_p2q -den.d2_pq * + new->d1_p - den.d1_p * new->d2_pq - new->d1_q * + den.d2_p2 - new->value * den.d3_p2q + + (den.d1_p * (new->d1_q * den.d1_p + new->value * + den.d2_pq - num.d2_pq) + + (new->value * den.d1_p - num.d1_p) * + (den.d2_pq - den.d1_p * den.d1_q / den.value)) / + den.value) / den.value; + new->d3_q2r = (-den.d1_r * new->d2_q2 + num.d3_q2r -den.d2_qr * + new->d1_q - den.d1_q * new->d2_qr - new->d1_r * + den.d2_q2 - new->value * den.d3_q2r + + (den.d1_q * (new->d1_r * den.d1_q + new->value * + den.d2_qr - num.d2_qr) + + (new->value * den.d1_q - num.d1_q) * + (den.d2_qr - den.d1_q * den.d1_r / den.value)) / + den.value) / den.value; + new->d3_pq2 = (-den.d1_p * new->d2_q2 + num.d3_pq2 -den.d2_pq * + new->d1_q - den.d1_q * new->d2_pq - new->d1_p * + den.d2_q2 - new->value * den.d3_pq2 + + (den.d1_q * (new->d1_p * den.d1_q + new->value * + den.d2_pq - num.d2_pq) + + (new->value * den.d1_q - num.d1_q) * + (den.d2_pq - den.d1_q * den.d1_p / den.value)) / + den.value) / den.value; + new->d3_pr2 = (-den.d1_p * new->d2_r2 + num.d3_pr2 -den.d2_pr * + new->d1_r - den.d1_r * new->d2_pr - new->d1_p * + den.d2_r2 - new->value * den.d3_pr2 + + (den.d1_r * (new->d1_p * den.d1_r + new->value * + den.d2_pr - num.d2_pr) + + (new->value * den.d1_r - num.d1_r) * + (den.d2_pr - den.d1_r * den.d1_p / den.value)) / + den.value) / den.value; + new->d3_qr2 = (-den.d1_q * new->d2_r2 + num.d3_qr2 -den.d2_qr * + new->d1_r - den.d1_r * new->d2_qr - new->d1_q * + den.d2_r2 - new->value * den.d3_qr2 + + (den.d1_r * (new->d1_q * den.d1_r + new->value * + den.d2_qr - num.d2_qr) + + (new->value * den.d1_r - num.d1_r) * + (den.d2_qr - den.d1_r * den.d1_q / den.value)) / + den.value) / den.value; + new->d3_pqr = (-den.d1_r * new->d2_pq + num.d3_pqr -den.d2_qr * + new->d1_p - den.d1_q * new->d2_pr - new->d1_r * + den.d2_pq - new->value * den.d3_pqr + + (den.d1_p * (new->d1_r * den.d1_q + new->value * + den.d2_qr - num.d2_qr) + + (new->value * den.d1_q - num.d1_q) * + (den.d2_pr - den.d1_p * den.d1_r / den.value)) / + den.value) / den.value; +} diff --git a/src/spicelib/devices/disto/equalder.c b/src/spicelib/devices/disto/equalder.c new file mode 100644 index 000000000..e0274d29c --- /dev/null +++ b/src/spicelib/devices/disto/equalder.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * EqualDeriv equates partial derivatives. + */ + +void +EqualDeriv(Dderivs *new, Dderivs *old) +{ + +new->value = old->value; +new->d1_p = old->d1_p; +new->d1_q = old->d1_q; +new->d1_r = old->d1_r; +new->d2_p2 = old->d2_p2 ; +new->d2_q2 = old->d2_q2 ; +new->d2_r2 = old->d2_r2 ; +new->d2_pq = old->d2_pq ; +new->d2_qr = old->d2_qr ; +new->d2_pr = old->d2_pr ; +new->d3_p3 = old->d3_p3 ; +new->d3_q3 = old->d3_q3 ; +new->d3_r3 = old->d3_r3 ; +new->d3_p2r = old->d3_p2r ; +new->d3_p2q = old->d3_p2q ; +new->d3_q2r = old->d3_q2r ; +new->d3_pq2 = old->d3_pq2 ; +new->d3_pr2 = old->d3_pr2 ; +new->d3_qr2 = old->d3_qr2 ; +new->d3_pqr = old->d3_pqr ; +} diff --git a/src/spicelib/devices/disto/expderiv.c b/src/spicelib/devices/disto/expderiv.c new file mode 100644 index 000000000..239312c5b --- /dev/null +++ b/src/spicelib/devices/disto/expderiv.c @@ -0,0 +1,64 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * ExpDeriv computes the partial derivatives of the exponential + * function where the argument to the function is itself a + * function of three variables p, q, and r. + */ + +void +ExpDeriv(Dderivs *new, Dderivs *old) +{ + + Dderivs temp; + + EqualDeriv(&temp, old); + new->value = exp(temp.value); + new->d1_p = new->value*temp.d1_p; + new->d1_q = new->value*temp.d1_q; + new->d1_r = new->value*temp.d1_r; + new->d2_p2 = new->value*temp.d2_p2 + temp.d1_p*new->d1_p; + new->d2_q2 = new->value*temp.d2_q2 + temp.d1_q*new->d1_q; + new->d2_r2 = new->value*temp.d2_r2 + temp.d1_r*new->d1_r; + new->d2_pq = new->value*temp.d2_pq + temp.d1_p*new->d1_q; + new->d2_qr = new->value*temp.d2_qr + temp.d1_q*new->d1_r; + new->d2_pr = new->value*temp.d2_pr + temp.d1_p*new->d1_r; + new->d3_p3 = new->value*temp.d3_p3 + temp.d2_p2*new->d1_p + + temp.d2_p2*new->d1_p + + new->d2_p2*temp.d1_p; + new->d3_q3 = new->value*temp.d3_q3 + temp.d2_q2*new->d1_q + + temp.d2_q2*new->d1_q + + new->d2_q2*temp.d1_q; + new->d3_r3 = new->value*temp.d3_r3 + temp.d2_r2*new->d1_r + + temp.d2_r2*new->d1_r + + new->d2_r2*temp.d1_r; + new->d3_p2r = new->value*temp.d3_p2r + temp.d2_p2*new->d1_r + + temp.d2_pr*new->d1_p + + new->d2_pr*temp.d1_p; + new->d3_p2q = new->value*temp.d3_p2q + temp.d2_p2*new->d1_q + + temp.d2_pq*new->d1_p + + new->d2_pq*temp.d1_p; + new->d3_q2r = new->value*temp.d3_q2r + temp.d2_q2*new->d1_r + + temp.d2_qr*new->d1_q + + new->d2_qr*temp.d1_q; + new->d3_pq2 = new->value*temp.d3_pq2 + temp.d2_q2*new->d1_p + + temp.d2_pq*new->d1_q + + new->d2_pq*temp.d1_q; + new->d3_pr2 = new->value*temp.d3_pr2 + temp.d2_r2*new->d1_p + + temp.d2_pr*new->d1_r + + new->d2_pr*temp.d1_r; + new->d3_qr2 = new->value*temp.d3_qr2 + temp.d2_r2*new->d1_q + + temp.d2_qr*new->d1_r + + new->d2_qr*temp.d1_r; + new->d3_pqr = new->value*temp.d3_pqr + temp.d2_pq*new->d1_r + + temp.d2_pr*new->d1_q + + new->d2_qr*temp.d1_p; + +} diff --git a/src/spicelib/devices/disto/invderiv.c b/src/spicelib/devices/disto/invderiv.c new file mode 100644 index 000000000..06d9872c9 --- /dev/null +++ b/src/spicelib/devices/disto/invderiv.c @@ -0,0 +1,64 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * InvDeriv computes the partial derivatives of the 1/x + * function where the argument to the function is itself a + * function of three variables p, q, and r. + */ + +void +InvDeriv(Dderivs *new, Dderivs *old) +{ + Dderivs temp; + + EqualDeriv(&temp, old); + + new->value = 1/temp.value; + new->d1_p = -new->value*new->value*temp.d1_p; + new->d1_q = -new->value*new->value*temp.d1_q; + new->d1_r = -new->value*new->value*temp.d1_r; + new->d2_p2 = -new->value*(2*new->d1_p*temp.d1_p + new->value*temp.d2_p2); + new->d2_q2 = -new->value*(2*new->d1_q*temp.d1_q + new->value*temp.d2_q2); + new->d2_r2 = -new->value*(2*new->d1_r*temp.d1_r + new->value*temp.d2_r2); + new->d2_pq = -new->value*(2*new->d1_q*temp.d1_p + new->value*temp.d2_pq); + new->d2_qr = -new->value*(2*new->d1_r*temp.d1_q + new->value*temp.d2_qr); + new->d2_pr = -new->value*(2*new->d1_r*temp.d1_p + new->value*temp.d2_pr); + new->d3_p3 = -(2*(temp.d1_p*new->d1_p*new->d1_p + new->value*( + new->d2_p2*temp.d1_p + new->d1_p*temp.d2_p2 + + new->d1_p*temp.d2_p2)) + new->value*new->value*temp.d3_p3); + new->d3_q3 = -(2*(temp.d1_q*new->d1_q*new->d1_q + new->value*( + new->d2_q2*temp.d1_q + new->d1_q*temp.d2_q2 + + new->d1_q*temp.d2_q2)) + new->value*new->value*temp.d3_q3); + new->d3_r3 = -(2*(temp.d1_r*new->d1_r*new->d1_r + new->value*( + new->d2_r2*temp.d1_r + new->d1_r*temp.d2_r2 + + new->d1_r*temp.d2_r2)) + new->value*new->value*temp.d3_r3); + new->d3_p2r = -(2*(temp.d1_p*new->d1_p*new->d1_r + new->value*( + new->d2_pr*temp.d1_p + new->d1_p*temp.d2_pr + + new->d1_r*temp.d2_p2)) + new->value*new->value*temp.d3_p2r); + new->d3_p2q = -(2*(temp.d1_p*new->d1_p*new->d1_q + new->value*( + new->d2_pq*temp.d1_p + new->d1_p*temp.d2_pq + + new->d1_q*temp.d2_p2)) + new->value*new->value*temp.d3_p2q); + new->d3_q2r = -(2*(temp.d1_q*new->d1_q*new->d1_r + new->value*( + new->d2_qr*temp.d1_q + new->d1_q*temp.d2_qr + + new->d1_r*temp.d2_q2)) + new->value*new->value*temp.d3_q2r); + new->d3_pq2 = -(2*(temp.d1_q*new->d1_q*new->d1_p + new->value*( + new->d2_pq*temp.d1_q + new->d1_q*temp.d2_pq + + new->d1_p*temp.d2_q2)) + new->value*new->value*temp.d3_pq2); + new->d3_pr2 = -(2*(temp.d1_r*new->d1_r*new->d1_p + new->value*( + new->d2_pr*temp.d1_r + new->d1_r*temp.d2_pr + + new->d1_p*temp.d2_r2)) + new->value*new->value*temp.d3_pr2); + new->d3_qr2 = -(2*(temp.d1_r*new->d1_r*new->d1_q + new->value*( + new->d2_qr*temp.d1_r + new->d1_r*temp.d2_qr + + new->d1_q*temp.d2_r2)) + new->value*new->value*temp.d3_qr2); + new->d3_pqr = -(2*(temp.d1_p*new->d1_q*new->d1_r + new->value*( + new->d2_qr*temp.d1_p + new->d1_q*temp.d2_pr + + new->d1_r*temp.d2_pq)) + new->value*new->value*temp.d3_pqr); + +} diff --git a/src/spicelib/devices/disto/multder.c b/src/spicelib/devices/disto/multder.c new file mode 100644 index 000000000..68a8d5a60 --- /dev/null +++ b/src/spicelib/devices/disto/multder.c @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * MultDeriv computes the partial derivatives of the multiplication + * function where the arguments to the function are + * functions of three variables p, q, and r. + */ + +void +MultDeriv(Dderivs *new, Dderivs *old1, Dderivs *old2) +{ + Dderivs temp1, temp2; + + EqualDeriv(&temp1, old1); + EqualDeriv(&temp2, old2); + + new->value = temp1.value * temp2.value; + new->d1_p = temp1.d1_p*temp2.value + temp1.value*temp2.d1_p; + new->d1_q = temp1.d1_q*temp2.value + temp1.value*temp2.d1_q; + new->d1_r = temp1.d1_r*temp2.value + temp1.value*temp2.d1_r; + new->d2_p2 = temp1.d2_p2*temp2.value + temp1.d1_p*temp2.d1_p + + temp1.d1_p*temp2.d1_p + temp1.value*temp2.d2_p2; + new->d2_q2 = temp1.d2_q2*temp2.value + temp1.d1_q*temp2.d1_q + + temp1.d1_q*temp2.d1_q + temp1.value*temp2.d2_q2; + new->d2_r2 = temp1.d2_r2*temp2.value + temp1.d1_r*temp2.d1_r + + temp1.d1_r*temp2.d1_r + temp1.value*temp2.d2_r2; + new->d2_pq = temp1.d2_pq*temp2.value + temp1.d1_p*temp2.d1_q + + temp1.d1_q*temp2.d1_p + temp1.value*temp2.d2_pq; + new->d2_qr = temp1.d2_qr*temp2.value + temp1.d1_q*temp2.d1_r + + temp1.d1_r*temp2.d1_q + temp1.value*temp2.d2_qr; + new->d2_pr = temp1.d2_pr*temp2.value + temp1.d1_p*temp2.d1_r + + temp1.d1_r*temp2.d1_p + temp1.value*temp2.d2_pr; + new->d3_p3 = temp1.d3_p3*temp2.value + temp1.d2_p2*temp2.d1_p + + temp1.d2_p2*temp2.d1_p + temp2.d2_p2*temp1.d1_p + + temp2.d2_p2*temp1.d1_p + temp1.d2_p2*temp2.d1_p + + temp2.d2_p2*temp1.d1_p + temp1.value*temp2.d3_p3; + + new->d3_q3 = temp1.d3_q3*temp2.value + temp1.d2_q2*temp2.d1_q + + temp1.d2_q2*temp2.d1_q + temp2.d2_q2*temp1.d1_q + + temp2.d2_q2*temp1.d1_q + temp1.d2_q2*temp2.d1_q + + temp2.d2_q2*temp1.d1_q + temp1.value*temp2.d3_q3; + new->d3_r3 = temp1.d3_r3*temp2.value + temp1.d2_r2*temp2.d1_r + + temp1.d2_r2*temp2.d1_r + temp2.d2_r2*temp1.d1_r + + temp2.d2_r2*temp1.d1_r + temp1.d2_r2*temp2.d1_r + + temp2.d2_r2*temp1.d1_r + temp1.value*temp2.d3_r3; + new->d3_p2r = temp1.d3_p2r*temp2.value + temp1.d2_p2*temp2.d1_r + + temp1.d2_pr*temp2.d1_p + temp2.d2_p2*temp1.d1_r + + temp2.d2_pr*temp1.d1_p + temp1.d2_pr*temp2.d1_p + + temp2.d2_pr*temp1.d1_p + temp1.value*temp2.d3_p2r; + new->d3_p2q = temp1.d3_p2q*temp2.value + temp1.d2_p2*temp2.d1_q + + temp1.d2_pq*temp2.d1_p + temp2.d2_p2*temp1.d1_q + + temp2.d2_pq*temp1.d1_p + temp1.d2_pq*temp2.d1_p + + temp2.d2_pq*temp1.d1_p + temp1.value*temp2.d3_p2q; + new->d3_q2r = temp1.d3_q2r*temp2.value + temp1.d2_q2*temp2.d1_r + + temp1.d2_qr*temp2.d1_q + temp2.d2_q2*temp1.d1_r + + temp2.d2_qr*temp1.d1_q + temp1.d2_qr*temp2.d1_q + + temp2.d2_qr*temp1.d1_q + temp1.value*temp2.d3_q2r; + new->d3_pq2 = temp1.d3_pq2*temp2.value + temp1.d2_q2*temp2.d1_p + + temp1.d2_pq*temp2.d1_q + temp2.d2_q2*temp1.d1_p + + temp2.d2_pq*temp1.d1_q + temp1.d2_pq*temp2.d1_q + + temp2.d2_pq*temp1.d1_q + temp1.value*temp2.d3_pq2; + new->d3_pr2 = temp1.d3_pr2*temp2.value + temp1.d2_r2*temp2.d1_p + + temp1.d2_pr*temp2.d1_r + temp2.d2_r2*temp1.d1_p + + temp2.d2_pr*temp1.d1_r + temp1.d2_pr*temp2.d1_r + + temp2.d2_pr*temp1.d1_r + temp1.value*temp2.d3_pr2; + new->d3_qr2 = temp1.d3_qr2*temp2.value + temp1.d2_r2*temp2.d1_q + + temp1.d2_qr*temp2.d1_r + temp2.d2_r2*temp1.d1_q + + temp2.d2_qr*temp1.d1_r + temp1.d2_qr*temp2.d1_r + + temp2.d2_qr*temp1.d1_r + temp1.value*temp2.d3_qr2; + new->d3_pqr = temp1.d3_pqr*temp2.value + temp1.d2_pq*temp2.d1_r + + temp1.d2_pr*temp2.d1_q + temp2.d2_pq*temp1.d1_r + + temp2.d2_qr*temp1.d1_p + temp1.d2_qr*temp2.d1_p + + temp2.d2_pr*temp1.d1_q + temp1.value*temp2.d3_pqr; +} diff --git a/src/spicelib/devices/disto/plusder.c b/src/spicelib/devices/disto/plusder.c new file mode 100644 index 000000000..5c03a4d73 --- /dev/null +++ b/src/spicelib/devices/disto/plusder.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * PlusDeriv computes the partial derivatives of the addition + * function where the arguments to the function are + * functions of three variables p, q, and r. + */ + +void +PlusDeriv(Dderivs *new, Dderivs *old1, Dderivs *old2) +{ + new->value = old1->value + old2->value; + new->d1_p = old1->d1_p + old2->d1_p; + new->d1_q = old1->d1_q + old2->d1_q; + new->d1_r = old1->d1_r + old2->d1_r; + new->d2_p2 = old1->d2_p2 + old2->d2_p2; + new->d2_q2 = old1->d2_q2 + old2->d2_q2; + new->d2_r2 = old1->d2_r2 + old2->d2_r2; + new->d2_pq = old1->d2_pq + old2->d2_pq; + new->d2_qr = old1->d2_qr + old2->d2_qr; + new->d2_pr = old1->d2_pr + old2->d2_pr; + new->d3_p3 = old1->d3_p3 + old2->d3_p3; + new->d3_q3 = old1->d3_q3 + old2->d3_q3; + new->d3_r3 = old1->d3_r3 + old2->d3_r3; + new->d3_p2r = old1->d3_p2r + old2->d3_p2r; + new->d3_p2q = old1->d3_p2q + old2->d3_p2q; + new->d3_q2r = old1->d3_q2r + old2->d3_q2r; + new->d3_pq2 = old1->d3_pq2 + old2->d3_pq2; + new->d3_pr2 = old1->d3_pr2 + old2->d3_pr2; + new->d3_qr2 = old1->d3_qr2 + old2->d3_qr2; + new->d3_pqr = old1->d3_pqr + old2->d3_pqr; +} diff --git a/src/spicelib/devices/disto/powderiv.c b/src/spicelib/devices/disto/powderiv.c new file mode 100644 index 000000000..054054af0 --- /dev/null +++ b/src/spicelib/devices/disto/powderiv.c @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * PowDeriv computes the partial derivatives of the x^^m + * function where the argument to the function is itself a + * function of three variables p, q, and r. m is a constant. + */ + +void +PowDeriv(Dderivs *new, Dderivs *old, double emm) +{ + Dderivs temp; + + EqualDeriv(&temp, old); + + new->value = pow(temp.value, emm); + new->d1_p = emm * new->value / temp.value * temp.d1_p; + new->d1_q = emm * new->value / temp.value * temp.d1_q; + new->d1_r = emm * new->value / temp.value * temp.d1_r; + new->d2_p2 = emm * new->value / temp.value * + ((emm-1) / temp.value * temp.d1_p * temp.d1_p + temp.d2_p2); + new->d2_q2 = emm * new->value / temp.value * + ((emm-1) / temp.value * temp.d1_q * temp.d1_q + temp.d2_q2); + new->d2_r2 = emm * new->value / temp.value * + ((emm-1) / temp.value * temp.d1_r * temp.d1_r + temp.d2_r2); + new->d2_pq = emm * new->value / temp.value * + ((emm-1) / temp.value * temp.d1_p * temp.d1_q + temp.d2_pq); + new->d2_qr = emm * new->value / temp.value * + ((emm-1) / temp.value * temp.d1_q * temp.d1_r + temp.d2_qr); + new->d2_pr = emm * new->value / temp.value * + ((emm-1) / temp.value * temp.d1_p * temp.d1_r + temp.d2_pr); + new->d3_p3 = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_p * + temp.d1_p * temp.d1_p + temp.d1_p * temp.d2_p2 + temp.d1_p * + temp.d2_p2 + temp.d1_p * temp.d2_p2) + emm * new->value / + temp.value * temp.d3_p3; + new->d3_q3 = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_q * + temp.d1_q * temp.d1_q + temp.d1_q * temp.d2_q2 + temp.d1_q * + temp.d2_q2 + temp.d1_q * temp.d2_q2) + emm * new->value / + temp.value * temp.d3_q3; + new->d3_r3 = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_r *temp.d1_r * temp.d1_r + + temp.d1_r * temp.d2_r2 + temp.d1_r * temp.d2_r2 + temp.d1_r * + temp.d2_r2) + emm * new->value / temp.value * temp.d3_r3; + new->d3_p2r = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_p * temp.d1_p * temp.d1_r + + temp.d1_p * temp.d2_pr + temp.d1_p * temp.d2_pr + temp.d1_r * + temp.d2_p2) + emm * new->value / temp.value * temp.d3_p2r; + new->d3_p2q = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_p * temp.d1_p * temp.d1_q + + temp.d1_p * temp.d2_pq + temp.d1_p * temp.d2_pq + temp.d1_q * + temp.d2_p2) + emm * new->value / temp.value * temp.d3_p2q; + new->d3_q2r = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_q * temp.d1_q * temp.d1_r + + temp.d1_q * temp.d2_qr + temp.d1_q * temp.d2_qr + temp.d1_r * + temp.d2_q2) + emm * new->value / temp.value * temp.d3_q2r; + new->d3_pq2 = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_q * temp.d1_q * temp.d1_p + + temp.d1_q * temp.d2_pq + temp.d1_q * temp.d2_pq + temp.d1_p * + temp.d2_q2) + emm * new->value / temp.value * temp.d3_pq2; + new->d3_pr2 = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_r * temp.d1_r * temp.d1_p + + temp.d1_r * temp.d2_pr + temp.d1_r * temp.d2_pr + temp.d1_p * + temp.d2_r2) + emm * new->value / temp.value * temp.d3_pr2; + new->d3_qr2 = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_r * temp.d1_r * temp.d1_q + + temp.d1_r * temp.d2_qr + temp.d1_r * temp.d2_qr + temp.d1_q * + temp.d2_r2) + emm * new->value / temp.value * temp.d3_qr2; + new->d3_pqr = emm * (emm-1) * new->value / (temp.value * temp.value) * + ((emm-2) / temp.value * temp.d1_p * temp.d1_q * temp.d1_r + + temp.d1_p * temp.d2_qr + temp.d1_q * temp.d2_pr + temp.d1_r * + temp.d2_pq) + emm * new->value / temp.value * temp.d3_pqr; +} diff --git a/src/spicelib/devices/disto/sqrtder.c b/src/spicelib/devices/disto/sqrtder.c new file mode 100644 index 000000000..663f62993 --- /dev/null +++ b/src/spicelib/devices/disto/sqrtder.c @@ -0,0 +1,122 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * SqrtDeriv computes the partial derivatives of the sqrt + * function where the argument to the function is itself a + * function of three variables p, q, and r. + */ + +void +SqrtDeriv(Dderivs *new, Dderivs *old) +{ + + Dderivs temp; + + EqualDeriv(&temp, old); + new->value = sqrt(temp.value); + if (temp.value == 0.0) + { + new->d1_p = 0.0; + new->d1_q = 0.0; + new->d1_r = 0.0; + new->d2_p2 = 0.0; + new->d2_q2 = 0.0; + new->d2_r2 = 0.0; + new->d2_pq = 0.0; + new->d2_qr = 0.0; + new->d2_pr = 0.0; + new->d3_p3 = 0.0; + new->d3_q3 = 0.0; + new->d3_r3 = 0.0; + new->d3_p2r = 0.0; + new->d3_p2q = 0.0; + new->d3_q2r = 0.0; + new->d3_pq2 = 0.0; + new->d3_pr2 = 0.0; + new->d3_qr2 = 0.0; + new->d3_pqr = 0.0; + } else { + new->d1_p = 0.5*temp.d1_p/new->value; + new->d1_q = 0.5*temp.d1_q/new->value; + new->d1_r = 0.5*temp.d1_r/new->value; + new->d2_p2 = 0.5/new->value * (temp.d2_p2 - 0.5 * temp.d1_p * + temp.d1_p/ temp.value); + new->d2_q2 = 0.5/new->value*(temp.d2_q2 -0.5 * temp.d1_q * + temp.d1_q/ temp.value); + new->d2_r2 = 0.5/new->value*(temp.d2_r2 -0.5 * temp.d1_r * + temp.d1_r/ temp.value); + new->d2_pq = 0.5/new->value*(temp.d2_pq -0.5 * temp.d1_p * + temp.d1_q/ temp.value); + new->d2_qr = 0.5/new->value*(temp.d2_qr -0.5 * temp.d1_q * + temp.d1_r/ temp.value); + new->d2_pr = 0.5/new->value*(temp.d2_pr -0.5 * temp.d1_p * + temp.d1_r/ temp.value); + new->d3_p3 = 0.5 * + (temp.d3_p3 / new->value - 0.5 / (temp.value*new->value) * + (-1.5 / temp.value * temp.d1_p * temp.d1_p * temp.d1_p + + temp.d1_p*temp.d2_p2 + + temp.d1_p*temp.d2_p2 + + temp.d1_p*temp.d2_p2)); + new->d3_q3 = 0.5 * + (temp.d3_q3 / new->value - 0.5 / (temp.value*new->value) * + (-1.5 / temp.value * temp.d1_q * temp.d1_q * temp.d1_q + + temp.d1_q*temp.d2_q2 + + temp.d1_q*temp.d2_q2 + + temp.d1_q* temp.d2_q2)); + new->d3_r3 = 0.5 * + (temp.d3_r3 / new->value - 0.5 / (temp.value*new->value) * + (-1.5 / temp.value * temp.d1_r * temp.d1_r * temp.d1_r + + temp.d1_r*temp.d2_r2 + + temp.d1_r*temp.d2_r2 + + temp.d1_r* temp.d2_r2)); + new->d3_p2r = 0.5 * + (temp.d3_p2r / new->value - 0.5 / (temp.value*new->value) * + (-1.5 / temp.value * temp.d1_p * temp.d1_p * temp.d1_r + + temp.d1_p * temp.d2_pr + + temp.d1_p * temp.d2_pr + + temp.d1_r * temp.d2_p2)); + new->d3_p2q = 0.5 * + (temp.d3_p2q / new->value - 0.5 / (temp.value * new->value) * + (-1.5/temp.value*temp.d1_p*temp.d1_p*temp.d1_q + + temp.d1_p * temp.d2_pq + + temp.d1_p * temp.d2_pq + + temp.d1_q * temp.d2_p2)); + new->d3_q2r = 0.5 * + (temp.d3_q2r / new->value - 0.5 / (temp.value * new->value) * + (-1.5 / temp.value * temp.d1_q * temp.d1_q * temp.d1_r + + temp.d1_q*temp.d2_qr + + temp.d1_q*temp.d2_qr + + temp.d1_r* temp.d2_q2)); + new->d3_pq2 = 0.5 * + (temp.d3_pq2 / new->value - 0.5 / (temp.value * new->value) * + (-1.5 / temp.value * temp.d1_q * temp.d1_q * temp.d1_p + + temp.d1_q*temp.d2_pq + + temp.d1_q*temp.d2_pq + + temp.d1_p* temp.d2_q2)); + new->d3_pr2 = 0.5 * + (temp.d3_pr2 / new->value - 0.5 / (temp.value * new->value) * + (-1.5/temp.value * temp.d1_r * temp.d1_r * temp.d1_p + + temp.d1_r*temp.d2_pr + + temp.d1_r*temp.d2_pr + + temp.d1_p* temp.d2_r2)); + new->d3_qr2 = 0.5 * + (temp.d3_qr2 / new->value - 0.5 / (temp.value * new->value) * + (-1.5/temp.value * temp.d1_r * temp.d1_r * temp.d1_q + + temp.d1_r*temp.d2_qr + + temp.d1_r*temp.d2_qr + + temp.d1_q* temp.d2_r2)); + new->d3_pqr = 0.5 * + (temp.d3_pqr / new->value - 0.5 / (temp.value * new->value) * + (-1.5/temp.value * temp.d1_p * temp.d1_q * temp.d1_r + + temp.d1_p*temp.d2_qr + + temp.d1_q*temp.d2_pr + + temp.d1_r* temp.d2_pq)); + } +} diff --git a/src/spicelib/devices/disto/tanderiv.c b/src/spicelib/devices/disto/tanderiv.c new file mode 100644 index 000000000..fec1f78b4 --- /dev/null +++ b/src/spicelib/devices/disto/tanderiv.c @@ -0,0 +1,64 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * TanDeriv computes the partial derivatives of the tangent + * function where the argument to the function is itself a + * function of three variables p, q, and r. + */ + +void TanDeriv(new, old) +Dderivs *new, *old; +{ + +Dderivs temp; + +EqualDeriv(&temp, old); +new->value = tan(temp.value); + +new->d1_p = (1 + new->value*new->value)*temp.d1_p; +new->d1_q = (1 + new->value*new->value)*temp.d1_q; +new->d1_r = (1 + new->value*new->value)*temp.d1_r; +new->d2_p2 = (1 + new->value*new->value)*temp.d2_p2 + 2*new->value*temp.d1_p*new->d1_p; +new->d2_q2 = (1 + new->value*new->value)*temp.d2_q2 + 2*new->value*temp.d1_q*new->d1_q; +new->d2_r2 = (1 + new->value*new->value)*temp.d2_r2 + 2*new->value*temp.d1_r*new->d1_r; +new->d2_pq = (1 + new->value*new->value)*temp.d2_pq + 2*new->value*temp.d1_p*new->d1_q; +new->d2_qr = (1 + new->value*new->value)*temp.d2_qr + 2*new->value*temp.d1_q*new->d1_r; +new->d2_pr = (1 + new->value*new->value)*temp.d2_pr + 2*new->value*temp.d1_p*new->d1_r; +new->d3_p3 = (1 + new->value*new->value)*temp.d3_p3 +2*( new->value*( + temp.d2_p2*new->d1_p + temp.d2_p2*new->d1_p + new->d2_p2* + temp.d1_p) + temp.d1_p*new->d1_p*new->d1_p); +new->d3_q3 = (1 + new->value*new->value)*temp.d3_q3 +2*( new->value*( + temp.d2_q2*new->d1_q + temp.d2_q2*new->d1_q + new->d2_q2* + temp.d1_q) + temp.d1_q*new->d1_q*new->d1_q); +new->d3_r3 = (1 + new->value*new->value)*temp.d3_r3 +2*( new->value*( + temp.d2_r2*new->d1_r + temp.d2_r2*new->d1_r + new->d2_r2* + temp.d1_r) + temp.d1_r*new->d1_r*new->d1_r); +new->d3_p2r = (1 + new->value*new->value)*temp.d3_p2r +2*( new->value*( + temp.d2_p2*new->d1_r + temp.d2_pr*new->d1_p + new->d2_pr* + temp.d1_p) + temp.d1_p*new->d1_p*new->d1_r); +new->d3_p2q = (1 + new->value*new->value)*temp.d3_p2q +2*( new->value*( + temp.d2_p2*new->d1_q + temp.d2_pq*new->d1_p + new->d2_pq* + temp.d1_p) + temp.d1_p*new->d1_p*new->d1_q); +new->d3_q2r = (1 + new->value*new->value)*temp.d3_q2r +2*( new->value*( + temp.d2_q2*new->d1_r + temp.d2_qr*new->d1_q + new->d2_qr* + temp.d1_q) + temp.d1_q*new->d1_q*new->d1_r); +new->d3_pq2 = (1 + new->value*new->value)*temp.d3_pq2 +2*( new->value*( + temp.d2_q2*new->d1_p + temp.d2_pq*new->d1_q + new->d2_pq* + temp.d1_q) + temp.d1_q*new->d1_q*new->d1_p); +new->d3_pr2 = (1 + new->value*new->value)*temp.d3_pr2 +2*( new->value*( + temp.d2_r2*new->d1_p + temp.d2_pr*new->d1_r + new->d2_pr* + temp.d1_r) + temp.d1_r*new->d1_r*new->d1_p); +new->d3_qr2 = (1 + new->value*new->value)*temp.d3_qr2 +2*( new->value*( + temp.d2_r2*new->d1_q + temp.d2_qr*new->d1_r + new->d2_qr* + temp.d1_r) + temp.d1_r*new->d1_r*new->d1_q); +new->d3_pqr = (1 + new->value*new->value)*temp.d3_pqr +2*( new->value*( + temp.d2_pq*new->d1_r + temp.d2_pr*new->d1_q + new->d2_qr* + temp.d1_p) + temp.d1_p*new->d1_q*new->d1_r); + } diff --git a/src/spicelib/devices/disto/timesder.c b/src/spicelib/devices/disto/timesder.c new file mode 100644 index 000000000..b5ca429ab --- /dev/null +++ b/src/spicelib/devices/disto/timesder.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "distodef.h" +#include "suffix.h" + +/* + * TimesDeriv computes the partial derivatives of the x*k + * function where the argument to the function is itself a + * function of three variables p, q, and r. k is a constant. + */ + +void +TimesDeriv(Dderivs *new, Dderivs *old, double k) +{ + new->value = k* old->value; + new->d1_p = k*old->d1_p; + new->d1_q = k*old->d1_q; + new->d1_r = k*old->d1_r; + new->d2_p2 = k*old->d2_p2; + new->d2_q2 = k*old->d2_q2; + new->d2_r2 = k*old->d2_r2; + new->d2_pq = k*old->d2_pq; + new->d2_qr = k*old->d2_qr; + new->d2_pr = k*old->d2_pr; + new->d3_p3 = k*old->d3_p3; + new->d3_q3 = k*old->d3_q3; + new->d3_r3 = k*old->d3_r3; + new->d3_p2r = k*old->d3_p2r; + new->d3_p2q = k*old->d3_p2q; + new->d3_q2r = k*old->d3_q2r; + new->d3_pq2 = k*old->d3_pq2; + new->d3_pr2 = k*old->d3_pr2; + new->d3_qr2 = k*old->d3_qr2; + new->d3_pqr = k*old->d3_pqr; +} diff --git a/src/spicelib/devices/ind/ChangeLog b/src/spicelib/devices/ind/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/ind/Makefile.am b/src/spicelib/devices/ind/Makefile.am new file mode 100644 index 000000000..322388b18 --- /dev/null +++ b/src/spicelib/devices/ind/Makefile.am @@ -0,0 +1,39 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libind.la + +libind_la_SOURCES = \ + ind.c \ + indacld.c \ + indask.c \ + inddefs.h \ + inddel.c \ + inddest.c \ + indext.h \ + inditf.h \ + indload.c \ + indmdel.c \ + indparam.c \ + indpzld.c \ + indsacl.c \ + indsetup.c \ + indsload.c \ + indsprt.c \ + indsset.c \ + indsupd.c \ + indtrunc.c \ + mutacld.c \ + mutask.c \ + mutdel.c \ + mutdest.c \ + mutmdel.c \ + mutparam.c \ + mutpzld.c \ + mutsetup.c \ + mutsprt.c \ + mutsset.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/ind/ind.c b/src/spicelib/devices/ind/ind.c new file mode 100644 index 000000000..f9a166e47 --- /dev/null +++ b/src/spicelib/devices/ind/ind.c @@ -0,0 +1,70 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include "devdefs.h" +#include "ifsim.h" +#include +#include "inddefs.h" +#include "suffix.h" + +IFparm INDpTable[] = { /* parameters */ + IOPAP("inductance",IND_IND, IF_REAL,"Inductance of inductor"), + IOPAU("ic", IND_IC, IF_REAL,"Initial current through inductor"), + IP( "sens_ind", IND_IND_SENS,IF_FLAG, + "flag to request sensitivity WRT inductance"), + OP( "flux", IND_FLUX, IF_REAL,"Flux through inductor"), + OP( "v", IND_VOLT, IF_REAL,"Terminal voltage of inductor"), + OPR("volt", IND_VOLT, IF_REAL,""), + OP( "i", IND_CURRENT,IF_REAL,"Current through the inductor"), + OPR( "current", IND_CURRENT,IF_REAL,""), + OP( "p", IND_POWER, IF_REAL, + "instantaneous power dissipated by the inductor"), + OPU( "sens_dc", IND_QUEST_SENS_DC, IF_REAL, "dc sensitivity sensitivity"), + OPU( "sens_real", IND_QUEST_SENS_REAL, IF_REAL, "real part of ac sensitivity"), + OPU( "sens_imag", IND_QUEST_SENS_IMAG, IF_REAL, + "dc sensitivity and imag part of ac sensitivty"), + OPU( "sens_mag", IND_QUEST_SENS_MAG, IF_REAL, "sensitivity of AC magnitude"), + OPU( "sens_ph", IND_QUEST_SENS_PH, IF_REAL, "sensitivity of AC phase"), + OPU( "sens_cplx", IND_QUEST_SENS_CPLX, IF_COMPLEX, "ac sensitivity") +}; + +char *INDnames[] = { + "L+", + "L-" +}; + + +int INDnSize = NUMELEMS(INDnames); +int INDpTSize = NUMELEMS(INDpTable); +int INDmPTSize = 0; +int INDiSize = sizeof(INDinstance); +int INDmSize = sizeof(INDmodel); + +#ifdef MUTUAL + +IFparm MUTpTable[] = { /* parameters */ + IOPAP( "k", MUT_COEFF, IF_REAL , "Mutual inductance"), + IOPR( "coefficient", MUT_COEFF, IF_REAL , ""), + IOP( "inductor1", MUT_IND1, IF_INSTANCE, "First coupled inductor"), + IOP( "inductor2", MUT_IND2, IF_INSTANCE, "Second coupled inductor"), + IP( "sens_coeff", MUT_COEFF_SENS, IF_FLAG, + "flag to request sensitivity WRT coupling factor"), + OPU( "sens_dc", MUT_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU( "sens_real", MUT_QUEST_SENS_REAL, IF_REAL, "real part of ac sensitivity"), + OPU( "sens_imag", MUT_QUEST_SENS_IMAG, IF_REAL, + "dc sensitivity and imag part of ac sensitivty"), + OPU( "sens_mag", MUT_QUEST_SENS_MAG, IF_REAL, "sensitivity of AC magnitude"), + OPU( "sens_ph", MUT_QUEST_SENS_PH, IF_REAL, "sensitivity of AC phase"), + OPU( "sens_cplx", MUT_QUEST_SENS_CPLX, IF_COMPLEX, "ac sensitivity") +}; + +int MUTnSize = NUMELEMS(INDnames); +int MUTpTSize = NUMELEMS(MUTpTable); +int MUTmPTSize = 0; +int MUTiSize = sizeof(INDinstance); +int MUTmSize = sizeof(INDmodel); + +#endif /*MUTUAL*/ diff --git a/src/spicelib/devices/ind/indacld.c b/src/spicelib/devices/ind/indacld.c new file mode 100644 index 000000000..34270665a --- /dev/null +++ b/src/spicelib/devices/ind/indacld.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +INDacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register INDmodel *model = (INDmodel*)inModel; + double val; + register INDinstance *here; + + for( ; model != NULL; model = model->INDnextModel) { + for( here = model->INDinstances;here != NULL; + here = here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + + val = ckt->CKTomega * here->INDinduct; + *(here->INDposIbrptr) += 1; + *(here->INDnegIbrptr) -= 1; + *(here->INDibrPosptr) += 1; + *(here->INDibrNegptr) -= 1; + *(here->INDibrIbrptr +1) -= val; + } + } + return(OK); + +} diff --git a/src/spicelib/devices/ind/indask.c b/src/spicelib/devices/ind/indask.c new file mode 100644 index 000000000..4dfeaa543 --- /dev/null +++ b/src/spicelib/devices/ind/indask.c @@ -0,0 +1,128 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +INDask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + INDinstance *here = (INDinstance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case IND_FLUX: + value->rValue = *(ckt->CKTstate0+here->INDflux); + return(OK); + case IND_VOLT: + value->rValue = *(ckt->CKTstate0+here->INDvolt); + return(OK); + case IND_IND: + value->rValue = here->INDinduct; + return(OK); + case IND_IC: + value->rValue = here->INDinitCond; + return(OK); + case IND_CURRENT : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "INDask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = *(ckt->CKTrhsOld + here->INDbrEq); + } + return(OK); + case IND_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "INDask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTrhsOld + here->INDbrEq) * + *(ckt->CKTstate0+here->INDvolt); + } + return(OK); + case IND_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->INDsenParmNo); + } + return(OK); + case IND_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->INDsenParmNo); + } + return(OK); + case IND_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->INDsenParmNo); + } + return(OK); + case IND_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->INDsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->INDsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case IND_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->INDsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->INDsenParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case IND_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->INDsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->INDsenParmNo); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/ind/inddefs.h b/src/spicelib/devices/ind/inddefs.h new file mode 100644 index 000000000..8a37eb819 --- /dev/null +++ b/src/spicelib/devices/ind/inddefs.h @@ -0,0 +1,156 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef IND +#define IND + + +/* turn on mutual inductor code */ +#define MUTUAL + +#include "ifsim.h" +#include "complex.h" +#include "gendefs.h" +#include "cktdefs.h" + + /* structures used to descrive inductors */ + + +/* information needed for each instance */ + +typedef struct sINDinstance { + struct sINDmodel *INDmodPtr; /* backpointer to model */ + struct sINDinstance *INDnextInstance; /* pointer to next instance of + * current model*/ + IFuid INDname; /* pointer to character string naming this instance */ + int INDowner; /* number of owner process */ + int INDstate; /* pointer to beginning of state vector for inductor */ + int INDposNode; /* number of positive node of inductor */ + int INDnegNode; /* number of negative node of inductor */ + + int INDbrEq; /* number of the branch equation added for current */ + double INDinduct; /* inductance */ + double INDinitCond; /* initial inductor voltage if specified */ + + double *INDposIbrptr; /* pointer to sparse matrix diagonal at + * (positive,branch eq) */ + double *INDnegIbrptr; /* pointer to sparse matrix diagonal at + * (negative,branch eq) */ + double *INDibrNegptr; /* pointer to sparse matrix offdiagonal at + * (branch eq,negative) */ + double *INDibrPosptr; /* pointer to sparse matrix offdiagonal at + * (branch eq,positive) */ + double *INDibrIbrptr; /* pointer to sparse matrix offdiagonal at + * (branch eq,branch eq) */ + unsigned INDindGiven : 1; /* flag to indicate inductance was specified */ + unsigned INDicGiven : 1; /* flag to indicate init. cond. was specified */ + int INDsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + +} INDinstance ; + +#define INDflux INDstate /* flux in the inductor */ +#define INDvolt INDstate+1 /* voltage - save an entry in table */ +#define INDsensxp INDstate+2 /* charge sensitivities and their derivatives. + +3 for the derivatives - pointer to the + beginning of the array */ + + +/* per model data */ + +typedef struct sINDmodel { /* model structure for an inductor */ + int INDmodType; /* type index of this device type */ + struct sINDmodel *INDnextModel; /* pointer to next possible model in + * linked list */ + INDinstance * INDinstances; /* pointer to list of instances that have this + * model */ + IFuid INDmodName; /* pointer to character string naming this model */ +} INDmodel; + + +#ifdef MUTUAL + + /* structures used to describe mutual inductors */ + + +/* information needed for each instance */ + +typedef struct sMUTinstance { + struct sMUTmodel *MUTmodPtr; /* backpointer to model */ + struct sMUTinstance *MUTnextInstance; /* pointer to next instance of + * current model*/ + IFuid MUTname; /* pointer to character string naming this instance */ + int MUTowner; /* number of owner process */ + double MUTcoupling; /* mutual inductance input by user */ + double MUTfactor; /* mutual inductance scaled for internal use */ + IFuid MUTindName1; /* name of coupled inductor 1 */ + IFuid MUTindName2; /* name of coupled inductor 2 */ + INDinstance *MUTind1; /* pointer to coupled inductor 1 */ + INDinstance *MUTind2; /* pointer to coupled inductor 2 */ + double *MUTbr1br2; /* pointers to off-diagonal intersections of */ + double *MUTbr2br1; /* current branch equations in matrix */ + + unsigned MUTindGiven : 1; /* flag to indicate inductance was specified */ + int MUTsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + + +} MUTinstance ; + + +/* per model data */ + +typedef struct sMUTmodel { /* model structure for a mutual inductor */ + int MUTmodType; /* type index of this device type */ + struct sMUTmodel *MUTnextModel; /* pointer to next possible model in + * linked list */ + MUTinstance * MUTinstances; /* pointer to list of instances that have this + * model */ + IFuid MUTmodName; /* pointer to character string naming this model */ +} MUTmodel; + +#endif /*MUTUAL*/ + +/* device parameters */ +#define IND_IND 1 +#define IND_IC 2 +#define IND_FLUX 3 +#define IND_VOLT 4 +#define IND_IND_SENS 5 +#define IND_CURRENT 6 +#define IND_POWER 7 + +/* model parameters */ + +/* device questions */ +#define IND_QUEST_SENS_REAL 201 +#define IND_QUEST_SENS_IMAG 202 +#define IND_QUEST_SENS_MAG 203 +#define IND_QUEST_SENS_PH 204 +#define IND_QUEST_SENS_CPLX 205 +#define IND_QUEST_SENS_DC 206 + +#ifdef MUTUAL +/* device parameters */ +#define MUT_COEFF 401 +#define MUT_IND1 402 +#define MUT_IND2 403 +#define MUT_COEFF_SENS 404 + +/* model parameters */ + +/* device questions */ +#define MUT_QUEST_SENS_REAL 601 +#define MUT_QUEST_SENS_IMAG 602 +#define MUT_QUEST_SENS_MAG 603 +#define MUT_QUEST_SENS_PH 604 +#define MUT_QUEST_SENS_CPLX 605 +#define MUT_QUEST_SENS_DC 606 + +#endif /*MUTUAL*/ + +#include "indext.h" + +#endif /*IND*/ diff --git a/src/spicelib/devices/ind/inddel.c b/src/spicelib/devices/ind/inddel.c new file mode 100644 index 000000000..faabba275 --- /dev/null +++ b/src/spicelib/devices/ind/inddel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +INDdelete(inModel,name,kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; +{ + INDmodel *model = (INDmodel*)inModel; + INDinstance **fast = (INDinstance**)kill; + INDinstance **prev = NULL; + INDinstance *here; + + for( ; model ; model = model->INDnextModel) { + prev = &(model->INDinstances); + for(here = *prev; here ; here = *prev) { + if(here->INDname == name || (fast && here==*fast) ) { + *prev= here->INDnextInstance; + FREE(here); + return(OK); + } + prev = &(here->INDnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/ind/inddest.c b/src/spicelib/devices/ind/inddest.c new file mode 100644 index 000000000..072162b8b --- /dev/null +++ b/src/spicelib/devices/ind/inddest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "suffix.h" + + +void +INDdestroy(inModel) + GENmodel **inModel; +{ + INDmodel **model = (INDmodel**)inModel; + INDinstance *here; + INDinstance *prev = NULL; + INDmodel *mod = *model; + INDmodel *oldmod = NULL; + + for( ; mod ; mod = mod->INDnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (INDinstance *)NULL; + for(here = mod->INDinstances ; here ; here = here->INDnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/ind/indext.h b/src/spicelib/devices/ind/indext.h new file mode 100644 index 000000000..02687490a --- /dev/null +++ b/src/spicelib/devices/ind/indext.h @@ -0,0 +1,68 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int INDacLoad(GENmodel*,CKTcircuit*); +extern int INDask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int INDdelete(GENmodel*,IFuid,GENinstance**); +extern void INDdestroy(GENmodel**); +extern int INDload(GENmodel*,CKTcircuit*); +extern int INDmDelete(GENmodel**,IFuid,GENmodel*); +extern int INDparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int INDpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int INDsAcLoad(GENmodel*,CKTcircuit*); +extern int INDsLoad(GENmodel*,CKTcircuit*); +extern void INDsPrint(GENmodel*,CKTcircuit*); +extern int INDsSetup(SENstruct*,GENmodel*); +extern int INDsUpdate(GENmodel*,CKTcircuit*); +extern int INDsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int INDunsetup(GENmodel*,CKTcircuit*); +extern int INDtrunc(GENmodel*,CKTcircuit*,double*); +#else /* stdc */ +extern int INDacLoad(); +extern int INDask(); +extern int INDdelete(); +extern void INDdestroy(); +extern int INDload(); +extern int INDmDelete(); +extern int INDparam(); +extern int INDpzLoad(); +extern int INDsAcLoad(); +extern int INDsLoad(); +extern void INDsPrint(); +extern int INDsSetup(); +extern int INDsUpdate(); +extern int INDsetup(); +extern int INDunsetup(); +extern int INDtrunc(); +#endif /* stdc */ + +#ifdef MUTUAL + +#ifdef __STDC__ +extern int MUTacLoad(GENmodel*,CKTcircuit*); +extern int MUTask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int MUTdelete(GENmodel*,IFuid,GENinstance**); +extern void MUTdestroy(GENmodel**); +extern int MUTmDelete(GENmodel**,IFuid,GENmodel*); +extern int MUTparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int MUTpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern void MUTsPrint(GENmodel*,CKTcircuit*); +extern int MUTsSetup(SENstruct*,GENmodel*); +extern int MUTsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +#else /* stdc */ +extern int MUTacLoad(); +extern int MUTask(); +extern int MUTdelete(); +extern void MUTdestroy(); +extern int MUTmDelete(); +extern int MUTparam(); +extern int MUTpzLoad(); +extern void MUTsPrint(); +extern int MUTsSetup(); +extern int MUTsetup(); +#endif /* stdc */ + +#endif diff --git a/src/spicelib/devices/ind/inditf.h b/src/spicelib/devices/ind/inditf.h new file mode 100644 index 000000000..faeaae5df --- /dev/null +++ b/src/spicelib/devices/ind/inditf.h @@ -0,0 +1,163 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_ind + +#ifndef DEV_IND +#define DEV_IND + +#define MUTUAL + +#include "indext.h" +extern IFparm INDpTable[ ]; +extern char *INDnames[ ]; +extern int INDpTSize; +extern int INDnSize; +extern int INDiSize; +extern int INDmSize; + +SPICEdev INDinfo = { + { + "Inductor", + "Inductors", + + &INDnSize, + &INDnSize, + INDnames, + + &INDpTSize, + INDpTable, + + 0, + NULL, + 0 + }, + + INDparam, + NULL, + INDload, + INDsetup, + INDunsetup, + INDsetup, + NULL, + INDtrunc, + NULL, + INDacLoad, + NULL, + INDdestroy, +#ifdef DELETES + INDmDelete, + INDdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + INDask, + NULL, +#ifdef AN_pz + INDpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense2 + INDsSetup, + INDsLoad, + INDsUpdate, + INDsAcLoad, + INDsPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense */ + NULL, /* DISTO */ + NULL, /* NOISE */ + + &INDiSize, + &INDmSize + +}; + +#ifdef MUTUAL +extern IFparm MUTpTable[ ]; +extern int MUTpTSize; +extern int MUTiSize; +extern int MUTmSize; + +SPICEdev MUTinfo = { + { + "mutual", + "Mutual inductors", + 0, /* term count */ + 0, /* term count */ + NULL, + + &MUTpTSize, + MUTpTable, + + 0, + NULL, + 0 + }, + + MUTparam, + NULL, + NULL,/* load handled by INDload */ + MUTsetup, + NULL, + MUTsetup, + NULL, + NULL, + NULL, + MUTacLoad, + NULL, + MUTdestroy, +#ifdef DELETES + MUTmDelete, + MUTdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + MUTask, + NULL, +#ifdef AN_pz + MUTpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense + MUTsSetup, + NULL, + NULL, + NULL, + MUTsPrint, + NULL, +#else /* AN_sense */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense */ + NULL, /* DISTO */ + NULL, /* NOISE */ + + &MUTiSize, + &MUTmSize + +}; + +#endif /*MUTUAL*/ + +#endif +#endif diff --git a/src/spicelib/devices/ind/indload.c b/src/spicelib/devices/ind/indload.c new file mode 100644 index 000000000..df26dfb26 --- /dev/null +++ b/src/spicelib/devices/ind/indload.c @@ -0,0 +1,121 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* actually load the current inductance value into the + * sparse matrix previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "inddefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +INDload(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + double veq; + double req; + int error; +#ifdef MUTUAL + register MUTinstance *muthere; + register MUTmodel *mutmodel; + int ktype; + int itype; +#endif + + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + + if(!(ckt->CKTmode & (MODEDC|MODEINITPRED))) { + if(ckt->CKTmode & MODEUIC && ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate0 + here->INDflux) = here->INDinduct * + here->INDinitCond; + } else { + *(ckt->CKTstate0 + here->INDflux) = here->INDinduct * + *(ckt->CKTrhsOld + here->INDbrEq); + } + } +#ifdef MUTUAL + } + } + ktype = CKTtypelook("mutual"); + mutmodel = (MUTmodel *)(ckt->CKThead[ktype]); + /* loop through all the mutual inductor models */ + for( ; mutmodel != NULL; mutmodel = mutmodel->MUTnextModel ) { + + /* loop through all the instances of the model */ + for (muthere = mutmodel->MUTinstances; muthere != NULL ; + muthere=muthere->MUTnextInstance) { + if (muthere->MUTowner != ARCHme) continue; + + if(!(ckt->CKTmode& (MODEDC|MODEINITPRED))) { + *(ckt->CKTstate0 + muthere->MUTind1->INDflux) += + muthere->MUTfactor * *(ckt->CKTrhsOld+ + muthere->MUTind2->INDbrEq); + *(ckt->CKTstate0 + muthere->MUTind2->INDflux) += + muthere->MUTfactor * *(ckt->CKTrhsOld+ + muthere->MUTind1->INDbrEq); + } + *(muthere->MUTbr1br2) -= muthere->MUTfactor*ckt->CKTag[0]; + *(muthere->MUTbr2br1) -= muthere->MUTfactor*ckt->CKTag[0]; + } + } + itype = CKTtypelook("Inductor"); + model = (INDmodel *)(ckt->CKThead[itype]); + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + +#endif /*MUTUAL*/ + if(ckt->CKTmode & MODEDC) { + req = 0; + veq = 0; + } else { +#ifndef PREDICTOR + if(ckt->CKTmode & MODEINITPRED) { + *(ckt->CKTstate0 + here->INDflux) = + *(ckt->CKTstate1 + here->INDflux); + } else { +#endif /*PREDICTOR*/ + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->INDflux) = + *(ckt->CKTstate0 + here->INDflux); + } +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + error=NIintegrate(ckt,&req,&veq,here->INDinduct,here->INDflux); + if(error) return(error); + } + *(ckt->CKTrhs+here->INDbrEq) += veq; + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1+here->INDvolt) = + *(ckt->CKTstate0+here->INDvolt); + } + *(here->INDposIbrptr) += 1; + *(here->INDnegIbrptr) -= 1; + *(here->INDibrPosptr) += 1; + *(here->INDibrNegptr) -= 1; + *(here->INDibrIbrptr) -= req; + } + } + return(OK); +} diff --git a/src/spicelib/devices/ind/indmdel.c b/src/spicelib/devices/ind/indmdel.c new file mode 100644 index 000000000..827a29133 --- /dev/null +++ b/src/spicelib/devices/ind/indmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +INDmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + INDmodel **model = (INDmodel**)inModel; + INDmodel *modfast = (INDmodel*)kill; + INDinstance *here; + INDinstance *prev = NULL; + INDmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->INDnextModel)) { + if( (*model)->INDmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->INDnextModel; /* cut deleted device out of list */ + for(here = (*model)->INDinstances ; here ; here = here->INDnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/ind/indparam.c b/src/spicelib/devices/ind/indparam.c new file mode 100644 index 000000000..f2deb4b71 --- /dev/null +++ b/src/spicelib/devices/ind/indparam.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +INDparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + INDinstance *here = (INDinstance*)inst; + switch(param) { + case IND_IND: + here->INDinduct = value->rValue; + here->INDindGiven = TRUE; + break; + case IND_IC: + here->INDinitCond = value->rValue; + here->INDicGiven = TRUE; + break; + case IND_IND_SENS: + here->INDsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/ind/indpzld.c b/src/spicelib/devices/ind/indpzld.c new file mode 100644 index 000000000..b195c304b --- /dev/null +++ b/src/spicelib/devices/ind/indpzld.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "inddefs.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +INDpzLoad(inModel,ckt,s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; +{ + register INDmodel *model = (INDmodel*)inModel; + double val; + register INDinstance *here; + + for( ; model != NULL; model = model->INDnextModel) { + for( here = model->INDinstances;here != NULL; + here = here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + + val = here->INDinduct; + *(here->INDposIbrptr) += 1; + *(here->INDnegIbrptr) -= 1; + *(here->INDibrPosptr) += 1; + *(here->INDibrNegptr) -= 1; + *(here->INDibrIbrptr ) -= val * s->real; + *(here->INDibrIbrptr +1) -= val * s->imag; + } + } + return(OK); + +} diff --git a/src/spicelib/devices/ind/indsacl.c b/src/spicelib/devices/ind/indsacl.c new file mode 100644 index 000000000..76dbeda9a --- /dev/null +++ b/src/spicelib/devices/ind/indsacl.c @@ -0,0 +1,171 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +INDsAcLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + double cind,icind,val,ival; +#ifdef MUTUAL + register MUTinstance *muthere; + register MUTmodel *mutmodel; + double cind1; + double icind1; + double cind2; + double icind2; + double val11; + double ival11; + double val12; + double ival12; + double val13; + double ival13; + double val21; + double ival21; + double val22; + double ival22; + double val23; + double ival23; + double rootl1; + double rootl2; + double w; + double k1; + double k2; + int ktype; + int itype; +#endif + SENstruct *info; + + info = ckt->CKTsenInfo; + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + +#ifdef MUTUAL + } + } + ktype = CKTtypelook("mutual"); + mutmodel = (MUTmodel *)(ckt->CKThead[ktype]); + /* loop through all the mutual inductor models */ + for( ; mutmodel != NULL; mutmodel = mutmodel->MUTnextModel ) { + + /* loop through all the instances of the model */ + for (muthere = mutmodel->MUTinstances; muthere != NULL ; + muthere=muthere->MUTnextInstance) { + + if(muthere->MUTsenParmNo || + muthere->MUTind1->INDsenParmNo || + muthere->MUTind2->INDsenParmNo){ + + cind1 = *(ckt->CKTrhsOld + muthere->MUTind1->INDbrEq); + icind1 = *(ckt->CKTirhsOld + muthere->MUTind1->INDbrEq); + cind2 = *(ckt->CKTrhsOld + muthere->MUTind2->INDbrEq); + icind2 = *(ckt->CKTirhsOld + muthere->MUTind2->INDbrEq); + rootl1 = sqrt(muthere->MUTind1->INDinduct) ; + rootl2 = sqrt(muthere->MUTind2->INDinduct) ; + k1 = 0.5 * muthere->MUTcoupling * rootl2 / rootl1 ; + k2 = 0.5 * muthere->MUTcoupling * rootl1 / rootl2 ; + w = ckt->CKTomega ; + + /* load the RHS matrix */ + + if(muthere->MUTind1->INDsenParmNo){ + val11 = - (w * (k1 * icind2)); + ival11 = w * (k1 * cind2); + val21 = - ( w * k1 * icind1) ; + ival21 = w * k1 * cind1 ; + *(info->SEN_RHS[muthere->MUTind1->INDbrEq] + + muthere->MUTind1->INDsenParmNo) += val11; + *(info->SEN_iRHS[muthere->MUTind1->INDbrEq] + + muthere->MUTind1->INDsenParmNo) += ival11; + *(info->SEN_RHS[muthere->MUTind2->INDbrEq] + + muthere->MUTind1->INDsenParmNo) += val21; + *(info->SEN_iRHS[muthere->MUTind2->INDbrEq] + + muthere->MUTind1->INDsenParmNo) += ival21; + } + + if(muthere->MUTind2->INDsenParmNo){ + val12 = -( w * k2 * icind2) ; + ival12 = w * k2 * cind2 ; + val22 = - (w * ( k2 * icind1)); + ival22 = w * ( k2 * cind1); + *(info->SEN_RHS[muthere->MUTind1->INDbrEq] + + muthere->MUTind2->INDsenParmNo) += val12; + *(info->SEN_iRHS[muthere->MUTind1->INDbrEq] + + muthere->MUTind2->INDsenParmNo) += ival12; + *(info->SEN_RHS[muthere->MUTind2->INDbrEq] + + muthere->MUTind2->INDsenParmNo) += val22; + *(info->SEN_iRHS[muthere->MUTind2->INDbrEq] + + muthere->MUTind2->INDsenParmNo) += ival22; + } + + if(muthere->MUTsenParmNo){ + val13 = - w * rootl1 * rootl2 * icind2; + ival13 = w * rootl1 * rootl2 * cind2; + val23 = - (w * rootl1 * rootl2 * icind1); + ival23 = w * rootl1 * rootl2 * cind1; + *(info->SEN_RHS[muthere->MUTind1->INDbrEq] + + muthere->MUTsenParmNo) += val13; + *(info->SEN_iRHS[muthere->MUTind1->INDbrEq] + + muthere->MUTsenParmNo) += ival13; + *(info->SEN_RHS[muthere->MUTind2->INDbrEq] + + muthere->MUTsenParmNo) += val23; + *(info->SEN_iRHS[muthere->MUTind2->INDbrEq] + + muthere->MUTsenParmNo) += ival23; + } + } + } + } + itype = CKTtypelook("Inductor"); + model = (INDmodel *)(ckt->CKThead[itype]); + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { +#endif /* MUTUAL */ + if(here->INDsenParmNo){ + cind = *(ckt->CKTrhsOld + here->INDbrEq); + icind = *(ckt->CKTirhsOld + here->INDbrEq); + val = icind * ckt->CKTomega ; + ival = cind * ckt->CKTomega ; + +#ifdef SENSDEBUG + fprintf(file,"cind = %.5e,icind = %.5e\n",cind,icind); + fprintf(file,"val = %.5e,ival = %.5e\n",val,ival); + fprintf(file,"brEq = %.5e,senparmno = %.5e\n", + here->INDbrEq,here->INDsenParmNo); +#endif /* SENSDEBUG */ + + /* load the RHS matrix */ + + *(info->SEN_RHS[here->INDbrEq] + here->INDsenParmNo) + -= val; + *(info->SEN_iRHS[here->INDbrEq] + here->INDsenParmNo) + += ival; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/ind/indsetup.c b/src/spicelib/devices/ind/indsetup.c new file mode 100644 index 000000000..04e1965f0 --- /dev/null +++ b/src/spicelib/devices/ind/indsetup.c @@ -0,0 +1,89 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +INDsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the inductor structure with those pointers needed later + * for fast matrix loading + */ +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) goto matrixpointers; + + here->INDflux = *states; + *states += 2 ; + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ + *states += 2 * (ckt->CKTsenInfo->SENparms); + } + +matrixpointers: + if(here->INDbrEq == 0) { + error = CKTmkCur(ckt,&tmp,here->INDname,"branch"); + if(error) return(error); + here->INDbrEq = tmp->number; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(INDposIbrptr,INDposNode,INDbrEq) + TSTALLOC(INDnegIbrptr,INDnegNode,INDbrEq) + TSTALLOC(INDibrNegptr,INDbrEq,INDnegNode) + TSTALLOC(INDibrPosptr,INDbrEq,INDposNode) + TSTALLOC(INDibrIbrptr,INDbrEq,INDbrEq) + } + } + return(OK); +} + +int +INDunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + INDmodel *model; + INDinstance *here; + + for (model = (INDmodel *)inModel; model != NULL; + model = model->INDnextModel) + { + for (here = model->INDinstances; here != NULL; + here=here->INDnextInstance) + { + if (here->INDbrEq) { + CKTdltNNum(ckt, here->INDbrEq); + here->INDbrEq = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/ind/indsload.c b/src/spicelib/devices/ind/indsload.c new file mode 100644 index 000000000..7c23b4349 --- /dev/null +++ b/src/spicelib/devices/ind/indsload.c @@ -0,0 +1,150 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +INDsLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + int iparmno; + double cind; + double Osxp; + double tag0; + double tag1; + SENstruct *info; + +#ifdef MUTUAL + register MUTinstance *muthere; + register MUTmodel *mutmodel; + double cind1; + double cind2; + double rootl1; + double rootl2; + int ktype; + int itype; + int IND1_brEq; + int IND2_brEq; +#endif + + info = ckt->CKTsenInfo; + + if((info->SENmode == DCSEN)||(ckt->CKTmode&MODETRANOP)) return( OK ); + if((info->SENmode == TRANSEN) && (ckt->CKTmode & MODEINITTRAN)) return(OK); + +#ifdef SENSDEBUG + fprintf(file,"INDsenLoad\n"); + fprintf(file,"time = %.5e\n",ckt->CKTtime); +#endif /* SENSDEBUG */ + + + tag0 = ckt->CKTag[0]; + tag1 = ckt->CKTag[1]; + if(ckt->CKTorder == 1){ + tag1 = 0; + } + + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + +#ifdef MUTUAL + } + } + ktype = CKTtypelook("mutual"); + mutmodel = (MUTmodel *)(ckt->CKThead[ktype]); + /* loop through all the mutual inductor models */ + for( ; mutmodel != NULL; mutmodel = mutmodel->MUTnextModel ) { + + /* loop through all the instances of the model */ + for (muthere = mutmodel->MUTinstances; muthere != NULL ; + muthere=muthere->MUTnextInstance) { + if (muthere->MUTowner != ARCHme) continue; + + if(muthere->MUTsenParmNo || + muthere->MUTind1->INDsenParmNo || + muthere->MUTind2->INDsenParmNo){ + + IND1_brEq = muthere->MUTind1->INDbrEq; + IND2_brEq = muthere->MUTind2->INDbrEq; + cind1 = *(ckt->CKTrhsOld + IND1_brEq); + cind2 = *(ckt->CKTrhsOld + IND2_brEq); + rootl1 = sqrt( muthere->MUTind1->INDinduct ); + rootl2 = sqrt( muthere->MUTind2->INDinduct ); + + if(muthere->MUTsenParmNo){ + *(info->SEN_RHS[IND1_brEq] + muthere->MUTsenParmNo) + += tag0*cind2*rootl2*rootl1; + *(info->SEN_RHS[IND2_brEq] + muthere->MUTsenParmNo) + += tag0*cind1*rootl2*rootl1; + } + if(muthere->MUTind1->INDsenParmNo){ + *(info->SEN_RHS[IND1_brEq] + muthere->MUTind1->INDsenParmNo) + += tag0*cind2*muthere->MUTcoupling*rootl2 / (2*rootl1); + *(info->SEN_RHS[IND2_brEq] + muthere->MUTind1->INDsenParmNo) + += tag0*cind1*muthere->MUTcoupling*rootl2 / (2*rootl1); + } + if(muthere->MUTind2->INDsenParmNo){ + *(info->SEN_RHS[IND1_brEq] + muthere->MUTind2->INDsenParmNo) + += tag0*cind2*muthere->MUTcoupling*rootl1 / (2*rootl2); + *(info->SEN_RHS[IND2_brEq] + muthere->MUTind2->INDsenParmNo) + += tag0*cind1*muthere->MUTcoupling*rootl1 / (2*rootl2); + } + } + +#ifdef SENSDEBUG + fprintf(file,"cind1 = %.5e,cind2 = %.5e\n",cind1,cind2); +#endif /* SENSDEBUG */ + + } + } + itype = CKTtypelook("Inductor"); + model = (INDmodel *)(ckt->CKThead[itype]); + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + +#endif /* MUTUAL */ + cind = *(ckt->CKTrhsOld + here->INDbrEq); +#ifdef SENSDEBUG + fprintf(file,"\n cind=%.5e\n",cind); + fprintf(file,"\n tag0=%.5e,tag1=%.5e\n",tag0,tag1); +#endif /* SENSDEBUG */ + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + Osxp = tag0 * *(ckt->CKTstate1 + here->INDsensxp + + 2*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->INDsensxp + + 2*(iparmno - 1) + 1); + if(iparmno == here->INDsenParmNo) Osxp = Osxp - tag0 * cind; +#ifdef SENSDEBUG + fprintf(file,"\n Osxp=%.5e\n",Osxp); +#endif /* SENSDEBUG */ + + *(info->SEN_RHS[here->INDbrEq] + iparmno) -= Osxp; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/ind/indsprt.c b/src/spicelib/devices/ind/indsprt.c new file mode 100644 index 000000000..afc5b6be6 --- /dev/null +++ b/src/spicelib/devices/ind/indsprt.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* Pretty print the sensitivity info for all + * the inductors in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + +void +INDsPrint(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + + printf("INDUCTORS----------\n"); + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + printf("Model name:%s\n",model->INDmodName); + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->INDname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->INDposNode),CKTnodName(ckt,here->INDnegNode)); + printf(" Branch Equation: %s\n",CKTnodName(ckt,here->INDbrEq)); + printf(" Inductance: %g ",here->INDinduct); + printf(here->INDindGiven ? "(specified)\n" : "(default)\n"); + printf(" INDsenParmNo:%d\n",here->INDsenParmNo); + } + } +} diff --git a/src/spicelib/devices/ind/indsset.c b/src/spicelib/devices/ind/indsset.c new file mode 100644 index 000000000..c5d1cb785 --- /dev/null +++ b/src/spicelib/devices/ind/indsset.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +INDsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + + if(here->INDsenParmNo){ + here->INDsenParmNo = ++(info->SENparms); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/ind/indsupd.c b/src/spicelib/devices/ind/indsupd.c new file mode 100644 index 000000000..79fdc0c2b --- /dev/null +++ b/src/spicelib/devices/ind/indsupd.c @@ -0,0 +1,154 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* update the charge sensitivities and their derivatives */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + +int +INDsUpdate(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + double cind; + double sxp; + double s1; + double s2; + double s; + int iparmno; + double dummy1; + double dummy2; + SENstruct *info; +#ifdef MUTUAL + register MUTinstance *muthere; + register MUTmodel *mutmodel; + double sxp1; + double sxp2; + double cind1,cind2; + double rootl1,rootl2; + int ktype; + int itype; +#endif + + info = ckt->CKTsenInfo; + if(ckt->CKTmode & MODEINITTRAN) return(OK); + + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + + cind = *(ckt->CKTrhsOld + here->INDbrEq); + s = *(info->SEN_Sap[here->INDbrEq] + iparmno); + sxp = here->INDinduct * s; + +#ifdef SENSDEBUG + printf("iparmno = %d,s=%.5e,cind = %.5e\n",iparmno,s,cind); + printf("sxp(before mut) = %.5e\n",sxp); +#endif /* SENSDEBUG */ + + if(iparmno == here->INDsenParmNo) sxp += cind; + + + *(ckt->CKTstate0 + here->INDsensxp + 2 * (iparmno - 1)) = sxp; + } + + +#ifdef MUTUAL + } + } + ktype = CKTtypelook("mutual"); + mutmodel = (MUTmodel *)(ckt->CKThead[ktype]); + /* loop through all the mutual inductor models */ + for( ; mutmodel != NULL; mutmodel = mutmodel->MUTnextModel ) { + + /* loop through all the instances of the model */ + for (muthere = mutmodel->MUTinstances; muthere != NULL ; + muthere=muthere->MUTnextInstance) { + + + cind1 = *(ckt->CKTrhsOld + muthere->MUTind1->INDbrEq); + cind2 = *(ckt->CKTrhsOld + muthere->MUTind2->INDbrEq); + rootl1 = sqrt( muthere->MUTind1->INDinduct ); + rootl2 = sqrt( muthere->MUTind2->INDinduct ); + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + s1 = *(info->SEN_Sap[muthere->MUTind1->INDbrEq] + iparmno); + s2 = *(info->SEN_Sap[muthere->MUTind2->INDbrEq] + iparmno); + sxp2 = muthere->MUTcoupling*rootl1*rootl2 * s1; + sxp1 = muthere->MUTcoupling*rootl1*rootl2 * s2; + if(iparmno == muthere->MUTsenParmNo){ + sxp1 += cind2 * rootl1 * rootl2; + sxp2 += cind1 * rootl1 * rootl2; + } + if(iparmno == muthere->MUTind1->INDsenParmNo){ + sxp1 += cind2 * muthere->MUTcoupling * rootl2 /(2 * rootl1); + sxp2 += cind1 * muthere->MUTcoupling * rootl2 /(2 * rootl1); + } + if(iparmno == muthere->MUTind2->INDsenParmNo){ + sxp1 += cind2 * muthere->MUTcoupling * rootl1 /(2 * rootl2); + sxp2 += cind1 * muthere->MUTcoupling * rootl1 /(2 * rootl2); + } + + + *(ckt->CKTstate0 + muthere->MUTind1->INDsensxp + 2 * + (iparmno - 1)) += sxp1; + + *(ckt->CKTstate0 + muthere->MUTind2->INDsensxp + 2 * + (iparmno - 1)) += sxp2; + +#ifdef SENSDEBUG + printf("iparmno = %d\n",iparmno); + printf("sxp1 = %.5e,sxp2 = %.5e\n",sxp1,sxp2); +#endif /* SENSDEBUG */ + } + + } + } + + + itype = CKTtypelook("Inductor"); + model = (INDmodel *)(ckt->CKThead[itype]); + /* loop through all the inductor models */ + for( ; model != NULL; model = model->INDnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->INDinstances; here != NULL ; + here=here->INDnextInstance) { +#endif /* MUTUAL */ + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + + if(ckt->CKTmode&MODETRANOP){ + *(ckt->CKTstate0 + here->INDsensxp + 2 * + (iparmno - 1) + 1) = 0; + } else{ + NIintegrate(ckt,&dummy1,&dummy2,here->INDinduct, + (here->INDsensxp + 2*(iparmno - 1))); + } +#ifdef SENSDEBUG + printf("sxp = %.5e,sdotxp = %.5e\n", + *(ckt->CKTstate0 + here->INDsensxp + 2 * + (iparmno - 1)), + *(ckt->CKTstate0 + here->INDsensxp + 2 * + (iparmno - 1) + 1)); +#endif /* SENSDEBUG */ + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/ind/indtrunc.c b/src/spicelib/devices/ind/indtrunc.c new file mode 100644 index 000000000..e97f29b25 --- /dev/null +++ b/src/spicelib/devices/ind/indtrunc.c @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +INDtrunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + register double *timeStep; +{ + register INDmodel *model = (INDmodel*)inModel; + register INDinstance *here; + for( ; model!= NULL; model = model->INDnextModel) { + for(here = model->INDinstances ; here != NULL ; + here = here->INDnextInstance) { + if (here->INDowner != ARCHme) continue; + + CKTterr(here->INDflux,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/ind/mutacld.c b/src/spicelib/devices/ind/mutacld.c new file mode 100644 index 000000000..6ef7121ea --- /dev/null +++ b/src/spicelib/devices/ind/mutacld.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +#ifdef MUTUAL +int +MUTacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MUTmodel *model = (MUTmodel*)inModel; + double val; + register MUTinstance *here; + + for( ; model != NULL; model = model->MUTnextModel) { + for( here = model->MUTinstances;here != NULL; + here = here->MUTnextInstance) { + if (here->MUTowner != ARCHme) continue; + + val = ckt->CKTomega * here->MUTfactor; + *(here->MUTbr1br2 +1) -= val; + *(here->MUTbr2br1 +1) -= val; + } + } + return(OK); + +} +#endif /* MUTUAL */ diff --git a/src/spicelib/devices/ind/mutask.c b/src/spicelib/devices/ind/mutask.c new file mode 100644 index 000000000..69cb6b26c --- /dev/null +++ b/src/spicelib/devices/ind/mutask.c @@ -0,0 +1,106 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "sperror.h" +#include "suffix.h" + +#ifdef MUTUAL + +/*ARGSUSED*/ +int +MUTask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + MUTinstance *here = (MUTinstance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + switch(which) { + case MUT_COEFF: + value->rValue = here->MUTfactor; + return(OK); + case MUT_IND1: + value->uValue = here->MUTindName1; + return(OK); + case MUT_IND2: + value->uValue = here->MUTindName2; + return(OK); + case MUT_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MUTsenParmNo); + } + return(OK); + case MUT_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MUTsenParmNo); + } + return(OK); + case MUT_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MUTsenParmNo); + } + return(OK); + case MUT_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MUTsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MUTsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MUT_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MUTsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MUTsenParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MUT_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MUTsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MUTsenParmNo); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} +#endif /* MUTUAL */ diff --git a/src/spicelib/devices/ind/mutdel.c b/src/spicelib/devices/ind/mutdel.c new file mode 100644 index 000000000..ba993efa0 --- /dev/null +++ b/src/spicelib/devices/ind/mutdel.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +#ifdef MUTUAL +int +MUTdelete(inModel,name,kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; +{ + MUTmodel *model = (MUTmodel*)inModel; + MUTinstance **fast = (MUTinstance**)kill; + MUTinstance **prev = NULL; + MUTinstance *here; + + for( ; model ; model = model->MUTnextModel) { + prev = &(model->MUTinstances); + for(here = *prev; here ; here = *prev) { + if(here->MUTname == name || (fast && here==*fast) ) { + *prev= here->MUTnextInstance; + FREE(here); + return(OK); + } + prev = &(here->MUTnextInstance); + } + } + return(E_NODEV); +} +#endif /*MUTUAL*/ diff --git a/src/spicelib/devices/ind/mutdest.c b/src/spicelib/devices/ind/mutdest.c new file mode 100644 index 000000000..a8a104e04 --- /dev/null +++ b/src/spicelib/devices/ind/mutdest.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "suffix.h" + + +#ifdef MUTUAL +void +MUTdestroy(inModel) + GENmodel **inModel; +{ + MUTmodel **model = (MUTmodel**)inModel; + MUTinstance *here; + MUTinstance *prev = NULL; + MUTmodel *mod = *model; + MUTmodel *oldmod = NULL; + + for( ; mod ; mod = mod->MUTnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (MUTinstance *)NULL; + for(here = mod->MUTinstances ; here ; here = here->MUTnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} +#endif /* MUTUAL */ diff --git a/src/spicelib/devices/ind/mutmdel.c b/src/spicelib/devices/ind/mutmdel.c new file mode 100644 index 000000000..fe31fb7ac --- /dev/null +++ b/src/spicelib/devices/ind/mutmdel.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +#ifdef MUTUAL +int +MUTmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + MUTmodel **model = (MUTmodel**)inModel; + MUTmodel *modfast = (MUTmodel*)kill; + MUTinstance *here; + MUTinstance *prev = NULL; + MUTmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->MUTnextModel)) { + if( (*model)->MUTmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->MUTnextModel; /* cut deleted device out of list */ + for(here = (*model)->MUTinstances ; here ; here = here->MUTnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} +#endif /* MUTUAL */ diff --git a/src/spicelib/devices/ind/mutparam.c b/src/spicelib/devices/ind/mutparam.c new file mode 100644 index 000000000..983a80dac --- /dev/null +++ b/src/spicelib/devices/ind/mutparam.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +#ifdef MUTUAL +/* ARGSUSED */ +int +MUTparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + MUTinstance *here = (MUTinstance*)inst; + switch(param) { + case MUT_COEFF: + here->MUTcoupling = value->rValue; + here->MUTindGiven = TRUE; + break; + case MUT_IND1: + here->MUTindName1 = value->uValue; + break; + case MUT_IND2: + here->MUTindName2 = value->uValue; + break; + case MUT_COEFF_SENS: + here->MUTsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} +#endif /* MUTUAL */ diff --git a/src/spicelib/devices/ind/mutpzld.c b/src/spicelib/devices/ind/mutpzld.c new file mode 100644 index 000000000..983288eda --- /dev/null +++ b/src/spicelib/devices/ind/mutpzld.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "inddefs.h" +#include "suffix.h" + + +#ifdef MUTUAL +/* ARGSUSED */ +int +MUTpzLoad(inModel,ckt,s) + GENmodel *inModel; + CKTcircuit *ckt; + register SPcomplex *s; +{ + register MUTmodel *model = (MUTmodel*)inModel; + double val; + register MUTinstance *here; + + for( ; model != NULL; model = model->MUTnextModel) { + for( here = model->MUTinstances;here != NULL; + here = here->MUTnextInstance) { + if (here->MUTowner != ARCHme) continue; + + val = here->MUTfactor; + *(here->MUTbr1br2 ) -= val * s->real; + *(here->MUTbr1br2 +1) -= val * s->imag; + *(here->MUTbr2br1 ) -= val * s->real; + *(here->MUTbr2br1 +1) -= val * s->imag; + } + } + return(OK); + +} +#endif /*MUTUAL*/ diff --git a/src/spicelib/devices/ind/mutsetup.c b/src/spicelib/devices/ind/mutsetup.c new file mode 100644 index 000000000..16d67a50d --- /dev/null +++ b/src/spicelib/devices/ind/mutsetup.c @@ -0,0 +1,88 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* load the inductor structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +#ifdef MUTUAL +/*ARGSUSED*/ +int +MUTsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; +{ + register MUTmodel *model = (MUTmodel*)inModel; + register MUTinstance *here; + int ktype; + int error; + + /* loop through all the inductor models */ + for( ; model != NULL; model = model->MUTnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MUTinstances; here != NULL ; + here=here->MUTnextInstance) { + + ktype = CKTtypelook("Inductor"); + if(ktype <= 0) { + (*(SPfrontEnd->IFerror))(ERR_PANIC, + "mutual inductor, but inductors not available!", + (IFuid *)NULL); + return(E_INTERN); + } + + error = CKTfndDev((void *)ckt,&ktype,(void **)&(here->MUTind1), + here->MUTindName1, (void *)NULL,(char *)NULL); + if(error && error!= E_NODEV && error != E_NOMOD) return(error); + if(error) { + IFuid namarray[2]; + namarray[0]=here->MUTname; + namarray[1]=here->MUTindName1; + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: coupling to non-existant inductor %s.", + namarray); + } + error = CKTfndDev((void *)ckt,&ktype,(void **)&(here->MUTind2), + here->MUTindName2,(void *)NULL,(char *)NULL); + if(error && error!= E_NODEV && error != E_NOMOD) return(error); + if(error) { + IFuid namarray[2]; + namarray[0]=here->MUTname; + namarray[1]=here->MUTindName2; + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: coupling to non-existant inductor %s.", + namarray); + } + + here->MUTfactor = here->MUTcoupling *sqrt(here->MUTind1->INDinduct * + here->MUTind2->INDinduct); + + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(MUTbr1br2,MUTind1->INDbrEq,MUTind2->INDbrEq) + TSTALLOC(MUTbr2br1,MUTind2->INDbrEq,MUTind1->INDbrEq) + } + } + return(OK); +} +#endif /* MUTUAL */ diff --git a/src/spicelib/devices/ind/mutsprt.c b/src/spicelib/devices/ind/mutsprt.c new file mode 100644 index 000000000..7bd8035e6 --- /dev/null +++ b/src/spicelib/devices/ind/mutsprt.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* Pretty print the sensitivity info for all + * the mutual inductors in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + + +#ifdef MUTUAL +/* ARGSUSED */ +void +MUTsPrint(inModel,ckt) + GENmodel *inModel; + CKTcircuit* ckt; +{ + register MUTmodel *model = (MUTmodel*)inModel; + register MUTinstance *here; + + printf("MUTUAL INDUCTORS-----------------\n"); + /* loop through all the inductor models */ + for( ; model != NULL; model = model->MUTnextModel ) { + + printf("Model name:%s\n",model->MUTmodName); + + /* loop through all the instances of the model */ + for (here = model->MUTinstances; here != NULL ; + here=here->MUTnextInstance) { + if (here->MUTowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->MUTname); + printf(" Mutual Inductance: %g ",here->MUTcoupling); + printf(here->MUTindGiven ? "(specified)\n" : "(default)\n"); + printf(" coupling factor: %g \n",here->MUTfactor); + printf(" inductor 1 name: %s \n",here->MUTindName1); + printf(" inductor 2 name: %s \n",here->MUTindName2); + printf(" MUTsenParmNo:%d\n",here->MUTsenParmNo); + + } + } +} +#endif /* MUTUAL */ diff --git a/src/spicelib/devices/ind/mutsset.c b/src/spicelib/devices/ind/mutsset.c new file mode 100644 index 000000000..e264dec0b --- /dev/null +++ b/src/spicelib/devices/ind/mutsset.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "inddefs.h" +#include "sperror.h" +#include "suffix.h" + +#ifdef MUTUAL +/*ARGSUSED*/ +int +MUTsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register MUTmodel *model = (MUTmodel*)inModel; + register MUTinstance *here; + + /* loop through all the inductor models */ + for( ; model != NULL; model = model->MUTnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MUTinstances; here != NULL ; + here=here->MUTnextInstance) { + if (here->MUTowner != ARCHme) continue; + + if(here->MUTsenParmNo){ + here->MUTsenParmNo = ++(info->SENparms); + } + + + } + } + return(OK); +} +#endif /* MUTUAL */ + diff --git a/src/spicelib/devices/isrc/ChangeLog b/src/spicelib/devices/isrc/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/isrc/Makefile.am b/src/spicelib/devices/isrc/Makefile.am new file mode 100644 index 000000000..0c691535b --- /dev/null +++ b/src/spicelib/devices/isrc/Makefile.am @@ -0,0 +1,23 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libisrc.la + +libisrc_la_SOURCES = \ + isrc.c \ + isrcacct.c \ + isrcacld.c \ + isrcask.c \ + isrcdefs.h \ + isrcdel.c \ + isrcdest.c \ + isrcext.h \ + isrcitf.h \ + isrcload.c \ + isrcmdel.c \ + isrcpar.c \ + isrctemp.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/isrc/isrc.c b/src/spicelib/devices/isrc/isrc.c new file mode 100644 index 000000000..96d295ec5 --- /dev/null +++ b/src/spicelib/devices/isrc/isrc.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "isrcdefs.h" +#include "suffix.h" + +IFparm ISRCpTable[] = { /* parameters */ + IOPP( "dc", ISRC_DC, IF_REAL ,"DC value of source"), + IOPPA( "acmag", ISRC_AC_MAG, IF_REAL ,"AC magnitude"), + IOPAAU( "acphase", ISRC_AC_PHASE, IF_REAL ,"AC phase"), + IP ( "pulse", ISRC_PULSE, IF_REALVEC,"Pulse description"), + IP ( "sine", ISRC_SINE, IF_REALVEC,"Sinusoidal source description"), + IP ( "sin", ISRC_SINE, IF_REALVEC,"Sinusoidal source description"), + IP ( "exp", ISRC_EXP, IF_REALVEC,"Exponential source description"), + IP ( "pwl", ISRC_PWL, IF_REALVEC,"Piecewise linear description"), + IP ( "sffm", ISRC_SFFM, IF_REALVEC,"single freq. FM description"), + OPU ( "neg_node",ISRC_NEG_NODE, IF_INTEGER,"Negative node of source"), + OPU ( "pos_node",ISRC_POS_NODE, IF_INTEGER,"Positive node of source"), + OPU ( "acreal", ISRC_AC_REAL, IF_REAL ,"AC real part"), + OPU ( "acimag", ISRC_AC_IMAG, IF_REAL ,"AC imaginary part"), + OPU ( "function",ISRC_FCN_TYPE, IF_INTEGER,"Function of the source"), + OPU ( "order", ISRC_FCN_ORDER, IF_INTEGER,"Order of the source function"), + OPU ( "coeffs", ISRC_FCN_COEFFS,IF_REALVEC,"Coefficients of the source"), + OP ( "v", ISRC_VOLTS, IF_REAL, "Voltage across the supply"), + OP ( "p", ISRC_POWER, IF_REAL, "Power supplied by the source"), + IP ( "ac", ISRC_AC, IF_REALVEC,"AC magnitude,phase vector"), + IP ( "c", ISRC_DC, IF_REAL, "Current through current source"), + IP ( "distof1", ISRC_D_F1, IF_REALVEC,"f1 input for distortion"), + IP ( "distof2", ISRC_D_F2, IF_REALVEC,"f2 input for distortion") +}; + +char *ISRCnames[] = { + "I+", + "I-" +}; + +int ISRCnSize = NUMELEMS(ISRCnames); +int ISRCpTSize = NUMELEMS(ISRCpTable); +int ISRCmPTSize = 0; +int ISRCiSize = sizeof(ISRCinstance); +int ISRCmSize = sizeof(ISRCmodel); diff --git a/src/spicelib/devices/isrc/isrcacct.c b/src/spicelib/devices/isrc/isrcacct.c new file mode 100644 index 000000000..e0bcaa851 --- /dev/null +++ b/src/spicelib/devices/isrc/isrcacct.c @@ -0,0 +1,162 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "isrcdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +ISRCaccept(ckt,inModel) + register CKTcircuit *ckt; + GENmodel *inModel; + /* set up the breakpoint table. */ +{ + register ISRCmodel *model = (ISRCmodel*)inModel; + register ISRCinstance *here; + int error; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->ISRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ISRCinstances; here != NULL ; + here=here->ISRCnextInstance) { + + if(!ckt->CKTmode & (MODETRAN | MODETRANOP)) { + /* not transient, so shouldn't be here */ + return(OK); + } else { + /* use the transient functions */ + switch(here->ISRCfunctionType) { + default: { /* no function specified:DC no breakpoints */ + break; + } + + case PULSE: { + +#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW) +#define TIMETOL 1e-7 + + double TD, TR, TF, PW, PER; + double time; + double basetime = 0; + + TD = here->ISRCfunctionOrder > 2 + ? here->ISRCcoeffs[2] : 0.0; + TR = here->ISRCfunctionOrder > 3 + && here->ISRCcoeffs[3] != 0.0 + ? here->ISRCcoeffs[3] : ckt->CKTstep; + TF = here->ISRCfunctionOrder > 4 + && here->ISRCcoeffs[4] != 0.0 + ? here->ISRCcoeffs[4] : ckt->CKTstep; + PW = here->ISRCfunctionOrder > 5 + && here->ISRCcoeffs[5] != 0.0 + ? here->ISRCcoeffs[5] : ckt->CKTfinalTime; + PER = here->ISRCfunctionOrder > 6 + && here->ISRCcoeffs[6] != 0.0 + ? here->ISRCcoeffs[6] : ckt->CKTfinalTime; + time = ckt->CKTtime - TD; + + if(time >= PER) { + /* repeating signal - figure out where we are */ + /* in period */ + basetime = PER * floor(time/PER); + time -= basetime; + } + if( time <= 0 || time >= TR + PW + TF) { + if(ckt->CKTbreak && SAMETIME(time,0)) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TR +TD); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(TR+PW+TF,time) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + PER + TD); + if(error) return(error); + } else if (ckt->CKTbreak && (time == -TD) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD); + if(error) return(error); + } else if (ckt->CKTbreak && SAMETIME(PER,time) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD + TR + PER); + if(error) return(error); + } + } else if ( time >= TR && time <= TR + PW) { + if(ckt->CKTbreak && SAMETIME(time,TR) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(TR+PW,time) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW + TF); + if(error) return(error); + } + } else if (time > 0 && time < TR) { + if(ckt->CKTbreak && SAMETIME(time,0) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(time,TR)) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW); + if(error) return(error); + } + } else { /* time > TR + PW && < TR + PW + TF */ + if(ckt->CKTbreak && SAMETIME(time,TR+PW) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW +TF); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(time,TR+PW+TF) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+PER); + if(error) return(error); + } + } + } + break; + + case SINE: { + /* no breakpoints (yet) */ + } + break; + case EXP: { + /* no breakpoints (yet) */ + } + break; + case SFFM:{ + /* no breakpoints (yet) */ + } + break; + case PWL: { + register int i; + if(ckt->CKTtime < *(here->ISRCcoeffs)) { + if(ckt->CKTbreak) { + error = CKTsetBreak(ckt,*(here->ISRCcoeffs)); + break; + } + } + for(i=0;i<(here->ISRCfunctionOrder/2)-1;i++) { + if((*(here->ISRCcoeffs+2*i)==ckt->CKTtime)) { + if(ckt->CKTbreak) { + error = CKTsetBreak(ckt, + *(here->ISRCcoeffs+2*i+2)); + if(error) return(error); + } + goto bkptset; + } + } + break; + } + } + } +bkptset: ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/isrc/isrcacld.c b/src/spicelib/devices/isrc/isrcacld.c new file mode 100644 index 000000000..82b79b61b --- /dev/null +++ b/src/spicelib/devices/isrc/isrcacld.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "isrcdefs.h" +#include "sperror.h" +#include "suffix.h" + +int +ISRCacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register ISRCmodel *model = (ISRCmodel*)inModel; + register ISRCinstance *here; + + for( ; model != NULL; model = model->ISRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ISRCinstances; here != NULL ; + here=here->ISRCnextInstance) { + if (here->ISRCowner != ARCHme) continue; + + *(ckt->CKTrhs + (here->ISRCposNode)) += + here->ISRCacReal; + *(ckt->CKTrhs + (here->ISRCnegNode)) -= + here->ISRCacReal; + *(ckt->CKTirhs + (here->ISRCposNode)) += + here->ISRCacImag; + *(ckt->CKTirhs + (here->ISRCnegNode)) -= + here->ISRCacImag; + } + } + return(OK); + +} diff --git a/src/spicelib/devices/isrc/isrcask.c b/src/spicelib/devices/isrc/isrcask.c new file mode 100644 index 000000000..da9a0c9de --- /dev/null +++ b/src/spicelib/devices/isrc/isrcask.c @@ -0,0 +1,98 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal device parameters + * of independent current SouRCe + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "isrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +ISRCask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + ISRCinstance *here = (ISRCinstance*)inst; + static char *msg = "Current and power not available in ac analysis"; + int temp; + double *v, *w; + + switch(which) { + case ISRC_DC: + value->rValue = here->ISRCdcValue; + return (OK); + case ISRC_AC_MAG: + value->rValue = here->ISRCacMag; + return (OK); + case ISRC_AC_PHASE: + value->rValue = here->ISRCacPhase; + return (OK); + case ISRC_PULSE: + case ISRC_SINE: + case ISRC_EXP: + case ISRC_PWL: + case ISRC_SFFM: + case ISRC_FCN_COEFFS: + temp = value->v.numValue = here->ISRCfunctionOrder; + value->v.vec.rVec = (double *) + MALLOC(here->ISRCfunctionOrder * sizeof(double)); + v = value->v.vec.rVec; + w = here->ISRCcoeffs; + while (temp--) + *v++ = *w++; + return (OK); + case ISRC_NEG_NODE: + value->iValue = here->ISRCnegNode; + return (OK); + case ISRC_POS_NODE: + value->iValue = here->ISRCposNode; + return (OK); + case ISRC_FCN_TYPE: + value->iValue = here->ISRCfunctionType; + case ISRC_AC_REAL: + value->rValue = here->ISRCacReal; + return (OK); + case ISRC_AC_IMAG: + value->rValue = here->ISRCacImag; + return (OK); + case ISRC_FCN_ORDER: + value->rValue = here->ISRCfunctionOrder; + return (OK); + case ISRC_VOLTS: + value->rValue = (*(ckt->CKTrhsOld + here->ISRCposNode) - + *(ckt->CKTrhsOld + here->ISRCnegNode)); + return(OK); + case ISRC_POWER: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "ISRCask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = -here->ISRCdcValue * + (*(ckt->CKTrhsOld + here->ISRCposNode) - + *(ckt->CKTrhsOld + here->ISRCnegNode)); + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/isrc/isrcdefs.h b/src/spicelib/devices/isrc/isrcdefs.h new file mode 100644 index 000000000..cdadecb2b --- /dev/null +++ b/src/spicelib/devices/isrc/isrcdefs.h @@ -0,0 +1,109 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef ISRC +#define ISRC + +#include "ifsim.h" +#include "complex.h" +#include "cktdefs.h" +#include "gendefs.h" + + /* structures used to describe current sources */ + + +/* information needed per source instance */ + +typedef struct sISRCinstance { + struct sISRCmodel *ISRCmodPtr; /* backpointer to model */ + struct sISRCinstance *ISRCnextInstance; /* pointer to next instance of + *current model*/ + IFuid ISRCname; /* pointer to character string naming this instance */ + int ISRCowner; /* number of owner process */ + int ISRCstate; /* not used */ + + int ISRCnegNode; /* number of negative node of source */ + int ISRCposNode; /* number of positive node of source */ + + int ISRCfunctionType; /* code number of function type for source */ + int ISRCfunctionOrder; /* order of the function for the source */ + double *ISRCcoeffs; /* pointer to array of coefficients */ + + double ISRCdcValue; /* DC and TRANSIENT value of source */ + double ISRCacPhase; /* AC phase angle */ + double ISRCacMag; /* AC magnitude */ + double ISRCacReal; /* AC real part */ + double ISRCacImag; /* AC imaginary */ + + double ISRCdF1mag; /* distortion f1 magnitude */ + double ISRCdF2mag; /* distortion f2 magnitude */ + double ISRCdF1phase; /* distortion f1 phase */ + double ISRCdF2phase; /* distortion f2 phase */ + + unsigned ISRCdcGiven :1 ; /* flag to indicate dc value given */ + unsigned ISRCacGiven :1 ; /* flag to indicate ac keyword given */ + unsigned ISRCacMGiven :1 ; /* flag to indicate ac magnitude given */ + unsigned ISRCacPGiven :1 ; /* flag to indicate ac phase given */ + unsigned ISRCfuncTGiven :1 ; /* flag to indicate function type given */ + unsigned ISRCcoeffsGiven :1 ; /* flag to indicate function coeffs given */ + unsigned ISRCdGiven :1 ; /* flag to indicate source is a distortion input */ + unsigned ISRCdF1given :1; /* flag to indicate source is an f1 distortion input */ + unsigned ISRCdF2given :1; /* flag to indicate source is an f2 distortion input */ +} ISRCinstance ; + + +/* per model data */ + +typedef struct sISRCmodel { /* model structure for a resistor */ + int ISRCmodType; /* type index of this device type */ + struct sISRCmodel *ISRCnextModel; /* pointer to next possible model + *in linked list */ + ISRCinstance * ISRCinstances; /* pointer to list of instances + * that have this model */ + IFuid ISRCmodName; /* pointer to character string naming this model */ +} ISRCmodel; + + +/* source types */ + +#ifndef PULSE +#define PULSE 1 +#define SINE 2 +#define EXP 3 +#define SFFM 4 +#define PWL 5 +#endif /*PULSE*/ + +/* device parameters */ +#define ISRC_DC 1 +#define ISRC_AC_MAG 2 +#define ISRC_AC_PHASE 3 +#define ISRC_AC 4 +#define ISRC_PULSE 5 +#define ISRC_SINE 6 +#define ISRC_EXP 7 +#define ISRC_PWL 8 +#define ISRC_SFFM 9 +#define ISRC_NEG_NODE 10 +#define ISRC_POS_NODE 11 +#define ISRC_AC_REAL 12 +#define ISRC_AC_IMAG 13 +#define ISRC_FCN_TYPE 14 +#define ISRC_FCN_ORDER 15 +#define ISRC_FCN_COEFFS 16 +#define ISRC_POWER 17 +#define ISRC_D_F1 18 +#define ISRC_D_F2 19 +#define ISRC_VOLTS 20 + +/* model parameters */ + +/* device questions */ + +/* model questions */ + +#include "isrcext.h" + +#endif /*ISRC*/ diff --git a/src/spicelib/devices/isrc/isrcdel.c b/src/spicelib/devices/isrc/isrcdel.c new file mode 100644 index 000000000..cd510813b --- /dev/null +++ b/src/spicelib/devices/isrc/isrcdel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "isrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +ISRCdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + ISRCmodel *model = (ISRCmodel*)inModel; + ISRCinstance **fast = (ISRCinstance**)inst; + ISRCinstance **prev = NULL; + ISRCinstance *here; + + for( ; model ; model = model->ISRCnextModel) { + prev = &(model->ISRCinstances); + for(here = *prev; here ; here = *prev) { + if(here->ISRCname == name || (fast && here==*fast) ) { + *prev= here->ISRCnextInstance; + FREE(here); + return(OK); + } + prev = &(here->ISRCnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/isrc/isrcdest.c b/src/spicelib/devices/isrc/isrcdest.c new file mode 100644 index 000000000..c78926c59 --- /dev/null +++ b/src/spicelib/devices/isrc/isrcdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "isrcdefs.h" +#include "suffix.h" + + +void +ISRCdestroy(inModel) + GENmodel **inModel; +{ + ISRCmodel **model = (ISRCmodel**)inModel; + ISRCinstance *here; + ISRCinstance *prev = NULL; + ISRCmodel *mod = *model; + ISRCmodel *oldmod = NULL; + + for( ; mod ; mod = mod->ISRCnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (ISRCinstance *)NULL; + for(here = mod->ISRCinstances ; here ; here = here->ISRCnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/isrc/isrcext.h b/src/spicelib/devices/isrc/isrcext.h new file mode 100644 index 000000000..e34b46cf3 --- /dev/null +++ b/src/spicelib/devices/isrc/isrcext.h @@ -0,0 +1,28 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int ISRCaccept(CKTcircuit*,GENmodel*); +extern int ISRCacLoad(GENmodel*,CKTcircuit*); +extern int ISRCask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int ISRCdelete(GENmodel*,IFuid,GENinstance**); +extern void ISRCdestroy(GENmodel**); +extern int ISRCload(GENmodel*,CKTcircuit*); +extern int ISRCmDelete(GENmodel**,IFuid,GENmodel*); +extern int ISRCparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int ISRCpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int ISRCtemp(GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int ISRCaccept(); +extern int ISRCacLoad(); +extern int ISRCask(); +extern int ISRCdelete(); +extern void ISRCdestroy(); +extern int ISRCload(); +extern int ISRCmDelete(); +extern int ISRCparam(); +extern int ISRCpzLoad(); +extern int ISRCtemp(); +#endif /* stdc */ diff --git a/src/spicelib/devices/isrc/isrcitf.h b/src/spicelib/devices/isrc/isrcitf.h new file mode 100644 index 000000000..da46bc780 --- /dev/null +++ b/src/spicelib/devices/isrc/isrcitf.h @@ -0,0 +1,73 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_isrc + +#ifndef DEV_ISRC +#define DEV_ISRC + +#include "isrcext.h" +extern IFparm ISRCpTable[ ]; +extern char *ISRCnames[ ]; +extern int ISRCpTSize; +extern int ISRCnSize; +extern int ISRCiSize; +extern int ISRCmSize; + +SPICEdev ISRCinfo = { + { + "Isource", + "Independent current source", + + &ISRCnSize, + &ISRCnSize, + ISRCnames, + + &ISRCpTSize, + ISRCpTable, + + 0, + NULL, + DEV_DEFAULT + }, + + ISRCparam, + NULL, + ISRCload, + NULL, + NULL, + NULL, + ISRCtemp, + NULL, + NULL, + ISRCacLoad, + ISRCaccept, + ISRCdestroy, +#ifdef DELETES + ISRCmDelete, + ISRCdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + ISRCask, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* DISTO */ + NULL, /* NOISE */ + + &ISRCiSize, + &ISRCmSize +}; + + +#endif +#endif diff --git a/src/spicelib/devices/isrc/isrcload.c b/src/spicelib/devices/isrc/isrcload.c new file mode 100644 index 000000000..2fe5a344b --- /dev/null +++ b/src/spicelib/devices/isrc/isrcload.c @@ -0,0 +1,195 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "isrcdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +ISRCload(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current current value into the + * sparse matrix previously provided + */ +{ + register ISRCmodel *model = (ISRCmodel*)inModel; + register ISRCinstance *here; + double value; + double time; + + /* loop through all the current source models */ + for( ; model != NULL; model = model->ISRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ISRCinstances; here != NULL ; + here=here->ISRCnextInstance) { + if (here->ISRCowner != ARCHme) continue; + + if( (ckt->CKTmode & (MODEDCOP | MODEDCTRANCURVE)) && + here->ISRCdcGiven ) { + /* load using DC value */ + value = here->ISRCdcValue * ckt->CKTsrcFact; + } else { + if(ckt->CKTmode & (MODEDC)) { + time = 0; + } else { + time = ckt->CKTtime; + } + /* use transient function */ + switch(here->ISRCfunctionType) { + case PULSE: { + + double V1, V2, TD, TR, TF, PW, PER; + double basetime = 0; + + V1 = here->ISRCcoeffs[0]; + V2 = here->ISRCcoeffs[1]; + TD = here->ISRCfunctionOrder > 2 + ? here->ISRCcoeffs[2] : 0.0; + TR = here->ISRCfunctionOrder > 3 + && here->ISRCcoeffs[3] != 0.0 + ? here->ISRCcoeffs[3] : ckt->CKTstep; + TF = here->ISRCfunctionOrder > 4 + && here->ISRCcoeffs[4] != 0.0 + ? here->ISRCcoeffs[4] : ckt->CKTstep; + PW = here->ISRCfunctionOrder > 5 + && here->ISRCcoeffs[5] != 0.0 + ? here->ISRCcoeffs[5] : ckt->CKTfinalTime; + PER = here->ISRCfunctionOrder > 6 + && here->ISRCcoeffs[6] != 0.0 + ? here->ISRCcoeffs[6] : ckt->CKTfinalTime; + + time -= TD; + + if(time > PER) { + /* repeating signal - figure out where we are */ + /* in period */ + basetime = PER * floor(time/PER); + time -= basetime; + } + if( time <= 0 || time >= TR + PW + TF) { + value = V1; + } else if ( time >= TR && time <= TR + PW) { + value = V2; + } else if (time > 0 && time < TR) { + value = V1 + (V2 - V1) * (time) / TR; + } else { /* time > TR + PW && < TR + PW + TF */ + value = V2 + (V1 - V2) * (time - (TR + PW)) / TF; + } + } + break; + + case SINE: { +#define VO (*(here->ISRCcoeffs)) +#define VA (*(here->ISRCcoeffs+1)) +#define FREQ (((here->ISRCfunctionOrder >=3) && (*(here->ISRCcoeffs+2)))? \ + (*(here->ISRCcoeffs+2)):(1/ckt->CKTfinalTime)) +#define TD ((here->ISRCfunctionOrder >=4)?(*(here->ISRCcoeffs+3)):(0.0)) +#define THETA ((here->ISRCfunctionOrder >=5)?(*(here->ISRCcoeffs+4)):(0.0)) + time -= TD; + if (time <= 0) { + value = VO; + } else { + value = VO + VA * sin(FREQ*time * 2.0 * M_PI) * + exp(-time*THETA); + } +#undef VO +#undef VA +#undef FREQ +#undef TD +#undef THETA + } + break; + case EXP: { + double td1; + double td2; +#define V1 (*(here->ISRCcoeffs)) +#define V2 (*(here->ISRCcoeffs+1)) +#define TD1 ((here->ISRCfunctionOrder >=3)?(*(here->ISRCcoeffs+2)):\ + ckt->CKTstep) +#define TAU1 (((here->ISRCfunctionOrder >=4) && (*(here->ISRCcoeffs+3)))? \ + (*(here->ISRCcoeffs+3)):ckt->CKTstep) +#define TD2 (((here->ISRCfunctionOrder >=5) && (*(here->ISRCcoeffs+4)))? \ + (*(here->ISRCcoeffs+4)):TD1+ckt->CKTstep) +#define TAU2 (((here->ISRCfunctionOrder >=6) && (*(here->ISRCcoeffs+5)))? \ + (*(here->ISRCcoeffs+5)):ckt->CKTstep) + td1 = TD1; + td2 = TD2; + if(time <= td1) { + value = V1; + } else if (time <= td2) { + value = V1 + (V2-V1)*(1-exp(-(time-td1)/TAU1)); + } else { + value = V1 + (V2-V1)*(1-exp(-(time-td1)/TAU1)) + + (V1-V2)*(1-exp(-(time-td2)/TAU2)) ; + } +#undef V1 +#undef V2 +#undef TD1 +#undef TAU1 +#undef TD2 +#undef TAU2 + } + break; + case SFFM:{ +#define VO (*(here->ISRCcoeffs)) +#define VA (*(here->ISRCcoeffs+1)) +#define FC (((here->ISRCfunctionOrder >=3) && (*(here->ISRCcoeffs+2)))? \ + (*(here->ISRCcoeffs+2)):(1/ckt->CKTfinalTime)) +#define MDI ((here->ISRCfunctionOrder>=4)?(*(here->ISRCcoeffs+3)):0.0) +#define FS (((here->ISRCfunctionOrder >=5) && (*(here->ISRCcoeffs+4)))? \ + (*(here->ISRCcoeffs+4)):(1/ckt->CKTfinalTime)) + value = VO + VA * + sin((2.0 * M_PI * FC * time) + + MDI * sin(2.0 * M_PI * FS * time)); +#undef VO +#undef VA +#undef FC +#undef MDI +#undef FS + } + break; + default: + value = here->ISRCdcValue * ckt->CKTsrcFact; + break; + case PWL: { + register int i; + if(time< *(here->ISRCcoeffs)) { + value = *(here->ISRCcoeffs + 1) ; + break; + } + for(i=0;i<=(here->ISRCfunctionOrder/2)-1;i++) { + if((*(here->ISRCcoeffs+2*i)==time)) { + value = *(here->ISRCcoeffs+2*i+1); + goto loadDone; + } + if((*(here->ISRCcoeffs+2*i)ISRCcoeffs+2*(i+1)) >time)) { + value = *(here->ISRCcoeffs+2*i+1) + + (((time-*(here->ISRCcoeffs+2*i))/ + (*(here->ISRCcoeffs+2*(i+1)) - + *(here->ISRCcoeffs+2*i))) * + (*(here->ISRCcoeffs+2*i+3) - + *(here->ISRCcoeffs+2*i+1))); + goto loadDone; + } + } + value = *(here->ISRCcoeffs+ here->ISRCfunctionOrder-1) ; + break; + } + } + } +loadDone: + *(ckt->CKTrhs + (here->ISRCposNode)) += value; + *(ckt->CKTrhs + (here->ISRCnegNode)) -= value; + } + } + return(OK); +} diff --git a/src/spicelib/devices/isrc/isrcmdel.c b/src/spicelib/devices/isrc/isrcmdel.c new file mode 100644 index 000000000..29cabe026 --- /dev/null +++ b/src/spicelib/devices/isrc/isrcmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "isrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +ISRCmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + ISRCmodel **model = (ISRCmodel**)inModel; + ISRCmodel *modfast = (ISRCmodel*)kill; + ISRCinstance *here; + ISRCinstance *prev = NULL; + ISRCmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->ISRCnextModel)) { + if( (*model)->ISRCmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->ISRCnextModel; /* cut deleted device out of list */ + for(here = (*model)->ISRCinstances ; here ; here = here->ISRCnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/isrc/isrcpar.c b/src/spicelib/devices/isrc/isrcpar.c new file mode 100644 index 000000000..9ccc71be3 --- /dev/null +++ b/src/spicelib/devices/isrc/isrcpar.c @@ -0,0 +1,139 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "isrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +ISRCparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + ISRCinstance *here = (ISRCinstance*)inst; + switch(param) { + case ISRC_DC: + here->ISRCdcValue = value->rValue; + here->ISRCdcGiven = TRUE; + break; + case ISRC_AC_MAG: + here->ISRCacMag = value->rValue; + here->ISRCacMGiven = TRUE; + here->ISRCacGiven = TRUE; + break; + case ISRC_AC_PHASE: + here->ISRCacPhase = value->rValue; + here->ISRCacPGiven = TRUE; + here->ISRCacGiven = TRUE; + break; + case ISRC_AC: + switch(value->v.numValue) { + case 2: + here->ISRCacPhase = *(value->v.vec.rVec+1); + here->ISRCacPGiven = TRUE; + case 1: + here->ISRCacMag = *(value->v.vec.rVec); + here->ISRCacMGiven = TRUE; + case 0: + here->ISRCacGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + case ISRC_PULSE: + if(value->v.numValue <2) return(E_BADPARM); + here->ISRCfunctionType = PULSE; + here->ISRCfuncTGiven = TRUE; + here->ISRCcoeffs = value->v.vec.rVec; + here->ISRCfunctionOrder = value->v.numValue; + here->ISRCcoeffsGiven = TRUE; + break; + case ISRC_SINE: + if(value->v.numValue <2) return(E_BADPARM); + here->ISRCfunctionType = SINE; + here->ISRCfuncTGiven = TRUE; + here->ISRCcoeffs = value->v.vec.rVec; + here->ISRCfunctionOrder = value->v.numValue; + here->ISRCcoeffsGiven = TRUE; + break; + case ISRC_EXP: + if(value->v.numValue <2) return(E_BADPARM); + here->ISRCfunctionType = EXP; + here->ISRCfuncTGiven = TRUE; + here->ISRCcoeffs = value->v.vec.rVec; + here->ISRCfunctionOrder = value->v.numValue; + here->ISRCcoeffsGiven = TRUE; + break; + case ISRC_PWL: + if(value->v.numValue <2) return(E_BADPARM); + here->ISRCfunctionType = PWL; + here->ISRCfuncTGiven = TRUE; + here->ISRCcoeffs = value->v.vec.rVec; + here->ISRCfunctionOrder = value->v.numValue; + here->ISRCcoeffsGiven = TRUE; + break; + case ISRC_SFFM: + if(value->v.numValue <2) return(E_BADPARM); + here->ISRCfunctionType = SFFM; + here->ISRCfuncTGiven = TRUE; + here->ISRCcoeffs = value->v.vec.rVec; + here->ISRCfunctionOrder = value->v.numValue; + here->ISRCcoeffsGiven = TRUE; + break; + case ISRC_D_F1: + here->ISRCdF1given = TRUE; + here->ISRCdGiven = TRUE; + switch(value->v.numValue) { + case 2: + here->ISRCdF1phase = *(value->v.vec.rVec+1); + here->ISRCdF1mag = *(value->v.vec.rVec); + break; + case 1: + here->ISRCdF1mag = *(value->v.vec.rVec); + here->ISRCdF1phase = 0.0; + break; + case 0: + here->ISRCdF1mag = 1.0; + here->ISRCdF1phase = 0.0; + break; + default: + return(E_BADPARM); + } + break; + case ISRC_D_F2: + here->ISRCdF2given = TRUE; + here->ISRCdGiven = TRUE; + switch(value->v.numValue) { + case 2: + here->ISRCdF2phase = *(value->v.vec.rVec+1); + here->ISRCdF2mag = *(value->v.vec.rVec); + break; + case 1: + here->ISRCdF2mag = *(value->v.vec.rVec); + here->ISRCdF2phase = 0.0; + break; + case 0: + here->ISRCdF2mag = 1.0; + here->ISRCdF2phase = 0.0; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/isrc/isrctemp.c b/src/spicelib/devices/isrc/isrctemp.c new file mode 100644 index 000000000..94ea5207c --- /dev/null +++ b/src/spicelib/devices/isrc/isrctemp.c @@ -0,0 +1,56 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "isrcdefs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +ISRCtemp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register ISRCmodel *model = (ISRCmodel*)inModel; + register ISRCinstance *here; + double radians; + + for( ; model != NULL; model = model->ISRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->ISRCinstances; here != NULL ; + here=here->ISRCnextInstance) { + if (here->ISRCowner != ARCHme) continue; + + if(here->ISRCacGiven && !here->ISRCacMGiven) { + here->ISRCacMag=1; + } + if(here->ISRCacGiven && !here->ISRCacPGiven) { + here->ISRCacPhase=0; + } + if(!here->ISRCdcGiven) { + /* no DC value - either have a transient value, or none */ + if(here->ISRCfuncTGiven) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "Source %s has no DC value, transient time 0 value used", + &(here->ISRCname)); + } else { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "Source %s has no value, DC 0 assumed\n", + &(here->ISRCname)); + } + } + radians = here->ISRCacPhase * M_PI / 180.0; + here->ISRCacReal = here->ISRCacMag * cos(radians); + here->ISRCacImag = here->ISRCacMag * sin(radians); + } + } + return(OK); + +} diff --git a/src/spicelib/devices/jfet/ChangeLog b/src/spicelib/devices/jfet/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/jfet/Makefile.am b/src/spicelib/devices/jfet/Makefile.am new file mode 100644 index 000000000..5f5129403 --- /dev/null +++ b/src/spicelib/devices/jfet/Makefile.am @@ -0,0 +1,31 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libjfet.la + +libjfet_la_SOURCES = \ + jfet.c \ + jfetacld.c \ + jfetask.c \ + jfetdefs.h \ + jfetdel.c \ + jfetdest.c \ + jfetdist.c \ + jfetdset.c \ + jfetext.h \ + jfetic.c \ + jfetitf.h \ + jfetload.c \ + jfetmask.c \ + jfetmdel.c \ + jfetmpar.c \ + jfetnoi.c \ + jfetpar.c \ + jfetpzld.c \ + jfetset.c \ + jfettemp.c \ + jfettrun.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/jfet/jfet.c b/src/spicelib/devices/jfet/jfet.c new file mode 100644 index 000000000..03a405b13 --- /dev/null +++ b/src/spicelib/devices/jfet/jfet.c @@ -0,0 +1,84 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Sydney University mods Copyright(c) 1989 Anthony E. Parker, David J. Skellern + Laboratory for Communication Science Engineering + Sydney University Department of Electrical Engineering, Australia +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "jfetdefs.h" +#include "suffix.h" + +IFparm JFETpTable[] = { /* device parameters */ + IOPU("off", JFET_OFF, IF_FLAG, "Device initially off"), + IOPAU("ic", JFET_IC, IF_REALVEC,"Initial VDS,VGS vector"), + IOPU("area", JFET_AREA, IF_REAL, "Area factor"), + IOPAU("ic-vds", JFET_IC_VDS, IF_REAL, "Initial D-S voltage"), + IOPAU("ic-vgs", JFET_IC_VGS, IF_REAL, "Initial G-S volrage"), + IOPU("temp", JFET_TEMP, IF_REAL, "Instance temperature"), + OPU("drain-node", JFET_DRAINNODE, IF_INTEGER,"Number of drain node"), + OPU("gate-node", JFET_GATENODE, IF_INTEGER,"Number of gate node"), + OPU("source-node", JFET_SOURCENODE, IF_INTEGER,"Number of source node"), + OPU("drain-prime-node", JFET_DRAINPRIMENODE, IF_INTEGER,"Internal drain node"), + OPU("source-prime-node",JFET_SOURCEPRIMENODE,IF_INTEGER, + "Internal source node"), + OP("vgs", JFET_VGS, IF_REAL, "Voltage G-S"), + OP("vgd", JFET_VGD, IF_REAL, "Voltage G-D"), + OP("ig", JFET_CG, IF_REAL, "Current at gate node"), + OP("id", JFET_CD, IF_REAL, "Current at drain node"), + OP("is", JFET_CS, IF_REAL, "Source current"), + OP("igd", JFET_CGD, IF_REAL, "Current G-D"), + OP("gm", JFET_GM, IF_REAL, "Transconductance"), + OP("gds", JFET_GDS, IF_REAL, "Conductance D-S"), + OP("ggs", JFET_GGS, IF_REAL, "Conductance G-S"), + OP("ggd", JFET_GGD, IF_REAL, "Conductance G-D"), + OPU("qgs", JFET_QGS, IF_REAL,"Charge storage G-S junction"), + OPU("qgd", JFET_QGD, IF_REAL,"Charge storage G-D junction"), + OPU("cqgs",JFET_CQGS, IF_REAL, + "Capacitance due to charge storage G-S junction"), + OPU("cqgd",JFET_CQGD, IF_REAL, + "Capacitance due to charge storage G-D junction"), + OPU("p", JFET_POWER,IF_REAL,"Power dissipated by the JFET"), +}; + +IFparm JFETmPTable[] = { /* model parameters */ + OP("type", JFET_MOD_TYPE, IF_STRING, "N-type or P-type JFET model"), + IOP("njf", JFET_MOD_NJF, IF_FLAG,"N type JFET model"), + IOP("pjf", JFET_MOD_PJF, IF_FLAG,"P type JFET model"), + IOP("vt0", JFET_MOD_VTO, IF_REAL,"Threshold voltage"), + IOPR("vto", JFET_MOD_VTO, IF_REAL,"Threshold voltage"), + IOP("beta", JFET_MOD_BETA, IF_REAL,"Transconductance parameter"), + IOP("lambda", JFET_MOD_LAMBDA, IF_REAL,"Channel length modulation param."), + IOP("rd", JFET_MOD_RD, IF_REAL,"Drain ohmic resistance"), + OPU("gd", JFET_MOD_DRAINCONDUCT, IF_REAL,"Drain conductance"), + IOP("rs", JFET_MOD_RS, IF_REAL,"Source ohmic resistance"), + OPU("gs",JFET_MOD_SOURCECONDUCT,IF_REAL,"Source conductance"), + IOPA("cgs", JFET_MOD_CGS, IF_REAL,"G-S junction capactance"), + IOPA("cgd", JFET_MOD_CGD, IF_REAL,"G-D junction cap"), + IOP("pb", JFET_MOD_PB, IF_REAL,"Gate junction potential"), + IOP("is", JFET_MOD_IS, IF_REAL,"Gate junction saturation current"), + IOP("fc", JFET_MOD_FC, IF_REAL,"Forward bias junction fit parm."), + /* Modification for Sydney University JFET model */ + IOP("b", JFET_MOD_B, IF_REAL,"Doping tail parameter"), + /* end Sydney University mod. */ + IOPU("tnom", JFET_MOD_TNOM, IF_REAL,"parameter measurement temperature"), + IOP("kf", JFET_MOD_KF,IF_REAL,"Flicker Noise Coefficient"), + IOP("af", JFET_MOD_AF,IF_REAL,"Flicker Noise Exponent") +}; + + +char *JFETnames[] = { + "Drain", + "Gate", + "Source" +}; + +int JFETnSize = NUMELEMS(JFETnames); +int JFETpTSize = NUMELEMS(JFETpTable); +int JFETmPTSize = NUMELEMS(JFETmPTable); +int JFETiSize = sizeof(JFETinstance); +int JFETmSize = sizeof(JFETmodel); diff --git a/src/spicelib/devices/jfet/jfetacld.c b/src/spicelib/devices/jfet/jfetacld.c new file mode 100644 index 000000000..151fe9a6b --- /dev/null +++ b/src/spicelib/devices/jfet/jfetacld.c @@ -0,0 +1,72 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFETacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register JFETmodel *model = (JFETmodel*)inModel; + register JFETinstance *here; + double gdpr; + double gspr; + double gm; + double gds; + double ggs; + double xgs; + double ggd; + double xgd; + + for( ; model != NULL; model = model->JFETnextModel ) { + + for( here = model->JFETinstances; here != NULL; + here = here->JFETnextInstance) { + if (here->JFETowner != ARCHme) continue; + + gdpr=model->JFETdrainConduct * here->JFETarea; + gspr=model->JFETsourceConduct * here->JFETarea; + gm= *(ckt->CKTstate0 + here->JFETgm) ; + gds= *(ckt->CKTstate0 + here->JFETgds) ; + ggs= *(ckt->CKTstate0 + here->JFETggs) ; + xgs= *(ckt->CKTstate0 + here->JFETqgs) * ckt->CKTomega ; + ggd= *(ckt->CKTstate0 + here->JFETggd) ; + xgd= *(ckt->CKTstate0 + here->JFETqgd) * ckt->CKTomega ; + *(here->JFETdrainDrainPtr ) += gdpr; + *(here->JFETgateGatePtr ) += ggd+ggs; + *(here->JFETgateGatePtr +1) += xgd+xgs; + *(here->JFETsourceSourcePtr ) += gspr; + *(here->JFETdrainPrimeDrainPrimePtr ) += gdpr+gds+ggd; + *(here->JFETdrainPrimeDrainPrimePtr +1) += xgd; + *(here->JFETsourcePrimeSourcePrimePtr ) += gspr+gds+gm+ggs; + *(here->JFETsourcePrimeSourcePrimePtr +1) += xgs; + *(here->JFETdrainDrainPrimePtr ) -= gdpr; + *(here->JFETgateDrainPrimePtr ) -= ggd; + *(here->JFETgateDrainPrimePtr +1) -= xgd; + *(here->JFETgateSourcePrimePtr ) -= ggs; + *(here->JFETgateSourcePrimePtr +1) -= xgs; + *(here->JFETsourceSourcePrimePtr ) -= gspr; + *(here->JFETdrainPrimeDrainPtr ) -= gdpr; + *(here->JFETdrainPrimeGatePtr ) += (-ggd+gm); + *(here->JFETdrainPrimeGatePtr +1) -= xgd; + *(here->JFETdrainPrimeSourcePrimePtr ) += (-gds-gm); + *(here->JFETsourcePrimeGatePtr ) += (-ggs-gm); + *(here->JFETsourcePrimeGatePtr +1) -= xgs; + *(here->JFETsourcePrimeSourcePtr ) -= gspr; + *(here->JFETsourcePrimeDrainPrimePtr ) -= gds; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet/jfetask.c b/src/spicelib/devices/jfet/jfetask.c new file mode 100644 index 000000000..1a3337e60 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetask.c @@ -0,0 +1,132 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +JFETask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + JFETinstance *here = (JFETinstance*)inst; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case JFET_TEMP: + value->rValue = here->JFETtemp-CONSTCtoK; + return(OK); + case JFET_AREA: + value->rValue = here->JFETarea; + return(OK); + case JFET_IC_VDS: + value->rValue = here->JFETicVDS; + return(OK); + case JFET_IC_VGS: + value->rValue = here->JFETicVGS; + return(OK); + case JFET_OFF: + value->iValue = here->JFEToff; + return(OK); + case JFET_DRAINNODE: + value->iValue = here->JFETdrainNode; + return(OK); + case JFET_GATENODE: + value->iValue = here->JFETgateNode; + return(OK); + case JFET_SOURCENODE: + value->iValue = here->JFETsourceNode; + return(OK); + case JFET_DRAINPRIMENODE: + value->iValue = here->JFETdrainPrimeNode; + return(OK); + case JFET_SOURCEPRIMENODE: + value->iValue = here->JFETsourcePrimeNode; + return(OK); + case JFET_VGS: + value->rValue = *(ckt->CKTstate0 + here->JFETvgs); + return(OK); + case JFET_VGD: + value->rValue = *(ckt->CKTstate0 + here->JFETvgd); + return(OK); + case JFET_CG: + value->rValue = *(ckt->CKTstate0 + here->JFETcg); + return(OK); + case JFET_CD: + value->rValue = *(ckt->CKTstate0 + here->JFETcd); + return(OK); + case JFET_CGD: + value->rValue = *(ckt->CKTstate0 + here->JFETcgd); + return(OK); + case JFET_GM: + value->rValue = *(ckt->CKTstate0 + here->JFETgm); + return(OK); + case JFET_GDS: + value->rValue = *(ckt->CKTstate0 + here->JFETgds); + return(OK); + case JFET_GGS: + value->rValue = *(ckt->CKTstate0 + here->JFETggs); + return(OK); + case JFET_GGD: + value->rValue = *(ckt->CKTstate0 + here->JFETggd); + return(OK); + case JFET_QGS: + value->rValue = *(ckt->CKTstate0 + here->JFETqgs); + return(OK); + case JFET_CQGS: + value->rValue = *(ckt->CKTstate0 + here->JFETcqgs); + return(OK); + case JFET_QGD: + value->rValue = *(ckt->CKTstate0 + here->JFETqgd); + return(OK); + case JFET_CQGD: + value->rValue = *(ckt->CKTstate0 + here->JFETcqgd); + return(OK); + case JFET_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "JFETask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -*(ckt->CKTstate0 + here->JFETcd); + value->rValue -= *(ckt->CKTstate0 + here->JFETcg); + } + return(OK); + case JFET_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "JFETask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTstate0 + here->JFETcd) * + *(ckt->CKTrhsOld + here->JFETdrainNode); + value->rValue += *(ckt->CKTstate0 + here->JFETcg) * + *(ckt->CKTrhsOld + here->JFETgateNode); + value->rValue -= (*(ckt->CKTstate0 + here->JFETcd) + + *(ckt->CKTstate0 + here->JFETcg)) * + *(ckt->CKTrhsOld + here->JFETsourceNode); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/jfet/jfetdefs.h b/src/spicelib/devices/jfet/jfetdefs.h new file mode 100644 index 000000000..72564f812 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetdefs.h @@ -0,0 +1,287 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Sydney University mods Copyright(c) 1989 Anthony E. Parker, David J. Skellern + Laboratory for Communication Science Engineering + Sydney University Department of Electrical Engineering, Australia +**********/ + +#ifndef JFET +#define JFET + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + + /* structures used to describe Junction Field Effect Transistors */ + + +/* information used to describe a single instance */ + +typedef struct sJFETinstance { + struct sJFETmodel *JFETmodPtr; /* backpointer to model */ + struct sJFETinstance *JFETnextInstance; /* pointer to next instance of + * current model*/ + IFuid JFETname; /* pointer to character string naming this instance */ + int JFETowner; /* number of owner process */ + int JFETstate; /* pointer to start of state vector for jfet */ + int JFETdrainNode; /* number of drain node of jfet */ + int JFETgateNode; /* number of gate node of jfet */ + int JFETsourceNode; /* number of source node of jfet */ + int JFETdrainPrimeNode; /* number of internal drain node of jfet */ + int JFETsourcePrimeNode; /* number of internal source node of jfet */ + + double *JFETdrainDrainPrimePtr; /* pointer to sparse matrix at + * (drain,drain prime) */ + double *JFETgateDrainPrimePtr; /* pointer to sparse matrix at + * (gate,drain prime) */ + double *JFETgateSourcePrimePtr; /* pointer to sparse matrix at + * (gate,source prime) */ + double *JFETsourceSourcePrimePtr; /* pointer to sparse matrix at + * (source,source prime) */ + double *JFETdrainPrimeDrainPtr; /* pointer to sparse matrix at + * (drain prime,drain) */ + double *JFETdrainPrimeGatePtr; /* pointer to sparse matrix at + * (drain prime,gate) */ + double *JFETdrainPrimeSourcePrimePtr; /* pointer to sparse matrix + * (drain prime,source prime) */ + double *JFETsourcePrimeGatePtr; /* pointer to sparse matrix at + * (source prime,gate) */ + double *JFETsourcePrimeSourcePtr; /* pointer to sparse matrix at + * (source prime,source) */ + double *JFETsourcePrimeDrainPrimePtr; /* pointer to sparse matrix + * (source prime,drain prime) */ + double *JFETdrainDrainPtr; /* pointer to sparse matrix at + * (drain,drain) */ + double *JFETgateGatePtr; /* pointer to sparse matrix at + * (gate,gate) */ + double *JFETsourceSourcePtr; /* pointer to sparse matrix at + * (source,source) */ + double *JFETdrainPrimeDrainPrimePtr; /* pointer to sparse matrix + * (drain prime,drain prime) */ + double *JFETsourcePrimeSourcePrimePtr; /* pointer to sparse matrix + * (source prime,source prime) */ + + int JFETmode; + /* distortion analysis Taylor coeffs. */ + +/* + * naming convention: + * x = vgs + * y = vds + * cdr = cdrain + */ + +#define JFETNDCOEFFS 21 + +#ifndef NODISTO + double JFETdCoeffs[JFETNDCOEFFS]; +#else /* NODISTO */ + double *JFETdCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define cdr_x JFETdCoeffs[0] +#define cdr_y JFETdCoeffs[1] +#define cdr_x2 JFETdCoeffs[2] +#define cdr_y2 JFETdCoeffs[3] +#define cdr_xy JFETdCoeffs[4] +#define cdr_x3 JFETdCoeffs[5] +#define cdr_y3 JFETdCoeffs[6] +#define cdr_x2y JFETdCoeffs[7] +#define cdr_xy2 JFETdCoeffs[8] + +#define ggs1 JFETdCoeffs[9] +#define ggd1 JFETdCoeffs[10] +#define ggs2 JFETdCoeffs[11] +#define ggd2 JFETdCoeffs[12] +#define ggs3 JFETdCoeffs[13] +#define ggd3 JFETdCoeffs[14] +#define capgs1 JFETdCoeffs[15] +#define capgd1 JFETdCoeffs[16] +#define capgs2 JFETdCoeffs[17] +#define capgd2 JFETdCoeffs[18] +#define capgs3 JFETdCoeffs[19] +#define capgd3 JFETdCoeffs[20] + +#endif + +/* indices to an array of JFET noise sources */ + +#define JFETRDNOIZ 0 +#define JFETRSNOIZ 1 +#define JFETIDNOIZ 2 +#define JFETFLNOIZ 3 +#define JFETTOTNOIZ 4 + +#define JFETNSRCS 5 + +#ifndef NONOISE + double JFETnVar[NSTATVARS][JFETNSRCS]; +#else /* NONOISE */ + double **JFETnVar; +#endif /* NONOISE */ + + unsigned JFEToff :1; /* 'off' flag for jfet */ + unsigned JFETareaGiven : 1; /* flag to indicate area was specified */ + unsigned JFETicVDSGiven : 1; /* initial condition given flag for V D-S*/ + unsigned JFETicVGSGiven : 1; /* initial condition given flag for V G-S*/ + unsigned JFETtempGiven : 1; /* flag to indicate instance temp given */ + + + double JFETarea; /* area factor for the jfet */ + double JFETicVDS; /* initial condition voltage D-S*/ + double JFETicVGS; /* initial condition voltage G-S*/ + double JFETtemp; /* operating temperature */ + double JFETtSatCur; /* temperature adjusted saturation current */ + double JFETtGatePot; /* temperature adjusted gate potential */ + double JFETtCGS; /* temperature corrected G-S capacitance */ + double JFETtCGD; /* temperature corrected G-D capacitance */ + double JFETcorDepCap; /* joining point of the fwd bias dep. cap eq.s */ + double JFETvcrit; /* critical voltage for the instance */ + double JFETf1; /* coefficient of capacitance polynomial exp */ + + +} JFETinstance ; + +#define JFETvgs JFETstate +#define JFETvgd JFETstate+1 +#define JFETcg JFETstate+2 +#define JFETcd JFETstate+3 +#define JFETcgd JFETstate+4 +#define JFETgm JFETstate+5 +#define JFETgds JFETstate+6 +#define JFETggs JFETstate+7 +#define JFETggd JFETstate+8 +#define JFETqgs JFETstate+9 +#define JFETcqgs JFETstate+10 +#define JFETqgd JFETstate+11 +#define JFETcqgd JFETstate+12 + +/* per model data */ + +typedef struct sJFETmodel { /* model structure for a jfet */ + int JFETmodType; /* type index of this device type */ + struct sJFETmodel *JFETnextModel; /* pointer to next possible model in + * linked list */ + JFETinstance * JFETinstances; /* pointer to list of instances + * that have this model */ + IFuid JFETmodName; /* pointer to character string naming this model */ + int JFETtype; + + double JFETthreshold; + double JFETbeta; + double JFETlModulation; + double JFETdrainResist; + double JFETsourceResist; + double JFETcapGS; + double JFETcapGD; + double JFETgatePotential; + double JFETgateSatCurrent; + double JFETdepletionCapCoeff; + double JFETfNcoef; + double JFETfNexp; + + + double JFETdrainConduct; + double JFETsourceConduct; + double JFETf2; + double JFETf3; + /* Modification for Sydney University JFET model */ + double JFETb; /* doping profile parameter */ + double JFETbFac; /* internal derived doping profile parameter */ + /* end Sydney University mod */ + double JFETtnom; /* temperature at which parameters were measured */ + + unsigned JFETthresholdGiven : 1; + unsigned JFETbetaGiven : 1; + unsigned JFETlModulationGiven : 1; + unsigned JFETdrainResistGiven : 1; + unsigned JFETsourceResistGiven : 1; + unsigned JFETcapGSGiven : 1; + unsigned JFETcapGDGiven : 1; + unsigned JFETgatePotentialGiven : 1; + unsigned JFETgateSatCurrentGiven : 1; + unsigned JFETdepletionCapCoeffGiven : 1; + /* Modification for Sydney University JFET model */ + unsigned JFETbGiven : 1; + /* end Sydney University mod */ + unsigned JFETtnomGiven : 1; /* user specified Tnom for model */ + unsigned JFETfNcoefGiven : 1; + unsigned JFETfNexpGiven : 1; + + +} JFETmodel; + +#ifndef NJF + +#define NJF 1 +#define PJF -1 + +#endif /*NJF*/ + +/* device parameters */ +#define JFET_AREA 1 +#define JFET_IC_VDS 2 +#define JFET_IC_VGS 3 +#define JFET_IC 4 +#define JFET_OFF 5 +#define JFET_TEMP 6 + +/* model parameters */ +#define JFET_MOD_VTO 101 +#define JFET_MOD_BETA 102 +#define JFET_MOD_LAMBDA 103 +#define JFET_MOD_RD 104 +#define JFET_MOD_RS 105 +#define JFET_MOD_CGS 106 +#define JFET_MOD_CGD 107 +#define JFET_MOD_PB 108 +#define JFET_MOD_IS 109 +#define JFET_MOD_FC 110 +#define JFET_MOD_NJF 111 +#define JFET_MOD_PJF 112 +#define JFET_MOD_TNOM 113 +#define JFET_MOD_KF 114 +#define JFET_MOD_AF 115 +/* Modification for Sydney University JFET model */ +#define JFET_MOD_B 116 +/* end Sydney University mod */ + +/* device questions */ +#define JFET_DRAINNODE 301 +#define JFET_GATENODE 302 +#define JFET_SOURCENODE 303 +#define JFET_DRAINPRIMENODE 304 +#define JFET_SOURCEPRIMENODE 305 +#define JFET_VGS 306 +#define JFET_VGD 307 +#define JFET_CG 308 +#define JFET_CD 309 +#define JFET_CGD 310 +#define JFET_GM 311 +#define JFET_GDS 312 +#define JFET_GGS 313 +#define JFET_GGD 314 +#define JFET_QGS 315 +#define JFET_CQGS 316 +#define JFET_QGD 317 +#define JFET_CQGD 318 +#define JFET_CS 319 +#define JFET_POWER 320 + +/* model questions */ +#define JFET_MOD_DRAINCONDUCT 301 +#define JFET_MOD_SOURCECONDUCT 302 +#define JFET_MOD_DEPLETIONCAP 303 +#define JFET_MOD_VCRIT 304 +#define JFET_MOD_TYPE 305 + +/* function definitions */ + +#include "jfetext.h" + +#endif /*JFET*/ diff --git a/src/spicelib/devices/jfet/jfetdel.c b/src/spicelib/devices/jfet/jfetdel.c new file mode 100644 index 000000000..71e3a7503 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetdel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFETdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + JFETmodel *model = (JFETmodel*)inModel; + JFETinstance **fast = (JFETinstance**)inst; + JFETinstance **prev = NULL; + JFETinstance *here; + + for( ; model ; model = model->JFETnextModel) { + prev = &(model->JFETinstances); + for(here = *prev; here ; here = *prev) { + if(here->JFETname == name || (fast && here==*fast) ) { + *prev= here->JFETnextInstance; + FREE(here); + return(OK); + } + prev = &(here->JFETnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/jfet/jfetdest.c b/src/spicelib/devices/jfet/jfetdest.c new file mode 100644 index 000000000..fe51a23ed --- /dev/null +++ b/src/spicelib/devices/jfet/jfetdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "jfetdefs.h" +#include "suffix.h" + + +void +JFETdestroy(inModel) + GENmodel **inModel; +{ + JFETmodel **model = (JFETmodel**)inModel; + JFETinstance *here; + JFETinstance *prev = NULL; + JFETmodel *mod = *model; + JFETmodel *oldmod = NULL; + + for( ; mod ; mod = mod->JFETnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (JFETinstance *)NULL; + for(here = mod->JFETinstances ; here ; here = here->JFETnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/jfet/jfetdist.c b/src/spicelib/devices/jfet/jfetdist.c new file mode 100644 index 000000000..0df391a14 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetdist.c @@ -0,0 +1,962 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +JFETdisto(mode,genmodel,ckt) + GENmodel *genmodel; + register CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + JFETmodel *model = (JFETmodel *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double temp, itemp; + register JFETinstance *here; + +if (mode == D_SETUP) + return(JFETdSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the JFET models */ +for( ; model != NULL; model = model->JFETnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->JFETinstances; here != NULL ; + here=here->JFETnextInstance) { + if (here->JFETowner != ARCHme) continue; + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->JFETgateNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->JFETgateNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn2F1(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + itemp = DFi2F1(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1n2F1(here->ggs2, + r1h1x, + i1h1x); + + itemp = D1i2F1(here->ggs2, + r1h1x, + i1h1x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1n2F1(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + itemp = D1i2F1(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgs2, + r1h1x, + i1h1x); + + itemp = ckt->CKTomega * + D1n2F1(here->capgs2, + r1h1x, + i1h1x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgd2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capgd2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* capgd over */ + + /* all done */ + + break; + + case D_THRF1: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->JFETgateNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->JFETgateNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r2h11x = *(job->r2H11ptr + (here->JFETgateNode)) - + *(job->r2H11ptr + (here->JFETsourcePrimeNode)); + i2h11x = *(job->i2H11ptr + (here->JFETgateNode)) - + *(job->i2H11ptr + (here->JFETsourcePrimeNode)); + + r2h11y = *(job->r2H11ptr + (here->JFETdrainPrimeNode)) - + *(job->r2H11ptr + (here->JFETsourcePrimeNode)); + i2h11y = *(job->i2H11ptr + (here->JFETdrainPrimeNode)) - + *(job->i2H11ptr + (here->JFETsourcePrimeNode)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn3F1(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + here->cdr_x3, + here->cdr_y3, + 0.0, + here->cdr_x2y, + 0.0, + here->cdr_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + itemp = DFi3F1(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + here->cdr_x3, + here->cdr_y3, + 0.0, + here->cdr_x2y, + 0.0, + here->cdr_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1n3F1(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = D1i3F1(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1n3F1(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + itemp = D1i3F1(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = ckt->CKTomega * + D1n3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* capgd over */ + + /* all done */ + + break; + case D_F1PF2: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->JFETgateNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->JFETgateNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r1h2x = *(job->r1H2ptr + (here->JFETgateNode)) - + *(job->r1H2ptr + (here->JFETsourcePrimeNode)); + i1h2x = *(job->i1H2ptr + (here->JFETgateNode)) - + *(job->i1H2ptr + (here->JFETsourcePrimeNode)); + + r1h2y = *(job->r1H2ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H2ptr + (here->JFETsourcePrimeNode)); + i1h2y = *(job->i1H2ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H2ptr + (here->JFETsourcePrimeNode)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1nF12(here->ggs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = D1iF12(here->ggs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1nF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + itemp = D1iF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* capgd over */ + + /* all done */ + + break; + case D_F1MF2: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->JFETgateNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->JFETgateNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r1hm2x = *(job->r1H2ptr + (here->JFETgateNode)) - + *(job->r1H2ptr + (here->JFETsourcePrimeNode)); + i1hm2x = -(*(job->i1H2ptr + (here->JFETgateNode)) - + *(job->i1H2ptr + (here->JFETsourcePrimeNode))); + + r1hm2y = *(job->r1H2ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H2ptr + (here->JFETsourcePrimeNode)); + i1hm2y = -(*(job->i1H2ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H2ptr + (here->JFETsourcePrimeNode))); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + 0.0, + here->cdr_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1nF12(here->ggs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = D1iF12(here->ggs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1nF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + itemp = D1iF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* capgd over */ + + /* all done */ + + break; + case D_2F1MF2: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->JFETgateNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->JFETgateNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H1ptr + (here->JFETsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H1ptr + (here->JFETsourcePrimeNode)); + + r2h11x = *(job->r2H11ptr + (here->JFETgateNode)) - + *(job->r2H11ptr + (here->JFETsourcePrimeNode)); + i2h11x = *(job->i2H11ptr + (here->JFETgateNode)) - + *(job->i2H11ptr + (here->JFETsourcePrimeNode)); + + r2h11y = *(job->r2H11ptr + (here->JFETdrainPrimeNode)) - + *(job->r2H11ptr + (here->JFETsourcePrimeNode)); + i2h11y = *(job->i2H11ptr + (here->JFETdrainPrimeNode)) - + *(job->i2H11ptr + (here->JFETsourcePrimeNode)); + + r1hm2x = *(job->r1H2ptr + (here->JFETgateNode)) - + *(job->r1H2ptr + (here->JFETsourcePrimeNode)); + i1hm2x = -(*(job->i1H2ptr + (here->JFETgateNode)) - + *(job->i1H2ptr + (here->JFETsourcePrimeNode))); + + r1hm2y = *(job->r1H2ptr + (here->JFETdrainPrimeNode)) - + *(job->r1H2ptr + (here->JFETsourcePrimeNode)); +i1hm2y = -(*(job->i1H2ptr + (here->JFETdrainPrimeNode)) - + *(job->i1H2ptr + (here->JFETsourcePrimeNode))); + + r2h1m2x = *(job->r2H1m2ptr + (here->JFETgateNode)) - + *(job->r2H1m2ptr + (here->JFETsourcePrimeNode)); + i2h1m2x = *(job->i2H1m2ptr + (here->JFETgateNode)) - + *(job->i2H1m2ptr + (here->JFETsourcePrimeNode)); + + r2h1m2y = *(job->r2H1m2ptr + (here->JFETdrainPrimeNode)) - + *(job->r2H1m2ptr + (here->JFETsourcePrimeNode)); +i2h1m2y = *(job->i2H1m2ptr + (here->JFETdrainPrimeNode)) + - *(job->i2H1m2ptr + (here->JFETsourcePrimeNode)); + + /* loading starts here */ + /* loading cdrain term */ + +pass.cxx = here->cdr_x2; +pass.cyy = here->cdr_y2; +pass.czz = 0.0; +pass.cxy = here->cdr_xy; +pass.cyz = 0.0; +pass.cxz = 0.0; +pass.cxxx = here->cdr_x3; +pass.cyyy = here->cdr_y3; +pass.czzz = 0.0; +pass.cxxy = here->cdr_x2y; +pass.cxxz = 0.0; +pass.cxyy = here->cdr_xy2; +pass.cyyz = 0.0; +pass.cxzz = 0.0; +pass.cyzz = 0.0; +pass.cxyz = 0.0; +pass.r1h1x = r1h1x; +pass.i1h1x = i1h1x; +pass.r1h1y = r1h1y; +pass.i1h1y = i1h1y; +pass.r1h1z = 0.0; +pass.i1h1z = 0.0; +pass.r1h2x = r1hm2x; +pass.i1h2x = i1hm2x; +pass.r1h2y = r1hm2y; +pass.i1h2y = i1hm2y; +pass.r1h2z = 0.0; +pass.i1h2z = 0.0; +pass.r2h11x = r2h11x; +pass.i2h11x = i2h11x; +pass.r2h11y = r2h11y; +pass.i2h11y = i2h11y; +pass.r2h11z = 0.0; +pass.i2h11z = 0.0; +pass.h2f1f2x = r2h1m2x; +pass.ih2f1f2x = i2h1m2x; +pass.h2f1f2y = r2h1m2y; +pass.ih2f1f2y = i2h1m2y; +pass.h2f1f2z = 0.0; +pass.ih2f1f2z = 0.0; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1n2F12(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = D1i2F12(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1n2F12(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + itemp = D1i2F12(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = ckt->CKTomega * + D1n2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETsourcePrimeNode)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + + *(ckt->CKTrhs + (here->JFETgateNode)) -= temp; + *(ckt->CKTirhs + (here->JFETgateNode)) -= itemp; + *(ckt->CKTrhs + (here->JFETdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->JFETdrainPrimeNode)) += itemp; + + /* capgd over */ + + /* all done */ + + break; + default: +; + } + } +} +return(OK); +} + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/jfet/jfetdset.c b/src/spicelib/devices/jfet/jfetdset.c new file mode 100644 index 000000000..f11051946 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetdset.c @@ -0,0 +1,303 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "distodef.h" +#include "cktdefs.h" +#include "jfetdefs.h" +#include "const.h" +#include "trandefs.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +JFETdSetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register JFETmodel *model = (JFETmodel*)inModel; + register JFETinstance *here; + double beta; + double betap; + double lcapgd1; + double lcapgd2; + double lcapgd3; + double lcapgs2; + double lcapgs3; + double lcapgs1; + double cd; + double cdrain; + double temp; + double cg; + double cgd; + double csat; + double czgd; + double czgdf2; + double czgs; + double czgsf2; + double evgd; + double evgs; + double fcpb2; + double gdpr; + double gds1; + double gds2; + double gds3; + double lggd1; + double lggd2; + double lggd3; + double lggs1; + double lggs2; + double lggs3; + double gm1; + double gm2; + double gm3; + double gmds; + double gm2ds; + double gmds2; + double gspr; + double sarg; + double twob; + double twop; + double vds; + double vgd; + double vgs; + double vgst; + + /* loop through all the models */ + for( ; model != NULL; model = model->JFETnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->JFETinstances; here != NULL ; + here=here->JFETnextInstance) { + if (here->JFETowner != ARCHme) continue; + + /* + * dc model parameters + */ + beta = model->JFETbeta * here->JFETarea; + gdpr=model->JFETdrainConduct*here->JFETarea; + gspr=model->JFETsourceConduct*here->JFETarea; + csat=here->JFETtSatCur*here->JFETarea; + /* + * initialization + */ + vgs= model->JFETtype*(*(ckt->CKTrhsOld + here->JFETgateNode) + - *(ckt->CKTrhsOld + here->JFETsourcePrimeNode)); + vgd= model->JFETtype*(*(ckt->CKTrhsOld + here->JFETgateNode) + - *(ckt->CKTrhsOld + here->JFETdrainPrimeNode)); + /* + * determine dc current and derivatives + */ + vds=vgs-vgd; + + if (vds < 0.0) { + vds = -vds; + temp = vgs; + vgs = vgd; + vgd = temp; /* so now these have become the + local variables */ + here->JFETmode = -1; + } else { + here->JFETmode = 1; + } + + if (vgs <= -5*here->JFETtemp*CONSTKoverQ) { + lggs1 = -csat/vgs+ckt->CKTgmin; + lggs2=lggs3=0; + cg = lggs1*vgs; + } else { + evgs = exp(vgs/(here->JFETtemp*CONSTKoverQ)); + lggs1 = csat*evgs/(here->JFETtemp*CONSTKoverQ)+ckt->CKTgmin; + lggs2 = (lggs1-ckt->CKTgmin)/((here->JFETtemp*CONSTKoverQ)*2); + lggs3 = lggs2/(3*(here->JFETtemp*CONSTKoverQ)); + cg = csat*(evgs-1)+ckt->CKTgmin*vgs; + } + if (vgd <= -5*(here->JFETtemp*CONSTKoverQ)) { + lggd1 = -csat/vgd+ckt->CKTgmin; + lggd2=lggd3=0; + cgd = lggd1*vgd; + } else { + evgd = exp(vgd/(here->JFETtemp*CONSTKoverQ)); + lggd1 = csat*evgd/(here->JFETtemp*CONSTKoverQ)+ckt->CKTgmin; + lggd2 = (lggd1-ckt->CKTgmin)/((here->JFETtemp*CONSTKoverQ)*2); + lggd3 = lggd2/(3*(here->JFETtemp*CONSTKoverQ)); + cgd = csat*(evgd-1)+ckt->CKTgmin*vgd; + } + cg = cg+cgd; + /* + * compute drain current and derivatives + */ + vgst=vgs-model->JFETthreshold; + /* + * cutoff region + */ + if (vgst <= 0) { + cdrain=0; + gm1=gm2=gm3=0; + gds1=gds2=gds3=0; + gmds=gm2ds=gmds2=0; + } else { + betap=beta*(1+model->JFETlModulation*vds); + twob=betap+betap; + if (vgst <= vds) { + /* + * normal mode, saturation region + */ + + /* note - for cdrain, all the g's refer to the + * derivatives which have not been divided to + * become Taylor coeffs. A notational + * inconsistency but simplifies processing later. + */ + cdrain=betap*vgst*vgst; + gm1=twob*vgst; + gm2=twob; + gm3=0; + gds1=model->JFETlModulation*beta*vgst*vgst; + gds2=gds3=gmds2=0; + gm2ds=2*model->JFETlModulation*beta; + gmds=gm2ds*vgst; + } else { + /* + * normal mode, linear region + */ + cdrain=betap*vds*(vgst+vgst-vds); + gm1=twob*vds; + gm2=0; + gm3=0; + gmds=(beta+beta)*(1+2*model->JFETlModulation*vds); + gm2ds=0; + gds2=2*beta*(2*model->JFETlModulation*vgst - 1 - + 3*model->JFETlModulation*vds); + gds1=beta*(2*(vgst-vds) + 4*vgst*vds* + model->JFETlModulation - 3*model->JFETlModulation*vds*vds); + gmds2=4*beta*model->JFETlModulation; + gds3= -6*beta*model->JFETlModulation; + } + } + /* + * compute equivalent drain current source + */ + cd=cdrain-cgd; + /* + * charge storage elements + */ + czgs=here->JFETtCGS*here->JFETarea; + czgd=here->JFETtCGD*here->JFETarea; + twop=here->JFETtGatePot+here->JFETtGatePot; + fcpb2=here->JFETcorDepCap*here->JFETcorDepCap; + czgsf2=czgs/model->JFETf2; + czgdf2=czgd/model->JFETf2; + if (vgs < here->JFETcorDepCap) { + sarg=sqrt(1-vgs/here->JFETtGatePot); + lcapgs1=czgs/sarg; + lcapgs2=lcapgs1/(here->JFETtGatePot*4*sarg*sarg); + lcapgs3=lcapgs2/(here->JFETtGatePot*2*sarg*sarg); + } else { + lcapgs1=czgsf2*(model->JFETf3+vgs/twop); + lcapgs2=czgsf2/twop*0.5; + lcapgs3=0; + } + if (vgd < here->JFETcorDepCap) { + sarg=sqrt(1-vgd/here->JFETtGatePot); + lcapgd1=czgd/sarg; + lcapgd2=lcapgd1/(here->JFETtGatePot*4*sarg*sarg); + lcapgd3=lcapgd2/(here->JFETtGatePot*2*sarg*sarg); + } else { + lcapgd1=czgdf2*(model->JFETf3+vgd/twop); + lcapgd2=czgdf2/twop*0.5; + lcapgd3=0; + } + /* + * process to get Taylor coefficients, taking into + * account type and mode. + */ + + if (here->JFETmode == 1) + { + /* normal mode - no source-drain interchange */ +here->cdr_x = gm1; +here->cdr_y = gds1; +here->cdr_x2 = gm2; +here->cdr_y2 = gds2; +here->cdr_xy = gmds; +here->cdr_x3 = gm3; +here->cdr_y3 = gds3; +here->cdr_x2y = gm2ds; +here->cdr_xy2 = gmds2; + +here->ggs1 = lggs1; +here->ggd1 = lggd1; +here->ggs2 = lggs2; +here->ggd2 = lggd2; +here->ggs3 = lggs3; +here->ggd3 = lggd3; +here->capgs1 = lcapgs1; +here->capgd1 = lcapgd1; +here->capgs2 = lcapgs2; +here->capgd2 = lcapgd2; +here->capgs3 = lcapgs3; +here->capgd3 = lcapgd3; +} else { + /* + * inverse mode - source and drain interchanged + */ + + +here->cdr_x = -gm1; +here->cdr_y = gm1 + gds1; +here->cdr_x2 = -gm2; +here->cdr_y2 = -(gm2 + gds2 + 2*gmds); +here->cdr_xy = gm2 + gmds; +here->cdr_x3 = -gm3; +here->cdr_y3 = gm3 + gds3 + 3*(gm2ds + gmds2 ) ; +here->cdr_x2y = gm3 + gm2ds; +here->cdr_xy2 = -(gm3 + 2*gm2ds + gmds2); + +here->ggs1 = lggd1; +here->ggd1 = lggs1; + +here->ggs2 = lggd2; +here->ggd2 = lggs2; + +here->ggs3 = lggd3; +here->ggd3 = lggs3; + +here->capgs1 = lcapgd1; +here->capgd1 = lcapgs1; + +here->capgs2 = lcapgd2; +here->capgd2 = lcapgs2; + +here->capgs3 = lcapgd3; +here->capgd3 = lcapgs3; +} + +/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ + +here->cdr_x2 = 0.5*model->JFETtype*here->cdr_x2; +here->cdr_y2 = 0.5*model->JFETtype*here->cdr_y2; +here->cdr_xy = model->JFETtype*here->cdr_xy; +here->cdr_x3 = here->cdr_x3/6.; +here->cdr_y3 = here->cdr_y3/6.; +here->cdr_x2y = 0.5*here->cdr_x2y; +here->cdr_xy2 = 0.5*here->cdr_xy2; + + +here->ggs2 = model->JFETtype*lggs2; +here->ggd2 = model->JFETtype*lggd2; + +here->capgs2 = model->JFETtype*lcapgs2; +here->capgd2 = model->JFETtype*lcapgd2; + + } + } + return(OK); + } diff --git a/src/spicelib/devices/jfet/jfetext.h b/src/spicelib/devices/jfet/jfetext.h new file mode 100644 index 000000000..9da1e4ea0 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetext.h @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int JFETacLoad(GENmodel*,CKTcircuit*); +extern int JFETask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int JFETdelete(GENmodel*,IFuid,GENinstance**); +extern void JFETdestroy(GENmodel**); +extern int JFETgetic(GENmodel*,CKTcircuit*); +extern int JFETload(GENmodel*,CKTcircuit*); +extern int JFETmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int JFETmDelete(GENmodel**,IFuid,GENmodel*); +extern int JFETmParam(int,IFvalue*,GENmodel*); +extern int JFETparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int JFETpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int JFETsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int JFETunsetup(GENmodel*,CKTcircuit*); +extern int JFETtemp(GENmodel*,CKTcircuit*); +extern int JFETtrunc(GENmodel*,CKTcircuit*,double*); +extern int JFETdisto(int,GENmodel*,CKTcircuit*); +extern int JFETnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ +extern int JFETacLoad(); +extern int JFETask(); +extern int JFETdelete(); +extern void JFETdestroy(); +extern int JFETgetic(); +extern int JFETload(); +extern int JFETmAsk(); +extern int JFETmDelete(); +extern int JFETmParam(); +extern int JFETparam(); +extern int JFETpzLoad(); +extern int JFETsetup(); +extern int JFETunsetup(); +extern int JFETtemp(); +extern int JFETtrunc(); +extern int JFETdisto(); +extern int JFETnoise(); +#endif /* stdc */ diff --git a/src/spicelib/devices/jfet/jfetic.c b/src/spicelib/devices/jfet/jfetic.c new file mode 100644 index 000000000..cdad6d4d9 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetic.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFETgetic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + JFETmodel *model = (JFETmodel*)inModel; + JFETinstance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->JFETnextModel) { + for(here = model->JFETinstances; here ; here = here->JFETnextInstance) { + if (here->JFETowner != ARCHme) continue; + + if(!here->JFETicVDSGiven) { + here->JFETicVDS = + *(ckt->CKTrhs + here->JFETdrainNode) - + *(ckt->CKTrhs + here->JFETsourceNode); + } + if(!here->JFETicVGSGiven) { + here->JFETicVGS = + *(ckt->CKTrhs + here->JFETgateNode) - + *(ckt->CKTrhs + here->JFETsourceNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet/jfetitf.h b/src/spicelib/devices/jfet/jfetitf.h new file mode 100644 index 000000000..1ac351fff --- /dev/null +++ b/src/spicelib/devices/jfet/jfetitf.h @@ -0,0 +1,88 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_jfet + +#ifndef DEV_JFET +#define DEV_JFET + +#include "jfetext.h" +extern IFparm JFETpTable[ ]; +extern IFparm JFETmPTable[ ]; +extern char *JFETnames[ ]; +extern int JFETpTSize; +extern int JFETmPTSize; +extern int JFETnSize; +extern int JFETiSize; +extern int JFETmSize; + +SPICEdev JFETinfo = { + { + "JFET", + "Junction Field effect transistor", + + &JFETnSize, + &JFETnSize, + JFETnames, + + &JFETpTSize, + JFETpTable, + + &JFETmPTSize, + JFETmPTable, + DEV_DEFAULT + }, + + JFETparam, + JFETmParam, + JFETload, + JFETsetup, + JFETunsetup, + JFETsetup, + JFETtemp, + JFETtrunc, + NULL, + JFETacLoad, + NULL, + JFETdestroy, +#ifdef DELETES + JFETmDelete, + JFETdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + JFETgetic, + JFETask, + JFETmAsk, +#ifdef AN_pz + JFETpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#ifdef AN_disto + JFETdisto, +#else /* AN_disto */ + NULL, +#endif /* AN_disto */ +#ifdef AN_noise + JFETnoise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &JFETiSize, + &JFETmSize + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/jfet/jfetload.c b/src/spicelib/devices/jfet/jfetload.c new file mode 100644 index 000000000..3baeab8b8 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetload.c @@ -0,0 +1,518 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Sydney University mods Copyright(c) 1989 Anthony E. Parker, David J. Skellern + Laboratory for Communication Science Engineering + Sydney University Department of Electrical Engineering, Australia +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfetdefs.h" +#include "const.h" +#include "trandefs.h" +#include "sperror.h" +#include "devdefs.h" +#include "suffix.h" + +int +JFETload(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register JFETmodel *model = (JFETmodel*)inModel; + register JFETinstance *here; + double beta; + double betap; + double capgd; + double capgs; + double cd; + double cdhat; + double cdrain; + double cdreq; + double ceq; + double ceqgd; + double ceqgs; + double cg; + double cgd; + double cghat; + double csat; + double czgd; + double czgdf2; + double czgs; + double czgsf2; + double delvds; + double delvgd; + double delvgs; + double evgd; + double evgs; + double fcpb2; + double gdpr; + double gds; + double geq; + double ggd; + double ggs; + double gm; + double gspr; + double sarg; + double twop; + double vds; + double vgd; + double vgdt; + double vgs; + double vgst; + double xfact; + /* Modification for Sydney University JFET model */ + double vto; + double apart,cpart; + double Bfac; + /* end Sydney University mod. */ + int icheck; + int ichk1; + int error; + + /* loop through all the models */ + for( ; model != NULL; model = model->JFETnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->JFETinstances; here != NULL ; + here=here->JFETnextInstance) { + if (here->JFETowner != ARCHme) continue; + + /* + * dc model parameters + */ + beta = model->JFETbeta * here->JFETarea; + gdpr=model->JFETdrainConduct*here->JFETarea; + gspr=model->JFETsourceConduct*here->JFETarea; + csat=here->JFETtSatCur*here->JFETarea; + /* + * initialization + */ + icheck=1; + if( ckt->CKTmode & MODEINITSMSIG) { + vgs= *(ckt->CKTstate0 + here->JFETvgs); + vgd= *(ckt->CKTstate0 + here->JFETvgd); + } else if (ckt->CKTmode & MODEINITTRAN) { + vgs= *(ckt->CKTstate1 + here->JFETvgs); + vgd= *(ckt->CKTstate1 + here->JFETvgd); + } else if ( (ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC) ) { + vds=model->JFETtype*here->JFETicVDS; + vgs=model->JFETtype*here->JFETicVGS; + vgd=vgs-vds; + } else if ( (ckt->CKTmode & MODEINITJCT) && + (here->JFEToff == 0) ) { + vgs = -1; + vgd = -1; + } else if( (ckt->CKTmode & MODEINITJCT) || + ((ckt->CKTmode & MODEINITFIX) && (here->JFEToff))) { + vgs = 0; + vgd = 0; + } else { +#ifndef PREDICTOR + if(ckt->CKTmode & MODEINITPRED) { + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->JFETvgs)= + *(ckt->CKTstate1 + here->JFETvgs); + vgs=(1+xfact)* *(ckt->CKTstate1 + here->JFETvgs)-xfact* + *(ckt->CKTstate2 + here->JFETvgs); + *(ckt->CKTstate0 + here->JFETvgd)= + *(ckt->CKTstate1 + here->JFETvgd); + vgd=(1+xfact)* *(ckt->CKTstate1 + here->JFETvgd)-xfact* + *(ckt->CKTstate2 + here->JFETvgd); + *(ckt->CKTstate0 + here->JFETcg)= + *(ckt->CKTstate1 + here->JFETcg); + *(ckt->CKTstate0 + here->JFETcd)= + *(ckt->CKTstate1 + here->JFETcd); + *(ckt->CKTstate0 + here->JFETcgd)= + *(ckt->CKTstate1 + here->JFETcgd); + *(ckt->CKTstate0 + here->JFETgm)= + *(ckt->CKTstate1 + here->JFETgm); + *(ckt->CKTstate0 + here->JFETgds)= + *(ckt->CKTstate1 + here->JFETgds); + *(ckt->CKTstate0 + here->JFETggs)= + *(ckt->CKTstate1 + here->JFETggs); + *(ckt->CKTstate0 + here->JFETggd)= + *(ckt->CKTstate1 + here->JFETggd); + } else { +#endif /*PREDICTOR*/ + /* + * compute new nonlinear branch voltages + */ + vgs=model->JFETtype* + (*(ckt->CKTrhsOld+ here->JFETgateNode)- + *(ckt->CKTrhsOld+ + here->JFETsourcePrimeNode)); + vgd=model->JFETtype* + (*(ckt->CKTrhsOld+here->JFETgateNode)- + *(ckt->CKTrhsOld+ + here->JFETdrainPrimeNode)); +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + delvgs=vgs- *(ckt->CKTstate0 + here->JFETvgs); + delvgd=vgd- *(ckt->CKTstate0 + here->JFETvgd); + delvds=delvgs-delvgd; + cghat= *(ckt->CKTstate0 + here->JFETcg)+ + *(ckt->CKTstate0 + here->JFETggd)*delvgd+ + *(ckt->CKTstate0 + here->JFETggs)*delvgs; + cdhat= *(ckt->CKTstate0 + here->JFETcd)+ + *(ckt->CKTstate0 + here->JFETgm)*delvgs+ + *(ckt->CKTstate0 + here->JFETgds)*delvds- + *(ckt->CKTstate0 + here->JFETggd)*delvgd; + /* + * bypass if solution has not changed + */ + if((ckt->CKTbypass) && + (!(ckt->CKTmode & MODEINITPRED)) && + (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs), + fabs(*(ckt->CKTstate0 + here->JFETvgs)))+ + ckt->CKTvoltTol) ) + if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd), + fabs(*(ckt->CKTstate0 + here->JFETvgd)))+ + ckt->CKTvoltTol)) + if ( (fabs(cghat-*(ckt->CKTstate0 + here->JFETcg)) + < ckt->CKTreltol*MAX(fabs(cghat), + fabs(*(ckt->CKTstate0 + here->JFETcg)))+ + ckt->CKTabstol) ) if ( /* hack - expression too big */ + (fabs(cdhat-*(ckt->CKTstate0 + here->JFETcd)) + < ckt->CKTreltol*MAX(fabs(cdhat), + fabs(*(ckt->CKTstate0 + here->JFETcd)))+ + ckt->CKTabstol) ) { + + /* we can do a bypass */ + vgs= *(ckt->CKTstate0 + here->JFETvgs); + vgd= *(ckt->CKTstate0 + here->JFETvgd); + vds= vgs-vgd; + cg= *(ckt->CKTstate0 + here->JFETcg); + cd= *(ckt->CKTstate0 + here->JFETcd); + cgd= *(ckt->CKTstate0 + here->JFETcgd); + gm= *(ckt->CKTstate0 + here->JFETgm); + gds= *(ckt->CKTstate0 + here->JFETgds); + ggs= *(ckt->CKTstate0 + here->JFETggs); + ggd= *(ckt->CKTstate0 + here->JFETggd); + goto load; + } + /* + * limit nonlinear branch voltages + */ + ichk1=1; + vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->JFETvgs), + (here->JFETtemp*CONSTKoverQ), here->JFETvcrit, &icheck); + vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->JFETvgd), + (here->JFETtemp*CONSTKoverQ), here->JFETvcrit,&ichk1); + if (ichk1 == 1) { + icheck=1; + } + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->JFETvgs), + model->JFETthreshold); + vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->JFETvgd), + model->JFETthreshold); + } + /* + * determine dc current and derivatives + */ + vds=vgs-vgd; + if (vgs <= -5*here->JFETtemp*CONSTKoverQ) { + ggs = -csat/vgs+ckt->CKTgmin; + cg = ggs*vgs; + } else { + evgs = exp(vgs/(here->JFETtemp*CONSTKoverQ)); + ggs = csat*evgs/(here->JFETtemp*CONSTKoverQ)+ckt->CKTgmin; + cg = csat*(evgs-1)+ckt->CKTgmin*vgs; + } + if (vgd <= -5*(here->JFETtemp*CONSTKoverQ)) { + ggd = -csat/vgd+ckt->CKTgmin; + cgd = ggd*vgd; + } else { + evgd = exp(vgd/(here->JFETtemp*CONSTKoverQ)); + ggd = csat*evgd/(here->JFETtemp*CONSTKoverQ)+ckt->CKTgmin; + cgd = csat*(evgd-1)+ckt->CKTgmin*vgd; + } + cg = cg+cgd; + + /* Modification for Sydney University JFET model */ + vto = model->JFETthreshold; + if (vds >= 0) { + vgst = vgs - vto; + /* + * compute drain current and derivatives for normal mode + */ + if (vgst <= 0) { + /* + * normal mode, cutoff region + */ + cdrain = 0; + gm = 0; + gds = 0; + } else { + betap = beta*(1 + model->JFETlModulation*vds); + Bfac = model->JFETbFac; + if (vgst >= vds) { + /* + * normal mode, linear region + */ + apart = 2*model->JFETb + 3*Bfac*(vgst - vds); + cpart = vds*(vds*(Bfac*vds - model->JFETb)+vgst*apart); + cdrain = betap*cpart; + gm = betap*vds*(apart + 3*Bfac*vgst); + gds = betap*(vgst - vds)*apart + + beta*model->JFETlModulation*cpart; + } else { + Bfac = vgst*Bfac; + gm = betap*vgst*(2*model->JFETb+3*Bfac); + /* + * normal mode, saturation region + */ + cpart=vgst*vgst*(model->JFETb+Bfac); + cdrain = betap*cpart; + gds = model->JFETlModulation*beta*cpart; + } + } + } else { + vgdt = vgd - vto; + /* + * compute drain current and derivatives for inverse mode + */ + if (vgdt <= 0) { + /* + * inverse mode, cutoff region + */ + cdrain = 0; + gm = 0; + gds = 0; + } else { + betap = beta*(1 - model->JFETlModulation*vds); + Bfac = model->JFETbFac; + if (vgdt + vds >= 0) { + /* + * inverse mode, linear region + */ + apart = 2*model->JFETb + 3*Bfac*(vgdt + vds); + cpart = vds*(-vds*(-Bfac*vds-model->JFETb)+vgdt*apart); + cdrain = betap*cpart; + gm = betap*vds*(apart + 3*Bfac*vgdt); + gds = betap*(vgdt + vds)*apart + - beta*model->JFETlModulation*cpart - gm; + } else { + Bfac = vgdt*Bfac; + gm = -betap*vgdt*(2*model->JFETb+3*Bfac); + /* + * inverse mode, saturation region + */ + cpart=vgdt*vgdt*(model->JFETb+Bfac); + cdrain = - betap*cpart; + gds = model->JFETlModulation*beta*cpart-gm; + } + } + } +#ifdef notdef + /* The original section is now commented out */ + /* end Sydney University mod */ + /* + * compute drain current and derivitives for normal mode + */ + if (vds >= 0) { + vgst=vgs-model->JFETthreshold; + /* + * normal mode, cutoff region + */ + if (vgst <= 0) { + cdrain=0; + gm=0; + gds=0; + } else { + betap=beta*(1+model->JFETlModulation*vds); + twob=betap+betap; + if (vgst <= vds) { + /* + * normal mode, saturation region + */ + cdrain=betap*vgst*vgst; + gm=twob*vgst; + gds=model->JFETlModulation*beta*vgst*vgst; + } else { + /* + * normal mode, linear region + */ + cdrain=betap*vds*(vgst+vgst-vds); + gm=twob*vds; + gds=twob*(vgst-vds)+model->JFETlModulation*beta* + vds*(vgst+vgst-vds); + } + } + } else { + /* + * compute drain current and derivitives for inverse mode + */ + vgdt=vgd-model->JFETthreshold; + if (vgdt <= 0) { + /* + * inverse mode, cutoff region + */ + cdrain=0; + gm=0; + gds=0; + } else { + /* + * inverse mode, saturation region + */ + betap=beta*(1-model->JFETlModulation*vds); + twob=betap+betap; + if (vgdt <= -vds) { + cdrain = -betap*vgdt*vgdt; + gm = -twob*vgdt; + gds = model->JFETlModulation*beta*vgdt*vgdt-gm; + } else { + /* + * inverse mode, linear region + */ + cdrain=betap*vds*(vgdt+vgdt+vds); + gm=twob*vds; + gds=twob*vgdt-model->JFETlModulation*beta*vds* + (vgdt+vgdt+vds); + } + } + } + /* end of original section, now deleted (replaced w/SU mod */ +#endif + /* + * compute equivalent drain current source + */ + cd=cdrain-cgd; + if ( (ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG) ) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){ + /* + * charge storage elements + */ + czgs=here->JFETtCGS*here->JFETarea; + czgd=here->JFETtCGD*here->JFETarea; + twop=here->JFETtGatePot+here->JFETtGatePot; + fcpb2=here->JFETcorDepCap*here->JFETcorDepCap; + czgsf2=czgs/model->JFETf2; + czgdf2=czgd/model->JFETf2; + if (vgs < here->JFETcorDepCap) { + sarg=sqrt(1-vgs/here->JFETtGatePot); + *(ckt->CKTstate0 + here->JFETqgs) = twop*czgs*(1-sarg); + capgs=czgs/sarg; + } else { + *(ckt->CKTstate0 + here->JFETqgs) = czgs*here->JFETf1 + + czgsf2*(model->JFETf3 *(vgs- + here->JFETcorDepCap)+(vgs*vgs-fcpb2)/ + (twop+twop)); + capgs=czgsf2*(model->JFETf3+vgs/twop); + } + if (vgd < here->JFETcorDepCap) { + sarg=sqrt(1-vgd/here->JFETtGatePot); + *(ckt->CKTstate0 + here->JFETqgd) = twop*czgd*(1-sarg); + capgd=czgd/sarg; + } else { + *(ckt->CKTstate0 + here->JFETqgd) = czgd*here->JFETf1+ + czgdf2*(model->JFETf3* (vgd- + here->JFETcorDepCap)+(vgd*vgd-fcpb2)/ + (twop+twop)); + capgd=czgdf2*(model->JFETf3+vgd/twop); + } + /* + * store small-signal parameters + */ + if( (!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC)) ) { + if(ckt->CKTmode & MODEINITSMSIG) { + *(ckt->CKTstate0 + here->JFETqgs) = capgs; + *(ckt->CKTstate0 + here->JFETqgd) = capgd; + continue; /*go to 1000*/ + } + /* + * transient analysis + */ + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->JFETqgs) = + *(ckt->CKTstate0 + here->JFETqgs); + *(ckt->CKTstate1 + here->JFETqgd) = + *(ckt->CKTstate0 + here->JFETqgd); + } + error = NIintegrate(ckt,&geq,&ceq,capgs,here->JFETqgs); + if(error) return(error); + ggs = ggs + geq; + cg = cg + *(ckt->CKTstate0 + here->JFETcqgs); + error = NIintegrate(ckt,&geq,&ceq,capgd,here->JFETqgd); + if(error) return(error); + ggd = ggd + geq; + cg = cg + *(ckt->CKTstate0 + here->JFETcqgd); + cd = cd - *(ckt->CKTstate0 + here->JFETcqgd); + cgd = cgd + *(ckt->CKTstate0 + here->JFETcqgd); + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->JFETcqgs) = + *(ckt->CKTstate0 + here->JFETcqgs); + *(ckt->CKTstate1 + here->JFETcqgd) = + *(ckt->CKTstate0 + here->JFETcqgd); + } + } + } + /* + * check convergence + */ + if( (!(ckt->CKTmode & MODEINITFIX)) | (!(ckt->CKTmode & MODEUIC))) { + if( (icheck == 1) +#ifndef NEWCONV +/* XXX */ +#endif /*NEWCONV*/ + || (fabs(cghat-cg) >= ckt->CKTreltol* + MAX(fabs(cghat),fabs(cg))+ckt->CKTabstol) || + (fabs(cdhat-cd) > ckt->CKTreltol* + MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol) + ) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } + *(ckt->CKTstate0 + here->JFETvgs) = vgs; + *(ckt->CKTstate0 + here->JFETvgd) = vgd; + *(ckt->CKTstate0 + here->JFETcg) = cg; + *(ckt->CKTstate0 + here->JFETcd) = cd; + *(ckt->CKTstate0 + here->JFETcgd) = cgd; + *(ckt->CKTstate0 + here->JFETgm) = gm; + *(ckt->CKTstate0 + here->JFETgds) = gds; + *(ckt->CKTstate0 + here->JFETggs) = ggs; + *(ckt->CKTstate0 + here->JFETggd) = ggd; + /* + * load current vector + */ +load: + ceqgd=model->JFETtype*(cgd-ggd*vgd); + ceqgs=model->JFETtype*((cg-cgd)-ggs*vgs); + cdreq=model->JFETtype*((cd+cgd)-gds*vds-gm*vgs); + *(ckt->CKTrhs + here->JFETgateNode) += (-ceqgs-ceqgd); + *(ckt->CKTrhs + here->JFETdrainPrimeNode) += + (-cdreq+ceqgd); + *(ckt->CKTrhs + here->JFETsourcePrimeNode) += + (cdreq+ceqgs); + /* + * load y matrix + */ + *(here->JFETdrainDrainPrimePtr) += (-gdpr); + *(here->JFETgateDrainPrimePtr) += (-ggd); + *(here->JFETgateSourcePrimePtr) += (-ggs); + *(here->JFETsourceSourcePrimePtr) += (-gspr); + *(here->JFETdrainPrimeDrainPtr) += (-gdpr); + *(here->JFETdrainPrimeGatePtr) += (gm-ggd); + *(here->JFETdrainPrimeSourcePrimePtr) += (-gds-gm); + *(here->JFETsourcePrimeGatePtr) += (-ggs-gm); + *(here->JFETsourcePrimeSourcePtr) += (-gspr); + *(here->JFETsourcePrimeDrainPrimePtr) += (-gds); + *(here->JFETdrainDrainPtr) += (gdpr); + *(here->JFETgateGatePtr) += (ggd+ggs); + *(here->JFETsourceSourcePtr) += (gspr); + *(here->JFETdrainPrimeDrainPrimePtr) += (gdpr+gds+ggd); + *(here->JFETsourcePrimeSourcePrimePtr) += (gspr+gds+gm+ggs); + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet/jfetmask.c b/src/spicelib/devices/jfet/jfetmask.c new file mode 100644 index 000000000..8a874ec98 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetmask.c @@ -0,0 +1,87 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles +Sydney University mods Copyright(c) 1989 Anthony E. Parker, David J. Skellern + Laboratory for Communication Science Engineering + Sydney University Department of Electrical Engineering, Australia +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +JFETmAsk(ckt,inModel,which,value) + CKTcircuit *ckt; + GENmodel *inModel; + int which; + IFvalue *value; +{ + JFETmodel *model = (JFETmodel*)inModel; + switch(which) { + case JFET_MOD_TNOM: + value->rValue = model->JFETtnom-CONSTCtoK; + return(OK); + case JFET_MOD_VTO: + value->rValue = model->JFETthreshold; + return(OK); + case JFET_MOD_BETA: + value->rValue = model->JFETbeta; + return(OK); + case JFET_MOD_LAMBDA: + value->rValue = model->JFETlModulation; + return(OK); + /* Modification for Sydney University JFET model */ + case JFET_MOD_B: + value->rValue = model->JFETb; + return(OK); + /* end Sydney University mod */ + case JFET_MOD_RD: + value->rValue = model->JFETdrainResist; + return(OK); + case JFET_MOD_RS: + value->rValue = model->JFETsourceResist; + return(OK); + case JFET_MOD_CGS: + value->rValue = model->JFETcapGS; + return(OK); + case JFET_MOD_CGD: + value->rValue = model->JFETcapGD; + return(OK); + case JFET_MOD_PB: + value->rValue = model->JFETgatePotential; + return(OK); + case JFET_MOD_IS: + value->rValue = model->JFETgateSatCurrent; + return(OK); + case JFET_MOD_FC: + value->rValue = model->JFETdepletionCapCoeff; + return(OK); + case JFET_MOD_DRAINCONDUCT: + value->rValue = model->JFETdrainConduct; + return(OK); + case JFET_MOD_SOURCECONDUCT: + value->rValue = model->JFETsourceConduct; + return(OK); + case JFET_MOD_TYPE: + if (model->JFETtype == NJF) + value->sValue = "njf"; + else + value->sValue = "pjf"; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/jfet/jfetmdel.c b/src/spicelib/devices/jfet/jfetmdel.c new file mode 100644 index 000000000..e6395f035 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFETmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + JFETmodel **model = (JFETmodel**)inModel; + JFETmodel *modfast = (JFETmodel*)kill; + JFETinstance *here; + JFETinstance *prev = NULL; + JFETmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->JFETnextModel)) { + if( (*model)->JFETmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->JFETnextModel; /* cut deleted device out of list */ + for(here = (*model)->JFETinstances ; here ; here = here->JFETnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/jfet/jfetmpar.c b/src/spicelib/devices/jfet/jfetmpar.c new file mode 100644 index 000000000..fba72ce57 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetmpar.c @@ -0,0 +1,97 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFETmParam(param,value,inModels) + int param; + IFvalue *value; + GENmodel *inModels; +{ + JFETmodel *model = (JFETmodel*)inModels; + switch(param) { + case JFET_MOD_TNOM: + model->JFETtnomGiven = TRUE; + model->JFETtnom = value->rValue+CONSTCtoK; + break; + case JFET_MOD_VTO: + model->JFETthresholdGiven = TRUE; + model->JFETthreshold = value->rValue; + break; + case JFET_MOD_BETA: + model->JFETbetaGiven = TRUE; + model->JFETbeta = value->rValue; + break; + case JFET_MOD_LAMBDA: + model->JFETlModulationGiven = TRUE; + model->JFETlModulation = value->rValue; + break; + case JFET_MOD_RD: + model->JFETdrainResistGiven = TRUE; + model->JFETdrainResist = value->rValue; + break; + case JFET_MOD_RS: + model->JFETsourceResistGiven = TRUE; + model->JFETsourceResist = value->rValue; + break; + case JFET_MOD_CGS: + model->JFETcapGSGiven = TRUE; + model->JFETcapGS = value->rValue; + break; + case JFET_MOD_CGD: + model->JFETcapGDGiven = TRUE; + model->JFETcapGD = value->rValue; + break; + case JFET_MOD_PB: + model->JFETgatePotentialGiven = TRUE; + model->JFETgatePotential = value->rValue; + break; + case JFET_MOD_IS: + model->JFETgateSatCurrentGiven = TRUE; + model->JFETgateSatCurrent = value->rValue; + break; + case JFET_MOD_FC: + model->JFETdepletionCapCoeffGiven = TRUE; + model->JFETdepletionCapCoeff = value->rValue; + break; + case JFET_MOD_NJF: + if(value->iValue) { + model->JFETtype = NJF; + } + break; + case JFET_MOD_PJF: + if(value->iValue) { + model->JFETtype = PJF; + } + break; + case JFET_MOD_KF: + model->JFETfNcoefGiven = TRUE; + model->JFETfNcoef = value->rValue; + break; + case JFET_MOD_AF: + model->JFETfNexpGiven = TRUE; + model->JFETfNexp = value->rValue; + break; + /* Modification for Sydney University JFET model */ + case JFET_MOD_B: + model->JFETbGiven = TRUE; + model->JFETb = value->rValue; + return(OK); + /* end Sydney University mod */ + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/jfet/jfetnoi.c b/src/spicelib/devices/jfet/jfetnoi.c new file mode 100644 index 000000000..85b3988ba --- /dev/null +++ b/src/spicelib/devices/jfet/jfetnoi.c @@ -0,0 +1,217 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "jfetdefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * JFETnoise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with JFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the JFET's is summed with the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +JFETnoise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + JFETmodel *firstModel = (JFETmodel *) genmodel; + register JFETmodel *model; + register JFETinstance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[JFETNSRCS]; + double lnNdens[JFETNSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *JFETnNames[JFETNSRCS] = { /* Note that we have to keep the order */ + "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ + "_rs", /* noise due to rs */ /* in JFETdefs.h */ + "_id", /* noise due to id */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->JFETnextModel) { + for (inst=model->JFETinstances; inst != NULL; inst=inst->JFETnextInstance) { + if (inst->JFETowner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < JFETNSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->JFETname,JFETnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + + case INT_NOIZ: + for (i=0; i < JFETNSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->JFETname,JFETnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->JFETname,JFETnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[JFETRDNOIZ],&lnNdens[JFETRDNOIZ], + ckt,THERMNOISE,inst->JFETdrainPrimeNode,inst->JFETdrainNode, + model->JFETdrainConduct * inst->JFETarea); + + NevalSrc(&noizDens[JFETRSNOIZ],&lnNdens[JFETRSNOIZ], + ckt,THERMNOISE,inst->JFETsourcePrimeNode, + inst->JFETsourceNode,model->JFETsourceConduct*inst->JFETarea); + + NevalSrc(&noizDens[JFETIDNOIZ],&lnNdens[JFETIDNOIZ], + ckt,THERMNOISE,inst->JFETdrainPrimeNode, + inst->JFETsourcePrimeNode, + (2.0/3.0 * fabs(*(ckt->CKTstate0 + inst->JFETgm)))); + + NevalSrc(&noizDens[JFETFLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->JFETdrainPrimeNode, + inst->JFETsourcePrimeNode, (double)0.0); + noizDens[JFETFLNOIZ] *= model->JFETfNcoef * + exp(model->JFETfNexp * + log(MAX(fabs(*(ckt->CKTstate0 + inst->JFETcd)),N_MINLOG))) / + data->freq; + lnNdens[JFETFLNOIZ] = + log(MAX(noizDens[JFETFLNOIZ],N_MINLOG)); + + noizDens[JFETTOTNOIZ] = noizDens[JFETRDNOIZ] + + noizDens[JFETRSNOIZ] + + noizDens[JFETIDNOIZ] + + noizDens[JFETFLNOIZ]; + lnNdens[JFETTOTNOIZ] = + log(MAX(noizDens[JFETTOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[JFETTOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < JFETNSRCS; i++) { + inst->JFETnVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < JFETNSRCS; i++) { + inst->JFETnVar[OUTNOIZ][i] = 0.0; + inst->JFETnVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + for (i=0; i < JFETNSRCS; i++) { + if (i != JFETTOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->JFETnVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->JFETnVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->JFETnVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->JFETnVar[OUTNOIZ][i] += tempOnoise; + inst->JFETnVar[OUTNOIZ][JFETTOTNOIZ] += tempOnoise; + inst->JFETnVar[INNOIZ][i] += tempInoise; + inst->JFETnVar[INNOIZ][JFETTOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < JFETNSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < JFETNSRCS; i++) { + data->outpVector[data->outNumber++] = inst->JFETnVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->JFETnVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} + + diff --git a/src/spicelib/devices/jfet/jfetpar.c b/src/spicelib/devices/jfet/jfetpar.c new file mode 100644 index 000000000..8c1550577 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetpar.c @@ -0,0 +1,63 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +JFETparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + JFETinstance *here = (JFETinstance *)inst; + switch(param) { + case JFET_TEMP: + here->JFETtemp = value->rValue+CONSTCtoK; + here->JFETtempGiven = TRUE; + break; + case JFET_AREA: + here->JFETarea = value->rValue; + here->JFETareaGiven = TRUE; + break; + case JFET_IC_VDS: + here->JFETicVDS = value->rValue; + here->JFETicVDSGiven = TRUE; + break; + case JFET_IC_VGS: + here->JFETicVGS = value->rValue; + here->JFETicVGSGiven = TRUE; + break; + case JFET_OFF: + here->JFEToff = value->iValue; + break; + case JFET_IC: + switch(value->v.numValue) { + case 2: + here->JFETicVGS = *(value->v.vec.rVec+1); + here->JFETicVGSGiven = TRUE; + case 1: + here->JFETicVDS = *(value->v.vec.rVec); + here->JFETicVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/jfet/jfetpzld.c b/src/spicelib/devices/jfet/jfetpzld.c new file mode 100644 index 000000000..997cf0af3 --- /dev/null +++ b/src/spicelib/devices/jfet/jfetpzld.c @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "jfetdefs.h" +#include "suffix.h" + + +int +JFETpzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + register SPcomplex *s; +{ + register JFETmodel *model = (JFETmodel*)inModel; + register JFETinstance *here; + double gdpr; + double gspr; + double gm; + double gds; + double ggs; + double xgs; + double ggd; + double xgd; + + for( ; model != NULL; model = model->JFETnextModel ) { + + for( here = model->JFETinstances; here != NULL; + here = here->JFETnextInstance) { + if (here->JFETowner != ARCHme) continue; + + gdpr=model->JFETdrainResist * here->JFETarea; + gspr=model->JFETsourceResist * here->JFETarea; + gm= *(ckt->CKTstate0 + here->JFETgm) ; + gds= *(ckt->CKTstate0 + here->JFETgds) ; + ggs= *(ckt->CKTstate0 + here->JFETggs) ; + xgs= *(ckt->CKTstate0 + here->JFETqgs) ; + ggd= *(ckt->CKTstate0 + here->JFETggd) ; + xgd= *(ckt->CKTstate0 + here->JFETqgd) ; + *(here->JFETdrainDrainPtr ) += gdpr; + *(here->JFETgateGatePtr ) += ggd+ggs; + *(here->JFETgateGatePtr ) += (xgd+xgs) * s->real; + *(here->JFETgateGatePtr +1) += (xgd+xgs) * s->imag; + *(here->JFETsourceSourcePtr ) += gspr; + *(here->JFETdrainPrimeDrainPrimePtr ) += gdpr+gds+ggd; + *(here->JFETdrainPrimeDrainPrimePtr ) += xgd * s->real; + *(here->JFETdrainPrimeDrainPrimePtr +1) += xgd * s->imag; + *(here->JFETsourcePrimeSourcePrimePtr ) += gspr+gds+gm+ggs; + *(here->JFETsourcePrimeSourcePrimePtr ) += xgs * s->real; + *(here->JFETsourcePrimeSourcePrimePtr +1) += xgs * s->imag; + *(here->JFETdrainDrainPrimePtr ) -= gdpr; + *(here->JFETgateDrainPrimePtr ) -= ggd; + *(here->JFETgateDrainPrimePtr ) -= xgd * s->real; + *(here->JFETgateDrainPrimePtr +1) -= xgd * s->imag; + *(here->JFETgateSourcePrimePtr ) -= ggs; + *(here->JFETgateSourcePrimePtr ) -= xgs * s->real; + *(here->JFETgateSourcePrimePtr +1) -= xgs * s->imag; + *(here->JFETsourceSourcePrimePtr ) -= gspr; + *(here->JFETdrainPrimeDrainPtr ) -= gdpr; + *(here->JFETdrainPrimeGatePtr ) += (-ggd+gm); + *(here->JFETdrainPrimeGatePtr ) -= xgd * s->real; + *(here->JFETdrainPrimeGatePtr +1) -= xgd * s->imag; + *(here->JFETdrainPrimeSourcePrimePtr ) += (-gds-gm); + *(here->JFETsourcePrimeGatePtr ) += (-ggs-gm); + *(here->JFETsourcePrimeGatePtr ) -= xgs * s->real; + *(here->JFETsourcePrimeGatePtr +1) -= xgs * s->imag; + *(here->JFETsourcePrimeSourcePtr ) -= gspr; + *(here->JFETsourcePrimeDrainPrimePtr ) -= gds; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet/jfetset.c b/src/spicelib/devices/jfet/jfetset.c new file mode 100644 index 000000000..5902604fe --- /dev/null +++ b/src/spicelib/devices/jfet/jfetset.c @@ -0,0 +1,183 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Sydney University mods Copyright(c) 1989 Anthony E. Parker, David J. Skellern + Laboratory for Communication Science Engineering + Sydney University Department of Electrical Engineering, Australia +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "jfetdefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +JFETsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the diode structure with those pointers needed later + * for fast matrix loading + */ +{ + register JFETmodel *model = (JFETmodel*)inModel; + register JFETinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->JFETnextModel ) { + + if( (model->JFETtype != NJF) && (model->JFETtype != PJF) ) { + model->JFETtype = NJF; + } + if(!model->JFETthresholdGiven) { + model->JFETthreshold = -2; + } + if(!model->JFETbetaGiven) { + model->JFETbeta = 1e-4; + } + if(!model->JFETlModulationGiven) { + model->JFETlModulation = 0; + } + if(!model->JFETdrainResistGiven) { + model->JFETdrainResist = 0; + } + if(!model->JFETsourceResistGiven) { + model->JFETsourceResist = 0; + } + if(!model->JFETcapGSGiven) { + model->JFETcapGS = 0; + } + if(!model->JFETcapGDGiven) { + model->JFETcapGD = 0; + } + if(!model->JFETgatePotentialGiven) { + model->JFETgatePotential = 1; + } + if(!model->JFETgateSatCurrentGiven) { + model->JFETgateSatCurrent = 1e-14; + } + if(!model->JFETdepletionCapCoeffGiven) { + model->JFETdepletionCapCoeff = .5; + } + if(!model->JFETfNcoefGiven) { + model->JFETfNcoef = 0; + } + if(!model->JFETfNexpGiven) { + model->JFETfNexp = 1; + } + + /* Modification for Sydney University JFET model */ + if(!model->JFETbGiven) { + model->JFETb = 1.0; + } + /* end Sydney University mod */ + + if(model->JFETdrainResist != 0) { + model->JFETdrainConduct = 1/model->JFETdrainResist; + } else { + model->JFETdrainConduct = 0; + } + if(model->JFETsourceResist != 0) { + model->JFETsourceConduct = 1/model->JFETsourceResist; + } else { + model->JFETsourceConduct = 0; + } + + /* loop through all the instances of the model */ + for (here = model->JFETinstances; here != NULL ; + here=here->JFETnextInstance) { + if (here->JFETowner != ARCHme) goto matrixpointers; + + if(!here->JFETareaGiven) { + here->JFETarea = 1; + } + here->JFETstate = *states; + *states += 13; + +matrixpointers: + if(model->JFETsourceResist != 0 && here->JFETsourcePrimeNode==0) { + error = CKTmkVolt(ckt,&tmp,here->JFETname,"source"); + if(error) return(error); + here->JFETsourcePrimeNode = tmp->number; + } else { + here->JFETsourcePrimeNode = here->JFETsourceNode; + } + if(model->JFETdrainResist != 0 && here->JFETdrainPrimeNode==0) { + error = CKTmkVolt(ckt,&tmp,here->JFETname,"drain"); + if(error) return(error); + here->JFETdrainPrimeNode = tmp->number; + } else { + here->JFETdrainPrimeNode = here->JFETdrainNode; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(JFETdrainDrainPrimePtr,JFETdrainNode,JFETdrainPrimeNode) + TSTALLOC(JFETgateDrainPrimePtr,JFETgateNode,JFETdrainPrimeNode) + TSTALLOC(JFETgateSourcePrimePtr,JFETgateNode,JFETsourcePrimeNode) + TSTALLOC(JFETsourceSourcePrimePtr,JFETsourceNode, + JFETsourcePrimeNode) + TSTALLOC(JFETdrainPrimeDrainPtr,JFETdrainPrimeNode,JFETdrainNode) + TSTALLOC(JFETdrainPrimeGatePtr,JFETdrainPrimeNode,JFETgateNode) + TSTALLOC(JFETdrainPrimeSourcePrimePtr,JFETdrainPrimeNode, + JFETsourcePrimeNode) + TSTALLOC(JFETsourcePrimeGatePtr,JFETsourcePrimeNode,JFETgateNode) + TSTALLOC(JFETsourcePrimeSourcePtr,JFETsourcePrimeNode, + JFETsourceNode) + TSTALLOC(JFETsourcePrimeDrainPrimePtr,JFETsourcePrimeNode, + JFETdrainPrimeNode) + TSTALLOC(JFETdrainDrainPtr,JFETdrainNode,JFETdrainNode) + TSTALLOC(JFETgateGatePtr,JFETgateNode,JFETgateNode) + TSTALLOC(JFETsourceSourcePtr,JFETsourceNode,JFETsourceNode) + TSTALLOC(JFETdrainPrimeDrainPrimePtr,JFETdrainPrimeNode, + JFETdrainPrimeNode) + TSTALLOC(JFETsourcePrimeSourcePrimePtr,JFETsourcePrimeNode, + JFETsourcePrimeNode) + } + } + return(OK); +} + +int +JFETunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + JFETmodel *model; + JFETinstance *here; + + for (model = (JFETmodel *)inModel; model != NULL; + model = model->JFETnextModel) + { + for (here = model->JFETinstances; here != NULL; + here=here->JFETnextInstance) + { + if (here->JFETsourcePrimeNode + && here->JFETsourcePrimeNode != here->JFETsourceNode) + { + CKTdltNNum(ckt, here->JFETsourcePrimeNode); + here->JFETsourcePrimeNode = 0; + } + if (here->JFETdrainPrimeNode + && here->JFETdrainPrimeNode != here->JFETdrainNode) + { + CKTdltNNum(ckt, here->JFETdrainPrimeNode); + here->JFETdrainPrimeNode = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/jfet/jfettemp.c b/src/spicelib/devices/jfet/jfettemp.c new file mode 100644 index 000000000..0fa92c6ad --- /dev/null +++ b/src/spicelib/devices/jfet/jfettemp.c @@ -0,0 +1,115 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Sydney University mods Copyright(c) 1989 Anthony E. Parker, David J. Skellern + Laboratory for Communication Science Engineering + Sydney University Department of Electrical Engineering, Australia +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "jfetdefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +JFETtemp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* Pre-process the model parameters after a possible change + */ +{ + register JFETmodel *model = (JFETmodel*)inModel; + register JFETinstance *here; + double xfc; + double vt; + double vtnom; + double kt,kt1; + double arg,arg1; + double fact1,fact2; + double egfet,egfet1; + double pbfact,pbfact1; + double gmanew,gmaold; + double ratio1; + double pbo; + double cjfact,cjfact1; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->JFETnextModel ) { + + if(!(model->JFETtnomGiven)) { + model->JFETtnom = ckt->CKTnomTemp; + } + vtnom = CONSTKoverQ * model->JFETtnom; + fact1 = model->JFETtnom/REFTEMP; + kt1 = CONSTboltz * model->JFETtnom; + egfet1 = 1.16-(7.02e-4*model->JFETtnom*model->JFETtnom)/ + (model->JFETtnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom * (1.5*log(fact1)+CHARGE*arg1); + pbo = (model->JFETgatePotential-pbfact1)/fact1; + gmaold = (model->JFETgatePotential-pbo)/pbo; + cjfact = 1/(1+.5*(4e-4*(model->JFETtnom-REFTEMP)-gmaold)); + + if(model->JFETdrainResist != 0) { + model->JFETdrainConduct = 1/model->JFETdrainResist; + } else { + model->JFETdrainConduct = 0; + } + if(model->JFETsourceResist != 0) { + model->JFETsourceConduct = 1/model->JFETsourceResist; + } else { + model->JFETsourceConduct = 0; + } + if(model->JFETdepletionCapCoeff >.95) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: Depletion cap. coefficient too large, limited to .95", + &(model->JFETmodName)); + model->JFETdepletionCapCoeff = .95; + } + + xfc = log(1 - model->JFETdepletionCapCoeff); + model->JFETf2 = exp((1+.5)*xfc); + model->JFETf3 = 1 - model->JFETdepletionCapCoeff * (1 + .5); + /* Modification for Sydney University JFET model */ + model->JFETbFac = (1 - model->JFETb) + / (model->JFETgatePotential - model->JFETthreshold); + /* end Sydney University mod */ + + /* loop through all the instances of the model */ + for (here = model->JFETinstances; here != NULL ; + here=here->JFETnextInstance) { + if (here->JFETowner != ARCHme) continue; + + if(!(here->JFETtempGiven)) { + here->JFETtemp = ckt->CKTtemp; + } + vt = here->JFETtemp * CONSTKoverQ; + fact2 = here->JFETtemp/REFTEMP; + ratio1 = here->JFETtemp/model->JFETtnom -1; + here->JFETtSatCur = model->JFETgateSatCurrent * exp(ratio1*1.11/vt); + here->JFETtCGS = model->JFETcapGS * cjfact; + here->JFETtCGD = model->JFETcapGD * cjfact; + kt = CONSTboltz*here->JFETtemp; + egfet = 1.16-(7.02e-4*here->JFETtemp*here->JFETtemp)/ + (here->JFETtemp+1108); + arg = -egfet/(kt+kt) + 1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2 * vt * (1.5*log(fact2)+CHARGE*arg); + here->JFETtGatePot = fact2 * pbo + pbfact; + gmanew = (here->JFETtGatePot-pbo)/pbo; + cjfact1 = 1+.5*(4e-4*(here->JFETtemp-REFTEMP)-gmanew); + here->JFETtCGS *= cjfact1; + here->JFETtCGD *= cjfact1; + + here->JFETcorDepCap = model->JFETdepletionCapCoeff * + here->JFETtGatePot; + here->JFETf1 = here->JFETtGatePot * (1 - exp((1-.5)*xfc))/(1-.5); + here->JFETvcrit = vt * log(vt/(CONSTroot2 * here->JFETtSatCur)); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet/jfettrun.c b/src/spicelib/devices/jfet/jfettrun.c new file mode 100644 index 000000000..8af535469 --- /dev/null +++ b/src/spicelib/devices/jfet/jfettrun.c @@ -0,0 +1,34 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfetdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFETtrunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register JFETmodel *model = (JFETmodel*)inModel; + register JFETinstance *here; + + for( ; model != NULL; model = model->JFETnextModel) { + for(here=model->JFETinstances;here!=NULL;here = here->JFETnextInstance){ + if (here->JFETowner != ARCHme) continue; + + CKTterr(here->JFETqgs,ckt,timeStep); + CKTterr(here->JFETqgd,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/ChangeLog b/src/spicelib/devices/jfet2/ChangeLog new file mode 100644 index 000000000..9460de740 --- /dev/null +++ b/src/spicelib/devices/jfet2/ChangeLog @@ -0,0 +1,19 @@ +2000-03-11 Paolo Nenzi + + * jfet2acld.c: prepared the code for multiprocessing and CIDER integration. + + * jfet2ic.c: prepared the code for multiprocessing and CIDER integration. + + * jfet2set.c: prepared the code for multiprocessing and CIDER integration. + + * jfet2load.c: prepared the code for multiprocessing and CIDER integration. + + * jfet2noi.c: prepared the code for multiprocessing and CIDER integration. + + * jfet2trun.c: prepared the code for multiprocessing and CIDER integration. + +1999-09-07 Arno + + * jfet2load.c: removed unused variables. + + * jfet2noi.c: removed unused variable. Reformatted some comments. diff --git a/src/spicelib/devices/jfet2/Makefile.am b/src/spicelib/devices/jfet2/Makefile.am new file mode 100644 index 000000000..03b175bbc --- /dev/null +++ b/src/spicelib/devices/jfet2/Makefile.am @@ -0,0 +1,32 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libjfet2.la + +libjfet2_la_SOURCES = \ + jfet2.c \ + jfet2acld.c \ + jfet2ask.c \ + jfet2defs.h \ + jfet2del.c \ + jfet2dest.c \ + jfet2ext.h \ + jfet2ic.c \ + jfet2itf.h \ + jfet2load.c \ + jfet2mask.c \ + jfet2mdel.c \ + jfet2mpar.c \ + jfet2noi.c \ + jfet2par.c \ + jfet2parm.h \ + jfet2set.c \ + jfet2temp.c \ + jfet2trun.c \ + psmodel.c \ + psmodel.h + + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/jfet2/jfet2.c b/src/spicelib/devices/jfet2/jfet2.c new file mode 100644 index 000000000..a5087340a --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2.c @@ -0,0 +1,76 @@ +/********** +Based on jfet.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: Parameter definitions called from jfetparm.h + Extra state vectors added to JFET2pTable +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "jfet2defs.h" +#include "suffix.h" + +IFparm JFET2pTable[] = { /* device parameters */ + IOPU("off", JFET2_OFF, IF_FLAG, "Device initially off"), + IOPAU("ic", JFET2_IC, IF_REALVEC,"Initial VDS,VGS vector"), + IOPU("area", JFET2_AREA, IF_REAL, "Area factor"), + IOPAU("ic-vds", JFET2_IC_VDS, IF_REAL, "Initial D-S voltage"), + IOPAU("ic-vgs", JFET2_IC_VGS, IF_REAL, "Initial G-S volrage"), + IOPU("temp", JFET2_TEMP, IF_REAL, "Instance temperature"), + OPU("drain-node", JFET2_DRAINNODE, IF_INTEGER,"Number of drain node"), + OPU("gate-node", JFET2_GATENODE, IF_INTEGER,"Number of gate node"), + OPU("source-node", JFET2_SOURCENODE, IF_INTEGER,"Number of source node"), + OPU("drain-prime-node", JFET2_DRAINPRIMENODE, IF_INTEGER,"Internal drain node"), + OPU("source-prime-node",JFET2_SOURCEPRIMENODE,IF_INTEGER,"Internal source node"), + OP("vgs", JFET2_VGS, IF_REAL, "Voltage G-S"), + OP("vgd", JFET2_VGD, IF_REAL, "Voltage G-D"), + OP("ig", JFET2_CG, IF_REAL, "Current at gate node"), + OP("id", JFET2_CD, IF_REAL, "Current at drain node"), + OP("is", JFET2_CS, IF_REAL, "Source current"), + OP("igd", JFET2_CGD, IF_REAL, "Current G-D"), + OP("gm", JFET2_GM, IF_REAL, "Transconductance"), + OP("gds", JFET2_GDS, IF_REAL, "Conductance D-S"), + OP("ggs", JFET2_GGS, IF_REAL, "Conductance G-S"), + OP("ggd", JFET2_GGD, IF_REAL, "Conductance G-D"), + OPU("qgs", JFET2_QGS, IF_REAL, "Charge storage G-S junction"), + OPU("qgd", JFET2_QGD, IF_REAL, "Charge storage G-D junction"), + OPU("cqgs", JFET2_CQGS, IF_REAL, "Capacitance due to charge storage G-S junction"), + OPU("cqgd", JFET2_CQGD, IF_REAL, "Capacitance due to charge storage G-D junction"), + OPU("p", JFET2_POWER,IF_REAL, "Power dissipated by the JFET2"), + OPU("vtrap",JFET2_VTRAP,IF_REAL, "Quiescent drain feedback potential"), + OPU("vpave",JFET2_PAVE, IF_REAL, "Quiescent power dissipation"), +}; + +IFparm JFET2mPTable[] = { /* model parameters */ + OP("type", JFET2_MOD_TYPE, IF_STRING, "N-type or P-type JFET2 model"), + IOP("njf", JFET2_MOD_NJF, IF_FLAG,"N type JFET2 model"), + IOP("pjf", JFET2_MOD_PJF, IF_FLAG,"P type JFET2 model"), + IOPR("vt0", JFET2_MOD_VTO, IF_REAL,"Threshold voltage"), + IOPR("vbi", JFET2_MOD_PB, IF_REAL,"Gate junction potential"), +#define PARAM(code,id,flag,ref,default,descrip) IOP(code,id,IF_REAL,descrip), +#define PARAMA(code,id,flag,ref,default,descrip) IOPA(code,id,IF_REAL,descrip), +#include "jfet2parm.h" + + OPU("gd", JFET2_MOD_DRAINCONDUCT, IF_REAL,"Drain conductance"), + OPU("gs", JFET2_MOD_SOURCECONDUCT,IF_REAL,"Source conductance"), + IOPU("tnom", JFET2_MOD_TNOM, IF_REAL,"parameter measurement temperature"), +}; + + +char *JFET2names[] = { + "Drain", + "Gate", + "Source" +}; + +int JFET2nSize = NUMELEMS(JFET2names); +int JFET2pTSize = NUMELEMS(JFET2pTable); +int JFET2mPTSize = NUMELEMS(JFET2mPTable); +int JFET2iSize = sizeof(JFET2instance); +int JFET2mSize = sizeof(JFET2model); diff --git a/src/spicelib/devices/jfet2/jfet2acld.c b/src/spicelib/devices/jfet2/jfet2acld.c new file mode 100644 index 000000000..c2d441419 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2acld.c @@ -0,0 +1,90 @@ +/********** +Based on jfetacld.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: New call to PSacload() with matrix loading +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfet2defs.h" +#include "sperror.h" +#include "psmodel.h" +#include "suffix.h" + +int +JFET2acLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register JFET2model *model = (JFET2model*)inModel; + register JFET2instance *here; + double gdpr; + double gspr; + double gm; + double gds; + double ggs; + double xgs; + double ggd; + double xgd; + double xgm, xgds, vgd, vgs, cd; + + for( ; model != NULL; model = model->JFET2nextModel ) { + + for( here = model->JFET2instances; here != NULL; + here = here->JFET2nextInstance) { + if (here->JFET2owner != ARCHme) continue; + + gdpr=model->JFET2drainConduct * here->JFET2area; + gspr=model->JFET2sourceConduct * here->JFET2area; + gm= *(ckt->CKTstate0 + here->JFET2gm) ; + gds= *(ckt->CKTstate0 + here->JFET2gds) ; + ggs= *(ckt->CKTstate0 + here->JFET2ggs) ; + xgs= *(ckt->CKTstate0 + here->JFET2qgs) * ckt->CKTomega ; + ggd= *(ckt->CKTstate0 + here->JFET2ggd) ; + xgd= *(ckt->CKTstate0 + here->JFET2qgd) * ckt->CKTomega ; + + vgs = *(ckt->CKTstate0 + here->JFET2vgs); + vgd = *(ckt->CKTstate0 + here->JFET2vgd); + cd = *(ckt->CKTstate0 + here->JFET2cd); + PSacload(ckt,model, here, vgs, vgd, cd, ckt->CKTomega, + &gm, &xgm, &gds, &xgds); + xgds += *(ckt->CKTstate0 + here->JFET2qds) * ckt->CKTomega ; + *(here->JFET2drainPrimeDrainPrimePtr +1) += xgds; + *(here->JFET2sourcePrimeSourcePrimePtr +1) += xgds+xgm; + *(here->JFET2drainPrimeGatePtr +1) += xgm; + *(here->JFET2drainPrimeSourcePrimePtr +1) -= xgds+xgm; + *(here->JFET2sourcePrimeGatePtr +1) -= xgm; + *(here->JFET2sourcePrimeDrainPrimePtr +1) -= xgds; + + *(here->JFET2drainDrainPtr ) += gdpr; + *(here->JFET2gateGatePtr ) += ggd+ggs; + *(here->JFET2gateGatePtr +1) += xgd+xgs; + *(here->JFET2sourceSourcePtr ) += gspr; + *(here->JFET2drainPrimeDrainPrimePtr ) += gdpr+gds+ggd; + *(here->JFET2drainPrimeDrainPrimePtr +1) += xgd; + *(here->JFET2sourcePrimeSourcePrimePtr ) += gspr+gds+gm+ggs; + *(here->JFET2sourcePrimeSourcePrimePtr +1) += xgs; + *(here->JFET2drainDrainPrimePtr ) -= gdpr; + *(here->JFET2gateDrainPrimePtr ) -= ggd; + *(here->JFET2gateDrainPrimePtr +1) -= xgd; + *(here->JFET2gateSourcePrimePtr ) -= ggs; + *(here->JFET2gateSourcePrimePtr +1) -= xgs; + *(here->JFET2sourceSourcePrimePtr ) -= gspr; + *(here->JFET2drainPrimeDrainPtr ) -= gdpr; + *(here->JFET2drainPrimeGatePtr ) += (-ggd+gm); + *(here->JFET2drainPrimeGatePtr +1) -= xgd; + *(here->JFET2drainPrimeSourcePrimePtr ) += (-gds-gm); + *(here->JFET2sourcePrimeGatePtr ) += (-ggs-gm); + *(here->JFET2sourcePrimeGatePtr +1) -= xgs; + *(here->JFET2sourcePrimeSourcePtr ) -= gspr; + *(here->JFET2sourcePrimeDrainPrimePtr ) -= gds; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/jfet2ask.c b/src/spicelib/devices/jfet2/jfet2ask.c new file mode 100644 index 000000000..c472ecc85 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2ask.c @@ -0,0 +1,141 @@ +/********** +Based on jfetask.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: JFET2vtrap and JFET2pave added +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +JFET2ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + JFET2instance *here = (JFET2instance*)inst; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case JFET2_TEMP: + value->rValue = here->JFET2temp-CONSTCtoK; + return(OK); + case JFET2_AREA: + value->rValue = here->JFET2area; + return(OK); + case JFET2_IC_VDS: + value->rValue = here->JFET2icVDS; + return(OK); + case JFET2_IC_VGS: + value->rValue = here->JFET2icVGS; + return(OK); + case JFET2_OFF: + value->iValue = here->JFET2off; + return(OK); + case JFET2_DRAINNODE: + value->iValue = here->JFET2drainNode; + return(OK); + case JFET2_GATENODE: + value->iValue = here->JFET2gateNode; + return(OK); + case JFET2_SOURCENODE: + value->iValue = here->JFET2sourceNode; + return(OK); + case JFET2_DRAINPRIMENODE: + value->iValue = here->JFET2drainPrimeNode; + return(OK); + case JFET2_SOURCEPRIMENODE: + value->iValue = here->JFET2sourcePrimeNode; + return(OK); + case JFET2_VGS: + value->rValue = *(ckt->CKTstate0 + here->JFET2vgs); + return(OK); + case JFET2_VGD: + value->rValue = *(ckt->CKTstate0 + here->JFET2vgd); + return(OK); + case JFET2_CG: + value->rValue = *(ckt->CKTstate0 + here->JFET2cg); + return(OK); + case JFET2_CD: + value->rValue = *(ckt->CKTstate0 + here->JFET2cd); + return(OK); + case JFET2_CGD: + value->rValue = *(ckt->CKTstate0 + here->JFET2cgd); + return(OK); + case JFET2_GM: + value->rValue = *(ckt->CKTstate0 + here->JFET2gm); + return(OK); + case JFET2_GDS: + value->rValue = *(ckt->CKTstate0 + here->JFET2gds); + return(OK); + case JFET2_GGS: + value->rValue = *(ckt->CKTstate0 + here->JFET2ggs); + return(OK); + case JFET2_GGD: + value->rValue = *(ckt->CKTstate0 + here->JFET2ggd); + return(OK); + case JFET2_QGS: + value->rValue = *(ckt->CKTstate0 + here->JFET2qgs); + return(OK); + case JFET2_CQGS: + value->rValue = *(ckt->CKTstate0 + here->JFET2cqgs); + return(OK); + case JFET2_QGD: + value->rValue = *(ckt->CKTstate0 + here->JFET2qgd); + return(OK); + case JFET2_CQGD: + value->rValue = *(ckt->CKTstate0 + here->JFET2cqgd); + return(OK); + case JFET2_VTRAP: + value->rValue = *(ckt->CKTstate0 + here->JFET2vtrap); + return(OK); + case JFET2_PAVE: + value->rValue = *(ckt->CKTstate0 + here->JFET2pave); + return(OK); + case JFET2_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "JFET2ask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -*(ckt->CKTstate0 + here->JFET2cd); + value->rValue -= *(ckt->CKTstate0 + here->JFET2cg); + } + return(OK); + case JFET2_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "JFET2ask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTstate0 + here->JFET2cd) * + *(ckt->CKTrhsOld + here->JFET2drainNode); + value->rValue += *(ckt->CKTstate0 + here->JFET2cg) * + *(ckt->CKTrhsOld + here->JFET2gateNode); + value->rValue -= (*(ckt->CKTstate0 + here->JFET2cd) + + *(ckt->CKTstate0 + here->JFET2cg)) * + *(ckt->CKTrhsOld + here->JFET2sourceNode); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/jfet2/jfet2defs.h b/src/spicelib/devices/jfet2/jfet2defs.h new file mode 100644 index 000000000..4469a35ae --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2defs.h @@ -0,0 +1,254 @@ +/********** +Based on jfetdefs.h +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: Added xiwoo, d3 and alpha to JFET2instance + JFET2pave, JFET2vtrap ad JFET2_STATE_COUNT + Changed model to call jfetparm.h, added JFET2za to model struct + Defined JFET2_VTRAP and JFET2_PAVE +**********/ + +#ifndef JFET2 +#define JFET2 + +#include "ifsim.h" +#include "gendefs.h" +#include "cktdefs.h" +#include "complex.h" +#include "noisedef.h" + + /* structures used to describe Junction Field Effect Transistors */ + + +/* information used to describe a single instance */ + +typedef struct sJFET2instance { + struct sJFET2model *JFET2modPtr; /* backpointer to model */ + struct sJFET2instance *JFET2nextInstance; /* pointer to next instance of + * current model*/ + IFuid JFET2name; /* pointer to character string naming this instance */ + int JFET2owner; /* number of owner process */ + int JFET2state; /* pointer to start of state vector for jfet */ + int JFET2drainNode; /* number of drain node of jfet */ + int JFET2gateNode; /* number of gate node of jfet */ + int JFET2sourceNode; /* number of source node of jfet */ + int JFET2drainPrimeNode; /* number of internal drain node of jfet */ + int JFET2sourcePrimeNode; /* number of internal source node of jfet */ + + double *JFET2drainDrainPrimePtr; /* pointer to sparse matrix at + * (drain,drain prime) */ + double *JFET2gateDrainPrimePtr; /* pointer to sparse matrix at + * (gate,drain prime) */ + double *JFET2gateSourcePrimePtr; /* pointer to sparse matrix at + * (gate,source prime) */ + double *JFET2sourceSourcePrimePtr; /* pointer to sparse matrix at + * (source,source prime) */ + double *JFET2drainPrimeDrainPtr; /* pointer to sparse matrix at + * (drain prime,drain) */ + double *JFET2drainPrimeGatePtr; /* pointer to sparse matrix at + * (drain prime,gate) */ + double *JFET2drainPrimeSourcePrimePtr; /* pointer to sparse matrix + * (drain prime,source prime) */ + double *JFET2sourcePrimeGatePtr; /* pointer to sparse matrix at + * (source prime,gate) */ + double *JFET2sourcePrimeSourcePtr; /* pointer to sparse matrix at + * (source prime,source) */ + double *JFET2sourcePrimeDrainPrimePtr; /* pointer to sparse matrix + * (source prime,drain prime) */ + double *JFET2drainDrainPtr; /* pointer to sparse matrix at + * (drain,drain) */ + double *JFET2gateGatePtr; /* pointer to sparse matrix at + * (gate,gate) */ + double *JFET2sourceSourcePtr; /* pointer to sparse matrix at + * (source,source) */ + double *JFET2drainPrimeDrainPrimePtr; /* pointer to sparse matrix + * (drain prime,drain prime) */ + double *JFET2sourcePrimeSourcePrimePtr; /* pointer to sparse matrix + * (source prime,source prime) */ + + int JFET2mode; + /* distortion analysis Taylor coeffs. */ + +/* + * naming convention: + * x = vgs + * y = vds + * cdr = cdrain + */ + +#define JFET2NDCOEFFS 21 + +#ifndef NODISTO + double JFET2dCoeffs[JFET2NDCOEFFS]; +#else /* NODISTO */ + double *JFET2dCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define cdr_x JFET2dCoeffs[0] +#define cdr_y JFET2dCoeffs[1] +#define cdr_x2 JFET2dCoeffs[2] +#define cdr_y2 JFET2dCoeffs[3] +#define cdr_xy JFET2dCoeffs[4] +#define cdr_x3 JFET2dCoeffs[5] +#define cdr_y3 JFET2dCoeffs[6] +#define cdr_x2y JFET2dCoeffs[7] +#define cdr_xy2 JFET2dCoeffs[8] + +#define ggs1 JFET2dCoeffs[9] +#define ggd1 JFET2dCoeffs[10] +#define ggs2 JFET2dCoeffs[11] +#define ggd2 JFET2dCoeffs[12] +#define ggs3 JFET2dCoeffs[13] +#define ggd3 JFET2dCoeffs[14] +#define capgs1 JFET2dCoeffs[15] +#define capgd1 JFET2dCoeffs[16] +#define capgs2 JFET2dCoeffs[17] +#define capgd2 JFET2dCoeffs[18] +#define capgs3 JFET2dCoeffs[19] +#define capgd3 JFET2dCoeffs[20] + +#endif + +/* indices to an array of JFET2 noise sources */ + +#define JFET2RDNOIZ 0 +#define JFET2RSNOIZ 1 +#define JFET2IDNOIZ 2 +#define JFET2FLNOIZ 3 +#define JFET2TOTNOIZ 4 + +#define JFET2NSRCS 5 + +#ifndef NONOISE + double JFET2nVar[NSTATVARS][JFET2NSRCS]; +#else /* NONOISE */ + double **JFET2nVar; +#endif /* NONOISE */ + + unsigned JFET2off :1; /* 'off' flag for jfet */ + unsigned JFET2areaGiven : 1; /* flag to indicate area was specified */ + unsigned JFET2icVDSGiven : 1; /* initial condition given flag for V D-S*/ + unsigned JFET2icVGSGiven : 1; /* initial condition given flag for V G-S*/ + unsigned JFET2tempGiven : 1; /* flag to indicate instance temp given */ + + + double JFET2area; /* area factor for the jfet */ + double JFET2icVDS; /* initial condition voltage D-S*/ + double JFET2icVGS; /* initial condition voltage G-S*/ + double JFET2temp; /* operating temperature */ + double JFET2tSatCur; /* temperature adjusted saturation current */ + double JFET2tGatePot; /* temperature adjusted gate potential */ + double JFET2tCGS; /* temperature corrected G-S capacitance */ + double JFET2tCGD; /* temperature corrected G-D capacitance */ + double JFET2corDepCap; /* joining point of the fwd bias dep. cap eq.s */ + double JFET2vcrit; /* critical voltage for the instance */ + double JFET2f1; /* coefficient of capacitance polynomial exp */ + double JFET2xiwoo; /* velocity saturation potential */ + double JFET2d3; /* Dual Power-law parameter */ + double JFET2alpha; /* capacitance model transition parameter */ + +} JFET2instance ; + +#define JFET2vgs JFET2state +#define JFET2vgd JFET2state+1 +#define JFET2cg JFET2state+2 +#define JFET2cd JFET2state+3 +#define JFET2cgd JFET2state+4 +#define JFET2gm JFET2state+5 +#define JFET2gds JFET2state+6 +#define JFET2ggs JFET2state+7 +#define JFET2ggd JFET2state+8 +#define JFET2qgs JFET2state+9 +#define JFET2cqgs JFET2state+10 +#define JFET2qgd JFET2state+11 +#define JFET2cqgd JFET2state+12 +#define JFET2qds JFET2state+13 +#define JFET2cqds JFET2state+14 +#define JFET2pave JFET2state+15 +#define JFET2vtrap JFET2state+16 +#define JFET2vgstrap JFET2state+17 +#define JFET2_STATE_COUNT 18 + +/* per model data */ + +typedef struct sJFET2model { /* model structure for a jfet */ + int JFET2modType; /* type index of this device type */ + struct sJFET2model *JFET2nextModel; /* pointer to next possible model in + * linked list */ + JFET2instance * JFET2instances; /* pointer to list of instances + * that have this model */ + IFuid JFET2modName; /* pointer to character string naming this model */ + int JFET2type; + +#define PARAM(code,id,flag,ref,default,descrip) double ref; +#include "jfet2parm.h" + + double JFET2drainConduct; + double JFET2sourceConduct; + double JFET2f2; + double JFET2f3; + double JFET2za; /* saturation index parameter */ + double JFET2tnom; /* temperature at which parameters were measured */ + +#define PARAM(code,id,flag,ref,default,descrip) unsigned flag : 1; +#include "jfet2parm.h" + unsigned JFET2tnomGiven : 1; /* user specified Tnom for model */ + +} JFET2model; + +#ifndef NJF + +#define NJF 1 +#define PJF -1 + +#endif /*NJF*/ + +/* device parameters */ +#define JFET2_AREA 1 +#define JFET2_IC_VDS 2 +#define JFET2_IC_VGS 3 +#define JFET2_IC 4 +#define JFET2_OFF 5 +#define JFET2_TEMP 6 + +/* device questions */ +#define JFET2_DRAINNODE 301 +#define JFET2_GATENODE 302 +#define JFET2_SOURCENODE 303 +#define JFET2_DRAINPRIMENODE 304 +#define JFET2_SOURCEPRIMENODE 305 +#define JFET2_VGS 306 +#define JFET2_VGD 307 +#define JFET2_CG 308 +#define JFET2_CD 309 +#define JFET2_CGD 310 +#define JFET2_GM 311 +#define JFET2_GDS 312 +#define JFET2_GGS 313 +#define JFET2_GGD 314 +#define JFET2_QGS 315 +#define JFET2_CQGS 316 +#define JFET2_QGD 317 +#define JFET2_CQGD 318 +#define JFET2_CS 319 +#define JFET2_POWER 320 +#define JFET2_VTRAP 321 +#define JFET2_PAVE 322 + +/* model questions */ +#define JFET2_MOD_DRAINCONDUCT 301 +#define JFET2_MOD_SOURCECONDUCT 302 +#define JFET2_MOD_DEPLETIONCAP 303 +#define JFET2_MOD_VCRIT 304 +#define JFET2_MOD_TYPE 305 + +/* function definitions */ + +#include "jfet2ext.h" + +#endif /*JFET2*/ diff --git a/src/spicelib/devices/jfet2/jfet2del.c b/src/spicelib/devices/jfet2/jfet2del.c new file mode 100644 index 000000000..41606e4b2 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2del.c @@ -0,0 +1,40 @@ +/********** +Based on jfetdel.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to jfet2 for PS model definition ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ + +#include "ngspice.h" +#include +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFET2delete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + JFET2model *model = (JFET2model*)inModel; + JFET2instance **fast = (JFET2instance**)inst; + JFET2instance **prev = NULL; + JFET2instance *here; + + for( ; model ; model = model->JFET2nextModel) { + prev = &(model->JFET2instances); + for(here = *prev; here ; here = *prev) { + if(here->JFET2name == name || (fast && here==*fast) ) { + *prev= here->JFET2nextInstance; + FREE(here); + return(OK); + } + prev = &(here->JFET2nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/jfet2/jfet2dest.c b/src/spicelib/devices/jfet2/jfet2dest.c new file mode 100644 index 000000000..730448513 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2dest.c @@ -0,0 +1,40 @@ +/********** +Based on jfetdest.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to jfet2 for PS model definition ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "jfet2defs.h" +#include "suffix.h" + + +void +JFET2destroy(inModel) + GENmodel **inModel; +{ + JFET2model **model = (JFET2model**)inModel; + JFET2instance *here; + JFET2instance *prev = NULL; + JFET2model *mod = *model; + JFET2model *oldmod = NULL; + + for( ; mod ; mod = mod->JFET2nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (JFET2instance *)NULL; + for(here = mod->JFET2instances ; here ; here = here->JFET2nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/jfet2/jfet2ext.h b/src/spicelib/devices/jfet2/jfet2ext.h new file mode 100644 index 000000000..0f401100a --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2ext.h @@ -0,0 +1,43 @@ +/********** +Based on jfetext.h +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ + +#ifdef __STDC__ +extern int JFET2acLoad(GENmodel*,CKTcircuit*); +extern int JFET2ask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int JFET2delete(GENmodel*,IFuid,GENinstance**); +extern void JFET2destroy(GENmodel**); +extern int JFET2getic(GENmodel*,CKTcircuit*); +extern int JFET2load(GENmodel*,CKTcircuit*); +extern int JFET2mAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int JFET2mDelete(GENmodel**,IFuid,GENmodel*); +extern int JFET2mParam(int,IFvalue*,GENmodel*); +extern int JFET2param(int,IFvalue*,GENinstance*,IFvalue*); +extern int JFET2setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int JFET2unsetup(GENmodel*,CKTcircuit*); +extern int JFET2temp(GENmodel*,CKTcircuit*); +extern int JFET2trunc(GENmodel*,CKTcircuit*,double*); +extern int JFET2noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ +extern int JFET2acLoad(); +extern int JFET2ask(); +extern int JFET2delete(); +extern void JFET2destroy(); +extern int JFET2getic(); +extern int JFET2load(); +extern int JFET2mAsk(); +extern int JFET2mDelete(); +extern int JFET2mParam(); +extern int JFET2param(); +extern int JFET2setup(); +extern int JFET2unsetup(); +extern int JFET2temp(); +extern int JFET2trunc(); +extern int JFET2noise(); +#endif /* stdc */ diff --git a/src/spicelib/devices/jfet2/jfet2ic.c b/src/spicelib/devices/jfet2/jfet2ic.c new file mode 100644 index 000000000..7c252f174 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2ic.c @@ -0,0 +1,48 @@ +/********** +Based on jfetic.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to jfet2 for PS model definition ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFET2getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + JFET2model *model = (JFET2model*)inModel; + JFET2instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->JFET2nextModel) { + for(here = model->JFET2instances; here ; here = here->JFET2nextInstance) { + if (here->JFET2owner != ARCHme) continue; + if(!here->JFET2icVDSGiven) { + here->JFET2icVDS = + *(ckt->CKTrhs + here->JFET2drainNode) - + *(ckt->CKTrhs + here->JFET2sourceNode); + } + if(!here->JFET2icVGSGiven) { + here->JFET2icVGS = + *(ckt->CKTrhs + here->JFET2gateNode) - + *(ckt->CKTrhs + here->JFET2sourceNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/jfet2itf.h b/src/spicelib/devices/jfet2/jfet2itf.h new file mode 100644 index 000000000..cef2de662 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2itf.h @@ -0,0 +1,85 @@ +/********** +Based on jfetitf.h +Copyright 1990 Regents of the University of California. All rights reserved. + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + pz and disto not supported +**********/ +#ifdef DEV_jfet2 + +#ifndef DEV_JFET2 +#define DEV_JFET2 + +#include "jfet2ext.h" +extern IFparm JFET2pTable[ ]; +extern IFparm JFET2mPTable[ ]; +extern char *JFET2names[ ]; +extern int JFET2pTSize; +extern int JFET2mPTSize; +extern int JFET2nSize; +extern int JFET2iSize; +extern int JFET2mSize; + +SPICEdev JFET2info = { + { + "JFET2", + "Short channel field effect transistor", + + &JFET2nSize, + &JFET2nSize, + JFET2names, + + &JFET2pTSize, + JFET2pTable, + + &JFET2mPTSize, + JFET2mPTable, + DEV_DEFAULT + }, + + JFET2param, + JFET2mParam, + JFET2load, + JFET2setup, + JFET2unsetup, + JFET2setup, + JFET2temp, + JFET2trunc, + NULL, + JFET2acLoad, + NULL, + JFET2destroy, +#ifdef DELETES + JFET2mDelete, + JFET2delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + JFET2getic, + JFET2ask, + JFET2mAsk, + NULL, /* AN_pz */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* AN_disto */ +#ifdef AN_noise + JFET2noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &JFET2iSize, + &JFET2mSize + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/jfet2/jfet2load.c b/src/spicelib/devices/jfet2/jfet2load.c new file mode 100644 index 000000000..0e24f1aba --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2load.c @@ -0,0 +1,329 @@ +/********** +Based on jfetload.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: New code added to call psmodel.c routines +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfet2defs.h" +#include "const.h" +#include "trandefs.h" +#include "sperror.h" +#include "devdefs.h" +#include "psmodel.h" +#include "suffix.h" + +int +JFET2load(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register JFET2model *model = (JFET2model*)inModel; + register JFET2instance *here; + double capgd; + double capgs; + double cd; + double cdhat; + double cdreq; + double ceq; + double ceqgd; + double ceqgs; + double cg; + double cgd; + double cghat; + double delvds; + double delvgd; + double delvgs; + double gdpr; + double gds; + double geq; + double ggd; + double ggs; + double gm; + double gspr; + double vds; + double vgd; + double vgs; + double xfact; + int icheck; + int ichk1; + int error; + + /* loop through all the models */ + for( ; model != NULL; model = model->JFET2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->JFET2instances; here != NULL ; + here=here->JFET2nextInstance) { + if (here->JFET2owner != ARCHme) continue; + /* + * dc model parameters + */ + gdpr=model->JFET2drainConduct*here->JFET2area; + gspr=model->JFET2sourceConduct*here->JFET2area; + /* + * initialization + */ + icheck=1; + if( ckt->CKTmode & MODEINITSMSIG) { + vgs= *(ckt->CKTstate0 + here->JFET2vgs); + vgd= *(ckt->CKTstate0 + here->JFET2vgd); + } else if (ckt->CKTmode & MODEINITTRAN) { + vgs= *(ckt->CKTstate1 + here->JFET2vgs); + vgd= *(ckt->CKTstate1 + here->JFET2vgd); + } else if ( (ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC) ) { + vds=model->JFET2type*here->JFET2icVDS; + vgs=model->JFET2type*here->JFET2icVGS; + vgd=vgs-vds; + } else if ( (ckt->CKTmode & MODEINITJCT) && + (here->JFET2off == 0) ) { + vgs = -1; + vgd = -1; + } else if( (ckt->CKTmode & MODEINITJCT) || + ((ckt->CKTmode & MODEINITFIX) && (here->JFET2off))) { + vgs = 0; + vgd = 0; + } else { +#ifndef PREDICTOR + if(ckt->CKTmode & MODEINITPRED) { + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->JFET2vgs)= + *(ckt->CKTstate1 + here->JFET2vgs); + vgs=(1+xfact)* *(ckt->CKTstate1 + here->JFET2vgs)-xfact* + *(ckt->CKTstate2 + here->JFET2vgs); + *(ckt->CKTstate0 + here->JFET2vgd)= + *(ckt->CKTstate1 + here->JFET2vgd); + vgd=(1+xfact)* *(ckt->CKTstate1 + here->JFET2vgd)-xfact* + *(ckt->CKTstate2 + here->JFET2vgd); + *(ckt->CKTstate0 + here->JFET2cg)= + *(ckt->CKTstate1 + here->JFET2cg); + *(ckt->CKTstate0 + here->JFET2cd)= + *(ckt->CKTstate1 + here->JFET2cd); + *(ckt->CKTstate0 + here->JFET2cgd)= + *(ckt->CKTstate1 + here->JFET2cgd); + *(ckt->CKTstate0 + here->JFET2gm)= + *(ckt->CKTstate1 + here->JFET2gm); + *(ckt->CKTstate0 + here->JFET2gds)= + *(ckt->CKTstate1 + here->JFET2gds); + *(ckt->CKTstate0 + here->JFET2ggs)= + *(ckt->CKTstate1 + here->JFET2ggs); + *(ckt->CKTstate0 + here->JFET2ggd)= + *(ckt->CKTstate1 + here->JFET2ggd); + } else { +#endif /*PREDICTOR*/ + /* + * compute new nonlinear branch voltages + */ + vgs=model->JFET2type* + (*(ckt->CKTrhsOld+ here->JFET2gateNode)- + *(ckt->CKTrhsOld+ + here->JFET2sourcePrimeNode)); + vgd=model->JFET2type* + (*(ckt->CKTrhsOld+here->JFET2gateNode)- + *(ckt->CKTrhsOld+ + here->JFET2drainPrimeNode)); +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + delvgs=vgs- *(ckt->CKTstate0 + here->JFET2vgs); + delvgd=vgd- *(ckt->CKTstate0 + here->JFET2vgd); + delvds=delvgs-delvgd; + cghat= *(ckt->CKTstate0 + here->JFET2cg)+ + *(ckt->CKTstate0 + here->JFET2ggd)*delvgd+ + *(ckt->CKTstate0 + here->JFET2ggs)*delvgs; + cdhat= *(ckt->CKTstate0 + here->JFET2cd)+ + *(ckt->CKTstate0 + here->JFET2gm)*delvgs+ + *(ckt->CKTstate0 + here->JFET2gds)*delvds- + *(ckt->CKTstate0 + here->JFET2ggd)*delvgd; + /* + * bypass if solution has not changed + */ + if((ckt->CKTbypass) && + (!(ckt->CKTmode & MODEINITPRED)) && + (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs), + fabs(*(ckt->CKTstate0 + here->JFET2vgs)))+ + ckt->CKTvoltTol) ) + if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd), + fabs(*(ckt->CKTstate0 + here->JFET2vgd)))+ + ckt->CKTvoltTol)) + if ( (fabs(cghat-*(ckt->CKTstate0 + here->JFET2cg)) + < ckt->CKTreltol*MAX(fabs(cghat), + fabs(*(ckt->CKTstate0 + here->JFET2cg)))+ + ckt->CKTabstol) ) if ( /* hack - expression too big */ + (fabs(cdhat-*(ckt->CKTstate0 + here->JFET2cd)) + < ckt->CKTreltol*MAX(fabs(cdhat), + fabs(*(ckt->CKTstate0 + here->JFET2cd)))+ + ckt->CKTabstol) ) { + + /* we can do a bypass */ + vgs= *(ckt->CKTstate0 + here->JFET2vgs); + vgd= *(ckt->CKTstate0 + here->JFET2vgd); + vds= vgs-vgd; + cg= *(ckt->CKTstate0 + here->JFET2cg); + cd= *(ckt->CKTstate0 + here->JFET2cd); + cgd= *(ckt->CKTstate0 + here->JFET2cgd); + gm= *(ckt->CKTstate0 + here->JFET2gm); + gds= *(ckt->CKTstate0 + here->JFET2gds); + ggs= *(ckt->CKTstate0 + here->JFET2ggs); + ggd= *(ckt->CKTstate0 + here->JFET2ggd); + goto load; + } + /* + * limit nonlinear branch voltages + */ + ichk1=1; + vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->JFET2vgs), + (here->JFET2temp*CONSTKoverQ), here->JFET2vcrit, &icheck); + vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->JFET2vgd), + (here->JFET2temp*CONSTKoverQ), here->JFET2vcrit,&ichk1); + if (ichk1 == 1) { + icheck=1; + } + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->JFET2vgs), + model->JFET2vto); + vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->JFET2vgd), + model->JFET2vto); + } + /* + * determine dc current and derivatives + */ + vds=vgs-vgd; + if (vds < 0.0) { + cd = -PSids(ckt, model, here, vgd, vgs, + &cgd, &cg, &ggd, &ggs, &gm, &gds); + gds += gm; + gm = -gm; + } else { + cd = PSids(ckt, model, here, vgs, vgd, + &cg, &cgd, &ggs, &ggd, &gm, &gds); + } + cg = cg + cgd; + cd = cd - cgd; + + if ( (ckt->CKTmode & (MODETRAN | MODEAC | MODEINITSMSIG) ) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){ + /* + * charge storage elements + */ + double capds = model->JFET2capds*here->JFET2area; + + PScharge(ckt, model, here, vgs, vgd, &capgs, &capgd); + + *(ckt->CKTstate0 + here->JFET2qds) = capds * vds; + + /* + * store small-signal parameters + */ + if( (!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC)) ) { + if(ckt->CKTmode & MODEINITSMSIG) { + *(ckt->CKTstate0 + here->JFET2qgs) = capgs; + *(ckt->CKTstate0 + here->JFET2qgd) = capgd; + *(ckt->CKTstate0 + here->JFET2qds) = capds; + continue; /*go to 1000*/ + } + /* + * transient analysis + */ + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->JFET2qgs) = + *(ckt->CKTstate0 + here->JFET2qgs); + *(ckt->CKTstate1 + here->JFET2qgd) = + *(ckt->CKTstate0 + here->JFET2qgd); + *(ckt->CKTstate1 + here->JFET2qds) = + *(ckt->CKTstate0 + here->JFET2qds); + } + error = NIintegrate(ckt,&geq,&ceq,capgs,here->JFET2qgs); + if(error) return(error); + ggs = ggs + geq; + cg = cg + *(ckt->CKTstate0 + here->JFET2cqgs); + error = NIintegrate(ckt,&geq,&ceq,capgd,here->JFET2qgd); + if(error) return(error); + ggd = ggd + geq; + cg = cg + *(ckt->CKTstate0 + here->JFET2cqgd); + cd = cd - *(ckt->CKTstate0 + here->JFET2cqgd); + cgd = cgd + *(ckt->CKTstate0 + here->JFET2cqgd); + error = NIintegrate(ckt,&geq,&ceq,capds,here->JFET2qds); + cd = cd + *(ckt->CKTstate0 + here->JFET2cqds); + if(error) return(error); + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->JFET2cqgs) = + *(ckt->CKTstate0 + here->JFET2cqgs); + *(ckt->CKTstate1 + here->JFET2cqgd) = + *(ckt->CKTstate0 + here->JFET2cqgd); + *(ckt->CKTstate1 + here->JFET2cqds) = + *(ckt->CKTstate0 + here->JFET2cqds); + } + } + } + /* + * check convergence + */ + if( (!(ckt->CKTmode & MODEINITFIX)) | (!(ckt->CKTmode & MODEUIC))) { + if( (icheck == 1) +#ifndef NEWCONV +/* XXX */ +#endif /*NEWCONV*/ + || (fabs(cghat-cg) >= ckt->CKTreltol* + MAX(fabs(cghat),fabs(cg))+ckt->CKTabstol) || + (fabs(cdhat-cd) > ckt->CKTreltol* + MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol) + ) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } + *(ckt->CKTstate0 + here->JFET2vgs) = vgs; + *(ckt->CKTstate0 + here->JFET2vgd) = vgd; + *(ckt->CKTstate0 + here->JFET2cg) = cg; + *(ckt->CKTstate0 + here->JFET2cd) = cd; + *(ckt->CKTstate0 + here->JFET2cgd) = cgd; + *(ckt->CKTstate0 + here->JFET2gm) = gm; + *(ckt->CKTstate0 + here->JFET2gds) = gds; + *(ckt->CKTstate0 + here->JFET2ggs) = ggs; + *(ckt->CKTstate0 + here->JFET2ggd) = ggd; + /* + * load current vector + */ +load: + ceqgd=model->JFET2type*(cgd-ggd*vgd); + ceqgs=model->JFET2type*((cg-cgd)-ggs*vgs); + cdreq=model->JFET2type*((cd+cgd)-gds*vds-gm*vgs); + *(ckt->CKTrhs + here->JFET2gateNode) += (-ceqgs-ceqgd); + *(ckt->CKTrhs + here->JFET2drainPrimeNode) += + (-cdreq+ceqgd); + *(ckt->CKTrhs + here->JFET2sourcePrimeNode) += + (cdreq+ceqgs); + /* + * load y matrix + */ + *(here->JFET2drainDrainPrimePtr) += (-gdpr); + *(here->JFET2gateDrainPrimePtr) += (-ggd); + *(here->JFET2gateSourcePrimePtr) += (-ggs); + *(here->JFET2sourceSourcePrimePtr) += (-gspr); + *(here->JFET2drainPrimeDrainPtr) += (-gdpr); + *(here->JFET2drainPrimeGatePtr) += (gm-ggd); + *(here->JFET2drainPrimeSourcePrimePtr) += (-gds-gm); + *(here->JFET2sourcePrimeGatePtr) += (-ggs-gm); + *(here->JFET2sourcePrimeSourcePtr) += (-gspr); + *(here->JFET2sourcePrimeDrainPrimePtr) += (-gds); + *(here->JFET2drainDrainPtr) += (gdpr); + *(here->JFET2gateGatePtr) += (ggd+ggs); + *(here->JFET2sourceSourcePtr) += (gspr); + *(here->JFET2drainPrimeDrainPrimePtr) += (gdpr+gds+ggd); + *(here->JFET2sourcePrimeSourcePrimePtr) += (gspr+gds+gm+ggs); + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/jfet2mask.c b/src/spicelib/devices/jfet2/jfet2mask.c new file mode 100644 index 000000000..48615aae1 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2mask.c @@ -0,0 +1,59 @@ +/********** +Based on jfetmask.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: Added call to jfetparm.h +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +JFET2mAsk(ckt,inModel,which,value) + CKTcircuit *ckt; + GENmodel *inModel; + int which; + IFvalue *value; +{ + JFET2model *model = (JFET2model*)inModel; + switch(which) { + case JFET2_MOD_TNOM: + value->rValue = model->JFET2tnom-CONSTCtoK; + return(OK); + +#define PARAM(code,id,flag,ref,default,descrip) case id: \ + value->rValue = model->ref; return(OK); +#include "jfet2parm.h" + + case JFET2_MOD_DRAINCONDUCT: + value->rValue = model->JFET2drainConduct; + return(OK); + case JFET2_MOD_SOURCECONDUCT: + value->rValue = model->JFET2sourceConduct; + return(OK); + case JFET2_MOD_TYPE: + if (model->JFET2type == NJF) + value->sValue = "njf"; + else + value->sValue = "pjf"; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/jfet2/jfet2mdel.c b/src/spicelib/devices/jfet2/jfet2mdel.c new file mode 100644 index 000000000..edaf8df58 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2mdel.c @@ -0,0 +1,48 @@ +/********** +based on jfetmdel.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to jfet2 for PS model definition ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFET2mDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + JFET2model **model = (JFET2model**)inModel; + JFET2model *modfast = (JFET2model*)kill; + JFET2instance *here; + JFET2instance *prev = NULL; + JFET2model **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->JFET2nextModel)) { + if( (*model)->JFET2modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->JFET2nextModel; /* cut deleted device out of list */ + for(here = (*model)->JFET2instances ; here ; here = here->JFET2nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/jfet2/jfet2mpar.c b/src/spicelib/devices/jfet2/jfet2mpar.c new file mode 100644 index 000000000..a2a2222ed --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2mpar.c @@ -0,0 +1,49 @@ +/********** +Based on jfetmpar.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: Added call to jfetparm.h +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFET2mParam(param,value,inModels) + int param; + IFvalue *value; + GENmodel *inModels; +{ + JFET2model *model = (JFET2model*)inModels; + switch(param) { + case JFET2_MOD_TNOM: + model->JFET2tnomGiven = TRUE; + model->JFET2tnom = value->rValue+CONSTCtoK; + break; +#define PARAM(code,id,flag,ref,default,descrip) case id: \ + model->flag = TRUE; model->ref = value->rValue; break; +#include "jfet2parm.h" + case JFET2_MOD_NJF: + if(value->iValue) { + model->JFET2type = NJF; + } + break; + case JFET2_MOD_PJF: + if(value->iValue) { + model->JFET2type = PJF; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/jfet2noi.c b/src/spicelib/devices/jfet2/jfet2noi.c new file mode 100644 index 000000000..d9fe4ea0a --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2noi.c @@ -0,0 +1,223 @@ +/********** +based on jfetnoi.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng + +Modified to jfet2 for PS model definition ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ + +#include "ngspice.h" +#include +#include "jfet2defs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * JFET2noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with JFET2's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the JFET2's is summed with the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +JFET2noise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + JFET2model *firstModel = (JFET2model *) genmodel; + register JFET2model *model; + register JFET2instance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[JFET2NSRCS]; + double lnNdens[JFET2NSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *JFET2nNames[JFET2NSRCS] = { + /* Note that we have to keep the order consistent with the + strchr definitions in JFET2defs.h */ + "_rd", /* noise due to rd */ + "_rs", /* noise due to rs */ + "_id", /* noise due to id */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->JFET2nextModel) { + for (inst=model->JFET2instances; inst != NULL; inst=inst->JFET2nextInstance) { + if (inst->JFET2owner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < JFET2NSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->JFET2name,JFET2nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + + case INT_NOIZ: + for (i=0; i < JFET2NSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->JFET2name,JFET2nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->JFET2name,JFET2nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[JFET2RDNOIZ],&lnNdens[JFET2RDNOIZ], + ckt,THERMNOISE,inst->JFET2drainPrimeNode,inst->JFET2drainNode, + model->JFET2drainConduct * inst->JFET2area); + + NevalSrc(&noizDens[JFET2RSNOIZ],&lnNdens[JFET2RSNOIZ], + ckt,THERMNOISE,inst->JFET2sourcePrimeNode, + inst->JFET2sourceNode,model->JFET2sourceConduct*inst->JFET2area); + + NevalSrc(&noizDens[JFET2IDNOIZ],&lnNdens[JFET2IDNOIZ], + ckt,THERMNOISE,inst->JFET2drainPrimeNode, + inst->JFET2sourcePrimeNode, + (2.0/3.0 * fabs(*(ckt->CKTstate0 + inst->JFET2gm)))); + + NevalSrc(&noizDens[JFET2FLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->JFET2drainPrimeNode, + inst->JFET2sourcePrimeNode, (double)0.0); + noizDens[JFET2FLNOIZ] *= model->JFET2fNcoef * + exp(model->JFET2fNexp * + log(MAX(fabs(*(ckt->CKTstate0 + inst->JFET2cd)),N_MINLOG))) / + data->freq; + lnNdens[JFET2FLNOIZ] = + log(MAX(noizDens[JFET2FLNOIZ],N_MINLOG)); + + noizDens[JFET2TOTNOIZ] = noizDens[JFET2RDNOIZ] + + noizDens[JFET2RSNOIZ] + + noizDens[JFET2IDNOIZ] + + noizDens[JFET2FLNOIZ]; + lnNdens[JFET2TOTNOIZ] = + log(MAX(noizDens[JFET2TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[JFET2TOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < JFET2NSRCS; i++) { + inst->JFET2nVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < JFET2NSRCS; i++) { + inst->JFET2nVar[OUTNOIZ][i] = 0.0; + inst->JFET2nVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + for (i=0; i < JFET2NSRCS; i++) { + if (i != JFET2TOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->JFET2nVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->JFET2nVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->JFET2nVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->JFET2nVar[OUTNOIZ][i] += tempOnoise; + inst->JFET2nVar[OUTNOIZ][JFET2TOTNOIZ] += tempOnoise; + inst->JFET2nVar[INNOIZ][i] += tempInoise; + inst->JFET2nVar[INNOIZ][JFET2TOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < JFET2NSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < JFET2NSRCS; i++) { + data->outpVector[data->outNumber++] = inst->JFET2nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->JFET2nVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} + + diff --git a/src/spicelib/devices/jfet2/jfet2par.c b/src/spicelib/devices/jfet2/jfet2par.c new file mode 100644 index 000000000..4695390a2 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2par.c @@ -0,0 +1,67 @@ +/********** +based on jfetpar.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to jfet2 for PS model definition ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +JFET2param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + JFET2instance *here = (JFET2instance *)inst; + switch(param) { + case JFET2_TEMP: + here->JFET2temp = value->rValue+CONSTCtoK; + here->JFET2tempGiven = TRUE; + break; + case JFET2_AREA: + here->JFET2area = value->rValue; + here->JFET2areaGiven = TRUE; + break; + case JFET2_IC_VDS: + here->JFET2icVDS = value->rValue; + here->JFET2icVDSGiven = TRUE; + break; + case JFET2_IC_VGS: + here->JFET2icVGS = value->rValue; + here->JFET2icVGSGiven = TRUE; + break; + case JFET2_OFF: + here->JFET2off = value->iValue; + break; + case JFET2_IC: + switch(value->v.numValue) { + case 2: + here->JFET2icVGS = *(value->v.vec.rVec+1); + here->JFET2icVGSGiven = TRUE; + case 1: + here->JFET2icVDS = *(value->v.vec.rVec); + here->JFET2icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/jfet2parm.h b/src/spicelib/devices/jfet2/jfet2parm.h new file mode 100644 index 000000000..97c6b1088 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2parm.h @@ -0,0 +1,52 @@ + +#ifndef PARAMA +#define PARAMA(code,id,flag,ref,default,descrip) PARAM(code,id,flag,ref,default,descrip) +#endif +#ifndef JFET2_MOD_VTO +#define JFET2_MOD_VTO 141 +#define JFET2_MOD_NJF 102 +#define JFET2_MOD_PJF 103 +#define JFET2_MOD_TNOM 104 +#define JFET2_MOD_PB 131 +#endif + PARAM("acgam", 107, JFET2acgamGiven, JFET2acgam, 0, "") + PARAM("af", 108, JFET2fNexpGiven, JFET2fNexp, 1, "Flicker Noise Exponent") + PARAM("beta", 109, JFET2betaGiven, JFET2beta, 1e-4, "Transconductance parameter") + PARAMA("cds", 146, JFET2capDSGiven, JFET2capds, 0, "D-S junction capacitance") + PARAMA("cgd", 110, JFET2capGDGiven, JFET2capgd, 0, "G-D junction capacitance") + PARAMA("cgs", 111, JFET2capGSGiven, JFET2capgs, 0, "G-S junction capacitance") + PARAM("delta", 113, JFET2deltaGiven, JFET2delta, 0, "coef of thermal current reduction") + PARAM("hfeta", 114, JFET2hfetaGiven, JFET2hfeta, 0, "drain feedback modulation") + PARAM("hfe1", 115, JFET2hfe1Given, JFET2hfe1, 0, "") + PARAM("hfe2", 116, JFET2hfe2Given, JFET2hfe2, 0, "") + PARAM("hfg1", 117, JFET2hfg1Given, JFET2hfg1, 0, "") + PARAM("hfg2", 118, JFET2hfg2Given, JFET2hfg2, 0, "") + PARAM("mvst", 119, JFET2mvstGiven, JFET2mvst, 0, "modulation index for subtreshold current") + PARAM("mxi", 120, JFET2mxiGiven, JFET2mxi, 0, "saturation potential modulation parameter") + PARAM("fc", 121, JFET2fcGiven, JFET2fc, 0.5, "Forward bias junction fit parm.") + PARAM("ibd", 122, JFET2ibdGiven, JFET2ibd, 0, "Breakdown current of diode jnc") + PARAM("is", 123, JFET2isGiven, JFET2is, 1e-14, "Gate junction saturation current") + PARAM("kf", 124, JFET2kfGiven, JFET2fNcoef, 0, "Flicker Noise Coefficient") + PARAM("lambda",125, JFET2lamGiven, JFET2lambda, 0, "Channel length modulation param.") + PARAM("lfgam", 126, JFET2lfgamGiven, JFET2lfgam, 0, "drain feedback parameter") + PARAM("lfg1", 127, JFET2lfg1Given, JFET2lfg1, 0, "") + PARAM("lfg2", 128, JFET2lfg2Given, JFET2lfg2, 0, "") + PARAM("n", 129, JFET2nGiven, JFET2n, 1, "gate junction ideality factor") + PARAM("p", 130, JFET2pGiven, JFET2p, 2, "Power law (triode region)") + PARAM("pb", JFET2_MOD_PB, JFET2phiGiven, JFET2phi, 1, "Gate junction potential") + PARAM("q", 132, JFET2qGiven, JFET2q, 2, "Power Law (Saturated region)") + PARAM("rd", 133, JFET2rdGiven, JFET2rd, 0, "Drain ohmic resistance") + PARAM("rs", 134, JFET2rsGiven, JFET2rs, 0, "Source ohmic resistance") + PARAM("taud", 135, JFET2taudGiven, JFET2taud, 0, "Thermal relaxation time") + PARAM("taug", 136, JFET2taugGiven, JFET2taug, 0, "Drain feedback relaxation time") + PARAM("vbd", 137, JFET2vbdGiven, JFET2vbd, 1, "Breakdown potential of diode jnc") + PARAM("ver", 139, JFET2verGiven, JFET2ver, 0, "version number of PS model") + PARAM("vst", 140, JFET2vstGiven, JFET2vst, 0, "Crit Poten subthreshold conductn") + PARAM("vto", JFET2_MOD_VTO, JFET2vtoGiven, JFET2vto, -2, "Threshold voltage") + PARAM("xc", 142, JFET2xcGiven, JFET2xc, 0, "amount of cap. red at pinch-off") + PARAM("xi", 143, JFET2xiGiven, JFET2xi, 1000, "velocity saturation index") + PARAM("z", 144, JFET2zGiven, JFET2z, 1, "rate of velocity saturation") + PARAM("hfgam", 145, JFET2hfgGiven, JFET2hfgam, model->JFET2lfgam, "high freq drain feedback parm") +#undef PARAM +#undef PARAMA + diff --git a/src/spicelib/devices/jfet2/jfet2set.c b/src/spicelib/devices/jfet2/jfet2set.c new file mode 100644 index 000000000..3a93e006e --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2set.c @@ -0,0 +1,135 @@ +/********** +Based on jfetset.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: Added call to jfetparm.h, used JFET_STATE_COUNT +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "jfet2defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +JFET2setup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the diode structure with those pointers needed later + * for fast matrix loading + */ +{ + register JFET2model *model = (JFET2model*)inModel; + register JFET2instance *here; + int error; + CKTnode *tmp; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->JFET2nextModel ) { + + if( (model->JFET2type != NJF) && (model->JFET2type != PJF) ) { + model->JFET2type = NJF; + } +#define PARAM(code,id,flag,ref,default,descrip) \ + if(!model->flag) {model->ref = default;} +#include "jfet2parm.h" + + /* loop through all the instances of the model */ + for (here = model->JFET2instances; here != NULL ; + here=here->JFET2nextInstance) { + if (here->JFET2owner != ARCHme) goto matrixpointers2; + + if(!here->JFET2areaGiven) { + here->JFET2area = 1; + } + here->JFET2state = *states; + *states += JFET2_STATE_COUNT + 1; + +matrixpointers2: + if(model->JFET2rs != 0 && here->JFET2sourcePrimeNode==0) { + error = CKTmkVolt(ckt,&tmp,here->JFET2name,"source"); + if(error) return(error); + here->JFET2sourcePrimeNode = tmp->number; + } else { + here->JFET2sourcePrimeNode = here->JFET2sourceNode; + } + if(model->JFET2rd != 0 && here->JFET2drainPrimeNode==0) { + error = CKTmkVolt(ckt,&tmp,here->JFET2name,"drain"); + if(error) return(error); + here->JFET2drainPrimeNode = tmp->number; + } else { + here->JFET2drainPrimeNode = here->JFET2drainNode; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(JFET2drainDrainPrimePtr,JFET2drainNode,JFET2drainPrimeNode) + TSTALLOC(JFET2gateDrainPrimePtr,JFET2gateNode,JFET2drainPrimeNode) + TSTALLOC(JFET2gateSourcePrimePtr,JFET2gateNode,JFET2sourcePrimeNode) + TSTALLOC(JFET2sourceSourcePrimePtr,JFET2sourceNode, + JFET2sourcePrimeNode) + TSTALLOC(JFET2drainPrimeDrainPtr,JFET2drainPrimeNode,JFET2drainNode) + TSTALLOC(JFET2drainPrimeGatePtr,JFET2drainPrimeNode,JFET2gateNode) + TSTALLOC(JFET2drainPrimeSourcePrimePtr,JFET2drainPrimeNode, + JFET2sourcePrimeNode) + TSTALLOC(JFET2sourcePrimeGatePtr,JFET2sourcePrimeNode,JFET2gateNode) + TSTALLOC(JFET2sourcePrimeSourcePtr,JFET2sourcePrimeNode, + JFET2sourceNode) + TSTALLOC(JFET2sourcePrimeDrainPrimePtr,JFET2sourcePrimeNode, + JFET2drainPrimeNode) + TSTALLOC(JFET2drainDrainPtr,JFET2drainNode,JFET2drainNode) + TSTALLOC(JFET2gateGatePtr,JFET2gateNode,JFET2gateNode) + TSTALLOC(JFET2sourceSourcePtr,JFET2sourceNode,JFET2sourceNode) + TSTALLOC(JFET2drainPrimeDrainPrimePtr,JFET2drainPrimeNode, + JFET2drainPrimeNode) + TSTALLOC(JFET2sourcePrimeSourcePrimePtr,JFET2sourcePrimeNode, + JFET2sourcePrimeNode) + } + } + return(OK); +} + +int +JFET2unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + JFET2model *model; + JFET2instance *here; + + for (model = (JFET2model *)inModel; model != NULL; + model = model->JFET2nextModel) + { + for (here = model->JFET2instances; here != NULL; + here=here->JFET2nextInstance) + { + if (here->JFET2sourcePrimeNode + && here->JFET2sourcePrimeNode != here->JFET2sourceNode) + { + CKTdltNNum(ckt, here->JFET2sourcePrimeNode); + here->JFET2sourcePrimeNode = 0; + } + if (here->JFET2drainPrimeNode + && here->JFET2drainPrimeNode != here->JFET2drainNode) + { + CKTdltNNum(ckt, here->JFET2drainPrimeNode); + here->JFET2drainPrimeNode = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/jfet2/jfet2temp.c b/src/spicelib/devices/jfet2/jfet2temp.c new file mode 100644 index 000000000..fa28fcf0b --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2temp.c @@ -0,0 +1,115 @@ +/********** +Base on jfettemp.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to add PS model and new parameter definitions ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. + 10 Feb 1994: Call to PSinstanceinit() added + Change gatePotential to phi and used rs and rd for + sourceResist and drainResist, and fc for depletionCapCoef +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "jfet2defs.h" +#include "const.h" +#include "sperror.h" +#include "psmodel.h" +#include "suffix.h" + +int +JFET2temp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* Pre-process the model parameters after a possible change + */ +{ + register JFET2model *model = (JFET2model*)inModel; + register JFET2instance *here; + double xfc; + double vt; + double vtnom; + double kt,kt1; + double arg,arg1; + double fact1,fact2; + double egfet,egfet1; + double pbfact,pbfact1; + double gmanew,gmaold; + double ratio1; + double pbo; + double cjfact,cjfact1; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->JFET2nextModel ) { + + if(!(model->JFET2tnomGiven)) { + model->JFET2tnom = ckt->CKTnomTemp; + } + vtnom = CONSTKoverQ * model->JFET2tnom; + fact1 = model->JFET2tnom/REFTEMP; + kt1 = CONSTboltz * model->JFET2tnom; + egfet1 = 1.16-(7.02e-4*model->JFET2tnom*model->JFET2tnom)/ + (model->JFET2tnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom * (1.5*log(fact1)+CHARGE*arg1); + pbo = (model->JFET2phi-pbfact1)/fact1; + gmaold = (model->JFET2phi-pbo)/pbo; + cjfact = 1/(1+.5*(4e-4*(model->JFET2tnom-REFTEMP)-gmaold)); + + if(model->JFET2rd != 0) { + model->JFET2drainConduct = 1/model->JFET2rd; + } else { + model->JFET2drainConduct = 0; + } + if(model->JFET2rs != 0) { + model->JFET2sourceConduct = 1/model->JFET2rs; + } else { + model->JFET2sourceConduct = 0; + } + if(model->JFET2fc >.95) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: Depletion cap. coefficient too large, limited to .95", + &(model->JFET2modName)); + model->JFET2fc = .95; + } + + xfc = log(1 - model->JFET2fc); + model->JFET2f2 = exp((1+.5)*xfc); + model->JFET2f3 = 1 - model->JFET2fc * (1 + .5); + + /* loop through all the instances of the model */ + for (here = model->JFET2instances; here != NULL ; + here=here->JFET2nextInstance) { + if(!(here->JFET2tempGiven)) { + here->JFET2temp = ckt->CKTtemp; + } + vt = here->JFET2temp * CONSTKoverQ; + fact2 = here->JFET2temp/REFTEMP; + ratio1 = here->JFET2temp/model->JFET2tnom -1; + here->JFET2tSatCur = model->JFET2is * exp(ratio1*1.11/vt); + here->JFET2tCGS = model->JFET2capgs * cjfact; + here->JFET2tCGD = model->JFET2capgd * cjfact; + kt = CONSTboltz*here->JFET2temp; + egfet = 1.16-(7.02e-4*here->JFET2temp*here->JFET2temp)/ + (here->JFET2temp+1108); + arg = -egfet/(kt+kt) + 1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2 * vt * (1.5*log(fact2)+CHARGE*arg); + here->JFET2tGatePot = fact2 * pbo + pbfact; + gmanew = (here->JFET2tGatePot-pbo)/pbo; + cjfact1 = 1+.5*(4e-4*(here->JFET2temp-REFTEMP)-gmanew); + here->JFET2tCGS *= cjfact1; + here->JFET2tCGD *= cjfact1; + + here->JFET2corDepCap = model->JFET2fc * here->JFET2tGatePot; + here->JFET2f1 = here->JFET2tGatePot * (1 - exp((1-.5)*xfc))/(1-.5); + here->JFET2vcrit = vt * log(vt/(CONSTroot2 * here->JFET2tSatCur)); + + PSinstanceinit(model, here); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/jfet2trun.c b/src/spicelib/devices/jfet2/jfet2trun.c new file mode 100644 index 000000000..07b687bc6 --- /dev/null +++ b/src/spicelib/devices/jfet2/jfet2trun.c @@ -0,0 +1,38 @@ +/********** +Based on jfettrunc.c +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles + +Modified to jfet2 for PS model definition ( Anthony E. Parker ) + Copyright 1994 Macquarie University, Sydney Australia. +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "jfet2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +JFET2trunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register JFET2model *model = (JFET2model*)inModel; + register JFET2instance *here; + + for( ; model != NULL; model = model->JFET2nextModel) { + for(here=model->JFET2instances;here!=NULL;here = here->JFET2nextInstance){ + if (here->JFET2owner != ARCHme) continue; + + CKTterr(here->JFET2qgs,ckt,timeStep); + CKTterr(here->JFET2qgd,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/jfet2/psmodel.c b/src/spicelib/devices/jfet2/psmodel.c new file mode 100644 index 000000000..9becb7ecc --- /dev/null +++ b/src/spicelib/devices/jfet2/psmodel.c @@ -0,0 +1,359 @@ +/* + Parker-Skellern MESFET model + + Copyright (C) 1994, 1995, 1996 Macquarie University + All Rights Reserved + Author: Anthony Parker + Date: 2 Feb 1994 created + 9 Feb 1994 correct NaN problem in strong cut-off region + 20 MAR 1994 corrected capacitance initialization + 24 MAR 1994 added parameter MVST + 28 MAR 1994 reorganized declaration scopes + 19 APR 1994 added new parameters: PS_HFETA, PS_HFE1, PS_HFE2, + PS_HFG1, and PS_HFG2 + 18 May 1994 corrected 1/0 error when PS_VSUB=0 + 15 Jul 1994 corrected errors in acload routine + 10 Aug 1995 added PS_VSUB to gds += gm*PS_VSUB*mvst*(vgt-vgst*(a.. + 12 Sep 1995 changed _XXX to PS_XXX to aid portability + 13 Sep 1995 change to give arg=1-1/subfac; + if(vst!=0) gds+=gm*PS_VSUB..; + gm *= arg; + 10 Feb 1996 change to names to match MicroSim code. + 5 Jul 1996 corrected diode eq (change Gmin*vgs to Gmin*vgd). + +*****************************************************************************/ + +/*----------- +| functions defined in this file are: + PSids() returns dc drain source current and assigns other + current and branch conductances + qgg() static function that returns gate charge + PScharge() returns gate-source and gate-drain charge and capacitance + PSacload() returns small-signal conductance elements + PSinstanceinit() initializes model parameters + */ + +#define PSMODEL_C /* activate local definitions in psmesfet.h */ +#include "psmodel.h" + +/*----------- +| dc current and conductance calculation */ +double +PSids(ckt, model, here, vgs, vgd, igs, igd, ggs, ggd, Gm, Gds) +cref *ckt; +modl *model; +inst *here; +double vgs; +double vgd; +double *igs; +double *igd; +double *ggs; +double *ggd; +double *Gm; +double *Gds; +{ +#define FX -10.0 /* not too small else fatal rounding error in (rpt-a_rpt) */ +#define MX 40.0 /* maximum exponential argument */ +#define EMX 2.353852668370199842e17 /* exp(MX) */ + + double idrain, arg; + double area = AREA; + + { /* gate junction diodes */ + double zz; + { /* gate-junction forward conduction */ + double Gmin = GMIN; + double Vt = NVT; + double isat = IS * area; + if ((arg=vgs/Vt) > FX) { + if(arg < MX) { + *ggs=(zz=isat*exp(arg))/Vt+Gmin; *igs= zz -isat +Gmin*vgs; + } else { + *ggs=(zz=isat*EMX)/Vt+Gmin; *igs=zz*(arg-MX+1)-isat+Gmin*vgs; + } + } else { + *ggs = Gmin; *igs = -isat + Gmin * vgs; + } + if ((arg=vgd/Vt) > FX) { + if(arg < MX) { + *ggd=(zz=isat*exp(arg))/Vt+Gmin; *igd= zz -isat +Gmin*vgd; + } else { + *ggd=(zz=isat*EMX)/Vt+Gmin; *igd=zz*(arg-MX+1)-isat+Gmin*vgd; + } + } else { + *ggd = Gmin; *igd = -isat + Gmin * vgd; + } + } + { /* gate-junction reverse 'breakdown' conduction */ + double Vbd = VBD; + double ibd = IBD * area; + if ((arg=-vgs/Vbd) > FX) { + if(arg < MX) { + *ggs += (zz=ibd*exp(arg))/Vbd; *igs -= zz-ibd; + } else { + *ggs += (zz=ibd*EMX)/Vbd; *igs -= zz*((arg-MX)+1) - ibd; + } + } else *igs += ibd; + if ((arg=-vgd/Vbd) > FX) { + if(arg < MX) { + *ggd += (zz=ibd*exp(arg))/Vbd; *igd -= zz-ibd; + } else { + *ggd += (zz=ibd*EMX)/Vbd; *igd -= zz*((arg-MX)+1) - ibd; + } + } else *igd += ibd; + } + } + + { /* compute drain current and derivitives */ + double gm, gds; + double vdst = vgs - vgd; + double stepofour = STEP * FOURTH; + { /* Include rate dependent threshold modulation */ + double vgst, dvgd, dvgs, h, vgdtrap, vgstrap, eta, gam; + double vto = VTO; + double LFg = LFGAM, LFg1 = LFG1, LFg2 = LFG2; + double HFg = HFGAM, HFg1 = HFG1, HFg2 = HFG2; + double HFe = HFETA, HFe1 = HFE1, HFe2 = HFE2; + if(TRAN_ANAL) { + double taug = TAUG; + h = taug/(taug + stepofour); h*=h; h*=h; /*4th power*/ + VGDTRAP_NOW = vgdtrap = h*VGDTRAP_BEFORE + (1-h) * vgd; + VGSTRAP_NOW = vgstrap = h*VGSTRAP_BEFORE + (1-h) * vgs; + } else { + h = 0; + VGDTRAP_NOW = vgdtrap = vgd; + VGSTRAP_NOW = vgstrap = vgs; + } + vgst = vgs - vto; + vgst -= ( LFg - LFg1*vgstrap + LFg2*vgdtrap)*vgdtrap; + vgst += (eta = HFe - HFe1*vgdtrap + HFe2*vgstrap)*(dvgs = vgstrap-vgs); + vgst += (gam = HFg - HFg1*vgstrap + HFg2*vgdtrap)*(dvgd = vgdtrap-vgd); + { /* Exponential Subthreshold effect ids(vgst,vdst) */ + double vgt, subfac; + double mvst = MVST; + double vst = VSUB * (1 + mvst*vdst); + if (vgst > FX*vst) { + if (vgst > (arg=MX*vst)) { /* numerically large */ + vgt = (EMX/(subfac = EMX+1))*(vgst-arg) + arg; + } else /* limit gate bias exponentially */ + vgt = vst * log( subfac=(1 + exp(vgst/vst)) ); + { /* Dual Power-law ids(vgt,vdst) */ + double mQ = Q; + double PmQ = P - mQ; + double dvpd_dvdst=(double)D3*pow(vgt,PmQ); + double vdp = vdst*dvpd_dvdst; /*D3=P/Q/((VBI-vto)^PmQ)*/ + { /* Early saturation effect ids(vgt,vdp) */ + double za = (double)ZA; /* sqrt(1 + Z)/2 */ + double mxi = MXI; + double vsatFac = vgt/(mxi*vgt + (double)XI_WOO); + double vsat=vgt/(1 + vsatFac); + double aa = za*vdp+vsat/2.0; + double a_aa = aa-vsat; + double rpt = sqrt( aa * aa + (arg=vsat*vsat*Z/4.0)); + double a_rpt = sqrt(a_aa * a_aa + arg); + double vdt = (rpt - a_rpt); + double dvdt_dvdp = za * (aa/rpt - a_aa/a_rpt); + double dvdt_dvgt = (vdt - vdp*dvdt_dvdp) + *(1 + mxi*vsatFac*vsatFac)/(1 + vsatFac)/vgt; + { /* Intrinsic Q-law FET equation ids(vgt,vdt) */ + gds=pow(vgt-vdt,mQ-1); + idrain = vdt*gds + vgt*(gm=pow(vgt,mQ-1)-gds); + gds *= mQ; + gm *= mQ; + } + gm += gds*dvdt_dvgt; + gds *= dvdt_dvdp; + } + gm += gds*PmQ*vdp/vgt; + gds *= dvpd_dvdst; + } + arg = 1 - 1/subfac; + if(vst != 0) gds += gm*VSUB*mvst*(vgt-vgst*arg)/vst; + gm *= arg; + } else { /* in extreme cut-off (numerically) */ + idrain = gm = gds = 0.0e0; + } + } + gds += gm*(arg = h*gam + + (1-h)*(HFe1*dvgs-HFg2*dvgd+2*LFg2*vgdtrap-LFg1*vgstrap+LFg)); + gm *= 1 - h*eta + (1-h)*(HFe2*dvgs -HFg1*dvgd + LFg1*vgdtrap) - arg; + } + { /* apply channel length modulation and beta scaling */ + double lambda = LAM; + double beta = BETA * area; + gm *= (arg = beta*(1 + lambda*vdst)); + gds = beta*lambda*idrain + gds*arg; + idrain *= arg; + } + + { /* apply thermal reduction of drain current */ + double h, pfac, pAverage; + double delta = DELT / area; + if(TRAN_ANAL) { + double taud = TAUD; + h = taud/(taud + stepofour); h*=h; h*=h; + POWR_NOW = pAverage = h*POWR_BEFORE + (1-h)*vdst*idrain; + } else { + POWR_NOW = POWR_BEFORE = pAverage = vdst*idrain; h = 0; + } + idrain /= (pfac = 1+pAverage*delta); + *Gm = gm * (arg = (h*delta*POWR_BEFORE + 1)/pfac/pfac); + *Gds = gds * arg - (1-h) * delta*idrain*idrain; + } + } + return(idrain); +} + +/*----------- +| code based on Statz et. al. capacitance model, IEEE Tran ED Feb 87 */ +static double +qgg(vgs, vgd, gamma, pb, alpha, vto, vmax, xc, cgso, cgdo, cgs, cgd) +double vgs, vgd, gamma, pb, alpha, vto, vmax, xc, cgso, cgdo, *cgs, *cgd; +{ + double qrt, ext, Cgso, cpm, cplus, cminus; + double vds = vgs-vgd; + double d1_xc = 1-xc; + double vert = sqrt( vds * vds + alpha ); + double veff = 0.5*(vgs + vgd + vert) + gamma*vds; + double vnr = d1_xc*(veff-vto); + double vnrt = sqrt( vnr*vnr + 0.04 ); + double vnew = veff + 0.5*(vnrt - vnr); + if ( vnew < vmax ) { + ext = 0; + qrt = sqrt(1 - vnew/pb); + Cgso = 0.5*cgso/qrt*(1+xc + d1_xc*vnr/vnrt); + } else { + double vx = 0.5*(vnew-vmax); + double par = 1+vx/(pb-vmax); + qrt = sqrt(1 - vmax/pb); + ext = vx*(1 + par)/qrt; + Cgso = 0.5*cgso/qrt*(1+xc + d1_xc*vnr/vnrt) * par; + } + cplus = 0.5*(1 + (cpm = vds/vert)); cminus = cplus - cpm; + *cgs = Cgso*(cplus +gamma) + cgdo*(cminus+gamma); + *cgd = Cgso*(cminus-gamma) + cgdo*(cplus -gamma); + return(cgso*((pb+pb)*(1-qrt) + ext) + cgdo*(veff - vert)); +} + +/*----------- +| call during ac analysis initialisation or during transient analysis */ +void +PScharge(ckt, model, here, vgs, vgd, capgs, capgd) +cref *ckt; +modl *model; +inst *here; +double vgs; +double vgd; +double *capgs; +double *capgd; +{ +#define QGG(a,b,c,d) qgg(a,b,gac,phib,alpha,vto,vmax,xc,czgs,czgd,c,d) +/* double qgg(); */ + + double czgs = CGS * AREA; + double czgd = CGD * AREA; + double vto = VTO; + double alpha = (double)ALPHA; /* (XI*woo/(XI+1)/2)^2 */ + double xc = XC; + double vmax = VMAX; + double phib = VBI; + double gac = ACGAM; + + if(/*TRAN_INIT ||*/ !TRAN_ANAL) + QGS_NOW = QGD_NOW = QGS_BEFORE = QGD_BEFORE + = QGG(vgs,vgd,capgs,capgd); + else { + double cgsna,cgsnc; + double cgdna,cgdnb, a_cap; + double vgs1 = VGS1; + double vgd1 = VGD1; + double qgga=QGG(vgs ,vgd ,&cgsna,&cgdna); + double qggb=QGG(vgs1,vgd ,&a_cap,&cgdnb); + double qggc=QGG(vgs ,vgd1,&cgsnc,&a_cap); + double qggd=QGG(vgs1,vgd1,&a_cap,&a_cap); + QGS_NOW = QGS_BEFORE + 0.5 * (qgga-qggb + qggc-qggd); + QGD_NOW = QGD_BEFORE + 0.5 * (qgga-qggc + qggb-qggd); + *capgs = 0.5 * (cgsna + cgsnc); + *capgd = 0.5 * (cgdna + cgdnb); + } +} + + +/*----------- +| call for each frequency in ac analysis */ +void +PSacload(ckt, model, here, vgs, vgd, ids, omega, Gm, xGm, Gds, xGds) +cref *ckt; +modl *model; +inst *here; +double vgs; +double vgd; +double ids; +double omega; +double *Gm; +double *xGm; +double *Gds; +double *xGds; +{ + double arg; + double vds = vgs - vgd; + double LFgam = LFGAM; + double LFg1 = LFG1; + double LFg2 = LFG2*vgd; + double HFg1 = HFG1; + double HFg2 = HFG2*vgd; + double HFeta = HFETA; + double HFe1 = HFE1; + double HFe2 = HFE2*vgs; + double hfgam= HFGAM - HFg1*vgs + HFg2; + double eta = HFeta - HFe1*vgd + HFe2; + double lfga = LFgam - LFg1*vgs + LFg2 + LFg2; + double gmo = *Gm/(1 - lfga + LFg1*vgd); + + double wtg = TAUG * omega; + double wtgdet = 1 + wtg*wtg; + double gwtgdet = gmo/wtgdet; + + double gdsi = (arg=hfgam - lfga)*gwtgdet; + double gdsr = arg*gmo - gdsi; + double gmi = (eta + LFg1*vgd)*gwtgdet + gdsi; + + double xgds = wtg*gdsi; + double gds = *Gds + gdsr; + double xgm = -wtg*gmi; + double gm = gmi + gmo*(1 -eta - hfgam); + + double delta = DELT / AREA; + double wtd = TAUD * omega ; + double wtddet = 1 + wtd * wtd; + double fac = delta * ids; + double del = 1/(1 - fac * vds); + double dd = (del-1) / wtddet; + double dr = del - dd; + double di = wtd * dd; + + double cdsqr = fac * ids * del * wtd/wtddet; + + *Gm = dr*gm - di*xgm; + *xGm = di*gm + dr*xgm; + + *Gds = dr*gds - di*xgds + cdsqr*wtd; + *xGds = di*gds + dr*xgds + cdsqr; +} + + +void /* call when temperature changes */ +PSinstanceinit(model, here) +modl *model; +inst *here; +{ +#ifndef PARAM_CAST /* allow casting to parameter type */ +#define PARAM_CAST /* if not specified then don't cast */ +#endif + + double woo = (VBI - VTO); + XI_WOO = PARAM_CAST (XI * woo); + ZA = PARAM_CAST (sqrt(1 + Z)/2); + ALPHA = PARAM_CAST (XI_WOO*XI_WOO/(XI+1)/(XI+1)/ 4); + D3 = PARAM_CAST (P/Q/pow(woo,(P - Q))); +} diff --git a/src/spicelib/devices/jfet2/psmodel.h b/src/spicelib/devices/jfet2/psmodel.h new file mode 100644 index 000000000..e943bef78 --- /dev/null +++ b/src/spicelib/devices/jfet2/psmodel.h @@ -0,0 +1,121 @@ +/* + Parker-Skellern MESFET model, UCB Spice Glue Header + + Copyright (C) 1994, 1995, 1996 Macquarie University + All Rights Reserved + Author: Anthony Parker + Creation Date: 2 Feb 1994 + Modified: 24 Mar 1994: Parameters MVST and ETA added. + 18 Apr 1994: Added new parameters and comments + 12 Sep 1995: Changed _XXX to PS_XXX to aid portability + */ + + +#ifdef PSMODEL_C /* PSMODEL_C defined when included from "psmodel.c" */ +#include "ngspice.h" +#include "jfet2defs.h" +#include "const.h" +#endif + +/* Glue definitions for cref modl and inst */ +typedef CKTcircuit cref; /* circuit specific variables */ +typedef JFET2model modl; /* model parameters for this type of device */ +typedef JFET2instance inst; /* parameters specific to this device instance */ + +#ifdef __STDC__ +extern void PSinstanceinit(modl *,inst *); +extern double PSids(cref *,modl *,inst *,double,double, + double *,double *,double *,double *,double *,double *); +extern void PScharge(cref *,modl *,inst *,double,double,double *,double *); +extern void PSacload(cref *,modl *,inst *,double,double,double,double, + double *,double *,double *,double *); +#else +extern void PSinstanceinit(); +extern double PSids(); +extern void PScharge(); +extern void PSacload(); +#endif + +#ifdef PSMODEL_C /* PSMODEL_C defined when included from "psmodel.c" */ +/* The following glue definitions need to be changed to suit the specific + simulator. */ +/* simulator mode flags + TRAN_ANAL should be true during transient analysis iteration. + (ie. false for other analysis functions and tran operating point.) + TRAN_INIT should be true only during the first calculation of the initial + transient analysis time point. It should be false for remaining + iterations at that time point and the rest of the transient analysis. + */ +#define TRAN_ANAL (ckt->CKTmode & MODETRAN) +#define TRAN_INIT (ckt->CKTmode & MODEINITTRAN) + +/* state variables */ +/* initialized when TRAN_ANAL is false */ +#define VGSTRAP_BEFORE (*(ckt->CKTstate1 + here->JFET2vgstrap)) +#define VGSTRAP_NOW (*(ckt->CKTstate0 + here->JFET2vgstrap)) +#define VGDTRAP_BEFORE (*(ckt->CKTstate1 + here->JFET2vtrap)) +#define VGDTRAP_NOW (*(ckt->CKTstate0 + here->JFET2vtrap)) +#define POWR_BEFORE (*(ckt->CKTstate1 + here->JFET2pave)) +#define POWR_NOW (*(ckt->CKTstate0 + here->JFET2pave)) + +/* initialized when TRAN_INIT is true or TRAN_ANAL is false */ +#define QGS_BEFORE (*(ckt->CKTstate1 + here->JFET2qgs)) +#define QGS_NOW (*(ckt->CKTstate0 + here->JFET2qgs)) +#define QGD_BEFORE (*(ckt->CKTstate1 + here->JFET2qgd)) +#define QGD_NOW (*(ckt->CKTstate0 + here->JFET2qgd)) + +/* past terminal potentials used if TRAN_INIT is false and TRAN_ANAL is true */ +#define VGS1 (*(ckt->CKTstate1 + here->JFET2vgs)) +#define VGD1 (*(ckt->CKTstate1 + here->JFET2vgd)) + +/* simulator specific parameters */ +#define GMIN ckt->CKTgmin /* SPICE gmin (1E12 ohms) */ +#define NVT here->JFET2temp*CONSTKoverQ*model->JFET2n /* nkT/q */ +#define STEP ckt->CKTdelta /* time step of this transient solution */ +#define FOURTH 0.25 /* eldo requires 2.5e-10 for units conversion */ + +/* model parameters */ +/* dc model */ +#define BETA model->JFET2beta /* transconductance scaling */ +#define DELT model->JFET2delta /* thermal current reduction */ +#define IBD model->JFET2ibd /* breakdown current */ +#define IS here->JFET2tSatCur /* gate reverse saturation current */ +#define LAM model->JFET2lambda /* channel length modulation */ +#define LFGAM model->JFET2lfgam /* dc drain feedback */ +#define LFG1 model->JFET2lfg1 /* dc drain feedback vgs modulation */ +#define LFG2 model->JFET2lfg2 /* dc drain feedback vgd modulation */ +#define MVST model->JFET2mvst /* subthreshold vds modulation */ +#define MXI model->JFET2mxi /* saturation index vgs modulation */ +#define P model->JFET2p /* power law in controlled resistance */ +#define Q model->JFET2q /* power law in controlled current */ +#define VBD model->JFET2vbd /* breakdown exponential coef */ +#define VBI here->JFET2tGatePot /* junction built-in potential */ +#define VSUB model->JFET2vst /* subthreshold exponential coef */ +#define VTO model->JFET2vto /* pinch-off potential */ +#define XI model->JFET2xi /* saturation index */ +#define Z model->JFET2z /* saturation knee curvature */ + +/* ac model */ +#define ACGAM model->JFET2acgam /* capacitance vds modulation */ +#define CGS here->JFET2tCGS /* zero bias cgs */ +#define CGD here->JFET2tCGD /* zero bias cgd */ +#define HFETA model->JFET2hfeta /* ac source feedback */ +#define HFE1 model->JFET2hfe1 /* ac source feedback vgd modulation */ +#define HFE2 model->JFET2hfe2 /* ac source feedback vgs modulation */ +#define HFGAM model->JFET2hfgam /* ac drain feedback */ +#define HFG1 model->JFET2hfg1 /* ac drain feedback vgs modulation */ +#define HFG2 model->JFET2hfg2 /* ac drain feedback vgd modulation */ +#define TAUD model->JFET2taud /* thermal time constant */ +#define TAUG model->JFET2taug /* dc ac feedback time constant */ +#define XC model->JFET2xc /* cgs reduction at pinch-off */ + +/* device instance */ +#define AREA here->JFET2area /* area factor of fet */ + +/* internally derived model parameters */ +#define ALPHA here->JFET2alpha /* cgs cgd reversal interval */ +#define D3 here->JFET2d3 /* dual power-law parameter */ +#define VMAX here->JFET2corDepCap /* forward capacitance potential */ +#define XI_WOO here->JFET2xiwoo /* saturation potential */ +#define ZA model->JFET2za /* saturation knee parameter */ +#endif diff --git a/src/spicelib/devices/ltra/ChangeLog b/src/spicelib/devices/ltra/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/ltra/Makefile.am b/src/spicelib/devices/ltra/Makefile.am new file mode 100644 index 000000000..a9c725ef1 --- /dev/null +++ b/src/spicelib/devices/ltra/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libltra.la + +libltra_la_SOURCES = \ + ltra.c \ + ltraacct.c \ + ltraacld.c \ + ltraask.c \ + ltradefs.h \ + ltradel.c \ + ltradest.c \ + ltraext.h \ + ltraitf.h \ + ltraload.c \ + ltramask.c \ + ltramdel.c \ + ltramisc.c \ + ltrampar.c \ + ltrapar.c \ + ltraset.c \ + ltratemp.c \ + ltratrun.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/ltra/ltra.c b/src/spicelib/devices/ltra/ltra.c new file mode 100644 index 000000000..817a988e1 --- /dev/null +++ b/src/spicelib/devices/ltra/ltra.c @@ -0,0 +1,85 @@ +/********** +Copyright 1990 Regents of the University of California. All rights +reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +/* + * This file defines the LTRA data structures that are available to the next + * level(s) up the calling hierarchy + */ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "ltradefs.h" +#include "suffix.h" + +IFparm LTRApTable[] = { /* parameters */ + IOPAU("v1", LTRA_V1, IF_REAL, "Initial voltage at end 1"), + IOPAU("v2", LTRA_V2, IF_REAL, "Initial voltage at end 2"), + IOPAU("i1", LTRA_I1, IF_REAL, "Initial current at end 1"), + IOPAU("i2", LTRA_I2, IF_REAL, "Initial current at end 2"), + IP("ic", LTRA_IC, IF_REALVEC, "Initial condition vector:v1,i1,v2,i2"), + OPU("pos_node1", LTRA_POS_NODE1, IF_INTEGER, "Positive node of end 1 of t-line"), + OPU("neg_node1", LTRA_NEG_NODE1, IF_INTEGER, "Negative node of end 1 of t.line"), + OPU("pos_node2", LTRA_POS_NODE2, IF_INTEGER, "Positive node of end 2 of t-line"), + OPU("neg_node2", LTRA_NEG_NODE2, IF_INTEGER, "Negative node of end 2 of t-line") +}; + +IFparm LTRAmPTable[] = { /* model parameters */ + IOP("ltra", LTRA_MOD_LTRA, IF_FLAG, "LTRA model"), + IOPU("r", LTRA_MOD_R, IF_REAL, "Resistance per metre"), + IOPAU("l", LTRA_MOD_L, IF_REAL, "Inductance per metre"), + IOPR("g", LTRA_MOD_G, IF_REAL, "Conductance per metre"), + IOPAU("c", LTRA_MOD_C, IF_REAL, "Capacitance per metre"), + IOPU("len", LTRA_MOD_LEN, IF_REAL, "length of line"), + OP("rel", LTRA_MOD_RELTOL, IF_REAL, "Rel. rate of change of deriv. for bkpt"), + OP("abs", LTRA_MOD_ABSTOL, IF_REAL, "Abs. rate of change of deriv. for bkpt"), + + IOPU("nocontrol", LTRA_MOD_NOCONTROL, IF_FLAG, "No timestep control"), + IOPU("steplimit", LTRA_MOD_STEPLIMIT, IF_FLAG, + "always limit timestep to 0.8*(delay of line)"), + IOPU("nosteplimit", LTRA_MOD_NOSTEPLIMIT, IF_FLAG, + "don't always limit timestep to 0.8*(delay of line)"), + IOPU("lininterp", LTRA_MOD_LININTERP, IF_FLAG, "use linear interpolation"), + IOPU("quadinterp", LTRA_MOD_QUADINTERP, IF_FLAG, "use quadratic interpolation"), + IOPU("mixedinterp", LTRA_MOD_MIXEDINTERP, IF_FLAG, + "use linear interpolation if quadratic results look unacceptable"), + IOPU("truncnr", LTRA_MOD_TRUNCNR, IF_FLAG, + "use N-R iterations for step calculation in LTRAtrunc"), + IOPU("truncdontcut", LTRA_MOD_TRUNCDONTCUT, IF_FLAG, + "don't limit timestep to keep impulse response calculation errors low"), + IOPAU("compactrel", LTRA_MOD_STLINEREL, IF_REAL, + "special reltol for straight line checking"), + IOPAU("compactabs", LTRA_MOD_STLINEABS, IF_REAL, + "special abstol for straight line checking") +#ifdef notdef + IOP("f", LTRA_MOD_FREQ, IF_REAL, "Frequency"), + IOP("nl", LTRA_MOD_NL, IF_REAL, "Normalized length at frequency given"), + IOP("fullcontrol", LTRA_MOD_FULLCONTROL, IF_FLAG, "rigorous timestep control"), + IOP("halfcontrol", LTRA_MOD_HALFCONTROL, IF_FLAG, + "only the current step is considered for timestep control"), + IOP("print", LTRA_MOD_PRINT, IF_FLAG, "printing of debugging info on"), + IOP("noprint", LTRA_MOD_NOPRINT, IF_FLAG, "printing of debugging info off"), + IOP("ronly", LTRA_MOD_RONLY, IF_FLAG, "use special load routines for G=0"), + IOP("choprel", LTRA_MOD_CHOPREL, IF_REAL, + "special reltol for truncation of impulse responses"), + IOP("chopabs", LTRA_MOD_CHOPABS, IF_REAL, + "special abstol for truncation of impulse responses "), +#endif +}; + +char *LTRAnames[] = { + "P1+", + "P1-", + "P2+", + "P2-" +}; + +int LTRAnSize = NUMELEMS(LTRAnames); +int LTRApTSize = NUMELEMS(LTRApTable); +int LTRAmPTSize = NUMELEMS(LTRAmPTable); +int LTRAiSize = sizeof(LTRAinstance); +int LTRAmSize = sizeof(LTRAmodel); diff --git a/src/spicelib/devices/ltra/ltraacct.c b/src/spicelib/devices/ltra/ltraacct.c new file mode 100644 index 000000000..f060519ce --- /dev/null +++ b/src/spicelib/devices/ltra/ltraacct.c @@ -0,0 +1,307 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAaccept(ckt, inModel) + register CKTcircuit *ckt; + GENmodel *inModel; +{ + register LTRAmodel *model = (LTRAmodel *) inModel; + register LTRAinstance *here; + double v1, v2, v3, v4; + double v5, v6, d1, d2, d3, d4; + int tmp_test; + int error; + int compact = 1; + + + /* loop through all the transmission line models */ + for (; model != NULL; model = model->LTRAnextModel) { + + if (ckt->CKTmode & MODEINITTRAN) { + +#define LTRAmemMANAGE(a,b) \ + if ( a != NULL) FREE(a);\ + a = (double *) MALLOC( b * sizeof(double)); + + model->LTRAmodelListSize = 10; + + + LTRAmemMANAGE(model->LTRAh1dashCoeffs, model->LTRAmodelListSize) + LTRAmemMANAGE(model->LTRAh2Coeffs, model->LTRAmodelListSize) + LTRAmemMANAGE(model->LTRAh3dashCoeffs, model->LTRAmodelListSize) + } + if (ckt->CKTtimeIndex >= model->LTRAmodelListSize) { /* need more space */ + model->LTRAmodelListSize += ckt->CKTsizeIncr; + + + model->LTRAh1dashCoeffs = (double *) + REALLOC((char *) model->LTRAh1dashCoeffs, + sizeof(double) * model->LTRAmodelListSize); + model->LTRAh2Coeffs = (double *) + REALLOC((char *) model->LTRAh2Coeffs, + sizeof(double) * model->LTRAmodelListSize); + model->LTRAh3dashCoeffs = (double *) + REALLOC((char *) model->LTRAh3dashCoeffs, + sizeof(double) * model->LTRAmodelListSize); + } + /* loop through all the instances of the model */ + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + if (here->LTRAowner != ARCHme) continue; /* XXX */ + + if (ckt->CKTmode & MODEINITTRAN) { + here->LTRAinstListSize = 10; + + LTRAmemMANAGE(here->LTRAv1, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAi1, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAv2, here->LTRAinstListSize) + LTRAmemMANAGE(here->LTRAi2, here->LTRAinstListSize) + } + /* + * why is this here? ask TQ + * + * if (ckt->CKTtimeIndex == 0? 1: (ckt->CKTtime- + * (ckt->CKTtimePoints+ckt->CKTtimeIndex-1) > ckt->CKTminBreak)) { + * + */ + if (ckt->CKTtimeIndex >= here->LTRAinstListSize) { /* need more space */ + here->LTRAinstListSize += ckt->CKTsizeIncr; + + here->LTRAv1 = (double *) REALLOC((char *) + here->LTRAv1, sizeof(double) * (here->LTRAinstListSize)); + here->LTRAi1 = (double *) REALLOC((char *) + here->LTRAi1, sizeof(double) * (here->LTRAinstListSize)); + here->LTRAi2 = (double *) REALLOC((char *) + here->LTRAi2, sizeof(double) * (here->LTRAinstListSize)); + here->LTRAv2 = (double *) REALLOC((char *) + here->LTRAv2, sizeof(double) * (here->LTRAinstListSize)); + } + *(here->LTRAv1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAposNode1) - *(ckt->CKTrhsOld + + here->LTRAnegNode1); + *(here->LTRAv2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAposNode2) - *(ckt->CKTrhsOld + + here->LTRAnegNode2); + *(here->LTRAi1 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAbrEq1); + *(here->LTRAi2 + ckt->CKTtimeIndex) = *(ckt->CKTrhsOld + + here->LTRAbrEq2); + + if (ckt->CKTtryToCompact && (ckt->CKTtimeIndex >= 2)) { + + /* + * figure out if the last 3 points lie on a st. line for all the + * terminal variables + */ + { + double t1, t2, t3; + + t1 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 2); + t2 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1); + t3 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex); + + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAv1 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAv1 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAv1 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAv2 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAv2 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAv2 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAi1 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAi1 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAi1 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + if (compact) { + compact = LTRAstraightLineCheck(t1, + *(here->LTRAi2 + ckt->CKTtimeIndex - 2), + t2, *(here->LTRAi2 + ckt->CKTtimeIndex - 1), + t3, *(here->LTRAi2 + ckt->CKTtimeIndex), + model->LTRAstLineReltol, model->LTRAstLineAbstol); + } + } + } + if (ckt->CKTtimeIndex > 0) { +#ifdef NOTDEF + v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + + *(here->LTRAi1 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) + * model->LTRAimped) * model->LTRAattenuation; + v3 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + + *(here->LTRAi2 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + if ((fabs(v1 - v2) >= 50 * ckt->CKTreltol * + MAX(fabs(v1), fabs(v2)) + 50 * ckt->CKTvoltTol) || + (fabs(v3 - v4) >= 50 * ckt->CKTreltol * + MAX(fabs(v3), fabs(v4)) + 50 * ckt->CKTvoltTol)) { + /* changing - need to schedule after delay */ + /* + * don't really need this error = + * CKTsetBreak(ckt,ckt->CKTtime+model->LTRAtd); if(error) + * return(error); + */ + /* the PREVIOUS point is the real breakpoint */ + error = CKTsetBreak(ckt, + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + + model->LTRAtd); + CKTbreakDump(ckt); + if (error) + return (error); + } +#else + /* + * remove the hack here - store the total inputs for the last 2 or 3 + * timesteps + */ + + v1 = (*(here->LTRAv1 + ckt->CKTtimeIndex) + + *(here->LTRAi1 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v2 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + v3 = ckt->CKTtimeIndex < 2 ? v2 : (*(here->LTRAv1 + ckt->CKTtimeIndex - 2) + + *(here->LTRAi1 + ckt->CKTtimeIndex - 2) * + model->LTRAimped) * model->LTRAattenuation; + v4 = (*(here->LTRAv2 + ckt->CKTtimeIndex) + + *(here->LTRAi2 + ckt->CKTtimeIndex) * + model->LTRAimped) * model->LTRAattenuation; + v5 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) * + model->LTRAimped) * model->LTRAattenuation; + v6 = ckt->CKTtimeIndex < 2 ? v5 : (*(here->LTRAv2 + ckt->CKTtimeIndex - 2) + + *(here->LTRAi2 + ckt->CKTtimeIndex - 2) * + model->LTRAimped) * model->LTRAattenuation; + d1 = (v1 - v2) / (*(ckt->CKTtimePoints + + ckt->CKTtimeIndex) - *(ckt->CKTtimePoints + + ckt->CKTtimeIndex - 1)); + d2 = (v2 - v3) / (*(ckt->CKTtimePoints + + ckt->CKTtimeIndex - 1) - *(ckt->CKTtimePoints + + ckt->CKTtimeIndex - 2)); + d3 = (v4 - v5) / (*(ckt->CKTtimePoints + + ckt->CKTtimeIndex) - *(ckt->CKTtimePoints + + ckt->CKTtimeIndex - 1)); + d4 = (v5 - v6) / (*(ckt->CKTtimePoints + + ckt->CKTtimeIndex - 1) - *(ckt->CKTtimePoints + + ckt->CKTtimeIndex - 2)); + + /* + * here we have a big problem with the scheme boxed by the *s below. + * Note the following: if LTRAreltol == 1, (assuming LTRAabstol==0) + * then breakpoints are set if and only if d1 and d2 have opposite + * signs or one is zero. If LTRAreltol > 2, breakpoints are never + * set. The problem is that when the waveform is steady at a value, + * small random numerical inaccuracies may produce derivatives of + * opposite sign, and breakpoints get set. This can, in practice, get + * quite killing... To alleviate this, we try to determine if the + * waveform is actually steady using the following tests: 1. Check if + * the maximum difference between v1,v2 and v3 is less than + * 50*CKTreltol*(the average of v1,v2,and v3) + 50*ckt->CKTabstol + * (the 50 has been taken from the NOTDEF section above, reason + * unknown - hopefully there is a good reason for it - ask TQ) + * + * 2. Criterion 1 may be satisfied by a legitimate breakpoint. To + * further check, find one more derivative one timepoint ago and see + * if that is close to d2. If not, then the likelihood of numerical + * inaccuracies is greater... + */ + + /********************************************************************* + if( (fabs(d1-d2) >= model->LTRAreltol*MAX(fabs(d1),fabs(d2))+ + model->LTRAabstol) || + (fabs(d3-d4) >= model->LTRAreltol*MAX(fabs(d3),fabs(d4))+ + model->LTRAabstol) ) { + *********************************************************************/ +#define CHECK(a,b,c) (MAX(MAX(a,b),c)-MIN(MIN(a,b),c) >= \ + fabs(50.0*(ckt->CKTreltol/3.0*(a+b+c) +\ + ckt->CKTabstol))) + + tmp_test = (fabs(d1 - d2) + >= model->LTRAreltol * MAX(fabs(d1), fabs(d2)) + + model->LTRAabstol) + && CHECK(v1, v2, v3); + if (tmp_test || ((fabs(d3 - d4) + >= model->LTRAreltol * MAX(fabs(d3), fabs(d4)) + + model->LTRAabstol) + && CHECK(v4, v5, v6))) { + /* criterion 2 not implemented yet... */ + error = CKTsetBreak(ckt, + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) + + model->LTRAtd); + /* + * this is not necessary - the previous timepoint was the + * breakpoint error = CKTsetBreak(ckt, ckt->CKTtime + + * model->LTRAtd); + */ +#ifdef LTRADEBUG + fprintf(stdout, "\nbreakpoints set at %14.14g at %14.14g at time %14.14g\n", ckt->CKTtime + model->LTRAtd, *(ckt->CKTtimePoints + ckt->CKTtimeIndex + - 1) + model->LTRAtd, ckt->CKTtime); + fprintf(stdout, "d1 through d4 are %14.14g %14.14g %14.14g %14.14g\n\n", d1, d2, d3, d4); +#endif + if (error) + return (error); + } + /* } */ +#endif /* NOTDEF */ + } + /* ask TQ } */ + + } /* instance */ + } /* model */ + + + if (ckt->CKTtryToCompact && compact && (ckt->CKTtimeIndex >= 2)) { + + /* + * last three timepoints have variables lying on a straight line, do a + * compaction + */ + + model = (LTRAmodel *) inModel; + for (; model != NULL; model = model->LTRAnextModel) { + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + *(here->LTRAv1 + ckt->CKTtimeIndex - 1) = *(here->LTRAv1 + + ckt->CKTtimeIndex); + *(here->LTRAv2 + ckt->CKTtimeIndex - 1) = *(here->LTRAv2 + + ckt->CKTtimeIndex); + *(here->LTRAi1 + ckt->CKTtimeIndex - 1) = *(here->LTRAi1 + + ckt->CKTtimeIndex); + *(here->LTRAi2 + ckt->CKTtimeIndex - 1) = *(here->LTRAi2 + + ckt->CKTtimeIndex); + } + } + *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1) = + *(ckt->CKTtimePoints + ckt->CKTtimeIndex); + ckt->CKTtimeIndex--; +#ifdef LTRADEBUG + fprintf(stdout, "compacted at time=%g\n", *(ckt->CKTtimePoints + ckt->CKTtimeIndex)); + fflush(stdout); +#endif + } + return (OK); +} diff --git a/src/spicelib/devices/ltra/ltraacld.c b/src/spicelib/devices/ltra/ltraacld.c new file mode 100644 index 000000000..1b43c4ea3 --- /dev/null +++ b/src/spicelib/devices/ltra/ltraacld.c @@ -0,0 +1,148 @@ +/********** +Copyright 1990 Regents of the University of California. All rights +reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ltradefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAacLoad(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +/* + * load the appropriate values for the current timepoint into the sparse + * matrix and the right-hand-side vector + */ +{ + register LTRAmodel *model = (LTRAmodel *) inModel; + register LTRAinstance *here; + double y0_r, y0_i, lambda_r, lambda_i, mag, theta; + double exparg_r, exparg_i, explambda_r, explambda_i; + double y0exp_r, y0exp_i; + int savemode, error; + + /* + * LTRAacLoad - loads for LTRA lines for the s.s. ac case the equations are + * the following: + * + * Y_0(s) * V_1(s) - I_1(s) = exp(-lambda(s)*length) * (Y_0(s) * V_2(s) + + * I_2(s)) Y_0(s) * V_2(s) - I_2(s) = exp(-lambda(s)*length) * (Y_0(s) * + * V_1(s) + I_1(s)) + * + * where Y_0(s) and lambda(s) are as follows: + * + * Y_0(s) = sqrt( (sC+G)/(sL+R) ) lambda(s) = sqrt( (sC+G)*(sL+R) ) + * + * for the RC, RLC, and LC cases, G=0. The RG case is handled exactly as the + * DC case, (and the above equations require reformulation because they + * become identical for the DC case.) + */ + + /* loop through all the transmission line models */ + for (; model != NULL; model = model->LTRAnextModel) { + + switch (model->LTRAspecialCase) { + + case LTRA_MOD_LC: + + y0_r = model->LTRAadmit; + y0_i = 0.0; + lambda_i = model->LTRAtd * ckt->CKTomega; + lambda_r = 0.0; + break; + + case LTRA_MOD_RLC: + + theta = 0.5 * atan(model->LTRAresist / (ckt->CKTomega*model->LTRAinduct)); + mag = sqrt(ckt->CKTomega * model->LTRAcapac / + sqrt(model->LTRAresist * model->LTRAresist + + ckt->CKTomega * ckt->CKTomega * model->LTRAinduct * + model->LTRAinduct)); + y0_r = mag * cos(theta); + y0_i = mag * sin(theta); + + theta = M_PI / 2 - theta; + mag *= sqrt(model->LTRAresist * model->LTRAresist + + ckt->CKTomega * ckt->CKTomega * model->LTRAinduct * + model->LTRAinduct); + lambda_r = mag * cos(theta); + lambda_i = mag * sin(theta); + break; + + case LTRA_MOD_RC: + + y0_r = y0_i = sqrt(0.5 * ckt->CKTomega * model->LTRAcByR); + lambda_r = lambda_i = + sqrt(0.5 * ckt->CKTomega * model->LTRAresist * model->LTRAcapac); + break; + + case LTRA_MOD_RG: + + savemode = ckt->CKTmode; + ckt->CKTmode |= MODEDC; + error = LTRAload(inModel, ckt); + ckt->CKTmode = savemode; + return (error); + break; + + default: + return (E_BADPARM); + } + + exparg_r = -lambda_r * model->LTRAlength; + exparg_i = -lambda_i * model->LTRAlength; + explambda_r = exp(exparg_r) * cos(exparg_i); + explambda_i = exp(exparg_r) * sin(exparg_i); + y0exp_r = y0_r * explambda_r - y0_i * explambda_i; + y0exp_i = y0_r * explambda_i + y0_i * explambda_r; + + /* loop through all the instances of the model */ + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + if (here->LTRAowner != ARCHme) continue; + + *(here->LTRAibr1Pos1Ptr + 0) += y0_r; + *(here->LTRAibr1Pos1Ptr + 1) += y0_i; + *(here->LTRAibr1Neg1Ptr + 0) -= y0_r; + *(here->LTRAibr1Neg1Ptr + 1) -= y0_i; + + *(here->LTRAibr1Ibr1Ptr + 0) -= 1.0; + + *(here->LTRAibr1Pos2Ptr + 0) -= y0exp_r; + *(here->LTRAibr1Pos2Ptr + 1) -= y0exp_i; + *(here->LTRAibr1Neg2Ptr + 0) += y0exp_r; + *(here->LTRAibr1Neg2Ptr + 1) += y0exp_i; + + *(here->LTRAibr1Ibr2Ptr + 0) -= explambda_r; + *(here->LTRAibr1Ibr2Ptr + 1) -= explambda_i; + + *(here->LTRAibr2Pos2Ptr + 0) += y0_r; + *(here->LTRAibr2Pos2Ptr + 1) += y0_i; + *(here->LTRAibr2Neg2Ptr + 0) -= y0_r; + *(here->LTRAibr2Neg2Ptr + 1) -= y0_i; + + *(here->LTRAibr2Ibr2Ptr + 0) -= 1.0; + + *(here->LTRAibr2Pos1Ptr + 0) -= y0exp_r; + *(here->LTRAibr2Pos1Ptr + 1) -= y0exp_i; + *(here->LTRAibr2Neg1Ptr + 0) += y0exp_r; + *(here->LTRAibr2Neg1Ptr + 1) += y0exp_i; + + *(here->LTRAibr2Ibr1Ptr + 0) -= explambda_r; + *(here->LTRAibr2Ibr1Ptr + 1) -= explambda_i; + + *(here->LTRApos1Ibr1Ptr + 0) += 1.0; + *(here->LTRAneg1Ibr1Ptr + 0) -= 1.0; + *(here->LTRApos2Ibr2Ptr + 0) += 1.0; + *(here->LTRAneg2Ibr2Ptr + 0) -= 1.0; + } + } + return (OK); +} diff --git a/src/spicelib/devices/ltra/ltraask.c b/src/spicelib/devices/ltra/ltraask.c new file mode 100644 index 000000000..bf4e07cb9 --- /dev/null +++ b/src/spicelib/devices/ltra/ltraask.c @@ -0,0 +1,93 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +/* + * This routine gives access to the internal device parameter of LTRA lines + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +LTRAask(ckt, inst, which, value, select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + LTRAinstance *here = (LTRAinstance *) inst; + int temp; + + switch (which) { + case LTRA_POS_NODE1: + value->iValue = here->LTRAposNode1; + return (OK); + case LTRA_NEG_NODE1: + value->iValue = here->LTRAnegNode1; + return (OK); + case LTRA_POS_NODE2: + value->iValue = here->LTRAposNode2; + return (OK); + case LTRA_NEG_NODE2: + value->iValue = here->LTRAnegNode2; + return (OK); + case LTRA_MOD_Z0: + value->rValue = here->LTRAmodPtr->LTRAimped; + return (OK); + case LTRA_MOD_TD: + value->rValue = here->LTRAmodPtr->LTRAtd; + return (OK); + case LTRA_MOD_NL: + value->rValue = here->LTRAmodPtr->LTRAnl; + return (OK); + case LTRA_MOD_FREQ: + value->rValue = here->LTRAmodPtr->LTRAf; + return (OK); + case LTRA_V1: + value->rValue = here->LTRAinitVolt1; + return (OK); + case LTRA_I1: + value->rValue = here->LTRAinitCur1; + return (OK); + case LTRA_V2: + value->rValue = here->LTRAinitVolt2; + return (OK); + case LTRA_I2: + value->rValue = here->LTRAinitCur2; + return (OK); + case LTRA_MOD_RELTOL: + value->rValue = here->LTRAmodPtr->LTRAreltol; + return (OK); + case LTRA_MOD_ABSTOL: + value->rValue = here->LTRAmodPtr->LTRAabstol; + return (OK); + case LTRA_BR_EQ1: + value->rValue = here->LTRAbrEq1; + return (OK); + case LTRA_BR_EQ2: + value->rValue = here->LTRAbrEq2; + return (OK); + case LTRA_DELAY: + /* + * value->v.vec.rVec = (double *) MALLOC(here->LTRAsizeDelay); + * value->v.numValue = temp = here->LTRAsizeDelay; while (temp--) { + * value->v.vec.rVec++ = *here->LTRAdelays++; + */ + value->v.vec.rVec = (double *) NULL; + value->v.numValue = temp = 0; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/ltra/ltradefs.h b/src/spicelib/devices/ltra/ltradefs.h new file mode 100644 index 000000000..e8204f7ec --- /dev/null +++ b/src/spicelib/devices/ltra/ltradefs.h @@ -0,0 +1,244 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#ifndef LTRA +#define LTRA +#undef LTRALTEINFO +#undef LTRADEBUG + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + +/* structures used to describe lossy transmission liness */ + +/* information used to describe a single instance */ + +typedef struct sLTRAinstance { + struct sLTRAmodel *LTRAmodPtr; /* backpointer to model */ + struct sLTRAinstance *LTRAnextInstance; /* pointer to next instance of + * current model*/ + IFuid LTRAname; /* pointer to character string naming this instance */ + int LTRAowner; /* number of owner process */ + int LTRAstate; /* not used */ + int LTRAposNode1; /* number of positive node of end 1 of t. line */ + int LTRAnegNode1; /* number of negative node of end 1 of t. line */ + int LTRAposNode2; /* number of positive node of end 2 of t. line */ + int LTRAnegNode2; /* number of negative node of end 2 of t. line */ + + int LTRAbrEq1; /* number of branch equation for end 1 of t. line */ + int LTRAbrEq2; /* number of branch equation for end 2 of t. line */ + double LTRAinput1; /* accumulated excitation for port 1 */ + double LTRAinput2; /* accumulated excitation for port 2 */ + double LTRAinitVolt1; /* initial condition: voltage on port 1 */ + double LTRAinitCur1; /* initial condition: current at port 1 */ + double LTRAinitVolt2; /* initial condition: voltage on port 2 */ + double LTRAinitCur2; /* initial condition: current at port 2 */ + double *LTRAv1; /* past values of v1 */ + double *LTRAi1; /* past values of i1 */ + double *LTRAv2; /* past values of v2 */ + double *LTRAi2; /* past values of i2 */ + int LTRAinstListSize; /* size of above lists */ + + double *LTRAibr1Ibr1Ptr; /* pointer to sparse matrix */ + double *LTRAibr1Ibr2Ptr; /* pointer to sparse matrix */ + double *LTRAibr1Pos1Ptr; /* pointer to sparse matrix */ + double *LTRAibr1Neg1Ptr; /* pointer to sparse matrix */ + double *LTRAibr1Pos2Ptr; /* pointer to sparse matrix */ + double *LTRAibr1Neg2Ptr; /* pointer to sparse matrix */ + double *LTRAibr2Ibr1Ptr; /* pointer to sparse matrix */ + double *LTRAibr2Ibr2Ptr; /* pointer to sparse matrix */ + double *LTRAibr2Pos1Ptr; /* pointer to sparse matrix */ + double *LTRAibr2Neg1Ptr; /* pointer to sparse matrix */ + double *LTRAibr2Pos2Ptr; /* pointer to sparse matrix */ + double *LTRAibr2Neg2Ptr; /* pointer to sparse matrix */ + double *LTRAneg1Ibr1Ptr; /* pointer to sparse matrix */ + double *LTRAneg2Ibr2Ptr; /* pointer to sparse matrix */ + double *LTRApos1Ibr1Ptr; /* pointer to sparse matrix */ + double *LTRApos2Ibr2Ptr; /* pointer to sparse matrix */ + double *LTRApos1Pos1Ptr; /* pointer to sparse matrix */ + double *LTRAneg1Neg1Ptr; /* pointer to sparse matrix */ + double *LTRApos2Pos2Ptr; /* pointer to sparse matrix */ + double *LTRAneg2Neg2Ptr; /* pointer to sparse matrix */ + + unsigned LTRAicV1Given : 1; /* flag to ind. init. voltage at port 1 given */ + unsigned LTRAicC1Given : 1; /* flag to ind. init. current at port 1 given */ + unsigned LTRAicV2Given : 1; /* flag to ind. init. voltage at port 2 given */ + unsigned LTRAicC2Given : 1; /* flag to ind. init. current at port 2 given */ +} LTRAinstance ; + + +/* per model data */ + +typedef struct sLTRAmodel { /* model structure for a transmission lines */ + int LTRAmodType; /* type index of this device type */ + struct sLTRAmodel *LTRAnextModel; /* pointer to next possible model in + * linked list */ + LTRAinstance * LTRAinstances; /* pointer to list of instances that have this + * model */ + IFuid LTRAmodName; /* pointer to character string naming this model */ + + double LTRAh1dashFirstVal; /* first needed value of h1dasg at + current timepoint */ + double LTRAh2FirstVal; /* first needed value of h2 at current + timepoint */ + double LTRAh3dashFirstVal; /* first needed value of h3dash at + current timepoint */ + +#if 0 + double *LTRAh1dashValues; /* values of h1dash for all previous + times */ + double *LTRAh2Values; /* values of h2 for all previous times */ + double *LTRAh3dashValues; /* values of h3dash for all previous + times */ + + double LTRAh2FirstOthVal; /* needed for LTE calc; but their values */ + double LTRAh3dashFirstOthVal; /*may depend on the current timepoint*/ + + double *LTRAh1dashOthVals; /* these lists of other values are */ + double *LTRAh2OthVals; /* needed for truncation error */ + double *LTRAh3dashOthVals; /* calculation */ +#endif + /* the OthVals do not depend on the current + * timepoint; hence they are set up in LTRAaccept.c. + * They are used in LTRAtrunc.c + */ + + double LTRAh1dashFirstCoeff; /* first needed coeff of h1dash for + the current timepoint */ + double LTRAh2FirstCoeff; /* first needed coeff of h2 for the + current timepoint */ + double LTRAh3dashFirstCoeff; /* first needed coeff of h3dash for + the current timepoint */ + + double *LTRAh1dashCoeffs; /* list of other coefficients for h1dash */ + double *LTRAh2Coeffs; /* list of other coefficients for h2 */ + double *LTRAh3dashCoeffs; /* list of other coefficients for h3dash */ + int LTRAmodelListSize; /* size of above lists */ + + double LTRAconduct; /* conductance G - input */ + double LTRAresist; /* resistance R - input */ + double LTRAinduct; /* inductance L - input */ + double LTRAcapac; /* capacitance C - input */ + double LTRAlength; /* length l - input */ + double LTRAtd; /* propagation delay T - calculated*/ + double LTRAimped; /* impedance Z - calculated*/ + double LTRAadmit; /* admittance Y - calculated*/ + double LTRAalpha; /* alpha - calculated */ + double LTRAbeta; /* beta - calculated */ + double LTRAattenuation; /* e^(-beta T) - calculated */ + double LTRAcByR; /* C/R - for the RC line - calculated */ + double LTRArclsqr; /* RCl^2 - for the RC line - calculated */ + double LTRAintH1dash;/* \int_0^\inf h'_1(\tau) d \tau - calculated*/ + double LTRAintH2;/* \int_0^\inf h_2(\tau) d \tau - calculated*/ + double LTRAintH3dash;/* \int_0^\inf h'_3(\tau) d \tau - calculated*/ + + double LTRAnl; /* normalized length - historical significance only*/ + double LTRAf; /* frequency at which nl is measured - historical significance only*/ + double LTRAcoshlrootGR; /* cosh(l*sqrt(G*R)), used for DC anal */ + double LTRArRsLrGRorG; /* sqrt(R)*sinh(l*sqrt(G*R))/sqrt(G) */ + double LTRArGsLrGRorR; /* sqrt(G)*sinh(l*sqrt(G*R))/sqrt(R) */ + + /*int LTRAh1dashIndex;*/ /* index for h1dash that points to the + latest nonzero coefficient in the list */ + /*int LTRAh2Index;*/ /* ditto for h2 */ + /*int LTRAh3dashIndex;*/ /* ditto for h3dash */ + int LTRAauxIndex; /* auxiliary index for h2 and h3dash */ + double LTRAstLineReltol; /* separate reltol for checking st. lines */ + double LTRAchopReltol; /* separate reltol for truncation of impulse responses*/ + double LTRAstLineAbstol; /* separate abstol for checking st. lines */ + double LTRAchopAbstol; /* separate abstol for truncation of impulse responses */ + + unsigned LTRAreltolGiven:1; /* flag to ind. relative deriv. tol. given */ + unsigned LTRAabstolGiven:1; /* flag to ind. absolute deriv. tol. given */ + unsigned LTRAtruncNR:1; /* flag to ind. use N-R iterations for calculating step in LTRAtrunc */ + unsigned LTRAtruncDontCut:1; /* flag to ind. don't bother about errors in impulse response calculations due to large steps*/ + double LTRAmaxSafeStep; /* maximum safe step for impulse response calculations */ + unsigned LTRAresistGiven : 1; /* flag to indicate R was specified */ + unsigned LTRAconductGiven : 1; /* flag to indicate G was specified */ + unsigned LTRAinductGiven : 1; /* flag to indicate L was specified */ + unsigned LTRAcapacGiven : 1; /* flag to indicate C was specified */ + unsigned LTRAlengthGiven : 1; /* flag to indicate length was specified */ + unsigned LTRAnlGiven : 1; /* flag to indicate norm length was specified */ + int LTRAlteConType; /* indicates whether full control, half control or no control */ + int LTRAhowToInterp; /* indicates how to interpolate for delayed timepoint */ + unsigned LTRAprintFlag: 1; /* flag to indicate whether debugging output should be printed */ + /*unsigned LTRArOnly: 1;*/ /* flag to indicate G=0, use known Bessel + integrals for accuracy and speed */ + int LTRAstepLimit; /* flag to indicate that the timestep + should always be limited to + 0.8*LTRAtd */ + unsigned LTRAfGiven : 1; /* flag to indicate freq was specified */ + double LTRAabstol; /* absolute deriv. tol. for breakpoint setting */ + double LTRAreltol; /* relative deriv. tol. for breakpoint setting */ + int LTRAspecialCase; /* what kind of model (RC, RLC, RL, ...) */ +} LTRAmodel; + +/* device parameters */ +#define LTRA_MOD_LTRA 0 +#define LTRA_MOD_R 1 +#define LTRA_MOD_L 2 +#define LTRA_MOD_G 3 +#define LTRA_MOD_C 4 +#define LTRA_MOD_LEN 5 +#define LTRA_V1 6 +#define LTRA_I1 7 +#define LTRA_V2 8 +#define LTRA_I2 9 +#define LTRA_IC 10 +#define LTRA_MOD_RELTOL 11 +#define LTRA_MOD_ABSTOL 12 +#define LTRA_POS_NODE1 13 +#define LTRA_NEG_NODE1 14 +#define LTRA_POS_NODE2 15 +#define LTRA_NEG_NODE2 16 +#define LTRA_INPUT1 17 +#define LTRA_INPUT2 18 +#define LTRA_DELAY 19 +#define LTRA_BR_EQ1 20 +#define LTRA_BR_EQ2 21 +#define LTRA_MOD_NL 22 +#define LTRA_MOD_FREQ 23 +#define LTRA_MOD_Z0 24 +#define LTRA_MOD_TD 25 + +#define LTRA_MOD_FULLCONTROL 26 +#define LTRA_MOD_HALFCONTROL 27 +#define LTRA_MOD_NOCONTROL 28 +#define LTRA_MOD_PRINT 29 +#define LTRA_MOD_NOPRINT 30 +/* +#define LTRA_MOD_RONLY 31 +*/ +#define LTRA_MOD_STEPLIMIT 32 +#define LTRA_MOD_NOSTEPLIMIT 33 +#define LTRA_MOD_LININTERP 34 +#define LTRA_MOD_QUADINTERP 35 +#define LTRA_MOD_MIXEDINTERP 36 +#define LTRA_MOD_RLC 37 +#define LTRA_MOD_RC 38 +#define LTRA_MOD_RG 39 +#define LTRA_MOD_LC 40 +#define LTRA_MOD_RL 41 +#define LTRA_MOD_STLINEREL 42 +#define LTRA_MOD_STLINEABS 43 +#define LTRA_MOD_CHOPREL 44 +#define LTRA_MOD_CHOPABS 45 +#define LTRA_MOD_TRUNCNR 46 +#define LTRA_MOD_TRUNCDONTCUT 47 + + + +/* model parameters */ + +/* device questions */ + +/* model questions */ + +#include "ltraext.h" + +#endif /*LTRA*/ + diff --git a/src/spicelib/devices/ltra/ltradel.c b/src/spicelib/devices/ltra/ltradel.c new file mode 100644 index 000000000..1d897af9c --- /dev/null +++ b/src/spicelib/devices/ltra/ltradel.c @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAdelete(inModel, name, kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; +{ + LTRAinstance **fast = (LTRAinstance **) kill; + LTRAmodel *model = (LTRAmodel *) inModel; + LTRAinstance **prev = NULL; + LTRAinstance *here; + + for (; model; model = model->LTRAnextModel) { + prev = &(model->LTRAinstances); + for (here = *prev; here; here = *prev) { + if (here->LTRAname == name || (fast && here == *fast)) { + *prev = here->LTRAnextInstance; + FREE(here); + return (OK); + } + prev = &(here->LTRAnextInstance); + } + } + return (E_NODEV); +} diff --git a/src/spicelib/devices/ltra/ltradest.c b/src/spicelib/devices/ltra/ltradest.c new file mode 100644 index 000000000..99438ea9f --- /dev/null +++ b/src/spicelib/devices/ltra/ltradest.c @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "ltradefs.h" +#include "suffix.h" + +void +LTRAdestroy(inModel) + GENmodel **inModel; +{ + LTRAmodel **model = (LTRAmodel **) inModel; + LTRAinstance *here; + LTRAinstance *prev = NULL; + LTRAmodel *mod = *model; + LTRAmodel *oldmod = NULL; + + for (; mod; mod = mod->LTRAnextModel) { + if (oldmod) + FREE(oldmod); + oldmod = mod; + prev = (LTRAinstance *) NULL; + for (here = mod->LTRAinstances; here; here = here->LTRAnextInstance) { + if (prev) + FREE(prev); + prev = here; + } + if (prev) + FREE(prev); + } + if (oldmod) + FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/ltra/ltraext.h b/src/spicelib/devices/ltra/ltraext.h new file mode 100644 index 000000000..5cd0a5625 --- /dev/null +++ b/src/spicelib/devices/ltra/ltraext.h @@ -0,0 +1,83 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#ifdef __STDC__ +extern int LTRAaccept(CKTcircuit*,GENmodel*); +extern int LTRAask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int LTRAacLoad(GENmodel*,CKTcircuit*); +extern int LTRAdelete(GENmodel*,IFuid,GENinstance**); +extern void LTRAdestroy(GENmodel**); +extern int LTRAload(GENmodel*,CKTcircuit*); +extern int LTRAmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int LTRAmDelete(GENmodel**,IFuid,GENmodel*); +extern int LTRAparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int LTRAmParam(int,IFvalue*,GENmodel*); +extern int LTRAsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int LTRAunsetup(GENmodel*,CKTcircuit*); +extern int LTRAtemp(GENmodel*,CKTcircuit*); +extern int LTRAtrunc(GENmodel*,CKTcircuit*,double*); + +extern int LTRAquadInterp(double,double,double,double,double*,double*,double*); +/* +extern double LTRAcoeffSetup(double*,int,double,double,double*,double,double*,int,int*); +extern double LTRAtCoeffSetup(double*,int,double,double*,double,double*,double,double*,int,int*); +extern double LTRAdivDiffs(double*,double*,double,double,double*,int); +*/ +extern double LTRArlcH1dashFunc(double,double,double,double); +extern double LTRArlcH2Func(double,double,double,double); +extern double LTRArlcH3dashFunc(double,double,double,double); +extern double LTRArlcH1dashTwiceIntFunc(double,double); +extern double LTRArlcH3dashIntFunc(double,double,double); +extern double LTRArcH1dashTwiceIntFunc(double,double); +extern double LTRArcH2TwiceIntFunc(double,double); +extern double LTRArcH3dashTwiceIntFunc(double,double,double); +extern double LTRAlteCalculate(CKTcircuit*,GENmodel*,GENinstance*,double); +/* +extern double LTRAh1dashCoeffSetup(double*,int,double,double,double*,int,int*); +extern double LTRAh3dashCoeffSetup(double*,int,double,double,double,double*,int,int*); +*/ +extern void LTRArcCoeffsSetup(double*,double*,double*,double*,double*,double*,int,double,double,double,double*,int,double); +extern void LTRArlcCoeffsSetup(double*,double*,double*,double*,double*,double*,int,double,double,double,double,double*,int,double,int*); +extern int LTRAstraightLineCheck(double,double,double,double,double,double,double,double); +#else /* stdc */ +extern int LTRAaccept(); +extern int LTRAask(); +extern int LTRAacLoad(); +extern int LTRAdelete(); +extern void LTRAdestroy(); +extern int LTRAload(); +extern int LTRAmAsk(); +extern int LTRAmDelete(); +extern int LTRAparam(); +extern int LTRAmParam(); +extern int LTRAsetup(); +extern int LTRAunsetup(); +extern int LTRAtemp(); +extern int LTRAtrunc(); + +extern int LTRAquadInterp(); +/* +extern double LTRAcoeffSetup(); +extern double LTRAtCoeffSetup(); +extern double LTRAdivDiffs(); +*/ +extern double LTRArlcH1dashFunc(); +extern double LTRArlcH2Func(); +extern double LTRArlcH3dashFunc(); +extern double LTRArlcH1dashTwiceIntFunc(); +extern double LTRArlcH3dashIntFunc(); +extern double LTRArcH1dashTwiceIntFunc(); +extern double LTRArcH2TwiceIntFunc(); +extern double LTRArcH3dashTwiceIntFunc(); +extern double LTRAlteCalculate(); +/* +extern double LTRAh1dashCoeffSetup(); +extern double LTRAh3dashCoeffSetup(); +*/ +extern void LTRArcCoeffsSetup(); +extern void LTRArlcCoeffsSetup(); +extern int LTRAstraightLineCheck(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/ltra/ltraitf.h b/src/spicelib/devices/ltra/ltraitf.h new file mode 100644 index 000000000..4e1259d98 --- /dev/null +++ b/src/spicelib/devices/ltra/ltraitf.h @@ -0,0 +1,77 @@ +/********** +Copyright 1990 Regents of the University of California. All rights +reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ +#ifdef DEV_ltra + +#ifndef DEV_LTRA +#define DEV_LTRA + +#include "ltraext.h" +extern IFparm LTRApTable[ ]; +extern IFparm LTRAmPTable[ ]; +extern char *LTRAnames[ ]; +extern int LTRApTSize; +extern int LTRAmPTSize; +extern int LTRAnSize; +extern int LTRAiSize; +extern int LTRAmSize; + +SPICEdev LTRAinfo = { + { "LTRA", + "Lossy transmission line", + + <RAnSize, + <RAnSize, + LTRAnames, + + <RApTSize, + LTRApTable, + + <RAmPTSize, + LTRAmPTable, + 0 + }, + + LTRAparam, + LTRAmParam, + LTRAload, + LTRAsetup, + LTRAunsetup, + LTRAsetup, + LTRAtemp, + LTRAtrunc, + NULL, + LTRAacLoad /*LTRAacLoad*/, + LTRAaccept, + LTRAdestroy, +#ifdef DELETES + LTRAmDelete, + LTRAdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, /* getic */ + LTRAask, + LTRAmAsk, /* */ + NULL, /* pzLoad */ + NULL, /* convTest */ + NULL, /* sSetup */ + NULL, /* sLoad */ + NULL, /* sUpdate */ + NULL, /* sAcLoad */ + NULL, /* sPrint */ + NULL, /* */ + NULL, /* disto */ + NULL, /* noise */ + + <RAiSize, + <RAmSize + +}; + +#endif + +#endif diff --git a/src/spicelib/devices/ltra/ltraload.c b/src/spicelib/devices/ltra/ltraload.c new file mode 100644 index 000000000..d3bd91d1d --- /dev/null +++ b/src/spicelib/devices/ltra/ltraload.c @@ -0,0 +1,855 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ltradefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAload(inModel, ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +/* + * load the appropriate values for the current timepoint into the sparse + * matrix and the right-hand-side vector + */ +{ + register LTRAmodel *model = (LTRAmodel *) inModel; + register LTRAinstance *here; + double t1, t2, t3; + double qf1, qf2, qf3; + double lf2, lf3; + double v1d, v2d, i1d, i2d; + double dummy1, dummy2; + int isaved; + unsigned tdover; + register int i; + double max, min; + + /* loop through all the transmission line models */ + for (; model != NULL; model = model->LTRAnextModel) { + + if (ckt->CKTmode & MODEDC) { + switch (model->LTRAspecialCase) { + + case LTRA_MOD_RG: + dummy1 = model->LTRAlength * sqrt(model->LTRAresist * + model->LTRAconduct); + dummy2 = exp(-dummy1); + dummy1 = exp(dummy1); /* LTRA warning: may overflow! */ + model->LTRAcoshlrootGR = 0.5 * (dummy1 + dummy2); + + if (model->LTRAconduct <= 1.0e-10) { /* hack! */ + model->LTRArRsLrGRorG = model->LTRAlength * + model->LTRAresist; + } else { + model->LTRArRsLrGRorG = 0.5 * (dummy1 - + dummy2) * sqrt(model->LTRAresist / + model->LTRAconduct); + } + + if (model->LTRAresist <= 1.0e-10) { /* hack! */ + model->LTRArGsLrGRorR = model->LTRAlength * + model->LTRAconduct; + } else { + model->LTRArGsLrGRorR = 0.5 * (dummy1 - + dummy2) * sqrt(model->LTRAconduct / + model->LTRAresist); + } + break; + + case LTRA_MOD_RC: + case LTRA_MOD_LC: + case LTRA_MOD_RLC: + + /* simple resistor-like behaviour */ + /* nothing to set up */ + break; + + default: + return (E_BADPARM); + } /* switch */ + } else { + + if ((ckt->CKTmode & MODEINITTRAN) || + (ckt->CKTmode & MODEINITPRED)) { + switch (model->LTRAspecialCase) { + + case LTRA_MOD_RLC: + case LTRA_MOD_LC: + + if (ckt->CKTtime > model->LTRAtd) { + tdover = 1; + } else { + tdover = 0; + } + default: + break; + } + + switch (model->LTRAspecialCase) { + case LTRA_MOD_RLC: + /* + * set up lists of values of the functions at the necessary + * timepoints. + */ + + + /* + * set up coefficient lists LTRAh1dashCoeffs, LTRAh2Coeffs, + * LTRAh3dashCoeffs for current timepoint + */ + + /* + * NOTE: h1, h2 and h3 here actually refer to h1tilde, h2tilde, + * h3tilde in the paper + */ + + /* + * Note: many function evaluations are saved by doing the following + * all together in one procedure + */ + + (void) + LTRArlcCoeffsSetup(&(model->LTRAh1dashFirstCoeff), + &(model->LTRAh2FirstCoeff), + &(model->LTRAh3dashFirstCoeff), + model->LTRAh1dashCoeffs, model->LTRAh2Coeffs, + model->LTRAh3dashCoeffs, model->LTRAmodelListSize, + model->LTRAtd, model->LTRAalpha, model->LTRAbeta, + ckt->CKTtime, ckt->CKTtimePoints, ckt->CKTtimeIndex, + model->LTRAchopReltol, &(model->LTRAauxIndex)); + + + case LTRA_MOD_LC: + + /* setting up the coefficients for interpolation */ + if (tdover) { /* serious hack -fix! */ + for (i = ckt->CKTtimeIndex; i >= 0; i--) { + if (*(ckt->CKTtimePoints + i) < + ckt->CKTtime - model->LTRAtd) { + break; + } + } +#ifdef LTRADEBUG + if (i == ckt->CKTtimeIndex) { + fprintf(stdout, "LTRAload: Warning: timestep larger than delay of line\n"); + fprintf(stdout, " Time now: %g\n\n", ckt->CKTtime); + } +#endif + + if (i == ckt->CKTtimeIndex) + i--; + +#ifdef LTRADEBUG + if ((i == -1)) { + printf("LTRAload: mistake: cannot find delayed timepoint\n"); + } +#else + return E_INTERN; +#endif + + isaved = i; + + t2 = *(ckt->CKTtimePoints + i); + t3 = *(ckt->CKTtimePoints + i + 1); + + if ((i != 0) && ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP))) { + /* quadratic interpolation */ + t1 = *(ckt->CKTtimePoints + i - 1); + + LTRAquadInterp(ckt->CKTtime - model->LTRAtd, + t1, t2, t3, &qf1, &qf2, &qf3); + + } + if ((i == 0) || (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP) || (model->LTRAhowToInterp + == LTRA_MOD_LININTERP)) { /* linear interpolation */ + + LTRAlinInterp(ckt->CKTtime - model->LTRAtd, + t2, t3, &lf2, &lf3); + } + } + /* interpolation coefficients set-up */ + + break; + + case LTRA_MOD_RC: + + /* + * set up lists of values of the coefficients at the necessary + * timepoints. + */ + + + /* + * set up coefficient lists LTRAh1dashCoeffs, LTRAh2Coeffs, + * LTRAh3dashCoeffs for current timepoint + */ + + /* + * Note: many function evaluations are saved by doing the following + * all together in one procedure + */ + + + (void) + LTRArcCoeffsSetup(&(model->LTRAh1dashFirstCoeff), + &(model->LTRAh2FirstCoeff), + &(model->LTRAh3dashFirstCoeff), + model->LTRAh1dashCoeffs, model->LTRAh2Coeffs, + model->LTRAh3dashCoeffs, model->LTRAmodelListSize, + model->LTRAcByR, model->LTRArclsqr, ckt->CKTtime, + ckt->CKTtimePoints, ckt->CKTtimeIndex, model->LTRAchopReltol); + + break; + + case LTRA_MOD_RG: + break; + default: + return (E_BADPARM); + } + } + } + /* loop through all the instances of the model */ + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + if (here->LTRAowner != ARCHme) continue; + + if ((ckt->CKTmode & MODEDC) || + (model->LTRAspecialCase == LTRA_MOD_RG)) { + + switch (model->LTRAspecialCase) { + + case LTRA_MOD_RG: + *(here->LTRAibr1Pos1Ptr) += 1.0; + *(here->LTRAibr1Neg1Ptr) -= 1.0; + *(here->LTRAibr1Pos2Ptr) -= model->LTRAcoshlrootGR; + *(here->LTRAibr1Neg2Ptr) += model->LTRAcoshlrootGR; + *(here->LTRAibr1Ibr2Ptr) += (1 + ckt->CKTgmin) * + model->LTRArRsLrGRorG; + + *(here->LTRAibr2Ibr2Ptr) += model->LTRAcoshlrootGR; + *(here->LTRAibr2Pos2Ptr) -= (1 + ckt->CKTgmin) * + model->LTRArGsLrGRorR; + *(here->LTRAibr2Neg2Ptr) += (1 + ckt->CKTgmin) * + model->LTRArGsLrGRorR; + *(here->LTRAibr2Ibr1Ptr) += 1.0; + + *(here->LTRApos1Ibr1Ptr) += 1.0; + *(here->LTRAneg1Ibr1Ptr) -= 1.0; + *(here->LTRApos2Ibr2Ptr) += 1.0; + *(here->LTRAneg2Ibr2Ptr) -= 1.0; + + here->LTRAinput1 = here->LTRAinput2 = 0.0; + + /* + * Somewhere else, we have fixed the matrix with zero entries so + * that SMPpreOrder doesn't have fits + */ + + break; + + case LTRA_MOD_LC: + case LTRA_MOD_RLC: + case LTRA_MOD_RC: /* load a simple resistor */ + + *(here->LTRApos1Ibr1Ptr) += 1.0; + *(here->LTRAneg1Ibr1Ptr) -= 1.0; + *(here->LTRApos2Ibr2Ptr) += 1.0; + *(here->LTRAneg2Ibr2Ptr) -= 1.0; + + *(here->LTRAibr1Ibr1Ptr) += 1.0; + *(here->LTRAibr1Ibr2Ptr) += 1.0; + *(here->LTRAibr2Pos1Ptr) += 1.0; + *(here->LTRAibr2Pos2Ptr) -= 1.0; + *(here->LTRAibr2Ibr1Ptr) -= model->LTRAresist * model->LTRAlength; + + here->LTRAinput1 = here->LTRAinput2 = 0.0; + break; + + + default: + return (E_BADPARM); + } + + } else { + /* all cases other than DC or the RG case */ + + /* first timepoint after zero */ + if (ckt->CKTmode & MODEINITTRAN) { + if (!(ckt->CKTmode & MODEUIC)) { + + here->LTRAinitVolt1 = + (*(ckt->CKTrhsOld + here->LTRAposNode1) + - *(ckt->CKTrhsOld + here->LTRAnegNode1)); + here->LTRAinitVolt2 = + (*(ckt->CKTrhsOld + here->LTRAposNode2) + - *(ckt->CKTrhsOld + here->LTRAnegNode2)); + here->LTRAinitCur1 = *(ckt->CKTrhsOld + here->LTRAbrEq1); + here->LTRAinitCur2 = *(ckt->CKTrhsOld + here->LTRAbrEq2); + } + } + /* matrix loading - done every time LTRAload is called */ + switch (model->LTRAspecialCase) { + + case LTRA_MOD_RLC: + /* loading for convolution parts' first terms */ + + dummy1 = model->LTRAadmit * model->LTRAh1dashFirstCoeff; + *(here->LTRAibr1Pos1Ptr) += dummy1; + *(here->LTRAibr1Neg1Ptr) -= dummy1; + *(here->LTRAibr2Pos2Ptr) += dummy1; + *(here->LTRAibr2Neg2Ptr) -= dummy1; + /* end loading for convolution parts' first terms */ + + case LTRA_MOD_LC: + /* + * this section loads for the parts of the equations that resemble + * the lossless equations + */ + + *(here->LTRAibr1Pos1Ptr) += model->LTRAadmit; + *(here->LTRAibr1Neg1Ptr) -= model->LTRAadmit; + *(here->LTRAibr1Ibr1Ptr) -= 1.0; + *(here->LTRApos1Ibr1Ptr) += 1.0; + *(here->LTRAneg1Ibr1Ptr) -= 1.0; + + *(here->LTRAibr2Pos2Ptr) += model->LTRAadmit; + *(here->LTRAibr2Neg2Ptr) -= model->LTRAadmit; + *(here->LTRAibr2Ibr2Ptr) -= 1.0; + *(here->LTRApos2Ibr2Ptr) += 1.0; + *(here->LTRAneg2Ibr2Ptr) -= 1.0; + + /* loading for lossless-like parts over */ + break; + + case LTRA_MOD_RC: + + /* + * this section loads for the parts of the equations that have no + * convolution + */ + + *(here->LTRAibr1Ibr1Ptr) -= 1.0; + *(here->LTRApos1Ibr1Ptr) += 1.0; + *(here->LTRAneg1Ibr1Ptr) -= 1.0; + + *(here->LTRAibr2Ibr2Ptr) -= 1.0; + *(here->LTRApos2Ibr2Ptr) += 1.0; + *(here->LTRAneg2Ibr2Ptr) -= 1.0; + + /* loading for non-convolution parts over */ + /* loading for convolution parts' first terms */ + + dummy1 = model->LTRAh1dashFirstCoeff; + *(here->LTRAibr1Pos1Ptr) += dummy1; + *(here->LTRAibr1Neg1Ptr) -= dummy1; + *(here->LTRAibr2Pos2Ptr) += dummy1; + *(here->LTRAibr2Neg2Ptr) -= dummy1; + + dummy1 = model->LTRAh2FirstCoeff; + *(here->LTRAibr1Ibr2Ptr) -= dummy1; + *(here->LTRAibr2Ibr1Ptr) -= dummy1; + + dummy1 = model->LTRAh3dashFirstCoeff; + *(here->LTRAibr1Pos2Ptr) -= dummy1; + *(here->LTRAibr1Neg2Ptr) += dummy1; + *(here->LTRAibr2Pos1Ptr) -= dummy1; + *(here->LTRAibr2Neg1Ptr) += dummy1; + + /* end loading for convolution parts' first terms */ + + + break; + default: + return (E_BADPARM); + } + + + /* INITPRED - first NR iteration of each timepoint */ + /* set up LTRAinputs - to go into the RHS of the circuit equations */ + + if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) { + + here->LTRAinput1 = here->LTRAinput2 = 0.0; + + switch (model->LTRAspecialCase) { + + case LTRA_MOD_LC: + case LTRA_MOD_RLC: + + if (tdover) { + /* have to interpolate values */ + + if ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP))) { + + v1d = *(here->LTRAv1 + isaved - 1) * qf1 + + *(here->LTRAv1 + isaved) * qf2 + + *(here->LTRAv1 + isaved + 1) * qf3; + + max = MAX(*(here->LTRAv1 + isaved - 1), + *(here->LTRAv1 + isaved)); + max = MAX(max, *(here->LTRAv1 + isaved + 1)); + min = MIN(*(here->LTRAv1 + isaved - 1), + *(here->LTRAv1 + isaved)); + min = MIN(min, *(here->LTRAv1 + isaved + 1)); + + } + if ((model->LTRAhowToInterp == + LTRA_MOD_LININTERP) || (isaved == 0) || + ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP)) && + ((v1d > max) || (v1d < min)))) { + + + if ((isaved != 0) && + (model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP)) { +#ifdef LTRADEBUG + fprintf(stdout, "LTRAload: warning: interpolated v1 is out of range after timepoint %d\n", ckt->CKTtimeIndex); + fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n", + *(here->LTRAv1 + isaved - 1), + *(here->LTRAv1 + isaved), + *(here->LTRAv1 + isaved + 1), + v1d); + fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd); +#endif + } else { + + v1d = *(here->LTRAv1 + isaved) * lf2 + + *(here->LTRAv1 + isaved + 1) * + lf3; + } + + } + if ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP))) { + + i1d = *(here->LTRAi1 + isaved - 1) * qf1 + + *(here->LTRAi1 + isaved) * qf2 + + *(here->LTRAi1 + isaved + 1) * qf3; + + max = MAX(*(here->LTRAi1 + isaved - 1), + *(here->LTRAi1 + isaved)); + max = MAX(max, *(here->LTRAi1 + isaved + 1)); + min = MIN(*(here->LTRAi1 + isaved - 1), + *(here->LTRAi1 + isaved)); + min = MIN(min, *(here->LTRAi1 + isaved + 1)); + + } + if ((model->LTRAhowToInterp == + LTRA_MOD_LININTERP) || (isaved == 0) || + ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP)) && + ((i1d > max) || (i1d < min)))) { + + + if ((isaved != 0) && + (model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP)) { +#ifdef LTRADEBUG + fprintf(stdout, "LTRAload: warning: interpolated i1 is out of range after timepoint %d\n", ckt->CKTtimeIndex); + fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n", + *(here->LTRAi1 + isaved - 1), + *(here->LTRAi1 + isaved), + *(here->LTRAi1 + isaved + 1), + i1d); + fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd); +#endif + } else { + + i1d = *(here->LTRAi1 + isaved) * lf2 + + *(here->LTRAi1 + isaved + 1) * + lf3; + } + + } + if ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP))) { + + v2d = *(here->LTRAv2 + isaved - 1) * qf1 + + *(here->LTRAv2 + isaved) * qf2 + + *(here->LTRAv2 + isaved + 1) * qf3; + + max = MAX(*(here->LTRAv2 + isaved - 1), + *(here->LTRAv2 + isaved)); + max = MAX(max, *(here->LTRAv2 + isaved + 1)); + min = MIN(*(here->LTRAv2 + isaved - 1), + *(here->LTRAv2 + isaved)); + min = MIN(min, *(here->LTRAv2 + isaved + 1)); + + } + if ((model->LTRAhowToInterp == + LTRA_MOD_LININTERP) || (isaved == 0) || + ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP)) && + ((v2d > max) || (v2d < min)))) { + + + if ((isaved != 0) && + (model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP)) { +#ifdef LTRADEBUG + fprintf(stdout, "LTRAload: warning: interpolated v2 is out of range after timepoint %d\n", ckt->CKTtimeIndex); + fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n", + *(here->LTRAv2 + isaved - 1), + *(here->LTRAv2 + isaved), + *(here->LTRAv2 + isaved + 1), + v2d); + fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd); +#endif + } else { + + v2d = *(here->LTRAv2 + isaved) * lf2 + + *(here->LTRAv2 + isaved + 1) * + lf3; + } + + } + if ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP))) { + + i2d = *(here->LTRAi2 + isaved - 1) * qf1 + + *(here->LTRAi2 + isaved) * qf2 + + *(here->LTRAi2 + isaved + 1) * qf3; + + max = MAX(*(here->LTRAi2 + isaved - 1), + *(here->LTRAi2 + isaved)); + max = MAX(max, *(here->LTRAi2 + isaved + 1)); + min = MIN(*(here->LTRAi2 + isaved - 1), + *(here->LTRAi2 + isaved)); + min = MIN(min, *(here->LTRAi2 + isaved + 1)); + + } + if ((model->LTRAhowToInterp == + LTRA_MOD_LININTERP) || (isaved == 0) || + ((isaved != 0) && + ((model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP) || + (model->LTRAhowToInterp == + LTRA_MOD_MIXEDINTERP)) && + ((i2d > max) || (i2d < min)))) { + + + if ((isaved != 0) && + (model->LTRAhowToInterp == + LTRA_MOD_QUADINTERP)) { +#ifdef LTRADEBUG + fprintf(stdout, "LTRAload: warning: interpolated i2 is out of range after timepoint %d\n", ckt->CKTtimeIndex); + fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n", + *(here->LTRAi2 + isaved - 1), + *(here->LTRAi2 + isaved), + *(here->LTRAi2 + isaved + 1), + i2d); + fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd); +#endif + } else { + + i2d = *(here->LTRAi2 + isaved) * lf2 + + *(here->LTRAi2 + isaved + 1) * + lf3; + } + + } + } + /* interpolation done */ + break; + + case LTRA_MOD_RC: + break; + + default: + return (E_BADPARM); + } + + switch (model->LTRAspecialCase) { + case LTRA_MOD_RLC: + + /* begin convolution parts */ + + /* convolution of h1dash with v1 and v2 */ + /* the matrix has already been loaded above */ + + dummy1 = dummy2 = 0.0; + for (i = /* model->LTRAh1dashIndex */ ckt->CKTtimeIndex; i > 0; i--) { + if (*(model->LTRAh1dashCoeffs + i) != 0.0) { + dummy1 += *(model->LTRAh1dashCoeffs + + i) * (*(here->LTRAv1 + i) - + here->LTRAinitVolt1); + dummy2 += *(model->LTRAh1dashCoeffs + + i) * (*(here->LTRAv2 + i) - + here->LTRAinitVolt2); + } + } + + dummy1 += here->LTRAinitVolt1 * + model->LTRAintH1dash; + dummy2 += here->LTRAinitVolt2 * + model->LTRAintH1dash; + + dummy1 -= here->LTRAinitVolt1 * + model->LTRAh1dashFirstCoeff; + dummy2 -= here->LTRAinitVolt2 * + model->LTRAh1dashFirstCoeff; + + here->LTRAinput1 -= dummy1 * model->LTRAadmit; + here->LTRAinput2 -= dummy2 * model->LTRAadmit; + + /* end convolution of h1dash with v1 and v2 */ + + /* convolution of h2 with i2 and i1 */ + + dummy1 = dummy2 = 0.0; + if (tdover) { + + /* the term for ckt->CKTtime - model->LTRAtd */ + + dummy1 = (i2d - here->LTRAinitCur2) * + model->LTRAh2FirstCoeff; + dummy2 = (i1d - here->LTRAinitCur1) * + model->LTRAh2FirstCoeff; + + /* the rest of the convolution */ + + for (i = /* model->LTRAh2Index */ model->LTRAauxIndex; i > 0; i--) { + + if (*(model->LTRAh2Coeffs + i) != 0.0) { + dummy1 += *(model->LTRAh2Coeffs + + i) * (*(here->LTRAi2 + i) - + here->LTRAinitCur2); + dummy2 += *(model->LTRAh2Coeffs + + i) * (*(here->LTRAi1 + i) - + here->LTRAinitCur1); + } + } + } + /* the initial-condition terms */ + + dummy1 += here->LTRAinitCur2 * + model->LTRAintH2; + dummy2 += here->LTRAinitCur1 * + model->LTRAintH2; + + here->LTRAinput1 += dummy1; + here->LTRAinput2 += dummy2; + + /* end convolution of h2 with i2 and i1 */ + + /* convolution of h3dash with v2 and v1 */ + + /* the term for ckt->CKTtime - model->LTRAtd */ + + dummy1 = dummy2 = 0.0; + if (tdover) { + + dummy1 = (v2d - here->LTRAinitVolt2) * + model->LTRAh3dashFirstCoeff; + dummy2 = (v1d - here->LTRAinitVolt1) * + model->LTRAh3dashFirstCoeff; + + /* the rest of the convolution */ + + for (i = /* model->LTRAh3dashIndex */ model->LTRAauxIndex; i > 0; i--) { + if (*(model->LTRAh3dashCoeffs + i) != 0.0) { + dummy1 += *(model->LTRAh3dashCoeffs + + i) * (*(here->LTRAv2 + i) - + here->LTRAinitVolt2); + dummy2 += *(model->LTRAh3dashCoeffs + + i) * (*(here->LTRAv1 + i) - + here->LTRAinitVolt1); + } + } + } + /* the initial-condition terms */ + + dummy1 += here->LTRAinitVolt2 * + model->LTRAintH3dash; + dummy2 += here->LTRAinitVolt1 * + model->LTRAintH3dash; + + here->LTRAinput1 += model->LTRAadmit * dummy1; + here->LTRAinput2 += model->LTRAadmit * dummy2; + + /* end convolution of h3dash with v2 and v1 */ + + case LTRA_MOD_LC: + /* begin lossless-like parts */ + + if (!tdover) { + + here->LTRAinput1 += model->LTRAattenuation * + (here->LTRAinitVolt2 * model->LTRAadmit + + here->LTRAinitCur2); + here->LTRAinput2 += model->LTRAattenuation * + (here->LTRAinitVolt1 * model->LTRAadmit + + here->LTRAinitCur1); + + } else { + + here->LTRAinput1 += model->LTRAattenuation * + (v2d * model->LTRAadmit + i2d); + here->LTRAinput2 += model->LTRAattenuation * + (v1d * model->LTRAadmit + i1d); + + } + + /* end lossless-like parts */ + break; + + case LTRA_MOD_RC: + + + /* begin convolution parts */ + + /* convolution of h1dash with v1 and v2 */ + /* the matrix has already been loaded above */ + + dummy1 = 0.0; + dummy2 = 0.0; + for (i = ckt->CKTtimeIndex; i > 0; i--) { + if (*(model->LTRAh1dashCoeffs + i) != 0.0) { + dummy1 += *(model->LTRAh1dashCoeffs + + i) * (*(here->LTRAv1 + i) - + here->LTRAinitVolt1); + dummy2 += *(model->LTRAh1dashCoeffs + + i) * (*(here->LTRAv2 + i) - + here->LTRAinitVolt2); + } + } + + /* the initial condition terms */ + + dummy1 += here->LTRAinitVolt1 * + model->LTRAintH1dash; + dummy2 += here->LTRAinitVolt2 * + model->LTRAintH1dash; + + /* + * the constant contributed by the init condition and the latest + * timepoint + */ + + dummy1 -= here->LTRAinitVolt1 * + model->LTRAh1dashFirstCoeff; + dummy2 -= here->LTRAinitVolt2 * + model->LTRAh1dashFirstCoeff; + + here->LTRAinput1 -= dummy1; + here->LTRAinput2 -= dummy2; + + /* end convolution of h1dash with v1 and v2 */ + + + /* convolution of h2 with i2 and i1 */ + + dummy1 = dummy2 = 0.0; + + for (i = ckt->CKTtimeIndex; i > 0; i--) { + if (*(model->LTRAh2Coeffs + i) != 0.0) { + dummy1 += *(model->LTRAh2Coeffs + + i) * (*(here->LTRAi2 + i) - + here->LTRAinitCur2); + dummy2 += *(model->LTRAh2Coeffs + + i) * (*(here->LTRAi1 + i) - + here->LTRAinitCur1); + } + } + + /* the initial-condition terms */ + + dummy1 += here->LTRAinitCur2 * + model->LTRAintH2; + dummy2 += here->LTRAinitCur1 * + model->LTRAintH2; + + dummy1 -= here->LTRAinitCur2 * + model->LTRAh2FirstCoeff; + dummy2 -= here->LTRAinitCur1 * + model->LTRAh2FirstCoeff; + + here->LTRAinput1 += dummy1; + here->LTRAinput2 += dummy2; + + /* end convolution of h2 with i2 and i1 */ + + /* convolution of h3dash with v2 and v1 */ + + + dummy1 = dummy2 = 0.0; + + + for (i = ckt->CKTtimeIndex; i > 0; i--) { + if (*(model->LTRAh3dashCoeffs + i) != 0.0) { + dummy1 += *(model->LTRAh3dashCoeffs + + i) * (*(here->LTRAv2 + i) - + here->LTRAinitVolt2); + dummy2 += *(model->LTRAh3dashCoeffs + + i) * (*(here->LTRAv1 + i) - + here->LTRAinitVolt1); + } + } + + /* the initial-condition terms */ + + dummy1 += here->LTRAinitVolt2 * + model->LTRAintH3dash; + dummy2 += here->LTRAinitVolt1 * + model->LTRAintH3dash; + + dummy1 -= here->LTRAinitVolt2 * + model->LTRAh3dashFirstCoeff; + dummy2 -= here->LTRAinitVolt1 * + model->LTRAh3dashFirstCoeff; + + here->LTRAinput1 += dummy1; + here->LTRAinput2 += dummy2; + + /* end convolution of h3dash with v2 and v1 */ + + break; + + default: + return (E_BADPARM); + } + } + /* load the RHS - done every time this routine is called */ + + *(ckt->CKTrhs + here->LTRAbrEq1) += here->LTRAinput1; + *(ckt->CKTrhs + here->LTRAbrEq2) += here->LTRAinput2; + + } + } + } + return (OK); +} diff --git a/src/spicelib/devices/ltra/ltramask.c b/src/spicelib/devices/ltra/ltramask.c new file mode 100644 index 000000000..c6a468f8a --- /dev/null +++ b/src/spicelib/devices/ltra/ltramask.c @@ -0,0 +1,113 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +/* + * This routine sets model parameters for LTRA lines in the circuit. + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAmAsk(ckt, inModel, param, value) + CKTcircuit *ckt; + GENmodel *inModel; + int param; + IFvalue *value; +{ + LTRAmodel *mods = (LTRAmodel *) inModel; + + switch (param) { + case LTRA_MOD_LTRA: + value->iValue = 1; + break; + case LTRA_MOD_RELTOL: + value->rValue = mods->LTRAreltol; + break; + case LTRA_MOD_ABSTOL: + value->rValue = mods->LTRAabstol; + break; + case LTRA_MOD_STLINEREL: + value->rValue = mods->LTRAstLineReltol; + break; + case LTRA_MOD_STLINEABS: + value->rValue = mods->LTRAstLineAbstol; + break; + case LTRA_MOD_CHOPREL: + value->rValue = mods->LTRAchopReltol; + break; + case LTRA_MOD_CHOPABS: + value->rValue = mods->LTRAchopAbstol; + break; + case LTRA_MOD_TRUNCNR: + value->iValue = mods->LTRAtruncNR; + break; + case LTRA_MOD_TRUNCDONTCUT: + value->iValue = mods->LTRAtruncDontCut; + break; + case LTRA_MOD_R: + value->rValue = mods->LTRAresist; + break; + case LTRA_MOD_L: + value->rValue = mods->LTRAinduct; + break; + case LTRA_MOD_G: + value->rValue = mods->LTRAconduct; + break; + case LTRA_MOD_C: + value->rValue = mods->LTRAcapac; + break; + case LTRA_MOD_LEN: + value->rValue = mods->LTRAlength; + break; + case LTRA_MOD_NL: + value->rValue = mods->LTRAnl; + break; + case LTRA_MOD_FREQ: + value->rValue = mods->LTRAf; + break; + case LTRA_MOD_FULLCONTROL: + value->iValue = mods->LTRAlteConType; + break; + case LTRA_MOD_HALFCONTROL: + value->iValue = mods->LTRAlteConType; + break; + case LTRA_MOD_NOCONTROL: + value->iValue = mods->LTRAlteConType; + break; + case LTRA_MOD_PRINT: + value->iValue = mods->LTRAprintFlag; + break; + case LTRA_MOD_NOPRINT: + mods->LTRAprintFlag = FALSE; + break; + /* + * case LTRA_MOD_RONLY: mods->LTRArOnly= TRUE; break; + */ + case LTRA_MOD_STEPLIMIT: + value->iValue = mods->LTRAstepLimit; + break; + case LTRA_MOD_NOSTEPLIMIT: + value->iValue = mods->LTRAstepLimit; + break; + case LTRA_MOD_LININTERP: + value->iValue = mods->LTRAhowToInterp; + break; + case LTRA_MOD_QUADINTERP: + value->iValue = mods->LTRAhowToInterp; + break; + case LTRA_MOD_MIXEDINTERP: + value->iValue = mods->LTRAhowToInterp; + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/ltra/ltramdel.c b/src/spicelib/devices/ltra/ltramdel.c new file mode 100644 index 000000000..da31773a7 --- /dev/null +++ b/src/spicelib/devices/ltra/ltramdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAmDelete(inModel, modname, kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + LTRAmodel **model = (LTRAmodel **) inModel; + LTRAmodel *modfast = (LTRAmodel *) kill; + LTRAinstance *here; + LTRAinstance *prev = NULL; + LTRAmodel **oldmod; + oldmod = model; + for (; *model; model = &((*model)->LTRAnextModel)) { + if ((*model)->LTRAmodName == modname || + (modfast && *model == modfast)) + goto delgot; + oldmod = model; + } + return (E_NOMOD); + +delgot: + *oldmod = (*model)->LTRAnextModel; /* cut deleted device out of list */ + for (here = (*model)->LTRAinstances; here; here = here->LTRAnextInstance) { + if (prev) + FREE(prev); + prev = here; + } + if (prev) + FREE(prev); + FREE(*model); + return (OK); + +} diff --git a/src/spicelib/devices/ltra/ltramisc.c b/src/spicelib/devices/ltra/ltramisc.c new file mode 100644 index 000000000..5085660e2 --- /dev/null +++ b/src/spicelib/devices/ltra/ltramisc.c @@ -0,0 +1,1758 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include "ltradefs.h" +#include "suffix.h" + +/* + * Miscellaneous functions to do with lossy lines + */ + +/* + * LTRAquadInterp - quadratic interpolation function t = timepoint where + * value wanted t1, t2, t3 are three timepoints where the value is known c1, + * c2, c3 are set to the proper coefficients by the function the interpolated + * value is c1*v1 + c2*v2 + c3*v3; this should be done in the calling + * program; (v1,v2,v3 are the known values at t1,t2,t3) + */ + + +int +LTRAquadInterp(t, t1, t2, t3, c1, c2, c3) + double t, t1, t2, t3; + double *c1, *c2, *c3; +{ + double f1, f2, f3; + + if (t == t1) { + *c1 = 1.0; + *c2 = 0.0; + *c3 = 0.0; + return (0); + } + if (t == t2) { + *c1 = 0.0; + *c2 = 1.0; + *c3 = 0.0; + return (0); + } + if (t == t3) { + *c1 = 0.0; + *c2 = 0.0; + *c3 = 1.0; + return (0); + } + if ((t2 - t1) == 0 || (t3 - t2) == 0 || (t1 - t3) == 0) + return (1); + + f1 = (t - t2) * (t - t3); + f2 = (t - t1) * (t - t3); + f3 = (t - t1) * (t - t2); + if ((t2 - t1) == 0) { /* should never happen, but don't want to + * divide by zero, EVER... */ + f1 = 0; + f2 = 0; + } else { + f1 /= (t1 - t2); + f2 /= (t2 - t1); + } + if ((t3 - t2) == 0) { /* should never happen, but don't want to + * divide by zero, EVER... */ + f2 = 0; + f3 = 0; + } else { + f2 /= (t2 - t3); + f3 /= (t2 - t3); + } + if ((t3 - t1) == 0) { /* should never happen, but don't want to + * divide by zero, EVER... */ + f1 = 0; + f2 = 0; + } else { + f1 /= (t1 - t3); + f3 /= (t1 - t3); + } + *c1 = f1; + *c2 = f2; + *c3 = f3; + return (0); +} + +/* linear interpolation */ + +int +LTRAlinInterp(t, t1, t2, c1, c2) + double t, t1, t2; + double *c1, *c2; + +{ + double temp; + + if (t1 == t2) + return (1); + + if (t == t1) { + *c1 = 1.0; + *c2 = 0.0; + return (0); + } + if (t == t2) { + *c1 = 0.0; + *c2 = 1.0; + return (0); + } + temp = (t - t1) / (t2 - t1); + *c2 = temp; + *c1 = 1 - temp; + return (0); +} + +/* + * intlinfunc returns \int_lolimit^hilimit h(\tau) d \tau, where h(\tau) is + * assumed to be linear, with values lovalue and hivalue \tau = t1 and t2 + * respectively this is used only locally + */ + +double +intlinfunc(lolimit, hilimit, lovalue, hivalue, t1, t2) + double lolimit, hilimit, lovalue, hivalue, t1, t2; +{ + double width, m; + + + width = t2 - t1; + if (width == 0.0) + return (0.0); + m = (hivalue - lovalue) / width; + + return ((hilimit - lolimit) * lovalue + 0.5 * m * ((hilimit - t1) * (hilimit - t1) + - (lolimit - t1) * (lolimit - t1))); +} + + +/* + * twiceintlinfunc returns \int_lolimit^hilimit \int_otherlolimit^\tau + * h(\tau') d \tau' d \tau , where h(\tau') is assumed to be linear, with + * values lovalue and hivalue \tau = t1 and t2 respectively this is used only + * locally + */ + +double +twiceintlinfunc(lolimit, hilimit, otherlolimit, lovalue, hivalue, t1, t2) + double lolimit, hilimit, lovalue, hivalue, t1, t2, otherlolimit; +{ + double width, m, dummy; + double temp1, temp2, temp3; + + + width = t2 - t1; + if (width == 0.0) + return (0.0); + m = (hivalue - lovalue) / width; + + temp1 = hilimit - t1; + temp2 = lolimit - t1; + temp3 = otherlolimit - t1; + dummy = lovalue * ((hilimit - otherlolimit) * (hilimit - otherlolimit) - + (lolimit - otherlolimit) * (lolimit - otherlolimit)); + dummy += m * ((temp1 * temp1 * temp1 - temp2 * temp2 * temp2) / 3.0 - + temp3 * temp3 * (hilimit - lolimit)); + return (dummy * 0.5); +} + +/* + * thriceintlinfunc returns \int_lolimit^hilimit \int_secondlolimit^\tau + * \int_thirdlolimit^\tau' h(\tau'') d \tau'' d \tau' d \tau , where + * h(\tau'') is assumed to be linear, with values lovalue and hivalue \tau = + * t1 and t2 respectively this is used only locally + */ + +double +thriceintlinfunc(lolimit, hilimit, secondlolimit, thirdlolimit, lovalue, + hivalue, t1, t2) + double lolimit, hilimit, lovalue, hivalue, t1, t2, secondlolimit, thirdlolimit; +{ + double width, m, dummy; + double temp1, temp2, temp3, temp4; + double temp5, temp6, temp7, temp8, temp9, temp10; + + + width = t2 - t1; + if (width == 0.0) + return (0.0); + m = (hivalue - lovalue) / width; + + temp1 = hilimit - t1; + temp2 = lolimit - t1; + temp3 = secondlolimit - t1; + temp4 = thirdlolimit - t1; + temp5 = hilimit - thirdlolimit; + temp6 = lolimit - thirdlolimit; + temp7 = secondlolimit - thirdlolimit; + temp8 = hilimit - lolimit; + temp9 = hilimit - secondlolimit; + temp10 = lolimit - secondlolimit; + dummy = lovalue * ((temp5 * temp5 * temp5 - temp6 * temp6 * temp6) / 3 - + temp7 * temp5 * temp8); + dummy += m * (((temp1 * temp1 * temp1 * temp1 - temp2 * temp2 * temp2 * temp2) * 0.25 - + temp3 * temp3 * temp3 * temp8) / 3 - temp4 * temp4 * 0.5 * (temp9 * temp9 - + temp10 * temp10)); + return (dummy * 0.5); +} + + +/* + * These are from the book Numerical Recipes in C + * + */ + +double +bessI0(x) + double x; +{ + double ax, ans; + double y; + + if ((ax = fabs(x)) < 3.75) { + y = x / 3.75; + y *= y; + ans = 1.0 + y * (3.5156229 + y * (3.0899424 + y * (1.2067492 + + y * (0.2659732 + y * (0.360768e-1 + y * 0.45813e-2))))); + } else { + y = 3.75 / ax; + ans = (exp(ax) / sqrt(ax)) * (0.39894228 + y * (0.1328592e-1 + + y * (0.225319e-2 + y * (-0.157565e-2 + y * (0.916281e-2 + + y * (-0.2057706e-1 + y * (0.2635537e-1 + y * (-0.1647633e-1 + + y * 0.392377e-2)))))))); + } + return (ans); +} + +double +bessI1(x) + double x; +{ + double ax, ans; + double y; + + if ((ax = fabs(x)) < 3.75) { + y = x / 3.75; + y *= y; + ans = ax * (0.5 + y * (0.87890594 + y * (0.51498869 + y * (0.15084934 + + y * (0.2658733e-1 + y * (0.301532e-2 + y * 0.32411e-3)))))); + } else { + y = 3.75 / ax; + ans = 0.2282967e-1 + y * (-0.2895312e-1 + y * (0.1787654e-1 + - y * 0.420059e-2)); + ans = 0.39894228 + y * (-0.3988024e-1 + y * (-0.362018e-2 + + y * (0.163801e-2 + y * (-0.1031555e-1 + y * ans)))); + ans *= (exp(ax) / sqrt(ax)); + } + return (x < 0.0 ? -ans : ans); +} + +double +bessI1xOverX(x) + double x; +{ + double ax, ans; + double y; + + if ((ax = fabs(x)) < 3.75) { + y = x / 3.75; + y *= y; + ans = 0.5 + y * (0.87890594 + y * (0.51498869 + y * (0.15084934 + + y * (0.2658733e-1 + y * (0.301532e-2 + y * 0.32411e-3))))); + } else { + y = 3.75 / ax; + ans = 0.2282967e-1 + y * (-0.2895312e-1 + y * (0.1787654e-1 + - y * 0.420059e-2)); + ans = 0.39894228 + y * (-0.3988024e-1 + y * (-0.362018e-2 + + y * (0.163801e-2 + y * (-0.1031555e-1 + y * ans)))); + ans *= (exp(ax) / (ax * sqrt(ax))); + } + return (ans); +} + +/* LTRArlcH1dashFunc - the first impulse response function */ + +double +LTRArlcH1dashFunc(time, T, alpha, beta) + double time, T, alpha, beta; + +{ + double besselarg, exparg, returnval; + /* T is not used in this function */ + + /* + * result = alpha * e^{- beta*time} * {I_1(alpha*time) - I_0(alpha*time)} + */ + + if (alpha == 0.0) + return (0.0); + + exparg = -beta * time; + besselarg = alpha * time; + + returnval = (bessI1(besselarg) - bessI0(besselarg)) * alpha * exp(exparg); + return (returnval); +} + +double +LTRArlcH2Func(time, T, alpha, beta) + double time, T, alpha, beta; + +{ + double besselarg, exparg, returnval; + + /* + * result = 0, time < T = (alpha*T*e^{-beta*time})/sqrt(t^2 - T^2) * + * I_1(alpha*sqrt(t^2 - T^2)), time >= T + */ + + if (alpha == 0.0) + return (0.0); + if (time < T) + return (0.0); + + if (time != T) { + besselarg = alpha * sqrt(time * time - T * T); + } else { + besselarg = 0.0; + } + exparg = -beta * time; + + returnval = alpha * alpha * T * exp(exparg) * bessI1xOverX(besselarg); + return (returnval); +} + +double +LTRArlcH3dashFunc(time, T, alpha, beta) + double time, T, alpha, beta; + +{ + double exparg, besselarg, returnval; + + /* + * result = 0, time < T = alpha*e^{-beta*time}*(t/sqrt(t^2-T^2)* + * I_1(alpha*sqrt(t^2-T^2)) - I_0(alpha*sqrt(t^2-T^2))) + */ + + if (alpha == 0.0) + return (0.0); + if (time < T) + return (0.0); + + exparg = -beta * time; + if (time != T) { + besselarg = alpha * sqrt(time * time - T * T); + } else { + besselarg = 0.0; + } + + returnval = alpha * time * bessI1xOverX(besselarg) - bessI0(besselarg); + returnval *= alpha * exp(exparg); + return (returnval); +} + +/* + * LTRArlcH1dashTwiceIntFunc - twice repeated integral of h1dash for the + * special case of G = 0 + */ + +double +LTRArlcH1dashTwiceIntFunc(time, beta) + double time, beta; +{ + double arg, returnval; + + /* + * result = time * e^{- beta*time} * {I_0(beta*time) + I_1(beta*time)} - + * time + */ + + if (beta == 0.0) + return (time); + arg = beta * time; + if (arg == 0.0) + return (0.0); + + returnval = (bessI1(arg) + bessI0(arg)) * time * exp(-arg) - time; + return (returnval); +} + +/* + * LTRArlcH3dashIntFunc - twice repeated integral of h1dash for the special + * case of G = 0 + */ + +double +LTRArlcH3dashIntFunc(time, T, beta) + double time, T, beta; + +{ + double exparg, besselarg; + double returnval; + + if (time <= T) + return (0.0); + if (beta == 0.0) + return (0.0); + exparg = -beta * time; + besselarg = beta * sqrt(time * time - T * T); + returnval = exp(exparg) * bessI0(besselarg) - exp(-beta * T); + return (returnval); +} + + +double +LTRArcH1dashTwiceIntFunc(time, cbyr) + double time, cbyr; +{ + + return (sqrt(4 * cbyr * time / M_PI)); +} + + + + +double +LTRArcH2TwiceIntFunc(time, rclsqr) + double time, rclsqr; +{ + double temp; + + if (time != 0.0) { + temp = rclsqr / (4 * time); + return ((time + rclsqr * 0.5) * erfc(sqrt(temp)) - sqrt(time * rclsqr / M_PI) * exp(-temp)); + } else { + return (0.0); + } +} + + + +double +LTRArcH3dashTwiceIntFunc(time, cbyr, rclsqr) + double time, cbyr, rclsqr; +{ + double temp; + + if (time != 0.0) { + temp = rclsqr / (4 * time); + temp = 2 * sqrt(time / M_PI) * exp(-temp) - sqrt(rclsqr) * erfc(sqrt(temp)); + return (sqrt(cbyr) * temp); + } else { + return (0.0); + } +} + + +/* + * LTRArcCoeffsSetup sets up the all coefficient lists for the special case + * where L=G=0 + */ + +void +LTRArcCoeffsSetup(h1dashfirstcoeff, h2firstcoeff, h3dashfirstcoeff, h1dashcoeffs, h2coeffs, h3dashcoeffs, listsize, cbyr, rclsqr, curtime, timelist, timeindex, reltol) + double *h1dashcoeffs, *h2coeffs, *h3dashcoeffs, *timelist; + int listsize, timeindex; + double cbyr, rclsqr, curtime, *h1dashfirstcoeff, *h2firstcoeff, *h3dashfirstcoeff; + double reltol; + +{ + double delta1, delta2; + double h1dummy1, h1dummy2; + double h2dummy1, h2dummy2; + double h3dummy1, h3dummy2; + double lolimit1, lolimit2, hilimit1, hilimit2; + double h1lovalue1, h1lovalue2, h1hivalue1, h1hivalue2; + double h2lovalue1, h2lovalue2, h2hivalue1, h2hivalue2; + double h3lovalue1, h3lovalue2, h3hivalue1, h3hivalue2; + double temp, temp2, temp3, temp4, temp5; + double h1relval, h2relval, h3relval; + int doh1 = 1, doh2 = 1, doh3 = 1; + int i, auxindex; + + /* coefflists should already have been allocated to the necessary size */ + +#ifdef LTRAdebug + if (listsize <= timeindex) { + printf("LTRAcoeffSetup: not enough space in coefflist\n"); + } +#endif + + + + auxindex = timeindex; + + /* the first coefficients */ + + delta1 = curtime - *(timelist + auxindex); + lolimit1 = 0.0; + hilimit1 = delta1; + + h1lovalue1 = 0.0; + h1hivalue1 = /* LTRArcH1dashTwiceIntFunc(hilimit1,cbyr); */ + sqrt(4 * cbyr * hilimit1 / M_PI); + h1dummy1 = h1hivalue1 / delta1; + *h1dashfirstcoeff = h1dummy1; + h1relval = fabs(h1dummy1 * reltol); + + temp = rclsqr / (4 * hilimit1); + temp2 = (temp >= 100.0 ? 0.0 : erfc(sqrt(temp))); + temp3 = exp(-temp); + temp4 = sqrt(rclsqr); + temp5 = sqrt(cbyr); + + h2lovalue1 = 0.0; + h2hivalue1 = /* LTRArcH2TwiceIntFunc(hilimit1,rclsqr); */ + (hilimit1 != 0.0 ? (hilimit1 + rclsqr * 0.5) * temp2 - sqrt(hilimit1 * rclsqr / M_PI) * temp3 : 0.0); + + + h2dummy1 = h2hivalue1 / delta1; + *h2firstcoeff = h2dummy1; + h2relval = fabs(h2dummy1 * reltol); + + h3lovalue1 = 0.0; + h3hivalue1 = /* LTRArcH3dashTwiceIntFunc(hilimit1,cbyr,rcls + * qr); */ + (hilimit1 != 0.0 ? temp = 2 * sqrt(hilimit1 / M_PI) * temp3 - temp4 * temp2, (temp5 * temp) : 0.0); + + + h3dummy1 = h3hivalue1 / delta1; + *h3dashfirstcoeff = h3dummy1; + h3relval = fabs(h3dummy1 * reltol); + + /* the coefficients for the rest of the timepoints */ + + for (i = auxindex; i > 0; i--) { + + delta2 = delta1; /* previous delta1 */ + lolimit2 = lolimit1; /* previous lolimit1 */ + hilimit2 = hilimit1; /* previous hilimit1 */ + + delta1 = *(timelist + i) - *(timelist + i - 1); + lolimit1 = hilimit2; + hilimit1 = curtime - *(timelist + i - 1); + + if (doh1) { + h1lovalue2 = h1lovalue1; /* previous lovalue1 */ + h1hivalue2 = h1hivalue1; /* previous hivalue1 */ + h1dummy2 = h1dummy1; /* previous dummy1 */ + + h1lovalue1 = h1hivalue2; + h1hivalue1 = /* LTRArcH1dashTwiceIntFunc(hilimit1,cbyr); */ + sqrt(4 * cbyr * hilimit1 / M_PI); + h1dummy1 = (h1hivalue1 - h1lovalue1) / delta1; + *(h1dashcoeffs + i) = h1dummy1 - h1dummy2; + if (fabs(*(h1dashcoeffs + i)) < h1relval) + doh1 = 0; + } else + *(h1dashcoeffs + i) = 0.0; + + if (doh2 || doh3) { + temp = rclsqr / (4 * hilimit1); + temp2 = (temp >= 100.0 ? 0.0 : erfc(sqrt(temp))); + temp3 = exp(-temp); + } + if (doh2) { + h2lovalue2 = h2lovalue1; /* previous lovalue1 */ + h2hivalue2 = h2hivalue1; /* previous hivalue1 */ + h2dummy2 = h2dummy1; /* previous dummy1 */ + + h2lovalue1 = h2hivalue2; + h2hivalue1 = /* LTRArcH2TwiceIntFunc(hilimit1,rclsqr); */ + (hilimit1 != 0.0 ? (hilimit1 + rclsqr * 0.5) * temp2 - sqrt(hilimit1 * rclsqr / M_PI) * temp3 : 0.0); + h2dummy1 = (h2hivalue1 - h2lovalue1) / delta1; + *(h2coeffs + i) = h2dummy1 - h2dummy2; + if (fabs(*(h2coeffs + i)) < h2relval) + doh2 = 0; + } else + *(h2coeffs + i) = 0.0; + + if (doh3) { + h3lovalue2 = h3lovalue1; /* previous lovalue1 */ + h3hivalue2 = h3hivalue1; /* previous hivalue1 */ + h3dummy2 = h3dummy1; /* previous dummy1 */ + + h3lovalue1 = h3hivalue2; + h3hivalue1 = /* LTRArcH3dashTwiceIntFunc(hilimit1,cbyr,rcls + * qr); */ + (hilimit1 != 0.0 ? temp = 2 * sqrt(hilimit1 / M_PI) * temp3 - temp4 * temp2, (temp5 * temp) : 0.0); + h3dummy1 = (h3hivalue1 - h3lovalue1) / delta1; + *(h3dashcoeffs + i) = h3dummy1 - h3dummy2; + if (fabs(*(h3dashcoeffs + i)) < h3relval) + doh3 = 0; + } else + *(h3dashcoeffs + i) = 0.0; + } +} + +void +LTRArlcCoeffsSetup(h1dashfirstcoeff, h2firstcoeff, h3dashfirstcoeff, h1dashcoeffs, h2coeffs, h3dashcoeffs, listsize, T, alpha, beta, curtime, timelist, timeindex, reltol, auxindexptr) + double *h1dashfirstcoeff, *h2firstcoeff, *h3dashfirstcoeff; + double *h1dashcoeffs, *h2coeffs, *h3dashcoeffs, *timelist; + double T, alpha, beta, curtime, reltol; + int listsize, timeindex, *auxindexptr; +{ + unsigned exact; + double lolimit1, lolimit2, hilimit1, hilimit2; + double delta1, delta2; + + double h1dummy1, h1dummy2; + double h1lovalue1, h1lovalue2, h1hivalue1, h1hivalue2; + + double h2dummy1, h2dummy2; + double h2lovalue1, h2lovalue2, h2hivalue1, h2hivalue2; + + double h3dummy1, h3dummy2; + double h3lovalue1, h3lovalue2, h3hivalue1, h3hivalue2; + + double exparg, besselarg, expterm, bessi1overxterm, bessi0term; + double expbetaTterm, alphasqTterm; + double h1relval, h2relval, h3relval; + int doh1 = 1, doh2 = 1, doh3 = 1; + + int i, auxindex; + + /* coefflists should already have been allocated to the necessary size */ + +#ifdef LTRAdebug + if (listsize <= timeindex) { + printf("LTRArlcCoeffsSetup: not enough space in coefflist\n"); + } +#endif + + + /* + * we assume a piecewise linear function, and we calculate the coefficients + * using this assumption in the integration of the function + */ + + if (T == 0.0) { + auxindex = timeindex; + } else { + + if (curtime - T <= 0.0) { + auxindex = 0; + } else { + exact = 0; + for (i = timeindex; i >= 0; i--) { + if (curtime - *(timelist + i) == T) { + exact = 1; + break; + } + if (curtime - *(timelist + i) > T) + break; + } + +#ifdef LTRADEBUG + if ((i < 0) || ((i == 0) && (exact == 1))) + printf("LTRAcoeffSetup: i <= 0: some mistake!\n"); +#endif + + if (exact == 1) { + auxindex = i - 1; + } else { + auxindex = i; + } + } + } + /* the first coefficient */ + + if (auxindex != 0) { + lolimit1 = T; + hilimit1 = curtime - *(timelist + auxindex); + delta1 = hilimit1 - lolimit1; + + h2lovalue1 = LTRArlcH2Func(T, T, alpha, beta); + besselarg = (hilimit1 > T) ? alpha * sqrt(hilimit1 * hilimit1 - T * T) : 0.0; + exparg = -beta * hilimit1; + expterm = exp(exparg); + bessi1overxterm = bessI1xOverX(besselarg); + alphasqTterm = alpha * alpha * T; + h2hivalue1 = /* LTRArlcH2Func(hilimit1,T,alpha,beta); */ + ((alpha == 0.0) || (hilimit1 < T)) ? 0.0 : alphasqTterm * expterm * bessi1overxterm; + + h2dummy1 = twiceintlinfunc(lolimit1, hilimit1, lolimit1, h2lovalue1, + h2hivalue1, lolimit1, hilimit1) / delta1; + *h2firstcoeff = h2dummy1; + h2relval = fabs(reltol * h2dummy1); + + h3lovalue1 = 0.0; /* E3dash should be consistent with this */ + bessi0term = bessI0(besselarg); + expbetaTterm = exp(-beta * T); + h3hivalue1 = /* LTRArlcH3dashIntFunc(hilimit1,T,beta); */ + ((hilimit1 <= T) || (beta == 0.0)) ? 0.0 : expterm * bessi0term - expbetaTterm; + h3dummy1 = intlinfunc(lolimit1, hilimit1, h3lovalue1, + h3hivalue1, lolimit1, hilimit1) / delta1; + *h3dashfirstcoeff = h3dummy1; + h3relval = fabs(h3dummy1 * reltol); + } else { + *h2firstcoeff = *h3dashfirstcoeff = 0.0; + } + + lolimit1 = 0.0; + hilimit1 = curtime - *(timelist + timeindex); + delta1 = hilimit1 - lolimit1; + exparg = -beta * hilimit1; + expterm = exp(exparg); + + h1lovalue1 = 0.0; + h1hivalue1 = /* LTRArlcH1dashTwiceIntFunc(hilimit1,beta); */ + (beta == 0.0) ? hilimit1 : ((hilimit1 == 0.0) ? 0.0 : (bessI1(-exparg) + bessI0(-exparg)) * hilimit1 * expterm - hilimit1); + h1dummy1 = h1hivalue1 / delta1; + *h1dashfirstcoeff = h1dummy1; + h1relval = fabs(h1dummy1 * reltol); + + + /* the coefficients for the rest of the timepoints */ + + for (i = timeindex; i > 0; i--) { + + if (doh1 || doh2 || doh3) { + lolimit2 = lolimit1; /* previous lolimit1 */ + hilimit2 = hilimit1; /* previous hilimit1 */ + delta2 = delta1; /* previous delta1 */ + + lolimit1 = hilimit2; + hilimit1 = curtime - *(timelist + i - 1); + delta1 = *(timelist + i) - *(timelist + i - 1); + + exparg = -beta * hilimit1; + expterm = exp(exparg); + } + if (doh1) { + h1lovalue2 = h1lovalue1; /* previous lovalue1 */ + h1hivalue2 = h1hivalue1; /* previous hivalue1 */ + h1dummy2 = h1dummy1; /* previous dummy1 */ + + h1lovalue1 = h1hivalue2; + h1hivalue1 = /* LTRArlcH1dashTwiceIntFunc(hilimit1,beta); */ + (beta == 0.0) ? hilimit1 : ((hilimit1 == 0.0) ? 0.0 : (bessI1(-exparg) + bessI0(-exparg)) * hilimit1 * expterm - hilimit1); + h1dummy1 = (h1hivalue1 - h1lovalue1) / delta1; + + *(h1dashcoeffs + i) = h1dummy1 - h1dummy2; + if (fabs(*(h1dashcoeffs + i)) <= h1relval) + doh1 = 0; + } else + *(h1dashcoeffs + i) = 0.0; + + if (i <= auxindex) { + + /* + * if (i == auxindex) { lolimit2 = T; delta2 = hilimit2 - lolimit2; } + */ + + if (doh2 || doh3) + besselarg = (hilimit1 > T) ? alpha * sqrt(hilimit1 * hilimit1 - T * T) : 0.0; + + if (doh2) { + h2lovalue2 = h2lovalue1;/* previous lovalue1 */ + h2hivalue2 = h2hivalue1;/* previous hivalue1 */ + h2dummy2 = h2dummy1; /* previous dummy1 */ + + h2lovalue1 = h2hivalue2; + bessi1overxterm = bessI1xOverX(besselarg); + h2hivalue1 = /* LTRArlcH2Func(hilimit1,T,alpha,beta); */ + ((alpha == 0.0) || (hilimit1 < T)) ? 0.0 : alphasqTterm * expterm * bessi1overxterm; + h2dummy1 = twiceintlinfunc(lolimit1, hilimit1, lolimit1, + h2lovalue1, h2hivalue1, lolimit1, hilimit1) / delta1; + + *(h2coeffs + i) = h2dummy1 - h2dummy2 + intlinfunc(lolimit2, hilimit2, + h2lovalue2, h2hivalue2, lolimit2, hilimit2); + if (fabs(*(h2coeffs + i)) <= h2relval) + doh2 = 0; + } else + *(h2coeffs + i) = 0.0; + + if (doh3) { + h3lovalue2 = h3lovalue1;/* previous lovalue1 */ + h3hivalue2 = h3hivalue1;/* previous hivalue1 */ + h3dummy2 = h3dummy1; /* previous dummy1 */ + + h3lovalue1 = h3hivalue2; + bessi0term = bessI0(besselarg); + h3hivalue1 = /* LTRArlcH3dashIntFunc(hilimit1,T,beta); */ + ((hilimit1 <= T) || (beta == 0.0)) ? 0.0 : expterm * bessi0term - expbetaTterm; + h3dummy1 = intlinfunc(lolimit1, hilimit1, h3lovalue1, h3hivalue1, lolimit1, hilimit1) / delta1; + + *(h3dashcoeffs + i) = h3dummy1 - h3dummy2; + if (fabs(*(h3dashcoeffs + i)) <= h3relval) + doh3 = 0; + } else + *(h3dashcoeffs + i) = 0.0; + } + } + *auxindexptr = auxindex; +} + +/* + * LTRAstraightLineCheck - takes the co-ordinates of three points, finds the + * area of the triangle enclosed by these points and compares this area with + * the area of the quadrilateral formed by the line between the first point + * and the third point, the perpendiculars from the first and third points to + * the x-axis, and the x-axis. If within reltol, then it returns 1, else 0. + * The purpose of this function is to determine if three points lie + * acceptably close to a straight line. This area criterion is used because + * it is related to integrals and convolution + */ + +int +LTRAstraightLineCheck(x1, y1, x2, y2, x3, y3, reltol, abstol) + double x1, y1, x2, y2, x3, y3, reltol, abstol; + +{ + /* + * double asqr, bsqr, csqr, c, c1sqr; double htsqr; + */ + double TRarea, QUADarea1, QUADarea2, QUADarea3, area; + + /* + * asqr = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1); bsqr = (x3-x2)*(x3-x2) + + * (y3-y2)*(y3-y2); csqr = (x3-x1)*(x3-x1) + (y3-y1)*(y3-y1); c = + * sqrt(csqr); c1sqr = (asqr - bsqr + csqr)/(2*c); c1sqr *= c1sqr; htsqr = + * asqr - c1sqr; TRarea = c*sqrt(htsqr)*0.5; + */ + /* + * this should work if y1,y2,y3 all have the same sign and x1,x2,x3 are in + * increasing order + */ + + QUADarea1 = (fabs(y2) + fabs(y1)) * 0.5 * fabs(x2 - x1); + QUADarea2 = (fabs(y3) + fabs(y2)) * 0.5 * fabs(x3 - x2); + QUADarea3 = (fabs(y3) + fabs(y1)) * 0.5 * fabs(x3 - x1); + TRarea = fabs(QUADarea3 - QUADarea1 - QUADarea2); + area = QUADarea1 + QUADarea2; + if (area * reltol + abstol > TRarea) + return (1); + else + return (0); +} + + +/* + * i is thestrchr of the latest value, a,b,c values correspond to values at + * t_{i-2}, t{i-1} and t_i + */ + +#define SECONDDERIV(i,a,b,c) (oof = (i==ckt->CKTtimeIndex+1?curtime:\ +*(ckt->CKTtimePoints+i)),\ +(( c - b )/(oof-*(ckt->CKTtimePoints+i-1)) -\ +( b - a )/(*(ckt->CKTtimePoints+i-1)-\ +*(ckt->CKTtimePoints+i-2)))/(oof - \ +*(ckt->CKTtimePoints+i-2))) + +/* + * LTRAlteCalculate - returns sum of the absolute values of the total local + * truncation error of the 2 equations for the LTRAline + */ + + +double +LTRAlteCalculate(ckt, genmodel, geninstance, curtime) + register CKTcircuit *ckt; + GENmodel *genmodel; + GENinstance *geninstance; + double curtime; +{ + LTRAmodel *model = (LTRAmodel *) genmodel; + LTRAinstance *instance = (LTRAinstance *) geninstance; + double h1dashTfirstCoeff; + double h2TfirstCoeff; + double h3dashTfirstCoeff; + double dashdash; + double oof; + double hilimit1, lolimit1, hivalue1, lovalue1, f1i, g1i; + double eq1LTE = 0.0, eq2LTE = 0.0; + int auxindex, tdover, i, exact; + + switch (model->LTRAspecialCase) { + + case LTRA_MOD_LC: + case LTRA_MOD_RG: + return (0.0); + break; + + case LTRA_MOD_RLC: + + if (curtime > model->LTRAtd) { + tdover = 1; + + exact = 0; + for (i = ckt->CKTtimeIndex; i >= 0; i--) { + if (curtime - *(ckt->CKTtimePoints + i) + == model->LTRAtd) { + exact = 1; + break; + } + if (curtime - *(ckt->CKTtimePoints + i) + > model->LTRAtd) + break; + } + +#ifdef LTRADEBUG + if ((i < 0) || ((i == 0) && (exact == 1))) + printf("LTRAlteCalculate: i <= 0: some mistake!\n"); +#endif + + if (exact == 1) { + auxindex = i - 1; + } else { + auxindex = i; + } + + } else { + tdover = 0; + } + + hilimit1 = curtime - *(ckt->CKTtimePoints + ckt->CKTtimeIndex); + lolimit1 = 0.0; + hivalue1 = LTRArlcH1dashTwiceIntFunc(hilimit1, model->LTRAbeta); + lovalue1 = 0.0; + + f1i = hivalue1; + g1i = intlinfunc(lolimit1, hilimit1, lovalue1, hivalue1, + lolimit1, hilimit1); + h1dashTfirstCoeff = 0.5 * f1i * + (curtime - *(ckt->CKTtimePoints + ckt->CKTtimeIndex)) - g1i; + + if (tdover) { + hilimit1 = curtime - *(ckt->CKTtimePoints + auxindex); + lolimit1 = *(ckt->CKTtimePoints + ckt->CKTtimeIndex) - *(ckt->CKTtimePoints + auxindex); + lolimit1 = MAX(model->LTRAtd, lolimit1); + + /* + * are the following really doing the operations in the write-up? + */ + hivalue1 = LTRArlcH2Func(hilimit1, model->LTRAtd, model->LTRAalpha, model->LTRAbeta); + lovalue1 = LTRArlcH2Func(lolimit1, model->LTRAtd, model->LTRAalpha, model->LTRAbeta); + f1i = twiceintlinfunc(lolimit1, hilimit1, lolimit1, lovalue1, hivalue1, lolimit1, + hilimit1); + g1i = thriceintlinfunc(lolimit1, hilimit1, lolimit1, lolimit1, lovalue1, + hivalue1, lolimit1, hilimit1); + h2TfirstCoeff = 0.5 * f1i * (curtime - model->LTRAtd - *(ckt->CKTtimePoints + auxindex)) - g1i; + + hivalue1 = LTRArlcH3dashIntFunc(hilimit1, model->LTRAtd, model->LTRAbeta); + lovalue1 = LTRArlcH3dashIntFunc(lolimit1, model->LTRAtd, model->LTRAbeta); + f1i = intlinfunc(lolimit1, hilimit1, lovalue1, hivalue1, lolimit1, + hilimit1); + g1i = twiceintlinfunc(lolimit1, hilimit1, lolimit1, lovalue1, + hivalue1, lolimit1, hilimit1); + h3dashTfirstCoeff = 0.5 * f1i * (curtime - model->LTRAtd - *(ckt->CKTtimePoints + auxindex)) - g1i; + } + /* LTEs for convolution with v1 */ + /* get divided differences for v1 (2nd derivative estimates) */ + + /* + * no need to subtract operating point values because taking differences + * anyway + */ + + dashdash = SECONDDERIV(ckt->CKTtimeIndex + 1, + *(instance->LTRAv1 + ckt->CKTtimeIndex - 1), + *(instance->LTRAv1 + ckt->CKTtimeIndex), + *(ckt->CKTrhsOld + instance->LTRAposNode1) - + *(ckt->CKTrhsOld + instance->LTRAnegNode1)); + eq1LTE += model->LTRAadmit * fabs(dashdash * + h1dashTfirstCoeff); + + + /* + * not bothering to interpolate since everything is approximate anyway + */ + + if (tdover) { + + dashdash = SECONDDERIV(auxindex + 1, + *(instance->LTRAv1 + auxindex - 1), + *(instance->LTRAv1 + auxindex), + *(instance->LTRAv1 + auxindex + 1)); + + eq2LTE += model->LTRAadmit * fabs(dashdash * + h3dashTfirstCoeff); + + } + /* end LTEs for convolution with v1 */ + + /* LTEs for convolution with v2 */ + /* get divided differences for v2 (2nd derivative estimates) */ + + dashdash = SECONDDERIV(ckt->CKTtimeIndex + 1, + *(instance->LTRAv2 + ckt->CKTtimeIndex - 1), + *(instance->LTRAv2 + ckt->CKTtimeIndex), + *(ckt->CKTrhsOld + instance->LTRAposNode2) - + *(ckt->CKTrhsOld + instance->LTRAnegNode2)); + + eq2LTE += model->LTRAadmit * fabs(dashdash * + h1dashTfirstCoeff); + + + if (tdover) { + + + dashdash = SECONDDERIV(auxindex + 1, + *(instance->LTRAv2 + auxindex - 1), + *(instance->LTRAv2 + auxindex), + *(instance->LTRAv2 + auxindex + 1)); + + eq1LTE += model->LTRAadmit * fabs(dashdash * + h3dashTfirstCoeff); + + } + /* end LTEs for convolution with v2 */ + + /* LTE for convolution with i1 */ + /* get divided differences for i1 (2nd derivative estimates) */ + + if (tdover) { + + + dashdash = SECONDDERIV(auxindex + 1, + *(instance->LTRAi1 + auxindex - 1), + *(instance->LTRAi1 + auxindex), + *(instance->LTRAi1 + auxindex + 1)); + + eq2LTE += fabs(dashdash * h2TfirstCoeff); + + + } + /* end LTE for convolution with i1 */ + + /* LTE for convolution with i2 */ + /* get divided differences for i2 (2nd derivative estimates) */ + + if (tdover) { + + dashdash = SECONDDERIV(auxindex + 1, + *(instance->LTRAi2 + auxindex - 1), + *(instance->LTRAi2 + auxindex), + *(instance->LTRAi2 + auxindex + 1)); + + eq1LTE += fabs(dashdash * h2TfirstCoeff); + + } + /* end LTE for convolution with i1 */ + + break; + + case LTRA_MOD_RC: + + hilimit1 = curtime - *(ckt->CKTtimePoints + ckt->CKTtimeIndex); + lolimit1 = 0.0; + + hivalue1 = LTRArcH1dashTwiceIntFunc(hilimit1, model->LTRAcByR); + lovalue1 = 0.0; + + f1i = hivalue1; + g1i = intlinfunc(lolimit1, hilimit1, lovalue1, hivalue1, lolimit1, hilimit1); + h1dashTfirstCoeff = 0.5 * f1i * (curtime - *(ckt->CKTtimePoints + ckt->CKTtimeIndex)) - g1i; + + + + + hivalue1 = LTRArcH2TwiceIntFunc(hilimit1, model->LTRArclsqr); + lovalue1 = 0.0; + + f1i = hivalue1; + g1i = intlinfunc(lolimit1, hilimit1, lovalue1, hivalue1, lolimit1, hilimit1); + h1dashTfirstCoeff = 0.5 * f1i * (curtime - *(ckt->CKTtimePoints + ckt->CKTtimeIndex)) - g1i; + + + + + + hivalue1 = LTRArcH2TwiceIntFunc(hilimit1, model->LTRArclsqr); + lovalue1 = 0.0; + + f1i = hivalue1; + g1i = intlinfunc(lolimit1, hilimit1, lovalue1, + hivalue1, lolimit1, hilimit1); + h1dashTfirstCoeff = 0.5 * f1i * (curtime - + *(ckt->CKTtimePoints + ckt->CKTtimeIndex)) - g1i; + + + + /* LTEs for convolution with v1 */ + /* get divided differences for v1 (2nd derivative estimates) */ + + /* + * no need to subtract operating point values because taking differences + * anyway + */ + + dashdash = SECONDDERIV(ckt->CKTtimeIndex + 1, + *(instance->LTRAv1 + ckt->CKTtimeIndex - 1), + *(instance->LTRAv1 + ckt->CKTtimeIndex), + *(ckt->CKTrhsOld + instance->LTRAposNode1) - + *(ckt->CKTrhsOld + instance->LTRAnegNode1)); + eq1LTE += fabs(dashdash * h1dashTfirstCoeff); + eq2LTE += fabs(dashdash * h3dashTfirstCoeff); + + /* end LTEs for convolution with v1 */ + + /* LTEs for convolution with v2 */ + /* get divided differences for v2 (2nd derivative estimates) */ + + dashdash = SECONDDERIV(ckt->CKTtimeIndex + 1, + *(instance->LTRAv2 + ckt->CKTtimeIndex - 1), + *(instance->LTRAv2 + ckt->CKTtimeIndex), + *(ckt->CKTrhsOld + instance->LTRAposNode2) - + *(ckt->CKTrhsOld + instance->LTRAnegNode2)); + + eq2LTE += fabs(dashdash * h1dashTfirstCoeff); + eq1LTE += fabs(dashdash * h3dashTfirstCoeff); + + /* end LTEs for convolution with v2 */ + + /* LTE for convolution with i1 */ + /* get divided differences for i1 (2nd derivative estimates) */ + + dashdash = SECONDDERIV(ckt->CKTtimeIndex + 1, + *(instance->LTRAi1 + ckt->CKTtimeIndex - 1), + *(instance->LTRAi1 + ckt->CKTtimeIndex), + *(ckt->CKTrhsOld + instance->LTRAbrEq1)); + + eq2LTE += fabs(dashdash * h2TfirstCoeff); + + + /* end LTE for convolution with i1 */ + + /* LTE for convolution with i2 */ + /* get divided differences for i2 (2nd derivative estimates) */ + + dashdash = SECONDDERIV(ckt->CKTtimeIndex + 1, + *(instance->LTRAi2 + ckt->CKTtimeIndex - 1), + *(instance->LTRAi2 + ckt->CKTtimeIndex), + *(ckt->CKTrhsOld + instance->LTRAbrEq2)); + + + eq1LTE += fabs(dashdash * h2TfirstCoeff); + + + /* end LTE for convolution with i1 */ + + break; + + default: + return (1 /* error */ ); + } + + +#ifdef LTRADEBUG + fprintf(stdout, "%s: LTE/input for Eq1 at time %g is: %g\n", + instance->LTRAname, curtime, eq1LTE / instance->LTRAinput1); + fprintf(stdout, "%s: LTE/input for Eq2 at time %g is: %g\n", + instance->LTRAname, curtime, eq2LTE / instance->LTRAinput1); + fprintf(stdout, "\n"); +#endif + + return (fabs(eq1LTE) + fabs(eq2LTE)); +} + +/*********************************************************************/ +/****************** old stuff, retained for historical interest ******/ +/*********************************************************************/ + + + +/* + * LTRAcoeffSetup sets up the coefficient list for the convolution, returns + * the coefficient at (current_timepoint-T) + */ + +/* + * double + * LTRAcoeffSetup(coefflist,listsize,T,firstvalue,valuelist,curtime,timelist,t + * imeindex,auxindexptr) double *coefflist, *timelist, *valuelist; int + * listsize, timeindex; double T, firstvalue, curtime; int *auxindexptr; + * + * { unsigned exact; double returnval, delta1, delta2; double dummy1, dummy2; + * double lolimit1,lolimit2,hilimit1,hilimit2; double + * lovalue1,lovalue2,hivalue1,hivalue2; int i,auxindex; + */ + +/* coefflist should already have been allocated to the necessary size */ + +/* + * #ifdef LTRAdebug if (listsize <= timeindex) { printf("LTRAcoeffSetup: not + * enough space in coefflist\n"); } #endif + * + */ + +/* + * we assume a piecewise linear function, and we calculate the coefficients + * using this assumption in the integration of the function + */ + +/* + * if (T == 0.0) { auxindex = timeindex; } else { + * + * if (curtime - T <= 0.0) { for (i =0; i<= timeindex; i++) { (coefflist + i) = + * 0.0; } auxindexptr = 0; return(0.0); } else { exact = 0; for (i = + * timeindex; i>= 0; i--) { if (curtime - *(timelist + i) == T) { exact =1; + * break; } if (curtime - *(timelist + i) > T) break; } + * + * #ifdef LTRADEBUG if ((i < 0) || ((i==0) && (exact==1))) + * printf("LTRAcoeffSetup: i <= 0: some mistake!\n"); #endif + * + * if (exact == 1) { auxindex = i-1; } else { auxindex = i; } } } + */ +/* the first coefficient */ + +/* + * delta1 = curtime -T - *(timelist + auxindex); lolimit1 = T; hilimit1 = T + + * delta1; lovalue1 = firstvalue; hivalue1 = *(valuelist + auxindex); dummy1 + * = twiceintlinfunc(lolimit1,hilimit1,lolimit1,lovalue1, + * hivalue1,lolimit1,hilimit1)/delta1; returnval = dummy1; + * + */ + + +/* the coefficients for the rest of the timepoints */ + +/* + * for (i=auxindex; i>0; i--) { + * + * delta2 = delta1; + *//* previous delta1 */ +/* lolimit2 = lolimit1; *//* previous lolimit1 */ +/* hilimit2 = hilimit1; *//* previous hilimit1 */ +/* lovalue2 = lovalue1; *//* previous lovalue1 */ +/* hivalue2 = hivalue1; *//* previous hivalue1 */ +/* dummy2 = dummy1; *//* previous dummy1 */ +/* + * delta1 = *(timelist + i) - *(timelist + i - 1); lolimit1 = hilimit2; + * hilimit1 = curtime - *(timelist + i - 1); lovalue1 = hivalue2; hivalue1 = + * *(valuelist + i - 1); dummy1 = twiceintlinfunc(lolimit1,hilimit1,lolimit1, + * lovalue1,hivalue1,lolimit1,hilimit1)/delta1; + * + * (coefflist + i) = dummy1 - dummy2 + intlinfunc(lolimit2,hilimit2, + * lovalue2,hivalue2,lolimit2,hilimit2); } auxindexptr = auxindex; + * return(returnval); } + */ + +/* + * LTRAtCoeffSetup sets up the coefficient list for the LTE calculation, + * returns the coefficient at (current_timepoint-T) + */ + +/* + * double LTRAtCoeffSetup(coefflist,listsize,T,valuelist, + * firstothervalue,othervaluelist,curtime,timelist,timeindex, auxindexptr, + * ltecontype) double *coefflist, *timelist, *valuelist, *othervaluelist; int + * listsize, timeindex; double T, firstothervalue, curtime; int *auxindexptr, + * ltecontype; + * + * { unsigned exact; double returnval, delta; double dummy; double f1i, f2i, + * g1i, g2i; double lolimit1, hilimit1; double lovalue1, hivalue1; double + * lolimit2, hilimit2; double lovalue2, hivalue2; double firstint1 = 0.0, + * firstint2 = 0.0; double secondint1 = 0.0, secondint2 = 0.0; int + * i,auxindex; + * + */ +/* coefflist should already have been allocated to the necessary size */ + +/* + * #ifdef LTRAdebug if (listsize <= timeindex) { printf("LTRAtCoeffSetup: not + * enough space in coefflist\n"); } #endif + * + */ + +/* + * we assume a piecewise linear function, and we calculate the coefficients + * using this assumption in the integration of the function + */ + +/* + * if (T == 0.0) { auxindex = timeindex; } else { + * + * if (curtime - T <= 0.0) { for (i =0; i<= timeindex; i++) { (coefflist + i) = + * 0.0; } auxindexptr = 0; return(0.0); } else { exact = 0; for (i = + * timeindex; i>= 0; i--) { if (curtime - *(timelist + i) == T) { exact =1; + * break; } if (curtime - *(timelist + i) > T) break; } + * + * #ifdef LTRADEBUG if ((i < 0) || ((i==0) && (exact==1))) + * printf("LTRAcoeffSetup: i <= 0: some mistake!\n"); #endif + * + * if (exact == 1) { auxindex = i-1; } else { auxindex = i; } } } + */ +/* the first coefficient */ + +/* i = n in the write-up */ + +/* + * hilimit1 = curtime - *(timelist + auxindex); hivalue1 = *(valuelist + + * auxindex); lolimit1 = *(timelist + timeindex) - *(timelist + auxindex); + * lolimit1 = MAX(T,lolimit1); lovalue1 = firstothervalue; f1i = + * twiceintlinfunc(lolimit1,hilimit1,lolimit1,lovalue1,hivalue1,lolimit1, + * hilimit1); g1i = + * thriceintlinfunc(lolimit1,hilimit1,lolimit1,lolimit1,lovalue1, + * hivalue1,lolimit1,hilimit1); returnval = 0.5*f1i*(curtime-T- + * *(timelist+auxindex)) - g1i; + * + */ +/* the coefficients for the rest of the timepoints */ + +/* + * if (ltecontype != LTRA_MOD_HALFCONTROL) { for (i=auxindex; i>0; i--) { + * + * lolimit2 = lolimit1; + *//* previous lolimit1 */ +/* hilimit2 = hilimit1; *//* previous hilimit1 */ +/* lovalue2 = lovalue1; *//* previous lovalue1 */ +/* hivalue2 = hivalue1; *//* previous hivalue1 */ +/* f2i = f1i; *//* previous f1i */ +/* g2i = g1i; *//* previous g1i */ +/* firstint2 = firstint1; *//* previous firstint1 */ +/* secondint2 = secondint1; *//* previous secondint1 */ +/* + * lolimit1 = *(timelist + timeindex) - *(timelist + i - 1); hilimit1 = + * curtime - *(timelist + i - 1); lovalue1 = *(othervaluelist + i - 1); + * hivalue1 = *(valuelist + i - 1); firstint1 += intlinfunc(lolimit2, + * lolimit1, lovalue2, lovalue1, lolimit2, lolimit1); secondint1 += + * (lolimit1-lolimit2)*firstint2 + twiceintlinfunc( + * lolimit2,lolimit1,lolimit2,lovalue2,lovalue1,lolimit2,lolimit1); f1i = + * twiceintlinfunc(lolimit1,hilimit1,lolimit1,lovalue1,hivalue1, + * lolimit1,hilimit1) + firstint1*(hilimit1-lolimit1); g1i = + * thriceintlinfunc(lolimit1,hilimit1,lolimit1,lolimit1, + * lovalue1,hivalue1,lolimit1,hilimit1) + + * (hilimit1-lolimit1)*(hilimit1-lolimit1)*0.5*firstint1 + + * (hilimit1-lolimit1)*secondint1; + * + * (coefflist + i) = g2i - g1i + 0.5*(f1i + f2i)*(*(timelist+i) - + * (timelist+i-1)); } } auxindexptr = auxindex; return(returnval); } + */ + + +/* + * formulae taken from the Handbook of Mathematical Functions by Milton + * Abramowitz and Irene A. Stegan, page 378, formulae 9.8.1 - 9.8.4 + */ + +/* + * double bessi0(x) double x; { double t, tsq, oneovert, result, dummy; int i; + * static double coeffs1[7], coeffs2[9]; + * + * coeffs1[0] = 1.0; coeffs1[1] = 3.5156229; coeffs1[2] = 3.0899424; coeffs1[3] + * = 1.2067492; coeffs1[4] = 0.2659732; coeffs1[5] = 0.0360768; coeffs1[6] = + * 0.0045813; + * + * coeffs2[0] = 0.39894228; coeffs2[1] = 0.01328592; coeffs2[2] = 0.00225319; + * coeffs2[3] = -0.00157565; coeffs2[4] = 0.00916281; coeffs2[5] = + * -0.02057706; coeffs2[6] = 0.02635537; coeffs2[7] = -0.01647633; coeffs2[8] + * = 0.00392377; + * + * t = x/3.75; dummy = 1.0; + * + * if (fabs(t) <= 1) { tsq = t*t; + * + * result = 1.0; for (i=1;i<=6;i++) { dummy *= tsq; ; result += dummy * + * coeffs1[i]; } } else { oneovert = 1/fabs(t); + * + * result = coeffs2[0]; for (i=1;i<=8;i++) { dummy *= oneovert; result += + * coeffs2[2] * dummy; } result *= exp(x) * sqrt(1/fabs(x)); } + * return(result); } + * + * double bessi1(x) double x; { double t, tsq, oneovert, result, dummy; int i; + * static double coeffs1[7], coeffs2[9]; + * + * coeffs1[0] = 0.5; coeffs1[1] = 0.87890594; coeffs1[2] = 0.51498869; + * coeffs1[3] = 0.15084934; coeffs1[4] = 0.02658733; coeffs1[5] = 0.00301532; + * coeffs1[6] = 0.00032411; + * + * coeffs2[0] = 0.39894228; coeffs2[1] = -0.03988024; coeffs2[2] = -0.00362018; + * coeffs2[3] = 0.00163801; coeffs2[4] = -0.01031555; coeffs2[5] = + * 0.02282967; coeffs2[6] = -0.02895312; coeffs2[7] = 0.01787654; coeffs2[8] + * = -0.00420059; + * + * t = x/3.75; dummy = 1.0; + * + * if (fabs(t) <= 1) { tsq = t*t; + * + * result = 0.5; for (i=1;i<=6;i++) { dummy *= tsq; ; result += dummy * + * coeffs1[i]; } result *= x; } else { oneovert = 1/fabs(t); + * + * result = coeffs2[0]; for (i=1;i<=8;i++) { dummy *= oneovert; result += + * coeffs2[2] * dummy; } result *= exp(x) * sqrt(1/fabs(x)); if (x < 0) + * result = -result; } return(result); } */ + +/* + * LTRAdivDiffs returns divided differences after 2 iterations, an + * approximation to the second derivatives. The algorithm is picked up + * directly from Tom Quarles' CKTterr.c; no attempt has been made to figure + * out why it does what it does. + */ + +/* + * double LTRAdivDiffs(difflist, valuelist, firstvalue, curtime, timelist, + * timeindex) double *difflist, *valuelist, firstvalue, *timelist, curtime; + * int timeindex; + * + * { double *dtime, *diffs, returnval; int i,j; + * + * diffs = (double *) MALLOC(sizeof(double) * (timeindex+2)); dtime = (double *) + * MALLOC(sizeof(double) * (timeindex+2)); + */ + +/* now divided differences */ +/* + * for(i=timeindex+1;i>=0;i--) { (diffs+i) = (i == timeindex+1 ? firstvalue : + * *(valuelist + i)); } for(i=timeindex+1 ; i > 0 ; i--) { (dtime+i) = (i == + * timeindex+1? curtime: *(timelist + i)) - (timelist + i - 1); } j = 2; + *//* for the second derivative */ +/* + * while(1) { for(i=timeindex + 1;i > 0; i--) { (diffs+i) = (*(diffs+i) - + * *(diffs+i-1))/ *(dtime+i); } j--; if (j <= 0) break; for(i=timeindex+1;i > + * 0;i--) { (dtime+i) = *(dtime+i-1) + (i == timeindex+1? curtime: *(timelist + * + i)) - *(timelist + i - 1); } } + * + * for (i = timeindex; i>=0 ; i--) { (difflist+i) = *(diffs+i); } + * + * returnval = *(diffs+timeindex+1); FREE(dtime); FREE(diffs); + */ + +/* difflist[0] is going to be bad */ +/* + * return(returnval); } */ + + +/* + * LTRAlteCalculate - returns sum of the absolute values of the total local + * truncation error of the 2 equations for the LTRAline + */ + +/* + * double LTRAlteCalculate(ckt,model,instance,curtime) register CKTcircuit *ckt; + * register LTRAmodel *model; register LTRAinstance *instance; double + * curtime; + * + * { double *h1dashTcoeffs, h1dashTfirstCoeff; double *h2Tcoeffs, h2TfirstCoeff; + * double *h3dashTcoeffs, h3dashTfirstCoeff; double *SecondDerivs, + * FirstSecondDeriv; double t1, t2, t3, f1, f2, f3; double eq1LTE=0.0, + * eq2LTE=0.0; int isaved, tdover, i; + * + * if (curtime > model->LTRAtd) { tdover = 1; } else { tdover = 0; } + * + * h1dashTcoeffs = (double *) MALLOC(sizeof(double) * model->LTRAmodelListSize); + * h2Tcoeffs = (double *) MALLOC(sizeof(double) * model->LTRAmodelListSize); + * h3dashTcoeffs = (double *) MALLOC(sizeof(double) * + * model->LTRAmodelListSize); SecondDerivs = (double *) MALLOC(sizeof(double) * + * model->LTRAmodelListSize); + * + */ + +/* + * note that other OthVals have been set up in LTRAaccept, and Values in + * LTRAload + */ + + +/* + * h1dashTfirstCoeff = LTRAtCoeffSetup(h1dashTcoeffs, + * model->LTRAmodelListSize, 0.0, model->LTRAh1dashValues, + * model->LTRAh1dashFirstVal, model->LTRAh1dashOthVals, curtime, + * ckt->CKTtimePoints,ckt->CKTtimeIndex, &(model->LTRAh1dashIndex), + * model->LTRAlteConType); + * + * if (tdover) { + * + * h2TfirstCoeff = LTRAtCoeffSetup(h2Tcoeffs, model->LTRAmodelListSize, + * model->LTRAtd, model->LTRAh2Values, model->LTRAh2FirstOthVal, + * model->LTRAh2OthVals, curtime, ckt->CKTtimePoints, ckt->CKTtimeIndex, + * &(model->LTRAh2Index), model->LTRAlteConType); + * + * h3dashTfirstCoeff = LTRAtCoeffSetup(h3dashTcoeffs, model->LTRAmodelListSize, + * model->LTRAtd, model->LTRAh3dashValues, model->LTRAh3dashFirstOthVal, + * model->LTRAh3dashOthVals, curtime, ckt->CKTtimePoints,ckt->CKTtimeIndex, + * &(model->LTRAh3dashIndex), model->LTRAlteConType); + */ + +/* setting up the coefficients for interpolation */ +/* + * for (i = ckt->CKTtimeIndex; i>= 0; i--) { if (*(ckt->CKTtimePoints + i) < + * curtime - model->LTRAtd) { break; } } #ifdef LTRAdebug if (i == + * ckt->CKTtimeIndex) || (i == -1) { printf("LTRAtrunc: mistake: cannot find + * delayed timepoint\n"); } #endif t1 = *(ckt->CKTtimePoints + i - 1); t2 = + * *(ckt->CKTtimePoints + i); t3 = *(ckt->CKTtimePoints + i + 1); + * + * LTRAquadInterp(curtime - model->LTRAtd, t1,t2,t3,&f1,&f2,&f3); + * + * isaved = i; } */ + +/* interpolation coefficients set-up */ + +/* LTEs for convolution with v1 */ +/* get divided differences for v1 (2nd derivative estimates) */ + +/* + * no need to subtract operating point values because taking differences + * anyway + */ + +/* + * FirstSecondDeriv = LTRAdivDiffs(SecondDerivs,instance->LTRAv1, + * (ckt->CKTrhsOld + instance->LTRAposNode1) - *(ckt->CKTrhsOld + + * instance->LTRAnegNode1),curtime, ckt->CKTtimePoints,ckt->CKTtimeIndex); + * + * eq1LTE += model->LTRAadmit*fabs(FirstSecondDeriv * h1dashTfirstCoeff); + * + * if (model->LTRAlteConType != LTRA_MOD_HALFCONTROL) { for (i = + * model->LTRAh1dashIndex; i > 0; i--) { if ((*(SecondDerivs+i) != 0.0) && + * (*(h1dashTcoeffs+i)!=0.0)) { eq1LTE += + * model->LTRAadmit*fabs(*(SecondDerivs+i) * (h1dashTcoeffs+i)); } } } + * + */ +/* interpolate */ +/* + * if (tdover) { + * + * FirstSecondDeriv = *(SecondDerivs + isaved - 1) * f1 + *(SecondDerivs + + * isaved) * f2 + *(SecondDerivs + isaved + 1) * f3; + * + * eq2LTE += model->LTRAadmit*fabs(FirstSecondDeriv * h3dashTfirstCoeff); + * + * if (model->LTRAlteConType != LTRA_MOD_HALFCONTROL) { for (i = + * model->LTRAh3dashIndex; i > 0; i--) { if ((*(SecondDerivs+i) != 0.0) && + * (*(h3dashTcoeffs+i)!=0.0)) { eq2LTE += + * model->LTRAadmit*fabs(*(SecondDerivs+i) * (h3dashTcoeffs+i)); } } } } + */ +/* end LTEs for convolution with v1 */ + +/* LTEs for convolution with v2 */ +/* get divided differences for v2 (2nd derivative estimates) */ + +/* + * FirstSecondDeriv = LTRAdivDiffs(SecondDerivs,instance->LTRAv2, + * (ckt->CKTrhsOld + instance->LTRAposNode2) - *(ckt->CKTrhsOld + + * instance->LTRAnegNode2),curtime, ckt->CKTtimePoints,ckt->CKTtimeIndex); + * + * eq2LTE += model->LTRAadmit*fabs(FirstSecondDeriv * h1dashTfirstCoeff); + * + * if (model->LTRAlteConType != LTRA_MOD_HALFCONTROL) { for (i = + * model->LTRAh1dashIndex; i > 0; i--) { if ((*(SecondDerivs+i) != 0.0) && + * (*(h1dashTcoeffs+i)!=0.0)) { eq2LTE += + * model->LTRAadmit*fabs(*(SecondDerivs+i) * (h1dashTcoeffs+i)); } } } + * + * if (tdover) { + */ +/* interpolate */ + +/* + * FirstSecondDeriv = *(SecondDerivs + isaved - 1) * f1 + *(SecondDerivs + + * isaved) * f2 + *(SecondDerivs + isaved + 1) * f3; + * + * eq1LTE += model->LTRAadmit*fabs(FirstSecondDeriv * h3dashTfirstCoeff); + * + * if (model->LTRAlteConType != LTRA_MOD_HALFCONTROL) { for (i = + * model->LTRAh3dashIndex; i > 0; i--) { if ((*(SecondDerivs+i) != 0.0) && + * (*(h3dashTcoeffs+i)!=0.0)) { eq1LTE += + * model->LTRAadmit*fabs(*(SecondDerivs+i) * (h3dashTcoeffs+i)); } } } } + * + */ +/* end LTEs for convolution with v2 */ + +/* LTE for convolution with i1 */ +/* get divided differences for i1 (2nd derivative estimates) */ + +/* + * if (tdover) { FirstSecondDeriv = + * LTRAdivDiffs(SecondDerivs,instance->LTRAi1, (ckt->CKTrhsOld + + * instance->LTRAbrEq1),curtime, ckt->CKTtimePoints,ckt->CKTtimeIndex); + * + */ +/* interpolate */ + +/* + * FirstSecondDeriv = *(SecondDerivs + isaved - 1) * f1 + *(SecondDerivs + + * isaved) * f2 + *(SecondDerivs + isaved + 1) * f3; + * + * eq2LTE += fabs(FirstSecondDeriv * h2TfirstCoeff); + * + * if (model->LTRAlteConType != LTRA_MOD_HALFCONTROL) { for (i = + * model->LTRAh2Index; i > 0; i--) { if ((*(SecondDerivs+i) != 0.0) && + * (*(h2Tcoeffs+i)!=0.0)) { eq2LTE += model->LTRAadmit*fabs(*(SecondDerivs+i) * + * (h2Tcoeffs+i)); } } } + * + * } */ +/* end LTE for convolution with i1 */ + +/* LTE for convolution with i2 */ +/* get divided differences for i2 (2nd derivative estimates) */ + +/* + * if (tdover) { FirstSecondDeriv = + * LTRAdivDiffs(SecondDerivs,instance->LTRAi2, (ckt->CKTrhsOld + + * instance->LTRAbrEq2),curtime, ckt->CKTtimePoints,ckt->CKTtimeIndex); + * + */ +/* interpolate */ + +/* + * FirstSecondDeriv = *(SecondDerivs + isaved - 1) * f1 + *(SecondDerivs + + * isaved) * f2 + *(SecondDerivs + isaved + 1) * f3; + * + * eq1LTE += fabs(FirstSecondDeriv * h2TfirstCoeff); + * + * if (model->LTRAlteConType != LTRA_MOD_HALFCONTROL) { for (i = + * model->LTRAh2Index; i > 0; i--) { if ((*(SecondDerivs+i) != 0.0) && + * (*(h2Tcoeffs+i)!=0.0)) { eq1LTE += model->LTRAadmit*fabs(*(SecondDerivs+i) * + * (h2Tcoeffs+i)); } } } } + * + */ +/* end LTE for convolution with i1 */ + +#ifdef LTRADEBUG +/* + * fprintf(stdout,"%s: LTE/input for Eq1 at time %g is: %g\n", + * instance->LTRAname, curtime, eq1LTE/instance->LTRAinput1); + * fprintf(stdout,"%s: LTE/input for Eq2 at time %g is: %g\n", + * instance->LTRAname, curtime, eq2LTE/instance->LTRAinput1); + * fprintf(stdout,"\n"); + */ +#endif + +/* + * FREE(SecondDerivs); FREE(h1dashTcoeffs); FREE(h2Tcoeffs); + * FREE(h3dashTcoeffs); + * + * return(fabs(eq1LTE) + fabs(eq2LTE)); } + */ + +/* + * LTRAh3dashCoeffSetup sets up the coefficient list for h3dash for the + * special case where G=0, * returns the coefficient at (current_timepoint-T) + */ + +/* + * double + * LTRAh3dashCoeffSetup(coefflist,listsize,T,beta,curtime,timelist,timeindex,a + * uxindexptr) double *coefflist, *timelist; int listsize, timeindex; double + * T, curtime, beta; int *auxindexptr; + * + * { unsigned exact; double returnval, delta1, delta2; double dummy1, dummy2; + * double lolimit1,lolimit2,hilimit1,hilimit2; double + * lovalue1,lovalue2,hivalue1,hivalue2; int i,auxindex; + * + */ +/* coefflist should already have been allocated to the necessary size */ + +/* + * #ifdef LTRAdebug if (listsize <= timeindex) { printf("LTRAcoeffSetup: not + * enough space in coefflist\n"); } #endif + * + * + */ +/* + * we assume a piecewise linear function, and we calculate the coefficients + * using this assumption in the integration of the function + */ + +/* + * if (T == 0.0) { auxindex = timeindex; } else { + * + * if (curtime - T <= 0.0) { for (i =0; i<= timeindex; i++) { (coefflist + i) = + * 0.0; } auxindexptr = 0; return(0.0); } else { exact = 0; for (i = + * timeindex; i>= 0; i--) { if (curtime - *(timelist + i) == T) { exact =1; + * break; } if (curtime - *(timelist + i) > T) break; } + * + * #ifdef LTRADEBUG if ((i < 0) || ((i==0) && (exact==1))) + * printf("LTRAcoeffSetup: i <= 0: some mistake!\n"); #endif + * + * if (exact == 1) { auxindex = i-1; } else { auxindex = i; } } } + */ +/* the first coefficient */ + +/* + * delta1 = curtime -T - *(timelist + auxindex); lolimit1 = T; hilimit1 = T + + * delta1; lovalue1 = 0.0; + *//* E3dash should be consistent with this */ +/* + * hivalue1 = LTRArlcH3dashIntFunc(hilimit1,T,beta); dummy1 = + * intlinfunc(lolimit1,hilimit1,lovalue1, hivalue1,lolimit1,hilimit1)/delta1; + * returnval = dummy1; + * + * + */ +/* the coefficients for the rest of the timepoints */ +/* + * for (i=auxindex; i>0; i--) { + * + * delta2 = delta1; + *//* previous delta1 */ +/* lolimit2 = lolimit1; *//* previous lolimit1 */ +/* hilimit2 = hilimit1; *//* previous hilimit1 */ +/* lovalue2 = lovalue1; *//* previous lovalue1 */ +/* hivalue2 = hivalue1; *//* previous hivalue1 */ +/* dummy2 = dummy1; *//* previous dummy1 */ +/* + * delta1 = *(timelist + i) - *(timelist + i - 1); lolimit1 = hilimit2; + * hilimit1 = curtime - *(timelist + i - 1); lovalue1 = hivalue2; hivalue1 = + * LTRArlcH3dashIntFunc(hilimit1,T,beta); dummy1 = + * intlinfunc(lolimit1,hilimit1,lovalue1,hivalue1,lolimit1,hilimit1)/delta1; + * + * (coefflist + i) = dummy1 - dummy2; } auxindexptr = auxindex; + * return(returnval); } + */ + +/* + * LTRAh1dashCoeffSetup sets up the coefficient list for h1dash in the + * special case where G=0 returns the coefficient at current_timepoint + */ +/* + * double + * LTRAh1dashCoeffSetup(coefflist,listsize,beta,curtime,timelist,timeindex,aux + *strchrptr) double *coefflist, *timelist; int listsize, timeindex; double + * beta, curtime; int *auxindexptr; + * + * { double returnval, delta1, delta2; double dummy1, dummy2; double + * lolimit1,lolimit2,hilimit1,hilimit2; double + * lovalue1,lovalue2,hivalue1,hivalue2; int i,auxindex; + * + */ +/* coefflist should already have been allocated to the necessary size */ + +/* + * #ifdef LTRAdebug if (listsize <= timeindex) { + * printf("LTRAh1dashCoeffSetup: not enough space in coefflist\n"); } #endif + * + * + * + * auxindex = timeindex; + * + */ +/* the first coefficient */ +/* + * delta1 = curtime - *(timelist + auxindex); lolimit1 = 0.0; hilimit1 = + * delta1; lovalue1 = 0.0; hivalue1 = + * LTRArlcH1dashTwiceIntFunc(hilimit1,beta); dummy1 = hivalue1/delta1; + * returnval = dummy1; + * + * + * + */ +/* the coefficients for the rest of the timepoints */ + +/* + * for (i=auxindex; i>0; i--) { + * + * delta2 = delta1; + *//* previous delta1 */ +/* lolimit2 = lolimit1; *//* previous lolimit1 */ +/* hilimit2 = hilimit1; *//* previous hilimit1 */ +/* lovalue2 = lovalue1; *//* previous lovalue1 */ +/* hivalue2 = hivalue1; *//* previous hivalue1 */ +/* dummy2 = dummy1; *//* previous dummy1 */ +/* + * delta1 = *(timelist + i) - *(timelist + i - 1); lolimit1 = hilimit2; + * hilimit1 = curtime - *(timelist + i - 1); lovalue1 = hivalue2; hivalue1 = + * LTRArlcH1dashTwiceIntFunc(hilimit1,beta); dummy1 = (hivalue1 - + * lovalue1)/delta1; + * + * (coefflist + i) = dummy1 - dummy2; } auxindexptr = auxindex; + * return(returnval); } + */ diff --git a/src/spicelib/devices/ltra/ltrampar.c b/src/spicelib/devices/ltra/ltrampar.c new file mode 100644 index 000000000..11d8e1fb3 --- /dev/null +++ b/src/spicelib/devices/ltra/ltrampar.c @@ -0,0 +1,120 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +/* + * This routine sets model parameters for LTRA lines in the circuit. + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAmParam(param, value, inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + LTRAmodel *mods = (LTRAmodel *) inModel; + + switch (param) { + case LTRA_MOD_LTRA: + break; + case LTRA_MOD_RELTOL: + mods->LTRAreltol = value->rValue; + mods->LTRAreltolGiven = TRUE; + break; + case LTRA_MOD_ABSTOL: + mods->LTRAabstol = value->rValue; + mods->LTRAabstolGiven = TRUE; + break; + case LTRA_MOD_STLINEREL: + mods->LTRAstLineReltol = value->rValue; + break; + case LTRA_MOD_STLINEABS: + mods->LTRAstLineAbstol = value->rValue; + break; + case LTRA_MOD_CHOPREL: + mods->LTRAchopReltol = value->rValue; + break; + case LTRA_MOD_CHOPABS: + mods->LTRAchopAbstol = value->rValue; + break; + case LTRA_MOD_TRUNCNR: + mods->LTRAtruncNR = TRUE; + break; + case LTRA_MOD_TRUNCDONTCUT: + mods->LTRAtruncDontCut = TRUE; + break; + case LTRA_MOD_R: + mods->LTRAresist = value->rValue; + mods->LTRAresistGiven = TRUE; + break; + case LTRA_MOD_L: + mods->LTRAinduct = value->rValue; + mods->LTRAinductGiven = TRUE; + break; + case LTRA_MOD_G: + mods->LTRAconduct = value->rValue; + mods->LTRAconductGiven = TRUE; + break; + case LTRA_MOD_C: + mods->LTRAcapac = value->rValue; + mods->LTRAcapacGiven = TRUE; + break; + case LTRA_MOD_LEN: + mods->LTRAlength = value->rValue; + mods->LTRAlengthGiven = TRUE; + break; + case LTRA_MOD_NL: + mods->LTRAnl = value->rValue; + mods->LTRAnlGiven = TRUE; + break; + case LTRA_MOD_FREQ: + mods->LTRAf = value->rValue; + mods->LTRAfGiven = TRUE; + break; + case LTRA_MOD_FULLCONTROL: + mods->LTRAlteConType = LTRA_MOD_FULLCONTROL; + break; + case LTRA_MOD_HALFCONTROL: + mods->LTRAlteConType = LTRA_MOD_HALFCONTROL; + break; + case LTRA_MOD_NOCONTROL: + mods->LTRAlteConType = LTRA_MOD_NOCONTROL; + break; + case LTRA_MOD_PRINT: + mods->LTRAprintFlag = TRUE; + break; + case LTRA_MOD_NOPRINT: + mods->LTRAprintFlag = FALSE; + break; + /* + * case LTRA_MOD_RONLY: mods->LTRArOnly= TRUE; break; + */ + case LTRA_MOD_STEPLIMIT: + mods->LTRAstepLimit = LTRA_MOD_STEPLIMIT; + break; + case LTRA_MOD_NOSTEPLIMIT: + mods->LTRAstepLimit = LTRA_MOD_NOSTEPLIMIT; + break; + case LTRA_MOD_LININTERP: + mods->LTRAhowToInterp = LTRA_MOD_LININTERP; + break; + case LTRA_MOD_QUADINTERP: + mods->LTRAhowToInterp = LTRA_MOD_QUADINTERP; + break; + case LTRA_MOD_MIXEDINTERP: + mods->LTRAhowToInterp = LTRA_MOD_MIXEDINTERP; + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/ltra/ltrapar.c b/src/spicelib/devices/ltra/ltrapar.c new file mode 100644 index 000000000..2cbd68e3a --- /dev/null +++ b/src/spicelib/devices/ltra/ltrapar.c @@ -0,0 +1,59 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "ltradefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +LTRAparam(param, value, inst, select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + LTRAinstance *here = (LTRAinstance *) inst; + switch (param) { + case LTRA_V1: + here->LTRAinitVolt1 = value->rValue; + here->LTRAicV1Given = TRUE; + break; + case LTRA_I1: + here->LTRAinitCur1 = value->rValue; + here->LTRAicC1Given = TRUE; + break; + case LTRA_V2: + here->LTRAinitVolt2 = value->rValue; + here->LTRAicV2Given = TRUE; + break; + case LTRA_I2: + here->LTRAinitCur2 = value->rValue; + here->LTRAicC2Given = TRUE; + break; + case LTRA_IC: + switch (value->v.numValue) { + case 4: + here->LTRAinitCur2 = *(value->v.vec.rVec + 3); + case 3: + here->LTRAinitVolt2 = *(value->v.vec.rVec + 2); + case 2: + here->LTRAinitCur1 = *(value->v.vec.rVec + 1); + case 1: + here->LTRAinitVolt1 = *(value->v.vec.rVec); + break; + default: + return (E_BADPARM); + } + break; + default: + return (E_BADPARM); + } + return (OK); +} diff --git a/src/spicelib/devices/ltra/ltraset.c b/src/spicelib/devices/ltra/ltraset.c new file mode 100644 index 000000000..2a7cdedb4 --- /dev/null +++ b/src/spicelib/devices/ltra/ltraset.c @@ -0,0 +1,254 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAsetup(matrix, inModel, ckt, state) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *state; +/* + * load the transmission line structure with those pointers needed later for + * fast matrix loading + */ +{ + register LTRAmodel *model = (LTRAmodel *) inModel; + register LTRAinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the transmission line models */ + for (; model != NULL; model = model->LTRAnextModel) { + + if (!model->LTRAnlGiven) { + model->LTRAnl = .25; + } + if (!model->LTRAfGiven) { + model->LTRAf = 1e9; + } + if (!model->LTRAreltolGiven) { + model->LTRAreltol = 1; + } + if (!model->LTRAabstolGiven) { + model->LTRAabstol = 1; + } + if (!model->LTRAresistGiven) { + (*(SPfrontEnd->IFerror)) (ERR_WARNING, + "%s: lossy line series resistance not given, assumed zero", + &(model->LTRAmodName)); + model->LTRAresist = 0.0; + /* return(E_BADPARM); */ + } + if (model->LTRAstLineReltol == 0.0) + model->LTRAstLineReltol = ckt->CKTreltol; + if (model->LTRAstLineAbstol == 0.0) + model->LTRAstLineAbstol = ckt->CKTabstol; + /* LTRAchopReltol and LTRAchopAbstol default zero */ + + if ((model->LTRAhowToInterp != LTRA_MOD_LININTERP) && + (model->LTRAhowToInterp != LTRA_MOD_QUADINTERP) && + (model->LTRAhowToInterp != LTRA_MOD_MIXEDINTERP)) { + + /* + * (*(SPfrontEnd->IFerror))(ERR_FATAL, "%s: have to specify one of + * lininterp, quadinterp or mixedinterp", &(model->LTRAmodName)); + * return(E_BADPARM); + */ + if (ckt->CKTtryToCompact) { + model->LTRAhowToInterp = LTRA_MOD_LININTERP; + (*(SPfrontEnd->IFerror)) (ERR_WARNING, + "%s: using linear interpolation because trytocompact option specified", + &(model->LTRAmodName)); + } else { + model->LTRAhowToInterp = LTRA_MOD_QUADINTERP; + } + } + if ((model->LTRAstepLimit != LTRA_MOD_NOSTEPLIMIT)) + model->LTRAstepLimit = LTRA_MOD_STEPLIMIT; +#ifdef notdef + if ((model->LTRAprintFlag != LTRA_MOD_PRINT)) + model->LTRAprintFlag = LTRA_MOD_NOPRINT; +#endif + if ((model->LTRAlteConType != LTRA_MOD_FULLCONTROL) && + (model->LTRAlteConType != LTRA_MOD_HALFCONTROL)) + model->LTRAlteConType = LTRA_MOD_NOCONTROL; + + if (!model->LTRAconductGiven) { + /* + * (*(SPfrontEnd->IFerror))(ERR_WARNING, "%s: lossy line parallel + * conductance not given, assumed zero", &(model->LTRAmodName)); + */ + model->LTRAconduct = 0.0; + /* return(E_BADPARM); */ + } + if (!model->LTRAinductGiven) { + (*(SPfrontEnd->IFerror)) (ERR_WARNING, + "%s: lossy line series inductance not given, assumed zero", + &(model->LTRAmodName)); + model->LTRAinduct = 0.0; + /* return(E_BADPARM); */ + } + if (!model->LTRAcapacGiven) { + (*(SPfrontEnd->IFerror)) (ERR_FATAL, + "%s: lossy line parallel capacitance not given, assumed zero", + &(model->LTRAmodName)); + model->LTRAcapac = 0.0; + /* return(E_BADPARM); */ + } + if (!model->LTRAlengthGiven) { + (*(SPfrontEnd->IFerror)) (ERR_FATAL, + "%s: lossy line length must be given", + &(model->LTRAmodName)); + return (E_BADPARM); + } + if ((model->LTRAresist == 0) && (model->LTRAconduct == 0) && + (model->LTRAcapac != 0) && (model->LTRAinduct != 0)) { + model->LTRAspecialCase = LTRA_MOD_LC; +#ifdef LTRADEBUG + (*(SPfrontEnd->IFerror)) (ERR_INFO, + "%s: lossless line", + &(model->LTRAmodName)); +#endif + } + if ((model->LTRAresist != 0) && (model->LTRAconduct == 0) && + (model->LTRAcapac != 0) && (model->LTRAinduct != 0)) { + model->LTRAspecialCase = LTRA_MOD_RLC; +#ifdef LTRADEBUG + (*(SPfrontEnd->IFerror)) (ERR_INFO, + "%s: RLC line", + &(model->LTRAmodName)); +#endif + } + if ((model->LTRAresist != 0) && (model->LTRAconduct == 0) && + (model->LTRAcapac != 0) && (model->LTRAinduct == 0)) { + model->LTRAspecialCase = LTRA_MOD_RC; +#ifdef LTRADEBUG + (*(SPfrontEnd->IFerror)) (ERR_INFO, + "%s: RC line", + &(model->LTRAmodName)); +#endif + } + if ((model->LTRAresist != 0) && (model->LTRAconduct == 0) && + (model->LTRAcapac == 0) && (model->LTRAinduct != 0)) { + model->LTRAspecialCase = LTRA_MOD_RL; + (*(SPfrontEnd->IFerror)) (ERR_FATAL, + "%s: RL line not supported yet", + &(model->LTRAmodName)); + return (E_BADPARM); +#ifdef LTRADEBUG +#endif + } + if ((model->LTRAresist != 0) && (model->LTRAconduct != 0) && + (model->LTRAcapac == 0) && (model->LTRAinduct == 0)) { + model->LTRAspecialCase = LTRA_MOD_RG; +#ifdef LTRADEBUG + (*(SPfrontEnd->IFerror)) (ERR_INFO, + "%s: RG line", + &(model->LTRAmodName)); +#endif + } + if ((model->LTRAconduct != 0) && ((model->LTRAcapac != 0) || + (model->LTRAinduct != 0))) { + model->LTRAspecialCase = LTRA_MOD_LTRA; + (*(SPfrontEnd->IFerror)) (ERR_FATAL, + "%s: Nonzero G (except RG) line not supported yet", + &(model->LTRAmodName)); + return (E_BADPARM); +#ifdef LTRADEBUG +#endif + } + if ((model->LTRAresist == 0.0 ? 0 : 1) + (model->LTRAconduct + == 0.0 ? 0 : 1) + (model->LTRAinduct == 0.0 ? 0 : 1) + + (model->LTRAcapac == 0.0 ? 0 : 1) <= 1) { + (*(SPfrontEnd->IFerror)) (ERR_FATAL, + "%s: At least two of R,L,G,C must be specified and nonzero", + &(model->LTRAmodName)); + return (E_BADPARM); + } + /* loop through all the instances of the model */ + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + + if (here->LTRAbrEq1 == 0) { + error = CKTmkVolt(ckt, &tmp, here->LTRAname, "i1"); + if (error) + return (error); + here->LTRAbrEq1 = tmp->number; + } + if (here->LTRAbrEq2 == 0) { + error = CKTmkVolt(ckt, &tmp, here->LTRAname, "i2"); + if (error) + return (error); + here->LTRAbrEq2 = tmp->number; + } + /* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(LTRAibr1Pos1Ptr, LTRAbrEq1, LTRAposNode1) + TSTALLOC(LTRAibr1Neg1Ptr, LTRAbrEq1, LTRAnegNode1) + TSTALLOC(LTRAibr1Pos2Ptr, LTRAbrEq1, LTRAposNode2) + TSTALLOC(LTRAibr1Neg2Ptr, LTRAbrEq1, LTRAnegNode2) + TSTALLOC(LTRAibr1Ibr1Ptr, LTRAbrEq1, LTRAbrEq1) + TSTALLOC(LTRAibr1Ibr2Ptr, LTRAbrEq1, LTRAbrEq2) + TSTALLOC(LTRAibr2Pos1Ptr, LTRAbrEq2, LTRAposNode1) + TSTALLOC(LTRAibr2Neg1Ptr, LTRAbrEq2, LTRAnegNode1) + TSTALLOC(LTRAibr2Pos2Ptr, LTRAbrEq2, LTRAposNode2) + TSTALLOC(LTRAibr2Neg2Ptr, LTRAbrEq2, LTRAnegNode2) + TSTALLOC(LTRAibr2Ibr1Ptr, LTRAbrEq2, LTRAbrEq1) + TSTALLOC(LTRAibr2Ibr2Ptr, LTRAbrEq2, LTRAbrEq2) + TSTALLOC(LTRApos1Ibr1Ptr, LTRAposNode1, LTRAbrEq1) + TSTALLOC(LTRAneg1Ibr1Ptr, LTRAnegNode1, LTRAbrEq1) + TSTALLOC(LTRApos2Ibr2Ptr, LTRAposNode2, LTRAbrEq2) + TSTALLOC(LTRAneg2Ibr2Ptr, LTRAnegNode2, LTRAbrEq2) + /* + * the following are done so that SMPpreOrder does not screw up on + * occasion - for example, when one end of the lossy line is hanging + */ + TSTALLOC(LTRApos1Pos1Ptr, LTRAposNode1, LTRAposNode1) + TSTALLOC(LTRAneg1Neg1Ptr, LTRAnegNode1, LTRAnegNode1) + TSTALLOC(LTRApos2Pos2Ptr, LTRAposNode2, LTRAposNode2) + TSTALLOC(LTRAneg2Neg2Ptr, LTRAnegNode2, LTRAnegNode2) + } + } + return (OK); +} + +int +LTRAunsetup(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + LTRAmodel *model; + LTRAinstance *here; + + for (model = (LTRAmodel *) inModel; model != NULL; + model = model->LTRAnextModel) { + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + if (here->LTRAbrEq1) { + CKTdltNNum(ckt, (void *) here->LTRAbrEq1); + here->LTRAbrEq1 = 0; + } + if (here->LTRAbrEq2) { + CKTdltNNum(ckt, (void *) here->LTRAbrEq2); + here->LTRAbrEq2 = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/ltra/ltratemp.c b/src/spicelib/devices/ltra/ltratemp.c new file mode 100644 index 000000000..6fc3bcd91 --- /dev/null +++ b/src/spicelib/devices/ltra/ltratemp.c @@ -0,0 +1,162 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +LTRAtemp(inModel, ckt) + GENmodel *inModel; + CKTcircuit *ckt; +/* + * pre-process parameters for later use + */ +{ + register LTRAmodel *model = (LTRAmodel *) inModel; + register LTRAinstance *here; + + /* loop through all the transmission line models */ + for (; model != NULL; model = model->LTRAnextModel) { + /* + * if(!model->LTRAtdGiven) { model->LTRAtd = model->LTRAnl/model->LTRAf; + * } + */ + switch (model->LTRAspecialCase) { + + case LTRA_MOD_LC: + model->LTRAimped = + sqrt(model->LTRAinduct / model->LTRAcapac); + model->LTRAadmit = 1 / model->LTRAimped; + model->LTRAtd = + sqrt(model->LTRAinduct * model->LTRAcapac) * model->LTRAlength; + model->LTRAattenuation = 1.0; + break; + + case LTRA_MOD_RLC: + model->LTRAimped = + sqrt(model->LTRAinduct / model->LTRAcapac); + model->LTRAadmit = 1 / model->LTRAimped; + model->LTRAtd = + sqrt(model->LTRAinduct * model->LTRAcapac) * model->LTRAlength; + model->LTRAalpha = + 0.5 * (model->LTRAresist / model->LTRAinduct + /* - model->LTRAconduct/model->LTRAcapac */ ); + model->LTRAbeta = model->LTRAalpha; + /* + * 0.5*(model->LTRAresist/model->LTRAinduct + + * model->LTRAconduct/model->LTRAcapac); + */ + model->LTRAattenuation = exp(-model->LTRAbeta * + model->LTRAtd); + if (model->LTRAalpha > 0.0) { + model->LTRAintH1dash = + /* + * sqrt(model->LTRAconduct/model->LTRAresist)/ model->LTRAadmit + */ -1.0; + model->LTRAintH2 = + /* + * exp(-model->LTRAlength*sqrt(model->LTRAconduct* + * model->LTRAresist)) + */ 1.0 - model->LTRAattenuation; + model->LTRAintH3dash = /* (model->LTRAintH1dash+1.0)* + (model->LTRAintH2+model->LTRAattenuation) */ - + model->LTRAattenuation; + } else if (model->LTRAalpha == 0.0) { + model->LTRAintH1dash = model->LTRAintH2 = + model->LTRAintH3dash = 0.0; + } else { +#ifdef LTRADEBUG + fprintf(stdout, "LTRAtemp: error: alpha < 0.0\n"); +#endif + } + + /* + * model->LTRAh1dashValues = (double *) NULL; model->LTRAh2Values = + * (double *) NULL; model->LTRAh3dashValues = (double *) NULL; + * + * model->LTRAh1dashOthVals = (double *) NULL; model->LTRAh2OthVals = + * (double *) NULL; model->LTRAh3dashOthVals = (double *) NULL; + */ + + model->LTRAh1dashCoeffs = (double *) NULL; + model->LTRAh2Coeffs = (double *) NULL; + model->LTRAh3dashCoeffs = (double *) NULL; + + if (!model->LTRAtruncDontCut) { + + double xbig, xsmall, xmid, y1big, y1small, y1mid; + double y2big, y2small, y2mid; + int done = 0, maxiter = 50, iters = 0; + + xbig = model->LTRAtd + /* ckt->CKTmaxStep */ 9 * model->LTRAtd; + /* hack! ckt is not yet initialised... */ + xsmall = model->LTRAtd; + xmid = 0.5 * (xbig + xsmall); + y1small = LTRArlcH2Func(xsmall, model->LTRAtd, model->LTRAalpha, model->LTRAbeta); + y2small = LTRArlcH3dashFunc(xsmall, model->LTRAtd, model->LTRAbeta, model->LTRAbeta); + iters = 0; + while (1) { + + iters++; + y1big = LTRArlcH2Func(xbig, model->LTRAtd, model->LTRAalpha, model->LTRAbeta); + y1mid = LTRArlcH2Func(xmid, model->LTRAtd, model->LTRAalpha, model->LTRAbeta); + y2big = LTRArlcH3dashFunc(xbig, model->LTRAtd, model->LTRAbeta, model->LTRAbeta); + y2mid = LTRArlcH3dashFunc(xmid, model->LTRAtd, model->LTRAbeta, model->LTRAbeta); + done = + LTRAstraightLineCheck(xbig, y1big, xmid, y1mid, xsmall, + y1small, model->LTRAstLineReltol, + model->LTRAstLineAbstol) + + LTRAstraightLineCheck(xbig, y1big, xmid, y1mid, xsmall, + y1small, model->LTRAstLineReltol, + model->LTRAstLineAbstol); + if ((done == 2) || (iters > maxiter)) + break; + xbig = xmid; + xmid = 0.5 * (xbig + xsmall); + } + model->LTRAmaxSafeStep = xbig - model->LTRAtd; + } + break; + + case LTRA_MOD_RC: + model->LTRAcByR = model->LTRAcapac / model->LTRAresist; + model->LTRArclsqr = model->LTRAresist * model->LTRAcapac + * model->LTRAlength * model->LTRAlength; + model->LTRAintH1dash = 0.0; + model->LTRAintH2 = 1.0; + model->LTRAintH3dash = 0.0; + + model->LTRAh1dashCoeffs = (double *) NULL; + model->LTRAh2Coeffs = (double *) NULL; + model->LTRAh3dashCoeffs = (double *) NULL; + + break; + + case LTRA_MOD_RG: + break; + + default: + return (E_BADPARM); + } + + /* loop through all the instances of the model */ + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + if (here->LTRAowner != ARCHme) continue; + + here->LTRAv1 = (double *) NULL; + here->LTRAi1 = (double *) NULL; + here->LTRAv2 = (double *) NULL; + here->LTRAi2 = (double *) NULL; + } + } + return (OK); +} diff --git a/src/spicelib/devices/ltra/ltratrun.c b/src/spicelib/devices/ltra/ltratrun.c new file mode 100644 index 000000000..550784ee8 --- /dev/null +++ b/src/spicelib/devices/ltra/ltratrun.c @@ -0,0 +1,201 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1990 Jaijeet S. Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "ltradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +LTRAtrunc(inModel, ckt, timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register LTRAmodel *model = (LTRAmodel *) inModel; + register LTRAinstance *here; + double i1, i2, i3, i4; + double i5, i6, d1, d2, d3, d4; + double tmp; + double tolerance; + double current_lte; + int maxiter = 2, iterations = 0; + double x, y, change, deriv, deriv_delta; + + /* loop through all the transmission line models */ + for (; model != NULL; model = model->LTRAnextModel) { + /* loop through all the instances of the model */ + for (here = model->LTRAinstances; here != NULL; + here = here->LTRAnextInstance) { + if (here->LTRAowner != ARCHme) continue; + + switch (model->LTRAspecialCase) { + + case LTRA_MOD_LC: + case LTRA_MOD_RLC: + + if (model->LTRAstepLimit == LTRA_MOD_STEPLIMIT) { + tmp = model->LTRAtd; + *timeStep = MIN(*timeStep, tmp); + } else { + i1 = ((*(ckt->CKTrhsOld + here->LTRAposNode2) + - *(ckt->CKTrhsOld + here->LTRAnegNode2)) + * model->LTRAadmit + *(ckt->CKTrhsOld + here->LTRAbrEq2)) + * model->LTRAattenuation; + i2 = (*(here->LTRAv2 + ckt->CKTtimeIndex) * + model->LTRAadmit + *(here->LTRAi2 + ckt->CKTtimeIndex)) + * model->LTRAattenuation; + i3 = (*(here->LTRAv2 + ckt->CKTtimeIndex - 1) * model->LTRAadmit + + *(here->LTRAi2 + ckt->CKTtimeIndex - 1)) + * model->LTRAattenuation; + i4 = ((*(ckt->CKTrhsOld + here->LTRAposNode1) - + *(ckt->CKTrhsOld + here->LTRAnegNode1)) + * model->LTRAadmit + *(ckt->CKTrhsOld + here->LTRAbrEq1)) + * model->LTRAattenuation; + i5 = (*(here->LTRAv1 + ckt->CKTtimeIndex) * model->LTRAadmit + + *(here->LTRAi1 + ckt->CKTtimeIndex)) + * model->LTRAattenuation; + i6 = (*(here->LTRAv1 + ckt->CKTtimeIndex - 1) * model->LTRAadmit + + *(here->LTRAi1 + ckt->CKTtimeIndex - 1)) + * model->LTRAattenuation; + /* + * d1 = (i1-i2)/ckt->CKTdeltaOld[1]; d2 = + * (i2-i3)/ckt->CKTdeltaOld[2]; d3 = (i4-i5)/ckt->CKTdeltaOld[1]; + * d4 = (i5-i6)/ckt->CKTdeltaOld[2]; + */ + d1 = (i1 - i2) / (ckt->CKTtime - *(ckt->CKTtimePoints + + ckt->CKTtimeIndex)); + d2 = (i2 - i3) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) + - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); + d3 = (i4 - i5) / (ckt->CKTtime - *(ckt->CKTtimePoints + + ckt->CKTtimeIndex)); + d4 = (i5 - i6) / (*(ckt->CKTtimePoints + ckt->CKTtimeIndex) + - *(ckt->CKTtimePoints + ckt->CKTtimeIndex - 1)); + + if ((fabs(d1 - d2) >= model->LTRAreltol * MAX(fabs(d1), fabs(d2)) + + model->LTRAabstol) || + (fabs(d3 - d4) >= model->LTRAreltol * MAX(fabs(d3), fabs(d4)) + + model->LTRAabstol)) { + /* derivitive changing - need to schedule after delay */ + /* the PREVIOUS point was the breakpoint */ + /* the previous timepoint plus the delay */ + + + /* + * tmp = *(ckt->CKTtimePoints + ckt->CKTtimeIndex) + + * model->LTRAtd; the work of a confused mind minus current time + * tmp -= ckt->CKTtime; + */ + + tmp = model->LTRAtd; + + *timeStep = MIN(*timeStep, tmp); + } + } + break; + + case LTRA_MOD_RC: + case LTRA_MOD_RG: + break; + + default: + return (E_BADPARM); + } + + + + + /* + * the above was for the parts of the equations that resemble the + * lossless equations. Now we need to estimate the local truncation + * error in each of the three convolution equations, and if possible + * adjust the timestep so that all of them remain within some bound. + * Unfortunately, the expression for the LTE in a convolution operation + * is complicated and costly to evaluate; in addition, no explicit + * inverse exists. + * + * So what we do here (for the moment) is check to see the current error + * is acceptable. If so, the timestep is not changed. If not, then an + * estimate is made for the new timestep using a few iterations of the + * newton-raphson method. + * + * modification: we change the timestep to half its previous value + */ + + if ((model->LTRAspecialCase == LTRA_MOD_RLC) && + (!model->LTRAtruncDontCut)) { + *timeStep = MIN(*timeStep, model->LTRAmaxSafeStep); + } + if (model->LTRAlteConType != LTRA_MOD_NOCONTROL) { + switch (model->LTRAspecialCase) { + + case LTRA_MOD_RLC: + case LTRA_MOD_RC: + tolerance = ckt->CKTtrtol * (ckt->CKTreltol * ( + fabs(here->LTRAinput1) + fabs(here->LTRAinput2)) + + ckt->CKTabstol); + + current_lte = LTRAlteCalculate(ckt, (GENmodel *) model, + (GENinstance *) here, ckt->CKTtime); + + if (current_lte >= tolerance) { + if (model->LTRAtruncNR) { + + x = ckt->CKTtime; + y = current_lte; + while (1) { + deriv_delta = 0.01 * (x - *(ckt->CKTtimePoints + + ckt->CKTtimeIndex)); + +#ifdef LTRADEBUG + if (deriv_delta <= 0.0) + fprintf(stdout, "LTRAtrunc: error: timestep is now less than zero\n"); +#endif + deriv = LTRAlteCalculate(ckt, (GENmodel *) model, + (GENinstance *) here, + x + deriv_delta) - y; + deriv /= deriv_delta; + change = (tolerance - y) / deriv; + x += change; + if (maxiter == 0) { + if (fabs(change) <= fabs(deriv_delta)) + break; + } else { + iterations++; + if (iterations >= maxiter) + break; + } + y = LTRAlteCalculate(ckt, (GENmodel *) model, + (GENinstance *) here, x); + } + + tmp = x - *(ckt->CKTtimePoints + ckt->CKTtimeIndex); + *timeStep = MIN(*timeStep, tmp); + } else + *timeStep *= 0.5; + } + break; + + case LTRA_MOD_RG: + case LTRA_MOD_LC: + break; + + default: + return (E_BADPARM); + } + } + } +#ifdef LTRADEBUG + if (*timeStep >= model->LTRAtd) { + fprintf(stdout, "LTRAtrunc: Warning: Timestep bigger than delay of line %s\n", model->LTRAmodName); + fflush(stdout); + } +#endif + } + return (OK); +} diff --git a/src/spicelib/devices/mes/ChangeLog b/src/spicelib/devices/mes/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/mes/Makefile.am b/src/spicelib/devices/mes/Makefile.am new file mode 100644 index 000000000..515f2a4fb --- /dev/null +++ b/src/spicelib/devices/mes/Makefile.am @@ -0,0 +1,31 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libmes.la + +libmes_la_SOURCES = \ + mes.c \ + mesacl.c \ + mesask.c \ + mesdefs.h \ + mesdel.c \ + mesdest.c \ + mesdisto.c \ + mesdset.c \ + mesext.h \ + mesgetic.c \ + mesitf.h \ + mesload.c \ + mesmask.c \ + mesmdel.c \ + mesmpar.c \ + mesnoise.c \ + mesparam.c \ + mespzld.c \ + messetup.c \ + mestemp.c \ + mestrunc.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/mes/mes.c b/src/spicelib/devices/mes/mes.c new file mode 100644 index 000000000..45c4bed16 --- /dev/null +++ b/src/spicelib/devices/mes/mes.c @@ -0,0 +1,76 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "mesdefs.h" +#include "suffix.h" + +IFparm MESpTable[] = { /* parameters */ + OPU("off", MES_OFF, IF_FLAG ,"Device initially off"), + IOPU("area", MES_AREA, IF_REAL ,"Area factor"), + IOPAU("icvds", MES_IC_VDS, IF_REAL ,"Initial D-S voltage"), + IOPAU("icvgs", MES_IC_VGS, IF_REAL ,"Initial G-S voltage"), + OPU("dnode", MES_DRAINNODE, IF_INTEGER,"Number of drain node"), + OPU("gnode", MES_GATENODE, IF_INTEGER,"Number of gate node"), + OPU("snode", MES_SOURCENODE, IF_INTEGER,"Number of source node"), + OPU("dprimenode",MES_DRAINPRIMENODE,IF_INTEGER,"Number of internal drain node"), + OPU("sprimenode",MES_SOURCEPRIMENODE,IF_INTEGER, + "Number of internal source node"), + OP("vgs", MES_VGS, IF_REAL,"Gate-Source voltage"), + OP("vgd", MES_VGD, IF_REAL,"Gate-Drain voltage"), + OP("cg", MES_CG, IF_REAL,"Gate capacitance"), + OP("cd", MES_CD, IF_REAL,"Drain capacitance"), + OP("cgd", MES_CGD, IF_REAL,"Gate-Drain capacitance"), + OP("gm", MES_GM, IF_REAL,"Transconductance"), + OP("gds", MES_GDS, IF_REAL,"Drain-Source conductance"), + OP("ggs", MES_GGS, IF_REAL,"Gate-Source conductance"), + OP("ggd", MES_GGD, IF_REAL,"Gate-Drain conductance"), + OP("cqgs", MES_CQGS, IF_REAL,"Capacitance due to gate-source charge storage"), + OP("cqgd", MES_CQGD, IF_REAL,"Capacitance due to gate-drain charge storage"), + OPU("qgs", MES_QGS, IF_REAL,"Gate-Source charge storage"), + OPU("qgd", MES_QGD, IF_REAL,"Gate-Drain charge storage"), + OP("is", MES_CS, IF_REAL ,"Source current"), + OP("p", MES_POWER, IF_REAL ,"Power dissipated by the mesfet") +}; + +IFparm MESmPTable[] = { /* model parameters */ + OP( "type", MES_MOD_TYPE, IF_FLAG,"N-type or P-type MESfet model"), + IP( "nmf", MES_MOD_NMF, IF_FLAG,"N type MESfet model"), + IP( "pmf", MES_MOD_PMF, IF_FLAG,"P type MESfet model"), + IOP( "vt0", MES_MOD_VTO, IF_REAL,"Pinch-off voltage"), + IOPR( "vto", MES_MOD_VTO, IF_REAL,"Pinch-off voltage"), + IOP( "alpha", MES_MOD_ALPHA, IF_REAL,"Saturation voltage parameter"), + IOP( "beta", MES_MOD_BETA, IF_REAL,"Transconductance parameter"), + IOP( "lambda", MES_MOD_LAMBDA, IF_REAL,"Channel length modulation parm."), + IOP( "b", MES_MOD_B, IF_REAL,"Doping tail extending parameter"), + IOP( "rd", MES_MOD_RD, IF_REAL,"Drain ohmic resistance"), + OPU( "gd", MES_MOD_DRAINCONDUCT, IF_REAL,"Drain conductance"), + IOP( "rs", MES_MOD_RS, IF_REAL,"Source ohmic resistance"), + OPU( "gs", MES_MOD_SOURCECONDUCT, IF_REAL,"Source conductance"), + IOPA( "cgs", MES_MOD_CGS, IF_REAL,"G-S junction capacitance"), + IOPA( "cgd", MES_MOD_CGD, IF_REAL,"G-D junction capacitance"), + IOP( "pb", MES_MOD_PB, IF_REAL,"Gate junction potential"), + IOP( "is", MES_MOD_IS, IF_REAL,"Junction saturation current"), + IOP( "fc", MES_MOD_FC, IF_REAL,"Forward bias junction fit parm."), + OP( "depl_cap", MES_MOD_DEPLETIONCAP, IF_REAL,"Depletion capacitance"), + OP( "vcrit", MES_MOD_VCRIT, IF_REAL,"Critical voltage"), + IOP("kf", MES_MOD_KF, IF_REAL,"Flicker noise coefficient"), + IOP("af", MES_MOD_AF, IF_REAL,"Flicker noise exponent") +}; + +char *MESnames[] = { + "Drain", + "Gate", + "Source" +}; + +int MESnSize = NUMELEMS(MESnames); +int MESpTSize = NUMELEMS(MESpTable); +int MESmPTSize = NUMELEMS(MESmPTable); +int MESiSize = sizeof(MESinstance); +int MESmSize = sizeof(MESmodel); diff --git a/src/spicelib/devices/mes/mesacl.c b/src/spicelib/devices/mes/mesacl.c new file mode 100644 index 000000000..4142e2e70 --- /dev/null +++ b/src/spicelib/devices/mes/mesacl.c @@ -0,0 +1,72 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MESacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MESmodel *model = (MESmodel*)inModel; + register MESinstance *here; + double gdpr; + double gspr; + double gm; + double gds; + double ggs; + double xgs; + double ggd; + double xgd; + + for( ; model != NULL; model = model->MESnextModel ) { + + for( here = model->MESinstances; here != NULL; + here = here->MESnextInstance) { + if (here->MESowner != ARCHme) continue; + + gdpr=model->MESdrainConduct * here->MESarea; + gspr=model->MESsourceConduct * here->MESarea; + gm= *(ckt->CKTstate0 + here->MESgm) ; + gds= *(ckt->CKTstate0 + here->MESgds) ; + ggs= *(ckt->CKTstate0 + here->MESggs) ; + xgs= *(ckt->CKTstate0 + here->MESqgs) * ckt->CKTomega ; + ggd= *(ckt->CKTstate0 + here->MESggd) ; + xgd= *(ckt->CKTstate0 + here->MESqgd) * ckt->CKTomega ; + *(here->MESdrainDrainPtr ) += gdpr; + *(here->MESgateGatePtr ) += ggd+ggs; + *(here->MESgateGatePtr +1) += xgd+xgs; + *(here->MESsourceSourcePtr ) += gspr; + *(here->MESdrainPrimeDrainPrimePtr ) += gdpr+gds+ggd; + *(here->MESdrainPrimeDrainPrimePtr +1) += xgd; + *(here->MESsourcePrimeSourcePrimePtr ) += gspr+gds+gm+ggs; + *(here->MESsourcePrimeSourcePrimePtr +1) += xgs; + *(here->MESdrainDrainPrimePtr ) -= gdpr; + *(here->MESgateDrainPrimePtr ) -= ggd; + *(here->MESgateDrainPrimePtr +1) -= xgd; + *(here->MESgateSourcePrimePtr ) -= ggs; + *(here->MESgateSourcePrimePtr +1) -= xgs; + *(here->MESsourceSourcePrimePtr ) -= gspr; + *(here->MESdrainPrimeDrainPtr ) -= gdpr; + *(here->MESdrainPrimeGatePtr ) += (-ggd+gm); + *(here->MESdrainPrimeGatePtr +1) -= xgd; + *(here->MESdrainPrimeSourcePrimePtr ) += (-gds-gm); + *(here->MESsourcePrimeGatePtr ) += (-ggs-gm); + *(here->MESsourcePrimeGatePtr +1) -= xgs; + *(here->MESsourcePrimeSourcePtr ) -= gspr; + *(here->MESsourcePrimeDrainPrimePtr ) -= gds; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mes/mesask.c b/src/spicelib/devices/mes/mesask.c new file mode 100644 index 000000000..7db5a5ad0 --- /dev/null +++ b/src/spicelib/devices/mes/mesask.c @@ -0,0 +1,124 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MESask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + MESinstance *here = (MESinstance*)inst; + static char *msg = "Current and power not available in ac analysis"; + switch(which) { + case MES_AREA: + value->rValue = here->MESarea; + return (OK); + case MES_IC_VDS: + value->rValue = here->MESicVDS; + return (OK); + case MES_IC_VGS: + value->rValue = here->MESicVGS; + return (OK); + case MES_OFF: + value->iValue = here->MESoff; + return (OK); + case MES_DRAINNODE: + value->iValue = here->MESdrainNode; + return (OK); + case MES_GATENODE: + value->iValue = here->MESgateNode; + return (OK); + case MES_SOURCENODE: + value->iValue = here->MESsourceNode; + return (OK); + case MES_DRAINPRIMENODE: + value->iValue = here->MESdrainPrimeNode; + return (OK); + case MES_VGS: + value->rValue = *(ckt->CKTstate0 + here->MESvgs); + return (OK); + case MES_VGD: + value->rValue = *(ckt->CKTstate0 + here->MESvgd); + return (OK); + case MES_CG: + value->rValue = *(ckt->CKTstate0 + here->MEScg); + return (OK); + case MES_CD: + value->rValue = *(ckt->CKTstate0 + here->MEScd); + return (OK); + case MES_CGD: + value->rValue = *(ckt->CKTstate0 + here->MEScgd); + return (OK); + case MES_GM: + value->rValue = *(ckt->CKTstate0 + here->MESgm); + return (OK); + case MES_GDS: + value->rValue = *(ckt->CKTstate0 + here->MESgds); + return (OK); + case MES_GGS: + value->rValue = *(ckt->CKTstate0 + here->MESggs); + return (OK); + case MES_GGD: + value->rValue = *(ckt->CKTstate0 + here->MESggd); + return (OK); + case MES_QGS: + value->rValue = *(ckt->CKTstate0 + here->MESqgs); + return (OK); + case MES_CQGS: + value->rValue = *(ckt->CKTstate0 + here->MEScqgs); + return (OK); + case MES_QGD: + value->rValue = *(ckt->CKTstate0 + here->MESqgd); + return (OK); + case MES_CQGD: + value->rValue = *(ckt->CKTstate0 + here->MEScqgd); + return (OK); + case MES_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MESask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -*(ckt->CKTstate0 + here->MEScd); + value->rValue -= *(ckt->CKTstate0 + here->MEScg); + } + return(OK); + case MES_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MESask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTstate0 + here->MEScd) * + *(ckt->CKTrhsOld + here->MESdrainNode); + value->rValue += *(ckt->CKTstate0 + here->MEScg) * + *(ckt->CKTrhsOld + here->MESgateNode); + value->rValue -= (*(ckt->CKTstate0+here->MEScd) + + *(ckt->CKTstate0 + here->MEScg)) * + *(ckt->CKTrhsOld + here->MESsourceNode); + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/mes/mesdefs.h b/src/spicelib/devices/mes/mesdefs.h new file mode 100644 index 000000000..1133fc6fe --- /dev/null +++ b/src/spicelib/devices/mes/mesdefs.h @@ -0,0 +1,278 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ + +#ifndef MES +#define MES + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + +#define MESnumStates 13 + + /* structures used to describe MESFET Transistors */ + + +/* information used to describe a single instance */ + +typedef struct sMESinstance { + struct sMESmodel *MESmodPtr; /* backpointer to model */ + struct sMESinstance *MESnextInstance; /* pointer to next instance of + * current model*/ + IFuid MESname; /* pointer to character string naming this instance */ + int MESowner; /* number of owner process */ + int MESstate; /* pointer to start of state vector for mesfet */ + int MESdrainNode; /* number of drain node of mesfet */ + int MESgateNode; /* number of gate node of mesfet */ + int MESsourceNode; /* number of source node of mesfet */ + int MESdrainPrimeNode; /* number of internal drain node of mesfet */ + int MESsourcePrimeNode; /* number of internal source node of mesfet */ + + double MESarea; /* area factor for the mesfet */ + double MESicVDS; /* initial condition voltage D-S*/ + double MESicVGS; /* initial condition voltage G-S*/ + double *MESdrainDrainPrimePtr; /* pointer to sparse matrix at + * (drain,drain prime) */ + double *MESgateDrainPrimePtr; /* pointer to sparse matrix at + * (gate,drain prime) */ + double *MESgateSourcePrimePtr; /* pointer to sparse matrix at + * (gate,source prime) */ + double *MESsourceSourcePrimePtr; /* pointer to sparse matrix at + * (source,source prime) */ + double *MESdrainPrimeDrainPtr; /* pointer to sparse matrix at + * (drain prime,drain) */ + double *MESdrainPrimeGatePtr; /* pointer to sparse matrix at + * (drain prime,gate) */ + double *MESdrainPrimeSourcePrimePtr; /* pointer to sparse matrix + * (drain prime,source prime) */ + double *MESsourcePrimeGatePtr; /* pointer to sparse matrix at + * (source prime,gate) */ + double *MESsourcePrimeSourcePtr; /* pointer to sparse matrix at + * (source prime,source) */ + double *MESsourcePrimeDrainPrimePtr; /* pointer to sparse matrix + * (source prime,drain prime) */ + double *MESdrainDrainPtr; /* pointer to sparse matrix at + * (drain,drain) */ + double *MESgateGatePtr; /* pointer to sparse matrix at + * (gate,gate) */ + double *MESsourceSourcePtr; /* pointer to sparse matrix at + * (source,source) */ + double *MESdrainPrimeDrainPrimePtr; /* pointer to sparse matrix + * (drain prime,drain prime) */ + double *MESsourcePrimeSourcePrimePtr; /* pointer to sparse matrix + * (source prime,source prime) */ + + int MESoff; /* 'off' flag for mesfet */ + unsigned MESareaGiven : 1; /* flag to indicate area was specified */ + unsigned MESicVDSGiven : 1; /* initial condition given flag for V D-S*/ + unsigned MESicVGSGiven : 1; /* initial condition given flag for V G-S*/ + +int MESmode; + +/* + * naming convention: + * x = vgs + * y = vgd + * z = vds + * cdr = cdrain + */ + +#define MESNDCOEFFS 27 + +#ifndef NODISTO + double MESdCoeffs[MESNDCOEFFS]; +#else /* NODISTO */ + double *MESdCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define cdr_x MESdCoeffs[0] +#define cdr_z MESdCoeffs[1] +#define cdr_x2 MESdCoeffs[2] +#define cdr_z2 MESdCoeffs[3] +#define cdr_xz MESdCoeffs[4] +#define cdr_x3 MESdCoeffs[5] +#define cdr_z3 MESdCoeffs[6] +#define cdr_x2z MESdCoeffs[7] +#define cdr_xz2 MESdCoeffs[8] + +#define ggs3 MESdCoeffs[9] +#define ggd3 MESdCoeffs[10] +#define ggs2 MESdCoeffs[11] +#define ggd2 MESdCoeffs[12] + +#define qgs_x2 MESdCoeffs[13] +#define qgs_y2 MESdCoeffs[14] +#define qgs_xy MESdCoeffs[15] +#define qgs_x3 MESdCoeffs[16] +#define qgs_y3 MESdCoeffs[17] +#define qgs_x2y MESdCoeffs[18] +#define qgs_xy2 MESdCoeffs[19] + +#define qgd_x2 MESdCoeffs[20] +#define qgd_y2 MESdCoeffs[21] +#define qgd_xy MESdCoeffs[22] +#define qgd_x3 MESdCoeffs[23] +#define qgd_y3 MESdCoeffs[24] +#define qgd_x2y MESdCoeffs[25] +#define qgd_xy2 MESdCoeffs[26] + +#endif + +/* indices to the array of MESFET noise sources */ + +#define MESRDNOIZ 0 +#define MESRSNOIZ 1 +#define MESIDNOIZ 2 +#define MESFLNOIZ 3 +#define MESTOTNOIZ 4 + +#define MESNSRCS 5 /* the number of MESFET noise sources */ + +#ifndef NONOISE + double MESnVar[NSTATVARS][MESNSRCS]; +#else /* NONOISE */ + double **MESnVar; +#endif /* NONOISE */ + +} MESinstance ; + +#define MESvgs MESstate +#define MESvgd MESstate+1 +#define MEScg MESstate+2 +#define MEScd MESstate+3 +#define MEScgd MESstate+4 +#define MESgm MESstate+5 +#define MESgds MESstate+6 +#define MESggs MESstate+7 +#define MESggd MESstate+8 +#define MESqgs MESstate+9 +#define MEScqgs MESstate+10 +#define MESqgd MESstate+11 +#define MEScqgd MESstate+12 + + +/* per model data */ + +typedef struct sMESmodel { /* model structure for a mesfet */ + int MESmodType; /* type index of this device type */ + struct sMESmodel *MESnextModel; /* pointer to next possible model in + * linked list */ + MESinstance * MESinstances; /* pointer to list of instances + * that have this model */ + IFuid MESmodName; /* pointer to character string naming this model */ + int MEStype; + + double MESthreshold; + double MESalpha; + double MESbeta; + double MESlModulation; + double MESb; + double MESdrainResist; + double MESsourceResist; + double MEScapGS; + double MEScapGD; + double MESgatePotential; + double MESgateSatCurrent; + double MESdepletionCapCoeff; + double MESfNcoef; + double MESfNexp; + + double MESdrainConduct; + double MESsourceConduct; + double MESdepletionCap; + double MESf1; + double MESf2; + double MESf3; + double MESvcrit; + + unsigned MESthresholdGiven : 1; + unsigned MESalphaGiven : 1; + unsigned MESbetaGiven : 1; + unsigned MESlModulationGiven : 1; + unsigned MESbGiven : 1; + unsigned MESdrainResistGiven : 1; + unsigned MESsourceResistGiven : 1; + unsigned MEScapGSGiven : 1; + unsigned MEScapGDGiven : 1; + unsigned MESgatePotentialGiven : 1; + unsigned MESgateSatCurrentGiven : 1; + unsigned MESdepletionCapCoeffGiven : 1; + unsigned MESfNcoefGiven : 1; + unsigned MESfNexpGiven : 1; + + +} MESmodel; + +#ifndef NMF + +#define NMF 1 +#define PMF -1 + +#endif /*NMF*/ + +/* device parameters */ +#define MES_AREA 1 +#define MES_IC_VDS 2 +#define MES_IC_VGS 3 +#define MES_IC 4 +#define MES_OFF 5 +#define MES_CS 6 +#define MES_POWER 7 + +/* model parameters */ +#define MES_MOD_VTO 101 +#define MES_MOD_ALPHA 102 +#define MES_MOD_BETA 103 +#define MES_MOD_LAMBDA 104 +#define MES_MOD_B 105 +#define MES_MOD_RD 106 +#define MES_MOD_RS 107 +#define MES_MOD_CGS 108 +#define MES_MOD_CGD 109 +#define MES_MOD_PB 110 +#define MES_MOD_IS 111 +#define MES_MOD_FC 112 +#define MES_MOD_NMF 113 +#define MES_MOD_PMF 114 +#define MES_MOD_KF 115 +#define MES_MOD_AF 116 + +/* device questions */ + +#define MES_DRAINNODE 201 +#define MES_GATENODE 202 +#define MES_SOURCENODE 203 +#define MES_DRAINPRIMENODE 204 +#define MES_SOURCEPRIMENODE 205 + +#define MES_VGS 206 +#define MES_VGD 207 +#define MES_CG 208 +#define MES_CD 209 +#define MES_CGD 210 +#define MES_GM 211 +#define MES_GDS 212 +#define MES_GGS 213 +#define MES_GGD 214 +#define MES_QGS 215 +#define MES_CQGS 216 +#define MES_QGD 217 +#define MES_CQGD 218 + +/* model questions */ + +#define MES_MOD_DRAINCONDUCT 301 +#define MES_MOD_SOURCECONDUCT 302 +#define MES_MOD_DEPLETIONCAP 303 +#define MES_MOD_VCRIT 304 +#define MES_MOD_TYPE 305 + +#include "mesext.h" + +#endif /*MES*/ diff --git a/src/spicelib/devices/mes/mesdel.c b/src/spicelib/devices/mes/mesdel.c new file mode 100644 index 000000000..b788dca18 --- /dev/null +++ b/src/spicelib/devices/mes/mesdel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MESdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + MESmodel *model = (MESmodel*)inModel; + MESinstance **fast = (MESinstance**)inst; + MESinstance **prev = NULL; + MESinstance *here; + + for( ; model ; model = model->MESnextModel) { + prev = &(model->MESinstances); + for(here = *prev; here ; here = *prev) { + if(here->MESname == name || (fast && here==*fast) ) { + *prev= here->MESnextInstance; + FREE(here); + return(OK); + } + prev = &(here->MESnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/mes/mesdest.c b/src/spicelib/devices/mes/mesdest.c new file mode 100644 index 000000000..6ce9cf95c --- /dev/null +++ b/src/spicelib/devices/mes/mesdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mesdefs.h" +#include "suffix.h" + + +void +MESdestroy(inModel) + GENmodel **inModel; +{ + MESmodel **model = (MESmodel**)inModel; + MESinstance *here; + MESinstance *prev = NULL; + MESmodel *mod = *model; + MESmodel *oldmod = NULL; + + for( ; mod ; mod = mod->MESnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (MESinstance *)NULL; + for(here = mod->MESinstances ; here ; here = here->MESnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/mes/mesdisto.c b/src/spicelib/devices/mes/mesdisto.c new file mode 100644 index 000000000..ef6f35319 --- /dev/null +++ b/src/spicelib/devices/mes/mesdisto.c @@ -0,0 +1,1215 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mesdefs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +MESdisto(mode,genmodel,ckt) + GENmodel *genmodel; + register CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + MESmodel *model = (MESmodel *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double temp, itemp; + register MESinstance *here; + +if (mode == D_SETUP) + return(MESdSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the MES models */ +for( ; model != NULL; model = model->MESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MESinstances; here != NULL ; + here=here->MESnextInstance) { + if (here->MESowner != ARCHme) continue; + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MESgateNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->MESgateNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->MESdrainPrimeNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->MESdrainPrimeNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn2F1(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + itemp = DFi2F1(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1n2F1(here->ggs2, + r1h1x, + i1h1x); + + itemp = D1i2F1(here->ggs2, + r1h1x, + i1h1x); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1n2F1(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + itemp = D1i2F1(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading qgs term */ + + temp = -ckt->CKTomega * + DFi2F1(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFn2F1(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* qgs term over */ + + /* loading qgd term */ + + temp = -ckt->CKTomega * + DFi2F1(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFn2F1(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* qgd term over */ + /* all done */ + + break; + + case D_THRF1: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MESgateNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->MESgateNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->MESdrainPrimeNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->MESdrainPrimeNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r2h11x = *(job->r2H11ptr + (here->MESgateNode)) - + *(job->r2H11ptr + (here->MESsourcePrimeNode)); + i2h11x = *(job->i2H11ptr + (here->MESgateNode)) - + *(job->i2H11ptr + (here->MESsourcePrimeNode)); + + r2h11y = *(job->r2H11ptr + (here->MESdrainPrimeNode)) - + *(job->r2H11ptr + (here->MESsourcePrimeNode)); + i2h11y = *(job->i2H11ptr + (here->MESdrainPrimeNode)) - + *(job->i2H11ptr + (here->MESsourcePrimeNode)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn3F1(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + here->cdr_x3, + here->cdr_z3, + 0.0, + here->cdr_x2z, + 0.0, + here->cdr_xz2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + itemp = DFi3F1(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + here->cdr_x3, + here->cdr_z3, + 0.0, + here->cdr_x2z, + 0.0, + here->cdr_xz2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1n3F1(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = D1i3F1(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1n3F1(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + itemp = D1i3F1(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading qgs term */ + + temp = -ckt->CKTomega* + DFi3F1(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + here->qgs_x3, + here->qgs_y3, + 0.0, + here->qgs_x2y, + 0.0, + here->qgs_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11x - r2h11y, + i2h11x - i2h11y, + 0.0, + 0.0); + + itemp =ckt->CKTomega* + DFn3F1(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + here->qgs_x3, + here->qgs_y3, + 0.0, + here->qgs_x2y, + 0.0, + here->qgs_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11x - r2h11y, + i2h11x - i2h11y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* qgs term over */ + + /* loading qgd term */ + + temp = -ckt->CKTomega* + DFi3F1(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + here->qgd_x3, + here->qgd_y3, + 0.0, + here->qgd_x2y, + 0.0, + here->qgd_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11x - r2h11y, + i2h11x - i2h11y, + 0.0, + 0.0); + + itemp =ckt->CKTomega* + DFn3F1(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + here->qgd_x3, + here->qgd_y3, + 0.0, + here->qgd_x2y, + 0.0, + here->qgd_xy2, + 0.0, + 0.0, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r2h11x, + i2h11x, + r2h11x - r2h11y, + i2h11x - i2h11y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* qgd term over */ + /* all done */ + + break; + case D_F1PF2: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra transform */ + r1h1x = *(job->r1H1ptr + (here->MESgateNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->MESgateNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->MESdrainPrimeNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->MESdrainPrimeNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r1h2x = *(job->r1H2ptr + (here->MESgateNode)) - + *(job->r1H2ptr + (here->MESsourcePrimeNode)); + i1h2x = *(job->i1H2ptr + (here->MESgateNode)) - + *(job->i1H2ptr + (here->MESsourcePrimeNode)); + + r1h2y = *(job->r1H2ptr + (here->MESdrainPrimeNode)) - + *(job->r1H2ptr + (here->MESsourcePrimeNode)); + i1h2y = *(job->i1H2ptr + (here->MESdrainPrimeNode)) - + *(job->i1H2ptr + (here->MESsourcePrimeNode)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); + + itemp = DFiF12(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1nF12(here->ggs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = D1iF12(here->ggs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1nF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + itemp = D1iF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading qgs term */ + + temp = -ckt->CKTomega* + DFiF12(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2x - r1h2y, + i1h2x - i1h2y, + 0.0, + 0.0); + + itemp =ckt->CKTomega* + DFnF12(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2x - r1h2y, + i1h2x - i1h2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* qgs term over */ + + /* loading qgd term */ + + temp = -ckt->CKTomega* + DFiF12(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2x - r1h2y, + i1h2x - i1h2y, + 0.0, + 0.0); + + itemp =ckt->CKTomega* + DFnF12(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1h2x, + i1h2x, + r1h2x - r1h2y, + i1h2x - i1h2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* qgd term over */ + /* all done */ + + break; + case D_F1MF2: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MESgateNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->MESgateNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->MESdrainPrimeNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->MESdrainPrimeNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r1hm2x = *(job->r1H2ptr + (here->MESgateNode)) - + *(job->r1H2ptr + (here->MESsourcePrimeNode)); + i1hm2x = -(*(job->i1H2ptr + (here->MESgateNode)) - + *(job->i1H2ptr + (here->MESsourcePrimeNode))); + + r1hm2y = *(job->r1H2ptr + (here->MESdrainPrimeNode)) - + *(job->r1H2ptr + (here->MESsourcePrimeNode)); + i1hm2y = -(*(job->i1H2ptr + (here->MESdrainPrimeNode)) - + *(job->i1H2ptr + (here->MESsourcePrimeNode))); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + itemp = DFiF12(here->cdr_x2, + here->cdr_z2, + 0.0, + here->cdr_xz, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1nF12(here->ggs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = D1iF12(here->ggs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1nF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + itemp = D1iF12(here->ggd2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading qgs term */ + + temp = -ckt->CKTomega* + DFiF12(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFnF12(here->qgs_x2, + here->qgs_y2, + 0.0, + here->qgs_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* qgs term over */ + + /* loading qgd term */ + + temp = -ckt->CKTomega* + DFiF12(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + 0.0, + 0.0); + + itemp = ckt->CKTomega* + DFnF12(here->qgd_x2, + here->qgd_y2, + 0.0, + here->qgd_xy, + 0.0, + 0.0, + r1h1x, + i1h1x, + r1h1x - r1h1y, + i1h1x - i1h1y, + 0.0, + 0.0, + r1hm2x, + i1hm2x, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + 0.0, + 0.0); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* qgd term over */ + /* all done */ + + break; + case D_2F1MF2: + /* x = vgs, y = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MESgateNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1x = *(job->i1H1ptr + (here->MESgateNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r1h1y = *(job->r1H1ptr + (here->MESdrainPrimeNode)) - + *(job->r1H1ptr + (here->MESsourcePrimeNode)); + i1h1y = *(job->i1H1ptr + (here->MESdrainPrimeNode)) - + *(job->i1H1ptr + (here->MESsourcePrimeNode)); + + r2h11x = *(job->r2H11ptr + (here->MESgateNode)) - + *(job->r2H11ptr + (here->MESsourcePrimeNode)); + i2h11x = *(job->i2H11ptr + (here->MESgateNode)) - + *(job->i2H11ptr + (here->MESsourcePrimeNode)); + + r2h11y = *(job->r2H11ptr + (here->MESdrainPrimeNode)) - + *(job->r2H11ptr + (here->MESsourcePrimeNode)); + i2h11y = *(job->i2H11ptr + (here->MESdrainPrimeNode)) - + *(job->i2H11ptr + (here->MESsourcePrimeNode)); + + r1hm2x = *(job->r1H2ptr + (here->MESgateNode)) - + *(job->r1H2ptr + (here->MESsourcePrimeNode)); + i1hm2x = -(*(job->i1H2ptr + (here->MESgateNode)) - + *(job->i1H2ptr + (here->MESsourcePrimeNode))); + + r1hm2y = *(job->r1H2ptr + (here->MESdrainPrimeNode)) - + *(job->r1H2ptr + (here->MESsourcePrimeNode)); + i1hm2y = -(*(job->i1H2ptr + (here->MESdrainPrimeNode)) - + *(job->i1H2ptr + (here->MESsourcePrimeNode))); + + r2h1m2x = *(job->r2H1m2ptr + (here->MESgateNode)) - + *(job->r2H1m2ptr + (here->MESsourcePrimeNode)); + i2h1m2x = *(job->i2H1m2ptr + (here->MESgateNode)) - + *(job->i2H1m2ptr + (here->MESsourcePrimeNode)); + + r2h1m2y = *(job->r2H1m2ptr + (here->MESdrainPrimeNode)) - + *(job->r2H1m2ptr + (here->MESsourcePrimeNode)); + i2h1m2y = *(job->i2H1m2ptr + (here->MESdrainPrimeNode)) + - *(job->i2H1m2ptr + (here->MESsourcePrimeNode)); + + /* loading starts here */ + /* loading cdrain term */ + + pass.cxx = here->cdr_x2; + pass.cyy = here->cdr_z2; + pass.czz = 0.0; + pass.cxy = here->cdr_xz; + pass.cyz = 0.0; + pass.cxz = 0.0; + pass.cxxx = here->cdr_x3; + pass.cyyy = here->cdr_z3; + pass.czzz = 0.0; + pass.cxxy = here->cdr_x2z; + pass.cxxz = 0.0; + pass.cxyy = here->cdr_xz2; + pass.cyyz = 0.0; + pass.cxzz = 0.0; + pass.cyzz = 0.0; + pass.cxyz = 0.0; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1y; + pass.i1h1y = i1h1y; + pass.r1h1z = 0.0; + pass.i1h1z = 0.0; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2y; + pass.i1h2y = i1hm2y; + pass.r1h2z = 0.0; + pass.i1h2z = 0.0; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11y; + pass.i2h11y = i2h11y; + pass.r2h11z = 0.0; + pass.i2h11z = 0.0; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2y; + pass.ih2f1f2y = i2h1m2y; + pass.h2f1f2z = 0.0; + pass.ih2f1f2z = 0.0; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) -= temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* cdrain term over */ + + /* loading ggs term */ + + temp = D1n2F12(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = D1i2F12(here->ggs2, + here->ggs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* ggs over */ + + /* loading ggd term */ + + temp = D1n2F12(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + itemp = D1i2F12(here->ggd2, + here->ggd3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* ggd over */ + + /* loading qgs term */ + + pass.cxx = here->qgs_x2; + pass.cyy = here->qgs_y2; + pass.czz = 0.0; + pass.cxy = here->qgs_xy; + pass.cyz = 0.0; + pass.cxz = 0.0; + pass.cxxx = here->qgs_x3; + pass.cyyy = here->qgs_y3; + pass.czzz = 0.0; + pass.cxxy = here->qgs_x2y; + pass.cxxz = 0.0; + pass.cxyy = here->qgs_xy2; + pass.cyyz = 0.0; + pass.cxzz = 0.0; + pass.cyzz = 0.0; + pass.cxyz = 0.0; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1x - r1h1y; + pass.i1h1y = i1h1x - i1h1y; + pass.r1h1z = 0.0; + pass.i1h1z = 0.0; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2x - r1hm2y; + pass.i1h2y = i1hm2x - i1hm2y; + pass.r1h2z = 0.0; + pass.i1h2z = 0.0; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11x - r2h11y; + pass.i2h11y = i2h11x - i2h11y; + pass.r2h11z = 0.0; + pass.i2h11z = 0.0; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2x - r2h1m2y; + pass.ih2f1f2y = i2h1m2x - i2h1m2y; + pass.h2f1f2z = 0.0; + pass.ih2f1f2z = 0.0; + temp = -ckt->CKTomega*DFi2F12(&pass); + + itemp = ckt->CKTomega*DFn2F12(&pass); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESsourcePrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESsourcePrimeNode)) += itemp; + + /* qgs term over */ + + /* loading qgd term */ + + pass.cxx = here->qgd_x2; + pass.cyy = here->qgd_y2; + pass.czz = 0.0; + pass.cxy = here->qgd_xy; + pass.cyz = 0.0; + pass.cxz = 0.0; + pass.cxxx = here->qgd_x3; + pass.cyyy = here->qgd_y3; + pass.czzz = 0.0; + pass.cxxy = here->qgd_x2y; + pass.cxxz = 0.0; + pass.cxyy = here->qgd_xy2; + pass.cyyz = 0.0; + pass.cxzz = 0.0; + pass.cyzz = 0.0; + pass.cxyz = 0.0; + pass.r1h1x = r1h1x; + pass.i1h1x = i1h1x; + pass.r1h1y = r1h1x - r1h1y; + pass.i1h1y = i1h1x - i1h1y; + pass.r1h1z = 0.0; + pass.i1h1z = 0.0; + pass.r1h2x = r1hm2x; + pass.i1h2x = i1hm2x; + pass.r1h2y = r1hm2x - r1hm2y; + pass.i1h2y = i1hm2x - i1hm2y; + pass.r1h2z = 0.0; + pass.i1h2z = 0.0; + pass.r2h11x = r2h11x; + pass.i2h11x = i2h11x; + pass.r2h11y = r2h11x - r2h11y; + pass.i2h11y = i2h11x - i2h11y; + pass.r2h11z = 0.0; + pass.i2h11z = 0.0; + pass.h2f1f2x = r2h1m2x; + pass.ih2f1f2x = i2h1m2x; + pass.h2f1f2y = r2h1m2x - r2h1m2y; + pass.ih2f1f2y = i2h1m2x - i2h1m2y; + pass.h2f1f2z = 0.0; + pass.ih2f1f2z = 0.0; + temp = -ckt->CKTomega*DFi2F12(&pass); + + itemp = ckt->CKTomega*DFn2F12(&pass); + + *(ckt->CKTrhs + (here->MESgateNode)) -= temp; + *(ckt->CKTirhs + (here->MESgateNode)) -= itemp; + *(ckt->CKTrhs + (here->MESdrainPrimeNode)) += temp; + *(ckt->CKTirhs + (here->MESdrainPrimeNode)) += itemp; + + /* qgd term over */ + /* all done */ + + break; + default: +; + } + } +} +return(OK); +} +else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/mes/mesdset.c b/src/spicelib/devices/mes/mesdset.c new file mode 100644 index 000000000..0a49e0f42 --- /dev/null +++ b/src/spicelib/devices/mes/mesdset.c @@ -0,0 +1,411 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "cktdefs.h" +#include "mesdefs.h" +#include "distodef.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MESdSetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register MESmodel *model = (MESmodel*)inModel; + register MESinstance *here; + double afact; + double beta; + double betap; + double cdrain; + double cg; + double cgd; + double csat; + double czgd; + double czgs; + double denom; + double evgd; + double evgs; + double gdpr; + double gspr; + double invdenom; + double lfact; + double phib; + double prod; + double vcap; + double vcrit; + double vds; + double vgd; + double vgs; + double vgst; + double vto; + double lggd1; + double lggd2; + double lggd3; + double lggs1; + double lggs2; + double lggs3; + Dderivs d_cdrain, d_qgs, d_qgd; + Dderivs d_p, d_q, d_r, d_zero; + + /* loop through all the models */ + for( ; model != NULL; model = model->MESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MESinstances; here != NULL ; + here=here->MESnextInstance) { + if (here->MESowner != ARCHme) continue; + + /* + * dc model parameters + */ + beta = model->MESbeta * here->MESarea; + gdpr = model->MESdrainConduct * here->MESarea; + gspr = model->MESsourceConduct * here->MESarea; + csat = model->MESgateSatCurrent * here->MESarea; + vcrit = model->MESvcrit; + vto = model->MESthreshold; + /* + * initialization + */ + /* + * compute new nonlinear branch voltages + */ + vgs = model->MEStype* + (*(ckt->CKTrhsOld+ here->MESgateNode)- + *(ckt->CKTrhsOld+ + here->MESsourcePrimeNode)); + vgd = model->MEStype* + (*(ckt->CKTrhsOld+here->MESgateNode)- + *(ckt->CKTrhsOld+ + here->MESdrainPrimeNode)); + + /* + * determine dc current and derivatives + */ + vds = vgs-vgd; + if (vgs <= -5*CONSTvt0) { + lggs1 = -csat/vgs+ckt->CKTgmin; + lggs2=lggs3=0; + cg = lggs1*vgs; + } else { + evgs = exp(vgs/CONSTvt0); + lggs1 = csat*evgs/CONSTvt0+ckt->CKTgmin; + lggs2 = (lggs1-ckt->CKTgmin)/(CONSTvt0*2); + lggs3 = lggs2/(3*CONSTvt0); + cg = csat*(evgs-1)+ckt->CKTgmin*vgs; + } + if (vgd <= -5*CONSTvt0) { + lggd1 = -csat/vgd+ckt->CKTgmin; + lggd2=lggd3=0; + cgd = lggd1*vgd; + } else { + evgd = exp(vgd/CONSTvt0); + lggd1 = csat*evgd/CONSTvt0+ckt->CKTgmin; + lggd2 = (lggd1-ckt->CKTgmin)/(CONSTvt0*2); + lggd3 = lggd2/(3*CONSTvt0); + cgd = csat*(evgd-1)+ckt->CKTgmin*vgd; + } + cg = cg+cgd; + /* + * compute drain current and derivitives for normal mode + */ + /* until now, we were using the real vgs, vgd, and vds */ + { + /* converting (temporarily) to local vgs, vgd, and vds */ + double vgsreal=vgs; + double vgdreal=vgd; + double vdsreal=vds; + Dderivs d_afact, d_lfact; + Dderivs d_betap, d_denom, d_invdenom; + Dderivs d_prod; + Dderivs d_vgst; + + if (vdsreal < 0.0) { + vgs = vgdreal; + vgd = vgsreal; + vds = -vdsreal; + here->MESmode = -1; + + /* source-drain interchange */ + + } + else + here->MESmode = 1; +d_p.value = 0.0; +d_p.d1_p = 1.0; +d_p.d1_q = 0.0; +d_p.d1_r = 0.0; +d_p.d2_p2 = 0.0; +d_p.d2_q2 = 0.0; +d_p.d2_r2 = 0.0; +d_p.d2_pq = 0.0; +d_p.d2_qr = 0.0; +d_p.d2_pr = 0.0; +d_p.d3_p3 = 0.0; +d_p.d3_q3 = 0.0; +d_p.d3_r3 = 0.0; +d_p.d3_p2r = 0.0; +d_p.d3_p2q = 0.0; +d_p.d3_q2r = 0.0; +d_p.d3_pq2 = 0.0; +d_p.d3_pr2 = 0.0; +d_p.d3_qr2 = 0.0; +d_p.d3_pqr = 0.0; + EqualDeriv(&d_q,&d_p); + EqualDeriv(&d_r,&d_p); + EqualDeriv(&d_zero,&d_p); + d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0; + d_q.d1_q = d_r.d1_r = 1.0; + d_p.value = vgs; d_r.value = vds; + + /* p =vgs; q= nothing in particular ; r = vds */ + + vgst = vgs-model->MESthreshold; + EqualDeriv(&d_vgst,&d_p); + d_vgst.value = vgst; + /* + * normal mode, cutoff region + */ + if (vgst <= 0) { + cdrain = 0; + EqualDeriv(&d_cdrain,&d_zero); + } else { + prod = 1 + model->MESlModulation * vds; + TimesDeriv(&d_prod,&d_r,model->MESlModulation); + d_prod.value = prod; + betap = beta * prod; + TimesDeriv(&d_betap,&d_prod,beta); + denom = 1 + model->MESb * vgst; + TimesDeriv(&d_denom,&d_vgst,model->MESb); + d_denom.value = denom; + invdenom = 1 / denom; + InvDeriv(&d_invdenom,&d_denom); + /* + * normal mode, saturation region + */ + cdrain = betap * vgst * vgst * invdenom; + MultDeriv(&d_cdrain,&d_betap,&d_vgst); + MultDeriv(&d_cdrain,&d_cdrain,&d_vgst); + MultDeriv(&d_cdrain,&d_cdrain,&d_invdenom); + + if (vds < ( 3 / model->MESalpha ) ) { + /* + * normal mode, linear region + */ + afact = 1 - model->MESalpha * vds / 3; + TimesDeriv(&d_afact,&d_r,-model->MESalpha/3.0); + d_afact.value = afact; + lfact = 1 - afact * afact * afact; + CubeDeriv(&d_lfact,&d_afact); + TimesDeriv(&d_lfact,&d_lfact,-1.0); + d_lfact.value += 1.0; + cdrain = betap*vgst*vgst*invdenom*lfact; + MultDeriv(&d_cdrain,&d_betap,&d_vgst); + MultDeriv(&d_cdrain,&d_cdrain,&d_vgst); + MultDeriv(&d_cdrain,&d_cdrain,&d_invdenom); + MultDeriv(&d_cdrain,&d_cdrain,&d_lfact); + } + } + + /* converting back to real vgs, vgd, vds */ + + if (here->MESmode == -1) { + vgs = vgsreal; + vgd = vgdreal; + vds = vdsreal; + } + } + /* + * charge storage elements + */ +{ /* code block */ +czgs = model->MEScapGS * here->MESarea; +czgd = model->MEScapGD * here->MESarea; +phib = model->MESgatePotential; +vcap = 1 / model->MESalpha; + +/* + * qgga = qggnew(vgs,vgd,phib,vcap,vto,czgs,czgd,&cgsna,&cgdna); + */ +/* function qggnew - private, used by MESload*/ +{ + double veroot,veff1,veff2,del,vnroot,vnew1,vnew3,vmax,ext; + double qroot,par1,cfact,cplus,cminus; + Dderivs d_vnroot; + Dderivs d_cgsnew, d_cgdnew, d_dummy, d_dummy2; + Dderivs d_ext, d_qroot, d_par1, d_cfact, d_cplus, d_cminus; + Dderivs d_veroot, d_veff1, d_veff2, d_vnew1, d_vnew3; + +/* now p=vgs, q=vgd, r= nothing */ + + d_q.value = vgd; d_p.value = vgs; + veroot = sqrt( (vgs - vgd) * (vgs - vgd) + vcap*vcap ); + TimesDeriv(&d_veroot,&d_q,-1.0); + PlusDeriv(&d_veroot,&d_veroot,&d_p); + MultDeriv(&d_veroot,&d_veroot,&d_veroot); + d_veroot.value += vcap*vcap; + SqrtDeriv(&d_veroot,&d_veroot); + veff1 = 0.5 * (vgs + vgd + veroot); + PlusDeriv(&d_veff1,&d_veroot,&d_p); + PlusDeriv(&d_veff1,&d_veff1,&d_q); + TimesDeriv(&d_veff1,&d_veff1,0.5); + veff2 = veff1 - veroot; + TimesDeriv(&d_veff2,&d_veroot,-1.0); + PlusDeriv(&d_veff2,&d_veff2,&d_veff1); + + del = 0.2;/*const*/ + vnroot = sqrt( (veff1 - vto)*(veff1 - vto) + del * del ); + EqualDeriv(&d_vnroot,&d_veff1); + d_vnroot.value -= vto; + MultDeriv(&d_vnroot,&d_vnroot,&d_vnroot); + d_vnroot.value += del*del; + SqrtDeriv(&d_vnroot,&d_vnroot); + vnew1 = 0.5 * (veff1 + vto + vnroot); + PlusDeriv(&d_vnew1,&d_veff1,&d_vnroot); + d_vnew1.value += vto; + TimesDeriv(&d_vnew1,&d_vnew1,0.5); + vnew3 = vnew1; + EqualDeriv(&d_vnew3,&d_vnew1); + vmax = 0.5;/*const*/ + if ( vnew1 < vmax ) { + ext=0; + EqualDeriv(&d_ext,&d_zero); + } else { + vnew1 = vmax; + EqualDeriv(&d_vnew1,&d_zero); + d_vnew1.value = vmax; + ext = (vnew3 - vmax)/sqrt(1 - vmax/phib); + EqualDeriv(&d_ext,&d_vnew3); + d_ext.value -= vmax; + TimesDeriv(&d_ext,&d_ext,1/sqrt(1 - vmax/phib)); + } + + qroot = sqrt(1 - vnew1/phib); + TimesDeriv(&d_qroot,&d_vnew1,-1/phib); + d_qroot.value += 1.0; + SqrtDeriv(&d_qroot,&d_qroot); + /* + * qggval = czgs * (2*phib*(1-qroot) + ext) + czgd*veff2; + */ + par1 = 0.5 * ( 1 + (veff1-vto)/vnroot); + EqualDeriv(&d_par1,&d_veff1); + d_par1.value -= vto; + DivDeriv(&d_par1,&d_par1,&d_vnroot); + d_par1.value += 1.0; + TimesDeriv(&d_par1,&d_par1,0.5); + cfact = (vgs- vgd)/veroot; + TimesDeriv(&d_cfact,&d_q,-1.0); + PlusDeriv(&d_cfact,&d_cfact,&d_p); + DivDeriv(&d_cfact,&d_cfact,&d_veroot); + cplus = 0.5 * (1 + cfact); + TimesDeriv(&d_cplus,&d_cfact,0.5); + d_cplus.value += 0.5; + cminus = cplus - cfact; + TimesDeriv(&d_cminus,&d_cfact,-0.5); + d_cminus.value += 0.5; + /* + *cgsnew = czgs/qroot*par1*cplus + czgd*cminus; + *cgdnew = czgs/qroot*par1*cminus + czgd*cplus; + * + * assuming qgs = vgs*cgsnew + * and qgd = vgd*cgsnew + * + * This is probably wrong but then so is the a.c. analysis + * routine and everything else + * + */ + + MultDeriv(&d_dummy,&d_qroot,&d_par1); + InvDeriv(&d_dummy,&d_dummy); + TimesDeriv(&d_dummy,&d_dummy,czgs); + + TimesDeriv(&d_cgsnew,&d_cminus,czgd); + MultDeriv(&d_dummy2,&d_dummy,&d_cplus); + PlusDeriv(&d_cgsnew,&d_cgsnew,&d_dummy2); + + TimesDeriv(&d_cgdnew,&d_cplus,czgd); + MultDeriv(&d_dummy2,&d_dummy,&d_cminus); + PlusDeriv(&d_cgdnew,&d_cgdnew,&d_dummy2); + + MultDeriv(&d_qgs,&d_cgsnew,&d_p); + MultDeriv(&d_qgd,&d_cgdnew,&d_q); +} +} + + + if (here->MESmode == 1) + { + /* normal mode - no source-drain interchange */ +here->cdr_x = d_cdrain.d1_p; +here->cdr_z = d_cdrain.d1_r; +here->cdr_x2 = d_cdrain.d2_p2; +here->cdr_z2 = d_cdrain.d2_r2; +here->cdr_xz = d_cdrain.d2_pr; +here->cdr_x3 = d_cdrain.d3_p3; +here->cdr_z3 = d_cdrain.d3_r3;; +here->cdr_x2z = d_cdrain.d3_p2r; +here->cdr_xz2 = d_cdrain.d3_pr2; + +} else { + /* + * inverse mode - source and drain interchanged + */ + + +here->cdr_x = -d_cdrain.d1_p; +here->cdr_z = d_cdrain.d1_p + d_cdrain.d1_r; +here->cdr_x2 = -d_cdrain.d2_p2; +here->cdr_z2 = -(d_cdrain.d2_p2 + d_cdrain.d2_r2 + 2*d_cdrain.d2_pr); +here->cdr_xz = d_cdrain.d2_p2 + d_cdrain.d2_pr; +here->cdr_x3 = -d_cdrain.d3_p3; +here->cdr_z3 = d_cdrain.d3_p3 + d_cdrain.d3_r3 + 3*(d_cdrain.d3_p2r + d_cdrain.d3_pr2 ) ; +here->cdr_x2z = d_cdrain.d3_p3 + d_cdrain.d3_p2r; +here->cdr_xz2 = -(d_cdrain.d3_p3 + 2*d_cdrain.d3_p2r + d_cdrain.d3_pr2); + +} + +/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ + +here->cdr_x2 = 0.5*model->MEStype*here->cdr_x2; +here->cdr_z2 = 0.5*model->MEStype*here->cdr_z2; +here->cdr_xz = model->MEStype*here->cdr_xz; +here->cdr_x3 = here->cdr_x3/6.; +here->cdr_z3 = here->cdr_z3/6.; +here->cdr_x2z = 0.5*here->cdr_x2z; +here->cdr_xz2 = 0.5*here->cdr_xz2; + + +here->ggs3 = lggs3; +here->ggd3 = lggd3; +here->ggs2 = model->MEStype*lggs2; +here->ggd2 = model->MEStype*lggd2; + +here->qgs_x2 = 0.5*model->MEStype*d_qgs.d2_p2; +here->qgs_y2 = 0.5*model->MEStype*d_qgs.d2_q2; +here->qgs_xy = model->MEStype*d_qgs.d2_pq; +here->qgs_x3 = d_qgs.d3_p3/6.; +here->qgs_y3 = d_qgs.d3_q3/6.; +here->qgs_x2y = 0.5*d_qgs.d3_p2q; +here->qgs_xy2 = 0.5*d_qgs.d3_pq2; + +here->qgd_x2 = 0.5*model->MEStype*d_qgd.d2_p2; +here->qgd_y2 = 0.5*model->MEStype*d_qgd.d2_q2; +here->qgd_xy = model->MEStype*d_qgd.d2_pq; +here->qgd_x3 = d_qgd.d3_p3/6.; +here->qgd_y3 = d_qgd.d3_q3/6.; +here->qgd_x2y = 0.5*d_qgd.d3_p2q; +here->qgd_xy2 = 0.5*d_qgd.d3_pq2; + } + } + return(OK); +} diff --git a/src/spicelib/devices/mes/mesext.h b/src/spicelib/devices/mes/mesext.h new file mode 100644 index 000000000..7185d6867 --- /dev/null +++ b/src/spicelib/devices/mes/mesext.h @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ + +#ifdef __STDC__ +extern int MESacLoad(GENmodel*,CKTcircuit*); +extern int MESask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int MESdelete(GENmodel*,IFuid,GENinstance**); +extern void MESdestroy(GENmodel**); +extern int MESgetic(GENmodel*,CKTcircuit*); +extern int MESload(GENmodel*,CKTcircuit*); +extern int MESmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int MESmDelete(GENmodel**,IFuid,GENmodel*); +extern int MESmParam(int,IFvalue*,GENmodel*); +extern int MESparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int MESpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int MESsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int MESunsetup(GENmodel*,CKTcircuit*); +extern int MEStemp(GENmodel*,CKTcircuit*); +extern int MEStrunc(GENmodel*,CKTcircuit*,double*); +extern int MESdisto(int,GENmodel*,CKTcircuit*); +extern int MESnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ +extern int MESacLoad(); +extern int MESask(); +extern int MESdelete(); +extern void MESdestroy(); +extern int MESgetic(); +extern int MESload(); +extern int MESmAsk(); +extern int MESmDelete(); +extern int MESmParam(); +extern int MESparam(); +extern int MESpzLoad(); +extern int MESsetup(); +extern int MESunsetup(); +extern int MEStemp(); +extern int MEStrunc(); +extern int MESdisto(); +extern int MESnoise(); +#endif /* stdc */ diff --git a/src/spicelib/devices/mes/mesgetic.c b/src/spicelib/devices/mes/mesgetic.c new file mode 100644 index 000000000..6cd90f9e2 --- /dev/null +++ b/src/spicelib/devices/mes/mesgetic.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MESgetic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MESmodel *model = (MESmodel*)inModel; + MESinstance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->MESnextModel) { + for(here = model->MESinstances; here ; here = here->MESnextInstance) { + if (here->MESowner != ARCHme) continue; + + if(!here->MESicVDSGiven) { + here->MESicVDS = + *(ckt->CKTrhs + here->MESdrainNode) - + *(ckt->CKTrhs + here->MESsourceNode); + } + if(!here->MESicVGSGiven) { + here->MESicVGS = + *(ckt->CKTrhs + here->MESgateNode) - + *(ckt->CKTrhs + here->MESsourceNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mes/mesitf.h b/src/spicelib/devices/mes/mesitf.h new file mode 100644 index 000000000..e4f18bc62 --- /dev/null +++ b/src/spicelib/devices/mes/mesitf.h @@ -0,0 +1,87 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_mes + +#ifndef DEV_MES +#define DEV_MES + +#include "mesext.h" +extern IFparm MESpTable[ ]; +extern IFparm MESmPTable[ ]; +extern char *MESnames[ ]; +extern int MESpTSize; +extern int MESmPTSize; +extern int MESnSize; +extern int MESiSize; +extern int MESmSize; + +SPICEdev MESinfo = { + { + "MES", + "GaAs MESFET model", + + &MESnSize, + &MESnSize, + MESnames, + + &MESpTSize, + MESpTable, + + &MESmPTSize, + MESmPTable, + DEV_DEFAULT + }, + + MESparam, + MESmParam, + MESload, + MESsetup, + MESunsetup, + MESsetup, + MEStemp, + MEStrunc, + NULL, + MESacLoad, + NULL, + MESdestroy, +#ifdef DELETES + MESmDelete, + MESdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + MESgetic, + MESask, + MESmAsk, +#ifdef AN_pz + MESpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#ifdef AN_disto + MESdisto, +#else /* AN_disto */ + NULL, +#endif /* AN_disto */ +#ifdef AN_noise + MESnoise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &MESiSize, + &MESmSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/mes/mesload.c b/src/spicelib/devices/mes/mesload.c new file mode 100644 index 000000000..7e2cc1f9e --- /dev/null +++ b/src/spicelib/devices/mes/mesload.c @@ -0,0 +1,492 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "cktdefs.h" +#include "mesdefs.h" +#include "const.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +/* forward declaraction of our helper function */ +#ifdef __STDC__ +static double qggnew(double,double,double,double,double,double,double, + double*,double*); +#else /* stdc */ +static double qggnew(); +#endif /* stdc */ + +int +MESload(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + register MESmodel *model = (MESmodel*)inModel; + register MESinstance *here; + double afact; + double beta; + double betap; + double capgd; + double capgs; + double cd; + double cdhat; + double cdrain; + double cdreq; + double ceq; + double ceqgd; + double ceqgs; + double cg; + double cgd; + double cgdna,cgdnb,cgdnc,cgdnd; + double cghat; + double cgsna,cgsnb,cgsnc,cgsnd; + double csat; + double czgd; + double czgs; + double delvds; + double delvgd; + double delvgs; + double denom; + double evgd; + double evgs; + double gdpr; + double gds; + double geq; + double ggd; + double ggs; + double gm; + double gspr; + double invdenom; + double lfact; + double phib; + double prod; + double qgga,qggb,qggc,qggd; + double vcap; + double vcrit; + double vds; + double vgd; + double vgd1; + double vgdt; + double vgs; + double vgs1; + double vgst; + double vto; + double xfact; + int icheck; + int ichk1; + int error; + + /* loop through all the models */ + for( ; model != NULL; model = model->MESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MESinstances; here != NULL ; + here=here->MESnextInstance) { + if (here->MESowner != ARCHme) continue; + + /* + * dc model parameters + */ + beta = model->MESbeta * here->MESarea; + gdpr = model->MESdrainConduct * here->MESarea; + gspr = model->MESsourceConduct * here->MESarea; + csat = model->MESgateSatCurrent * here->MESarea; + vcrit = model->MESvcrit; + vto = model->MESthreshold; + /* + * initialization + */ + icheck = 1; + if( ckt->CKTmode & MODEINITSMSIG) { + vgs = *(ckt->CKTstate0 + here->MESvgs); + vgd = *(ckt->CKTstate0 + here->MESvgd); + } else if (ckt->CKTmode & MODEINITTRAN) { + vgs = *(ckt->CKTstate1 + here->MESvgs); + vgd = *(ckt->CKTstate1 + here->MESvgd); + } else if ( (ckt->CKTmode & MODEINITJCT) && + (ckt->CKTmode & MODETRANOP) && + (ckt->CKTmode & MODEUIC) ) { + vds = model->MEStype*here->MESicVDS; + vgs = model->MEStype*here->MESicVGS; + vgd = vgs-vds; + } else if ( (ckt->CKTmode & MODEINITJCT) && + (here->MESoff == 0) ) { + vgs = -1; + vgd = -1; + } else if( (ckt->CKTmode & MODEINITJCT) || + ((ckt->CKTmode & MODEINITFIX) && (here->MESoff))) { + vgs = 0; + vgd = 0; + } else { +#ifndef PREDICTOR + if(ckt->CKTmode & MODEINITPRED) { + xfact = ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->MESvgs) = + *(ckt->CKTstate1 + here->MESvgs); + vgs = (1+xfact) * *(ckt->CKTstate1 + here->MESvgs) - + xfact * *(ckt->CKTstate2 + here->MESvgs); + *(ckt->CKTstate0 + here->MESvgd) = + *(ckt->CKTstate1 + here->MESvgd); + vgd = (1+xfact)* *(ckt->CKTstate1 + here->MESvgd) - + xfact * *(ckt->CKTstate2 + here->MESvgd); + *(ckt->CKTstate0 + here->MEScg) = + *(ckt->CKTstate1 + here->MEScg); + *(ckt->CKTstate0 + here->MEScd) = + *(ckt->CKTstate1 + here->MEScd); + *(ckt->CKTstate0 + here->MEScgd) = + *(ckt->CKTstate1 + here->MEScgd); + *(ckt->CKTstate0 + here->MESgm) = + *(ckt->CKTstate1 + here->MESgm); + *(ckt->CKTstate0 + here->MESgds) = + *(ckt->CKTstate1 + here->MESgds); + *(ckt->CKTstate0 + here->MESggs) = + *(ckt->CKTstate1 + here->MESggs); + *(ckt->CKTstate0 + here->MESggd) = + *(ckt->CKTstate1 + here->MESggd); + } else { +#endif /* PREDICTOR */ + /* + * compute new nonlinear branch voltages + */ + vgs = model->MEStype* + (*(ckt->CKTrhsOld+ here->MESgateNode)- + *(ckt->CKTrhsOld+ + here->MESsourcePrimeNode)); + vgd = model->MEStype* + (*(ckt->CKTrhsOld+here->MESgateNode)- + *(ckt->CKTrhsOld+ + here->MESdrainPrimeNode)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + delvgs=vgs - *(ckt->CKTstate0 + here->MESvgs); + delvgd=vgd - *(ckt->CKTstate0 + here->MESvgd); + delvds=delvgs - delvgd; + cghat= *(ckt->CKTstate0 + here->MEScg) + + *(ckt->CKTstate0 + here->MESggd)*delvgd + + *(ckt->CKTstate0 + here->MESggs)*delvgs; + cdhat= *(ckt->CKTstate0 + here->MEScd) + + *(ckt->CKTstate0 + here->MESgm)*delvgs + + *(ckt->CKTstate0 + here->MESgds)*delvds - + *(ckt->CKTstate0 + here->MESggd)*delvgd; + /* + * bypass if solution has not changed + */ + if((ckt->CKTbypass) && + (!(ckt->CKTmode & MODEINITPRED)) && + (fabs(delvgs) < ckt->CKTreltol*MAX(fabs(vgs), + fabs(*(ckt->CKTstate0 + here->MESvgs)))+ + ckt->CKTvoltTol) ) + if ( (fabs(delvgd) < ckt->CKTreltol*MAX(fabs(vgd), + fabs(*(ckt->CKTstate0 + here->MESvgd)))+ + ckt->CKTvoltTol)) + if ( (fabs(cghat-*(ckt->CKTstate0 + here->MEScg)) + < ckt->CKTreltol*MAX(fabs(cghat), + fabs(*(ckt->CKTstate0 + here->MEScg)))+ + ckt->CKTabstol) ) if ( /* hack - expression too big */ + (fabs(cdhat-*(ckt->CKTstate0 + here->MEScd)) + < ckt->CKTreltol*MAX(fabs(cdhat), + fabs(*(ckt->CKTstate0 + here->MEScd)))+ + ckt->CKTabstol) ) { + + /* we can do a bypass */ + vgs= *(ckt->CKTstate0 + here->MESvgs); + vgd= *(ckt->CKTstate0 + here->MESvgd); + vds= vgs-vgd; + cg= *(ckt->CKTstate0 + here->MEScg); + cd= *(ckt->CKTstate0 + here->MEScd); + cgd= *(ckt->CKTstate0 + here->MEScgd); + gm= *(ckt->CKTstate0 + here->MESgm); + gds= *(ckt->CKTstate0 + here->MESgds); + ggs= *(ckt->CKTstate0 + here->MESggs); + ggd= *(ckt->CKTstate0 + here->MESggd); + goto load; + } + /* + * limit nonlinear branch voltages + */ + ichk1=1; + vgs = DEVpnjlim(vgs,*(ckt->CKTstate0 + here->MESvgs),CONSTvt0, + vcrit, &icheck); + vgd = DEVpnjlim(vgd,*(ckt->CKTstate0 + here->MESvgd),CONSTvt0, + vcrit,&ichk1); + if (ichk1 == 1) { + icheck=1; + } + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MESvgs), + model->MESthreshold); + vgd = DEVfetlim(vgd,*(ckt->CKTstate0 + here->MESvgd), + model->MESthreshold); + } + /* + * determine dc current and derivatives + */ + vds = vgs-vgd; + if (vgs <= -5*CONSTvt0) { + ggs = -csat/vgs+ckt->CKTgmin; + cg = ggs*vgs; + } else { + evgs = exp(vgs/CONSTvt0); + ggs = csat*evgs/CONSTvt0+ckt->CKTgmin; + cg = csat*(evgs-1)+ckt->CKTgmin*vgs; + } + if (vgd <= -5*CONSTvt0) { + ggd = -csat/vgd+ckt->CKTgmin; + cgd = ggd*vgd; + } else { + evgd = exp(vgd/CONSTvt0); + ggd = csat*evgd/CONSTvt0+ckt->CKTgmin; + cgd = csat*(evgd-1)+ckt->CKTgmin*vgd; + } + cg = cg+cgd; + /* + * compute drain current and derivitives for normal mode + */ + if (vds >= 0) { + vgst = vgs-model->MESthreshold; + /* + * normal mode, cutoff region + */ + if (vgst <= 0) { + cdrain = 0; + gm = 0; + gds = 0; + } else { + prod = 1 + model->MESlModulation * vds; + betap = beta * prod; + denom = 1 + model->MESb * vgst; + invdenom = 1 / denom; + if (vds >= ( 3 / model->MESalpha ) ) { + /* + * normal mode, saturation region + */ + cdrain = betap * vgst * vgst * invdenom; + gm = betap * vgst * (1 + denom) * invdenom * invdenom; + gds = model->MESlModulation * beta * vgst * vgst * + invdenom; + } else { + /* + * normal mode, linear region + */ + afact = 1 - model->MESalpha * vds / 3; + lfact = 1 - afact * afact * afact; + cdrain = betap * vgst * vgst * invdenom * lfact; + gm = betap * vgst * (1 + denom) * invdenom * invdenom * + lfact; + gds = beta * vgst * vgst * invdenom * (model->MESalpha * + afact * afact * prod + lfact * + model->MESlModulation); + } + } + } else { + /* + * compute drain current and derivitives for inverse mode + */ + vgdt = vgd - model->MESthreshold; + if (vgdt <= 0) { + /* + * inverse mode, cutoff region + */ + cdrain = 0; + gm = 0; + gds = 0; + } else { + /* + * inverse mode, saturation region + */ + prod = 1 - model->MESlModulation * vds; + betap = beta * prod; + denom = 1 + model->MESb * vgdt; + invdenom = 1 / denom; + if ( -vds >= ( 3 / model->MESalpha ) ) { + cdrain = -betap * vgdt * vgdt * invdenom; + gm = -betap * vgdt * (1 + denom) * invdenom * invdenom; + gds = model->MESlModulation * beta * vgdt * vgdt * + invdenom-gm; + } else { + /* + * inverse mode, linear region + */ + afact = 1 + model->MESalpha * vds / 3; + lfact = 1 - afact * afact * afact; + cdrain = -betap * vgdt * vgdt * invdenom * lfact; + gm = -betap * vgdt * (1 + denom) * invdenom * + invdenom * lfact; + gds = beta * vgdt * vgdt * invdenom * (model->MESalpha * + afact * afact * prod + lfact * + model->MESlModulation)-gm; + } + } + } + /* + * compute equivalent drain current source + */ + cd = cdrain - cgd; + if ( (ckt->CKTmode & (MODETRAN|MODEINITSMSIG)) || + ((ckt->CKTmode & MODETRANOP) && (ckt->CKTmode & MODEUIC)) ){ + /* + * charge storage elements + */ + czgs = model->MEScapGS * here->MESarea; + czgd = model->MEScapGD * here->MESarea; + phib = model->MESgatePotential; + vgs1 = *(ckt->CKTstate1 + here->MESvgs); + vgd1 = *(ckt->CKTstate1 + here->MESvgd); + vcap = 1 / model->MESalpha; + + qgga = qggnew(vgs,vgd,phib,vcap,vto,czgs,czgd,&cgsna,&cgdna); + qggb = qggnew(vgs1,vgd,phib,vcap,vto,czgs,czgd,&cgsnb,&cgdnb); + qggc = qggnew(vgs,vgd1,phib,vcap,vto,czgs,czgd,&cgsnc,&cgdnc); + qggd = qggnew(vgs1,vgd1,phib,vcap,vto,czgs,czgd,&cgsnd,&cgdnd); + + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->MESqgs) = qgga; + *(ckt->CKTstate1 + here->MESqgd) = qgga; + } + *(ckt->CKTstate0+here->MESqgs) = *(ckt->CKTstate1+here->MESqgs) + + 0.5 * (qgga-qggb + qggc-qggd); + *(ckt->CKTstate0+here->MESqgd) = *(ckt->CKTstate1+here->MESqgd) + + 0.5 * (qgga-qggc + qggb-qggd); + capgs = cgsna; + capgd = cgdna; + + /* + * store small-signal parameters + */ + if( (!(ckt->CKTmode & MODETRANOP)) || + (!(ckt->CKTmode & MODEUIC)) ) { + if(ckt->CKTmode & MODEINITSMSIG) { + *(ckt->CKTstate0 + here->MESqgs) = capgs; + *(ckt->CKTstate0 + here->MESqgd) = capgd; + continue; /*go to 1000*/ + } + /* + * transient analysis + */ + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->MESqgs) = + *(ckt->CKTstate0 + here->MESqgs); + *(ckt->CKTstate1 + here->MESqgd) = + *(ckt->CKTstate0 + here->MESqgd); + } + error = NIintegrate(ckt,&geq,&ceq,capgs,here->MESqgs); + if(error) return(error); + ggs = ggs + geq; + cg = cg + *(ckt->CKTstate0 + here->MEScqgs); + error = NIintegrate(ckt,&geq,&ceq,capgd,here->MESqgd); + if(error) return(error); + ggd = ggd + geq; + cg = cg + *(ckt->CKTstate0 + here->MEScqgd); + cd = cd - *(ckt->CKTstate0 + here->MEScqgd); + cgd = cgd + *(ckt->CKTstate0 + here->MEScqgd); + if (ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->MEScqgs) = + *(ckt->CKTstate0 + here->MEScqgs); + *(ckt->CKTstate1 + here->MEScqgd) = + *(ckt->CKTstate0 + here->MEScqgd); + } + } + } + /* + * check convergence + */ + if( (!(ckt->CKTmode & MODEINITFIX)) | (!(ckt->CKTmode & MODEUIC))) { + if( (icheck == 1) +#ifndef NEWCONV +/* XXX */ +#endif /* NEWCONV */ + || (fabs(cghat-cg) >= ckt->CKTreltol* + MAX(fabs(cghat),fabs(cg))+ckt->CKTabstol) || + (fabs(cdhat-cd) > ckt->CKTreltol* + MAX(fabs(cdhat),fabs(cd))+ckt->CKTabstol) + ) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } + *(ckt->CKTstate0 + here->MESvgs) = vgs; + *(ckt->CKTstate0 + here->MESvgd) = vgd; + *(ckt->CKTstate0 + here->MEScg) = cg; + *(ckt->CKTstate0 + here->MEScd) = cd; + *(ckt->CKTstate0 + here->MEScgd) = cgd; + *(ckt->CKTstate0 + here->MESgm) = gm; + *(ckt->CKTstate0 + here->MESgds) = gds; + *(ckt->CKTstate0 + here->MESggs) = ggs; + *(ckt->CKTstate0 + here->MESggd) = ggd; + /* + * load current vector + */ +load: + ceqgd=model->MEStype*(cgd-ggd*vgd); + ceqgs=model->MEStype*((cg-cgd)-ggs*vgs); + cdreq=model->MEStype*((cd+cgd)-gds*vds-gm*vgs); + *(ckt->CKTrhs + here->MESgateNode) += (-ceqgs-ceqgd); + *(ckt->CKTrhs + here->MESdrainPrimeNode) += + (-cdreq+ceqgd); + *(ckt->CKTrhs + here->MESsourcePrimeNode) += + (cdreq+ceqgs); + /* + * load y matrix + */ + *(here->MESdrainDrainPrimePtr) += (-gdpr); + *(here->MESgateDrainPrimePtr) += (-ggd); + *(here->MESgateSourcePrimePtr) += (-ggs); + *(here->MESsourceSourcePrimePtr) += (-gspr); + *(here->MESdrainPrimeDrainPtr) += (-gdpr); + *(here->MESdrainPrimeGatePtr) += (gm-ggd); + *(here->MESdrainPrimeSourcePrimePtr) += (-gds-gm); + *(here->MESsourcePrimeGatePtr) += (-ggs-gm); + *(here->MESsourcePrimeSourcePtr) += (-gspr); + *(here->MESsourcePrimeDrainPrimePtr) += (-gds); + *(here->MESdrainDrainPtr) += (gdpr); + *(here->MESgateGatePtr) += (ggd+ggs); + *(here->MESsourceSourcePtr) += (gspr); + *(here->MESdrainPrimeDrainPrimePtr) += (gdpr+gds+ggd); + *(here->MESsourcePrimeSourcePrimePtr) += (gspr+gds+gm+ggs); + } + } + return(OK); +} + + +/* function qggnew - private, used by MESload*/ +static double +qggnew(vgs,vgd,phib,vcap,vto,cgs,cgd,cgsnew,cgdnew) + double vgs,vgd,phib,vcap,vto,cgs,cgd,*cgsnew,*cgdnew; +{ + double veroot,veff1,veff2,del,vnroot,vnew1,vnew3,vmax,ext; + double qroot,qggval,par1,cfact,cplus,cminus; + + veroot = sqrt( (vgs - vgd) * (vgs - vgd) + vcap*vcap ); + veff1 = 0.5 * (vgs + vgd + veroot); + veff2 = veff1 - veroot; + del = 0.2; + vnroot = sqrt( (veff1 - vto)*(veff1 - vto) + del * del ); + vnew1 = 0.5 * (veff1 + vto + vnroot); + vnew3 = vnew1; + vmax = 0.5; + if ( vnew1 < vmax ) { + ext=0; + } else { + vnew1 = vmax; + ext = (vnew3 - vmax)/sqrt(1 - vmax/phib); + } + + qroot = sqrt(1 - vnew1/phib); + qggval = cgs * (2*phib*(1-qroot) + ext) + cgd*veff2; + par1 = 0.5 * ( 1 + (veff1-vto)/vnroot); + cfact = (vgs- vgd)/veroot; + cplus = 0.5 * (1 + cfact); + cminus = cplus - cfact; + *cgsnew = cgs/qroot*par1*cplus + cgd*cminus; + *cgdnew = cgs/qroot*par1*cminus + cgd*cplus; + return(qggval); +} diff --git a/src/spicelib/devices/mes/mesmask.c b/src/spicelib/devices/mes/mesmask.c new file mode 100644 index 000000000..75c2eaadb --- /dev/null +++ b/src/spicelib/devices/mes/mesmask.c @@ -0,0 +1,85 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MESmAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + MESmodel *here = (MESmodel*)inst; + switch(which) { + case MES_MOD_VTO: + value->rValue = here->MESthreshold; + return (OK); + case MES_MOD_ALPHA: + value->rValue = here->MESalpha; + return (OK); + case MES_MOD_BETA: + value->rValue = here->MESbeta; + return (OK); + case MES_MOD_LAMBDA: + value->rValue = here->MESlModulation; + return (OK); + case MES_MOD_B: + value->rValue = here->MESb; + return (OK); + case MES_MOD_RD: + value->rValue = here->MESdrainResist; + return (OK); + case MES_MOD_RS: + value->rValue = here->MESsourceResist; + return (OK); + case MES_MOD_CGS: + value->rValue = here->MEScapGS; + return (OK); + case MES_MOD_CGD: + value->rValue = here->MEScapGD; + return (OK); + case MES_MOD_PB: + value->rValue = here->MESgatePotential; + return (OK); + case MES_MOD_IS: + value->rValue = here->MESgateSatCurrent; + return (OK); + case MES_MOD_FC: + value->rValue = here->MESdepletionCapCoeff; + return (OK); + case MES_MOD_DRAINCONDUCT: + value->rValue = here->MESdrainConduct; + return (OK); + case MES_MOD_SOURCECONDUCT: + value->rValue = here->MESsourceConduct; + return (OK); + case MES_MOD_DEPLETIONCAP: + value->rValue = here->MESdepletionCap; + return (OK); + case MES_MOD_VCRIT: + value->rValue = here->MESvcrit; + return (OK); + case MES_MOD_TYPE: + if (here->MEStype == NMF) + value->sValue = "nmf"; + else + value->sValue = "pmf"; + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/mes/mesmdel.c b/src/spicelib/devices/mes/mesmdel.c new file mode 100644 index 000000000..1e02314ae --- /dev/null +++ b/src/spicelib/devices/mes/mesmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MESmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + MESmodel **model = (MESmodel**)inModel; + MESmodel *modfast = (MESmodel*)kill; + MESinstance *here; + MESinstance *prev = NULL; + MESmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->MESnextModel)) { + if( (*model)->MESmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->MESnextModel; /* cut deleted device out of list */ + for(here = (*model)->MESinstances ; here ; here = here->MESnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/mes/mesmpar.c b/src/spicelib/devices/mes/mesmpar.c new file mode 100644 index 000000000..3bea7f5a1 --- /dev/null +++ b/src/spicelib/devices/mes/mesmpar.c @@ -0,0 +1,94 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MESmParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + MESmodel *model = (MESmodel*)inModel; + switch(param) { + case MES_MOD_VTO: + model->MESthresholdGiven = TRUE; + model->MESthreshold = value->rValue; + break; + case MES_MOD_ALPHA: + model->MESalphaGiven = TRUE; + model->MESalpha = value->rValue; + break; + case MES_MOD_BETA: + model->MESbetaGiven = TRUE; + model->MESbeta = value->rValue; + break; + case MES_MOD_LAMBDA: + model->MESlModulationGiven = TRUE; + model->MESlModulation = value->rValue; + break; + case MES_MOD_B: + model->MESbGiven = TRUE; + model->MESb = value->rValue; + break; + case MES_MOD_RD: + model->MESdrainResistGiven = TRUE; + model->MESdrainResist = value->rValue; + break; + case MES_MOD_RS: + model->MESsourceResistGiven = TRUE; + model->MESsourceResist = value->rValue; + break; + case MES_MOD_CGS: + model->MEScapGSGiven = TRUE; + model->MEScapGS = value->rValue; + break; + case MES_MOD_CGD: + model->MEScapGDGiven = TRUE; + model->MEScapGD = value->rValue; + break; + case MES_MOD_PB: + model->MESgatePotentialGiven = TRUE; + model->MESgatePotential = value->rValue; + break; + case MES_MOD_IS: + model->MESgateSatCurrentGiven = TRUE; + model->MESgateSatCurrent = value->rValue; + break; + case MES_MOD_FC: + model->MESdepletionCapCoeffGiven = TRUE; + model->MESdepletionCapCoeff = value->rValue; + break; + case MES_MOD_NMF: + if(value->iValue) { + model->MEStype = NMF; + } + break; + case MES_MOD_PMF: + if(value->iValue) { + model->MEStype = PMF; + } + break; + case MES_MOD_KF: + model->MESfNcoefGiven = TRUE; + model->MESfNcoef = value->rValue; + break; + case MES_MOD_AF: + model->MESfNexpGiven = TRUE; + model->MESfNexp = value->rValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mes/mesnoise.c b/src/spicelib/devices/mes/mesnoise.c new file mode 100644 index 000000000..6b6b1b284 --- /dev/null +++ b/src/spicelib/devices/mes/mesnoise.c @@ -0,0 +1,222 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "mesdefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * MESnoise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MESFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MESFET's is summed with the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +MESnoise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + MESmodel *firstModel = (MESmodel *) genmodel; + register MESmodel *model; + register MESinstance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[MESNSRCS]; + double lnNdens[MESNSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *MESnNames[MESNSRCS] = { /* Note that we have to keep the order */ + "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ + "_rs", /* noise due to rs */ /* in MESdefs.h */ + "_id", /* noise due to id */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->MESnextModel) { + for (inst=model->MESinstances; inst != NULL; inst=inst->MESnextInstance) { + if (inst->MESowner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < MESNSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->MESname,MESnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + + case INT_NOIZ: + for (i=0; i < MESNSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->MESname,MESnNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->MESname,MESnNames[i]); + + /* + OUTname(name,SV_INPUT_NOISE_V_SQ); + data->numPlots += 2; + */ + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[MESRDNOIZ],&lnNdens[MESRDNOIZ], + ckt,THERMNOISE,inst->MESdrainPrimeNode,inst->MESdrainNode, + model->MESdrainConduct * inst->MESarea); + + NevalSrc(&noizDens[MESRSNOIZ],&lnNdens[MESRSNOIZ], + ckt,THERMNOISE,inst->MESsourcePrimeNode,inst->MESsourceNode, + model->MESsourceConduct * inst->MESarea); + + NevalSrc(&noizDens[MESIDNOIZ],&lnNdens[MESIDNOIZ], + ckt,THERMNOISE,inst->MESdrainPrimeNode, + inst->MESsourcePrimeNode, + (2.0/3.0 * fabs(*(ckt->CKTstate0 + inst->MESgm)))); + + NevalSrc(&noizDens[MESFLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->MESdrainPrimeNode, inst->MESsourcePrimeNode, + (double)0.0); + noizDens[MESFLNOIZ] *= model->MESfNcoef * + exp(model->MESfNexp * + log(MAX(fabs(*(ckt->CKTstate0 + inst->MEScd)),N_MINLOG))) / + data->freq; + lnNdens[MESFLNOIZ] = + log(MAX(noizDens[MESFLNOIZ],N_MINLOG)); + + noizDens[MESTOTNOIZ] = noizDens[MESRDNOIZ] + + noizDens[MESRSNOIZ] + + noizDens[MESIDNOIZ] + + noizDens[MESFLNOIZ]; + lnNdens[MESTOTNOIZ] = + log(MAX(noizDens[MESTOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[MESTOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < MESNSRCS; i++) { + inst->MESnVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < MESNSRCS; i++) { + inst->MESnVar[OUTNOIZ][i] = 0.0; + inst->MESnVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + for (i=0; i < MESNSRCS; i++) { + if (i != MESTOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->MESnVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->MESnVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->MESnVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->MESnVar[OUTNOIZ][i] += tempOnoise; + inst->MESnVar[OUTNOIZ][MESTOTNOIZ] += tempOnoise; + inst->MESnVar[INNOIZ][i] += tempInoise; + inst->MESnVar[INNOIZ][MESTOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < MESNSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < MESNSRCS; i++) { + data->outpVector[data->outNumber++] = inst->MESnVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->MESnVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} + + diff --git a/src/spicelib/devices/mes/mesparam.c b/src/spicelib/devices/mes/mesparam.c new file mode 100644 index 000000000..5db8da5c9 --- /dev/null +++ b/src/spicelib/devices/mes/mesparam.c @@ -0,0 +1,58 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MESparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + MESinstance *here = (MESinstance*)inst; + switch(param) { + case MES_AREA: + here->MESarea = value->rValue; + here->MESareaGiven = TRUE; + break; + case MES_IC_VDS: + here->MESicVDS = value->rValue; + here->MESicVDSGiven = TRUE; + break; + case MES_IC_VGS: + here->MESicVGS = value->rValue; + here->MESicVGSGiven = TRUE; + break; + case MES_OFF: + here->MESoff = value->iValue; + break; + case MES_IC: + switch(value->v.numValue) { + case 2: + here->MESicVGS = *(value->v.vec.rVec+1); + here->MESicVGSGiven = TRUE; + case 1: + here->MESicVDS = *(value->v.vec.rVec); + here->MESicVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mes/mespzld.c b/src/spicelib/devices/mes/mespzld.c new file mode 100644 index 000000000..e9a3f917f --- /dev/null +++ b/src/spicelib/devices/mes/mespzld.c @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mesdefs.h" +#include "sperror.h" +#include "complex.h" +#include "suffix.h" + + +int +MESpzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; +{ + register MESmodel *model = (MESmodel*)inModel; + register MESinstance *here; + double gdpr; + double gspr; + double gm; + double gds; + double ggs; + double xgs; + double ggd; + double xgd; + + for( ; model != NULL; model = model->MESnextModel ) { + + for( here = model->MESinstances; here != NULL; + here = here->MESnextInstance) { + if (here->MESowner != ARCHme) continue; + + gdpr=model->MESdrainConduct * here->MESarea; + gspr=model->MESsourceConduct * here->MESarea; + gm= *(ckt->CKTstate0 + here->MESgm) ; + gds= *(ckt->CKTstate0 + here->MESgds) ; + ggs= *(ckt->CKTstate0 + here->MESggs) ; + xgs= *(ckt->CKTstate0 + here->MESqgs) ; + ggd= *(ckt->CKTstate0 + here->MESggd) ; + xgd= *(ckt->CKTstate0 + here->MESqgd) ; + *(here->MESdrainDrainPtr ) += gdpr; + *(here->MESgateGatePtr ) += ggd+ggs; + *(here->MESgateGatePtr ) += (xgd+xgs)*s->real; + *(here->MESgateGatePtr +1) += (xgd+xgs)*s->imag; + *(here->MESsourceSourcePtr ) += gspr; + *(here->MESdrainPrimeDrainPrimePtr ) += gdpr+gds+ggd; + *(here->MESdrainPrimeDrainPrimePtr ) += xgd*s->real; + *(here->MESdrainPrimeDrainPrimePtr +1) += xgd*s->imag; + *(here->MESsourcePrimeSourcePrimePtr ) += gspr+gds+gm+ggs; + *(here->MESsourcePrimeSourcePrimePtr ) += xgs*s->real; + *(here->MESsourcePrimeSourcePrimePtr +1) += xgs*s->imag; + *(here->MESdrainDrainPrimePtr ) -= gdpr; + *(here->MESgateDrainPrimePtr ) -= ggd; + *(here->MESgateDrainPrimePtr ) -= xgd*s->real; + *(here->MESgateDrainPrimePtr +1) -= xgd*s->imag; + *(here->MESgateSourcePrimePtr ) -= ggs; + *(here->MESgateSourcePrimePtr ) -= xgs*s->real; + *(here->MESgateSourcePrimePtr +1) -= xgs*s->imag; + *(here->MESsourceSourcePrimePtr ) -= gspr; + *(here->MESdrainPrimeDrainPtr ) -= gdpr; + *(here->MESdrainPrimeGatePtr ) += (-ggd+gm); + *(here->MESdrainPrimeGatePtr ) -= xgd*s->real; + *(here->MESdrainPrimeGatePtr +1) -= xgd*s->imag; + *(here->MESdrainPrimeSourcePrimePtr ) += (-gds-gm); + *(here->MESsourcePrimeGatePtr ) += (-ggs-gm); + *(here->MESsourcePrimeGatePtr ) -= xgs*s->real; + *(here->MESsourcePrimeGatePtr +1) -= xgs*s->imag; + *(here->MESsourcePrimeSourcePtr ) -= gspr; + *(here->MESsourcePrimeDrainPrimePtr ) -= gds; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mes/messetup.c b/src/spicelib/devices/mes/messetup.c new file mode 100644 index 000000000..bf8c7c1e7 --- /dev/null +++ b/src/spicelib/devices/mes/messetup.c @@ -0,0 +1,169 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mesdefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MESsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the diode structure with those pointers needed later + * for fast matrix loading + */ +{ + register MESmodel *model = (MESmodel*)inModel; + register MESinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->MESnextModel ) { + + if( (model->MEStype != NMF) && (model->MEStype != PMF) ) { + model->MEStype = NMF; + } + if(!model->MESthresholdGiven) { + model->MESthreshold = -2; + } + if(!model->MESbetaGiven) { + model->MESbeta = 2.5e-3; + } + if(!model->MESbGiven) { + model->MESb = 0.3; + } + if(!model->MESalphaGiven) { + model->MESalpha = 2; + } + if(!model->MESlModulationGiven) { + model->MESlModulation = 0; + } + if(!model->MESdrainResistGiven) { + model->MESdrainResist = 0; + } + if(!model->MESsourceResistGiven) { + model->MESsourceResist = 0; + } + if(!model->MEScapGSGiven) { + model->MEScapGS = 0; + } + if(!model->MEScapGDGiven) { + model->MEScapGD = 0; + } + if(!model->MESgatePotentialGiven) { + model->MESgatePotential = 1; + } + if(!model->MESgateSatCurrentGiven) { + model->MESgateSatCurrent = 1e-14; + } + if(!model->MESdepletionCapCoeffGiven) { + model->MESdepletionCapCoeff = .5; + } + if(!model->MESfNcoefGiven) { + model->MESfNcoef = 0; + } + if(!model->MESfNexpGiven) { + model->MESfNexp = 1; + } + + /* loop through all the instances of the model */ + for (here = model->MESinstances; here != NULL ; + here=here->MESnextInstance) { + if (here->MESowner != ARCHme) goto matrixpointers; + + if(!here->MESareaGiven) { + here->MESarea = 1; + } + here->MESstate = *states; + *states += MESnumStates; + +matrixpointers: + if(model->MESsourceResist != 0 && here->MESsourcePrimeNode==0) { + error = CKTmkVolt(ckt,&tmp,here->MESname,"source"); + if(error) return(error); + here->MESsourcePrimeNode = tmp->number; + } else { + here->MESsourcePrimeNode = here->MESsourceNode; + } + if(model->MESdrainResist != 0 && here->MESdrainPrimeNode==0) { + error = CKTmkVolt(ckt,&tmp,here->MESname,"drain"); + if(error) return(error); + here->MESdrainPrimeNode = tmp->number; + } else { + here->MESdrainPrimeNode = here->MESdrainNode; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(MESdrainDrainPrimePtr,MESdrainNode,MESdrainPrimeNode) + TSTALLOC(MESgateDrainPrimePtr,MESgateNode,MESdrainPrimeNode) + TSTALLOC(MESgateSourcePrimePtr,MESgateNode,MESsourcePrimeNode) + TSTALLOC(MESsourceSourcePrimePtr,MESsourceNode, + MESsourcePrimeNode) + TSTALLOC(MESdrainPrimeDrainPtr,MESdrainPrimeNode,MESdrainNode) + TSTALLOC(MESdrainPrimeGatePtr,MESdrainPrimeNode,MESgateNode) + TSTALLOC(MESdrainPrimeSourcePrimePtr,MESdrainPrimeNode, + MESsourcePrimeNode) + TSTALLOC(MESsourcePrimeGatePtr,MESsourcePrimeNode,MESgateNode) + TSTALLOC(MESsourcePrimeSourcePtr,MESsourcePrimeNode, + MESsourceNode) + TSTALLOC(MESsourcePrimeDrainPrimePtr,MESsourcePrimeNode, + MESdrainPrimeNode) + TSTALLOC(MESdrainDrainPtr,MESdrainNode,MESdrainNode) + TSTALLOC(MESgateGatePtr,MESgateNode,MESgateNode) + TSTALLOC(MESsourceSourcePtr,MESsourceNode,MESsourceNode) + TSTALLOC(MESdrainPrimeDrainPrimePtr,MESdrainPrimeNode, + MESdrainPrimeNode) + TSTALLOC(MESsourcePrimeSourcePrimePtr,MESsourcePrimeNode, + MESsourcePrimeNode) + } + } + return(OK); +} + +int +MESunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + MESmodel *model; + MESinstance *here; + + for (model = (MESmodel *)inModel; model != NULL; + model = model->MESnextModel) + { + for (here = model->MESinstances; here != NULL; + here=here->MESnextInstance) + { + if (here->MESsourcePrimeNode + && here->MESsourcePrimeNode != here->MESsourceNode) + { + CKTdltNNum(ckt, here->MESsourcePrimeNode); + here->MESsourcePrimeNode = 0; + } + if (here->MESdrainPrimeNode + && here->MESdrainPrimeNode != here->MESdrainNode) + { + CKTdltNNum(ckt, here->MESdrainPrimeNode); + here->MESdrainPrimeNode = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/mes/mestemp.c b/src/spicelib/devices/mes/mestemp.c new file mode 100644 index 000000000..c331e41d7 --- /dev/null +++ b/src/spicelib/devices/mes/mestemp.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mesdefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +MEStemp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* load the diode structure with those pointers needed later + * for fast matrix loading + */ +{ + register MESmodel *model = (MESmodel*)inModel; + double xfc, temp; + + /* loop through all the diode models */ + for( ; model != NULL; model = model->MESnextModel ) { + + if(model->MESdrainResist != 0) { + model->MESdrainConduct = 1/model->MESdrainResist; + } else { + model->MESdrainConduct = 0; + } + if(model->MESsourceResist != 0) { + model->MESsourceConduct = 1/model->MESsourceResist; + } else { + model->MESsourceConduct = 0; + } + + model->MESdepletionCap = model->MESdepletionCapCoeff * + model->MESgatePotential; + xfc = (1 - model->MESdepletionCapCoeff); + temp = sqrt(xfc); + model->MESf1 = model->MESgatePotential * (1 - temp)/(1-.5); + model->MESf2 = temp * temp * temp; + model->MESf3 = 1 - model->MESdepletionCapCoeff * (1 + .5); + model->MESvcrit = CONSTvt0 * log(CONSTvt0/ + (CONSTroot2 * model->MESgateSatCurrent)); + + } + return(OK); +} diff --git a/src/spicelib/devices/mes/mestrunc.c b/src/spicelib/devices/mes/mestrunc.c new file mode 100644 index 000000000..6a3517f00 --- /dev/null +++ b/src/spicelib/devices/mes/mestrunc.c @@ -0,0 +1,34 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 S. Hwang +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mesdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MEStrunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register MESmodel *model = (MESmodel*)inModel; + register MESinstance *here; + + for( ; model != NULL; model = model->MESnextModel) { + for(here=model->MESinstances;here!=NULL;here = here->MESnextInstance){ + if (here->MESowner != ARCHme) continue; + + CKTterr(here->MESqgs,ckt,timeStep); + CKTterr(here->MESqgd,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/ChangeLog b/src/spicelib/devices/mos1/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/mos1/Makefile.am b/src/spicelib/devices/mos1/Makefile.am new file mode 100644 index 000000000..075322152 --- /dev/null +++ b/src/spicelib/devices/mos1/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libmos1.la + +libmos1_la_SOURCES = \ + mos1.c \ + mos1acld.c \ + mos1ask.c \ + mos1conv.c \ + mos1defs.h \ + mos1del.c \ + mos1dest.c \ + mos1dist.c \ + mos1dset.c \ + mos1ext.h \ + mos1ic.c \ + mos1itf.h \ + mos1load.c \ + mos1mask.c \ + mos1mdel.c \ + mos1mpar.c \ + mos1noi.c \ + mos1par.c \ + mos1pzld.c \ + mos1sacl.c \ + mos1set.c \ + mos1sld.c \ + mos1sprt.c \ + mos1sset.c \ + mos1supd.c \ + mos1temp.c \ + mos1trun.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/mos1/mos1.c b/src/spicelib/devices/mos1/mos1.c new file mode 100644 index 000000000..82f74bcf5 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1.c @@ -0,0 +1,163 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "mos1defs.h" +#include "suffix.h" + +IFparm MOS1pTable[] = { /* parameters */ + IOPU("l", MOS1_L, IF_REAL , "Length"), + IOPU("w", MOS1_W, IF_REAL , "Width"), + IOPU("ad", MOS1_AD, IF_REAL , "Drain area"), + IOPU("as", MOS1_AS, IF_REAL , "Source area"), + IOPU("pd", MOS1_PD, IF_REAL , "Drain perimeter"), + IOPU("ps", MOS1_PS, IF_REAL , "Source perimeter"), + IOPU("nrd", MOS1_NRD, IF_REAL , "Drain squares"), + IOPU("nrs", MOS1_NRS, IF_REAL , "Source squares"), + IP("off", MOS1_OFF, IF_FLAG , "Device initially off"), + IOPU("icvds", MOS1_IC_VDS, IF_REAL , "Initial D-S voltage"), + IOPU("icvgs", MOS1_IC_VGS, IF_REAL , "Initial G-S voltage"), + IOPU("icvbs", MOS1_IC_VBS, IF_REAL , "Initial B-S voltage"), + IOPU("temp", MOS1_TEMP, IF_REAL, "Instance temperature"), + IP( "ic", MOS1_IC, IF_REALVEC, "Vector of D-S, G-S, B-S voltages"), + IP( "sens_l", MOS1_L_SENS, IF_FLAG, "flag to request sensitivity WRT length"), + IP( "sens_w", MOS1_W_SENS, IF_FLAG, "flag to request sensitivity WRT width"), + + OP( "id", MOS1_CD, IF_REAL, "Drain current"), + OP( "is", MOS1_CS, IF_REAL, "Source current"), + OP( "ig", MOS1_CG, IF_REAL, "Gate current "), + OP( "ib", MOS1_CB, IF_REAL, "Bulk current "), + OPU( "ibd", MOS1_CBD, IF_REAL, "B-D junction current"), + OPU( "ibs", MOS1_CBS, IF_REAL, "B-S junction current"), + OP( "vgs", MOS1_VGS, IF_REAL, "Gate-Source voltage"), + OP( "vds", MOS1_VDS, IF_REAL, "Drain-Source voltage"), + OP( "vbs", MOS1_VBS, IF_REAL, "Bulk-Source voltage"), + OPU( "vbd", MOS1_VBD, IF_REAL, "Bulk-Drain voltage"), + /* + OP( "cgs", MOS1_CGS, IF_REAL , "Gate-Source capacitance"), + OP( "cgd", MOS1_CGD, IF_REAL , "Gate-Drain capacitance"), + */ + + OPU( "dnode", MOS1_DNODE, IF_INTEGER, "Number of the drain node "), + OPU( "gnode", MOS1_GNODE, IF_INTEGER, "Number of the gate node "), + OPU( "snode", MOS1_SNODE, IF_INTEGER, "Number of the source node "), + OPU( "bnode", MOS1_BNODE, IF_INTEGER, "Number of the node "), + OPU( "dnodeprime", MOS1_DNODEPRIME, IF_INTEGER, "Number of int. drain node"), + OPU( "snodeprime", MOS1_SNODEPRIME, IF_INTEGER, "Number of int. source node "), + + OP( "von", MOS1_VON, IF_REAL, " "), + OP( "vdsat", MOS1_VDSAT, IF_REAL, "Saturation drain voltage"), + OPU( "sourcevcrit", MOS1_SOURCEVCRIT,IF_REAL, "Critical source voltage"), + OPU( "drainvcrit", MOS1_DRAINVCRIT, IF_REAL, "Critical drain voltage"), + OP( "rs", MOS1_SOURCERESIST, IF_REAL, "Source resistance"), + OPU("sourceconductance", MOS1_SOURCECONDUCT, IF_REAL, "Conductance of source"), + OP( "rd", MOS1_DRAINRESIST, IF_REAL, "Drain conductance"), + OPU("drainconductance", MOS1_DRAINCONDUCT, IF_REAL, "Conductance of drain"), + + OP( "gm", MOS1_GM, IF_REAL, "Transconductance"), + OP( "gds", MOS1_GDS, IF_REAL, "Drain-Source conductance"), + OP( "gmb", MOS1_GMBS, IF_REAL, "Bulk-Source transconductance"), + OPR( "gmbs", MOS1_GMBS, IF_REAL, ""), + OPU( "gbd", MOS1_GBD, IF_REAL, "Bulk-Drain conductance"), + OPU( "gbs", MOS1_GBS, IF_REAL, "Bulk-Source conductance"), + + OP( "cbd", MOS1_CAPBD, IF_REAL, "Bulk-Drain capacitance"), + OP( "cbs", MOS1_CAPBS, IF_REAL, "Bulk-Source capacitance"), + OP( "cgs", MOS1_CAPGS, IF_REAL, "Gate-Source capacitance"), + OP( "cgd", MOS1_CAPGD, IF_REAL, "Gate-Drain capacitance"), + OP( "cgb", MOS1_CAPGB, IF_REAL, "Gate-Bulk capacitance"), + + OPU( "cqgs",MOS1_CQGS,IF_REAL,"Capacitance due to gate-source charge storage"), + OPU( "cqgd",MOS1_CQGD,IF_REAL,"Capacitance due to gate-drain charge storage"), + OPU( "cqgb",MOS1_CQGB,IF_REAL,"Capacitance due to gate-bulk charge storage"), + OPU( "cqbd",MOS1_CQBD,IF_REAL,"Capacitance due to bulk-drain charge storage"), + OPU( "cqbs",MOS1_CQBS,IF_REAL,"Capacitance due to bulk-source charge storage"), + + OP( "cbd0", MOS1_CAPZEROBIASBD, IF_REAL, "Zero-Bias B-D junction capacitance"), + OP( "cbdsw0", MOS1_CAPZEROBIASBDSW, IF_REAL, " "), + OP( "cbs0", MOS1_CAPZEROBIASBS, IF_REAL, "Zero-Bias B-S junction capacitance"), + OP( "cbssw0", MOS1_CAPZEROBIASBSSW, IF_REAL, " "), + + OPU( "qgs", MOS1_QGS, IF_REAL, "Gate-Source charge storage"), + OPU( "qgd", MOS1_QGD, IF_REAL, "Gate-Drain charge storage"), + OPU( "qgb", MOS1_QGB, IF_REAL, "Gate-Bulk charge storage"), + OPU( "qbd", MOS1_QBD, IF_REAL, "Bulk-Drain charge storage"), + OPU( "qbs", MOS1_QBS, IF_REAL, "Bulk-Source charge storage"), + OPU( "p", MOS1_POWER, IF_REAL, "Instaneous power"), + OPU( "sens_l_dc", MOS1_L_SENS_DC, IF_REAL, "dc sensitivity wrt length"), + OPU( "sens_l_real", MOS1_L_SENS_REAL,IF_REAL, + "real part of ac sensitivity wrt length"), + OPU( "sens_l_imag", MOS1_L_SENS_IMAG,IF_REAL, + "imag part of ac sensitivity wrt length"), + OPU( "sens_l_mag", MOS1_L_SENS_MAG, IF_REAL, + "sensitivity wrt l of ac magnitude"), + OPU( "sens_l_ph", MOS1_L_SENS_PH, IF_REAL, + "sensitivity wrt l of ac phase"), + OPU( "sens_l_cplx", MOS1_L_SENS_CPLX,IF_COMPLEX, "ac sensitivity wrt length"), + OPU( "sens_w_dc", MOS1_W_SENS_DC, IF_REAL, "dc sensitivity wrt width"), + OPU( "sens_w_real", MOS1_W_SENS_REAL,IF_REAL, + "real part of ac sensitivity wrt width"), + OPU( "sens_w_imag", MOS1_W_SENS_IMAG,IF_REAL, + "imag part of ac sensitivity wrt width"), + OPU( "sens_w_mag", MOS1_W_SENS_MAG, IF_REAL, + "sensitivity wrt w of ac magnitude"), + OPU( "sens_w_ph", MOS1_W_SENS_PH, IF_REAL, + "sensitivity wrt w of ac phase"), + OPU( "sens_w_cplx", MOS1_W_SENS_CPLX,IF_COMPLEX, "ac sensitivity wrt width") +}; + +IFparm MOS1mPTable[] = { /* model parameters */ + OP("type", MOS1_MOD_TYPE, IF_STRING, "N-channel or P-channel MOS"), + IOP("vto", MOS1_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOPR("vt0", MOS1_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOP("kp", MOS1_MOD_KP, IF_REAL ,"Transconductance parameter"), + IOP("gamma", MOS1_MOD_GAMMA, IF_REAL ,"Bulk threshold parameter"), + IOP("phi", MOS1_MOD_PHI, IF_REAL ,"Surface potential"), + IOP("lambda",MOS1_MOD_LAMBDA,IF_REAL ,"Channel length modulation"), + IOP("rd", MOS1_MOD_RD, IF_REAL ,"Drain ohmic resistance"), + IOP("rs", MOS1_MOD_RS, IF_REAL ,"Source ohmic resistance"), + IOPA("cbd", MOS1_MOD_CBD, IF_REAL ,"B-D junction capacitance"), + IOPA("cbs", MOS1_MOD_CBS, IF_REAL ,"B-S junction capacitance"), + IOP("is", MOS1_MOD_IS, IF_REAL ,"Bulk junction sat. current"), + IOP("pb", MOS1_MOD_PB, IF_REAL ,"Bulk junction potential"), + IOPA("cgso", MOS1_MOD_CGSO, IF_REAL ,"Gate-source overlap cap."), + IOPA("cgdo", MOS1_MOD_CGDO, IF_REAL ,"Gate-drain overlap cap."), + IOPA("cgbo", MOS1_MOD_CGBO, IF_REAL ,"Gate-bulk overlap cap."), + IOP("rsh", MOS1_MOD_RSH, IF_REAL ,"Sheet resistance"), + IOPA("cj", MOS1_MOD_CJ, IF_REAL ,"Bottom junction cap per area"), + IOP("mj", MOS1_MOD_MJ, IF_REAL ,"Bottom grading coefficient"), + IOPA("cjsw", MOS1_MOD_CJSW, IF_REAL ,"Side junction cap per area"), + IOP("mjsw", MOS1_MOD_MJSW, IF_REAL ,"Side grading coefficient"), + IOP("js", MOS1_MOD_JS, IF_REAL ,"Bulk jct. sat. current density"), + IOP("tox", MOS1_MOD_TOX, IF_REAL ,"Oxide thickness"), + IOP("ld", MOS1_MOD_LD, IF_REAL ,"Lateral diffusion"), + IOP("u0", MOS1_MOD_U0, IF_REAL ,"Surface mobility"), + IOPR("uo", MOS1_MOD_U0, IF_REAL ,"Surface mobility"), + IOP("fc", MOS1_MOD_FC, IF_REAL ,"Forward bias jct. fit parm."), + IP("nmos", MOS1_MOD_NMOS, IF_FLAG ,"N type MOSfet model"), + IP("pmos", MOS1_MOD_PMOS, IF_FLAG ,"P type MOSfet model"), + IOP("nsub", MOS1_MOD_NSUB, IF_REAL ,"Substrate doping"), + IOP("tpg", MOS1_MOD_TPG, IF_INTEGER,"Gate type"), + IOP("nss", MOS1_MOD_NSS, IF_REAL ,"Surface state density"), + IOP("tnom", MOS1_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), + IOP("kf", MOS1_MOD_KF, IF_REAL ,"Flicker noise coefficient"), + IOP("af", MOS1_MOD_AF, IF_REAL ,"Flicker noise exponent") +}; + +char *MOS1names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int MOS1nSize = NUMELEMS(MOS1names); +int MOS1pTSize = NUMELEMS(MOS1pTable); +int MOS1mPTSize = NUMELEMS(MOS1mPTable); +int MOS1iSize = sizeof(MOS1instance); +int MOS1mSize = sizeof(MOS1model); diff --git a/src/spicelib/devices/mos1/mos1acld.c b/src/spicelib/devices/mos1/mos1acld.c new file mode 100644 index 000000000..3299e7eeb --- /dev/null +++ b/src/spicelib/devices/mos1/mos1acld.c @@ -0,0 +1,119 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS1acLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS1model *model = (MOS1model*)inModel; + register MOS1instance *here; + int xnrm; + int xrev; + double xgs; + double xgd; + double xgb; + double xbd; + double xbs; + double capgs; + double capgd; + double capgb; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double EffectiveLength; + + for( ; model != NULL; model = model->MOS1nextModel) { + for(here = model->MOS1instances; here!= NULL; + here = here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + if (here->MOS1mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * meyer's model parameters + */ + EffectiveLength=here->MOS1l - 2*model->MOS1latDiff; + GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * + here->MOS1w; + GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * + here->MOS1w; + GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * + EffectiveLength; + capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ + *(ckt->CKTstate0+here->MOS1capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ + *(ckt->CKTstate0+here->MOS1capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ + *(ckt->CKTstate0+here->MOS1capgb) + + GateBulkOverlapCap ); + xgs = capgs * ckt->CKTomega; + xgd = capgd * ckt->CKTomega; + xgb = capgb * ckt->CKTomega; + xbd = here->MOS1capbd * ckt->CKTomega; + xbs = here->MOS1capbs * ckt->CKTomega; + /* + * load matrix + */ + + *(here->MOS1GgPtr +1) += xgd+xgs+xgb; + *(here->MOS1BbPtr +1) += xgb+xbd+xbs; + *(here->MOS1DPdpPtr +1) += xgd+xbd; + *(here->MOS1SPspPtr +1) += xgs+xbs; + *(here->MOS1GbPtr +1) -= xgb; + *(here->MOS1GdpPtr +1) -= xgd; + *(here->MOS1GspPtr +1) -= xgs; + *(here->MOS1BgPtr +1) -= xgb; + *(here->MOS1BdpPtr +1) -= xbd; + *(here->MOS1BspPtr +1) -= xbs; + *(here->MOS1DPgPtr +1) -= xgd; + *(here->MOS1DPbPtr +1) -= xbd; + *(here->MOS1SPgPtr +1) -= xgs; + *(here->MOS1SPbPtr +1) -= xbs; + *(here->MOS1DdPtr) += here->MOS1drainConductance; + *(here->MOS1SsPtr) += here->MOS1sourceConductance; + *(here->MOS1BbPtr) += here->MOS1gbd+here->MOS1gbs; + *(here->MOS1DPdpPtr) += here->MOS1drainConductance+ + here->MOS1gds+here->MOS1gbd+ + xrev*(here->MOS1gm+here->MOS1gmbs); + *(here->MOS1SPspPtr) += here->MOS1sourceConductance+ + here->MOS1gds+here->MOS1gbs+ + xnrm*(here->MOS1gm+here->MOS1gmbs); + *(here->MOS1DdpPtr) -= here->MOS1drainConductance; + *(here->MOS1SspPtr) -= here->MOS1sourceConductance; + *(here->MOS1BdpPtr) -= here->MOS1gbd; + *(here->MOS1BspPtr) -= here->MOS1gbs; + *(here->MOS1DPdPtr) -= here->MOS1drainConductance; + *(here->MOS1DPgPtr) += (xnrm-xrev)*here->MOS1gm; + *(here->MOS1DPbPtr) += -here->MOS1gbd+(xnrm-xrev)*here->MOS1gmbs; + *(here->MOS1DPspPtr) -= here->MOS1gds+ + xnrm*(here->MOS1gm+here->MOS1gmbs); + *(here->MOS1SPgPtr) -= (xnrm-xrev)*here->MOS1gm; + *(here->MOS1SPsPtr) -= here->MOS1sourceConductance; + *(here->MOS1SPbPtr) -= here->MOS1gbs+(xnrm-xrev)*here->MOS1gmbs; + *(here->MOS1SPdpPtr) -= here->MOS1gds+ + xrev*(here->MOS1gm+here->MOS1gmbs); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1ask.c b/src/spicelib/devices/mos1/mos1ask.c new file mode 100644 index 000000000..2b471061b --- /dev/null +++ b/src/spicelib/devices/mos1/mos1ask.c @@ -0,0 +1,422 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +MOS1ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + MOS1instance *here = (MOS1instance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case MOS1_TEMP: + value->rValue = here->MOS1temp-CONSTCtoK; + return(OK); + case MOS1_CGS: + value->rValue = *(ckt->CKTstate0 + here->MOS1capgs); + return(OK); + case MOS1_CGD: + value->rValue = *(ckt->CKTstate0 + here->MOS1capgd); + return(OK); + case MOS1_L: + value->rValue = here->MOS1l; + return(OK); + case MOS1_W: + value->rValue = here->MOS1w; + return(OK); + case MOS1_AS: + value->rValue = here->MOS1sourceArea; + return(OK); + case MOS1_AD: + value->rValue = here->MOS1drainArea; + return(OK); + case MOS1_PS: + value->rValue = here->MOS1sourcePerimiter; + return(OK); + case MOS1_PD: + value->rValue = here->MOS1drainPerimiter; + return(OK); + case MOS1_NRS: + value->rValue = here->MOS1sourceSquares; + return(OK); + case MOS1_NRD: + value->rValue = here->MOS1drainSquares; + return(OK); + case MOS1_OFF: + value->rValue = here->MOS1off; + return(OK); + case MOS1_IC_VBS: + value->rValue = here->MOS1icVBS; + return(OK); + case MOS1_IC_VDS: + value->rValue = here->MOS1icVDS; + return(OK); + case MOS1_IC_VGS: + value->rValue = here->MOS1icVGS; + return(OK); + case MOS1_DNODE: + value->iValue = here->MOS1dNode; + return(OK); + case MOS1_GNODE: + value->iValue = here->MOS1gNode; + return(OK); + case MOS1_SNODE: + value->iValue = here->MOS1sNode; + return(OK); + case MOS1_BNODE: + value->iValue = here->MOS1bNode; + return(OK); + case MOS1_DNODEPRIME: + value->iValue = here->MOS1dNodePrime; + return(OK); + case MOS1_SNODEPRIME: + value->iValue = here->MOS1sNodePrime; + return(OK); + case MOS1_SOURCECONDUCT: + value->rValue = here->MOS1sourceConductance; + return(OK); + case MOS1_SOURCERESIST: + if (here->MOS1sNodePrime != here->MOS1sNode) + value->rValue = 1.0 / here->MOS1sourceConductance; + else + value->rValue = 0.0; + return(OK); + case MOS1_DRAINCONDUCT: + value->rValue = here->MOS1drainConductance; + return(OK); + case MOS1_DRAINRESIST: + if (here->MOS1dNodePrime != here->MOS1dNode) + value->rValue = 1.0 / here->MOS1drainConductance; + else + value->rValue = 0.0; + return(OK); + case MOS1_VON: + value->rValue = here->MOS1von; + return(OK); + case MOS1_VDSAT: + value->rValue = here->MOS1vdsat; + return(OK); + case MOS1_SOURCEVCRIT: + value->rValue = here->MOS1sourceVcrit; + return(OK); + case MOS1_DRAINVCRIT: + value->rValue = here->MOS1drainVcrit; + return(OK); + case MOS1_CD: + value->rValue = here->MOS1cd; + return(OK); + case MOS1_CBS: + value->rValue = here->MOS1cbs; + return(OK); + case MOS1_CBD: + value->rValue = here->MOS1cbd; + return(OK); + case MOS1_GMBS: + value->rValue = here->MOS1gmbs; + return(OK); + case MOS1_GM: + value->rValue = here->MOS1gm; + return(OK); + case MOS1_GDS: + value->rValue = here->MOS1gds; + return(OK); + case MOS1_GBD: + value->rValue = here->MOS1gbd; + return(OK); + case MOS1_GBS: + value->rValue = here->MOS1gbs; + return(OK); + case MOS1_CAPBD: + value->rValue = here->MOS1capbd; + return(OK); + case MOS1_CAPBS: + value->rValue = here->MOS1capbs; + return(OK); + case MOS1_CAPZEROBIASBD: + value->rValue = here->MOS1Cbd; + return(OK); + case MOS1_CAPZEROBIASBDSW: + value->rValue = here->MOS1Cbdsw; + return(OK); + case MOS1_CAPZEROBIASBS: + value->rValue = here->MOS1Cbs; + return(OK); + case MOS1_CAPZEROBIASBSSW: + value->rValue = here->MOS1Cbssw; + return(OK); + case MOS1_VBD: + value->rValue = *(ckt->CKTstate0 + here->MOS1vbd); + return(OK); + case MOS1_VBS: + value->rValue = *(ckt->CKTstate0 + here->MOS1vbs); + return(OK); + case MOS1_VGS: + value->rValue = *(ckt->CKTstate0 + here->MOS1vgs); + return(OK); + case MOS1_VDS: + value->rValue = *(ckt->CKTstate0 + here->MOS1vds); + return(OK); + case MOS1_CAPGS: + value->rValue = *(ckt->CKTstate0 + here->MOS1capgs); + return(OK); + case MOS1_QGS: + value->rValue = *(ckt->CKTstate0 + here->MOS1qgs); + return(OK); + case MOS1_CQGS: + value->rValue = *(ckt->CKTstate0 + here->MOS1cqgs); + return(OK); + case MOS1_CAPGD: + value->rValue = *(ckt->CKTstate0 + here->MOS1capgd); + return(OK); + case MOS1_QGD: + value->rValue = *(ckt->CKTstate0 + here->MOS1qgd); + return(OK); + case MOS1_CQGD: + value->rValue = *(ckt->CKTstate0 + here->MOS1cqgd); + return(OK); + case MOS1_CAPGB: + value->rValue = *(ckt->CKTstate0 + here->MOS1capgb); + return(OK); + case MOS1_QGB: + value->rValue = *(ckt->CKTstate0 + here->MOS1qgb); + return(OK); + case MOS1_CQGB: + value->rValue = *(ckt->CKTstate0 + here->MOS1cqgb); + return(OK); + case MOS1_QBD: + value->rValue = *(ckt->CKTstate0 + here->MOS1qbd); + return(OK); + case MOS1_CQBD: + value->rValue = *(ckt->CKTstate0 + here->MOS1cqbd); + return(OK); + case MOS1_QBS: + value->rValue = *(ckt->CKTstate0 + here->MOS1qbs); + return(OK); + case MOS1_CQBS: + value->rValue = *(ckt->CKTstate0 + here->MOS1cqbs); + return(OK); + case MOS1_L_SENS_DC: + if(ckt->CKTsenInfo && here->MOS1sens_l){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS1senParmNo); + } + return(OK); + case MOS1_L_SENS_REAL: + if(ckt->CKTsenInfo && here->MOS1sens_l){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo); + } + return(OK); + case MOS1_L_SENS_IMAG: + if(ckt->CKTsenInfo && here->MOS1sens_l){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo); + } + return(OK); + case MOS1_L_SENS_MAG: + if(ckt->CKTsenInfo && here->MOS1sens_l){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS1_L_SENS_PH: + if(ckt->CKTsenInfo && here->MOS1sens_l){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS1_L_SENS_CPLX: + if(ckt->CKTsenInfo && here->MOS1sens_l){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo); + } + return(OK); + case MOS1_W_SENS_DC: + if(ckt->CKTsenInfo && here->MOS1sens_w){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + } + return(OK); + case MOS1_W_SENS_REAL: + if(ckt->CKTsenInfo && here->MOS1sens_w){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + } + return(OK); + case MOS1_W_SENS_IMAG: + if(ckt->CKTsenInfo && here->MOS1sens_w){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + } + return(OK); + case MOS1_W_SENS_MAG: + if(ckt->CKTsenInfo && here->MOS1sens_w){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS1_W_SENS_PH: + if(ckt->CKTsenInfo && here->MOS1sens_w){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS1_W_SENS_CPLX: + if(ckt->CKTsenInfo && here->MOS1sens_w){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS1senParmNo + here->MOS1sens_l); + } + return(OK); + case MOS1_CB : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS1ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = here->MOS1cbd + here->MOS1cbs - *(ckt->CKTstate0 + + here->MOS1cqgb); + } + return(OK); + case MOS1_CG : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS1ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { + value->rValue = 0; + } else if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + (ckt->CKTmode & MODETRANOP)) { + value->rValue = 0; + } else { + value->rValue = *(ckt->CKTstate0 + here->MOS1cqgb) + + *(ckt->CKTstate0 + here->MOS1cqgd) + *(ckt->CKTstate0 + + here->MOS1cqgs); + } + return(OK); + case MOS1_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS1ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -here->MOS1cd; + value->rValue -= here->MOS1cbd + here->MOS1cbs - + *(ckt->CKTstate0 + here->MOS1cqgb); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue -= *(ckt->CKTstate0 + here->MOS1cqgb) + + *(ckt->CKTstate0 + here->MOS1cqgd) + + *(ckt->CKTstate0 + here->MOS1cqgs); + } + } + return(OK); + case MOS1_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS1ask.c"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + double temp; + + value->rValue = here->MOS1cd * + *(ckt->CKTrhsOld + here->MOS1dNode); + value->rValue += (here->MOS1cbd + here->MOS1cbs - + *(ckt->CKTstate0 + here->MOS1cqgb)) * + *(ckt->CKTrhsOld + here->MOS1bNode); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue += (*(ckt->CKTstate0 + here->MOS1cqgb) + + *(ckt->CKTstate0 + here->MOS1cqgd) + + *(ckt->CKTstate0 + here->MOS1cqgs)) * + *(ckt->CKTrhsOld + here->MOS1gNode); + } + temp = -here->MOS1cd; + temp -= here->MOS1cbd + here->MOS1cbs ; + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + temp -= *(ckt->CKTstate0 + here->MOS1cqgb) + + *(ckt->CKTstate0 + here->MOS1cqgd) + + *(ckt->CKTstate0 + here->MOS1cqgs); + } + value->rValue += temp * *(ckt->CKTrhsOld + here->MOS1sNode); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos1/mos1conv.c b/src/spicelib/devices/mos1/mos1conv.c new file mode 100644 index 000000000..50d882744 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1conv.c @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1convTest(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS1model *model = (MOS1model*)inModel; + register MOS1instance *here; + double delvbs; + double delvbd; + double delvgs; + double delvds; + double delvgd; + double cbhat; + double cdhat; + double vbs; + double vbd; + double vgs; + double vds; + double vgd; + double vgdo; + double tol; + + for( ; model != NULL; model = model->MOS1nextModel) { + for(here = model->MOS1instances; here!= NULL; + here = here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + vbs = model->MOS1type * ( + *(ckt->CKTrhs+here->MOS1bNode) - + *(ckt->CKTrhs+here->MOS1sNodePrime)); + vgs = model->MOS1type * ( + *(ckt->CKTrhs+here->MOS1gNode) - + *(ckt->CKTrhs+here->MOS1sNodePrime)); + vds = model->MOS1type * ( + *(ckt->CKTrhs+here->MOS1dNodePrime) - + *(ckt->CKTrhs+here->MOS1sNodePrime)); + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS1vgs) - + *(ckt->CKTstate0 + here->MOS1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS1vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS1vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS1mode >= 0) { + cdhat= + here->MOS1cd- + here->MOS1gbd * delvbd + + here->MOS1gmbs * delvbs + + here->MOS1gm * delvgs + + here->MOS1gds * delvds ; + } else { + cdhat= + here->MOS1cd - + ( here->MOS1gbd - + here->MOS1gmbs) * delvbd - + here->MOS1gm * delvgd + + here->MOS1gds * delvds ; + } + cbhat= + here->MOS1cbs + + here->MOS1cbd + + here->MOS1gbd * delvbd + + here->MOS1gbs * delvbs ; + /* + * check convergence + */ + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(here->MOS1cd))+ + ckt->CKTabstol; + if (fabs(cdhat-here->MOS1cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged */ + } else { + tol=ckt->CKTreltol* + MAX(fabs(cbhat),fabs(here->MOS1cbs+here->MOS1cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS1cbs+here->MOS1cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged*/ + } + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1defs.h b/src/spicelib/devices/mos1/mos1defs.h new file mode 100644 index 000000000..fd1a254b0 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1defs.h @@ -0,0 +1,511 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef MOS1 +#define MOS1 + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + +/* declarations for level 1 MOSFETs */ + +/* information needed for each instance */ + +typedef struct sMOS1instance { + struct sMOS1model *sMOS1modPtr; /* backpointer to model */ + struct sMOS1instance *MOS1nextInstance; /* pointer to next instance of + *current model*/ + IFuid MOS1name; /* pointer to character string naming this instance */ + int MOS1owner; /* number of owner process */ + int MOS1states; /* index into state table for this device */ + + int MOS1dNode; /* number of the gate node of the mosfet */ + int MOS1gNode; /* number of the gate node of the mosfet */ + int MOS1sNode; /* number of the source node of the mosfet */ + int MOS1bNode; /* number of the bulk node of the mosfet */ + int MOS1dNodePrime; /* number of the internal drain node of the mosfet */ + int MOS1sNodePrime; /* number of the internal source node of the mosfet */ + + double MOS1l; /* the length of the channel region */ + double MOS1w; /* the width of the channel region */ + double MOS1drainArea; /* the area of the drain diffusion */ + double MOS1sourceArea; /* the area of the source diffusion */ + double MOS1drainSquares; /* the length of the drain in squares */ + double MOS1sourceSquares; /* the length of the source in squares */ + double MOS1drainPerimiter; + double MOS1sourcePerimiter; + double MOS1sourceConductance; /*conductance of source(or 0):set in setup*/ + double MOS1drainConductance; /*conductance of drain(or 0):set in setup*/ + double MOS1temp; /* operating temperature of this instance */ + + double MOS1tTransconductance; /* temperature corrected transconductance*/ + double MOS1tSurfMob; /* temperature corrected surface mobility */ + double MOS1tPhi; /* temperature corrected Phi */ + double MOS1tVto; /* temperature corrected Vto */ + double MOS1tSatCur; /* temperature corrected saturation Cur. */ + double MOS1tSatCurDens; /* temperature corrected saturation Cur. density*/ + double MOS1tCbd; /* temperature corrected B-D Capacitance */ + double MOS1tCbs; /* temperature corrected B-S Capacitance */ + double MOS1tCj; /* temperature corrected Bulk bottom Capacitance */ + double MOS1tCjsw; /* temperature corrected Bulk side Capacitance */ + double MOS1tBulkPot; /* temperature corrected Bulk potential */ + double MOS1tDepCap; /* temperature adjusted transition point in */ + /* the cureve matching Fc * Vj */ + double MOS1tVbi; /* temperature adjusted Vbi */ + + double MOS1icVBS; /* initial condition B-S voltage */ + double MOS1icVDS; /* initial condition D-S voltage */ + double MOS1icVGS; /* initial condition G-S voltage */ + double MOS1von; + double MOS1vdsat; + double MOS1sourceVcrit; /* Vcrit for pos. vds */ + double MOS1drainVcrit; /* Vcrit for pos. vds */ + double MOS1cd; + double MOS1cbs; + double MOS1cbd; + double MOS1gmbs; + double MOS1gm; + double MOS1gds; + double MOS1gbd; + double MOS1gbs; + double MOS1capbd; + double MOS1capbs; + double MOS1Cbd; + double MOS1Cbdsw; + double MOS1Cbs; + double MOS1Cbssw; + double MOS1f2d; + double MOS1f3d; + double MOS1f4d; + double MOS1f2s; + double MOS1f3s; + double MOS1f4s; + +/* + * naming convention: + * x = vgs + * y = vbs + * z = vds + * cdr = cdrain + */ + +#define MOS1NDCOEFFS 30 + +#ifndef NODISTO + double MOS1dCoeffs[MOS1NDCOEFFS]; +#else /* NODISTO */ + double *MOS1dCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define capbs2 MOS1dCoeffs[0] +#define capbs3 MOS1dCoeffs[1] +#define capbd2 MOS1dCoeffs[2] +#define capbd3 MOS1dCoeffs[3] +#define gbs2 MOS1dCoeffs[4] +#define gbs3 MOS1dCoeffs[5] +#define gbd2 MOS1dCoeffs[6] +#define gbd3 MOS1dCoeffs[7] +#define capgb2 MOS1dCoeffs[8] +#define capgb3 MOS1dCoeffs[9] +#define cdr_x2 MOS1dCoeffs[10] +#define cdr_y2 MOS1dCoeffs[11] +#define cdr_z2 MOS1dCoeffs[12] +#define cdr_xy MOS1dCoeffs[13] +#define cdr_yz MOS1dCoeffs[14] +#define cdr_xz MOS1dCoeffs[15] +#define cdr_x3 MOS1dCoeffs[16] +#define cdr_y3 MOS1dCoeffs[17] +#define cdr_z3 MOS1dCoeffs[18] +#define cdr_x2z MOS1dCoeffs[19] +#define cdr_x2y MOS1dCoeffs[20] +#define cdr_y2z MOS1dCoeffs[21] +#define cdr_xy2 MOS1dCoeffs[22] +#define cdr_xz2 MOS1dCoeffs[23] +#define cdr_yz2 MOS1dCoeffs[24] +#define cdr_xyz MOS1dCoeffs[25] +#define capgs2 MOS1dCoeffs[26] +#define capgs3 MOS1dCoeffs[27] +#define capgd2 MOS1dCoeffs[28] +#define capgd3 MOS1dCoeffs[29] + +#endif + +#define MOS1RDNOIZ 0 +#define MOS1RSNOIZ 1 +#define MOS1IDNOIZ 2 +#define MOS1FLNOIZ 3 +#define MOS1TOTNOIZ 4 + +#define MOS1NSRCS 5 /* the number of MOS1FET noise sources*/ + +#ifndef NONOISE + double MOS1nVar[NSTATVARS][MOS1NSRCS]; +#else /* NONOISE */ + double **MOS1nVar; +#endif /* NONOISE */ + + int MOS1mode; /* device mode : 1 = normal, -1 = inverse */ + + + unsigned MOS1off:1; /* non-zero to indicate device is off for dc analysis*/ + unsigned MOS1tempGiven :1; /* instance temperature specified */ + unsigned MOS1lGiven :1; + unsigned MOS1wGiven :1; + unsigned MOS1drainAreaGiven :1; + unsigned MOS1sourceAreaGiven :1; + unsigned MOS1drainSquaresGiven :1; + unsigned MOS1sourceSquaresGiven :1; + unsigned MOS1drainPerimiterGiven :1; + unsigned MOS1sourcePerimiterGiven :1; + unsigned MOS1dNodePrimeSet :1; + unsigned MOS1sNodePrimeSet :1; + unsigned MOS1icVBSGiven :1; + unsigned MOS1icVDSGiven :1; + unsigned MOS1icVGSGiven :1; + unsigned MOS1vonGiven :1; + unsigned MOS1vdsatGiven :1; + unsigned MOS1modeGiven :1; + + + double *MOS1DdPtr; /* pointer to sparse matrix element at + * (Drain node,drain node) */ + double *MOS1GgPtr; /* pointer to sparse matrix element at + * (gate node,gate node) */ + double *MOS1SsPtr; /* pointer to sparse matrix element at + * (source node,source node) */ + double *MOS1BbPtr; /* pointer to sparse matrix element at + * (bulk node,bulk node) */ + double *MOS1DPdpPtr; /* pointer to sparse matrix element at + * (drain prime node,drain prime node) */ + double *MOS1SPspPtr; /* pointer to sparse matrix element at + * (source prime node,source prime node) */ + double *MOS1DdpPtr; /* pointer to sparse matrix element at + * (drain node,drain prime node) */ + double *MOS1GbPtr; /* pointer to sparse matrix element at + * (gate node,bulk node) */ + double *MOS1GdpPtr; /* pointer to sparse matrix element at + * (gate node,drain prime node) */ + double *MOS1GspPtr; /* pointer to sparse matrix element at + * (gate node,source prime node) */ + double *MOS1SspPtr; /* pointer to sparse matrix element at + * (source node,source prime node) */ + double *MOS1BdpPtr; /* pointer to sparse matrix element at + * (bulk node,drain prime node) */ + double *MOS1BspPtr; /* pointer to sparse matrix element at + * (bulk node,source prime node) */ + double *MOS1DPspPtr; /* pointer to sparse matrix element at + * (drain prime node,source prime node) */ + double *MOS1DPdPtr; /* pointer to sparse matrix element at + * (drain prime node,drain node) */ + double *MOS1BgPtr; /* pointer to sparse matrix element at + * (bulk node,gate node) */ + double *MOS1DPgPtr; /* pointer to sparse matrix element at + * (drain prime node,gate node) */ + + double *MOS1SPgPtr; /* pointer to sparse matrix element at + * (source prime node,gate node) */ + double *MOS1SPsPtr; /* pointer to sparse matrix element at + * (source prime node,source node) */ + double *MOS1DPbPtr; /* pointer to sparse matrix element at + * (drain prime node,bulk node) */ + double *MOS1SPbPtr; /* pointer to sparse matrix element at + * (source prime node,bulk node) */ + double *MOS1SPdpPtr; /* pointer to sparse matrix element at + * (source prime node,drain prime node) */ + + int MOS1senParmNo; /* parameter # for sensitivity use; + set equal to 0 if neither length + nor width of the mosfet is a design + parameter */ + unsigned MOS1sens_l :1; /* field which indicates whether + length of the mosfet is a design + parameter or not */ + unsigned MOS1sens_w :1; /* field which indicates whether + width of the mosfet is a design + parameter or not */ + unsigned MOS1senPertFlag :1; /* indictes whether the the + parameter of the particular instance is + to be perturbed */ + double MOS1cgs; + double MOS1cgd; + double MOS1cgb; + double *MOS1sens; + +#define MOS1senCgs MOS1sens /* contains pertured values of cgs */ +#define MOS1senCgd MOS1sens + 6 /* contains perturbed values of cgd*/ +#define MOS1senCgb MOS1sens + 12 /* contains perturbed values of cgb*/ +#define MOS1senCbd MOS1sens + 18 /* contains perturbed values of cbd*/ +#define MOS1senCbs MOS1sens + 24 /* contains perturbed values of cbs*/ +#define MOS1senGds MOS1sens + 30 /* contains perturbed values of gds*/ +#define MOS1senGbs MOS1sens + 36 /* contains perturbed values of gbs*/ +#define MOS1senGbd MOS1sens + 42 /* contains perturbed values of gbd*/ +#define MOS1senGm MOS1sens + 48 /* contains perturbed values of gm*/ +#define MOS1senGmbs MOS1sens + 54 /* contains perturbed values of gmbs*/ +#define MOS1dphigs_dl MOS1sens + 60 +#define MOS1dphigd_dl MOS1sens + 61 +#define MOS1dphigb_dl MOS1sens + 62 +#define MOS1dphibs_dl MOS1sens + 63 +#define MOS1dphibd_dl MOS1sens + 64 +#define MOS1dphigs_dw MOS1sens + 65 +#define MOS1dphigd_dw MOS1sens + 66 +#define MOS1dphigb_dw MOS1sens + 67 +#define MOS1dphibs_dw MOS1sens + 68 +#define MOS1dphibd_dw MOS1sens + 69 + +} MOS1instance ; + +#define MOS1vbd MOS1states+ 0 /* bulk-drain voltage */ +#define MOS1vbs MOS1states+ 1 /* bulk-source voltage */ +#define MOS1vgs MOS1states+ 2 /* gate-source voltage */ +#define MOS1vds MOS1states+ 3 /* drain-source voltage */ + +#define MOS1capgs MOS1states+4 /* gate-source capacitor value */ +#define MOS1qgs MOS1states+ 5 /* gate-source capacitor charge */ +#define MOS1cqgs MOS1states+ 6 /* gate-source capacitor current */ + +#define MOS1capgd MOS1states+ 7 /* gate-drain capacitor value */ +#define MOS1qgd MOS1states+ 8 /* gate-drain capacitor charge */ +#define MOS1cqgd MOS1states+ 9 /* gate-drain capacitor current */ + +#define MOS1capgb MOS1states+10 /* gate-bulk capacitor value */ +#define MOS1qgb MOS1states+ 11 /* gate-bulk capacitor charge */ +#define MOS1cqgb MOS1states+ 12 /* gate-bulk capacitor current */ + +#define MOS1qbd MOS1states+ 13 /* bulk-drain capacitor charge */ +#define MOS1cqbd MOS1states+ 14 /* bulk-drain capacitor current */ + +#define MOS1qbs MOS1states+ 15 /* bulk-source capacitor charge */ +#define MOS1cqbs MOS1states+ 16 /* bulk-source capacitor current */ + +#define MOS1numStates 17 + +#define MOS1sensxpgs MOS1states+17 /* charge sensitivities and + their derivatives. +18 for the derivatives: + pointer to the beginning of the array */ +#define MOS1sensxpgd MOS1states+19 +#define MOS1sensxpgb MOS1states+21 +#define MOS1sensxpbs MOS1states+23 +#define MOS1sensxpbd MOS1states+25 + +#define MOS1numSenStates 10 + + +/* per model data */ + + /* NOTE: parameters marked 'input - use xxxx' are paramters for + * which a temperature correction is applied in MOS1temp, thus + * the MOS1xxxx value in the per-instance structure should be used + * instead in all calculations + */ + + +typedef struct sMOS1model { /* model structure for a resistor */ + int MOS1modType; /* type index to this device type */ + struct sMOS1model *MOS1nextModel; /* pointer to next possible model + *in linked list */ + MOS1instance * MOS1instances; /* pointer to list of instances + * that have this model */ + IFuid MOS1modName; /* pointer to character string naming this model */ + int MOS1type; /* device type : 1 = nmos, -1 = pmos */ + double MOS1tnom; /* temperature at which parameters measured */ + double MOS1latDiff; + double MOS1jctSatCurDensity; /* input - use tSatCurDens */ + double MOS1jctSatCur; /* input - use tSatCur */ + double MOS1drainResistance; + double MOS1sourceResistance; + double MOS1sheetResistance; + double MOS1transconductance; /* input - use tTransconductance */ + double MOS1gateSourceOverlapCapFactor; + double MOS1gateDrainOverlapCapFactor; + double MOS1gateBulkOverlapCapFactor; + double MOS1oxideCapFactor; + double MOS1vt0; /* input - use tVto */ + double MOS1capBD; /* input - use tCbd */ + double MOS1capBS; /* input - use tCbs */ + double MOS1bulkCapFactor; /* input - use tCj */ + double MOS1sideWallCapFactor; /* input - use tCjsw */ + double MOS1bulkJctPotential; /* input - use tBulkPot */ + double MOS1bulkJctBotGradingCoeff; + double MOS1bulkJctSideGradingCoeff; + double MOS1fwdCapDepCoeff; + double MOS1phi; /* input - use tPhi */ + double MOS1gamma; + double MOS1lambda; + double MOS1substrateDoping; + int MOS1gateType; + double MOS1surfaceStateDensity; + double MOS1oxideThickness; + double MOS1surfaceMobility; /* input - use tSurfMob */ + double MOS1fNcoef; + double MOS1fNexp; + + unsigned MOS1typeGiven :1; + unsigned MOS1latDiffGiven :1; + unsigned MOS1jctSatCurDensityGiven :1; + unsigned MOS1jctSatCurGiven :1; + unsigned MOS1drainResistanceGiven :1; + unsigned MOS1sourceResistanceGiven :1; + unsigned MOS1sheetResistanceGiven :1; + unsigned MOS1transconductanceGiven :1; + unsigned MOS1gateSourceOverlapCapFactorGiven :1; + unsigned MOS1gateDrainOverlapCapFactorGiven :1; + unsigned MOS1gateBulkOverlapCapFactorGiven :1; + unsigned MOS1vt0Given :1; + unsigned MOS1capBDGiven :1; + unsigned MOS1capBSGiven :1; + unsigned MOS1bulkCapFactorGiven :1; + unsigned MOS1sideWallCapFactorGiven :1; + unsigned MOS1bulkJctPotentialGiven :1; + unsigned MOS1bulkJctBotGradingCoeffGiven :1; + unsigned MOS1bulkJctSideGradingCoeffGiven :1; + unsigned MOS1fwdCapDepCoeffGiven :1; + unsigned MOS1phiGiven :1; + unsigned MOS1gammaGiven :1; + unsigned MOS1lambdaGiven :1; + unsigned MOS1substrateDopingGiven :1; + unsigned MOS1gateTypeGiven :1; + unsigned MOS1surfaceStateDensityGiven :1; + unsigned MOS1oxideThicknessGiven :1; + unsigned MOS1surfaceMobilityGiven :1; + unsigned MOS1tnomGiven :1; + unsigned MOS1fNcoefGiven :1; + unsigned MOS1fNexpGiven :1; + +} MOS1model; + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + +/* device parameters */ +#define MOS1_W 1 +#define MOS1_L 2 +#define MOS1_AS 3 +#define MOS1_AD 4 +#define MOS1_PS 5 +#define MOS1_PD 6 +#define MOS1_NRS 7 +#define MOS1_NRD 8 +#define MOS1_OFF 9 +#define MOS1_IC 10 +#define MOS1_IC_VBS 11 +#define MOS1_IC_VDS 12 +#define MOS1_IC_VGS 13 +#define MOS1_W_SENS 14 +#define MOS1_L_SENS 15 +#define MOS1_CB 16 +#define MOS1_CG 17 +#define MOS1_CS 18 +#define MOS1_POWER 19 +#define MOS1_TEMP 20 + +/* model paramerers */ +#define MOS1_MOD_VTO 101 +#define MOS1_MOD_KP 102 +#define MOS1_MOD_GAMMA 103 +#define MOS1_MOD_PHI 104 +#define MOS1_MOD_LAMBDA 105 +#define MOS1_MOD_RD 106 +#define MOS1_MOD_RS 107 +#define MOS1_MOD_CBD 108 +#define MOS1_MOD_CBS 109 +#define MOS1_MOD_IS 110 +#define MOS1_MOD_PB 111 +#define MOS1_MOD_CGSO 112 +#define MOS1_MOD_CGDO 113 +#define MOS1_MOD_CGBO 114 +#define MOS1_MOD_CJ 115 +#define MOS1_MOD_MJ 116 +#define MOS1_MOD_CJSW 117 +#define MOS1_MOD_MJSW 118 +#define MOS1_MOD_JS 119 +#define MOS1_MOD_TOX 120 +#define MOS1_MOD_LD 121 +#define MOS1_MOD_RSH 122 +#define MOS1_MOD_U0 123 +#define MOS1_MOD_FC 124 +#define MOS1_MOD_NSUB 125 +#define MOS1_MOD_TPG 126 +#define MOS1_MOD_NSS 127 +#define MOS1_MOD_NMOS 128 +#define MOS1_MOD_PMOS 129 +#define MOS1_MOD_TNOM 130 +#define MOS1_MOD_KF 131 +#define MOS1_MOD_AF 132 +#define MOS1_MOD_TYPE 133 + +/* device questions */ +#define MOS1_CGS 201 +#define MOS1_CGD 202 +#define MOS1_DNODE 203 +#define MOS1_GNODE 204 +#define MOS1_SNODE 205 +#define MOS1_BNODE 206 +#define MOS1_DNODEPRIME 207 +#define MOS1_SNODEPRIME 208 +#define MOS1_SOURCECONDUCT 209 +#define MOS1_DRAINCONDUCT 210 +#define MOS1_VON 211 +#define MOS1_VDSAT 212 +#define MOS1_SOURCEVCRIT 213 +#define MOS1_DRAINVCRIT 214 +#define MOS1_CD 215 +#define MOS1_CBS 216 +#define MOS1_CBD 217 +#define MOS1_GMBS 218 +#define MOS1_GM 219 +#define MOS1_GDS 220 +#define MOS1_GBD 221 +#define MOS1_GBS 222 +#define MOS1_CAPBD 223 +#define MOS1_CAPBS 224 +#define MOS1_CAPZEROBIASBD 225 +#define MOS1_CAPZEROBIASBDSW 226 +#define MOS1_CAPZEROBIASBS 227 +#define MOS1_CAPZEROBIASBSSW 228 +#define MOS1_VBD 229 +#define MOS1_VBS 230 +#define MOS1_VGS 231 +#define MOS1_VDS 232 +#define MOS1_CAPGS 233 +#define MOS1_QGS 234 +#define MOS1_CQGS 235 +#define MOS1_CAPGD 236 +#define MOS1_QGD 237 +#define MOS1_CQGD 238 +#define MOS1_CAPGB 239 +#define MOS1_QGB 240 +#define MOS1_CQGB 241 +#define MOS1_QBD 242 +#define MOS1_CQBD 243 +#define MOS1_QBS 244 +#define MOS1_CQBS 245 +#define MOS1_L_SENS_REAL 246 +#define MOS1_L_SENS_IMAG 247 +#define MOS1_L_SENS_MAG 248 +#define MOS1_L_SENS_PH 249 +#define MOS1_L_SENS_CPLX 250 +#define MOS1_W_SENS_REAL 251 +#define MOS1_W_SENS_IMAG 252 +#define MOS1_W_SENS_MAG 253 +#define MOS1_W_SENS_PH 254 +#define MOS1_W_SENS_CPLX 255 +#define MOS1_L_SENS_DC 256 +#define MOS1_W_SENS_DC 257 +#define MOS1_SOURCERESIST 258 +#define MOS1_DRAINRESIST 259 + +/* model questions */ + +#include "mos1ext.h" + +#endif /*MOS1*/ + diff --git a/src/spicelib/devices/mos1/mos1del.c b/src/spicelib/devices/mos1/mos1del.c new file mode 100644 index 000000000..4a89b4d9a --- /dev/null +++ b/src/spicelib/devices/mos1/mos1del.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS1delete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + MOS1model *model = (MOS1model *)inModel; + MOS1instance **fast = (MOS1instance **)inst; + MOS1instance **prev = NULL; + MOS1instance *here; + + for( ; model ; model = model->MOS1nextModel) { + prev = &(model->MOS1instances); + for(here = *prev; here ; here = *prev) { + if(here->MOS1name == name || (fast && here==*fast) ) { + *prev= here->MOS1nextInstance; + FREE(here); + return(OK); + } + prev = &(here->MOS1nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/mos1/mos1dest.c b/src/spicelib/devices/mos1/mos1dest.c new file mode 100644 index 000000000..7e1f78b98 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1dest.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos1defs.h" +#include "suffix.h" + + +void +MOS1destroy(inModel) + GENmodel **inModel; +{ + MOS1model **model = (MOS1model**)inModel; + MOS1instance *here; + MOS1instance *prev = NULL; + MOS1model *mod = *model; + MOS1model *oldmod = NULL; + + for( ; mod ; mod = mod->MOS1nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (MOS1instance *)NULL; + for(here = mod->MOS1instances ; here ; here = here->MOS1nextInstance) { + if(prev){ + if(prev->MOS1sens) FREE(prev->MOS1sens); + FREE(prev); + } + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/mos1/mos1dist.c b/src/spicelib/devices/mos1/mos1dist.c new file mode 100644 index 000000000..615f9b62f --- /dev/null +++ b/src/spicelib/devices/mos1/mos1dist.c @@ -0,0 +1,1387 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +MOS1disto(mode,genmodel,ckt) + GENmodel *genmodel; + register CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + MOS1model *model = (MOS1model *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h1z, i1h1z; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1h2z, i1h2z; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r1hm2z, i1hm2z; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h11z, i2h11z; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double r2h1m2z, i2h1m2z; + double temp, itemp; + register MOS1instance *here; + +if (mode == D_SETUP) + return(MOS1dSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the MOS1 models */ +for( ; model != NULL; model = model->MOS1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + + + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS1gNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS1gNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS1bNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS1bNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS1dNodePrime)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS1dNodePrime)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = DFi2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + (here->MOS1dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F1(here->gbs2, + r1h1y, + i1h1y); + + itemp = D1i2F1(here->gbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = D1i2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgs2, + r1h1x, + i1h1x); + + itemp = ckt->CKTomega * + D1n2F1(here->capgs2, + r1h1x, + i1h1x); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1bNode)) += temp; + *(ckt->CKTirhs + (here->MOS1bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbs2, + r1h1y, + i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + + case D_THRF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS1gNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS1gNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS1bNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS1bNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS1dNodePrime)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS1dNodePrime)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r2h11x = *(job->r2H11ptr + (here->MOS1gNode)) - + *(job->r2H11ptr + (here->MOS1sNodePrime)); + i2h11x = *(job->i2H11ptr + (here->MOS1gNode)) - + *(job->i2H11ptr + (here->MOS1sNodePrime)); + + r2h11y = *(job->r2H11ptr + (here->MOS1bNode)) - + *(job->r2H11ptr + (here->MOS1sNodePrime)); + i2h11y = *(job->i2H11ptr + (here->MOS1bNode)) - + *(job->i2H11ptr + (here->MOS1sNodePrime)); + + r2h11z = *(job->r2H11ptr + (here->MOS1dNodePrime)) - + *(job->r2H11ptr + (here->MOS1sNodePrime)); + i2h11z = *(job->i2H11ptr + (here->MOS1dNodePrime)) - + *(job->i2H11ptr + (here->MOS1sNodePrime)); + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + itemp = DFi3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + + *(ckt->CKTrhs + (here->MOS1dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + itemp = D1i3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = D1i3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = ckt->CKTomega * + D1n3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1bNode)) += temp; + *(ckt->CKTirhs + (here->MOS1bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1PF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS1gNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS1gNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS1bNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS1bNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS1dNodePrime)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS1dNodePrime)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h2x = *(job->r1H2ptr + (here->MOS1gNode)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1h2x = *(job->i1H2ptr + (here->MOS1gNode)) - + *(job->i1H2ptr + (here->MOS1sNodePrime)); + + r1h2y = *(job->r1H2ptr + (here->MOS1bNode)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1h2y = *(job->i1H2ptr + (here->MOS1bNode)) - + *(job->i1H2ptr + (here->MOS1sNodePrime)); + + r1h2z = *(job->r1H2ptr + (here->MOS1dNodePrime)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1h2z = *(job->i1H2ptr + (here->MOS1dNodePrime)) - + *(job->i1H2ptr + (here->MOS1sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + (here->MOS1dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1bNode)) += temp; + *(ckt->CKTirhs + (here->MOS1bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS1gNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS1gNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS1bNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS1bNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS1dNodePrime)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS1dNodePrime)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS1gNode)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS1gNode)) - + *(job->i1H2ptr + (here->MOS1sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS1bNode)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS1bNode)) - + *(job->i1H2ptr + (here->MOS1sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS1dNodePrime)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS1dNodePrime)) - + *(job->i1H2ptr + (here->MOS1sNodePrime))); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + (here->MOS1dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1bNode)) += temp; + *(ckt->CKTirhs + (here->MOS1bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_2F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS1gNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS1gNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS1bNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS1bNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS1dNodePrime)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS1dNodePrime)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS1gNode)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS1gNode)) - + *(job->i1H2ptr + (here->MOS1sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS1bNode)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS1bNode)) - + *(job->i1H2ptr + (here->MOS1sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS1dNodePrime)) - + *(job->r1H2ptr + (here->MOS1sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS1dNodePrime)) - + *(job->i1H2ptr + (here->MOS1sNodePrime))); + + r2h11x = *(job->r1H1ptr + (here->MOS1gNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i2h11x = *(job->i1H1ptr + (here->MOS1gNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r2h11y = *(job->r1H1ptr + (here->MOS1bNode)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i2h11y = *(job->i1H1ptr + (here->MOS1bNode)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r2h11z = *(job->r1H1ptr + (here->MOS1dNodePrime)) - + *(job->r1H1ptr + (here->MOS1sNodePrime)); + i2h11z = *(job->i1H1ptr + (here->MOS1dNodePrime)) - + *(job->i1H1ptr + (here->MOS1sNodePrime)); + + r2h1m2x = *(job->r2H1m2ptr + (here->MOS1gNode)) - + *(job->r2H1m2ptr + (here->MOS1sNodePrime)); + i2h1m2x = *(job->i2H1m2ptr + (here->MOS1gNode)) - + *(job->i2H1m2ptr + (here->MOS1sNodePrime)); + + r2h1m2y = *(job->r2H1m2ptr + (here->MOS1bNode)) - + *(job->r2H1m2ptr + (here->MOS1sNodePrime)); + i2h1m2y = *(job->i2H1m2ptr + (here->MOS1bNode)) - + *(job->i2H1m2ptr + (here->MOS1sNodePrime)); + +r2h1m2z = *(job->r2H1m2ptr + (here->MOS1dNodePrime)) - + *(job->r2H1m2ptr + (here->MOS1sNodePrime)); +i2h1m2z = *(job->i2H1m2ptr + (here->MOS1dNodePrime)) - + *(job->i2H1m2ptr + (here->MOS1sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + +pass.cxx = here->cdr_x2; +pass.cyy = here->cdr_y2; +pass.czz = here->cdr_z2; +pass.cxy = here->cdr_xy; +pass.cyz = here->cdr_yz; +pass.cxz = here->cdr_xz; +pass.cxxx = here->cdr_x3; +pass.cyyy = here->cdr_y3; +pass.czzz = here->cdr_z3; +pass.cxxy = here->cdr_x2y; +pass.cxxz = here->cdr_x2z; +pass.cxyy = here->cdr_xy2; +pass.cyyz = here->cdr_y2z; +pass.cxzz = here->cdr_xz2; +pass.cyzz = here->cdr_yz2; +pass.cxyz = here->cdr_xyz; +pass.r1h1x = r1h1x; +pass.i1h1x = i1h1x; +pass.r1h1y = r1h1y; +pass.i1h1y = i1h1y; +pass.r1h1z = r1h1z; +pass.i1h1z = i1h1z; +pass.r1h2x = r1hm2x; +pass.i1h2x = i1hm2x; +pass.r1h2y = r1hm2y; +pass.i1h2y = i1hm2y; +pass.r1h2z = r1hm2z; +pass.i1h2z = i1hm2z; +pass.r2h11x = r2h11x; +pass.i2h11x = i2h11x; +pass.r2h11y = r2h11y; +pass.i2h11y = i2h11y; +pass.r2h11z = r2h11z; +pass.i2h11z = i2h11z; +pass.h2f1f2x = r2h1m2x; +pass.ih2f1f2x = i2h1m2x; +pass.h2f1f2y = r2h1m2y; +pass.ih2f1f2y = i2h1m2y; +pass.h2f1f2z = r2h1m2z; +pass.ih2f1f2z = i2h1m2z; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + + + *(ckt->CKTrhs + (here->MOS1dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + + itemp = D1i2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = D1i2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = ckt->CKTomega * + D1n2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + *(ckt->CKTrhs + (here->MOS1gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1bNode)) += temp; + *(ckt->CKTirhs + (here->MOS1bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + + *(ckt->CKTrhs + (here->MOS1bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS1bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS1dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS1dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + default: +; + } + } +} +return(OK); +} + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/mos1/mos1dset.c b/src/spicelib/devices/mos1/mos1dset.c new file mode 100644 index 000000000..89ced3ed3 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1dset.c @@ -0,0 +1,589 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "mos1defs.h" +#include "distodef.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1dSetup(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS1model *model = (MOS1model *) inModel; + register MOS1instance *here; + double Beta; + double DrainSatCur; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double gm; + double gds; + double gb; + double ebd; + double vgst; + double evbs; + double sargsw; + double vbd; + double vbs; + double vds; + double arg; + double sarg; + double vdsat; + double vgd; + double vgs; + double von; + double vt; + double lgbs; + double lgbs2; + double lgbs3; + double lgbd; + double lgbd2; + double lgbd3; + double gm2; + double gds2; + double gb2; + double gmds; + double gmb; + double gbds; + double gm3; + double gds3; + double gb3; + double gm2ds; + double gmds2; + double gm2b; + double gmb2; + double gb2ds; + double gbds2; + double lcapgb2; + double lcapgb3; + double lcapgs2; + double lcapgs3; + double lcapgd2; + double lcapgd3; + double lcapbs2; + double lcapbs3; + double lcapbd2; + double lcapbd3; + double gmbds; +#ifndef NOBYPASS +#endif /*NOBYPASS*/ + + + + /* loop through all the MOS1 device models */ + for( ; model != NULL; model = model->MOS1nextModel ) { + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + vt = CONSTKoverQ * here->MOS1temp; + EffectiveLength=here->MOS1l - 2*model->MOS1latDiff; + if( (here->MOS1tSatCurDens == 0) || + (here->MOS1drainArea == 0) || + (here->MOS1sourceArea == 0)) { + DrainSatCur = here->MOS1tSatCur; + SourceSatCur = here->MOS1tSatCur; + } else { + DrainSatCur = here->MOS1tSatCurDens * + here->MOS1drainArea; + SourceSatCur = here->MOS1tSatCurDens * + here->MOS1sourceArea; + } + GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * + here->MOS1w; + GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * + here->MOS1w; + GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * + EffectiveLength; + Beta = here->MOS1tTransconductance * here->MOS1w/EffectiveLength; + OxideCap = model->MOS1oxideCapFactor * EffectiveLength * + here->MOS1w; + + vbs = model->MOS1type * ( + *(ckt->CKTrhsOld+here->MOS1bNode) - + *(ckt->CKTrhsOld+here->MOS1sNodePrime)); + vgs = model->MOS1type * ( + *(ckt->CKTrhsOld+here->MOS1gNode) - + *(ckt->CKTrhsOld+here->MOS1sNodePrime)); + vds = model->MOS1type * ( + *(ckt->CKTrhsOld+here->MOS1dNodePrime) - + *(ckt->CKTrhsOld+here->MOS1sNodePrime)); + + /* now some common crunching for some more useful quantities */ + + vbd=vbs-vds; + vgd=vgs-vds; + + /* + * bulk-source and bulk-drain diodes + * here we just evaluate the ideal diode current and the + * corresponding derivative (conductance). + */ + if(vbs <= 0) { + lgbs = SourceSatCur/vt; + lgbs += ckt->CKTgmin; + lgbs2 = lgbs3 = 0; + } else { + evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); + lgbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + lgbs2 = model->MOS1type *0.5 * (lgbs - ckt->CKTgmin)/vt; + lgbs3 = model->MOS1type *lgbs2/(vt*3); + + } + if(vbd <= 0) { + lgbd = DrainSatCur/vt; + lgbd += ckt->CKTgmin; + lgbd2 = lgbd3 = 0; + } else { + ebd = exp(MIN(MAX_EXP_ARG,vbd/vt)); + lgbd = DrainSatCur*ebd/vt +ckt->CKTgmin; + lgbd2 = model->MOS1type *0.5 * (lgbd - ckt->CKTgmin)/vt; + lgbd3 = model->MOS1type *lgbd2/(vt*3); + } + + /* now to determine whether the user was able to correctly + * identify the source and drain of his device + */ + if(vds >= 0) { + /* normal mode */ + here->MOS1mode = 1; + } else { + /* inverse mode */ + here->MOS1mode = -1; + } + + /* + * this block of code evaluates the drain current and its + * derivatives using the shichman-hodges model and the + * charges associated with the gate, channel and bulk for + * mosfets + * + */ + + /* the following variables are local to this code block until + * it is obvious that they can be made global + */ + { + double betap; + double dvondvbs; + double d2vondvbs2; + double d3vondvbs3; + + if ((here->MOS1mode==1?vbs:vbd) <= 0 ) { + sarg=sqrt(here->MOS1tPhi-(here->MOS1mode==1?vbs:vbd)); + if (-model->MOS1gamma != 0.0) { + dvondvbs = -model->MOS1gamma*0.5/sarg; + d2vondvbs2 = - dvondvbs*0.5/(sarg*sarg); + d3vondvbs3 = 1.5*d2vondvbs2/(sarg*sarg); + } + else { + dvondvbs = d2vondvbs2 = d3vondvbs3 = 0.0; + } + } else { + sarg=sqrt(here->MOS1tPhi); + if (model->MOS1gamma != 0.0) { + dvondvbs = -model->MOS1gamma/(sarg+sarg); + } + else { + dvondvbs = 0.0; + } + d2vondvbs2 = d3vondvbs3 = 0; + sarg=sarg-(here->MOS1mode==1?vbs:vbd)/(sarg+sarg); + sarg=MAX(0,sarg); + dvondvbs = (sarg<=0?0:dvondvbs); + } + von=(here->MOS1tVbi*model->MOS1type)+model->MOS1gamma*sarg; + vgst=(here->MOS1mode==1?vgs:vgd)-von; + vdsat=MAX(vgst,0); +/* if (sarg <= 0) { + arg=0; + } else { + arg=model->MOS1gamma/(sarg+sarg); + } */ + if (vgst <= 0) { + /* + * cutoff region + */ + /* cdrain = 0 */ + gm=0; + gds=0; + gb=0; + gm2=gb2=gds2=0; + gmds=gbds=gmb=0; + gm3=gb3=gds3=0; + gm2ds=gmds2=gm2b=gmb2=gb2ds=gbds2=0; + } else{ + /* + * saturation region + */ + + betap=Beta*(1+model->MOS1lambda*(vds*here->MOS1mode)); + /* cdrain = betap * vgst * vgst * 0.5; */ + if (vgst <= (vds*here->MOS1mode)){ + gm=betap*vgst; + gds=model->MOS1lambda*Beta*vgst*vgst*.5; + /* gb=here->MOS1gm*arg; */ + gb= -gm*dvondvbs; + gm2 = betap; + gds2 = 0; + gb2 = -(gm*d2vondvbs2 - betap*dvondvbs*dvondvbs); + gmds = vgst*model->MOS1lambda*Beta; + gbds = - gmds*dvondvbs; + gmb = -betap*dvondvbs; + gm3 = 0; + gb3 = -(gmb*d2vondvbs2 + gm*d3vondvbs3 - + betap*2*dvondvbs*d2vondvbs2); + gds3 = 0; + gm2ds = Beta * model->MOS1lambda; + gm2b = 0; + gmb2 = -betap*d2vondvbs2; + gb2ds = -(gmds*d2vondvbs2 - dvondvbs*dvondvbs* + Beta * model->MOS1lambda); + gmds2 = 0; + gbds2 = 0; + gmbds = -Beta * model->MOS1lambda*dvondvbs; + + + } else { + /* + * linear region + */ + /* cdrain = betap * vds * (vgst - vds/2); */ + gm=betap*(vds*here->MOS1mode); + gds= Beta * model->MOS1lambda*(vgst* + vds*here->MOS1mode - vds*vds*0.5) + + betap*(vgst - vds*here->MOS1mode); + /* gb=gm*arg; */ + gb = - gm*dvondvbs; + gm2 = 0; + gb2 = -(gm*d2vondvbs2); + gds2 = 2*Beta * model->MOS1lambda*(vgst - + vds*here->MOS1mode) - betap; + gmds = Beta * model->MOS1lambda* vds * + here->MOS1mode + betap; + gbds = - gmds*dvondvbs; + gmb=0; + gm3=0; + gb3 = -gm*d3vondvbs3; + gds3 = -Beta*model->MOS1lambda*3.; + gm2ds=gm2b=gmb2=0; + gmds2 = 2*model->MOS1lambda*Beta; + gb2ds = -(gmds*d2vondvbs2); + gbds2 = -gmds2*dvondvbs; + gmbds = 0; + } + } + /* + * finished + */ + } /* code block */ + + + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + /* + * now we do the hard part of the bulk-drain and bulk-source + * diode - we evaluate the non-linear capacitance and + * charge + * + * the basic equations are not hard, but the implementation + * is somewhat long in an attempt to avoid log/exponential + * evaluations + */ + /* + * charge storage elements + * + *.. bulk-drain and bulk-source depletion capacitances + */ + if (vbs < here->MOS1tDepCap){ + arg=1-vbs/here->MOS1tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS1bulkJctBotGradingCoeff == + model->MOS1bulkJctSideGradingCoeff) { + if(model->MOS1bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS1bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS1bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS1bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS1bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + /* + lcapbs=here->MOS1Cbs*sarg+ + here->MOS1Cbssw*sargsw; + */ + lcapbs2 = model->MOS1type*0.5/here->MOS1tBulkPot*( + here->MOS1Cbs*model->MOS1bulkJctBotGradingCoeff* + sarg/arg + here->MOS1Cbssw* + model->MOS1bulkJctSideGradingCoeff*sargsw/arg); + lcapbs3 = here->MOS1Cbs*sarg* + model->MOS1bulkJctBotGradingCoeff* + (model->MOS1bulkJctBotGradingCoeff+1); + lcapbs3 += here->MOS1Cbssw*sargsw* + model->MOS1bulkJctSideGradingCoeff* + (model->MOS1bulkJctSideGradingCoeff+1); + lcapbs3 = lcapbs3/(6*here->MOS1tBulkPot* + here->MOS1tBulkPot*arg*arg); + } else { + /* *(ckt->CKTstate0 + here->MOS1qbs)= here->MOS1f4s + + vbs*(here->MOS1f2s+vbs*(here->MOS1f3s/2));*/ + /* + lcapbs=here->MOS1f2s+here->MOS1f3s*vbs; + */ + lcapbs2 = 0.5*here->MOS1f3s; + lcapbs3 = 0; + } + if (vbd < here->MOS1tDepCap) { + arg=1-vbd/here->MOS1tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS1bulkJctBotGradingCoeff == .5 && + model->MOS1bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS1bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS1bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS1bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + /* + lcapbd=here->MOS1Cbd*sarg+ + here->MOS1Cbdsw*sargsw; + */ + lcapbd2 = model->MOS1type*0.5/here->MOS1tBulkPot*( + here->MOS1Cbd*model->MOS1bulkJctBotGradingCoeff* + sarg/arg + here->MOS1Cbdsw* + model->MOS1bulkJctSideGradingCoeff*sargsw/arg); + lcapbd3 = here->MOS1Cbd*sarg* + model->MOS1bulkJctBotGradingCoeff* + (model->MOS1bulkJctBotGradingCoeff+1); + lcapbd3 += here->MOS1Cbdsw*sargsw* + model->MOS1bulkJctSideGradingCoeff* + (model->MOS1bulkJctSideGradingCoeff+1); + lcapbd3 = lcapbd3/(6*here->MOS1tBulkPot* + here->MOS1tBulkPot*arg*arg); + } else { + /* + lcapbd=here->MOS1f2d + vbd * here->MOS1f3d; + */ + lcapbd2=0.5*here->MOS1f3d; + lcapbd3=0; + } + /* + * meyer's capacitor model + */ + /* + * the meyer capacitance equations are in DEVqmeyer + * these expressions are derived from those equations. + * these expressions are incorrect; they assume just one + * controlling variable for each charge storage element + * while actually there are several; the MOS1 small + * signal ac linear model is also wrong because it + * ignores controlled capacitive elements. these can be + * corrected (as can the linear ss ac model) if the + * expressions for the charge are available + */ + + +{ + + + double phi; + double cox; + double vddif; + double vddif1; + double vddif2; + /* von, vgst and vdsat have already been adjusted for + possible source-drain interchange */ + + + + phi = here->MOS1tPhi; + cox = OxideCap; + if (vgst <= -phi) { + lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else if (vgst <= -phi/2) { + lcapgb2= -cox/(4*phi); + lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else if (vgst <= 0) { + lcapgb2= -cox/(4*phi); + lcapgb3=lcapgs3=lcapgd2=lcapgd3=0; + lcapgs2 = cox/(3*phi); + } else { /* the MOS1modes are around because + vds has not been adjusted */ + if (vdsat <= here->MOS1mode*vds) { + lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else { + vddif = 2.0*vdsat-here->MOS1mode*vds; + vddif1 = vdsat-here->MOS1mode*vds/*-1.0e-12*/; + vddif2 = vddif*vddif; + lcapgd2 = -vdsat*here->MOS1mode*vds*cox/(3*vddif*vddif2); + lcapgd3 = - here->MOS1mode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2); + lcapgs2 = -vddif1*here->MOS1mode*vds*cox/(3*vddif*vddif2); + lcapgs3 = - here->MOS1mode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2); + lcapgb2=lcapgb3=0; + } + } + } + + /* the b-s and b-d diodes need no processing ... */ + here->capbs2 = lcapbs2; + here->capbs3 = lcapbs3; + here->capbd2 = lcapbd2; + here->capbd3 = lcapbd3; + here->gbs2 = lgbs2; + here->gbs3 = lgbs3; + here->gbd2 = lgbd2; + here->gbd3 = lgbd3; + here->capgb2 = model->MOS1type*lcapgb2; + here->capgb3 = lcapgb3; + /* + * process to get Taylor coefficients, taking into + * account type and mode. + */ + + if (here->MOS1mode == 1) + { + /* normal mode - no source-drain interchange */ + + here->cdr_x2 = gm2; + here->cdr_y2 = gb2;; + here->cdr_z2 = gds2;; + here->cdr_xy = gmb; + here->cdr_yz = gbds; + here->cdr_xz = gmds; + here->cdr_x3 = gm3; + here->cdr_y3 = gb3; + here->cdr_z3 = gds3; + here->cdr_x2z = gm2ds; + here->cdr_x2y = gm2b; + here->cdr_y2z = gb2ds; + here->cdr_xy2 = gmb2; + here->cdr_xz2 = gmds2; + here->cdr_yz2 = gbds2; + here->cdr_xyz = gmbds; + + /* the gate caps have been divided and made into + Taylor coeffs., but not adjusted for type */ + + here->capgs2 = model->MOS1type*lcapgs2; + here->capgs3 = lcapgs3; + here->capgd2 = model->MOS1type*lcapgd2; + here->capgd3 = lcapgd3; +} else { + /* + * inverse mode - source and drain interchanged + */ + +here->cdr_x2 = -gm2; +here->cdr_y2 = -gb2; +here->cdr_z2 = -(gm2 + gb2 + gds2 + 2*(gmb + gmds + gbds)); +here->cdr_xy = -gmb; +here->cdr_yz = gmb + gb2 + gbds; +here->cdr_xz = gm2 + gmb + gmds; +here->cdr_x3 = -gm3; +here->cdr_y3 = -gb3; +here->cdr_z3 = gm3 + gb3 + gds3 + + 3*(gm2b + gm2ds + gmb2 + gb2ds + gmds2 + gbds2) + 6*gmbds ; +here->cdr_x2z = gm3 + gm2b + gm2ds; +here->cdr_x2y = -gm2b; +here->cdr_y2z = gmb2 + gb3 + gb2ds; +here->cdr_xy2 = -gmb2; +here->cdr_xz2 = -(gm3 + 2*(gm2b + gm2ds + gmbds) + + gmb2 + gmds2); +here->cdr_yz2 = -(gb3 + 2*(gmb2 + gb2ds + gmbds) + + gm2b + gbds2); +here->cdr_xyz = gm2b + gmb2 + gmbds; + + here->capgs2 = model->MOS1type*lcapgd2; + here->capgs3 = lcapgd3; + + here->capgd2 = model->MOS1type*lcapgs2; + here->capgd3 = lcapgs3; + +} + +/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ + +here->cdr_x2 = 0.5*model->MOS1type*here->cdr_x2; +here->cdr_y2 = 0.5*model->MOS1type*here->cdr_y2; +here->cdr_z2 = 0.5*model->MOS1type*here->cdr_z2; +here->cdr_xy = model->MOS1type*here->cdr_xy; +here->cdr_yz = model->MOS1type*here->cdr_yz; +here->cdr_xz = model->MOS1type*here->cdr_xz; +here->cdr_x3 = here->cdr_x3/6.; +here->cdr_y3 = here->cdr_y3/6.; +here->cdr_z3 = here->cdr_z3/6.; +here->cdr_x2z = 0.5*here->cdr_x2z; +here->cdr_x2y = 0.5*here->cdr_x2y; +here->cdr_y2z = 0.5*here->cdr_y2z; +here->cdr_xy2 = 0.5*here->cdr_xy2; +here->cdr_xz2 = 0.5*here->cdr_xz2; +here->cdr_yz2 = 0.5*here->cdr_yz2; + + + } + } + return(OK); + } diff --git a/src/spicelib/devices/mos1/mos1ext.h b/src/spicelib/devices/mos1/mos1ext.h new file mode 100644 index 000000000..94306a507 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1ext.h @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int MOS1acLoad(GENmodel *,CKTcircuit*); +extern int MOS1ask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int MOS1delete(GENmodel*,IFuid,GENinstance**); +extern void MOS1destroy(GENmodel**); +extern int MOS1getic(GENmodel*,CKTcircuit*); +extern int MOS1load(GENmodel*,CKTcircuit*); +extern int MOS1mAsk(CKTcircuit *,GENmodel *,int,IFvalue*); +extern int MOS1mDelete(GENmodel**,IFuid,GENmodel*); +extern int MOS1mParam(int,IFvalue*,GENmodel*); +extern int MOS1param(int,IFvalue*,GENinstance*,IFvalue*); +extern int MOS1pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int MOS1sAcLoad(GENmodel*,CKTcircuit*); +extern int MOS1sLoad(GENmodel*,CKTcircuit*); +extern void MOS1sPrint(GENmodel*,CKTcircuit*); +extern int MOS1sSetup(SENstruct*,GENmodel*); +extern int MOS1sUpdate(GENmodel*,CKTcircuit*); +extern int MOS1setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int MOS1unsetup(GENmodel*,CKTcircuit*); +extern int MOS1temp(GENmodel*,CKTcircuit*); +extern int MOS1trunc(GENmodel*,CKTcircuit*,double*); +extern int MOS1convTest(GENmodel*,CKTcircuit*); +extern int MOS1disto(int,GENmodel*,CKTcircuit*); +extern int MOS1noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); + +#else /* stdc */ +extern int MOS1acLoad(); +extern int MOS1ask(); +extern int MOS1delete(); +extern void MOS1destroy(); +extern int MOS1getic(); +extern int MOS1load(); +extern int MOS1mAsk(); +extern int MOS1mDelete(); +extern int MOS1mParam(); +extern int MOS1param(); +extern int MOS1pzLoad(); +extern int MOS1sAcLoad(); +extern int MOS1sLoad(); +extern void MOS1sPrint(); +extern int MOS1sSetup(); +extern int MOS1sUpdate(); +extern int MOS1setup(); +extern int MOS1unsetup(); +extern int MOS1temp(); +extern int MOS1trunc(); +extern int MOS1convTest(); +extern int MOS1disto(); +extern int MOS1noise(); +#endif /* stdc */ diff --git a/src/spicelib/devices/mos1/mos1ic.c b/src/spicelib/devices/mos1/mos1ic.c new file mode 100644 index 000000000..efab88487 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1ic.c @@ -0,0 +1,50 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS1getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS1model *model = (MOS1model *)inModel; + MOS1instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->MOS1nextModel) { + for(here = model->MOS1instances; here ; here = here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + if(!here->MOS1icVBSGiven) { + here->MOS1icVBS = + *(ckt->CKTrhs + here->MOS1bNode) - + *(ckt->CKTrhs + here->MOS1sNode); + } + if(!here->MOS1icVDSGiven) { + here->MOS1icVDS = + *(ckt->CKTrhs + here->MOS1dNode) - + *(ckt->CKTrhs + here->MOS1sNode); + } + if(!here->MOS1icVGSGiven) { + here->MOS1icVGS = + *(ckt->CKTrhs + here->MOS1gNode) - + *(ckt->CKTrhs + here->MOS1sNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1itf.h b/src/spicelib/devices/mos1/mos1itf.h new file mode 100644 index 000000000..38ad3361c --- /dev/null +++ b/src/spicelib/devices/mos1/mos1itf.h @@ -0,0 +1,101 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_mos1 + +#ifndef DEV_MOS1 +#define DEV_MOS1 + +#include "mos1ext.h" +extern IFparm MOS1pTable[ ]; +extern IFparm MOS1mPTable[ ]; +extern char *MOS1names[ ]; +extern int MOS1pTSize; +extern int MOS1mPTSize; +extern int MOS1nSize; +extern int MOS1iSize; +extern int MOS1mSize; + +SPICEdev MOS1info = { + { + "Mos1", + "Level 1 MOSfet model with Meyer capacitance model", + + &MOS1nSize, + &MOS1nSize, + MOS1names, + + &MOS1pTSize, + MOS1pTable, + + &MOS1mPTSize, + MOS1mPTable, + DEV_DEFAULT + }, + + MOS1param, + MOS1mParam, + MOS1load, + MOS1setup, + MOS1unsetup, + MOS1setup, + MOS1temp, + MOS1trunc, + NULL, + MOS1acLoad, + NULL, + MOS1destroy, +#ifdef DELETES + MOS1mDelete, + MOS1delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + MOS1getic, + MOS1ask, + MOS1mAsk, +#ifdef AN_pz + MOS1pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + MOS1convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + +#ifdef AN_sense2 + MOS1sSetup, + MOS1sLoad, + MOS1sUpdate, + MOS1sAcLoad, + MOS1sPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ +#ifdef AN_disto + MOS1disto, +#else /* AN_disto */ + NULL, +#endif /* AN_disto */ +#ifdef AN_noise + MOS1noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &MOS1iSize, + &MOS1mSize +}; + + +#endif +#endif diff --git a/src/spicelib/devices/mos1/mos1load.c b/src/spicelib/devices/mos1/mos1load.c new file mode 100644 index 000000000..bdca66a70 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1load.c @@ -0,0 +1,1020 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "mos1defs.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1load(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS1model *model = (MOS1model *) inModel; + register MOS1instance *here; + double Beta; + double DrainSatCur; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double arg; + double cbhat; + double cdhat; + double cdrain; + double cdreq; + double ceq; + double ceqbd; + double ceqbs; + double ceqgb; + double ceqgd; + double ceqgs; + double delvbd; + double delvbs; + double delvds; + double delvgd; + double delvgs; + double evbd; + double evbs; + double gcgb; + double gcgd; + double gcgs; + double geq; + double sarg; + double sargsw; + double vbd; + double vbs; + double vds; + double vdsat; + double vgb1; + double vgb; + double vgd1; + double vgd; + double vgdo; + double vgs1; + double vgs; + double von; + double vt; + double xfact; + int xnrm; + int xrev; + double capgs; /* total gate-source capacitance */ + double capgd; /* total gate-drain capacitance */ + double capgb; /* total gate-bulk capacitance */ + int Check; +#ifndef NOBYPASS + double tempv; +#endif /*NOBYPASS*/ + int error; +#ifdef CAPBYPASS + int senflag; +#endif /* CAPBYPASS */ + int SenCond; + + +#ifdef CAPBYPASS + senflag = 0; + if(ckt->CKTsenInfo && ckt->CKTsenInfo->SENstatus == PERTURBATION && + (ckt->CKTsenInfo->SENmode & (ACSEN | TRANSEN))) { + senflag = 1; + } +#endif /* CAPBYPASS */ + + /* loop through all the MOS1 device models */ + for( ; model != NULL; model = model->MOS1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + vt = CONSTKoverQ * here->MOS1temp; + Check=1; + if(ckt->CKTsenInfo){ +#ifdef SENSDEBUG + printf("MOS1load \n"); +#endif /* SENSDEBUG */ + + if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&& + (here->MOS1senPertFlag == OFF))continue; + + } + SenCond = ckt->CKTsenInfo && here->MOS1senPertFlag; + +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospta"); +asm("mospta:"); +#endif /*DETAILPROF*/ + + /* first, we compute a few useful values - these could be + * pre-computed, but for historical reasons are still done + * here. They may be moved at the expense of instance size + */ + + EffectiveLength=here->MOS1l - 2*model->MOS1latDiff; + if( (here->MOS1tSatCurDens == 0) || + (here->MOS1drainArea == 0) || + (here->MOS1sourceArea == 0)) { + DrainSatCur = here->MOS1tSatCur; + SourceSatCur = here->MOS1tSatCur; + } else { + DrainSatCur = here->MOS1tSatCurDens * + here->MOS1drainArea; + SourceSatCur = here->MOS1tSatCurDens * + here->MOS1sourceArea; + } + GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * + here->MOS1w; + GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * + here->MOS1w; + GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * + EffectiveLength; + Beta = here->MOS1tTransconductance * here->MOS1w/EffectiveLength; + OxideCap = model->MOS1oxideCapFactor * EffectiveLength * + here->MOS1w; + /* + * ok - now to do the start-up operations + * + * we must get values for vbs, vds, and vgs from somewhere + * so we either predict them or recover them from last iteration + * These are the two most common cases - either a prediction + * step or the general iteration step and they + * share some code, so we put them first - others later on + */ + + if(SenCond){ +#ifdef SENSDEBUG + printf("MOS1senPertFlag = ON \n"); +#endif /* SENSDEBUG */ + if((ckt->CKTsenInfo->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) { + vgs = *(ckt->CKTstate1 + here->MOS1vgs); + vds = *(ckt->CKTstate1 + here->MOS1vds); + vbs = *(ckt->CKTstate1 + here->MOS1vbs); + vbd = *(ckt->CKTstate1 + here->MOS1vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } + else if (ckt->CKTsenInfo->SENmode == ACSEN){ + vgb = model->MOS1type * ( + *(ckt->CKTrhsOp+here->MOS1gNode) - + *(ckt->CKTrhsOp+here->MOS1bNode)); + vbs = *(ckt->CKTstate0 + here->MOS1vbs); + vbd = *(ckt->CKTstate0 + here->MOS1vbd); + vgd = vgb + vbd ; + vgs = vgb + vbs ; + vds = vbs - vbd ; + } + else{ + vgs = *(ckt->CKTstate0 + here->MOS1vgs); + vds = *(ckt->CKTstate0 + here->MOS1vds); + vbs = *(ckt->CKTstate0 + here->MOS1vbs); + vbd = *(ckt->CKTstate0 + here->MOS1vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } +#ifdef SENSDEBUG + printf(" vbs = %.7e ,vbd = %.7e,vgb = %.7e\n",vbs,vbd,vgb); + printf(" vgs = %.7e ,vds = %.7e,vgd = %.7e\n",vgs,vds,vgd); +#endif /* SENSDEBUG */ + goto next1; + } + + + if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG + | MODEINITTRAN)) || + ( (ckt->CKTmode & MODEINITFIX) && (!here->MOS1off) ) ) { +#ifndef PREDICTOR + if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + + /* predictor step */ + + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->MOS1vbs) = + *(ckt->CKTstate1 + here->MOS1vbs); + vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vbs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS1vbs))); + *(ckt->CKTstate0 + here->MOS1vgs) = + *(ckt->CKTstate1 + here->MOS1vgs); + vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vgs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS1vgs))); + *(ckt->CKTstate0 + here->MOS1vds) = + *(ckt->CKTstate1 + here->MOS1vds); + vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS1vds)) + -(xfact * (*(ckt->CKTstate2 + here->MOS1vds))); + *(ckt->CKTstate0 + here->MOS1vbd) = + *(ckt->CKTstate0 + here->MOS1vbs)- + *(ckt->CKTstate0 + here->MOS1vds); + } else { +#endif /* PREDICTOR */ + + /* general iteration */ + + vbs = model->MOS1type * ( + *(ckt->CKTrhsOld+here->MOS1bNode) - + *(ckt->CKTrhsOld+here->MOS1sNodePrime)); + vgs = model->MOS1type * ( + *(ckt->CKTrhsOld+here->MOS1gNode) - + *(ckt->CKTrhsOld+here->MOS1sNodePrime)); + vds = model->MOS1type * ( + *(ckt->CKTrhsOld+here->MOS1dNodePrime) - + *(ckt->CKTrhsOld+here->MOS1sNodePrime)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + + /* now some common crunching for some more useful quantities */ + + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS1vgs) - + *(ckt->CKTstate0 + here->MOS1vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS1vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS1vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS1vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS1vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS1mode >= 0) { + cdhat= + here->MOS1cd- + here->MOS1gbd * delvbd + + here->MOS1gmbs * delvbs + + here->MOS1gm * delvgs + + here->MOS1gds * delvds ; + } else { + cdhat= + here->MOS1cd - + ( here->MOS1gbd - + here->MOS1gmbs) * delvbd - + here->MOS1gm * delvgd + + here->MOS1gds * delvds ; + } + cbhat= + here->MOS1cbs + + here->MOS1cbd + + here->MOS1gbd * delvbd + + here->MOS1gbs * delvbs ; +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptb"); +asm("mosptb:"); +#endif /*DETAILPROF*/ +#ifndef NOBYPASS + /* now lets see if we can bypass (ugh) */ + /* the following mess should be one if statement, but + * many compilers can't handle it all at once, so it + * is split into several successive if statements + */ + tempv = MAX(fabs(cbhat),fabs(here->MOS1cbs + + here->MOS1cbd))+ckt->CKTabstol; + if((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG) + )) && (ckt->CKTbypass) ) + if ( (fabs(cbhat-(here->MOS1cbs + + here->MOS1cbd)) < ckt->CKTreltol * + tempv)) + if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS1vbs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS1vbd)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->MOS1vgs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->MOS1vds)))+ + ckt->CKTvoltTol)) ) + if( (fabs(cdhat- here->MOS1cd) < + ckt->CKTreltol * MAX(fabs(cdhat),fabs( + here->MOS1cd)) + ckt->CKTabstol) ) { + /* bypass code */ + /* nothing interesting has changed since last + * iteration on this device, so we just + * copy all the values computed last iteration out + * and keep going + */ + vbs = *(ckt->CKTstate0 + here->MOS1vbs); + vbd = *(ckt->CKTstate0 + here->MOS1vbd); + vgs = *(ckt->CKTstate0 + here->MOS1vgs); + vds = *(ckt->CKTstate0 + here->MOS1vds); + vgd = vgs - vds; + vgb = vgs - vbs; + cdrain = here->MOS1mode * (here->MOS1cd + here->MOS1cbd); + if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { + capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ + *(ckt->CKTstate1+here->MOS1capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ + *(ckt->CKTstate1+here->MOS1capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ + *(ckt->CKTstate1+here->MOS1capgb) + + GateBulkOverlapCap ); + + if(ckt->CKTsenInfo){ + here->MOS1cgs = capgs; + here->MOS1cgd = capgd; + here->MOS1cgb = capgb; + } + } + goto bypass; + } +#endif /*NOBYPASS*/ +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptc"); +asm("mosptc:"); +#endif /*DETAILPROF*/ + /* ok - bypass is out, do it the hard way */ + + von = model->MOS1type * here->MOS1von; + +#ifndef NODELIMITING + /* + * limiting + * we want to keep device voltages from changing + * so fast that the exponentials churn out overflows + * and similar rudeness + */ + + if(*(ckt->CKTstate0 + here->MOS1vds) >=0) { + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS1vgs) + ,von); + vds = vgs - vgd; + vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS1vds)); + vgd = vgs - vds; + } else { + vgd = DEVfetlim(vgd,vgdo,von); + vds = vgs - vgd; + if(!(ckt->CKTfixLimit)) { + vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + + here->MOS1vds))); + } + vgs = vgd + vds; + } + if(vds >= 0) { + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS1vbs), + vt,here->MOS1sourceVcrit,&Check); + vbd = vbs-vds; + } else { + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS1vbd), + vt,here->MOS1drainVcrit,&Check); + vbs = vbd + vds; + } +#endif /*NODELIMITING*/ +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptd"); +asm("mosptd:"); +#endif /*DETAILPROF*/ + } else { + + /* ok - not one of the simple cases, so we have to + * look at all of the possibilities for why we were + * called. We still just initialize the three voltages + */ + + if((ckt->CKTmode & MODEINITJCT) && !here->MOS1off) { + vds= model->MOS1type * here->MOS1icVDS; + vgs= model->MOS1type * here->MOS1icVGS; + vbs= model->MOS1type * here->MOS1icVBS; + if((vds==0) && (vgs==0) && (vbs==0) && + ((ckt->CKTmode & + (MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || + (!(ckt->CKTmode & MODEUIC)))) { + vbs = -1; + vgs = model->MOS1type * here->MOS1tVto; + vds = 0; + } + } else { + vbs=vgs=vds=0; + } + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospte"); +asm("mospte:"); +#endif /*DETAILPROF*/ + + /* + * now all the preliminaries are over - we can start doing the + * real work + */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + + /* + * bulk-source and bulk-drain diodes + * here we just evaluate the ideal diode current and the + * corresponding derivative (conductance). + */ +next1: if(vbs <= 0) { + here->MOS1gbs = SourceSatCur/vt; + here->MOS1cbs = here->MOS1gbs*vbs; + here->MOS1gbs += ckt->CKTgmin; + } else { + evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); + here->MOS1gbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + here->MOS1cbs = SourceSatCur * (evbs-1); + } + if(vbd <= 0) { + here->MOS1gbd = DrainSatCur/vt; + here->MOS1cbd = here->MOS1gbd *vbd; + here->MOS1gbd += ckt->CKTgmin; + } else { + evbd = exp(MIN(MAX_EXP_ARG,vbd/vt)); + here->MOS1gbd = DrainSatCur*evbd/vt +ckt->CKTgmin; + here->MOS1cbd = DrainSatCur *(evbd-1); + } + + /* now to determine whether the user was able to correctly + * identify the source and drain of his device + */ + if(vds >= 0) { + /* normal mode */ + here->MOS1mode = 1; + } else { + /* inverse mode */ + here->MOS1mode = -1; + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptf"); +asm("mosptf:"); +#endif /*DETAILPROF*/ + { + /* + * this block of code evaluates the drain current and its + * derivatives using the shichman-hodges model and the + * charges associated with the gate, channel and bulk for + * mosfets + * + */ + + /* the following 4 variables are local to this code block until + * it is obvious that they can be made global + */ + double arg; + double betap; + double sarg; + double vgst; + + if ((here->MOS1mode==1?vbs:vbd) <= 0 ) { + sarg=sqrt(here->MOS1tPhi-(here->MOS1mode==1?vbs:vbd)); + } else { + sarg=sqrt(here->MOS1tPhi); + sarg=sarg-(here->MOS1mode==1?vbs:vbd)/(sarg+sarg); + sarg=MAX(0,sarg); + } + von=(here->MOS1tVbi*model->MOS1type)+model->MOS1gamma*sarg; + vgst=(here->MOS1mode==1?vgs:vgd)-von; + vdsat=MAX(vgst,0); + if (sarg <= 0) { + arg=0; + } else { + arg=model->MOS1gamma/(sarg+sarg); + } + if (vgst <= 0) { + /* + * cutoff region + */ + cdrain=0; + here->MOS1gm=0; + here->MOS1gds=0; + here->MOS1gmbs=0; + } else{ + /* + * saturation region + */ + betap=Beta*(1+model->MOS1lambda*(vds*here->MOS1mode)); + if (vgst <= (vds*here->MOS1mode)){ + cdrain=betap*vgst*vgst*.5; + here->MOS1gm=betap*vgst; + here->MOS1gds=model->MOS1lambda*Beta*vgst*vgst*.5; + here->MOS1gmbs=here->MOS1gm*arg; + } else { + /* + * linear region + */ + cdrain=betap*(vds*here->MOS1mode)* + (vgst-.5*(vds*here->MOS1mode)); + here->MOS1gm=betap*(vds*here->MOS1mode); + here->MOS1gds=betap*(vgst-(vds*here->MOS1mode))+ + model->MOS1lambda*Beta* + (vds*here->MOS1mode)* + (vgst-.5*(vds*here->MOS1mode)); + here->MOS1gmbs=here->MOS1gm*arg; + } + } + /* + * finished + */ + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptg"); +asm("mosptg:"); +#endif /*DETAILPROF*/ + + /* now deal with n vs p polarity */ + + here->MOS1von = model->MOS1type * von; + here->MOS1vdsat = model->MOS1type * vdsat; + /* line 490 */ + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + here->MOS1cd=here->MOS1mode * cdrain - here->MOS1cbd; + + if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) { + /* + * now we do the hard part of the bulk-drain and bulk-source + * diode - we evaluate the non-linear capacitance and + * charge + * + * the basic equations are not hard, but the implementation + * is somewhat long in an attempt to avoid log/exponential + * evaluations + */ + /* + * charge storage elements + * + *.. bulk-drain and bulk-source depletion capacitances + */ +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbs) >= ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS1vbs)))+ + ckt->CKTvoltTol)|| senflag) +#endif /*CAPBYPASS*/ + { + /* can't bypass the diode capacitance calculations */ +#ifdef CAPZEROBYPASS + if(here->MOS1Cbs != 0 || here->MOS1Cbssw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbs < here->MOS1tDepCap){ + arg=1-vbs/here->MOS1tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS1bulkJctBotGradingCoeff == + model->MOS1bulkJctSideGradingCoeff) { + if(model->MOS1bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS1bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS1bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS1bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS1bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS1qbs) = + here->MOS1tBulkPot*(here->MOS1Cbs* + (1-arg*sarg)/(1-model->MOS1bulkJctBotGradingCoeff) + +here->MOS1Cbssw* + (1-arg*sargsw)/ + (1-model->MOS1bulkJctSideGradingCoeff)); + here->MOS1capbs=here->MOS1Cbs*sarg+ + here->MOS1Cbssw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS1qbs) = here->MOS1f4s + + vbs*(here->MOS1f2s+vbs*(here->MOS1f3s/2)); + here->MOS1capbs=here->MOS1f2s+here->MOS1f3s*vbs; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS1qbs) = 0; + here->MOS1capbs=0; + } +#endif /*CAPZEROBYPASS*/ + } +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS1vbd)))+ + ckt->CKTvoltTol)|| senflag) +#endif /*CAPBYPASS*/ + /* can't bypass the diode capacitance calculations */ + { +#ifdef CAPZEROBYPASS + if(here->MOS1Cbd != 0 || here->MOS1Cbdsw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbd < here->MOS1tDepCap) { + arg=1-vbd/here->MOS1tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS1bulkJctBotGradingCoeff == .5 && + model->MOS1bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS1bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS1bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS1bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS1bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS1qbd) = + here->MOS1tBulkPot*(here->MOS1Cbd* + (1-arg*sarg) + /(1-model->MOS1bulkJctBotGradingCoeff) + +here->MOS1Cbdsw* + (1-arg*sargsw) + /(1-model->MOS1bulkJctSideGradingCoeff)); + here->MOS1capbd=here->MOS1Cbd*sarg+ + here->MOS1Cbdsw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS1qbd) = here->MOS1f4d + + vbd * (here->MOS1f2d + vbd * here->MOS1f3d/2); + here->MOS1capbd=here->MOS1f2d + vbd * here->MOS1f3d; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS1qbd) = 0; + here->MOS1capbd = 0; + } +#endif /*CAPZEROBYPASS*/ + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospth"); +asm("mospth:"); +#endif /*DETAILPROF*/ + + if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; + + if ( (ckt->CKTmode & MODETRAN) || ( (ckt->CKTmode&MODEINITTRAN) + && !(ckt->CKTmode&MODEUIC)) ) { + /* (above only excludes tranop, since we're only at this + * point if tran or tranop ) + */ + + /* + * calculate equivalent conductances and currents for + * depletion capacitors + */ + + /* integrate the capacitors and save results */ + + error = NIintegrate(ckt,&geq,&ceq,here->MOS1capbd, + here->MOS1qbd); + if(error) return(error); + here->MOS1gbd += geq; + here->MOS1cbd += *(ckt->CKTstate0 + here->MOS1cqbd); + here->MOS1cd -= *(ckt->CKTstate0 + here->MOS1cqbd); + error = NIintegrate(ckt,&geq,&ceq,here->MOS1capbs, + here->MOS1qbs); + if(error) return(error); + here->MOS1gbs += geq; + here->MOS1cbs += *(ckt->CKTstate0 + here->MOS1cqbs); + } + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospti"); +asm("mospti:"); +#endif /*DETAILPROF*/ + + if(SenCond) goto next2; + + + /* + * check convergence + */ + if ( (here->MOS1off == 0) || + (!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV + } else { + tol=ckt->CKTreltol*MAX(fabs(cdhat), + fabs(here->MOS1cd))+ckt->CKTabstol; + if (fabs(cdhat-here->MOS1cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } else { + tol=ckt->CKTreltol*MAX(fabs(cbhat), + fabs(here->MOS1cbs+here->MOS1cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS1cbs+here->MOS1cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } +#endif /*NEWCONV*/ + } + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptj"); +asm("mosptj:"); +#endif /*DETAILPROF*/ + + /* save things away for next time */ + +next2: *(ckt->CKTstate0 + here->MOS1vbs) = vbs; + *(ckt->CKTstate0 + here->MOS1vbd) = vbd; + *(ckt->CKTstate0 + here->MOS1vgs) = vgs; + *(ckt->CKTstate0 + here->MOS1vds) = vds; + +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptk"); +asm("mosptk:"); +#endif /*DETAILPROF*/ + /* + * meyer's capacitor model + */ + if ( ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG) ) { + /* + * calculate meyer's capacitors + */ + /* + * new cmeyer - this just evaluates at the current time, + * expects you to remember values from previous time + * returns 1/2 of non-constant portion of capacitance + * you must add in the other half from previous time + * and the constant part + */ + if (here->MOS1mode > 0){ + DEVqmeyer (vgs,vgd,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS1capgs), + (ckt->CKTstate0 + here->MOS1capgd), + (ckt->CKTstate0 + here->MOS1capgb), + here->MOS1tPhi,OxideCap); + } else { + DEVqmeyer (vgd,vgs,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS1capgd), + (ckt->CKTstate0 + here->MOS1capgs), + (ckt->CKTstate0 + here->MOS1capgb), + here->MOS1tPhi,OxideCap); + } + vgs1 = *(ckt->CKTstate1 + here->MOS1vgs); + vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS1vds); + vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS1vbs); + if(ckt->CKTmode & (MODETRANOP|MODEINITSMSIG)) { + capgs = 2 * *(ckt->CKTstate0+here->MOS1capgs)+ + GateSourceOverlapCap ; + capgd = 2 * *(ckt->CKTstate0+here->MOS1capgd)+ + GateDrainOverlapCap ; + capgb = 2 * *(ckt->CKTstate0+here->MOS1capgb)+ + GateBulkOverlapCap ; + } else { + capgs = ( *(ckt->CKTstate0+here->MOS1capgs)+ + *(ckt->CKTstate1+here->MOS1capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS1capgd)+ + *(ckt->CKTstate1+here->MOS1capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS1capgb)+ + *(ckt->CKTstate1+here->MOS1capgb) + + GateBulkOverlapCap ); + } + if(ckt->CKTsenInfo){ + here->MOS1cgs = capgs; + here->MOS1cgd = capgd; + here->MOS1cgb = capgb; + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptl"); +asm("mosptl:"); +#endif /*DETAILPROF*/ + /* + * store small-signal parameters (for meyer's model) + * all parameters already stored, so done... + */ + if(SenCond){ + if((ckt->CKTsenInfo->SENmode == DCSEN)|| + (ckt->CKTsenInfo->SENmode == ACSEN)){ + continue; + } + } + +#ifndef PREDICTOR + if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + *(ckt->CKTstate0 + here->MOS1qgs) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS1qgs) + - xfact * *(ckt->CKTstate2 + here->MOS1qgs); + *(ckt->CKTstate0 + here->MOS1qgd) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS1qgd) + - xfact * *(ckt->CKTstate2 + here->MOS1qgd); + *(ckt->CKTstate0 + here->MOS1qgb) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS1qgb) + - xfact * *(ckt->CKTstate2 + here->MOS1qgb); + } else { +#endif /*PREDICTOR*/ + if(ckt->CKTmode & MODETRAN) { + *(ckt->CKTstate0 + here->MOS1qgs) = (vgs-vgs1)*capgs + + *(ckt->CKTstate1 + here->MOS1qgs) ; + *(ckt->CKTstate0 + here->MOS1qgd) = (vgd-vgd1)*capgd + + *(ckt->CKTstate1 + here->MOS1qgd) ; + *(ckt->CKTstate0 + here->MOS1qgb) = (vgb-vgb1)*capgb + + *(ckt->CKTstate1 + here->MOS1qgb) ; + } else { + /* TRANOP only */ + *(ckt->CKTstate0 + here->MOS1qgs) = vgs*capgs; + *(ckt->CKTstate0 + here->MOS1qgd) = vgd*capgd; + *(ckt->CKTstate0 + here->MOS1qgb) = vgb*capgb; + } +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + } +bypass: + if(SenCond) continue; + + if ( (ckt->CKTmode & (MODEINITTRAN)) || + (! (ckt->CKTmode & (MODETRAN)) ) ) { + /* + * initialize to zero charge conductances + * and current + */ + gcgs=0; + ceqgs=0; + gcgd=0; + ceqgd=0; + gcgb=0; + ceqgb=0; + } else { + if(capgs == 0) *(ckt->CKTstate0 + here->MOS1cqgs) =0; + if(capgd == 0) *(ckt->CKTstate0 + here->MOS1cqgd) =0; + if(capgb == 0) *(ckt->CKTstate0 + here->MOS1cqgb) =0; + /* + * calculate equivalent conductances and currents for + * meyer"s capacitors + */ + error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS1qgs); + if(error) return(error); + error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS1qgd); + if(error) return(error); + error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS1qgb); + if(error) return(error); + ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS1qgs); + ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS1qgd); + ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS1qgb); + } + /* + * store charge storage info for meyer's cap in lx table + */ + + /* + * load current vector + */ + ceqbs = model->MOS1type * + (here->MOS1cbs-(here->MOS1gbs-ckt->CKTgmin)*vbs); + ceqbd = model->MOS1type * + (here->MOS1cbd-(here->MOS1gbd-ckt->CKTgmin)*vbd); + if (here->MOS1mode >= 0) { + xnrm=1; + xrev=0; + cdreq=model->MOS1type*(cdrain-here->MOS1gds*vds- + here->MOS1gm*vgs-here->MOS1gmbs*vbs); + } else { + xnrm=0; + xrev=1; + cdreq = -(model->MOS1type)*(cdrain-here->MOS1gds*(-vds)- + here->MOS1gm*vgd-here->MOS1gmbs*vbd); + } + *(ckt->CKTrhs + here->MOS1gNode) -= + (model->MOS1type * (ceqgs + ceqgb + ceqgd)); + *(ckt->CKTrhs + here->MOS1bNode) -= + (ceqbs + ceqbd - model->MOS1type * ceqgb); + *(ckt->CKTrhs + here->MOS1dNodePrime) += + (ceqbd - cdreq + model->MOS1type * ceqgd); + *(ckt->CKTrhs + here->MOS1sNodePrime) += + cdreq + ceqbs + model->MOS1type * ceqgs; + /* + * load y matrix + */ + + *(here->MOS1DdPtr) += (here->MOS1drainConductance); + *(here->MOS1GgPtr) += ((gcgd+gcgs+gcgb)); + *(here->MOS1SsPtr) += (here->MOS1sourceConductance); + *(here->MOS1BbPtr) += (here->MOS1gbd+here->MOS1gbs+gcgb); + *(here->MOS1DPdpPtr) += + (here->MOS1drainConductance+here->MOS1gds+ + here->MOS1gbd+xrev*(here->MOS1gm+here->MOS1gmbs)+gcgd); + *(here->MOS1SPspPtr) += + (here->MOS1sourceConductance+here->MOS1gds+ + here->MOS1gbs+xnrm*(here->MOS1gm+here->MOS1gmbs)+gcgs); + *(here->MOS1DdpPtr) += (-here->MOS1drainConductance); + *(here->MOS1GbPtr) -= gcgb; + *(here->MOS1GdpPtr) -= gcgd; + *(here->MOS1GspPtr) -= gcgs; + *(here->MOS1SspPtr) += (-here->MOS1sourceConductance); + *(here->MOS1BgPtr) -= gcgb; + *(here->MOS1BdpPtr) -= here->MOS1gbd; + *(here->MOS1BspPtr) -= here->MOS1gbs; + *(here->MOS1DPdPtr) += (-here->MOS1drainConductance); + *(here->MOS1DPgPtr) += ((xnrm-xrev)*here->MOS1gm-gcgd); + *(here->MOS1DPbPtr) += (-here->MOS1gbd+(xnrm-xrev)*here->MOS1gmbs); + *(here->MOS1DPspPtr) += (-here->MOS1gds-xnrm* + (here->MOS1gm+here->MOS1gmbs)); + *(here->MOS1SPgPtr) += (-(xnrm-xrev)*here->MOS1gm-gcgs); + *(here->MOS1SPsPtr) += (-here->MOS1sourceConductance); + *(here->MOS1SPbPtr) += (-here->MOS1gbs-(xnrm-xrev)*here->MOS1gmbs); + *(here->MOS1SPdpPtr) += (-here->MOS1gds-xrev* + (here->MOS1gm+here->MOS1gmbs)); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1mask.c b/src/spicelib/devices/mos1/mos1mask.c new file mode 100644 index 000000000..f5509c3e1 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1mask.c @@ -0,0 +1,121 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +MOS1mAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + MOS1model *model = (MOS1model *)inst; + switch(which) { + case MOS1_MOD_TNOM: + value->rValue = model->MOS1tnom-CONSTCtoK; + return(OK); + case MOS1_MOD_VTO: + value->rValue = model->MOS1vt0; + return(OK); + case MOS1_MOD_KP: + value->rValue = model->MOS1transconductance; + return(OK); + case MOS1_MOD_GAMMA: + value->rValue = model->MOS1gamma; + return(OK); + case MOS1_MOD_PHI: + value->rValue = model->MOS1phi; + return(OK); + case MOS1_MOD_LAMBDA: + value->rValue = model->MOS1lambda; + return(OK); + case MOS1_MOD_RD: + value->rValue = model->MOS1drainResistance; + return(OK); + case MOS1_MOD_RS: + value->rValue = model->MOS1sourceResistance; + return(OK); + case MOS1_MOD_CBD: + value->rValue = model->MOS1capBD; + return(OK); + case MOS1_MOD_CBS: + value->rValue = model->MOS1capBS; + return(OK); + case MOS1_MOD_IS: + value->rValue = model->MOS1jctSatCur; + return(OK); + case MOS1_MOD_PB: + value->rValue = model->MOS1bulkJctPotential; + return(OK); + case MOS1_MOD_CGSO: + value->rValue = model->MOS1gateSourceOverlapCapFactor; + return(OK); + case MOS1_MOD_CGDO: + value->rValue = model->MOS1gateDrainOverlapCapFactor; + return(OK); + case MOS1_MOD_CGBO: + value->rValue = model->MOS1gateBulkOverlapCapFactor; + return(OK); + case MOS1_MOD_CJ: + value->rValue = model->MOS1bulkCapFactor; + return(OK); + case MOS1_MOD_MJ: + value->rValue = model->MOS1bulkJctBotGradingCoeff; + return(OK); + case MOS1_MOD_CJSW: + value->rValue = model->MOS1sideWallCapFactor; + return(OK); + case MOS1_MOD_MJSW: + value->rValue = model->MOS1bulkJctSideGradingCoeff; + return(OK); + case MOS1_MOD_JS: + value->rValue = model->MOS1jctSatCurDensity; + return(OK); + case MOS1_MOD_TOX: + value->rValue = model->MOS1oxideThickness; + return(OK); + case MOS1_MOD_LD: + value->rValue = model->MOS1latDiff; + return(OK); + case MOS1_MOD_RSH: + value->rValue = model->MOS1sheetResistance; + return(OK); + case MOS1_MOD_U0: + value->rValue = model->MOS1surfaceMobility; + return(OK); + case MOS1_MOD_FC: + value->rValue = model->MOS1fwdCapDepCoeff; + return(OK); + case MOS1_MOD_NSUB: + value->rValue = model->MOS1substrateDoping; + return(OK); + case MOS1_MOD_TPG: + value->iValue = model->MOS1gateType; + return(OK); + case MOS1_MOD_NSS: + value->rValue = model->MOS1surfaceStateDensity; + return(OK); + case MOS1_MOD_TYPE: + if (model->MOS1type > 0) + value->sValue = "nmos"; + else + value->sValue = "pmos"; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos1/mos1mdel.c b/src/spicelib/devices/mos1/mos1mdel.c new file mode 100644 index 000000000..7669da534 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1mdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS1mDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + MOS1model **model = (MOS1model **)inModel; + MOS1model *modfast = (MOS1model *)kill; + MOS1instance *here; + MOS1instance *prev = NULL; + MOS1model **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->MOS1nextModel)) { + if( (*model)->MOS1modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->MOS1nextModel; /* cut deleted device out of list */ + for(here = (*model)->MOS1instances ; here ; here = here->MOS1nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/mos1/mos1mpar.c b/src/spicelib/devices/mos1/mos1mpar.c new file mode 100644 index 000000000..4eefc0e7d --- /dev/null +++ b/src/spicelib/devices/mos1/mos1mpar.c @@ -0,0 +1,158 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1mParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + register MOS1model *model = (MOS1model *)inModel; + switch(param) { + case MOS1_MOD_TNOM: + model->MOS1tnom = value->rValue+CONSTCtoK; + model->MOS1tnomGiven = TRUE; + break; + case MOS1_MOD_VTO: + model->MOS1vt0 = value->rValue; + model->MOS1vt0Given = TRUE; + break; + case MOS1_MOD_KP: + model->MOS1transconductance = value->rValue; + model->MOS1transconductanceGiven = TRUE; + break; + case MOS1_MOD_GAMMA: + model->MOS1gamma = value->rValue; + model->MOS1gammaGiven = TRUE; + break; + case MOS1_MOD_PHI: + model->MOS1phi = value->rValue; + model->MOS1phiGiven = TRUE; + break; + case MOS1_MOD_LAMBDA: + model->MOS1lambda = value->rValue; + model->MOS1lambdaGiven = TRUE; + break; + case MOS1_MOD_RD: + model->MOS1drainResistance = value->rValue; + model->MOS1drainResistanceGiven = TRUE; + break; + case MOS1_MOD_RS: + model->MOS1sourceResistance = value->rValue; + model->MOS1sourceResistanceGiven = TRUE; + break; + case MOS1_MOD_CBD: + model->MOS1capBD = value->rValue; + model->MOS1capBDGiven = TRUE; + break; + case MOS1_MOD_CBS: + model->MOS1capBS = value->rValue; + model->MOS1capBSGiven = TRUE; + break; + case MOS1_MOD_IS: + model->MOS1jctSatCur = value->rValue; + model->MOS1jctSatCurGiven = TRUE; + break; + case MOS1_MOD_PB: + model->MOS1bulkJctPotential = value->rValue; + model->MOS1bulkJctPotentialGiven = TRUE; + break; + case MOS1_MOD_CGSO: + model->MOS1gateSourceOverlapCapFactor = value->rValue; + model->MOS1gateSourceOverlapCapFactorGiven = TRUE; + break; + case MOS1_MOD_CGDO: + model->MOS1gateDrainOverlapCapFactor = value->rValue; + model->MOS1gateDrainOverlapCapFactorGiven = TRUE; + break; + case MOS1_MOD_CGBO: + model->MOS1gateBulkOverlapCapFactor = value->rValue; + model->MOS1gateBulkOverlapCapFactorGiven = TRUE; + break; + case MOS1_MOD_CJ: + model->MOS1bulkCapFactor = value->rValue; + model->MOS1bulkCapFactorGiven = TRUE; + break; + case MOS1_MOD_MJ: + model->MOS1bulkJctBotGradingCoeff = value->rValue; + model->MOS1bulkJctBotGradingCoeffGiven = TRUE; + break; + case MOS1_MOD_CJSW: + model->MOS1sideWallCapFactor = value->rValue; + model->MOS1sideWallCapFactorGiven = TRUE; + break; + case MOS1_MOD_MJSW: + model->MOS1bulkJctSideGradingCoeff = value->rValue; + model->MOS1bulkJctSideGradingCoeffGiven = TRUE; + break; + case MOS1_MOD_JS: + model->MOS1jctSatCurDensity = value->rValue; + model->MOS1jctSatCurDensityGiven = TRUE; + break; + case MOS1_MOD_TOX: + model->MOS1oxideThickness = value->rValue; + model->MOS1oxideThicknessGiven = TRUE; + break; + case MOS1_MOD_LD: + model->MOS1latDiff = value->rValue; + model->MOS1latDiffGiven = TRUE; + break; + case MOS1_MOD_RSH: + model->MOS1sheetResistance = value->rValue; + model->MOS1sheetResistanceGiven = TRUE; + break; + case MOS1_MOD_U0: + model->MOS1surfaceMobility = value->rValue; + model->MOS1surfaceMobilityGiven = TRUE; + break; + case MOS1_MOD_FC: + model->MOS1fwdCapDepCoeff = value->rValue; + model->MOS1fwdCapDepCoeffGiven = TRUE; + break; + case MOS1_MOD_NSS: + model->MOS1surfaceStateDensity = value->rValue; + model->MOS1surfaceStateDensityGiven = TRUE; + break; + case MOS1_MOD_NSUB: + model->MOS1substrateDoping = value->rValue; + model->MOS1substrateDopingGiven = TRUE; + break; + case MOS1_MOD_TPG: + model->MOS1gateType = value->iValue; + model->MOS1gateTypeGiven = TRUE; + break; + case MOS1_MOD_NMOS: + if(value->iValue) { + model->MOS1type = 1; + model->MOS1typeGiven = TRUE; + } + break; + case MOS1_MOD_PMOS: + if(value->iValue) { + model->MOS1type = -1; + model->MOS1typeGiven = TRUE; + } + break; + case MOS1_MOD_KF: + model->MOS1fNcoef = value->rValue; + model->MOS1fNcoefGiven = TRUE; + break; + case MOS1_MOD_AF: + model->MOS1fNexp = value->rValue; + model->MOS1fNexpGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1noi.c b/src/spicelib/devices/mos1/mos1noi.c new file mode 100644 index 000000000..666a20281 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1noi.c @@ -0,0 +1,226 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "mos1defs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * MOS1noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MOSFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MOSFET's is summed with the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +MOS1noise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + MOS1model *firstModel = (MOS1model *) genmodel; + register MOS1model *model; + register MOS1instance *inst; + char name[N_MXVLNTH]; + double coxSquared; + double tempOnoise; + double tempInoise; + double noizDens[MOS1NSRCS]; + double lnNdens[MOS1NSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *MOS1nNames[MOS1NSRCS] = { /* Note that we have to keep the order */ + "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ + "_rs", /* noise due to rs */ /* in MOS1defs.h */ + "_id", /* noise due to id */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->MOS1nextModel) { + + /* Oxide capacitance can be zero in MOS level 1. Since this will give us problems in our 1/f */ + /* noise model, we ASSUME an actual "tox" of 1e-7 */ + + if (model->MOS1oxideCapFactor == 0.0) { + coxSquared = 3.9 * 8.854214871e-12 / 1e-7; + } else { + coxSquared = model->MOS1oxideCapFactor; + } + coxSquared *= coxSquared; + for (inst=model->MOS1instances; inst != NULL; inst=inst->MOS1nextInstance) { + if (inst->MOS1owner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < MOS1NSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->MOS1name,MOS1nNames[i]); + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + + case INT_NOIZ: + for (i=0; i < MOS1NSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->MOS1name,MOS1nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->MOS1name,MOS1nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[MOS1RDNOIZ],&lnNdens[MOS1RDNOIZ], + ckt,THERMNOISE,inst->MOS1dNodePrime,inst->MOS1dNode, + inst->MOS1drainConductance); + + NevalSrc(&noizDens[MOS1RSNOIZ],&lnNdens[MOS1RSNOIZ], + ckt,THERMNOISE,inst->MOS1sNodePrime,inst->MOS1sNode, + inst->MOS1sourceConductance); + + NevalSrc(&noizDens[MOS1IDNOIZ],&lnNdens[MOS1IDNOIZ], + ckt,THERMNOISE,inst->MOS1dNodePrime,inst->MOS1sNodePrime, + (2.0/3.0 * fabs(inst->MOS1gm))); + + NevalSrc(&noizDens[MOS1FLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->MOS1dNodePrime, inst->MOS1sNodePrime, + (double)0.0); + noizDens[MOS1FLNOIZ] *= model->MOS1fNcoef * + exp(model->MOS1fNexp * + log(MAX(fabs(inst->MOS1cd),N_MINLOG))) / + (data->freq * inst->MOS1w * + (inst->MOS1l - 2*model->MOS1latDiff) * coxSquared); + lnNdens[MOS1FLNOIZ] = + log(MAX(noizDens[MOS1FLNOIZ],N_MINLOG)); + + noizDens[MOS1TOTNOIZ] = noizDens[MOS1RDNOIZ] + + noizDens[MOS1RSNOIZ] + + noizDens[MOS1IDNOIZ] + + noizDens[MOS1FLNOIZ]; + lnNdens[MOS1TOTNOIZ] = + log(MAX(noizDens[MOS1TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[MOS1TOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < MOS1NSRCS; i++) { + inst->MOS1nVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < MOS1NSRCS; i++) { + inst->MOS1nVar[OUTNOIZ][i] = 0.0; + inst->MOS1nVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + for (i=0; i < MOS1NSRCS; i++) { + if (i != MOS1TOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->MOS1nVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->MOS1nVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->MOS1nVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->MOS1nVar[OUTNOIZ][i] += tempOnoise; + inst->MOS1nVar[OUTNOIZ][MOS1TOTNOIZ] += tempOnoise; + inst->MOS1nVar[INNOIZ][i] += tempInoise; + inst->MOS1nVar[INNOIZ][MOS1TOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < MOS1NSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < MOS1NSRCS; i++) { + data->outpVector[data->outNumber++] = inst->MOS1nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->MOS1nVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1par.c b/src/spicelib/devices/mos1/mos1par.c new file mode 100644 index 000000000..a8dbce338 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1par.c @@ -0,0 +1,110 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MOS1param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + MOS1instance *here = (MOS1instance *)inst; + switch(param) { + case MOS1_TEMP: + here->MOS1temp = value->rValue+CONSTCtoK; + here->MOS1tempGiven = TRUE; + break; + case MOS1_W: + here->MOS1w = value->rValue; + here->MOS1wGiven = TRUE; + break; + case MOS1_L: + here->MOS1l = value->rValue; + here->MOS1lGiven = TRUE; + break; + case MOS1_AS: + here->MOS1sourceArea = value->rValue; + here->MOS1sourceAreaGiven = TRUE; + break; + case MOS1_AD: + here->MOS1drainArea = value->rValue; + here->MOS1drainAreaGiven = TRUE; + break; + case MOS1_PS: + here->MOS1sourcePerimiter = value->rValue; + here->MOS1sourcePerimiterGiven = TRUE; + break; + case MOS1_PD: + here->MOS1drainPerimiter = value->rValue; + here->MOS1drainPerimiterGiven = TRUE; + break; + case MOS1_NRS: + here->MOS1sourceSquares = value->rValue; + here->MOS1sourceSquaresGiven = TRUE; + break; + case MOS1_NRD: + here->MOS1drainSquares = value->rValue; + here->MOS1drainSquaresGiven = TRUE; + break; + case MOS1_OFF: + here->MOS1off = value->iValue; + break; + case MOS1_IC_VBS: + here->MOS1icVBS = value->rValue; + here->MOS1icVBSGiven = TRUE; + break; + case MOS1_IC_VDS: + here->MOS1icVDS = value->rValue; + here->MOS1icVDSGiven = TRUE; + break; + case MOS1_IC_VGS: + here->MOS1icVGS = value->rValue; + here->MOS1icVGSGiven = TRUE; + break; + case MOS1_IC: + switch(value->v.numValue){ + case 3: + here->MOS1icVBS = *(value->v.vec.rVec+2); + here->MOS1icVBSGiven = TRUE; + case 2: + here->MOS1icVGS = *(value->v.vec.rVec+1); + here->MOS1icVGSGiven = TRUE; + case 1: + here->MOS1icVDS = *(value->v.vec.rVec); + here->MOS1icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + case MOS1_L_SENS: + if(value->iValue) { + here->MOS1senParmNo = 1; + here->MOS1sens_l = 1; + } + break; + case MOS1_W_SENS: + if(value->iValue) { + here->MOS1senParmNo = 1; + here->MOS1sens_w = 1; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1pzld.c b/src/spicelib/devices/mos1/mos1pzld.c new file mode 100644 index 000000000..162dd9dd4 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1pzld.c @@ -0,0 +1,134 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS1pzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; +{ + register MOS1model *model = (MOS1model*)inModel; + register MOS1instance *here; + int xnrm; + int xrev; + double xgs; + double xgd; + double xgb; + double xbd; + double xbs; + double capgs; + double capgd; + double capgb; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double EffectiveLength; + + for( ; model != NULL; model = model->MOS1nextModel) { + for(here = model->MOS1instances; here!= NULL; + here = here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + if (here->MOS1mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * meyer's model parameters + */ + EffectiveLength=here->MOS1l - 2*model->MOS1latDiff; + GateSourceOverlapCap = model->MOS1gateSourceOverlapCapFactor * + here->MOS1w; + GateDrainOverlapCap = model->MOS1gateDrainOverlapCapFactor * + here->MOS1w; + GateBulkOverlapCap = model->MOS1gateBulkOverlapCapFactor * + EffectiveLength; + capgs = ( 2* *(ckt->CKTstate0+here->MOS1capgs)+ + GateSourceOverlapCap ); + capgd = ( 2* *(ckt->CKTstate0+here->MOS1capgd)+ + GateDrainOverlapCap ); + capgb = ( 2* *(ckt->CKTstate0+here->MOS1capgb)+ + GateBulkOverlapCap ); + xgs = capgs; + xgd = capgd; + xgb = capgb; + xbd = here->MOS1capbd; + xbs = here->MOS1capbs; + /*printf("mos2: xgs=%g, xgd=%g, xgb=%g, xbd=%g, xbs=%g\n", + xgs,xgd,xgb,xbd,xbs);*/ + /* + * load matrix + */ + + *(here->MOS1GgPtr ) += (xgd+xgs+xgb)*s->real; + *(here->MOS1GgPtr +1) += (xgd+xgs+xgb)*s->imag; + *(here->MOS1BbPtr ) += (xgb+xbd+xbs)*s->real; + *(here->MOS1BbPtr +1) += (xgb+xbd+xbs)*s->imag; + *(here->MOS1DPdpPtr ) += (xgd+xbd)*s->real; + *(here->MOS1DPdpPtr +1) += (xgd+xbd)*s->imag; + *(here->MOS1SPspPtr ) += (xgs+xbs)*s->real; + *(here->MOS1SPspPtr +1) += (xgs+xbs)*s->imag; + *(here->MOS1GbPtr ) -= xgb*s->real; + *(here->MOS1GbPtr +1) -= xgb*s->imag; + *(here->MOS1GdpPtr ) -= xgd*s->real; + *(here->MOS1GdpPtr +1) -= xgd*s->imag; + *(here->MOS1GspPtr ) -= xgs*s->real; + *(here->MOS1GspPtr +1) -= xgs*s->imag; + *(here->MOS1BgPtr ) -= xgb*s->real; + *(here->MOS1BgPtr +1) -= xgb*s->imag; + *(here->MOS1BdpPtr ) -= xbd*s->real; + *(here->MOS1BdpPtr +1) -= xbd*s->imag; + *(here->MOS1BspPtr ) -= xbs*s->real; + *(here->MOS1BspPtr +1) -= xbs*s->imag; + *(here->MOS1DPgPtr ) -= xgd*s->real; + *(here->MOS1DPgPtr +1) -= xgd*s->imag; + *(here->MOS1DPbPtr ) -= xbd*s->real; + *(here->MOS1DPbPtr +1) -= xbd*s->imag; + *(here->MOS1SPgPtr ) -= xgs*s->real; + *(here->MOS1SPgPtr +1) -= xgs*s->imag; + *(here->MOS1SPbPtr ) -= xbs*s->real; + *(here->MOS1SPbPtr +1) -= xbs*s->imag; + *(here->MOS1DdPtr) += here->MOS1drainConductance; + *(here->MOS1SsPtr) += here->MOS1sourceConductance; + *(here->MOS1BbPtr) += here->MOS1gbd+here->MOS1gbs; + *(here->MOS1DPdpPtr) += here->MOS1drainConductance+ + here->MOS1gds+here->MOS1gbd+ + xrev*(here->MOS1gm+here->MOS1gmbs); + *(here->MOS1SPspPtr) += here->MOS1sourceConductance+ + here->MOS1gds+here->MOS1gbs+ + xnrm*(here->MOS1gm+here->MOS1gmbs); + *(here->MOS1DdpPtr) -= here->MOS1drainConductance; + *(here->MOS1SspPtr) -= here->MOS1sourceConductance; + *(here->MOS1BdpPtr) -= here->MOS1gbd; + *(here->MOS1BspPtr) -= here->MOS1gbs; + *(here->MOS1DPdPtr) -= here->MOS1drainConductance; + *(here->MOS1DPgPtr) += (xnrm-xrev)*here->MOS1gm; + *(here->MOS1DPbPtr) += -here->MOS1gbd+(xnrm-xrev)*here->MOS1gmbs; + *(here->MOS1DPspPtr) -= here->MOS1gds+ + xnrm*(here->MOS1gm+here->MOS1gmbs); + *(here->MOS1SPgPtr) -= (xnrm-xrev)*here->MOS1gm; + *(here->MOS1SPsPtr) -= here->MOS1sourceConductance; + *(here->MOS1SPbPtr) -= here->MOS1gbs+(xnrm-xrev)*here->MOS1gmbs; + *(here->MOS1SPdpPtr) -= here->MOS1gds+ + xrev*(here->MOS1gm+here->MOS1gmbs); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1sacl.c b/src/spicelib/devices/mos1/mos1sacl.c new file mode 100644 index 000000000..53fabf24a --- /dev/null +++ b/src/spicelib/devices/mos1/mos1sacl.c @@ -0,0 +1,787 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "const.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +int +MOS1sAcLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ + register MOS1model *model = (MOS1model*)inModel; + register MOS1instance *here; + int xnrm; + int xrev; + double A0; + double Apert; + double DELA; + double DELAinv; + double gdpr0; + double gspr0; + double gds0; + double gbs0; + double gbd0; + double gm0; + double gmbs0; + double gdpr; + double gspr; + double gds; + double gbs; + double gbd; + double gm; + double gmbs; + double xcgs0; + double xcgd0; + double xcgb0; + double xbd0; + double xbs0; + double xcgs; + double xcgd; + double xcgb; + double xbd; + double xbs; + double vbsOp; + double vbdOp; + double vspr; + double vdpr; + double vgs; + double vgd; + double vgb; + double vbs; + double vbd; + double vds; + double ivspr; + double ivdpr; + double ivgs; + double ivgd; + double ivgb; + double ivbs; + double ivbd; + double ivds; + double cspr; + double cdpr; + double cgs; + double cgd; + double cgb; + double cbs; + double cbd; + double cds; + double cs0; + double csprm0; + double cd0; + double cdprm0; + double cg0; + double cb0; + double cs; + double csprm; + double cd; + double cdprm; + double cg; + double cb; + double icspr; + double icdpr; + double icgs; + double icgd; + double icgb; + double icbs; + double icbd; + double icds; + double ics0; + double icsprm0; + double icd0; + double icdprm0; + double icg0; + double icb0; + double ics; + double icsprm; + double icd; + double icdprm; + double icg; + double icb; + double DvDp; + int i; + int flag; + int error; + int iparmno; + double arg; + double sarg; + double sargsw; + double SaveState[44]; + int save_mode; + SENstruct *info; + +#ifdef SENSDEBUG + printf("MOS1senacload\n"); + printf("CKTomega = %.5e\n",ckt->CKTomega); +#endif /* SENSDEBUG */ + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + for( ; model != NULL; model = model->MOS1nextModel) { + for(here = model->MOS1instances; here!= NULL; + here = here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++) + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS1states + i); + + *(SaveState + 17) = here->MOS1sourceConductance; + *(SaveState + 18) = here->MOS1drainConductance; + *(SaveState + 19) = here->MOS1cd; + *(SaveState + 20) = here->MOS1cbs; + *(SaveState + 21) = here->MOS1cbd; + *(SaveState + 22) = here->MOS1gmbs; + *(SaveState + 23) = here->MOS1gm; + *(SaveState + 24) = here->MOS1gds; + *(SaveState + 25) = here->MOS1gbd; + *(SaveState + 26) = here->MOS1gbs; + *(SaveState + 27) = here->MOS1capbd; + *(SaveState + 28) = here->MOS1capbs; + *(SaveState + 29) = here->MOS1Cbd; + *(SaveState + 30) = here->MOS1Cbdsw; + *(SaveState + 31) = here->MOS1Cbs; + *(SaveState + 32) = here->MOS1Cbssw; + *(SaveState + 33) = here->MOS1f2d; + *(SaveState + 34) = here->MOS1f3d; + *(SaveState + 35) = here->MOS1f4d; + *(SaveState + 36) = here->MOS1f2s; + *(SaveState + 37) = here->MOS1f3s; + *(SaveState + 38) = here->MOS1f4s; + *(SaveState + 39) = here->MOS1cgs; + *(SaveState + 40) = here->MOS1cgd; + *(SaveState + 41) = here->MOS1cgb; + *(SaveState + 42) = here->MOS1vdsat; + *(SaveState + 43) = here->MOS1von; + save_mode = here->MOS1mode; + + xnrm=1; + xrev=0; + if (here->MOS1mode < 0) { + xnrm=0; + xrev=1; + } + + vbsOp = model->MOS1type * ( + *(ckt->CKTrhsOp+here->MOS1bNode) - + *(ckt->CKTrhsOp+here->MOS1sNodePrime)); + vbdOp = model->MOS1type * ( + *(ckt->CKTrhsOp+here->MOS1bNode) - + *(ckt->CKTrhsOp+here->MOS1dNodePrime)); + vspr = *(ckt->CKTrhsOld + here->MOS1sNode) + - *(ckt->CKTrhsOld + + here->MOS1sNodePrime) ; + ivspr = *(ckt->CKTirhsOld + here->MOS1sNode) + - *(ckt->CKTirhsOld + + here->MOS1sNodePrime) ; + vdpr = *(ckt->CKTrhsOld + here->MOS1dNode) + - *(ckt->CKTrhsOld + + here->MOS1dNodePrime) ; + ivdpr = *(ckt->CKTirhsOld + here->MOS1dNode) + - *(ckt->CKTirhsOld + + here->MOS1dNodePrime) ; + vgb = *(ckt->CKTrhsOld + here->MOS1gNode) + - *(ckt->CKTrhsOld + + here->MOS1bNode) ; + ivgb = *(ckt->CKTirhsOld + here->MOS1gNode) + - *(ckt->CKTirhsOld + + here->MOS1bNode) ; + vbs = *(ckt->CKTrhsOld + here->MOS1bNode) + - *(ckt->CKTrhsOld + + here->MOS1sNodePrime) ; + ivbs = *(ckt->CKTirhsOld + here->MOS1bNode) + - *(ckt->CKTirhsOld + + here->MOS1sNodePrime) ; + vbd = *(ckt->CKTrhsOld + here->MOS1bNode) + - *(ckt->CKTrhsOld + + here->MOS1dNodePrime) ; + ivbd = *(ckt->CKTirhsOld + here->MOS1bNode) + - *(ckt->CKTirhsOld + + here->MOS1dNodePrime) ; + vds = vbs - vbd ; + ivds = ivbs - ivbd ; + vgs = vgb + vbs ; + ivgs = ivgb + ivbs ; + vgd = vgb + vbd ; + ivgd = ivgb + ivbd ; + +#ifdef SENSDEBUG + printf("senacload instance name %s\n",here->MOS1name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS1gNode,here->MOS1dNode,here->MOS1dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS1sNode ,here->MOS1sNodePrime,here->MOS1bNode, + here->MOS1senParmNo); + printf("\n without perturbation \n"); +#endif /* SENSDEBUG */ + /* without perturbation */ + *(ckt->CKTstate0 + here->MOS1vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS1vbd) = vbdOp; + + here->MOS1senPertFlag = ON ; + if(info->SENacpertflag == 1){ + /* store the unperturbed values of small signal parameters */ + if((error = MOS1load((GENmodel*)model,ckt))) + return(error); + *(here->MOS1senCgs) = here->MOS1cgs; + *(here->MOS1senCgd) = here->MOS1cgd; + *(here->MOS1senCgb) = here->MOS1cgb; + *(here->MOS1senCbd) = here->MOS1capbd; + *(here->MOS1senCbs) = here->MOS1capbs; + *(here->MOS1senGds) = here->MOS1gds; + *(here->MOS1senGbs) = here->MOS1gbs; + *(here->MOS1senGbd) = here->MOS1gbd; + *(here->MOS1senGm) = here->MOS1gm; + *(here->MOS1senGmbs) = here->MOS1gmbs; + + } + xcgs0= *(here->MOS1senCgs) * ckt->CKTomega; + xcgd0= *(here->MOS1senCgd) * ckt->CKTomega; + xcgb0= *(here->MOS1senCgb) * ckt->CKTomega; + xbd0= *(here->MOS1senCbd) * ckt->CKTomega; + xbs0= *(here->MOS1senCbs) * ckt->CKTomega; + gds0= *(here->MOS1senGds); + gbs0= *(here->MOS1senGbs); + gbd0= *(here->MOS1senGbd); + gm0= *(here->MOS1senGm); + gmbs0= *(here->MOS1senGmbs); + gdpr0 = here->MOS1drainConductance; + gspr0 = here->MOS1sourceConductance; + + + cspr = gspr0 * vspr ; + icspr = gspr0 * ivspr ; + cdpr = gdpr0 * vdpr ; + icdpr = gdpr0 * ivdpr ; + cgs = ( - xcgs0 * ivgs ); + icgs = xcgs0 * vgs ; + cgd = ( - xcgd0 * ivgd ); + icgd = xcgd0 * vgd ; + cgb = ( - xcgb0 * ivgb ); + icgb = xcgb0 * vgb ; + cbs = ( gbs0 * vbs - xbs0 * ivbs ); + icbs = ( xbs0 * vbs + gbs0 * ivbs ); + cbd = ( gbd0 * vbd - xbd0 * ivbd ); + icbd = ( xbd0 * vbd + gbd0 * ivbd ); + cds = ( gds0 * vds + xnrm * (gm0 * vgs + gmbs0 * vbs) + - xrev * (gm0 * vgd + gmbs0 * vbd) ); + icds = ( gds0 * ivds + xnrm * (gm0 * ivgs + gmbs0 * ivbs) + - xrev * (gm0 * ivgd + gmbs0 * ivbd) ); + + cs0 = cspr; + ics0 = icspr; + csprm0 = ( -cspr - cgs - cbs - cds ) ; + icsprm0 = ( -icspr - icgs - icbs - icds ) ; + cd0 = cdpr; + icd0 = icdpr; + cdprm0 = ( -cdpr - cgd - cbd + cds ) ; + icdprm0 = ( -icdpr - icgd - icbd + icds ) ; + cg0 = cgs + cgd + cgb ; + icg0 = icgs + icgd + icgb ; + cb0 = cbs + cbd - cgb ; + icb0 = icbs + icbd - icgb ; +#ifdef SENSDEBUG + printf("gspr0 = %.7e , gdpr0 = %.7e , gds0 = %.7e, gbs0 = %.7e\n", + gspr0,gdpr0,gds0,gbs0); + printf("gbd0 = %.7e , gm0 = %.7e , gmbs0 = %.7e\n",gbd0,gm0,gmbs0); + printf("xcgs0 = %.7e , xcgd0 = %.7e , xcgb0 = %.7e,", + xcgs0,xcgd0,xcgb0); + printf("xbd0 = %.7e,xbs0 = %.7e\n",xbd0,xbs0); + printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); + printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); + printf("cbs0 = %.7e , cbd0 = %.7e , cgb0 = %.7e\n",cbs,cbd,cgb); + printf("cb0 = %.7e , cg0 = %.7e , cs0 = %.7e\n",cb0,cg0,cs0); + printf("csprm0 = %.7e, cd0 = %.7e, cdprm0 = %.7e\n", + csprm0,cd0,cdprm0); + printf("icb0 = %.7e , icg0 = %.7e , ics0 = %.7e\n",icb0,icg0,ics0); + printf("icsprm0 = %.7e, icd0 = %.7e, icdprm0 = %.7e\n", + icsprm0,icd0,icdprm0); + printf("\nPerturbation of vbs\n"); +#endif /* SENSDEBUG */ + + /* Perturbation of vbs */ + flag = 1; + A0 = vbsOp; + DELA = info->SENpertfac * here->MOS1tVto ; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vbs */ + Apert = A0 + DELA; + *(ckt->CKTstate0 + here->MOS1vbs) = Apert; + *(ckt->CKTstate0 + here->MOS1vbd) = vbdOp; + + if((error = MOS1load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS1senCgs + 1) = here->MOS1cgs; + *(here->MOS1senCgd + 1) = here->MOS1cgd; + *(here->MOS1senCgb + 1) = here->MOS1cgb; + *(here->MOS1senCbd + 1) = here->MOS1capbd; + *(here->MOS1senCbs + 1) = here->MOS1capbs; + *(here->MOS1senGds + 1) = here->MOS1gds; + *(here->MOS1senGbs + 1) = here->MOS1gbs; + *(here->MOS1senGbd + 1) = here->MOS1gbd; + *(here->MOS1senGm + 1) = here->MOS1gm; + *(here->MOS1senGmbs + 1) = here->MOS1gmbs; + + *(ckt->CKTstate0 + here->MOS1vbs) = A0; + + + } + + goto load; + + +pertvbd: /* Perturbation of vbd */ +#ifdef SENSDEBUG + printf("\nPerturbation of vbd\n"); +#endif /* SENSDEBUG */ + + flag = 2; + A0 = vbdOp; + DELA = info->SENpertfac * here->MOS1tVto + 1e-8; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vbd */ + Apert = A0 + DELA; + *(ckt->CKTstate0 + here->MOS1vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS1vbd) = Apert; + + if((error = MOS1load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS1senCgs + 2) = here->MOS1cgs; + *(here->MOS1senCgd + 2) = here->MOS1cgd; + *(here->MOS1senCgb + 2) = here->MOS1cgb; + *(here->MOS1senCbd + 2) = here->MOS1capbd; + *(here->MOS1senCbs + 2) = here->MOS1capbs; + *(here->MOS1senGds + 2) = here->MOS1gds; + *(here->MOS1senGbs + 2) = here->MOS1gbs; + *(here->MOS1senGbd + 2) = here->MOS1gbd; + *(here->MOS1senGm + 2) = here->MOS1gm; + *(here->MOS1senGmbs + 2) = here->MOS1gmbs; + + *(ckt->CKTstate0 + here->MOS1vbd) = A0; + + } + + goto load; + + +pertvgb: /* Perturbation of vgb */ +#ifdef SENSDEBUG + printf("\nPerturbation of vgb\n"); +#endif /* SENSDEBUG */ + + flag = 3; + A0 = model->MOS1type * (*(ckt->CKTrhsOp + here->MOS1gNode) + - *(ckt->CKTrhsOp + here->MOS1bNode)); + DELA = info->SENpertfac * A0 + 1e-8; + DELAinv = model->MOS1type * 1.0/DELA; + + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vgb */ + *(ckt->CKTstate0 + here->MOS1vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS1vbd) = vbdOp; + *(ckt->CKTrhsOp + here->MOS1bNode) -= DELA; + + if((error = MOS1load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS1senCgs + 3) = here->MOS1cgs; + *(here->MOS1senCgd + 3) = here->MOS1cgd; + *(here->MOS1senCgb + 3) = here->MOS1cgb; + *(here->MOS1senCbd + 3) = here->MOS1capbd; + *(here->MOS1senCbs + 3) = here->MOS1capbs; + *(here->MOS1senGds + 3) = here->MOS1gds; + *(here->MOS1senGbs + 3) = here->MOS1gbs; + *(here->MOS1senGbd + 3) = here->MOS1gbd; + *(here->MOS1senGm + 3) = here->MOS1gm; + *(here->MOS1senGmbs + 3) = here->MOS1gmbs; + + + *(ckt->CKTrhsOp + here->MOS1bNode) += DELA; + } + goto load; + +pertl: /* Perturbation of length */ + + if(here->MOS1sens_l == 0){ + goto pertw; + } +#ifdef SENSDEBUG + printf("\nPerturbation of length\n"); +#endif /* SENSDEBUG */ + flag = 4; + A0 = here->MOS1l; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed length */ + Apert = A0 + DELA; + here->MOS1l = Apert; + + *(ckt->CKTstate0 + here->MOS1vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS1vbd) = vbdOp; + + if ((error = MOS1load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS1senCgs + 4) = here->MOS1cgs; + *(here->MOS1senCgd + 4) = here->MOS1cgd; + *(here->MOS1senCgb + 4) = here->MOS1cgb; + *(here->MOS1senCbd + 4) = here->MOS1capbd; + *(here->MOS1senCbs + 4) = here->MOS1capbs; + *(here->MOS1senGds + 4) = here->MOS1gds; + *(here->MOS1senGbs + 4) = here->MOS1gbs; + *(here->MOS1senGbd + 4) = here->MOS1gbd; + *(here->MOS1senGm + 4) = here->MOS1gm; + *(here->MOS1senGmbs + 4) = here->MOS1gmbs; + + here->MOS1l = A0; + + } + + goto load; + +pertw: /* Perturbation of width */ + if(here->MOS1sens_w == 0) + goto next; +#ifdef SENSDEBUG + printf("\nPerturbation of width\n"); +#endif /* SENSDEBUG */ + flag = 5; + A0 = here->MOS1w; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed width */ + here->MOS1w = Apert; + here->MOS1drainArea *= (1 + info->SENpertfac); + here->MOS1sourceArea *= (1 + info->SENpertfac); + here->MOS1Cbd *= (1 + info->SENpertfac); + here->MOS1Cbs *= (1 + info->SENpertfac); + if(here->MOS1drainPerimiter){ + here->MOS1Cbdsw += here->MOS1Cbdsw * + DELA/here->MOS1drainPerimiter; + } + if(here->MOS1sourcePerimiter){ + here->MOS1Cbssw += here->MOS1Cbssw * + DELA/here->MOS1sourcePerimiter; + } + if(vbdOp >= here->MOS1tDepCap){ + arg = 1-model->MOS1fwdCapDepCoeff; + sarg = exp( (-model->MOS1bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS1bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS1f2d = here->MOS1Cbd*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctBotGradingCoeff))* sarg/arg + + here->MOS1Cbdsw*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS1f3d = here->MOS1Cbd * + model->MOS1bulkJctBotGradingCoeff * sarg/arg/ + here->MOS1tBulkPot + here->MOS1Cbdsw * + model->MOS1bulkJctSideGradingCoeff * sargsw/arg / + here->MOS1tBulkPot; + here->MOS1f4d = here->MOS1Cbd*here->MOS1tBulkPot* + (1-arg*sarg)/ (1-model->MOS1bulkJctBotGradingCoeff) + + here->MOS1Cbdsw*here->MOS1tBulkPot*(1-arg*sargsw)/ + (1-model->MOS1bulkJctSideGradingCoeff) + -here->MOS1f3d/2* + (here->MOS1tDepCap*here->MOS1tDepCap) + -here->MOS1tDepCap * here->MOS1f2d; + } + if(vbsOp >= here->MOS1tDepCap){ + arg = 1-model->MOS1fwdCapDepCoeff; + sarg = exp( (-model->MOS1bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS1bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS1f2s = here->MOS1Cbs*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctBotGradingCoeff))* sarg/arg + + here->MOS1Cbssw*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS1f3s = here->MOS1Cbs * + model->MOS1bulkJctBotGradingCoeff * sarg/arg/ + here->MOS1tBulkPot + here->MOS1Cbssw * + model->MOS1bulkJctSideGradingCoeff * sargsw/arg / + here->MOS1tBulkPot; + here->MOS1f4s = here->MOS1Cbs* + here->MOS1tBulkPot*(1-arg*sarg)/ + (1-model->MOS1bulkJctBotGradingCoeff) + + here->MOS1Cbssw*here->MOS1tBulkPot*(1-arg*sargsw)/ + (1-model->MOS1bulkJctSideGradingCoeff) + -here->MOS1f3s/2* + (here->MOS1tDepCap*here->MOS1tDepCap) + -here->MOS1tDepCap * here->MOS1f2s; + } + + *(ckt->CKTstate0 + here->MOS1vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS1vbd) = vbdOp; + + if ((error = MOS1load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS1senCgs + 5) = here->MOS1cgs; + *(here->MOS1senCgd + 5) = here->MOS1cgd; + *(here->MOS1senCgb + 5) = here->MOS1cgb; + *(here->MOS1senCbd + 5) = here->MOS1capbd; + *(here->MOS1senCbs + 5) = here->MOS1capbs; + *(here->MOS1senGds + 5) = here->MOS1gds; + *(here->MOS1senGbs + 5) = here->MOS1gbs; + *(here->MOS1senGbd + 5) = here->MOS1gbd; + *(here->MOS1senGm + 5) = here->MOS1gm; + *(here->MOS1senGmbs + 5) = here->MOS1gmbs; + + here->MOS1w = A0; + here->MOS1drainArea /= (1 + info->SENpertfac); + here->MOS1sourceArea /= (1 + info->SENpertfac); + } + +load: + + gds= *(here->MOS1senGds + flag); + gbs= *(here->MOS1senGbs + flag); + gbd= *(here->MOS1senGbd + flag); + gm= *(here->MOS1senGm + flag); + gmbs= *(here->MOS1senGmbs + flag); + if(flag == 5){ + gdpr = here->MOS1drainConductance * Apert/A0; + gspr = here->MOS1sourceConductance * Apert/A0; + } + else{ + gdpr = here->MOS1drainConductance; + gspr = here->MOS1sourceConductance; + } + + xcgs= *(here->MOS1senCgs + flag) * ckt->CKTomega; + xcgd= *(here->MOS1senCgd + flag) * ckt->CKTomega; + xcgb= *(here->MOS1senCgb + flag) * ckt->CKTomega; + xbd= *(here->MOS1senCbd + flag) * ckt->CKTomega; + xbs= *(here->MOS1senCbs + flag) * ckt->CKTomega; + +#ifdef SENSDEBUG + printf("flag = %d \n",flag); + printf("gspr = %.7e , gdpr = %.7e , gds = %.7e, gbs = %.7e\n", + gspr,gdpr,gds,gbs); + printf("gbd = %.7e , gm = %.7e , gmbs = %.7e\n",gbd,gm,gmbs); + printf("xcgs = %.7e , xcgd = %.7e , xcgb = %.7e,", xcgs,xcgd,xcgb); + printf("xbd = %.7e,xbs = %.7e\n",xbd,xbs); +#endif /* SENSDEBUG */ + cspr = gspr * vspr ; + icspr = gspr * ivspr ; + cdpr = gdpr * vdpr ; + icdpr = gdpr * ivdpr ; + cgs = ( - xcgs * ivgs ); + icgs = xcgs * vgs ; + cgd = ( - xcgd * ivgd ); + icgd = xcgd * vgd ; + cgb = ( - xcgb * ivgb ); + icgb = xcgb * vgb ; + cbs = ( gbs * vbs - xbs * ivbs ); + icbs = ( xbs * vbs + gbs * ivbs ); + cbd = ( gbd * vbd - xbd * ivbd ); + icbd = ( xbd * vbd + gbd * ivbd ); + cds = ( gds * vds + xnrm * (gm * vgs + gmbs * vbs) + - xrev * (gm * vgd + gmbs * vbd) ); + icds = ( gds * ivds + xnrm * (gm * ivgs + gmbs * ivbs) + - xrev * (gm * ivgd + gmbs * ivbd) ); + + cs = cspr; + ics = icspr; + csprm = ( -cspr - cgs - cbs - cds ) ; + icsprm = ( -icspr - icgs - icbs - icds ) ; + cd = cdpr; + icd = icdpr; + cdprm = ( -cdpr - cgd - cbd + cds ) ; + icdprm = ( -icdpr - icgd - icbd + icds ) ; + cg = cgs + cgd + cgb ; + icg = icgs + icgd + icgb ; + cb = cbs + cbd - cgb ; + icb = icbs + icbd - icgb ; + +#ifdef SENSDEBUG + printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); + printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); + printf("cbs = %.7e , cbd = %.7e , cgb = %.7e\n",cbs,cbd,cgb); + printf("cb = %.7e , cg = %.7e , cs = %.7e\n",cb,cg,cs); + printf("csprm = %.7e, cd = %.7e, cdprm = %.7e\n",csprm,cd,cdprm); + printf("icb = %.7e , icg = %.7e , ics = %.7e\n",icb,icg,ics); + printf("icsprm = %.7e, icd = %.7e, icdprm = %.7e\n", + icsprm,icd,icdprm); +#endif /* SENSDEBUG */ + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + if((flag == 4) && (iparmno != here->MOS1senParmNo)) continue; + if( (flag == 5) && (iparmno != (here->MOS1senParmNo + + here->MOS1sens_l))) continue; + + switch(flag){ + case 1: + DvDp = model->MOS1type * + (info->SEN_Sap[here->MOS1bNode][iparmno] + - info->SEN_Sap[here->MOS1sNodePrime][iparmno]); + break; + case 2: + DvDp = model->MOS1type * + ( info->SEN_Sap[here->MOS1bNode][iparmno] + - info->SEN_Sap[here->MOS1dNodePrime][iparmno]); + break; + case 3: + DvDp = model->MOS1type * + ( info->SEN_Sap[here->MOS1gNode][iparmno] + - info->SEN_Sap[here->MOS1bNode][iparmno]); + break; + case 4: + DvDp = 1; + break; + case 5: + DvDp = 1; + break; + } + *(info->SEN_RHS[here->MOS1bNode] + iparmno) -= + ( cb - cb0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS1bNode] + iparmno) -= + ( icb - icb0) * DELAinv * DvDp; + + *(info->SEN_RHS[here->MOS1gNode] + iparmno) -= + ( cg - cg0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS1gNode] + iparmno) -= + ( icg - icg0) * DELAinv * DvDp; + + if(here->MOS1sNode != here->MOS1sNodePrime){ + *(info->SEN_RHS[here->MOS1sNode] + iparmno) -= + ( cs - cs0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS1sNode] + iparmno) -= + ( ics - ics0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS1sNodePrime] + iparmno) -= + ( csprm - csprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS1sNodePrime] + iparmno) -= + ( icsprm - icsprm0) * DELAinv * DvDp; + + if(here->MOS1dNode != here->MOS1dNodePrime){ + *(info->SEN_RHS[here->MOS1dNode] + iparmno) -= + ( cd - cd0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS1dNode] + iparmno) -= + ( icd - icd0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS1dNodePrime] + iparmno) -= + ( cdprm - cdprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS1dNodePrime] + iparmno) -= + ( icdprm - icdprm0) * DELAinv * DvDp; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("DvDp = %.5e , DELAinv = %.5e ,flag = %d ,", + DvDp,DELAinv,flag); + printf("iparmno = %d,senparmno = %d\n", + iparmno,here->MOS1senParmNo); + printf("A0 = %.5e , Apert = %.5e ,CONSTvt = %.5e \n", + A0,Apert,here->MOS1tVto); + printf("senb = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS1bNode] + iparmno), + *(info->SEN_iRHS[here->MOS1bNode] + iparmno)); + printf("seng = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS1gNode] + iparmno), + *(info->SEN_iRHS[here->MOS1gNode] + iparmno)); + printf("sens = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS1sNode] + iparmno), + *(info->SEN_iRHS[here->MOS1sNode] + iparmno)); + printf("sensprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS1sNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS1sNodePrime] + iparmno)); + printf("send = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS1dNode] + iparmno), + *(info->SEN_iRHS[here->MOS1dNode] + iparmno)); + printf("sendprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS1dNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS1dNodePrime] + iparmno)); +#endif /* SENSDEBUG */ + + } + switch(flag){ + case 1: + goto pertvbd ; + case 2: + goto pertvgb ; + case 3: + goto pertl ; + case 4: + goto pertw ; + case 5: + break; + } +next: + ; + + /* put the unperturbed values back into the state vector */ + for(i=0; i <= 16; i++) + *(ckt->CKTstate0 + here->MOS1states + i) = *(SaveState + i); + + here->MOS1sourceConductance = *(SaveState + 17) ; + here->MOS1drainConductance = *(SaveState + 18) ; + here->MOS1cd = *(SaveState + 19) ; + here->MOS1cbs = *(SaveState + 20) ; + here->MOS1cbd = *(SaveState + 21) ; + here->MOS1gmbs = *(SaveState + 22) ; + here->MOS1gm = *(SaveState + 23) ; + here->MOS1gds = *(SaveState + 24) ; + here->MOS1gbd = *(SaveState + 25) ; + here->MOS1gbs = *(SaveState + 26) ; + here->MOS1capbd = *(SaveState + 27) ; + here->MOS1capbs = *(SaveState + 28) ; + here->MOS1Cbd = *(SaveState + 29) ; + here->MOS1Cbdsw = *(SaveState + 30) ; + here->MOS1Cbs = *(SaveState + 31) ; + here->MOS1Cbssw = *(SaveState + 32) ; + here->MOS1f2d = *(SaveState + 33) ; + here->MOS1f3d = *(SaveState + 34) ; + here->MOS1f4d = *(SaveState + 35) ; + here->MOS1f2s = *(SaveState + 36) ; + here->MOS1f3s = *(SaveState + 37) ; + here->MOS1f4s = *(SaveState + 38) ; + here->MOS1cgs = *(SaveState + 39) ; + here->MOS1cgd = *(SaveState + 40) ; + here->MOS1cgb = *(SaveState + 41) ; + here->MOS1vdsat = *(SaveState + 42) ; + here->MOS1von = *(SaveState + 43) ; + here->MOS1mode = save_mode ; + + here->MOS1senPertFlag = OFF; + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS1senacload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + + diff --git a/src/spicelib/devices/mos1/mos1set.c b/src/spicelib/devices/mos1/mos1set.c new file mode 100644 index 000000000..21067f6d8 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1set.c @@ -0,0 +1,221 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* load the MOS1 device structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1setup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; +{ + register MOS1model *model = (MOS1model *)inModel; + register MOS1instance *here; + int error; + CKTnode *tmp; + + /* loop through all the MOS1 device models */ + for( ; model != NULL; model = model->MOS1nextModel ) { + + if(!model->MOS1typeGiven) { + model->MOS1type = NMOS; + } + if(!model->MOS1latDiffGiven) { + model->MOS1latDiff = 0; + } + if(!model->MOS1jctSatCurDensityGiven) { + model->MOS1jctSatCurDensity = 0; + } + if(!model->MOS1jctSatCurGiven) { + model->MOS1jctSatCur = 1e-14; + } + if(!model->MOS1transconductanceGiven) { + model->MOS1transconductance = 2e-5; + } + if(!model->MOS1gateSourceOverlapCapFactorGiven) { + model->MOS1gateSourceOverlapCapFactor = 0; + } + if(!model->MOS1gateDrainOverlapCapFactorGiven) { + model->MOS1gateDrainOverlapCapFactor = 0; + } + if(!model->MOS1gateBulkOverlapCapFactorGiven) { + model->MOS1gateBulkOverlapCapFactor = 0; + } + if(!model->MOS1vt0Given) { + model->MOS1vt0 = 0; + } + if(!model->MOS1bulkCapFactorGiven) { + model->MOS1bulkCapFactor = 0; + } + if(!model->MOS1sideWallCapFactorGiven) { + model->MOS1sideWallCapFactor = 0; + } + if(!model->MOS1bulkJctPotentialGiven) { + model->MOS1bulkJctPotential = .8; + } + if(!model->MOS1bulkJctBotGradingCoeffGiven) { + model->MOS1bulkJctBotGradingCoeff = .5; + } + if(!model->MOS1bulkJctSideGradingCoeffGiven) { + model->MOS1bulkJctSideGradingCoeff = .5; + } + if(!model->MOS1fwdCapDepCoeffGiven) { + model->MOS1fwdCapDepCoeff = .5; + } + if(!model->MOS1phiGiven) { + model->MOS1phi = .6; + } + if(!model->MOS1lambdaGiven) { + model->MOS1lambda = 0; + } + if(!model->MOS1gammaGiven) { + model->MOS1gamma = 0; + } + if(!model->MOS1fNcoefGiven) { + model->MOS1fNcoef = 0; + } + if(!model->MOS1fNexpGiven) { + model->MOS1fNexp = 1; + } + + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + + if (here->MOS1owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->MOS1states = *states; + *states += MOS1numStates; + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ + *states += 10 * (ckt->CKTsenInfo->SENparms); + } + } + + if(!here->MOS1drainPerimiterGiven) { + here->MOS1drainPerimiter = 0; + } + if(!here->MOS1icVBSGiven) { + here->MOS1icVBS = 0; + } + if(!here->MOS1icVDSGiven) { + here->MOS1icVDS = 0; + } + if(!here->MOS1icVGSGiven) { + here->MOS1icVGS = 0; + } + if(!here->MOS1sourcePerimiterGiven) { + here->MOS1sourcePerimiter = 0; + } + if(!here->MOS1vdsatGiven) { + here->MOS1vdsat = 0; + } + if(!here->MOS1vonGiven) { + here->MOS1von = 0; + } + if(!here->MOS1drainSquaresGiven) { + here->MOS1drainSquares=1; + } + if(!here->MOS1sourceSquaresGiven) { + here->MOS1sourceSquares=1; + } + + if ((model->MOS1drainResistance != 0 + || (model->MOS1sheetResistance != 0 + && here->MOS1drainSquares != 0) ) + && here->MOS1dNodePrime == 0) { + error = CKTmkVolt(ckt,&tmp,here->MOS1name,"drain"); + if(error) return(error); + here->MOS1dNodePrime = tmp->number; + } else { + here->MOS1dNodePrime = here->MOS1dNode; + } + + if((model->MOS1sourceResistance != 0 || + (model->MOS1sheetResistance != 0 && + here->MOS1sourceSquares != 0) ) && + here->MOS1sNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS1name,"source"); + if(error) return(error); + here->MOS1sNodePrime = tmp->number; + } else { + here->MOS1sNodePrime = here->MOS1sNode; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + TSTALLOC(MOS1DdPtr,MOS1dNode,MOS1dNode) + TSTALLOC(MOS1GgPtr,MOS1gNode,MOS1gNode) + TSTALLOC(MOS1SsPtr,MOS1sNode,MOS1sNode) + TSTALLOC(MOS1BbPtr,MOS1bNode,MOS1bNode) + TSTALLOC(MOS1DPdpPtr,MOS1dNodePrime,MOS1dNodePrime) + TSTALLOC(MOS1SPspPtr,MOS1sNodePrime,MOS1sNodePrime) + TSTALLOC(MOS1DdpPtr,MOS1dNode,MOS1dNodePrime) + TSTALLOC(MOS1GbPtr,MOS1gNode,MOS1bNode) + TSTALLOC(MOS1GdpPtr,MOS1gNode,MOS1dNodePrime) + TSTALLOC(MOS1GspPtr,MOS1gNode,MOS1sNodePrime) + TSTALLOC(MOS1SspPtr,MOS1sNode,MOS1sNodePrime) + TSTALLOC(MOS1BdpPtr,MOS1bNode,MOS1dNodePrime) + TSTALLOC(MOS1BspPtr,MOS1bNode,MOS1sNodePrime) + TSTALLOC(MOS1DPspPtr,MOS1dNodePrime,MOS1sNodePrime) + TSTALLOC(MOS1DPdPtr,MOS1dNodePrime,MOS1dNode) + TSTALLOC(MOS1BgPtr,MOS1bNode,MOS1gNode) + TSTALLOC(MOS1DPgPtr,MOS1dNodePrime,MOS1gNode) + TSTALLOC(MOS1SPgPtr,MOS1sNodePrime,MOS1gNode) + TSTALLOC(MOS1SPsPtr,MOS1sNodePrime,MOS1sNode) + TSTALLOC(MOS1DPbPtr,MOS1dNodePrime,MOS1bNode) + TSTALLOC(MOS1SPbPtr,MOS1sNodePrime,MOS1bNode) + TSTALLOC(MOS1SPdpPtr,MOS1sNodePrime,MOS1dNodePrime) + + } + } + return(OK); +} + +int +MOS1unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + MOS1model *model; + MOS1instance *here; + + for (model = (MOS1model *)inModel; model != NULL; + model = model->MOS1nextModel) + { + for (here = model->MOS1instances; here != NULL; + here=here->MOS1nextInstance) + { + if (here->MOS1dNodePrime + && here->MOS1dNodePrime != here->MOS1dNode) + { + CKTdltNNum(ckt, here->MOS1dNodePrime); + here->MOS1dNodePrime= 0; + } + if (here->MOS1sNodePrime + && here->MOS1sNodePrime != here->MOS1sNode) + { + CKTdltNNum(ckt, here->MOS1sNodePrime); + here->MOS1sNodePrime= 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/mos1/mos1sld.c b/src/spicelib/devices/mos1/mos1sld.c new file mode 100644 index 000000000..2b1bef937 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1sld.c @@ -0,0 +1,625 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1sLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + register MOS1model *model = (MOS1model *)inModel; + register MOS1instance *here; + double SaveState[44]; + int save_mode; + int i; + int iparmno; + int error; + int flag; + double A0; + double DELA; + double Apert; + double DELAinv; + double gspr0; + double gspr; + double gdpr0; + double gdpr; + double cdpr0; + double cspr0; + double cd0; + double cbd0; + double cbs0; + double cd; + double cbd; + double cbs; + double DcdprDp; + double DcsprDp; + double DcbDp; + double DcdDp; + double DcbsDp; + double DcbdDp; + double DcdprmDp; + double DcsprmDp; + double qgs0; + double qgd0; + double qgb0; + double qbd0; + double qbd; + double qbs0; + double qbs; + double DqgsDp; + double DqgdDp; + double DqgbDp; + double DqbdDp; + double DqbsDp; + double Osxpgs; + double Osxpgd; + double Osxpgb; + double Osxpbd; + double Osxpbs; + double tag0; + double tag1; + double arg; + double sarg; + double sargsw; + int offset; + double EffectiveLength; + SENstruct *info; + +#ifdef SENSDEBUG + printf("MOS1senload \n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); + printf("CKTorder = %d\n",ckt->CKTorder); +#endif /* SENSDEBUG */ + + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + + tag0 = ckt->CKTag[0]; + tag1 = ckt->CKTag[1]; + if(ckt->CKTorder == 1){ + tag1 = 0; + } + + /* loop through all the models */ + for( ; model != NULL; model = model->MOS1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("senload instance name %s\n",here->MOS1name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS1gNode,here->MOS1dNode,here->MOS1dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS1sNode ,here->MOS1sNodePrime, + here->MOS1bNode,here->MOS1senParmNo); +#endif /* SENSDEBUG */ + + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++){ + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS1states + i); + } + + *(SaveState + 17) = here->MOS1sourceConductance; + *(SaveState + 18) = here->MOS1drainConductance; + *(SaveState + 19) = here->MOS1cd; + *(SaveState + 20) = here->MOS1cbs; + *(SaveState + 21) = here->MOS1cbd; + *(SaveState + 22) = here->MOS1gmbs; + *(SaveState + 23) = here->MOS1gm; + *(SaveState + 24) = here->MOS1gds; + *(SaveState + 25) = here->MOS1gbd; + *(SaveState + 26) = here->MOS1gbs; + *(SaveState + 27) = here->MOS1capbd; + *(SaveState + 28) = here->MOS1capbs; + *(SaveState + 29) = here->MOS1Cbd; + *(SaveState + 30) = here->MOS1Cbdsw; + *(SaveState + 31) = here->MOS1Cbs; + *(SaveState + 32) = here->MOS1Cbssw; + *(SaveState + 33) = here->MOS1f2d; + *(SaveState + 34) = here->MOS1f3d; + *(SaveState + 35) = here->MOS1f4d; + *(SaveState + 36) = here->MOS1f2s; + *(SaveState + 37) = here->MOS1f3s; + *(SaveState + 38) = here->MOS1f4s; + *(SaveState + 39) = here->MOS1cgs; + *(SaveState + 40) = here->MOS1cgd; + *(SaveState + 41) = here->MOS1cgb; + *(SaveState + 42) = here->MOS1vdsat; + *(SaveState + 43) = here->MOS1von; + save_mode = here->MOS1mode; + + + if(here->MOS1senParmNo == 0) goto next1; + +#ifdef SENSDEBUG + printf("without perturbation \n"); + printf("gbd =%.5e\n",here->MOS1gbd); + printf("satCur =%.5e\n",here->MOS1tSatCur); + printf("satCurDens =%.5e\n",here->MOS1tSatCurDens); + printf("vbd =%.5e\n",*(ckt->CKTstate0 + here->MOS1vbd)); +#endif /* SENSDEBUG */ + + cdpr0= here->MOS1cd; + cspr0= -(here->MOS1cd + here->MOS1cbd + here->MOS1cbs); + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)){ + qgs0 = *(ckt->CKTstate1 + here->MOS1qgs); + qgd0 = *(ckt->CKTstate1 + here->MOS1qgd); + qgb0 = *(ckt->CKTstate1 + here->MOS1qgb); + } + else{ + qgs0 = *(ckt->CKTstate0 + here->MOS1qgs); + qgd0 = *(ckt->CKTstate0 + here->MOS1qgd); + qgb0 = *(ckt->CKTstate0 + here->MOS1qgb); + } + + here->MOS1senPertFlag = ON; + error = MOS1load((GENmodel*)model,ckt); + if(error) return(error); + + cd0 = here->MOS1cd ; + cbd0 = here->MOS1cbd ; + cbs0 = here->MOS1cbs ; + gspr0= here->MOS1sourceConductance ; + gdpr0= here->MOS1drainConductance ; + + qbs0 = *(ckt->CKTstate0 + here->MOS1qbs); + qbd0 = *(ckt->CKTstate0 + here->MOS1qbd); + + for( flag = 0 ; flag <= 1 ; flag++){ + if(here->MOS1sens_l == 0) + if(flag == 0) goto next2; + if(here->MOS1sens_w == 0) + if(flag == 1) goto next2; + if(flag == 0){ + A0 = here->MOS1l; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS1l = Apert; + } + else{ + A0 = here->MOS1w; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS1w = Apert; + here->MOS1drainArea *= (1 + info->SENpertfac); + here->MOS1sourceArea *= (1 + info->SENpertfac); + here->MOS1Cbd *= (1 + info->SENpertfac); + here->MOS1Cbs *= (1 + info->SENpertfac); + if(here->MOS1drainPerimiter){ + here->MOS1Cbdsw += here->MOS1Cbdsw * + DELA/here->MOS1drainPerimiter; + } + if(here->MOS1sourcePerimiter){ + here->MOS1Cbssw += here->MOS1Cbssw * + DELA/here->MOS1sourcePerimiter; + } + if(*(ckt->CKTstate0 + here->MOS1vbd) >= + here->MOS1tDepCap){ + arg = 1-model->MOS1fwdCapDepCoeff; + sarg = exp( (-model->MOS1bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS1bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS1f2d = here->MOS1Cbd* + (1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctBotGradingCoeff))* sarg/arg + + here->MOS1Cbdsw*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS1f3d = here->MOS1Cbd * + model->MOS1bulkJctBotGradingCoeff * sarg/arg/ + here->MOS1tBulkPot + + here->MOS1Cbdsw * + model->MOS1bulkJctSideGradingCoeff * sargsw/arg/ + here->MOS1tBulkPot; + here->MOS1f4d = here->MOS1Cbd* + here->MOS1tBulkPot*(1-arg*sarg)/ + (1-model->MOS1bulkJctBotGradingCoeff) + + here->MOS1Cbdsw*here->MOS1tBulkPot* + (1-arg*sargsw)/ + (1-model->MOS1bulkJctSideGradingCoeff) + -here->MOS1f3d/2* + (here->MOS1tDepCap*here->MOS1tDepCap) + -here->MOS1tDepCap * here->MOS1f2d; + } + if(*(ckt->CKTstate0 + here->MOS1vbs) >= + here->MOS1tDepCap){ + arg = 1-model->MOS1fwdCapDepCoeff; + sarg = exp( (-model->MOS1bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS1bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS1f2s = here->MOS1Cbs* + (1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctBotGradingCoeff))* sarg/arg + + here->MOS1Cbssw*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS1f3s = here->MOS1Cbs * + model->MOS1bulkJctBotGradingCoeff * sarg/arg/ + here->MOS1tBulkPot + + here->MOS1Cbssw * + model->MOS1bulkJctSideGradingCoeff * sargsw/arg/ + here->MOS1tBulkPot; + here->MOS1f4s = here->MOS1Cbs* + here->MOS1tBulkPot*(1-arg*sarg)/ + (1-model->MOS1bulkJctBotGradingCoeff) + + here->MOS1Cbssw*here->MOS1tBulkPot* + (1-arg*sargsw)/ + (1-model->MOS1bulkJctSideGradingCoeff) + -here->MOS1f3s/2* + (here->MOS1tDepCap*here->MOS1tDepCap) + -here->MOS1tDepCap * here->MOS1f2s; + } + here->MOS1drainConductance *= Apert/A0; + here->MOS1sourceConductance *= Apert/A0; + } + + +#ifdef SENSDEBUG + if(flag == 0) + printf("perturbation of l\n"); + if(flag == 1) + printf("perturbation of w\n"); +#endif /* SENSDEBUG */ + + error = MOS1load((GENmodel*)model,ckt); + if(error) return(error); + + if(flag == 0){ + here->MOS1l = A0; + } + else{ + here->MOS1w = A0; + here->MOS1drainArea /= (1 + info->SENpertfac); + here->MOS1sourceArea /= (1 + info->SENpertfac); + here->MOS1drainConductance *= A0/Apert; + here->MOS1sourceConductance *= A0/Apert; + } + cd = here->MOS1cd ; + cbd = here->MOS1cbd ; + cbs = here->MOS1cbs ; + + gspr= here->MOS1sourceConductance ; + gdpr= here->MOS1drainConductance ; + + DcdDp = (cd - cd0) * DELAinv; + DcbsDp = (cbs - cbs0) * DELAinv; + DcbdDp = (cbd - cbd0) * DELAinv; + DcbDp = ( DcbsDp + DcbdDp ); + + DcdprDp = 0; + DcsprDp = 0; + if(here->MOS1dNode != here->MOS1dNodePrime) + if(gdpr0) DcdprDp = cdpr0 * (gdpr - gdpr0)/gdpr0 * DELAinv; + if(here->MOS1sNode != here->MOS1sNodePrime) + if(gspr0) DcsprDp = cspr0 * (gspr - gspr0)/gspr0 * DELAinv; + + DcdprmDp = ( - DcdprDp + DcdDp); + DcsprmDp = ( - DcbsDp - DcdDp - DcbdDp - DcsprDp); + + if(flag == 0){ + EffectiveLength = here->MOS1l + - 2*model->MOS1latDiff; + if(EffectiveLength == 0){ + DqgsDp = 0; + DqgdDp = 0; + DqgbDp = 0; + } + else{ + DqgsDp = model->MOS1type * qgs0 / EffectiveLength; + DqgdDp = model->MOS1type * qgd0 / EffectiveLength; + DqgbDp = model->MOS1type * qgb0 / EffectiveLength; + } + } + else{ + DqgsDp = model->MOS1type * qgs0 / here->MOS1w; + DqgdDp = model->MOS1type * qgd0 / here->MOS1w; + DqgbDp = model->MOS1type * qgb0 / here->MOS1w; + } + + + qbd = *(ckt->CKTstate0 + here->MOS1qbd); + qbs = *(ckt->CKTstate0 + here->MOS1qbs); + + DqbsDp = model->MOS1type * (qbs - qbs0)*DELAinv; + DqbdDp = model->MOS1type * (qbd - qbd0)*DELAinv; + + if(flag == 0){ + *(here->MOS1dphigs_dl) = DqgsDp; + *(here->MOS1dphigd_dl) = DqgdDp; + *(here->MOS1dphibs_dl) = DqbsDp; + *(here->MOS1dphibd_dl) = DqbdDp; + *(here->MOS1dphigb_dl) = DqgbDp; + } + else{ + *(here->MOS1dphigs_dw) = DqgsDp; + *(here->MOS1dphigd_dw) = DqgdDp; + *(here->MOS1dphibs_dw) = DqbsDp; + *(here->MOS1dphibd_dw) = DqbdDp; + *(here->MOS1dphigb_dw) = DqgbDp; + } + + +#ifdef SENSDEBUG + printf("CKTag[0]=%.7e,CKTag[1]=%.7e,flag= %d\n", + ckt->CKTag[0],ckt->CKTag[1],flag); + printf("cd0 = %.7e ,cd = %.7e,\n",cd0,cd); + printf("cbs0 = %.7e ,cbs = %.7e,\n",cbs0,cbs); + printf("cbd0 = %.7e ,cbd = %.7e,\n",cbd0,cbd); + printf("DcdprmDp = %.7e,\n",DcdprmDp); + printf("DcsprmDp = %.7e,\n",DcsprmDp); + printf("DcdprDp = %.7e,\n",DcdprDp); + printf("DcsprDp = %.7e,\n",DcsprDp); + printf("qgs0 = %.7e \n",qgs0); + printf("qgd0 = %.7e \n",qgd0); + printf("qgb0 = %.7e \n",qgb0); + printf("qbs0 = %.7e ,qbs = %.7e,\n",qbs0,qbs); + printf("qbd0 = %.7e ,qbd = %.7e,\n",qbd0,qbd); + printf("DqgsDp = %.7e \n",DqgsDp); + printf("DqgdDp = %.7e \n",DqgdDp); + printf("DqgbDp = %.7e \n",DqgbDp); + printf("DqbsDp = %.7e \n",DqbsDp); + printf("DqbdDp = %.7e \n",DqbdDp); + printf("EffectiveLength = %.7e \n",EffectiveLength); + printf("tdepCap = %.7e \n",here->MOS1tDepCap); + printf("\n"); +#endif /* SENSDEBUG*/ + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) + goto next2; + + /* + * load RHS matrix + */ + + if(flag == 0){ + *(info->SEN_RHS[here->MOS1bNode] + here->MOS1senParmNo) -= + model->MOS1type * DcbDp; + *(info->SEN_RHS[here->MOS1dNode] + here->MOS1senParmNo) -= + model->MOS1type * DcdprDp; + *(info->SEN_RHS[here->MOS1dNodePrime] + + here->MOS1senParmNo) -= model->MOS1type * DcdprmDp; + *(info->SEN_RHS[here->MOS1sNode] + here->MOS1senParmNo) -= + model->MOS1type * DcsprDp; + *(info->SEN_RHS[here->MOS1sNodePrime] + + here->MOS1senParmNo) -= model->MOS1type * DcsprmDp; + } + else{ + offset = here->MOS1sens_l; + + *(info->SEN_RHS[here->MOS1bNode] + here->MOS1senParmNo + + offset) -= model->MOS1type * DcbDp; + *(info->SEN_RHS[here->MOS1dNode] + here->MOS1senParmNo + + offset) -= model->MOS1type * DcdprDp; + *(info->SEN_RHS[here->MOS1dNodePrime] + here->MOS1senParmNo + + offset) -= model->MOS1type * DcdprmDp; + *(info->SEN_RHS[here->MOS1sNode] + here->MOS1senParmNo + + offset) -= model->MOS1type * DcsprDp; + *(info->SEN_RHS[here->MOS1sNodePrime] + here->MOS1senParmNo + + offset) -= model->MOS1type * DcsprmDp; + } +#ifdef SENSDEBUG + printf("after loading\n"); + if(flag == 0){ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS1bNode] + + here->MOS1senParmNo)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNode] + + here->MOS1senParmNo)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNode] + + here->MOS1senParmNo)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNodePrime] + + here->MOS1senParmNo)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNodePrime] + + here->MOS1senParmNo)); + printf("\n"); + } + else{ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS1bNode] + + here->MOS1senParmNo + here->MOS1sens_l)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNode] + + here->MOS1senParmNo + here->MOS1sens_l)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNode] + + here->MOS1senParmNo + here->MOS1sens_l)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNodePrime] + + here->MOS1senParmNo + here->MOS1sens_l)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNodePrime] + + here->MOS1senParmNo + here->MOS1sens_l)); + } +#endif /* SENSDEBUG*/ +next2: + ; + } +next1: + if((info->SENmode == DCSEN) || + (ckt->CKTmode&MODETRANOP) ) goto restore; + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) goto restore; + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ +#ifdef SENSDEBUG + printf("after conductive currents\n"); + printf("iparmno = %d\n",iparmno); + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS1bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNodePrime] + iparmno)); + printf("\n"); +#endif /* SENSDEBUG */ + Osxpgs = tag0 * *(ckt->CKTstate1 + here->MOS1sensxpgs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS1sensxpgs + + 10*(iparmno - 1) + 1); + + Osxpgd = tag0 * *(ckt->CKTstate1 + here->MOS1sensxpgd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS1sensxpgd + + 10*(iparmno - 1) + 1); + + Osxpbs = tag0 * *(ckt->CKTstate1 + here->MOS1sensxpbs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS1sensxpbs + + 10*(iparmno - 1) + 1); + + Osxpbd =tag0 * *(ckt->CKTstate1 + here->MOS1sensxpbd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS1sensxpbd + + 10*(iparmno - 1) + 1); + Osxpgb = tag0 * *(ckt->CKTstate1 + here->MOS1sensxpgb + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS1sensxpgb + + 10*(iparmno - 1) + 1); + +#ifdef SENSDEBUG + printf("iparmno=%d\n",iparmno); + printf("sxpgs=%.7e,sdgs=%.7e\n", + *(ckt->CKTstate1 + here->MOS1sensxpgs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS1sensxpgs + 10*(iparmno - 1) + 1)); + printf("sxpgd=%.7e,sdgd=%.7e\n", + *(ckt->CKTstate1 + here->MOS1sensxpgd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS1sensxpgd + 10*(iparmno - 1) + 1)); + printf("sxpbs=%.7e,sdbs=%.7e\n", + *(ckt->CKTstate1 + here->MOS1sensxpbs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS1sensxpbs + 10*(iparmno - 1) + 1)); + printf("sxpbd=%.7e,sdbd=%.7e\n", + *(ckt->CKTstate1 + here->MOS1sensxpbd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS1sensxpbd + 10*(iparmno - 1) + 1)); + printf("sxpgb=%.7e,sdgb=%.7e\n", + *(ckt->CKTstate1 + here->MOS1sensxpgb + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS1sensxpgb + 10*(iparmno - 1) + 1)); + printf("before loading DqDp\n"); + printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); + printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", + Osxpbs,Osxpbd,Osxpgb); + printf("\n"); +#endif /* SENSDEBUG */ + if(here->MOS1sens_l && (iparmno == here->MOS1senParmNo)){ + Osxpgs -= tag0 * *(here->MOS1dphigs_dl); + Osxpgd -= tag0 * *(here->MOS1dphigd_dl); + Osxpbs -= tag0 * *(here->MOS1dphibs_dl); + Osxpbd -= tag0 * *(here->MOS1dphibd_dl); + Osxpgb -= tag0 * *(here->MOS1dphigb_dl); + } + if(here->MOS1sens_w && + (iparmno == (here->MOS1senParmNo + here->MOS1sens_l))){ + Osxpgs -= tag0 * *(here->MOS1dphigs_dw); + Osxpgd -= tag0 * *(here->MOS1dphigd_dw); + Osxpbs -= tag0 * *(here->MOS1dphibs_dw); + Osxpbd -= tag0 * *(here->MOS1dphibd_dw); + Osxpgb -= tag0 * *(here->MOS1dphigb_dw); + } +#ifdef SENSDEBUG + printf("after loading DqDp\n"); + printf("DqgsDp=%.7e",DqgsDp); + printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); + printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", + Osxpbs,Osxpbd,Osxpgb); +#endif /* SENSDEBUG */ + + *(info->SEN_RHS[here->MOS1bNode] + iparmno) += + Osxpbs + Osxpbd -Osxpgb; + *(info->SEN_RHS[here->MOS1gNode] + iparmno) += + Osxpgs + Osxpgd + Osxpgb; + + *(info->SEN_RHS[here->MOS1dNodePrime] + iparmno) -= + Osxpgd + Osxpbd ; + *(info->SEN_RHS[here->MOS1sNodePrime] + iparmno) -= + Osxpgs + Osxpbs; +#ifdef SENSDEBUG + printf("after capacitive currents\n"); + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS1bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS1sNodePrime] + iparmno)); +#endif /* SENSDEBUG */ + + } +restore: /* put the unperturbed values back into the state vector */ + for(i=0; i <= 16; i++) + *(ckt->CKTstate0 + here->MOS1states + i) = *(SaveState + i); + here->MOS1sourceConductance = *(SaveState + 17) ; + here->MOS1drainConductance = *(SaveState + 18) ; + here->MOS1cd = *(SaveState + 19) ; + here->MOS1cbs = *(SaveState + 20) ; + here->MOS1cbd = *(SaveState + 21) ; + here->MOS1gmbs = *(SaveState + 22) ; + here->MOS1gm = *(SaveState + 23) ; + here->MOS1gds = *(SaveState + 24) ; + here->MOS1gbd = *(SaveState + 25) ; + here->MOS1gbs = *(SaveState + 26) ; + here->MOS1capbd = *(SaveState + 27) ; + here->MOS1capbs = *(SaveState + 28) ; + here->MOS1Cbd = *(SaveState + 29) ; + here->MOS1Cbdsw = *(SaveState + 30) ; + here->MOS1Cbs = *(SaveState + 31) ; + here->MOS1Cbssw = *(SaveState + 32) ; + here->MOS1f2d = *(SaveState + 33) ; + here->MOS1f3d = *(SaveState + 34) ; + here->MOS1f4d = *(SaveState + 35) ; + here->MOS1f2s = *(SaveState + 36) ; + here->MOS1f3s = *(SaveState + 37) ; + here->MOS1f4s = *(SaveState + 38) ; + here->MOS1cgs = *(SaveState + 39) ; + here->MOS1cgd = *(SaveState + 40) ; + here->MOS1cgb = *(SaveState + 41) ; + here->MOS1vdsat = *(SaveState + 42) ; + here->MOS1von = *(SaveState + 43) ; + here->MOS1mode = save_mode ; + + here->MOS1senPertFlag = OFF; + + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS1senload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + diff --git a/src/spicelib/devices/mos1/mos1sprt.c b/src/spicelib/devices/mos1/mos1sprt.c new file mode 100644 index 000000000..0775d8e16 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1sprt.c @@ -0,0 +1,66 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* Pretty print the sensitivity info for all + * the MOS1 devices in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +void +MOS1sPrint(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +/* Pretty print the sensitivity info for all the MOS1 + * devices in the circuit. + */ +{ + register MOS1model *model = (MOS1model *)inModel; + register MOS1instance *here; + + printf("LEVEL 1 MOSFETS-----------------\n"); + /* loop through all the MOS1 models */ + for( ; model != NULL; model = model->MOS1nextModel ) { + + printf("Model name:%s\n",model->MOS1modName); + + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + printf(" Instance name:%s\n",here->MOS1name); + printf(" Drain, Gate , Source nodes: %s, %s ,%s\n", + CKTnodName(ckt,here->MOS1dNode),CKTnodName(ckt,here->MOS1gNode), + CKTnodName(ckt,here->MOS1sNode)); + + printf(" Length: %g ",here->MOS1l); + printf(here->MOS1lGiven ? "(specified)\n" : "(default)\n"); + printf(" Width: %g ",here->MOS1w); + printf(here->MOS1wGiven ? "(specified)\n" : "(default)\n"); + if(here->MOS1sens_l == 1){ + printf(" MOS1senParmNo:l = %d ",here->MOS1senParmNo); + } + else{ + printf(" MOS1senParmNo:l = 0 "); + } + if(here->MOS1sens_w == 1){ + printf(" w = %d \n",here->MOS1senParmNo + here->MOS1sens_l); + } + else{ + printf(" w = 0 \n"); + } + + + } + } +} + diff --git a/src/spicelib/devices/mos1/mos1sset.c b/src/spicelib/devices/mos1/mos1sset.c new file mode 100644 index 000000000..59ca505cd --- /dev/null +++ b/src/spicelib/devices/mos1/mos1sset.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1sSetup(info,inModel) +register SENstruct *info; +GENmodel *inModel; +/* loop through all the devices and + * allocate parameter #s to design parameters + */ +{ + register MOS1model *model = (MOS1model *)inModel; + register MOS1instance *here; + + /* loop through all the models */ + for( ; model != NULL; model = model->MOS1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + + if(here->MOS1senParmNo){ + if((here->MOS1sens_l)&&(here->MOS1sens_w)){ + here->MOS1senParmNo = ++(info->SENparms); + ++(info->SENparms);/* MOS has two design parameters */ + } + else{ + here->MOS1senParmNo = ++(info->SENparms); + } + } + if((here->MOS1sens = (double *)MALLOC(70*sizeof(double))) == NULL) { + return(E_NOMEM); + } + here->MOS1senPertFlag = OFF; + + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/mos1/mos1supd.c b/src/spicelib/devices/mos1/mos1supd.c new file mode 100644 index 000000000..37fefe911 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1supd.c @@ -0,0 +1,185 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + +/* update the charge sensitivities and their derivatives */ + +int +MOS1sUpdate(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS1model *model = (MOS1model *)inModel; + register MOS1instance *here; + int iparmno; + double sb; + double sg; + double sdprm; + double ssprm; + double sxpgs; + double sxpgd; + double sxpbs; + double sxpbd; + double sxpgb; + double dummy1; + double dummy2; + SENstruct *info; + + + if(ckt->CKTtime == 0) return(OK); + info = ckt->CKTsenInfo; + +#ifdef SENSDEBUG + printf("MOS1senupdate\n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); +#endif /* SENSDEBUG */ + + sxpgs = 0; + sxpgd = 0; + sxpbs = 0; + sxpbd = 0; + sxpgb = 0; + dummy1 = 0; + dummy2 = 0; + + /* loop through all the MOS1 models */ + for( ; model != NULL; model = model->MOS1nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS1instances; here != NULL ; + here=here->MOS1nextInstance) { + if (here->MOS1owner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("senupdate instance name %s\n",here->MOS1name); + printf("before loading\n"); + printf("CKTag[0] = %.2e,CKTag[1] = %.2e\n", + ckt->CKTag[0],ckt->CKTag[1]); + printf("capgs = %.7e\n",here->MOS1cgs); + printf("capgd = %.7e\n",here->MOS1cgd); + printf("capgb = %.7e\n",here->MOS1cgb); + printf("capbs = %.7e\n",here->MOS1capbs); + printf("capbd = %.7e\n",here->MOS1capbd); +#endif /* SENSDEBUG */ + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + + sb = *(info->SEN_Sap[here->MOS1bNode] + iparmno); + sg = *(info->SEN_Sap[here->MOS1gNode] + iparmno); + ssprm = *(info->SEN_Sap[here->MOS1sNodePrime] + iparmno); + sdprm = *(info->SEN_Sap[here->MOS1dNodePrime] + iparmno); +#ifdef SENSDEBUG + printf("iparmno = %d\n",iparmno); + printf("sb = %.7e,sg = %.7e\n",sb,sg); + printf("ssprm = %.7e,sdprm = %.7e\n",ssprm,sdprm); +#endif /* SENSDEBUG */ + + sxpgs = (sg - ssprm) * here->MOS1cgs ; + sxpgd = (sg - sdprm) * here->MOS1cgd ; + sxpgb = (sg - sb) * here->MOS1cgb ; + sxpbs = (sb - ssprm) * here->MOS1capbs ; + sxpbd = (sb - sdprm) * here->MOS1capbd ; + + if(here->MOS1sens_l && (iparmno == here->MOS1senParmNo)){ + sxpgs += *(here->MOS1dphigs_dl); + sxpgd += *(here->MOS1dphigd_dl); + sxpbs += *(here->MOS1dphibs_dl); + sxpbd += *(here->MOS1dphibd_dl); + sxpgb += *(here->MOS1dphigb_dl); + } + if(here->MOS1sens_w && + (iparmno == (here->MOS1senParmNo+here->MOS1sens_l))){ + sxpgs += *(here->MOS1dphigs_dw); + sxpgd += *(here->MOS1dphigd_dw); + sxpbs += *(here->MOS1dphibs_dw); + sxpbd += *(here->MOS1dphibd_dw); + sxpgb += *(here->MOS1dphigb_dw); + } + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->MOS1sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate1 + here->MOS1sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate1 + here->MOS1sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate1 + here->MOS1sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate1 + here->MOS1sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + *(ckt->CKTstate1 + here->MOS1sensxpgs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS1sensxpgd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS1sensxpbs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS1sensxpbd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS1sensxpgb + + 10 * (iparmno - 1) + 1) = 0; + goto next; + } + + *(ckt->CKTstate0 + here->MOS1sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate0 + here->MOS1sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate0 + here->MOS1sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate0 + here->MOS1sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate0 + here->MOS1sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS1cgs, + here->MOS1sensxpgs + 10*(iparmno -1)); + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS1cgd, + here->MOS1sensxpgd + 10*(iparmno -1)); + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS1cgb, + here->MOS1sensxpgb + 10*(iparmno -1)); + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS1capbs, + here->MOS1sensxpbs + 10*(iparmno -1)); + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS1capbd, + here->MOS1sensxpbd + 10*(iparmno -1)); +next: + ; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("sxpgs = %.7e,sdotxpgs = %.7e\n", + sxpgs,*(ckt->CKTstate0 + here->MOS1sensxpgs + + 10 * (iparmno - 1) + 1)); + printf("sxpgd = %.7e,sdotxpgd = %.7e\n", + sxpgd,*(ckt->CKTstate0 + here->MOS1sensxpgd + + 10 * (iparmno - 1) + 1)); + printf("sxpgb = %.7e,sdotxpgb = %.7e\n", + sxpgb,*(ckt->CKTstate0 + here->MOS1sensxpgb + + 10 * (iparmno - 1) + 1)); + printf("sxpbs = %.7e,sdotxpbs = %.7e\n", + sxpbs,*(ckt->CKTstate0 + here->MOS1sensxpbs + + 10 * (iparmno - 1) + 1)); + printf("sxpbd = %.7e,sdotxpbd = %.7e\n", + sxpbd,*(ckt->CKTstate0 + here->MOS1sensxpbd + + 10 * (iparmno - 1) + 1)); +#endif /* SENSDEBUG */ + } + } + } +#ifdef SENSDEBUG + printf("MOS1senupdate end\n"); +#endif /* SENSDEBUG */ + return(OK); + +} + diff --git a/src/spicelib/devices/mos1/mos1temp.c b/src/spicelib/devices/mos1/mos1temp.c new file mode 100644 index 000000000..ea93c84f5 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1temp.c @@ -0,0 +1,313 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos1defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS1temp(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS1model *model = (MOS1model *)inModel; + register MOS1instance *here; + + double egfet,egfet1; + double fact1,fact2; + double kt,kt1; + double arg1; + double ratio,ratio4; + double phio; + double pbo; + double gmanew,gmaold; + double capfact; + double pbfact1,pbfact; + double vt,vtnom; + double wkfngs; + double wkfng; + double fermig; + double fermis; + double vfb; + /* loop through all the resistor models */ + for( ; model != NULL; model = model->MOS1nextModel) { + + + /* perform model defaulting */ + if(!model->MOS1tnomGiven) { + model->MOS1tnom = ckt->CKTnomTemp; + } + + fact1 = model->MOS1tnom/REFTEMP; + vtnom = model->MOS1tnom*CONSTKoverQ; + kt1 = CONSTboltz * model->MOS1tnom; + egfet1 = 1.16-(7.02e-4*model->MOS1tnom*model->MOS1tnom)/ + (model->MOS1tnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1); + + /* now model parameter preprocessing */ + + if(!model->MOS1oxideThicknessGiven || model->MOS1oxideThickness == 0) { + model->MOS1oxideCapFactor = 0; + } else { + model->MOS1oxideCapFactor = 3.9 * 8.854214871e-12/ + model->MOS1oxideThickness; + if(!model->MOS1transconductanceGiven) { + if(!model->MOS1surfaceMobilityGiven) { + model->MOS1surfaceMobility=600; + } + model->MOS1transconductance = model->MOS1surfaceMobility * + model->MOS1oxideCapFactor * 1e-4 /*(m**2/cm**2)*/; + } + if(model->MOS1substrateDopingGiven) { + if(model->MOS1substrateDoping*1e6 /*(cm**3/m**3)*/ >1.45e16) { + if(!model->MOS1phiGiven) { + model->MOS1phi = 2*vtnom* + log(model->MOS1substrateDoping* + 1e6/*(cm**3/m**3)*//1.45e16); + model->MOS1phi = MAX(.1,model->MOS1phi); + } + fermis = model->MOS1type * .5 * model->MOS1phi; + wkfng = 3.2; + if(!model->MOS1gateTypeGiven) model->MOS1gateType=1; + if(model->MOS1gateType != 0) { + fermig = model->MOS1type *model->MOS1gateType*.5*egfet1; + wkfng = 3.25 + .5 * egfet1 - fermig; + } + wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis); + if(!model->MOS1gammaGiven) { + model->MOS1gamma = sqrt(2 * 11.70 * 8.854214871e-12 * + CHARGE * model->MOS1substrateDoping* + 1e6/*(cm**3/m**3)*/)/ + model->MOS1oxideCapFactor; + } + if(!model->MOS1vt0Given) { + if(!model->MOS1surfaceStateDensityGiven) + model->MOS1surfaceStateDensity=0; + vfb = wkfngs - + model->MOS1surfaceStateDensity * + 1e4 /*(cm**2/m**2)*/ * + CHARGE/model->MOS1oxideCapFactor; + model->MOS1vt0 = vfb + model->MOS1type * + (model->MOS1gamma * sqrt(model->MOS1phi)+ + model->MOS1phi); + } + } else { + model->MOS1substrateDoping = 0; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: Nsub < Ni",&model->MOS1modName); + return(E_BADPARM); + } + } + } + + + /* loop through all instances of the model */ + for(here = model->MOS1instances; here!= NULL; + here = here->MOS1nextInstance) { + double czbd; /* zero voltage bulk-drain capacitance */ + double czbdsw; /* zero voltage bulk-drain sidewall capacitance */ + double czbs; /* zero voltage bulk-source capacitance */ + double czbssw; /* zero voltage bulk-source sidewall capacitance */ + double arg; /* 1 - fc */ + double sarg; /* (1-fc) ^^ (-mj) */ + double sargsw; /* (1-fc) ^^ (-mjsw) */ + if (here->MOS1owner != ARCHme) continue; + + /* perform the parameter defaulting */ + if(!here->MOS1tempGiven) { + here->MOS1temp = ckt->CKTtemp; + } + vt = here->MOS1temp * CONSTKoverQ; + ratio = here->MOS1temp/model->MOS1tnom; + fact2 = here->MOS1temp/REFTEMP; + kt = here->MOS1temp * CONSTboltz; + egfet = 1.16-(7.02e-4*here->MOS1temp*here->MOS1temp)/ + (here->MOS1temp+1108); + arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); + + if(!here->MOS1drainAreaGiven) { + here->MOS1drainArea = ckt->CKTdefaultMosAD; + } + if(!here->MOS1lGiven) { + here->MOS1l = ckt->CKTdefaultMosL; + } + if(!here->MOS1sourceAreaGiven) { + here->MOS1sourceArea = ckt->CKTdefaultMosAS; + } + if(!here->MOS1wGiven) { + here->MOS1w = ckt->CKTdefaultMosW; + } + + if(here->MOS1l - 2 * model->MOS1latDiff <=0) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: effective channel length less than zero", + &(model->MOS1modName)); + } + ratio4 = ratio * sqrt(ratio); + here->MOS1tTransconductance = model->MOS1transconductance / ratio4; + here->MOS1tSurfMob = model->MOS1surfaceMobility/ratio4; + phio= (model->MOS1phi-pbfact1)/fact1; + here->MOS1tPhi = fact2 * phio + pbfact; + here->MOS1tVbi = + model->MOS1vt0 - model->MOS1type * + (model->MOS1gamma* sqrt(model->MOS1phi)) + +.5*(egfet1-egfet) + + model->MOS1type*.5* (here->MOS1tPhi-model->MOS1phi); + here->MOS1tVto = here->MOS1tVbi + model->MOS1type * + model->MOS1gamma * sqrt(here->MOS1tPhi); + here->MOS1tSatCur = model->MOS1jctSatCur* + exp(-egfet/vt+egfet1/vtnom); + here->MOS1tSatCurDens = model->MOS1jctSatCurDensity * + exp(-egfet/vt+egfet1/vtnom); + pbo = (model->MOS1bulkJctPotential - pbfact1)/fact1; + gmaold = (model->MOS1bulkJctPotential-pbo)/pbo; + capfact = 1/(1+model->MOS1bulkJctBotGradingCoeff* + (4e-4*(model->MOS1tnom-REFTEMP)-gmaold)); + here->MOS1tCbd = model->MOS1capBD * capfact; + here->MOS1tCbs = model->MOS1capBS * capfact; + here->MOS1tCj = model->MOS1bulkCapFactor * capfact; + capfact = 1/(1+model->MOS1bulkJctSideGradingCoeff* + (4e-4*(model->MOS1tnom-REFTEMP)-gmaold)); + here->MOS1tCjsw = model->MOS1sideWallCapFactor * capfact; + here->MOS1tBulkPot = fact2 * pbo+pbfact; + gmanew = (here->MOS1tBulkPot-pbo)/pbo; + capfact = (1+model->MOS1bulkJctBotGradingCoeff* + (4e-4*(here->MOS1temp-REFTEMP)-gmanew)); + here->MOS1tCbd *= capfact; + here->MOS1tCbs *= capfact; + here->MOS1tCj *= capfact; + capfact = (1+model->MOS1bulkJctSideGradingCoeff* + (4e-4*(here->MOS1temp-REFTEMP)-gmanew)); + here->MOS1tCjsw *= capfact; + here->MOS1tDepCap = model->MOS1fwdCapDepCoeff * here->MOS1tBulkPot; + if( (here->MOS1tSatCurDens == 0) || + (here->MOS1drainArea == 0) || + (here->MOS1sourceArea == 0) ) { + here->MOS1sourceVcrit = here->MOS1drainVcrit = + vt*log(vt/(CONSTroot2*here->MOS1tSatCur)); + } else { + here->MOS1drainVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS1tSatCurDens * here->MOS1drainArea)); + here->MOS1sourceVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS1tSatCurDens * here->MOS1sourceArea)); + } + + if(model->MOS1capBDGiven) { + czbd = here->MOS1tCbd; + } else { + if(model->MOS1bulkCapFactorGiven) { + czbd=here->MOS1tCj*here->MOS1drainArea; + } else { + czbd=0; + } + } + if(model->MOS1sideWallCapFactorGiven) { + czbdsw= here->MOS1tCjsw * here->MOS1drainPerimiter; + } else { + czbdsw=0; + } + arg = 1-model->MOS1fwdCapDepCoeff; + sarg = exp( (-model->MOS1bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS1bulkJctSideGradingCoeff) * log(arg) ); + here->MOS1Cbd = czbd; + here->MOS1Cbdsw = czbdsw; + here->MOS1f2d = czbd*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctBotGradingCoeff))* sarg/arg + + czbdsw*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS1f3d = czbd * model->MOS1bulkJctBotGradingCoeff * sarg/arg/ + here->MOS1tBulkPot + + czbdsw * model->MOS1bulkJctSideGradingCoeff * sargsw/arg / + here->MOS1tBulkPot; + here->MOS1f4d = czbd*here->MOS1tBulkPot*(1-arg*sarg)/ + (1-model->MOS1bulkJctBotGradingCoeff) + + czbdsw*here->MOS1tBulkPot*(1-arg*sargsw)/ + (1-model->MOS1bulkJctSideGradingCoeff) + -here->MOS1f3d/2* + (here->MOS1tDepCap*here->MOS1tDepCap) + -here->MOS1tDepCap * here->MOS1f2d; + if(model->MOS1capBSGiven) { + czbs=here->MOS1tCbs; + } else { + if(model->MOS1bulkCapFactorGiven) { + czbs=here->MOS1tCj*here->MOS1sourceArea; + } else { + czbs=0; + } + } + if(model->MOS1sideWallCapFactorGiven) { + czbssw = here->MOS1tCjsw * here->MOS1sourcePerimiter; + } else { + czbssw=0; + } + arg = 1-model->MOS1fwdCapDepCoeff; + sarg = exp( (-model->MOS1bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS1bulkJctSideGradingCoeff) * log(arg) ); + here->MOS1Cbs = czbs; + here->MOS1Cbssw = czbssw; + here->MOS1f2s = czbs*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctBotGradingCoeff))* sarg/arg + + czbssw*(1-model->MOS1fwdCapDepCoeff* + (1+model->MOS1bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS1f3s = czbs * model->MOS1bulkJctBotGradingCoeff * sarg/arg/ + here->MOS1tBulkPot + + czbssw * model->MOS1bulkJctSideGradingCoeff * sargsw/arg / + here->MOS1tBulkPot; + here->MOS1f4s = czbs*here->MOS1tBulkPot*(1-arg*sarg)/ + (1-model->MOS1bulkJctBotGradingCoeff) + + czbssw*here->MOS1tBulkPot*(1-arg*sargsw)/ + (1-model->MOS1bulkJctSideGradingCoeff) + -here->MOS1f3s/2* + (here->MOS1tDepCap*here->MOS1tDepCap) + -here->MOS1tDepCap * here->MOS1f2s; + + + if(model->MOS1drainResistanceGiven) { + if(model->MOS1drainResistance != 0) { + here->MOS1drainConductance = 1/model->MOS1drainResistance; + } else { + here->MOS1drainConductance = 0; + } + } else if (model->MOS1sheetResistanceGiven) { + if(model->MOS1sheetResistance != 0) { + here->MOS1drainConductance = + 1/(model->MOS1sheetResistance*here->MOS1drainSquares); + } else { + here->MOS1drainConductance = 0; + } + } else { + here->MOS1drainConductance = 0; + } + if(model->MOS1sourceResistanceGiven) { + if(model->MOS1sourceResistance != 0) { + here->MOS1sourceConductance = 1/model->MOS1sourceResistance; + } else { + here->MOS1sourceConductance = 0; + } + } else if (model->MOS1sheetResistanceGiven) { + if(model->MOS1sheetResistance != 0) { + here->MOS1sourceConductance = + 1/(model->MOS1sheetResistance*here->MOS1sourceSquares); + } else { + here->MOS1sourceConductance = 0; + } + } else { + here->MOS1sourceConductance = 0; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos1/mos1trun.c b/src/spicelib/devices/mos1/mos1trun.c new file mode 100644 index 000000000..d91420910 --- /dev/null +++ b/src/spicelib/devices/mos1/mos1trun.c @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos1defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS1trunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register MOS1model *model = (MOS1model *)inModel; + register MOS1instance *here; + + for( ; model != NULL; model = model->MOS1nextModel) { + for(here=model->MOS1instances;here!=NULL;here = here->MOS1nextInstance){ + if (here->MOS1owner != ARCHme) continue; + + CKTterr(here->MOS1qgs,ckt,timeStep); + CKTterr(here->MOS1qgd,ckt,timeStep); + CKTterr(here->MOS1qgb,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/ChangeLog b/src/spicelib/devices/mos2/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/mos2/Makefile.am b/src/spicelib/devices/mos2/Makefile.am new file mode 100644 index 000000000..9d4ff7f62 --- /dev/null +++ b/src/spicelib/devices/mos2/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libmos2.la + +libmos2_la_SOURCES = \ + mos2.c \ + mos2acld.c \ + mos2ask.c \ + mos2conv.c \ + mos2defs.h \ + mos2del.c \ + mos2dest.c \ + mos2dist.c \ + mos2dset.c \ + mos2ext.h \ + mos2ic.c \ + mos2itf.h \ + mos2load.c \ + mos2mask.c \ + mos2mdel.c \ + mos2mpar.c \ + mos2noi.c \ + mos2par.c \ + mos2pzld.c \ + mos2sacl.c \ + mos2set.c \ + mos2sld.c \ + mos2sprt.c \ + mos2sset.c \ + mos2supd.c \ + mos2temp.c \ + mos2trun.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/mos2/mos2.c b/src/spicelib/devices/mos2/mos2.c new file mode 100644 index 000000000..706db5ea3 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2.c @@ -0,0 +1,171 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "mos2defs.h" +#include "suffix.h" + +IFparm MOS2pTable[] = { /* parameters */ + IOPU("l", MOS2_L, IF_REAL , "Length"), + IOPU("w", MOS2_W, IF_REAL , "Width"), + IOPU("ad", MOS2_AD, IF_REAL , "Drain area"), + IOPU("as", MOS2_AS, IF_REAL , "Source area"), + IOPU("pd", MOS2_PD, IF_REAL , "Drain perimeter"), + IOPU("ps", MOS2_PS, IF_REAL , "Source perimeter"), + OP( "id", MOS2_CD, IF_REAL,"Drain current"), + OPR( "cd", MOS2_CD, IF_REAL,""), + OP( "ibd", MOS2_CBD, IF_REAL, "B-D junction current"), + OP( "ibs", MOS2_CBS, IF_REAL, "B-S junction current"), + OP( "is", MOS2_CS, IF_REAL, "Source current "), + OP( "ig", MOS2_CG, IF_REAL, "Gate current "), + OP( "ib", MOS2_CB, IF_REAL, "Bulk current "), + OP( "vgs", MOS2_VGS, IF_REAL, "Gate-Source voltage"), + OP( "vds", MOS2_VDS, IF_REAL, "Drain-Source voltage"), + OP( "vbs", MOS2_VBS, IF_REAL, "Bulk-Source voltage"), + OPU( "vbd", MOS2_VBD, IF_REAL, "Bulk-Drain voltage"), + IOPU("nrd", MOS2_NRD, IF_REAL , "Drain squares"), + IOPU("nrs", MOS2_NRS, IF_REAL , "Source squares"), + IP("off", MOS2_OFF, IF_FLAG , "Device initially off"), + IOPAU("icvds", MOS2_IC_VDS,IF_REAL , "Initial D-S voltage"), + IOPAU("icvgs", MOS2_IC_VGS,IF_REAL , "Initial G-S voltage"), + IOPAU("icvbs", MOS2_IC_VBS,IF_REAL , "Initial B-S voltage"), + IOPU("temp", MOS2_TEMP, IF_REAL , "Instance operating temperature"), + IP( "ic", MOS2_IC, IF_REALVEC, "Vector of D-S, G-S, B-S voltages"), + IP( "sens_l", MOS2_L_SENS,IF_FLAG, "flag to request sensitivity WRT length"), + IP( "sens_w", MOS2_W_SENS,IF_FLAG, "flag to request sensitivity WRT width"), + /* + OP( "cgs", MOS2_CGS, IF_REAL , "Gate-Source capacitance"), + OP( "cgd", MOS2_CGD, IF_REAL , "Gate-Drain capacitance"), + */ + OPU( "dnode", MOS2_DNODE, IF_INTEGER, "Number of drain node"), + OPU( "gnode", MOS2_GNODE, IF_INTEGER, "Number of gate node"), + OPU( "snode", MOS2_SNODE, IF_INTEGER, "Number of source node"), + OPU( "bnode", MOS2_BNODE, IF_INTEGER, "Number of bulk node"), + OPU( "dnodeprime", MOS2_DNODEPRIME, IF_INTEGER, + "Number of internal drain node"), + OPU( "snodeprime", MOS2_SNODEPRIME, IF_INTEGER, + "Number of internal source node"), + OP( "von", MOS2_VON, IF_REAL, " "), + OP( "vdsat", MOS2_VDSAT, IF_REAL,"Saturation drain voltage"), + OPU( "sourcevcrit", MOS2_SOURCEVCRIT, IF_REAL,"Critical source voltage"), + OPU( "drainvcrit", MOS2_DRAINVCRIT, IF_REAL,"Critical drain voltage"), + OP( "rs", MOS2_SOURCERESIST, IF_REAL, "Source resistance"), + OPU( "sourceconductance", MOS2_SOURCECONDUCT, IF_REAL, "Source conductance"), + OP( "rd", MOS2_DRAINRESIST, IF_REAL, "Drain resistance"), + OPU( "drainconductance", MOS2_DRAINCONDUCT, IF_REAL, "Drain conductance"), + OP( "gm", MOS2_GM, IF_REAL, "Transconductance"), + OP( "gds", MOS2_GDS, IF_REAL, "Drain-Source conductance"), + OP( "gmb", MOS2_GMBS, IF_REAL, "Bulk-Source transconductance"), + OPR( "gmbs", MOS2_GMBS, IF_REAL, ""), + OPU( "gbd", MOS2_GBD, IF_REAL, "Bulk-Drain conductance"), + OPU( "gbs", MOS2_GBS, IF_REAL, "Bulk-Source conductance"), + OP( "cbd", MOS2_CAPBD, IF_REAL, "Bulk-Drain capacitance"), + OP( "cbs", MOS2_CAPBS, IF_REAL, "Bulk-Source capacitance"), + OP( "cgs", MOS2_CAPGS, IF_REAL, "Gate-Source capacitance"), + OP( "cgd", MOS2_CAPGD, IF_REAL, "Gate-Drain capacitance"), + OP( "cgb", MOS2_CAPGB, IF_REAL, "Gate-Bulk capacitance"), + + OPU( "cbd0", MOS2_CAPZEROBIASBD, IF_REAL,"Zero-Bias B-D junction capacitance"), + OPU( "cbdsw0",MOS2_CAPZEROBIASBDSW,IF_REAL, " "), + OPU( "cbs0", MOS2_CAPZEROBIASBS, IF_REAL,"Zero-Bias B-S junction capacitance"), + OPU( "cbssw0", MOS2_CAPZEROBIASBSSW,IF_REAL," "), + OPU("cqgs",MOS2_CQGS,IF_REAL,"Capacitance due to gate-source charge storage"), + OPU("cqgd",MOS2_CQGD,IF_REAL,"Capacitance due to gate-drain charge storage"), + OPU("cqgb",MOS2_CQGB,IF_REAL,"Capacitance due to gate-bulk charge storage"), + OPU("cqbd",MOS2_CQBD,IF_REAL,"Capacitance due to bulk-drain charge storage"), + OPU("cqbs",MOS2_CQBS,IF_REAL,"Capacitance due to bulk-source charge storage"), + OPU( "qgs", MOS2_QGS, IF_REAL, "Gate-Source charge storage"), + OPU( "qgd", MOS2_QGD, IF_REAL, "Gate-Drain charge storage"), + OPU( "qgb", MOS2_QGB, IF_REAL, "Gate-Bulk charge storage"), + OPU( "qbd", MOS2_QBD, IF_REAL, "Bulk-Drain charge storage"), + OPU( "qbs", MOS2_QBS, IF_REAL, "Bulk-Source charge storage"), + + OPU( "p", MOS2_POWER, IF_REAL, "Instantaneous power "), + OPU( "sens_l_dc", MOS2_L_SENS_DC, IF_REAL, + "dc sensitivity wrt length"), + OPU( "sens_l_real", MOS2_L_SENS_REAL, IF_REAL, + "real part of ac sensitivity wrt length"), + OPU( "sens_l_imag", MOS2_L_SENS_IMAG, IF_REAL, + "imag part of ac sensitivity wrt length"), + OPU( "sens_l_cplx", MOS2_L_SENS_CPLX, IF_COMPLEX, + "ac sensitivity wrt length"), + OPU( "sens_l_mag", MOS2_L_SENS_MAG, IF_REAL, + "sensitivity wrt l of ac magnitude"), + OPU( "sens_l_ph", MOS2_L_SENS_PH, IF_REAL, + "sensitivity wrt l of ac phase"), + OPU( "sens_w_dc", MOS2_W_SENS_DC, IF_REAL, + "dc sensitivity wrt width"), + OPU( "sens_w_real", MOS2_W_SENS_REAL, IF_REAL, + "dc sensitivity and real part of ac sensitivity wrt width"), + OPU( "sens_w_imag", MOS2_W_SENS_IMAG, IF_REAL, + "imag part of ac sensitivity wrt width"), + OPU( "sens_w_mag", MOS2_W_SENS_MAG, IF_REAL, + "sensitivity wrt w of ac magnitude"), + OPU( "sens_w_ph", MOS2_W_SENS_PH, IF_REAL, + "sensitivity wrt w of ac phase"), + OPU( "sens_w_cplx", MOS2_W_SENS_CPLX, IF_COMPLEX, + "ac sensitivity wrt width") +}; + +IFparm MOS2mPTable[] = { /* model parameters */ + OP("type", MOS2_MOD_TYPE, IF_STRING ,"N-channel or P-channel MOS"), + IOP("vto", MOS2_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOPR("vt0", MOS2_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOP("kp", MOS2_MOD_KP, IF_REAL ,"Transconductance parameter"), + IOP("gamma", MOS2_MOD_GAMMA, IF_REAL ,"Bulk threshold parameter"), + IOP("phi", MOS2_MOD_PHI, IF_REAL ,"Surface potential"), + IOP("lambda",MOS2_MOD_LAMBDA,IF_REAL ,"Channel length modulation"), + IOP("rd", MOS2_MOD_RD, IF_REAL ,"Drain ohmic resistance"), + IOP("rs", MOS2_MOD_RS, IF_REAL ,"Source ohmic resistance"), + IOP("cbd", MOS2_MOD_CBD, IF_REAL ,"B-D junction capacitance"), + IOP("cbs", MOS2_MOD_CBS, IF_REAL ,"B-S junction capacitance"), + IOP("is", MOS2_MOD_IS, IF_REAL ,"Bulk junction sat. current"), + IOP("pb", MOS2_MOD_PB, IF_REAL ,"Bulk junction potential"), + IOPA("cgso", MOS2_MOD_CGSO, IF_REAL ,"Gate-source overlap cap."), + IOPA("cgdo", MOS2_MOD_CGDO, IF_REAL ,"Gate-drain overlap cap."), + IOPA("cgbo", MOS2_MOD_CGBO, IF_REAL ,"Gate-bulk overlap cap."), + IOP("rsh", MOS2_MOD_RSH, IF_REAL ,"Sheet resistance"), + IOPA("cj", MOS2_MOD_CJ, IF_REAL ,"Bottom junction cap per area"), + IOP("mj", MOS2_MOD_MJ, IF_REAL ,"Bottom grading coefficient"), + IOPA("cjsw", MOS2_MOD_CJSW, IF_REAL ,"Side junction cap per area"), + IOP("mjsw", MOS2_MOD_MJSW, IF_REAL ,"Side grading coefficient"), + IOP("js", MOS2_MOD_JS, IF_REAL ,"Bulk jct. sat. current density"), + IOP("tox", MOS2_MOD_TOX, IF_REAL ,"Oxide thickness"), + IOP("ld", MOS2_MOD_LD, IF_REAL ,"Lateral diffusion"), + IOP("u0", MOS2_MOD_U0, IF_REAL ,"Surface mobility"), + IOPR("uo", MOS2_MOD_U0, IF_REAL ,"Surface mobility"), + IOP("fc", MOS2_MOD_FC, IF_REAL ,"Forward bias jct. fit parm."), + IP("nmos", MOS2_MOD_NMOS, IF_FLAG ,"N type MOSfet model"), + IP("pmos", MOS2_MOD_PMOS, IF_FLAG ,"P type MOSfet model"), + IOP("nsub", MOS2_MOD_NSUB, IF_REAL ,"Substrate doping"), + IOP("tpg", MOS2_MOD_TPG, IF_INTEGER,"Gate type"), + IOP("nss", MOS2_MOD_NSS, IF_REAL ,"Surface state density"), + IOP("delta", MOS2_MOD_DELTA, IF_REAL ,"Width effect on threshold"), + IOP("uexp", MOS2_MOD_UEXP, IF_REAL ,"Crit. field exp for mob. deg."), + IOP("ucrit", MOS2_MOD_UCRIT, IF_REAL ,"Crit. field for mob. degradation"), + IOP("vmax", MOS2_MOD_VMAX, IF_REAL ,"Maximum carrier drift velocity"), + IOP("xj", MOS2_MOD_XJ, IF_REAL ,"Junction depth"), + IOP("neff", MOS2_MOD_NEFF, IF_REAL ,"Total channel charge coeff."), + IOP("nfs", MOS2_MOD_NFS, IF_REAL ,"Fast surface state density"), + IOPU("tnom", MOS2_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), + IOP("kf", MOS2_MOD_KF, IF_REAL ,"Flicker noise coefficient"), + IOP("af", MOS2_MOD_AF, IF_REAL ,"Flicker noise exponent") +}; + +char *MOS2names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int MOS2nSize = NUMELEMS(MOS2names); +int MOS2pTSize = NUMELEMS(MOS2pTable); +int MOS2mPTSize = NUMELEMS(MOS2mPTable); +int MOS2iSize = sizeof(MOS2instance); +int MOS2mSize = sizeof(MOS2model); diff --git a/src/spicelib/devices/mos2/mos2acld.c b/src/spicelib/devices/mos2/mos2acld.c new file mode 100644 index 000000000..e598ce039 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2acld.c @@ -0,0 +1,119 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS2acLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + int xnrm; + int xrev; + double xgs; + double xgd; + double xgb; + double xbd; + double xbs; + double capgs; + double capgd; + double capgb; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double EffectiveLength; + + for( ; model != NULL; model = model->MOS2nextModel) { + for(here = model->MOS2instances; here!= NULL; + here = here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + if (here->MOS2mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * meyer's model parameters + */ + EffectiveLength=here->MOS2l - 2*model->MOS2latDiff; + GateSourceOverlapCap = model->MOS2gateSourceOverlapCapFactor * + here->MOS2w; + GateDrainOverlapCap = model->MOS2gateDrainOverlapCapFactor * + here->MOS2w; + GateBulkOverlapCap = model->MOS2gateBulkOverlapCapFactor * + EffectiveLength; + capgs = ( *(ckt->CKTstate0+here->MOS2capgs)+ + *(ckt->CKTstate0+here->MOS2capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS2capgd)+ + *(ckt->CKTstate0+here->MOS2capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS2capgb)+ + *(ckt->CKTstate0+here->MOS2capgb) + + GateBulkOverlapCap ); + xgs = capgs * ckt->CKTomega; + xgd = capgd * ckt->CKTomega; + xgb = capgb * ckt->CKTomega; + xbd = here->MOS2capbd * ckt->CKTomega; + xbs = here->MOS2capbs * ckt->CKTomega; + /* + * load matrix + */ + + *(here->MOS2GgPtr +1) += xgd+xgs+xgb; + *(here->MOS2BbPtr +1) += xgb+xbd+xbs; + *(here->MOS2DPdpPtr +1) += xgd+xbd; + *(here->MOS2SPspPtr +1) += xgs+xbs; + *(here->MOS2GbPtr +1) -= xgb; + *(here->MOS2GdpPtr +1) -= xgd; + *(here->MOS2GspPtr +1) -= xgs; + *(here->MOS2BgPtr +1) -= xgb; + *(here->MOS2BdpPtr +1) -= xbd; + *(here->MOS2BspPtr +1) -= xbs; + *(here->MOS2DPgPtr +1) -= xgd; + *(here->MOS2DPbPtr +1) -= xbd; + *(here->MOS2SPgPtr +1) -= xgs; + *(here->MOS2SPbPtr +1) -= xbs; + *(here->MOS2DdPtr) += here->MOS2drainConductance; + *(here->MOS2SsPtr) += here->MOS2sourceConductance; + *(here->MOS2BbPtr) += here->MOS2gbd+here->MOS2gbs; + *(here->MOS2DPdpPtr) += here->MOS2drainConductance+ + here->MOS2gds+here->MOS2gbd+ + xrev*(here->MOS2gm+here->MOS2gmbs); + *(here->MOS2SPspPtr) += here->MOS2sourceConductance+ + here->MOS2gds+here->MOS2gbs+ + xnrm*(here->MOS2gm+here->MOS2gmbs); + *(here->MOS2DdpPtr) -= here->MOS2drainConductance; + *(here->MOS2SspPtr) -= here->MOS2sourceConductance; + *(here->MOS2BdpPtr) -= here->MOS2gbd; + *(here->MOS2BspPtr) -= here->MOS2gbs; + *(here->MOS2DPdPtr) -= here->MOS2drainConductance; + *(here->MOS2DPgPtr) += (xnrm-xrev)*here->MOS2gm; + *(here->MOS2DPbPtr) += -here->MOS2gbd+(xnrm-xrev)*here->MOS2gmbs; + *(here->MOS2DPspPtr) -= here->MOS2gds+ + xnrm*(here->MOS2gm+here->MOS2gmbs); + *(here->MOS2SPgPtr) -= (xnrm-xrev)*here->MOS2gm; + *(here->MOS2SPsPtr) -= here->MOS2sourceConductance; + *(here->MOS2SPbPtr) -= here->MOS2gbs+(xnrm-xrev)*here->MOS2gmbs; + *(here->MOS2SPdpPtr) -= here->MOS2gds+ + xrev*(here->MOS2gm+here->MOS2gmbs); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2ask.c b/src/spicelib/devices/mos2/mos2ask.c new file mode 100644 index 000000000..14e05377a --- /dev/null +++ b/src/spicelib/devices/mos2/mos2ask.c @@ -0,0 +1,422 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +MOS2ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + MOS2instance *here = (MOS2instance *)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case MOS2_TEMP: + value->rValue = here->MOS2temp-CONSTCtoK; + return(OK); + case MOS2_CGS: + value->rValue = *(ckt->CKTstate0 + here->MOS2capgs); + return(OK); + case MOS2_CGD: + value->rValue = *(ckt->CKTstate0 + here->MOS2capgd); + return(OK); + case MOS2_L: + value->rValue = here->MOS2l; + return(OK); + case MOS2_W: + value->rValue = here->MOS2w; + return(OK); + case MOS2_AS: + value->rValue = here->MOS2sourceArea; + return(OK); + case MOS2_AD: + value->rValue = here->MOS2drainArea; + return(OK); + case MOS2_PS: + value->rValue = here->MOS2sourcePerimiter; + return(OK); + case MOS2_PD: + value->rValue = here->MOS2drainPerimiter; + return(OK); + case MOS2_NRS: + value->rValue = here->MOS2sourceSquares; + return(OK); + case MOS2_NRD: + value->rValue = here->MOS2drainSquares; + return(OK); + case MOS2_OFF: + value->rValue = here->MOS2off; + return(OK); + case MOS2_IC_VBS: + value->rValue = here->MOS2icVBS; + return(OK); + case MOS2_IC_VDS: + value->rValue = here->MOS2icVDS; + return(OK); + case MOS2_IC_VGS: + value->rValue = here->MOS2icVGS; + return(OK); + case MOS2_DNODE: + value->iValue = here->MOS2dNode; + return(OK); + case MOS2_GNODE: + value->iValue = here->MOS2gNode; + return(OK); + case MOS2_SNODE: + value->iValue = here->MOS2sNode; + return(OK); + case MOS2_BNODE: + value->iValue = here->MOS2bNode; + return(OK); + case MOS2_DNODEPRIME: + value->iValue = here->MOS2dNodePrime; + return(OK); + case MOS2_SNODEPRIME: + value->iValue = here->MOS2sNodePrime; + return(OK); + case MOS2_SOURCECONDUCT: + value->rValue = here->MOS2sourceConductance; + return(OK); + case MOS2_DRAINCONDUCT: + value->rValue = here->MOS2drainConductance; + return(OK); + case MOS2_SOURCERESIST: + if (here->MOS2sNodePrime != here->MOS2sNode) + value->rValue = 1.0 / here->MOS2sourceConductance; + else + value->rValue = 0.0; + return(OK); + case MOS2_DRAINRESIST: + if (here->MOS2dNodePrime != here->MOS2dNode) + value->rValue = 1.0 / here->MOS2drainConductance; + else + value->rValue = 0.0; + return(OK); + case MOS2_VON: + value->rValue = here->MOS2von; + return(OK); + case MOS2_VDSAT: + value->rValue = here->MOS2vdsat; + return(OK); + case MOS2_SOURCEVCRIT: + value->rValue = here->MOS2sourceVcrit; + return(OK); + case MOS2_DRAINVCRIT: + value->rValue = here->MOS2drainVcrit; + return(OK); + case MOS2_CD: + value->rValue = here->MOS2cd; + return(OK); + case MOS2_CBS: + value->rValue = here->MOS2cbs; + return(OK); + case MOS2_CBD: + value->rValue = here->MOS2cbd; + return(OK); + case MOS2_GMBS: + value->rValue = here->MOS2gmbs; + return(OK); + case MOS2_GM: + value->rValue = here->MOS2gm; + return(OK); + case MOS2_GDS: + value->rValue = here->MOS2gds; + return(OK); + case MOS2_GBD: + value->rValue = here->MOS2gbd; + return(OK); + case MOS2_GBS: + value->rValue = here->MOS2gbs; + return(OK); + case MOS2_CAPBD: + value->rValue = here->MOS2capbd; + return(OK); + case MOS2_CAPBS: + value->rValue = here->MOS2capbs; + return(OK); + case MOS2_CAPZEROBIASBD: + value->rValue = here->MOS2Cbd; + return(OK); + case MOS2_CAPZEROBIASBDSW: + value->rValue = here->MOS2Cbdsw; + return(OK); + case MOS2_CAPZEROBIASBS: + value->rValue = here->MOS2Cbs; + return(OK); + case MOS2_CAPZEROBIASBSSW: + value->rValue = here->MOS2Cbssw; + return(OK); + case MOS2_VBD: + value->rValue = *(ckt->CKTstate0 + here->MOS2vbd); + return(OK); + case MOS2_VBS: + value->rValue = *(ckt->CKTstate0 + here->MOS2vbs); + return(OK); + case MOS2_VGS: + value->rValue = *(ckt->CKTstate0 + here->MOS2vgs); + return(OK); + case MOS2_VDS: + value->rValue = *(ckt->CKTstate0 + here->MOS2vds); + return(OK); + case MOS2_CAPGS: + value->rValue = *(ckt->CKTstate0 + here->MOS2capgs); + return(OK); + case MOS2_QGS: + value->rValue = *(ckt->CKTstate0 + here->MOS2qgs); + return(OK); + case MOS2_CQGS: + value->rValue = *(ckt->CKTstate0 + here->MOS2cqgs); + return(OK); + case MOS2_CAPGD: + value->rValue = *(ckt->CKTstate0 + here->MOS2capgd); + return(OK); + case MOS2_QGD: + value->rValue = *(ckt->CKTstate0 + here->MOS2qgd); + return(OK); + case MOS2_CQGD: + value->rValue = *(ckt->CKTstate0 + here->MOS2cqgd); + return(OK); + case MOS2_CAPGB: + value->rValue = *(ckt->CKTstate0 + here->MOS2capgb); + return(OK); + case MOS2_QGB: + value->rValue = *(ckt->CKTstate0 + here->MOS2qgb); + return(OK); + case MOS2_CQGB: + value->rValue = *(ckt->CKTstate0 + here->MOS2cqgb); + return(OK); + case MOS2_QBD: + value->rValue = *(ckt->CKTstate0 + here->MOS2qbd); + return(OK); + case MOS2_CQBD: + value->rValue = *(ckt->CKTstate0 + here->MOS2cqbd); + return(OK); + case MOS2_QBS: + value->rValue = *(ckt->CKTstate0 + here->MOS2qbs); + return(OK); + case MOS2_CQBS: + value->rValue = *(ckt->CKTstate0 + here->MOS2cqbs); + return(OK); + case MOS2_L_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS2senParmNo); + } + return(OK); + case MOS2_L_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo); + } + return(OK); + case MOS2_L_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo); + } + return(OK); + case MOS2_L_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS2_L_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS2_L_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo); + } + return(OK); + case MOS2_W_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + } + return(OK); + case MOS2_W_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + } + return(OK); + case MOS2_W_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + } + return(OK); + case MOS2_W_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS2_W_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS2_W_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS2senParmNo + here->MOS2sens_l); + } + return(OK); + case MOS2_CB : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS2ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = here->MOS2cbd + here->MOS2cbs - *(ckt->CKTstate0 + + here->MOS2cqgb); + } + return(OK); + case MOS2_CG : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS2ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { + value->rValue = 0; + } else if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + (ckt->CKTmode & MODETRANOP)) { + value->rValue = 0; + } else { + value->rValue = *(ckt->CKTstate0 + here->MOS2cqgb) + + *(ckt->CKTstate0 + here->MOS2cqgd) + *(ckt->CKTstate0 + + here->MOS2cqgs); + } + return(OK); + case MOS2_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS2ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -here->MOS2cd; + value->rValue -= here->MOS2cbd + here->MOS2cbs - + *(ckt->CKTstate0 + here->MOS2cqgb); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue -= *(ckt->CKTstate0 + here->MOS2cqgb) + + *(ckt->CKTstate0 + here->MOS2cqgd) + + *(ckt->CKTstate0 + here->MOS2cqgs); + } + } + return(OK); + case MOS2_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS2ask.c"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + double temp; + + value->rValue = here->MOS2cd * + *(ckt->CKTrhsOld + here->MOS2dNode); + value->rValue += (here->MOS2cbd + here->MOS2cbs - + *(ckt->CKTstate0 + here->MOS2cqgb)) * + *(ckt->CKTrhsOld + here->MOS2bNode); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue += (*(ckt->CKTstate0 + here->MOS2cqgb) + + *(ckt->CKTstate0 + here->MOS2cqgd) + + *(ckt->CKTstate0 + here->MOS2cqgs)) * + *(ckt->CKTrhsOld + here->MOS2gNode); + } + temp = -here->MOS2cd; + temp -= here->MOS2cbd + here->MOS2cbs ; + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + temp -= *(ckt->CKTstate0 + here->MOS2cqgb) + + *(ckt->CKTstate0 + here->MOS2cqgd) + + *(ckt->CKTstate0 + here->MOS2cqgs); + } + value->rValue += temp * *(ckt->CKTrhsOld + here->MOS2sNode); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos2/mos2conv.c b/src/spicelib/devices/mos2/mos2conv.c new file mode 100644 index 000000000..1a35108c1 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2conv.c @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS2convTest(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + double delvbs; + double delvbd; + double delvgs; + double delvds; + double delvgd; + double cbhat; + double cdhat; + double vbs; + double vbd; + double vgs; + double vds; + double vgd; + double vgdo; + double tol; + + for( ; model != NULL; model = model->MOS2nextModel) { + for(here = model->MOS2instances; here!= NULL; + here = here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + vbs = model->MOS2type * ( + *(ckt->CKTrhs+here->MOS2bNode) - + *(ckt->CKTrhs+here->MOS2sNodePrime)); + vgs = model->MOS2type * ( + *(ckt->CKTrhs+here->MOS2gNode) - + *(ckt->CKTrhs+here->MOS2sNodePrime)); + vds = model->MOS2type * ( + *(ckt->CKTrhs+here->MOS2dNodePrime) - + *(ckt->CKTrhs+here->MOS2sNodePrime)); + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS2vgs) - + *(ckt->CKTstate0 + here->MOS2vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS2vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS2vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS2vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS2vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS2mode >= 0) { + cdhat= + here->MOS2cd- + here->MOS2gbd * delvbd + + here->MOS2gmbs * delvbs + + here->MOS2gm * delvgs + + here->MOS2gds * delvds ; + } else { + cdhat= + here->MOS2cd - + ( here->MOS2gbd - + here->MOS2gmbs) * delvbd - + here->MOS2gm * delvgd + + here->MOS2gds * delvds ; + } + cbhat= + here->MOS2cbs + + here->MOS2cbd + + here->MOS2gbd * delvbd + + here->MOS2gbs * delvbs ; + /* + * check convergence + */ + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(here->MOS2cd))+ + ckt->CKTabstol; + if (fabs(cdhat-here->MOS2cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged */ + } else { + tol=ckt->CKTreltol* + MAX(fabs(cbhat),fabs(here->MOS2cbs+here->MOS2cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS2cbs+here->MOS2cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged*/ + } + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2defs.h b/src/spicelib/devices/mos2/mos2defs.h new file mode 100644 index 000000000..5bec7c8eb --- /dev/null +++ b/src/spicelib/devices/mos2/mos2defs.h @@ -0,0 +1,541 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef MOS2 +#define MOS2 + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + +/* declarations for level 2 MOSFETs */ + +/* information needed for each instance */ + +typedef struct sMOS2instance { + struct sMOS2model *MOS2modPtr; /* backpointer to model */ + struct sMOS2instance *MOS2nextInstance; /* pointer to next instance of + *current model*/ + IFuid MOS2name; /* pointer to character string naming this instance */ + int MOS2owner; /* number of owner process */ + int MOS2states; /* index into state table for this device */ + int MOS2dNode; /* number of the gate node of the mosfet */ + int MOS2gNode; /* number of the gate node of the mosfet */ + int MOS2sNode; /* number of the source node of the mosfet */ + int MOS2bNode; /* number of the bulk node of the mosfet */ + int MOS2dNodePrime; /* number of the internal drain node of the mosfet */ + int MOS2sNodePrime; /* number of the internal source node of the mosfet */ + + + int MOS2mode; /* device mode : 1 = normal, -1 = inverse */ + + unsigned MOS2off :1;/* non-zero to indicate device is off for dc analysis*/ + unsigned MOS2lGiven :1; + unsigned MOS2wGiven :1; + unsigned MOS2drainAreaGiven :1; + unsigned MOS2sourceAreaGiven :1; + unsigned MOS2drainSquaresGiven :1; + unsigned MOS2sourceSquaresGiven :1; + unsigned MOS2drainPerimiterGiven :1; + unsigned MOS2sourcePerimiterGiven :1; + unsigned MOS2dNodePrimeSet :1; + unsigned MOS2sNodePrimeSet :1; + unsigned MOS2icVBSGiven :1; + unsigned MOS2icVDSGiven :1; + unsigned MOS2icVGSGiven :1; + unsigned MOS2vonGiven :1; + unsigned MOS2vdsatGiven :1; + unsigned MOS2tempGiven :1; /* per-instance temperature specified? */ + unsigned MOS2sens_l :1; /* field which indicates whether + length of the mosfet is a design + parameter or not */ + unsigned MOS2sens_w :1; /* field which indicates whether + width of the mosfet is a design + parameter or not */ + unsigned MOS2senPertFlag :1; /* indictes whether the the parameter of + the particular instance is to be perturbed */ + + + double *MOS2DdPtr; /* pointer to sparse matrix element at + * (Drain node,drain node) */ + double *MOS2GgPtr; /* pointer to sparse matrix element at + * (gate node,gate node) */ + double *MOS2SsPtr; /* pointer to sparse matrix element at + * (source node,source node) */ + double *MOS2BbPtr; /* pointer to sparse matrix element at + * (bulk node,bulk node) */ + double *MOS2DPdpPtr; /* pointer to sparse matrix element at + * (drain prime node,drain prime node) */ + double *MOS2SPspPtr; /* pointer to sparse matrix element at + * (source prime node,source prime node) */ + double *MOS2DdpPtr; /* pointer to sparse matrix element at + * (drain node,drain prime node) */ + double *MOS2GbPtr; /* pointer to sparse matrix element at + * (gate node,bulk node) */ + double *MOS2GdpPtr; /* pointer to sparse matrix element at + * (gate node,drain prime node) */ + double *MOS2GspPtr; /* pointer to sparse matrix element at + * (gate node,source prime node) */ + double *MOS2SspPtr; /* pointer to sparse matrix element at + * (source node,source prime node) */ + double *MOS2BdpPtr; /* pointer to sparse matrix element at + * (bulk node,drain prime node) */ + double *MOS2BspPtr; /* pointer to sparse matrix element at + * (bulk node,source prime node) */ + double *MOS2DPspPtr; /* pointer to sparse matrix element at + * (drain prime node,source prime node) */ + double *MOS2DPdPtr; /* pointer to sparse matrix element at + * (drain prime node,drain node) */ + double *MOS2BgPtr; /* pointer to sparse matrix element at + * (bulk node,gate node) */ + double *MOS2DPgPtr; /* pointer to sparse matrix element at + * (drain prime node,gate node) */ + + double *MOS2SPgPtr; /* pointer to sparse matrix element at + * (source prime node,gate node) */ + double *MOS2SPsPtr; /* pointer to sparse matrix element at + * (source prime node,source node) */ + double *MOS2DPbPtr; /* pointer to sparse matrix element at + * (drain prime node,bulk node) */ + double *MOS2SPbPtr; /* pointer to sparse matrix element at + * (source prime node,bulk node) */ + double *MOS2SPdpPtr; /* pointer to sparse matrix element at + * (source prime node,drain prime node) */ + int MOS2senParmNo; /* parameter # for sensitivity use; + set equal to 0 if neither length + nor width of the mosfet is a design + parameter */ + double MOS2cgs; + double MOS2cgd; + double MOS2cgb; + double *MOS2sens; + +#define MOS2senCgs MOS2sens /* contains pertured values of cgs */ +#define MOS2senCgd MOS2sens + 6 /* contains perturbed values of cgd*/ +#define MOS2senCgb MOS2sens + 12 /* contains perturbed values of cgb*/ +#define MOS2senCbd MOS2sens + 18 /* contains perturbed values of cbd*/ +#define MOS2senCbs MOS2sens + 24 /* contains perturbed values of cbs*/ +#define MOS2senGds MOS2sens + 30 /* contains perturbed values of gds*/ +#define MOS2senGbs MOS2sens + 36 /* contains perturbed values of gbs*/ +#define MOS2senGbd MOS2sens + 42 /* contains perturbed values of gbd*/ +#define MOS2senGm MOS2sens + 48 /* contains perturbed values of gm*/ +#define MOS2senGmbs MOS2sens + 54 /* contains perturbed values of gmbs*/ +#define MOS2dphigs_dl MOS2sens + 60 +#define MOS2dphigd_dl MOS2sens + 61 +#define MOS2dphigb_dl MOS2sens + 62 +#define MOS2dphibs_dl MOS2sens + 63 +#define MOS2dphibd_dl MOS2sens + 64 +#define MOS2dphigs_dw MOS2sens + 65 +#define MOS2dphigd_dw MOS2sens + 66 +#define MOS2dphigb_dw MOS2sens + 67 +#define MOS2dphibs_dw MOS2sens + 68 +#define MOS2dphibd_dw MOS2sens + 69 + + double MOS2temp; /* temperature at which this instance operates */ + double MOS2tTransconductance; /* temperature corrected transconductance*/ + double MOS2tSurfMob; /* temperature corrected surface mobility */ + double MOS2tPhi; /* temperature corrected Phi */ + double MOS2tVto; /* temperature corrected Vto */ + double MOS2tSatCur; /* temperature corrected saturation Cur. */ + double MOS2tSatCurDens; /* temperature corrected saturation Cur. density*/ + double MOS2tCbd; /* temperature corrected B-D Capacitance */ + double MOS2tCbs; /* temperature corrected B-S Capacitance */ + double MOS2tCj; /* temperature corrected Bulk bottom Capacitance */ + double MOS2tCjsw; /* temperature corrected Bulk side Capacitance */ + double MOS2tBulkPot; /* temperature corrected Bulk potential */ + double MOS2tDepCap; /* temperature adjusted transition point in */ + /* the cureve matching Fc * Vj */ + double MOS2tVbi; /* temperature adjusted Vbi */ + + double MOS2l; /* the length of the channel region */ + double MOS2w; /* the width of the channel region */ + double MOS2drainArea; /* the area of the drain diffusion */ + double MOS2sourceArea; /* the area of the source diffusion */ + double MOS2drainSquares; /* the length of the drain in squares */ + double MOS2sourceSquares; /* the length of the source in squares */ + double MOS2drainPerimiter; + double MOS2sourcePerimiter; + double MOS2sourceConductance; /*conductance of source(or 0):set in setup*/ + double MOS2drainConductance; /*conductance of drain(or 0):set in setup*/ + + double MOS2icVBS; /* initial condition B-S voltage */ + double MOS2icVDS; /* initial condition D-S voltage */ + double MOS2icVGS; /* initial condition G-S voltage */ + double MOS2von; + double MOS2vdsat; + double MOS2sourceVcrit; /* Vcrit for pos. vds */ + double MOS2drainVcrit; /* Vcrit for pos. vds */ + double MOS2cd; + double MOS2cbs; + double MOS2cbd; + double MOS2gmbs; + double MOS2gm; + double MOS2gds; + double MOS2gbd; + double MOS2gbs; + double MOS2capbd; + double MOS2capbs; + double MOS2Cbd; + double MOS2Cbdsw; + double MOS2Cbs; + double MOS2Cbssw; + double MOS2f2d; + double MOS2f3d; + double MOS2f4d; + double MOS2f2s; + double MOS2f3s; + double MOS2f4s; + + /* distortion stuff */ +/* + * naming convention: + * x = vgs + * y = vbs + * z = vds + * cdr = cdrain + */ + + + +#define MOS2NDCOEFFS 30 + +#ifndef NODISTO + double MOS2dCoeffs[MOS2NDCOEFFS]; +#else /* NODISTO */ + double *MOS2dCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define capbs2 MOS2dCoeffs[0] +#define capbs3 MOS2dCoeffs[1] +#define capbd2 MOS2dCoeffs[2] +#define capbd3 MOS2dCoeffs[3] +#define gbs2 MOS2dCoeffs[4] +#define gbs3 MOS2dCoeffs[5] +#define gbd2 MOS2dCoeffs[6] +#define gbd3 MOS2dCoeffs[7] +#define capgb2 MOS2dCoeffs[8] +#define capgb3 MOS2dCoeffs[9] +#define cdr_x2 MOS2dCoeffs[10] +#define cdr_y2 MOS2dCoeffs[11] +#define cdr_z2 MOS2dCoeffs[12] +#define cdr_xy MOS2dCoeffs[13] +#define cdr_yz MOS2dCoeffs[14] +#define cdr_xz MOS2dCoeffs[15] +#define cdr_x3 MOS2dCoeffs[16] +#define cdr_y3 MOS2dCoeffs[17] +#define cdr_z3 MOS2dCoeffs[18] +#define cdr_x2z MOS2dCoeffs[19] +#define cdr_x2y MOS2dCoeffs[20] +#define cdr_y2z MOS2dCoeffs[21] +#define cdr_xy2 MOS2dCoeffs[22] +#define cdr_xz2 MOS2dCoeffs[23] +#define cdr_yz2 MOS2dCoeffs[24] +#define cdr_xyz MOS2dCoeffs[25] +#define capgs2 MOS2dCoeffs[26] +#define capgs3 MOS2dCoeffs[27] +#define capgd2 MOS2dCoeffs[28] +#define capgd3 MOS2dCoeffs[29] + /* end distortion coeffs. */ + +#endif + +/* indices to the array of MOSFET(2) noise sources */ + +#define MOS2RDNOIZ 0 +#define MOS2RSNOIZ 1 +#define MOS2IDNOIZ 2 +#define MOS2FLNOIZ 3 +#define MOS2TOTNOIZ 4 + +#define MOS2NSRCS 5 /* the number of MOS2FET noise sources */ + +#ifndef NONOISE + double MOS2nVar[NSTATVARS][MOS2NSRCS]; +#else /* NONOISE */ + double **MOS2nVar; +#endif /* NONOISE */ + + + +} MOS2instance ; + + +#define MOS2vbd MOS2states+ 0 /* bulk-drain voltage */ +#define MOS2vbs MOS2states+ 1 /* bulk-source voltage */ +#define MOS2vgs MOS2states+ 2 /* gate-source voltage */ +#define MOS2vds MOS2states+ 3 /* drain-source voltage */ + +#define MOS2capgs MOS2states+4 /* gate-source capacitor value */ +#define MOS2qgs MOS2states+ 5 /* gate-source capacitor charge */ +#define MOS2cqgs MOS2states+ 6 /* gate-source capacitor current */ + +#define MOS2capgd MOS2states+ 7 /* gate-drain capacitor value */ +#define MOS2qgd MOS2states+ 8 /* gate-drain capacitor charge */ +#define MOS2cqgd MOS2states+ 9 /* gate-drain capacitor current */ + +#define MOS2capgb MOS2states+10 /* gate-bulk capacitor value */ +#define MOS2qgb MOS2states+ 11 /* gate-bulk capacitor charge */ +#define MOS2cqgb MOS2states+ 12 /* gate-bulk capacitor current */ + +#define MOS2qbd MOS2states+ 13 /* bulk-drain capacitor charge */ +#define MOS2cqbd MOS2states+ 14 /* bulk-drain capacitor current */ + +#define MOS2qbs MOS2states+ 15 /* bulk-source capacitor charge */ +#define MOS2cqbs MOS2states+ 16 /* bulk-source capacitor current */ + +#define MOS2numStates 17 + + +#define MOS2sensxpgs MOS2states+17 /* charge sensitivities and their derivatives + +18 for the derivatives - pointer to the + beginning of the array */ + +#define MOS2sensxpgd MOS2states+19 +#define MOS2sensxpgb MOS2states+21 +#define MOS2sensxpbs MOS2states+23 +#define MOS2sensxpbd MOS2states+25 + +#define MOS2numSenStates 10 + + +/* per model data */ + + + /* NOTE: parameters makred 'input - use xxxx' are parameters for + * which a temperature correction is applied in MOS2temp, thus + * the MOS3xxxx value in the per-instance structure should be used + * instead in all calculations + */ + +typedef struct sMOS2model { /* model structure for a resistor */ + int MOS2modType; /* type index of this device type */ + struct sMOS2model *MOS2nextModel; /* pointer to next possible model + *in linked list */ + MOS2instance * MOS2instances; /* pointer to list of instances + * that have this model */ + IFuid MOS2modName; /* pointer to character string naming this model */ + int MOS2type; /* device type : 1 = nmos, -1 = pmos */ + int MOS2gateType; + + double MOS2tnom; /* temperature at which parms were measured */ + double MOS2latDiff; + double MOS2jctSatCurDensity; /* input - use tSatCurDens */ + double MOS2jctSatCur; /* input - use tSatCur */ + double MOS2drainResistance; + double MOS2sourceResistance; + double MOS2sheetResistance; + double MOS2transconductance; /* input - use tTransconductance */ + double MOS2gateSourceOverlapCapFactor; + double MOS2gateDrainOverlapCapFactor; + double MOS2gateBulkOverlapCapFactor; + double MOS2oxideCapFactor; + double MOS2vt0; /* input - use tVto */ + double MOS2capBD; /* input - use tCbd */ + double MOS2capBS; /* input - use tCbs */ + double MOS2bulkCapFactor; /* input - use tCj */ + double MOS2sideWallCapFactor; /* input - use tCjsw */ + double MOS2bulkJctPotential; /* input - use tBulkPot */ + double MOS2bulkJctBotGradingCoeff; + double MOS2bulkJctSideGradingCoeff; + double MOS2fwdCapDepCoeff; + double MOS2phi; /* input - use tPhi */ + double MOS2gamma; + double MOS2lambda; + double MOS2substrateDoping; + double MOS2surfaceStateDensity; + double MOS2fastSurfaceStateDensity; /* nfs */ + double MOS2oxideThickness; + double MOS2surfaceMobility; + double MOS2fNcoef; + double MOS2fNexp; + + double MOS2narrowFactor; /* delta */ + double MOS2critFieldExp; /* uexp */ + double MOS2critField; /* ucrit */ + double MOS2maxDriftVel; /* vmax */ + double MOS2xd; + double MOS2junctionDepth; /* xj */ + double MOS2channelCharge; /* neff */ + + unsigned MOS2tnomGiven :1; /* user specified parm. meas. temp */ + unsigned MOS2typeGiven :1; + unsigned MOS2latDiffGiven :1; + unsigned MOS2jctSatCurDensityGiven :1; + unsigned MOS2jctSatCurGiven :1; + unsigned MOS2drainResistanceGiven :1; + unsigned MOS2sourceResistanceGiven :1; + unsigned MOS2sheetResistanceGiven :1; + unsigned MOS2transconductanceGiven :1; + unsigned MOS2gateSourceOverlapCapFactorGiven :1; + unsigned MOS2gateDrainOverlapCapFactorGiven :1; + unsigned MOS2gateBulkOverlapCapFactorGiven :1; + unsigned MOS2vt0Given :1; + unsigned MOS2capBDGiven :1; + unsigned MOS2capBSGiven :1; + unsigned MOS2bulkCapFactorGiven :1; + unsigned MOS2sideWallCapFactorGiven :1; + unsigned MOS2bulkJctPotentialGiven :1; + unsigned MOS2bulkJctBotGradingCoeffGiven :1; + unsigned MOS2bulkJctSideGradingCoeffGiven :1; + unsigned MOS2fwdCapDepCoeffGiven :1; + unsigned MOS2phiGiven :1; + unsigned MOS2gammaGiven :1; + unsigned MOS2lambdaGiven :1; + unsigned MOS2substrateDopingGiven :1; + unsigned MOS2gateTypeGiven :1; + unsigned MOS2surfaceStateDensityGiven :1; + unsigned MOS2fastSurfaceStateDensityGiven :1; /* nfs */ + unsigned MOS2oxideThicknessGiven :1; + unsigned MOS2surfaceMobilityGiven :1; + unsigned MOS2narrowFactorGiven :1; /* delta */ + unsigned MOS2critFieldExpGiven :1; /* uexp */ + unsigned MOS2critFieldGiven :1; /* ucrit */ + unsigned MOS2maxDriftVelGiven :1; /* vmax */ + unsigned MOS2junctionDepthGiven :1; /* xj */ + unsigned MOS2channelChargeGiven :1; /* neff */ + unsigned MOS2fNcoefGiven :1; + unsigned MOS2fNexpGiven :1; + +} MOS2model; + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + +/* device parameters */ +#define MOS2_W 1 +#define MOS2_L 2 +#define MOS2_AS 3 +#define MOS2_AD 4 +#define MOS2_PS 5 +#define MOS2_PD 6 +#define MOS2_NRS 7 +#define MOS2_NRD 8 +#define MOS2_OFF 9 +#define MOS2_IC 10 +#define MOS2_IC_VBS 11 +#define MOS2_IC_VDS 12 +#define MOS2_IC_VGS 13 +#define MOS2_W_SENS 14 +#define MOS2_L_SENS 15 +#define MOS2_CB 16 +#define MOS2_CG 17 +#define MOS2_CS 18 +#define MOS2_POWER 19 +#define MOS2_CGS 20 +#define MOS2_CGD 21 +#define MOS2_DNODE 22 +#define MOS2_GNODE 23 +#define MOS2_SNODE 24 +#define MOS2_BNODE 25 +#define MOS2_DNODEPRIME 26 +#define MOS2_SNODEPRIME 27 +#define MOS2_SOURCECONDUCT 28 +#define MOS2_DRAINCONDUCT 29 +#define MOS2_VON 30 +#define MOS2_VDSAT 31 +#define MOS2_SOURCEVCRIT 32 +#define MOS2_DRAINVCRIT 33 +#define MOS2_CD 34 +#define MOS2_CBS 35 +#define MOS2_CBD 36 +#define MOS2_GMBS 37 +#define MOS2_GM 38 +#define MOS2_GDS 39 +#define MOS2_GBD 40 +#define MOS2_GBS 41 +#define MOS2_CAPBD 42 +#define MOS2_CAPBS 43 +#define MOS2_CAPZEROBIASBD 44 +#define MOS2_CAPZEROBIASBDSW 45 +#define MOS2_CAPZEROBIASBS 46 +#define MOS2_CAPZEROBIASBSSW 47 +#define MOS2_VBD 48 +#define MOS2_VBS 49 +#define MOS2_VGS 50 +#define MOS2_VDS 51 +#define MOS2_CAPGS 52 +#define MOS2_QGS 53 +#define MOS2_CQGS 54 +#define MOS2_CAPGD 55 +#define MOS2_QGD 56 +#define MOS2_CQGD 57 +#define MOS2_CAPGB 58 +#define MOS2_QGB 59 +#define MOS2_CQGB 60 +#define MOS2_QBD 61 +#define MOS2_CQBD 62 +#define MOS2_QBS 63 +#define MOS2_CQBS 64 +#define MOS2_W_SENS_REAL 65 +#define MOS2_W_SENS_IMAG 66 +#define MOS2_W_SENS_MAG 67 +#define MOS2_W_SENS_PH 68 +#define MOS2_W_SENS_CPLX 69 +#define MOS2_L_SENS_REAL 70 +#define MOS2_L_SENS_IMAG 71 +#define MOS2_L_SENS_MAG 72 +#define MOS2_L_SENS_PH 73 +#define MOS2_L_SENS_CPLX 74 +#define MOS2_L_SENS_DC 75 +#define MOS2_W_SENS_DC 76 +#define MOS2_TEMP 77 +#define MOS2_SOURCERESIST 78 +#define MOS2_DRAINRESIST 79 + +/* model paramerers */ +#define MOS2_MOD_VTO 101 +#define MOS2_MOD_KP 102 +#define MOS2_MOD_GAMMA 103 +#define MOS2_MOD_PHI 104 +#define MOS2_MOD_LAMBDA 105 +#define MOS2_MOD_RD 106 +#define MOS2_MOD_RS 107 +#define MOS2_MOD_CBD 108 +#define MOS2_MOD_CBS 109 +#define MOS2_MOD_IS 110 +#define MOS2_MOD_PB 111 +#define MOS2_MOD_CGSO 112 +#define MOS2_MOD_CGDO 113 +#define MOS2_MOD_CGBO 114 +#define MOS2_MOD_CJ 115 +#define MOS2_MOD_MJ 116 +#define MOS2_MOD_CJSW 117 +#define MOS2_MOD_MJSW 118 +#define MOS2_MOD_JS 119 +#define MOS2_MOD_TOX 120 +#define MOS2_MOD_LD 121 +#define MOS2_MOD_RSH 122 +#define MOS2_MOD_U0 123 +#define MOS2_MOD_FC 124 +#define MOS2_MOD_NSUB 125 +#define MOS2_MOD_TPG 126 +#define MOS2_MOD_NSS 127 +#define MOS2_MOD_NFS 128 +#define MOS2_MOD_DELTA 129 +#define MOS2_MOD_UEXP 130 +#define MOS2_MOD_VMAX 131 +#define MOS2_MOD_XJ 132 +#define MOS2_MOD_NEFF 133 +#define MOS2_MOD_UCRIT 134 +#define MOS2_MOD_NMOS 135 +#define MOS2_MOD_PMOS 136 +#define MOS2_MOD_TNOM 137 +#define MOS2_MOD_KF 139 +#define MOS2_MOD_AF 140 +#define MOS2_MOD_TYPE 141 + + +/* model questions */ + +#include "mos2ext.h" + +#endif /*MOS2*/ + diff --git a/src/spicelib/devices/mos2/mos2del.c b/src/spicelib/devices/mos2/mos2del.c new file mode 100644 index 000000000..ee2ec9d49 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2del.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS2delete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + MOS2model *model = (MOS2model *)inModel; + MOS2instance **fast = (MOS2instance **)inst; + MOS2instance **prev = NULL; + MOS2instance *here; + + for( ; model ; model = model->MOS2nextModel) { + prev = &(model->MOS2instances); + for(here = *prev; here ; here = *prev) { + if(here->MOS2name == name || (fast && here==*fast) ) { + *prev= here->MOS2nextInstance; + FREE(here); + return(OK); + } + prev = &(here->MOS2nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/mos2/mos2dest.c b/src/spicelib/devices/mos2/mos2dest.c new file mode 100644 index 000000000..e760b42b2 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2dest.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos2defs.h" +#include "suffix.h" + + +void +MOS2destroy(inModel) + GENmodel **inModel; +{ + MOS2model **model = (MOS2model **)inModel; + MOS2instance *here; + MOS2instance *prev = NULL; + MOS2model *mod = *model; + MOS2model *oldmod = NULL; + + for( ; mod ; mod = mod->MOS2nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (MOS2instance *)NULL; + for(here = mod->MOS2instances ; here ; here = here->MOS2nextInstance) { + if(prev){ + if(prev->MOS2sens) FREE(prev->MOS2sens); + FREE(prev); + } + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/mos2/mos2dist.c b/src/spicelib/devices/mos2/mos2dist.c new file mode 100644 index 000000000..d4f0c4ef1 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2dist.c @@ -0,0 +1,1387 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +MOS2disto(mode,genmodel,ckt) + GENmodel *genmodel; + register CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + MOS2model *model = (MOS2model *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h1z, i1h1z; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1h2z, i1h2z; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r1hm2z, i1hm2z; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h11z, i2h11z; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double r2h1m2z, i2h1m2z; + double temp, itemp; + register MOS2instance *here; + +if (mode == D_SETUP) + return(MOS2dSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the MOS2 models */ +for( ; model != NULL; model = model->MOS2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + + + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS2gNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS2gNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS2bNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS2bNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS2dNodePrime)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS2dNodePrime)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = DFi2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + (here->MOS2dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F1(here->gbs2, + r1h1y, + i1h1y); + + itemp = D1i2F1(here->gbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = D1i2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgs2, + r1h1x, + i1h1x); + + itemp = ckt->CKTomega * + D1n2F1(here->capgs2, + r1h1x, + i1h1x); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2bNode)) += temp; + *(ckt->CKTirhs + (here->MOS2bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbs2, + r1h1y, + i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + + case D_THRF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS2gNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS2gNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS2bNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS2bNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS2dNodePrime)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS2dNodePrime)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r2h11x = *(job->r2H11ptr + (here->MOS2gNode)) - + *(job->r2H11ptr + (here->MOS2sNodePrime)); + i2h11x = *(job->i2H11ptr + (here->MOS2gNode)) - + *(job->i2H11ptr + (here->MOS2sNodePrime)); + + r2h11y = *(job->r2H11ptr + (here->MOS2bNode)) - + *(job->r2H11ptr + (here->MOS2sNodePrime)); + i2h11y = *(job->i2H11ptr + (here->MOS2bNode)) - + *(job->i2H11ptr + (here->MOS2sNodePrime)); + + r2h11z = *(job->r2H11ptr + (here->MOS2dNodePrime)) - + *(job->r2H11ptr + (here->MOS2sNodePrime)); + i2h11z = *(job->i2H11ptr + (here->MOS2dNodePrime)) - + *(job->i2H11ptr + (here->MOS2sNodePrime)); + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + itemp = DFi3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + + *(ckt->CKTrhs + (here->MOS2dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + itemp = D1i3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = D1i3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = ckt->CKTomega * + D1n3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2bNode)) += temp; + *(ckt->CKTirhs + (here->MOS2bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1PF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS2gNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS2gNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS2bNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS2bNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS2dNodePrime)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS2dNodePrime)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h2x = *(job->r1H2ptr + (here->MOS2gNode)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1h2x = *(job->i1H2ptr + (here->MOS2gNode)) - + *(job->i1H2ptr + (here->MOS2sNodePrime)); + + r1h2y = *(job->r1H2ptr + (here->MOS2bNode)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1h2y = *(job->i1H2ptr + (here->MOS2bNode)) - + *(job->i1H2ptr + (here->MOS2sNodePrime)); + + r1h2z = *(job->r1H2ptr + (here->MOS2dNodePrime)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1h2z = *(job->i1H2ptr + (here->MOS2dNodePrime)) - + *(job->i1H2ptr + (here->MOS2sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + (here->MOS2dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2bNode)) += temp; + *(ckt->CKTirhs + (here->MOS2bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS2gNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS2gNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS2bNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS2bNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS2dNodePrime)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS2dNodePrime)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS2gNode)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS2gNode)) - + *(job->i1H2ptr + (here->MOS2sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS2bNode)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS2bNode)) - + *(job->i1H2ptr + (here->MOS2sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS2dNodePrime)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS2dNodePrime)) - + *(job->i1H2ptr + (here->MOS2sNodePrime))); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + (here->MOS2dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2bNode)) += temp; + *(ckt->CKTirhs + (here->MOS2bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_2F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS2gNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS2gNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS2bNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS2bNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS2dNodePrime)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS2dNodePrime)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS2gNode)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS2gNode)) - + *(job->i1H2ptr + (here->MOS2sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS2bNode)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS2bNode)) - + *(job->i1H2ptr + (here->MOS2sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS2dNodePrime)) - + *(job->r1H2ptr + (here->MOS2sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS2dNodePrime)) - + *(job->i1H2ptr + (here->MOS2sNodePrime))); + + r2h11x = *(job->r1H1ptr + (here->MOS2gNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i2h11x = *(job->i1H1ptr + (here->MOS2gNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r2h11y = *(job->r1H1ptr + (here->MOS2bNode)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i2h11y = *(job->i1H1ptr + (here->MOS2bNode)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r2h11z = *(job->r1H1ptr + (here->MOS2dNodePrime)) - + *(job->r1H1ptr + (here->MOS2sNodePrime)); + i2h11z = *(job->i1H1ptr + (here->MOS2dNodePrime)) - + *(job->i1H1ptr + (here->MOS2sNodePrime)); + + r2h1m2x = *(job->r2H1m2ptr + (here->MOS2gNode)) - + *(job->r2H1m2ptr + (here->MOS2sNodePrime)); + i2h1m2x = *(job->i2H1m2ptr + (here->MOS2gNode)) - + *(job->i2H1m2ptr + (here->MOS2sNodePrime)); + + r2h1m2y = *(job->r2H1m2ptr + (here->MOS2bNode)) - + *(job->r2H1m2ptr + (here->MOS2sNodePrime)); + i2h1m2y = *(job->i2H1m2ptr + (here->MOS2bNode)) - + *(job->i2H1m2ptr + (here->MOS2sNodePrime)); + +r2h1m2z = *(job->r2H1m2ptr + (here->MOS2dNodePrime)) - + *(job->r2H1m2ptr + (here->MOS2sNodePrime)); +i2h1m2z = *(job->i2H1m2ptr + (here->MOS2dNodePrime)) - + *(job->i2H1m2ptr + (here->MOS2sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + +pass.cxx = here->cdr_x2; +pass.cyy = here->cdr_y2; +pass.czz = here->cdr_z2; +pass.cxy = here->cdr_xy; +pass.cyz = here->cdr_yz; +pass.cxz = here->cdr_xz; +pass.cxxx = here->cdr_x3; +pass.cyyy = here->cdr_y3; +pass.czzz = here->cdr_z3; +pass.cxxy = here->cdr_x2y; +pass.cxxz = here->cdr_x2z; +pass.cxyy = here->cdr_xy2; +pass.cyyz = here->cdr_y2z; +pass.cxzz = here->cdr_xz2; +pass.cyzz = here->cdr_yz2; +pass.cxyz = here->cdr_xyz; +pass.r1h1x = r1h1x; +pass.i1h1x = i1h1x; +pass.r1h1y = r1h1y; +pass.i1h1y = i1h1y; +pass.r1h1z = r1h1z; +pass.i1h1z = i1h1z; +pass.r1h2x = r1hm2x; +pass.i1h2x = i1hm2x; +pass.r1h2y = r1hm2y; +pass.i1h2y = i1hm2y; +pass.r1h2z = r1hm2z; +pass.i1h2z = i1hm2z; +pass.r2h11x = r2h11x; +pass.i2h11x = i2h11x; +pass.r2h11y = r2h11y; +pass.i2h11y = i2h11y; +pass.r2h11z = r2h11z; +pass.i2h11z = i2h11z; +pass.h2f1f2x = r2h1m2x; +pass.ih2f1f2x = i2h1m2x; +pass.h2f1f2y = r2h1m2y; +pass.ih2f1f2y = i2h1m2y; +pass.h2f1f2z = r2h1m2z; +pass.ih2f1f2z = i2h1m2z; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + + + *(ckt->CKTrhs + (here->MOS2dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + + itemp = D1i2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = D1i2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = ckt->CKTomega * + D1n2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + *(ckt->CKTrhs + (here->MOS2gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2bNode)) += temp; + *(ckt->CKTirhs + (here->MOS2bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + + *(ckt->CKTrhs + (here->MOS2bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS2bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS2dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS2dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + default: +; + } + } +} +return(OK); +} + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/mos2/mos2dset.c b/src/spicelib/devices/mos2/mos2dset.c new file mode 100644 index 000000000..9dfcad00c --- /dev/null +++ b/src/spicelib/devices/mos2/mos2dset.c @@ -0,0 +1,1413 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include +#include "ngspice.h" +#include "distodef.h" +#include "devdefs.h" +#include "cktdefs.h" +#include "mos2defs.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* assuming silicon - make definition for epsilon of silicon */ +#define EPSSIL (11.7 * 8.854214871e-12) + +static double sig1[4] = {1.0, -1.0, 1.0, -1.0}; +static double sig2[4] = {1.0, 1.0,-1.0, -1.0}; + +int +MOS2dSetup(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + double Beta; + double DrainSatCur; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double arg; + double cdrain; + double ebd; + double evbs; + double sarg; + double sargsw; + double vbd; + double vbs; + double vds; + double vdsat; + double vgb; + double vgd; + double vgs; + double von; + double vt; /* K * T / Q */ + double lcapgs2; + double lcapgd2; + double lcapgb2; + double lcapgs3; + double lcapgd3; + double lcapgb3; + double lgbs, lgbs2, lgbs3; + double lgbd, lgbd2, lgbd3; + double vgst; +double lcapbs, lcapbs2, lcapbs3; +double lcapbd, lcapbd2, lcapbd3; +double gm2, gb2, gds2; +double gmb, gmds, gbds; +double gm3, gb3, gds3; +double gm2b, gm2ds, gmb2, gmds2, gbds2, gb2ds; +double gmbds; + Dderivs d_cdrain; + + /* loop through all the MOS2 device models */ + for( ; model != NULL; model = model->MOS2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + vt = CONSTKoverQ * here->MOS2temp; + + EffectiveLength=here->MOS2l - 2*model->MOS2latDiff; + if( (here->MOS2tSatCurDens == 0) || + (here->MOS2drainArea == 0) || + (here->MOS2sourceArea == 0)) { + DrainSatCur = here->MOS2tSatCur; + SourceSatCur = here->MOS2tSatCur; + } else { + DrainSatCur = here->MOS2tSatCurDens * + here->MOS2drainArea; + SourceSatCur = here->MOS2tSatCurDens * + here->MOS2sourceArea; + } + GateSourceOverlapCap = model->MOS2gateSourceOverlapCapFactor * + here->MOS2w; + GateDrainOverlapCap = model->MOS2gateDrainOverlapCapFactor * + here->MOS2w; + GateBulkOverlapCap = model->MOS2gateBulkOverlapCapFactor * + EffectiveLength; + Beta = here->MOS2tTransconductance * here->MOS2w/EffectiveLength; + OxideCap = model->MOS2oxideCapFactor * EffectiveLength * + here->MOS2w; + + + + + + /* general iteration */ + + + vbs = model->MOS2type * ( + *(ckt->CKTrhsOld+here->MOS2bNode) - + *(ckt->CKTrhsOld+here->MOS2sNodePrime)); + vgs = model->MOS2type * ( + *(ckt->CKTrhsOld+here->MOS2gNode) - + *(ckt->CKTrhsOld+here->MOS2sNodePrime)); + vds = model->MOS2type * ( + *(ckt->CKTrhsOld+here->MOS2dNodePrime) - + *(ckt->CKTrhsOld+here->MOS2sNodePrime)); + + /* now some common crunching for some more useful quantities */ + + + vbd=vbs-vds; + vgd=vgs-vds; + + /* now all the preliminaries are over - we can start doing the * real work + */ + + vgb = vgs - vbs; + + /* bulk-source and bulk-drain doides here we just evaluate + * the ideal diode current and the correspoinding + * derivative (conductance). */ + if(vbs <= 0) { + lgbs = SourceSatCur/vt; + lgbs += ckt->CKTgmin; + lgbs2 = lgbs3 = 0; + } else { + evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); + lgbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + lgbs2 = model->MOS2type *0.5 * (lgbs - ckt->CKTgmin)/vt; + lgbs3 = model->MOS2type *lgbs2/(vt*3); + + } + if(vbd <= 0) { + lgbd = DrainSatCur/vt; + lgbd += ckt->CKTgmin; + lgbd2 = lgbd3 = 0; + } else { + ebd = exp(MIN(MAX_EXP_ARG,vbd/vt)); + lgbd = DrainSatCur*ebd/vt +ckt->CKTgmin; + lgbd2 = model->MOS2type *0.5 * (lgbd - ckt->CKTgmin)/vt; + lgbd3 = model->MOS2type *lgbd2/(vt*3); + } + + if(vds >= 0) { + /* normal mode */ + here->MOS2mode = 1; + } else { + /* inverse mode */ + here->MOS2mode = -1; + } + { + /* moseq2(vds,vbs,vgs,gm,gds,gmbs,qg,qc,qb, + * cggb,cgdb,cgsb,cbgb,cbdb,cbsb) + */ + /* note: cgdb, cgsb, cbdb, cbsb never used */ + + /* + * this routine evaluates the drain current, its derivatives and * the charges associated with the gate, channel and bulk * for mosfets * + */ + + double arg; + double sarg; + double a4[4],b4[4],x4[8],poly4[8]; + double beta1; + double sphi; /* square root of phi */ + double sphi3; /* square root of phi cubed */ + double barg; + double factor; + double eta; + double vbin; + double argd; + double args; + double argss; + double argsd; + double argxs; + double argxd; + double gamasd; + double xwd; + double xws; + double gammad; + double cfs; + double cdonco; + double xn; + double argg; + double sarg3; + double sbiarg; + double body; + double udenom; + double gammd2; + double argv; + double vgsx; + double ufact; + double ueff; + double a1; + double a3; + double a; + double b1; + double b3; + double b; + double c1; + double c; + double d1; + double fi; + double p0; + double p2; + double p3; + double p4; + double p; + double r3; + double r; + double ro; + double s2; + double s; + double v1; + double v2; + double xv; + double y3; + double delta4; + double xvalid; + double bsarg; + double bodys; + double sargv; + double xlfact; + double xdv; + double xlv; + double xls; + double clfact; + double xleff; + double deltal; + double xwb; + double vdson; + double cdson; + double expg; + double xld; + double xlamda = model->MOS2lambda; + Dderivs d_xleff, d_delta1; + Dderivs d_xlfact; + Dderivs d_xlv, d_xls; + Dderivs d_bsarg, d_bodys, d_vdsat, d_sargv; + Dderivs d_delta4, d_a4[3], d_b4[3], d_x4[3], d_poly4[3]; + Dderivs d_xvalid; + Dderivs d_ro, d_fi, d_y3, d_p3, d_p4, d_a3, d_b3; + Dderivs d_r3, d_s2, d_pee, d_p0, d_p2; + Dderivs d_b1, d_c1, d_d1, d_a, d_b, d_c, d_arr, d_s; + Dderivs d_xv, d_a1; + Dderivs d_v1, d_v2; + Dderivs d_argv,d_gammd2; + Dderivs d_ufact; + Dderivs d_udenom; + Dderivs d_sarg3, d_body; + Dderivs d_vgst; + Dderivs d_argg; + Dderivs d_cdonco,d_tmp,d_xn; + Dderivs d_dbargs,d_dbargd,d_dgddvb; + Dderivs d_dbxwd,d_dbxws; + Dderivs d_dsrgdb, d_dbrgdb; + Dderivs d_gamasd, d_gammad, d_args, d_argd; + Dderivs d_argxs, d_argxd; + Dderivs d_argss, d_argsd; + Dderivs d_xwd, d_xws; + Dderivs d_zero; + Dderivs d_vbin; + Dderivs d_barg; + Dderivs d_sarg; + Dderivs d_phiMinVbs; + Dderivs d_p, d_q, d_r; + Dderivs d_von, d_dummy, d_vgsx, d_arg, d_dumarg; + Dderivs d_ueff, d_beta1, d_clfact, d_xlamda,d_mos2gds; + Dderivs d_vdson, d_cdson, d_expg; + double dsrgdb, dbrgdb, dbxwd, dbxws, dbargs, dbargd; + double dgddvb; + + +/* from now on, p=vgs, q=vbs, r=vds */ + +/* + * 'local' variables - these switch d & s around appropriately + * so that we don't have to worry about vds < 0 + */ + + double lvbs = here->MOS2mode==1?vbs:vbd; + double lvds = here->MOS2mode*vds; + double lvgs = here->MOS2mode==1?vgs:vgd; + double phiMinVbs = here->MOS2tPhi - lvbs; + double tmp; /* a temporary variable, not used for more than */ + /* about 10 lines at a time */ + int iknt; + int jknt; + int i; + int j; + + /* + * compute some useful quantities + */ +d_p.value = 0.0; +d_p.d1_p = 1.0; +d_p.d1_q = 0.0; +d_p.d1_r = 0.0; +d_p.d2_p2 = 0.0; +d_p.d2_q2 = 0.0; +d_p.d2_r2 = 0.0; +d_p.d2_pq = 0.0; +d_p.d2_qr = 0.0; +d_p.d2_pr = 0.0; +d_p.d3_p3 = 0.0; +d_p.d3_q3 = 0.0; +d_p.d3_r3 = 0.0; +d_p.d3_p2r = 0.0; +d_p.d3_p2q = 0.0; +d_p.d3_q2r = 0.0; +d_p.d3_pq2 = 0.0; +d_p.d3_pr2 = 0.0; +d_p.d3_qr2 = 0.0; +d_p.d3_pqr = 0.0; + EqualDeriv(&d_q,&d_p); + EqualDeriv(&d_r,&d_p); + EqualDeriv(&d_zero,&d_p); + d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0; + d_q.d1_q = d_r.d1_r = 1.0; + + EqualDeriv(&d_phiMinVbs,&d_q); + d_phiMinVbs.value = phiMinVbs; + d_phiMinVbs.d1_q = - d_phiMinVbs.d1_q; + + if (lvbs <= 0.0) { + sarg = sqrt(phiMinVbs); + SqrtDeriv(&d_sarg, &d_phiMinVbs); + dsrgdb = -0.5/sarg; + InvDeriv(&d_dsrgdb,&d_sarg); + TimesDeriv(&d_dsrgdb,&d_dsrgdb,-0.5); + + } else { + sphi = sqrt(here->MOS2tPhi); /*const*/ + sphi3 = here->MOS2tPhi*sphi; /*const*/ + sarg = sphi/(1.0+0.5*lvbs/here->MOS2tPhi); + EqualDeriv(&d_sarg,&d_q); d_sarg.value = lvbs; + TimesDeriv(&d_sarg,&d_sarg,0.5/here->MOS2tPhi); + d_sarg.value += 1.0; + InvDeriv(&d_sarg,&d_sarg); + TimesDeriv(&d_sarg,&d_sarg,sphi); + dsrgdb = -0.5*sarg*sarg/sphi3; + MultDeriv(&d_dsrgdb,&d_sarg,&d_sarg); + TimesDeriv(&d_dsrgdb,&d_dsrgdb,-0.5/sphi3); + /* tmp = sarg/sphi3; */ + } + if ((lvds-lvbs) >= 0) { + barg = sqrt(phiMinVbs+lvds); + EqualDeriv(&d_barg,&d_phiMinVbs); + d_barg.value += lvds; d_barg.d1_r += 1.0; + SqrtDeriv(&d_barg,&d_barg); + dbrgdb = -0.5/barg; + InvDeriv(&d_dbrgdb,&d_barg); + TimesDeriv(&d_dbrgdb,&d_dbrgdb,-0.5); + } else { + barg = sphi/(1.0+0.5*(lvbs-lvds)/here->MOS2tPhi); + EqualDeriv(&d_barg,&d_q); d_barg.value = lvbs - lvds; + d_barg.d1_r -= 1.0; + TimesDeriv(&d_barg,&d_barg,0.5/here->MOS2tPhi); + d_barg.value += 1.0; + InvDeriv(&d_barg,&d_barg); + TimesDeriv(&d_barg,&d_barg,sphi); + dbrgdb = -0.5*barg*barg/sphi3; + MultDeriv(&d_dbrgdb,&d_barg,&d_barg); + TimesDeriv(&d_dbrgdb,&d_dbrgdb,-0.5/sphi3); + /* tmp = barg/sphi3; */ + } + /* + * calculate threshold voltage (von) + * narrow-channel effect + */ + + /*XXX constant per device */ + factor = 0.125*model->MOS2narrowFactor*2.0*M_PI*EPSSIL/ + OxideCap*EffectiveLength; + /*XXX constant per device */ + eta = 1.0+factor; + vbin = here->MOS2tVbi*model->MOS2type+factor*phiMinVbs; + /* mistake! fixed Dec 7 '89 + TimesDeriv(&d_vbin,&d_phiMinVbs,here->MOS2tVbi* + model->MOS2type+factor); + */ + TimesDeriv(&d_vbin,&d_phiMinVbs,factor); + d_vbin.value += here->MOS2tVbi*model->MOS2type; + + if ((model->MOS2gamma > 0.0) || + (model->MOS2substrateDoping > 0.0)) { + xwd = model->MOS2xd*barg; + xws = model->MOS2xd*sarg; + TimesDeriv(&d_xwd,&d_barg,model->MOS2xd); + TimesDeriv(&d_xws,&d_sarg,model->MOS2xd); + + /* + * short-channel effect with vds .ne. 0.0 */ + + argss = 0.0; + argsd = 0.0; + EqualDeriv(&d_argss,&d_zero); + EqualDeriv(&d_argsd,&d_zero); + if (model->MOS2junctionDepth > 0) { + tmp = 2.0/model->MOS2junctionDepth; /*const*/ + argxs = 1.0+xws*tmp; + TimesDeriv(&d_argxs,&d_xws,tmp); + d_argxs.value += 1.0; + argxd = 1.0+xwd*tmp; + TimesDeriv(&d_argxd,&d_xwd,tmp); + d_argxd.value += 1.0; + args = sqrt(argxs); + SqrtDeriv(&d_args,&d_argxs); + argd = sqrt(argxd); + SqrtDeriv(&d_argd,&d_argxd); + tmp = .5*model->MOS2junctionDepth/EffectiveLength; + argss = tmp * (args-1.0); + TimesDeriv(&d_argss,&d_args,tmp); + d_argss.value -= tmp; + argsd = tmp * (argd-1.0); + TimesDeriv(&d_argsd,&d_argd,tmp); + d_argsd.value -= tmp; + } + gamasd = model->MOS2gamma*(1.0-argss-argsd); + PlusDeriv(&d_gamasd,&d_argss,&d_argsd); + d_gamasd.value -= 1.0; + TimesDeriv(&d_gamasd,&d_gamasd,-model->MOS2gamma); + dbxwd = model->MOS2xd*dbrgdb; + dbxws = model->MOS2xd*dsrgdb; + TimesDeriv(&d_dbxwd,&d_dbrgdb,model->MOS2xd); + TimesDeriv(&d_dbxws,&d_dsrgdb,model->MOS2xd); + if (model->MOS2junctionDepth > 0) { + tmp = 0.5/EffectiveLength; + dbargs = tmp*dbxws/args; + dbargd = tmp*dbxwd/argd; + DivDeriv(&d_dbargs,&d_dbxws,&d_args); + DivDeriv(&d_dbargd,&d_dbxwd,&d_argd); + TimesDeriv(&d_dbargs,&d_dbargs,tmp); + TimesDeriv(&d_dbargd,&d_dbargd,tmp); + } + dgddvb = -model->MOS2gamma*(dbargs+dbargd); + PlusDeriv(&d_dgddvb,&d_dbargs,&d_dbargd); + TimesDeriv(&d_dgddvb,&d_dgddvb,-model->MOS2gamma); + if (model->MOS2junctionDepth > 0) { + } + } else { + gamasd = model->MOS2gamma; + gammad = model->MOS2gamma; + EqualDeriv(&d_gamasd,&d_zero); + EqualDeriv(&d_gammad,&d_zero); + d_gamasd.value = d_gammad.value = model->MOS2gamma; + dgddvb = 0.0; + EqualDeriv(&d_dgddvb,&d_zero); + } + von = vbin+gamasd*sarg; + MultDeriv(&d_von,&d_gamasd,&d_sarg); + PlusDeriv(&d_von,&d_von,&d_vbin); + /* + vth = von; + EqualDeriv(&d_vth,&d_von); + */ + vdsat = 0.0; + EqualDeriv(&d_vdsat,&d_zero); + if (model->MOS2fastSurfaceStateDensity != 0.0 && OxideCap != 0.0) { + /* XXX constant per model */ + cfs = CHARGE*model->MOS2fastSurfaceStateDensity* + 1e4 /*(cm**2/m**2)*/; + cdonco = -(gamasd*dsrgdb + dgddvb*sarg) + factor; + MultDeriv(&d_dummy,&d_dgddvb,&d_sarg); + MultDeriv(&d_cdonco,&d_gamasd,&d_dsrgdb); + PlusDeriv(&d_cdonco,&d_cdonco,&d_dummy); + TimesDeriv(&d_cdonco,&d_cdonco,-1.0); + d_cdonco.value += factor; + xn = 1.0+cfs/OxideCap*here->MOS2w*EffectiveLength+cdonco; + EqualDeriv(&d_xn,&d_cdonco); + d_xn.value = xn; + tmp = vt*xn; + TimesDeriv(&d_tmp,&d_xn,vt); + von = von+tmp; + PlusDeriv(&d_von,&d_von,&d_tmp); + argg = 1.0/tmp; + InvDeriv(&d_argg,&d_tmp); + vgst = lvgs-von; + TimesDeriv(&d_vgst,&d_von,-1.0); + PlusDeriv(&d_vgst,&d_vgst,&d_p); + d_vgst.value += lvgs; + } else { + vgst = lvgs-von; + TimesDeriv(&d_vgst,&d_von,-1.0); + PlusDeriv(&d_vgst,&d_vgst,&d_p); + d_vgst.value += lvgs; + + if (lvgs <= von) { + /* + * cutoff region */ + here->MOS2gds = 0.0; /* look at this later */ + goto line1050; + } + } + + /* + * compute some more useful quantities */ + + sarg3 = sarg*sarg*sarg; + CubeDeriv(&d_sarg3,&d_sarg); + /* XXX constant per model */ + sbiarg = sqrt(here->MOS2tBulkPot); /*const*/ + gammad = gamasd; + EqualDeriv(&d_gammad,&d_gamasd); + body = barg*barg*barg-sarg3; + TimesDeriv(&d_body,&d_sarg3,-1.0); + CubeDeriv(&d_dummy,&d_barg); + PlusDeriv(&d_body,&d_body,&d_dummy); + if (model->MOS2fastSurfaceStateDensity == 0.0) goto line400; + if (OxideCap == 0.0) goto line410; + /* + * evaluate effective mobility and its derivatives */ +line400: + if (OxideCap <= 0.0) goto line410; + udenom = vgst; + EqualDeriv(&d_udenom,&d_vgst); + tmp = model->MOS2critField * 100 /* cm/m */ * EPSSIL/ + model->MOS2oxideCapFactor; + if (udenom <= tmp) goto line410; + ufact = exp(model->MOS2critFieldExp*log(tmp/udenom)); + /* dummy = tmp/udenom */ + InvDeriv(&d_dummy,&d_udenom); + TimesDeriv(&d_dummy,&d_dummy,tmp); + PowDeriv(&d_ufact,&d_dummy,model->MOS2critFieldExp); + ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ *ufact; + TimesDeriv(&d_ueff,&d_ufact,model->MOS2surfaceMobility * 1e-4); + goto line500; +line410: + ufact = 0.0; + EqualDeriv(&d_ufact,&d_zero); + ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ ; + EqualDeriv(&d_ueff,&d_zero); + d_ueff.value = ueff; + + /* + * evaluate saturation voltage and its derivatives according to + * grove-frohman equation */ +line500: + vgsx = lvgs; + EqualDeriv(&d_vgsx,&d_p); d_vgsx.value = lvgs; + gammad = gamasd/eta; /* eta is a constant */ + TimesDeriv(&d_gammad,&d_gamasd,1/eta); + if (model->MOS2fastSurfaceStateDensity != 0 && OxideCap != 0) { + vgsx = MAX(lvgs,von); + /* mistake! fixed Dec 8 '89 if (vgsx < von) { } */ + if (lvgs > von) { + EqualDeriv(&d_vgsx,&d_p);d_vgsx.value = lvgs; + } else { + EqualDeriv(&d_vgsx,&d_von); + } + } + + if (gammad > 0) { + gammd2 = gammad*gammad; + MultDeriv(&d_gammd2,&d_gammad,&d_gammad); + argv = (vgsx-vbin)/eta+phiMinVbs; + TimesDeriv(&d_argv,&d_vbin,-1.0); + PlusDeriv(&d_argv,&d_vgsx,&d_vgsx); + TimesDeriv(&d_argv,&d_argv,1/eta); + PlusDeriv(&d_argv,&d_argv,&d_phiMinVbs); + if (argv <= 0.0) { + vdsat = 0.0; + EqualDeriv(&d_vdsat,&d_zero); + } else { + arg = sqrt(1.0+4.0*argv/gammd2); + DivDeriv(&d_arg,&d_argv,&d_gammd2); + TimesDeriv(&d_arg,&d_arg,4.0);d_arg.value += 1.0; + SqrtDeriv(&d_arg,&d_arg); +#if 0 + dumarg= sqrt(gammd2*gammd2 +4*argv*gammd2); + TimesDeriv(&d_dumarg,&d_argv,4.0); + PlusDeriv(&d_dumarg,&d_dumarg,&d_gammd2); + MultDeriv(&d_dumarg,&d_dumarg,&d_gammd2); + SqrtDeriv(&d_dumarg,&d_dumarg); + + vdsat = (vgsx-vbin)/eta+gammd2*(1.0-arg)/2.0; + /* distortion vdsat=(vgsx-vbin)/eta + (gammd2 - dumarg)/2.0 + = argv - phiMinVbs + (gammd2 - dumarg)/2 */ +#endif + TimesDeriv(&d_dummy,&d_dumarg,-1.0); + PlusDeriv(&d_dummy,&d_dummy,&d_gammd2); + TimesDeriv(&d_dummy,&d_dummy,0.5); + TimesDeriv(&d_vdsat,&d_phiMinVbs,-1.0); + PlusDeriv(&d_vdsat,&d_vdsat,&d_argv); + PlusDeriv(&d_vdsat,&d_dummy,&d_vdsat); + vdsat = MAX(vdsat,0.0); + if (vdsat < 0.0) { + EqualDeriv(&d_vdsat,&d_zero); + } + } + } else { + vdsat = (vgsx-vbin)/eta; + TimesDeriv(&d_vdsat,&d_vbin,-1.0); + PlusDeriv(&d_vdsat,&d_vgsx,&d_vdsat); + TimesDeriv(&d_vdsat,&d_vdsat,1/eta); + vdsat = MAX(vdsat,0.0); + if (vdsat < 0.0) { + EqualDeriv(&d_vdsat,&d_zero); + } + } + if (model->MOS2maxDriftVel > 0) { + /* + * evaluate saturation voltage and its derivatives + * according to baum's theory of scattering velocity + * saturation + */ + gammd2 = gammad*gammad; + MultDeriv(&d_gammd2,&d_gammad,&d_gammad); + v1 = (vgsx-vbin)/eta+phiMinVbs; + TimesDeriv(&d_v1,&d_vbin,-1.0); +#if 0 + /* mistake ! (fixed Dec 7 '89) thanks to Jean Hsu */ + PlusDeriv(&d_v1,&d_vgsx,&d_vgsx); +#endif + PlusDeriv(&d_v1,&d_v1,&d_vgsx); + TimesDeriv(&d_v1,&d_v1,1/eta); + PlusDeriv(&d_v1,&d_v1,&d_phiMinVbs); + v2 = phiMinVbs; + EqualDeriv(&d_v2,&d_phiMinVbs); + xv = model->MOS2maxDriftVel*EffectiveLength/ueff; + InvDeriv(&d_xv,&d_ueff); + TimesDeriv(&d_xv,&d_xv,model->MOS2maxDriftVel*EffectiveLength); + a1 = gammad/0.75; + TimesDeriv(&d_a1,&d_gammad,4.0/3.0); + /* dummy1 = a1 */ + b1 = -2.0*(v1+xv); + PlusDeriv(&d_b1,&d_v1,&d_xv); + TimesDeriv(&d_b1,&d_b1,-2.0); + /* dummy2 = b1 */ + c1 = -2.0*gammad*xv; + MultDeriv(&d_c1,&d_gammad,&d_xv); + TimesDeriv(&d_c1,&d_c1,-2.0); + /* dummy3 = c1 */ + d1 = 2.0*v1*(v2+xv)-v2*v2-4.0/3.0*gammad*sarg3; + MultDeriv(&d_d1,&d_gammad,&d_sarg3); + TimesDeriv(&d_d1,&d_d1,4.0/3.0); + MultDeriv(&d_dummy,&d_v2,&d_v2); + PlusDeriv(&d_d1,&d_d1,&d_dummy); + TimesDeriv(&d_d1,&d_d1,-1.0); + PlusDeriv(&d_dummy,&d_v2,&d_xv); + MultDeriv(&d_dummy,&d_dummy,&d_v1); + TimesDeriv(&d_dummy,&d_dummy,2.0); + PlusDeriv(&d_d1,&d_d1,&d_dummy); + a = -b1; + TimesDeriv(&d_a,&d_b1,-1.0); + b = a1*c1-4.0*d1; + TimesDeriv(&d_b,&d_d1,-4.0); + MultDeriv(&d_dummy,&d_a1,&d_c1); + /* mistake! - fixed Dec 8 '89 + PlusDeriv(&d_d1,&d_d1,&d_dummy); + */ + PlusDeriv(&d_b,&d_b,&d_dummy); + c = -d1*(a1*a1-4.0*b1)-c1*c1; + TimesDeriv(&d_dummy,&d_b1,-4.0); + MultDeriv(&d_c,&d_a1,&d_a1); + PlusDeriv(&d_dummy,&d_dummy,&d_c); + MultDeriv(&d_c,&d_dummy,&d_d1); + MultDeriv(&d_dummy,&d_c1,&d_c1); + PlusDeriv(&d_c,&d_c,&d_dummy); + TimesDeriv(&d_c,&d_c,-1.0); + + r = -a*a/3.0+b; + MultDeriv(&d_arr,&d_a,&d_a); + TimesDeriv(&d_arr,&d_arr,-1.0/3.0); + PlusDeriv(&d_arr,&d_arr,&d_b); + + s = 2.0*a*a*a/27.0-a*b/3.0+c; + CubeDeriv(&d_s,&d_a); + TimesDeriv(&d_s,&d_s,2.0/27.0); + PlusDeriv(&d_s,&d_s,&d_c); + MultDeriv(&d_dummy,&d_a,&d_b); + TimesDeriv(&d_dummy,&d_dummy,-1.0/3.0); + PlusDeriv(&d_s,&d_s,&d_dummy); + + r3 = r*r*r; + CubeDeriv(&d_r3,&d_arr); + + s2 = s*s; + MultDeriv(&d_s2,&d_s,&d_s); + + p = s2/4.0+r3/27.0; + TimesDeriv(&d_dummy,&d_r3,1.0/27.0); + TimesDeriv(&d_pee,&d_s2,0.25); + PlusDeriv(&d_pee,&d_pee,&d_dummy); + p0 = fabs(p); + if (p < 0.0) + /* mistake! fixed Dec 8 '89 + TimesDeriv(&d_pee,&d_pee, -1.0); + */ + TimesDeriv(&d_p0,&d_pee, -1.0); + p2 = sqrt(p0); + SqrtDeriv(&d_p2,&d_p0); + if (p < 0) { + ro = sqrt(s2/4.0+p0); + ro = log(ro)/3.0; + ro = exp(ro); + /* the above is eqvt. to + ro = (s2/4.0 + p0)^1/6; */ + TimesDeriv(&d_ro,&d_s2,0.25); + PlusDeriv(&d_ro,&d_ro,&d_p0); + PowDeriv(&d_ro,&d_ro,1.0/6.0); + fi = atan(-2.0*p2/s); + DivDeriv(&d_fi,&d_p2,&d_s); + TimesDeriv(&d_fi,&d_fi,-2.0); + AtanDeriv(&d_fi,&d_fi); + y3 = 2.0*ro*cos(fi/3.0)-a/3.0; + TimesDeriv(&d_dummy,&d_fi,1.0/3.0); + CosDeriv(&d_dummy,&d_dummy); + MultDeriv(&d_y3,&d_ro,&d_dummy); + TimesDeriv(&d_y3,&d_y3,2.0); + /* mistake! fixed Dec 8 '89 + TimesDeriv(&d_dummy,&d_a,-3.0); + */ + TimesDeriv(&d_dummy,&d_a,-1/3.0); + PlusDeriv(&d_y3,&d_y3,&d_dummy); + } else { + p3 = (-s/2.0+p2); + TimesDeriv(&d_p3,&d_s,-0.5); + PlusDeriv(&d_p3,&d_p3,&d_p2); + p3 = exp(log(fabs(p3))/3.0); + /* eqvt. to (fabs(p3)) ^ 1/3 */ + if (p3 < 0.0) + TimesDeriv(&d_p3,&d_p3,-1.0); + PowDeriv(&d_p3,&d_p3,1.0/3.0); + p4 = (-s/2.0-p2); + TimesDeriv(&d_p4,&d_s,0.5); + PlusDeriv(&d_p4,&d_p4,&d_p2); + if (p4 < 0.0) + TimesDeriv(&d_p4,&d_p4,-1.0); /* this is fabs(p4) */ + p4 = exp(log(fabs(p4))/3.0); + PowDeriv(&d_p4,&d_p4,1.0/3.0); + + y3 = p3+p4-a/3.0; + TimesDeriv(&d_y3,&d_a,-1.0/3.0); + PlusDeriv(&d_y3,&d_y3,&d_p4); + PlusDeriv(&d_y3,&d_y3,&d_p3); + } + iknt = 0; + a3 = sqrt(a1*a1/4.0-b1+y3); + MultDeriv(&d_a3,&d_a1,&d_a1); + TimesDeriv(&d_a3,&d_a3,0.25); + PlusDeriv(&d_a3,&d_a3,&d_y3); + TimesDeriv(&d_dummy,&d_b1,-1.0); + PlusDeriv(&d_a3,&d_a3,&d_dummy); + SqrtDeriv(&d_a3,&d_a3); + + b3 = sqrt(y3*y3/4.0-d1); + MultDeriv(&d_b3,&d_y3,&d_y3); + TimesDeriv(&d_b3,&d_b3,0.25); + TimesDeriv(&d_dummy,&d_d1,-1.0); + PlusDeriv(&d_b3,&d_b3,&d_dummy); + SqrtDeriv(&d_b3,&d_b3); + + for(i = 1;i<=4;i++) { + a4[i-1] = a1/2.0+sig1[i-1]*a3; + TimesDeriv(&d_a4[i-1],&d_a1,0.5); + TimesDeriv(&d_dummy,&d_a3,sig1[i-1]); + PlusDeriv(&d_a4[i-1],&d_a4[i-1],&d_dummy); + b4[i-1] = y3/2.0+sig2[i-1]*b3; + TimesDeriv(&d_b4[i-1],&d_y3,0.5); + TimesDeriv(&d_dummy,&d_b3,sig2[i-1]); + PlusDeriv(&d_b4[i-1],&d_b4[i-1],&d_dummy); + delta4 = a4[i-1]*a4[i-1]/4.0-b4[i-1]; + MultDeriv(&d_delta4,&d_a4[i-1],&d_a4[i-1]); + TimesDeriv(&d_delta4,&d_delta4,0.25); + TimesDeriv(&d_dummy,&d_b4[i-1],-1.0); + PlusDeriv(&d_delta4,&d_delta4,&d_dummy); + + if (delta4 < 0) continue; + iknt = iknt+1; + tmp = sqrt(delta4); + SqrtDeriv(&d_tmp,&d_delta4); + x4[iknt-1] = -a4[i-1]/2.0+tmp; + TimesDeriv(&d_x4[iknt-1],&d_a4[i-1],-0.5); + PlusDeriv(&d_x4[iknt-1],&d_x4[iknt-1],&d_tmp); + iknt = iknt+1; + x4[iknt-1] = -a4[i-1]/2.0-tmp; + TimesDeriv(&d_x4[iknt-1],&d_a4[i-1],-0.5); + PlusDeriv(&d_x4[iknt-1],&d_x4[iknt-1],&d_tmp); + } + jknt = 0; + for(j = 1;j<=iknt;j++) { + if (x4[j-1] <= 0) continue; + /* XXX implement this sanely */ + poly4[j-1] = x4[j-1]*x4[j-1]*x4[j-1]*x4[j-1]+a1*x4[j-1]* + x4[j-1]*x4[j-1]; + CubeDeriv(&d_dummy,&d_x4[j-1]); + PlusDeriv(&d_poly4[j-1],&d_x4[j-1],&d_a1); + MultDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_dummy); + poly4[j-1] = poly4[j-1]+b1*x4[j-1]*x4[j-1]+c1*x4[j-1]+d1; + PlusDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_d1); + MultDeriv(&d_dummy,&d_b1,&d_x4[j-1]); + PlusDeriv(&d_dummy,&d_dummy,&d_c1); + MultDeriv(&d_dummy,&d_dummy,&d_x4[j-1]); + PlusDeriv(&d_poly4[j-1],&d_poly4[j-1],&d_dummy); + if (fabs(poly4[j-1]) > 1.0e-6) continue; + jknt = jknt+1; + if (jknt <= 1) { + xvalid = x4[j-1]; + EqualDeriv(&d_xvalid,&d_x4[j-1]); + } + if (x4[j-1] > xvalid) continue; + xvalid = x4[j-1]; + EqualDeriv(&d_xvalid,&d_x4[j-1]); + } + if (jknt > 0) { + vdsat = xvalid*xvalid-phiMinVbs; + MultDeriv(&d_vdsat,&d_xvalid,&d_xvalid); + TimesDeriv(&d_dummy,&d_phiMinVbs,-1.0); + PlusDeriv(&d_vdsat,&d_vdsat,&d_dummy); + } + } + /* + * evaluate effective channel length and its derivatives */ + if (lvds != 0.0) { + gammad = gamasd; + EqualDeriv(&d_gammad,&d_gamasd); + if ((lvbs-vdsat) <= 0) { + bsarg = sqrt(vdsat+phiMinVbs); + PlusDeriv(&d_bsarg,&d_vdsat,&d_phiMinVbs); + SqrtDeriv(&d_bsarg,&d_bsarg); + + } else { + bsarg = sphi/(1.0+0.5*(lvbs-vdsat)/here->MOS2tPhi); + TimesDeriv(&d_bsarg,&d_vdsat,-1.0); + d_bsarg.value += lvbs; d_bsarg.d1_r += 1.0; + TimesDeriv(&d_bsarg,&d_bsarg,0.5/here->MOS2tPhi); + d_bsarg.value += 1.0; + InvDeriv(&d_bsarg,&d_bsarg); + TimesDeriv(&d_bsarg,&d_bsarg,sphi); + + } + bodys = bsarg*bsarg*bsarg-sarg3; + CubeDeriv(&d_bodys,&d_bsarg); + TimesDeriv(&d_dummy,&d_sarg3,-1.0); + PlusDeriv(&d_bodys,&d_bodys,&d_dummy); + if (model->MOS2maxDriftVel <= 0) { + if (model->MOS2substrateDoping == 0.0) goto line610; + if (xlamda > 0.0) goto line610; + argv = (lvds-vdsat)/4.0; + TimesDeriv(&d_argv,&d_vdsat,-1.0); + d_argv.value += lvds; d_argv.d1_r += 1.0; + TimesDeriv(&d_argv,&d_argv,0.25); + + sargv = sqrt(1.0+argv*argv); + MultDeriv(&d_sargv,&d_argv,&d_argv); + d_sargv.value += 1.0; + SqrtDeriv(&d_sargv,&d_sargv); + arg = sqrt(argv+sargv); + PlusDeriv(&d_arg,&d_sargv,&d_argv); + SqrtDeriv(&d_arg,&d_arg); + xlfact = model->MOS2xd/(EffectiveLength*lvds); + EqualDeriv(&d_xlfact,&d_r); d_xlfact.value = lvds; + InvDeriv(&d_xlfact,&d_xlfact); + TimesDeriv(&d_xlfact,&d_xlfact,model->MOS2xd/EffectiveLength); + xlamda = xlfact*arg; + MultDeriv(&d_xlamda,&d_xlfact,&d_arg); + } else { + argv = (vgsx-vbin)/eta-vdsat; + TimesDeriv(&d_argv,&d_vbin,-1.0); + PlusDeriv(&d_argv,&d_argv,&d_vgsx); + TimesDeriv(&d_argv,&d_argv,1/eta); + TimesDeriv(&d_dummy,&d_vdsat,-1.0); + PlusDeriv(&d_argv,&d_argv,&d_dummy); + xdv = model->MOS2xd/sqrt(model->MOS2channelCharge); /*const*/ + xlv = model->MOS2maxDriftVel*xdv/(2.0*ueff); + InvDeriv(&d_xlv,&d_ueff); + TimesDeriv(&d_xlv,&d_xlv,model->MOS2maxDriftVel*xdv*0.5); + /* retained for historical interest + vqchan = argv-gammad*bsarg; + MultDeriv(&d_vqchan,&d_gammad,&d_bsarg); + TimesDeriv(&d_vqchan,&d_vqchan,-1); + PlusDeriv(&d_vqchan,&d_vqchan,&d_argv); + */ + /* gammad = gamasd + vl = model->MOS2maxDriftVel*EffectiveLength;const*/ + if (model->MOS2substrateDoping == 0.0) goto line610; + if (xlamda > 0.0) goto line610; + argv = lvds-vdsat; + TimesDeriv(&d_argv,&d_vdsat,-1.0); + d_argv.value += lvds; + d_argv.d1_r += 1.0; + if (argv < 0.0) + EqualDeriv(&d_argv,&d_zero); + argv = MAX(argv,0.0); + xls = sqrt(xlv*xlv+argv); + MultDeriv(&d_xls,&d_xlv,&d_xlv); + PlusDeriv(&d_xls,&d_xls,&d_argv); + SqrtDeriv(&d_xls,&d_xls); + /* dummy9 = xlv*xlv + argv */ + xlfact = xdv/(EffectiveLength*lvds); + EqualDeriv(&d_xlfact,&d_r); + d_xlfact.value += lvds; + InvDeriv(&d_xlfact,&d_xlfact); + TimesDeriv(&d_xlfact,&d_xlfact,xdv/EffectiveLength); + xlamda = xlfact*(xls-xlv); + TimesDeriv(&d_xlamda,&d_xlv,-1.0); + PlusDeriv(&d_xlamda,&d_xlamda,&d_xls); + MultDeriv(&d_xlamda,&d_xlamda,&d_xlfact); + + } + } +line610: + + /* + * limit channel shortening at punch-through */ + xwb = model->MOS2xd*sbiarg; /*const*/ + xld = EffectiveLength-xwb; /*const*/ + clfact = 1.0-xlamda*lvds; + EqualDeriv(&d_clfact,&d_r); d_clfact.value = lvds; + d_clfact.d1_r = -1; + MultDeriv(&d_clfact,&d_clfact,&d_xlamda); + d_clfact.value += 1.0; + xleff = EffectiveLength*clfact; + TimesDeriv(&d_xleff,&d_clfact,EffectiveLength); + deltal = xlamda*lvds*EffectiveLength; + EqualDeriv(&d_delta1,&d_r); + d_delta1.value = EffectiveLength*lvds; + d_delta1.d1_r = EffectiveLength; + MultDeriv(&d_delta1,&d_delta1,&d_xlamda); + + + if (model->MOS2substrateDoping == 0.0) xwb = 0.25e-6; + if (xleff < xwb) { + xleff = xwb/(1.0+(deltal-xld)/xwb); + EqualDeriv(&d_xleff,&d_delta1);d_xleff.value -= xld; + TimesDeriv(&d_xleff,&d_xleff,1/xwb);d_xleff.value += 1.0; + InvDeriv(&d_xleff,&d_xleff); + TimesDeriv(&d_xleff,&d_xleff,xwb); + clfact = xleff/EffectiveLength; + TimesDeriv(&d_clfact,&d_xleff,1/EffectiveLength); + + /* dfact = xleff*xleff/(xwb*xwb); */ + } + /* + * evaluate effective beta (effective kp) + */ + beta1 = Beta*ufact/clfact; + DivDeriv(&d_beta1,&d_ufact,&d_clfact); + TimesDeriv(&d_beta1,&d_beta1,Beta); + /* + * test for mode of operation and branch appropriately */ + gammad = gamasd; + EqualDeriv(&d_gammad,&d_gamasd); + if (lvds <= 1.0e-10) { + if (lvgs <= von) { + if ((model->MOS2fastSurfaceStateDensity == 0.0) || + (OxideCap == 0.0)) { + here->MOS2gds = 0.0; + d_cdrain.d1_q = 0.0; + d_cdrain.d2_q2 = 0.0; + d_cdrain.d3_q3 = 0.0; + goto line1050; + } + + here->MOS2gds = beta1*(von-vbin-gammad*sarg)*exp(argg* + (lvgs-von)); + MultDeriv(&d_dummy,&d_gammad,&d_sarg); + PlusDeriv(&d_dummy,&d_dummy,&d_vbin); + TimesDeriv(&d_dummy,&d_dummy,-1.0); + PlusDeriv(&d_dummy,&d_dummy,&d_von); + MultDeriv(&d_mos2gds,&d_beta1,&d_dummy); + TimesDeriv(&d_dummy,&d_von,-1.0); + PlusDeriv(&d_dummy,&d_dummy,&d_p); + d_dummy.value += lvgs; + MultDeriv(&d_dummy,&d_dummy,&d_argg); + ExpDeriv(&d_dummy,&d_dummy); + MultDeriv(&d_mos2gds,&d_mos2gds,&d_dummy); + d_cdrain.d1_r = d_mos2gds.value; + d_cdrain.d2_r2 = d_mos2gds.d1_r; + d_cdrain.d3_r3 = d_mos2gds.d2_r2; + /* dummy1 = von - vbin - gamasd*sarg */ + goto line1050; + } + + + here->MOS2gds = beta1*(lvgs-vbin-gammad*sarg); + MultDeriv(&d_mos2gds,&d_gammad,&d_sarg); + PlusDeriv(&d_mos2gds,&d_mos2gds,&d_vbin); + TimesDeriv(&d_mos2gds,&d_mos2gds,-1.0); + MultDeriv(&d_mos2gds,&d_mos2gds,&d_beta1); + d_cdrain.d1_r = d_mos2gds.value; + d_cdrain.d2_r2 = d_mos2gds.d1_r; + d_cdrain.d3_r3 = d_mos2gds.d2_r2; + + goto line1050; + } + + if (lvgs > von) goto line900; + /* + * subthreshold region */ + if (vdsat <= 0) { + here->MOS2gds = 0.0; + d_cdrain.d1_r = 0.0; + d_cdrain.d2_r2 = 0.0; + d_cdrain.d3_r3 = 0.0; + /* if (lvgs > vth) goto doneval; */ + goto line1050; + } + vdson = MIN(vdsat,lvds); + if (vdsat <= lvds) { + EqualDeriv(&d_vdson,&d_vdsat); + } else { + EqualDeriv(&d_vdson,&d_r); + d_vdson.value = lvds; + } + if (lvds > vdsat) { + barg = bsarg; + EqualDeriv(&d_barg,&d_bsarg); + body = bodys; + EqualDeriv(&d_body,&d_bodys); + } + cdson = beta1*((von-vbin-eta*vdson*0.5)*vdson-gammad*body/1.5); + MultDeriv(&d_dummy,&d_gammad,&d_body); + TimesDeriv(&d_cdson,&d_dummy,-1/1.5); + TimesDeriv(&d_dummy,&d_vdson,0.5*eta); + PlusDeriv(&d_dummy,&d_dummy,&d_vbin); + TimesDeriv(&d_dummy,&d_dummy,-1.0); + PlusDeriv(&d_dummy,&d_dummy,&d_von); + MultDeriv(&d_dummy,&d_dummy,&d_vdson); + PlusDeriv(&d_dummy,&d_dummy,&d_cdson); + MultDeriv(&d_cdson,&d_dummy,&d_beta1); + expg = exp(argg*(lvgs-von)); + TimesDeriv(&d_expg,&d_von,-1.0); + d_expg.value += lvgs; + d_expg.d1_p += 1.0; + MultDeriv(&d_expg,&d_expg,&d_argg); + ExpDeriv(&d_expg,&d_expg); + + cdrain = cdson*expg; + MultDeriv(&d_cdrain,&d_cdson,&d_expg); + /* + gmw = cdrain*argg; + here->MOS2gm = gmw; + tmp = gmw*(lvgs-von)/xn; + */ + goto doneval; + +line900: + if (lvds <= vdsat) { + /* + * linear region */ + cdrain = beta1*((lvgs-vbin-eta*lvds/2.0)*lvds-gammad*body/1.5); + MultDeriv(&d_dummy,&d_gammad,&d_body); + TimesDeriv(&d_dummy,&d_dummy,-1/1.5); + EqualDeriv(&d_cdrain,&d_r); + d_cdrain.value = eta*lvds*0.5; + d_cdrain.d1_r = 0.5*eta; + PlusDeriv(&d_cdrain,&d_cdrain,&d_vbin); + TimesDeriv(&d_cdrain,&d_cdrain,-1.0); + d_cdrain.value += lvgs; + d_cdrain.d1_p += 1.0; + EqualDeriv(&d_dummy,&d_r); + d_dummy.value = lvds; + MultDeriv(&d_cdrain,&d_cdrain,&d_dummy); + MultDeriv(&d_dummy,&d_gammad,&d_body); + TimesDeriv(&d_dummy,&d_dummy,-1/1.5); + PlusDeriv(&d_cdrain,&d_cdrain,&d_dummy); + MultDeriv(&d_cdrain,&d_cdrain,&d_beta1); + } else { + /* + * saturation region */ + cdrain = beta1*((lvgs-vbin-eta* + vdsat/2.0)*vdsat-gammad*bodys/1.5); + TimesDeriv(&d_cdrain,&d_vdsat,0.5*eta); + PlusDeriv(&d_cdrain,&d_cdrain,&d_vbin); + TimesDeriv(&d_cdrain,&d_cdrain,-1.0); + d_cdrain.value += lvgs; + d_cdrain.d1_p += 1.0; + MultDeriv(&d_cdrain,&d_cdrain,&d_vdsat); + MultDeriv(&d_dummy,&d_gammad,&d_bodys); + TimesDeriv(&d_dummy,&d_dummy,-1/1.5); + PlusDeriv(&d_cdrain,&d_cdrain,&d_dummy); + MultDeriv(&d_cdrain,&d_cdrain,&d_beta1); + } + /* + * compute charges for "on" region */ + goto doneval; + /* + * finish special cases */ +line1050: + cdrain = 0.0; + here->MOS2gm = 0.0; + here->MOS2gmbs = 0.0; +d_cdrain.value = 0.0; +d_cdrain.d1_p = 0.0; +d_cdrain.d1_q = 0.0; +d_cdrain.d2_p2 = 0.0; +d_cdrain.d2_q2 = 0.0; +d_cdrain.d2_pq = 0.0; +d_cdrain.d2_qr = 0.0; +d_cdrain.d2_pr = 0.0; +d_cdrain.d3_p3 = 0.0; +d_cdrain.d3_q3 = 0.0; +d_cdrain.d3_p2r = 0.0; +d_cdrain.d3_p2q = 0.0; +d_cdrain.d3_q2r = 0.0; +d_cdrain.d3_pq2 = 0.0; +d_cdrain.d3_pr2 = 0.0; +d_cdrain.d3_qr2 = 0.0; +d_cdrain.d3_pqr = 0.0; +} + + /* + * finished + */ + +/*================HERE=================*/ +doneval: + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + /* + * now we do the hard part of the bulk-drain and bulk-source + * diode - we evaluate the non-linear capacitance and + * charge + * the basic equations are not hard, but the implementation + * is somewhat long in an attempt to avoid log/exponential + * evaluations + */ + /* + * charge storage elements * + *.. bulk-drain and bulk-source depletion capacitances + */ + if (vbs < here->MOS2tDepCap){ + arg=1-vbs/here->MOS2tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading * coefficients of .5, and sqrt is MUCH faster than an * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS2bulkJctBotGradingCoeff == + model->MOS2bulkJctSideGradingCoeff) { + if(model->MOS2bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS2bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS2bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS2bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS2bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS2bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + lcapbs=here->MOS2Cbs*sarg+ + here->MOS2Cbssw*sargsw; + lcapbs2 = model->MOS2type*0.5/here->MOS2tBulkPot*( + here->MOS2Cbs*model->MOS2bulkJctBotGradingCoeff* + sarg/arg + here->MOS2Cbssw* + model->MOS2bulkJctSideGradingCoeff*sargsw/arg); + lcapbs3 = here->MOS2Cbs*sarg* + model->MOS2bulkJctBotGradingCoeff* + (model->MOS2bulkJctBotGradingCoeff+1); + lcapbs3 += here->MOS2Cbssw*sargsw* + model->MOS2bulkJctSideGradingCoeff* + (model->MOS2bulkJctSideGradingCoeff+1); + lcapbs3 = lcapbs3/(6*here->MOS2tBulkPot* + here->MOS2tBulkPot*arg*arg); + } else { + /* *(ckt->CKTstate0 + here->MOS2qbs)= here->MOS2f4s + + vbs*(here->MOS2f2s+vbs*(here->MOS2f3s/2));*/ + lcapbs=here->MOS2f2s+here->MOS2f3s*vbs; + lcapbs2 = 0.5*here->MOS2f3s; + lcapbs3 = 0; + } + if (vbd < here->MOS2tDepCap) { + arg=1-vbd/here->MOS2tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading * coefficients of .5, and sqrt is MUCH faster than an * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS2bulkJctBotGradingCoeff == .5 && + model->MOS2bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS2bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS2bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS2bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS2bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + lcapbd=here->MOS2Cbd*sarg+ + here->MOS2Cbdsw*sargsw; + lcapbd2 = model->MOS2type*0.5/here->MOS2tBulkPot*( + here->MOS2Cbd*model->MOS2bulkJctBotGradingCoeff* + sarg/arg + here->MOS2Cbdsw* + model->MOS2bulkJctSideGradingCoeff*sargsw/arg); + lcapbd3 = here->MOS2Cbd*sarg* + model->MOS2bulkJctBotGradingCoeff* + (model->MOS2bulkJctBotGradingCoeff+1); + lcapbd3 += here->MOS2Cbdsw*sargsw* + model->MOS2bulkJctSideGradingCoeff* + (model->MOS2bulkJctSideGradingCoeff+1); + lcapbd3 = lcapbd3/(6*here->MOS2tBulkPot* + here->MOS2tBulkPot*arg*arg); + } else { + lcapbd=here->MOS2f2d + vbd * here->MOS2f3d; + lcapbd2=0.5*here->MOS2f3d; + lcapbd3=0; + } + /* + * meyer's capacitor model */ + /* + * the meyer capacitance equations are in DEVqmeyer + * these expressions are derived from those equations. + * these expressions are incorrect; they assume just one + * controlling variable for each charge storage element + * while actually there are several; the MOS2 small + * signal ac linear model is also wrong because it + * ignores controlled capacitive elements. these can be + * corrected (as can the linear ss ac model) if the + * expressions for the charge are available + */ + + +{ + + + double phi; + double cox; + double vddif; + double vddif1; + double vddif2; + /* von, vgst and vdsat have already been adjusted for + possible source-drain interchange */ + + + + phi = here->MOS2tPhi; + cox = OxideCap; + if (vgst <= -phi) { + lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else if (vgst <= -phi/2) { + lcapgb2= -cox/(4*phi); + lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else if (vgst <= 0) { + lcapgb2= -cox/(4*phi); + lcapgb3=lcapgs3=lcapgd2=lcapgd3=0; + lcapgs2 = cox/(3*phi); + } else { /* the MOS2modes are around because + vds has not been adjusted */ + if (vdsat <= here->MOS2mode*vds) { + lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else { + vddif = 2.0*vdsat-here->MOS2mode*vds; + vddif1 = vdsat-here->MOS2mode*vds/*-1.0e-12*/; + vddif2 = vddif*vddif; + lcapgd2 = -vdsat*here->MOS2mode*vds*cox/(3*vddif*vddif2); + lcapgd3 = - here->MOS2mode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2); + lcapgs2 = -vddif1*here->MOS2mode*vds*cox/(3*vddif*vddif2); + lcapgs3 = - here->MOS2mode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2); + lcapgb2=lcapgb3=0; + } + } + } + + /* the b-s and b-d diodes need no processing ... */ + here->capbs2 = lcapbs2; + here->capbs3 = lcapbs3; + here->capbd2 = lcapbd2; + here->capbd3 = lcapbd3; + here->gbs2 = lgbs2; + here->gbs3 = lgbs3; + here->gbd2 = lgbd2; + here->gbd3 = lgbd3; + here->capgb2 = model->MOS2type*lcapgb2; + here->capgb3 = lcapgb3; + /* + * process to get Taylor coefficients, taking into * account type and mode. + */ +gm2 = d_cdrain.d2_p2; +gb2 = d_cdrain.d2_q2; +gds2 = d_cdrain.d2_r2; +gmb = d_cdrain.d2_pq; +gbds = d_cdrain.d2_qr; +gmds = d_cdrain.d2_pr; +gm3 = d_cdrain.d3_p3; +gb3 = d_cdrain.d3_q3; +gds3 = d_cdrain.d3_r3; +gm2ds = d_cdrain.d3_p2r; +gm2b = d_cdrain.d3_p2q; +gb2ds = d_cdrain.d3_q2r; +gmb2 = d_cdrain.d3_pq2; +gmds2 = d_cdrain.d3_pr2; +gbds2 = d_cdrain.d3_qr2; +gmbds = d_cdrain.d3_pqr; + + if (here->MOS2mode == 1) + { + /* normal mode - no source-drain interchange */ + + here->cdr_x2 = gm2; + here->cdr_y2 = gb2; + here->cdr_z2 = gds2; + here->cdr_xy = gmb; + here->cdr_yz = gbds; + here->cdr_xz = gmds; + here->cdr_x3 = gm3; + here->cdr_y3 = gb3; + here->cdr_z3 = gds3; + here->cdr_x2z = gm2ds; + here->cdr_x2y = gm2b; + here->cdr_y2z = gb2ds; + here->cdr_xy2 = gmb2; + here->cdr_xz2 = gmds2; + here->cdr_yz2 = gbds2; + here->cdr_xyz = gmbds; + + /* the gate caps have been divided and made into Taylor coeffs., but not adjusted for type */ + + here->capgs2 = model->MOS2type*lcapgs2; + here->capgs3 = lcapgs3; + here->capgd2 = model->MOS2type*lcapgd2; + here->capgd3 = lcapgd3; +} else { + /* + * inverse mode - source and drain interchanged */ +here->cdr_x2 = -gm2; +here->cdr_y2 = -gb2; +here->cdr_z2 = -(gm2 + gb2 + gds2 + 2*(gmb + gmds + gbds)); +here->cdr_xy = -gmb; +here->cdr_yz = gmb + gb2 + gbds; +here->cdr_xz = gm2 + gmb + gmds; +here->cdr_x3 = -gm3; +here->cdr_y3 = -gb3; +here->cdr_z3 = gm3 + gb3 + gds3 + + 3*(gm2b + gm2ds + gmb2 + gb2ds + gmds2 + gbds2) + 6*gmbds ; +here->cdr_x2z = gm3 + gm2b + gm2ds; +here->cdr_x2y = -gm2b; +here->cdr_y2z = gmb2 + gb3 + gb2ds; +here->cdr_xy2 = -gmb2; +here->cdr_xz2 = -(gm3 + 2*(gm2b + gm2ds + gmbds) + + gmb2 + gmds2); +here->cdr_yz2 = -(gb3 + 2*(gmb2 + gb2ds + gmbds) + + gm2b + gbds2); +here->cdr_xyz = gm2b + gmb2 + gmbds; + + here->capgs2 = model->MOS2type*lcapgd2; + here->capgs3 = lcapgd3; + + here->capgd2 = model->MOS2type*lcapgs2; + here->capgd3 = lcapgs3; + +} + +/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ + +here->cdr_x2 = 0.5*model->MOS2type*here->cdr_x2; +here->cdr_y2 = 0.5*model->MOS2type*here->cdr_y2; +here->cdr_z2 = 0.5*model->MOS2type*here->cdr_z2; +here->cdr_xy = model->MOS2type*here->cdr_xy; +here->cdr_yz = model->MOS2type*here->cdr_yz; +here->cdr_xz = model->MOS2type*here->cdr_xz; +here->cdr_x3 = here->cdr_x3/6.; +here->cdr_y3 = here->cdr_y3/6.; +here->cdr_z3 = here->cdr_z3/6.; +here->cdr_x2z = 0.5*here->cdr_x2z; +here->cdr_x2y = 0.5*here->cdr_x2y; +here->cdr_y2z = 0.5*here->cdr_y2z; +here->cdr_xy2 = 0.5*here->cdr_xy2; +here->cdr_xz2 = 0.5*here->cdr_xz2; +here->cdr_yz2 = 0.5*here->cdr_yz2; + + + } + } + return(OK); + } diff --git a/src/spicelib/devices/mos2/mos2ext.h b/src/spicelib/devices/mos2/mos2ext.h new file mode 100644 index 000000000..fd472fc5b --- /dev/null +++ b/src/spicelib/devices/mos2/mos2ext.h @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int MOS2acLoad(GENmodel*,CKTcircuit*); +extern int MOS2ask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int MOS2mAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int MOS2convTest(GENmodel*,CKTcircuit*); +extern int MOS2delete(GENmodel*,IFuid,GENinstance**); +extern void MOS2destroy(GENmodel**); +extern int MOS2getic(GENmodel*,CKTcircuit*); +extern int MOS2load(GENmodel*,CKTcircuit*); +extern int MOS2mDelete(GENmodel**,IFuid,GENmodel*); +extern int MOS2mParam(int,IFvalue*,GENmodel*); +extern int MOS2param(int,IFvalue*,GENinstance*,IFvalue*); +extern int MOS2pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int MOS2sAcLoad(GENmodel*,CKTcircuit*); +extern int MOS2sLoad(GENmodel*,CKTcircuit*); +extern void MOS2sPrint(GENmodel*,CKTcircuit*); +extern int MOS2sSetup(SENstruct*,GENmodel*); +extern int MOS2sUpdate(GENmodel*,CKTcircuit*); +extern int MOS2setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int MOS2unsetup(GENmodel*,CKTcircuit*); +extern int MOS2temp(GENmodel*,CKTcircuit*); +extern int MOS2trunc(GENmodel*,CKTcircuit*,double*); +extern int MOS2disto(int,GENmodel*,CKTcircuit*); +extern int MOS2noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); +#else /* stdc */ +extern int MOS2acLoad(); +extern int MOS2ask(); +extern int MOS2mAsk(); +extern int MOS2convTest(); +extern int MOS2delete(); +extern void MOS2destroy(); +extern int MOS2getic(); +extern int MOS2load(); +extern int MOS2mDelete(); +extern int MOS2mParam(); +extern int MOS2param(); +extern int MOS2pzLoad(); +extern int MOS2sAcLoad(); +extern int MOS2sLoad(); +extern void MOS2sPrint(); +extern int MOS2sSetup(); +extern int MOS2sUpdate(); +extern int MOS2setup(); +extern int MOS2unsetup(); +extern int MOS2temp(); +extern int MOS2trunc(); +extern int MOS2disto(); +extern int MOS2noise(); +#endif /* stdc */ diff --git a/src/spicelib/devices/mos2/mos2ic.c b/src/spicelib/devices/mos2/mos2ic.c new file mode 100644 index 000000000..00b1ed27d --- /dev/null +++ b/src/spicelib/devices/mos2/mos2ic.c @@ -0,0 +1,50 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS2getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS2model *model = (MOS2model *)inModel; + MOS2instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->MOS2nextModel) { + for(here = model->MOS2instances; here ; here = here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + if(!here->MOS2icVBSGiven) { + here->MOS2icVBS = + *(ckt->CKTrhs + here->MOS2bNode) - + *(ckt->CKTrhs + here->MOS2sNode); + } + if(!here->MOS2icVDSGiven) { + here->MOS2icVDS = + *(ckt->CKTrhs + here->MOS2dNode) - + *(ckt->CKTrhs + here->MOS2sNode); + } + if(!here->MOS2icVGSGiven) { + here->MOS2icVGS = + *(ckt->CKTrhs + here->MOS2gNode) - + *(ckt->CKTrhs + here->MOS2sNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2itf.h b/src/spicelib/devices/mos2/mos2itf.h new file mode 100644 index 000000000..7a57d8332 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2itf.h @@ -0,0 +1,101 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_mos2 + +#ifndef DEV_MOS2 +#define DEV_MOS2 + +#include "mos2ext.h" +extern IFparm MOS2pTable[ ]; +extern IFparm MOS2mPTable[ ]; +extern char *MOS2names[ ]; +extern int MOS2pTSize; +extern int MOS2mPTSize; +extern int MOS2nSize; +extern int MOS2iSize; +extern int MOS2mSize; + +SPICEdev MOS2info = { + { + "Mos2", + "Level 2 MOSfet model with Meyer capacitance model", + + &MOS2nSize, + &MOS2nSize, + MOS2names, + + &MOS2pTSize, + MOS2pTable, + + &MOS2mPTSize, + MOS2mPTable, + DEV_DEFAULT + }, + + MOS2param, + MOS2mParam, + MOS2load, + MOS2setup, + MOS2unsetup, + MOS2setup, + MOS2temp, + MOS2trunc, + NULL, + MOS2acLoad, + NULL, + MOS2destroy, +#ifdef DELETES + MOS2mDelete, + MOS2delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + MOS2getic, + MOS2ask, + MOS2mAsk, +#ifdef AN_pz + MOS2pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + MOS2convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + +#ifdef AN_sense2 + MOS2sSetup, + MOS2sLoad, + MOS2sUpdate, + MOS2sAcLoad, + MOS2sPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ +#ifdef AN_disto + MOS2disto, +#else /* AN_disto */ + NULL, +#endif /* AN_disto */ +#ifdef AN_noise + MOS2noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &MOS2iSize, + &MOS2mSize +}; + + +#endif +#endif diff --git a/src/spicelib/devices/mos2/mos2load.c b/src/spicelib/devices/mos2/mos2load.c new file mode 100644 index 000000000..8115d4ee5 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2load.c @@ -0,0 +1,1424 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "cktdefs.h" +#include "mos2defs.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* assuming silicon - make definition for epsilon of silicon */ +#define EPSSIL (11.7 * 8.854214871e-12) + +static double sig1[4] = {1.0, -1.0, 1.0, -1.0}; +static double sig2[4] = {1.0, 1.0,-1.0, -1.0}; + +int +MOS2load(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + int error; + double Beta; + double DrainSatCur; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double arg; + double cbhat; + double cdhat; + double cdrain; + double cdreq; + double ceq; + double ceqbd; + double ceqbs; + double ceqgb; + double ceqgd; + double ceqgs; + double delvbd; + double delvbs; + double delvds; + double delvgd; + double delvgs; + double evbd; + double evbs; + double gcgb; + double gcgd; + double gcgs; + double geq; + double sarg; + double sargsw; + double vbd; + double vbs; + double vds; + double vdsat; + double vgb1; + double vgb; + double vgd1; + double vgd; + double vgdo; + double vgs1; + double vgs; + double von; + double vt; /* K * T / Q */ + double xfact; + double capgs; /* total gate-source capacitance */ + double capgd; /* total gate-drain capacitance */ + double capgb; /* total gate-bulk capacitance */ + int xnrm; + int xrev; + int Check; +#ifndef NOBYPASS + double tempv; +#endif /*NOBYPASS*/ +#ifdef CAPBYPASS + int senflag; +#endif /* CAPBYPASS */ + int SenCond=0; + +#ifdef CAPBYPASS + senflag = 0; + if(ckt->CKTsenInfo){ + if(ckt->CKTsenInfo->SENstatus == PERTURBATION){ + if((ckt->CKTsenInfo->SENmode == ACSEN)|| + (ckt->CKTsenInfo->SENmode == TRANSEN)){ + senflag = 1; + } + } + } +#endif /* CAPBYPASS */ + + + /* loop through all the MOS2 device models */ + for( ; model != NULL; model = model->MOS2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + vt = CONSTKoverQ * here->MOS2temp; + Check=1; + if(ckt->CKTsenInfo){ +#ifdef SENSDEBUG + printf("MOS2load %s\n",here->MOS2name); +#endif /* SENSDEBUG */ + + if(ckt->CKTsenInfo->SENstatus == PERTURBATION) { + if(here->MOS2senPertFlag == OFF)continue; + } + SenCond = here->MOS2senPertFlag; + + } + + EffectiveLength=here->MOS2l - 2*model->MOS2latDiff; + if( (here->MOS2tSatCurDens == 0) || + (here->MOS2drainArea == 0) || + (here->MOS2sourceArea == 0)) { + DrainSatCur = here->MOS2tSatCur; + SourceSatCur = here->MOS2tSatCur; + } else { + DrainSatCur = here->MOS2tSatCurDens * + here->MOS2drainArea; + SourceSatCur = here->MOS2tSatCurDens * + here->MOS2sourceArea; + } + GateSourceOverlapCap = model->MOS2gateSourceOverlapCapFactor * + here->MOS2w; + GateDrainOverlapCap = model->MOS2gateDrainOverlapCapFactor * + here->MOS2w; + GateBulkOverlapCap = model->MOS2gateBulkOverlapCapFactor * + EffectiveLength; + Beta = here->MOS2tTransconductance * here->MOS2w/EffectiveLength; + OxideCap = model->MOS2oxideCapFactor * EffectiveLength * + here->MOS2w; + + + if(SenCond){ +#ifdef SENSDEBUG + printf("MOS2senPertFlag = ON \n"); +#endif /* SENSDEBUG */ + if((ckt->CKTsenInfo->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) { + vgs = *(ckt->CKTstate1 + here->MOS2vgs); + vds = *(ckt->CKTstate1 + here->MOS2vds); + vbs = *(ckt->CKTstate1 + here->MOS2vbs); + vbd = *(ckt->CKTstate1 + here->MOS2vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } + else if (ckt->CKTsenInfo->SENmode == ACSEN){ + vgb = model->MOS2type * ( + *(ckt->CKTrhsOp+here->MOS2gNode) - + *(ckt->CKTrhsOp+here->MOS2bNode)); + vbs = *(ckt->CKTstate0 + here->MOS2vbs); + vbd = *(ckt->CKTstate0 + here->MOS2vbd); + vgd = vgb + vbd ; + vgs = vgb + vbs ; + vds = vbs - vbd ; + } + else{ + vgs = *(ckt->CKTstate0 + here->MOS2vgs); + vds = *(ckt->CKTstate0 + here->MOS2vds); + vbs = *(ckt->CKTstate0 + here->MOS2vbs); + vbd = *(ckt->CKTstate0 + here->MOS2vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } +#ifdef SENSDEBUG + printf(" vbs = %.7e ,vbd = %.7e,vgb = %.7e\n",vbs,vbd,vgb); + printf(" vgs = %.7e ,vds = %.7e,vgd = %.7e\n",vgs,vds,vgd); +#endif /* SENSDEBUG */ + goto next1; + } + + + if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED |MODEINITSMSIG + | MODEINITTRAN)) || + ( (ckt->CKTmode & MODEINITFIX) && (!here->MOS2off) ) ) { +#ifndef PREDICTOR + if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + + /* predictor step */ + + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->MOS2vbs) = + *(ckt->CKTstate1 + here->MOS2vbs); + vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS2vbs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS2vbs))); + *(ckt->CKTstate0 + here->MOS2vgs) = + *(ckt->CKTstate1 + here->MOS2vgs); + vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS2vgs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS2vgs))); + *(ckt->CKTstate0 + here->MOS2vds) = + *(ckt->CKTstate1 + here->MOS2vds); + vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS2vds)) + -(xfact * (*(ckt->CKTstate2 + here->MOS2vds))); + *(ckt->CKTstate0 + here->MOS2vbd) = + *(ckt->CKTstate0 + here->MOS2vbs)- + *(ckt->CKTstate0 + here->MOS2vds); + } else { +#endif /* PREDICTOR */ + + /* general iteration */ + + + vbs = model->MOS2type * ( + *(ckt->CKTrhsOld+here->MOS2bNode) - + *(ckt->CKTrhsOld+here->MOS2sNodePrime)); + vgs = model->MOS2type * ( + *(ckt->CKTrhsOld+here->MOS2gNode) - + *(ckt->CKTrhsOld+here->MOS2sNodePrime)); + vds = model->MOS2type * ( + *(ckt->CKTrhsOld+here->MOS2dNodePrime) - + *(ckt->CKTrhsOld+here->MOS2sNodePrime)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + + /* now some common crunching for some more useful quantities */ + + + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS2vgs) - + *(ckt->CKTstate0 + here->MOS2vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS2vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS2vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS2vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS2vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + if (here->MOS2mode >= 0) { + cdhat= + here->MOS2cd - + here->MOS2gbd * delvbd + + here->MOS2gmbs * delvbs + + here->MOS2gm * delvgs + + here->MOS2gds * delvds ; + } else { + cdhat= + here->MOS2cd + + ( here->MOS2gmbs - + here->MOS2gbd) * delvbd - + here->MOS2gm * delvgd + + here->MOS2gds * delvds ; + } + cbhat= + here->MOS2cbs + + here->MOS2cbd + + here->MOS2gbd * delvbd + + here->MOS2gbs * delvbs ; + + + /* now lets see if we can bypass (ugh) */ + /* the following massive if should all be one + * single compound if statement, but most compilers + * can't handle it in one piece, so it is broken up + * into several stages here + */ +#ifndef NOBYPASS + tempv = MAX(fabs(cbhat),fabs(here->MOS2cbs+here->MOS2cbd))+ + ckt->CKTabstol; + if((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG) + )) && (ckt->CKTbypass) ) + if ( (fabs(cbhat-(here->MOS2cbs + here->MOS2cbd)) + < ckt->CKTreltol * tempv)) + if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS2vbs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS2vbd)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->MOS2vgs)))+ + ckt->CKTvoltTol)) ) + if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->MOS2vds)))+ + ckt->CKTvoltTol)) ) + if( (fabs(cdhat- here->MOS2cd) < + ckt->CKTreltol * MAX(fabs(cdhat),fabs( + here->MOS2cd)) + ckt->CKTabstol) ) { + /* bypass code */ + /* nothing interesting has changed since last + * iteration on this device, so we just + * copy all the values computed last iteration + * out and keep going + */ + vbs = *(ckt->CKTstate0 + here->MOS2vbs); + vbd = *(ckt->CKTstate0 + here->MOS2vbd); + vgs = *(ckt->CKTstate0 + here->MOS2vgs); + vds = *(ckt->CKTstate0 + here->MOS2vds); + vgd = vgs - vds; + vgb = vgs - vbs; + cdrain = here->MOS2mode * (here->MOS2cd + here->MOS2cbd); + if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { + capgs = ( *(ckt->CKTstate0 + here->MOS2capgs)+ + *(ckt->CKTstate1 + here->MOS2capgs)+ + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0 + here->MOS2capgd)+ + *(ckt->CKTstate1 + here->MOS2capgd)+ + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0 + here->MOS2capgb)+ + *(ckt->CKTstate1 + here->MOS2capgb)+ + GateBulkOverlapCap ); + if(ckt->CKTsenInfo){ + here->MOS2cgs = capgs; + here->MOS2cgd = capgd; + here->MOS2cgb = capgb; + } + } + goto bypass; + } +#endif /*NOBYPASS*/ + /* ok - bypass is out, do it the hard way */ + + von = model->MOS2type * here->MOS2von; + /* + * limiting + * We want to keep device voltages from changing + * so fast that the exponentials churn out overflows + * and similar rudeness + */ + if(*(ckt->CKTstate0 + here->MOS2vds) >=0) { + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS2vgs) + ,von); + vds = vgs - vgd; + vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS2vds)); + vgd = vgs - vds; + } else { + vgd = DEVfetlim(vgd,vgdo,von); + vds = vgs - vgd; + if(!(ckt->CKTfixLimit)) { + vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + + here->MOS2vds))); + } + vgs = vgd + vds; + } + if(vds >= 0) { + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS2vbs), + vt,here->MOS2sourceVcrit,&Check); + vbd = vbs-vds; + } else { + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS2vbd), + vt,here->MOS2drainVcrit,&Check); + vbs = vbd + vds; + } + } else { + /* ok - not one of the simple cases, so we have to + * look at other possibilities + */ + + if((ckt->CKTmode & MODEINITJCT) && !here->MOS2off) { + vds= model->MOS2type * here->MOS2icVDS; + vgs= model->MOS2type * here->MOS2icVGS; + vbs= model->MOS2type * here->MOS2icVBS; + if((vds==0) && (vgs==0) && (vbs==0) && + ((ckt->CKTmode & + (MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || + (!(ckt->CKTmode & MODEUIC)))) { + vbs = -1; + vgs = model->MOS2type * here->MOS2tVto; + vds = 0; + } + } else { + vbs=vgs=vds=0; + } + } + + /* now all the preliminaries are over - we can start doing the + * real work + */ + + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + /* bulk-source and bulk-drain doides + * here we just evaluate the ideal diode current and the + * correspoinding derivative (conductance). + */ + +next1: if(vbs <= 0) { + here->MOS2gbs = SourceSatCur/vt; + here->MOS2cbs = here->MOS2gbs*vbs; + here->MOS2gbs += ckt->CKTgmin; + } else { + evbs = exp(vbs/vt); + here->MOS2gbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + here->MOS2cbs = SourceSatCur * (evbs-1); + } + if(vbd <= 0) { + here->MOS2gbd = DrainSatCur/vt; + here->MOS2cbd = here->MOS2gbd *vbd; + here->MOS2gbd += ckt->CKTgmin; + } else { + evbd = exp(vbd/vt); + here->MOS2gbd = DrainSatCur*evbd/vt +ckt->CKTgmin; + here->MOS2cbd = DrainSatCur *(evbd-1); + } + if(vds >= 0) { + /* normal mode */ + here->MOS2mode = 1; + } else { + /* inverse mode */ + here->MOS2mode = -1; + } + { + /* moseq2(vds,vbs,vgs,gm,gds,gmbs,qg,qc,qb, + * cggb,cgdb,cgsb,cbgb,cbdb,cbsb) + */ + /* note: cgdb, cgsb, cbdb, cbsb never used */ + + /* + * this routine evaluates the drain current, its derivatives and + * the charges associated with the gate, channel and bulk + * for mosfets + * + */ + + double arg; + double sarg; + double a4[4],b4[4],x4[8],poly4[8]; + double beta1; + double dsrgdb; + double d2sdb2; + double sphi; /* square root of phi */ + double sphi3; /* square root of phi cubed */ + double barg; + double d2bdb2; + double factor; + double dbrgdb; + double eta; + double vbin; + double argd; + double args; + double argss; + double argsd; + double argxs; + double argxd; + double daddb2; + double dasdb2; + double dbargd; + double dbargs; + double dbxwd; + double dbxws; + double dgddb2; + double dgddvb; + double dgdvds; + double gamasd; + double xwd; + double xws; + double ddxwd; + double gammad; + double vth; + double cfs; + double cdonco; + double xn; + double argg; + double vgst; + double sarg3; + double sbiarg; + double dgdvbs; + double body; + double gdbdv; + double dodvbs; + double dodvds; + double dxndvd; + double dxndvb; + double udenom; + double dudvgs; + double dudvds; + double dudvbs; + double gammd2; + double argv; + double vgsx; + double ufact; + double ueff; + double dsdvgs; + double dsdvbs; + double a1; + double a3; + double a; + double b1; + double b3; + double b; + double c1; + double c; + double d1; + double fi; + double p0; + double p2; + double p3; + double p4; + double p; + double r3; + double r; + double ro; + double s2; + double s; + double v1; + double v2; + double xv; + double y3; + double delta4; + double xvalid; + double bsarg; + double dbsrdb; + double bodys; + double gdbdvs; + double sargv; + double xlfact; + double dldsat; + double xdv; + double xlv; + double vqchan; + double dqdsat; + double vl; + double dfundg; + double dfunds; + double dfundb; + double xls; + double dldvgs; + double dldvds; + double dldvbs; + double dfact; + double clfact; + double xleff; + double deltal; + double xwb; + double vdson; + double cdson; + double didvds; + double gdson; + double gmw; + double gbson; + double expg; + double xld; + double xlamda = model->MOS2lambda; + /* 'local' variables - these switch d & s around appropriately + * so that we don't have to worry about vds < 0 + */ + double lvbs = here->MOS2mode==1?vbs:vbd; + double lvds = here->MOS2mode*vds; + double lvgs = here->MOS2mode==1?vgs:vgd; + double phiMinVbs = here->MOS2tPhi - lvbs; + double tmp; /* a temporary variable, not used for more than */ + /* about 10 lines at a time */ + int iknt; + int jknt; + int i; + int j; + + /* + * compute some useful quantities + */ + + if (lvbs <= 0.0) { + sarg = sqrt(phiMinVbs); + dsrgdb = -0.5/sarg; + d2sdb2 = 0.5*dsrgdb/phiMinVbs; + } else { + sphi = sqrt(here->MOS2tPhi); + sphi3 = here->MOS2tPhi*sphi; + sarg = sphi/(1.0+0.5*lvbs/here->MOS2tPhi); + tmp = sarg/sphi3; + dsrgdb = -0.5*sarg*tmp; + d2sdb2 = -dsrgdb*tmp; + } + if ((lvds-lvbs) >= 0) { + barg = sqrt(phiMinVbs+lvds); + dbrgdb = -0.5/barg; + d2bdb2 = 0.5*dbrgdb/(phiMinVbs+lvds); + } else { + barg = sphi/(1.0+0.5*(lvbs-lvds)/here->MOS2tPhi); + tmp = barg/sphi3; + dbrgdb = -0.5*barg*tmp; + d2bdb2 = -dbrgdb*tmp; + } + /* + * calculate threshold voltage (von) + * narrow-channel effect + */ + + /*XXX constant per device */ + factor = 0.125*model->MOS2narrowFactor*2.0*M_PI*EPSSIL/ + OxideCap*EffectiveLength; + /*XXX constant per device */ + eta = 1.0+factor; + vbin = here->MOS2tVbi*model->MOS2type+factor*phiMinVbs; + if ((model->MOS2gamma > 0.0) || + (model->MOS2substrateDoping > 0.0)) { + xwd = model->MOS2xd*barg; + xws = model->MOS2xd*sarg; + + /* + * short-channel effect with vds .ne. 0.0 + */ + + argss = 0.0; + argsd = 0.0; + dbargs = 0.0; + dbargd = 0.0; + dgdvds = 0.0; + dgddb2 = 0.0; + if (model->MOS2junctionDepth > 0) { + tmp = 2.0/model->MOS2junctionDepth; + argxs = 1.0+xws*tmp; + argxd = 1.0+xwd*tmp; + args = sqrt(argxs); + argd = sqrt(argxd); + tmp = .5*model->MOS2junctionDepth/EffectiveLength; + argss = tmp * (args-1.0); + argsd = tmp * (argd-1.0); + } + gamasd = model->MOS2gamma*(1.0-argss-argsd); + dbxwd = model->MOS2xd*dbrgdb; + dbxws = model->MOS2xd*dsrgdb; + if (model->MOS2junctionDepth > 0) { + tmp = 0.5/EffectiveLength; + dbargs = tmp*dbxws/args; + dbargd = tmp*dbxwd/argd; + dasdb2 = -model->MOS2xd*( d2sdb2+dsrgdb*dsrgdb* + model->MOS2xd/(model->MOS2junctionDepth*argxs))/ + (EffectiveLength*args); + daddb2 = -model->MOS2xd*( d2bdb2+dbrgdb*dbrgdb* + model->MOS2xd/(model->MOS2junctionDepth*argxd))/ + (EffectiveLength*argd); + dgddb2 = -0.5*model->MOS2gamma*(dasdb2+daddb2); + } + dgddvb = -model->MOS2gamma*(dbargs+dbargd); + if (model->MOS2junctionDepth > 0) { + ddxwd = -dbxwd; + dgdvds = -model->MOS2gamma*0.5*ddxwd/(EffectiveLength*argd); + } + } else { + gamasd = model->MOS2gamma; + gammad = model->MOS2gamma; + dgddvb = 0.0; + dgdvds = 0.0; + dgddb2 = 0.0; + } + von = vbin+gamasd*sarg; + vth = von; + vdsat = 0.0; + if (model->MOS2fastSurfaceStateDensity != 0.0 && OxideCap != 0.0) { + /* XXX constant per model */ + cfs = CHARGE*model->MOS2fastSurfaceStateDensity* + 1e4 /*(cm**2/m**2)*/; + cdonco = -(gamasd*dsrgdb+dgddvb*sarg)+factor; + xn = 1.0+cfs/OxideCap*here->MOS2w*EffectiveLength+cdonco; + tmp = vt*xn; + von = von+tmp; + argg = 1.0/tmp; + vgst = lvgs-von; + } else { + vgst = lvgs-von; + if (lvgs <= von) { + /* + * cutoff region + */ + here->MOS2gds = 0.0; + goto line1050; + } + } + + /* + * compute some more useful quantities + */ + + sarg3 = sarg*sarg*sarg; + /* XXX constant per model */ + sbiarg = sqrt(here->MOS2tBulkPot); + gammad = gamasd; + dgdvbs = dgddvb; + body = barg*barg*barg-sarg3; + gdbdv = 2.0*gammad*(barg*barg*dbrgdb-sarg*sarg*dsrgdb); + dodvbs = -factor+dgdvbs*sarg+gammad*dsrgdb; + if (model->MOS2fastSurfaceStateDensity == 0.0) goto line400; + if (OxideCap == 0.0) goto line410; + dxndvb = 2.0*dgdvbs*dsrgdb+gammad*d2sdb2+dgddb2*sarg; + dodvbs = dodvbs+vt*dxndvb; + dxndvd = dgdvds*dsrgdb; + dodvds = dgdvds*sarg+vt*dxndvd; + /* + * evaluate effective mobility and its derivatives + */ +line400: + if (OxideCap <= 0.0) goto line410; + udenom = vgst; + tmp = model->MOS2critField * 100 /* cm/m */ * EPSSIL/ + model->MOS2oxideCapFactor; + if (udenom <= tmp) goto line410; + ufact = exp(model->MOS2critFieldExp*log(tmp/udenom)); + ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ *ufact; + dudvgs = -ufact*model->MOS2critFieldExp/udenom; + dudvds = 0.0; + dudvbs = model->MOS2critFieldExp*ufact*dodvbs/vgst; + goto line500; +line410: + ufact = 1.0; + ueff = model->MOS2surfaceMobility * 1e-4 /*(m**2/cm**2) */ ; + dudvgs = 0.0; + dudvds = 0.0; + dudvbs = 0.0; + /* + * evaluate saturation voltage and its derivatives according to + * grove-frohman equation + */ +line500: + vgsx = lvgs; + gammad = gamasd/eta; + dgdvbs = dgddvb; + if (model->MOS2fastSurfaceStateDensity != 0 && OxideCap != 0) { + vgsx = MAX(lvgs,von); + } + if (gammad > 0) { + gammd2 = gammad*gammad; + argv = (vgsx-vbin)/eta+phiMinVbs; + if (argv <= 0.0) { + vdsat = 0.0; + dsdvgs = 0.0; + dsdvbs = 0.0; + } else { + arg = sqrt(1.0+4.0*argv/gammd2); + vdsat = (vgsx-vbin)/eta+gammd2*(1.0-arg)/2.0; + vdsat = MAX(vdsat,0.0); + dsdvgs = (1.0-1.0/arg)/eta; + dsdvbs = (gammad*(1.0-arg)+2.0*argv/(gammad*arg))/ + eta*dgdvbs+1.0/arg+factor*dsdvgs; + } + } else { + vdsat = (vgsx-vbin)/eta; + vdsat = MAX(vdsat,0.0); + dsdvgs = 1.0; + dsdvbs = 0.0; + } + if (model->MOS2maxDriftVel > 0) { + /* + * evaluate saturation voltage and its derivatives + * according to baum's theory of scattering velocity + * saturation + */ + gammd2 = gammad*gammad; + v1 = (vgsx-vbin)/eta+phiMinVbs; + v2 = phiMinVbs; + xv = model->MOS2maxDriftVel*EffectiveLength/ueff; + a1 = gammad/0.75; + b1 = -2.0*(v1+xv); + c1 = -2.0*gammad*xv; + d1 = 2.0*v1*(v2+xv)-v2*v2-4.0/3.0*gammad*sarg3; + a = -b1; + b = a1*c1-4.0*d1; + c = -d1*(a1*a1-4.0*b1)-c1*c1; + r = -a*a/3.0+b; + s = 2.0*a*a*a/27.0-a*b/3.0+c; + r3 = r*r*r; + s2 = s*s; + p = s2/4.0+r3/27.0; + p0 = fabs(p); + p2 = sqrt(p0); + if (p < 0) { + ro = sqrt(s2/4.0+p0); + ro = log(ro)/3.0; + ro = exp(ro); + fi = atan(-2.0*p2/s); + y3 = 2.0*ro*cos(fi/3.0)-a/3.0; + } else { + p3 = (-s/2.0+p2); + p3 = exp(log(fabs(p3))/3.0); + p4 = (-s/2.0-p2); + p4 = exp(log(fabs(p4))/3.0); + y3 = p3+p4-a/3.0; + } + iknt = 0; + a3 = sqrt(a1*a1/4.0-b1+y3); + b3 = sqrt(y3*y3/4.0-d1); + for(i = 1;i<=4;i++) { + a4[i-1] = a1/2.0+sig1[i-1]*a3; + b4[i-1] = y3/2.0+sig2[i-1]*b3; + delta4 = a4[i-1]*a4[i-1]/4.0-b4[i-1]; + if (delta4 < 0) continue; + iknt = iknt+1; + tmp = sqrt(delta4); + x4[iknt-1] = -a4[i-1]/2.0+tmp; + iknt = iknt+1; + x4[iknt-1] = -a4[i-1]/2.0-tmp; + } + jknt = 0; + for(j = 1;j<=iknt;j++) { + if (x4[j-1] <= 0) continue; + /* XXX implement this sanely */ + poly4[j-1] = x4[j-1]*x4[j-1]*x4[j-1]*x4[j-1]+a1*x4[j-1]* + x4[j-1]*x4[j-1]; + poly4[j-1] = poly4[j-1]+b1*x4[j-1]*x4[j-1]+c1*x4[j-1]+d1; + if (fabs(poly4[j-1]) > 1.0e-6) continue; + jknt = jknt+1; + if (jknt <= 1) { + xvalid = x4[j-1]; + } + if (x4[j-1] > xvalid) continue; + xvalid = x4[j-1]; + } + if (jknt > 0) { + vdsat = xvalid*xvalid-phiMinVbs; + } + } + /* + * evaluate effective channel length and its derivatives + */ + if (lvds != 0.0) { + gammad = gamasd; + if ((lvbs-vdsat) <= 0) { + bsarg = sqrt(vdsat+phiMinVbs); + dbsrdb = -0.5/bsarg; + } else { + bsarg = sphi/(1.0+0.5*(lvbs-vdsat)/here->MOS2tPhi); + dbsrdb = -0.5*bsarg*bsarg/sphi3; + } + bodys = bsarg*bsarg*bsarg-sarg3; + gdbdvs = 2.0*gammad*(bsarg*bsarg*dbsrdb-sarg*sarg*dsrgdb); + if (model->MOS2maxDriftVel <= 0) { + if (model->MOS2substrateDoping == 0.0) goto line610; + if (xlamda > 0.0) goto line610; + argv = (lvds-vdsat)/4.0; + sargv = sqrt(1.0+argv*argv); + arg = sqrt(argv+sargv); + xlfact = model->MOS2xd/(EffectiveLength*lvds); + xlamda = xlfact*arg; + dldsat = lvds*xlamda/(8.0*sargv); + } else { + argv = (vgsx-vbin)/eta-vdsat; + xdv = model->MOS2xd/sqrt(model->MOS2channelCharge); + xlv = model->MOS2maxDriftVel*xdv/(2.0*ueff); + vqchan = argv-gammad*bsarg; + dqdsat = -1.0+gammad*dbsrdb; + vl = model->MOS2maxDriftVel*EffectiveLength; + dfunds = vl*dqdsat-ueff*vqchan; + dfundg = (vl-ueff*vdsat)/eta; + dfundb = -vl*(1.0+dqdsat-factor/eta)+ueff* + (gdbdvs-dgdvbs*bodys/1.5)/eta; + dsdvgs = -dfundg/dfunds; + dsdvbs = -dfundb/dfunds; + if (model->MOS2substrateDoping == 0.0) goto line610; + if (xlamda > 0.0) goto line610; + argv = lvds-vdsat; + argv = MAX(argv,0.0); + xls = sqrt(xlv*xlv+argv); + dldsat = xdv/(2.0*xls); + xlfact = xdv/(EffectiveLength*lvds); + xlamda = xlfact*(xls-xlv); + dldsat = dldsat/EffectiveLength; + } + dldvgs = dldsat*dsdvgs; + dldvds = -xlamda+dldsat; + dldvbs = dldsat*dsdvbs; + } else { +line610: + dldvgs = 0.0; + dldvds = 0.0; + dldvbs = 0.0; + } + /* + * limit channel shortening at punch-through + */ + xwb = model->MOS2xd*sbiarg; + xld = EffectiveLength-xwb; + clfact = 1.0-xlamda*lvds; + dldvds = -xlamda-dldvds; + xleff = EffectiveLength*clfact; + deltal = xlamda*lvds*EffectiveLength; + if (model->MOS2substrateDoping == 0.0) xwb = 0.25e-6; + if (xleff < xwb) { + xleff = xwb/(1.0+(deltal-xld)/xwb); + clfact = xleff/EffectiveLength; + dfact = xleff*xleff/(xwb*xwb); + dldvgs = dfact*dldvgs; + dldvds = dfact*dldvds; + dldvbs = dfact*dldvbs; + } + /* + * evaluate effective beta (effective kp) + */ + beta1 = Beta*ufact/clfact; + /* + * test for mode of operation and branch appropriately + */ + gammad = gamasd; + dgdvbs = dgddvb; + if (lvds <= 1.0e-10) { + if (lvgs <= von) { + if ((model->MOS2fastSurfaceStateDensity == 0.0) || + (OxideCap == 0.0)) { + here->MOS2gds = 0.0; + goto line1050; + } + + here->MOS2gds = beta1*(von-vbin-gammad*sarg)*exp(argg* + (lvgs-von)); + goto line1050; + } + + + here->MOS2gds = beta1*(lvgs-vbin-gammad*sarg); + goto line1050; + } + + if (lvgs > von) goto line900; + /* + * subthreshold region + */ + if (vdsat <= 0) { + here->MOS2gds = 0.0; + if (lvgs > vth) goto doneval; + goto line1050; + } + vdson = MIN(vdsat,lvds); + if (lvds > vdsat) { + barg = bsarg; + dbrgdb = dbsrdb; + body = bodys; + gdbdv = gdbdvs; + } + cdson = beta1*((von-vbin-eta*vdson*0.5)*vdson-gammad*body/1.5); + didvds = beta1*(von-vbin-eta*vdson-gammad*barg); + gdson = -cdson*dldvds/clfact-beta1*dgdvds*body/1.5; + if (lvds < vdsat) gdson = gdson+didvds; + gbson = -cdson*dldvbs/clfact+beta1* + (dodvbs*vdson+factor*vdson-dgdvbs*body/1.5-gdbdv); + if (lvds > vdsat) gbson = gbson+didvds*dsdvbs; + expg = exp(argg*(lvgs-von)); + cdrain = cdson*expg; + gmw = cdrain*argg; + here->MOS2gm = gmw; + if (lvds > vdsat) here->MOS2gm = gmw+didvds*dsdvgs*expg; + tmp = gmw*(lvgs-von)/xn; + here->MOS2gds = gdson*expg-here->MOS2gm*dodvds-tmp*dxndvd; + here->MOS2gmbs = gbson*expg-here->MOS2gm*dodvbs-tmp*dxndvb; + goto doneval; + +line900: + if (lvds <= vdsat) { + /* + * linear region + */ + cdrain = beta1*((lvgs-vbin-eta*lvds/2.0)*lvds-gammad*body/1.5); + arg = cdrain*(dudvgs/ufact-dldvgs/clfact); + here->MOS2gm = arg+beta1*lvds; + arg = cdrain*(dudvds/ufact-dldvds/clfact); + here->MOS2gds = arg+beta1*(lvgs-vbin-eta* + lvds-gammad*barg-dgdvds*body/1.5); + arg = cdrain*(dudvbs/ufact-dldvbs/clfact); + here->MOS2gmbs = arg-beta1*(gdbdv+dgdvbs*body/1.5-factor*lvds); + } else { + /* + * saturation region + */ + cdrain = beta1*((lvgs-vbin-eta* + vdsat/2.0)*vdsat-gammad*bodys/1.5); + arg = cdrain*(dudvgs/ufact-dldvgs/clfact); + here->MOS2gm = arg+beta1*vdsat+beta1*(lvgs- + vbin-eta*vdsat-gammad*bsarg)*dsdvgs; + here->MOS2gds = -cdrain*dldvds/clfact-beta1*dgdvds*bodys/1.5; + arg = cdrain*(dudvbs/ufact-dldvbs/clfact); + here->MOS2gmbs = arg-beta1*(gdbdvs+dgdvbs*bodys/1.5-factor* + vdsat)+beta1* (lvgs-vbin-eta*vdsat-gammad*bsarg)*dsdvbs; + } + /* + * compute charges for "on" region + */ + goto doneval; + /* + * finish special cases + */ +line1050: + cdrain = 0.0; + here->MOS2gm = 0.0; + here->MOS2gmbs = 0.0; + /* + * finished + */ + + } +doneval: + here->MOS2von = model->MOS2type * von; + here->MOS2vdsat = model->MOS2type * vdsat; + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + here->MOS2cd=here->MOS2mode * cdrain - here->MOS2cbd; + + if (ckt->CKTmode & (MODETRAN | MODETRANOP|MODEINITSMSIG)) { + /* + * now we do the hard part of the bulk-drain and bulk-source + * diode - we evaluate the non-linear capacitance and + * charge + * + * the basic equations are not hard, but the implementation + * is somewhat long in an attempt to avoid log/exponential + * evaluations + */ + /* + * charge storage elements + * + *.. bulk-drain and bulk-source depletion capacitances + */ +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbs) >= ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS2vbs)))+ + ckt->CKTvoltTol)|| senflag) +#endif /*CAPBYPASS*/ + { + /* can't bypass the diode capacitance calculations */ +#ifdef CAPZEROBYPASS + if(here->MOS2Cbs != 0 || here->MOS2Cbssw != 0) { +#endif /*CAPZEROBYPASS*/ + if (vbs < here->MOS2tDepCap){ + arg=1-vbs/here->MOS2tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS2bulkJctBotGradingCoeff == + model->MOS2bulkJctSideGradingCoeff) { + if(model->MOS2bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS2bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS2bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS2bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS2bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS2bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS2qbs) = + here->MOS2tBulkPot*(here->MOS2Cbs* + (1-arg*sarg)/(1-model->MOS2bulkJctBotGradingCoeff) + +here->MOS2Cbssw* + (1-arg*sargsw)/ + (1-model->MOS2bulkJctSideGradingCoeff)); + here->MOS2capbs=here->MOS2Cbs*sarg+ + here->MOS2Cbssw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS2qbs) = here->MOS2f4s + + vbs*(here->MOS2f2s+vbs*(here->MOS2f3s/2)); + here->MOS2capbs=here->MOS2f2s+here->MOS2f3s*vbs; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS2qbs) = 0; + here->MOS2capbs=0; + } +#endif /*CAPZEROBYPASS*/ + } +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS2vbd)))+ + ckt->CKTvoltTol)|| senflag) +#endif /*CAPBYPASS*/ + /* can't bypass the diode capacitance calculations */ + { +#ifdef CAPZEROBYPASS + if(here->MOS2Cbd != 0 || here->MOS2Cbdsw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbd < here->MOS2tDepCap) { + arg=1-vbd/here->MOS2tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS2bulkJctBotGradingCoeff == .5 && + model->MOS2bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS2bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS2bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS2bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS2bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS2qbd) = + here->MOS2tBulkPot*(here->MOS2Cbd* + (1-arg*sarg) + /(1-model->MOS2bulkJctBotGradingCoeff) + +here->MOS2Cbdsw* + (1-arg*sargsw) + /(1-model->MOS2bulkJctSideGradingCoeff)); + here->MOS2capbd=here->MOS2Cbd*sarg+ + here->MOS2Cbdsw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS2qbd) = here->MOS2f4d + + vbd * (here->MOS2f2d + vbd * here->MOS2f3d/2); + here->MOS2capbd=here->MOS2f2d + vbd * here->MOS2f3d; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS2qbd) = 0; + here->MOS2capbd = 0; + } +#endif /*CAPZEROBYPASS*/ + } + if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; + + if ( ckt->CKTmode & MODETRAN ) { + /* (above only excludes tranop, since we're only at this + * point if tran or tranop ) + */ + + /* + * calculate equivalent conductances and currents for + * depletion capacitors + */ + + /* integrate the capacitors and save results */ + + error = NIintegrate(ckt,&geq,&ceq,here->MOS2capbd, + here->MOS2qbd); + if(error) return(error); + here->MOS2gbd += geq; + here->MOS2cbd += *(ckt->CKTstate0 + here->MOS2cqbd); + here->MOS2cd -= *(ckt->CKTstate0 + here->MOS2cqbd); + error = NIintegrate(ckt,&geq,&ceq,here->MOS2capbs, + here->MOS2qbs); + if(error) return(error); + here->MOS2gbs += geq; + here->MOS2cbs += *(ckt->CKTstate0 + here->MOS2cqbs); + } + } + + if(SenCond) goto next2; + /* + * check convergence + */ + if ( (here->MOS2off == 0) || + (!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV +#ifdef STEPDEBUG + printf("MOS2: %s limiting noncon\n",here->MOS2name); +#endif /* STEPDEBUG */ + } else { + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(here->MOS2cd))+ + ckt->CKTabstol; + if (fabs(cdhat-here->MOS2cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifdef STEPDEBUG + printf("MOS2: %s cd noncon cd=%g, cdhat=%g, mode=%d\n", + here->MOS2name,here->MOS2cd,cdhat, + here->MOS2mode); +#endif /* STEPDEBUG */ + } else { + tol=ckt->CKTreltol* + MAX(fabs(cbhat),fabs(here->MOS2cbs+here->MOS2cbd))+ ckt->CKTabstol; + if (fabs(cbhat-(here->MOS2cbs+here->MOS2cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifdef STEPDEBUG + printf("MOS2: %s cb noncon\n",here->MOS2name); +#endif /* STEPDEBUG */ + } + } +#endif /* NEWCONV */ + } + } +next2: *(ckt->CKTstate0 + here->MOS2vbs) = vbs; + *(ckt->CKTstate0 + here->MOS2vbd) = vbd; + *(ckt->CKTstate0 + here->MOS2vgs) = vgs; + *(ckt->CKTstate0 + here->MOS2vds) = vds; + + /* + * meyer's capacitor model + */ + if ( ckt->CKTmode & (MODETRAN|MODETRANOP|MODEINITSMSIG)) { + /* + * calculate meyer's capacitors + */ + if (here->MOS2mode > 0){ + DEVqmeyer (vgs,vgd,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS2capgs), + (ckt->CKTstate0 + here->MOS2capgd), + (ckt->CKTstate0 + here->MOS2capgb), + here->MOS2tPhi,OxideCap); + } else { + DEVqmeyer (vgd,vgs,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS2capgd), + (ckt->CKTstate0 + here->MOS2capgs), + (ckt->CKTstate0 + here->MOS2capgb), + here->MOS2tPhi,OxideCap); + } + vgs1 = *(ckt->CKTstate1 + here->MOS2vgs); + vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS2vds); + vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS2vbs); + if(ckt->CKTmode & MODETRANOP) { + capgs = 2 * *(ckt->CKTstate0 + here->MOS2capgs)+ + GateSourceOverlapCap; + capgd = 2 * *(ckt->CKTstate0 + here->MOS2capgd)+ + GateDrainOverlapCap; + capgb = 2 * *(ckt->CKTstate0 + here->MOS2capgb)+ + GateBulkOverlapCap; + } else { + capgs = *(ckt->CKTstate0 + here->MOS2capgs)+ + *(ckt->CKTstate1 + here->MOS2capgs)+ + GateSourceOverlapCap; + capgd = *(ckt->CKTstate0 + here->MOS2capgd)+ + *(ckt->CKTstate1 + here->MOS2capgd)+ + GateDrainOverlapCap; + capgb = *(ckt->CKTstate0 + here->MOS2capgb)+ + *(ckt->CKTstate1 + here->MOS2capgb)+ + GateBulkOverlapCap; + } + if(ckt->CKTsenInfo){ + here->MOS2cgs = capgs; + here->MOS2cgd = capgd; + here->MOS2cgb = capgb; + } + /* + * store small-signal parameters (for meyer's model) + * all parameters already stored, so done... + */ + + if(SenCond){ + if(ckt->CKTsenInfo->SENmode & (DCSEN|ACSEN)){ + continue; + } + } + +#ifndef PREDICTOR + if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + *(ckt->CKTstate0 + here->MOS2qgs) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS2qgs) + -xfact * *(ckt->CKTstate2 + here->MOS2qgs); + *(ckt->CKTstate0 + here->MOS2qgd) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS2qgd) + -xfact * *(ckt->CKTstate2 + here->MOS2qgd); + *(ckt->CKTstate0 + here->MOS2qgb) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS2qgb) + -xfact * *(ckt->CKTstate2 + here->MOS2qgb); + } else { +#endif /* PREDICTOR */ + if(ckt->CKTmode & MODETRAN) { + *(ckt->CKTstate0 + here->MOS2qgs) = (vgs-vgs1)*capgs + + *(ckt->CKTstate1 + here->MOS2qgs) ; + *(ckt->CKTstate0 + here->MOS2qgd) = (vgd-vgd1)*capgd + + *(ckt->CKTstate1 + here->MOS2qgd) ; + *(ckt->CKTstate0 + here->MOS2qgb) = (vgb-vgb1)*capgb + + *(ckt->CKTstate1 + here->MOS2qgb) ; + } else { + /* TRANOP */ + *(ckt->CKTstate0 + here->MOS2qgs) = capgs*vgs; + *(ckt->CKTstate0 + here->MOS2qgd) = capgd*vgd; + *(ckt->CKTstate0 + here->MOS2qgb) = capgb*vgb; + } +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + } +#ifndef NOBYPASS +bypass: +#endif /* NOBYPASS */ + + if(SenCond) continue; + + + if((ckt->CKTmode & MODEINITTRAN) || (!(ckt->CKTmode & MODETRAN)) ) { + /* initialize to zero charge conductances and current */ + + gcgs=0; + ceqgs=0; + gcgd=0; + ceqgd=0; + gcgb=0; + ceqgb=0; + } else { + if(capgs == 0) *(ckt->CKTstate0 + here->MOS2cqgs) =0; + if(capgd == 0) *(ckt->CKTstate0 + here->MOS2cqgd) =0; + if(capgb == 0) *(ckt->CKTstate0 + here->MOS2cqgb) =0; + /* + * calculate equivalent conductances and currents for + * meyer"s capacitors + */ + error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS2qgs); + if(error) return(error); + error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS2qgd); + if(error) return(error); + error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS2qgb); + if(error) return(error); + ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS2qgs); + ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS2qgd); + ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS2qgb); + } + /* + * store charge storage info for meyer's cap in lx table + */ + + /* + * load current vector + */ + ceqbs = model->MOS2type * + (here->MOS2cbs-(here->MOS2gbs-ckt->CKTgmin)*vbs); + ceqbd = model->MOS2type * + (here->MOS2cbd-(here->MOS2gbd-ckt->CKTgmin)*vbd); + if (here->MOS2mode >= 0) { + xnrm=1; + xrev=0; + cdreq=model->MOS2type*(cdrain-here->MOS2gds*vds- + here->MOS2gm*vgs-here->MOS2gmbs*vbs); + } else { + xnrm=0; + xrev=1; + cdreq = -(model->MOS2type)*(cdrain-here->MOS2gds*(-vds)- + here->MOS2gm*vgd-here->MOS2gmbs*vbd); + } + *(ckt->CKTrhs + here->MOS2gNode) -= + model->MOS2type * (ceqgs + ceqgb + ceqgd); + *(ckt->CKTrhs + here->MOS2bNode) -= + (ceqbs+ceqbd-model->MOS2type * ceqgb); + *(ckt->CKTrhs + here->MOS2dNodePrime) += + ceqbd - cdreq + model->MOS2type * ceqgd; + *(ckt->CKTrhs + here->MOS2sNodePrime) += + cdreq + ceqbs + model->MOS2type * ceqgs; + +#if 0 + printf(" loading %s at time %g\n", here->MOS2name, ckt->CKTtime); + printf("%g %g %g %g %g\n", here->MOS2drainConductance, + gcgd+gcgs+gcgb, here->MOS2sourceConductance, + here->MOS2gbd, here->MOS2gbs); + printf("%g %g %g %g %g\n", -gcgb, 0.0, 0.0, + here->MOS2gds, here->MOS2gm); + printf("%g %g %g %g %g\n", here->MOS2gds, here->MOS2gmbs, + gcgd, -gcgs, -gcgd); + printf("%g %g %g %g %g\n", -gcgs, -gcgd, 0.0, -gcgs, 0.0); +#endif + + /* + * load y matrix + */ + *(here->MOS2DdPtr) += (here->MOS2drainConductance); + *(here->MOS2GgPtr) += gcgd+gcgs+gcgb; + *(here->MOS2SsPtr) += (here->MOS2sourceConductance); + *(here->MOS2BbPtr) += (here->MOS2gbd+here->MOS2gbs+gcgb); + *(here->MOS2DPdpPtr) += here->MOS2drainConductance+here->MOS2gds+ + here->MOS2gbd+xrev*(here->MOS2gm+here->MOS2gmbs)+gcgd; + *(here->MOS2SPspPtr) += here->MOS2sourceConductance+here->MOS2gds+ + here->MOS2gbs+xnrm*(here->MOS2gm+here->MOS2gmbs)+gcgs; + *(here->MOS2DdpPtr) -= here->MOS2drainConductance; + *(here->MOS2GbPtr) -= gcgb; + *(here->MOS2GdpPtr) -= gcgd; + *(here->MOS2GspPtr) -= gcgs; + *(here->MOS2SspPtr) -= here->MOS2sourceConductance; + *(here->MOS2BgPtr) -= gcgb; + *(here->MOS2BdpPtr) -= here->MOS2gbd; + *(here->MOS2BspPtr) -= here->MOS2gbs; + *(here->MOS2DPdPtr) -= here->MOS2drainConductance; + *(here->MOS2DPgPtr) += ((xnrm-xrev)*here->MOS2gm-gcgd); + *(here->MOS2DPbPtr) += (-here->MOS2gbd+(xnrm-xrev)*here->MOS2gmbs); + *(here->MOS2DPspPtr) -= here->MOS2gds+xnrm*(here->MOS2gm+ + here->MOS2gmbs); + *(here->MOS2SPgPtr) -= (xnrm-xrev)*here->MOS2gm+gcgs; + *(here->MOS2SPsPtr) -= here->MOS2sourceConductance; + *(here->MOS2SPbPtr) -= here->MOS2gbs+(xnrm-xrev)*here->MOS2gmbs; + *(here->MOS2SPdpPtr) -= here->MOS2gds+xrev*(here->MOS2gm+ + here->MOS2gmbs); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2mask.c b/src/spicelib/devices/mos2/mos2mask.c new file mode 100644 index 000000000..5f65978bf --- /dev/null +++ b/src/spicelib/devices/mos2/mos2mask.c @@ -0,0 +1,144 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS2mAsk(ckt,inModel,param,value) + CKTcircuit *ckt; + GENmodel *inModel; + int param; + IFvalue *value; +{ + register MOS2model *model = (MOS2model *)inModel; + switch(param) { + case MOS2_MOD_TNOM: + value->rValue = model->MOS2tnom - CONSTCtoK; + break; + case MOS2_MOD_VTO: + value->rValue = model->MOS2vt0; + break; + case MOS2_MOD_KP: + value->rValue = model->MOS2transconductance; + break; + case MOS2_MOD_GAMMA: + value->rValue = model->MOS2gamma; + break; + case MOS2_MOD_PHI: + value->rValue = model->MOS2phi; + break; + case MOS2_MOD_LAMBDA: + value->rValue = model->MOS2lambda; + break; + case MOS2_MOD_RD: + value->rValue = model->MOS2drainResistance; + break; + case MOS2_MOD_RS: + value->rValue = model->MOS2sourceResistance; + break; + case MOS2_MOD_CBD: + value->rValue = model->MOS2capBD; + break; + case MOS2_MOD_CBS: + value->rValue = model->MOS2capBS; + break; + case MOS2_MOD_IS: + value->rValue = model->MOS2jctSatCur; + break; + case MOS2_MOD_PB: + value->rValue = model->MOS2bulkJctPotential; + break; + case MOS2_MOD_CGSO: + value->rValue = model->MOS2gateSourceOverlapCapFactor; + break; + case MOS2_MOD_CGDO: + value->rValue = model->MOS2gateDrainOverlapCapFactor; + break; + case MOS2_MOD_CGBO: + value->rValue = model->MOS2gateBulkOverlapCapFactor; + break; + case MOS2_MOD_CJ: + value->rValue = model->MOS2bulkCapFactor; + break; + case MOS2_MOD_MJ: + value->rValue = model->MOS2bulkJctBotGradingCoeff; + break; + case MOS2_MOD_CJSW: + value->rValue = model->MOS2sideWallCapFactor; + break; + case MOS2_MOD_MJSW: + value->rValue = model->MOS2bulkJctSideGradingCoeff; + break; + case MOS2_MOD_JS: + value->rValue = model->MOS2jctSatCurDensity; + break; + case MOS2_MOD_TOX: + value->rValue = model->MOS2oxideThickness; + break; + case MOS2_MOD_LD: + value->rValue = model->MOS2latDiff; + break; + case MOS2_MOD_RSH: + value->rValue = model->MOS2sheetResistance; + break; + case MOS2_MOD_U0: + value->rValue = model->MOS2surfaceMobility; + break; + case MOS2_MOD_FC: + value->rValue = model->MOS2fwdCapDepCoeff; + break; + case MOS2_MOD_NSUB: + value->rValue = model->MOS2substrateDoping; + break; + case MOS2_MOD_TPG: + value->rValue = model->MOS2gateType; + break; + case MOS2_MOD_NSS: + value->rValue = model->MOS2surfaceStateDensity; + break; + case MOS2_MOD_NFS: + value->rValue = model->MOS2fastSurfaceStateDensity; + break; + case MOS2_MOD_DELTA: + value->rValue = model->MOS2narrowFactor; + break; + case MOS2_MOD_UEXP: + value->rValue = model->MOS2critFieldExp; + break; + case MOS2_MOD_VMAX: + value->rValue = model->MOS2maxDriftVel; + break; + case MOS2_MOD_XJ: + value->rValue = model->MOS2junctionDepth; + break; + case MOS2_MOD_NEFF: + value->rValue = model->MOS2channelCharge; + break; + case MOS2_MOD_UCRIT: + value->rValue = model->MOS2critField; + break; + case MOS2_MOD_KF: + value->rValue = model->MOS2fNcoef; + break; + case MOS2_MOD_AF: + value->rValue = model->MOS2fNexp; + break; + case MOS2_MOD_TYPE: + if (model->MOS2type > 0) + value->sValue = "nmos"; + else + value->sValue = "pmos"; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2mdel.c b/src/spicelib/devices/mos2/mos2mdel.c new file mode 100644 index 000000000..83043dd1e --- /dev/null +++ b/src/spicelib/devices/mos2/mos2mdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS2mDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + MOS2model **model = (MOS2model **)inModel; + MOS2model *modfast = (MOS2model *)kill; + MOS2instance *here; + MOS2instance *prev = NULL; + MOS2model **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->MOS2nextModel)) { + if( (*model)->MOS2modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->MOS2nextModel; /* cut deleted device out of list */ + for(here = (*model)->MOS2instances ; here ; here = here->MOS2nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/mos2/mos2mpar.c b/src/spicelib/devices/mos2/mos2mpar.c new file mode 100644 index 000000000..5a97a9151 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2mpar.c @@ -0,0 +1,189 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS2mParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + register MOS2model *model = (MOS2model *)inModel; + switch(param) { + case MOS2_MOD_TNOM: + model->MOS2tnom = value->rValue+CONSTCtoK; + model->MOS2tnomGiven = TRUE; + break; + case MOS2_MOD_VTO: + model->MOS2vt0 = value->rValue; + model->MOS2vt0Given = TRUE; + break; + case MOS2_MOD_KP: + model->MOS2transconductance = value->rValue; + model->MOS2transconductanceGiven = TRUE; + break; + case MOS2_MOD_GAMMA: + model->MOS2gamma = value->rValue; + model->MOS2gammaGiven = TRUE; + break; + case MOS2_MOD_PHI: + model->MOS2phi = value->rValue; + model->MOS2phiGiven = TRUE; + break; + case MOS2_MOD_LAMBDA: + model->MOS2lambda = value->rValue; + model->MOS2lambdaGiven = TRUE; + break; + case MOS2_MOD_RD: + model->MOS2drainResistance = value->rValue; + model->MOS2drainResistanceGiven = TRUE; + break; + case MOS2_MOD_RS: + model->MOS2sourceResistance = value->rValue; + model->MOS2sourceResistanceGiven = TRUE; + break; + case MOS2_MOD_CBD: + model->MOS2capBD = value->rValue; + model->MOS2capBDGiven = TRUE; + break; + case MOS2_MOD_CBS: + model->MOS2capBS = value->rValue; + model->MOS2capBSGiven = TRUE; + break; + case MOS2_MOD_IS: + model->MOS2jctSatCur = value->rValue; + model->MOS2jctSatCurGiven = TRUE; + break; + case MOS2_MOD_PB: + model->MOS2bulkJctPotential = value->rValue; + model->MOS2bulkJctPotentialGiven = TRUE; + break; + case MOS2_MOD_CGSO: + model->MOS2gateSourceOverlapCapFactor = value->rValue; + model->MOS2gateSourceOverlapCapFactorGiven = TRUE; + break; + case MOS2_MOD_CGDO: + model->MOS2gateDrainOverlapCapFactor = value->rValue; + model->MOS2gateDrainOverlapCapFactorGiven = TRUE; + break; + case MOS2_MOD_CGBO: + model->MOS2gateBulkOverlapCapFactor = value->rValue; + model->MOS2gateBulkOverlapCapFactorGiven = TRUE; + break; + case MOS2_MOD_CJ: + model->MOS2bulkCapFactor = value->rValue; + model->MOS2bulkCapFactorGiven = TRUE; + break; + case MOS2_MOD_MJ: + model->MOS2bulkJctBotGradingCoeff = value->rValue; + model->MOS2bulkJctBotGradingCoeffGiven = TRUE; + break; + case MOS2_MOD_CJSW: + model->MOS2sideWallCapFactor = value->rValue; + model->MOS2sideWallCapFactorGiven = TRUE; + break; + case MOS2_MOD_MJSW: + model->MOS2bulkJctSideGradingCoeff = value->rValue; + model->MOS2bulkJctSideGradingCoeffGiven = TRUE; + break; + case MOS2_MOD_JS: + model->MOS2jctSatCurDensity = value->rValue; + model->MOS2jctSatCurDensityGiven = TRUE; + break; + case MOS2_MOD_TOX: + model->MOS2oxideThickness = value->rValue; + model->MOS2oxideThicknessGiven = TRUE; + break; + case MOS2_MOD_LD: + model->MOS2latDiff = value->rValue; + model->MOS2latDiffGiven = TRUE; + break; + case MOS2_MOD_RSH: + model->MOS2sheetResistance = value->rValue; + model->MOS2sheetResistanceGiven = TRUE; + break; + case MOS2_MOD_U0: + model->MOS2surfaceMobility = value->rValue; + model->MOS2surfaceMobilityGiven = TRUE; + break; + case MOS2_MOD_FC: + model->MOS2fwdCapDepCoeff = value->rValue; + model->MOS2fwdCapDepCoeffGiven = TRUE; + break; + case MOS2_MOD_NSUB: + model->MOS2substrateDoping = value->rValue; + model->MOS2substrateDopingGiven = TRUE; + break; + case MOS2_MOD_TPG: + model->MOS2gateType = value->iValue; + model->MOS2gateTypeGiven = TRUE; + break; + case MOS2_MOD_NSS: + model->MOS2surfaceStateDensity = value->rValue; + model->MOS2surfaceStateDensityGiven = TRUE; + break; + case MOS2_MOD_NFS: + model->MOS2fastSurfaceStateDensity = value->rValue; + model->MOS2fastSurfaceStateDensityGiven = TRUE; + break; + case MOS2_MOD_DELTA: + model->MOS2narrowFactor = value->rValue; + model->MOS2narrowFactorGiven = TRUE; + break; + case MOS2_MOD_UEXP: + model->MOS2critFieldExp = value->rValue; + model->MOS2critFieldExpGiven = TRUE; + break; + case MOS2_MOD_VMAX: + model->MOS2maxDriftVel = value->rValue; + model->MOS2maxDriftVelGiven = TRUE; + break; + case MOS2_MOD_XJ: + model->MOS2junctionDepth = value->rValue; + model->MOS2junctionDepthGiven = TRUE; + break; + case MOS2_MOD_NEFF: + model->MOS2channelCharge = value->rValue; + model->MOS2channelChargeGiven = TRUE; + break; + case MOS2_MOD_UCRIT: + model->MOS2critField = value->rValue; + model->MOS2critFieldGiven = TRUE; + break; + case MOS2_MOD_NMOS: + if(value->iValue) { + model->MOS2type = 1; + model->MOS2typeGiven = TRUE; + } + break; + case MOS2_MOD_PMOS: + if(value->iValue) { + model->MOS2type = -1; + model->MOS2typeGiven = TRUE; + } + break; + case MOS2_MOD_KF: + model->MOS2fNcoef = value->rValue; + model->MOS2fNcoefGiven = TRUE; + break; + case MOS2_MOD_AF: + model->MOS2fNexp = value->rValue; + model->MOS2fNexpGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2noi.c b/src/spicelib/devices/mos2/mos2noi.c new file mode 100644 index 000000000..fea335003 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2noi.c @@ -0,0 +1,217 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "mos2defs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * MOS2noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MOSFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MOSFET's is summed with the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +MOS2noise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + MOS2model *firstModel = (MOS2model *) genmodel; + register MOS2model *model; + register MOS2instance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[MOS2NSRCS]; + double lnNdens[MOS2NSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *MOS2nNames[MOS2NSRCS] = { /* Note that we have to keep the order */ + "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ + "_rs", /* noise due to rs */ /* in MOS2defs.h */ + "_id", /* noise due to id */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->MOS2nextModel) { + for (inst=model->MOS2instances; inst != NULL; inst=inst->MOS2nextInstance) { + if (inst->MOS2owner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < MOS2NSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->MOS2name,MOS2nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + + case INT_NOIZ: + for (i=0; i < MOS2NSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->MOS2name,MOS2nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->MOS2name,MOS2nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[MOS2RDNOIZ],&lnNdens[MOS2RDNOIZ], + ckt,THERMNOISE,inst->MOS2dNodePrime,inst->MOS2dNode, + inst->MOS2drainConductance); + + NevalSrc(&noizDens[MOS2RSNOIZ],&lnNdens[MOS2RSNOIZ], + ckt,THERMNOISE,inst->MOS2sNodePrime,inst->MOS2sNode, + inst->MOS2sourceConductance); + + NevalSrc(&noizDens[MOS2IDNOIZ],&lnNdens[MOS2IDNOIZ], + ckt,THERMNOISE,inst->MOS2dNodePrime,inst->MOS2sNodePrime, + (2.0/3.0 * fabs(inst->MOS2gm))); + + NevalSrc(&noizDens[MOS2FLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->MOS2dNodePrime, inst->MOS2sNodePrime, + (double)0.0); + noizDens[MOS2FLNOIZ] *= model->MOS2fNcoef * + exp(model->MOS2fNexp * + log(MAX(fabs(inst->MOS2cd),N_MINLOG))) / + (data->freq * inst->MOS2w * + (inst->MOS2l - 2*model->MOS2latDiff) * + model->MOS2oxideCapFactor * model->MOS2oxideCapFactor); + lnNdens[MOS2FLNOIZ] = + log(MAX(noizDens[MOS2FLNOIZ],N_MINLOG)); + + noizDens[MOS2TOTNOIZ] = noizDens[MOS2RDNOIZ] + + noizDens[MOS2RSNOIZ] + + noizDens[MOS2IDNOIZ] + + noizDens[MOS2FLNOIZ]; + lnNdens[MOS2TOTNOIZ] = + log(MAX(noizDens[MOS2TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[MOS2TOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < MOS2NSRCS; i++) { + inst->MOS2nVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < MOS2NSRCS; i++) { + inst->MOS2nVar[OUTNOIZ][i] = 0.0; + inst->MOS2nVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + for (i=0; i < MOS2NSRCS; i++) { + if (i != MOS2TOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->MOS2nVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->MOS2nVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->MOS2nVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->MOS2nVar[OUTNOIZ][i] += tempOnoise; + inst->MOS2nVar[OUTNOIZ][MOS2TOTNOIZ] += tempOnoise; + inst->MOS2nVar[INNOIZ][i] += tempInoise; + inst->MOS2nVar[INNOIZ][MOS2TOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < MOS2NSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < MOS2NSRCS; i++) { + data->outpVector[data->outNumber++] = inst->MOS2nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->MOS2nVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2par.c b/src/spicelib/devices/mos2/mos2par.c new file mode 100644 index 000000000..24e002e2b --- /dev/null +++ b/src/spicelib/devices/mos2/mos2par.c @@ -0,0 +1,110 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MOS2param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + MOS2instance *here = (MOS2instance *)inst; + switch(param) { + case MOS2_TEMP: + here->MOS2temp = value->rValue+CONSTCtoK; + here->MOS2tempGiven = TRUE; + break; + case MOS2_W: + here->MOS2w = value->rValue; + here->MOS2wGiven = TRUE; + break; + case MOS2_L: + here->MOS2l = value->rValue; + here->MOS2lGiven = TRUE; + break; + case MOS2_AS: + here->MOS2sourceArea = value->rValue; + here->MOS2sourceAreaGiven = TRUE; + break; + case MOS2_AD: + here->MOS2drainArea = value->rValue; + here->MOS2drainAreaGiven = TRUE; + break; + case MOS2_PS: + here->MOS2sourcePerimiter = value->rValue; + here->MOS2sourcePerimiterGiven = TRUE; + break; + case MOS2_PD: + here->MOS2drainPerimiter = value->rValue; + here->MOS2drainPerimiterGiven = TRUE; + break; + case MOS2_NRS: + here->MOS2sourceSquares = value->rValue; + here->MOS2sourceSquaresGiven = TRUE; + break; + case MOS2_NRD: + here->MOS2drainSquares = value->rValue; + here->MOS2drainSquaresGiven = TRUE; + break; + case MOS2_OFF: + here->MOS2off = value->iValue; + break; + case MOS2_IC_VBS: + here->MOS2icVBS = value->rValue; + here->MOS2icVBSGiven = TRUE; + break; + case MOS2_IC_VDS: + here->MOS2icVDS = value->rValue; + here->MOS2icVDSGiven = TRUE; + break; + case MOS2_IC_VGS: + here->MOS2icVGS = value->rValue; + here->MOS2icVGSGiven = TRUE; + break; + case MOS2_IC: + switch(value->v.numValue){ + case 3: + here->MOS2icVBS = *(value->v.vec.rVec+2); + here->MOS2icVBSGiven = TRUE; + case 2: + here->MOS2icVGS = *(value->v.vec.rVec+1); + here->MOS2icVGSGiven = TRUE; + case 1: + here->MOS2icVDS = *(value->v.vec.rVec); + here->MOS2icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + case MOS2_L_SENS: + if(value->iValue) { + here->MOS2senParmNo = 1; + here->MOS2sens_l = 1; + } + break; + case MOS2_W_SENS: + if(value->iValue) { + here->MOS2senParmNo = 1; + here->MOS2sens_w = 1; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2pzld.c b/src/spicelib/devices/mos2/mos2pzld.c new file mode 100644 index 000000000..bf231d25b --- /dev/null +++ b/src/spicelib/devices/mos2/mos2pzld.c @@ -0,0 +1,134 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS2pzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + int xnrm; + int xrev; + double xgs; + double xgd; + double xgb; + double xbd; + double xbs; + double capgs; + double capgd; + double capgb; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double EffectiveLength; + + for( ; model != NULL; model = model->MOS2nextModel) { + for(here = model->MOS2instances; here!= NULL; + here = here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + if (here->MOS2mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * meyer's model parameters + */ + EffectiveLength=here->MOS2l - 2*model->MOS2latDiff; + GateSourceOverlapCap = model->MOS2gateSourceOverlapCapFactor * + here->MOS2w; + GateDrainOverlapCap = model->MOS2gateDrainOverlapCapFactor * + here->MOS2w; + GateBulkOverlapCap = model->MOS2gateBulkOverlapCapFactor * + EffectiveLength; + capgs = ( 2* *(ckt->CKTstate0+here->MOS2capgs)+ + GateSourceOverlapCap ); + capgd = ( 2* *(ckt->CKTstate0+here->MOS2capgd)+ + GateDrainOverlapCap ); + capgb = ( 2* *(ckt->CKTstate0+here->MOS2capgb)+ + GateBulkOverlapCap ); + xgs = capgs; + xgd = capgd; + xgb = capgb; + xbd = here->MOS2capbd; + xbs = here->MOS2capbs; + /*printf("mos2: xgs=%g, xgd=%g, xgb=%g, xbd=%g, xbs=%g\n", + xgs,xgd,xgb,xbd,xbs);*/ + /* + * load matrix + */ + + *(here->MOS2GgPtr ) += (xgd+xgs+xgb)*s->real; + *(here->MOS2GgPtr +1) += (xgd+xgs+xgb)*s->imag; + *(here->MOS2BbPtr ) += (xgb+xbd+xbs)*s->real; + *(here->MOS2BbPtr +1) += (xgb+xbd+xbs)*s->imag; + *(here->MOS2DPdpPtr ) += (xgd+xbd)*s->real; + *(here->MOS2DPdpPtr +1) += (xgd+xbd)*s->imag; + *(here->MOS2SPspPtr ) += (xgs+xbs)*s->real; + *(here->MOS2SPspPtr +1) += (xgs+xbs)*s->imag; + *(here->MOS2GbPtr ) -= xgb*s->real; + *(here->MOS2GbPtr +1) -= xgb*s->imag; + *(here->MOS2GdpPtr ) -= xgd*s->real; + *(here->MOS2GdpPtr +1) -= xgd*s->imag; + *(here->MOS2GspPtr ) -= xgs*s->real; + *(here->MOS2GspPtr +1) -= xgs*s->imag; + *(here->MOS2BgPtr ) -= xgb*s->real; + *(here->MOS2BgPtr +1) -= xgb*s->imag; + *(here->MOS2BdpPtr ) -= xbd*s->real; + *(here->MOS2BdpPtr +1) -= xbd*s->imag; + *(here->MOS2BspPtr ) -= xbs*s->real; + *(here->MOS2BspPtr +1) -= xbs*s->imag; + *(here->MOS2DPgPtr ) -= xgd*s->real; + *(here->MOS2DPgPtr +1) -= xgd*s->imag; + *(here->MOS2DPbPtr ) -= xbd*s->real; + *(here->MOS2DPbPtr +1) -= xbd*s->imag; + *(here->MOS2SPgPtr ) -= xgs*s->real; + *(here->MOS2SPgPtr +1) -= xgs*s->imag; + *(here->MOS2SPbPtr ) -= xbs*s->real; + *(here->MOS2SPbPtr +1) -= xbs*s->imag; + *(here->MOS2DdPtr) += here->MOS2drainConductance; + *(here->MOS2SsPtr) += here->MOS2sourceConductance; + *(here->MOS2BbPtr) += here->MOS2gbd+here->MOS2gbs; + *(here->MOS2DPdpPtr) += here->MOS2drainConductance+ + here->MOS2gds+here->MOS2gbd+ + xrev*(here->MOS2gm+here->MOS2gmbs); + *(here->MOS2SPspPtr) += here->MOS2sourceConductance+ + here->MOS2gds+here->MOS2gbs+ + xnrm*(here->MOS2gm+here->MOS2gmbs); + *(here->MOS2DdpPtr) -= here->MOS2drainConductance; + *(here->MOS2SspPtr) -= here->MOS2sourceConductance; + *(here->MOS2BdpPtr) -= here->MOS2gbd; + *(here->MOS2BspPtr) -= here->MOS2gbs; + *(here->MOS2DPdPtr) -= here->MOS2drainConductance; + *(here->MOS2DPgPtr) += (xnrm-xrev)*here->MOS2gm; + *(here->MOS2DPbPtr) += -here->MOS2gbd+(xnrm-xrev)*here->MOS2gmbs; + *(here->MOS2DPspPtr) -= here->MOS2gds+ + xnrm*(here->MOS2gm+here->MOS2gmbs); + *(here->MOS2SPgPtr) -= (xnrm-xrev)*here->MOS2gm; + *(here->MOS2SPsPtr) -= here->MOS2sourceConductance; + *(here->MOS2SPbPtr) -= here->MOS2gbs+(xnrm-xrev)*here->MOS2gmbs; + *(here->MOS2SPdpPtr) -= here->MOS2gds+ + xrev*(here->MOS2gm+here->MOS2gmbs); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2sacl.c b/src/spicelib/devices/mos2/mos2sacl.c new file mode 100644 index 000000000..cd014add3 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2sacl.c @@ -0,0 +1,783 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "const.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS2sAcLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + int xnrm; + int xrev; + double A0; + double Apert; + double DELA; + double DELAinv; + double gdpr0; + double gspr0; + double gds0; + double gbs0; + double gbd0; + double gm0; + double gmbs0; + double gdpr; + double gspr; + double gds; + double gbs; + double gbd; + double gm; + double gmbs; + double xcgs0; + double xcgd0; + double xcgb0; + double xbd0; + double xbs0; + double xcgs; + double xcgd; + double xcgb; + double xbd; + double xbs; + double vbsOp; + double vbdOp; + double vspr; + double vdpr; + double vgs; + double vgd; + double vgb; + double vbs; + double vbd; + double vds; + double ivspr; + double ivdpr; + double ivgs; + double ivgd; + double ivgb; + double ivbs; + double ivbd; + double ivds; + double cspr; + double cdpr; + double cgs; + double cgd; + double cgb; + double cbs; + double cbd; + double cds; + double cs0; + double csprm0; + double cd0; + double cdprm0; + double cg0; + double cb0; + double cs; + double csprm; + double cd; + double cdprm; + double cg; + double cb; + double icspr; + double icdpr; + double icgs; + double icgd; + double icgb; + double icbs; + double icbd; + double icds; + double ics0; + double icsprm0; + double icd0; + double icdprm0; + double icg0; + double icb0; + double ics; + double icsprm; + double icd; + double icdprm; + double icg; + double icb; + double DvDp; + int i; + int flag; + int error; + int iparmno; + double arg; + double sarg; + double sargsw; + double SaveState[44]; + int save_mode; + SENstruct *info; + +#ifdef SENSDEBUG + printf("MOS2senacload\n"); + printf("CKTomega = %.5e\n",ckt->CKTomega); +#endif /* SENSDEBUG */ + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + for( ; model != NULL; model = model->MOS2nextModel) { + for(here = model->MOS2instances; here!= NULL; + here = here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++) + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS2states + i); + + *(SaveState + 17) = here->MOS2sourceConductance; + *(SaveState + 18) = here->MOS2drainConductance; + *(SaveState + 19) = here->MOS2cd; + *(SaveState + 20) = here->MOS2cbs; + *(SaveState + 21) = here->MOS2cbd; + *(SaveState + 22) = here->MOS2gmbs; + *(SaveState + 23) = here->MOS2gm; + *(SaveState + 24) = here->MOS2gds; + *(SaveState + 25) = here->MOS2gbd; + *(SaveState + 26) = here->MOS2gbs; + *(SaveState + 27) = here->MOS2capbd; + *(SaveState + 28) = here->MOS2capbs; + *(SaveState + 29) = here->MOS2Cbd; + *(SaveState + 30) = here->MOS2Cbdsw; + *(SaveState + 31) = here->MOS2Cbs; + *(SaveState + 32) = here->MOS2Cbssw; + *(SaveState + 33) = here->MOS2f2d; + *(SaveState + 34) = here->MOS2f3d; + *(SaveState + 35) = here->MOS2f4d; + *(SaveState + 36) = here->MOS2f2s; + *(SaveState + 37) = here->MOS2f3s; + *(SaveState + 38) = here->MOS2f4s; + *(SaveState + 39) = here->MOS2cgs; + *(SaveState + 40) = here->MOS2cgd; + *(SaveState + 41) = here->MOS2cgb; + *(SaveState + 42) = here->MOS2vdsat; + *(SaveState + 43) = here->MOS2von; + save_mode = here->MOS2mode; + + xnrm=1; + xrev=0; + if (here->MOS2mode < 0) { + xnrm=0; + xrev=1; + } + + vbsOp = model->MOS2type * ( + *(ckt->CKTrhsOp+here->MOS2bNode) - + *(ckt->CKTrhsOp+here->MOS2sNodePrime)); + vbdOp = model->MOS2type * ( + *(ckt->CKTrhsOp+here->MOS2bNode) - + *(ckt->CKTrhsOp+here->MOS2dNodePrime)); + vspr = *(ckt->CKTrhsOld + here->MOS2sNode) + - *(ckt->CKTrhsOld + + here->MOS2sNodePrime) ; + ivspr = *(ckt->CKTirhsOld + here->MOS2sNode) + - *(ckt->CKTirhsOld + + here->MOS2sNodePrime) ; + vdpr = *(ckt->CKTrhsOld + here->MOS2dNode) + - *(ckt->CKTrhsOld + + here->MOS2dNodePrime) ; + ivdpr = *(ckt->CKTirhsOld + here->MOS2dNode) + - *(ckt->CKTirhsOld + + here->MOS2dNodePrime) ; + vgb = *(ckt->CKTrhsOld + here->MOS2gNode) + - *(ckt->CKTrhsOld + + here->MOS2bNode) ; + ivgb = *(ckt->CKTirhsOld + here->MOS2gNode) + - *(ckt->CKTirhsOld + + here->MOS2bNode) ; + vbs = *(ckt->CKTrhsOld + here->MOS2bNode) + - *(ckt->CKTrhsOld + + here->MOS2sNodePrime) ; + ivbs = *(ckt->CKTirhsOld + here->MOS2bNode) + - *(ckt->CKTirhsOld + + here->MOS2sNodePrime) ; + vbd = *(ckt->CKTrhsOld + here->MOS2bNode) + - *(ckt->CKTrhsOld + + here->MOS2dNodePrime) ; + ivbd = *(ckt->CKTirhsOld + here->MOS2bNode) + - *(ckt->CKTirhsOld + + here->MOS2dNodePrime) ; + vds = vbs - vbd ; + ivds = ivbs - ivbd ; + vgs = vgb + vbs ; + ivgs = ivgb + ivbs ; + vgd = vgb + vbd ; + ivgd = ivgb + ivbd ; + +#ifdef SENSDEBUG + printf("senacload instance name %s\n",here->MOS2name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS2gNode,here->MOS2dNode,here->MOS2dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS2sNode ,here->MOS2sNodePrime, + here->MOS2bNode,here->MOS2senParmNo); + printf("\n without perturbation \n"); +#endif /* SENSDEBUG */ + /* without perturbation */ + *(ckt->CKTstate0 + here->MOS2vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS2vbd) = vbdOp; + + here->MOS2senPertFlag = ON ; + if(info->SENacpertflag == 1){ + /* store the unperturbed values of small signal parameters */ + if((error = MOS2load((GENmodel*)model,ckt))) + return(error); + *(here->MOS2senCgs) = here->MOS2cgs; + *(here->MOS2senCgd) = here->MOS2cgd; + *(here->MOS2senCgb) = here->MOS2cgb; + *(here->MOS2senCbd) = here->MOS2capbd; + *(here->MOS2senCbs) = here->MOS2capbs; + *(here->MOS2senGds) = here->MOS2gds; + *(here->MOS2senGbs) = here->MOS2gbs; + *(here->MOS2senGbd) = here->MOS2gbd; + *(here->MOS2senGm) = here->MOS2gm; + *(here->MOS2senGmbs) = here->MOS2gmbs; + + } + xcgs0= *(here->MOS2senCgs) * ckt->CKTomega; + xcgd0= *(here->MOS2senCgd) * ckt->CKTomega; + xcgb0= *(here->MOS2senCgb) * ckt->CKTomega; + xbd0= *(here->MOS2senCbd) * ckt->CKTomega; + xbs0= *(here->MOS2senCbs) * ckt->CKTomega; + gds0= *(here->MOS2senGds); + gbs0= *(here->MOS2senGbs); + gbd0= *(here->MOS2senGbd); + gm0= *(here->MOS2senGm); + gmbs0= *(here->MOS2senGmbs); + gdpr0 = here->MOS2drainConductance; + gspr0 = here->MOS2sourceConductance; + + + cspr = gspr0 * vspr ; + icspr = gspr0 * ivspr ; + cdpr = gdpr0 * vdpr ; + icdpr = gdpr0 * ivdpr ; + cgs = ( - xcgs0 * ivgs ); + icgs = xcgs0 * vgs ; + cgd = ( - xcgd0 * ivgd ); + icgd = xcgd0 * vgd ; + cgb = ( - xcgb0 * ivgb ); + icgb = xcgb0 * vgb ; + cbs = ( gbs0 * vbs - xbs0 * ivbs ); + icbs = ( xbs0 * vbs + gbs0 * ivbs ); + cbd = ( gbd0 * vbd - xbd0 * ivbd ); + icbd = ( xbd0 * vbd + gbd0 * ivbd ); + cds = ( gds0 * vds + xnrm * (gm0 * vgs + gmbs0 * vbs) + - xrev * (gm0 * vgd + gmbs0 * vbd) ); + icds = ( gds0 * ivds + xnrm * (gm0 * ivgs + gmbs0 * ivbs) + - xrev * (gm0 * ivgd + gmbs0 * ivbd) ); + + cs0 = cspr; + ics0 = icspr; + csprm0 = ( -cspr - cgs - cbs - cds ) ; + icsprm0 = ( -icspr - icgs - icbs - icds ) ; + cd0 = cdpr; + icd0 = icdpr; + cdprm0 = ( -cdpr - cgd - cbd + cds ) ; + icdprm0 = ( -icdpr - icgd - icbd + icds ) ; + cg0 = cgs + cgd + cgb ; + icg0 = icgs + icgd + icgb ; + cb0 = cbs + cbd - cgb ; + icb0 = icbs + icbd - icgb ; +#ifdef SENSDEBUG + printf("gspr0 = %.7e , gdpr0 = %.7e , gds0 = %.7e, gbs0 = %.7e\n", + gspr0,gdpr0,gds0,gbs0); + printf("gbd0 = %.7e , gm0 = %.7e , gmbs0 = %.7e\n",gbd0,gm0,gmbs0); + printf("xcgs0 = %.7e , xcgd0 = %.7e , xcgb0 = %.7e,", + xcgs0,xcgd0,xcgb0); + printf("xbd0 = %.7e,xbs0 = %.7e\n", xbd0,xbs0); + printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); + printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); + printf("cbs0 = %.7e , cbd0 = %.7e , cgb0 = %.7e\n",cbs,cbd,cgb); + printf("cb0 = %.7e , cg0 = %.7e , cs0 = %.7e\n",cb0,cg0,cs0); + printf("csprm0 = %.7e, cd0 = %.7e, cdprm0 = %.7e\n", + csprm0,cd0,cdprm0); + printf("icb0 = %.7e , icg0 = %.7e , ics0 = %.7e\n",icb0,icg0,ics0); + printf("icsprm0 = %.7e, icd0 = %.7e, icdprm0 = %.7e\n", + icsprm0,icd0,icdprm0); + printf("\nPerturbation of vbs\n"); +#endif /* SENSDEBUG */ + + /* Perturbation of vbs */ + flag = 1; + A0 = vbsOp; + DELA = info->SENpertfac * CONSTvt0 ; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vbs */ + Apert = A0 + DELA; + *(ckt->CKTstate0 + here->MOS2vbs) = Apert; + *(ckt->CKTstate0 + here->MOS2vbd) = vbdOp; + + if((error = MOS2load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS2senCgs + 1) = here->MOS2cgs; + *(here->MOS2senCgd + 1) = here->MOS2cgd; + *(here->MOS2senCgb + 1) = here->MOS2cgb; + *(here->MOS2senCbd + 1) = here->MOS2capbd; + *(here->MOS2senCbs + 1) = here->MOS2capbs; + *(here->MOS2senGds + 1) = here->MOS2gds; + *(here->MOS2senGbs + 1) = here->MOS2gbs; + *(here->MOS2senGbd + 1) = here->MOS2gbd; + *(here->MOS2senGm + 1) = here->MOS2gm; + *(here->MOS2senGmbs + 1) = here->MOS2gmbs; + + *(ckt->CKTstate0 + here->MOS2vbs) = A0; + + + } + + goto load; + + +pertvbd: /* Perturbation of vbd */ +#ifdef SENSDEBUG + printf("\nPerturbation of vbd\n"); +#endif /* SENSDEBUG */ + + flag = 2; + A0 = vbdOp; + DELA = info->SENpertfac * CONSTvt0 + 1e-8; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vbd */ + Apert = A0 + DELA; + *(ckt->CKTstate0 + here->MOS2vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS2vbd) = Apert; + + if((error = MOS2load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS2senCgs + 2) = here->MOS2cgs; + *(here->MOS2senCgd + 2) = here->MOS2cgd; + *(here->MOS2senCgb + 2) = here->MOS2cgb; + *(here->MOS2senCbd + 2) = here->MOS2capbd; + *(here->MOS2senCbs + 2) = here->MOS2capbs; + *(here->MOS2senGds + 2) = here->MOS2gds; + *(here->MOS2senGbs + 2) = here->MOS2gbs; + *(here->MOS2senGbd + 2) = here->MOS2gbd; + *(here->MOS2senGm + 2) = here->MOS2gm; + *(here->MOS2senGmbs + 2) = here->MOS2gmbs; + + *(ckt->CKTstate0 + here->MOS2vbd) = A0; + + } + + goto load; + + +pertvgb: /* Perturbation of vgb */ +#ifdef SENSDEBUG + printf("\nPerturbation of vgb\n"); +#endif /* SENSDEBUG */ + + flag = 3; + A0 = model->MOS2type * (*(ckt->CKTrhsOp + here->MOS2gNode) + - *(ckt->CKTrhsOp + here->MOS2bNode)); + DELA = info->SENpertfac * A0 + 1e-8; + DELAinv = model->MOS2type * 1.0/DELA; + + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vgb */ + *(ckt->CKTstate0 + here->MOS2vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS2vbd) = vbdOp; + *(ckt->CKTrhsOp + here->MOS2bNode) -= DELA; + + if((error = MOS2load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS2senCgs + 3) = here->MOS2cgs; + *(here->MOS2senCgd + 3) = here->MOS2cgd; + *(here->MOS2senCgb + 3) = here->MOS2cgb; + *(here->MOS2senCbd + 3) = here->MOS2capbd; + *(here->MOS2senCbs + 3) = here->MOS2capbs; + *(here->MOS2senGds + 3) = here->MOS2gds; + *(here->MOS2senGbs + 3) = here->MOS2gbs; + *(here->MOS2senGbd + 3) = here->MOS2gbd; + *(here->MOS2senGm + 3) = here->MOS2gm; + *(here->MOS2senGmbs + 3) = here->MOS2gmbs; + + + *(ckt->CKTrhsOp + here->MOS2bNode) += DELA; + } + goto load; + +pertl: /* Perturbation of length */ + + if(here->MOS2sens_l == 0){ + goto pertw; + } +#ifdef SENSDEBUG + printf("\nPerturbation of length\n"); +#endif /* SENSDEBUG */ + flag = 4; + A0 = here->MOS2l; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed length */ + Apert = A0 + DELA; + here->MOS2l = Apert; + + *(ckt->CKTstate0 + here->MOS2vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS2vbd) = vbdOp; + + if((error = MOS2load((GENmodel*)model,ckt))) return(error); + + *(here->MOS2senCgs + 4) = here->MOS2cgs; + *(here->MOS2senCgd + 4) = here->MOS2cgd; + *(here->MOS2senCgb + 4) = here->MOS2cgb; + *(here->MOS2senCbd + 4) = here->MOS2capbd; + *(here->MOS2senCbs + 4) = here->MOS2capbs; + *(here->MOS2senGds + 4) = here->MOS2gds; + *(here->MOS2senGbs + 4) = here->MOS2gbs; + *(here->MOS2senGbd + 4) = here->MOS2gbd; + *(here->MOS2senGm + 4) = here->MOS2gm; + *(here->MOS2senGmbs + 4) = here->MOS2gmbs; + + here->MOS2l = A0; + + } + + goto load; + +pertw: /* Perturbation of width */ + if(here->MOS2sens_w == 0) + goto next; +#ifdef SENSDEBUG + printf("\nPerturbation of width\n"); +#endif /* SENSDEBUG */ + flag = 5; + A0 = here->MOS2w; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed width */ + here->MOS2w = Apert; + here->MOS2drainArea *= (1 + info->SENpertfac); + here->MOS2sourceArea *= (1 + info->SENpertfac); + here->MOS2Cbd *= (1 + info->SENpertfac); + here->MOS2Cbs *= (1 + info->SENpertfac); + if(here->MOS2drainPerimiter){ + here->MOS2Cbdsw += here->MOS2Cbdsw * + DELA/here->MOS2drainPerimiter; + } + if(here->MOS2sourcePerimiter){ + here->MOS2Cbssw += here->MOS2Cbssw * + DELA/here->MOS2sourcePerimiter; + } + if(vbdOp >= here->MOS2tDepCap){ + arg = 1-model->MOS2fwdCapDepCoeff; + sarg = exp( (-model->MOS2bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS2bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS2f2d = here->MOS2Cbd*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctBotGradingCoeff))* sarg/arg + + here->MOS2Cbdsw*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS2f3d = here->MOS2Cbd * + model->MOS2bulkJctBotGradingCoeff * sarg/arg/ + here->MOS2tBulkPot + here->MOS2Cbdsw * + model->MOS2bulkJctSideGradingCoeff * sargsw/arg / + here->MOS2tBulkPot; + here->MOS2f4d = here->MOS2Cbd*here->MOS2tBulkPot* + (1-arg*sarg)/(1-model->MOS2bulkJctBotGradingCoeff) + + here->MOS2Cbdsw*here->MOS2tBulkPot*(1-arg*sargsw)/ + (1-model->MOS2bulkJctSideGradingCoeff) + -here->MOS2f3d/2* + (here->MOS2tDepCap*here->MOS2tDepCap) + -here->MOS2tDepCap * here->MOS2f2d; + } + if(vbsOp >= here->MOS2tDepCap){ + arg = 1-model->MOS2fwdCapDepCoeff; + sarg = exp( (-model->MOS2bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS2bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS2f2s = here->MOS2Cbs*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctBotGradingCoeff))* sarg/arg + + here->MOS2Cbssw*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS2f3s = here->MOS2Cbs * + model->MOS2bulkJctBotGradingCoeff * sarg/arg/ + here->MOS2tBulkPot + here->MOS2Cbssw * + model->MOS2bulkJctSideGradingCoeff * sargsw/arg / + here->MOS2tBulkPot; + here->MOS2f4s = here->MOS2Cbs*here->MOS2tBulkPot* + (1-arg*sarg)/(1-model->MOS2bulkJctBotGradingCoeff) + + here->MOS2Cbssw*here->MOS2tBulkPot*(1-arg*sargsw)/ + (1-model->MOS2bulkJctSideGradingCoeff) + -here->MOS2f3s/2* + (here->MOS2tDepCap*here->MOS2tDepCap) + -here->MOS2tDepCap * here->MOS2f2s; + } + + *(ckt->CKTstate0 + here->MOS2vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS2vbd) = vbdOp; + + if((error = MOS2load((GENmodel*)model,ckt))) return(error); + + *(here->MOS2senCgs + 5) = here->MOS2cgs; + *(here->MOS2senCgd + 5) = here->MOS2cgd; + *(here->MOS2senCgb + 5) = here->MOS2cgb; + *(here->MOS2senCbd + 5) = here->MOS2capbd; + *(here->MOS2senCbs + 5) = here->MOS2capbs; + *(here->MOS2senGds + 5) = here->MOS2gds; + *(here->MOS2senGbs + 5) = here->MOS2gbs; + *(here->MOS2senGbd + 5) = here->MOS2gbd; + *(here->MOS2senGm + 5) = here->MOS2gm; + *(here->MOS2senGmbs + 5) = here->MOS2gmbs; + + here->MOS2w = A0; + here->MOS2drainArea /= (1 + info->SENpertfac); + here->MOS2sourceArea /= (1 + info->SENpertfac); + } + +load: + + gds= *(here->MOS2senGds + flag); + gbs= *(here->MOS2senGbs + flag); + gbd= *(here->MOS2senGbd + flag); + gm= *(here->MOS2senGm + flag); + gmbs= *(here->MOS2senGmbs + flag); + if(flag == 5){ + gdpr = here->MOS2drainConductance * Apert/A0; + gspr = here->MOS2sourceConductance * Apert/A0; + } + else{ + gdpr = here->MOS2drainConductance; + gspr = here->MOS2sourceConductance; + } + + xcgs= *(here->MOS2senCgs + flag) * ckt->CKTomega; + xcgd= *(here->MOS2senCgd + flag) * ckt->CKTomega; + xcgb= *(here->MOS2senCgb + flag) * ckt->CKTomega; + xbd= *(here->MOS2senCbd + flag) * ckt->CKTomega; + xbs= *(here->MOS2senCbs + flag) * ckt->CKTomega; + +#ifdef SENSDEBUG + printf("flag = %d \n",flag); + printf("gspr = %.7e , gdpr = %.7e , gds = %.7e, gbs = %.7e\n", + gspr,gdpr,gds,gbs); + printf("gbd = %.7e , gm = %.7e , gmbs = %.7e\n",gbd,gm,gmbs); + printf("xcgs = %.7e , xcgd = %.7e , xcgb = %.7e,", xcgs,xcgd,xcgb); + printf("xbd = %.7e,xbs = %.7e\n", xbd,xbs); +#endif /* SENSDEBUG */ + cspr = gspr * vspr ; + icspr = gspr * ivspr ; + cdpr = gdpr * vdpr ; + icdpr = gdpr * ivdpr ; + cgs = ( - xcgs * ivgs ); + icgs = xcgs * vgs ; + cgd = ( - xcgd * ivgd ); + icgd = xcgd * vgd ; + cgb = ( - xcgb * ivgb ); + icgb = xcgb * vgb ; + cbs = ( gbs * vbs - xbs * ivbs ); + icbs = ( xbs * vbs + gbs * ivbs ); + cbd = ( gbd * vbd - xbd * ivbd ); + icbd = ( xbd * vbd + gbd * ivbd ); + cds = ( gds * vds + xnrm * (gm * vgs + gmbs * vbs) + - xrev * (gm * vgd + gmbs * vbd) ); + icds = ( gds * ivds + xnrm * (gm * ivgs + gmbs * ivbs) + - xrev * (gm * ivgd + gmbs * ivbd) ); + + cs = cspr; + ics = icspr; + csprm = ( -cspr - cgs - cbs - cds ) ; + icsprm = ( -icspr - icgs - icbs - icds ) ; + cd = cdpr; + icd = icdpr; + cdprm = ( -cdpr - cgd - cbd + cds ) ; + icdprm = ( -icdpr - icgd - icbd + icds ) ; + cg = cgs + cgd + cgb ; + icg = icgs + icgd + icgb ; + cb = cbs + cbd - cgb ; + icb = icbs + icbd - icgb ; + +#ifdef SENSDEBUG + printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); + printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); + printf("cbs = %.7e , cbd = %.7e , cgb = %.7e\n",cbs,cbd,cgb); + printf("cb = %.7e , cg = %.7e , cs = %.7e\n",cb,cg,cs); + printf("csprm = %.7e, cd = %.7e, cdprm = %.7e\n",csprm,cd,cdprm); + printf("icb = %.7e , icg = %.7e , ics = %.7e\n",icb,icg,ics); + printf("icsprm = %.7e, icd = %.7e, icdprm = %.7e\n", + icsprm,icd,icdprm); +#endif /* SENSDEBUG */ + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + if ((flag == 4) || (iparmno != here->MOS2senParmNo) ) continue; + if ((flag == 5) || (iparmno != (here->MOS2senParmNo + + here->MOS2sens_l)) ) continue; + switch(flag){ + case 1: + DvDp = model->MOS2type * + (info->SEN_Sap[here->MOS2bNode][iparmno] + - info->SEN_Sap[here->MOS2sNodePrime][iparmno]); + break; + case 2: + DvDp = model->MOS2type * + ( info->SEN_Sap[here->MOS2bNode][iparmno] + - info->SEN_Sap[here->MOS2dNodePrime][iparmno]); + break; + case 3: + DvDp = model->MOS2type * + ( info->SEN_Sap[here->MOS2gNode][iparmno] + - info->SEN_Sap[here->MOS2bNode][iparmno]); + break; + case 4: + DvDp = 1; + break; + case 5: + DvDp = 1; + break; + } + *(info->SEN_RHS[here->MOS2bNode] + iparmno) -= + ( cb - cb0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS2bNode] + iparmno) -= + ( icb - icb0) * DELAinv * DvDp; + + *(info->SEN_RHS[here->MOS2gNode] + iparmno) -= + ( cg - cg0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS2gNode] + iparmno) -= + ( icg - icg0) * DELAinv * DvDp; + + if(here->MOS2sNode != here->MOS2sNodePrime){ + *(info->SEN_RHS[here->MOS2sNode] + iparmno) -= + ( cs - cs0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS2sNode] + iparmno) -= + ( ics - ics0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS2sNodePrime] + iparmno) -= + ( csprm - csprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS2sNodePrime] + iparmno) -= + ( icsprm - icsprm0) * DELAinv * DvDp; + + if(here->MOS2dNode != here->MOS2dNodePrime){ + *(info->SEN_RHS[here->MOS2dNode] + iparmno) -= + ( cd - cd0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS2dNode] + iparmno) -= + ( icd - icd0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS2dNodePrime] + iparmno) -= + ( cdprm - cdprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS2dNodePrime] + iparmno) -= + ( icdprm - icdprm0) * DELAinv * DvDp; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("DvDp = %.5e , DELAinv = %.5e ,flag = %d ,", + DvDp,DELAinv,flag); + printf("iparmno = %d,senparmno = %d\n" + ,iparmno,here->MOS2senParmNo); + printf("A0 = %.5e , Apert = %.5e ,CONSTvt0 = %.5e \n", + A0,Apert,CONSTvt0); + printf("senb = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS2bNode] + iparmno), + *(info->SEN_iRHS[here->MOS2bNode] + iparmno)); + printf("seng = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS2gNode] + iparmno), + *(info->SEN_iRHS[here->MOS2gNode] + iparmno)); + printf("sens = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS2sNode] + iparmno), + *(info->SEN_iRHS[here->MOS2sNode] + iparmno)); + printf("sensprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS2sNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS2sNodePrime] + iparmno)); + printf("send = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS2dNode] + iparmno), + *(info->SEN_iRHS[here->MOS2dNode] + iparmno)); + printf("sendprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS2dNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS2dNodePrime] + iparmno)); +#endif /* SENSDEBUG */ + + } + switch(flag){ + case 1: + goto pertvbd ; + case 2: + goto pertvgb ; + case 3: + goto pertl ; + case 4: + goto pertw ; + case 5: + break; + } +next: + ; + + /* put the unperturbed values back into the state vector */ + for(i=0; i <= 16; i++) + *(ckt->CKTstate0 + here->MOS2states + i) = *(SaveState + i); + + here->MOS2sourceConductance = *(SaveState + 17) ; + here->MOS2drainConductance = *(SaveState + 18) ; + here->MOS2cd = *(SaveState + 19) ; + here->MOS2cbs = *(SaveState + 20) ; + here->MOS2cbd = *(SaveState + 21) ; + here->MOS2gmbs = *(SaveState + 22) ; + here->MOS2gm = *(SaveState + 23) ; + here->MOS2gds = *(SaveState + 24) ; + here->MOS2gbd = *(SaveState + 25) ; + here->MOS2gbs = *(SaveState + 26) ; + here->MOS2capbd = *(SaveState + 27) ; + here->MOS2capbs = *(SaveState + 28) ; + here->MOS2Cbd = *(SaveState + 29) ; + here->MOS2Cbdsw = *(SaveState + 30) ; + here->MOS2Cbs = *(SaveState + 31) ; + here->MOS2Cbssw = *(SaveState + 32) ; + here->MOS2f2d = *(SaveState + 33) ; + here->MOS2f3d = *(SaveState + 34) ; + here->MOS2f4d = *(SaveState + 35) ; + here->MOS2f2s = *(SaveState + 36) ; + here->MOS2f3s = *(SaveState + 37) ; + here->MOS2f4s = *(SaveState + 38) ; + here->MOS2cgs = *(SaveState + 39) ; + here->MOS2cgd = *(SaveState + 40) ; + here->MOS2cgb = *(SaveState + 41) ; + here->MOS2vdsat = *(SaveState + 42) ; + here->MOS2von = *(SaveState + 43) ; + here->MOS2mode = save_mode ; + + here->MOS2senPertFlag = OFF; + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS2senacload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + + diff --git a/src/spicelib/devices/mos2/mos2set.c b/src/spicelib/devices/mos2/mos2set.c new file mode 100644 index 000000000..5e50bfb81 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2set.c @@ -0,0 +1,248 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "const.h" +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS2setup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; + /* load the MOS2 device structure with those pointers needed later + * for fast matrix loading + */ +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + int error; + CKTnode *tmp; + + /* loop through all the MOS2 device models */ + for( ; model != NULL; model = model->MOS2nextModel ) { + + if(!model->MOS2typeGiven) { + model->MOS2type = NMOS; + } + if(!model->MOS2latDiffGiven) { + model->MOS2latDiff = 0; + } + if(!model->MOS2jctSatCurDensityGiven) { + model->MOS2jctSatCurDensity = 0; + } + if(!model->MOS2jctSatCurGiven) { + model->MOS2jctSatCur = 1e-14; + } + if(!model->MOS2drainResistanceGiven) { + model->MOS2drainResistance = 0; + } + if(!model->MOS2sourceResistanceGiven) { + model->MOS2sourceResistance = 0; + } + if(!model->MOS2sheetResistanceGiven) { + model->MOS2sheetResistance = 0; + } + if(!model->MOS2gateSourceOverlapCapFactorGiven) { + model->MOS2gateSourceOverlapCapFactor = 0; + } + if(!model->MOS2gateDrainOverlapCapFactorGiven) { + model->MOS2gateDrainOverlapCapFactor = 0; + } + if(!model->MOS2gateBulkOverlapCapFactorGiven) { + model->MOS2gateBulkOverlapCapFactor = 0; + } + if(!model->MOS2vt0Given) { + model->MOS2vt0 = 0; + } + if(!model->MOS2bulkJctPotentialGiven) { + model->MOS2bulkJctPotential = .8; + } + if(!model->MOS2capBDGiven) { + model->MOS2capBD = 0; + } + if(!model->MOS2capBSGiven) { + model->MOS2capBS = 0; + } + if(!model->MOS2sideWallCapFactorGiven) { + model->MOS2sideWallCapFactor = 0; + } + if(!model->MOS2bulkJctBotGradingCoeffGiven) { + model->MOS2bulkJctBotGradingCoeff = .5; + } + if(!model->MOS2bulkJctSideGradingCoeffGiven) { + model->MOS2bulkJctSideGradingCoeff = .33; + } + if(!model->MOS2fwdCapDepCoeffGiven) { + model->MOS2fwdCapDepCoeff = .5; + } + if(!model->MOS2phiGiven) { + model->MOS2phi = .6; + } + if(!model->MOS2lambdaGiven) { + model->MOS2lambda = 0; + } + if(!model->MOS2gammaGiven) { + model->MOS2gamma = 0; + } + if(!model->MOS2narrowFactorGiven) { + model->MOS2narrowFactor = 0; + } + if(!model->MOS2critFieldExpGiven) { + model->MOS2critFieldExp = 0; + } + if(!model->MOS2critFieldGiven) { + model->MOS2critField = 1e4; + } + if(!model->MOS2maxDriftVelGiven) { + model->MOS2maxDriftVel = 0; + } + if(!model->MOS2junctionDepthGiven) { + model->MOS2junctionDepth = 0; + } + if(!model->MOS2channelChargeGiven) { + model->MOS2channelCharge = 1; + } + if(!model->MOS2fastSurfaceStateDensityGiven) { + model->MOS2fastSurfaceStateDensity = 0; + } + if(!model->MOS2fNcoefGiven) { + model->MOS2fNcoef = 0; + } + if(!model->MOS2fNexpGiven) { + model->MOS2fNexp = 1; + } + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + + if (here->MOS2owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->MOS2states = *states; + *states += MOS2numStates; + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ + *states += 10 * (ckt->CKTsenInfo->SENparms); + } + } + + if(!here->MOS2drainPerimiterGiven) { + here->MOS2drainPerimiter = 0; + } + if(!here->MOS2icVBSGiven) { + here->MOS2icVBS = 0; + } + if(!here->MOS2icVDSGiven) { + here->MOS2icVDS = 0; + } + if(!here->MOS2icVGSGiven) { + here->MOS2icVGS = 0; + } + if(!here->MOS2sourcePerimiterGiven) { + here->MOS2sourcePerimiter = 0; + } + if(!here->MOS2vdsatGiven) { + here->MOS2vdsat = 0; + } + if (!here->MOS2drainSquaresGiven) { + here->MOS2drainSquares=1; + } + if (!here->MOS2sourceSquaresGiven) { + here->MOS2sourceSquares=1; + } + if ((model->MOS2drainResistance != 0 + || (here->MOS2drainSquares != 0 + && model->MOS2sheetResistance != 0)) + && here->MOS2dNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS2name,"internal#drain"); + if(error) return(error); + here->MOS2dNodePrime = tmp->number; + } else { + here->MOS2dNodePrime = here->MOS2dNode; + } + + if( ( (model->MOS2sourceResistance != 0) || + ((here->MOS2sourceSquares != 0) && + (model->MOS2sheetResistance != 0)) ) && + (here->MOS2sNodePrime==0) ) { + error = CKTmkVolt(ckt,&tmp,here->MOS2name,"internal#source"); + if(error) return(error); + here->MOS2sNodePrime = tmp->number; + } else { + here->MOS2sNodePrime = here->MOS2sNode; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(MOS2DdPtr, MOS2dNode, MOS2dNode) + TSTALLOC(MOS2GgPtr, MOS2gNode, MOS2gNode) + TSTALLOC(MOS2SsPtr, MOS2sNode, MOS2sNode) + TSTALLOC(MOS2BbPtr, MOS2bNode, MOS2bNode) + TSTALLOC(MOS2DPdpPtr, MOS2dNodePrime, MOS2dNodePrime) + TSTALLOC(MOS2SPspPtr, MOS2sNodePrime, MOS2sNodePrime) + TSTALLOC(MOS2DdpPtr, MOS2dNode, MOS2dNodePrime) + TSTALLOC(MOS2GbPtr, MOS2gNode, MOS2bNode) + TSTALLOC(MOS2GdpPtr, MOS2gNode, MOS2dNodePrime) + TSTALLOC(MOS2GspPtr, MOS2gNode, MOS2sNodePrime) + TSTALLOC(MOS2SspPtr, MOS2sNode, MOS2sNodePrime) + TSTALLOC(MOS2BdpPtr, MOS2bNode, MOS2dNodePrime) + TSTALLOC(MOS2BspPtr, MOS2bNode, MOS2sNodePrime) + TSTALLOC(MOS2DPspPtr, MOS2dNodePrime, MOS2sNodePrime) + TSTALLOC(MOS2DPdPtr, MOS2dNodePrime, MOS2dNode) + TSTALLOC(MOS2BgPtr, MOS2bNode, MOS2gNode) + TSTALLOC(MOS2DPgPtr, MOS2dNodePrime, MOS2gNode) + TSTALLOC(MOS2SPgPtr, MOS2sNodePrime, MOS2gNode) + TSTALLOC(MOS2SPsPtr, MOS2sNodePrime, MOS2sNode) + TSTALLOC(MOS2DPbPtr, MOS2dNodePrime, MOS2bNode) + TSTALLOC(MOS2SPbPtr, MOS2sNodePrime, MOS2bNode) + TSTALLOC(MOS2SPdpPtr, MOS2sNodePrime, MOS2dNodePrime) + + } + } + return(OK); +} + +int +MOS2unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + MOS2model *model; + MOS2instance *here; + + for (model = (MOS2model *)inModel; model != NULL; + model = model->MOS2nextModel) + { + for (here = model->MOS2instances; here != NULL; + here=here->MOS2nextInstance) + { + if (here->MOS2sNodePrime + && here->MOS2sNodePrime != here->MOS2sNode) + { + CKTdltNNum(ckt, here->MOS2sNodePrime); + here->MOS2sNodePrime = 0; + } + if (here->MOS2dNodePrime + && here->MOS2dNodePrime != here->MOS2dNode) + { + CKTdltNNum(ckt, here->MOS2dNodePrime); + here->MOS2dNodePrime = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/mos2/mos2sld.c b/src/spicelib/devices/mos2/mos2sld.c new file mode 100644 index 000000000..0a31d6914 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2sld.c @@ -0,0 +1,624 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS2sLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + double SaveState[44]; + int save_mode; + int i; + int iparmno; + int error; + int flag; + double A0; + double DELA; + double Apert; + double DELAinv; + double gspr0; + double gspr; + double gdpr0; + double gdpr; + double cdpr0; + double cspr0; + double cd0; + double cbd0; + double cbs0; + double cd; + double cbd; + double cbs; + double DcdprDp; + double DcsprDp; + double DcbDp; + double DcdDp; + double DcbsDp; + double DcbdDp; + double DcdprmDp; + double DcsprmDp; + double qgs0; + double qgd0; + double qgb0; + double qbd0; + double qbd; + double qbs0; + double qbs; + double DqgsDp; + double DqgdDp; + double DqgbDp; + double DqbdDp; + double DqbsDp; + double Osxpgs; + double Osxpgd; + double Osxpgb; + double Osxpbd; + double Osxpbs; + double tag0; + double tag1; + double arg; + double sarg; + double sargsw; + int offset; + double EffectiveLength; + SENstruct *info; + +#ifdef SENSDEBUG + printf("MOS2senload \n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); + printf("CKTorder = %d\n",ckt->CKTorder); +#endif /* SENSDEBUG */ + + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + + tag0 = ckt->CKTag[0]; + tag1 = ckt->CKTag[1]; + if(ckt->CKTorder == 1){ + tag1 = 0; + } + + /* loop through all the models */ + for( ; model != NULL; model = model->MOS2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("senload instance name %s\n",here->MOS2name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS2gNode,here->MOS2dNode,here->MOS2dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS2sNode ,here->MOS2sNodePrime, + here->MOS2bNode,here->MOS2senParmNo); +#endif /* SENSDEBUG */ + + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++){ + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS2states + i); + } + + *(SaveState + 17) = here->MOS2sourceConductance; + *(SaveState + 18) = here->MOS2drainConductance; + *(SaveState + 19) = here->MOS2cd; + *(SaveState + 20) = here->MOS2cbs; + *(SaveState + 21) = here->MOS2cbd; + *(SaveState + 22) = here->MOS2gmbs; + *(SaveState + 23) = here->MOS2gm; + *(SaveState + 24) = here->MOS2gds; + *(SaveState + 25) = here->MOS2gbd; + *(SaveState + 26) = here->MOS2gbs; + *(SaveState + 27) = here->MOS2capbd; + *(SaveState + 28) = here->MOS2capbs; + *(SaveState + 29) = here->MOS2Cbd; + *(SaveState + 30) = here->MOS2Cbdsw; + *(SaveState + 31) = here->MOS2Cbs; + *(SaveState + 32) = here->MOS2Cbssw; + *(SaveState + 33) = here->MOS2f2d; + *(SaveState + 34) = here->MOS2f3d; + *(SaveState + 35) = here->MOS2f4d; + *(SaveState + 36) = here->MOS2f2s; + *(SaveState + 37) = here->MOS2f3s; + *(SaveState + 38) = here->MOS2f4s; + *(SaveState + 39) = here->MOS2cgs; + *(SaveState + 40) = here->MOS2cgd; + *(SaveState + 41) = here->MOS2cgb; + *(SaveState + 42) = here->MOS2vdsat; + *(SaveState + 43) = here->MOS2von; + save_mode = here->MOS2mode; + + + if(here->MOS2senParmNo == 0) goto next1; + +#ifdef SENSDEBUG + printf("without perturbation \n"); + printf("gbd =%.5e\n",here->MOS2gbd); + printf("satCur =%.5e\n",here->MOS2tSatCur); + printf("satCurDens =%.5e\n",here->MOS2tSatCurDens); + printf("vbd =%.5e\n",*(ckt->CKTstate0 + here->MOS2vbd)); +#endif /* SENSDEBUG */ + + cdpr0= here->MOS2cd; + cspr0= -(here->MOS2cd + here->MOS2cbd + here->MOS2cbs); + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)){ + qgs0 = *(ckt->CKTstate1 + here->MOS2qgs); + qgd0 = *(ckt->CKTstate1 + here->MOS2qgd); + qgb0 = *(ckt->CKTstate1 + here->MOS2qgb); + } + else{ + qgs0 = *(ckt->CKTstate0 + here->MOS2qgs); + qgd0 = *(ckt->CKTstate0 + here->MOS2qgd); + qgb0 = *(ckt->CKTstate0 + here->MOS2qgb); + } + + here->MOS2senPertFlag = ON; + error = MOS2load((GENmodel*)model,ckt); + if(error) return(error); + + cd0 = here->MOS2cd ; + cbd0 = here->MOS2cbd ; + cbs0 = here->MOS2cbs ; + gspr0= here->MOS2sourceConductance ; + gdpr0= here->MOS2drainConductance ; + + qbs0 = *(ckt->CKTstate0 + here->MOS2qbs); + qbd0 = *(ckt->CKTstate0 + here->MOS2qbd); + + for( flag = 0 ; flag <= 1 ; flag++){ + if(here->MOS2sens_l == 0) + if(flag == 0) goto next2; + if(here->MOS2sens_w == 0) + if(flag == 1) goto next2; + if(flag == 0){ + A0 = here->MOS2l; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS2l = Apert; + } + else{ + A0 = here->MOS2w; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS2w = Apert; + here->MOS2drainArea *= (1 + info->SENpertfac); + here->MOS2sourceArea *= (1 + info->SENpertfac); + here->MOS2Cbd *= (1 + info->SENpertfac); + here->MOS2Cbs *= (1 + info->SENpertfac); + if(here->MOS2drainPerimiter){ + here->MOS2Cbdsw += here->MOS2Cbdsw * + DELA/here->MOS2drainPerimiter; + } + if(here->MOS2sourcePerimiter){ + here->MOS2Cbssw += here->MOS2Cbssw * + DELA/here->MOS2sourcePerimiter; + } + if(*(ckt->CKTstate0 + here->MOS2vbd) >= + here->MOS2tDepCap){ + arg = 1-model->MOS2fwdCapDepCoeff; + sarg = exp( (-model->MOS2bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS2bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS2f2d = here->MOS2Cbd* + (1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctBotGradingCoeff))* sarg/arg + + here->MOS2Cbdsw*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS2f3d = here->MOS2Cbd * + model->MOS2bulkJctBotGradingCoeff * sarg/arg/ + here->MOS2tBulkPot + here->MOS2Cbdsw * + model->MOS2bulkJctSideGradingCoeff * + sargsw/arg / here->MOS2tBulkPot; + here->MOS2f4d = here->MOS2Cbd* + here->MOS2tBulkPot*(1-arg*sarg)/ + (1-model->MOS2bulkJctBotGradingCoeff) + + here->MOS2Cbdsw*here->MOS2tBulkPot* + (1-arg*sargsw)/ + (1-model->MOS2bulkJctSideGradingCoeff) + -here->MOS2f3d/2* + (here->MOS2tDepCap*here->MOS2tDepCap) + -here->MOS2tDepCap * here->MOS2f2d; + } + if(*(ckt->CKTstate0 + here->MOS2vbs) >= + here->MOS2tDepCap){ + arg = 1-model->MOS2fwdCapDepCoeff; + sarg = exp( (-model->MOS2bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS2bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS2f2s = here->MOS2Cbs* + (1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctBotGradingCoeff))* sarg/arg + + here->MOS2Cbssw*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS2f3s = here->MOS2Cbs * + model->MOS2bulkJctBotGradingCoeff * sarg/arg/ + here->MOS2tBulkPot + here->MOS2Cbssw * + model->MOS2bulkJctSideGradingCoeff *sargsw/arg / + here->MOS2tBulkPot; + here->MOS2f4s = here->MOS2Cbs*here->MOS2tBulkPot* + (1-arg*sarg)/ + (1-model->MOS2bulkJctBotGradingCoeff) + + here->MOS2Cbssw*here->MOS2tBulkPot* + (1-arg*sargsw)/ + (1-model->MOS2bulkJctSideGradingCoeff) + -here->MOS2f3s/2* + (here->MOS2tDepCap*here->MOS2tDepCap) + -here->MOS2tDepCap * here->MOS2f2s; + } + here->MOS2drainConductance *= Apert/A0; + here->MOS2sourceConductance *= Apert/A0; + } + + +#ifdef SENSDEBUG + if(flag == 0) + printf("perturbation of l\n"); + if(flag == 1) + printf("perturbation of w\n"); +#endif /* SENSDEBUG */ + + error = MOS2load((GENmodel*)model,ckt); + if(error) return(error); + + if(flag == 0){ + here->MOS2l = A0; + } + else{ + here->MOS2w = A0; + here->MOS2drainArea /= (1 + info->SENpertfac); + here->MOS2sourceArea /= (1 + info->SENpertfac); + here->MOS2drainConductance *= A0/Apert; + here->MOS2sourceConductance *= A0/Apert; + } + cd = here->MOS2cd ; + cbd = here->MOS2cbd ; + cbs = here->MOS2cbs ; + + gspr= here->MOS2sourceConductance ; + gdpr= here->MOS2drainConductance ; + + DcdDp = (cd - cd0) * DELAinv; + DcbsDp = (cbs - cbs0) * DELAinv; + DcbdDp = (cbd - cbd0) * DELAinv; + DcbDp = ( DcbsDp + DcbdDp ); + + DcdprDp = 0; + DcsprDp = 0; + if(here->MOS2dNode != here->MOS2dNodePrime) + if(gdpr0) DcdprDp = cdpr0 * (gdpr - gdpr0)/gdpr0 * DELAinv; + if(here->MOS2sNode != here->MOS2sNodePrime) + if(gspr0) DcsprDp = cspr0 * (gspr - gspr0)/gspr0 * DELAinv; + + DcdprmDp = ( - DcdprDp + DcdDp); + DcsprmDp = ( - DcbsDp - DcdDp - DcbdDp - DcsprDp); + + if(flag == 0){ + EffectiveLength = here->MOS2l + - 2*model->MOS2latDiff; + if(EffectiveLength == 0){ + DqgsDp = 0; + DqgdDp = 0; + DqgbDp = 0; + } + else{ + DqgsDp = model->MOS2type * qgs0 / EffectiveLength; + DqgdDp = model->MOS2type * qgd0 / EffectiveLength; + DqgbDp = model->MOS2type * qgb0 / EffectiveLength; + } + } + else{ + DqgsDp = model->MOS2type * qgs0 / here->MOS2w; + DqgdDp = model->MOS2type * qgd0 / here->MOS2w; + DqgbDp = model->MOS2type * qgb0 / here->MOS2w; + } + + + qbd = *(ckt->CKTstate0 + here->MOS2qbd); + qbs = *(ckt->CKTstate0 + here->MOS2qbs); + + DqbsDp = model->MOS2type * (qbs - qbs0)*DELAinv; + DqbdDp = model->MOS2type * (qbd - qbd0)*DELAinv; + + if(flag == 0){ + *(here->MOS2dphigs_dl) = DqgsDp; + *(here->MOS2dphigd_dl) = DqgdDp; + *(here->MOS2dphibs_dl) = DqbsDp; + *(here->MOS2dphibd_dl) = DqbdDp; + *(here->MOS2dphigb_dl) = DqgbDp; + } + else{ + *(here->MOS2dphigs_dw) = DqgsDp; + *(here->MOS2dphigd_dw) = DqgdDp; + *(here->MOS2dphibs_dw) = DqbsDp; + *(here->MOS2dphibd_dw) = DqbdDp; + *(here->MOS2dphigb_dw) = DqgbDp; + } + + +#ifdef SENSDEBUG + printf("CKTag[0]=%.7e,CKTag[1]=%.7e,flag= %d\n", + ckt->CKTag[0],ckt->CKTag[1],flag); + printf("cd0 = %.7e ,cd = %.7e,\n",cd0,cd); + printf("cbs0 = %.7e ,cbs = %.7e,\n",cbs0,cbs); + printf("cbd0 = %.7e ,cbd = %.7e,\n",cbd0,cbd); + printf("DcdprmDp = %.7e,\n",DcdprmDp); + printf("DcsprmDp = %.7e,\n",DcsprmDp); + printf("DcdprDp = %.7e,\n",DcdprDp); + printf("DcsprDp = %.7e,\n",DcsprDp); + printf("qgs0 = %.7e \n",qgs0); + printf("qgd0 = %.7e \n",qgd0); + printf("qgb0 = %.7e \n",qgb0); + printf("qbs0 = %.7e ,qbs = %.7e,\n",qbs0,qbs); + printf("qbd0 = %.7e ,qbd = %.7e,\n",qbd0,qbd); + printf("DqgsDp = %.7e \n",DqgsDp); + printf("DqgdDp = %.7e \n",DqgdDp); + printf("DqgbDp = %.7e \n",DqgbDp); + printf("DqbsDp = %.7e \n",DqbsDp); + printf("DqbdDp = %.7e \n",DqbdDp); + printf("EffectiveLength = %.7e \n",EffectiveLength); + printf("tdepCap = %.7e \n",here->MOS2tDepCap); + printf("\n"); +#endif /* SENSDEBUG*/ + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) + goto next2; + + /* + * load RHS matrix + */ + + if(flag == 0){ + *(info->SEN_RHS[here->MOS2bNode] + here->MOS2senParmNo) -= + model->MOS2type * DcbDp; + *(info->SEN_RHS[here->MOS2dNode] + here->MOS2senParmNo) -= + model->MOS2type * DcdprDp; + *(info->SEN_RHS[here->MOS2dNodePrime] + here->MOS2senParmNo) + -= model->MOS2type * DcdprmDp; + *(info->SEN_RHS[here->MOS2sNode] + here->MOS2senParmNo) -= + model->MOS2type * DcsprDp; + *(info->SEN_RHS[here->MOS2sNodePrime] + here->MOS2senParmNo) + -= model->MOS2type * DcsprmDp; + } + else{ + offset = here->MOS2sens_l; + + *(info->SEN_RHS[here->MOS2bNode] + here->MOS2senParmNo + + offset) -= model->MOS2type * DcbDp; + *(info->SEN_RHS[here->MOS2dNode] + here->MOS2senParmNo + + offset) -= model->MOS2type * DcdprDp; + *(info->SEN_RHS[here->MOS2dNodePrime] + here->MOS2senParmNo + + offset) -= model->MOS2type * DcdprmDp; + *(info->SEN_RHS[here->MOS2sNode] + here->MOS2senParmNo + + offset) -= model->MOS2type * DcsprDp; + *(info->SEN_RHS[here->MOS2sNodePrime] + here->MOS2senParmNo + + offset) -= model->MOS2type * DcsprmDp; + } +#ifdef SENSDEBUG + printf("after loading\n"); + if(flag == 0){ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS2bNode] + + here->MOS2senParmNo)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNode] + + here->MOS2senParmNo)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNode] + + here->MOS2senParmNo)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNodePrime] + + here->MOS2senParmNo)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNodePrime] + + here->MOS2senParmNo)); + printf("\n"); + } + else{ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS2bNode] + + here->MOS2senParmNo + here->MOS2sens_l)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNode] + + here->MOS2senParmNo + here->MOS2sens_l)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNode] + + here->MOS2senParmNo + here->MOS2sens_l)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNodePrime] + + here->MOS2senParmNo + here->MOS2sens_l)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNodePrime] + + here->MOS2senParmNo + here->MOS2sens_l)); + } +#endif /* SENSDEBUG*/ +next2: + ; + } +next1: + if((info->SENmode == DCSEN) || + (ckt->CKTmode&MODETRANOP) ) goto restore; + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) goto restore; + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ +#ifdef SENSDEBUG + printf("after conductive currents\n"); + printf("iparmno = %d\n",iparmno); + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS2bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNodePrime] + iparmno)); + printf("\n"); +#endif /* SENSDEBUG */ + Osxpgs = tag0 * *(ckt->CKTstate1 + here->MOS2sensxpgs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS2sensxpgs + + 10*(iparmno - 1) + 1); + + Osxpgd = tag0 * *(ckt->CKTstate1 + here->MOS2sensxpgd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS2sensxpgd + + 10*(iparmno - 1) + 1); + + Osxpbs = tag0 * *(ckt->CKTstate1 + here->MOS2sensxpbs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS2sensxpbs + + 10*(iparmno - 1) + 1); + + Osxpbd =tag0 * *(ckt->CKTstate1 + here->MOS2sensxpbd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS2sensxpbd + + 10*(iparmno - 1) + 1); + Osxpgb = tag0 * *(ckt->CKTstate1 + here->MOS2sensxpgb + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS2sensxpgb + + 10*(iparmno - 1) + 1); + +#ifdef SENSDEBUG + printf("iparmno=%d\n",iparmno); + printf("sxpgs=%.7e,sdgs=%.7e\n", + *(ckt->CKTstate1 + here->MOS2sensxpgs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS2sensxpgs + 10*(iparmno - 1) + 1)); + printf("sxpgd=%.7e,sdgd=%.7e\n", + *(ckt->CKTstate1 + here->MOS2sensxpgd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS2sensxpgd + 10*(iparmno - 1) + 1)); + printf("sxpbs=%.7e,sdbs=%.7e\n", + *(ckt->CKTstate1 + here->MOS2sensxpbs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS2sensxpbs + 10*(iparmno - 1) + 1)); + printf("sxpbd=%.7e,sdbd=%.7e\n", + *(ckt->CKTstate1 + here->MOS2sensxpbd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS2sensxpbd + 10*(iparmno - 1) + 1)); + printf("sxpgb=%.7e,sdgb=%.7e\n", + *(ckt->CKTstate1 + here->MOS2sensxpgb + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS2sensxpgb + 10*(iparmno - 1) + 1)); + printf("before loading DqDp\n"); + printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); + printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", + Osxpbs,Osxpbd,Osxpgb); + printf("\n"); +#endif /* SENSDEBUG */ + if(here->MOS2sens_l && (iparmno == here->MOS2senParmNo)){ + Osxpgs -= tag0 * *(here->MOS2dphigs_dl); + Osxpgd -= tag0 * *(here->MOS2dphigd_dl); + Osxpbs -= tag0 * *(here->MOS2dphibs_dl); + Osxpbd -= tag0 * *(here->MOS2dphibd_dl); + Osxpgb -= tag0 * *(here->MOS2dphigb_dl); + } + if(here->MOS2sens_w && + (iparmno == (here->MOS2senParmNo + here->MOS2sens_l))){ + Osxpgs -= tag0 * *(here->MOS2dphigs_dw); + Osxpgd -= tag0 * *(here->MOS2dphigd_dw); + Osxpbs -= tag0 * *(here->MOS2dphibs_dw); + Osxpbd -= tag0 * *(here->MOS2dphibd_dw); + Osxpgb -= tag0 * *(here->MOS2dphigb_dw); + } +#ifdef SENSDEBUG + printf("after loading DqDp\n"); + printf("DqgsDp=%.7e",DqgsDp); + printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); + printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", + Osxpbs,Osxpbd,Osxpgb); +#endif /* SENSDEBUG */ + + *(info->SEN_RHS[here->MOS2bNode] + iparmno) += + Osxpbs + Osxpbd -Osxpgb; + *(info->SEN_RHS[here->MOS2gNode] + iparmno) += + Osxpgs + Osxpgd + Osxpgb; + + *(info->SEN_RHS[here->MOS2dNodePrime] + iparmno) -= + Osxpgd + Osxpbd ; + + *(info->SEN_RHS[here->MOS2sNodePrime] + iparmno) -= + Osxpgs + Osxpbs; +#ifdef SENSDEBUG + printf("after capacitive currents\n"); + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS2bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS2sNodePrime] + iparmno)); +#endif /* SENSDEBUG */ + + } +restore: /* put the unperturbed values back into the state vector */ + for(i=0; i <= 16; i++) + *(ckt->CKTstate0 + here->MOS2states + i) = *(SaveState + i); + here->MOS2sourceConductance = *(SaveState + 17) ; + here->MOS2drainConductance = *(SaveState + 18) ; + here->MOS2cd = *(SaveState + 19) ; + here->MOS2cbs = *(SaveState + 20) ; + here->MOS2cbd = *(SaveState + 21) ; + here->MOS2gmbs = *(SaveState + 22) ; + here->MOS2gm = *(SaveState + 23) ; + here->MOS2gds = *(SaveState + 24) ; + here->MOS2gbd = *(SaveState + 25) ; + here->MOS2gbs = *(SaveState + 26) ; + here->MOS2capbd = *(SaveState + 27) ; + here->MOS2capbs = *(SaveState + 28) ; + here->MOS2Cbd = *(SaveState + 29) ; + here->MOS2Cbdsw = *(SaveState + 30) ; + here->MOS2Cbs = *(SaveState + 31) ; + here->MOS2Cbssw = *(SaveState + 32) ; + here->MOS2f2d = *(SaveState + 33) ; + here->MOS2f3d = *(SaveState + 34) ; + here->MOS2f4d = *(SaveState + 35) ; + here->MOS2f2s = *(SaveState + 36) ; + here->MOS2f3s = *(SaveState + 37) ; + here->MOS2f4s = *(SaveState + 38) ; + here->MOS2cgs = *(SaveState + 39) ; + here->MOS2cgd = *(SaveState + 40) ; + here->MOS2cgb = *(SaveState + 41) ; + here->MOS2vdsat = *(SaveState + 42) ; + here->MOS2von = *(SaveState + 43) ; + here->MOS2mode = save_mode ; + + here->MOS2senPertFlag = OFF; + + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS2senload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + diff --git a/src/spicelib/devices/mos2/mos2sprt.c b/src/spicelib/devices/mos2/mos2sprt.c new file mode 100644 index 000000000..a3890942d --- /dev/null +++ b/src/spicelib/devices/mos2/mos2sprt.c @@ -0,0 +1,62 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +void +MOS2sPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* Pretty print the sensitivity info for all the MOS2 + * devices in the circuit. + */ +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + + printf("LEVEL 1 MOSFETS-----------------\n"); + /* loop through all the MOS2 models */ + for( ; model != NULL; model = model->MOS2nextModel ) { + + printf("Model name:%s\n",model->MOS2modName); + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + printf(" Instance name:%s\n",here->MOS2name); + printf(" Drain, Gate , Source nodes: %s, %s ,%s\n", + CKTnodName(ckt,here->MOS2dNode),CKTnodName(ckt,here->MOS2gNode), + CKTnodName(ckt,here->MOS2sNode)); + + printf(" Length: %g ",here->MOS2l); + printf(here->MOS2lGiven ? "(specified)\n" : "(default)\n"); + printf(" Width: %g ",here->MOS2w); + printf(here->MOS2wGiven ? "(specified)\n" : "(default)\n"); + if(here->MOS2sens_l == 1){ + printf(" MOS2senParmNo:l = %d ",here->MOS2senParmNo); + } + else{ + printf(" MOS2senParmNo:l = 0 "); + } + if(here->MOS2sens_w == 1){ + printf(" w = %d \n",here->MOS2senParmNo + here->MOS2sens_l); + } + else{ + printf(" w = 0 \n"); + } + + + } + } +} + diff --git a/src/spicelib/devices/mos2/mos2sset.c b/src/spicelib/devices/mos2/mos2sset.c new file mode 100644 index 000000000..b002d7946 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2sset.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS2sSetup(info,inModel) +register SENstruct *info; +GENmodel *inModel; +/* loop through all the devices and + * allocate parameter #s to design parameters + */ +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + + /* loop through all the models */ + for( ; model != NULL; model = model->MOS2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + + if(here->MOS2senParmNo){ + if((here->MOS2sens_l)&&(here->MOS2sens_w)){ + here->MOS2senParmNo = ++(info->SENparms); + ++(info->SENparms);/* MOS has two design parameters */ + } + else{ + here->MOS2senParmNo = ++(info->SENparms); + } + } + here->MOS2senPertFlag = OFF; + if((here->MOS2sens = (double *)MALLOC(70*sizeof(double))) == NULL) { + return(E_NOMEM); + } + + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/mos2/mos2supd.c b/src/spicelib/devices/mos2/mos2supd.c new file mode 100644 index 000000000..a3a13cb3e --- /dev/null +++ b/src/spicelib/devices/mos2/mos2supd.c @@ -0,0 +1,181 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* update the charge sensitivities and their derivatives */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS2sUpdate(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + int iparmno; + double sb; + double sg; + double sdprm; + double ssprm; + double sxpgs; + double sxpgd; + double sxpbs; + double sxpbd; + double sxpgb; + double dummy1; + double dummy2; + SENstruct *info; + + + if(ckt->CKTtime == 0) return(OK); + info = ckt->CKTsenInfo; + +#ifdef SENSDEBUG + printf("MOS2senupdate\n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); +#endif /* SENSDEBUG */ + + sxpgs = 0; + sxpgd = 0; + sxpbs = 0; + sxpbd = 0; + sxpgb = 0; + dummy1 = 0; + dummy2 = 0; + + /* loop through all the MOS2 models */ + for( ; model != NULL; model = model->MOS2nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS2instances; here != NULL ; + here=here->MOS2nextInstance) { + if (here->MOS2owner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("senupdate instance name %s\n",here->MOS2name); + printf("before loading\n"); + printf("CKTag[0] = %.2e,CKTag[1] = %.2e\n", + ckt->CKTag[0],ckt->CKTag[1]); + printf("capgs = %.7e\n",here->MOS2cgs); + printf("capgd = %.7e\n",here->MOS2cgd); + printf("capgb = %.7e\n",here->MOS2cgb); + printf("capbs = %.7e\n",here->MOS2capbs); + printf("capbd = %.7e\n",here->MOS2capbd); +#endif /* SENSDEBUG */ + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + + sb = *(info->SEN_Sap[here->MOS2bNode] + iparmno); + sg = *(info->SEN_Sap[here->MOS2gNode] + iparmno); + ssprm = *(info->SEN_Sap[here->MOS2sNodePrime] + iparmno); + sdprm = *(info->SEN_Sap[here->MOS2dNodePrime] + iparmno); +#ifdef SENSDEBUG + printf("iparmno = %d\n",iparmno); + printf("sb = %.7e,sg = %.7e\n",sb,sg); + printf("ssprm = %.7e,sdprm = %.7e\n",ssprm,sdprm); +#endif /* SENSDEBUG */ + + sxpgs = (sg - ssprm) * here->MOS2cgs ; + sxpgd = (sg - sdprm) * here->MOS2cgd ; + sxpgb = (sg - sb) * here->MOS2cgb ; + sxpbs = (sb - ssprm) * here->MOS2capbs ; + sxpbd = (sb - sdprm) * here->MOS2capbd ; + + if(here->MOS2sens_l && (iparmno == here->MOS2senParmNo)){ + sxpgs += *(here->MOS2dphigs_dl); + sxpgd += *(here->MOS2dphigd_dl); + sxpbs += *(here->MOS2dphibs_dl); + sxpbd += *(here->MOS2dphibd_dl); + sxpgb += *(here->MOS2dphigb_dl); + } + if(here->MOS2sens_w && + (iparmno == (here->MOS2senParmNo+here->MOS2sens_l))){ + sxpgs += *(here->MOS2dphigs_dw); + sxpgd += *(here->MOS2dphigd_dw); + sxpbs += *(here->MOS2dphibs_dw); + sxpbd += *(here->MOS2dphibd_dw); + sxpgb += *(here->MOS2dphigb_dw); + } + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->MOS2sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate1 + here->MOS2sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate1 + here->MOS2sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate1 + here->MOS2sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate1 + here->MOS2sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + *(ckt->CKTstate1 + here->MOS2sensxpgs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS2sensxpgd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS2sensxpbs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS2sensxpbd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS2sensxpgb + + 10 * (iparmno - 1) + 1) = 0; + goto next; + } + + *(ckt->CKTstate0 + here->MOS2sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate0 + here->MOS2sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate0 + here->MOS2sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate0 + here->MOS2sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate0 + here->MOS2sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS2cgs, + here->MOS2sensxpgs + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS2cgd, + here->MOS2sensxpgd + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS2cgb, + here->MOS2sensxpgb + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS2capbs, + here->MOS2sensxpbs + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS2capbd, + here->MOS2sensxpbd + 10*(iparmno -1)); +next: + ; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("sxpgs = %.7e,sdotxpgs = %.7e\n", + sxpgs,*(ckt->CKTstate0 + here->MOS2sensxpgs + + 10 * (iparmno - 1) + 1)); + printf("sxpgd = %.7e,sdotxpgd = %.7e\n", + sxpgd,*(ckt->CKTstate0 + here->MOS2sensxpgd + + 10 * (iparmno - 1) + 1)); + printf("sxpgb = %.7e,sdotxpgb = %.7e\n", + sxpgb,*(ckt->CKTstate0 + here->MOS2sensxpgb + + 10 * (iparmno - 1) + 1)); + printf("sxpbs = %.7e,sdotxpbs = %.7e\n", + sxpbs,*(ckt->CKTstate0 + here->MOS2sensxpbs + + 10 * (iparmno - 1) + 1)); + printf("sxpbd = %.7e,sdotxpbd = %.7e\n", + sxpbd,*(ckt->CKTstate0 + here->MOS2sensxpbd + + 10 * (iparmno - 1) + 1)); +#endif /* SENSDEBUG */ + } + } + } +#ifdef SENSDEBUG + printf("MOS2senupdate end\n"); +#endif /* SENSDEBUG */ + return(OK); + +} + diff --git a/src/spicelib/devices/mos2/mos2temp.c b/src/spicelib/devices/mos2/mos2temp.c new file mode 100644 index 000000000..b5f8d8521 --- /dev/null +++ b/src/spicelib/devices/mos2/mos2temp.c @@ -0,0 +1,324 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos2defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* assuming silicon - make definition for epsilon of silicon */ +#define EPSSIL (11.7 * 8.854214871e-12) + +int +MOS2temp(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + double egfet; + double wkfngs; + double wkfng; + double fermig; + double fermis; + double vfb; + double fact1,fact2; + double vt,vtnom; + double kt,kt1; + double egfet1; + double arg1; + double pbfact,pbfact1; + double ratio,ratio4; + double phio; + double pbo; + double gmaold,gmanew; + double capfact; + /* loop through all the resistor models */ + for( ; model != NULL; model = model->MOS2nextModel) { + + /* perform model defaulting */ + + /* now model parameter preprocessing */ + if(!model->MOS2tnomGiven) { + model->MOS2tnom = ckt->CKTnomTemp; + } + fact1 = model->MOS2tnom/REFTEMP; + vtnom = model->MOS2tnom*CONSTKoverQ; + kt1 = CONSTboltz * model->MOS2tnom; + egfet1 = 1.16-(7.02e-4*model->MOS2tnom*model->MOS2tnom)/ + (model->MOS2tnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1); + + + if(!model->MOS2oxideThicknessGiven) { + model->MOS2oxideThickness = 1e-7; + } + model->MOS2oxideCapFactor = 3.9 * 8.854214871e-12/ + model->MOS2oxideThickness; + + if(!model->MOS2surfaceMobilityGiven) model->MOS2surfaceMobility=600; + if(!model->MOS2transconductanceGiven) { + model->MOS2transconductance = model->MOS2surfaceMobility + * 1e-4 /*(m**2/cm**2) */ * model->MOS2oxideCapFactor; + } + if(model->MOS2substrateDopingGiven) { + if(model->MOS2substrateDoping *1e6 /*(cm**3/m**3)*/ >1.45e16) { + if(!model->MOS2phiGiven) { + model->MOS2phi = 2*vtnom* + log(model->MOS2substrateDoping* + 1e6 /*(cm**3/m**3)*//1.45e16); + model->MOS2phi = MAX(.1,model->MOS2phi); + } + fermis = model->MOS2type * .5 * model->MOS2phi; + wkfng = 3.2; + if(!model->MOS2gateTypeGiven) model->MOS2gateType=1; + if(model->MOS2gateType != 0) { + fermig = model->MOS2type * model->MOS2gateType*.5*egfet1; + wkfng = 3.25 + .5 * egfet1 - fermig; + } + wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis); + if(!model->MOS2gammaGiven) { + model->MOS2gamma = sqrt(2 * 11.70 * 8.854214871e-12 * + CHARGE * model->MOS2substrateDoping * + 1e6 /*(cm**3/m**3)*/)/model->MOS2oxideCapFactor; + } + if(!model->MOS2vt0Given) { + if(!model->MOS2surfaceStateDensityGiven) + model->MOS2surfaceStateDensity=0; + vfb = wkfngs - + model->MOS2surfaceStateDensity * + 1e4 /*(cm**2/m**2)*/ * CHARGE/model->MOS2oxideCapFactor; + model->MOS2vt0 = vfb + model->MOS2type * + (model->MOS2gamma * sqrt(model->MOS2phi)+ + model->MOS2phi); + } else { + vfb = model->MOS2vt0 - model->MOS2type * (model->MOS2gamma* + sqrt(model->MOS2phi)+model->MOS2phi); + } + model->MOS2xd = sqrt((EPSSIL+EPSSIL)/ + (CHARGE*model->MOS2substrateDoping *1e6 /*(cm**3/m**3)*/)); + } else { + model->MOS2substrateDoping = 0; + (*(SPfrontEnd->IFerror))(ERR_FATAL,"%s: Nsub < Ni", + &(model->MOS2modName)); + return(E_BADPARM); + } + } + if(!model->MOS2bulkCapFactorGiven) { + model->MOS2bulkCapFactor = sqrt(EPSSIL*CHARGE* + model->MOS2substrateDoping* 1e6 /*cm**3/m**3*/ + /(2*model->MOS2bulkJctPotential)); + } + + + /* loop through all instances of the model */ + for(here = model->MOS2instances; here!= NULL; + here = here->MOS2nextInstance) { + double czbd; /* zero voltage bulk-drain capacitance */ + double czbdsw; /* zero voltage bulk-drain sidewall capacitance */ + double czbs; /* zero voltage bulk-source capacitance */ + double czbssw; /* zero voltage bulk-source sidewall capacitance */ + double arg; /* 1 - fc */ + double sarg; /* (1-fc) ^^ (-mj) */ + double sargsw; /* (1-fc) ^^ (-mjsw) */ + if (here->MOS2owner != ARCHme) continue; + + /* perform the parameter defaulting */ + if(!here->MOS2tempGiven) { + here->MOS2temp = ckt->CKTtemp; + } + here->MOS2mode = 1; + here->MOS2von = 0; + + vt = here->MOS2temp * CONSTKoverQ; + ratio = here->MOS2temp/model->MOS2tnom; + fact2 = here->MOS2temp/REFTEMP; + kt = here->MOS2temp * CONSTboltz; + egfet = 1.16-(7.02e-4*here->MOS2temp*here->MOS2temp)/ + (here->MOS2temp+1108); + arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); + + if(!here->MOS2drainAreaGiven) { + here->MOS2drainArea = ckt->CKTdefaultMosAD; + } + if(!here->MOS2lGiven) { + here->MOS2l = ckt->CKTdefaultMosL; + } + if(!here->MOS2sourceAreaGiven) { + here->MOS2sourceArea = ckt->CKTdefaultMosAS; + } + if(!here->MOS2wGiven) { + here->MOS2w = ckt->CKTdefaultMosW; + } + if(model->MOS2drainResistanceGiven) { + if(model->MOS2drainResistance != 0) { + here->MOS2drainConductance = 1/model->MOS2drainResistance; + } else { + here->MOS2drainConductance = 0; + } + } else if (model->MOS2sheetResistanceGiven) { + if(model->MOS2sheetResistance != 0) { + here->MOS2drainConductance = + 1/(model->MOS2sheetResistance*here->MOS2drainSquares); + } else { + here->MOS2drainConductance = 0; + } + } else { + here->MOS2drainConductance = 0; + } + if(model->MOS2sourceResistanceGiven) { + if(model->MOS2sourceResistance != 0) { + here->MOS2sourceConductance = 1/model->MOS2sourceResistance; + } else { + here->MOS2sourceConductance = 0; + } + } else if (model->MOS2sheetResistanceGiven) { + if(model->MOS2sheetResistance != 0) { + here->MOS2sourceConductance = + 1/(model->MOS2sheetResistance*here->MOS2sourceSquares); + } else { + here->MOS2sourceConductance = 0; + } + } else { + here->MOS2sourceConductance = 0; + } + if(here->MOS2l - 2 * model->MOS2latDiff <=0) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: effective channel length less than zero", + &(here->MOS2name)); + } + + ratio4 = ratio * sqrt(ratio); + here->MOS2tTransconductance = model->MOS2transconductance / ratio4; + here->MOS2tSurfMob = model->MOS2surfaceMobility/ratio4; + phio= (model->MOS2phi-pbfact1)/fact1; + here->MOS2tPhi = fact2 * phio + pbfact; + here->MOS2tVbi = + model->MOS2vt0 - model->MOS2type * + (model->MOS2gamma* sqrt(model->MOS2phi)) + +.5*(egfet1-egfet) + + model->MOS2type*.5* (here->MOS2tPhi-model->MOS2phi); + here->MOS2tVto = here->MOS2tVbi + model->MOS2type * + model->MOS2gamma * sqrt(here->MOS2tPhi); + here->MOS2tSatCur = model->MOS2jctSatCur* + exp(-egfet/vt+egfet1/vtnom); + here->MOS2tSatCurDens = model->MOS2jctSatCurDensity * + exp(-egfet/vt+egfet1/vtnom); + pbo = (model->MOS2bulkJctPotential - pbfact1)/fact1; + gmaold = (model->MOS2bulkJctPotential-pbo)/pbo; + capfact = 1/(1+model->MOS2bulkJctBotGradingCoeff* + (4e-4*(model->MOS2tnom-REFTEMP)-gmaold)); + here->MOS2tCbd = model->MOS2capBD * capfact; + here->MOS2tCbs = model->MOS2capBS * capfact; + here->MOS2tCj = model->MOS2bulkCapFactor * capfact; + capfact = 1/(1+model->MOS2bulkJctSideGradingCoeff* + (4e-4*(model->MOS2tnom-REFTEMP)-gmaold)); + here->MOS2tCjsw = model->MOS2sideWallCapFactor * capfact; + here->MOS2tBulkPot = fact2 * pbo+pbfact; + gmanew = (here->MOS2tBulkPot-pbo)/pbo; + capfact = (1+model->MOS2bulkJctBotGradingCoeff* + (4e-4*(here->MOS2temp-REFTEMP)-gmanew)); + here->MOS2tCbd *= capfact; + here->MOS2tCbs *= capfact; + here->MOS2tCj *= capfact; + capfact = (1+model->MOS2bulkJctSideGradingCoeff* + (4e-4*(here->MOS2temp-REFTEMP)-gmanew)); + here->MOS2tCjsw *= capfact; + here->MOS2tDepCap = model->MOS2fwdCapDepCoeff * here->MOS2tBulkPot; + + + if( (here->MOS2tSatCurDens == 0) || + (here->MOS2drainArea == 0) || + (here->MOS2sourceArea == 0) ) { + here->MOS2sourceVcrit = here->MOS2drainVcrit = + vt*log(vt/(CONSTroot2*here->MOS2tSatCur)); + } else { + here->MOS2drainVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS2tSatCurDens * here->MOS2drainArea)); + here->MOS2sourceVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS2tSatCurDens * here->MOS2sourceArea)); + } + if(model->MOS2capBDGiven) { + czbd = here->MOS2tCbd; + } else { + if(model->MOS2bulkCapFactorGiven) { + czbd=here->MOS2tCj*here->MOS2drainArea; + } else { + czbd=0; + } + } + if(model->MOS2sideWallCapFactorGiven) { + czbdsw= here->MOS2tCjsw * here->MOS2drainPerimiter; + } else { + czbdsw=0; + } + arg = 1-model->MOS2fwdCapDepCoeff; + sarg = exp( (-model->MOS2bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS2bulkJctSideGradingCoeff) * log(arg) ); + here->MOS2Cbd = czbd; + here->MOS2Cbdsw = czbdsw; + here->MOS2f2d = czbd*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctBotGradingCoeff))* sarg/arg + + czbdsw*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS2f3d = czbd * model->MOS2bulkJctBotGradingCoeff * sarg/arg/ + here->MOS2tBulkPot + + czbdsw * model->MOS2bulkJctSideGradingCoeff * sargsw/arg / + here->MOS2tBulkPot; + here->MOS2f4d = czbd*here->MOS2tBulkPot*(1-arg*sarg)/ + (1-model->MOS2bulkJctBotGradingCoeff) + + czbdsw*here->MOS2tBulkPot*(1-arg*sargsw)/ + (1-model->MOS2bulkJctSideGradingCoeff) + -here->MOS2f3d/2* + (here->MOS2tDepCap*here->MOS2tDepCap) + -here->MOS2tDepCap * here->MOS2f2d; + if(model->MOS2capBSGiven) { + czbs=here->MOS2tCbs; + } else { + if(model->MOS2bulkCapFactorGiven) { + czbs=here->MOS2tCj*here->MOS2sourceArea; + } else { + czbs=0; + } + } + if(model->MOS2sideWallCapFactorGiven) { + czbssw = here->MOS2tCjsw * here->MOS2sourcePerimiter; + } else { + czbssw=0; + } + arg = 1-model->MOS2fwdCapDepCoeff; + sarg = exp( (-model->MOS2bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS2bulkJctSideGradingCoeff) * log(arg) ); + here->MOS2Cbs = czbs; + here->MOS2Cbssw = czbssw; + here->MOS2f2s = czbs*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctBotGradingCoeff))* sarg/arg + + czbssw*(1-model->MOS2fwdCapDepCoeff* + (1+model->MOS2bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS2f3s = czbs * model->MOS2bulkJctBotGradingCoeff * sarg/arg/ + here->MOS2tBulkPot + + czbssw * model->MOS2bulkJctSideGradingCoeff * sargsw/arg / + here->MOS2tBulkPot; + here->MOS2f4s = czbs*here->MOS2tBulkPot*(1-arg*sarg)/ + (1-model->MOS2bulkJctBotGradingCoeff) + + czbssw*here->MOS2tBulkPot*(1-arg*sargsw)/ + (1-model->MOS2bulkJctSideGradingCoeff) + -here->MOS2f3s/2* + (here->MOS2tDepCap*here->MOS2tDepCap) + -here->MOS2tDepCap * here->MOS2f2s; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos2/mos2trun.c b/src/spicelib/devices/mos2/mos2trun.c new file mode 100644 index 000000000..8a615dbef --- /dev/null +++ b/src/spicelib/devices/mos2/mos2trun.c @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos2defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS2trunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register MOS2model *model = (MOS2model *)inModel; + register MOS2instance *here; + + for( ; model != NULL; model = model->MOS2nextModel) { + for(here=model->MOS2instances;here!=NULL;here = here->MOS2nextInstance){ + if (here->MOS2owner != ARCHme) continue; + + CKTterr(here->MOS2qgs,ckt,timeStep); + CKTterr(here->MOS2qgd,ckt,timeStep); + CKTterr(here->MOS2qgb,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/ChangeLog b/src/spicelib/devices/mos3/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/mos3/Makefile.am b/src/spicelib/devices/mos3/Makefile.am new file mode 100644 index 000000000..0006ec791 --- /dev/null +++ b/src/spicelib/devices/mos3/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libmos3.la + +libmos3_la_SOURCES = \ + mos3.c \ + mos3acld.c \ + mos3ask.c \ + mos3conv.c \ + mos3defs.h \ + mos3del.c \ + mos3dest.c \ + mos3dist.c \ + mos3dset.c \ + mos3ext.h \ + mos3ic.c \ + mos3itf.h \ + mos3load.c \ + mos3mask.c \ + mos3mdel.c \ + mos3mpar.c \ + mos3noi.c \ + mos3par.c \ + mos3pzld.c \ + mos3sacl.c \ + mos3set.c \ + mos3sld.c \ + mos3sprt.c \ + mos3sset.c \ + mos3supd.c \ + mos3temp.c \ + mos3trun.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/mos3/mos3.c b/src/spicelib/devices/mos3/mos3.c new file mode 100644 index 000000000..04c1566cb --- /dev/null +++ b/src/spicelib/devices/mos3/mos3.c @@ -0,0 +1,166 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "mos3defs.h" +#include "suffix.h" + +IFparm MOS3pTable[] = { /* parameters */ + IOPU("l", MOS3_L, IF_REAL , "Length"), + IOPU("w", MOS3_W, IF_REAL , "Width"), + IOPU("ad", MOS3_AD, IF_REAL , "Drain area"), + IOPU("as", MOS3_AS, IF_REAL , "Source area"), + IOPU("pd", MOS3_PD, IF_REAL , "Drain perimeter"), + IOPU("ps", MOS3_PS, IF_REAL , "Source perimeter"), + OP("id", MOS3_CD, IF_REAL, "Drain current"), + OPR("cd", MOS3_CD, IF_REAL, "Drain current"), + OPU("ibd", MOS3_CBD, IF_REAL, "B-D junction current"), + OPU("ibs", MOS3_CBS, IF_REAL, "B-S junction current"), + OPU("is", MOS3_CS, IF_REAL, "Source current"), + OPU("ig", MOS3_CG, IF_REAL, "Gate current"), + OPU("ib", MOS3_CB, IF_REAL, "Bulk current"), + OP("vgs", MOS3_VGS, IF_REAL, "Gate-Source voltage"), + OP("vds", MOS3_VDS, IF_REAL, "Drain-Source voltage"), + OP("vbs", MOS3_VBS, IF_REAL, "Bulk-Source voltage"), + OPU("vbd", MOS3_VBD, IF_REAL, "Bulk-Drain voltage"), + IOPU("nrd", MOS3_NRD, IF_REAL , "Drain squares"), + IOPU("nrs", MOS3_NRS, IF_REAL , "Source squares"), + IP("off", MOS3_OFF, IF_FLAG , "Device initially off"), + IOPAU("icvds", MOS3_IC_VDS, IF_REAL , "Initial D-S voltage"), + IOPAU("icvgs", MOS3_IC_VGS, IF_REAL , "Initial G-S voltage"), + IOPAU("icvbs", MOS3_IC_VBS, IF_REAL , "Initial B-S voltage"), + IOPU("ic", MOS3_IC, IF_REALVEC, "Vector of D-S, G-S, B-S voltages"), + IOPU("temp", MOS3_TEMP, IF_REAL , "Instance operating temperature"), + IP("sens_l", MOS3_L_SENS, IF_FLAG, "flag to request sensitivity WRT length"), + IP("sens_w", MOS3_W_SENS, IF_FLAG, "flag to request sensitivity WRT width"), + OPU("dnode", MOS3_DNODE, IF_INTEGER, "Number of drain node"), + OPU("gnode", MOS3_GNODE, IF_INTEGER, "Number of gate node"), + OPU("snode", MOS3_SNODE, IF_INTEGER, "Number of source node"), + OPU("bnode", MOS3_BNODE, IF_INTEGER, "Number of bulk node"), + OPU("dnodeprime", MOS3_DNODEPRIME,IF_INTEGER,"Number of internal drain node"), + OPU("snodeprime", MOS3_SNODEPRIME,IF_INTEGER,"Number of internal source node"), + OP("von", MOS3_VON, IF_REAL, "Turn-on voltage"), + OP("vdsat", MOS3_VDSAT, IF_REAL, "Saturation drain voltage"), + OPU("sourcevcrit", MOS3_SOURCEVCRIT, IF_REAL, "Critical source voltage"), + OPU("drainvcrit", MOS3_DRAINVCRIT, IF_REAL, "Critical drain voltage"), + OP("rs", MOS3_SOURCERESIST, IF_REAL, "Source resistance"), + OPU("sourceconductance", MOS3_SOURCECONDUCT, IF_REAL, "Source conductance"), + OP("rd", MOS3_DRAINRESIST, IF_REAL, "Drain resistance"), + OPU("drainconductance", MOS3_DRAINCONDUCT, IF_REAL, "Drain conductance"), + OP("gm", MOS3_GM, IF_REAL, "Transconductance"), + OP("gds", MOS3_GDS, IF_REAL, "Drain-Source conductance"), + OP("gmb", MOS3_GMBS, IF_REAL, "Bulk-Source transconductance"), + OPR("gmbs", MOS3_GMBS, IF_REAL, "Bulk-Source transconductance"), + OPU("gbd", MOS3_GBD, IF_REAL, "Bulk-Drain conductance"), + OPU("gbs", MOS3_GBS, IF_REAL, "Bulk-Source conductance"), + + OP("cbd", MOS3_CAPBD, IF_REAL, "Bulk-Drain capacitance"), + OP("cbs", MOS3_CAPBS, IF_REAL, "Bulk-Source capacitance"), + OP("cgs", MOS3_CAPGS, IF_REAL, "Gate-Source capacitance"), +/* OPR("cgs", MOS3_CGS, IF_REAL , "Gate-Source capacitance"),*/ + OP("cgd", MOS3_CAPGD, IF_REAL, "Gate-Drain capacitance"), +/* OPR("cgd", MOS3_CGD, IF_REAL , "Gate-Drain capacitance"),*/ + OP("cgb", MOS3_CAPGB, IF_REAL, "Gate-Bulk capacitance"), + + OPU("cqgs",MOS3_CQGS,IF_REAL,"Capacitance due to gate-source charge storage"), + OPU("cqgd",MOS3_CQGD, IF_REAL,"Capacitance due to gate-drain charge storage"), + OPU("cqgb",MOS3_CQGB, IF_REAL,"Capacitance due to gate-bulk charge storage"), + OPU("cqbd",MOS3_CQBD,IF_REAL,"Capacitance due to bulk-drain charge storage"), + OPU("cqbs",MOS3_CQBS,IF_REAL,"Capacitance due to bulk-source charge storage"), + + OPU("cbd0",MOS3_CAPZEROBIASBD,IF_REAL,"Zero-Bias B-D junction capacitance"), + OPU("cbdsw0",MOS3_CAPZEROBIASBDSW,IF_REAL, + "Zero-Bias B-D sidewall capacitance"), + OPU("cbs0",MOS3_CAPZEROBIASBS,IF_REAL,"Zero-Bias B-S junction capacitance"), + OPU("cbssw0",MOS3_CAPZEROBIASBSSW,IF_REAL, + "Zero-Bias B-S sidewall capacitance"), + OPU("qbs", MOS3_QBS, IF_REAL, "Bulk-Source charge storage"), + OPU("qgs", MOS3_QGS, IF_REAL, "Gate-Source charge storage"), + OPU("qgd", MOS3_QGD, IF_REAL, "Gate-Drain charge storage"), + OPU("qgb", MOS3_QGB, IF_REAL, "Gate-Bulk charge storage"), + OPU("qbd", MOS3_QBD, IF_REAL, "Bulk-Drain charge storage"), + OPU("p", MOS3_POWER, IF_REAL, "Instantaneous power"), + OPU("sens_l_dc", MOS3_L_SENS_DC, IF_REAL, "dc sensitivity wrt length"), + OPU("sens_l_real",MOS3_L_SENS_REAL, IF_REAL, + "real part of ac sensitivity wrt length"), + OPU("sens_l_imag",MOS3_L_SENS_IMAG, IF_REAL, + "imag part of ac sensitivity wrt length"), + OPU("sens_l_cplx",MOS3_L_SENS_CPLX, IF_COMPLEX, "ac sensitivity wrt length"), + OPU("sens_l_mag", MOS3_L_SENS_MAG, IF_REAL, + "sensitivity wrt l of ac magnitude"), + OPU("sens_l_ph", MOS3_L_SENS_PH, IF_REAL, "sensitivity wrt l of ac phase"), + OPU("sens_w_dc", MOS3_W_SENS_DC, IF_REAL, "dc sensitivity wrt width"), + OPU("sens_w_real",MOS3_W_SENS_REAL, IF_REAL, + "real part of ac sensitivity wrt width"), + OPU("sens_w_imag",MOS3_W_SENS_IMAG, IF_REAL, + "imag part of ac sensitivity wrt width"), + OPU("sens_w_mag", MOS3_W_SENS_MAG, IF_REAL, + "sensitivity wrt w of ac magnitude"), + OPU("sens_w_ph", MOS3_W_SENS_PH, IF_REAL, "sensitivity wrt w of ac phase"), + OPU("sens_w_cplx",MOS3_W_SENS_CPLX, IF_COMPLEX, "ac sensitivity wrt width") +}; + +IFparm MOS3mPTable[] = { /* model parameters */ + OP("type", MOS3_MOD_TYPE, IF_STRING ,"N-channel or P-channel MOS"), + IP("nmos", MOS3_MOD_NMOS, IF_FLAG ,"N type MOSfet model"), + IP("pmos", MOS3_MOD_PMOS, IF_FLAG ,"P type MOSfet model"), + IOP("vto", MOS3_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOPR("vt0", MOS3_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOP("kp", MOS3_MOD_KP, IF_REAL ,"Transconductance parameter"), + IOP("gamma", MOS3_MOD_GAMMA, IF_REAL ,"Bulk threshold parameter"), + IOP("phi", MOS3_MOD_PHI, IF_REAL ,"Surface potential"), + IOP("rd", MOS3_MOD_RD, IF_REAL ,"Drain ohmic resistance"), + IOP("rs", MOS3_MOD_RS, IF_REAL ,"Source ohmic resistance"), + IOPA("cbd", MOS3_MOD_CBD, IF_REAL ,"B-D junction capacitance"), + IOPA("cbs", MOS3_MOD_CBS, IF_REAL ,"B-S junction capacitance"), + IOP("is", MOS3_MOD_IS, IF_REAL ,"Bulk junction sat. current"), + IOP("pb", MOS3_MOD_PB, IF_REAL ,"Bulk junction potential"), + IOPA("cgso", MOS3_MOD_CGSO, IF_REAL ,"Gate-source overlap cap."), + IOPA("cgdo", MOS3_MOD_CGDO, IF_REAL ,"Gate-drain overlap cap."), + IOPA("cgbo", MOS3_MOD_CGBO, IF_REAL ,"Gate-bulk overlap cap."), + IOP("rsh", MOS3_MOD_RSH, IF_REAL ,"Sheet resistance"), + IOPA("cj", MOS3_MOD_CJ, IF_REAL ,"Bottom junction cap per area"), + IOP("mj", MOS3_MOD_MJ, IF_REAL ,"Bottom grading coefficient"), + IOPA("cjsw", MOS3_MOD_CJSW, IF_REAL ,"Side junction cap per area"), + IOP("mjsw", MOS3_MOD_MJSW, IF_REAL ,"Side grading coefficient"), + IOPU("js", MOS3_MOD_JS, IF_REAL ,"Bulk jct. sat. current density"), + IOP("tox", MOS3_MOD_TOX, IF_REAL ,"Oxide thickness"), + IOP("ld", MOS3_MOD_LD, IF_REAL ,"Lateral diffusion"), + IOP("u0", MOS3_MOD_U0, IF_REAL ,"Surface mobility"), + IOPR("uo", MOS3_MOD_U0, IF_REAL ,"Surface mobility"), + IOP("fc", MOS3_MOD_FC, IF_REAL ,"Forward bias jct. fit parm."), + IOP("nsub", MOS3_MOD_NSUB, IF_REAL ,"Substrate doping"), + IOP("tpg", MOS3_MOD_TPG, IF_INTEGER,"Gate type"), + IOP("nss", MOS3_MOD_NSS, IF_REAL ,"Surface state density"), + IOP("vmax", MOS3_MOD_VMAX, IF_REAL ,"Maximum carrier drift velocity"), + IOP("xj", MOS3_MOD_XJ, IF_REAL ,"Junction depth"), + IOP("nfs", MOS3_MOD_NFS, IF_REAL ,"Fast surface state density"), + IOP("xd", MOS3_MOD_XD, IF_REAL ,"Depletion layer width"), + IOP("alpha", MOS3_MOD_ALPHA, IF_REAL ,"Alpha"), + IOP("eta", MOS3_MOD_ETA, IF_REAL ,"Vds dependence of threshold voltage"), + IOP("delta", MOS3_MOD_DELTA, IF_REAL ,"Width effect on threshold"), + IOPR("input_delta", MOS3_DELTA, IF_REAL ,""), + IOP("theta", MOS3_MOD_THETA, IF_REAL ,"Vgs dependence on mobility"), + IOP("kappa", MOS3_MOD_KAPPA, IF_REAL ,"Kappa"), + IOPU("tnom", MOS3_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), + IOP("kf", MOS3_MOD_KF, IF_REAL ,"Flicker noise coefficient"), + IOP("af", MOS3_MOD_AF, IF_REAL ,"Flicker noise exponent") +}; + +char *MOS3names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int MOS3nSize = NUMELEMS(MOS3names); +int MOS3pTSize = NUMELEMS(MOS3pTable); +int MOS3mPTSize = NUMELEMS(MOS3mPTable); +int MOS3iSize = sizeof(MOS3instance); +int MOS3mSize = sizeof(MOS3model); diff --git a/src/spicelib/devices/mos3/mos3acld.c b/src/spicelib/devices/mos3/mos3acld.c new file mode 100644 index 000000000..a1db9e4b0 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3acld.c @@ -0,0 +1,122 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS3acLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + int xnrm; + int xrev; + double EffectiveLength; + double xgs; + double xgd; + double xgb; + double xbd; + double xbs; + double capgs; + double capgd; + double capgb; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + + for( ; model != NULL; model = model->MOS3nextModel) { + for(here = model->MOS3instances; here!= NULL; + here = here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + if (here->MOS3mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * charge oriented model parameters + */ + EffectiveLength=here->MOS3l-2*model->MOS3latDiff; + GateSourceOverlapCap = model->MOS3gateSourceOverlapCapFactor * + here->MOS3w; + GateDrainOverlapCap = model->MOS3gateDrainOverlapCapFactor * + here->MOS3w; + GateBulkOverlapCap = model->MOS3gateBulkOverlapCapFactor * + EffectiveLength; + /* + * meyer"s model parameters + */ + capgs = ( *(ckt->CKTstate0+here->MOS3capgs)+ + *(ckt->CKTstate0+here->MOS3capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS3capgd)+ + *(ckt->CKTstate0+here->MOS3capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS3capgb)+ + *(ckt->CKTstate0+here->MOS3capgb) + + GateBulkOverlapCap ); + xgs = capgs * ckt->CKTomega; + xgd = capgd * ckt->CKTomega; + xgb = capgb * ckt->CKTomega; + xbd = here->MOS3capbd * ckt->CKTomega; + xbs = here->MOS3capbs * ckt->CKTomega; + + /* + * load matrix + */ + + *(here->MOS3GgPtr +1) += xgd+xgs+xgb; + *(here->MOS3BbPtr +1) += xgb+xbd+xbs; + *(here->MOS3DPdpPtr +1) += xgd+xbd; + *(here->MOS3SPspPtr +1) += xgs+xbs; + *(here->MOS3GbPtr +1) -= xgb; + *(here->MOS3GdpPtr +1) -= xgd; + *(here->MOS3GspPtr +1) -= xgs; + *(here->MOS3BgPtr +1) -= xgb; + *(here->MOS3BdpPtr +1) -= xbd; + *(here->MOS3BspPtr +1) -= xbs; + *(here->MOS3DPgPtr +1) -= xgd; + *(here->MOS3DPbPtr +1) -= xbd; + *(here->MOS3SPgPtr +1) -= xgs; + *(here->MOS3SPbPtr +1) -= xbs; + *(here->MOS3DdPtr) += here->MOS3drainConductance; + *(here->MOS3SsPtr) += here->MOS3sourceConductance; + *(here->MOS3BbPtr) += here->MOS3gbd+here->MOS3gbs; + *(here->MOS3DPdpPtr) += here->MOS3drainConductance+ + here->MOS3gds+here->MOS3gbd+ + xrev*(here->MOS3gm+here->MOS3gmbs); + *(here->MOS3SPspPtr) += here->MOS3sourceConductance+ + here->MOS3gds+here->MOS3gbs+ + xnrm*(here->MOS3gm+here->MOS3gmbs); + *(here->MOS3DdpPtr) -= here->MOS3drainConductance; + *(here->MOS3SspPtr) -= here->MOS3sourceConductance; + *(here->MOS3BdpPtr) -= here->MOS3gbd; + *(here->MOS3BspPtr) -= here->MOS3gbs; + *(here->MOS3DPdPtr) -= here->MOS3drainConductance; + *(here->MOS3DPgPtr) += (xnrm-xrev)*here->MOS3gm; + *(here->MOS3DPbPtr) += -here->MOS3gbd+(xnrm-xrev)*here->MOS3gmbs; + *(here->MOS3DPspPtr) -= here->MOS3gds+ + xnrm*(here->MOS3gm+here->MOS3gmbs); + *(here->MOS3SPgPtr) -= (xnrm-xrev)*here->MOS3gm; + *(here->MOS3SPsPtr) -= here->MOS3sourceConductance; + *(here->MOS3SPbPtr) -= here->MOS3gbs+(xnrm-xrev)*here->MOS3gmbs; + *(here->MOS3SPdpPtr) -= here->MOS3gds+ + xrev*(here->MOS3gm+here->MOS3gmbs); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3ask.c b/src/spicelib/devices/mos3/mos3ask.c new file mode 100644 index 000000000..03f35a8b7 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3ask.c @@ -0,0 +1,422 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Mathew Lew and Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +MOS3ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + MOS3instance *here = (MOS3instance *)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case MOS3_TEMP: + value->rValue = here->MOS3temp-CONSTCtoK; + return(OK); + case MOS3_CGS: + value->rValue = *(ckt->CKTstate0 + here->MOS3capgs); + return(OK); + case MOS3_CGD: + value->rValue = *(ckt->CKTstate0 + here->MOS3capgd); + return(OK); + case MOS3_L: + value->rValue = here->MOS3l; + return(OK); + case MOS3_W: + value->rValue = here->MOS3w; + return(OK); + case MOS3_AS: + value->rValue = here->MOS3sourceArea; + return(OK); + case MOS3_AD: + value->rValue = here->MOS3drainArea; + return(OK); + case MOS3_PS: + value->rValue = here->MOS3sourcePerimiter; + return(OK); + case MOS3_PD: + value->rValue = here->MOS3drainPerimiter; + return(OK); + case MOS3_NRS: + value->rValue = here->MOS3sourceSquares; + return(OK); + case MOS3_NRD: + value->rValue = here->MOS3drainSquares; + return(OK); + case MOS3_OFF: + value->rValue = here->MOS3off; + return(OK); + case MOS3_IC_VBS: + value->rValue = here->MOS3icVBS; + return(OK); + case MOS3_IC_VDS: + value->rValue = here->MOS3icVDS; + return(OK); + case MOS3_IC_VGS: + value->rValue = here->MOS3icVGS; + return(OK); + case MOS3_DNODE: + value->iValue = here->MOS3dNode; + return(OK); + case MOS3_GNODE: + value->iValue = here->MOS3gNode; + return(OK); + case MOS3_SNODE: + value->iValue = here->MOS3sNode; + return(OK); + case MOS3_BNODE: + value->iValue = here->MOS3bNode; + return(OK); + case MOS3_DNODEPRIME: + value->iValue = here->MOS3dNodePrime; + return(OK); + case MOS3_SNODEPRIME: + value->iValue = here->MOS3sNodePrime; + return(OK); + case MOS3_SOURCECONDUCT: + value->rValue = here->MOS3sourceConductance; + return(OK); + case MOS3_DRAINCONDUCT: + value->rValue = here->MOS3drainConductance; + return(OK); + case MOS3_SOURCERESIST: + if (here->MOS3sNodePrime != here->MOS3sNode) + value->rValue = 1.0 / here->MOS3sourceConductance; + else + value->rValue = 0.0; + return(OK); + case MOS3_DRAINRESIST: + if (here->MOS3dNodePrime != here->MOS3dNode) + value->rValue = 1.0 / here->MOS3drainConductance; + else + value->rValue = 0.0; + return(OK); + case MOS3_VON: + value->rValue = here->MOS3von; + return(OK); + case MOS3_VDSAT: + value->rValue = here->MOS3vdsat; + return(OK); + case MOS3_SOURCEVCRIT: + value->rValue = here->MOS3sourceVcrit; + return(OK); + case MOS3_DRAINVCRIT: + value->rValue = here->MOS3drainVcrit; + return(OK); + case MOS3_CD: + value->rValue = here->MOS3cd; + return(OK); + case MOS3_CBS: + value->rValue = here->MOS3cbs; + return(OK); + case MOS3_CBD: + value->rValue = here->MOS3cbd; + return(OK); + case MOS3_GMBS: + value->rValue = here->MOS3gmbs; + return(OK); + case MOS3_GM: + value->rValue = here->MOS3gm; + return(OK); + case MOS3_GDS: + value->rValue = here->MOS3gds; + return(OK); + case MOS3_GBD: + value->rValue = here->MOS3gbd; + return(OK); + case MOS3_GBS: + value->rValue = here->MOS3gbs; + return(OK); + case MOS3_CAPBD: + value->rValue = here->MOS3capbd; + return(OK); + case MOS3_CAPBS: + value->rValue = here->MOS3capbs; + return(OK); + case MOS3_CAPZEROBIASBD: + value->rValue = here->MOS3Cbd; + return(OK); + case MOS3_CAPZEROBIASBDSW: + value->rValue = here->MOS3Cbdsw; + return(OK); + case MOS3_CAPZEROBIASBS: + value->rValue = here->MOS3Cbs; + return(OK); + case MOS3_CAPZEROBIASBSSW: + value->rValue = here->MOS3Cbssw; + return(OK); + case MOS3_VBD: + value->rValue = *(ckt->CKTstate0 + here->MOS3vbd); + return(OK); + case MOS3_VBS: + value->rValue = *(ckt->CKTstate0 + here->MOS3vbs); + return(OK); + case MOS3_VGS: + value->rValue = *(ckt->CKTstate0 + here->MOS3vgs); + return(OK); + case MOS3_VDS: + value->rValue = *(ckt->CKTstate0 + here->MOS3vds); + return(OK); + case MOS3_CAPGS: + value->rValue = *(ckt->CKTstate0 + here->MOS3capgs); + return(OK); + case MOS3_QGS: + value->rValue = *(ckt->CKTstate0 + here->MOS3qgs); + return(OK); + case MOS3_CQGS: + value->rValue = *(ckt->CKTstate0 + here->MOS3cqgs); + return(OK); + case MOS3_CAPGD: + value->rValue = *(ckt->CKTstate0 + here->MOS3capgd); + return(OK); + case MOS3_QGD: + value->rValue = *(ckt->CKTstate0 + here->MOS3qgd); + return(OK); + case MOS3_CQGD: + value->rValue = *(ckt->CKTstate0 + here->MOS3cqgd); + return(OK); + case MOS3_CAPGB: + value->rValue = *(ckt->CKTstate0 + here->MOS3capgb); + return(OK); + case MOS3_QGB: + value->rValue = *(ckt->CKTstate0 + here->MOS3qgb); + return(OK); + case MOS3_CQGB: + value->rValue = *(ckt->CKTstate0 + here->MOS3cqgb); + return(OK); + case MOS3_QBD: + value->rValue = *(ckt->CKTstate0 + here->MOS3qbd); + return(OK); + case MOS3_CQBD: + value->rValue = *(ckt->CKTstate0 + here->MOS3cqbd); + return(OK); + case MOS3_QBS: + value->rValue = *(ckt->CKTstate0 + here->MOS3qbs); + return(OK); + case MOS3_CQBS: + value->rValue = *(ckt->CKTstate0 + here->MOS3cqbs); + return(OK); + case MOS3_L_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS3senParmNo); + } + return(OK); + case MOS3_L_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo); + } + return(OK); + case MOS3_L_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo); + } + return(OK); + case MOS3_L_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS3_L_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS3_L_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo); + } + return(OK); + case MOS3_W_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + } + return(OK); + case MOS3_W_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + } + return(OK); + case MOS3_W_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + } + return(OK); + case MOS3_W_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS3_W_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS3_W_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS3senParmNo + here->MOS3sens_l); + } + return(OK); + case MOS3_CB : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS3ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = here->MOS3cbd + here->MOS3cbs - *(ckt->CKTstate0 + + here->MOS3cqgb); + } + return(OK); + case MOS3_CG : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS3ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { + value->rValue = 0; + } else if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + (ckt->CKTmode & MODETRANOP)) { + value->rValue = 0; + } else { + value->rValue = *(ckt->CKTstate0 + here->MOS3cqgb) + + *(ckt->CKTstate0 + here->MOS3cqgd) + *(ckt->CKTstate0 + + here->MOS3cqgs); + } + return(OK); + case MOS3_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS3ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -here->MOS3cd; + value->rValue -= here->MOS3cbd + here->MOS3cbs - + *(ckt->CKTstate0 + here->MOS3cqgb); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue -= *(ckt->CKTstate0 + here->MOS3cqgb) + + *(ckt->CKTstate0 + here->MOS3cqgd) + + *(ckt->CKTstate0 + here->MOS3cqgs); + } + } + return(OK); + case MOS3_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS3ask.c"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + double temp; + + value->rValue = here->MOS3cd * + *(ckt->CKTrhsOld + here->MOS3dNode); + value->rValue += (here->MOS3cbd + here->MOS3cbs - + *(ckt->CKTstate0 + here->MOS3cqgb)) * + *(ckt->CKTrhsOld + here->MOS3bNode); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue += (*(ckt->CKTstate0 + here->MOS3cqgb) + + *(ckt->CKTstate0 + here->MOS3cqgd) + + *(ckt->CKTstate0 + here->MOS3cqgs)) * + *(ckt->CKTrhsOld + here->MOS3gNode); + } + temp = -here->MOS3cd; + temp -= here->MOS3cbd + here->MOS3cbs ; + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + temp -= *(ckt->CKTstate0 + here->MOS3cqgb) + + *(ckt->CKTstate0 + here->MOS3cqgd) + + *(ckt->CKTstate0 + here->MOS3cqgs); + } + value->rValue += temp * *(ckt->CKTrhsOld + here->MOS3sNode); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos3/mos3conv.c b/src/spicelib/devices/mos3/mos3conv.c new file mode 100644 index 000000000..d5318d64a --- /dev/null +++ b/src/spicelib/devices/mos3/mos3conv.c @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3convTest(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + double delvbs; + double delvbd; + double delvgs; + double delvds; + double delvgd; + double cbhat; + double cdhat; + double vbs; + double vbd; + double vgs; + double vds; + double vgd; + double vgdo; + double tol; + + for( ; model != NULL; model = model->MOS3nextModel) { + for(here = model->MOS3instances; here!= NULL; + here = here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + vbs = model->MOS3type * ( + *(ckt->CKTrhs+here->MOS3bNode) - + *(ckt->CKTrhs+here->MOS3sNodePrime)); + vgs = model->MOS3type * ( + *(ckt->CKTrhs+here->MOS3gNode) - + *(ckt->CKTrhs+here->MOS3sNodePrime)); + vds = model->MOS3type * ( + *(ckt->CKTrhs+here->MOS3dNodePrime) - + *(ckt->CKTrhs+here->MOS3sNodePrime)); + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS3vgs) - + *(ckt->CKTstate0 + here->MOS3vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS3vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS3vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS3vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS3vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS3mode >= 0) { + cdhat= + here->MOS3cd- + here->MOS3gbd * delvbd + + here->MOS3gmbs * delvbs + + here->MOS3gm * delvgs + + here->MOS3gds * delvds ; + } else { + cdhat= + here->MOS3cd - + ( here->MOS3gbd - + here->MOS3gmbs) * delvbd - + here->MOS3gm * delvgd + + here->MOS3gds * delvds ; + } + cbhat= + here->MOS3cbs + + here->MOS3cbd + + here->MOS3gbd * delvbd + + here->MOS3gbs * delvbs ; + /* + * check convergence + */ + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(here->MOS3cd))+ + ckt->CKTabstol; + if (fabs(cdhat-here->MOS3cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged */ + } else { + tol=ckt->CKTreltol* + MAX(fabs(cbhat),fabs(here->MOS3cbs+here->MOS3cbd)) + + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS3cbs+here->MOS3cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged*/ + } + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3defs.h b/src/spicelib/devices/mos3/mos3defs.h new file mode 100644 index 000000000..70dfab657 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3defs.h @@ -0,0 +1,542 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef MOS3 +#define MOS3 + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + + /* declarations for level 3 MOSFETs */ + +/* information needed for each instance */ + +typedef struct sMOS3instance { + struct sMOS3model *MOS3modPtr; /* backpointer to model */ + struct sMOS3instance *MOS3nextInstance; /* pointer to next instance of + *current model*/ + IFuid MOS3name; /* pointer to character string naming this instance */ + int MOS3owner; /* number of owner process */ + int MOS3states; /* index into state table for this device */ + int MOS3dNode; /* number of the gate node of the mosfet */ + int MOS3gNode; /* number of the gate node of the mosfet */ + int MOS3sNode; /* number of the source node of the mosfet */ + int MOS3bNode; /* number of the bulk node of the mosfet */ + int MOS3dNodePrime; /* number of the internal drain node of the mosfet */ + int MOS3sNodePrime; /* number of the internal source node of the mosfet */ + + double MOS3l; /* the length of the channel region */ + double MOS3w; /* the width of the channel region */ + double MOS3drainArea; /* the area of the drain diffusion */ + double MOS3sourceArea; /* the area of the source diffusion */ + double MOS3drainSquares; /* the length of the drain in squares */ + double MOS3sourceSquares; /* the length of the source in squares */ + double MOS3drainPerimiter; + double MOS3sourcePerimiter; + double MOS3sourceConductance; /*conductance of source(or 0):set in setup*/ + double MOS3drainConductance; /*conductance of drain(or 0):set in setup*/ + double MOS3temp; /* operating temperature of this instance */ + + double MOS3tTransconductance; /* temperature corrected transconductance*/ + double MOS3tSurfMob; /* temperature corrected surface mobility */ + double MOS3tPhi; /* temperature corrected Phi */ + double MOS3tVto; /* temperature corrected Vto */ + double MOS3tSatCur; /* temperature corrected saturation Cur. */ + double MOS3tSatCurDens; /* temperature corrected saturation Cur. density*/ + double MOS3tCbd; /* temperature corrected B-D Capacitance */ + double MOS3tCbs; /* temperature corrected B-S Capacitance */ + double MOS3tCj; /* temperature corrected Bulk bottom Capacitance */ + double MOS3tCjsw; /* temperature corrected Bulk side Capacitance */ + double MOS3tBulkPot; /* temperature corrected Bulk potential */ + double MOS3tDepCap; /* temperature adjusted transition point in */ + /* the cureve matching Fc * Vj */ + double MOS3tVbi; /* temperature adjusted Vbi */ + + double MOS3icVBS; /* initial condition B-S voltage */ + double MOS3icVDS; /* initial condition D-S voltage */ + double MOS3icVGS; /* initial condition G-S voltage */ + double MOS3von; + double MOS3vdsat; + double MOS3sourceVcrit; /* vcrit for pos. vds */ + double MOS3drainVcrit; /* vcrit for neg. vds */ + double MOS3cd; + double MOS3cbs; + double MOS3cbd; + double MOS3gmbs; + double MOS3gm; + double MOS3gds; + double MOS3gbd; + double MOS3gbs; + double MOS3capbd; + double MOS3capbs; + double MOS3Cbd; + double MOS3Cbdsw; + double MOS3Cbs; + double MOS3Cbssw; + double MOS3f2d; + double MOS3f3d; + double MOS3f4d; + double MOS3f2s; + double MOS3f3s; + double MOS3f4s; + int MOS3mode; /* device mode : 1 = normal, -1 = inverse */ + + + unsigned MOS3off :1;/* non-zero to indicate device is off for dc analysis*/ + unsigned MOS3tempGiven :1; /* instance temperature specified */ + unsigned MOS3lGiven :1; + unsigned MOS3wGiven :1; + unsigned MOS3drainAreaGiven :1; + unsigned MOS3sourceAreaGiven :1; + unsigned MOS3drainSquaresGiven :1; + unsigned MOS3sourceSquaresGiven :1; + unsigned MOS3drainPerimiterGiven :1; + unsigned MOS3sourcePerimiterGiven :1; + unsigned MOS3dNodePrimeSet :1; + unsigned MOS3sNodePrimeSet :1; + unsigned MOS3icVBSGiven :1; + unsigned MOS3icVDSGiven :1; + unsigned MOS3icVGSGiven :1; + unsigned MOS3vonGiven :1; + unsigned MOS3vdsatGiven :1; + unsigned MOS3modeGiven :1; + + + double *MOS3DdPtr; /* pointer to sparse matrix element at + * (Drain node,drain node) */ + double *MOS3GgPtr; /* pointer to sparse matrix element at + * (gate node,gate node) */ + double *MOS3SsPtr; /* pointer to sparse matrix element at + * (source node,source node) */ + double *MOS3BbPtr; /* pointer to sparse matrix element at + * (bulk node,bulk node) */ + double *MOS3DPdpPtr; /* pointer to sparse matrix element at + * (drain prime node,drain prime node) */ + double *MOS3SPspPtr; /* pointer to sparse matrix element at + * (source prime node,source prime node) */ + double *MOS3DdpPtr; /* pointer to sparse matrix element at + * (drain node,drain prime node) */ + double *MOS3GbPtr; /* pointer to sparse matrix element at + * (gate node,bulk node) */ + double *MOS3GdpPtr; /* pointer to sparse matrix element at + * (gate node,drain prime node) */ + double *MOS3GspPtr; /* pointer to sparse matrix element at + * (gate node,source prime node) */ + double *MOS3SspPtr; /* pointer to sparse matrix element at + * (source node,source prime node) */ + double *MOS3BdpPtr; /* pointer to sparse matrix element at + * (bulk node,drain prime node) */ + double *MOS3BspPtr; /* pointer to sparse matrix element at + * (bulk node,source prime node) */ + double *MOS3DPspPtr; /* pointer to sparse matrix element at + * (drain prime node,source prime node) */ + double *MOS3DPdPtr; /* pointer to sparse matrix element at + * (drain prime node,drain node) */ + double *MOS3BgPtr; /* pointer to sparse matrix element at + * (bulk node,gate node) */ + double *MOS3DPgPtr; /* pointer to sparse matrix element at + * (drain prime node,gate node) */ + + double *MOS3SPgPtr; /* pointer to sparse matrix element at + * (source prime node,gate node) */ + double *MOS3SPsPtr; /* pointer to sparse matrix element at + * (source prime node,source node) */ + double *MOS3DPbPtr; /* pointer to sparse matrix element at + * (drain prime node,bulk node) */ + double *MOS3SPbPtr; /* pointer to sparse matrix element at + * (source prime node,bulk node) */ + double *MOS3SPdpPtr; /* pointer to sparse matrix element at + * (source prime node,drain prime node) */ + int MOS3senParmNo; /* parameter # for sensitivity use; + set equal to 0 if neither length + nor width of the mosfet is a design + parameter */ + unsigned MOS3sens_l :1; /* field which indicates whether + length of the mosfet is a design + parameter or not */ + unsigned MOS3sens_w :1; /* field which indicates whether + width of the mosfet is a design + parameter or not */ + unsigned MOS3senPertFlag :1; /* indictes whether the the parameter of + the particular instance is to be perturbed */ + double MOS3cgs; + double MOS3cgd; + double MOS3cgb; + double *MOS3sens; + +#define MOS3senGdpr MOS3sens +#define MOS3senGspr MOS3sens + 1 +#define MOS3senCgs MOS3sens + 2 /* contains pertured values of cgs */ +#define MOS3senCgd MOS3sens + 8 /* contains perturbed values of cgd*/ +#define MOS3senCgb MOS3sens + 14 /* contains perturbed values of cgb*/ +#define MOS3senCbd MOS3sens + 20 /* contains perturbed values of cbd*/ +#define MOS3senCbs MOS3sens + 26 /* contains perturbed values of cbs*/ +#define MOS3senGds MOS3sens + 32 /* contains perturbed values of gds*/ +#define MOS3senGbs MOS3sens + 38 /* contains perturbed values of gbs*/ +#define MOS3senGbd MOS3sens + 44 /* contains perturbed values of gbd*/ +#define MOS3senGm MOS3sens + 50 /* contains perturbed values of gm*/ +#define MOS3senGmbs MOS3sens + 56 /* contains perturbed values of gmbs*/ +#define MOS3dphigs_dl MOS3sens + 62 +#define MOS3dphigd_dl MOS3sens + 63 +#define MOS3dphigb_dl MOS3sens + 64 +#define MOS3dphibs_dl MOS3sens + 65 +#define MOS3dphibd_dl MOS3sens + 66 +#define MOS3dphigs_dw MOS3sens + 67 +#define MOS3dphigd_dw MOS3sens + 68 +#define MOS3dphigb_dw MOS3sens + 69 +#define MOS3dphibs_dw MOS3sens + 70 +#define MOS3dphibd_dw MOS3sens + 71 + + /* distortion stuff */ +/* + * naming convention: + * x = vgs + * y = vbs + * z = vds + * cdr = cdrain + */ + + +#define MOS3NDCOEFFS 30 + +#ifndef NODISTO + double MOS3dCoeffs[MOS3NDCOEFFS]; +#else /* NODISTO */ + double *MOS3dCoeffs; +#endif /* NODISTO */ + +#ifndef CONFIG + +#define capbs2 MOS3dCoeffs[0] +#define capbs3 MOS3dCoeffs[1] +#define capbd2 MOS3dCoeffs[2] +#define capbd3 MOS3dCoeffs[3] +#define gbs2 MOS3dCoeffs[4] +#define gbs3 MOS3dCoeffs[5] +#define gbd2 MOS3dCoeffs[6] +#define gbd3 MOS3dCoeffs[7] +#define capgb2 MOS3dCoeffs[8] +#define capgb3 MOS3dCoeffs[9] +#define cdr_x2 MOS3dCoeffs[10] +#define cdr_y2 MOS3dCoeffs[11] +#define cdr_z2 MOS3dCoeffs[12] +#define cdr_xy MOS3dCoeffs[13] +#define cdr_yz MOS3dCoeffs[14] +#define cdr_xz MOS3dCoeffs[15] +#define cdr_x3 MOS3dCoeffs[16] +#define cdr_y3 MOS3dCoeffs[17] +#define cdr_z3 MOS3dCoeffs[18] +#define cdr_x2z MOS3dCoeffs[19] +#define cdr_x2y MOS3dCoeffs[20] +#define cdr_y2z MOS3dCoeffs[21] +#define cdr_xy2 MOS3dCoeffs[22] +#define cdr_xz2 MOS3dCoeffs[23] +#define cdr_yz2 MOS3dCoeffs[24] +#define cdr_xyz MOS3dCoeffs[25] +#define capgs2 MOS3dCoeffs[26] +#define capgs3 MOS3dCoeffs[27] +#define capgd2 MOS3dCoeffs[28] +#define capgd3 MOS3dCoeffs[29] + +#endif + + /* end distortion coeffs. */ +/* indices to the array of MOSFET(3) noise sources */ + +#define MOS3RDNOIZ 0 +#define MOS3RSNOIZ 1 +#define MOS3IDNOIZ 2 +#define MOS3FLNOIZ 3 +#define MOS3TOTNOIZ 4 + +#define MOS3NSRCS 5 /* the number of MOSFET(3) noise sources */ + +#ifndef NONOISE + double MOS3nVar[NSTATVARS][MOS3NSRCS]; +#else /* NONOISE */ + double **MOS3nVar; +#endif /* NONOISE */ + +} MOS3instance ; + +#define MOS3vbd MOS3states+ 0 +#define MOS3vbs MOS3states+ 1 +#define MOS3vgs MOS3states+ 2 +#define MOS3vds MOS3states+ 3 + +/* meyer capacitances */ +#define MOS3capgs MOS3states+ 4 /* gate-source capacitor value */ +#define MOS3qgs MOS3states+ 5 /* gate-source capacitor charge */ +#define MOS3cqgs MOS3states+ 6 /* gate-source capacitor current */ + +#define MOS3capgd MOS3states+ 7 /* gate-drain capacitor value */ +#define MOS3qgd MOS3states+ 8 /* gate-drain capacitor charge */ +#define MOS3cqgd MOS3states+ 9 /* gate-drain capacitor current */ + +#define MOS3capgb MOS3states+ 10/* gate-bulk capacitor value */ +#define MOS3qgb MOS3states+ 11 /* gate-bulk capacitor charge */ +#define MOS3cqgb MOS3states+ 12 /* gate-bulk capacitor current */ + +/* diode capacitances */ +#define MOS3qbd MOS3states+ 13 /* bulk-drain capacitor charge */ +#define MOS3cqbd MOS3states+ 14 /* bulk-drain capacitor current */ + +#define MOS3qbs MOS3states+ 15 /* bulk-source capacitor charge */ +#define MOS3cqbs MOS3states+ 16 /* bulk-source capacitor current */ + +#define MOS3NUMSTATES 17 + + +#define MOS3sensxpgs MOS3states+17 /* charge sensitivities and their derivatives + +18 for the derivatives - pointer to the + beginning of the array */ +#define MOS3sensxpgd MOS3states+19 +#define MOS3sensxpgb MOS3states+21 +#define MOS3sensxpbs MOS3states+23 +#define MOS3sensxpbd MOS3states+25 + +#define MOS3numSenStates 10 + + +/* per model data */ + + /* NOTE: parameters marked 'input - use xxxx' are paramters for + * which a temperature correction is applied in MOS3temp, thus + * the MOS3xxxx value in the per-instance structure should be used + * instead in all calculations + */ + +typedef struct sMOS3model { /* model structure for a resistor */ + int MOS3modType; /* type index of this device type */ + struct sMOS3model *MOS3nextModel; /* pointer to next possible model + *in linked list */ + MOS3instance * MOS3instances; /* pointer to list of instances + * that have this model */ + IFuid MOS3modName; /* pointer to character string naming this model */ + int MOS3type; /* device type : 1 = nmos, -1 = pmos */ + double MOS3tnom; /* temperature at which parameters measured */ + double MOS3latDiff; + double MOS3jctSatCurDensity; /* input - use tSatCurDens*/ + double MOS3jctSatCur; /* input - use tSatCur instead */ + double MOS3drainResistance; + double MOS3sourceResistance; + double MOS3sheetResistance; + double MOS3transconductance; /* input - use tTransconductance */ + double MOS3gateSourceOverlapCapFactor; + double MOS3gateDrainOverlapCapFactor; + double MOS3gateBulkOverlapCapFactor; + double MOS3oxideCapFactor; + double MOS3vt0; /* input - use tVto */ + double MOS3capBD; /* input - use tCbs */ + double MOS3capBS; /* input - use tCbd */ + double MOS3bulkCapFactor; /* input - use tCj */ + double MOS3sideWallCapFactor; /* input - use tCjsw */ + double MOS3bulkJctPotential; /* input - use tBulkPot */ + double MOS3bulkJctBotGradingCoeff; + double MOS3bulkJctSideGradingCoeff; + double MOS3fwdCapDepCoeff; + double MOS3phi; /* input - use tPhi */ + double MOS3gamma; + double MOS3substrateDoping; + int MOS3gateType; + double MOS3surfaceStateDensity; + double MOS3oxideThickness; + double MOS3surfaceMobility; /* input - use tSurfMob */ + double MOS3eta; + double MOS3junctionDepth; + double MOS3coeffDepLayWidth; /* xd */ + double MOS3narrowFactor; /* delta */ + double MOS3delta; /* input delta */ + double MOS3fastSurfaceStateDensity; /* nfs */ + double MOS3theta; /* theta */ + double MOS3maxDriftVel; /* vmax */ + double MOS3alpha; /* alpha */ + double MOS3kappa; /* kappa */ + double MOS3fNcoef; + double MOS3fNexp; + + unsigned MOS3typeGiven :1; + unsigned MOS3latDiffGiven :1; + unsigned MOS3jctSatCurDensityGiven :1; + unsigned MOS3jctSatCurGiven :1; + unsigned MOS3drainResistanceGiven :1; + unsigned MOS3sourceResistanceGiven :1; + unsigned MOS3sheetResistanceGiven :1; + unsigned MOS3transconductanceGiven :1; + unsigned MOS3gateSourceOverlapCapFactorGiven :1; + unsigned MOS3gateDrainOverlapCapFactorGiven :1; + unsigned MOS3gateBulkOverlapCapFactorGiven :1; + unsigned MOS3vt0Given :1; + unsigned MOS3capBDGiven :1; + unsigned MOS3capBSGiven :1; + unsigned MOS3bulkCapFactorGiven :1; + unsigned MOS3sideWallCapFactorGiven :1; + unsigned MOS3bulkJctPotentialGiven :1; + unsigned MOS3bulkJctBotGradingCoeffGiven :1; + unsigned MOS3bulkJctSideGradingCoeffGiven :1; + unsigned MOS3fwdCapDepCoeffGiven :1; + unsigned MOS3phiGiven :1; + unsigned MOS3gammaGiven :1; + unsigned MOS3substrateDopingGiven :1; + unsigned MOS3gateTypeGiven :1; + unsigned MOS3surfaceStateDensityGiven :1; + unsigned MOS3oxideThicknessGiven :1; + unsigned MOS3surfaceMobilityGiven :1; + unsigned MOS3etaGiven :1; + unsigned MOS3junctionDepthGiven :1; + unsigned MOS3deltaGiven :1; /* delta */ + unsigned MOS3fastSurfaceStateDensityGiven :1; /* nfs */ + unsigned MOS3thetaGiven :1; /* theta */ + unsigned MOS3maxDriftVelGiven :1; /* vmax */ + unsigned MOS3kappaGiven :1; /* kappa */ + unsigned MOS3tnomGiven :1; /* Tnom was given? */ + unsigned MOS3fNcoefGiven :1; + unsigned MOS3fNexpGiven :1; + +} MOS3model; + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + +/* device parameters */ +#define MOS3_W 1 +#define MOS3_L 2 +#define MOS3_AS 3 +#define MOS3_AD 4 +#define MOS3_PS 5 +#define MOS3_PD 6 +#define MOS3_NRS 7 +#define MOS3_NRD 8 +#define MOS3_OFF 9 +#define MOS3_IC 10 +#define MOS3_IC_VBS 11 +#define MOS3_IC_VDS 12 +#define MOS3_IC_VGS 13 +#define MOS3_W_SENS 14 +#define MOS3_L_SENS 15 +#define MOS3_CB 16 +#define MOS3_CG 17 +#define MOS3_CS 18 +#define MOS3_POWER 19 +#define MOS3_CGS 20 +#define MOS3_CGD 21 +#define MOS3_DNODE 22 +#define MOS3_GNODE 23 +#define MOS3_SNODE 24 +#define MOS3_BNODE 25 +#define MOS3_DNODEPRIME 26 +#define MOS3_SNODEPRIME 27 +#define MOS3_SOURCECONDUCT 28 +#define MOS3_DRAINCONDUCT 29 +#define MOS3_VON 30 +#define MOS3_VDSAT 31 +#define MOS3_SOURCEVCRIT 32 +#define MOS3_DRAINVCRIT 33 +#define MOS3_CD 34 +#define MOS3_CBS 35 +#define MOS3_CBD 36 +#define MOS3_GMBS 37 +#define MOS3_GM 38 +#define MOS3_GDS 39 +#define MOS3_GBD 40 +#define MOS3_GBS 41 +#define MOS3_CAPBD 42 +#define MOS3_CAPBS 43 +#define MOS3_CAPZEROBIASBD 44 +#define MOS3_CAPZEROBIASBDSW 45 +#define MOS3_CAPZEROBIASBS 46 +#define MOS3_CAPZEROBIASBSSW 47 +#define MOS3_VBD 48 +#define MOS3_VBS 49 +#define MOS3_VGS 50 +#define MOS3_VDS 51 +#define MOS3_CAPGS 52 +#define MOS3_QGS 53 +#define MOS3_CQGS 54 +#define MOS3_CAPGD 55 +#define MOS3_QGD 56 +#define MOS3_CQGD 57 +#define MOS3_CAPGB 58 +#define MOS3_QGB 59 +#define MOS3_CQGB 60 +#define MOS3_QBD 61 +#define MOS3_CQBD 62 +#define MOS3_QBS 63 +#define MOS3_CQBS 64 +#define MOS3_W_SENS_REAL 65 +#define MOS3_W_SENS_IMAG 66 +#define MOS3_W_SENS_MAG 67 +#define MOS3_W_SENS_PH 68 +#define MOS3_W_SENS_CPLX 69 +#define MOS3_L_SENS_REAL 70 +#define MOS3_L_SENS_IMAG 71 +#define MOS3_L_SENS_MAG 72 +#define MOS3_L_SENS_PH 73 +#define MOS3_L_SENS_CPLX 74 +#define MOS3_W_SENS_DC 75 +#define MOS3_L_SENS_DC 76 +#define MOS3_TEMP 77 +#define MOS3_SOURCERESIST 78 +#define MOS3_DRAINRESIST 79 + +/* model parameters */ +#define MOS3_MOD_VTO 101 +#define MOS3_MOD_KP 102 +#define MOS3_MOD_GAMMA 103 +#define MOS3_MOD_PHI 104 +#define MOS3_MOD_RD 105 +#define MOS3_MOD_RS 106 +#define MOS3_MOD_CBD 107 +#define MOS3_MOD_CBS 108 +#define MOS3_MOD_IS 109 +#define MOS3_MOD_PB 110 +#define MOS3_MOD_CGSO 111 +#define MOS3_MOD_CGDO 112 +#define MOS3_MOD_CGBO 113 +#define MOS3_MOD_RSH 114 +#define MOS3_MOD_CJ 115 +#define MOS3_MOD_MJ 116 +#define MOS3_MOD_CJSW 117 +#define MOS3_MOD_MJSW 118 +#define MOS3_MOD_JS 119 +#define MOS3_MOD_TOX 120 +#define MOS3_MOD_LD 121 +#define MOS3_MOD_U0 122 +#define MOS3_MOD_FC 123 +#define MOS3_MOD_NSUB 124 +#define MOS3_MOD_TPG 125 +#define MOS3_MOD_NSS 126 +#define MOS3_MOD_ETA 127 +#define MOS3_MOD_DELTA 128 +#define MOS3_MOD_NFS 129 +#define MOS3_MOD_THETA 130 +#define MOS3_MOD_VMAX 131 +#define MOS3_MOD_KAPPA 132 +#define MOS3_MOD_NMOS 133 +#define MOS3_MOD_PMOS 134 +#define MOS3_MOD_XJ 135 +#define MOS3_MOD_UEXP 136 +#define MOS3_MOD_NEFF 137 +#define MOS3_MOD_XD 138 +#define MOS3_MOD_ALPHA 139 +#define MOS3_DELTA 140 +#define MOS3_MOD_TNOM 141 +#define MOS3_MOD_KF 142 +#define MOS3_MOD_AF 143 +#define MOS3_MOD_TYPE 144 + +/* device questions */ + + +/* model questions */ + +#include "mos3ext.h" + +#endif /*MOS3*/ diff --git a/src/spicelib/devices/mos3/mos3del.c b/src/spicelib/devices/mos3/mos3del.c new file mode 100644 index 000000000..406dfea77 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3del.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS3delete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + MOS3model *model = (MOS3model *)inModel; + MOS3instance **fast = (MOS3instance **)inst; + MOS3instance **prev = NULL; + MOS3instance *here; + + for( ; model ; model = model->MOS3nextModel) { + prev = &(model->MOS3instances); + for(here = *prev; here ; here = *prev) { + if(here->MOS3name == name || (fast && here==*fast) ) { + *prev= here->MOS3nextInstance; + FREE(here); + return(OK); + } + prev = &(here->MOS3nextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/mos3/mos3dest.c b/src/spicelib/devices/mos3/mos3dest.c new file mode 100644 index 000000000..44a5b57d4 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3dest.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos3defs.h" +#include "suffix.h" + + +void +MOS3destroy(inModel) + GENmodel **inModel; +{ + MOS3model **model = (MOS3model **)inModel; + MOS3instance *here; + MOS3instance *prev = NULL; + MOS3model *mod = *model; + MOS3model *oldmod = NULL; + + for( ; mod ; mod = mod->MOS3nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (MOS3instance *)NULL; + for(here = mod->MOS3instances ; here ; here = here->MOS3nextInstance) { + if(prev){ + if(prev->MOS3sens) FREE(prev->MOS3sens); + FREE(prev); + } + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/mos3/mos3dist.c b/src/spicelib/devices/mos3/mos3dist.c new file mode 100644 index 000000000..94e95af10 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3dist.c @@ -0,0 +1,1387 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "distodef.h" +#include "suffix.h" + +int +MOS3disto(mode,genmodel,ckt) + GENmodel *genmodel; + register CKTcircuit *ckt; + int mode; + +/* assuming here that ckt->CKTomega has been initialised to + * the correct value + */ +{ + MOS3model *model = (MOS3model *) genmodel; + DISTOAN* job = (DISTOAN*) ckt->CKTcurJob; + DpassStr pass; + double r1h1x,i1h1x; + double r1h1y,i1h1y; + double r1h1z, i1h1z; + double r1h2x, i1h2x; + double r1h2y, i1h2y; + double r1h2z, i1h2z; + double r1hm2x,i1hm2x; + double r1hm2y,i1hm2y; + double r1hm2z, i1hm2z; + double r2h11x,i2h11x; + double r2h11y,i2h11y; + double r2h11z, i2h11z; + double r2h1m2x,i2h1m2x; + double r2h1m2y,i2h1m2y; + double r2h1m2z, i2h1m2z; + double temp, itemp; + register MOS3instance *here; + +if (mode == D_SETUP) + return(MOS3dSetup(model,ckt)); + +if ((mode == D_TWOF1) || (mode == D_THRF1) || + (mode == D_F1PF2) || (mode == D_F1MF2) || + (mode == D_2F1MF2)) { + + /* loop through all the MOS3 models */ +for( ; model != NULL; model = model->MOS3nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + + + + /* loading starts here */ + + switch (mode) { + case D_TWOF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS3gNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS3gNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS3bNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS3bNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS3dNodePrime)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS3dNodePrime)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + itemp = DFi2F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z); + + *(ckt->CKTrhs + (here->MOS3dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F1(here->gbs2, + r1h1y, + i1h1y); + + itemp = D1i2F1(here->gbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = D1i2F1(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgs2, + r1h1x, + i1h1x); + + itemp = ckt->CKTomega * + D1n2F1(here->capgs2, + r1h1x, + i1h1x); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z); + + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3bNode)) += temp; + *(ckt->CKTirhs + (here->MOS3bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbs2, + r1h1y, + i1h1y); + + itemp = ckt->CKTomega * + D1n2F1(here->capbs2, + r1h1y, + i1h1y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + itemp = ckt->CKTomega * + D1n2F1(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + + case D_THRF1: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS3gNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS3gNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS3bNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS3bNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS3dNodePrime)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS3dNodePrime)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r2h11x = *(job->r2H11ptr + (here->MOS3gNode)) - + *(job->r2H11ptr + (here->MOS3sNodePrime)); + i2h11x = *(job->i2H11ptr + (here->MOS3gNode)) - + *(job->i2H11ptr + (here->MOS3sNodePrime)); + + r2h11y = *(job->r2H11ptr + (here->MOS3bNode)) - + *(job->r2H11ptr + (here->MOS3sNodePrime)); + i2h11y = *(job->i2H11ptr + (here->MOS3bNode)) - + *(job->i2H11ptr + (here->MOS3sNodePrime)); + + r2h11z = *(job->r2H11ptr + (here->MOS3dNodePrime)) - + *(job->r2H11ptr + (here->MOS3sNodePrime)); + i2h11z = *(job->i2H11ptr + (here->MOS3dNodePrime)) - + *(job->i2H11ptr + (here->MOS3sNodePrime)); + /* loading starts here */ + /* loading cdrain term */ + + temp = DFn3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + itemp = DFi3F1(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + here->cdr_x3, + here->cdr_y3, + here->cdr_z3, + here->cdr_x2y, + here->cdr_x2z, + here->cdr_xy2, + here->cdr_y2z, + here->cdr_xz2, + here->cdr_yz2, + here->cdr_xyz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r2h11x, + i2h11x, + r2h11y, + i2h11y, + r2h11z, + i2h11z); + + + *(ckt->CKTrhs + (here->MOS3dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + itemp = D1i3F1(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = D1i3F1(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + itemp = ckt->CKTomega * + D1n3F1(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r2h11x, + i2h11x); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r2h11x - r2h11z, + i2h11x - i2h11z); + + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r2h11x - r2h11y, + i2h11x - i2h11y); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3bNode)) += temp; + *(ckt->CKTirhs + (here->MOS3bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + itemp = ckt->CKTomega * + D1n3F1(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r2h11y, + i2h11y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + itemp = ckt->CKTomega * + D1n3F1(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r2h11y - r2h11z, + i2h11y - i2h11z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1PF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS3gNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS3gNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS3bNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS3bNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS3dNodePrime)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS3dNodePrime)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h2x = *(job->r1H2ptr + (here->MOS3gNode)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1h2x = *(job->i1H2ptr + (here->MOS3gNode)) - + *(job->i1H2ptr + (here->MOS3sNodePrime)); + + r1h2y = *(job->r1H2ptr + (here->MOS3bNode)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1h2y = *(job->i1H2ptr + (here->MOS3bNode)) - + *(job->i1H2ptr + (here->MOS3sNodePrime)); + + r1h2z = *(job->r1H2ptr + (here->MOS3dNodePrime)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1h2z = *(job->i1H2ptr + (here->MOS3dNodePrime)) - + *(job->i1H2ptr + (here->MOS3sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1h2x, + i1h2x, + r1h2y, + i1h2y, + r1h2z, + i1h2z); + + *(ckt->CKTrhs + (here->MOS3dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1h2x, + i1h2x); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1h2x - r1h2z, + i1h2x - i1h2z); + + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1h2x - r1h2y, + i1h2x - i1h2y); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3bNode)) += temp; + *(ckt->CKTirhs + (here->MOS3bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1h2y, + i1h2y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1h2y - r1h2z, + i1h2y - i1h2z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS3gNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS3gNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS3bNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS3bNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS3dNodePrime)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS3dNodePrime)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS3gNode)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS3gNode)) - + *(job->i1H2ptr + (here->MOS3sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS3bNode)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS3bNode)) - + *(job->i1H2ptr + (here->MOS3sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS3dNodePrime)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS3dNodePrime)) - + *(job->i1H2ptr + (here->MOS3sNodePrime))); + + /* loading starts here */ + /* loading cdrain term */ + + temp = DFnF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + itemp = DFiF12(here->cdr_x2, + here->cdr_y2, + here->cdr_z2, + here->cdr_xy, + here->cdr_yz, + here->cdr_xz, + r1h1x, + i1h1x, + r1h1y, + i1h1y, + r1h1z, + i1h1z, + r1hm2x, + i1hm2x, + r1hm2y, + i1hm2y, + r1hm2z, + i1hm2z); + + *(ckt->CKTrhs + (here->MOS3dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1nF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = D1iF12(here->gbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1nF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = D1iF12(here->gbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + itemp = ckt->CKTomega * + D1nF12(here->capgs2, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capgd2, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1iF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capgb2, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3bNode)) += temp; + *(ckt->CKTirhs + (here->MOS3bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + itemp = ckt->CKTomega * + D1nF12(here->capbs2, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1iF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + itemp = ckt->CKTomega * + D1nF12(here->capbd2, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + case D_2F1MF2: + /* x = vgs, y = vbs z = vds */ + + /* getting first order (linear) Volterra kernel */ + r1h1x = *(job->r1H1ptr + (here->MOS3gNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1x = *(job->i1H1ptr + (here->MOS3gNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1y = *(job->r1H1ptr + (here->MOS3bNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1y = *(job->i1H1ptr + (here->MOS3bNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1h1z = *(job->r1H1ptr + (here->MOS3dNodePrime)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i1h1z = *(job->i1H1ptr + (here->MOS3dNodePrime)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r1hm2x = *(job->r1H2ptr + (here->MOS3gNode)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1hm2x = -(*(job->i1H2ptr + (here->MOS3gNode)) - + *(job->i1H2ptr + (here->MOS3sNodePrime))); + + r1hm2y = *(job->r1H2ptr + (here->MOS3bNode)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1hm2y = -(*(job->i1H2ptr + (here->MOS3bNode)) - + *(job->i1H2ptr + (here->MOS3sNodePrime))); + + r1hm2z = *(job->r1H2ptr + (here->MOS3dNodePrime)) - + *(job->r1H2ptr + (here->MOS3sNodePrime)); + i1hm2z = -(*(job->i1H2ptr + (here->MOS3dNodePrime)) - + *(job->i1H2ptr + (here->MOS3sNodePrime))); + + r2h11x = *(job->r1H1ptr + (here->MOS3gNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i2h11x = *(job->i1H1ptr + (here->MOS3gNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r2h11y = *(job->r1H1ptr + (here->MOS3bNode)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i2h11y = *(job->i1H1ptr + (here->MOS3bNode)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r2h11z = *(job->r1H1ptr + (here->MOS3dNodePrime)) - + *(job->r1H1ptr + (here->MOS3sNodePrime)); + i2h11z = *(job->i1H1ptr + (here->MOS3dNodePrime)) - + *(job->i1H1ptr + (here->MOS3sNodePrime)); + + r2h1m2x = *(job->r2H1m2ptr + (here->MOS3gNode)) - + *(job->r2H1m2ptr + (here->MOS3sNodePrime)); + i2h1m2x = *(job->i2H1m2ptr + (here->MOS3gNode)) - + *(job->i2H1m2ptr + (here->MOS3sNodePrime)); + + r2h1m2y = *(job->r2H1m2ptr + (here->MOS3bNode)) - + *(job->r2H1m2ptr + (here->MOS3sNodePrime)); + i2h1m2y = *(job->i2H1m2ptr + (here->MOS3bNode)) - + *(job->i2H1m2ptr + (here->MOS3sNodePrime)); + +r2h1m2z = *(job->r2H1m2ptr + (here->MOS3dNodePrime)) - + *(job->r2H1m2ptr + (here->MOS3sNodePrime)); +i2h1m2z = *(job->i2H1m2ptr + (here->MOS3dNodePrime)) - + *(job->i2H1m2ptr + (here->MOS3sNodePrime)); + + /* loading starts here */ + /* loading cdrain term */ + +pass.cxx = here->cdr_x2; +pass.cyy = here->cdr_y2; +pass.czz = here->cdr_z2; +pass.cxy = here->cdr_xy; +pass.cyz = here->cdr_yz; +pass.cxz = here->cdr_xz; +pass.cxxx = here->cdr_x3; +pass.cyyy = here->cdr_y3; +pass.czzz = here->cdr_z3; +pass.cxxy = here->cdr_x2y; +pass.cxxz = here->cdr_x2z; +pass.cxyy = here->cdr_xy2; +pass.cyyz = here->cdr_y2z; +pass.cxzz = here->cdr_xz2; +pass.cyzz = here->cdr_yz2; +pass.cxyz = here->cdr_xyz; +pass.r1h1x = r1h1x; +pass.i1h1x = i1h1x; +pass.r1h1y = r1h1y; +pass.i1h1y = i1h1y; +pass.r1h1z = r1h1z; +pass.i1h1z = i1h1z; +pass.r1h2x = r1hm2x; +pass.i1h2x = i1hm2x; +pass.r1h2y = r1hm2y; +pass.i1h2y = i1hm2y; +pass.r1h2z = r1hm2z; +pass.i1h2z = i1hm2z; +pass.r2h11x = r2h11x; +pass.i2h11x = i2h11x; +pass.r2h11y = r2h11y; +pass.i2h11y = i2h11y; +pass.r2h11z = r2h11z; +pass.i2h11z = i2h11z; +pass.h2f1f2x = r2h1m2x; +pass.ih2f1f2x = i2h1m2x; +pass.h2f1f2y = r2h1m2y; +pass.ih2f1f2y = i2h1m2y; +pass.h2f1f2z = r2h1m2z; +pass.ih2f1f2z = i2h1m2z; + temp = DFn2F12(&pass); + + itemp = DFi2F12(&pass); + + + *(ckt->CKTrhs + (here->MOS3dNodePrime)) -= temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* cdrain term over */ + + /* loading gbs term */ + + temp = D1n2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + + itemp = D1i2F12(here->gbs2, + here->gbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* gbs over */ + + /* loading gbd term */ + + temp = D1n2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = D1i2F12(here->gbd2, + here->gbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* gbd over */ + + /* loading capgs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + itemp = ckt->CKTomega * + D1n2F12(here->capgs2, + here->capgs3, + r1h1x, + i1h1x, + r1hm2x, + i1hm2x, + r2h11x, + i2h11x, + r2h1m2x, + i2h1m2x); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capgs over */ + + /* loading capgd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capgd2, + here->capgd3, + r1h1x - r1h1z, + i1h1x - i1h1z, + r1hm2x - r1hm2z, + i1hm2x - i1hm2z, + r2h11x - r2h11z, + i2h11x - i2h11z, + r2h1m2x - r2h1m2z, + i2h1m2x - i2h1m2z); + + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capgd over */ + /* loading capgb term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capgb2, + here->capgb3, + r1h1x - r1h1y, + i1h1x - i1h1y, + r1hm2x - r1hm2y, + i1hm2x - i1hm2y, + r2h11x - r2h11y, + i2h11x - i2h11y, + r2h1m2x - r2h1m2y, + i2h1m2x - i2h1m2y); + + *(ckt->CKTrhs + (here->MOS3gNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3gNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3bNode)) += temp; + *(ckt->CKTirhs + (here->MOS3bNode)) += itemp; + + /* capgb over */ + + /* loading capbs term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + itemp = ckt->CKTomega * + D1n2F12(here->capbs2, + here->capbs3, + r1h1y, + i1h1y, + r1hm2y, + i1hm2y, + r2h11y, + i2h11y, + r2h1m2y, + i2h1m2y); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3sNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3sNodePrime)) += itemp; + + /* capbs over */ + + /* loading capbd term */ + + temp = -ckt->CKTomega * + D1i2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + itemp = ckt->CKTomega * + D1n2F12(here->capbd2, + here->capbd3, + r1h1y - r1h1z, + i1h1y - i1h1z, + r1hm2y - r1hm2z, + i1hm2y - i1hm2z, + r2h11y - r2h11z, + i2h11y - i2h11z, + r2h1m2y - r2h1m2z, + i2h1m2y - i2h1m2z); + + + *(ckt->CKTrhs + (here->MOS3bNode)) -= temp; + *(ckt->CKTirhs + (here->MOS3bNode)) -= itemp; + *(ckt->CKTrhs + (here->MOS3dNodePrime)) += temp; + *(ckt->CKTirhs + (here->MOS3dNodePrime)) += itemp; + + /* capbd over */ + /* all done */ + + break; + default: +; + } + } +} +return(OK); +} + else + return(E_BADPARM); +} diff --git a/src/spicelib/devices/mos3/mos3dset.c b/src/spicelib/devices/mos3/mos3dset.c new file mode 100644 index 000000000..6013da964 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3dset.c @@ -0,0 +1,972 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1988 Jaijeet S Roychowdhury +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "mos3defs.h" +#include "trandefs.h" +#include "distodef.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3dSetup(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + double Beta; + double DrainSatCur; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double arg; + double cdrain; + double evbs; + double sarg; + double sargsw; + double lvgs; + double vbd; + double vbs; + double vds; + double vdsat; + double vgb; + double vgd; + double vgs; + double von; + double lcapgs2,lcapgs3; /* total gate-source capacitance */ + double lcapgd2,lcapgd3; /* total gate-drain capacitance */ + double lcapgb2,lcapgb3; /* total gate-bulk capacitance */ + double lgbs, lgbs2, lgbs3; + double lgbd, lgbd2, lgbd3; + double gm2, gb2, gds2, gmb, gmds, gbds; + double gm3, gb3, gds3, gm2ds, gm2b, gb2ds, gbds2, gmb2, gmds2, gmbds; + double lcapbd, lcapbd2, lcapbd3; + double lcapbs, lcapbs2, lcapbs3; + double ebd; + double vt; /* vt at instance temperature */ + Dderivs d_cdrain; + + + + /* loop through all the MOS3 device models */ + for( ; model != NULL; model = model->MOS3nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + vt = CONSTKoverQ * here->MOS3temp; + + /* first, we compute a few useful values - these could be + * pre-computed, but for historical reasons are still done + * here. They may be moved at the expense of instance size + */ + + EffectiveLength=here->MOS3l - 2*model->MOS3latDiff; + if( (here->MOS3tSatCurDens == 0) || + (here->MOS3drainArea == 0) || + (here->MOS3sourceArea == 0)) { + DrainSatCur = here->MOS3tSatCur; + SourceSatCur = here->MOS3tSatCur; + } else { + DrainSatCur = here->MOS3tSatCurDens * + here->MOS3drainArea; + SourceSatCur = here->MOS3tSatCurDens * + here->MOS3sourceArea; + } + GateSourceOverlapCap = model->MOS3gateSourceOverlapCapFactor * + here->MOS3w; + GateDrainOverlapCap = model->MOS3gateDrainOverlapCapFactor * + here->MOS3w; + GateBulkOverlapCap = model->MOS3gateBulkOverlapCapFactor * + EffectiveLength; + Beta = here->MOS3tTransconductance * here->MOS3w/EffectiveLength; + OxideCap = model->MOS3oxideCapFactor * EffectiveLength * + here->MOS3w; + + + + /* + * ok - now to do the start-up operations + * + * we must get values for vbs, vds, and vgs from somewhere + * so we either predict them or recover them from last iteration + * These are the two most common cases - either a prediction + * step or the general iteration step and they + * share some code, so we put them first - others later on + */ + + + /* general iteration */ + + vbs = model->MOS3type * ( + *(ckt->CKTrhsOld+here->MOS3bNode) - + *(ckt->CKTrhsOld+here->MOS3sNodePrime)); + vgs = model->MOS3type * ( + *(ckt->CKTrhsOld+here->MOS3gNode) - + *(ckt->CKTrhsOld+here->MOS3sNodePrime)); + vds = model->MOS3type * ( + *(ckt->CKTrhsOld+here->MOS3dNodePrime) - + *(ckt->CKTrhsOld+here->MOS3sNodePrime)); + + /* now some common crunching for some more useful quantities */ + + + + /* + * now all the preliminaries are over - we can start doing the + * real work + */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + /* bulk-source and bulk-drain doides + * here we just evaluate the ideal diode current and the + * correspoinding derivative (conductance). + */ + if(vbs <= 0) { + lgbs = SourceSatCur/vt; + lgbs += ckt->CKTgmin; + lgbs2 = lgbs3 = 0; + } else { + evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); + lgbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + lgbs2 = model->MOS3type *0.5 * (lgbs - ckt->CKTgmin)/vt; + lgbs3 = model->MOS3type *lgbs2/(vt*3); + + } + if(vbd <= 0) { + lgbd = DrainSatCur/vt; + lgbd += ckt->CKTgmin; + lgbd2 = lgbd3 = 0; + } else { + ebd = exp(MIN(MAX_EXP_ARG,vbd/vt)); + lgbd = DrainSatCur*ebd/vt +ckt->CKTgmin; + lgbd2 = model->MOS3type *0.5 * (lgbd - ckt->CKTgmin)/vt; + lgbd3 = model->MOS3type *lgbd2/(vt*3); + } + + + /* now to determine whether the user was able to correctly + * identify the source and drain of his device + */ + if(vds >= 0) { + /* normal mode */ + here->MOS3mode = 1; + } else { + /* inverse mode */ + here->MOS3mode = -1; + } + + { + /* + * subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs, + * qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb) + */ + + /* + * this routine evaluates the drain current, its derivatives and + * the charges associated with the gate, channel and bulk + * for mosfets based on semi-empirical equations + */ + + /* + common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld, + 1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof, + 2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev + common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet, + 1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon, + 2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile + common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok, + 1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox, + 2 pivtol,pivrel + */ + + /* equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)*/ + + double coeff0 = 0.0631353e0; + double coeff1 = 0.8013292e0; + double coeff2 = -0.01110777e0; + double oneoverxl; /* 1/effective length */ + double eta; /* eta from model after length factor */ + double phibs; /* phi - vbs */ + double sqphbs; /* square root of phibs */ + double sqphis; /* square root of phi */ + double wps; + double oneoverxj; /* 1/junction depth */ + double xjonxl; /* junction depth/effective length */ + double djonxj; + double wponxj; + double arga; + double argb; + double argc; + double gammas; + double fbodys; + double fbody; + double onfbdy; + double qbonco; + double vbix; + double wconxj; + double vth; + double csonco; + double cdonco; + double vgsx; + double onfg; + double fgate; + double us; + double xn; + double vdsc; + double onvdsc; + double vdsx; + double cdnorm; + double cdo; + double fdrain; + double gdsat; + double cdsat; + double emax; + double delxl; + double dlonxl; + double xlfact; + double ondvt; + double onxn; + double wfact; + double fshort; + double lvds, lvbs, lvbd; + Dderivs d_onxn, d_ondvt, d_wfact, d_MOS3gds; + Dderivs d_emax, d_delxl, d_dlonxl, d_xlfact; + Dderivs d_cdonco, d_fdrain, d_cdsat, d_gdsat; + Dderivs d_vdsx, d_cdo, d_cdnorm, d_Beta, d_dummy; + Dderivs d_vdsc, d_onvdsc, d_arga, d_argb; + Dderivs d_onfg, d_fgate, d_us, d_vgsx; + Dderivs d_von, d_xn, d_vth, d_onfbdy, d_qbonco, d_vbix; + Dderivs d_argc, d_fshort, d_gammas, d_fbodys, d_fbody; + Dderivs d_wps, d_wconxj, d_wponxj; + Dderivs d_phibs, d_sqphbs; + Dderivs d_p, d_q, d_r, d_zero, d_vdsat; + + /* + * bypasses the computation of charges + */ + if (here->MOS3mode == 1) { + lvgs = vgs; + lvds = vds; + lvbs = vbs; + lvbd = vbd; + } else { + lvgs = vgd; + lvds = -vds; + lvbs = vbd; + lvbd = vbs; + } + + /* + * reference cdrain equations to source and + * charge equations to bulk + */ +d_p.value = 0.0; +d_p.d1_p = 1.0; +d_p.d1_q = 0.0; +d_p.d1_r = 0.0; +d_p.d2_p2 = 0.0; +d_p.d2_q2 = 0.0; +d_p.d2_r2 = 0.0; +d_p.d2_pq = 0.0; +d_p.d2_qr = 0.0; +d_p.d2_pr = 0.0; +d_p.d3_p3 = 0.0; +d_p.d3_q3 = 0.0; +d_p.d3_r3 = 0.0; +d_p.d3_p2r = 0.0; +d_p.d3_p2q = 0.0; +d_p.d3_q2r = 0.0; +d_p.d3_pq2 = 0.0; +d_p.d3_pr2 = 0.0; +d_p.d3_qr2 = 0.0; +d_p.d3_pqr = 0.0; + EqualDeriv(&d_q,&d_p); + EqualDeriv(&d_r,&d_p); + EqualDeriv(&d_zero,&d_p); + d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0; + d_q.d1_q = d_r.d1_r = 1.0; + vdsat = 0.0; + EqualDeriv(&d_vdsat,&d_zero); + oneoverxl = 1.0/EffectiveLength;/*const*/ + eta = model->MOS3eta * 8.15e-22/(model->MOS3oxideCapFactor* + EffectiveLength*EffectiveLength*EffectiveLength);/*const*/ + /* + *.....square root term + */ + if ( lvbs <= 0.0 ) { + phibs = here->MOS3tPhi-lvbs; + EqualDeriv(&d_phibs,&d_q); + d_phibs.value = lvbs; + TimesDeriv(&d_phibs,&d_phibs,-1.0); + d_phibs.value += here->MOS3tPhi; + sqphbs = sqrt(phibs); + SqrtDeriv(&d_sqphbs,&d_phibs); + } else { + sqphis = sqrt(here->MOS3tPhi);/*const*/ + /*sqphs3 = here->MOS3tPhi*sqphis;const*/ + sqphbs = sqphis/(1.0+lvbs/ + (here->MOS3tPhi+here->MOS3tPhi)); + EqualDeriv(&d_sqphbs,&d_q); d_sqphbs.value = lvbs; + TimesDeriv(&d_sqphbs,&d_sqphbs,1/(here->MOS3tPhi+here->MOS3tPhi)); + d_sqphbs.value += 1.0; + InvDeriv(&d_sqphbs,&d_sqphbs); + TimesDeriv(&d_sqphbs,&d_sqphbs,sqphis); + phibs = sqphbs*sqphbs; + MultDeriv(&d_phibs,&d_sqphbs,&d_sqphbs); + } + /* + *.....short channel effect factor + */ + if ( (model->MOS3junctionDepth != 0.0) && + (model->MOS3coeffDepLayWidth != 0.0) ) { + wps = model->MOS3coeffDepLayWidth*sqphbs; + TimesDeriv(&d_wps,&d_sqphbs,model->MOS3coeffDepLayWidth); + oneoverxj = 1.0/model->MOS3junctionDepth;/*const*/ + xjonxl = model->MOS3junctionDepth*oneoverxl;/*const*/ + djonxj = model->MOS3latDiff*oneoverxj;/*const*/ + wponxj = wps*oneoverxj; + TimesDeriv(&d_wponxj,&d_wps,oneoverxj); + wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj; + TimesDeriv(&d_wconxj,&d_wponxj,coeff2); + d_wconxj.value += coeff1; + MultDeriv(&d_wconxj,&d_wconxj,&d_wponxj); + d_wconxj.value += coeff0; + arga = wconxj + djonxj; + EqualDeriv(&d_arga,&d_wconxj); d_arga.value += djonxj; + argc = wponxj/(1.0+wponxj); + EqualDeriv(&d_argc,&d_wponxj); + d_argc.value += 1.0; + InvDeriv(&d_argc,&d_argc); + MultDeriv(&d_argc,&d_argc,&d_wponxj); + argb = sqrt(1.0-argc*argc); + MultDeriv(&d_argb,&d_argc,&d_argc); + TimesDeriv(&d_argb,&d_argb,-1.0); + d_argb.value += 1.0; + SqrtDeriv(&d_argb,&d_argb); + + fshort = 1.0-xjonxl*(arga*argb-djonxj); + MultDeriv(&d_fshort,&d_arga,&d_argb); + d_fshort.value -= djonxj; + TimesDeriv(&d_fshort,&d_fshort,-xjonxl); + d_fshort.value += 1.0; + } else { + fshort = 1.0; + EqualDeriv(&d_fshort,&d_zero); + d_fshort.value = 1.0; + + } + /* + *.....body effect + */ + gammas = model->MOS3gamma*fshort; + TimesDeriv(&d_gammas,&d_fshort,model->MOS3gamma); + fbodys = 0.5*gammas/(sqphbs+sqphbs); + DivDeriv(&d_fbodys,&d_gammas,&d_sqphbs); + TimesDeriv(&d_fbodys,&d_fbodys,0.25); + fbody = fbodys+model->MOS3narrowFactor/here->MOS3w; + EqualDeriv(&d_fbody,&d_fbodys); + d_fbody.value += fbody - fbodys; + + onfbdy = 1.0/(1.0+fbody); + EqualDeriv(&d_onfbdy,&d_fbody); + d_onfbdy.value += 1.0; + InvDeriv(&d_onfbdy,&d_onfbdy); + qbonco =gammas*sqphbs+model->MOS3narrowFactor*phibs/here->MOS3w; + EqualDeriv(&d_dummy,&d_phibs); + TimesDeriv(&d_dummy,&d_dummy,model->MOS3narrowFactor*here->MOS3w); + MultDeriv(&d_qbonco,&d_gammas,&d_sqphbs); + PlusDeriv(&d_qbonco,&d_qbonco,&d_dummy); + /* + *.....static feedback effect + */ + vbix = here->MOS3tVbi*model->MOS3type-eta*(lvds); + EqualDeriv(&d_vbix,&d_r); d_vbix.value = vbix; + d_vbix.d1_r = -eta; + /* + *.....threshold voltage + */ + vth = vbix+qbonco; + PlusDeriv(&d_vth,&d_vbix,&d_qbonco); + /* + *.....joint weak inversion and strong inversion + */ + von = vth; + EqualDeriv(&d_von,&d_vth); + if ( model->MOS3fastSurfaceStateDensity != 0.0 ) { + csonco = CHARGE*model->MOS3fastSurfaceStateDensity * + 1e4 /*(cm**2/m**2)*/ *EffectiveLength*here->MOS3w/OxideCap;/*const*/ + cdonco = 0.5*qbonco/phibs; + DivDeriv(&d_cdonco,&d_qbonco,&d_phibs); + TimesDeriv(&d_cdonco,&d_cdonco,0.5); + xn = 1.0+csonco+cdonco; + EqualDeriv(&d_xn,&d_cdonco); + d_xn.value += 1.0 + csonco; + von = vth+vt*xn; + TimesDeriv(&d_von,&d_xn,vt); + PlusDeriv(&d_von,&d_von,&d_vth); + + + } else { + /* + *.....cutoff region + */ + if ( lvgs <= von ) { + cdrain = 0.0; + EqualDeriv(&d_cdrain,&d_zero); + goto innerline1000; + } + } + /* + *.....device is on + */ + vgsx = MAX(lvgs,von); +if (lvgs >= von) { +EqualDeriv(&d_vgsx,&d_p); +d_vgsx.value = lvgs; +} else { +EqualDeriv(&d_vgsx,&d_von); +} + /* + *.....mobility modulation by gate voltage + */ + onfg = 1.0+model->MOS3theta*(vgsx-vth); + TimesDeriv(&d_onfg,&d_vth,-1.0); + PlusDeriv(&d_onfg,&d_onfg,&d_vgsx); + TimesDeriv(&d_onfg,&d_onfg,model->MOS3theta); + d_onfg.value += 1.0; + fgate = 1.0/onfg; + InvDeriv(&d_fgate,&d_onfg); + us = here->MOS3tSurfMob * 1e-4 /*(m**2/cm**2)*/ *fgate; + TimesDeriv(&d_us,&d_fgate,here->MOS3tSurfMob * 1e-4); + /* + *.....saturation voltage + */ + vdsat = (vgsx-vth)*onfbdy; + TimesDeriv(&d_vdsat,&d_vth, -1.0); + PlusDeriv(&d_vdsat,&d_vdsat,&d_vgsx); + MultDeriv(&d_vdsat,&d_vdsat,&d_onfbdy); + if ( model->MOS3maxDriftVel <= 0.0 ) { + } else { + vdsc = EffectiveLength*model->MOS3maxDriftVel/us; + InvDeriv(&d_vdsc,&d_us); + TimesDeriv(&d_vdsc,&d_vdsc,EffectiveLength*model->MOS3maxDriftVel); + onvdsc = 1.0/vdsc; + InvDeriv(&d_onvdsc,&d_vdsc); + arga = (vgsx-vth)*onfbdy; + /* note arga = vdsat at this point */ + EqualDeriv(&d_arga,&d_vdsat); + argb = sqrt(arga*arga+vdsc*vdsc); + MultDeriv(&d_dummy,&d_arga,&d_arga); + MultDeriv(&d_argb,&d_vdsc,&d_vdsc); + PlusDeriv(&d_argb,&d_argb,&d_dummy); + SqrtDeriv(&d_argb,&d_argb); + vdsat = arga+vdsc-argb; + TimesDeriv(&d_vdsat,&d_argb,-1.0); + PlusDeriv(&d_vdsat,&d_vdsat,&d_vdsc); + PlusDeriv(&d_vdsat,&d_vdsat,&d_arga); + } + /* + *.....current factors in linear region + */ + vdsx = MIN((lvds),vdsat); +if (lvds < vdsat) { +EqualDeriv(&d_vdsx,&d_r); +d_vdsx.value = lvds; +} else { +EqualDeriv(&d_vdsx,&d_vdsat); +} + + if ( vdsx == 0.0 ) goto line900; + cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx; + EqualDeriv(&d_cdo,&d_fbody); + d_cdo.value += 1.0; + MultDeriv(&d_cdo,&d_cdo,&d_vdsx); + TimesDeriv(&d_cdo,&d_cdo,0.5); + PlusDeriv(&d_cdo,&d_cdo,&d_vth); + TimesDeriv(&d_cdo,&d_cdo,-1.0); + PlusDeriv(&d_cdo,&d_cdo,&d_vgsx); + + + /* + *.....normalized drain current + */ + cdnorm = cdo*vdsx; + MultDeriv(&d_cdnorm,&d_cdo,&d_vdsx); + /* + *.....drain current without velocity saturation effect + */ +/* Beta is a constant till now */ + Beta = Beta*fgate; + TimesDeriv(&d_Beta,&d_fgate,Beta); + cdrain = Beta*cdnorm; + MultDeriv(&d_cdrain,&d_Beta,&d_cdnorm); + /* + *.....velocity saturation factor + */ + if ( model->MOS3maxDriftVel != 0.0 ) { + fdrain = 1.0/(1.0+vdsx*onvdsc); + MultDeriv(&d_fdrain,&d_vdsx,&d_onvdsc); + d_fdrain.value += 1.0; + InvDeriv(&d_fdrain,&d_fdrain); + /* + *.....drain current + */ + cdrain = fdrain*cdrain; + MultDeriv(&d_cdrain,&d_cdrain,&d_fdrain); + Beta = Beta*fdrain; + MultDeriv(&d_Beta,&d_Beta,&d_fdrain); + + } + /* + *.....channel length modulation + */ + if ( (lvds) <= vdsat ) goto line700; + if ( model->MOS3maxDriftVel == 0.0 ) goto line510; + if (model->MOS3alpha == 0.0) goto line700; + cdsat = cdrain; + EqualDeriv(&d_cdsat,&d_cdrain); + gdsat = cdsat*(1.0-fdrain)*onvdsc; + TimesDeriv(&d_dummy,&d_fdrain,-1.0); + d_dummy.value += 1.0; + MultDeriv(&d_gdsat,&d_cdsat,&d_dummy); + MultDeriv(&d_gdsat,&d_gdsat,&d_onvdsc); + gdsat = MAX(1.0e-12,gdsat); + if (gdsat == 1.0e-12) { + EqualDeriv(&d_gdsat,&d_zero); + d_gdsat.value = gdsat; + } + + emax = cdsat*oneoverxl/gdsat; + DivDeriv(&d_emax,&d_cdsat,&d_gdsat); + TimesDeriv(&d_emax,&d_emax,oneoverxl); + + + arga = 0.5*emax*model->MOS3alpha; + TimesDeriv(&d_arga,&d_emax,0.5*model->MOS3alpha); + argc = model->MOS3kappa*model->MOS3alpha;/*const*/ + argb = sqrt(arga*arga+argc*((lvds)-vdsat)); + TimesDeriv(&d_dummy,&d_vdsat,-1.0); + d_dummy.value += lvds; + d_dummy.d1_r += 1.0; + TimesDeriv(&d_argb,&d_dummy,argc); + MultDeriv(&d_dummy,&d_arga,&d_arga); + PlusDeriv(&d_argb,&d_argb,&d_dummy); + SqrtDeriv(&d_argb,&d_argb); + delxl = argb-arga; + TimesDeriv(&d_delxl,&d_arga,-1.0); + PlusDeriv(&d_delxl,&d_argb,&d_delxl); + goto line520; +line510: + delxl = sqrt(model->MOS3kappa*((lvds)-vdsat)*model->MOS3alpha); + TimesDeriv(&d_delxl,&d_vdsat,-1.0); + d_delxl.value += lvds; + d_delxl.d1_r += 1.0; + TimesDeriv(&d_delxl,&d_delxl,model->MOS3kappa*model->MOS3alpha); + SqrtDeriv(&d_delxl,&d_delxl); + + /* + *.....punch through approximation + */ +line520: + if ( delxl > (0.5*EffectiveLength) ) { + delxl = EffectiveLength - (EffectiveLength*EffectiveLength/ + delxl*0.25); + InvDeriv(&d_delxl,&d_delxl); + TimesDeriv(&d_delxl,&d_delxl,-EffectiveLength*EffectiveLength*0.25); + d_delxl.value += EffectiveLength; + } + /* + *.....saturation region + */ + dlonxl = delxl*oneoverxl; + TimesDeriv(&d_dlonxl,&d_delxl,oneoverxl); + xlfact = 1.0/(1.0-dlonxl); + TimesDeriv(&d_xlfact,&d_dlonxl,-1.0); + d_xlfact.value += 1.0; + InvDeriv(&d_xlfact,&d_xlfact); + + cdrain = cdrain*xlfact; + MultDeriv(&d_cdrain,&d_cdrain,&d_xlfact); + /* + *.....finish strong inversion case + */ +line700: + if ( lvgs < von ) { + /* + *.....weak inversion + */ + onxn = 1.0/xn; + InvDeriv(&d_onxn,&d_xn); + ondvt = onxn/vt; + TimesDeriv(&d_ondvt,&d_onxn,1/vt); + wfact = exp( (lvgs-von)*ondvt ); + TimesDeriv(&d_wfact,&d_von,-1.0); + d_wfact.value += lvgs; + d_wfact.d1_p += 1.0; + MultDeriv(&d_wfact,&d_wfact,&d_ondvt); + ExpDeriv(&d_wfact,&d_wfact); + cdrain = cdrain*wfact; + MultDeriv(&d_cdrain,&d_cdrain,&d_wfact); + } + /* + *.....charge computation + */ + goto innerline1000; + /* + *.....special case of vds = 0.0d0 + */ + +line900: + Beta = Beta*fgate; + /* Beta is still a constant */ + TimesDeriv(&d_Beta,&d_fgate,Beta); + cdrain = 0.0; + EqualDeriv(&d_cdrain,&d_zero); + here->MOS3gds = Beta*(vgsx-vth); + TimesDeriv(&d_MOS3gds,&d_vth,-1.0); + PlusDeriv(&d_MOS3gds,&d_MOS3gds,&d_vgsx); + MultDeriv(&d_MOS3gds,&d_MOS3gds,&d_Beta); + if ( (model->MOS3fastSurfaceStateDensity != 0.0) && + (lvgs < von) ) { + here->MOS3gds *=exp((lvgs-von)/(vt*xn)); + TimesDeriv(&d_dummy,&d_von,-1.0); + d_dummy.value += lvgs; + d_dummy.d1_p += 1.0; + DivDeriv(&d_dummy,&d_dummy,&d_xn); + TimesDeriv(&d_dummy,&d_dummy,1/vt); + ExpDeriv(&d_dummy,&d_dummy); + MultDeriv(&d_MOS3gds,&d_MOS3gds,&d_dummy); + } + d_cdrain.d1_r = d_MOS3gds.value; + d_cdrain.d2_r2 = d_MOS3gds.d1_r; + d_cdrain.d3_r3 = d_MOS3gds.d2_r2; + + + +innerline1000:; + /* + *.....done + */ + } + + + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + /* + * now we do the hard part of the bulk-drain and bulk-source + * diode - we evaluate the non-linear capacitance and + * charge + * + * the basic equations are not hard, but the implementation + * is somewhat long in an attempt to avoid log/exponential + * evaluations + */ + /* + * charge storage elements + * + *.. bulk-drain and bulk-source depletion capacitances + */ + if (vbs < here->MOS3tDepCap){ + arg=1-vbs/here->MOS3tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS3bulkJctBotGradingCoeff == + model->MOS3bulkJctSideGradingCoeff) { + if(model->MOS3bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS3bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS3bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS3bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS3bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS3bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + lcapbs=here->MOS3Cbs*sarg+ + here->MOS3Cbssw*sargsw; + lcapbs2 = model->MOS3type*0.5/here->MOS3tBulkPot*( + here->MOS3Cbs*model->MOS3bulkJctBotGradingCoeff* + sarg/arg + here->MOS3Cbssw* + model->MOS3bulkJctSideGradingCoeff*sargsw/arg); + lcapbs3 = here->MOS3Cbs*sarg* + model->MOS3bulkJctBotGradingCoeff* + (model->MOS3bulkJctBotGradingCoeff+1); + lcapbs3 += here->MOS3Cbssw*sargsw* + model->MOS3bulkJctSideGradingCoeff* + (model->MOS3bulkJctSideGradingCoeff+1); + lcapbs3 = lcapbs3/(6*here->MOS3tBulkPot* + here->MOS3tBulkPot*arg*arg); + } else { + /* *(ckt->CKTstate0 + here->MOS3qbs)= here->MOS3f4s + + vbs*(here->MOS3f2s+vbs*(here->MOS3f3s/2));*/ + lcapbs=here->MOS3f2s+here->MOS3f3s*vbs; + lcapbs2 = 0.5*here->MOS3f3s; + lcapbs3 = 0; + } + if (vbd < here->MOS3tDepCap) { + arg=1-vbd/here->MOS3tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS3bulkJctBotGradingCoeff == .5 && + model->MOS3bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS3bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS3bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS3bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS3bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + lcapbd=here->MOS3Cbd*sarg+ + here->MOS3Cbdsw*sargsw; + lcapbd2 = model->MOS3type*0.5/here->MOS3tBulkPot*( + here->MOS3Cbd*model->MOS3bulkJctBotGradingCoeff* + sarg/arg + here->MOS3Cbdsw* + model->MOS3bulkJctSideGradingCoeff*sargsw/arg); + lcapbd3 = here->MOS3Cbd*sarg* + model->MOS3bulkJctBotGradingCoeff* + (model->MOS3bulkJctBotGradingCoeff+1); + lcapbd3 += here->MOS3Cbdsw*sargsw* + model->MOS3bulkJctSideGradingCoeff* + (model->MOS3bulkJctSideGradingCoeff+1); + lcapbd3 = lcapbd3/(6*here->MOS3tBulkPot* + here->MOS3tBulkPot*arg*arg); + } else { + lcapbd=here->MOS3f2d + vbd * here->MOS3f3d; + lcapbd2=0.5*here->MOS3f3d; + lcapbd3=0; + } + /* + * meyer's capacitor model + */ + /* + * the meyer capacitance equations are in DEVqmeyer + * these expressions are derived from those equations. + * these expressions are incorrect; they assume just one + * controlling variable for each charge storage element + * while actually there are several; the MOS3 small + * signal ac linear model is also wrong because it + * ignores controlled capacitive elements. these can be + * corrected (as can the linear ss ac model) if the + * expressions for the charge are available + */ + + +{ + + + double phi; + double cox; + double vddif; + double vddif1; + double vddif2; + double vgst; + /* von, lvgs and vdsat have already been adjusted for + possible source-drain interchange */ + + + + vgst = lvgs -von; + phi = here->MOS3tPhi; + cox = OxideCap; + if (vgst <= -phi) { + lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else if (vgst <= -phi/2) { + lcapgb2= -cox/(4*phi); + lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else if (vgst <= 0) { + lcapgb2= -cox/(4*phi); + lcapgb3=lcapgs3=lcapgd2=lcapgd3=0; + lcapgs2 = cox/(3*phi); + } else { /* the MOS3modes are around because + vds has not been adjusted */ + if (vdsat <= here->MOS3mode*vds) { + lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; + } else { + vddif = 2.0*vdsat-here->MOS3mode*vds; + vddif1 = vdsat-here->MOS3mode*vds/*-1.0e-12*/; + vddif2 = vddif*vddif; + lcapgd2 = -vdsat*here->MOS3mode*vds*cox/(3*vddif*vddif2); + lcapgd3 = - here->MOS3mode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2); + lcapgs2 = -vddif1*here->MOS3mode*vds*cox/(3*vddif*vddif2); + lcapgs3 = - here->MOS3mode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2); + lcapgb2=lcapgb3=0; + } + } + } + + /* the b-s and b-d diodes need no processing ... */ + here->capbs2 = lcapbs2; + here->capbs3 = lcapbs3; + here->capbd2 = lcapbd2; + here->capbd3 = lcapbd3; + here->gbs2 = lgbs2; + here->gbs3 = lgbs3; + here->gbd2 = lgbd2; + here->gbd3 = lgbd3; + here->capgb2 = model->MOS3type*lcapgb2; + here->capgb3 = lcapgb3; + /* + * process to get Taylor coefficients, taking into + * account type and mode. + */ +gm2 = d_cdrain.d2_p2; +gb2 = d_cdrain.d2_q2; +gds2 = d_cdrain.d2_r2; +gmb = d_cdrain.d2_pq; +gbds = d_cdrain.d2_qr; +gmds = d_cdrain.d2_pr; +gm3 = d_cdrain.d3_p3; +gb3 = d_cdrain.d3_q3; +gds3 = d_cdrain.d3_r3; +gm2ds = d_cdrain.d3_p2r; +gm2b = d_cdrain.d3_p2q; +gb2ds = d_cdrain.d3_q2r; +gmb2 = d_cdrain.d3_pq2; +gmds2 = d_cdrain.d3_pr2; +gbds2 = d_cdrain.d3_qr2; +gmbds = d_cdrain.d3_pqr; + + if (here->MOS3mode == 1) + { + /* normal mode - no source-drain interchange */ + + here->cdr_x2 = gm2; + here->cdr_y2 = gb2;; + here->cdr_z2 = gds2;; + here->cdr_xy = gmb; + here->cdr_yz = gbds; + here->cdr_xz = gmds; + here->cdr_x3 = gm3; + here->cdr_y3 = gb3; + here->cdr_z3 = gds3; + here->cdr_x2z = gm2ds; + here->cdr_x2y = gm2b; + here->cdr_y2z = gb2ds; + here->cdr_xy2 = gmb2; + here->cdr_xz2 = gmds2; + here->cdr_yz2 = gbds2; + here->cdr_xyz = gmbds; + + /* the gate caps have been divided and made into + Taylor coeffs., but not adjusted for type */ + + here->capgs2 = model->MOS3type*lcapgs2; + here->capgs3 = lcapgs3; + here->capgd2 = model->MOS3type*lcapgd2; + here->capgd3 = lcapgd3; +} else { + /* + * inverse mode - source and drain interchanged + */ + +here->cdr_x2 = -gm2; +here->cdr_y2 = -gb2; +here->cdr_z2 = -(gm2 + gb2 + gds2 + 2*(gmb + gmds + gbds)); +here->cdr_xy = -gmb; +here->cdr_yz = gmb + gb2 + gbds; +here->cdr_xz = gm2 + gmb + gmds; +here->cdr_x3 = -gm3; +here->cdr_y3 = -gb3; +here->cdr_z3 = gm3 + gb3 + gds3 + + 3*(gm2b + gm2ds + gmb2 + gb2ds + gmds2 + gbds2) + 6*gmbds ; +here->cdr_x2z = gm3 + gm2b + gm2ds; +here->cdr_x2y = -gm2b; +here->cdr_y2z = gmb2 + gb3 + gb2ds; +here->cdr_xy2 = -gmb2; +here->cdr_xz2 = -(gm3 + 2*(gm2b + gm2ds + gmbds) + + gmb2 + gmds2); +here->cdr_yz2 = -(gb3 + 2*(gmb2 + gb2ds + gmbds) + + gm2b + gbds2); +here->cdr_xyz = gm2b + gmb2 + gmbds; + + here->capgs2 = model->MOS3type*lcapgd2; + here->capgs3 = lcapgd3; + + here->capgd2 = model->MOS3type*lcapgs2; + here->capgd3 = lcapgs3; + +} + +/* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ + +here->cdr_x2 = 0.5*model->MOS3type*here->cdr_x2; +here->cdr_y2 = 0.5*model->MOS3type*here->cdr_y2; +here->cdr_z2 = 0.5*model->MOS3type*here->cdr_z2; +here->cdr_xy = model->MOS3type*here->cdr_xy; +here->cdr_yz = model->MOS3type*here->cdr_yz; +here->cdr_xz = model->MOS3type*here->cdr_xz; +here->cdr_x3 = here->cdr_x3/6.; +here->cdr_y3 = here->cdr_y3/6.; +here->cdr_z3 = here->cdr_z3/6.; +here->cdr_x2z = 0.5*here->cdr_x2z; +here->cdr_x2y = 0.5*here->cdr_x2y; +here->cdr_y2z = 0.5*here->cdr_y2z; +here->cdr_xy2 = 0.5*here->cdr_xy2; +here->cdr_xz2 = 0.5*here->cdr_xz2; +here->cdr_yz2 = 0.5*here->cdr_yz2; + + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3ext.h b/src/spicelib/devices/mos3/mos3ext.h new file mode 100644 index 000000000..06aa589a4 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3ext.h @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int MOS3acLoad(GENmodel*,CKTcircuit*); +extern int MOS3ask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int MOS3convTest(GENmodel *,CKTcircuit *); +extern int MOS3delete(GENmodel*,IFuid,GENinstance**); +extern void MOS3destroy(GENmodel**); +extern int MOS3getic(GENmodel*,CKTcircuit*); +extern int MOS3load(GENmodel*,CKTcircuit*); +extern int MOS3mAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int MOS3mDelete(GENmodel**,IFuid,GENmodel*); +extern int MOS3mParam(int,IFvalue*,GENmodel*); +extern int MOS3param(int,IFvalue*,GENinstance*,IFvalue*); +extern int MOS3pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int MOS3sAcLoad(GENmodel*,CKTcircuit*); +extern int MOS3sLoad(GENmodel*,CKTcircuit*); +extern void MOS3sPrint(GENmodel*,CKTcircuit*); +extern int MOS3sSetup(SENstruct*,GENmodel*); +extern int MOS3sUpdate(GENmodel*,CKTcircuit*); +extern int MOS3setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int MOS3unsetup(GENmodel*,CKTcircuit*); +extern int MOS3temp(GENmodel*,CKTcircuit*); +extern int MOS3trunc(GENmodel*,CKTcircuit*,double*); +extern int MOS3disto(int,GENmodel*,CKTcircuit*); +extern int MOS3noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); +#else /* stdc */ +extern int MOS3acLoad(); +extern int MOS3ask(); +extern int MOS3convTest(); +extern int MOS3delete(); +extern void MOS3destroy(); +extern int MOS3getic(); +extern int MOS3load(); +extern int MOS3mAsk(); +extern int MOS3mDelete(); +extern int MOS3mParam(); +extern int MOS3param(); +extern int MOS3pzLoad(); +extern int MOS3sAcLoad(); +extern int MOS3sLoad(); +extern void MOS3sPrint(); +extern int MOS3sSetup(); +extern int MOS3sUpdate(); +extern int MOS3setup(); +extern int MOS3unsetup(); +extern int MOS3temp(); +extern int MOS3trunc(); +extern int MOS3disto(); +extern int MOS3noise(); +#endif /* stdc */ diff --git a/src/spicelib/devices/mos3/mos3ic.c b/src/spicelib/devices/mos3/mos3ic.c new file mode 100644 index 000000000..dc6f128b5 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3ic.c @@ -0,0 +1,50 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS3getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS3model *model = (MOS3model *)inModel; + MOS3instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->MOS3nextModel) { + for(here = model->MOS3instances; here ; here = here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + if(!here->MOS3icVBSGiven) { + here->MOS3icVBS = + *(ckt->CKTrhs + here->MOS3bNode) - + *(ckt->CKTrhs + here->MOS3sNode); + } + if(!here->MOS3icVDSGiven) { + here->MOS3icVDS = + *(ckt->CKTrhs + here->MOS3dNode) - + *(ckt->CKTrhs + here->MOS3sNode); + } + if(!here->MOS3icVGSGiven) { + here->MOS3icVGS = + *(ckt->CKTrhs + here->MOS3gNode) - + *(ckt->CKTrhs + here->MOS3sNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3itf.h b/src/spicelib/devices/mos3/mos3itf.h new file mode 100644 index 000000000..27069b8fa --- /dev/null +++ b/src/spicelib/devices/mos3/mos3itf.h @@ -0,0 +1,101 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_mos3 + +#ifndef DEV_MOS3 +#define DEV_MOS3 + +#include "mos3ext.h" +extern IFparm MOS3pTable[ ]; +extern IFparm MOS3mPTable[ ]; +extern char *MOS3names[ ]; +extern int MOS3pTSize; +extern int MOS3mPTSize; +extern int MOS3nSize; +extern int MOS3iSize; +extern int MOS3mSize; + +SPICEdev MOS3info = { + { + "Mos3", + "Level 3 MOSfet model with Meyer capacitance model", + + &MOS3nSize, + &MOS3nSize, + MOS3names, + + &MOS3pTSize, + MOS3pTable, + + &MOS3mPTSize, + MOS3mPTable, + DEV_DEFAULT + }, + + MOS3param, + MOS3mParam, + MOS3load, + MOS3setup, + MOS3unsetup, + MOS3setup, + MOS3temp, + MOS3trunc, + NULL, + MOS3acLoad, + NULL, + MOS3destroy, +#ifdef DELETES + MOS3mDelete, + MOS3delete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + MOS3getic, + MOS3ask, + MOS3mAsk, +#ifdef AN_pz + MOS3pzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ +#ifdef NEWCONV + MOS3convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + +#ifdef AN_sense2 + MOS3sSetup, + MOS3sLoad, + MOS3sUpdate, + MOS3sAcLoad, + MOS3sPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ +#ifdef AN_disto + MOS3disto, +#else /* AN_disto */ + NULL, +#endif /* AN_disto */ +#ifdef AN_noise + MOS3noise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &MOS3iSize, + &MOS3mSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/mos3/mos3load.c b/src/spicelib/devices/mos3/mos3load.c new file mode 100644 index 000000000..d4d8242b4 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3load.c @@ -0,0 +1,1342 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "mos3defs.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3load(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + double Beta; + double DrainSatCur; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double arg; + double cbhat; + double cdhat; + double cdrain; + double cdreq; + double ceq; + double ceqbd; + double ceqbs; + double ceqgb; + double ceqgd; + double ceqgs; + double delvbd; + double delvbs; + double delvds; + double delvgd; + double delvgs; + double evbd; + double evbs; + double gcgb; + double gcgd; + double gcgs; + double geq; + double sarg; + double sargsw; + double vbd; + double vbs; + double vds; + double vdsat; + double vgb1; + double vgb; + double vgd1; + double vgd; + double vgdo; + double vgs1; + double vgs; + double von; + double xfact; + int xnrm; + int xrev; + double capgs; /* total gate-source capacitance */ + double capgd; /* total gate-drain capacitance */ + double capgb; /* total gate-bulk capacitance */ + int Check; +#ifndef NOBYPASS + double tempv; +#endif /*NOBYPASS*/ + int error; +#ifdef CAPBYPASS + int senflag; +#endif /* CAPBYPASS */ + int SenCond; + double vt; /* vt at instance temperature */ + + +#ifdef CAPBYPASS + senflag = 0; +#endif /* CAPBYPASS */ + if(ckt->CKTsenInfo){ + if(ckt->CKTsenInfo->SENstatus == PERTURBATION) { + if((ckt->CKTsenInfo->SENmode == ACSEN)|| + (ckt->CKTsenInfo->SENmode == TRANSEN)){ +#ifdef CAPBYPASS + senflag = 1; +#endif /* CAPBYPASS */ + } + goto next; + } + } + + /* loop through all the MOS3 device models */ +next: + for( ; model != NULL; model = model->MOS3nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + vt = CONSTKoverQ * here->MOS3temp; + Check=1; + + if(ckt->CKTsenInfo){ +#ifdef SENSDEBUG + printf("MOS3load \n"); +#endif /* SENSDEBUG */ + + if(ckt->CKTsenInfo->SENstatus == PERTURBATION) + if(here->MOS3senPertFlag == OFF)continue; + + } + SenCond = ckt->CKTsenInfo && here->MOS3senPertFlag; +#ifdef DETAILPROF +asm(" .globl mos3pta"); +asm("mos3pta:"); +#endif /* DETAILPROF */ + + /* first, we compute a few useful values - these could be + * pre-computed, but for historical reasons are still done + * here. They may be moved at the expense of instance size + */ + + EffectiveLength=here->MOS3l - 2*model->MOS3latDiff; + if( (here->MOS3tSatCurDens == 0) || + (here->MOS3drainArea == 0) || + (here->MOS3sourceArea == 0)) { + DrainSatCur = here->MOS3tSatCur; + SourceSatCur = here->MOS3tSatCur; + } else { + DrainSatCur = here->MOS3tSatCurDens * + here->MOS3drainArea; + SourceSatCur = here->MOS3tSatCurDens * + here->MOS3sourceArea; + } + GateSourceOverlapCap = model->MOS3gateSourceOverlapCapFactor * + here->MOS3w; + GateDrainOverlapCap = model->MOS3gateDrainOverlapCapFactor * + here->MOS3w; + GateBulkOverlapCap = model->MOS3gateBulkOverlapCapFactor * + EffectiveLength; + Beta = here->MOS3tTransconductance * here->MOS3w/EffectiveLength; + OxideCap = model->MOS3oxideCapFactor * EffectiveLength * + here->MOS3w; + + if(SenCond){ +#ifdef SENSDEBUG + printf("MOS3senPertFlag = ON \n"); +#endif /* SENSDEBUG */ + if((ckt->CKTsenInfo->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) { + vgs = *(ckt->CKTstate1 + here->MOS3vgs); + vds = *(ckt->CKTstate1 + here->MOS3vds); + vbs = *(ckt->CKTstate1 + here->MOS3vbs); + vbd = *(ckt->CKTstate1 + here->MOS3vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } + else if (ckt->CKTsenInfo->SENmode == ACSEN){ + vgb = model->MOS3type * ( + *(ckt->CKTrhsOp+here->MOS3gNode) - + *(ckt->CKTrhsOp+here->MOS3bNode)); + vbs = *(ckt->CKTstate0 + here->MOS3vbs); + vbd = *(ckt->CKTstate0 + here->MOS3vbd); + vgd = vgb + vbd ; + vgs = vgb + vbs ; + vds = vbs - vbd ; + } + else{ + vgs = *(ckt->CKTstate0 + here->MOS3vgs); + vds = *(ckt->CKTstate0 + here->MOS3vds); + vbs = *(ckt->CKTstate0 + here->MOS3vbs); + vbd = *(ckt->CKTstate0 + here->MOS3vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } +#ifdef SENSDEBUG + printf(" vbs = %.7e ,vbd = %.7e,vgb = %.7e\n",vbs,vbd,vgb); + printf(" vgs = %.7e ,vds = %.7e,vgd = %.7e\n",vgs,vds,vgd); +#endif /* SENSDEBUG */ + goto next1; + } + +#ifdef DETAILPROF +asm(" .globl mos3ptax"); +asm("mos3ptax:"); +#endif /* DETAILPROF */ + + /* + * ok - now to do the start-up operations + * + * we must get values for vbs, vds, and vgs from somewhere + * so we either predict them or recover them from last iteration + * These are the two most common cases - either a prediction + * step or the general iteration step and they + * share some code, so we put them first - others later on + */ + + if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG | + MODEINITTRAN)) || + ( (ckt->CKTmode & MODEINITFIX) && (!here->MOS3off) ) ) { +#ifndef PREDICTOR + if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + + /* predictor step */ + + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->MOS3vbs) = + *(ckt->CKTstate1 + here->MOS3vbs); + vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS3vbs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS3vbs))); + *(ckt->CKTstate0 + here->MOS3vgs) = + *(ckt->CKTstate1 + here->MOS3vgs); + vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS3vgs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS3vgs))); + *(ckt->CKTstate0 + here->MOS3vds) = + *(ckt->CKTstate1 + here->MOS3vds); + vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS3vds)) + -(xfact * (*(ckt->CKTstate2 + here->MOS3vds))); + *(ckt->CKTstate0 + here->MOS3vbd) = + *(ckt->CKTstate0 + here->MOS3vbs)- + *(ckt->CKTstate0 + here->MOS3vds); + } else { +#endif /*PREDICTOR*/ + + /* general iteration */ + + vbs = model->MOS3type * ( + *(ckt->CKTrhsOld+here->MOS3bNode) - + *(ckt->CKTrhsOld+here->MOS3sNodePrime)); + vgs = model->MOS3type * ( + *(ckt->CKTrhsOld+here->MOS3gNode) - + *(ckt->CKTrhsOld+here->MOS3sNodePrime)); + vds = model->MOS3type * ( + *(ckt->CKTrhsOld+here->MOS3dNodePrime) - + *(ckt->CKTrhsOld+here->MOS3sNodePrime)); +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + + /* now some common crunching for some more useful quantities */ +#ifdef DETAILPROF +asm(" .globl mos3ptay"); +asm("mos3ptay:"); +#endif /* DETAILPROF */ + + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS3vgs) - + *(ckt->CKTstate0 + here->MOS3vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS3vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS3vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS3vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS3vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS3mode >= 0) { + cdhat= + here->MOS3cd- + here->MOS3gbd * delvbd + + here->MOS3gmbs * delvbs + + here->MOS3gm * delvgs + + here->MOS3gds * delvds ; + } else { + cdhat= + here->MOS3cd - + ( here->MOS3gbd - + here->MOS3gmbs) * delvbd - + here->MOS3gm * delvgd + + here->MOS3gds * delvds ; + } + cbhat= + here->MOS3cbs + + here->MOS3cbd + + here->MOS3gbd * delvbd + + here->MOS3gbs * delvbs ; + +#ifdef DETAILPROF +asm(" .globl mos3ptb"); +asm("mos3ptb:"); +#endif /* DETAILPROF */ +#ifndef NOBYPASS + /* now lets see if we can bypass (ugh) */ + /* the following mess should be one if statement, but + * many compilers can't handle it all at once, so it + * is split into several successive if statements + */ + tempv = MAX(fabs(cbhat),fabs(here->MOS3cbs + + here->MOS3cbd))+ckt->CKTabstol; + if((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG) + )) && (ckt->CKTbypass) ) + if ( (fabs(cbhat-(here->MOS3cbs + + here->MOS3cbd)) < ckt->CKTreltol * + tempv)) + if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS3vbs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS3vbd)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->MOS3vgs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->MOS3vds)))+ + ckt->CKTvoltTol)) ) + if( (fabs(cdhat- here->MOS3cd) < + ckt->CKTreltol * MAX(fabs(cdhat),fabs( + here->MOS3cd)) + ckt->CKTabstol) ) { + /* bypass code */ + /* nothing interesting has changed since last + * iteration on this device, so we just + * copy all the values computed last iteration out + * and keep going + */ + vbs = *(ckt->CKTstate0 + here->MOS3vbs); + vbd = *(ckt->CKTstate0 + here->MOS3vbd); + vgs = *(ckt->CKTstate0 + here->MOS3vgs); + vds = *(ckt->CKTstate0 + here->MOS3vds); + vgd = vgs - vds; + vgb = vgs - vbs; + cdrain = here->MOS3mode * (here->MOS3cd + here->MOS3cbd); + if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { + capgs = ( *(ckt->CKTstate0+here->MOS3capgs)+ + *(ckt->CKTstate1+here->MOS3capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS3capgd)+ + *(ckt->CKTstate1+here->MOS3capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS3capgb)+ + *(ckt->CKTstate1+here->MOS3capgb) + + GateBulkOverlapCap ); + } + goto bypass; + } +#endif /*NOBYPASS*/ + +#ifdef DETAILPROF +asm(" .globl mos3ptc"); +asm("mos3ptc:"); +#endif /* DETAILPROF */ + /* ok - bypass is out, do it the hard way */ + + von = model->MOS3type * here->MOS3von; + +#ifndef NODELIMITING + /* + * limiting + * we want to keep device voltages from changing + * so fast that the exponentials churn out overflows + * and similar rudeness + */ + + if(*(ckt->CKTstate0 + here->MOS3vds) >=0) { + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS3vgs) + ,von); + vds = vgs - vgd; + vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS3vds)); + vgd = vgs - vds; + } else { + vgd = DEVfetlim(vgd,vgdo,von); + vds = vgs - vgd; + if(!(ckt->CKTfixLimit)) { + vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + + here->MOS3vds))); + } + vgs = vgd + vds; + } + if(vds >= 0) { + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS3vbs), + vt,here->MOS3sourceVcrit,&Check); + vbd = vbs-vds; + } else { + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS3vbd), + vt,here->MOS3drainVcrit,&Check); + vbs = vbd + vds; + } +#endif /*NODELIMITING*/ + + } else { + +#ifdef DETAILPROF +asm(" .globl mos3ptd"); +asm("mos3ptd:"); +#endif /* DETAILPROF */ + /* ok - not one of the simple cases, so we have to + * look at all of the possibilities for why we were + * called. We still just initialize the three voltages + */ + + if((ckt->CKTmode & MODEINITJCT) && !here->MOS3off) { + vds= model->MOS3type * here->MOS3icVDS; + vgs= model->MOS3type * here->MOS3icVGS; + vbs= model->MOS3type * here->MOS3icVBS; + if((vds==0) && (vgs==0) && (vbs==0) && + ((ckt->CKTmode & + (MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || + (!(ckt->CKTmode & MODEUIC)))) { + vbs = -1; + vgs = model->MOS3type * here->MOS3tVto; + vds = 0; + } + } else { + vbs=vgs=vds=0; + } + } + +#ifdef DETAILPROF +asm(" .globl mos3pte"); +asm("mos3pte:"); +#endif /* DETAILPROF */ + /* + * now all the preliminaries are over - we can start doing the + * real work + */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + + /* + * bulk-source and bulk-drain diodes + * here we just evaluate the ideal diode current and the + * corresponding derivative (conductance). + */ +next1: if(vbs <= 0) { + here->MOS3gbs = SourceSatCur/vt; + here->MOS3cbs = here->MOS3gbs*vbs; + here->MOS3gbs += ckt->CKTgmin; + } else { + evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); + here->MOS3gbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + here->MOS3cbs = SourceSatCur * (evbs-1); + } + if(vbd <= 0) { + here->MOS3gbd = DrainSatCur/vt; + here->MOS3cbd = here->MOS3gbd *vbd; + here->MOS3gbd += ckt->CKTgmin; + } else { + evbd = exp(MIN(MAX_EXP_ARG,vbd/vt)); + here->MOS3gbd = DrainSatCur*evbd/vt +ckt->CKTgmin; + here->MOS3cbd = DrainSatCur *(evbd-1); + } + + /* now to determine whether the user was able to correctly + * identify the source and drain of his device + */ + if(vds >= 0) { + /* normal mode */ + here->MOS3mode = 1; + } else { + /* inverse mode */ + here->MOS3mode = -1; + } + +#ifdef DETAILPROF +asm(" .globl mos3ptf"); +asm("mos3ptf:"); +#endif /* DETAILPROF */ + { + /* + * subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs, + * qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb) + */ + + /* + * this routine evaluates the drain current, its derivatives and + * the charges associated with the gate, channel and bulk + * for mosfets based on semi-empirical equations + */ + + /* + common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld, + 1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof, + 2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev + common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet, + 1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon, + 2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile + common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok, + 1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox, + 2 pivtol,pivrel + */ + + /* equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)*/ + + double coeff0 = 0.0631353e0; + double coeff1 = 0.8013292e0; + double coeff2 = -0.01110777e0; + double oneoverxl; /* 1/effective length */ + double eta; /* eta from model after length factor */ + double phibs; /* phi - vbs */ + double sqphbs; /* square root of phibs */ + double dsqdvb; /* */ + double sqphis; /* square root of phi */ + double sqphs3; /* square root of phi cubed */ + double wps; + double oneoverxj; /* 1/junction depth */ + double xjonxl; /* junction depth/effective length */ + double djonxj; + double wponxj; + double arga; + double argb; + double argc; + double dwpdvb; + double dadvb; + double dbdvb; + double gammas; + double fbodys; + double fbody; + double onfbdy; + double qbonco; + double vbix; + double wconxj; + double dfsdvb; + double dfbdvb; + double dqbdvb; + double vth; + double dvtdvb; + double csonco; + double cdonco; + double dxndvb; + double dvodvb; + double dvodvd; + double vgsx; + double dvtdvd; + double onfg; + double fgate; + double us; + double dfgdvg; + double dfgdvd; + double dfgdvb; + double dvsdvg; + double dvsdvb; + double dvsdvd; + double xn; + double vdsc; + double onvdsc; + double dvsdga; + double vdsx; + double dcodvb; + double cdnorm; + double cdo; + double cd1; + double fdrain; + double fd2; + double dfddvg; + double dfddvb; + double dfddvd; + double gdsat; + double cdsat; + double gdoncd; + double gdonfd; + double gdonfg; + double dgdvg; + double dgdvd; + double dgdvb; + double emax; + double emongd; + double demdvg; + double demdvd; + double demdvb; + double delxl; + double dldvd; + double dldem; + double ddldvg; + double ddldvd; + double ddldvb; + double dlonxl; + double xlfact; + double diddl; + double gds0; + double emoncd; + double ondvt; + double onxn; + double wfact; + double gms; + double gmw; + double fshort; + + /* + * bypasses the computation of charges + */ + + /* + * reference cdrain equations to source and + * charge equations to bulk + */ + vdsat = 0.0; + oneoverxl = 1.0/EffectiveLength; + eta = model->MOS3eta * 8.15e-22/(model->MOS3oxideCapFactor* + EffectiveLength*EffectiveLength*EffectiveLength); + /* + *.....square root term + */ + if ( (here->MOS3mode==1?vbs:vbd) <= 0.0 ) { + phibs = here->MOS3tPhi-(here->MOS3mode==1?vbs:vbd); + sqphbs = sqrt(phibs); + dsqdvb = -0.5/sqphbs; + } else { + sqphis = sqrt(here->MOS3tPhi); + sqphs3 = here->MOS3tPhi*sqphis; + sqphbs = sqphis/(1.0+(here->MOS3mode==1?vbs:vbd)/ + (here->MOS3tPhi+here->MOS3tPhi)); + phibs = sqphbs*sqphbs; + dsqdvb = -phibs/(sqphs3+sqphs3); + } + /* + *.....short channel effect factor + */ + if ( (model->MOS3junctionDepth != 0.0) && + (model->MOS3coeffDepLayWidth != 0.0) ) { + wps = model->MOS3coeffDepLayWidth*sqphbs; + oneoverxj = 1.0/model->MOS3junctionDepth; + xjonxl = model->MOS3junctionDepth*oneoverxl; + djonxj = model->MOS3latDiff*oneoverxj; + wponxj = wps*oneoverxj; + wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj; + arga = wconxj+djonxj; + argc = wponxj/(1.0+wponxj); + argb = sqrt(1.0-argc*argc); + fshort = 1.0-xjonxl*(arga*argb-djonxj); + dwpdvb = model->MOS3coeffDepLayWidth*dsqdvb; + dadvb = (coeff1+coeff2*(wponxj+wponxj))*dwpdvb*oneoverxj; + dbdvb = -argc*argc*(1.0-argc)*dwpdvb/(argb*wps); + dfsdvb = -xjonxl*(dadvb*argb+arga*dbdvb); + } else { + fshort = 1.0; + dfsdvb = 0.0; + } + /* + *.....body effect + */ + gammas = model->MOS3gamma*fshort; + fbodys = 0.5*gammas/(sqphbs+sqphbs); + fbody = fbodys+model->MOS3narrowFactor/here->MOS3w; + onfbdy = 1.0/(1.0+fbody); + dfbdvb = -fbodys*dsqdvb/sqphbs+fbodys*dfsdvb/fshort; + qbonco =gammas*sqphbs+model->MOS3narrowFactor*phibs/here->MOS3w; + dqbdvb = gammas*dsqdvb+model->MOS3gamma*dfsdvb*sqphbs- + model->MOS3narrowFactor/here->MOS3w; + /* + *.....static feedback effect + */ + vbix = here->MOS3tVbi*model->MOS3type-eta*(here->MOS3mode*vds); + /* + *.....threshold voltage + */ + vth = vbix+qbonco; + dvtdvd = -eta; + dvtdvb = dqbdvb; + /* + *.....joint weak inversion and strong inversion + */ + von = vth; + if ( model->MOS3fastSurfaceStateDensity != 0.0 ) { + csonco = CHARGE*model->MOS3fastSurfaceStateDensity * + 1e4 /*(cm**2/m**2)*/ *EffectiveLength*here->MOS3w/OxideCap; + cdonco = qbonco/(phibs+phibs); + xn = 1.0+csonco+cdonco; + von = vth+vt*xn; + dxndvb = dqbdvb/(phibs+phibs)-qbonco*dsqdvb/(phibs*sqphbs); + dvodvd = dvtdvd; + dvodvb = dvtdvb+vt*dxndvb; + } else { + /* + *.....cutoff region + */ + if ( (here->MOS3mode==1?vgs:vgd) <= von ) { + cdrain = 0.0; + here->MOS3gm = 0.0; + here->MOS3gds = 0.0; + here->MOS3gmbs = 0.0; + goto innerline1000; + } + } + /* + *.....device is on + */ + vgsx = MAX((here->MOS3mode==1?vgs:vgd),von); + /* + *.....mobility modulation by gate voltage + */ + onfg = 1.0+model->MOS3theta*(vgsx-vth); + fgate = 1.0/onfg; + us = here->MOS3tSurfMob * 1e-4 /*(m**2/cm**2)*/ *fgate; + dfgdvg = -model->MOS3theta*fgate*fgate; + dfgdvd = -dfgdvg*dvtdvd; + dfgdvb = -dfgdvg*dvtdvb; + /* + *.....saturation voltage + */ + vdsat = (vgsx-vth)*onfbdy; + if ( model->MOS3maxDriftVel <= 0.0 ) { + dvsdvg = onfbdy; + dvsdvd = -dvsdvg*dvtdvd; + dvsdvb = -dvsdvg*dvtdvb-vdsat*dfbdvb*onfbdy; + } else { + vdsc = EffectiveLength*model->MOS3maxDriftVel/us; + onvdsc = 1.0/vdsc; + arga = (vgsx-vth)*onfbdy; + argb = sqrt(arga*arga+vdsc*vdsc); + vdsat = arga+vdsc-argb; + dvsdga = (1.0-arga/argb)*onfbdy; + dvsdvg = dvsdga-(1.0-vdsc/argb)*vdsc*dfgdvg*onfg; + dvsdvd = -dvsdvg*dvtdvd; + dvsdvb = -dvsdvg*dvtdvb-arga*dvsdga*dfbdvb; + } + /* + *.....current factors in linear region + */ + vdsx = MIN((here->MOS3mode*vds),vdsat); + if ( vdsx == 0.0 ) goto line900; + cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx; + dcodvb = -dvtdvb-0.5*dfbdvb*vdsx; + /* + *.....normalized drain current + */ + cdnorm = cdo*vdsx; + here->MOS3gm = vdsx; + here->MOS3gds = vgsx-vth-(1.0+fbody+dvtdvd)*vdsx; + here->MOS3gmbs = dcodvb*vdsx; + /* + *.....drain current without velocity saturation effect + */ + cd1 = Beta*cdnorm; + Beta = Beta*fgate; + cdrain = Beta*cdnorm; + here->MOS3gm = Beta*here->MOS3gm+dfgdvg*cd1; + here->MOS3gds = Beta*here->MOS3gds+dfgdvd*cd1; + here->MOS3gmbs = Beta*here->MOS3gmbs; + /* + *.....velocity saturation factor + */ + if ( model->MOS3maxDriftVel != 0.0 ) { + fdrain = 1.0/(1.0+vdsx*onvdsc); + fd2 = fdrain*fdrain; + arga = fd2*vdsx*onvdsc*onfg; + dfddvg = -dfgdvg*arga; + dfddvd = -dfgdvd*arga-fd2*onvdsc; + dfddvb = -dfgdvb*arga; + /* + *.....drain current + */ + here->MOS3gm = fdrain*here->MOS3gm+dfddvg*cdrain; + here->MOS3gds = fdrain*here->MOS3gds+dfddvd*cdrain; + here->MOS3gmbs = fdrain*here->MOS3gmbs+dfddvb*cdrain; + cdrain = fdrain*cdrain; + Beta = Beta*fdrain; + } + /* + *.....channel length modulation + */ + if ( (here->MOS3mode*vds) <= vdsat ) goto line700; + if ( model->MOS3maxDriftVel <= 0.0 ) goto line510; + if (model->MOS3alpha == 0.0) goto line700; + cdsat = cdrain; + gdsat = cdsat*(1.0-fdrain)*onvdsc; + gdsat = MAX(1.0e-12,gdsat); + gdoncd = gdsat/cdsat; + gdonfd = gdsat/(1.0-fdrain); + gdonfg = gdsat*onfg; + dgdvg = gdoncd*here->MOS3gm-gdonfd*dfddvg+gdonfg*dfgdvg; + dgdvd = gdoncd*here->MOS3gds-gdonfd*dfddvd+gdonfg*dfgdvd; + dgdvb = gdoncd*here->MOS3gmbs-gdonfd*dfddvb+gdonfg*dfgdvb; + + if (ckt->CKTbadMos3) + emax = cdsat*oneoverxl/gdsat; + else + emax = model->MOS3kappa * cdsat*oneoverxl/gdsat; + emoncd = emax/cdsat; + emongd = emax/gdsat; + demdvg = emoncd*here->MOS3gm-emongd*dgdvg; + demdvd = emoncd*here->MOS3gds-emongd*dgdvd; + demdvb = emoncd*here->MOS3gmbs-emongd*dgdvb; + + arga = 0.5*emax*model->MOS3alpha; + argc = model->MOS3kappa*model->MOS3alpha; + argb = sqrt(arga*arga+argc*((here->MOS3mode*vds)-vdsat)); + delxl = argb-arga; + if (argb != 0.0) { + dldvd = argc/(argb+argb); + dldem = 0.5*(arga/argb-1.0)*model->MOS3alpha; + } else { + dldvd = 0.0; + dldem = 0.0; + } + ddldvg = dldem*demdvg; + ddldvd = dldem*demdvd-dldvd; + ddldvb = dldem*demdvb; + goto line520; +line510: + delxl = sqrt(model->MOS3kappa*((here->MOS3mode*vds)-vdsat)* + model->MOS3alpha); + dldvd = 0.5*delxl/((here->MOS3mode*vds)-vdsat); + ddldvg = 0.0; + ddldvd = -dldvd; + ddldvb = 0.0; + /* + *.....punch through approximation + */ +line520: + if ( delxl > (0.5*EffectiveLength) ) { + delxl = EffectiveLength-(EffectiveLength*EffectiveLength/ + (4.0*delxl)); + arga = 4.0*(EffectiveLength-delxl)*(EffectiveLength-delxl)/ + (EffectiveLength*EffectiveLength); + ddldvg = ddldvg*arga; + ddldvd = ddldvd*arga; + ddldvb = ddldvb*arga; + dldvd = dldvd*arga; + } + /* + *.....saturation region + */ + dlonxl = delxl*oneoverxl; + xlfact = 1.0/(1.0-dlonxl); + cdrain = cdrain*xlfact; + diddl = cdrain/(EffectiveLength-delxl); + here->MOS3gm = here->MOS3gm*xlfact+diddl*ddldvg; + gds0 = here->MOS3gds*xlfact+diddl*ddldvd; + here->MOS3gmbs = here->MOS3gmbs*xlfact+diddl*ddldvb; + here->MOS3gm = here->MOS3gm+gds0*dvsdvg; + here->MOS3gmbs = here->MOS3gmbs+gds0*dvsdvb; + here->MOS3gds = gds0*dvsdvd+diddl*dldvd; + /* + *.....finish strong inversion case + */ +line700: + if ( (here->MOS3mode==1?vgs:vgd) < von ) { + /* + *.....weak inversion + */ + onxn = 1.0/xn; + ondvt = onxn/vt; + wfact = exp( ((here->MOS3mode==1?vgs:vgd)-von)*ondvt ); + cdrain = cdrain*wfact; + gms = here->MOS3gm*wfact; + gmw = cdrain*ondvt; + here->MOS3gm = gmw; + if ((here->MOS3mode*vds) > vdsat) { + here->MOS3gm = here->MOS3gm+gds0*dvsdvg*wfact; + } + here->MOS3gds = here->MOS3gds*wfact+(gms-gmw)*dvodvd; + here->MOS3gmbs = here->MOS3gmbs*wfact+(gms-gmw)*dvodvb-gmw* + ((here->MOS3mode==1?vgs:vgd)-von)*onxn*dxndvb; + } + /* + *.....charge computation + */ + goto innerline1000; + /* + *.....special case of vds = 0.0d0 + */ +line900: + Beta = Beta*fgate; + cdrain = 0.0; + here->MOS3gm = 0.0; + here->MOS3gds = Beta*(vgsx-vth); + here->MOS3gmbs = 0.0; + if ( (model->MOS3fastSurfaceStateDensity != 0.0) && + ((here->MOS3mode==1?vgs:vgd) < von) ) { + here->MOS3gds *=exp(((here->MOS3mode==1?vgs:vgd)-von)/(vt*xn)); + } +innerline1000:; + /* + *.....done + */ + } + +#ifdef DETAILPROF +asm(" .globl mos3ptg"); +asm("mos3ptg:"); +#endif /* DETAILPROF */ + + /* now deal with n vs p polarity */ + + here->MOS3von = model->MOS3type * von; + here->MOS3vdsat = model->MOS3type * vdsat; + /* line 490 */ + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + here->MOS3cd=here->MOS3mode * cdrain - here->MOS3cbd; + + if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) { + /* + * now we do the hard part of the bulk-drain and bulk-source + * diode - we evaluate the non-linear capacitance and + * charge + * + * the basic equations are not hard, but the implementation + * is somewhat long in an attempt to avoid log/exponential + * evaluations + */ + /* + * charge storage elements + * + *.. bulk-drain and bulk-source depletion capacitances + */ +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbs) >= ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS3vbs)))+ + ckt->CKTvoltTol)|| senflag ) +#endif /*CAPBYPASS*/ + { + /* can't bypass the diode capacitance calculations */ +#ifdef CAPZEROBYPASS + if(here->MOS3Cbs != 0 || here->MOS3Cbssw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbs < here->MOS3tDepCap){ + arg=1-vbs/here->MOS3tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS3bulkJctBotGradingCoeff == + model->MOS3bulkJctSideGradingCoeff) { + if(model->MOS3bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS3bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS3bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS3bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS3bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS3bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS3qbs) = + here->MOS3tBulkPot*(here->MOS3Cbs* + (1-arg*sarg)/(1-model->MOS3bulkJctBotGradingCoeff) + +here->MOS3Cbssw* + (1-arg*sargsw)/ + (1-model->MOS3bulkJctSideGradingCoeff)); + here->MOS3capbs=here->MOS3Cbs*sarg+ + here->MOS3Cbssw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS3qbs) = here->MOS3f4s + + vbs*(here->MOS3f2s+vbs*(here->MOS3f3s/2)); + here->MOS3capbs=here->MOS3f2s+here->MOS3f3s*vbs; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS3qbs) = 0; + here->MOS3capbs=0; + } +#endif /*CAPZEROBYPASS*/ + } +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS3vbd)))+ + ckt->CKTvoltTol)|| senflag ) +#endif /*CAPBYPASS*/ + /* can't bypass the diode capacitance calculations */ + { +#ifdef CAPZEROBYPASS + if(here->MOS3Cbd != 0 || here->MOS3Cbdsw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbd < here->MOS3tDepCap) { + arg=1-vbd/here->MOS3tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS3bulkJctBotGradingCoeff == .5 && + model->MOS3bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS3bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS3bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS3bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS3bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS3qbd) = + here->MOS3tBulkPot*(here->MOS3Cbd* + (1-arg*sarg) + /(1-model->MOS3bulkJctBotGradingCoeff) + +here->MOS3Cbdsw* + (1-arg*sargsw) + /(1-model->MOS3bulkJctSideGradingCoeff)); + here->MOS3capbd=here->MOS3Cbd*sarg+ + here->MOS3Cbdsw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS3qbd) = here->MOS3f4d + + vbd * (here->MOS3f2d + vbd * here->MOS3f3d/2); + here->MOS3capbd=here->MOS3f2d + vbd * here->MOS3f3d; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS3qbd) = 0; + here->MOS3capbd = 0; + } +#endif /*CAPZEROBYPASS*/ + } +#ifdef DETAILPROF +asm(" .globl mos3pth"); +asm("mos3pth:"); +#endif /* DETAILPROF */ + if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; + + if ( ckt->CKTmode & MODETRAN ) { + /* (above only excludes tranop, since we're only at this + * point if tran or tranop ) + */ + + /* + * calculate equivalent conductances and currents for + * depletion capacitors + */ + + /* integrate the capacitors and save results */ + + error = NIintegrate(ckt,&geq,&ceq,here->MOS3capbd, + here->MOS3qbd); + if(error) return(error); + here->MOS3gbd += geq; + here->MOS3cbd += *(ckt->CKTstate0 + here->MOS3cqbd); + here->MOS3cd -= *(ckt->CKTstate0 + here->MOS3cqbd); + error = NIintegrate(ckt,&geq,&ceq,here->MOS3capbs, + here->MOS3qbs); + if(error) return(error); + here->MOS3gbs += geq; + here->MOS3cbs += *(ckt->CKTstate0 + here->MOS3cqbs); + } + } +#ifdef DETAILPROF +asm(" .globl mos3pti"); +asm("mos3pti:"); +#endif /* DETAILPROF */ + if(SenCond) goto next2; + + /* + * check convergence + */ + if ( (here->MOS3off == 0) || + (!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV + } else { + tol=ckt->CKTreltol*MAX(fabs(cdhat), + fabs(here->MOS3cd))+ckt->CKTabstol; + if (fabs(cdhat-here->MOS3cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } else { + tol=ckt->CKTreltol*MAX(fabs(cbhat), + fabs(here->MOS3cbs+here->MOS3cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS3cbs+here->MOS3cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } +#endif /* NEWCONV */ + } + } + +#ifdef DETAILPROF +asm(" .globl mos3ptj"); +asm("mos3ptj:"); +#endif /* DETAILPROF */ + + /* save things away for next time */ + +next2: *(ckt->CKTstate0 + here->MOS3vbs) = vbs; + *(ckt->CKTstate0 + here->MOS3vbd) = vbd; + *(ckt->CKTstate0 + here->MOS3vgs) = vgs; + *(ckt->CKTstate0 + here->MOS3vds) = vds; + +#ifdef DETAILPROF +asm(" .globl mos3ptk"); +asm("mos3ptk:"); +#endif /* DETAILPROF */ + + /* + * meyer's capacitor model + */ + if ( ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG) ) { + /* + * calculate meyer's capacitors + */ + /* + * new cmeyer - this just evaluates at the current time, + * expects you to remember values from previous time + * returns 1/2 of non-constant portion of capacitance + * you must add in the other half from previous time + * and the constant part + */ + if (here->MOS3mode > 0){ + DEVqmeyer (vgs,vgd,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS3capgs), + (ckt->CKTstate0 + here->MOS3capgd), + (ckt->CKTstate0 + here->MOS3capgb), + here->MOS3tPhi,OxideCap); + } else { + DEVqmeyer (vgd,vgs,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS3capgd), + (ckt->CKTstate0 + here->MOS3capgs), + (ckt->CKTstate0 + here->MOS3capgb), + here->MOS3tPhi,OxideCap); + } + vgs1 = *(ckt->CKTstate1 + here->MOS3vgs); + vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS3vds); + vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS3vbs); + if(ckt->CKTmode & MODETRANOP) { + capgs = 2 * *(ckt->CKTstate0+here->MOS3capgs)+ + GateSourceOverlapCap ; + capgd = 2 * *(ckt->CKTstate0+here->MOS3capgd)+ + GateDrainOverlapCap ; + capgb = 2 * *(ckt->CKTstate0+here->MOS3capgb)+ + GateBulkOverlapCap ; + } else { + capgs = ( *(ckt->CKTstate0+here->MOS3capgs)+ + *(ckt->CKTstate1+here->MOS3capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS3capgd)+ + *(ckt->CKTstate1+here->MOS3capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS3capgb)+ + *(ckt->CKTstate1+here->MOS3capgb) + + GateBulkOverlapCap ); + } + if(ckt->CKTsenInfo){ + here->MOS3cgs = capgs; + here->MOS3cgd = capgd; + here->MOS3cgb = capgb; + } + +#ifdef DETAILPROF +asm(" .globl mos3ptl"); +asm("mos3ptl:"); +#endif /* DETAILPROF */ + /* + * store small-signal parameters (for meyer's model) + * all parameters already stored, so done... + */ + + + if(SenCond){ + if(ckt->CKTsenInfo->SENmode & (DCSEN|ACSEN)) { + continue; + } + } +#ifndef PREDICTOR + if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + *(ckt->CKTstate0 + here->MOS3qgs) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS3qgs) + - xfact * *(ckt->CKTstate2 + here->MOS3qgs); + *(ckt->CKTstate0 + here->MOS3qgd) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS3qgd) + - xfact * *(ckt->CKTstate2 + here->MOS3qgd); + *(ckt->CKTstate0 + here->MOS3qgb) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS3qgb) + - xfact * *(ckt->CKTstate2 + here->MOS3qgb); + } else { +#endif /*PREDICTOR*/ + if(ckt->CKTmode & MODETRAN) { + *(ckt->CKTstate0 + here->MOS3qgs) = (vgs-vgs1)*capgs + + *(ckt->CKTstate1 + here->MOS3qgs) ; + *(ckt->CKTstate0 + here->MOS3qgd) = (vgd-vgd1)*capgd + + *(ckt->CKTstate1 + here->MOS3qgd) ; + *(ckt->CKTstate0 + here->MOS3qgb) = (vgb-vgb1)*capgb + + *(ckt->CKTstate1 + here->MOS3qgb) ; + } else { + /* TRANOP only */ + *(ckt->CKTstate0 + here->MOS3qgs) = vgs*capgs; + *(ckt->CKTstate0 + here->MOS3qgd) = vgd*capgd; + *(ckt->CKTstate0 + here->MOS3qgb) = vgb*capgb; + } +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + } +bypass: + if(SenCond) continue; +#ifdef DETAILPROF +asm(" .globl mos3ptm"); +asm("mos3ptm:"); +#endif /* DETAILPROF */ + + if ( (ckt->CKTmode & (MODEINITTRAN)) || + (! (ckt->CKTmode & (MODETRAN)) ) ) { + /* + * initialize to zero charge conductances + * and current + */ + gcgs=0; + ceqgs=0; + gcgd=0; + ceqgd=0; + gcgb=0; + ceqgb=0; + } else { + if(capgs == 0) *(ckt->CKTstate0 + here->MOS3cqgs) =0; + if(capgd == 0) *(ckt->CKTstate0 + here->MOS3cqgd) =0; + if(capgb == 0) *(ckt->CKTstate0 + here->MOS3cqgb) =0; + /* + * calculate equivalent conductances and currents for + * meyer"s capacitors + */ + error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS3qgs); + if(error) return(error); + error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS3qgd); + if(error) return(error); + error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS3qgb); + if(error) return(error); + ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS3qgs); + ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS3qgd); + ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS3qgb); + } + /* + * store charge storage info for meyer's cap in lx table + */ + +#ifdef DETAILPROF +asm(" .globl mos3ptn"); +asm("mos3ptn:"); +#endif /* DETAILPROF */ + /* + * load current vector + */ + ceqbs = model->MOS3type * + (here->MOS3cbs-(here->MOS3gbs-ckt->CKTgmin)*vbs); + ceqbd = model->MOS3type * + (here->MOS3cbd-(here->MOS3gbd-ckt->CKTgmin)*vbd); + if (here->MOS3mode >= 0) { + xnrm=1; + xrev=0; + cdreq=model->MOS3type*(cdrain-here->MOS3gds*vds- + here->MOS3gm*vgs-here->MOS3gmbs*vbs); + } else { + xnrm=0; + xrev=1; + cdreq = -(model->MOS3type)*(cdrain-here->MOS3gds*(-vds)- + here->MOS3gm*vgd-here->MOS3gmbs*vbd); + } + *(ckt->CKTrhs + here->MOS3gNode) -= + (model->MOS3type * (ceqgs + ceqgb + ceqgd)); + *(ckt->CKTrhs + here->MOS3bNode) -= + (ceqbs + ceqbd - model->MOS3type * ceqgb); + *(ckt->CKTrhs + here->MOS3dNodePrime) += + (ceqbd - cdreq + model->MOS3type * ceqgd); + *(ckt->CKTrhs + here->MOS3sNodePrime) += + cdreq + ceqbs + model->MOS3type * ceqgs; + /* + * load y matrix + */ +/*printf(" loading %s at time %g\n",here->MOS3name,ckt->CKTtime);*/ +/*printf("%g %g %g %g %g\n", here->MOS3drainConductance,gcgd+gcgs+gcgb, + here->MOS3sourceConductance,here->MOS3gbd,here->MOS3gbs);*/ +/*printf("%g %g %g %g %g\n",-gcgb,0.0,0.0,here->MOS3gds,here->MOS3gm);*/ +/*printf("%g %g %g %g %g\n", here->MOS3gds,here->MOS3gmbs,gcgd,-gcgs,-gcgd);*/ +/*printf("%g %g %g %g %g\n", -gcgs,-gcgd,0.0,-gcgs,0.0);*/ + + *(here->MOS3DdPtr) += (here->MOS3drainConductance); + *(here->MOS3GgPtr) += ((gcgd+gcgs+gcgb)); + *(here->MOS3SsPtr) += (here->MOS3sourceConductance); + *(here->MOS3BbPtr) += (here->MOS3gbd+here->MOS3gbs+gcgb); + *(here->MOS3DPdpPtr) += + (here->MOS3drainConductance+here->MOS3gds+ + here->MOS3gbd+xrev*(here->MOS3gm+here->MOS3gmbs)+gcgd); + *(here->MOS3SPspPtr) += + (here->MOS3sourceConductance+here->MOS3gds+ + here->MOS3gbs+xnrm*(here->MOS3gm+here->MOS3gmbs)+gcgs); + *(here->MOS3DdpPtr) += (-here->MOS3drainConductance); + *(here->MOS3GbPtr) -= gcgb; + *(here->MOS3GdpPtr) -= gcgd; + *(here->MOS3GspPtr) -= gcgs; + *(here->MOS3SspPtr) += (-here->MOS3sourceConductance); + *(here->MOS3BgPtr) -= gcgb; + *(here->MOS3BdpPtr) -= here->MOS3gbd; + *(here->MOS3BspPtr) -= here->MOS3gbs; + *(here->MOS3DPdPtr) += (-here->MOS3drainConductance); + *(here->MOS3DPgPtr) += ((xnrm-xrev)*here->MOS3gm-gcgd); + *(here->MOS3DPbPtr) += (-here->MOS3gbd+(xnrm-xrev)*here->MOS3gmbs); + *(here->MOS3DPspPtr) += (-here->MOS3gds- + xnrm*(here->MOS3gm+here->MOS3gmbs)); + *(here->MOS3SPgPtr) += (-(xnrm-xrev)*here->MOS3gm-gcgs); + *(here->MOS3SPsPtr) += (-here->MOS3sourceConductance); + *(here->MOS3SPbPtr) += (-here->MOS3gbs-(xnrm-xrev)*here->MOS3gmbs); + *(here->MOS3SPdpPtr) += (-here->MOS3gds- + xrev*(here->MOS3gm+here->MOS3gmbs)); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3mask.c b/src/spicelib/devices/mos3/mos3mask.c new file mode 100644 index 000000000..f316110a1 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3mask.c @@ -0,0 +1,151 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +MOS3mAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + MOS3model *here = (MOS3model *)inst; + switch(which) { + case MOS3_MOD_TNOM: + value->rValue = here->MOS3tnom-CONSTCtoK; + return(OK); + case MOS3_MOD_VTO: + value->rValue = here->MOS3vt0; + return(OK); + case MOS3_MOD_KP: + value->rValue = here->MOS3transconductance; + return(OK); + case MOS3_MOD_GAMMA: + value->rValue = here->MOS3gamma; + return(OK); + case MOS3_MOD_PHI: + value->rValue = here->MOS3phi; + return(OK); + case MOS3_MOD_RD: + value->rValue = here->MOS3drainResistance; + return(OK); + case MOS3_MOD_RS: + value->rValue = here->MOS3sourceResistance; + return(OK); + case MOS3_MOD_CBD: + value->rValue = here->MOS3capBD; + return(OK); + case MOS3_MOD_CBS: + value->rValue = here->MOS3capBS; + return(OK); + case MOS3_MOD_IS: + value->rValue = here->MOS3jctSatCur; + return(OK); + case MOS3_MOD_PB: + value->rValue = here->MOS3bulkJctPotential; + return(OK); + case MOS3_MOD_CGSO: + value->rValue = here->MOS3gateSourceOverlapCapFactor; + return(OK); + case MOS3_MOD_CGDO: + value->rValue = here->MOS3gateDrainOverlapCapFactor; + return(OK); + case MOS3_MOD_CGBO: + value->rValue = here->MOS3gateBulkOverlapCapFactor; + return(OK); + case MOS3_MOD_CJ: + value->rValue = here->MOS3bulkCapFactor; + return(OK); + case MOS3_MOD_MJ: + value->rValue = here->MOS3bulkJctBotGradingCoeff; + return(OK); + case MOS3_MOD_CJSW: + value->rValue = here->MOS3sideWallCapFactor; + return(OK); + case MOS3_MOD_MJSW: + value->rValue = here->MOS3bulkJctSideGradingCoeff; + return(OK); + case MOS3_MOD_JS: + value->rValue = here->MOS3jctSatCurDensity; + return(OK); + case MOS3_MOD_TOX: + value->rValue = here->MOS3oxideThickness; + return(OK); + case MOS3_MOD_LD: + value->rValue = here->MOS3latDiff; + return(OK); + case MOS3_MOD_RSH: + value->rValue = here->MOS3sheetResistance; + return(OK); + case MOS3_MOD_U0: + value->rValue = here->MOS3surfaceMobility; + return(OK); + case MOS3_MOD_FC: + value->rValue = here->MOS3fwdCapDepCoeff; + return(OK); + case MOS3_MOD_NSUB: + value->rValue = here->MOS3substrateDoping; + return(OK); + case MOS3_MOD_TPG: + value->iValue = here->MOS3gateType; + return(OK); + case MOS3_MOD_NSS: + value->rValue = here->MOS3surfaceStateDensity; + return(OK); + case MOS3_MOD_NFS: + value->rValue = here->MOS3fastSurfaceStateDensity; + return(OK); + case MOS3_MOD_DELTA: + value->rValue = here->MOS3narrowFactor; + return(OK); + case MOS3_MOD_VMAX: + value->rValue = here->MOS3maxDriftVel; + return(OK); + case MOS3_MOD_XJ: + value->rValue = here->MOS3junctionDepth; + return(OK); + case MOS3_MOD_ETA: + value->rValue = here->MOS3eta; + return(OK); + case MOS3_MOD_XD: + value->rValue = here->MOS3coeffDepLayWidth; + return(OK); + case MOS3_DELTA: + value->rValue = here->MOS3delta; + return(OK); + case MOS3_MOD_THETA: + value->rValue = here->MOS3theta; + return(OK); + case MOS3_MOD_ALPHA: + value->rValue = here->MOS3alpha; + return(OK); + case MOS3_MOD_KAPPA: + value->rValue = here->MOS3kappa; + return(OK); + case MOS3_MOD_TYPE: + if (here->MOS3type > 0) + value->sValue = "nmos"; + else + value->sValue = "pmos"; + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos3/mos3mdel.c b/src/spicelib/devices/mos3/mos3mdel.c new file mode 100644 index 000000000..ed8a758b9 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3mdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS3mDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + MOS3model **model = (MOS3model **)inModel; + MOS3model *modfast = (MOS3model *)kill; + MOS3instance *here; + MOS3instance *prev = NULL; + MOS3model **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->MOS3nextModel)) { + if( (*model)->MOS3modName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->MOS3nextModel; /* cut deleted device out of list */ + for(here = (*model)->MOS3instances ; here ; here = here->MOS3nextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/mos3/mos3mpar.c b/src/spicelib/devices/mos3/mos3mpar.c new file mode 100644 index 000000000..4d47f2d7b --- /dev/null +++ b/src/spicelib/devices/mos3/mos3mpar.c @@ -0,0 +1,185 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS3mParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + register MOS3model *model = (MOS3model *)inModel; + switch(param) { + case MOS3_MOD_VTO: + model->MOS3vt0 = value->rValue; + model->MOS3vt0Given = TRUE; + break; + case MOS3_MOD_KP: + model->MOS3transconductance = value->rValue; + model->MOS3transconductanceGiven = TRUE; + break; + case MOS3_MOD_GAMMA: + model->MOS3gamma = value->rValue; + model->MOS3gammaGiven = TRUE; + break; + case MOS3_MOD_PHI: + model->MOS3phi = value->rValue; + model->MOS3phiGiven = TRUE; + break; + case MOS3_MOD_RD: + model->MOS3drainResistance = value->rValue; + model->MOS3drainResistanceGiven = TRUE; + break; + case MOS3_MOD_RS: + model->MOS3sourceResistance = value->rValue; + model->MOS3sourceResistanceGiven = TRUE; + break; + case MOS3_MOD_CBD: + model->MOS3capBD = value->rValue; + model->MOS3capBDGiven = TRUE; + break; + case MOS3_MOD_CBS: + model->MOS3capBS = value->rValue; + model->MOS3capBSGiven = TRUE; + break; + case MOS3_MOD_IS: + model->MOS3jctSatCur = value->rValue; + model->MOS3jctSatCurGiven = TRUE; + break; + case MOS3_MOD_PB: + model->MOS3bulkJctPotential = value->rValue; + model->MOS3bulkJctPotentialGiven = TRUE; + break; + case MOS3_MOD_CGSO: + model->MOS3gateSourceOverlapCapFactor = value->rValue; + model->MOS3gateSourceOverlapCapFactorGiven = TRUE; + break; + case MOS3_MOD_CGDO: + model->MOS3gateDrainOverlapCapFactor = value->rValue; + model->MOS3gateDrainOverlapCapFactorGiven = TRUE; + break; + case MOS3_MOD_CGBO: + model->MOS3gateBulkOverlapCapFactor = value->rValue; + model->MOS3gateBulkOverlapCapFactorGiven = TRUE; + break; + case MOS3_MOD_RSH: + model->MOS3sheetResistance = value->rValue; + model->MOS3sheetResistanceGiven = TRUE; + break; + case MOS3_MOD_CJ: + model->MOS3bulkCapFactor = value->rValue; + model->MOS3bulkCapFactorGiven = TRUE; + break; + case MOS3_MOD_MJ: + model->MOS3bulkJctBotGradingCoeff = value->rValue; + model->MOS3bulkJctBotGradingCoeffGiven = TRUE; + break; + case MOS3_MOD_CJSW: + model->MOS3sideWallCapFactor = value->rValue; + model->MOS3sideWallCapFactorGiven = TRUE; + break; + case MOS3_MOD_MJSW: + model->MOS3bulkJctSideGradingCoeff = value->rValue; + model->MOS3bulkJctSideGradingCoeffGiven = TRUE; + break; + case MOS3_MOD_JS: + model->MOS3jctSatCurDensity = value->rValue; + model->MOS3jctSatCurDensityGiven = TRUE; + break; + case MOS3_MOD_TOX: + model->MOS3oxideThickness = value->rValue; + model->MOS3oxideThicknessGiven = TRUE; + break; + case MOS3_MOD_LD: + model->MOS3latDiff = value->rValue; + model->MOS3latDiffGiven = TRUE; + break; + case MOS3_MOD_U0: + model->MOS3surfaceMobility = value->rValue; + model->MOS3surfaceMobilityGiven = TRUE; + break; + case MOS3_MOD_FC: + model->MOS3fwdCapDepCoeff = value->rValue; + model->MOS3fwdCapDepCoeffGiven = TRUE; + break; + case MOS3_MOD_NSUB: + model->MOS3substrateDoping = value->rValue; + model->MOS3substrateDopingGiven = TRUE; + break; + case MOS3_MOD_TPG: + model->MOS3gateType = value->iValue; + model->MOS3gateTypeGiven = TRUE; + break; + case MOS3_MOD_NSS: + model->MOS3surfaceStateDensity = value->rValue; + model->MOS3surfaceStateDensityGiven = TRUE; + break; + case MOS3_MOD_ETA: + model->MOS3eta = value->rValue; + model->MOS3etaGiven = TRUE; + break; + case MOS3_MOD_DELTA: + model->MOS3delta = value->rValue; + model->MOS3deltaGiven = TRUE; + break; + case MOS3_MOD_NFS: + model->MOS3fastSurfaceStateDensity = value->rValue; + model->MOS3fastSurfaceStateDensityGiven = TRUE; + break; + case MOS3_MOD_THETA: + model->MOS3theta = value->rValue; + model->MOS3thetaGiven = TRUE; + break; + case MOS3_MOD_VMAX: + model->MOS3maxDriftVel = value->rValue; + model->MOS3maxDriftVelGiven = TRUE; + break; + case MOS3_MOD_KAPPA: + model->MOS3kappa = value->rValue; + model->MOS3kappaGiven = TRUE; + break; + case MOS3_MOD_NMOS: + if(value->iValue) { + model->MOS3type = 1; + model->MOS3typeGiven = TRUE; + } + break; + case MOS3_MOD_PMOS: + if(value->iValue) { + model->MOS3type = -1; + model->MOS3typeGiven = TRUE; + } + break; + case MOS3_MOD_XJ: + model->MOS3junctionDepth = value->rValue; + model->MOS3junctionDepthGiven = TRUE; + break; + case MOS3_MOD_TNOM: + model->MOS3tnom = value->rValue+CONSTCtoK; + model->MOS3tnomGiven = TRUE; + break; + case MOS3_MOD_KF: + model->MOS3fNcoef = value->rValue; + model->MOS3fNcoefGiven = TRUE; + break; + case MOS3_MOD_AF: + model->MOS3fNexp = value->rValue; + model->MOS3fNexpGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3noi.c b/src/spicelib/devices/mos3/mos3noi.c new file mode 100644 index 000000000..228a443e0 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3noi.c @@ -0,0 +1,218 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "mos3defs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * MOS3noise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with MOSFET's. It starts with the model *firstModel and + * traverses all of its insts. It then proceeds to any other models + * on the linked list. The total output noise density generated by + * all of the MOSFET's is summed with the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +MOS3noise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + MOS3model *firstModel = (MOS3model *) genmodel; + register MOS3model *model; + register MOS3instance *inst; + char name[N_MXVLNTH]; + double tempOnoise; + double tempInoise; + double noizDens[MOS3NSRCS]; + double lnNdens[MOS3NSRCS]; + int i; + + /* define the names of the noise sources */ + + static char *MOS3nNames[MOS3NSRCS] = { /* Note that we have to keep the order */ + "_rd", /* noise due to rd */ /* consistent with thestrchr definitions */ + "_rs", /* noise due to rs */ /* in MOS3defs.h */ + "_id", /* noise due to id */ + "_1overf", /* flicker (1/f) noise */ + "" /* total transistor noise */ + }; + + for (model=firstModel; model != NULL; model=model->MOS3nextModel) { + for (inst=model->MOS3instances; inst != NULL; inst=inst->MOS3nextInstance) { + if (inst->MOS3owner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name all the noise generators */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + for (i=0; i < MOS3NSRCS; i++) { + (void)sprintf(name,"onoise_%s%s",inst->MOS3name,MOS3nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + } + break; + + case INT_NOIZ: + for (i=0; i < MOS3NSRCS; i++) { + (void)sprintf(name,"onoise_total_%s%s",inst->MOS3name,MOS3nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s%s",inst->MOS3name,MOS3nNames[i]); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + + } + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens[MOS3RDNOIZ],&lnNdens[MOS3RDNOIZ], + ckt,THERMNOISE,inst->MOS3dNodePrime,inst->MOS3dNode, + inst->MOS3drainConductance); + + NevalSrc(&noizDens[MOS3RSNOIZ],&lnNdens[MOS3RSNOIZ], + ckt,THERMNOISE,inst->MOS3sNodePrime,inst->MOS3sNode, + inst->MOS3sourceConductance); + + NevalSrc(&noizDens[MOS3IDNOIZ],&lnNdens[MOS3IDNOIZ], + ckt,THERMNOISE,inst->MOS3dNodePrime,inst->MOS3sNodePrime, + (2.0/3.0 * fabs(inst->MOS3gm))); + + NevalSrc(&noizDens[MOS3FLNOIZ],(double*)NULL,ckt, + N_GAIN,inst->MOS3dNodePrime, inst->MOS3sNodePrime, + (double)0.0); + noizDens[MOS3FLNOIZ] *= model->MOS3fNcoef * + exp(model->MOS3fNexp * + log(MAX(fabs(inst->MOS3cd),N_MINLOG))) / + (data->freq * inst->MOS3w * + (inst->MOS3l - 2*model->MOS3latDiff) * + model->MOS3oxideCapFactor * model->MOS3oxideCapFactor); + lnNdens[MOS3FLNOIZ] = + log(MAX(noizDens[MOS3FLNOIZ],N_MINLOG)); + + noizDens[MOS3TOTNOIZ] = noizDens[MOS3RDNOIZ] + + noizDens[MOS3RSNOIZ] + + noizDens[MOS3IDNOIZ] + + noizDens[MOS3FLNOIZ]; + lnNdens[MOS3TOTNOIZ] = + log(MAX(noizDens[MOS3TOTNOIZ], N_MINLOG)); + + *OnDens += noizDens[MOS3TOTNOIZ]; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + for (i=0; i < MOS3NSRCS; i++) { + inst->MOS3nVar[LNLSTDENS][i] = lnNdens[i]; + } + + /* clear out our integration variables if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + for (i=0; i < MOS3NSRCS; i++) { + inst->MOS3nVar[OUTNOIZ][i] = 0.0; + inst->MOS3nVar[INNOIZ][i] = 0.0; + } + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + for (i=0; i < MOS3NSRCS; i++) { + if (i != MOS3TOTNOIZ) { + tempOnoise = Nintegrate(noizDens[i], lnNdens[i], + inst->MOS3nVar[LNLSTDENS][i], data); + tempInoise = Nintegrate(noizDens[i] * data->GainSqInv , + lnNdens[i] + data->lnGainInv, + inst->MOS3nVar[LNLSTDENS][i] + data->lnGainInv, + data); + inst->MOS3nVar[LNLSTDENS][i] = lnNdens[i]; + data->outNoiz += tempOnoise; + data->inNoise += tempInoise; + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + inst->MOS3nVar[OUTNOIZ][i] += tempOnoise; + inst->MOS3nVar[OUTNOIZ][MOS3TOTNOIZ] += tempOnoise; + inst->MOS3nVar[INNOIZ][i] += tempInoise; + inst->MOS3nVar[INNOIZ][MOS3TOTNOIZ] += tempInoise; + } + } + } + } + if (data->prtSummary) { + for (i=0; i < MOS3NSRCS; i++) { /* print a summary report */ + data->outpVector[data->outNumber++] = noizDens[i]; + } + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + for (i=0; i < MOS3NSRCS; i++) { + data->outpVector[data->outNumber++] = inst->MOS3nVar[OUTNOIZ][i]; + data->outpVector[data->outNumber++] = inst->MOS3nVar[INNOIZ][i]; + } + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3par.c b/src/spicelib/devices/mos3/mos3par.c new file mode 100644 index 000000000..7723975f4 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3par.c @@ -0,0 +1,110 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MOS3param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + MOS3instance *here = (MOS3instance *)inst; + switch(param) { + case MOS3_W: + here->MOS3w = value->rValue; + here->MOS3wGiven = TRUE; + break; + case MOS3_L: + here->MOS3l = value->rValue; + here->MOS3lGiven = TRUE; + break; + case MOS3_AS: + here->MOS3sourceArea = value->rValue; + here->MOS3sourceAreaGiven = TRUE; + break; + case MOS3_AD: + here->MOS3drainArea = value->rValue; + here->MOS3drainAreaGiven = TRUE; + break; + case MOS3_PS: + here->MOS3sourcePerimiter = value->rValue; + here->MOS3sourcePerimiterGiven = TRUE; + break; + case MOS3_PD: + here->MOS3drainPerimiter = value->rValue; + here->MOS3drainPerimiterGiven = TRUE; + break; + case MOS3_NRS: + here->MOS3sourceSquares = value->rValue; + here->MOS3sourceSquaresGiven = TRUE; + break; + case MOS3_NRD: + here->MOS3drainSquares = value->rValue; + here->MOS3drainSquaresGiven = TRUE; + break; + case MOS3_OFF: + here->MOS3off = value->iValue; + break; + case MOS3_IC_VBS: + here->MOS3icVBS = value->rValue; + here->MOS3icVBSGiven = TRUE; + break; + case MOS3_IC_VDS: + here->MOS3icVDS = value->rValue; + here->MOS3icVDSGiven = TRUE; + break; + case MOS3_IC_VGS: + here->MOS3icVGS = value->rValue; + here->MOS3icVGSGiven = TRUE; + break; + case MOS3_TEMP: + here->MOS3temp = value->rValue+CONSTCtoK; + here->MOS3tempGiven = TRUE; + break; + case MOS3_IC: + switch(value->v.numValue){ + case 3: + here->MOS3icVBS = *(value->v.vec.rVec+2); + here->MOS3icVBSGiven = TRUE; + case 2: + here->MOS3icVGS = *(value->v.vec.rVec+1); + here->MOS3icVGSGiven = TRUE; + case 1: + here->MOS3icVDS = *(value->v.vec.rVec); + here->MOS3icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + case MOS3_L_SENS: + if(value->iValue) { + here->MOS3senParmNo = 1; + here->MOS3sens_l = 1; + } + break; + case MOS3_W_SENS: + if(value->iValue) { + here->MOS3senParmNo = 1; + here->MOS3sens_w = 1; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3pzld.c b/src/spicelib/devices/mos3/mos3pzld.c new file mode 100644 index 000000000..c8ba529da --- /dev/null +++ b/src/spicelib/devices/mos3/mos3pzld.c @@ -0,0 +1,134 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS3pzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + int xnrm; + int xrev; + double xgs; + double xgd; + double xgb; + double xbd; + double xbs; + double capgs; + double capgd; + double capgb; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double EffectiveLength; + + for( ; model != NULL; model = model->MOS3nextModel) { + for(here = model->MOS3instances; here!= NULL; + here = here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + if (here->MOS3mode < 0) { + xnrm=0; + xrev=1; + } else { + xnrm=1; + xrev=0; + } + /* + * meyer's model parameters + */ + EffectiveLength=here->MOS3l - 2*model->MOS3latDiff; + GateSourceOverlapCap = model->MOS3gateSourceOverlapCapFactor * + here->MOS3w; + GateDrainOverlapCap = model->MOS3gateDrainOverlapCapFactor * + here->MOS3w; + GateBulkOverlapCap = model->MOS3gateBulkOverlapCapFactor * + EffectiveLength; + capgs = ( 2* *(ckt->CKTstate0+here->MOS3capgs)+ + GateSourceOverlapCap ); + capgd = ( 2* *(ckt->CKTstate0+here->MOS3capgd)+ + GateDrainOverlapCap ); + capgb = ( 2* *(ckt->CKTstate0+here->MOS3capgb)+ + GateBulkOverlapCap ); + xgs = capgs; + xgd = capgd; + xgb = capgb; + xbd = here->MOS3capbd; + xbs = here->MOS3capbs; + /*printf("mos2: xgs=%g, xgd=%g, xgb=%g, xbd=%g, xbs=%g\n", + xgs,xgd,xgb,xbd,xbs);*/ + /* + * load matrix + */ + + *(here->MOS3GgPtr ) += (xgd+xgs+xgb)*s->real; + *(here->MOS3GgPtr +1) += (xgd+xgs+xgb)*s->imag; + *(here->MOS3BbPtr ) += (xgb+xbd+xbs)*s->real; + *(here->MOS3BbPtr +1) += (xgb+xbd+xbs)*s->imag; + *(here->MOS3DPdpPtr ) += (xgd+xbd)*s->real; + *(here->MOS3DPdpPtr +1) += (xgd+xbd)*s->imag; + *(here->MOS3SPspPtr ) += (xgs+xbs)*s->real; + *(here->MOS3SPspPtr +1) += (xgs+xbs)*s->imag; + *(here->MOS3GbPtr ) -= xgb*s->real; + *(here->MOS3GbPtr +1) -= xgb*s->imag; + *(here->MOS3GdpPtr ) -= xgd*s->real; + *(here->MOS3GdpPtr +1) -= xgd*s->imag; + *(here->MOS3GspPtr ) -= xgs*s->real; + *(here->MOS3GspPtr +1) -= xgs*s->imag; + *(here->MOS3BgPtr ) -= xgb*s->real; + *(here->MOS3BgPtr +1) -= xgb*s->imag; + *(here->MOS3BdpPtr ) -= xbd*s->real; + *(here->MOS3BdpPtr +1) -= xbd*s->imag; + *(here->MOS3BspPtr ) -= xbs*s->real; + *(here->MOS3BspPtr +1) -= xbs*s->imag; + *(here->MOS3DPgPtr ) -= xgd*s->real; + *(here->MOS3DPgPtr +1) -= xgd*s->imag; + *(here->MOS3DPbPtr ) -= xbd*s->real; + *(here->MOS3DPbPtr +1) -= xbd*s->imag; + *(here->MOS3SPgPtr ) -= xgs*s->real; + *(here->MOS3SPgPtr +1) -= xgs*s->imag; + *(here->MOS3SPbPtr ) -= xbs*s->real; + *(here->MOS3SPbPtr +1) -= xbs*s->imag; + *(here->MOS3DdPtr) += here->MOS3drainConductance; + *(here->MOS3SsPtr) += here->MOS3sourceConductance; + *(here->MOS3BbPtr) += here->MOS3gbd+here->MOS3gbs; + *(here->MOS3DPdpPtr) += here->MOS3drainConductance+ + here->MOS3gds+here->MOS3gbd+ + xrev*(here->MOS3gm+here->MOS3gmbs); + *(here->MOS3SPspPtr) += here->MOS3sourceConductance+ + here->MOS3gds+here->MOS3gbs+ + xnrm*(here->MOS3gm+here->MOS3gmbs); + *(here->MOS3DdpPtr) -= here->MOS3drainConductance; + *(here->MOS3SspPtr) -= here->MOS3sourceConductance; + *(here->MOS3BdpPtr) -= here->MOS3gbd; + *(here->MOS3BspPtr) -= here->MOS3gbs; + *(here->MOS3DPdPtr) -= here->MOS3drainConductance; + *(here->MOS3DPgPtr) += (xnrm-xrev)*here->MOS3gm; + *(here->MOS3DPbPtr) += -here->MOS3gbd+(xnrm-xrev)*here->MOS3gmbs; + *(here->MOS3DPspPtr) -= here->MOS3gds+ + xnrm*(here->MOS3gm+here->MOS3gmbs); + *(here->MOS3SPgPtr) -= (xnrm-xrev)*here->MOS3gm; + *(here->MOS3SPsPtr) -= here->MOS3sourceConductance; + *(here->MOS3SPbPtr) -= here->MOS3gbs+(xnrm-xrev)*here->MOS3gmbs; + *(here->MOS3SPdpPtr) -= here->MOS3gds+ + xrev*(here->MOS3gm+here->MOS3gmbs); + + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3sacl.c b/src/spicelib/devices/mos3/mos3sacl.c new file mode 100644 index 000000000..5591afa36 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3sacl.c @@ -0,0 +1,788 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current ac sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "const.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3sAcLoad(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + int xnrm; + int xrev; + double A0; + double Apert; + double DELA; + double DELAinv; + double gdpr0; + double gspr0; + double gds0; + double gbs0; + double gbd0; + double gm0; + double gmbs0; + double gdpr; + double gspr; + double gds; + double gbs; + double gbd; + double gm; + double gmbs; + double xcgs0; + double xcgd0; + double xcgb0; + double xbd0; + double xbs0; + double xcgs; + double xcgd; + double xcgb; + double xbd; + double xbs; + double vbsOp; + double vbdOp; + double vspr; + double vdpr; + double vgs; + double vgd; + double vgb; + double vbs; + double vbd; + double vds; + double ivspr; + double ivdpr; + double ivgs; + double ivgd; + double ivgb; + double ivbs; + double ivbd; + double ivds; + double cspr; + double cdpr; + double cgs; + double cgd; + double cgb; + double cbs; + double cbd; + double cds; + double cs0; + double csprm0; + double cd0; + double cdprm0; + double cg0; + double cb0; + double cs; + double csprm; + double cd; + double cdprm; + double cg; + double cb; + double icspr; + double icdpr; + double icgs; + double icgd; + double icgb; + double icbs; + double icbd; + double icds; + double ics0; + double icsprm0; + double icd0; + double icdprm0; + double icg0; + double icb0; + double ics; + double icsprm; + double icd; + double icdprm; + double icg; + double icb; + double DvDp; + int i; + int flag; + int error; + int iparmno; + double arg; + double sarg; + double sargsw; + double SaveState[44]; + int save_mode; + SENstruct *info; + +#ifdef SENSDEBUG + printf("MOS3senacload\n"); + printf("CKTomega = %.5e\n",ckt->CKTomega); +#endif /* SENSDEBUG */ + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + for( ; model != NULL; model = model->MOS3nextModel) { + for(here = model->MOS3instances; here!= NULL; + here = here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++) + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS3states + i); + + *(SaveState + 17) = here->MOS3sourceConductance; + *(SaveState + 18) = here->MOS3drainConductance; + *(SaveState + 19) = here->MOS3cd; + *(SaveState + 20) = here->MOS3cbs; + *(SaveState + 21) = here->MOS3cbd; + *(SaveState + 22) = here->MOS3gmbs; + *(SaveState + 23) = here->MOS3gm; + *(SaveState + 24) = here->MOS3gds; + *(SaveState + 25) = here->MOS3gbd; + *(SaveState + 26) = here->MOS3gbs; + *(SaveState + 27) = here->MOS3capbd; + *(SaveState + 28) = here->MOS3capbs; + *(SaveState + 29) = here->MOS3Cbd; + *(SaveState + 30) = here->MOS3Cbdsw; + *(SaveState + 31) = here->MOS3Cbs; + *(SaveState + 32) = here->MOS3Cbssw; + *(SaveState + 33) = here->MOS3f2d; + *(SaveState + 34) = here->MOS3f3d; + *(SaveState + 35) = here->MOS3f4d; + *(SaveState + 36) = here->MOS3f2s; + *(SaveState + 37) = here->MOS3f3s; + *(SaveState + 38) = here->MOS3f4s; + *(SaveState + 39) = here->MOS3cgs; + *(SaveState + 40) = here->MOS3cgd; + *(SaveState + 41) = here->MOS3cgb; + *(SaveState + 42) = here->MOS3vdsat; + *(SaveState + 43) = here->MOS3von; + save_mode = here->MOS3mode; + + xnrm=1; + xrev=0; + if (here->MOS3mode < 0) { + xnrm=0; + xrev=1; + } + + vbsOp = model->MOS3type * ( + *(ckt->CKTrhsOp+here->MOS3bNode) - + *(ckt->CKTrhsOp+here->MOS3sNodePrime)); + vbdOp = model->MOS3type * ( + *(ckt->CKTrhsOp+here->MOS3bNode) - + *(ckt->CKTrhsOp+here->MOS3dNodePrime)); + vspr = *(ckt->CKTrhsOld + here->MOS3sNode) + - *(ckt->CKTrhsOld + + here->MOS3sNodePrime) ; + ivspr = *(ckt->CKTirhsOld + here->MOS3sNode) + - *(ckt->CKTirhsOld + + here->MOS3sNodePrime) ; + vdpr = *(ckt->CKTrhsOld + here->MOS3dNode) + - *(ckt->CKTrhsOld + + here->MOS3dNodePrime) ; + ivdpr = *(ckt->CKTirhsOld + here->MOS3dNode) + - *(ckt->CKTirhsOld + + here->MOS3dNodePrime) ; + vgb = *(ckt->CKTrhsOld + here->MOS3gNode) + - *(ckt->CKTrhsOld + + here->MOS3bNode) ; + ivgb = *(ckt->CKTirhsOld + here->MOS3gNode) + - *(ckt->CKTirhsOld + + here->MOS3bNode) ; + vbs = *(ckt->CKTrhsOld + here->MOS3bNode) + - *(ckt->CKTrhsOld + + here->MOS3sNodePrime) ; + ivbs = *(ckt->CKTirhsOld + here->MOS3bNode) + - *(ckt->CKTirhsOld + + here->MOS3sNodePrime) ; + vbd = *(ckt->CKTrhsOld + here->MOS3bNode) + - *(ckt->CKTrhsOld + + here->MOS3dNodePrime) ; + ivbd = *(ckt->CKTirhsOld + here->MOS3bNode) + - *(ckt->CKTirhsOld + + here->MOS3dNodePrime) ; + vds = vbs - vbd ; + ivds = ivbs - ivbd ; + vgs = vgb + vbs ; + ivgs = ivgb + ivbs ; + vgd = vgb + vbd ; + ivgd = ivgb + ivbd ; + +#ifdef SENSDEBUG + printf("senacload instance name %s\n",here->MOS3name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS3gNode,here->MOS3dNode,here->MOS3dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS3sNode ,here->MOS3sNodePrime, + here->MOS3bNode,here->MOS3senParmNo); + printf("\n without perturbation \n"); +#endif /* SENSDEBUG */ + /* without perturbation */ + *(ckt->CKTstate0 + here->MOS3vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS3vbd) = vbdOp; + + here->MOS3senPertFlag = ON ; + if(info->SENacpertflag == 1){ + /* store the unperturbed values of small signal parameters */ + if((error = MOS3load((GENmodel*)model,ckt))) + return(error); + *(here->MOS3senCgs) = here->MOS3cgs; + *(here->MOS3senCgd) = here->MOS3cgd; + *(here->MOS3senCgb) = here->MOS3cgb; + *(here->MOS3senCbd) = here->MOS3capbd; + *(here->MOS3senCbs) = here->MOS3capbs; + *(here->MOS3senGds) = here->MOS3gds; + *(here->MOS3senGbs) = here->MOS3gbs; + *(here->MOS3senGbd) = here->MOS3gbd; + *(here->MOS3senGm) = here->MOS3gm; + *(here->MOS3senGmbs) = here->MOS3gmbs; + + } + xcgs0= *(here->MOS3senCgs) * ckt->CKTomega; + xcgd0= *(here->MOS3senCgd) * ckt->CKTomega; + xcgb0= *(here->MOS3senCgb) * ckt->CKTomega; + xbd0= *(here->MOS3senCbd) * ckt->CKTomega; + xbs0= *(here->MOS3senCbs) * ckt->CKTomega; + gds0= *(here->MOS3senGds); + gbs0= *(here->MOS3senGbs); + gbd0= *(here->MOS3senGbd); + gm0= *(here->MOS3senGm); + gmbs0= *(here->MOS3senGmbs); + gdpr0 = here->MOS3drainConductance; + gspr0 = here->MOS3sourceConductance; + + + cspr = gspr0 * vspr ; + icspr = gspr0 * ivspr ; + cdpr = gdpr0 * vdpr ; + icdpr = gdpr0 * ivdpr ; + cgs = ( - xcgs0 * ivgs ); + icgs = xcgs0 * vgs ; + cgd = ( - xcgd0 * ivgd ); + icgd = xcgd0 * vgd ; + cgb = ( - xcgb0 * ivgb ); + icgb = xcgb0 * vgb ; + cbs = ( gbs0 * vbs - xbs0 * ivbs ); + icbs = ( xbs0 * vbs + gbs0 * ivbs ); + cbd = ( gbd0 * vbd - xbd0 * ivbd ); + icbd = ( xbd0 * vbd + gbd0 * ivbd ); + cds = ( gds0 * vds + xnrm * (gm0 * vgs + gmbs0 * vbs) + - xrev * (gm0 * vgd + gmbs0 * vbd) ); + icds = ( gds0 * ivds + xnrm * (gm0 * ivgs + gmbs0 * ivbs) + - xrev * (gm0 * ivgd + gmbs0 * ivbd) ); + + cs0 = cspr; + ics0 = icspr; + csprm0 = ( -cspr - cgs - cbs - cds ) ; + icsprm0 = ( -icspr - icgs - icbs - icds ) ; + cd0 = cdpr; + icd0 = icdpr; + cdprm0 = ( -cdpr - cgd - cbd + cds ) ; + icdprm0 = ( -icdpr - icgd - icbd + icds ) ; + cg0 = cgs + cgd + cgb ; + icg0 = icgs + icgd + icgb ; + cb0 = cbs + cbd - cgb ; + icb0 = icbs + icbd - icgb ; +#ifdef SENSDEBUG + printf("gspr0 = %.7e , gdpr0 = %.7e , gds0 = %.7e, gbs0 = %.7e\n", + gspr0,gdpr0,gds0,gbs0); + printf("gbd0 = %.7e , gm0 = %.7e , gmbs0 = %.7e\n",gbd0,gm0,gmbs0); + printf("xcgs0 = %.7e , xcgd0 = %.7e ,", xcgs0,xcgd0); + printf("xcgb0 = %.7e, xbd0 = %.7e,xbs0 = %.7e\n" ,xcgb0,xbd0,xbs0); + printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); + printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); + printf("cbs0 = %.7e , cbd0 = %.7e , cgb0 = %.7e\n",cbs,cbd,cgb); + printf("cb0 = %.7e , cg0 = %.7e , cs0 = %.7e\n",cb0,cg0,cs0); + printf("csprm0 = %.7e, cd0 = %.7e, cdprm0 = %.7e\n", + csprm0,cd0,cdprm0); + printf("icb0 = %.7e , icg0 = %.7e , ics0 = %.7e\n",icb0,icg0,ics0); + printf("icsprm0 = %.7e, icd0 = %.7e, icdprm0 = %.7e\n", + icsprm0,icd0,icdprm0); + printf("\nPerturbation of vbs\n"); +#endif /* SENSDEBUG */ + + /* Perturbation of vbs */ + flag = 1; + A0 = vbsOp; + DELA = info->SENpertfac * CONSTvt0 ; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vbs */ + Apert = A0 + DELA; + *(ckt->CKTstate0 + here->MOS3vbs) = Apert; + *(ckt->CKTstate0 + here->MOS3vbd) = vbdOp; + + if((error = MOS3load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS3senCgs + 1) = here->MOS3cgs; + *(here->MOS3senCgd + 1) = here->MOS3cgd; + *(here->MOS3senCgb + 1) = here->MOS3cgb; + *(here->MOS3senCbd + 1) = here->MOS3capbd; + *(here->MOS3senCbs + 1) = here->MOS3capbs; + *(here->MOS3senGds + 1) = here->MOS3gds; + *(here->MOS3senGbs + 1) = here->MOS3gbs; + *(here->MOS3senGbd + 1) = here->MOS3gbd; + *(here->MOS3senGm + 1) = here->MOS3gm; + *(here->MOS3senGmbs + 1) = here->MOS3gmbs; + + *(ckt->CKTstate0 + here->MOS3vbs) = A0; + + + } + + goto load; + + +pertvbd: /* Perturbation of vbd */ +#ifdef SENSDEBUG + printf("\nPerturbation of vbd\n"); +#endif /* SENSDEBUG */ + + flag = 2; + A0 = vbdOp; + DELA = info->SENpertfac * CONSTvt0 + 1e-8; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vbd */ + Apert = A0 + DELA; + *(ckt->CKTstate0 + here->MOS3vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS3vbd) = Apert; + + if((error = MOS3load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS3senCgs + 2) = here->MOS3cgs; + *(here->MOS3senCgd + 2) = here->MOS3cgd; + *(here->MOS3senCgb + 2) = here->MOS3cgb; + *(here->MOS3senCbd + 2) = here->MOS3capbd; + *(here->MOS3senCbs + 2) = here->MOS3capbs; + *(here->MOS3senGds + 2) = here->MOS3gds; + *(here->MOS3senGbs + 2) = here->MOS3gbs; + *(here->MOS3senGbd + 2) = here->MOS3gbd; + *(here->MOS3senGm + 2) = here->MOS3gm; + *(here->MOS3senGmbs + 2) = here->MOS3gmbs; + + *(ckt->CKTstate0 + here->MOS3vbd) = A0; + + } + + goto load; + + +pertvgb: /* Perturbation of vgb */ +#ifdef SENSDEBUG + printf("\nPerturbation of vgb\n"); +#endif /* SENSDEBUG */ + + flag = 3; + A0 = model->MOS3type * (*(ckt->CKTrhsOp + here->MOS3gNode) + - *(ckt->CKTrhsOp + here->MOS3bNode)); + DELA = info->SENpertfac * A0 + 1e-8; + DELAinv = model->MOS3type * 1.0/DELA; + + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed vgb */ + *(ckt->CKTstate0 + here->MOS3vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS3vbd) = vbdOp; + *(ckt->CKTrhsOp + here->MOS3bNode) -= DELA; + + if((error = MOS3load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS3senCgs + 3) = here->MOS3cgs; + *(here->MOS3senCgd + 3) = here->MOS3cgd; + *(here->MOS3senCgb + 3) = here->MOS3cgb; + *(here->MOS3senCbd + 3) = here->MOS3capbd; + *(here->MOS3senCbs + 3) = here->MOS3capbs; + *(here->MOS3senGds + 3) = here->MOS3gds; + *(here->MOS3senGbs + 3) = here->MOS3gbs; + *(here->MOS3senGbd + 3) = here->MOS3gbd; + *(here->MOS3senGm + 3) = here->MOS3gm; + *(here->MOS3senGmbs + 3) = here->MOS3gmbs; + + + *(ckt->CKTrhsOp + here->MOS3bNode) += DELA; + } + goto load; + +pertl: /* Perturbation of length */ + + if(here->MOS3sens_l == 0){ + goto pertw; + } +#ifdef SENSDEBUG + printf("\nPerturbation of length\n"); +#endif /* SENSDEBUG */ + flag = 4; + A0 = here->MOS3l; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed length */ + Apert = A0 + DELA; + here->MOS3l = Apert; + + *(ckt->CKTstate0 + here->MOS3vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS3vbd) = vbdOp; + + if((error = MOS3load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS3senCgs + 4) = here->MOS3cgs; + *(here->MOS3senCgd + 4) = here->MOS3cgd; + *(here->MOS3senCgb + 4) = here->MOS3cgb; + *(here->MOS3senCbd + 4) = here->MOS3capbd; + *(here->MOS3senCbs + 4) = here->MOS3capbs; + *(here->MOS3senGds + 4) = here->MOS3gds; + *(here->MOS3senGbs + 4) = here->MOS3gbs; + *(here->MOS3senGbd + 4) = here->MOS3gbd; + *(here->MOS3senGm + 4) = here->MOS3gm; + *(here->MOS3senGmbs + 4) = here->MOS3gmbs; + + here->MOS3l = A0; + + } + + goto load; + +pertw: /* Perturbation of width */ + if(here->MOS3sens_w == 0) + goto next; +#ifdef SENSDEBUG + printf("\nPerturbation of width\n"); +#endif /* SENSDEBUG */ + flag = 5; + A0 = here->MOS3w; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + + if(info->SENacpertflag == 1){ + /* store the values of small signal parameters + * corresponding to perturbed width */ + here->MOS3w = Apert; + here->MOS3drainArea *= (1 + info->SENpertfac); + here->MOS3sourceArea *= (1 + info->SENpertfac); + here->MOS3Cbd *= (1 + info->SENpertfac); + here->MOS3Cbs *= (1 + info->SENpertfac); + if(here->MOS3drainPerimiter){ + here->MOS3Cbdsw += here->MOS3Cbdsw * + DELA/here->MOS3drainPerimiter; + } + if(here->MOS3sourcePerimiter){ + here->MOS3Cbssw += here->MOS3Cbssw * + DELA/here->MOS3sourcePerimiter; + } + if(vbdOp >= here->MOS3tDepCap){ + arg = 1-model->MOS3fwdCapDepCoeff; + sarg = exp( (-model->MOS3bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS3bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS3f2d = here->MOS3Cbd*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctBotGradingCoeff))* sarg/arg + + here->MOS3Cbdsw*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS3f3d = here->MOS3Cbd * + model->MOS3bulkJctBotGradingCoeff * sarg/arg/ + model->MOS3bulkJctPotential + + here->MOS3Cbdsw * + model->MOS3bulkJctSideGradingCoeff * sargsw/arg / + model->MOS3bulkJctPotential; + here->MOS3f4d = here->MOS3Cbd*model->MOS3bulkJctPotential* + (1-arg*sarg)/ (1-model->MOS3bulkJctBotGradingCoeff) + + here->MOS3Cbdsw*model->MOS3bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS3bulkJctSideGradingCoeff) + -here->MOS3f3d/2* + (here->MOS3tDepCap*here->MOS3tDepCap) + -here->MOS3tDepCap * here->MOS3f2d; + } + if(vbsOp >= here->MOS3tDepCap){ + arg = 1-model->MOS3fwdCapDepCoeff; + sarg = exp( (-model->MOS3bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS3bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS3f2s = here->MOS3Cbs*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctBotGradingCoeff))* sarg/arg + + here->MOS3Cbssw*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS3f3s = here->MOS3Cbs * + model->MOS3bulkJctBotGradingCoeff * sarg/arg/ + model->MOS3bulkJctPotential + here->MOS3Cbssw * + model->MOS3bulkJctSideGradingCoeff * sargsw/arg / + model->MOS3bulkJctPotential; + here->MOS3f4s = here->MOS3Cbs*model->MOS3bulkJctPotential* + (1-arg*sarg)/ (1-model->MOS3bulkJctBotGradingCoeff) + + here->MOS3Cbssw*model->MOS3bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS3bulkJctSideGradingCoeff) + -here->MOS3f3s/2* + (here->MOS3tBulkPot*here->MOS3tBulkPot) + -here->MOS3tBulkPot * here->MOS3f2s; + } + + *(ckt->CKTstate0 + here->MOS3vbs) = vbsOp; + *(ckt->CKTstate0 + here->MOS3vbd) = vbdOp; + + if((error = MOS3load((GENmodel*)model,ckt))) + return(error); + + *(here->MOS3senCgs + 5) = here->MOS3cgs; + *(here->MOS3senCgd + 5) = here->MOS3cgd; + *(here->MOS3senCgb + 5) = here->MOS3cgb; + *(here->MOS3senCbd + 5) = here->MOS3capbd; + *(here->MOS3senCbs + 5) = here->MOS3capbs; + *(here->MOS3senGds + 5) = here->MOS3gds; + *(here->MOS3senGbs + 5) = here->MOS3gbs; + *(here->MOS3senGbd + 5) = here->MOS3gbd; + *(here->MOS3senGm + 5) = here->MOS3gm; + *(here->MOS3senGmbs + 5) = here->MOS3gmbs; + + here->MOS3w = A0; + here->MOS3drainArea /= (1 + info->SENpertfac); + here->MOS3sourceArea /= (1 + info->SENpertfac); + } + +load: + + gds= *(here->MOS3senGds + flag); + gbs= *(here->MOS3senGbs + flag); + gbd= *(here->MOS3senGbd + flag); + gm= *(here->MOS3senGm + flag); + gmbs= *(here->MOS3senGmbs + flag); + if(flag == 5){ + gdpr = here->MOS3drainConductance * Apert/A0; + gspr = here->MOS3sourceConductance * Apert/A0; + } + else{ + gdpr = here->MOS3drainConductance; + gspr = here->MOS3sourceConductance; + } + + xcgs= *(here->MOS3senCgs + flag) * ckt->CKTomega; + xcgd= *(here->MOS3senCgd + flag) * ckt->CKTomega; + xcgb= *(here->MOS3senCgb + flag) * ckt->CKTomega; + xbd= *(here->MOS3senCbd + flag) * ckt->CKTomega; + xbs= *(here->MOS3senCbs + flag) * ckt->CKTomega; + +#ifdef SENSDEBUG + printf("flag = %d \n",flag); + printf("gspr = %.7e , gdpr = %.7e , gds = %.7e, gbs = %.7e\n", + gspr,gdpr,gds,gbs); + printf("gbd = %.7e , gm = %.7e , gmbs = %.7e\n",gbd,gm,gmbs); + printf("xcgs = %.7e , xcgd = %.7e , xcgb = %.7e,", xcgs,xcgd,xcgb); + printf("xbd = %.7e,xbs = %.7e\n" ,xbd,xbs); +#endif /* SENSDEBUG */ + cspr = gspr * vspr ; + icspr = gspr * ivspr ; + cdpr = gdpr * vdpr ; + icdpr = gdpr * ivdpr ; + cgs = ( - xcgs * ivgs ); + icgs = xcgs * vgs ; + cgd = ( - xcgd * ivgd ); + icgd = xcgd * vgd ; + cgb = ( - xcgb * ivgb ); + icgb = xcgb * vgb ; + cbs = ( gbs * vbs - xbs * ivbs ); + icbs = ( xbs * vbs + gbs * ivbs ); + cbd = ( gbd * vbd - xbd * ivbd ); + icbd = ( xbd * vbd + gbd * ivbd ); + cds = ( gds * vds + xnrm * (gm * vgs + gmbs * vbs) + - xrev * (gm * vgd + gmbs * vbd) ); + icds = ( gds * ivds + xnrm * (gm * ivgs + gmbs * ivbs) + - xrev * (gm * ivgd + gmbs * ivbd) ); + + cs = cspr; + ics = icspr; + csprm = ( -cspr - cgs - cbs - cds ) ; + icsprm = ( -icspr - icgs - icbs - icds ) ; + cd = cdpr; + icd = icdpr; + cdprm = ( -cdpr - cgd - cbd + cds ) ; + icdprm = ( -icdpr - icgd - icbd + icds ) ; + cg = cgs + cgd + cgb ; + icg = icgs + icgd + icgb ; + cb = cbs + cbd - cgb ; + icb = icbs + icbd - icgb ; + +#ifdef SENSDEBUG + printf("vbs = %.7e , vbd = %.7e , vgb = %.7e\n",vbs,vbd,vgb); + printf("ivbs = %.7e , ivbd = %.7e , ivgb = %.7e\n",ivbs,ivbd,ivgb); + printf("cbs = %.7e , cbd = %.7e , cgb = %.7e\n",cbs,cbd,cgb); + printf("cb = %.7e , cg = %.7e , cs = %.7e\n",cb,cg,cs); + printf("csprm = %.7e, cd = %.7e, cdprm = %.7e\n",csprm,cd,cdprm); + printf("icb = %.7e , icg = %.7e , ics = %.7e\n",icb,icg,ics); + printf("icsprm = %.7e, icd = %.7e, icdprm = %.7e\n", + icsprm,icd,icdprm); +#endif /* SENSDEBUG */ + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + if( (flag == 4) && (iparmno != here->MOS3senParmNo) ) continue; + if( (flag == 5) && (iparmno != (here->MOS3senParmNo + + here->MOS3sens_l)) ) continue; + + switch(flag){ + case 1: + DvDp = model->MOS3type * + (info->SEN_Sap[here->MOS3bNode][iparmno] + - info->SEN_Sap[here->MOS3sNodePrime][iparmno]); + break; + case 2: + DvDp = model->MOS3type * + ( info->SEN_Sap[here->MOS3bNode][iparmno] + - info->SEN_Sap[here->MOS3dNodePrime][iparmno]); + break; + case 3: + DvDp = model->MOS3type * + ( info->SEN_Sap[here->MOS3gNode][iparmno] + - info->SEN_Sap[here->MOS3bNode][iparmno]); + break; + case 4: + DvDp = 1; + break; + case 5: + DvDp = 1; + break; + } + *(info->SEN_RHS[here->MOS3bNode] + iparmno) -= + ( cb - cb0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS3bNode] + iparmno) -= + ( icb - icb0) * DELAinv * DvDp; + + *(info->SEN_RHS[here->MOS3gNode] + iparmno) -= + ( cg - cg0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS3gNode] + iparmno) -= + ( icg - icg0) * DELAinv * DvDp; + + if(here->MOS3sNode != here->MOS3sNodePrime){ + *(info->SEN_RHS[here->MOS3sNode] + iparmno) -= + ( cs - cs0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS3sNode] + iparmno) -= + ( ics - ics0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS3sNodePrime] + iparmno) -= + ( csprm - csprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS3sNodePrime] + iparmno) -= + ( icsprm - icsprm0) * DELAinv * DvDp; + + if(here->MOS3dNode != here->MOS3dNodePrime){ + *(info->SEN_RHS[here->MOS3dNode] + iparmno) -= + ( cd - cd0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS3dNode] + iparmno) -= + ( icd - icd0) * DELAinv * DvDp; + } + + *(info->SEN_RHS[here->MOS3dNodePrime] + iparmno) -= + ( cdprm - cdprm0) * DELAinv * DvDp; + *(info->SEN_iRHS[here->MOS3dNodePrime] + iparmno) -= + ( icdprm - icdprm0) * DELAinv * DvDp; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("DvDp = %.5e , DELAinv = %.5e ,flag = %d ,", + DvDp,DELAinv,flag); + printf("iparmno = %d,senparmno = %d\n", + iparmno,here->MOS3senParmNo); + printf("A0 = %.5e , Apert = %.5e ,CONSTvt0 = %.5e \n", + A0,Apert,CONSTvt0); + printf("senb = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS3bNode] + iparmno), + *(info->SEN_iRHS[here->MOS3bNode] + iparmno)); + printf("seng = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS3gNode] + iparmno), + *(info->SEN_iRHS[here->MOS3gNode] + iparmno)); + printf("sens = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS3sNode] + iparmno), + *(info->SEN_iRHS[here->MOS3sNode] + iparmno)); + printf("sensprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS3sNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS3sNodePrime] + iparmno)); + printf("send = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS3dNode] + iparmno), + *(info->SEN_iRHS[here->MOS3dNode] + iparmno)); + printf("sendprm = %.7e + j%.7e ", + *(info->SEN_RHS[here->MOS3dNodePrime] + iparmno), + *(info->SEN_iRHS[here->MOS3dNodePrime] + iparmno)); +#endif /* SENSDEBUG */ + + } + switch(flag){ + case 1: + goto pertvbd ; + case 2: + goto pertvgb ; + case 3: + goto pertl ; + case 4: + goto pertw ; + case 5: + break; + } +next: + ; + + /* put the unperturbed values back into the state vector */ + for(i=0; i <= 16; i++) + *(ckt->CKTstate0 + here->MOS3states + i) = *(SaveState + i); + + here->MOS3sourceConductance = *(SaveState + 17) ; + here->MOS3drainConductance = *(SaveState + 18) ; + here->MOS3cd = *(SaveState + 19) ; + here->MOS3cbs = *(SaveState + 20) ; + here->MOS3cbd = *(SaveState + 21) ; + here->MOS3gmbs = *(SaveState + 22) ; + here->MOS3gm = *(SaveState + 23) ; + here->MOS3gds = *(SaveState + 24) ; + here->MOS3gbd = *(SaveState + 25) ; + here->MOS3gbs = *(SaveState + 26) ; + here->MOS3capbd = *(SaveState + 27) ; + here->MOS3capbs = *(SaveState + 28) ; + here->MOS3Cbd = *(SaveState + 29) ; + here->MOS3Cbdsw = *(SaveState + 30) ; + here->MOS3Cbs = *(SaveState + 31) ; + here->MOS3Cbssw = *(SaveState + 32) ; + here->MOS3f2d = *(SaveState + 33) ; + here->MOS3f3d = *(SaveState + 34) ; + here->MOS3f4d = *(SaveState + 35) ; + here->MOS3f2s = *(SaveState + 36) ; + here->MOS3f3s = *(SaveState + 37) ; + here->MOS3f4s = *(SaveState + 38) ; + here->MOS3cgs = *(SaveState + 39) ; + here->MOS3cgd = *(SaveState + 40) ; + here->MOS3cgb = *(SaveState + 41) ; + here->MOS3vdsat = *(SaveState + 42) ; + here->MOS3von = *(SaveState + 43) ; + here->MOS3mode = save_mode ; + + here->MOS3senPertFlag = OFF; + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS3senacload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + + diff --git a/src/spicelib/devices/mos3/mos3set.c b/src/spicelib/devices/mos3/mos3set.c new file mode 100644 index 000000000..4114cf0dd --- /dev/null +++ b/src/spicelib/devices/mos3/mos3set.c @@ -0,0 +1,266 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos3defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* assuming silicon - make definition for epsilon of silicon */ +#define EPSSIL (11.7 * 8.854214871e-12) + +int +MOS3setup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; + /* load the MOS3 device structure with those pointers needed later + * for fast matrix loading + */ + +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + int error; + CKTnode *tmp; + + /* loop through all the MOS3 device models */ + for( ; model != NULL; model = model->MOS3nextModel ) { + + /* perform model defaulting */ + if(!model->MOS3typeGiven) { + model->MOS3type = NMOS; + } + if(!model->MOS3latDiffGiven) { + model->MOS3latDiff = 0; + } + if(!model->MOS3jctSatCurDensityGiven) { + model->MOS3jctSatCurDensity = 0; + } + if(!model->MOS3jctSatCurGiven) { + model->MOS3jctSatCur = 1e-14; + } + if(!model->MOS3drainResistanceGiven) { + model->MOS3drainResistance = 0; + } + if(!model->MOS3sourceResistanceGiven) { + model->MOS3sourceResistance = 0; + } + if(!model->MOS3sheetResistanceGiven) { + model->MOS3sheetResistance = 0; + } + if(!model->MOS3transconductanceGiven) { + model->MOS3transconductance = 2e-5; + } + if(!model->MOS3gateSourceOverlapCapFactorGiven) { + model->MOS3gateSourceOverlapCapFactor = 0; + } + if(!model->MOS3gateDrainOverlapCapFactorGiven) { + model->MOS3gateDrainOverlapCapFactor = 0; + } + if(!model->MOS3gateBulkOverlapCapFactorGiven) { + model->MOS3gateBulkOverlapCapFactor = 0; + } + if(!model->MOS3vt0Given) { + model->MOS3vt0 = 0; + } + if(!model->MOS3capBDGiven) { + model->MOS3capBD = 0; + } + if(!model->MOS3capBSGiven) { + model->MOS3capBS = 0; + } + if(!model->MOS3bulkCapFactorGiven) { + model->MOS3bulkCapFactor = 0; + } + if(!model->MOS3sideWallCapFactorGiven) { + model->MOS3sideWallCapFactor = 0; + } + if(!model->MOS3bulkJctPotentialGiven) { + model->MOS3bulkJctPotential = .8; + } + if(!model->MOS3bulkJctBotGradingCoeffGiven) { + model->MOS3bulkJctBotGradingCoeff = .5; + } + if(!model->MOS3bulkJctSideGradingCoeffGiven) { + model->MOS3bulkJctSideGradingCoeff = .33; + } + if(!model->MOS3fwdCapDepCoeffGiven) { + model->MOS3fwdCapDepCoeff = .5; + } + if(!model->MOS3phiGiven) { + model->MOS3phi = .6; + } + if(!model->MOS3gammaGiven) { + model->MOS3gamma = 0; + } + if(!model->MOS3deltaGiven) { + model->MOS3delta = 0; + } + if(!model->MOS3maxDriftVelGiven) { + model->MOS3maxDriftVel = 0; + } + if(!model->MOS3junctionDepthGiven) { + model->MOS3junctionDepth = 0; + } + if(!model->MOS3fastSurfaceStateDensityGiven) { + model->MOS3fastSurfaceStateDensity = 0; + } + if(!model->MOS3etaGiven) { + model->MOS3eta = 0; + } + if(!model->MOS3thetaGiven) { + model->MOS3theta = 0; + } + if(!model->MOS3kappaGiven) { + model->MOS3kappa = .2; + } + if(!model->MOS3oxideThicknessGiven) { + model->MOS3oxideThickness = 1e-7; + } + if(!model->MOS3fNcoefGiven) { + model->MOS3fNcoef = 0; + } + if(!model->MOS3fNexpGiven) { + model->MOS3fNexp = 1; + } + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + + if (here->MOS3owner == ARCHme) { + /* allocate a chunk of the state vector */ + here->MOS3states = *states; + *states += MOS3NUMSTATES; + } + + if(!here->MOS3drainAreaGiven) { + here->MOS3drainArea = ckt->CKTdefaultMosAD; + } + if(!here->MOS3drainPerimiterGiven) { + here->MOS3drainPerimiter = 0; + } + if(!here->MOS3drainSquaresGiven) { + here->MOS3drainSquares = 1; + } + if(!here->MOS3icVBSGiven) { + here->MOS3icVBS = 0; + } + if(!here->MOS3icVDSGiven) { + here->MOS3icVDS = 0; + } + if(!here->MOS3icVGSGiven) { + here->MOS3icVGS = 0; + } + if(!here->MOS3sourcePerimiterGiven) { + here->MOS3sourcePerimiter = 0; + } + if(!here->MOS3sourceSquaresGiven) { + here->MOS3sourceSquares = 1; + } + if(!here->MOS3vdsatGiven) { + here->MOS3vdsat = 0; + } + if(!here->MOS3vonGiven) { + here->MOS3von = 0; + } + if(!here->MOS3modeGiven) { + here->MOS3mode = 1; + } + + if((model->MOS3drainResistance != 0 || + (model->MOS3sheetResistance != 0 && + here->MOS3drainSquares != 0 ) ) && + here->MOS3dNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS3name,"internal#drain"); + if(error) return(error); + here->MOS3dNodePrime = tmp->number; + } else { + here->MOS3dNodePrime = here->MOS3dNode; + } + + if((model->MOS3sourceResistance != 0 || + (model->MOS3sheetResistance != 0 && + here->MOS3sourceSquares != 0 ) ) && + here->MOS3sNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS3name,"internal#source"); + if(error) return(error); + here->MOS3sNodePrime = tmp->number; + } else { + here->MOS3sNodePrime = here->MOS3sNode; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(MOS3DdPtr, MOS3dNode, MOS3dNode) + TSTALLOC(MOS3GgPtr, MOS3gNode, MOS3gNode) + TSTALLOC(MOS3SsPtr, MOS3sNode, MOS3sNode) + TSTALLOC(MOS3BbPtr, MOS3bNode, MOS3bNode) + TSTALLOC(MOS3DPdpPtr, MOS3dNodePrime, MOS3dNodePrime) + TSTALLOC(MOS3SPspPtr, MOS3sNodePrime, MOS3sNodePrime) + TSTALLOC(MOS3DdpPtr, MOS3dNode, MOS3dNodePrime) + TSTALLOC(MOS3GbPtr, MOS3gNode, MOS3bNode) + TSTALLOC(MOS3GdpPtr, MOS3gNode, MOS3dNodePrime) + TSTALLOC(MOS3GspPtr, MOS3gNode, MOS3sNodePrime) + TSTALLOC(MOS3SspPtr, MOS3sNode, MOS3sNodePrime) + TSTALLOC(MOS3BdpPtr, MOS3bNode, MOS3dNodePrime) + TSTALLOC(MOS3BspPtr, MOS3bNode, MOS3sNodePrime) + TSTALLOC(MOS3DPspPtr, MOS3dNodePrime, MOS3sNodePrime) + TSTALLOC(MOS3DPdPtr, MOS3dNodePrime, MOS3dNode) + TSTALLOC(MOS3BgPtr, MOS3bNode, MOS3gNode) + TSTALLOC(MOS3DPgPtr, MOS3dNodePrime, MOS3gNode) + TSTALLOC(MOS3SPgPtr, MOS3sNodePrime, MOS3gNode) + TSTALLOC(MOS3SPsPtr, MOS3sNodePrime, MOS3sNode) + TSTALLOC(MOS3DPbPtr, MOS3dNodePrime, MOS3bNode) + TSTALLOC(MOS3SPbPtr, MOS3sNodePrime, MOS3bNode) + TSTALLOC(MOS3SPdpPtr, MOS3sNodePrime, MOS3dNodePrime) + + } + } + return(OK); +} + +int +MOS3unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + MOS3model *model; + MOS3instance *here; + + for (model = (MOS3model *)inModel; model != NULL; + model = model->MOS3nextModel) + { + for (here = model->MOS3instances; here != NULL; + here=here->MOS3nextInstance) + { + if (here->MOS3dNodePrime + && here->MOS3dNodePrime != here->MOS3dNode) + { + CKTdltNNum(ckt, here->MOS3dNodePrime); + here->MOS3dNodePrime= 0; + } + if (here->MOS3sNodePrime + && here->MOS3sNodePrime != here->MOS3sNode) + { + CKTdltNNum(ckt, here->MOS3sNodePrime); + here->MOS3sNodePrime= 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/mos3/mos3sld.c b/src/spicelib/devices/mos3/mos3sld.c new file mode 100644 index 000000000..ab795d0ac --- /dev/null +++ b/src/spicelib/devices/mos3/mos3sld.c @@ -0,0 +1,621 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* actually load the current sensitivity + * information into the array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3sLoad(inModel,ckt) +GENmodel *inModel; +CKTcircuit *ckt; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + double SaveState[44]; + int save_mode; + int i; + int iparmno; + int error; + int flag; + double A0; + double DELA; + double Apert; + double DELAinv; + double gspr0; + double gspr; + double gdpr0; + double gdpr; + double cdpr0; + double cspr0; + double cd0; + double cbd0; + double cbs0; + double cd; + double cbd; + double cbs; + double DcdprDp; + double DcsprDp; + double DcbDp; + double DcdDp; + double DcbsDp; + double DcbdDp; + double DcdprmDp; + double DcsprmDp; + double qgs0; + double qgd0; + double qgb0; + double qbd0; + double qbd; + double qbs0; + double qbs; + double DqgsDp; + double DqgdDp; + double DqgbDp; + double DqbdDp; + double DqbsDp; + double Osxpgs; + double Osxpgd; + double Osxpgb; + double Osxpbd; + double Osxpbs; + double tag0; + double tag1; + double arg; + double sarg; + double sargsw; + int offset; + double EffectiveLength; + SENstruct *info; + +#ifdef SENSDEBUG + printf("MOS3senload \n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); + printf("CKTorder = %d\n",ckt->CKTorder); +#endif /* SENSDEBUG */ + + info = ckt->CKTsenInfo; + info->SENstatus = PERTURBATION; + + tag0 = ckt->CKTag[0]; + tag1 = ckt->CKTag[1]; + if(ckt->CKTorder == 1){ + tag1 = 0; + } + + /* loop through all the models */ + for( ; model != NULL; model = model->MOS3nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("senload instance name %s\n",here->MOS3name); + printf("gate = %d ,drain = %d, drainprm = %d\n", + here->MOS3gNode,here->MOS3dNode,here->MOS3dNodePrime); + printf("source = %d , sourceprm = %d ,body = %d, senparmno = %d\n", + here->MOS3sNode ,here->MOS3sNodePrime, + here->MOS3bNode,here->MOS3senParmNo); +#endif /* SENSDEBUG */ + + + /* save the unperturbed values in the state vector */ + for(i=0; i <= 16; i++){ + *(SaveState + i) = *(ckt->CKTstate0 + here->MOS3states + i); + } + + *(SaveState + 17) = here->MOS3sourceConductance; + *(SaveState + 18) = here->MOS3drainConductance; + *(SaveState + 19) = here->MOS3cd; + *(SaveState + 20) = here->MOS3cbs; + *(SaveState + 21) = here->MOS3cbd; + *(SaveState + 22) = here->MOS3gmbs; + *(SaveState + 23) = here->MOS3gm; + *(SaveState + 24) = here->MOS3gds; + *(SaveState + 25) = here->MOS3gbd; + *(SaveState + 26) = here->MOS3gbs; + *(SaveState + 27) = here->MOS3capbd; + *(SaveState + 28) = here->MOS3capbs; + *(SaveState + 29) = here->MOS3Cbd; + *(SaveState + 30) = here->MOS3Cbdsw; + *(SaveState + 31) = here->MOS3Cbs; + *(SaveState + 32) = here->MOS3Cbssw; + *(SaveState + 33) = here->MOS3f2d; + *(SaveState + 34) = here->MOS3f3d; + *(SaveState + 35) = here->MOS3f4d; + *(SaveState + 36) = here->MOS3f2s; + *(SaveState + 37) = here->MOS3f3s; + *(SaveState + 38) = here->MOS3f4s; + *(SaveState + 39) = here->MOS3cgs; + *(SaveState + 40) = here->MOS3cgd; + *(SaveState + 41) = here->MOS3cgb; + *(SaveState + 42) = here->MOS3vdsat; + *(SaveState + 43) = here->MOS3von; + save_mode = here->MOS3mode; + + + if(here->MOS3senParmNo == 0) goto next1; + +#ifdef SENSDEBUG + printf("without perturbation \n"); +#endif /* SENSDEBUG */ + + cdpr0= here->MOS3cd; + cspr0= -(here->MOS3cd + here->MOS3cbd + here->MOS3cbs); + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)){ + qgs0 = *(ckt->CKTstate1 + here->MOS3qgs); + qgd0 = *(ckt->CKTstate1 + here->MOS3qgd); + qgb0 = *(ckt->CKTstate1 + here->MOS3qgb); + } + else{ + qgs0 = *(ckt->CKTstate0 + here->MOS3qgs); + qgd0 = *(ckt->CKTstate0 + here->MOS3qgd); + qgb0 = *(ckt->CKTstate0 + here->MOS3qgb); + } + + here->MOS3senPertFlag = ON; + error = MOS3load((GENmodel*)model,ckt); + if(error) return(error); + + cd0 = here->MOS3cd ; + cbd0 = here->MOS3cbd ; + cbs0 = here->MOS3cbs ; + gspr0= here->MOS3sourceConductance ; + gdpr0= here->MOS3drainConductance ; + + qbs0 = *(ckt->CKTstate0 + here->MOS3qbs); + qbd0 = *(ckt->CKTstate0 + here->MOS3qbd); + + for( flag = 0 ; flag <= 1 ; flag++){ + if(here->MOS3sens_l == 0) + if(flag == 0) goto next2; + if(here->MOS3sens_w == 0) + if(flag == 1) goto next2; + if(flag == 0){ + A0 = here->MOS3l; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS3l = Apert; + } + else{ + A0 = here->MOS3w; + DELA = info->SENpertfac * A0; + DELAinv = 1.0/DELA; + Apert = A0 + DELA; + here->MOS3w = Apert; + here->MOS3drainArea *= (1 + info->SENpertfac); + here->MOS3sourceArea *= (1 + info->SENpertfac); + here->MOS3Cbd *= (1 + info->SENpertfac); + here->MOS3Cbs *= (1 + info->SENpertfac); + if(here->MOS3drainPerimiter){ + here->MOS3Cbdsw += here->MOS3Cbdsw * + DELA/here->MOS3drainPerimiter; + } + if(here->MOS3sourcePerimiter){ + here->MOS3Cbssw += here->MOS3Cbssw * + DELA/here->MOS3sourcePerimiter; + } + if(*(ckt->CKTstate0 + here->MOS3vbd) >= + here->MOS3tDepCap){ + arg = 1-model->MOS3fwdCapDepCoeff; + sarg = exp( (-model->MOS3bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS3bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS3f2d = here->MOS3Cbd* + (1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctBotGradingCoeff))* sarg/arg + + here->MOS3Cbdsw*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS3f3d = here->MOS3Cbd * + model->MOS3bulkJctBotGradingCoeff * sarg/arg/ + model->MOS3bulkJctPotential + + here->MOS3Cbdsw * + model->MOS3bulkJctSideGradingCoeff *sargsw/arg / + model->MOS3bulkJctPotential; + here->MOS3f4d = here->MOS3Cbd* + model->MOS3bulkJctPotential*(1-arg*sarg)/ + (1-model->MOS3bulkJctBotGradingCoeff) + + here->MOS3Cbdsw*model->MOS3bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS3bulkJctSideGradingCoeff) + -here->MOS3f3d/2* + (here->MOS3tDepCap*here->MOS3tDepCap) + -here->MOS3tDepCap * here->MOS3f2d; + } + if(*(ckt->CKTstate0 + here->MOS3vbs) >= + here->MOS3tDepCap){ + arg = 1-model->MOS3fwdCapDepCoeff; + sarg = exp( (-model->MOS3bulkJctBotGradingCoeff) * + log(arg) ); + sargsw = exp( (-model->MOS3bulkJctSideGradingCoeff) * + log(arg) ); + here->MOS3f2s = here->MOS3Cbs* + (1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctBotGradingCoeff))* sarg/arg + + here->MOS3Cbssw*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS3f3s = here->MOS3Cbs * + model->MOS3bulkJctBotGradingCoeff * sarg/arg/ + model->MOS3bulkJctPotential + + here->MOS3Cbssw * + model->MOS3bulkJctSideGradingCoeff * sargsw/arg/ + model->MOS3bulkJctPotential; + here->MOS3f4s = here->MOS3Cbs* + model->MOS3bulkJctPotential*(1-arg*sarg)/ + (1-model->MOS3bulkJctBotGradingCoeff) + + here->MOS3Cbssw*model->MOS3bulkJctPotential* + (1-arg*sargsw)/ + (1-model->MOS3bulkJctSideGradingCoeff) + -here->MOS3f3s/2* + (here->MOS3tBulkPot*here->MOS3tBulkPot) + -here->MOS3tBulkPot * here->MOS3f2s; + } + here->MOS3drainConductance *= Apert/A0; + here->MOS3sourceConductance *= Apert/A0; + } + + +#ifdef SENSDEBUG + if(flag == 0) + printf("perturbation of l\n"); + if(flag == 1) + printf("perturbation of w\n"); +#endif /* SENSDEBUG */ + + error = MOS3load((GENmodel*)model,ckt); + if(error) return(error); + + if(flag == 0){ + here->MOS3l = A0; + } + else{ + here->MOS3w = A0; + here->MOS3drainArea /= (1 + info->SENpertfac); + here->MOS3sourceArea /= (1 + info->SENpertfac); + here->MOS3drainConductance *= A0/Apert; + here->MOS3sourceConductance *= A0/Apert; + } + cd = here->MOS3cd ; + cbd = here->MOS3cbd ; + cbs = here->MOS3cbs ; + + gspr= here->MOS3sourceConductance ; + gdpr= here->MOS3drainConductance ; + + DcdDp = (cd - cd0) * DELAinv; + DcbsDp = (cbs - cbs0) * DELAinv; + DcbdDp = (cbd - cbd0) * DELAinv; + DcbDp = ( DcbsDp + DcbdDp ); + + DcdprDp = 0; + DcsprDp = 0; + if(here->MOS3dNode != here->MOS3dNodePrime) + if(gdpr0) DcdprDp = cdpr0 * (gdpr - gdpr0)/gdpr0 * DELAinv; + if(here->MOS3sNode != here->MOS3sNodePrime) + if(gspr0) DcsprDp = cspr0 * (gspr - gspr0)/gspr0 * DELAinv; + + DcdprmDp = ( - DcdprDp + DcdDp); + DcsprmDp = ( - DcbsDp - DcdDp - DcbdDp - DcsprDp); + + if(flag == 0){ + EffectiveLength = here->MOS3l + - 2*model->MOS3latDiff; + if(EffectiveLength == 0){ + DqgsDp = 0; + DqgdDp = 0; + DqgbDp = 0; + } + else{ + DqgsDp = model->MOS3type * qgs0 / EffectiveLength; + DqgdDp = model->MOS3type * qgd0 / EffectiveLength; + DqgbDp = model->MOS3type * qgb0 / EffectiveLength; + } + } + else{ + DqgsDp = model->MOS3type * qgs0 / here->MOS3w; + DqgdDp = model->MOS3type * qgd0 / here->MOS3w; + DqgbDp = model->MOS3type * qgb0 / here->MOS3w; + } + + + qbd = *(ckt->CKTstate0 + here->MOS3qbd); + qbs = *(ckt->CKTstate0 + here->MOS3qbs); + + DqbsDp = model->MOS3type * (qbs - qbs0)*DELAinv; + DqbdDp = model->MOS3type * (qbd - qbd0)*DELAinv; + + if(flag == 0){ + *(here->MOS3dphigs_dl) = DqgsDp; + *(here->MOS3dphigd_dl) = DqgdDp; + *(here->MOS3dphibs_dl) = DqbsDp; + *(here->MOS3dphibd_dl) = DqbdDp; + *(here->MOS3dphigb_dl) = DqgbDp; + } + else{ + *(here->MOS3dphigs_dw) = DqgsDp; + *(here->MOS3dphigd_dw) = DqgdDp; + *(here->MOS3dphibs_dw) = DqbsDp; + *(here->MOS3dphibd_dw) = DqbdDp; + *(here->MOS3dphigb_dw) = DqgbDp; + } + + +#ifdef SENSDEBUG + printf("CKTag[0]=%.7e,CKTag[1]=%.7e,flag= %d\n", + ckt->CKTag[0],ckt->CKTag[1],flag); + printf("cd0 = %.7e ,cd = %.7e,\n",cd0,cd); + printf("cbs0 = %.7e ,cbs = %.7e,\n",cbs0,cbs); + printf("cbd0 = %.7e ,cbd = %.7e,\n",cbd0,cbd); + printf("DcdprmDp = %.7e,\n",DcdprmDp); + printf("DcsprmDp = %.7e,\n",DcsprmDp); + printf("DcdprDp = %.7e,\n",DcdprDp); + printf("DcsprDp = %.7e,\n",DcsprDp); + printf("qgs0 = %.7e \n",qgs0); + printf("qgd0 = %.7e \n",qgd0); + printf("qgb0 = %.7e \n",qgb0); + printf("qbs0 = %.7e ,qbs = %.7e,\n",qbs0,qbs); + printf("qbd0 = %.7e ,qbd = %.7e,\n",qbd0,qbd); + printf("DqgsDp = %.7e \n",DqgsDp); + printf("DqgdDp = %.7e \n",DqgdDp); + printf("DqgbDp = %.7e \n",DqgbDp); + printf("DqbsDp = %.7e \n",DqbsDp); + printf("DqbdDp = %.7e \n",DqbdDp); + printf("EffectiveLength = %.7e \n",EffectiveLength); + printf("tdepCap = %.7e \n",here->MOS3tDepCap); + printf("\n"); +#endif /* SENSDEBUG*/ + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) + goto next2; + + /* + * load RHS matrix + */ + + if(flag == 0){ + *(info->SEN_RHS[here->MOS3bNode] + here->MOS3senParmNo) + -= model->MOS3type * DcbDp; + *(info->SEN_RHS[here->MOS3dNode] + here->MOS3senParmNo) + -= model->MOS3type * DcdprDp; + *(info->SEN_RHS[here->MOS3dNodePrime] + here->MOS3senParmNo) + -= model->MOS3type * DcdprmDp; + *(info->SEN_RHS[here->MOS3sNode] + here->MOS3senParmNo) + -= model->MOS3type * DcsprDp; + *(info->SEN_RHS[here->MOS3sNodePrime] + here->MOS3senParmNo) + -= model->MOS3type * DcsprmDp; + } + else{ + offset = here->MOS3sens_l; + + *(info->SEN_RHS[here->MOS3bNode] + here->MOS3senParmNo + + offset) -= model->MOS3type * DcbDp; + *(info->SEN_RHS[here->MOS3dNode] + here->MOS3senParmNo + + offset) -= model->MOS3type * DcdprDp; + *(info->SEN_RHS[here->MOS3dNodePrime] + here->MOS3senParmNo + + offset) -= model->MOS3type * DcdprmDp; + *(info->SEN_RHS[here->MOS3sNode] + here->MOS3senParmNo + + offset) -= model->MOS3type * DcsprDp; + *(info->SEN_RHS[here->MOS3sNodePrime] + here->MOS3senParmNo + + offset) -= model->MOS3type * DcsprmDp; + } +#ifdef SENSDEBUG + printf("after loading\n"); + if(flag == 0){ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS3bNode] + + here->MOS3senParmNo)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNode] + + here->MOS3senParmNo)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNode] + + here->MOS3senParmNo)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNodePrime] + + here->MOS3senParmNo)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNodePrime] + + here->MOS3senParmNo)); + printf("\n"); + } + else{ + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS3bNode] + + here->MOS3senParmNo + here->MOS3sens_l)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNode] + + here->MOS3senParmNo + here->MOS3sens_l)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNode] + + here->MOS3senParmNo + here->MOS3sens_l)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNodePrime] + + here->MOS3senParmNo + here->MOS3sens_l)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNodePrime] + + here->MOS3senParmNo + here->MOS3sens_l)); + } +#endif /* SENSDEBUG*/ +next2: + ; + } +next1: + if((info->SENmode == DCSEN) || + (ckt->CKTmode&MODETRANOP) ) goto restore; + if((info->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) goto restore; + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ +#ifdef SENSDEBUG + printf("after conductive currents\n"); + printf("iparmno = %d\n",iparmno); + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS3bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNodePrime] + iparmno)); + printf("\n"); +#endif /* SENSDEBUG */ + Osxpgs = tag0 * *(ckt->CKTstate1 + here->MOS3sensxpgs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS3sensxpgs + + 10*(iparmno - 1) + 1); + + Osxpgd = tag0 * *(ckt->CKTstate1 + here->MOS3sensxpgd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS3sensxpgd + + 10*(iparmno - 1) + 1); + + Osxpbs = tag0 * *(ckt->CKTstate1 + here->MOS3sensxpbs + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS3sensxpbs + + 10*(iparmno - 1) + 1); + + Osxpbd =tag0 * *(ckt->CKTstate1 + here->MOS3sensxpbd + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS3sensxpbd + + 10*(iparmno - 1) + 1); + Osxpgb = tag0 * *(ckt->CKTstate1 + here->MOS3sensxpgb + + 10*(iparmno - 1)) + + tag1 * *(ckt->CKTstate1 + here->MOS3sensxpgb + + 10*(iparmno - 1) + 1); + +#ifdef SENSDEBUG + printf("iparmno=%d\n",iparmno); + printf("sxpgs=%.7e,sdgs=%.7e\n", + *(ckt->CKTstate1 + here->MOS3sensxpgs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS3sensxpgs + 10*(iparmno - 1) + 1)); + printf("sxpgd=%.7e,sdgd=%.7e\n", + *(ckt->CKTstate1 + here->MOS3sensxpgd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS3sensxpgd + 10*(iparmno - 1) + 1)); + printf("sxpbs=%.7e,sdbs=%.7e\n", + *(ckt->CKTstate1 + here->MOS3sensxpbs + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS3sensxpbs + 10*(iparmno - 1) + 1)); + printf("sxpbd=%.7e,sdbd=%.7e\n", + *(ckt->CKTstate1 + here->MOS3sensxpbd + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS3sensxpbd + 10*(iparmno - 1) + 1)); + printf("sxpgb=%.7e,sdgb=%.7e\n", + *(ckt->CKTstate1 + here->MOS3sensxpgb + + 10*(iparmno - 1)), *(ckt->CKTstate1 + + here->MOS3sensxpgb + 10*(iparmno - 1) + 1)); + printf("before loading DqDp\n"); + printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); + printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", + Osxpbs,Osxpbd,Osxpgb); + printf("\n"); +#endif /* SENSDEBUG */ + if(here->MOS3sens_l && (iparmno == here->MOS3senParmNo)){ + Osxpgs -= tag0 * *(here->MOS3dphigs_dl); + Osxpgd -= tag0 * *(here->MOS3dphigd_dl); + Osxpbs -= tag0 * *(here->MOS3dphibs_dl); + Osxpbd -= tag0 * *(here->MOS3dphibd_dl); + Osxpgb -= tag0 * *(here->MOS3dphigb_dl); + } + if(here->MOS3sens_w && + (iparmno == (here->MOS3senParmNo + here->MOS3sens_l))){ + Osxpgs -= tag0 * *(here->MOS3dphigs_dw); + Osxpgd -= tag0 * *(here->MOS3dphigd_dw); + Osxpbs -= tag0 * *(here->MOS3dphibs_dw); + Osxpbd -= tag0 * *(here->MOS3dphibd_dw); + Osxpgb -= tag0 * *(here->MOS3dphigb_dw); + } +#ifdef SENSDEBUG + printf("after loading DqDp\n"); + printf("DqgsDp=%.7e",DqgsDp); + printf("Osxpgs=%.7e,Osxpgd=%.7e\n",Osxpgs,Osxpgd); + printf("Osxpbs=%.7e,Osxpbd=%.7e,Osxpgb=%.7e\n", + Osxpbs,Osxpbd,Osxpgb); +#endif /* SENSDEBUG */ + + *(info->SEN_RHS[here->MOS3bNode] + iparmno) += + Osxpbs + Osxpbd -Osxpgb; + *(info->SEN_RHS[here->MOS3gNode] + iparmno) += + Osxpgs + Osxpgd + Osxpgb; + + *(info->SEN_RHS[here->MOS3dNodePrime] + iparmno) -= + Osxpgd + Osxpbd ; + *(info->SEN_RHS[here->MOS3sNodePrime] + iparmno) -= + Osxpgs + Osxpbs; +#ifdef SENSDEBUG + printf("after capacitive currents\n"); + printf("DcbDp=%.7e\n", + *(info->SEN_RHS[here->MOS3bNode] + iparmno)); + printf("DcdprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNode] + iparmno)); + printf("DcdprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3dNodePrime] + iparmno)); + printf("DcsprDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNode] + iparmno)); + printf("DcsprmDp=%.7e\n", + *(info->SEN_RHS[here->MOS3sNodePrime] + iparmno)); +#endif /* SENSDEBUG */ + + } +restore: /* put the unperturbed values back into the state vector */ + for(i=0; i <= 16; i++) + *(ckt->CKTstate0 + here->MOS3states + i) = *(SaveState + i); + here->MOS3sourceConductance = *(SaveState + 17) ; + here->MOS3drainConductance = *(SaveState + 18) ; + here->MOS3cd = *(SaveState + 19) ; + here->MOS3cbs = *(SaveState + 20) ; + here->MOS3cbd = *(SaveState + 21) ; + here->MOS3gmbs = *(SaveState + 22) ; + here->MOS3gm = *(SaveState + 23) ; + here->MOS3gds = *(SaveState + 24) ; + here->MOS3gbd = *(SaveState + 25) ; + here->MOS3gbs = *(SaveState + 26) ; + here->MOS3capbd = *(SaveState + 27) ; + here->MOS3capbs = *(SaveState + 28) ; + here->MOS3Cbd = *(SaveState + 29) ; + here->MOS3Cbdsw = *(SaveState + 30) ; + here->MOS3Cbs = *(SaveState + 31) ; + here->MOS3Cbssw = *(SaveState + 32) ; + here->MOS3f2d = *(SaveState + 33) ; + here->MOS3f3d = *(SaveState + 34) ; + here->MOS3f4d = *(SaveState + 35) ; + here->MOS3f2s = *(SaveState + 36) ; + here->MOS3f3s = *(SaveState + 37) ; + here->MOS3f4s = *(SaveState + 38) ; + here->MOS3cgs = *(SaveState + 39) ; + here->MOS3cgd = *(SaveState + 40) ; + here->MOS3cgb = *(SaveState + 41) ; + here->MOS3vdsat = *(SaveState + 42) ; + here->MOS3von = *(SaveState + 43) ; + here->MOS3mode = save_mode ; + + here->MOS3senPertFlag = OFF; + + } + } + info->SENstatus = NORMAL; +#ifdef SENSDEBUG + printf("MOS3senload end\n"); +#endif /* SENSDEBUG */ + return(OK); +} + diff --git a/src/spicelib/devices/mos3/mos3sprt.c b/src/spicelib/devices/mos3/mos3sprt.c new file mode 100644 index 000000000..a504d0b6a --- /dev/null +++ b/src/spicelib/devices/mos3/mos3sprt.c @@ -0,0 +1,63 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* Pretty print the sensitivity info for all the MOS3 + * devices in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +void +MOS3sPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + + printf("LEVEL 1 MOSFETS-----------------\n"); + /* loop through all the MOS3 models */ + for( ; model != NULL; model = model->MOS3nextModel ) { + + printf("Model name:%s\n",model->MOS3modName); + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + printf(" Instance name:%s\n",here->MOS3name); + printf(" Drain, Gate , Source nodes: %s, %s ,%s\n", + CKTnodName(ckt,here->MOS3dNode),CKTnodName(ckt,here->MOS3gNode), + CKTnodName(ckt,here->MOS3sNode)); + + printf(" Length: %g ",here->MOS3l); + printf(here->MOS3lGiven ? "(specified)\n" : "(default)\n"); + printf(" Width: %g ",here->MOS3w); + printf(here->MOS3wGiven ? "(specified)\n" : "(default)\n"); + if(here->MOS3sens_l == 1){ + printf(" MOS3senParmNo:l = %d ",here->MOS3senParmNo); + } + else{ + printf(" MOS3senParmNo:l = 0 "); + } + if(here->MOS3sens_w == 1){ + printf(" w = %d \n",here->MOS3senParmNo + here->MOS3sens_l); + } + else{ + printf(" w = 0 \n"); + } + + + } + } +} + diff --git a/src/spicelib/devices/mos3/mos3sset.c b/src/spicelib/devices/mos3/mos3sset.c new file mode 100644 index 000000000..876691003 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3sset.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + + /* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3sSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + + /* loop through all the models */ + for( ; model != NULL; model = model->MOS3nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + + if(here->MOS3senParmNo){ + if((here->MOS3sens_l)&&(here->MOS3sens_w)){ + here->MOS3senParmNo = ++(info->SENparms); + ++(info->SENparms);/* MOS has two design parameters */ + } + else{ + here->MOS3senParmNo = ++(info->SENparms); + } + } + here->MOS3senPertFlag = OFF; + if((here->MOS3sens = (double *)MALLOC(72*sizeof(double))) == NULL) { + return(E_NOMEM); + } + + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/mos3/mos3supd.c b/src/spicelib/devices/mos3/mos3supd.c new file mode 100644 index 000000000..20d9dcb5e --- /dev/null +++ b/src/spicelib/devices/mos3/mos3supd.c @@ -0,0 +1,181 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include +#include "ngspice.h" +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3sUpdate(inModel,ckt) +GENmodel *inModel; +register CKTcircuit *ckt; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + int iparmno; + double sb; + double sg; + double sdprm; + double ssprm; + double sxpgs; + double sxpgd; + double sxpbs; + double sxpbd; + double sxpgb; + double dummy1; + double dummy2; + SENstruct *info; + + + if(ckt->CKTtime == 0) return(OK); + info = ckt->CKTsenInfo; + +#ifdef SENSDEBUG + printf("MOS3senupdate\n"); + printf("CKTtime = %.5e\n",ckt->CKTtime); +#endif /* SENSDEBUG */ + + sxpgs = 0; + sxpgd = 0; + sxpbs = 0; + sxpbd = 0; + sxpgb = 0; + dummy1 = 0; + dummy2 = 0; + + /* loop through all the MOS3 models */ + for( ; model != NULL; model = model->MOS3nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS3instances; here != NULL ; + here=here->MOS3nextInstance) { + if (here->MOS3owner != ARCHme) continue; + +#ifdef SENSDEBUG + printf("senupdate instance name %s\n",here->MOS3name); + printf("before loading\n"); + printf("CKTag[0] = %.2e,CKTag[1] = %.2e\n", + ckt->CKTag[0],ckt->CKTag[1]); + printf("capgs = %.7e\n",here->MOS3cgs); + printf("capgd = %.7e\n",here->MOS3cgd); + printf("capgb = %.7e\n",here->MOS3cgb); + printf("capbs = %.7e\n",here->MOS3capbs); + printf("capbd = %.7e\n",here->MOS3capbd); +#endif /* SENSDEBUG */ + + for(iparmno = 1;iparmno<=info->SENparms;iparmno++){ + + sb = *(info->SEN_Sap[here->MOS3bNode] + iparmno); + sg = *(info->SEN_Sap[here->MOS3gNode] + iparmno); + ssprm = *(info->SEN_Sap[here->MOS3sNodePrime] + iparmno); + sdprm = *(info->SEN_Sap[here->MOS3dNodePrime] + iparmno); +#ifdef SENSDEBUG + printf("iparmno = %d\n",iparmno); + printf("sb = %.7e,sg = %.7e\n",sb,sg); + printf("ssprm = %.7e,sdprm = %.7e\n",ssprm,sdprm); +#endif /* SENSDEBUG */ + + sxpgs = (sg - ssprm) * here->MOS3cgs ; + sxpgd = (sg - sdprm) * here->MOS3cgd ; + sxpgb = (sg - sb) * here->MOS3cgb ; + sxpbs = (sb - ssprm) * here->MOS3capbs ; + sxpbd = (sb - sdprm) * here->MOS3capbd ; + + if(here->MOS3sens_l && (iparmno == here->MOS3senParmNo)){ + sxpgs += *(here->MOS3dphigs_dl); + sxpgd += *(here->MOS3dphigd_dl); + sxpbs += *(here->MOS3dphibs_dl); + sxpbd += *(here->MOS3dphibd_dl); + sxpgb += *(here->MOS3dphigb_dl); + } + if(here->MOS3sens_w && + (iparmno == (here->MOS3senParmNo+here->MOS3sens_l))){ + sxpgs += *(here->MOS3dphigs_dw); + sxpgd += *(here->MOS3dphigd_dw); + sxpbs += *(here->MOS3dphibs_dw); + sxpbd += *(here->MOS3dphibd_dw); + sxpgb += *(here->MOS3dphigb_dw); + } + if(ckt->CKTmode & MODEINITTRAN) { + *(ckt->CKTstate1 + here->MOS3sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate1 + here->MOS3sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate1 + here->MOS3sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate1 + here->MOS3sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate1 + here->MOS3sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + *(ckt->CKTstate1 + here->MOS3sensxpgs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS3sensxpgd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS3sensxpbs + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS3sensxpbd + + 10 * (iparmno - 1) + 1) = 0; + *(ckt->CKTstate1 + here->MOS3sensxpgb + + 10 * (iparmno - 1) + 1) = 0; + goto next; + } + + *(ckt->CKTstate0 + here->MOS3sensxpgs + + 10 * (iparmno - 1)) = sxpgs; + *(ckt->CKTstate0 + here->MOS3sensxpgd + + 10 * (iparmno - 1)) = sxpgd; + *(ckt->CKTstate0 + here->MOS3sensxpbs + + 10 * (iparmno - 1)) = sxpbs; + *(ckt->CKTstate0 + here->MOS3sensxpbd + + 10 * (iparmno - 1)) = sxpbd; + *(ckt->CKTstate0 + here->MOS3sensxpgb + + 10 * (iparmno - 1)) = sxpgb; + + NIintegrate(ckt,&dummy1,&dummy2,here->MOS3cgs, + here->MOS3sensxpgs + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS3cgd, + here->MOS3sensxpgd + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS3cgb, + here->MOS3sensxpgb + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS3capbs, + here->MOS3sensxpbs + 10*(iparmno -1)); + NIintegrate(ckt,&dummy1,&dummy2,here->MOS3capbd, + here->MOS3sensxpbd + 10*(iparmno -1)); + + +next: + ; +#ifdef SENSDEBUG + printf("after loading\n"); + printf("sxpgs = %.7e,sdotxpgs = %.7e\n", + sxpgs,*(ckt->CKTstate0 + here->MOS3sensxpgs + + 10 * (iparmno - 1) + 1)); + printf("sxpgd = %.7e,sdotxpgd = %.7e\n", + sxpgd,*(ckt->CKTstate0 + here->MOS3sensxpgd + + 10 * (iparmno - 1) + 1)); + printf("sxpgb = %.7e,sdotxpgb = %.7e\n", + sxpgb,*(ckt->CKTstate0 + here->MOS3sensxpgb + + 10 * (iparmno - 1) + 1)); + printf("sxpbs = %.7e,sdotxpbs = %.7e\n", + sxpbs,*(ckt->CKTstate0 + here->MOS3sensxpbs + + 10 * (iparmno - 1) + 1)); + printf("sxpbd = %.7e,sdotxpbd = %.7e\n", + sxpbd,*(ckt->CKTstate0 + here->MOS3sensxpbd + + 10 * (iparmno - 1) + 1)); +#endif /* SENSDEBUG */ + } + } + } +#ifdef SENSDEBUG + printf("MOS3senupdate end\n"); +#endif /* SENSDEBUG */ + return(OK); + +} + diff --git a/src/spicelib/devices/mos3/mos3temp.c b/src/spicelib/devices/mos3/mos3temp.c new file mode 100644 index 000000000..52f4b0997 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3temp.c @@ -0,0 +1,311 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos3defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +/* assuming silicon - make definition for epsilon of silicon */ +#define EPSSIL (11.7 * 8.854214871e-12) + +int +MOS3temp(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + double wkfngs; + double wkfng; + double fermig; + double fermis; + double vfb; + double fact1,fact2; + double vt,vtnom; + double kt,kt1; + double ratio,ratio4; + double egfet,egfet1; + double pbfact,pbfact1,pbo; + double phio; + double arg1; + double capfact; + double gmanew,gmaold; + /* loop through all the mosfet models */ + for( ; model != NULL; model = model->MOS3nextModel) { + + if(!model->MOS3tnomGiven) { + model->MOS3tnom = ckt->CKTnomTemp; + } + fact1 = model->MOS3tnom/REFTEMP; + vtnom = model->MOS3tnom*CONSTKoverQ; + kt1 = CONSTboltz * model->MOS3tnom; + egfet1 = 1.16-(7.02e-4*model->MOS3tnom*model->MOS3tnom)/ + (model->MOS3tnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1); + + + model->MOS3oxideCapFactor = 3.9 * 8.854214871e-12/ + model->MOS3oxideThickness; + if(!model->MOS3surfaceMobilityGiven) model->MOS3surfaceMobility=600; + if(!model->MOS3transconductanceGiven) { + model->MOS3transconductance = model->MOS3surfaceMobility * + model->MOS3oxideCapFactor * 1e-4; + } + if(model->MOS3substrateDopingGiven) { + if(model->MOS3substrateDoping*1e6 /*(cm**3/m**3)*/ >1.45e16) { + if(!model->MOS3phiGiven) { + model->MOS3phi = 2*vtnom* + log(model->MOS3substrateDoping* + 1e6/*(cm**3/m**3)*//1.45e16); + model->MOS3phi = MAX(.1,model->MOS3phi); + } + fermis = model->MOS3type * .5 * model->MOS3phi; + wkfng = 3.2; + if(!model->MOS3gateTypeGiven) model->MOS3gateType=1; + if(model->MOS3gateType != 0) { + fermig = model->MOS3type * model->MOS3gateType*.5*egfet1; + wkfng = 3.25 + .5 * egfet1 - fermig; + } + wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis); + if(!model->MOS3gammaGiven) { + model->MOS3gamma = sqrt(2 * EPSSIL * + CHARGE * model->MOS3substrateDoping* + 1e6 /*(cm**3/m**3)*/ )/ model->MOS3oxideCapFactor; + } + if(!model->MOS3vt0Given) { + if(!model->MOS3surfaceStateDensityGiven) + model->MOS3surfaceStateDensity=0; + vfb = wkfngs - model->MOS3surfaceStateDensity * 1e4 + * CHARGE/model->MOS3oxideCapFactor; + model->MOS3vt0 = vfb + model->MOS3type * + (model->MOS3gamma * sqrt(model->MOS3phi)+ + model->MOS3phi); + } else { + vfb = model->MOS3vt0 - model->MOS3type * (model->MOS3gamma* + sqrt(model->MOS3phi)+model->MOS3phi); + } + model->MOS3alpha = (EPSSIL+EPSSIL)/ + (CHARGE*model->MOS3substrateDoping*1e6 /*(cm**3/m**3)*/ ); + model->MOS3coeffDepLayWidth = sqrt(model->MOS3alpha); + } else { + model->MOS3substrateDoping = 0; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: Nsub < Ni ",&(model->MOS3modName)); + return(E_BADPARM); + } + } + /* now model parameter preprocessing */ + model->MOS3narrowFactor = model->MOS3delta * 0.5 * M_PI * EPSSIL / + model->MOS3oxideCapFactor ; + + + /* loop through all instances of the model */ + for(here = model->MOS3instances; here!= NULL; + here = here->MOS3nextInstance) { + + double czbd; /* zero voltage bulk-drain capacitance */ + double czbdsw; /* zero voltage bulk-drain sidewall capacitance */ + double czbs; /* zero voltage bulk-source capacitance */ + double czbssw; /* zero voltage bulk-source sidewall capacitance */ + double arg; /* 1 - fc */ + double sarg; /* (1-fc) ^^ (-mj) */ + double sargsw; /* (1-fc) ^^ (-mjsw) */ + if (here->MOS3owner != ARCHme) continue; + + + /* perform the parameter defaulting */ + + if(!here->MOS3tempGiven) { + here->MOS3temp = ckt->CKTtemp; + } + vt = here->MOS3temp * CONSTKoverQ; + ratio = here->MOS3temp/model->MOS3tnom; + fact2 = here->MOS3temp/REFTEMP; + kt = here->MOS3temp * CONSTboltz; + egfet = 1.16-(7.02e-4*here->MOS3temp*here->MOS3temp)/ + (here->MOS3temp+1108); + arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); + + + if(!here->MOS3lGiven) { + here->MOS3l = ckt->CKTdefaultMosL; + } + if(!here->MOS3sourceAreaGiven) { + here->MOS3sourceArea = ckt->CKTdefaultMosAS; + } + if(!here->MOS3wGiven) { + here->MOS3w = ckt->CKTdefaultMosW; + } + if(model->MOS3drainResistanceGiven) { + if(model->MOS3drainResistance != 0) { + here->MOS3drainConductance = 1/model->MOS3drainResistance; + } else { + here->MOS3drainConductance = 0; + } + } else if (model->MOS3sheetResistanceGiven) { + if(model->MOS3sheetResistance != 0) { + here->MOS3drainConductance = + 1/(model->MOS3sheetResistance*here->MOS3drainSquares); + } else { + here->MOS3drainConductance = 0; + } + } else { + here->MOS3drainConductance = 0; + } + if(model->MOS3sourceResistanceGiven) { + if(model->MOS3sourceResistance != 0) { + here->MOS3sourceConductance = 1/model->MOS3sourceResistance; + } else { + here->MOS3sourceConductance = 0; + } + } else if (model->MOS3sheetResistanceGiven) { + if(model->MOS3sheetResistance != 0) { + here->MOS3sourceConductance = + 1/(model->MOS3sheetResistance*here->MOS3sourceSquares); + } else { + here->MOS3sourceConductance = 0; + } + } else { + here->MOS3sourceConductance = 0; + } + + if(here->MOS3l - 2 * model->MOS3latDiff <=0) { + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: effective channel length less than zero", + &(here->MOS3name)); + return(E_BADPARM); + } + + ratio4 = ratio * sqrt(ratio); + here->MOS3tTransconductance = model->MOS3transconductance / ratio4; + here->MOS3tSurfMob = model->MOS3surfaceMobility/ratio4; + phio= (model->MOS3phi-pbfact1)/fact1; + here->MOS3tPhi = fact2 * phio + pbfact; + here->MOS3tVbi = + model->MOS3vt0 - model->MOS3type * + (model->MOS3gamma* sqrt(model->MOS3phi)) + +.5*(egfet1-egfet) + + model->MOS3type*.5* (here->MOS3tPhi-model->MOS3phi); + here->MOS3tVto = here->MOS3tVbi + model->MOS3type * + model->MOS3gamma * sqrt(here->MOS3tPhi); + here->MOS3tSatCur = model->MOS3jctSatCur* + exp(-egfet/vt+egfet1/vtnom); + here->MOS3tSatCurDens = model->MOS3jctSatCurDensity * + exp(-egfet/vt+egfet1/vtnom); + pbo = (model->MOS3bulkJctPotential - pbfact1)/fact1; + gmaold = (model->MOS3bulkJctPotential-pbo)/pbo; + capfact = 1/(1+model->MOS3bulkJctBotGradingCoeff* + (4e-4*(model->MOS3tnom-REFTEMP)-gmaold)); + here->MOS3tCbd = model->MOS3capBD * capfact; + here->MOS3tCbs = model->MOS3capBS * capfact; + here->MOS3tCj = model->MOS3bulkCapFactor * capfact; + capfact = 1/(1+model->MOS3bulkJctSideGradingCoeff* + (4e-4*(model->MOS3tnom-REFTEMP)-gmaold)); + here->MOS3tCjsw = model->MOS3sideWallCapFactor * capfact; + here->MOS3tBulkPot = fact2 * pbo+pbfact; + gmanew = (here->MOS3tBulkPot-pbo)/pbo; + capfact = (1+model->MOS3bulkJctBotGradingCoeff* + (4e-4*(here->MOS3temp-REFTEMP)-gmanew)); + here->MOS3tCbd *= capfact; + here->MOS3tCbs *= capfact; + here->MOS3tCj *= capfact; + capfact = (1+model->MOS3bulkJctSideGradingCoeff* + (4e-4*(here->MOS3temp-REFTEMP)-gmanew)); + here->MOS3tCjsw *= capfact; + here->MOS3tDepCap = model->MOS3fwdCapDepCoeff * here->MOS3tBulkPot; + + if( (model->MOS3jctSatCurDensity == 0) || + (here->MOS3drainArea == 0) || + (here->MOS3sourceArea == 0) ) { + here->MOS3sourceVcrit = here->MOS3drainVcrit = + vt*log(vt/(CONSTroot2*model->MOS3jctSatCur)); + } else { + here->MOS3drainVcrit = + vt * log( vt / (CONSTroot2 * + model->MOS3jctSatCurDensity * here->MOS3drainArea)); + here->MOS3sourceVcrit = + vt * log( vt / (CONSTroot2 * + model->MOS3jctSatCurDensity * here->MOS3sourceArea)); + } + if(model->MOS3capBDGiven) { + czbd = here->MOS3tCbd; + } else { + if(model->MOS3bulkCapFactorGiven) { + czbd=here->MOS3tCj*here->MOS3drainArea; + } else { + czbd=0; + } + } + if(model->MOS3sideWallCapFactorGiven) { + czbdsw= here->MOS3tCjsw * here->MOS3drainPerimiter; + } else { + czbdsw=0; + } + arg = 1-model->MOS3fwdCapDepCoeff; + sarg = exp( (-model->MOS3bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS3bulkJctSideGradingCoeff) * log(arg) ); + here->MOS3Cbd = czbd; + here->MOS3Cbdsw = czbdsw; + here->MOS3f2d = czbd*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctBotGradingCoeff))* sarg/arg + + czbdsw*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS3f3d = czbd * model->MOS3bulkJctBotGradingCoeff * sarg/arg/ + model->MOS3bulkJctPotential + + czbdsw * model->MOS3bulkJctSideGradingCoeff * sargsw/arg / + model->MOS3bulkJctPotential; + here->MOS3f4d = czbd*model->MOS3bulkJctPotential*(1-arg*sarg)/ + (1-model->MOS3bulkJctBotGradingCoeff) + + czbdsw*model->MOS3bulkJctPotential*(1-arg*sargsw)/ + (1-model->MOS3bulkJctSideGradingCoeff) + -here->MOS3f3d/2* + (here->MOS3tDepCap*here->MOS3tDepCap) + -here->MOS3tDepCap * here->MOS3f2d; + if(model->MOS3capBSGiven) { + czbs=here->MOS3tCbs; + } else { + if(model->MOS3bulkCapFactorGiven) { + czbs=here->MOS3tCj*here->MOS3sourceArea; + } else { + czbs=0; + } + } + if(model->MOS3sideWallCapFactorGiven) { + czbssw = here->MOS3tCjsw * here->MOS3sourcePerimiter; + } else { + czbssw=0; + } + arg = 1-model->MOS3fwdCapDepCoeff; + sarg = exp( (-model->MOS3bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS3bulkJctSideGradingCoeff) * log(arg) ); + here->MOS3Cbs = czbs; + here->MOS3Cbssw = czbssw; + here->MOS3f2s = czbs*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctBotGradingCoeff))* sarg/arg + + czbssw*(1-model->MOS3fwdCapDepCoeff* + (1+model->MOS3bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS3f3s = czbs * model->MOS3bulkJctBotGradingCoeff * sarg/arg/ + model->MOS3bulkJctPotential + + czbssw * model->MOS3bulkJctSideGradingCoeff * sargsw/arg / + model->MOS3bulkJctPotential; + here->MOS3f4s = czbs*model->MOS3bulkJctPotential*(1-arg*sarg)/ + (1-model->MOS3bulkJctBotGradingCoeff) + + czbssw*model->MOS3bulkJctPotential*(1-arg*sargsw)/ + (1-model->MOS3bulkJctSideGradingCoeff) + -here->MOS3f3s/2* + (here->MOS3tBulkPot*here->MOS3tBulkPot) + -here->MOS3tBulkPot * here->MOS3f2s; + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos3/mos3trun.c b/src/spicelib/devices/mos3/mos3trun.c new file mode 100644 index 000000000..5fa7c21c5 --- /dev/null +++ b/src/spicelib/devices/mos3/mos3trun.c @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos3defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS3trunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register MOS3model *model = (MOS3model *)inModel; + register MOS3instance *here; + + for( ; model != NULL; model = model->MOS3nextModel) { + for(here=model->MOS3instances;here!=NULL;here = here->MOS3nextInstance){ + if (here->MOS3owner != ARCHme) continue; + + CKTterr(here->MOS3qgs,ckt,timeStep); + CKTterr(here->MOS3qgd,ckt,timeStep); + CKTterr(here->MOS3qgb,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/ChangeLog b/src/spicelib/devices/mos6/ChangeLog new file mode 100644 index 000000000..f5b99d3c2 --- /dev/null +++ b/src/spicelib/devices/mos6/ChangeLog @@ -0,0 +1,3 @@ +1999-08-20 Paolo Nenzi + * mos6itf.h: added patch to the interface code. The patch was + downloaded from ftp://ftp.mpce.mq.edu.au/pub/elec/spice/patches diff --git a/src/spicelib/devices/mos6/Makefile.am b/src/spicelib/devices/mos6/Makefile.am new file mode 100644 index 000000000..8d59aa0df --- /dev/null +++ b/src/spicelib/devices/mos6/Makefile.am @@ -0,0 +1,25 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libmos6.la + +libmos6_la_SOURCES = \ + mos6.c \ + mos6ask.c \ + mos6conv.c \ + mos6defs.h \ + mos6dest.c \ + mos6ext.h \ + mos6ic.c \ + mos6itf.h \ + mos6load.c \ + mos6mask.c \ + mos6mpar.c \ + mos6par.c \ + mos6set.c \ + mos6temp.c \ + mos6trun.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/mos6/mos6.c b/src/spicelib/devices/mos6/mos6.c new file mode 100644 index 000000000..290fb22a4 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6.c @@ -0,0 +1,168 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "mos6defs.h" +#include "suffix.h" + +IFparm MOS6pTable[] = { /* parameters */ + IOPU("l", MOS6_L, IF_REAL , "Length"), + IOPU("w", MOS6_W, IF_REAL , "Width"), + IOPU("ad", MOS6_AD, IF_REAL , "Drain area"), + IOPU("as", MOS6_AS, IF_REAL , "Source area"), + IOPU("pd", MOS6_PD, IF_REAL , "Drain perimeter"), + IOPU("ps", MOS6_PS, IF_REAL , "Source perimeter"), + OP( "id", MOS6_CD, IF_REAL, "Drain current"), + OPR( "cd", MOS6_CD, IF_REAL, "Drain current"), + OP( "is", MOS6_CS, IF_REAL, "Source current"), + OP( "ig", MOS6_CG, IF_REAL, "Gate current "), + OP( "ib", MOS6_CB, IF_REAL, "Bulk current "), + OP( "ibs", MOS6_CBS, IF_REAL, "B-S junction capacitance"), + OP( "ibd", MOS6_CBD, IF_REAL, "B-D junction capacitance"), + OP( "vgs", MOS6_VGS, IF_REAL, "Gate-Source voltage"), + OP( "vds", MOS6_VDS, IF_REAL, "Drain-Source voltage"), + OP( "vbs", MOS6_VBS, IF_REAL, "Bulk-Source voltage"), + OPU( "vbd", MOS6_VBD, IF_REAL, "Bulk-Drain voltage"), + IOPU("nrd", MOS6_NRD, IF_REAL , "Drain squares"), + IOPU("nrs", MOS6_NRS, IF_REAL , "Source squares"), + IP("off", MOS6_OFF, IF_FLAG , "Device initially off"), + IOPAU("icvds", MOS6_IC_VDS, IF_REAL , "Initial D-S voltage"), + IOPAU("icvgs", MOS6_IC_VGS, IF_REAL , "Initial G-S voltage"), + IOPAU("icvbs", MOS6_IC_VBS, IF_REAL , "Initial B-S voltage"), + IOPU("temp", MOS6_TEMP, IF_REAL, "Instance temperature"), + IP( "ic", MOS6_IC, IF_REALVEC, "Vector of D-S, G-S, B-S voltages"), + IP( "sens_l", MOS6_L_SENS, IF_FLAG, "flag to request sensitivity WRT length"), + IP( "sens_w", MOS6_W_SENS, IF_FLAG, "flag to request sensitivity WRT width"), + +/* + OP( "cgs", MOS6_CGS, IF_REAL , "Gate-Source capacitance"), + OP( "cgd", MOS6_CGD, IF_REAL , "Gate-Drain capacitance"), +*/ + + OPU( "dnode", MOS6_DNODE, IF_INTEGER, "Number of the drain node "), + OPU( "gnode", MOS6_GNODE, IF_INTEGER, "Number of the gate node "), + OPU( "snode", MOS6_SNODE, IF_INTEGER, "Number of the source node "), + OPU( "bnode", MOS6_BNODE, IF_INTEGER, "Number of the node "), + OPU( "dnodeprime", MOS6_DNODEPRIME, IF_INTEGER, "Number of int. drain node"), + OPU( "snodeprime", MOS6_SNODEPRIME, IF_INTEGER, "Number of int. source node "), + OP( "rs", MOS6_SOURCERESIST, IF_REAL, "Source resistance"), + OPU("sourceconductance", MOS6_SOURCECONDUCT, IF_REAL, "Source conductance"), + OP( "rd", MOS6_DRAINRESIST, IF_REAL, "Drain resistance"), + OPU( "drainconductance", MOS6_DRAINCONDUCT, IF_REAL, "Drain conductance"), + OP( "von", MOS6_VON, IF_REAL, "Turn-on voltage"), + OP( "vdsat", MOS6_VDSAT, IF_REAL, "Saturation drain voltage"), + OPU( "sourcevcrit", MOS6_SOURCEVCRIT,IF_REAL, "Critical source voltage"), + OPU( "drainvcrit", MOS6_DRAINVCRIT, IF_REAL, "Critical drain voltage"), + + OP( "gmbs", MOS6_GMBS, IF_REAL, "Bulk-Source transconductance"), + OP( "gm", MOS6_GM, IF_REAL, "Transconductance"), + OP( "gds", MOS6_GDS, IF_REAL, "Drain-Source conductance"), + OP( "gbd", MOS6_GBD, IF_REAL, "Bulk-Drain conductance"), + OP( "gbs", MOS6_GBS, IF_REAL, "Bulk-Source conductance"), + + OP( "cgs", MOS6_CAPGS, IF_REAL, "Gate-Source capacitance"), + OP( "cgd", MOS6_CAPGD, IF_REAL, "Gate-Drain capacitance"), + OP( "cgb", MOS6_CAPGB, IF_REAL, "Gate-Bulk capacitance"), + OP( "cbd", MOS6_CAPBD, IF_REAL, "Bulk-Drain capacitance"), + OP( "cbs", MOS6_CAPBS, IF_REAL, "Bulk-Source capacitance"), + + OP( "cbd0", MOS6_CAPZEROBIASBD, IF_REAL, "Zero-Bias B-D junction capacitance"), + OP( "cbdsw0", MOS6_CAPZEROBIASBDSW, IF_REAL, " "), + OP( "cbs0", MOS6_CAPZEROBIASBS, IF_REAL, "Zero-Bias B-S junction capacitance"), + OP( "cbssw0", MOS6_CAPZEROBIASBSSW, IF_REAL, " "), + + OPU( "cqgs",MOS6_CQGS,IF_REAL,"Capacitance due to gate-source charge storage"), + OPU( "cqgd",MOS6_CQGD,IF_REAL,"Capacitance due to gate-drain charge storage"), + OPU( "cqgb",MOS6_CQGB,IF_REAL,"Capacitance due to gate-bulk charge storage"), + OPU( "cqbd",MOS6_CQBD,IF_REAL,"Capacitance due to bulk-drain charge storage"), + OPU( "cqbs",MOS6_CQBS,IF_REAL,"Capacitance due to bulk-source charge storage"), + OPU( "qgs", MOS6_QGS, IF_REAL, "Gate-Source charge storage"), + OPU( "qgd", MOS6_QGD, IF_REAL, "Gate-Drain charge storage"), + OPU( "qgb", MOS6_QGB, IF_REAL, "Gate-Bulk charge storage"), + OPU( "qbd", MOS6_QBD, IF_REAL, "Bulk-Drain charge storage"), + OPU( "qbs", MOS6_QBS, IF_REAL, "Bulk-Source charge storage"), + OPU( "p", MOS6_POWER, IF_REAL, "Instaneous power"), + OPU( "sens_l_dc", MOS6_L_SENS_DC, IF_REAL, "dc sensitivity wrt length"), + OPU( "sens_l_real", MOS6_L_SENS_REAL,IF_REAL, + "real part of ac sensitivity wrt length"), + OPU( "sens_l_imag", MOS6_L_SENS_IMAG,IF_REAL, + "imag part of ac sensitivity wrt length"), + OPU( "sens_l_mag", MOS6_L_SENS_MAG, IF_REAL, + "sensitivity wrt l of ac magnitude"), + OPU( "sens_l_ph", MOS6_L_SENS_PH, IF_REAL, + "sensitivity wrt l of ac phase"), + OPU( "sens_l_cplx", MOS6_L_SENS_CPLX,IF_COMPLEX, "ac sensitivity wrt length"), + OPU( "sens_w_dc", MOS6_W_SENS_DC, IF_REAL, "dc sensitivity wrt width"), + OPU( "sens_w_real", MOS6_W_SENS_REAL,IF_REAL, + "real part of ac sensitivity wrt width"), + OPU( "sens_w_imag", MOS6_W_SENS_IMAG,IF_REAL, + "imag part of ac sensitivity wrt width"), + OPU( "sens_w_mag", MOS6_W_SENS_MAG, IF_REAL, + "sensitivity wrt w of ac magnitude"), + OPU( "sens_w_ph", MOS6_W_SENS_PH, IF_REAL, + "sensitivity wrt w of ac phase"), + OPU( "sens_w_cplx", MOS6_W_SENS_CPLX,IF_COMPLEX, "ac sensitivity wrt width") +}; + +IFparm MOS6mPTable[] = { /* model parameters */ + OP("type", MOS6_MOD_TYPE, IF_STRING ,"N-channel or P-channel MOS"), + IOP("vto", MOS6_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOPR("vt0", MOS6_MOD_VTO, IF_REAL ,"Threshold voltage"), + IOP("kv", MOS6_MOD_KV, IF_REAL ,"Saturation voltage factor"), + IOP("nv", MOS6_MOD_NV, IF_REAL ,"Saturation voltage coeff."), + IOP("kc", MOS6_MOD_KC, IF_REAL ,"Saturation current factor"), + IOP("nc", MOS6_MOD_NC, IF_REAL ,"Saturation current coeff."), + IOP("nvth", MOS6_MOD_NVTH, IF_REAL ,"Threshold voltage coeff."), + IOP("ps", MOS6_MOD_PS, IF_REAL ,"Sat. current modification par."), + IOP("gamma", MOS6_MOD_GAMMA, IF_REAL ,"Bulk threshold parameter"), + IOP("gamma1",MOS6_MOD_GAMMA1,IF_REAL ,"Bulk threshold parameter 1"), + IOP("sigma", MOS6_MOD_SIGMA, IF_REAL ,"Static feedback effect par."), + IOP("phi", MOS6_MOD_PHI, IF_REAL ,"Surface potential"), + IOP("lambda",MOS6_MOD_LAMBDA,IF_REAL ,"Channel length modulation param."), + IOP("lambda0",MOS6_MOD_LAMDA0,IF_REAL ,"Channel length modulation param. 0"), + IOP("lambda1",MOS6_MOD_LAMDA1,IF_REAL ,"Channel length modulation param. 1"), + IOP("rd", MOS6_MOD_RD, IF_REAL ,"Drain ohmic resistance"), + IOP("rs", MOS6_MOD_RS, IF_REAL ,"Source ohmic resistance"), + IOPA("cbd", MOS6_MOD_CBD, IF_REAL ,"B-D junction capacitance"), + IOPA("cbs", MOS6_MOD_CBS, IF_REAL ,"B-S junction capacitance"), + IOP("is", MOS6_MOD_IS, IF_REAL ,"Bulk junction sat. current"), + IOP("pb", MOS6_MOD_PB, IF_REAL ,"Bulk junction potential"), + IOPA("cgso", MOS6_MOD_CGSO, IF_REAL ,"Gate-source overlap cap."), + IOPA("cgdo", MOS6_MOD_CGDO, IF_REAL ,"Gate-drain overlap cap."), + IOPA("cgbo", MOS6_MOD_CGBO, IF_REAL ,"Gate-bulk overlap cap."), + IOP("rsh", MOS6_MOD_RSH, IF_REAL ,"Sheet resistance"), + IOPA("cj", MOS6_MOD_CJ, IF_REAL ,"Bottom junction cap per area"), + IOP("mj", MOS6_MOD_MJ, IF_REAL ,"Bottom grading coefficient"), + IOPA("cjsw", MOS6_MOD_CJSW, IF_REAL ,"Side junction cap per area"), + IOP("mjsw", MOS6_MOD_MJSW, IF_REAL ,"Side grading coefficient"), + IOP("js", MOS6_MOD_JS, IF_REAL ,"Bulk jct. sat. current density"), + IOP("ld", MOS6_MOD_LD, IF_REAL ,"Lateral diffusion"), + IOP("tox", MOS6_MOD_TOX, IF_REAL ,"Oxide thickness"), + IOP("u0", MOS6_MOD_U0, IF_REAL ,"Surface mobility"), + IOPR("uo", MOS6_MOD_U0, IF_REAL ,"Surface mobility"), + IOP("fc", MOS6_MOD_FC, IF_REAL ,"Forward bias jct. fit parm."), + IP("nmos", MOS6_MOD_NMOS, IF_FLAG ,"N type MOSfet model"), + IP("pmos", MOS6_MOD_PMOS, IF_FLAG ,"P type MOSfet model"), + IOP("tpg", MOS6_MOD_TPG, IF_INTEGER,"Gate type"), + IOP("nsub", MOS6_MOD_NSUB, IF_REAL ,"Substrate doping"), + IOP("nss", MOS6_MOD_NSS, IF_REAL ,"Surface state density"), + IOP("tnom", MOS6_MOD_TNOM, IF_REAL ,"Parameter measurement temperature") +}; + +char *MOS6names[] = { + "Drain", + "Gate", + "Source", + "Bulk" +}; + +int MOS6nSize = NUMELEMS(MOS6names); +int MOS6pTSize = NUMELEMS(MOS6pTable); +int MOS6mPTSize = NUMELEMS(MOS6mPTable); +int MOS6iSize = sizeof(MOS6instance); +int MOS6mSize = sizeof(MOS6model); diff --git a/src/spicelib/devices/mos6/mos6ask.c b/src/spicelib/devices/mos6/mos6ask.c new file mode 100644 index 000000000..e9d465c18 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6ask.c @@ -0,0 +1,418 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "devdefs.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +MOS6ask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + MOS6instance *here = (MOS6instance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case MOS6_TEMP: + value->rValue = here->MOS6temp-CONSTCtoK; + return(OK); + case MOS6_CGS: + value->rValue = *(ckt->CKTstate0 + here->MOS6capgs); + return(OK); + case MOS6_CGD: + value->rValue = *(ckt->CKTstate0 + here->MOS6capgd); + return(OK); + case MOS6_L: + value->rValue = here->MOS6l; + return(OK); + case MOS6_W: + value->rValue = here->MOS6w; + return(OK); + case MOS6_AS: + value->rValue = here->MOS6sourceArea; + return(OK); + case MOS6_AD: + value->rValue = here->MOS6drainArea; + return(OK); + case MOS6_PS: + value->rValue = here->MOS6sourcePerimiter; + return(OK); + case MOS6_PD: + value->rValue = here->MOS6drainPerimiter; + return(OK); + case MOS6_NRS: + value->rValue = here->MOS6sourceSquares; + return(OK); + case MOS6_NRD: + value->rValue = here->MOS6drainSquares; + return(OK); + case MOS6_OFF: + value->rValue = here->MOS6off; + return(OK); + case MOS6_IC_VBS: + value->rValue = here->MOS6icVBS; + return(OK); + case MOS6_IC_VDS: + value->rValue = here->MOS6icVDS; + return(OK); + case MOS6_IC_VGS: + value->rValue = here->MOS6icVGS; + return(OK); + case MOS6_DNODE: + value->iValue = here->MOS6dNode; + return(OK); + case MOS6_GNODE: + value->iValue = here->MOS6gNode; + return(OK); + case MOS6_SNODE: + value->iValue = here->MOS6sNode; + return(OK); + case MOS6_BNODE: + value->iValue = here->MOS6bNode; + return(OK); + case MOS6_DNODEPRIME: + value->iValue = here->MOS6dNodePrime; + return(OK); + case MOS6_SNODEPRIME: + value->iValue = here->MOS6sNodePrime; + return(OK); + case MOS6_SOURCECONDUCT: + value->rValue = here->MOS6sourceConductance; + return(OK); + case MOS6_DRAINCONDUCT: + value->rValue = here->MOS6drainConductance; + return(OK); + case MOS6_SOURCERESIST: + if (here->MOS6sNodePrime != here->MOS6sNode) + value->rValue = 1.0 / here->MOS6sourceConductance; + else + value->rValue = 0.0; + return(OK); + case MOS6_DRAINRESIST: + if (here->MOS6dNodePrime != here->MOS6dNode) + value->rValue = 1.0 / here->MOS6drainConductance; + else + value->rValue = 0.0; + return(OK); + case MOS6_VON: + value->rValue = here->MOS6von; + return(OK); + case MOS6_VDSAT: + value->rValue = here->MOS6vdsat; + return(OK); + case MOS6_SOURCEVCRIT: + value->rValue = here->MOS6sourceVcrit; + return(OK); + case MOS6_DRAINVCRIT: + value->rValue = here->MOS6drainVcrit; + return(OK); + case MOS6_CD: + value->rValue = here->MOS6cd; + return(OK); + case MOS6_CBS: + value->rValue = here->MOS6cbs; + return(OK); + case MOS6_CBD: + value->rValue = here->MOS6cbd; + return(OK); + case MOS6_GMBS: + value->rValue = here->MOS6gmbs; + return(OK); + case MOS6_GM: + value->rValue = here->MOS6gm; + return(OK); + case MOS6_GDS: + value->rValue = here->MOS6gds; + return(OK); + case MOS6_GBD: + value->rValue = here->MOS6gbd; + return(OK); + case MOS6_GBS: + value->rValue = here->MOS6gbs; + return(OK); + case MOS6_CAPBD: + value->rValue = here->MOS6capbd; + return(OK); + case MOS6_CAPBS: + value->rValue = here->MOS6capbs; + return(OK); + case MOS6_CAPZEROBIASBD: + value->rValue = here->MOS6Cbd; + return(OK); + case MOS6_CAPZEROBIASBDSW: + value->rValue = here->MOS6Cbdsw; + return(OK); + case MOS6_CAPZEROBIASBS: + value->rValue = here->MOS6Cbs; + return(OK); + case MOS6_CAPZEROBIASBSSW: + value->rValue = here->MOS6Cbssw; + return(OK); + case MOS6_VBD: + value->rValue = *(ckt->CKTstate0 + here->MOS6vbd); + return(OK); + case MOS6_VBS: + value->rValue = *(ckt->CKTstate0 + here->MOS6vbs); + return(OK); + case MOS6_VGS: + value->rValue = *(ckt->CKTstate0 + here->MOS6vgs); + return(OK); + case MOS6_VDS: + value->rValue = *(ckt->CKTstate0 + here->MOS6vds); + return(OK); + case MOS6_CAPGS: + value->rValue = *(ckt->CKTstate0 + here->MOS6capgs); + return(OK); + case MOS6_QGS: + value->rValue = *(ckt->CKTstate0 + here->MOS6qgs); + return(OK); + case MOS6_CQGS: + value->rValue = *(ckt->CKTstate0 + here->MOS6cqgs); + return(OK); + case MOS6_CAPGD: + value->rValue = *(ckt->CKTstate0 + here->MOS6capgd); + return(OK); + case MOS6_QGD: + value->rValue = *(ckt->CKTstate0 + here->MOS6qgd); + return(OK); + case MOS6_CQGD: + value->rValue = *(ckt->CKTstate0 + here->MOS6cqgd); + return(OK); + case MOS6_CAPGB: + value->rValue = *(ckt->CKTstate0 + here->MOS6capgb); + return(OK); + case MOS6_QGB: + value->rValue = *(ckt->CKTstate0 + here->MOS6qgb); + return(OK); + case MOS6_CQGB: + value->rValue = *(ckt->CKTstate0 + here->MOS6cqgb); + return(OK); + case MOS6_QBD: + value->rValue = *(ckt->CKTstate0 + here->MOS6qbd); + return(OK); + case MOS6_CQBD: + value->rValue = *(ckt->CKTstate0 + here->MOS6cqbd); + return(OK); + case MOS6_QBS: + value->rValue = *(ckt->CKTstate0 + here->MOS6qbs); + return(OK); + case MOS6_CQBS: + value->rValue = *(ckt->CKTstate0 + here->MOS6cqbs); + return(OK); + case MOS6_L_SENS_DC: + if(ckt->CKTsenInfo && here->MOS6sens_l){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS6senParmNo); + } + return(OK); + case MOS6_L_SENS_REAL: + if(ckt->CKTsenInfo && here->MOS6sens_l){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo); + } + return(OK); + case MOS6_L_SENS_IMAG: + if(ckt->CKTsenInfo && here->MOS6sens_l){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo); + } + return(OK); + case MOS6_L_SENS_MAG: + if(ckt->CKTsenInfo && here->MOS6sens_l){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS6_L_SENS_PH: + if(ckt->CKTsenInfo && here->MOS6sens_l){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS6_L_SENS_CPLX: + if(ckt->CKTsenInfo && here->MOS6sens_l){ + value->cValue.real= *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo); + value->cValue.imag= *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo); + } + return(OK); + case MOS6_W_SENS_DC: + if(ckt->CKTsenInfo && here->MOS6sens_w){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + } + return(OK); + case MOS6_W_SENS_REAL: + if(ckt->CKTsenInfo && here->MOS6sens_w){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + } + return(OK); + case MOS6_W_SENS_IMAG: + if(ckt->CKTsenInfo && here->MOS6sens_w){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + } + return(OK); + case MOS6_W_SENS_MAG: + if(ckt->CKTsenInfo && here->MOS6sens_w){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case MOS6_W_SENS_PH: + if(ckt->CKTsenInfo && here->MOS6sens_w){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case MOS6_W_SENS_CPLX: + if(ckt->CKTsenInfo && here->MOS6sens_w){ + value->cValue.real= *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + value->cValue.imag= *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->MOS6senParmNo + here->MOS6sens_l); + } + return(OK); + case MOS6_CB : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS6ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = here->MOS6cbd + here->MOS6cbs - *(ckt->CKTstate0 + + here->MOS6cqgb); + } + return(OK); + case MOS6_CG : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS6ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else if (ckt->CKTcurrentAnalysis & (DOING_DCOP | DOING_TRCV)) { + value->rValue = 0; + } else if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + (ckt->CKTmode & MODETRANOP)) { + value->rValue = 0; + } else { + value->rValue = *(ckt->CKTstate0 + here->MOS6cqgb) + + *(ckt->CKTstate0 + here->MOS6cqgd) + *(ckt->CKTstate0 + + here->MOS6cqgs); + } + return(OK); + case MOS6_CS : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS6ask.c"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = -here->MOS6cd; + value->rValue -= here->MOS6cbd + here->MOS6cbs - + *(ckt->CKTstate0 + here->MOS6cqgb); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue -= *(ckt->CKTstate0 + here->MOS6cqgb) + + *(ckt->CKTstate0 + here->MOS6cqgd) + + *(ckt->CKTstate0 + here->MOS6cqgs); + } + } + return(OK); + case MOS6_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "MOS6ask.c"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + double temp; + + value->rValue = here->MOS6cd * + *(ckt->CKTrhsOld + here->MOS6dNode); + value->rValue += (here->MOS6cbd + here->MOS6cbs - + *(ckt->CKTstate0 + here->MOS6cqgb)) * + *(ckt->CKTrhsOld + here->MOS6bNode); + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + value->rValue += (*(ckt->CKTstate0 + here->MOS6cqgb) + + *(ckt->CKTstate0 + here->MOS6cqgd) + + *(ckt->CKTstate0 + here->MOS6cqgs)) * + *(ckt->CKTrhsOld + here->MOS6gNode); + } + temp = -here->MOS6cd; + temp -= here->MOS6cbd + here->MOS6cbs ; + if ((ckt->CKTcurrentAnalysis & DOING_TRAN) && + !(ckt->CKTmode & MODETRANOP)) { + temp -= *(ckt->CKTstate0 + here->MOS6cqgb) + + *(ckt->CKTstate0 + here->MOS6cqgd) + + *(ckt->CKTstate0 + here->MOS6cqgs); + } + value->rValue += temp * *(ckt->CKTrhsOld + here->MOS6sNode); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} + diff --git a/src/spicelib/devices/mos6/mos6conv.c b/src/spicelib/devices/mos6/mos6conv.c new file mode 100644 index 000000000..5fa60bb52 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6conv.c @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS6convTest(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS6model *model = (MOS6model*)inModel; + register MOS6instance *here; + double delvbs; + double delvbd; + double delvgs; + double delvds; + double delvgd; + double cbhat; + double cdhat; + double vbs; + double vbd; + double vgs; + double vds; + double vgd; + double vgdo; + double tol; + + for( ; model != NULL; model = model->MOS6nextModel) { + for(here = model->MOS6instances; here!= NULL; + here = here->MOS6nextInstance) { + if (here->MOS6owner != ARCHme) continue; + + vbs = model->MOS6type * ( + *(ckt->CKTrhs+here->MOS6bNode) - + *(ckt->CKTrhs+here->MOS6sNodePrime)); + vgs = model->MOS6type * ( + *(ckt->CKTrhs+here->MOS6gNode) - + *(ckt->CKTrhs+here->MOS6sNodePrime)); + vds = model->MOS6type * ( + *(ckt->CKTrhs+here->MOS6dNodePrime) - + *(ckt->CKTrhs+here->MOS6sNodePrime)); + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS6vgs) - + *(ckt->CKTstate0 + here->MOS6vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS6vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS6vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS6vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS6vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS6mode >= 0) { + cdhat= + here->MOS6cd- + here->MOS6gbd * delvbd + + here->MOS6gmbs * delvbs + + here->MOS6gm * delvgs + + here->MOS6gds * delvds ; + } else { + cdhat= + here->MOS6cd - + ( here->MOS6gbd - + here->MOS6gmbs) * delvbd - + here->MOS6gm * delvgd + + here->MOS6gds * delvds ; + } + cbhat= + here->MOS6cbs + + here->MOS6cbd + + here->MOS6gbd * delvbd + + here->MOS6gbs * delvbs ; + /* + * check convergence + */ + tol=ckt->CKTreltol*MAX(fabs(cdhat),fabs(here->MOS6cd))+ + ckt->CKTabstol; + if (fabs(cdhat-here->MOS6cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged */ + } else { + tol=ckt->CKTreltol* + MAX(fabs(cbhat),fabs(here->MOS6cbs+here->MOS6cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS6cbs+here->MOS6cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + return(OK); /* no reason to continue, we haven't converged*/ + } + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/mos6defs.h b/src/spicelib/devices/mos6/mos6defs.h new file mode 100644 index 000000000..23dec0528 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6defs.h @@ -0,0 +1,465 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef MOS6 +#define MOS6 + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + +/* declarations for level 5 MOSFETs */ + +/* information needed for each instance */ + +typedef struct sMOS6instance { + struct sMOS6model *sMOS6modPtr; /* backpointer to model */ + struct sMOS6instance *MOS6nextInstance; /* pointer to next instance of + *current model*/ + IFuid MOS6name; /* pointer to character string naming this instance */ + int MOS6owner; /* number of owner process */ + int MOS6states; /* index into state table for this device */ + int MOS6dNode; /* number of the gate node of the mosfet */ + int MOS6gNode; /* number of the gate node of the mosfet */ + int MOS6sNode; /* number of the source node of the mosfet */ + int MOS6bNode; /* number of the bulk node of the mosfet */ + int MOS6dNodePrime; /* number of the internal drain node of the mosfet */ + int MOS6sNodePrime; /* number of the internal source node of the mosfet */ + + double MOS6l; /* the length of the channel region */ + double MOS6w; /* the width of the channel region */ + double MOS6drainArea; /* the area of the drain diffusion */ + double MOS6sourceArea; /* the area of the source diffusion */ + double MOS6drainSquares; /* the length of the drain in squares */ + double MOS6sourceSquares; /* the length of the source in squares */ + double MOS6drainPerimiter; + double MOS6sourcePerimiter; + double MOS6sourceConductance; /*conductance of source(or 0):set in setup*/ + double MOS6drainConductance; /*conductance of drain(or 0):set in setup*/ + double MOS6temp; /* operating temperature of this instance */ + + double MOS6tKv; /* temperature corrected drain linear cond. factor*/ + double MOS6tKc; /* temperature corrected saturation cur. factor*/ + double MOS6tSurfMob; /* temperature corrected surface mobility */ + double MOS6tPhi; /* temperature corrected Phi */ + double MOS6tVto; /* temperature corrected Vto */ + double MOS6tSatCur; /* temperature corrected saturation Cur. */ + double MOS6tSatCurDens; /* temperature corrected saturation Cur. density*/ + double MOS6tCbd; /* temperature corrected B-D Capacitance */ + double MOS6tCbs; /* temperature corrected B-S Capacitance */ + double MOS6tCj; /* temperature corrected Bulk bottom Capacitance */ + double MOS6tCjsw; /* temperature corrected Bulk side Capacitance */ + double MOS6tBulkPot; /* temperature corrected Bulk potential */ + double MOS6tDepCap; /* temperature adjusted transition point in */ + /* the cureve matching Fc * Vj */ + double MOS6tVbi; /* temperature adjusted Vbi */ + + double MOS6icVBS; /* initial condition B-S voltage */ + double MOS6icVDS; /* initial condition D-S voltage */ + double MOS6icVGS; /* initial condition G-S voltage */ + double MOS6von; + double MOS6vdsat; + double MOS6sourceVcrit; /* Vcrit for pos. vds */ + double MOS6drainVcrit; /* Vcrit for pos. vds */ + double MOS6cd; + double MOS6cbs; + double MOS6cbd; + double MOS6gmbs; + double MOS6gm; + double MOS6gds; + double MOS6gbd; + double MOS6gbs; + double MOS6capbd; + double MOS6capbs; + double MOS6Cbd; + double MOS6Cbdsw; + double MOS6Cbs; + double MOS6Cbssw; + double MOS6f2d; + double MOS6f3d; + double MOS6f4d; + double MOS6f2s; + double MOS6f3s; + double MOS6f4s; + int MOS6mode; /* device mode : 1 = normal, -1 = inverse */ + + + unsigned MOS6off:1; /* non-zero to indicate device is off for dc analysis*/ + unsigned MOS6tempGiven :1; /* instance temperature specified */ + unsigned MOS6lGiven :1; + unsigned MOS6wGiven :1; + unsigned MOS6drainAreaGiven :1; + unsigned MOS6sourceAreaGiven :1; + unsigned MOS6drainSquaresGiven :1; + unsigned MOS6sourceSquaresGiven :1; + unsigned MOS6drainPerimiterGiven :1; + unsigned MOS6sourcePerimiterGiven :1; + unsigned MOS6dNodePrimeSet :1; + unsigned MOS6sNodePrimeSet :1; + unsigned MOS6icVBSGiven :1; + unsigned MOS6icVDSGiven :1; + unsigned MOS6icVGSGiven :1; + unsigned MOS6vonGiven :1; + unsigned MOS6vdsatGiven :1; + unsigned MOS6modeGiven :1; + + + double *MOS6DdPtr; /* pointer to sparse matrix element at + * (Drain node,drain node) */ + double *MOS6GgPtr; /* pointer to sparse matrix element at + * (gate node,gate node) */ + double *MOS6SsPtr; /* pointer to sparse matrix element at + * (source node,source node) */ + double *MOS6BbPtr; /* pointer to sparse matrix element at + * (bulk node,bulk node) */ + double *MOS6DPdpPtr; /* pointer to sparse matrix element at + * (drain prime node,drain prime node) */ + double *MOS6SPspPtr; /* pointer to sparse matrix element at + * (source prime node,source prime node) */ + double *MOS6DdpPtr; /* pointer to sparse matrix element at + * (drain node,drain prime node) */ + double *MOS6GbPtr; /* pointer to sparse matrix element at + * (gate node,bulk node) */ + double *MOS6GdpPtr; /* pointer to sparse matrix element at + * (gate node,drain prime node) */ + double *MOS6GspPtr; /* pointer to sparse matrix element at + * (gate node,source prime node) */ + double *MOS6SspPtr; /* pointer to sparse matrix element at + * (source node,source prime node) */ + double *MOS6BdpPtr; /* pointer to sparse matrix element at + * (bulk node,drain prime node) */ + double *MOS6BspPtr; /* pointer to sparse matrix element at + * (bulk node,source prime node) */ + double *MOS6DPspPtr; /* pointer to sparse matrix element at + * (drain prime node,source prime node) */ + double *MOS6DPdPtr; /* pointer to sparse matrix element at + * (drain prime node,drain node) */ + double *MOS6BgPtr; /* pointer to sparse matrix element at + * (bulk node,gate node) */ + double *MOS6DPgPtr; /* pointer to sparse matrix element at + * (drain prime node,gate node) */ + + double *MOS6SPgPtr; /* pointer to sparse matrix element at + * (source prime node,gate node) */ + double *MOS6SPsPtr; /* pointer to sparse matrix element at + * (source prime node,source node) */ + double *MOS6DPbPtr; /* pointer to sparse matrix element at + * (drain prime node,bulk node) */ + double *MOS6SPbPtr; /* pointer to sparse matrix element at + * (source prime node,bulk node) */ + double *MOS6SPdpPtr; /* pointer to sparse matrix element at + * (source prime node,drain prime node) */ + + int MOS6senParmNo; /* parameter # for sensitivity use; + set equal to 0 if neither length + nor width of the mosfet is a design + parameter */ + unsigned MOS6sens_l :1; /* field which indicates whether + length of the mosfet is a design + parameter or not */ + unsigned MOS6sens_w :1; /* field which indicates whether + width of the mosfet is a design + parameter or not */ + unsigned MOS6senPertFlag :1; /* indictes whether the the + parameter of the particular instance is + to be perturbed */ + double MOS6cgs; + double MOS6cgd; + double MOS6cgb; + double *MOS6sens; + +#define MOS6senCgs MOS6sens /* contains pertured values of cgs */ +#define MOS6senCgd MOS6sens + 6 /* contains perturbed values of cgd*/ +#define MOS6senCgb MOS6sens + 12 /* contains perturbed values of cgb*/ +#define MOS6senCbd MOS6sens + 18 /* contains perturbed values of cbd*/ +#define MOS6senCbs MOS6sens + 24 /* contains perturbed values of cbs*/ +#define MOS6senGds MOS6sens + 30 /* contains perturbed values of gds*/ +#define MOS6senGbs MOS6sens + 36 /* contains perturbed values of gbs*/ +#define MOS6senGbd MOS6sens + 42 /* contains perturbed values of gbd*/ +#define MOS6senGm MOS6sens + 48 /* contains perturbed values of gm*/ +#define MOS6senGmbs MOS6sens + 54 /* contains perturbed values of gmbs*/ +#define MOS6dphigs_dl MOS6sens + 60 +#define MOS6dphigd_dl MOS6sens + 61 +#define MOS6dphigb_dl MOS6sens + 62 +#define MOS6dphibs_dl MOS6sens + 63 +#define MOS6dphibd_dl MOS6sens + 64 +#define MOS6dphigs_dw MOS6sens + 65 +#define MOS6dphigd_dw MOS6sens + 66 +#define MOS6dphigb_dw MOS6sens + 67 +#define MOS6dphibs_dw MOS6sens + 68 +#define MOS6dphibd_dw MOS6sens + 69 + +} MOS6instance ; + +#define MOS6vbd MOS6states+ 0 /* bulk-drain voltage */ +#define MOS6vbs MOS6states+ 1 /* bulk-source voltage */ +#define MOS6vgs MOS6states+ 2 /* gate-source voltage */ +#define MOS6vds MOS6states+ 3 /* drain-source voltage */ + +#define MOS6capgs MOS6states+4 /* gate-source capacitor value */ +#define MOS6qgs MOS6states+ 5 /* gate-source capacitor charge */ +#define MOS6cqgs MOS6states+ 6 /* gate-source capacitor current */ + +#define MOS6capgd MOS6states+ 7 /* gate-drain capacitor value */ +#define MOS6qgd MOS6states+ 8 /* gate-drain capacitor charge */ +#define MOS6cqgd MOS6states+ 9 /* gate-drain capacitor current */ + +#define MOS6capgb MOS6states+10 /* gate-bulk capacitor value */ +#define MOS6qgb MOS6states+ 11 /* gate-bulk capacitor charge */ +#define MOS6cqgb MOS6states+ 12 /* gate-bulk capacitor current */ + +#define MOS6qbd MOS6states+ 13 /* bulk-drain capacitor charge */ +#define MOS6cqbd MOS6states+ 14 /* bulk-drain capacitor current */ + +#define MOS6qbs MOS6states+ 15 /* bulk-source capacitor charge */ +#define MOS6cqbs MOS6states+ 16 /* bulk-source capacitor current */ + +#define MOS6numStates 17 + +#define MOS6sensxpgs MOS6states+17 /* charge sensitivities and + their derivatives. +18 for the derivatives: + pointer to the beginning of the array */ +#define MOS6sensxpgd MOS6states+19 +#define MOS6sensxpgb MOS6states+21 +#define MOS6sensxpbs MOS6states+23 +#define MOS6sensxpbd MOS6states+25 + +#define MOS6numSenStates 10 + + +/* per model data */ + + /* NOTE: parameters marked 'input - use xxxx' are paramters for + * which a temperature correction is applied in MOS6temp, thus + * the MOS6xxxx value in the per-instance structure should be used + * instead in all calculations + */ + + +typedef struct sMOS6model { /* model structure for a resistor */ + int MOS6modType; /* type index to this device type */ + struct sMOS6model *MOS6nextModel; /* pointer to next possible model + *in linked list */ + MOS6instance * MOS6instances; /* pointer to list of instances + * that have this model */ + IFuid MOS6modName; /* pointer to character string naming this model */ + int MOS6type; /* device type : 1 = nmos, -1 = pmos */ + double MOS6tnom; /* temperature at which parameters measured */ + double MOS6latDiff; + double MOS6jctSatCurDensity; /* input - use tSatCurDens */ + double MOS6jctSatCur; /* input - use tSatCur */ + double MOS6drainResistance; + double MOS6sourceResistance; + double MOS6sheetResistance; + double MOS6kv; /* input - use tKv */ + double MOS6nv; /* drain linear conductance factor*/ + double MOS6kc; /* input - use tKc */ + double MOS6nc; /* saturation current coeff.*/ + double MOS6nvth; /* threshold voltage coeff.*/ + double MOS6ps; /* saturation current modification parameter*/ + double MOS6gateSourceOverlapCapFactor; + double MOS6gateDrainOverlapCapFactor; + double MOS6gateBulkOverlapCapFactor; + double MOS6oxideCapFactor; + double MOS6vt0; /* input - use tVto */ + double MOS6capBD; /* input - use tCbd */ + double MOS6capBS; /* input - use tCbs */ + double MOS6bulkCapFactor; /* input - use tCj */ + double MOS6sideWallCapFactor; /* input - use tCjsw */ + double MOS6bulkJctPotential; /* input - use tBulkPot */ + double MOS6bulkJctBotGradingCoeff; + double MOS6bulkJctSideGradingCoeff; + double MOS6fwdCapDepCoeff; + double MOS6phi; /* input - use tPhi */ + double MOS6gamma; + double MOS6gamma1; /* secondary back-gate effect parametr */ + double MOS6sigma; + double MOS6lambda; + double MOS6lamda0; + double MOS6lamda1; + double MOS6substrateDoping; + int MOS6gateType; + double MOS6surfaceStateDensity; + double MOS6oxideThickness; + double MOS6surfaceMobility; /* input - use tSurfMob */ + + unsigned MOS6typeGiven :1; + unsigned MOS6latDiffGiven :1; + unsigned MOS6jctSatCurDensityGiven :1; + unsigned MOS6jctSatCurGiven :1; + unsigned MOS6drainResistanceGiven :1; + unsigned MOS6sourceResistanceGiven :1; + unsigned MOS6sheetResistanceGiven :1; + unsigned MOS6kvGiven :1; + unsigned MOS6nvGiven :1; + unsigned MOS6kcGiven :1; + unsigned MOS6ncGiven :1; + unsigned MOS6nvthGiven :1; + unsigned MOS6psGiven :1; + unsigned MOS6gateSourceOverlapCapFactorGiven :1; + unsigned MOS6gateDrainOverlapCapFactorGiven :1; + unsigned MOS6gateBulkOverlapCapFactorGiven :1; + unsigned MOS6vt0Given :1; + unsigned MOS6capBDGiven :1; + unsigned MOS6capBSGiven :1; + unsigned MOS6bulkCapFactorGiven :1; + unsigned MOS6sideWallCapFactorGiven :1; + unsigned MOS6bulkJctPotentialGiven :1; + unsigned MOS6bulkJctBotGradingCoeffGiven :1; + unsigned MOS6bulkJctSideGradingCoeffGiven :1; + unsigned MOS6fwdCapDepCoeffGiven :1; + unsigned MOS6phiGiven :1; + unsigned MOS6gammaGiven :1; + unsigned MOS6gamma1Given :1; + unsigned MOS6sigmaGiven :1; + unsigned MOS6lambdaGiven :1; + unsigned MOS6lamda0Given :1; + unsigned MOS6lamda1Given :1; + unsigned MOS6substrateDopingGiven :1; + unsigned MOS6gateTypeGiven :1; + unsigned MOS6surfaceStateDensityGiven :1; + unsigned MOS6oxideThicknessGiven :1; + unsigned MOS6surfaceMobilityGiven :1; + unsigned MOS6tnomGiven :1; + +} MOS6model; + +#ifndef NMOS +#define NMOS 1 +#define PMOS -1 +#endif /*NMOS*/ + +/* device parameters */ +#define MOS6_W 1 +#define MOS6_L 2 +#define MOS6_AS 3 +#define MOS6_AD 4 +#define MOS6_PS 5 +#define MOS6_PD 6 +#define MOS6_NRS 7 +#define MOS6_NRD 8 +#define MOS6_OFF 9 +#define MOS6_IC 10 +#define MOS6_IC_VBS 11 +#define MOS6_IC_VDS 12 +#define MOS6_IC_VGS 13 +#define MOS6_W_SENS 14 +#define MOS6_L_SENS 15 +#define MOS6_CB 16 +#define MOS6_CG 17 +#define MOS6_CS 18 +#define MOS6_POWER 19 +#define MOS6_TEMP 20 + +/* model paramerers */ +#define MOS6_MOD_VTO 101 +#define MOS6_MOD_KV 102 +#define MOS6_MOD_NV 103 +#define MOS6_MOD_KC 104 +#define MOS6_MOD_NC 105 +#define MOS6_MOD_NVTH 106 +#define MOS6_MOD_PS 107 +#define MOS6_MOD_GAMMA 108 +#define MOS6_MOD_GAMMA1 109 +#define MOS6_MOD_SIGMA 110 +#define MOS6_MOD_PHI 111 +#define MOS6_MOD_LAMBDA 112 +#define MOS6_MOD_LAMDA0 113 +#define MOS6_MOD_LAMDA1 114 +#define MOS6_MOD_RD 115 +#define MOS6_MOD_RS 116 +#define MOS6_MOD_CBD 117 +#define MOS6_MOD_CBS 118 +#define MOS6_MOD_IS 119 +#define MOS6_MOD_PB 120 +#define MOS6_MOD_CGSO 121 +#define MOS6_MOD_CGDO 122 +#define MOS6_MOD_CGBO 123 +#define MOS6_MOD_CJ 124 +#define MOS6_MOD_MJ 125 +#define MOS6_MOD_CJSW 126 +#define MOS6_MOD_MJSW 127 +#define MOS6_MOD_JS 128 +#define MOS6_MOD_TOX 129 +#define MOS6_MOD_LD 130 +#define MOS6_MOD_RSH 131 +#define MOS6_MOD_U0 132 +#define MOS6_MOD_FC 133 +#define MOS6_MOD_NSUB 134 +#define MOS6_MOD_TPG 135 +#define MOS6_MOD_NSS 136 +#define MOS6_MOD_NMOS 137 +#define MOS6_MOD_PMOS 138 +#define MOS6_MOD_TNOM 139 +#define MOS6_MOD_TYPE 140 + +/* device questions */ +#define MOS6_CGS 201 +#define MOS6_CGD 202 +#define MOS6_DNODE 203 +#define MOS6_GNODE 204 +#define MOS6_SNODE 205 +#define MOS6_BNODE 206 +#define MOS6_DNODEPRIME 207 +#define MOS6_SNODEPRIME 208 +#define MOS6_SOURCECONDUCT 209 +#define MOS6_DRAINCONDUCT 210 +#define MOS6_VON 211 +#define MOS6_VDSAT 212 +#define MOS6_SOURCEVCRIT 213 +#define MOS6_DRAINVCRIT 214 +#define MOS6_CD 215 +#define MOS6_CBS 216 +#define MOS6_CBD 217 +#define MOS6_GMBS 218 +#define MOS6_GM 219 +#define MOS6_GDS 220 +#define MOS6_GBD 221 +#define MOS6_GBS 222 +#define MOS6_CAPBD 223 +#define MOS6_CAPBS 224 +#define MOS6_CAPZEROBIASBD 225 +#define MOS6_CAPZEROBIASBDSW 226 +#define MOS6_CAPZEROBIASBS 227 +#define MOS6_CAPZEROBIASBSSW 228 +#define MOS6_VBD 229 +#define MOS6_VBS 230 +#define MOS6_VGS 231 +#define MOS6_VDS 232 +#define MOS6_CAPGS 233 +#define MOS6_QGS 234 +#define MOS6_CQGS 235 +#define MOS6_CAPGD 236 +#define MOS6_QGD 237 +#define MOS6_CQGD 238 +#define MOS6_CAPGB 239 +#define MOS6_QGB 240 +#define MOS6_CQGB 241 +#define MOS6_QBD 242 +#define MOS6_CQBD 243 +#define MOS6_QBS 244 +#define MOS6_CQBS 245 +#define MOS6_L_SENS_REAL 246 +#define MOS6_L_SENS_IMAG 247 +#define MOS6_L_SENS_MAG 248 +#define MOS6_L_SENS_PH 249 +#define MOS6_L_SENS_CPLX 250 +#define MOS6_W_SENS_REAL 251 +#define MOS6_W_SENS_IMAG 252 +#define MOS6_W_SENS_MAG 253 +#define MOS6_W_SENS_PH 254 +#define MOS6_W_SENS_CPLX 255 +#define MOS6_L_SENS_DC 256 +#define MOS6_W_SENS_DC 257 +#define MOS6_SOURCERESIST 258 +#define MOS6_DRAINRESIST 259 + +/* model questions */ + +#include "mos6ext.h" + +#endif /*MOS6*/ + diff --git a/src/spicelib/devices/mos6/mos6dest.c b/src/spicelib/devices/mos6/mos6dest.c new file mode 100644 index 000000000..83f66fdc6 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6dest.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "mos6defs.h" +#include "suffix.h" + + +void +MOS6destroy(inModel) + GENmodel **inModel; +{ + MOS6model **model = (MOS6model**)inModel; + MOS6instance *here; + MOS6instance *prev = NULL; + MOS6model *mod = *model; + MOS6model *oldmod = NULL; + + for( ; mod ; mod = mod->MOS6nextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (MOS6instance *)NULL; + for(here = mod->MOS6instances ; here ; here = here->MOS6nextInstance) { + if(prev){ + if(prev->MOS6sens) FREE(prev->MOS6sens); + FREE(prev); + } + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/mos6/mos6ext.h b/src/spicelib/devices/mos6/mos6ext.h new file mode 100644 index 000000000..e37ba67f3 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6ext.h @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int MOS6acLoad(GENmodel *,CKTcircuit*); +extern int MOS6ask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int MOS6delete(GENmodel*,IFuid,GENinstance**); +extern void MOS6destroy(GENmodel**); +extern int MOS6getic(GENmodel*,CKTcircuit*); +extern int MOS6load(GENmodel*,CKTcircuit*); +extern int MOS6mAsk(CKTcircuit *,GENmodel *,int,IFvalue*); +extern int MOS6mDelete(GENmodel**,IFuid,GENmodel*); +extern int MOS6mParam(int,IFvalue*,GENmodel*); +extern int MOS6param(int,IFvalue*,GENinstance*,IFvalue*); +extern int MOS6pzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +#ifdef notdef +extern int MOS6sAcLoad(GENmodel*,CKTcircuit*); +extern int MOS6sLoad(GENmodel*,CKTcircuit*); +extern void MOS6sPrint(GENmodel*,CKTcircuit*); +extern int MOS6sSetup(SENstruct*,GENmodel*); +extern int MOS6sUpdate(GENmodel*,CKTcircuit*); +#endif +extern int MOS6setup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int MOS6unsetup(GENmodel*,CKTcircuit*); +extern int MOS6temp(GENmodel*,CKTcircuit*); +extern int MOS6trunc(GENmodel*,CKTcircuit*,double*); +extern int MOS6convTest(GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int MOS6acLoad(); +extern int MOS6ask(); +extern int MOS6delete(); +extern void MOS6destroy(); +extern int MOS6getic(); +extern int MOS6load(); +extern int MOS6mAsk(); +extern int MOS6mDelete(); +extern int MOS6mParam(); +extern int MOS6param(); +extern int MOS6pzLoad(); +extern int MOS6sAcLoad(); +extern int MOS6sLoad(); +extern void MOS6sPrint(); +extern int MOS6sSetup(); +extern int MOS6sUpdate(); +extern int MOS6setup(); +extern int MOS6unsetup(); +extern int MOS6temp(); +extern int MOS6trunc(); +extern int MOS6convTest(); +#endif /* stdc */ diff --git a/src/spicelib/devices/mos6/mos6ic.c b/src/spicelib/devices/mos6/mos6ic.c new file mode 100644 index 000000000..98997a36a --- /dev/null +++ b/src/spicelib/devices/mos6/mos6ic.c @@ -0,0 +1,50 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS6getic(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + MOS6model *model = (MOS6model *)inModel; + MOS6instance *here; + /* + * grab initial conditions out of rhs array. User specified, so use + * external nodes to get values + */ + + for( ; model ; model = model->MOS6nextModel) { + for(here = model->MOS6instances; here ; here = here->MOS6nextInstance) { + if (here->MOS6owner != ARCHme) continue; + + if(!here->MOS6icVBSGiven) { + here->MOS6icVBS = + *(ckt->CKTrhs + here->MOS6bNode) - + *(ckt->CKTrhs + here->MOS6sNode); + } + if(!here->MOS6icVDSGiven) { + here->MOS6icVDS = + *(ckt->CKTrhs + here->MOS6dNode) - + *(ckt->CKTrhs + here->MOS6sNode); + } + if(!here->MOS6icVGSGiven) { + here->MOS6icVGS = + *(ckt->CKTrhs + here->MOS6gNode) - + *(ckt->CKTrhs + here->MOS6sNode); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/mos6itf.h b/src/spicelib/devices/mos6/mos6itf.h new file mode 100644 index 000000000..b4951e05d --- /dev/null +++ b/src/spicelib/devices/mos6/mos6itf.h @@ -0,0 +1,77 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 T. Sakurai +Modified: 1999 Paolo Nenzi +**********/ +#ifdef DEV_mos6 + +#ifndef DEV_MOS6 +#define DEV_MOS6 + +#include "mos6ext.h" +extern IFparm MOS6pTable[ ]; +extern IFparm MOS6mPTable[ ]; +extern char *MOS6names[ ]; +extern int MOS6nSize; +extern int MOS6pTSize; +extern int MOS6mPTSize; +extern int MOS6iSize; +extern int MOS6mSize; + +SPICEdev MOS6info = { + { + "Mos6", + "Level 6 MOSfet model with Meyer capacitance model", + + &MOS6nSize, + &MOS6nSize, + MOS6names, + + &MOS6pTSize, + MOS6pTable, + + &MOS6mPTSize, + MOS6mPTable, + DEV_DEFAULT + }, + + MOS6param, + MOS6mParam, + MOS6load, + MOS6setup, + MOS6unsetup, + NULL, /* PZsetup routine */ + MOS6temp, + MOS6trunc, + NULL, + NULL, /* MOS6acLoad, XXX */ + NULL, + MOS6destroy, + NULL, /* DELETES */ + NULL,/* DELETES */ + MOS6getic, + MOS6ask, + MOS6mAsk, + NULL, /*MOS6pzLoad, XXX */ +#ifdef NEWCONV + MOS6convTest, +#else /* NEWCONV */ + NULL, +#endif /* NEWCONV */ + + NULL /* MOS6sSetup */, + NULL /* MOS6sLoad */, + NULL /* MOS6sUpdate */, + NULL /* MOS6sAcLoad */, + NULL /* MOS6sPrint */, + NULL, + NULL, /* Distortion routine */ + NULL, /* Noise routine */ + + + &MOS6iSize, + &MOS6mSize +}; + +#endif +#endif diff --git a/src/spicelib/devices/mos6/mos6load.c b/src/spicelib/devices/mos6/mos6load.c new file mode 100644 index 000000000..f0b5e8551 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6load.c @@ -0,0 +1,1041 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "mos6defs.h" +#include "trandefs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS6load(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current value into the + * sparse matrix previously provided + */ +{ + register MOS6model *model = (MOS6model *) inModel; + register MOS6instance *here; + double betac; + double DrainSatCur; + double EffectiveLength; + double GateBulkOverlapCap; + double GateDrainOverlapCap; + double GateSourceOverlapCap; + double OxideCap; + double SourceSatCur; + double arg; + double cbhat; + double cdhat; + double cdrain; + double cdreq; + double ceq; + double ceqbd; + double ceqbs; + double ceqgb; + double ceqgd; + double ceqgs; + double delvbd; + double delvbs; + double delvds; + double delvgd; + double delvgs; + double evbd; + double evbs; + double gcgb; + double gcgd; + double gcgs; + double geq; + double sarg; + double sargsw; + double vbd; + double vbs; + double vds; + double vdsat; + double vgb1; + double vgb; + double vgd1; + double vgd; + double vgdo; + double vgs1; + double vgs; + double von; + double vt; + double xfact; + int xnrm; + int xrev; + double capgs; /* total gate-source capacitance */ + double capgd; /* total gate-drain capacitance */ + double capgb; /* total gate-bulk capacitance */ + int Check; +#ifndef NOBYPASS + double tempv; +#endif /*NOBYPASS*/ + int error; +#ifdef CAPBYPASS + int senflag; +#endif /* CAPBYPASS */ + int SenCond; + + +#ifdef CAPBYPASS + senflag = 0; + if(ckt->CKTsenInfo && ckt->CKTsenInfo->SENstatus == PERTURBATION && + (ckt->CKTsenInfo->SENmode & (ACSEN | TRANSEN))) { + senflag = 1; + } +#endif /* CAPBYPASS */ + + /* loop through all the MOS6 device models */ + for( ; model != NULL; model = model->MOS6nextModel ) { + + /* loop through all the instances of the model */ + for (here = model->MOS6instances; here != NULL ; + here=here->MOS6nextInstance) { + if (here->MOS6owner != ARCHme) continue; + + vt = CONSTKoverQ * here->MOS6temp; + Check=1; + if(ckt->CKTsenInfo){ +#ifdef SENSDEBUG + printf("MOS6load \n"); +#endif /* SENSDEBUG */ + + if((ckt->CKTsenInfo->SENstatus == PERTURBATION)&& + (here->MOS6senPertFlag == OFF))continue; + + } + SenCond = ckt->CKTsenInfo && here->MOS6senPertFlag; + +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospta"); +asm("mospta:"); +#endif /*DETAILPROF*/ + + /* first, we compute a few useful values - these could be + * pre-computed, but for historical reasons are still done + * here. They may be moved at the expense of instance size + */ + + EffectiveLength=here->MOS6l - 2*model->MOS6latDiff; + if( (here->MOS6tSatCurDens == 0) || + (here->MOS6drainArea == 0) || + (here->MOS6sourceArea == 0)) { + DrainSatCur = here->MOS6tSatCur; + SourceSatCur = here->MOS6tSatCur; + } else { + DrainSatCur = here->MOS6tSatCurDens * + here->MOS6drainArea; + SourceSatCur = here->MOS6tSatCurDens * + here->MOS6sourceArea; + } + GateSourceOverlapCap = model->MOS6gateSourceOverlapCapFactor * + here->MOS6w; + GateDrainOverlapCap = model->MOS6gateDrainOverlapCapFactor * + here->MOS6w; + GateBulkOverlapCap = model->MOS6gateBulkOverlapCapFactor * + EffectiveLength; + betac = here->MOS6tKc * here->MOS6w/EffectiveLength; + OxideCap = model->MOS6oxideCapFactor * EffectiveLength * + here->MOS6w; + /* + * ok - now to do the start-up operations + * + * we must get values for vbs, vds, and vgs from somewhere + * so we either predict them or recover them from last iteration + * These are the two most common cases - either a prediction + * step or the general iteration step and they + * share some code, so we put them first - others later on + */ + + if(SenCond){ +#ifdef SENSDEBUG + printf("MOS6senPertFlag = ON \n"); +#endif /* SENSDEBUG */ + if((ckt->CKTsenInfo->SENmode == TRANSEN) && + (ckt->CKTmode & MODEINITTRAN)) { + vgs = *(ckt->CKTstate1 + here->MOS6vgs); + vds = *(ckt->CKTstate1 + here->MOS6vds); + vbs = *(ckt->CKTstate1 + here->MOS6vbs); + vbd = *(ckt->CKTstate1 + here->MOS6vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } + else if (ckt->CKTsenInfo->SENmode == ACSEN){ + vgb = model->MOS6type * ( + *(ckt->CKTrhsOp+here->MOS6gNode) - + *(ckt->CKTrhsOp+here->MOS6bNode)); + vbs = *(ckt->CKTstate0 + here->MOS6vbs); + vbd = *(ckt->CKTstate0 + here->MOS6vbd); + vgd = vgb + vbd ; + vgs = vgb + vbs ; + vds = vbs - vbd ; + } + else{ + vgs = *(ckt->CKTstate0 + here->MOS6vgs); + vds = *(ckt->CKTstate0 + here->MOS6vds); + vbs = *(ckt->CKTstate0 + here->MOS6vbs); + vbd = *(ckt->CKTstate0 + here->MOS6vbd); + vgb = vgs - vbs; + vgd = vgs - vds; + } +#ifdef SENSDEBUG + printf(" vbs = %.7e ,vbd = %.7e,vgb = %.7e\n",vbs,vbd,vgb); + printf(" vgs = %.7e ,vds = %.7e,vgd = %.7e\n",vgs,vds,vgd); +#endif /* SENSDEBUG */ + goto next1; + } + + + if((ckt->CKTmode & (MODEINITFLOAT | MODEINITPRED | MODEINITSMSIG + | MODEINITTRAN)) || + ( (ckt->CKTmode & MODEINITFIX) && (!here->MOS6off) ) ) { +#ifndef PREDICTOR + if(ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + + /* predictor step */ + + xfact=ckt->CKTdelta/ckt->CKTdeltaOld[1]; + *(ckt->CKTstate0 + here->MOS6vbs) = + *(ckt->CKTstate1 + here->MOS6vbs); + vbs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS6vbs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS6vbs))); + *(ckt->CKTstate0 + here->MOS6vgs) = + *(ckt->CKTstate1 + here->MOS6vgs); + vgs = (1+xfact)* (*(ckt->CKTstate1 + here->MOS6vgs)) + -(xfact * (*(ckt->CKTstate2 + here->MOS6vgs))); + *(ckt->CKTstate0 + here->MOS6vds) = + *(ckt->CKTstate1 + here->MOS6vds); + vds = (1+xfact)* (*(ckt->CKTstate1 + here->MOS6vds)) + -(xfact * (*(ckt->CKTstate2 + here->MOS6vds))); + *(ckt->CKTstate0 + here->MOS6vbd) = + *(ckt->CKTstate0 + here->MOS6vbs)- + *(ckt->CKTstate0 + here->MOS6vds); + } else { +#endif /* PREDICTOR */ + + /* general iteration */ + + vbs = model->MOS6type * ( + *(ckt->CKTrhsOld+here->MOS6bNode) - + *(ckt->CKTrhsOld+here->MOS6sNodePrime)); + vgs = model->MOS6type * ( + *(ckt->CKTrhsOld+here->MOS6gNode) - + *(ckt->CKTrhsOld+here->MOS6sNodePrime)); + vds = model->MOS6type * ( + *(ckt->CKTrhsOld+here->MOS6dNodePrime) - + *(ckt->CKTrhsOld+here->MOS6sNodePrime)); +#ifndef PREDICTOR + } +#endif /* PREDICTOR */ + + /* now some common crunching for some more useful quantities */ + + vbd=vbs-vds; + vgd=vgs-vds; + vgdo = *(ckt->CKTstate0 + here->MOS6vgs) - + *(ckt->CKTstate0 + here->MOS6vds); + delvbs = vbs - *(ckt->CKTstate0 + here->MOS6vbs); + delvbd = vbd - *(ckt->CKTstate0 + here->MOS6vbd); + delvgs = vgs - *(ckt->CKTstate0 + here->MOS6vgs); + delvds = vds - *(ckt->CKTstate0 + here->MOS6vds); + delvgd = vgd-vgdo; + + /* these are needed for convergence testing */ + + if (here->MOS6mode >= 0) { + cdhat= + here->MOS6cd- + here->MOS6gbd * delvbd + + here->MOS6gmbs * delvbs + + here->MOS6gm * delvgs + + here->MOS6gds * delvds ; + } else { + cdhat= + here->MOS6cd - + ( here->MOS6gbd - + here->MOS6gmbs) * delvbd - + here->MOS6gm * delvgd + + here->MOS6gds * delvds ; + } + cbhat= + here->MOS6cbs + + here->MOS6cbd + + here->MOS6gbd * delvbd + + here->MOS6gbs * delvbs ; +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptb"); +asm("mosptb:"); +#endif /*DETAILPROF*/ +#ifndef NOBYPASS + /* now lets see if we can bypass (ugh) */ + /* the following mess should be one if statement, but + * many compilers can't handle it all at once, so it + * is split into several successive if statements + */ + tempv = MAX(fabs(cbhat),fabs(here->MOS6cbs + + here->MOS6cbd))+ckt->CKTabstol; + if((!(ckt->CKTmode & (MODEINITPRED|MODEINITTRAN|MODEINITSMSIG) + )) && (ckt->CKTbypass) ) + if ( (fabs(cbhat-(here->MOS6cbs + + here->MOS6cbd)) < ckt->CKTreltol * + tempv)) + if( (fabs(delvbs) < (ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS6vbs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvbd) < (ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS6vbd)))+ + ckt->CKTvoltTol)) ) + if( (fabs(delvgs) < (ckt->CKTreltol * MAX(fabs(vgs), + fabs(*(ckt->CKTstate0+here->MOS6vgs)))+ + ckt->CKTvoltTol))) + if ( (fabs(delvds) < (ckt->CKTreltol * MAX(fabs(vds), + fabs(*(ckt->CKTstate0+here->MOS6vds)))+ + ckt->CKTvoltTol)) ) + if( (fabs(cdhat- here->MOS6cd) < + ckt->CKTreltol * MAX(fabs(cdhat),fabs( + here->MOS6cd)) + ckt->CKTabstol) ) { + /* bypass code */ + /* nothing interesting has changed since last + * iteration on this device, so we just + * copy all the values computed last iteration out + * and keep going + */ + vbs = *(ckt->CKTstate0 + here->MOS6vbs); + vbd = *(ckt->CKTstate0 + here->MOS6vbd); + vgs = *(ckt->CKTstate0 + here->MOS6vgs); + vds = *(ckt->CKTstate0 + here->MOS6vds); + vgd = vgs - vds; + vgb = vgs - vbs; + cdrain = here->MOS6mode * (here->MOS6cd + here->MOS6cbd); + if(ckt->CKTmode & (MODETRAN | MODETRANOP)) { + capgs = ( *(ckt->CKTstate0+here->MOS6capgs)+ + *(ckt->CKTstate1+here->MOS6capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS6capgd)+ + *(ckt->CKTstate1+here->MOS6capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS6capgb)+ + *(ckt->CKTstate1+here->MOS6capgb) + + GateBulkOverlapCap ); + + if(ckt->CKTsenInfo){ + here->MOS6cgs = capgs; + here->MOS6cgd = capgd; + here->MOS6cgb = capgb; + } + } + goto bypass; + } +#endif /*NOBYPASS*/ +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptc"); +asm("mosptc:"); +#endif /*DETAILPROF*/ + /* ok - bypass is out, do it the hard way */ + + von = model->MOS6type * here->MOS6von; + +#ifndef NODELIMITING + /* + * limiting + * we want to keep device voltages from changing + * so fast that the exponentials churn out overflows + * and similar rudeness + */ + + if(*(ckt->CKTstate0 + here->MOS6vds) >=0) { + vgs = DEVfetlim(vgs,*(ckt->CKTstate0 + here->MOS6vgs) + ,von); + vds = vgs - vgd; + vds = DEVlimvds(vds,*(ckt->CKTstate0 + here->MOS6vds)); + vgd = vgs - vds; + } else { + vgd = DEVfetlim(vgd,vgdo,von); + vds = vgs - vgd; + if(!(ckt->CKTfixLimit)) { + vds = -DEVlimvds(-vds,-(*(ckt->CKTstate0 + + here->MOS6vds))); + } + vgs = vgd + vds; + } + if(vds >= 0) { + vbs = DEVpnjlim(vbs,*(ckt->CKTstate0 + here->MOS6vbs), + vt,here->MOS6sourceVcrit,&Check); + vbd = vbs-vds; + } else { + vbd = DEVpnjlim(vbd,*(ckt->CKTstate0 + here->MOS6vbd), + vt,here->MOS6drainVcrit,&Check); + vbs = vbd + vds; + } +#endif /*NODELIMITING*/ +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptd"); +asm("mosptd:"); +#endif /*DETAILPROF*/ + } else { + + /* ok - not one of the simple cases, so we have to + * look at all of the possibilities for why we were + * called. We still just initialize the three voltages + */ + + if((ckt->CKTmode & MODEINITJCT) && !here->MOS6off) { + vds= model->MOS6type * here->MOS6icVDS; + vgs= model->MOS6type * here->MOS6icVGS; + vbs= model->MOS6type * here->MOS6icVBS; + if((vds==0) && (vgs==0) && (vbs==0) && + ((ckt->CKTmode & + (MODETRAN|MODEDCOP|MODEDCTRANCURVE)) || + (!(ckt->CKTmode & MODEUIC)))) { + vbs = -1; + vgs = model->MOS6type * here->MOS6tVto; + vds = 0; + } + } else { + vbs=vgs=vds=0; + } + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospte"); +asm("mospte:"); +#endif /*DETAILPROF*/ + + /* + * now all the preliminaries are over - we can start doing the + * real work + */ + vbd = vbs - vds; + vgd = vgs - vds; + vgb = vgs - vbs; + + + /* + * bulk-source and bulk-drain diodes + * here we just evaluate the ideal diode current and the + * corresponding derivative (conductance). + */ +next1: if(vbs <= 0) { + here->MOS6gbs = SourceSatCur/vt; + here->MOS6cbs = here->MOS6gbs*vbs; + here->MOS6gbs += ckt->CKTgmin; + } else { + evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); + here->MOS6gbs = SourceSatCur*evbs/vt + ckt->CKTgmin; + here->MOS6cbs = SourceSatCur * (evbs-1); + } + if(vbd <= 0) { + here->MOS6gbd = DrainSatCur/vt; + here->MOS6cbd = here->MOS6gbd *vbd; + here->MOS6gbd += ckt->CKTgmin; + } else { + evbd = exp(MIN(MAX_EXP_ARG,vbd/vt)); + here->MOS6gbd = DrainSatCur*evbd/vt +ckt->CKTgmin; + here->MOS6cbd = DrainSatCur *(evbd-1); + } + + /* now to determine whether the user was able to correctly + * identify the source and drain of his device + */ + if(vds >= 0) { + /* normal mode */ + here->MOS6mode = 1; + } else { + /* inverse mode */ + here->MOS6mode = -1; + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptf"); +asm("mosptf:"); +#endif /*DETAILPROF*/ + { + /* + * this block of code evaluates the drain current and its + * derivatives using the n-th power MOS model and the + * charges associated with the gate, channel and bulk for + * mosfets + * + */ + + /* the following 14 variables are local to this code block until + * it is obvious that they can be made global + */ + double arg; + double sarg; + double vgon; + double vdshere, vbsvbd; + double idsat, lambda, vonbm; + double vdst, vdst2, ivdst1, vdstg; + + vbsvbd = (here->MOS6mode==1?vbs:vbd); + if (vbsvbd <= 0 ) { + sarg = sqrt(here->MOS6tPhi - vbsvbd); + } else { + sarg = sqrt(here->MOS6tPhi); + sarg = sarg - vbsvbd / (sarg+sarg); + sarg = MAX(0,sarg); + } + vdshere = vds * here->MOS6mode; + von=(here->MOS6tVbi*model->MOS6type)+model->MOS6gamma*sarg + - model->MOS6gamma1 * vbsvbd; +#if 0 + - model->MOS6sigma * vdshere; +#endif + vgon = (here->MOS6mode==1?vgs:vgd) - von; + + if (vgon <= 0) { + /* + * cutoff region + */ + vdsat = 0; + cdrain=0; + here->MOS6gm=0; + here->MOS6gds=0; + here->MOS6gmbs=0; + + } else { + if (sarg <= 0) { + arg=0; + } else { + if ((here->MOS6mode==1?vbs:vbd) <= 0 ) { + vonbm = model->MOS6gamma1 + + model->MOS6gamma / (sarg + sarg); + } else { + vonbm = model->MOS6gamma1 + + model->MOS6gamma / 2 / sqrt(here->MOS6tPhi); + } + } + sarg = log(vgon); + vdsat = model->MOS6kv * exp(sarg * model->MOS6nv); + idsat = betac * exp(sarg * model->MOS6nc); + lambda = model->MOS6lamda0 - model->MOS6lamda1 * vbsvbd; + /* + * saturation region + */ + cdrain = idsat * (1 + lambda * vdshere); + here->MOS6gm = cdrain * model->MOS6nc / vgon; + here->MOS6gds = here->MOS6gm * model->MOS6sigma + + idsat * lambda; + here->MOS6gmbs = here->MOS6gm * vonbm + - idsat * model->MOS6lamda1 * vdshere; + if (vdsat > vdshere){ + /* + * linear region + */ + vdst = vdshere / vdsat; + vdst2 = (2 - vdst) * vdst; + vdstg = - vdst * model->MOS6nv / vgon; + ivdst1 = cdrain * (2 - vdst - vdst); + cdrain = cdrain * vdst2; + here->MOS6gm = here->MOS6gm * vdst2 + ivdst1 * vdstg; + here->MOS6gds = here->MOS6gds * vdst2 + ivdst1 + * (1 / vdsat + vdstg * model->MOS6sigma); + here->MOS6gmbs = here->MOS6gmbs * vdst2 + + ivdst1 * vdstg * vonbm; + } + } + /* + * finished + */ + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptg"); +asm("mosptg:"); +#endif /*DETAILPROF*/ + + /* now deal with n vs p polarity */ + + here->MOS6von = model->MOS6type * von; + here->MOS6vdsat = model->MOS6type * vdsat; + /* line 490 */ + /* + * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE + */ + here->MOS6cd=here->MOS6mode * cdrain - here->MOS6cbd; + + if (ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG)) { + /* + * now we do the hard part of the bulk-drain and bulk-source + * diode - we evaluate the non-linear capacitance and + * charge + * + * the basic equations are not hard, but the implementation + * is somewhat long in an attempt to avoid log/exponential + * evaluations + */ + /* + * charge storage elements + * + *.. bulk-drain and bulk-source depletion capacitances + */ +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbs) >= ckt->CKTreltol * MAX(fabs(vbs), + fabs(*(ckt->CKTstate0+here->MOS6vbs)))+ + ckt->CKTvoltTol)|| senflag) +#endif /*CAPBYPASS*/ + { + /* can't bypass the diode capacitance calculations */ +#ifdef CAPZEROBYPASS + if(here->MOS6Cbs != 0 || here->MOS6Cbssw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbs < here->MOS6tDepCap){ + arg=1-vbs/here->MOS6tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS6bulkJctBotGradingCoeff == + model->MOS6bulkJctSideGradingCoeff) { + if(model->MOS6bulkJctBotGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + sarg = sargsw = + exp(-model->MOS6bulkJctBotGradingCoeff* + log(arg)); + } + } else { + if(model->MOS6bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS6bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS6bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS6bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS6qbs) = + here->MOS6tBulkPot*(here->MOS6Cbs* + (1-arg*sarg)/(1-model->MOS6bulkJctBotGradingCoeff) + +here->MOS6Cbssw* + (1-arg*sargsw)/ + (1-model->MOS6bulkJctSideGradingCoeff)); + here->MOS6capbs=here->MOS6Cbs*sarg+ + here->MOS6Cbssw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS6qbs) = here->MOS6f4s + + vbs*(here->MOS6f2s+vbs*(here->MOS6f3s/2)); + here->MOS6capbs=here->MOS6f2s+here->MOS6f3s*vbs; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS6qbs) = 0; + here->MOS6capbs=0; + } +#endif /*CAPZEROBYPASS*/ + } +#ifdef CAPBYPASS + if(((ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) || + fabs(delvbd) >= ckt->CKTreltol * MAX(fabs(vbd), + fabs(*(ckt->CKTstate0+here->MOS6vbd)))+ + ckt->CKTvoltTol)|| senflag) +#endif /*CAPBYPASS*/ + /* can't bypass the diode capacitance calculations */ + { +#ifdef CAPZEROBYPASS + if(here->MOS6Cbd != 0 || here->MOS6Cbdsw != 0 ) { +#endif /*CAPZEROBYPASS*/ + if (vbd < here->MOS6tDepCap) { + arg=1-vbd/here->MOS6tBulkPot; + /* + * the following block looks somewhat long and messy, + * but since most users use the default grading + * coefficients of .5, and sqrt is MUCH faster than an + * exp(log()) we use this special case code to buy time. + * (as much as 10% of total job time!) + */ +#ifndef NOSQRT + if(model->MOS6bulkJctBotGradingCoeff == .5 && + model->MOS6bulkJctSideGradingCoeff == .5) { + sarg = sargsw = 1/sqrt(arg); + } else { + if(model->MOS6bulkJctBotGradingCoeff == .5) { + sarg = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sarg = exp(-model->MOS6bulkJctBotGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + if(model->MOS6bulkJctSideGradingCoeff == .5) { + sargsw = 1/sqrt(arg); + } else { +#endif /*NOSQRT*/ + sargsw =exp(-model->MOS6bulkJctSideGradingCoeff* + log(arg)); +#ifndef NOSQRT + } + } +#endif /*NOSQRT*/ + *(ckt->CKTstate0 + here->MOS6qbd) = + here->MOS6tBulkPot*(here->MOS6Cbd* + (1-arg*sarg) + /(1-model->MOS6bulkJctBotGradingCoeff) + +here->MOS6Cbdsw* + (1-arg*sargsw) + /(1-model->MOS6bulkJctSideGradingCoeff)); + here->MOS6capbd=here->MOS6Cbd*sarg+ + here->MOS6Cbdsw*sargsw; + } else { + *(ckt->CKTstate0 + here->MOS6qbd) = here->MOS6f4d + + vbd * (here->MOS6f2d + vbd * here->MOS6f3d/2); + here->MOS6capbd=here->MOS6f2d + vbd * here->MOS6f3d; + } +#ifdef CAPZEROBYPASS + } else { + *(ckt->CKTstate0 + here->MOS6qbd) = 0; + here->MOS6capbd = 0; + } +#endif /*CAPZEROBYPASS*/ + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospth"); +asm("mospth:"); +#endif /*DETAILPROF*/ + + if(SenCond && (ckt->CKTsenInfo->SENmode==TRANSEN)) goto next2; + + if ( ckt->CKTmode & MODETRAN ) { + /* (above only excludes tranop, since we're only at this + * point if tran or tranop ) + */ + + /* + * calculate equivalent conductances and currents for + * depletion capacitors + */ + + /* integrate the capacitors and save results */ + + error = NIintegrate(ckt,&geq,&ceq,here->MOS6capbd, + here->MOS6qbd); + if(error) return(error); + here->MOS6gbd += geq; + here->MOS6cbd += *(ckt->CKTstate0 + here->MOS6cqbd); + here->MOS6cd -= *(ckt->CKTstate0 + here->MOS6cqbd); + error = NIintegrate(ckt,&geq,&ceq,here->MOS6capbs, + here->MOS6qbs); + if(error) return(error); + here->MOS6gbs += geq; + here->MOS6cbs += *(ckt->CKTstate0 + here->MOS6cqbs); + } + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mospti"); +asm("mospti:"); +#endif /*DETAILPROF*/ + + if(SenCond) goto next2; + + + /* + * check convergence + */ + if ( (here->MOS6off == 0) || + (!(ckt->CKTmode & (MODEINITFIX|MODEINITSMSIG))) ){ + if (Check == 1) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; +#ifndef NEWCONV + } else { + tol=ckt->CKTreltol*MAX(fabs(cdhat), + fabs(here->MOS6cd))+ckt->CKTabstol; + if (fabs(cdhat-here->MOS6cd) >= tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } else { + tol=ckt->CKTreltol*MAX(fabs(cbhat), + fabs(here->MOS6cbs+here->MOS6cbd))+ + ckt->CKTabstol; + if (fabs(cbhat-(here->MOS6cbs+here->MOS6cbd)) > tol) { + ckt->CKTnoncon++; + ckt->CKTtroubleElt = (GENinstance *) here; + } + } +#endif /*NEWCONV*/ + } + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptj"); +asm("mosptj:"); +#endif /*DETAILPROF*/ + + /* save things away for next time */ + +next2: *(ckt->CKTstate0 + here->MOS6vbs) = vbs; + *(ckt->CKTstate0 + here->MOS6vbd) = vbd; + *(ckt->CKTstate0 + here->MOS6vgs) = vgs; + *(ckt->CKTstate0 + here->MOS6vds) = vds; + +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptk"); +asm("mosptk:"); +#endif /*DETAILPROF*/ + /* + * meyer's capacitor model + */ + if ( ckt->CKTmode & (MODETRAN | MODETRANOP | MODEINITSMSIG) ) { + /* + * calculate meyer's capacitors + */ + /* + * new cmeyer - this just evaluates at the current time, + * expects you to remember values from previous time + * returns 1/2 of non-constant portion of capacitance + * you must add in the other half from previous time + * and the constant part + */ + if (here->MOS6mode > 0){ + DEVqmeyer (vgs,vgd,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS6capgs), + (ckt->CKTstate0 + here->MOS6capgd), + (ckt->CKTstate0 + here->MOS6capgb), + here->MOS6tPhi,OxideCap); + } else { + DEVqmeyer (vgd,vgs,vgb,von,vdsat, + (ckt->CKTstate0 + here->MOS6capgd), + (ckt->CKTstate0 + here->MOS6capgs), + (ckt->CKTstate0 + here->MOS6capgb), + here->MOS6tPhi,OxideCap); + } + vgs1 = *(ckt->CKTstate1 + here->MOS6vgs); + vgd1 = vgs1 - *(ckt->CKTstate1 + here->MOS6vds); + vgb1 = vgs1 - *(ckt->CKTstate1 + here->MOS6vbs); + if(ckt->CKTmode & (MODETRANOP|MODEINITSMSIG)) { + capgs = 2 * *(ckt->CKTstate0+here->MOS6capgs)+ + GateSourceOverlapCap ; + capgd = 2 * *(ckt->CKTstate0+here->MOS6capgd)+ + GateDrainOverlapCap ; + capgb = 2 * *(ckt->CKTstate0+here->MOS6capgb)+ + GateBulkOverlapCap ; + } else { + capgs = ( *(ckt->CKTstate0+here->MOS6capgs)+ + *(ckt->CKTstate1+here->MOS6capgs) + + GateSourceOverlapCap ); + capgd = ( *(ckt->CKTstate0+here->MOS6capgd)+ + *(ckt->CKTstate1+here->MOS6capgd) + + GateDrainOverlapCap ); + capgb = ( *(ckt->CKTstate0+here->MOS6capgb)+ + *(ckt->CKTstate1+here->MOS6capgb) + + GateBulkOverlapCap ); + } + if(ckt->CKTsenInfo){ + here->MOS6cgs = capgs; + here->MOS6cgd = capgd; + here->MOS6cgb = capgb; + } +/* + +*/ + +#ifdef DETAILPROF +asm(" .globl mosptl"); +asm("mosptl:"); +#endif /*DETAILPROF*/ + /* + * store small-signal parameters (for meyer's model) + * all parameters already stored, so done... + */ + if(SenCond){ + if((ckt->CKTsenInfo->SENmode == DCSEN)|| + (ckt->CKTsenInfo->SENmode == ACSEN)){ + continue; + } + } + +#ifndef PREDICTOR + if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN) ) { + *(ckt->CKTstate0 + here->MOS6qgs) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS6qgs) + - xfact * *(ckt->CKTstate2 + here->MOS6qgs); + *(ckt->CKTstate0 + here->MOS6qgd) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS6qgd) + - xfact * *(ckt->CKTstate2 + here->MOS6qgd); + *(ckt->CKTstate0 + here->MOS6qgb) = + (1+xfact) * *(ckt->CKTstate1 + here->MOS6qgb) + - xfact * *(ckt->CKTstate2 + here->MOS6qgb); + } else { +#endif /*PREDICTOR*/ + if(ckt->CKTmode & MODETRAN) { + *(ckt->CKTstate0 + here->MOS6qgs) = (vgs-vgs1)*capgs + + *(ckt->CKTstate1 + here->MOS6qgs) ; + *(ckt->CKTstate0 + here->MOS6qgd) = (vgd-vgd1)*capgd + + *(ckt->CKTstate1 + here->MOS6qgd) ; + *(ckt->CKTstate0 + here->MOS6qgb) = (vgb-vgb1)*capgb + + *(ckt->CKTstate1 + here->MOS6qgb) ; + } else { + /* TRANOP only */ + *(ckt->CKTstate0 + here->MOS6qgs) = vgs*capgs; + *(ckt->CKTstate0 + here->MOS6qgd) = vgd*capgd; + *(ckt->CKTstate0 + here->MOS6qgb) = vgb*capgb; + } +#ifndef PREDICTOR + } +#endif /*PREDICTOR*/ + } +bypass: + if(SenCond) continue; + + if ( (ckt->CKTmode & (MODEINITTRAN)) || + (! (ckt->CKTmode & (MODETRAN)) ) ) { + /* + * initialize to zero charge conductances + * and current + */ + gcgs=0; + ceqgs=0; + gcgd=0; + ceqgd=0; + gcgb=0; + ceqgb=0; + } else { + if(capgs == 0) *(ckt->CKTstate0 + here->MOS6cqgs) =0; + if(capgd == 0) *(ckt->CKTstate0 + here->MOS6cqgd) =0; + if(capgb == 0) *(ckt->CKTstate0 + here->MOS6cqgb) =0; + /* + * calculate equivalent conductances and currents for + * meyer"s capacitors + */ + error = NIintegrate(ckt,&gcgs,&ceqgs,capgs,here->MOS6qgs); + if(error) return(error); + error = NIintegrate(ckt,&gcgd,&ceqgd,capgd,here->MOS6qgd); + if(error) return(error); + error = NIintegrate(ckt,&gcgb,&ceqgb,capgb,here->MOS6qgb); + if(error) return(error); + ceqgs=ceqgs-gcgs*vgs+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS6qgs); + ceqgd=ceqgd-gcgd*vgd+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS6qgd); + ceqgb=ceqgb-gcgb*vgb+ckt->CKTag[0]* + *(ckt->CKTstate0 + here->MOS6qgb); + } + /* + * store charge storage info for meyer's cap in lx table + */ + + /* + * load current vector + */ + ceqbs = model->MOS6type * + (here->MOS6cbs-(here->MOS6gbs-ckt->CKTgmin)*vbs); + ceqbd = model->MOS6type * + (here->MOS6cbd-(here->MOS6gbd-ckt->CKTgmin)*vbd); + if (here->MOS6mode >= 0) { + xnrm=1; + xrev=0; + cdreq=model->MOS6type*(cdrain-here->MOS6gds*vds- + here->MOS6gm*vgs-here->MOS6gmbs*vbs); + } else { + xnrm=0; + xrev=1; + cdreq = -(model->MOS6type)*(cdrain-here->MOS6gds*(-vds)- + here->MOS6gm*vgd-here->MOS6gmbs*vbd); + } + *(ckt->CKTrhs + here->MOS6gNode) -= + (model->MOS6type * (ceqgs + ceqgb + ceqgd)); + *(ckt->CKTrhs + here->MOS6bNode) -= + (ceqbs + ceqbd - model->MOS6type * ceqgb); + *(ckt->CKTrhs + here->MOS6dNodePrime) += + (ceqbd - cdreq + model->MOS6type * ceqgd); + *(ckt->CKTrhs + here->MOS6sNodePrime) += + cdreq + ceqbs + model->MOS6type * ceqgs; + /* + * load y matrix + */ + + *(here->MOS6DdPtr) += (here->MOS6drainConductance); + *(here->MOS6GgPtr) += ((gcgd+gcgs+gcgb)); + *(here->MOS6SsPtr) += (here->MOS6sourceConductance); + *(here->MOS6BbPtr) += (here->MOS6gbd+here->MOS6gbs+gcgb); + *(here->MOS6DPdpPtr) += + (here->MOS6drainConductance+here->MOS6gds+ + here->MOS6gbd+xrev*(here->MOS6gm+here->MOS6gmbs)+gcgd); + *(here->MOS6SPspPtr) += + (here->MOS6sourceConductance+here->MOS6gds+ + here->MOS6gbs+xnrm*(here->MOS6gm+here->MOS6gmbs)+gcgs); + *(here->MOS6DdpPtr) += (-here->MOS6drainConductance); + *(here->MOS6GbPtr) -= gcgb; + *(here->MOS6GdpPtr) -= gcgd; + *(here->MOS6GspPtr) -= gcgs; + *(here->MOS6SspPtr) += (-here->MOS6sourceConductance); + *(here->MOS6BgPtr) -= gcgb; + *(here->MOS6BdpPtr) -= here->MOS6gbd; + *(here->MOS6BspPtr) -= here->MOS6gbs; + *(here->MOS6DPdPtr) += (-here->MOS6drainConductance); + *(here->MOS6DPgPtr) += ((xnrm-xrev)*here->MOS6gm-gcgd); + *(here->MOS6DPbPtr) += (-here->MOS6gbd+(xnrm-xrev)*here->MOS6gmbs); + *(here->MOS6DPspPtr) += (-here->MOS6gds-xnrm* + (here->MOS6gm+here->MOS6gmbs)); + *(here->MOS6SPgPtr) += (-(xnrm-xrev)*here->MOS6gm-gcgs); + *(here->MOS6SPsPtr) += (-here->MOS6sourceConductance); + *(here->MOS6SPbPtr) += (-here->MOS6gbs-(xnrm-xrev)*here->MOS6gmbs); + *(here->MOS6SPdpPtr) += (-here->MOS6gds-xrev* + (here->MOS6gm+here->MOS6gmbs)); + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/mos6mask.c b/src/spicelib/devices/mos6/mos6mask.c new file mode 100644 index 000000000..4eb93831e --- /dev/null +++ b/src/spicelib/devices/mos6/mos6mask.c @@ -0,0 +1,144 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS6mAsk(ckt,inModel,param,value) + CKTcircuit *ckt; + GENmodel *inModel; + int param; + IFvalue *value; +{ + register MOS6model *model = (MOS6model *)inModel; + switch(param) { + case MOS6_MOD_TNOM: + value->rValue = model->MOS6tnom; + break; + case MOS6_MOD_VTO: + value->rValue = model->MOS6vt0; + break; + case MOS6_MOD_KV: + value->rValue = model->MOS6kv; + break; + case MOS6_MOD_NV: + value->rValue = model->MOS6nv; + break; + case MOS6_MOD_KC: + value->rValue = model->MOS6kc; + break; + case MOS6_MOD_NC: + value->rValue = model->MOS6nc; + break; + case MOS6_MOD_NVTH: + value->rValue = model->MOS6nvth; + break; + case MOS6_MOD_PS: + value->rValue = model->MOS6ps; + break; + case MOS6_MOD_GAMMA: + value->rValue = model->MOS6gamma; + break; + case MOS6_MOD_GAMMA1: + value->rValue = model->MOS6gamma1; + break; + case MOS6_MOD_SIGMA: + value->rValue = model->MOS6sigma; + break; + case MOS6_MOD_PHI: + value->rValue = model->MOS6phi; + break; + case MOS6_MOD_LAMBDA: + value->rValue = model->MOS6lambda; + break; + case MOS6_MOD_LAMDA0: + value->rValue = model->MOS6lamda0; + break; + case MOS6_MOD_LAMDA1: + value->rValue = model->MOS6lamda1; + break; + case MOS6_MOD_RD: + value->rValue = model->MOS6drainResistance; + break; + case MOS6_MOD_RS: + value->rValue = model->MOS6sourceResistance; + break; + case MOS6_MOD_CBD: + value->rValue = model->MOS6capBD; + break; + case MOS6_MOD_CBS: + value->rValue = model->MOS6capBS; + break; + case MOS6_MOD_IS: + value->rValue = model->MOS6jctSatCur; + break; + case MOS6_MOD_PB: + value->rValue = model->MOS6bulkJctPotential; + break; + case MOS6_MOD_CGSO: + value->rValue = model->MOS6gateSourceOverlapCapFactor; + break; + case MOS6_MOD_CGDO: + value->rValue = model->MOS6gateDrainOverlapCapFactor; + break; + case MOS6_MOD_CGBO: + value->rValue = model->MOS6gateBulkOverlapCapFactor; + break; + case MOS6_MOD_CJ: + value->rValue = model->MOS6bulkCapFactor; + break; + case MOS6_MOD_MJ: + value->rValue = model->MOS6bulkJctBotGradingCoeff; + break; + case MOS6_MOD_CJSW: + value->rValue = model->MOS6sideWallCapFactor; + break; + case MOS6_MOD_MJSW: + value->rValue = model->MOS6bulkJctSideGradingCoeff; + break; + case MOS6_MOD_JS: + value->rValue = model->MOS6jctSatCurDensity; + break; + case MOS6_MOD_TOX: + value->rValue = model->MOS6oxideThickness; + break; + case MOS6_MOD_LD: + value->rValue = model->MOS6latDiff; + break; + case MOS6_MOD_RSH: + value->rValue = model->MOS6sheetResistance; + break; + case MOS6_MOD_U0: + value->rValue = model->MOS6surfaceMobility; + break; + case MOS6_MOD_FC: + value->rValue = model->MOS6fwdCapDepCoeff; + break; + case MOS6_MOD_NSS: + value->rValue = model->MOS6surfaceStateDensity; + break; + case MOS6_MOD_NSUB: + value->rValue = model->MOS6substrateDoping; + break; + case MOS6_MOD_TPG: + value->iValue = model->MOS6gateType; + break; + case MOS6_MOD_TYPE: + if (model->MOS6type > 0) + value->sValue = "nmos"; + else + value->sValue = "pmos"; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/mos6mpar.c b/src/spicelib/devices/mos6/mos6mpar.c new file mode 100644 index 000000000..12441118f --- /dev/null +++ b/src/spicelib/devices/mos6/mos6mpar.c @@ -0,0 +1,189 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS6mParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + register MOS6model *model = (MOS6model *)inModel; + switch(param) { + case MOS6_MOD_TNOM: + model->MOS6tnom = value->rValue+CONSTCtoK; + model->MOS6tnomGiven = TRUE; + break; + case MOS6_MOD_VTO: + model->MOS6vt0 = value->rValue; + model->MOS6vt0Given = TRUE; + break; + case MOS6_MOD_KV: + model->MOS6kv = value->rValue; + model->MOS6kvGiven = TRUE; + break; + case MOS6_MOD_NV: + model->MOS6nv = value->rValue; + model->MOS6nvGiven = TRUE; + break; + case MOS6_MOD_KC: + model->MOS6kc = value->rValue; + model->MOS6kcGiven = TRUE; + break; + case MOS6_MOD_NC: + model->MOS6nc = value->rValue; + model->MOS6ncGiven = TRUE; + break; + case MOS6_MOD_NVTH: + model->MOS6nvth = value->rValue; + model->MOS6nvthGiven = TRUE; + break; + case MOS6_MOD_PS: + model->MOS6ps = value->rValue; + model->MOS6psGiven = TRUE; + break; + case MOS6_MOD_GAMMA: + model->MOS6gamma = value->rValue; + model->MOS6gammaGiven = TRUE; + break; + case MOS6_MOD_GAMMA1: + model->MOS6gamma1 = value->rValue; + model->MOS6gamma1Given = TRUE; + break; + case MOS6_MOD_SIGMA: + model->MOS6sigma = value->rValue; + model->MOS6sigmaGiven = TRUE; + break; + case MOS6_MOD_PHI: + model->MOS6phi = value->rValue; + model->MOS6phiGiven = TRUE; + break; + case MOS6_MOD_LAMBDA: + model->MOS6lambda = value->rValue; + model->MOS6lambdaGiven = TRUE; + break; + case MOS6_MOD_LAMDA0: + model->MOS6lamda0 = value->rValue; + model->MOS6lamda0Given = TRUE; + break; + case MOS6_MOD_LAMDA1: + model->MOS6lamda1 = value->rValue; + model->MOS6lamda1Given = TRUE; + break; + case MOS6_MOD_RD: + model->MOS6drainResistance = value->rValue; + model->MOS6drainResistanceGiven = TRUE; + break; + case MOS6_MOD_RS: + model->MOS6sourceResistance = value->rValue; + model->MOS6sourceResistanceGiven = TRUE; + break; + case MOS6_MOD_CBD: + model->MOS6capBD = value->rValue; + model->MOS6capBDGiven = TRUE; + break; + case MOS6_MOD_CBS: + model->MOS6capBS = value->rValue; + model->MOS6capBSGiven = TRUE; + break; + case MOS6_MOD_IS: + model->MOS6jctSatCur = value->rValue; + model->MOS6jctSatCurGiven = TRUE; + break; + case MOS6_MOD_PB: + model->MOS6bulkJctPotential = value->rValue; + model->MOS6bulkJctPotentialGiven = TRUE; + break; + case MOS6_MOD_CGSO: + model->MOS6gateSourceOverlapCapFactor = value->rValue; + model->MOS6gateSourceOverlapCapFactorGiven = TRUE; + break; + case MOS6_MOD_CGDO: + model->MOS6gateDrainOverlapCapFactor = value->rValue; + model->MOS6gateDrainOverlapCapFactorGiven = TRUE; + break; + case MOS6_MOD_CGBO: + model->MOS6gateBulkOverlapCapFactor = value->rValue; + model->MOS6gateBulkOverlapCapFactorGiven = TRUE; + break; + case MOS6_MOD_CJ: + model->MOS6bulkCapFactor = value->rValue; + model->MOS6bulkCapFactorGiven = TRUE; + break; + case MOS6_MOD_MJ: + model->MOS6bulkJctBotGradingCoeff = value->rValue; + model->MOS6bulkJctBotGradingCoeffGiven = TRUE; + break; + case MOS6_MOD_CJSW: + model->MOS6sideWallCapFactor = value->rValue; + model->MOS6sideWallCapFactorGiven = TRUE; + break; + case MOS6_MOD_MJSW: + model->MOS6bulkJctSideGradingCoeff = value->rValue; + model->MOS6bulkJctSideGradingCoeffGiven = TRUE; + break; + case MOS6_MOD_JS: + model->MOS6jctSatCurDensity = value->rValue; + model->MOS6jctSatCurDensityGiven = TRUE; + break; + case MOS6_MOD_TOX: + model->MOS6oxideThickness = value->rValue; + model->MOS6oxideThicknessGiven = TRUE; + break; + case MOS6_MOD_LD: + model->MOS6latDiff = value->rValue; + model->MOS6latDiffGiven = TRUE; + break; + case MOS6_MOD_RSH: + model->MOS6sheetResistance = value->rValue; + model->MOS6sheetResistanceGiven = TRUE; + break; + case MOS6_MOD_U0: + model->MOS6surfaceMobility = value->rValue; + model->MOS6surfaceMobilityGiven = TRUE; + break; + case MOS6_MOD_FC: + model->MOS6fwdCapDepCoeff = value->rValue; + model->MOS6fwdCapDepCoeffGiven = TRUE; + break; + case MOS6_MOD_NSS: + model->MOS6surfaceStateDensity = value->rValue; + model->MOS6surfaceStateDensityGiven = TRUE; + break; + case MOS6_MOD_NSUB: + model->MOS6substrateDoping = value->rValue; + model->MOS6substrateDopingGiven = TRUE; + break; + case MOS6_MOD_TPG: + model->MOS6gateType = value->iValue; + model->MOS6gateTypeGiven = TRUE; + break; + case MOS6_MOD_NMOS: + if(value->iValue) { + model->MOS6type = 1; + model->MOS6typeGiven = TRUE; + } + break; + case MOS6_MOD_PMOS: + if(value->iValue) { + model->MOS6type = -1; + model->MOS6typeGiven = TRUE; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/mos6par.c b/src/spicelib/devices/mos6/mos6par.c new file mode 100644 index 000000000..4842ac4c4 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6par.c @@ -0,0 +1,110 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +MOS6param(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + MOS6instance *here = (MOS6instance *)inst; + switch(param) { + case MOS6_TEMP: + here->MOS6temp = value->rValue+CONSTCtoK; + here->MOS6tempGiven = TRUE; + break; + case MOS6_W: + here->MOS6w = value->rValue; + here->MOS6wGiven = TRUE; + break; + case MOS6_L: + here->MOS6l = value->rValue; + here->MOS6lGiven = TRUE; + break; + case MOS6_AS: + here->MOS6sourceArea = value->rValue; + here->MOS6sourceAreaGiven = TRUE; + break; + case MOS6_AD: + here->MOS6drainArea = value->rValue; + here->MOS6drainAreaGiven = TRUE; + break; + case MOS6_PS: + here->MOS6sourcePerimiter = value->rValue; + here->MOS6sourcePerimiterGiven = TRUE; + break; + case MOS6_PD: + here->MOS6drainPerimiter = value->rValue; + here->MOS6drainPerimiterGiven = TRUE; + break; + case MOS6_NRS: + here->MOS6sourceSquares = value->rValue; + here->MOS6sourceSquaresGiven = TRUE; + break; + case MOS6_NRD: + here->MOS6drainSquares = value->rValue; + here->MOS6drainSquaresGiven = TRUE; + break; + case MOS6_OFF: + here->MOS6off = value->iValue; + break; + case MOS6_IC_VBS: + here->MOS6icVBS = value->rValue; + here->MOS6icVBSGiven = TRUE; + break; + case MOS6_IC_VDS: + here->MOS6icVDS = value->rValue; + here->MOS6icVDSGiven = TRUE; + break; + case MOS6_IC_VGS: + here->MOS6icVGS = value->rValue; + here->MOS6icVGSGiven = TRUE; + break; + case MOS6_IC: + switch(value->v.numValue){ + case 3: + here->MOS6icVBS = *(value->v.vec.rVec+2); + here->MOS6icVBSGiven = TRUE; + case 2: + here->MOS6icVGS = *(value->v.vec.rVec+1); + here->MOS6icVGSGiven = TRUE; + case 1: + here->MOS6icVDS = *(value->v.vec.rVec); + here->MOS6icVDSGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + case MOS6_L_SENS: + if(value->iValue) { + here->MOS6senParmNo = 1; + here->MOS6sens_l = 1; + } + break; + case MOS6_W_SENS: + if(value->iValue) { + here->MOS6senParmNo = 1; + here->MOS6sens_w = 1; + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/mos6set.c b/src/spicelib/devices/mos6/mos6set.c new file mode 100644 index 000000000..a6edf0720 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6set.c @@ -0,0 +1,237 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ + + /* load the MOS6 device structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS6setup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; +{ + register MOS6model *model = (MOS6model *)inModel; + register MOS6instance *here; + int error; + CKTnode *tmp; + + /* loop through all the MOS6 device models */ + for( ; model != NULL; model = model->MOS6nextModel ) { + + if(!model->MOS6typeGiven) { + model->MOS6type = NMOS; + } + if(!model->MOS6latDiffGiven) { + model->MOS6latDiff = 0; + } + if(!model->MOS6jctSatCurDensityGiven) { + model->MOS6jctSatCurDensity = 0; + } + if(!model->MOS6jctSatCurGiven) { + model->MOS6jctSatCur = 1e-14; + } + if(!model->MOS6kvGiven) { + model->MOS6kv = 2; + } + if(!model->MOS6nvGiven) { + model->MOS6nv = 0.5; + } + if(!model->MOS6kcGiven) { + model->MOS6kc = 5e-5; + } + if(!model->MOS6ncGiven) { + model->MOS6nc = 1; + } + if(!model->MOS6nvthGiven) { + model->MOS6nvth = 0.5; + } + if(!model->MOS6psGiven) { + model->MOS6ps = 0; + } + if(!model->MOS6gateSourceOverlapCapFactorGiven) { + model->MOS6gateSourceOverlapCapFactor = 0; + } + if(!model->MOS6gateDrainOverlapCapFactorGiven) { + model->MOS6gateDrainOverlapCapFactor = 0; + } + if(!model->MOS6gateBulkOverlapCapFactorGiven) { + model->MOS6gateBulkOverlapCapFactor = 0; + } + if(!model->MOS6vt0Given) { + model->MOS6vt0 = 0; + } + if(!model->MOS6bulkCapFactorGiven) { + model->MOS6bulkCapFactor = 0; + } + if(!model->MOS6sideWallCapFactorGiven) { + model->MOS6sideWallCapFactor = 0; + } + if(!model->MOS6bulkJctPotentialGiven) { + model->MOS6bulkJctPotential = .8; + } + if(!model->MOS6bulkJctBotGradingCoeffGiven) { + model->MOS6bulkJctBotGradingCoeff = .5; + } + if(!model->MOS6bulkJctSideGradingCoeffGiven) { + model->MOS6bulkJctSideGradingCoeff = .5; + } + if(!model->MOS6fwdCapDepCoeffGiven) { + model->MOS6fwdCapDepCoeff = .5; + } + if(!model->MOS6phiGiven) { + model->MOS6phi = .6; + } + if(!model->MOS6lamda0Given) { + model->MOS6lamda0 = 0; + if(model->MOS6lambdaGiven) { + model->MOS6lamda0 = model->MOS6lambda; + } + } + if(!model->MOS6lamda1Given) { + model->MOS6lamda1 = 0; + } + if(!model->MOS6sigmaGiven) { + model->MOS6sigma = 0; + } + if(!model->MOS6gammaGiven) { + model->MOS6gamma = 0; + } + if(!model->MOS6gamma1Given) { + model->MOS6gamma1 = 0; + } + + /* loop through all the instances of the model */ + for (here = model->MOS6instances; here != NULL ; + here=here->MOS6nextInstance) { + if (here->MOS6owner != ARCHme) goto matrixpointers; + + if(!here->MOS6drainPerimiterGiven) { + here->MOS6drainPerimiter = 0; + } + if(!here->MOS6icVBSGiven) { + here->MOS6icVBS = 0; + } + if(!here->MOS6icVDSGiven) { + here->MOS6icVDS = 0; + } + if(!here->MOS6icVGSGiven) { + here->MOS6icVGS = 0; + } + if(!here->MOS6sourcePerimiterGiven) { + here->MOS6sourcePerimiter = 0; + } + if(!here->MOS6vdsatGiven) { + here->MOS6vdsat = 0; + } + if(!here->MOS6vonGiven) { + here->MOS6von = 0; + } + + + /* allocate a chunk of the state vector */ + here->MOS6states = *states; + *states += MOS6numStates; + if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN) ){ + *states += 10 * (ckt->CKTsenInfo->SENparms); + } + +matrixpointers: + if((model->MOS6drainResistance != 0 || + (model->MOS6sheetResistance != 0 && + here->MOS6drainSquares != 0) ) && + here->MOS6dNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS6name,"drain"); + if(error) return(error); + here->MOS6dNodePrime = tmp->number; + } else { + here->MOS6dNodePrime = here->MOS6dNode; + } + + if((model->MOS6sourceResistance != 0 || + (model->MOS6sheetResistance != 0 && + here->MOS6sourceSquares != 0) ) && + here->MOS6sNodePrime==0) { + error = CKTmkVolt(ckt,&tmp,here->MOS6name,"source"); + if(error) return(error); + here->MOS6sNodePrime = tmp->number; + } else { + here->MOS6sNodePrime = here->MOS6sNode; + } +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(MOS6DdPtr,MOS6dNode,MOS6dNode) + TSTALLOC(MOS6GgPtr,MOS6gNode,MOS6gNode) + TSTALLOC(MOS6SsPtr,MOS6sNode,MOS6sNode) + TSTALLOC(MOS6BbPtr,MOS6bNode,MOS6bNode) + TSTALLOC(MOS6DPdpPtr,MOS6dNodePrime,MOS6dNodePrime) + TSTALLOC(MOS6SPspPtr,MOS6sNodePrime,MOS6sNodePrime) + TSTALLOC(MOS6DdpPtr,MOS6dNode,MOS6dNodePrime) + TSTALLOC(MOS6GbPtr,MOS6gNode,MOS6bNode) + TSTALLOC(MOS6GdpPtr,MOS6gNode,MOS6dNodePrime) + TSTALLOC(MOS6GspPtr,MOS6gNode,MOS6sNodePrime) + TSTALLOC(MOS6SspPtr,MOS6sNode,MOS6sNodePrime) + TSTALLOC(MOS6BdpPtr,MOS6bNode,MOS6dNodePrime) + TSTALLOC(MOS6BspPtr,MOS6bNode,MOS6sNodePrime) + TSTALLOC(MOS6DPspPtr,MOS6dNodePrime,MOS6sNodePrime) + TSTALLOC(MOS6DPdPtr,MOS6dNodePrime,MOS6dNode) + TSTALLOC(MOS6BgPtr,MOS6bNode,MOS6gNode) + TSTALLOC(MOS6DPgPtr,MOS6dNodePrime,MOS6gNode) + TSTALLOC(MOS6SPgPtr,MOS6sNodePrime,MOS6gNode) + TSTALLOC(MOS6SPsPtr,MOS6sNodePrime,MOS6sNode) + TSTALLOC(MOS6DPbPtr,MOS6dNodePrime,MOS6bNode) + TSTALLOC(MOS6SPbPtr,MOS6sNodePrime,MOS6bNode) + TSTALLOC(MOS6SPdpPtr,MOS6sNodePrime,MOS6dNodePrime) + + } + } + return(OK); +} + +int +MOS6unsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + MOS6model *model; + MOS6instance *here; + + for (model = (MOS6model *)inModel; model != NULL; + model = model->MOS6nextModel) + { + for (here = model->MOS6instances; here != NULL; + here=here->MOS6nextInstance) + { + if (here->MOS6dNodePrime + && here->MOS6dNodePrime != here->MOS6dNode) + { + CKTdltNNum(ckt, here->MOS6dNodePrime); + here->MOS6dNodePrime= 0; + } + if (here->MOS6sNodePrime + && here->MOS6sNodePrime != here->MOS6sNode) + { + CKTdltNNum(ckt, here->MOS6sNodePrime); + here->MOS6sNodePrime= 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/mos6/mos6temp.c b/src/spicelib/devices/mos6/mos6temp.c new file mode 100644 index 000000000..238b0b21b --- /dev/null +++ b/src/spicelib/devices/mos6/mos6temp.c @@ -0,0 +1,326 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos6defs.h" +#include "const.h" +#include "sperror.h" +#include "suffix.h" + +int +MOS6temp(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register MOS6model *model = (MOS6model *)inModel; + register MOS6instance *here; + + double egfet,egfet1; + double fact1,fact2; + double kt,kt1; + double arg1; + double ratio,ratio4; + double phio; + double pbo; + double gmanew,gmaold; + double capfact; + double pbfact1,pbfact; + double vt,vtnom; + double wkfngs; + double wkfng; + double fermig; + double fermis; + double vfb; + /* loop through all the resistor models */ + for( ; model != NULL; model = model->MOS6nextModel) { + + + /* perform model defaulting */ + if(!model->MOS6tnomGiven) { + model->MOS6tnom = ckt->CKTnomTemp; + } + + fact1 = model->MOS6tnom/REFTEMP; + vtnom = model->MOS6tnom*CONSTKoverQ; + kt1 = CONSTboltz * model->MOS6tnom; + egfet1 = 1.16-(7.02e-4*model->MOS6tnom*model->MOS6tnom)/ + (model->MOS6tnom+1108); + arg1 = -egfet1/(kt1+kt1)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact1 = -2*vtnom *(1.5*log(fact1)+CHARGE*arg1); + + /* now model parameter preprocessing */ + + if(!model->MOS6oxideThicknessGiven || model->MOS6oxideThickness == 0) { + model->MOS6oxideCapFactor = 0; + } else { + model->MOS6oxideCapFactor = 3.9 * 8.854214871e-12/ + model->MOS6oxideThickness; + if(!model->MOS6kcGiven) { + if(!model->MOS6surfaceMobilityGiven) { + model->MOS6surfaceMobility=600; + } + model->MOS6kc = 0.5 * model->MOS6surfaceMobility * + model->MOS6oxideCapFactor * 1e-4 /*(m**2/cm**2)*/; + } + if(model->MOS6substrateDopingGiven) { + if(model->MOS6substrateDoping*1e6 /*(cm**3/m**3)*/ >1.45e16) { + if(!model->MOS6phiGiven) { + model->MOS6phi = 2*vtnom* + log(model->MOS6substrateDoping* + 1e6/*(cm**3/m**3)*//1.45e16); + model->MOS6phi = MAX(.1,model->MOS6phi); + } + fermis = model->MOS6type * .5 * model->MOS6phi; + wkfng = 3.2; + if(!model->MOS6gateTypeGiven) model->MOS6gateType=1; + if(model->MOS6gateType != 0) { + fermig = model->MOS6type *model->MOS6gateType*.5*egfet1; + wkfng = 3.25 + .5 * egfet1 - fermig; + } + wkfngs = wkfng - (3.25 + .5 * egfet1 +fermis); + if(!model->MOS6gammaGiven) { + model->MOS6gamma = sqrt(2 * 11.70 * 8.854214871e-12 * + CHARGE * model->MOS6substrateDoping* + 1e6/*(cm**3/m**3)*/)/ + model->MOS6oxideCapFactor; + } + if(!model->MOS6gamma1Given) { + model->MOS6gamma1 = 0.0; + } + if(!model->MOS6vt0Given) { + if(!model->MOS6surfaceStateDensityGiven) + model->MOS6surfaceStateDensity=0; + vfb = wkfngs - + model->MOS6surfaceStateDensity * + 1e4 /*(cm**2/m**2)*/ * + CHARGE/model->MOS6oxideCapFactor; + model->MOS6vt0 = vfb + model->MOS6type * + (model->MOS6gamma * sqrt(model->MOS6phi)+ + model->MOS6phi); + } + } else { + model->MOS6substrateDoping = 0; + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: Nsub < Ni",&model->MOS6modName); + return(E_BADPARM); + } + } + } + + + /* loop through all instances of the model */ + for(here = model->MOS6instances; here!= NULL; + here = here->MOS6nextInstance) { + + double czbd; /* zero voltage bulk-drain capacitance */ + double czbdsw; /* zero voltage bulk-drain sidewall capacitance */ + double czbs; /* zero voltage bulk-source capacitance */ + double czbssw; /* zero voltage bulk-source sidewall capacitance */ + double arg; /* 1 - fc */ + double sarg; /* (1-fc) ^^ (-mj) */ + double sargsw; /* (1-fc) ^^ (-mjsw) */ + if (here->MOS6owner != ARCHme) continue; + + /* perform the parameter defaulting */ + if(!here->MOS6tempGiven) { + here->MOS6temp = ckt->CKTtemp; + } + vt = here->MOS6temp * CONSTKoverQ; + ratio = here->MOS6temp/model->MOS6tnom; + fact2 = here->MOS6temp/REFTEMP; + kt = here->MOS6temp * CONSTboltz; + egfet = 1.16-(7.02e-4*here->MOS6temp*here->MOS6temp)/ + (here->MOS6temp+1108); + arg = -egfet/(kt+kt)+1.1150877/(CONSTboltz*(REFTEMP+REFTEMP)); + pbfact = -2*vt *(1.5*log(fact2)+CHARGE*arg); + + if(!here->MOS6drainAreaGiven) { + here->MOS6drainArea = ckt->CKTdefaultMosAD; + } + if(!here->MOS6lGiven) { + here->MOS6l = ckt->CKTdefaultMosL; + } + if(!here->MOS6sourceAreaGiven) { + here->MOS6sourceArea = ckt->CKTdefaultMosAS; + } + if(!here->MOS6wGiven) { + here->MOS6w = ckt->CKTdefaultMosW; + } + + if(here->MOS6l - 2 * model->MOS6latDiff <=0) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: effective channel length less than zero", + &(model->MOS6modName)); + } + ratio4 = ratio * sqrt(ratio); + here->MOS6tKv = model->MOS6kv; + here->MOS6tKc = model->MOS6kc / ratio4; + here->MOS6tSurfMob = model->MOS6surfaceMobility/ratio4; + phio= (model->MOS6phi-pbfact1)/fact1; + here->MOS6tPhi = fact2 * phio + pbfact; + here->MOS6tVbi = + model->MOS6vt0 - model->MOS6type * + (model->MOS6gamma* sqrt(model->MOS6phi)) + +.5*(egfet1-egfet) + + model->MOS6type*.5* (here->MOS6tPhi-model->MOS6phi); + here->MOS6tVto = here->MOS6tVbi + model->MOS6type * + model->MOS6gamma * sqrt(here->MOS6tPhi); + here->MOS6tSatCur = model->MOS6jctSatCur* + exp(-egfet/vt+egfet1/vtnom); + here->MOS6tSatCurDens = model->MOS6jctSatCurDensity * + exp(-egfet/vt+egfet1/vtnom); + pbo = (model->MOS6bulkJctPotential - pbfact1)/fact1; + gmaold = (model->MOS6bulkJctPotential-pbo)/pbo; + capfact = 1/(1+model->MOS6bulkJctBotGradingCoeff* + (4e-4*(model->MOS6tnom-REFTEMP)-gmaold)); + here->MOS6tCbd = model->MOS6capBD * capfact; + here->MOS6tCbs = model->MOS6capBS * capfact; + here->MOS6tCj = model->MOS6bulkCapFactor * capfact; + capfact = 1/(1+model->MOS6bulkJctSideGradingCoeff* + (4e-4*(model->MOS6tnom-REFTEMP)-gmaold)); + here->MOS6tCjsw = model->MOS6sideWallCapFactor * capfact; + here->MOS6tBulkPot = fact2 * pbo+pbfact; + gmanew = (here->MOS6tBulkPot-pbo)/pbo; + capfact = (1+model->MOS6bulkJctBotGradingCoeff* + (4e-4*(here->MOS6temp-REFTEMP)-gmanew)); + here->MOS6tCbd *= capfact; + here->MOS6tCbs *= capfact; + here->MOS6tCj *= capfact; + capfact = (1+model->MOS6bulkJctSideGradingCoeff* + (4e-4*(here->MOS6temp-REFTEMP)-gmanew)); + here->MOS6tCjsw *= capfact; + here->MOS6tDepCap = model->MOS6fwdCapDepCoeff * here->MOS6tBulkPot; + if( (here->MOS6tSatCurDens == 0) || + (here->MOS6drainArea == 0) || + (here->MOS6sourceArea == 0) ) { + here->MOS6sourceVcrit = here->MOS6drainVcrit = + vt*log(vt/(CONSTroot2*here->MOS6tSatCur)); + } else { + here->MOS6drainVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS6tSatCurDens * here->MOS6drainArea)); + here->MOS6sourceVcrit = + vt * log( vt / (CONSTroot2 * + here->MOS6tSatCurDens * here->MOS6sourceArea)); + } + + if(model->MOS6capBDGiven) { + czbd = here->MOS6tCbd; + } else { + if(model->MOS6bulkCapFactorGiven) { + czbd=here->MOS6tCj*here->MOS6drainArea; + } else { + czbd=0; + } + } + if(model->MOS6sideWallCapFactorGiven) { + czbdsw= here->MOS6tCjsw * here->MOS6drainPerimiter; + } else { + czbdsw=0; + } + arg = 1-model->MOS6fwdCapDepCoeff; + sarg = exp( (-model->MOS6bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS6bulkJctSideGradingCoeff) * log(arg) ); + here->MOS6Cbd = czbd; + here->MOS6Cbdsw = czbdsw; + here->MOS6f2d = czbd*(1-model->MOS6fwdCapDepCoeff* + (1+model->MOS6bulkJctBotGradingCoeff))* sarg/arg + + czbdsw*(1-model->MOS6fwdCapDepCoeff* + (1+model->MOS6bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS6f3d = czbd * model->MOS6bulkJctBotGradingCoeff * sarg/arg/ + here->MOS6tBulkPot + + czbdsw * model->MOS6bulkJctSideGradingCoeff * sargsw/arg / + here->MOS6tBulkPot; + here->MOS6f4d = czbd*here->MOS6tBulkPot*(1-arg*sarg)/ + (1-model->MOS6bulkJctBotGradingCoeff) + + czbdsw*here->MOS6tBulkPot*(1-arg*sargsw)/ + (1-model->MOS6bulkJctSideGradingCoeff) + -here->MOS6f3d/2* + (here->MOS6tDepCap*here->MOS6tDepCap) + -here->MOS6tDepCap * here->MOS6f2d; + if(model->MOS6capBSGiven) { + czbs=here->MOS6tCbs; + } else { + if(model->MOS6bulkCapFactorGiven) { + czbs=here->MOS6tCj*here->MOS6sourceArea; + } else { + czbs=0; + } + } + if(model->MOS6sideWallCapFactorGiven) { + czbssw = here->MOS6tCjsw * here->MOS6sourcePerimiter; + } else { + czbssw=0; + } + arg = 1-model->MOS6fwdCapDepCoeff; + sarg = exp( (-model->MOS6bulkJctBotGradingCoeff) * log(arg) ); + sargsw = exp( (-model->MOS6bulkJctSideGradingCoeff) * log(arg) ); + here->MOS6Cbs = czbs; + here->MOS6Cbssw = czbssw; + here->MOS6f2s = czbs*(1-model->MOS6fwdCapDepCoeff* + (1+model->MOS6bulkJctBotGradingCoeff))* sarg/arg + + czbssw*(1-model->MOS6fwdCapDepCoeff* + (1+model->MOS6bulkJctSideGradingCoeff))* + sargsw/arg; + here->MOS6f3s = czbs * model->MOS6bulkJctBotGradingCoeff * sarg/arg/ + here->MOS6tBulkPot + + czbssw * model->MOS6bulkJctSideGradingCoeff * sargsw/arg / + here->MOS6tBulkPot; + here->MOS6f4s = czbs*here->MOS6tBulkPot*(1-arg*sarg)/ + (1-model->MOS6bulkJctBotGradingCoeff) + + czbssw*here->MOS6tBulkPot*(1-arg*sargsw)/ + (1-model->MOS6bulkJctSideGradingCoeff) + -here->MOS6f3s/2* + (here->MOS6tDepCap*here->MOS6tDepCap) + -here->MOS6tDepCap * here->MOS6f2s; + + + if(model->MOS6drainResistanceGiven) { + if(model->MOS6drainResistance != 0) { + here->MOS6drainConductance = 1/model->MOS6drainResistance; + } else { + here->MOS6drainConductance = 0; + } + } else if (model->MOS6sheetResistanceGiven) { + if( (!here->MOS6drainSquaresGiven) || + ( here->MOS6drainSquares==0) ){ + here->MOS6drainSquares=1; + } + if(model->MOS6sheetResistance != 0) { + here->MOS6drainConductance = + 1/(model->MOS6sheetResistance*here->MOS6drainSquares); + } else { + here->MOS6drainConductance = 0; + } + } else { + here->MOS6drainConductance = 0; + } + if(model->MOS6sourceResistanceGiven) { + if(model->MOS6sourceResistance != 0) { + here->MOS6sourceConductance = 1/model->MOS6sourceResistance; + } else { + here->MOS6sourceConductance = 0; + } + } else if (model->MOS6sheetResistanceGiven) { + if( (!here->MOS6sourceSquaresGiven) || + ( here->MOS6sourceSquares==0) ) { + here->MOS6sourceSquares=1; + } + if(model->MOS6sheetResistance != 0) { + here->MOS6sourceConductance = + 1/(model->MOS6sheetResistance*here->MOS6sourceSquares); + } else { + here->MOS6sourceConductance = 0; + } + } else { + here->MOS6sourceConductance = 0; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/mos6/mos6trun.c b/src/spicelib/devices/mos6/mos6trun.c new file mode 100644 index 000000000..992304b69 --- /dev/null +++ b/src/spicelib/devices/mos6/mos6trun.c @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1989 Takayasu Sakurai +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "mos6defs.h" +#include "sperror.h" +#include "suffix.h" + + +int +MOS6trunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; +{ + register MOS6model *model = (MOS6model *)inModel; + register MOS6instance *here; + + for( ; model != NULL; model = model->MOS6nextModel) { + for(here=model->MOS6instances;here!=NULL;here = here->MOS6nextInstance){ + if (here->MOS6owner != ARCHme) continue; + + CKTterr(here->MOS6qgs,ckt,timeStep); + CKTterr(here->MOS6qgd,ckt,timeStep); + CKTterr(here->MOS6qgb,ckt,timeStep); + } + } + return(OK); +} diff --git a/src/spicelib/devices/res/ChangeLog b/src/spicelib/devices/res/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/res/Makefile.am b/src/spicelib/devices/res/Makefile.am new file mode 100644 index 000000000..bf50f74ad --- /dev/null +++ b/src/spicelib/devices/res/Makefile.am @@ -0,0 +1,30 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libres.la + +libres_la_SOURCES = \ + res.c \ + resask.c \ + resdefs.h \ + resdel.c \ + resdest.c \ + resext.h \ + resitf.h \ + resload.c \ + resmask.c \ + resmdel.c \ + resmpar.c \ + resnoise.c \ + resparam.c \ + respzld.c \ + ressacl.c \ + ressetup.c \ + ressload.c \ + ressprt.c \ + ressset.c \ + restemp.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/res/res.c b/src/spicelib/devices/res/res.c new file mode 100644 index 000000000..050cb1080 --- /dev/null +++ b/src/spicelib/devices/res/res.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "resdefs.h" +#include "devdefs.h" +#include "ifsim.h" + +IFparm RESpTable[] = { /* parameters */ + IOPP( "resistance", RES_RESIST, IF_REAL,"Resistance"), + IOPPA( "ac", RES_ACRESIST, IF_REAL, "AC resistance value"), + IOPZU( "temp", RES_TEMP, IF_REAL,"Instance operating temperature"), + IOPQU( "l", RES_LENGTH, IF_REAL,"Length"), + IOPZU( "w", RES_WIDTH, IF_REAL,"Width"), + IP( "sens_resist", RES_RESIST_SENS, IF_FLAG, + "flag to request sensitivity WRT resistance"), + OP( "i", RES_CURRENT,IF_REAL,"Current"), + OP( "p", RES_POWER, IF_REAL,"Power"), + OPU( "sens_dc", RES_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU( "sens_real",RES_QUEST_SENS_REAL,IF_REAL, + "dc sensitivity and real part of ac sensitivity"), + OPU( "sens_imag",RES_QUEST_SENS_IMAG,IF_REAL, + "dc sensitivity and imag part of ac sensitivity"), + OPU( "sens_mag", RES_QUEST_SENS_MAG, IF_REAL, "ac sensitivity of magnitude"), + OPU( "sens_ph", RES_QUEST_SENS_PH, IF_REAL, "ac sensitivity of phase"), + OPU( "sens_cplx",RES_QUEST_SENS_CPLX,IF_COMPLEX, "ac sensitivity") +} ; + +IFparm RESmPTable[] = { /* model parameters */ + IOPQ( "rsh", RES_MOD_RSH, IF_REAL,"Sheet resistance"), + IOPZ( "narrow", RES_MOD_NARROW, IF_REAL,"Narrowing of resistor"), + IOPQ( "tc1", RES_MOD_TC1, IF_REAL,"First order temp. coefficient"), + IOPQO( "tc2", RES_MOD_TC2, IF_REAL,"Second order temp. coefficient"), + IOPX( "defw", RES_MOD_DEFWIDTH, IF_REAL,"Default device width"), + IOPXU("tnom", RES_MOD_TNOM, IF_REAL,"Parameter measurement temperature"), + IP( "r", RES_MOD_R, IF_FLAG,"Device is a resistor model") +}; + +char *RESnames[] = { + "R+", + "R-" +}; + +int RESnSize = NUMELEMS(RESnames); +int RESpTSize = NUMELEMS(RESpTable); +int RESmPTSize = NUMELEMS(RESmPTable); +int RESiSize = sizeof(RESinstance); +int RESmSize = sizeof(RESmodel); diff --git a/src/spicelib/devices/res/resask.c b/src/spicelib/devices/res/resask.c new file mode 100644 index 000000000..23523d847 --- /dev/null +++ b/src/spicelib/devices/res/resask.c @@ -0,0 +1,139 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "resdefs.h" +#include "ifsim.h" +#include "cktdefs.h" +#include "sperror.h" + + +int +RESask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, + IFvalue *select) +{ + RESinstance *fast = (RESinstance *)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case RES_TEMP: + value->rValue = fast->REStemp-CONSTCtoK; + return(OK); + case RES_CONDUCT: + value->rValue = fast->RESconduct; + return(OK); + case RES_RESIST: + value->rValue = fast->RESresist; + return(OK); + case RES_ACCONDUCT: + value->rValue = fast->RESacConduct; + return (OK); + case RES_ACRESIST: + value->rValue = fast->RESacResist; + return(OK); + case RES_LENGTH: + value->rValue = fast->RESlength; + return(OK); + case RES_WIDTH : + value->rValue = fast->RESwidth; + return(OK); + case RES_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + fast->RESsenParmNo); + } + return(OK); + case RES_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + fast->RESsenParmNo); + } + return(OK); + case RES_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + fast->RESsenParmNo); + } + return(OK); + case RES_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + fast->RESsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + fast->RESsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case RES_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + fast->RESsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + fast->RESsenParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case RES_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + fast->RESsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + fast->RESsenParmNo); + } + return(OK); + case RES_CURRENT: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "RESask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = (*(ckt->CKTrhsOld + fast->RESposNode) - + *(ckt->CKTrhsOld + fast->RESnegNode)) + *fast->RESconduct; + } + return(OK); + case RES_POWER: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "RESask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = (*(ckt->CKTrhsOld + fast->RESposNode) - + *(ckt->CKTrhsOld + fast->RESnegNode)) * + fast->RESconduct * + (*(ckt->CKTrhsOld + fast->RESposNode) - + *(ckt->CKTrhsOld + fast->RESnegNode)); + } + return(OK); + default: + return(E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/res/resdefs.h b/src/spicelib/devices/res/resdefs.h new file mode 100644 index 000000000..dee61c485 --- /dev/null +++ b/src/spicelib/devices/res/resdefs.h @@ -0,0 +1,123 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef RES +#define RES + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + + /* definitions used to describe resistors */ + + +/* information used to describe a single instance */ + +typedef struct sRESinstance { + struct sRESmodel *RESmodPtr; /* backpointer to model */ + struct sRESinstance *RESnextInstance; /* pointer to next instance of + * current model*/ + + IFuid RESname; /* pointer to character string naming this instance */ + int RESowner; /* number of owner process */ + int RESstate; /* not used */ + int RESposNode; /* number of positive node of resistor */ + int RESnegNode; /* number of negative node of resistor */ + + double REStemp; /* temperature at which this resistor operates */ + double RESconduct; /* conductance at current analysis temperature */ + double RESresist; /* resistance at temperature Tnom */ +/* serban */ + double RESacResist; /* AC resistance, useful for fancy .ac analyses */ + double RESacConduct; /* AC conductance */ + double RESwidth; /* width of the resistor */ + double RESlength; /* length of the resistor */ + double *RESposPosptr; /* pointer to sparse matrix diagonal at + * (positive,positive) */ + double *RESnegNegptr; /* pointer to sparse matrix diagonal at + * (negative,negative) */ + double *RESposNegptr; /* pointer to sparse matrix offdiagonal at + * (positive,negative) */ + double *RESnegPosptr; /* pointer to sparse matrix offdiagonal at + * (negative,positive) */ + unsigned RESresGiven : 1; /* flag to indicate resistance was specified */ + unsigned RESwidthGiven : 1; /* flag to indicate width given */ + unsigned RESlengthGiven : 1; /* flag to indicate length given */ + unsigned REStempGiven : 1; /* indicates temperature specified */ +/* serban */ + unsigned RESacresGiven : 1; /* indicates AC value specified */ + int RESsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ +#ifndef NONOISE + double RESnVar[NSTATVARS]; +#else /* NONOISE */ + double *RESnVar; +#endif /* NONOISE */ + +} RESinstance ; + + +/* per model data */ + +typedef struct sRESmodel { /* model structure for a resistor */ + int RESmodType; /* type index of this device type */ + struct sRESmodel *RESnextModel; /* pointer to next possible model in + * linked list */ + RESinstance * RESinstances; /* pointer to list of instances that have this + * model */ + IFuid RESmodName; /* pointer to character string naming this model */ + + double REStnom; /* temperature at which resistance measured */ + double REStempCoeff1; /* first temperature coefficient of resistors */ + double REStempCoeff2; /* second temperature coefficient of resistors */ + double RESsheetRes; /* sheet resistance of devices in ohms/square */ + double RESdefWidth; /* default width of a resistor */ + double RESnarrow; /* amount by which device is narrower than drawn */ + unsigned REStnomGiven: 1; /* flag to indicate nominal temp. was given */ + unsigned REStc1Given : 1; /* flag to indicate tc1 was specified */ + unsigned REStc2Given : 1; /* flag to indicate tc2 was specified */ + unsigned RESsheetResGiven :1; /* flag to indicate sheet resistance given*/ + unsigned RESdefWidthGiven :1; /* flag to indicate default width given */ + unsigned RESnarrowGiven :1; /* flag to indicate narrow effect given */ +} RESmodel; + +/* device parameters */ +#define RES_RESIST 1 +#define RES_WIDTH 2 +#define RES_LENGTH 3 +#define RES_CONDUCT 4 +#define RES_RESIST_SENS 5 +#define RES_CURRENT 6 +#define RES_POWER 7 +#define RES_TEMP 8 +/* serban */ +#define RES_ACRESIST 10 +#define RES_ACCONDUCT 11 + + +/* model parameters */ +#define RES_MOD_TC1 101 +#define RES_MOD_TC2 102 +#define RES_MOD_RSH 103 +#define RES_MOD_DEFWIDTH 104 +#define RES_MOD_NARROW 105 +#define RES_MOD_R 106 +#define RES_MOD_TNOM 107 + +/* device questions */ +#define RES_QUEST_SENS_REAL 201 +#define RES_QUEST_SENS_IMAG 202 +#define RES_QUEST_SENS_MAG 203 +#define RES_QUEST_SENS_PH 204 +#define RES_QUEST_SENS_CPLX 205 +#define RES_QUEST_SENS_DC 206 + +/* model questions */ + +#include "resext.h" + +#endif /*RES*/ diff --git a/src/spicelib/devices/res/resdel.c b/src/spicelib/devices/res/resdel.c new file mode 100644 index 000000000..35fe2f4c3 --- /dev/null +++ b/src/spicelib/devices/res/resdel.c @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "resdefs.h" +#include "sperror.h" + + +int +RESdelete(GENmodel *inModel, IFuid name, GENinstance **inst) +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance **fast = (RESinstance **)inst; + RESinstance **prev = NULL; + RESinstance *here; + + for( ; model ; model = model->RESnextModel) { + prev = &(model->RESinstances); + for(here = *prev; here ; here = *prev) { + if(here->RESname == name || (fast && here==*fast) ) { + *prev= here->RESnextInstance; + FREE(here); + return(OK); + } + prev = &(here->RESnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/res/resdest.c b/src/spicelib/devices/res/resdest.c new file mode 100644 index 000000000..aa8be2cb5 --- /dev/null +++ b/src/spicelib/devices/res/resdest.c @@ -0,0 +1,35 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "resdefs.h" + + +void +RESdestroy(GENmodel **inModel) +{ + RESmodel **model = (RESmodel **)inModel; + RESinstance *here; + RESinstance *prev = NULL; + RESmodel *mod = *model; + RESmodel *oldmod = NULL; + + for( ; mod ; mod = mod->RESnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (RESinstance *)NULL; + for(here = mod->RESinstances ; here ; here = here->RESnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/res/resext.h b/src/spicelib/devices/res/resext.h new file mode 100644 index 000000000..ee4be5516 --- /dev/null +++ b/src/spicelib/devices/res/resext.h @@ -0,0 +1,22 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +extern int RESask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int RESdelete(GENmodel*,IFuid,GENinstance**); +extern void RESdestroy(GENmodel**); +extern int RESload(GENmodel*,CKTcircuit*); +extern int RESacload(GENmodel*,CKTcircuit*); +extern int RESmodAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int RESmDelete(GENmodel**,IFuid,GENmodel*); +extern int RESmParam(int,IFvalue*,GENmodel*); +extern int RESparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int RESpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int RESsAcLoad(GENmodel*,CKTcircuit*); +extern int RESsLoad(GENmodel*,CKTcircuit*); +extern int RESsSetup(SENstruct*,GENmodel*); +extern void RESsPrint(GENmodel*,CKTcircuit*); +extern int RESsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int REStemp(GENmodel*,CKTcircuit*); +extern int RESnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); diff --git a/src/spicelib/devices/res/resitf.h b/src/spicelib/devices/res/resitf.h new file mode 100644 index 000000000..bfc6a7e8c --- /dev/null +++ b/src/spicelib/devices/res/resitf.h @@ -0,0 +1,93 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_res + +#ifndef DEV_RES +#define DEV_RES + +#include "resext.h" +extern IFparm RESpTable[ ]; +extern IFparm RESmPTable[ ]; +extern char *RESnames[ ]; +extern int RESpTSize; +extern int RESmPTSize; +extern int RESnSize; +extern int RESiSize; +extern int RESmSize; + +SPICEdev RESinfo = { + { + "Resistor", + "Simple linear resistor", + + &RESnSize, + &RESnSize, + RESnames, + + &RESpTSize, + RESpTable, + + &RESmPTSize, + RESmPTable, + 0 + }, + + RESparam, + RESmParam, + RESload, + RESsetup, + NULL, + RESsetup, + REStemp, + NULL, + NULL, +/* serban - added ac support */ + RESacload, /* ac load and normal load are identical */ + NULL, + RESdestroy, +#ifdef DELETES + RESmDelete, + RESdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + RESask, + RESmodAsk, +#ifdef AN_pz + RESpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense2 + RESsSetup, + RESsLoad, + NULL, + RESsAcLoad, + RESsPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ + NULL, /* Disto */ +#ifdef AN_noise + RESnoise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &RESiSize, + &RESmSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/res/resload.c b/src/spicelib/devices/res/resload.c new file mode 100644 index 000000000..b2754c136 --- /dev/null +++ b/src/spicelib/devices/res/resload.c @@ -0,0 +1,69 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "resdefs.h" +#include "sperror.h" + + +int +RESload(GENmodel *inModel, CKTcircuit *ckt) + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + + *(here->RESposPosptr) += here->RESconduct; + *(here->RESnegNegptr) += here->RESconduct; + *(here->RESposNegptr) -= here->RESconduct; + *(here->RESnegPosptr) -= here->RESconduct; + } + } + return(OK); +} + +int +RESacload(GENmodel *inModel, CKTcircuit *ckt) + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + + if(here->RESacresGiven) { + *(here->RESposPosptr) += here->RESacConduct; + *(here->RESnegNegptr) += here->RESacConduct; + *(here->RESposNegptr) -= here->RESacConduct; + *(here->RESnegPosptr) -= here->RESacConduct; + } else { + *(here->RESposPosptr) += here->RESconduct; + *(here->RESnegNegptr) += here->RESconduct; + *(here->RESposNegptr) -= here->RESconduct; + *(here->RESnegPosptr) -= here->RESconduct; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/res/resmask.c b/src/spicelib/devices/res/resmask.c new file mode 100644 index 000000000..101dc2863 --- /dev/null +++ b/src/spicelib/devices/res/resmask.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + + +#include "ngspice.h" +#include +#include "const.h" +#include "cktdefs.h" +#include "ifsim.h" +#include "resdefs.h" +#include "sperror.h" +#include "devdefs.h" + + +int +RESmodAsk(CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value) +{ + RESmodel *model = (RESmodel *)inModel; + switch(which) { + case RES_MOD_TNOM: + value->rValue = model->REStnom-CONSTCtoK; + return(OK); + case RES_MOD_TC1: + value->rValue = model->REStempCoeff1; + return(OK); + case RES_MOD_TC2: + value->rValue = model->REStempCoeff2; + return(OK); + case RES_MOD_RSH: + value->rValue = model->RESsheetRes; + return(OK); + case RES_MOD_DEFWIDTH: + value->rValue = model->RESdefWidth; + return(OK); + case RES_MOD_NARROW: + value->rValue = model->RESnarrow; + return(OK); + default: + return(E_BADPARM); + } +} + diff --git a/src/spicelib/devices/res/resmdel.c b/src/spicelib/devices/res/resmdel.c new file mode 100644 index 000000000..56c50e9ba --- /dev/null +++ b/src/spicelib/devices/res/resmdel.c @@ -0,0 +1,39 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "resdefs.h" +#include "sperror.h" + + +int +RESmDelete(GENmodel **inModel, IFuid modname, GENmodel *kill) +{ + RESmodel **model = (RESmodel **)inModel; + RESmodel *modfast = (RESmodel *)kill; + RESinstance *here; + RESinstance *prev = NULL; + RESmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->RESnextModel)) { + if( (*model)->RESmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->RESnextModel; /* cut deleted device out of list */ + for(here = (*model)->RESinstances ; here ; here = here->RESnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/res/resmpar.c b/src/spicelib/devices/res/resmpar.c new file mode 100644 index 000000000..5350fdeb8 --- /dev/null +++ b/src/spicelib/devices/res/resmpar.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "resdefs.h" +#include "sperror.h" + + +int +RESmParam(int param, IFvalue *value, GENmodel *inModel) +{ + RESmodel *model = (RESmodel *)inModel; + + switch(param) { + case RES_MOD_TNOM: + model->REStnom = value->rValue+CONSTCtoK; + model->REStnomGiven = TRUE; + break; + case RES_MOD_TC1: + model->REStempCoeff1 = value->rValue; + model->REStc1Given = TRUE; + break; + case RES_MOD_TC2: + model->REStempCoeff2 = value->rValue; + model->REStc2Given = TRUE; + break; + case RES_MOD_RSH: + model->RESsheetRes = value->rValue; + model->RESsheetResGiven = TRUE; + break; + case RES_MOD_DEFWIDTH: + model->RESdefWidth = value->rValue; + model->RESdefWidthGiven = TRUE; + break; + case RES_MOD_NARROW: + model->RESnarrow = value->rValue; + model->RESnarrowGiven = TRUE; + break; + case RES_MOD_R: + /* just being reassured by user that this is a resistor model */ + /* no-op */ + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/res/resnoise.c b/src/spicelib/devices/res/resnoise.c new file mode 100644 index 000000000..777694804 --- /dev/null +++ b/src/spicelib/devices/res/resnoise.c @@ -0,0 +1,155 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "resdefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" + +/* + * RESnoise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with resistors. It starts with the model *firstModel + * and traverses all of its instances. It then proceeds to any other + * models on the linked list. The total output noise density + * generated by all the resistors is summed in the variable "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +RESnoise (int mode, int operation, GENmodel *genmodel, CKTcircuit *ckt, + Ndata *data, double *OnDens) +{ + RESmodel *firstModel = (RESmodel *) genmodel; + RESmodel *model; + RESinstance *inst; + char name[N_MXVLNTH]; + double tempOutNoise; + double tempInNoise; + double noizDens; + double lnNdens; + + + for (model=firstModel; model != NULL; model=model->RESnextModel) { + for (inst=model->RESinstances; inst != NULL; inst=inst->RESnextInstance) { + if (inst->RESowner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name the noise generator */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + (void)sprintf(name,"onoise_%s",inst->RESname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + break; + + case INT_NOIZ: + (void)sprintf(name,"onoise_total_%s",inst->RESname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s",inst->RESname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + NevalSrc(&noizDens,&lnNdens,ckt,THERMNOISE, + inst->RESposNode,inst->RESnegNode,inst->RESconduct); + + *OnDens += noizDens; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + inst->RESnVar[LNLSTDENS] = lnNdens; + + /* clear out our integration variable if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + inst->RESnVar[OUTNOIZ] = 0.0; + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + tempOutNoise = Nintegrate(noizDens, lnNdens, + inst->RESnVar[LNLSTDENS], data); + tempInNoise = Nintegrate(noizDens * + data->GainSqInv ,lnNdens + data->lnGainInv, + inst->RESnVar[LNLSTDENS] + data->lnGainInv, + data); + inst->RESnVar[OUTNOIZ] += tempOutNoise; + inst->RESnVar[INNOIZ] += tempInNoise; + data->outNoiz += tempOutNoise; + data->inNoise += tempInNoise; + inst->RESnVar[LNLSTDENS] = lnNdens; + } + if (data->prtSummary) { + data->outpVector[data->outNumber++] = noizDens; + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + data->outpVector[data->outNumber++] = inst->RESnVar[OUTNOIZ]; + data->outpVector[data->outNumber++] = inst->RESnVar[INNOIZ]; + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} + + diff --git a/src/spicelib/devices/res/resparam.c b/src/spicelib/devices/res/resparam.c new file mode 100644 index 000000000..0bf029de0 --- /dev/null +++ b/src/spicelib/devices/res/resparam.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "const.h" +#include "ifsim.h" +#include "resdefs.h" +#include "sperror.h" + + +int +RESparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) +{ + RESinstance *here = (RESinstance *)inst; + switch(param) { + case RES_TEMP: + here->REStemp = value->rValue+CONSTCtoK; + here->REStempGiven = TRUE; + break; + case RES_RESIST: + here->RESresist = value->rValue; + here->RESresGiven = TRUE; + break; + case RES_ACRESIST: + here->RESacResist = value->rValue; + here->RESacresGiven = TRUE; + break; + case RES_WIDTH: + here->RESwidth = value->rValue; + here->RESwidthGiven = TRUE; + break; + case RES_LENGTH: + here->RESlength = value->rValue; + here->RESlengthGiven = TRUE; + break; + case RES_RESIST_SENS: + here->RESsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/res/respzld.c b/src/spicelib/devices/res/respzld.c new file mode 100644 index 000000000..f861985f7 --- /dev/null +++ b/src/spicelib/devices/res/respzld.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "resdefs.h" + + + +int +RESpzLoad(GENmodel *inModel, CKTcircuit *ckt, SPcomplex *s) + /* actually load the current resistance value into the + * sparse matrix previously provided + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + if (here->RESowner != ARCHme) continue; + + *(here->RESposPosptr) += here->RESconduct; + *(here->RESnegNegptr) += here->RESconduct; + *(here->RESposNegptr) -= here->RESconduct; + *(here->RESnegPosptr) -= here->RESconduct; + } + } + return(OK); +} diff --git a/src/spicelib/devices/res/ressacl.c b/src/spicelib/devices/res/ressacl.c new file mode 100644 index 000000000..3b195414f --- /dev/null +++ b/src/spicelib/devices/res/ressacl.c @@ -0,0 +1,56 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "resdefs.h" +#include "sperror.h" + + +int +RESsAcLoad(GENmodel *inModel, CKTcircuit *ckt) + /* actually load the current ac sensitivity info into the + * array previously provided + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + double vres; + double ivres; + double value; + double ivalue; + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + if (here->RESowner != ARCHme) continue; + + if(here->RESsenParmNo){ + vres = *(ckt->CKTrhsOld+here->RESposNode) - + *(ckt->CKTrhsOld+here->RESnegNode); + ivres = *(ckt->CKTirhsOld+here->RESposNode) - + *(ckt->CKTirhsOld+here->RESnegNode); + value = vres * here->RESconduct * here->RESconduct; + ivalue = ivres * here->RESconduct * here->RESconduct; + + /* load the RHS matrix */ + *(ckt->CKTsenInfo->SEN_RHS[here->RESposNode] + + here->RESsenParmNo) += value; + *(ckt->CKTsenInfo->SEN_iRHS[here->RESposNode] + + here->RESsenParmNo) += ivalue; + *(ckt->CKTsenInfo->SEN_RHS[here->RESnegNode] + + here->RESsenParmNo) -= value; + *(ckt->CKTsenInfo->SEN_iRHS[here->RESnegNode] + + here->RESsenParmNo) -= ivalue; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/res/ressetup.c b/src/spicelib/devices/res/ressetup.c new file mode 100644 index 000000000..805291719 --- /dev/null +++ b/src/spicelib/devices/res/ressetup.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "resdefs.h" +#include "sperror.h" + + +int +RESsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit*ckt, int *state) + /* load the resistor structure with those pointers needed later + * for fast matrix loading + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(RESposPosptr, RESposNode, RESposNode); + TSTALLOC(RESnegNegptr, RESnegNode, RESnegNode); + TSTALLOC(RESposNegptr, RESposNode, RESnegNode); + TSTALLOC(RESnegPosptr, RESnegNode, RESposNode); + } + } + return(OK); +} diff --git a/src/spicelib/devices/res/ressload.c b/src/spicelib/devices/res/ressload.c new file mode 100644 index 000000000..f33601fb5 --- /dev/null +++ b/src/spicelib/devices/res/ressload.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "resdefs.h" +#include "sperror.h" + + +int +RESsLoad(GENmodel *inModel, CKTcircuit *ckt) + /* actually load the current resistance sensitivity value into + * the array previously provided + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + double vres; + double value; + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + + if(here->RESsenParmNo){ + vres = *(ckt->CKTrhsOld+here->RESposNode) - + *(ckt->CKTrhsOld+here->RESnegNode); + value = vres * here->RESconduct * here->RESconduct; + + /* load the RHS matrix */ + *(ckt->CKTsenInfo->SEN_RHS[here->RESposNode] + + here->RESsenParmNo) += value; + *(ckt->CKTsenInfo->SEN_RHS[here->RESnegNode] + + here->RESsenParmNo) -= value; + } + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/res/ressprt.c b/src/spicelib/devices/res/ressprt.c new file mode 100644 index 000000000..3358119f7 --- /dev/null +++ b/src/spicelib/devices/res/ressprt.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +/* Pretty print the sensitivity info for all + * the resistors in the circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "resdefs.h" +#include "sperror.h" + + +void +RESsPrint(GENmodel *inModel, CKTcircuit *ckt) +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + printf("RESISTORS-----------------\n"); + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + printf("Model name:%s\n",model->RESmodName); + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + if (here->RESowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->RESname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->RESposNode),CKTnodName(ckt,here->RESnegNode)); + printf(" Resistance: %f ",here->RESresist); + printf(here->RESresGiven ? "(specified)\n" : "(default)\n"); + printf(" RESsenParmNo:%d\n",here->RESsenParmNo); + + } + } +} diff --git a/src/spicelib/devices/res/ressset.c b/src/spicelib/devices/res/ressset.c new file mode 100644 index 000000000..58880fe01 --- /dev/null +++ b/src/spicelib/devices/res/ressset.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified: Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "resdefs.h" +#include "sperror.h" +#include "cktdefs.h" + + +int +RESsSetup(SENstruct *info, GENmodel *inModel) + /* loop through all the devices and + * assign parameter #s to design parameters + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + if (here->RESowner != ARCHme) continue; + + if(here->RESsenParmNo){ + here->RESsenParmNo = ++(info->SENparms); + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/res/restemp.c b/src/spicelib/devices/res/restemp.c new file mode 100644 index 000000000..77d9060ed --- /dev/null +++ b/src/spicelib/devices/res/restemp.c @@ -0,0 +1,73 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +Modified Apr 2000 - Paolo Nenzi +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "resdefs.h" +#include "sperror.h" + + +int +REStemp(GENmodel *inModel, CKTcircuit *ckt) + /* perform the temperature update to the resistors + * calculate the conductance as a function of the + * given nominal and current temperatures - the + * resistance given in the struct is the nominal + * temperature resistance + */ +{ + RESmodel *model = (RESmodel *)inModel; + RESinstance *here; + double factor; + double difference; + + + /* loop through all the resistor models */ + for( ; model != NULL; model = model->RESnextModel ) { + + /* Default Value Processing for Resistor Models */ + if(!model->REStnomGiven) model->REStnom = ckt->CKTnomTemp; + if(!model->RESsheetResGiven) model->RESsheetRes = 0; + if(!model->RESdefWidthGiven) model->RESdefWidth = 10.e-6; /*M*/ + if(!model->REStc1Given) model->REStempCoeff1 = 0; + if(!model->REStc2Given) model->REStempCoeff2 = 0; + if(!model->RESnarrowGiven) model->RESnarrow = 0; + + /* loop through all the instances of the model */ + for (here = model->RESinstances; here != NULL ; + here=here->RESnextInstance) { + if (here->RESowner != ARCHme) continue; + + /* Default Value Processing for Resistor Instance */ + if(!here->REStempGiven) here->REStemp = ckt->CKTtemp; + if(!here->RESwidthGiven) here->RESwidth = model->RESdefWidth; + if(!here->RESlengthGiven) here->RESlength = 0 ; + if(!here->RESresGiven) { + if(model->RESsheetResGiven && (model->RESsheetRes != 0) && + (here->RESlength != 0)) { + here->RESresist = model->RESsheetRes * (here->RESlength - + model->RESnarrow) / (here->RESwidth - model->RESnarrow); + } else { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: resistance=0, set to 1000",&(here->RESname)); + here->RESresist=1000; + } + } + + difference = here->REStemp - model->REStnom; + factor = 1.0 + (model->REStempCoeff1)*difference + + (model->REStempCoeff2)*difference*difference; + + here->RESconduct = 1.0/(here->RESresist * factor); + + /* Paolo Nenzi: Temperature effects for AC value */ + if(here->RESacresGiven) + here->RESacConduct = 1.0/(here->RESacResist * factor); + } + } + return(OK); +} diff --git a/src/spicelib/devices/sw/ChangeLog b/src/spicelib/devices/sw/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/sw/Makefile.am b/src/spicelib/devices/sw/Makefile.am new file mode 100644 index 000000000..cd450566c --- /dev/null +++ b/src/spicelib/devices/sw/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libsw.la + +libsw_la_SOURCES = \ + sw.c \ + swacload.c \ + swask.c \ + swdefs.h \ + swdelete.c \ + swdest.c \ + swext.h \ + switf.h \ + swload.c \ + swmask.c \ + swmdel.c \ + swmparam.c \ + swnoise.c \ + swparam.c \ + swpzload.c \ + swsetup.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/sw/sw.c b/src/spicelib/devices/sw/sw.c new file mode 100644 index 000000000..c80f25f82 --- /dev/null +++ b/src/spicelib/devices/sw/sw.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "swdefs.h" +#include "suffix.h" + +IFparm SWpTable[] = { /* parameters */ + IP("on", SW_IC_ON, IF_FLAG,"Switch initially closed"), + IP("off", SW_IC_OFF, IF_FLAG,"Switch initially open"), + IOPU("pos_node", SW_POS_NODE,IF_INTEGER,"Positive node of switch"), + IOPU("neg_node", SW_NEG_NODE,IF_INTEGER,"Negative node of switch"), + OPU("cont_p_node",SW_POS_CONT_NODE,IF_INTEGER, + "Positive contr. node of switch"), + OPU("cont_n_node",SW_NEG_CONT_NODE,IF_INTEGER, + "Positive contr. node of switch"), + OP("i", SW_CURRENT, IF_REAL, "Switch current"), + OP("p", SW_POWER, IF_REAL, "Switch power") +}; + +IFparm SWmPTable[] = { /* model parameters */ + IOPU( "sw", SW_MOD_SW, IF_FLAG,"Switch model"), + IOPU( "vt", SW_MOD_VTH, IF_REAL,"Threshold voltage"), + IOPU( "vh", SW_MOD_VHYS, IF_REAL,"Hysteresis voltage"), + IOPU( "ron", SW_MOD_RON, IF_REAL,"Resistance when closed"), + OPU( "gon", SW_MOD_GON, IF_REAL,"Conductance when closed"), + IOPU( "roff", SW_MOD_ROFF, IF_REAL,"Resistance when open"), + OPU( "goff", SW_MOD_GOFF, IF_REAL,"Conductance when open") +}; + +char *SWnames[] = { + "S+", + "S-", + "SC+", + "SC-" +}; + +int SWnSize = NUMELEMS(SWnames); +int SWpTSize = NUMELEMS(SWpTable); +int SWmPTSize = NUMELEMS(SWmPTable); +int SWiSize = sizeof(SWinstance); +int SWmSize = sizeof(SWmodel); diff --git a/src/spicelib/devices/sw/swacload.c b/src/spicelib/devices/sw/swacload.c new file mode 100644 index 000000000..4c3ab45f2 --- /dev/null +++ b/src/spicelib/devices/sw/swacload.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "swdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +SWacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* load the current values into the + * sparse matrix previously provided + * during AC analysis. + */ +{ + register SWmodel *model = (SWmodel *)inModel; + register SWinstance *here; + double g_now; + int current_state; + + /* loop through all the switch models */ + for( ; model != NULL; model = model->SWnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->SWinstances; here != NULL ; + here=here->SWnextInstance) { + if (here->SWowner != ARCHme) continue; + + /* In AC analysis, just propogate the state... */ + + current_state = (int)*(ckt->CKTstate0 + here->SWstate); + + g_now = current_state?(model->SWonConduct):(model->SWoffConduct); + + *(here->SWposPosptr) += g_now; + *(here->SWposNegptr) -= g_now; + *(here->SWnegPosptr) -= g_now; + *(here->SWnegNegptr) += g_now; + } + } + return(OK); +} diff --git a/src/spicelib/devices/sw/swask.c b/src/spicelib/devices/sw/swask.c new file mode 100644 index 000000000..5fec57e3b --- /dev/null +++ b/src/spicelib/devices/sw/swask.c @@ -0,0 +1,78 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal device parameters + * of voltage controlled SWitch + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "swdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +SWask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + SWinstance *here = (SWinstance *)inst; + static char *msg = "Current and power not available in ac analysis"; + + switch(which) { + case SW_POS_NODE: + value->iValue = here->SWposNode; + return (OK); + case SW_NEG_NODE: + value->iValue = here->SWnegNode; + return (OK); + case SW_POS_CONT_NODE: + value->iValue = here->SWposCntrlNode; + return (OK); + case SW_NEG_CONT_NODE: + value->iValue = here->SWnegCntrlNode; + return (OK); + case SW_CURRENT: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "SWask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = (*(ckt->CKTrhsOld + here->SWposNode) + - *(ckt->CKTrhsOld + here->SWnegNode)) * + here->SWcond; + } + return(OK); + case SW_POWER: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "SWask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = (*(ckt->CKTrhsOld + here->SWposNode) + - *(ckt->CKTrhsOld + here->SWnegNode)) * + (*(ckt->CKTrhsOld + here->SWposNode) + - *(ckt->CKTrhsOld + here->SWnegNode)) * + here->SWcond; + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/sw/swdefs.h b/src/spicelib/devices/sw/swdefs.h new file mode 100644 index 000000000..db50cb932 --- /dev/null +++ b/src/spicelib/devices/sw/swdefs.h @@ -0,0 +1,104 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon M. Jacobs +**********/ + +#ifndef SW +#define SW + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" +#include "noisedef.h" + + /* structures used to describe voltage controlled switches */ + + +/* information to describe each instance */ + +typedef struct sSWinstance { + struct sSWmodel *SWmodPtr; /* backpointer to model */ + struct sSWinstance *SWnextInstance; /* pointer to next instance of + * current model*/ + IFuid SWname; /* pointer to character string naming this instance */ + int SWowner; /* number of owner process */ + int SWstate; /* pointer to start of switch's section of state vector */ + + int SWposNode; /* number of positive node of switch */ + int SWnegNode; /* number of negative node of switch */ + int SWposCntrlNode; /* number of positive controlling node of switch */ + int SWnegCntrlNode; /* number of negative controlling node of switch */ + + double *SWposPosptr; /* pointer to sparse matrix diagonal at + (positive,positive) for switch conductance */ + double *SWnegPosptr; /* pointer to sparse matrix offdiagonal at + (neagtive,positive) for switch conductance */ + double *SWposNegptr; /* pointer to sparse matrix offdiagonal at + (positive,neagtive) for switch conductance */ + double *SWnegNegptr; /* pointer to sparse matrix diagonal at + (neagtive,neagtive) for switch conductance */ + + double SWcond; /* conductance of the switch now */ + + unsigned SWzero_stateGiven : 1; /* flag to indicate initial state */ +#ifndef NONOISE + double SWnVar[NSTATVARS]; +#else /* NONOISE */ + double *SWnVar; +#endif /* NONOISE */ +} SWinstance ; + +/* data per model */ + +#define SW_ON_CONDUCTANCE 1.0 /* default on conductance = 1 mho */ +#define SW_OFF_CONDUCTANCE ckt->CKTgmin /* default off conductance */ +#define SW_NUM_STATES 1 + +typedef struct sSWmodel { /* model structure for a switch */ + int SWmodType; /* type index of this device type */ + struct sSWmodel *SWnextModel; /* pointer to next possible model in + * linked list */ + SWinstance *SWinstances; /* pointer to list of instances that have this + * model */ + IFuid SWmodName; /* pointer to character string naming this model */ + + double SWonResistance; /* switch "on" resistance */ + double SWoffResistance; /* switch "off" resistance */ + double SWvThreshold; /* switching threshold voltage */ + double SWvHysteresis; /* switching hysteresis voltage */ + double SWonConduct; /* switch "on" conductance */ + double SWoffConduct; /* switch "off" conductance */ + + unsigned SWonGiven : 1; /* flag to indicate on-resistance was specified */ + unsigned SWoffGiven : 1; /* flag to indicate off-resistance was " */ + unsigned SWthreshGiven : 1; /* flag to indicate threshold volt was given */ + unsigned SWhystGiven : 1; /* flag to indicate hysteresis volt was given */ +} SWmodel; + +/* device parameters */ +#define SW_IC_ON 1 +#define SW_IC_OFF 2 +#define SW_POS_NODE 3 +#define SW_NEG_NODE 4 +#define SW_POS_CONT_NODE 5 +#define SW_NEG_CONT_NODE 6 +#define SW_CURRENT 7 +#define SW_POWER 8 + +/* model parameters */ +#define SW_MOD_SW 101 +#define SW_MOD_RON 102 +#define SW_MOD_ROFF 103 +#define SW_MOD_VTH 104 +#define SW_MOD_VHYS 105 +#define SW_MOD_GON 106 +#define SW_MOD_GOFF 107 + +/* device questions */ + +/* model questions */ + +#include "swext.h" + +#endif /*SW*/ diff --git a/src/spicelib/devices/sw/swdelete.c b/src/spicelib/devices/sw/swdelete.c new file mode 100644 index 000000000..b8c4c5434 --- /dev/null +++ b/src/spicelib/devices/sw/swdelete.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "swdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +SWdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + SWmodel *model = (SWmodel *)inModel; + SWinstance **fast = (SWinstance **)inst; + SWinstance **prev = NULL; + SWinstance *here; + + for( ; model ; model = model->SWnextModel) { + prev = &(model->SWinstances); + for(here = *prev; here ; here = *prev) { + if(here->SWname == name || (fast && here==*fast) ) { + *prev= here->SWnextInstance; + FREE(here); + return(OK); + } + prev = &(here->SWnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/sw/swdest.c b/src/spicelib/devices/sw/swdest.c new file mode 100644 index 000000000..523ae2d90 --- /dev/null +++ b/src/spicelib/devices/sw/swdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "swdefs.h" +#include "suffix.h" + + +void +SWdestroy(inModel) + GENmodel **inModel; +{ + SWmodel **model = (SWmodel**)inModel; + SWinstance *here; + SWinstance *prev = NULL; + SWmodel *mod = *model; + SWmodel *oldmod = NULL; + + for( ; mod ; mod = mod->SWnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (SWinstance *)NULL; + for(here = mod->SWinstances ; here ; here = here->SWnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/sw/swext.h b/src/spicelib/devices/sw/swext.h new file mode 100644 index 000000000..492a540fd --- /dev/null +++ b/src/spicelib/devices/sw/swext.h @@ -0,0 +1,33 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon M. Jacobs +**********/ + +#ifdef __STDC__ +extern int SWacLoad(GENmodel*,CKTcircuit*); +extern int SWask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int SWdelete(GENmodel*,IFuid,GENinstance**); +extern void SWdestroy(GENmodel**); +extern int SWload(GENmodel*,CKTcircuit*); +extern int SWmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int SWmDelete(GENmodel**,IFuid,GENmodel*); +extern int SWmParam(int,IFvalue*,GENmodel*); +extern int SWparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int SWpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int SWsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int SWnoise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*); +#else /* stdc */ +extern int SWacLoad(); +extern int SWask(); +extern int SWdelete(); +extern void SWdestroy(); +extern int SWload(); +extern int SWmAsk(); +extern int SWmDelete(); +extern int SWmParam(); +extern int SWparam(); +extern int SWpzLoad(); +extern int SWsetup(); +extern int SWnoise(); +#endif /* stdc */ + diff --git a/src/spicelib/devices/sw/switf.h b/src/spicelib/devices/sw/switf.h new file mode 100644 index 000000000..eb292972f --- /dev/null +++ b/src/spicelib/devices/sw/switf.h @@ -0,0 +1,83 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_sw + +#ifndef DEV_SW +#define DEV_SW + +#include "swext.h" +extern IFparm SWpTable[ ]; +extern IFparm SWmPTable[ ]; +extern char *SWnames[ ]; +extern int SWpTSize; +extern int SWmPTSize; +extern int SWnSize; +extern int SWiSize; +extern int SWmSize; + +SPICEdev SWinfo = { + { + "Switch", + "Ideal voltage controlled switch", + + &SWnSize, + &SWnSize, + SWnames, + + &SWpTSize, + SWpTable, + + &SWmPTSize, + SWmPTable, + 0 + }, + + SWparam, + SWmParam, + SWload, + SWsetup, + NULL, + SWsetup, + NULL, + NULL, + NULL, + SWacLoad, + NULL, + SWdestroy, +#ifdef DELETES + SWmDelete, + SWdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + SWask, + SWmAsk, +#ifdef AN_pz + SWpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* DISTO */ +#ifdef AN_noise + SWnoise, +#else /* AN_noise */ + NULL, +#endif /* AN_noise */ + + &SWiSize, + &SWmSize + +}; + +#endif +#endif diff --git a/src/spicelib/devices/sw/swload.c b/src/spicelib/devices/sw/swload.c new file mode 100644 index 000000000..16eea80b6 --- /dev/null +++ b/src/spicelib/devices/sw/swload.c @@ -0,0 +1,111 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "swdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +SWload(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current values into the + * sparse matrix previously provided + */ +{ + register SWmodel *model = (SWmodel *) inModel; + register SWinstance *here; + double g_now; + double v_ctrl; + double previous_state; + double current_state; + + /* loop through all the switch models */ + for( ; model != NULL; model = model->SWnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->SWinstances; here != NULL ; + here=here->SWnextInstance) { + if (here->SWowner != ARCHme) continue; + + /* decide the state of the switch */ + + if(ckt->CKTmode & (MODEINITFIX|MODEINITJCT)) { + + if(here->SWzero_stateGiven) { + /* switch specified "on" */ + *(ckt->CKTstate0 + here->SWstate) = 1.0; + current_state = 1.0; + } else { + *(ckt->CKTstate0 + here->SWstate) = 0.0; + current_state = 0.0; + } + + } else if (ckt->CKTmode & (MODEINITSMSIG)) { + + previous_state = *(ckt->CKTstate0 + here->SWstate); + current_state = previous_state; + + } else if (ckt->CKTmode & (MODEINITFLOAT)) { + + /* use state0 since INITTRAN or INITPRED already called */ + previous_state = *(ckt->CKTstate0 + here->SWstate); + v_ctrl = *(ckt->CKTrhsOld + here->SWposCntrlNode) + - *(ckt->CKTrhsOld + here->SWnegCntrlNode); + if(v_ctrl > (model->SWvThreshold + model->SWvHysteresis)) { + *(ckt->CKTstate0 + here->SWstate) = 1.0; + current_state = 1.0; + } else if(v_ctrl < (model->SWvThreshold - + model->SWvHysteresis)) { + *(ckt->CKTstate0 + here->SWstate) = 0.0; + current_state = 0.0; + } else { + current_state = previous_state; + } + + if(current_state != previous_state) { + ckt->CKTnoncon++; /* ensure one more iteration */ + ckt->CKTtroubleElt = (GENinstance *) here; + } + + + } else if(ckt->CKTmode & (MODEINITTRAN|MODEINITPRED) ) { + + previous_state = *(ckt->CKTstate1 + here->SWstate); + v_ctrl = *(ckt->CKTrhsOld + here->SWposCntrlNode) + - *(ckt->CKTrhsOld + here->SWnegCntrlNode); + + if(v_ctrl > (model->SWvThreshold + model->SWvHysteresis)) { + current_state = 1.0; + } else if(v_ctrl < (model->SWvThreshold - + model->SWvHysteresis)) { + current_state = 0.0; + } else { + current_state = previous_state; + } + + if(current_state == 0) { + *(ckt->CKTstate0 + here->SWstate) = 0.0; + } else { + *(ckt->CKTstate0 + here->SWstate) = 1.0; + } + + } + + g_now = current_state?(model->SWonConduct):(model->SWoffConduct); + here->SWcond = g_now; + + *(here->SWposPosptr) += g_now; + *(here->SWposNegptr) -= g_now; + *(here->SWnegPosptr) -= g_now; + *(here->SWnegNegptr) += g_now; + } + } + return(OK); +} diff --git a/src/spicelib/devices/sw/swmask.c b/src/spicelib/devices/sw/swmask.c new file mode 100644 index 000000000..1d737acdf --- /dev/null +++ b/src/spicelib/devices/sw/swmask.c @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal model parameter + * of voltage controlled SWitch + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "swdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +SWmAsk(ckt,inModel,which,value) + CKTcircuit *ckt; + GENmodel *inModel; + int which; + IFvalue *value; +{ + SWmodel *model = (SWmodel *)inModel; + switch(which) { + case SW_MOD_RON: + value->rValue = model->SWonResistance; + return (OK); + case SW_MOD_ROFF: + value->rValue = model->SWoffResistance; + return (OK); + case SW_MOD_VTH: + value->rValue = model->SWvThreshold; + return (OK); + case SW_MOD_VHYS: + value->rValue = model->SWvHysteresis; + return (OK); + case SW_MOD_GON: + value->rValue = model->SWonConduct; + return (OK); + case SW_MOD_GOFF: + value->rValue = model->SWoffConduct; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/sw/swmdel.c b/src/spicelib/devices/sw/swmdel.c new file mode 100644 index 000000000..f1ed0ce0e --- /dev/null +++ b/src/spicelib/devices/sw/swmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "swdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +SWmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + SWmodel **model = (SWmodel **)inModel; + SWmodel *modfast = (SWmodel *)kill; + SWinstance *here; + SWinstance *prev = NULL; + SWmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->SWnextModel)) { + if( (*model)->SWmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->SWnextModel; /* cut deleted device out of list */ + for(here = (*model)->SWinstances ; here ; here = here->SWnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/sw/swmparam.c b/src/spicelib/devices/sw/swmparam.c new file mode 100644 index 000000000..b337adfc2 --- /dev/null +++ b/src/spicelib/devices/sw/swmparam.c @@ -0,0 +1,53 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "swdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +int +SWmParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + SWmodel *model = (SWmodel *)inModel; + switch(param) { + case SW_MOD_SW: + /* just says that this is a switch */ + break; + case SW_MOD_RON: + model->SWonResistance = value->rValue; + model->SWonConduct = 1.0/(value->rValue); + model->SWonGiven = TRUE; + break; + case SW_MOD_ROFF: + model->SWoffResistance = value->rValue; + model->SWoffConduct = 1.0/(value->rValue); + model->SWoffGiven = TRUE; + break; + case SW_MOD_VTH: + /* take absolute value of hysteresis voltage */ + model->SWvThreshold = value->rValue; + model->SWthreshGiven = TRUE; + break; + case SW_MOD_VHYS: + /* take absolute value of hysteresis voltage */ + model->SWvHysteresis = (value->rValue < 0) ? -(value->rValue) : + value->rValue; + model->SWhystGiven = TRUE; + break; + default: + return(E_BADPARM); + } + + return(OK); +} diff --git a/src/spicelib/devices/sw/swnoise.c b/src/spicelib/devices/sw/swnoise.c new file mode 100644 index 000000000..2c5484e84 --- /dev/null +++ b/src/spicelib/devices/sw/swnoise.c @@ -0,0 +1,162 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Gary W. Ng +**********/ + +#include "ngspice.h" +#include +#include "swdefs.h" +#include "cktdefs.h" +#include "fteconst.h" +#include "iferrmsg.h" +#include "noisedef.h" +#include "suffix.h" + +/* + * SWnoise (mode, operation, firstModel, ckt, data, OnDens) + * This routine names and evaluates all of the noise sources + * associated with voltage- controlled switches. It starts with the + * model *firstModel and traverses all of its instances. It then + * proceeds to any other models on the linked list. The total output + * noise density generated by the SW's is summed in the variable + * "OnDens". + */ + +extern void NevalSrc(); +extern double Nintegrate(); + +int +SWnoise (mode, operation, genmodel, ckt, data, OnDens) + int mode; + int operation; + GENmodel *genmodel; + CKTcircuit *ckt; + register Ndata *data; + double *OnDens; +{ + SWmodel *firstModel = (SWmodel *) genmodel; + register SWmodel *model; + register SWinstance *inst; + char name[N_MXVLNTH]; + double tempOutNoise; + double tempInNoise; + double noizDens; + double lnNdens; + int current_state; + + + for (model=firstModel; model != NULL; model=model->SWnextModel) { + for (inst=model->SWinstances; inst != NULL; inst=inst->SWnextInstance) { + if (inst->SWowner != ARCHme) continue; + + switch (operation) { + + case N_OPEN: + + /* see if we have to to produce a summary report */ + /* if so, name the noise generator */ + + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + switch (mode) { + + case N_DENS: + (void)sprintf(name,"onoise_%s",inst->SWname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + break; + + case INT_NOIZ: + (void)sprintf(name,"onoise_total_%s",inst->SWname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + (void)sprintf(name,"inoise_total_%s",inst->SWname); + + +data->namelist = (IFuid *)trealloc((char *)data->namelist,(data->numPlots + 1)*sizeof(IFuid)); +if (!data->namelist) return(E_NOMEM); + (*(SPfrontEnd->IFnewUid))(ckt, + &(data->namelist[data->numPlots++]), + (IFuid)NULL,name,UID_OTHER,(void **)NULL); + /* we've added one more plot */ + + + break; + } + } + break; + + case N_CALC: + switch (mode) { + + case N_DENS: + current_state = *(ckt->CKTstate0 + inst->SWstate); + NevalSrc(&noizDens,&lnNdens,ckt,THERMNOISE, + inst->SWposNode,inst->SWnegNode, + current_state?(model->SWonConduct):(model->SWoffConduct)); + + *OnDens += noizDens; + + if (data->delFreq == 0.0) { + + /* if we haven't done any previous integration, we need to */ + /* initialize our "history" variables */ + + inst->SWnVar[LNLSTDENS] = lnNdens; + + /* clear out our integration variable if it's the first pass */ + + if (data->freq == ((NOISEAN*)ckt->CKTcurJob)->NstartFreq) { + inst->SWnVar[OUTNOIZ] = 0.0; + } + } else { /* data->delFreq != 0.0 (we have to integrate) */ + tempOutNoise = Nintegrate(noizDens, lnNdens, + inst->SWnVar[LNLSTDENS], data); + tempInNoise = Nintegrate(noizDens * + data->GainSqInv ,lnNdens + data->lnGainInv, + inst->SWnVar[LNLSTDENS] + data->lnGainInv, + data); + inst->SWnVar[OUTNOIZ] += tempOutNoise; + inst->SWnVar[INNOIZ] += tempInNoise; + data->outNoiz += tempOutNoise; + data->inNoise += tempInNoise; + inst->SWnVar[LNLSTDENS] = lnNdens; + } + if (data->prtSummary) { + data->outpVector[data->outNumber++] = noizDens; + } + break; + + case INT_NOIZ: /* already calculated, just output */ + if (((NOISEAN*)ckt->CKTcurJob)->NStpsSm != 0) { + data->outpVector[data->outNumber++] = inst->SWnVar[OUTNOIZ]; + data->outpVector[data->outNumber++] = inst->SWnVar[INNOIZ]; + } /* if */ + break; + } /* switch (mode) */ + break; + + case N_CLOSE: + return (OK); /* do nothing, the main calling routine will close */ + break; /* the plots */ + } /* switch (operation) */ + } /* for inst */ + } /* for model */ + +return(OK); +} diff --git a/src/spicelib/devices/sw/swparam.c b/src/spicelib/devices/sw/swparam.c new file mode 100644 index 000000000..8eab88353 --- /dev/null +++ b/src/spicelib/devices/sw/swparam.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "swdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +SWparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + SWinstance *here = (SWinstance *)inst; + switch(param) { + case SW_IC_ON: + if(value->iValue) { + here->SWzero_stateGiven = TRUE; + } + break; + case SW_IC_OFF: + if(value->iValue) { + here->SWzero_stateGiven = FALSE; + } + break; + default: + return(E_BADPARM); + } + + return(OK); +} diff --git a/src/spicelib/devices/sw/swpzload.c b/src/spicelib/devices/sw/swpzload.c new file mode 100644 index 000000000..da36352b3 --- /dev/null +++ b/src/spicelib/devices/sw/swpzload.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "swdefs.h" +#include "sperror.h" +#include "complex.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +SWpzLoad(inModel,ckt,s) + GENmodel *inModel; + register CKTcircuit *ckt; + SPcomplex *s; + /* load the current values into the + * sparse matrix previously provided + * during AC analysis. + */ +{ + register SWmodel *model = (SWmodel *)inModel; + register SWinstance *here; + double g_now; + int current_state; + + /* loop through all the switch models */ + for( ; model != NULL; model = model->SWnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->SWinstances; here != NULL ; + here=here->SWnextInstance) { + if (here->SWowner != ARCHme) continue; + + /* In AC analysis, just propogate the state... */ + + current_state = (int)*(ckt->CKTstate0 + here->SWstate); + + g_now = current_state?(model->SWonConduct):(model->SWoffConduct); + + *(here->SWposPosptr) += g_now; + *(here->SWposNegptr) -= g_now; + *(here->SWnegPosptr) -= g_now; + *(here->SWnegNegptr) += g_now; + } + } + return(OK); +} diff --git a/src/spicelib/devices/sw/swsetup.c b/src/spicelib/devices/sw/swsetup.c new file mode 100644 index 000000000..4a6b9505b --- /dev/null +++ b/src/spicelib/devices/sw/swsetup.c @@ -0,0 +1,73 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Gordon Jacobs +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "swdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +SWsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; + /* load the switch conductance with those pointers needed later + * for fast matrix loading + */ +{ + register SWmodel *model = (SWmodel *)inModel; + register SWinstance *here; + + /* loop through all the current source models */ + for( ; model != NULL; model = model->SWnextModel ) { + /* Default Value Processing for Switch Model */ + if (!model->SWthreshGiven) { + model->SWvThreshold = 0; + } + if (!model->SWhystGiven) { + model->SWvHysteresis = 0; + } + if (!model->SWonGiven) { + model->SWonConduct = SW_ON_CONDUCTANCE; + model->SWonResistance = 1.0/model->SWonConduct; + } + if (!model->SWoffGiven) { + model->SWoffConduct = SW_OFF_CONDUCTANCE; + model->SWoffResistance = 1.0/model->SWoffConduct; + } + + /* loop through all the instances of the model */ + for (here = model->SWinstances; here != NULL ; + here=here->SWnextInstance) { + if (here->SWowner != ARCHme) goto matrixpointers; + + here->SWstate = *states; + *states += SW_NUM_STATES; + + /* Default Value Processing for Switch Instance */ + /* none */ + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + +matrixpointers: + TSTALLOC(SWposPosptr, SWposNode, SWposNode) + TSTALLOC(SWposNegptr, SWposNode, SWnegNode) + TSTALLOC(SWnegPosptr, SWnegNode, SWposNode) + TSTALLOC(SWnegNegptr, SWnegNode, SWnegNode) + } + } + return(OK); +} diff --git a/src/spicelib/devices/tra/ChangeLog b/src/spicelib/devices/tra/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/tra/Makefile.am b/src/spicelib/devices/tra/Makefile.am new file mode 100644 index 000000000..669b84e84 --- /dev/null +++ b/src/spicelib/devices/tra/Makefile.am @@ -0,0 +1,25 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libtra.la + +libtra_la_SOURCES = \ + tra.c \ + traacct.c \ + traacld.c \ + traask.c \ + tradefs.h \ + tradel.c \ + tradest.c \ + traext.h \ + traitf.h \ + traload.c \ + tramdel.c \ + traparam.c \ + trasetup.c \ + tratemp.c \ + tratrunc.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/tra/tra.c b/src/spicelib/devices/tra/tra.c new file mode 100644 index 000000000..cde047471 --- /dev/null +++ b/src/spicelib/devices/tra/tra.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "tradefs.h" +#include "suffix.h" + +IFparm TRApTable[] = { /* parameters */ + IOPU( "z0", TRA_Z0, IF_REAL , "Characteristic impedance"), + IOPR( "zo", TRA_Z0, IF_REAL , "Characteristic impedance"), + IOPAU( "f", TRA_FREQ, IF_REAL , "Frequency"), + IOPAU( "td", TRA_TD, IF_REAL , "Transmission delay"), + IOPAU( "nl", TRA_NL, IF_REAL , "Normalized length at frequency given"), + IOPAU( "v1", TRA_V1, IF_REAL , "Initial voltage at end 1"), + IOPAU( "v2", TRA_V2, IF_REAL , "Initial voltage at end 2"), + IOPAU( "i1", TRA_I1, IF_REAL , "Initial current at end 1"), + IOPAU( "i2", TRA_I2, IF_REAL , "Initial current at end 2"), + IP("ic", TRA_IC, IF_REALVEC,"Initial condition vector:v1,i1,v2,i2"), + OP("rel", TRA_RELTOL, IF_REAL , "Rel. rate of change of deriv. for bkpt"), + OP("abs", TRA_ABSTOL, IF_REAL , "Abs. rate of change of deriv. for bkpt"), + OPU( "pos_node1",TRA_POS_NODE1,IF_INTEGER,"Positive node of end 1 of t. line"), + OPU( "neg_node1",TRA_NEG_NODE1,IF_INTEGER,"Negative node of end 1 of t. line"), + OPU( "pos_node2",TRA_POS_NODE2,IF_INTEGER,"Positive node of end 2 of t. line"), + OPU( "neg_node2",TRA_NEG_NODE2,IF_INTEGER,"Negative node of end 2 of t. line"), + OPU( "delays",TRA_DELAY, IF_REALVEC, "Delayed values of excitation") +}; + +char *TRAnames[] = { + "P1+", + "P1-", + "P2+", + "P2-" +}; + +int TRAnSize = NUMELEMS(TRAnames); +int TRApTSize = NUMELEMS(TRApTable); +int TRAmPTSize = 0; +int TRAiSize = sizeof(TRAinstance); +int TRAmSize = sizeof(TRAmodel); diff --git a/src/spicelib/devices/tra/traacct.c b/src/spicelib/devices/tra/traacct.c new file mode 100644 index 000000000..c42ced7de --- /dev/null +++ b/src/spicelib/devices/tra/traacct.c @@ -0,0 +1,134 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +TRAaccept(ckt,inModel) + register CKTcircuit *ckt; + GENmodel *inModel; +{ + register TRAmodel *model = (TRAmodel *)inModel; + register TRAinstance *here; + register int i=0,j; + double v1,v2,v3,v4; + double v5,v6,d1,d2,d3,d4; + double *from,*to; + int error; + + + /* loop through all the transmission line models */ + for( ; model != NULL; model = model->TRAnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->TRAinstances; here != NULL ; + here=here->TRAnextInstance) { + if (here->TRAowner != ARCHme) continue; /* XXX */ + + if( (ckt->CKTtime - here->TRAtd) > *(here->TRAdelays+6)) { + /* shift! */ + for(i=2;iTRAsizeDelay && + (ckt->CKTtime - here->TRAtd > *(here->TRAdelays+3*i));i++) + { /* loop does it all */ ; } + i -= 2; + for(j=i;j<=here->TRAsizeDelay;j++) { + from = here->TRAdelays + 3*j; + to = here->TRAdelays + 3*(j-i); + *(to) = *(from); + *(to+1) = *(from+1); + *(to+2) = *(from+2); + } + here->TRAsizeDelay -= i; + } + if(ckt->CKTtime - *(here->TRAdelays+3*here->TRAsizeDelay) > + ckt->CKTminBreak) { + if(here->TRAallocDelay <= here->TRAsizeDelay) { + /* need to grab some more space */ + here->TRAallocDelay += 5; + here->TRAdelays = (double *)REALLOC((char *)here->TRAdelays, + (here->TRAallocDelay+1)*3*sizeof(double)); + } + here->TRAsizeDelay ++; + to = (here->TRAdelays +3*here->TRAsizeDelay); + *to = ckt->CKTtime; + to = (here->TRAdelays+1+3*here->TRAsizeDelay); + *to = ( *(ckt->CKTrhsOld + here->TRAposNode2) + -*(ckt->CKTrhsOld + here->TRAnegNode2)) + + *(ckt->CKTrhsOld + here->TRAbrEq2)* + here->TRAimped; + *(here->TRAdelays+2+3*here->TRAsizeDelay) = + ( *(ckt->CKTrhsOld + here->TRAposNode1) + -*(ckt->CKTrhsOld + here->TRAnegNode1)) + + *(ckt->CKTrhsOld + here->TRAbrEq1)* + here->TRAimped; +#ifdef NOTDEF + v1 = *(here->TRAdelays+1+3*here->TRAsizeDelay); + v2 = *(here->TRAdelays+1+3*(here->TRAsizeDelay-1)); + v3 = *(here->TRAdelays+2+3*here->TRAsizeDelay); + v4 = *(here->TRAdelays+2+3*(here->TRAsizeDelay-1)); + if( (fabs(v1-v2) >= 50*ckt->CKTreltol* + MAX(fabs(v1),fabs(v2))+50*ckt->CKTvoltTol) || + (fabs(v3-v4) >= 50*ckt->CKTreltol* + MAX(fabs(v3),fabs(v4))+50*ckt->CKTvoltTol) ) { + /* changing - need to schedule after delay */ + /*printf("%s: at %g set for %g and %g\n",here->TRAname, + ckt->CKTtime, + ckt->CKTtime+here->TRAtd, + *(here->TRAdelays+3*here->TRAsizeDelay-3)+ + here->TRAtd);*/ + error = CKTsetBreak(ckt,ckt->CKTtime+here->TRAtd); + if(error) return(error); + /* also set for break after PREVIOUS point */ + error = CKTsetBreak(ckt, + *(here->TRAdelays+3*here->TRAsizeDelay -3) + + here->TRAtd); + CKTbreakDump(ckt); + if(error) return(error); + } +#else + v1 = *(here->TRAdelays+1+3*here->TRAsizeDelay); + v2 = *(here->TRAdelays+1+3*(here->TRAsizeDelay-1)); + v3 = *(here->TRAdelays+1+3*(here->TRAsizeDelay-2)); + v4 = *(here->TRAdelays+2+3*here->TRAsizeDelay); + v5 = *(here->TRAdelays+2+3*(here->TRAsizeDelay-1)); + v6 = *(here->TRAdelays+2+3*(here->TRAsizeDelay-2)); + d1 = (v1-v2)/ckt->CKTdeltaOld[0]; + d2 = (v2-v3)/ckt->CKTdeltaOld[1]; + d3 = (v4-v5)/ckt->CKTdeltaOld[0]; + d4 = (v5-v6)/ckt->CKTdeltaOld[1]; + /*printf("%s: at %g derivs are %g, %g and %g, %g\n", + here->TRAname,ckt->CKTtime,d1,d2,d3,d4);*/ + if( (fabs(d1-d2) >= here->TRAreltol*MAX(fabs(d1),fabs(d2))+ + here->TRAabstol) || + (fabs(d3-d4) >= here->TRAreltol*MAX(fabs(d3),fabs(d4))+ + here->TRAabstol) ) { + /* derivitive changing - need to schedule after delay */ + /*printf("%s: at %g set for %g\n",here->TRAname, + ckt->CKTtime, + *(here->TRAdelays+3*here->TRAsizeDelay-3)+here->TRAtd + );*/ + /*printf("%g, %g, %g -> %g, %g \n",v1,v2,v3,d1,d2);*/ + /*printf("%g, %g, %g -> %g, %g \n",v4,v5,v6,d3,d4);*/ + /* also set for break after PREVIOUS point */ + /*printf("setting break\n");*/ + error = CKTsetBreak(ckt, + *(here->TRAdelays+3*here->TRAsizeDelay -3) + + here->TRAtd); + if(error) return(error); + } +#endif /*NOTDEF*/ + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/tra/traacld.c b/src/spicelib/devices/tra/traacld.c new file mode 100644 index 000000000..e9ce9408e --- /dev/null +++ b/src/spicelib/devices/tra/traacld.c @@ -0,0 +1,69 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + +int +TRAacLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current values into the + * sparse matrix previously provided + */ +{ + register TRAmodel *model = (TRAmodel *)inModel; + register TRAinstance *here; + double real; + double imag; + + /* loop through all the transmission line models */ + for( ; model != NULL; model = model->TRAnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->TRAinstances; here != NULL ; + here=here->TRAnextInstance) { + if (here->TRAowner != ARCHme) continue; + + real = cos(-ckt->CKTomega*here->TRAtd); + imag = sin(-ckt->CKTomega*here->TRAtd); + + *(here->TRApos1Pos1Ptr) += here->TRAconduct; + *(here->TRApos1Int1Ptr) -= here->TRAconduct; + *(here->TRAneg1Ibr1Ptr) -= 1; + *(here->TRApos2Pos2Ptr) += here->TRAconduct; + *(here->TRAneg2Ibr2Ptr) -= 1; + *(here->TRAint1Pos1Ptr) -= here->TRAconduct; + *(here->TRAint1Int1Ptr) += here->TRAconduct; + *(here->TRAint1Ibr1Ptr) += 1; + *(here->TRAint2Int2Ptr) += here->TRAconduct; + *(here->TRAint2Ibr2Ptr) += 1; + *(here->TRAibr1Neg1Ptr) -= 1; + *(here->TRAibr1Pos2Ptr+0) -= real; + *(here->TRAibr1Pos2Ptr+1) -= imag; + *(here->TRAibr1Neg2Ptr+0) += real; + *(here->TRAibr1Neg2Ptr+1) += imag; + *(here->TRAibr1Int1Ptr) += 1; + *(here->TRAibr1Ibr2Ptr+0) -= real * here->TRAimped; + *(here->TRAibr1Ibr2Ptr+1) -= imag * here->TRAimped; + *(here->TRAibr2Pos1Ptr+0) -= real; + *(here->TRAibr2Pos1Ptr+1) -= imag; + *(here->TRAibr2Neg1Ptr+0) += real; + *(here->TRAibr2Neg1Ptr+1) += imag; + *(here->TRAibr2Neg2Ptr) -= 1; + *(here->TRAibr2Int2Ptr) += 1; + *(here->TRAibr2Ibr1Ptr+0) -= real * here->TRAimped; + *(here->TRAibr2Ibr1Ptr+1) -= imag * here->TRAimped; + *(here->TRApos2Int2Ptr) -= here->TRAconduct; + *(here->TRAint2Pos2Ptr) -= here->TRAconduct; + + } + } + return(OK); +} diff --git a/src/spicelib/devices/tra/traask.c b/src/spicelib/devices/tra/traask.c new file mode 100644 index 000000000..707fbab2d --- /dev/null +++ b/src/spicelib/devices/tra/traask.c @@ -0,0 +1,103 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal device parameter + * of TRAnsmission lines + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +TRAask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + TRAinstance *here = (TRAinstance *)inst; + int temp; + double *v, *w; + + switch(which) { + case TRA_POS_NODE1: + value->iValue = here->TRAposNode1; + return (OK); + case TRA_NEG_NODE1: + value->iValue = here->TRAnegNode1; + return (OK); + case TRA_POS_NODE2: + value->iValue = here->TRAposNode2; + return (OK); + case TRA_NEG_NODE2: + value->iValue = here->TRAnegNode2; + return (OK); + case TRA_INT_NODE1: + value->iValue = here->TRAintNode1; + return (OK); + case TRA_INT_NODE2: + value->iValue = here->TRAintNode2; + return (OK); + case TRA_Z0: + value->rValue = here->TRAimped; + return (OK); + case TRA_TD: + value->rValue = here->TRAtd; + return (OK); + case TRA_NL: + value->rValue = here->TRAnl; + return (OK); + case TRA_FREQ: + value->rValue = here->TRAf; + return (OK); + case TRA_V1: + value->rValue = here->TRAinitVolt1; + return (OK); + case TRA_I1: + value->rValue = here->TRAinitCur1; + return (OK); + case TRA_V2: + value->rValue = here->TRAinitVolt2; + return (OK); + case TRA_I2: + value->rValue = here->TRAinitCur2; + return (OK); + case TRA_RELTOL: + value->rValue = here->TRAreltol; + return (OK); + case TRA_ABSTOL: + value->rValue = here->TRAabstol; + return (OK); + case TRA_BR_EQ1: + value->rValue = here->TRAbrEq1; + return (OK); + case TRA_BR_EQ2: + value->rValue = here->TRAbrEq2; + return (OK); + case TRA_DELAY: + value->v.vec.rVec = (double *) MALLOC(here->TRAsizeDelay); + value->v.numValue = temp = here->TRAsizeDelay; + v = value->v.vec.rVec; + w = here->TRAdelays; + while (temp--) + *v++ = *w++; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/tra/tradefs.h b/src/spicelib/devices/tra/tradefs.h new file mode 100644 index 000000000..1523ba1bf --- /dev/null +++ b/src/spicelib/devices/tra/tradefs.h @@ -0,0 +1,131 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef TRA +#define TRA + + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + + /* definitions used to describe transmission liness */ + + +/* information used to describe a single instance */ + +typedef struct sTRAinstance { + struct sTRAmodel *TRAmodPtr; /* backpointer to model */ + struct sTRAinstance *TRAnextInstance; /* pointer to next instance of + * current model*/ + IFuid TRAname; /* pointer to character string naming this instance */ + int TRAowner; /* number of owner process */ + int TRAstate; /* not used */ + int TRAposNode1; /* number of positive node of end 1 of t. line */ + int TRAnegNode1; /* number of negative node of end 1 of t. line */ + int TRAposNode2; /* number of positive node of end 2 of t. line */ + int TRAnegNode2; /* number of negative node of end 2 of t. line */ + int TRAintNode1; /* number of internal node of end 1 of t. line */ + int TRAintNode2; /* number of internal node of end 2 of t. line */ + + double TRAimped; /* impedance - input */ + double TRAconduct; /* conductance - calculated */ + double TRAtd; /* propagation delay */ + double TRAnl; /* normalized length */ + double TRAf; /* frequency at which nl is measured */ + double TRAinput1; /* accumulated excitation for port 1 */ + double TRAinput2; /* accumulated excitation for port 2 */ + double TRAinitVolt1; /* initial condition: voltage on port 1 */ + double TRAinitCur1; /* initial condition: current at port 1 */ + double TRAinitVolt2; /* initial condition: voltage on port 2 */ + double TRAinitCur2; /* initial condition: current at port 2 */ + double TRAreltol; /* relative deriv. tol. for breakpoint setting */ + double TRAabstol; /* absolute deriv. tol. for breakpoint setting */ + double *TRAdelays; /* delayed values of excitation */ + int TRAsizeDelay; /* size of active delayed table */ + int TRAallocDelay; /* allocated size of delayed table */ + int TRAbrEq1; /* number of branch equation for end 1 of t. line */ + int TRAbrEq2; /* number of branch equation for end 2 of t. line */ + double *TRAibr1Ibr2Ptr; /* pointer to sparse matrix */ + double *TRAibr1Int1Ptr; /* pointer to sparse matrix */ + double *TRAibr1Neg1Ptr; /* pointer to sparse matrix */ + double *TRAibr1Neg2Ptr; /* pointer to sparse matrix */ + double *TRAibr1Pos2Ptr; /* pointer to sparse matrix */ + double *TRAibr2Ibr1Ptr; /* pointer to sparse matrix */ + double *TRAibr2Int2Ptr; /* pointer to sparse matrix */ + double *TRAibr2Neg1Ptr; /* pointer to sparse matrix */ + double *TRAibr2Neg2Ptr; /* pointer to sparse matrix */ + double *TRAibr2Pos1Ptr; /* pointer to sparse matrix */ + double *TRAint1Ibr1Ptr; /* pointer to sparse matrix */ + double *TRAint1Int1Ptr; /* pointer to sparse matrix */ + double *TRAint1Pos1Ptr; /* pointer to sparse matrix */ + double *TRAint2Ibr2Ptr; /* pointer to sparse matrix */ + double *TRAint2Int2Ptr; /* pointer to sparse matrix */ + double *TRAint2Pos2Ptr; /* pointer to sparse matrix */ + double *TRAneg1Ibr1Ptr; /* pointer to sparse matrix */ + double *TRAneg2Ibr2Ptr; /* pointer to sparse matrix */ + double *TRApos1Int1Ptr; /* pointer to sparse matrix */ + double *TRApos1Pos1Ptr; /* pointer to sparse matrix */ + double *TRApos2Int2Ptr; /* pointer to sparse matrix */ + double *TRApos2Pos2Ptr; /* pointer to sparse matrix */ + unsigned TRAimpedGiven : 1; /* flag to indicate impedence was specified */ + unsigned TRAtdGiven : 1; /* flag to indicate delay was specified */ + unsigned TRAnlGiven : 1; /* flag to indicate norm length was specified */ + unsigned TRAfGiven : 1; /* flag to indicate freq was specified */ + unsigned TRAicV1Given : 1; /* flag to ind. init. voltage at port 1 given */ + unsigned TRAicC1Given : 1; /* flag to ind. init. current at port 1 given */ + unsigned TRAicV2Given : 1; /* flag to ind. init. voltage at port 2 given */ + unsigned TRAicC2Given : 1; /* flag to ind. init. current at port 2 given */ + unsigned TRAreltolGiven:1; /* flag to ind. relative deriv. tol. given */ + unsigned TRAabstolGiven:1; /* flag to ind. absolute deriv. tol. given */ +} TRAinstance ; + + +/* per model data */ + +typedef struct sTRAmodel { /* model structure for a transmission lines */ + int TRAmodType; /* type index of this device type */ + struct sTRAmodel *TRAnextModel; /* pointer to next possible model in + * linked list */ + TRAinstance * TRAinstances; /* pointer to list of instances that have this + * model */ + IFuid TRAmodName; /* pointer to character string naming this model */ +} TRAmodel; + +/* device parameters */ +#define TRA_Z0 1 +#define TRA_TD 2 +#define TRA_NL 3 +#define TRA_FREQ 4 +#define TRA_V1 5 +#define TRA_I1 6 +#define TRA_V2 7 +#define TRA_I2 8 +#define TRA_IC 9 +#define TRA_RELTOL 10 +#define TRA_ABSTOL 11 +#define TRA_POS_NODE1 12 +#define TRA_NEG_NODE1 13 +#define TRA_POS_NODE2 14 +#define TRA_NEG_NODE2 15 +#define TRA_INPUT1 16 +#define TRA_INPUT2 17 +#define TRA_DELAY 18 +#define TRA_BR_EQ1 19 +#define TRA_BR_EQ2 20 +#define TRA_INT_NODE1 21 +#define TRA_INT_NODE2 22 + +/* model parameters */ + +/* device questions */ + +/* model questions */ + +#include "traext.h" + +#endif /*TRA*/ + diff --git a/src/spicelib/devices/tra/tradel.c b/src/spicelib/devices/tra/tradel.c new file mode 100644 index 000000000..8dc4b61bf --- /dev/null +++ b/src/spicelib/devices/tra/tradel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +TRAdelete(inModel,name,kill) + GENmodel *inModel; + IFuid name; + GENinstance **kill; +{ + TRAinstance **fast = (TRAinstance **)kill; + TRAmodel *model = (TRAmodel *)inModel; + TRAinstance **prev = NULL; + TRAinstance *here; + + for( ; model ; model = model->TRAnextModel) { + prev = &(model->TRAinstances); + for(here = *prev; here ; here = *prev) { + if(here->TRAname == name || (fast && here==*fast) ) { + *prev= here->TRAnextInstance; + FREE(here); + return(OK); + } + prev = &(here->TRAnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/tra/tradest.c b/src/spicelib/devices/tra/tradest.c new file mode 100644 index 000000000..210c313f3 --- /dev/null +++ b/src/spicelib/devices/tra/tradest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "tradefs.h" +#include "suffix.h" + + +void +TRAdestroy(inModel) + GENmodel **inModel; +{ + TRAmodel **model = (TRAmodel **)inModel; + TRAinstance *here; + TRAinstance *prev = NULL; + TRAmodel *mod = *model; + TRAmodel *oldmod = NULL; + + for( ; mod ; mod = mod->TRAnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (TRAinstance *)NULL; + for(here = mod->TRAinstances ; here ; here = here->TRAnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/tra/traext.h b/src/spicelib/devices/tra/traext.h new file mode 100644 index 000000000..11faa7911 --- /dev/null +++ b/src/spicelib/devices/tra/traext.h @@ -0,0 +1,34 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int TRAacLoad(GENmodel*,CKTcircuit*); +extern int TRAaccept(CKTcircuit*,GENmodel*); +extern int TRAask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int TRAdelete(GENmodel*,IFuid,GENinstance**); +extern void TRAdestroy(GENmodel**); +extern int TRAload(GENmodel*,CKTcircuit*); +extern int TRAmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int TRAmDelete(GENmodel**,IFuid,GENmodel*); +extern int TRAparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int TRAsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int TRAunsetup(GENmodel*,CKTcircuit*); +extern int TRAtemp(GENmodel*,CKTcircuit*); +extern int TRAtrunc(GENmodel*,CKTcircuit*,double*); +#else /* stdc */ +extern int TRAacLoad(); +extern int TRAaccept(); +extern int TRAask(); +extern int TRAdelete(); +extern void TRAdestroy(); +extern int TRAload(); +extern int TRAmAsk(); +extern int TRAmDelete(); +extern int TRAparam(); +extern int TRAsetup(); +extern int TRAunsetup(); +extern int TRAtemp(); +extern int TRAtrunc(); +#endif /* stdc */ diff --git a/src/spicelib/devices/tra/traitf.h b/src/spicelib/devices/tra/traitf.h new file mode 100644 index 000000000..9e515a84f --- /dev/null +++ b/src/spicelib/devices/tra/traitf.h @@ -0,0 +1,74 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_tra + +#ifndef DEV_TRA +#define DEV_TRA + +#include "traext.h" +extern IFparm TRApTable[ ]; +extern char *TRAnames[ ]; +extern int TRApTSize; +extern int TRAnSize; +extern int TRAiSize; +extern int TRAmSize; + +SPICEdev TRAinfo = { + { + "Tranline", + "Lossless transmission line", + + &TRAnSize, + &TRAnSize, + TRAnames, + + &TRApTSize, + TRApTable, + + 0, + NULL, + 0 + }, + + TRAparam, + NULL, + TRAload, + TRAsetup, + TRAunsetup, + TRAsetup, + TRAtemp, + TRAtrunc, + NULL, + TRAacLoad, + TRAaccept, + TRAdestroy, +#ifdef DELETES + TRAmDelete, + TRAdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + TRAask, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* DISTO */ + NULL, /* NOISE */ + + &TRAiSize, + &TRAmSize + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/tra/traload.c b/src/spicelib/devices/tra/traload.c new file mode 100644 index 000000000..e4dacbf2d --- /dev/null +++ b/src/spicelib/devices/tra/traload.c @@ -0,0 +1,154 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "tradefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +TRAload(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current values into the + * sparse matrix previously provided + */ +{ + register TRAmodel *model = (TRAmodel *)inModel; + register TRAinstance *here; + double t1,t2,t3; + double f1,f2,f3; + register int i; + + /* loop through all the transmission line models */ + for( ; model != NULL; model = model->TRAnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->TRAinstances; here != NULL ; + here=here->TRAnextInstance) { + if (here->TRAowner != ARCHme) continue; + + *(here->TRApos1Pos1Ptr) += here->TRAconduct; + *(here->TRApos1Int1Ptr) -= here->TRAconduct; + *(here->TRAneg1Ibr1Ptr) -= 1; + *(here->TRApos2Pos2Ptr) += here->TRAconduct; + *(here->TRAneg2Ibr2Ptr) -= 1; + *(here->TRAint1Pos1Ptr) -= here->TRAconduct; + *(here->TRAint1Int1Ptr) += here->TRAconduct; + *(here->TRAint1Ibr1Ptr) += 1; + *(here->TRAint2Int2Ptr) += here->TRAconduct; + *(here->TRAint2Ibr2Ptr) += 1; + *(here->TRAibr1Neg1Ptr) -= 1; + *(here->TRAibr1Int1Ptr) += 1; + *(here->TRAibr2Neg2Ptr) -= 1; + *(here->TRAibr2Int2Ptr) += 1; + *(here->TRApos2Int2Ptr) -= here->TRAconduct; + *(here->TRAint2Pos2Ptr) -= here->TRAconduct; + + if(ckt->CKTmode & MODEDC) { + *(here->TRAibr1Pos2Ptr) -= 1; + *(here->TRAibr1Neg2Ptr) += 1; + *(here->TRAibr1Ibr2Ptr) -= (1-ckt->CKTgmin)*here->TRAimped; + *(here->TRAibr2Pos1Ptr) -= 1; + *(here->TRAibr2Neg1Ptr) += 1; + *(here->TRAibr2Ibr1Ptr) -= (1-ckt->CKTgmin)*here->TRAimped; + } else { + if (ckt->CKTmode & MODEINITTRAN) { + if(ckt->CKTmode & MODEUIC) { + here->TRAinput1 = here->TRAinitVolt2 + here->TRAinitCur2 + * here->TRAimped; + here->TRAinput2 = here->TRAinitVolt1 + here->TRAinitCur1 + * here->TRAimped; + } else { + here->TRAinput1 = + ( *(ckt->CKTrhsOld+here->TRAposNode2) + - *(ckt->CKTrhsOld+here->TRAnegNode2) ) + + ( *(ckt->CKTrhsOld+here->TRAbrEq2) + *here->TRAimped); + here->TRAinput2 = + ( *(ckt->CKTrhsOld+here->TRAposNode1) + - *(ckt->CKTrhsOld+here->TRAnegNode1) ) + + ( *(ckt->CKTrhsOld+here->TRAbrEq1) + *here->TRAimped); + } + *(here->TRAdelays ) = -2*here->TRAtd; + *(here->TRAdelays+3) = -here->TRAtd; + *(here->TRAdelays+6) = 0; + *(here->TRAdelays+1) = *(here->TRAdelays +4) = + *(here->TRAdelays+7) = here->TRAinput1; + *(here->TRAdelays+2) = *(here->TRAdelays +5) = + *(here->TRAdelays+8) = here->TRAinput2; + here->TRAsizeDelay = 2; + } else { + if(ckt->CKTmode & MODEINITPRED) { + for(i=2;(iTRAsizeDelay) && + (*(here->TRAdelays +3*i) <= + (ckt->CKTtime-here->TRAtd));i++) {;/*loop does it*/} + t1 = *(here->TRAdelays + (3*(i-2))); + t2 = *(here->TRAdelays + (3*(i-1))); + t3 = *(here->TRAdelays + (3*(i ))); + if( (t2-t1)==0 || (t3-t2) == 0) continue; + f1 = (ckt->CKTtime - here->TRAtd - t2) * + (ckt->CKTtime - here->TRAtd - t3) ; + f2 = (ckt->CKTtime - here->TRAtd - t1) * + (ckt->CKTtime - here->TRAtd - t3) ; + f3 = (ckt->CKTtime - here->TRAtd - t1) * + (ckt->CKTtime - here->TRAtd - t2) ; + if((t2-t1)==0) { /* should never happen, but don't want + * to divide by zero, EVER... */ + f1=0; + f2=0; + } else { + f1 /= (t1-t2); + f2 /= (t2-t1); + } + if((t3-t2)==0) { /* should never happen, but don't want + * to divide by zero, EVER... */ + f2=0; + f3=0; + } else { + f2 /= (t2-t3); + f3 /= (t2-t3); + } + if((t3-t1)==0) { /* should never happen, but don't want + * to divide by zero, EVER... */ + f1=0; + f2=0; + } else { + f1 /= (t1-t3); + f3 /= (t1-t3); + } + /*printf("at time %g, using %g, %g, %g\n",ckt->CKTtime, + t1,t2,t3); + printf("values %g, %g, %g \n", + *(here->TRAdelays + (3*(i-2))+1), + *(here->TRAdelays + (3*(i-1))+1), + *(here->TRAdelays + (3*(i ))+1) ); + printf("and %g, %g, %g \n", + *(here->TRAdelays + (3*(i-2))+2), + *(here->TRAdelays + (3*(i-1))+2), + *(here->TRAdelays + (3*(i ))+2) );*/ + here->TRAinput1 = f1 * *(here->TRAdelays + (3*(i-2))+1) + + f2 * *(here->TRAdelays + (3*(i-1))+1) + + f3 * *(here->TRAdelays + (3*(i ))+1); + here->TRAinput2 = f1 * *(here->TRAdelays + (3*(i-2))+2) + + f2 * *(here->TRAdelays + (3*(i-1))+2) + + f3 * *(here->TRAdelays + (3*(i ))+2); + } + } + *(ckt->CKTrhs + here->TRAbrEq1) += here->TRAinput1; + *(ckt->CKTrhs + here->TRAbrEq2) += here->TRAinput2; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/tra/tramdel.c b/src/spicelib/devices/tra/tramdel.c new file mode 100644 index 000000000..01e00c8b7 --- /dev/null +++ b/src/spicelib/devices/tra/tramdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +TRAmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + TRAmodel **model = (TRAmodel **)inModel; + TRAmodel *modfast = (TRAmodel *)kill; + TRAinstance *here; + TRAinstance *prev = NULL; + TRAmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->TRAnextModel)) { + if( (*model)->TRAmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->TRAnextModel; /* cut deleted device out of list */ + for(here = (*model)->TRAinstances ; here ; here = here->TRAnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/tra/traparam.c b/src/spicelib/devices/tra/traparam.c new file mode 100644 index 000000000..2790336fa --- /dev/null +++ b/src/spicelib/devices/tra/traparam.c @@ -0,0 +1,85 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "tradefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +TRAparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + TRAinstance *here = (TRAinstance *)inst; + switch(param) { + case TRA_RELTOL: + here->TRAreltol = value->rValue; + here->TRAreltolGiven = TRUE; + break; + case TRA_ABSTOL: + here->TRAabstol = value->rValue; + here->TRAabstolGiven = TRUE; + break; + case TRA_Z0: + here->TRAimped = value->rValue; + here->TRAimpedGiven = TRUE; + break; + case TRA_TD: + here->TRAtd = value->rValue; + here->TRAtdGiven = TRUE; + break; + case TRA_NL: + here->TRAnl= value->rValue; + here->TRAnlGiven = TRUE; + break; + case TRA_FREQ: + here->TRAf= value->rValue; + here->TRAfGiven = TRUE; + break; + case TRA_V1: + here->TRAinitVolt1 = value->rValue; + here->TRAicV1Given = TRUE; + break; + case TRA_I1: + here->TRAinitCur1 = value->rValue; + here->TRAicC1Given = TRUE; + break; + case TRA_V2: + here->TRAinitVolt2 = value->rValue; + here->TRAicV2Given = TRUE; + break; + case TRA_I2: + here->TRAinitCur2 = value->rValue; + here->TRAicC2Given = TRUE; + break; + case TRA_IC: + switch(value->v.numValue){ + case 4: + here->TRAinitCur2 = *(value->v.vec.rVec+3); + case 3: + here->TRAinitVolt2 = *(value->v.vec.rVec+2); + case 2: + here->TRAinitCur1 = *(value->v.vec.rVec+1); + case 1: + here->TRAinitVolt1 = *(value->v.vec.rVec); + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/tra/trasetup.c b/src/spicelib/devices/tra/trasetup.c new file mode 100644 index 000000000..13588c23f --- /dev/null +++ b/src/spicelib/devices/tra/trasetup.c @@ -0,0 +1,155 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +TRAsetup(matrix,inModel,ckt,state) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *state; + /* load the transmission line structure with those pointers needed later + * for fast matrix loading + */ +{ + register TRAmodel *model = (TRAmodel *)inModel; + register TRAinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the transmission line models */ + for( ; model != NULL; model = model->TRAnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->TRAinstances; here != NULL ; + here=here->TRAnextInstance) { + + if(here->TRAbrEq1==0) { + error = CKTmkVolt(ckt,&tmp,here->TRAname,"i1"); + if(error) return(error); + here->TRAbrEq1 = tmp->number; + } + + if(here->TRAbrEq2==0) { + error = CKTmkVolt(ckt,&tmp,here->TRAname,"i2"); + if(error) return(error); + here->TRAbrEq2 = tmp->number; + } + + if(here->TRAintNode1==0) { + error = CKTmkVolt(ckt,&tmp,here->TRAname,"int1"); + if(error) return(error); + here->TRAintNode1 = tmp->number; + } + + if(here->TRAintNode2==0) { + error = CKTmkVolt(ckt,&tmp,here->TRAname,"int2"); + if(error) return(error); + here->TRAintNode2 = tmp->number; + } + + /* allocate the delay table */ + here->TRAdelays = (double *)MALLOC(15*sizeof(double)); + here->TRAallocDelay = 4; + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(TRAibr1Ibr2Ptr, TRAbrEq1, TRAbrEq2) + TSTALLOC(TRAibr1Int1Ptr, TRAbrEq1, TRAintNode1) + TSTALLOC(TRAibr1Neg1Ptr, TRAbrEq1, TRAnegNode1) + TSTALLOC(TRAibr1Neg2Ptr, TRAbrEq1, TRAnegNode2) + TSTALLOC(TRAibr1Pos2Ptr, TRAbrEq1, TRAposNode2) + TSTALLOC(TRAibr2Ibr1Ptr, TRAbrEq2, TRAbrEq1) + TSTALLOC(TRAibr2Int2Ptr, TRAbrEq2, TRAintNode2) + TSTALLOC(TRAibr2Neg1Ptr, TRAbrEq2, TRAnegNode1) + TSTALLOC(TRAibr2Neg2Ptr, TRAbrEq2, TRAnegNode2) + TSTALLOC(TRAibr2Pos1Ptr, TRAbrEq2, TRAposNode1) + TSTALLOC(TRAint1Ibr1Ptr, TRAintNode1, TRAbrEq1) + TSTALLOC(TRAint1Int1Ptr, TRAintNode1, TRAintNode1) + TSTALLOC(TRAint1Pos1Ptr, TRAintNode1, TRAposNode1) + TSTALLOC(TRAint2Ibr2Ptr, TRAintNode2, TRAbrEq2) + TSTALLOC(TRAint2Int2Ptr, TRAintNode2, TRAintNode2) + TSTALLOC(TRAint2Pos2Ptr, TRAintNode2, TRAposNode2) + TSTALLOC(TRAneg1Ibr1Ptr, TRAnegNode1, TRAbrEq1) + TSTALLOC(TRAneg2Ibr2Ptr, TRAnegNode2, TRAbrEq2) + TSTALLOC(TRApos1Int1Ptr, TRAposNode1, TRAintNode1) + TSTALLOC(TRApos1Pos1Ptr, TRAposNode1, TRAposNode1) + TSTALLOC(TRApos2Int2Ptr, TRAposNode2, TRAintNode2) + TSTALLOC(TRApos2Pos2Ptr, TRAposNode2, TRAposNode2) + + if(!here->TRAnlGiven) { + here->TRAnl = .25; + } + if(!here->TRAfGiven) { + here->TRAf = 1e9; + } + if(!here->TRAreltolGiven) { + here->TRAreltol = 1; + } + if(!here->TRAabstolGiven) { + here->TRAabstol = 1; + } + if(!here->TRAimpedGiven) { + (*(SPfrontEnd->IFerror))(ERR_FATAL, + "%s: transmission line z0 must be given", + &(here->TRAname)); + return(E_BADPARM); + } + } + } + return(OK); +} + +int +TRAunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + TRAmodel *model; + TRAinstance *here; + + for (model = (TRAmodel *)inModel; model != NULL; + model = model->TRAnextModel) + { + for (here = model->TRAinstances; here != NULL; + here=here->TRAnextInstance) + { + if (here->TRAbrEq1) { + CKTdltNNum(ckt, here->TRAbrEq1); + here->TRAbrEq1= 0; + } + if (here->TRAbrEq2) { + CKTdltNNum(ckt, here->TRAbrEq2); + here->TRAbrEq2= 0; + } + if (here->TRAintNode1) { + CKTdltNNum(ckt, here->TRAintNode1); + here->TRAintNode1= 0; + } + if (here->TRAintNode2) { + CKTdltNNum(ckt, here->TRAintNode2); + here->TRAintNode2= 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/tra/tratemp.c b/src/spicelib/devices/tra/tratemp.c new file mode 100644 index 000000000..144e81445 --- /dev/null +++ b/src/spicelib/devices/tra/tratemp.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +TRAtemp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* + * pre-process parameters for later use + */ +{ + register TRAmodel *model = (TRAmodel *)inModel; + register TRAinstance *here; + + /* loop through all the transmission line models */ + for( ; model != NULL; model = model->TRAnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->TRAinstances; here != NULL ; + here=here->TRAnextInstance) { + if (here->TRAowner != ARCHme) continue; + + if(!here->TRAtdGiven) { + here->TRAtd = here->TRAnl/here->TRAf; + } + here->TRAconduct = 1/here->TRAimped; + } + } + return(OK); +} diff --git a/src/spicelib/devices/tra/tratrunc.c b/src/spicelib/devices/tra/tratrunc.c new file mode 100644 index 000000000..95be3f0f6 --- /dev/null +++ b/src/spicelib/devices/tra/tratrunc.c @@ -0,0 +1,82 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "tradefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +TRAtrunc(inModel,ckt,timeStep) + GENmodel *inModel; + register CKTcircuit *ckt; + double *timeStep; + +{ + register TRAmodel *model = (TRAmodel *)inModel; + register TRAinstance *here; + double v1,v2,v3,v4; + double v5,v6,d1,d2,d3,d4; + double tmp; + + /* loop through all the transmission line models */ + for( ; model != NULL; model = model->TRAnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->TRAinstances; here != NULL ; + here=here->TRAnextInstance) { + if (here->TRAowner != ARCHme) continue; + + v1 = ( *(ckt->CKTrhsOld + here->TRAposNode2) + - *(ckt->CKTrhsOld + here->TRAnegNode2)) + + *(ckt->CKTrhsOld + here->TRAbrEq2) * + here->TRAimped; + v2 = *(here->TRAdelays+1+3*(here->TRAsizeDelay)); + v3 = *(here->TRAdelays+1+3*(here->TRAsizeDelay-1)); + v4 = ( *(ckt->CKTrhsOld + here->TRAposNode1) + - *(ckt->CKTrhsOld + here->TRAnegNode1)) + + *(ckt->CKTrhsOld + here->TRAbrEq1) * + here->TRAimped; + v5 = *(here->TRAdelays+2+3*(here->TRAsizeDelay)); + v6 = *(here->TRAdelays+2+3*(here->TRAsizeDelay-1)); + d1 = (v1-v2)/ckt->CKTdeltaOld[1]; + d2 = (v2-v3)/ckt->CKTdeltaOld[2]; + d3 = (v4-v5)/ckt->CKTdeltaOld[1]; + d4 = (v5-v6)/ckt->CKTdeltaOld[2]; + /*printf("%s: at %g derivs are %g, %g and %g, %g\n", + here->TRAname,ckt->CKTtime,d1,d2,d3,d4);*/ + if( (fabs(d1-d2) >= here->TRAreltol*MAX(fabs(d1),fabs(d2))+ + here->TRAabstol) || + (fabs(d3-d4) >= here->TRAreltol*MAX(fabs(d3),fabs(d4))+ + here->TRAabstol) ) { + /* derivitive changing - need to schedule after delay */ + /*printf("%s: at %g set for %g\n",here->TRAname, + ckt->CKTtime, + *(here->TRAdelays+3*here->TRAsizeDelay-3)+here->TRAtd + );*/ + /*printf("%g, %g, %g -> %g, %g \n",v1,v2,v3,d1,d2);*/ + /*printf("%g, %g, %g -> %g, %g \n",v4,v5,v6,d3,d4);*/ + /* also set for break after PREVIOUS point */ + /*printf("setting break\n");*/ + /* will need to set a breakpoint at + *(here->TRAdelays+3*(here->TRAsizeDelay)) + here->TRAtd + so we need to make sure we don't step past it + */ + /* the previous timepoint plus the delay */ + tmp = *(here->TRAdelays+3*here->TRAsizeDelay) + here->TRAtd; + /* minus current time */ + tmp -= ckt->CKTtime; + *timeStep = MIN(*timeStep,tmp); + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/urc/ChangeLog b/src/spicelib/devices/urc/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/urc/Makefile.am b/src/spicelib/devices/urc/Makefile.am new file mode 100644 index 000000000..bee09e353 --- /dev/null +++ b/src/spicelib/devices/urc/Makefile.am @@ -0,0 +1,22 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = liburc.la + +liburc_la_SOURCES = \ + urc.c \ + urcask.c \ + urcdefs.h \ + urcdel.c \ + urcdest.c \ + urcext.h \ + urcitf.h \ + urcmask.c \ + urcmdel.c \ + urcmpar.c \ + urcparam.c \ + urcsetup.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/urc/urc.c b/src/spicelib/devices/urc/urc.c new file mode 100644 index 000000000..682150f58 --- /dev/null +++ b/src/spicelib/devices/urc/urc.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "urcdefs.h" +#include "suffix.h" + +IFparm URCpTable[] = { /* parameters */ + IOPU( "l", URC_LEN, IF_REAL, "Length of transmission line"), + IOPU( "n", URC_LUMPS, IF_REAL, "Number of lumps"), + OPU( "pos_node",URC_POS_NODE,IF_INTEGER,"Positive node of URC"), + OPU( "neg_node",URC_NEG_NODE,IF_INTEGER,"Negative node of URC"), + OPU( "gnd", URC_GND_NODE,IF_INTEGER,"Ground node of URC") +}; + +IFparm URCmPTable[] = { /* model parameters */ + IOP( "k", URC_MOD_K, IF_REAL, "Propagation constant"), + IOPA( "fmax", URC_MOD_FMAX, IF_REAL, "Maximum frequency of interest"), + IOP( "rperl", URC_MOD_RPERL, IF_REAL, "Resistance per unit length"), + IOPA( "cperl", URC_MOD_CPERL, IF_REAL, "Capacitance per unit length"), + IOP( "isperl", URC_MOD_ISPERL, IF_REAL, "Saturation current per length"), + IOP( "rsperl", URC_MOD_RSPERL, IF_REAL, "Diode resistance per length"), + IP( "urc", URC_MOD_URC, IF_FLAG, "Uniform R.C. line model") +}; + +char *URCnames[] = { + "P1", + "P2", + "Ref" +}; + +int URCnSize = NUMELEMS(URCnames); +int URCpTSize = NUMELEMS(URCpTable); +int URCmPTSize = NUMELEMS(URCmPTable); +int URCiSize = sizeof(URCinstance); +int URCmSize = sizeof(URCmodel); diff --git a/src/spicelib/devices/urc/urcask.c b/src/spicelib/devices/urc/urcask.c new file mode 100644 index 000000000..d36bf2d5e --- /dev/null +++ b/src/spicelib/devices/urc/urcask.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + + +/* + * This routine gives access to the internal device parameters + * of Uniform distributed RC lines + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "urcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +URCask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + URCinstance *here = (URCinstance *)inst; + switch(which) { + case URC_POS_NODE: + value->iValue = here->URCposNode; + return (OK); + case URC_NEG_NODE: + value->iValue = here->URCnegNode; + return (OK); + case URC_GND_NODE: + value->iValue = here->URCgndNode; + return (OK); + case URC_LEN: + value->rValue = here->URClength; + return (OK); + case URC_LUMPS: + value->iValue = here->URClumps; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/urc/urcdefs.h b/src/spicelib/devices/urc/urcdefs.h new file mode 100644 index 000000000..0bf81e1bd --- /dev/null +++ b/src/spicelib/devices/urc/urcdefs.h @@ -0,0 +1,84 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef URC +#define URC + + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + + /* + * structures used to describe uniform RC lines + */ + +/* information needed for each instance */ + +typedef struct sURCinstance { + struct sURCmodel *URCmodPtr; /* backpointer to model */ + struct sURCinstance *URCnextInstance; /* pointer to next instance of + * current model*/ + IFuid URCname; /* pointer to character string naming this instance */ + int URCowner; /* number of owner process */ + int URCstate; /* not used */ + int URCposNode; /* number of positive node of URC */ + int URCnegNode; /* number of negative node of URC */ + int URCgndNode; /* number of the "ground" node of the URC */ + + double URClength; /* length of line */ + int URClumps; /* number of lumps in line */ + unsigned URClenGiven : 1; /* flag to indicate length was specified */ + unsigned URClumpsGiven : 1; /* flag to indicate lumps was specified */ +} URCinstance ; + +/* per model data */ + +typedef struct sURCmodel { /* model structure for a resistor */ + int URCmodType; /* type index of this device type */ + struct sURCmodel *URCnextModel; /* pointer to next possible model + * in linked list */ + URCinstance * URCinstances; /* pointer to list of instances that have this + * model */ + IFuid URCmodName; /* pointer to character string naming this model */ + + double URCk; /* propagation constant for URC */ + double URCfmax; /* max frequence of interest */ + double URCrPerL; /* resistance per unit length */ + double URCcPerL; /* capacitance per unit length */ + double URCisPerL; /* diode saturation current per unit length */ + double URCrsPerL; /* diode resistance per unit length */ + unsigned URCkGiven : 1; /* flag to indicate k was specified */ + unsigned URCfmaxGiven : 1; /* flag to indicate fmax was specified */ + unsigned URCrPerLGiven : 1; /* flag to indicate rPerL was specified */ + unsigned URCcPerLGiven : 1; /* flag to indicate cPerL was specified */ + unsigned URCisPerLGiven : 1; /* flag to indicate isPerL was specified */ + unsigned URCrsPerLGiven : 1; /* flag to indicate rsPerL was specified */ +} URCmodel; + +/* device parameters */ +#define URC_LEN 1 +#define URC_LUMPS 2 +#define URC_POS_NODE 3 +#define URC_NEG_NODE 4 +#define URC_GND_NODE 5 + +/* model parameters */ +#define URC_MOD_K 101 +#define URC_MOD_FMAX 102 +#define URC_MOD_RPERL 103 +#define URC_MOD_CPERL 104 +#define URC_MOD_ISPERL 105 +#define URC_MOD_RSPERL 106 +#define URC_MOD_URC 107 + +/* device questions */ + +/* model questions */ + +#include "urcext.h" + +#endif /*URC*/ diff --git a/src/spicelib/devices/urc/urcdel.c b/src/spicelib/devices/urc/urcdel.c new file mode 100644 index 000000000..2a80a64b9 --- /dev/null +++ b/src/spicelib/devices/urc/urcdel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "urcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +URCdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + URCmodel *model = (URCmodel *)inModel; + URCinstance **fast = (URCinstance**)inst; + URCinstance **prev = NULL; + URCinstance *here; + + for( ; model ; model = model->URCnextModel) { + prev = &(model->URCinstances); + for(here = *prev; here ; here = *prev) { + if(here->URCname == name || (fast && here==*fast) ) { + *prev= here->URCnextInstance; + FREE(here); + return(OK); + } + prev = &(here->URCnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/urc/urcdest.c b/src/spicelib/devices/urc/urcdest.c new file mode 100644 index 000000000..0f4849e65 --- /dev/null +++ b/src/spicelib/devices/urc/urcdest.c @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + + +#include "ngspice.h" +#include +#include "urcdefs.h" +#include "suffix.h" + + +void +URCdestroy(inModel) + GENmodel **inModel; +{ + URCmodel **model = (URCmodel **)inModel; + URCinstance *here; + URCinstance *prev = NULL; + URCmodel *mod = *model; + URCmodel *oldmod = NULL; + + for( ; mod ; mod = mod->URCnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (URCinstance *)NULL; + for(here = mod->URCinstances ; here ; here = here->URCnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/urc/urcext.h b/src/spicelib/devices/urc/urcext.h new file mode 100644 index 000000000..0b58b9ade --- /dev/null +++ b/src/spicelib/devices/urc/urcext.h @@ -0,0 +1,26 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int URCask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int URCdelete(GENmodel*,IFuid,GENinstance**); +extern void URCdestroy(GENmodel**); +extern int URCmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int URCmDelete(GENmodel**,IFuid,GENmodel*); +extern int URCmParam(int,IFvalue*,GENmodel*); +extern int URCparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int URCsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int URCunsetup(GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int URCask(); +extern int URCdelete(); +extern void URCdestroy(); +extern int URCmAsk(); +extern int URCmDelete(); +extern int URCmParam(); +extern int URCparam(); +extern int URCsetup(); +extern int URCunsetup(); +#endif /* stdc */ diff --git a/src/spicelib/devices/urc/urcitf.h b/src/spicelib/devices/urc/urcitf.h new file mode 100644 index 000000000..ce9cefeb6 --- /dev/null +++ b/src/spicelib/devices/urc/urcitf.h @@ -0,0 +1,76 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_urc + +#ifndef DEV_URC +#define DEV_URC + +#include "urcext.h" +extern IFparm URCpTable[ ]; +extern IFparm URCmPTable[ ]; +extern char *URCnames[ ]; +extern int URCpTSize; +extern int URCmPTSize; +extern int URCnSize; +extern int URCiSize; +extern int URCmSize; + +SPICEdev URCinfo = { + { + "URC", /* MUST precede both resistors and capacitors */ + "Uniform R.C. line", + + &URCnSize, + &URCnSize, + URCnames, + + &URCpTSize, + URCpTable, + + &URCmPTSize, + URCmPTable, + 0 + }, + + URCparam, + URCmParam, + NULL, + URCsetup, + URCunsetup, + URCsetup, + NULL, + NULL, + NULL, + NULL, + NULL, + URCdestroy, +#ifdef DELETES + URCmDelete, + URCdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + URCask, + URCmAsk, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* DISTO */ + NULL, /* NOISE */ + + &URCiSize, + &URCmSize + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/urc/urcmask.c b/src/spicelib/devices/urc/urcmask.c new file mode 100644 index 000000000..522705a28 --- /dev/null +++ b/src/spicelib/devices/urc/urcmask.c @@ -0,0 +1,55 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal model parameters + * of Uniform distributed RC lines + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "urcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +URCmAsk(ckt,inst,which,value) + CKTcircuit *ckt; + GENmodel *inst; + int which; + IFvalue *value; +{ + URCmodel *here = (URCmodel *)inst; + switch(which) { + case URC_MOD_K: + value->rValue = here->URCk; + return (OK); + case URC_MOD_FMAX: + value->rValue = here->URCfmax; + return (OK); + case URC_MOD_RPERL: + value->rValue = here->URCrPerL; + return (OK); + case URC_MOD_CPERL: + value->rValue = here->URCcPerL; + return (OK); + case URC_MOD_ISPERL: + value->rValue = here->URCisPerL; + return (OK); + case URC_MOD_RSPERL: + value->rValue = here->URCrsPerL; + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/urc/urcmdel.c b/src/spicelib/devices/urc/urcmdel.c new file mode 100644 index 000000000..7e9d8bf1a --- /dev/null +++ b/src/spicelib/devices/urc/urcmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "urcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +URCmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + URCmodel **model = (URCmodel**)inModel; + URCmodel *modfast = (URCmodel *)kill; + URCinstance *here; + URCinstance *prev = NULL; + URCmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->URCnextModel)) { + if( (*model)->URCmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->URCnextModel; /* cut deleted device out of list */ + for(here = (*model)->URCinstances ; here ; here = here->URCnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/urc/urcmpar.c b/src/spicelib/devices/urc/urcmpar.c new file mode 100644 index 000000000..cc352923a --- /dev/null +++ b/src/spicelib/devices/urc/urcmpar.c @@ -0,0 +1,56 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "urcdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +int +URCmParam(param,value,inModel) + int param; + IFvalue *value; + GENmodel *inModel; +{ + register URCmodel *model = (URCmodel *)inModel; + switch(param) { + case URC_MOD_K: + model->URCk = value->rValue; + model->URCkGiven = TRUE; + break; + case URC_MOD_FMAX: + model->URCfmax = value->rValue; + model->URCfmaxGiven = TRUE; + break; + case URC_MOD_RPERL: + model->URCrPerL = value->rValue; + model->URCrPerLGiven = TRUE; + break; + case URC_MOD_CPERL: + model->URCcPerL = value->rValue; + model->URCcPerLGiven = TRUE; + break; + case URC_MOD_ISPERL: + model->URCisPerL = value->rValue; + model->URCisPerLGiven = TRUE; + break; + case URC_MOD_RSPERL: + model->URCrsPerL = value->rValue; + model->URCrsPerLGiven = TRUE; + break; + case URC_MOD_URC: + /* no operation - already know we are a URC, but this makes*/ + /* spice-2 like parsers happy */ + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/urc/urcparam.c b/src/spicelib/devices/urc/urcparam.c new file mode 100644 index 000000000..5e6d81f04 --- /dev/null +++ b/src/spicelib/devices/urc/urcparam.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "urcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +URCparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + URCinstance *here = (URCinstance *)inst; + switch(param) { + case URC_LEN: + here->URClength = value->rValue; + here->URClenGiven = TRUE; + break; + case URC_LUMPS: + here->URClumps = value->rValue; + here->URClumpsGiven = TRUE; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/urc/urcsetup.c b/src/spicelib/devices/urc/urcsetup.c new file mode 100644 index 000000000..a65970506 --- /dev/null +++ b/src/spicelib/devices/urc/urcsetup.c @@ -0,0 +1,343 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "urcdefs.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +URCsetup(matrix,inModel,ckt,state) + SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *state; + /* create the resistors/capacitors used to model the URC + */ +{ + register URCmodel *model = (URCmodel *)inModel; + register URCinstance *here; + int rtype; + int ctype; + int dtype; + CKTnode * lowl; + CKTnode * lowr; + CKTnode * hil; + CKTnode * hir; + char *nameelt; + char *namehi; + CKTnode *nodehi; + CKTnode *nodelo; + char *namelo; + double r; + double c; + IFvalue ptemp; + double p; + double r0; + double c0; + double i0; + double r1; + double c1; + double i1; + double rd; + double wnorm; + double prop; + int i; + GENinstance *fast; + GENmodel *modfast; /* capacitor or diode model */ + GENmodel *rmodfast; /* resistor model */ + int error; + IFuid dioUid; + IFuid resUid; + IFuid capUid; + IFuid eltUid; + + rtype = CKTtypelook("Resistor"); + ctype = CKTtypelook("Capacitor"); + dtype = CKTtypelook("Diode"); + /* loop through all the URC models */ + for( ; model != NULL; model = model->URCnextModel ) { + if(!model->URCkGiven) + model->URCk = 1.5; + if(!model->URCfmaxGiven) + model->URCfmax = 1e9; + if(!model->URCrPerLGiven) + model->URCrPerL = 1000; + if(!model->URCcPerLGiven) + model->URCcPerL = 1e-12; + +/* may need to put in limits: k>=1.1, freq <=1e9, rperl >=.1 */ + + /* loop through all the instances of the model */ + for (here = model->URCinstances; here != NULL ; + here=here->URCnextInstance) + { + p = model->URCk; + r0 = here->URClength * model->URCrPerL; + c0 = here->URClength * model->URCcPerL; + i0 = here->URClength * model->URCisPerL; + if(!here->URClumpsGiven) { + wnorm = model->URCfmax * r0 * c0 * 2.0 * M_PI; + here->URClumps=MAX(3.0,log(wnorm*(((p-1)/p)*((p-1)/p)))/log(p)); + if(wnorm <35) here->URClumps=3; + /* may want to limit lumps to <= 100 or something like that */ + } + r1 = (r0*(p-1))/((2*(pow(p,(double)here->URClumps)))-2); + c1 = (c0 * (p-1))/((pow(p,(double)(here->URClumps-1)))*(p+1)-2); + i1 = (i0 * (p-1))/((pow(p,(double)(here->URClumps-1)))*(p+1)-2); + rd = here->URClength * here->URClumps * model->URCrsPerL; + /* may want to check that c1 > 0 */ + prop=1; + + if(model->URCisPerLGiven) { + error = (*(SPfrontEnd->IFnewUid))(ckt,&dioUid,here->URCname, + "diodemod",UID_MODEL,(void **)NULL); + if(error) return(error); + modfast = (GENmodel *)NULL; + error = CKTmodCrt((void *)ckt,dtype,(void **)&modfast, + dioUid); + if(error) return(error); + ptemp.rValue = c1; + error= CKTpModName("cjo",&ptemp,ckt,dtype,dioUid,&modfast); + if(error) return(error); + ptemp.rValue = rd; + error = CKTpModName("rs",&ptemp,ckt,dtype,dioUid,&modfast); + if(error) return(error); + ptemp.rValue = i1; + error = CKTpModName("is",&ptemp,ckt,dtype,dioUid,&modfast); + if(error) return(error); + } else { + error = (*(SPfrontEnd->IFnewUid))((void *)ckt,&capUid, + here->URCname, "capmod",UID_MODEL,(void **)NULL); + if(error) return(error); + modfast = (GENmodel *)NULL; + error = CKTmodCrt((void *)ckt,ctype,(void **)&modfast, + capUid); + if(error) return(error); + } + + error = (*(SPfrontEnd->IFnewUid))(ckt,&resUid,here->URCname, + "resmod",UID_MODEL,(void **)NULL); + if(error) return(error); + rmodfast = (GENmodel *)NULL; + error = CKTmodCrt((void *)ckt,rtype,(void **)&rmodfast,resUid); + if(error) return(error); + lowl = CKTnum2nod(ckt,here->URCposNode); + hir = CKTnum2nod(ckt,here->URCnegNode); + for(i=1;i<=here->URClumps;i++) { + namehi = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(namehi,"hi%d",i); + error = CKTmkVolt(ckt,(CKTnode**)&nodehi,here->URCname,namehi); + if(error) return(error); + hil = nodehi; + if(i==here->URClumps) { + lowr = hil; + } else { + namelo = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(namelo,"lo%d",i); + error = CKTmkVolt(ckt,(CKTnode**)&nodelo,here->URCname, + namelo); + if(error) return(error); + lowr = nodelo; + } + r = prop*r1; + c = prop*c1; + + nameelt = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(nameelt,"rlo%d",i); + error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,here->URCname, + nameelt,UID_INSTANCE, (void **)NULL); + if(error) return(error); + error = CKTcrtElt((void *)ckt,(void *)rmodfast, + (void **)&fast,eltUid); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,1,lowl); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,2,lowr); + if(error) return(error); + ptemp.rValue = r; + error = CKTpName("resistance",&ptemp,ckt,rtype,nameelt,&fast); + if(error) return(error); + fast->GENowner = here->URCowner; + + nameelt = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(nameelt,"rhi%d",i); + error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,here->URCname, + nameelt,UID_INSTANCE, (void **)NULL); + if(error) return(error); + error = CKTcrtElt((void *)ckt,(void *)rmodfast, + (void **)&fast,eltUid); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,1,hil); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,2,hir); + if(error) return(error); + ptemp.rValue = r; + error = CKTpName("resistance",&ptemp,ckt,rtype,nameelt,&fast); + if(error) return(error); + fast->GENowner = here->URCowner; + + if(model->URCisPerLGiven) { + /* use diode */ + nameelt = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(nameelt,"dlo%d",i); + error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid, + here->URCname,nameelt,UID_INSTANCE, + (void **)NULL); + if(error) return(error); + error = CKTcrtElt((void *)ckt,(void *)modfast, + (void **)&fast, eltUid); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,1,lowr); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,2, + (void *)CKTnum2nod(ckt, here->URCgndNode)); + if(error) return(error); + ptemp.rValue = prop; + error = CKTpName("area",&ptemp,ckt,dtype,nameelt,&fast); + if(error) return(error); + fast->GENowner = here->URCowner; + } else { + /* use simple capacitor */ + nameelt = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(nameelt,"clo%d",i); + error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,here->URCname + ,nameelt,UID_INSTANCE, (void **)NULL); + if(error) return(error); + error = CKTcrtElt((void *)ckt,(void *)modfast, + (void **)&fast, eltUid); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,1,lowr); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,2, + (void *)CKTnum2nod(ckt, here->URCgndNode)); + if(error) return(error); + ptemp.rValue = c; + error = CKTpName("capacitance",&ptemp,ckt,ctype,nameelt, + &fast); + if(error) return(error); + fast->GENowner = here->URCowner; + } + + if(i!=here->URClumps){ + if(model->URCisPerLGiven) { + /* use diode */ + nameelt = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(nameelt,"dhi%d",i); + error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid, + here->URCname,nameelt,UID_INSTANCE, + (void **)NULL); + if(error) return(error); + error = CKTcrtElt((void *)ckt,(void *)modfast, + (void **) &fast,eltUid); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,1,hil); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,2, + (void *)CKTnum2nod(ckt, here->URCgndNode)); + if(error) return(error); + ptemp.rValue = prop; + error=CKTpName("area",&ptemp,ckt,dtype,nameelt,&fast); + if(error) return(error); + fast->GENowner = here->URCowner; + } else { + /* use simple capacitor */ + nameelt = (char *)MALLOC(10*sizeof(char)); + (void)sprintf(nameelt,"chi%d",i); + error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid, + here->URCname,nameelt,UID_INSTANCE, + (void **)NULL); + if(error) return(error); + error = CKTcrtElt((void *)ckt,(void *)modfast, + (void **)&fast,eltUid); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,1,hil); + if(error) return(error); + error = CKTbindNode((void *)ckt,(void *)fast,2, + (void *)CKTnum2nod(ckt, here->URCgndNode)); + if(error) return(error); + ptemp.rValue = c; + error =CKTpName("capacitance",&ptemp,ckt,ctype,nameelt, + &fast); + if(error) return(error); + fast->GENowner = here->URCowner; + } + } + prop *= p; + lowl = lowr; + hir = hil; + } + } + } + return(OK); +} + +int +URCunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + IFuid varUid; + int error; + URCinstance *here; + URCmodel *model = (URCmodel *) inModel; + GENinstance *in; + GENmodel *modfast; + int type; + + /* Delete models, devices, and intermediate nodes; + */ + + for ( ; model; model = model->URCnextModel) { + for (here = model->URCinstances; here; + here = here->URCnextInstance) + { + if(model->URCisPerLGiven) { + /* Diodes */ + error = (*(SPfrontEnd->IFnewUid))(ckt,&varUid,here->URCname, + "diodemod",UID_MODEL,(void **)NULL); + } else { + /* Capacitors */ + error = (*(SPfrontEnd->IFnewUid))((void *)ckt,&varUid, + here->URCname, "capmod",UID_MODEL,(void **)NULL); + } + if (error && error != E_EXISTS) + return error; + + modfast = NULL; + type = -1; + error = CKTfndMod(ckt, &type, (void **) &modfast, varUid); + if (error) + return error; + + for (in = modfast->GENinstances; in; in = in->GENnextInstance) + CKTdltNNum(ckt, in->GENnode1); + + CKTdltMod(ckt, modfast); /* Does the elements too */ + + /* Resistors */ + error = (*(SPfrontEnd->IFnewUid))(ckt,&varUid,here->URCname, + "resmod",UID_MODEL,(void **)NULL); + if (error && error != E_EXISTS) + return error; + + modfast = NULL; + type = -1; + error = CKTfndMod(ckt, &type, (void **) &modfast, varUid); + if (error) + return error; + + CKTdltMod(ckt, modfast); + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/vccs/ChangeLog b/src/spicelib/devices/vccs/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/vccs/Makefile.am b/src/spicelib/devices/vccs/Makefile.am new file mode 100644 index 000000000..96dd6506e --- /dev/null +++ b/src/spicelib/devices/vccs/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libvccs.la + +libvccs_la_SOURCES = \ + vccs.c \ + vccsask.c \ + vccsdefs.h \ + vccsdel.c \ + vccsdest.c \ + vccsext.h \ + vccsitf.h \ + vccsload.c \ + vccsmdel.c \ + vccspar.c \ + vccspzld.c \ + vccssacl.c \ + vccsset.c \ + vccssld.c \ + vccssprt.c \ + vccssset.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/vccs/vccs.c b/src/spicelib/devices/vccs/vccs.c new file mode 100644 index 000000000..59f934f2a --- /dev/null +++ b/src/spicelib/devices/vccs/vccs.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "vccsdefs.h" +#include "suffix.h" + +IFparm VCCSpTable[] = { /* parameters */ + IOPU("gain", VCCS_TRANS, IF_REAL, "Transconductance of source (gain)"), + IP("sens_trans", VCCS_TRANS_SENS,IF_FLAG, + "flag to request sensitivity WRT transconductance"), + OPU("pos_node", VCCS_POS_NODE, IF_INTEGER, "Positive node of source"), + OPU("neg_node", VCCS_NEG_NODE, IF_INTEGER, "Negative node of source"), + OPU("cont_p_node",VCCS_CONT_P_NODE,IF_INTEGER, + "Positive node of contr. source"), + OPU("cont_n_node",VCCS_CONT_N_NODE,IF_INTEGER, + "Negative node of contr. source"), + IP("ic", VCCS_IC, IF_REAL, "Initial condition of controlling source"), + OP("i", VCCS_CURRENT,IF_REAL, "Output current"), + OP("v", VCCS_VOLTS,IF_REAL, "Voltage across output"), + OP("p", VCCS_POWER, IF_REAL, "Power"), + OPU("sens_dc", VCCS_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU("sens_real", VCCS_QUEST_SENS_REAL, IF_REAL, "real part of ac sensitivity"), + OPU("sens_imag", VCCS_QUEST_SENS_IMAG, IF_REAL, "imag part of ac sensitivity"), + OPU("sens_mag", VCCS_QUEST_SENS_MAG, IF_REAL, "sensitivity of ac magnitude"), + OPU("sens_ph", VCCS_QUEST_SENS_PH, IF_REAL, "sensitivity of ac phase"), + OPU("sens_cplx", VCCS_QUEST_SENS_CPLX, IF_COMPLEX, "ac sensitivity") +}; + +char *VCCSnames[] = { + "V+", + "V-", + "VC+", + "VC-" +}; + +int VCCSnSize = NUMELEMS(VCCSnames); +int VCCSpTSize = NUMELEMS(VCCSpTable); +int VCCSmPTSize = 0; +int VCCSiSize = sizeof(VCCSinstance); +int VCCSmSize = sizeof(VCCSmodel); diff --git a/src/spicelib/devices/vccs/vccsask.c b/src/spicelib/devices/vccs/vccsask.c new file mode 100644 index 000000000..8e7e601d9 --- /dev/null +++ b/src/spicelib/devices/vccs/vccsask.c @@ -0,0 +1,148 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +/* + * This routine gives access to the internal device parameters + * of Voltage Controlled Current Source + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +VCCSask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + VCCSinstance *here = (VCCSinstance*)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case VCCS_TRANS: + value->rValue = here->VCCScoeff; + return (OK); + case VCCS_POS_NODE: + value->iValue = here->VCCSposNode; + return (OK); + case VCCS_NEG_NODE: + value->iValue = here->VCCSnegNode; + return (OK); + case VCCS_CONT_P_NODE: + value->iValue = here->VCCScontPosNode; + return (OK); + case VCCS_CONT_N_NODE: + value->iValue = here->VCCScontNegNode; + return (OK); + case VCCS_CONT_V_OLD: + value->rValue = *(ckt->CKTstate0 + here->VCCScontVOld); + return (OK); + case VCCS_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->VCCSsenParmNo); + } + return(OK); + case VCCS_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCCSsenParmNo); + } + return(OK); + case VCCS_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCCSsenParmNo); + } + return(OK); + case VCCS_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCCSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCCSsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case VCCS_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCCSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCCSsenParmNo); + value->rValue = (vr * si - vi * sr)/vm; + } + return(OK); + case VCCS_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCCSsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCCSsenParmNo); + } + return(OK); + case VCCS_CURRENT: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "VCCSask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = (*(ckt->CKTrhsOld+here->VCCScontPosNode) + - *(ckt->CKTrhsOld + here->VCCScontNegNode)) * + (here->VCCScoeff); + } + return (OK); + case VCCS_VOLTS: + value->rValue = (*(ckt->CKTrhsOld+here->VCCSposNode) + - *(ckt->CKTrhsOld + here->VCCSnegNode)); + return (OK); + case VCCS_POWER: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "BJTask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = (*(ckt->CKTrhsOld+here->VCCScontPosNode) + - *(ckt->CKTrhsOld + here->VCCScontNegNode)) * + (here->VCCScoeff) * (*(ckt->CKTrhsOld+here->VCCSposNode) + - *(ckt->CKTrhsOld + here->VCCSnegNode)); + } + return (OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/vccs/vccsdefs.h b/src/spicelib/devices/vccs/vccsdefs.h new file mode 100644 index 000000000..3b7ad5d53 --- /dev/null +++ b/src/spicelib/devices/vccs/vccsdefs.h @@ -0,0 +1,90 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef VCCS +#define VCCS + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + + /* + * structures to describe Voltage Controlled Current Sources + */ + +/* information to describe a single instance */ + +typedef struct sVCCSinstance { + struct sVCCSmodel *VCCSmodPtr; /* backpointer to model */ + struct sVCCSinstance *VCCSnextInstance; /* pointer to next instance of + *current model*/ + IFuid VCCSname; /* pointer to character string naming this instance */ + int VCCSowner; /* number of owner process */ + int VCCSstates; /* state info */ + + int VCCSposNode; /* number of positive node of source */ + int VCCSnegNode; /* number of negative node of source */ + int VCCScontPosNode; /* number of positive node of controlling source */ + int VCCScontNegNode; /* number of negative node of controlling source */ + + double VCCSinitCond; /* initial condition (of controlling source) */ + double VCCScoeff; /* coefficient */ + + double *VCCSposContPosptr; /* pointer to sparse matrix element at + * (positive node, control positive node) */ + double *VCCSposContNegptr; /* pointer to sparse matrix element at + * (negative node, control negative node) */ + double *VCCSnegContPosptr; /* pointer to sparse matrix element at + * (positive node, control positive node) */ + double *VCCSnegContNegptr; /* pointer to sparse matrix element at + * (negative node, control negative node) */ + unsigned VCCScoeffGiven :1 ;/* flag to indicate function coeffs given */ + + int VCCSsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + +} VCCSinstance ; + +#define VCCSvOld VCCSstates +#define VCCScontVOld VCCSstates + 1 + +/* per model data */ + +typedef struct sVCCSmodel { /* model structure for a source */ + int VCCSmodType; /* type index of this device type */ + struct sVCCSmodel *VCCSnextModel; /* pointer to next possible model + * in linked list */ + VCCSinstance * VCCSinstances; /* pointer to list of instances + * that have this model */ + IFuid VCCSmodName; /* pointer to character string naming this model */ +} VCCSmodel; + +/* device parameters */ +#define VCCS_TRANS 1 +#define VCCS_IC 2 +#define VCCS_POS_NODE 3 +#define VCCS_NEG_NODE 4 +#define VCCS_CONT_P_NODE 5 +#define VCCS_CONT_N_NODE 6 +#define VCCS_CONT_V_OLD 7 +#define VCCS_TRANS_SENS 8 +#define VCCS_CURRENT 9 +#define VCCS_POWER 10 +#define VCCS_VOLTS 11 + +/* model parameters */ + +/* device questions */ +#define VCCS_QUEST_SENS_REAL 201 +#define VCCS_QUEST_SENS_IMAG 202 +#define VCCS_QUEST_SENS_MAG 203 +#define VCCS_QUEST_SENS_PH 204 +#define VCCS_QUEST_SENS_CPLX 205 +#define VCCS_QUEST_SENS_DC 206 + +/* model questions */ + +#endif /*VCCS*/ diff --git a/src/spicelib/devices/vccs/vccsdel.c b/src/spicelib/devices/vccs/vccsdel.c new file mode 100644 index 000000000..5799e083e --- /dev/null +++ b/src/spicelib/devices/vccs/vccsdel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCCSdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + VCCSmodel *model = (VCCSmodel *)inModel; + VCCSinstance **fast = (VCCSinstance**)inst; + VCCSinstance **prev = NULL; + VCCSinstance *here; + + for( ; model ; model = model->VCCSnextModel) { + prev = &(model->VCCSinstances); + for(here = *prev; here ; here = *prev) { + if(here->VCCSname == name || (fast && here==*fast) ) { + *prev= here->VCCSnextInstance; + FREE(here); + return(OK); + } + prev = &(here->VCCSnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/vccs/vccsdest.c b/src/spicelib/devices/vccs/vccsdest.c new file mode 100644 index 000000000..8e82528ab --- /dev/null +++ b/src/spicelib/devices/vccs/vccsdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vccsdefs.h" +#include "suffix.h" + + +void +VCCSdestroy(inModel) + GENmodel **inModel; +{ + VCCSmodel **model = (VCCSmodel**)inModel; + VCCSinstance *here; + VCCSinstance *prev = NULL; + VCCSmodel *mod = *model; + VCCSmodel *oldmod = NULL; + + for( ; mod ; mod = mod->VCCSnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (VCCSinstance *)NULL; + for(here = mod->VCCSinstances ; here ; here = here->VCCSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/vccs/vccsext.h b/src/spicelib/devices/vccs/vccsext.h new file mode 100644 index 000000000..57e2cdf83 --- /dev/null +++ b/src/spicelib/devices/vccs/vccsext.h @@ -0,0 +1,32 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int VCCSask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int VCCSdelete(GENmodel*,IFuid,GENinstance**); +extern void VCCSdestroy(GENmodel**); +extern int VCCSload(GENmodel*,CKTcircuit*); +extern int VCCSmDelete(GENmodel**,IFuid,GENmodel*); +extern int VCCSparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int VCCSpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int VCCSsAcLoad(GENmodel*,CKTcircuit*); +extern int VCCSsLoad(GENmodel*,CKTcircuit*); +extern int VCCSsSetup(SENstruct*,GENmodel*); +extern void VCCSsPrint(GENmodel*,CKTcircuit*); +extern int VCCSsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +#else /* stdc */ +extern int VCCSask(); +extern int VCCSdelete(); +extern void VCCSdestroy(); +extern int VCCSload(); +extern int VCCSmDelete(); +extern int VCCSparam(); +extern int VCCSpzLoad(); +extern int VCCSsAcLoad(); +extern int VCCSsLoad(); +extern int VCCSsSetup(); +extern void VCCSsPrint(); +extern int VCCSsetup(); +#endif /* stdc */ diff --git a/src/spicelib/devices/vccs/vccsitf.h b/src/spicelib/devices/vccs/vccsitf.h new file mode 100644 index 000000000..2850a8846 --- /dev/null +++ b/src/spicelib/devices/vccs/vccsitf.h @@ -0,0 +1,88 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_vccs + +#ifndef DEV_VCCS +#define DEV_VCCS + +#include "vccsext.h" +extern IFparm VCCSpTable[ ]; +extern char *VCCSnames[ ]; +extern int VCCSpTSize; +extern int VCCSnSize; +extern int VCCSiSize; +extern int VCCSmSize; + +SPICEdev VCCSinfo = { + { + "VCCS", + "Voltage controlled current source", + + &VCCSnSize, + &VCCSnSize, + VCCSnames, + + &VCCSpTSize, + VCCSpTable, + + 0, + NULL, + DEV_DEFAULT + }, + + VCCSparam, + NULL, + VCCSload, + VCCSsetup, + NULL, + VCCSsetup, + NULL, + NULL, + NULL, + VCCSload, /* ac and normal loads are identical */ + NULL, + VCCSdestroy, +#ifdef DELETES + VCCSmDelete, + VCCSdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + VCCSask, + NULL, +#ifdef AN_pz + VCCSpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense2 + VCCSsSetup, + VCCSsLoad, + NULL, + VCCSsAcLoad, + VCCSsPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ + NULL, /* DISTO */ + NULL, /* NOISE */ + + &VCCSiSize, + &VCCSmSize + + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/vccs/vccsload.c b/src/spicelib/devices/vccs/vccsload.c new file mode 100644 index 000000000..73653b240 --- /dev/null +++ b/src/spicelib/devices/vccs/vccsload.c @@ -0,0 +1,43 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +VCCSload(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current values into the + * sparse matrix previously provided + */ +{ + register VCCSmodel *model = (VCCSmodel *)inModel; + register VCCSinstance *here; + + /* loop through all the source models */ + for( ; model != NULL; model = model->VCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCCSinstances; here != NULL ; + here=here->VCCSnextInstance) { + if (here->VCCSowner != ARCHme) continue; + + *(here->VCCSposContPosptr) += here->VCCScoeff ; + *(here->VCCSposContNegptr) -= here->VCCScoeff ; + *(here->VCCSnegContPosptr) -= here->VCCScoeff ; + *(here->VCCSnegContNegptr) += here->VCCScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/vccs/vccsmdel.c b/src/spicelib/devices/vccs/vccsmdel.c new file mode 100644 index 000000000..00bdaa822 --- /dev/null +++ b/src/spicelib/devices/vccs/vccsmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCCSmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + VCCSmodel **model = (VCCSmodel **)inModel; + VCCSmodel *modfast = (VCCSmodel *)kill; + VCCSinstance *here; + VCCSinstance *prev = NULL; + VCCSmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->VCCSnextModel)) { + if( (*model)->VCCSmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->VCCSnextModel; /* cut deleted device out of list */ + for(here = (*model)->VCCSinstances ; here ; here = here->VCCSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/vccs/vccspar.c b/src/spicelib/devices/vccs/vccspar.c new file mode 100644 index 000000000..322786478 --- /dev/null +++ b/src/spicelib/devices/vccs/vccspar.c @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +VCCSparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + VCCSinstance *here = (VCCSinstance *)inst; + switch(param) { + case VCCS_TRANS: + here->VCCScoeff = value->rValue; + here->VCCScoeffGiven = TRUE; + break; + case VCCS_TRANS_SENS: + here->VCCSsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/vccs/vccspzld.c b/src/spicelib/devices/vccs/vccspzld.c new file mode 100644 index 000000000..26d713976 --- /dev/null +++ b/src/spicelib/devices/vccs/vccspzld.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "vccsdefs.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +VCCSpzLoad(inModel,ckt,s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; + /* actually load the current values into the + * sparse matrix previously provided + */ +{ + register VCCSmodel *model = (VCCSmodel *)inModel; + register VCCSinstance *here; + + /* loop through all the source models */ + for( ; model != NULL; model = model->VCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCCSinstances; here != NULL ; + here=here->VCCSnextInstance) { + if (here->VCCSowner != ARCHme) continue; + + *(here->VCCSposContPosptr) += here->VCCScoeff ; + *(here->VCCSposContNegptr) -= here->VCCScoeff ; + *(here->VCCSnegContPosptr) -= here->VCCScoeff ; + *(here->VCCSnegContNegptr) += here->VCCScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/vccs/vccssacl.c b/src/spicelib/devices/vccs/vccssacl.c new file mode 100644 index 000000000..02ff2c6cf --- /dev/null +++ b/src/spicelib/devices/vccs/vccssacl.c @@ -0,0 +1,59 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current ac sensitivity information into the + * array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCCSsAcLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register VCCSmodel *model = (VCCSmodel *)inModel; + register VCCSinstance *here; + double vc; + double ivc; + + + /* loop through all the source models */ + for( ; model != NULL; model = model->VCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCCSinstances; here != NULL ; + here=here->VCCSnextInstance) { + if (here->VCCSowner != ARCHme) continue; + + if (here->VCCSsenParmNo){ + vc = *(ckt->CKTrhsOld + here->VCCScontPosNode) + - *(ckt->CKTrhsOld + here->VCCScontNegNode); + ivc = *(ckt->CKTirhsOld + here->VCCScontPosNode) + - *(ckt->CKTirhsOld + here->VCCScontNegNode); + *(ckt->CKTsenInfo->SEN_RHS[here->VCCSposNode] + + here->VCCSsenParmNo) -= vc; + *(ckt->CKTsenInfo->SEN_iRHS[here->VCCSposNode] + + here->VCCSsenParmNo) -= ivc; + *(ckt->CKTsenInfo->SEN_RHS[here->VCCSnegNode] + + here->VCCSsenParmNo) += vc; + *(ckt->CKTsenInfo->SEN_iRHS[here->VCCSnegNode] + + here->VCCSsenParmNo) += ivc; + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/vccs/vccsset.c b/src/spicelib/devices/vccs/vccsset.c new file mode 100644 index 000000000..610c388e3 --- /dev/null +++ b/src/spicelib/devices/vccs/vccsset.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + + /* load the current source structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +VCCSsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + CKTcircuit *ckt; + int *states; +{ + register VCCSmodel *model = (VCCSmodel *)inModel; + register VCCSinstance *here; + + /* loop through all the current source models */ + for( ; model != NULL; model = model->VCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCCSinstances; here != NULL ; + here=here->VCCSnextInstance) { + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(VCCSposContPosptr, VCCSposNode, VCCScontPosNode) + TSTALLOC(VCCSposContNegptr, VCCSposNode, VCCScontNegNode) + TSTALLOC(VCCSnegContPosptr, VCCSnegNode, VCCScontPosNode) + TSTALLOC(VCCSnegContNegptr, VCCSnegNode, VCCScontNegNode) + } + } + return(OK); +} diff --git a/src/spicelib/devices/vccs/vccssld.c b/src/spicelib/devices/vccs/vccssld.c new file mode 100644 index 000000000..664b46213 --- /dev/null +++ b/src/spicelib/devices/vccs/vccssld.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current sensitivity information into the + * array previously provided + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCCSsLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register VCCSmodel *model = (VCCSmodel *)inModel; + register VCCSinstance *here; + double vc; + + /* loop through all the source models */ + for( ; model != NULL; model = model->VCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCCSinstances; here != NULL ; + here=here->VCCSnextInstance) { + if (here->VCCSowner != ARCHme) continue; + + if(here->VCCSsenParmNo){ + vc = *(ckt->CKTrhsOld + here->VCCScontPosNode) + - *(ckt->CKTrhsOld + here->VCCScontNegNode); + *(ckt->CKTsenInfo->SEN_RHS[here->VCCSposNode] + + here->VCCSsenParmNo) -= vc; + *(ckt->CKTsenInfo->SEN_RHS[here->VCCSnegNode] + + here->VCCSsenParmNo) += vc; + } + } + } + return(OK); +} + + diff --git a/src/spicelib/devices/vccs/vccssprt.c b/src/spicelib/devices/vccs/vccssprt.c new file mode 100644 index 000000000..ac09f105c --- /dev/null +++ b/src/spicelib/devices/vccs/vccssprt.c @@ -0,0 +1,51 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* Pretty print the sensitivity info for + * all the VCCS in the circuit. + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +void +VCCSsPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register VCCSmodel *model = (VCCSmodel *)inModel; + register VCCSinstance *here; + + printf("VOLTAGE CONTROLLED CURRENT SOURCES-----------------\n"); + /* loop through all the source models */ + for( ; model != NULL; model = model->VCCSnextModel ) { + + printf("Model name:%s\n",model->VCCSmodName); + + /* loop through all the instances of the model */ + for (here = model->VCCSinstances; here != NULL ; + here=here->VCCSnextInstance) { + if (here->VCCSowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->VCCSname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->VCCSposNode), + CKTnodName(ckt,here->VCCSnegNode)); + printf(" Controlling Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->VCCScontPosNode), + CKTnodName(ckt,here->VCCScontNegNode)); + printf(" Coefficient: %f\n",here->VCCScoeff); + printf(" VCCSsenParmNo:%d\n",here->VCCSsenParmNo); + } + } +} diff --git a/src/spicelib/devices/vccs/vccssset.c b/src/spicelib/devices/vccs/vccssset.c new file mode 100644 index 000000000..259032ca4 --- /dev/null +++ b/src/spicelib/devices/vccs/vccssset.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vccsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCCSsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register VCCSmodel *model = (VCCSmodel *)inModel; + register VCCSinstance *here; + + /* loop through all the current source models */ + for( ; model != NULL; model = model->VCCSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCCSinstances; here != NULL ; + here=here->VCCSnextInstance) { + if (here->VCCSowner != ARCHme) continue; + + if(here->VCCSsenParmNo){ + here->VCCSsenParmNo = ++(info->SENparms); + } + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/vcvs/ChangeLog b/src/spicelib/devices/vcvs/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/vcvs/Makefile.am b/src/spicelib/devices/vcvs/Makefile.am new file mode 100644 index 000000000..50f021cd2 --- /dev/null +++ b/src/spicelib/devices/vcvs/Makefile.am @@ -0,0 +1,27 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libvcvs.la + +libvcvs_la_SOURCES = \ + vcvs.c \ + vcvsask.c \ + vcvsdefs.h \ + vcvsdel.c \ + vcvsdest.c \ + vcvsext.h \ + vcvsfbr.c \ + vcvsitf.h \ + vcvsload.c \ + vcvsmdel.c \ + vcvspar.c \ + vcvspzld.c \ + vcvssacl.c \ + vcvsset.c \ + vcvssld.c \ + vcvssprt.c \ + vcvssset.c + + + +INCLUDES = -I$(top_srcdir)/src/include +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/vcvs/vcvs.c b/src/spicelib/devices/vcvs/vcvs.c new file mode 100644 index 000000000..b7fb014ac --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvs.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "devdefs.h" +#include "vcvsdefs.h" +#include "suffix.h" + +IFparm VCVSpTable[] = { /* parameters */ + IOPU("gain", VCVS_GAIN, IF_REAL,"Voltage gain"), + IP("sens_gain",VCVS_GAIN_SENS,IF_FLAG,"flag to request sensitivity WRT gain"), + OPU("pos_node", VCVS_POS_NODE, IF_INTEGER, "Positive node of source"), + OPU("neg_node", VCVS_NEG_NODE, IF_INTEGER, "Negative node of source"), + OPU("cont_p_node",VCVS_CONT_P_NODE,IF_INTEGER, + "Positive node of contr. source"), + OPU("cont_n_node",VCVS_CONT_N_NODE,IF_INTEGER, + "Negative node of contr. source"), + IP("ic", VCVS_IC, IF_REAL, "Initial condition of controlling source"), + OP("i", VCVS_CURRENT, IF_REAL, "Output current"), + OP("v", VCVS_VOLTS, IF_REAL, "Output voltage"), + OP("p", VCVS_POWER, IF_REAL, "Power"), + OPU("sens_dc", VCVS_QUEST_SENS_DC, IF_REAL, "dc sensitivity "), + OPU("sens_real", VCVS_QUEST_SENS_REAL,IF_REAL, "real part of ac sensitivity"), + OPU("sens_imag", VCVS_QUEST_SENS_IMAG,IF_REAL, "imag part of ac sensitivity"), + OPU("sens_mag", VCVS_QUEST_SENS_MAG, IF_REAL, "sensitivity of ac magnitude"), + OPU("sens_ph", VCVS_QUEST_SENS_PH, IF_REAL, "sensitivity of ac phase"), + OPU("sens_cplx", VCVS_QUEST_SENS_CPLX, IF_COMPLEX, "ac sensitivity") +}; + +char *VCVSnames[] = { + "V+", + "V-", + "VC+", + "VC-" +}; + +int VCVSnSize = NUMELEMS(VCVSnames); +int VCVSpTSize = NUMELEMS(VCVSpTable); +int VCVSmPTSize = 0; +int VCVSiSize = sizeof(VCVSinstance); +int VCVSmSize = sizeof(VCVSmodel); diff --git a/src/spicelib/devices/vcvs/vcvsask.c b/src/spicelib/devices/vcvs/vcvsask.c new file mode 100644 index 000000000..993e82607 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsask.c @@ -0,0 +1,153 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +/* + * This routine gives access to the internal device parameters + * of Voltage Controlled Voltage Source + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +VCVSask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + VCVSinstance *here = (VCVSinstance *)inst; + double vr; + double vi; + double sr; + double si; + double vm; + static char *msg = "Current and power not available for ac analysis"; + switch(which) { + case VCVS_POS_NODE: + value->iValue = here->VCVSposNode; + return (OK); + case VCVS_NEG_NODE: + value->iValue = here->VCVSnegNode; + return (OK); + case VCVS_CONT_P_NODE: + value->iValue = here->VCVScontPosNode; + return (OK); + case VCVS_CONT_N_NODE: + value->iValue = here->VCVScontNegNode; + return (OK); + case VCVS_IC: + value->rValue = here->VCVSinitCond; + return (OK); + case VCVS_GAIN: + value->rValue = here->VCVScoeff; + return (OK); + case VCVS_CONT_V_OLD: + value->rValue = *(ckt->CKTstate0 + here->VCVScontVOld); + return (OK); + case VCVS_BR: + value->iValue = here->VCVSbranch; + return (OK); + case VCVS_QUEST_SENS_DC: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_Sap[select->iValue + 1]+ + here->VCVSsenParmNo); + } + return(OK); + case VCVS_QUEST_SENS_REAL: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCVSsenParmNo); + } + return(OK); + case VCVS_QUEST_SENS_IMAG: + if(ckt->CKTsenInfo){ + value->rValue = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCVSsenParmNo); + } + return(OK); + case VCVS_QUEST_SENS_MAG: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = sqrt(vr*vr + vi*vi); + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCVSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCVSsenParmNo); + value->rValue = (vr * sr + vi * si)/vm; + } + return(OK); + case VCVS_QUEST_SENS_PH: + if(ckt->CKTsenInfo){ + vr = *(ckt->CKTrhsOld + select->iValue + 1); + vi = *(ckt->CKTirhsOld + select->iValue + 1); + vm = vr*vr + vi*vi; + if(vm == 0){ + value->rValue = 0; + return(OK); + } + sr = *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCVSsenParmNo); + si = *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCVSsenParmNo); + + value->rValue = (vr * si - vi * sr)/vm; + } + + return(OK); + case VCVS_QUEST_SENS_CPLX: + if(ckt->CKTsenInfo){ + value->cValue.real= + *(ckt->CKTsenInfo->SEN_RHS[select->iValue + 1]+ + here->VCVSsenParmNo); + value->cValue.imag= + *(ckt->CKTsenInfo->SEN_iRHS[select->iValue + 1]+ + here->VCVSsenParmNo); + } + return(OK); + case VCVS_CURRENT : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "VCVSask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = *(ckt->CKTrhsOld + here->VCVSbranch); + } + return(OK); + case VCVS_VOLTS : + value->rValue = (*(ckt->CKTrhsOld + here->VCVSposNode) - + *(ckt->CKTrhsOld + here->VCVSnegNode)); + return(OK); + case VCVS_POWER : + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "VCVSask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = *(ckt->CKTrhsOld + here->VCVSbranch) * + (*(ckt->CKTrhsOld + here->VCVSposNode) - + *(ckt->CKTrhsOld + here->VCVSnegNode)); + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/vcvs/vcvsdefs.h b/src/spicelib/devices/vcvs/vcvsdefs.h new file mode 100644 index 000000000..b782b1063 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsdefs.h @@ -0,0 +1,99 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef VCVS +#define VCVS + + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + + /* + * structures to describe Voltage Controlled Voltage Sources + */ + +/* information to describe a single instance */ + +typedef struct sVCVSinstance { + struct sVCVSmodel *VCVSmodPtr; /* backpointer to model */ + struct sVCVSinstance *VCVSnextInstance; /* pointer to next instance of + *current model*/ + IFuid VCVSname; /* pointer to character string naming this instance */ + int VCVSowner; /* number of owner process */ + int VCVSstates; /* state info */ + + int VCVSposNode; /* number of positive node of source */ + int VCVSnegNode; /* number of negative node of source */ + int VCVScontPosNode; /* number of positive node of controlling source */ + int VCVScontNegNode; /* number of negative node of controlling source */ + int VCVSbranch; /* equation number of branch equation added for v source */ + + double VCVSinitCond; /* initial condition (of controlling source) */ + double VCVScoeff; /* coefficient */ + + double *VCVSposIbrptr; /* pointer to sparse matrix element at + * (positive node, branch equation) */ + double *VCVSnegIbrptr; /* pointer to sparse matrix element at + * (negative node, branch equation) */ + double *VCVSibrPosptr; /* pointer to sparse matrix element at + * (branch equation, positive node) */ + double *VCVSibrNegptr; /* pointer to sparse matrix element at + * (branch equation, negative node) */ + double *VCVSibrContPosptr; /* pointer to sparse matrix element at + *(branch equation, control positive node)*/ + double *VCVSibrContNegptr; /* pointer to sparse matrix element at + *(branch equation, control negative node)*/ + unsigned VCVScoeffGiven :1 ;/* flag to indicate function coeffs given */ + + int VCVSsenParmNo; /* parameter # for sensitivity use; + set equal to 0 if not a design parameter*/ + +} VCVSinstance ; + +#define VCVSvOld VCVSstates +#define VCVScontVOld VCVSstates + 1 + +/* per model data */ + +typedef struct sVCVSmodel { /* model structure for a source */ + int VCVSmodType; /* type index of this device type */ + struct sVCVSmodel *VCVSnextModel; /* pointer to next possible model + *in linked list */ + VCVSinstance * VCVSinstances; /* pointer to list of instances + * that have this model */ + IFuid VCVSmodName; /* pointer to character string naming this model */ +} VCVSmodel; + +/* device parameters */ +#define VCVS_GAIN 1 +#define VCVS_POS_NODE 2 +#define VCVS_NEG_NODE 3 +#define VCVS_CONT_P_NODE 4 +#define VCVS_CONT_N_NODE 5 +#define VCVS_BR 6 +#define VCVS_IC 7 +#define VCVS_CONT_V_OLD 8 +#define VCVS_GAIN_SENS 9 +#define VCVS_CURRENT 10 +#define VCVS_POWER 11 +#define VCVS_VOLTS 12 + +/* model parameters */ + +/* device questions */ +#define VCVS_QUEST_SENS_REAL 201 +#define VCVS_QUEST_SENS_IMAG 202 +#define VCVS_QUEST_SENS_MAG 203 +#define VCVS_QUEST_SENS_PH 204 +#define VCVS_QUEST_SENS_CPLX 205 +#define VCVS_QUEST_SENS_DC 206 + +/* model questions */ + +#include "vcvsext.h" + +#endif /*VCVS*/ diff --git a/src/spicelib/devices/vcvs/vcvsdel.c b/src/spicelib/devices/vcvs/vcvsdel.c new file mode 100644 index 000000000..d95347c83 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsdel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCVSdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + VCVSmodel *model = (VCVSmodel *)inModel; + VCVSinstance **fast = (VCVSinstance**)inst; + VCVSinstance **prev = NULL; + VCVSinstance *here; + + for( ; model ; model = model->VCVSnextModel) { + prev = &(model->VCVSinstances); + for(here = *prev; here ; here = *prev) { + if(here->VCVSname == name || (fast && here==*fast) ) { + *prev= here->VCVSnextInstance; + FREE(here); + return(OK); + } + prev = &(here->VCVSnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/vcvs/vcvsdest.c b/src/spicelib/devices/vcvs/vcvsdest.c new file mode 100644 index 000000000..c043c7b18 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vcvsdefs.h" +#include "suffix.h" + + +void +VCVSdestroy(inModel) + GENmodel **inModel; +{ + VCVSmodel **model = (VCVSmodel **)inModel; + VCVSinstance *here; + VCVSinstance *prev = NULL; + VCVSmodel *mod = *model; + VCVSmodel *oldmod = NULL; + + for( ; mod ; mod = mod->VCVSnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (VCVSinstance *)NULL; + for(here = mod->VCVSinstances ; here ; here = here->VCVSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/vcvs/vcvsext.h b/src/spicelib/devices/vcvs/vcvsext.h new file mode 100644 index 000000000..d31f28567 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsext.h @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int VCVSask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int VCVSdelete(GENmodel*,IFuid,GENinstance**); +extern void VCVSdestroy(GENmodel**); +extern int VCVSfindBr(CKTcircuit*,GENmodel*,IFuid); +extern int VCVSload(GENmodel*,CKTcircuit*); +extern int VCVSmDelete(GENmodel**,IFuid,GENmodel*); +extern int VCVSparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int VCVSpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int VCVSsAcLoad(GENmodel*,CKTcircuit*); +extern int VCVSsLoad(GENmodel*,CKTcircuit*); +extern int VCVSsSetup(SENstruct*,GENmodel*); +extern void VCVSsPrint(GENmodel*,CKTcircuit*); +extern int VCVSsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int VCVSunsetup(GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int VCVSask(); +extern int VCVSdelete(); +extern void VCVSdestroy(); +extern int VCVSfindBr(); +extern int VCVSload(); +extern int VCVSmDelete(); +extern int VCVSparam(); +extern int VCVSpzLoad(); +extern int VCVSsAcLoad(); +extern int VCVSsLoad(); +extern int VCVSsSetup(); +extern void VCVSsPrint(); +extern int VCVSsetup(); +extern int VCVSunsetup(); +#endif /* stdc */ diff --git a/src/spicelib/devices/vcvs/vcvsfbr.c b/src/spicelib/devices/vcvs/vcvsfbr.c new file mode 100644 index 000000000..35620f245 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsfbr.c @@ -0,0 +1,42 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vcvsdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCVSfindBr(ckt,inModel,name) + register CKTcircuit *ckt; + GENmodel *inModel; + register IFuid name; +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + int error; + CKTnode *tmp; + + for( ; model != NULL; model = model->VCVSnextModel) { + for (here = model->VCVSinstances; here != NULL; + here = here->VCVSnextInstance) { + if(here->VCVSname == name) { + if(here->VCVSbranch == 0) { + error = CKTmkCur(ckt,&tmp,here->VCVSname,"branch"); + if(error) return(error); + here->VCVSbranch = tmp->number; + } + return(here->VCVSbranch); + } + } + } + return(0); +} diff --git a/src/spicelib/devices/vcvs/vcvsitf.h b/src/spicelib/devices/vcvs/vcvsitf.h new file mode 100644 index 000000000..14475dc8b --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsitf.h @@ -0,0 +1,87 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_vcvs + +#ifndef DEV_VCVS +#define DEV_VCVS + +#include "vcvsext.h" +extern IFparm VCVSpTable[ ]; +extern char *VCVSnames[ ]; +extern int VCVSpTSize; +extern int VCVSnSize; +extern int VCVSiSize; +extern int VCVSmSize; + +SPICEdev VCVSinfo = { + { + "VCVS", + "Voltage controlled voltage source", + + &VCVSnSize, + &VCVSnSize, + VCVSnames, + + &VCVSpTSize, + VCVSpTable, + + 0, + NULL, + DEV_DEFAULT + }, + + VCVSparam, + NULL, + VCVSload, + VCVSsetup, + VCVSunsetup, + VCVSsetup, + NULL, + NULL, + VCVSfindBr, + VCVSload, /* AC and normal loads are identical */ + NULL, + VCVSdestroy, +#ifdef DELETES + VCVSmDelete, + VCVSdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + VCVSask, + NULL, +#ifdef AN_pz + VCVSpzLoad, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + NULL, +#ifdef AN_sense2 + VCVSsSetup, + VCVSsLoad, + NULL, + VCVSsAcLoad, + VCVSsPrint, + NULL, +#else /* AN_sense2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +#endif /* AN_sense2 */ + NULL, /* DISTO */ + NULL, /* NOISE */ + + &VCVSiSize, + &VCVSmSize + +}; + + +#endif +#endif diff --git a/src/spicelib/devices/vcvs/vcvsload.c b/src/spicelib/devices/vcvs/vcvsload.c new file mode 100644 index 000000000..dbe38d850 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsload.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +VCVSload(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCVSinstances; here != NULL ; + here=here->VCVSnextInstance) { + if (here->VCVSowner != ARCHme) continue; + + *(here->VCVSposIbrptr) += 1.0 ; + *(here->VCVSnegIbrptr) -= 1.0 ; + *(here->VCVSibrPosptr) += 1.0 ; + *(here->VCVSibrNegptr) -= 1.0 ; + *(here->VCVSibrContPosptr) -= here->VCVScoeff ; + *(here->VCVSibrContNegptr) += here->VCVScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/vcvs/vcvsmdel.c b/src/spicelib/devices/vcvs/vcvsmdel.c new file mode 100644 index 000000000..1b17dce03 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCVSmDelete(inModel,modname,kill) + GENmodel **inModel; + IFuid modname; + GENmodel *kill; +{ + VCVSmodel **model = (VCVSmodel**)inModel; + VCVSmodel *modfast = (VCVSmodel *)kill; + VCVSinstance *here; + VCVSinstance *prev = NULL; + VCVSmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->VCVSnextModel)) { + if( (*model)->VCVSmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->VCVSnextModel; /* cut deleted device out of list */ + for(here = (*model)->VCVSinstances ; here ; here = here->VCVSnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/vcvs/vcvspar.c b/src/spicelib/devices/vcvs/vcvspar.c new file mode 100644 index 000000000..291dbe7c3 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvspar.c @@ -0,0 +1,37 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "ifsim.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +VCVSparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + VCVSinstance *here = (VCVSinstance *)inst; + switch(param) { + case VCVS_GAIN: + here->VCVScoeff = value->rValue; + here->VCVScoeffGiven = TRUE; + break; + case VCVS_GAIN_SENS: + here->VCVSsenParmNo = value->iValue; + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/vcvs/vcvspzld.c b/src/spicelib/devices/vcvs/vcvspzld.c new file mode 100644 index 000000000..8e890aba6 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvspzld.c @@ -0,0 +1,47 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "vcvsdefs.h" +#include "suffix.h" + + +/*ARGSUSED*/ +int +VCVSpzLoad(inModel,ckt,s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCVSinstances; here != NULL ; + here=here->VCVSnextInstance) { + if (here->VCVSowner != ARCHme) continue; + + *(here->VCVSposIbrptr) += 1.0 ; + *(here->VCVSnegIbrptr) -= 1.0 ; + *(here->VCVSibrPosptr) += 1.0 ; + *(here->VCVSibrNegptr) -= 1.0 ; + *(here->VCVSibrContPosptr) -= here->VCVScoeff ; + *(here->VCVSibrContNegptr) += here->VCVScoeff ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/vcvs/vcvssacl.c b/src/spicelib/devices/vcvs/vcvssacl.c new file mode 100644 index 000000000..c7d840ebb --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvssacl.c @@ -0,0 +1,54 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current ac sensitivity information into the + * array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCVSsAcLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + double vc; + double ivc; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCVSinstances; here != NULL ; + here=here->VCVSnextInstance) { + if (here->VCVSowner != ARCHme) continue; + + if(here->VCVSsenParmNo){ + + vc = *(ckt->CKTrhsOld + here->VCVScontPosNode) + - *(ckt->CKTrhsOld + here->VCVScontNegNode); + ivc = *(ckt->CKTirhsOld + here->VCVScontPosNode) + - *(ckt->CKTirhsOld + here->VCVScontNegNode); + + *(ckt->CKTsenInfo->SEN_RHS[here->VCVSbranch] + + here->VCVSsenParmNo) += vc; + *(ckt->CKTsenInfo->SEN_iRHS[here->VCVSbranch] + + here->VCVSsenParmNo) += ivc; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/vcvs/vcvsset.c b/src/spicelib/devices/vcvs/vcvsset.c new file mode 100644 index 000000000..0a995992a --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvsset.c @@ -0,0 +1,84 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +/* load the voltage source structure with those pointers needed later + * for fast matrix loading + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + +/*ARGSUSED*/ +int +VCVSsetup(matrix,inModel,ckt,states) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *states; +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + int error; + CKTnode *tmp; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCVSinstances; here != NULL ; + here=here->VCVSnextInstance) { + + if(here->VCVSbranch == 0) { + error = CKTmkCur(ckt,&tmp,here->VCVSname,"branch"); + if(error) return(error); + here->VCVSbranch = tmp->number; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(VCVSposIbrptr, VCVSposNode, VCVSbranch) + TSTALLOC(VCVSnegIbrptr, VCVSnegNode, VCVSbranch) + TSTALLOC(VCVSibrNegptr, VCVSbranch, VCVSnegNode) + TSTALLOC(VCVSibrPosptr, VCVSbranch, VCVSposNode) + TSTALLOC(VCVSibrContPosptr, VCVSbranch, VCVScontPosNode) + TSTALLOC(VCVSibrContNegptr, VCVSbranch, VCVScontNegNode) + } + } + return(OK); +} + +int +VCVSunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + VCVSmodel *model; + VCVSinstance *here; + + for (model = (VCVSmodel *)inModel; model != NULL; + model = model->VCVSnextModel) + { + for (here = model->VCVSinstances; here != NULL; + here=here->VCVSnextInstance) + { + if (here->VCVSbranch) { + CKTdltNNum(ckt, here->VCVSbranch); + here->VCVSbranch = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/vcvs/vcvssld.c b/src/spicelib/devices/vcvs/vcvssld.c new file mode 100644 index 000000000..f87d168af --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvssld.c @@ -0,0 +1,49 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* actually load the current sensitivity information into the + * array previously provided + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCVSsLoad(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + double vc; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCVSinstances; here != NULL ; + here=here->VCVSnextInstance) { + if (here->VCVSowner != ARCHme) continue; + + if(here->VCVSsenParmNo){ + + vc = *(ckt->CKTrhsOld + here->VCVScontPosNode) + - *(ckt->CKTrhsOld + here->VCVScontNegNode); + + *(ckt->CKTsenInfo->SEN_RHS[here->VCVSbranch] + + here->VCVSsenParmNo) += vc; + } + } + } + return(OK); +} + diff --git a/src/spicelib/devices/vcvs/vcvssprt.c b/src/spicelib/devices/vcvs/vcvssprt.c new file mode 100644 index 000000000..cb054cc0a --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvssprt.c @@ -0,0 +1,52 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* Pretty print the sensitivity info for + * all the VCVS in the circuit. + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +void +VCVSsPrint(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + + printf("VOLTAGE CONTROLLED VOLTAGE SOURCES-----------------\n"); + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VCVSnextModel ) { + + printf("Model name:%s\n",model->VCVSmodName); + + /* loop through all the instances of the model */ + for (here = model->VCVSinstances; here != NULL ; + here=here->VCVSnextInstance) { + if (here->VCVSowner != ARCHme) continue; + + printf(" Instance name:%s\n",here->VCVSname); + printf(" Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->VCVSposNode), + CKTnodName(ckt,here->VCVSnegNode)); + printf(" Controlling Positive, negative nodes: %s, %s\n", + CKTnodName(ckt,here->VCVScontPosNode), + CKTnodName(ckt,here->VCVScontNegNode)); + printf(" Branch equation number: %s\n", + CKTnodName(ckt,here->VCVSbranch)); + printf(" Coefficient: %f\n",here->VCVScoeff); + printf(" VCVSsenParmNo:%d\n",here->VCVSsenParmNo); + } + } +} diff --git a/src/spicelib/devices/vcvs/vcvssset.c b/src/spicelib/devices/vcvs/vcvssset.c new file mode 100644 index 000000000..df44a0580 --- /dev/null +++ b/src/spicelib/devices/vcvs/vcvssset.c @@ -0,0 +1,45 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +/* loop through all the devices and + * allocate parameter #s to design parameters + */ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vcvsdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VCVSsSetup(info,inModel) + register SENstruct *info; + GENmodel *inModel; +{ + register VCVSmodel *model = (VCVSmodel *)inModel; + register VCVSinstance *here; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VCVSnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VCVSinstances; here != NULL ; + here=here->VCVSnextInstance) { + if (here->VCVSowner != ARCHme) continue; + + if(here->VCVSsenParmNo){ + here->VCVSsenParmNo = ++(info->SENparms); + } + + } + } + return(OK); +} + diff --git a/src/spicelib/devices/vsrc/ChangeLog b/src/spicelib/devices/vsrc/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/src/spicelib/devices/vsrc/Makefile.am b/src/spicelib/devices/vsrc/Makefile.am new file mode 100644 index 000000000..e3eb3a318 --- /dev/null +++ b/src/spicelib/devices/vsrc/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +pkglib_LTLIBRARIES = libvsrc.la + +libvsrc_la_SOURCES = \ + vsrc.c \ + vsrcacct.c \ + vsrcacld.c \ + vsrcask.c \ + vsrcdefs.h \ + vsrcdel.c \ + vsrcdest.c \ + vsrcext.h \ + vsrcfbr.c \ + vsrcitf.h \ + vsrcload.c \ + vsrcmdel.c \ + vsrcpar.c \ + vsrcpzld.c \ + vsrcpzs.c \ + vsrcset.c \ + vsrctemp.c + + + +INCLUDES = -I$(top_srcdir)/src/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/spicelib/devices/vsrc/vsrc.c b/src/spicelib/devices/vsrc/vsrc.c new file mode 100644 index 000000000..4e7e69850 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrc.c @@ -0,0 +1,46 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "devdefs.h" +#include "ifsim.h" +#include "vsrcdefs.h" +#include "suffix.h" + +IFparm VSRCpTable[] = { /* parameters */ + IOPP("dc", VSRC_DC, IF_REAL ,"D.C. source value"), + IOPPA("acmag", VSRC_AC_MAG, IF_REAL ,"A.C. Magnitude"), + IOPAAU("acphase", VSRC_AC_PHASE, IF_REAL ,"A.C. Phase"), + IP ("pulse", VSRC_PULSE, IF_REALVEC,"Pulse description"), + IP ("sine", VSRC_SINE, IF_REALVEC,"Sinusoidal source description"), + IP ("sin", VSRC_SINE, IF_REALVEC,"Sinusoidal source description"), + IP ("exp", VSRC_EXP, IF_REALVEC,"Exponential source description"), + IP ("pwl", VSRC_PWL, IF_REALVEC,"Piecewise linear description"), + IP ("sffm", VSRC_SFFM, IF_REALVEC,"Single freq. FM descripton"), + OPU ("pos_node",VSRC_POS_NODE, IF_INTEGER,"Positive node of source"), + OPU ("neg_node",VSRC_NEG_NODE, IF_INTEGER,"Negative node of source"), + OPU ("function",VSRC_FCN_TYPE, IF_INTEGER,"Function of the source"), + OPU ("order", VSRC_FCN_ORDER, IF_INTEGER,"Order of the source function"), + OPU ("coeffs", VSRC_FCN_COEFFS,IF_REALVEC,"Coefficients for the function"), + OPU ("acreal", VSRC_AC_REAL, IF_REAL, "AC real part"), + OPU ("acimag", VSRC_AC_IMAG, IF_REAL, "AC imaginary part"), + IP ("ac", VSRC_AC, IF_REALVEC,"AC magnitude, phase vector"), + OP ("i", VSRC_CURRENT, IF_REAL, "Voltage source current"), + OP ("p", VSRC_POWER, IF_REAL, "Instantaneous power"), + IP ("distof1", VSRC_D_F1, IF_REALVEC,"f1 input for distortion"), + IP ("distof2", VSRC_D_F2, IF_REALVEC,"f2 input for distortion") +}; + +char *VSRCnames[] = { + "V+", + "V-" +}; + +int VSRCnSize = NUMELEMS(VSRCnames); +int VSRCpTSize = NUMELEMS(VSRCpTable); +int VSRCmPTSize = 0; +int VSRCiSize = sizeof(VSRCinstance); +int VSRCmSize = sizeof(VSRCmodel); diff --git a/src/spicelib/devices/vsrc/vsrcacct.c b/src/spicelib/devices/vsrc/vsrcacct.c new file mode 100644 index 000000000..a59765eb5 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcacct.c @@ -0,0 +1,176 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vsrcdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +VSRCaccept(ckt,inModel) + register CKTcircuit *ckt; + GENmodel *inModel; + /* set up the breakpoint table. + */ +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + int error; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VSRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VSRCinstances; here != NULL ; + here=here->VSRCnextInstance) { + + if(!ckt->CKTmode & (MODETRAN | MODETRANOP)) { + /* not transient, so shouldn't be here */ + return(OK); + } else { + /* use the transient functions */ + switch(here->VSRCfunctionType) { + default: { /* no function specified:DC no breakpoints */ + break; + } + + case PULSE: { + double TD, TR, TF, PW, PER; + double time; + double basetime = 0; + + TD = here->VSRCfunctionOrder > 2 + ? here->VSRCcoeffs[2] : 0.0; + TR = here->VSRCfunctionOrder > 3 + && here->VSRCcoeffs[3] != 0.0 + ? here->VSRCcoeffs[3] : ckt->CKTstep; + TF = here->VSRCfunctionOrder > 4 + && here->VSRCcoeffs[4] != 0.0 + ? here->VSRCcoeffs[4] : ckt->CKTstep; + PW = here->VSRCfunctionOrder > 5 + && here->VSRCcoeffs[5] != 0.0 + ? here->VSRCcoeffs[5] : ckt->CKTfinalTime; + PER = here->VSRCfunctionOrder > 6 + && here->VSRCcoeffs[6] != 0.0 + ? here->VSRCcoeffs[6] : ckt->CKTfinalTime; + +/* + #define TD ((here->VSRCfunctionOrder >=3)?(*(here->VSRCcoeffs+2)):\ + (0.0)) + #define TR ((here->VSRCfunctionOrder >=4)?(*(here->VSRCcoeffs+3)):\ + (ckt->CKTstep)) + #define TF ((here->VSRCfunctionOrder >=5)?(*(here->VSRCcoeffs+4)):\ + (ckt->CKTstep)) + #define PW ((here->VSRCfunctionOrder >=6)?(*(here->VSRCcoeffs+5)):\ + (ckt->CKTfinalTime)) + #define PER ((here->VSRCfunctionOrder>=7)?(*(here->VSRCcoeffs+6)):\ + (ckt->CKTfinalTime)) +*/ + +#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW) +#define TIMETOL 1e-7 + + time = ckt->CKTtime - TD; + /* if(ckt->CKTtime >= PER) XXX was this */ + if(time >= PER) { + /* repeating signal - figure out where we are */ + /* in period */ + basetime = PER * floor(time/PER); + time -= basetime; + } + if( time <= 0 || time >= TR + PW + TF) { + if(ckt->CKTbreak && SAMETIME(time,0)) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TR +TD); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(TR+PW+TF,time) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + PER + TD); + if(error) return(error); + } else if (ckt->CKTbreak && (time == -TD) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD); + if(error) return(error); + } else if (ckt->CKTbreak && SAMETIME(PER,time) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD + TR + PER); + if(error) return(error); + } + } else if ( time >= TR && time <= TR + PW) { + if(ckt->CKTbreak && SAMETIME(time,TR) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(TR+PW,time) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW + TF); + if(error) return(error); + } + } else if (time > 0 && time < TR) { + if(ckt->CKTbreak && SAMETIME(time,0) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(time,TR)) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW); + if(error) return(error); + } + } else { /* time > TR + PW && < TR + PW + TF */ + if(ckt->CKTbreak && SAMETIME(time,TR+PW) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+TR + PW +TF); + if(error) return(error); + } else if(ckt->CKTbreak && SAMETIME(time,TR+PW+TF) ) { + /* set next breakpoint */ + error = CKTsetBreak(ckt,basetime + TD+PER); + if(error) return(error); + } + } + } + break; + + case SINE: { + /* no breakpoints (yet) */ + } + break; + case EXP: { + /* no breakpoints (yet) */ + } + break; + case SFFM:{ + /* no breakpoints (yet) */ + } + break; + case PWL: { + register int i; + if(ckt->CKTtime < *(here->VSRCcoeffs)) { + if(ckt->CKTbreak) { + error = CKTsetBreak(ckt,*(here->VSRCcoeffs)); + break; + } + } + for(i=0;i<(here->VSRCfunctionOrder/2)-1;i++) { + if((*(here->VSRCcoeffs+2*i)==ckt->CKTtime)) { + if(ckt->CKTbreak) { + error = CKTsetBreak(ckt, + *(here->VSRCcoeffs+2*i+2)); + if(error) return(error); + } + goto bkptset; + } + } + break; + } + } + } +bkptset: ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/vsrc/vsrcacld.c b/src/spicelib/devices/vsrc/vsrcacld.c new file mode 100644 index 000000000..f8f25376f --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcacld.c @@ -0,0 +1,40 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VSRCacLoad(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + + for( ; model != NULL; model = model->VSRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VSRCinstances; here != NULL ; + here=here->VSRCnextInstance) { + if (here->VSRCowner != ARCHme) continue; + + *(here->VSRCposIbrptr) += 1.0 ; + *(here->VSRCnegIbrptr) -= 1.0 ; + *(here->VSRCibrPosptr) += 1.0 ; + *(here->VSRCibrNegptr) -= 1.0 ; + *(ckt->CKTrhs + (here->VSRCbranch)) += here->VSRCacReal; + *(ckt->CKTirhs + (here->VSRCbranch)) += here->VSRCacImag; + } + } + return(OK); +} diff --git a/src/spicelib/devices/vsrc/vsrcask.c b/src/spicelib/devices/vsrc/vsrcask.c new file mode 100644 index 000000000..364519918 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcask.c @@ -0,0 +1,112 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1987 Thomas L. Quarles +**********/ +/* + */ + +/* + * This routine gives access to the internal device parameters + * of independent Voltage SouRCe + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "devdefs.h" +#include "ifsim.h" +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +VSRCask(ckt,inst,which,value,select) + CKTcircuit *ckt; + GENinstance *inst; + int which; + IFvalue *value; + IFvalue *select; +{ + VSRCinstance *here = (VSRCinstance*)inst; + int temp; + static char *msg = "Current and power not available in ac analysis"; + double *v, *w; + + switch(which) { + case VSRC_DC: + value->rValue = here->VSRCdcValue; + return (OK); + case VSRC_AC_MAG: + value->rValue = here->VSRCacMag; + return (OK); + case VSRC_AC_PHASE: + value->rValue = here->VSRCacPhase; + return (OK); + case VSRC_PULSE: + case VSRC_SINE: + case VSRC_EXP: + case VSRC_PWL: + case VSRC_SFFM: + case VSRC_FCN_COEFFS: + temp = value->v.numValue = here->VSRCfunctionOrder; + v = value->v.vec.rVec = (double *) + MALLOC (here->VSRCfunctionOrder * sizeof(double)); + w = here->VSRCcoeffs; + while (temp--) { + *v++ = *w++; + } + return (OK); + case VSRC_AC: + value->v.numValue = 2; + value->v.vec.rVec = (double *) + MALLOC (value->v.numValue * sizeof (double)); + value->v.vec.rVec[0] = here->VSRCacMag; + value->v.vec.rVec[1] = here->VSRCacPhase; + return (OK); + case VSRC_NEG_NODE: + value->iValue = here->VSRCnegNode; + return (OK); + case VSRC_POS_NODE: + value->iValue = here->VSRCposNode; + return (OK); + case VSRC_FCN_TYPE: + value->iValue = here->VSRCfunctionType; + return (OK); + case VSRC_AC_REAL: + value->rValue = here->VSRCacReal; + return (OK); + case VSRC_AC_IMAG: + value->rValue = here->VSRCacImag; + return (OK); + case VSRC_FCN_ORDER: + value->rValue = here->VSRCfunctionOrder; + return (OK); + case VSRC_CURRENT: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "VSRCask"; + strcpy(errMsg,msg); + return(E_ASKCURRENT); + } else { + value->rValue = *(ckt->CKTrhsOld+here->VSRCbranch); + } + return(OK); + case VSRC_POWER: + if (ckt->CKTcurrentAnalysis & DOING_AC) { + errMsg = MALLOC(strlen(msg)+1); + errRtn = "VSRCask"; + strcpy(errMsg,msg); + return(E_ASKPOWER); + } else { + value->rValue = (*(ckt->CKTrhsOld+here->VSRCposNode) + - *(ckt->CKTrhsOld + here->VSRCnegNode)) * + -*(ckt->CKTrhsOld + here->VSRCbranch); + } + return(OK); + default: + return (E_BADPARM); + } + /* NOTREACHED */ +} diff --git a/src/spicelib/devices/vsrc/vsrcdefs.h b/src/spicelib/devices/vsrc/vsrcdefs.h new file mode 100644 index 000000000..867379ddc --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcdefs.h @@ -0,0 +1,124 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifndef VSRC +#define VSRC + +#include "ifsim.h" +#include "cktdefs.h" +#include "gendefs.h" +#include "complex.h" + + /* + * structures to describe independent voltage sources + */ + + +/* information needed for each instance */ + +typedef struct sVSRCinstance { + struct sVSRCmodel *VSRCmodPtr; /* backpointer to model */ + struct sVSRCinstance *VSRCnextInstance; /* pointer to next instance of + *current model */ + IFuid VSRCname; /* pointer to character string naming this instance */ + int VSRCowner; /* number of owner process */ + int VSRCstate; /* not used */ + + int VSRCposNode; /* number of positive node of resistor */ + int VSRCnegNode; /* number of negative node of resistor */ + + int VSRCbranch; /* equation number of branch equation added for source */ + + int VSRCfunctionType; /* code number of function type for source */ + int VSRCfunctionOrder; /* order of the function for the source */ + double *VSRCcoeffs; /* pointer to array of coefficients */ + + double VSRCdcValue; /* DC and TRANSIENT value of source */ + + double VSRCacPhase; /* AC phase angle */ + double VSRCacMag; /* AC magnitude */ + + double VSRCacReal; /* AC real component */ + double VSRCacImag; /* AC imaginary component */ + + double VSRCdF1mag; /* distortion f1 magnitude */ + double VSRCdF2mag; /* distortion f2 magnitude */ + double VSRCdF1phase; /* distortion f1 phase */ + double VSRCdF2phase; /* distortion f2 phase */ + + double *VSRCposIbrptr; /* pointer to sparse matrix element at + * (positive node, branch equation) */ + double *VSRCnegIbrptr; /* pointer to sparse matrix element at + * (negative node, branch equation) */ + double *VSRCibrPosptr; /* pointer to sparse matrix element at + * (branch equation, positive node) */ + double *VSRCibrNegptr; /* pointer to sparse matrix element at + * (branch equation, negative node) */ + double *VSRCibrIbrptr; /* pointer to sparse matrix element at + * (branch equation, branch equation) */ + unsigned VSRCdcGiven :1 ; /* flag to indicate dc value given */ + unsigned VSRCacGiven :1 ; /* flag to indicate ac keyword given */ + unsigned VSRCacMGiven :1 ; /* flag to indicate ac magnitude given */ + unsigned VSRCacPGiven :1 ; /* flag to indicate ac phase given */ + unsigned VSRCfuncTGiven :1 ; /* flag to indicate function type given */ + unsigned VSRCcoeffsGiven :1 ; /* flag to indicate function coeffs given */ + unsigned VSRCdGiven :1 ; /* flag to indicate source is a disto input */ + unsigned VSRCdF1given :1; /* flag to indicate source is an f1 dist input */ + unsigned VSRCdF2given :1; /* flag to indicate source is an f2 dist input */ +} VSRCinstance ; + + +/* per model data */ + +typedef struct sVSRCmodel { + int VSRCmodType; /* type index of this device type */ + struct sVSRCmodel *VSRCnextModel; /* pointer to next possible model + *in linked list */ + VSRCinstance * VSRCinstances; /* pointer to list of instances + * that have this model */ + IFuid VSRCmodName; /* pointer to character string naming this model */ +} VSRCmodel; + +/* source function types (shared with current sources) */ +#ifndef PULSE +#define PULSE 1 +#define SINE 2 +#define EXP 3 +#define SFFM 4 +#define PWL 5 +#endif /*PULSE*/ + +/* device parameters */ +#define VSRC_DC 1 +#define VSRC_AC 2 +#define VSRC_AC_MAG 3 +#define VSRC_AC_PHASE 4 +#define VSRC_PULSE 5 +#define VSRC_SINE 6 +#define VSRC_EXP 7 +#define VSRC_PWL 8 +#define VSRC_SFFM 9 +#define VSRC_BR 10 +#define VSRC_FCN_TYPE 11 +#define VSRC_FCN_ORDER 12 +#define VSRC_FCN_COEFFS 13 +#define VSRC_AC_REAL 14 +#define VSRC_AC_IMAG 15 +#define VSRC_POS_NODE 16 +#define VSRC_NEG_NODE 17 +#define VSRC_CURRENT 18 +#define VSRC_POWER 19 +#define VSRC_D_F1 20 +#define VSRC_D_F2 21 + +/* model parameters */ + +/* device questions */ + +/* model questions */ + +#include "vsrcext.h" + +#endif /*VSRC*/ diff --git a/src/spicelib/devices/vsrc/vsrcdel.c b/src/spicelib/devices/vsrc/vsrcdel.c new file mode 100644 index 000000000..5e3bc779e --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcdel.c @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VSRCdelete(inModel,name,inst) + GENmodel *inModel; + IFuid name; + GENinstance **inst; +{ + VSRCmodel *model = (VSRCmodel *)inModel; + VSRCinstance **fast = (VSRCinstance**)inst; + VSRCinstance **prev = NULL; + VSRCinstance *here; + + for( ; model ; model = model->VSRCnextModel) { + prev = &(model->VSRCinstances); + for(here = *prev; here ; here = *prev) { + if(here->VSRCname == name || (fast && here==*fast) ) { + *prev= here->VSRCnextInstance; + FREE(here); + return(OK); + } + prev = &(here->VSRCnextInstance); + } + } + return(E_NODEV); +} diff --git a/src/spicelib/devices/vsrc/vsrcdest.c b/src/spicelib/devices/vsrc/vsrcdest.c new file mode 100644 index 000000000..e624efac7 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcdest.c @@ -0,0 +1,36 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vsrcdefs.h" +#include "suffix.h" + + +void +VSRCdestroy(inModel) + GENmodel **inModel; +{ + VSRCmodel **model = (VSRCmodel**)inModel; + VSRCinstance *here; + VSRCinstance *prev = NULL; + VSRCmodel *mod = *model; + VSRCmodel *oldmod = NULL; + + for( ; mod ; mod = mod->VSRCnextModel) { + if(oldmod) FREE(oldmod); + oldmod = mod; + prev = (VSRCinstance *)NULL; + for(here = mod->VSRCinstances ; here ; here = here->VSRCnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + } + if(oldmod) FREE(oldmod); + *model = NULL; +} diff --git a/src/spicelib/devices/vsrc/vsrcext.h b/src/spicelib/devices/vsrc/vsrcext.h new file mode 100644 index 000000000..9037f1482 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcext.h @@ -0,0 +1,38 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#ifdef __STDC__ +extern int VSRCacLoad(GENmodel*,CKTcircuit*); +extern int VSRCaccept(CKTcircuit*,GENmodel *); +extern int VSRCask(CKTcircuit*,GENinstance*,int,IFvalue*,IFvalue*); +extern int VSRCdelete(GENmodel*,IFuid,GENinstance**); +extern void VSRCdestroy(GENmodel**); +extern int VSRCfindBr(CKTcircuit*,GENmodel*,IFuid); +extern int VSRCload(GENmodel*,CKTcircuit*); +extern int VSRCmAsk(CKTcircuit*,GENmodel*,int,IFvalue*); +extern int VSRCmDelete(GENmodel**,IFuid,GENmodel*); +extern int VSRCparam(int,IFvalue*,GENinstance*,IFvalue*); +extern int VSRCpzLoad(GENmodel*,CKTcircuit*,SPcomplex*); +extern int VSRCsetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int VSRCunsetup(GENmodel*,CKTcircuit*); +extern int VSRCpzSetup(SMPmatrix*,GENmodel*,CKTcircuit*,int*); +extern int VSRCtemp(GENmodel*,CKTcircuit*); +#else /* stdc */ +extern int VSRCacLoad(); +extern int VSRCaccept(); +extern int VSRCask(); +extern int VSRCdelete(); +extern void VSRCdestroy(); +extern int VSRCfindBr(); +extern int VSRCload(); +extern int VSRCmAsk(); +extern int VSRCmDelete(); +extern int VSRCparam(); +extern int VSRCpzLoad(); +extern int VSRCsetup(); +extern int VSRCunsetup(); +extern int VSRCpzSetup(); +extern int VSRCtemp(); +#endif /* stdc */ diff --git a/src/spicelib/devices/vsrc/vsrcfbr.c b/src/spicelib/devices/vsrc/vsrcfbr.c new file mode 100644 index 000000000..b2ecf433e --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcfbr.c @@ -0,0 +1,41 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VSRCfindBr(ckt,inModel,name) + register CKTcircuit *ckt; + GENmodel *inModel; + register IFuid name; +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + int error; + CKTnode *tmp; + + for( ; model != NULL; model = model->VSRCnextModel) { + for (here = model->VSRCinstances; here != NULL; + here = here->VSRCnextInstance) { + if(here->VSRCname == name) { + if(here->VSRCbranch == 0) { + error = CKTmkCur(ckt,&tmp,here->VSRCname,"branch"); + if(error) return(error); + here->VSRCbranch = tmp->number; + } + return(here->VSRCbranch); + } + } + } + return(0); +} diff --git a/src/spicelib/devices/vsrc/vsrcitf.h b/src/spicelib/devices/vsrc/vsrcitf.h new file mode 100644 index 000000000..4aeda0056 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcitf.h @@ -0,0 +1,77 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +**********/ +#ifdef DEV_vsrc + +#ifndef DEV_VSRC +#define DEV_VSRC + +#include "vsrcext.h" +extern IFparm VSRCpTable[ ]; +extern char *VSRCnames[ ]; +extern int VSRCpTSize; +extern int VSRCnSize; +extern int VSRCiSize; +extern int VSRCmSize; + +SPICEdev VSRCinfo = { + { + "Vsource", + "Independent voltage source", + + &VSRCnSize, + &VSRCnSize, + VSRCnames, + + &VSRCpTSize, + VSRCpTable, + + 0, + NULL, + DEV_DEFAULT + }, + + VSRCparam, + NULL, + VSRCload, + VSRCsetup, + VSRCunsetup, +#ifdef AN_pz + VSRCpzSetup, +#else /* AN_pz */ + NULL, +#endif /* AN_pz */ + VSRCtemp, + NULL, + VSRCfindBr, + VSRCacLoad, + VSRCaccept, + VSRCdestroy, +#ifdef DELETES + VSRCmDelete, + VSRCdelete, +#else /* DELETES */ + NULL, + NULL, +#endif /* DELETES */ + NULL, + VSRCask, + NULL, + VSRCpzLoad, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, /* DISTO */ + NULL, /* NOISE */ + + &VSRCiSize, + &VSRCmSize +}; + + +#endif +#endif diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c new file mode 100644 index 000000000..b80d701be --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -0,0 +1,214 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "vsrcdefs.h" +#include "trandefs.h" +#include "sperror.h" +#include "suffix.h" + +int +VSRCload(inModel,ckt) + GENmodel *inModel; + register CKTcircuit *ckt; + /* actually load the current voltage value into the + * sparse matrix previously provided + */ +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + double time; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VSRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VSRCinstances; here != NULL ; + here=here->VSRCnextInstance) { + if (here->VSRCowner != ARCHme) continue; + + *(here->VSRCposIbrptr) += 1.0 ; + *(here->VSRCnegIbrptr) -= 1.0 ; + *(here->VSRCibrPosptr) += 1.0 ; + *(here->VSRCibrNegptr) -= 1.0 ; + if( (ckt->CKTmode & (MODEDCOP | MODEDCTRANCURVE)) && + here->VSRCdcGiven ) { + /* grab dc value */ + *(ckt->CKTrhs + (here->VSRCbranch)) += ckt->CKTsrcFact * + here->VSRCdcValue; + } else { + if(ckt->CKTmode & (MODEDC)) { + time = 0; + } else { + time = ckt->CKTtime; + } + /* use the transient functions */ + switch(here->VSRCfunctionType) { + default: { /* no function specified: use the DC value */ + *(ckt->CKTrhs + (here->VSRCbranch)) += here->VSRCdcValue; + break; + } + + case PULSE: { + double V1, V2, TD, TR, TF, PW, PER; + double basetime = 0; + + V1 = here->VSRCcoeffs[0]; + V2 = here->VSRCcoeffs[1]; + TD = here->VSRCfunctionOrder > 2 + ? here->VSRCcoeffs[2] : 0.0; + TR = here->VSRCfunctionOrder > 3 + && here->VSRCcoeffs[3] != 0.0 + ? here->VSRCcoeffs[3] : ckt->CKTstep; + TF = here->VSRCfunctionOrder > 4 + && here->VSRCcoeffs[4] != 0.0 + ? here->VSRCcoeffs[4] : ckt->CKTstep; + PW = here->VSRCfunctionOrder > 5 + && here->VSRCcoeffs[5] != 0.0 + ? here->VSRCcoeffs[5] : ckt->CKTfinalTime; + PER = here->VSRCfunctionOrder > 6 + && here->VSRCcoeffs[6] != 0.0 + ? here->VSRCcoeffs[6] : ckt->CKTfinalTime; + + time -= TD; + if(time > PER) { + /* repeating signal - figure out where we are */ + /* in period */ + basetime = PER * floor(time/PER); + time -= basetime; + } + if (time <= 0 || time >= TR + PW + TF) { + ckt->CKTrhs[here->VSRCbranch] += V1; + } else if (time >= TR && time <= TR + PW) { + ckt->CKTrhs[here->VSRCbranch] += V2; + } else if (time > 0 && time < TR) { + ckt->CKTrhs[here->VSRCbranch] += + V1 + (V2 - V1) * (time) / TR; + } else { /* time > TR + PW && < TR + PW + TF */ + ckt->CKTrhs[here->VSRCbranch] += + V2 + (V1 - V2) * (time - (TR + PW)) / TF; + } + + } + break; + + case SINE: { +#define VO (*(here->VSRCcoeffs)) +#define VA (*(here->VSRCcoeffs+1)) +#define FREQ (((here->VSRCfunctionOrder >=3) && (*(here->VSRCcoeffs+2)))? \ + (*(here->VSRCcoeffs+2)):(1/ckt->CKTfinalTime)) +#define TD ((here->VSRCfunctionOrder >=4)?(*(here->VSRCcoeffs+3)):(0.0)) +#define THETA ((here->VSRCfunctionOrder >=5)?(*(here->VSRCcoeffs+4)):(0.0)) + time -= TD; + if (time <= 0) { + *(ckt->CKTrhs + (here->VSRCbranch)) += VO; + } else { + *(ckt->CKTrhs + (here->VSRCbranch)) += + VO + VA * sin(FREQ * time * 2.0 * M_PI) * + exp(-(time*THETA)); + /* 2PI to convert from hz to radians/sec*/ + } +#undef VO +#undef VA +#undef FREQ +#undef TD +#undef THETA + } + break; + + case EXP: { + double td1; + double td2; +#define V1 (*(here->VSRCcoeffs)) +#define V2 (*(here->VSRCcoeffs+1)) +#define TD1 ((here->VSRCfunctionOrder >=3)?(*(here->VSRCcoeffs+2)):\ + ckt->CKTstep) +#define TAU1 (((here->VSRCfunctionOrder >=4) && (*(here->VSRCcoeffs+3)))? \ + (*(here->VSRCcoeffs+3)):ckt->CKTstep) +#define TD2 (((here->VSRCfunctionOrder >=5) && (*(here->VSRCcoeffs+4)))? \ + (*(here->VSRCcoeffs+4)):TD1+ckt->CKTstep) +#define TAU2 (((here->VSRCfunctionOrder >=6) && (*(here->VSRCcoeffs+5)))? \ + (*(here->VSRCcoeffs+5)):ckt->CKTstep) + td1 = TD1; + td2 = TD2; + if(time <= td1) { + *(ckt->CKTrhs + (here->VSRCbranch)) += V1; + } else if (time <= td2) { + *(ckt->CKTrhs + (here->VSRCbranch)) += + V1 + (V2-V1)*(1-exp(-(time-td1)/TAU1)); + } else { + *(ckt->CKTrhs + (here->VSRCbranch)) += + V1 + (V2-V1)*(1-exp(-(time-td1)/TAU1)) + + (V1-V2)*(1-exp(-(time-td2)/TAU2)) ; + } +#undef V1 +#undef V2 +#undef TD1 +#undef TAU1 +#undef TD2 +#undef TAU2 + } + break; + + case SFFM:{ +#define VO (*(here->VSRCcoeffs)) +#define VA (*(here->VSRCcoeffs+1)) +#define FC (((here->VSRCfunctionOrder >=3) && (*(here->VSRCcoeffs+2)))? \ + (*(here->VSRCcoeffs+2)):(1/ckt->CKTfinalTime)) +#define MDI ((here->VSRCfunctionOrder>=4)?(*(here->VSRCcoeffs+3)):\ + 0.0) +#define FS (((here->VSRCfunctionOrder >=5) && (*(here->VSRCcoeffs+4)))? \ + (*(here->VSRCcoeffs+4)):(1/ckt->CKTfinalTime)) + *(ckt->CKTrhs + (here->VSRCbranch)) += VO + VA * + sin((2 * 3.141592654 * FC * time) + + MDI * sin(2 * 3.141592654 * FS * time)); +#undef VO +#undef VA +#undef FC +#undef MDI +#undef FS + } + break; + + case PWL: { + register int i; + double foo; + if(time < *(here->VSRCcoeffs)) { + foo = *(here->VSRCcoeffs + 1) ; + *(ckt->CKTrhs + (here->VSRCbranch)) += foo; + goto loadDone; + } + for(i=0;i<(here->VSRCfunctionOrder/2)-1;i++) { + if((*(here->VSRCcoeffs+2*i)==time)) { + foo = *(here->VSRCcoeffs+2*i+1); + *(ckt->CKTrhs + (here->VSRCbranch)) += + foo; + goto loadDone; + } else if((*(here->VSRCcoeffs+2*i)VSRCcoeffs+2*(i+1)) >time)) { + foo = *(here->VSRCcoeffs+2*i+1) + + (((time-*(here->VSRCcoeffs+2*i))/ + (*(here->VSRCcoeffs+2*(i+1)) - + *(here->VSRCcoeffs+2*i))) * + (*(here->VSRCcoeffs+2*i+3) - + *(here->VSRCcoeffs+2*i+1))); + *(ckt->CKTrhs + (here->VSRCbranch)) += + foo; + goto loadDone; + } + } + foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ; + *(ckt->CKTrhs + (here->VSRCbranch)) += foo; + break; + } + } + } +loadDone: ; + } + } + return(OK); +} diff --git a/src/spicelib/devices/vsrc/vsrcmdel.c b/src/spicelib/devices/vsrc/vsrcmdel.c new file mode 100644 index 000000000..5613b15c1 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcmdel.c @@ -0,0 +1,44 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + + +int +VSRCmDelete(inModel,modname,fast) + GENmodel **inModel; + IFuid modname; + GENmodel *fast; +{ + VSRCmodel **model = (VSRCmodel **)inModel; + VSRCmodel *modfast = (VSRCmodel *)fast; + VSRCinstance *here; + VSRCinstance *prev = NULL; + VSRCmodel **oldmod; + oldmod = model; + for( ; *model ; model = &((*model)->VSRCnextModel)) { + if( (*model)->VSRCmodName == modname || + (modfast && *model == modfast) ) goto delgot; + oldmod = model; + } + return(E_NOMOD); + +delgot: + *oldmod = (*model)->VSRCnextModel; /* cut deleted device out of list */ + for(here = (*model)->VSRCinstances ; here ; here = here->VSRCnextInstance) { + if(prev) FREE(prev); + prev = here; + } + if(prev) FREE(prev); + FREE(*model); + return(OK); + +} diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c new file mode 100644 index 000000000..b7447a895 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -0,0 +1,134 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ +/* + */ + +#include "ngspice.h" +#include +#include "vsrcdefs.h" +#include "ifsim.h" +#include "sperror.h" +#include "suffix.h" + + +/* ARGSUSED */ +int +VSRCparam(param,value,inst,select) + int param; + IFvalue *value; + GENinstance *inst; + IFvalue *select; +{ + VSRCinstance *here = (VSRCinstance *)inst; + switch(param) { + case VSRC_DC: + here->VSRCdcValue = value->rValue; + here->VSRCdcGiven = TRUE; + break; + case VSRC_AC_MAG: + here->VSRCacMag = value->rValue; + here->VSRCacMGiven = TRUE; + here->VSRCacGiven = TRUE; + break; + case VSRC_AC_PHASE: + here->VSRCacPhase = value->rValue; + here->VSRCacPGiven = TRUE; + here->VSRCacGiven = TRUE; + break; + case VSRC_AC: + switch(value->v.numValue) { + case 2: + here->VSRCacPhase = *(value->v.vec.rVec+1); + here->VSRCacPGiven = TRUE; + case 1: + here->VSRCacMag = *(value->v.vec.rVec); + here->VSRCacMGiven = TRUE; + case 0: + here->VSRCacGiven = TRUE; + break; + default: + return(E_BADPARM); + } + break; + case VSRC_PULSE: + here->VSRCfunctionType = PULSE; + here->VSRCfuncTGiven = TRUE; + here->VSRCcoeffs = value->v.vec.rVec; + here->VSRCfunctionOrder = value->v.numValue; + here->VSRCcoeffsGiven = TRUE; + break; + case VSRC_SINE: + here->VSRCfunctionType = SINE; + here->VSRCfuncTGiven = TRUE; + here->VSRCcoeffs = value->v.vec.rVec; + here->VSRCfunctionOrder = value->v.numValue; + here->VSRCcoeffsGiven = TRUE; + break; + case VSRC_EXP: + here->VSRCfunctionType = EXP; + here->VSRCfuncTGiven = TRUE; + here->VSRCcoeffs = value->v.vec.rVec; + here->VSRCfunctionOrder = value->v.numValue; + here->VSRCcoeffsGiven = TRUE; + break; + case VSRC_PWL: + here->VSRCfunctionType = PWL; + here->VSRCfuncTGiven = TRUE; + here->VSRCcoeffs = value->v.vec.rVec; + here->VSRCfunctionOrder = value->v.numValue; + here->VSRCcoeffsGiven = TRUE; + break; + case VSRC_SFFM: + here->VSRCfunctionType = SFFM; + here->VSRCfuncTGiven = TRUE; + here->VSRCcoeffs = value->v.vec.rVec; + here->VSRCfunctionOrder = value->v.numValue; + here->VSRCcoeffsGiven = TRUE; + break; + case VSRC_D_F1: + here->VSRCdF1given = TRUE; + here->VSRCdGiven = TRUE; + switch(value->v.numValue) { + case 2: + here->VSRCdF1phase = *(value->v.vec.rVec+1); + here->VSRCdF1mag = *(value->v.vec.rVec); + break; + case 1: + here->VSRCdF1mag = *(value->v.vec.rVec); + here->VSRCdF1phase = 0.0; + break; + case 0: + here->VSRCdF1mag = 1.0; + here->VSRCdF1phase = 0.0; + break; + default: + return(E_BADPARM); + break; + } + case VSRC_D_F2: + here->VSRCdF2given = TRUE; + here->VSRCdGiven = TRUE; + switch(value->v.numValue) { + case 2: + here->VSRCdF2phase = *(value->v.vec.rVec+1); + here->VSRCdF2mag = *(value->v.vec.rVec); + break; + case 1: + here->VSRCdF2mag = *(value->v.vec.rVec); + here->VSRCdF2phase = 0.0; + break; + case 0: + here->VSRCdF2mag = 1.0; + here->VSRCdF2phase = 0.0; + break; + default: + return(E_BADPARM); + } + break; + default: + return(E_BADPARM); + } + return(OK); +} diff --git a/src/spicelib/devices/vsrc/vsrcpzld.c b/src/spicelib/devices/vsrc/vsrcpzld.c new file mode 100644 index 000000000..7041460f4 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcpzld.c @@ -0,0 +1,50 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "cktdefs.h" +#include "complex.h" +#include "sperror.h" +#include "vsrcdefs.h" +#include "suffix.h" + +/* ARGSUSED */ +int +VSRCpzLoad(inModel,ckt,s) + GENmodel *inModel; + CKTcircuit *ckt; + SPcomplex *s; +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + + for( ; model != NULL; model = model->VSRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VSRCinstances; here != NULL ; + here=here->VSRCnextInstance) { + if (here->VSRCowner != ARCHme) continue; + + if (!(here->VSRCacGiven)) { + /*a dc source*/ + /*the connecting nodes are shorted*/ + *(here->VSRCposIbrptr) += 1.0 ; + *(here->VSRCnegIbrptr) += -1.0 ; + *(here->VSRCibrPosptr) += 1.0 ; + *(here->VSRCibrNegptr) += -1.0 ; + } else { + /*an ac source*/ + /*no effective contribution + *diagonal element made 1 + */ + *(here->VSRCposIbrptr) += 1.0 ; + *(here->VSRCnegIbrptr) += -1.0 ; + *(here->VSRCibrIbrptr) += 1.0 ; + } + } + } + return(OK); +} diff --git a/src/spicelib/devices/vsrc/vsrcpzs.c b/src/spicelib/devices/vsrc/vsrcpzs.c new file mode 100644 index 000000000..e1161db40 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcpzs.c @@ -0,0 +1,57 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +VSRCpzSetup(matrix,inModel,ckt,state) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *state; + /* load the voltage source structure with those pointers needed later + * for fast matrix loading + */ +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + CKTnode *tmp; + int error; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VSRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VSRCinstances; here != NULL ; + here=here->VSRCnextInstance) { + + if(here->VSRCbranch == 0) { + error = CKTmkCur(ckt,&tmp,here->VSRCname,"branch"); + if(error) return(error); + here->VSRCbranch = tmp->number; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(VSRCposIbrptr, VSRCposNode, VSRCbranch) + TSTALLOC(VSRCnegIbrptr, VSRCnegNode, VSRCbranch) + TSTALLOC(VSRCibrNegptr, VSRCbranch, VSRCnegNode) + TSTALLOC(VSRCibrPosptr, VSRCbranch, VSRCposNode) + TSTALLOC(VSRCibrIbrptr, VSRCbranch, VSRCbranch) + } + } + return(OK); +} diff --git a/src/spicelib/devices/vsrc/vsrcset.c b/src/spicelib/devices/vsrc/vsrcset.c new file mode 100644 index 000000000..d3758b520 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrcset.c @@ -0,0 +1,81 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +VSRCsetup(matrix,inModel,ckt,state) + register SMPmatrix *matrix; + GENmodel *inModel; + register CKTcircuit *ckt; + int *state; + /* load the voltage source structure with those pointers needed later + * for fast matrix loading + */ +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + CKTnode *tmp; + int error; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VSRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VSRCinstances; here != NULL ; + here=here->VSRCnextInstance) { + + if(here->VSRCbranch == 0) { + error = CKTmkCur(ckt,&tmp,here->VSRCname,"branch"); + if(error) return(error); + here->VSRCbranch = tmp->number; + } + +/* macro to make elements with built in test for out of memory */ +#define TSTALLOC(ptr,first,second) \ +if((here->ptr = SMPmakeElt(matrix,here->first,here->second))==(double *)NULL){\ + return(E_NOMEM);\ +} + + TSTALLOC(VSRCposIbrptr, VSRCposNode, VSRCbranch) + TSTALLOC(VSRCnegIbrptr, VSRCnegNode, VSRCbranch) + TSTALLOC(VSRCibrNegptr, VSRCbranch, VSRCnegNode) + TSTALLOC(VSRCibrPosptr, VSRCbranch, VSRCposNode) + } + } + return(OK); +} + +int +VSRCunsetup(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; +{ +#ifndef HAS_BATCHSIM + VSRCmodel *model; + VSRCinstance *here; + + for (model = (VSRCmodel *)inModel; model != NULL; + model = model->VSRCnextModel) + { + for (here = model->VSRCinstances; here != NULL; + here=here->VSRCnextInstance) + { + if (here->VSRCbranch) { + CKTdltNNum(ckt, here->VSRCbranch); + here->VSRCbranch = 0; + } + } + } +#endif + return OK; +} diff --git a/src/spicelib/devices/vsrc/vsrctemp.c b/src/spicelib/devices/vsrc/vsrctemp.c new file mode 100644 index 000000000..8dbae8ed7 --- /dev/null +++ b/src/spicelib/devices/vsrc/vsrctemp.c @@ -0,0 +1,59 @@ +/********** +Copyright 1990 Regents of the University of California. All rights reserved. +Author: 1985 Thomas L. Quarles +**********/ + +#include "ngspice.h" +#include +#include "smpdefs.h" +#include "cktdefs.h" +#include "vsrcdefs.h" +#include "sperror.h" +#include "suffix.h" + +/* ARGSUSED */ +int +VSRCtemp(inModel,ckt) + GENmodel *inModel; + CKTcircuit *ckt; + /* Pre-process voltage source parameters + */ +{ + register VSRCmodel *model = (VSRCmodel *)inModel; + register VSRCinstance *here; + double radians; + + /* loop through all the voltage source models */ + for( ; model != NULL; model = model->VSRCnextModel ) { + + /* loop through all the instances of the model */ + for (here = model->VSRCinstances; here != NULL ; + here=here->VSRCnextInstance) { + if (here->VSRCowner != ARCHme) continue; + + if(here->VSRCacGiven && !here->VSRCacMGiven) { + here->VSRCacMag = 1; + } + if(here->VSRCacGiven && !here->VSRCacPGiven) { + here->VSRCacPhase = 0; + } + if(!here->VSRCdcGiven) { + /* no DC value - either have a transient value, or none */ + if(here->VSRCfuncTGiven) { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: no DC value, transient time 0 value used", + &(here->VSRCname)); + } else { + (*(SPfrontEnd->IFerror))(ERR_WARNING, + "%s: has no value, DC 0 assumed", + &(here->VSRCname)); + } + } + radians = here->VSRCacPhase * M_PI / 180.0; + here->VSRCacReal = here->VSRCacMag * cos(radians); + here->VSRCacImag = here->VSRCacMag * sin(radians); + + } + } + return(OK); +} diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 000000000..36b6a187f --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in + +TESTS = diffpair.sh fourbitadder.sh resistor.sh + +TESTS_ENVIRONMENT = $(SHELL) + +EXTRA_DIST = \ + README \ + config.sh \ + $(TESTS) \ + diffpair.cir \ + diffpair.out \ + fourbitadder.cir \ + fourbitadder.out \ + resistor.cir \ + resistor.out + +MAINTAINERCLEANFILES = Makefile.in diff --git a/tests/README b/tests/README new file mode 100644 index 000000000..d10d80754 --- /dev/null +++ b/tests/README @@ -0,0 +1,5 @@ +TO ADD NEW TESTS + +Take an existing test and adopt it to your liking. Add the test +script and its supporting files to Makefile.am. Use `make check' to +see your new test in action. diff --git a/tests/config.sh b/tests/config.sh new file mode 100644 index 000000000..ea8e5d0b6 --- /dev/null +++ b/tests/config.sh @@ -0,0 +1,13 @@ +#! /bin/sh + +NGSPICE=../src/ngspice +DIFFPIPE="Analysis|CPU|memory|Date|Note" + +function spicetest () { + $NGSPICE < $srcdir/$1.cir 2>&1 | egrep -v $DIFFPIPE > $1.test + if diff -u $1.test $srcdir/$1.out; then + rm $1.test + exit 0 + fi + exit 1 +} diff --git a/tests/diffpair.cir b/tests/diffpair.cir new file mode 100644 index 000000000..c926364f3 --- /dev/null +++ b/tests/diffpair.cir @@ -0,0 +1,29 @@ +simple differential pair - CM and DM dc sensitivity + +* Models: +.model qnl npn(bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf va=50) +.model qnr npn(bf=80 rb=100 ccs=2pf tf=0.3ns tr=6ns cje=3pf cjc=2pf va=50) + +* Circuit description: +q1 4 2 6 qnr +q2 5 3 6 qnl +rs1 11 2 1k +rs2 3 1 1k +rc1 4 8 10k +rc2 5 8 10k +q3 7 7 9 qnl +q4 6 7 9 qnr +rbias 7 8 20k + +* Inputs/Supplies: +vcm 1 0 dc 0 sin(0 0.1 5meg) ac 1 +vdm 1 11 dc 0 sin(0 0.1 5meg) ac 1 +vcc 8 0 12 +vee 9 0 -12 + +* Analysys: +.tf v(5) vcm +.tf v(5) vdm +.sens v(5,4) + +.end diff --git a/tests/diffpair.out b/tests/diffpair.out new file mode 100644 index 000000000..cd91abbdf --- /dev/null +++ b/tests/diffpair.out @@ -0,0 +1,19 @@ + +Circuit: simple differential pair - CM and DM dc sensitivity + +Circuit: simple differential pair - CM and DM dc sensitivity + + +Transfer function information: +transfer_function = -1.10340e-01 +output_impedance_at_v(5) = 9.446409e+03 +vcm#input_impedance = 1.792504e+06 + +Transfer function information: +transfer_function = -8.78993e+01 +output_impedance_at_v(5) = 9.446409e+03 +vdm#input_impedance = 8.934967e+03 + + + + diff --git a/tests/diffpair.sh b/tests/diffpair.sh new file mode 100644 index 000000000..7baba1433 --- /dev/null +++ b/tests/diffpair.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +. $srcdir/config.sh +spicetest diffpair diff --git a/tests/fourbitadder.cir b/tests/fourbitadder.cir new file mode 100644 index 000000000..101e46605 --- /dev/null +++ b/tests/fourbitadder.cir @@ -0,0 +1,78 @@ +4 bit adder + +* Models: +.MODEL dmod D +.MODEL qmod NPN(BF=75 RB=100 CJE=1PF CJC=3PF) + + +.SUBCKT NAND 1 2 3 4 +* noeuds: entrees(2) sortie vcc +q1 9 5 1 qmod +d1clamp 0 1 dmod +q2 9 5 2 qmod +d2clamp 0 2 dmod +rb 4 5 4k +r1 4 6 1.6k +q3 6 9 8 qmod +r2 8 0 1k +rc 4 7 130 +q4 7 6 10 qmod +dvbedrop 10 3 dmod +q5 3 8 0 qmod +.ends NAND + +.SUBCKT ONEBIT 1 2 3 4 5 6 +* noeuds entrees(2) ,carryin, sortie, carryout, vcc +x1 1 2 7 6 NAND +x2 1 7 8 6 NAND +x3 2 7 9 6 NAND +x4 8 9 10 6 NAND +x5 3 10 11 6 NAND +x6 3 11 12 6 NAND +x7 10 11 13 6 NAND +x8 12 13 4 6 NAND +x9 11 7 5 6 NAND +.ends ONEBIT + +.SUBCKT TWOBIT 1 2 3 4 5 6 7 8 9 +* noeuds +x1 1 2 7 5 10 9 ONEBIT +x2 3 4 10 6 8 9 ONEBIT +.ends TWOBIT + +.SUBCKT FOURBIT 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + +x1 1 2 3 4 9 10 13 16 15 TWOBIT +x2 5 6 7 8 11 12 16 14 15 TWOBIT +.ends FOURBIT + + + +* Inputs/Supplies: + +vcc 99 0 DC 5V +VIN1A 1 0 DC 0 pulse(0 3 0 10ns 10ns 10ns 50ns) +VIN1B 2 0 DC 0 pulse(0 3 0 10ns 10ns 20ns 100ns) +VIN2A 3 0 DC 0 pulse(0 3 0 10ns 10ns 40ns 200ns) +VIN2B 4 0 DC 0 pulse(0 3 0 10ns 10ns 80ns 400ns) +VIN3A 5 0 DC 0 pulse(0 3 0 10ns 10ns 160ns 800ns) +VIN3B 6 0 DC 0 pulse(0 3 0 10ns 10ns 320ns 1600ns) +VIN4A 7 0 DC 0 pulse(0 3 0 10ns 10ns 640ns 3200ns) +VIN4B 8 0 DC 0 pulse(0 3 0 10ns 10ns 1280ns 6400ns) + +* Circuit description: +x1 1 2 3 4 5 6 7 8 9 10 11 12 0 13 99 FOURBIT +rbit0 9 0 1k +rbit1 10 0 1k +rbit2 11 0 1k +rbit3 12 0 1k +rcout 13 0 1k + +* Analysys: +.tran 1ns 6ns +.print tran v(1) + + +.end + + diff --git a/tests/fourbitadder.out b/tests/fourbitadder.out new file mode 100644 index 000000000..99661b4c4 --- /dev/null +++ b/tests/fourbitadder.out @@ -0,0 +1,77 @@ + +Circuit: 4 bit adder + +Circuit: 4 bit adder + + + 4 bit adder +-------------------------------------------------------------------------------- +Index time v(1) +-------------------------------------------------------------------------------- +0 0.000000e+00 0.000000e+00 +1 1.200000e-12 3.600000e-04 +2 1.542463e-12 4.627390e-04 +3 2.227390e-12 6.682170e-04 +4 3.597243e-12 1.079173e-03 +5 6.336950e-12 1.901085e-03 +6 1.181636e-11 3.544909e-03 +7 2.277519e-11 6.832557e-03 +8 4.469284e-11 1.340785e-02 +9 8.852815e-11 2.655844e-02 +10 1.761988e-10 5.285963e-02 +11 2.824896e-10 8.474689e-02 +12 4.024896e-10 1.207469e-01 +13 5.224896e-10 1.567469e-01 +14 6.424896e-10 1.927469e-01 +15 7.624896e-10 2.287469e-01 +16 8.824896e-10 2.647469e-01 +17 1.002490e-09 3.007469e-01 +18 1.122490e-09 3.367469e-01 +19 1.242490e-09 3.727469e-01 +20 1.362490e-09 4.087469e-01 +21 1.482490e-09 4.447469e-01 +22 1.602490e-09 4.807469e-01 +23 1.722490e-09 5.167469e-01 +24 1.842490e-09 5.527469e-01 +25 1.962490e-09 5.887469e-01 +26 2.082490e-09 6.247469e-01 +27 2.202490e-09 6.607469e-01 +28 2.322490e-09 6.967469e-01 +29 2.442490e-09 7.327469e-01 +30 2.562490e-09 7.687469e-01 +31 2.682490e-09 8.047469e-01 +32 2.802490e-09 8.407469e-01 +33 2.922490e-09 8.767469e-01 +34 3.042490e-09 9.127469e-01 +35 3.162490e-09 9.487469e-01 +36 3.282490e-09 9.847469e-01 +37 3.402490e-09 1.020747e+00 +38 3.522490e-09 1.056747e+00 +39 3.642490e-09 1.092747e+00 +40 3.762490e-09 1.128747e+00 +41 3.882490e-09 1.164747e+00 +42 4.002490e-09 1.200747e+00 +43 4.122490e-09 1.236747e+00 +44 4.242490e-09 1.272747e+00 +45 4.362490e-09 1.308747e+00 +46 4.482490e-09 1.344747e+00 +47 4.602490e-09 1.380747e+00 +48 4.722490e-09 1.416747e+00 +49 4.842490e-09 1.452747e+00 +50 4.962490e-09 1.488747e+00 +51 5.082490e-09 1.524747e+00 +52 5.202490e-09 1.560747e+00 +53 5.322490e-09 1.596747e+00 +54 5.442490e-09 1.632747e+00 + +Index time v(1) +-------------------------------------------------------------------------------- +55 5.562490e-09 1.668747e+00 +56 5.682490e-09 1.704747e+00 +57 5.802490e-09 1.740747e+00 +58 5.922490e-09 1.776747e+00 +59 6.000000e-09 1.800000e+00 + + + + diff --git a/tests/fourbitadder.sh b/tests/fourbitadder.sh new file mode 100644 index 000000000..9bb086f30 --- /dev/null +++ b/tests/fourbitadder.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +. $srcdir/config.sh +spicetest fourbitadder diff --git a/tests/resistance/respart.cir b/tests/resistance/respart.cir new file mode 100644 index 000000000..9355a8148 --- /dev/null +++ b/tests/resistance/respart.cir @@ -0,0 +1,9 @@ +* Resistive partition with different ratios for AC/DC (Print V(2)) + +vin 1 0 DC 1V AC 1V +r1 1 2 5K +r2 2 0 5K ac=15k + +.OP +.AC DEC 10 1 10K +.END diff --git a/tests/resistance/test1.cir b/tests/resistance/test1.cir new file mode 100644 index 000000000..0ae7dc5b6 --- /dev/null +++ b/tests/resistance/test1.cir @@ -0,0 +1,13 @@ +A Simple AC Run + +.OPTIONS LIST NODE POST TRANS +.OP +.AC DEC 10 1k 1Meg +.PRINT AC V(2) + +V1 1 0 DC 0 AC 1 SIN 0 1 1K 0 0 DISTOF1 0 DISTOF2 0 +R1 1 2 10k +R2 2 0 10k +C1 2 0 1n + +.END diff --git a/tests/resistor.cir b/tests/resistor.cir new file mode 100644 index 000000000..53d885443 --- /dev/null +++ b/tests/resistor.cir @@ -0,0 +1,9 @@ +A simple resistor with a voltage source + +R1 1 0 10k +V1 1 0 1 + +.TRAN 1ns 6ns +.PRINT TRAN I(V1) + +.END diff --git a/tests/resistor.out b/tests/resistor.out new file mode 100644 index 000000000..979d85e20 --- /dev/null +++ b/tests/resistor.out @@ -0,0 +1,75 @@ + +Circuit: A simple resistor with a voltage source + +Circuit: A simple resistor with a voltage source + + + A simple resistor with a voltage source +-------------------------------------------------------------------------------- +Index time v1#branch +-------------------------------------------------------------------------------- +0 0.000000e+00 -1.000000e-04 +1 1.200000e-12 -1.000000e-04 +2 2.400000e-12 -1.000000e-04 +3 4.800000e-12 -1.000000e-04 +4 9.600000e-12 -1.000000e-04 +5 1.920000e-11 -1.000000e-04 +6 3.840000e-11 -1.000000e-04 +7 7.680000e-11 -1.000000e-04 +8 1.536000e-10 -1.000000e-04 +9 2.736000e-10 -1.000000e-04 +10 3.936000e-10 -1.000000e-04 +11 5.136000e-10 -1.000000e-04 +12 6.336000e-10 -1.000000e-04 +13 7.536000e-10 -1.000000e-04 +14 8.736000e-10 -1.000000e-04 +15 9.936000e-10 -1.000000e-04 +16 1.113600e-09 -1.000000e-04 +17 1.233600e-09 -1.000000e-04 +18 1.353600e-09 -1.000000e-04 +19 1.473600e-09 -1.000000e-04 +20 1.593600e-09 -1.000000e-04 +21 1.713600e-09 -1.000000e-04 +22 1.833600e-09 -1.000000e-04 +23 1.953600e-09 -1.000000e-04 +24 2.073600e-09 -1.000000e-04 +25 2.193600e-09 -1.000000e-04 +26 2.313600e-09 -1.000000e-04 +27 2.433600e-09 -1.000000e-04 +28 2.553600e-09 -1.000000e-04 +29 2.673600e-09 -1.000000e-04 +30 2.793600e-09 -1.000000e-04 +31 2.913600e-09 -1.000000e-04 +32 3.033600e-09 -1.000000e-04 +33 3.153600e-09 -1.000000e-04 +34 3.273600e-09 -1.000000e-04 +35 3.393600e-09 -1.000000e-04 +36 3.513600e-09 -1.000000e-04 +37 3.633600e-09 -1.000000e-04 +38 3.753600e-09 -1.000000e-04 +39 3.873600e-09 -1.000000e-04 +40 3.993600e-09 -1.000000e-04 +41 4.113600e-09 -1.000000e-04 +42 4.233600e-09 -1.000000e-04 +43 4.353600e-09 -1.000000e-04 +44 4.473600e-09 -1.000000e-04 +45 4.593600e-09 -1.000000e-04 +46 4.713600e-09 -1.000000e-04 +47 4.833600e-09 -1.000000e-04 +48 4.953600e-09 -1.000000e-04 +49 5.073600e-09 -1.000000e-04 +50 5.193600e-09 -1.000000e-04 +51 5.313600e-09 -1.000000e-04 +52 5.433600e-09 -1.000000e-04 +53 5.553600e-09 -1.000000e-04 +54 5.673600e-09 -1.000000e-04 + +Index time v1#branch +-------------------------------------------------------------------------------- +55 5.793600e-09 -1.000000e-04 +56 5.913600e-09 -1.000000e-04 +57 6.000000e-09 -1.000000e-04 + + + + diff --git a/tests/resistor.sh b/tests/resistor.sh new file mode 100644 index 000000000..769e37207 --- /dev/null +++ b/tests/resistor.sh @@ -0,0 +1,4 @@ +#! /bin/sh + +. $srcdir/config.sh +spicetest resistor