Compare commits

..

10 Commits

Author SHA1 Message Date
R. Timothy Edwards f998f8ee6f Corrected an error that has been known for a while but which had
not previously been tracked down.  Behavior was that GDS additions
to correct hierarchical interactions would miss areas, especially
on large chip designs.  This was found to be caused by a nested
use of DBSrCellPlaneArea();  the inner use was changing the outer
use's search area and causing it to exit early.  Corrected by
removing the nested use of the subroutines.  Also, created a
proper client data structure to pass information to and from the
subroutine, eliminating the ugly global variables that had been
used for that purpose.
2025-12-30 12:15:15 -05:00
R. Timothy Edwards 662e21a2d1 Corrected an error that had been introduced when creating the
parameter types "l1", "l2", etc., for terminal lengths.  There
was a string comparison against an unterminated character array
which was causing intermittant errors.  This problem was masking
the incorrect handling of "l1", "l2", etc., parameters.  The
parameter types had been introduced to cover a specific type of
drain-unsalicided FET in GF180MCU, which is used as an ESD
device in the foundry I/O cells, so the impact had been
relatively limited, although typically showed up as unexpected
property errors on the ESD devices when running LVS on a chip
top level.  Both discovered errors have been fixed.
2025-12-29 10:52:08 -05:00
R. Timothy Edwards 949ec7672c Reworked the code from the previous commit in a completely different
way.  The code as previously written was undermining other code
written to avoid long run-times on ext2spice, and didn't solve at
least one issue with unnecessary resistor shorts being added to the
netlist output.  The current solution fixes one underlying problem
where a wrongly-placed parenthesis caused the "preferred net name"
routine EFHNBest() not to be run, which prevented original node
names from being preferred over their suffixed versions created by
"extract unique".  However, I also added code to EFbuild.c to
merge unique nodes when the nodes are not really unique.  The
problem is caused by "extract unique" operating only on one level
of hierarchy and being unable to see where nets may connect through
subcircuits.  That can be determined from the "merge" statements
in the .ext file, and now the EFbuild routines will merge these
"false unique" names back into the original net.
2025-12-24 16:00:08 -05:00
R. Timothy Edwards bd417aa54b Updating the version number to go along with the merge of pull
request #478 from Mitch Bailey.  Also edited the code from the
PR for programming style.
2025-12-24 11:31:43 -05:00
Mitch Bailey 73e08e0c88 Prefer original ports over duplicate ports in extracted spice netlist.
Prioritize lowest port number when merging nodes.

Signed-off-by: Mitch Bailey <d.mitch.bailey@gmail.com>
2025-12-24 11:19:16 -05:00
R. Timothy Edwards 893a36cae7 Updated the version to go along with the merge of pull requests
475, 476, and 477 (first ones for mac OS and arch Linux support
on github;  the last to modify recent code changes to work with
the last code merge for eliminating the one-off freeMagic().
2025-12-22 09:57:56 -05:00
Darryl L. Miles 3b4d66e7d7 freeMagic1() additions
These additional uses of freeMagic() also require defer-by-one using stack
storage (not global storage idiom, recently introduced).
Not sure if they were missed original or new/modified code in the past
12 months.  Some areas/line-of-code are not usually compiled, maybe that
is why they were originally missed.
2025-12-22 09:57:42 -05:00
Darryl L. Miles 5e8a3f038a CalmaWrite: fix: introduced memory leak, missed free
Appears the 'listtop' is a sentinal/entryexit value to a circular list
My recent patch does not copy original behaviour in freeing this list
entry (as well as the reset of the list).
2025-12-22 09:57:42 -05:00
Darryl L. Miles 9850c5586e GHA: main-aarch64.yml: insert apt-get update 2025-12-22 09:57:29 -05:00
Darryl L. Miles 27df5f9c5f GHA: Migrate macos-13 => macos-15-intel 2025-12-22 09:57:04 -05:00
12 changed files with 271 additions and 119 deletions

View File

@ -16,6 +16,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Get Dependencies - name: Get Dependencies
run: | run: |
sudo apt-get update
sudo apt-get install -y tcl-dev tk-dev libcairo-dev sudo apt-get install -y tcl-dev tk-dev libcairo-dev
- name: Build - name: Build
run: | run: |

View File

@ -10,8 +10,8 @@ on:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel # A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs: jobs:
simple_build_macos13: simple_build_macos15:
runs-on: macos-13 runs-on: macos-15-intel # only and last supported intel MacOS
timeout-minutes: 45 # x86_64 seems non-SSD based (slower) timeout-minutes: 45 # x86_64 seems non-SSD based (slower)
steps: steps:
- name: Checkout - name: Checkout
@ -235,10 +235,10 @@ jobs:
cp *.mak dist/BUILD-INFO/ cp *.mak dist/BUILD-INFO/
cp *.LOG dist/BUILD-INFO/ cp *.LOG dist/BUILD-INFO/
- name: Upload archive magic-macos13 - name: Upload archive magic-macos15
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: magic-macos13 name: magic-macos15
path: | path: |
${{ github.workspace }}/dist ${{ github.workspace }}/dist

View File

@ -1 +1 @@
8.3.583 8.3.587

View File

@ -2432,6 +2432,7 @@ calmaProcessBoundary(
freeMagic1(&mm1, lbref); freeMagic1(&mm1, lbref);
lbref = lbref->lb_next; lbref = lbref->lb_next;
} }
freeMagic1(&mm1, lbref);
freeMagic1_end(&mm1); freeMagic1_end(&mm1);
} }
} }

