⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 twoadmit.c

📁 spice中支持多层次元件模型仿真的可单独运行的插件源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/**********Copyright 1991 Regents of the University of California.  All rights reserved.Author: 1987 Kartikeya Mayaram, U. C. Berkeley CAD Group**********//* Functions to compute the ac admittances of a device. */#include <math.h>#include "numglobs.h"#include "numenum.h"#include "nummacs.h"#include "numconst.h"#include "twodev.h"#include "twomesh.h"#include "numcmplx.h"#include "spmatrix.h"#include "ifsim.h"extern IFfrontEnd *SPfrontEnd;/* Forward declarations. */BOOLEAN TWOsorSolve();void TWO_jacLoad(), TWONjacLoad(), TWOPjacLoad();void storeNewRhs();complex *contactAdmittance(), *oxideAdmittance();/* Temporary hack to remove NUMOS gate special case */#ifdef NORMAL_GATE#define GateTypeAdmittance oxideAdmittance#else#define GateTypeAdmittance contactAdmittance#endif				/* NORMAL_GATE *//* AC / PZ debugging flag */int TWOacDebug = 0;intNUMD2admittance(pDevice, omega, yd)  TWOdevice *pDevice;  double omega;  complex *yd;{  TWOnode *pNode;  TWOelem *pElem;  int index, eIndex;  double dxdy;  double *solnReal, *solnImag;  double *rhsReal, *rhsImag;  complex yAc, cOmega, *y;  BOOLEAN deltaVContact = FALSE;  BOOLEAN SORFailed;  double startTime;  /* Each time we call this counts as one AC iteration. */  pDevice->pStats->numIters[STAT_AC] += 1;  /*   * change context names of solution vectors for ac analysis dcDeltaSolution   * stores the real part and copiedSolution stores the imaginary part of the   * ac solution vector   */  pDevice->solverType = SLV_SMSIG;  rhsReal = pDevice->rhs;  rhsImag = pDevice->rhsImag;  solnReal = pDevice->dcDeltaSolution;  solnImag = pDevice->copiedSolution;  /* use a normalized radian frequency */  omega *= TNorm;  CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega);  if (AcAnalysisMethod IS SOR OR AcAnalysisMethod IS SOR_ONLY) {    /* LOAD */    startTime = SPfrontEnd->IFseconds();    /* zero the rhsImag */    for (index = 1; index <= pDevice->numEqns; index++) {      rhsImag[index] = 0.0;    }    /* store the new rhs vector */    storeNewRhs(pDevice, pDevice->pLastContact);    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* SOLVE */    startTime = SPfrontEnd->IFseconds();    SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    if (SORFailed AND AcAnalysisMethod IS SOR) {      AcAnalysisMethod = DIRECT;      printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",	  omega / (TWO_PI * TNorm) );    } else if (SORFailed) {	/* Told to only do SOR, so give up. */      printf("SOR failed at %g Hz, returning null admittance.\n",	  omega / (TWO_PI * TNorm) );      CMPLX_ASSIGN_VALUE(*yd, 0.0, 0.0);      return (AcAnalysisMethod);    }  }  if (AcAnalysisMethod IS DIRECT) {    /* LOAD */    startTime = SPfrontEnd->IFseconds();    for (index = 1; index <= pDevice->numEqns; index++) {      rhsImag[index] = 0.0;    }    /* solve the system of equations directly */    if (NOT OneCarrier) {      TWO_jacLoad(pDevice);    } else if (OneCarrier IS N_TYPE) {      TWONjacLoad(pDevice);    } else if (OneCarrier IS P_TYPE) {      TWOPjacLoad(pDevice);    }    storeNewRhs(pDevice, pDevice->pLastContact);    spSetComplex(pDevice->matrix);    for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {      pElem = pDevice->elements[eIndex];      if (pElem->elemType IS SEMICON) {	dxdy = 0.25 * pElem->dx * pElem->dy;	for (index = 0; index <= 3; index++) {	  pNode = pElem->pNodes[index];	  if (pNode->nodeType ISNOT CONTACT) {	    if (NOT OneCarrier) {	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);	    } else if (OneCarrier IS N_TYPE) {	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);	    } else if (OneCarrier IS P_TYPE) {	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);	    }	  }	}      }    }    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* FACTOR */    startTime = SPfrontEnd->IFseconds();    spFactor(pDevice->matrix);    pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* SOLVE */    startTime = SPfrontEnd->IFseconds();    spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;  }  /* MISC */  startTime = SPfrontEnd->IFseconds();  y = contactAdmittance(pDevice, pDevice->pFirstContact, deltaVContact,      solnReal, solnImag, &cOmega);  CMPLX_ASSIGN_VALUE(yAc, -y->real, -y->imag);  CMPLX_ASSIGN(*yd, yAc);  CMPLX_MULT_SELF_SCALAR(*yd, GNorm * pDevice->width * LNorm);  pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;  return (AcAnalysisMethod);}intNBJT2admittance(pDevice, omega, yIeVce, yIcVce, yIeVbe, yIcVbe)  TWOdevice *pDevice;  double omega;  complex *yIeVce, *yIcVce, *yIeVbe, *yIcVbe;{  TWOcontact *pEmitContact = pDevice->pLastContact;  TWOcontact *pColContact = pDevice->pFirstContact;  TWOcontact *pBaseContact = pDevice->pFirstContact->next;  TWOnode *pNode;  TWOelem *pElem;  int index, eIndex;  double width = pDevice->width;  double dxdy;  double *solnReal, *solnImag;  double *rhsReal, *rhsImag;  BOOLEAN SORFailed;  complex *y;  complex pIeVce, pIcVce, pIeVbe, pIcVbe;  complex cOmega;  double startTime;  /* Each time we call this counts as one AC iteration. */  pDevice->pStats->numIters[STAT_AC] += 1;  pDevice->solverType = SLV_SMSIG;  rhsReal = pDevice->rhs;  rhsImag = pDevice->rhsImag;  solnReal = pDevice->dcDeltaSolution;  solnImag = pDevice->copiedSolution;  /* use a normalized radian frequency */  omega *= TNorm;  CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega);  if (AcAnalysisMethod IS SOR OR AcAnalysisMethod IS SOR_ONLY) {    /* LOAD */    startTime = SPfrontEnd->IFseconds();    /* zero the rhs before loading in the new rhs */    for (index = 1; index <= pDevice->numEqns; index++) {      rhsImag[index] = 0.0;    }    storeNewRhs(pDevice, pColContact);    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* SOLVE */    startTime = SPfrontEnd->IFseconds();    SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    if (SORFailed AND AcAnalysisMethod IS SOR) {      AcAnalysisMethod = DIRECT;      printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",	  omega / (TWO_PI * TNorm) );    } else if (SORFailed) {	/* Told to only do SOR, so give up. */      printf("SOR failed at %g Hz, returning null admittance.\n",	  omega / (TWO_PI * TNorm) );      CMPLX_ASSIGN_VALUE(*yIeVce, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(*yIcVce, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(*yIeVbe, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(*yIcVbe, 0.0, 0.0);      return (AcAnalysisMethod);    } else {      /* MISC */      startTime = SPfrontEnd->IFseconds();      y = contactAdmittance(pDevice, pEmitContact, FALSE,	  solnReal, solnImag, &cOmega);      CMPLX_ASSIGN_VALUE(pIeVce, y->real, y->imag);      y = contactAdmittance(pDevice, pColContact, TRUE,	  solnReal, solnImag, &cOmega);      CMPLX_ASSIGN_VALUE(pIcVce, y->real, y->imag);      pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;      /* LOAD */      startTime = SPfrontEnd->IFseconds();      /* load in the base contribution to the rhs */      for (index = 1; index <= pDevice->numEqns; index++) {	rhsImag[index] = 0.0;      }      storeNewRhs(pDevice, pBaseContact);      pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;      /* SOLVE */      startTime = SPfrontEnd->IFseconds();      SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);      pDevice->pStats->solveTime[STAT_AC] +=	  SPfrontEnd->IFseconds() - startTime;      if (SORFailed AND AcAnalysisMethod IS SOR) {	AcAnalysisMethod = DIRECT;	printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",	    omega / (TWO_PI * TNorm) );      } else if (SORFailed) {	/* Told to only do SOR, so give up. */	printf("SOR failed at %g Hz, returning null admittance.\n",	    omega / (TWO_PI * TNorm) );	CMPLX_ASSIGN_VALUE(*yIeVce, 0.0, 0.0);	CMPLX_ASSIGN_VALUE(*yIcVce, 0.0, 0.0);	CMPLX_ASSIGN_VALUE(*yIeVbe, 0.0, 0.0);	CMPLX_ASSIGN_VALUE(*yIcVbe, 0.0, 0.0);	return (AcAnalysisMethod);      }    }  }  if (AcAnalysisMethod IS DIRECT) {    /* LOAD */    startTime = SPfrontEnd->IFseconds();    for (index = 1; index <= pDevice->numEqns; index++) {      rhsImag[index] = 0.0;    }    /* solve the system of equations directly */    if (NOT OneCarrier) {      TWO_jacLoad(pDevice);    } else if (OneCarrier IS N_TYPE) {      TWONjacLoad(pDevice);    } else if (OneCarrier IS P_TYPE) {      TWOPjacLoad(pDevice);    }    storeNewRhs(pDevice, pColContact);    spSetComplex(pDevice->matrix);    for (eIndex = 1; eIndex <= pDevice->numElems; eIndex++) {      pElem = pDevice->elements[eIndex];      if (pElem->elemType IS SEMICON) {	dxdy = 0.25 * pElem->dx * pElem->dy;	for (index = 0; index <= 3; index++) {	  pNode = pElem->pNodes[index];	  if (pNode->nodeType ISNOT CONTACT) {	    if (NOT OneCarrier) {	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);	    } else if (OneCarrier IS N_TYPE) {	      spADD_COMPLEX_ELEMENT(pNode->fNN, 0.0, -dxdy * omega);	    } else if (OneCarrier IS P_TYPE) {	      spADD_COMPLEX_ELEMENT(pNode->fPP, 0.0, dxdy * omega);	    }	  }	}      }    }    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* FACTOR */    startTime = SPfrontEnd->IFseconds();    spFactor(pDevice->matrix);    pDevice->pStats->factorTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* SOLVE */    startTime = SPfrontEnd->IFseconds();    spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* MISC */    startTime = SPfrontEnd->IFseconds();    y = contactAdmittance(pDevice, pEmitContact, FALSE,	solnReal, solnImag, &cOmega);    CMPLX_ASSIGN_VALUE(pIeVce, y->real, y->imag);    y = contactAdmittance(pDevice, pColContact, TRUE,	solnReal, solnImag, &cOmega);    CMPLX_ASSIGN_VALUE(pIcVce, y->real, y->imag);    pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* LOAD */    startTime = SPfrontEnd->IFseconds();    for (index = 1; index <= pDevice->numEqns; index++) {      rhsImag[index] = 0.0;    }    storeNewRhs(pDevice, pBaseContact);    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* FACTOR: already done, no need to repeat. */    /* SOLVE */    startTime = SPfrontEnd->IFseconds();    spSolve(pDevice->matrix, rhsReal, solnReal, rhsImag, solnImag);    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;  }  /* MISC */  startTime = SPfrontEnd->IFseconds();  y = contactAdmittance(pDevice, pEmitContact, FALSE,      solnReal, solnImag, &cOmega);  CMPLX_ASSIGN_VALUE(pIeVbe, y->real, y->imag);  y = contactAdmittance(pDevice, pColContact, FALSE,      solnReal, solnImag, &cOmega);  CMPLX_ASSIGN_VALUE(pIcVbe, y->real, y->imag);  CMPLX_ASSIGN(*yIeVce, pIeVce);  CMPLX_ASSIGN(*yIeVbe, pIeVbe);  CMPLX_ASSIGN(*yIcVce, pIcVce);  CMPLX_ASSIGN(*yIcVbe, pIcVbe);  CMPLX_MULT_SELF_SCALAR(*yIeVce, GNorm * width * LNorm);  CMPLX_MULT_SELF_SCALAR(*yIeVbe, GNorm * width * LNorm);  CMPLX_MULT_SELF_SCALAR(*yIcVce, GNorm * width * LNorm);  CMPLX_MULT_SELF_SCALAR(*yIcVbe, GNorm * width * LNorm);  pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;  return (AcAnalysisMethod);}intNUMOSadmittance(pDevice, omega, yAc)  TWOdevice *pDevice;  double omega;  struct mosAdmittances *yAc;{  TWOcontact *pDContact = pDevice->pFirstContact;  TWOcontact *pGContact = pDevice->pFirstContact->next;  TWOcontact *pSContact = pDevice->pFirstContact->next->next;  TWOcontact *pBContact = pDevice->pLastContact;  TWOnode *pNode;  TWOelem *pElem;  int index, eIndex;  double width = pDevice->width;  double dxdy;  double *solnReal, *solnImag;  double *rhsReal, *rhsImag;  BOOLEAN SORFailed;  complex *y, cOmega;  double startTime;  /* Each time we call this counts as one AC iteration. */  pDevice->pStats->numIters[STAT_AC] += 1;  pDevice->solverType = SLV_SMSIG;  rhsReal = pDevice->rhs;  rhsImag = pDevice->rhsImag;  solnReal = pDevice->dcDeltaSolution;  solnImag = pDevice->copiedSolution;  /* use a normalized radian frequency */  omega *= TNorm;  CMPLX_ASSIGN_VALUE(cOmega, 0.0, omega);  if (AcAnalysisMethod IS SOR OR AcAnalysisMethod IS SOR_ONLY) {    /* LOAD */    startTime = SPfrontEnd->IFseconds();    /* zero the rhs before loading in the new rhs */    for (index = 1; index <= pDevice->numEqns; index++) {      rhsImag[index] = 0.0;    }    storeNewRhs(pDevice, pDContact);    pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    /* SOLVE */    startTime = SPfrontEnd->IFseconds();    SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);    pDevice->pStats->solveTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;    if (SORFailed AND AcAnalysisMethod IS SOR) {      AcAnalysisMethod = DIRECT;      printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",	  omega / (TWO_PI * TNorm) );    } else if (SORFailed) {	/* Told to only do SOR, so give up. */      printf("SOR failed at %g Hz, returning null admittance.\n",	  omega / (TWO_PI * TNorm) );      CMPLX_ASSIGN_VALUE(yAc->yIdVdb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIdVsb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIdVgb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIsVdb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIsVsb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIsVgb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIgVdb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIgVsb, 0.0, 0.0);      CMPLX_ASSIGN_VALUE(yAc->yIgVgb, 0.0, 0.0);      return (AcAnalysisMethod);    } else {      /* MISC */      startTime = SPfrontEnd->IFseconds();      y = contactAdmittance(pDevice, pDContact, TRUE,	  solnReal, solnImag, &cOmega);      CMPLX_ASSIGN_VALUE(yAc->yIdVdb, y->real, y->imag);      y = contactAdmittance(pDevice, pSContact, FALSE,	  solnReal, solnImag, &cOmega);      CMPLX_ASSIGN_VALUE(yAc->yIsVdb, y->real, y->imag);      y = GateTypeAdmittance(pDevice, pGContact, FALSE,	  solnReal, solnImag, &cOmega);      CMPLX_ASSIGN_VALUE(yAc->yIgVdb, y->real, y->imag);      pDevice->pStats->miscTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;      /* LOAD */      startTime = SPfrontEnd->IFseconds();      /* load in the source contribution to the rhs */      for (index = 1; index <= pDevice->numEqns; index++) {	rhsImag[index] = 0.0;      }      storeNewRhs(pDevice, pSContact);      pDevice->pStats->loadTime[STAT_AC] += SPfrontEnd->IFseconds() - startTime;      /* SOLVE */      startTime = SPfrontEnd->IFseconds();      SORFailed = TWOsorSolve(pDevice, solnReal, solnImag, omega);      pDevice->pStats->solveTime[STAT_AC] +=	  SPfrontEnd->IFseconds() - startTime;      if (SORFailed AND AcAnalysisMethod IS SOR) {	AcAnalysisMethod = DIRECT;	printf("SOR failed at %g Hz, switching to direct-method ac analysis.\n",	    omega / (TWO_PI * TNorm) );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -