Implemented the resistor "pi" model, which evenly splits the

capacitance of a resistor device between the two terminals.  If
the resistor device model contains the capacitance, then the
resistor type should not be included in types that generate
parasitics.  If not, then the "pi" model is used.  The "tee" model
is still available using "ext2spice resistor tee on".  What this
update does is to default to the "pi" model instead of ignoring
the capacitance of the resistor type (e.g., "rm1"), and because
the capacitance of that node is removed after distributing it
between the two terminals, it will no longer produce a "floating"
node in the netlist output.
This commit is contained in:
R. Timothy Edwards 2026-06-24 10:34:23 -04:00
parent 338b3899bf
commit b266ec6272
3 changed files with 86 additions and 26 deletions

View File

@ -1028,24 +1028,21 @@ spcdevHierVisit(
if (sdM != 1.0)
fprintf(esSpiceF, " M=%g", sdM);
}
else
{
spcdevResPi(hc->hc_hierName, gate->dterm_node->efnode_name->efnn_hier,
source->dterm_node->efnode_name->efnn_hier,
drain->dterm_node->efnode_name->efnn_hier,
"subckt");
}
break;
case DEV_RES:
if (esDoResistorTee)
{
/* There are three ways of handling capacitance */
/* on resistor networks. One is to ignore it */
/* (the default; generates "floating" nodes in */
/* the SPICE output) which is okay for LVS. */
/* Another way is the Pi network, in which the */
/* capacitance is split evenly between the */
/* terminals. Again, the resistor node is left */
/* floating. The third is the Tee network, in */
/* which the resistance is split in two parts, */
/* connecting to a capacitor to ground in the */
/* middle. This is the best solution but plays */
/* havoc with LVS. So, the choice is a command */
/* line option. */
/* There are two ways of handling resistor */
/* capacitance to substrate: The Pi model and */
/* the Tee model (see ext2spice.c). */
esOutputHierResistor(hc, dev, scale, gate, source, has_model,
l, w, 2);
@ -1061,6 +1058,11 @@ spcdevHierVisit(
{
esOutputHierResistor(hc, dev, scale, source, drain, has_model,
l, w, 1);
spcdevResPi(hc->hc_hierName, gate->dterm_node->efnode_name->efnn_hier,
source->dterm_node->efnode_name->efnn_hier,
drain->dterm_node->efnode_name->efnn_hier,
"subckt");
}
break;

View File

@ -2995,8 +2995,15 @@ spcdevVisit(
name, esSpiceF);
}
else if (dev->dev_nterm > 2)
{
spcdevOutNode(hierName, drain->dterm_node->efnode_name->efnn_hier,
name, esSpiceF);
spcdevResPi(hierName, gate->dterm_node->efnode_name->efnn_hier,
source->dterm_node->efnode_name->efnn_hier,
drain->dterm_node->efnode_name->efnn_hier,
name);
}
}
else /* class DEV_MSUBCKT */
{
@ -3093,19 +3100,15 @@ spcdevVisit(
case DEV_RES:
if (esDoResistorTee)
{
/* There are three ways of handling capacitance */
/* on resistor networks. One is to ignore it */
/* (the default; generates "floating" nodes in */
/* the SPICE output) which is okay for LVS. */
/* Another way is the Pi network, in which the */
/* capacitance is split evenly between the */
/* terminals. Again, the resistor node is left */
/* floating. The third is the Tee network, in */
/* which the resistance is split in two parts, */
/* connecting to a capacitor to ground in the */
/* middle. This is the best solution but plays */
/* havoc with LVS. So, the choice is a command */
/* line option. */
/* There are two ways of handling capacitance */
/* on resistor networks. The default is the Pi */
/* network, which splits the capacitance of the */
/* resistor itself evenly between the two */
/* terminals. The resistor itself is not */
/* output as a node. The other is the Tee */
/* network, in which the resistor is divided in */
/* two, with the capacitance to substrate in */
/* the middle. */
esOutputResistor(dev, hierName, scale, gate, source, has_model,
l, w, 2);
@ -3121,6 +3124,11 @@ spcdevVisit(
{
esOutputResistor(dev, hierName, scale, source, drain, has_model,
l, w, 1);
spcdevResPi(hierName, gate->dterm_node->efnode_name->efnn_hier,
source->dterm_node->efnode_name->efnn_hier,
drain->dterm_node->efnode_name->efnn_hier,
name);
}
break;
@ -3851,6 +3859,55 @@ spcnAPHier(
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* spcdevResPi --
*
* Handle a "pi" resistor model: Take the capacitance of the "gate"
* (resistor device layer) to substrate, and split it between the two
* resistor terminals.
*
* Results:
* None.
*
* Side effects:
* Modifies the capacitance values on the terminal and "gate" nodes
* of the resistor device.
*
* ----------------------------------------------------------------------------
*/
void
spcdevResPi(
const HierName *prefix,
const HierName *gate_suffix,
const HierName *source_suffix,
const HierName *drain_suffix,
const char *name)
{
HashEntry *he;
EFNodeName *nngate, *nnsource, *nndrain;
EFCapValue rescap;
he = EFHNConcatLook(prefix, gate_suffix, name);
if (he == NULL) return;
nngate = (EFNodeName *) HashGetValue(he);
he = EFHNConcatLook(prefix, drain_suffix, name);
if (he == NULL) return;
nndrain = (EFNodeName *) HashGetValue(he);
he = EFHNConcatLook(prefix, source_suffix, name);
if (he == NULL) return;
nnsource = (EFNodeName *) HashGetValue(he);
rescap = nngate->efnn_node->efnode_cap / 2.0;
nnsource->efnn_node->efnode_cap += rescap;
nndrain->efnn_node->efnode_cap += rescap;
nngate->efnn_node->efnode_cap = 0;
}
/*
* ----------------------------------------------------------------------------
*

View File

@ -49,6 +49,7 @@ extern void setDevMult(int i, float f);
extern int EFHNSprintf(char *str, HierName *hierName);
extern int printSubcktDict(void);
extern int spcdevOutNode(const HierName *prefix, const HierName *suffix, const char *name, FILE *outf);
extern void spcdevResPi(const HierName *prefix, const HierName *gate, const HierName *source, const HierName *drain, const char *name);
extern int spcnAP(DevTerm *dterm, EFNode *node, int resClass, float scale, char *asterm, char *psterm, float m, FILE *outf, int w);
extern int parallelDevs(const devMerge *f1, const devMerge *f2);
extern int nodeHspiceName(char *s);