View File

@ -1867,6 +1867,7 @@ calmaProcessBoundaryZ(
freeMagic1(&mm1, lbref); freeMagic1(&mm1, lbref);
lbref = lbref->lb_next; lbref = lbref->lb_next;
} }
freeMagic1(&mm1, lbref);
freeMagic1_end(&mm1); freeMagic1_end(&mm1);
} }
} }

View File

@ -27,6 +27,7 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "utils/magic.h" #include "utils/magic.h"
#include "textio/textio.h" #include "textio/textio.h"
#include "utils/malloc.h"
#include "utils/signals.h" #include "utils/signals.h"
#include "utils/geometry.h" #include "utils/geometry.h"
#include "tiles/tile.h" #include "tiles/tile.h"
@ -37,18 +38,12 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include "commands/commands.h" #include "commands/commands.h"
#include "utils/undo.h" #include "utils/undo.h"
/* The variables below are made owns so that they can be used to /* The variables below are made global so that they can be used to
* pass information to the various search functions. * pass information to the various search functions.
*/ */
static Rect drcSubIntArea; /* Accumulates area of interactions. */
static CellDef *drcSubDef; /* Cell definition we're checking. */
static int drcSubRadius; /* Interaction radius. */
static CellUse *drcCurSub; /* Holds current use while searching for interactions */
static Rect drcSubLookArea; /* Area where we're looking for interactions */
static void (*drcSubFunc)(); /* Error function. */ static void (*drcSubFunc)(); /* Error function. */
static ClientData drcSubClientData; static ClientData drcSubClientData; /* To be passed to error function. */
/* To be passed to error function. */
/* The cookie below is dummied up to provide an error message for /* The cookie below is dummied up to provide an error message for
* errors that occur because of inexact overlaps between subcells. * errors that occur because of inexact overlaps between subcells.
@ -92,6 +87,28 @@ static DRCCookie drcOffGridCookie = {
extern int DRCErrorType; extern int DRCErrorType;
extern CellDef *DRCErrorDef; extern CellDef *DRCErrorDef;
/* Structure used to hold information about child uses found in the
* search area during DRCFindInteractions(), so these can be
* subsequently searched for sibling interactions.
*/
struct drcLinkedUse {
CellUse *dlu_use; // Use being checked
Rect dlu_area; // Area of use to check (w/halo)
struct drcLinkedUse *dlu_next; // For linked list
};
/* Structure used to pass information to and from drcSubcellFunc() */
struct drcSubcellArg {
CellDef *dsa_def; /* Cell use being checked */
int dsa_radius; /* Halo radius around area to check */
Rect *dsa_searchArea; /* Area of cell use being searched */
Rect *dsa_intArea; /* Total interaction area */
bool dsa_found; /* At least one interacting cell was found */
struct drcLinkedUse *dsa_dlu;
};
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* *
@ -113,12 +130,12 @@ extern CellDef *DRCErrorDef;
*/ */
int int
drcFindOtherCells(use, area) drcFindOtherCells(use, dlu)
CellUse *use; CellUse *use;
Rect *area; struct drcLinkedUse *dlu;
{ {
if (use != drcCurSub) if (use != dlu->dlu_use)
GeoInclude(&use->cu_bbox, area); GeoInclude(&use->cu_bbox, &dlu->dlu_area);
return 0; return 0;
} }
@ -228,68 +245,56 @@ drcSubCopyFunc(scx, cdarg)
*/ */
int int
drcSubcellFunc(subUse, flags) drcSubcellFunc(subUse, dsa)
CellUse *subUse; /* Subcell instance. */ CellUse *subUse; /* Subcell instance found in area. */
int *flags; /* Information to propagate up */ struct drcSubcellArg *dsa; /* Information needed for funtion and to pass
* back to the caller.
*/
{ {
Rect area, haloArea, intArea, subIntArea, locIntArea; Rect area, haloArea, intArea;
int i; int i;
/* A subcell has been seen, so set the "cell found" flag */ /* Record that a subcell has been seen in the search area. */
*flags |= CELLFOUND_FLAG; dsa->dsa_found = TRUE;
/* To determine interactions, find the bounding box of /* To determine interactions, find the bounding box of
* all paint and other subcells within one halo of this * all paint and other subcells within one halo of this
* subcell (and also within the original area where * subcell (and also within the original area where
* we're recomputing errors). * we're recomputing errors).
*/ */
area = subUse->cu_bbox; area = subUse->cu_bbox;
GEO_EXPAND(&area, drcSubRadius, &haloArea); GEO_EXPAND(&area, dsa->dsa_radius, &haloArea);
GeoClip(&haloArea, &drcSubLookArea); GeoClip(&haloArea, dsa->dsa_searchArea);
intArea = GeoNullRect; intArea = GeoNullRect;
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{ {
(void) DBSrPaintArea((Tile *) NULL, drcSubDef->cd_planes[i], (void) DBSrPaintArea((Tile *) NULL, dsa->dsa_def->cd_planes[i],
&haloArea, &DBAllButSpaceBits, drcIncludeArea, &haloArea, &DBAllButSpaceBits, drcIncludeArea,
(ClientData) &intArea); (ClientData) &intArea);
} }
/* DRC error tiles in a subcell are automatically pulled into the */ /* To check sibling interactions, DBSrCellPlaneArea() must not be
/* interaction area of the parent. Ultimately this is recursive as */ * called from within itself, so save the information about this
/* all cells are checked and errors propagate to the top level. */ * cell and its area in a linked list. If haloArea is already
* inside intArea, then do nothing.
*/
subIntArea = GeoNullRect; if (!GEO_SURROUND(&intArea, &haloArea))
{
#if (0) struct drcLinkedUse *newdlu;
/* NOTE: DRC errors inside a subcell should be ignored for */ newdlu = (struct drcLinkedUse *)mallocMagic(sizeof(struct drcLinkedUse));
/* the purpose of finding interactions. Errors should only */ newdlu->dlu_use = subUse;
/* be copied up into the parent when in a non-interaction */ newdlu->dlu_area = haloArea;
/* area. This is done below in DRCFindInteractions(). */ newdlu->dlu_next = dsa->dsa_dlu;
/* (Method added by Tim, 10/15/2020) */ dsa->dsa_dlu = newdlu;
}
/* Maybe S and PS errors should be pulled here? */
DBSrPaintArea((Tile *) NULL, subUse->cu_def->cd_planes[PL_DRC_ERROR],
&TiPlaneRect, &DBAllButSpaceBits, drcIncludeArea,
(ClientData) &subIntArea);
GeoTransRect(&(subUse->cu_transform), &subIntArea, &locIntArea);
GeoInclude(&locIntArea, &intArea);
#endif
if (!GEO_RECTNULL(&subIntArea)) *flags |= PROPAGATE_FLAG;
drcCurSub = subUse;
(void) DBSrCellPlaneArea(drcSubDef->cd_cellPlane, &haloArea,
drcFindOtherCells, (ClientData)(&intArea));
if (GEO_RECTNULL(&intArea)) return 0; if (GEO_RECTNULL(&intArea)) return 0;
GEO_EXPAND(&intArea, drcSubRadius, &intArea); GEO_EXPAND(&intArea, dsa->dsa_radius, &intArea);
GeoClip(&intArea, &haloArea); GeoClip(&intArea, &haloArea);
(void) GeoInclude(&intArea, &drcSubIntArea); (void) GeoInclude(&intArea, dsa->dsa_intArea);
return 0; return 0;
} }
@ -413,10 +418,11 @@ DRCFindInteractions(def, area, radius, interaction)
int i; int i;
CellUse *use; CellUse *use;
SearchContext scx; SearchContext scx;
Rect searchArea, intArea;
int flags; int flags;
struct drcSubcellArg dsa;
struct drcLinkedUse *curDLU;
drcSubDef = def;
drcSubRadius = radius;
DRCDummyUse->cu_def = def; DRCDummyUse->cu_def = def;
/* Find all the interactions in the area and compute the /* Find all the interactions in the area and compute the
@ -426,11 +432,53 @@ DRCFindInteractions(def, area, radius, interaction)
* each cell has material everywhere within its bounding box. * each cell has material everywhere within its bounding box.
*/ */
drcSubIntArea = GeoNullRect; GEO_EXPAND(area, radius, &searchArea);
GEO_EXPAND(area, radius, &drcSubLookArea); intArea = GeoNullRect;
flags = 0;
(void) DBSrCellPlaneArea(def->cd_cellPlane, &drcSubLookArea, /* Copy drcSubLookArea to a local Rect structure because it
drcSubcellFunc, (ClientData)(&flags)); * gets modified by drcSubcellFunc().
*/
dsa.dsa_def = def;
dsa.dsa_radius = radius;
dsa.dsa_searchArea = &searchArea;
dsa.dsa_intArea = &intArea;
dsa.dsa_found = FALSE;
dsa.dsa_dlu = (struct drcLinkedUse *)NULL;
(void) DBSrCellPlaneArea(def->cd_cellPlane, &searchArea,
drcSubcellFunc, (ClientData)&dsa);
/* If no subcells were in the search area, there is nothing
* more to do.
*/
if (dsa.dsa_found == FALSE) return -1;
/* If drcSubcellFunc() returned a list of uses, then check
* the area of each use for interacting sibling uses, and
* add the overlap to the potential interaction area.
*/
curDLU = dsa.dsa_dlu;
while (curDLU != NULL)
{
Rect subIntArea, subSearchArea;
struct drcLinkedUse *nextdlu = curDLU->dlu_next;
subSearchArea = curDLU->dlu_area;
curDLU->dlu_area = GeoNullRect;
(void) DBSrCellPlaneArea(def->cd_cellPlane, &subSearchArea,
drcFindOtherCells, (ClientData)curDLU);
/* Re-clip interaction area to subcell halo area */
GEO_EXPAND(&curDLU->dlu_area, radius, &curDLU->dlu_area);
GeoClip(&curDLU->dlu_area, &subSearchArea);
(void) GeoInclude(&curDLU->dlu_area, &intArea);
/* Free entry and move to next entry in linked list */
freeMagic((char *)curDLU);
curDLU = nextdlu;
}
/* If there seems to be an interaction area, make a second pass /* If there seems to be an interaction area, make a second pass
* to make sure there's more than one cell with paint in the * to make sure there's more than one cell with paint in the
@ -438,8 +486,7 @@ DRCFindInteractions(def, area, radius, interaction)
* have overlapping bounding boxes without overlapping paint. * have overlapping bounding boxes without overlapping paint.
*/ */
if (!(flags & CELLFOUND_FLAG)) return -1; if (GEO_RECTNULL(&intArea)) return 0;
if (GEO_RECTNULL(&drcSubIntArea)) return 0;
use = NULL; use = NULL;
/* If errors are being propagated up from child to parent, */ /* If errors are being propagated up from child to parent, */
@ -450,7 +497,7 @@ DRCFindInteractions(def, area, radius, interaction)
for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++) for (i = PL_TECHDEPBASE; i < DBNumPlanes; i++)
{ {
if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i], if (DBSrPaintArea((Tile *) NULL, def->cd_planes[i],
&drcSubIntArea, &DBAllButSpaceBits, drcAlwaysOne, &intArea, &DBAllButSpaceBits, drcAlwaysOne,
(ClientData) NULL) != 0) (ClientData) NULL) != 0)
{ {
use = (CellUse *) -1; use = (CellUse *) -1;
@ -459,14 +506,14 @@ DRCFindInteractions(def, area, radius, interaction)
} }
scx.scx_use = DRCDummyUse; scx.scx_use = DRCDummyUse;
scx.scx_trans = GeoIdentityTransform; scx.scx_trans = GeoIdentityTransform;
scx.scx_area = drcSubIntArea; scx.scx_area = intArea;
if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0) if (DBTreeSrCells(&scx, 0, drcSubCheckPaint, (ClientData) &use) == 0)
return 0; return 0;
} }
/* OK, no more excuses, there's really an interaction area here. */ /* OK, no more excuses, there's really an interaction area here. */
*interaction = drcSubIntArea; *interaction = intArea;
GeoClip(interaction, area); GeoClip(interaction, area);
if (GEO_RECTNULL(interaction)) return 0; if (GEO_RECTNULL(interaction)) return 0;
return 1; return 1;

