Alpha Version of the new Reliability Analysis, based upon Giorgio Liatis' Model
This commit is contained in:
parent
0c5196e773
commit
a5b8aa535f
|
|
@ -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 *);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,8 @@ libckt_la_SOURCES = \
|
|||
tranaskq.c \
|
||||
traninit.c \
|
||||
transetp.c \
|
||||
cluster.c
|
||||
cluster.c \
|
||||
cktreliability.c
|
||||
|
||||
|
||||
if PSS_WANTED
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) ;
|
||||
}
|
||||
|
|
@ -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)){
|
||||
|
|
|
|||
|
|
@ -72,7 +72,10 @@ SPICEdev CAPinfo = {
|
|||
/* DEVacct */ NULL,
|
||||
#endif
|
||||
/* DEVinstSize */ &CAPiSize,
|
||||
/* DEVmodSize */ &CAPmSize
|
||||
/* DEVmodSize */ &CAPmSize,
|
||||
|
||||
NULL
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@ libmos1_la_SOURCES = \
|
|||
mos1sset.c \
|
||||
mos1supd.c \
|
||||
mos1temp.c \
|
||||
mos1trun.c
|
||||
mos1trun.c \
|
||||
mos1reliability.c
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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) ;
|
||||
|
|
|
|||
|
|
@ -73,7 +73,10 @@ SPICEdev MOS1info = {
|
|||
/* DEVacct */ NULL,
|
||||
#endif
|
||||
/* DEVinstSize */ &MOS1iSize,
|
||||
/* DEVmodSize */ &MOS1mSize
|
||||
/* DEVmodSize */ &MOS1mSize,
|
||||
|
||||
MOS1reliability
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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) ;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,10 @@ SPICEdev VSRCinfo = {
|
|||
/* DEVacct */ NULL,
|
||||
#endif
|
||||
/* DEVinstSize */ &VSRCiSize,
|
||||
/* DEVmodSize */ &VSRCmSize
|
||||
/* DEVmodSize */ &VSRCmSize,
|
||||
|
||||
NULL
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue