Alpha Version of the new Reliability Analysis, based upon Giorgio Liatis' Model

This commit is contained in:
Francesco Lannutti 2015-06-28 21:49:23 +02:00
parent 0c5196e773
commit a5b8aa535f
14 changed files with 256 additions and 5 deletions

View File

@ -423,6 +423,8 @@ extern int DCpss(CKTcircuit *, int);
/* SP */
#endif
extern int CKTreliability (CKTcircuit *, unsigned int) ;
extern int NaskQuest(CKTcircuit *, JOB *, int, IFvalue *);
extern int NsetParm(CKTcircuit *, JOB *, int, IFvalue *);
extern int NIacIter(CKTcircuit *);

View File

@ -114,6 +114,8 @@ typedef struct SPICEdev {
int *DEVinstSize; /* size of an instance */
int *DEVmodSize; /* size of a model */
int (*DEVreliability)(GENmodel *, CKTcircuit *, unsigned int) ;
} SPICEdev; /* instance of structure for each possible type of device */

View File

@ -95,7 +95,8 @@ libckt_la_SOURCES = \
tranaskq.c \
traninit.c \
transetp.c \
cluster.c
cluster.c \
cktreliability.c
if PSS_WANTED

View File

@ -223,6 +223,9 @@ CKTdoJob(CKTcircuit *ckt, int reset, TSKtask *task)
error = analInfo[i]->an_func (ckt, reset);
/* txl, cpl addition */
if (error == 1111) break;
CKTreliability (ckt, 1) ;
}
if (error)
error2 = error;

View File

