swapDrainSource moved into a function to encapsulate swap-related tasks; area parameters swapped according to the D/S attributes; SPICE attribute comment printf moved to the end of export function as it allows to add more device types

This commit is contained in:
Jan Belohoubek 2020-08-09 17:34:24 +02:00
parent 1ee9309d15
commit 6c508c25b9
2 changed files with 88 additions and 29 deletions

View File

@ -439,6 +439,8 @@ subcktHierVisit(use, hierName, is_top)
return subcktVisit(use, hierName, is_top); return subcktVisit(use, hierName, is_top);
} }
extern void swapDrainSource();
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -516,8 +518,7 @@ spcdevHierVisit(hc, dev, scale)
(dev->dev_terms[2].dterm_attrs && (dev->dev_terms[2].dterm_attrs &&
!strcmp(dev->dev_terms[2].dterm_attrs, "S"))) !strcmp(dev->dev_terms[2].dterm_attrs, "S")))
{ {
drain = &dev->dev_terms[1]; swapDrainSource(dev, &source, &drain);
source = &dev->dev_terms[2];
} }
else else
drain = &dev->dev_terms[2]; drain = &dev->dev_terms[2];
@ -666,12 +667,12 @@ spcdevHierVisit(hc, dev, scale)
break; break;
case DEV_MSUBCKT: case DEV_MSUBCKT:
/* msubcircuit is "Xnnn source gate [drain [sub]]]" */ /* msubcircuit is "Xnnn drain gate [source [sub]]]" */
/* to more conveniently handle situations where MOSFETs */ /* to more conveniently handle situations where MOSFETs */
/* are modeled by subcircuits with the same pin ordering. */ /* are modeled by subcircuits with the same pin ordering. */
spcdevOutNode(hc->hc_hierName, spcdevOutNode(hc->hc_hierName,
source->dterm_node->efnode_name->efnn_hier, drain->dterm_node->efnode_name->efnn_hier,
"subckt", esSpiceF); "subckt", esSpiceF);
/* Drop through to below (no break statement) */ /* Drop through to below (no break statement) */
@ -693,15 +694,21 @@ spcdevHierVisit(hc, dev, scale)
/* except that the "gate" node is treated as an identifier */ /* except that the "gate" node is treated as an identifier */
/* only and is not output. */ /* only and is not output. */
if ((dev->dev_nterm > 1) && (dev->dev_class != DEV_MSUBCKT)) if (dev->dev_class != DEV_MSUBCKT)
spcdevOutNode(hc->hc_hierName, {
source->dterm_node->efnode_name->efnn_hier, if (dev->dev_nterm > 1)
"subckt", esSpiceF); spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier,
if (dev->dev_nterm > 2) "subckt", esSpiceF);
spcdevOutNode(hc->hc_hierName, if (dev->dev_nterm > 2)
drain->dterm_node->efnode_name->efnn_hier, spcdevOutNode(hc->hc_hierName, drain->dterm_node->efnode_name->efnn_hier,
"subckt", esSpiceF); "subckt", esSpiceF);
}
else /* class DEV_MSUBCKT */
{
if (dev->dev_nterm > 2)
spcdevOutNode(hc->hc_hierName, source->dterm_node->efnode_name->efnn_hier,
"subckt", esSpiceF);
}
/* The following only applies to DEV_SUBCKT*, which may define as */ /* The following only applies to DEV_SUBCKT*, which may define as */
/* many terminal types as it wants. */ /* many terminal types as it wants. */
@ -979,20 +986,27 @@ spcdevHierVisit(hc, dev, scale)
else else
fprintf(esSpiceF, "asub=0 psub=0"); fprintf(esSpiceF, "asub=0 psub=0");
} }
}
/* Now output attributes, if present */
if (!esNoAttrs) /* Output attributes, if present - it looks more convenient here, as other device types may be added */
{ switch (dev->dev_class)
if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs) {
fprintf(esSpiceF,"\n**devattr"); case DEV_FET:
if (gate->dterm_attrs) case DEV_MOSFET:
fprintf(esSpiceF, " g=%s", gate->dterm_attrs); case DEV_ASYMMETRIC:
if (source->dterm_attrs) case DEV_MSUBCKT:
fprintf(esSpiceF, " s=%s", source->dterm_attrs); if (!esNoAttrs)
if (drain->dterm_attrs) {
fprintf(esSpiceF, " d=%s", drain->dterm_attrs); if (gate->dterm_attrs || source->dterm_attrs || drain->dterm_attrs)
} fprintf(esSpiceF,"\n**devattr");
break; if (gate->dterm_attrs)
fprintf(esSpiceF, " g=%s", gate->dterm_attrs);
if (source->dterm_attrs)
fprintf(esSpiceF, " s=%s", source->dterm_attrs);
if (drain->dterm_attrs)
fprintf(esSpiceF, " d=%s", drain->dterm_attrs);
}
break;
} }
fprintf(esSpiceF, "\n"); fprintf(esSpiceF, "\n");
return 0; return 0;

View File

@ -2184,6 +2184,51 @@ getCurDevMult()
return (esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0; return (esFMult && (esFMIndex > 0)) ? esFMult[esFMIndex-1] : (float)1.0;
} }
/*
* swapDrainSource
*
* Swap drain and source ordering and the related stuff
* including the drain/source area parameters
*
* This is typycally called if any terminal is marked with attribute "D" or "S"
* (label "D$" or "S$" at poly-diffusion interface),
* then swap order of source and drain compared to the default ordering.
*
*/
void
swapDrainSource(dev, source, drain)
Dev *dev;
DevTerm **source, **drain;
{
DevParam *plist;
/* swap drain/source ordering */
*drain = &dev->dev_terms[1];
*source = &dev->dev_terms[2];
/* swap drain/source-related parameters */
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL)
{
TxPrintf(" * param: %s; type: %c%c\n", plist->parm_name, plist->parm_type[0], plist->parm_type[1]);
/* swap drain/source parameters only */
if (!(strcmp(plist->parm_name, "as")) || !(strcmp(plist->parm_name, "ps")))
{
plist->parm_type[1] = '0' + 2;
}
else if (!(strcmp(plist->parm_name, "ad")) || !(strcmp(plist->parm_name, "pd")))
{
plist->parm_type[1] = '0' + 1;
}
/* move pointer */
plist = plist->parm_next;
}
}
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -2263,8 +2308,8 @@ spcdevVisit(dev, hc, scale, trans)
(dev->dev_terms[2].dterm_attrs && (dev->dev_terms[2].dterm_attrs &&
!strcmp(dev->dev_terms[2].dterm_attrs, "S"))) !strcmp(dev->dev_terms[2].dterm_attrs, "S")))
{ {
drain = &dev->dev_terms[1]; /* If D/S should be swapped, also parameters must be swapped */
source = &dev->dev_terms[2]; swapDrainSource(dev, &source, &drain);
} }
else else
drain = &dev->dev_terms[2]; drain = &dev->dev_terms[2];