Adding degradation monitors

This commit is contained in:
Holger Vogt 2025-11-01 15:04:49 +01:00
parent e2046ae7c9
commit 21fbffbccf
4 changed files with 157 additions and 0 deletions

View File

@ -963,6 +963,10 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile)
/* Translate all SPICE 2G6 polynomial type sources */
deck->nextcard = ENHtranslate_poly(deck->nextcard);
#endif
/* quote nodes of degmons, is required for parsing the a device node,
when [x] is part of a node nname. */
int err = 0;
err = quote_degmons(deck->nextcard);
line_free(deck->actualLine, FALSE);
deck->actualLine = realdeck;

View File

@ -1100,6 +1100,9 @@ struct card *inp_readall(FILE *fp, const char *dir_name, const char* file_name,
/* collect .agemodel data */
readdegparams(working);
/* Add degradation monitors to devices in X lines */
adddegmonitors(working);
if (newcompat.lt && newcompat.a)
ltspice_compat_a(working);
if (newcompat.ps && newcompat.a)

View File

@ -14,5 +14,7 @@ extern char* inp_remove_ws(char* s);
extern char* search_plain_identifier(char* str, const char* identifier);
extern int readdegparams(struct card* deck);
extern int adddegmonitors(struct card* deck);
extern int quote_degmons(struct card* deck);
#endif

View File

@ -91,6 +91,10 @@ int readdegparams (struct card *deck) {
ftok = dftok = gettok(&cut_line);
/* parameter name */
f1 = gettok_char(&ftok, '=', FALSE, FALSE);
if (!f1) {
fprintf(stderr, "Error: bad.agemodel syntax in line\n % s", card->line);
controlled_exit(1);
}
/* parameter value */
f2 = copy(ftok + 1);
agemods[ageindex].paramnames[parno] = f1;
@ -116,4 +120,148 @@ int readdegparams (struct card *deck) {
return 0;
}
/* Look for an X line.
Check if the model in the x line is found in the model list agemodds.
Create a degradation monitor for each x line if model found.
Add the x instance name to the degmod name.
Add degmon line and its model line to the netlist.*/
int adddegmonitors(struct card* deck) {
static int degmonno;
double tfuture = 315336e4;
int nodes = 4;
if (agemods[0].paramhash == NULL)
return 1;
for (; deck; deck = deck->nextcard) {
int skip_control = 0;
char* line = deck->line;
if (*line == '*') {
continue;
}
/* there is no e source inside .control ... .endc */
if (ciprefix(".control", line)) {
skip_control++;
continue;
}
else if (ciprefix(".endc", line)) {
skip_control--;
continue;
}
else if (skip_control > 0) {
continue;
}
if (*line == 'x') {
char *modname, *fournodes, *instname;
int ii;
// fprintf(stdout, "%.80s\n", line);
/* x instance model in subcircuit */
/* get instance name */
instname = gettok_instance(&line);
fournodes = line;
/* and 4 nodes */
for (ii = 0; ii < nodes; ii++)
line = nexttok(line);
if (!line) {
/* Must be something else, not a 4-node MOS */
continue;
}
fournodes = copy_substring(fournodes, line);
modname = gettok(&line);
/*check if model is available in agemods */
for (ii = 0; ii < DEGMODMAX; ii++) {
if (agemods[ii].devmodel) {
if (cieq(modname, agemods[ii].devmodel)) {
// fprintf(stdout, "device model %s found as no. %d\n\n", modname, ii);
/* get the channel length */
char* lpos = strstr(line, "l=");
if (!lpos) {
fprintf(stderr, "Error, l not found in device %s \n\n", deck->line);
return 1;
}
char* clength = gettok(&lpos);
/* Now add a degradation monitor like
adegmon1 %v([z a vss vss]) mon degmon1
.model degmon1 degmon (tfuture=3153360000 l=0.15e-6 devmod="sg13_lv_nmos")
*/
char* aline = tprintf("adegmon%d_%s %%v([%s]) mon%d degmon%d\n",
degmonno, instname, fournodes, degmonno, degmonno);
char* mline = tprintf(".model degmon%d degmon (tfuture=%e %s devmod=\"%s\"\n",
degmonno, tfuture, clength, modname);
tfree(clength);
insert_new_line(deck, aline, 0, deck->linenum_orig, deck->linesource);
insert_new_line(deck, mline, 0, deck->linenum_orig, deck->linesource);
degmonno++;
break;
}
}
else {
// fprintf(stderr, "No model found for device %.80s \n\n", deck->line);
break;
}
}
tfree(fournodes);
tfree(modname);
tfree(instname);
}
}
return 0;
}
int quote_degmons(struct card* deck) {
for (; deck; deck = deck->nextcard) {
int skip_control = 0;
char* line = deck->line;
if (*line == '*') {
continue;
}
/* there is no e source inside .control ... .endc */
if (ciprefix(".control", line)) {
skip_control++;
continue;
}
else if (ciprefix(".endc", line)) {
skip_control--;
continue;
}
else if (skip_control > 0) {
continue;
}
if (*line == 'a' && strstr(line, "adegmon")) {
char allnodes[1024];
allnodes[0] = '\0';
int ii, nodes = 4;
char* newnodes, *instname;
instname = gettok_instance(&line);
/* skip %v */
line = nexttok(line);
char* deltoken;
char* nodetoken = deltoken = gettok_char(&line, ']', false, true);
if (!nodetoken)
break;
/* go beyond '[' */
nodetoken++;
for (ii = 0; ii < nodes; ii++) {
char* nexttoken = gettok(&nodetoken);
sprintf(allnodes, "%s \"%s\"", allnodes, nexttoken);
if (!nexttoken)
break;
tfree(nexttoken);
}
if (!line || eq(line, "")) {
/* Must be something else, not a 4-node MOS */
continue;
}
newnodes = tprintf("%s %%v [ %s %s", instname, allnodes, line);
tfree(deltoken);
tfree(instname);
tfree(deck->line);
deck->line = newnodes;
}
}
return 0;
}