|
|
@ -7721,7 +7721,23 @@ static struct card *find_model(struct card *startcard, |
|
|
return returncard; |
|
|
return returncard; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* do the .model replacement required by ako (a kind of) |
|
|
|
|
|
|
|
|
/* Process any .distribution cards for PSPICE's Monte-Carlo feature. |
|
|
|
|
|
* A .distribution card defines a probability distribution by a PWL |
|
|
|
|
|
* density function. This could be rewritten as a function that |
|
|
|
|
|
* returns a random value following that distribution. |
|
|
|
|
|
* For now, just comment it away. |
|
|
|
|
|
*/ |
|
|
|
|
|
static void do_distribution(struct card *oldcard) { |
|
|
|
|
|
while (oldcard) { |
|
|
|
|
|
char *line = oldcard->line; |
|
|
|
|
|
|
|
|
|
|
|
if (line && ciprefix(".distribution", line)) |
|
|
|
|
|
*line = '*'; |
|
|
|
|
|
oldcard = oldcard->nextcard; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Do the .model replacement required by ako (a kind of) |
|
|
* PSPICE does not support nested .subckt definitions, so |
|
|
* PSPICE does not support nested .subckt definitions, so |
|
|
* a simple structure is needed: search for ako:modelname, |
|
|
* a simple structure is needed: search for ako:modelname, |
|
|
* then for modelname in the subcircuit or in the top level. |
|
|
* then for modelname in the subcircuit or in the top level. |
|
|
@ -7740,31 +7756,37 @@ static struct card *ako_model(struct card *startcard) |
|
|
for (card = startcard; card; card = card->nextcard) { |
|
|
for (card = startcard; card; card = card->nextcard) { |
|
|
char *akostr, *searchname; |
|
|
char *akostr, *searchname; |
|
|
char *cut_line = card->line; |
|
|
char *cut_line = card->line; |
|
|
|
|
|
|
|
|
if (ciprefix(".subckt", cut_line)) |
|
|
if (ciprefix(".subckt", cut_line)) |
|
|
subcktcard = card; |
|
|
subcktcard = card; |
|
|
else if (ciprefix(".ends", cut_line)) |
|
|
else if (ciprefix(".ends", cut_line)) |
|
|
subcktcard = NULL; |
|
|
subcktcard = NULL; |
|
|
if (ciprefix(".model", cut_line) && |
|
|
|
|
|
((akostr = strstr(cut_line, "ako:")) != NULL) && |
|
|
|
|
|
|
|
|
if (ciprefix(".model", cut_line)) { |
|
|
|
|
|
if ((akostr = strstr(cut_line, "ako:")) != NULL && |
|
|
isspace_c(akostr[-1])) { |
|
|
isspace_c(akostr[-1])) { |
|
|
akostr += 4; |
|
|
|
|
|
searchname = gettok(&akostr); |
|
|
|
|
|
cut_line = nexttok(cut_line); |
|
|
|
|
|
newmname = gettok(&cut_line); |
|
|
|
|
|
newmtype = gettok_noparens(&akostr); |
|
|
|
|
|
/* find the model and do the replacement */ |
|
|
|
|
|
if (subcktcard) |
|
|
|
|
|
returncard = find_model(subcktcard, card, searchname, |
|
|
|
|
|
newmname, newmtype, akostr); |
|
|
|
|
|
if (returncard || !subcktcard) |
|
|
|
|
|
returncard = find_model(startcard, card, searchname, newmname, |
|
|
|
|
|
newmtype, akostr); |
|
|
|
|
|
tfree(searchname); |
|
|
|
|
|
tfree(newmname); |
|
|
|
|
|
tfree(newmtype); |
|
|
|
|
|
/* replacement not possible, bail out */ |
|
|
|
|
|
if (returncard) |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
akostr += 4; |
|
|
|
|
|
searchname = gettok(&akostr); |
|
|
|
|
|
cut_line = nexttok(cut_line); |
|
|
|
|
|
newmname = gettok(&cut_line); |
|
|
|
|
|
newmtype = gettok_noparens(&akostr); |
|
|
|
|
|
|
|
|
|
|
|
/* Find the model and do the replacement. */ |
|
|
|
|
|
|
|
|
|
|
|
if (subcktcard) |
|
|
|
|
|
returncard = find_model(subcktcard, card, searchname, |
|
|
|
|
|
newmname, newmtype, akostr); |
|
|
|
|
|
if (returncard || !subcktcard) |
|
|
|
|
|
returncard = find_model(startcard, card, searchname, |
|
|
|
|
|
newmname, newmtype, akostr); |
|
|
|
|
|
tfree(searchname); |
|
|
|
|
|
tfree(newmname); |
|
|
|
|
|
tfree(newmtype); |
|
|
|
|
|
|
|
|
|
|
|
/* Replacement not possible, bail out. */ |
|
|
|
|
|
|
|
|
|
|
|
if (returncard) |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
return returncard; |
|
|
return returncard; |
|
|
@ -7925,6 +7947,9 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
controlled_exit(1); |
|
|
controlled_exit(1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Process .distribution cards. */ |
|
|
|
|
|
do_distribution(oldcard); |
|
|
|
|
|
|
|
|
/* replace TABLE function in E source */ |
|
|
/* replace TABLE function in E source */ |
|
|
replace_table(oldcard); |
|
|
replace_table(oldcard); |
|
|
|
|
|
|
|
|
@ -7988,12 +8013,14 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
.model xxx NPN/PNP level=2 --> level = 6 |
|
|
.model xxx NPN/PNP level=2 --> level = 6 |
|
|
.model xxx LPNP level=n --> level = 1 subs=-1 */ |
|
|
.model xxx LPNP level=n --> level = 1 subs=-1 */ |
|
|
|
|
|
|
|
|
/* check for double '{', replace the inner '{', '}' by '(', ')'*/ |
|
|
|
|
|
|
|
|
/* Check for double '{', replace the inner '{', '}' by '(', ')'. |
|
|
|
|
|
Also, remove any Monte - Carlo variation parameters from .model cards.*/ |
|
|
for (card = newcard; card; card = card->nextcard) { |
|
|
for (card = newcard; card; card = card->nextcard) { |
|
|
char* cut_line = card->line; |
|
|
char* cut_line = card->line; |
|
|
if (ciprefix(".model", cut_line)) { |
|
|
if (ciprefix(".model", cut_line)) { |
|
|
char *cut_del = cut_line = inp_remove_ws(copy(cut_line)); |
|
|
|
|
|
char* modname, *modtype; |
|
|
|
|
|
|
|
|
char* modname, *modtype, *curr_line; |
|
|
|
|
|
int i; |
|
|
|
|
|
char *cut_del = curr_line = cut_line = inp_remove_ws(copy(cut_line)); |
|
|
cut_line = nexttok(cut_line); /* skip .model */ |
|
|
cut_line = nexttok(cut_line); /* skip .model */ |
|
|
modname = gettok(&cut_line); /* save model name */ |
|
|
modname = gettok(&cut_line); /* save model name */ |
|
|
modtype = gettok_noparens(&cut_line); /* save model type */ |
|
|
modtype = gettok_noparens(&cut_line); /* save model type */ |
|
|
@ -8010,7 +8037,7 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
/* EKV 2.6 in the adms branch */ |
|
|
/* EKV 2.6 in the adms branch */ |
|
|
char* newline = tprintf(".model %s %s level=44 %s", modname, modtype, lv); |
|
|
char* newline = tprintf(".model %s %s level=44 %s", modname, modtype, lv); |
|
|
tfree(card->line); |
|
|
tfree(card->line); |
|
|
card->line = newline; |
|
|
|
|
|
|
|
|
card->line = curr_line = newline; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
case 6: |
|
|
case 6: |
|
|
@ -8019,7 +8046,7 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
/* BSIM3 version 3.2.4 */ |
|
|
/* BSIM3 version 3.2.4 */ |
|
|
char* newline = tprintf(".model %s %s level=8 version=3.2.4 %s", modname, modtype, lv); |
|
|
char* newline = tprintf(".model %s %s level=8 version=3.2.4 %s", modname, modtype, lv); |
|
|
tfree(card->line); |
|
|
tfree(card->line); |
|
|
card->line = newline; |
|
|
|
|
|
|
|
|
card->line = curr_line = newline; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
case 8: |
|
|
case 8: |
|
|
@ -8027,7 +8054,7 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
/* BSIM4 version 4.5.0 */ |
|
|
/* BSIM4 version 4.5.0 */ |
|
|
char* newline = tprintf(".model %s %s level=14 version=4.5.0 %s", modname, modtype, lv); |
|
|
char* newline = tprintf(".model %s %s level=14 version=4.5.0 %s", modname, modtype, lv); |
|
|
tfree(card->line); |
|
|
tfree(card->line); |
|
|
card->line = newline; |
|
|
|
|
|
|
|
|
card->line = curr_line = newline; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
default: |
|
|
default: |
|
|
@ -8049,7 +8076,7 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
/* MEXTRAM 504.12.1 in the adms branch */ |
|
|
/* MEXTRAM 504.12.1 in the adms branch */ |
|
|
char* newline = tprintf(".model %s %s level=6 %s", modname, modtype, lv); |
|
|
char* newline = tprintf(".model %s %s level=6 %s", modname, modtype, lv); |
|
|
tfree(card->line); |
|
|
tfree(card->line); |
|
|
card->line = newline; |
|
|
|
|
|
|
|
|
card->line = curr_line = newline; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
|
default: |
|
|
default: |
|
|
@ -8062,14 +8089,13 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
/* lateral PNP enabled */ |
|
|
/* lateral PNP enabled */ |
|
|
char* newline = tprintf(".model %s PNP level=1 subs=-1 %s", modname, cut_line); |
|
|
char* newline = tprintf(".model %s PNP level=1 subs=-1 %s", modname, cut_line); |
|
|
tfree(card->line); |
|
|
tfree(card->line); |
|
|
card->line = newline; |
|
|
|
|
|
|
|
|
card->line = curr_line = newline; |
|
|
} |
|
|
} |
|
|
tfree(modname); |
|
|
tfree(modname); |
|
|
tfree(modtype); |
|
|
tfree(modtype); |
|
|
tfree(cut_del); |
|
|
|
|
|
|
|
|
|
|
|
/* check for double '{', replace the inner '{', '}' by '(', ')'*/ |
|
|
/* check for double '{', replace the inner '{', '}' by '(', ')'*/ |
|
|
cut_line = strchr(card->line, '{'); |
|
|
|
|
|
|
|
|
cut_line = strchr(curr_line, '{'); |
|
|
if (cut_line) |
|
|
if (cut_line) |
|
|
{ |
|
|
{ |
|
|
int level = 1; |
|
|
int level = 1; |
|
|
@ -8088,8 +8114,39 @@ static struct card *pspice_compat(struct card *oldcard) |
|
|
cut_line++; |
|
|
cut_line++; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* Remove any Monte-Carlo variation parameters. They qualify |
|
|
|
|
|
* a previous parameter, so there must be at least 3 tokens. |
|
|
|
|
|
* There are two keywords "dev" (different values for each device), |
|
|
|
|
|
* and "lot" (all devices of this model share a value). |
|
|
|
|
|
* The keyword may be optionally followed by '/' and |
|
|
|
|
|
* a probability distribution name, then there must be '=' and |
|
|
|
|
|
* a value, then an optional '%' indicating relative rather than |
|
|
|
|
|
* absolute variation. Allow muliple lot and dev on a single .model line. |
|
|
|
|
|
*/ |
|
|
|
|
|
bool remdevlot = FALSE; |
|
|
|
|
|
cut_line = curr_line; |
|
|
|
|
|
for (i = 0; i < 3; i++) |
|
|
|
|
|
cut_line = nexttok(cut_line); |
|
|
|
|
|
while (cut_line) { |
|
|
|
|
|
if (!strncmp(cut_line, "dev=", 4) || |
|
|
|
|
|
!strncmp(cut_line, "lot=", 4)) { |
|
|
|
|
|
while (*cut_line && !isspace_c(*cut_line)) { |
|
|
|
|
|
*cut_line++ = ' '; |
|
|
|
|
|
} |
|
|
|
|
|
remdevlot = TRUE; |
|
|
|
|
|
cut_line = skip_ws(cut_line); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
cut_line = nexttok(cut_line); |
|
|
|
|
|
} |
|
|
|
|
|
if (remdevlot) { |
|
|
|
|
|
tfree(card->line); |
|
|
|
|
|
card->line = curr_line; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
tfree(cut_del); |
|
|
|
|
|
} // if .model |
|
|
|
|
|
} // for loop through all cards |
|
|
|
|
|
|
|
|
/* x ... params: p1=val1, p2=val2 replace comma separator by space. |
|
|
/* x ... params: p1=val1, p2=val2 replace comma separator by space. |
|
|
Do nothing if you are inside of { }. */ |
|
|
Do nothing if you are inside of { }. */ |
|
|
|