From b9ebfe2ce6813ad940ff53dd0a7313454fea80ac Mon Sep 17 00:00:00 2001 From: Francesco Lannutti Date: Mon, 6 Jul 2015 00:10:17 +0200 Subject: [PATCH] Added the possibility to specify the instance names to be considered from the Reliability Analysis --- src/include/ngspice/gendefs.h | 8 +- src/spicelib/devices/bsim4/b4reliability.c | 373 +++++++++++---------- src/spicelib/devices/bsim4/bsim4def.h | 1 + src/spicelib/parser/inppas3.c | 39 ++- 4 files changed, 237 insertions(+), 184 deletions(-) diff --git a/src/include/ngspice/gendefs.h b/src/include/ngspice/gendefs.h index 0546d22f0..498613ef2 100644 --- a/src/include/ngspice/gendefs.h +++ b/src/include/ngspice/gendefs.h @@ -9,7 +9,12 @@ Author: 1985 Thomas L. Quarles #include "ngspice/typedefs.h" #include "ngspice/ifsim.h" - +#ifdef RELAN +typedef struct sGENrelmodelDeviceElem { + char *device_name ; /* Name of the device considered by Relmodel */ + struct sGENrelmodelDeviceElem *next ; /* Pointer to the next device name */ +} GENrelmodelDeviceElem ; +#endif /* definitions used to describe generic devices */ @@ -43,6 +48,7 @@ struct GENmodel { /* model structure for a resistor */ #ifdef RELAN GENmodel *GENrelmodelModel ; /* Relmodel Companion Model */ + GENrelmodelDeviceElem *GENrelmodelDeviceList ; /* List of devices to be considered by Relmodel */ #endif }; diff --git a/src/spicelib/devices/bsim4/b4reliability.c b/src/spicelib/devices/bsim4/b4reliability.c index afe700a1f..a18996868 100644 --- a/src/spicelib/devices/bsim4/b4reliability.c +++ b/src/spicelib/devices/bsim4/b4reliability.c @@ -7,196 +7,223 @@ Author: 2015 Francesco Lannutti - July 2015 #include "bsim4def.h" #include "ngspice/sperror.h" +static int +BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mode) +{ + BSIM4model *model ; + double delta, vds, vgs, von ; + int NowIsON, ret ; + + model = here->BSIM4modPtr ; + + // Determine if the transistor is ON or OFF + vds = ckt->CKTstate0 [here->BSIM4vds] ; + vgs = ckt->CKTstate0 [here->BSIM4vgs] ; + von = model->BSIM4type * here->BSIM4von ; + if (vds >= 0) + { +// printf ("VDS >= 0\tBSIM4type: %d\tBSIM4instance: %s\tVgs: %-.9g\tVon: %-.9g\t", model->BSIM4type, here->BSIM4name, vgs, von) ; + if (vgs > von) + { + if (here->BSIM4rgateMod == 3) + { + double vges, vgms ; + vges = ckt->CKTstate0 [here->BSIM4vges] ; + vgms = ckt->CKTstate0 [here->BSIM4vgms] ; + if ((vges > von) && (vgms > von)) + { +// printf ("Acceso!\n") ; + NowIsON = 1 ; + } else { +// printf ("Spento!\n") ; + NowIsON = 0 ; + } + } else if ((here->BSIM4rgateMod == 1) || (here->BSIM4rgateMod == 2)) { + double vges ; + vges = ckt->CKTstate0 [here->BSIM4vges] ; + if (vges > von) + { +// printf ("Acceso!\n") ; + NowIsON = 1 ; + } else { +// printf ("Spento!\n") ; + NowIsON = 0 ; + } + } else { +// printf ("Acceso!\n") ; + NowIsON = 1 ; + } + } else { +// printf ("Spento!\n") ; + NowIsON = 0 ; + } + } else { + double vgd ; + vgd = vgs - vds ; +// printf ("VDS < 0\tBSIM4type: %d\tBSIM4instance: %s\tVgd: %-.9g\tVon: %-.9g\t", model->BSIM4type, here->BSIM4name, vgd, von) ; + if (vgd > von) + { + if (here->BSIM4rgateMod == 3) + { + double vges, vged, vgms, vgmd ; + vges = ckt->CKTstate0 [here->BSIM4vges] ; + vged = vges - vds ; + vgms = ckt->CKTstate0 [here->BSIM4vgms] ; + vgmd = vgms - vds ; + if ((vged > von) && (vgmd > von)) + { +// printf ("Acceso!\n") ; + NowIsON = 1 ; + } else { +// printf ("Spento!\n") ; + NowIsON = 0 ; + } + } else if ((here->BSIM4rgateMod == 1) || (here->BSIM4rgateMod == 2)) { + double vges, vged ; + vges = ckt->CKTstate0 [here->BSIM4vges] ; + vged = vges - vds ; + if (vged > von) + { +// printf ("Acceso!\n") ; + NowIsON = 1 ; + } else { +// printf ("Spento!\n") ; + NowIsON = 0 ; + } + } else { +// printf ("Acceso!\n") ; + NowIsON = 1 ; + } + } else { +// printf ("Spento!\n") ; + NowIsON = 0 ; + } + } + + // If it's the first time, initialize 'here->relStruct->IsON' + if (here->relStruct->IsON == -1) + { + here->relStruct->IsON = NowIsON ; + } + + if (mode == 0) + { + if (NowIsON) + { + if (here->relStruct->IsON == 1) + { + // Until now, the device was ON - Do NOTHING + delta = -1 ; + } else if (here->relStruct->IsON == 0) { + // Until now, the device was OFF - Calculate recovery + delta = ckt->CKTtime - here->relStruct->time ; + + // Calculate Aging - Giogio Liatis' Model + ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 0) ; + if (ret == 1) + { + return (E_INTERN) ; + } + + // Update time and flag - Stress begins + here->relStruct->time = ckt->CKTtime ; + here->relStruct->IsON = 1 ; + } else { + fprintf (stderr, "Reliability Analysis Error\n") ; + } + } else { + if (here->relStruct->IsON == 1) + { + // Until now, the device was ON - Calculate stress + delta = ckt->CKTtime - here->relStruct->time ; + + // Calculate Aging - Giorgio Liatis' Model + ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1) ; + if (ret == 1) + { + return (E_INTERN) ; + } + + // Update time and flag - Recovery begins + here->relStruct->time = ckt->CKTtime ; + here->relStruct->IsON = 0 ; + } else if (here->relStruct->IsON == 0) { + // Until now, the device was OFF - Do NOTHING + delta = -1 ; + } else { + fprintf (stderr, "Reliability Analysis Error\n") ; + } + } + } else if (mode == 1) { + // In this mode, it doesn't matter if NOW the device is in stress or in recovery, since it's the last timestep + if (here->relStruct->IsON == 1) + { + // Calculate stress + delta = ckt->CKTtime - here->relStruct->time ; + ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1) ; + if (ret == 1) + { + return (E_INTERN) ; + } + + // Update time and flag - Maybe Optional + here->relStruct->time = ckt->CKTtime ; + here->relStruct->IsON = 1 ; + } else if (here->relStruct->IsON == 0) { + // Calculate recovery + delta = ckt->CKTtime - here->relStruct->time ; + ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 0) ; + if (ret == 1) + { + return (E_INTERN) ; + } + + // Update time and flag - Maybe Optional + here->relStruct->time = ckt->CKTtime ; + here->relStruct->IsON = 0 ; + } else { + fprintf (stderr, "Reliability Analysis Error\n") ; + } + printf ("\tTime: %-.9gs\t\t", ckt->CKTtime) ; + printf ("DeltaVth: %-.9gmV\t\t", here->relStruct->deltaVth * 1000) ; + printf ("Device Name: %s\t\t", here->BSIM4name) ; + printf ("Device Type: %s\n\n", model->BSIM4modName) ; + } else { + fprintf (stderr, "Reliability Analysis Error\n") ; + } + + return 0 ; +} + int BSIM4reliability (GENmodel *inModel, CKTcircuit *ckt, unsigned int mode) { BSIM4model *model = (BSIM4model *)inModel ; BSIM4instance *here ; - double delta, vds, vgs, von ; - int NowIsON, ret ; + GENrelmodelDeviceElem *elem ; /* loop through all the BSIM4 device models */ for ( ; model != NULL ; model = model->BSIM4nextModel) { - /* loop through all the instances of the model */ - for (here = model->BSIM4instances ; here != NULL ; here=here->BSIM4nextInstance) + if (model->BSIM4type == PMOS) { - if (model->BSIM4type == PMOS) + if (model->BSIM4relmodelDeviceList != NULL) { - // Determine if the transistor is ON or OFF - vds = ckt->CKTstate0 [here->BSIM4vds] ; - vgs = ckt->CKTstate0 [here->BSIM4vgs] ; - von = model->BSIM4type * here->BSIM4von ; - if (vds >= 0) + for (elem = model->BSIM4relmodelDeviceList ; elem != NULL ; elem = elem->next) { -// printf ("VDS >= 0\tBSIM4type: %d\tBSIM4instance: %s\tVgs: %-.9g\tVon: %-.9g\t", model->BSIM4type, here->BSIM4name, vgs, von) ; - if (vgs > von) + here = (BSIM4instance *)(CKTfndDev (ckt, elem->device_name)) ; + if (!here) { - if (here->BSIM4rgateMod == 3) - { - double vges, vgms ; - vges = ckt->CKTstate0 [here->BSIM4vges] ; - vgms = ckt->CKTstate0 [here->BSIM4vgms] ; - if ((vges > von) && (vgms > von)) - { -// printf ("Acceso!\n") ; - NowIsON = 1 ; - } else { -// printf ("Spento!\n") ; - NowIsON = 0 ; - } - } else if ((here->BSIM4rgateMod == 1) || (here->BSIM4rgateMod == 2)) { - double vges ; - vges = ckt->CKTstate0 [here->BSIM4vges] ; - if (vges > von) - { -// printf ("Acceso!\n") ; - NowIsON = 1 ; - } else { -// printf ("Spento!\n") ; - NowIsON = 0 ; - } - } else { -// printf ("Acceso!\n") ; - NowIsON = 1 ; - } + SPfrontEnd->IFerrorf (ERR_WARNING, "Error: Cannot find the %s instance of the %s model", elem->device_name, model->BSIM4modName) ; } else { -// printf ("Spento!\n") ; - NowIsON = 0 ; - } - } else { - double vgd ; - vgd = vgs - vds ; -// printf ("VDS < 0\tBSIM4type: %d\tBSIM4instance: %s\tVgd: %-.9g\tVon: %-.9g\t", model->BSIM4type, here->BSIM4name, vgd, von) ; - if (vgd > von) - { - if (here->BSIM4rgateMod == 3) - { - double vges, vged, vgms, vgmd ; - vges = ckt->CKTstate0 [here->BSIM4vges] ; - vged = vges - vds ; - vgms = ckt->CKTstate0 [here->BSIM4vgms] ; - vgmd = vgms - vds ; - if ((vged > von) && (vgmd > von)) - { -// printf ("Acceso!\n") ; - NowIsON = 1 ; - } else { -// printf ("Spento!\n") ; - NowIsON = 0 ; - } - } else if ((here->BSIM4rgateMod == 1) || (here->BSIM4rgateMod == 2)) { - double vges, vged ; - vges = ckt->CKTstate0 [here->BSIM4vges] ; - vged = vges - vds ; - if (vged > von) - { -// printf ("Acceso!\n") ; - NowIsON = 1 ; - } else { -// printf ("Spento!\n") ; - NowIsON = 0 ; - } - } else { -// printf ("Acceso!\n") ; - NowIsON = 1 ; - } - } else { -// printf ("Spento!\n") ; - NowIsON = 0 ; + BSIM4reliability_internal (here, ckt, mode) ; } } - - // If it's the first time, initialize 'here->relStruct->IsON' - if (here->relStruct->IsON == -1) + } else { + /* loop through all the instances of the model */ + for (here = model->BSIM4instances ; here != NULL ; here=here->BSIM4nextInstance) { - here->relStruct->IsON = NowIsON ; - } - - if (mode == 0) - { - if (NowIsON) - { - if (here->relStruct->IsON == 1) - { - // Until now, the device was ON - Do NOTHING - delta = -1 ; - } else if (here->relStruct->IsON == 0) { - // Until now, the device was OFF - Calculate recovery - delta = ckt->CKTtime - here->relStruct->time ; - - // Calculate Aging - Giogio Liatis' Model - ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 0) ; - if (ret == 1) - { - return (E_INTERN) ; - } - - // Update time and flag - Stress begins - here->relStruct->time = ckt->CKTtime ; - here->relStruct->IsON = 1 ; - } else { - fprintf (stderr, "Reliability Analysis Error\n") ; - } - } else { - if (here->relStruct->IsON == 1) - { - // Until now, the device was ON - Calculate stress - delta = ckt->CKTtime - here->relStruct->time ; - - // Calculate Aging - Giorgio Liatis' Model - ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1) ; - if (ret == 1) - { - return (E_INTERN) ; - } - - // Update time and flag - Recovery begins - here->relStruct->time = ckt->CKTtime ; - here->relStruct->IsON = 0 ; - } else if (here->relStruct->IsON == 0) { - // Until now, the device was OFF - Do NOTHING - delta = -1 ; - } else { - fprintf (stderr, "Reliability Analysis Error\n") ; - } - } - } else if (mode == 1) { - // In this mode, it doesn't matter if NOW the device is in stress or in recovery, since it's the last timestep - if (here->relStruct->IsON == 1) - { - // Calculate stress - delta = ckt->CKTtime - here->relStruct->time ; - ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1) ; - if (ret == 1) - { - return (E_INTERN) ; - } - - // Update time and flag - Maybe Optional - here->relStruct->time = ckt->CKTtime ; - here->relStruct->IsON = 1 ; - } else if (here->relStruct->IsON == 0) { - // Calculate recovery - delta = ckt->CKTtime - here->relStruct->time ; - ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 0) ; - if (ret == 1) - { - return (E_INTERN) ; - } - - // Update time and flag - Maybe Optional - here->relStruct->time = ckt->CKTtime ; - here->relStruct->IsON = 0 ; - } else { - fprintf (stderr, "Reliability Analysis Error\n") ; - } - printf ("\tTime: %-.9gs\t\t", ckt->CKTtime) ; - printf ("DeltaVth: %-.9gmV\t\t", here->relStruct->deltaVth * 1000) ; - printf ("Device Name: %s\t\t", here->BSIM4name) ; - printf ("Device Type: %s\n\n", model->BSIM4modName) ; - } else { - fprintf (stderr, "Reliability Analysis Error\n") ; + BSIM4reliability_internal (here, ckt, mode) ; } } } diff --git a/src/spicelib/devices/bsim4/bsim4def.h b/src/spicelib/devices/bsim4/bsim4def.h index f18846a4e..414998a5f 100644 --- a/src/spicelib/devices/bsim4/bsim4def.h +++ b/src/spicelib/devices/bsim4/bsim4def.h @@ -834,6 +834,7 @@ typedef struct sBSIM4model #ifdef RELAN GENmodel *BSIM4relmodelModel ; + GENrelmodelDeviceElem *BSIM4relmodelDeviceList ; #endif /* --- end of generic struct GENmodel --- */ diff --git a/src/spicelib/parser/inppas3.c b/src/spicelib/parser/inppas3.c index 8f0fa8920..599a49117 100644 --- a/src/spicelib/parser/inppas3.c +++ b/src/spicelib/parser/inppas3.c @@ -18,17 +18,19 @@ extern IFsimulator *ft_sim; static void dot_appendmodel (CKTcircuit *ckt, INPtables *tab, card *current) { - /* .appendmodel from_model to_model */ + /* .appendmodel from_model to_model */ - int type; /* the type the model says it is */ - char *line ; /* the part of the current line left to parse */ - char *relmodel_name ; /* the relmodel name */ - char *appendmodel_name ; /* the appendmodel name */ - char *save ; /* saj - used to save the posn of the start of - the parameters if the model is a mosfet */ - char *model ; /* the name of the model */ - INPmodel *thismodel ; /* pointer to model description for user's model */ - GENmodel *mdfast ; /* pointer to the actual model */ + int error ; /* error code temporary */ + int type ; /* the type the model says it is */ + char *line ; /* the part of the current line left to parse */ + char *relmodel_name ; /* the relmodel name */ + char *appendmodel_name ; /* the appendmodel name */ + char *device_name ; /* the device name in the list of devices */ + char *save ; /* saj - used to save the posn of the start of + the parameters if the model is a mosfet */ + char *model ; /* the name of the model */ + INPmodel *thismodel ; /* pointer to model description for user's model */ + GENmodel *mdfast ; /* pointer to the actual model */ char* err_msg ; #ifdef TRACE @@ -122,6 +124,23 @@ dot_appendmodel (CKTcircuit *ckt, INPtables *tab, card *current) INPgetModBin (ckt, relmodel_name, &thismodel, tab, line) ; } thismodel->INPmodfast->GENrelmodelModel = mdfast ; /* Attach 'relmodel' model to 'appendmodel' model */ + + // Parse the rest of the line, which is a list of devices + thismodel->INPmodfast->GENrelmodelDeviceList = NULL ; + while (*line) + { + INPgetTok (&line, &device_name, 1) ; + error = INPretrieve (&device_name, tab) ; + if (error) + { + printf ("Warning: Cannot find the %s instance of the %s model - Skipping this instance\n\n", device_name, appendmodel_name) ; + } else { + GENrelmodelDeviceElem *GENrelmodelDevice = TMALLOC (GENrelmodelDeviceElem, 1) ; + GENrelmodelDevice->device_name = device_name ; + GENrelmodelDevice->next = thismodel->INPmodfast->GENrelmodelDeviceList ; + thismodel->INPmodfast->GENrelmodelDeviceList = GENrelmodelDevice ; + } + } } else { LITERR ("Error: The model 'relmodel' hasn't been defined\n\n") ; }