@ -0,0 +1,24 @@
/**********
Author: 2015 Francesco Lannutti
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/devdefs.h"
#include "ngspice/sperror.h"
int
CKTreliability (CKTcircuit *ckt, unsigned int mode)
{
int error, i ;
for (i = 0 ; i < DEVmaxnum ; i++)
{
if (DEVices [i] && DEVices [i]->DEVreliability && ckt->CKThead [i])
{
error = DEVices [i]->DEVreliability (ckt->CKThead [i], ckt, mode) ;
}
}
return (OK) ;
}

View File

@ -828,6 +828,17 @@ resume:
#endif
} else {
printf ("CKTtime: %-.9g\n", ckt->CKTtime) ;
CKTreliability (ckt, 0) ;
/** Nel RHSold, ogni device deve accedere ai propri valori per vedere se esso stesso è acceso o spento.
Nel caso del BSIM4, vale la regola Vgs > Vth, dove Vgs = ckt->CKTrhsOld [here->BSIM4...] - ckt->CKTrhsOld [here->BSIM4...] e Vth = here->BSIM4vth .
In caso il transistor sia acceso, si alza un flag, privato del device, che indica che è acceso. Se è spento, lo stesso flag sarà basso.
Il tempo corrente CKTtime deve essere memorizzato insieme, in modo tale da poter poi calcolare il delta di tempo necessario al modello.
QUI, deve essere controllato che all'istante precedente il device sia acceso (o spento). Se si manifesta un cambio, allora la fase di stress (o di recovery)
è finita e bisogna calcolare il delta_vth attraverso il modello.
*/
if (firsttime) {
#ifdef WANT_SENSE2
if(ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & TRANSEN)){

View File

@ -72,7 +72,10 @@ SPICEdev CAPinfo = {
/* DEVacct */ NULL,
#endif
/* DEVinstSize */ &CAPiSize,
/* DEVmodSize */ &CAPmSize
/* DEVmodSize */ &CAPmSize,
NULL
};

View File

@ -31,7 +31,8 @@ libmos1_la_SOURCES = \
mos1sset.c \
mos1supd.c \
mos1temp.c \
mos1trun.c
mos1trun.c \
mos1reliability.c

View File

@ -13,6 +13,13 @@ Modified: 2000 AlansFixes
#include "ngspice/complex.h"
#include "ngspice/noisedef.h"
typedef struct sMOS1relStruct {
double time ;
double deltaVth ;
double t_star ;
int IsON ;
} MOS1relStruct ;
/* declarations for level 1 MOSFETs */
/* information needed for each instance */
@ -264,6 +271,8 @@ typedef struct sMOS1instance {
#define MOS1dphibs_dw MOS1sens + 68
#define MOS1dphibd_dw MOS1sens + 69
MOS1relStruct *MOS1reliability ;
} MOS1instance ;
#define MOS1vbd MOS1states+ 0 /* bulk-drain voltage */

View File

@ -28,3 +28,5 @@ extern int MOS1convTest(GENmodel*,CKTcircuit*);
extern int MOS1disto(int,GENmodel*,CKTcircuit*);
extern int MOS1noise(int,int,GENmodel*,CKTcircuit*,Ndata*,double*);
extern int MOS1dSetup(GENmodel*,CKTcircuit*);
extern int MOS1reliability (GENmodel *, CKTcircuit *, unsigned int) ;

View File

@ -73,7 +73,10 @@ SPICEdev MOS1info = {
/* DEVacct */ NULL,
#endif
/* DEVinstSize */ &MOS1iSize,
/* DEVmodSize */ &MOS1mSize
/* DEVmodSize */ &MOS1mSize,
MOS1reliability
};

View File

@ -0,0 +1,182 @@
/**********
Author: 2015 Francesco Lannutti
**********/
#include "ngspice/ngspice.h"
#include "ngspice/devdefs.h"
#include "mos1defs.h"
#include "ngspice/sperror.h"
static int
calculate_aging
(
MOS1instance *here,
double t_aging,
unsigned int stress_or_recovery
)
{
double K_b, T, h_cut, q, Nts, T_hk, Nt, eps_0, eps_hk, eps_SiO2, m_star, W, tau_0, beta, tau_e, beta1 ;
double A ;
K_b = 8.6e-5 ;
T = 300 ;
h_cut = 1.05e-34 ;
q = 1.6e-19 ;
Nts = 2e13 ;
T_hk = 2 ;
Nt = pow ((sqrt (Nts)), 3) * 1e-21 ;
eps_0 = 8.85e-21 ;
eps_hk = 25 ;
eps_SiO2 = 3.9 ;
m_star = 0.1 * 9.11e-31 ;
W = 1.5 * 1.6e-19 ;
tau_0 = 1e-11 ;
beta = 0.373 ;
tau_e = 0.85e-9 ;
beta1 = 0.112 ;
A = (q / (4 * eps_0 * eps_hk)) * pow ((h_cut / (2 * sqrt (2 * m_star * W)) * 1e9), 2) ;
if (stress_or_recovery)
{
if (h_cut / (2 * sqrt (2 * m_star * W)) * log (1 + pow (((t_aging + here->MOS1reliability->t_star) / tau_0), beta)) * 1e9 <= 2)
{
here->MOS1reliability->deltaVth = Nt * A * pow (log (1 + pow (((t_aging + here->MOS1reliability->t_star) / tau_0), beta)), 2) ;
} else {
here->MOS1reliability->deltaVth = pow ((q / (4 * eps_0 * eps_hk)) * Nt * T_hk, 2) ;
}
} else {
here->MOS1reliability->deltaVth = here->MOS1reliability->deltaVth * log (1 + (1.718 / (1 + pow ((t_aging / tau_e), beta1)))) ;
}
if (!stress_or_recovery)
{
here->MOS1reliability->t_star = pow ((exp (sqrt (here->MOS1reliability->deltaVth / (Nt * A))) - 1), (1 / beta)) * tau_0 ;
}
return 0 ;
}
int
MOS1reliability (GENmodel *inModel, CKTcircuit *ckt, unsigned int mode)
{
MOS1model *model = (MOS1model *)inModel ;
MOS1instance *here ;
double delta, vds, vgs, von ;
int NowIsON ;
/* 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)
{
vds = ckt->CKTstate0 [here->MOS1vds] ;
vgs = ckt->CKTstate0 [here->MOS1vgs] ;
von = model->MOS1type * here->MOS1von ;
if (vds >= 0)
{
printf ("VDS >= 0\tMOS1type: %d\tMOS1instance: %s\tVgs: %-.9g\tVon: %-.9g\t", model->MOS1type, here->MOS1name, vgs, von) ;
if (vgs > von)
{
printf ("Acceso!\n") ;
NowIsON = 1 ;
} else {
printf ("Spento!\n") ;
NowIsON = 0 ;
}
} else {
double vgd ;
vgd = vgs - vds ;
printf ("VDS < 0\tMOS1type: %d\tMOS1instance: %s\tVgd: %-.9g\tVon: %-.9g\t", model->MOS1type, here->MOS1name, vgd, von) ;
if (vgd > von)
{
printf ("Acceso!\n") ;
NowIsON = 1 ;
} else {
printf ("Spento!\n") ;
NowIsON = 0 ;
}
}
// If it's the first time, initialize 'here->MOS1reliability->IsON'
if (here->MOS1reliability->IsON == -1)
{
here->MOS1reliability->IsON = NowIsON ;
}
if (mode == 0)
{
if (NowIsON)
{
if (here->MOS1reliability->IsON == 1)
{
// Until now, the device was ON - Do NOTHING
delta = -1 ;
} else if (here->MOS1reliability->IsON == 0) {
// Until now, the device was OFF - Calculate recovery
delta = ckt->CKTtime - here->MOS1reliability->time ;
// Calculate Aging - Giogio Liatis' Model
calculate_aging (here, delta, 0) ;
// Update time and flag - Stress begins
here->MOS1reliability->time = ckt->CKTtime ;
here->MOS1reliability->IsON = 1 ;
} else {
fprintf (stderr, "Reliability Analysis Error\n") ;
}
} else {
if (here->MOS1reliability->IsON == 1)
{
// Until now, the device was ON - Calculate stress
delta = ckt->CKTtime - here->MOS1reliability->time ;
// Calculate Aging - Giorgio Liatis' Model
calculate_aging (here, delta, 1) ;
// Update time and flag - Recovery begins
here->MOS1reliability->time = ckt->CKTtime ;
here->MOS1reliability->IsON = 0 ;
} else if (here->MOS1reliability->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->MOS1reliability->IsON == 1)
{
// Calculate stress
delta = ckt->CKTtime - here->MOS1reliability->time ;
calculate_aging (here, delta, 1) ;
// Update time and flag - Maybe Optional
here->MOS1reliability->time = ckt->CKTtime ;
here->MOS1reliability->IsON = 1 ;
} else if (here->MOS1reliability->IsON == 0) {
// Calculate recovery
delta = ckt->CKTtime - here->MOS1reliability->time ;
calculate_aging (here, delta, 0) ;
// Update time and flag - Maybe Optional
here->MOS1reliability->time = ckt->CKTtime ;
here->MOS1reliability->IsON = 0 ;
} else {
fprintf (stderr, "Reliability Analysis Error\n") ;
}
} else {
fprintf (stderr, "Reliability Analysis Error\n") ;
}
printf ("Time: %-.9gs\t", here->MOS1reliability->time) ;
printf ("DeltaVth: %-.9gmV\t", here->MOS1reliability->deltaVth * 1000) ;
printf ("IsON: %u\t", here->MOS1reliability->IsON) ;
printf ("t_star: %-.9gs\n\n\n", here->MOS1reliability->t_star) ;
}
}
return (OK) ;
}

View File

@ -206,6 +206,11 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
TSTALLOC(MOS1SPbPtr,MOS1sNodePrime,MOS1bNode);
TSTALLOC(MOS1SPdpPtr,MOS1sNodePrime,MOS1dNodePrime);
here->MOS1reliability = TMALLOC (MOS1relStruct, 1) ;
here->MOS1reliability->time = 0 ;
here->MOS1reliability->deltaVth = 0 ;
here->MOS1reliability->t_star = 0 ;
here->MOS1reliability->IsON = -1 ;
}
}
return(OK);

View File

@ -73,7 +73,10 @@ SPICEdev VSRCinfo = {
/* DEVacct */ NULL,
#endif
/* DEVinstSize */ &VSRCiSize,
/* DEVmodSize */ &VSRCmSize
/* DEVmodSize */ &VSRCmSize,
NULL
};