View File

@ -814,7 +814,10 @@ main(
EFVisitDevs(simmergeVisit, PTR2CD(NULL)); EFVisitDevs(simmergeVisit, PTR2CD(NULL));
TxPrintf("Devices merged: %d\n", esDevsMerged); TxPrintf("Devices merged: %d\n", esDevsMerged);
esFMIndex = 0; esFMIndex = 0;
for (p = devMergeList; p != NULL; p = p->next) freeMagic((char *)p); free_magic1_t mm1 = freeMagic1_init();
for (p = devMergeList; p != NULL; p = p->next)
freeMagic1(&mm1, (char *)p);
freeMagic1_end(&mm1);
} }
EFVisitDevs(simdevVisit, PTR2CD(NULL)); EFVisitDevs(simdevVisit, PTR2CD(NULL));

View File

@ -242,9 +242,20 @@ spcHierWriteParams(
/* Write all requested parameters to the subcircuit call. */ /* Write all requested parameters to the subcircuit call. */
bool checkme = FALSE;
if ((!strcmp(EFDevTypes[dev->dev_type], "pfet_06v0_dss")) ||
(!strcmp(EFDevTypes[dev->dev_type], "nfet_06v0_dss")))
{
checkme = TRUE;
TxPrintf("Diagnostic: Parameter list for %s\n", EFDevTypes[dev->dev_type]);
}
plist = efGetDeviceParams(EFDevTypes[dev->dev_type]); plist = efGetDeviceParams(EFDevTypes[dev->dev_type]);
while (plist != NULL) while (plist != NULL)
{ {
if (checkme) TxPrintf("Plist entry %s %s\n", plist->parm_name, plist->parm_type);
switch (plist->parm_type[0]) switch (plist->parm_type[0])
{ {
case 'a': case 'a':
@ -345,6 +356,7 @@ spcHierWriteParams(
// Check for device length vs. terminal length // Check for device length vs. terminal length
if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0') if (plist->parm_type[1] == '\0' || plist->parm_type[1] == '0')
{ {
if (checkme) TxPrintf("Handling entry l or l0\n");
fprintf(esSpiceF, " %s=", plist->parm_name); fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0) if (esScale < 0)
fprintf(esSpiceF, "%g", l * scale); fprintf(esSpiceF, "%g", l * scale);
@ -359,8 +371,10 @@ spcHierWriteParams(
{ {
/* l1, l2, etc. used to indicate the length of the terminal */ /* l1, l2, etc. used to indicate the length of the terminal */
/* Find value in dev_params */ /* Find value in dev_params */
if (checkme) TxPrintf("Handling entry l1 or l2\n");
for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next) for (dparam = dev->dev_params; dparam; dparam = dparam->parm_next)
{ {
if (checkme) TxPrintf("Checking dev_params entry %s\n", dparam->parm_name);
if ((strlen(dparam->parm_name) > 2) && if ((strlen(dparam->parm_name) > 2) &&
(dparam->parm_name[0] == 'l') && (dparam->parm_name[0] == 'l') &&
(dparam->parm_name[1] == plist->parm_type[1]) && (dparam->parm_name[1] == plist->parm_type[1]) &&
@ -369,6 +383,8 @@ spcHierWriteParams(
int dval; int dval;
if (sscanf(&dparam->parm_name[3], "%d", &dval) == 1) if (sscanf(&dparam->parm_name[3], "%d", &dval) == 1)
{ {
if (checkme) TxPrintf("Handling dev_params entry %s (to be "
"culled at end)\n", dparam->parm_name);
fprintf(esSpiceF, " %s=", plist->parm_name); fprintf(esSpiceF, " %s=", plist->parm_name);
if (esScale < 0) if (esScale < 0)
fprintf(esSpiceF, "%g", dval * scale); fprintf(esSpiceF, "%g", dval * scale);
@ -378,6 +394,7 @@ spcHierWriteParams(
else else
esSIvalue(esSpiceF, (dval + plist->parm_offset) esSIvalue(esSpiceF, (dval + plist->parm_offset)
* scale * esScale * 1.0E-6); * scale * esScale * 1.0E-6);
/* Why is this here? */
dparam->parm_name[0] = '\0'; dparam->parm_name[0] = '\0';
break; break;
} }

View File

@ -1347,7 +1347,10 @@ main(
{ {
const devMerge *p; const devMerge *p;
for ( p = devMergeList ; p != NULL ; p=p->next ) freeMagic((char *)p); free_magic1_t mm1 = freeMagic1_init();
for (p = devMergeList; p != NULL; p = p->next)
freeMagic1(&mm1, (char *)p);
freeMagic1_end(&mm1);
} }
} else if ( esDistrJunct ) } else if ( esDistrJunct )
EFVisitDevs(devDistJunctVisit, (ClientData) NULL); EFVisitDevs(devDistJunctVisit, (ClientData) NULL);

View File

@ -602,6 +602,26 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
if (!strcasecmp(nodeName1, nodeName2)) equalByCase = TRUE; if (!strcasecmp(nodeName1, nodeName2)) equalByCase = TRUE;
} }
if (!equalByCase) if (!equalByCase)
{
/* If one of the nodes has been generated from the
* other by "extract unique", then this is a case where
* the "extract unique" algorithm is blind to shorts
* through subcell hierarchy and has made a name unique
* unnecessarily. In that case, merge the node instead
* of generating a short.
*/
char *uniqstr1, *uniqstr2;
bool isuniq;
uniqstr1 = strstr(nodeName1, "_uq");
uniqstr2 = strstr(nodeName2, "_uq");
if (uniqstr1) *uniqstr1 = '\0';
if (uniqstr2) *uniqstr2 = '\0';
isuniq = !strcmp(nodeName1, nodeName2);
if (uniqstr1) *uniqstr1 = '_';
if (uniqstr2) *uniqstr2 = '_';
if (!isuniq)
{ {
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE) if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE)
{ {
@ -627,12 +647,16 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
return; return;
} }
else if (!resist) else if (!resist)
TxError("Warning: Ports \"%s\" and \"%s\" are electrically shorted.\n", TxError("Warning: Ports \"%s\" and \"%s\" are electrically "
nodeName1, nodeName2); "shorted.\n", nodeName1, nodeName2);
else else
/* Do not merge the nodes when folding in extresist parasitics */ /* Do not merge the nodes when folding in extresist parasitics */
return; return;
} }
else if (resist)
/* Do not merge the nodes when folding in extresist parasitics */
return;
}
} }
/* If both names exist and are for different nodes, merge them */ /* If both names exist and are for different nodes, merge them */
@ -652,8 +676,6 @@ efBuildEquiv(def, nodeName1, nodeName2, resist, isspice)
if (efWarn) if (efWarn)
efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2); efReadError("Merged nodes %s and %s\n", nodeName1, nodeName2);
lostnode = efNodeMerge(&nn1->efnn_node, &nn2->efnn_node); lostnode = efNodeMerge(&nn1->efnn_node, &nn2->efnn_node);
if (nn1->efnn_port > 0) nn2->efnn_port = nn1->efnn_port;
else if (nn2->efnn_port > 0) nn1->efnn_port = nn2->efnn_port;
/* Check if there are any device terminals pointing to the /* Check if there are any device terminals pointing to the
* node that was just removed. * node that was just removed.
@ -904,20 +926,22 @@ efBuildDevice(
/* Parse initial arguments for parameters */ /* Parse initial arguments for parameters */
while ((pptr = strchr(argv[argstart], '=')) != NULL) while ((pptr = strchr(argv[argstart], '=')) != NULL)
{ {
// Check if this parameter is in the table. /* If the parameter is in the parameter list "devp", then save
// If so, handle appropriately. Otherwise, the * the value as appropriate. If not, then the entire phrase
// parameter gets saved verbatim locally. The * will be output verbatim, so just save the whole string.
// "parameters" line comes before any "device" line *
// in the .ext file, so the table should be complete. * The "parameters" line comes before any "device" line in the
* .ext file, so the "devp" list should be complete.
*/
*pptr = '\0'; *pptr = '\0';
for (sparm = devp; sparm; sparm = sparm->parm_next) for (sparm = devp; sparm; sparm = sparm->parm_next)
if (!strcasecmp(sparm->parm_type, argv[argstart])) if (!strncasecmp(sparm->parm_type, argv[argstart], 2))
break; break;
*pptr = '='; *pptr = '=';
if (sparm == NULL) if (sparm == NULL)
{ {
/* Copy the parameter into dev_params */ /* Copy the whole string into dev_params */
/* (parm_type and parm_scale records are not used) */ /* (parm_type and parm_scale records are not used) */
newparm = (DevParam *)mallocMagic(sizeof(DevParam)); newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[argstart]); newparm->parm_name = StrDup((char **)NULL, argv[argstart]);
@ -932,30 +956,59 @@ efBuildDevice(
{ {
case 'a': case 'a':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[argstart]) == 2)
devtmp.dev_area = atoi(pptr); devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale);
else else
{ {
/* Check for a0, a1, a2, ... If a0, handle like "a".
* Otherwise, don't handle it here.
*/
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[argstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_area = (int)(0.5 + (float)atoi(pptr) devtmp.dev_area = (int)(0.5 + (float)atoi(pptr)
* locScale * locScale); * locScale * locScale);
/* Otherwise, punt */
} }
break; break;
case 'p': case 'p':
if ((pptr - argv[argstart]) == 2) if ((pptr - argv[argstart]) == 2)
devtmp.dev_perim = atoi(pptr); devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
else else
{ {
/* Check for p0, p1, p2, ... If p0, handle like "p".
* Otherwise, don't handle it here.
*/
pn = *(argv[argstart] + 1) - '0'; pn = *(argv[argstart] + 1) - '0';
if (pn == 0) if (pn == 0)
devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_perim = (int)(0.5 + (float)atoi(pptr) * locScale);
/* Otherwise, use verbatim */
} }
break; break;
case 'l': case 'l':
if ((pptr - argv[argstart]) == 2)
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
/* Check for l0, l1, l2, ... If l0, handle like "l".
* Otherwise, save it verbatim like an unknown parameter,
* because its value will not be calculated from terminal
* values like "a1, a2, ..." or "p1, p2, ...".
*/
pn = *(argv[argstart] + 1) - '0';
if (pn == 0)
devtmp.dev_length = (int)(0.5 + (float)atoi(pptr) * locScale);
else
{
/* Copy the whole string into dev_params */
newparm = (DevParam *)mallocMagic(sizeof(DevParam));
newparm->parm_name = StrDup((char **)NULL, argv[argstart]);
newparm->parm_next = devtmp.dev_params;
devtmp.dev_params = newparm;
}
}
break; break;
case 'w': case 'w':
devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale); devtmp.dev_width = (int)(0.5 + (float)atoi(pptr) * locScale);
break; break;
@ -1546,7 +1599,25 @@ efBuildConnect(def, nodeName1, nodeName2, deltaC, av, ac)
unsigned size = sizeof (Connection) unsigned size = sizeof (Connection)
+ (efNumResistClasses - 1) * sizeof (EFPerimArea); + (efNumResistClasses - 1) * sizeof (EFPerimArea);
if ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE) /* If one of the nodes has been generated from the
* other by "extract unique", then this is a case where
* the "extract unique" algorithm is blind to shorts
* through subcell hierarchy and has made a name unique
* unnecessarily. In that case, merge the node instead
* of generating a short.
*/
char *uniqstr1, *uniqstr2;
bool isuniq;
uniqstr1 = strstr(nodeName1, "_uq");
uniqstr2 = strstr(nodeName2, "_uq");
if (uniqstr1) *uniqstr1 = '\0';
if (uniqstr2) *uniqstr2 = '\0';
isuniq = !strcmp(nodeName1, nodeName2);
if (uniqstr1) *uniqstr1 = '_';
if (uniqstr2) *uniqstr2 = '_';
if (!isuniq && ((EFOutputFlags & EF_SHORT_MASK) != EF_SHORT_NONE))
{ {
/* Handle the case where two ports on different nets get merged. /* Handle the case where two ports on different nets get merged.
* If "extract short resistor" or "extract short voltage" has * If "extract short resistor" or "extract short voltage" has
@ -1949,8 +2020,10 @@ efNodeMerge(node1ptr, node2ptr)
if (*node1ptr == *node2ptr) if (*node1ptr == *node2ptr)
return NULL; return NULL;
/* Keep the node with the greater number of entries, and merge */ /*
/* the node with fewer entries into it. */ * Keep the node with the greater number of entries, and merge
* the node with fewer entries into it.
*/
if ((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num) if ((*node1ptr)->efnode_num >= (*node2ptr)->efnode_num)
{ {
@ -1990,7 +2063,7 @@ efNodeMerge(node1ptr, node2ptr)
/* Make all EFNodeNames point to "keeping" */ /* Make all EFNodeNames point to "keeping" */
if (removing->efnode_name) if (removing->efnode_name)
{ {
bool topportk, topportr; bool topportk, topportr, bestname;
for (nn = removing->efnode_name; nn; nn = nn->efnn_next) for (nn = removing->efnode_name; nn; nn = nn->efnn_next)
{ {
@ -2002,9 +2075,9 @@ efNodeMerge(node1ptr, node2ptr)
topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE; topportr = (removing->efnode_flags & EF_TOP_PORT) ? TRUE : FALSE;
/* Concatenate list of EFNodeNames, taking into account precedence */ /* Concatenate list of EFNodeNames, taking into account precedence */
if ((!keeping->efnode_name) || (!topportk && (topportr if ((!keeping->efnode_name) || (!topportk && topportr)
|| EFHNBest(removing->efnode_name->efnn_hier, || EFHNBest(removing->efnode_name->efnn_hier,
keeping->efnode_name->efnn_hier)))) keeping->efnode_name->efnn_hier))
{ {
/* /*
* New official name is that of "removing". * New official name is that of "removing".

View File

@ -95,6 +95,7 @@ extOutputGeneratedLabels(parentUse, f)
parentDef = parentUse->cu_def; parentDef = parentUse->cu_def;
free_magic1_t mm1 = freeMagic1_init();
while ((lab = parentDef->cd_labels) != NULL) while ((lab = parentDef->cd_labels) != NULL)
{ {
if ((lab->lab_flags & LABEL_GENERATE) == 0) return; if ((lab->lab_flags & LABEL_GENERATE) == 0) return;
@ -106,9 +107,10 @@ extOutputGeneratedLabels(parentUse, f)
for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++) for (n = 0; n < ExtCurStyle->exts_numResistClasses; n++)
fprintf(f, " 0 0"); fprintf(f, " 0 0");
putc('\n', f); putc('\n', f);
freeMagic(lab); freeMagic1(&mm1, lab);
parentDef->cd_labels = lab->lab_next; parentDef->cd_labels = lab->lab_next;
} }
freeMagic1_end(&mm1);
} }
#endif #endif

View File

@ -2776,8 +2776,12 @@ extOutputDevices(def, transList, outFile)
/* Free the lists */ /* Free the lists */
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{
free_magic1_t mm1 = freeMagic1_init();
for (lb = extSpecialBounds[i]; lb != NULL; lb = lb->b_next) for (lb = extSpecialBounds[i]; lb != NULL; lb = lb->b_next)
freeMagic((char *)lb); freeMagic1(&mm1, (char *)lb);
freeMagic1_end(&mm1);
}
freeMagic((char *)extSpecialBounds); freeMagic((char *)extSpecialBounds);
/* Put the region list back the way we found it: */ /* Put the region list back the way we found it: */